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