"Fossies" - the Fresh Open Source Software Archive

Member "libspf2-1.2.10/src/libreplace/__ns_name_uncompress.c" (28 Jan 2012, 21375 Bytes) of package /linux/privat/libspf2-1.2.10.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 "__ns_name_uncompress.c" see the Fossies "Dox" file reference documentation.

    1 /*
    2  * Copyright (c) 1996,1999 by Internet Software Consortium.
    3  *
    4  * Permission to use, copy, modify, and distribute this software for any
    5  * purpose with or without fee is hereby granted, provided that the above
    6  * copyright notice and this permission notice appear in all copies.
    7  *
    8  * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
    9  * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
   10  * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
   11  * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
   12  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
   13  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
   14  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
   15  * SOFTWARE.
   16  */
   17 
   18 #ifndef lint
   19 static const char rcsid[] = "$Id: ns_name.c,v 1.3.2.4 2003/07/02 04:10:27 marka Exp $";
   20 #endif
   21 
   22 /* #include "port_before.h" */
   23 #include "config.h"
   24 
   25 #ifdef STDC_HEADERS
   26 # include <stdio.h>
   27 #endif
   28 
   29 #include <sys/types.h>
   30 
   31 #include <netinet/in.h>
   32 #include "arpa_nameser.h"
   33 
   34 #include <errno.h>
   35 /* #include <resolv.h> */
   36 #ifdef HAVE_STRING_H
   37 # include <string.h>       /* strstr / strdup */
   38 #else
   39 # ifdef HAVE_STRINGS_H
   40 #  include <strings.h>       /* strstr / strdup */
   41 # endif
   42 #endif
   43 
   44 #include <ctype.h>
   45 #include <stdlib.h>
   46 #include <limits.h>
   47 
   48 /* #include "port_after.h" */
   49 
   50 #ifdef SPRINTF_CHAR
   51 # define SPRINTF(x) strlen(sprintf/**/x)
   52 #else
   53 # define SPRINTF(x) ((size_t)sprintf x)
   54 #endif
   55 
   56 #define NS_TYPE_ELT         0x40 /* EDNS0 extended label type */
   57 #define DNS_LABELTYPE_BITSTRING     0x41
   58 
   59 /* Data. */
   60 
   61 static const char   digits[] = "0123456789";
   62 
   63 static const char digitvalue[256] = {
   64     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*16*/
   65     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*32*/
   66     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*48*/
   67      0,  1,  2,  3,  4,  5,  6,  7,  8,  9, -1, -1, -1, -1, -1, -1, /*64*/
   68     -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*80*/
   69     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*96*/
   70     -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*112*/
   71     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*128*/
   72     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
   73     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
   74     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
   75     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
   76     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
   77     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
   78     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
   79     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*256*/
   80 };
   81 
   82 /* Forward. */
   83 
   84 static int      special(int);
   85 static int      printable(int);
   86 static int      dn_find(const u_char *, const u_char *,
   87                 const u_char * const *,
   88                 const u_char * const *);
   89 static int      encode_bitsring(const char **, const char *,
   90                     char **, char **, const char *);
   91 static int      labellen(const u_char *);
   92 static int      decode_bitstring(const char **, char *, const char *);
   93 
   94 /* Public. */
   95 
   96 /*
   97  * ns_name_ntop(src, dst, dstsiz)
   98  *  Convert an encoded domain name to printable ascii as per RFC1035.
   99  * return:
  100  *  Number of bytes written to buffer, or -1 (with errno set)
  101  * notes:
  102  *  The root is returned as "."
  103  *  All other domains are returned in non absolute form
  104  */
  105 int
  106 ns_name_ntop(const u_char *src, char *dst, size_t dstsiz)
  107 {
  108     const u_char *cp;
  109     char *dn, *eom;
  110     u_char c;
  111     u_int n;
  112     int l;
  113 
  114     cp = src;
  115     dn = dst;
  116     eom = dst + dstsiz;
  117 
  118     while ((n = *cp++) != 0) {
  119         if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
  120             /* Some kind of compression pointer. */
  121             errno = EMSGSIZE;
  122             return (-1);
  123         }
  124         if (dn != dst) {
  125             if (dn >= eom) {
  126                 errno = EMSGSIZE;
  127                 return (-1);
  128             }
  129             *dn++ = '.';
  130         }
  131         if ((l = labellen(cp - 1)) < 0) {
  132             errno = EMSGSIZE; /* XXX */
  133             return(-1);
  134         }
  135         if (dn + l >= eom) {
  136             errno = EMSGSIZE;
  137             return (-1);
  138         }
  139         if ((n & NS_CMPRSFLGS) == NS_TYPE_ELT) {
  140             int m;
  141 
  142             if (n != DNS_LABELTYPE_BITSTRING) {
  143                 /* XXX: labellen should reject this case */
  144                 errno = EINVAL;
  145                 return(-1);
  146             }
  147             if ((m = decode_bitstring((const char **)&cp, dn, eom)) < 0)
  148             {
  149                 errno = EMSGSIZE;
  150                 return(-1);
  151             }
  152             dn += m; 
  153             continue;
  154         }
  155         for ((void)NULL; l > 0; l--) {
  156             c = *cp++;
  157             if (special(c)) {
  158                 if (dn + 1 >= eom) {
  159                     errno = EMSGSIZE;
  160                     return (-1);
  161                 }
  162                 *dn++ = '\\';
  163                 *dn++ = (char)c;
  164             } else if (!printable(c)) {
  165                 if (dn + 3 >= eom) {
  166                     errno = EMSGSIZE;
  167                     return (-1);
  168                 }
  169                 *dn++ = '\\';
  170                 *dn++ = digits[c / 100];
  171                 *dn++ = digits[(c % 100) / 10];
  172                 *dn++ = digits[c % 10];
  173             } else {
  174                 if (dn >= eom) {
  175                     errno = EMSGSIZE;
  176                     return (-1);
  177                 }
  178                 *dn++ = (char)c;
  179             }
  180         }
  181     }
  182     if (dn == dst) {
  183         if (dn >= eom) {
  184             errno = EMSGSIZE;
  185             return (-1);
  186         }
  187         *dn++ = '.';
  188     }
  189     if (dn >= eom) {
  190         errno = EMSGSIZE;
  191         return (-1);
  192     }
  193     *dn++ = '\0';
  194     return (dn - dst);
  195 }
  196 
  197 /*
  198  * ns_name_pton(src, dst, dstsiz)
  199  *  Convert a ascii string into an encoded domain name as per RFC1035.
  200  * return:
  201  *  -1 if it fails
  202  *  1 if string was fully qualified
  203  *  0 is string was not fully qualified
  204  * notes:
  205  *  Enforces label and domain length limits.
  206  */
  207 
  208 int
  209 ns_name_pton(const char *src, u_char *dst, size_t dstsiz)
  210 {
  211     u_char *label, *bp, *eom;
  212     int c, n, escaped, e = 0;
  213     char *cp;
  214 
  215     escaped = 0;
  216     bp = dst;
  217     eom = dst + dstsiz;
  218     label = bp++;
  219 
  220     while ((c = *src++) != 0) {
  221         if (escaped) {
  222             if (c == '[') { /* start a bit string label */
  223                 if ((cp = strchr(src, ']')) == NULL) {
  224                     errno = EINVAL; /* ??? */
  225                     return(-1);
  226                 }
  227                 if ((e = encode_bitsring(&src,
  228                              cp + 2,
  229                              (char **)&label,
  230                              (char **)&bp,
  231                              (const char *)eom))
  232                     != 0) {
  233                     errno = e;
  234                     return(-1);
  235                 }
  236                 escaped = 0;
  237                 label = bp++;
  238                 if ((c = *src++) == 0)
  239                     goto done;
  240                 else if (c != '.') {
  241                     errno = EINVAL;
  242                     return(-1);
  243                 }
  244                 continue;
  245             }
  246             else if ((cp = strchr(digits, c)) != NULL) {
  247                 n = (cp - digits) * 100;
  248                 if ((c = *src++) == 0 ||
  249                     (cp = strchr(digits, c)) == NULL) {
  250                     errno = EMSGSIZE;
  251                     return (-1);
  252                 }
  253                 n += (cp - digits) * 10;
  254                 if ((c = *src++) == 0 ||
  255                     (cp = strchr(digits, c)) == NULL) {
  256                     errno = EMSGSIZE;
  257                     return (-1);
  258                 }
  259                 n += (cp - digits);
  260                 if (n > 255) {
  261                     errno = EMSGSIZE;
  262                     return (-1);
  263                 }
  264                 c = n;
  265             }
  266             escaped = 0;
  267         } else if (c == '\\') {
  268             escaped = 1;
  269             continue;
  270         } else if (c == '.') {
  271             c = (bp - label - 1);
  272             if ((c & NS_CMPRSFLGS) != 0) {  /* Label too big. */
  273                 errno = EMSGSIZE;
  274                 return (-1);
  275             }
  276             if (label >= eom) {
  277                 errno = EMSGSIZE;
  278                 return (-1);
  279             }
  280             *label = c;
  281             /* Fully qualified ? */
  282             if (*src == '\0') {
  283                 if (c != 0) {
  284                     if (bp >= eom) {
  285                         errno = EMSGSIZE;
  286                         return (-1);
  287                     }
  288                     *bp++ = '\0';
  289                 }
  290                 if ((bp - dst) > NS_MAXCDNAME) {
  291                     errno = EMSGSIZE;
  292                     return (-1);
  293                 }
  294                 return (1);
  295             }
  296             if (c == 0 || *src == '.') {
  297                 errno = EMSGSIZE;
  298                 return (-1);
  299             }
  300             label = bp++;
  301             continue;
  302         }
  303         if (bp >= eom) {
  304             errno = EMSGSIZE;
  305             return (-1);
  306         }
  307         *bp++ = (u_char)c;
  308     }
  309     c = (bp - label - 1);
  310     if ((c & NS_CMPRSFLGS) != 0) {      /* Label too big. */
  311         errno = EMSGSIZE;
  312         return (-1);
  313     }
  314   done:
  315     if (label >= eom) {
  316         errno = EMSGSIZE;
  317         return (-1);
  318     }
  319     *label = c;
  320     if (c != 0) {
  321         if (bp >= eom) {
  322             errno = EMSGSIZE;
  323             return (-1);
  324         }
  325         *bp++ = 0;
  326     }
  327     if ((bp - dst) > NS_MAXCDNAME) {    /* src too big */
  328         errno = EMSGSIZE;
  329         return (-1);
  330     }
  331     return (0);
  332 }
  333 
  334 /*
  335  * ns_name_ntol(src, dst, dstsiz)
  336  *  Convert a network strings labels into all lowercase.
  337  * return:
  338  *  Number of bytes written to buffer, or -1 (with errno set)
  339  * notes:
  340  *  Enforces label and domain length limits.
  341  */
  342 
  343 int
  344 ns_name_ntol(const u_char *src, u_char *dst, size_t dstsiz)
  345 {
  346     const u_char *cp;
  347     u_char *dn, *eom;
  348     u_char c;
  349     u_int n;
  350     int l;
  351 
  352     cp = src;
  353     dn = dst;
  354     eom = dst + dstsiz;
  355 
  356     if (dn >= eom) {
  357         errno = EMSGSIZE;
  358         return (-1);
  359     }
  360     while ((n = *cp++) != 0) {
  361         if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
  362             /* Some kind of compression pointer. */
  363             errno = EMSGSIZE;
  364             return (-1);
  365         }
  366         *dn++ = n;
  367         if ((l = labellen(cp - 1)) < 0) {
  368             errno = EMSGSIZE;
  369             return (-1);
  370         }
  371         if (dn + l >= eom) {
  372             errno = EMSGSIZE;
  373             return (-1);
  374         }
  375         for ((void)NULL; l > 0; l--) {
  376             c = *cp++;
  377             if (isupper(c))
  378                 *dn++ = tolower(c);
  379             else
  380                 *dn++ = c;
  381         }
  382     }
  383     *dn++ = '\0';
  384     return (dn - dst);
  385 }
  386 
  387 /*
  388  * ns_name_unpack(msg, eom, src, dst, dstsiz)
  389  *  Unpack a domain name from a message, source may be compressed.
  390  * return:
  391  *  -1 if it fails, or consumed octets if it succeeds.
  392  */
  393 int
  394 ns_name_unpack(const u_char *msg, const u_char *eom, const u_char *src,
  395            u_char *dst, size_t dstsiz)
  396 {
  397     const u_char *srcp, *dstlim;
  398     u_char *dstp;
  399     int n, len, checked, l;
  400 
  401     len = -1;
  402     checked = 0;
  403     dstp = dst;
  404     srcp = src;
  405     dstlim = dst + dstsiz;
  406     if (srcp < msg || srcp >= eom) {
  407         errno = EMSGSIZE;
  408         return (-1);
  409     }
  410     /* Fetch next label in domain name. */
  411     while ((n = *srcp++) != 0) {
  412         /* Check for indirection. */
  413         switch (n & NS_CMPRSFLGS) {
  414         case 0:
  415         case NS_TYPE_ELT:
  416             /* Limit checks. */
  417             if ((l = labellen(srcp - 1)) < 0) {
  418                 errno = EMSGSIZE;
  419                 return(-1);
  420             }
  421             if (dstp + l + 1 >= dstlim || srcp + l >= eom) {
  422                 errno = EMSGSIZE;
  423                 return (-1);
  424             }
  425             checked += l + 1;
  426             *dstp++ = n;
  427             memcpy(dstp, srcp, l);
  428             dstp += l;
  429             srcp += l;
  430             break;
  431 
  432         case NS_CMPRSFLGS:
  433             if (srcp >= eom) {
  434                 errno = EMSGSIZE;
  435                 return (-1);
  436             }
  437             if (len < 0)
  438                 len = srcp - src + 1;
  439             srcp = msg + (((n & 0x3f) << 8) | (*srcp & 0xff));
  440             if (srcp < msg || srcp >= eom) {  /* Out of range. */
  441                 errno = EMSGSIZE;
  442                 return (-1);
  443             }
  444             checked += 2;
  445             /*
  446              * Check for loops in the compressed name;
  447              * if we've looked at the whole message,
  448              * there must be a loop.
  449              */
  450             if (checked >= eom - msg) {
  451                 errno = EMSGSIZE;
  452                 return (-1);
  453             }
  454             break;
  455 
  456         default:
  457             errno = EMSGSIZE;
  458             return (-1);            /* flag error */
  459         }
  460     }
  461     *dstp = '\0';
  462     if (len < 0)
  463         len = srcp - src;
  464     return (len);
  465 }
  466 
  467 /*
  468  * ns_name_pack(src, dst, dstsiz, dnptrs, lastdnptr)
  469  *  Pack domain name 'domain' into 'comp_dn'.
  470  * return:
  471  *  Size of the compressed name, or -1.
  472  * notes:
  473  *  'dnptrs' is an array of pointers to previous compressed names.
  474  *  dnptrs[0] is a pointer to the beginning of the message. The array
  475  *  ends with NULL.
  476  *  'lastdnptr' is a pointer to the end of the array pointed to
  477  *  by 'dnptrs'.
  478  * Side effects:
  479  *  The list of pointers in dnptrs is updated for labels inserted into
  480  *  the message as we compress the name.  If 'dnptr' is NULL, we don't
  481  *  try to compress names. If 'lastdnptr' is NULL, we don't update the
  482  *  list.
  483  */
  484 int
  485 ns_name_pack(const u_char *src, u_char *dst, int dstsiz,
  486          const u_char **dnptrs, const u_char **lastdnptr)
  487 {
  488     u_char *dstp;
  489     const u_char **cpp, **lpp, *eob, *msg;
  490     const u_char *srcp;
  491     int n, l, first = 1;
  492 
  493     srcp = src;
  494     dstp = dst;
  495     eob = dstp + dstsiz;
  496     lpp = cpp = NULL;
  497     if (dnptrs != NULL) {
  498         if ((msg = *dnptrs++) != NULL) {
  499             for (cpp = dnptrs; *cpp != NULL; cpp++)
  500                 (void)NULL;
  501             lpp = cpp;  /* end of list to search */
  502         }
  503     } else
  504         msg = NULL;
  505 
  506     /* make sure the domain we are about to add is legal */
  507     l = 0;
  508     do {
  509         int l0;
  510 
  511         n = *srcp;
  512         if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
  513             errno = EMSGSIZE;
  514             return (-1);
  515         }
  516         if ((l0 = labellen(srcp)) < 0) {
  517             errno = EINVAL;
  518             return(-1);
  519         }
  520         l += l0 + 1;
  521         if (l > NS_MAXCDNAME) {
  522             errno = EMSGSIZE;
  523             return (-1);
  524         }
  525         srcp += l0 + 1;
  526     } while (n != 0);
  527 
  528     /* from here on we need to reset compression pointer array on error */
  529     srcp = src;
  530     do {
  531         /* Look to see if we can use pointers. */
  532         n = *srcp;
  533         if (n != 0 && msg != NULL) {
  534             l = dn_find(srcp, msg, (const u_char * const *)dnptrs,
  535                     (const u_char * const *)lpp);
  536             if (l >= 0) {
  537                 if (dstp + 1 >= eob) {
  538                     goto cleanup;
  539                 }
  540                 *dstp++ = (l >> 8) | NS_CMPRSFLGS;
  541                 *dstp++ = l % 256;
  542                 return (dstp - dst);
  543             }
  544             /* Not found, save it. */
  545             if (lastdnptr != NULL && cpp < lastdnptr - 1 &&
  546                 (dstp - msg) < 0x4000 && first) {
  547                 *cpp++ = dstp;
  548                 *cpp = NULL;
  549                 first = 0;
  550             }
  551         }
  552         /* copy label to buffer */
  553         if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
  554             /* Should not happen. */
  555             goto cleanup;
  556         }
  557         n = labellen(srcp);
  558         if (dstp + 1 + n >= eob) {
  559             goto cleanup;
  560         }
  561         memcpy(dstp, srcp, n + 1);
  562         srcp += n + 1;
  563         dstp += n + 1;
  564     } while (n != 0);
  565 
  566     if (dstp > eob) {
  567 cleanup:
  568         if (msg != NULL)
  569             *lpp = NULL;
  570         errno = EMSGSIZE;
  571         return (-1);
  572     } 
  573     return (dstp - dst);
  574 }
  575 
  576 /*
  577  * ns_name_uncompress(msg, eom, src, dst, dstsiz)
  578  *  Expand compressed domain name to presentation format.
  579  * return:
  580  *  Number of bytes read out of `src', or -1 (with errno set).
  581  * note:
  582  *  Root domain returns as "." not "".
  583  */
  584 int
  585 ns_name_uncompress(const u_char *msg, const u_char *eom, const u_char *src,
  586            char *dst, size_t dstsiz)
  587 {
  588     u_char tmp[NS_MAXCDNAME];
  589     int n;
  590     
  591     if ((n = ns_name_unpack(msg, eom, src, tmp, sizeof tmp)) == -1)
  592         return (-1);
  593     if (ns_name_ntop(tmp, dst, dstsiz) == -1)
  594         return (-1);
  595     return (n);
  596 }
  597 
  598 /*
  599  * ns_name_compress(src, dst, dstsiz, dnptrs, lastdnptr)
  600  *  Compress a domain name into wire format, using compression pointers.
  601  * return:
  602  *  Number of bytes consumed in `dst' or -1 (with errno set).
  603  * notes:
  604  *  'dnptrs' is an array of pointers to previous compressed names.
  605  *  dnptrs[0] is a pointer to the beginning of the message.
  606  *  The list ends with NULL.  'lastdnptr' is a pointer to the end of the
  607  *  array pointed to by 'dnptrs'. Side effect is to update the list of
  608  *  pointers for labels inserted into the message as we compress the name.
  609  *  If 'dnptr' is NULL, we don't try to compress names. If 'lastdnptr'
  610  *  is NULL, we don't update the list.
  611  */
  612 int
  613 ns_name_compress(const char *src, u_char *dst, size_t dstsiz,
  614          const u_char **dnptrs, const u_char **lastdnptr)
  615 {
  616     u_char tmp[NS_MAXCDNAME];
  617 
  618     if (ns_name_pton(src, tmp, sizeof tmp) == -1)
  619         return (-1);
  620     return (ns_name_pack(tmp, dst, dstsiz, dnptrs, lastdnptr));
  621 }
  622 
  623 /*
  624  * Reset dnptrs so that there are no active references to pointers at or
  625  * after src.
  626  */
  627 void
  628 ns_name_rollback(const u_char *src, const u_char **dnptrs,
  629          const u_char **lastdnptr)
  630 {
  631     while (dnptrs < lastdnptr && *dnptrs != NULL) {
  632         if (*dnptrs >= src) {
  633             *dnptrs = NULL;
  634             break;
  635         }
  636         dnptrs++;
  637     }
  638 }
  639 
  640 /*
  641  * ns_name_skip(ptrptr, eom)
  642  *  Advance *ptrptr to skip over the compressed name it points at.
  643  * return:
  644  *  0 on success, -1 (with errno set) on failure.
  645  */
  646 int
  647 ns_name_skip(const u_char **ptrptr, const u_char *eom)
  648 {
  649     const u_char *cp;
  650     u_int n;
  651     int l;
  652 
  653     cp = *ptrptr;
  654     while (cp < eom && (n = *cp++) != 0) {
  655         /* Check for indirection. */
  656         switch (n & NS_CMPRSFLGS) {
  657         case 0:         /* normal case, n == len */
  658             cp += n;
  659             continue;
  660         case NS_TYPE_ELT: /* EDNS0 extended label */
  661             if ((l = labellen(cp - 1)) < 0) {
  662                 errno = EMSGSIZE; /* XXX */
  663                 return(-1);
  664             }
  665             cp += l;
  666             continue;
  667         case NS_CMPRSFLGS:  /* indirection */
  668             cp++;
  669             break;
  670         default:        /* illegal type */
  671             errno = EMSGSIZE;
  672             return (-1);
  673         }
  674         break;
  675     }
  676     if (cp > eom) {
  677         errno = EMSGSIZE;
  678         return (-1);
  679     }
  680     *ptrptr = cp;
  681     return (0);
  682 }
  683 
  684 /* Private. */
  685 
  686 /*
  687  * special(ch)
  688  *  Thinking in noninternationalized USASCII (per the DNS spec),
  689  *  is this characted special ("in need of quoting") ?
  690  * return:
  691  *  boolean.
  692  */
  693 static int
  694 special(int ch) {
  695     switch (ch) {
  696     case 0x22: /* '"' */
  697     case 0x2E: /* '.' */
  698     case 0x3B: /* ';' */
  699     case 0x5C: /* '\\' */
  700     case 0x28: /* '(' */
  701     case 0x29: /* ')' */
  702     /* Special modifiers in zone files. */
  703     case 0x40: /* '@' */
  704     case 0x24: /* '$' */
  705         return (1);
  706     default:
  707         return (0);
  708     }
  709 }
  710 
  711 /*
  712  * printable(ch)
  713  *  Thinking in noninternationalized USASCII (per the DNS spec),
  714  *  is this character visible and not a space when printed ?
  715  * return:
  716  *  boolean.
  717  */
  718 static int
  719 printable(int ch) {
  720     return (ch > 0x20 && ch < 0x7f);
  721 }
  722 
  723 /*
  724  *  Thinking in noninternationalized USASCII (per the DNS spec),
  725  *  convert this character to lower case if it's upper case.
  726  */
  727 static int
  728 mklower(int ch) {
  729     if (ch >= 0x41 && ch <= 0x5A)
  730         return (ch + 0x20);
  731     return (ch);
  732 }
  733 
  734 /*
  735  * dn_find(domain, msg, dnptrs, lastdnptr)
  736  *  Search for the counted-label name in an array of compressed names.
  737  * return:
  738  *  offset from msg if found, or -1.
  739  * notes:
  740  *  dnptrs is the pointer to the first name on the list,
  741  *  not the pointer to the start of the message.
  742  */
  743 static int
  744 dn_find(const u_char *domain, const u_char *msg,
  745     const u_char * const *dnptrs,
  746     const u_char * const *lastdnptr)
  747 {
  748     const u_char *dn, *cp, *sp;
  749     const u_char * const *cpp;
  750     u_int n;
  751 
  752     for (cpp = dnptrs; cpp < lastdnptr; cpp++) {
  753         sp = *cpp;
  754         /*
  755          * terminate search on:
  756          * root label
  757          * compression pointer
  758          * unusable offset
  759          */
  760         while (*sp != 0 && (*sp & NS_CMPRSFLGS) == 0 &&
  761                (sp - msg) < 0x4000) {
  762             dn = domain;
  763             cp = sp;
  764             while ((n = *cp++) != 0) {
  765                 /*
  766                  * check for indirection
  767                  */
  768                 switch (n & NS_CMPRSFLGS) {
  769                 case 0:     /* normal case, n == len */
  770                     n = labellen(cp - 1); /* XXX */
  771 
  772                     if (n != *dn++)
  773                         goto next;
  774 
  775                     for ((void)NULL; n > 0; n--)
  776                         if (mklower(*dn++) !=
  777                             mklower(*cp++))
  778                             goto next;
  779                     /* Is next root for both ? */
  780                     if (*dn == '\0' && *cp == '\0')
  781                         return (sp - msg);
  782                     if (*dn)
  783                         continue;
  784                     goto next;
  785                 case NS_CMPRSFLGS:  /* indirection */
  786                     cp = msg + (((n & 0x3f) << 8) | *cp);
  787                     break;
  788 
  789                 default:    /* illegal type */
  790                     errno = EMSGSIZE;
  791                     return (-1);
  792                 }
  793             }
  794  next: ;
  795             sp += *sp + 1;
  796         }
  797     }
  798     errno = ENOENT;
  799     return (-1);
  800 }
  801 
  802 static int
  803 decode_bitstring(const char **cpp, char *dn, const char *eom)
  804 {
  805     const char *cp = *cpp;
  806     char *beg = dn, tc;
  807     int b, blen, plen, i;
  808 
  809     if ((blen = (*cp & 0xff)) == 0)
  810         blen = 256;
  811     plen = (blen + 3) / 4;
  812     plen += sizeof("\\[x/]") + (blen > 99 ? 3 : (blen > 9) ? 2 : 1);
  813     if (dn + plen >= eom)
  814         return(-1);
  815 
  816     cp++;
  817     i = SPRINTF((dn, "\\[x"));
  818     if (i < 0)
  819         return (-1);
  820     dn += i;
  821     for (b = blen; b > 7; b -= 8, cp++) {
  822         i = SPRINTF((dn, "%02x", *cp & 0xff));
  823         if (i < 0)
  824             return (-1);
  825         dn += i;
  826     }
  827     if (b > 4) {
  828         tc = *cp++;
  829         i = SPRINTF((dn, "%02x", tc & (0xff << (8 - b))));
  830         if (i < 0)
  831             return (-1);
  832         dn += i;
  833     } else if (b > 0) {
  834         tc = *cp++;
  835         i = SPRINTF((dn, "%1x",
  836                    ((tc >> 4) & 0x0f) & (0x0f << (4 - b)))); 
  837         if (i < 0)
  838             return (-1);
  839         dn += i;
  840     }
  841     i = SPRINTF((dn, "/%d]", blen));
  842     if (i < 0)
  843         return (-1);
  844     dn += i;
  845 
  846     *cpp = cp;
  847     return(dn - beg);
  848 }
  849 
  850 static int
  851 encode_bitsring(const char **bp, const char *end, char **labelp,
  852             char ** dst, const char *eom)
  853 {
  854     int afterslash = 0;
  855     const char *cp = *bp;
  856     char *tp, c;
  857     const char *beg_blen;
  858     char *end_blen = NULL;
  859     int value = 0, count = 0, tbcount = 0, blen = 0;
  860 
  861     beg_blen = end_blen = NULL;
  862 
  863     /* a bitstring must contain at least 2 characters */
  864     if (end - cp < 2)
  865         return(EINVAL);
  866 
  867     /* XXX: currently, only hex strings are supported */
  868     if (*cp++ != 'x')
  869         return(EINVAL);
  870     if (!isxdigit((*cp) & 0xff)) /* reject '\[x/BLEN]' */
  871         return(EINVAL);
  872 
  873     for (tp = *dst + 1; cp < end && tp < eom; cp++) {
  874         switch((c = *cp)) {
  875         case ']':   /* end of the bitstring */
  876             if (afterslash) {
  877                 if (beg_blen == NULL)
  878                     return(EINVAL);
  879                 blen = (int)strtol(beg_blen, &end_blen, 10);
  880                 if (*end_blen != ']')
  881                     return(EINVAL);
  882             }
  883             if (count)
  884                 *tp++ = ((value << 4) & 0xff);
  885             cp++;   /* skip ']' */
  886             goto done;
  887         case '/':
  888             afterslash = 1;
  889             break;
  890         default:
  891             if (afterslash) {
  892                 if (!isdigit(c&0xff))
  893                     return(EINVAL);
  894                 if (beg_blen == NULL) {
  895                     
  896                     if (c == '0') {
  897                         /* blen never begings with 0 */
  898                         return(EINVAL);
  899                     }
  900                     beg_blen = cp;
  901                 }
  902             } else {
  903                 if (!isxdigit(c&0xff))
  904                     return(EINVAL);
  905                 value <<= 4;
  906                 value += digitvalue[(int)c];
  907                 count += 4;
  908                 tbcount += 4;
  909                 if (tbcount > 256)
  910                     return(EINVAL);
  911                 if (count == 8) {
  912                     *tp++ = value;
  913                     count = 0;
  914                 }
  915             }
  916             break;
  917         }
  918     }
  919   done:
  920     if (cp >= end || tp >= eom)
  921         return(EMSGSIZE);
  922 
  923     /*
  924      * bit length validation:
  925      * If a <length> is present, the number of digits in the <bit-data>
  926      * MUST be just sufficient to contain the number of bits specified
  927      * by the <length>. If there are insignificant bits in a final
  928      * hexadecimal or octal digit, they MUST be zero.
  929      * RFC 2673, Section 3.2.
  930      */
  931     if (blen > 0) {
  932         int traillen;
  933 
  934         if (((blen + 3) & ~3) != tbcount)
  935             return(EINVAL);
  936         traillen = tbcount - blen; /* between 0 and 3 */
  937         if (((value << (8 - traillen)) & 0xff) != 0)
  938             return(EINVAL);
  939     }
  940     else
  941         blen = tbcount;
  942     if (blen == 256)
  943         blen = 0;
  944 
  945     /* encode the type and the significant bit fields */
  946     **labelp = DNS_LABELTYPE_BITSTRING;
  947     **dst = blen;
  948 
  949     *bp = cp;
  950     *dst = tp;
  951 
  952     return(0);
  953 }
  954 
  955 static int
  956 labellen(const u_char *lp)
  957 {
  958     int bitlen;
  959     u_char l = *lp;
  960 
  961     if ((l & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
  962         /* should be avoided by the caller */
  963         return(-1);
  964     }
  965 
  966     if ((l & NS_CMPRSFLGS) == NS_TYPE_ELT) {
  967         if (l == DNS_LABELTYPE_BITSTRING) {
  968             if ((bitlen = *(lp + 1)) == 0)
  969                 bitlen = 256;
  970             return((bitlen + 7 ) / 8 + 1);
  971         }
  972         return(-1); /* unknwon ELT */
  973     }
  974     return(l);
  975 }