[BACK]Return to ns_name.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / lib / libc / nameser

Annotation of src/lib/libc/nameser/ns_name.c, Revision 1.6

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

CVSweb <webmaster@jp.NetBSD.org>