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