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