Annotation of src/lib/libc/nameser/ns_name.c, Revision 1.6.6.2
1.6.6.2 ! christos 1: /* $NetBSD: ns_name.c,v 1.6 2008/06/21 20:41:48 christos Exp $ */
! 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:
! 20: #include <sys/cdefs.h>
! 21: #ifndef lint
! 22: #ifdef notdef
! 23: static const char rcsid[] = "Id: ns_name.c,v 1.10 2005/04/27 04:56:40 sra Exp";
! 24: #else
! 25: __RCSID("$NetBSD: ns_name.c,v 1.6 2008/06/21 20:41:48 christos Exp $");
! 26: #endif
! 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:
! 51: #define NS_TYPE_ELT 0x40 /*%< EDNS0 extended label type */
! 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 *,
! 85: unsigned char **, unsigned char **,
! 86: unsigned const char *);
! 87: static int labellen(const u_char *);
! 88: static int decode_bitstring(const unsigned char **,
! 89: char *, const char *);
! 90:
! 91: /* Public. */
! 92:
! 93: /*%
! 94: * Convert an encoded domain name to printable ascii as per RFC1035.
! 95:
! 96: * return:
! 97: *\li Number of bytes written to buffer, or -1 (with errno set)
! 98: *
! 99: * notes:
! 100: *\li The root is returned as "."
! 101: *\li All other domains are returned in non absolute form
! 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) {
! 130: errno = EMSGSIZE; /*%< XXX */
! 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: }
! 145: if ((m = decode_bitstring(&cp, dn, eom)) < 0)
! 146: {
! 147: errno = EMSGSIZE;
! 148: return(-1);
! 149: }
! 150: dn += m;
! 151: continue;
! 152: }
! 153: for (; l > 0; l--) {
! 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:
! 195: /*%
! 196: * Convert a ascii string into an encoded domain name as per RFC1035.
! 197: *
! 198: * return:
! 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: *
! 204: * notes:
! 205: *\li Enforces label and domain length limits.
! 206: */
! 207:
! 208: int
! 209: ns_name_pton(const char *src, u_char *dst, size_t dstsiz)
! 210: {
! 211: u_char *label, *bp, *eom;
! 212: int c, n, escaped, e = 0;
! 213: char *cp;
! 214:
! 215: escaped = 0;
! 216: bp = dst;
! 217: eom = dst + dstsiz;
! 218: label = bp++;
! 219:
! 220: while ((c = *src++) != 0) {
! 221: if (escaped) {
! 222: if (c == '[') { /*%< start a bit string label */
! 223: if ((cp = strchr(src, ']')) == NULL) {
! 224: errno = EINVAL; /*%< ??? */
! 225: return(-1);
! 226: }
! 227: if ((e = encode_bitsring(&src, cp + 2,
! 228: &label, &bp, eom))
! 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);
! 269: if ((c & NS_CMPRSFLGS) != 0) { /*%< Label too big. */
! 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);
! 307: if ((c & NS_CMPRSFLGS) != 0) { /*%< Label too big. */
! 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: }
! 324: if ((bp - dst) > MAXCDNAME) { /*%< src too big */
! 325: errno = EMSGSIZE;
! 326: return (-1);
! 327: }
! 328: return (0);
! 329: }
! 330:
! 331: /*%
! 332: * Convert a network strings labels into all lowercase.
! 333: *
! 334: * return:
! 335: *\li Number of bytes written to buffer, or -1 (with errno set)
! 336: *
! 337: * notes:
! 338: *\li Enforces label and domain length limits.
! 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: }
! 373: for (; l > 0; l--) {
! 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:
! 385: /*%
! 386: * Unpack a domain name from a message, source may be compressed.
! 387: *
! 388: * return:
! 389: *\li -1 if it fails, or consumed octets if it succeeds.
! 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;
! 425: memcpy(dstp, srcp, (size_t)l);
! 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));
! 438: if (srcp < msg || srcp >= eom) { /*%< Out of range. */
! 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;
! 456: return (-1); /*%< flag error */
! 457: }
! 458: }
! 459: *dstp = '\0';
! 460: if (len < 0)
! 461: len = srcp - src;
! 462: return (len);
! 463: }
! 464:
! 465: /*%
! 466: * Pack domain name 'domain' into 'comp_dn'.
! 467: *
! 468: * return:
! 469: *\li Size of the compressed name, or -1.
! 470: *
! 471: * notes:
! 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
! 474: * ends with NULL.
! 475: *\li 'lastdnptr' is a pointer to the end of the array pointed to
! 476: * by 'dnptrs'.
! 477: *
! 478: * Side effects:
! 479: *\li The list of pointers in dnptrs is updated for labels inserted into
! 480: * the message as we compress the name. If 'dnptr' is NULL, we don't
! 481: * try to compress names. If 'lastdnptr' is NULL, we don't update the
! 482: * list.
! 483: */
! 484: int
! 485: ns_name_pack(const u_char *src, u_char *dst, int dstsiz,
! 486: const u_char **dnptrs, const u_char **lastdnptr)
! 487: {
! 488: u_char *dstp;
! 489: const u_char **cpp, **lpp, *eob, *msg;
! 490: const u_char *srcp;
! 491: int n, l, first = 1;
! 492:
! 493: srcp = src;
! 494: dstp = dst;
! 495: eob = dstp + dstsiz;
! 496: lpp = cpp = NULL;
! 497: if (dnptrs != NULL) {
! 498: if ((msg = *dnptrs++) != NULL) {
! 499: for (cpp = dnptrs; *cpp != NULL; cpp++)
! 500: continue;
! 501: lpp = cpp; /*%< end of list to search */
! 502: }
! 503: } else
! 504: msg = NULL;
! 505:
! 506: /* make sure the domain we are about to add is legal */
! 507: l = 0;
! 508: do {
! 509: int l0;
! 510:
! 511: n = *srcp;
! 512: if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
! 513: errno = EMSGSIZE;
! 514: return (-1);
! 515: }
! 516: if ((l0 = labellen(srcp)) < 0) {
! 517: errno = EINVAL;
! 518: return(-1);
! 519: }
! 520: l += l0 + 1;
! 521: if (l > MAXCDNAME) {
! 522: errno = EMSGSIZE;
! 523: return (-1);
! 524: }
! 525: srcp += l0 + 1;
! 526: } while (n != 0);
! 527:
! 528: /* from here on we need to reset compression pointer array on error */
! 529: srcp = src;
! 530: do {
! 531: /* Look to see if we can use pointers. */
! 532: n = *srcp;
! 533: if (n != 0 && msg != NULL) {
! 534: l = dn_find(srcp, msg, (const u_char * const *)dnptrs,
! 535: (const u_char * const *)lpp);
! 536: if (l >= 0) {
! 537: if (dstp + 1 >= eob) {
! 538: goto cleanup;
! 539: }
! 540: *dstp++ = ((u_int32_t)l >> 8) | NS_CMPRSFLGS;
! 541: *dstp++ = l % 256;
! 542: return (dstp - dst);
! 543: }
! 544: /* Not found, save it. */
! 545: if (lastdnptr != NULL && cpp < lastdnptr - 1 &&
! 546: (dstp - msg) < 0x4000 && first) {
! 547: *cpp++ = dstp;
! 548: *cpp = NULL;
! 549: first = 0;
! 550: }
! 551: }
! 552: /* copy label to buffer */
! 553: if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
! 554: /* Should not happen. */
! 555: goto cleanup;
! 556: }
! 557: n = labellen(srcp);
! 558: if (dstp + 1 + n >= eob) {
! 559: goto cleanup;
! 560: }
! 561: memcpy(dstp, srcp, (size_t)(n + 1));
! 562: srcp += n + 1;
! 563: dstp += n + 1;
! 564: } while (n != 0);
! 565:
! 566: if (dstp > eob) {
! 567: cleanup:
! 568: if (msg != NULL)
! 569: *lpp = NULL;
! 570: errno = EMSGSIZE;
! 571: return (-1);
! 572: }
! 573: return (dstp - dst);
! 574: }
! 575:
! 576: /*%
! 577: * Expand compressed domain name to presentation format.
! 578: *
! 579: * return:
! 580: *\li Number of bytes read out of `src', or -1 (with errno set).
! 581: *
! 582: * note:
! 583: *\li Root domain returns as "." not "".
! 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:
! 599: /*%
! 600: * Compress a domain name into wire format, using compression pointers.
! 601: *
! 602: * return:
! 603: *\li Number of bytes consumed in `dst' or -1 (with errno set).
! 604: *
! 605: * notes:
! 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
! 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.
! 611: *\li If 'dnptr' is NULL, we don't try to compress names. If 'lastdnptr'
! 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);
! 622: return (ns_name_pack(tmp, dst, (int)dstsiz, dnptrs, lastdnptr));
! 623: }
! 624:
! 625: /*%
! 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:
! 642: /*%
! 643: * Advance *ptrptr to skip over the compressed name it points at.
! 644: *
! 645: * return:
! 646: *\li 0 on success, -1 (with errno set) on failure.
! 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) {
! 659: case 0: /*%< normal case, n == len */
! 660: cp += n;
! 661: continue;
! 662: case NS_TYPE_ELT: /*%< EDNS0 extended label */
! 663: if ((l = labellen(cp - 1)) < 0) {
! 664: errno = EMSGSIZE; /*%< XXX */
! 665: return(-1);
! 666: }
! 667: cp += l;
! 668: continue;
! 669: case NS_CMPRSFLGS: /*%< indirection */
! 670: cp++;
! 671: break;
! 672: default: /*%< illegal type */
! 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:
! 688: /*%
! 689: * Thinking in noninternationalized USASCII (per the DNS spec),
! 690: * is this characted special ("in need of quoting") ?
! 691: *
! 692: * return:
! 693: *\li boolean.
! 694: */
! 695: static int
! 696: special(int ch) {
! 697: switch (ch) {
! 698: case 0x22: /*%< '"' */
! 699: case 0x2E: /*%< '.' */
! 700: case 0x3B: /*%< ';' */
! 701: case 0x5C: /*%< '\\' */
! 702: case 0x28: /*%< '(' */
! 703: case 0x29: /*%< ')' */
! 704: /* Special modifiers in zone files. */
! 705: case 0x40: /*%< '@' */
! 706: case 0x24: /*%< '$' */
! 707: return (1);
! 708: default:
! 709: return (0);
! 710: }
! 711: }
! 712:
! 713: /*%
! 714: * Thinking in noninternationalized USASCII (per the DNS spec),
! 715: * is this character visible and not a space when printed ?
! 716: *
! 717: * return:
! 718: *\li boolean.
! 719: */
! 720: static int
! 721: printable(int ch) {
! 722: return (ch > 0x20 && ch < 0x7f);
! 723: }
! 724:
! 725: /*%
! 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:
! 736: /*%
! 737: * Search for the counted-label name in an array of compressed names.
! 738: *
! 739: * return:
! 740: *\li offset from msg if found, or -1.
! 741: *
! 742: * notes:
! 743: *\li dnptrs is the pointer to the first name on the list,
! 744: *\li not the pointer to the start of the message.
! 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) {
! 772: case 0: /*%< normal case, n == len */
! 773: n = labellen(cp - 1); /*%< XXX */
! 774: if (n != *dn++)
! 775: goto next;
! 776:
! 777: for (; n > 0; n--)
! 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;
! 787: case NS_CMPRSFLGS: /*%< indirection */
! 788: cp = msg + (((n & 0x3f) << 8) | *cp);
! 789: break;
! 790:
! 791: default: /*%< illegal type */
! 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
! 805: decode_bitstring(const unsigned char **cpp, char *dn, const char *eom)
! 806: {
! 807: const unsigned char *cp = *cpp;
! 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",
! 838: (((u_int32_t)tc >> 4) & 0x0f) & (0x0f << (4 - b))));
! 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
! 853: encode_bitsring(const char **bp, const char *end, unsigned char **labelp,
! 854: unsigned char ** dst, unsigned const char *eom)
! 855: {
! 856: int afterslash = 0;
! 857: const char *cp = *bp;
! 858: unsigned char *tp;
! 859: char c;
! 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);
! 873: if (!isxdigit((*cp) & 0xff)) /*%< reject '\[x/BLEN]' */
! 874: return(EINVAL);
! 875:
! 876: for (tp = *dst + 1; cp < end && tp < eom; cp++) {
! 877: switch((c = *cp)) {
! 878: case ']': /*%< end of the bitstring */
! 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);
! 888: cp++; /*%< skip ']' */
! 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.
! 932: * RFC2673, Section 3.2.
! 933: */
! 934: if (blen > 0) {
! 935: int traillen;
! 936:
! 937: if (((blen + 3) & ~3) != tbcount)
! 938: return(EINVAL);
! 939: traillen = tbcount - blen; /*%< between 0 and 3 */
! 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: }
! 975: return(-1); /*%< unknwon ELT */
! 976: }
! 977: return(l);
! 978: }
! 979:
! 980: /*! \file */
CVSweb <webmaster@jp.NetBSD.org>