__ns_name_uncompress.c

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

Generated on Tue Nov 4 13:27:39 2008 for libspf2 by  doxygen 1.5.4