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