1 /* $NetBSD: a6_38.c,v 1.8 2022/09/23 12:15:31 christos Exp $ */
2
3 /*
4 * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
5 *
6 * SPDX-License-Identifier: MPL-2.0
7 *
8 * This Source Code Form is subject to the terms of the Mozilla Public
9 * License, v. 2.0. If a copy of the MPL was not distributed with this
10 * file, you can obtain one at https://mozilla.org/MPL/2.0/.
11 *
12 * See the COPYRIGHT file distributed with this work for additional
13 * information regarding copyright ownership.
14 */
15
16 /* RFC2874 */
17
18 #ifndef RDATA_IN_1_A6_28_C
19 #define RDATA_IN_1_A6_28_C
20
21 #include <isc/net.h>
22
23 #define RRTYPE_A6_ATTRIBUTES (0)
24
25 static isc_result_t
fromtext_in_a6(ARGS_FROMTEXT)26 fromtext_in_a6(ARGS_FROMTEXT) {
27 isc_token_t token;
28 unsigned char addr[16];
29 unsigned char prefixlen;
30 unsigned char octets;
31 unsigned char mask;
32 dns_name_t name;
33 isc_buffer_t buffer;
34 bool ok;
35
36 REQUIRE(type == dns_rdatatype_a6);
37 REQUIRE(rdclass == dns_rdataclass_in);
38
39 UNUSED(type);
40 UNUSED(rdclass);
41 UNUSED(callbacks);
42
43 /*
44 * Prefix length.
45 */
46 RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number,
47 false));
48 if (token.value.as_ulong > 128U) {
49 RETTOK(ISC_R_RANGE);
50 }
51
52 prefixlen = (unsigned char)token.value.as_ulong;
53 RETERR(mem_tobuffer(target, &prefixlen, 1));
54
55 /*
56 * Suffix.
57 */
58 if (prefixlen != 128) {
59 /*
60 * Prefix 0..127.
61 */
62 octets = prefixlen / 8;
63 /*
64 * Octets 0..15.
65 */
66 RETERR(isc_lex_getmastertoken(lexer, &token,
67 isc_tokentype_string, false));
68 if (inet_pton(AF_INET6, DNS_AS_STR(token), addr) != 1) {
69 RETTOK(DNS_R_BADAAAA);
70 }
71 mask = 0xff >> (prefixlen % 8);
72 addr[octets] &= mask;
73 RETERR(mem_tobuffer(target, &addr[octets], 16 - octets));
74 }
75
76 if (prefixlen == 0) {
77 return (ISC_R_SUCCESS);
78 }
79
80 RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
81 false));
82 dns_name_init(&name, NULL);
83 buffer_fromregion(&buffer, &token.value.as_region);
84 if (origin == NULL) {
85 origin = dns_rootname;
86 }
87 RETTOK(dns_name_fromtext(&name, &buffer, origin, options, target));
88 ok = true;
89 if ((options & DNS_RDATA_CHECKNAMES) != 0) {
90 ok = dns_name_ishostname(&name, false);
91 }
92 if (!ok && (options & DNS_RDATA_CHECKNAMESFAIL) != 0) {
93 RETTOK(DNS_R_BADNAME);
94 }
95 if (!ok && callbacks != NULL) {
96 warn_badname(&name, lexer, callbacks);
97 }
98 return (ISC_R_SUCCESS);
99 }
100
101 static isc_result_t
totext_in_a6(ARGS_TOTEXT)102 totext_in_a6(ARGS_TOTEXT) {
103 isc_region_t sr, ar;
104 unsigned char addr[16];
105 unsigned char prefixlen;
106 unsigned char octets;
107 unsigned char mask;
108 char buf[sizeof("128")];
109 dns_name_t name;
110 dns_name_t prefix;
111 bool sub;
112
113 REQUIRE(rdata->type == dns_rdatatype_a6);
114 REQUIRE(rdata->rdclass == dns_rdataclass_in);
115 REQUIRE(rdata->length != 0);
116
117 dns_rdata_toregion(rdata, &sr);
118 prefixlen = sr.base[0];
119 INSIST(prefixlen <= 128);
120 isc_region_consume(&sr, 1);
121 snprintf(buf, sizeof(buf), "%u", prefixlen);
122 RETERR(str_totext(buf, target));
123 RETERR(str_totext(" ", target));
124
125 if (prefixlen != 128) {
126 octets = prefixlen / 8;
127 memset(addr, 0, sizeof(addr));
128 memmove(&addr[octets], sr.base, 16 - octets);
129 mask = 0xff >> (prefixlen % 8);
130 addr[octets] &= mask;
131 ar.base = addr;
132 ar.length = sizeof(addr);
133 RETERR(inet_totext(AF_INET6, tctx->flags, &ar, target));
134 isc_region_consume(&sr, 16 - octets);
135 }
136
137 if (prefixlen == 0) {
138 return (ISC_R_SUCCESS);
139 }
140
141 RETERR(str_totext(" ", target));
142 dns_name_init(&name, NULL);
143 dns_name_init(&prefix, NULL);
144 dns_name_fromregion(&name, &sr);
145 sub = name_prefix(&name, tctx->origin, &prefix);
146 return (dns_name_totext(&prefix, sub, target));
147 }
148
149 static isc_result_t
fromwire_in_a6(ARGS_FROMWIRE)150 fromwire_in_a6(ARGS_FROMWIRE) {
151 isc_region_t sr;
152 unsigned char prefixlen;
153 unsigned char octets;
154 unsigned char mask;
155 dns_name_t name;
156
157 REQUIRE(type == dns_rdatatype_a6);
158 REQUIRE(rdclass == dns_rdataclass_in);
159
160 UNUSED(type);
161 UNUSED(rdclass);
162
163 dns_decompress_setmethods(dctx, DNS_COMPRESS_NONE);
164
165 isc_buffer_activeregion(source, &sr);
166 /*
167 * Prefix length.
168 */
169 if (sr.length < 1) {
170 return (ISC_R_UNEXPECTEDEND);
171 }
172 prefixlen = sr.base[0];
173 if (prefixlen > 128) {
174 return (ISC_R_RANGE);
175 }
176 isc_region_consume(&sr, 1);
177 RETERR(mem_tobuffer(target, &prefixlen, 1));
178 isc_buffer_forward(source, 1);
179
180 /*
181 * Suffix.
182 */
183 if (prefixlen != 128) {
184 octets = 16 - prefixlen / 8;
185 if (sr.length < octets) {
186 return (ISC_R_UNEXPECTEDEND);
187 }
188 mask = 0xff >> (prefixlen % 8);
189 if ((sr.base[0] & ~mask) != 0) {
190 return (DNS_R_FORMERR);
191 }
192 RETERR(mem_tobuffer(target, sr.base, octets));
193 isc_buffer_forward(source, octets);
194 }
195
196 if (prefixlen == 0) {
197 return (ISC_R_SUCCESS);
198 }
199
200 dns_name_init(&name, NULL);
201 return (dns_name_fromwire(&name, source, dctx, options, target));
202 }
203
204 static isc_result_t
towire_in_a6(ARGS_TOWIRE)205 towire_in_a6(ARGS_TOWIRE) {
206 isc_region_t sr;
207 dns_name_t name;
208 dns_offsets_t offsets;
209 unsigned char prefixlen;
210 unsigned char octets;
211
212 REQUIRE(rdata->type == dns_rdatatype_a6);
213 REQUIRE(rdata->rdclass == dns_rdataclass_in);
214 REQUIRE(rdata->length != 0);
215
216 dns_compress_setmethods(cctx, DNS_COMPRESS_NONE);
217 dns_rdata_toregion(rdata, &sr);
218 prefixlen = sr.base[0];
219 INSIST(prefixlen <= 128);
220
221 octets = 1 + 16 - prefixlen / 8;
222 RETERR(mem_tobuffer(target, sr.base, octets));
223 isc_region_consume(&sr, octets);
224
225 if (prefixlen == 0) {
226 return (ISC_R_SUCCESS);
227 }
228
229 dns_name_init(&name, offsets);
230 dns_name_fromregion(&name, &sr);
231 return (dns_name_towire(&name, cctx, target));
232 }
233
234 static int
compare_in_a6(ARGS_COMPARE)235 compare_in_a6(ARGS_COMPARE) {
236 int order;
237 unsigned char prefixlen1, prefixlen2;
238 unsigned char octets;
239 dns_name_t name1;
240 dns_name_t name2;
241 isc_region_t region1;
242 isc_region_t region2;
243
244 REQUIRE(rdata1->type == rdata2->type);
245 REQUIRE(rdata1->rdclass == rdata2->rdclass);
246 REQUIRE(rdata1->type == dns_rdatatype_a6);
247 REQUIRE(rdata1->rdclass == dns_rdataclass_in);
248 REQUIRE(rdata1->length != 0);
249 REQUIRE(rdata2->length != 0);
250
251 dns_rdata_toregion(rdata1, ®ion1);
252 dns_rdata_toregion(rdata2, ®ion2);
253 prefixlen1 = region1.base[0];
254 prefixlen2 = region2.base[0];
255 isc_region_consume(®ion1, 1);
256 isc_region_consume(®ion2, 1);
257 if (prefixlen1 < prefixlen2) {
258 return (-1);
259 } else if (prefixlen1 > prefixlen2) {
260 return (1);
261 }
262 /*
263 * Prefix lengths are equal.
264 */
265 octets = 16 - prefixlen1 / 8;
266
267 if (octets > 0) {
268 order = memcmp(region1.base, region2.base, octets);
269 if (order < 0) {
270 return (-1);
271 } else if (order > 0) {
272 return (1);
273 }
274 /*
275 * Address suffixes are equal.
276 */
277 if (prefixlen1 == 0) {
278 return (order);
279 }
280 isc_region_consume(®ion1, octets);
281 isc_region_consume(®ion2, octets);
282 }
283
284 dns_name_init(&name1, NULL);
285 dns_name_init(&name2, NULL);
286 dns_name_fromregion(&name1, ®ion1);
287 dns_name_fromregion(&name2, ®ion2);
288 return (dns_name_rdatacompare(&name1, &name2));
289 }
290
291 static isc_result_t
fromstruct_in_a6(ARGS_FROMSTRUCT)292 fromstruct_in_a6(ARGS_FROMSTRUCT) {
293 dns_rdata_in_a6_t *a6 = source;
294 isc_region_t region;
295 int octets;
296 uint8_t bits;
297 uint8_t first;
298 uint8_t mask;
299
300 REQUIRE(type == dns_rdatatype_a6);
301 REQUIRE(rdclass == dns_rdataclass_in);
302 REQUIRE(a6 != NULL);
303 REQUIRE(a6->common.rdtype == type);
304 REQUIRE(a6->common.rdclass == rdclass);
305
306 UNUSED(type);
307 UNUSED(rdclass);
308
309 if (a6->prefixlen > 128) {
310 return (ISC_R_RANGE);
311 }
312
313 RETERR(uint8_tobuffer(a6->prefixlen, target));
314
315 /* Suffix */
316 if (a6->prefixlen != 128) {
317 octets = 16 - a6->prefixlen / 8;
318 bits = a6->prefixlen % 8;
319 if (bits != 0) {
320 mask = 0xffU >> bits;
321 first = a6->in6_addr.s6_addr[16 - octets] & mask;
322 RETERR(uint8_tobuffer(first, target));
323 octets--;
324 }
325 if (octets > 0) {
326 RETERR(mem_tobuffer(target,
327 a6->in6_addr.s6_addr + 16 - octets,
328 octets));
329 }
330 }
331
332 if (a6->prefixlen == 0) {
333 return (ISC_R_SUCCESS);
334 }
335 dns_name_toregion(&a6->prefix, ®ion);
336 return (isc_buffer_copyregion(target, ®ion));
337 }
338
339 static isc_result_t
tostruct_in_a6(ARGS_TOSTRUCT)340 tostruct_in_a6(ARGS_TOSTRUCT) {
341 dns_rdata_in_a6_t *a6 = target;
342 unsigned char octets;
343 dns_name_t name;
344 isc_region_t r;
345
346 REQUIRE(rdata->type == dns_rdatatype_a6);
347 REQUIRE(rdata->rdclass == dns_rdataclass_in);
348 REQUIRE(a6 != NULL);
349 REQUIRE(rdata->length != 0);
350
351 a6->common.rdclass = rdata->rdclass;
352 a6->common.rdtype = rdata->type;
353 ISC_LINK_INIT(&a6->common, link);
354
355 dns_rdata_toregion(rdata, &r);
356
357 a6->prefixlen = uint8_fromregion(&r);
358 isc_region_consume(&r, 1);
359 memset(a6->in6_addr.s6_addr, 0, sizeof(a6->in6_addr.s6_addr));
360
361 /*
362 * Suffix.
363 */
364 if (a6->prefixlen != 128) {
365 octets = 16 - a6->prefixlen / 8;
366 INSIST(r.length >= octets);
367 memmove(a6->in6_addr.s6_addr + 16 - octets, r.base, octets);
368 isc_region_consume(&r, octets);
369 }
370
371 /*
372 * Prefix.
373 */
374 dns_name_init(&a6->prefix, NULL);
375 if (a6->prefixlen != 0) {
376 dns_name_init(&name, NULL);
377 dns_name_fromregion(&name, &r);
378 RETERR(name_duporclone(&name, mctx, &a6->prefix));
379 }
380 a6->mctx = mctx;
381 return (ISC_R_SUCCESS);
382 }
383
384 static void
freestruct_in_a6(ARGS_FREESTRUCT)385 freestruct_in_a6(ARGS_FREESTRUCT) {
386 dns_rdata_in_a6_t *a6 = source;
387
388 REQUIRE(a6 != NULL);
389 REQUIRE(a6->common.rdclass == dns_rdataclass_in);
390 REQUIRE(a6->common.rdtype == dns_rdatatype_a6);
391
392 if (a6->mctx == NULL) {
393 return;
394 }
395
396 if (dns_name_dynamic(&a6->prefix)) {
397 dns_name_free(&a6->prefix, a6->mctx);
398 }
399 a6->mctx = NULL;
400 }
401
402 static isc_result_t
additionaldata_in_a6(ARGS_ADDLDATA)403 additionaldata_in_a6(ARGS_ADDLDATA) {
404 REQUIRE(rdata->type == dns_rdatatype_a6);
405 REQUIRE(rdata->rdclass == dns_rdataclass_in);
406
407 UNUSED(rdata);
408 UNUSED(add);
409 UNUSED(arg);
410
411 return (ISC_R_SUCCESS);
412 }
413
414 static isc_result_t
digest_in_a6(ARGS_DIGEST)415 digest_in_a6(ARGS_DIGEST) {
416 isc_region_t r1, r2;
417 unsigned char prefixlen, octets;
418 isc_result_t result;
419 dns_name_t name;
420
421 REQUIRE(rdata->type == dns_rdatatype_a6);
422 REQUIRE(rdata->rdclass == dns_rdataclass_in);
423
424 dns_rdata_toregion(rdata, &r1);
425 r2 = r1;
426 prefixlen = r1.base[0];
427 octets = 1 + 16 - prefixlen / 8;
428
429 r1.length = octets;
430 result = (digest)(arg, &r1);
431 if (result != ISC_R_SUCCESS) {
432 return (result);
433 }
434 if (prefixlen == 0) {
435 return (ISC_R_SUCCESS);
436 }
437
438 isc_region_consume(&r2, octets);
439 dns_name_init(&name, NULL);
440 dns_name_fromregion(&name, &r2);
441 return (dns_name_digest(&name, digest, arg));
442 }
443
444 static bool
checkowner_in_a6(ARGS_CHECKOWNER)445 checkowner_in_a6(ARGS_CHECKOWNER) {
446 REQUIRE(type == dns_rdatatype_a6);
447 REQUIRE(rdclass == dns_rdataclass_in);
448
449 UNUSED(type);
450 UNUSED(rdclass);
451
452 return (dns_name_ishostname(name, wildcard));
453 }
454
455 static bool
checknames_in_a6(ARGS_CHECKNAMES)456 checknames_in_a6(ARGS_CHECKNAMES) {
457 isc_region_t region;
458 dns_name_t name;
459 unsigned int prefixlen;
460
461 REQUIRE(rdata->type == dns_rdatatype_a6);
462 REQUIRE(rdata->rdclass == dns_rdataclass_in);
463
464 UNUSED(owner);
465
466 dns_rdata_toregion(rdata, ®ion);
467 prefixlen = uint8_fromregion(®ion);
468 if (prefixlen == 0) {
469 return (true);
470 }
471 isc_region_consume(®ion, 1 + 16 - prefixlen / 8);
472 dns_name_init(&name, NULL);
473 dns_name_fromregion(&name, ®ion);
474 if (!dns_name_ishostname(&name, false)) {
475 if (bad != NULL) {
476 dns_name_clone(&name, bad);
477 }
478 return (false);
479 }
480 return (true);
481 }
482
483 static int
casecompare_in_a6(ARGS_COMPARE)484 casecompare_in_a6(ARGS_COMPARE) {
485 return (compare_in_a6(rdata1, rdata2));
486 }
487
488 #endif /* RDATA_IN_1_A6_38_C */
489