104 105#include <syslog.h> 106#include <stdarg.h> 107#include <nsswitch.h> 108#include "un-namespace.h" 109 110#if defined(__KAME__) && defined(INET6) 111# define FAITH 112#endif 113 114#define SUCCESS 0 115#define ANY 0 116#define YES 1 117#define NO 0 118 119static const char in_addrany[] = { 0, 0, 0, 0 }; 120static const char in6_addrany[] = { 121 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 122}; 123static const char in_loopback[] = { 127, 0, 0, 1 }; 124static const char in6_loopback[] = { 125 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 126}; 127 128static const struct afd { 129 int a_af; 130 int a_addrlen; 131 int a_socklen; 132 int a_off; 133 const char *a_addrany; 134 const char *a_loopback; 135 int a_scoped; 136} afdl [] = { 137#ifdef INET6 138#define N_INET6 0 139 {PF_INET6, sizeof(struct in6_addr), 140 sizeof(struct sockaddr_in6), 141 offsetof(struct sockaddr_in6, sin6_addr), 142 in6_addrany, in6_loopback, 1}, 143#define N_INET 1 144#else 145#define N_INET 0 146#endif 147 {PF_INET, sizeof(struct in_addr), 148 sizeof(struct sockaddr_in), 149 offsetof(struct sockaddr_in, sin_addr), 150 in_addrany, in_loopback, 0}, 151 {0, 0, 0, 0, NULL, NULL, 0}, 152}; 153 154struct explore { 155 int e_af; 156 int e_socktype; 157 int e_protocol; 158 const char *e_protostr; 159 int e_wild; 160#define WILD_AF(ex) ((ex)->e_wild & 0x01) 161#define WILD_SOCKTYPE(ex) ((ex)->e_wild & 0x02) 162#define WILD_PROTOCOL(ex) ((ex)->e_wild & 0x04) 163}; 164 165static const struct explore explore[] = { 166#if 0 167 { PF_LOCAL, 0, ANY, ANY, NULL, 0x01 }, 168#endif 169#ifdef INET6 170 { PF_INET6, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 }, 171 { PF_INET6, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 }, 172 { PF_INET6, SOCK_RAW, ANY, NULL, 0x05 }, 173#endif 174 { PF_INET, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 }, 175 { PF_INET, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 }, 176 { PF_INET, SOCK_RAW, ANY, NULL, 0x05 }, 177 { PF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 }, 178 { PF_UNSPEC, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 }, 179 { PF_UNSPEC, SOCK_RAW, ANY, NULL, 0x05 }, 180 { -1, 0, 0, NULL, 0 }, 181}; 182 183#ifdef INET6 184#define PTON_MAX 16 185#else 186#define PTON_MAX 4 187#endif 188 189static const ns_src default_dns_files[] = { 190 { NSSRC_FILES, NS_SUCCESS }, 191 { NSSRC_DNS, NS_SUCCESS }, 192 { 0 } 193}; 194 195#if PACKETSZ > 1024 196#define MAXPACKET PACKETSZ 197#else 198#define MAXPACKET 1024 199#endif 200 201typedef union { 202 HEADER hdr; 203 u_char buf[MAXPACKET]; 204} querybuf; 205 206struct res_target { 207 struct res_target *next; 208 const char *name; /* domain name */ 209 int qclass, qtype; /* class and type of query */ 210 u_char *answer; /* buffer to put answer */ 211 int anslen; /* size of answer buffer */ 212 int n; /* result length */ 213}; 214 215static int str_isnumber __P((const char *)); 216static int explore_fqdn __P((const struct addrinfo *, const char *, 217 const char *, struct addrinfo **)); 218static int explore_null __P((const struct addrinfo *, 219 const char *, struct addrinfo **)); 220static int explore_numeric __P((const struct addrinfo *, const char *, 221 const char *, struct addrinfo **)); 222static int explore_numeric_scope __P((const struct addrinfo *, const char *, 223 const char *, struct addrinfo **)); 224static int get_canonname __P((const struct addrinfo *, 225 struct addrinfo *, const char *)); 226static struct addrinfo *get_ai __P((const struct addrinfo *, 227 const struct afd *, const char *)); 228static int get_portmatch __P((const struct addrinfo *, const char *)); 229static int get_port __P((struct addrinfo *, const char *, int)); 230static const struct afd *find_afd __P((int)); 231static int addrconfig __P((struct addrinfo *)); 232#ifdef INET6 233static int ip6_str2scopeid __P((char *, struct sockaddr_in6 *)); 234#endif 235 236static struct addrinfo *getanswer __P((const querybuf *, int, const char *, int, 237 const struct addrinfo *)); 238static int _dns_getaddrinfo __P((void *, void *, va_list)); 239static void _sethtent __P((void)); 240static void _endhtent __P((void)); 241static struct addrinfo *_gethtent __P((const char *, const struct addrinfo *)); 242static int _files_getaddrinfo __P((void *, void *, va_list)); 243#ifdef YP 244static struct addrinfo *_yphostent __P((char *, const struct addrinfo *)); 245static int _yp_getaddrinfo __P((void *, void *, va_list)); 246#endif 247 248static int res_queryN __P((const char *, struct res_target *)); 249static int res_searchN __P((const char *, struct res_target *)); 250static int res_querydomainN __P((const char *, const char *, 251 struct res_target *)); 252 253static char *ai_errlist[] = { 254 "Success", 255 "Address family for hostname not supported", /* EAI_ADDRFAMILY */ 256 "Temporary failure in name resolution", /* EAI_AGAIN */ 257 "Invalid value for ai_flags", /* EAI_BADFLAGS */ 258 "Non-recoverable failure in name resolution", /* EAI_FAIL */ 259 "ai_family not supported", /* EAI_FAMILY */ 260 "Memory allocation failure", /* EAI_MEMORY */ 261 "No address associated with hostname", /* EAI_NODATA */ 262 "hostname nor servname provided, or not known", /* EAI_NONAME */ 263 "servname not supported for ai_socktype", /* EAI_SERVICE */ 264 "ai_socktype not supported", /* EAI_SOCKTYPE */ 265 "System error returned in errno", /* EAI_SYSTEM */ 266 "Invalid value for hints", /* EAI_BADHINTS */ 267 "Resolved protocol is unknown", /* EAI_PROTOCOL */ 268 "Unknown error", /* EAI_MAX */ 269}; 270 271/* XXX macros that make external reference is BAD. */ 272 273#define GET_AI(ai, afd, addr) \ 274do { \ 275 /* external reference: pai, error, and label free */ \ 276 (ai) = get_ai(pai, (afd), (addr)); \ 277 if ((ai) == NULL) { \ 278 error = EAI_MEMORY; \ 279 goto free; \ 280 } \ 281} while (/*CONSTCOND*/0) 282 283#define GET_PORT(ai, serv) \ 284do { \ 285 /* external reference: error and label free */ \ 286 error = get_port((ai), (serv), 0); \ 287 if (error != 0) \ 288 goto free; \ 289} while (/*CONSTCOND*/0) 290 291#define GET_CANONNAME(ai, str) \ 292do { \ 293 /* external reference: pai, error and label free */ \ 294 error = get_canonname(pai, (ai), (str)); \ 295 if (error != 0) \ 296 goto free; \ 297} while (/*CONSTCOND*/0) 298 299#define ERR(err) \ 300do { \ 301 /* external reference: error, and label bad */ \ 302 error = (err); \ 303 goto bad; \ 304 /*NOTREACHED*/ \ 305} while (/*CONSTCOND*/0) 306 307#define MATCH_FAMILY(x, y, w) \ 308 ((x) == (y) || (/*CONSTCOND*/(w) && ((x) == PF_UNSPEC || (y) == PF_UNSPEC))) 309#define MATCH(x, y, w) \ 310 ((x) == (y) || (/*CONSTCOND*/(w) && ((x) == ANY || (y) == ANY))) 311 312char * 313gai_strerror(ecode) 314 int ecode; 315{ 316 if (ecode < 0 || ecode > EAI_MAX) 317 ecode = EAI_MAX; 318 return ai_errlist[ecode]; 319} 320 321void 322freeaddrinfo(ai) 323 struct addrinfo *ai; 324{ 325 struct addrinfo *next; 326 327 do { 328 next = ai->ai_next; 329 if (ai->ai_canonname) 330 free(ai->ai_canonname); 331 /* no need to free(ai->ai_addr) */ 332 free(ai); 333 ai = next; 334 } while (ai); 335} 336 337static int 338str_isnumber(p) 339 const char *p; 340{ 341 char *ep; 342 343 if (*p == '\0') 344 return NO; 345 ep = NULL; 346 (void)strtoul(p, &ep, 10); 347 if (ep && *ep == '\0') 348 return YES; 349 else 350 return NO; 351} 352 353int 354getaddrinfo(hostname, servname, hints, res) 355 const char *hostname, *servname; 356 const struct addrinfo *hints; 357 struct addrinfo **res; 358{ 359 struct addrinfo sentinel; 360 struct addrinfo *cur; 361 int error = 0; 362 struct addrinfo ai; 363 struct addrinfo ai0; 364 struct addrinfo *pai; 365 const struct explore *ex; 366 367 memset(&sentinel, 0, sizeof(sentinel)); 368 cur = &sentinel; 369 pai = &ai; 370 pai->ai_flags = 0; 371 pai->ai_family = PF_UNSPEC; 372 pai->ai_socktype = ANY; 373 pai->ai_protocol = ANY; 374 pai->ai_addrlen = 0; 375 pai->ai_canonname = NULL; 376 pai->ai_addr = NULL; 377 pai->ai_next = NULL; 378 379 if (hostname == NULL && servname == NULL) 380 return EAI_NONAME; 381 if (hints) { 382 /* error check for hints */ 383 if (hints->ai_addrlen || hints->ai_canonname || 384 hints->ai_addr || hints->ai_next) 385 ERR(EAI_BADHINTS); /* xxx */ 386 if (hints->ai_flags & ~AI_MASK) 387 ERR(EAI_BADFLAGS); 388 switch (hints->ai_family) { 389 case PF_UNSPEC: 390 case PF_INET: 391#ifdef INET6 392 case PF_INET6: 393#endif 394 break; 395 default: 396 ERR(EAI_FAMILY); 397 } 398 memcpy(pai, hints, sizeof(*pai)); 399 400 /* 401 * if both socktype/protocol are specified, check if they 402 * are meaningful combination. 403 */ 404 if (pai->ai_socktype != ANY && pai->ai_protocol != ANY) { 405 for (ex = explore; ex->e_af >= 0; ex++) { 406 if (pai->ai_family != ex->e_af) 407 continue; 408 if (ex->e_socktype == ANY) 409 continue; 410 if (ex->e_protocol == ANY) 411 continue; 412 if (pai->ai_socktype == ex->e_socktype 413 && pai->ai_protocol != ex->e_protocol) { 414 ERR(EAI_BADHINTS); 415 } 416 } 417 } 418 } 419 420 /* 421 * post-2553: AI_ALL and AI_V4MAPPED are effective only against 422 * AF_INET6 query. They needs to be ignored if specified in other 423 * occassions. 424 */ 425 switch (pai->ai_flags & (AI_ALL | AI_V4MAPPED)) { 426 case AI_V4MAPPED: 427 case AI_ALL | AI_V4MAPPED: 428 if (pai->ai_family != AF_INET6) 429 pai->ai_flags &= ~(AI_ALL | AI_V4MAPPED); 430 break; 431 case AI_ALL: 432#if 1 433 /* illegal */ 434 ERR(EAI_BADFLAGS); 435#else 436 pai->ai_flags &= ~(AI_ALL | AI_V4MAPPED); 437#endif 438 break; 439 } 440 441 /* 442 * check for special cases. (1) numeric servname is disallowed if 443 * socktype/protocol are left unspecified. (2) servname is disallowed 444 * for raw and other inet{,6} sockets. 445 */ 446 if (MATCH_FAMILY(pai->ai_family, PF_INET, 1) 447#ifdef PF_INET6 448 || MATCH_FAMILY(pai->ai_family, PF_INET6, 1) 449#endif 450 ) { 451 ai0 = *pai; /* backup *pai */ 452 453 if (pai->ai_family == PF_UNSPEC) { 454#ifdef PF_INET6 455 pai->ai_family = PF_INET6; 456#else 457 pai->ai_family = PF_INET; 458#endif 459 } 460 error = get_portmatch(pai, servname); 461 if (error) 462 ERR(error); 463 464 *pai = ai0; 465 } 466 467 ai0 = *pai; 468 469 /* NULL hostname, or numeric hostname */ 470 for (ex = explore; ex->e_af >= 0; ex++) { 471 *pai = ai0; 472 473 /* PF_UNSPEC entries are prepared for DNS queries only */ 474 if (ex->e_af == PF_UNSPEC) 475 continue; 476 477 if (!MATCH_FAMILY(pai->ai_family, ex->e_af, WILD_AF(ex))) 478 continue; 479 if (!MATCH(pai->ai_socktype, ex->e_socktype, WILD_SOCKTYPE(ex))) 480 continue; 481 if (!MATCH(pai->ai_protocol, ex->e_protocol, WILD_PROTOCOL(ex))) 482 continue; 483 484 if (pai->ai_family == PF_UNSPEC) 485 pai->ai_family = ex->e_af; 486 if (pai->ai_socktype == ANY && ex->e_socktype != ANY) 487 pai->ai_socktype = ex->e_socktype; 488 if (pai->ai_protocol == ANY && ex->e_protocol != ANY) 489 pai->ai_protocol = ex->e_protocol; 490 491 if (hostname == NULL) 492 error = explore_null(pai, servname, &cur->ai_next); 493 else 494 error = explore_numeric_scope(pai, hostname, servname, &cur->ai_next); 495 496 if (error) 497 goto free; 498 499 while (cur && cur->ai_next) 500 cur = cur->ai_next; 501 } 502 503 /* 504 * XXX 505 * If numreic representation of AF1 can be interpreted as FQDN 506 * representation of AF2, we need to think again about the code below. 507 */ 508 if (sentinel.ai_next) 509 goto good; 510 511 if (pai->ai_flags & AI_NUMERICHOST) 512 ERR(EAI_NODATA); 513 if (hostname == NULL) 514 ERR(EAI_NODATA); 515 516 if ((pai->ai_flags & AI_ADDRCONFIG) != 0 && !addrconfig(&ai0)) 517 ERR(EAI_FAIL); 518 519 /* 520 * hostname as alphabetical name. 521 * we would like to prefer AF_INET6 than AF_INET, so we'll make a 522 * outer loop by AFs. 523 */ 524 for (ex = explore; ex->e_af >= 0; ex++) { 525 *pai = ai0; 526 527 /* require exact match for family field */ 528 if (pai->ai_family != ex->e_af) 529 continue; 530 531 if (!MATCH(pai->ai_socktype, ex->e_socktype, 532 WILD_SOCKTYPE(ex))) { 533 continue; 534 } 535 if (!MATCH(pai->ai_protocol, ex->e_protocol, 536 WILD_PROTOCOL(ex))) { 537 continue; 538 } 539 540 if (pai->ai_socktype == ANY && ex->e_socktype != ANY) 541 pai->ai_socktype = ex->e_socktype; 542 if (pai->ai_protocol == ANY && ex->e_protocol != ANY) 543 pai->ai_protocol = ex->e_protocol; 544 545 error = explore_fqdn(pai, hostname, servname, 546 &cur->ai_next); 547 548 while (cur && cur->ai_next) 549 cur = cur->ai_next; 550 } 551 552 /* XXX */ 553 if (sentinel.ai_next) 554 error = 0; 555 556 if (error) 557 goto free; 558 if (error == 0) { 559 if (sentinel.ai_next) { 560 good: 561 *res = sentinel.ai_next; 562 return SUCCESS; 563 } else 564 error = EAI_FAIL; 565 } 566 free: 567 bad: 568 if (sentinel.ai_next) 569 freeaddrinfo(sentinel.ai_next); 570 *res = NULL; 571 return error; 572} 573 574/* 575 * FQDN hostname, DNS lookup 576 */ 577static int 578explore_fqdn(pai, hostname, servname, res) 579 const struct addrinfo *pai; 580 const char *hostname; 581 const char *servname; 582 struct addrinfo **res; 583{ 584 struct addrinfo *result; 585 struct addrinfo *cur; 586 int error = 0; 587 static const ns_dtab dtab[] = { 588 NS_FILES_CB(_files_getaddrinfo, NULL) 589 { NSSRC_DNS, _dns_getaddrinfo, NULL }, /* force -DHESIOD */ 590 NS_NIS_CB(_yp_getaddrinfo, NULL) 591 { 0 } 592 }; 593 594 result = NULL; 595 596 /* 597 * if the servname does not match socktype/protocol, ignore it. 598 */ 599 if (get_portmatch(pai, servname) != 0) 600 return 0; 601 602 switch (nsdispatch(&result, dtab, NSDB_HOSTS, "getaddrinfo", 603 default_dns_files, hostname, pai)) { 604 case NS_TRYAGAIN: 605 error = EAI_AGAIN; 606 goto free; 607 case NS_UNAVAIL: 608 error = EAI_FAIL; 609 goto free; 610 case NS_NOTFOUND: 611 error = EAI_NODATA; 612 goto free; 613 case NS_SUCCESS: 614 error = 0; 615 for (cur = result; cur; cur = cur->ai_next) { 616 GET_PORT(cur, servname); 617 /* canonname should be filled already */ 618 } 619 break; 620 } 621 622 *res = result; 623 624 return 0; 625 626free: 627 if (result) 628 freeaddrinfo(result); 629 return error; 630} 631 632/* 633 * hostname == NULL. 634 * passive socket -> anyaddr (0.0.0.0 or ::) 635 * non-passive socket -> localhost (127.0.0.1 or ::1) 636 */ 637static int 638explore_null(pai, servname, res) 639 const struct addrinfo *pai; 640 const char *servname; 641 struct addrinfo **res; 642{ 643 int s; 644 const struct afd *afd; 645 struct addrinfo *cur; 646 struct addrinfo sentinel; 647 int error; 648 649 *res = NULL; 650 sentinel.ai_next = NULL; 651 cur = &sentinel; 652 653 /* 654 * filter out AFs that are not supported by the kernel 655 * XXX errno? 656 */ 657 s = _socket(pai->ai_family, SOCK_DGRAM, 0); 658 if (s < 0) { 659 if (errno != EMFILE) 660 return 0; 661 } else 662 _close(s); 663 664 /* 665 * if the servname does not match socktype/protocol, ignore it. 666 */ 667 if (get_portmatch(pai, servname) != 0) 668 return 0; 669 670 afd = find_afd(pai->ai_family); 671 if (afd == NULL) 672 return 0; 673 674 if (pai->ai_flags & AI_PASSIVE) { 675 GET_AI(cur->ai_next, afd, afd->a_addrany); 676 /* xxx meaningless? 677 * GET_CANONNAME(cur->ai_next, "anyaddr"); 678 */ 679 GET_PORT(cur->ai_next, servname); 680 } else { 681 GET_AI(cur->ai_next, afd, afd->a_loopback); 682 /* xxx meaningless? 683 * GET_CANONNAME(cur->ai_next, "localhost"); 684 */ 685 GET_PORT(cur->ai_next, servname); 686 } 687 cur = cur->ai_next; 688 689 *res = sentinel.ai_next; 690 return 0; 691 692free: 693 if (sentinel.ai_next) 694 freeaddrinfo(sentinel.ai_next); 695 return error; 696} 697 698/* 699 * numeric hostname 700 */ 701static int 702explore_numeric(pai, hostname, servname, res) 703 const struct addrinfo *pai; 704 const char *hostname; 705 const char *servname; 706 struct addrinfo **res; 707{ 708 const struct afd *afd; 709 struct addrinfo *cur; 710 struct addrinfo sentinel; 711 int error; 712 char pton[PTON_MAX]; 713 714 *res = NULL; 715 sentinel.ai_next = NULL; 716 cur = &sentinel; 717 718 /* 719 * if the servname does not match socktype/protocol, ignore it. 720 */ 721 if (get_portmatch(pai, servname) != 0) 722 return 0; 723 724 afd = find_afd(pai->ai_family); 725 if (afd == NULL) 726 return 0; 727 728 switch (afd->a_af) { 729#if 1 /*X/Open spec*/ 730 case AF_INET: 731 if (inet_aton(hostname, (struct in_addr *)pton) == 1) { 732 if (pai->ai_family == afd->a_af || 733 pai->ai_family == PF_UNSPEC /*?*/) { 734 GET_AI(cur->ai_next, afd, pton); 735 GET_PORT(cur->ai_next, servname); 736 while (cur && cur->ai_next) 737 cur = cur->ai_next; 738 } else 739 ERR(EAI_FAMILY); /*xxx*/ 740 } 741 break; 742#endif 743 default: 744 if (inet_pton(afd->a_af, hostname, pton) == 1) { 745 if (pai->ai_family == afd->a_af || 746 pai->ai_family == PF_UNSPEC /*?*/) { 747 GET_AI(cur->ai_next, afd, pton); 748 GET_PORT(cur->ai_next, servname); 749 while (cur && cur->ai_next) 750 cur = cur->ai_next; 751 } else 752 ERR(EAI_FAMILY); /*xxx*/ 753 } 754 break; 755 } 756 757 *res = sentinel.ai_next; 758 return 0; 759 760free: 761bad: 762 if (sentinel.ai_next) 763 freeaddrinfo(sentinel.ai_next); 764 return error; 765} 766 767/* 768 * numeric hostname with scope 769 */ 770static int 771explore_numeric_scope(pai, hostname, servname, res) 772 const struct addrinfo *pai; 773 const char *hostname; 774 const char *servname; 775 struct addrinfo **res; 776{ 777#if !defined(SCOPE_DELIMITER) || !defined(INET6) 778 return explore_numeric(pai, hostname, servname, res); 779#else 780 const struct afd *afd; 781 struct addrinfo *cur; 782 int error; 783 char *cp, *hostname2 = NULL, *scope, *addr; 784 struct sockaddr_in6 *sin6; 785 786 /* 787 * if the servname does not match socktype/protocol, ignore it. 788 */ 789 if (get_portmatch(pai, servname) != 0) 790 return 0; 791 792 afd = find_afd(pai->ai_family); 793 if (afd == NULL) 794 return 0; 795 796 if (!afd->a_scoped) 797 return explore_numeric(pai, hostname, servname, res); 798 799 cp = strchr(hostname, SCOPE_DELIMITER); 800 if (cp == NULL) 801 return explore_numeric(pai, hostname, servname, res); 802 803 /* 804 * Handle special case of <scoped_address><delimiter><scope id> 805 */ 806 hostname2 = strdup(hostname); 807 if (hostname2 == NULL) 808 return EAI_MEMORY; 809 /* terminate at the delimiter */ 810 hostname2[cp - hostname] = '\0'; 811 addr = hostname2; 812 scope = cp + 1; 813 814 error = explore_numeric(pai, addr, servname, res); 815 if (error == 0) { 816 int scopeid; 817 818 for (cur = *res; cur; cur = cur->ai_next) { 819 if (cur->ai_family != AF_INET6) 820 continue; 821 sin6 = (struct sockaddr_in6 *)(void *)cur->ai_addr; 822 if ((scopeid = ip6_str2scopeid(scope, sin6)) == -1) { 823 free(hostname2); 824 return(EAI_NODATA); /* XXX: is return OK? */ 825 } 826 sin6->sin6_scope_id = scopeid; 827 } 828 } 829 830 free(hostname2); 831 832 return error; 833#endif 834} 835 836static int 837get_canonname(pai, ai, str) 838 const struct addrinfo *pai; 839 struct addrinfo *ai; 840 const char *str; 841{ 842 if ((pai->ai_flags & AI_CANONNAME) != 0) { 843 ai->ai_canonname = (char *)malloc(strlen(str) + 1); 844 if (ai->ai_canonname == NULL) 845 return EAI_MEMORY; 846 strcpy(ai->ai_canonname, str); 847 } 848 return 0; 849} 850 851static struct addrinfo * 852get_ai(pai, afd, addr) 853 const struct addrinfo *pai; 854 const struct afd *afd; 855 const char *addr; 856{ 857 char *p; 858 struct addrinfo *ai; 859#ifdef FAITH 860 struct in6_addr faith_prefix; 861 char *fp_str; 862 int translate = 0; 863#endif 864 865#ifdef FAITH 866 /* 867 * Transfrom an IPv4 addr into a special IPv6 addr format for 868 * IPv6->IPv4 translation gateway. (only TCP is supported now) 869 * 870 * +-----------------------------------+------------+ 871 * | faith prefix part (12 bytes) | embedded | 872 * | | IPv4 addr part (4 bytes) 873 * +-----------------------------------+------------+ 874 * 875 * faith prefix part is specified as ascii IPv6 addr format 876 * in environmental variable GAI. 877 * For FAITH to work correctly, routing to faith prefix must be 878 * setup toward a machine where a FAITH daemon operates. 879 * Also, the machine must enable some mechanizm 880 * (e.g. faith interface hack) to divert those packet with 881 * faith prefixed destination addr to user-land FAITH daemon. 882 */ 883 fp_str = getenv("GAI"); 884 if (fp_str && inet_pton(AF_INET6, fp_str, &faith_prefix) == 1 && 885 afd->a_af == AF_INET && pai->ai_socktype == SOCK_STREAM) { 886 u_int32_t v4a; 887 u_int8_t v4a_top; 888 889 memcpy(&v4a, addr, sizeof v4a); 890 v4a_top = v4a >> IN_CLASSA_NSHIFT; 891 if (!IN_MULTICAST(v4a) && !IN_EXPERIMENTAL(v4a) && 892 v4a_top != 0 && v4a != IN_LOOPBACKNET) { 893 afd = &afdl[N_INET6]; 894 memcpy(&faith_prefix.s6_addr[12], addr, 895 sizeof(struct in_addr)); 896 translate = 1; 897 } 898 } 899#endif 900 901 ai = (struct addrinfo *)malloc(sizeof(struct addrinfo) 902 + (afd->a_socklen)); 903 if (ai == NULL) 904 return NULL; 905 906 memcpy(ai, pai, sizeof(struct addrinfo)); 907 ai->ai_addr = (struct sockaddr *)(void *)(ai + 1); 908 memset(ai->ai_addr, 0, (size_t)afd->a_socklen); 909 ai->ai_addr->sa_len = afd->a_socklen; 910 ai->ai_addrlen = afd->a_socklen; 911 ai->ai_addr->sa_family = ai->ai_family = afd->a_af; 912 p = (char *)(void *)(ai->ai_addr); 913#ifdef FAITH 914 if (translate == 1) 915 memcpy(p + afd->a_off, &faith_prefix, (size_t)afd->a_addrlen); 916 else 917#endif 918 memcpy(p + afd->a_off, addr, (size_t)afd->a_addrlen); 919 return ai; 920} 921 922static int 923get_portmatch(ai, servname) 924 const struct addrinfo *ai; 925 const char *servname; 926{ 927 928 /* get_port does not touch first argument. when matchonly == 1. */ 929 /* LINTED const cast */ 930 return get_port((struct addrinfo *)ai, servname, 1); 931} 932 933static int 934get_port(ai, servname, matchonly) 935 struct addrinfo *ai; 936 const char *servname; 937 int matchonly; 938{ 939 const char *proto; 940 struct servent *sp; 941 int port; 942 int allownumeric; 943 944 if (servname == NULL) 945 return 0; 946 switch (ai->ai_family) { 947 case AF_INET: 948#ifdef AF_INET6 949 case AF_INET6: 950#endif 951 break; 952 default: 953 return 0; 954 } 955 956 switch (ai->ai_socktype) { 957 case SOCK_RAW: 958 return EAI_SERVICE; 959 case SOCK_DGRAM: 960 case SOCK_STREAM: 961 allownumeric = 1; 962 break; 963 case ANY: 964 allownumeric = 0; 965 break; 966 default: 967 return EAI_SOCKTYPE; 968 } 969 970 if (str_isnumber(servname)) { 971 if (!allownumeric) 972 return EAI_SERVICE; 973 port = htons(atoi(servname)); 974 if (port < 0 || port > 65535) 975 return EAI_SERVICE; 976 } else { 977 switch (ai->ai_socktype) { 978 case SOCK_DGRAM: 979 proto = "udp"; 980 break; 981 case SOCK_STREAM: 982 proto = "tcp"; 983 break; 984 default: 985 proto = NULL; 986 break; 987 } 988 989 if ((sp = getservbyname(servname, proto)) == NULL) 990 return EAI_SERVICE; 991 port = sp->s_port; 992 } 993 994 if (!matchonly) { 995 switch (ai->ai_family) { 996 case AF_INET: 997 ((struct sockaddr_in *)(void *) 998 ai->ai_addr)->sin_port = port; 999 break; 1000#ifdef INET6 1001 case AF_INET6: 1002 ((struct sockaddr_in6 *)(void *) 1003 ai->ai_addr)->sin6_port = port; 1004 break; 1005#endif 1006 } 1007 } 1008 1009 return 0; 1010} 1011 1012static const struct afd * 1013find_afd(af) 1014 int af; 1015{ 1016 const struct afd *afd; 1017 1018 if (af == PF_UNSPEC) 1019 return NULL; 1020 for (afd = afdl; afd->a_af; afd++) { 1021 if (afd->a_af == af) 1022 return afd; 1023 } 1024 return NULL; 1025} 1026 1027/* 1028 * post-2553: AI_ADDRCONFIG check. if we use getipnodeby* as backend, backend 1029 * will take care of it. 1030 * the semantics of AI_ADDRCONFIG is not defined well. we are not sure 1031 * if the code is right or not. 1032 * 1033 * XXX PF_UNSPEC -> PF_INET6 + PF_INET mapping needs to be in sync with 1034 * _dns_getaddrinfo. 1035 */ 1036static int 1037addrconfig(pai) 1038 struct addrinfo *pai; 1039{ 1040 int s, af; 1041 1042 /* 1043 * TODO: 1044 * Note that implementation dependent test for address 1045 * configuration should be done everytime called 1046 * (or apropriate interval), 1047 * because addresses will be dynamically assigned or deleted. 1048 */ 1049 af = pai->ai_family; 1050 if (af == AF_UNSPEC) { 1051 if ((s = _socket(AF_INET6, SOCK_DGRAM, 0)) < 0) 1052 af = AF_INET; 1053 else { 1054 _close(s); 1055 if ((s = _socket(AF_INET, SOCK_DGRAM, 0)) < 0) 1056 af = AF_INET6; 1057 else 1058 _close(s); 1059 } 1060 } 1061 if (af != AF_UNSPEC) { 1062 if ((s = _socket(af, SOCK_DGRAM, 0)) < 0) 1063 return 0; 1064 _close(s); 1065 } 1066 pai->ai_family = af; 1067 return 1; 1068} 1069 1070#ifdef INET6 1071/* convert a string to a scope identifier. XXX: IPv6 specific */ 1072static int 1073ip6_str2scopeid(scope, sin6) 1074 char *scope; 1075 struct sockaddr_in6 *sin6; 1076{ 1077 int scopeid; 1078 struct in6_addr *a6 = &sin6->sin6_addr; 1079 char *ep; 1080 1081 /* empty scopeid portion is invalid */ 1082 if (*scope == '\0') 1083 return -1; 1084 1085 if (IN6_IS_ADDR_LINKLOCAL(a6) || IN6_IS_ADDR_MC_LINKLOCAL(a6)) { 1086 /* 1087 * We currently assume a one-to-one mapping between links 1088 * and interfaces, so we simply use interface indices for 1089 * like-local scopes. 1090 */ 1091 scopeid = if_nametoindex(scope); 1092 if (scopeid == 0) 1093 goto trynumeric; 1094 return(scopeid); 1095 } 1096 1097 /* still unclear about literal, allow numeric only - placeholder */ 1098 if (IN6_IS_ADDR_SITELOCAL(a6) || IN6_IS_ADDR_MC_SITELOCAL(a6)) 1099 goto trynumeric; 1100 if (IN6_IS_ADDR_MC_ORGLOCAL(a6)) 1101 goto trynumeric; 1102 else 1103 goto trynumeric; /* global */ 1104 1105 /* try to convert to a numeric id as a last resort */ 1106 trynumeric: 1107 scopeid = (int)strtoul(scope, &ep, 10); 1108 if (*ep == '\0') 1109 return scopeid; 1110 else 1111 return -1; 1112} 1113#endif 1114 1115#ifdef DEBUG 1116static const char AskedForGot[] = 1117 "gethostby*.getanswer: asked for \"%s\", got \"%s\""; 1118#endif 1119static FILE *hostf = NULL; 1120 1121static struct addrinfo * 1122getanswer(answer, anslen, qname, qtype, pai) 1123 const querybuf *answer; 1124 int anslen; 1125 const char *qname; 1126 int qtype; 1127 const struct addrinfo *pai; 1128{ 1129 struct addrinfo sentinel, *cur; 1130 struct addrinfo ai; 1131 const struct afd *afd; 1132 char *canonname; 1133 const HEADER *hp; 1134 const u_char *cp; 1135 int n; 1136 const u_char *eom; 1137 char *bp; 1138 int type, class, buflen, ancount, qdcount; 1139 int haveanswer, had_error; 1140 char tbuf[MAXDNAME]; 1141 int (*name_ok) __P((const char *)); 1142 char hostbuf[8*1024]; 1143 1144 memset(&sentinel, 0, sizeof(sentinel)); 1145 cur = &sentinel; 1146 1147 canonname = NULL; 1148 eom = answer->buf + anslen; 1149 switch (qtype) { 1150 case T_A: 1151 case T_AAAA: 1152 case T_ANY: /*use T_ANY only for T_A/T_AAAA lookup*/ 1153 name_ok = res_hnok; 1154 break; 1155 default: 1156 return (NULL); /* XXX should be abort(); */ 1157 } 1158 /* 1159 * find first satisfactory answer 1160 */ 1161 hp = &answer->hdr; 1162 ancount = ntohs(hp->ancount); 1163 qdcount = ntohs(hp->qdcount); 1164 bp = hostbuf; 1165 buflen = sizeof hostbuf; 1166 cp = answer->buf + HFIXEDSZ; 1167 if (qdcount != 1) { 1168 h_errno = NO_RECOVERY; 1169 return (NULL); 1170 } 1171 n = dn_expand(answer->buf, eom, cp, bp, buflen); 1172 if ((n < 0) || !(*name_ok)(bp)) { 1173 h_errno = NO_RECOVERY; 1174 return (NULL); 1175 } 1176 cp += n + QFIXEDSZ; 1177 if (qtype == T_A || qtype == T_AAAA || qtype == T_ANY) { 1178 /* res_send() has already verified that the query name is the 1179 * same as the one we sent; this just gets the expanded name 1180 * (i.e., with the succeeding search-domain tacked on). 1181 */ 1182 n = strlen(bp) + 1; /* for the \0 */ 1183 if (n >= MAXHOSTNAMELEN) { 1184 h_errno = NO_RECOVERY; 1185 return (NULL); 1186 } 1187 canonname = bp; 1188 bp += n; 1189 buflen -= n; 1190 /* The qname can be abbreviated, but h_name is now absolute. */ 1191 qname = canonname; 1192 } 1193 haveanswer = 0; 1194 had_error = 0; 1195 while (ancount-- > 0 && cp < eom && !had_error) { 1196 n = dn_expand(answer->buf, eom, cp, bp, buflen); 1197 if ((n < 0) || !(*name_ok)(bp)) { 1198 had_error++; 1199 continue; 1200 } 1201 cp += n; /* name */ 1202 type = _getshort(cp); 1203 cp += INT16SZ; /* type */ 1204 class = _getshort(cp); 1205 cp += INT16SZ + INT32SZ; /* class, TTL */ 1206 n = _getshort(cp); 1207 cp += INT16SZ; /* len */ 1208 if (class != C_IN) { 1209 /* XXX - debug? syslog? */ 1210 cp += n; 1211 continue; /* XXX - had_error++ ? */ 1212 } 1213 if ((qtype == T_A || qtype == T_AAAA || qtype == T_ANY) && 1214 type == T_CNAME) { 1215 n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf); 1216 if ((n < 0) || !(*name_ok)(tbuf)) { 1217 had_error++; 1218 continue; 1219 } 1220 cp += n; 1221 /* Get canonical name. */ 1222 n = strlen(tbuf) + 1; /* for the \0 */ 1223 if (n > buflen || n >= MAXHOSTNAMELEN) { 1224 had_error++; 1225 continue; 1226 } 1227 strcpy(bp, tbuf); 1228 canonname = bp; 1229 bp += n; 1230 buflen -= n; 1231 continue; 1232 } 1233 if (qtype == T_ANY) { 1234 if (!(type == T_A || type == T_AAAA)) { 1235 cp += n; 1236 continue; 1237 } 1238 } else if (type != qtype) { 1239#ifdef DEBUG 1240 if (type != T_KEY && type != T_SIG) 1241 syslog(LOG_NOTICE|LOG_AUTH, 1242 "gethostby*.getanswer: asked for \"%s %s %s\", got type \"%s\"", 1243 qname, p_class(C_IN), p_type(qtype), 1244 p_type(type)); 1245#endif 1246 cp += n; 1247 continue; /* XXX - had_error++ ? */ 1248 } 1249 switch (type) { 1250 case T_A: 1251 case T_AAAA: 1252 if (strcasecmp(canonname, bp) != 0) { 1253#ifdef DEBUG 1254 syslog(LOG_NOTICE|LOG_AUTH, 1255 AskedForGot, canonname, bp); 1256#endif 1257 cp += n; 1258 continue; /* XXX - had_error++ ? */ 1259 } 1260 if (type == T_A && n != INADDRSZ) { 1261 cp += n; 1262 continue; 1263 } 1264 if (type == T_AAAA && n != IN6ADDRSZ) { 1265 cp += n; 1266 continue; 1267 } 1268#ifdef FILTER_V4MAPPED 1269 if (type == T_AAAA) { 1270 struct in6_addr in6; 1271 memcpy(&in6, cp, sizeof(in6)); 1272 if (IN6_IS_ADDR_V4MAPPED(&in6)) { 1273 cp += n; 1274 continue; 1275 } 1276 } 1277#endif 1278 if (!haveanswer) { 1279 int nn; 1280 1281 canonname = bp; 1282 nn = strlen(bp) + 1; /* for the \0 */ 1283 bp += nn; 1284 buflen -= nn; 1285 } 1286 1287 /* don't overwrite pai */ 1288 ai = *pai; 1289 ai.ai_family = (type == T_A) ? AF_INET : AF_INET6; 1290 afd = find_afd(ai.ai_family); 1291 if (afd == NULL) { 1292 cp += n; 1293 continue; 1294 } 1295 cur->ai_next = get_ai(&ai, afd, (const char *)cp); 1296 if (cur->ai_next == NULL) 1297 had_error++; 1298 while (cur && cur->ai_next) 1299 cur = cur->ai_next; 1300 cp += n; 1301 break; 1302 default: 1303 abort(); 1304 } 1305 if (!had_error) 1306 haveanswer++; 1307 } 1308 if (haveanswer) { 1309 if (!canonname) 1310 (void)get_canonname(pai, sentinel.ai_next, qname); 1311 else 1312 (void)get_canonname(pai, sentinel.ai_next, canonname); 1313 h_errno = NETDB_SUCCESS; 1314 return sentinel.ai_next; 1315 } 1316 1317 h_errno = NO_RECOVERY; 1318 return NULL; 1319} 1320 1321/*ARGSUSED*/ 1322static int 1323_dns_getaddrinfo(rv, cb_data, ap) 1324 void *rv; 1325 void *cb_data; 1326 va_list ap; 1327{ 1328 struct addrinfo *ai; 1329 querybuf buf, buf2; 1330 const char *name; 1331 const struct addrinfo *pai; 1332 struct addrinfo sentinel, *cur; 1333 struct res_target q, q2; 1334 1335 name = va_arg(ap, char *); 1336 pai = va_arg(ap, const struct addrinfo *); 1337 1338 memset(&q, 0, sizeof(q2)); 1339 memset(&q2, 0, sizeof(q2)); 1340 memset(&sentinel, 0, sizeof(sentinel)); 1341 cur = &sentinel; 1342 1343 switch (pai->ai_family) { 1344 case AF_UNSPEC: 1345 /* prefer IPv6 */ 1346 q.qclass = C_IN; 1347 q.qtype = T_AAAA; 1348 q.answer = buf.buf; 1349 q.anslen = sizeof(buf); 1350 q.next = &q2; 1351 q2.qclass = C_IN; 1352 q2.qtype = T_A; 1353 q2.answer = buf2.buf; 1354 q2.anslen = sizeof(buf2); 1355 break; 1356 case AF_INET: 1357 q.qclass = C_IN; 1358 q.qtype = T_A; 1359 q.answer = buf.buf; 1360 q.anslen = sizeof(buf); 1361 break; 1362 case AF_INET6: 1363 q.qclass = C_IN; 1364 q.qtype = T_AAAA; 1365 q.answer = buf.buf; 1366 q.anslen = sizeof(buf); 1367 break; 1368 default: 1369 return NS_UNAVAIL; 1370 } 1371 if (res_searchN(name, &q) < 0) 1372 return NS_NOTFOUND; 1373 ai = getanswer(&buf, q.n, q.name, q.qtype, pai); 1374 if (ai) { 1375 cur->ai_next = ai; 1376 while (cur && cur->ai_next) 1377 cur = cur->ai_next; 1378 } 1379 if (q.next) { 1380 ai = getanswer(&buf2, q2.n, q2.name, q2.qtype, pai); 1381 if (ai) 1382 cur->ai_next = ai; 1383 } 1384 if (sentinel.ai_next == NULL) 1385 switch (h_errno) { 1386 case HOST_NOT_FOUND: 1387 return NS_NOTFOUND; 1388 case TRY_AGAIN: 1389 return NS_TRYAGAIN; 1390 default: 1391 return NS_UNAVAIL; 1392 } 1393 *((struct addrinfo **)rv) = sentinel.ai_next; 1394 return NS_SUCCESS; 1395} 1396 1397static void 1398_sethtent() 1399{ 1400 if (!hostf) 1401 hostf = fopen(_PATH_HOSTS, "r" ); 1402 else 1403 rewind(hostf); 1404} 1405 1406static void 1407_endhtent() 1408{ 1409 if (hostf) { 1410 (void) fclose(hostf); 1411 hostf = NULL; 1412 } 1413} 1414 1415static struct addrinfo * 1416_gethtent(name, pai) 1417 const char *name; 1418 const struct addrinfo *pai; 1419{ 1420 char *p; 1421 char *cp, *tname, *cname; 1422 struct addrinfo hints, *res0, *res; 1423 int error; 1424 const char *addr; 1425 char hostbuf[8*1024]; 1426 1427 if (!hostf && !(hostf = fopen(_PATH_HOSTS, "r" ))) 1428 return (NULL); 1429 again: 1430 if (!(p = fgets(hostbuf, sizeof hostbuf, hostf))) 1431 return (NULL); 1432 if (*p == '#') 1433 goto again; 1434 if (!(cp = strpbrk(p, "#\n"))) 1435 goto again; 1436 *cp = '\0'; 1437 if (!(cp = strpbrk(p, " \t"))) 1438 goto again; 1439 *cp++ = '\0'; 1440 addr = p; 1441 cname = NULL; 1442 /* if this is not something we're looking for, skip it. */ 1443 while (cp && *cp) { 1444 if (*cp == ' ' || *cp == '\t') { 1445 cp++; 1446 continue; 1447 } 1448 tname = cp; 1449 if (cname == NULL) 1450 cname = cp; 1451 if ((cp = strpbrk(cp, " \t")) != NULL) 1452 *cp++ = '\0'; 1453 if (strcasecmp(name, tname) == 0) 1454 goto found; 1455 } 1456 goto again; 1457 1458found: 1459 hints = *pai; 1460 hints.ai_flags = AI_NUMERICHOST; 1461 error = getaddrinfo(addr, NULL, &hints, &res0); 1462 if (error) 1463 goto again; 1464#ifdef FILTER_V4MAPPED 1465 /* XXX should check all items in the chain */ 1466 if (res0->ai_family == AF_INET6 && 1467 IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)res0->ai_addr)->sin6_addr)) { 1468 freeaddrinfo(res0); 1469 goto again; 1470 } 1471#endif 1472 for (res = res0; res; res = res->ai_next) { 1473 /* cover it up */ 1474 res->ai_flags = pai->ai_flags; 1475 1476 if (pai->ai_flags & AI_CANONNAME) { 1477 if (get_canonname(pai, res, cname) != 0) { 1478 freeaddrinfo(res0); 1479 goto again; 1480 } 1481 } 1482 } 1483 return res0; 1484} 1485 1486/*ARGSUSED*/ 1487static int 1488_files_getaddrinfo(rv, cb_data, ap) 1489 void *rv; 1490 void *cb_data; 1491 va_list ap; 1492{ 1493 const char *name; 1494 const struct addrinfo *pai; 1495 struct addrinfo sentinel, *cur; 1496 struct addrinfo *p; 1497 1498 name = va_arg(ap, char *); 1499 pai = va_arg(ap, struct addrinfo *); 1500 1501 memset(&sentinel, 0, sizeof(sentinel)); 1502 cur = &sentinel; 1503 1504 _sethtent(); 1505 while ((p = _gethtent(name, pai)) != NULL) { 1506 cur->ai_next = p; 1507 while (cur && cur->ai_next) 1508 cur = cur->ai_next; 1509 } 1510 _endhtent(); 1511 1512 *((struct addrinfo **)rv) = sentinel.ai_next; 1513 if (sentinel.ai_next == NULL) 1514 return NS_NOTFOUND; 1515 return NS_SUCCESS; 1516} 1517 1518#ifdef YP 1519static char *__ypdomain; 1520 1521/*ARGSUSED*/ 1522static struct addrinfo * 1523_yphostent(line, pai) 1524 char *line; 1525 const struct addrinfo *pai; 1526{ 1527 struct addrinfo sentinel, *cur; 1528 struct addrinfo hints, *res, *res0; 1529 int error; 1530 char *p = line; 1531 const char *addr, *canonname; 1532 char *nextline; 1533 char *cp; 1534 1535 addr = canonname = NULL; 1536 1537 memset(&sentinel, 0, sizeof(sentinel)); 1538 cur = &sentinel; 1539 1540nextline: 1541 /* terminate line */ 1542 cp = strchr(p, '\n'); 1543 if (cp) { 1544 *cp++ = '\0'; 1545 nextline = cp; 1546 } else 1547 nextline = NULL; 1548 1549 cp = strpbrk(p, " \t"); 1550 if (cp == NULL) { 1551 if (canonname == NULL) 1552 return (NULL); 1553 else 1554 goto done; 1555 } 1556 *cp++ = '\0'; 1557 1558 addr = p; 1559 1560 while (cp && *cp) { 1561 if (*cp == ' ' || *cp == '\t') { 1562 cp++; 1563 continue; 1564 } 1565 if (!canonname) 1566 canonname = cp; 1567 if ((cp = strpbrk(cp, " \t")) != NULL) 1568 *cp++ = '\0'; 1569 } 1570 1571 hints = *pai; 1572 hints.ai_flags = AI_NUMERICHOST; 1573 error = getaddrinfo(addr, NULL, &hints, &res0); 1574 if (error == 0) { 1575 for (res = res0; res; res = res->ai_next) { 1576 /* cover it up */ 1577 res->ai_flags = pai->ai_flags; 1578 1579 if (pai->ai_flags & AI_CANONNAME) 1580 (void)get_canonname(pai, res, canonname); 1581 } 1582 } else 1583 res0 = NULL; 1584 if (res0) { 1585 cur->ai_next = res0; 1586 while (cur && cur->ai_next) 1587 cur = cur->ai_next; 1588 } 1589 1590 if (nextline) { 1591 p = nextline; 1592 goto nextline; 1593 } 1594 1595done: 1596 return sentinel.ai_next; 1597} 1598 1599/*ARGSUSED*/ 1600static int 1601_yp_getaddrinfo(rv, cb_data, ap) 1602 void *rv; 1603 void *cb_data; 1604 va_list ap; 1605{ 1606 struct addrinfo sentinel, *cur; 1607 struct addrinfo *ai = NULL; 1608 static char *__ypcurrent; 1609 int __ypcurrentlen, r; 1610 const char *name; 1611 const struct addrinfo *pai; 1612 1613 name = va_arg(ap, char *); 1614 pai = va_arg(ap, const struct addrinfo *); 1615 1616 memset(&sentinel, 0, sizeof(sentinel)); 1617 cur = &sentinel; 1618 1619 if (!__ypdomain) { 1620 if (_yp_check(&__ypdomain) == 0) 1621 return NS_UNAVAIL; 1622 } 1623 if (__ypcurrent) 1624 free(__ypcurrent); 1625 __ypcurrent = NULL; 1626 1627 /* hosts.byname is only for IPv4 (Solaris8) */ 1628 if (pai->ai_family == PF_UNSPEC || pai->ai_family == PF_INET) { 1629 r = yp_match(__ypdomain, "hosts.byname", name, 1630 (int)strlen(name), &__ypcurrent, &__ypcurrentlen); 1631 if (r == 0) { 1632 struct addrinfo ai4; 1633 1634 ai4 = *pai; 1635 ai4.ai_family = AF_INET; 1636 ai = _yphostent(__ypcurrent, &ai4); 1637 if (ai) { 1638 cur->ai_next = ai; 1639 while (cur && cur->ai_next) 1640 cur = cur->ai_next; 1641 } 1642 } 1643 } 1644 1645 /* ipnodes.byname can hold both IPv4/v6 */ 1646 r = yp_match(__ypdomain, "ipnodes.byname", name, 1647 (int)strlen(name), &__ypcurrent, &__ypcurrentlen); 1648 if (r == 0) { 1649 ai = _yphostent(__ypcurrent, pai); 1650 if (ai) { 1651 cur->ai_next = ai; 1652 while (cur && cur->ai_next) 1653 cur = cur->ai_next; 1654 } 1655 } 1656 1657 if (sentinel.ai_next == NULL) { 1658 h_errno = HOST_NOT_FOUND; 1659 return NS_NOTFOUND; 1660 } 1661 *((struct addrinfo **)rv) = sentinel.ai_next; 1662 return NS_SUCCESS; 1663} 1664#endif 1665 1666/* resolver logic */ 1667 1668extern const char *__hostalias __P((const char *)); 1669extern int h_errno; 1670 1671/* 1672 * Formulate a normal query, send, and await answer. 1673 * Returned answer is placed in supplied buffer "answer". 1674 * Perform preliminary check of answer, returning success only 1675 * if no error is indicated and the answer count is nonzero. 1676 * Return the size of the response on success, -1 on error. 1677 * Error number is left in h_errno. 1678 * 1679 * Caller must parse answer and determine whether it answers the question. 1680 */ 1681static int 1682res_queryN(name, target) 1683 const char *name; /* domain name */ 1684 struct res_target *target; 1685{ 1686 u_char buf[MAXPACKET]; 1687 HEADER *hp; 1688 int n; 1689 struct res_target *t; 1690 int rcode; 1691 int ancount; 1692 1693 rcode = NOERROR; 1694 ancount = 0; 1695 1696 if ((_res.options & RES_INIT) == 0 && res_init() == -1) { 1697 h_errno = NETDB_INTERNAL; 1698 return (-1); 1699 } 1700 1701 for (t = target; t; t = t->next) { 1702 int class, type; 1703 u_char *answer; 1704 int anslen; 1705 1706 hp = (HEADER *)(void *)t->answer; 1707 hp->rcode = NOERROR; /* default */ 1708 1709 /* make it easier... */ 1710 class = t->qclass; 1711 type = t->qtype; 1712 answer = t->answer; 1713 anslen = t->anslen; 1714#ifdef DEBUG 1715 if (_res.options & RES_DEBUG) 1716 printf(";; res_query(%s, %d, %d)\n", name, class, type); 1717#endif 1718 1719 n = res_mkquery(QUERY, name, class, type, NULL, 0, NULL, 1720 buf, sizeof(buf));
| 106 107#include <syslog.h> 108#include <stdarg.h> 109#include <nsswitch.h> 110#include "un-namespace.h" 111 112#if defined(__KAME__) && defined(INET6) 113# define FAITH 114#endif 115 116#define SUCCESS 0 117#define ANY 0 118#define YES 1 119#define NO 0 120 121static const char in_addrany[] = { 0, 0, 0, 0 }; 122static const char in6_addrany[] = { 123 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 124}; 125static const char in_loopback[] = { 127, 0, 0, 1 }; 126static const char in6_loopback[] = { 127 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 128}; 129 130static const struct afd { 131 int a_af; 132 int a_addrlen; 133 int a_socklen; 134 int a_off; 135 const char *a_addrany; 136 const char *a_loopback; 137 int a_scoped; 138} afdl [] = { 139#ifdef INET6 140#define N_INET6 0 141 {PF_INET6, sizeof(struct in6_addr), 142 sizeof(struct sockaddr_in6), 143 offsetof(struct sockaddr_in6, sin6_addr), 144 in6_addrany, in6_loopback, 1}, 145#define N_INET 1 146#else 147#define N_INET 0 148#endif 149 {PF_INET, sizeof(struct in_addr), 150 sizeof(struct sockaddr_in), 151 offsetof(struct sockaddr_in, sin_addr), 152 in_addrany, in_loopback, 0}, 153 {0, 0, 0, 0, NULL, NULL, 0}, 154}; 155 156struct explore { 157 int e_af; 158 int e_socktype; 159 int e_protocol; 160 const char *e_protostr; 161 int e_wild; 162#define WILD_AF(ex) ((ex)->e_wild & 0x01) 163#define WILD_SOCKTYPE(ex) ((ex)->e_wild & 0x02) 164#define WILD_PROTOCOL(ex) ((ex)->e_wild & 0x04) 165}; 166 167static const struct explore explore[] = { 168#if 0 169 { PF_LOCAL, 0, ANY, ANY, NULL, 0x01 }, 170#endif 171#ifdef INET6 172 { PF_INET6, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 }, 173 { PF_INET6, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 }, 174 { PF_INET6, SOCK_RAW, ANY, NULL, 0x05 }, 175#endif 176 { PF_INET, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 }, 177 { PF_INET, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 }, 178 { PF_INET, SOCK_RAW, ANY, NULL, 0x05 }, 179 { PF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 }, 180 { PF_UNSPEC, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 }, 181 { PF_UNSPEC, SOCK_RAW, ANY, NULL, 0x05 }, 182 { -1, 0, 0, NULL, 0 }, 183}; 184 185#ifdef INET6 186#define PTON_MAX 16 187#else 188#define PTON_MAX 4 189#endif 190 191static const ns_src default_dns_files[] = { 192 { NSSRC_FILES, NS_SUCCESS }, 193 { NSSRC_DNS, NS_SUCCESS }, 194 { 0 } 195}; 196 197#if PACKETSZ > 1024 198#define MAXPACKET PACKETSZ 199#else 200#define MAXPACKET 1024 201#endif 202 203typedef union { 204 HEADER hdr; 205 u_char buf[MAXPACKET]; 206} querybuf; 207 208struct res_target { 209 struct res_target *next; 210 const char *name; /* domain name */ 211 int qclass, qtype; /* class and type of query */ 212 u_char *answer; /* buffer to put answer */ 213 int anslen; /* size of answer buffer */ 214 int n; /* result length */ 215}; 216 217static int str_isnumber __P((const char *)); 218static int explore_fqdn __P((const struct addrinfo *, const char *, 219 const char *, struct addrinfo **)); 220static int explore_null __P((const struct addrinfo *, 221 const char *, struct addrinfo **)); 222static int explore_numeric __P((const struct addrinfo *, const char *, 223 const char *, struct addrinfo **)); 224static int explore_numeric_scope __P((const struct addrinfo *, const char *, 225 const char *, struct addrinfo **)); 226static int get_canonname __P((const struct addrinfo *, 227 struct addrinfo *, const char *)); 228static struct addrinfo *get_ai __P((const struct addrinfo *, 229 const struct afd *, const char *)); 230static int get_portmatch __P((const struct addrinfo *, const char *)); 231static int get_port __P((struct addrinfo *, const char *, int)); 232static const struct afd *find_afd __P((int)); 233static int addrconfig __P((struct addrinfo *)); 234#ifdef INET6 235static int ip6_str2scopeid __P((char *, struct sockaddr_in6 *)); 236#endif 237 238static struct addrinfo *getanswer __P((const querybuf *, int, const char *, int, 239 const struct addrinfo *)); 240static int _dns_getaddrinfo __P((void *, void *, va_list)); 241static void _sethtent __P((void)); 242static void _endhtent __P((void)); 243static struct addrinfo *_gethtent __P((const char *, const struct addrinfo *)); 244static int _files_getaddrinfo __P((void *, void *, va_list)); 245#ifdef YP 246static struct addrinfo *_yphostent __P((char *, const struct addrinfo *)); 247static int _yp_getaddrinfo __P((void *, void *, va_list)); 248#endif 249 250static int res_queryN __P((const char *, struct res_target *)); 251static int res_searchN __P((const char *, struct res_target *)); 252static int res_querydomainN __P((const char *, const char *, 253 struct res_target *)); 254 255static char *ai_errlist[] = { 256 "Success", 257 "Address family for hostname not supported", /* EAI_ADDRFAMILY */ 258 "Temporary failure in name resolution", /* EAI_AGAIN */ 259 "Invalid value for ai_flags", /* EAI_BADFLAGS */ 260 "Non-recoverable failure in name resolution", /* EAI_FAIL */ 261 "ai_family not supported", /* EAI_FAMILY */ 262 "Memory allocation failure", /* EAI_MEMORY */ 263 "No address associated with hostname", /* EAI_NODATA */ 264 "hostname nor servname provided, or not known", /* EAI_NONAME */ 265 "servname not supported for ai_socktype", /* EAI_SERVICE */ 266 "ai_socktype not supported", /* EAI_SOCKTYPE */ 267 "System error returned in errno", /* EAI_SYSTEM */ 268 "Invalid value for hints", /* EAI_BADHINTS */ 269 "Resolved protocol is unknown", /* EAI_PROTOCOL */ 270 "Unknown error", /* EAI_MAX */ 271}; 272 273/* XXX macros that make external reference is BAD. */ 274 275#define GET_AI(ai, afd, addr) \ 276do { \ 277 /* external reference: pai, error, and label free */ \ 278 (ai) = get_ai(pai, (afd), (addr)); \ 279 if ((ai) == NULL) { \ 280 error = EAI_MEMORY; \ 281 goto free; \ 282 } \ 283} while (/*CONSTCOND*/0) 284 285#define GET_PORT(ai, serv) \ 286do { \ 287 /* external reference: error and label free */ \ 288 error = get_port((ai), (serv), 0); \ 289 if (error != 0) \ 290 goto free; \ 291} while (/*CONSTCOND*/0) 292 293#define GET_CANONNAME(ai, str) \ 294do { \ 295 /* external reference: pai, error and label free */ \ 296 error = get_canonname(pai, (ai), (str)); \ 297 if (error != 0) \ 298 goto free; \ 299} while (/*CONSTCOND*/0) 300 301#define ERR(err) \ 302do { \ 303 /* external reference: error, and label bad */ \ 304 error = (err); \ 305 goto bad; \ 306 /*NOTREACHED*/ \ 307} while (/*CONSTCOND*/0) 308 309#define MATCH_FAMILY(x, y, w) \ 310 ((x) == (y) || (/*CONSTCOND*/(w) && ((x) == PF_UNSPEC || (y) == PF_UNSPEC))) 311#define MATCH(x, y, w) \ 312 ((x) == (y) || (/*CONSTCOND*/(w) && ((x) == ANY || (y) == ANY))) 313 314char * 315gai_strerror(ecode) 316 int ecode; 317{ 318 if (ecode < 0 || ecode > EAI_MAX) 319 ecode = EAI_MAX; 320 return ai_errlist[ecode]; 321} 322 323void 324freeaddrinfo(ai) 325 struct addrinfo *ai; 326{ 327 struct addrinfo *next; 328 329 do { 330 next = ai->ai_next; 331 if (ai->ai_canonname) 332 free(ai->ai_canonname); 333 /* no need to free(ai->ai_addr) */ 334 free(ai); 335 ai = next; 336 } while (ai); 337} 338 339static int 340str_isnumber(p) 341 const char *p; 342{ 343 char *ep; 344 345 if (*p == '\0') 346 return NO; 347 ep = NULL; 348 (void)strtoul(p, &ep, 10); 349 if (ep && *ep == '\0') 350 return YES; 351 else 352 return NO; 353} 354 355int 356getaddrinfo(hostname, servname, hints, res) 357 const char *hostname, *servname; 358 const struct addrinfo *hints; 359 struct addrinfo **res; 360{ 361 struct addrinfo sentinel; 362 struct addrinfo *cur; 363 int error = 0; 364 struct addrinfo ai; 365 struct addrinfo ai0; 366 struct addrinfo *pai; 367 const struct explore *ex; 368 369 memset(&sentinel, 0, sizeof(sentinel)); 370 cur = &sentinel; 371 pai = &ai; 372 pai->ai_flags = 0; 373 pai->ai_family = PF_UNSPEC; 374 pai->ai_socktype = ANY; 375 pai->ai_protocol = ANY; 376 pai->ai_addrlen = 0; 377 pai->ai_canonname = NULL; 378 pai->ai_addr = NULL; 379 pai->ai_next = NULL; 380 381 if (hostname == NULL && servname == NULL) 382 return EAI_NONAME; 383 if (hints) { 384 /* error check for hints */ 385 if (hints->ai_addrlen || hints->ai_canonname || 386 hints->ai_addr || hints->ai_next) 387 ERR(EAI_BADHINTS); /* xxx */ 388 if (hints->ai_flags & ~AI_MASK) 389 ERR(EAI_BADFLAGS); 390 switch (hints->ai_family) { 391 case PF_UNSPEC: 392 case PF_INET: 393#ifdef INET6 394 case PF_INET6: 395#endif 396 break; 397 default: 398 ERR(EAI_FAMILY); 399 } 400 memcpy(pai, hints, sizeof(*pai)); 401 402 /* 403 * if both socktype/protocol are specified, check if they 404 * are meaningful combination. 405 */ 406 if (pai->ai_socktype != ANY && pai->ai_protocol != ANY) { 407 for (ex = explore; ex->e_af >= 0; ex++) { 408 if (pai->ai_family != ex->e_af) 409 continue; 410 if (ex->e_socktype == ANY) 411 continue; 412 if (ex->e_protocol == ANY) 413 continue; 414 if (pai->ai_socktype == ex->e_socktype 415 && pai->ai_protocol != ex->e_protocol) { 416 ERR(EAI_BADHINTS); 417 } 418 } 419 } 420 } 421 422 /* 423 * post-2553: AI_ALL and AI_V4MAPPED are effective only against 424 * AF_INET6 query. They needs to be ignored if specified in other 425 * occassions. 426 */ 427 switch (pai->ai_flags & (AI_ALL | AI_V4MAPPED)) { 428 case AI_V4MAPPED: 429 case AI_ALL | AI_V4MAPPED: 430 if (pai->ai_family != AF_INET6) 431 pai->ai_flags &= ~(AI_ALL | AI_V4MAPPED); 432 break; 433 case AI_ALL: 434#if 1 435 /* illegal */ 436 ERR(EAI_BADFLAGS); 437#else 438 pai->ai_flags &= ~(AI_ALL | AI_V4MAPPED); 439#endif 440 break; 441 } 442 443 /* 444 * check for special cases. (1) numeric servname is disallowed if 445 * socktype/protocol are left unspecified. (2) servname is disallowed 446 * for raw and other inet{,6} sockets. 447 */ 448 if (MATCH_FAMILY(pai->ai_family, PF_INET, 1) 449#ifdef PF_INET6 450 || MATCH_FAMILY(pai->ai_family, PF_INET6, 1) 451#endif 452 ) { 453 ai0 = *pai; /* backup *pai */ 454 455 if (pai->ai_family == PF_UNSPEC) { 456#ifdef PF_INET6 457 pai->ai_family = PF_INET6; 458#else 459 pai->ai_family = PF_INET; 460#endif 461 } 462 error = get_portmatch(pai, servname); 463 if (error) 464 ERR(error); 465 466 *pai = ai0; 467 } 468 469 ai0 = *pai; 470 471 /* NULL hostname, or numeric hostname */ 472 for (ex = explore; ex->e_af >= 0; ex++) { 473 *pai = ai0; 474 475 /* PF_UNSPEC entries are prepared for DNS queries only */ 476 if (ex->e_af == PF_UNSPEC) 477 continue; 478 479 if (!MATCH_FAMILY(pai->ai_family, ex->e_af, WILD_AF(ex))) 480 continue; 481 if (!MATCH(pai->ai_socktype, ex->e_socktype, WILD_SOCKTYPE(ex))) 482 continue; 483 if (!MATCH(pai->ai_protocol, ex->e_protocol, WILD_PROTOCOL(ex))) 484 continue; 485 486 if (pai->ai_family == PF_UNSPEC) 487 pai->ai_family = ex->e_af; 488 if (pai->ai_socktype == ANY && ex->e_socktype != ANY) 489 pai->ai_socktype = ex->e_socktype; 490 if (pai->ai_protocol == ANY && ex->e_protocol != ANY) 491 pai->ai_protocol = ex->e_protocol; 492 493 if (hostname == NULL) 494 error = explore_null(pai, servname, &cur->ai_next); 495 else 496 error = explore_numeric_scope(pai, hostname, servname, &cur->ai_next); 497 498 if (error) 499 goto free; 500 501 while (cur && cur->ai_next) 502 cur = cur->ai_next; 503 } 504 505 /* 506 * XXX 507 * If numreic representation of AF1 can be interpreted as FQDN 508 * representation of AF2, we need to think again about the code below. 509 */ 510 if (sentinel.ai_next) 511 goto good; 512 513 if (pai->ai_flags & AI_NUMERICHOST) 514 ERR(EAI_NODATA); 515 if (hostname == NULL) 516 ERR(EAI_NODATA); 517 518 if ((pai->ai_flags & AI_ADDRCONFIG) != 0 && !addrconfig(&ai0)) 519 ERR(EAI_FAIL); 520 521 /* 522 * hostname as alphabetical name. 523 * we would like to prefer AF_INET6 than AF_INET, so we'll make a 524 * outer loop by AFs. 525 */ 526 for (ex = explore; ex->e_af >= 0; ex++) { 527 *pai = ai0; 528 529 /* require exact match for family field */ 530 if (pai->ai_family != ex->e_af) 531 continue; 532 533 if (!MATCH(pai->ai_socktype, ex->e_socktype, 534 WILD_SOCKTYPE(ex))) { 535 continue; 536 } 537 if (!MATCH(pai->ai_protocol, ex->e_protocol, 538 WILD_PROTOCOL(ex))) { 539 continue; 540 } 541 542 if (pai->ai_socktype == ANY && ex->e_socktype != ANY) 543 pai->ai_socktype = ex->e_socktype; 544 if (pai->ai_protocol == ANY && ex->e_protocol != ANY) 545 pai->ai_protocol = ex->e_protocol; 546 547 error = explore_fqdn(pai, hostname, servname, 548 &cur->ai_next); 549 550 while (cur && cur->ai_next) 551 cur = cur->ai_next; 552 } 553 554 /* XXX */ 555 if (sentinel.ai_next) 556 error = 0; 557 558 if (error) 559 goto free; 560 if (error == 0) { 561 if (sentinel.ai_next) { 562 good: 563 *res = sentinel.ai_next; 564 return SUCCESS; 565 } else 566 error = EAI_FAIL; 567 } 568 free: 569 bad: 570 if (sentinel.ai_next) 571 freeaddrinfo(sentinel.ai_next); 572 *res = NULL; 573 return error; 574} 575 576/* 577 * FQDN hostname, DNS lookup 578 */ 579static int 580explore_fqdn(pai, hostname, servname, res) 581 const struct addrinfo *pai; 582 const char *hostname; 583 const char *servname; 584 struct addrinfo **res; 585{ 586 struct addrinfo *result; 587 struct addrinfo *cur; 588 int error = 0; 589 static const ns_dtab dtab[] = { 590 NS_FILES_CB(_files_getaddrinfo, NULL) 591 { NSSRC_DNS, _dns_getaddrinfo, NULL }, /* force -DHESIOD */ 592 NS_NIS_CB(_yp_getaddrinfo, NULL) 593 { 0 } 594 }; 595 596 result = NULL; 597 598 /* 599 * if the servname does not match socktype/protocol, ignore it. 600 */ 601 if (get_portmatch(pai, servname) != 0) 602 return 0; 603 604 switch (nsdispatch(&result, dtab, NSDB_HOSTS, "getaddrinfo", 605 default_dns_files, hostname, pai)) { 606 case NS_TRYAGAIN: 607 error = EAI_AGAIN; 608 goto free; 609 case NS_UNAVAIL: 610 error = EAI_FAIL; 611 goto free; 612 case NS_NOTFOUND: 613 error = EAI_NODATA; 614 goto free; 615 case NS_SUCCESS: 616 error = 0; 617 for (cur = result; cur; cur = cur->ai_next) { 618 GET_PORT(cur, servname); 619 /* canonname should be filled already */ 620 } 621 break; 622 } 623 624 *res = result; 625 626 return 0; 627 628free: 629 if (result) 630 freeaddrinfo(result); 631 return error; 632} 633 634/* 635 * hostname == NULL. 636 * passive socket -> anyaddr (0.0.0.0 or ::) 637 * non-passive socket -> localhost (127.0.0.1 or ::1) 638 */ 639static int 640explore_null(pai, servname, res) 641 const struct addrinfo *pai; 642 const char *servname; 643 struct addrinfo **res; 644{ 645 int s; 646 const struct afd *afd; 647 struct addrinfo *cur; 648 struct addrinfo sentinel; 649 int error; 650 651 *res = NULL; 652 sentinel.ai_next = NULL; 653 cur = &sentinel; 654 655 /* 656 * filter out AFs that are not supported by the kernel 657 * XXX errno? 658 */ 659 s = _socket(pai->ai_family, SOCK_DGRAM, 0); 660 if (s < 0) { 661 if (errno != EMFILE) 662 return 0; 663 } else 664 _close(s); 665 666 /* 667 * if the servname does not match socktype/protocol, ignore it. 668 */ 669 if (get_portmatch(pai, servname) != 0) 670 return 0; 671 672 afd = find_afd(pai->ai_family); 673 if (afd == NULL) 674 return 0; 675 676 if (pai->ai_flags & AI_PASSIVE) { 677 GET_AI(cur->ai_next, afd, afd->a_addrany); 678 /* xxx meaningless? 679 * GET_CANONNAME(cur->ai_next, "anyaddr"); 680 */ 681 GET_PORT(cur->ai_next, servname); 682 } else { 683 GET_AI(cur->ai_next, afd, afd->a_loopback); 684 /* xxx meaningless? 685 * GET_CANONNAME(cur->ai_next, "localhost"); 686 */ 687 GET_PORT(cur->ai_next, servname); 688 } 689 cur = cur->ai_next; 690 691 *res = sentinel.ai_next; 692 return 0; 693 694free: 695 if (sentinel.ai_next) 696 freeaddrinfo(sentinel.ai_next); 697 return error; 698} 699 700/* 701 * numeric hostname 702 */ 703static int 704explore_numeric(pai, hostname, servname, res) 705 const struct addrinfo *pai; 706 const char *hostname; 707 const char *servname; 708 struct addrinfo **res; 709{ 710 const struct afd *afd; 711 struct addrinfo *cur; 712 struct addrinfo sentinel; 713 int error; 714 char pton[PTON_MAX]; 715 716 *res = NULL; 717 sentinel.ai_next = NULL; 718 cur = &sentinel; 719 720 /* 721 * if the servname does not match socktype/protocol, ignore it. 722 */ 723 if (get_portmatch(pai, servname) != 0) 724 return 0; 725 726 afd = find_afd(pai->ai_family); 727 if (afd == NULL) 728 return 0; 729 730 switch (afd->a_af) { 731#if 1 /*X/Open spec*/ 732 case AF_INET: 733 if (inet_aton(hostname, (struct in_addr *)pton) == 1) { 734 if (pai->ai_family == afd->a_af || 735 pai->ai_family == PF_UNSPEC /*?*/) { 736 GET_AI(cur->ai_next, afd, pton); 737 GET_PORT(cur->ai_next, servname); 738 while (cur && cur->ai_next) 739 cur = cur->ai_next; 740 } else 741 ERR(EAI_FAMILY); /*xxx*/ 742 } 743 break; 744#endif 745 default: 746 if (inet_pton(afd->a_af, hostname, pton) == 1) { 747 if (pai->ai_family == afd->a_af || 748 pai->ai_family == PF_UNSPEC /*?*/) { 749 GET_AI(cur->ai_next, afd, pton); 750 GET_PORT(cur->ai_next, servname); 751 while (cur && cur->ai_next) 752 cur = cur->ai_next; 753 } else 754 ERR(EAI_FAMILY); /*xxx*/ 755 } 756 break; 757 } 758 759 *res = sentinel.ai_next; 760 return 0; 761 762free: 763bad: 764 if (sentinel.ai_next) 765 freeaddrinfo(sentinel.ai_next); 766 return error; 767} 768 769/* 770 * numeric hostname with scope 771 */ 772static int 773explore_numeric_scope(pai, hostname, servname, res) 774 const struct addrinfo *pai; 775 const char *hostname; 776 const char *servname; 777 struct addrinfo **res; 778{ 779#if !defined(SCOPE_DELIMITER) || !defined(INET6) 780 return explore_numeric(pai, hostname, servname, res); 781#else 782 const struct afd *afd; 783 struct addrinfo *cur; 784 int error; 785 char *cp, *hostname2 = NULL, *scope, *addr; 786 struct sockaddr_in6 *sin6; 787 788 /* 789 * if the servname does not match socktype/protocol, ignore it. 790 */ 791 if (get_portmatch(pai, servname) != 0) 792 return 0; 793 794 afd = find_afd(pai->ai_family); 795 if (afd == NULL) 796 return 0; 797 798 if (!afd->a_scoped) 799 return explore_numeric(pai, hostname, servname, res); 800 801 cp = strchr(hostname, SCOPE_DELIMITER); 802 if (cp == NULL) 803 return explore_numeric(pai, hostname, servname, res); 804 805 /* 806 * Handle special case of <scoped_address><delimiter><scope id> 807 */ 808 hostname2 = strdup(hostname); 809 if (hostname2 == NULL) 810 return EAI_MEMORY; 811 /* terminate at the delimiter */ 812 hostname2[cp - hostname] = '\0'; 813 addr = hostname2; 814 scope = cp + 1; 815 816 error = explore_numeric(pai, addr, servname, res); 817 if (error == 0) { 818 int scopeid; 819 820 for (cur = *res; cur; cur = cur->ai_next) { 821 if (cur->ai_family != AF_INET6) 822 continue; 823 sin6 = (struct sockaddr_in6 *)(void *)cur->ai_addr; 824 if ((scopeid = ip6_str2scopeid(scope, sin6)) == -1) { 825 free(hostname2); 826 return(EAI_NODATA); /* XXX: is return OK? */ 827 } 828 sin6->sin6_scope_id = scopeid; 829 } 830 } 831 832 free(hostname2); 833 834 return error; 835#endif 836} 837 838static int 839get_canonname(pai, ai, str) 840 const struct addrinfo *pai; 841 struct addrinfo *ai; 842 const char *str; 843{ 844 if ((pai->ai_flags & AI_CANONNAME) != 0) { 845 ai->ai_canonname = (char *)malloc(strlen(str) + 1); 846 if (ai->ai_canonname == NULL) 847 return EAI_MEMORY; 848 strcpy(ai->ai_canonname, str); 849 } 850 return 0; 851} 852 853static struct addrinfo * 854get_ai(pai, afd, addr) 855 const struct addrinfo *pai; 856 const struct afd *afd; 857 const char *addr; 858{ 859 char *p; 860 struct addrinfo *ai; 861#ifdef FAITH 862 struct in6_addr faith_prefix; 863 char *fp_str; 864 int translate = 0; 865#endif 866 867#ifdef FAITH 868 /* 869 * Transfrom an IPv4 addr into a special IPv6 addr format for 870 * IPv6->IPv4 translation gateway. (only TCP is supported now) 871 * 872 * +-----------------------------------+------------+ 873 * | faith prefix part (12 bytes) | embedded | 874 * | | IPv4 addr part (4 bytes) 875 * +-----------------------------------+------------+ 876 * 877 * faith prefix part is specified as ascii IPv6 addr format 878 * in environmental variable GAI. 879 * For FAITH to work correctly, routing to faith prefix must be 880 * setup toward a machine where a FAITH daemon operates. 881 * Also, the machine must enable some mechanizm 882 * (e.g. faith interface hack) to divert those packet with 883 * faith prefixed destination addr to user-land FAITH daemon. 884 */ 885 fp_str = getenv("GAI"); 886 if (fp_str && inet_pton(AF_INET6, fp_str, &faith_prefix) == 1 && 887 afd->a_af == AF_INET && pai->ai_socktype == SOCK_STREAM) { 888 u_int32_t v4a; 889 u_int8_t v4a_top; 890 891 memcpy(&v4a, addr, sizeof v4a); 892 v4a_top = v4a >> IN_CLASSA_NSHIFT; 893 if (!IN_MULTICAST(v4a) && !IN_EXPERIMENTAL(v4a) && 894 v4a_top != 0 && v4a != IN_LOOPBACKNET) { 895 afd = &afdl[N_INET6]; 896 memcpy(&faith_prefix.s6_addr[12], addr, 897 sizeof(struct in_addr)); 898 translate = 1; 899 } 900 } 901#endif 902 903 ai = (struct addrinfo *)malloc(sizeof(struct addrinfo) 904 + (afd->a_socklen)); 905 if (ai == NULL) 906 return NULL; 907 908 memcpy(ai, pai, sizeof(struct addrinfo)); 909 ai->ai_addr = (struct sockaddr *)(void *)(ai + 1); 910 memset(ai->ai_addr, 0, (size_t)afd->a_socklen); 911 ai->ai_addr->sa_len = afd->a_socklen; 912 ai->ai_addrlen = afd->a_socklen; 913 ai->ai_addr->sa_family = ai->ai_family = afd->a_af; 914 p = (char *)(void *)(ai->ai_addr); 915#ifdef FAITH 916 if (translate == 1) 917 memcpy(p + afd->a_off, &faith_prefix, (size_t)afd->a_addrlen); 918 else 919#endif 920 memcpy(p + afd->a_off, addr, (size_t)afd->a_addrlen); 921 return ai; 922} 923 924static int 925get_portmatch(ai, servname) 926 const struct addrinfo *ai; 927 const char *servname; 928{ 929 930 /* get_port does not touch first argument. when matchonly == 1. */ 931 /* LINTED const cast */ 932 return get_port((struct addrinfo *)ai, servname, 1); 933} 934 935static int 936get_port(ai, servname, matchonly) 937 struct addrinfo *ai; 938 const char *servname; 939 int matchonly; 940{ 941 const char *proto; 942 struct servent *sp; 943 int port; 944 int allownumeric; 945 946 if (servname == NULL) 947 return 0; 948 switch (ai->ai_family) { 949 case AF_INET: 950#ifdef AF_INET6 951 case AF_INET6: 952#endif 953 break; 954 default: 955 return 0; 956 } 957 958 switch (ai->ai_socktype) { 959 case SOCK_RAW: 960 return EAI_SERVICE; 961 case SOCK_DGRAM: 962 case SOCK_STREAM: 963 allownumeric = 1; 964 break; 965 case ANY: 966 allownumeric = 0; 967 break; 968 default: 969 return EAI_SOCKTYPE; 970 } 971 972 if (str_isnumber(servname)) { 973 if (!allownumeric) 974 return EAI_SERVICE; 975 port = htons(atoi(servname)); 976 if (port < 0 || port > 65535) 977 return EAI_SERVICE; 978 } else { 979 switch (ai->ai_socktype) { 980 case SOCK_DGRAM: 981 proto = "udp"; 982 break; 983 case SOCK_STREAM: 984 proto = "tcp"; 985 break; 986 default: 987 proto = NULL; 988 break; 989 } 990 991 if ((sp = getservbyname(servname, proto)) == NULL) 992 return EAI_SERVICE; 993 port = sp->s_port; 994 } 995 996 if (!matchonly) { 997 switch (ai->ai_family) { 998 case AF_INET: 999 ((struct sockaddr_in *)(void *) 1000 ai->ai_addr)->sin_port = port; 1001 break; 1002#ifdef INET6 1003 case AF_INET6: 1004 ((struct sockaddr_in6 *)(void *) 1005 ai->ai_addr)->sin6_port = port; 1006 break; 1007#endif 1008 } 1009 } 1010 1011 return 0; 1012} 1013 1014static const struct afd * 1015find_afd(af) 1016 int af; 1017{ 1018 const struct afd *afd; 1019 1020 if (af == PF_UNSPEC) 1021 return NULL; 1022 for (afd = afdl; afd->a_af; afd++) { 1023 if (afd->a_af == af) 1024 return afd; 1025 } 1026 return NULL; 1027} 1028 1029/* 1030 * post-2553: AI_ADDRCONFIG check. if we use getipnodeby* as backend, backend 1031 * will take care of it. 1032 * the semantics of AI_ADDRCONFIG is not defined well. we are not sure 1033 * if the code is right or not. 1034 * 1035 * XXX PF_UNSPEC -> PF_INET6 + PF_INET mapping needs to be in sync with 1036 * _dns_getaddrinfo. 1037 */ 1038static int 1039addrconfig(pai) 1040 struct addrinfo *pai; 1041{ 1042 int s, af; 1043 1044 /* 1045 * TODO: 1046 * Note that implementation dependent test for address 1047 * configuration should be done everytime called 1048 * (or apropriate interval), 1049 * because addresses will be dynamically assigned or deleted. 1050 */ 1051 af = pai->ai_family; 1052 if (af == AF_UNSPEC) { 1053 if ((s = _socket(AF_INET6, SOCK_DGRAM, 0)) < 0) 1054 af = AF_INET; 1055 else { 1056 _close(s); 1057 if ((s = _socket(AF_INET, SOCK_DGRAM, 0)) < 0) 1058 af = AF_INET6; 1059 else 1060 _close(s); 1061 } 1062 } 1063 if (af != AF_UNSPEC) { 1064 if ((s = _socket(af, SOCK_DGRAM, 0)) < 0) 1065 return 0; 1066 _close(s); 1067 } 1068 pai->ai_family = af; 1069 return 1; 1070} 1071 1072#ifdef INET6 1073/* convert a string to a scope identifier. XXX: IPv6 specific */ 1074static int 1075ip6_str2scopeid(scope, sin6) 1076 char *scope; 1077 struct sockaddr_in6 *sin6; 1078{ 1079 int scopeid; 1080 struct in6_addr *a6 = &sin6->sin6_addr; 1081 char *ep; 1082 1083 /* empty scopeid portion is invalid */ 1084 if (*scope == '\0') 1085 return -1; 1086 1087 if (IN6_IS_ADDR_LINKLOCAL(a6) || IN6_IS_ADDR_MC_LINKLOCAL(a6)) { 1088 /* 1089 * We currently assume a one-to-one mapping between links 1090 * and interfaces, so we simply use interface indices for 1091 * like-local scopes. 1092 */ 1093 scopeid = if_nametoindex(scope); 1094 if (scopeid == 0) 1095 goto trynumeric; 1096 return(scopeid); 1097 } 1098 1099 /* still unclear about literal, allow numeric only - placeholder */ 1100 if (IN6_IS_ADDR_SITELOCAL(a6) || IN6_IS_ADDR_MC_SITELOCAL(a6)) 1101 goto trynumeric; 1102 if (IN6_IS_ADDR_MC_ORGLOCAL(a6)) 1103 goto trynumeric; 1104 else 1105 goto trynumeric; /* global */ 1106 1107 /* try to convert to a numeric id as a last resort */ 1108 trynumeric: 1109 scopeid = (int)strtoul(scope, &ep, 10); 1110 if (*ep == '\0') 1111 return scopeid; 1112 else 1113 return -1; 1114} 1115#endif 1116 1117#ifdef DEBUG 1118static const char AskedForGot[] = 1119 "gethostby*.getanswer: asked for \"%s\", got \"%s\""; 1120#endif 1121static FILE *hostf = NULL; 1122 1123static struct addrinfo * 1124getanswer(answer, anslen, qname, qtype, pai) 1125 const querybuf *answer; 1126 int anslen; 1127 const char *qname; 1128 int qtype; 1129 const struct addrinfo *pai; 1130{ 1131 struct addrinfo sentinel, *cur; 1132 struct addrinfo ai; 1133 const struct afd *afd; 1134 char *canonname; 1135 const HEADER *hp; 1136 const u_char *cp; 1137 int n; 1138 const u_char *eom; 1139 char *bp; 1140 int type, class, buflen, ancount, qdcount; 1141 int haveanswer, had_error; 1142 char tbuf[MAXDNAME]; 1143 int (*name_ok) __P((const char *)); 1144 char hostbuf[8*1024]; 1145 1146 memset(&sentinel, 0, sizeof(sentinel)); 1147 cur = &sentinel; 1148 1149 canonname = NULL; 1150 eom = answer->buf + anslen; 1151 switch (qtype) { 1152 case T_A: 1153 case T_AAAA: 1154 case T_ANY: /*use T_ANY only for T_A/T_AAAA lookup*/ 1155 name_ok = res_hnok; 1156 break; 1157 default: 1158 return (NULL); /* XXX should be abort(); */ 1159 } 1160 /* 1161 * find first satisfactory answer 1162 */ 1163 hp = &answer->hdr; 1164 ancount = ntohs(hp->ancount); 1165 qdcount = ntohs(hp->qdcount); 1166 bp = hostbuf; 1167 buflen = sizeof hostbuf; 1168 cp = answer->buf + HFIXEDSZ; 1169 if (qdcount != 1) { 1170 h_errno = NO_RECOVERY; 1171 return (NULL); 1172 } 1173 n = dn_expand(answer->buf, eom, cp, bp, buflen); 1174 if ((n < 0) || !(*name_ok)(bp)) { 1175 h_errno = NO_RECOVERY; 1176 return (NULL); 1177 } 1178 cp += n + QFIXEDSZ; 1179 if (qtype == T_A || qtype == T_AAAA || qtype == T_ANY) { 1180 /* res_send() has already verified that the query name is the 1181 * same as the one we sent; this just gets the expanded name 1182 * (i.e., with the succeeding search-domain tacked on). 1183 */ 1184 n = strlen(bp) + 1; /* for the \0 */ 1185 if (n >= MAXHOSTNAMELEN) { 1186 h_errno = NO_RECOVERY; 1187 return (NULL); 1188 } 1189 canonname = bp; 1190 bp += n; 1191 buflen -= n; 1192 /* The qname can be abbreviated, but h_name is now absolute. */ 1193 qname = canonname; 1194 } 1195 haveanswer = 0; 1196 had_error = 0; 1197 while (ancount-- > 0 && cp < eom && !had_error) { 1198 n = dn_expand(answer->buf, eom, cp, bp, buflen); 1199 if ((n < 0) || !(*name_ok)(bp)) { 1200 had_error++; 1201 continue; 1202 } 1203 cp += n; /* name */ 1204 type = _getshort(cp); 1205 cp += INT16SZ; /* type */ 1206 class = _getshort(cp); 1207 cp += INT16SZ + INT32SZ; /* class, TTL */ 1208 n = _getshort(cp); 1209 cp += INT16SZ; /* len */ 1210 if (class != C_IN) { 1211 /* XXX - debug? syslog? */ 1212 cp += n; 1213 continue; /* XXX - had_error++ ? */ 1214 } 1215 if ((qtype == T_A || qtype == T_AAAA || qtype == T_ANY) && 1216 type == T_CNAME) { 1217 n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf); 1218 if ((n < 0) || !(*name_ok)(tbuf)) { 1219 had_error++; 1220 continue; 1221 } 1222 cp += n; 1223 /* Get canonical name. */ 1224 n = strlen(tbuf) + 1; /* for the \0 */ 1225 if (n > buflen || n >= MAXHOSTNAMELEN) { 1226 had_error++; 1227 continue; 1228 } 1229 strcpy(bp, tbuf); 1230 canonname = bp; 1231 bp += n; 1232 buflen -= n; 1233 continue; 1234 } 1235 if (qtype == T_ANY) { 1236 if (!(type == T_A || type == T_AAAA)) { 1237 cp += n; 1238 continue; 1239 } 1240 } else if (type != qtype) { 1241#ifdef DEBUG 1242 if (type != T_KEY && type != T_SIG) 1243 syslog(LOG_NOTICE|LOG_AUTH, 1244 "gethostby*.getanswer: asked for \"%s %s %s\", got type \"%s\"", 1245 qname, p_class(C_IN), p_type(qtype), 1246 p_type(type)); 1247#endif 1248 cp += n; 1249 continue; /* XXX - had_error++ ? */ 1250 } 1251 switch (type) { 1252 case T_A: 1253 case T_AAAA: 1254 if (strcasecmp(canonname, bp) != 0) { 1255#ifdef DEBUG 1256 syslog(LOG_NOTICE|LOG_AUTH, 1257 AskedForGot, canonname, bp); 1258#endif 1259 cp += n; 1260 continue; /* XXX - had_error++ ? */ 1261 } 1262 if (type == T_A && n != INADDRSZ) { 1263 cp += n; 1264 continue; 1265 } 1266 if (type == T_AAAA && n != IN6ADDRSZ) { 1267 cp += n; 1268 continue; 1269 } 1270#ifdef FILTER_V4MAPPED 1271 if (type == T_AAAA) { 1272 struct in6_addr in6; 1273 memcpy(&in6, cp, sizeof(in6)); 1274 if (IN6_IS_ADDR_V4MAPPED(&in6)) { 1275 cp += n; 1276 continue; 1277 } 1278 } 1279#endif 1280 if (!haveanswer) { 1281 int nn; 1282 1283 canonname = bp; 1284 nn = strlen(bp) + 1; /* for the \0 */ 1285 bp += nn; 1286 buflen -= nn; 1287 } 1288 1289 /* don't overwrite pai */ 1290 ai = *pai; 1291 ai.ai_family = (type == T_A) ? AF_INET : AF_INET6; 1292 afd = find_afd(ai.ai_family); 1293 if (afd == NULL) { 1294 cp += n; 1295 continue; 1296 } 1297 cur->ai_next = get_ai(&ai, afd, (const char *)cp); 1298 if (cur->ai_next == NULL) 1299 had_error++; 1300 while (cur && cur->ai_next) 1301 cur = cur->ai_next; 1302 cp += n; 1303 break; 1304 default: 1305 abort(); 1306 } 1307 if (!had_error) 1308 haveanswer++; 1309 } 1310 if (haveanswer) { 1311 if (!canonname) 1312 (void)get_canonname(pai, sentinel.ai_next, qname); 1313 else 1314 (void)get_canonname(pai, sentinel.ai_next, canonname); 1315 h_errno = NETDB_SUCCESS; 1316 return sentinel.ai_next; 1317 } 1318 1319 h_errno = NO_RECOVERY; 1320 return NULL; 1321} 1322 1323/*ARGSUSED*/ 1324static int 1325_dns_getaddrinfo(rv, cb_data, ap) 1326 void *rv; 1327 void *cb_data; 1328 va_list ap; 1329{ 1330 struct addrinfo *ai; 1331 querybuf buf, buf2; 1332 const char *name; 1333 const struct addrinfo *pai; 1334 struct addrinfo sentinel, *cur; 1335 struct res_target q, q2; 1336 1337 name = va_arg(ap, char *); 1338 pai = va_arg(ap, const struct addrinfo *); 1339 1340 memset(&q, 0, sizeof(q2)); 1341 memset(&q2, 0, sizeof(q2)); 1342 memset(&sentinel, 0, sizeof(sentinel)); 1343 cur = &sentinel; 1344 1345 switch (pai->ai_family) { 1346 case AF_UNSPEC: 1347 /* prefer IPv6 */ 1348 q.qclass = C_IN; 1349 q.qtype = T_AAAA; 1350 q.answer = buf.buf; 1351 q.anslen = sizeof(buf); 1352 q.next = &q2; 1353 q2.qclass = C_IN; 1354 q2.qtype = T_A; 1355 q2.answer = buf2.buf; 1356 q2.anslen = sizeof(buf2); 1357 break; 1358 case AF_INET: 1359 q.qclass = C_IN; 1360 q.qtype = T_A; 1361 q.answer = buf.buf; 1362 q.anslen = sizeof(buf); 1363 break; 1364 case AF_INET6: 1365 q.qclass = C_IN; 1366 q.qtype = T_AAAA; 1367 q.answer = buf.buf; 1368 q.anslen = sizeof(buf); 1369 break; 1370 default: 1371 return NS_UNAVAIL; 1372 } 1373 if (res_searchN(name, &q) < 0) 1374 return NS_NOTFOUND; 1375 ai = getanswer(&buf, q.n, q.name, q.qtype, pai); 1376 if (ai) { 1377 cur->ai_next = ai; 1378 while (cur && cur->ai_next) 1379 cur = cur->ai_next; 1380 } 1381 if (q.next) { 1382 ai = getanswer(&buf2, q2.n, q2.name, q2.qtype, pai); 1383 if (ai) 1384 cur->ai_next = ai; 1385 } 1386 if (sentinel.ai_next == NULL) 1387 switch (h_errno) { 1388 case HOST_NOT_FOUND: 1389 return NS_NOTFOUND; 1390 case TRY_AGAIN: 1391 return NS_TRYAGAIN; 1392 default: 1393 return NS_UNAVAIL; 1394 } 1395 *((struct addrinfo **)rv) = sentinel.ai_next; 1396 return NS_SUCCESS; 1397} 1398 1399static void 1400_sethtent() 1401{ 1402 if (!hostf) 1403 hostf = fopen(_PATH_HOSTS, "r" ); 1404 else 1405 rewind(hostf); 1406} 1407 1408static void 1409_endhtent() 1410{ 1411 if (hostf) { 1412 (void) fclose(hostf); 1413 hostf = NULL; 1414 } 1415} 1416 1417static struct addrinfo * 1418_gethtent(name, pai) 1419 const char *name; 1420 const struct addrinfo *pai; 1421{ 1422 char *p; 1423 char *cp, *tname, *cname; 1424 struct addrinfo hints, *res0, *res; 1425 int error; 1426 const char *addr; 1427 char hostbuf[8*1024]; 1428 1429 if (!hostf && !(hostf = fopen(_PATH_HOSTS, "r" ))) 1430 return (NULL); 1431 again: 1432 if (!(p = fgets(hostbuf, sizeof hostbuf, hostf))) 1433 return (NULL); 1434 if (*p == '#') 1435 goto again; 1436 if (!(cp = strpbrk(p, "#\n"))) 1437 goto again; 1438 *cp = '\0'; 1439 if (!(cp = strpbrk(p, " \t"))) 1440 goto again; 1441 *cp++ = '\0'; 1442 addr = p; 1443 cname = NULL; 1444 /* if this is not something we're looking for, skip it. */ 1445 while (cp && *cp) { 1446 if (*cp == ' ' || *cp == '\t') { 1447 cp++; 1448 continue; 1449 } 1450 tname = cp; 1451 if (cname == NULL) 1452 cname = cp; 1453 if ((cp = strpbrk(cp, " \t")) != NULL) 1454 *cp++ = '\0'; 1455 if (strcasecmp(name, tname) == 0) 1456 goto found; 1457 } 1458 goto again; 1459 1460found: 1461 hints = *pai; 1462 hints.ai_flags = AI_NUMERICHOST; 1463 error = getaddrinfo(addr, NULL, &hints, &res0); 1464 if (error) 1465 goto again; 1466#ifdef FILTER_V4MAPPED 1467 /* XXX should check all items in the chain */ 1468 if (res0->ai_family == AF_INET6 && 1469 IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)res0->ai_addr)->sin6_addr)) { 1470 freeaddrinfo(res0); 1471 goto again; 1472 } 1473#endif 1474 for (res = res0; res; res = res->ai_next) { 1475 /* cover it up */ 1476 res->ai_flags = pai->ai_flags; 1477 1478 if (pai->ai_flags & AI_CANONNAME) { 1479 if (get_canonname(pai, res, cname) != 0) { 1480 freeaddrinfo(res0); 1481 goto again; 1482 } 1483 } 1484 } 1485 return res0; 1486} 1487 1488/*ARGSUSED*/ 1489static int 1490_files_getaddrinfo(rv, cb_data, ap) 1491 void *rv; 1492 void *cb_data; 1493 va_list ap; 1494{ 1495 const char *name; 1496 const struct addrinfo *pai; 1497 struct addrinfo sentinel, *cur; 1498 struct addrinfo *p; 1499 1500 name = va_arg(ap, char *); 1501 pai = va_arg(ap, struct addrinfo *); 1502 1503 memset(&sentinel, 0, sizeof(sentinel)); 1504 cur = &sentinel; 1505 1506 _sethtent(); 1507 while ((p = _gethtent(name, pai)) != NULL) { 1508 cur->ai_next = p; 1509 while (cur && cur->ai_next) 1510 cur = cur->ai_next; 1511 } 1512 _endhtent(); 1513 1514 *((struct addrinfo **)rv) = sentinel.ai_next; 1515 if (sentinel.ai_next == NULL) 1516 return NS_NOTFOUND; 1517 return NS_SUCCESS; 1518} 1519 1520#ifdef YP 1521static char *__ypdomain; 1522 1523/*ARGSUSED*/ 1524static struct addrinfo * 1525_yphostent(line, pai) 1526 char *line; 1527 const struct addrinfo *pai; 1528{ 1529 struct addrinfo sentinel, *cur; 1530 struct addrinfo hints, *res, *res0; 1531 int error; 1532 char *p = line; 1533 const char *addr, *canonname; 1534 char *nextline; 1535 char *cp; 1536 1537 addr = canonname = NULL; 1538 1539 memset(&sentinel, 0, sizeof(sentinel)); 1540 cur = &sentinel; 1541 1542nextline: 1543 /* terminate line */ 1544 cp = strchr(p, '\n'); 1545 if (cp) { 1546 *cp++ = '\0'; 1547 nextline = cp; 1548 } else 1549 nextline = NULL; 1550 1551 cp = strpbrk(p, " \t"); 1552 if (cp == NULL) { 1553 if (canonname == NULL) 1554 return (NULL); 1555 else 1556 goto done; 1557 } 1558 *cp++ = '\0'; 1559 1560 addr = p; 1561 1562 while (cp && *cp) { 1563 if (*cp == ' ' || *cp == '\t') { 1564 cp++; 1565 continue; 1566 } 1567 if (!canonname) 1568 canonname = cp; 1569 if ((cp = strpbrk(cp, " \t")) != NULL) 1570 *cp++ = '\0'; 1571 } 1572 1573 hints = *pai; 1574 hints.ai_flags = AI_NUMERICHOST; 1575 error = getaddrinfo(addr, NULL, &hints, &res0); 1576 if (error == 0) { 1577 for (res = res0; res; res = res->ai_next) { 1578 /* cover it up */ 1579 res->ai_flags = pai->ai_flags; 1580 1581 if (pai->ai_flags & AI_CANONNAME) 1582 (void)get_canonname(pai, res, canonname); 1583 } 1584 } else 1585 res0 = NULL; 1586 if (res0) { 1587 cur->ai_next = res0; 1588 while (cur && cur->ai_next) 1589 cur = cur->ai_next; 1590 } 1591 1592 if (nextline) { 1593 p = nextline; 1594 goto nextline; 1595 } 1596 1597done: 1598 return sentinel.ai_next; 1599} 1600 1601/*ARGSUSED*/ 1602static int 1603_yp_getaddrinfo(rv, cb_data, ap) 1604 void *rv; 1605 void *cb_data; 1606 va_list ap; 1607{ 1608 struct addrinfo sentinel, *cur; 1609 struct addrinfo *ai = NULL; 1610 static char *__ypcurrent; 1611 int __ypcurrentlen, r; 1612 const char *name; 1613 const struct addrinfo *pai; 1614 1615 name = va_arg(ap, char *); 1616 pai = va_arg(ap, const struct addrinfo *); 1617 1618 memset(&sentinel, 0, sizeof(sentinel)); 1619 cur = &sentinel; 1620 1621 if (!__ypdomain) { 1622 if (_yp_check(&__ypdomain) == 0) 1623 return NS_UNAVAIL; 1624 } 1625 if (__ypcurrent) 1626 free(__ypcurrent); 1627 __ypcurrent = NULL; 1628 1629 /* hosts.byname is only for IPv4 (Solaris8) */ 1630 if (pai->ai_family == PF_UNSPEC || pai->ai_family == PF_INET) { 1631 r = yp_match(__ypdomain, "hosts.byname", name, 1632 (int)strlen(name), &__ypcurrent, &__ypcurrentlen); 1633 if (r == 0) { 1634 struct addrinfo ai4; 1635 1636 ai4 = *pai; 1637 ai4.ai_family = AF_INET; 1638 ai = _yphostent(__ypcurrent, &ai4); 1639 if (ai) { 1640 cur->ai_next = ai; 1641 while (cur && cur->ai_next) 1642 cur = cur->ai_next; 1643 } 1644 } 1645 } 1646 1647 /* ipnodes.byname can hold both IPv4/v6 */ 1648 r = yp_match(__ypdomain, "ipnodes.byname", name, 1649 (int)strlen(name), &__ypcurrent, &__ypcurrentlen); 1650 if (r == 0) { 1651 ai = _yphostent(__ypcurrent, pai); 1652 if (ai) { 1653 cur->ai_next = ai; 1654 while (cur && cur->ai_next) 1655 cur = cur->ai_next; 1656 } 1657 } 1658 1659 if (sentinel.ai_next == NULL) { 1660 h_errno = HOST_NOT_FOUND; 1661 return NS_NOTFOUND; 1662 } 1663 *((struct addrinfo **)rv) = sentinel.ai_next; 1664 return NS_SUCCESS; 1665} 1666#endif 1667 1668/* resolver logic */ 1669 1670extern const char *__hostalias __P((const char *)); 1671extern int h_errno; 1672 1673/* 1674 * Formulate a normal query, send, and await answer. 1675 * Returned answer is placed in supplied buffer "answer". 1676 * Perform preliminary check of answer, returning success only 1677 * if no error is indicated and the answer count is nonzero. 1678 * Return the size of the response on success, -1 on error. 1679 * Error number is left in h_errno. 1680 * 1681 * Caller must parse answer and determine whether it answers the question. 1682 */ 1683static int 1684res_queryN(name, target) 1685 const char *name; /* domain name */ 1686 struct res_target *target; 1687{ 1688 u_char buf[MAXPACKET]; 1689 HEADER *hp; 1690 int n; 1691 struct res_target *t; 1692 int rcode; 1693 int ancount; 1694 1695 rcode = NOERROR; 1696 ancount = 0; 1697 1698 if ((_res.options & RES_INIT) == 0 && res_init() == -1) { 1699 h_errno = NETDB_INTERNAL; 1700 return (-1); 1701 } 1702 1703 for (t = target; t; t = t->next) { 1704 int class, type; 1705 u_char *answer; 1706 int anslen; 1707 1708 hp = (HEADER *)(void *)t->answer; 1709 hp->rcode = NOERROR; /* default */ 1710 1711 /* make it easier... */ 1712 class = t->qclass; 1713 type = t->qtype; 1714 answer = t->answer; 1715 anslen = t->anslen; 1716#ifdef DEBUG 1717 if (_res.options & RES_DEBUG) 1718 printf(";; res_query(%s, %d, %d)\n", name, class, type); 1719#endif 1720 1721 n = res_mkquery(QUERY, name, class, type, NULL, 0, NULL, 1722 buf, sizeof(buf));
|