xref: /minix/external/bsd/bind/dist/lib/dns/dns64.c (revision 00b67f09)
1 /*	$NetBSD: dns64.c,v 1.6 2014/12/10 04:37:58 christos Exp $	*/
2 
3 /*
4  * Copyright (C) 2010, 2011, 2014  Internet Systems Consortium, Inc. ("ISC")
5  *
6  * Permission to use, copy, modify, and/or distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
11  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
12  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
13  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
14  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
15  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
16  * PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 /* Id: dns64.c,v 1.8 2011/03/12 04:59:47 tbox Exp  */
20 
21 #include <config.h>
22 
23 #include <isc/list.h>
24 #include <isc/mem.h>
25 #include <isc/netaddr.h>
26 #include <isc/string.h>
27 #include <isc/util.h>
28 
29 #include <dns/acl.h>
30 #include <dns/dns64.h>
31 #include <dns/rdata.h>
32 #include <dns/rdataset.h>
33 #include <dns/result.h>
34 
35 struct dns_dns64 {
36 	unsigned char		bits[16];	/*
37 						 * Prefix + suffix bits.
38 						 */
39 	dns_acl_t *		clients;	/*
40 						 * Which clients get mapped
41 						 * addresses.
42 						 */
43 	dns_acl_t *		mapped;		/*
44 						 * IPv4 addresses to be mapped.
45 						 */
46 	dns_acl_t *		excluded;	/*
47 						 * IPv6 addresses that are
48 						 * treated as not existing.
49 						 */
50 	unsigned int		prefixlen;	/*
51 						 * Start of mapped address.
52 						 */
53 	unsigned int		flags;
54 	isc_mem_t *		mctx;
55 	ISC_LINK(dns_dns64_t)	link;
56 };
57 
58 isc_result_t
dns_dns64_create(isc_mem_t * mctx,isc_netaddr_t * prefix,unsigned int prefixlen,isc_netaddr_t * suffix,dns_acl_t * clients,dns_acl_t * mapped,dns_acl_t * excluded,unsigned int flags,dns_dns64_t ** dns64)59 dns_dns64_create(isc_mem_t *mctx, isc_netaddr_t *prefix,
60 		 unsigned int prefixlen, isc_netaddr_t *suffix,
61 		 dns_acl_t *clients, dns_acl_t *mapped, dns_acl_t *excluded,
62 		 unsigned int flags, dns_dns64_t **dns64)
63 {
64 	dns_dns64_t *new;
65 	unsigned int nbytes = 16;
66 
67 	REQUIRE(prefix != NULL && prefix->family == AF_INET6);
68 	/* Legal prefix lengths from rfc6052.txt. */
69 	REQUIRE(prefixlen == 32 || prefixlen == 40 || prefixlen == 48 ||
70 		prefixlen == 56 || prefixlen == 64 || prefixlen == 96);
71 	REQUIRE(isc_netaddr_prefixok(prefix, prefixlen) == ISC_R_SUCCESS);
72 	REQUIRE(dns64 != NULL && *dns64 == NULL);
73 
74 	if (suffix != NULL) {
75 		static const unsigned char zeros[16];
76 		REQUIRE(prefix->family == AF_INET6);
77 		nbytes = prefixlen / 8 + 4;
78 		/* Bits 64-71 are zeros. rfc6052.txt */
79 		if (prefixlen >= 32 && prefixlen <= 64)
80 			nbytes++;
81 		REQUIRE(memcmp(suffix->type.in6.s6_addr, zeros, nbytes) == 0);
82 	}
83 
84 	new = isc_mem_get(mctx, sizeof(dns_dns64_t));
85 	if (new == NULL)
86 		return (ISC_R_NOMEMORY);
87 	memset(new->bits, 0, sizeof(new->bits));
88 	memmove(new->bits, prefix->type.in6.s6_addr, prefixlen / 8);
89 	if (suffix != NULL)
90 		memmove(new->bits + nbytes, suffix->type.in6.s6_addr + nbytes,
91 			16 - nbytes);
92 	new->clients = NULL;
93 	if (clients != NULL)
94 		dns_acl_attach(clients, &new->clients);
95 	new->mapped = NULL;
96 	if (mapped != NULL)
97 		dns_acl_attach(mapped, &new->mapped);
98 	new->excluded = NULL;
99 	if (excluded != NULL)
100 		dns_acl_attach(excluded, &new->excluded);
101 	new->prefixlen = prefixlen;
102 	new->flags = flags;
103 	ISC_LINK_INIT(new, link);
104 	new->mctx = NULL;
105 	isc_mem_attach(mctx, &new->mctx);
106 	*dns64 = new;
107 	return (ISC_R_SUCCESS);
108 }
109 
110 void
dns_dns64_destroy(dns_dns64_t ** dns64p)111 dns_dns64_destroy(dns_dns64_t **dns64p) {
112 	dns_dns64_t *dns64;
113 
114 	REQUIRE(dns64p != NULL && *dns64p != NULL);
115 
116 	dns64 = *dns64p;
117 	*dns64p = NULL;
118 
119 	REQUIRE(!ISC_LINK_LINKED(dns64, link));
120 
121 	if (dns64->clients != NULL)
122 		dns_acl_detach(&dns64->clients);
123 	if (dns64->mapped != NULL)
124 		dns_acl_detach(&dns64->mapped);
125 	if (dns64->excluded != NULL)
126 		dns_acl_detach(&dns64->excluded);
127 	isc_mem_putanddetach(&dns64->mctx, dns64, sizeof(*dns64));
128 }
129 
130 isc_result_t
dns_dns64_aaaafroma(const dns_dns64_t * dns64,const isc_netaddr_t * reqaddr,const dns_name_t * reqsigner,const dns_aclenv_t * env,unsigned int flags,unsigned char * a,unsigned char * aaaa)131 dns_dns64_aaaafroma(const dns_dns64_t *dns64, const isc_netaddr_t *reqaddr,
132 		    const dns_name_t *reqsigner, const dns_aclenv_t *env,
133 		    unsigned int flags, unsigned char *a, unsigned char *aaaa)
134 {
135 	unsigned int nbytes, i;
136 	isc_result_t result;
137 	int match;
138 
139 	if ((dns64->flags & DNS_DNS64_RECURSIVE_ONLY) != 0 &&
140 	    (flags & DNS_DNS64_RECURSIVE) == 0)
141 		return (DNS_R_DISALLOWED);
142 
143 	if ((dns64->flags & DNS_DNS64_BREAK_DNSSEC) == 0 &&
144 	    (flags & DNS_DNS64_DNSSEC) != 0)
145 		return (DNS_R_DISALLOWED);
146 
147 	if (dns64->clients != NULL) {
148 		result = dns_acl_match(reqaddr, reqsigner, dns64->clients, env,
149 				       &match, NULL);
150 		if (result != ISC_R_SUCCESS)
151 			return (result);
152 		if (match <= 0)
153 			return (DNS_R_DISALLOWED);
154 	}
155 
156 	if (dns64->mapped != NULL) {
157 		struct in_addr ina;
158 		isc_netaddr_t netaddr;
159 
160 		memmove(&ina.s_addr, a, 4);
161 		isc_netaddr_fromin(&netaddr, &ina);
162 		result = dns_acl_match(&netaddr, NULL, dns64->mapped, env,
163 				       &match, NULL);
164 		if (result != ISC_R_SUCCESS)
165 			return (result);
166 		if (match <= 0)
167 			return (DNS_R_DISALLOWED);
168 	}
169 
170 	nbytes = dns64->prefixlen / 8;
171 	INSIST(nbytes <= 12);
172 	/* Copy prefix. */
173 	memmove(aaaa, dns64->bits, nbytes);
174 	/* Bits 64-71 are zeros. rfc6052.txt */
175 	if (nbytes == 8)
176 		aaaa[nbytes++] = 0;
177 	/* Copy mapped address. */
178 	for (i = 0; i < 4U; i++) {
179 		aaaa[nbytes++] = a[i];
180 		/* Bits 64-71 are zeros. rfc6052.txt */
181 		if (nbytes == 8)
182 			aaaa[nbytes++] = 0;
183 	}
184 	/* Copy suffix. */
185 	memmove(aaaa + nbytes, dns64->bits + nbytes, 16 - nbytes);
186 	return (ISC_R_SUCCESS);
187 }
188 
189 dns_dns64_t *
dns_dns64_next(dns_dns64_t * dns64)190 dns_dns64_next(dns_dns64_t *dns64) {
191 	dns64 = ISC_LIST_NEXT(dns64, link);
192 	return (dns64);
193 }
194 
195 void
dns_dns64_append(dns_dns64list_t * list,dns_dns64_t * dns64)196 dns_dns64_append(dns_dns64list_t *list, dns_dns64_t *dns64) {
197 	ISC_LIST_APPEND(*list, dns64, link);
198 }
199 
200 void
dns_dns64_unlink(dns_dns64list_t * list,dns_dns64_t * dns64)201 dns_dns64_unlink(dns_dns64list_t *list, dns_dns64_t *dns64) {
202 	ISC_LIST_UNLINK(*list, dns64, link);
203 }
204 
205 isc_boolean_t
dns_dns64_aaaaok(const dns_dns64_t * dns64,const isc_netaddr_t * reqaddr,const dns_name_t * reqsigner,const dns_aclenv_t * env,unsigned int flags,dns_rdataset_t * rdataset,isc_boolean_t * aaaaok,size_t aaaaoklen)206 dns_dns64_aaaaok(const dns_dns64_t *dns64, const isc_netaddr_t *reqaddr,
207 		 const dns_name_t *reqsigner, const dns_aclenv_t *env,
208 		 unsigned int flags, dns_rdataset_t *rdataset,
209 		 isc_boolean_t *aaaaok, size_t aaaaoklen)
210 {
211 	struct in6_addr in6;
212 	isc_netaddr_t netaddr;
213 	isc_result_t result;
214 	int match;
215 	isc_boolean_t answer = ISC_FALSE;
216 	isc_boolean_t found = ISC_FALSE;
217 	unsigned int i, ok;
218 
219 	REQUIRE(rdataset != NULL);
220 	REQUIRE(rdataset->type == dns_rdatatype_aaaa);
221 	REQUIRE(rdataset->rdclass == dns_rdataclass_in);
222 	if (aaaaok != NULL)
223 		REQUIRE(aaaaoklen == dns_rdataset_count(rdataset));
224 
225 	for (;dns64 != NULL; dns64 = ISC_LIST_NEXT(dns64, link)) {
226 		if ((dns64->flags & DNS_DNS64_RECURSIVE_ONLY) != 0 &&
227 		    (flags & DNS_DNS64_RECURSIVE) == 0)
228 			continue;
229 
230 		if ((dns64->flags & DNS_DNS64_BREAK_DNSSEC) == 0 &&
231 		    (flags & DNS_DNS64_DNSSEC) != 0)
232 			continue;
233 		/*
234 		 * Work out if this dns64 structure applies to this client.
235 		 */
236 		if (dns64->clients != NULL) {
237 			result = dns_acl_match(reqaddr, reqsigner,
238 					       dns64->clients, env,
239 					       &match, NULL);
240 			if (result != ISC_R_SUCCESS)
241 				continue;
242 			if (match <= 0)
243 				continue;
244 		}
245 
246 		if (!found && aaaaok != NULL) {
247 			for (i = 0; i < aaaaoklen; i++)
248 				aaaaok[i] = ISC_FALSE;
249 		}
250 		found = ISC_TRUE;
251 
252 		/*
253 		 * If we are not excluding any addresses then any AAAA
254 		 * will do.
255 		 */
256 		if (dns64->excluded == NULL) {
257 			answer = ISC_TRUE;
258 			if (aaaaok == NULL)
259 				goto done;
260 			for (i = 0; i < aaaaoklen; i++)
261 				aaaaok[i] = ISC_TRUE;
262 			goto done;
263 		}
264 
265 		i = 0; ok = 0;
266 		for (result = dns_rdataset_first(rdataset);
267 		     result == ISC_R_SUCCESS;
268 		     result = dns_rdataset_next(rdataset)) {
269 			dns_rdata_t rdata = DNS_RDATA_INIT;
270 			if (aaaaok == NULL || !aaaaok[i]) {
271 
272 				dns_rdataset_current(rdataset, &rdata);
273 				memmove(&in6.s6_addr, rdata.data, 16);
274 				isc_netaddr_fromin6(&netaddr, &in6);
275 
276 				result = dns_acl_match(&netaddr, NULL,
277 						       dns64->excluded,
278 						       env, &match, NULL);
279 				if (result == ISC_R_SUCCESS && match <= 0) {
280 					answer = ISC_TRUE;
281 					if (aaaaok == NULL)
282 						goto done;
283 					aaaaok[i] = ISC_TRUE;
284 					ok++;
285 				}
286 			} else
287 				ok++;
288 			i++;
289 		}
290 		/*
291 		 * Are all addresses ok?
292 		 */
293 		if (aaaaok != NULL && ok == aaaaoklen)
294 			goto done;
295 	}
296 
297  done:
298 	if (!found && aaaaok != NULL) {
299 		for (i = 0; i < aaaaoklen; i++)
300 			aaaaok[i] = ISC_TRUE;
301 	}
302 	return (found ? answer : ISC_TRUE);
303 }
304