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 			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