Back to index

glibc  2.9
ns_name.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
00003  * Copyright (c) 1996,1999 by Internet Software Consortium.
00004  *
00005  * Permission to use, copy, modify, and distribute this software for any
00006  * purpose with or without fee is hereby granted, provided that the above
00007  * copyright notice and this permission notice appear in all copies.
00008  *
00009  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
00010  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
00011  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
00012  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
00013  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
00014  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
00015  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
00016  */
00017 
00018 #if !defined(_LIBC) && !defined(lint)
00019 static const char rcsid[] = "$BINDId: ns_name.c,v 8.15 2000/03/30 22:53:46 vixie Exp $";
00020 #endif
00021 
00022 #include <sys/types.h>
00023 
00024 #include <netinet/in.h>
00025 #include <arpa/nameser.h>
00026 
00027 #include <errno.h>
00028 #include <resolv.h>
00029 #include <string.h>
00030 #include <ctype.h>
00031 #include <stdlib.h>
00032 #include <limits.h>
00033 
00034 # define SPRINTF(x) ((size_t)sprintf x)
00035 
00036 #define NS_TYPE_ELT                0x40 /*%< EDNS0 extended label type */
00037 #define DNS_LABELTYPE_BITSTRING           0x41
00038 
00039 /* Data. */
00040 
00041 static const char    digits[] = "0123456789";
00042 
00043 static const char digitvalue[256] = {
00044        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*16*/
00045        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*32*/
00046        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*48*/
00047          0,  1,  2,  3,  4,  5,  6,  7,  8,  9, -1, -1, -1, -1, -1, -1, /*64*/
00048        -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*80*/
00049        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*96*/
00050        -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*112*/
00051        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*128*/
00052        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
00053        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
00054        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
00055        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
00056        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
00057        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
00058        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
00059        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*256*/
00060 };
00061 
00062 /* Forward. */
00063 
00064 static int           special(int);
00065 static int           printable(int);
00066 static int           dn_find(const u_char *, const u_char *,
00067                             const u_char * const *,
00068                             const u_char * const *);
00069 static int           encode_bitstring(const char **, const char *,
00070                                     unsigned char **, unsigned char **,
00071                                     unsigned const char *);
00072 static int           labellen(const u_char *);
00073 static int           decode_bitstring(const unsigned char **,
00074                                     char *, const char *);
00075 
00076 /* Public. */
00077 
00078 /*%
00079  *     Convert an encoded domain name to printable ascii as per RFC1035.
00080 
00081  * return:
00082  *\li  Number of bytes written to buffer, or -1 (with errno set)
00083  *
00084  * notes:
00085  *\li  The root is returned as "."
00086  *\li  All other domains are returned in non absolute form
00087  */
00088 int
00089 ns_name_ntop(const u_char *src, char *dst, size_t dstsiz)
00090 {
00091        const u_char *cp;
00092        char *dn, *eom;
00093        u_char c;
00094        u_int n;
00095        int l;
00096 
00097        cp = src;
00098        dn = dst;
00099        eom = dst + dstsiz;
00100 
00101        while ((n = *cp++) != 0) {
00102               if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
00103                      /* Some kind of compression pointer. */
00104                      __set_errno (EMSGSIZE);
00105                      return (-1);
00106               }
00107               if (dn != dst) {
00108                      if (dn >= eom) {
00109                             __set_errno (EMSGSIZE);
00110                             return (-1);
00111                      }
00112                      *dn++ = '.';
00113               }
00114               if ((l = labellen(cp - 1)) < 0) {
00115                      __set_errno (EMSGSIZE);
00116                      return(-1);
00117               }
00118               if (dn + l >= eom) {
00119                      __set_errno (EMSGSIZE);
00120                      return (-1);
00121               }
00122               if ((n & NS_CMPRSFLGS) == NS_TYPE_ELT) {
00123                      int m;
00124 
00125                      if (n != DNS_LABELTYPE_BITSTRING) {
00126                             /* XXX: labellen should reject this case */
00127                             __set_errno (EINVAL);
00128                             return(-1);
00129                      }
00130                      if ((m = decode_bitstring(&cp, dn, eom)) < 0)
00131                      {
00132                             __set_errno (EMSGSIZE);
00133                             return(-1);
00134                      }
00135                      dn += m;
00136                      continue;
00137               }
00138               for ((void)NULL; l > 0; l--) {
00139                      c = *cp++;
00140                      if (special(c)) {
00141                             if (dn + 1 >= eom) {
00142                                    __set_errno (EMSGSIZE);
00143                                    return (-1);
00144                             }
00145                             *dn++ = '\\';
00146                             *dn++ = (char)c;
00147                      } else if (!printable(c)) {
00148                             if (dn + 3 >= eom) {
00149                                    __set_errno (EMSGSIZE);
00150                                    return (-1);
00151                             }
00152                             *dn++ = '\\';
00153                             *dn++ = digits[c / 100];
00154                             *dn++ = digits[(c % 100) / 10];
00155                             *dn++ = digits[c % 10];
00156                      } else {
00157                             if (dn >= eom) {
00158                                    __set_errno (EMSGSIZE);
00159                                    return (-1);
00160                             }
00161                             *dn++ = (char)c;
00162                      }
00163               }
00164        }
00165        if (dn == dst) {
00166               if (dn >= eom) {
00167                      __set_errno (EMSGSIZE);
00168                      return (-1);
00169               }
00170               *dn++ = '.';
00171        }
00172        if (dn >= eom) {
00173               __set_errno (EMSGSIZE);
00174               return (-1);
00175        }
00176        *dn++ = '\0';
00177        return (dn - dst);
00178 }
00179 libresolv_hidden_def (ns_name_ntop)
00180 strong_alias (ns_name_ntop, __ns_name_ntop)
00181 
00182 /*%
00183  *     Convert a ascii string into an encoded domain name as per RFC1035.
00184  *
00185  * return:
00186  *
00187  *\li  -1 if it fails
00188  *\li  1 if string was fully qualified
00189  *\li  0 is string was not fully qualified
00190  *
00191  * notes:
00192  *\li  Enforces label and domain length limits.
00193  */
00194 
00195 int
00196 ns_name_pton(const char *src, u_char *dst, size_t dstsiz)
00197 {
00198        u_char *label, *bp, *eom;
00199        int c, n, escaped, e = 0;
00200        char *cp;
00201 
00202        escaped = 0;
00203        bp = dst;
00204        eom = dst + dstsiz;
00205        label = bp++;
00206 
00207        while ((c = *src++) != 0) {
00208               if (escaped) {
00209                      if (c == '[') { /*%< start a bit string label */
00210                             if ((cp = strchr(src, ']')) == NULL) {
00211                                    __set_errno (EINVAL);
00212                                    return(-1);
00213                             }
00214                             if ((e = encode_bitstring(&src, cp + 2,
00215                                                    &label, &bp, eom))
00216                                 != 0) {
00217                                    __set_errno (e);
00218                                    return(-1);
00219                             }
00220                             escaped = 0;
00221                             label = bp++;
00222                             if ((c = *src++) == 0)
00223                                    goto done;
00224                             else if (c != '.') {
00225                                    __set_errno (EINVAL);
00226                                    return(-1);
00227                             }
00228                             continue;
00229                      }
00230                      else if ((cp = strchr(digits, c)) != NULL) {
00231                             n = (cp - digits) * 100;
00232                             if ((c = *src++) == 0 ||
00233                                 (cp = strchr(digits, c)) == NULL) {
00234                                    __set_errno (EMSGSIZE);
00235                                    return (-1);
00236                             }
00237                             n += (cp - digits) * 10;
00238                             if ((c = *src++) == 0 ||
00239                                 (cp = strchr(digits, c)) == NULL) {
00240                                    __set_errno (EMSGSIZE);
00241                                    return (-1);
00242                             }
00243                             n += (cp - digits);
00244                             if (n > 255) {
00245                                    __set_errno (EMSGSIZE);
00246                                    return (-1);
00247                             }
00248                             c = n;
00249                      }
00250                      escaped = 0;
00251               } else if (c == '\\') {
00252                      escaped = 1;
00253                      continue;
00254               } else if (c == '.') {
00255                      c = (bp - label - 1);
00256                      if ((c & NS_CMPRSFLGS) != 0) {     /*%< Label too big. */
00257                             __set_errno (EMSGSIZE);
00258                             return (-1);
00259                      }
00260                      if (label >= eom) {
00261                             __set_errno (EMSGSIZE);
00262                             return (-1);
00263                      }
00264                      *label = c;
00265                      /* Fully qualified ? */
00266                      if (*src == '\0') {
00267                             if (c != 0) {
00268                                    if (bp >= eom) {
00269                                           __set_errno (EMSGSIZE);
00270                                           return (-1);
00271                                    }
00272                                    *bp++ = '\0';
00273                             }
00274                             if ((bp - dst) > MAXCDNAME) {
00275                                    __set_errno (EMSGSIZE);
00276                                    return (-1);
00277                             }
00278                             return (1);
00279                      }
00280                      if (c == 0 || *src == '.') {
00281                             __set_errno (EMSGSIZE);
00282                             return (-1);
00283                      }
00284                      label = bp++;
00285                      continue;
00286               }
00287               if (bp >= eom) {
00288                      __set_errno (EMSGSIZE);
00289                      return (-1);
00290               }
00291               *bp++ = (u_char)c;
00292        }
00293        c = (bp - label - 1);
00294        if ((c & NS_CMPRSFLGS) != 0) {            /*%< Label too big. */
00295               __set_errno (EMSGSIZE);
00296               return (-1);
00297        }
00298   done:
00299        if (label >= eom) {
00300               __set_errno (EMSGSIZE);
00301               return (-1);
00302        }
00303        *label = c;
00304        if (c != 0) {
00305               if (bp >= eom) {
00306                      __set_errno (EMSGSIZE);
00307                      return (-1);
00308               }
00309               *bp++ = 0;
00310        }
00311        if ((bp - dst) > MAXCDNAME) {      /*%< src too big */
00312               __set_errno (EMSGSIZE);
00313               return (-1);
00314        }
00315        return (0);
00316 }
00317 libresolv_hidden_def (ns_name_pton)
00318 
00319 /*%
00320  *     Convert a network strings labels into all lowercase.
00321  *
00322  * return:
00323  *\li  Number of bytes written to buffer, or -1 (with errno set)
00324  *
00325  * notes:
00326  *\li  Enforces label and domain length limits.
00327  */
00328 
00329 int
00330 ns_name_ntol(const u_char *src, u_char *dst, size_t dstsiz)
00331 {
00332        const u_char *cp;
00333        u_char *dn, *eom;
00334        u_char c;
00335        u_int n;
00336        int l;
00337 
00338        cp = src;
00339        dn = dst;
00340        eom = dst + dstsiz;
00341 
00342        if (dn >= eom) {
00343               __set_errno (EMSGSIZE);
00344               return (-1);
00345        }
00346        while ((n = *cp++) != 0) {
00347               if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
00348                      /* Some kind of compression pointer. */
00349                      __set_errno (EMSGSIZE);
00350                      return (-1);
00351               }
00352               *dn++ = n;
00353               if ((l = labellen(cp - 1)) < 0) {
00354                      __set_errno (EMSGSIZE);
00355                      return (-1);
00356               }
00357               if (dn + l >= eom) {
00358                      __set_errno (EMSGSIZE);
00359                      return (-1);
00360               }
00361               for ((void)NULL; l > 0; l--) {
00362                      c = *cp++;
00363                      if (isupper(c))
00364                             *dn++ = tolower(c);
00365                      else
00366                             *dn++ = c;
00367               }
00368        }
00369        *dn++ = '\0';
00370        return (dn - dst);
00371 }
00372 
00373 /*%
00374  *     Unpack a domain name from a message, source may be compressed.
00375  *
00376  * return:
00377  *\li  -1 if it fails, or consumed octets if it succeeds.
00378  */
00379 int
00380 ns_name_unpack(const u_char *msg, const u_char *eom, const u_char *src,
00381               u_char *dst, size_t dstsiz)
00382 {
00383        const u_char *srcp, *dstlim;
00384        u_char *dstp;
00385        int n, len, checked, l;
00386 
00387        len = -1;
00388        checked = 0;
00389        dstp = dst;
00390        srcp = src;
00391        dstlim = dst + dstsiz;
00392        if (srcp < msg || srcp >= eom) {
00393               __set_errno (EMSGSIZE);
00394               return (-1);
00395        }
00396        /* Fetch next label in domain name. */
00397        while ((n = *srcp++) != 0) {
00398               /* Check for indirection. */
00399               switch (n & NS_CMPRSFLGS) {
00400               case 0:
00401               case NS_TYPE_ELT:
00402                      /* Limit checks. */
00403                      if ((l = labellen(srcp - 1)) < 0) {
00404                             __set_errno (EMSGSIZE);
00405                             return(-1);
00406                      }
00407                      if (dstp + l + 1 >= dstlim || srcp + l >= eom) {
00408                             __set_errno (EMSGSIZE);
00409                             return (-1);
00410                      }
00411                      checked += l + 1;
00412                      *dstp++ = n;
00413                      memcpy(dstp, srcp, l);
00414                      dstp += l;
00415                      srcp += l;
00416                      break;
00417 
00418               case NS_CMPRSFLGS:
00419                      if (srcp >= eom) {
00420                             __set_errno (EMSGSIZE);
00421                             return (-1);
00422                      }
00423                      if (len < 0)
00424                             len = srcp - src + 1;
00425                      srcp = msg + (((n & 0x3f) << 8) | (*srcp & 0xff));
00426                      if (srcp < msg || srcp >= eom) {  /*%< Out of range. */
00427                             __set_errno (EMSGSIZE);
00428                             return (-1);
00429                      }
00430                      checked += 2;
00431                      /*
00432                       * Check for loops in the compressed name;
00433                       * if we've looked at the whole message,
00434                       * there must be a loop.
00435                       */
00436                      if (checked >= eom - msg) {
00437                             __set_errno (EMSGSIZE);
00438                             return (-1);
00439                      }
00440                      break;
00441 
00442               default:
00443                      __set_errno (EMSGSIZE);
00444                      return (-1);                /*%< flag error */
00445               }
00446        }
00447        *dstp = '\0';
00448        if (len < 0)
00449               len = srcp - src;
00450        return (len);
00451 }
00452 libresolv_hidden_def (ns_name_unpack)
00453 strong_alias (ns_name_unpack, __ns_name_unpack)
00454 
00455 /*%
00456  *     Pack domain name 'domain' into 'comp_dn'.
00457  *
00458  * return:
00459  *\li  Size of the compressed name, or -1.
00460  *
00461  * notes:
00462  *\li  'dnptrs' is an array of pointers to previous compressed names.
00463  *\li  dnptrs[0] is a pointer to the beginning of the message. The array
00464  *     ends with NULL.
00465  *\li  'lastdnptr' is a pointer to the end of the array pointed to
00466  *     by 'dnptrs'.
00467  *
00468  * Side effects:
00469  *\li  The list of pointers in dnptrs is updated for labels inserted into
00470  *     the message as we compress the name.  If 'dnptr' is NULL, we don't
00471  *     try to compress names. If 'lastdnptr' is NULL, we don't update the
00472  *     list.
00473  */
00474 int
00475 ns_name_pack(const u_char *src, u_char *dst, int dstsiz,
00476             const u_char **dnptrs, const u_char **lastdnptr)
00477 {
00478        u_char *dstp;
00479        const u_char **cpp, **lpp, *eob, *msg;
00480        const u_char *srcp;
00481        int n, l, first = 1;
00482 
00483        srcp = src;
00484        dstp = dst;
00485        eob = dstp + dstsiz;
00486        lpp = cpp = NULL;
00487        if (dnptrs != NULL) {
00488               if ((msg = *dnptrs++) != NULL) {
00489                      for (cpp = dnptrs; *cpp != NULL; cpp++)
00490                             (void)NULL;
00491                      lpp = cpp;    /*%< end of list to search */
00492               }
00493        } else
00494               msg = NULL;
00495 
00496        /* make sure the domain we are about to add is legal */
00497        l = 0;
00498        do {
00499               int l0;
00500 
00501               n = *srcp;
00502               if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
00503                      __set_errno (EMSGSIZE);
00504                      return (-1);
00505               }
00506               if ((l0 = labellen(srcp)) < 0) {
00507                      __set_errno (EINVAL);
00508                      return(-1);
00509               }
00510               l += l0 + 1;
00511               if (l > MAXCDNAME) {
00512                      __set_errno (EMSGSIZE);
00513                      return (-1);
00514               }
00515               srcp += l0 + 1;
00516        } while (n != 0);
00517 
00518        /* from here on we need to reset compression pointer array on error */
00519        srcp = src;
00520        do {
00521               /* Look to see if we can use pointers. */
00522               n = *srcp;
00523               if (n != 0 && msg != NULL) {
00524                      l = dn_find(srcp, msg, (const u_char * const *)dnptrs,
00525                                 (const u_char * const *)lpp);
00526                      if (l >= 0) {
00527                             if (dstp + 1 >= eob) {
00528                                    goto cleanup;
00529                             }
00530                             *dstp++ = (l >> 8) | NS_CMPRSFLGS;
00531                             *dstp++ = l % 256;
00532                             return (dstp - dst);
00533                      }
00534                      /* Not found, save it. */
00535                      if (lastdnptr != NULL && cpp < lastdnptr - 1 &&
00536                          (dstp - msg) < 0x4000 && first) {
00537                             *cpp++ = dstp;
00538                             *cpp = NULL;
00539                             first = 0;
00540                      }
00541               }
00542               /* copy label to buffer */
00543               if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
00544                      /* Should not happen. */
00545                      goto cleanup;
00546               }
00547               n = labellen(srcp);
00548               if (dstp + 1 + n >= eob) {
00549                      goto cleanup;
00550               }
00551               memcpy(dstp, srcp, n + 1);
00552               srcp += n + 1;
00553               dstp += n + 1;
00554        } while (n != 0);
00555 
00556        if (dstp > eob) {
00557 cleanup:
00558               if (msg != NULL)
00559                      *lpp = NULL;
00560               __set_errno (EMSGSIZE);
00561               return (-1);
00562        }
00563        return (dstp - dst);
00564 }
00565 libresolv_hidden_def (ns_name_pack)
00566 
00567 /*%
00568  *     Expand compressed domain name to presentation format.
00569  *
00570  * return:
00571  *\li  Number of bytes read out of `src', or -1 (with errno set).
00572  *
00573  * note:
00574  *\li  Root domain returns as "." not "".
00575  */
00576 int
00577 ns_name_uncompress(const u_char *msg, const u_char *eom, const u_char *src,
00578                  char *dst, size_t dstsiz)
00579 {
00580        u_char tmp[NS_MAXCDNAME];
00581        int n;
00582 
00583        if ((n = ns_name_unpack(msg, eom, src, tmp, sizeof tmp)) == -1)
00584               return (-1);
00585        if (ns_name_ntop(tmp, dst, dstsiz) == -1)
00586               return (-1);
00587        return (n);
00588 }
00589 libresolv_hidden_def (ns_name_uncompress)
00590 
00591 /*%
00592  *     Compress a domain name into wire format, using compression pointers.
00593  *
00594  * return:
00595  *\li  Number of bytes consumed in `dst' or -1 (with errno set).
00596  *
00597  * notes:
00598  *\li  'dnptrs' is an array of pointers to previous compressed names.
00599  *\li  dnptrs[0] is a pointer to the beginning of the message.
00600  *\li  The list ends with NULL.  'lastdnptr' is a pointer to the end of the
00601  *     array pointed to by 'dnptrs'. Side effect is to update the list of
00602  *     pointers for labels inserted into the message as we compress the name.
00603  *\li  If 'dnptr' is NULL, we don't try to compress names. If 'lastdnptr'
00604  *     is NULL, we don't update the list.
00605  */
00606 int
00607 ns_name_compress(const char *src, u_char *dst, size_t dstsiz,
00608                const u_char **dnptrs, const u_char **lastdnptr)
00609 {
00610        u_char tmp[NS_MAXCDNAME];
00611 
00612        if (ns_name_pton(src, tmp, sizeof tmp) == -1)
00613               return (-1);
00614        return (ns_name_pack(tmp, dst, dstsiz, dnptrs, lastdnptr));
00615 }
00616 libresolv_hidden_def (ns_name_compress)
00617 
00618 /*%
00619  * Reset dnptrs so that there are no active references to pointers at or
00620  * after src.
00621  */
00622 void
00623 ns_name_rollback(const u_char *src, const u_char **dnptrs,
00624                const u_char **lastdnptr)
00625 {
00626        while (dnptrs < lastdnptr && *dnptrs != NULL) {
00627               if (*dnptrs >= src) {
00628                      *dnptrs = NULL;
00629                      break;
00630               }
00631               dnptrs++;
00632        }
00633 }
00634 
00635 /*%
00636  *     Advance *ptrptr to skip over the compressed name it points at.
00637  *
00638  * return:
00639  *\li  0 on success, -1 (with errno set) on failure.
00640  */
00641 int
00642 ns_name_skip(const u_char **ptrptr, const u_char *eom)
00643 {
00644        const u_char *cp;
00645        u_int n;
00646        int l;
00647 
00648        cp = *ptrptr;
00649        while (cp < eom && (n = *cp++) != 0) {
00650               /* Check for indirection. */
00651               switch (n & NS_CMPRSFLGS) {
00652               case 0:                     /*%< normal case, n == len */
00653                      cp += n;
00654                      continue;
00655               case NS_TYPE_ELT: /*%< EDNS0 extended label */
00656                      if ((l = labellen(cp - 1)) < 0) {
00657                             __set_errno (EMSGSIZE);
00658                             return(-1);
00659                      }
00660                      cp += l;
00661                      continue;
00662               case NS_CMPRSFLGS:   /*%< indirection */
00663                      cp++;
00664                      break;
00665               default:             /*%< illegal type */
00666                      __set_errno (EMSGSIZE);
00667                      return (-1);
00668               }
00669               break;
00670        }
00671        if (cp > eom) {
00672               __set_errno (EMSGSIZE);
00673               return (-1);
00674        }
00675        *ptrptr = cp;
00676        return (0);
00677 }
00678 libresolv_hidden_def (ns_name_skip)
00679 
00680 /* Private. */
00681 
00682 /*%
00683  *     Thinking in noninternationalized USASCII (per the DNS spec),
00684  *     is this characted special ("in need of quoting") ?
00685  *
00686  * return:
00687  *\li  boolean.
00688  */
00689 static int
00690 special(int ch) {
00691        switch (ch) {
00692        case 0x22: /*%< '"' */
00693        case 0x2E: /*%< '.' */
00694        case 0x3B: /*%< ';' */
00695        case 0x5C: /*%< '\\' */
00696        case 0x28: /*%< '(' */
00697        case 0x29: /*%< ')' */
00698        /* Special modifiers in zone files. */
00699        case 0x40: /*%< '@' */
00700        case 0x24: /*%< '$' */
00701               return (1);
00702        default:
00703               return (0);
00704        }
00705 }
00706 
00707 /*%
00708  *     Thinking in noninternationalized USASCII (per the DNS spec),
00709  *     is this character visible and not a space when printed ?
00710  *
00711  * return:
00712  *\li  boolean.
00713  */
00714 static int
00715 printable(int ch) {
00716        return (ch > 0x20 && ch < 0x7f);
00717 }
00718 
00719 /*%
00720  *     Thinking in noninternationalized USASCII (per the DNS spec),
00721  *     convert this character to lower case if it's upper case.
00722  */
00723 static int
00724 mklower(int ch) {
00725        if (ch >= 0x41 && ch <= 0x5A)
00726               return (ch + 0x20);
00727        return (ch);
00728 }
00729 
00730 /*%
00731  *     Search for the counted-label name in an array of compressed names.
00732  *
00733  * return:
00734  *\li  offset from msg if found, or -1.
00735  *
00736  * notes:
00737  *\li  dnptrs is the pointer to the first name on the list,
00738  *\li  not the pointer to the start of the message.
00739  */
00740 static int
00741 dn_find(const u_char *domain, const u_char *msg,
00742        const u_char * const *dnptrs,
00743        const u_char * const *lastdnptr)
00744 {
00745        const u_char *dn, *cp, *sp;
00746        const u_char * const *cpp;
00747        u_int n;
00748 
00749        for (cpp = dnptrs; cpp < lastdnptr; cpp++) {
00750               sp = *cpp;
00751               /*
00752                * terminate search on:
00753                * root label
00754                * compression pointer
00755                * unusable offset
00756                */
00757               while (*sp != 0 && (*sp & NS_CMPRSFLGS) == 0 &&
00758                      (sp - msg) < 0x4000) {
00759                      dn = domain;
00760                      cp = sp;
00761                      while ((n = *cp++) != 0) {
00762                             /*
00763                              * check for indirection
00764                              */
00765                             switch (n & NS_CMPRSFLGS) {
00766                             case 0:              /*%< normal case, n == len */
00767                                    n = labellen(cp - 1); /*%< XXX */
00768                                    if (n != *dn++)
00769                                           goto next;
00770 
00771                                    for ((void)NULL; n > 0; n--)
00772                                           if (mklower(*dn++) !=
00773                                               mklower(*cp++))
00774                                                  goto next;
00775                                    /* Is next root for both ? */
00776                                    if (*dn == '\0' && *cp == '\0')
00777                                           return (sp - msg);
00778                                    if (*dn)
00779                                           continue;
00780                                    goto next;
00781                             case NS_CMPRSFLGS:   /*%< indirection */
00782                                    cp = msg + (((n & 0x3f) << 8) | *cp);
00783                                    break;
00784 
00785                             default:      /*%< illegal type */
00786                                    __set_errno (EMSGSIZE);
00787                                    return (-1);
00788                             }
00789                      }
00790   next: ;
00791                      sp += *sp + 1;
00792               }
00793        }
00794        __set_errno (ENOENT);
00795        return (-1);
00796 }
00797 
00798 static int
00799 decode_bitstring(const unsigned char **cpp, char *dn, const char *eom)
00800 {
00801        const unsigned char *cp = *cpp;
00802        char *beg = dn, tc;
00803        int b, blen, plen, i;
00804 
00805        if ((blen = (*cp & 0xff)) == 0)
00806               blen = 256;
00807        plen = (blen + 3) / 4;
00808        plen += sizeof("\\[x/]") + (blen > 99 ? 3 : (blen > 9) ? 2 : 1);
00809        if (dn + plen >= eom)
00810               return(-1);
00811 
00812        cp++;
00813        i = SPRINTF((dn, "\\[x"));
00814        if (i < 0)
00815               return (-1);
00816        dn += i;
00817        for (b = blen; b > 7; b -= 8, cp++) {
00818               i = SPRINTF((dn, "%02x", *cp & 0xff));
00819               if (i < 0)
00820                      return (-1);
00821               dn += i;
00822        }
00823        if (b > 4) {
00824               tc = *cp++;
00825               i = SPRINTF((dn, "%02x", tc & (0xff << (8 - b))));
00826               if (i < 0)
00827                      return (-1);
00828               dn += i;
00829        } else if (b > 0) {
00830               tc = *cp++;
00831               i = SPRINTF((dn, "%1x",
00832                             ((tc >> 4) & 0x0f) & (0x0f << (4 - b))));
00833               if (i < 0)
00834                      return (-1);
00835               dn += i;
00836        }
00837        i = SPRINTF((dn, "/%d]", blen));
00838        if (i < 0)
00839               return (-1);
00840        dn += i;
00841 
00842        *cpp = cp;
00843        return(dn - beg);
00844 }
00845 
00846 static int
00847 encode_bitstring(const char **bp, const char *end, unsigned char **labelp,
00848                unsigned char ** dst, unsigned const char *eom)
00849 {
00850        int afterslash = 0;
00851        const char *cp = *bp;
00852        unsigned char *tp;
00853        char c;
00854        const char *beg_blen;
00855        char *end_blen = NULL;
00856        int value = 0, count = 0, tbcount = 0, blen = 0;
00857 
00858        beg_blen = end_blen = NULL;
00859 
00860        /* a bitstring must contain at least 2 characters */
00861        if (end - cp < 2)
00862               return(EINVAL);
00863 
00864        /* XXX: currently, only hex strings are supported */
00865        if (*cp++ != 'x')
00866               return(EINVAL);
00867        if (!isxdigit((*cp) & 0xff)) /*%< reject '\[x/BLEN]' */
00868               return(EINVAL);
00869 
00870        for (tp = *dst + 1; cp < end && tp < eom; cp++) {
00871               switch((c = *cp)) {
00872               case ']':     /*%< end of the bitstring */
00873                      if (afterslash) {
00874                             if (beg_blen == NULL)
00875                                    return(EINVAL);
00876                             blen = (int)strtol(beg_blen, &end_blen, 10);
00877                             if (*end_blen != ']')
00878                                    return(EINVAL);
00879                      }
00880                      if (count)
00881                             *tp++ = ((value << 4) & 0xff);
00882                      cp++;  /*%< skip ']' */
00883                      goto done;
00884               case '/':
00885                      afterslash = 1;
00886                      break;
00887               default:
00888                      if (afterslash) {
00889                             if (!isdigit(c&0xff))
00890                                    return(EINVAL);
00891                             if (beg_blen == NULL) {
00892 
00893                                    if (c == '0') {
00894                                           /* blen never begings with 0 */
00895                                           return(EINVAL);
00896                                    }
00897                                    beg_blen = cp;
00898                             }
00899                      } else {
00900                             if (!isxdigit(c&0xff))
00901                                    return(EINVAL);
00902                             value <<= 4;
00903                             value += digitvalue[(int)c];
00904                             count += 4;
00905                             tbcount += 4;
00906                             if (tbcount > 256)
00907                                    return(EINVAL);
00908                             if (count == 8) {
00909                                    *tp++ = value;
00910                                    count = 0;
00911                             }
00912                      }
00913                      break;
00914               }
00915        }
00916   done:
00917        if (cp >= end || tp >= eom)
00918               return(EMSGSIZE);
00919 
00920        /*
00921         * bit length validation:
00922         * If a <length> is present, the number of digits in the <bit-data>
00923         * MUST be just sufficient to contain the number of bits specified
00924         * by the <length>. If there are insignificant bits in a final
00925         * hexadecimal or octal digit, they MUST be zero.
00926         * RFC2673, Section 3.2.
00927         */
00928        if (blen > 0) {
00929               int traillen;
00930 
00931               if (((blen + 3) & ~3) != tbcount)
00932                      return(EINVAL);
00933               traillen = tbcount - blen; /*%< between 0 and 3 */
00934               if (((value << (8 - traillen)) & 0xff) != 0)
00935                      return(EINVAL);
00936        }
00937        else
00938               blen = tbcount;
00939        if (blen == 256)
00940               blen = 0;
00941 
00942        /* encode the type and the significant bit fields */
00943        **labelp = DNS_LABELTYPE_BITSTRING;
00944        **dst = blen;
00945 
00946        *bp = cp;
00947        *dst = tp;
00948 
00949        return(0);
00950 }
00951 
00952 static int
00953 labellen(const u_char *lp)
00954 {
00955        int bitlen;
00956        u_char l = *lp;
00957 
00958        if ((l & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
00959               /* should be avoided by the caller */
00960               return(-1);
00961        }
00962 
00963        if ((l & NS_CMPRSFLGS) == NS_TYPE_ELT) {
00964               if (l == DNS_LABELTYPE_BITSTRING) {
00965                      if ((bitlen = *(lp + 1)) == 0)
00966                             bitlen = 256;
00967                      return((bitlen + 7 ) / 8 + 1);
00968               }
00969               return(-1);   /*%< unknwon ELT */
00970        }
00971        return(l);
00972 }
00973