Initial vendor import of ldns-1.6.4 into contrib.
[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 ldns_rdf *
34 ldns_dname_cat_clone(const ldns_rdf *rd1, const ldns_rdf *rd2)
35 {
36         ldns_rdf *new;
37         uint16_t new_size;
38         uint8_t *buf;
39         uint16_t left_size;
40
41         if (ldns_rdf_get_type(rd1) != LDNS_RDF_TYPE_DNAME ||
42                         ldns_rdf_get_type(rd2) != LDNS_RDF_TYPE_DNAME) {
43                 return NULL;
44         }
45
46         /* remove root label if it is present at the end of the left
47          * rd, by reducing the size with 1
48          */
49         left_size = ldns_rdf_size(rd1);
50         if (left_size > 0 &&ldns_rdf_data(rd1)[left_size - 1] == 0) {
51                 left_size--;
52         }
53
54         /* we overwrite the nullbyte of rd1 */
55         new_size = left_size + ldns_rdf_size(rd2);
56         buf = LDNS_XMALLOC(uint8_t, new_size);
57         if (!buf) {
58                 return NULL;
59         }
60
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));
64
65         new = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_DNAME, new_size, buf);
66
67         LDNS_FREE(buf);
68         return new;
69 }
70
71 ldns_status
72 ldns_dname_cat(ldns_rdf *rd1, ldns_rdf *rd2)
73 {
74         uint16_t left_size;
75         uint16_t size;
76
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;
80         }
81
82         /* remove root label if it is present at the end of the left
83          * rd, by reducing the size with 1
84          */
85         left_size = ldns_rdf_size(rd1);
86         if (left_size > 0 &&ldns_rdf_data(rd1)[left_size - 1] == 0) {
87                 left_size--;
88         }
89
90         size = left_size + ldns_rdf_size(rd2);
91
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),
94                         ldns_rdf_size(rd2));
95         ldns_rdf_set_size(rd1, size);
96
97         return LDNS_STATUS_OK;
98 }
99
100 ldns_rdf *
101 ldns_dname_reverse(const ldns_rdf *d)
102 {
103         ldns_rdf *new;
104         ldns_rdf *tmp;
105         ldns_rdf *d_tmp;
106         ldns_status status;
107
108         d_tmp = ldns_rdf_clone(d);
109
110         new = ldns_dname_new_frm_str(".");
111
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);
116                 new = tmp;
117                 tmp = ldns_dname_left_chop(d_tmp);
118                 ldns_rdf_deep_free(d_tmp);
119                 d_tmp = tmp;
120         }
121         ldns_rdf_deep_free(d_tmp);
122
123         return new;
124 }
125
126 ldns_rdf *
127 ldns_dname_clone_from(const ldns_rdf *d, uint16_t n)
128 {
129         uint8_t *data;
130         uint8_t label_size;
131         size_t data_size;
132
133         if (!d ||
134             ldns_rdf_get_type(d) != LDNS_RDF_TYPE_DNAME ||
135             ldns_dname_label_count(d) < n) {
136                 return NULL;
137         }
138
139         data = ldns_rdf_data(d);
140         data_size = ldns_rdf_size(d);
141         while (n > 0) {
142                 label_size = data[0] + 1;
143                 data += label_size;
144                 if (data_size < label_size) {
145                         /* this label is very broken */
146                         return NULL;
147                 }
148                 data_size -= label_size;
149                 n--;
150         }
151
152         return ldns_dname_new_frm_data(data_size, data);
153 }
154
155 ldns_rdf *
156 ldns_dname_left_chop(const ldns_rdf *d)
157 {
158         uint8_t label_pos;
159         ldns_rdf *chop;
160
161         if (!d) {
162                 return NULL;
163         }
164
165         if (ldns_rdf_get_type(d) != LDNS_RDF_TYPE_DNAME) {
166                 return NULL;
167         }
168         if (ldns_dname_label_count(d) == 0) {
169                 /* root label */
170                 return NULL;
171         }
172         /* 05blaat02nl00 */
173         label_pos = ldns_rdf_data(d)[0];
174
175         chop = ldns_dname_new_frm_data(ldns_rdf_size(d) - label_pos - 1,
176                         ldns_rdf_data(d) + label_pos + 1);
177         return chop;
178 }
179
180 uint8_t
181 ldns_dname_label_count(const ldns_rdf *r)
182 {
183         uint16_t src_pos;
184         uint16_t len;
185         uint8_t i;
186         size_t r_size;
187
188         if (!r) {
189                 return 0;
190         }
191
192         i = 0;
193         src_pos = 0;
194         r_size = ldns_rdf_size(r);
195
196         if (ldns_rdf_get_type(r) != LDNS_RDF_TYPE_DNAME) {
197                 return 0;
198         } else {
199                 len = ldns_rdf_data(r)[src_pos]; /* start of the label */
200
201                 /* single root label */
202                 if (1 == r_size) {
203                         return 0;
204                 } else {
205                         while ((len > 0) && src_pos < r_size) {
206                                 src_pos++;
207                                 src_pos += len;
208                                 len = ldns_rdf_data(r)[src_pos];
209                                 i++;
210                         }
211                 }
212         }
213         return i;
214 }
215
216 ldns_rdf *
217 ldns_dname_new(uint16_t s, void *d)
218 {
219         ldns_rdf *rd;
220
221         rd = LDNS_MALLOC(ldns_rdf);
222         if (!rd) {
223                 return NULL;
224         }
225         ldns_rdf_set_size(rd, s);
226         ldns_rdf_set_type(rd, LDNS_RDF_TYPE_DNAME);
227         ldns_rdf_set_data(rd, d);
228         return rd;
229 }
230
231 ldns_rdf *
232 ldns_dname_new_frm_str(const char *str)
233 {
234         return ldns_rdf_new_frm_str(LDNS_RDF_TYPE_DNAME, str);
235 }
236
237 ldns_rdf *
238 ldns_dname_new_frm_data(uint16_t size, const void *data)
239 {
240         return ldns_rdf_new_frm_data(LDNS_RDF_TYPE_DNAME, size, data);
241 }
242
243 void
244 ldns_dname2canonical(const ldns_rdf *rd)
245 {
246         uint8_t *rdd;
247         uint16_t i;
248
249         if (ldns_rdf_get_type(rd) != LDNS_RDF_TYPE_DNAME) {
250                 return;
251         }
252
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);
256         }
257 }
258
259 bool
260 ldns_dname_is_subdomain(const ldns_rdf *sub, const ldns_rdf *parent)
261 {
262         uint8_t sub_lab;
263         uint8_t par_lab;
264         int8_t i, j;
265         ldns_rdf *tmp_sub = NULL;
266         ldns_rdf *tmp_par = NULL;
267     ldns_rdf *sub_clone;
268     ldns_rdf *parent_clone;
269     bool result = true;
270
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) {
274                 return false;
275         }
276
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);
282
283         sub_lab = ldns_dname_label_count(sub_clone);
284         par_lab = ldns_dname_label_count(parent_clone);
285
286         /* if sub sits above parent, it cannot be a child/sub domain */
287         if (sub_lab < par_lab) {
288                 result = false;
289         } else {
290                 /* check all labels the from the parent labels, from right to left.
291                  * When they /all/ match we have found a subdomain
292                  */
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);
301                                 result = false;
302                                 break;
303                         }
304
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);
309                                 result = false;
310                                 break;
311                         }
312                         ldns_rdf_deep_free(tmp_sub);
313                         ldns_rdf_deep_free(tmp_par);
314                         j--;
315                 }
316         }
317         ldns_rdf_deep_free(sub_clone);
318         ldns_rdf_deep_free(parent_clone);
319         return result;
320 }
321
322 int
323 ldns_dname_compare(const ldns_rdf *dname1, const ldns_rdf *dname2)
324 {
325         size_t lc1, lc2, lc1f, lc2f;
326         size_t i;
327         int result = 0;
328         uint8_t *lp1, *lp2;
329
330         /* see RFC4034 for this algorithm */
331         /* this algorithm assumes the names are normalized to case */
332
333         /* only when both are not NULL we can say anything about them */
334         if (!dname1 && !dname2) {
335                 return 0;
336         }
337         if (!dname1 || !dname2) {
338                 return -1;
339         }
340         /* asserts must happen later as we are looking in the
341          * dname, which could be NULL. But this case is handled
342          * above
343          */
344         assert(ldns_rdf_get_type(dname1) == LDNS_RDF_TYPE_DNAME);
345         assert(ldns_rdf_get_type(dname2) == LDNS_RDF_TYPE_DNAME);
346
347         lc1 = ldns_dname_label_count(dname1);
348         lc2 = ldns_dname_label_count(dname2);
349
350         if (lc1 == 0 && lc2 == 0) {
351                 return 0;
352         }
353         if (lc1 == 0) {
354                 return -1;
355         }
356         if (lc2 == 0) {
357                 return 1;
358         }
359         lc1--;
360         lc2--;
361         /* we start at the last label */
362         while (true) {
363                 /* find the label first */
364                 lc1f = lc1;
365                 lp1 = ldns_rdf_data(dname1);
366                 while (lc1f > 0) {
367                         lp1 += *lp1 + 1;
368                         lc1f--;
369                 }
370
371                 /* and find the other one */
372                 lc2f = lc2;
373                 lp2 = ldns_rdf_data(dname2);
374                 while (lc2f > 0) {
375                         lp2 += *lp2 + 1;
376                         lc2f--;
377                 }
378
379                 /* now check the label character for character. */
380                 for (i = 1; i < (size_t)(*lp1 + 1); i++) {
381                         if (i > *lp2) {
382                                 /* apparently label 1 is larger */
383                                 result = 1;
384                                 goto done;
385                         }
386                         if (LDNS_DNAME_NORMALIZE((int) *(lp1 + i)) <
387                             LDNS_DNAME_NORMALIZE((int) *(lp2 + i))) {
388                             result = -1;
389                             goto done;
390                         } else if (LDNS_DNAME_NORMALIZE((int) *(lp1 + i)) >
391                             LDNS_DNAME_NORMALIZE((int) *(lp2 + i))) {
392                             result = 1;
393                             goto done;
394                         }
395                 }
396                 if (*lp1 < *lp2) {
397                         /* apparently label 2 is larger */
398                         result = -1;
399                         goto done;
400                 }
401                 if (lc1 == 0 && lc2 > 0) {
402                         result = -1;
403                         goto done;
404                 } else if (lc1 > 0 && lc2 == 0) {
405                         result = 1;
406                         goto done;
407                 } else if (lc1 == 0 && lc2 == 0) {
408                         result = 0;
409                         goto done;
410                 }
411                 lc1--;
412                 lc2--;
413         }
414
415         done:
416         return result;
417 }
418
419 int
420 ldns_dname_match_wildcard(const ldns_rdf *dname, const ldns_rdf *wildcard)
421 {
422         ldns_rdf *wc_chopped;
423         int result;
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
429                  * without the *
430                  */
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);
434         } else {
435                 result = (ldns_dname_compare(dname, wildcard) == 0);
436         }
437         return result;
438 }
439
440 /* nsec test: does prev <= middle < next
441  * -1 = yes
442  * 0 = error/can't tell
443  * 1 = no
444  */
445 int
446 ldns_dname_interval(const ldns_rdf *prev, const ldns_rdf *middle,
447                 const ldns_rdf *next)
448 {
449         int prev_check, next_check;
450
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);
454
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...
459          */
460         if (next_check == 0) {
461                 return 0;
462         }
463
464                         /* <= */
465         if ((prev_check == -1 || prev_check == 0) &&
466                         /* < */
467                         next_check == -1) {
468                 return -1;
469         } else {
470                 return 1;
471         }
472 }
473
474
475 bool
476 ldns_dname_str_absolute(const char *dname_str)
477 {
478         if(dname_str && strcmp(dname_str, ".") == 0)
479                 return 1;
480         return (dname_str &&
481                 strlen(dname_str) > 1 &&
482                 dname_str[strlen(dname_str) - 1] == '.' &&
483                 dname_str[strlen(dname_str) - 2] != '\\');
484 }
485
486 ldns_rdf *
487 ldns_dname_label(const ldns_rdf *rdf, uint8_t labelpos)
488 {
489         uint8_t labelcnt;
490         uint16_t src_pos;
491         uint16_t len;
492         ldns_rdf *tmpnew;
493         size_t s;
494
495         if (ldns_rdf_get_type(rdf) != LDNS_RDF_TYPE_DNAME) {
496                 return NULL;
497         }
498
499         labelcnt = 0;
500         src_pos = 0;
501         s = ldns_rdf_size(rdf);
502
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);
508                         if (!tmpnew) {
509                                 return NULL;
510                         }
511                         tmpnew->_type = LDNS_RDF_TYPE_DNAME;
512                         tmpnew->_data = LDNS_XMALLOC(uint8_t, len + 2);
513                         if (!tmpnew->_data) {
514                                 LDNS_FREE(tmpnew);
515                                 return NULL;
516                         }
517                         memset(tmpnew->_data, 0, len + 2);
518                         memcpy(tmpnew->_data, ldns_rdf_data(rdf) + src_pos, len + 1);
519                         tmpnew->_size = len + 2;
520                         return tmpnew;
521                 }
522                 src_pos++;
523                 src_pos += len;
524                 len = ldns_rdf_data(rdf)[src_pos];
525                 labelcnt++;
526         }
527         return NULL;
528 }