1 /* 2 * util/data/dname.h - domain name handling 3 * 4 * Copyright (c) 2007, NLnet Labs. All rights reserved. 5 * 6 * This software is open source. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 12 * Redistributions of source code must retain the above copyright notice, 13 * this list of conditions and the following disclaimer. 14 * 15 * Redistributions in binary form must reproduce the above copyright notice, 16 * this list of conditions and the following disclaimer in the documentation 17 * and/or other materials provided with the distribution. 18 * 19 * Neither the name of the NLNET LABS nor the names of its contributors may 20 * be used to endorse or promote products derived from this software without 21 * specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 26 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 27 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 28 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 29 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 30 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 31 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 32 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 33 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34 */ 35 36 /** 37 * \file 38 * 39 * This file contains domain name handling functions. 40 */ 41 42 #include "config.h" 43 #include <ctype.h> 44 #include "util/data/dname.h" 45 #include "util/data/msgparse.h" 46 #include "util/log.h" 47 #include "util/storage/lookup3.h" 48 #include "sldns/sbuffer.h" 49 50 /* determine length of a dname in buffer, no compression pointers allowed */ 51 size_t 52 query_dname_len(sldns_buffer* query) 53 { 54 size_t len = 0; 55 size_t labellen; 56 while(1) { 57 if(sldns_buffer_remaining(query) < 1) 58 return 0; /* parse error, need label len */ 59 labellen = sldns_buffer_read_u8(query); 60 if(labellen&0xc0) 61 return 0; /* no compression allowed in queries */ 62 len += labellen + 1; 63 if(len > LDNS_MAX_DOMAINLEN) 64 return 0; /* too long */ 65 if(labellen == 0) 66 return len; 67 if(sldns_buffer_remaining(query) < labellen) 68 return 0; /* parse error, need content */ 69 sldns_buffer_skip(query, (ssize_t)labellen); 70 } 71 } 72 73 size_t 74 dname_valid(uint8_t* dname, size_t maxlen) 75 { 76 size_t len = 0; 77 size_t labellen; 78 labellen = *dname++; 79 while(labellen) { 80 if(labellen&0xc0) 81 return 0; /* no compression ptrs allowed */ 82 len += labellen + 1; 83 if(len >= LDNS_MAX_DOMAINLEN) 84 return 0; /* too long */ 85 if(len > maxlen) 86 return 0; /* does not fit in memory allocation */ 87 dname += labellen; 88 labellen = *dname++; 89 } 90 len += 1; 91 if(len > maxlen) 92 return 0; /* does not fit in memory allocation */ 93 return len; 94 } 95 96 /** compare uncompressed, noncanonical, registers are hints for speed */ 97 int 98 query_dname_compare(register uint8_t* d1, register uint8_t* d2) 99 { 100 register uint8_t lab1, lab2; 101 log_assert(d1 && d2); 102 lab1 = *d1++; 103 lab2 = *d2++; 104 while( lab1 != 0 || lab2 != 0 ) { 105 /* compare label length */ 106 /* if one dname ends, it has labellength 0 */ 107 if(lab1 != lab2) { 108 if(lab1 < lab2) 109 return -1; 110 return 1; 111 } 112 log_assert(lab1 == lab2 && lab1 != 0); 113 /* compare lowercased labels. */ 114 while(lab1--) { 115 /* compare bytes first for speed */ 116 if(*d1 != *d2 && 117 tolower((unsigned char)*d1) != tolower((unsigned char)*d2)) { 118 if(tolower((unsigned char)*d1) < tolower((unsigned char)*d2)) 119 return -1; 120 return 1; 121 } 122 d1++; 123 d2++; 124 } 125 /* next pair of labels. */ 126 lab1 = *d1++; 127 lab2 = *d2++; 128 } 129 return 0; 130 } 131 132 void 133 query_dname_tolower(uint8_t* dname) 134 { 135 /* the dname is stored uncompressed */ 136 uint8_t labellen; 137 labellen = *dname; 138 while(labellen) { 139 dname++; 140 while(labellen--) { 141 *dname = (uint8_t)tolower((unsigned char)*dname); 142 dname++; 143 } 144 labellen = *dname; 145 } 146 } 147 148 void 149 pkt_dname_tolower(sldns_buffer* pkt, uint8_t* dname) 150 { 151 uint8_t lablen; 152 int count = 0; 153 if(dname >= sldns_buffer_end(pkt)) 154 return; 155 lablen = *dname++; 156 while(lablen) { 157 if(LABEL_IS_PTR(lablen)) { 158 if((size_t)PTR_OFFSET(lablen, *dname) 159 >= sldns_buffer_limit(pkt)) 160 return; 161 dname = sldns_buffer_at(pkt, PTR_OFFSET(lablen, *dname)); 162 lablen = *dname++; 163 if(count++ > MAX_COMPRESS_PTRS) 164 return; 165 continue; 166 } 167 if(dname+lablen >= sldns_buffer_end(pkt)) 168 return; 169 while(lablen--) { 170 *dname = (uint8_t)tolower((unsigned char)*dname); 171 dname++; 172 } 173 if(dname >= sldns_buffer_end(pkt)) 174 return; 175 lablen = *dname++; 176 } 177 } 178 179 180 size_t 181 pkt_dname_len(sldns_buffer* pkt) 182 { 183 size_t len = 0; 184 int ptrcount = 0; 185 uint8_t labellen; 186 size_t endpos = 0; 187 188 /* read dname and determine length */ 189 /* check compression pointers, loops, out of bounds */ 190 while(1) { 191 /* read next label */ 192 if(sldns_buffer_remaining(pkt) < 1) 193 return 0; 194 labellen = sldns_buffer_read_u8(pkt); 195 if(LABEL_IS_PTR(labellen)) { 196 /* compression ptr */ 197 uint16_t ptr; 198 if(sldns_buffer_remaining(pkt) < 1) 199 return 0; 200 ptr = PTR_OFFSET(labellen, sldns_buffer_read_u8(pkt)); 201 if(ptrcount++ > MAX_COMPRESS_PTRS) 202 return 0; /* loop! */ 203 if(sldns_buffer_limit(pkt) <= ptr) 204 return 0; /* out of bounds! */ 205 if(!endpos) 206 endpos = sldns_buffer_position(pkt); 207 sldns_buffer_set_position(pkt, ptr); 208 } else { 209 /* label contents */ 210 if(labellen > 0x3f) 211 return 0; /* label too long */ 212 len += 1 + labellen; 213 if(len > LDNS_MAX_DOMAINLEN) 214 return 0; 215 if(labellen == 0) { 216 /* end of dname */ 217 break; 218 } 219 if(sldns_buffer_remaining(pkt) < labellen) 220 return 0; 221 sldns_buffer_skip(pkt, (ssize_t)labellen); 222 } 223 } 224 if(endpos) 225 sldns_buffer_set_position(pkt, endpos); 226 227 return len; 228 } 229 230 int 231 dname_pkt_compare(sldns_buffer* pkt, uint8_t* d1, uint8_t* d2) 232 { 233 uint8_t len1, len2; 234 log_assert(pkt && d1 && d2); 235 len1 = *d1++; 236 len2 = *d2++; 237 while( len1 != 0 || len2 != 0 ) { 238 /* resolve ptrs */ 239 if(LABEL_IS_PTR(len1)) { 240 d1 = sldns_buffer_at(pkt, PTR_OFFSET(len1, *d1)); 241 len1 = *d1++; 242 continue; 243 } 244 if(LABEL_IS_PTR(len2)) { 245 d2 = sldns_buffer_at(pkt, PTR_OFFSET(len2, *d2)); 246 len2 = *d2++; 247 continue; 248 } 249 /* check label length */ 250 log_assert(len1 <= LDNS_MAX_LABELLEN); 251 log_assert(len2 <= LDNS_MAX_LABELLEN); 252 if(len1 != len2) { 253 if(len1 < len2) return -1; 254 return 1; 255 } 256 log_assert(len1 == len2 && len1 != 0); 257 /* compare labels */ 258 while(len1--) { 259 if(tolower((unsigned char)*d1) != tolower((unsigned char)*d2)) { 260 if(tolower((unsigned char)*d1) < tolower((unsigned char)*d2)) 261 return -1; 262 return 1; 263 } 264 d1++; 265 d2++; 266 } 267 len1 = *d1++; 268 len2 = *d2++; 269 } 270 return 0; 271 } 272 273 hashvalue_t 274 dname_query_hash(uint8_t* dname, hashvalue_t h) 275 { 276 uint8_t labuf[LDNS_MAX_LABELLEN+1]; 277 uint8_t lablen; 278 int i; 279 280 /* preserve case of query, make hash label by label */ 281 lablen = *dname++; 282 while(lablen) { 283 log_assert(lablen <= LDNS_MAX_LABELLEN); 284 labuf[0] = lablen; 285 i=0; 286 while(lablen--) { 287 labuf[++i] = (uint8_t)tolower((unsigned char)*dname); 288 dname++; 289 } 290 h = hashlittle(labuf, labuf[0] + 1, h); 291 lablen = *dname++; 292 } 293 294 return h; 295 } 296 297 hashvalue_t 298 dname_pkt_hash(sldns_buffer* pkt, uint8_t* dname, hashvalue_t h) 299 { 300 uint8_t labuf[LDNS_MAX_LABELLEN+1]; 301 uint8_t lablen; 302 int i; 303 304 /* preserve case of query, make hash label by label */ 305 lablen = *dname++; 306 while(lablen) { 307 if(LABEL_IS_PTR(lablen)) { 308 /* follow pointer */ 309 dname = sldns_buffer_at(pkt, PTR_OFFSET(lablen, *dname)); 310 lablen = *dname++; 311 continue; 312 } 313 log_assert(lablen <= LDNS_MAX_LABELLEN); 314 labuf[0] = lablen; 315 i=0; 316 while(lablen--) { 317 labuf[++i] = (uint8_t)tolower((unsigned char)*dname); 318 dname++; 319 } 320 h = hashlittle(labuf, labuf[0] + 1, h); 321 lablen = *dname++; 322 } 323 324 return h; 325 } 326 327 void dname_pkt_copy(sldns_buffer* pkt, uint8_t* to, uint8_t* dname) 328 { 329 /* copy over the dname and decompress it at the same time */ 330 size_t len = 0; 331 uint8_t lablen; 332 lablen = *dname++; 333 while(lablen) { 334 if(LABEL_IS_PTR(lablen)) { 335 /* follow pointer */ 336 dname = sldns_buffer_at(pkt, PTR_OFFSET(lablen, *dname)); 337 lablen = *dname++; 338 continue; 339 } 340 log_assert(lablen <= LDNS_MAX_LABELLEN); 341 len += (size_t)lablen+1; 342 if(len >= LDNS_MAX_DOMAINLEN) { 343 *to = 0; /* end the result prematurely */ 344 log_err("bad dname in dname_pkt_copy"); 345 return; 346 } 347 *to++ = lablen; 348 memmove(to, dname, lablen); 349 dname += lablen; 350 to += lablen; 351 lablen = *dname++; 352 } 353 /* copy last \0 */ 354 *to = 0; 355 } 356 357 void dname_print(FILE* out, struct sldns_buffer* pkt, uint8_t* dname) 358 { 359 uint8_t lablen; 360 if(!out) out = stdout; 361 if(!dname) return; 362 363 lablen = *dname++; 364 if(!lablen) 365 fputc('.', out); 366 while(lablen) { 367 if(LABEL_IS_PTR(lablen)) { 368 /* follow pointer */ 369 if(!pkt) { 370 fputs("??compressionptr??", out); 371 return; 372 } 373 dname = sldns_buffer_at(pkt, PTR_OFFSET(lablen, *dname)); 374 lablen = *dname++; 375 continue; 376 } 377 if(lablen > LDNS_MAX_LABELLEN) { 378 fputs("??extendedlabel??", out); 379 return; 380 } 381 while(lablen--) 382 fputc((int)*dname++, out); 383 fputc('.', out); 384 lablen = *dname++; 385 } 386 } 387 388 int 389 dname_count_labels(uint8_t* dname) 390 { 391 uint8_t lablen; 392 int labs = 1; 393 394 lablen = *dname++; 395 while(lablen) { 396 labs++; 397 dname += lablen; 398 lablen = *dname++; 399 } 400 return labs; 401 } 402 403 int 404 dname_count_size_labels(uint8_t* dname, size_t* size) 405 { 406 uint8_t lablen; 407 int labs = 1; 408 size_t sz = 1; 409 410 lablen = *dname++; 411 while(lablen) { 412 labs++; 413 sz += lablen+1; 414 dname += lablen; 415 lablen = *dname++; 416 } 417 *size = sz; 418 return labs; 419 } 420 421 /** 422 * Compare labels in memory, lowercase while comparing. 423 * @param p1: label 1 424 * @param p2: label 2 425 * @param len: number of bytes to compare. 426 * @return: 0, -1, +1 comparison result. 427 */ 428 static int 429 memlowercmp(uint8_t* p1, uint8_t* p2, uint8_t len) 430 { 431 while(len--) { 432 if(*p1 != *p2 && tolower((unsigned char)*p1) != tolower((unsigned char)*p2)) { 433 if(tolower((unsigned char)*p1) < tolower((unsigned char)*p2)) 434 return -1; 435 return 1; 436 } 437 p1++; 438 p2++; 439 } 440 return 0; 441 } 442 443 int 444 dname_lab_cmp(uint8_t* d1, int labs1, uint8_t* d2, int labs2, int* mlabs) 445 { 446 uint8_t len1, len2; 447 int atlabel = labs1; 448 int lastmlabs; 449 int lastdiff = 0; 450 /* first skip so that we compare same label. */ 451 if(labs1 > labs2) { 452 while(atlabel > labs2) { 453 len1 = *d1++; 454 d1 += len1; 455 atlabel--; 456 } 457 log_assert(atlabel == labs2); 458 } else if(labs1 < labs2) { 459 atlabel = labs2; 460 while(atlabel > labs1) { 461 len2 = *d2++; 462 d2 += len2; 463 atlabel--; 464 } 465 log_assert(atlabel == labs1); 466 } 467 lastmlabs = atlabel+1; 468 /* now at same label in d1 and d2, atlabel */ 469 /* www.example.com. */ 470 /* 4 3 2 1 atlabel number */ 471 /* repeat until at root label (which is always the same) */ 472 while(atlabel > 1) { 473 len1 = *d1++; 474 len2 = *d2++; 475 if(len1 != len2) { 476 log_assert(len1 != 0 && len2 != 0); 477 if(len1<len2) 478 lastdiff = -1; 479 else lastdiff = 1; 480 lastmlabs = atlabel; 481 d1 += len1; 482 d2 += len2; 483 } else { 484 /* memlowercmp is inlined here; or just like 485 * if((c=memlowercmp(d1, d2, len1)) != 0) { 486 * lastdiff = c; 487 * lastmlabs = atlabel; } apart from d1++,d2++ */ 488 while(len1) { 489 if(*d1 != *d2 && tolower((unsigned char)*d1) 490 != tolower((unsigned char)*d2)) { 491 if(tolower((unsigned char)*d1) < 492 tolower((unsigned char)*d2)) { 493 lastdiff = -1; 494 lastmlabs = atlabel; 495 d1 += len1; 496 d2 += len1; 497 break; 498 } 499 lastdiff = 1; 500 lastmlabs = atlabel; 501 d1 += len1; 502 d2 += len1; 503 break; /* out of memlowercmp */ 504 } 505 d1++; 506 d2++; 507 len1--; 508 } 509 } 510 atlabel--; 511 } 512 /* last difference atlabel number, so number of labels matching, 513 * at the right side, is one less. */ 514 *mlabs = lastmlabs-1; 515 if(lastdiff == 0) { 516 /* all labels compared were equal, check if one has more 517 * labels, so that example.com. > com. */ 518 if(labs1 > labs2) 519 return 1; 520 else if(labs1 < labs2) 521 return -1; 522 } 523 return lastdiff; 524 } 525 526 int 527 dname_buffer_write(sldns_buffer* pkt, uint8_t* dname) 528 { 529 uint8_t lablen; 530 531 if(sldns_buffer_remaining(pkt) < 1) 532 return 0; 533 lablen = *dname++; 534 sldns_buffer_write_u8(pkt, lablen); 535 while(lablen) { 536 if(sldns_buffer_remaining(pkt) < (size_t)lablen+1) 537 return 0; 538 sldns_buffer_write(pkt, dname, lablen); 539 dname += lablen; 540 lablen = *dname++; 541 sldns_buffer_write_u8(pkt, lablen); 542 } 543 return 1; 544 } 545 546 void dname_str(uint8_t* dname, char* str) 547 { 548 size_t len = 0; 549 uint8_t lablen = 0; 550 char* s = str; 551 if(!dname || !*dname) { 552 *s++ = '.'; 553 *s = 0; 554 return; 555 } 556 lablen = *dname++; 557 while(lablen) { 558 if(lablen > LDNS_MAX_LABELLEN) { 559 *s++ = '#'; 560 *s = 0; 561 return; 562 } 563 len += lablen+1; 564 if(len >= LDNS_MAX_DOMAINLEN-1) { 565 *s++ = '&'; 566 *s = 0; 567 return; 568 } 569 while(lablen--) { 570 if(isalnum((unsigned char)*dname) 571 || *dname == '-' || *dname == '_' 572 || *dname == '*') 573 *s++ = *(char*)dname++; 574 else { 575 *s++ = '?'; 576 dname++; 577 } 578 } 579 *s++ = '.'; 580 lablen = *dname++; 581 } 582 *s = 0; 583 } 584 585 int 586 dname_strict_subdomain(uint8_t* d1, int labs1, uint8_t* d2, int labs2) 587 { 588 int m; 589 /* check subdomain: d1: www.example.com. and d2: example.com. */ 590 if(labs2 >= labs1) 591 return 0; 592 if(dname_lab_cmp(d1, labs1, d2, labs2, &m) > 0) { 593 /* subdomain if all labels match */ 594 return (m == labs2); 595 } 596 return 0; 597 } 598 599 int 600 dname_strict_subdomain_c(uint8_t* d1, uint8_t* d2) 601 { 602 return dname_strict_subdomain(d1, dname_count_labels(d1), d2, 603 dname_count_labels(d2)); 604 } 605 606 int 607 dname_subdomain_c(uint8_t* d1, uint8_t* d2) 608 { 609 int m; 610 /* check subdomain: d1: www.example.com. and d2: example.com. */ 611 /* or d1: example.com. and d2: example.com. */ 612 int labs1 = dname_count_labels(d1); 613 int labs2 = dname_count_labels(d2); 614 if(labs2 > labs1) 615 return 0; 616 if(dname_lab_cmp(d1, labs1, d2, labs2, &m) < 0) { 617 /* must have been example.com , www.example.com - wrong */ 618 /* or otherwise different dnames */ 619 return 0; 620 } 621 return (m == labs2); 622 } 623 624 int 625 dname_is_root(uint8_t* dname) 626 { 627 uint8_t len; 628 log_assert(dname); 629 len = dname[0]; 630 log_assert(!LABEL_IS_PTR(len)); 631 return (len == 0); 632 } 633 634 void 635 dname_remove_label(uint8_t** dname, size_t* len) 636 { 637 size_t lablen; 638 log_assert(dname && *dname && len); 639 lablen = (*dname)[0]; 640 log_assert(!LABEL_IS_PTR(lablen)); 641 log_assert(*len > lablen); 642 if(lablen == 0) 643 return; /* do not modify root label */ 644 *len -= lablen+1; 645 *dname += lablen+1; 646 } 647 648 void 649 dname_remove_labels(uint8_t** dname, size_t* len, int n) 650 { 651 int i; 652 for(i=0; i<n; i++) 653 dname_remove_label(dname, len); 654 } 655 656 int 657 dname_signame_label_count(uint8_t* dname) 658 { 659 uint8_t lablen; 660 int count = 0; 661 if(!*dname) 662 return 0; 663 if(dname[0] == 1 && dname[1] == '*') 664 dname += 2; 665 lablen = dname[0]; 666 while(lablen) { 667 count++; 668 dname += lablen; 669 dname += 1; 670 lablen = dname[0]; 671 } 672 return count; 673 } 674 675 int 676 dname_is_wild(uint8_t* dname) 677 { 678 return (dname[0] == 1 && dname[1] == '*'); 679 } 680 681 /** 682 * Compare labels in memory, lowercase while comparing. 683 * Returns canonical order for labels. If all is equal, the 684 * shortest is first. 685 * 686 * @param p1: label 1 687 * @param len1: length of label 1. 688 * @param p2: label 2 689 * @param len2: length of label 2. 690 * @return: 0, -1, +1 comparison result. 691 */ 692 static int 693 memcanoncmp(uint8_t* p1, uint8_t len1, uint8_t* p2, uint8_t len2) 694 { 695 uint8_t min = (len1<len2)?len1:len2; 696 int c = memlowercmp(p1, p2, min); 697 if(c != 0) 698 return c; 699 /* equal, see who is shortest */ 700 if(len1 < len2) 701 return -1; 702 if(len1 > len2) 703 return 1; 704 return 0; 705 } 706 707 708 int 709 dname_canon_lab_cmp(uint8_t* d1, int labs1, uint8_t* d2, int labs2, int* mlabs) 710 { 711 /* like dname_lab_cmp, but with different label comparison, 712 * empty character sorts before \000. 713 * So ylyly is before z. */ 714 uint8_t len1, len2; 715 int atlabel = labs1; 716 int lastmlabs; 717 int lastdiff = 0; 718 int c; 719 /* first skip so that we compare same label. */ 720 if(labs1 > labs2) { 721 while(atlabel > labs2) { 722 len1 = *d1++; 723 d1 += len1; 724 atlabel--; 725 } 726 log_assert(atlabel == labs2); 727 } else if(labs1 < labs2) { 728 atlabel = labs2; 729 while(atlabel > labs1) { 730 len2 = *d2++; 731 d2 += len2; 732 atlabel--; 733 } 734 log_assert(atlabel == labs1); 735 } 736 lastmlabs = atlabel+1; 737 /* now at same label in d1 and d2, atlabel */ 738 /* www.example.com. */ 739 /* 4 3 2 1 atlabel number */ 740 /* repeat until at root label (which is always the same) */ 741 while(atlabel > 1) { 742 len1 = *d1++; 743 len2 = *d2++; 744 745 if((c=memcanoncmp(d1, len1, d2, len2)) != 0) { 746 if(c<0) 747 lastdiff = -1; 748 else lastdiff = 1; 749 lastmlabs = atlabel; 750 } 751 752 d1 += len1; 753 d2 += len2; 754 atlabel--; 755 } 756 /* last difference atlabel number, so number of labels matching, 757 * at the right side, is one less. */ 758 *mlabs = lastmlabs-1; 759 if(lastdiff == 0) { 760 /* all labels compared were equal, check if one has more 761 * labels, so that example.com. > com. */ 762 if(labs1 > labs2) 763 return 1; 764 else if(labs1 < labs2) 765 return -1; 766 } 767 return lastdiff; 768 } 769 770 int 771 dname_canonical_compare(uint8_t* d1, uint8_t* d2) 772 { 773 int labs1, labs2, m; 774 labs1 = dname_count_labels(d1); 775 labs2 = dname_count_labels(d2); 776 return dname_canon_lab_cmp(d1, labs1, d2, labs2, &m); 777 } 778 779 uint8_t* dname_get_shared_topdomain(uint8_t* d1, uint8_t* d2) 780 { 781 int labs1, labs2, m; 782 size_t len = LDNS_MAX_DOMAINLEN; 783 labs1 = dname_count_labels(d1); 784 labs2 = dname_count_labels(d2); 785 (void)dname_lab_cmp(d1, labs1, d2, labs2, &m); 786 dname_remove_labels(&d1, &len, labs1-m); 787 return d1; 788 } 789