PageRenderTime 23ms CodeModel.GetById 2ms app.highlight 17ms RepoModel.GetById 1ms app.codeStats 0ms

/contrib/bind9/lib/dns/dns64.c

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