1/* $NetBSD: a6_38.c,v 1.1 2024/02/18 20:57:45 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 25static isc_result_t 26fromtext_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 101static isc_result_t 102totext_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 149static isc_result_t 150fromwire_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 204static isc_result_t 205towire_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 234static int 235compare_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 291static isc_result_t 292fromstruct_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 339static isc_result_t 340tostruct_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 384static void 385freestruct_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 402static isc_result_t 403additionaldata_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 414static isc_result_t 415digest_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 444static bool 445checkowner_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 455static bool 456checknames_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 483static int 484casecompare_in_a6(ARGS_COMPARE) { 485 return (compare_in_a6(rdata1, rdata2)); 486} 487 488#endif /* RDATA_IN_1_A6_38_C */ 489