1238104Sdes/*
2238104Sdes * dname.c
3238104Sdes *
4238104Sdes * dname specific rdata implementations
5238104Sdes * A dname is a rdf structure with type LDNS_RDF_TYPE_DNAME
6238104Sdes * It is not a /real/ type! All function must therefor check
7238104Sdes * for LDNS_RDF_TYPE_DNAME.
8238104Sdes *
9238104Sdes * a Net::DNS like library for C
10238104Sdes *
11238104Sdes * (c) NLnet Labs, 2004-2006
12238104Sdes *
13238104Sdes * See the file LICENSE for the license
14238104Sdes */
15238104Sdes
16238104Sdes#include <ldns/config.h>
17238104Sdes
18238104Sdes#include <ldns/ldns.h>
19238104Sdes
20238104Sdes#ifdef HAVE_NETINET_IN_H
21238104Sdes#include <netinet/in.h>
22238104Sdes#endif
23238104Sdes#ifdef HAVE_SYS_SOCKET_H
24238104Sdes#include <sys/socket.h>
25238104Sdes#endif
26238104Sdes#ifdef HAVE_NETDB_H
27238104Sdes#include <netdb.h>
28238104Sdes#endif
29238104Sdes#ifdef HAVE_ARPA_INET_H
30238104Sdes#include <arpa/inet.h>
31238104Sdes#endif
32238104Sdes
33246854Sdes/* Returns whether the last label in the name is a root label (a empty label).
34246854Sdes * Note that it is not enough to just test the last character to be 0,
35246854Sdes * because it may be part of the last label itself.
36246854Sdes */
37246854Sdesstatic bool
38246854Sdesldns_dname_last_label_is_root_label(const ldns_rdf* dname)
39246854Sdes{
40246854Sdes	size_t src_pos;
41246854Sdes	size_t len = 0;
42246854Sdes
43246854Sdes	for (src_pos = 0; src_pos < ldns_rdf_size(dname); src_pos += len + 1) {
44246854Sdes		len = ldns_rdf_data(dname)[src_pos];
45246854Sdes	}
46246854Sdes	assert(src_pos == ldns_rdf_size(dname));
47246854Sdes
48246854Sdes	return src_pos > 0 && len == 0;
49246854Sdes}
50246854Sdes
51238104Sdesldns_rdf *
52238104Sdesldns_dname_cat_clone(const ldns_rdf *rd1, const ldns_rdf *rd2)
53238104Sdes{
54238104Sdes	ldns_rdf *new;
55238104Sdes	uint16_t new_size;
56238104Sdes	uint8_t *buf;
57238104Sdes	uint16_t left_size;
58238104Sdes
59238104Sdes	if (ldns_rdf_get_type(rd1) != LDNS_RDF_TYPE_DNAME ||
60238104Sdes			ldns_rdf_get_type(rd2) != LDNS_RDF_TYPE_DNAME) {
61238104Sdes		return NULL;
62238104Sdes	}
63238104Sdes
64238104Sdes	/* remove root label if it is present at the end of the left
65238104Sdes	 * rd, by reducing the size with 1
66238104Sdes	 */
67238104Sdes	left_size = ldns_rdf_size(rd1);
68246854Sdes	if (ldns_dname_last_label_is_root_label(rd1)) {
69238104Sdes		left_size--;
70238104Sdes	}
71238104Sdes
72238104Sdes	/* we overwrite the nullbyte of rd1 */
73238104Sdes	new_size = left_size + ldns_rdf_size(rd2);
74238104Sdes	buf = LDNS_XMALLOC(uint8_t, new_size);
75238104Sdes	if (!buf) {
76238104Sdes		return NULL;
77238104Sdes	}
78238104Sdes
79238104Sdes	/* put the two dname's after each other */
80238104Sdes	memcpy(buf, ldns_rdf_data(rd1), left_size);
81238104Sdes	memcpy(buf + left_size, ldns_rdf_data(rd2), ldns_rdf_size(rd2));
82238104Sdes
83238104Sdes	new = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_DNAME, new_size, buf);
84238104Sdes
85238104Sdes	LDNS_FREE(buf);
86238104Sdes	return new;
87238104Sdes}
88238104Sdes
89238104Sdesldns_status
90238104Sdesldns_dname_cat(ldns_rdf *rd1, ldns_rdf *rd2)
91238104Sdes{
92238104Sdes	uint16_t left_size;
93238104Sdes	uint16_t size;
94238104Sdes	uint8_t* newd;
95238104Sdes
96238104Sdes	if (ldns_rdf_get_type(rd1) != LDNS_RDF_TYPE_DNAME ||
97238104Sdes			ldns_rdf_get_type(rd2) != LDNS_RDF_TYPE_DNAME) {
98238104Sdes		return LDNS_STATUS_ERR;
99238104Sdes	}
100238104Sdes
101238104Sdes	/* remove root label if it is present at the end of the left
102238104Sdes	 * rd, by reducing the size with 1
103238104Sdes	 */
104238104Sdes	left_size = ldns_rdf_size(rd1);
105246854Sdes	if (ldns_dname_last_label_is_root_label(rd1)) {
106238104Sdes		left_size--;
107238104Sdes	}
108238104Sdes
109238104Sdes	size = left_size + ldns_rdf_size(rd2);
110238104Sdes	newd = LDNS_XREALLOC(ldns_rdf_data(rd1), uint8_t, size);
111238104Sdes	if(!newd) {
112238104Sdes		return LDNS_STATUS_MEM_ERR;
113238104Sdes	}
114238104Sdes
115238104Sdes	ldns_rdf_set_data(rd1, newd);
116238104Sdes	memcpy(ldns_rdf_data(rd1) + left_size, ldns_rdf_data(rd2),
117238104Sdes			ldns_rdf_size(rd2));
118238104Sdes	ldns_rdf_set_size(rd1, size);
119238104Sdes
120238104Sdes	return LDNS_STATUS_OK;
121238104Sdes}
122238104Sdes
123246854Sdesldns_rdf*
124246854Sdesldns_dname_reverse(const ldns_rdf *dname)
125238104Sdes{
126246854Sdes	size_t rd_size;
127246854Sdes	uint8_t* buf;
128246854Sdes	ldns_rdf* new;
129246854Sdes	size_t src_pos;
130246854Sdes	size_t len ;
131238104Sdes
132246854Sdes	assert(ldns_rdf_get_type(dname) == LDNS_RDF_TYPE_DNAME);
133246854Sdes
134246854Sdes	rd_size = ldns_rdf_size(dname);
135246854Sdes	buf = LDNS_XMALLOC(uint8_t, rd_size);
136246854Sdes	if (! buf) {
137246854Sdes		return NULL;
138238104Sdes	}
139246854Sdes	new = ldns_rdf_new(LDNS_RDF_TYPE_DNAME, rd_size, buf);
140246854Sdes	if (! new) {
141246854Sdes		LDNS_FREE(buf);
142246854Sdes		return NULL;
143246854Sdes	}
144246854Sdes
145246854Sdes	/* If dname ends in a root label, the reverse should too.
146246854Sdes	 */
147246854Sdes	if (ldns_dname_last_label_is_root_label(dname)) {
148246854Sdes		buf[rd_size - 1] = 0;
149246854Sdes		rd_size -= 1;
150246854Sdes	}
151246854Sdes	for (src_pos = 0; src_pos < rd_size; src_pos += len + 1) {
152246854Sdes		len = ldns_rdf_data(dname)[src_pos];
153246854Sdes		memcpy(&buf[rd_size - src_pos - len - 1],
154246854Sdes				&ldns_rdf_data(dname)[src_pos], len + 1);
155246854Sdes	}
156238104Sdes	return new;
157238104Sdes}
158238104Sdes
159238104Sdesldns_rdf *
160238104Sdesldns_dname_clone_from(const ldns_rdf *d, uint16_t n)
161238104Sdes{
162238104Sdes	uint8_t *data;
163238104Sdes	uint8_t label_size;
164238104Sdes	size_t data_size;
165238104Sdes
166238104Sdes	if (!d ||
167238104Sdes	    ldns_rdf_get_type(d) != LDNS_RDF_TYPE_DNAME ||
168238104Sdes	    ldns_dname_label_count(d) < n) {
169238104Sdes		return NULL;
170238104Sdes	}
171238104Sdes
172238104Sdes	data = ldns_rdf_data(d);
173238104Sdes	data_size = ldns_rdf_size(d);
174238104Sdes	while (n > 0) {
175238104Sdes		label_size = data[0] + 1;
176238104Sdes		data += label_size;
177238104Sdes		if (data_size < label_size) {
178238104Sdes			/* this label is very broken */
179238104Sdes			return NULL;
180238104Sdes		}
181238104Sdes		data_size -= label_size;
182238104Sdes		n--;
183238104Sdes	}
184238104Sdes
185238104Sdes	return ldns_dname_new_frm_data(data_size, data);
186238104Sdes}
187238104Sdes
188238104Sdesldns_rdf *
189238104Sdesldns_dname_left_chop(const ldns_rdf *d)
190238104Sdes{
191238104Sdes	uint8_t label_pos;
192238104Sdes	ldns_rdf *chop;
193238104Sdes
194238104Sdes	if (!d) {
195238104Sdes		return NULL;
196238104Sdes	}
197238104Sdes
198238104Sdes	if (ldns_rdf_get_type(d) != LDNS_RDF_TYPE_DNAME) {
199238104Sdes		return NULL;
200238104Sdes	}
201238104Sdes	if (ldns_dname_label_count(d) == 0) {
202238104Sdes		/* root label */
203238104Sdes		return NULL;
204238104Sdes	}
205238104Sdes	/* 05blaat02nl00 */
206238104Sdes	label_pos = ldns_rdf_data(d)[0];
207238104Sdes
208238104Sdes	chop = ldns_dname_new_frm_data(ldns_rdf_size(d) - label_pos - 1,
209238104Sdes			ldns_rdf_data(d) + label_pos + 1);
210238104Sdes	return chop;
211238104Sdes}
212238104Sdes
213238104Sdesuint8_t
214238104Sdesldns_dname_label_count(const ldns_rdf *r)
215238104Sdes{
216238104Sdes        uint16_t src_pos;
217238104Sdes        uint16_t len;
218238104Sdes        uint8_t i;
219238104Sdes        size_t r_size;
220238104Sdes
221238104Sdes	if (!r) {
222238104Sdes		return 0;
223238104Sdes	}
224238104Sdes
225238104Sdes	i = 0;
226238104Sdes	src_pos = 0;
227238104Sdes	r_size = ldns_rdf_size(r);
228238104Sdes
229238104Sdes	if (ldns_rdf_get_type(r) != LDNS_RDF_TYPE_DNAME) {
230238104Sdes		return 0;
231238104Sdes	} else {
232238104Sdes		len = ldns_rdf_data(r)[src_pos]; /* start of the label */
233238104Sdes
234238104Sdes		/* single root label */
235238104Sdes		if (1 == r_size) {
236238104Sdes			return 0;
237238104Sdes		} else {
238238104Sdes			while ((len > 0) && src_pos < r_size) {
239238104Sdes				src_pos++;
240238104Sdes				src_pos += len;
241238104Sdes				len = ldns_rdf_data(r)[src_pos];
242238104Sdes				i++;
243238104Sdes			}
244238104Sdes		}
245238104Sdes	}
246238104Sdes	return i;
247238104Sdes}
248238104Sdes
249238104Sdesldns_rdf *
250238104Sdesldns_dname_new(uint16_t s, void *d)
251238104Sdes{
252238104Sdes        ldns_rdf *rd;
253238104Sdes
254238104Sdes        rd = LDNS_MALLOC(ldns_rdf);
255238104Sdes        if (!rd) {
256238104Sdes                return NULL;
257238104Sdes        }
258238104Sdes        ldns_rdf_set_size(rd, s);
259238104Sdes        ldns_rdf_set_type(rd, LDNS_RDF_TYPE_DNAME);
260238104Sdes        ldns_rdf_set_data(rd, d);
261238104Sdes        return rd;
262238104Sdes}
263238104Sdes
264238104Sdesldns_rdf *
265238104Sdesldns_dname_new_frm_str(const char *str)
266238104Sdes{
267238104Sdes	return ldns_rdf_new_frm_str(LDNS_RDF_TYPE_DNAME, str);
268238104Sdes}
269238104Sdes
270238104Sdesldns_rdf *
271238104Sdesldns_dname_new_frm_data(uint16_t size, const void *data)
272238104Sdes{
273238104Sdes	return ldns_rdf_new_frm_data(LDNS_RDF_TYPE_DNAME, size, data);
274238104Sdes}
275238104Sdes
276238104Sdesvoid
277238104Sdesldns_dname2canonical(const ldns_rdf *rd)
278238104Sdes{
279238104Sdes	uint8_t *rdd;
280238104Sdes	uint16_t i;
281238104Sdes
282238104Sdes	if (ldns_rdf_get_type(rd) != LDNS_RDF_TYPE_DNAME) {
283238104Sdes		return;
284238104Sdes	}
285238104Sdes
286238104Sdes	rdd = (uint8_t*)ldns_rdf_data(rd);
287238104Sdes	for (i = 0; i < ldns_rdf_size(rd); i++, rdd++) {
288238104Sdes		*rdd = (uint8_t)LDNS_DNAME_NORMALIZE((int)*rdd);
289238104Sdes	}
290238104Sdes}
291238104Sdes
292238104Sdesbool
293238104Sdesldns_dname_is_subdomain(const ldns_rdf *sub, const ldns_rdf *parent)
294238104Sdes{
295238104Sdes	uint8_t sub_lab;
296238104Sdes	uint8_t par_lab;
297238104Sdes	int8_t i, j;
298238104Sdes	ldns_rdf *tmp_sub = NULL;
299238104Sdes	ldns_rdf *tmp_par = NULL;
300238104Sdes    ldns_rdf *sub_clone;
301238104Sdes    ldns_rdf *parent_clone;
302238104Sdes    bool result = true;
303238104Sdes
304238104Sdes	if (ldns_rdf_get_type(sub) != LDNS_RDF_TYPE_DNAME ||
305238104Sdes			ldns_rdf_get_type(parent) != LDNS_RDF_TYPE_DNAME ||
306238104Sdes			ldns_rdf_compare(sub, parent) == 0) {
307238104Sdes		return false;
308238104Sdes	}
309238104Sdes
310238104Sdes    /* would be nicer if we do not have to clone... */
311238104Sdes    sub_clone = ldns_dname_clone_from(sub, 0);
312238104Sdes    parent_clone = ldns_dname_clone_from(parent, 0);
313238104Sdes    ldns_dname2canonical(sub_clone);
314238104Sdes    ldns_dname2canonical(parent_clone);
315238104Sdes
316238104Sdes	sub_lab = ldns_dname_label_count(sub_clone);
317238104Sdes	par_lab = ldns_dname_label_count(parent_clone);
318238104Sdes
319238104Sdes	/* if sub sits above parent, it cannot be a child/sub domain */
320238104Sdes	if (sub_lab < par_lab) {
321238104Sdes		result = false;
322238104Sdes	} else {
323238104Sdes		/* check all labels the from the parent labels, from right to left.
324238104Sdes		 * When they /all/ match we have found a subdomain
325238104Sdes		 */
326238104Sdes		j = sub_lab - 1; /* we count from zero, thank you */
327238104Sdes		for (i = par_lab -1; i >= 0; i--) {
328238104Sdes			tmp_sub = ldns_dname_label(sub_clone, j);
329238104Sdes			tmp_par = ldns_dname_label(parent_clone, i);
330238104Sdes			if (!tmp_sub || !tmp_par) {
331238104Sdes				/* deep free does null check */
332238104Sdes				ldns_rdf_deep_free(tmp_sub);
333238104Sdes				ldns_rdf_deep_free(tmp_par);
334238104Sdes				result = false;
335238104Sdes				break;
336238104Sdes			}
337238104Sdes
338238104Sdes			if (ldns_rdf_compare(tmp_sub, tmp_par) != 0) {
339238104Sdes				/* they are not equal */
340238104Sdes				ldns_rdf_deep_free(tmp_sub);
341238104Sdes				ldns_rdf_deep_free(tmp_par);
342238104Sdes				result = false;
343238104Sdes				break;
344238104Sdes			}
345238104Sdes			ldns_rdf_deep_free(tmp_sub);
346238104Sdes			ldns_rdf_deep_free(tmp_par);
347238104Sdes			j--;
348238104Sdes		}
349238104Sdes	}
350238104Sdes	ldns_rdf_deep_free(sub_clone);
351238104Sdes	ldns_rdf_deep_free(parent_clone);
352238104Sdes	return result;
353238104Sdes}
354238104Sdes
355238104Sdesint
356238104Sdesldns_dname_compare(const ldns_rdf *dname1, const ldns_rdf *dname2)
357238104Sdes{
358238104Sdes	size_t lc1, lc2, lc1f, lc2f;
359238104Sdes	size_t i;
360238104Sdes	int result = 0;
361238104Sdes	uint8_t *lp1, *lp2;
362238104Sdes
363238104Sdes	/* see RFC4034 for this algorithm */
364238104Sdes	/* this algorithm assumes the names are normalized to case */
365238104Sdes
366238104Sdes        /* only when both are not NULL we can say anything about them */
367238104Sdes        if (!dname1 && !dname2) {
368238104Sdes                return 0;
369238104Sdes        }
370238104Sdes        if (!dname1 || !dname2) {
371238104Sdes                return -1;
372238104Sdes        }
373238104Sdes	/* asserts must happen later as we are looking in the
374238104Sdes	 * dname, which could be NULL. But this case is handled
375238104Sdes	 * above
376238104Sdes	 */
377238104Sdes	assert(ldns_rdf_get_type(dname1) == LDNS_RDF_TYPE_DNAME);
378238104Sdes	assert(ldns_rdf_get_type(dname2) == LDNS_RDF_TYPE_DNAME);
379238104Sdes
380238104Sdes	lc1 = ldns_dname_label_count(dname1);
381238104Sdes	lc2 = ldns_dname_label_count(dname2);
382238104Sdes
383238104Sdes	if (lc1 == 0 && lc2 == 0) {
384238104Sdes		return 0;
385238104Sdes	}
386238104Sdes	if (lc1 == 0) {
387238104Sdes		return -1;
388238104Sdes	}
389238104Sdes	if (lc2 == 0) {
390238104Sdes		return 1;
391238104Sdes	}
392238104Sdes	lc1--;
393238104Sdes	lc2--;
394238104Sdes	/* we start at the last label */
395238104Sdes	while (true) {
396238104Sdes		/* find the label first */
397238104Sdes		lc1f = lc1;
398238104Sdes		lp1 = ldns_rdf_data(dname1);
399238104Sdes		while (lc1f > 0) {
400238104Sdes			lp1 += *lp1 + 1;
401238104Sdes			lc1f--;
402238104Sdes		}
403238104Sdes
404238104Sdes		/* and find the other one */
405238104Sdes		lc2f = lc2;
406238104Sdes		lp2 = ldns_rdf_data(dname2);
407238104Sdes		while (lc2f > 0) {
408238104Sdes			lp2 += *lp2 + 1;
409238104Sdes			lc2f--;
410238104Sdes		}
411238104Sdes
412238104Sdes		/* now check the label character for character. */
413238104Sdes		for (i = 1; i < (size_t)(*lp1 + 1); i++) {
414238104Sdes			if (i > *lp2) {
415238104Sdes				/* apparently label 1 is larger */
416238104Sdes				result = 1;
417238104Sdes				goto done;
418238104Sdes			}
419238104Sdes			if (LDNS_DNAME_NORMALIZE((int) *(lp1 + i)) <
420238104Sdes			    LDNS_DNAME_NORMALIZE((int) *(lp2 + i))) {
421238104Sdes			    result = -1;
422238104Sdes			    goto done;
423238104Sdes			} else if (LDNS_DNAME_NORMALIZE((int) *(lp1 + i)) >
424238104Sdes			    LDNS_DNAME_NORMALIZE((int) *(lp2 + i))) {
425238104Sdes			    result = 1;
426238104Sdes			    goto done;
427238104Sdes			}
428238104Sdes		}
429238104Sdes		if (*lp1 < *lp2) {
430238104Sdes			/* apparently label 2 is larger */
431238104Sdes			result = -1;
432238104Sdes			goto done;
433238104Sdes		}
434238104Sdes		if (lc1 == 0 && lc2 > 0) {
435238104Sdes			result = -1;
436238104Sdes			goto done;
437238104Sdes		} else if (lc1 > 0 && lc2 == 0) {
438238104Sdes			result = 1;
439238104Sdes			goto done;
440238104Sdes		} else if (lc1 == 0 && lc2 == 0) {
441238104Sdes			result = 0;
442238104Sdes			goto done;
443238104Sdes		}
444238104Sdes		lc1--;
445238104Sdes		lc2--;
446238104Sdes	}
447238104Sdes
448238104Sdes	done:
449238104Sdes	return result;
450238104Sdes}
451238104Sdes
452238104Sdesint
453238104Sdesldns_dname_is_wildcard(const ldns_rdf* dname)
454238104Sdes{
455238104Sdes	return ( ldns_dname_label_count(dname) > 0 &&
456238104Sdes		 ldns_rdf_data(dname)[0] == 1 &&
457238104Sdes		 ldns_rdf_data(dname)[1] == '*');
458238104Sdes}
459238104Sdes
460238104Sdesint
461238104Sdesldns_dname_match_wildcard(const ldns_rdf *dname, const ldns_rdf *wildcard)
462238104Sdes{
463238104Sdes	ldns_rdf *wc_chopped;
464238104Sdes	int result;
465238104Sdes	/* check whether it really is a wildcard */
466238104Sdes	if (ldns_dname_is_wildcard(wildcard)) {
467238104Sdes		/* ok, so the dname needs to be a subdomain of the wildcard
468238104Sdes		 * without the *
469238104Sdes		 */
470238104Sdes		wc_chopped = ldns_dname_left_chop(wildcard);
471238104Sdes		result = (int) ldns_dname_is_subdomain(dname, wc_chopped);
472238104Sdes		ldns_rdf_deep_free(wc_chopped);
473238104Sdes	} else {
474238104Sdes		result = (ldns_dname_compare(dname, wildcard) == 0);
475238104Sdes	}
476238104Sdes	return result;
477238104Sdes}
478238104Sdes
479238104Sdes/* nsec test: does prev <= middle < next
480238104Sdes * -1 = yes
481238104Sdes * 0 = error/can't tell
482238104Sdes * 1 = no
483238104Sdes */
484238104Sdesint
485238104Sdesldns_dname_interval(const ldns_rdf *prev, const ldns_rdf *middle,
486238104Sdes		const ldns_rdf *next)
487238104Sdes{
488238104Sdes	int prev_check, next_check;
489238104Sdes
490238104Sdes	assert(ldns_rdf_get_type(prev) == LDNS_RDF_TYPE_DNAME);
491238104Sdes	assert(ldns_rdf_get_type(middle) == LDNS_RDF_TYPE_DNAME);
492238104Sdes	assert(ldns_rdf_get_type(next) == LDNS_RDF_TYPE_DNAME);
493238104Sdes
494238104Sdes	prev_check = ldns_dname_compare(prev, middle);
495238104Sdes	next_check = ldns_dname_compare(middle, next);
496238104Sdes	/* <= next. This cannot be the case for nsec, because then we would
497238104Sdes	 * have gotten the nsec of next...
498238104Sdes	 */
499238104Sdes	if (next_check == 0) {
500238104Sdes		return 0;
501238104Sdes	}
502238104Sdes
503238104Sdes			/* <= */
504238104Sdes	if ((prev_check == -1 || prev_check == 0) &&
505238104Sdes			/* < */
506238104Sdes			next_check == -1) {
507238104Sdes		return -1;
508238104Sdes	} else {
509238104Sdes		return 1;
510238104Sdes	}
511238104Sdes}
512238104Sdes
513238104Sdes
514238104Sdesbool
515238104Sdesldns_dname_str_absolute(const char *dname_str)
516238104Sdes{
517238104Sdes        const char* s;
518238104Sdes	if(dname_str && strcmp(dname_str, ".") == 0)
519238104Sdes		return 1;
520238104Sdes        if(!dname_str || strlen(dname_str) < 2)
521238104Sdes                return 0;
522238104Sdes        if(dname_str[strlen(dname_str) - 1] != '.')
523238104Sdes                return 0;
524238104Sdes        if(dname_str[strlen(dname_str) - 2] != '\\')
525238104Sdes                return 1; /* ends in . and no \ before it */
526238104Sdes        /* so we have the case of ends in . and there is \ before it */
527238104Sdes        for(s=dname_str; *s; s++) {
528238104Sdes                if(*s == '\\') {
529238104Sdes                        if(s[1] && s[2] && s[3] /* check length */
530238104Sdes                                && isdigit(s[1]) && isdigit(s[2]) &&
531238104Sdes                                isdigit(s[3]))
532238104Sdes                                s += 3;
533238104Sdes                        else if(!s[1] || isdigit(s[1])) /* escape of nul,0-9 */
534238104Sdes                                return 0; /* parse error */
535238104Sdes                        else s++; /* another character escaped */
536238104Sdes                }
537238104Sdes                else if(!*(s+1) && *s == '.')
538238104Sdes                        return 1; /* trailing dot, unescaped */
539238104Sdes        }
540238104Sdes        return 0;
541238104Sdes}
542238104Sdes
543246854Sdesbool
544246854Sdesldns_dname_absolute(const ldns_rdf *rdf)
545246854Sdes{
546246854Sdes	char *str = ldns_rdf2str(rdf);
547246854Sdes	if (str) {
548246854Sdes		bool r = ldns_dname_str_absolute(str);
549246854Sdes		LDNS_FREE(str);
550246854Sdes		return r;
551246854Sdes	}
552246854Sdes	return false;
553246854Sdes}
554246854Sdes
555238104Sdesldns_rdf *
556238104Sdesldns_dname_label(const ldns_rdf *rdf, uint8_t labelpos)
557238104Sdes{
558238104Sdes	uint8_t labelcnt;
559238104Sdes	uint16_t src_pos;
560238104Sdes	uint16_t len;
561238104Sdes	ldns_rdf *tmpnew;
562238104Sdes	size_t s;
563238104Sdes	uint8_t *data;
564238104Sdes
565238104Sdes	if (ldns_rdf_get_type(rdf) != LDNS_RDF_TYPE_DNAME) {
566238104Sdes		return NULL;
567238104Sdes	}
568238104Sdes
569238104Sdes	labelcnt = 0;
570238104Sdes	src_pos = 0;
571238104Sdes	s = ldns_rdf_size(rdf);
572238104Sdes
573238104Sdes	len = ldns_rdf_data(rdf)[src_pos]; /* label start */
574238104Sdes	while ((len > 0) && src_pos < s) {
575238104Sdes		if (labelcnt == labelpos) {
576238104Sdes			/* found our label */
577238104Sdes			data = LDNS_XMALLOC(uint8_t, len + 2);
578238104Sdes			if (!data) {
579238104Sdes				return NULL;
580238104Sdes			}
581238104Sdes			memcpy(data, ldns_rdf_data(rdf) + src_pos, len + 1);
582238104Sdes			data[len + 2 - 1] = 0;
583238104Sdes
584238104Sdes			tmpnew = ldns_rdf_new( LDNS_RDF_TYPE_DNAME
585238104Sdes					     , len + 2, data);
586238104Sdes			if (!tmpnew) {
587238104Sdes				LDNS_FREE(data);
588238104Sdes				return NULL;
589238104Sdes			}
590238104Sdes			return tmpnew;
591238104Sdes		}
592238104Sdes		src_pos++;
593238104Sdes		src_pos += len;
594238104Sdes		len = ldns_rdf_data(rdf)[src_pos];
595238104Sdes		labelcnt++;
596238104Sdes	}
597238104Sdes	return NULL;
598238104Sdes}
599