1 /* $NetBSD: naptr_35.c,v 1.8 2024/02/21 22:52:13 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 /* RFC2915 */ 17 18 #ifndef RDATA_GENERIC_NAPTR_35_C 19 #define RDATA_GENERIC_NAPTR_35_C 20 21 #define RRTYPE_NAPTR_ATTRIBUTES (0) 22 23 #include <isc/regex.h> 24 25 /* 26 * Check the wire format of the Regexp field. 27 * Don't allow embedded NUL's. 28 */ 29 static isc_result_t 30 txt_valid_regex(const unsigned char *txt) { 31 unsigned int nsub = 0; 32 char regex[256]; 33 char *cp; 34 bool flags = false; 35 bool replace = false; 36 unsigned char c; 37 unsigned char delim; 38 unsigned int len; 39 int n; 40 41 len = *txt++; 42 if (len == 0U) { 43 return (ISC_R_SUCCESS); 44 } 45 46 delim = *txt++; 47 len--; 48 49 /* 50 * Digits, backslash and flags can't be delimiters. 51 */ 52 switch (delim) { 53 case '0': 54 case '1': 55 case '2': 56 case '3': 57 case '4': 58 case '5': 59 case '6': 60 case '7': 61 case '8': 62 case '9': 63 case '\\': 64 case 'i': 65 case 0: 66 return (DNS_R_SYNTAX); 67 } 68 69 cp = regex; 70 while (len-- > 0) { 71 c = *txt++; 72 if (c == 0) { 73 return (DNS_R_SYNTAX); 74 } 75 if (c == delim && !replace) { 76 replace = true; 77 continue; 78 } else if (c == delim && !flags) { 79 flags = true; 80 continue; 81 } else if (c == delim) { 82 return (DNS_R_SYNTAX); 83 } 84 /* 85 * Flags are not escaped. 86 */ 87 if (flags) { 88 switch (c) { 89 case 'i': 90 continue; 91 default: 92 return (DNS_R_SYNTAX); 93 } 94 } 95 if (!replace) { 96 *cp++ = c; 97 } 98 if (c == '\\') { 99 if (len == 0) { 100 return (DNS_R_SYNTAX); 101 } 102 c = *txt++; 103 if (c == 0) { 104 return (DNS_R_SYNTAX); 105 } 106 len--; 107 if (replace) { 108 switch (c) { 109 case '0': 110 return (DNS_R_SYNTAX); 111 case '1': 112 if (nsub < 1) { 113 nsub = 1; 114 } 115 break; 116 case '2': 117 if (nsub < 2) { 118 nsub = 2; 119 } 120 break; 121 case '3': 122 if (nsub < 3) { 123 nsub = 3; 124 } 125 break; 126 case '4': 127 if (nsub < 4) { 128 nsub = 4; 129 } 130 break; 131 case '5': 132 if (nsub < 5) { 133 nsub = 5; 134 } 135 break; 136 case '6': 137 if (nsub < 6) { 138 nsub = 6; 139 } 140 break; 141 case '7': 142 if (nsub < 7) { 143 nsub = 7; 144 } 145 break; 146 case '8': 147 if (nsub < 8) { 148 nsub = 8; 149 } 150 break; 151 case '9': 152 if (nsub < 9) { 153 nsub = 9; 154 } 155 break; 156 } 157 } 158 if (!replace) { 159 *cp++ = c; 160 } 161 } 162 } 163 if (!flags) { 164 return (DNS_R_SYNTAX); 165 } 166 *cp = '\0'; 167 n = isc_regex_validate(regex); 168 if (n < 0 || nsub > (unsigned int)n) { 169 return (DNS_R_SYNTAX); 170 } 171 return (ISC_R_SUCCESS); 172 } 173 174 static isc_result_t 175 fromtext_naptr(ARGS_FROMTEXT) { 176 isc_token_t token; 177 dns_name_t name; 178 isc_buffer_t buffer; 179 unsigned char *regex; 180 181 REQUIRE(type == dns_rdatatype_naptr); 182 183 UNUSED(type); 184 UNUSED(rdclass); 185 UNUSED(callbacks); 186 187 /* 188 * Order. 189 */ 190 RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number, 191 false)); 192 if (token.value.as_ulong > 0xffffU) { 193 RETTOK(ISC_R_RANGE); 194 } 195 RETERR(uint16_tobuffer(token.value.as_ulong, target)); 196 197 /* 198 * Preference. 199 */ 200 RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number, 201 false)); 202 if (token.value.as_ulong > 0xffffU) { 203 RETTOK(ISC_R_RANGE); 204 } 205 RETERR(uint16_tobuffer(token.value.as_ulong, target)); 206 207 /* 208 * Flags. 209 */ 210 RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_qstring, 211 false)); 212 RETTOK(txt_fromtext(&token.value.as_textregion, target)); 213 214 /* 215 * Service. 216 */ 217 RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_qstring, 218 false)); 219 RETTOK(txt_fromtext(&token.value.as_textregion, target)); 220 221 /* 222 * Regexp. 223 */ 224 regex = isc_buffer_used(target); 225 RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_qstring, 226 false)); 227 RETTOK(txt_fromtext(&token.value.as_textregion, target)); 228 RETTOK(txt_valid_regex(regex)); 229 230 /* 231 * Replacement. 232 */ 233 RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string, 234 false)); 235 dns_name_init(&name, NULL); 236 buffer_fromregion(&buffer, &token.value.as_region); 237 if (origin == NULL) { 238 origin = dns_rootname; 239 } 240 RETTOK(dns_name_fromtext(&name, &buffer, origin, options, target)); 241 return (ISC_R_SUCCESS); 242 } 243 244 static isc_result_t 245 totext_naptr(ARGS_TOTEXT) { 246 isc_region_t region; 247 dns_name_t name; 248 dns_name_t prefix; 249 bool sub; 250 char buf[sizeof("64000")]; 251 unsigned short num; 252 253 REQUIRE(rdata->type == dns_rdatatype_naptr); 254 REQUIRE(rdata->length != 0); 255 256 dns_name_init(&name, NULL); 257 dns_name_init(&prefix, NULL); 258 259 dns_rdata_toregion(rdata, ®ion); 260 261 /* 262 * Order. 263 */ 264 num = uint16_fromregion(®ion); 265 isc_region_consume(®ion, 2); 266 snprintf(buf, sizeof(buf), "%u", num); 267 RETERR(str_totext(buf, target)); 268 RETERR(str_totext(" ", target)); 269 270 /* 271 * Preference. 272 */ 273 num = uint16_fromregion(®ion); 274 isc_region_consume(®ion, 2); 275 snprintf(buf, sizeof(buf), "%u", num); 276 RETERR(str_totext(buf, target)); 277 RETERR(str_totext(" ", target)); 278 279 /* 280 * Flags. 281 */ 282 RETERR(txt_totext(®ion, true, target)); 283 RETERR(str_totext(" ", target)); 284 285 /* 286 * Service. 287 */ 288 RETERR(txt_totext(®ion, true, target)); 289 RETERR(str_totext(" ", target)); 290 291 /* 292 * Regexp. 293 */ 294 RETERR(txt_totext(®ion, true, target)); 295 RETERR(str_totext(" ", target)); 296 297 /* 298 * Replacement. 299 */ 300 dns_name_fromregion(&name, ®ion); 301 sub = name_prefix(&name, tctx->origin, &prefix); 302 return (dns_name_totext(&prefix, sub, target)); 303 } 304 305 static isc_result_t 306 fromwire_naptr(ARGS_FROMWIRE) { 307 dns_name_t name; 308 isc_region_t sr; 309 unsigned char *regex; 310 311 REQUIRE(type == dns_rdatatype_naptr); 312 313 UNUSED(type); 314 UNUSED(rdclass); 315 316 dns_decompress_setmethods(dctx, DNS_COMPRESS_NONE); 317 318 dns_name_init(&name, NULL); 319 320 /* 321 * Order, preference. 322 */ 323 isc_buffer_activeregion(source, &sr); 324 if (sr.length < 4) { 325 return (ISC_R_UNEXPECTEDEND); 326 } 327 RETERR(mem_tobuffer(target, sr.base, 4)); 328 isc_buffer_forward(source, 4); 329 330 /* 331 * Flags. 332 */ 333 RETERR(txt_fromwire(source, target)); 334 335 /* 336 * Service. 337 */ 338 RETERR(txt_fromwire(source, target)); 339 340 /* 341 * Regexp. 342 */ 343 regex = isc_buffer_used(target); 344 RETERR(txt_fromwire(source, target)); 345 RETERR(txt_valid_regex(regex)); 346 347 /* 348 * Replacement. 349 */ 350 return (dns_name_fromwire(&name, source, dctx, options, target)); 351 } 352 353 static isc_result_t 354 towire_naptr(ARGS_TOWIRE) { 355 dns_name_t name; 356 dns_offsets_t offsets; 357 isc_region_t sr; 358 359 REQUIRE(rdata->type == dns_rdatatype_naptr); 360 REQUIRE(rdata->length != 0); 361 362 dns_compress_setmethods(cctx, DNS_COMPRESS_NONE); 363 /* 364 * Order, preference. 365 */ 366 dns_rdata_toregion(rdata, &sr); 367 RETERR(mem_tobuffer(target, sr.base, 4)); 368 isc_region_consume(&sr, 4); 369 370 /* 371 * Flags. 372 */ 373 RETERR(mem_tobuffer(target, sr.base, sr.base[0] + 1)); 374 isc_region_consume(&sr, sr.base[0] + 1); 375 376 /* 377 * Service. 378 */ 379 RETERR(mem_tobuffer(target, sr.base, sr.base[0] + 1)); 380 isc_region_consume(&sr, sr.base[0] + 1); 381 382 /* 383 * Regexp. 384 */ 385 RETERR(mem_tobuffer(target, sr.base, sr.base[0] + 1)); 386 isc_region_consume(&sr, sr.base[0] + 1); 387 388 /* 389 * Replacement. 390 */ 391 dns_name_init(&name, offsets); 392 dns_name_fromregion(&name, &sr); 393 return (dns_name_towire(&name, cctx, target)); 394 } 395 396 static int 397 compare_naptr(ARGS_COMPARE) { 398 dns_name_t name1; 399 dns_name_t name2; 400 isc_region_t region1; 401 isc_region_t region2; 402 int order, len; 403 404 REQUIRE(rdata1->type == rdata2->type); 405 REQUIRE(rdata1->rdclass == rdata2->rdclass); 406 REQUIRE(rdata1->type == dns_rdatatype_naptr); 407 REQUIRE(rdata1->length != 0); 408 REQUIRE(rdata2->length != 0); 409 410 dns_rdata_toregion(rdata1, ®ion1); 411 dns_rdata_toregion(rdata2, ®ion2); 412 413 /* 414 * Order, preference. 415 */ 416 order = memcmp(region1.base, region2.base, 4); 417 if (order != 0) { 418 return (order < 0 ? -1 : 1); 419 } 420 isc_region_consume(®ion1, 4); 421 isc_region_consume(®ion2, 4); 422 423 /* 424 * Flags. 425 */ 426 len = ISC_MIN(region1.base[0], region2.base[0]); 427 order = memcmp(region1.base, region2.base, len + 1); 428 if (order != 0) { 429 return (order < 0 ? -1 : 1); 430 } 431 isc_region_consume(®ion1, region1.base[0] + 1); 432 isc_region_consume(®ion2, region2.base[0] + 1); 433 434 /* 435 * Service. 436 */ 437 len = ISC_MIN(region1.base[0], region2.base[0]); 438 order = memcmp(region1.base, region2.base, len + 1); 439 if (order != 0) { 440 return (order < 0 ? -1 : 1); 441 } 442 isc_region_consume(®ion1, region1.base[0] + 1); 443 isc_region_consume(®ion2, region2.base[0] + 1); 444 445 /* 446 * Regexp. 447 */ 448 len = ISC_MIN(region1.base[0], region2.base[0]); 449 order = memcmp(region1.base, region2.base, len + 1); 450 if (order != 0) { 451 return (order < 0 ? -1 : 1); 452 } 453 isc_region_consume(®ion1, region1.base[0] + 1); 454 isc_region_consume(®ion2, region2.base[0] + 1); 455 456 /* 457 * Replacement. 458 */ 459 dns_name_init(&name1, NULL); 460 dns_name_init(&name2, NULL); 461 462 dns_name_fromregion(&name1, ®ion1); 463 dns_name_fromregion(&name2, ®ion2); 464 465 return (dns_name_rdatacompare(&name1, &name2)); 466 } 467 468 static isc_result_t 469 fromstruct_naptr(ARGS_FROMSTRUCT) { 470 dns_rdata_naptr_t *naptr = source; 471 isc_region_t region; 472 473 REQUIRE(type == dns_rdatatype_naptr); 474 REQUIRE(naptr != NULL); 475 REQUIRE(naptr->common.rdtype == type); 476 REQUIRE(naptr->common.rdclass == rdclass); 477 REQUIRE(naptr->flags != NULL || naptr->flags_len == 0); 478 REQUIRE(naptr->service != NULL || naptr->service_len == 0); 479 REQUIRE(naptr->regexp != NULL || naptr->regexp_len == 0); 480 481 UNUSED(type); 482 UNUSED(rdclass); 483 484 RETERR(uint16_tobuffer(naptr->order, target)); 485 RETERR(uint16_tobuffer(naptr->preference, target)); 486 RETERR(uint8_tobuffer(naptr->flags_len, target)); 487 RETERR(mem_tobuffer(target, naptr->flags, naptr->flags_len)); 488 RETERR(uint8_tobuffer(naptr->service_len, target)); 489 RETERR(mem_tobuffer(target, naptr->service, naptr->service_len)); 490 RETERR(uint8_tobuffer(naptr->regexp_len, target)); 491 RETERR(mem_tobuffer(target, naptr->regexp, naptr->regexp_len)); 492 dns_name_toregion(&naptr->replacement, ®ion); 493 return (isc_buffer_copyregion(target, ®ion)); 494 } 495 496 static isc_result_t 497 tostruct_naptr(ARGS_TOSTRUCT) { 498 dns_rdata_naptr_t *naptr = target; 499 isc_region_t r; 500 dns_name_t name; 501 502 REQUIRE(rdata->type == dns_rdatatype_naptr); 503 REQUIRE(naptr != NULL); 504 REQUIRE(rdata->length != 0); 505 506 naptr->common.rdclass = rdata->rdclass; 507 naptr->common.rdtype = rdata->type; 508 ISC_LINK_INIT(&naptr->common, link); 509 510 naptr->flags = NULL; 511 naptr->service = NULL; 512 naptr->regexp = NULL; 513 514 dns_rdata_toregion(rdata, &r); 515 516 naptr->order = uint16_fromregion(&r); 517 isc_region_consume(&r, 2); 518 519 naptr->preference = uint16_fromregion(&r); 520 isc_region_consume(&r, 2); 521 522 naptr->flags_len = uint8_fromregion(&r); 523 isc_region_consume(&r, 1); 524 INSIST(naptr->flags_len <= r.length); 525 naptr->flags = mem_maybedup(mctx, r.base, naptr->flags_len); 526 if (naptr->flags == NULL) { 527 goto cleanup; 528 } 529 isc_region_consume(&r, naptr->flags_len); 530 531 naptr->service_len = uint8_fromregion(&r); 532 isc_region_consume(&r, 1); 533 INSIST(naptr->service_len <= r.length); 534 naptr->service = mem_maybedup(mctx, r.base, naptr->service_len); 535 if (naptr->service == NULL) { 536 goto cleanup; 537 } 538 isc_region_consume(&r, naptr->service_len); 539 540 naptr->regexp_len = uint8_fromregion(&r); 541 isc_region_consume(&r, 1); 542 INSIST(naptr->regexp_len <= r.length); 543 naptr->regexp = mem_maybedup(mctx, r.base, naptr->regexp_len); 544 if (naptr->regexp == NULL) { 545 goto cleanup; 546 } 547 isc_region_consume(&r, naptr->regexp_len); 548 549 dns_name_init(&name, NULL); 550 dns_name_fromregion(&name, &r); 551 dns_name_init(&naptr->replacement, NULL); 552 name_duporclone(&name, mctx, &naptr->replacement); 553 naptr->mctx = mctx; 554 return (ISC_R_SUCCESS); 555 556 cleanup: 557 if (mctx != NULL && naptr->flags != NULL) { 558 isc_mem_free(mctx, naptr->flags); 559 } 560 if (mctx != NULL && naptr->service != NULL) { 561 isc_mem_free(mctx, naptr->service); 562 } 563 if (mctx != NULL && naptr->regexp != NULL) { 564 isc_mem_free(mctx, naptr->regexp); 565 } 566 return (ISC_R_NOMEMORY); 567 } 568 569 static void 570 freestruct_naptr(ARGS_FREESTRUCT) { 571 dns_rdata_naptr_t *naptr = source; 572 573 REQUIRE(naptr != NULL); 574 REQUIRE(naptr->common.rdtype == dns_rdatatype_naptr); 575 576 if (naptr->mctx == NULL) { 577 return; 578 } 579 580 if (naptr->flags != NULL) { 581 isc_mem_free(naptr->mctx, naptr->flags); 582 } 583 if (naptr->service != NULL) { 584 isc_mem_free(naptr->mctx, naptr->service); 585 } 586 if (naptr->regexp != NULL) { 587 isc_mem_free(naptr->mctx, naptr->regexp); 588 } 589 dns_name_free(&naptr->replacement, naptr->mctx); 590 naptr->mctx = NULL; 591 } 592 593 static isc_result_t 594 additionaldata_naptr(ARGS_ADDLDATA) { 595 dns_name_t name; 596 dns_offsets_t offsets; 597 isc_region_t sr; 598 dns_rdatatype_t atype; 599 unsigned int i, flagslen; 600 char *cp; 601 602 REQUIRE(rdata->type == dns_rdatatype_naptr); 603 604 UNUSED(owner); 605 606 /* 607 * Order, preference. 608 */ 609 dns_rdata_toregion(rdata, &sr); 610 isc_region_consume(&sr, 4); 611 612 /* 613 * Flags. 614 */ 615 atype = 0; 616 flagslen = sr.base[0]; 617 cp = (char *)&sr.base[1]; 618 for (i = 0; i < flagslen; i++, cp++) { 619 if (*cp == 'S' || *cp == 's') { 620 atype = dns_rdatatype_srv; 621 break; 622 } 623 if (*cp == 'A' || *cp == 'a') { 624 atype = dns_rdatatype_a; 625 break; 626 } 627 } 628 isc_region_consume(&sr, flagslen + 1); 629 630 /* 631 * Service. 632 */ 633 isc_region_consume(&sr, sr.base[0] + 1); 634 635 /* 636 * Regexp. 637 */ 638 isc_region_consume(&sr, sr.base[0] + 1); 639 640 /* 641 * Replacement. 642 */ 643 dns_name_init(&name, offsets); 644 dns_name_fromregion(&name, &sr); 645 646 if (atype != 0) { 647 return ((add)(arg, &name, atype, NULL)); 648 } 649 650 return (ISC_R_SUCCESS); 651 } 652 653 static isc_result_t 654 digest_naptr(ARGS_DIGEST) { 655 isc_region_t r1, r2; 656 unsigned int length, n; 657 isc_result_t result; 658 dns_name_t name; 659 660 REQUIRE(rdata->type == dns_rdatatype_naptr); 661 662 dns_rdata_toregion(rdata, &r1); 663 r2 = r1; 664 length = 0; 665 666 /* 667 * Order, preference. 668 */ 669 length += 4; 670 isc_region_consume(&r2, 4); 671 672 /* 673 * Flags. 674 */ 675 n = r2.base[0] + 1; 676 length += n; 677 isc_region_consume(&r2, n); 678 679 /* 680 * Service. 681 */ 682 n = r2.base[0] + 1; 683 length += n; 684 isc_region_consume(&r2, n); 685 686 /* 687 * Regexp. 688 */ 689 n = r2.base[0] + 1; 690 length += n; 691 isc_region_consume(&r2, n); 692 693 /* 694 * Digest the RR up to the replacement name. 695 */ 696 r1.length = length; 697 result = (digest)(arg, &r1); 698 if (result != ISC_R_SUCCESS) { 699 return (result); 700 } 701 702 /* 703 * Replacement. 704 */ 705 706 dns_name_init(&name, NULL); 707 dns_name_fromregion(&name, &r2); 708 709 return (dns_name_digest(&name, digest, arg)); 710 } 711 712 static bool 713 checkowner_naptr(ARGS_CHECKOWNER) { 714 REQUIRE(type == dns_rdatatype_naptr); 715 716 UNUSED(name); 717 UNUSED(type); 718 UNUSED(rdclass); 719 UNUSED(wildcard); 720 721 return (true); 722 } 723 724 static bool 725 checknames_naptr(ARGS_CHECKNAMES) { 726 REQUIRE(rdata->type == dns_rdatatype_naptr); 727 728 UNUSED(rdata); 729 UNUSED(owner); 730 UNUSED(bad); 731 732 return (true); 733 } 734 735 static int 736 casecompare_naptr(ARGS_COMPARE) { 737 return (compare_naptr(rdata1, rdata2)); 738 } 739 740 #endif /* RDATA_GENERIC_NAPTR_35_C */ 741