dhcpcd: Update README.DRAGONFLY for 10.0.2
[dragonfly.git] / contrib / ldns / dname.c
blob4f311ee29856bead027075c7613b045d8d3db378
1 /*
2 * dname.c
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 therefore 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>
22 #endif
23 #ifdef HAVE_SYS_SOCKET_H
24 #include <sys/socket.h>
25 #endif
26 #ifdef HAVE_NETDB_H
27 #include <netdb.h>
28 #endif
29 #ifdef HAVE_ARPA_INET_H
30 #include <arpa/inet.h>
31 #endif
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.
37 static bool
38 ldns_dname_last_label_is_root_label(const ldns_rdf* dname)
40 size_t src_pos;
41 size_t len = 0;
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;
51 ldns_rdf *
52 ldns_dname_cat_clone(const ldns_rdf *rd1, const ldns_rdf *rd2)
54 ldns_rdf *new;
55 uint16_t new_size;
56 uint8_t *buf;
57 uint16_t left_size;
59 if (ldns_rdf_get_type(rd1) != LDNS_RDF_TYPE_DNAME ||
60 ldns_rdf_get_type(rd2) != LDNS_RDF_TYPE_DNAME) {
61 return NULL;
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)) {
69 left_size--;
72 /* we overwrite the nullbyte of rd1 */
73 new_size = left_size + ldns_rdf_size(rd2);
74 buf = LDNS_XMALLOC(uint8_t, new_size);
75 if (!buf) {
76 return NULL;
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);
85 LDNS_FREE(buf);
86 return new;
89 ldns_status
90 ldns_dname_cat(ldns_rdf *rd1, const ldns_rdf *rd2)
92 uint16_t left_size;
93 uint16_t size;
94 uint8_t* newd;
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)) {
106 left_size--;
109 size = left_size + ldns_rdf_size(rd2);
110 newd = LDNS_XREALLOC(ldns_rdf_data(rd1), uint8_t, size);
111 if(!newd) {
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),
117 ldns_rdf_size(rd2));
118 ldns_rdf_set_size(rd1, size);
120 return LDNS_STATUS_OK;
123 ldns_rdf*
124 ldns_dname_reverse(const ldns_rdf *dname)
126 size_t rd_size;
127 uint8_t* buf;
128 ldns_rdf* new;
129 size_t src_pos;
130 size_t len ;
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);
136 if (! buf) {
137 return NULL;
139 new = ldns_rdf_new(LDNS_RDF_TYPE_DNAME, rd_size, buf);
140 if (! new) {
141 LDNS_FREE(buf);
142 return NULL;
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;
149 rd_size -= 1;
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);
156 return new;
159 ldns_rdf *
160 ldns_dname_clone_from(const ldns_rdf *d, uint16_t n)
162 uint8_t *data;
163 uint8_t label_size;
164 size_t data_size;
166 if (!d ||
167 ldns_rdf_get_type(d) != LDNS_RDF_TYPE_DNAME ||
168 ldns_dname_label_count(d) < n) {
169 return NULL;
172 data = ldns_rdf_data(d);
173 data_size = ldns_rdf_size(d);
174 while (n > 0) {
175 label_size = data[0] + 1;
176 data += label_size;
177 if (data_size < label_size) {
178 /* this label is very broken */
179 return NULL;
181 data_size -= label_size;
182 n--;
185 return ldns_dname_new_frm_data(data_size, data);
188 ldns_rdf *
189 ldns_dname_left_chop(const ldns_rdf *d)
191 uint8_t label_pos;
192 ldns_rdf *chop;
194 if (!d) {
195 return NULL;
198 if (ldns_rdf_get_type(d) != LDNS_RDF_TYPE_DNAME) {
199 return NULL;
201 if (ldns_dname_label_count(d) == 0) {
202 /* root label */
203 return NULL;
205 /* 05blaat02nl00 */
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);
210 return chop;
213 uint8_t
214 ldns_dname_label_count(const ldns_rdf *r)
216 uint16_t src_pos;
217 uint16_t len;
218 uint8_t i;
219 size_t r_size;
221 if (!r) {
222 return 0;
225 i = 0;
226 src_pos = 0;
227 r_size = ldns_rdf_size(r);
229 if (ldns_rdf_get_type(r) != LDNS_RDF_TYPE_DNAME) {
230 return 0;
231 } else {
232 len = ldns_rdf_data(r)[src_pos]; /* start of the label */
234 /* single root label */
235 if (1 == r_size) {
236 return 0;
237 } else {
238 while ((len > 0) && src_pos < r_size) {
239 src_pos++;
240 src_pos += len;
241 len = ldns_rdf_data(r)[src_pos];
242 i++;
246 return i;
249 ldns_rdf *
250 ldns_dname_new(uint16_t s, void *d)
252 ldns_rdf *rd;
254 if (!s || !d) {
255 return NULL;
257 rd = LDNS_MALLOC(ldns_rdf);
258 if (!rd) {
259 return NULL;
261 ldns_rdf_set_size(rd, s);
262 ldns_rdf_set_type(rd, LDNS_RDF_TYPE_DNAME);
263 ldns_rdf_set_data(rd, d);
264 return rd;
267 ldns_rdf *
268 ldns_dname_new_frm_str(const char *str)
270 return ldns_rdf_new_frm_str(LDNS_RDF_TYPE_DNAME, str);
273 ldns_rdf *
274 ldns_dname_new_frm_data(uint16_t size, const void *data)
276 return ldns_rdf_new_frm_data(LDNS_RDF_TYPE_DNAME, size, data);
279 void
280 ldns_dname2canonical(const ldns_rdf *rd)
282 uint8_t *rdd;
283 uint16_t i;
285 if (ldns_rdf_get_type(rd) != LDNS_RDF_TYPE_DNAME) {
286 return;
289 rdd = (uint8_t*)ldns_rdf_data(rd);
290 for (i = 0; i < ldns_rdf_size(rd); i++, rdd++) {
291 *rdd = (uint8_t)LDNS_DNAME_NORMALIZE((int)*rdd);
295 bool
296 ldns_dname_is_subdomain(const ldns_rdf *sub, const ldns_rdf *parent)
298 uint8_t sub_lab;
299 uint8_t par_lab;
300 int8_t i, j;
301 ldns_rdf *tmp_sub = NULL;
302 ldns_rdf *tmp_par = NULL;
303 ldns_rdf *sub_clone;
304 ldns_rdf *parent_clone;
305 bool result = true;
307 if (ldns_rdf_get_type(sub) != LDNS_RDF_TYPE_DNAME ||
308 ldns_rdf_get_type(parent) != LDNS_RDF_TYPE_DNAME ||
309 ldns_rdf_compare(sub, parent) == 0) {
310 return false;
313 /* would be nicer if we do not have to clone... */
314 sub_clone = ldns_dname_clone_from(sub, 0);
315 parent_clone = ldns_dname_clone_from(parent, 0);
316 ldns_dname2canonical(sub_clone);
317 ldns_dname2canonical(parent_clone);
319 sub_lab = ldns_dname_label_count(sub_clone);
320 par_lab = ldns_dname_label_count(parent_clone);
322 /* if sub sits above parent, it cannot be a child/sub domain */
323 if (sub_lab < par_lab) {
324 result = false;
325 } else {
326 /* check all labels the from the parent labels, from right to left.
327 * When they /all/ match we have found a subdomain
329 j = sub_lab - 1; /* we count from zero, thank you */
330 for (i = par_lab -1; i >= 0; i--) {
331 tmp_sub = ldns_dname_label(sub_clone, j);
332 tmp_par = ldns_dname_label(parent_clone, i);
333 if (!tmp_sub || !tmp_par) {
334 /* deep free does null check */
335 ldns_rdf_deep_free(tmp_sub);
336 ldns_rdf_deep_free(tmp_par);
337 result = false;
338 break;
341 if (ldns_rdf_compare(tmp_sub, tmp_par) != 0) {
342 /* they are not equal */
343 ldns_rdf_deep_free(tmp_sub);
344 ldns_rdf_deep_free(tmp_par);
345 result = false;
346 break;
348 ldns_rdf_deep_free(tmp_sub);
349 ldns_rdf_deep_free(tmp_par);
350 j--;
353 ldns_rdf_deep_free(sub_clone);
354 ldns_rdf_deep_free(parent_clone);
355 return result;
359 ldns_dname_compare(const ldns_rdf *dname1, const ldns_rdf *dname2)
361 size_t lc1, lc2, lc1f, lc2f;
362 size_t i;
363 int result = 0;
364 uint8_t *lp1, *lp2;
366 /* see RFC4034 for this algorithm */
367 /* this algorithm assumes the names are normalized to case */
369 /* only when both are not NULL we can say anything about them */
370 if (!dname1 && !dname2) {
371 return 0;
373 if (!dname1 || !dname2) {
374 return -1;
376 /* asserts must happen later as we are looking in the
377 * dname, which could be NULL. But this case is handled
378 * above
380 assert(ldns_rdf_get_type(dname1) == LDNS_RDF_TYPE_DNAME);
381 assert(ldns_rdf_get_type(dname2) == LDNS_RDF_TYPE_DNAME);
383 lc1 = ldns_dname_label_count(dname1);
384 lc2 = ldns_dname_label_count(dname2);
386 if (lc1 == 0 && lc2 == 0) {
387 return 0;
389 if (lc1 == 0) {
390 return -1;
392 if (lc2 == 0) {
393 return 1;
395 lc1--;
396 lc2--;
397 /* we start at the last label */
398 while (true) {
399 /* find the label first */
400 lc1f = lc1;
401 lp1 = ldns_rdf_data(dname1);
402 while (lc1f > 0) {
403 lp1 += *lp1 + 1;
404 lc1f--;
407 /* and find the other one */
408 lc2f = lc2;
409 lp2 = ldns_rdf_data(dname2);
410 while (lc2f > 0) {
411 lp2 += *lp2 + 1;
412 lc2f--;
415 /* now check the label character for character. */
416 for (i = 1; i < (size_t)(*lp1 + 1); i++) {
417 if (i > *lp2) {
418 /* apparently label 1 is larger */
419 result = 1;
420 goto done;
422 if (LDNS_DNAME_NORMALIZE((int) *(lp1 + i)) <
423 LDNS_DNAME_NORMALIZE((int) *(lp2 + i))) {
424 result = -1;
425 goto done;
426 } else if (LDNS_DNAME_NORMALIZE((int) *(lp1 + i)) >
427 LDNS_DNAME_NORMALIZE((int) *(lp2 + i))) {
428 result = 1;
429 goto done;
432 if (*lp1 < *lp2) {
433 /* apparently label 2 is larger */
434 result = -1;
435 goto done;
437 if (lc1 == 0 && lc2 > 0) {
438 result = -1;
439 goto done;
440 } else if (lc1 > 0 && lc2 == 0) {
441 result = 1;
442 goto done;
443 } else if (lc1 == 0 && lc2 == 0) {
444 result = 0;
445 goto done;
447 lc1--;
448 lc2--;
451 done:
452 return result;
456 ldns_dname_is_wildcard(const ldns_rdf* dname)
458 return ( ldns_dname_label_count(dname) > 0 &&
459 ldns_rdf_data(dname)[0] == 1 &&
460 ldns_rdf_data(dname)[1] == '*');
464 ldns_dname_match_wildcard(const ldns_rdf *dname, const ldns_rdf *wildcard)
466 ldns_rdf *wc_chopped;
467 int result;
468 /* check whether it really is a wildcard */
469 if (ldns_dname_is_wildcard(wildcard)) {
470 /* ok, so the dname needs to be a subdomain of the wildcard
471 * without the *
473 wc_chopped = ldns_dname_left_chop(wildcard);
474 result = (int) ldns_dname_is_subdomain(dname, wc_chopped);
475 ldns_rdf_deep_free(wc_chopped);
476 } else {
477 result = (ldns_dname_compare(dname, wildcard) == 0);
479 return result;
482 /* nsec test: does prev <= middle < next
483 * -1 = yes
484 * 0 = error/can't tell
485 * 1 = no
488 ldns_dname_interval(const ldns_rdf *prev, const ldns_rdf *middle,
489 const ldns_rdf *next)
491 int prev_check, next_check;
493 assert(ldns_rdf_get_type(prev) == LDNS_RDF_TYPE_DNAME);
494 assert(ldns_rdf_get_type(middle) == LDNS_RDF_TYPE_DNAME);
495 assert(ldns_rdf_get_type(next) == LDNS_RDF_TYPE_DNAME);
497 prev_check = ldns_dname_compare(prev, middle);
498 next_check = ldns_dname_compare(middle, next);
499 /* <= next. This cannot be the case for nsec, because then we would
500 * have gotten the nsec of next...
502 if (next_check == 0) {
503 return 0;
506 /* <= */
507 if ((prev_check == -1 || prev_check == 0) &&
508 /* < */
509 next_check == -1) {
510 return -1;
511 } else {
512 return 1;
517 bool
518 ldns_dname_str_absolute(const char *dname_str)
520 const char* s;
521 if(dname_str && strcmp(dname_str, ".") == 0)
522 return 1;
523 if(!dname_str || strlen(dname_str) < 2)
524 return 0;
525 if(dname_str[strlen(dname_str) - 1] != '.')
526 return 0;
527 if(dname_str[strlen(dname_str) - 2] != '\\')
528 return 1; /* ends in . and no \ before it */
529 /* so we have the case of ends in . and there is \ before it */
530 for(s=dname_str; *s; s++) {
531 if(*s == '\\') {
532 if(s[1] && s[2] && s[3] /* check length */
533 && isdigit((unsigned char)s[1])
534 && isdigit((unsigned char)s[2])
535 && isdigit((unsigned char)s[3]))
536 s += 3;
537 else if(!s[1] || isdigit((unsigned char)s[1])) /* escape of nul,0-9 */
538 return 0; /* parse error */
539 else s++; /* another character escaped */
541 else if(!*(s+1) && *s == '.')
542 return 1; /* trailing dot, unescaped */
544 return 0;
547 bool
548 ldns_dname_absolute(const ldns_rdf *rdf)
550 char *str = ldns_rdf2str(rdf);
551 if (str) {
552 bool r = ldns_dname_str_absolute(str);
553 LDNS_FREE(str);
554 return r;
556 return false;
559 ldns_rdf *
560 ldns_dname_label(const ldns_rdf *rdf, uint8_t labelpos)
562 uint8_t labelcnt;
563 uint16_t src_pos;
564 uint16_t len;
565 ldns_rdf *tmpnew;
566 size_t s;
567 uint8_t *data;
569 if (ldns_rdf_get_type(rdf) != LDNS_RDF_TYPE_DNAME) {
570 return NULL;
573 labelcnt = 0;
574 src_pos = 0;
575 s = ldns_rdf_size(rdf);
577 len = ldns_rdf_data(rdf)[src_pos]; /* label start */
578 while ((len > 0) && src_pos < s) {
579 if (labelcnt == labelpos) {
580 /* found our label */
581 data = LDNS_XMALLOC(uint8_t, len + 2);
582 if (!data) {
583 return NULL;
585 memcpy(data, ldns_rdf_data(rdf) + src_pos, len + 1);
586 data[len + 2 - 1] = 0;
588 tmpnew = ldns_rdf_new( LDNS_RDF_TYPE_DNAME
589 , len + 2, data);
590 if (!tmpnew) {
591 LDNS_FREE(data);
592 return NULL;
594 return tmpnew;
596 src_pos++;
597 src_pos += len;
598 len = ldns_rdf_data(rdf)[src_pos];
599 labelcnt++;
601 return NULL;