dname.c

Go to the documentation of this file.
00001 /*
00002  * dname.c
00003  *
00004  * dname specific rdata implementations
00005  * A dname is a rdf structure with type LDNS_RDF_TYPE_DNAME
00006  * It is not a /real/ type! All function must therefor check
00007  * for LDNS_RDF_TYPE_DNAME.
00008  *
00009  * a Net::DNS like library for C
00010  *
00011  * (c) NLnet Labs, 2004-2006
00012  *
00013  * See the file LICENSE for the license
00014  */
00015 
00016 #include <ldns/config.h>
00017 
00018 #include <ldns/ldns.h>
00019 
00020 #ifdef HAVE_NETINET_IN_H
00021 #include <netinet/in.h>
00022 #endif
00023 #ifdef HAVE_SYS_SOCKET_H
00024 #include <sys/socket.h>
00025 #endif
00026 #ifdef HAVE_NETDB_H
00027 #include <netdb.h>
00028 #endif
00029 #ifdef HAVE_ARPA_INET_H
00030 #include <arpa/inet.h>
00031 #endif
00032 
00033 /* Returns whether the last label in the name is a root label (a empty label).
00034  * Note that it is not enough to just test the last character to be 0,
00035  * because it may be part of the last label itself.
00036  */
00037 static bool
00038 ldns_dname_last_label_is_root_label(const ldns_rdf* dname)
00039 {
00040         size_t src_pos;
00041         size_t len = 0;
00042 
00043         for (src_pos = 0; src_pos < ldns_rdf_size(dname); src_pos += len + 1) {
00044                 len = ldns_rdf_data(dname)[src_pos];
00045         }
00046         assert(src_pos == ldns_rdf_size(dname));
00047 
00048         return src_pos > 0 && len == 0;
00049 }
00050 
00051 ldns_rdf *
00052 ldns_dname_cat_clone(const ldns_rdf *rd1, const ldns_rdf *rd2)
00053 {
00054         ldns_rdf *new;
00055         uint16_t new_size;
00056         uint8_t *buf;
00057         uint16_t left_size;
00058 
00059         if (ldns_rdf_get_type(rd1) != LDNS_RDF_TYPE_DNAME ||
00060                         ldns_rdf_get_type(rd2) != LDNS_RDF_TYPE_DNAME) {
00061                 return NULL;
00062         }
00063 
00064         /* remove root label if it is present at the end of the left
00065          * rd, by reducing the size with 1
00066          */
00067         left_size = ldns_rdf_size(rd1);
00068         if (ldns_dname_last_label_is_root_label(rd1)) {
00069                 left_size--;
00070         }
00071 
00072         /* we overwrite the nullbyte of rd1 */
00073         new_size = left_size + ldns_rdf_size(rd2);
00074         buf = LDNS_XMALLOC(uint8_t, new_size);
00075         if (!buf) {
00076                 return NULL;
00077         }
00078 
00079         /* put the two dname's after each other */
00080         memcpy(buf, ldns_rdf_data(rd1), left_size);
00081         memcpy(buf + left_size, ldns_rdf_data(rd2), ldns_rdf_size(rd2));
00082 
00083         new = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_DNAME, new_size, buf);
00084 
00085         LDNS_FREE(buf);
00086         return new;
00087 }
00088 
00089 ldns_status
00090 ldns_dname_cat(ldns_rdf *rd1, ldns_rdf *rd2)
00091 {
00092         uint16_t left_size;
00093         uint16_t size;
00094         uint8_t* newd;
00095 
00096         if (ldns_rdf_get_type(rd1) != LDNS_RDF_TYPE_DNAME ||
00097                         ldns_rdf_get_type(rd2) != LDNS_RDF_TYPE_DNAME) {
00098                 return LDNS_STATUS_ERR;
00099         }
00100 
00101         /* remove root label if it is present at the end of the left
00102          * rd, by reducing the size with 1
00103          */
00104         left_size = ldns_rdf_size(rd1);
00105         if (ldns_dname_last_label_is_root_label(rd1)) {
00106                 left_size--;
00107         }
00108 
00109         size = left_size + ldns_rdf_size(rd2);
00110         newd = LDNS_XREALLOC(ldns_rdf_data(rd1), uint8_t, size);
00111         if(!newd) {
00112                 return LDNS_STATUS_MEM_ERR;
00113         }
00114 
00115         ldns_rdf_set_data(rd1, newd);
00116         memcpy(ldns_rdf_data(rd1) + left_size, ldns_rdf_data(rd2),
00117                         ldns_rdf_size(rd2));
00118         ldns_rdf_set_size(rd1, size);
00119 
00120         return LDNS_STATUS_OK;
00121 }
00122 
00123 ldns_rdf*
00124 ldns_dname_reverse(const ldns_rdf *dname)
00125 {
00126         size_t rd_size;
00127         uint8_t* buf;
00128         ldns_rdf* new;
00129         size_t src_pos;
00130         size_t len ;
00131 
00132         assert(ldns_rdf_get_type(dname) == LDNS_RDF_TYPE_DNAME);
00133         
00134         rd_size = ldns_rdf_size(dname);
00135         buf = LDNS_XMALLOC(uint8_t, rd_size);
00136         if (! buf) {
00137                 return NULL;
00138         }
00139         new = ldns_rdf_new(LDNS_RDF_TYPE_DNAME, rd_size, buf);
00140         if (! new) {
00141                 LDNS_FREE(buf);
00142                 return NULL;
00143         }
00144         
00145         /* If dname ends in a root label, the reverse should too.
00146          */
00147         if (ldns_dname_last_label_is_root_label(dname)) {
00148                 buf[rd_size - 1] = 0;
00149                 rd_size -= 1;
00150         }
00151         for (src_pos = 0; src_pos < rd_size; src_pos += len + 1) {
00152                 len = ldns_rdf_data(dname)[src_pos];
00153                 memcpy(&buf[rd_size - src_pos - len - 1],
00154                                 &ldns_rdf_data(dname)[src_pos], len + 1);
00155         }
00156         return new;
00157 }
00158 
00159 ldns_rdf *
00160 ldns_dname_clone_from(const ldns_rdf *d, uint16_t n)
00161 {
00162         uint8_t *data;
00163         uint8_t label_size;
00164         size_t data_size;
00165 
00166         if (!d ||
00167             ldns_rdf_get_type(d) != LDNS_RDF_TYPE_DNAME ||
00168             ldns_dname_label_count(d) < n) {
00169                 return NULL;
00170         }
00171 
00172         data = ldns_rdf_data(d);
00173         data_size = ldns_rdf_size(d);
00174         while (n > 0) {
00175                 label_size = data[0] + 1;
00176                 data += label_size;
00177                 if (data_size < label_size) {
00178                         /* this label is very broken */
00179                         return NULL;
00180                 }
00181                 data_size -= label_size;
00182                 n--;
00183         }
00184 
00185         return ldns_dname_new_frm_data(data_size, data);
00186 }
00187 
00188 ldns_rdf *
00189 ldns_dname_left_chop(const ldns_rdf *d)
00190 {
00191         uint8_t label_pos;
00192         ldns_rdf *chop;
00193 
00194         if (!d) {
00195                 return NULL;
00196         }
00197 
00198         if (ldns_rdf_get_type(d) != LDNS_RDF_TYPE_DNAME) {
00199                 return NULL;
00200         }
00201         if (ldns_dname_label_count(d) == 0) {
00202                 /* root label */
00203                 return NULL;
00204         }
00205         /* 05blaat02nl00 */
00206         label_pos = ldns_rdf_data(d)[0];
00207 
00208         chop = ldns_dname_new_frm_data(ldns_rdf_size(d) - label_pos - 1,
00209                         ldns_rdf_data(d) + label_pos + 1);
00210         return chop;
00211 }
00212 
00213 uint8_t
00214 ldns_dname_label_count(const ldns_rdf *r)
00215 {
00216         uint16_t src_pos;
00217         uint16_t len;
00218         uint8_t i;
00219         size_t r_size;
00220 
00221         if (!r) {
00222                 return 0;
00223         }
00224 
00225         i = 0;
00226         src_pos = 0;
00227         r_size = ldns_rdf_size(r);
00228 
00229         if (ldns_rdf_get_type(r) != LDNS_RDF_TYPE_DNAME) {
00230                 return 0;
00231         } else {
00232                 len = ldns_rdf_data(r)[src_pos]; /* start of the label */
00233 
00234                 /* single root label */
00235                 if (1 == r_size) {
00236                         return 0;
00237                 } else {
00238                         while ((len > 0) && src_pos < r_size) {
00239                                 src_pos++;
00240                                 src_pos += len;
00241                                 len = ldns_rdf_data(r)[src_pos];
00242                                 i++;
00243                         }
00244                 }
00245         }
00246         return i;
00247 }
00248 
00249 ldns_rdf *
00250 ldns_dname_new(uint16_t s, void *d)
00251 {
00252         ldns_rdf *rd;
00253 
00254         rd = LDNS_MALLOC(ldns_rdf);
00255         if (!rd) {
00256                 return NULL;
00257         }
00258         ldns_rdf_set_size(rd, s);
00259         ldns_rdf_set_type(rd, LDNS_RDF_TYPE_DNAME);
00260         ldns_rdf_set_data(rd, d);
00261         return rd;
00262 }
00263 
00264 ldns_rdf *
00265 ldns_dname_new_frm_str(const char *str)
00266 {
00267         return ldns_rdf_new_frm_str(LDNS_RDF_TYPE_DNAME, str);
00268 }
00269 
00270 ldns_rdf *
00271 ldns_dname_new_frm_data(uint16_t size, const void *data)
00272 {
00273         return ldns_rdf_new_frm_data(LDNS_RDF_TYPE_DNAME, size, data);
00274 }
00275 
00276 void
00277 ldns_dname2canonical(const ldns_rdf *rd)
00278 {
00279         uint8_t *rdd;
00280         uint16_t i;
00281 
00282         if (ldns_rdf_get_type(rd) != LDNS_RDF_TYPE_DNAME) {
00283                 return;
00284         }
00285 
00286         rdd = (uint8_t*)ldns_rdf_data(rd);
00287         for (i = 0; i < ldns_rdf_size(rd); i++, rdd++) {
00288                 *rdd = (uint8_t)LDNS_DNAME_NORMALIZE((int)*rdd);
00289         }
00290 }
00291 
00292 bool
00293 ldns_dname_is_subdomain(const ldns_rdf *sub, const ldns_rdf *parent)
00294 {
00295         uint8_t sub_lab;
00296         uint8_t par_lab;
00297         int8_t i, j;
00298         ldns_rdf *tmp_sub = NULL;
00299         ldns_rdf *tmp_par = NULL;
00300     ldns_rdf *sub_clone;
00301     ldns_rdf *parent_clone;
00302     bool result = true;
00303 
00304         if (ldns_rdf_get_type(sub) != LDNS_RDF_TYPE_DNAME ||
00305                         ldns_rdf_get_type(parent) != LDNS_RDF_TYPE_DNAME ||
00306                         ldns_rdf_compare(sub, parent) == 0) {
00307                 return false;
00308         }
00309 
00310     /* would be nicer if we do not have to clone... */
00311     sub_clone = ldns_dname_clone_from(sub, 0);
00312     parent_clone = ldns_dname_clone_from(parent, 0);
00313     ldns_dname2canonical(sub_clone);
00314     ldns_dname2canonical(parent_clone);
00315 
00316         sub_lab = ldns_dname_label_count(sub_clone);
00317         par_lab = ldns_dname_label_count(parent_clone);
00318 
00319         /* if sub sits above parent, it cannot be a child/sub domain */
00320         if (sub_lab < par_lab) {
00321                 result = false;
00322         } else {
00323                 /* check all labels the from the parent labels, from right to left.
00324                  * When they /all/ match we have found a subdomain
00325                  */
00326                 j = sub_lab - 1; /* we count from zero, thank you */
00327                 for (i = par_lab -1; i >= 0; i--) {
00328                         tmp_sub = ldns_dname_label(sub_clone, j);
00329                         tmp_par = ldns_dname_label(parent_clone, i);
00330                         if (!tmp_sub || !tmp_par) {
00331                                 /* deep free does null check */
00332                                 ldns_rdf_deep_free(tmp_sub);
00333                                 ldns_rdf_deep_free(tmp_par);
00334                                 result = false;
00335                                 break;
00336                         }
00337 
00338                         if (ldns_rdf_compare(tmp_sub, tmp_par) != 0) {
00339                                 /* they are not equal */
00340                                 ldns_rdf_deep_free(tmp_sub);
00341                                 ldns_rdf_deep_free(tmp_par);
00342                                 result = false;
00343                                 break;
00344                         }
00345                         ldns_rdf_deep_free(tmp_sub);
00346                         ldns_rdf_deep_free(tmp_par);
00347                         j--;
00348                 }
00349         }
00350         ldns_rdf_deep_free(sub_clone);
00351         ldns_rdf_deep_free(parent_clone);
00352         return result;
00353 }
00354 
00355 int
00356 ldns_dname_compare(const ldns_rdf *dname1, const ldns_rdf *dname2)
00357 {
00358         size_t lc1, lc2, lc1f, lc2f;
00359         size_t i;
00360         int result = 0;
00361         uint8_t *lp1, *lp2;
00362 
00363         /* see RFC4034 for this algorithm */
00364         /* this algorithm assumes the names are normalized to case */
00365 
00366         /* only when both are not NULL we can say anything about them */
00367         if (!dname1 && !dname2) {
00368                 return 0;
00369         }
00370         if (!dname1 || !dname2) {
00371                 return -1;
00372         }
00373         /* asserts must happen later as we are looking in the
00374          * dname, which could be NULL. But this case is handled
00375          * above
00376          */
00377         assert(ldns_rdf_get_type(dname1) == LDNS_RDF_TYPE_DNAME);
00378         assert(ldns_rdf_get_type(dname2) == LDNS_RDF_TYPE_DNAME);
00379 
00380         lc1 = ldns_dname_label_count(dname1);
00381         lc2 = ldns_dname_label_count(dname2);
00382 
00383         if (lc1 == 0 && lc2 == 0) {
00384                 return 0;
00385         }
00386         if (lc1 == 0) {
00387                 return -1;
00388         }
00389         if (lc2 == 0) {
00390                 return 1;
00391         }
00392         lc1--;
00393         lc2--;
00394         /* we start at the last label */
00395         while (true) {
00396                 /* find the label first */
00397                 lc1f = lc1;
00398                 lp1 = ldns_rdf_data(dname1);
00399                 while (lc1f > 0) {
00400                         lp1 += *lp1 + 1;
00401                         lc1f--;
00402                 }
00403 
00404                 /* and find the other one */
00405                 lc2f = lc2;
00406                 lp2 = ldns_rdf_data(dname2);
00407                 while (lc2f > 0) {
00408                         lp2 += *lp2 + 1;
00409                         lc2f--;
00410                 }
00411 
00412                 /* now check the label character for character. */
00413                 for (i = 1; i < (size_t)(*lp1 + 1); i++) {
00414                         if (i > *lp2) {
00415                                 /* apparently label 1 is larger */
00416                                 result = 1;
00417                                 goto done;
00418                         }
00419                         if (LDNS_DNAME_NORMALIZE((int) *(lp1 + i)) <
00420                             LDNS_DNAME_NORMALIZE((int) *(lp2 + i))) {
00421                             result = -1;
00422                             goto done;
00423                         } else if (LDNS_DNAME_NORMALIZE((int) *(lp1 + i)) >
00424                             LDNS_DNAME_NORMALIZE((int) *(lp2 + i))) {
00425                             result = 1;
00426                             goto done;
00427                         }
00428                 }
00429                 if (*lp1 < *lp2) {
00430                         /* apparently label 2 is larger */
00431                         result = -1;
00432                         goto done;
00433                 }
00434                 if (lc1 == 0 && lc2 > 0) {
00435                         result = -1;
00436                         goto done;
00437                 } else if (lc1 > 0 && lc2 == 0) {
00438                         result = 1;
00439                         goto done;
00440                 } else if (lc1 == 0 && lc2 == 0) {
00441                         result = 0;
00442                         goto done;
00443                 }
00444                 lc1--;
00445                 lc2--;
00446         }
00447 
00448         done:
00449         return result;
00450 }
00451 
00452 int
00453 ldns_dname_is_wildcard(const ldns_rdf* dname)
00454 {
00455         return ( ldns_dname_label_count(dname) > 0 &&
00456                  ldns_rdf_data(dname)[0] == 1 &&
00457                  ldns_rdf_data(dname)[1] == '*');
00458 }
00459 
00460 int
00461 ldns_dname_match_wildcard(const ldns_rdf *dname, const ldns_rdf *wildcard)
00462 {
00463         ldns_rdf *wc_chopped;
00464         int result;
00465         /* check whether it really is a wildcard */
00466         if (ldns_dname_is_wildcard(wildcard)) {
00467                 /* ok, so the dname needs to be a subdomain of the wildcard
00468                  * without the *
00469                  */
00470                 wc_chopped = ldns_dname_left_chop(wildcard);
00471                 result = (int) ldns_dname_is_subdomain(dname, wc_chopped);
00472                 ldns_rdf_deep_free(wc_chopped);
00473         } else {
00474                 result = (ldns_dname_compare(dname, wildcard) == 0);
00475         }
00476         return result;
00477 }
00478 
00479 /* nsec test: does prev <= middle < next
00480  * -1 = yes
00481  * 0 = error/can't tell
00482  * 1 = no
00483  */
00484 int
00485 ldns_dname_interval(const ldns_rdf *prev, const ldns_rdf *middle,
00486                 const ldns_rdf *next)
00487 {
00488         int prev_check, next_check;
00489 
00490         assert(ldns_rdf_get_type(prev) == LDNS_RDF_TYPE_DNAME);
00491         assert(ldns_rdf_get_type(middle) == LDNS_RDF_TYPE_DNAME);
00492         assert(ldns_rdf_get_type(next) == LDNS_RDF_TYPE_DNAME);
00493 
00494         prev_check = ldns_dname_compare(prev, middle);
00495         next_check = ldns_dname_compare(middle, next);
00496         /* <= next. This cannot be the case for nsec, because then we would
00497          * have gotten the nsec of next...
00498          */
00499         if (next_check == 0) {
00500                 return 0;
00501         }
00502 
00503                         /* <= */
00504         if ((prev_check == -1 || prev_check == 0) &&
00505                         /* < */
00506                         next_check == -1) {
00507                 return -1;
00508         } else {
00509                 return 1;
00510         }
00511 }
00512 
00513 
00514 bool
00515 ldns_dname_str_absolute(const char *dname_str)
00516 {
00517         const char* s;
00518         if(dname_str && strcmp(dname_str, ".") == 0)
00519                 return 1;
00520         if(!dname_str || strlen(dname_str) < 2)
00521                 return 0;
00522         if(dname_str[strlen(dname_str) - 1] != '.')
00523                 return 0;
00524         if(dname_str[strlen(dname_str) - 2] != '\\')
00525                 return 1; /* ends in . and no \ before it */
00526         /* so we have the case of ends in . and there is \ before it */
00527         for(s=dname_str; *s; s++) {
00528                 if(*s == '\\') {
00529                         if(s[1] && s[2] && s[3] /* check length */
00530                                 && isdigit(s[1]) && isdigit(s[2]) && 
00531                                 isdigit(s[3]))
00532                                 s += 3;
00533                         else if(!s[1] || isdigit(s[1])) /* escape of nul,0-9 */
00534                                 return 0; /* parse error */
00535                         else s++; /* another character escaped */
00536                 }
00537                 else if(!*(s+1) && *s == '.')
00538                         return 1; /* trailing dot, unescaped */
00539         }
00540         return 0;
00541 }
00542 
00543 bool
00544 ldns_dname_absolute(const ldns_rdf *rdf)
00545 {
00546         char *str = ldns_rdf2str(rdf);
00547         if (str) {
00548                 bool r = ldns_dname_str_absolute(str);
00549                 LDNS_FREE(str);
00550                 return r;
00551         }
00552         return false;
00553 }
00554 
00555 ldns_rdf *
00556 ldns_dname_label(const ldns_rdf *rdf, uint8_t labelpos)
00557 {
00558         uint8_t labelcnt;
00559         uint16_t src_pos;
00560         uint16_t len;
00561         ldns_rdf *tmpnew;
00562         size_t s;
00563         uint8_t *data;
00564 
00565         if (ldns_rdf_get_type(rdf) != LDNS_RDF_TYPE_DNAME) {
00566                 return NULL;
00567         }
00568 
00569         labelcnt = 0;
00570         src_pos = 0;
00571         s = ldns_rdf_size(rdf);
00572 
00573         len = ldns_rdf_data(rdf)[src_pos]; /* label start */
00574         while ((len > 0) && src_pos < s) {
00575                 if (labelcnt == labelpos) {
00576                         /* found our label */
00577                         data = LDNS_XMALLOC(uint8_t, len + 2);
00578                         if (!data) {
00579                                 return NULL;
00580                         }
00581                         memcpy(data, ldns_rdf_data(rdf) + src_pos, len + 1);
00582                         data[len + 2 - 1] = 0;
00583 
00584                         tmpnew = ldns_rdf_new( LDNS_RDF_TYPE_DNAME
00585                                              , len + 2, data);
00586                         if (!tmpnew) {
00587                                 LDNS_FREE(data);
00588                                 return NULL;
00589                         }
00590                         return tmpnew;
00591                 }
00592                 src_pos++;
00593                 src_pos += len;
00594                 len = ldns_rdf_data(rdf)[src_pos];
00595                 labelcnt++;
00596         }
00597         return NULL;
00598 }

Generated on 8 Apr 2014 for ldns by  doxygen 1.4.7