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 #include <netinet/in.h>
00021 #include <sys/socket.h>
00022 #include <netdb.h>
00023 #include <arpa/inet.h>
00024 
00025 ldns_rdf *
00026 ldns_dname_cat_clone(const ldns_rdf *rd1, const ldns_rdf *rd2)
00027 {
00028         ldns_rdf *new;
00029         uint16_t new_size;
00030         uint8_t *buf;
00031         uint16_t left_size;
00032 
00033         if (ldns_rdf_get_type(rd1) != LDNS_RDF_TYPE_DNAME ||
00034                         ldns_rdf_get_type(rd2) != LDNS_RDF_TYPE_DNAME) {
00035                 return NULL;
00036         }
00037 
00038         /* remove root label if it is present at the end of the left
00039          * rd, by reducing the size with 1
00040          */
00041         left_size = ldns_rdf_size(rd1);
00042         if (left_size > 0 &&ldns_rdf_data(rd1)[left_size - 1] == 0) {
00043                 left_size--;
00044         }
00045 
00046         /* we overwrite the nullbyte of rd1 */
00047         new_size = left_size + ldns_rdf_size(rd2);
00048         buf = LDNS_XMALLOC(uint8_t, new_size);
00049         if (!buf) {
00050                 return NULL;
00051         }
00052 
00053         /* put the two dname's after each other */
00054         memcpy(buf, ldns_rdf_data(rd1), left_size);
00055         memcpy(buf + left_size, ldns_rdf_data(rd2), ldns_rdf_size(rd2));
00056         
00057         new = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_DNAME, new_size, buf);
00058 
00059         LDNS_FREE(buf);
00060         return new;
00061 }
00062 
00063 ldns_status
00064 ldns_dname_cat(ldns_rdf *rd1, ldns_rdf *rd2)
00065 {
00066         uint16_t left_size;
00067         uint16_t size;
00068 
00069         if (ldns_rdf_get_type(rd1) != LDNS_RDF_TYPE_DNAME ||
00070                         ldns_rdf_get_type(rd2) != LDNS_RDF_TYPE_DNAME) {
00071                 return LDNS_STATUS_ERR;
00072         }
00073 
00074         /* remove root label if it is present at the end of the left
00075          * rd, by reducing the size with 1
00076          */
00077         left_size = ldns_rdf_size(rd1);
00078         if (left_size > 0 &&ldns_rdf_data(rd1)[left_size - 1] == 0) {
00079                 left_size--;
00080         }
00081 
00082         size = left_size + ldns_rdf_size(rd2);
00083 
00084         ldns_rdf_set_data(rd1, LDNS_XREALLOC(ldns_rdf_data(rd1), uint8_t, size));
00085         memcpy(ldns_rdf_data(rd1) + left_size, ldns_rdf_data(rd2), 
00086                         ldns_rdf_size(rd2));
00087         ldns_rdf_set_size(rd1, size);
00088 
00089         return LDNS_STATUS_OK;
00090 }
00091 
00092 ldns_rdf *
00093 ldns_dname_reverse(const ldns_rdf *d)
00094 {
00095         ldns_rdf *new;
00096         ldns_rdf *tmp;
00097         ldns_rdf *d_tmp;
00098         ldns_status status;
00099 
00100         d_tmp = ldns_rdf_clone(d);
00101 
00102         new = ldns_dname_new_frm_str(".");
00103 
00104         while(ldns_dname_label_count(d_tmp) > 0) {
00105                 tmp = ldns_dname_label(d_tmp, 0);
00106                 status = ldns_dname_cat(tmp, new);
00107                 ldns_rdf_deep_free(new);
00108                 new = tmp;
00109                 tmp = ldns_dname_left_chop(d_tmp);
00110                 ldns_rdf_deep_free(d_tmp);
00111                 d_tmp = tmp;
00112         }
00113         ldns_rdf_deep_free(d_tmp);
00114 
00115         return new;
00116 }
00117 
00118 ldns_rdf *
00119 ldns_dname_left_chop(ldns_rdf *d)
00120 {
00121         uint8_t label_pos;
00122         ldns_rdf *chop;
00123 
00124         if (!d) {
00125                 return NULL;
00126         }
00127                 
00128         if (ldns_rdf_get_type(d) != LDNS_RDF_TYPE_DNAME) {
00129                 return NULL;
00130         }
00131         if (ldns_dname_label_count(d) == 0) {
00132                 /* root label */
00133                 return NULL;
00134         }
00135         /* 05blaat02nl00 */
00136         label_pos = ldns_rdf_data(d)[0];
00137 
00138         chop = ldns_dname_new_frm_data(ldns_rdf_size(d) - label_pos - 1,
00139                         ldns_rdf_data(d) + label_pos + 1);
00140         return chop;
00141 }
00142 
00143 uint8_t         
00144 ldns_dname_label_count(const ldns_rdf *r)
00145 {       
00146         uint16_t src_pos;
00147         uint16_t len;
00148         uint8_t i;
00149         size_t r_size;
00150 
00151         if (!r) {
00152                 return 0;
00153         }
00154 
00155         i = 0; 
00156         src_pos = 0;
00157         r_size = ldns_rdf_size(r);
00158 
00159         if (ldns_rdf_get_type(r) != LDNS_RDF_TYPE_DNAME) {
00160                 return 0;
00161         } else {
00162                 len = ldns_rdf_data(r)[src_pos]; /* start of the label */
00163 
00164                 /* single root label */
00165                 if (1 == r_size) {
00166                         return 0; 
00167                 } else {
00168                         while ((len > 0) && src_pos < r_size) {
00169                                 src_pos++;
00170                                 src_pos += len;
00171                                 len = ldns_rdf_data(r)[src_pos];
00172                                 i++;
00173                         }
00174                 }
00175                 return i;
00176         }
00177 }
00178 
00179 ldns_rdf *
00180 ldns_dname_new(uint16_t s, void *d)
00181 {
00182         ldns_rdf *rd;
00183 
00184         rd = LDNS_MALLOC(ldns_rdf);
00185         if (!rd) {
00186                 return NULL;
00187         }
00188         ldns_rdf_set_size(rd, s);
00189         ldns_rdf_set_type(rd, LDNS_RDF_TYPE_DNAME);
00190         ldns_rdf_set_data(rd, d);
00191         return rd;
00192 }
00193 
00194 ldns_rdf *
00195 ldns_dname_new_frm_str(const char *str)
00196 {
00197         return ldns_rdf_new_frm_str(LDNS_RDF_TYPE_DNAME, str);
00198 }
00199 
00200 ldns_rdf *
00201 ldns_dname_new_frm_data(uint16_t size, const void *data)
00202 {
00203         return ldns_rdf_new_frm_data(LDNS_RDF_TYPE_DNAME, size, data);
00204 }
00205 
00206 void
00207 ldns_dname2canonical(const ldns_rdf *rd)
00208 {
00209         uint8_t *rdd;
00210         uint16_t i;
00211 
00212         if (ldns_rdf_get_type(rd) != LDNS_RDF_TYPE_DNAME) {
00213                 return;
00214         }
00215 
00216         rdd = (uint8_t*)ldns_rdf_data(rd);
00217         for (i = 0; i < ldns_rdf_size(rd); i++, rdd++) {
00218                 *rdd = (uint8_t)LDNS_DNAME_NORMALIZE((int)*rdd);
00219         }
00220 }
00221 
00222 bool
00223 ldns_dname_is_subdomain(const ldns_rdf *sub, const ldns_rdf *parent)
00224 {
00225         uint8_t sub_lab;
00226         uint8_t par_lab;
00227         int8_t i, j;
00228         ldns_rdf *tmp_sub;
00229         ldns_rdf *tmp_par;
00230 
00231         if (ldns_rdf_get_type(sub) != LDNS_RDF_TYPE_DNAME ||
00232                         ldns_rdf_get_type(parent) != LDNS_RDF_TYPE_DNAME ||
00233                         ldns_rdf_compare(sub, parent) == 0) {
00234                 return false;
00235         }
00236 
00237         sub_lab = ldns_dname_label_count(sub);
00238         par_lab = ldns_dname_label_count(parent);
00239 
00240         /* if sub sits above parent, it cannot be a child/sub domain */
00241         if (sub_lab < par_lab) {
00242                 return false;
00243         }
00244         
00245         /* check all labels the from the parent labels, from right to left. 
00246          * When they /all/ match we have found a subdomain
00247          */
00248         j = sub_lab - 1; /* we count from zero, thank you */
00249         for (i = par_lab -1; i >= 0; i--) {
00250                 tmp_sub = ldns_dname_label(sub, j);
00251                 tmp_par = ldns_dname_label(parent, i);
00252 
00253                 if (ldns_rdf_compare(tmp_sub, tmp_par) != 0) {
00254                         /* they are not equal */
00255                         ldns_rdf_deep_free(tmp_sub);
00256                         ldns_rdf_deep_free(tmp_par);
00257                         return false;
00258                 }
00259                 ldns_rdf_deep_free(tmp_sub);
00260                 ldns_rdf_deep_free(tmp_par);
00261                 j--;
00262         }
00263         return true; 
00264 }
00265 
00266 int
00267 ldns_dname_compare(const ldns_rdf *dname1, const ldns_rdf *dname2)
00268 {
00269         size_t lc1, lc2, lc1f, lc2f;
00270         size_t i;
00271         int result = 0;
00272         uint8_t *lp1, *lp2;
00273 
00274         /* see RFC4034 for this algorithm */
00275         /* this algorithm assumes the names are normalized to case */
00276 
00277         /* only when both are not NULL we can say anything about them */
00278         if (!dname1 && !dname2) {
00279                 return 0;
00280         }
00281         if (!dname1 || !dname2) {
00282                 return -1;
00283         }
00284         /* asserts must happen later as we are looking in the
00285          * dname, which could be NULL. But this case is handled
00286          * above
00287          */
00288         assert(ldns_rdf_get_type(dname1) == LDNS_RDF_TYPE_DNAME);
00289         assert(ldns_rdf_get_type(dname2) == LDNS_RDF_TYPE_DNAME);
00290 
00291         
00292         lc1 = ldns_dname_label_count(dname1);
00293         lc2 = ldns_dname_label_count(dname2);
00294         
00295         if (lc1 == 0 && lc2 == 0) {
00296                 return 0;
00297         }
00298         if (lc1 == 0) {
00299                 return -1;
00300         }
00301         if (lc2 == 0) {
00302                 return 1;
00303         }
00304         lc1--;
00305         lc2--;
00306         /* we start at the last label */
00307         while (true) {
00308                 /* find the label first */
00309                 lc1f = lc1;
00310                 lp1 = ldns_rdf_data(dname1);
00311                 while (lc1f > 0) {
00312                         lp1 += *lp1 + 1;
00313                         lc1f--;
00314                 }
00315                 
00316                 /* and find the other one */
00317                 lc2f = lc2;
00318                 lp2 = ldns_rdf_data(dname2);
00319                 while (lc2f > 0) {
00320                         lp2 += *lp2 + 1;
00321                         lc2f--;
00322                 }
00323                 
00324                 /* now check the label character for character. */
00325                 for (i = 1; i < (size_t)(*lp1 + 1); i++) {
00326                         if (i > *lp2) {
00327                                 /* apparently label 1 is larger */
00328                                 result = 1;
00329                                 goto done;
00330                         }
00331                         if (LDNS_DNAME_NORMALIZE((int) *(lp1 + i)) <
00332                             LDNS_DNAME_NORMALIZE((int) *(lp2 + i))) {
00333                             result = -1;
00334                             goto done;
00335                         } else if (LDNS_DNAME_NORMALIZE((int) *(lp1 + i)) >
00336                             LDNS_DNAME_NORMALIZE((int) *(lp2 + i))) {
00337                             result = 1;
00338                             goto done;
00339                         }
00340                 }
00341                 if (i-1 < *lp2) {
00342                         /* apparently label 2 is larger */
00343                         result = -1;
00344                         goto done;
00345                 }
00346                 if (lc1 == 0 && lc2 > 0) {
00347                         result = -1;
00348                         goto done;
00349                 } else if (lc1 > 0 && lc2 == 0) {
00350                         result = 1;
00351                         goto done;
00352                 } else if (lc1 == 0 && lc2 == 0) {
00353                         result = 0;
00354                         goto done;
00355                 }
00356                 lc1--;
00357                 lc2--;
00358         }
00359                 
00360         
00361         done:
00362         return result;
00363 }
00364 
00365 /* nsec test: does prev <= middle < next 
00366  * -1 = yes
00367  * 0 = error/can't tell
00368  * 1 = no
00369  */
00370 int
00371 ldns_dname_interval(const ldns_rdf *prev, const ldns_rdf *middle, 
00372                 const ldns_rdf *next)
00373 {
00374         int prev_check, next_check;
00375 
00376         assert(ldns_rdf_get_type(prev) == LDNS_RDF_TYPE_DNAME);
00377         assert(ldns_rdf_get_type(middle) == LDNS_RDF_TYPE_DNAME);
00378         assert(ldns_rdf_get_type(next) == LDNS_RDF_TYPE_DNAME);
00379 
00380         prev_check = ldns_dname_compare(prev, middle);
00381         next_check = ldns_dname_compare(middle, next);
00382         /* <= next. This cannot be the case for nsec, because then we would
00383          * have gotten the nsec of next...
00384          */
00385         if (next_check == 0) {
00386                 return 0;
00387         }
00388 
00389                         /* <= */
00390         if ((prev_check == -1 || prev_check == 0) &&
00391                         /* < */
00392                         next_check == -1) {
00393                 return -1;
00394         } else {
00395                 return 1; 
00396         }
00397 }
00398 
00399 
00400 bool
00401 ldns_dname_str_absolute(const char *dname_str)
00402 {
00403         return (dname_str && 
00404                 strlen(dname_str) > 1 && 
00405                 dname_str[strlen(dname_str) - 1] == '.' &&
00406                 dname_str[strlen(dname_str) - 2] != '\\');
00407 }
00408 
00409 ldns_rdf *
00410 ldns_dname_label(const ldns_rdf *rdf, uint8_t labelpos)
00411 {
00412         uint8_t labelcnt;
00413         uint16_t src_pos;
00414         uint16_t len;
00415         ldns_rdf *tmpnew;
00416         size_t s;
00417         
00418         if (ldns_rdf_get_type(rdf) != LDNS_RDF_TYPE_DNAME) {
00419                 return NULL;
00420         }
00421 
00422         labelcnt = 0; 
00423         src_pos = 0;
00424         s = ldns_rdf_size(rdf);
00425         
00426         len = ldns_rdf_data(rdf)[src_pos]; /* label start */
00427         while ((len > 0) && src_pos < s) {
00428                 if (labelcnt == labelpos) {
00429                         /* found our label */
00430                         tmpnew = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_DNAME, len + 1,
00431                                         (ldns_rdf_data(rdf) + src_pos));
00432                         return tmpnew;
00433                 }
00434                 src_pos++;
00435                 src_pos += len;
00436                 len = ldns_rdf_data(rdf)[src_pos];
00437                 labelcnt++;
00438         }
00439         return NULL;
00440 }

Generated on Fri Nov 23 00:48:29 2007 for ldns by  doxygen 1.5.3-20071008