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