Merge branch 'vendor/OPENSSL'
[dragonfly.git] / contrib / ldns / dname.c
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 <ldns/config.h>
17
18 #include <ldns/ldns.h>
19
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
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 ldns_dname_last_label_is_root_label(const ldns_rdf* dname)
39 {
40         size_t src_pos;
41         size_t len = 0;
42
43         for (src_pos = 0; src_pos < ldns_rdf_size(dname); src_pos += len + 1) {
44                 len = ldns_rdf_data(dname)[src_pos];
45         }
46         assert(src_pos == ldns_rdf_size(dname));
47
48         return src_pos > 0 && len == 0;
49 }
50
51 ldns_rdf *
52 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         if (ldns_rdf_get_type(rd1) != LDNS_RDF_TYPE_DNAME ||
60                         ldns_rdf_get_type(rd2) != LDNS_RDF_TYPE_DNAME) {
61                 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         left_size = ldns_rdf_size(rd1);
68         if (ldns_dname_last_label_is_root_label(rd1)) {
69                 left_size--;
70         }
71
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;
77         }
78
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));
82
83         new = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_DNAME, new_size, buf);
84
85         LDNS_FREE(buf);
86         return new;
87 }
88
89 ldns_status
90 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         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;
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         left_size = ldns_rdf_size(rd1);
105         if (ldns_dname_last_label_is_root_label(rd1)) {
106                 left_size--;
107         }
108
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;
113         }
114
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);
119
120         return LDNS_STATUS_OK;
121 }
122
123 ldns_rdf*
124 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         rd_size = ldns_rdf_size(dname);
135         buf = LDNS_XMALLOC(uint8_t, rd_size);
136         if (! buf) {
137                 return NULL;
138         }
139         new = ldns_rdf_new(LDNS_RDF_TYPE_DNAME, rd_size, buf);
140         if (! new) {
141                 LDNS_FREE(buf);
142                 return NULL;
143         }
144         
145         /* If dname ends in a root label, the reverse should too.
146          */
147         if (ldns_dname_last_label_is_root_label(dname)) {
148                 buf[rd_size - 1] = 0;
149                 rd_size -= 1;
150         }
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);
155         }
156         return new;
157 }
158
159 ldns_rdf *
160 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         if (!d ||
167             ldns_rdf_get_type(d) != LDNS_RDF_TYPE_DNAME ||
168             ldns_dname_label_count(d) < n) {
169                 return NULL;
170         }
171
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;
180                 }
181                 data_size -= label_size;
182                 n--;
183         }
184
185         return ldns_dname_new_frm_data(data_size, data);
186 }
187
188 ldns_rdf *
189 ldns_dname_left_chop(const ldns_rdf *d)
190 {
191         uint8_t label_pos;
192         ldns_rdf *chop;
193
194         if (!d) {
195                 return NULL;
196         }
197
198         if (ldns_rdf_get_type(d) != LDNS_RDF_TYPE_DNAME) {
199                 return NULL;
200         }
201         if (ldns_dname_label_count(d) == 0) {
202                 /* root label */
203                 return NULL;
204         }
205         /* 05blaat02nl00 */
206         label_pos = ldns_rdf_data(d)[0];
207
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;
211 }
212
213 uint8_t
214 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         if (!r) {
222                 return 0;
223         }
224
225         i = 0;
226         src_pos = 0;
227         r_size = ldns_rdf_size(r);
228
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 */
233
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++;
243                         }
244                 }
245         }
246         return i;
247 }
248
249 ldns_rdf *
250 ldns_dname_new(uint16_t s, void *d)
251 {
252         ldns_rdf *rd;
253
254         rd = LDNS_MALLOC(ldns_rdf);
255         if (!rd) {
256                 return NULL;
257         }
258         ldns_rdf_set_size(rd, s);
259         ldns_rdf_set_type(rd, LDNS_RDF_TYPE_DNAME);
260         ldns_rdf_set_data(rd, d);
261         return rd;
262 }
263
264 ldns_rdf *
265 ldns_dname_new_frm_str(const char *str)
266 {
267         return ldns_rdf_new_frm_str(LDNS_RDF_TYPE_DNAME, str);
268 }
269
270 ldns_rdf *
271 ldns_dname_new_frm_data(uint16_t size, const void *data)
272 {
273         return ldns_rdf_new_frm_data(LDNS_RDF_TYPE_DNAME, size, data);
274 }
275
276 void
277 ldns_dname2canonical(const ldns_rdf *rd)
278 {
279         uint8_t *rdd;
280         uint16_t i;
281
282         if (ldns_rdf_get_type(rd) != LDNS_RDF_TYPE_DNAME) {
283                 return;
284         }
285
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);
289         }
290 }
291
292 bool
293 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         ldns_rdf *tmp_sub = NULL;
299         ldns_rdf *tmp_par = NULL;
300     ldns_rdf *sub_clone;
301     ldns_rdf *parent_clone;
302     bool result = true;
303
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) {
307                 return false;
308         }
309
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);
315
316         sub_lab = ldns_dname_label_count(sub_clone);
317         par_lab = ldns_dname_label_count(parent_clone);
318
319         /* if sub sits above parent, it cannot be a child/sub domain */
320         if (sub_lab < par_lab) {
321                 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                 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);
334                                 result = false;
335                                 break;
336                         }
337
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);
342                                 result = false;
343                                 break;
344                         }
345                         ldns_rdf_deep_free(tmp_sub);
346                         ldns_rdf_deep_free(tmp_par);
347                         j--;
348                 }
349         }
350         ldns_rdf_deep_free(sub_clone);
351         ldns_rdf_deep_free(parent_clone);
352         return result;
353 }
354
355 int
356 ldns_dname_compare(const ldns_rdf *dname1, const ldns_rdf *dname2)
357 {
358         size_t lc1, lc2, lc1f, lc2f;
359         size_t i;
360         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         if (!dname1 && !dname2) {
368                 return 0;
369         }
370         if (!dname1 || !dname2) {
371                 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         lc1 = ldns_dname_label_count(dname1);
381         lc2 = ldns_dname_label_count(dname2);
382
383         if (lc1 == 0 && lc2 == 0) {
384                 return 0;
385         }
386         if (lc1 == 0) {
387                 return -1;
388         }
389         if (lc2 == 0) {
390                 return 1;
391         }
392         lc1--;
393         lc2--;
394         /* we start at the last label */
395         while (true) {
396                 /* find the label first */
397                 lc1f = lc1;
398                 lp1 = ldns_rdf_data(dname1);
399                 while (lc1f > 0) {
400                         lp1 += *lp1 + 1;
401                         lc1f--;
402                 }
403
404                 /* and find the other one */
405                 lc2f = lc2;
406                 lp2 = ldns_rdf_data(dname2);
407                 while (lc2f > 0) {
408                         lp2 += *lp2 + 1;
409                         lc2f--;
410                 }
411
412                 /* now check the label character for character. */
413                 for (i = 1; i < (size_t)(*lp1 + 1); i++) {
414                         if (i > *lp2) {
415                                 /* apparently label 1 is larger */
416                                 result = 1;
417                                 goto done;
418                         }
419                         if (LDNS_DNAME_NORMALIZE((int) *(lp1 + i)) <
420                             LDNS_DNAME_NORMALIZE((int) *(lp2 + i))) {
421                             result = -1;
422                             goto done;
423                         } else if (LDNS_DNAME_NORMALIZE((int) *(lp1 + i)) >
424                             LDNS_DNAME_NORMALIZE((int) *(lp2 + i))) {
425                             result = 1;
426                             goto done;
427                         }
428                 }
429                 if (*lp1 < *lp2) {
430                         /* apparently label 2 is larger */
431                         result = -1;
432                         goto done;
433                 }
434                 if (lc1 == 0 && lc2 > 0) {
435                         result = -1;
436                         goto done;
437                 } else if (lc1 > 0 && lc2 == 0) {
438                         result = 1;
439                         goto done;
440                 } else if (lc1 == 0 && lc2 == 0) {
441                         result = 0;
442                         goto done;
443                 }
444                 lc1--;
445                 lc2--;
446         }
447
448         done:
449         return result;
450 }
451
452 int
453 ldns_dname_is_wildcard(const ldns_rdf* dname)
454 {
455         return ( ldns_dname_label_count(dname) > 0 &&
456                  ldns_rdf_data(dname)[0] == 1 &&
457                  ldns_rdf_data(dname)[1] == '*');
458 }
459
460 int
461 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         if (ldns_dname_is_wildcard(wildcard)) {
467                 /* ok, so the dname needs to be a subdomain of the wildcard
468                  * without the *
469                  */
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);
473         } else {
474                 result = (ldns_dname_compare(dname, wildcard) == 0);
475         }
476         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 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         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...
498          */
499         if (next_check == 0) {
500                 return 0;
501         }
502
503                         /* <= */
504         if ((prev_check == -1 || prev_check == 0) &&
505                         /* < */
506                         next_check == -1) {
507                 return -1;
508         } else {
509                 return 1;
510         }
511 }
512
513
514 bool
515 ldns_dname_str_absolute(const char *dname_str)
516 {
517         const char* s;
518         if(dname_str && strcmp(dname_str, ".") == 0)
519                 return 1;
520         if(!dname_str || strlen(dname_str) < 2)
521                 return 0;
522         if(dname_str[strlen(dname_str) - 1] != '.')
523                 return 0;
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++) {
528                 if(*s == '\\') {
529                         if(s[1] && s[2] && s[3] /* check length */
530                                 && isdigit(s[1]) && isdigit(s[2]) && 
531                                 isdigit(s[3]))
532                                 s += 3;
533                         else if(!s[1] || isdigit(s[1])) /* escape of nul,0-9 */
534                                 return 0; /* parse error */
535                         else s++; /* another character escaped */
536                 }
537                 else if(!*(s+1) && *s == '.')
538                         return 1; /* trailing dot, unescaped */
539         }
540         return 0;
541 }
542
543 bool
544 ldns_dname_absolute(const ldns_rdf *rdf)
545 {
546         char *str = ldns_rdf2str(rdf);
547         if (str) {
548                 bool r = ldns_dname_str_absolute(str);
549                 LDNS_FREE(str);
550                 return r;
551         }
552         return false;
553 }
554
555 ldns_rdf *
556 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         if (ldns_rdf_get_type(rdf) != LDNS_RDF_TYPE_DNAME) {
566                 return NULL;
567         }
568
569         labelcnt = 0;
570         src_pos = 0;
571         s = ldns_rdf_size(rdf);
572
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);
578                         if (!data) {
579                                 return NULL;
580                         }
581                         memcpy(data, ldns_rdf_data(rdf) + src_pos, len + 1);
582                         data[len + 2 - 1] = 0;
583
584                         tmpnew = ldns_rdf_new( LDNS_RDF_TYPE_DNAME
585                                              , len + 2, data);
586                         if (!tmpnew) {
587                                 LDNS_FREE(data);
588                                 return NULL;
589                         }
590                         return tmpnew;
591                 }
592                 src_pos++;
593                 src_pos += len;
594                 len = ldns_rdf_data(rdf)[src_pos];
595                 labelcnt++;
596         }
597         return NULL;
598 }