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>
33 /* Returns whether the last label in the name is a root label (a empty label).
34 * Note that it is not enough to just test the last character to be 0,
35 * because it may be part of the last label itself.
38 ldns_dname_last_label_is_root_label(const ldns_rdf
* dname
)
43 for (src_pos
= 0; src_pos
< ldns_rdf_size(dname
); src_pos
+= len
+ 1) {
44 len
= ldns_rdf_data(dname
)[src_pos
];
46 assert(src_pos
== ldns_rdf_size(dname
));
48 return src_pos
> 0 && len
== 0;
52 ldns_dname_cat_clone(const ldns_rdf
*rd1
, const ldns_rdf
*rd2
)
59 if (ldns_rdf_get_type(rd1
) != LDNS_RDF_TYPE_DNAME
||
60 ldns_rdf_get_type(rd2
) != LDNS_RDF_TYPE_DNAME
) {
64 /* remove root label if it is present at the end of the left
65 * rd, by reducing the size with 1
67 left_size
= ldns_rdf_size(rd1
);
68 if (ldns_dname_last_label_is_root_label(rd1
)) {
72 /* we overwrite the nullbyte of rd1 */
73 new_size
= left_size
+ ldns_rdf_size(rd2
);
74 buf
= LDNS_XMALLOC(uint8_t, new_size
);
79 /* put the two dname's after each other */
80 memcpy(buf
, ldns_rdf_data(rd1
), left_size
);
81 memcpy(buf
+ left_size
, ldns_rdf_data(rd2
), ldns_rdf_size(rd2
));
83 new = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_DNAME
, new_size
, buf
);
90 ldns_dname_cat(ldns_rdf
*rd1
, ldns_rdf
*rd2
)
96 if (ldns_rdf_get_type(rd1
) != LDNS_RDF_TYPE_DNAME
||
97 ldns_rdf_get_type(rd2
) != LDNS_RDF_TYPE_DNAME
) {
98 return LDNS_STATUS_ERR
;
101 /* remove root label if it is present at the end of the left
102 * rd, by reducing the size with 1
104 left_size
= ldns_rdf_size(rd1
);
105 if (ldns_dname_last_label_is_root_label(rd1
)) {
109 size
= left_size
+ ldns_rdf_size(rd2
);
110 newd
= LDNS_XREALLOC(ldns_rdf_data(rd1
), uint8_t, size
);
112 return LDNS_STATUS_MEM_ERR
;
115 ldns_rdf_set_data(rd1
, newd
);
116 memcpy(ldns_rdf_data(rd1
) + left_size
, ldns_rdf_data(rd2
),
118 ldns_rdf_set_size(rd1
, size
);
120 return LDNS_STATUS_OK
;
124 ldns_dname_reverse(const ldns_rdf
*dname
)
132 assert(ldns_rdf_get_type(dname
) == LDNS_RDF_TYPE_DNAME
);
134 rd_size
= ldns_rdf_size(dname
);
135 buf
= LDNS_XMALLOC(uint8_t, rd_size
);
139 new = ldns_rdf_new(LDNS_RDF_TYPE_DNAME
, rd_size
, buf
);
145 /* If dname ends in a root label, the reverse should too.
147 if (ldns_dname_last_label_is_root_label(dname
)) {
148 buf
[rd_size
- 1] = 0;
151 for (src_pos
= 0; src_pos
< rd_size
; src_pos
+= len
+ 1) {
152 len
= ldns_rdf_data(dname
)[src_pos
];
153 memcpy(&buf
[rd_size
- src_pos
- len
- 1],
154 &ldns_rdf_data(dname
)[src_pos
], len
+ 1);
160 ldns_dname_clone_from(const ldns_rdf
*d
, uint16_t n
)
167 ldns_rdf_get_type(d
) != LDNS_RDF_TYPE_DNAME
||
168 ldns_dname_label_count(d
) < n
) {
172 data
= ldns_rdf_data(d
);
173 data_size
= ldns_rdf_size(d
);
175 label_size
= data
[0] + 1;
177 if (data_size
< label_size
) {
178 /* this label is very broken */
181 data_size
-= label_size
;
185 return ldns_dname_new_frm_data(data_size
, data
);
189 ldns_dname_left_chop(const ldns_rdf
*d
)
198 if (ldns_rdf_get_type(d
) != LDNS_RDF_TYPE_DNAME
) {
201 if (ldns_dname_label_count(d
) == 0) {
206 label_pos
= ldns_rdf_data(d
)[0];
208 chop
= ldns_dname_new_frm_data(ldns_rdf_size(d
) - label_pos
- 1,
209 ldns_rdf_data(d
) + label_pos
+ 1);
214 ldns_dname_label_count(const ldns_rdf
*r
)
227 r_size
= ldns_rdf_size(r
);
229 if (ldns_rdf_get_type(r
) != LDNS_RDF_TYPE_DNAME
) {
232 len
= ldns_rdf_data(r
)[src_pos
]; /* start of the label */
234 /* single root label */
238 while ((len
> 0) && src_pos
< r_size
) {
241 len
= ldns_rdf_data(r
)[src_pos
];
250 ldns_dname_new(uint16_t s
, void *d
)
254 rd
= LDNS_MALLOC(ldns_rdf
);
258 ldns_rdf_set_size(rd
, s
);
259 ldns_rdf_set_type(rd
, LDNS_RDF_TYPE_DNAME
);
260 ldns_rdf_set_data(rd
, d
);
265 ldns_dname_new_frm_str(const char *str
)
267 return ldns_rdf_new_frm_str(LDNS_RDF_TYPE_DNAME
, str
);
271 ldns_dname_new_frm_data(uint16_t size
, const void *data
)
273 return ldns_rdf_new_frm_data(LDNS_RDF_TYPE_DNAME
, size
, data
);
277 ldns_dname2canonical(const ldns_rdf
*rd
)
282 if (ldns_rdf_get_type(rd
) != LDNS_RDF_TYPE_DNAME
) {
286 rdd
= (uint8_t*)ldns_rdf_data(rd
);
287 for (i
= 0; i
< ldns_rdf_size(rd
); i
++, rdd
++) {
288 *rdd
= (uint8_t)LDNS_DNAME_NORMALIZE((int)*rdd
);
293 ldns_dname_is_subdomain(const ldns_rdf
*sub
, const ldns_rdf
*parent
)
298 ldns_rdf
*tmp_sub
= NULL
;
299 ldns_rdf
*tmp_par
= NULL
;
301 ldns_rdf
*parent_clone
;
304 if (ldns_rdf_get_type(sub
) != LDNS_RDF_TYPE_DNAME
||
305 ldns_rdf_get_type(parent
) != LDNS_RDF_TYPE_DNAME
||
306 ldns_rdf_compare(sub
, parent
) == 0) {
310 /* would be nicer if we do not have to clone... */
311 sub_clone
= ldns_dname_clone_from(sub
, 0);
312 parent_clone
= ldns_dname_clone_from(parent
, 0);
313 ldns_dname2canonical(sub_clone
);
314 ldns_dname2canonical(parent_clone
);
316 sub_lab
= ldns_dname_label_count(sub_clone
);
317 par_lab
= ldns_dname_label_count(parent_clone
);
319 /* if sub sits above parent, it cannot be a child/sub domain */
320 if (sub_lab
< par_lab
) {
323 /* check all labels the from the parent labels, from right to left.
324 * When they /all/ match we have found a subdomain
326 j
= sub_lab
- 1; /* we count from zero, thank you */
327 for (i
= par_lab
-1; i
>= 0; i
--) {
328 tmp_sub
= ldns_dname_label(sub_clone
, j
);
329 tmp_par
= ldns_dname_label(parent_clone
, i
);
330 if (!tmp_sub
|| !tmp_par
) {
331 /* deep free does null check */
332 ldns_rdf_deep_free(tmp_sub
);
333 ldns_rdf_deep_free(tmp_par
);
338 if (ldns_rdf_compare(tmp_sub
, tmp_par
) != 0) {
339 /* they are not equal */
340 ldns_rdf_deep_free(tmp_sub
);
341 ldns_rdf_deep_free(tmp_par
);
345 ldns_rdf_deep_free(tmp_sub
);
346 ldns_rdf_deep_free(tmp_par
);
350 ldns_rdf_deep_free(sub_clone
);
351 ldns_rdf_deep_free(parent_clone
);
356 ldns_dname_compare(const ldns_rdf
*dname1
, const ldns_rdf
*dname2
)
358 size_t lc1
, lc2
, lc1f
, lc2f
;
363 /* see RFC4034 for this algorithm */
364 /* this algorithm assumes the names are normalized to case */
366 /* only when both are not NULL we can say anything about them */
367 if (!dname1
&& !dname2
) {
370 if (!dname1
|| !dname2
) {
373 /* asserts must happen later as we are looking in the
374 * dname, which could be NULL. But this case is handled
377 assert(ldns_rdf_get_type(dname1
) == LDNS_RDF_TYPE_DNAME
);
378 assert(ldns_rdf_get_type(dname2
) == LDNS_RDF_TYPE_DNAME
);
380 lc1
= ldns_dname_label_count(dname1
);
381 lc2
= ldns_dname_label_count(dname2
);
383 if (lc1
== 0 && lc2
== 0) {
394 /* we start at the last label */
396 /* find the label first */
398 lp1
= ldns_rdf_data(dname1
);
404 /* and find the other one */
406 lp2
= ldns_rdf_data(dname2
);
412 /* now check the label character for character. */
413 for (i
= 1; i
< (size_t)(*lp1
+ 1); i
++) {
415 /* apparently label 1 is larger */
419 if (LDNS_DNAME_NORMALIZE((int) *(lp1
+ i
)) <
420 LDNS_DNAME_NORMALIZE((int) *(lp2
+ i
))) {
423 } else if (LDNS_DNAME_NORMALIZE((int) *(lp1
+ i
)) >
424 LDNS_DNAME_NORMALIZE((int) *(lp2
+ i
))) {
430 /* apparently label 2 is larger */
434 if (lc1
== 0 && lc2
> 0) {
437 } else if (lc1
> 0 && lc2
== 0) {
440 } else if (lc1
== 0 && lc2
== 0) {
453 ldns_dname_is_wildcard(const ldns_rdf
* dname
)
455 return ( ldns_dname_label_count(dname
) > 0 &&
456 ldns_rdf_data(dname
)[0] == 1 &&
457 ldns_rdf_data(dname
)[1] == '*');
461 ldns_dname_match_wildcard(const ldns_rdf
*dname
, const ldns_rdf
*wildcard
)
463 ldns_rdf
*wc_chopped
;
465 /* check whether it really is a wildcard */
466 if (ldns_dname_is_wildcard(wildcard
)) {
467 /* ok, so the dname needs to be a subdomain of the wildcard
470 wc_chopped
= ldns_dname_left_chop(wildcard
);
471 result
= (int) ldns_dname_is_subdomain(dname
, wc_chopped
);
472 ldns_rdf_deep_free(wc_chopped
);
474 result
= (ldns_dname_compare(dname
, wildcard
) == 0);
479 /* nsec test: does prev <= middle < next
481 * 0 = error/can't tell
485 ldns_dname_interval(const ldns_rdf
*prev
, const ldns_rdf
*middle
,
486 const ldns_rdf
*next
)
488 int prev_check
, next_check
;
490 assert(ldns_rdf_get_type(prev
) == LDNS_RDF_TYPE_DNAME
);
491 assert(ldns_rdf_get_type(middle
) == LDNS_RDF_TYPE_DNAME
);
492 assert(ldns_rdf_get_type(next
) == LDNS_RDF_TYPE_DNAME
);
494 prev_check
= ldns_dname_compare(prev
, middle
);
495 next_check
= ldns_dname_compare(middle
, next
);
496 /* <= next. This cannot be the case for nsec, because then we would
497 * have gotten the nsec of next...
499 if (next_check
== 0) {
504 if ((prev_check
== -1 || prev_check
== 0) &&
515 ldns_dname_str_absolute(const char *dname_str
)
518 if(dname_str
&& strcmp(dname_str
, ".") == 0)
520 if(!dname_str
|| strlen(dname_str
) < 2)
522 if(dname_str
[strlen(dname_str
) - 1] != '.')
524 if(dname_str
[strlen(dname_str
) - 2] != '\\')
525 return 1; /* ends in . and no \ before it */
526 /* so we have the case of ends in . and there is \ before it */
527 for(s
=dname_str
; *s
; s
++) {
529 if(s
[1] && s
[2] && s
[3] /* check length */
530 && isdigit(s
[1]) && isdigit(s
[2]) &&
533 else if(!s
[1] || isdigit(s
[1])) /* escape of nul,0-9 */
534 return 0; /* parse error */
535 else s
++; /* another character escaped */
537 else if(!*(s
+1) && *s
== '.')
538 return 1; /* trailing dot, unescaped */
544 ldns_dname_absolute(const ldns_rdf
*rdf
)
546 char *str
= ldns_rdf2str(rdf
);
548 bool r
= ldns_dname_str_absolute(str
);
556 ldns_dname_label(const ldns_rdf
*rdf
, uint8_t labelpos
)
565 if (ldns_rdf_get_type(rdf
) != LDNS_RDF_TYPE_DNAME
) {
571 s
= ldns_rdf_size(rdf
);
573 len
= ldns_rdf_data(rdf
)[src_pos
]; /* label start */
574 while ((len
> 0) && src_pos
< s
) {
575 if (labelcnt
== labelpos
) {
576 /* found our label */
577 data
= LDNS_XMALLOC(uint8_t, len
+ 2);
581 memcpy(data
, ldns_rdf_data(rdf
) + src_pos
, len
+ 1);
582 data
[len
+ 2 - 1] = 0;
584 tmpnew
= ldns_rdf_new( LDNS_RDF_TYPE_DNAME
594 len
= ldns_rdf_data(rdf
)[src_pos
];