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} 302