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