4 * dname specific rdata implementations
5 * A dname is a rdf structure with type LDNS_RDF_TYPE_DNAME
6 * It is not a /real/ type! All function must therefor check
7 * for LDNS_RDF_TYPE_DNAME.
9 * a Net::DNS like library for C
11 * (c) NLnet Labs, 2004-2006
13 * See the file LICENSE for the license
16 #include <ldns/config.h>
18 #include <ldns/ldns.h>
20 #ifdef HAVE_NETINET_IN_H
21 #include <netinet/in.h>
23 #ifdef HAVE_SYS_SOCKET_H
24 #include <sys/socket.h>
29 #ifdef HAVE_ARPA_INET_H
30 #include <arpa/inet.h>
34 ldns_dname_cat_clone(const ldns_rdf *rd1, const ldns_rdf *rd2)
41 if (ldns_rdf_get_type(rd1) != LDNS_RDF_TYPE_DNAME ||
42 ldns_rdf_get_type(rd2) != LDNS_RDF_TYPE_DNAME) {
46 /* remove root label if it is present at the end of the left
47 * rd, by reducing the size with 1
49 left_size = ldns_rdf_size(rd1);
50 if (left_size > 0 &&ldns_rdf_data(rd1)[left_size - 1] == 0) {
54 /* we overwrite the nullbyte of rd1 */
55 new_size = left_size + ldns_rdf_size(rd2);
56 buf = LDNS_XMALLOC(uint8_t, new_size);
61 /* put the two dname's after each other */
62 memcpy(buf, ldns_rdf_data(rd1), left_size);
63 memcpy(buf + left_size, ldns_rdf_data(rd2), ldns_rdf_size(rd2));
65 new = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_DNAME, new_size, buf);
72 ldns_dname_cat(ldns_rdf *rd1, ldns_rdf *rd2)
77 if (ldns_rdf_get_type(rd1) != LDNS_RDF_TYPE_DNAME ||
78 ldns_rdf_get_type(rd2) != LDNS_RDF_TYPE_DNAME) {
79 return LDNS_STATUS_ERR;
82 /* remove root label if it is present at the end of the left
83 * rd, by reducing the size with 1
85 left_size = ldns_rdf_size(rd1);
86 if (left_size > 0 &&ldns_rdf_data(rd1)[left_size - 1] == 0) {
90 size = left_size + ldns_rdf_size(rd2);
92 ldns_rdf_set_data(rd1, LDNS_XREALLOC(ldns_rdf_data(rd1), uint8_t, size));
93 memcpy(ldns_rdf_data(rd1) + left_size, ldns_rdf_data(rd2),
95 ldns_rdf_set_size(rd1, size);
97 return LDNS_STATUS_OK;
101 ldns_dname_reverse(const ldns_rdf *d)
108 d_tmp = ldns_rdf_clone(d);
110 new = ldns_dname_new_frm_str(".");
112 while(ldns_dname_label_count(d_tmp) > 0) {
113 tmp = ldns_dname_label(d_tmp, 0);
114 status = ldns_dname_cat(tmp, new);
115 ldns_rdf_deep_free(new);
117 tmp = ldns_dname_left_chop(d_tmp);
118 ldns_rdf_deep_free(d_tmp);
121 ldns_rdf_deep_free(d_tmp);
127 ldns_dname_clone_from(const ldns_rdf *d, uint16_t n)
134 ldns_rdf_get_type(d) != LDNS_RDF_TYPE_DNAME ||
135 ldns_dname_label_count(d) < n) {
139 data = ldns_rdf_data(d);
140 data_size = ldns_rdf_size(d);
142 label_size = data[0] + 1;
144 if (data_size < label_size) {
145 /* this label is very broken */
148 data_size -= label_size;
152 return ldns_dname_new_frm_data(data_size, data);
156 ldns_dname_left_chop(const ldns_rdf *d)
165 if (ldns_rdf_get_type(d) != LDNS_RDF_TYPE_DNAME) {
168 if (ldns_dname_label_count(d) == 0) {
173 label_pos = ldns_rdf_data(d)[0];
175 chop = ldns_dname_new_frm_data(ldns_rdf_size(d) - label_pos - 1,
176 ldns_rdf_data(d) + label_pos + 1);
181 ldns_dname_label_count(const ldns_rdf *r)
194 r_size = ldns_rdf_size(r);
196 if (ldns_rdf_get_type(r) != LDNS_RDF_TYPE_DNAME) {
199 len = ldns_rdf_data(r)[src_pos]; /* start of the label */
201 /* single root label */
205 while ((len > 0) && src_pos < r_size) {
208 len = ldns_rdf_data(r)[src_pos];
217 ldns_dname_new(uint16_t s, void *d)
221 rd = LDNS_MALLOC(ldns_rdf);
225 ldns_rdf_set_size(rd, s);
226 ldns_rdf_set_type(rd, LDNS_RDF_TYPE_DNAME);
227 ldns_rdf_set_data(rd, d);
232 ldns_dname_new_frm_str(const char *str)
234 return ldns_rdf_new_frm_str(LDNS_RDF_TYPE_DNAME, str);
238 ldns_dname_new_frm_data(uint16_t size, const void *data)
240 return ldns_rdf_new_frm_data(LDNS_RDF_TYPE_DNAME, size, data);
244 ldns_dname2canonical(const ldns_rdf *rd)
249 if (ldns_rdf_get_type(rd) != LDNS_RDF_TYPE_DNAME) {
253 rdd = (uint8_t*)ldns_rdf_data(rd);
254 for (i = 0; i < ldns_rdf_size(rd); i++, rdd++) {
255 *rdd = (uint8_t)LDNS_DNAME_NORMALIZE((int)*rdd);
260 ldns_dname_is_subdomain(const ldns_rdf *sub, const ldns_rdf *parent)
265 ldns_rdf *tmp_sub = NULL;
266 ldns_rdf *tmp_par = NULL;
268 ldns_rdf *parent_clone;
271 if (ldns_rdf_get_type(sub) != LDNS_RDF_TYPE_DNAME ||
272 ldns_rdf_get_type(parent) != LDNS_RDF_TYPE_DNAME ||
273 ldns_rdf_compare(sub, parent) == 0) {
277 /* would be nicer if we do not have to clone... */
278 sub_clone = ldns_dname_clone_from(sub, 0);
279 parent_clone = ldns_dname_clone_from(parent, 0);
280 ldns_dname2canonical(sub_clone);
281 ldns_dname2canonical(parent_clone);
283 sub_lab = ldns_dname_label_count(sub_clone);
284 par_lab = ldns_dname_label_count(parent_clone);
286 /* if sub sits above parent, it cannot be a child/sub domain */
287 if (sub_lab < par_lab) {
290 /* check all labels the from the parent labels, from right to left.
291 * When they /all/ match we have found a subdomain
293 j = sub_lab - 1; /* we count from zero, thank you */
294 for (i = par_lab -1; i >= 0; i--) {
295 tmp_sub = ldns_dname_label(sub_clone, j);
296 tmp_par = ldns_dname_label(parent_clone, i);
297 if (!tmp_sub || !tmp_par) {
298 /* deep free does null check */
299 ldns_rdf_deep_free(tmp_sub);
300 ldns_rdf_deep_free(tmp_par);
305 if (ldns_rdf_compare(tmp_sub, tmp_par) != 0) {
306 /* they are not equal */
307 ldns_rdf_deep_free(tmp_sub);
308 ldns_rdf_deep_free(tmp_par);
312 ldns_rdf_deep_free(tmp_sub);
313 ldns_rdf_deep_free(tmp_par);
317 ldns_rdf_deep_free(sub_clone);
318 ldns_rdf_deep_free(parent_clone);
323 ldns_dname_compare(const ldns_rdf *dname1, const ldns_rdf *dname2)
325 size_t lc1, lc2, lc1f, lc2f;
330 /* see RFC4034 for this algorithm */
331 /* this algorithm assumes the names are normalized to case */
333 /* only when both are not NULL we can say anything about them */
334 if (!dname1 && !dname2) {
337 if (!dname1 || !dname2) {
340 /* asserts must happen later as we are looking in the
341 * dname, which could be NULL. But this case is handled
344 assert(ldns_rdf_get_type(dname1) == LDNS_RDF_TYPE_DNAME);
345 assert(ldns_rdf_get_type(dname2) == LDNS_RDF_TYPE_DNAME);
347 lc1 = ldns_dname_label_count(dname1);
348 lc2 = ldns_dname_label_count(dname2);
350 if (lc1 == 0 && lc2 == 0) {
361 /* we start at the last label */
363 /* find the label first */
365 lp1 = ldns_rdf_data(dname1);
371 /* and find the other one */
373 lp2 = ldns_rdf_data(dname2);
379 /* now check the label character for character. */
380 for (i = 1; i < (size_t)(*lp1 + 1); i++) {
382 /* apparently label 1 is larger */
386 if (LDNS_DNAME_NORMALIZE((int) *(lp1 + i)) <
387 LDNS_DNAME_NORMALIZE((int) *(lp2 + i))) {
390 } else if (LDNS_DNAME_NORMALIZE((int) *(lp1 + i)) >
391 LDNS_DNAME_NORMALIZE((int) *(lp2 + i))) {
397 /* apparently label 2 is larger */
401 if (lc1 == 0 && lc2 > 0) {
404 } else if (lc1 > 0 && lc2 == 0) {
407 } else if (lc1 == 0 && lc2 == 0) {
420 ldns_dname_match_wildcard(const ldns_rdf *dname, const ldns_rdf *wildcard)
422 ldns_rdf *wc_chopped;
424 /* check whether it really is a wildcard */
425 if (ldns_dname_label_count(wildcard) > 0 &&
426 ldns_rdf_data(wildcard)[0] == 1 &&
427 ldns_rdf_data(wildcard)[1] == '*') {
428 /* ok, so the dname needs to be a subdomain of the wildcard
431 wc_chopped = ldns_dname_left_chop(wildcard);
432 result = (int) ldns_dname_is_subdomain(dname, wc_chopped);
433 ldns_rdf_deep_free(wc_chopped);
435 result = (ldns_dname_compare(dname, wildcard) == 0);
440 /* nsec test: does prev <= middle < next
442 * 0 = error/can't tell
446 ldns_dname_interval(const ldns_rdf *prev, const ldns_rdf *middle,
447 const ldns_rdf *next)
449 int prev_check, next_check;
451 assert(ldns_rdf_get_type(prev) == LDNS_RDF_TYPE_DNAME);
452 assert(ldns_rdf_get_type(middle) == LDNS_RDF_TYPE_DNAME);
453 assert(ldns_rdf_get_type(next) == LDNS_RDF_TYPE_DNAME);
455 prev_check = ldns_dname_compare(prev, middle);
456 next_check = ldns_dname_compare(middle, next);
457 /* <= next. This cannot be the case for nsec, because then we would
458 * have gotten the nsec of next...
460 if (next_check == 0) {
465 if ((prev_check == -1 || prev_check == 0) &&
476 ldns_dname_str_absolute(const char *dname_str)
478 if(dname_str && strcmp(dname_str, ".") == 0)
481 strlen(dname_str) > 1 &&
482 dname_str[strlen(dname_str) - 1] == '.' &&
483 dname_str[strlen(dname_str) - 2] != '\\');
487 ldns_dname_label(const ldns_rdf *rdf, uint8_t labelpos)
495 if (ldns_rdf_get_type(rdf) != LDNS_RDF_TYPE_DNAME) {
501 s = ldns_rdf_size(rdf);
503 len = ldns_rdf_data(rdf)[src_pos]; /* label start */
504 while ((len > 0) && src_pos < s) {
505 if (labelcnt == labelpos) {
506 /* found our label */
507 tmpnew = LDNS_MALLOC(ldns_rdf);
511 tmpnew->_type = LDNS_RDF_TYPE_DNAME;
512 tmpnew->_data = LDNS_XMALLOC(uint8_t, len + 2);
513 if (!tmpnew->_data) {
517 memset(tmpnew->_data, 0, len + 2);
518 memcpy(tmpnew->_data, ldns_rdf_data(rdf) + src_pos, len + 1);
519 tmpnew->_size = len + 2;
524 len = ldns_rdf_data(rdf)[src_pos];