1 /* 2 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") 3 * Copyright (c) 1996,1999 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 18 #ifndef lint 19 static const char rcsid[] = "$Id: ns_name.c,v 1.8.18.2 2005/04/27 05:01:08 sra Exp $"; 20 #endif 21 22 #include "port_before.h" 23 24 #include <sys/types.h> 25 26 #include <netinet/in.h> 27 #include <arpa/nameser.h> 28 29 #include <errno.h> 30 #include <resolv.h> 31 #include <string.h> 32 #include <ctype.h> 33 #include <stdlib.h> 34 #include <limits.h> 35 36 #include "port_after.h" 37 38 #ifdef SPRINTF_CHAR 39 # define SPRINTF(x) strlen(sprintf/**/x) 40 #else 41 # define SPRINTF(x) ((size_t)sprintf x) 42 #endif 43 44 #define NS_TYPE_ELT 0x40 /*%< EDNS0 extended label type */ 45 #define DNS_LABELTYPE_BITSTRING 0x41 46 47 /* Data. */ 48 49 static const char digits[] = "0123456789"; 50 51 static const char digitvalue[256] = { 52 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*16*/ 53 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*32*/ 54 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*48*/ 55 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, /*64*/ 56 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*80*/ 57 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*96*/ 58 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*112*/ 59 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*128*/ 60 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 61 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 63 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 64 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 65 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 66 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 67 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*256*/ 68 }; 69 70 /* Forward. */ 71 72 static int special(int); 73 static int printable(int); 74 static int dn_find(const u_char *, const u_char *, 75 const u_char * const *, 76 const u_char * const *); 77 static int encode_bitsring(const char **, const char *, 78 unsigned char **, unsigned char **, 79 unsigned const char *); 80 static int labellen(const u_char *); 81 static int decode_bitstring(const unsigned char **, 82 char *, const char *); 83 84 /* Public. */ 85 86 /*% 87 * Convert an encoded domain name to printable ascii as per RFC1035. 88 89 * return: 90 *\li Number of bytes written to buffer, or -1 (with errno set) 91 * 92 * notes: 93 *\li The root is returned as "." 94 *\li All other domains are returned in non absolute form 95 */ 96 int 97 ns_name_ntop(const u_char *src, char *dst, size_t dstsiz) 98 { 99 const u_char *cp; 100 char *dn, *eom; 101 u_char c; 102 u_int n; 103 int l; 104 105 cp = src; 106 dn = dst; 107 eom = dst + dstsiz; 108 109 while ((n = *cp++) != 0) { 110 if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) { 111 /* Some kind of compression pointer. */ 112 errno = EMSGSIZE; 113 return (-1); 114 } 115 if (dn != dst) { 116 if (dn >= eom) { 117 errno = EMSGSIZE; 118 return (-1); 119 } 120 *dn++ = '.'; 121 } 122 if ((l = labellen(cp - 1)) < 0) { 123 errno = EMSGSIZE; /*%< XXX */ 124 return(-1); 125 } 126 if (dn + l >= eom) { 127 errno = EMSGSIZE; 128 return (-1); 129 } 130 if ((n & NS_CMPRSFLGS) == NS_TYPE_ELT) { 131 int m; 132 133 if (n != DNS_LABELTYPE_BITSTRING) { 134 /* XXX: labellen should reject this case */ 135 errno = EINVAL; 136 return(-1); 137 } 138 if ((m = decode_bitstring(&cp, dn, eom)) < 0) 139 { 140 errno = EMSGSIZE; 141 return(-1); 142 } 143 dn += m; 144 continue; 145 } 146 for ((void)NULL; l > 0; l--) { 147 c = *cp++; 148 if (special(c)) { 149 if (dn + 1 >= eom) { 150 errno = EMSGSIZE; 151 return (-1); 152 } 153 *dn++ = '\\'; 154 *dn++ = (char)c; 155 } else if (!printable(c)) { 156 if (dn + 3 >= eom) { 157 errno = EMSGSIZE; 158 return (-1); 159 } 160 *dn++ = '\\'; 161 *dn++ = digits[c / 100]; 162 *dn++ = digits[(c % 100) / 10]; 163 *dn++ = digits[c % 10]; 164 } else { 165 if (dn >= eom) { 166 errno = EMSGSIZE; 167 return (-1); 168 } 169 *dn++ = (char)c; 170 } 171 } 172 } 173 if (dn == dst) { 174 if (dn >= eom) { 175 errno = EMSGSIZE; 176 return (-1); 177 } 178 *dn++ = '.'; 179 } 180 if (dn >= eom) { 181 errno = EMSGSIZE; 182 return (-1); 183 } 184 *dn++ = '\0'; 185 return (dn - dst); 186 } 187 188 /*% 189 * Convert a ascii string into an encoded domain name as per RFC1035. 190 * 191 * return: 192 * 193 *\li -1 if it fails 194 *\li 1 if string was fully qualified 195 *\li 0 is string was not fully qualified 196 * 197 * notes: 198 *\li Enforces label and domain length limits. 199 */ 200 201 int 202 ns_name_pton(const char *src, u_char *dst, size_t dstsiz) 203 { 204 u_char *label, *bp, *eom; 205 int c, n, escaped, e = 0; 206 char *cp; 207 208 escaped = 0; 209 bp = dst; 210 eom = dst + dstsiz; 211 label = bp++; 212 213 while ((c = *src++) != 0) { 214 if (escaped) { 215 if (c == '[') { /*%< start a bit string label */ 216 if ((cp = strchr(src, ']')) == NULL) { 217 errno = EINVAL; /*%< ??? */ 218 return(-1); 219 } 220 if ((e = encode_bitsring(&src, cp + 2, 221 &label, &bp, eom)) 222 != 0) { 223 errno = e; 224 return(-1); 225 } 226 escaped = 0; 227 label = bp++; 228 if ((c = *src++) == 0) 229 goto done; 230 else if (c != '.') { 231 errno = EINVAL; 232 return(-1); 233 } 234 continue; 235 } 236 else if ((cp = strchr(digits, c)) != NULL) { 237 n = (cp - digits) * 100; 238 if ((c = *src++) == 0 || 239 (cp = strchr(digits, c)) == NULL) { 240 errno = EMSGSIZE; 241 return (-1); 242 } 243 n += (cp - digits) * 10; 244 if ((c = *src++) == 0 || 245 (cp = strchr(digits, c)) == NULL) { 246 errno = EMSGSIZE; 247 return (-1); 248 } 249 n += (cp - digits); 250 if (n > 255) { 251 errno = EMSGSIZE; 252 return (-1); 253 } 254 c = n; 255 } 256 escaped = 0; 257 } else if (c == '\\') { 258 escaped = 1; 259 continue; 260 } else if (c == '.') { 261 c = (bp - label - 1); 262 if ((c & NS_CMPRSFLGS) != 0) { /*%< Label too big. */ 263 errno = EMSGSIZE; 264 return (-1); 265 } 266 if (label >= eom) { 267 errno = EMSGSIZE; 268 return (-1); 269 } 270 *label = c; 271 /* Fully qualified ? */ 272 if (*src == '\0') { 273 if (c != 0) { 274 if (bp >= eom) { 275 errno = EMSGSIZE; 276 return (-1); 277 } 278 *bp++ = '\0'; 279 } 280 if ((bp - dst) > MAXCDNAME) { 281 errno = EMSGSIZE; 282 return (-1); 283 } 284 return (1); 285 } 286 if (c == 0 || *src == '.') { 287 errno = EMSGSIZE; 288 return (-1); 289 } 290 label = bp++; 291 continue; 292 } 293 if (bp >= eom) { 294 errno = EMSGSIZE; 295 return (-1); 296 } 297 *bp++ = (u_char)c; 298 } 299 c = (bp - label - 1); 300 if ((c & NS_CMPRSFLGS) != 0) { /*%< Label too big. */ 301 errno = EMSGSIZE; 302 return (-1); 303 } 304 done: 305 if (label >= eom) { 306 errno = EMSGSIZE; 307 return (-1); 308 } 309 *label = c; 310 if (c != 0) { 311 if (bp >= eom) { 312 errno = EMSGSIZE; 313 return (-1); 314 } 315 *bp++ = 0; 316 } 317 if ((bp - dst) > MAXCDNAME) { /*%< src too big */ 318 errno = EMSGSIZE; 319 return (-1); 320 } 321 return (0); 322 } 323 324 /*% 325 * Convert a network strings labels into all lowercase. 326 * 327 * return: 328 *\li Number of bytes written to buffer, or -1 (with errno set) 329 * 330 * notes: 331 *\li Enforces label and domain length limits. 332 */ 333 334 int 335 ns_name_ntol(const u_char *src, u_char *dst, size_t dstsiz) 336 { 337 const u_char *cp; 338 u_char *dn, *eom; 339 u_char c; 340 u_int n; 341 int l; 342 343 cp = src; 344 dn = dst; 345 eom = dst + dstsiz; 346 347 if (dn >= eom) { 348 errno = EMSGSIZE; 349 return (-1); 350 } 351 while ((n = *cp++) != 0) { 352 if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) { 353 /* Some kind of compression pointer. */ 354 errno = EMSGSIZE; 355 return (-1); 356 } 357 *dn++ = n; 358 if ((l = labellen(cp - 1)) < 0) { 359 errno = EMSGSIZE; 360 return (-1); 361 } 362 if (dn + l >= eom) { 363 errno = EMSGSIZE; 364 return (-1); 365 } 366 for ((void)NULL; l > 0; l--) { 367 c = *cp++; 368 if (isupper(c)) 369 *dn++ = tolower(c); 370 else 371 *dn++ = c; 372 } 373 } 374 *dn++ = '\0'; 375 return (dn - dst); 376 } 377 378 /*% 379 * Unpack a domain name from a message, source may be compressed. 380 * 381 * return: 382 *\li -1 if it fails, or consumed octets if it succeeds. 383 */ 384 int 385 ns_name_unpack(const u_char *msg, const u_char *eom, const u_char *src, 386 u_char *dst, size_t dstsiz) 387 { 388 const u_char *srcp, *dstlim; 389 u_char *dstp; 390 int n, len, checked, l; 391 392 len = -1; 393 checked = 0; 394 dstp = dst; 395 srcp = src; 396 dstlim = dst + dstsiz; 397 if (srcp < msg || srcp >= eom) { 398 errno = EMSGSIZE; 399 return (-1); 400 } 401 /* Fetch next label in domain name. */ 402 while ((n = *srcp++) != 0) { 403 /* Check for indirection. */ 404 switch (n & NS_CMPRSFLGS) { 405 case 0: 406 case NS_TYPE_ELT: 407 /* Limit checks. */ 408 if ((l = labellen(srcp - 1)) < 0) { 409 errno = EMSGSIZE; 410 return(-1); 411 } 412 if (dstp + l + 1 >= dstlim || srcp + l >= eom) { 413 errno = EMSGSIZE; 414 return (-1); 415 } 416 checked += l + 1; 417 *dstp++ = n; 418 memcpy(dstp, srcp, l); 419 dstp += l; 420 srcp += l; 421 break; 422 423 case NS_CMPRSFLGS: 424 if (srcp >= eom) { 425 errno = EMSGSIZE; 426 return (-1); 427 } 428 if (len < 0) 429 len = srcp - src + 1; 430 srcp = msg + (((n & 0x3f) << 8) | (*srcp & 0xff)); 431 if (srcp < msg || srcp >= eom) { /*%< Out of range. */ 432 errno = EMSGSIZE; 433 return (-1); 434 } 435 checked += 2; 436 /* 437 * Check for loops in the compressed name; 438 * if we've looked at the whole message, 439 * there must be a loop. 440 */ 441 if (checked >= eom - msg) { 442 errno = EMSGSIZE; 443 return (-1); 444 } 445 break; 446 447 default: 448 errno = EMSGSIZE; 449 return (-1); /*%< flag error */ 450 } 451 } 452 *dstp = '\0'; 453 if (len < 0) 454 len = srcp - src; 455 return (len); 456 } 457 458 /*% 459 * Pack domain name 'domain' into 'comp_dn'. 460 * 461 * return: 462 *\li Size of the compressed name, or -1. 463 * 464 * notes: 465 *\li 'dnptrs' is an array of pointers to previous compressed names. 466 *\li dnptrs[0] is a pointer to the beginning of the message. The array 467 * ends with NULL. 468 *\li 'lastdnptr' is a pointer to the end of the array pointed to 469 * by 'dnptrs'. 470 * 471 * Side effects: 472 *\li The list of pointers in dnptrs is updated for labels inserted into 473 * the message as we compress the name. If 'dnptr' is NULL, we don't 474 * try to compress names. If 'lastdnptr' is NULL, we don't update the 475 * list. 476 */ 477 int 478 ns_name_pack(const u_char *src, u_char *dst, int dstsiz, 479 const u_char **dnptrs, const u_char **lastdnptr) 480 { 481 u_char *dstp; 482 const u_char **cpp, **lpp, *eob, *msg; 483 const u_char *srcp; 484 int n, l, first = 1; 485 486 srcp = src; 487 dstp = dst; 488 eob = dstp + dstsiz; 489 lpp = cpp = NULL; 490 if (dnptrs != NULL) { 491 if ((msg = *dnptrs++) != NULL) { 492 for (cpp = dnptrs; *cpp != NULL; cpp++) 493 (void)NULL; 494 lpp = cpp; /*%< end of list to search */ 495 } 496 } else 497 msg = NULL; 498 499 /* make sure the domain we are about to add is legal */ 500 l = 0; 501 do { 502 int l0; 503 504 n = *srcp; 505 if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) { 506 errno = EMSGSIZE; 507 return (-1); 508 } 509 if ((l0 = labellen(srcp)) < 0) { 510 errno = EINVAL; 511 return(-1); 512 } 513 l += l0 + 1; 514 if (l > MAXCDNAME) { 515 errno = EMSGSIZE; 516 return (-1); 517 } 518 srcp += l0 + 1; 519 } while (n != 0); 520 521 /* from here on we need to reset compression pointer array on error */ 522 srcp = src; 523 do { 524 /* Look to see if we can use pointers. */ 525 n = *srcp; 526 if (n != 0 && msg != NULL) { 527 l = dn_find(srcp, msg, (const u_char * const *)dnptrs, 528 (const u_char * const *)lpp); 529 if (l >= 0) { 530 if (dstp + 1 >= eob) { 531 goto cleanup; 532 } 533 *dstp++ = (l >> 8) | NS_CMPRSFLGS; 534 *dstp++ = l % 256; 535 return (dstp - dst); 536 } 537 /* Not found, save it. */ 538 if (lastdnptr != NULL && cpp < lastdnptr - 1 && 539 (dstp - msg) < 0x4000 && first) { 540 *cpp++ = dstp; 541 *cpp = NULL; 542 first = 0; 543 } 544 } 545 /* copy label to buffer */ 546 if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) { 547 /* Should not happen. */ 548 goto cleanup; 549 } 550 n = labellen(srcp); 551 if (dstp + 1 + n >= eob) { 552 goto cleanup; 553 } 554 memcpy(dstp, srcp, n + 1); 555 srcp += n + 1; 556 dstp += n + 1; 557 } while (n != 0); 558 559 if (dstp > eob) { 560 cleanup: 561 if (msg != NULL) 562 *lpp = NULL; 563 errno = EMSGSIZE; 564 return (-1); 565 } 566 return (dstp - dst); 567 } 568 569 /*% 570 * Expand compressed domain name to presentation format. 571 * 572 * return: 573 *\li Number of bytes read out of `src', or -1 (with errno set). 574 * 575 * note: 576 *\li Root domain returns as "." not "". 577 */ 578 int 579 ns_name_uncompress(const u_char *msg, const u_char *eom, const u_char *src, 580 char *dst, size_t dstsiz) 581 { 582 u_char tmp[NS_MAXCDNAME]; 583 int n; 584 585 if ((n = ns_name_unpack(msg, eom, src, tmp, sizeof tmp)) == -1) 586 return (-1); 587 if (ns_name_ntop(tmp, dst, dstsiz) == -1) 588 return (-1); 589 return (n); 590 } 591 592 /*% 593 * Compress a domain name into wire format, using compression pointers. 594 * 595 * return: 596 *\li Number of bytes consumed in `dst' or -1 (with errno set). 597 * 598 * notes: 599 *\li 'dnptrs' is an array of pointers to previous compressed names. 600 *\li dnptrs[0] is a pointer to the beginning of the message. 601 *\li 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 *\li 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 * Advance *ptrptr to skip over the compressed name it points at. 637 * 638 * return: 639 *\li 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 * Thinking in noninternationalized USASCII (per the DNS spec), 683 * is this characted special ("in need of quoting") ? 684 * 685 * return: 686 *\li 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 * Thinking in noninternationalized USASCII (per the DNS spec), 708 * is this character visible and not a space when printed ? 709 * 710 * return: 711 *\li 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 * Search for the counted-label name in an array of compressed names. 731 * 732 * return: 733 *\li offset from msg if found, or -1. 734 * 735 * notes: 736 *\li dnptrs is the pointer to the first name on the list, 737 *\li not the pointer to the start of the message. 738 */ 739 static int 740 dn_find(const u_char *domain, const u_char *msg, 741 const u_char * const *dnptrs, 742 const u_char * const *lastdnptr) 743 { 744 const u_char *dn, *cp, *sp; 745 const u_char * const *cpp; 746 u_int n; 747 748 for (cpp = dnptrs; cpp < lastdnptr; cpp++) { 749 sp = *cpp; 750 /* 751 * terminate search on: 752 * root label 753 * compression pointer 754 * unusable offset 755 */ 756 while (*sp != 0 && (*sp & NS_CMPRSFLGS) == 0 && 757 (sp - msg) < 0x4000) { 758 dn = domain; 759 cp = sp; 760 while ((n = *cp++) != 0) { 761 /* 762 * check for indirection 763 */ 764 switch (n & NS_CMPRSFLGS) { 765 case 0: /*%< normal case, n == len */ 766 n = labellen(cp - 1); /*%< XXX */ 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 unsigned char **cpp, char *dn, const char *eom) 799 { 800 const unsigned 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, unsigned char **labelp, 847 unsigned char ** dst, unsigned const char *eom) 848 { 849 int afterslash = 0; 850 const char *cp = *bp; 851 unsigned char *tp; 852 char c; 853 const char *beg_blen; 854 char *end_blen = NULL; 855 int value = 0, count = 0, tbcount = 0, blen = 0; 856 857 beg_blen = end_blen = NULL; 858 859 /* a bitstring must contain at least 2 characters */ 860 if (end - cp < 2) 861 return(EINVAL); 862 863 /* XXX: currently, only hex strings are supported */ 864 if (*cp++ != 'x') 865 return(EINVAL); 866 if (!isxdigit((*cp) & 0xff)) /*%< reject '\[x/BLEN]' */ 867 return(EINVAL); 868 869 for (tp = *dst + 1; cp < end && tp < eom; cp++) { 870 switch((c = *cp)) { 871 case ']': /*%< end of the bitstring */ 872 if (afterslash) { 873 if (beg_blen == NULL) 874 return(EINVAL); 875 blen = (int)strtol(beg_blen, &end_blen, 10); 876 if (*end_blen != ']') 877 return(EINVAL); 878 } 879 if (count) 880 *tp++ = ((value << 4) & 0xff); 881 cp++; /*%< skip ']' */ 882 goto done; 883 case '/': 884 afterslash = 1; 885 break; 886 default: 887 if (afterslash) { 888 if (!isdigit(c&0xff)) 889 return(EINVAL); 890 if (beg_blen == NULL) { 891 892 if (c == '0') { 893 /* blen never begings with 0 */ 894 return(EINVAL); 895 } 896 beg_blen = cp; 897 } 898 } else { 899 if (!isxdigit(c&0xff)) 900 return(EINVAL); 901 value <<= 4; 902 value += digitvalue[(int)c]; 903 count += 4; 904 tbcount += 4; 905 if (tbcount > 256) 906 return(EINVAL); 907 if (count == 8) { 908 *tp++ = value; 909 count = 0; 910 } 911 } 912 break; 913 } 914 } 915 done: 916 if (cp >= end || tp >= eom) 917 return(EMSGSIZE); 918 919 /* 920 * bit length validation: 921 * If a <length> is present, the number of digits in the <bit-data> 922 * MUST be just sufficient to contain the number of bits specified 923 * by the <length>. If there are insignificant bits in a final 924 * hexadecimal or octal digit, they MUST be zero. 925 * RFC2673, Section 3.2. 926 */ 927 if (blen > 0) { 928 int traillen; 929 930 if (((blen + 3) & ~3) != tbcount) 931 return(EINVAL); 932 traillen = tbcount - blen; /*%< between 0 and 3 */ 933 if (((value << (8 - traillen)) & 0xff) != 0) 934 return(EINVAL); 935 } 936 else 937 blen = tbcount; 938 if (blen == 256) 939 blen = 0; 940 941 /* encode the type and the significant bit fields */ 942 **labelp = DNS_LABELTYPE_BITSTRING; 943 **dst = blen; 944 945 *bp = cp; 946 *dst = tp; 947 948 return(0); 949 } 950 951 static int 952 labellen(const u_char *lp) 953 { 954 int bitlen; 955 u_char l = *lp; 956 957 if ((l & NS_CMPRSFLGS) == NS_CMPRSFLGS) { 958 /* should be avoided by the caller */ 959 return(-1); 960 } 961 962 if ((l & NS_CMPRSFLGS) == NS_TYPE_ELT) { 963 if (l == DNS_LABELTYPE_BITSTRING) { 964 if ((bitlen = *(lp + 1)) == 0) 965 bitlen = 256; 966 return((bitlen + 7 ) / 8 + 1); 967 } 968 return(-1); /*%< unknwon ELT */ 969 } 970 return(l); 971 } 972 973 /*! \file */ 974