(linenum→info "unix/slp.c:2238")

glibc/2.7/resolv/ns_name.c

    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: #if !defined(_LIBC) && !defined(lint)
   19: static const char rcsid[] = "$BINDId: ns_name.c,v 8.15 2000/03/30 22:53:46 vixie Exp $";
   20: #endif
   21: 
   22: #include <sys/types.h>
   23: 
   24: #include <netinet/in.h>
   25: #include <arpa/nameser.h>
   26: 
   27: #include <ctype.h>
   28: #include <errno.h>
   29: #include <resolv.h>
   30: #include <string.h>
   31: #include <ctype.h>
   32: 
   33: /* Data. */
   34: 
   35: static const char       digits[] = "0123456789";
   36: 
   37: /* Forward. */
   38: 
   39: static int              special(int);
   40: static int              printable(int);
   41: static int              dn_find(const u_char *, const u_char *,
   42:                                 const u_char * const *,
   43:                                 const u_char * const *);
   44: 
   45: /* Public. */
   46: 
   47: /*
   48:  * ns_name_ntop(src, dst, dstsiz)
   49:  *      Convert an encoded domain name to printable ascii as per RFC1035.
   50:  * return:
   51:  *      Number of bytes written to buffer, or -1 (with errno set)
   52:  * notes:
   53:  *      The root is returned as "."
   54:  *      All other domains are returned in non absolute form
   55:  */
   56: int
   57: ns_name_ntop(const u_char *src, char *dst, size_t dstsiz) {
   58:         const u_char *cp;
   59:         char *dn, *eom;
   60:         u_char c;
   61:         u_int n;
   62: 
   63:         cp = src;
   64:         dn = dst;
   65:         eom = dst + dstsiz;
   66: 
   67:         while ((n = *cp++) != 0) {
   68:                 if ((n & NS_CMPRSFLGS) != 0 && n != 0x41) {
   69:                         /* Some kind of compression pointer. */
   70:                         __set_errno (EMSGSIZE);
   71:                         return (-1);
   72:                 }
   73:                 if (dn != dst) {
   74:                         if (dn >= eom) {
   75:                                 __set_errno (EMSGSIZE);
   76:                                 return (-1);
   77:                         }
   78:                         *dn++ = '.';
   79:                 }
   80: 
   81:                 if (n == 0x41) {
   82:                         n = *cp++ / 8;
   83:                         if (dn + n * 2 + 4 >= eom) {
   84:                                 __set_errno (EMSGSIZE);
   85:                                 return (-1);
   86:                         }
   87:                         *dn++ = '\\';
   88:                         *dn++ = '[';
   89:                         *dn++ = 'x';
   90: 
   91:                         while (n-- > 0) {
   92:                                 c = *cp++;
   93:                                 unsigned u = c >> 4;
   94:                                 *dn++ = u > 9 ? 'a' + u - 10 : '0' + u;
   95:                                 u = c & 0xf;
   96:                                 *dn++ = u > 9 ? 'a' + u - 10 : '0' + u;
   97:                         }
   98: 
   99:                         *dn++ = ']';
  100:                         continue;
  101:                 }
  102: 
  103:                 if (dn + n >= eom) {
  104:                         __set_errno (EMSGSIZE);
  105:                         return (-1);
  106:                 }
  107:                 for ((void)NULL; n > 0; n--) {
  108:                         c = *cp++;
  109:                         if (special(c)) {
  110:                                 if (dn + 1 >= eom) {
  111:                                         __set_errno (EMSGSIZE);
  112:                                         return (-1);
  113:                                 }
  114:                                 *dn++ = '\\';
  115:                                 *dn++ = (char)c;
  116:                         } else if (!printable(c)) {
  117:                                 if (dn + 3 >= eom) {
  118:                                         __set_errno (EMSGSIZE);
  119:                                         return (-1);
  120:                                 }
  121:                                 *dn++ = '\\';
  122:                                 *dn++ = digits[c / 100];
  123:                                 *dn++ = digits[(c % 100) / 10];
  124:                                 *dn++ = digits[c % 10];
  125:                         } else {
  126:                                 if (dn >= eom) {
  127:                                         __set_errno (EMSGSIZE);
  128:                                         return (-1);
  129:                                 }
  130:                                 *dn++ = (char)c;
  131:                         }
  132:                 }
  133:         }
  134:         if (dn == dst) {
  135:                 if (dn >= eom) {
  136:                         __set_errno (EMSGSIZE);
  137:                         return (-1);
  138:                 }
  139:                 *dn++ = '.';
  140:         }
  141:         if (dn >= eom) {
  142:                 __set_errno (EMSGSIZE);
  143:                 return (-1);
  144:         }
  145:         *dn++ = '\0';
  146:         return (dn - dst);
  147: }
  148: libresolv_hidden_def (ns_name_ntop)
  149: 
  150: /*
  151:  * ns_name_pton(src, dst, dstsiz)
  152:  *      Convert a ascii string into an encoded domain name as per RFC1035.
  153:  * return:
  154:  *      -1 if it fails
  155:  *      1 if string was fully qualified
  156:  *      0 is string was not fully qualified
  157:  * notes:
  158:  *      Enforces label and domain length limits.
  159:  */
  160: 
  161: int
  162: ns_name_pton(const char *src, u_char *dst, size_t dstsiz) {
  163:         u_char *label, *bp, *eom;
  164:         int c, n, escaped;
  165:         char *cp;
  166: 
  167:         escaped = 0;
  168:         bp = dst;
  169:         eom = dst + dstsiz;
  170:         label = bp++;
  171: 
  172:         while ((c = *src++) != 0) {
  173:                 if (escaped) {
  174:                         if ((cp = strchr(digits, c)) != NULL) {
  175:                                 n = (cp - digits) * 100;
  176:                                 if ((c = *src++) == 0 ||
  177:                                     (cp = strchr(digits, c)) == NULL) {
  178:                                         __set_errno (EMSGSIZE);
  179:                                         return (-1);
  180:                                 }
  181:                                 n += (cp - digits) * 10;
  182:                                 if ((c = *src++) == 0 ||
  183:                                     (cp = strchr(digits, c)) == NULL) {
  184:                                         __set_errno (EMSGSIZE);
  185:                                         return (-1);
  186:                                 }
  187:                                 n += (cp - digits);
  188:                                 if (n > 255) {
  189:                                         __set_errno (EMSGSIZE);
  190:                                         return (-1);
  191:                                 }
  192:                                 c = n;
  193:                         } else if (c == '[' && label == bp - 1 && *src == 'x') {
  194:                                 /* Theoretically we would have to handle \[o
  195:                                    as well but we do not since we do not need
  196:                                    it internally.  */
  197:                                 *label = 0x41;
  198:                                 label = bp++;
  199:                                 ++src;
  200:                                 while (isxdigit (*src)) {
  201:                                         n = *src > '9' ? *src - 'a' + 10 : *src - '0';
  202:                                         ++src;
  203:                                         if (! isxdigit(*src)) {
  204:                                                 __set_errno (EMSGSIZE);
  205:                                                 return (-1);
  206:                                         }
  207:                                         n <<= 4;
  208:                                         n += *src > '9' ? *src - 'a' + 10 : *src - '0';
  209:                                         if (bp + 1 >= eom) {
  210:                                                 __set_errno (EMSGSIZE);
  211:                                                 return (-1);
  212:                                         }
  213:                                         *bp++ = n;
  214:                                         ++src;
  215:                                 }
  216:                                 *label = (bp - label - 1) * 8;
  217:                                 if (*src++ != ']' || *src++ != '.') {
  218:                                         __set_errno (EMSGSIZE);
  219:                                         return (-1);
  220:                                 }
  221:                                 escaped = 0;
  222:                                 label = bp++;
  223:                                 if (bp >= eom) {
  224:                                         __set_errno (EMSGSIZE);
  225:                                         return (-1);
  226:                                 }
  227:                                 continue;
  228:                         }
  229:                         escaped = 0;
  230:                 } else if (c == '\\') {
  231:                         escaped = 1;
  232:                         continue;
  233:                 } else if (c == '.') {
  234:                         c = (bp - label - 1);
  235:                         if ((c & NS_CMPRSFLGS) != 0) {       /* Label too big. */
  236:                                 __set_errno (EMSGSIZE);
  237:                                 return (-1);
  238:                         }
  239:                         if (label >= eom) {
  240:                                 __set_errno (EMSGSIZE);
  241:                                 return (-1);
  242:                         }
  243:                         *label = c;
  244:                         /* Fully qualified ? */
  245:                         if (*src == '\0') {
  246:                                 if (c != 0) {
  247:                                         if (bp >= eom) {
  248:                                                 __set_errno (EMSGSIZE);
  249:                                                 return (-1);
  250:                                         }
  251:                                         *bp++ = '\0';
  252:                                 }
  253:                                 if ((bp - dst) > MAXCDNAME) {
  254:                                         __set_errno (EMSGSIZE);
  255:                                         return (-1);
  256:                                 }
  257:                                 return (1);
  258:                         }
  259:                         if (c == 0 || *src == '.') {
  260:                                 __set_errno (EMSGSIZE);
  261:                                 return (-1);
  262:                         }
  263:                         label = bp++;
  264:                         continue;
  265:                 }
  266:                 if (bp >= eom) {
  267:                         __set_errno (EMSGSIZE);
  268:                         return (-1);
  269:                 }
  270:                 *bp++ = (u_char)c;
  271:         }
  272:         c = (bp - label - 1);
  273:         if ((c & NS_CMPRSFLGS) != 0) {         /* Label too big. */
  274:                 __set_errno (EMSGSIZE);
  275:                 return (-1);
  276:         }
  277:         if (label >= eom) {
  278:                 __set_errno (EMSGSIZE);
  279:                 return (-1);
  280:         }
  281:         *label = c;
  282:         if (c != 0) {
  283:                 if (bp >= eom) {
  284:                         __set_errno (EMSGSIZE);
  285:                         return (-1);
  286:                 }
  287:                 *bp++ = 0;
  288:         }
  289:         if ((bp - dst) > MAXCDNAME) {  /* src too big */
  290:                 __set_errno (EMSGSIZE);
  291:                 return (-1);
  292:         }
  293:         return (0);
  294: }
  295: 
  296: /*
  297:  * ns_name_ntol(src, dst, dstsiz)
  298:  *      Convert a network strings labels into all lowercase.
  299:  * return:
  300:  *      Number of bytes written to buffer, or -1 (with errno set)
  301:  * notes:
  302:  *      Enforces label and domain length limits.
  303:  */
  304: 
  305: int
  306: ns_name_ntol(const u_char *src, u_char *dst, size_t dstsiz) {
  307:         const u_char *cp;
  308:         u_char *dn, *eom;
  309:         u_char c;
  310:         u_int n;
  311: 
  312:         cp = src;
  313:         dn = dst;
  314:         eom = dst + dstsiz;
  315: 
  316:         while ((n = *cp++) != 0) {
  317:                 if ((n & NS_CMPRSFLGS) != 0) {
  318:                         /* Some kind of compression pointer. */
  319:                         __set_errno (EMSGSIZE);
  320:                         return (-1);
  321:                 }
  322:                 *dn++ = n;
  323:                 if (dn + n >= eom) {
  324:                         __set_errno (EMSGSIZE);
  325:                         return (-1);
  326:                 }
  327:                 for ((void)NULL; n > 0; n--) {
  328:                         c = *cp++;
  329:                         if (isupper(c))
  330:                                 *dn++ = tolower(c);
  331:                         else
  332:                                 *dn++ = c;
  333:                 }
  334:         }
  335:         *dn++ = '\0';
  336:         return (dn - dst);
  337: }
  338: 
  339: /*
  340:  * ns_name_unpack(msg, eom, src, dst, dstsiz)
  341:  *      Unpack a domain name from a message, source may be compressed.
  342:  * return:
  343:  *      -1 if it fails, or consumed octets if it succeeds.
  344:  */
  345: int
  346: ns_name_unpack(const u_char *msg, const u_char *eom, const u_char *src,
  347:                u_char *dst, size_t dstsiz)
  348: {
  349:         const u_char *srcp, *dstlim;
  350:         u_char *dstp;
  351:         int n, len, checked;
  352: 
  353:         len = -1;
  354:         checked = 0;
  355:         dstp = dst;
  356:         srcp = src;
  357:         dstlim = dst + dstsiz;
  358:         if (srcp < msg || srcp >= eom) {
  359:                 __set_errno (EMSGSIZE);
  360:                 return (-1);
  361:         }
  362:         /* Fetch next label in domain name. */
  363:         while ((n = *srcp++) != 0) {
  364:                 /* Check for indirection. */
  365:                 switch (n & NS_CMPRSFLGS) {
  366:                 case 0x40:
  367:                         if (n == 0x41) {
  368:                                 if (dstp + 1 >= dstlim) {
  369:                                         __set_errno (EMSGSIZE);
  370:                                         return (-1);
  371:                              }
  372:                                 *dstp++ = 0x41;
  373:                                 n = *srcp++ / 8;
  374:                                 ++checked;
  375:                         } else {
  376:                                 __set_errno (EMSGSIZE);
  377:                                 return (-1);                /* flag error */
  378:                         }
  379:                         /* FALLTHROUGH */
  380:                 case 0:
  381:                         /* Limit checks. */
  382:                         if (dstp + n + 1 >= dstlim || srcp + n >= eom) {
  383:                                 __set_errno (EMSGSIZE);
  384:                                 return (-1);
  385:                         }
  386:                         checked += n + 1;
  387:                         dstp = mempcpy(dstp, srcp - 1, n + 1);
  388:                         srcp += n;
  389:                         break;
  390: 
  391:                 case NS_CMPRSFLGS:
  392:                         if (srcp >= eom) {
  393:                                 __set_errno (EMSGSIZE);
  394:                                 return (-1);
  395:                         }
  396:                         if (len < 0)
  397:                                 len = srcp - src + 1;
  398:                         srcp = msg + (((n & 0x3f) << 8) | (*srcp & 0xff));
  399:                         if (srcp < msg || srcp >= eom) {  /* Out of range. */
  400:                                 __set_errno (EMSGSIZE);
  401:                                 return (-1);
  402:                         }
  403:                         checked += 2;
  404:                         /*
  405:                          * Check for loops in the compressed name;
  406:                          * if we've looked at the whole message,
  407:                          * there must be a loop.
  408:                          */
  409:                         if (checked >= eom - msg) {
  410:                                 __set_errno (EMSGSIZE);
  411:                                 return (-1);
  412:                         }
  413:                         break;
  414: 
  415:                 default:
  416:                         __set_errno (EMSGSIZE);
  417:                         return (-1);                 /* flag error */
  418:                 }
  419:         }
  420:         *dstp = '\0';
  421:         if (len < 0)
  422:                 len = srcp - src;
  423:         return (len);
  424: }
  425: libresolv_hidden_def (ns_name_unpack)
  426: 
  427: /*
  428:  * ns_name_pack(src, dst, dstsiz, dnptrs, lastdnptr)
  429:  *      Pack domain name 'domain' into 'comp_dn'.
  430:  * return:
  431:  *      Size of the compressed name, or -1.
  432:  * notes:
  433:  *      'dnptrs' is an array of pointers to previous compressed names.
  434:  *      dnptrs[0] is a pointer to the beginning of the message. The array
  435:  *      ends with NULL.
  436:  *      'lastdnptr' is a pointer to the end of the array pointed to
  437:  *      by 'dnptrs'.
  438:  * Side effects:
  439:  *      The list of pointers in dnptrs is updated for labels inserted into
  440:  *      the message as we compress the name.  If 'dnptr' is NULL, we don't
  441:  *      try to compress names. If 'lastdnptr' is NULL, we don't update the
  442:  *      list.
  443:  */
  444: int
  445: ns_name_pack(const u_char *src, u_char *dst, int dstsiz,
  446:              const u_char **dnptrs, const u_char **lastdnptr)
  447: {
  448:         u_char *dstp;
  449:         const u_char **cpp, **lpp, *eob, *msg;
  450:         const u_char *srcp;
  451:         int n, l, first = 1;
  452: 
  453:         srcp = src;
  454:         dstp = dst;
  455:         eob = dstp + dstsiz;
  456:         lpp = cpp = NULL;
  457:         if (dnptrs != NULL) {
  458:                 if ((msg = *dnptrs++) != NULL) {
  459:                         for (cpp = dnptrs; *cpp != NULL; cpp++)
  460:                                 (void)NULL;
  461:                         lpp = cpp;   /* end of list to search */
  462:                 }
  463:         } else
  464:                 msg = NULL;
  465: 
  466:         /* make sure the domain we are about to add is legal */
  467:         l = 0;
  468:         do {
  469:                 n = *srcp;
  470:                 if ((n & NS_CMPRSFLGS) != 0 && n != 0x41) {
  471:                         __set_errno (EMSGSIZE);
  472:                         return (-1);
  473:                 }
  474:                 if (n == 0x41)
  475:                         n = *++srcp / 8;
  476:                 l += n + 1;
  477:                 if (l > MAXCDNAME) {
  478:                         __set_errno (EMSGSIZE);
  479:                         return (-1);
  480:                 }
  481:                 srcp += n + 1;
  482:         } while (n != 0);
  483: 
  484:         /* from here on we need to reset compression pointer array on error */
  485:         srcp = src;
  486:         do {
  487:                 /* Look to see if we can use pointers. */
  488:                 n = *srcp;
  489:                 if (n != 0 && n != 0x41 && msg != NULL) {
  490:                         l = dn_find(srcp, msg, (const u_char * const *)dnptrs,
  491:                                     (const u_char * const *)lpp);
  492:                         if (l >= 0) {
  493:                                 if (dstp + 1 >= eob) {
  494:                                         goto cleanup;
  495:                                 }
  496:                                 *dstp++ = (l >> 8) | NS_CMPRSFLGS;
  497:                                 *dstp++ = l % 256;
  498:                                 return (dstp - dst);
  499:                         }
  500:                         /* Not found, save it. */
  501:                         if (lastdnptr != NULL && cpp < lastdnptr - 1 &&
  502:                             (dstp - msg) < 0x4000 && first) {
  503:                                 *cpp++ = dstp;
  504:                                 *cpp = NULL;
  505:                                 first = 0;
  506:                         }
  507:                 }
  508:                 /* copy label to buffer */
  509:                 if ((n & NS_CMPRSFLGS) != 0 && n != 0x41) {           /* Should not happen. */
  510:                         goto cleanup;
  511:                 }
  512:                 if (n == 0x41) {
  513:                         n = *++srcp / 8;
  514:                         if (dstp + 1 >= eob)
  515:                                 goto cleanup;
  516:                         *dstp++ = 0x41;
  517:                 }
  518:                 if (dstp + 1 + n >= eob) {
  519:                         goto cleanup;
  520:                 }
  521:                 memcpy(dstp, srcp, n + 1);
  522:                 srcp += n + 1;
  523:                 dstp += n + 1;
  524:         } while (n != 0);
  525: 
  526:         if (dstp > eob) {
  527: cleanup:
  528:                 if (msg != NULL)
  529:                         *lpp = NULL;
  530:                 __set_errno (EMSGSIZE);
  531:                 return (-1);
  532:         }
  533:         return (dstp - dst);
  534: }
  535: 
  536: /*
  537:  * ns_name_uncompress(msg, eom, src, dst, dstsiz)
  538:  *      Expand compressed domain name to presentation format.
  539:  * return:
  540:  *      Number of bytes read out of `src', or -1 (with errno set).
  541:  * note:
  542:  *      Root domain returns as "." not "".
  543:  */
  544: int
  545: ns_name_uncompress(const u_char *msg, const u_char *eom, const u_char *src,
  546:                    char *dst, size_t dstsiz)
  547: {
  548:         u_char tmp[NS_MAXCDNAME];
  549:         int n;
  550: 
  551:         if ((n = ns_name_unpack(msg, eom, src, tmp, sizeof tmp)) == -1)
  552:                 return (-1);
  553:         if (ns_name_ntop(tmp, dst, dstsiz) == -1)
  554:                 return (-1);
  555:         return (n);
  556: }
  557: 
  558: /*
  559:  * ns_name_compress(src, dst, dstsiz, dnptrs, lastdnptr)
  560:  *      Compress a domain name into wire format, using compression pointers.
  561:  * return:
  562:  *      Number of bytes consumed in `dst' or -1 (with errno set).
  563:  * notes:
  564:  *      'dnptrs' is an array of pointers to previous compressed names.
  565:  *      dnptrs[0] is a pointer to the beginning of the message.
  566:  *      The list ends with NULL.  'lastdnptr' is a pointer to the end of the
  567:  *      array pointed to by 'dnptrs'. Side effect is to update the list of
  568:  *      pointers for labels inserted into the message as we compress the name.
  569:  *      If 'dnptr' is NULL, we don't try to compress names. If 'lastdnptr'
  570:  *      is NULL, we don't update the list.
  571:  */