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 */ 981