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 int count1 = 0, count2 = 0; 237 log_assert(pkt && d1 && d2); 238 len1 = *d1++; 239 len2 = *d2++; 240 while( len1 != 0 || len2 != 0 ) { 241 /* resolve ptrs */ 242 if(LABEL_IS_PTR(len1)) { 243 if((size_t)PTR_OFFSET(len1, *d1) 244 >= sldns_buffer_limit(pkt)) 245 return -1; 246 if(count1++ > MAX_COMPRESS_PTRS) 247 return -1; 248 d1 = sldns_buffer_at(pkt, PTR_OFFSET(len1, *d1)); 249 len1 = *d1++; 250 continue; 251 } 252 if(LABEL_IS_PTR(len2)) { 253 if((size_t)PTR_OFFSET(len2, *d2) 254 >= sldns_buffer_limit(pkt)) 255 return 1; 256 if(count2++ > MAX_COMPRESS_PTRS) 257 return 1; 258 d2 = sldns_buffer_at(pkt, PTR_OFFSET(len2, *d2)); 259 len2 = *d2++; 260 continue; 261 } 262 /* check label length */ 263 log_assert(len1 <= LDNS_MAX_LABELLEN); 264 log_assert(len2 <= LDNS_MAX_LABELLEN); 265 if(len1 != len2) { 266 if(len1 < len2) return -1; 267 return 1; 268 } 269 log_assert(len1 == len2 && len1 != 0); 270 /* compare labels */ 271 while(len1--) { 272 if(tolower((unsigned char)*d1) != tolower((unsigned char)*d2)) { 273 if(tolower((unsigned char)*d1) < tolower((unsigned char)*d2)) 274 return -1; 275 return 1; 276 } 277 d1++; 278 d2++; 279 } 280 len1 = *d1++; 281 len2 = *d2++; 282 } 283 return 0; 284 } 285 286 hashvalue_type 287 dname_query_hash(uint8_t* dname, hashvalue_type h) 288 { 289 uint8_t labuf[LDNS_MAX_LABELLEN+1]; 290 uint8_t lablen; 291 int i; 292 293 /* preserve case of query, make hash label by label */ 294 lablen = *dname++; 295 while(lablen) { 296 log_assert(lablen <= LDNS_MAX_LABELLEN); 297 labuf[0] = lablen; 298 i=0; 299 while(lablen--) { 300 labuf[++i] = (uint8_t)tolower((unsigned char)*dname); 301 dname++; 302 } 303 h = hashlittle(labuf, labuf[0] + 1, h); 304 lablen = *dname++; 305 } 306 307 return h; 308 } 309 310 hashvalue_type 311 dname_pkt_hash(sldns_buffer* pkt, uint8_t* dname, hashvalue_type h) 312 { 313 uint8_t labuf[LDNS_MAX_LABELLEN+1]; 314 uint8_t lablen; 315 int i; 316 int count = 0; 317 318 /* preserve case of query, make hash label by label */ 319 lablen = *dname++; 320 while(lablen) { 321 if(LABEL_IS_PTR(lablen)) { 322 /* follow pointer */ 323 if((size_t)PTR_OFFSET(lablen, *dname) 324 >= sldns_buffer_limit(pkt)) 325 return h; 326 if(count++ > MAX_COMPRESS_PTRS) 327 return h; 328 dname = sldns_buffer_at(pkt, PTR_OFFSET(lablen, *dname)); 329 lablen = *dname++; 330 continue; 331 } 332 log_assert(lablen <= LDNS_MAX_LABELLEN); 333 labuf[0] = lablen; 334 i=0; 335 while(lablen--) { 336 labuf[++i] = (uint8_t)tolower((unsigned char)*dname); 337 dname++; 338 } 339 h = hashlittle(labuf, labuf[0] + 1, h); 340 lablen = *dname++; 341 } 342 343 return h; 344 } 345 346 void dname_pkt_copy(sldns_buffer* pkt, uint8_t* to, uint8_t* dname) 347 { 348 /* copy over the dname and decompress it at the same time */ 349 size_t comprcount = 0; 350 size_t len = 0; 351 uint8_t lablen; 352 lablen = *dname++; 353 while(lablen) { 354 if(LABEL_IS_PTR(lablen)) { 355 if(comprcount++ > MAX_COMPRESS_PTRS) { 356 /* too many compression pointers */ 357 *to = 0; /* end the result prematurely */ 358 return; 359 } 360 /* follow pointer */ 361 if((size_t)PTR_OFFSET(lablen, *dname) 362 >= sldns_buffer_limit(pkt)) 363 return; 364 dname = sldns_buffer_at(pkt, PTR_OFFSET(lablen, *dname)); 365 lablen = *dname++; 366 continue; 367 } 368 if(lablen > LDNS_MAX_LABELLEN) { 369 *to = 0; /* end the result prematurely */ 370 return; 371 } 372 log_assert(lablen <= LDNS_MAX_LABELLEN); 373 len += (size_t)lablen+1; 374 if(len >= LDNS_MAX_DOMAINLEN) { 375 *to = 0; /* end the result prematurely */ 376 log_err("bad dname in dname_pkt_copy"); 377 return; 378 } 379 *to++ = lablen; 380 memmove(to, dname, lablen); 381 dname += lablen; 382 to += lablen; 383 lablen = *dname++; 384 } 385 /* copy last \0 */ 386 *to = 0; 387 } 388 389 void dname_print(FILE* out, struct sldns_buffer* pkt, uint8_t* dname) 390 { 391 uint8_t lablen; 392 int count = 0; 393 if(!out) out = stdout; 394 if(!dname) return; 395 396 lablen = *dname++; 397 if(!lablen) 398 fputc('.', out); 399 while(lablen) { 400 if(LABEL_IS_PTR(lablen)) { 401 /* follow pointer */ 402 if(!pkt) { 403 fputs("??compressionptr??", out); 404 return; 405 } 406 if((size_t)PTR_OFFSET(lablen, *dname) 407 >= sldns_buffer_limit(pkt)) { 408 fputs("??compressionptr??", out); 409 return; 410 } 411 if(count++ > MAX_COMPRESS_PTRS) { 412 fputs("??compressionptr??", out); 413 return; 414 } 415 dname = sldns_buffer_at(pkt, PTR_OFFSET(lablen, *dname)); 416 lablen = *dname++; 417 continue; 418 } 419 if(lablen > LDNS_MAX_LABELLEN) { 420 fputs("??extendedlabel??", out); 421 return; 422 } 423 while(lablen--) 424 fputc((int)*dname++, out); 425 fputc('.', out); 426 lablen = *dname++; 427 } 428 } 429 430 int 431 dname_count_labels(uint8_t* dname) 432 { 433 uint8_t lablen; 434 int labs = 1; 435 436 lablen = *dname++; 437 while(lablen) { 438 labs++; 439 dname += lablen; 440 lablen = *dname++; 441 } 442 return labs; 443 } 444 445 int 446 dname_count_size_labels(uint8_t* dname, size_t* size) 447 { 448 uint8_t lablen; 449 int labs = 1; 450 size_t sz = 1; 451 452 lablen = *dname++; 453 while(lablen) { 454 labs++; 455 sz += lablen+1; 456 dname += lablen; 457 lablen = *dname++; 458 } 459 *size = sz; 460 return labs; 461 } 462 463 /** 464 * Compare labels in memory, lowercase while comparing. 465 * @param p1: label 1 466 * @param p2: label 2 467 * @param len: number of bytes to compare. 468 * @return: 0, -1, +1 comparison result. 469 */ 470 static int 471 memlowercmp(uint8_t* p1, uint8_t* p2, uint8_t len) 472 { 473 while(len--) { 474 if(*p1 != *p2 && tolower((unsigned char)*p1) != tolower((unsigned char)*p2)) { 475 if(tolower((unsigned char)*p1) < tolower((unsigned char)*p2)) 476 return -1; 477 return 1; 478 } 479 p1++; 480 p2++; 481 } 482 return 0; 483 } 484 485 int 486 dname_lab_cmp(uint8_t* d1, int labs1, uint8_t* d2, int labs2, int* mlabs) 487 { 488 uint8_t len1, len2; 489 int atlabel = labs1; 490 int lastmlabs; 491 int lastdiff = 0; 492 /* first skip so that we compare same label. */ 493 if(labs1 > labs2) { 494 while(atlabel > labs2) { 495 len1 = *d1++; 496 d1 += len1; 497 atlabel--; 498 } 499 log_assert(atlabel == labs2); 500 } else if(labs1 < labs2) { 501 atlabel = labs2; 502 while(atlabel > labs1) { 503 len2 = *d2++; 504 d2 += len2; 505 atlabel--; 506 } 507 log_assert(atlabel == labs1); 508 } 509 lastmlabs = atlabel+1; 510 /* now at same label in d1 and d2, atlabel */ 511 /* www.example.com. */ 512 /* 4 3 2 1 atlabel number */ 513 /* repeat until at root label (which is always the same) */ 514 while(atlabel > 1) { 515 len1 = *d1++; 516 len2 = *d2++; 517 if(len1 != len2) { 518 log_assert(len1 != 0 && len2 != 0); 519 if(len1<len2) 520 lastdiff = -1; 521 else lastdiff = 1; 522 lastmlabs = atlabel; 523 d1 += len1; 524 d2 += len2; 525 } else { 526 /* memlowercmp is inlined here; or just like 527 * if((c=memlowercmp(d1, d2, len1)) != 0) { 528 * lastdiff = c; 529 * lastmlabs = atlabel; } apart from d1++,d2++ */ 530 while(len1) { 531 if(*d1 != *d2 && tolower((unsigned char)*d1) 532 != tolower((unsigned char)*d2)) { 533 if(tolower((unsigned char)*d1) < 534 tolower((unsigned char)*d2)) { 535 lastdiff = -1; 536 lastmlabs = atlabel; 537 d1 += len1; 538 d2 += len1; 539 break; 540 } 541 lastdiff = 1; 542 lastmlabs = atlabel; 543 d1 += len1; 544 d2 += len1; 545 break; /* out of memlowercmp */ 546 } 547 d1++; 548 d2++; 549 len1--; 550 } 551 } 552 atlabel--; 553 } 554 /* last difference atlabel number, so number of labels matching, 555 * at the right side, is one less. */ 556 *mlabs = lastmlabs-1; 557 if(lastdiff == 0) { 558 /* all labels compared were equal, check if one has more 559 * labels, so that example.com. > com. */ 560 if(labs1 > labs2) 561 return 1; 562 else if(labs1 < labs2) 563 return -1; 564 } 565 return lastdiff; 566 } 567 568 int 569 dname_lab_startswith(uint8_t* label, char* prefix, char** endptr) 570 { 571 size_t plen = strlen(prefix); 572 size_t orig_plen = plen; 573 size_t lablen = (size_t)*label; 574 if(plen > lablen) 575 return 0; 576 label++; 577 while(plen--) { 578 if(*prefix != tolower((unsigned char)*label)) { 579 return 0; 580 } 581 prefix++; label++; 582 } 583 if(orig_plen < lablen) 584 *endptr = (char *)label; 585 else 586 /* prefix length == label length */ 587 *endptr = NULL; 588 return 1; 589 } 590 591 int 592 dname_has_label(uint8_t* dname, size_t dnamelen, uint8_t* label) 593 { 594 size_t len; 595 596 /* 1 byte needed for the label length */ 597 if(dnamelen < 1) 598 return 0; 599 600 len = *dname; 601 while(len <= dnamelen) { 602 if(!(*dname)) { 603 if(*dname == *label) 604 return 1; /* empty label match */ 605 /* termination label found, stop iterating */ 606 return 0; 607 } 608 if(*dname == *label && *label && 609 memlowercmp(dname+1, label+1, *dname) == 0) 610 return 1; 611 len += *dname; 612 dname += *dname; 613 dname++; 614 len++; 615 } 616 return 0; 617 } 618 619 int 620 dname_buffer_write(sldns_buffer* pkt, uint8_t* dname) 621 { 622 uint8_t lablen; 623 624 if(sldns_buffer_remaining(pkt) < 1) 625 return 0; 626 lablen = *dname++; 627 sldns_buffer_write_u8(pkt, lablen); 628 while(lablen) { 629 if(sldns_buffer_remaining(pkt) < (size_t)lablen+1) 630 return 0; 631 sldns_buffer_write(pkt, dname, lablen); 632 dname += lablen; 633 lablen = *dname++; 634 sldns_buffer_write_u8(pkt, lablen); 635 } 636 return 1; 637 } 638 639 void dname_str(uint8_t* dname, char* str) 640 { 641 size_t len = 0; 642 uint8_t lablen = 0; 643 char* s = str; 644 if(!dname || !*dname) { 645 *s++ = '.'; 646 *s = 0; 647 return; 648 } 649 lablen = *dname++; 650 while(lablen) { 651 len += lablen+1; 652 if(len >= LDNS_MAX_DOMAINLEN) { 653 if ((s-str) >= (LDNS_MAX_DOMAINLEN-1)) 654 s = str + LDNS_MAX_DOMAINLEN - 2; 655 *s++ = '&'; 656 *s = 0; 657 return; 658 } 659 if(lablen > LDNS_MAX_LABELLEN) { 660 *s++ = '#'; 661 *s = 0; 662 return; 663 } 664 while(lablen--) { 665 if(isalnum((unsigned char)*dname) 666 || *dname == '-' || *dname == '_' 667 || *dname == '*') 668 *s++ = *(char*)dname++; 669 else { 670 *s++ = '?'; 671 dname++; 672 } 673 } 674 *s++ = '.'; 675 lablen = *dname++; 676 } 677 *s = 0; 678 } 679 680 int 681 dname_strict_subdomain(uint8_t* d1, int labs1, uint8_t* d2, int labs2) 682 { 683 int m; 684 /* check subdomain: d1: www.example.com. and d2: example.com. */ 685 if(labs2 >= labs1) 686 return 0; 687 if(dname_lab_cmp(d1, labs1, d2, labs2, &m) > 0) { 688 /* subdomain if all labels match */ 689 return (m == labs2); 690 } 691 return 0; 692 } 693 694 int 695 dname_strict_subdomain_c(uint8_t* d1, uint8_t* d2) 696 { 697 return dname_strict_subdomain(d1, dname_count_labels(d1), d2, 698 dname_count_labels(d2)); 699 } 700 701 int 702 dname_subdomain_c(uint8_t* d1, uint8_t* d2) 703 { 704 int m; 705 /* check subdomain: d1: www.example.com. and d2: example.com. */ 706 /* or d1: example.com. and d2: example.com. */ 707 int labs1 = dname_count_labels(d1); 708 int labs2 = dname_count_labels(d2); 709 if(labs2 > labs1) 710 return 0; 711 if(dname_lab_cmp(d1, labs1, d2, labs2, &m) < 0) { 712 /* must have been example.com , www.example.com - wrong */ 713 /* or otherwise different dnames */ 714 return 0; 715 } 716 return (m == labs2); 717 } 718 719 int 720 dname_is_root(uint8_t* dname) 721 { 722 uint8_t len; 723 log_assert(dname); 724 len = dname[0]; 725 log_assert(!LABEL_IS_PTR(len)); 726 return (len == 0); 727 } 728 729 void 730 dname_remove_label(uint8_t** dname, size_t* len) 731 { 732 size_t lablen; 733 log_assert(dname && *dname && len); 734 lablen = (*dname)[0]; 735 log_assert(!LABEL_IS_PTR(lablen)); 736 log_assert(*len > lablen); 737 if(lablen == 0) 738 return; /* do not modify root label */ 739 *len -= lablen+1; 740 *dname += lablen+1; 741 } 742 743 int 744 dname_remove_label_limit_len(uint8_t** dname, size_t* len, size_t lenlimit) 745 { 746 size_t lablen; 747 log_assert(dname && *dname && len); 748 lablen = (*dname)[0]; 749 log_assert(!LABEL_IS_PTR(lablen)); 750 log_assert(*len > lablen); 751 if(lablen == 0) 752 return 0; /* do not modify root label */ 753 if(*len - (lablen + 1) < lenlimit) return 0; 754 *len -= lablen+1; 755 *dname += lablen+1; 756 return 1; 757 } 758 759 void 760 dname_remove_labels(uint8_t** dname, size_t* len, int n) 761 { 762 int i; 763 for(i=0; i<n; i++) 764 dname_remove_label(dname, len); 765 } 766 767 int 768 dname_signame_label_count(uint8_t* dname) 769 { 770 uint8_t lablen; 771 int count = 0; 772 if(!*dname) 773 return 0; 774 if(dname[0] == 1 && dname[1] == '*') 775 dname += 2; 776 lablen = dname[0]; 777 while(lablen) { 778 count++; 779 dname += lablen; 780 dname += 1; 781 lablen = dname[0]; 782 } 783 return count; 784 } 785 786 int 787 dname_is_wild(uint8_t* dname) 788 { 789 return (dname[0] == 1 && dname[1] == '*'); 790 } 791 792 /** 793 * Compare labels in memory, lowercase while comparing. 794 * Returns canonical order for labels. If all is equal, the 795 * shortest is first. 796 * 797 * @param p1: label 1 798 * @param len1: length of label 1. 799 * @param p2: label 2 800 * @param len2: length of label 2. 801 * @return: 0, -1, +1 comparison result. 802 */ 803 static int 804 memcanoncmp(uint8_t* p1, uint8_t len1, uint8_t* p2, uint8_t len2) 805 { 806 uint8_t min = (len1<len2)?len1:len2; 807 int c = memlowercmp(p1, p2, min); 808 if(c != 0) 809 return c; 810 /* equal, see who is shortest */ 811 if(len1 < len2) 812 return -1; 813 if(len1 > len2) 814 return 1; 815 return 0; 816 } 817 818 819 int 820 dname_canon_lab_cmp(uint8_t* d1, int labs1, uint8_t* d2, int labs2, int* mlabs) 821 { 822 /* like dname_lab_cmp, but with different label comparison, 823 * empty character sorts before \000. 824 * So ylyly is before z. */ 825 uint8_t len1, len2; 826 int atlabel = labs1; 827 int lastmlabs; 828 int lastdiff = 0; 829 int c; 830 /* first skip so that we compare same label. */ 831 if(labs1 > labs2) { 832 while(atlabel > labs2) { 833 len1 = *d1++; 834 d1 += len1; 835 atlabel--; 836 } 837 log_assert(atlabel == labs2); 838 } else if(labs1 < labs2) { 839 atlabel = labs2; 840 while(atlabel > labs1) { 841 len2 = *d2++; 842 d2 += len2; 843 atlabel--; 844 } 845 log_assert(atlabel == labs1); 846 } 847 lastmlabs = atlabel+1; 848 /* now at same label in d1 and d2, atlabel */ 849 /* www.example.com. */ 850 /* 4 3 2 1 atlabel number */ 851 /* repeat until at root label (which is always the same) */ 852 while(atlabel > 1) { 853 len1 = *d1++; 854 len2 = *d2++; 855 856 if((c=memcanoncmp(d1, len1, d2, len2)) != 0) { 857 if(c<0) 858 lastdiff = -1; 859 else lastdiff = 1; 860 lastmlabs = atlabel; 861 } 862 863 d1 += len1; 864 d2 += len2; 865 atlabel--; 866 } 867 /* last difference atlabel number, so number of labels matching, 868 * at the right side, is one less. */ 869 *mlabs = lastmlabs-1; 870 if(lastdiff == 0) { 871 /* all labels compared were equal, check if one has more 872 * labels, so that example.com. > com. */ 873 if(labs1 > labs2) 874 return 1; 875 else if(labs1 < labs2) 876 return -1; 877 } 878 return lastdiff; 879 } 880 881 int 882 dname_canonical_compare(uint8_t* d1, uint8_t* d2) 883 { 884 int labs1, labs2, m; 885 labs1 = dname_count_labels(d1); 886 labs2 = dname_count_labels(d2); 887 return dname_canon_lab_cmp(d1, labs1, d2, labs2, &m); 888 } 889 890 uint8_t* dname_get_shared_topdomain(uint8_t* d1, uint8_t* d2) 891 { 892 int labs1, labs2, m; 893 size_t len = LDNS_MAX_DOMAINLEN; 894 labs1 = dname_count_labels(d1); 895 labs2 = dname_count_labels(d2); 896 (void)dname_lab_cmp(d1, labs1, d2, labs2, &m); 897 dname_remove_labels(&d1, &len, labs1-m); 898 return d1; 899 } 900