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