Home | History | Annotate | Line # | Download | only in data
      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