1 /* $NetBSD: name.c,v 1.17 2026/06/19 20:10:00 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 /*! \file */ 17 18 #include <ctype.h> 19 #include <inttypes.h> 20 #include <stdbool.h> 21 #include <stdlib.h> 22 23 #include <isc/ascii.h> 24 #include <isc/buffer.h> 25 #include <isc/hash.h> 26 #include <isc/hex.h> 27 #include <isc/mem.h> 28 #include <isc/once.h> 29 #include <isc/random.h> 30 #include <isc/result.h> 31 #include <isc/string.h> 32 #include <isc/thread.h> 33 #include <isc/util.h> 34 35 #include <dns/compress.h> 36 #include <dns/fixedname.h> 37 #include <dns/name.h> 38 39 typedef enum { 40 ft_init = 0, 41 ft_start, 42 ft_ordinary, 43 ft_initialescape, 44 ft_escape, 45 ft_escdecimal, 46 ft_at 47 } ft_state; 48 49 #define INIT_OFFSETS(name, var, default_offsets) \ 50 if ((name)->offsets != NULL) \ 51 var = (name)->offsets; \ 52 else \ 53 var = (default_offsets); 54 55 #define SETUP_OFFSETS(name, var, default_offsets) \ 56 if ((name)->offsets != NULL) { \ 57 var = (name)->offsets; \ 58 } else { \ 59 var = (default_offsets); \ 60 set_offsets(name, var, NULL); \ 61 } 62 63 /*% 64 * Note: If additional attributes are added that should not be set for 65 * empty names, MAKE_EMPTY() must be changed so it clears them. 66 */ 67 #define MAKE_EMPTY(name) \ 68 do { \ 69 name->ndata = NULL; \ 70 name->length = 0; \ 71 name->labels = 0; \ 72 name->attributes.absolute = false; \ 73 } while (0); 74 75 /*% 76 * Note that the name data must be a char array, not a string 77 * literal, to avoid compiler warnings about discarding 78 * the const attribute of a string. 79 */ 80 static unsigned char root_ndata[] = { "" }; 81 static unsigned char root_offsets[] = { 0 }; 82 83 static dns_name_t root = DNS_NAME_INITABSOLUTE(root_ndata, root_offsets); 84 const dns_name_t *dns_rootname = &root; 85 86 static unsigned char wild_ndata[] = { "\001*" }; 87 static unsigned char wild_offsets[] = { 0 }; 88 89 static dns_name_t const wild = DNS_NAME_INITNONABSOLUTE(wild_ndata, 90 wild_offsets); 91 92 const dns_name_t *dns_wildcardname = &wild; 93 94 /* 95 * dns_name_t to text post-conversion procedure. 96 */ 97 static thread_local dns_name_totextfilter_t *totext_filter_proc = NULL; 98 99 static void 100 set_offsets(const dns_name_t *name, unsigned char *offsets, 101 dns_name_t *set_name); 102 103 bool 104 dns_name_isvalid(const dns_name_t *name) { 105 unsigned char *ndata, *offsets; 106 unsigned int offset, count, length, nlabels; 107 108 if (!DNS_NAME_VALID(name)) { 109 return false; 110 } 111 112 if (name->labels > DNS_NAME_MAXLABELS) { 113 return false; 114 } 115 116 ndata = name->ndata; 117 length = name->length; 118 offsets = name->offsets; 119 offset = 0; 120 nlabels = 0; 121 122 while (offset != length) { 123 count = *ndata; 124 if (count > DNS_NAME_LABELLEN) { 125 return false; 126 } 127 if (offsets != NULL && offsets[nlabels] != offset) { 128 return false; 129 } 130 131 nlabels++; 132 offset += count + 1; 133 ndata += count + 1; 134 if (offset > length) { 135 return false; 136 } 137 138 if (count == 0) { 139 break; 140 } 141 } 142 143 if (nlabels != name->labels || offset != name->length) { 144 return false; 145 } 146 147 return true; 148 } 149 150 bool 151 dns_name_hasbuffer(const dns_name_t *name) { 152 /* 153 * Does 'name' have a dedicated buffer? 154 */ 155 156 REQUIRE(DNS_NAME_VALID(name)); 157 158 if (name->buffer != NULL) { 159 return true; 160 } 161 162 return false; 163 } 164 165 bool 166 dns_name_isabsolute(const dns_name_t *name) { 167 /* 168 * Does 'name' end in the root label? 169 */ 170 171 REQUIRE(DNS_NAME_VALID(name)); 172 173 return name->attributes.absolute; 174 } 175 176 #define hyphenchar(c) ((c) == 0x2d) 177 #define asterchar(c) ((c) == 0x2a) 178 #define alphachar(c) \ 179 (((c) >= 0x41 && (c) <= 0x5a) || ((c) >= 0x61 && (c) <= 0x7a)) 180 #define digitchar(c) ((c) >= 0x30 && (c) <= 0x39) 181 #define borderchar(c) (alphachar(c) || digitchar(c)) 182 #define middlechar(c) (borderchar(c) || hyphenchar(c)) 183 #define domainchar(c) ((c) > 0x20 && (c) < 0x7f) 184 185 bool 186 dns_name_ismailbox(const dns_name_t *name) { 187 unsigned char *ndata, ch; 188 unsigned int n; 189 bool first; 190 191 REQUIRE(DNS_NAME_VALID(name)); 192 REQUIRE(name->labels > 0); 193 REQUIRE(name->attributes.absolute); 194 195 /* 196 * Root label. 197 */ 198 if (name->length == 1) { 199 return true; 200 } 201 202 ndata = name->ndata; 203 n = *ndata++; 204 INSIST(n <= DNS_NAME_LABELLEN); 205 while (n--) { 206 ch = *ndata++; 207 if (!domainchar(ch)) { 208 return false; 209 } 210 } 211 212 if (ndata == name->ndata + name->length) { 213 return false; 214 } 215 216 /* 217 * RFC952/RFC1123 hostname. 218 */ 219 while (ndata < (name->ndata + name->length)) { 220 n = *ndata++; 221 INSIST(n <= DNS_NAME_LABELLEN); 222 first = true; 223 while (n--) { 224 ch = *ndata++; 225 if (first || n == 0) { 226 if (!borderchar(ch)) { 227 return false; 228 } 229 } else { 230 if (!middlechar(ch)) { 231 return false; 232 } 233 } 234 first = false; 235 } 236 } 237 return true; 238 } 239 240 bool 241 dns_name_ishostname(const dns_name_t *name, bool wildcard) { 242 unsigned char *ndata, ch; 243 unsigned int n; 244 bool first; 245 246 REQUIRE(DNS_NAME_VALID(name)); 247 REQUIRE(name->labels > 0); 248 REQUIRE(name->attributes.absolute); 249 250 /* 251 * Root label. 252 */ 253 if (name->length == 1) { 254 return true; 255 } 256 257 /* 258 * Skip wildcard if this is a ownername. 259 */ 260 ndata = name->ndata; 261 if (wildcard && ndata[0] == 1 && ndata[1] == '*') { 262 ndata += 2; 263 } 264 265 /* 266 * RFC952/RFC1123 hostname. 267 */ 268 while (ndata < (name->ndata + name->length)) { 269 n = *ndata++; 270 INSIST(n <= DNS_NAME_LABELLEN); 271 first = true; 272 while (n--) { 273 ch = *ndata++; 274 if (first || n == 0) { 275 if (!borderchar(ch)) { 276 return false; 277 } 278 } else { 279 if (!middlechar(ch)) { 280 return false; 281 } 282 } 283 first = false; 284 } 285 } 286 return true; 287 } 288 289 bool 290 dns_name_iswildcard(const dns_name_t *name) { 291 unsigned char *ndata; 292 293 /* 294 * Is 'name' a wildcard name? 295 */ 296 297 REQUIRE(DNS_NAME_VALID(name)); 298 REQUIRE(name->labels > 0); 299 300 if (name->length >= 2) { 301 ndata = name->ndata; 302 if (ndata[0] == 1 && ndata[1] == '*') { 303 return true; 304 } 305 } 306 307 return false; 308 } 309 310 bool 311 dns_name_internalwildcard(const dns_name_t *name) { 312 unsigned char *ndata; 313 unsigned int count; 314 unsigned int label; 315 316 /* 317 * Does 'name' contain a internal wildcard? 318 */ 319 320 REQUIRE(DNS_NAME_VALID(name)); 321 REQUIRE(name->labels > 0); 322 323 /* 324 * Skip first label. 325 */ 326 ndata = name->ndata; 327 count = *ndata++; 328 INSIST(count <= DNS_NAME_LABELLEN); 329 ndata += count; 330 label = 1; 331 /* 332 * Check all but the last of the remaining labels. 333 */ 334 while (label + 1 < name->labels) { 335 count = *ndata++; 336 INSIST(count <= DNS_NAME_LABELLEN); 337 if (count == 1 && *ndata == '*') { 338 return true; 339 } 340 ndata += count; 341 label++; 342 } 343 return false; 344 } 345 346 uint32_t 347 dns_name_hash(const dns_name_t *name) { 348 REQUIRE(DNS_NAME_VALID(name)); 349 350 return isc_hash32(name->ndata, name->length, false); 351 } 352 353 dns_namereln_t 354 dns_name_fullcompare(const dns_name_t *name1, const dns_name_t *name2, 355 int *orderp, unsigned int *nlabelsp) { 356 unsigned int l1, l2, l, count1, count2, count, nlabels; 357 int cdiff, ldiff, diff; 358 unsigned char *label1, *label2; 359 unsigned char *offsets1, *offsets2; 360 dns_offsets_t odata1, odata2; 361 dns_namereln_t namereln = dns_namereln_none; 362 363 /* 364 * Determine the relative ordering under the DNSSEC order relation of 365 * 'name1' and 'name2', and also determine the hierarchical 366 * relationship of the names. 367 * 368 * Note: It makes no sense for one of the names to be relative and the 369 * other absolute. If both names are relative, then to be meaningfully 370 * compared the caller must ensure that they are both relative to the 371 * same domain. 372 */ 373 374 REQUIRE(DNS_NAME_VALID(name1)); 375 REQUIRE(DNS_NAME_VALID(name2)); 376 REQUIRE(orderp != NULL); 377 REQUIRE(nlabelsp != NULL); 378 /* 379 * Either name1 is absolute and name2 is absolute, or neither is. 380 */ 381 REQUIRE((name1->attributes.absolute) == (name2->attributes.absolute)); 382 383 if (name1 == name2) { 384 *orderp = 0; 385 *nlabelsp = name1->labels; 386 return dns_namereln_equal; 387 } 388 389 SETUP_OFFSETS(name1, offsets1, odata1); 390 SETUP_OFFSETS(name2, offsets2, odata2); 391 392 nlabels = 0; 393 l1 = name1->labels; 394 l2 = name2->labels; 395 if (l2 > l1) { 396 l = l1; 397 ldiff = 0 - (l2 - l1); 398 } else { 399 l = l2; 400 ldiff = l1 - l2; 401 } 402 403 offsets1 += l1; 404 offsets2 += l2; 405 406 while (l-- > 0) { 407 offsets1--; 408 offsets2--; 409 label1 = &name1->ndata[*offsets1]; 410 label2 = &name2->ndata[*offsets2]; 411 count1 = *label1++; 412 count2 = *label2++; 413 414 cdiff = (int)count1 - (int)count2; 415 if (cdiff < 0) { 416 count = count1; 417 } else { 418 count = count2; 419 } 420 421 diff = isc_ascii_lowercmp(label1, label2, count); 422 if (diff != 0) { 423 *orderp = diff; 424 goto done; 425 } 426 427 if (cdiff != 0) { 428 *orderp = cdiff; 429 goto done; 430 } 431 nlabels++; 432 } 433 434 *orderp = ldiff; 435 if (ldiff < 0) { 436 namereln = dns_namereln_contains; 437 } else if (ldiff > 0) { 438 namereln = dns_namereln_subdomain; 439 } else { 440 namereln = dns_namereln_equal; 441 } 442 *nlabelsp = nlabels; 443 return namereln; 444 445 done: 446 *nlabelsp = nlabels; 447 if (nlabels > 0) { 448 namereln = dns_namereln_commonancestor; 449 } 450 451 return namereln; 452 } 453 454 int 455 dns_name_compare(const dns_name_t *name1, const dns_name_t *name2) { 456 int order; 457 unsigned int nlabels; 458 459 /* 460 * Determine the relative ordering under the DNSSEC order relation of 461 * 'name1' and 'name2'. 462 * 463 * Note: It makes no sense for one of the names to be relative and the 464 * other absolute. If both names are relative, then to be meaningfully 465 * compared the caller must ensure that they are both relative to the 466 * same domain. 467 */ 468 469 (void)dns_name_fullcompare(name1, name2, &order, &nlabels); 470 471 return order; 472 } 473 474 bool 475 dns_name_equal(const dns_name_t *name1, const dns_name_t *name2) { 476 unsigned int length; 477 478 /* 479 * Are 'name1' and 'name2' equal? 480 * 481 * Note: It makes no sense for one of the names to be relative and the 482 * other absolute. If both names are relative, then to be meaningfully 483 * compared the caller must ensure that they are both relative to the 484 * same domain. 485 */ 486 487 REQUIRE(DNS_NAME_VALID(name1)); 488 REQUIRE(DNS_NAME_VALID(name2)); 489 /* 490 * Either name1 is absolute and name2 is absolute, or neither is. 491 */ 492 REQUIRE((name1->attributes.absolute) == (name2->attributes.absolute)); 493 494 if (name1 == name2) { 495 return true; 496 } 497 498 length = name1->length; 499 if (length != name2->length) { 500 return false; 501 } 502 503 /* label lengths are < 64 so tolower() does not affect them */ 504 return isc_ascii_lowerequal(name1->ndata, name2->ndata, length); 505 } 506 507 bool 508 dns_name_caseequal(const dns_name_t *name1, const dns_name_t *name2) { 509 /* 510 * Are 'name1' and 'name2' equal? 511 * 512 * Note: It makes no sense for one of the names to be relative and the 513 * other absolute. If both names are relative, then to be meaningfully 514 * compared the caller must ensure that they are both relative to the 515 * same domain. 516 */ 517 518 REQUIRE(DNS_NAME_VALID(name1)); 519 REQUIRE(DNS_NAME_VALID(name2)); 520 /* 521 * Either name1 is absolute and name2 is absolute, or neither is. 522 */ 523 REQUIRE((name1->attributes.absolute) == (name2->attributes.absolute)); 524 525 if (name1->length != name2->length) { 526 return false; 527 } 528 529 if (memcmp(name1->ndata, name2->ndata, name1->length) != 0) { 530 return false; 531 } 532 533 return true; 534 } 535 536 int 537 dns_name_rdatacompare(const dns_name_t *name1, const dns_name_t *name2) { 538 /* 539 * Compare two absolute names as rdata. 540 */ 541 542 REQUIRE(DNS_NAME_VALID(name1)); 543 REQUIRE(name1->labels > 0); 544 REQUIRE(name1->attributes.absolute); 545 REQUIRE(DNS_NAME_VALID(name2)); 546 REQUIRE(name2->labels > 0); 547 REQUIRE(name2->attributes.absolute); 548 549 /* label lengths are < 64 so tolower() does not affect them */ 550 return isc_ascii_lowercmp(name1->ndata, name2->ndata, 551 ISC_MIN(name1->length, name2->length)); 552 } 553 554 bool 555 dns_name_issubdomain(const dns_name_t *name1, const dns_name_t *name2) { 556 int order; 557 unsigned int nlabels; 558 dns_namereln_t namereln; 559 560 /* 561 * Is 'name1' a subdomain of 'name2'? 562 * 563 * Note: It makes no sense for one of the names to be relative and the 564 * other absolute. If both names are relative, then to be meaningfully 565 * compared the caller must ensure that they are both relative to the 566 * same domain. 567 */ 568 569 namereln = dns_name_fullcompare(name1, name2, &order, &nlabels); 570 if (namereln == dns_namereln_subdomain || 571 namereln == dns_namereln_equal) 572 { 573 return true; 574 } 575 576 return false; 577 } 578 579 bool 580 dns_name_matcheswildcard(const dns_name_t *name, const dns_name_t *wname) { 581 int order; 582 unsigned int nlabels, labels; 583 dns_name_t tname; 584 585 REQUIRE(DNS_NAME_VALID(name)); 586 REQUIRE(name->labels > 0); 587 REQUIRE(DNS_NAME_VALID(wname)); 588 labels = wname->labels; 589 REQUIRE(labels > 0); 590 REQUIRE(dns_name_iswildcard(wname)); 591 592 dns_name_init(&tname, NULL); 593 dns_name_getlabelsequence(wname, 1, labels - 1, &tname); 594 if (dns_name_fullcompare(name, &tname, &order, &nlabels) == 595 dns_namereln_subdomain) 596 { 597 return true; 598 } 599 return false; 600 } 601 602 void 603 dns_name_getlabel(const dns_name_t *name, unsigned int n, dns_label_t *label) { 604 unsigned char *offsets; 605 dns_offsets_t odata; 606 607 /* 608 * Make 'label' refer to the 'n'th least significant label of 'name'. 609 */ 610 611 REQUIRE(DNS_NAME_VALID(name)); 612 REQUIRE(name->labels > 0); 613 REQUIRE(n < name->labels); 614 REQUIRE(label != NULL); 615 616 SETUP_OFFSETS(name, offsets, odata); 617 618 label->base = &name->ndata[offsets[n]]; 619 if (n == (unsigned int)name->labels - 1) { 620 label->length = name->length - offsets[n]; 621 } else { 622 label->length = offsets[n + 1] - offsets[n]; 623 } 624 } 625 626 void 627 dns_name_getlabelsequence(const dns_name_t *source, unsigned int first, 628 unsigned int n, dns_name_t *target) { 629 unsigned char *p, l; 630 unsigned int firstoffset, endoffset; 631 unsigned int i; 632 633 /* 634 * Make 'target' refer to the 'n' labels including and following 635 * 'first' in 'source'. 636 */ 637 638 REQUIRE(DNS_NAME_VALID(source)); 639 REQUIRE(DNS_NAME_VALID(target)); 640 REQUIRE(first <= source->labels); 641 REQUIRE(n <= source->labels - first); /* note first+n could overflow */ 642 REQUIRE(DNS_NAME_BINDABLE(target)); 643 644 p = source->ndata; 645 if (first == source->labels) { 646 firstoffset = source->length; 647 } else { 648 for (i = 0; i < first; i++) { 649 l = *p; 650 p += l + 1; 651 } 652 firstoffset = (unsigned int)(p - source->ndata); 653 } 654 655 if (first + n == source->labels) { 656 endoffset = source->length; 657 } else { 658 for (i = 0; i < n; i++) { 659 l = *p; 660 p += l + 1; 661 } 662 endoffset = (unsigned int)(p - source->ndata); 663 } 664 665 target->ndata = &source->ndata[firstoffset]; 666 target->length = endoffset - firstoffset; 667 668 if (first + n == source->labels && n > 0 && source->attributes.absolute) 669 { 670 target->attributes.absolute = true; 671 } else { 672 target->attributes.absolute = false; 673 } 674 675 target->labels = n; 676 677 /* 678 * If source and target are the same, and we're making target 679 * a prefix of source, the offsets table is correct already 680 * so we don't need to call set_offsets(). 681 */ 682 if (target->offsets != NULL && (target != source || first != 0)) { 683 set_offsets(target, target->offsets, NULL); 684 } 685 } 686 687 void 688 dns_name_clone(const dns_name_t *source, dns_name_t *target) { 689 /* 690 * Make 'target' refer to the same name as 'source'. 691 */ 692 693 REQUIRE(DNS_NAME_VALID(source)); 694 REQUIRE(DNS_NAME_VALID(target)); 695 REQUIRE(DNS_NAME_BINDABLE(target)); 696 697 target->ndata = source->ndata; 698 target->length = source->length; 699 target->labels = source->labels; 700 target->attributes = source->attributes; 701 target->attributes.readonly = false; 702 target->attributes.dynamic = false; 703 target->attributes.dynoffsets = false; 704 if (target->offsets != NULL && source->labels > 0) { 705 if (source->offsets != NULL) { 706 memmove(target->offsets, source->offsets, 707 source->labels); 708 } else { 709 set_offsets(target, target->offsets, NULL); 710 } 711 } 712 } 713 714 void 715 dns_name_fromregion(dns_name_t *name, const isc_region_t *r) { 716 unsigned char *offsets; 717 dns_offsets_t odata; 718 unsigned int len; 719 isc_region_t r2 = { .base = NULL, .length = 0 }; 720 721 /* 722 * Make 'name' refer to region 'r'. 723 */ 724 725 REQUIRE(DNS_NAME_VALID(name)); 726 REQUIRE(r != NULL); 727 REQUIRE(DNS_NAME_BINDABLE(name)); 728 729 INIT_OFFSETS(name, offsets, odata); 730 731 name->ndata = r->base; 732 if (name->buffer != NULL) { 733 isc_buffer_clear(name->buffer); 734 isc_buffer_availableregion(name->buffer, &r2); 735 len = (r->length < r2.length) ? r->length : r2.length; 736 if (len > DNS_NAME_MAXWIRE) { 737 len = DNS_NAME_MAXWIRE; 738 } 739 name->length = len; 740 } else { 741 name->length = (r->length <= DNS_NAME_MAXWIRE) 742 ? r->length 743 : DNS_NAME_MAXWIRE; 744 } 745 746 if (r->length > 0) { 747 set_offsets(name, offsets, name); 748 } else { 749 name->labels = 0; 750 name->attributes.absolute = false; 751 } 752 753 if (name->buffer != NULL) { 754 /* 755 * name->length has been updated by set_offsets to the actual 756 * length of the name data so we can now copy the actual name 757 * data and not anything after it. 758 */ 759 if (name->length > 0) { 760 memmove(r2.base, r->base, name->length); 761 } 762 name->ndata = r2.base; 763 isc_buffer_add(name->buffer, name->length); 764 } 765 } 766 767 isc_result_t 768 dns_name_fromtext(dns_name_t *name, isc_buffer_t *source, 769 const dns_name_t *origin, unsigned int options, 770 isc_buffer_t *target) { 771 unsigned char *ndata, *label = NULL; 772 char *tdata; 773 char c; 774 ft_state state; 775 unsigned int value = 0, count = 0; 776 unsigned int n1 = 0, n2 = 0; 777 unsigned int tlen, nrem, nused, digits = 0, labels, tused; 778 bool done; 779 unsigned char *offsets; 780 dns_offsets_t odata; 781 bool downcase; 782 783 /* 784 * Convert the textual representation of a DNS name at source 785 * into uncompressed wire form stored in target. 786 * 787 * Notes: 788 * Relative domain names will have 'origin' appended to them 789 * unless 'origin' is NULL, in which case relative domain names 790 * will remain relative. 791 */ 792 793 REQUIRE(DNS_NAME_VALID(name)); 794 REQUIRE(ISC_BUFFER_VALID(source)); 795 REQUIRE((target != NULL && ISC_BUFFER_VALID(target)) || 796 (target == NULL && ISC_BUFFER_VALID(name->buffer))); 797 798 downcase = ((options & DNS_NAME_DOWNCASE) != 0); 799 800 if (target == NULL && name->buffer != NULL) { 801 target = name->buffer; 802 isc_buffer_clear(target); 803 } 804 805 REQUIRE(DNS_NAME_BINDABLE(name)); 806 807 INIT_OFFSETS(name, offsets, odata); 808 offsets[0] = 0; 809 810 /* 811 * Make 'name' empty in case of failure. 812 */ 813 MAKE_EMPTY(name); 814 815 /* 816 * Set up the state machine. 817 */ 818 tdata = (char *)source->base + source->current; 819 tlen = isc_buffer_remaininglength(source); 820 tused = 0; 821 ndata = isc_buffer_used(target); 822 nrem = isc_buffer_availablelength(target); 823 if (nrem > DNS_NAME_MAXWIRE) { 824 nrem = DNS_NAME_MAXWIRE; 825 } 826 nused = 0; 827 labels = 0; 828 done = false; 829 state = ft_init; 830 831 while (nrem > 0 && tlen > 0 && !done) { 832 c = *tdata++; 833 tlen--; 834 tused++; 835 836 switch (state) { 837 case ft_init: 838 /* 839 * Is this the root name? 840 */ 841 if (c == '.') { 842 if (tlen != 0) { 843 return DNS_R_EMPTYLABEL; 844 } 845 labels++; 846 *ndata++ = 0; 847 nrem--; 848 nused++; 849 done = true; 850 break; 851 } 852 if (c == '@' && tlen == 0) { 853 state = ft_at; 854 break; 855 } 856 857 FALLTHROUGH; 858 case ft_start: 859 label = ndata; 860 ndata++; 861 nrem--; 862 nused++; 863 count = 0; 864 if (c == '\\') { 865 state = ft_initialescape; 866 break; 867 } 868 state = ft_ordinary; 869 if (nrem == 0) { 870 return ISC_R_NOSPACE; 871 } 872 FALLTHROUGH; 873 case ft_ordinary: 874 if (c == '.') { 875 if (count == 0) { 876 return DNS_R_EMPTYLABEL; 877 } 878 *label = count; 879 labels++; 880 INSIST(labels < DNS_NAME_MAXLABELS); 881 offsets[labels] = nused; 882 if (tlen == 0) { 883 labels++; 884 *ndata++ = 0; 885 nrem--; 886 nused++; 887 done = true; 888 } 889 state = ft_start; 890 } else if (c == '\\') { 891 state = ft_escape; 892 } else { 893 if (count >= DNS_NAME_LABELLEN) { 894 return DNS_R_LABELTOOLONG; 895 } 896 count++; 897 if (downcase) { 898 c = isc_ascii_tolower(c); 899 } 900 *ndata++ = c; 901 nrem--; 902 nused++; 903 } 904 break; 905 case ft_initialescape: 906 if (c == '[') { 907 /* 908 * This looks like a bitstring label, which 909 * was deprecated. Intentionally drop it. 910 */ 911 return DNS_R_BADLABELTYPE; 912 } 913 state = ft_escape; 914 POST(state); 915 FALLTHROUGH; 916 case ft_escape: 917 if (!isdigit((unsigned char)c)) { 918 if (count >= DNS_NAME_LABELLEN) { 919 return DNS_R_LABELTOOLONG; 920 } 921 count++; 922 if (downcase) { 923 c = isc_ascii_tolower(c); 924 } 925 *ndata++ = c; 926 nrem--; 927 nused++; 928 state = ft_ordinary; 929 break; 930 } 931 digits = 0; 932 value = 0; 933 state = ft_escdecimal; 934 FALLTHROUGH; 935 case ft_escdecimal: 936 if (!isdigit((unsigned char)c)) { 937 return DNS_R_BADESCAPE; 938 } 939 value = 10 * value + c - '0'; 940 digits++; 941 if (digits == 3) { 942 if (value > 255) { 943 return DNS_R_BADESCAPE; 944 } 945 if (count >= DNS_NAME_LABELLEN) { 946 return DNS_R_LABELTOOLONG; 947 } 948 count++; 949 if (downcase) { 950 value = isc_ascii_tolower(value); 951 } 952 *ndata++ = value; 953 nrem--; 954 nused++; 955 state = ft_ordinary; 956 } 957 break; 958 default: 959 FATAL_ERROR("Unexpected state %d", state); 960 /* Does not return. */ 961 } 962 } 963 964 if (!done) { 965 if (nrem == 0) { 966 return ISC_R_NOSPACE; 967 } 968 INSIST(tlen == 0); 969 if (state != ft_ordinary && state != ft_at) { 970 return ISC_R_UNEXPECTEDEND; 971 } 972 if (state == ft_ordinary) { 973 INSIST(count != 0); 974 INSIST(label != NULL); 975 *label = count; 976 labels++; 977 INSIST(labels < DNS_NAME_MAXLABELS); 978 offsets[labels] = nused; 979 } 980 if (origin != NULL) { 981 if (nrem < origin->length) { 982 return ISC_R_NOSPACE; 983 } 984 label = origin->ndata; 985 n1 = origin->length; 986 nrem -= n1; 987 POST(nrem); 988 while (n1 > 0) { 989 n2 = *label++; 990 INSIST(n2 <= DNS_NAME_LABELLEN); 991 *ndata++ = n2; 992 n1 -= n2 + 1; 993 nused += n2 + 1; 994 while (n2 > 0) { 995 c = *label++; 996 if (downcase) { 997 c = isc_ascii_tolower(c); 998 } 999 *ndata++ = c; 1000 n2--; 1001 } 1002 labels++; 1003 if (n1 > 0) { 1004 INSIST(labels < DNS_NAME_MAXLABELS); 1005 offsets[labels] = nused; 1006 } 1007 } 1008 if (origin->attributes.absolute) { 1009 name->attributes.absolute = true; 1010 } 1011 } 1012 } else { 1013 name->attributes.absolute = true; 1014 } 1015 1016 name->ndata = (unsigned char *)target->base + target->used; 1017 name->labels = labels; 1018 name->length = nused; 1019 1020 isc_buffer_forward(source, tused); 1021 isc_buffer_add(target, name->length); 1022 1023 return ISC_R_SUCCESS; 1024 } 1025 1026 isc_result_t 1027 dns_name_totext(const dns_name_t *name, unsigned int options, 1028 isc_buffer_t *target) { 1029 unsigned char *ndata; 1030 char *tdata; 1031 unsigned int nlen, tlen; 1032 unsigned char c; 1033 unsigned int trem, count; 1034 unsigned int labels; 1035 bool saw_root = false; 1036 unsigned int oused; 1037 bool omit_final_dot = ((options & DNS_NAME_OMITFINALDOT) != 0); 1038 1039 /* 1040 * This function assumes the name is in proper uncompressed 1041 * wire format. 1042 */ 1043 REQUIRE(DNS_NAME_VALID(name)); 1044 REQUIRE(ISC_BUFFER_VALID(target)); 1045 1046 oused = target->used; 1047 1048 ndata = name->ndata; 1049 nlen = name->length; 1050 labels = name->labels; 1051 tdata = isc_buffer_used(target); 1052 tlen = isc_buffer_availablelength(target); 1053 1054 trem = tlen; 1055 1056 if (labels == 0 && nlen == 0) { 1057 /* 1058 * Special handling for an empty name. 1059 */ 1060 if (trem == 0) { 1061 return ISC_R_NOSPACE; 1062 } 1063 1064 /* 1065 * The names of these booleans are misleading in this case. 1066 * This empty name is not necessarily from the root node of 1067 * the DNS root zone, nor is a final dot going to be included. 1068 * They need to be set this way, though, to keep the "@" 1069 * from being trounced. 1070 */ 1071 saw_root = true; 1072 omit_final_dot = false; 1073 *tdata++ = '@'; 1074 trem--; 1075 1076 /* 1077 * Skip the while() loop. 1078 */ 1079 nlen = 0; 1080 } else if (nlen == 1 && labels == 1 && *ndata == '\0') { 1081 /* 1082 * Special handling for the root label. 1083 */ 1084 if (trem == 0) { 1085 return ISC_R_NOSPACE; 1086 } 1087 1088 saw_root = true; 1089 omit_final_dot = false; 1090 *tdata++ = '.'; 1091 trem--; 1092 1093 /* 1094 * Skip the while() loop. 1095 */ 1096 nlen = 0; 1097 } 1098 1099 while (labels > 0 && nlen > 0 && trem > 0) { 1100 labels--; 1101 count = *ndata++; 1102 nlen--; 1103 if (count == 0) { 1104 saw_root = true; 1105 break; 1106 } 1107 if (count <= DNS_NAME_LABELLEN) { 1108 INSIST(nlen >= count); 1109 while (count > 0) { 1110 c = *ndata; 1111 switch (c) { 1112 /* Special modifiers in zone files. */ 1113 case 0x40: /* '@' */ 1114 case 0x24: /* '$' */ 1115 if ((options & DNS_NAME_PRINCIPAL) != 0) 1116 { 1117 goto no_escape; 1118 } 1119 FALLTHROUGH; 1120 case 0x22: /* '"' */ 1121 case 0x28: /* '(' */ 1122 case 0x29: /* ')' */ 1123 case 0x2E: /* '.' */ 1124 case 0x3B: /* ';' */ 1125 case 0x5C: /* '\\' */ 1126 if (trem < 2) { 1127 return ISC_R_NOSPACE; 1128 } 1129 *tdata++ = '\\'; 1130 *tdata++ = c; 1131 ndata++; 1132 trem -= 2; 1133 nlen--; 1134 break; 1135 no_escape: 1136 default: 1137 if (c > 0x20 && c < 0x7f) { 1138 if (trem == 0) { 1139 return ISC_R_NOSPACE; 1140 } 1141 *tdata++ = c; 1142 ndata++; 1143 trem--; 1144 nlen--; 1145 } else { 1146 if (trem < 4) { 1147 return ISC_R_NOSPACE; 1148 } 1149 *tdata++ = 0x5c; 1150 *tdata++ = 0x30 + 1151 ((c / 100) % 10); 1152 *tdata++ = 0x30 + 1153 ((c / 10) % 10); 1154 *tdata++ = 0x30 + (c % 10); 1155 trem -= 4; 1156 ndata++; 1157 nlen--; 1158 } 1159 } 1160 count--; 1161 } 1162 } else { 1163 FATAL_ERROR("Unexpected label type %02x", count); 1164 UNREACHABLE(); 1165 } 1166 1167 /* 1168 * The following assumes names are absolute. If not, we 1169 * fix things up later. Note that this means that in some 1170 * cases one more byte of text buffer is required than is 1171 * needed in the final output. 1172 */ 1173 if (trem == 0) { 1174 return ISC_R_NOSPACE; 1175 } 1176 *tdata++ = '.'; 1177 trem--; 1178 } 1179 1180 if (nlen != 0 && trem == 0) { 1181 return ISC_R_NOSPACE; 1182 } 1183 1184 if (!saw_root || omit_final_dot) { 1185 trem++; 1186 tdata--; 1187 } 1188 if (trem > 0) { 1189 *tdata = 0; 1190 } 1191 isc_buffer_add(target, tlen - trem); 1192 1193 if (totext_filter_proc != NULL) { 1194 return (totext_filter_proc)(target, oused); 1195 } 1196 1197 return ISC_R_SUCCESS; 1198 } 1199 1200 isc_result_t 1201 dns_name_tofilenametext(const dns_name_t *name, bool omit_final_dot, 1202 isc_buffer_t *target) { 1203 unsigned char *ndata; 1204 char *tdata; 1205 unsigned int nlen, tlen; 1206 unsigned char c; 1207 unsigned int trem, count; 1208 unsigned int labels; 1209 1210 /* 1211 * This function assumes the name is in proper uncompressed 1212 * wire format. 1213 */ 1214 REQUIRE(DNS_NAME_VALID(name)); 1215 REQUIRE(name->attributes.absolute); 1216 REQUIRE(ISC_BUFFER_VALID(target)); 1217 1218 ndata = name->ndata; 1219 nlen = name->length; 1220 labels = name->labels; 1221 tdata = isc_buffer_used(target); 1222 tlen = isc_buffer_availablelength(target); 1223 1224 trem = tlen; 1225 1226 if (nlen == 1 && labels == 1 && *ndata == '\0') { 1227 /* 1228 * Special handling for the root label. 1229 */ 1230 if (trem == 0) { 1231 return ISC_R_NOSPACE; 1232 } 1233 1234 omit_final_dot = false; 1235 *tdata++ = '.'; 1236 trem--; 1237 1238 /* 1239 * Skip the while() loop. 1240 */ 1241 nlen = 0; 1242 } 1243 1244 while (labels > 0 && nlen > 0 && trem > 0) { 1245 labels--; 1246 count = *ndata++; 1247 nlen--; 1248 if (count == 0) { 1249 break; 1250 } 1251 if (count <= DNS_NAME_LABELLEN) { 1252 INSIST(nlen >= count); 1253 while (count > 0) { 1254 c = *ndata; 1255 if ((c >= 0x30 && c <= 0x39) || /* digit */ 1256 (c >= 0x41 && c <= 0x5A) || /* uppercase */ 1257 (c >= 0x61 && c <= 0x7A) || /* lowercase */ 1258 c == 0x2D || /* hyphen */ 1259 c == 0x5F) /* underscore */ 1260 { 1261 if (trem == 0) { 1262 return ISC_R_NOSPACE; 1263 } 1264 /* downcase */ 1265 if (c >= 0x41 && c <= 0x5A) { 1266 c += 0x20; 1267 } 1268 *tdata++ = c; 1269 ndata++; 1270 trem--; 1271 nlen--; 1272 } else { 1273 if (trem < 4) { 1274 return ISC_R_NOSPACE; 1275 } 1276 snprintf(tdata, trem, "%%%02X", c); 1277 tdata += 3; 1278 trem -= 3; 1279 ndata++; 1280 nlen--; 1281 } 1282 count--; 1283 } 1284 } else { 1285 FATAL_ERROR("Unexpected label type %02x", count); 1286 UNREACHABLE(); 1287 } 1288 1289 /* 1290 * The following assumes names are absolute. If not, we 1291 * fix things up later. Note that this means that in some 1292 * cases one more byte of text buffer is required than is 1293 * needed in the final output. 1294 */ 1295 if (trem == 0) { 1296 return ISC_R_NOSPACE; 1297 } 1298 *tdata++ = '.'; 1299 trem--; 1300 } 1301 1302 if (nlen != 0 && trem == 0) { 1303 return ISC_R_NOSPACE; 1304 } 1305 1306 if (omit_final_dot) { 1307 trem++; 1308 } 1309 1310 isc_buffer_add(target, tlen - trem); 1311 1312 return ISC_R_SUCCESS; 1313 } 1314 1315 isc_result_t 1316 dns_name_downcase(const dns_name_t *source, dns_name_t *name, 1317 isc_buffer_t *target) { 1318 unsigned char *ndata; 1319 isc_buffer_t buffer; 1320 1321 /* 1322 * Downcase 'source'. 1323 */ 1324 1325 REQUIRE(DNS_NAME_VALID(source)); 1326 REQUIRE(DNS_NAME_VALID(name)); 1327 if (source == name) { 1328 REQUIRE(!name->attributes.readonly); 1329 isc_buffer_init(&buffer, source->ndata, source->length); 1330 target = &buffer; 1331 ndata = source->ndata; 1332 } else { 1333 REQUIRE(DNS_NAME_BINDABLE(name)); 1334 REQUIRE((target != NULL && ISC_BUFFER_VALID(target)) || 1335 (target == NULL && ISC_BUFFER_VALID(name->buffer))); 1336 if (target == NULL) { 1337 target = name->buffer; 1338 isc_buffer_clear(name->buffer); 1339 } 1340 ndata = (unsigned char *)target->base + target->used; 1341 name->ndata = ndata; 1342 } 1343 1344 if (source->length > (target->length - target->used)) { 1345 MAKE_EMPTY(name); 1346 return ISC_R_NOSPACE; 1347 } 1348 1349 /* label lengths are < 64 so tolower() does not affect them */ 1350 isc_ascii_lowercopy(ndata, source->ndata, source->length); 1351 1352 if (source != name) { 1353 name->labels = source->labels; 1354 name->length = source->length; 1355 name->attributes = (struct dns_name_attrs){ 1356 .absolute = source->attributes.absolute 1357 }; 1358 if (name->labels > 0 && name->offsets != NULL) { 1359 set_offsets(name, name->offsets, NULL); 1360 } 1361 } 1362 1363 isc_buffer_add(target, name->length); 1364 1365 return ISC_R_SUCCESS; 1366 } 1367 1368 static void 1369 set_offsets(const dns_name_t *name, unsigned char *offsets, 1370 dns_name_t *set_name) { 1371 unsigned int offset, count, length, nlabels; 1372 unsigned char *ndata; 1373 bool absolute; 1374 1375 ndata = name->ndata; 1376 length = name->length; 1377 offset = 0; 1378 nlabels = 0; 1379 absolute = false; 1380 while (offset != length) { 1381 INSIST(nlabels < DNS_NAME_MAXLABELS); 1382 offsets[nlabels++] = offset; 1383 count = *ndata; 1384 INSIST(count <= DNS_NAME_LABELLEN); 1385 offset += count + 1; 1386 ndata += count + 1; 1387 INSIST(offset <= length); 1388 if (count == 0) { 1389 absolute = true; 1390 break; 1391 } 1392 } 1393 if (set_name != NULL) { 1394 INSIST(set_name == name); 1395 1396 set_name->labels = nlabels; 1397 set_name->length = offset; 1398 set_name->attributes.absolute = absolute; 1399 } 1400 INSIST(nlabels == name->labels); 1401 INSIST(offset == name->length); 1402 } 1403 1404 isc_result_t 1405 dns_name_fromwire(dns_name_t *const name, isc_buffer_t *const source, 1406 const dns_decompress_t dctx, isc_buffer_t *target) { 1407 /* 1408 * Copy the name at source into target, decompressing it. 1409 * 1410 * *** WARNING *** 1411 * 1412 * dns_name_fromwire() deals with raw network data. An error in this 1413 * routine could result in the failure or hijacking of the server. 1414 * 1415 * The description of name compression in RFC 1035 section 4.1.4 is 1416 * subtle wrt certain edge cases. The first important sentence is: 1417 * 1418 * > In this scheme, an entire domain name or a list of labels at the 1419 * > end of a domain name is replaced with a pointer to a prior 1420 * > occurrence of the same name. 1421 * 1422 * The key word is "prior". This says that compression pointers must 1423 * point strictly earlier in the message (before our "marker" variable), 1424 * which is enough to prevent DoS attacks due to compression loops. 1425 * 1426 * The next important sentence is: 1427 * 1428 * > If a domain name is contained in a part of the message subject to a 1429 * > length field (such as the RDATA section of an RR), and compression 1430 * > is used, the length of the compressed name is used in the length 1431 * > calculation, rather than the length of the expanded name. 1432 * 1433 * When decompressing, this means that the amount of the source buffer 1434 * that we consumed (which is checked wrt the container's length field) 1435 * is the length of the compressed name. A compressed name is defined as 1436 * a sequence of labels ending with the root label or a compression 1437 * pointer, that is, the segment of the name that dns_name_fromwire() 1438 * examines first. 1439 * 1440 * This matters when handling names that play dirty tricks, like: 1441 * 1442 * +---+---+---+---+---+---+ 1443 * | 4 | 1 |'a'|192| 0 | 0 | 1444 * +---+---+---+---+---+---+ 1445 * 1446 * We start at octet 1. There is an ordinary single character label "a", 1447 * followed by a compression pointer that refers back to octet zero. 1448 * Here there is a label of length 4, which weirdly re-uses the octets 1449 * we already examined as the data for the label. It is followed by the 1450 * root label, 1451 * 1452 * The specification says that the compressed name ends after the first 1453 * zero octet (after the compression pointer) not the second zero octet, 1454 * even though the second octet is later in the message. This shows the 1455 * correct way to set our "consumed" variable. 1456 */ 1457 1458 REQUIRE(DNS_NAME_VALID(name)); 1459 REQUIRE(DNS_NAME_BINDABLE(name)); 1460 REQUIRE((target != NULL && ISC_BUFFER_VALID(target)) || 1461 (target == NULL && ISC_BUFFER_VALID(name->buffer))); 1462 1463 if (target == NULL && name->buffer != NULL) { 1464 target = name->buffer; 1465 isc_buffer_clear(target); 1466 } 1467 1468 uint8_t *const name_buf = isc_buffer_used(target); 1469 const uint32_t name_max = ISC_MIN(DNS_NAME_MAXWIRE, 1470 isc_buffer_availablelength(target)); 1471 uint32_t name_len = 0; 1472 MAKE_EMPTY(name); /* in case of failure */ 1473 1474 dns_offsets_t odata; 1475 uint8_t *offsets = NULL; 1476 uint32_t labels = 0; 1477 INIT_OFFSETS(name, offsets, odata); 1478 1479 /* 1480 * After chasing a compression pointer, these variables refer to the 1481 * source buffer as follows: 1482 * 1483 * sb --- mr --- cr --- st --- cd --- sm 1484 * 1485 * sb = source_buf (const) 1486 * mr = marker 1487 * cr = cursor 1488 * st = start (const) 1489 * cd = consumed 1490 * sm = source_max (const) 1491 * 1492 * The marker hops backwards for each pointer. 1493 * The cursor steps forwards for each label. 1494 * The amount of the source we consumed is set once. 1495 */ 1496 const uint8_t *const source_buf = isc_buffer_base(source); 1497 const uint8_t *const source_max = isc_buffer_used(source); 1498 const uint8_t *const start = isc_buffer_current(source); 1499 const uint8_t *marker = start; 1500 const uint8_t *cursor = start; 1501 const uint8_t *consumed = NULL; 1502 1503 /* 1504 * One iteration per label. 1505 */ 1506 while (cursor < source_max) { 1507 const uint8_t label_len = *cursor++; 1508 if (label_len <= DNS_NAME_LABELLEN) { 1509 /* 1510 * Normal label: record its offset, and check bounds on 1511 * the name length, which also ensures we don't overrun 1512 * the offsets array. Don't touch any source bytes yet! 1513 * The source bounds check will happen when we loop. 1514 */ 1515 offsets[labels++] = name_len; 1516 /* and then a step to the ri-i-i-i-i-ight */ 1517 cursor += label_len; 1518 name_len += label_len + 1; 1519 if (name_len > name_max) { 1520 return name_max == DNS_NAME_MAXWIRE 1521 ? DNS_R_NAMETOOLONG 1522 : ISC_R_NOSPACE; 1523 } else if (label_len == 0) { 1524 goto root_label; 1525 } 1526 } else if (label_len < 192) { 1527 return DNS_R_BADLABELTYPE; 1528 } else if (!dns_decompress_getpermitted(dctx)) { 1529 return DNS_R_DISALLOWED; 1530 } else if (cursor < source_max) { 1531 /* 1532 * Compression pointer. Ensure it does not loop. 1533 * 1534 * Copy multiple labels in one go, to make the most of 1535 * memmove() performance. Start at the marker and finish 1536 * just before the pointer's hi+lo bytes, before the 1537 * cursor. Bounds were already checked. 1538 */ 1539 const uint32_t hi = label_len & 0x3F; 1540 const uint32_t lo = *cursor++; 1541 const uint8_t *pointer = source_buf + (256 * hi + lo); 1542 if (pointer >= marker) { 1543 return DNS_R_BADPOINTER; 1544 } 1545 const uint32_t copy_len = (cursor - 2) - marker; 1546 uint8_t *const dest = name_buf + name_len - copy_len; 1547 memmove(dest, marker, copy_len); 1548 consumed = consumed != NULL ? consumed : cursor; 1549 /* it's just a jump to the left */ 1550 cursor = marker = pointer; 1551 } 1552 } 1553 return ISC_R_UNEXPECTEDEND; 1554 root_label:; 1555 /* 1556 * Copy labels almost like we do for compression pointers, 1557 * from the marker up to and including the root label. 1558 */ 1559 const uint32_t copy_len = cursor - marker; 1560 memmove(name_buf + name_len - copy_len, marker, copy_len); 1561 consumed = consumed != NULL ? consumed : cursor; 1562 isc_buffer_forward(source, consumed - start); 1563 1564 name->attributes.absolute = true; 1565 name->ndata = name_buf; 1566 name->labels = labels; 1567 name->length = name_len; 1568 isc_buffer_add(target, name_len); 1569 1570 return ISC_R_SUCCESS; 1571 } 1572 1573 isc_result_t 1574 dns_name_towire(const dns_name_t *name, dns_compress_t *cctx, 1575 isc_buffer_t *target, uint16_t *name_coff) { 1576 bool compress; 1577 dns_offsets_t clo; 1578 dns_name_t clname; 1579 unsigned int here; 1580 unsigned int prefix_length; 1581 unsigned int suffix_coff; 1582 1583 /* 1584 * Convert 'name' into wire format, compressing it as specified by the 1585 * compression context 'cctx', and storing the result in 'target'. 1586 */ 1587 1588 REQUIRE(DNS_NAME_VALID(name)); 1589 REQUIRE(cctx != NULL); 1590 REQUIRE(ISC_BUFFER_VALID(target)); 1591 1592 compress = !name->attributes.nocompress && 1593 dns_compress_getpermitted(cctx); 1594 1595 /* 1596 * Write a compression pointer directly if the caller passed us 1597 * a pointer to this name's offset that we saved previously. 1598 */ 1599 if (compress && name_coff != NULL && *name_coff < 0x4000) { 1600 if (isc_buffer_availablelength(target) < 2) { 1601 return ISC_R_NOSPACE; 1602 } 1603 isc_buffer_putuint16(target, *name_coff | 0xc000); 1604 return ISC_R_SUCCESS; 1605 } 1606 1607 if (name->offsets == NULL) { 1608 dns_name_init(&clname, clo); 1609 dns_name_clone(name, &clname); 1610 name = &clname; 1611 } 1612 1613 /* 1614 * Always add the name to the compression context; if compression 1615 * is off, reset the return values before writing the name. 1616 */ 1617 prefix_length = name->length; 1618 suffix_coff = 0; 1619 dns_compress_name(cctx, target, name, &prefix_length, &suffix_coff); 1620 if (!compress) { 1621 prefix_length = name->length; 1622 suffix_coff = 0; 1623 } 1624 1625 /* 1626 * Return this name's compression offset for use next time, provided 1627 * it isn't too short for compression to help (i.e. it's the root) 1628 */ 1629 here = isc_buffer_usedlength(target); 1630 if (name_coff != NULL && here < 0x4000 && prefix_length > 1) { 1631 *name_coff = (uint16_t)here; 1632 } 1633 1634 if (prefix_length > 0) { 1635 if (isc_buffer_availablelength(target) < prefix_length) { 1636 return ISC_R_NOSPACE; 1637 } 1638 memmove(isc_buffer_used(target), name->ndata, prefix_length); 1639 isc_buffer_add(target, prefix_length); 1640 } 1641 1642 if (suffix_coff > 0) { 1643 if (name_coff != NULL && prefix_length == 0) { 1644 *name_coff = suffix_coff; 1645 } 1646 if (isc_buffer_availablelength(target) < 2) { 1647 return ISC_R_NOSPACE; 1648 } 1649 isc_buffer_putuint16(target, suffix_coff | 0xc000); 1650 } 1651 1652 return ISC_R_SUCCESS; 1653 } 1654 1655 isc_result_t 1656 dns_name_concatenate(const dns_name_t *prefix, const dns_name_t *suffix, 1657 dns_name_t *name, isc_buffer_t *target) { 1658 unsigned char *ndata, *offsets; 1659 unsigned int nrem, labels, prefix_length, length; 1660 bool copy_prefix = true; 1661 bool copy_suffix = true; 1662 bool absolute = false; 1663 dns_name_t tmp_name; 1664 dns_offsets_t odata; 1665 1666 /* 1667 * Concatenate 'prefix' and 'suffix'. 1668 */ 1669 1670 REQUIRE(prefix == NULL || DNS_NAME_VALID(prefix)); 1671 REQUIRE(suffix == NULL || DNS_NAME_VALID(suffix)); 1672 REQUIRE(name == NULL || DNS_NAME_VALID(name)); 1673 REQUIRE((target != NULL && ISC_BUFFER_VALID(target)) || 1674 (target == NULL && name != NULL && 1675 ISC_BUFFER_VALID(name->buffer))); 1676 if (prefix == NULL || prefix->labels == 0) { 1677 copy_prefix = false; 1678 } 1679 if (suffix == NULL || suffix->labels == 0) { 1680 copy_suffix = false; 1681 } 1682 if (copy_prefix && prefix->attributes.absolute) { 1683 absolute = true; 1684 REQUIRE(!copy_suffix); 1685 } 1686 if (name == NULL) { 1687 dns_name_init(&tmp_name, odata); 1688 name = &tmp_name; 1689 } 1690 if (target == NULL) { 1691 INSIST(name->buffer != NULL); 1692 target = name->buffer; 1693 isc_buffer_clear(name->buffer); 1694 } 1695 1696 REQUIRE(DNS_NAME_BINDABLE(name)); 1697 1698 /* 1699 * Set up. 1700 */ 1701 nrem = target->length - target->used; 1702 ndata = (unsigned char *)target->base + target->used; 1703 if (nrem > DNS_NAME_MAXWIRE) { 1704 nrem = DNS_NAME_MAXWIRE; 1705 } 1706 length = 0; 1707 prefix_length = 0; 1708 labels = 0; 1709 if (copy_prefix) { 1710 prefix_length = prefix->length; 1711 length += prefix_length; 1712 labels += prefix->labels; 1713 } 1714 if (copy_suffix) { 1715 length += suffix->length; 1716 labels += suffix->labels; 1717 } 1718 if (length > DNS_NAME_MAXWIRE) { 1719 MAKE_EMPTY(name); 1720 return DNS_R_NAMETOOLONG; 1721 } 1722 if (length > nrem) { 1723 MAKE_EMPTY(name); 1724 return ISC_R_NOSPACE; 1725 } 1726 1727 if (copy_suffix) { 1728 if (suffix->attributes.absolute) { 1729 absolute = true; 1730 } 1731 memmove(ndata + prefix_length, suffix->ndata, suffix->length); 1732 } 1733 1734 /* 1735 * If 'prefix' and 'name' are the same object, and the object has 1736 * a dedicated buffer, and we're using it, then we don't have to 1737 * copy anything. 1738 */ 1739 if (copy_prefix && (prefix != name || prefix->buffer != target)) { 1740 memmove(ndata, prefix->ndata, prefix_length); 1741 } 1742 1743 name->ndata = ndata; 1744 name->labels = labels; 1745 name->length = length; 1746 name->attributes.absolute = absolute; 1747 1748 if (name->labels > 0 && name->offsets != NULL) { 1749 INIT_OFFSETS(name, offsets, odata); 1750 set_offsets(name, offsets, NULL); 1751 } 1752 1753 isc_buffer_add(target, name->length); 1754 1755 return ISC_R_SUCCESS; 1756 } 1757 1758 void 1759 dns_name_dup(const dns_name_t *source, isc_mem_t *mctx, dns_name_t *target) { 1760 /* 1761 * Make 'target' a dynamically allocated copy of 'source'. 1762 */ 1763 1764 REQUIRE(DNS_NAME_VALID(source)); 1765 REQUIRE(source->length > 0); 1766 REQUIRE(DNS_NAME_VALID(target)); 1767 REQUIRE(DNS_NAME_BINDABLE(target)); 1768 1769 /* 1770 * Make 'target' empty in case of failure. 1771 */ 1772 MAKE_EMPTY(target); 1773 1774 target->ndata = isc_mem_get(mctx, source->length); 1775 1776 memmove(target->ndata, source->ndata, source->length); 1777 1778 target->length = source->length; 1779 target->labels = source->labels; 1780 target->attributes = (struct dns_name_attrs){ .dynamic = true }; 1781 target->attributes.absolute = source->attributes.absolute; 1782 if (target->offsets != NULL) { 1783 if (source->offsets != NULL) { 1784 memmove(target->offsets, source->offsets, 1785 source->labels); 1786 } else { 1787 set_offsets(target, target->offsets, NULL); 1788 } 1789 } 1790 } 1791 1792 void 1793 dns_name_dupwithoffsets(const dns_name_t *source, isc_mem_t *mctx, 1794 dns_name_t *target) { 1795 /* 1796 * Make 'target' a read-only dynamically allocated copy of 'source'. 1797 * 'target' will also have a dynamically allocated offsets table. 1798 */ 1799 1800 REQUIRE(DNS_NAME_VALID(source)); 1801 REQUIRE(source->length > 0); 1802 REQUIRE(DNS_NAME_VALID(target)); 1803 REQUIRE(DNS_NAME_BINDABLE(target)); 1804 REQUIRE(target->offsets == NULL); 1805 1806 /* 1807 * Make 'target' empty in case of failure. 1808 */ 1809 MAKE_EMPTY(target); 1810 1811 target->ndata = isc_mem_get(mctx, source->length + source->labels); 1812 1813 memmove(target->ndata, source->ndata, source->length); 1814 1815 target->length = source->length; 1816 target->labels = source->labels; 1817 target->attributes = (struct dns_name_attrs){ .dynamic = true, 1818 .dynoffsets = true, 1819 .readonly = true }; 1820 target->attributes.absolute = source->attributes.absolute; 1821 target->offsets = target->ndata + source->length; 1822 if (source->offsets != NULL) { 1823 memmove(target->offsets, source->offsets, source->labels); 1824 } else { 1825 set_offsets(target, target->offsets, NULL); 1826 } 1827 } 1828 1829 void 1830 dns_name_free(dns_name_t *name, isc_mem_t *mctx) { 1831 size_t size; 1832 1833 /* 1834 * Free 'name'. 1835 */ 1836 1837 REQUIRE(DNS_NAME_VALID(name)); 1838 REQUIRE(name->attributes.dynamic); 1839 1840 size = name->length; 1841 if (name->attributes.dynoffsets) { 1842 size += name->labels; 1843 } 1844 isc_mem_put(mctx, name->ndata, size); 1845 dns_name_invalidate(name); 1846 } 1847 1848 size_t 1849 dns_name_size(const dns_name_t *name) { 1850 size_t size; 1851 1852 REQUIRE(DNS_NAME_VALID(name)); 1853 1854 if (!name->attributes.dynamic) { 1855 return 0; 1856 } 1857 1858 size = name->length; 1859 if (name->attributes.dynoffsets) { 1860 size += name->labels; 1861 } 1862 1863 return size; 1864 } 1865 1866 isc_result_t 1867 dns_name_digest(const dns_name_t *name, dns_digestfunc_t digest, void *arg) { 1868 dns_name_t downname; 1869 unsigned char data[256]; 1870 isc_buffer_t buffer; 1871 isc_result_t result; 1872 isc_region_t r; 1873 1874 /* 1875 * Send 'name' in DNSSEC canonical form to 'digest'. 1876 */ 1877 1878 REQUIRE(DNS_NAME_VALID(name)); 1879 REQUIRE(digest != NULL); 1880 1881 dns_name_init(&downname, NULL); 1882 1883 isc_buffer_init(&buffer, data, sizeof(data)); 1884 1885 result = dns_name_downcase(name, &downname, &buffer); 1886 if (result != ISC_R_SUCCESS) { 1887 return result; 1888 } 1889 1890 isc_buffer_usedregion(&buffer, &r); 1891 1892 return (digest)(arg, &r); 1893 } 1894 1895 bool 1896 dns_name_dynamic(const dns_name_t *name) { 1897 REQUIRE(DNS_NAME_VALID(name)); 1898 1899 /* 1900 * Returns whether there is dynamic memory associated with this name. 1901 */ 1902 1903 return name->attributes.dynamic; 1904 } 1905 1906 isc_result_t 1907 dns_name_print(const dns_name_t *name, FILE *stream) { 1908 isc_result_t result; 1909 isc_buffer_t b; 1910 isc_region_t r; 1911 char t[1024]; 1912 1913 /* 1914 * Print 'name' on 'stream'. 1915 */ 1916 1917 REQUIRE(DNS_NAME_VALID(name)); 1918 1919 isc_buffer_init(&b, t, sizeof(t)); 1920 result = dns_name_totext(name, 0, &b); 1921 if (result != ISC_R_SUCCESS) { 1922 return result; 1923 } 1924 isc_buffer_usedregion(&b, &r); 1925 fprintf(stream, "%.*s", (int)r.length, (char *)r.base); 1926 1927 return ISC_R_SUCCESS; 1928 } 1929 1930 isc_result_t 1931 dns_name_settotextfilter(dns_name_totextfilter_t *proc) { 1932 /* 1933 * If we already have been here set / clear as appropriate. 1934 */ 1935 if (totext_filter_proc != NULL && proc != NULL) { 1936 if (totext_filter_proc == proc) { 1937 return ISC_R_SUCCESS; 1938 } 1939 } 1940 if (proc == NULL && totext_filter_proc != NULL) { 1941 totext_filter_proc = NULL; 1942 return ISC_R_SUCCESS; 1943 } 1944 1945 totext_filter_proc = proc; 1946 1947 return ISC_R_SUCCESS; 1948 } 1949 1950 void 1951 dns_name_format(const dns_name_t *name, char *cp, unsigned int size) { 1952 isc_result_t result; 1953 isc_buffer_t buf; 1954 1955 REQUIRE(size > 0); 1956 1957 /* 1958 * Leave room for null termination after buffer. 1959 */ 1960 isc_buffer_init(&buf, cp, size - 1); 1961 result = dns_name_totext(name, DNS_NAME_OMITFINALDOT, &buf); 1962 if (result == ISC_R_SUCCESS) { 1963 isc_buffer_putuint8(&buf, (uint8_t)'\0'); 1964 } else { 1965 snprintf(cp, size, "<unknown>"); 1966 } 1967 } 1968 1969 /* 1970 * dns_name_tostring() -- similar to dns_name_format() but allocates its own 1971 * memory. 1972 */ 1973 isc_result_t 1974 dns_name_tostring(const dns_name_t *name, char **target, isc_mem_t *mctx) { 1975 isc_result_t result; 1976 isc_buffer_t buf; 1977 isc_region_t reg; 1978 char *p, txt[DNS_NAME_FORMATSIZE]; 1979 1980 REQUIRE(DNS_NAME_VALID(name)); 1981 REQUIRE(target != NULL && *target == NULL); 1982 1983 isc_buffer_init(&buf, txt, sizeof(txt)); 1984 result = dns_name_totext(name, 0, &buf); 1985 if (result != ISC_R_SUCCESS) { 1986 return result; 1987 } 1988 1989 isc_buffer_usedregion(&buf, ®); 1990 p = isc_mem_allocate(mctx, reg.length + 1); 1991 memmove(p, (char *)reg.base, (int)reg.length); 1992 p[reg.length] = '\0'; 1993 1994 *target = p; 1995 return ISC_R_SUCCESS; 1996 } 1997 1998 isc_result_t 1999 dns_name_fromstring(dns_name_t *target, const char *src, 2000 const dns_name_t *origin, unsigned int options, 2001 isc_mem_t *mctx) { 2002 isc_result_t result; 2003 isc_buffer_t buf; 2004 dns_fixedname_t fn; 2005 dns_name_t *name; 2006 2007 REQUIRE(src != NULL); 2008 2009 isc_buffer_constinit(&buf, src, strlen(src)); 2010 isc_buffer_add(&buf, strlen(src)); 2011 if (DNS_NAME_BINDABLE(target) && target->buffer != NULL) { 2012 name = target; 2013 } else { 2014 name = dns_fixedname_initname(&fn); 2015 } 2016 2017 result = dns_name_fromtext(name, &buf, origin, options, NULL); 2018 if (result != ISC_R_SUCCESS) { 2019 return result; 2020 } 2021 2022 if (name != target) { 2023 dns_name_dupwithoffsets(name, mctx, target); 2024 } 2025 return result; 2026 } 2027 2028 void 2029 dns_name_copy(const dns_name_t *source, dns_name_t *dest) { 2030 isc_buffer_t *target = NULL; 2031 unsigned char *ndata = NULL; 2032 2033 REQUIRE(DNS_NAME_VALID(source)); 2034 REQUIRE(DNS_NAME_VALID(dest)); 2035 REQUIRE(DNS_NAME_BINDABLE(dest)); 2036 2037 target = dest->buffer; 2038 2039 REQUIRE(target != NULL); 2040 REQUIRE(target->length >= source->length); 2041 2042 isc_buffer_clear(target); 2043 2044 ndata = (unsigned char *)target->base; 2045 dest->ndata = target->base; 2046 2047 if (source->length != 0) { 2048 memmove(ndata, source->ndata, source->length); 2049 } 2050 2051 dest->ndata = ndata; 2052 dest->labels = source->labels; 2053 dest->length = source->length; 2054 dest->attributes.absolute = source->attributes.absolute; 2055 2056 if (dest->labels > 0 && dest->offsets != NULL) { 2057 if (source->offsets != NULL && source->labels != 0) { 2058 memmove(dest->offsets, source->offsets, source->labels); 2059 } else { 2060 set_offsets(dest, dest->offsets, NULL); 2061 } 2062 } 2063 2064 isc_buffer_add(target, dest->length); 2065 } 2066 2067 /* 2068 * Service Discovery Prefixes RFC 6763. 2069 */ 2070 static unsigned char b_dns_sd_udp_data[] = "\001b\007_dns-sd\004_udp"; 2071 static unsigned char b_dns_sd_udp_offsets[] = { 0, 2, 10 }; 2072 static unsigned char db_dns_sd_udp_data[] = "\002db\007_dns-sd\004_udp"; 2073 static unsigned char db_dns_sd_udp_offsets[] = { 0, 3, 11 }; 2074 static unsigned char r_dns_sd_udp_data[] = "\001r\007_dns-sd\004_udp"; 2075 static unsigned char r_dns_sd_udp_offsets[] = { 0, 2, 10 }; 2076 static unsigned char dr_dns_sd_udp_data[] = "\002dr\007_dns-sd\004_udp"; 2077 static unsigned char dr_dns_sd_udp_offsets[] = { 0, 3, 11 }; 2078 static unsigned char lb_dns_sd_udp_data[] = "\002lb\007_dns-sd\004_udp"; 2079 static unsigned char lb_dns_sd_udp_offsets[] = { 0, 3, 11 }; 2080 2081 static dns_name_t const dns_sd[] = { 2082 DNS_NAME_INITNONABSOLUTE(b_dns_sd_udp_data, b_dns_sd_udp_offsets), 2083 DNS_NAME_INITNONABSOLUTE(db_dns_sd_udp_data, db_dns_sd_udp_offsets), 2084 DNS_NAME_INITNONABSOLUTE(r_dns_sd_udp_data, r_dns_sd_udp_offsets), 2085 DNS_NAME_INITNONABSOLUTE(dr_dns_sd_udp_data, dr_dns_sd_udp_offsets), 2086 DNS_NAME_INITNONABSOLUTE(lb_dns_sd_udp_data, lb_dns_sd_udp_offsets) 2087 }; 2088 2089 bool 2090 dns_name_isdnssd(const dns_name_t *name) { 2091 size_t i; 2092 dns_name_t prefix; 2093 2094 if (dns_name_countlabels(name) > 3U) { 2095 dns_name_init(&prefix, NULL); 2096 dns_name_getlabelsequence(name, 0, 3, &prefix); 2097 for (i = 0; i < (sizeof(dns_sd) / sizeof(dns_sd[0])); i++) { 2098 if (dns_name_equal(&prefix, &dns_sd[i])) { 2099 return true; 2100 } 2101 } 2102 } 2103 2104 return false; 2105 } 2106 2107 static unsigned char inaddr10_offsets[] = { 0, 3, 11, 16 }; 2108 static unsigned char inaddr172_offsets[] = { 0, 3, 7, 15, 20 }; 2109 static unsigned char inaddr192_offsets[] = { 0, 4, 8, 16, 21 }; 2110 2111 static unsigned char inaddr10[] = "\00210\007IN-ADDR\004ARPA"; 2112 2113 static unsigned char inaddr16172[] = "\00216\003172\007IN-ADDR\004ARPA"; 2114 static unsigned char inaddr17172[] = "\00217\003172\007IN-ADDR\004ARPA"; 2115 static unsigned char inaddr18172[] = "\00218\003172\007IN-ADDR\004ARPA"; 2116 static unsigned char inaddr19172[] = "\00219\003172\007IN-ADDR\004ARPA"; 2117 static unsigned char inaddr20172[] = "\00220\003172\007IN-ADDR\004ARPA"; 2118 static unsigned char inaddr21172[] = "\00221\003172\007IN-ADDR\004ARPA"; 2119 static unsigned char inaddr22172[] = "\00222\003172\007IN-ADDR\004ARPA"; 2120 static unsigned char inaddr23172[] = "\00223\003172\007IN-ADDR\004ARPA"; 2121 static unsigned char inaddr24172[] = "\00224\003172\007IN-ADDR\004ARPA"; 2122 static unsigned char inaddr25172[] = "\00225\003172\007IN-ADDR\004ARPA"; 2123 static unsigned char inaddr26172[] = "\00226\003172\007IN-ADDR\004ARPA"; 2124 static unsigned char inaddr27172[] = "\00227\003172\007IN-ADDR\004ARPA"; 2125 static unsigned char inaddr28172[] = "\00228\003172\007IN-ADDR\004ARPA"; 2126 static unsigned char inaddr29172[] = "\00229\003172\007IN-ADDR\004ARPA"; 2127 static unsigned char inaddr30172[] = "\00230\003172\007IN-ADDR\004ARPA"; 2128 static unsigned char inaddr31172[] = "\00231\003172\007IN-ADDR\004ARPA"; 2129 2130 static unsigned char inaddr168192[] = "\003168\003192\007IN-ADDR\004ARPA"; 2131 2132 static dns_name_t const rfc1918names[] = { 2133 DNS_NAME_INITABSOLUTE(inaddr10, inaddr10_offsets), 2134 DNS_NAME_INITABSOLUTE(inaddr16172, inaddr172_offsets), 2135 DNS_NAME_INITABSOLUTE(inaddr17172, inaddr172_offsets), 2136 DNS_NAME_INITABSOLUTE(inaddr18172, inaddr172_offsets), 2137 DNS_NAME_INITABSOLUTE(inaddr19172, inaddr172_offsets), 2138 DNS_NAME_INITABSOLUTE(inaddr20172, inaddr172_offsets), 2139 DNS_NAME_INITABSOLUTE(inaddr21172, inaddr172_offsets), 2140 DNS_NAME_INITABSOLUTE(inaddr22172, inaddr172_offsets), 2141 DNS_NAME_INITABSOLUTE(inaddr23172, inaddr172_offsets), 2142 DNS_NAME_INITABSOLUTE(inaddr24172, inaddr172_offsets), 2143 DNS_NAME_INITABSOLUTE(inaddr25172, inaddr172_offsets), 2144 DNS_NAME_INITABSOLUTE(inaddr26172, inaddr172_offsets), 2145 DNS_NAME_INITABSOLUTE(inaddr27172, inaddr172_offsets), 2146 DNS_NAME_INITABSOLUTE(inaddr28172, inaddr172_offsets), 2147 DNS_NAME_INITABSOLUTE(inaddr29172, inaddr172_offsets), 2148 DNS_NAME_INITABSOLUTE(inaddr30172, inaddr172_offsets), 2149 DNS_NAME_INITABSOLUTE(inaddr31172, inaddr172_offsets), 2150 DNS_NAME_INITABSOLUTE(inaddr168192, inaddr192_offsets) 2151 }; 2152 2153 bool 2154 dns_name_isrfc1918(const dns_name_t *name) { 2155 size_t i; 2156 2157 for (i = 0; i < (sizeof(rfc1918names) / sizeof(*rfc1918names)); i++) { 2158 if (dns_name_issubdomain(name, &rfc1918names[i])) { 2159 return true; 2160 } 2161 } 2162 return false; 2163 } 2164 2165 static unsigned char ulaoffsets[] = { 0, 2, 4, 8, 13 }; 2166 static unsigned char ip6fc[] = "\001c\001f\003ip6\004ARPA"; 2167 static unsigned char ip6fd[] = "\001d\001f\003ip6\004ARPA"; 2168 2169 static dns_name_t const ulanames[] = { DNS_NAME_INITABSOLUTE(ip6fc, ulaoffsets), 2170 DNS_NAME_INITABSOLUTE(ip6fd, 2171 ulaoffsets) }; 2172 2173 bool 2174 dns_name_isula(const dns_name_t *name) { 2175 size_t i; 2176 2177 for (i = 0; i < (sizeof(ulanames) / sizeof(*ulanames)); i++) { 2178 if (dns_name_issubdomain(name, &ulanames[i])) { 2179 return true; 2180 } 2181 } 2182 return false; 2183 } 2184 2185 bool 2186 dns_name_istat(const dns_name_t *name) { 2187 unsigned char len; 2188 const unsigned char *ndata; 2189 2190 REQUIRE(DNS_NAME_VALID(name)); 2191 2192 if (name->labels < 1) { 2193 return false; 2194 } 2195 2196 ndata = name->ndata; 2197 len = ndata[0]; 2198 INSIST(len <= name->length); 2199 ndata++; 2200 2201 /* 2202 * Is there at least one trust anchor reported and is the 2203 * label length consistent with a trust-anchor-telemetry label. 2204 */ 2205 if ((len < 8) || (len - 3) % 5 != 0) { 2206 return false; 2207 } 2208 2209 if (ndata[0] != '_' || isc_ascii_tolower(ndata[1]) != 't' || 2210 isc_ascii_tolower(ndata[2]) != 'a') 2211 { 2212 return false; 2213 } 2214 ndata += 3; 2215 len -= 3; 2216 2217 while (len > 0) { 2218 INSIST(len >= 5); 2219 if (ndata[0] != '-' || !isc_hex_char(ndata[1]) || 2220 !isc_hex_char(ndata[2]) || !isc_hex_char(ndata[3]) || 2221 !isc_hex_char(ndata[4])) 2222 { 2223 return false; 2224 } 2225 ndata += 5; 2226 len -= 5; 2227 } 2228 return true; 2229 } 2230 2231 bool 2232 dns_name_isdnssvcb(const dns_name_t *name) { 2233 unsigned char len, len1; 2234 const unsigned char *ndata; 2235 2236 REQUIRE(DNS_NAME_VALID(name)); 2237 2238 if (name->labels < 1 || name->length < 5) { 2239 return false; 2240 } 2241 2242 ndata = name->ndata; 2243 len = len1 = ndata[0]; 2244 INSIST(len <= name->length); 2245 ndata++; 2246 2247 if (len < 2 || ndata[0] != '_') { 2248 return false; 2249 } 2250 if (isdigit(ndata[1]) && name->labels > 1) { 2251 char buf[sizeof("65000")]; 2252 long port; 2253 char *endp; 2254 2255 /* 2256 * Do we have a valid _port label? 2257 */ 2258 if (len > 6U || (ndata[1] == '0' && len != 2)) { 2259 return false; 2260 } 2261 memcpy(buf, ndata + 1, len - 1); 2262 buf[len - 1] = 0; 2263 port = strtol(buf, &endp, 10); 2264 if (*endp != 0 || port < 0 || port > 0xffff) { 2265 return false; 2266 } 2267 2268 /* 2269 * Move to next label. 2270 */ 2271 ndata += len; 2272 INSIST(len1 + 1U < name->length); 2273 len = *ndata; 2274 INSIST(len + len1 + 1U <= name->length); 2275 ndata++; 2276 } 2277 2278 if (len == 4U && strncasecmp((const char *)ndata, "_dns", 4) == 0) { 2279 return true; 2280 } 2281 2282 return false; 2283 } 2284