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