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