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 if(maxlen == 0) 79 return 0; /* too short, shortest is '0' root label */ 80 labellen = *dname++; 81 while(labellen) { 82 if(labellen&0xc0) 83 return 0; /* no compression ptrs allowed */ 84 len += labellen + 1; 85 if(len >= LDNS_MAX_DOMAINLEN) 86 return 0; /* too long */ 87 if(len > maxlen) 88 return 0; /* does not fit in memory allocation */ 89 dname += labellen; 90 labellen = *dname++; 91 } 92 len += 1; 93 if(len > maxlen) 94 return 0; /* does not fit in memory allocation */ 95 return len; 96 } 97 98 /** compare uncompressed, noncanonical, registers are hints for speed */ 99 int 100 query_dname_compare(register uint8_t* d1, register uint8_t* d2) 101 { 102 register uint8_t lab1, lab2; 103 log_assert(d1 && d2); 104 lab1 = *d1++; 105 lab2 = *d2++; 106 while( lab1 != 0 || lab2 != 0 ) { 107 /* compare label length */ 108 /* if one dname ends, it has labellength 0 */ 109 if(lab1 != lab2) { 110 if(lab1 < lab2) 111 return -1; 112 return 1; 113 } 114 log_assert(lab1 == lab2 && lab1 != 0); 115 /* compare lowercased labels. */ 116 while(lab1--) { 117 /* compare bytes first for speed */ 118 if(*d1 != *d2 && 119 tolower((unsigned char)*d1) != tolower((unsigned char)*d2)) { 120 if(tolower((unsigned char)*d1) < tolower((unsigned char)*d2)) 121 return -1; 122 return 1; 123 } 124 d1++; 125 d2++; 126 } 127 /* next pair of labels. */ 128 lab1 = *d1++; 129 lab2 = *d2++; 130 } 131 return 0; 132 } 133 134 void 135 query_dname_tolower(uint8_t* dname) 136 { 137 /* the dname is stored uncompressed */ 138 uint8_t labellen; 139 labellen = *dname; 140 while(labellen) { 141 dname++; 142 while(labellen--) { 143 *dname = (uint8_t)tolower((unsigned char)*dname); 144 dname++; 145 } 146 labellen = *dname; 147 } 148 } 149 150 void 151 pkt_dname_tolower(sldns_buffer* pkt, uint8_t* dname) 152 { 153 uint8_t lablen; 154 int count = 0; 155 if(dname >= sldns_buffer_end(pkt)) 156 return; 157 lablen = *dname++; 158 while(lablen) { 159 if(LABEL_IS_PTR(lablen)) { 160 if((size_t)PTR_OFFSET(lablen, *dname) 161 >= sldns_buffer_limit(pkt)) 162 return; 163 dname = sldns_buffer_at(pkt, PTR_OFFSET(lablen, *dname)); 164 lablen = *dname++; 165 if(count++ > MAX_COMPRESS_PTRS) 166 return; 167 continue; 168 } 169 if(dname+lablen >= sldns_buffer_end(pkt)) 170 return; 171 while(lablen--) { 172 *dname = (uint8_t)tolower((unsigned char)*dname); 173 dname++; 174 } 175 if(dname >= sldns_buffer_end(pkt)) 176 return; 177 lablen = *dname++; 178 } 179 } 180 181 182 size_t 183 pkt_dname_len(sldns_buffer* pkt) 184 { 185 size_t len = 0; 186 int ptrcount = 0; 187 uint8_t labellen; 188 size_t endpos = 0; 189 190 /* read dname and determine length */ 191 /* check compression pointers, loops, out of bounds */ 192 while(1) { 193 /* read next label */ 194 if(sldns_buffer_remaining(pkt) < 1) 195 return 0; 196 labellen = sldns_buffer_read_u8(pkt); 197 if(LABEL_IS_PTR(labellen)) { 198 /* compression ptr */ 199 uint16_t ptr; 200 if(sldns_buffer_remaining(pkt) < 1) 201 return 0; 202 ptr = PTR_OFFSET(labellen, sldns_buffer_read_u8(pkt)); 203 if(ptrcount++ > MAX_COMPRESS_PTRS) 204 return 0; /* loop! */ 205 if(sldns_buffer_limit(pkt) <= ptr) 206 return 0; /* out of bounds! */ 207 if(!endpos) 208 endpos = sldns_buffer_position(pkt); 209 sldns_buffer_set_position(pkt, ptr); 210 } else { 211 /* label contents */ 212 if(labellen > 0x3f) 213 return 0; /* label too long */ 214 len += 1 + labellen; 215 if(len > LDNS_MAX_DOMAINLEN) 216 return 0; 217 if(labellen == 0) { 218 /* end of dname */ 219 break; 220 } 221 if(sldns_buffer_remaining(pkt) < labellen) 222 return 0; 223 sldns_buffer_skip(pkt, (ssize_t)labellen); 224 } 225 } 226 if(endpos) 227 sldns_buffer_set_position(pkt, endpos); 228 229 return len; 230 } 231 232 int 233 dname_pkt_compare(sldns_buffer* pkt, uint8_t* d1, uint8_t* d2) 234 { 235 uint8_t len1, len2; 236 log_assert(pkt && d1 && d2); 237 len1 = *d1++; 238 len2 = *d2++; 239 while( len1 != 0 || len2 != 0 ) { 240 /* resolve ptrs */ 241 if(LABEL_IS_PTR(len1)) { 242 d1 = sldns_buffer_at(pkt, PTR_OFFSET(len1, *d1)); 243 len1 = *d1++; 244 continue; 245 } 246 if(LABEL_IS_PTR(len2)) { 247 d2 = sldns_buffer_at(pkt, PTR_OFFSET(len2, *d2)); 248 len2 = *d2++; 249 continue; 250 } 251 /* check label length */ 252 log_assert(len1 <= LDNS_MAX_LABELLEN); 253 log_assert(len2 <= LDNS_MAX_LABELLEN); 254 if(len1 != len2) { 255 if(len1 < len2) return -1; 256 return 1; 257 } 258 log_assert(len1 == len2 && len1 != 0); 259 /* compare labels */ 260 while(len1--) { 261 if(tolower((unsigned char)*d1) != tolower((unsigned char)*d2)) { 262 if(tolower((unsigned char)*d1) < tolower((unsigned char)*d2)) 263 return -1; 264 return 1; 265 } 266 d1++; 267 d2++; 268 } 269 len1 = *d1++; 270 len2 = *d2++; 271 } 272 return 0; 273 } 274 275 hashvalue_type 276 dname_query_hash(uint8_t* dname, hashvalue_type h) 277 { 278 uint8_t labuf[LDNS_MAX_LABELLEN+1]; 279 uint8_t lablen; 280 int i; 281 282 /* preserve case of query, make hash label by label */ 283 lablen = *dname++; 284 while(lablen) { 285 log_assert(lablen <= LDNS_MAX_LABELLEN); 286 labuf[0] = lablen; 287 i=0; 288 while(lablen--) { 289 labuf[++i] = (uint8_t)tolower((unsigned char)*dname); 290 dname++; 291 } 292 h = hashlittle(labuf, labuf[0] + 1, h); 293 lablen = *dname++; 294 } 295 296 return h; 297 } 298 299 hashvalue_type 300 dname_pkt_hash(sldns_buffer* pkt, uint8_t* dname, hashvalue_type h) 301 { 302 uint8_t labuf[LDNS_MAX_LABELLEN+1]; 303 uint8_t lablen; 304 int i; 305 306 /* preserve case of query, make hash label by label */ 307 lablen = *dname++; 308 while(lablen) { 309 if(LABEL_IS_PTR(lablen)) { 310 /* follow pointer */ 311 dname = sldns_buffer_at(pkt, PTR_OFFSET(lablen, *dname)); 312 lablen = *dname++; 313 continue; 314 } 315 log_assert(lablen <= LDNS_MAX_LABELLEN); 316 labuf[0] = lablen; 317 i=0; 318 while(lablen--) { 319 labuf[++i] = (uint8_t)tolower((unsigned char)*dname); 320 dname++; 321 } 322 h = hashlittle(labuf, labuf[0] + 1, h); 323 lablen = *dname++; 324 } 325 326 return h; 327 } 328 329 void dname_pkt_copy(sldns_buffer* pkt, uint8_t* to, uint8_t* dname) 330 { 331 /* copy over the dname and decompress it at the same time */ 332 size_t comprcount = 0; 333 size_t len = 0; 334 uint8_t lablen; 335 lablen = *dname++; 336 while(lablen) { 337 if(LABEL_IS_PTR(lablen)) { 338 if(comprcount++ > MAX_COMPRESS_PTRS) { 339 /* too many compression pointers */ 340 *to = 0; /* end the result prematurely */ 341 return; 342 } 343 /* follow pointer */ 344 dname = sldns_buffer_at(pkt, PTR_OFFSET(lablen, *dname)); 345 lablen = *dname++; 346 continue; 347 } 348 if(lablen > LDNS_MAX_LABELLEN) { 349 *to = 0; /* end the result prematurely */ 350 return; 351 } 352 log_assert(lablen <= LDNS_MAX_LABELLEN); 353 len += (size_t)lablen+1; 354 if(len >= LDNS_MAX_DOMAINLEN) { 355 *to = 0; /* end the result prematurely */ 356 log_err("bad dname in dname_pkt_copy"); 357 return; 358 } 359 *to++ = lablen; 360 memmove(to, dname, lablen); 361 dname += lablen; 362 to += lablen; 363 lablen = *dname++; 364 } 365 /* copy last \0 */ 366 *to = 0; 367 } 368 369 void dname_print(FILE* out, struct sldns_buffer* pkt, uint8_t* dname) 370 { 371 uint8_t lablen; 372 if(!out) out = stdout; 373 if(!dname) return; 374 375 lablen = *dname++; 376 if(!lablen) 377 fputc('.', out); 378 while(lablen) { 379 if(LABEL_IS_PTR(lablen)) { 380 /* follow pointer */ 381 if(!pkt) { 382 fputs("??compressionptr??", out); 383 return; 384 } 385 dname = sldns_buffer_at(pkt, PTR_OFFSET(lablen, *dname)); 386 lablen = *dname++; 387 continue; 388 } 389 if(lablen > LDNS_MAX_LABELLEN) { 390 fputs("??extendedlabel??", out); 391 return; 392 } 393 while(lablen--) 394 fputc((int)*dname++, out); 395 fputc('.', out); 396 lablen = *dname++; 397 } 398 } 399 400 int 401 dname_count_labels(uint8_t* dname) 402 { 403 uint8_t lablen; 404 int labs = 1; 405 406 lablen = *dname++; 407 while(lablen) { 408 labs++; 409 dname += lablen; 410 lablen = *dname++; 411 } 412 return labs; 413 } 414 415 int 416 dname_count_size_labels(uint8_t* dname, size_t* size) 417 { 418 uint8_t lablen; 419 int labs = 1; 420 size_t sz = 1; 421 422 lablen = *dname++; 423 while(lablen) { 424 labs++; 425 sz += lablen+1; 426 dname += lablen; 427 lablen = *dname++; 428 } 429 *size = sz; 430 return labs; 431 } 432 433 /** 434 * Compare labels in memory, lowercase while comparing. 435 * @param p1: label 1 436 * @param p2: label 2 437 * @param len: number of bytes to compare. 438 * @return: 0, -1, +1 comparison result. 439 */ 440 static int 441 memlowercmp(uint8_t* p1, uint8_t* p2, uint8_t len) 442 { 443 while(len--) { 444 if(*p1 != *p2 && tolower((unsigned char)*p1) != tolower((unsigned char)*p2)) { 445 if(tolower((unsigned char)*p1) < tolower((unsigned char)*p2)) 446 return -1; 447 return 1; 448 } 449 p1++; 450 p2++; 451 } 452 return 0; 453 } 454 455 int 456 dname_lab_cmp(uint8_t* d1, int labs1, uint8_t* d2, int labs2, int* mlabs) 457 { 458 uint8_t len1, len2; 459 int atlabel = labs1; 460 int lastmlabs; 461 int lastdiff = 0; 462 /* first skip so that we compare same label. */ 463 if(labs1 > labs2) { 464 while(atlabel > labs2) { 465 len1 = *d1++; 466 d1 += len1; 467 atlabel--; 468 } 469 log_assert(atlabel == labs2); 470 } else if(labs1 < labs2) { 471 atlabel = labs2; 472 while(atlabel > labs1) { 473 len2 = *d2++; 474 d2 += len2; 475 atlabel--; 476 } 477 log_assert(atlabel == labs1); 478 } 479 lastmlabs = atlabel+1; 480 /* now at same label in d1 and d2, atlabel */ 481 /* www.example.com. */ 482 /* 4 3 2 1 atlabel number */ 483 /* repeat until at root label (which is always the same) */ 484 while(atlabel > 1) { 485 len1 = *d1++; 486 len2 = *d2++; 487 if(len1 != len2) { 488 log_assert(len1 != 0 && len2 != 0); 489 if(len1<len2) 490 lastdiff = -1; 491 else lastdiff = 1; 492 lastmlabs = atlabel; 493 d1 += len1; 494 d2 += len2; 495 } else { 496 /* memlowercmp is inlined here; or just like 497 * if((c=memlowercmp(d1, d2, len1)) != 0) { 498 * lastdiff = c; 499 * lastmlabs = atlabel; } apart from d1++,d2++ */ 500 while(len1) { 501 if(*d1 != *d2 && tolower((unsigned char)*d1) 502 != tolower((unsigned char)*d2)) { 503 if(tolower((unsigned char)*d1) < 504 tolower((unsigned char)*d2)) { 505 lastdiff = -1; 506 lastmlabs = atlabel; 507 d1 += len1; 508 d2 += len1; 509 break; 510 } 511 lastdiff = 1; 512 lastmlabs = atlabel; 513 d1 += len1; 514 d2 += len1; 515 break; /* out of memlowercmp */ 516 } 517 d1++; 518 d2++; 519 len1--; 520 } 521 } 522 atlabel--; 523 } 524 /* last difference atlabel number, so number of labels matching, 525 * at the right side, is one less. */ 526 *mlabs = lastmlabs-1; 527 if(lastdiff == 0) { 528 /* all labels compared were equal, check if one has more 529 * labels, so that example.com. > com. */ 530 if(labs1 > labs2) 531 return 1; 532 else if(labs1 < labs2) 533 return -1; 534 } 535 return lastdiff; 536 } 537 538 int 539 dname_lab_startswith(uint8_t* label, char* prefix, char** endptr) 540 { 541 size_t plen = strlen(prefix); 542 size_t orig_plen = plen; 543 size_t lablen = (size_t)*label; 544 if(plen > lablen) 545 return 0; 546 label++; 547 while(plen--) { 548 if(*prefix != tolower((unsigned char)*label)) { 549 return 0; 550 } 551 prefix++; label++; 552 } 553 if(orig_plen < lablen) 554 *endptr = (char *)label; 555 else 556 /* prefix length == label length */ 557 *endptr = NULL; 558 return 1; 559 } 560 561 int 562 dname_buffer_write(sldns_buffer* pkt, uint8_t* dname) 563 { 564 uint8_t lablen; 565 566 if(sldns_buffer_remaining(pkt) < 1) 567 return 0; 568 lablen = *dname++; 569 sldns_buffer_write_u8(pkt, lablen); 570 while(lablen) { 571 if(sldns_buffer_remaining(pkt) < (size_t)lablen+1) 572 return 0; 573 sldns_buffer_write(pkt, dname, lablen); 574 dname += lablen; 575 lablen = *dname++; 576 sldns_buffer_write_u8(pkt, lablen); 577 } 578 return 1; 579 } 580 581 void dname_str(uint8_t* dname, char* str) 582 { 583 size_t len = 0; 584 uint8_t lablen = 0; 585 char* s = str; 586 if(!dname || !*dname) { 587 *s++ = '.'; 588 *s = 0; 589 return; 590 } 591 lablen = *dname++; 592 while(lablen) { 593 if(lablen > LDNS_MAX_LABELLEN) { 594 *s++ = '#'; 595 *s = 0; 596 return; 597 } 598 len += lablen+1; 599 if(len >= LDNS_MAX_DOMAINLEN-1) { 600 *s++ = '&'; 601 *s = 0; 602 return; 603 } 604 while(lablen--) { 605 if(isalnum((unsigned char)*dname) 606 || *dname == '-' || *dname == '_' 607 || *dname == '*') 608 *s++ = *(char*)dname++; 609 else { 610 *s++ = '?'; 611 dname++; 612 } 613 } 614 *s++ = '.'; 615 lablen = *dname++; 616 } 617 *s = 0; 618 } 619 620 int 621 dname_strict_subdomain(uint8_t* d1, int labs1, uint8_t* d2, int labs2) 622 { 623 int m; 624 /* check subdomain: d1: www.example.com. and d2: example.com. */ 625 if(labs2 >= labs1) 626 return 0; 627 if(dname_lab_cmp(d1, labs1, d2, labs2, &m) > 0) { 628 /* subdomain if all labels match */ 629 return (m == labs2); 630 } 631 return 0; 632 } 633 634 int 635 dname_strict_subdomain_c(uint8_t* d1, uint8_t* d2) 636 { 637 return dname_strict_subdomain(d1, dname_count_labels(d1), d2, 638 dname_count_labels(d2)); 639 } 640 641 int 642 dname_subdomain_c(uint8_t* d1, uint8_t* d2) 643 { 644 int m; 645 /* check subdomain: d1: www.example.com. and d2: example.com. */ 646 /* or d1: example.com. and d2: example.com. */ 647 int labs1 = dname_count_labels(d1); 648 int labs2 = dname_count_labels(d2); 649 if(labs2 > labs1) 650 return 0; 651 if(dname_lab_cmp(d1, labs1, d2, labs2, &m) < 0) { 652 /* must have been example.com , www.example.com - wrong */ 653 /* or otherwise different dnames */ 654 return 0; 655 } 656 return (m == labs2); 657 } 658 659 int 660 dname_is_root(uint8_t* dname) 661 { 662 uint8_t len; 663 log_assert(dname); 664 len = dname[0]; 665 log_assert(!LABEL_IS_PTR(len)); 666 return (len == 0); 667 } 668 669 void 670 dname_remove_label(uint8_t** dname, size_t* len) 671 { 672 size_t lablen; 673 log_assert(dname && *dname && len); 674 lablen = (*dname)[0]; 675 log_assert(!LABEL_IS_PTR(lablen)); 676 log_assert(*len > lablen); 677 if(lablen == 0) 678 return; /* do not modify root label */ 679 *len -= lablen+1; 680 *dname += lablen+1; 681 } 682 683 void 684 dname_remove_labels(uint8_t** dname, size_t* len, int n) 685 { 686 int i; 687 for(i=0; i<n; i++) 688 dname_remove_label(dname, len); 689 } 690 691 int 692 dname_signame_label_count(uint8_t* dname) 693 { 694 uint8_t lablen; 695 int count = 0; 696 if(!*dname) 697 return 0; 698 if(dname[0] == 1 && dname[1] == '*') 699 dname += 2; 700 lablen = dname[0]; 701 while(lablen) { 702 count++; 703 dname += lablen; 704 dname += 1; 705 lablen = dname[0]; 706 } 707 return count; 708 } 709 710 int 711 dname_is_wild(uint8_t* dname) 712 { 713 return (dname[0] == 1 && dname[1] == '*'); 714 } 715 716 /** 717 * Compare labels in memory, lowercase while comparing. 718 * Returns canonical order for labels. If all is equal, the 719 * shortest is first. 720 * 721 * @param p1: label 1 722 * @param len1: length of label 1. 723 * @param p2: label 2 724 * @param len2: length of label 2. 725 * @return: 0, -1, +1 comparison result. 726 */ 727 static int 728 memcanoncmp(uint8_t* p1, uint8_t len1, uint8_t* p2, uint8_t len2) 729 { 730 uint8_t min = (len1<len2)?len1:len2; 731 int c = memlowercmp(p1, p2, min); 732 if(c != 0) 733 return c; 734 /* equal, see who is shortest */ 735 if(len1 < len2) 736 return -1; 737 if(len1 > len2) 738 return 1; 739 return 0; 740 } 741 742 743 int 744 dname_canon_lab_cmp(uint8_t* d1, int labs1, uint8_t* d2, int labs2, int* mlabs) 745 { 746 /* like dname_lab_cmp, but with different label comparison, 747 * empty character sorts before \000. 748 * So ylyly is before z. */ 749 uint8_t len1, len2; 750 int atlabel = labs1; 751 int lastmlabs; 752 int lastdiff = 0; 753 int c; 754 /* first skip so that we compare same label. */ 755 if(labs1 > labs2) { 756 while(atlabel > labs2) { 757 len1 = *d1++; 758 d1 += len1; 759 atlabel--; 760 } 761 log_assert(atlabel == labs2); 762 } else if(labs1 < labs2) { 763 atlabel = labs2; 764 while(atlabel > labs1) { 765 len2 = *d2++; 766 d2 += len2; 767 atlabel--; 768 } 769 log_assert(atlabel == labs1); 770 } 771 lastmlabs = atlabel+1; 772 /* now at same label in d1 and d2, atlabel */ 773 /* www.example.com. */ 774 /* 4 3 2 1 atlabel number */ 775 /* repeat until at root label (which is always the same) */ 776 while(atlabel > 1) { 777 len1 = *d1++; 778 len2 = *d2++; 779 780 if((c=memcanoncmp(d1, len1, d2, len2)) != 0) { 781 if(c<0) 782 lastdiff = -1; 783 else lastdiff = 1; 784 lastmlabs = atlabel; 785 } 786 787 d1 += len1; 788 d2 += len2; 789 atlabel--; 790 } 791 /* last difference atlabel number, so number of labels matching, 792 * at the right side, is one less. */ 793 *mlabs = lastmlabs-1; 794 if(lastdiff == 0) { 795 /* all labels compared were equal, check if one has more 796 * labels, so that example.com. > com. */ 797 if(labs1 > labs2) 798 return 1; 799 else if(labs1 < labs2) 800 return -1; 801 } 802 return lastdiff; 803 } 804 805 int 806 dname_canonical_compare(uint8_t* d1, uint8_t* d2) 807 { 808 int labs1, labs2, m; 809 labs1 = dname_count_labels(d1); 810 labs2 = dname_count_labels(d2); 811 return dname_canon_lab_cmp(d1, labs1, d2, labs2, &m); 812 } 813 814 uint8_t* dname_get_shared_topdomain(uint8_t* d1, uint8_t* d2) 815 { 816 int labs1, labs2, m; 817 size_t len = LDNS_MAX_DOMAINLEN; 818 labs1 = dname_count_labels(d1); 819 labs2 = dname_count_labels(d2); 820 (void)dname_lab_cmp(d1, labs1, d2, labs2, &m); 821 dname_remove_labels(&d1, &len, labs1-m); 822 return d1; 823 } 824