/src/bind9/lib/dns/dns64.c
Line | Count | Source |
1 | | /* |
2 | | * Copyright (C) Internet Systems Consortium, Inc. ("ISC") |
3 | | * |
4 | | * SPDX-License-Identifier: MPL-2.0 |
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/result.h> |
21 | | #include <isc/string.h> |
22 | | #include <isc/util.h> |
23 | | |
24 | | #include <dns/acl.h> |
25 | | #include <dns/dns64.h> |
26 | | #include <dns/rdata.h> |
27 | | #include <dns/rdatalist.h> |
28 | | #include <dns/rdataset.h> |
29 | | |
30 | | struct dns_dns64 { |
31 | | unsigned char bits[16]; /* |
32 | | * Prefix + suffix bits. |
33 | | */ |
34 | | dns_acl_t *clients; /* |
35 | | * Which clients get mapped |
36 | | * addresses. |
37 | | */ |
38 | | dns_acl_t *mapped; /* |
39 | | * IPv4 addresses to be mapped. |
40 | | */ |
41 | | dns_acl_t *excluded; /* |
42 | | * IPv6 addresses that are |
43 | | * treated as not existing. |
44 | | */ |
45 | | unsigned int prefixlen; /* |
46 | | * Start of mapped address. |
47 | | */ |
48 | | unsigned int flags; |
49 | | isc_mem_t *mctx; |
50 | | ISC_LINK(dns_dns64_t) link; |
51 | | }; |
52 | | |
53 | | void |
54 | | dns_dns64_create(isc_mem_t *mctx, const isc_netaddr_t *prefix, |
55 | | unsigned int prefixlen, const isc_netaddr_t *suffix, |
56 | | dns_acl_t *clients, dns_acl_t *mapped, dns_acl_t *excluded, |
57 | 0 | unsigned int flags, dns_dns64_t **dns64p) { |
58 | 0 | dns_dns64_t *dns64; |
59 | 0 | unsigned int nbytes = 16; |
60 | |
|
61 | 0 | REQUIRE(prefix != NULL && prefix->family == AF_INET6); |
62 | | /* Legal prefix lengths from rfc6052.txt. */ |
63 | 0 | REQUIRE(prefixlen == 32 || prefixlen == 40 || prefixlen == 48 || |
64 | 0 | prefixlen == 56 || prefixlen == 64 || prefixlen == 96); |
65 | 0 | REQUIRE(isc_netaddr_prefixok(prefix, prefixlen) == ISC_R_SUCCESS); |
66 | 0 | REQUIRE(dns64p != NULL && *dns64p == NULL); |
67 | |
|
68 | 0 | if (suffix != NULL) { |
69 | 0 | static const unsigned char zeros[16]; |
70 | 0 | REQUIRE(prefix->family == AF_INET6); |
71 | 0 | nbytes = prefixlen / 8 + 4; |
72 | | /* Bits 64-71 are zeros. rfc6052.txt */ |
73 | 0 | if (prefixlen >= 32 && prefixlen <= 64) { |
74 | 0 | nbytes++; |
75 | 0 | } |
76 | 0 | REQUIRE(memcmp(suffix->type.in6.s6_addr, zeros, nbytes) == 0); |
77 | 0 | } |
78 | |
|
79 | 0 | dns64 = isc_mem_get(mctx, sizeof(dns_dns64_t)); |
80 | 0 | memset(dns64->bits, 0, sizeof(dns64->bits)); |
81 | 0 | memmove(dns64->bits, prefix->type.in6.s6_addr, prefixlen / 8); |
82 | 0 | if (suffix != NULL) { |
83 | 0 | memmove(dns64->bits + nbytes, suffix->type.in6.s6_addr + nbytes, |
84 | 0 | 16 - nbytes); |
85 | 0 | } |
86 | 0 | dns64->clients = NULL; |
87 | 0 | if (clients != NULL) { |
88 | 0 | dns_acl_attach(clients, &dns64->clients); |
89 | 0 | } |
90 | 0 | dns64->mapped = NULL; |
91 | 0 | if (mapped != NULL) { |
92 | 0 | dns_acl_attach(mapped, &dns64->mapped); |
93 | 0 | } |
94 | 0 | dns64->excluded = NULL; |
95 | 0 | if (excluded != NULL) { |
96 | 0 | dns_acl_attach(excluded, &dns64->excluded); |
97 | 0 | } |
98 | 0 | dns64->prefixlen = prefixlen; |
99 | 0 | dns64->flags = flags; |
100 | 0 | ISC_LINK_INIT(dns64, link); |
101 | 0 | dns64->mctx = NULL; |
102 | 0 | isc_mem_attach(mctx, &dns64->mctx); |
103 | 0 | *dns64p = dns64; |
104 | 0 | } |
105 | | |
106 | | void |
107 | 0 | dns_dns64_destroy(dns_dns64list_t *list, dns_dns64_t **dns64p) { |
108 | 0 | dns_dns64_t *dns64; |
109 | |
|
110 | 0 | REQUIRE(dns64p != NULL && *dns64p != NULL); |
111 | |
|
112 | 0 | dns64 = *dns64p; |
113 | 0 | *dns64p = NULL; |
114 | |
|
115 | 0 | ISC_LIST_UNLINK(*list, dns64, link); |
116 | |
|
117 | 0 | if (dns64->clients != NULL) { |
118 | 0 | dns_acl_detach(&dns64->clients); |
119 | 0 | } |
120 | 0 | if (dns64->mapped != NULL) { |
121 | 0 | dns_acl_detach(&dns64->mapped); |
122 | 0 | } |
123 | 0 | if (dns64->excluded != NULL) { |
124 | 0 | dns_acl_detach(&dns64->excluded); |
125 | 0 | } |
126 | 0 | isc_mem_putanddetach(&dns64->mctx, dns64, sizeof(*dns64)); |
127 | 0 | } |
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, dns_aclenv_t *env, |
132 | 0 | unsigned int flags, unsigned char *a, unsigned char *aaaa) { |
133 | 0 | unsigned int nbytes, i; |
134 | 0 | int match; |
135 | |
|
136 | 0 | if ((dns64->flags & DNS_DNS64_RECURSIVE_ONLY) != 0 && |
137 | 0 | (flags & DNS_DNS64_RECURSIVE) == 0) |
138 | 0 | { |
139 | 0 | return DNS_R_DISALLOWED; |
140 | 0 | } |
141 | | |
142 | 0 | if ((dns64->flags & DNS_DNS64_BREAK_DNSSEC) == 0 && |
143 | 0 | (flags & DNS_DNS64_DNSSEC) != 0) |
144 | 0 | { |
145 | 0 | return DNS_R_DISALLOWED; |
146 | 0 | } |
147 | | |
148 | 0 | if (dns64->clients != NULL && reqaddr != NULL) { |
149 | 0 | RETERR(dns_acl_match(reqaddr, reqsigner, dns64->clients, env, |
150 | 0 | &match, NULL)); |
151 | 0 | if (match <= 0) { |
152 | 0 | return DNS_R_DISALLOWED; |
153 | 0 | } |
154 | 0 | } |
155 | | |
156 | 0 | if (dns64->mapped != NULL) { |
157 | 0 | struct in_addr ina; |
158 | 0 | isc_netaddr_t netaddr; |
159 | |
|
160 | 0 | memmove(&ina.s_addr, a, 4); |
161 | 0 | isc_netaddr_fromin(&netaddr, &ina); |
162 | 0 | RETERR(dns_acl_match(&netaddr, NULL, dns64->mapped, env, &match, |
163 | 0 | NULL)); |
164 | 0 | if (match <= 0) { |
165 | 0 | return DNS_R_DISALLOWED; |
166 | 0 | } |
167 | 0 | } |
168 | | |
169 | 0 | nbytes = dns64->prefixlen / 8; |
170 | 0 | INSIST(nbytes <= 12); |
171 | | /* Copy prefix. */ |
172 | 0 | memmove(aaaa, dns64->bits, nbytes); |
173 | | /* Bits 64-71 are zeros. rfc6052.txt */ |
174 | 0 | if (nbytes == 8) { |
175 | 0 | aaaa[nbytes++] = 0; |
176 | 0 | } |
177 | | /* Copy mapped address. */ |
178 | 0 | for (i = 0; i < 4U; i++) { |
179 | 0 | aaaa[nbytes++] = a[i]; |
180 | | /* Bits 64-71 are zeros. rfc6052.txt */ |
181 | 0 | if (nbytes == 8) { |
182 | 0 | aaaa[nbytes++] = 0; |
183 | 0 | } |
184 | 0 | } |
185 | | /* Copy suffix. */ |
186 | 0 | memmove(aaaa + nbytes, dns64->bits + nbytes, 16 - nbytes); |
187 | 0 | return ISC_R_SUCCESS; |
188 | 0 | } |
189 | | |
190 | | void |
191 | 0 | dns_dns64_append(dns_dns64list_t *list, dns_dns64_t *dns64) { |
192 | 0 | ISC_LIST_APPEND(*list, dns64, link); |
193 | 0 | } |
194 | | |
195 | | bool |
196 | | dns_dns64_aaaaok(const dns_dns64_t *dns64, const isc_netaddr_t *reqaddr, |
197 | | const dns_name_t *reqsigner, dns_aclenv_t *env, |
198 | | unsigned int flags, dns_rdataset_t *rdataset, bool *aaaaok, |
199 | 0 | size_t aaaaoklen) { |
200 | 0 | struct in6_addr in6; |
201 | 0 | isc_netaddr_t netaddr; |
202 | 0 | isc_result_t result; |
203 | 0 | int match; |
204 | 0 | bool answer = false; |
205 | 0 | bool found = false; |
206 | 0 | unsigned int i, ok; |
207 | |
|
208 | 0 | REQUIRE(rdataset != NULL); |
209 | 0 | REQUIRE(rdataset->type == dns_rdatatype_aaaa); |
210 | 0 | REQUIRE(rdataset->rdclass == dns_rdataclass_in); |
211 | 0 | if (aaaaok != NULL) { |
212 | 0 | REQUIRE(aaaaoklen == dns_rdataset_count(rdataset)); |
213 | 0 | } |
214 | |
|
215 | 0 | for (; dns64 != NULL; dns64 = ISC_LIST_NEXT(dns64, link)) { |
216 | 0 | if ((dns64->flags & DNS_DNS64_RECURSIVE_ONLY) != 0 && |
217 | 0 | (flags & DNS_DNS64_RECURSIVE) == 0) |
218 | 0 | { |
219 | 0 | continue; |
220 | 0 | } |
221 | | |
222 | 0 | if ((dns64->flags & DNS_DNS64_BREAK_DNSSEC) == 0 && |
223 | 0 | (flags & DNS_DNS64_DNSSEC) != 0) |
224 | 0 | { |
225 | 0 | continue; |
226 | 0 | } |
227 | | /* |
228 | | * Work out if this dns64 structure applies to this client. |
229 | | */ |
230 | 0 | if (dns64->clients != NULL) { |
231 | 0 | result = dns_acl_match(reqaddr, reqsigner, |
232 | 0 | dns64->clients, env, &match, |
233 | 0 | NULL); |
234 | 0 | if (result != ISC_R_SUCCESS) { |
235 | 0 | continue; |
236 | 0 | } |
237 | 0 | if (match <= 0) { |
238 | 0 | continue; |
239 | 0 | } |
240 | 0 | } |
241 | | |
242 | 0 | if (!found && aaaaok != NULL) { |
243 | 0 | for (i = 0; i < aaaaoklen; i++) { |
244 | 0 | aaaaok[i] = false; |
245 | 0 | } |
246 | 0 | } |
247 | 0 | found = true; |
248 | | |
249 | | /* |
250 | | * If we are not excluding any addresses then any AAAA |
251 | | * will do. |
252 | | */ |
253 | 0 | if (dns64->excluded == NULL) { |
254 | 0 | answer = true; |
255 | 0 | if (aaaaok == NULL) { |
256 | 0 | goto done; |
257 | 0 | } |
258 | 0 | for (i = 0; i < aaaaoklen; i++) { |
259 | 0 | aaaaok[i] = true; |
260 | 0 | } |
261 | 0 | goto done; |
262 | 0 | } |
263 | | |
264 | 0 | i = 0; |
265 | 0 | ok = 0; |
266 | 0 | DNS_RDATASET_FOREACH(rdataset) { |
267 | 0 | dns_rdata_t rdata = DNS_RDATA_INIT; |
268 | 0 | if (aaaaok == NULL || !aaaaok[i]) { |
269 | 0 | dns_rdataset_current(rdataset, &rdata); |
270 | 0 | memmove(&in6.s6_addr, rdata.data, 16); |
271 | 0 | isc_netaddr_fromin6(&netaddr, &in6); |
272 | |
|
273 | 0 | result = dns_acl_match(&netaddr, NULL, |
274 | 0 | dns64->excluded, env, |
275 | 0 | &match, NULL); |
276 | 0 | if (result == ISC_R_SUCCESS && match <= 0) { |
277 | 0 | answer = true; |
278 | 0 | if (aaaaok == NULL) { |
279 | 0 | goto done; |
280 | 0 | } |
281 | 0 | aaaaok[i] = true; |
282 | 0 | ok++; |
283 | 0 | } |
284 | 0 | } else { |
285 | 0 | ok++; |
286 | 0 | } |
287 | 0 | i++; |
288 | 0 | } |
289 | | /* |
290 | | * Are all addresses ok? |
291 | | */ |
292 | 0 | if (aaaaok != NULL && ok == aaaaoklen) { |
293 | 0 | goto done; |
294 | 0 | } |
295 | 0 | } |
296 | | |
297 | 0 | done: |
298 | 0 | if (!found && aaaaok != NULL) { |
299 | 0 | for (i = 0; i < aaaaoklen; i++) { |
300 | 0 | aaaaok[i] = true; |
301 | 0 | } |
302 | 0 | } |
303 | 0 | return found ? answer : true; |
304 | 0 | } |
305 | | |
306 | | /* |
307 | | * Posible mapping of IPV4ONLY.ARPA A records into AAAA records |
308 | | * for valid RFC6052 prefixes. |
309 | | */ |
310 | | static struct { |
311 | | const unsigned char aa[16]; /* mapped version of 192.0.0.170 */ |
312 | | const unsigned char ab[16]; /* mapped version of 192.0.0.171 */ |
313 | | const unsigned char mask[16]; |
314 | | const unsigned int plen; |
315 | | } const prefixes[6] = { |
316 | | { { 0, 0, 0, 0, 192, 0, 0, 170, 0, 0, 0, 0, 0, 0, 0, 0 }, |
317 | | { 0, 0, 0, 0, 192, 0, 0, 171, 0, 0, 0, 0, 0, 0, 0, 0 }, |
318 | | { 0, 0, 0, 0, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0 }, |
319 | | 32 }, |
320 | | { { 0, 0, 0, 0, 0, 192, 0, 0, 0, 170, 0, 0, 0, 0, 0, 0 }, |
321 | | { 0, 0, 0, 0, 0, 192, 0, 0, 0, 171, 0, 0, 0, 0, 0, 0 }, |
322 | | { 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0 }, |
323 | | 40 }, |
324 | | { { 0, 0, 0, 0, 0, 0, 192, 0, 0, 0, 170, 0, 0, 0, 0, 0 }, |
325 | | { 0, 0, 0, 0, 0, 0, 192, 0, 0, 0, 171, 0, 0, 0, 0, 0 }, |
326 | | { 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0 }, |
327 | | 48 }, |
328 | | { { 0, 0, 0, 0, 0, 0, 0, 192, 0, 0, 0, 170, 0, 0, 0, 0 }, |
329 | | { 0, 0, 0, 0, 0, 0, 0, 192, 0, 0, 0, 171, 0, 0, 0, 0 }, |
330 | | { 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 0, 0, 0, 0 }, |
331 | | 56 }, |
332 | | { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 192, 0, 0, 170, 0, 0, 0 }, |
333 | | { 0, 0, 0, 0, 0, 0, 0, 0, 0, 192, 0, 0, 171, 0, 0, 0 }, |
334 | | { 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 0, 0, 0 }, |
335 | | 64 }, |
336 | | { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 192, 0, 0, 170 }, |
337 | | { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 192, 0, 0, 171 }, |
338 | | { 0, 0, 0, 0, 0, 0, 0, 0, 255, 0, 0, 0, 255, 255, 255, 255 }, |
339 | | 96 } |
340 | | }; |
341 | | |
342 | | static unsigned int |
343 | 0 | search(const dns_rdata_t *rd1, const dns_rdata_t *rd2, unsigned int plen) { |
344 | 0 | unsigned int i = 0, j; |
345 | 0 | const unsigned char *c, *m; |
346 | | |
347 | | /* |
348 | | * Resume looking for another aa match? |
349 | | */ |
350 | 0 | if (plen != 0U && rd2 == NULL) { |
351 | 0 | while (i < 6U) { |
352 | | /* Post increment as we resume on next entry. */ |
353 | 0 | if (prefixes[i++].plen == plen) { |
354 | 0 | break; |
355 | 0 | } |
356 | 0 | } |
357 | 0 | } |
358 | |
|
359 | 0 | for (; i < 6U; i++) { |
360 | 0 | j = 0; |
361 | 0 | if (rd2 != NULL) { |
362 | | /* Find the right entry. */ |
363 | 0 | if (prefixes[i].plen != plen) { |
364 | 0 | continue; |
365 | 0 | } |
366 | | /* Does the prefix match? */ |
367 | 0 | while ((j * 8U) < plen) { |
368 | 0 | if (rd1->data[j] != rd2->data[j]) { |
369 | 0 | return 0; |
370 | 0 | } |
371 | 0 | j++; |
372 | 0 | } |
373 | 0 | } |
374 | | |
375 | | /* Match well known mapped addresses. */ |
376 | 0 | c = (rd2 == NULL) ? prefixes[i].aa : prefixes[i].ab; |
377 | 0 | m = prefixes[i].mask; |
378 | 0 | for (; j < 16U; j++) { |
379 | 0 | if ((rd1->data[j] & m[j]) != (c[j] & m[j])) { |
380 | 0 | break; |
381 | 0 | } |
382 | 0 | } |
383 | 0 | if (j == 16U) { |
384 | 0 | return prefixes[i].plen; |
385 | 0 | } |
386 | 0 | if (rd2 != NULL) { |
387 | 0 | return 0; |
388 | 0 | } |
389 | 0 | } |
390 | 0 | return 0; |
391 | 0 | } |
392 | | |
393 | | isc_result_t |
394 | | dns_dns64_findprefix(dns_rdataset_t *rdataset, isc_netprefix_t *prefix, |
395 | 0 | size_t *len) { |
396 | 0 | dns_rdataset_t outer, inner; |
397 | 0 | unsigned int oplen, iplen; |
398 | 0 | size_t count = 0; |
399 | 0 | struct in6_addr ina6; |
400 | |
|
401 | 0 | REQUIRE(prefix != NULL && len != NULL && *len != 0U); |
402 | 0 | REQUIRE(rdataset != NULL && rdataset->type == dns_rdatatype_aaaa); |
403 | |
|
404 | 0 | dns_rdataset_init(&outer); |
405 | 0 | dns_rdataset_init(&inner); |
406 | 0 | dns_rdataset_clone(rdataset, &outer); |
407 | 0 | dns_rdataset_clone(rdataset, &inner); |
408 | |
|
409 | 0 | DNS_RDATASET_FOREACH(&outer) { |
410 | 0 | dns_rdata_t rd1 = DNS_RDATA_INIT; |
411 | 0 | dns_rdataset_current(&outer, &rd1); |
412 | 0 | oplen = 0; |
413 | 0 | resume: |
414 | | /* Look for a 192.0.0.170 match. */ |
415 | 0 | oplen = search(&rd1, NULL, oplen); |
416 | 0 | if (oplen == 0) { |
417 | 0 | continue; |
418 | 0 | } |
419 | | |
420 | | /* Look for the 192.0.0.171 match. */ |
421 | 0 | bool matched = false; |
422 | 0 | DNS_RDATASET_FOREACH(&inner) { |
423 | 0 | dns_rdata_t rd2 = DNS_RDATA_INIT; |
424 | |
|
425 | 0 | dns_rdataset_current(&inner, &rd2); |
426 | 0 | iplen = search(&rd2, &rd1, oplen); |
427 | 0 | if (iplen != 0) { |
428 | 0 | matched = true; |
429 | 0 | INSIST(iplen == oplen); |
430 | 0 | if (count >= *len) { |
431 | 0 | count++; |
432 | 0 | break; |
433 | 0 | } |
434 | | |
435 | | /* We have a prefix. */ |
436 | 0 | memset(ina6.s6_addr, 0, sizeof(ina6.s6_addr)); |
437 | 0 | memmove(ina6.s6_addr, rd1.data, oplen / 8); |
438 | 0 | isc_netaddr_fromin6(&prefix[count].addr, &ina6); |
439 | 0 | prefix[count].prefixlen = oplen; |
440 | 0 | count++; |
441 | 0 | } |
442 | 0 | } |
443 | | /* Didn't find a match look for a different prefix length. */ |
444 | 0 | if (!matched) { |
445 | 0 | goto resume; |
446 | 0 | } |
447 | 0 | } |
448 | 0 | if (count == 0U) { |
449 | 0 | return ISC_R_NOTFOUND; |
450 | 0 | } |
451 | 0 | if (count > *len) { |
452 | 0 | *len = count; |
453 | 0 | return ISC_R_NOSPACE; |
454 | 0 | } |
455 | 0 | *len = count; |
456 | 0 | return ISC_R_SUCCESS; |
457 | 0 | } |
458 | | |
459 | | isc_result_t |
460 | | dns_dns64_apply(isc_mem_t *mctx, dns_dns64list_t dns64s, unsigned int count, |
461 | | dns_message_t *message, dns_aclenv_t *env, isc_sockaddr_t *peer, |
462 | | dns_name_t *reqsigner, unsigned int flags, dns_rdataset_t *a, |
463 | 0 | dns_rdataset_t **aaaap) { |
464 | 0 | isc_result_t result; |
465 | 0 | dns_rdatalist_t *aaaalist = NULL; |
466 | 0 | isc_buffer_t *buffer = NULL; |
467 | 0 | isc_netaddr_t netaddr; |
468 | |
|
469 | 0 | REQUIRE(aaaap != NULL && *aaaap == NULL); |
470 | 0 | REQUIRE(a->type == dns_rdatatype_a); |
471 | |
|
472 | 0 | isc_netaddr_fromsockaddr(&netaddr, peer); |
473 | |
|
474 | 0 | isc_buffer_allocate(mctx, &buffer, count * 16 * dns_rdataset_count(a)); |
475 | |
|
476 | 0 | dns_message_gettemprdatalist(message, &aaaalist); |
477 | 0 | aaaalist->rdclass = dns_rdataclass_in; |
478 | 0 | aaaalist->type = dns_rdatatype_aaaa; |
479 | |
|
480 | 0 | DNS_RDATASET_FOREACH(a) { |
481 | 0 | dns_rdata_t rdata = DNS_RDATA_INIT; |
482 | 0 | dns_rdataset_current(a, &rdata); |
483 | |
|
484 | 0 | ISC_LIST_FOREACH(dns64s, dns64, link) { |
485 | 0 | dns_rdata_t *dns64_rdata = NULL; |
486 | 0 | isc_region_t r; |
487 | |
|
488 | 0 | isc_buffer_availableregion(buffer, &r); |
489 | 0 | INSIST(r.length >= 16); |
490 | 0 | result = dns_dns64_aaaafroma(dns64, &netaddr, reqsigner, |
491 | 0 | env, flags, rdata.data, |
492 | 0 | r.base); |
493 | 0 | if (result != ISC_R_SUCCESS) { |
494 | 0 | continue; |
495 | 0 | } |
496 | 0 | isc_buffer_add(buffer, 16); |
497 | 0 | isc_buffer_remainingregion(buffer, &r); |
498 | 0 | isc_buffer_forward(buffer, 16); |
499 | 0 | dns_message_gettemprdata(message, &dns64_rdata); |
500 | 0 | dns_rdata_fromregion(dns64_rdata, dns_rdataclass_in, |
501 | 0 | dns_rdatatype_aaaa, &r); |
502 | 0 | ISC_LIST_APPEND(aaaalist->rdata, dns64_rdata, link); |
503 | 0 | } |
504 | 0 | } |
505 | |
|
506 | 0 | if (!ISC_LIST_EMPTY(aaaalist->rdata)) { |
507 | 0 | dns_rdataset_t *aaaa = NULL; |
508 | 0 | dns_message_gettemprdataset(message, &aaaa); |
509 | 0 | dns_rdatalist_tordataset(aaaalist, aaaa); |
510 | 0 | dns_message_takebuffer(message, &buffer); |
511 | 0 | aaaa->trust = a->trust; |
512 | 0 | *aaaap = aaaa; |
513 | 0 | return ISC_R_SUCCESS; |
514 | 0 | } |
515 | | |
516 | | /* No applicable dns64; free the resources */ |
517 | 0 | isc_buffer_free(&buffer); |
518 | 0 | ISC_LIST_FOREACH(aaaalist->rdata, rdata, link) { |
519 | 0 | ISC_LIST_UNLINK(aaaalist->rdata, rdata, link); |
520 | 0 | dns_message_puttemprdata(message, &rdata); |
521 | 0 | } |
522 | 0 | dns_message_puttemprdatalist(message, &aaaalist); |
523 | |
|
524 | 0 | return ISC_R_NOMORE; |
525 | 0 | } |