xref: /freebsd/contrib/unbound/util/data/dname.c (revision be771a7b7f4580a30d99e41a5bb1b93a385a119d)
1b7579f77SDag-Erling Smørgrav /*
2b7579f77SDag-Erling Smørgrav  * util/data/dname.h - domain name handling
3b7579f77SDag-Erling Smørgrav  *
4b7579f77SDag-Erling Smørgrav  * Copyright (c) 2007, NLnet Labs. All rights reserved.
5b7579f77SDag-Erling Smørgrav  *
6b7579f77SDag-Erling Smørgrav  * This software is open source.
7b7579f77SDag-Erling Smørgrav  *
8b7579f77SDag-Erling Smørgrav  * Redistribution and use in source and binary forms, with or without
9b7579f77SDag-Erling Smørgrav  * modification, are permitted provided that the following conditions
10b7579f77SDag-Erling Smørgrav  * are met:
11b7579f77SDag-Erling Smørgrav  *
12b7579f77SDag-Erling Smørgrav  * Redistributions of source code must retain the above copyright notice,
13b7579f77SDag-Erling Smørgrav  * this list of conditions and the following disclaimer.
14b7579f77SDag-Erling Smørgrav  *
15b7579f77SDag-Erling Smørgrav  * Redistributions in binary form must reproduce the above copyright notice,
16b7579f77SDag-Erling Smørgrav  * this list of conditions and the following disclaimer in the documentation
17b7579f77SDag-Erling Smørgrav  * and/or other materials provided with the distribution.
18b7579f77SDag-Erling Smørgrav  *
19b7579f77SDag-Erling Smørgrav  * Neither the name of the NLNET LABS nor the names of its contributors may
20b7579f77SDag-Erling Smørgrav  * be used to endorse or promote products derived from this software without
21b7579f77SDag-Erling Smørgrav  * specific prior written permission.
22b7579f77SDag-Erling Smørgrav  *
23b7579f77SDag-Erling Smørgrav  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2417d15b25SDag-Erling Smørgrav  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2517d15b25SDag-Erling Smørgrav  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
2617d15b25SDag-Erling Smørgrav  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2717d15b25SDag-Erling Smørgrav  * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2817d15b25SDag-Erling Smørgrav  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
2917d15b25SDag-Erling Smørgrav  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
3017d15b25SDag-Erling Smørgrav  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
3117d15b25SDag-Erling Smørgrav  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
3217d15b25SDag-Erling Smørgrav  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
3317d15b25SDag-Erling Smørgrav  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34b7579f77SDag-Erling Smørgrav  */
35b7579f77SDag-Erling Smørgrav 
36b7579f77SDag-Erling Smørgrav /**
37b7579f77SDag-Erling Smørgrav  * \file
38b7579f77SDag-Erling Smørgrav  *
39b7579f77SDag-Erling Smørgrav  * This file contains domain name handling functions.
40b7579f77SDag-Erling Smørgrav  */
41b7579f77SDag-Erling Smørgrav 
42b7579f77SDag-Erling Smørgrav #include "config.h"
43b7579f77SDag-Erling Smørgrav #include <ctype.h>
44b7579f77SDag-Erling Smørgrav #include "util/data/dname.h"
45b7579f77SDag-Erling Smørgrav #include "util/data/msgparse.h"
46b7579f77SDag-Erling Smørgrav #include "util/log.h"
47b7579f77SDag-Erling Smørgrav #include "util/storage/lookup3.h"
4809a3aaf3SDag-Erling Smørgrav #include "sldns/sbuffer.h"
49b7579f77SDag-Erling Smørgrav 
50b7579f77SDag-Erling Smørgrav /* determine length of a dname in buffer, no compression pointers allowed */
51b7579f77SDag-Erling Smørgrav size_t
5217d15b25SDag-Erling Smørgrav query_dname_len(sldns_buffer* query)
53b7579f77SDag-Erling Smørgrav {
54b7579f77SDag-Erling Smørgrav 	size_t len = 0;
55b7579f77SDag-Erling Smørgrav 	size_t labellen;
56b7579f77SDag-Erling Smørgrav 	while(1) {
5717d15b25SDag-Erling Smørgrav 		if(sldns_buffer_remaining(query) < 1)
58b7579f77SDag-Erling Smørgrav 			return 0; /* parse error, need label len */
5917d15b25SDag-Erling Smørgrav 		labellen = sldns_buffer_read_u8(query);
60b7579f77SDag-Erling Smørgrav 		if(labellen&0xc0)
61b7579f77SDag-Erling Smørgrav 			return 0; /* no compression allowed in queries */
62b7579f77SDag-Erling Smørgrav 		len += labellen + 1;
63b7579f77SDag-Erling Smørgrav 		if(len > LDNS_MAX_DOMAINLEN)
64b7579f77SDag-Erling Smørgrav 			return 0; /* too long */
65b7579f77SDag-Erling Smørgrav 		if(labellen == 0)
66b7579f77SDag-Erling Smørgrav 			return len;
6717d15b25SDag-Erling Smørgrav 		if(sldns_buffer_remaining(query) < labellen)
68b7579f77SDag-Erling Smørgrav 			return 0; /* parse error, need content */
6917d15b25SDag-Erling Smørgrav 		sldns_buffer_skip(query, (ssize_t)labellen);
70b7579f77SDag-Erling Smørgrav 	}
71b7579f77SDag-Erling Smørgrav }
72b7579f77SDag-Erling Smørgrav 
73b7579f77SDag-Erling Smørgrav size_t
74b7579f77SDag-Erling Smørgrav dname_valid(uint8_t* dname, size_t maxlen)
75b7579f77SDag-Erling Smørgrav {
76b7579f77SDag-Erling Smørgrav 	size_t len = 0;
77b7579f77SDag-Erling Smørgrav 	size_t labellen;
780eefd307SCy Schubert 	if(maxlen == 0)
790eefd307SCy Schubert 		return 0; /* too short, shortest is '0' root label */
80b7579f77SDag-Erling Smørgrav 	labellen = *dname++;
81b7579f77SDag-Erling Smørgrav 	while(labellen) {
82b7579f77SDag-Erling Smørgrav 		if(labellen&0xc0)
83b7579f77SDag-Erling Smørgrav 			return 0; /* no compression ptrs allowed */
84b7579f77SDag-Erling Smørgrav 		len += labellen + 1;
85b7579f77SDag-Erling Smørgrav 		if(len >= LDNS_MAX_DOMAINLEN)
86b7579f77SDag-Erling Smørgrav 			return 0; /* too long */
87b7579f77SDag-Erling Smørgrav 		if(len > maxlen)
88b7579f77SDag-Erling Smørgrav 			return 0; /* does not fit in memory allocation */
89b7579f77SDag-Erling Smørgrav 		dname += labellen;
90b7579f77SDag-Erling Smørgrav 		labellen = *dname++;
91b7579f77SDag-Erling Smørgrav 	}
92b7579f77SDag-Erling Smørgrav 	len += 1;
93b7579f77SDag-Erling Smørgrav 	if(len > maxlen)
94b7579f77SDag-Erling Smørgrav 		return 0; /* does not fit in memory allocation */
95b7579f77SDag-Erling Smørgrav 	return len;
96b7579f77SDag-Erling Smørgrav }
97b7579f77SDag-Erling Smørgrav 
98b7579f77SDag-Erling Smørgrav /** compare uncompressed, noncanonical, registers are hints for speed */
99b7579f77SDag-Erling Smørgrav int
100b7579f77SDag-Erling Smørgrav query_dname_compare(register uint8_t* d1, register uint8_t* d2)
101b7579f77SDag-Erling Smørgrav {
102b7579f77SDag-Erling Smørgrav 	register uint8_t lab1, lab2;
103b7579f77SDag-Erling Smørgrav 	log_assert(d1 && d2);
104b7579f77SDag-Erling Smørgrav 	lab1 = *d1++;
105b7579f77SDag-Erling Smørgrav 	lab2 = *d2++;
106b7579f77SDag-Erling Smørgrav 	while( lab1 != 0 || lab2 != 0 ) {
107b7579f77SDag-Erling Smørgrav 		/* compare label length */
108b7579f77SDag-Erling Smørgrav 		/* if one dname ends, it has labellength 0 */
109b7579f77SDag-Erling Smørgrav 		if(lab1 != lab2) {
110b7579f77SDag-Erling Smørgrav 			if(lab1 < lab2)
111b7579f77SDag-Erling Smørgrav 				return -1;
112b7579f77SDag-Erling Smørgrav 			return 1;
113b7579f77SDag-Erling Smørgrav 		}
114b7579f77SDag-Erling Smørgrav 		log_assert(lab1 == lab2 && lab1 != 0);
115b7579f77SDag-Erling Smørgrav 		/* compare lowercased labels. */
116b7579f77SDag-Erling Smørgrav 		while(lab1--) {
117b7579f77SDag-Erling Smørgrav 			/* compare bytes first for speed */
118b7579f77SDag-Erling Smørgrav 			if(*d1 != *d2 &&
119ff825849SDag-Erling Smørgrav 				tolower((unsigned char)*d1) != tolower((unsigned char)*d2)) {
120ff825849SDag-Erling Smørgrav 				if(tolower((unsigned char)*d1) < tolower((unsigned char)*d2))
121b7579f77SDag-Erling Smørgrav 					return -1;
122b7579f77SDag-Erling Smørgrav 				return 1;
123b7579f77SDag-Erling Smørgrav 			}
124b7579f77SDag-Erling Smørgrav 			d1++;
125b7579f77SDag-Erling Smørgrav 			d2++;
126b7579f77SDag-Erling Smørgrav 		}
127b7579f77SDag-Erling Smørgrav 		/* next pair of labels. */
128b7579f77SDag-Erling Smørgrav 		lab1 = *d1++;
129b7579f77SDag-Erling Smørgrav 		lab2 = *d2++;
130b7579f77SDag-Erling Smørgrav 	}
131b7579f77SDag-Erling Smørgrav 	return 0;
132b7579f77SDag-Erling Smørgrav }
133b7579f77SDag-Erling Smørgrav 
134b7579f77SDag-Erling Smørgrav void
135b7579f77SDag-Erling Smørgrav query_dname_tolower(uint8_t* dname)
136b7579f77SDag-Erling Smørgrav {
137b7579f77SDag-Erling Smørgrav 	/* the dname is stored uncompressed */
138b7579f77SDag-Erling Smørgrav 	uint8_t labellen;
139b7579f77SDag-Erling Smørgrav 	labellen = *dname;
140b7579f77SDag-Erling Smørgrav 	while(labellen) {
141b7579f77SDag-Erling Smørgrav 		dname++;
142b7579f77SDag-Erling Smørgrav 		while(labellen--) {
143ff825849SDag-Erling Smørgrav 			*dname = (uint8_t)tolower((unsigned char)*dname);
144b7579f77SDag-Erling Smørgrav 			dname++;
145b7579f77SDag-Erling Smørgrav 		}
146b7579f77SDag-Erling Smørgrav 		labellen = *dname;
147b7579f77SDag-Erling Smørgrav 	}
148b7579f77SDag-Erling Smørgrav }
149b7579f77SDag-Erling Smørgrav 
150b7579f77SDag-Erling Smørgrav void
15117d15b25SDag-Erling Smørgrav pkt_dname_tolower(sldns_buffer* pkt, uint8_t* dname)
152b7579f77SDag-Erling Smørgrav {
153b7579f77SDag-Erling Smørgrav 	uint8_t lablen;
154b7579f77SDag-Erling Smørgrav 	int count = 0;
15517d15b25SDag-Erling Smørgrav 	if(dname >= sldns_buffer_end(pkt))
156b7579f77SDag-Erling Smørgrav 		return;
157b7579f77SDag-Erling Smørgrav 	lablen = *dname++;
158b7579f77SDag-Erling Smørgrav 	while(lablen) {
159b7579f77SDag-Erling Smørgrav 		if(LABEL_IS_PTR(lablen)) {
160b7579f77SDag-Erling Smørgrav 			if((size_t)PTR_OFFSET(lablen, *dname)
16117d15b25SDag-Erling Smørgrav 				>= sldns_buffer_limit(pkt))
162b7579f77SDag-Erling Smørgrav 				return;
16317d15b25SDag-Erling Smørgrav 			dname = sldns_buffer_at(pkt, PTR_OFFSET(lablen, *dname));
164b7579f77SDag-Erling Smørgrav 			lablen = *dname++;
165b7579f77SDag-Erling Smørgrav 			if(count++ > MAX_COMPRESS_PTRS)
166b7579f77SDag-Erling Smørgrav 				return;
167b7579f77SDag-Erling Smørgrav 			continue;
168b7579f77SDag-Erling Smørgrav 		}
16917d15b25SDag-Erling Smørgrav 		if(dname+lablen >= sldns_buffer_end(pkt))
170b7579f77SDag-Erling Smørgrav 			return;
171b7579f77SDag-Erling Smørgrav 		while(lablen--) {
172ff825849SDag-Erling Smørgrav 			*dname = (uint8_t)tolower((unsigned char)*dname);
173b7579f77SDag-Erling Smørgrav 			dname++;
174b7579f77SDag-Erling Smørgrav 		}
17517d15b25SDag-Erling Smørgrav 		if(dname >= sldns_buffer_end(pkt))
176b7579f77SDag-Erling Smørgrav 			return;
177b7579f77SDag-Erling Smørgrav 		lablen = *dname++;
178b7579f77SDag-Erling Smørgrav 	}
179b7579f77SDag-Erling Smørgrav }
180b7579f77SDag-Erling Smørgrav 
181b7579f77SDag-Erling Smørgrav 
182b7579f77SDag-Erling Smørgrav size_t
18317d15b25SDag-Erling Smørgrav pkt_dname_len(sldns_buffer* pkt)
184b7579f77SDag-Erling Smørgrav {
185b7579f77SDag-Erling Smørgrav 	size_t len = 0;
186b7579f77SDag-Erling Smørgrav 	int ptrcount = 0;
187b7579f77SDag-Erling Smørgrav 	uint8_t labellen;
188b7579f77SDag-Erling Smørgrav 	size_t endpos = 0;
189b7579f77SDag-Erling Smørgrav 
190b7579f77SDag-Erling Smørgrav 	/* read dname and determine length */
191b7579f77SDag-Erling Smørgrav 	/* check compression pointers, loops, out of bounds */
192b7579f77SDag-Erling Smørgrav 	while(1) {
193b7579f77SDag-Erling Smørgrav 		/* read next label */
19417d15b25SDag-Erling Smørgrav 		if(sldns_buffer_remaining(pkt) < 1)
195b7579f77SDag-Erling Smørgrav 			return 0;
19617d15b25SDag-Erling Smørgrav 		labellen = sldns_buffer_read_u8(pkt);
197b7579f77SDag-Erling Smørgrav 		if(LABEL_IS_PTR(labellen)) {
198b7579f77SDag-Erling Smørgrav 			/* compression ptr */
199b7579f77SDag-Erling Smørgrav 			uint16_t ptr;
20017d15b25SDag-Erling Smørgrav 			if(sldns_buffer_remaining(pkt) < 1)
201b7579f77SDag-Erling Smørgrav 				return 0;
20217d15b25SDag-Erling Smørgrav 			ptr = PTR_OFFSET(labellen, sldns_buffer_read_u8(pkt));
203b7579f77SDag-Erling Smørgrav 			if(ptrcount++ > MAX_COMPRESS_PTRS)
204b7579f77SDag-Erling Smørgrav 				return 0; /* loop! */
20517d15b25SDag-Erling Smørgrav 			if(sldns_buffer_limit(pkt) <= ptr)
206b7579f77SDag-Erling Smørgrav 				return 0; /* out of bounds! */
207b7579f77SDag-Erling Smørgrav 			if(!endpos)
20817d15b25SDag-Erling Smørgrav 				endpos = sldns_buffer_position(pkt);
20917d15b25SDag-Erling Smørgrav 			sldns_buffer_set_position(pkt, ptr);
210b7579f77SDag-Erling Smørgrav 		} else {
211b7579f77SDag-Erling Smørgrav 			/* label contents */
212b7579f77SDag-Erling Smørgrav 			if(labellen > 0x3f)
213b7579f77SDag-Erling Smørgrav 				return 0; /* label too long */
214b7579f77SDag-Erling Smørgrav 			len += 1 + labellen;
215b7579f77SDag-Erling Smørgrav 			if(len > LDNS_MAX_DOMAINLEN)
216b7579f77SDag-Erling Smørgrav 				return 0;
217b7579f77SDag-Erling Smørgrav 			if(labellen == 0) {
218b7579f77SDag-Erling Smørgrav 				/* end of dname */
219b7579f77SDag-Erling Smørgrav 				break;
220b7579f77SDag-Erling Smørgrav 			}
22117d15b25SDag-Erling Smørgrav 			if(sldns_buffer_remaining(pkt) < labellen)
222b7579f77SDag-Erling Smørgrav 				return 0;
22317d15b25SDag-Erling Smørgrav 			sldns_buffer_skip(pkt, (ssize_t)labellen);
224b7579f77SDag-Erling Smørgrav 		}
225b7579f77SDag-Erling Smørgrav 	}
226b7579f77SDag-Erling Smørgrav 	if(endpos)
22717d15b25SDag-Erling Smørgrav 		sldns_buffer_set_position(pkt, endpos);
228b7579f77SDag-Erling Smørgrav 
229b7579f77SDag-Erling Smørgrav 	return len;
230b7579f77SDag-Erling Smørgrav }
231b7579f77SDag-Erling Smørgrav 
232b7579f77SDag-Erling Smørgrav int
23317d15b25SDag-Erling Smørgrav dname_pkt_compare(sldns_buffer* pkt, uint8_t* d1, uint8_t* d2)
234b7579f77SDag-Erling Smørgrav {
235b7579f77SDag-Erling Smørgrav 	uint8_t len1, len2;
236091e9e46SCy Schubert 	int count1 = 0, count2 = 0;
237b7579f77SDag-Erling Smørgrav 	log_assert(pkt && d1 && d2);
238b7579f77SDag-Erling Smørgrav 	len1 = *d1++;
239b7579f77SDag-Erling Smørgrav 	len2 = *d2++;
240b7579f77SDag-Erling Smørgrav 	while( len1 != 0 || len2 != 0 ) {
241b7579f77SDag-Erling Smørgrav 		/* resolve ptrs */
242b7579f77SDag-Erling Smørgrav 		if(LABEL_IS_PTR(len1)) {
243091e9e46SCy Schubert 			if((size_t)PTR_OFFSET(len1, *d1)
244091e9e46SCy Schubert 				>= sldns_buffer_limit(pkt))
245091e9e46SCy Schubert 				return -1;
246091e9e46SCy Schubert 			if(count1++ > MAX_COMPRESS_PTRS)
247091e9e46SCy Schubert 				return -1;
24817d15b25SDag-Erling Smørgrav 			d1 = sldns_buffer_at(pkt, PTR_OFFSET(len1, *d1));
249b7579f77SDag-Erling Smørgrav 			len1 = *d1++;
250b7579f77SDag-Erling Smørgrav 			continue;
251b7579f77SDag-Erling Smørgrav 		}
252b7579f77SDag-Erling Smørgrav 		if(LABEL_IS_PTR(len2)) {
253091e9e46SCy Schubert 			if((size_t)PTR_OFFSET(len2, *d2)
254091e9e46SCy Schubert 				>= sldns_buffer_limit(pkt))
255091e9e46SCy Schubert 				return 1;
256091e9e46SCy Schubert 			if(count2++ > MAX_COMPRESS_PTRS)
257091e9e46SCy Schubert 				return 1;
25817d15b25SDag-Erling Smørgrav 			d2 = sldns_buffer_at(pkt, PTR_OFFSET(len2, *d2));
259b7579f77SDag-Erling Smørgrav 			len2 = *d2++;
260b7579f77SDag-Erling Smørgrav 			continue;
261b7579f77SDag-Erling Smørgrav 		}
262b7579f77SDag-Erling Smørgrav 		/* check label length */
263b7579f77SDag-Erling Smørgrav 		log_assert(len1 <= LDNS_MAX_LABELLEN);
264b7579f77SDag-Erling Smørgrav 		log_assert(len2 <= LDNS_MAX_LABELLEN);
265b7579f77SDag-Erling Smørgrav 		if(len1 != len2) {
266b7579f77SDag-Erling Smørgrav 			if(len1 < len2) return -1;
267b7579f77SDag-Erling Smørgrav 			return 1;
268b7579f77SDag-Erling Smørgrav 		}
269b7579f77SDag-Erling Smørgrav 		log_assert(len1 == len2 && len1 != 0);
270b7579f77SDag-Erling Smørgrav 		/* compare labels */
271b7579f77SDag-Erling Smørgrav 		while(len1--) {
272e2d15004SDag-Erling Smørgrav 			if(tolower((unsigned char)*d1) != tolower((unsigned char)*d2)) {
273e2d15004SDag-Erling Smørgrav 				if(tolower((unsigned char)*d1) < tolower((unsigned char)*d2))
274b7579f77SDag-Erling Smørgrav 					return -1;
275b7579f77SDag-Erling Smørgrav 				return 1;
276b7579f77SDag-Erling Smørgrav 			}
277e2d15004SDag-Erling Smørgrav 			d1++;
278e2d15004SDag-Erling Smørgrav 			d2++;
279b7579f77SDag-Erling Smørgrav 		}
280b7579f77SDag-Erling Smørgrav 		len1 = *d1++;
281b7579f77SDag-Erling Smørgrav 		len2 = *d2++;
282b7579f77SDag-Erling Smørgrav 	}
283b7579f77SDag-Erling Smørgrav 	return 0;
284b7579f77SDag-Erling Smørgrav }
285b7579f77SDag-Erling Smørgrav 
2863005e0a3SDag-Erling Smørgrav hashvalue_type
2873005e0a3SDag-Erling Smørgrav dname_query_hash(uint8_t* dname, hashvalue_type h)
288b7579f77SDag-Erling Smørgrav {
289b7579f77SDag-Erling Smørgrav 	uint8_t labuf[LDNS_MAX_LABELLEN+1];
290b7579f77SDag-Erling Smørgrav 	uint8_t lablen;
291b7579f77SDag-Erling Smørgrav 	int i;
292b7579f77SDag-Erling Smørgrav 
293b7579f77SDag-Erling Smørgrav 	/* preserve case of query, make hash label by label */
294b7579f77SDag-Erling Smørgrav 	lablen = *dname++;
295b7579f77SDag-Erling Smørgrav 	while(lablen) {
296b7579f77SDag-Erling Smørgrav 		log_assert(lablen <= LDNS_MAX_LABELLEN);
297b7579f77SDag-Erling Smørgrav 		labuf[0] = lablen;
298b7579f77SDag-Erling Smørgrav 		i=0;
299e2d15004SDag-Erling Smørgrav 		while(lablen--) {
300e2d15004SDag-Erling Smørgrav 			labuf[++i] = (uint8_t)tolower((unsigned char)*dname);
301e2d15004SDag-Erling Smørgrav 			dname++;
302e2d15004SDag-Erling Smørgrav 		}
303b7579f77SDag-Erling Smørgrav 		h = hashlittle(labuf, labuf[0] + 1, h);
304b7579f77SDag-Erling Smørgrav 		lablen = *dname++;
305b7579f77SDag-Erling Smørgrav 	}
306b7579f77SDag-Erling Smørgrav 
307b7579f77SDag-Erling Smørgrav 	return h;
308b7579f77SDag-Erling Smørgrav }
309b7579f77SDag-Erling Smørgrav 
3103005e0a3SDag-Erling Smørgrav hashvalue_type
3113005e0a3SDag-Erling Smørgrav dname_pkt_hash(sldns_buffer* pkt, uint8_t* dname, hashvalue_type h)
312b7579f77SDag-Erling Smørgrav {
313b7579f77SDag-Erling Smørgrav 	uint8_t labuf[LDNS_MAX_LABELLEN+1];
314b7579f77SDag-Erling Smørgrav 	uint8_t lablen;
315b7579f77SDag-Erling Smørgrav 	int i;
316091e9e46SCy Schubert 	int count = 0;
317b7579f77SDag-Erling Smørgrav 
318b7579f77SDag-Erling Smørgrav 	/* preserve case of query, make hash label by label */
319b7579f77SDag-Erling Smørgrav 	lablen = *dname++;
320b7579f77SDag-Erling Smørgrav 	while(lablen) {
321b7579f77SDag-Erling Smørgrav 		if(LABEL_IS_PTR(lablen)) {
322b7579f77SDag-Erling Smørgrav 			/* follow pointer */
323091e9e46SCy Schubert 			if((size_t)PTR_OFFSET(lablen, *dname)
324091e9e46SCy Schubert 				>= sldns_buffer_limit(pkt))
325091e9e46SCy Schubert 				return h;
326091e9e46SCy Schubert 			if(count++ > MAX_COMPRESS_PTRS)
327091e9e46SCy Schubert 				return h;
32817d15b25SDag-Erling Smørgrav 			dname = sldns_buffer_at(pkt, PTR_OFFSET(lablen, *dname));
329b7579f77SDag-Erling Smørgrav 			lablen = *dname++;
330b7579f77SDag-Erling Smørgrav 			continue;
331b7579f77SDag-Erling Smørgrav 		}
332b7579f77SDag-Erling Smørgrav 		log_assert(lablen <= LDNS_MAX_LABELLEN);
333b7579f77SDag-Erling Smørgrav 		labuf[0] = lablen;
334b7579f77SDag-Erling Smørgrav 		i=0;
335e2d15004SDag-Erling Smørgrav 		while(lablen--) {
336e2d15004SDag-Erling Smørgrav 			labuf[++i] = (uint8_t)tolower((unsigned char)*dname);
337e2d15004SDag-Erling Smørgrav 			dname++;
338e2d15004SDag-Erling Smørgrav 		}
339b7579f77SDag-Erling Smørgrav 		h = hashlittle(labuf, labuf[0] + 1, h);
340b7579f77SDag-Erling Smørgrav 		lablen = *dname++;
341b7579f77SDag-Erling Smørgrav 	}
342b7579f77SDag-Erling Smørgrav 
343b7579f77SDag-Erling Smørgrav 	return h;
344b7579f77SDag-Erling Smørgrav }
345b7579f77SDag-Erling Smørgrav 
34617d15b25SDag-Erling Smørgrav void dname_pkt_copy(sldns_buffer* pkt, uint8_t* to, uint8_t* dname)
347b7579f77SDag-Erling Smørgrav {
348b7579f77SDag-Erling Smørgrav 	/* copy over the dname and decompress it at the same time */
3490eefd307SCy Schubert 	size_t comprcount = 0;
350b7579f77SDag-Erling Smørgrav 	size_t len = 0;
351b7579f77SDag-Erling Smørgrav 	uint8_t lablen;
352b7579f77SDag-Erling Smørgrav 	lablen = *dname++;
353b7579f77SDag-Erling Smørgrav 	while(lablen) {
354b7579f77SDag-Erling Smørgrav 		if(LABEL_IS_PTR(lablen)) {
3550eefd307SCy Schubert 			if(comprcount++ > MAX_COMPRESS_PTRS) {
3560eefd307SCy Schubert 				/* too many compression pointers */
3570eefd307SCy Schubert 				*to = 0; /* end the result prematurely */
3580eefd307SCy Schubert 				return;
3590eefd307SCy Schubert 			}
360b7579f77SDag-Erling Smørgrav 			/* follow pointer */
361091e9e46SCy Schubert 			if((size_t)PTR_OFFSET(lablen, *dname)
362091e9e46SCy Schubert 				>= sldns_buffer_limit(pkt))
363091e9e46SCy Schubert 				return;
36417d15b25SDag-Erling Smørgrav 			dname = sldns_buffer_at(pkt, PTR_OFFSET(lablen, *dname));
365b7579f77SDag-Erling Smørgrav 			lablen = *dname++;
366b7579f77SDag-Erling Smørgrav 			continue;
367b7579f77SDag-Erling Smørgrav 		}
3680eefd307SCy Schubert 		if(lablen > LDNS_MAX_LABELLEN) {
3690eefd307SCy Schubert 			*to = 0; /* end the result prematurely */
3700eefd307SCy Schubert 			return;
3710eefd307SCy Schubert 		}
372b7579f77SDag-Erling Smørgrav 		log_assert(lablen <= LDNS_MAX_LABELLEN);
373b7579f77SDag-Erling Smørgrav 		len += (size_t)lablen+1;
374b7579f77SDag-Erling Smørgrav 		if(len >= LDNS_MAX_DOMAINLEN) {
375b7579f77SDag-Erling Smørgrav 			*to = 0; /* end the result prematurely */
376b7579f77SDag-Erling Smørgrav 			log_err("bad dname in dname_pkt_copy");
377b7579f77SDag-Erling Smørgrav 			return;
378b7579f77SDag-Erling Smørgrav 		}
379b7579f77SDag-Erling Smørgrav 		*to++ = lablen;
380b7579f77SDag-Erling Smørgrav 		memmove(to, dname, lablen);
381b7579f77SDag-Erling Smørgrav 		dname += lablen;
382b7579f77SDag-Erling Smørgrav 		to += lablen;
383b7579f77SDag-Erling Smørgrav 		lablen = *dname++;
384b7579f77SDag-Erling Smørgrav 	}
385b7579f77SDag-Erling Smørgrav 	/* copy last \0 */
386b7579f77SDag-Erling Smørgrav 	*to = 0;
387b7579f77SDag-Erling Smørgrav }
388b7579f77SDag-Erling Smørgrav 
38917d15b25SDag-Erling Smørgrav void dname_print(FILE* out, struct sldns_buffer* pkt, uint8_t* dname)
390b7579f77SDag-Erling Smørgrav {
391b7579f77SDag-Erling Smørgrav 	uint8_t lablen;
392091e9e46SCy Schubert 	int count = 0;
393b7579f77SDag-Erling Smørgrav 	if(!out) out = stdout;
394b7579f77SDag-Erling Smørgrav 	if(!dname) return;
395b7579f77SDag-Erling Smørgrav 
396b7579f77SDag-Erling Smørgrav 	lablen = *dname++;
397b7579f77SDag-Erling Smørgrav 	if(!lablen)
398b7579f77SDag-Erling Smørgrav 		fputc('.', out);
399b7579f77SDag-Erling Smørgrav 	while(lablen) {
400b7579f77SDag-Erling Smørgrav 		if(LABEL_IS_PTR(lablen)) {
401b7579f77SDag-Erling Smørgrav 			/* follow pointer */
402b7579f77SDag-Erling Smørgrav 			if(!pkt) {
403b7579f77SDag-Erling Smørgrav 				fputs("??compressionptr??", out);
404b7579f77SDag-Erling Smørgrav 				return;
405b7579f77SDag-Erling Smørgrav 			}
406091e9e46SCy Schubert 			if((size_t)PTR_OFFSET(lablen, *dname)
407091e9e46SCy Schubert 				>= sldns_buffer_limit(pkt)) {
408091e9e46SCy Schubert 				fputs("??compressionptr??", out);
409091e9e46SCy Schubert 				return;
410091e9e46SCy Schubert 			}
411091e9e46SCy Schubert 			if(count++ > MAX_COMPRESS_PTRS) {
412091e9e46SCy Schubert 				fputs("??compressionptr??", out);
413091e9e46SCy Schubert 				return;
414091e9e46SCy Schubert 			}
41517d15b25SDag-Erling Smørgrav 			dname = sldns_buffer_at(pkt, PTR_OFFSET(lablen, *dname));
416b7579f77SDag-Erling Smørgrav 			lablen = *dname++;
417b7579f77SDag-Erling Smørgrav 			continue;
418b7579f77SDag-Erling Smørgrav 		}
419b7579f77SDag-Erling Smørgrav 		if(lablen > LDNS_MAX_LABELLEN) {
420b7579f77SDag-Erling Smørgrav 			fputs("??extendedlabel??", out);
421b7579f77SDag-Erling Smørgrav 			return;
422b7579f77SDag-Erling Smørgrav 		}
423b7579f77SDag-Erling Smørgrav 		while(lablen--)
424b7579f77SDag-Erling Smørgrav 			fputc((int)*dname++, out);
425b7579f77SDag-Erling Smørgrav 		fputc('.', out);
426b7579f77SDag-Erling Smørgrav 		lablen = *dname++;
427b7579f77SDag-Erling Smørgrav 	}
428b7579f77SDag-Erling Smørgrav }
429b7579f77SDag-Erling Smørgrav 
430b7579f77SDag-Erling Smørgrav int
431b7579f77SDag-Erling Smørgrav dname_count_labels(uint8_t* dname)
432b7579f77SDag-Erling Smørgrav {
433b7579f77SDag-Erling Smørgrav 	uint8_t lablen;
434b7579f77SDag-Erling Smørgrav 	int labs = 1;
435b7579f77SDag-Erling Smørgrav 
436b7579f77SDag-Erling Smørgrav 	lablen = *dname++;
437b7579f77SDag-Erling Smørgrav 	while(lablen) {
438b7579f77SDag-Erling Smørgrav 		labs++;
439b7579f77SDag-Erling Smørgrav 		dname += lablen;
440b7579f77SDag-Erling Smørgrav 		lablen = *dname++;
441b7579f77SDag-Erling Smørgrav 	}
442b7579f77SDag-Erling Smørgrav 	return labs;
443b7579f77SDag-Erling Smørgrav }
444b7579f77SDag-Erling Smørgrav 
445b7579f77SDag-Erling Smørgrav int
446b7579f77SDag-Erling Smørgrav dname_count_size_labels(uint8_t* dname, size_t* size)
447b7579f77SDag-Erling Smørgrav {
448b7579f77SDag-Erling Smørgrav 	uint8_t lablen;
449b7579f77SDag-Erling Smørgrav 	int labs = 1;
450b7579f77SDag-Erling Smørgrav 	size_t sz = 1;
451b7579f77SDag-Erling Smørgrav 
452b7579f77SDag-Erling Smørgrav 	lablen = *dname++;
453b7579f77SDag-Erling Smørgrav 	while(lablen) {
454b7579f77SDag-Erling Smørgrav 		labs++;
455b7579f77SDag-Erling Smørgrav 		sz += lablen+1;
456b7579f77SDag-Erling Smørgrav 		dname += lablen;
457b7579f77SDag-Erling Smørgrav 		lablen = *dname++;
458b7579f77SDag-Erling Smørgrav 	}
459b7579f77SDag-Erling Smørgrav 	*size = sz;
460b7579f77SDag-Erling Smørgrav 	return labs;
461b7579f77SDag-Erling Smørgrav }
462b7579f77SDag-Erling Smørgrav 
463b7579f77SDag-Erling Smørgrav /**
464b7579f77SDag-Erling Smørgrav  * Compare labels in memory, lowercase while comparing.
465b7579f77SDag-Erling Smørgrav  * @param p1: label 1
466b7579f77SDag-Erling Smørgrav  * @param p2: label 2
467b7579f77SDag-Erling Smørgrav  * @param len: number of bytes to compare.
468b7579f77SDag-Erling Smørgrav  * @return: 0, -1, +1 comparison result.
469b7579f77SDag-Erling Smørgrav  */
470b7579f77SDag-Erling Smørgrav static int
471b7579f77SDag-Erling Smørgrav memlowercmp(uint8_t* p1, uint8_t* p2, uint8_t len)
472b7579f77SDag-Erling Smørgrav {
473b7579f77SDag-Erling Smørgrav 	while(len--) {
474ff825849SDag-Erling Smørgrav 		if(*p1 != *p2 && tolower((unsigned char)*p1) != tolower((unsigned char)*p2)) {
475ff825849SDag-Erling Smørgrav 			if(tolower((unsigned char)*p1) < tolower((unsigned char)*p2))
476b7579f77SDag-Erling Smørgrav 				return -1;
477b7579f77SDag-Erling Smørgrav 			return 1;
478b7579f77SDag-Erling Smørgrav 		}
479b7579f77SDag-Erling Smørgrav 		p1++;
480b7579f77SDag-Erling Smørgrav 		p2++;
481b7579f77SDag-Erling Smørgrav 	}
482b7579f77SDag-Erling Smørgrav 	return 0;
483b7579f77SDag-Erling Smørgrav }
484b7579f77SDag-Erling Smørgrav 
485b7579f77SDag-Erling Smørgrav int
486b7579f77SDag-Erling Smørgrav dname_lab_cmp(uint8_t* d1, int labs1, uint8_t* d2, int labs2, int* mlabs)
487b7579f77SDag-Erling Smørgrav {
488b7579f77SDag-Erling Smørgrav 	uint8_t len1, len2;
489b7579f77SDag-Erling Smørgrav 	int atlabel = labs1;
490b7579f77SDag-Erling Smørgrav 	int lastmlabs;
491b7579f77SDag-Erling Smørgrav 	int lastdiff = 0;
492b7579f77SDag-Erling Smørgrav 	/* first skip so that we compare same label. */
493b7579f77SDag-Erling Smørgrav 	if(labs1 > labs2) {
494b7579f77SDag-Erling Smørgrav 		while(atlabel > labs2) {
495b7579f77SDag-Erling Smørgrav 			len1 = *d1++;
496b7579f77SDag-Erling Smørgrav 			d1 += len1;
497b7579f77SDag-Erling Smørgrav 			atlabel--;
498b7579f77SDag-Erling Smørgrav 		}
499b7579f77SDag-Erling Smørgrav 		log_assert(atlabel == labs2);
500b7579f77SDag-Erling Smørgrav 	} else if(labs1 < labs2) {
501b7579f77SDag-Erling Smørgrav 		atlabel = labs2;
502b7579f77SDag-Erling Smørgrav 		while(atlabel > labs1) {
503b7579f77SDag-Erling Smørgrav 			len2 = *d2++;
504b7579f77SDag-Erling Smørgrav 			d2 += len2;
505b7579f77SDag-Erling Smørgrav 			atlabel--;
506b7579f77SDag-Erling Smørgrav 		}
507b7579f77SDag-Erling Smørgrav 		log_assert(atlabel == labs1);
508b7579f77SDag-Erling Smørgrav 	}
509b7579f77SDag-Erling Smørgrav 	lastmlabs = atlabel+1;
510b7579f77SDag-Erling Smørgrav 	/* now at same label in d1 and d2, atlabel */
511b7579f77SDag-Erling Smørgrav 	/* www.example.com.                  */
512b7579f77SDag-Erling Smørgrav 	/* 4   3       2  1   atlabel number */
513b7579f77SDag-Erling Smørgrav 	/* repeat until at root label (which is always the same) */
514b7579f77SDag-Erling Smørgrav 	while(atlabel > 1) {
515b7579f77SDag-Erling Smørgrav 		len1 = *d1++;
516b7579f77SDag-Erling Smørgrav 		len2 = *d2++;
517b7579f77SDag-Erling Smørgrav 		if(len1 != len2) {
518b7579f77SDag-Erling Smørgrav 			log_assert(len1 != 0 && len2 != 0);
519b7579f77SDag-Erling Smørgrav 			if(len1<len2)
520b7579f77SDag-Erling Smørgrav 				lastdiff = -1;
521b7579f77SDag-Erling Smørgrav 			else	lastdiff = 1;
522b7579f77SDag-Erling Smørgrav 			lastmlabs = atlabel;
523b7579f77SDag-Erling Smørgrav 			d1 += len1;
524b7579f77SDag-Erling Smørgrav 			d2 += len2;
525b7579f77SDag-Erling Smørgrav 		} else {
526b7579f77SDag-Erling Smørgrav 			/* memlowercmp is inlined here; or just like
527b7579f77SDag-Erling Smørgrav 			 * if((c=memlowercmp(d1, d2, len1)) != 0) {
528b7579f77SDag-Erling Smørgrav 			 *	lastdiff = c;
529b7579f77SDag-Erling Smørgrav 			 *	lastmlabs = atlabel; } apart from d1++,d2++ */
530b7579f77SDag-Erling Smørgrav 			while(len1) {
531ff825849SDag-Erling Smørgrav 				if(*d1 != *d2 && tolower((unsigned char)*d1)
532ff825849SDag-Erling Smørgrav 					!= tolower((unsigned char)*d2)) {
533ff825849SDag-Erling Smørgrav 					if(tolower((unsigned char)*d1) <
534ff825849SDag-Erling Smørgrav 						tolower((unsigned char)*d2)) {
535b7579f77SDag-Erling Smørgrav 						lastdiff = -1;
536b7579f77SDag-Erling Smørgrav 						lastmlabs = atlabel;
537b7579f77SDag-Erling Smørgrav 						d1 += len1;
538b7579f77SDag-Erling Smørgrav 						d2 += len1;
539b7579f77SDag-Erling Smørgrav 						break;
540b7579f77SDag-Erling Smørgrav 					}
541b7579f77SDag-Erling Smørgrav 					lastdiff = 1;
542b7579f77SDag-Erling Smørgrav 					lastmlabs = atlabel;
543b7579f77SDag-Erling Smørgrav 					d1 += len1;
544b7579f77SDag-Erling Smørgrav 					d2 += len1;
545b7579f77SDag-Erling Smørgrav 					break; /* out of memlowercmp */
546b7579f77SDag-Erling Smørgrav 				}
547b7579f77SDag-Erling Smørgrav 				d1++;
548b7579f77SDag-Erling Smørgrav 				d2++;
549b7579f77SDag-Erling Smørgrav 				len1--;
550b7579f77SDag-Erling Smørgrav 			}
551b7579f77SDag-Erling Smørgrav 		}
552b7579f77SDag-Erling Smørgrav 		atlabel--;
553b7579f77SDag-Erling Smørgrav 	}
554b7579f77SDag-Erling Smørgrav 	/* last difference atlabel number, so number of labels matching,
555b7579f77SDag-Erling Smørgrav 	 * at the right side, is one less. */
556b7579f77SDag-Erling Smørgrav 	*mlabs = lastmlabs-1;
557b7579f77SDag-Erling Smørgrav 	if(lastdiff == 0) {
558b7579f77SDag-Erling Smørgrav 		/* all labels compared were equal, check if one has more
559b7579f77SDag-Erling Smørgrav 		 * labels, so that example.com. > com. */
560b7579f77SDag-Erling Smørgrav 		if(labs1 > labs2)
561b7579f77SDag-Erling Smørgrav 			return 1;
562b7579f77SDag-Erling Smørgrav 		else if(labs1 < labs2)
563b7579f77SDag-Erling Smørgrav 			return -1;
564b7579f77SDag-Erling Smørgrav 	}
565b7579f77SDag-Erling Smørgrav 	return lastdiff;
566b7579f77SDag-Erling Smørgrav }
567b7579f77SDag-Erling Smørgrav 
568b7579f77SDag-Erling Smørgrav int
5690fb34990SDag-Erling Smørgrav dname_lab_startswith(uint8_t* label, char* prefix, char** endptr)
5700fb34990SDag-Erling Smørgrav {
5710fb34990SDag-Erling Smørgrav 	size_t plen = strlen(prefix);
5720fb34990SDag-Erling Smørgrav 	size_t orig_plen = plen;
5730fb34990SDag-Erling Smørgrav 	size_t lablen = (size_t)*label;
5740fb34990SDag-Erling Smørgrav 	if(plen > lablen)
5750fb34990SDag-Erling Smørgrav 		return 0;
5760fb34990SDag-Erling Smørgrav 	label++;
5770fb34990SDag-Erling Smørgrav 	while(plen--) {
5780fb34990SDag-Erling Smørgrav 		if(*prefix != tolower((unsigned char)*label)) {
5790fb34990SDag-Erling Smørgrav 			return 0;
5800fb34990SDag-Erling Smørgrav 		}
5810fb34990SDag-Erling Smørgrav 		prefix++; label++;
5820fb34990SDag-Erling Smørgrav 	}
5830fb34990SDag-Erling Smørgrav 	if(orig_plen < lablen)
5840fb34990SDag-Erling Smørgrav 		*endptr = (char *)label;
5850fb34990SDag-Erling Smørgrav 	else
5860fb34990SDag-Erling Smørgrav 		/* prefix length == label length */
5870fb34990SDag-Erling Smørgrav 		*endptr = NULL;
5880fb34990SDag-Erling Smørgrav 	return 1;
5890fb34990SDag-Erling Smørgrav }
5900fb34990SDag-Erling Smørgrav 
5910fb34990SDag-Erling Smørgrav int
592091e9e46SCy Schubert dname_has_label(uint8_t* dname, size_t dnamelen, uint8_t* label)
593091e9e46SCy Schubert {
594091e9e46SCy Schubert 	size_t len;
595091e9e46SCy Schubert 
596091e9e46SCy Schubert 	/* 1 byte needed for the label length */
597091e9e46SCy Schubert 	if(dnamelen < 1)
598091e9e46SCy Schubert 		return 0;
599091e9e46SCy Schubert 
600091e9e46SCy Schubert 	len = *dname;
601091e9e46SCy Schubert 	while(len <= dnamelen) {
602091e9e46SCy Schubert 		if(!(*dname)) {
603091e9e46SCy Schubert 			if(*dname == *label)
604091e9e46SCy Schubert 				return 1; /* empty label match */
605091e9e46SCy Schubert 			/* termination label found, stop iterating */
606091e9e46SCy Schubert 			return 0;
607091e9e46SCy Schubert 		}
608091e9e46SCy Schubert 		if(*dname == *label && *label &&
609091e9e46SCy Schubert 			memlowercmp(dname+1, label+1, *dname) == 0)
610091e9e46SCy Schubert 			return 1;
611091e9e46SCy Schubert 		len += *dname;
612091e9e46SCy Schubert 		dname += *dname;
613091e9e46SCy Schubert 		dname++;
614091e9e46SCy Schubert 		len++;
615091e9e46SCy Schubert 	}
616091e9e46SCy Schubert 	return 0;
617091e9e46SCy Schubert }
618091e9e46SCy Schubert 
619091e9e46SCy Schubert int
62017d15b25SDag-Erling Smørgrav dname_buffer_write(sldns_buffer* pkt, uint8_t* dname)
621b7579f77SDag-Erling Smørgrav {
622b7579f77SDag-Erling Smørgrav 	uint8_t lablen;
623b7579f77SDag-Erling Smørgrav 
62417d15b25SDag-Erling Smørgrav 	if(sldns_buffer_remaining(pkt) < 1)
625b7579f77SDag-Erling Smørgrav 		return 0;
626b7579f77SDag-Erling Smørgrav 	lablen = *dname++;
62717d15b25SDag-Erling Smørgrav 	sldns_buffer_write_u8(pkt, lablen);
628b7579f77SDag-Erling Smørgrav 	while(lablen) {
62917d15b25SDag-Erling Smørgrav 		if(sldns_buffer_remaining(pkt) < (size_t)lablen+1)
630b7579f77SDag-Erling Smørgrav 			return 0;
63117d15b25SDag-Erling Smørgrav 		sldns_buffer_write(pkt, dname, lablen);
632b7579f77SDag-Erling Smørgrav 		dname += lablen;
633b7579f77SDag-Erling Smørgrav 		lablen = *dname++;
63417d15b25SDag-Erling Smørgrav 		sldns_buffer_write_u8(pkt, lablen);
635b7579f77SDag-Erling Smørgrav 	}
636b7579f77SDag-Erling Smørgrav 	return 1;
637b7579f77SDag-Erling Smørgrav }
638b7579f77SDag-Erling Smørgrav 
639b7579f77SDag-Erling Smørgrav void dname_str(uint8_t* dname, char* str)
640b7579f77SDag-Erling Smørgrav {
641b7579f77SDag-Erling Smørgrav 	size_t len = 0;
642b7579f77SDag-Erling Smørgrav 	uint8_t lablen = 0;
643b7579f77SDag-Erling Smørgrav 	char* s = str;
644b7579f77SDag-Erling Smørgrav 	if(!dname || !*dname) {
645b7579f77SDag-Erling Smørgrav 		*s++ = '.';
646b7579f77SDag-Erling Smørgrav 		*s = 0;
647*be771a7bSCy Schubert 		goto out;
648b7579f77SDag-Erling Smørgrav 	}
649b7579f77SDag-Erling Smørgrav 	lablen = *dname++;
650b7579f77SDag-Erling Smørgrav 	while(lablen) {
651b7579f77SDag-Erling Smørgrav 		if(lablen > LDNS_MAX_LABELLEN) {
652b7579f77SDag-Erling Smørgrav 			*s++ = '#';
653b7579f77SDag-Erling Smørgrav 			*s = 0;
654*be771a7bSCy Schubert 			goto out;
655b7579f77SDag-Erling Smørgrav 		}
656b7579f77SDag-Erling Smørgrav 		len += lablen+1;
657*be771a7bSCy Schubert 		if(len >= LDNS_MAX_DOMAINLEN) {
658b7579f77SDag-Erling Smørgrav 			*s++ = '&';
659b7579f77SDag-Erling Smørgrav 			*s = 0;
660*be771a7bSCy Schubert 			goto out;
661b7579f77SDag-Erling Smørgrav 		}
662b7579f77SDag-Erling Smørgrav 		while(lablen--) {
663ff825849SDag-Erling Smørgrav 			if(isalnum((unsigned char)*dname)
664b7579f77SDag-Erling Smørgrav 				|| *dname == '-' || *dname == '_'
665b7579f77SDag-Erling Smørgrav 				|| *dname == '*')
666b7579f77SDag-Erling Smørgrav 				*s++ = *(char*)dname++;
667b7579f77SDag-Erling Smørgrav 			else	{
668b7579f77SDag-Erling Smørgrav 				*s++ = '?';
669b7579f77SDag-Erling Smørgrav 				dname++;
670b7579f77SDag-Erling Smørgrav 			}
671b7579f77SDag-Erling Smørgrav 		}
672b7579f77SDag-Erling Smørgrav 		*s++ = '.';
673b7579f77SDag-Erling Smørgrav 		lablen = *dname++;
674b7579f77SDag-Erling Smørgrav 	}
675b7579f77SDag-Erling Smørgrav 	*s = 0;
676*be771a7bSCy Schubert 
677*be771a7bSCy Schubert out:
678*be771a7bSCy Schubert 	log_assert(s - str < LDNS_MAX_DOMAINLEN);
679*be771a7bSCy Schubert 	return;
680b7579f77SDag-Erling Smørgrav }
681b7579f77SDag-Erling Smørgrav 
682b7579f77SDag-Erling Smørgrav int
683b7579f77SDag-Erling Smørgrav dname_strict_subdomain(uint8_t* d1, int labs1, uint8_t* d2, int labs2)
684b7579f77SDag-Erling Smørgrav {
685b7579f77SDag-Erling Smørgrav 	int m;
686b7579f77SDag-Erling Smørgrav 	/* check subdomain: d1: www.example.com. and d2: example.com. */
687b7579f77SDag-Erling Smørgrav 	if(labs2 >= labs1)
688b7579f77SDag-Erling Smørgrav 		return 0;
689b7579f77SDag-Erling Smørgrav 	if(dname_lab_cmp(d1, labs1, d2, labs2, &m) > 0) {
690b7579f77SDag-Erling Smørgrav 		/* subdomain if all labels match */
691b7579f77SDag-Erling Smørgrav 		return (m == labs2);
692b7579f77SDag-Erling Smørgrav 	}
693b7579f77SDag-Erling Smørgrav 	return 0;
694b7579f77SDag-Erling Smørgrav }
695b7579f77SDag-Erling Smørgrav 
696b7579f77SDag-Erling Smørgrav int
697b7579f77SDag-Erling Smørgrav dname_strict_subdomain_c(uint8_t* d1, uint8_t* d2)
698b7579f77SDag-Erling Smørgrav {
699b7579f77SDag-Erling Smørgrav 	return dname_strict_subdomain(d1, dname_count_labels(d1), d2,
700b7579f77SDag-Erling Smørgrav 		dname_count_labels(d2));
701b7579f77SDag-Erling Smørgrav }
702b7579f77SDag-Erling Smørgrav 
703b7579f77SDag-Erling Smørgrav int
704b7579f77SDag-Erling Smørgrav dname_subdomain_c(uint8_t* d1, uint8_t* d2)
705b7579f77SDag-Erling Smørgrav {
706b7579f77SDag-Erling Smørgrav 	int m;
707b7579f77SDag-Erling Smørgrav 	/* check subdomain: d1: www.example.com. and d2: example.com. */
708b7579f77SDag-Erling Smørgrav 	/*  	or 	    d1: example.com. and d2: example.com. */
709b7579f77SDag-Erling Smørgrav 	int labs1 = dname_count_labels(d1);
710b7579f77SDag-Erling Smørgrav 	int labs2 = dname_count_labels(d2);
711b7579f77SDag-Erling Smørgrav 	if(labs2 > labs1)
712b7579f77SDag-Erling Smørgrav 		return 0;
713b7579f77SDag-Erling Smørgrav 	if(dname_lab_cmp(d1, labs1, d2, labs2, &m) < 0) {
714b7579f77SDag-Erling Smørgrav 		/* must have been example.com , www.example.com - wrong */
715b7579f77SDag-Erling Smørgrav 		/* or otherwise different dnames */
716b7579f77SDag-Erling Smørgrav 		return 0;
717b7579f77SDag-Erling Smørgrav 	}
718b7579f77SDag-Erling Smørgrav 	return (m == labs2);
719b7579f77SDag-Erling Smørgrav }
720b7579f77SDag-Erling Smørgrav 
721b7579f77SDag-Erling Smørgrav int
722b7579f77SDag-Erling Smørgrav dname_is_root(uint8_t* dname)
723b7579f77SDag-Erling Smørgrav {
724b7579f77SDag-Erling Smørgrav 	uint8_t len;
725b7579f77SDag-Erling Smørgrav 	log_assert(dname);
726b7579f77SDag-Erling Smørgrav 	len = dname[0];
727b7579f77SDag-Erling Smørgrav 	log_assert(!LABEL_IS_PTR(len));
728b7579f77SDag-Erling Smørgrav 	return (len == 0);
729b7579f77SDag-Erling Smørgrav }
730b7579f77SDag-Erling Smørgrav 
731b7579f77SDag-Erling Smørgrav void
732b7579f77SDag-Erling Smørgrav dname_remove_label(uint8_t** dname, size_t* len)
733b7579f77SDag-Erling Smørgrav {
734b7579f77SDag-Erling Smørgrav 	size_t lablen;
735b7579f77SDag-Erling Smørgrav 	log_assert(dname && *dname && len);
736b7579f77SDag-Erling Smørgrav 	lablen = (*dname)[0];
737b7579f77SDag-Erling Smørgrav 	log_assert(!LABEL_IS_PTR(lablen));
738b7579f77SDag-Erling Smørgrav 	log_assert(*len > lablen);
739b7579f77SDag-Erling Smørgrav 	if(lablen == 0)
740b7579f77SDag-Erling Smørgrav 		return; /* do not modify root label */
741b7579f77SDag-Erling Smørgrav 	*len -= lablen+1;
742b7579f77SDag-Erling Smørgrav 	*dname += lablen+1;
743b7579f77SDag-Erling Smørgrav }
744b7579f77SDag-Erling Smørgrav 
745b7579f77SDag-Erling Smørgrav void
746b7579f77SDag-Erling Smørgrav dname_remove_labels(uint8_t** dname, size_t* len, int n)
747b7579f77SDag-Erling Smørgrav {
748b7579f77SDag-Erling Smørgrav 	int i;
749b7579f77SDag-Erling Smørgrav 	for(i=0; i<n; i++)
750b7579f77SDag-Erling Smørgrav 		dname_remove_label(dname, len);
751b7579f77SDag-Erling Smørgrav }
752b7579f77SDag-Erling Smørgrav 
753b7579f77SDag-Erling Smørgrav int
754b7579f77SDag-Erling Smørgrav dname_signame_label_count(uint8_t* dname)
755b7579f77SDag-Erling Smørgrav {
756b7579f77SDag-Erling Smørgrav 	uint8_t lablen;
757b7579f77SDag-Erling Smørgrav 	int count = 0;
758b7579f77SDag-Erling Smørgrav 	if(!*dname)
759b7579f77SDag-Erling Smørgrav 		return 0;
760b7579f77SDag-Erling Smørgrav 	if(dname[0] == 1 && dname[1] == '*')
761b7579f77SDag-Erling Smørgrav 		dname += 2;
762b7579f77SDag-Erling Smørgrav 	lablen = dname[0];
763b7579f77SDag-Erling Smørgrav 	while(lablen) {
764b7579f77SDag-Erling Smørgrav 		count++;
765b7579f77SDag-Erling Smørgrav 		dname += lablen;
766b7579f77SDag-Erling Smørgrav 		dname += 1;
767b7579f77SDag-Erling Smørgrav 		lablen = dname[0];
768b7579f77SDag-Erling Smørgrav 	}
769b7579f77SDag-Erling Smørgrav 	return count;
770b7579f77SDag-Erling Smørgrav }
771b7579f77SDag-Erling Smørgrav 
772b7579f77SDag-Erling Smørgrav int
773b7579f77SDag-Erling Smørgrav dname_is_wild(uint8_t* dname)
774b7579f77SDag-Erling Smørgrav {
775b7579f77SDag-Erling Smørgrav 	return (dname[0] == 1 && dname[1] == '*');
776b7579f77SDag-Erling Smørgrav }
777b7579f77SDag-Erling Smørgrav 
778b7579f77SDag-Erling Smørgrav /**
779b7579f77SDag-Erling Smørgrav  * Compare labels in memory, lowercase while comparing.
780b7579f77SDag-Erling Smørgrav  * Returns canonical order for labels. If all is equal, the
781b7579f77SDag-Erling Smørgrav  * shortest is first.
782b7579f77SDag-Erling Smørgrav  *
783b7579f77SDag-Erling Smørgrav  * @param p1: label 1
784b7579f77SDag-Erling Smørgrav  * @param len1: length of label 1.
785b7579f77SDag-Erling Smørgrav  * @param p2: label 2
786b7579f77SDag-Erling Smørgrav  * @param len2: length of label 2.
787b7579f77SDag-Erling Smørgrav  * @return: 0, -1, +1 comparison result.
788b7579f77SDag-Erling Smørgrav  */
789b7579f77SDag-Erling Smørgrav static int
790b7579f77SDag-Erling Smørgrav memcanoncmp(uint8_t* p1, uint8_t len1, uint8_t* p2, uint8_t len2)
791b7579f77SDag-Erling Smørgrav {
792b7579f77SDag-Erling Smørgrav 	uint8_t min = (len1<len2)?len1:len2;
793b7579f77SDag-Erling Smørgrav 	int c = memlowercmp(p1, p2, min);
794b7579f77SDag-Erling Smørgrav 	if(c != 0)
795b7579f77SDag-Erling Smørgrav 		return c;
796b7579f77SDag-Erling Smørgrav 	/* equal, see who is shortest */
797b7579f77SDag-Erling Smørgrav 	if(len1 < len2)
798b7579f77SDag-Erling Smørgrav 		return -1;
799b7579f77SDag-Erling Smørgrav 	if(len1 > len2)
800b7579f77SDag-Erling Smørgrav 		return 1;
801b7579f77SDag-Erling Smørgrav 	return 0;
802b7579f77SDag-Erling Smørgrav }
803b7579f77SDag-Erling Smørgrav 
804b7579f77SDag-Erling Smørgrav 
805b7579f77SDag-Erling Smørgrav int
806b7579f77SDag-Erling Smørgrav dname_canon_lab_cmp(uint8_t* d1, int labs1, uint8_t* d2, int labs2, int* mlabs)
807b7579f77SDag-Erling Smørgrav {
808b7579f77SDag-Erling Smørgrav 	/* like dname_lab_cmp, but with different label comparison,
809b7579f77SDag-Erling Smørgrav 	 * empty character sorts before \000.
810b7579f77SDag-Erling Smørgrav 	 * So   ylyly is before z. */
811b7579f77SDag-Erling Smørgrav 	uint8_t len1, len2;
812b7579f77SDag-Erling Smørgrav 	int atlabel = labs1;
813b7579f77SDag-Erling Smørgrav 	int lastmlabs;
814b7579f77SDag-Erling Smørgrav 	int lastdiff = 0;
815b7579f77SDag-Erling Smørgrav 	int c;
816b7579f77SDag-Erling Smørgrav 	/* first skip so that we compare same label. */
817b7579f77SDag-Erling Smørgrav 	if(labs1 > labs2) {
818b7579f77SDag-Erling Smørgrav 		while(atlabel > labs2) {
819b7579f77SDag-Erling Smørgrav 			len1 = *d1++;
820b7579f77SDag-Erling Smørgrav 			d1 += len1;
821b7579f77SDag-Erling Smørgrav 			atlabel--;
822b7579f77SDag-Erling Smørgrav 		}
823b7579f77SDag-Erling Smørgrav 		log_assert(atlabel == labs2);
824b7579f77SDag-Erling Smørgrav 	} else if(labs1 < labs2) {
825b7579f77SDag-Erling Smørgrav 		atlabel = labs2;
826b7579f77SDag-Erling Smørgrav 		while(atlabel > labs1) {
827b7579f77SDag-Erling Smørgrav 			len2 = *d2++;
828b7579f77SDag-Erling Smørgrav 			d2 += len2;
829b7579f77SDag-Erling Smørgrav 			atlabel--;
830b7579f77SDag-Erling Smørgrav 		}
831b7579f77SDag-Erling Smørgrav 		log_assert(atlabel == labs1);
832b7579f77SDag-Erling Smørgrav 	}
833b7579f77SDag-Erling Smørgrav 	lastmlabs = atlabel+1;
834b7579f77SDag-Erling Smørgrav 	/* now at same label in d1 and d2, atlabel */
835b7579f77SDag-Erling Smørgrav 	/* www.example.com.                  */
836b7579f77SDag-Erling Smørgrav 	/* 4   3       2  1   atlabel number */
837b7579f77SDag-Erling Smørgrav 	/* repeat until at root label (which is always the same) */
838b7579f77SDag-Erling Smørgrav 	while(atlabel > 1) {
839b7579f77SDag-Erling Smørgrav 		len1 = *d1++;
840b7579f77SDag-Erling Smørgrav 		len2 = *d2++;
841b7579f77SDag-Erling Smørgrav 
842b7579f77SDag-Erling Smørgrav 		if((c=memcanoncmp(d1, len1, d2, len2)) != 0) {
843b7579f77SDag-Erling Smørgrav 			if(c<0)
844b7579f77SDag-Erling Smørgrav 				lastdiff = -1;
845b7579f77SDag-Erling Smørgrav 			else	lastdiff = 1;
846b7579f77SDag-Erling Smørgrav 			lastmlabs = atlabel;
847b7579f77SDag-Erling Smørgrav 		}
848b7579f77SDag-Erling Smørgrav 
849b7579f77SDag-Erling Smørgrav 		d1 += len1;
850b7579f77SDag-Erling Smørgrav 		d2 += len2;
851b7579f77SDag-Erling Smørgrav 		atlabel--;
852b7579f77SDag-Erling Smørgrav 	}
853b7579f77SDag-Erling Smørgrav 	/* last difference atlabel number, so number of labels matching,
854b7579f77SDag-Erling Smørgrav 	 * at the right side, is one less. */
855b7579f77SDag-Erling Smørgrav 	*mlabs = lastmlabs-1;
856b7579f77SDag-Erling Smørgrav 	if(lastdiff == 0) {
857b7579f77SDag-Erling Smørgrav 		/* all labels compared were equal, check if one has more
858b7579f77SDag-Erling Smørgrav 		 * labels, so that example.com. > com. */
859b7579f77SDag-Erling Smørgrav 		if(labs1 > labs2)
860b7579f77SDag-Erling Smørgrav 			return 1;
861b7579f77SDag-Erling Smørgrav 		else if(labs1 < labs2)
862b7579f77SDag-Erling Smørgrav 			return -1;
863b7579f77SDag-Erling Smørgrav 	}
864b7579f77SDag-Erling Smørgrav 	return lastdiff;
865b7579f77SDag-Erling Smørgrav }
866b7579f77SDag-Erling Smørgrav 
867b7579f77SDag-Erling Smørgrav int
868b7579f77SDag-Erling Smørgrav dname_canonical_compare(uint8_t* d1, uint8_t* d2)
869b7579f77SDag-Erling Smørgrav {
870b7579f77SDag-Erling Smørgrav 	int labs1, labs2, m;
871b7579f77SDag-Erling Smørgrav 	labs1 = dname_count_labels(d1);
872b7579f77SDag-Erling Smørgrav 	labs2 = dname_count_labels(d2);
873b7579f77SDag-Erling Smørgrav 	return dname_canon_lab_cmp(d1, labs1, d2, labs2, &m);
874b7579f77SDag-Erling Smørgrav }
875b7579f77SDag-Erling Smørgrav 
876b7579f77SDag-Erling Smørgrav uint8_t* dname_get_shared_topdomain(uint8_t* d1, uint8_t* d2)
877b7579f77SDag-Erling Smørgrav {
878b7579f77SDag-Erling Smørgrav 	int labs1, labs2, m;
879b7579f77SDag-Erling Smørgrav 	size_t len = LDNS_MAX_DOMAINLEN;
880b7579f77SDag-Erling Smørgrav 	labs1 = dname_count_labels(d1);
881b7579f77SDag-Erling Smørgrav 	labs2 = dname_count_labels(d2);
882b7579f77SDag-Erling Smørgrav 	(void)dname_lab_cmp(d1, labs1, d2, labs2, &m);
883b7579f77SDag-Erling Smørgrav 	dname_remove_labels(&d1, &len, labs1-m);
884b7579f77SDag-Erling Smørgrav 	return d1;
885b7579f77SDag-Erling Smørgrav }
886