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