Home | History | Annotate | Line # | Download | only in dns
dns64.c revision 1.1.1.4
      1 /*	$NetBSD: dns64.c,v 1.1.1.4 2021/02/19 16:37:12 christos Exp $	*/
      2 
      3 /*
      4  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
      5  *
      6  * This Source Code Form is subject to the terms of the Mozilla Public
      7  * License, v. 2.0. If a copy of the MPL was not distributed with this
      8  * file, you can obtain one at https://mozilla.org/MPL/2.0/.
      9  *
     10  * See the COPYRIGHT file distributed with this work for additional
     11  * information regarding copyright ownership.
     12  */
     13 
     14 #include <stdbool.h>
     15 #include <string.h>
     16 
     17 #include <isc/list.h>
     18 #include <isc/mem.h>
     19 #include <isc/netaddr.h>
     20 #include <isc/string.h>
     21 #include <isc/util.h>
     22 
     23 #include <dns/acl.h>
     24 #include <dns/dns64.h>
     25 #include <dns/rdata.h>
     26 #include <dns/rdataset.h>
     27 #include <dns/result.h>
     28 
     29 struct dns_dns64 {
     30 	unsigned char bits[16]; /*
     31 				 * Prefix + suffix bits.
     32 				 */
     33 	dns_acl_t *clients;	/*
     34 				 * Which clients get mapped
     35 				 * addresses.
     36 				 */
     37 	dns_acl_t *mapped;	/*
     38 				 * IPv4 addresses to be mapped.
     39 				 */
     40 	dns_acl_t *excluded;	/*
     41 				 * IPv6 addresses that are
     42 				 * treated as not existing.
     43 				 */
     44 	unsigned int prefixlen; /*
     45 				 * Start of mapped address.
     46 				 */
     47 	unsigned int flags;
     48 	isc_mem_t *mctx;
     49 	ISC_LINK(dns_dns64_t) link;
     50 };
     51 
     52 isc_result_t
     53 dns_dns64_create(isc_mem_t *mctx, const isc_netaddr_t *prefix,
     54 		 unsigned int prefixlen, const isc_netaddr_t *suffix,
     55 		 dns_acl_t *clients, dns_acl_t *mapped, dns_acl_t *excluded,
     56 		 unsigned int flags, dns_dns64_t **dns64p) {
     57 	dns_dns64_t *dns64;
     58 	unsigned int nbytes = 16;
     59 
     60 	REQUIRE(prefix != NULL && prefix->family == AF_INET6);
     61 	/* Legal prefix lengths from rfc6052.txt. */
     62 	REQUIRE(prefixlen == 32 || prefixlen == 40 || prefixlen == 48 ||
     63 		prefixlen == 56 || prefixlen == 64 || prefixlen == 96);
     64 	REQUIRE(isc_netaddr_prefixok(prefix, prefixlen) == ISC_R_SUCCESS);
     65 	REQUIRE(dns64p != NULL && *dns64p == NULL);
     66 
     67 	if (suffix != NULL) {
     68 		static const unsigned char zeros[16];
     69 		REQUIRE(prefix->family == AF_INET6);
     70 		nbytes = prefixlen / 8 + 4;
     71 		/* Bits 64-71 are zeros. rfc6052.txt */
     72 		if (prefixlen >= 32 && prefixlen <= 64) {
     73 			nbytes++;
     74 		}
     75 		REQUIRE(memcmp(suffix->type.in6.s6_addr, zeros, nbytes) == 0);
     76 	}
     77 
     78 	dns64 = isc_mem_get(mctx, sizeof(dns_dns64_t));
     79 	memset(dns64->bits, 0, sizeof(dns64->bits));
     80 	memmove(dns64->bits, prefix->type.in6.s6_addr, prefixlen / 8);
     81 	if (suffix != NULL) {
     82 		memmove(dns64->bits + nbytes, suffix->type.in6.s6_addr + nbytes,
     83 			16 - nbytes);
     84 	}
     85 	dns64->clients = NULL;
     86 	if (clients != NULL) {
     87 		dns_acl_attach(clients, &dns64->clients);
     88 	}
     89 	dns64->mapped = NULL;
     90 	if (mapped != NULL) {
     91 		dns_acl_attach(mapped, &dns64->mapped);
     92 	}
     93 	dns64->excluded = NULL;
     94 	if (excluded != NULL) {
     95 		dns_acl_attach(excluded, &dns64->excluded);
     96 	}
     97 	dns64->prefixlen = prefixlen;
     98 	dns64->flags = flags;
     99 	ISC_LINK_INIT(dns64, link);
    100 	dns64->mctx = NULL;
    101 	isc_mem_attach(mctx, &dns64->mctx);
    102 	*dns64p = dns64;
    103 	return (ISC_R_SUCCESS);
    104 }
    105 
    106 void
    107 dns_dns64_destroy(dns_dns64_t **dns64p) {
    108 	dns_dns64_t *dns64;
    109 
    110 	REQUIRE(dns64p != NULL && *dns64p != NULL);
    111 
    112 	dns64 = *dns64p;
    113 	*dns64p = NULL;
    114 
    115 	REQUIRE(!ISC_LINK_LINKED(dns64, link));
    116 
    117 	if (dns64->clients != NULL) {
    118 		dns_acl_detach(&dns64->clients);
    119 	}
    120 	if (dns64->mapped != NULL) {
    121 		dns_acl_detach(&dns64->mapped);
    122 	}
    123 	if (dns64->excluded != NULL) {
    124 		dns_acl_detach(&dns64->excluded);
    125 	}
    126 	isc_mem_putanddetach(&dns64->mctx, dns64, sizeof(*dns64));
    127 }
    128 
    129 isc_result_t
    130 dns_dns64_aaaafroma(const dns_dns64_t *dns64, const isc_netaddr_t *reqaddr,
    131 		    const dns_name_t *reqsigner, const dns_aclenv_t *env,
    132 		    unsigned int flags, unsigned char *a, unsigned char *aaaa) {
    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 	{
    140 		return (DNS_R_DISALLOWED);
    141 	}
    142 
    143 	if ((dns64->flags & DNS_DNS64_BREAK_DNSSEC) == 0 &&
    144 	    (flags & DNS_DNS64_DNSSEC) != 0)
    145 	{
    146 		return (DNS_R_DISALLOWED);
    147 	}
    148 
    149 	if (dns64->clients != NULL) {
    150 		result = dns_acl_match(reqaddr, reqsigner, dns64->clients, env,
    151 				       &match, NULL);
    152 		if (result != ISC_R_SUCCESS) {
    153 			return (result);
    154 		}
    155 		if (match <= 0) {
    156 			return (DNS_R_DISALLOWED);
    157 		}
    158 	}
    159 
    160 	if (dns64->mapped != NULL) {
    161 		struct in_addr ina;
    162 		isc_netaddr_t netaddr;
    163 
    164 		memmove(&ina.s_addr, a, 4);
    165 		isc_netaddr_fromin(&netaddr, &ina);
    166 		result = dns_acl_match(&netaddr, NULL, dns64->mapped, env,
    167 				       &match, NULL);
    168 		if (result != ISC_R_SUCCESS) {
    169 			return (result);
    170 		}
    171 		if (match <= 0) {
    172 			return (DNS_R_DISALLOWED);
    173 		}
    174 	}
    175 
    176 	nbytes = dns64->prefixlen / 8;
    177 	INSIST(nbytes <= 12);
    178 	/* Copy prefix. */
    179 	memmove(aaaa, dns64->bits, nbytes);
    180 	/* Bits 64-71 are zeros. rfc6052.txt */
    181 	if (nbytes == 8) {
    182 		aaaa[nbytes++] = 0;
    183 	}
    184 	/* Copy mapped address. */
    185 	for (i = 0; i < 4U; i++) {
    186 		aaaa[nbytes++] = a[i];
    187 		/* Bits 64-71 are zeros. rfc6052.txt */
    188 		if (nbytes == 8) {
    189 			aaaa[nbytes++] = 0;
    190 		}
    191 	}
    192 	/* Copy suffix. */
    193 	memmove(aaaa + nbytes, dns64->bits + nbytes, 16 - nbytes);
    194 	return (ISC_R_SUCCESS);
    195 }
    196 
    197 dns_dns64_t *
    198 dns_dns64_next(dns_dns64_t *dns64) {
    199 	dns64 = ISC_LIST_NEXT(dns64, link);
    200 	return (dns64);
    201 }
    202 
    203 void
    204 dns_dns64_append(dns_dns64list_t *list, dns_dns64_t *dns64) {
    205 	ISC_LIST_APPEND(*list, dns64, link);
    206 }
    207 
    208 void
    209 dns_dns64_unlink(dns_dns64list_t *list, dns_dns64_t *dns64) {
    210 	ISC_LIST_UNLINK(*list, dns64, link);
    211 }
    212 
    213 bool
    214 dns_dns64_aaaaok(const dns_dns64_t *dns64, const isc_netaddr_t *reqaddr,
    215 		 const dns_name_t *reqsigner, const dns_aclenv_t *env,
    216 		 unsigned int flags, dns_rdataset_t *rdataset, bool *aaaaok,
    217 		 size_t aaaaoklen) {
    218 	struct in6_addr in6;
    219 	isc_netaddr_t netaddr;
    220 	isc_result_t result;
    221 	int match;
    222 	bool answer = false;
    223 	bool found = false;
    224 	unsigned int i, ok;
    225 
    226 	REQUIRE(rdataset != NULL);
    227 	REQUIRE(rdataset->type == dns_rdatatype_aaaa);
    228 	REQUIRE(rdataset->rdclass == dns_rdataclass_in);
    229 	if (aaaaok != NULL) {
    230 		REQUIRE(aaaaoklen == dns_rdataset_count(rdataset));
    231 	}
    232 
    233 	for (; dns64 != NULL; dns64 = ISC_LIST_NEXT(dns64, link)) {
    234 		if ((dns64->flags & DNS_DNS64_RECURSIVE_ONLY) != 0 &&
    235 		    (flags & DNS_DNS64_RECURSIVE) == 0)
    236 		{
    237 			continue;
    238 		}
    239 
    240 		if ((dns64->flags & DNS_DNS64_BREAK_DNSSEC) == 0 &&
    241 		    (flags & DNS_DNS64_DNSSEC) != 0)
    242 		{
    243 			continue;
    244 		}
    245 		/*
    246 		 * Work out if this dns64 structure applies to this client.
    247 		 */
    248 		if (dns64->clients != NULL) {
    249 			result = dns_acl_match(reqaddr, reqsigner,
    250 					       dns64->clients, env, &match,
    251 					       NULL);
    252 			if (result != ISC_R_SUCCESS) {
    253 				continue;
    254 			}
    255 			if (match <= 0) {
    256 				continue;
    257 			}
    258 		}
    259 
    260 		if (!found && aaaaok != NULL) {
    261 			for (i = 0; i < aaaaoklen; i++) {
    262 				aaaaok[i] = false;
    263 			}
    264 		}
    265 		found = true;
    266 
    267 		/*
    268 		 * If we are not excluding any addresses then any AAAA
    269 		 * will do.
    270 		 */
    271 		if (dns64->excluded == NULL) {
    272 			answer = true;
    273 			if (aaaaok == NULL) {
    274 				goto done;
    275 			}
    276 			for (i = 0; i < aaaaoklen; i++) {
    277 				aaaaok[i] = true;
    278 			}
    279 			goto done;
    280 		}
    281 
    282 		i = 0;
    283 		ok = 0;
    284 		for (result = dns_rdataset_first(rdataset);
    285 		     result == ISC_R_SUCCESS;
    286 		     result = dns_rdataset_next(rdataset))
    287 		{
    288 			dns_rdata_t rdata = DNS_RDATA_INIT;
    289 			if (aaaaok == NULL || !aaaaok[i]) {
    290 				dns_rdataset_current(rdataset, &rdata);
    291 				memmove(&in6.s6_addr, rdata.data, 16);
    292 				isc_netaddr_fromin6(&netaddr, &in6);
    293 
    294 				result = dns_acl_match(&netaddr, NULL,
    295 						       dns64->excluded, env,
    296 						       &match, NULL);
    297 				if (result == ISC_R_SUCCESS && match <= 0) {
    298 					answer = true;
    299 					if (aaaaok == NULL) {
    300 						goto done;
    301 					}
    302 					aaaaok[i] = true;
    303 					ok++;
    304 				}
    305 			} else {
    306 				ok++;
    307 			}
    308 			i++;
    309 		}
    310 		/*
    311 		 * Are all addresses ok?
    312 		 */
    313 		if (aaaaok != NULL && ok == aaaaoklen) {
    314 			goto done;
    315 		}
    316 	}
    317 
    318 done:
    319 	if (!found && aaaaok != NULL) {
    320 		for (i = 0; i < aaaaoklen; i++) {
    321 			aaaaok[i] = true;
    322 		}
    323 	}
    324 	return (found ? answer : true);
    325 }
    326