xref: /dflybsd-src/contrib/ldns/dname.c (revision d1b2b5caec9ab35b37f82c6e75b7f14f9c9103b2)
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
6825eb42bSJan Lentfer  * It is not a /real/ type! All function must therefor 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 
33*d1b2b5caSJohn Marino /* Returns whether the last label in the name is a root label (a empty label).
34*d1b2b5caSJohn Marino  * Note that it is not enough to just test the last character to be 0,
35*d1b2b5caSJohn Marino  * because it may be part of the last label itself.
36*d1b2b5caSJohn Marino  */
37*d1b2b5caSJohn Marino static bool
38*d1b2b5caSJohn Marino ldns_dname_last_label_is_root_label(const ldns_rdf* dname)
39*d1b2b5caSJohn Marino {
40*d1b2b5caSJohn Marino 	size_t src_pos;
41*d1b2b5caSJohn Marino 	size_t len = 0;
42*d1b2b5caSJohn Marino 
43*d1b2b5caSJohn Marino 	for (src_pos = 0; src_pos < ldns_rdf_size(dname); src_pos += len + 1) {
44*d1b2b5caSJohn Marino 		len = ldns_rdf_data(dname)[src_pos];
45*d1b2b5caSJohn Marino 	}
46*d1b2b5caSJohn Marino 	assert(src_pos == ldns_rdf_size(dname));
47*d1b2b5caSJohn Marino 
48*d1b2b5caSJohn Marino 	return src_pos > 0 && len == 0;
49*d1b2b5caSJohn Marino }
50*d1b2b5caSJohn Marino 
51825eb42bSJan Lentfer ldns_rdf *
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);
68*d1b2b5caSJohn 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
90825eb42bSJan Lentfer ldns_dname_cat(ldns_rdf *rd1, 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);
105*d1b2b5caSJohn 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*
124*d1b2b5caSJohn Marino ldns_dname_reverse(const ldns_rdf *dname)
125825eb42bSJan Lentfer {
126*d1b2b5caSJohn Marino 	size_t rd_size;
127*d1b2b5caSJohn Marino 	uint8_t* buf;
128825eb42bSJan Lentfer 	ldns_rdf* new;
129*d1b2b5caSJohn Marino 	size_t src_pos;
130*d1b2b5caSJohn Marino 	size_t len ;
131825eb42bSJan Lentfer 
132*d1b2b5caSJohn Marino 	assert(ldns_rdf_get_type(dname) == LDNS_RDF_TYPE_DNAME);
133825eb42bSJan Lentfer 
134*d1b2b5caSJohn Marino 	rd_size = ldns_rdf_size(dname);
135*d1b2b5caSJohn Marino 	buf = LDNS_XMALLOC(uint8_t, rd_size);
136*d1b2b5caSJohn Marino 	if (! buf) {
137ac996e71SJan Lentfer 		return NULL;
138ac996e71SJan Lentfer 	}
139*d1b2b5caSJohn Marino 	new = ldns_rdf_new(LDNS_RDF_TYPE_DNAME, rd_size, buf);
140*d1b2b5caSJohn Marino 	if (! new) {
141*d1b2b5caSJohn Marino 		LDNS_FREE(buf);
142*d1b2b5caSJohn Marino 		return NULL;
143825eb42bSJan Lentfer 	}
144825eb42bSJan Lentfer 
145*d1b2b5caSJohn Marino 	/* If dname ends in a root label, the reverse should too.
146*d1b2b5caSJohn Marino 	 */
147*d1b2b5caSJohn Marino 	if (ldns_dname_last_label_is_root_label(dname)) {
148*d1b2b5caSJohn Marino 		buf[rd_size - 1] = 0;
149*d1b2b5caSJohn Marino 		rd_size -= 1;
150*d1b2b5caSJohn Marino 	}
151*d1b2b5caSJohn Marino 	for (src_pos = 0; src_pos < rd_size; src_pos += len + 1) {
152*d1b2b5caSJohn Marino 		len = ldns_rdf_data(dname)[src_pos];
153*d1b2b5caSJohn Marino 		memcpy(&buf[rd_size - src_pos - len - 1],
154*d1b2b5caSJohn Marino 				&ldns_rdf_data(dname)[src_pos], len + 1);
155*d1b2b5caSJohn Marino 	}
156825eb42bSJan Lentfer 	return new;
157825eb42bSJan Lentfer }
158825eb42bSJan Lentfer 
159825eb42bSJan Lentfer ldns_rdf *
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 *
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
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 *
250825eb42bSJan Lentfer ldns_dname_new(uint16_t s, void *d)
251825eb42bSJan Lentfer {
252825eb42bSJan Lentfer         ldns_rdf *rd;
253825eb42bSJan Lentfer 
254825eb42bSJan Lentfer         rd = LDNS_MALLOC(ldns_rdf);
255825eb42bSJan Lentfer         if (!rd) {
256825eb42bSJan Lentfer                 return NULL;
257825eb42bSJan Lentfer         }
258825eb42bSJan Lentfer         ldns_rdf_set_size(rd, s);
259825eb42bSJan Lentfer         ldns_rdf_set_type(rd, LDNS_RDF_TYPE_DNAME);
260825eb42bSJan Lentfer         ldns_rdf_set_data(rd, d);
261825eb42bSJan Lentfer         return rd;
262825eb42bSJan Lentfer }
263825eb42bSJan Lentfer 
264825eb42bSJan Lentfer ldns_rdf *
265825eb42bSJan Lentfer ldns_dname_new_frm_str(const char *str)
266825eb42bSJan Lentfer {
267825eb42bSJan Lentfer 	return ldns_rdf_new_frm_str(LDNS_RDF_TYPE_DNAME, str);
268825eb42bSJan Lentfer }
269825eb42bSJan Lentfer 
270825eb42bSJan Lentfer ldns_rdf *
271825eb42bSJan Lentfer ldns_dname_new_frm_data(uint16_t size, const void *data)
272825eb42bSJan Lentfer {
273825eb42bSJan Lentfer 	return ldns_rdf_new_frm_data(LDNS_RDF_TYPE_DNAME, size, data);
274825eb42bSJan Lentfer }
275825eb42bSJan Lentfer 
276825eb42bSJan Lentfer void
277825eb42bSJan Lentfer ldns_dname2canonical(const ldns_rdf *rd)
278825eb42bSJan Lentfer {
279825eb42bSJan Lentfer 	uint8_t *rdd;
280825eb42bSJan Lentfer 	uint16_t i;
281825eb42bSJan Lentfer 
282825eb42bSJan Lentfer 	if (ldns_rdf_get_type(rd) != LDNS_RDF_TYPE_DNAME) {
283825eb42bSJan Lentfer 		return;
284825eb42bSJan Lentfer 	}
285825eb42bSJan Lentfer 
286825eb42bSJan Lentfer 	rdd = (uint8_t*)ldns_rdf_data(rd);
287825eb42bSJan Lentfer 	for (i = 0; i < ldns_rdf_size(rd); i++, rdd++) {
288825eb42bSJan Lentfer 		*rdd = (uint8_t)LDNS_DNAME_NORMALIZE((int)*rdd);
289825eb42bSJan Lentfer 	}
290825eb42bSJan Lentfer }
291825eb42bSJan Lentfer 
292825eb42bSJan Lentfer bool
293825eb42bSJan Lentfer ldns_dname_is_subdomain(const ldns_rdf *sub, const ldns_rdf *parent)
294825eb42bSJan Lentfer {
295825eb42bSJan Lentfer 	uint8_t sub_lab;
296825eb42bSJan Lentfer 	uint8_t par_lab;
297825eb42bSJan Lentfer 	int8_t i, j;
298825eb42bSJan Lentfer 	ldns_rdf *tmp_sub = NULL;
299825eb42bSJan Lentfer 	ldns_rdf *tmp_par = NULL;
300825eb42bSJan Lentfer     ldns_rdf *sub_clone;
301825eb42bSJan Lentfer     ldns_rdf *parent_clone;
302825eb42bSJan Lentfer     bool result = true;
303825eb42bSJan Lentfer 
304825eb42bSJan Lentfer 	if (ldns_rdf_get_type(sub) != LDNS_RDF_TYPE_DNAME ||
305825eb42bSJan Lentfer 			ldns_rdf_get_type(parent) != LDNS_RDF_TYPE_DNAME ||
306825eb42bSJan Lentfer 			ldns_rdf_compare(sub, parent) == 0) {
307825eb42bSJan Lentfer 		return false;
308825eb42bSJan Lentfer 	}
309825eb42bSJan Lentfer 
310825eb42bSJan Lentfer     /* would be nicer if we do not have to clone... */
311825eb42bSJan Lentfer     sub_clone = ldns_dname_clone_from(sub, 0);
312825eb42bSJan Lentfer     parent_clone = ldns_dname_clone_from(parent, 0);
313825eb42bSJan Lentfer     ldns_dname2canonical(sub_clone);
314825eb42bSJan Lentfer     ldns_dname2canonical(parent_clone);
315825eb42bSJan Lentfer 
316825eb42bSJan Lentfer 	sub_lab = ldns_dname_label_count(sub_clone);
317825eb42bSJan Lentfer 	par_lab = ldns_dname_label_count(parent_clone);
318825eb42bSJan Lentfer 
319825eb42bSJan Lentfer 	/* if sub sits above parent, it cannot be a child/sub domain */
320825eb42bSJan Lentfer 	if (sub_lab < par_lab) {
321825eb42bSJan Lentfer 		result = false;
322825eb42bSJan Lentfer 	} else {
323825eb42bSJan Lentfer 		/* check all labels the from the parent labels, from right to left.
324825eb42bSJan Lentfer 		 * When they /all/ match we have found a subdomain
325825eb42bSJan Lentfer 		 */
326825eb42bSJan Lentfer 		j = sub_lab - 1; /* we count from zero, thank you */
327825eb42bSJan Lentfer 		for (i = par_lab -1; i >= 0; i--) {
328825eb42bSJan Lentfer 			tmp_sub = ldns_dname_label(sub_clone, j);
329825eb42bSJan Lentfer 			tmp_par = ldns_dname_label(parent_clone, i);
330825eb42bSJan Lentfer 			if (!tmp_sub || !tmp_par) {
331825eb42bSJan Lentfer 				/* deep free does null check */
332825eb42bSJan Lentfer 				ldns_rdf_deep_free(tmp_sub);
333825eb42bSJan Lentfer 				ldns_rdf_deep_free(tmp_par);
334825eb42bSJan Lentfer 				result = false;
335825eb42bSJan Lentfer 				break;
336825eb42bSJan Lentfer 			}
337825eb42bSJan Lentfer 
338825eb42bSJan Lentfer 			if (ldns_rdf_compare(tmp_sub, tmp_par) != 0) {
339825eb42bSJan Lentfer 				/* they are not equal */
340825eb42bSJan Lentfer 				ldns_rdf_deep_free(tmp_sub);
341825eb42bSJan Lentfer 				ldns_rdf_deep_free(tmp_par);
342825eb42bSJan Lentfer 				result = false;
343825eb42bSJan Lentfer 				break;
344825eb42bSJan Lentfer 			}
345825eb42bSJan Lentfer 			ldns_rdf_deep_free(tmp_sub);
346825eb42bSJan Lentfer 			ldns_rdf_deep_free(tmp_par);
347825eb42bSJan Lentfer 			j--;
348825eb42bSJan Lentfer 		}
349825eb42bSJan Lentfer 	}
350825eb42bSJan Lentfer 	ldns_rdf_deep_free(sub_clone);
351825eb42bSJan Lentfer 	ldns_rdf_deep_free(parent_clone);
352825eb42bSJan Lentfer 	return result;
353825eb42bSJan Lentfer }
354825eb42bSJan Lentfer 
355825eb42bSJan Lentfer int
356825eb42bSJan Lentfer ldns_dname_compare(const ldns_rdf *dname1, const ldns_rdf *dname2)
357825eb42bSJan Lentfer {
358825eb42bSJan Lentfer 	size_t lc1, lc2, lc1f, lc2f;
359825eb42bSJan Lentfer 	size_t i;
360825eb42bSJan Lentfer 	int result = 0;
361825eb42bSJan Lentfer 	uint8_t *lp1, *lp2;
362825eb42bSJan Lentfer 
363825eb42bSJan Lentfer 	/* see RFC4034 for this algorithm */
364825eb42bSJan Lentfer 	/* this algorithm assumes the names are normalized to case */
365825eb42bSJan Lentfer 
366825eb42bSJan Lentfer         /* only when both are not NULL we can say anything about them */
367825eb42bSJan Lentfer         if (!dname1 && !dname2) {
368825eb42bSJan Lentfer                 return 0;
369825eb42bSJan Lentfer         }
370825eb42bSJan Lentfer         if (!dname1 || !dname2) {
371825eb42bSJan Lentfer                 return -1;
372825eb42bSJan Lentfer         }
373825eb42bSJan Lentfer 	/* asserts must happen later as we are looking in the
374825eb42bSJan Lentfer 	 * dname, which could be NULL. But this case is handled
375825eb42bSJan Lentfer 	 * above
376825eb42bSJan Lentfer 	 */
377825eb42bSJan Lentfer 	assert(ldns_rdf_get_type(dname1) == LDNS_RDF_TYPE_DNAME);
378825eb42bSJan Lentfer 	assert(ldns_rdf_get_type(dname2) == LDNS_RDF_TYPE_DNAME);
379825eb42bSJan Lentfer 
380825eb42bSJan Lentfer 	lc1 = ldns_dname_label_count(dname1);
381825eb42bSJan Lentfer 	lc2 = ldns_dname_label_count(dname2);
382825eb42bSJan Lentfer 
383825eb42bSJan Lentfer 	if (lc1 == 0 && lc2 == 0) {
384825eb42bSJan Lentfer 		return 0;
385825eb42bSJan Lentfer 	}
386825eb42bSJan Lentfer 	if (lc1 == 0) {
387825eb42bSJan Lentfer 		return -1;
388825eb42bSJan Lentfer 	}
389825eb42bSJan Lentfer 	if (lc2 == 0) {
390825eb42bSJan Lentfer 		return 1;
391825eb42bSJan Lentfer 	}
392825eb42bSJan Lentfer 	lc1--;
393825eb42bSJan Lentfer 	lc2--;
394825eb42bSJan Lentfer 	/* we start at the last label */
395825eb42bSJan Lentfer 	while (true) {
396825eb42bSJan Lentfer 		/* find the label first */
397825eb42bSJan Lentfer 		lc1f = lc1;
398825eb42bSJan Lentfer 		lp1 = ldns_rdf_data(dname1);
399825eb42bSJan Lentfer 		while (lc1f > 0) {
400825eb42bSJan Lentfer 			lp1 += *lp1 + 1;
401825eb42bSJan Lentfer 			lc1f--;
402825eb42bSJan Lentfer 		}
403825eb42bSJan Lentfer 
404825eb42bSJan Lentfer 		/* and find the other one */
405825eb42bSJan Lentfer 		lc2f = lc2;
406825eb42bSJan Lentfer 		lp2 = ldns_rdf_data(dname2);
407825eb42bSJan Lentfer 		while (lc2f > 0) {
408825eb42bSJan Lentfer 			lp2 += *lp2 + 1;
409825eb42bSJan Lentfer 			lc2f--;
410825eb42bSJan Lentfer 		}
411825eb42bSJan Lentfer 
412825eb42bSJan Lentfer 		/* now check the label character for character. */
413825eb42bSJan Lentfer 		for (i = 1; i < (size_t)(*lp1 + 1); i++) {
414825eb42bSJan Lentfer 			if (i > *lp2) {
415825eb42bSJan Lentfer 				/* apparently label 1 is larger */
416825eb42bSJan Lentfer 				result = 1;
417825eb42bSJan Lentfer 				goto done;
418825eb42bSJan Lentfer 			}
419825eb42bSJan Lentfer 			if (LDNS_DNAME_NORMALIZE((int) *(lp1 + i)) <
420825eb42bSJan Lentfer 			    LDNS_DNAME_NORMALIZE((int) *(lp2 + i))) {
421825eb42bSJan Lentfer 			    result = -1;
422825eb42bSJan Lentfer 			    goto done;
423825eb42bSJan Lentfer 			} else if (LDNS_DNAME_NORMALIZE((int) *(lp1 + i)) >
424825eb42bSJan Lentfer 			    LDNS_DNAME_NORMALIZE((int) *(lp2 + i))) {
425825eb42bSJan Lentfer 			    result = 1;
426825eb42bSJan Lentfer 			    goto done;
427825eb42bSJan Lentfer 			}
428825eb42bSJan Lentfer 		}
429825eb42bSJan Lentfer 		if (*lp1 < *lp2) {
430825eb42bSJan Lentfer 			/* apparently label 2 is larger */
431825eb42bSJan Lentfer 			result = -1;
432825eb42bSJan Lentfer 			goto done;
433825eb42bSJan Lentfer 		}
434825eb42bSJan Lentfer 		if (lc1 == 0 && lc2 > 0) {
435825eb42bSJan Lentfer 			result = -1;
436825eb42bSJan Lentfer 			goto done;
437825eb42bSJan Lentfer 		} else if (lc1 > 0 && lc2 == 0) {
438825eb42bSJan Lentfer 			result = 1;
439825eb42bSJan Lentfer 			goto done;
440825eb42bSJan Lentfer 		} else if (lc1 == 0 && lc2 == 0) {
441825eb42bSJan Lentfer 			result = 0;
442825eb42bSJan Lentfer 			goto done;
443825eb42bSJan Lentfer 		}
444825eb42bSJan Lentfer 		lc1--;
445825eb42bSJan Lentfer 		lc2--;
446825eb42bSJan Lentfer 	}
447825eb42bSJan Lentfer 
448825eb42bSJan Lentfer 	done:
449825eb42bSJan Lentfer 	return result;
450825eb42bSJan Lentfer }
451825eb42bSJan Lentfer 
452825eb42bSJan Lentfer int
453ac996e71SJan Lentfer ldns_dname_is_wildcard(const ldns_rdf* dname)
454ac996e71SJan Lentfer {
455ac996e71SJan Lentfer 	return ( ldns_dname_label_count(dname) > 0 &&
456ac996e71SJan Lentfer 		 ldns_rdf_data(dname)[0] == 1 &&
457ac996e71SJan Lentfer 		 ldns_rdf_data(dname)[1] == '*');
458ac996e71SJan Lentfer }
459ac996e71SJan Lentfer 
460ac996e71SJan Lentfer int
461825eb42bSJan Lentfer ldns_dname_match_wildcard(const ldns_rdf *dname, const ldns_rdf *wildcard)
462825eb42bSJan Lentfer {
463825eb42bSJan Lentfer 	ldns_rdf *wc_chopped;
464825eb42bSJan Lentfer 	int result;
465825eb42bSJan Lentfer 	/* check whether it really is a wildcard */
466ac996e71SJan Lentfer 	if (ldns_dname_is_wildcard(wildcard)) {
467825eb42bSJan Lentfer 		/* ok, so the dname needs to be a subdomain of the wildcard
468825eb42bSJan Lentfer 		 * without the *
469825eb42bSJan Lentfer 		 */
470825eb42bSJan Lentfer 		wc_chopped = ldns_dname_left_chop(wildcard);
471825eb42bSJan Lentfer 		result = (int) ldns_dname_is_subdomain(dname, wc_chopped);
472825eb42bSJan Lentfer 		ldns_rdf_deep_free(wc_chopped);
473825eb42bSJan Lentfer 	} else {
474825eb42bSJan Lentfer 		result = (ldns_dname_compare(dname, wildcard) == 0);
475825eb42bSJan Lentfer 	}
476825eb42bSJan Lentfer 	return result;
477825eb42bSJan Lentfer }
478825eb42bSJan Lentfer 
479825eb42bSJan Lentfer /* nsec test: does prev <= middle < next
480825eb42bSJan Lentfer  * -1 = yes
481825eb42bSJan Lentfer  * 0 = error/can't tell
482825eb42bSJan Lentfer  * 1 = no
483825eb42bSJan Lentfer  */
484825eb42bSJan Lentfer int
485825eb42bSJan Lentfer ldns_dname_interval(const ldns_rdf *prev, const ldns_rdf *middle,
486825eb42bSJan Lentfer 		const ldns_rdf *next)
487825eb42bSJan Lentfer {
488825eb42bSJan Lentfer 	int prev_check, next_check;
489825eb42bSJan Lentfer 
490825eb42bSJan Lentfer 	assert(ldns_rdf_get_type(prev) == LDNS_RDF_TYPE_DNAME);
491825eb42bSJan Lentfer 	assert(ldns_rdf_get_type(middle) == LDNS_RDF_TYPE_DNAME);
492825eb42bSJan Lentfer 	assert(ldns_rdf_get_type(next) == LDNS_RDF_TYPE_DNAME);
493825eb42bSJan Lentfer 
494825eb42bSJan Lentfer 	prev_check = ldns_dname_compare(prev, middle);
495825eb42bSJan Lentfer 	next_check = ldns_dname_compare(middle, next);
496825eb42bSJan Lentfer 	/* <= next. This cannot be the case for nsec, because then we would
497825eb42bSJan Lentfer 	 * have gotten the nsec of next...
498825eb42bSJan Lentfer 	 */
499825eb42bSJan Lentfer 	if (next_check == 0) {
500825eb42bSJan Lentfer 		return 0;
501825eb42bSJan Lentfer 	}
502825eb42bSJan Lentfer 
503825eb42bSJan Lentfer 			/* <= */
504825eb42bSJan Lentfer 	if ((prev_check == -1 || prev_check == 0) &&
505825eb42bSJan Lentfer 			/* < */
506825eb42bSJan Lentfer 			next_check == -1) {
507825eb42bSJan Lentfer 		return -1;
508825eb42bSJan Lentfer 	} else {
509825eb42bSJan Lentfer 		return 1;
510825eb42bSJan Lentfer 	}
511825eb42bSJan Lentfer }
512825eb42bSJan Lentfer 
513825eb42bSJan Lentfer 
514825eb42bSJan Lentfer bool
515825eb42bSJan Lentfer ldns_dname_str_absolute(const char *dname_str)
516825eb42bSJan Lentfer {
517ac996e71SJan Lentfer         const char* s;
518825eb42bSJan Lentfer 	if(dname_str && strcmp(dname_str, ".") == 0)
519825eb42bSJan Lentfer 		return 1;
520ac996e71SJan Lentfer         if(!dname_str || strlen(dname_str) < 2)
521ac996e71SJan Lentfer                 return 0;
522ac996e71SJan Lentfer         if(dname_str[strlen(dname_str) - 1] != '.')
523ac996e71SJan Lentfer                 return 0;
524ac996e71SJan Lentfer         if(dname_str[strlen(dname_str) - 2] != '\\')
525ac996e71SJan Lentfer                 return 1; /* ends in . and no \ before it */
526ac996e71SJan Lentfer         /* so we have the case of ends in . and there is \ before it */
527ac996e71SJan Lentfer         for(s=dname_str; *s; s++) {
528ac996e71SJan Lentfer                 if(*s == '\\') {
529ac996e71SJan Lentfer                         if(s[1] && s[2] && s[3] /* check length */
530ac996e71SJan Lentfer                                 && isdigit(s[1]) && isdigit(s[2]) &&
531ac996e71SJan Lentfer                                 isdigit(s[3]))
532ac996e71SJan Lentfer                                 s += 3;
533ac996e71SJan Lentfer                         else if(!s[1] || isdigit(s[1])) /* escape of nul,0-9 */
534ac996e71SJan Lentfer                                 return 0; /* parse error */
535ac996e71SJan Lentfer                         else s++; /* another character escaped */
536ac996e71SJan Lentfer                 }
537ac996e71SJan Lentfer                 else if(!*(s+1) && *s == '.')
538ac996e71SJan Lentfer                         return 1; /* trailing dot, unescaped */
539ac996e71SJan Lentfer         }
540ac996e71SJan Lentfer         return 0;
541825eb42bSJan Lentfer }
542825eb42bSJan Lentfer 
543*d1b2b5caSJohn Marino bool
544*d1b2b5caSJohn Marino ldns_dname_absolute(const ldns_rdf *rdf)
545*d1b2b5caSJohn Marino {
546*d1b2b5caSJohn Marino 	char *str = ldns_rdf2str(rdf);
547*d1b2b5caSJohn Marino 	if (str) {
548*d1b2b5caSJohn Marino 		bool r = ldns_dname_str_absolute(str);
549*d1b2b5caSJohn Marino 		LDNS_FREE(str);
550*d1b2b5caSJohn Marino 		return r;
551*d1b2b5caSJohn Marino 	}
552*d1b2b5caSJohn Marino 	return false;
553*d1b2b5caSJohn Marino }
554*d1b2b5caSJohn Marino 
555825eb42bSJan Lentfer ldns_rdf *
556825eb42bSJan Lentfer ldns_dname_label(const ldns_rdf *rdf, uint8_t labelpos)
557825eb42bSJan Lentfer {
558825eb42bSJan Lentfer 	uint8_t labelcnt;
559825eb42bSJan Lentfer 	uint16_t src_pos;
560825eb42bSJan Lentfer 	uint16_t len;
561825eb42bSJan Lentfer 	ldns_rdf *tmpnew;
562825eb42bSJan Lentfer 	size_t s;
563*d1b2b5caSJohn Marino 	uint8_t *data;
564825eb42bSJan Lentfer 
565825eb42bSJan Lentfer 	if (ldns_rdf_get_type(rdf) != LDNS_RDF_TYPE_DNAME) {
566825eb42bSJan Lentfer 		return NULL;
567825eb42bSJan Lentfer 	}
568825eb42bSJan Lentfer 
569825eb42bSJan Lentfer 	labelcnt = 0;
570825eb42bSJan Lentfer 	src_pos = 0;
571825eb42bSJan Lentfer 	s = ldns_rdf_size(rdf);
572825eb42bSJan Lentfer 
573825eb42bSJan Lentfer 	len = ldns_rdf_data(rdf)[src_pos]; /* label start */
574825eb42bSJan Lentfer 	while ((len > 0) && src_pos < s) {
575825eb42bSJan Lentfer 		if (labelcnt == labelpos) {
576825eb42bSJan Lentfer 			/* found our label */
577*d1b2b5caSJohn Marino 			data = LDNS_XMALLOC(uint8_t, len + 2);
578*d1b2b5caSJohn Marino 			if (!data) {
579*d1b2b5caSJohn Marino 				return NULL;
580*d1b2b5caSJohn Marino 			}
581*d1b2b5caSJohn Marino 			memcpy(data, ldns_rdf_data(rdf) + src_pos, len + 1);
582*d1b2b5caSJohn Marino 			data[len + 2 - 1] = 0;
583*d1b2b5caSJohn Marino 
584*d1b2b5caSJohn Marino 			tmpnew = ldns_rdf_new( LDNS_RDF_TYPE_DNAME
585*d1b2b5caSJohn Marino 					     , len + 2, data);
586825eb42bSJan Lentfer 			if (!tmpnew) {
587*d1b2b5caSJohn Marino 				LDNS_FREE(data);
588825eb42bSJan Lentfer 				return NULL;
589825eb42bSJan Lentfer 			}
590825eb42bSJan Lentfer 			return tmpnew;
591825eb42bSJan Lentfer 		}
592825eb42bSJan Lentfer 		src_pos++;
593825eb42bSJan Lentfer 		src_pos += len;
594825eb42bSJan Lentfer 		len = ldns_rdf_data(rdf)[src_pos];
595825eb42bSJan Lentfer 		labelcnt++;
596825eb42bSJan Lentfer 	}
597825eb42bSJan Lentfer 	return NULL;
598825eb42bSJan Lentfer }
599