1 /* $NetBSD: caa_257.c,v 1.10 2025/01/26 16:25:30 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 #ifndef GENERIC_CAA_257_C 17 #define GENERIC_CAA_257_C 1 18 19 #define RRTYPE_CAA_ATTRIBUTES (0) 20 21 static unsigned char const alphanumeric[256] = { 22 /* 0x00-0x0f */ 0, 23 0, 24 0, 25 0, 26 0, 27 0, 28 0, 29 0, 30 0, 31 0, 32 0, 33 0, 34 0, 35 0, 36 0, 37 0, 38 /* 0x10-0x1f */ 0, 39 0, 40 0, 41 0, 42 0, 43 0, 44 0, 45 0, 46 0, 47 0, 48 0, 49 0, 50 0, 51 0, 52 0, 53 0, 54 /* 0x20-0x2f */ 0, 55 0, 56 0, 57 0, 58 0, 59 0, 60 0, 61 0, 62 0, 63 0, 64 0, 65 0, 66 0, 67 0, 68 0, 69 0, 70 /* 0x30-0x3f */ 1, 71 1, 72 1, 73 1, 74 1, 75 1, 76 1, 77 1, 78 1, 79 1, 80 0, 81 0, 82 0, 83 0, 84 0, 85 0, 86 /* 0x40-0x4f */ 0, 87 1, 88 1, 89 1, 90 1, 91 1, 92 1, 93 1, 94 1, 95 1, 96 1, 97 1, 98 1, 99 1, 100 1, 101 1, 102 /* 0x50-0x5f */ 1, 103 1, 104 1, 105 1, 106 1, 107 1, 108 1, 109 1, 110 1, 111 1, 112 1, 113 0, 114 0, 115 0, 116 0, 117 0, 118 /* 0x60-0x6f */ 0, 119 1, 120 1, 121 1, 122 1, 123 1, 124 1, 125 1, 126 1, 127 1, 128 1, 129 1, 130 1, 131 1, 132 1, 133 1, 134 /* 0x70-0x7f */ 1, 135 1, 136 1, 137 1, 138 1, 139 1, 140 1, 141 1, 142 1, 143 1, 144 1, 145 0, 146 0, 147 0, 148 0, 149 0, 150 /* 0x80-0x8f */ 0, 151 0, 152 0, 153 0, 154 0, 155 0, 156 0, 157 0, 158 0, 159 0, 160 0, 161 0, 162 0, 163 0, 164 0, 165 0, 166 /* 0x90-0x9f */ 0, 167 0, 168 0, 169 0, 170 0, 171 0, 172 0, 173 0, 174 0, 175 0, 176 0, 177 0, 178 0, 179 0, 180 0, 181 0, 182 /* 0xa0-0xaf */ 0, 183 0, 184 0, 185 0, 186 0, 187 0, 188 0, 189 0, 190 0, 191 0, 192 0, 193 0, 194 0, 195 0, 196 0, 197 0, 198 /* 0xb0-0xbf */ 0, 199 0, 200 0, 201 0, 202 0, 203 0, 204 0, 205 0, 206 0, 207 0, 208 0, 209 0, 210 0, 211 0, 212 0, 213 0, 214 /* 0xc0-0xcf */ 0, 215 0, 216 0, 217 0, 218 0, 219 0, 220 0, 221 0, 222 0, 223 0, 224 0, 225 0, 226 0, 227 0, 228 0, 229 0, 230 /* 0xd0-0xdf */ 0, 231 0, 232 0, 233 0, 234 0, 235 0, 236 0, 237 0, 238 0, 239 0, 240 0, 241 0, 242 0, 243 0, 244 0, 245 0, 246 /* 0xe0-0xef */ 0, 247 0, 248 0, 249 0, 250 0, 251 0, 252 0, 253 0, 254 0, 255 0, 256 0, 257 0, 258 0, 259 0, 260 0, 261 0, 262 /* 0xf0-0xff */ 0, 263 0, 264 0, 265 0, 266 0, 267 0, 268 0, 269 0, 270 0, 271 0, 272 0, 273 0, 274 0, 275 0, 276 0, 277 0, 278 }; 279 280 static isc_result_t 281 fromtext_caa(ARGS_FROMTEXT) { 282 isc_token_t token; 283 isc_textregion_t tr; 284 uint8_t flags; 285 unsigned int i; 286 287 REQUIRE(type == dns_rdatatype_caa); 288 289 UNUSED(type); 290 UNUSED(rdclass); 291 UNUSED(origin); 292 UNUSED(options); 293 UNUSED(callbacks); 294 295 /* Flags. */ 296 RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number, 297 false)); 298 if (token.value.as_ulong > 255U) { 299 RETTOK(ISC_R_RANGE); 300 } 301 flags = (uint8_t)(token.value.as_ulong & 255U); 302 RETERR(uint8_tobuffer(flags, target)); 303 304 /* 305 * Tag 306 */ 307 RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string, 308 false)); 309 tr = token.value.as_textregion; 310 for (i = 0; i < tr.length; i++) { 311 if (!alphanumeric[(unsigned char)tr.base[i]]) { 312 RETTOK(DNS_R_SYNTAX); 313 } 314 } 315 RETERR(uint8_tobuffer(tr.length, target)); 316 RETERR(mem_tobuffer(target, tr.base, tr.length)); 317 318 /* 319 * Value 320 */ 321 RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_qstring, 322 false)); 323 if (token.type != isc_tokentype_qstring && 324 token.type != isc_tokentype_string) 325 { 326 RETERR(DNS_R_SYNTAX); 327 } 328 RETERR(multitxt_fromtext(&token.value.as_textregion, target)); 329 return ISC_R_SUCCESS; 330 } 331 332 static isc_result_t 333 totext_caa(ARGS_TOTEXT) { 334 isc_region_t region; 335 uint8_t flags; 336 char buf[256]; 337 338 UNUSED(tctx); 339 340 REQUIRE(rdata->type == dns_rdatatype_caa); 341 REQUIRE(rdata->length >= 3U); 342 REQUIRE(rdata->data != NULL); 343 344 dns_rdata_toregion(rdata, ®ion); 345 346 /* 347 * Flags 348 */ 349 flags = uint8_consume_fromregion(®ion); 350 snprintf(buf, sizeof(buf), "%u ", flags); 351 RETERR(str_totext(buf, target)); 352 353 /* 354 * Tag 355 */ 356 RETERR(txt_totext(®ion, false, target)); 357 RETERR(str_totext(" ", target)); 358 359 /* 360 * Value 361 */ 362 RETERR(multitxt_totext(®ion, target)); 363 return ISC_R_SUCCESS; 364 } 365 366 static isc_result_t 367 fromwire_caa(ARGS_FROMWIRE) { 368 isc_region_t sr; 369 unsigned int len, i; 370 371 REQUIRE(type == dns_rdatatype_caa); 372 373 UNUSED(type); 374 UNUSED(rdclass); 375 UNUSED(dctx); 376 377 /* 378 * Flags 379 */ 380 isc_buffer_activeregion(source, &sr); 381 if (sr.length < 2) { 382 return ISC_R_UNEXPECTEDEND; 383 } 384 385 /* 386 * Flags, tag length 387 */ 388 RETERR(mem_tobuffer(target, sr.base, 2)); 389 len = sr.base[1]; 390 isc_region_consume(&sr, 2); 391 isc_buffer_forward(source, 2); 392 393 /* 394 * Zero length tag fields are illegal. 395 */ 396 if (sr.length < len || len == 0) { 397 RETERR(DNS_R_FORMERR); 398 } 399 400 /* Check the Tag's value */ 401 for (i = 0; i < len; i++) { 402 if (!alphanumeric[sr.base[i]]) { 403 RETERR(DNS_R_FORMERR); 404 /* 405 * Tag + Value 406 */ 407 } 408 } 409 /* 410 * Tag + Value 411 */ 412 isc_buffer_forward(source, sr.length); 413 return mem_tobuffer(target, sr.base, sr.length); 414 } 415 416 static isc_result_t 417 towire_caa(ARGS_TOWIRE) { 418 isc_region_t region; 419 420 REQUIRE(rdata->type == dns_rdatatype_caa); 421 REQUIRE(rdata->length >= 3U); 422 REQUIRE(rdata->data != NULL); 423 424 UNUSED(cctx); 425 426 dns_rdata_toregion(rdata, ®ion); 427 return mem_tobuffer(target, region.base, region.length); 428 } 429 430 static int 431 compare_caa(ARGS_COMPARE) { 432 isc_region_t r1, r2; 433 434 REQUIRE(rdata1->type == rdata2->type); 435 REQUIRE(rdata1->rdclass == rdata2->rdclass); 436 REQUIRE(rdata1->type == dns_rdatatype_caa); 437 REQUIRE(rdata1->length >= 3U); 438 REQUIRE(rdata2->length >= 3U); 439 REQUIRE(rdata1->data != NULL); 440 REQUIRE(rdata2->data != NULL); 441 442 dns_rdata_toregion(rdata1, &r1); 443 dns_rdata_toregion(rdata2, &r2); 444 return isc_region_compare(&r1, &r2); 445 } 446 447 static isc_result_t 448 fromstruct_caa(ARGS_FROMSTRUCT) { 449 dns_rdata_caa_t *caa = source; 450 isc_region_t region; 451 unsigned int i; 452 453 REQUIRE(type == dns_rdatatype_caa); 454 REQUIRE(caa != NULL); 455 REQUIRE(caa->common.rdtype == type); 456 REQUIRE(caa->common.rdclass == rdclass); 457 REQUIRE(caa->tag != NULL && caa->tag_len != 0); 458 REQUIRE(caa->value != NULL); 459 460 UNUSED(type); 461 UNUSED(rdclass); 462 463 /* 464 * Flags 465 */ 466 RETERR(uint8_tobuffer(caa->flags, target)); 467 468 /* 469 * Tag length 470 */ 471 RETERR(uint8_tobuffer(caa->tag_len, target)); 472 473 /* 474 * Tag 475 */ 476 region.base = caa->tag; 477 region.length = caa->tag_len; 478 for (i = 0; i < region.length; i++) { 479 if (!alphanumeric[region.base[i]]) { 480 RETERR(DNS_R_SYNTAX); 481 } 482 } 483 RETERR(isc_buffer_copyregion(target, ®ion)); 484 485 /* 486 * Value 487 */ 488 region.base = caa->value; 489 region.length = caa->value_len; 490 return isc_buffer_copyregion(target, ®ion); 491 } 492 493 static isc_result_t 494 tostruct_caa(ARGS_TOSTRUCT) { 495 dns_rdata_caa_t *caa = target; 496 isc_region_t sr; 497 498 REQUIRE(rdata->type == dns_rdatatype_caa); 499 REQUIRE(caa != NULL); 500 REQUIRE(rdata->length >= 3U); 501 REQUIRE(rdata->data != NULL); 502 503 caa->common.rdclass = rdata->rdclass; 504 caa->common.rdtype = rdata->type; 505 ISC_LINK_INIT(&caa->common, link); 506 507 dns_rdata_toregion(rdata, &sr); 508 509 /* 510 * Flags 511 */ 512 caa->flags = uint8_fromregion(&sr); 513 isc_region_consume(&sr, 1); 514 515 /* 516 * Tag length 517 */ 518 caa->tag_len = uint8_fromregion(&sr); 519 isc_region_consume(&sr, 1); 520 521 /* 522 * Tag 523 */ 524 INSIST(sr.length >= caa->tag_len); 525 caa->tag = mem_maybedup(mctx, sr.base, caa->tag_len); 526 isc_region_consume(&sr, caa->tag_len); 527 528 /* 529 * Value 530 */ 531 caa->value_len = sr.length; 532 caa->value = mem_maybedup(mctx, sr.base, sr.length); 533 534 caa->mctx = mctx; 535 return ISC_R_SUCCESS; 536 } 537 538 static void 539 freestruct_caa(ARGS_FREESTRUCT) { 540 dns_rdata_caa_t *caa = (dns_rdata_caa_t *)source; 541 542 REQUIRE(caa != NULL); 543 REQUIRE(caa->common.rdtype == dns_rdatatype_caa); 544 545 if (caa->mctx == NULL) { 546 return; 547 } 548 549 if (caa->tag != NULL) { 550 isc_mem_free(caa->mctx, caa->tag); 551 } 552 if (caa->value != NULL) { 553 isc_mem_free(caa->mctx, caa->value); 554 } 555 caa->mctx = NULL; 556 } 557 558 static isc_result_t 559 additionaldata_caa(ARGS_ADDLDATA) { 560 REQUIRE(rdata->type == dns_rdatatype_caa); 561 REQUIRE(rdata->data != NULL); 562 REQUIRE(rdata->length >= 3U); 563 564 UNUSED(rdata); 565 UNUSED(owner); 566 UNUSED(add); 567 UNUSED(arg); 568 569 return ISC_R_SUCCESS; 570 } 571 572 static isc_result_t 573 digest_caa(ARGS_DIGEST) { 574 isc_region_t r; 575 576 REQUIRE(rdata->type == dns_rdatatype_caa); 577 REQUIRE(rdata->data != NULL); 578 REQUIRE(rdata->length >= 3U); 579 580 dns_rdata_toregion(rdata, &r); 581 582 return (digest)(arg, &r); 583 } 584 585 static bool 586 checkowner_caa(ARGS_CHECKOWNER) { 587 REQUIRE(type == dns_rdatatype_caa); 588 589 UNUSED(name); 590 UNUSED(type); 591 UNUSED(rdclass); 592 UNUSED(wildcard); 593 594 return true; 595 } 596 597 static bool 598 checknames_caa(ARGS_CHECKNAMES) { 599 REQUIRE(rdata->type == dns_rdatatype_caa); 600 REQUIRE(rdata->data != NULL); 601 REQUIRE(rdata->length >= 3U); 602 603 UNUSED(rdata); 604 UNUSED(owner); 605 UNUSED(bad); 606 607 return true; 608 } 609 610 static int 611 casecompare_caa(ARGS_COMPARE) { 612 return compare_caa(rdata1, rdata2); 613 } 614 615 #endif /* GENERIC_CAA_257_C */ 616