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