1 /* $NetBSD: ns_name.c,v 1.3 2004/11/07 02:19:49 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.3.2.4.4.2 2004/05/04 03:27:47 marka Exp"; 24 #else 25 __RCSID("$NetBSD: ns_name.c,v 1.3 2004/11/07 02:19:49 christos Exp $"); 26 #endif 27 #endif 28 29 #include <sys/types.h> 30 31 #include <netinet/in.h> 32 #include "arpa_nameser.h" 33 34 #include <errno.h> 35 #ifdef ANDROID_CHANGES 36 #include "resolv_private.h" 37 #else 38 #include <resolv.h> 39 #endif 40 #include <string.h> 41 #include <ctype.h> 42 #include <stdlib.h> 43 #include <limits.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 * ns_name_ntop(src, dst, dstsiz) 95 * Convert an encoded domain name to printable ascii as per RFC1035. 96 * return: 97 * Number of bytes written to buffer, or -1 (with errno set) 98 * notes: 99 * The root is returned as "." 100 * All other domains are returned in non absolute form 101 */ 102 int 103 ns_name_ntop(const u_char *src, char *dst, size_t dstsiz) 104 { 105 const u_char *cp; 106 char *dn, *eom; 107 u_char c; 108 u_int n; 109 int l; 110 111 cp = src; 112 dn = dst; 113 eom = dst + dstsiz; 114 115 while ((n = *cp++) != 0) { 116 if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) { 117 /* Some kind of compression pointer. */ 118 errno = EMSGSIZE; 119 return (-1); 120 } 121 if (dn != dst) { 122 if (dn >= eom) { 123 errno = EMSGSIZE; 124 return (-1); 125 } 126 *dn++ = '.'; 127 } 128 if ((l = labellen(cp - 1)) < 0) { 129 errno = EMSGSIZE; /* XXX */ 130 return(-1); 131 } 132 if (dn + l >= eom) { 133 errno = EMSGSIZE; 134 return (-1); 135 } 136 if ((n & NS_CMPRSFLGS) == NS_TYPE_ELT) { 137 int m; 138 139 if (n != DNS_LABELTYPE_BITSTRING) { 140 /* XXX: labellen should reject this case */ 141 errno = EINVAL; 142 return(-1); 143 } 144 if ((m = decode_bitstring(&cp, dn, eom)) < 0) 145 { 146 errno = EMSGSIZE; 147 return(-1); 148 } 149 dn += m; 150 continue; 151 } 152 for (; l > 0; l--) { 153 c = *cp++; 154 if (special(c)) { 155 if (dn + 1 >= eom) { 156 errno = EMSGSIZE; 157 return (-1); 158 } 159 *dn++ = '\\'; 160 *dn++ = (char)c; 161 } else if (!printable(c)) { 162 if (dn + 3 >= eom) { 163 errno = EMSGSIZE; 164 return (-1); 165 } 166 *dn++ = '\\'; 167 *dn++ = digits[c / 100]; 168 *dn++ = digits[(c % 100) / 10]; 169 *dn++ = digits[c % 10]; 170 } else { 171 if (dn >= eom) { 172 errno = EMSGSIZE; 173 return (-1); 174 } 175 *dn++ = (char)c; 176 } 177 } 178 } 179 if (dn == dst) { 180 if (dn >= eom) { 181 errno = EMSGSIZE; 182 return (-1); 183 } 184 *dn++ = '.'; 185 } 186 if (dn >= eom) { 187 errno = EMSGSIZE; 188 return (-1); 189 } 190 *dn++ = '\0'; 191 return (dn - dst); 192 } 193 194 /* 195 * ns_name_pton(src, dst, dstsiz) 196 * Convert a ascii string into an encoded domain name as per RFC1035. 197 * return: 198 * -1 if it fails 199 * 1 if string was fully qualified 200 * 0 is string was not fully qualified 201 * notes: 202 * Enforces label and domain length limits. 203 */ 204 205 int 206 ns_name_pton(const char *src, u_char *dst, size_t dstsiz) 207 { 208 u_char *label, *bp, *eom; 209 int c, n, escaped, e = 0; 210 char *cp; 211 212 escaped = 0; 213 bp = dst; 214 eom = dst + dstsiz; 215 label = bp++; 216 217 while ((c = *src++) != 0) { 218 if (escaped) { 219 if (c == '[') { /* start a bit string label */ 220 if ((cp = strchr(src, ']')) == NULL) { 221 errno = EINVAL; /* ??? */ 222 return(-1); 223 } 224 if ((e = encode_bitsring(&src, cp + 2, 225 &label, &bp, eom)) 226 != 0) { 227 errno = e; 228 return(-1); 229 } 230 escaped = 0; 231 label = bp++; 232 if ((c = *src++) == 0) 233 goto done; 234 else if (c != '.') { 235 errno = EINVAL; 236 return(-1); 237 } 238 continue; 239 } 240 else if ((cp = strchr(digits, c)) != NULL) { 241 n = (cp - digits) * 100; 242 if ((c = *src++) == 0 || 243 (cp = strchr(digits, c)) == NULL) { 244 errno = EMSGSIZE; 245 return (-1); 246 } 247 n += (cp - digits) * 10; 248 if ((c = *src++) == 0 || 249 (cp = strchr(digits, c)) == NULL) { 250 errno = EMSGSIZE; 251 return (-1); 252 } 253 n += (cp - digits); 254 if (n > 255) { 255 errno = EMSGSIZE; 256 return (-1); 257 } 258 c = n; 259 } 260 escaped = 0; 261 } else if (c == '\\') { 262 escaped = 1; 263 continue; 264 } else if (c == '.') { 265 c = (bp - label - 1); 266 if ((c & NS_CMPRSFLGS) != 0) { /* Label too big. */ 267 errno = EMSGSIZE; 268 return (-1); 269 } 270 if (label >= eom) { 271 errno = EMSGSIZE; 272 return (-1); 273 } 274 *label = c; 275 /* Fully qualified ? */ 276 if (*src == '\0') { 277 if (c != 0) { 278 if (bp >= eom) { 279 errno = EMSGSIZE; 280 return (-1); 281 } 282 *bp++ = '\0'; 283 } 284 if ((bp - dst) > MAXCDNAME) { 285 errno = EMSGSIZE; 286 return (-1); 287 } 288 return (1); 289 } 290 if (c == 0 || *src == '.') { 291 errno = EMSGSIZE; 292 return (-1); 293 } 294 label = bp++; 295 continue; 296 } 297 if (bp >= eom) { 298 errno = EMSGSIZE; 299 return (-1); 300 } 301 *bp++ = (u_char)c; 302 } 303 c = (bp - label - 1); 304 if ((c & NS_CMPRSFLGS) != 0) { /* Label too big. */ 305 errno = EMSGSIZE; 306 return (-1); 307 } 308 done: 309 if (label >= eom) { 310 errno = EMSGSIZE; 311 return (-1); 312 } 313 *label = c; 314 if (c != 0) { 315 if (bp >= eom) { 316 errno = EMSGSIZE; 317 return (-1); 318 } 319 *bp++ = 0; 320 } 321 if ((bp - dst) > MAXCDNAME) { /* src too big */ 322 errno = EMSGSIZE; 323 return (-1); 324 } 325 return (0); 326 } 327 328 /* 329 * ns_name_ntol(src, dst, dstsiz) 330 * Convert a network strings labels into all lowercase. 331 * return: 332 * Number of bytes written to buffer, or -1 (with errno set) 333 * notes: 334 * Enforces label and domain length limits. 335 */ 336 337 int 338 ns_name_ntol(const u_char *src, u_char *dst, size_t dstsiz) 339 { 340 const u_char *cp; 341 u_char *dn, *eom; 342 u_char c; 343 u_int n; 344 int l; 345 346 cp = src; 347 dn = dst; 348 eom = dst + dstsiz; 349 350 if (dn >= eom) { 351 errno = EMSGSIZE; 352 return (-1); 353 } 354 while ((n = *cp++) != 0) { 355 if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) { 356 /* Some kind of compression pointer. */ 357 errno = EMSGSIZE; 358 return (-1); 359 } 360 *dn++ = n; 361 if ((l = labellen(cp - 1)) < 0) { 362 errno = EMSGSIZE; 363 return (-1); 364 } 365 if (dn + l >= eom) { 366 errno = EMSGSIZE; 367 return (-1); 368 } 369 for (; l > 0; l--) { 370 c = *cp++; 371 if (isupper(c)) 372 *dn++ = tolower(c); 373 else 374 *dn++ = c; 375 } 376 } 377 *dn++ = '\0'; 378 return (dn - dst); 379 } 380 381 /* 382 * ns_name_unpack(msg, eom, src, dst, dstsiz) 383 * Unpack a domain name from a message, source may be compressed. 384 * return: 385 * -1 if it fails, or consumed octets if it succeeds. 386 */ 387 int 388 ns_name_unpack(const u_char *msg, const u_char *eom, const u_char *src, 389 u_char *dst, size_t dstsiz) 390 { 391 const u_char *srcp, *dstlim; 392 u_char *dstp; 393 int n, len, checked, l; 394 395 len = -1; 396 checked = 0; 397 dstp = dst; 398 srcp = src; 399 dstlim = dst + dstsiz; 400 if (srcp < msg || srcp >= eom) { 401 errno = EMSGSIZE; 402 return (-1); 403 } 404 /* Fetch next label in domain name. */ 405 while ((n = *srcp++) != 0) { 406 /* Check for indirection. */ 407 switch (n & NS_CMPRSFLGS) { 408 case 0: 409 case NS_TYPE_ELT: 410 /* Limit checks. */ 411 if ((l = labellen(srcp - 1)) < 0) { 412 errno = EMSGSIZE; 413 return(-1); 414 } 415 if (dstp + l + 1 >= dstlim || srcp + l >= eom) { 416 errno = EMSGSIZE; 417 return (-1); 418 } 419 checked += l + 1; 420 *dstp++ = n; 421 memcpy(dstp, srcp, (size_t)l); 422 dstp += l; 423 srcp += l; 424 break; 425 426 case NS_CMPRSFLGS: 427 if (srcp >= eom) { 428 errno = EMSGSIZE; 429 return (-1); 430 } 431 if (len < 0) 432 len = srcp - src + 1; 433 srcp = msg + (((n & 0x3f) << 8) | (*srcp & 0xff)); 434 if (srcp < msg || srcp >= eom) { /* Out of range. */ 435 errno = EMSGSIZE; 436 return (-1); 437 } 438 checked += 2; 439 /* 440 * Check for loops in the compressed name; 441 * if we've looked at the whole message, 442 * there must be a loop. 443 */ 444 if (checked >= eom - msg) { 445 errno = EMSGSIZE; 446 return (-1); 447 } 448 break; 449 450 default: 451 errno = EMSGSIZE; 452 return (-1); /* flag error */ 453 } 454 } 455 *dstp = '\0'; 456 if (len < 0) 457 len = srcp - src; 458 return (len); 459 } 460 461 /* 462 * ns_name_pack(src, dst, dstsiz, dnptrs, lastdnptr) 463 * Pack domain name 'domain' into 'comp_dn'. 464 * return: 465 * Size of the compressed name, or -1. 466 * notes: 467 * 'dnptrs' is an array of pointers to previous compressed names. 468 * dnptrs[0] is a pointer to the beginning of the message. The array 469 * ends with NULL. 470 * 'lastdnptr' is a pointer to the end of the array pointed to 471 * by 'dnptrs'. 472 * Side effects: 473 * The list of pointers in dnptrs is updated for labels inserted into 474 * the message as we compress the name. If 'dnptr' is NULL, we don't 475 * try to compress names. If 'lastdnptr' is NULL, we don't update the 476 * list. 477 */ 478 int 479 ns_name_pack(const u_char *src, u_char *dst, int dstsiz, 480 const u_char **dnptrs, const u_char **lastdnptr) 481 { 482 u_char *dstp; 483 const u_char **cpp, **lpp, *eob, *msg; 484 const u_char *srcp; 485 int n, l, first = 1; 486 487 srcp = src; 488 dstp = dst; 489 eob = dstp + dstsiz; 490 lpp = cpp = NULL; 491 if (dnptrs != NULL) { 492 if ((msg = *dnptrs++) != NULL) { 493 for (cpp = dnptrs; *cpp != NULL; cpp++) 494 ; 495 lpp = cpp; /* end of list to search */ 496 } 497 } else 498 msg = NULL; 499 500 /* make sure the domain we are about to add is legal */ 501 l = 0; 502 do { 503 int l0; 504 505 n = *srcp; 506 if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) { 507 errno = EMSGSIZE; 508 return (-1); 509 } 510 if ((l0 = labellen(srcp)) < 0) { 511 errno = EINVAL; 512 return(-1); 513 } 514 l += l0 + 1; 515 if (l > MAXCDNAME) { 516 errno = EMSGSIZE; 517 return (-1); 518 } 519 srcp += l0 + 1; 520 } while (n != 0); 521 522 /* from here on we need to reset compression pointer array on error */ 523 srcp = src; 524 do { 525 /* Look to see if we can use pointers. */ 526 n = *srcp; 527 if (n != 0 && msg != NULL) { 528 l = dn_find(srcp, msg, (const u_char * const *)dnptrs, 529 (const u_char * const *)lpp); 530 if (l >= 0) { 531 if (dstp + 1 >= eob) { 532 goto cleanup; 533 } 534 *dstp++ = ((u_int32_t)l >> 8) | NS_CMPRSFLGS; 535 *dstp++ = l % 256; 536 return (dstp - dst); 537 } 538 /* Not found, save it. */ 539 if (lastdnptr != NULL && cpp < lastdnptr - 1 && 540 (dstp - msg) < 0x4000 && first) { 541 *cpp++ = dstp; 542 *cpp = NULL; 543 first = 0; 544 } 545 } 546 /* copy label to buffer */ 547 if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) { 548 /* Should not happen. */ 549 goto cleanup; 550 } 551 n = labellen(srcp); 552 if (dstp + 1 + n >= eob) { 553 goto cleanup; 554 } 555 memcpy(dstp, srcp, (size_t)(n + 1)); 556 srcp += n + 1; 557 dstp += n + 1; 558 } while (n != 0); 559 560 if (dstp > eob) { 561 cleanup: 562 if (msg != NULL) 563 *lpp = NULL; 564 errno = EMSGSIZE; 565 return (-1); 566 } 567 return (dstp - dst); 568 } 569 570 /* 571 * ns_name_uncompress(msg, eom, src, dst, dstsiz) 572 * Expand compressed domain name to presentation format. 573 * return: 574 * Number of bytes read out of `src', or -1 (with errno set). 575 * note: 576 * 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 * ns_name_compress(src, dst, dstsiz, dnptrs, lastdnptr) 594 * Compress a domain name into wire format, using compression pointers. 595 * return: 596 * Number of bytes consumed in `dst' or -1 (with errno set). 597 * notes: 598 * 'dnptrs' is an array of pointers to previous compressed names. 599 * dnptrs[0] is a pointer to the beginning of the message. 600 * The list ends with NULL. 'lastdnptr' is a pointer to the end of the 601 * array pointed to by 'dnptrs'. Side effect is to update the list of 602 * pointers for labels inserted into the message as we compress the name. 603 * If 'dnptr' is NULL, we don't try to compress names. If 'lastdnptr' 604 * is NULL, we don't update the list. 605 */ 606 int 607 ns_name_compress(const char *src, u_char *dst, size_t dstsiz, 608 const u_char **dnptrs, const u_char **lastdnptr) 609 { 610 u_char tmp[NS_MAXCDNAME]; 611 612 if (ns_name_pton(src, tmp, sizeof tmp) == -1) 613 return (-1); 614 return (ns_name_pack(tmp, dst, (int)dstsiz, dnptrs, lastdnptr)); 615 } 616 617 /* 618 * Reset dnptrs so that there are no active references to pointers at or 619 * after src. 620 */ 621 void 622 ns_name_rollback(const u_char *src, const u_char **dnptrs, 623 const u_char **lastdnptr) 624 { 625 while (dnptrs < lastdnptr && *dnptrs != NULL) { 626 if (*dnptrs >= src) { 627 *dnptrs = NULL; 628 break; 629 } 630 dnptrs++; 631 } 632 } 633 634 /* 635 * ns_name_skip(ptrptr, eom) 636 * Advance *ptrptr to skip over the compressed name it points at. 637 * return: 638 * 0 on success, -1 (with errno set) on failure. 639 */ 640 int 641 ns_name_skip(const u_char **ptrptr, const u_char *eom) 642 { 643 const u_char *cp; 644 u_int n; 645 int l; 646 647 cp = *ptrptr; 648 while (cp < eom && (n = *cp++) != 0) { 649 /* Check for indirection. */ 650 switch (n & NS_CMPRSFLGS) { 651 case 0: /* normal case, n == len */ 652 cp += n; 653 continue; 654 case NS_TYPE_ELT: /* EDNS0 extended label */ 655 if ((l = labellen(cp - 1)) < 0) { 656 errno = EMSGSIZE; /* XXX */ 657 return(-1); 658 } 659 cp += l; 660 continue; 661 case NS_CMPRSFLGS: /* indirection */ 662 cp++; 663 break; 664 default: /* illegal type */ 665 errno = EMSGSIZE; 666 return (-1); 667 } 668 break; 669 } 670 if (cp > eom) { 671 errno = EMSGSIZE; 672 return (-1); 673 } 674 *ptrptr = cp; 675 return (0); 676 } 677 678 /* Private. */ 679 680 /* 681 * special(ch) 682 * Thinking in noninternationalized USASCII (per the DNS spec), 683 * is this characted special ("in need of quoting") ? 684 * return: 685 * boolean. 686 */ 687 static int 688 special(int ch) { 689 switch (ch) { 690 case 0x22: /* '"' */ 691 case 0x2E: /* '.' */ 692 case 0x3B: /* ';' */ 693 case 0x5C: /* '\\' */ 694 case 0x28: /* '(' */ 695 case 0x29: /* ')' */ 696 /* Special modifiers in zone files. */ 697 case 0x40: /* '@' */ 698 case 0x24: /* '$' */ 699 return (1); 700 default: 701 return (0); 702 } 703 } 704 705 /* 706 * printable(ch) 707 * Thinking in noninternationalized USASCII (per the DNS spec), 708 * is this character visible and not a space when printed ? 709 * return: 710 * boolean. 711 */ 712 static int 713 printable(int ch) { 714 return (ch > 0x20 && ch < 0x7f); 715 } 716 717 /* 718 * Thinking in noninternationalized USASCII (per the DNS spec), 719 * convert this character to lower case if it's upper case. 720 */ 721 static int 722 mklower(int ch) { 723 if (ch >= 0x41 && ch <= 0x5A) 724 return (ch + 0x20); 725 return (ch); 726 } 727 728 /* 729 * dn_find(domain, msg, dnptrs, lastdnptr) 730 * Search for the counted-label name in an array of compressed names. 731 * return: 732 * offset from msg if found, or -1. 733 * notes: 734 * dnptrs is the pointer to the first name on the list, 735 * 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 766 if (n != *dn++) 767 goto next; 768 769 for (; n > 0; n--) 770 if (mklower(*dn++) != 771 mklower(*cp++)) 772 goto next; 773 /* Is next root for both ? */ 774 if (*dn == '\0' && *cp == '\0') 775 return (sp - msg); 776 if (*dn) 777 continue; 778 goto next; 779 case NS_CMPRSFLGS: /* indirection */ 780 cp = msg + (((n & 0x3f) << 8) | *cp); 781 break; 782 783 default: /* illegal type */ 784 errno = EMSGSIZE; 785 return (-1); 786 } 787 } 788 next: ; 789 sp += *sp + 1; 790 } 791 } 792 errno = ENOENT; 793 return (-1); 794 } 795 796 static int 797 decode_bitstring(const unsigned char **cpp, char *dn, const char *eom) 798 { 799 const unsigned char *cp = *cpp; 800 char *beg = dn, tc; 801 int b, blen, plen, i; 802 803 if ((blen = (*cp & 0xff)) == 0) 804 blen = 256; 805 plen = (blen + 3) / 4; 806 plen += sizeof("\\[x/]") + (blen > 99 ? 3 : (blen > 9) ? 2 : 1); 807 if (dn + plen >= eom) 808 return(-1); 809 810 cp++; 811 i = SPRINTF((dn, "\\[x")); 812 if (i < 0) 813 return (-1); 814 dn += i; 815 for (b = blen; b > 7; b -= 8, cp++) { 816 i = SPRINTF((dn, "%02x", *cp & 0xff)); 817 if (i < 0) 818 return (-1); 819 dn += i; 820 } 821 if (b > 4) { 822 tc = *cp++; 823 i = SPRINTF((dn, "%02x", tc & (0xff << (8 - b)))); 824 if (i < 0) 825 return (-1); 826 dn += i; 827 } else if (b > 0) { 828 tc = *cp++; 829 i = SPRINTF((dn, "%1x", 830 (((u_int32_t)tc >> 4) & 0x0f) & (0x0f << (4 - b)))); 831 if (i < 0) 832 return (-1); 833 dn += i; 834 } 835 i = SPRINTF((dn, "/%d]", blen)); 836 if (i < 0) 837 return (-1); 838 dn += i; 839 840 *cpp = cp; 841 return(dn - beg); 842 } 843 844 static int 845 encode_bitsring(const char **bp, const char *end, unsigned char **labelp, 846 unsigned char ** dst, unsigned const char *eom) 847 { 848 int afterslash = 0; 849 const char *cp = *bp; 850 unsigned char *tp; 851 char 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