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