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