File Coverage

src/ldns/dname.c
Criterion Covered Total %
statement 131 276 47.4
branch 63 166 37.9
condition n/a
subroutine n/a
pod n/a
total 194 442 43.8


line stmt bran cond sub pod time code
1             /*
2             * dname.c
3             *
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.
8             *
9             * a Net::DNS like library for C
10             *
11             * (c) NLnet Labs, 2004-2006
12             *
13             * See the file LICENSE for the license
14             */
15              
16             #include
17              
18             #include
19              
20             #ifdef HAVE_NETINET_IN_H
21             #include
22             #endif
23             #ifdef HAVE_SYS_SOCKET_H
24             #include
25             #endif
26             #ifdef HAVE_NETDB_H
27             #include
28             #endif
29             #ifdef HAVE_ARPA_INET_H
30             #include
31             #endif
32              
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.
36             */
37             static bool
38 16           ldns_dname_last_label_is_root_label(const ldns_rdf* dname)
39             {
40             size_t src_pos;
41 16           size_t len = 0;
42              
43 55 100         for (src_pos = 0; src_pos < ldns_rdf_size(dname); src_pos += len + 1) {
44 39           len = ldns_rdf_data(dname)[src_pos];
45             }
46             assert(src_pos == ldns_rdf_size(dname));
47              
48 16 50         return src_pos > 0 && len == 0;
    50          
49             }
50              
51             ldns_rdf *
52 2           ldns_dname_cat_clone(const ldns_rdf *rd1, const ldns_rdf *rd2)
53             {
54             ldns_rdf *new;
55             uint16_t new_size;
56             uint8_t *buf;
57             uint16_t left_size;
58              
59 4           if (ldns_rdf_get_type(rd1) != LDNS_RDF_TYPE_DNAME ||
60 2           ldns_rdf_get_type(rd2) != LDNS_RDF_TYPE_DNAME) {
61 0           return NULL;
62             }
63              
64             /* remove root label if it is present at the end of the left
65             * rd, by reducing the size with 1
66             */
67 2           left_size = ldns_rdf_size(rd1);
68 2 50         if (ldns_dname_last_label_is_root_label(rd1)) {
69 2           left_size--;
70             }
71              
72             /* we overwrite the nullbyte of rd1 */
73 2           new_size = left_size + ldns_rdf_size(rd2);
74 2           buf = LDNS_XMALLOC(uint8_t, new_size);
75 2 50         if (!buf) {
76 0           return NULL;
77             }
78              
79             /* put the two dname's after each other */
80 2           memcpy(buf, ldns_rdf_data(rd1), left_size);
81 2           memcpy(buf + left_size, ldns_rdf_data(rd2), ldns_rdf_size(rd2));
82              
83 2           new = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_DNAME, new_size, buf);
84              
85 2           LDNS_FREE(buf);
86 2           return new;
87             }
88              
89             ldns_status
90 14           ldns_dname_cat(ldns_rdf *rd1, ldns_rdf *rd2)
91             {
92             uint16_t left_size;
93             uint16_t size;
94             uint8_t* newd;
95              
96 28           if (ldns_rdf_get_type(rd1) != LDNS_RDF_TYPE_DNAME ||
97 14           ldns_rdf_get_type(rd2) != LDNS_RDF_TYPE_DNAME) {
98 0           return LDNS_STATUS_ERR;
99             }
100              
101             /* remove root label if it is present at the end of the left
102             * rd, by reducing the size with 1
103             */
104 14           left_size = ldns_rdf_size(rd1);
105 14 50         if (ldns_dname_last_label_is_root_label(rd1)) {
106 14           left_size--;
107             }
108              
109 14           size = left_size + ldns_rdf_size(rd2);
110 14           newd = LDNS_XREALLOC(ldns_rdf_data(rd1), uint8_t, size);
111 14 50         if(!newd) {
112 0           return LDNS_STATUS_MEM_ERR;
113             }
114              
115 14           ldns_rdf_set_data(rd1, newd);
116 14           memcpy(ldns_rdf_data(rd1) + left_size, ldns_rdf_data(rd2),
117             ldns_rdf_size(rd2));
118 14           ldns_rdf_set_size(rd1, size);
119              
120 14           return LDNS_STATUS_OK;
121             }
122              
123             ldns_rdf*
124 0           ldns_dname_reverse(const ldns_rdf *dname)
125             {
126             size_t rd_size;
127             uint8_t* buf;
128             ldns_rdf* new;
129             size_t src_pos;
130             size_t len ;
131              
132             assert(ldns_rdf_get_type(dname) == LDNS_RDF_TYPE_DNAME);
133            
134 0           rd_size = ldns_rdf_size(dname);
135 0           buf = LDNS_XMALLOC(uint8_t, rd_size);
136 0 0         if (! buf) {
137 0           return NULL;
138             }
139 0           new = ldns_rdf_new(LDNS_RDF_TYPE_DNAME, rd_size, buf);
140 0 0         if (! new) {
141 0           LDNS_FREE(buf);
142 0           return NULL;
143             }
144            
145             /* If dname ends in a root label, the reverse should too.
146             */
147 0 0         if (ldns_dname_last_label_is_root_label(dname)) {
148 0           buf[rd_size - 1] = 0;
149 0           rd_size -= 1;
150             }
151 0 0         for (src_pos = 0; src_pos < rd_size; src_pos += len + 1) {
152 0           len = ldns_rdf_data(dname)[src_pos];
153 0           memcpy(&buf[rd_size - src_pos - len - 1],
154 0           &ldns_rdf_data(dname)[src_pos], len + 1);
155             }
156 0           return new;
157             }
158              
159             ldns_rdf *
160 0           ldns_dname_clone_from(const ldns_rdf *d, uint16_t n)
161             {
162             uint8_t *data;
163             uint8_t label_size;
164             size_t data_size;
165              
166 0           if (!d ||
167 0 0         ldns_rdf_get_type(d) != LDNS_RDF_TYPE_DNAME ||
168 0           ldns_dname_label_count(d) < n) {
169 0           return NULL;
170             }
171              
172 0           data = ldns_rdf_data(d);
173 0           data_size = ldns_rdf_size(d);
174 0 0         while (n > 0) {
175 0           label_size = data[0] + 1;
176 0           data += label_size;
177 0 0         if (data_size < label_size) {
178             /* this label is very broken */
179 0           return NULL;
180             }
181 0           data_size -= label_size;
182 0           n--;
183             }
184              
185 0           return ldns_dname_new_frm_data(data_size, data);
186             }
187              
188             ldns_rdf *
189 82           ldns_dname_left_chop(const ldns_rdf *d)
190             {
191             uint8_t label_pos;
192             ldns_rdf *chop;
193              
194 82 50         if (!d) {
195 0           return NULL;
196             }
197              
198 82 50         if (ldns_rdf_get_type(d) != LDNS_RDF_TYPE_DNAME) {
199 0           return NULL;
200             }
201 82 50         if (ldns_dname_label_count(d) == 0) {
202             /* root label */
203 0           return NULL;
204             }
205             /* 05blaat02nl00 */
206 82           label_pos = ldns_rdf_data(d)[0];
207              
208 82           chop = ldns_dname_new_frm_data(ldns_rdf_size(d) - label_pos - 1,
209 82           ldns_rdf_data(d) + label_pos + 1);
210 82           return chop;
211             }
212              
213             uint8_t
214 283           ldns_dname_label_count(const ldns_rdf *r)
215             {
216             uint16_t src_pos;
217             uint16_t len;
218             uint8_t i;
219             size_t r_size;
220              
221 283 50         if (!r) {
222 0           return 0;
223             }
224              
225 283           i = 0;
226 283           src_pos = 0;
227 283           r_size = ldns_rdf_size(r);
228              
229 283 50         if (ldns_rdf_get_type(r) != LDNS_RDF_TYPE_DNAME) {
230 0           return 0;
231             } else {
232 283           len = ldns_rdf_data(r)[src_pos]; /* start of the label */
233              
234             /* single root label */
235 283 100         if (1 == r_size) {
236 34           return 0;
237             } else {
238 745 100         while ((len > 0) && src_pos < r_size) {
    50          
239 496           src_pos++;
240 496           src_pos += len;
241 496           len = ldns_rdf_data(r)[src_pos];
242 496           i++;
243             }
244             }
245             }
246 249           return i;
247             }
248              
249             ldns_rdf *
250 0           ldns_dname_new(uint16_t s, void *d)
251             {
252             ldns_rdf *rd;
253              
254 0           rd = LDNS_MALLOC(ldns_rdf);
255 0 0         if (!rd) {
256 0           return NULL;
257             }
258 0           ldns_rdf_set_size(rd, s);
259 0           ldns_rdf_set_type(rd, LDNS_RDF_TYPE_DNAME);
260 0           ldns_rdf_set_data(rd, d);
261 0           return rd;
262             }
263              
264             ldns_rdf *
265 74           ldns_dname_new_frm_str(const char *str)
266             {
267 74           return ldns_rdf_new_frm_str(LDNS_RDF_TYPE_DNAME, str);
268             }
269              
270             ldns_rdf *
271 82           ldns_dname_new_frm_data(uint16_t size, const void *data)
272             {
273 82           return ldns_rdf_new_frm_data(LDNS_RDF_TYPE_DNAME, size, data);
274             }
275              
276             void
277 60           ldns_dname2canonical(const ldns_rdf *rd)
278             {
279             uint8_t *rdd;
280             uint16_t i;
281              
282 60 100         if (ldns_rdf_get_type(rd) != LDNS_RDF_TYPE_DNAME) {
283 25           return;
284             }
285              
286 35           rdd = (uint8_t*)ldns_rdf_data(rd);
287 437 100         for (i = 0; i < ldns_rdf_size(rd); i++, rdd++) {
288 402           *rdd = (uint8_t)LDNS_DNAME_NORMALIZE((int)*rdd);
289             }
290             }
291              
292             bool
293 0           ldns_dname_is_subdomain(const ldns_rdf *sub, const ldns_rdf *parent)
294             {
295             uint8_t sub_lab;
296             uint8_t par_lab;
297             int8_t i, j;
298 0           ldns_rdf *tmp_sub = NULL;
299 0           ldns_rdf *tmp_par = NULL;
300             ldns_rdf *sub_clone;
301             ldns_rdf *parent_clone;
302 0           bool result = true;
303              
304 0           if (ldns_rdf_get_type(sub) != LDNS_RDF_TYPE_DNAME ||
305 0 0         ldns_rdf_get_type(parent) != LDNS_RDF_TYPE_DNAME ||
306 0           ldns_rdf_compare(sub, parent) == 0) {
307 0           return false;
308             }
309              
310             /* would be nicer if we do not have to clone... */
311 0           sub_clone = ldns_dname_clone_from(sub, 0);
312 0           parent_clone = ldns_dname_clone_from(parent, 0);
313 0           ldns_dname2canonical(sub_clone);
314 0           ldns_dname2canonical(parent_clone);
315              
316 0           sub_lab = ldns_dname_label_count(sub_clone);
317 0           par_lab = ldns_dname_label_count(parent_clone);
318              
319             /* if sub sits above parent, it cannot be a child/sub domain */
320 0 0         if (sub_lab < par_lab) {
321 0           result = false;
322             } else {
323             /* check all labels the from the parent labels, from right to left.
324             * When they /all/ match we have found a subdomain
325             */
326 0           j = sub_lab - 1; /* we count from zero, thank you */
327 0 0         for (i = par_lab -1; i >= 0; i--) {
328 0           tmp_sub = ldns_dname_label(sub_clone, j);
329 0           tmp_par = ldns_dname_label(parent_clone, i);
330 0 0         if (!tmp_sub || !tmp_par) {
    0          
331             /* deep free does null check */
332 0           ldns_rdf_deep_free(tmp_sub);
333 0           ldns_rdf_deep_free(tmp_par);
334 0           result = false;
335 0           break;
336             }
337              
338 0 0         if (ldns_rdf_compare(tmp_sub, tmp_par) != 0) {
339             /* they are not equal */
340 0           ldns_rdf_deep_free(tmp_sub);
341 0           ldns_rdf_deep_free(tmp_par);
342 0           result = false;
343 0           break;
344             }
345 0           ldns_rdf_deep_free(tmp_sub);
346 0           ldns_rdf_deep_free(tmp_par);
347 0           j--;
348             }
349             }
350 0           ldns_rdf_deep_free(sub_clone);
351 0           ldns_rdf_deep_free(parent_clone);
352 0           return result;
353             }
354              
355             int
356 38           ldns_dname_compare(const ldns_rdf *dname1, const ldns_rdf *dname2)
357             {
358             size_t lc1, lc2, lc1f, lc2f;
359             size_t i;
360 38           int result = 0;
361             uint8_t *lp1, *lp2;
362              
363             /* see RFC4034 for this algorithm */
364             /* this algorithm assumes the names are normalized to case */
365              
366             /* only when both are not NULL we can say anything about them */
367 38 50         if (!dname1 && !dname2) {
    0          
368 0           return 0;
369             }
370 38 50         if (!dname1 || !dname2) {
    50          
371 0           return -1;
372             }
373             /* asserts must happen later as we are looking in the
374             * dname, which could be NULL. But this case is handled
375             * above
376             */
377             assert(ldns_rdf_get_type(dname1) == LDNS_RDF_TYPE_DNAME);
378             assert(ldns_rdf_get_type(dname2) == LDNS_RDF_TYPE_DNAME);
379              
380 38           lc1 = ldns_dname_label_count(dname1);
381 38           lc2 = ldns_dname_label_count(dname2);
382              
383 38 50         if (lc1 == 0 && lc2 == 0) {
    0          
384 0           return 0;
385             }
386 38 50         if (lc1 == 0) {
387 0           return -1;
388             }
389 38 50         if (lc2 == 0) {
390 0           return 1;
391             }
392 38           lc1--;
393 38           lc2--;
394             /* we start at the last label */
395             while (true) {
396             /* find the label first */
397 72           lc1f = lc1;
398 72           lp1 = ldns_rdf_data(dname1);
399 106 100         while (lc1f > 0) {
400 34           lp1 += *lp1 + 1;
401 34           lc1f--;
402             }
403              
404             /* and find the other one */
405 72           lc2f = lc2;
406 72           lp2 = ldns_rdf_data(dname2);
407 106 100         while (lc2f > 0) {
408 34           lp2 += *lp2 + 1;
409 34           lc2f--;
410             }
411              
412             /* now check the label character for character. */
413 233 100         for (i = 1; i < (size_t)(*lp1 + 1); i++) {
414 172 50         if (i > *lp2) {
415             /* apparently label 1 is larger */
416 0           result = 1;
417 0           goto done;
418             }
419 172 100         if (LDNS_DNAME_NORMALIZE((int) *(lp1 + i)) <
420 172           LDNS_DNAME_NORMALIZE((int) *(lp2 + i))) {
421 7           result = -1;
422 7           goto done;
423 165 100         } else if (LDNS_DNAME_NORMALIZE((int) *(lp1 + i)) >
424 165           LDNS_DNAME_NORMALIZE((int) *(lp2 + i))) {
425 4           result = 1;
426 4           goto done;
427             }
428             }
429 61 100         if (*lp1 < *lp2) {
430             /* apparently label 2 is larger */
431 3           result = -1;
432 3           goto done;
433             }
434 58 100         if (lc1 == 0 && lc2 > 0) {
    50          
435 0           result = -1;
436 0           goto done;
437 58 100         } else if (lc1 > 0 && lc2 == 0) {
    50          
438 0           result = 1;
439 0           goto done;
440 58 100         } else if (lc1 == 0 && lc2 == 0) {
    50          
441 24           result = 0;
442 24           goto done;
443             }
444 34           lc1--;
445 34           lc2--;
446 34           }
447              
448             done:
449 38           return result;
450             }
451              
452             int
453 0           ldns_dname_is_wildcard(const ldns_rdf* dname)
454             {
455 0 0         return ( ldns_dname_label_count(dname) > 0 &&
456 0 0         ldns_rdf_data(dname)[0] == 1 &&
    0          
457 0           ldns_rdf_data(dname)[1] == '*');
458             }
459              
460             int
461 0           ldns_dname_match_wildcard(const ldns_rdf *dname, const ldns_rdf *wildcard)
462             {
463             ldns_rdf *wc_chopped;
464             int result;
465             /* check whether it really is a wildcard */
466 0 0         if (ldns_dname_is_wildcard(wildcard)) {
467             /* ok, so the dname needs to be a subdomain of the wildcard
468             * without the *
469             */
470 0           wc_chopped = ldns_dname_left_chop(wildcard);
471 0           result = (int) ldns_dname_is_subdomain(dname, wc_chopped);
472 0           ldns_rdf_deep_free(wc_chopped);
473             } else {
474 0           result = (ldns_dname_compare(dname, wildcard) == 0);
475             }
476 0           return result;
477             }
478              
479             /* nsec test: does prev <= middle < next
480             * -1 = yes
481             * 0 = error/can't tell
482             * 1 = no
483             */
484             int
485 0           ldns_dname_interval(const ldns_rdf *prev, const ldns_rdf *middle,
486             const ldns_rdf *next)
487             {
488             int prev_check, next_check;
489              
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);
493              
494 0           prev_check = ldns_dname_compare(prev, middle);
495 0           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...
498             */
499 0 0         if (next_check == 0) {
500 0           return 0;
501             }
502              
503             /* <= */
504 0 0         if ((prev_check == -1 || prev_check == 0) &&
    0          
    0          
505             /* < */
506             next_check == -1) {
507 0           return -1;
508             } else {
509 0           return 1;
510             }
511             }
512              
513              
514             bool
515 169           ldns_dname_str_absolute(const char *dname_str)
516             {
517             const char* s;
518 169 50         if(dname_str && strcmp(dname_str, ".") == 0)
    50          
519 0           return 1;
520 169 50         if(!dname_str || strlen(dname_str) < 2)
    50          
521 0           return 0;
522 169 100         if(dname_str[strlen(dname_str) - 1] != '.')
523 119           return 0;
524 50 50         if(dname_str[strlen(dname_str) - 2] != '\\')
525 50           return 1; /* ends in . and no \ before it */
526             /* so we have the case of ends in . and there is \ before it */
527 0 0         for(s=dname_str; *s; s++) {
528 0 0         if(*s == '\\') {
529 0 0         if(s[1] && s[2] && s[3] /* check length */
    0          
    0          
530 0 0         && isdigit(s[1]) && isdigit(s[2]) &&
531 0           isdigit(s[3]))
532 0           s += 3;
533 0 0         else if(!s[1] || isdigit(s[1])) /* escape of nul,0-9 */
    0          
534 0           return 0; /* parse error */
535 0           else s++; /* another character escaped */
536             }
537 0 0         else if(!*(s+1) && *s == '.')
    0          
538 0           return 1; /* trailing dot, unescaped */
539             }
540 0           return 0;
541             }
542              
543             bool
544 0           ldns_dname_absolute(const ldns_rdf *rdf)
545             {
546 0           char *str = ldns_rdf2str(rdf);
547 0 0         if (str) {
548 0           bool r = ldns_dname_str_absolute(str);
549 0           LDNS_FREE(str);
550 0           return r;
551             }
552 0           return false;
553             }
554              
555             ldns_rdf *
556 80           ldns_dname_label(const ldns_rdf *rdf, uint8_t labelpos)
557             {
558             uint8_t labelcnt;
559             uint16_t src_pos;
560             uint16_t len;
561             ldns_rdf *tmpnew;
562             size_t s;
563             uint8_t *data;
564              
565 80 50         if (ldns_rdf_get_type(rdf) != LDNS_RDF_TYPE_DNAME) {
566 0           return NULL;
567             }
568              
569 80           labelcnt = 0;
570 80           src_pos = 0;
571 80           s = ldns_rdf_size(rdf);
572              
573 80           len = ldns_rdf_data(rdf)[src_pos]; /* label start */
574 80 50         while ((len > 0) && src_pos < s) {
    50          
575 80 50         if (labelcnt == labelpos) {
576             /* found our label */
577 80           data = LDNS_XMALLOC(uint8_t, len + 2);
578 80 50         if (!data) {
579 0           return NULL;
580             }
581 80           memcpy(data, ldns_rdf_data(rdf) + src_pos, len + 1);
582 80           data[len + 2 - 1] = 0;
583              
584 80           tmpnew = ldns_rdf_new( LDNS_RDF_TYPE_DNAME
585 80           , len + 2, data);
586 80 50         if (!tmpnew) {
587 0           LDNS_FREE(data);
588 0           return NULL;
589             }
590 80           return tmpnew;
591             }
592 0           src_pos++;
593 0           src_pos += len;
594 0           len = ldns_rdf_data(rdf)[src_pos];
595 0           labelcnt++;
596             }
597 0           return NULL;
598             }