2 * Copyright (C) 2010, 2011, 2014 Internet Systems Consortium, Inc. ("ISC")
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.
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.
17 /* $Id: dns64.c,v 1.8 2011/03/12 04:59:47 tbox Exp $ */
23 #include <isc/netaddr.h>
24 #include <isc/string.h>
28 #include <dns/dns64.h>
29 #include <dns/rdata.h>
30 #include <dns/rdataset.h>
31 #include <dns/result.h>
34 unsigned char bits[16]; /*
35 * Prefix + suffix bits.
37 dns_acl_t * clients; /*
38 * Which clients get mapped
41 dns_acl_t * mapped; /*
42 * IPv4 addresses to be mapped.
44 dns_acl_t * excluded; /*
45 * IPv6 addresses that are
46 * treated as not existing.
48 unsigned int prefixlen; /*
49 * Start of mapped address.
53 ISC_LINK(dns_dns64_t) link;
57 dns_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)
63 unsigned int nbytes = 16;
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);
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)
79 REQUIRE(memcmp(suffix->type.in6.s6_addr, zeros, nbytes) == 0);
82 new = isc_mem_get(mctx, sizeof(dns_dns64_t));
84 return (ISC_R_NOMEMORY);
85 memset(new->bits, 0, sizeof(new->bits));
86 memmove(new->bits, prefix->type.in6.s6_addr, prefixlen / 8);
88 memmove(new->bits + nbytes, suffix->type.in6.s6_addr + nbytes,
92 dns_acl_attach(clients, &new->clients);
95 dns_acl_attach(mapped, &new->mapped);
98 dns_acl_attach(excluded, &new->excluded);
99 new->prefixlen = prefixlen;
101 ISC_LINK_INIT(new, link);
103 isc_mem_attach(mctx, &new->mctx);
105 return (ISC_R_SUCCESS);
109 dns_dns64_destroy(dns_dns64_t **dns64p) {
112 REQUIRE(dns64p != NULL && *dns64p != NULL);
117 REQUIRE(!ISC_LINK_LINKED(dns64, link));
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));
129 dns_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)
133 unsigned int nbytes, i;
137 if ((dns64->flags & DNS_DNS64_RECURSIVE_ONLY) != 0 &&
138 (flags & DNS_DNS64_RECURSIVE) == 0)
139 return (DNS_R_DISALLOWED);
141 if ((dns64->flags & DNS_DNS64_BREAK_DNSSEC) == 0 &&
142 (flags & DNS_DNS64_DNSSEC) != 0)
143 return (DNS_R_DISALLOWED);
145 if (dns64->clients != NULL) {
146 result = dns_acl_match(reqaddr, reqsigner, dns64->clients, env,
148 if (result != ISC_R_SUCCESS)
151 return (DNS_R_DISALLOWED);
154 if (dns64->mapped != NULL) {
156 isc_netaddr_t netaddr;
158 memmove(&ina.s_addr, a, 4);
159 isc_netaddr_fromin(&netaddr, &ina);
160 result = dns_acl_match(&netaddr, NULL, dns64->mapped, env,
162 if (result != ISC_R_SUCCESS)
165 return (DNS_R_DISALLOWED);
168 nbytes = dns64->prefixlen / 8;
169 INSIST(nbytes <= 12);
171 memmove(aaaa, dns64->bits, nbytes);
172 /* Bits 64-71 are zeros. draft-ietf-behave-address-format-04 */
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 */
183 memmove(aaaa + nbytes, dns64->bits + nbytes, 16 - nbytes);
184 return (ISC_R_SUCCESS);
188 dns_dns64_next(dns_dns64_t *dns64) {
189 dns64 = ISC_LIST_NEXT(dns64, link);
194 dns_dns64_append(dns_dns64list_t *list, dns_dns64_t *dns64) {
195 ISC_LIST_APPEND(*list, dns64, link);
199 dns_dns64_unlink(dns_dns64list_t *list, dns_dns64_t *dns64) {
200 ISC_LIST_UNLINK(*list, dns64, link);
204 dns_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)
210 isc_netaddr_t netaddr;
213 isc_boolean_t answer = ISC_FALSE;
214 isc_boolean_t found = ISC_FALSE;
217 REQUIRE(rdataset != NULL);
218 REQUIRE(rdataset->type == dns_rdatatype_aaaa);
219 REQUIRE(rdataset->rdclass == dns_rdataclass_in);
221 REQUIRE(aaaaoklen == dns_rdataset_count(rdataset));
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)
228 if ((dns64->flags & DNS_DNS64_BREAK_DNSSEC) == 0 &&
229 (flags & DNS_DNS64_DNSSEC) != 0)
232 * Work out if this dns64 structure applies to this client.
234 if (dns64->clients != NULL) {
235 result = dns_acl_match(reqaddr, reqsigner,
238 if (result != ISC_R_SUCCESS)
244 if (!found && aaaaok != NULL) {
245 for (i = 0; i < aaaaoklen; i++)
246 aaaaok[i] = ISC_FALSE;
251 * If we are not excluding any addresses then any AAAA
254 if (dns64->excluded == NULL) {
258 for (i = 0; i < aaaaoklen; i++)
259 aaaaok[i] = ISC_TRUE;
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]) {
270 dns_rdataset_current(rdataset, &rdata);
271 memmove(&in6.s6_addr, rdata.data, 16);
272 isc_netaddr_fromin6(&netaddr, &in6);
274 result = dns_acl_match(&netaddr, NULL,
277 if (result == ISC_R_SUCCESS && match <= 0) {
281 aaaaok[i] = ISC_TRUE;
289 * Are all addresses ok?
291 if (aaaaok != NULL && ok == aaaaoklen)
296 if (!found && aaaaok != NULL) {
297 for (i = 0; i < aaaaoklen; i++)
298 aaaaok[i] = ISC_TRUE;
300 return (found ? answer : ISC_TRUE);