xref: /netbsd/external/bsd/unbound/dist/util/data/dname.c (revision 762909a6)
1eaad808eSchristos /*
2eaad808eSchristos  * util/data/dname.h - domain name handling
3eaad808eSchristos  *
4eaad808eSchristos  * Copyright (c) 2007, NLnet Labs. All rights reserved.
5eaad808eSchristos  *
6eaad808eSchristos  * This software is open source.
7eaad808eSchristos  *
8eaad808eSchristos  * Redistribution and use in source and binary forms, with or without
9eaad808eSchristos  * modification, are permitted provided that the following conditions
10eaad808eSchristos  * are met:
11eaad808eSchristos  *
12eaad808eSchristos  * Redistributions of source code must retain the above copyright notice,
13eaad808eSchristos  * this list of conditions and the following disclaimer.
14eaad808eSchristos  *
15eaad808eSchristos  * Redistributions in binary form must reproduce the above copyright notice,
16eaad808eSchristos  * this list of conditions and the following disclaimer in the documentation
17eaad808eSchristos  * and/or other materials provided with the distribution.
18eaad808eSchristos  *
19eaad808eSchristos  * Neither the name of the NLNET LABS nor the names of its contributors may
20eaad808eSchristos  * be used to endorse or promote products derived from this software without
21eaad808eSchristos  * specific prior written permission.
22eaad808eSchristos  *
23eaad808eSchristos  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24eaad808eSchristos  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25eaad808eSchristos  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26eaad808eSchristos  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27eaad808eSchristos  * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28eaad808eSchristos  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
29eaad808eSchristos  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30eaad808eSchristos  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31eaad808eSchristos  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32eaad808eSchristos  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33eaad808eSchristos  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34eaad808eSchristos  */
35eaad808eSchristos 
36eaad808eSchristos /**
37eaad808eSchristos  * \file
38eaad808eSchristos  *
39eaad808eSchristos  * This file contains domain name handling functions.
40eaad808eSchristos  */
41eaad808eSchristos 
42eaad808eSchristos #include "config.h"
43eaad808eSchristos #include <ctype.h>
44eaad808eSchristos #include "util/data/dname.h"
45eaad808eSchristos #include "util/data/msgparse.h"
46eaad808eSchristos #include "util/log.h"
47eaad808eSchristos #include "util/storage/lookup3.h"
48eaad808eSchristos #include "sldns/sbuffer.h"
49eaad808eSchristos 
50eaad808eSchristos /* determine length of a dname in buffer, no compression pointers allowed */
51eaad808eSchristos size_t
52eaad808eSchristos query_dname_len(sldns_buffer* query)
53eaad808eSchristos {
54eaad808eSchristos 	size_t len = 0;
55eaad808eSchristos 	size_t labellen;
56eaad808eSchristos 	while(1) {
57eaad808eSchristos 		if(sldns_buffer_remaining(query) < 1)
58eaad808eSchristos 			return 0; /* parse error, need label len */
59eaad808eSchristos 		labellen = sldns_buffer_read_u8(query);
60eaad808eSchristos 		if(labellen&0xc0)
61eaad808eSchristos 			return 0; /* no compression allowed in queries */
62eaad808eSchristos 		len += labellen + 1;
63eaad808eSchristos 		if(len > LDNS_MAX_DOMAINLEN)
64eaad808eSchristos 			return 0; /* too long */
65eaad808eSchristos 		if(labellen == 0)
66eaad808eSchristos 			return len;
67eaad808eSchristos 		if(sldns_buffer_remaining(query) < labellen)
68eaad808eSchristos 			return 0; /* parse error, need content */
69eaad808eSchristos 		sldns_buffer_skip(query, (ssize_t)labellen);
70eaad808eSchristos 	}
71eaad808eSchristos }
72eaad808eSchristos 
73eaad808eSchristos size_t
74eaad808eSchristos dname_valid(uint8_t* dname, size_t maxlen)
75eaad808eSchristos {
76eaad808eSchristos 	size_t len = 0;
77eaad808eSchristos 	size_t labellen;
78eaad808eSchristos 	labellen = *dname++;
79eaad808eSchristos 	while(labellen) {
80eaad808eSchristos 		if(labellen&0xc0)
81eaad808eSchristos 			return 0; /* no compression ptrs allowed */
82eaad808eSchristos 		len += labellen + 1;
83eaad808eSchristos 		if(len >= LDNS_MAX_DOMAINLEN)
84eaad808eSchristos 			return 0; /* too long */
85eaad808eSchristos 		if(len > maxlen)
86eaad808eSchristos 			return 0; /* does not fit in memory allocation */
87eaad808eSchristos 		dname += labellen;
88eaad808eSchristos 		labellen = *dname++;
89eaad808eSchristos 	}
90eaad808eSchristos 	len += 1;
91eaad808eSchristos 	if(len > maxlen)
92eaad808eSchristos 		return 0; /* does not fit in memory allocation */
93eaad808eSchristos 	return len;
94eaad808eSchristos }
95eaad808eSchristos 
96eaad808eSchristos /** compare uncompressed, noncanonical, registers are hints for speed */
97eaad808eSchristos int
98eaad808eSchristos query_dname_compare(register uint8_t* d1, register uint8_t* d2)
99eaad808eSchristos {
100eaad808eSchristos 	register uint8_t lab1, lab2;
101eaad808eSchristos 	log_assert(d1 && d2);
102eaad808eSchristos 	lab1 = *d1++;
103eaad808eSchristos 	lab2 = *d2++;
104eaad808eSchristos 	while( lab1 != 0 || lab2 != 0 ) {
105eaad808eSchristos 		/* compare label length */
106eaad808eSchristos 		/* if one dname ends, it has labellength 0 */
107eaad808eSchristos 		if(lab1 != lab2) {
108eaad808eSchristos 			if(lab1 < lab2)
109eaad808eSchristos 				return -1;
110eaad808eSchristos 			return 1;
111eaad808eSchristos 		}
112eaad808eSchristos 		log_assert(lab1 == lab2 && lab1 != 0);
113eaad808eSchristos 		/* compare lowercased labels. */
114eaad808eSchristos 		while(lab1--) {
115eaad808eSchristos 			/* compare bytes first for speed */
116eaad808eSchristos 			if(*d1 != *d2 &&
117eaad808eSchristos 				tolower((unsigned char)*d1) != tolower((unsigned char)*d2)) {
118eaad808eSchristos 				if(tolower((unsigned char)*d1) < tolower((unsigned char)*d2))
119eaad808eSchristos 					return -1;
120eaad808eSchristos 				return 1;
121eaad808eSchristos 			}
122eaad808eSchristos 			d1++;
123eaad808eSchristos 			d2++;
124eaad808eSchristos 		}
125eaad808eSchristos 		/* next pair of labels. */
126eaad808eSchristos 		lab1 = *d1++;
127eaad808eSchristos 		lab2 = *d2++;
128eaad808eSchristos 	}
129eaad808eSchristos 	return 0;
130eaad808eSchristos }
131eaad808eSchristos 
132eaad808eSchristos void
133eaad808eSchristos query_dname_tolower(uint8_t* dname)
134eaad808eSchristos {
135eaad808eSchristos 	/* the dname is stored uncompressed */
136eaad808eSchristos 	uint8_t labellen;
137eaad808eSchristos 	labellen = *dname;
138eaad808eSchristos 	while(labellen) {
139eaad808eSchristos 		dname++;
140eaad808eSchristos 		while(labellen--) {
141eaad808eSchristos 			*dname = (uint8_t)tolower((unsigned char)*dname);
142eaad808eSchristos 			dname++;
143eaad808eSchristos 		}
144eaad808eSchristos 		labellen = *dname;
145eaad808eSchristos 	}
146eaad808eSchristos }
147eaad808eSchristos 
148eaad808eSchristos void
149eaad808eSchristos pkt_dname_tolower(sldns_buffer* pkt, uint8_t* dname)
150eaad808eSchristos {
151eaad808eSchristos 	uint8_t lablen;
152eaad808eSchristos 	int count = 0;
153eaad808eSchristos 	if(dname >= sldns_buffer_end(pkt))
154eaad808eSchristos 		return;
155eaad808eSchristos 	lablen = *dname++;
156eaad808eSchristos 	while(lablen) {
157eaad808eSchristos 		if(LABEL_IS_PTR(lablen)) {
158eaad808eSchristos 			if((size_t)PTR_OFFSET(lablen, *dname)
159eaad808eSchristos 				>= sldns_buffer_limit(pkt))
160eaad808eSchristos 				return;
161eaad808eSchristos 			dname = sldns_buffer_at(pkt, PTR_OFFSET(lablen, *dname));
162eaad808eSchristos 			lablen = *dname++;
163eaad808eSchristos 			if(count++ > MAX_COMPRESS_PTRS)
164eaad808eSchristos 				return;
165eaad808eSchristos 			continue;
166eaad808eSchristos 		}
167eaad808eSchristos 		if(dname+lablen >= sldns_buffer_end(pkt))
168eaad808eSchristos 			return;
169eaad808eSchristos 		while(lablen--) {
170eaad808eSchristos 			*dname = (uint8_t)tolower((unsigned char)*dname);
171eaad808eSchristos 			dname++;
172eaad808eSchristos 		}
173eaad808eSchristos 		if(dname >= sldns_buffer_end(pkt))
174eaad808eSchristos 			return;
175eaad808eSchristos 		lablen = *dname++;
176eaad808eSchristos 	}
177eaad808eSchristos }
178eaad808eSchristos 
179eaad808eSchristos 
180eaad808eSchristos size_t
181eaad808eSchristos pkt_dname_len(sldns_buffer* pkt)
182eaad808eSchristos {
183eaad808eSchristos 	size_t len = 0;
184eaad808eSchristos 	int ptrcount = 0;
185eaad808eSchristos 	uint8_t labellen;
186eaad808eSchristos 	size_t endpos = 0;
187eaad808eSchristos 
188eaad808eSchristos 	/* read dname and determine length */
189eaad808eSchristos 	/* check compression pointers, loops, out of bounds */
190eaad808eSchristos 	while(1) {
191eaad808eSchristos 		/* read next label */
192eaad808eSchristos 		if(sldns_buffer_remaining(pkt) < 1)
193eaad808eSchristos 			return 0;
194eaad808eSchristos 		labellen = sldns_buffer_read_u8(pkt);
195eaad808eSchristos 		if(LABEL_IS_PTR(labellen)) {
196eaad808eSchristos 			/* compression ptr */
197eaad808eSchristos 			uint16_t ptr;
198eaad808eSchristos 			if(sldns_buffer_remaining(pkt) < 1)
199eaad808eSchristos 				return 0;
200eaad808eSchristos 			ptr = PTR_OFFSET(labellen, sldns_buffer_read_u8(pkt));
201eaad808eSchristos 			if(ptrcount++ > MAX_COMPRESS_PTRS)
202eaad808eSchristos 				return 0; /* loop! */
203eaad808eSchristos 			if(sldns_buffer_limit(pkt) <= ptr)
204eaad808eSchristos 				return 0; /* out of bounds! */
205eaad808eSchristos 			if(!endpos)
206eaad808eSchristos 				endpos = sldns_buffer_position(pkt);
207eaad808eSchristos 			sldns_buffer_set_position(pkt, ptr);
208eaad808eSchristos 		} else {
209eaad808eSchristos 			/* label contents */
210eaad808eSchristos 			if(labellen > 0x3f)
211eaad808eSchristos 				return 0; /* label too long */
212eaad808eSchristos 			len += 1 + labellen;
213eaad808eSchristos 			if(len > LDNS_MAX_DOMAINLEN)
214eaad808eSchristos 				return 0;
215eaad808eSchristos 			if(labellen == 0) {
216eaad808eSchristos 				/* end of dname */
217eaad808eSchristos 				break;
218eaad808eSchristos 			}
219eaad808eSchristos 			if(sldns_buffer_remaining(pkt) < labellen)
220eaad808eSchristos 				return 0;
221eaad808eSchristos 			sldns_buffer_skip(pkt, (ssize_t)labellen);
222eaad808eSchristos 		}
223eaad808eSchristos 	}
224eaad808eSchristos 	if(endpos)
225eaad808eSchristos 		sldns_buffer_set_position(pkt, endpos);
226eaad808eSchristos 
227eaad808eSchristos 	return len;
228eaad808eSchristos }
229eaad808eSchristos 
230eaad808eSchristos int
231eaad808eSchristos dname_pkt_compare(sldns_buffer* pkt, uint8_t* d1, uint8_t* d2)
232eaad808eSchristos {
233eaad808eSchristos 	uint8_t len1, len2;
234eaad808eSchristos 	log_assert(pkt && d1 && d2);
235eaad808eSchristos 	len1 = *d1++;
236eaad808eSchristos 	len2 = *d2++;
237eaad808eSchristos 	while( len1 != 0 || len2 != 0 ) {
238eaad808eSchristos 		/* resolve ptrs */
239eaad808eSchristos 		if(LABEL_IS_PTR(len1)) {
240eaad808eSchristos 			d1 = sldns_buffer_at(pkt, PTR_OFFSET(len1, *d1));
241eaad808eSchristos 			len1 = *d1++;
242eaad808eSchristos 			continue;
243eaad808eSchristos 		}
244eaad808eSchristos 		if(LABEL_IS_PTR(len2)) {
245eaad808eSchristos 			d2 = sldns_buffer_at(pkt, PTR_OFFSET(len2, *d2));
246eaad808eSchristos 			len2 = *d2++;
247eaad808eSchristos 			continue;
248eaad808eSchristos 		}
249eaad808eSchristos 		/* check label length */
250eaad808eSchristos 		log_assert(len1 <= LDNS_MAX_LABELLEN);
251eaad808eSchristos 		log_assert(len2 <= LDNS_MAX_LABELLEN);
252eaad808eSchristos 		if(len1 != len2) {
253eaad808eSchristos 			if(len1 < len2) return -1;
254eaad808eSchristos 			return 1;
255eaad808eSchristos 		}
256eaad808eSchristos 		log_assert(len1 == len2 && len1 != 0);
257eaad808eSchristos 		/* compare labels */
258eaad808eSchristos 		while(len1--) {
259eaad808eSchristos 			if(tolower((unsigned char)*d1) != tolower((unsigned char)*d2)) {
260eaad808eSchristos 				if(tolower((unsigned char)*d1) < tolower((unsigned char)*d2))
261eaad808eSchristos 					return -1;
262eaad808eSchristos 				return 1;
263eaad808eSchristos 			}
264eaad808eSchristos 			d1++;
265eaad808eSchristos 			d2++;
266eaad808eSchristos 		}
267eaad808eSchristos 		len1 = *d1++;
268eaad808eSchristos 		len2 = *d2++;
269eaad808eSchristos 	}
270eaad808eSchristos 	return 0;
271eaad808eSchristos }
272eaad808eSchristos 
273*762909a6Schristos hashvalue_type
274*762909a6Schristos dname_query_hash(uint8_t* dname, hashvalue_type h)
275eaad808eSchristos {
276eaad808eSchristos 	uint8_t labuf[LDNS_MAX_LABELLEN+1];
277eaad808eSchristos 	uint8_t lablen;
278eaad808eSchristos 	int i;
279eaad808eSchristos 
280eaad808eSchristos 	/* preserve case of query, make hash label by label */
281eaad808eSchristos 	lablen = *dname++;
282eaad808eSchristos 	while(lablen) {
283eaad808eSchristos 		log_assert(lablen <= LDNS_MAX_LABELLEN);
284eaad808eSchristos 		labuf[0] = lablen;
285eaad808eSchristos 		i=0;
286eaad808eSchristos 		while(lablen--) {
287eaad808eSchristos 			labuf[++i] = (uint8_t)tolower((unsigned char)*dname);
288eaad808eSchristos 			dname++;
289eaad808eSchristos 		}
290eaad808eSchristos 		h = hashlittle(labuf, labuf[0] + 1, h);
291eaad808eSchristos 		lablen = *dname++;
292eaad808eSchristos 	}
293eaad808eSchristos 
294eaad808eSchristos 	return h;
295eaad808eSchristos }
296eaad808eSchristos 
297*762909a6Schristos hashvalue_type
298*762909a6Schristos dname_pkt_hash(sldns_buffer* pkt, uint8_t* dname, hashvalue_type h)
299eaad808eSchristos {
300eaad808eSchristos 	uint8_t labuf[LDNS_MAX_LABELLEN+1];
301eaad808eSchristos 	uint8_t lablen;
302eaad808eSchristos 	int i;
303eaad808eSchristos 
304eaad808eSchristos 	/* preserve case of query, make hash label by label */
305eaad808eSchristos 	lablen = *dname++;
306eaad808eSchristos 	while(lablen) {
307eaad808eSchristos 		if(LABEL_IS_PTR(lablen)) {
308eaad808eSchristos 			/* follow pointer */
309eaad808eSchristos 			dname = sldns_buffer_at(pkt, PTR_OFFSET(lablen, *dname));
310eaad808eSchristos 			lablen = *dname++;
311eaad808eSchristos 			continue;
312eaad808eSchristos 		}
313eaad808eSchristos 		log_assert(lablen <= LDNS_MAX_LABELLEN);
314eaad808eSchristos 		labuf[0] = lablen;
315eaad808eSchristos 		i=0;
316eaad808eSchristos 		while(lablen--) {
317eaad808eSchristos 			labuf[++i] = (uint8_t)tolower((unsigned char)*dname);
318eaad808eSchristos 			dname++;
319eaad808eSchristos 		}
320eaad808eSchristos 		h = hashlittle(labuf, labuf[0] + 1, h);
321eaad808eSchristos 		lablen = *dname++;
322eaad808eSchristos 	}
323eaad808eSchristos 
324eaad808eSchristos 	return h;
325eaad808eSchristos }
326eaad808eSchristos 
327eaad808eSchristos void dname_pkt_copy(sldns_buffer* pkt, uint8_t* to, uint8_t* dname)
328eaad808eSchristos {
329eaad808eSchristos 	/* copy over the dname and decompress it at the same time */
330eaad808eSchristos 	size_t len = 0;
331eaad808eSchristos 	uint8_t lablen;
332eaad808eSchristos 	lablen = *dname++;
333eaad808eSchristos 	while(lablen) {
334eaad808eSchristos 		if(LABEL_IS_PTR(lablen)) {
335eaad808eSchristos 			/* follow pointer */
336eaad808eSchristos 			dname = sldns_buffer_at(pkt, PTR_OFFSET(lablen, *dname));
337eaad808eSchristos 			lablen = *dname++;
338eaad808eSchristos 			continue;
339eaad808eSchristos 		}
340eaad808eSchristos 		log_assert(lablen <= LDNS_MAX_LABELLEN);
341eaad808eSchristos 		len += (size_t)lablen+1;
342eaad808eSchristos 		if(len >= LDNS_MAX_DOMAINLEN) {
343eaad808eSchristos 			*to = 0; /* end the result prematurely */
344eaad808eSchristos 			log_err("bad dname in dname_pkt_copy");
345eaad808eSchristos 			return;
346eaad808eSchristos 		}
347eaad808eSchristos 		*to++ = lablen;
348eaad808eSchristos 		memmove(to, dname, lablen);
349eaad808eSchristos 		dname += lablen;
350eaad808eSchristos 		to += lablen;
351eaad808eSchristos 		lablen = *dname++;
352eaad808eSchristos 	}
353eaad808eSchristos 	/* copy last \0 */
354eaad808eSchristos 	*to = 0;
355eaad808eSchristos }
356eaad808eSchristos 
357eaad808eSchristos void dname_print(FILE* out, struct sldns_buffer* pkt, uint8_t* dname)
358eaad808eSchristos {
359eaad808eSchristos 	uint8_t lablen;
360eaad808eSchristos 	if(!out) out = stdout;
361eaad808eSchristos 	if(!dname) return;
362eaad808eSchristos 
363eaad808eSchristos 	lablen = *dname++;
364eaad808eSchristos 	if(!lablen)
365eaad808eSchristos 		fputc('.', out);
366eaad808eSchristos 	while(lablen) {
367eaad808eSchristos 		if(LABEL_IS_PTR(lablen)) {
368eaad808eSchristos 			/* follow pointer */
369eaad808eSchristos 			if(!pkt) {
370eaad808eSchristos 				fputs("??compressionptr??", out);
371eaad808eSchristos 				return;
372eaad808eSchristos 			}
373eaad808eSchristos 			dname = sldns_buffer_at(pkt, PTR_OFFSET(lablen, *dname));
374eaad808eSchristos 			lablen = *dname++;
375eaad808eSchristos 			continue;
376eaad808eSchristos 		}
377eaad808eSchristos 		if(lablen > LDNS_MAX_LABELLEN) {
378eaad808eSchristos 			fputs("??extendedlabel??", out);
379eaad808eSchristos 			return;
380eaad808eSchristos 		}
381eaad808eSchristos 		while(lablen--)
382eaad808eSchristos 			fputc((int)*dname++, out);
383eaad808eSchristos 		fputc('.', out);
384eaad808eSchristos 		lablen = *dname++;
385eaad808eSchristos 	}
386eaad808eSchristos }
387eaad808eSchristos 
388eaad808eSchristos int
389eaad808eSchristos dname_count_labels(uint8_t* dname)
390eaad808eSchristos {
391eaad808eSchristos 	uint8_t lablen;
392eaad808eSchristos 	int labs = 1;
393eaad808eSchristos 
394eaad808eSchristos 	lablen = *dname++;
395eaad808eSchristos 	while(lablen) {
396eaad808eSchristos 		labs++;
397eaad808eSchristos 		dname += lablen;
398eaad808eSchristos 		lablen = *dname++;
399eaad808eSchristos 	}
400eaad808eSchristos 	return labs;
401eaad808eSchristos }
402eaad808eSchristos 
403eaad808eSchristos int
404eaad808eSchristos dname_count_size_labels(uint8_t* dname, size_t* size)
405eaad808eSchristos {
406eaad808eSchristos 	uint8_t lablen;
407eaad808eSchristos 	int labs = 1;
408eaad808eSchristos 	size_t sz = 1;
409eaad808eSchristos 
410eaad808eSchristos 	lablen = *dname++;
411eaad808eSchristos 	while(lablen) {
412eaad808eSchristos 		labs++;
413eaad808eSchristos 		sz += lablen+1;
414eaad808eSchristos 		dname += lablen;
415eaad808eSchristos 		lablen = *dname++;
416eaad808eSchristos 	}
417eaad808eSchristos 	*size = sz;
418eaad808eSchristos 	return labs;
419eaad808eSchristos }
420eaad808eSchristos 
421eaad808eSchristos /**
422eaad808eSchristos  * Compare labels in memory, lowercase while comparing.
423eaad808eSchristos  * @param p1: label 1
424eaad808eSchristos  * @param p2: label 2
425eaad808eSchristos  * @param len: number of bytes to compare.
426eaad808eSchristos  * @return: 0, -1, +1 comparison result.
427eaad808eSchristos  */
428eaad808eSchristos static int
429eaad808eSchristos memlowercmp(uint8_t* p1, uint8_t* p2, uint8_t len)
430eaad808eSchristos {
431eaad808eSchristos 	while(len--) {
432eaad808eSchristos 		if(*p1 != *p2 && tolower((unsigned char)*p1) != tolower((unsigned char)*p2)) {
433eaad808eSchristos 			if(tolower((unsigned char)*p1) < tolower((unsigned char)*p2))
434eaad808eSchristos 				return -1;
435eaad808eSchristos 			return 1;
436eaad808eSchristos 		}
437eaad808eSchristos 		p1++;
438eaad808eSchristos 		p2++;
439eaad808eSchristos 	}
440eaad808eSchristos 	return 0;
441eaad808eSchristos }
442eaad808eSchristos 
443eaad808eSchristos int
444eaad808eSchristos dname_lab_cmp(uint8_t* d1, int labs1, uint8_t* d2, int labs2, int* mlabs)
445eaad808eSchristos {
446eaad808eSchristos 	uint8_t len1, len2;
447eaad808eSchristos 	int atlabel = labs1;
448eaad808eSchristos 	int lastmlabs;
449eaad808eSchristos 	int lastdiff = 0;
450eaad808eSchristos 	/* first skip so that we compare same label. */
451eaad808eSchristos 	if(labs1 > labs2) {
452eaad808eSchristos 		while(atlabel > labs2) {
453eaad808eSchristos 			len1 = *d1++;
454eaad808eSchristos 			d1 += len1;
455eaad808eSchristos 			atlabel--;
456eaad808eSchristos 		}
457eaad808eSchristos 		log_assert(atlabel == labs2);
458eaad808eSchristos 	} else if(labs1 < labs2) {
459eaad808eSchristos 		atlabel = labs2;
460eaad808eSchristos 		while(atlabel > labs1) {
461eaad808eSchristos 			len2 = *d2++;
462eaad808eSchristos 			d2 += len2;
463eaad808eSchristos 			atlabel--;
464eaad808eSchristos 		}
465eaad808eSchristos 		log_assert(atlabel == labs1);
466eaad808eSchristos 	}
467eaad808eSchristos 	lastmlabs = atlabel+1;
468eaad808eSchristos 	/* now at same label in d1 and d2, atlabel */
469eaad808eSchristos 	/* www.example.com.                  */
470eaad808eSchristos 	/* 4   3       2  1   atlabel number */
471eaad808eSchristos 	/* repeat until at root label (which is always the same) */
472eaad808eSchristos 	while(atlabel > 1) {
473eaad808eSchristos 		len1 = *d1++;
474eaad808eSchristos 		len2 = *d2++;
475eaad808eSchristos 		if(len1 != len2) {
476eaad808eSchristos 			log_assert(len1 != 0 && len2 != 0);
477eaad808eSchristos 			if(len1<len2)
478eaad808eSchristos 				lastdiff = -1;
479eaad808eSchristos 			else	lastdiff = 1;
480eaad808eSchristos 			lastmlabs = atlabel;
481eaad808eSchristos 			d1 += len1;
482eaad808eSchristos 			d2 += len2;
483eaad808eSchristos 		} else {
484eaad808eSchristos 			/* memlowercmp is inlined here; or just like
485eaad808eSchristos 			 * if((c=memlowercmp(d1, d2, len1)) != 0) {
486eaad808eSchristos 			 *	lastdiff = c;
487eaad808eSchristos 			 *	lastmlabs = atlabel; } apart from d1++,d2++ */
488eaad808eSchristos 			while(len1) {
489eaad808eSchristos 				if(*d1 != *d2 && tolower((unsigned char)*d1)
490eaad808eSchristos 					!= tolower((unsigned char)*d2)) {
491eaad808eSchristos 					if(tolower((unsigned char)*d1) <
492eaad808eSchristos 						tolower((unsigned char)*d2)) {
493eaad808eSchristos 						lastdiff = -1;
494eaad808eSchristos 						lastmlabs = atlabel;
495eaad808eSchristos 						d1 += len1;
496eaad808eSchristos 						d2 += len1;
497eaad808eSchristos 						break;
498eaad808eSchristos 					}
499eaad808eSchristos 					lastdiff = 1;
500eaad808eSchristos 					lastmlabs = atlabel;
501eaad808eSchristos 					d1 += len1;
502eaad808eSchristos 					d2 += len1;
503eaad808eSchristos 					break; /* out of memlowercmp */
504eaad808eSchristos 				}
505eaad808eSchristos 				d1++;
506eaad808eSchristos 				d2++;
507eaad808eSchristos 				len1--;
508eaad808eSchristos 			}
509eaad808eSchristos 		}
510eaad808eSchristos 		atlabel--;
511eaad808eSchristos 	}
512eaad808eSchristos 	/* last difference atlabel number, so number of labels matching,
513eaad808eSchristos 	 * at the right side, is one less. */
514eaad808eSchristos 	*mlabs = lastmlabs-1;
515eaad808eSchristos 	if(lastdiff == 0) {
516eaad808eSchristos 		/* all labels compared were equal, check if one has more
517eaad808eSchristos 		 * labels, so that example.com. > com. */
518eaad808eSchristos 		if(labs1 > labs2)
519eaad808eSchristos 			return 1;
520eaad808eSchristos 		else if(labs1 < labs2)
521eaad808eSchristos 			return -1;
522eaad808eSchristos 	}
523eaad808eSchristos 	return lastdiff;
524eaad808eSchristos }
525eaad808eSchristos 
526eaad808eSchristos int
527eaad808eSchristos dname_buffer_write(sldns_buffer* pkt, uint8_t* dname)
528eaad808eSchristos {
529eaad808eSchristos 	uint8_t lablen;
530eaad808eSchristos 
531eaad808eSchristos 	if(sldns_buffer_remaining(pkt) < 1)
532eaad808eSchristos 		return 0;
533eaad808eSchristos 	lablen = *dname++;
534eaad808eSchristos 	sldns_buffer_write_u8(pkt, lablen);
535eaad808eSchristos 	while(lablen) {
536eaad808eSchristos 		if(sldns_buffer_remaining(pkt) < (size_t)lablen+1)
537eaad808eSchristos 			return 0;
538eaad808eSchristos 		sldns_buffer_write(pkt, dname, lablen);
539eaad808eSchristos 		dname += lablen;
540eaad808eSchristos 		lablen = *dname++;
541eaad808eSchristos 		sldns_buffer_write_u8(pkt, lablen);
542eaad808eSchristos 	}
543eaad808eSchristos 	return 1;
544eaad808eSchristos }
545eaad808eSchristos 
546eaad808eSchristos void dname_str(uint8_t* dname, char* str)
547eaad808eSchristos {
548eaad808eSchristos 	size_t len = 0;
549eaad808eSchristos 	uint8_t lablen = 0;
550eaad808eSchristos 	char* s = str;
551eaad808eSchristos 	if(!dname || !*dname) {
552eaad808eSchristos 		*s++ = '.';
553eaad808eSchristos 		*s = 0;
554eaad808eSchristos 		return;
555eaad808eSchristos 	}
556eaad808eSchristos 	lablen = *dname++;
557eaad808eSchristos 	while(lablen) {
558eaad808eSchristos 		if(lablen > LDNS_MAX_LABELLEN) {
559eaad808eSchristos 			*s++ = '#';
560eaad808eSchristos 			*s = 0;
561eaad808eSchristos 			return;
562eaad808eSchristos 		}
563eaad808eSchristos 		len += lablen+1;
564eaad808eSchristos 		if(len >= LDNS_MAX_DOMAINLEN-1) {
565eaad808eSchristos 			*s++ = '&';
566eaad808eSchristos 			*s = 0;
567eaad808eSchristos 			return;
568eaad808eSchristos 		}
569eaad808eSchristos 		while(lablen--) {
570eaad808eSchristos 			if(isalnum((unsigned char)*dname)
571eaad808eSchristos 				|| *dname == '-' || *dname == '_'
572eaad808eSchristos 				|| *dname == '*')
573eaad808eSchristos 				*s++ = *(char*)dname++;
574eaad808eSchristos 			else	{
575eaad808eSchristos 				*s++ = '?';
576eaad808eSchristos 				dname++;
577eaad808eSchristos 			}
578eaad808eSchristos 		}
579eaad808eSchristos 		*s++ = '.';
580eaad808eSchristos 		lablen = *dname++;
581eaad808eSchristos 	}
582eaad808eSchristos 	*s = 0;
583eaad808eSchristos }
584eaad808eSchristos 
585eaad808eSchristos int
586eaad808eSchristos dname_strict_subdomain(uint8_t* d1, int labs1, uint8_t* d2, int labs2)
587eaad808eSchristos {
588eaad808eSchristos 	int m;
589eaad808eSchristos 	/* check subdomain: d1: www.example.com. and d2: example.com. */
590eaad808eSchristos 	if(labs2 >= labs1)
591eaad808eSchristos 		return 0;
592eaad808eSchristos 	if(dname_lab_cmp(d1, labs1, d2, labs2, &m) > 0) {
593eaad808eSchristos 		/* subdomain if all labels match */
594eaad808eSchristos 		return (m == labs2);
595eaad808eSchristos 	}
596eaad808eSchristos 	return 0;
597eaad808eSchristos }
598eaad808eSchristos 
599eaad808eSchristos int
600eaad808eSchristos dname_strict_subdomain_c(uint8_t* d1, uint8_t* d2)
601eaad808eSchristos {
602eaad808eSchristos 	return dname_strict_subdomain(d1, dname_count_labels(d1), d2,
603eaad808eSchristos 		dname_count_labels(d2));
604eaad808eSchristos }
605eaad808eSchristos 
606eaad808eSchristos int
607eaad808eSchristos dname_subdomain_c(uint8_t* d1, uint8_t* d2)
608eaad808eSchristos {
609eaad808eSchristos 	int m;
610eaad808eSchristos 	/* check subdomain: d1: www.example.com. and d2: example.com. */
611eaad808eSchristos 	/*  	or 	    d1: example.com. and d2: example.com. */
612eaad808eSchristos 	int labs1 = dname_count_labels(d1);
613eaad808eSchristos 	int labs2 = dname_count_labels(d2);
614eaad808eSchristos 	if(labs2 > labs1)
615eaad808eSchristos 		return 0;
616eaad808eSchristos 	if(dname_lab_cmp(d1, labs1, d2, labs2, &m) < 0) {
617eaad808eSchristos 		/* must have been example.com , www.example.com - wrong */
618eaad808eSchristos 		/* or otherwise different dnames */
619eaad808eSchristos 		return 0;
620eaad808eSchristos 	}
621eaad808eSchristos 	return (m == labs2);
622eaad808eSchristos }
623eaad808eSchristos 
624eaad808eSchristos int
625eaad808eSchristos dname_is_root(uint8_t* dname)
626eaad808eSchristos {
627eaad808eSchristos 	uint8_t len;
628eaad808eSchristos 	log_assert(dname);
629eaad808eSchristos 	len = dname[0];
630eaad808eSchristos 	log_assert(!LABEL_IS_PTR(len));
631eaad808eSchristos 	return (len == 0);
632eaad808eSchristos }
633eaad808eSchristos 
634eaad808eSchristos void
635eaad808eSchristos dname_remove_label(uint8_t** dname, size_t* len)
636eaad808eSchristos {
637eaad808eSchristos 	size_t lablen;
638eaad808eSchristos 	log_assert(dname && *dname && len);
639eaad808eSchristos 	lablen = (*dname)[0];
640eaad808eSchristos 	log_assert(!LABEL_IS_PTR(lablen));
641eaad808eSchristos 	log_assert(*len > lablen);
642eaad808eSchristos 	if(lablen == 0)
643eaad808eSchristos 		return; /* do not modify root label */
644eaad808eSchristos 	*len -= lablen+1;
645eaad808eSchristos 	*dname += lablen+1;
646eaad808eSchristos }
647eaad808eSchristos 
648eaad808eSchristos void
649eaad808eSchristos dname_remove_labels(uint8_t** dname, size_t* len, int n)
650eaad808eSchristos {
651eaad808eSchristos 	int i;
652eaad808eSchristos 	for(i=0; i<n; i++)
653eaad808eSchristos 		dname_remove_label(dname, len);
654eaad808eSchristos }
655eaad808eSchristos 
656eaad808eSchristos int
657eaad808eSchristos dname_signame_label_count(uint8_t* dname)
658eaad808eSchristos {
659eaad808eSchristos 	uint8_t lablen;
660eaad808eSchristos 	int count = 0;
661eaad808eSchristos 	if(!*dname)
662eaad808eSchristos 		return 0;
663eaad808eSchristos 	if(dname[0] == 1 && dname[1] == '*')
664eaad808eSchristos 		dname += 2;
665eaad808eSchristos 	lablen = dname[0];
666eaad808eSchristos 	while(lablen) {
667eaad808eSchristos 		count++;
668eaad808eSchristos 		dname += lablen;
669eaad808eSchristos 		dname += 1;
670eaad808eSchristos 		lablen = dname[0];
671eaad808eSchristos 	}
672eaad808eSchristos 	return count;
673eaad808eSchristos }
674eaad808eSchristos 
675eaad808eSchristos int
676eaad808eSchristos dname_is_wild(uint8_t* dname)
677eaad808eSchristos {
678eaad808eSchristos 	return (dname[0] == 1 && dname[1] == '*');
679eaad808eSchristos }
680eaad808eSchristos 
681eaad808eSchristos /**
682eaad808eSchristos  * Compare labels in memory, lowercase while comparing.
683eaad808eSchristos  * Returns canonical order for labels. If all is equal, the
684eaad808eSchristos  * shortest is first.
685eaad808eSchristos  *
686eaad808eSchristos  * @param p1: label 1
687eaad808eSchristos  * @param len1: length of label 1.
688eaad808eSchristos  * @param p2: label 2
689eaad808eSchristos  * @param len2: length of label 2.
690eaad808eSchristos  * @return: 0, -1, +1 comparison result.
691eaad808eSchristos  */
692eaad808eSchristos static int
693eaad808eSchristos memcanoncmp(uint8_t* p1, uint8_t len1, uint8_t* p2, uint8_t len2)
694eaad808eSchristos {
695eaad808eSchristos 	uint8_t min = (len1<len2)?len1:len2;
696eaad808eSchristos 	int c = memlowercmp(p1, p2, min);
697eaad808eSchristos 	if(c != 0)
698eaad808eSchristos 		return c;
699eaad808eSchristos 	/* equal, see who is shortest */
700eaad808eSchristos 	if(len1 < len2)
701eaad808eSchristos 		return -1;
702eaad808eSchristos 	if(len1 > len2)
703eaad808eSchristos 		return 1;
704eaad808eSchristos 	return 0;
705eaad808eSchristos }
706eaad808eSchristos 
707eaad808eSchristos 
708eaad808eSchristos int
709eaad808eSchristos dname_canon_lab_cmp(uint8_t* d1, int labs1, uint8_t* d2, int labs2, int* mlabs)
710eaad808eSchristos {
711eaad808eSchristos 	/* like dname_lab_cmp, but with different label comparison,
712eaad808eSchristos 	 * empty character sorts before \000.
713eaad808eSchristos 	 * So   ylyly is before z. */
714eaad808eSchristos 	uint8_t len1, len2;
715eaad808eSchristos 	int atlabel = labs1;
716eaad808eSchristos 	int lastmlabs;
717eaad808eSchristos 	int lastdiff = 0;
718eaad808eSchristos 	int c;
719eaad808eSchristos 	/* first skip so that we compare same label. */
720eaad808eSchristos 	if(labs1 > labs2) {
721eaad808eSchristos 		while(atlabel > labs2) {
722eaad808eSchristos 			len1 = *d1++;
723eaad808eSchristos 			d1 += len1;
724eaad808eSchristos 			atlabel--;
725eaad808eSchristos 		}
726eaad808eSchristos 		log_assert(atlabel == labs2);
727eaad808eSchristos 	} else if(labs1 < labs2) {
728eaad808eSchristos 		atlabel = labs2;
729eaad808eSchristos 		while(atlabel > labs1) {
730eaad808eSchristos 			len2 = *d2++;
731eaad808eSchristos 			d2 += len2;
732eaad808eSchristos 			atlabel--;
733eaad808eSchristos 		}
734eaad808eSchristos 		log_assert(atlabel == labs1);
735eaad808eSchristos 	}
736eaad808eSchristos 	lastmlabs = atlabel+1;
737eaad808eSchristos 	/* now at same label in d1 and d2, atlabel */
738eaad808eSchristos 	/* www.example.com.                  */
739eaad808eSchristos 	/* 4   3       2  1   atlabel number */
740eaad808eSchristos 	/* repeat until at root label (which is always the same) */
741eaad808eSchristos 	while(atlabel > 1) {
742eaad808eSchristos 		len1 = *d1++;
743eaad808eSchristos 		len2 = *d2++;
744eaad808eSchristos 
745eaad808eSchristos 		if((c=memcanoncmp(d1, len1, d2, len2)) != 0) {
746eaad808eSchristos 			if(c<0)
747eaad808eSchristos 				lastdiff = -1;
748eaad808eSchristos 			else	lastdiff = 1;
749eaad808eSchristos 			lastmlabs = atlabel;
750eaad808eSchristos 		}
751eaad808eSchristos 
752eaad808eSchristos 		d1 += len1;
753eaad808eSchristos 		d2 += len2;
754eaad808eSchristos 		atlabel--;
755eaad808eSchristos 	}
756eaad808eSchristos 	/* last difference atlabel number, so number of labels matching,
757eaad808eSchristos 	 * at the right side, is one less. */
758eaad808eSchristos 	*mlabs = lastmlabs-1;
759eaad808eSchristos 	if(lastdiff == 0) {
760eaad808eSchristos 		/* all labels compared were equal, check if one has more
761eaad808eSchristos 		 * labels, so that example.com. > com. */
762eaad808eSchristos 		if(labs1 > labs2)
763eaad808eSchristos 			return 1;
764eaad808eSchristos 		else if(labs1 < labs2)
765eaad808eSchristos 			return -1;
766eaad808eSchristos 	}
767eaad808eSchristos 	return lastdiff;
768eaad808eSchristos }
769eaad808eSchristos 
770eaad808eSchristos int
771eaad808eSchristos dname_canonical_compare(uint8_t* d1, uint8_t* d2)
772eaad808eSchristos {
773eaad808eSchristos 	int labs1, labs2, m;
774eaad808eSchristos 	labs1 = dname_count_labels(d1);
775eaad808eSchristos 	labs2 = dname_count_labels(d2);
776eaad808eSchristos 	return dname_canon_lab_cmp(d1, labs1, d2, labs2, &m);
777eaad808eSchristos }
778eaad808eSchristos 
779eaad808eSchristos uint8_t* dname_get_shared_topdomain(uint8_t* d1, uint8_t* d2)
780eaad808eSchristos {
781eaad808eSchristos 	int labs1, labs2, m;
782eaad808eSchristos 	size_t len = LDNS_MAX_DOMAINLEN;
783eaad808eSchristos 	labs1 = dname_count_labels(d1);
784eaad808eSchristos 	labs2 = dname_count_labels(d2);
785eaad808eSchristos 	(void)dname_lab_cmp(d1, labs1, d2, labs2, &m);
786eaad808eSchristos 	dname_remove_labels(&d1, &len, labs1-m);
787eaad808eSchristos 	return d1;
788eaad808eSchristos }
789