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