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

Generated on Thu Apr 5 23:03:54 2012 for ldns by  doxygen 1.4.7