1/* $NetBSD: ns_name.c,v 1.2 2014/03/07 01:06:07 christos Exp $ */ 2 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 21static const char rcsid[] = "Id: ns_name.c,v 1.11 2009/01/23 19:59:16 each Exp "; 22#endif 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 467 n = ((n & 0x3f) << 8) | (*srcp & 0xff); 468 if (n >= eom - msg) { /*%< Out of range. */ 469 errno = EMSGSIZE; 470 return (-1); 471 } 472 srcp = msg + n; 473 checked += 2; 474 /* 475 * Check for loops in the compressed name; 476 * if we've looked at the whole message, 477 * there must be a loop. 478 */ 479 if (checked >= eom - msg) { 480 errno = EMSGSIZE; 481 return (-1); 482 } 483 break; 484 485 default: 486 errno = EMSGSIZE; 487 return (-1); /*%< flag error */ 488 } 489 } 490 *dstp++ = 0; 491 if (dstlen != NULL) 492 *dstlen = dstp - dst; 493 if (len < 0) 494 len = srcp - src; 495 return (len); 496} 497 498/*% 499 * Pack domain name 'domain' into 'comp_dn'. 500 * 501 * return: 502 *\li Size of the compressed name, or -1. 503 * 504 * notes: 505 *\li 'dnptrs' is an array of pointers to previous compressed names. 506 *\li dnptrs[0] is a pointer to the beginning of the message. The array 507 * ends with NULL. 508 *\li 'lastdnptr' is a pointer to the end of the array pointed to 509 * by 'dnptrs'. 510 * 511 * Side effects: 512 *\li The list of pointers in dnptrs is updated for labels inserted into 513 * the message as we compress the name. If 'dnptr' is NULL, we don't 514 * try to compress names. If 'lastdnptr' is NULL, we don't update the 515 * list. 516 */ 517int 518ns_name_pack(const u_char *src, u_char *dst, int dstsiz, 519 const u_char **dnptrs, const u_char **lastdnptr) 520{ 521 u_char *dstp; 522 const u_char **cpp, **lpp, *eob, *msg; 523 const u_char *srcp; 524 int n, l, first = 1; 525 526 srcp = src; 527 dstp = dst; 528 eob = dstp + dstsiz; 529 lpp = cpp = NULL; 530 if (dnptrs != NULL) { 531 if ((msg = *dnptrs++) != NULL) { 532 for (cpp = dnptrs; *cpp != NULL; cpp++) 533 (void)NULL; 534 lpp = cpp; /*%< end of list to search */ 535 } 536 } else 537 msg = NULL; 538 539 /* make sure the domain we are about to add is legal */ 540 l = 0; 541 do { 542 int l0; 543 544 n = *srcp; 545 if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) { 546 errno = EMSGSIZE; 547 return (-1); 548 } 549 if ((l0 = labellen(srcp)) < 0) { 550 errno = EINVAL; 551 return (-1); 552 } 553 l += l0 + 1; 554 if (l > MAXCDNAME) { 555 errno = EMSGSIZE; 556 return (-1); 557 } 558 srcp += l0 + 1; 559 } while (n != 0); 560 561 /* from here on we need to reset compression pointer array on error */ 562 srcp = src; 563 do { 564 /* Look to see if we can use pointers. */ 565 n = *srcp; 566 if (n != 0 && msg != NULL) { 567 l = dn_find(srcp, msg, (const u_char * const *)dnptrs, 568 (const u_char * const *)lpp); 569 if (l >= 0) { 570 if (dstp + 1 >= eob) { 571 goto cleanup; 572 } 573 *dstp++ = (l >> 8) | NS_CMPRSFLGS; 574 *dstp++ = l % 256; 575 return (dstp - dst); 576 } 577 /* Not found, save it. */ 578 if (lastdnptr != NULL && cpp < lastdnptr - 1 && 579 (dstp - msg) < 0x4000 && first) { 580 *cpp++ = dstp; 581 *cpp = NULL; 582 first = 0; 583 } 584 } 585 /* copy label to buffer */ 586 if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) { 587 /* Should not happen. */ 588 goto cleanup; 589 } 590 n = labellen(srcp); 591 if (dstp + 1 + n >= eob) { 592 goto cleanup; 593 } 594 memcpy(dstp, srcp, n + 1); 595 srcp += n + 1; 596 dstp += n + 1; 597 } while (n != 0); 598 599 if (dstp > eob) { 600cleanup: 601 if (msg != NULL) 602 *lpp = NULL; 603 errno = EMSGSIZE; 604 return (-1); 605 } 606 return (dstp - dst); 607} 608 609/*% 610 * Expand compressed domain name to presentation format. 611 * 612 * return: 613 *\li Number of bytes read out of `src', or -1 (with errno set). 614 * 615 * note: 616 *\li Root domain returns as "." not "". 617 */ 618int 619ns_name_uncompress(const u_char *msg, const u_char *eom, const u_char *src, 620 char *dst, size_t dstsiz) 621{ 622 u_char tmp[NS_MAXCDNAME]; 623 int n; 624 625 if ((n = ns_name_unpack(msg, eom, src, tmp, sizeof tmp)) == -1) 626 return (-1); 627 if (ns_name_ntop(tmp, dst, dstsiz) == -1) 628 return (-1); 629 return (n); 630} 631 632/*% 633 * Compress a domain name into wire format, using compression pointers. 634 * 635 * return: 636 *\li Number of bytes consumed in `dst' or -1 (with errno set). 637 * 638 * notes: 639 *\li 'dnptrs' is an array of pointers to previous compressed names. 640 *\li dnptrs[0] is a pointer to the beginning of the message. 641 *\li The list ends with NULL. 'lastdnptr' is a pointer to the end of the 642 * array pointed to by 'dnptrs'. Side effect is to update the list of 643 * pointers for labels inserted into the message as we compress the name. 644 *\li If 'dnptr' is NULL, we don't try to compress names. If 'lastdnptr' 645 * is NULL, we don't update the list. 646 */ 647int 648ns_name_compress(const char *src, u_char *dst, size_t dstsiz, 649 const u_char **dnptrs, const u_char **lastdnptr) 650{ 651 u_char tmp[NS_MAXCDNAME]; 652 653 if (ns_name_pton(src, tmp, sizeof tmp) == -1) 654 return (-1); 655 return (ns_name_pack(tmp, dst, dstsiz, dnptrs, lastdnptr)); 656} 657 658/*% 659 * Reset dnptrs so that there are no active references to pointers at or 660 * after src. 661 */ 662void 663ns_name_rollback(const u_char *src, const u_char **dnptrs, 664 const u_char **lastdnptr) 665{ 666 while (dnptrs < lastdnptr && *dnptrs != NULL) { 667 if (*dnptrs >= src) { 668 *dnptrs = NULL; 669 break; 670 } 671 dnptrs++; 672 } 673} 674 675/*% 676 * Advance *ptrptr to skip over the compressed name it points at. 677 * 678 * return: 679 *\li 0 on success, -1 (with errno set) on failure. 680 */ 681int 682ns_name_skip(const u_char **ptrptr, const u_char *eom) 683{ 684 const u_char *cp; 685 u_int n; 686 int l; 687 688 cp = *ptrptr; 689 while (cp < eom && (n = *cp++) != 0) { 690 /* Check for indirection. */ 691 switch (n & NS_CMPRSFLGS) { 692 case 0: /*%< normal case, n == len */ 693 cp += n; 694 continue; 695 case NS_TYPE_ELT: /*%< EDNS0 extended label */ 696 if ((l = labellen(cp - 1)) < 0) { 697 errno = EMSGSIZE; /*%< XXX */ 698 return (-1); 699 } 700 cp += l; 701 continue; 702 case NS_CMPRSFLGS: /*%< indirection */ 703 cp++; 704 break; 705 default: /*%< illegal type */ 706 errno = EMSGSIZE; 707 return (-1); 708 } 709 break; 710 } 711 if (cp > eom) { 712 errno = EMSGSIZE; 713 return (-1); 714 } 715 *ptrptr = cp; 716 return (0); 717} 718 719/* Find the number of octets an nname takes up, including the root label. 720 * (This is basically ns_name_skip() without compression-pointer support.) 721 * ((NOTE: can only return zero if passed-in namesiz argument is zero.)) 722 */ 723ssize_t 724ns_name_length(ns_nname_ct nname, size_t namesiz) { 725 ns_nname_ct orig = nname; 726 u_int n; 727 728 while (namesiz-- > 0 && (n = *nname++) != 0) { 729 if ((n & NS_CMPRSFLGS) != 0) { 730 errno = EISDIR; 731 return (-1); 732 } 733 if (n > namesiz) { 734 errno = EMSGSIZE; 735 return (-1); 736 } 737 nname += n; 738 namesiz -= n; 739 } 740 return (nname - orig); 741} 742 743/* Compare two nname's for equality. Return -1 on error (setting errno). 744 */ 745int 746ns_name_eq(ns_nname_ct a, size_t as, ns_nname_ct b, size_t bs) { 747 ns_nname_ct ae = a + as, be = b + bs; 748 int ac, bc; 749 750 while (ac = *a, bc = *b, ac != 0 && bc != 0) { 751 if ((ac & NS_CMPRSFLGS) != 0 || (bc & NS_CMPRSFLGS) != 0) { 752 errno = EISDIR; 753 return (-1); 754 } 755 if (a + ac >= ae || b + bc >= be) { 756 errno = EMSGSIZE; 757 return (-1); 758 } 759 if (ac != bc || strncasecmp((const char *) ++a, 760 (const char *) ++b, ac) != 0) 761 return (0); 762 a += ac, b += bc; 763 } 764 return (ac == 0 && bc == 0); 765} 766 767/* Is domain "A" owned by (at or below) domain "B"? 768 */ 769int 770ns_name_owned(ns_namemap_ct a, int an, ns_namemap_ct b, int bn) { 771 /* If A is shorter, it cannot be owned by B. */ 772 if (an < bn) 773 return (0); 774 775 /* If they are unequal before the length of the shorter, A cannot... */ 776 while (bn > 0) { 777 if (a->len != b->len || 778 strncasecmp((const char *) a->base, 779 (const char *) b->base, a->len) != 0) 780 return (0); 781 a++, an--; 782 b++, bn--; 783 } 784 785 /* A might be longer or not, but either way, B owns it. */ 786 return (1); 787} 788 789/* Build an array of <base,len> tuples from an nname, top-down order. 790 * Return the number of tuples (labels) thus discovered. 791 */ 792int 793ns_name_map(ns_nname_ct nname, size_t namelen, ns_namemap_t map, int mapsize) { 794 u_int n; 795 int l; 796 797 n = *nname++; 798 namelen--; 799 800 /* Root zone? */ 801 if (n == 0) { 802 /* Extra data follows name? */ 803 if (namelen > 0) { 804 errno = EMSGSIZE; 805 return (-1); 806 } 807 return (0); 808 } 809 810 /* Compression pointer? */ 811 if ((n & NS_CMPRSFLGS) != 0) { 812 errno = EISDIR; 813 return (-1); 814 } 815 816 /* Label too long? */ 817 if (n > namelen) { 818 errno = EMSGSIZE; 819 return (-1); 820 } 821 822 /* Recurse to get rest of name done first. */ 823 l = ns_name_map(nname + n, namelen - n, map, mapsize); 824 if (l < 0) 825 return (-1); 826 827 /* Too many labels? */ 828 if (l >= mapsize) { 829 errno = ENAMETOOLONG; 830 return (-1); 831 } 832 833 /* We're on our way back up-stack, store current map data. */ 834 map[l].base = nname; 835 map[l].len = n; 836 return (l + 1); 837} 838 839/* Count the labels in a domain name. Root counts, so COM. has two. This 840 * is to make the result comparable to the result of ns_name_map(). 841 */ 842int 843ns_name_labels(ns_nname_ct nname, size_t namesiz) { 844 int ret = 0; 845 u_int n; 846 847 while (namesiz-- > 0 && (n = *nname++) != 0) { 848 if ((n & NS_CMPRSFLGS) != 0) { 849 errno = EISDIR; 850 return (-1); 851 } 852 if (n > namesiz) { 853 errno = EMSGSIZE; 854 return (-1); 855 } 856 nname += n; 857 namesiz -= n; 858 ret++; 859 } 860 return (ret + 1); 861} 862 863/* Private. */ 864 865/*% 866 * Thinking in noninternationalized USASCII (per the DNS spec), 867 * is this characted special ("in need of quoting") ? 868 * 869 * return: 870 *\li boolean. 871 */ 872static int 873special(int ch) { 874 switch (ch) { 875 case 0x22: /*%< '"' */ 876 case 0x2E: /*%< '.' */ 877 case 0x3B: /*%< ';' */ 878 case 0x5C: /*%< '\\' */ 879 case 0x28: /*%< '(' */ 880 case 0x29: /*%< ')' */ 881 /* Special modifiers in zone files. */ 882 case 0x40: /*%< '@' */ 883 case 0x24: /*%< '$' */ 884 return (1); 885 default: 886 return (0); 887 } 888} 889 890/*% 891 * Thinking in noninternationalized USASCII (per the DNS spec), 892 * is this character visible and not a space when printed ? 893 * 894 * return: 895 *\li boolean. 896 */ 897static int 898printable(int ch) { 899 return (ch > 0x20 && ch < 0x7f); 900} 901 902/*% 903 * Thinking in noninternationalized USASCII (per the DNS spec), 904 * convert this character to lower case if it's upper case. 905 */ 906static int 907mklower(int ch) { 908 if (ch >= 0x41 && ch <= 0x5A) 909 return (ch + 0x20); 910 return (ch); 911} 912 913/*% 914 * Search for the counted-label name in an array of compressed names. 915 * 916 * return: 917 *\li offset from msg if found, or -1. 918 * 919 * notes: 920 *\li dnptrs is the pointer to the first name on the list, 921 *\li not the pointer to the start of the message. 922 */ 923static int 924dn_find(const u_char *domain, const u_char *msg, 925 const u_char * const *dnptrs, 926 const u_char * const *lastdnptr) 927{ 928 const u_char *dn, *cp, *sp; 929 const u_char * const *cpp; 930 u_int n; 931 932 for (cpp = dnptrs; cpp < lastdnptr; cpp++) { 933 sp = *cpp; 934 /* 935 * terminate search on: 936 * root label 937 * compression pointer 938 * unusable offset 939 */ 940 while (*sp != 0 && (*sp & NS_CMPRSFLGS) == 0 && 941 (sp - msg) < 0x4000) { 942 dn = domain; 943 cp = sp; 944 while ((n = *cp++) != 0) { 945 /* 946 * check for indirection 947 */ 948 switch (n & NS_CMPRSFLGS) { 949 case 0: /*%< normal case, n == len */ 950 n = labellen(cp - 1); /*%< XXX */ 951 if (n != *dn++) 952 goto next; 953 954 for ((void)NULL; n > 0; n--) 955 if (mklower(*dn++) != 956 mklower(*cp++)) 957 goto next; 958 /* Is next root for both ? */ 959 if (*dn == '\0' && *cp == '\0') 960 return (sp - msg); 961 if (*dn) 962 continue; 963 goto next; 964 case NS_CMPRSFLGS: /*%< indirection */ 965 cp = msg + (((n & 0x3f) << 8) | *cp); 966 break; 967 968 default: /*%< illegal type */ 969 errno = EMSGSIZE; 970 return (-1); 971 } 972 } 973 next: ; 974 sp += *sp + 1; 975 } 976 } 977 errno = ENOENT; 978 return (-1); 979} 980 981static int 982decode_bitstring(const unsigned char **cpp, char *dn, const char *eom) 983{ 984 const unsigned char *cp = *cpp; 985 char *beg = dn, tc; 986 int b, blen, plen, i; 987 988 if ((blen = (*cp & 0xff)) == 0) 989 blen = 256; 990 plen = (blen + 3) / 4; 991 plen += sizeof("\\[x/]") + (blen > 99 ? 3 : (blen > 9) ? 2 : 1); 992 if (dn + plen >= eom) 993 return (-1); 994 995 cp++; 996 i = SPRINTF((dn, "\\[x")); 997 if (i < 0) 998 return (-1); 999 dn += i; 1000 for (b = blen; b > 7; b -= 8, cp++) { 1001 i = SPRINTF((dn, "%02x", *cp & 0xff)); 1002 if (i < 0) 1003 return (-1); 1004 dn += i; 1005 } 1006 if (b > 4) { 1007 tc = *cp++; 1008 i = SPRINTF((dn, "%02x", tc & (0xff << (8 - b)))); 1009 if (i < 0) 1010 return (-1); 1011 dn += i; 1012 } else if (b > 0) { 1013 tc = *cp++; 1014 i = SPRINTF((dn, "%1x", 1015 ((tc >> 4) & 0x0f) & (0x0f << (4 - b)))); 1016 if (i < 0) 1017 return (-1); 1018 dn += i; 1019 } 1020 i = SPRINTF((dn, "/%d]", blen)); 1021 if (i < 0) 1022 return (-1); 1023 dn += i; 1024 1025 *cpp = cp; 1026 return (dn - beg); 1027} 1028 1029static int 1030encode_bitsring(const char **bp, const char *end, unsigned char **labelp, 1031 unsigned char ** dst, unsigned const char *eom) 1032{ 1033 int afterslash = 0; 1034 const char *cp = *bp; 1035 unsigned char *tp; 1036 char c; 1037 const char *beg_blen; 1038 char *end_blen = NULL; 1039 int value = 0, count = 0, tbcount = 0, blen = 0; 1040 1041 beg_blen = end_blen = NULL; 1042 1043 /* a bitstring must contain at least 2 characters */ 1044 if (end - cp < 2) 1045 return (EINVAL); 1046 1047 /* XXX: currently, only hex strings are supported */ 1048 if (*cp++ != 'x') 1049 return (EINVAL); 1050 if (!isxdigit((*cp) & 0xff)) /*%< reject '\[x/BLEN]' */ 1051 return (EINVAL); 1052 1053 for (tp = *dst + 1; cp < end && tp < eom; cp++) { 1054 switch((c = *cp)) { 1055 case ']': /*%< end of the bitstring */ 1056 if (afterslash) { 1057 if (beg_blen == NULL) 1058 return (EINVAL); 1059 blen = (int)strtol(beg_blen, &end_blen, 10); 1060 if (*end_blen != ']') 1061 return (EINVAL); 1062 } 1063 if (count) 1064 *tp++ = ((value << 4) & 0xff); 1065 cp++; /*%< skip ']' */ 1066 goto done; 1067 case '/': 1068 afterslash = 1; 1069 break; 1070 default: 1071 if (afterslash) { 1072 if (!isdigit(c&0xff)) 1073 return (EINVAL); 1074 if (beg_blen == NULL) { 1075 1076 if (c == '0') { 1077 /* blen never begings with 0 */ 1078 return (EINVAL); 1079 } 1080 beg_blen = cp; 1081 } 1082 } else { 1083 if (!isxdigit(c&0xff)) 1084 return (EINVAL); 1085 value <<= 4; 1086 value += digitvalue[(int)c]; 1087 count += 4; 1088 tbcount += 4; 1089 if (tbcount > 256) 1090 return (EINVAL); 1091 if (count == 8) { 1092 *tp++ = value; 1093 count = 0; 1094 } 1095 } 1096 break; 1097 } 1098 } 1099 done: 1100 if (cp >= end || tp >= eom) 1101 return (EMSGSIZE); 1102 1103 /* 1104 * bit length validation: 1105 * If a <length> is present, the number of digits in the <bit-data> 1106 * MUST be just sufficient to contain the number of bits specified 1107 * by the <length>. If there are insignificant bits in a final 1108 * hexadecimal or octal digit, they MUST be zero. 1109 * RFC2673, Section 3.2. 1110 */ 1111 if (blen > 0) { 1112 int traillen; 1113 1114 if (((blen + 3) & ~3) != tbcount) 1115 return (EINVAL); 1116 traillen = tbcount - blen; /*%< between 0 and 3 */ 1117 if (((value << (8 - traillen)) & 0xff) != 0) 1118 return (EINVAL); 1119 } 1120 else 1121 blen = tbcount; 1122 if (blen == 256) 1123 blen = 0; 1124 1125 /* encode the type and the significant bit fields */ 1126 **labelp = DNS_LABELTYPE_BITSTRING; 1127 **dst = blen; 1128 1129 *bp = cp; 1130 *dst = tp; 1131 1132 return (0); 1133} 1134 1135static int 1136labellen(const u_char *lp) 1137{ 1138 int bitlen; 1139 u_char l = *lp; 1140 1141 if ((l & NS_CMPRSFLGS) == NS_CMPRSFLGS) { 1142 /* should be avoided by the caller */ 1143 return (-1); 1144 } 1145 1146 if ((l & NS_CMPRSFLGS) == NS_TYPE_ELT) { 1147 if (l == DNS_LABELTYPE_BITSTRING) { 1148 if ((bitlen = *(lp + 1)) == 0) 1149 bitlen = 256; 1150 return ((bitlen + 7 ) / 8 + 1); 1151 } 1152 return (-1); /*%< unknwon ELT */ 1153 } 1154 return (l); 1155} 1156 1157/*! \file */ 1158