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