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