"Fossies" - the Fresh Open Source Software Archive

Member "nsd-4.3.6/dname.c" (6 Apr 2021, 12594 Bytes) of package /linux/misc/dns/nsd-4.3.6.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "dname.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 4.3.5_vs_4.3.6.

    1 /*
    2  * dname.c -- Domain name handling.
    3  *
    4  * Copyright (c) 2001-2006, NLnet Labs. All rights reserved.
    5  *
    6  * See LICENSE for the license.
    7  *
    8  */
    9 
   10 
   11 #include "config.h"
   12 
   13 #include <sys/types.h>
   14 
   15 #include <assert.h>
   16 #include <ctype.h>
   17 #include <limits.h>
   18 #include <stdio.h>
   19 #include <string.h>
   20 
   21 #include "dns.h"
   22 #include "dname.h"
   23 #include "query.h"
   24 
   25 const dname_type *
   26 dname_make(region_type *region, const uint8_t *name, int normalize)
   27 {
   28     size_t name_size = 0;
   29     uint8_t label_offsets[MAXDOMAINLEN];
   30     uint8_t label_count = 0;
   31     const uint8_t *label = name;
   32     dname_type *result;
   33     ssize_t i;
   34 
   35     assert(name);
   36 
   37     while (1) {
   38         if (label_is_pointer(label))
   39             return NULL;
   40 
   41         label_offsets[label_count] = (uint8_t) (label - name);
   42         ++label_count;
   43         name_size += label_length(label) + 1;
   44 
   45         if (label_is_root(label))
   46             break;
   47 
   48         label = label_next(label);
   49     }
   50 
   51     if (name_size > MAXDOMAINLEN)
   52         return NULL;
   53 
   54     assert(label_count <= MAXDOMAINLEN / 2 + 1);
   55 
   56     /* Reverse label offsets.  */
   57     for (i = 0; i < label_count / 2; ++i) {
   58         uint8_t tmp = label_offsets[i];
   59         label_offsets[i] = label_offsets[label_count - i - 1];
   60         label_offsets[label_count - i - 1] = tmp;
   61     }
   62 
   63     result = (dname_type *) region_alloc(
   64         region,
   65         (sizeof(dname_type)
   66          + (((size_t)label_count) + ((size_t)name_size)) * sizeof(uint8_t)));
   67     result->name_size = name_size;
   68     result->label_count = label_count;
   69     memcpy((uint8_t *) dname_label_offsets(result),
   70            label_offsets,
   71            label_count * sizeof(uint8_t));
   72     if (normalize) {
   73         uint8_t *dst = (uint8_t *) dname_name(result);
   74         const uint8_t *src = name;
   75         while (!label_is_root(src)) {
   76             ssize_t len = label_length(src);
   77             *dst++ = *src++;
   78             for (i = 0; i < len; ++i) {
   79                 *dst++ = DNAME_NORMALIZE((unsigned char)*src++);
   80             }
   81         }
   82         *dst = *src;
   83     } else {
   84         memcpy((uint8_t *) dname_name(result),
   85                name,
   86                name_size * sizeof(uint8_t));
   87     }
   88     return result;
   89 }
   90 
   91 
   92 const dname_type *
   93 dname_make_from_packet(region_type *region, buffer_type *packet,
   94                int allow_pointers, int normalize)
   95 {
   96     uint8_t buf[MAXDOMAINLEN + 1];
   97     if(!dname_make_wire_from_packet(buf, packet, allow_pointers))
   98         return 0;
   99     return dname_make(region, buf, normalize);
  100 }
  101 
  102 int
  103 dname_make_wire_from_packet(uint8_t *buf, buffer_type *packet,
  104                        int allow_pointers)
  105 {
  106     int done = 0;
  107     uint8_t visited[(MAX_PACKET_SIZE+7)/8];
  108     size_t dname_length = 0;
  109     const uint8_t *label;
  110     ssize_t mark = -1;
  111 
  112     if(sizeof(visited)<(buffer_limit(packet)+7)/8)
  113         memset(visited, 0, sizeof(visited));
  114     else    memset(visited, 0, (buffer_limit(packet)+7)/8);
  115 
  116     while (!done) {
  117         if (!buffer_available(packet, 1)) {
  118 /*          error("dname out of bounds"); */
  119             return 0;
  120         }
  121 
  122         if (get_bit(visited, buffer_position(packet))) {
  123 /*          error("dname loops"); */
  124             return 0;
  125         }
  126         set_bit(visited, buffer_position(packet));
  127 
  128         label = buffer_current(packet);
  129         if (label_is_pointer(label)) {
  130             size_t pointer;
  131             if (!allow_pointers) {
  132                 return 0;
  133             }
  134             if (!buffer_available(packet, 2)) {
  135 /*              error("dname pointer out of bounds"); */
  136                 return 0;
  137             }
  138             pointer = label_pointer_location(label);
  139             if (pointer >= buffer_limit(packet)) {
  140 /*              error("dname pointer points outside packet"); */
  141                 return 0;
  142             }
  143             buffer_skip(packet, 2);
  144             if (mark == -1) {
  145                 mark = buffer_position(packet);
  146             }
  147             buffer_set_position(packet, pointer);
  148         } else if (label_is_normal(label)) {
  149             size_t length = label_length(label) + 1;
  150             done = label_is_root(label);
  151             if (!buffer_available(packet, length)) {
  152 /*              error("dname label out of bounds"); */
  153                 return 0;
  154             }
  155             if (dname_length + length >= MAXDOMAINLEN+1) {
  156 /*              error("dname too large"); */
  157                 return 0;
  158             }
  159             buffer_read(packet, buf + dname_length, length);
  160             dname_length += length;
  161         } else {
  162 /*          error("bad label type"); */
  163             return 0;
  164         }
  165     }
  166 
  167     if (mark != -1) {
  168         buffer_set_position(packet, mark);
  169     }
  170 
  171     return dname_length;
  172 }
  173 
  174 const dname_type *
  175 dname_parse(region_type *region, const char *name)
  176 {
  177     uint8_t dname[MAXDOMAINLEN];
  178     if(!dname_parse_wire(dname, name))
  179         return 0;
  180     return dname_make(region, dname, 1);
  181 }
  182 
  183 int dname_parse_wire(uint8_t* dname, const char* name)
  184 {
  185     const uint8_t *s = (const uint8_t *) name;
  186     uint8_t *h;
  187     uint8_t *p;
  188     uint8_t *d = dname;
  189     size_t label_length;
  190 
  191     if (strcmp(name, ".") == 0) {
  192         /* Root domain.  */
  193         dname[0] = 0;
  194         return 1;
  195     }
  196 
  197     for (h = d, p = h + 1; *s; ++s, ++p) {
  198         if (p - dname >= MAXDOMAINLEN) {
  199             return 0;
  200         }
  201 
  202         switch (*s) {
  203         case '.':
  204             if (p == h + 1) {
  205                 /* Empty label.  */
  206                 return 0;
  207             } else {
  208                 label_length = p - h - 1;
  209                 if (label_length > MAXLABELLEN) {
  210                     return 0;
  211                 }
  212                 *h = label_length;
  213                 h = p;
  214             }
  215             break;
  216         case '\\':
  217             /* Handle escaped characters (RFC1035 5.1) */
  218             if (isdigit((unsigned char)s[1]) && isdigit((unsigned char)s[2]) && isdigit((unsigned char)s[3])) {
  219                 int val = (hexdigit_to_int(s[1]) * 100 +
  220                        hexdigit_to_int(s[2]) * 10 +
  221                        hexdigit_to_int(s[3]));
  222                 if (0 <= val && val <= 255) {
  223                     s += 3;
  224                     *p = val;
  225                 } else {
  226                     *p = *++s;
  227                 }
  228             } else if (s[1] != '\0') {
  229                 *p = *++s;
  230             }
  231             break;
  232         default:
  233             *p = *s;
  234             break;
  235         }
  236     }
  237 
  238     if (p != h + 1) {
  239         /* Terminate last label.  */
  240         label_length = p - h - 1;
  241         if (label_length > MAXLABELLEN) {
  242             return 0;
  243         }
  244         *h = label_length;
  245         h = p;
  246     }
  247 
  248     /* Add root label.  */
  249     if (h - dname >= MAXDOMAINLEN) {
  250         return 0;
  251     }
  252     *h = 0;
  253 
  254     return p-dname;
  255 }
  256 
  257 
  258 const dname_type *
  259 dname_copy(region_type *region, const dname_type *dname)
  260 {
  261     return (dname_type *) region_alloc_init(
  262         region, dname, dname_total_size(dname));
  263 }
  264 
  265 
  266 const dname_type *
  267 dname_partial_copy(region_type *region, const dname_type *dname, uint8_t label_count)
  268 {
  269     if (!dname)
  270         return NULL;
  271 
  272     if (label_count == 0) {
  273         /* Always copy the root label.  */
  274         label_count = 1;
  275     }
  276 
  277     assert(label_count <= dname->label_count);
  278 
  279     return dname_make(region, dname_label(dname, label_count - 1), 0);
  280 }
  281 
  282 
  283 const dname_type *
  284 dname_origin(region_type *region, const dname_type *dname)
  285 {
  286     return dname_partial_copy(region, dname, dname->label_count - 1);
  287 }
  288 
  289 
  290 int
  291 dname_is_subdomain(const dname_type *left, const dname_type *right)
  292 {
  293     uint8_t i;
  294 
  295     if (left->label_count < right->label_count)
  296         return 0;
  297 
  298     for (i = 1; i < right->label_count; ++i) {
  299         if (label_compare(dname_label(left, i),
  300                   dname_label(right, i)) != 0)
  301             return 0;
  302     }
  303 
  304     return 1;
  305 }
  306 
  307 
  308 int
  309 dname_compare(const dname_type *left, const dname_type *right)
  310 {
  311     int result;
  312     uint8_t label_count;
  313     uint8_t i;
  314 
  315     assert(left);
  316     assert(right);
  317 
  318     if (left == right) {
  319         return 0;
  320     }
  321 
  322     label_count = (left->label_count <= right->label_count
  323                ? left->label_count
  324                : right->label_count);
  325 
  326     /* Skip the root label by starting at label 1.  */
  327     for (i = 1; i < label_count; ++i) {
  328         result = label_compare(dname_label(left, i),
  329                        dname_label(right, i));
  330         if (result) {
  331             return result;
  332         }
  333     }
  334 
  335     /* Dname with the fewest labels is "first".  */
  336     /* the subtraction works because the size of int is much larger than
  337      * the label count and the values won't wrap around */
  338     return (int) left->label_count - (int) right->label_count;
  339 }
  340 
  341 
  342 int
  343 label_compare(const uint8_t *left, const uint8_t *right)
  344 {
  345     int left_length;
  346     int right_length;
  347     size_t size;
  348     int result;
  349 
  350     assert(left);
  351     assert(right);
  352 
  353     assert(label_is_normal(left));
  354     assert(label_is_normal(right));
  355 
  356     left_length = label_length(left);
  357     right_length = label_length(right);
  358     size = left_length < right_length ? left_length : right_length;
  359 
  360     result = memcmp(label_data(left), label_data(right), size);
  361     if (result) {
  362         return result;
  363     } else {
  364         /* the subtraction works because the size of int is much
  365          * larger than the lengths and the values won't wrap around */
  366         return (int) left_length - (int) right_length;
  367     }
  368 }
  369 
  370 
  371 uint8_t
  372 dname_label_match_count(const dname_type *left, const dname_type *right)
  373 {
  374     uint8_t i;
  375 
  376     assert(left);
  377     assert(right);
  378 
  379     for (i = 1; i < left->label_count && i < right->label_count; ++i) {
  380         if (label_compare(dname_label(left, i),
  381                   dname_label(right, i)) != 0)
  382         {
  383             return i;
  384         }
  385     }
  386 
  387     return i;
  388 }
  389 
  390 const char *
  391 dname_to_string(const dname_type *dname, const dname_type *origin)
  392 {
  393     static char buf[MAXDOMAINLEN * 5];
  394     size_t i;
  395     size_t labels_to_convert = dname->label_count - 1;
  396     int absolute = 1;
  397     char *dst;
  398     const uint8_t *src;
  399 
  400     if (dname->label_count == 1) {
  401         strlcpy(buf, ".", sizeof(buf));
  402         return buf;
  403     }
  404 
  405     if (origin && dname_is_subdomain(dname, origin)) {
  406         int common_labels = dname_label_match_count(dname, origin);
  407         labels_to_convert = dname->label_count - common_labels;
  408         absolute = 0;
  409     }
  410 
  411     dst = buf;
  412     src = dname_name(dname);
  413     for (i = 0; i < labels_to_convert; ++i) {
  414         size_t len = label_length(src);
  415         size_t j;
  416         ++src;
  417         for (j = 0; j < len; ++j) {
  418             uint8_t ch = *src++;
  419             if (isalnum((unsigned char)ch) || ch == '-' || ch == '_' || ch == '*') {
  420                 *dst++ = ch;
  421             } else if (ch == '.' || ch == '\\') {
  422                 *dst++ = '\\';
  423                 *dst++ = ch;
  424             } else {
  425                 snprintf(dst, 5, "\\%03u", (unsigned int)ch);
  426                 dst += 4;
  427             }
  428         }
  429         *dst++ = '.';
  430     }
  431     if (absolute) {
  432         *dst = '\0';
  433     } else {
  434         *--dst = '\0';
  435     }
  436     return buf;
  437 }
  438 
  439 
  440 const dname_type *
  441 dname_make_from_label(region_type *region,
  442               const uint8_t *label, const size_t length)
  443 {
  444     uint8_t temp[MAXLABELLEN + 2];
  445 
  446     assert(length > 0 && length <= MAXLABELLEN);
  447 
  448     temp[0] = length;
  449     memcpy(temp + 1, label, length * sizeof(uint8_t));
  450     temp[length + 1] = '\000';
  451 
  452     return dname_make(region, temp, 1);
  453 }
  454 
  455 
  456 const dname_type *
  457 dname_concatenate(region_type *region,
  458           const dname_type *left,
  459           const dname_type *right)
  460 {
  461     uint8_t temp[MAXDOMAINLEN];
  462 
  463     assert(left->name_size + right->name_size - 1 <= MAXDOMAINLEN);
  464 
  465     memcpy(temp, dname_name(left), left->name_size - 1);
  466     memcpy(temp + left->name_size - 1, dname_name(right), right->name_size);
  467 
  468     return dname_make(region, temp, 0);
  469 }
  470 
  471 
  472 const dname_type *
  473 dname_replace(region_type* region,
  474         const dname_type* name,
  475         const dname_type* src,
  476         const dname_type* dest)
  477 {
  478     /* nomenclature: name is said to be <x>.<src>. x can be null. */
  479     dname_type* res;
  480     int x_labels = name->label_count - src->label_count;
  481     int x_len = name->name_size - src->name_size;
  482     int i;
  483     assert(dname_is_subdomain(name, src));
  484 
  485     /* check if final size is acceptable */
  486     if(x_len+dest->name_size > MAXDOMAINLEN)
  487         return NULL;
  488 
  489     res = (dname_type*)region_alloc(region, sizeof(dname_type) +
  490         (x_labels+((int)dest->label_count) + x_len+((int)dest->name_size))
  491         *sizeof(uint8_t));
  492     res->name_size = x_len+dest->name_size;
  493     res->label_count = x_labels+dest->label_count;
  494     for(i=0; i<dest->label_count; i++)
  495         ((uint8_t*)dname_label_offsets(res))[i] =
  496             dname_label_offsets(dest)[i] + x_len;
  497     for(i=dest->label_count; i<res->label_count; i++)
  498         ((uint8_t*)dname_label_offsets(res))[i] =
  499             dname_label_offsets(name)[i - dest->label_count +
  500                 src->label_count];
  501     memcpy((uint8_t*)dname_name(res), dname_name(name), x_len);
  502     memcpy((uint8_t*)dname_name(res)+x_len, dname_name(dest), dest->name_size);
  503     assert(dname_is_subdomain(res, dest));
  504     return res;
  505 }
  506 
  507 char* wirelabel2str(const uint8_t* label)
  508 {
  509     static char buf[MAXDOMAINLEN*5+3];
  510     char* p = buf;
  511     uint8_t lablen;
  512     lablen = *label++;
  513     while(lablen--) {
  514         uint8_t ch = *label++;
  515         if (isalnum((unsigned char)ch) || ch == '-' || ch == '_' || ch == '*') {
  516             *p++ = ch;
  517         } else if (ch == '.' || ch == '\\') {
  518             *p++ = '\\';
  519             *p++ = ch;
  520         } else {
  521             snprintf(p, 5, "\\%03u", (unsigned int)ch);
  522             p += 4;
  523         }
  524     }
  525     *p++ = 0;
  526     return buf;
  527 }
  528 
  529 char* wiredname2str(const uint8_t* dname)
  530 {
  531     static char buf[MAXDOMAINLEN*5+3];
  532     char* p = buf;
  533     uint8_t lablen;
  534     if(*dname == 0) {
  535         strlcpy(buf, ".", sizeof(buf));
  536         return buf;
  537     }
  538     lablen = *dname++;
  539     while(lablen) {
  540         while(lablen--) {
  541             uint8_t ch = *dname++;
  542             if (isalnum((unsigned char)ch) || ch == '-' || ch == '_' || ch == '*') {
  543                 *p++ = ch;
  544             } else if (ch == '.' || ch == '\\') {
  545                 *p++ = '\\';
  546                 *p++ = ch;
  547             } else {
  548                 snprintf(p, 5, "\\%03u", (unsigned int)ch);
  549                 p += 4;
  550             }
  551         }
  552         lablen = *dname++;
  553         *p++ = '.';
  554     }
  555     *p++ = 0;
  556     return buf;
  557 }
  558 
  559 int dname_equal_nocase(uint8_t* a, uint8_t* b, uint16_t len)
  560 {
  561     uint8_t i, lablen;
  562     while(len > 0) {
  563         /* check labellen */
  564         if(*a != *b)
  565             return 0;
  566         lablen = *a++;
  567         b++;
  568         len--;
  569         /* malformed or compression ptr; we stop scanning */
  570         if((lablen & 0xc0) || len < lablen)
  571             return (memcmp(a, b, len) == 0);
  572         /* check the label, lowercased */
  573         for(i=0; i<lablen; i++) {
  574             if(DNAME_NORMALIZE((unsigned char)*a++) != DNAME_NORMALIZE((unsigned char)*b++))
  575                 return 0;
  576         }
  577         len -= lablen;
  578     }
  579     return 1;
  580 }