xref: /openbsd-src/usr.sbin/unbound/util/data/dname.c (revision 06a13c09c94ffcf198b2462aac9f18628335bfee)
1933707f3Ssthen /*
2933707f3Ssthen  * util/data/dname.h - domain name handling
3933707f3Ssthen  *
4933707f3Ssthen  * Copyright (c) 2007, NLnet Labs. All rights reserved.
5933707f3Ssthen  *
6933707f3Ssthen  * This software is open source.
7933707f3Ssthen  *
8933707f3Ssthen  * Redistribution and use in source and binary forms, with or without
9933707f3Ssthen  * modification, are permitted provided that the following conditions
10933707f3Ssthen  * are met:
11933707f3Ssthen  *
12933707f3Ssthen  * Redistributions of source code must retain the above copyright notice,
13933707f3Ssthen  * this list of conditions and the following disclaimer.
14933707f3Ssthen  *
15933707f3Ssthen  * Redistributions in binary form must reproduce the above copyright notice,
16933707f3Ssthen  * this list of conditions and the following disclaimer in the documentation
17933707f3Ssthen  * and/or other materials provided with the distribution.
18933707f3Ssthen  *
19933707f3Ssthen  * Neither the name of the NLNET LABS nor the names of its contributors may
20933707f3Ssthen  * be used to endorse or promote products derived from this software without
21933707f3Ssthen  * specific prior written permission.
22933707f3Ssthen  *
23933707f3Ssthen  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
245d76a658Ssthen  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
255d76a658Ssthen  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
265d76a658Ssthen  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
275d76a658Ssthen  * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
285d76a658Ssthen  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
295d76a658Ssthen  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
305d76a658Ssthen  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
315d76a658Ssthen  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
325d76a658Ssthen  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
335d76a658Ssthen  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34933707f3Ssthen  */
35933707f3Ssthen 
36933707f3Ssthen /**
37933707f3Ssthen  * \file
38933707f3Ssthen  *
39933707f3Ssthen  * This file contains domain name handling functions.
40933707f3Ssthen  */
41933707f3Ssthen 
42933707f3Ssthen #include "config.h"
43933707f3Ssthen #include <ctype.h>
44933707f3Ssthen #include "util/data/dname.h"
45933707f3Ssthen #include "util/data/msgparse.h"
46933707f3Ssthen #include "util/log.h"
47933707f3Ssthen #include "util/storage/lookup3.h"
48fdfb4ba6Ssthen #include "sldns/sbuffer.h"
49933707f3Ssthen 
50933707f3Ssthen /* determine length of a dname in buffer, no compression pointers allowed */
51933707f3Ssthen size_t
query_dname_len(sldns_buffer * query)525d76a658Ssthen query_dname_len(sldns_buffer* query)
53933707f3Ssthen {
54933707f3Ssthen 	size_t len = 0;
55933707f3Ssthen 	size_t labellen;
56933707f3Ssthen 	while(1) {
575d76a658Ssthen 		if(sldns_buffer_remaining(query) < 1)
58933707f3Ssthen 			return 0; /* parse error, need label len */
595d76a658Ssthen 		labellen = sldns_buffer_read_u8(query);
60933707f3Ssthen 		if(labellen&0xc0)
61933707f3Ssthen 			return 0; /* no compression allowed in queries */
62933707f3Ssthen 		len += labellen + 1;
63933707f3Ssthen 		if(len > LDNS_MAX_DOMAINLEN)
64933707f3Ssthen 			return 0; /* too long */
65933707f3Ssthen 		if(labellen == 0)
66933707f3Ssthen 			return len;
675d76a658Ssthen 		if(sldns_buffer_remaining(query) < labellen)
68933707f3Ssthen 			return 0; /* parse error, need content */
695d76a658Ssthen 		sldns_buffer_skip(query, (ssize_t)labellen);
70933707f3Ssthen 	}
71933707f3Ssthen }
72933707f3Ssthen 
73933707f3Ssthen size_t
dname_valid(uint8_t * dname,size_t maxlen)74933707f3Ssthen dname_valid(uint8_t* dname, size_t maxlen)
75933707f3Ssthen {
76933707f3Ssthen 	size_t len = 0;
77933707f3Ssthen 	size_t labellen;
78ebf5bb73Ssthen 	if(maxlen == 0)
79ebf5bb73Ssthen 		return 0; /* too short, shortest is '0' root label */
80933707f3Ssthen 	labellen = *dname++;
81933707f3Ssthen 	while(labellen) {
82933707f3Ssthen 		if(labellen&0xc0)
83933707f3Ssthen 			return 0; /* no compression ptrs allowed */
84933707f3Ssthen 		len += labellen + 1;
85933707f3Ssthen 		if(len >= LDNS_MAX_DOMAINLEN)
86933707f3Ssthen 			return 0; /* too long */
87933707f3Ssthen 		if(len > maxlen)
88933707f3Ssthen 			return 0; /* does not fit in memory allocation */
89933707f3Ssthen 		dname += labellen;
90933707f3Ssthen 		labellen = *dname++;
91933707f3Ssthen 	}
92933707f3Ssthen 	len += 1;
93933707f3Ssthen 	if(len > maxlen)
94933707f3Ssthen 		return 0; /* does not fit in memory allocation */
95933707f3Ssthen 	return len;
96933707f3Ssthen }
97933707f3Ssthen 
98933707f3Ssthen /** compare uncompressed, noncanonical, registers are hints for speed */
99933707f3Ssthen int
query_dname_compare(register uint8_t * d1,register uint8_t * d2)100933707f3Ssthen query_dname_compare(register uint8_t* d1, register uint8_t* d2)
101933707f3Ssthen {
102933707f3Ssthen 	register uint8_t lab1, lab2;
103933707f3Ssthen 	log_assert(d1 && d2);
104933707f3Ssthen 	lab1 = *d1++;
105933707f3Ssthen 	lab2 = *d2++;
106933707f3Ssthen 	while( lab1 != 0 || lab2 != 0 ) {
107933707f3Ssthen 		/* compare label length */
108933707f3Ssthen 		/* if one dname ends, it has labellength 0 */
109933707f3Ssthen 		if(lab1 != lab2) {
110933707f3Ssthen 			if(lab1 < lab2)
111933707f3Ssthen 				return -1;
112933707f3Ssthen 			return 1;
113933707f3Ssthen 		}
114933707f3Ssthen 		log_assert(lab1 == lab2 && lab1 != 0);
115933707f3Ssthen 		/* compare lowercased labels. */
116933707f3Ssthen 		while(lab1--) {
117933707f3Ssthen 			/* compare bytes first for speed */
118933707f3Ssthen 			if(*d1 != *d2 &&
11998f3ca02Sbrad 				tolower((unsigned char)*d1) != tolower((unsigned char)*d2)) {
12098f3ca02Sbrad 				if(tolower((unsigned char)*d1) < tolower((unsigned char)*d2))
121933707f3Ssthen 					return -1;
122933707f3Ssthen 				return 1;
123933707f3Ssthen 			}
124933707f3Ssthen 			d1++;
125933707f3Ssthen 			d2++;
126933707f3Ssthen 		}
127933707f3Ssthen 		/* next pair of labels. */
128933707f3Ssthen 		lab1 = *d1++;
129933707f3Ssthen 		lab2 = *d2++;
130933707f3Ssthen 	}
131933707f3Ssthen 	return 0;
132933707f3Ssthen }
133933707f3Ssthen 
134933707f3Ssthen void
query_dname_tolower(uint8_t * dname)135933707f3Ssthen query_dname_tolower(uint8_t* dname)
136933707f3Ssthen {
137933707f3Ssthen 	/* the dname is stored uncompressed */
138933707f3Ssthen 	uint8_t labellen;
139933707f3Ssthen 	labellen = *dname;
140933707f3Ssthen 	while(labellen) {
141933707f3Ssthen 		dname++;
142933707f3Ssthen 		while(labellen--) {
14398f3ca02Sbrad 			*dname = (uint8_t)tolower((unsigned char)*dname);
144933707f3Ssthen 			dname++;
145933707f3Ssthen 		}
146933707f3Ssthen 		labellen = *dname;
147933707f3Ssthen 	}
148933707f3Ssthen }
149933707f3Ssthen 
150933707f3Ssthen void
pkt_dname_tolower(sldns_buffer * pkt,uint8_t * dname)1515d76a658Ssthen pkt_dname_tolower(sldns_buffer* pkt, uint8_t* dname)
152933707f3Ssthen {
153933707f3Ssthen 	uint8_t lablen;
154933707f3Ssthen 	int count = 0;
1555d76a658Ssthen 	if(dname >= sldns_buffer_end(pkt))
156933707f3Ssthen 		return;
157933707f3Ssthen 	lablen = *dname++;
158933707f3Ssthen 	while(lablen) {
159933707f3Ssthen 		if(LABEL_IS_PTR(lablen)) {
160933707f3Ssthen 			if((size_t)PTR_OFFSET(lablen, *dname)
1615d76a658Ssthen 				>= sldns_buffer_limit(pkt))
162933707f3Ssthen 				return;
1635d76a658Ssthen 			dname = sldns_buffer_at(pkt, PTR_OFFSET(lablen, *dname));
164933707f3Ssthen 			lablen = *dname++;
165933707f3Ssthen 			if(count++ > MAX_COMPRESS_PTRS)
166933707f3Ssthen 				return;
167933707f3Ssthen 			continue;
168933707f3Ssthen 		}
1695d76a658Ssthen 		if(dname+lablen >= sldns_buffer_end(pkt))
170933707f3Ssthen 			return;
171933707f3Ssthen 		while(lablen--) {
17298f3ca02Sbrad 			*dname = (uint8_t)tolower((unsigned char)*dname);
173933707f3Ssthen 			dname++;
174933707f3Ssthen 		}
1755d76a658Ssthen 		if(dname >= sldns_buffer_end(pkt))
176933707f3Ssthen 			return;
177933707f3Ssthen 		lablen = *dname++;
178933707f3Ssthen 	}
179933707f3Ssthen }
180933707f3Ssthen 
181933707f3Ssthen 
182933707f3Ssthen size_t
pkt_dname_len(sldns_buffer * pkt)1835d76a658Ssthen pkt_dname_len(sldns_buffer* pkt)
184933707f3Ssthen {
185933707f3Ssthen 	size_t len = 0;
186933707f3Ssthen 	int ptrcount = 0;
187933707f3Ssthen 	uint8_t labellen;
188933707f3Ssthen 	size_t endpos = 0;
189933707f3Ssthen 
190933707f3Ssthen 	/* read dname and determine length */
191933707f3Ssthen 	/* check compression pointers, loops, out of bounds */
192933707f3Ssthen 	while(1) {
193933707f3Ssthen 		/* read next label */
1945d76a658Ssthen 		if(sldns_buffer_remaining(pkt) < 1)
195933707f3Ssthen 			return 0;
1965d76a658Ssthen 		labellen = sldns_buffer_read_u8(pkt);
197933707f3Ssthen 		if(LABEL_IS_PTR(labellen)) {
198933707f3Ssthen 			/* compression ptr */
199933707f3Ssthen 			uint16_t ptr;
2005d76a658Ssthen 			if(sldns_buffer_remaining(pkt) < 1)
201933707f3Ssthen 				return 0;
2025d76a658Ssthen 			ptr = PTR_OFFSET(labellen, sldns_buffer_read_u8(pkt));
203933707f3Ssthen 			if(ptrcount++ > MAX_COMPRESS_PTRS)
204933707f3Ssthen 				return 0; /* loop! */
2055d76a658Ssthen 			if(sldns_buffer_limit(pkt) <= ptr)
206933707f3Ssthen 				return 0; /* out of bounds! */
207933707f3Ssthen 			if(!endpos)
2085d76a658Ssthen 				endpos = sldns_buffer_position(pkt);
2095d76a658Ssthen 			sldns_buffer_set_position(pkt, ptr);
210933707f3Ssthen 		} else {
211933707f3Ssthen 			/* label contents */
212933707f3Ssthen 			if(labellen > 0x3f)
213933707f3Ssthen 				return 0; /* label too long */
214933707f3Ssthen 			len += 1 + labellen;
215933707f3Ssthen 			if(len > LDNS_MAX_DOMAINLEN)
216933707f3Ssthen 				return 0;
217933707f3Ssthen 			if(labellen == 0) {
218933707f3Ssthen 				/* end of dname */
219933707f3Ssthen 				break;
220933707f3Ssthen 			}
2215d76a658Ssthen 			if(sldns_buffer_remaining(pkt) < labellen)
222933707f3Ssthen 				return 0;
2235d76a658Ssthen 			sldns_buffer_skip(pkt, (ssize_t)labellen);
224933707f3Ssthen 		}
225933707f3Ssthen 	}
226933707f3Ssthen 	if(endpos)
2275d76a658Ssthen 		sldns_buffer_set_position(pkt, endpos);
228933707f3Ssthen 
229933707f3Ssthen 	return len;
230933707f3Ssthen }
231933707f3Ssthen 
232933707f3Ssthen int
dname_pkt_compare(sldns_buffer * pkt,uint8_t * d1,uint8_t * d2)2335d76a658Ssthen dname_pkt_compare(sldns_buffer* pkt, uint8_t* d1, uint8_t* d2)
234933707f3Ssthen {
235933707f3Ssthen 	uint8_t len1, len2;
236*06a13c09Ssthen 	int count1 = 0, count2 = 0;
237933707f3Ssthen 	log_assert(pkt && d1 && d2);
238933707f3Ssthen 	len1 = *d1++;
239933707f3Ssthen 	len2 = *d2++;
240933707f3Ssthen 	while( len1 != 0 || len2 != 0 ) {
241933707f3Ssthen 		/* resolve ptrs */
242933707f3Ssthen 		if(LABEL_IS_PTR(len1)) {
243*06a13c09Ssthen 			if((size_t)PTR_OFFSET(len1, *d1)
244*06a13c09Ssthen 				>= sldns_buffer_limit(pkt))
245*06a13c09Ssthen 				return -1;
246*06a13c09Ssthen 			if(count1++ > MAX_COMPRESS_PTRS)
247*06a13c09Ssthen 				return -1;
2485d76a658Ssthen 			d1 = sldns_buffer_at(pkt, PTR_OFFSET(len1, *d1));
249933707f3Ssthen 			len1 = *d1++;
250933707f3Ssthen 			continue;
251933707f3Ssthen 		}
252933707f3Ssthen 		if(LABEL_IS_PTR(len2)) {
253*06a13c09Ssthen 			if((size_t)PTR_OFFSET(len2, *d2)
254*06a13c09Ssthen 				>= sldns_buffer_limit(pkt))
255*06a13c09Ssthen 				return 1;
256*06a13c09Ssthen 			if(count2++ > MAX_COMPRESS_PTRS)
257*06a13c09Ssthen 				return 1;
2585d76a658Ssthen 			d2 = sldns_buffer_at(pkt, PTR_OFFSET(len2, *d2));
259933707f3Ssthen 			len2 = *d2++;
260933707f3Ssthen 			continue;
261933707f3Ssthen 		}
262933707f3Ssthen 		/* check label length */
263933707f3Ssthen 		log_assert(len1 <= LDNS_MAX_LABELLEN);
264933707f3Ssthen 		log_assert(len2 <= LDNS_MAX_LABELLEN);
265933707f3Ssthen 		if(len1 != len2) {
266933707f3Ssthen 			if(len1 < len2) return -1;
267933707f3Ssthen 			return 1;
268933707f3Ssthen 		}
269933707f3Ssthen 		log_assert(len1 == len2 && len1 != 0);
270933707f3Ssthen 		/* compare labels */
271933707f3Ssthen 		while(len1--) {
2722ee382b6Ssthen 			if(tolower((unsigned char)*d1) != tolower((unsigned char)*d2)) {
2732ee382b6Ssthen 				if(tolower((unsigned char)*d1) < tolower((unsigned char)*d2))
274933707f3Ssthen 					return -1;
275933707f3Ssthen 				return 1;
276933707f3Ssthen 			}
2772ee382b6Ssthen 			d1++;
2782ee382b6Ssthen 			d2++;
279933707f3Ssthen 		}
280933707f3Ssthen 		len1 = *d1++;
281933707f3Ssthen 		len2 = *d2++;
282933707f3Ssthen 	}
283933707f3Ssthen 	return 0;
284933707f3Ssthen }
285933707f3Ssthen 
28677079be7Ssthen hashvalue_type
dname_query_hash(uint8_t * dname,hashvalue_type h)28777079be7Ssthen dname_query_hash(uint8_t* dname, hashvalue_type h)
288933707f3Ssthen {
289933707f3Ssthen 	uint8_t labuf[LDNS_MAX_LABELLEN+1];
290933707f3Ssthen 	uint8_t lablen;
291933707f3Ssthen 	int i;
292933707f3Ssthen 
293933707f3Ssthen 	/* preserve case of query, make hash label by label */
294933707f3Ssthen 	lablen = *dname++;
295933707f3Ssthen 	while(lablen) {
296933707f3Ssthen 		log_assert(lablen <= LDNS_MAX_LABELLEN);
297933707f3Ssthen 		labuf[0] = lablen;
298933707f3Ssthen 		i=0;
2992ee382b6Ssthen 		while(lablen--) {
3002ee382b6Ssthen 			labuf[++i] = (uint8_t)tolower((unsigned char)*dname);
3012ee382b6Ssthen 			dname++;
3022ee382b6Ssthen 		}
303933707f3Ssthen 		h = hashlittle(labuf, labuf[0] + 1, h);
304933707f3Ssthen 		lablen = *dname++;
305933707f3Ssthen 	}
306933707f3Ssthen 
307933707f3Ssthen 	return h;
308933707f3Ssthen }
309933707f3Ssthen 
31077079be7Ssthen hashvalue_type
dname_pkt_hash(sldns_buffer * pkt,uint8_t * dname,hashvalue_type h)31177079be7Ssthen dname_pkt_hash(sldns_buffer* pkt, uint8_t* dname, hashvalue_type h)
312933707f3Ssthen {
313933707f3Ssthen 	uint8_t labuf[LDNS_MAX_LABELLEN+1];
314933707f3Ssthen 	uint8_t lablen;
315933707f3Ssthen 	int i;
316*06a13c09Ssthen 	int count = 0;
317933707f3Ssthen 
318933707f3Ssthen 	/* preserve case of query, make hash label by label */
319933707f3Ssthen 	lablen = *dname++;
320933707f3Ssthen 	while(lablen) {
321933707f3Ssthen 		if(LABEL_IS_PTR(lablen)) {
322933707f3Ssthen 			/* follow pointer */
323*06a13c09Ssthen 			if((size_t)PTR_OFFSET(lablen, *dname)
324*06a13c09Ssthen 				>= sldns_buffer_limit(pkt))
325*06a13c09Ssthen 				return h;
326*06a13c09Ssthen 			if(count++ > MAX_COMPRESS_PTRS)
327*06a13c09Ssthen 				return h;
3285d76a658Ssthen 			dname = sldns_buffer_at(pkt, PTR_OFFSET(lablen, *dname));
329933707f3Ssthen 			lablen = *dname++;
330933707f3Ssthen 			continue;
331933707f3Ssthen 		}
332933707f3Ssthen 		log_assert(lablen <= LDNS_MAX_LABELLEN);
333933707f3Ssthen 		labuf[0] = lablen;
334933707f3Ssthen 		i=0;
3352ee382b6Ssthen 		while(lablen--) {
3362ee382b6Ssthen 			labuf[++i] = (uint8_t)tolower((unsigned char)*dname);
3372ee382b6Ssthen 			dname++;
3382ee382b6Ssthen 		}
339933707f3Ssthen 		h = hashlittle(labuf, labuf[0] + 1, h);
340933707f3Ssthen 		lablen = *dname++;
341933707f3Ssthen 	}
342933707f3Ssthen 
343933707f3Ssthen 	return h;
344933707f3Ssthen }
345933707f3Ssthen 
dname_pkt_copy(sldns_buffer * pkt,uint8_t * to,uint8_t * dname)3465d76a658Ssthen void dname_pkt_copy(sldns_buffer* pkt, uint8_t* to, uint8_t* dname)
347933707f3Ssthen {
348933707f3Ssthen 	/* copy over the dname and decompress it at the same time */
349ebf5bb73Ssthen 	size_t comprcount = 0;
350933707f3Ssthen 	size_t len = 0;
351933707f3Ssthen 	uint8_t lablen;
352933707f3Ssthen 	lablen = *dname++;
353933707f3Ssthen 	while(lablen) {
354933707f3Ssthen 		if(LABEL_IS_PTR(lablen)) {
355ebf5bb73Ssthen 			if(comprcount++ > MAX_COMPRESS_PTRS) {
356ebf5bb73Ssthen 				/* too many compression pointers */
357ebf5bb73Ssthen 				*to = 0; /* end the result prematurely */
358ebf5bb73Ssthen 				return;
359ebf5bb73Ssthen 			}
360933707f3Ssthen 			/* follow pointer */
361*06a13c09Ssthen 			if((size_t)PTR_OFFSET(lablen, *dname)
362*06a13c09Ssthen 				>= sldns_buffer_limit(pkt))
363*06a13c09Ssthen 				return;
3645d76a658Ssthen 			dname = sldns_buffer_at(pkt, PTR_OFFSET(lablen, *dname));
365933707f3Ssthen 			lablen = *dname++;
366933707f3Ssthen 			continue;
367933707f3Ssthen 		}
368ebf5bb73Ssthen 		if(lablen > LDNS_MAX_LABELLEN) {
369ebf5bb73Ssthen 			*to = 0; /* end the result prematurely */
370ebf5bb73Ssthen 			return;
371ebf5bb73Ssthen 		}
372933707f3Ssthen 		log_assert(lablen <= LDNS_MAX_LABELLEN);
373933707f3Ssthen 		len += (size_t)lablen+1;
374933707f3Ssthen 		if(len >= LDNS_MAX_DOMAINLEN) {
375933707f3Ssthen 			*to = 0; /* end the result prematurely */
376933707f3Ssthen 			log_err("bad dname in dname_pkt_copy");
377933707f3Ssthen 			return;
378933707f3Ssthen 		}
379933707f3Ssthen 		*to++ = lablen;
380933707f3Ssthen 		memmove(to, dname, lablen);
381933707f3Ssthen 		dname += lablen;
382933707f3Ssthen 		to += lablen;
383933707f3Ssthen 		lablen = *dname++;
384933707f3Ssthen 	}
385933707f3Ssthen 	/* copy last \0 */
386933707f3Ssthen 	*to = 0;
387933707f3Ssthen }
388933707f3Ssthen 
dname_print(FILE * out,struct sldns_buffer * pkt,uint8_t * dname)3895d76a658Ssthen void dname_print(FILE* out, struct sldns_buffer* pkt, uint8_t* dname)
390933707f3Ssthen {
391933707f3Ssthen 	uint8_t lablen;
392*06a13c09Ssthen 	int count = 0;
393933707f3Ssthen 	if(!out) out = stdout;
394933707f3Ssthen 	if(!dname) return;
395933707f3Ssthen 
396933707f3Ssthen 	lablen = *dname++;
397933707f3Ssthen 	if(!lablen)
398933707f3Ssthen 		fputc('.', out);
399933707f3Ssthen 	while(lablen) {
400933707f3Ssthen 		if(LABEL_IS_PTR(lablen)) {
401933707f3Ssthen 			/* follow pointer */
402933707f3Ssthen 			if(!pkt) {
403933707f3Ssthen 				fputs("??compressionptr??", out);
404933707f3Ssthen 				return;
405933707f3Ssthen 			}
406*06a13c09Ssthen 			if((size_t)PTR_OFFSET(lablen, *dname)
407*06a13c09Ssthen 				>= sldns_buffer_limit(pkt)) {
408*06a13c09Ssthen 				fputs("??compressionptr??", out);
409*06a13c09Ssthen 				return;
410*06a13c09Ssthen 			}
411*06a13c09Ssthen 			if(count++ > MAX_COMPRESS_PTRS) {
412*06a13c09Ssthen 				fputs("??compressionptr??", out);
413*06a13c09Ssthen 				return;
414*06a13c09Ssthen 			}
4155d76a658Ssthen 			dname = sldns_buffer_at(pkt, PTR_OFFSET(lablen, *dname));
416933707f3Ssthen 			lablen = *dname++;
417933707f3Ssthen 			continue;
418933707f3Ssthen 		}
419933707f3Ssthen 		if(lablen > LDNS_MAX_LABELLEN) {
420933707f3Ssthen 			fputs("??extendedlabel??", out);
421933707f3Ssthen 			return;
422933707f3Ssthen 		}
423933707f3Ssthen 		while(lablen--)
424933707f3Ssthen 			fputc((int)*dname++, out);
425933707f3Ssthen 		fputc('.', out);
426933707f3Ssthen 		lablen = *dname++;
427933707f3Ssthen 	}
428933707f3Ssthen }
429933707f3Ssthen 
430933707f3Ssthen int
dname_count_labels(uint8_t * dname)431933707f3Ssthen dname_count_labels(uint8_t* dname)
432933707f3Ssthen {
433933707f3Ssthen 	uint8_t lablen;
434933707f3Ssthen 	int labs = 1;
435933707f3Ssthen 
436933707f3Ssthen 	lablen = *dname++;
437933707f3Ssthen 	while(lablen) {
438933707f3Ssthen 		labs++;
439933707f3Ssthen 		dname += lablen;
440933707f3Ssthen 		lablen = *dname++;
441933707f3Ssthen 	}
442933707f3Ssthen 	return labs;
443933707f3Ssthen }
444933707f3Ssthen 
445933707f3Ssthen int
dname_count_size_labels(uint8_t * dname,size_t * size)446933707f3Ssthen dname_count_size_labels(uint8_t* dname, size_t* size)
447933707f3Ssthen {
448933707f3Ssthen 	uint8_t lablen;
449933707f3Ssthen 	int labs = 1;
450933707f3Ssthen 	size_t sz = 1;
451933707f3Ssthen 
452933707f3Ssthen 	lablen = *dname++;
453933707f3Ssthen 	while(lablen) {
454933707f3Ssthen 		labs++;
455933707f3Ssthen 		sz += lablen+1;
456933707f3Ssthen 		dname += lablen;
457933707f3Ssthen 		lablen = *dname++;
458933707f3Ssthen 	}
459933707f3Ssthen 	*size = sz;
460933707f3Ssthen 	return labs;
461933707f3Ssthen }
462933707f3Ssthen 
463933707f3Ssthen /**
464933707f3Ssthen  * Compare labels in memory, lowercase while comparing.
465933707f3Ssthen  * @param p1: label 1
466933707f3Ssthen  * @param p2: label 2
467933707f3Ssthen  * @param len: number of bytes to compare.
468933707f3Ssthen  * @return: 0, -1, +1 comparison result.
469933707f3Ssthen  */
470933707f3Ssthen static int
memlowercmp(uint8_t * p1,uint8_t * p2,uint8_t len)471933707f3Ssthen memlowercmp(uint8_t* p1, uint8_t* p2, uint8_t len)
472933707f3Ssthen {
473933707f3Ssthen 	while(len--) {
47498f3ca02Sbrad 		if(*p1 != *p2 && tolower((unsigned char)*p1) != tolower((unsigned char)*p2)) {
47598f3ca02Sbrad 			if(tolower((unsigned char)*p1) < tolower((unsigned char)*p2))
476933707f3Ssthen 				return -1;
477933707f3Ssthen 			return 1;
478933707f3Ssthen 		}
479933707f3Ssthen 		p1++;
480933707f3Ssthen 		p2++;
481933707f3Ssthen 	}
482933707f3Ssthen 	return 0;
483933707f3Ssthen }
484933707f3Ssthen 
485933707f3Ssthen int
dname_lab_cmp(uint8_t * d1,int labs1,uint8_t * d2,int labs2,int * mlabs)486933707f3Ssthen dname_lab_cmp(uint8_t* d1, int labs1, uint8_t* d2, int labs2, int* mlabs)
487933707f3Ssthen {
488933707f3Ssthen 	uint8_t len1, len2;
489933707f3Ssthen 	int atlabel = labs1;
490933707f3Ssthen 	int lastmlabs;
491933707f3Ssthen 	int lastdiff = 0;
492933707f3Ssthen 	/* first skip so that we compare same label. */
493933707f3Ssthen 	if(labs1 > labs2) {
494933707f3Ssthen 		while(atlabel > labs2) {
495933707f3Ssthen 			len1 = *d1++;
496933707f3Ssthen 			d1 += len1;
497933707f3Ssthen 			atlabel--;
498933707f3Ssthen 		}
499933707f3Ssthen 		log_assert(atlabel == labs2);
500933707f3Ssthen 	} else if(labs1 < labs2) {
501933707f3Ssthen 		atlabel = labs2;
502933707f3Ssthen 		while(atlabel > labs1) {
503933707f3Ssthen 			len2 = *d2++;
504933707f3Ssthen 			d2 += len2;
505933707f3Ssthen 			atlabel--;
506933707f3Ssthen 		}
507933707f3Ssthen 		log_assert(atlabel == labs1);
508933707f3Ssthen 	}
509933707f3Ssthen 	lastmlabs = atlabel+1;
510933707f3Ssthen 	/* now at same label in d1 and d2, atlabel */
511933707f3Ssthen 	/* www.example.com.                  */
512933707f3Ssthen 	/* 4   3       2  1   atlabel number */
513933707f3Ssthen 	/* repeat until at root label (which is always the same) */
514933707f3Ssthen 	while(atlabel > 1) {
515933707f3Ssthen 		len1 = *d1++;
516933707f3Ssthen 		len2 = *d2++;
517933707f3Ssthen 		if(len1 != len2) {
518933707f3Ssthen 			log_assert(len1 != 0 && len2 != 0);
519933707f3Ssthen 			if(len1<len2)
520933707f3Ssthen 				lastdiff = -1;
521933707f3Ssthen 			else	lastdiff = 1;
522933707f3Ssthen 			lastmlabs = atlabel;
523933707f3Ssthen 			d1 += len1;
524933707f3Ssthen 			d2 += len2;
525933707f3Ssthen 		} else {
526933707f3Ssthen 			/* memlowercmp is inlined here; or just like
527933707f3Ssthen 			 * if((c=memlowercmp(d1, d2, len1)) != 0) {
528933707f3Ssthen 			 *	lastdiff = c;
529933707f3Ssthen 			 *	lastmlabs = atlabel; } apart from d1++,d2++ */
530933707f3Ssthen 			while(len1) {
53198f3ca02Sbrad 				if(*d1 != *d2 && tolower((unsigned char)*d1)
53298f3ca02Sbrad 					!= tolower((unsigned char)*d2)) {
53398f3ca02Sbrad 					if(tolower((unsigned char)*d1) <
53498f3ca02Sbrad 						tolower((unsigned char)*d2)) {
535933707f3Ssthen 						lastdiff = -1;
536933707f3Ssthen 						lastmlabs = atlabel;
537933707f3Ssthen 						d1 += len1;
538933707f3Ssthen 						d2 += len1;
539933707f3Ssthen 						break;
540933707f3Ssthen 					}
541933707f3Ssthen 					lastdiff = 1;
542933707f3Ssthen 					lastmlabs = atlabel;
543933707f3Ssthen 					d1 += len1;
544933707f3Ssthen 					d2 += len1;
545933707f3Ssthen 					break; /* out of memlowercmp */
546933707f3Ssthen 				}
547933707f3Ssthen 				d1++;
548933707f3Ssthen 				d2++;
549933707f3Ssthen 				len1--;
550933707f3Ssthen 			}
551933707f3Ssthen 		}
552933707f3Ssthen 		atlabel--;
553933707f3Ssthen 	}
554933707f3Ssthen 	/* last difference atlabel number, so number of labels matching,
555933707f3Ssthen 	 * at the right side, is one less. */
556933707f3Ssthen 	*mlabs = lastmlabs-1;
557933707f3Ssthen 	if(lastdiff == 0) {
558933707f3Ssthen 		/* all labels compared were equal, check if one has more
559933707f3Ssthen 		 * labels, so that example.com. > com. */
560933707f3Ssthen 		if(labs1 > labs2)
561933707f3Ssthen 			return 1;
562933707f3Ssthen 		else if(labs1 < labs2)
563933707f3Ssthen 			return -1;
564933707f3Ssthen 	}
565933707f3Ssthen 	return lastdiff;
566933707f3Ssthen }
567933707f3Ssthen 
568933707f3Ssthen int
dname_lab_startswith(uint8_t * label,char * prefix,char ** endptr)56920237c55Ssthen dname_lab_startswith(uint8_t* label, char* prefix, char** endptr)
57020237c55Ssthen {
57120237c55Ssthen 	size_t plen = strlen(prefix);
57220237c55Ssthen 	size_t orig_plen = plen;
57320237c55Ssthen 	size_t lablen = (size_t)*label;
57420237c55Ssthen 	if(plen > lablen)
57520237c55Ssthen 		return 0;
57620237c55Ssthen 	label++;
57720237c55Ssthen 	while(plen--) {
57820237c55Ssthen 		if(*prefix != tolower((unsigned char)*label)) {
57920237c55Ssthen 			return 0;
58020237c55Ssthen 		}
58120237c55Ssthen 		prefix++; label++;
58220237c55Ssthen 	}
58320237c55Ssthen 	if(orig_plen < lablen)
58420237c55Ssthen 		*endptr = (char *)label;
58520237c55Ssthen 	else
58620237c55Ssthen 		/* prefix length == label length */
58720237c55Ssthen 		*endptr = NULL;
58820237c55Ssthen 	return 1;
58920237c55Ssthen }
59020237c55Ssthen 
59120237c55Ssthen int
dname_has_label(uint8_t * dname,size_t dnamelen,uint8_t * label)592eaf2578eSsthen dname_has_label(uint8_t* dname, size_t dnamelen, uint8_t* label)
593eaf2578eSsthen {
594eaf2578eSsthen 	size_t len;
595eaf2578eSsthen 
596eaf2578eSsthen 	/* 1 byte needed for the label length */
597eaf2578eSsthen 	if(dnamelen < 1)
598eaf2578eSsthen 		return 0;
599eaf2578eSsthen 
600eaf2578eSsthen 	len = *dname;
601eaf2578eSsthen 	while(len <= dnamelen) {
602eaf2578eSsthen 		if(!(*dname)) {
603eaf2578eSsthen 			if(*dname == *label)
604eaf2578eSsthen 				return 1; /* empty label match */
605eaf2578eSsthen 			/* termination label found, stop iterating */
606eaf2578eSsthen 			return 0;
607eaf2578eSsthen 		}
608eaf2578eSsthen 		if(*dname == *label && *label &&
609eaf2578eSsthen 			memlowercmp(dname+1, label+1, *dname) == 0)
610eaf2578eSsthen 			return 1;
611eaf2578eSsthen 		len += *dname;
612eaf2578eSsthen 		dname += *dname;
613eaf2578eSsthen 		dname++;
614eaf2578eSsthen 		len++;
615eaf2578eSsthen 	}
616eaf2578eSsthen 	return 0;
617eaf2578eSsthen }
618eaf2578eSsthen 
619eaf2578eSsthen int
dname_buffer_write(sldns_buffer * pkt,uint8_t * dname)6205d76a658Ssthen dname_buffer_write(sldns_buffer* pkt, uint8_t* dname)
621933707f3Ssthen {
622933707f3Ssthen 	uint8_t lablen;
623933707f3Ssthen 
6245d76a658Ssthen 	if(sldns_buffer_remaining(pkt) < 1)
625933707f3Ssthen 		return 0;
626933707f3Ssthen 	lablen = *dname++;
6275d76a658Ssthen 	sldns_buffer_write_u8(pkt, lablen);
628933707f3Ssthen 	while(lablen) {
6295d76a658Ssthen 		if(sldns_buffer_remaining(pkt) < (size_t)lablen+1)
630933707f3Ssthen 			return 0;
6315d76a658Ssthen 		sldns_buffer_write(pkt, dname, lablen);
632933707f3Ssthen 		dname += lablen;
633933707f3Ssthen 		lablen = *dname++;
6345d76a658Ssthen 		sldns_buffer_write_u8(pkt, lablen);
635933707f3Ssthen 	}
636933707f3Ssthen 	return 1;
637933707f3Ssthen }
638933707f3Ssthen 
dname_str(uint8_t * dname,char * str)639933707f3Ssthen void dname_str(uint8_t* dname, char* str)
640933707f3Ssthen {
641933707f3Ssthen 	size_t len = 0;
642933707f3Ssthen 	uint8_t lablen = 0;
643933707f3Ssthen 	char* s = str;
644933707f3Ssthen 	if(!dname || !*dname) {
645933707f3Ssthen 		*s++ = '.';
646933707f3Ssthen 		*s = 0;
647933707f3Ssthen 		return;
648933707f3Ssthen 	}
649933707f3Ssthen 	lablen = *dname++;
650933707f3Ssthen 	while(lablen) {
651933707f3Ssthen 		if(lablen > LDNS_MAX_LABELLEN) {
652933707f3Ssthen 			*s++ = '#';
653933707f3Ssthen 			*s = 0;
654933707f3Ssthen 			return;
655933707f3Ssthen 		}
656933707f3Ssthen 		len += lablen+1;
657933707f3Ssthen 		if(len >= LDNS_MAX_DOMAINLEN-1) {
658933707f3Ssthen 			*s++ = '&';
659933707f3Ssthen 			*s = 0;
660933707f3Ssthen 			return;
661933707f3Ssthen 		}
662933707f3Ssthen 		while(lablen--) {
66398f3ca02Sbrad 			if(isalnum((unsigned char)*dname)
664933707f3Ssthen 				|| *dname == '-' || *dname == '_'
665933707f3Ssthen 				|| *dname == '*')
666933707f3Ssthen 				*s++ = *(char*)dname++;
667933707f3Ssthen 			else	{
668933707f3Ssthen 				*s++ = '?';
669933707f3Ssthen 				dname++;
670933707f3Ssthen 			}
671933707f3Ssthen 		}
672933707f3Ssthen 		*s++ = '.';
673933707f3Ssthen 		lablen = *dname++;
674933707f3Ssthen 	}
675933707f3Ssthen 	*s = 0;
676933707f3Ssthen }
677933707f3Ssthen 
678933707f3Ssthen int
dname_strict_subdomain(uint8_t * d1,int labs1,uint8_t * d2,int labs2)679933707f3Ssthen dname_strict_subdomain(uint8_t* d1, int labs1, uint8_t* d2, int labs2)
680933707f3Ssthen {
681933707f3Ssthen 	int m;
682933707f3Ssthen 	/* check subdomain: d1: www.example.com. and d2: example.com. */
683933707f3Ssthen 	if(labs2 >= labs1)
684933707f3Ssthen 		return 0;
685933707f3Ssthen 	if(dname_lab_cmp(d1, labs1, d2, labs2, &m) > 0) {
686933707f3Ssthen 		/* subdomain if all labels match */
687933707f3Ssthen 		return (m == labs2);
688933707f3Ssthen 	}
689933707f3Ssthen 	return 0;
690933707f3Ssthen }
691933707f3Ssthen 
692933707f3Ssthen int
dname_strict_subdomain_c(uint8_t * d1,uint8_t * d2)693933707f3Ssthen dname_strict_subdomain_c(uint8_t* d1, uint8_t* d2)
694933707f3Ssthen {
695933707f3Ssthen 	return dname_strict_subdomain(d1, dname_count_labels(d1), d2,
696933707f3Ssthen 		dname_count_labels(d2));
697933707f3Ssthen }
698933707f3Ssthen 
699933707f3Ssthen int
dname_subdomain_c(uint8_t * d1,uint8_t * d2)700933707f3Ssthen dname_subdomain_c(uint8_t* d1, uint8_t* d2)
701933707f3Ssthen {
702933707f3Ssthen 	int m;
703933707f3Ssthen 	/* check subdomain: d1: www.example.com. and d2: example.com. */
704933707f3Ssthen 	/*  	or 	    d1: example.com. and d2: example.com. */
705933707f3Ssthen 	int labs1 = dname_count_labels(d1);
706933707f3Ssthen 	int labs2 = dname_count_labels(d2);
707933707f3Ssthen 	if(labs2 > labs1)
708933707f3Ssthen 		return 0;
709933707f3Ssthen 	if(dname_lab_cmp(d1, labs1, d2, labs2, &m) < 0) {
710933707f3Ssthen 		/* must have been example.com , www.example.com - wrong */
711933707f3Ssthen 		/* or otherwise different dnames */
712933707f3Ssthen 		return 0;
713933707f3Ssthen 	}
714933707f3Ssthen 	return (m == labs2);
715933707f3Ssthen }
716933707f3Ssthen 
717933707f3Ssthen int
dname_is_root(uint8_t * dname)718933707f3Ssthen dname_is_root(uint8_t* dname)
719933707f3Ssthen {
720933707f3Ssthen 	uint8_t len;
721933707f3Ssthen 	log_assert(dname);
722933707f3Ssthen 	len = dname[0];
723933707f3Ssthen 	log_assert(!LABEL_IS_PTR(len));
724933707f3Ssthen 	return (len == 0);
725933707f3Ssthen }
726933707f3Ssthen 
727933707f3Ssthen void
dname_remove_label(uint8_t ** dname,size_t * len)728933707f3Ssthen dname_remove_label(uint8_t** dname, size_t* len)
729933707f3Ssthen {
730933707f3Ssthen 	size_t lablen;
731933707f3Ssthen 	log_assert(dname && *dname && len);
732933707f3Ssthen 	lablen = (*dname)[0];
733933707f3Ssthen 	log_assert(!LABEL_IS_PTR(lablen));
734933707f3Ssthen 	log_assert(*len > lablen);
735933707f3Ssthen 	if(lablen == 0)
736933707f3Ssthen 		return; /* do not modify root label */
737933707f3Ssthen 	*len -= lablen+1;
738933707f3Ssthen 	*dname += lablen+1;
739933707f3Ssthen }
740933707f3Ssthen 
741933707f3Ssthen void
dname_remove_labels(uint8_t ** dname,size_t * len,int n)742933707f3Ssthen dname_remove_labels(uint8_t** dname, size_t* len, int n)
743933707f3Ssthen {
744933707f3Ssthen 	int i;
745933707f3Ssthen 	for(i=0; i<n; i++)
746933707f3Ssthen 		dname_remove_label(dname, len);
747933707f3Ssthen }
748933707f3Ssthen 
749933707f3Ssthen int
dname_signame_label_count(uint8_t * dname)750933707f3Ssthen dname_signame_label_count(uint8_t* dname)
751933707f3Ssthen {
752933707f3Ssthen 	uint8_t lablen;
753933707f3Ssthen 	int count = 0;
754933707f3Ssthen 	if(!*dname)
755933707f3Ssthen 		return 0;
756933707f3Ssthen 	if(dname[0] == 1 && dname[1] == '*')
757933707f3Ssthen 		dname += 2;
758933707f3Ssthen 	lablen = dname[0];
759933707f3Ssthen 	while(lablen) {
760933707f3Ssthen 		count++;
761933707f3Ssthen 		dname += lablen;
762933707f3Ssthen 		dname += 1;
763933707f3Ssthen 		lablen = dname[0];
764933707f3Ssthen 	}
765933707f3Ssthen 	return count;
766933707f3Ssthen }
767933707f3Ssthen 
768933707f3Ssthen int
dname_is_wild(uint8_t * dname)769933707f3Ssthen dname_is_wild(uint8_t* dname)
770933707f3Ssthen {
771933707f3Ssthen 	return (dname[0] == 1 && dname[1] == '*');
772933707f3Ssthen }
773933707f3Ssthen 
774933707f3Ssthen /**
775933707f3Ssthen  * Compare labels in memory, lowercase while comparing.
776933707f3Ssthen  * Returns canonical order for labels. If all is equal, the
777933707f3Ssthen  * shortest is first.
778933707f3Ssthen  *
779933707f3Ssthen  * @param p1: label 1
780933707f3Ssthen  * @param len1: length of label 1.
781933707f3Ssthen  * @param p2: label 2
782933707f3Ssthen  * @param len2: length of label 2.
783933707f3Ssthen  * @return: 0, -1, +1 comparison result.
784933707f3Ssthen  */
785933707f3Ssthen static int
memcanoncmp(uint8_t * p1,uint8_t len1,uint8_t * p2,uint8_t len2)786933707f3Ssthen memcanoncmp(uint8_t* p1, uint8_t len1, uint8_t* p2, uint8_t len2)
787933707f3Ssthen {
788933707f3Ssthen 	uint8_t min = (len1<len2)?len1:len2;
789933707f3Ssthen 	int c = memlowercmp(p1, p2, min);
790933707f3Ssthen 	if(c != 0)
791933707f3Ssthen 		return c;
792933707f3Ssthen 	/* equal, see who is shortest */
793933707f3Ssthen 	if(len1 < len2)
794933707f3Ssthen 		return -1;
795933707f3Ssthen 	if(len1 > len2)
796933707f3Ssthen 		return 1;
797933707f3Ssthen 	return 0;
798933707f3Ssthen }
799933707f3Ssthen 
800933707f3Ssthen 
801933707f3Ssthen int
dname_canon_lab_cmp(uint8_t * d1,int labs1,uint8_t * d2,int labs2,int * mlabs)802933707f3Ssthen dname_canon_lab_cmp(uint8_t* d1, int labs1, uint8_t* d2, int labs2, int* mlabs)
803933707f3Ssthen {
804933707f3Ssthen 	/* like dname_lab_cmp, but with different label comparison,
805933707f3Ssthen 	 * empty character sorts before \000.
806933707f3Ssthen 	 * So   ylyly is before z. */
807933707f3Ssthen 	uint8_t len1, len2;
808933707f3Ssthen 	int atlabel = labs1;
809933707f3Ssthen 	int lastmlabs;
810933707f3Ssthen 	int lastdiff = 0;
811933707f3Ssthen 	int c;
812933707f3Ssthen 	/* first skip so that we compare same label. */
813933707f3Ssthen 	if(labs1 > labs2) {
814933707f3Ssthen 		while(atlabel > labs2) {
815933707f3Ssthen 			len1 = *d1++;
816933707f3Ssthen 			d1 += len1;
817933707f3Ssthen 			atlabel--;
818933707f3Ssthen 		}
819933707f3Ssthen 		log_assert(atlabel == labs2);
820933707f3Ssthen 	} else if(labs1 < labs2) {
821933707f3Ssthen 		atlabel = labs2;
822933707f3Ssthen 		while(atlabel > labs1) {
823933707f3Ssthen 			len2 = *d2++;
824933707f3Ssthen 			d2 += len2;
825933707f3Ssthen 			atlabel--;
826933707f3Ssthen 		}
827933707f3Ssthen 		log_assert(atlabel == labs1);
828933707f3Ssthen 	}
829933707f3Ssthen 	lastmlabs = atlabel+1;
830933707f3Ssthen 	/* now at same label in d1 and d2, atlabel */
831933707f3Ssthen 	/* www.example.com.                  */
832933707f3Ssthen 	/* 4   3       2  1   atlabel number */
833933707f3Ssthen 	/* repeat until at root label (which is always the same) */
834933707f3Ssthen 	while(atlabel > 1) {
835933707f3Ssthen 		len1 = *d1++;
836933707f3Ssthen 		len2 = *d2++;
837933707f3Ssthen 
838933707f3Ssthen 		if((c=memcanoncmp(d1, len1, d2, len2)) != 0) {
839933707f3Ssthen 			if(c<0)
840933707f3Ssthen 				lastdiff = -1;
841933707f3Ssthen 			else	lastdiff = 1;
842933707f3Ssthen 			lastmlabs = atlabel;
843933707f3Ssthen 		}
844933707f3Ssthen 
845933707f3Ssthen 		d1 += len1;
846933707f3Ssthen 		d2 += len2;
847933707f3Ssthen 		atlabel--;
848933707f3Ssthen 	}
849933707f3Ssthen 	/* last difference atlabel number, so number of labels matching,
850933707f3Ssthen 	 * at the right side, is one less. */
851933707f3Ssthen 	*mlabs = lastmlabs-1;
852933707f3Ssthen 	if(lastdiff == 0) {
853933707f3Ssthen 		/* all labels compared were equal, check if one has more
854933707f3Ssthen 		 * labels, so that example.com. > com. */
855933707f3Ssthen 		if(labs1 > labs2)
856933707f3Ssthen 			return 1;
857933707f3Ssthen 		else if(labs1 < labs2)
858933707f3Ssthen 			return -1;
859933707f3Ssthen 	}
860933707f3Ssthen 	return lastdiff;
861933707f3Ssthen }
862933707f3Ssthen 
863933707f3Ssthen int
dname_canonical_compare(uint8_t * d1,uint8_t * d2)864933707f3Ssthen dname_canonical_compare(uint8_t* d1, uint8_t* d2)
865933707f3Ssthen {
866933707f3Ssthen 	int labs1, labs2, m;
867933707f3Ssthen 	labs1 = dname_count_labels(d1);
868933707f3Ssthen 	labs2 = dname_count_labels(d2);
869933707f3Ssthen 	return dname_canon_lab_cmp(d1, labs1, d2, labs2, &m);
870933707f3Ssthen }
871933707f3Ssthen 
dname_get_shared_topdomain(uint8_t * d1,uint8_t * d2)872933707f3Ssthen uint8_t* dname_get_shared_topdomain(uint8_t* d1, uint8_t* d2)
873933707f3Ssthen {
874933707f3Ssthen 	int labs1, labs2, m;
875933707f3Ssthen 	size_t len = LDNS_MAX_DOMAINLEN;
876933707f3Ssthen 	labs1 = dname_count_labels(d1);
877933707f3Ssthen 	labs2 = dname_count_labels(d2);
878933707f3Ssthen 	(void)dname_lab_cmp(d1, labs1, d2, labs2, &m);
879933707f3Ssthen 	dname_remove_labels(&d1, &len, labs1-m);
880933707f3Ssthen 	return d1;
881933707f3Ssthen }
882