xref: /freebsd/contrib/ldns/dname.c (revision 7b5038d71c5c74ab863c1ff3fec33de94bf35a57)
1*7b5038d7SDag-Erling Smørgrav /*
2*7b5038d7SDag-Erling Smørgrav  * dname.c
3*7b5038d7SDag-Erling Smørgrav  *
4*7b5038d7SDag-Erling Smørgrav  * dname specific rdata implementations
5*7b5038d7SDag-Erling Smørgrav  * A dname is a rdf structure with type LDNS_RDF_TYPE_DNAME
6*7b5038d7SDag-Erling Smørgrav  * It is not a /real/ type! All function must therefor check
7*7b5038d7SDag-Erling Smørgrav  * for LDNS_RDF_TYPE_DNAME.
8*7b5038d7SDag-Erling Smørgrav  *
9*7b5038d7SDag-Erling Smørgrav  * a Net::DNS like library for C
10*7b5038d7SDag-Erling Smørgrav  *
11*7b5038d7SDag-Erling Smørgrav  * (c) NLnet Labs, 2004-2006
12*7b5038d7SDag-Erling Smørgrav  *
13*7b5038d7SDag-Erling Smørgrav  * See the file LICENSE for the license
14*7b5038d7SDag-Erling Smørgrav  */
15*7b5038d7SDag-Erling Smørgrav 
16*7b5038d7SDag-Erling Smørgrav #include <ldns/config.h>
17*7b5038d7SDag-Erling Smørgrav 
18*7b5038d7SDag-Erling Smørgrav #include <ldns/ldns.h>
19*7b5038d7SDag-Erling Smørgrav 
20*7b5038d7SDag-Erling Smørgrav #ifdef HAVE_NETINET_IN_H
21*7b5038d7SDag-Erling Smørgrav #include <netinet/in.h>
22*7b5038d7SDag-Erling Smørgrav #endif
23*7b5038d7SDag-Erling Smørgrav #ifdef HAVE_SYS_SOCKET_H
24*7b5038d7SDag-Erling Smørgrav #include <sys/socket.h>
25*7b5038d7SDag-Erling Smørgrav #endif
26*7b5038d7SDag-Erling Smørgrav #ifdef HAVE_NETDB_H
27*7b5038d7SDag-Erling Smørgrav #include <netdb.h>
28*7b5038d7SDag-Erling Smørgrav #endif
29*7b5038d7SDag-Erling Smørgrav #ifdef HAVE_ARPA_INET_H
30*7b5038d7SDag-Erling Smørgrav #include <arpa/inet.h>
31*7b5038d7SDag-Erling Smørgrav #endif
32*7b5038d7SDag-Erling Smørgrav 
33*7b5038d7SDag-Erling Smørgrav ldns_rdf *
34*7b5038d7SDag-Erling Smørgrav ldns_dname_cat_clone(const ldns_rdf *rd1, const ldns_rdf *rd2)
35*7b5038d7SDag-Erling Smørgrav {
36*7b5038d7SDag-Erling Smørgrav 	ldns_rdf *new;
37*7b5038d7SDag-Erling Smørgrav 	uint16_t new_size;
38*7b5038d7SDag-Erling Smørgrav 	uint8_t *buf;
39*7b5038d7SDag-Erling Smørgrav 	uint16_t left_size;
40*7b5038d7SDag-Erling Smørgrav 
41*7b5038d7SDag-Erling Smørgrav 	if (ldns_rdf_get_type(rd1) != LDNS_RDF_TYPE_DNAME ||
42*7b5038d7SDag-Erling Smørgrav 			ldns_rdf_get_type(rd2) != LDNS_RDF_TYPE_DNAME) {
43*7b5038d7SDag-Erling Smørgrav 		return NULL;
44*7b5038d7SDag-Erling Smørgrav 	}
45*7b5038d7SDag-Erling Smørgrav 
46*7b5038d7SDag-Erling Smørgrav 	/* remove root label if it is present at the end of the left
47*7b5038d7SDag-Erling Smørgrav 	 * rd, by reducing the size with 1
48*7b5038d7SDag-Erling Smørgrav 	 */
49*7b5038d7SDag-Erling Smørgrav 	left_size = ldns_rdf_size(rd1);
50*7b5038d7SDag-Erling Smørgrav 	if (left_size > 0 &&ldns_rdf_data(rd1)[left_size - 1] == 0) {
51*7b5038d7SDag-Erling Smørgrav 		left_size--;
52*7b5038d7SDag-Erling Smørgrav 	}
53*7b5038d7SDag-Erling Smørgrav 
54*7b5038d7SDag-Erling Smørgrav 	/* we overwrite the nullbyte of rd1 */
55*7b5038d7SDag-Erling Smørgrav 	new_size = left_size + ldns_rdf_size(rd2);
56*7b5038d7SDag-Erling Smørgrav 	buf = LDNS_XMALLOC(uint8_t, new_size);
57*7b5038d7SDag-Erling Smørgrav 	if (!buf) {
58*7b5038d7SDag-Erling Smørgrav 		return NULL;
59*7b5038d7SDag-Erling Smørgrav 	}
60*7b5038d7SDag-Erling Smørgrav 
61*7b5038d7SDag-Erling Smørgrav 	/* put the two dname's after each other */
62*7b5038d7SDag-Erling Smørgrav 	memcpy(buf, ldns_rdf_data(rd1), left_size);
63*7b5038d7SDag-Erling Smørgrav 	memcpy(buf + left_size, ldns_rdf_data(rd2), ldns_rdf_size(rd2));
64*7b5038d7SDag-Erling Smørgrav 
65*7b5038d7SDag-Erling Smørgrav 	new = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_DNAME, new_size, buf);
66*7b5038d7SDag-Erling Smørgrav 
67*7b5038d7SDag-Erling Smørgrav 	LDNS_FREE(buf);
68*7b5038d7SDag-Erling Smørgrav 	return new;
69*7b5038d7SDag-Erling Smørgrav }
70*7b5038d7SDag-Erling Smørgrav 
71*7b5038d7SDag-Erling Smørgrav ldns_status
72*7b5038d7SDag-Erling Smørgrav ldns_dname_cat(ldns_rdf *rd1, ldns_rdf *rd2)
73*7b5038d7SDag-Erling Smørgrav {
74*7b5038d7SDag-Erling Smørgrav 	uint16_t left_size;
75*7b5038d7SDag-Erling Smørgrav 	uint16_t size;
76*7b5038d7SDag-Erling Smørgrav 	uint8_t* newd;
77*7b5038d7SDag-Erling Smørgrav 
78*7b5038d7SDag-Erling Smørgrav 	if (ldns_rdf_get_type(rd1) != LDNS_RDF_TYPE_DNAME ||
79*7b5038d7SDag-Erling Smørgrav 			ldns_rdf_get_type(rd2) != LDNS_RDF_TYPE_DNAME) {
80*7b5038d7SDag-Erling Smørgrav 		return LDNS_STATUS_ERR;
81*7b5038d7SDag-Erling Smørgrav 	}
82*7b5038d7SDag-Erling Smørgrav 
83*7b5038d7SDag-Erling Smørgrav 	/* remove root label if it is present at the end of the left
84*7b5038d7SDag-Erling Smørgrav 	 * rd, by reducing the size with 1
85*7b5038d7SDag-Erling Smørgrav 	 */
86*7b5038d7SDag-Erling Smørgrav 	left_size = ldns_rdf_size(rd1);
87*7b5038d7SDag-Erling Smørgrav 	if (left_size > 0 &&ldns_rdf_data(rd1)[left_size - 1] == 0) {
88*7b5038d7SDag-Erling Smørgrav 		left_size--;
89*7b5038d7SDag-Erling Smørgrav 	}
90*7b5038d7SDag-Erling Smørgrav 
91*7b5038d7SDag-Erling Smørgrav 	size = left_size + ldns_rdf_size(rd2);
92*7b5038d7SDag-Erling Smørgrav 	newd = LDNS_XREALLOC(ldns_rdf_data(rd1), uint8_t, size);
93*7b5038d7SDag-Erling Smørgrav 	if(!newd) {
94*7b5038d7SDag-Erling Smørgrav 		return LDNS_STATUS_MEM_ERR;
95*7b5038d7SDag-Erling Smørgrav 	}
96*7b5038d7SDag-Erling Smørgrav 
97*7b5038d7SDag-Erling Smørgrav 	ldns_rdf_set_data(rd1, newd);
98*7b5038d7SDag-Erling Smørgrav 	memcpy(ldns_rdf_data(rd1) + left_size, ldns_rdf_data(rd2),
99*7b5038d7SDag-Erling Smørgrav 			ldns_rdf_size(rd2));
100*7b5038d7SDag-Erling Smørgrav 	ldns_rdf_set_size(rd1, size);
101*7b5038d7SDag-Erling Smørgrav 
102*7b5038d7SDag-Erling Smørgrav 	return LDNS_STATUS_OK;
103*7b5038d7SDag-Erling Smørgrav }
104*7b5038d7SDag-Erling Smørgrav 
105*7b5038d7SDag-Erling Smørgrav ldns_rdf *
106*7b5038d7SDag-Erling Smørgrav ldns_dname_reverse(const ldns_rdf *d)
107*7b5038d7SDag-Erling Smørgrav {
108*7b5038d7SDag-Erling Smørgrav 	ldns_rdf *new;
109*7b5038d7SDag-Erling Smørgrav 	ldns_rdf *tmp;
110*7b5038d7SDag-Erling Smørgrav 	ldns_rdf *d_tmp;
111*7b5038d7SDag-Erling Smørgrav 	ldns_status status;
112*7b5038d7SDag-Erling Smørgrav 
113*7b5038d7SDag-Erling Smørgrav 	d_tmp = ldns_rdf_clone(d);
114*7b5038d7SDag-Erling Smørgrav 
115*7b5038d7SDag-Erling Smørgrav 	new = ldns_dname_new_frm_str(".");
116*7b5038d7SDag-Erling Smørgrav         if(!new)
117*7b5038d7SDag-Erling Smørgrav                 return NULL;
118*7b5038d7SDag-Erling Smørgrav 
119*7b5038d7SDag-Erling Smørgrav 	while(ldns_dname_label_count(d_tmp) > 0) {
120*7b5038d7SDag-Erling Smørgrav 		tmp = ldns_dname_label(d_tmp, 0);
121*7b5038d7SDag-Erling Smørgrav 		status = ldns_dname_cat(tmp, new);
122*7b5038d7SDag-Erling Smørgrav                 if(status != LDNS_STATUS_OK) {
123*7b5038d7SDag-Erling Smørgrav                         ldns_rdf_deep_free(new);
124*7b5038d7SDag-Erling Smørgrav 	                ldns_rdf_deep_free(d_tmp);
125*7b5038d7SDag-Erling Smørgrav                         return NULL;
126*7b5038d7SDag-Erling Smørgrav                 }
127*7b5038d7SDag-Erling Smørgrav 		ldns_rdf_deep_free(new);
128*7b5038d7SDag-Erling Smørgrav 		new = tmp;
129*7b5038d7SDag-Erling Smørgrav 		tmp = ldns_dname_left_chop(d_tmp);
130*7b5038d7SDag-Erling Smørgrav 		ldns_rdf_deep_free(d_tmp);
131*7b5038d7SDag-Erling Smørgrav 		d_tmp = tmp;
132*7b5038d7SDag-Erling Smørgrav 	}
133*7b5038d7SDag-Erling Smørgrav 	ldns_rdf_deep_free(d_tmp);
134*7b5038d7SDag-Erling Smørgrav 
135*7b5038d7SDag-Erling Smørgrav 	return new;
136*7b5038d7SDag-Erling Smørgrav }
137*7b5038d7SDag-Erling Smørgrav 
138*7b5038d7SDag-Erling Smørgrav ldns_rdf *
139*7b5038d7SDag-Erling Smørgrav ldns_dname_clone_from(const ldns_rdf *d, uint16_t n)
140*7b5038d7SDag-Erling Smørgrav {
141*7b5038d7SDag-Erling Smørgrav 	uint8_t *data;
142*7b5038d7SDag-Erling Smørgrav 	uint8_t label_size;
143*7b5038d7SDag-Erling Smørgrav 	size_t data_size;
144*7b5038d7SDag-Erling Smørgrav 
145*7b5038d7SDag-Erling Smørgrav 	if (!d ||
146*7b5038d7SDag-Erling Smørgrav 	    ldns_rdf_get_type(d) != LDNS_RDF_TYPE_DNAME ||
147*7b5038d7SDag-Erling Smørgrav 	    ldns_dname_label_count(d) < n) {
148*7b5038d7SDag-Erling Smørgrav 		return NULL;
149*7b5038d7SDag-Erling Smørgrav 	}
150*7b5038d7SDag-Erling Smørgrav 
151*7b5038d7SDag-Erling Smørgrav 	data = ldns_rdf_data(d);
152*7b5038d7SDag-Erling Smørgrav 	data_size = ldns_rdf_size(d);
153*7b5038d7SDag-Erling Smørgrav 	while (n > 0) {
154*7b5038d7SDag-Erling Smørgrav 		label_size = data[0] + 1;
155*7b5038d7SDag-Erling Smørgrav 		data += label_size;
156*7b5038d7SDag-Erling Smørgrav 		if (data_size < label_size) {
157*7b5038d7SDag-Erling Smørgrav 			/* this label is very broken */
158*7b5038d7SDag-Erling Smørgrav 			return NULL;
159*7b5038d7SDag-Erling Smørgrav 		}
160*7b5038d7SDag-Erling Smørgrav 		data_size -= label_size;
161*7b5038d7SDag-Erling Smørgrav 		n--;
162*7b5038d7SDag-Erling Smørgrav 	}
163*7b5038d7SDag-Erling Smørgrav 
164*7b5038d7SDag-Erling Smørgrav 	return ldns_dname_new_frm_data(data_size, data);
165*7b5038d7SDag-Erling Smørgrav }
166*7b5038d7SDag-Erling Smørgrav 
167*7b5038d7SDag-Erling Smørgrav ldns_rdf *
168*7b5038d7SDag-Erling Smørgrav ldns_dname_left_chop(const ldns_rdf *d)
169*7b5038d7SDag-Erling Smørgrav {
170*7b5038d7SDag-Erling Smørgrav 	uint8_t label_pos;
171*7b5038d7SDag-Erling Smørgrav 	ldns_rdf *chop;
172*7b5038d7SDag-Erling Smørgrav 
173*7b5038d7SDag-Erling Smørgrav 	if (!d) {
174*7b5038d7SDag-Erling Smørgrav 		return NULL;
175*7b5038d7SDag-Erling Smørgrav 	}
176*7b5038d7SDag-Erling Smørgrav 
177*7b5038d7SDag-Erling Smørgrav 	if (ldns_rdf_get_type(d) != LDNS_RDF_TYPE_DNAME) {
178*7b5038d7SDag-Erling Smørgrav 		return NULL;
179*7b5038d7SDag-Erling Smørgrav 	}
180*7b5038d7SDag-Erling Smørgrav 	if (ldns_dname_label_count(d) == 0) {
181*7b5038d7SDag-Erling Smørgrav 		/* root label */
182*7b5038d7SDag-Erling Smørgrav 		return NULL;
183*7b5038d7SDag-Erling Smørgrav 	}
184*7b5038d7SDag-Erling Smørgrav 	/* 05blaat02nl00 */
185*7b5038d7SDag-Erling Smørgrav 	label_pos = ldns_rdf_data(d)[0];
186*7b5038d7SDag-Erling Smørgrav 
187*7b5038d7SDag-Erling Smørgrav 	chop = ldns_dname_new_frm_data(ldns_rdf_size(d) - label_pos - 1,
188*7b5038d7SDag-Erling Smørgrav 			ldns_rdf_data(d) + label_pos + 1);
189*7b5038d7SDag-Erling Smørgrav 	return chop;
190*7b5038d7SDag-Erling Smørgrav }
191*7b5038d7SDag-Erling Smørgrav 
192*7b5038d7SDag-Erling Smørgrav uint8_t
193*7b5038d7SDag-Erling Smørgrav ldns_dname_label_count(const ldns_rdf *r)
194*7b5038d7SDag-Erling Smørgrav {
195*7b5038d7SDag-Erling Smørgrav         uint16_t src_pos;
196*7b5038d7SDag-Erling Smørgrav         uint16_t len;
197*7b5038d7SDag-Erling Smørgrav         uint8_t i;
198*7b5038d7SDag-Erling Smørgrav         size_t r_size;
199*7b5038d7SDag-Erling Smørgrav 
200*7b5038d7SDag-Erling Smørgrav 	if (!r) {
201*7b5038d7SDag-Erling Smørgrav 		return 0;
202*7b5038d7SDag-Erling Smørgrav 	}
203*7b5038d7SDag-Erling Smørgrav 
204*7b5038d7SDag-Erling Smørgrav 	i = 0;
205*7b5038d7SDag-Erling Smørgrav 	src_pos = 0;
206*7b5038d7SDag-Erling Smørgrav 	r_size = ldns_rdf_size(r);
207*7b5038d7SDag-Erling Smørgrav 
208*7b5038d7SDag-Erling Smørgrav 	if (ldns_rdf_get_type(r) != LDNS_RDF_TYPE_DNAME) {
209*7b5038d7SDag-Erling Smørgrav 		return 0;
210*7b5038d7SDag-Erling Smørgrav 	} else {
211*7b5038d7SDag-Erling Smørgrav 		len = ldns_rdf_data(r)[src_pos]; /* start of the label */
212*7b5038d7SDag-Erling Smørgrav 
213*7b5038d7SDag-Erling Smørgrav 		/* single root label */
214*7b5038d7SDag-Erling Smørgrav 		if (1 == r_size) {
215*7b5038d7SDag-Erling Smørgrav 			return 0;
216*7b5038d7SDag-Erling Smørgrav 		} else {
217*7b5038d7SDag-Erling Smørgrav 			while ((len > 0) && src_pos < r_size) {
218*7b5038d7SDag-Erling Smørgrav 				src_pos++;
219*7b5038d7SDag-Erling Smørgrav 				src_pos += len;
220*7b5038d7SDag-Erling Smørgrav 				len = ldns_rdf_data(r)[src_pos];
221*7b5038d7SDag-Erling Smørgrav 				i++;
222*7b5038d7SDag-Erling Smørgrav 			}
223*7b5038d7SDag-Erling Smørgrav 		}
224*7b5038d7SDag-Erling Smørgrav 	}
225*7b5038d7SDag-Erling Smørgrav 	return i;
226*7b5038d7SDag-Erling Smørgrav }
227*7b5038d7SDag-Erling Smørgrav 
228*7b5038d7SDag-Erling Smørgrav ldns_rdf *
229*7b5038d7SDag-Erling Smørgrav ldns_dname_new(uint16_t s, void *d)
230*7b5038d7SDag-Erling Smørgrav {
231*7b5038d7SDag-Erling Smørgrav         ldns_rdf *rd;
232*7b5038d7SDag-Erling Smørgrav 
233*7b5038d7SDag-Erling Smørgrav         rd = LDNS_MALLOC(ldns_rdf);
234*7b5038d7SDag-Erling Smørgrav         if (!rd) {
235*7b5038d7SDag-Erling Smørgrav                 return NULL;
236*7b5038d7SDag-Erling Smørgrav         }
237*7b5038d7SDag-Erling Smørgrav         ldns_rdf_set_size(rd, s);
238*7b5038d7SDag-Erling Smørgrav         ldns_rdf_set_type(rd, LDNS_RDF_TYPE_DNAME);
239*7b5038d7SDag-Erling Smørgrav         ldns_rdf_set_data(rd, d);
240*7b5038d7SDag-Erling Smørgrav         return rd;
241*7b5038d7SDag-Erling Smørgrav }
242*7b5038d7SDag-Erling Smørgrav 
243*7b5038d7SDag-Erling Smørgrav ldns_rdf *
244*7b5038d7SDag-Erling Smørgrav ldns_dname_new_frm_str(const char *str)
245*7b5038d7SDag-Erling Smørgrav {
246*7b5038d7SDag-Erling Smørgrav 	return ldns_rdf_new_frm_str(LDNS_RDF_TYPE_DNAME, str);
247*7b5038d7SDag-Erling Smørgrav }
248*7b5038d7SDag-Erling Smørgrav 
249*7b5038d7SDag-Erling Smørgrav ldns_rdf *
250*7b5038d7SDag-Erling Smørgrav ldns_dname_new_frm_data(uint16_t size, const void *data)
251*7b5038d7SDag-Erling Smørgrav {
252*7b5038d7SDag-Erling Smørgrav 	return ldns_rdf_new_frm_data(LDNS_RDF_TYPE_DNAME, size, data);
253*7b5038d7SDag-Erling Smørgrav }
254*7b5038d7SDag-Erling Smørgrav 
255*7b5038d7SDag-Erling Smørgrav void
256*7b5038d7SDag-Erling Smørgrav ldns_dname2canonical(const ldns_rdf *rd)
257*7b5038d7SDag-Erling Smørgrav {
258*7b5038d7SDag-Erling Smørgrav 	uint8_t *rdd;
259*7b5038d7SDag-Erling Smørgrav 	uint16_t i;
260*7b5038d7SDag-Erling Smørgrav 
261*7b5038d7SDag-Erling Smørgrav 	if (ldns_rdf_get_type(rd) != LDNS_RDF_TYPE_DNAME) {
262*7b5038d7SDag-Erling Smørgrav 		return;
263*7b5038d7SDag-Erling Smørgrav 	}
264*7b5038d7SDag-Erling Smørgrav 
265*7b5038d7SDag-Erling Smørgrav 	rdd = (uint8_t*)ldns_rdf_data(rd);
266*7b5038d7SDag-Erling Smørgrav 	for (i = 0; i < ldns_rdf_size(rd); i++, rdd++) {
267*7b5038d7SDag-Erling Smørgrav 		*rdd = (uint8_t)LDNS_DNAME_NORMALIZE((int)*rdd);
268*7b5038d7SDag-Erling Smørgrav 	}
269*7b5038d7SDag-Erling Smørgrav }
270*7b5038d7SDag-Erling Smørgrav 
271*7b5038d7SDag-Erling Smørgrav bool
272*7b5038d7SDag-Erling Smørgrav ldns_dname_is_subdomain(const ldns_rdf *sub, const ldns_rdf *parent)
273*7b5038d7SDag-Erling Smørgrav {
274*7b5038d7SDag-Erling Smørgrav 	uint8_t sub_lab;
275*7b5038d7SDag-Erling Smørgrav 	uint8_t par_lab;
276*7b5038d7SDag-Erling Smørgrav 	int8_t i, j;
277*7b5038d7SDag-Erling Smørgrav 	ldns_rdf *tmp_sub = NULL;
278*7b5038d7SDag-Erling Smørgrav 	ldns_rdf *tmp_par = NULL;
279*7b5038d7SDag-Erling Smørgrav     ldns_rdf *sub_clone;
280*7b5038d7SDag-Erling Smørgrav     ldns_rdf *parent_clone;
281*7b5038d7SDag-Erling Smørgrav     bool result = true;
282*7b5038d7SDag-Erling Smørgrav 
283*7b5038d7SDag-Erling Smørgrav 	if (ldns_rdf_get_type(sub) != LDNS_RDF_TYPE_DNAME ||
284*7b5038d7SDag-Erling Smørgrav 			ldns_rdf_get_type(parent) != LDNS_RDF_TYPE_DNAME ||
285*7b5038d7SDag-Erling Smørgrav 			ldns_rdf_compare(sub, parent) == 0) {
286*7b5038d7SDag-Erling Smørgrav 		return false;
287*7b5038d7SDag-Erling Smørgrav 	}
288*7b5038d7SDag-Erling Smørgrav 
289*7b5038d7SDag-Erling Smørgrav     /* would be nicer if we do not have to clone... */
290*7b5038d7SDag-Erling Smørgrav     sub_clone = ldns_dname_clone_from(sub, 0);
291*7b5038d7SDag-Erling Smørgrav     parent_clone = ldns_dname_clone_from(parent, 0);
292*7b5038d7SDag-Erling Smørgrav     ldns_dname2canonical(sub_clone);
293*7b5038d7SDag-Erling Smørgrav     ldns_dname2canonical(parent_clone);
294*7b5038d7SDag-Erling Smørgrav 
295*7b5038d7SDag-Erling Smørgrav 	sub_lab = ldns_dname_label_count(sub_clone);
296*7b5038d7SDag-Erling Smørgrav 	par_lab = ldns_dname_label_count(parent_clone);
297*7b5038d7SDag-Erling Smørgrav 
298*7b5038d7SDag-Erling Smørgrav 	/* if sub sits above parent, it cannot be a child/sub domain */
299*7b5038d7SDag-Erling Smørgrav 	if (sub_lab < par_lab) {
300*7b5038d7SDag-Erling Smørgrav 		result = false;
301*7b5038d7SDag-Erling Smørgrav 	} else {
302*7b5038d7SDag-Erling Smørgrav 		/* check all labels the from the parent labels, from right to left.
303*7b5038d7SDag-Erling Smørgrav 		 * When they /all/ match we have found a subdomain
304*7b5038d7SDag-Erling Smørgrav 		 */
305*7b5038d7SDag-Erling Smørgrav 		j = sub_lab - 1; /* we count from zero, thank you */
306*7b5038d7SDag-Erling Smørgrav 		for (i = par_lab -1; i >= 0; i--) {
307*7b5038d7SDag-Erling Smørgrav 			tmp_sub = ldns_dname_label(sub_clone, j);
308*7b5038d7SDag-Erling Smørgrav 			tmp_par = ldns_dname_label(parent_clone, i);
309*7b5038d7SDag-Erling Smørgrav 			if (!tmp_sub || !tmp_par) {
310*7b5038d7SDag-Erling Smørgrav 				/* deep free does null check */
311*7b5038d7SDag-Erling Smørgrav 				ldns_rdf_deep_free(tmp_sub);
312*7b5038d7SDag-Erling Smørgrav 				ldns_rdf_deep_free(tmp_par);
313*7b5038d7SDag-Erling Smørgrav 				result = false;
314*7b5038d7SDag-Erling Smørgrav 				break;
315*7b5038d7SDag-Erling Smørgrav 			}
316*7b5038d7SDag-Erling Smørgrav 
317*7b5038d7SDag-Erling Smørgrav 			if (ldns_rdf_compare(tmp_sub, tmp_par) != 0) {
318*7b5038d7SDag-Erling Smørgrav 				/* they are not equal */
319*7b5038d7SDag-Erling Smørgrav 				ldns_rdf_deep_free(tmp_sub);
320*7b5038d7SDag-Erling Smørgrav 				ldns_rdf_deep_free(tmp_par);
321*7b5038d7SDag-Erling Smørgrav 				result = false;
322*7b5038d7SDag-Erling Smørgrav 				break;
323*7b5038d7SDag-Erling Smørgrav 			}
324*7b5038d7SDag-Erling Smørgrav 			ldns_rdf_deep_free(tmp_sub);
325*7b5038d7SDag-Erling Smørgrav 			ldns_rdf_deep_free(tmp_par);
326*7b5038d7SDag-Erling Smørgrav 			j--;
327*7b5038d7SDag-Erling Smørgrav 		}
328*7b5038d7SDag-Erling Smørgrav 	}
329*7b5038d7SDag-Erling Smørgrav 	ldns_rdf_deep_free(sub_clone);
330*7b5038d7SDag-Erling Smørgrav 	ldns_rdf_deep_free(parent_clone);
331*7b5038d7SDag-Erling Smørgrav 	return result;
332*7b5038d7SDag-Erling Smørgrav }
333*7b5038d7SDag-Erling Smørgrav 
334*7b5038d7SDag-Erling Smørgrav int
335*7b5038d7SDag-Erling Smørgrav ldns_dname_compare(const ldns_rdf *dname1, const ldns_rdf *dname2)
336*7b5038d7SDag-Erling Smørgrav {
337*7b5038d7SDag-Erling Smørgrav 	size_t lc1, lc2, lc1f, lc2f;
338*7b5038d7SDag-Erling Smørgrav 	size_t i;
339*7b5038d7SDag-Erling Smørgrav 	int result = 0;
340*7b5038d7SDag-Erling Smørgrav 	uint8_t *lp1, *lp2;
341*7b5038d7SDag-Erling Smørgrav 
342*7b5038d7SDag-Erling Smørgrav 	/* see RFC4034 for this algorithm */
343*7b5038d7SDag-Erling Smørgrav 	/* this algorithm assumes the names are normalized to case */
344*7b5038d7SDag-Erling Smørgrav 
345*7b5038d7SDag-Erling Smørgrav         /* only when both are not NULL we can say anything about them */
346*7b5038d7SDag-Erling Smørgrav         if (!dname1 && !dname2) {
347*7b5038d7SDag-Erling Smørgrav                 return 0;
348*7b5038d7SDag-Erling Smørgrav         }
349*7b5038d7SDag-Erling Smørgrav         if (!dname1 || !dname2) {
350*7b5038d7SDag-Erling Smørgrav                 return -1;
351*7b5038d7SDag-Erling Smørgrav         }
352*7b5038d7SDag-Erling Smørgrav 	/* asserts must happen later as we are looking in the
353*7b5038d7SDag-Erling Smørgrav 	 * dname, which could be NULL. But this case is handled
354*7b5038d7SDag-Erling Smørgrav 	 * above
355*7b5038d7SDag-Erling Smørgrav 	 */
356*7b5038d7SDag-Erling Smørgrav 	assert(ldns_rdf_get_type(dname1) == LDNS_RDF_TYPE_DNAME);
357*7b5038d7SDag-Erling Smørgrav 	assert(ldns_rdf_get_type(dname2) == LDNS_RDF_TYPE_DNAME);
358*7b5038d7SDag-Erling Smørgrav 
359*7b5038d7SDag-Erling Smørgrav 	lc1 = ldns_dname_label_count(dname1);
360*7b5038d7SDag-Erling Smørgrav 	lc2 = ldns_dname_label_count(dname2);
361*7b5038d7SDag-Erling Smørgrav 
362*7b5038d7SDag-Erling Smørgrav 	if (lc1 == 0 && lc2 == 0) {
363*7b5038d7SDag-Erling Smørgrav 		return 0;
364*7b5038d7SDag-Erling Smørgrav 	}
365*7b5038d7SDag-Erling Smørgrav 	if (lc1 == 0) {
366*7b5038d7SDag-Erling Smørgrav 		return -1;
367*7b5038d7SDag-Erling Smørgrav 	}
368*7b5038d7SDag-Erling Smørgrav 	if (lc2 == 0) {
369*7b5038d7SDag-Erling Smørgrav 		return 1;
370*7b5038d7SDag-Erling Smørgrav 	}
371*7b5038d7SDag-Erling Smørgrav 	lc1--;
372*7b5038d7SDag-Erling Smørgrav 	lc2--;
373*7b5038d7SDag-Erling Smørgrav 	/* we start at the last label */
374*7b5038d7SDag-Erling Smørgrav 	while (true) {
375*7b5038d7SDag-Erling Smørgrav 		/* find the label first */
376*7b5038d7SDag-Erling Smørgrav 		lc1f = lc1;
377*7b5038d7SDag-Erling Smørgrav 		lp1 = ldns_rdf_data(dname1);
378*7b5038d7SDag-Erling Smørgrav 		while (lc1f > 0) {
379*7b5038d7SDag-Erling Smørgrav 			lp1 += *lp1 + 1;
380*7b5038d7SDag-Erling Smørgrav 			lc1f--;
381*7b5038d7SDag-Erling Smørgrav 		}
382*7b5038d7SDag-Erling Smørgrav 
383*7b5038d7SDag-Erling Smørgrav 		/* and find the other one */
384*7b5038d7SDag-Erling Smørgrav 		lc2f = lc2;
385*7b5038d7SDag-Erling Smørgrav 		lp2 = ldns_rdf_data(dname2);
386*7b5038d7SDag-Erling Smørgrav 		while (lc2f > 0) {
387*7b5038d7SDag-Erling Smørgrav 			lp2 += *lp2 + 1;
388*7b5038d7SDag-Erling Smørgrav 			lc2f--;
389*7b5038d7SDag-Erling Smørgrav 		}
390*7b5038d7SDag-Erling Smørgrav 
391*7b5038d7SDag-Erling Smørgrav 		/* now check the label character for character. */
392*7b5038d7SDag-Erling Smørgrav 		for (i = 1; i < (size_t)(*lp1 + 1); i++) {
393*7b5038d7SDag-Erling Smørgrav 			if (i > *lp2) {
394*7b5038d7SDag-Erling Smørgrav 				/* apparently label 1 is larger */
395*7b5038d7SDag-Erling Smørgrav 				result = 1;
396*7b5038d7SDag-Erling Smørgrav 				goto done;
397*7b5038d7SDag-Erling Smørgrav 			}
398*7b5038d7SDag-Erling Smørgrav 			if (LDNS_DNAME_NORMALIZE((int) *(lp1 + i)) <
399*7b5038d7SDag-Erling Smørgrav 			    LDNS_DNAME_NORMALIZE((int) *(lp2 + i))) {
400*7b5038d7SDag-Erling Smørgrav 			    result = -1;
401*7b5038d7SDag-Erling Smørgrav 			    goto done;
402*7b5038d7SDag-Erling Smørgrav 			} else if (LDNS_DNAME_NORMALIZE((int) *(lp1 + i)) >
403*7b5038d7SDag-Erling Smørgrav 			    LDNS_DNAME_NORMALIZE((int) *(lp2 + i))) {
404*7b5038d7SDag-Erling Smørgrav 			    result = 1;
405*7b5038d7SDag-Erling Smørgrav 			    goto done;
406*7b5038d7SDag-Erling Smørgrav 			}
407*7b5038d7SDag-Erling Smørgrav 		}
408*7b5038d7SDag-Erling Smørgrav 		if (*lp1 < *lp2) {
409*7b5038d7SDag-Erling Smørgrav 			/* apparently label 2 is larger */
410*7b5038d7SDag-Erling Smørgrav 			result = -1;
411*7b5038d7SDag-Erling Smørgrav 			goto done;
412*7b5038d7SDag-Erling Smørgrav 		}
413*7b5038d7SDag-Erling Smørgrav 		if (lc1 == 0 && lc2 > 0) {
414*7b5038d7SDag-Erling Smørgrav 			result = -1;
415*7b5038d7SDag-Erling Smørgrav 			goto done;
416*7b5038d7SDag-Erling Smørgrav 		} else if (lc1 > 0 && lc2 == 0) {
417*7b5038d7SDag-Erling Smørgrav 			result = 1;
418*7b5038d7SDag-Erling Smørgrav 			goto done;
419*7b5038d7SDag-Erling Smørgrav 		} else if (lc1 == 0 && lc2 == 0) {
420*7b5038d7SDag-Erling Smørgrav 			result = 0;
421*7b5038d7SDag-Erling Smørgrav 			goto done;
422*7b5038d7SDag-Erling Smørgrav 		}
423*7b5038d7SDag-Erling Smørgrav 		lc1--;
424*7b5038d7SDag-Erling Smørgrav 		lc2--;
425*7b5038d7SDag-Erling Smørgrav 	}
426*7b5038d7SDag-Erling Smørgrav 
427*7b5038d7SDag-Erling Smørgrav 	done:
428*7b5038d7SDag-Erling Smørgrav 	return result;
429*7b5038d7SDag-Erling Smørgrav }
430*7b5038d7SDag-Erling Smørgrav 
431*7b5038d7SDag-Erling Smørgrav int
432*7b5038d7SDag-Erling Smørgrav ldns_dname_is_wildcard(const ldns_rdf* dname)
433*7b5038d7SDag-Erling Smørgrav {
434*7b5038d7SDag-Erling Smørgrav 	return ( ldns_dname_label_count(dname) > 0 &&
435*7b5038d7SDag-Erling Smørgrav 		 ldns_rdf_data(dname)[0] == 1 &&
436*7b5038d7SDag-Erling Smørgrav 		 ldns_rdf_data(dname)[1] == '*');
437*7b5038d7SDag-Erling Smørgrav }
438*7b5038d7SDag-Erling Smørgrav 
439*7b5038d7SDag-Erling Smørgrav int
440*7b5038d7SDag-Erling Smørgrav ldns_dname_match_wildcard(const ldns_rdf *dname, const ldns_rdf *wildcard)
441*7b5038d7SDag-Erling Smørgrav {
442*7b5038d7SDag-Erling Smørgrav 	ldns_rdf *wc_chopped;
443*7b5038d7SDag-Erling Smørgrav 	int result;
444*7b5038d7SDag-Erling Smørgrav 	/* check whether it really is a wildcard */
445*7b5038d7SDag-Erling Smørgrav 	if (ldns_dname_is_wildcard(wildcard)) {
446*7b5038d7SDag-Erling Smørgrav 		/* ok, so the dname needs to be a subdomain of the wildcard
447*7b5038d7SDag-Erling Smørgrav 		 * without the *
448*7b5038d7SDag-Erling Smørgrav 		 */
449*7b5038d7SDag-Erling Smørgrav 		wc_chopped = ldns_dname_left_chop(wildcard);
450*7b5038d7SDag-Erling Smørgrav 		result = (int) ldns_dname_is_subdomain(dname, wc_chopped);
451*7b5038d7SDag-Erling Smørgrav 		ldns_rdf_deep_free(wc_chopped);
452*7b5038d7SDag-Erling Smørgrav 	} else {
453*7b5038d7SDag-Erling Smørgrav 		result = (ldns_dname_compare(dname, wildcard) == 0);
454*7b5038d7SDag-Erling Smørgrav 	}
455*7b5038d7SDag-Erling Smørgrav 	return result;
456*7b5038d7SDag-Erling Smørgrav }
457*7b5038d7SDag-Erling Smørgrav 
458*7b5038d7SDag-Erling Smørgrav /* nsec test: does prev <= middle < next
459*7b5038d7SDag-Erling Smørgrav  * -1 = yes
460*7b5038d7SDag-Erling Smørgrav  * 0 = error/can't tell
461*7b5038d7SDag-Erling Smørgrav  * 1 = no
462*7b5038d7SDag-Erling Smørgrav  */
463*7b5038d7SDag-Erling Smørgrav int
464*7b5038d7SDag-Erling Smørgrav ldns_dname_interval(const ldns_rdf *prev, const ldns_rdf *middle,
465*7b5038d7SDag-Erling Smørgrav 		const ldns_rdf *next)
466*7b5038d7SDag-Erling Smørgrav {
467*7b5038d7SDag-Erling Smørgrav 	int prev_check, next_check;
468*7b5038d7SDag-Erling Smørgrav 
469*7b5038d7SDag-Erling Smørgrav 	assert(ldns_rdf_get_type(prev) == LDNS_RDF_TYPE_DNAME);
470*7b5038d7SDag-Erling Smørgrav 	assert(ldns_rdf_get_type(middle) == LDNS_RDF_TYPE_DNAME);
471*7b5038d7SDag-Erling Smørgrav 	assert(ldns_rdf_get_type(next) == LDNS_RDF_TYPE_DNAME);
472*7b5038d7SDag-Erling Smørgrav 
473*7b5038d7SDag-Erling Smørgrav 	prev_check = ldns_dname_compare(prev, middle);
474*7b5038d7SDag-Erling Smørgrav 	next_check = ldns_dname_compare(middle, next);
475*7b5038d7SDag-Erling Smørgrav 	/* <= next. This cannot be the case for nsec, because then we would
476*7b5038d7SDag-Erling Smørgrav 	 * have gotten the nsec of next...
477*7b5038d7SDag-Erling Smørgrav 	 */
478*7b5038d7SDag-Erling Smørgrav 	if (next_check == 0) {
479*7b5038d7SDag-Erling Smørgrav 		return 0;
480*7b5038d7SDag-Erling Smørgrav 	}
481*7b5038d7SDag-Erling Smørgrav 
482*7b5038d7SDag-Erling Smørgrav 			/* <= */
483*7b5038d7SDag-Erling Smørgrav 	if ((prev_check == -1 || prev_check == 0) &&
484*7b5038d7SDag-Erling Smørgrav 			/* < */
485*7b5038d7SDag-Erling Smørgrav 			next_check == -1) {
486*7b5038d7SDag-Erling Smørgrav 		return -1;
487*7b5038d7SDag-Erling Smørgrav 	} else {
488*7b5038d7SDag-Erling Smørgrav 		return 1;
489*7b5038d7SDag-Erling Smørgrav 	}
490*7b5038d7SDag-Erling Smørgrav }
491*7b5038d7SDag-Erling Smørgrav 
492*7b5038d7SDag-Erling Smørgrav 
493*7b5038d7SDag-Erling Smørgrav bool
494*7b5038d7SDag-Erling Smørgrav ldns_dname_str_absolute(const char *dname_str)
495*7b5038d7SDag-Erling Smørgrav {
496*7b5038d7SDag-Erling Smørgrav         const char* s;
497*7b5038d7SDag-Erling Smørgrav 	if(dname_str && strcmp(dname_str, ".") == 0)
498*7b5038d7SDag-Erling Smørgrav 		return 1;
499*7b5038d7SDag-Erling Smørgrav         if(!dname_str || strlen(dname_str) < 2)
500*7b5038d7SDag-Erling Smørgrav                 return 0;
501*7b5038d7SDag-Erling Smørgrav         if(dname_str[strlen(dname_str) - 1] != '.')
502*7b5038d7SDag-Erling Smørgrav                 return 0;
503*7b5038d7SDag-Erling Smørgrav         if(dname_str[strlen(dname_str) - 2] != '\\')
504*7b5038d7SDag-Erling Smørgrav                 return 1; /* ends in . and no \ before it */
505*7b5038d7SDag-Erling Smørgrav         /* so we have the case of ends in . and there is \ before it */
506*7b5038d7SDag-Erling Smørgrav         for(s=dname_str; *s; s++) {
507*7b5038d7SDag-Erling Smørgrav                 if(*s == '\\') {
508*7b5038d7SDag-Erling Smørgrav                         if(s[1] && s[2] && s[3] /* check length */
509*7b5038d7SDag-Erling Smørgrav                                 && isdigit(s[1]) && isdigit(s[2]) &&
510*7b5038d7SDag-Erling Smørgrav                                 isdigit(s[3]))
511*7b5038d7SDag-Erling Smørgrav                                 s += 3;
512*7b5038d7SDag-Erling Smørgrav                         else if(!s[1] || isdigit(s[1])) /* escape of nul,0-9 */
513*7b5038d7SDag-Erling Smørgrav                                 return 0; /* parse error */
514*7b5038d7SDag-Erling Smørgrav                         else s++; /* another character escaped */
515*7b5038d7SDag-Erling Smørgrav                 }
516*7b5038d7SDag-Erling Smørgrav                 else if(!*(s+1) && *s == '.')
517*7b5038d7SDag-Erling Smørgrav                         return 1; /* trailing dot, unescaped */
518*7b5038d7SDag-Erling Smørgrav         }
519*7b5038d7SDag-Erling Smørgrav         return 0;
520*7b5038d7SDag-Erling Smørgrav }
521*7b5038d7SDag-Erling Smørgrav 
522*7b5038d7SDag-Erling Smørgrav ldns_rdf *
523*7b5038d7SDag-Erling Smørgrav ldns_dname_label(const ldns_rdf *rdf, uint8_t labelpos)
524*7b5038d7SDag-Erling Smørgrav {
525*7b5038d7SDag-Erling Smørgrav 	uint8_t labelcnt;
526*7b5038d7SDag-Erling Smørgrav 	uint16_t src_pos;
527*7b5038d7SDag-Erling Smørgrav 	uint16_t len;
528*7b5038d7SDag-Erling Smørgrav 	ldns_rdf *tmpnew;
529*7b5038d7SDag-Erling Smørgrav 	size_t s;
530*7b5038d7SDag-Erling Smørgrav 	uint8_t *data;
531*7b5038d7SDag-Erling Smørgrav 
532*7b5038d7SDag-Erling Smørgrav 	if (ldns_rdf_get_type(rdf) != LDNS_RDF_TYPE_DNAME) {
533*7b5038d7SDag-Erling Smørgrav 		return NULL;
534*7b5038d7SDag-Erling Smørgrav 	}
535*7b5038d7SDag-Erling Smørgrav 
536*7b5038d7SDag-Erling Smørgrav 	labelcnt = 0;
537*7b5038d7SDag-Erling Smørgrav 	src_pos = 0;
538*7b5038d7SDag-Erling Smørgrav 	s = ldns_rdf_size(rdf);
539*7b5038d7SDag-Erling Smørgrav 
540*7b5038d7SDag-Erling Smørgrav 	len = ldns_rdf_data(rdf)[src_pos]; /* label start */
541*7b5038d7SDag-Erling Smørgrav 	while ((len > 0) && src_pos < s) {
542*7b5038d7SDag-Erling Smørgrav 		if (labelcnt == labelpos) {
543*7b5038d7SDag-Erling Smørgrav 			/* found our label */
544*7b5038d7SDag-Erling Smørgrav 			data = LDNS_XMALLOC(uint8_t, len + 2);
545*7b5038d7SDag-Erling Smørgrav 			if (!data) {
546*7b5038d7SDag-Erling Smørgrav 				return NULL;
547*7b5038d7SDag-Erling Smørgrav 			}
548*7b5038d7SDag-Erling Smørgrav 			memcpy(data, ldns_rdf_data(rdf) + src_pos, len + 1);
549*7b5038d7SDag-Erling Smørgrav 			data[len + 2 - 1] = 0;
550*7b5038d7SDag-Erling Smørgrav 
551*7b5038d7SDag-Erling Smørgrav 			tmpnew = ldns_rdf_new( LDNS_RDF_TYPE_DNAME
552*7b5038d7SDag-Erling Smørgrav 					     , len + 2, data);
553*7b5038d7SDag-Erling Smørgrav 			if (!tmpnew) {
554*7b5038d7SDag-Erling Smørgrav 				LDNS_FREE(data);
555*7b5038d7SDag-Erling Smørgrav 				return NULL;
556*7b5038d7SDag-Erling Smørgrav 			}
557*7b5038d7SDag-Erling Smørgrav 			return tmpnew;
558*7b5038d7SDag-Erling Smørgrav 		}
559*7b5038d7SDag-Erling Smørgrav 		src_pos++;
560*7b5038d7SDag-Erling Smørgrav 		src_pos += len;
561*7b5038d7SDag-Erling Smørgrav 		len = ldns_rdf_data(rdf)[src_pos];
562*7b5038d7SDag-Erling Smørgrav 		labelcnt++;
563*7b5038d7SDag-Erling Smørgrav 	}
564*7b5038d7SDag-Erling Smørgrav 	return NULL;
565*7b5038d7SDag-Erling Smørgrav }
566