xref: /freebsd/contrib/unbound/util/data/dname.c (revision b2efd602aea8b3cbc3fb215b9611946d04fceb10)
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
query_dname_len(sldns_buffer * query)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
dname_valid(uint8_t * dname,size_t maxlen)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
query_dname_compare(register uint8_t * d1,register uint8_t * d2)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
query_dname_tolower(uint8_t * dname)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
pkt_dname_tolower(sldns_buffer * pkt,uint8_t * dname)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
pkt_dname_len(sldns_buffer * pkt)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
dname_pkt_compare(sldns_buffer * pkt,uint8_t * d1,uint8_t * d2)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
dname_query_hash(uint8_t * dname,hashvalue_type h)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
dname_pkt_hash(sldns_buffer * pkt,uint8_t * dname,hashvalue_type h)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 
dname_pkt_copy(sldns_buffer * pkt,uint8_t * to,uint8_t * dname)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 
dname_print(FILE * out,struct sldns_buffer * pkt,uint8_t * dname)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
dname_count_labels(uint8_t * dname)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
dname_count_size_labels(uint8_t * dname,size_t * size)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
memlowercmp(uint8_t * p1,uint8_t * p2,uint8_t len)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
dname_lab_cmp(uint8_t * d1,int labs1,uint8_t * d2,int labs2,int * mlabs)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
dname_lab_startswith(uint8_t * label,char * prefix,char ** endptr)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
dname_has_label(uint8_t * dname,size_t dnamelen,uint8_t * label)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
dname_buffer_write(sldns_buffer * pkt,uint8_t * dname)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 
dname_str(uint8_t * dname,char * str)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
dname_strict_subdomain(uint8_t * d1,int labs1,uint8_t * d2,int labs2)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
dname_strict_subdomain_c(uint8_t * d1,uint8_t * d2)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
dname_subdomain_c(uint8_t * d1,uint8_t * d2)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
dname_is_root(uint8_t * dname)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
dname_remove_label(uint8_t ** dname,size_t * len)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
dname_remove_label_limit_len(uint8_t ** dname,size_t * len,size_t lenlimit)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
dname_remove_labels(uint8_t ** dname,size_t * len,int n)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
dname_signame_label_count(uint8_t * dname)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
dname_is_wild(uint8_t * dname)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
memcanoncmp(uint8_t * p1,uint8_t len1,uint8_t * p2,uint8_t len2)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
dname_canon_lab_cmp(uint8_t * d1,int labs1,uint8_t * d2,int labs2,int * mlabs)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
dname_canonical_compare(uint8_t * d1,uint8_t * d2)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 
dname_get_shared_topdomain(uint8_t * d1,uint8_t * d2)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