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