Annotation of embedaddon/dhcp/minires/ns_name.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Copyright (c) 2004,2009 by Internet Systems Consortium, Inc. ("ISC")
! 3: * Copyright (c) 1996-2003 by Internet Software Consortium
! 4: *
! 5: * Permission to use, copy, modify, and distribute this software for any
! 6: * purpose with or without fee is hereby granted, provided that the above
! 7: * copyright notice and this permission notice appear in all copies.
! 8: *
! 9: * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
! 10: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
! 11: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
! 12: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
! 13: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
! 14: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
! 15: * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
! 16: *
! 17: * Internet Systems Consortium, Inc.
! 18: * 950 Charter Street
! 19: * Redwood City, CA 94063
! 20: * <info@isc.org>
! 21: * https://www.isc.org/
! 22: */
! 23:
! 24: #ifndef lint
! 25: static const char rcsid[] = "$Id: ns_name.c,v 1.2.786.3 2009-07-24 22:04:52 sar Exp $";
! 26: #endif
! 27:
! 28: #include <sys/types.h>
! 29:
! 30: #include <netinet/in.h>
! 31: #include <sys/socket.h>
! 32:
! 33: #include <errno.h>
! 34: #include <string.h>
! 35: #include <ctype.h>
! 36:
! 37: #include "minires/minires.h"
! 38: #include "arpa/nameser.h"
! 39:
! 40: /* Data. */
! 41:
! 42: static const char digits[] = "0123456789";
! 43:
! 44: /* Forward. */
! 45:
! 46: static int special(int);
! 47: static int printable(int);
! 48: static int dn_find(const u_char *, const u_char *,
! 49: const u_char * const *,
! 50: const u_char * const *);
! 51:
! 52: /* Public. */
! 53:
! 54: /*
! 55: * ns_name_ntop(src, dst, dstsiz)
! 56: * Convert an encoded domain name to printable ascii as per RFC1035.
! 57: * return:
! 58: * Number of bytes written to buffer, or -1 (with errno set)
! 59: * notes:
! 60: * The root is returned as "."
! 61: * All other domains are returned in non absolute form
! 62: */
! 63: int
! 64: ns_name_ntop(const u_char *src, char *dst, size_t dstsiz) {
! 65: const u_char *cp;
! 66: char *dn, *eom;
! 67: u_char c;
! 68: u_int n;
! 69:
! 70: cp = src;
! 71: dn = dst;
! 72: eom = dst + dstsiz;
! 73:
! 74: if (dn >= eom) {
! 75: errno = EMSGSIZE;
! 76: return (-1);
! 77: }
! 78:
! 79: while ((n = *cp++) != 0) {
! 80: if ((n & NS_CMPRSFLGS) != 0) {
! 81: /* Some kind of compression pointer. */
! 82: errno = EMSGSIZE;
! 83: return (-1);
! 84: }
! 85: if (dn != dst) {
! 86: if (dn >= eom) {
! 87: errno = EMSGSIZE;
! 88: return (-1);
! 89: }
! 90: *dn++ = '.';
! 91: }
! 92: if (dn + n >= eom) {
! 93: errno = EMSGSIZE;
! 94: return (-1);
! 95: }
! 96: for ((void)NULL; n > 0; n--) {
! 97: c = *cp++;
! 98: if (special(c)) {
! 99: if (dn + 1 >= eom) {
! 100: errno = EMSGSIZE;
! 101: return (-1);
! 102: }
! 103: *dn++ = '\\';
! 104: *dn++ = (char)c;
! 105: } else if (!printable(c)) {
! 106: if (dn + 3 >= eom) {
! 107: errno = EMSGSIZE;
! 108: return (-1);
! 109: }
! 110: *dn++ = '\\';
! 111: *dn++ = digits[c / 100];
! 112: *dn++ = digits[(c % 100) / 10];
! 113: *dn++ = digits[c % 10];
! 114: } else {
! 115: if (dn >= eom) {
! 116: errno = EMSGSIZE;
! 117: return (-1);
! 118: }
! 119: *dn++ = (char)c;
! 120: }
! 121: }
! 122: }
! 123: if (dn == dst) {
! 124: if (dn >= eom) {
! 125: errno = EMSGSIZE;
! 126: return (-1);
! 127: }
! 128: *dn++ = '.';
! 129: }
! 130: if (dn >= eom) {
! 131: errno = EMSGSIZE;
! 132: return (-1);
! 133: }
! 134: *dn++ = '\0';
! 135: return (dn - dst);
! 136: }
! 137:
! 138: /*
! 139: * ns_name_pton(src, dst, dstsiz)
! 140: * Convert a ascii string into an encoded domain name as per RFC1035.
! 141: * return:
! 142: * -1 if it fails
! 143: * 1 if string was fully qualified
! 144: * 0 is string was not fully qualified
! 145: * notes:
! 146: * Enforces label and domain length limits.
! 147: */
! 148:
! 149: int
! 150: ns_name_pton(const char *src, u_char *dst, size_t dstsiz) {
! 151: u_char *label, *bp, *eom;
! 152: int c, n, escaped;
! 153: char *cp;
! 154:
! 155: escaped = 0;
! 156: bp = dst;
! 157: eom = dst + dstsiz;
! 158: label = bp++;
! 159:
! 160: while ((c = *src++) != 0) {
! 161: if (escaped) {
! 162: if ((cp = strchr(digits, c)) != NULL) {
! 163: n = (cp - digits) * 100;
! 164: if ((c = *src++) == 0 ||
! 165: (cp = strchr(digits, c)) == NULL) {
! 166: errno = EMSGSIZE;
! 167: return (-1);
! 168: }
! 169: n += (cp - digits) * 10;
! 170: if ((c = *src++) == 0 ||
! 171: (cp = strchr(digits, c)) == NULL) {
! 172: errno = EMSGSIZE;
! 173: return (-1);
! 174: }
! 175: n += (cp - digits);
! 176: if (n > 255) {
! 177: errno = EMSGSIZE;
! 178: return (-1);
! 179: }
! 180: c = n;
! 181: }
! 182: escaped = 0;
! 183: } else if (c == '\\') {
! 184: escaped = 1;
! 185: continue;
! 186: } else if (c == '.') {
! 187: c = (bp - label - 1);
! 188: if ((c & NS_CMPRSFLGS) != 0) { /* Label too big. */
! 189: errno = EMSGSIZE;
! 190: return (-1);
! 191: }
! 192: if (label >= eom) {
! 193: errno = EMSGSIZE;
! 194: return (-1);
! 195: }
! 196: *label = c;
! 197: /* Fully qualified ? */
! 198: if (*src == '\0') {
! 199: if (c != 0) {
! 200: if (bp >= eom) {
! 201: errno = EMSGSIZE;
! 202: return (-1);
! 203: }
! 204: *bp++ = '\0';
! 205: }
! 206: if ((bp - dst) > MAXCDNAME) {
! 207: errno = EMSGSIZE;
! 208: return (-1);
! 209: }
! 210: return (1);
! 211: }
! 212: if (c == 0 || *src == '.') {
! 213: errno = EMSGSIZE;
! 214: return (-1);
! 215: }
! 216: label = bp++;
! 217: continue;
! 218: }
! 219: if (bp >= eom) {
! 220: errno = EMSGSIZE;
! 221: return (-1);
! 222: }
! 223: *bp++ = (u_char)c;
! 224: }
! 225: c = (bp - label - 1);
! 226: if ((c & NS_CMPRSFLGS) != 0) { /* Label too big. */
! 227: errno = EMSGSIZE;
! 228: return (-1);
! 229: }
! 230: if (label >= eom) {
! 231: errno = EMSGSIZE;
! 232: return (-1);
! 233: }
! 234: *label = c;
! 235: if (c != 0) {
! 236: if (bp >= eom) {
! 237: errno = EMSGSIZE;
! 238: return (-1);
! 239: }
! 240: *bp++ = 0;
! 241: }
! 242: if ((bp - dst) > MAXCDNAME) { /* src too big */
! 243: errno = EMSGSIZE;
! 244: return (-1);
! 245: }
! 246: return (0);
! 247: }
! 248:
! 249: /*
! 250: * ns_name_ntol(src, dst, dstsiz)
! 251: * Convert a network strings labels into all lowercase.
! 252: * return:
! 253: * Number of bytes written to buffer, or -1 (with errno set)
! 254: * notes:
! 255: * Enforces label and domain length limits.
! 256: */
! 257:
! 258: int
! 259: ns_name_ntol(const u_char *src, u_char *dst, size_t dstsiz) {
! 260: const u_char *cp;
! 261: u_char *dn, *eom;
! 262: u_char c;
! 263: u_int n;
! 264:
! 265: cp = src;
! 266: dn = dst;
! 267: eom = dst + dstsiz;
! 268:
! 269: if (dn >= eom) {
! 270: errno = EMSGSIZE;
! 271: return (-1);
! 272: }
! 273: while ((n = *cp++) != 0) {
! 274: if ((n & NS_CMPRSFLGS) != 0) {
! 275: /* Some kind of compression pointer. */
! 276: errno = EMSGSIZE;
! 277: return (-1);
! 278: }
! 279: *dn++ = n;
! 280: if (dn + n >= eom) {
! 281: errno = EMSGSIZE;
! 282: return (-1);
! 283: }
! 284: for ((void)NULL; n > 0; n--) {
! 285: c = *cp++;
! 286: if (isupper(c))
! 287: *dn++ = tolower(c);
! 288: else
! 289: *dn++ = c;
! 290: }
! 291: }
! 292: *dn++ = '\0';
! 293: return (dn - dst);
! 294: }
! 295:
! 296: /*
! 297: * ns_name_unpack(msg, eom, src, dst, dstsiz)
! 298: * Unpack a domain name from a message, source may be compressed.
! 299: * return:
! 300: * -1 if it fails, or consumed octets if it succeeds.
! 301: */
! 302: int
! 303: ns_name_unpack(const u_char *msg, const u_char *eom, const u_char *src,
! 304: u_char *dst, size_t dstsiz)
! 305: {
! 306: const u_char *srcp, *dstlim;
! 307: u_char *dstp;
! 308: unsigned n;
! 309: int len;
! 310: int checked;
! 311:
! 312: len = -1;
! 313: checked = 0;
! 314: dstp = dst;
! 315: srcp = src;
! 316: dstlim = dst + dstsiz;
! 317: if (srcp < msg || srcp >= eom) {
! 318: errno = EMSGSIZE;
! 319: return (-1);
! 320: }
! 321: /* Fetch next label in domain name. */
! 322: while ((n = *srcp++) != 0) {
! 323: /* Check for indirection. */
! 324: switch (n & NS_CMPRSFLGS) {
! 325: case 0:
! 326: /* Limit checks. */
! 327: if (dstp + n + 1 >= dstlim || srcp + n >= eom) {
! 328: errno = EMSGSIZE;
! 329: return (-1);
! 330: }
! 331: checked += n + 1;
! 332: *dstp++ = n;
! 333: memcpy(dstp, srcp, n);
! 334: dstp += n;
! 335: srcp += n;
! 336: break;
! 337:
! 338: case NS_CMPRSFLGS:
! 339: if (srcp >= eom) {
! 340: errno = EMSGSIZE;
! 341: return (-1);
! 342: }
! 343: if (len < 0)
! 344: len = srcp - src + 1;
! 345: srcp = msg + (((n & 0x3f) << 8) | (*srcp & 0xff));
! 346: if (srcp < msg || srcp >= eom) { /* Out of range. */
! 347: errno = EMSGSIZE;
! 348: return (-1);
! 349: }
! 350: checked += 2;
! 351: /*
! 352: * Check for loops in the compressed name;
! 353: * if we've looked at the whole message,
! 354: * there must be a loop.
! 355: */
! 356: if (checked >= eom - msg) {
! 357: errno = EMSGSIZE;
! 358: return (-1);
! 359: }
! 360: break;
! 361:
! 362: default:
! 363: errno = EMSGSIZE;
! 364: return (-1); /* flag error */
! 365: }
! 366: }
! 367: *dstp = '\0';
! 368: if (len < 0)
! 369: len = srcp - src;
! 370: return (len);
! 371: }
! 372:
! 373: /*
! 374: * ns_name_pack(src, dst, dstsiz, dnptrs, lastdnptr)
! 375: * Pack domain name 'domain' into 'comp_dn'.
! 376: * return:
! 377: * Size of the compressed name, or -1.
! 378: * notes:
! 379: * 'dnptrs' is an array of pointers to previous compressed names.
! 380: * dnptrs[0] is a pointer to the beginning of the message. The array
! 381: * ends with NULL.
! 382: * 'lastdnptr' is a pointer to the end of the array pointed to
! 383: * by 'dnptrs'.
! 384: * Side effects:
! 385: * The list of pointers in dnptrs is updated for labels inserted into
! 386: * the message as we compress the name. If 'dnptr' is NULL, we don't
! 387: * try to compress names. If 'lastdnptr' is NULL, we don't update the
! 388: * list.
! 389: */
! 390: int
! 391: ns_name_pack(const u_char *src, u_char *dst, unsigned dstsiz,
! 392: const u_char **dnptrs, const u_char **lastdnptr)
! 393: {
! 394: u_char *dstp;
! 395: const u_char **cpp, **lpp, *eob, *msg;
! 396: const u_char *srcp;
! 397: unsigned n;
! 398: int l;
! 399:
! 400: srcp = src;
! 401: dstp = dst;
! 402: eob = dstp + dstsiz;
! 403: lpp = cpp = NULL;
! 404: if (dnptrs != NULL) {
! 405: if ((msg = *dnptrs++) != NULL) {
! 406: for (cpp = dnptrs; *cpp != NULL; cpp++)
! 407: (void)NULL;
! 408: lpp = cpp; /* end of list to search */
! 409: }
! 410: } else
! 411: msg = NULL;
! 412:
! 413: /* make sure the domain we are about to add is legal */
! 414: l = 0;
! 415: do {
! 416: n = *srcp;
! 417: if ((n & NS_CMPRSFLGS) != 0) {
! 418: errno = EMSGSIZE;
! 419: return (-1);
! 420: }
! 421: l += n + 1;
! 422: if (l > MAXCDNAME) {
! 423: errno = EMSGSIZE;
! 424: return (-1);
! 425: }
! 426: srcp += n + 1;
! 427: } while (n != 0);
! 428:
! 429: /* from here on we need to reset compression pointer array on error */
! 430: srcp = src;
! 431: do {
! 432: /* Look to see if we can use pointers. */
! 433: n = *srcp;
! 434: if (n != 0 && msg != NULL) {
! 435: l = dn_find(srcp, msg, (const u_char * const *)dnptrs,
! 436: (const u_char * const *)lpp);
! 437: if (l >= 0) {
! 438: if (dstp + 1 >= eob) {
! 439: goto cleanup;
! 440: }
! 441: *dstp++ = (l >> 8) | NS_CMPRSFLGS;
! 442: *dstp++ = l % 256;
! 443: return (dstp - dst);
! 444: }
! 445: /* Not found, save it. */
! 446: if (lastdnptr != NULL && cpp < lastdnptr - 1 &&
! 447: (dstp - msg) < 0x4000) {
! 448: *cpp++ = dstp;
! 449: *cpp = NULL;
! 450: }
! 451: }
! 452: /* copy label to buffer */
! 453: if (n & NS_CMPRSFLGS) { /* Should not happen. */
! 454: goto cleanup;
! 455: }
! 456: if (dstp + 1 + n >= eob) {
! 457: goto cleanup;
! 458: }
! 459: memcpy(dstp, srcp, n + 1);
! 460: srcp += n + 1;
! 461: dstp += n + 1;
! 462: } while (n != 0);
! 463:
! 464: if (dstp > eob) {
! 465: cleanup:
! 466: if (msg != NULL)
! 467: *lpp = NULL;
! 468: errno = EMSGSIZE;
! 469: return (-1);
! 470: }
! 471: return (dstp - dst);
! 472: }
! 473:
! 474: /*
! 475: * ns_name_uncompress(msg, eom, src, dst, dstsiz)
! 476: * Expand compressed domain name to presentation format.
! 477: * return:
! 478: * Number of bytes read out of `src', or -1 (with errno set).
! 479: * note:
! 480: * Root domain returns as "." not "".
! 481: */
! 482: int
! 483: ns_name_uncompress(const u_char *msg, const u_char *eom, const u_char *src,
! 484: char *dst, size_t dstsiz)
! 485: {
! 486: u_char tmp[NS_MAXCDNAME];
! 487: int n;
! 488:
! 489: if ((n = ns_name_unpack(msg, eom, src, tmp, sizeof tmp)) == -1)
! 490: return (-1);
! 491: if (ns_name_ntop(tmp, dst, dstsiz) == -1)
! 492: return (-1);
! 493: return (n);
! 494: }
! 495:
! 496: /*
! 497: * ns_name_compress(src, dst, dstsiz, dnptrs, lastdnptr)
! 498: * Compress a domain name into wire format, using compression pointers.
! 499: * return:
! 500: * Number of bytes consumed in `dst' or -1 (with errno set).
! 501: * notes:
! 502: * 'dnptrs' is an array of pointers to previous compressed names.
! 503: * dnptrs[0] is a pointer to the beginning of the message.
! 504: * The list ends with NULL. 'lastdnptr' is a pointer to the end of the
! 505: * array pointed to by 'dnptrs'. Side effect is to update the list of
! 506: * pointers for labels inserted into the message as we compress the name.
! 507: * If 'dnptr' is NULL, we don't try to compress names. If 'lastdnptr'
! 508: * is NULL, we don't update the list.
! 509: */
! 510: int
! 511: ns_name_compress(const char *src, u_char *dst, size_t dstsiz,
! 512: const u_char **dnptrs, const u_char **lastdnptr)
! 513: {
! 514: u_char tmp[NS_MAXCDNAME];
! 515:
! 516: if (ns_name_pton(src, tmp, sizeof tmp) == -1)
! 517: return (-1);
! 518: return (ns_name_pack(tmp, dst, dstsiz, dnptrs, lastdnptr));
! 519: }
! 520:
! 521: /*
! 522: * ns_name_skip(ptrptr, eom)
! 523: * Advance *ptrptr to skip over the compressed name it points at.
! 524: * return:
! 525: * 0 on success, -1 (with errno set) on failure.
! 526: */
! 527: int
! 528: ns_name_skip(const u_char **ptrptr, const u_char *eom) {
! 529: const u_char *cp;
! 530: u_int n;
! 531:
! 532: cp = *ptrptr;
! 533: while (cp < eom && (n = *cp++) != 0) {
! 534: /* Check for indirection. */
! 535: switch (n & NS_CMPRSFLGS) {
! 536: case 0: /* normal case, n == len */
! 537: cp += n;
! 538: continue;
! 539: case NS_CMPRSFLGS: /* indirection */
! 540: cp++;
! 541: break;
! 542: default: /* illegal type */
! 543: errno = EMSGSIZE;
! 544: return (-1);
! 545: }
! 546: break;
! 547: }
! 548: if (cp > eom) {
! 549: errno = EMSGSIZE;
! 550: return (-1);
! 551: }
! 552: *ptrptr = cp;
! 553: return (0);
! 554: }
! 555:
! 556: /* Private. */
! 557:
! 558: /*
! 559: * special(ch)
! 560: * Thinking in noninternationalized USASCII (per the DNS spec),
! 561: * is this characted special ("in need of quoting") ?
! 562: * return:
! 563: * boolean.
! 564: */
! 565: static int
! 566: special(int ch) {
! 567: switch (ch) {
! 568: case 0x22: /* '"' */
! 569: case 0x2E: /* '.' */
! 570: case 0x3B: /* ';' */
! 571: case 0x5C: /* '\\' */
! 572: /* Special modifiers in zone files. */
! 573: case 0x40: /* '@' */
! 574: case 0x24: /* '$' */
! 575: return (1);
! 576: default:
! 577: return (0);
! 578: }
! 579: }
! 580:
! 581: /*
! 582: * printable(ch)
! 583: * Thinking in noninternationalized USASCII (per the DNS spec),
! 584: * is this character visible and not a space when printed ?
! 585: * return:
! 586: * boolean.
! 587: */
! 588: static int
! 589: printable(int ch) {
! 590: return (ch > 0x20 && ch < 0x7f);
! 591: }
! 592:
! 593: /*
! 594: * Thinking in noninternationalized USASCII (per the DNS spec),
! 595: * convert this character to lower case if it's upper case.
! 596: */
! 597: static int
! 598: mklower(int ch) {
! 599: if (ch >= 0x41 && ch <= 0x5A)
! 600: return (ch + 0x20);
! 601: return (ch);
! 602: }
! 603:
! 604: /*
! 605: * dn_find(domain, msg, dnptrs, lastdnptr)
! 606: * Search for the counted-label name in an array of compressed names.
! 607: * return:
! 608: * offset from msg if found, or -1.
! 609: * notes:
! 610: * dnptrs is the pointer to the first name on the list,
! 611: * not the pointer to the start of the message.
! 612: */
! 613: static int
! 614: dn_find(const u_char *domain, const u_char *msg,
! 615: const u_char * const *dnptrs,
! 616: const u_char * const *lastdnptr)
! 617: {
! 618: const u_char *dn, *cp, *sp;
! 619: const u_char * const *cpp;
! 620: u_int n;
! 621:
! 622: for (cpp = dnptrs; cpp < lastdnptr; cpp++) {
! 623: dn = domain;
! 624: sp = cp = *cpp;
! 625: while ((n = *cp++) != 0) {
! 626: /*
! 627: * check for indirection
! 628: */
! 629: switch (n & NS_CMPRSFLGS) {
! 630: case 0: /* normal case, n == len */
! 631: if (n != *dn++)
! 632: goto next;
! 633: for ((void)NULL; n > 0; n--)
! 634: if (mklower(*dn++) != mklower(*cp++))
! 635: goto next;
! 636: /* Is next root for both ? */
! 637: if (*dn == '\0' && *cp == '\0')
! 638: return (sp - msg);
! 639: if (*dn)
! 640: continue;
! 641: goto next;
! 642:
! 643: case NS_CMPRSFLGS: /* indirection */
! 644: cp = msg + (((n & 0x3f) << 8) | *cp);
! 645: break;
! 646:
! 647: default: /* illegal type */
! 648: errno = EMSGSIZE;
! 649: return (-1);
! 650: }
! 651: }
! 652: next: ;
! 653: }
! 654: errno = ENOENT;
! 655: return (-1);
! 656: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>