ns_name.c revision 270838
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 19static 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: stable/10/lib/libc/nameser/ns_name.c 270838 2014-08-30 10:16:25Z ume $"); 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 51static const char digits[] = "0123456789"; 52 53static 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 74static int special(int); 75static int printable(int); 76static int dn_find(const u_char *, const u_char *, 77 const u_char * const *, 78 const u_char * const *); 79static int encode_bitsring(const char **, const char *, 80 unsigned char **, unsigned char **, 81 unsigned const char *); 82static int labellen(const u_char *); 83static 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 */ 98int 99ns_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 */ 202int 203ns_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 */ 219int 220ns_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 355int 356ns_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 */ 405int 406ns_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 */ 420int 421ns_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 srcp = msg + (((n & 0x3f) << 8) | (*srcp & 0xff)); 467 if (srcp < msg || srcp >= eom) { /*%< Out of range. */ 468 errno = EMSGSIZE; 469 return (-1); 470 } 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 */ 515int 516ns_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) { 598cleanup: 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 */ 616int 617ns_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 */ 645int 646ns_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 */ 660void 661ns_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 */ 679int 680ns_name_skip(const u_char **ptrptr, const u_char *eom) 681{ 682 const u_char *cp; 683 u_int n; 684 int l; 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 ((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 */ 721ssize_t 722ns_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 */ 743int 744ns_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 */ 767int 768ns_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 */ 790int 791ns_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 */ 840int 841ns_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 */ 870static int 871special(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 */ 895static int 896printable(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 */ 904static int 905mklower(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 */ 921static int 922dn_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 979static int 980decode_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 1027static int 1028encode_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 1133static int 1134labellen(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); /*%< unknwon ELT */ 1151 } 1152 return (l); 1153} 1154 1155/*! \file */ 1156