dns64.c revision 1.1.1.1 1 /* $NetBSD: dns64.c,v 1.1.1.1 2018/08/12 12:08:09 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 http://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
15 #include <config.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 {
58 dns_dns64_t *dns64;
59 unsigned int nbytes = 16;
60
61 REQUIRE(prefix != NULL && prefix->family == AF_INET6);
62 /* Legal prefix lengths from rfc6052.txt. */
63 REQUIRE(prefixlen == 32 || prefixlen == 40 || prefixlen == 48 ||
64 prefixlen == 56 || prefixlen == 64 || prefixlen == 96);
65 REQUIRE(isc_netaddr_prefixok(prefix, prefixlen) == ISC_R_SUCCESS);
66 REQUIRE(dns64p != NULL && *dns64p == NULL);
67
68 if (suffix != NULL) {
69 static const unsigned char zeros[16];
70 REQUIRE(prefix->family == AF_INET6);
71 nbytes = prefixlen / 8 + 4;
72 /* Bits 64-71 are zeros. rfc6052.txt */
73 if (prefixlen >= 32 && prefixlen <= 64)
74 nbytes++;
75 REQUIRE(memcmp(suffix->type.in6.s6_addr, zeros, nbytes) == 0);
76 }
77
78 dns64 = isc_mem_get(mctx, sizeof(dns_dns64_t));
79 if (dns64 == NULL)
80 return (ISC_R_NOMEMORY);
81 memset(dns64->bits, 0, sizeof(dns64->bits));
82 memmove(dns64->bits, prefix->type.in6.s6_addr, prefixlen / 8);
83 if (suffix != NULL)
84 memmove(dns64->bits + nbytes, suffix->type.in6.s6_addr + nbytes,
85 16 - nbytes);
86 dns64->clients = NULL;
87 if (clients != NULL)
88 dns_acl_attach(clients, &dns64->clients);
89 dns64->mapped = NULL;
90 if (mapped != NULL)
91 dns_acl_attach(mapped, &dns64->mapped);
92 dns64->excluded = NULL;
93 if (excluded != NULL)
94 dns_acl_attach(excluded, &dns64->excluded);
95 dns64->prefixlen = prefixlen;
96 dns64->flags = flags;
97 ISC_LINK_INIT(dns64, link);
98 dns64->mctx = NULL;
99 isc_mem_attach(mctx, &dns64->mctx);
100 *dns64p = dns64;
101 return (ISC_R_SUCCESS);
102 }
103
104 void
105 dns_dns64_destroy(dns_dns64_t **dns64p) {
106 dns_dns64_t *dns64;
107
108 REQUIRE(dns64p != NULL && *dns64p != NULL);
109
110 dns64 = *dns64p;
111 *dns64p = NULL;
112
113 REQUIRE(!ISC_LINK_LINKED(dns64, link));
114
115 if (dns64->clients != NULL)
116 dns_acl_detach(&dns64->clients);
117 if (dns64->mapped != NULL)
118 dns_acl_detach(&dns64->mapped);
119 if (dns64->excluded != NULL)
120 dns_acl_detach(&dns64->excluded);
121 isc_mem_putanddetach(&dns64->mctx, dns64, sizeof(*dns64));
122 }
123
124 isc_result_t
125 dns_dns64_aaaafroma(const dns_dns64_t *dns64, const isc_netaddr_t *reqaddr,
126 const dns_name_t *reqsigner, const dns_aclenv_t *env,
127 unsigned int flags, unsigned char *a, unsigned char *aaaa)
128 {
129 unsigned int nbytes, i;
130 isc_result_t result;
131 int match;
132
133 if ((dns64->flags & DNS_DNS64_RECURSIVE_ONLY) != 0 &&
134 (flags & DNS_DNS64_RECURSIVE) == 0)
135 return (DNS_R_DISALLOWED);
136
137 if ((dns64->flags & DNS_DNS64_BREAK_DNSSEC) == 0 &&
138 (flags & DNS_DNS64_DNSSEC) != 0)
139 return (DNS_R_DISALLOWED);
140
141 if (dns64->clients != NULL) {
142 result = dns_acl_match(reqaddr, reqsigner, dns64->clients, env,
143 &match, NULL);
144 if (result != ISC_R_SUCCESS)
145 return (result);
146 if (match <= 0)
147 return (DNS_R_DISALLOWED);
148 }
149
150 if (dns64->mapped != NULL) {
151 struct in_addr ina;
152 isc_netaddr_t netaddr;
153
154 memmove(&ina.s_addr, a, 4);
155 isc_netaddr_fromin(&netaddr, &ina);
156 result = dns_acl_match(&netaddr, NULL, dns64->mapped, env,
157 &match, NULL);
158 if (result != ISC_R_SUCCESS)
159 return (result);
160 if (match <= 0)
161 return (DNS_R_DISALLOWED);
162 }
163
164 nbytes = dns64->prefixlen / 8;
165 INSIST(nbytes <= 12);
166 /* Copy prefix. */
167 memmove(aaaa, dns64->bits, nbytes);
168 /* Bits 64-71 are zeros. rfc6052.txt */
169 if (nbytes == 8)
170 aaaa[nbytes++] = 0;
171 /* Copy mapped address. */
172 for (i = 0; i < 4U; i++) {
173 aaaa[nbytes++] = a[i];
174 /* Bits 64-71 are zeros. rfc6052.txt */
175 if (nbytes == 8)
176 aaaa[nbytes++] = 0;
177 }
178 /* Copy suffix. */
179 memmove(aaaa + nbytes, dns64->bits + nbytes, 16 - nbytes);
180 return (ISC_R_SUCCESS);
181 }
182
183 dns_dns64_t *
184 dns_dns64_next(dns_dns64_t *dns64) {
185 dns64 = ISC_LIST_NEXT(dns64, link);
186 return (dns64);
187 }
188
189 void
190 dns_dns64_append(dns_dns64list_t *list, dns_dns64_t *dns64) {
191 ISC_LIST_APPEND(*list, dns64, link);
192 }
193
194 void
195 dns_dns64_unlink(dns_dns64list_t *list, dns_dns64_t *dns64) {
196 ISC_LIST_UNLINK(*list, dns64, link);
197 }
198
199 isc_boolean_t
200 dns_dns64_aaaaok(const dns_dns64_t *dns64, const isc_netaddr_t *reqaddr,
201 const dns_name_t *reqsigner, const dns_aclenv_t *env,
202 unsigned int flags, dns_rdataset_t *rdataset,
203 isc_boolean_t *aaaaok, size_t aaaaoklen)
204 {
205 struct in6_addr in6;
206 isc_netaddr_t netaddr;
207 isc_result_t result;
208 int match;
209 isc_boolean_t answer = ISC_FALSE;
210 isc_boolean_t found = ISC_FALSE;
211 unsigned int i, ok;
212
213 REQUIRE(rdataset != NULL);
214 REQUIRE(rdataset->type == dns_rdatatype_aaaa);
215 REQUIRE(rdataset->rdclass == dns_rdataclass_in);
216 if (aaaaok != NULL)
217 REQUIRE(aaaaoklen == dns_rdataset_count(rdataset));
218
219 for (;dns64 != NULL; dns64 = ISC_LIST_NEXT(dns64, link)) {
220 if ((dns64->flags & DNS_DNS64_RECURSIVE_ONLY) != 0 &&
221 (flags & DNS_DNS64_RECURSIVE) == 0)
222 continue;
223
224 if ((dns64->flags & DNS_DNS64_BREAK_DNSSEC) == 0 &&
225 (flags & DNS_DNS64_DNSSEC) != 0)
226 continue;
227 /*
228 * Work out if this dns64 structure applies to this client.
229 */
230 if (dns64->clients != NULL) {
231 result = dns_acl_match(reqaddr, reqsigner,
232 dns64->clients, env,
233 &match, NULL);
234 if (result != ISC_R_SUCCESS)
235 continue;
236 if (match <= 0)
237 continue;
238 }
239
240 if (!found && aaaaok != NULL) {
241 for (i = 0; i < aaaaoklen; i++)
242 aaaaok[i] = ISC_FALSE;
243 }
244 found = ISC_TRUE;
245
246 /*
247 * If we are not excluding any addresses then any AAAA
248 * will do.
249 */
250 if (dns64->excluded == NULL) {
251 answer = ISC_TRUE;
252 if (aaaaok == NULL)
253 goto done;
254 for (i = 0; i < aaaaoklen; i++)
255 aaaaok[i] = ISC_TRUE;
256 goto done;
257 }
258
259 i = 0; ok = 0;
260 for (result = dns_rdataset_first(rdataset);
261 result == ISC_R_SUCCESS;
262 result = dns_rdataset_next(rdataset)) {
263 dns_rdata_t rdata = DNS_RDATA_INIT;
264 if (aaaaok == NULL || !aaaaok[i]) {
265
266 dns_rdataset_current(rdataset, &rdata);
267 memmove(&in6.s6_addr, rdata.data, 16);
268 isc_netaddr_fromin6(&netaddr, &in6);
269
270 result = dns_acl_match(&netaddr, NULL,
271 dns64->excluded,
272 env, &match, NULL);
273 if (result == ISC_R_SUCCESS && match <= 0) {
274 answer = ISC_TRUE;
275 if (aaaaok == NULL)
276 goto done;
277 aaaaok[i] = ISC_TRUE;
278 ok++;
279 }
280 } else
281 ok++;
282 i++;
283 }
284 /*
285 * Are all addresses ok?
286 */
287 if (aaaaok != NULL && ok == aaaaoklen)
288 goto done;
289 }
290
291 done:
292 if (!found && aaaaok != NULL) {
293 for (i = 0; i < aaaaoklen; i++)
294 aaaaok[i] = ISC_TRUE;
295 }
296 return (found ? answer : ISC_TRUE);
297 }
298