dname.c revision 356345
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 */
51size_t
52query_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
73size_t
74dname_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 */
99int
100query_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
134void
135query_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
150void
151pkt_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
182size_t
183pkt_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
232int
233dname_pkt_compare(sldns_buffer* pkt, uint8_t* d1, uint8_t* d2)
234{
235	uint8_t len1, len2;
236	log_assert(pkt && d1 && d2);
237	len1 = *d1++;
238	len2 = *d2++;
239	while( len1 != 0 || len2 != 0 ) {
240		/* resolve ptrs */
241		if(LABEL_IS_PTR(len1)) {
242			d1 = sldns_buffer_at(pkt, PTR_OFFSET(len1, *d1));
243			len1 = *d1++;
244			continue;
245		}
246		if(LABEL_IS_PTR(len2)) {
247			d2 = sldns_buffer_at(pkt, PTR_OFFSET(len2, *d2));
248			len2 = *d2++;
249			continue;
250		}
251		/* check label length */
252		log_assert(len1 <= LDNS_MAX_LABELLEN);
253		log_assert(len2 <= LDNS_MAX_LABELLEN);
254		if(len1 != len2) {
255			if(len1 < len2) return -1;
256			return 1;
257		}
258		log_assert(len1 == len2 && len1 != 0);
259		/* compare labels */
260		while(len1--) {
261			if(tolower((unsigned char)*d1) != tolower((unsigned char)*d2)) {
262				if(tolower((unsigned char)*d1) < tolower((unsigned char)*d2))
263					return -1;
264				return 1;
265			}
266			d1++;
267			d2++;
268		}
269		len1 = *d1++;
270		len2 = *d2++;
271	}
272	return 0;
273}
274
275hashvalue_type
276dname_query_hash(uint8_t* dname, hashvalue_type h)
277{
278	uint8_t labuf[LDNS_MAX_LABELLEN+1];
279	uint8_t lablen;
280	int i;
281
282	/* preserve case of query, make hash label by label */
283	lablen = *dname++;
284	while(lablen) {
285		log_assert(lablen <= LDNS_MAX_LABELLEN);
286		labuf[0] = lablen;
287		i=0;
288		while(lablen--) {
289			labuf[++i] = (uint8_t)tolower((unsigned char)*dname);
290			dname++;
291		}
292		h = hashlittle(labuf, labuf[0] + 1, h);
293		lablen = *dname++;
294	}
295
296	return h;
297}
298
299hashvalue_type
300dname_pkt_hash(sldns_buffer* pkt, uint8_t* dname, hashvalue_type h)
301{
302	uint8_t labuf[LDNS_MAX_LABELLEN+1];
303	uint8_t lablen;
304	int i;
305
306	/* preserve case of query, make hash label by label */
307	lablen = *dname++;
308	while(lablen) {
309		if(LABEL_IS_PTR(lablen)) {
310			/* follow pointer */
311			dname = sldns_buffer_at(pkt, PTR_OFFSET(lablen, *dname));
312			lablen = *dname++;
313			continue;
314		}
315		log_assert(lablen <= LDNS_MAX_LABELLEN);
316		labuf[0] = lablen;
317		i=0;
318		while(lablen--) {
319			labuf[++i] = (uint8_t)tolower((unsigned char)*dname);
320			dname++;
321		}
322		h = hashlittle(labuf, labuf[0] + 1, h);
323		lablen = *dname++;
324	}
325
326	return h;
327}
328
329void dname_pkt_copy(sldns_buffer* pkt, uint8_t* to, uint8_t* dname)
330{
331	/* copy over the dname and decompress it at the same time */
332	size_t comprcount = 0;
333	size_t len = 0;
334	uint8_t lablen;
335	lablen = *dname++;
336	while(lablen) {
337		if(LABEL_IS_PTR(lablen)) {
338			if(comprcount++ > MAX_COMPRESS_PTRS) {
339				/* too many compression pointers */
340				*to = 0; /* end the result prematurely */
341				return;
342			}
343			/* follow pointer */
344			dname = sldns_buffer_at(pkt, PTR_OFFSET(lablen, *dname));
345			lablen = *dname++;
346			continue;
347		}
348		if(lablen > LDNS_MAX_LABELLEN) {
349			*to = 0; /* end the result prematurely */
350			return;
351		}
352		log_assert(lablen <= LDNS_MAX_LABELLEN);
353		len += (size_t)lablen+1;
354		if(len >= LDNS_MAX_DOMAINLEN) {
355			*to = 0; /* end the result prematurely */
356			log_err("bad dname in dname_pkt_copy");
357			return;
358		}
359		*to++ = lablen;
360		memmove(to, dname, lablen);
361		dname += lablen;
362		to += lablen;
363		lablen = *dname++;
364	}
365	/* copy last \0 */
366	*to = 0;
367}
368
369void dname_print(FILE* out, struct sldns_buffer* pkt, uint8_t* dname)
370{
371	uint8_t lablen;
372	if(!out) out = stdout;
373	if(!dname) return;
374
375	lablen = *dname++;
376	if(!lablen)
377		fputc('.', out);
378	while(lablen) {
379		if(LABEL_IS_PTR(lablen)) {
380			/* follow pointer */
381			if(!pkt) {
382				fputs("??compressionptr??", out);
383				return;
384			}
385			dname = sldns_buffer_at(pkt, PTR_OFFSET(lablen, *dname));
386			lablen = *dname++;
387			continue;
388		}
389		if(lablen > LDNS_MAX_LABELLEN) {
390			fputs("??extendedlabel??", out);
391			return;
392		}
393		while(lablen--)
394			fputc((int)*dname++, out);
395		fputc('.', out);
396		lablen = *dname++;
397	}
398}
399
400int
401dname_count_labels(uint8_t* dname)
402{
403	uint8_t lablen;
404	int labs = 1;
405
406	lablen = *dname++;
407	while(lablen) {
408		labs++;
409		dname += lablen;
410		lablen = *dname++;
411	}
412	return labs;
413}
414
415int
416dname_count_size_labels(uint8_t* dname, size_t* size)
417{
418	uint8_t lablen;
419	int labs = 1;
420	size_t sz = 1;
421
422	lablen = *dname++;
423	while(lablen) {
424		labs++;
425		sz += lablen+1;
426		dname += lablen;
427		lablen = *dname++;
428	}
429	*size = sz;
430	return labs;
431}
432
433/**
434 * Compare labels in memory, lowercase while comparing.
435 * @param p1: label 1
436 * @param p2: label 2
437 * @param len: number of bytes to compare.
438 * @return: 0, -1, +1 comparison result.
439 */
440static int
441memlowercmp(uint8_t* p1, uint8_t* p2, uint8_t len)
442{
443	while(len--) {
444		if(*p1 != *p2 && tolower((unsigned char)*p1) != tolower((unsigned char)*p2)) {
445			if(tolower((unsigned char)*p1) < tolower((unsigned char)*p2))
446				return -1;
447			return 1;
448		}
449		p1++;
450		p2++;
451	}
452	return 0;
453}
454
455int
456dname_lab_cmp(uint8_t* d1, int labs1, uint8_t* d2, int labs2, int* mlabs)
457{
458	uint8_t len1, len2;
459	int atlabel = labs1;
460	int lastmlabs;
461	int lastdiff = 0;
462	/* first skip so that we compare same label. */
463	if(labs1 > labs2) {
464		while(atlabel > labs2) {
465			len1 = *d1++;
466			d1 += len1;
467			atlabel--;
468		}
469		log_assert(atlabel == labs2);
470	} else if(labs1 < labs2) {
471		atlabel = labs2;
472		while(atlabel > labs1) {
473			len2 = *d2++;
474			d2 += len2;
475			atlabel--;
476		}
477		log_assert(atlabel == labs1);
478	}
479	lastmlabs = atlabel+1;
480	/* now at same label in d1 and d2, atlabel */
481	/* www.example.com.                  */
482	/* 4   3       2  1   atlabel number */
483	/* repeat until at root label (which is always the same) */
484	while(atlabel > 1) {
485		len1 = *d1++;
486		len2 = *d2++;
487		if(len1 != len2) {
488			log_assert(len1 != 0 && len2 != 0);
489			if(len1<len2)
490				lastdiff = -1;
491			else	lastdiff = 1;
492			lastmlabs = atlabel;
493			d1 += len1;
494			d2 += len2;
495		} else {
496			/* memlowercmp is inlined here; or just like
497			 * if((c=memlowercmp(d1, d2, len1)) != 0) {
498			 *	lastdiff = c;
499			 *	lastmlabs = atlabel; } apart from d1++,d2++ */
500			while(len1) {
501				if(*d1 != *d2 && tolower((unsigned char)*d1)
502					!= tolower((unsigned char)*d2)) {
503					if(tolower((unsigned char)*d1) <
504						tolower((unsigned char)*d2)) {
505						lastdiff = -1;
506						lastmlabs = atlabel;
507						d1 += len1;
508						d2 += len1;
509						break;
510					}
511					lastdiff = 1;
512					lastmlabs = atlabel;
513					d1 += len1;
514					d2 += len1;
515					break; /* out of memlowercmp */
516				}
517				d1++;
518				d2++;
519				len1--;
520			}
521		}
522		atlabel--;
523	}
524	/* last difference atlabel number, so number of labels matching,
525	 * at the right side, is one less. */
526	*mlabs = lastmlabs-1;
527	if(lastdiff == 0) {
528		/* all labels compared were equal, check if one has more
529		 * labels, so that example.com. > com. */
530		if(labs1 > labs2)
531			return 1;
532		else if(labs1 < labs2)
533			return -1;
534	}
535	return lastdiff;
536}
537
538int
539dname_lab_startswith(uint8_t* label, char* prefix, char** endptr)
540{
541	size_t plen = strlen(prefix);
542	size_t orig_plen = plen;
543	size_t lablen = (size_t)*label;
544	if(plen > lablen)
545		return 0;
546	label++;
547	while(plen--) {
548		if(*prefix != tolower((unsigned char)*label)) {
549			return 0;
550		}
551		prefix++; label++;
552	}
553	if(orig_plen < lablen)
554		*endptr = (char *)label;
555	else
556		/* prefix length == label length */
557		*endptr = NULL;
558	return 1;
559}
560
561int
562dname_buffer_write(sldns_buffer* pkt, uint8_t* dname)
563{
564	uint8_t lablen;
565
566	if(sldns_buffer_remaining(pkt) < 1)
567		return 0;
568	lablen = *dname++;
569	sldns_buffer_write_u8(pkt, lablen);
570	while(lablen) {
571		if(sldns_buffer_remaining(pkt) < (size_t)lablen+1)
572			return 0;
573		sldns_buffer_write(pkt, dname, lablen);
574		dname += lablen;
575		lablen = *dname++;
576		sldns_buffer_write_u8(pkt, lablen);
577	}
578	return 1;
579}
580
581void dname_str(uint8_t* dname, char* str)
582{
583	size_t len = 0;
584	uint8_t lablen = 0;
585	char* s = str;
586	if(!dname || !*dname) {
587		*s++ = '.';
588		*s = 0;
589		return;
590	}
591	lablen = *dname++;
592	while(lablen) {
593		if(lablen > LDNS_MAX_LABELLEN) {
594			*s++ = '#';
595			*s = 0;
596			return;
597		}
598		len += lablen+1;
599		if(len >= LDNS_MAX_DOMAINLEN-1) {
600			*s++ = '&';
601			*s = 0;
602			return;
603		}
604		while(lablen--) {
605			if(isalnum((unsigned char)*dname)
606				|| *dname == '-' || *dname == '_'
607				|| *dname == '*')
608				*s++ = *(char*)dname++;
609			else	{
610				*s++ = '?';
611				dname++;
612			}
613		}
614		*s++ = '.';
615		lablen = *dname++;
616	}
617	*s = 0;
618}
619
620int
621dname_strict_subdomain(uint8_t* d1, int labs1, uint8_t* d2, int labs2)
622{
623	int m;
624	/* check subdomain: d1: www.example.com. and d2: example.com. */
625	if(labs2 >= labs1)
626		return 0;
627	if(dname_lab_cmp(d1, labs1, d2, labs2, &m) > 0) {
628		/* subdomain if all labels match */
629		return (m == labs2);
630	}
631	return 0;
632}
633
634int
635dname_strict_subdomain_c(uint8_t* d1, uint8_t* d2)
636{
637	return dname_strict_subdomain(d1, dname_count_labels(d1), d2,
638		dname_count_labels(d2));
639}
640
641int
642dname_subdomain_c(uint8_t* d1, uint8_t* d2)
643{
644	int m;
645	/* check subdomain: d1: www.example.com. and d2: example.com. */
646	/*  	or 	    d1: example.com. and d2: example.com. */
647	int labs1 = dname_count_labels(d1);
648	int labs2 = dname_count_labels(d2);
649	if(labs2 > labs1)
650		return 0;
651	if(dname_lab_cmp(d1, labs1, d2, labs2, &m) < 0) {
652		/* must have been example.com , www.example.com - wrong */
653		/* or otherwise different dnames */
654		return 0;
655	}
656	return (m == labs2);
657}
658
659int
660dname_is_root(uint8_t* dname)
661{
662	uint8_t len;
663	log_assert(dname);
664	len = dname[0];
665	log_assert(!LABEL_IS_PTR(len));
666	return (len == 0);
667}
668
669void
670dname_remove_label(uint8_t** dname, size_t* len)
671{
672	size_t lablen;
673	log_assert(dname && *dname && len);
674	lablen = (*dname)[0];
675	log_assert(!LABEL_IS_PTR(lablen));
676	log_assert(*len > lablen);
677	if(lablen == 0)
678		return; /* do not modify root label */
679	*len -= lablen+1;
680	*dname += lablen+1;
681}
682
683void
684dname_remove_labels(uint8_t** dname, size_t* len, int n)
685{
686	int i;
687	for(i=0; i<n; i++)
688		dname_remove_label(dname, len);
689}
690
691int
692dname_signame_label_count(uint8_t* dname)
693{
694	uint8_t lablen;
695	int count = 0;
696	if(!*dname)
697		return 0;
698	if(dname[0] == 1 && dname[1] == '*')
699		dname += 2;
700	lablen = dname[0];
701	while(lablen) {
702		count++;
703		dname += lablen;
704		dname += 1;
705		lablen = dname[0];
706	}
707	return count;
708}
709
710int
711dname_is_wild(uint8_t* dname)
712{
713	return (dname[0] == 1 && dname[1] == '*');
714}
715
716/**
717 * Compare labels in memory, lowercase while comparing.
718 * Returns canonical order for labels. If all is equal, the
719 * shortest is first.
720 *
721 * @param p1: label 1
722 * @param len1: length of label 1.
723 * @param p2: label 2
724 * @param len2: length of label 2.
725 * @return: 0, -1, +1 comparison result.
726 */
727static int
728memcanoncmp(uint8_t* p1, uint8_t len1, uint8_t* p2, uint8_t len2)
729{
730	uint8_t min = (len1<len2)?len1:len2;
731	int c = memlowercmp(p1, p2, min);
732	if(c != 0)
733		return c;
734	/* equal, see who is shortest */
735	if(len1 < len2)
736		return -1;
737	if(len1 > len2)
738		return 1;
739	return 0;
740}
741
742
743int
744dname_canon_lab_cmp(uint8_t* d1, int labs1, uint8_t* d2, int labs2, int* mlabs)
745{
746	/* like dname_lab_cmp, but with different label comparison,
747	 * empty character sorts before \000.
748	 * So   ylyly is before z. */
749	uint8_t len1, len2;
750	int atlabel = labs1;
751	int lastmlabs;
752	int lastdiff = 0;
753	int c;
754	/* first skip so that we compare same label. */
755	if(labs1 > labs2) {
756		while(atlabel > labs2) {
757			len1 = *d1++;
758			d1 += len1;
759			atlabel--;
760		}
761		log_assert(atlabel == labs2);
762	} else if(labs1 < labs2) {
763		atlabel = labs2;
764		while(atlabel > labs1) {
765			len2 = *d2++;
766			d2 += len2;
767			atlabel--;
768		}
769		log_assert(atlabel == labs1);
770	}
771	lastmlabs = atlabel+1;
772	/* now at same label in d1 and d2, atlabel */
773	/* www.example.com.                  */
774	/* 4   3       2  1   atlabel number */
775	/* repeat until at root label (which is always the same) */
776	while(atlabel > 1) {
777		len1 = *d1++;
778		len2 = *d2++;
779
780		if((c=memcanoncmp(d1, len1, d2, len2)) != 0) {
781			if(c<0)
782				lastdiff = -1;
783			else	lastdiff = 1;
784			lastmlabs = atlabel;
785		}
786
787		d1 += len1;
788		d2 += len2;
789		atlabel--;
790	}
791	/* last difference atlabel number, so number of labels matching,
792	 * at the right side, is one less. */
793	*mlabs = lastmlabs-1;
794	if(lastdiff == 0) {
795		/* all labels compared were equal, check if one has more
796		 * labels, so that example.com. > com. */
797		if(labs1 > labs2)
798			return 1;
799		else if(labs1 < labs2)
800			return -1;
801	}
802	return lastdiff;
803}
804
805int
806dname_canonical_compare(uint8_t* d1, uint8_t* d2)
807{
808	int labs1, labs2, m;
809	labs1 = dname_count_labels(d1);
810	labs2 = dname_count_labels(d2);
811	return dname_canon_lab_cmp(d1, labs1, d2, labs2, &m);
812}
813
814uint8_t* dname_get_shared_topdomain(uint8_t* d1, uint8_t* d2)
815{
816	int labs1, labs2, m;
817	size_t len = LDNS_MAX_DOMAINLEN;
818	labs1 = dname_count_labels(d1);
819	labs2 = dname_count_labels(d2);
820	(void)dname_lab_cmp(d1, labs1, d2, labs2, &m);
821	dname_remove_labels(&d1, &len, labs1-m);
822	return d1;
823}
824