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