xref: /freebsd/contrib/unbound/util/data/dname.c (revision cddbc3b40812213ff00041f79174cac0be360a2a)
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 	labellen = *dname++;
79 	while(labellen) {
80 		if(labellen&0xc0)
81 			return 0; /* no compression ptrs allowed */
82 		len += labellen + 1;
83 		if(len >= LDNS_MAX_DOMAINLEN)
84 			return 0; /* too long */
85 		if(len > maxlen)
86 			return 0; /* does not fit in memory allocation */
87 		dname += labellen;
88 		labellen = *dname++;
89 	}
90 	len += 1;
91 	if(len > maxlen)
92 		return 0; /* does not fit in memory allocation */
93 	return len;
94 }
95 
96 /** compare uncompressed, noncanonical, registers are hints for speed */
97 int
98 query_dname_compare(register uint8_t* d1, register uint8_t* d2)
99 {
100 	register uint8_t lab1, lab2;
101 	log_assert(d1 && d2);
102 	lab1 = *d1++;
103 	lab2 = *d2++;
104 	while( lab1 != 0 || lab2 != 0 ) {
105 		/* compare label length */
106 		/* if one dname ends, it has labellength 0 */
107 		if(lab1 != lab2) {
108 			if(lab1 < lab2)
109 				return -1;
110 			return 1;
111 		}
112 		log_assert(lab1 == lab2 && lab1 != 0);
113 		/* compare lowercased labels. */
114 		while(lab1--) {
115 			/* compare bytes first for speed */
116 			if(*d1 != *d2 &&
117 				tolower((unsigned char)*d1) != tolower((unsigned char)*d2)) {
118 				if(tolower((unsigned char)*d1) < tolower((unsigned char)*d2))
119 					return -1;
120 				return 1;
121 			}
122 			d1++;
123 			d2++;
124 		}
125 		/* next pair of labels. */
126 		lab1 = *d1++;
127 		lab2 = *d2++;
128 	}
129 	return 0;
130 }
131 
132 void
133 query_dname_tolower(uint8_t* dname)
134 {
135 	/* the dname is stored uncompressed */
136 	uint8_t labellen;
137 	labellen = *dname;
138 	while(labellen) {
139 		dname++;
140 		while(labellen--) {
141 			*dname = (uint8_t)tolower((unsigned char)*dname);
142 			dname++;
143 		}
144 		labellen = *dname;
145 	}
146 }
147 
148 void
149 pkt_dname_tolower(sldns_buffer* pkt, uint8_t* dname)
150 {
151 	uint8_t lablen;
152 	int count = 0;
153 	if(dname >= sldns_buffer_end(pkt))
154 		return;
155 	lablen = *dname++;
156 	while(lablen) {
157 		if(LABEL_IS_PTR(lablen)) {
158 			if((size_t)PTR_OFFSET(lablen, *dname)
159 				>= sldns_buffer_limit(pkt))
160 				return;
161 			dname = sldns_buffer_at(pkt, PTR_OFFSET(lablen, *dname));
162 			lablen = *dname++;
163 			if(count++ > MAX_COMPRESS_PTRS)
164 				return;
165 			continue;
166 		}
167 		if(dname+lablen >= sldns_buffer_end(pkt))
168 			return;
169 		while(lablen--) {
170 			*dname = (uint8_t)tolower((unsigned char)*dname);
171 			dname++;
172 		}
173 		if(dname >= sldns_buffer_end(pkt))
174 			return;
175 		lablen = *dname++;
176 	}
177 }
178 
179 
180 size_t
181 pkt_dname_len(sldns_buffer* pkt)
182 {
183 	size_t len = 0;
184 	int ptrcount = 0;
185 	uint8_t labellen;
186 	size_t endpos = 0;
187 
188 	/* read dname and determine length */
189 	/* check compression pointers, loops, out of bounds */
190 	while(1) {
191 		/* read next label */
192 		if(sldns_buffer_remaining(pkt) < 1)
193 			return 0;
194 		labellen = sldns_buffer_read_u8(pkt);
195 		if(LABEL_IS_PTR(labellen)) {
196 			/* compression ptr */
197 			uint16_t ptr;
198 			if(sldns_buffer_remaining(pkt) < 1)
199 				return 0;
200 			ptr = PTR_OFFSET(labellen, sldns_buffer_read_u8(pkt));
201 			if(ptrcount++ > MAX_COMPRESS_PTRS)
202 				return 0; /* loop! */
203 			if(sldns_buffer_limit(pkt) <= ptr)
204 				return 0; /* out of bounds! */
205 			if(!endpos)
206 				endpos = sldns_buffer_position(pkt);
207 			sldns_buffer_set_position(pkt, ptr);
208 		} else {
209 			/* label contents */
210 			if(labellen > 0x3f)
211 				return 0; /* label too long */
212 			len += 1 + labellen;
213 			if(len > LDNS_MAX_DOMAINLEN)
214 				return 0;
215 			if(labellen == 0) {
216 				/* end of dname */
217 				break;
218 			}
219 			if(sldns_buffer_remaining(pkt) < labellen)
220 				return 0;
221 			sldns_buffer_skip(pkt, (ssize_t)labellen);
222 		}
223 	}
224 	if(endpos)
225 		sldns_buffer_set_position(pkt, endpos);
226 
227 	return len;
228 }
229 
230 int
231 dname_pkt_compare(sldns_buffer* pkt, uint8_t* d1, uint8_t* d2)
232 {
233 	uint8_t len1, len2;
234 	log_assert(pkt && d1 && d2);
235 	len1 = *d1++;
236 	len2 = *d2++;
237 	while( len1 != 0 || len2 != 0 ) {
238 		/* resolve ptrs */
239 		if(LABEL_IS_PTR(len1)) {
240 			d1 = sldns_buffer_at(pkt, PTR_OFFSET(len1, *d1));
241 			len1 = *d1++;
242 			continue;
243 		}
244 		if(LABEL_IS_PTR(len2)) {
245 			d2 = sldns_buffer_at(pkt, PTR_OFFSET(len2, *d2));
246 			len2 = *d2++;
247 			continue;
248 		}
249 		/* check label length */
250 		log_assert(len1 <= LDNS_MAX_LABELLEN);
251 		log_assert(len2 <= LDNS_MAX_LABELLEN);
252 		if(len1 != len2) {
253 			if(len1 < len2) return -1;
254 			return 1;
255 		}
256 		log_assert(len1 == len2 && len1 != 0);
257 		/* compare labels */
258 		while(len1--) {
259 			if(tolower((unsigned char)*d1) != tolower((unsigned char)*d2)) {
260 				if(tolower((unsigned char)*d1) < tolower((unsigned char)*d2))
261 					return -1;
262 				return 1;
263 			}
264 			d1++;
265 			d2++;
266 		}
267 		len1 = *d1++;
268 		len2 = *d2++;
269 	}
270 	return 0;
271 }
272 
273 hashvalue_type
274 dname_query_hash(uint8_t* dname, hashvalue_type h)
275 {
276 	uint8_t labuf[LDNS_MAX_LABELLEN+1];
277 	uint8_t lablen;
278 	int i;
279 
280 	/* preserve case of query, make hash label by label */
281 	lablen = *dname++;
282 	while(lablen) {
283 		log_assert(lablen <= LDNS_MAX_LABELLEN);
284 		labuf[0] = lablen;
285 		i=0;
286 		while(lablen--) {
287 			labuf[++i] = (uint8_t)tolower((unsigned char)*dname);
288 			dname++;
289 		}
290 		h = hashlittle(labuf, labuf[0] + 1, h);
291 		lablen = *dname++;
292 	}
293 
294 	return h;
295 }
296 
297 hashvalue_type
298 dname_pkt_hash(sldns_buffer* pkt, uint8_t* dname, hashvalue_type h)
299 {
300 	uint8_t labuf[LDNS_MAX_LABELLEN+1];
301 	uint8_t lablen;
302 	int i;
303 
304 	/* preserve case of query, make hash label by label */
305 	lablen = *dname++;
306 	while(lablen) {
307 		if(LABEL_IS_PTR(lablen)) {
308 			/* follow pointer */
309 			dname = sldns_buffer_at(pkt, PTR_OFFSET(lablen, *dname));
310 			lablen = *dname++;
311 			continue;
312 		}
313 		log_assert(lablen <= LDNS_MAX_LABELLEN);
314 		labuf[0] = lablen;
315 		i=0;
316 		while(lablen--) {
317 			labuf[++i] = (uint8_t)tolower((unsigned char)*dname);
318 			dname++;
319 		}
320 		h = hashlittle(labuf, labuf[0] + 1, h);
321 		lablen = *dname++;
322 	}
323 
324 	return h;
325 }
326 
327 void dname_pkt_copy(sldns_buffer* pkt, uint8_t* to, uint8_t* dname)
328 {
329 	/* copy over the dname and decompress it at the same time */
330 	size_t len = 0;
331 	uint8_t lablen;
332 	lablen = *dname++;
333 	while(lablen) {
334 		if(LABEL_IS_PTR(lablen)) {
335 			/* follow pointer */
336 			dname = sldns_buffer_at(pkt, PTR_OFFSET(lablen, *dname));
337 			lablen = *dname++;
338 			continue;
339 		}
340 		log_assert(lablen <= LDNS_MAX_LABELLEN);
341 		len += (size_t)lablen+1;
342 		if(len >= LDNS_MAX_DOMAINLEN) {
343 			*to = 0; /* end the result prematurely */
344 			log_err("bad dname in dname_pkt_copy");
345 			return;
346 		}
347 		*to++ = lablen;
348 		memmove(to, dname, lablen);
349 		dname += lablen;
350 		to += lablen;
351 		lablen = *dname++;
352 	}
353 	/* copy last \0 */
354 	*to = 0;
355 }
356 
357 void dname_print(FILE* out, struct sldns_buffer* pkt, uint8_t* dname)
358 {
359 	uint8_t lablen;
360 	if(!out) out = stdout;
361 	if(!dname) return;
362 
363 	lablen = *dname++;
364 	if(!lablen)
365 		fputc('.', out);
366 	while(lablen) {
367 		if(LABEL_IS_PTR(lablen)) {
368 			/* follow pointer */
369 			if(!pkt) {
370 				fputs("??compressionptr??", out);
371 				return;
372 			}
373 			dname = sldns_buffer_at(pkt, PTR_OFFSET(lablen, *dname));
374 			lablen = *dname++;
375 			continue;
376 		}
377 		if(lablen > LDNS_MAX_LABELLEN) {
378 			fputs("??extendedlabel??", out);
379 			return;
380 		}
381 		while(lablen--)
382 			fputc((int)*dname++, out);
383 		fputc('.', out);
384 		lablen = *dname++;
385 	}
386 }
387 
388 int
389 dname_count_labels(uint8_t* dname)
390 {
391 	uint8_t lablen;
392 	int labs = 1;
393 
394 	lablen = *dname++;
395 	while(lablen) {
396 		labs++;
397 		dname += lablen;
398 		lablen = *dname++;
399 	}
400 	return labs;
401 }
402 
403 int
404 dname_count_size_labels(uint8_t* dname, size_t* size)
405 {
406 	uint8_t lablen;
407 	int labs = 1;
408 	size_t sz = 1;
409 
410 	lablen = *dname++;
411 	while(lablen) {
412 		labs++;
413 		sz += lablen+1;
414 		dname += lablen;
415 		lablen = *dname++;
416 	}
417 	*size = sz;
418 	return labs;
419 }
420 
421 /**
422  * Compare labels in memory, lowercase while comparing.
423  * @param p1: label 1
424  * @param p2: label 2
425  * @param len: number of bytes to compare.
426  * @return: 0, -1, +1 comparison result.
427  */
428 static int
429 memlowercmp(uint8_t* p1, uint8_t* p2, uint8_t len)
430 {
431 	while(len--) {
432 		if(*p1 != *p2 && tolower((unsigned char)*p1) != tolower((unsigned char)*p2)) {
433 			if(tolower((unsigned char)*p1) < tolower((unsigned char)*p2))
434 				return -1;
435 			return 1;
436 		}
437 		p1++;
438 		p2++;
439 	}
440 	return 0;
441 }
442 
443 int
444 dname_lab_cmp(uint8_t* d1, int labs1, uint8_t* d2, int labs2, int* mlabs)
445 {
446 	uint8_t len1, len2;
447 	int atlabel = labs1;
448 	int lastmlabs;
449 	int lastdiff = 0;
450 	/* first skip so that we compare same label. */
451 	if(labs1 > labs2) {
452 		while(atlabel > labs2) {
453 			len1 = *d1++;
454 			d1 += len1;
455 			atlabel--;
456 		}
457 		log_assert(atlabel == labs2);
458 	} else if(labs1 < labs2) {
459 		atlabel = labs2;
460 		while(atlabel > labs1) {
461 			len2 = *d2++;
462 			d2 += len2;
463 			atlabel--;
464 		}
465 		log_assert(atlabel == labs1);
466 	}
467 	lastmlabs = atlabel+1;
468 	/* now at same label in d1 and d2, atlabel */
469 	/* www.example.com.                  */
470 	/* 4   3       2  1   atlabel number */
471 	/* repeat until at root label (which is always the same) */
472 	while(atlabel > 1) {
473 		len1 = *d1++;
474 		len2 = *d2++;
475 		if(len1 != len2) {
476 			log_assert(len1 != 0 && len2 != 0);
477 			if(len1<len2)
478 				lastdiff = -1;
479 			else	lastdiff = 1;
480 			lastmlabs = atlabel;
481 			d1 += len1;
482 			d2 += len2;
483 		} else {
484 			/* memlowercmp is inlined here; or just like
485 			 * if((c=memlowercmp(d1, d2, len1)) != 0) {
486 			 *	lastdiff = c;
487 			 *	lastmlabs = atlabel; } apart from d1++,d2++ */
488 			while(len1) {
489 				if(*d1 != *d2 && tolower((unsigned char)*d1)
490 					!= tolower((unsigned char)*d2)) {
491 					if(tolower((unsigned char)*d1) <
492 						tolower((unsigned char)*d2)) {
493 						lastdiff = -1;
494 						lastmlabs = atlabel;
495 						d1 += len1;
496 						d2 += len1;
497 						break;
498 					}
499 					lastdiff = 1;
500 					lastmlabs = atlabel;
501 					d1 += len1;
502 					d2 += len1;
503 					break; /* out of memlowercmp */
504 				}
505 				d1++;
506 				d2++;
507 				len1--;
508 			}
509 		}
510 		atlabel--;
511 	}
512 	/* last difference atlabel number, so number of labels matching,
513 	 * at the right side, is one less. */
514 	*mlabs = lastmlabs-1;
515 	if(lastdiff == 0) {
516 		/* all labels compared were equal, check if one has more
517 		 * labels, so that example.com. > com. */
518 		if(labs1 > labs2)
519 			return 1;
520 		else if(labs1 < labs2)
521 			return -1;
522 	}
523 	return lastdiff;
524 }
525 
526 int
527 dname_lab_startswith(uint8_t* label, char* prefix, char** endptr)
528 {
529 	size_t plen = strlen(prefix);
530 	size_t orig_plen = plen;
531 	size_t lablen = (size_t)*label;
532 	if(plen > lablen)
533 		return 0;
534 	label++;
535 	while(plen--) {
536 		if(*prefix != tolower((unsigned char)*label)) {
537 			return 0;
538 		}
539 		prefix++; label++;
540 	}
541 	if(orig_plen < lablen)
542 		*endptr = (char *)label;
543 	else
544 		/* prefix length == label length */
545 		*endptr = NULL;
546 	return 1;
547 }
548 
549 int
550 dname_buffer_write(sldns_buffer* pkt, uint8_t* dname)
551 {
552 	uint8_t lablen;
553 
554 	if(sldns_buffer_remaining(pkt) < 1)
555 		return 0;
556 	lablen = *dname++;
557 	sldns_buffer_write_u8(pkt, lablen);
558 	while(lablen) {
559 		if(sldns_buffer_remaining(pkt) < (size_t)lablen+1)
560 			return 0;
561 		sldns_buffer_write(pkt, dname, lablen);
562 		dname += lablen;
563 		lablen = *dname++;
564 		sldns_buffer_write_u8(pkt, lablen);
565 	}
566 	return 1;
567 }
568 
569 void dname_str(uint8_t* dname, char* str)
570 {
571 	size_t len = 0;
572 	uint8_t lablen = 0;
573 	char* s = str;
574 	if(!dname || !*dname) {
575 		*s++ = '.';
576 		*s = 0;
577 		return;
578 	}
579 	lablen = *dname++;
580 	while(lablen) {
581 		if(lablen > LDNS_MAX_LABELLEN) {
582 			*s++ = '#';
583 			*s = 0;
584 			return;
585 		}
586 		len += lablen+1;
587 		if(len >= LDNS_MAX_DOMAINLEN-1) {
588 			*s++ = '&';
589 			*s = 0;
590 			return;
591 		}
592 		while(lablen--) {
593 			if(isalnum((unsigned char)*dname)
594 				|| *dname == '-' || *dname == '_'
595 				|| *dname == '*')
596 				*s++ = *(char*)dname++;
597 			else	{
598 				*s++ = '?';
599 				dname++;
600 			}
601 		}
602 		*s++ = '.';
603 		lablen = *dname++;
604 	}
605 	*s = 0;
606 }
607 
608 int
609 dname_strict_subdomain(uint8_t* d1, int labs1, uint8_t* d2, int labs2)
610 {
611 	int m;
612 	/* check subdomain: d1: www.example.com. and d2: example.com. */
613 	if(labs2 >= labs1)
614 		return 0;
615 	if(dname_lab_cmp(d1, labs1, d2, labs2, &m) > 0) {
616 		/* subdomain if all labels match */
617 		return (m == labs2);
618 	}
619 	return 0;
620 }
621 
622 int
623 dname_strict_subdomain_c(uint8_t* d1, uint8_t* d2)
624 {
625 	return dname_strict_subdomain(d1, dname_count_labels(d1), d2,
626 		dname_count_labels(d2));
627 }
628 
629 int
630 dname_subdomain_c(uint8_t* d1, uint8_t* d2)
631 {
632 	int m;
633 	/* check subdomain: d1: www.example.com. and d2: example.com. */
634 	/*  	or 	    d1: example.com. and d2: example.com. */
635 	int labs1 = dname_count_labels(d1);
636 	int labs2 = dname_count_labels(d2);
637 	if(labs2 > labs1)
638 		return 0;
639 	if(dname_lab_cmp(d1, labs1, d2, labs2, &m) < 0) {
640 		/* must have been example.com , www.example.com - wrong */
641 		/* or otherwise different dnames */
642 		return 0;
643 	}
644 	return (m == labs2);
645 }
646 
647 int
648 dname_is_root(uint8_t* dname)
649 {
650 	uint8_t len;
651 	log_assert(dname);
652 	len = dname[0];
653 	log_assert(!LABEL_IS_PTR(len));
654 	return (len == 0);
655 }
656 
657 void
658 dname_remove_label(uint8_t** dname, size_t* len)
659 {
660 	size_t lablen;
661 	log_assert(dname && *dname && len);
662 	lablen = (*dname)[0];
663 	log_assert(!LABEL_IS_PTR(lablen));
664 	log_assert(*len > lablen);
665 	if(lablen == 0)
666 		return; /* do not modify root label */
667 	*len -= lablen+1;
668 	*dname += lablen+1;
669 }
670 
671 void
672 dname_remove_labels(uint8_t** dname, size_t* len, int n)
673 {
674 	int i;
675 	for(i=0; i<n; i++)
676 		dname_remove_label(dname, len);
677 }
678 
679 int
680 dname_signame_label_count(uint8_t* dname)
681 {
682 	uint8_t lablen;
683 	int count = 0;
684 	if(!*dname)
685 		return 0;
686 	if(dname[0] == 1 && dname[1] == '*')
687 		dname += 2;
688 	lablen = dname[0];
689 	while(lablen) {
690 		count++;
691 		dname += lablen;
692 		dname += 1;
693 		lablen = dname[0];
694 	}
695 	return count;
696 }
697 
698 int
699 dname_is_wild(uint8_t* dname)
700 {
701 	return (dname[0] == 1 && dname[1] == '*');
702 }
703 
704 /**
705  * Compare labels in memory, lowercase while comparing.
706  * Returns canonical order for labels. If all is equal, the
707  * shortest is first.
708  *
709  * @param p1: label 1
710  * @param len1: length of label 1.
711  * @param p2: label 2
712  * @param len2: length of label 2.
713  * @return: 0, -1, +1 comparison result.
714  */
715 static int
716 memcanoncmp(uint8_t* p1, uint8_t len1, uint8_t* p2, uint8_t len2)
717 {
718 	uint8_t min = (len1<len2)?len1:len2;
719 	int c = memlowercmp(p1, p2, min);
720 	if(c != 0)
721 		return c;
722 	/* equal, see who is shortest */
723 	if(len1 < len2)
724 		return -1;
725 	if(len1 > len2)
726 		return 1;
727 	return 0;
728 }
729 
730 
731 int
732 dname_canon_lab_cmp(uint8_t* d1, int labs1, uint8_t* d2, int labs2, int* mlabs)
733 {
734 	/* like dname_lab_cmp, but with different label comparison,
735 	 * empty character sorts before \000.
736 	 * So   ylyly is before z. */
737 	uint8_t len1, len2;
738 	int atlabel = labs1;
739 	int lastmlabs;
740 	int lastdiff = 0;
741 	int c;
742 	/* first skip so that we compare same label. */
743 	if(labs1 > labs2) {
744 		while(atlabel > labs2) {
745 			len1 = *d1++;
746 			d1 += len1;
747 			atlabel--;
748 		}
749 		log_assert(atlabel == labs2);
750 	} else if(labs1 < labs2) {
751 		atlabel = labs2;
752 		while(atlabel > labs1) {
753 			len2 = *d2++;
754 			d2 += len2;
755 			atlabel--;
756 		}
757 		log_assert(atlabel == labs1);
758 	}
759 	lastmlabs = atlabel+1;
760 	/* now at same label in d1 and d2, atlabel */
761 	/* www.example.com.                  */
762 	/* 4   3       2  1   atlabel number */
763 	/* repeat until at root label (which is always the same) */
764 	while(atlabel > 1) {
765 		len1 = *d1++;
766 		len2 = *d2++;
767 
768 		if((c=memcanoncmp(d1, len1, d2, len2)) != 0) {
769 			if(c<0)
770 				lastdiff = -1;
771 			else	lastdiff = 1;
772 			lastmlabs = atlabel;
773 		}
774 
775 		d1 += len1;
776 		d2 += len2;
777 		atlabel--;
778 	}
779 	/* last difference atlabel number, so number of labels matching,
780 	 * at the right side, is one less. */
781 	*mlabs = lastmlabs-1;
782 	if(lastdiff == 0) {
783 		/* all labels compared were equal, check if one has more
784 		 * labels, so that example.com. > com. */
785 		if(labs1 > labs2)
786 			return 1;
787 		else if(labs1 < labs2)
788 			return -1;
789 	}
790 	return lastdiff;
791 }
792 
793 int
794 dname_canonical_compare(uint8_t* d1, uint8_t* d2)
795 {
796 	int labs1, labs2, m;
797 	labs1 = dname_count_labels(d1);
798 	labs2 = dname_count_labels(d2);
799 	return dname_canon_lab_cmp(d1, labs1, d2, labs2, &m);
800 }
801 
802 uint8_t* dname_get_shared_topdomain(uint8_t* d1, uint8_t* d2)
803 {
804 	int labs1, labs2, m;
805 	size_t len = LDNS_MAX_DOMAINLEN;
806 	labs1 = dname_count_labels(d1);
807 	labs2 = dname_count_labels(d2);
808 	(void)dname_lab_cmp(d1, labs1, d2, labs2, &m);
809 	dname_remove_labels(&d1, &len, labs1-m);
810 	return d1;
811 }
812