xref: /dragonfly/contrib/ldns/dname.c (revision ee791feb)
1825eb42bSJan Lentfer /*
2825eb42bSJan Lentfer  * dname.c
3825eb42bSJan Lentfer  *
4825eb42bSJan Lentfer  * dname specific rdata implementations
5825eb42bSJan Lentfer  * A dname is a rdf structure with type LDNS_RDF_TYPE_DNAME
6*ee791febSAntonio Huete Jimenez  * It is not a /real/ type! All function must therefore check
7825eb42bSJan Lentfer  * for LDNS_RDF_TYPE_DNAME.
8825eb42bSJan Lentfer  *
9825eb42bSJan Lentfer  * a Net::DNS like library for C
10825eb42bSJan Lentfer  *
11825eb42bSJan Lentfer  * (c) NLnet Labs, 2004-2006
12825eb42bSJan Lentfer  *
13825eb42bSJan Lentfer  * See the file LICENSE for the license
14825eb42bSJan Lentfer  */
15825eb42bSJan Lentfer 
16825eb42bSJan Lentfer #include <ldns/config.h>
17825eb42bSJan Lentfer 
18825eb42bSJan Lentfer #include <ldns/ldns.h>
19825eb42bSJan Lentfer 
20825eb42bSJan Lentfer #ifdef HAVE_NETINET_IN_H
21825eb42bSJan Lentfer #include <netinet/in.h>
22825eb42bSJan Lentfer #endif
23825eb42bSJan Lentfer #ifdef HAVE_SYS_SOCKET_H
24825eb42bSJan Lentfer #include <sys/socket.h>
25825eb42bSJan Lentfer #endif
26825eb42bSJan Lentfer #ifdef HAVE_NETDB_H
27825eb42bSJan Lentfer #include <netdb.h>
28825eb42bSJan Lentfer #endif
29825eb42bSJan Lentfer #ifdef HAVE_ARPA_INET_H
30825eb42bSJan Lentfer #include <arpa/inet.h>
31825eb42bSJan Lentfer #endif
32825eb42bSJan Lentfer 
33d1b2b5caSJohn Marino /* Returns whether the last label in the name is a root label (a empty label).
34d1b2b5caSJohn Marino  * Note that it is not enough to just test the last character to be 0,
35d1b2b5caSJohn Marino  * because it may be part of the last label itself.
36d1b2b5caSJohn Marino  */
37d1b2b5caSJohn Marino static bool
ldns_dname_last_label_is_root_label(const ldns_rdf * dname)38d1b2b5caSJohn Marino ldns_dname_last_label_is_root_label(const ldns_rdf* dname)
39d1b2b5caSJohn Marino {
40d1b2b5caSJohn Marino 	size_t src_pos;
41d1b2b5caSJohn Marino 	size_t len = 0;
42d1b2b5caSJohn Marino 
43d1b2b5caSJohn Marino 	for (src_pos = 0; src_pos < ldns_rdf_size(dname); src_pos += len + 1) {
44d1b2b5caSJohn Marino 		len = ldns_rdf_data(dname)[src_pos];
45d1b2b5caSJohn Marino 	}
46d1b2b5caSJohn Marino 	assert(src_pos == ldns_rdf_size(dname));
47d1b2b5caSJohn Marino 
48d1b2b5caSJohn Marino 	return src_pos > 0 && len == 0;
49d1b2b5caSJohn Marino }
50d1b2b5caSJohn Marino 
51825eb42bSJan Lentfer ldns_rdf *
ldns_dname_cat_clone(const ldns_rdf * rd1,const ldns_rdf * rd2)52825eb42bSJan Lentfer ldns_dname_cat_clone(const ldns_rdf *rd1, const ldns_rdf *rd2)
53825eb42bSJan Lentfer {
54825eb42bSJan Lentfer 	ldns_rdf *new;
55825eb42bSJan Lentfer 	uint16_t new_size;
56825eb42bSJan Lentfer 	uint8_t *buf;
57825eb42bSJan Lentfer 	uint16_t left_size;
58825eb42bSJan Lentfer 
59825eb42bSJan Lentfer 	if (ldns_rdf_get_type(rd1) != LDNS_RDF_TYPE_DNAME ||
60825eb42bSJan Lentfer 			ldns_rdf_get_type(rd2) != LDNS_RDF_TYPE_DNAME) {
61825eb42bSJan Lentfer 		return NULL;
62825eb42bSJan Lentfer 	}
63825eb42bSJan Lentfer 
64825eb42bSJan Lentfer 	/* remove root label if it is present at the end of the left
65825eb42bSJan Lentfer 	 * rd, by reducing the size with 1
66825eb42bSJan Lentfer 	 */
67825eb42bSJan Lentfer 	left_size = ldns_rdf_size(rd1);
68d1b2b5caSJohn Marino 	if (ldns_dname_last_label_is_root_label(rd1)) {
69825eb42bSJan Lentfer 		left_size--;
70825eb42bSJan Lentfer 	}
71825eb42bSJan Lentfer 
72825eb42bSJan Lentfer 	/* we overwrite the nullbyte of rd1 */
73825eb42bSJan Lentfer 	new_size = left_size + ldns_rdf_size(rd2);
74825eb42bSJan Lentfer 	buf = LDNS_XMALLOC(uint8_t, new_size);
75825eb42bSJan Lentfer 	if (!buf) {
76825eb42bSJan Lentfer 		return NULL;
77825eb42bSJan Lentfer 	}
78825eb42bSJan Lentfer 
79825eb42bSJan Lentfer 	/* put the two dname's after each other */
80825eb42bSJan Lentfer 	memcpy(buf, ldns_rdf_data(rd1), left_size);
81825eb42bSJan Lentfer 	memcpy(buf + left_size, ldns_rdf_data(rd2), ldns_rdf_size(rd2));
82825eb42bSJan Lentfer 
83825eb42bSJan Lentfer 	new = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_DNAME, new_size, buf);
84825eb42bSJan Lentfer 
85825eb42bSJan Lentfer 	LDNS_FREE(buf);
86825eb42bSJan Lentfer 	return new;
87825eb42bSJan Lentfer }
88825eb42bSJan Lentfer 
89825eb42bSJan Lentfer ldns_status
ldns_dname_cat(ldns_rdf * rd1,const ldns_rdf * rd2)905340022aSzrj ldns_dname_cat(ldns_rdf *rd1, const ldns_rdf *rd2)
91825eb42bSJan Lentfer {
92825eb42bSJan Lentfer 	uint16_t left_size;
93825eb42bSJan Lentfer 	uint16_t size;
94ac996e71SJan Lentfer 	uint8_t* newd;
95825eb42bSJan Lentfer 
96825eb42bSJan Lentfer 	if (ldns_rdf_get_type(rd1) != LDNS_RDF_TYPE_DNAME ||
97825eb42bSJan Lentfer 			ldns_rdf_get_type(rd2) != LDNS_RDF_TYPE_DNAME) {
98825eb42bSJan Lentfer 		return LDNS_STATUS_ERR;
99825eb42bSJan Lentfer 	}
100825eb42bSJan Lentfer 
101825eb42bSJan Lentfer 	/* remove root label if it is present at the end of the left
102825eb42bSJan Lentfer 	 * rd, by reducing the size with 1
103825eb42bSJan Lentfer 	 */
104825eb42bSJan Lentfer 	left_size = ldns_rdf_size(rd1);
105d1b2b5caSJohn Marino 	if (ldns_dname_last_label_is_root_label(rd1)) {
106825eb42bSJan Lentfer 		left_size--;
107825eb42bSJan Lentfer 	}
108825eb42bSJan Lentfer 
109825eb42bSJan Lentfer 	size = left_size + ldns_rdf_size(rd2);
110ac996e71SJan Lentfer 	newd = LDNS_XREALLOC(ldns_rdf_data(rd1), uint8_t, size);
111ac996e71SJan Lentfer 	if(!newd) {
112ac996e71SJan Lentfer 		return LDNS_STATUS_MEM_ERR;
113ac996e71SJan Lentfer 	}
114825eb42bSJan Lentfer 
115ac996e71SJan Lentfer 	ldns_rdf_set_data(rd1, newd);
116825eb42bSJan Lentfer 	memcpy(ldns_rdf_data(rd1) + left_size, ldns_rdf_data(rd2),
117825eb42bSJan Lentfer 			ldns_rdf_size(rd2));
118825eb42bSJan Lentfer 	ldns_rdf_set_size(rd1, size);
119825eb42bSJan Lentfer 
120825eb42bSJan Lentfer 	return LDNS_STATUS_OK;
121825eb42bSJan Lentfer }
122825eb42bSJan Lentfer 
123825eb42bSJan Lentfer ldns_rdf*
ldns_dname_reverse(const ldns_rdf * dname)124d1b2b5caSJohn Marino ldns_dname_reverse(const ldns_rdf *dname)
125825eb42bSJan Lentfer {
126d1b2b5caSJohn Marino 	size_t rd_size;
127d1b2b5caSJohn Marino 	uint8_t* buf;
128825eb42bSJan Lentfer 	ldns_rdf* new;
129d1b2b5caSJohn Marino 	size_t src_pos;
130d1b2b5caSJohn Marino 	size_t len ;
131825eb42bSJan Lentfer 
132d1b2b5caSJohn Marino 	assert(ldns_rdf_get_type(dname) == LDNS_RDF_TYPE_DNAME);
133825eb42bSJan Lentfer 
134d1b2b5caSJohn Marino 	rd_size = ldns_rdf_size(dname);
135d1b2b5caSJohn Marino 	buf = LDNS_XMALLOC(uint8_t, rd_size);
136d1b2b5caSJohn Marino 	if (! buf) {
137ac996e71SJan Lentfer 		return NULL;
138ac996e71SJan Lentfer 	}
139d1b2b5caSJohn Marino 	new = ldns_rdf_new(LDNS_RDF_TYPE_DNAME, rd_size, buf);
140d1b2b5caSJohn Marino 	if (! new) {
141d1b2b5caSJohn Marino 		LDNS_FREE(buf);
142d1b2b5caSJohn Marino 		return NULL;
143825eb42bSJan Lentfer 	}
144825eb42bSJan Lentfer 
145d1b2b5caSJohn Marino 	/* If dname ends in a root label, the reverse should too.
146d1b2b5caSJohn Marino 	 */
147d1b2b5caSJohn Marino 	if (ldns_dname_last_label_is_root_label(dname)) {
148d1b2b5caSJohn Marino 		buf[rd_size - 1] = 0;
149d1b2b5caSJohn Marino 		rd_size -= 1;
150d1b2b5caSJohn Marino 	}
151d1b2b5caSJohn Marino 	for (src_pos = 0; src_pos < rd_size; src_pos += len + 1) {
152d1b2b5caSJohn Marino 		len = ldns_rdf_data(dname)[src_pos];
153d1b2b5caSJohn Marino 		memcpy(&buf[rd_size - src_pos - len - 1],
154d1b2b5caSJohn Marino 				&ldns_rdf_data(dname)[src_pos], len + 1);
155d1b2b5caSJohn Marino 	}
156825eb42bSJan Lentfer 	return new;
157825eb42bSJan Lentfer }
158825eb42bSJan Lentfer 
159825eb42bSJan Lentfer ldns_rdf *
ldns_dname_clone_from(const ldns_rdf * d,uint16_t n)160825eb42bSJan Lentfer ldns_dname_clone_from(const ldns_rdf *d, uint16_t n)
161825eb42bSJan Lentfer {
162825eb42bSJan Lentfer 	uint8_t *data;
163825eb42bSJan Lentfer 	uint8_t label_size;
164825eb42bSJan Lentfer 	size_t data_size;
165825eb42bSJan Lentfer 
166825eb42bSJan Lentfer 	if (!d ||
167825eb42bSJan Lentfer 	    ldns_rdf_get_type(d) != LDNS_RDF_TYPE_DNAME ||
168825eb42bSJan Lentfer 	    ldns_dname_label_count(d) < n) {
169825eb42bSJan Lentfer 		return NULL;
170825eb42bSJan Lentfer 	}
171825eb42bSJan Lentfer 
172825eb42bSJan Lentfer 	data = ldns_rdf_data(d);
173825eb42bSJan Lentfer 	data_size = ldns_rdf_size(d);
174825eb42bSJan Lentfer 	while (n > 0) {
175825eb42bSJan Lentfer 		label_size = data[0] + 1;
176825eb42bSJan Lentfer 		data += label_size;
177825eb42bSJan Lentfer 		if (data_size < label_size) {
178825eb42bSJan Lentfer 			/* this label is very broken */
179825eb42bSJan Lentfer 			return NULL;
180825eb42bSJan Lentfer 		}
181825eb42bSJan Lentfer 		data_size -= label_size;
182825eb42bSJan Lentfer 		n--;
183825eb42bSJan Lentfer 	}
184825eb42bSJan Lentfer 
185825eb42bSJan Lentfer 	return ldns_dname_new_frm_data(data_size, data);
186825eb42bSJan Lentfer }
187825eb42bSJan Lentfer 
188825eb42bSJan Lentfer ldns_rdf *
ldns_dname_left_chop(const ldns_rdf * d)189825eb42bSJan Lentfer ldns_dname_left_chop(const ldns_rdf *d)
190825eb42bSJan Lentfer {
191825eb42bSJan Lentfer 	uint8_t label_pos;
192825eb42bSJan Lentfer 	ldns_rdf *chop;
193825eb42bSJan Lentfer 
194825eb42bSJan Lentfer 	if (!d) {
195825eb42bSJan Lentfer 		return NULL;
196825eb42bSJan Lentfer 	}
197825eb42bSJan Lentfer 
198825eb42bSJan Lentfer 	if (ldns_rdf_get_type(d) != LDNS_RDF_TYPE_DNAME) {
199825eb42bSJan Lentfer 		return NULL;
200825eb42bSJan Lentfer 	}
201825eb42bSJan Lentfer 	if (ldns_dname_label_count(d) == 0) {
202825eb42bSJan Lentfer 		/* root label */
203825eb42bSJan Lentfer 		return NULL;
204825eb42bSJan Lentfer 	}
205825eb42bSJan Lentfer 	/* 05blaat02nl00 */
206825eb42bSJan Lentfer 	label_pos = ldns_rdf_data(d)[0];
207825eb42bSJan Lentfer 
208825eb42bSJan Lentfer 	chop = ldns_dname_new_frm_data(ldns_rdf_size(d) - label_pos - 1,
209825eb42bSJan Lentfer 			ldns_rdf_data(d) + label_pos + 1);
210825eb42bSJan Lentfer 	return chop;
211825eb42bSJan Lentfer }
212825eb42bSJan Lentfer 
213825eb42bSJan Lentfer uint8_t
ldns_dname_label_count(const ldns_rdf * r)214825eb42bSJan Lentfer ldns_dname_label_count(const ldns_rdf *r)
215825eb42bSJan Lentfer {
216825eb42bSJan Lentfer         uint16_t src_pos;
217825eb42bSJan Lentfer         uint16_t len;
218825eb42bSJan Lentfer         uint8_t i;
219825eb42bSJan Lentfer         size_t r_size;
220825eb42bSJan Lentfer 
221825eb42bSJan Lentfer 	if (!r) {
222825eb42bSJan Lentfer 		return 0;
223825eb42bSJan Lentfer 	}
224825eb42bSJan Lentfer 
225825eb42bSJan Lentfer 	i = 0;
226825eb42bSJan Lentfer 	src_pos = 0;
227825eb42bSJan Lentfer 	r_size = ldns_rdf_size(r);
228825eb42bSJan Lentfer 
229825eb42bSJan Lentfer 	if (ldns_rdf_get_type(r) != LDNS_RDF_TYPE_DNAME) {
230825eb42bSJan Lentfer 		return 0;
231825eb42bSJan Lentfer 	} else {
232825eb42bSJan Lentfer 		len = ldns_rdf_data(r)[src_pos]; /* start of the label */
233825eb42bSJan Lentfer 
234825eb42bSJan Lentfer 		/* single root label */
235825eb42bSJan Lentfer 		if (1 == r_size) {
236825eb42bSJan Lentfer 			return 0;
237825eb42bSJan Lentfer 		} else {
238825eb42bSJan Lentfer 			while ((len > 0) && src_pos < r_size) {
239825eb42bSJan Lentfer 				src_pos++;
240825eb42bSJan Lentfer 				src_pos += len;
241825eb42bSJan Lentfer 				len = ldns_rdf_data(r)[src_pos];
242825eb42bSJan Lentfer 				i++;
243825eb42bSJan Lentfer 			}
244825eb42bSJan Lentfer 		}
245825eb42bSJan Lentfer 	}
246825eb42bSJan Lentfer 	return i;
247825eb42bSJan Lentfer }
248825eb42bSJan Lentfer 
249825eb42bSJan Lentfer ldns_rdf *
ldns_dname_new(uint16_t s,void * d)250825eb42bSJan Lentfer ldns_dname_new(uint16_t s, void *d)
251825eb42bSJan Lentfer {
252825eb42bSJan Lentfer         ldns_rdf *rd;
253825eb42bSJan Lentfer 
2545340022aSzrj         if (!s || !d) {
2555340022aSzrj                 return NULL;
2565340022aSzrj         }
257825eb42bSJan Lentfer         rd = LDNS_MALLOC(ldns_rdf);
258825eb42bSJan Lentfer         if (!rd) {
259825eb42bSJan Lentfer                 return NULL;
260825eb42bSJan Lentfer         }
261825eb42bSJan Lentfer         ldns_rdf_set_size(rd, s);
262825eb42bSJan Lentfer         ldns_rdf_set_type(rd, LDNS_RDF_TYPE_DNAME);
263825eb42bSJan Lentfer         ldns_rdf_set_data(rd, d);
264825eb42bSJan Lentfer         return rd;
265825eb42bSJan Lentfer }
266825eb42bSJan Lentfer 
267825eb42bSJan Lentfer ldns_rdf *
ldns_dname_new_frm_str(const char * str)268825eb42bSJan Lentfer ldns_dname_new_frm_str(const char *str)
269825eb42bSJan Lentfer {
270825eb42bSJan Lentfer 	return ldns_rdf_new_frm_str(LDNS_RDF_TYPE_DNAME, str);
271825eb42bSJan Lentfer }
272825eb42bSJan Lentfer 
273825eb42bSJan Lentfer ldns_rdf *
ldns_dname_new_frm_data(uint16_t size,const void * data)274825eb42bSJan Lentfer ldns_dname_new_frm_data(uint16_t size, const void *data)
275825eb42bSJan Lentfer {
276825eb42bSJan Lentfer 	return ldns_rdf_new_frm_data(LDNS_RDF_TYPE_DNAME, size, data);
277825eb42bSJan Lentfer }
278825eb42bSJan Lentfer 
279825eb42bSJan Lentfer void
ldns_dname2canonical(const ldns_rdf * rd)280825eb42bSJan Lentfer ldns_dname2canonical(const ldns_rdf *rd)
281825eb42bSJan Lentfer {
282825eb42bSJan Lentfer 	uint8_t *rdd;
283825eb42bSJan Lentfer 	uint16_t i;
284825eb42bSJan Lentfer 
285825eb42bSJan Lentfer 	if (ldns_rdf_get_type(rd) != LDNS_RDF_TYPE_DNAME) {
286825eb42bSJan Lentfer 		return;
287825eb42bSJan Lentfer 	}
288825eb42bSJan Lentfer 
289825eb42bSJan Lentfer 	rdd = (uint8_t*)ldns_rdf_data(rd);
290825eb42bSJan Lentfer 	for (i = 0; i < ldns_rdf_size(rd); i++, rdd++) {
291825eb42bSJan Lentfer 		*rdd = (uint8_t)LDNS_DNAME_NORMALIZE((int)*rdd);
292825eb42bSJan Lentfer 	}
293825eb42bSJan Lentfer }
294825eb42bSJan Lentfer 
295825eb42bSJan Lentfer bool
ldns_dname_is_subdomain(const ldns_rdf * sub,const ldns_rdf * parent)296825eb42bSJan Lentfer ldns_dname_is_subdomain(const ldns_rdf *sub, const ldns_rdf *parent)
297825eb42bSJan Lentfer {
298825eb42bSJan Lentfer 	uint8_t sub_lab;
299825eb42bSJan Lentfer 	uint8_t par_lab;
300825eb42bSJan Lentfer 	int8_t i, j;
301825eb42bSJan Lentfer 	ldns_rdf *tmp_sub = NULL;
302825eb42bSJan Lentfer 	ldns_rdf *tmp_par = NULL;
303825eb42bSJan Lentfer     ldns_rdf *sub_clone;
304825eb42bSJan Lentfer     ldns_rdf *parent_clone;
305825eb42bSJan Lentfer     bool result = true;
306825eb42bSJan Lentfer 
307825eb42bSJan Lentfer 	if (ldns_rdf_get_type(sub) != LDNS_RDF_TYPE_DNAME ||
308825eb42bSJan Lentfer 			ldns_rdf_get_type(parent) != LDNS_RDF_TYPE_DNAME ||
309825eb42bSJan Lentfer 			ldns_rdf_compare(sub, parent) == 0) {
310825eb42bSJan Lentfer 		return false;
311825eb42bSJan Lentfer 	}
312825eb42bSJan Lentfer 
313825eb42bSJan Lentfer     /* would be nicer if we do not have to clone... */
314825eb42bSJan Lentfer     sub_clone = ldns_dname_clone_from(sub, 0);
315825eb42bSJan Lentfer     parent_clone = ldns_dname_clone_from(parent, 0);
316825eb42bSJan Lentfer     ldns_dname2canonical(sub_clone);
317825eb42bSJan Lentfer     ldns_dname2canonical(parent_clone);
318825eb42bSJan Lentfer 
319825eb42bSJan Lentfer 	sub_lab = ldns_dname_label_count(sub_clone);
320825eb42bSJan Lentfer 	par_lab = ldns_dname_label_count(parent_clone);
321825eb42bSJan Lentfer 
322825eb42bSJan Lentfer 	/* if sub sits above parent, it cannot be a child/sub domain */
323825eb42bSJan Lentfer 	if (sub_lab < par_lab) {
324825eb42bSJan Lentfer 		result = false;
325825eb42bSJan Lentfer 	} else {
326825eb42bSJan Lentfer 		/* check all labels the from the parent labels, from right to left.
327825eb42bSJan Lentfer 		 * When they /all/ match we have found a subdomain
328825eb42bSJan Lentfer 		 */
329825eb42bSJan Lentfer 		j = sub_lab - 1; /* we count from zero, thank you */
330825eb42bSJan Lentfer 		for (i = par_lab -1; i >= 0; i--) {
331825eb42bSJan Lentfer 			tmp_sub = ldns_dname_label(sub_clone, j);
332825eb42bSJan Lentfer 			tmp_par = ldns_dname_label(parent_clone, i);
333825eb42bSJan Lentfer 			if (!tmp_sub || !tmp_par) {
334825eb42bSJan Lentfer 				/* deep free does null check */
335825eb42bSJan Lentfer 				ldns_rdf_deep_free(tmp_sub);
336825eb42bSJan Lentfer 				ldns_rdf_deep_free(tmp_par);
337825eb42bSJan Lentfer 				result = false;
338825eb42bSJan Lentfer 				break;
339825eb42bSJan Lentfer 			}
340825eb42bSJan Lentfer 
341825eb42bSJan Lentfer 			if (ldns_rdf_compare(tmp_sub, tmp_par) != 0) {
342825eb42bSJan Lentfer 				/* they are not equal */
343825eb42bSJan Lentfer 				ldns_rdf_deep_free(tmp_sub);
344825eb42bSJan Lentfer 				ldns_rdf_deep_free(tmp_par);
345825eb42bSJan Lentfer 				result = false;
346825eb42bSJan Lentfer 				break;
347825eb42bSJan Lentfer 			}
348825eb42bSJan Lentfer 			ldns_rdf_deep_free(tmp_sub);
349825eb42bSJan Lentfer 			ldns_rdf_deep_free(tmp_par);
350825eb42bSJan Lentfer 			j--;
351825eb42bSJan Lentfer 		}
352825eb42bSJan Lentfer 	}
353825eb42bSJan Lentfer 	ldns_rdf_deep_free(sub_clone);
354825eb42bSJan Lentfer 	ldns_rdf_deep_free(parent_clone);
355825eb42bSJan Lentfer 	return result;
356825eb42bSJan Lentfer }
357825eb42bSJan Lentfer 
358825eb42bSJan Lentfer int
ldns_dname_compare(const ldns_rdf * dname1,const ldns_rdf * dname2)359825eb42bSJan Lentfer ldns_dname_compare(const ldns_rdf *dname1, const ldns_rdf *dname2)
360825eb42bSJan Lentfer {
361825eb42bSJan Lentfer 	size_t lc1, lc2, lc1f, lc2f;
362825eb42bSJan Lentfer 	size_t i;
363825eb42bSJan Lentfer 	int result = 0;
364825eb42bSJan Lentfer 	uint8_t *lp1, *lp2;
365825eb42bSJan Lentfer 
366825eb42bSJan Lentfer 	/* see RFC4034 for this algorithm */
367825eb42bSJan Lentfer 	/* this algorithm assumes the names are normalized to case */
368825eb42bSJan Lentfer 
369825eb42bSJan Lentfer         /* only when both are not NULL we can say anything about them */
370825eb42bSJan Lentfer         if (!dname1 && !dname2) {
371825eb42bSJan Lentfer                 return 0;
372825eb42bSJan Lentfer         }
373825eb42bSJan Lentfer         if (!dname1 || !dname2) {
374825eb42bSJan Lentfer                 return -1;
375825eb42bSJan Lentfer         }
376825eb42bSJan Lentfer 	/* asserts must happen later as we are looking in the
377825eb42bSJan Lentfer 	 * dname, which could be NULL. But this case is handled
378825eb42bSJan Lentfer 	 * above
379825eb42bSJan Lentfer 	 */
380825eb42bSJan Lentfer 	assert(ldns_rdf_get_type(dname1) == LDNS_RDF_TYPE_DNAME);
381825eb42bSJan Lentfer 	assert(ldns_rdf_get_type(dname2) == LDNS_RDF_TYPE_DNAME);
382825eb42bSJan Lentfer 
383825eb42bSJan Lentfer 	lc1 = ldns_dname_label_count(dname1);
384825eb42bSJan Lentfer 	lc2 = ldns_dname_label_count(dname2);
385825eb42bSJan Lentfer 
386825eb42bSJan Lentfer 	if (lc1 == 0 && lc2 == 0) {
387825eb42bSJan Lentfer 		return 0;
388825eb42bSJan Lentfer 	}
389825eb42bSJan Lentfer 	if (lc1 == 0) {
390825eb42bSJan Lentfer 		return -1;
391825eb42bSJan Lentfer 	}
392825eb42bSJan Lentfer 	if (lc2 == 0) {
393825eb42bSJan Lentfer 		return 1;
394825eb42bSJan Lentfer 	}
395825eb42bSJan Lentfer 	lc1--;
396825eb42bSJan Lentfer 	lc2--;
397825eb42bSJan Lentfer 	/* we start at the last label */
398825eb42bSJan Lentfer 	while (true) {
399825eb42bSJan Lentfer 		/* find the label first */
400825eb42bSJan Lentfer 		lc1f = lc1;
401825eb42bSJan Lentfer 		lp1 = ldns_rdf_data(dname1);
402825eb42bSJan Lentfer 		while (lc1f > 0) {
403825eb42bSJan Lentfer 			lp1 += *lp1 + 1;
404825eb42bSJan Lentfer 			lc1f--;
405825eb42bSJan Lentfer 		}
406825eb42bSJan Lentfer 
407825eb42bSJan Lentfer 		/* and find the other one */
408825eb42bSJan Lentfer 		lc2f = lc2;
409825eb42bSJan Lentfer 		lp2 = ldns_rdf_data(dname2);
410825eb42bSJan Lentfer 		while (lc2f > 0) {
411825eb42bSJan Lentfer 			lp2 += *lp2 + 1;
412825eb42bSJan Lentfer 			lc2f--;
413825eb42bSJan Lentfer 		}
414825eb42bSJan Lentfer 
415825eb42bSJan Lentfer 		/* now check the label character for character. */
416825eb42bSJan Lentfer 		for (i = 1; i < (size_t)(*lp1 + 1); i++) {
417825eb42bSJan Lentfer 			if (i > *lp2) {
418825eb42bSJan Lentfer 				/* apparently label 1 is larger */
419825eb42bSJan Lentfer 				result = 1;
420825eb42bSJan Lentfer 				goto done;
421825eb42bSJan Lentfer 			}
422825eb42bSJan Lentfer 			if (LDNS_DNAME_NORMALIZE((int) *(lp1 + i)) <
423825eb42bSJan Lentfer 			    LDNS_DNAME_NORMALIZE((int) *(lp2 + i))) {
424825eb42bSJan Lentfer 			    result = -1;
425825eb42bSJan Lentfer 			    goto done;
426825eb42bSJan Lentfer 			} else if (LDNS_DNAME_NORMALIZE((int) *(lp1 + i)) >
427825eb42bSJan Lentfer 			    LDNS_DNAME_NORMALIZE((int) *(lp2 + i))) {
428825eb42bSJan Lentfer 			    result = 1;
429825eb42bSJan Lentfer 			    goto done;
430825eb42bSJan Lentfer 			}
431825eb42bSJan Lentfer 		}
432825eb42bSJan Lentfer 		if (*lp1 < *lp2) {
433825eb42bSJan Lentfer 			/* apparently label 2 is larger */
434825eb42bSJan Lentfer 			result = -1;
435825eb42bSJan Lentfer 			goto done;
436825eb42bSJan Lentfer 		}
437825eb42bSJan Lentfer 		if (lc1 == 0 && lc2 > 0) {
438825eb42bSJan Lentfer 			result = -1;
439825eb42bSJan Lentfer 			goto done;
440825eb42bSJan Lentfer 		} else if (lc1 > 0 && lc2 == 0) {
441825eb42bSJan Lentfer 			result = 1;
442825eb42bSJan Lentfer 			goto done;
443825eb42bSJan Lentfer 		} else if (lc1 == 0 && lc2 == 0) {
444825eb42bSJan Lentfer 			result = 0;
445825eb42bSJan Lentfer 			goto done;
446825eb42bSJan Lentfer 		}
447825eb42bSJan Lentfer 		lc1--;
448825eb42bSJan Lentfer 		lc2--;
449825eb42bSJan Lentfer 	}
450825eb42bSJan Lentfer 
451825eb42bSJan Lentfer 	done:
452825eb42bSJan Lentfer 	return result;
453825eb42bSJan Lentfer }
454825eb42bSJan Lentfer 
455825eb42bSJan Lentfer int
ldns_dname_is_wildcard(const ldns_rdf * dname)456ac996e71SJan Lentfer ldns_dname_is_wildcard(const ldns_rdf* dname)
457ac996e71SJan Lentfer {
458ac996e71SJan Lentfer 	return ( ldns_dname_label_count(dname) > 0 &&
459ac996e71SJan Lentfer 		 ldns_rdf_data(dname)[0] == 1 &&
460ac996e71SJan Lentfer 		 ldns_rdf_data(dname)[1] == '*');
461ac996e71SJan Lentfer }
462ac996e71SJan Lentfer 
463ac996e71SJan Lentfer int
ldns_dname_match_wildcard(const ldns_rdf * dname,const ldns_rdf * wildcard)464825eb42bSJan Lentfer ldns_dname_match_wildcard(const ldns_rdf *dname, const ldns_rdf *wildcard)
465825eb42bSJan Lentfer {
466825eb42bSJan Lentfer 	ldns_rdf *wc_chopped;
467825eb42bSJan Lentfer 	int result;
468825eb42bSJan Lentfer 	/* check whether it really is a wildcard */
469ac996e71SJan Lentfer 	if (ldns_dname_is_wildcard(wildcard)) {
470825eb42bSJan Lentfer 		/* ok, so the dname needs to be a subdomain of the wildcard
471825eb42bSJan Lentfer 		 * without the *
472825eb42bSJan Lentfer 		 */
473825eb42bSJan Lentfer 		wc_chopped = ldns_dname_left_chop(wildcard);
474825eb42bSJan Lentfer 		result = (int) ldns_dname_is_subdomain(dname, wc_chopped);
475825eb42bSJan Lentfer 		ldns_rdf_deep_free(wc_chopped);
476825eb42bSJan Lentfer 	} else {
477825eb42bSJan Lentfer 		result = (ldns_dname_compare(dname, wildcard) == 0);
478825eb42bSJan Lentfer 	}
479825eb42bSJan Lentfer 	return result;
480825eb42bSJan Lentfer }
481825eb42bSJan Lentfer 
482825eb42bSJan Lentfer /* nsec test: does prev <= middle < next
483825eb42bSJan Lentfer  * -1 = yes
484825eb42bSJan Lentfer  * 0 = error/can't tell
485825eb42bSJan Lentfer  * 1 = no
486825eb42bSJan Lentfer  */
487825eb42bSJan Lentfer int
ldns_dname_interval(const ldns_rdf * prev,const ldns_rdf * middle,const ldns_rdf * next)488825eb42bSJan Lentfer ldns_dname_interval(const ldns_rdf *prev, const ldns_rdf *middle,
489825eb42bSJan Lentfer 		const ldns_rdf *next)
490825eb42bSJan Lentfer {
491825eb42bSJan Lentfer 	int prev_check, next_check;
492825eb42bSJan Lentfer 
493825eb42bSJan Lentfer 	assert(ldns_rdf_get_type(prev) == LDNS_RDF_TYPE_DNAME);
494825eb42bSJan Lentfer 	assert(ldns_rdf_get_type(middle) == LDNS_RDF_TYPE_DNAME);
495825eb42bSJan Lentfer 	assert(ldns_rdf_get_type(next) == LDNS_RDF_TYPE_DNAME);
496825eb42bSJan Lentfer 
497825eb42bSJan Lentfer 	prev_check = ldns_dname_compare(prev, middle);
498825eb42bSJan Lentfer 	next_check = ldns_dname_compare(middle, next);
499825eb42bSJan Lentfer 	/* <= next. This cannot be the case for nsec, because then we would
500825eb42bSJan Lentfer 	 * have gotten the nsec of next...
501825eb42bSJan Lentfer 	 */
502825eb42bSJan Lentfer 	if (next_check == 0) {
503825eb42bSJan Lentfer 		return 0;
504825eb42bSJan Lentfer 	}
505825eb42bSJan Lentfer 
506825eb42bSJan Lentfer 			/* <= */
507825eb42bSJan Lentfer 	if ((prev_check == -1 || prev_check == 0) &&
508825eb42bSJan Lentfer 			/* < */
509825eb42bSJan Lentfer 			next_check == -1) {
510825eb42bSJan Lentfer 		return -1;
511825eb42bSJan Lentfer 	} else {
512825eb42bSJan Lentfer 		return 1;
513825eb42bSJan Lentfer 	}
514825eb42bSJan Lentfer }
515825eb42bSJan Lentfer 
516825eb42bSJan Lentfer 
517825eb42bSJan Lentfer bool
ldns_dname_str_absolute(const char * dname_str)518825eb42bSJan Lentfer ldns_dname_str_absolute(const char *dname_str)
519825eb42bSJan Lentfer {
520ac996e71SJan Lentfer         const char* s;
521825eb42bSJan Lentfer 	if(dname_str && strcmp(dname_str, ".") == 0)
522825eb42bSJan Lentfer 		return 1;
523ac996e71SJan Lentfer         if(!dname_str || strlen(dname_str) < 2)
524ac996e71SJan Lentfer                 return 0;
525ac996e71SJan Lentfer         if(dname_str[strlen(dname_str) - 1] != '.')
526ac996e71SJan Lentfer                 return 0;
527ac996e71SJan Lentfer         if(dname_str[strlen(dname_str) - 2] != '\\')
528ac996e71SJan Lentfer                 return 1; /* ends in . and no \ before it */
529ac996e71SJan Lentfer         /* so we have the case of ends in . and there is \ before it */
530ac996e71SJan Lentfer         for(s=dname_str; *s; s++) {
531ac996e71SJan Lentfer                 if(*s == '\\') {
532ac996e71SJan Lentfer                         if(s[1] && s[2] && s[3] /* check length */
5335340022aSzrj                                 && isdigit((unsigned char)s[1])
5345340022aSzrj 				&& isdigit((unsigned char)s[2])
5355340022aSzrj 				&& isdigit((unsigned char)s[3]))
536ac996e71SJan Lentfer                                 s += 3;
5375340022aSzrj                         else if(!s[1] || isdigit((unsigned char)s[1])) /* escape of nul,0-9 */
538ac996e71SJan Lentfer                                 return 0; /* parse error */
539ac996e71SJan Lentfer                         else s++; /* another character escaped */
540ac996e71SJan Lentfer                 }
541ac996e71SJan Lentfer                 else if(!*(s+1) && *s == '.')
542ac996e71SJan Lentfer                         return 1; /* trailing dot, unescaped */
543ac996e71SJan Lentfer         }
544ac996e71SJan Lentfer         return 0;
545825eb42bSJan Lentfer }
546825eb42bSJan Lentfer 
547d1b2b5caSJohn Marino bool
ldns_dname_absolute(const ldns_rdf * rdf)548d1b2b5caSJohn Marino ldns_dname_absolute(const ldns_rdf *rdf)
549d1b2b5caSJohn Marino {
550d1b2b5caSJohn Marino 	char *str = ldns_rdf2str(rdf);
551d1b2b5caSJohn Marino 	if (str) {
552d1b2b5caSJohn Marino 		bool r = ldns_dname_str_absolute(str);
553d1b2b5caSJohn Marino 		LDNS_FREE(str);
554d1b2b5caSJohn Marino 		return r;
555d1b2b5caSJohn Marino 	}
556d1b2b5caSJohn Marino 	return false;
557d1b2b5caSJohn Marino }
558d1b2b5caSJohn Marino 
559825eb42bSJan Lentfer ldns_rdf *
ldns_dname_label(const ldns_rdf * rdf,uint8_t labelpos)560825eb42bSJan Lentfer ldns_dname_label(const ldns_rdf *rdf, uint8_t labelpos)
561825eb42bSJan Lentfer {
562825eb42bSJan Lentfer 	uint8_t labelcnt;
563825eb42bSJan Lentfer 	uint16_t src_pos;
564825eb42bSJan Lentfer 	uint16_t len;
565825eb42bSJan Lentfer 	ldns_rdf *tmpnew;
566825eb42bSJan Lentfer 	size_t s;
567d1b2b5caSJohn Marino 	uint8_t *data;
568825eb42bSJan Lentfer 
569825eb42bSJan Lentfer 	if (ldns_rdf_get_type(rdf) != LDNS_RDF_TYPE_DNAME) {
570825eb42bSJan Lentfer 		return NULL;
571825eb42bSJan Lentfer 	}
572825eb42bSJan Lentfer 
573825eb42bSJan Lentfer 	labelcnt = 0;
574825eb42bSJan Lentfer 	src_pos = 0;
575825eb42bSJan Lentfer 	s = ldns_rdf_size(rdf);
576825eb42bSJan Lentfer 
577825eb42bSJan Lentfer 	len = ldns_rdf_data(rdf)[src_pos]; /* label start */
578825eb42bSJan Lentfer 	while ((len > 0) && src_pos < s) {
579825eb42bSJan Lentfer 		if (labelcnt == labelpos) {
580825eb42bSJan Lentfer 			/* found our label */
581d1b2b5caSJohn Marino 			data = LDNS_XMALLOC(uint8_t, len + 2);
582d1b2b5caSJohn Marino 			if (!data) {
583d1b2b5caSJohn Marino 				return NULL;
584d1b2b5caSJohn Marino 			}
585d1b2b5caSJohn Marino 			memcpy(data, ldns_rdf_data(rdf) + src_pos, len + 1);
586d1b2b5caSJohn Marino 			data[len + 2 - 1] = 0;
587d1b2b5caSJohn Marino 
588d1b2b5caSJohn Marino 			tmpnew = ldns_rdf_new( LDNS_RDF_TYPE_DNAME
589d1b2b5caSJohn Marino 					     , len + 2, data);
590825eb42bSJan Lentfer 			if (!tmpnew) {
591d1b2b5caSJohn Marino 				LDNS_FREE(data);
592825eb42bSJan Lentfer 				return NULL;
593825eb42bSJan Lentfer 			}
594825eb42bSJan Lentfer 			return tmpnew;
595825eb42bSJan Lentfer 		}
596825eb42bSJan Lentfer 		src_pos++;
597825eb42bSJan Lentfer 		src_pos += len;
598825eb42bSJan Lentfer 		len = ldns_rdf_data(rdf)[src_pos];
599825eb42bSJan Lentfer 		labelcnt++;
600825eb42bSJan Lentfer 	}
601825eb42bSJan Lentfer 	return NULL;
602825eb42bSJan Lentfer }
603