getaddrinfo.c revision 92905
1/* $FreeBSD: head/lib/libc/net/getaddrinfo.c 92905 2002-03-21 22:49:10Z obrien $ */ 2/* $KAME: getaddrinfo.c,v 1.15 2000/07/09 04:37:24 itojun Exp $ */ 3 4/* 5 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. Neither the name of the project nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33/* 34 * "#ifdef FAITH" part is local hack for supporting IPv4-v6 translator. 35 * 36 * Issues to be discussed: 37 * - Thread safe-ness must be checked. 38 * - Return values. There are nonstandard return values defined and used 39 * in the source code. This is because RFC2553 is silent about which error 40 * code must be returned for which situation. 41 * - freeaddrinfo(NULL). RFC2553 is silent about it. XNET 5.2 says it is 42 * invalid. 43 * current code - SEGV on freeaddrinfo(NULL) 44 * Note: 45 * - We use getipnodebyname() just for thread-safeness. There's no intent 46 * to let it do PF_UNSPEC (actually we never pass PF_UNSPEC to 47 * getipnodebyname(). 48 * - The code filters out AFs that are not supported by the kernel, 49 * when globbing NULL hostname (to loopback, or wildcard). Is it the right 50 * thing to do? What is the relationship with post-RFC2553 AI_ADDRCONFIG 51 * in ai_flags? 52 * - (post-2553) semantics of AI_ADDRCONFIG itself is too vague. 53 * (1) what should we do against numeric hostname (2) what should we do 54 * against NULL hostname (3) what is AI_ADDRCONFIG itself. AF not ready? 55 * non-loopback address configured? global address configured? 56 * - To avoid search order issue, we have a big amount of code duplicate 57 * from gethnamaddr.c and some other places. The issues that there's no 58 * lower layer function to lookup "IPv4 or IPv6" record. Calling 59 * gethostbyname2 from getaddrinfo will end up in wrong search order, as 60 * follows: 61 * - The code makes use of following calls when asked to resolver with 62 * ai_family = PF_UNSPEC: 63 * getipnodebyname(host, AF_INET6); 64 * getipnodebyname(host, AF_INET); 65 * This will result in the following queries if the node is configure to 66 * prefer /etc/hosts than DNS: 67 * lookup /etc/hosts for IPv6 address 68 * lookup DNS for IPv6 address 69 * lookup /etc/hosts for IPv4 address 70 * lookup DNS for IPv4 address 71 * which may not meet people's requirement. 72 * The right thing to happen is to have underlying layer which does 73 * PF_UNSPEC lookup (lookup both) and return chain of addrinfos. 74 * This would result in a bit of code duplicate with _dns_ghbyname() and 75 * friends. 76 */ 77/* 78 * diffs with other KAME platforms: 79 * - other KAME platforms already nuked FAITH ($GAI), but as FreeBSD 80 * 4.0-RELEASE supplies it, we still have the code here. 81 * - AI_ADDRCONFIG support is supplied 82 * - some of FreeBSD style (#define tabify and others) 83 * - classful IPv4 numeric (127.1) is allowed. 84 */ 85 86#include "namespace.h" 87#include <sys/types.h> 88#include <sys/param.h> 89#include <sys/socket.h> 90#include <net/if.h> 91#include <netinet/in.h> 92#include <arpa/inet.h> 93#include <arpa/nameser.h> 94#include <rpc/rpc.h> 95#include <rpcsvc/yp_prot.h> 96#include <rpcsvc/ypclnt.h> 97#include <netdb.h> 98#include <resolv.h> 99#include <string.h> 100#include <stdlib.h> 101#include <stddef.h> 102#include <ctype.h> 103#include <unistd.h> 104#include <stdio.h> 105#include <errno.h> 106#ifdef DEBUG 107#include <syslog.h> 108#endif 109 110#include <syslog.h> 111#include <stdarg.h> 112#include <nsswitch.h> 113#include "un-namespace.h" 114 115#if defined(__KAME__) && defined(INET6) 116# define FAITH 117#endif 118 119#define SUCCESS 0 120#define ANY 0 121#define YES 1 122#define NO 0 123 124static const char in_addrany[] = { 0, 0, 0, 0 }; 125static const char in6_addrany[] = { 126 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 127}; 128static const char in_loopback[] = { 127, 0, 0, 1 }; 129static const char in6_loopback[] = { 130 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 131}; 132 133static const struct afd { 134 int a_af; 135 int a_addrlen; 136 int a_socklen; 137 int a_off; 138 const char *a_addrany; 139 const char *a_loopback; 140 int a_scoped; 141} afdl [] = { 142#ifdef INET6 143#define N_INET6 0 144 {PF_INET6, sizeof(struct in6_addr), 145 sizeof(struct sockaddr_in6), 146 offsetof(struct sockaddr_in6, sin6_addr), 147 in6_addrany, in6_loopback, 1}, 148#define N_INET 1 149#else 150#define N_INET 0 151#endif 152 {PF_INET, sizeof(struct in_addr), 153 sizeof(struct sockaddr_in), 154 offsetof(struct sockaddr_in, sin_addr), 155 in_addrany, in_loopback, 0}, 156 {0, 0, 0, 0, NULL, NULL, 0}, 157}; 158 159struct explore { 160 int e_af; 161 int e_socktype; 162 int e_protocol; 163 const char *e_protostr; 164 int e_wild; 165#define WILD_AF(ex) ((ex)->e_wild & 0x01) 166#define WILD_SOCKTYPE(ex) ((ex)->e_wild & 0x02) 167#define WILD_PROTOCOL(ex) ((ex)->e_wild & 0x04) 168}; 169 170static const struct explore explore[] = { 171#if 0 172 { PF_LOCAL, 0, ANY, ANY, NULL, 0x01 }, 173#endif 174#ifdef INET6 175 { PF_INET6, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 }, 176 { PF_INET6, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 }, 177 { PF_INET6, SOCK_RAW, ANY, NULL, 0x05 }, 178#endif 179 { PF_INET, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 }, 180 { PF_INET, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 }, 181 { PF_INET, SOCK_RAW, ANY, NULL, 0x05 }, 182 { PF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 }, 183 { PF_UNSPEC, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 }, 184 { PF_UNSPEC, SOCK_RAW, ANY, NULL, 0x05 }, 185 { -1, 0, 0, NULL, 0 }, 186}; 187 188#ifdef INET6 189#define PTON_MAX 16 190#else 191#define PTON_MAX 4 192#endif 193 194static const ns_src default_dns_files[] = { 195 { NSSRC_FILES, NS_SUCCESS }, 196 { NSSRC_DNS, NS_SUCCESS }, 197 { 0 } 198}; 199 200#if PACKETSZ > 1024 201#define MAXPACKET PACKETSZ 202#else 203#define MAXPACKET 1024 204#endif 205 206typedef union { 207 HEADER hdr; 208 u_char buf[MAXPACKET]; 209} querybuf; 210 211struct res_target { 212 struct res_target *next; 213 const char *name; /* domain name */ 214 int qclass, qtype; /* class and type of query */ 215 u_char *answer; /* buffer to put answer */ 216 int anslen; /* size of answer buffer */ 217 int n; /* result length */ 218}; 219 220static int str_isnumber(const char *); 221static int explore_fqdn __P((const struct addrinfo *, const char *, 222 const char *, struct addrinfo **)); 223static int explore_null __P((const struct addrinfo *, 224 const char *, struct addrinfo **)); 225static int explore_numeric __P((const struct addrinfo *, const char *, 226 const char *, struct addrinfo **)); 227static int explore_numeric_scope __P((const struct addrinfo *, const char *, 228 const char *, struct addrinfo **)); 229static int get_canonname __P((const struct addrinfo *, 230 struct addrinfo *, const char *)); 231static struct addrinfo *get_ai __P((const struct addrinfo *, 232 const struct afd *, const char *)); 233static int get_portmatch(const struct addrinfo *, const char *); 234static int get_port(struct addrinfo *, const char *, int); 235static const struct afd *find_afd(int); 236static int addrconfig(struct addrinfo *); 237#ifdef INET6 238static int ip6_str2scopeid(char *, struct sockaddr_in6 *); 239#endif 240 241static struct addrinfo *getanswer __P((const querybuf *, int, const char *, int, 242 const struct addrinfo *)); 243static int _dns_getaddrinfo(void *, void *, va_list); 244static void _sethtent(void); 245static void _endhtent(void); 246static struct addrinfo *_gethtent(const char *, const struct addrinfo *); 247static int _files_getaddrinfo(void *, void *, va_list); 248#ifdef YP 249static struct addrinfo *_yphostent(char *, const struct addrinfo *); 250static int _yp_getaddrinfo(void *, void *, va_list); 251extern int _yp_check(char **); 252#endif 253 254static int res_queryN(const char *, struct res_target *); 255static int res_searchN(const char *, struct res_target *); 256static int res_querydomainN __P((const char *, const char *, 257 struct res_target *)); 258 259static char *ai_errlist[] = { 260 "Success", 261 "Address family for hostname not supported", /* EAI_ADDRFAMILY */ 262 "Temporary failure in name resolution", /* EAI_AGAIN */ 263 "Invalid value for ai_flags", /* EAI_BADFLAGS */ 264 "Non-recoverable failure in name resolution", /* EAI_FAIL */ 265 "ai_family not supported", /* EAI_FAMILY */ 266 "Memory allocation failure", /* EAI_MEMORY */ 267 "No address associated with hostname", /* EAI_NODATA */ 268 "hostname nor servname provided, or not known", /* EAI_NONAME */ 269 "servname not supported for ai_socktype", /* EAI_SERVICE */ 270 "ai_socktype not supported", /* EAI_SOCKTYPE */ 271 "System error returned in errno", /* EAI_SYSTEM */ 272 "Invalid value for hints", /* EAI_BADHINTS */ 273 "Resolved protocol is unknown", /* EAI_PROTOCOL */ 274 "Unknown error", /* EAI_MAX */ 275}; 276 277/* XXX macros that make external reference is BAD. */ 278 279#define GET_AI(ai, afd, addr) \ 280do { \ 281 /* external reference: pai, error, and label free */ \ 282 (ai) = get_ai(pai, (afd), (addr)); \ 283 if ((ai) == NULL) { \ 284 error = EAI_MEMORY; \ 285 goto free; \ 286 } \ 287} while (/*CONSTCOND*/0) 288 289#define GET_PORT(ai, serv) \ 290do { \ 291 /* external reference: error and label free */ \ 292 error = get_port((ai), (serv), 0); \ 293 if (error != 0) \ 294 goto free; \ 295} while (/*CONSTCOND*/0) 296 297#define GET_CANONNAME(ai, str) \ 298do { \ 299 /* external reference: pai, error and label free */ \ 300 error = get_canonname(pai, (ai), (str)); \ 301 if (error != 0) \ 302 goto free; \ 303} while (/*CONSTCOND*/0) 304 305#define ERR(err) \ 306do { \ 307 /* external reference: error, and label bad */ \ 308 error = (err); \ 309 goto bad; \ 310 /*NOTREACHED*/ \ 311} while (/*CONSTCOND*/0) 312 313#define MATCH_FAMILY(x, y, w) \ 314 ((x) == (y) || (/*CONSTCOND*/(w) && ((x) == PF_UNSPEC || (y) == PF_UNSPEC))) 315#define MATCH(x, y, w) \ 316 ((x) == (y) || (/*CONSTCOND*/(w) && ((x) == ANY || (y) == ANY))) 317 318char * 319gai_strerror(ecode) 320 int ecode; 321{ 322 if (ecode < 0 || ecode > EAI_MAX) 323 ecode = EAI_MAX; 324 return ai_errlist[ecode]; 325} 326 327void 328freeaddrinfo(ai) 329 struct addrinfo *ai; 330{ 331 struct addrinfo *next; 332 333 do { 334 next = ai->ai_next; 335 if (ai->ai_canonname) 336 free(ai->ai_canonname); 337 /* no need to free(ai->ai_addr) */ 338 free(ai); 339 ai = next; 340 } while (ai); 341} 342 343static int 344str_isnumber(p) 345 const char *p; 346{ 347 char *ep; 348 349 if (*p == '\0') 350 return NO; 351 ep = NULL; 352 (void)strtoul(p, &ep, 10); 353 if (ep && *ep == '\0') 354 return YES; 355 else 356 return NO; 357} 358 359int 360getaddrinfo(hostname, servname, hints, res) 361 const char *hostname, *servname; 362 const struct addrinfo *hints; 363 struct addrinfo **res; 364{ 365 struct addrinfo sentinel; 366 struct addrinfo *cur; 367 int error = 0; 368 struct addrinfo ai; 369 struct addrinfo ai0; 370 struct addrinfo *pai; 371 const struct explore *ex; 372 373 memset(&sentinel, 0, sizeof(sentinel)); 374 cur = &sentinel; 375 pai = &ai; 376 pai->ai_flags = 0; 377 pai->ai_family = PF_UNSPEC; 378 pai->ai_socktype = ANY; 379 pai->ai_protocol = ANY; 380 pai->ai_addrlen = 0; 381 pai->ai_canonname = NULL; 382 pai->ai_addr = NULL; 383 pai->ai_next = NULL; 384 385 if (hostname == NULL && servname == NULL) 386 return EAI_NONAME; 387 if (hints) { 388 /* error check for hints */ 389 if (hints->ai_addrlen || hints->ai_canonname || 390 hints->ai_addr || hints->ai_next) 391 ERR(EAI_BADHINTS); /* xxx */ 392 if (hints->ai_flags & ~AI_MASK) 393 ERR(EAI_BADFLAGS); 394 switch (hints->ai_family) { 395 case PF_UNSPEC: 396 case PF_INET: 397#ifdef INET6 398 case PF_INET6: 399#endif 400 break; 401 default: 402 ERR(EAI_FAMILY); 403 } 404 memcpy(pai, hints, sizeof(*pai)); 405 406 /* 407 * if both socktype/protocol are specified, check if they 408 * are meaningful combination. 409 */ 410 if (pai->ai_socktype != ANY && pai->ai_protocol != ANY) { 411 for (ex = explore; ex->e_af >= 0; ex++) { 412 if (pai->ai_family != ex->e_af) 413 continue; 414 if (ex->e_socktype == ANY) 415 continue; 416 if (ex->e_protocol == ANY) 417 continue; 418 if (pai->ai_socktype == ex->e_socktype 419 && pai->ai_protocol != ex->e_protocol) { 420 ERR(EAI_BADHINTS); 421 } 422 } 423 } 424 } 425 426 /* 427 * post-2553: AI_ALL and AI_V4MAPPED are effective only against 428 * AF_INET6 query. They needs to be ignored if specified in other 429 * occassions. 430 */ 431 switch (pai->ai_flags & (AI_ALL | AI_V4MAPPED)) { 432 case AI_V4MAPPED: 433 case AI_ALL | AI_V4MAPPED: 434 if (pai->ai_family != AF_INET6) 435 pai->ai_flags &= ~(AI_ALL | AI_V4MAPPED); 436 break; 437 case AI_ALL: 438#if 1 439 /* illegal */ 440 ERR(EAI_BADFLAGS); 441#else 442 pai->ai_flags &= ~(AI_ALL | AI_V4MAPPED); 443#endif 444 break; 445 } 446 447 /* 448 * check for special cases. (1) numeric servname is disallowed if 449 * socktype/protocol are left unspecified. (2) servname is disallowed 450 * for raw and other inet{,6} sockets. 451 */ 452 if (MATCH_FAMILY(pai->ai_family, PF_INET, 1) 453#ifdef PF_INET6 454 || MATCH_FAMILY(pai->ai_family, PF_INET6, 1) 455#endif 456 ) { 457 ai0 = *pai; /* backup *pai */ 458 459 if (pai->ai_family == PF_UNSPEC) { 460#ifdef PF_INET6 461 pai->ai_family = PF_INET6; 462#else 463 pai->ai_family = PF_INET; 464#endif 465 } 466 error = get_portmatch(pai, servname); 467 if (error) 468 ERR(error); 469 470 *pai = ai0; 471 } 472 473 ai0 = *pai; 474 475 /* NULL hostname, or numeric hostname */ 476 for (ex = explore; ex->e_af >= 0; ex++) { 477 *pai = ai0; 478 479 /* PF_UNSPEC entries are prepared for DNS queries only */ 480 if (ex->e_af == PF_UNSPEC) 481 continue; 482 483 if (!MATCH_FAMILY(pai->ai_family, ex->e_af, WILD_AF(ex))) 484 continue; 485 if (!MATCH(pai->ai_socktype, ex->e_socktype, WILD_SOCKTYPE(ex))) 486 continue; 487 if (!MATCH(pai->ai_protocol, ex->e_protocol, WILD_PROTOCOL(ex))) 488 continue; 489 490 if (pai->ai_family == PF_UNSPEC) 491 pai->ai_family = ex->e_af; 492 if (pai->ai_socktype == ANY && ex->e_socktype != ANY) 493 pai->ai_socktype = ex->e_socktype; 494 if (pai->ai_protocol == ANY && ex->e_protocol != ANY) 495 pai->ai_protocol = ex->e_protocol; 496 497 if (hostname == NULL) 498 error = explore_null(pai, servname, &cur->ai_next); 499 else 500 error = explore_numeric_scope(pai, hostname, servname, &cur->ai_next); 501 502 if (error) 503 goto free; 504 505 while (cur && cur->ai_next) 506 cur = cur->ai_next; 507 } 508 509 /* 510 * XXX 511 * If numreic representation of AF1 can be interpreted as FQDN 512 * representation of AF2, we need to think again about the code below. 513 */ 514 if (sentinel.ai_next) 515 goto good; 516 517 if (pai->ai_flags & AI_NUMERICHOST) 518 ERR(EAI_NONAME); 519 if (hostname == NULL) 520 ERR(EAI_NODATA); 521 522 if ((pai->ai_flags & AI_ADDRCONFIG) != 0 && !addrconfig(&ai0)) 523 ERR(EAI_FAIL); 524 525 /* 526 * hostname as alphabetical name. 527 * we would like to prefer AF_INET6 than AF_INET, so we'll make a 528 * outer loop by AFs. 529 */ 530 for (ex = explore; ex->e_af >= 0; ex++) { 531 *pai = ai0; 532 533 /* require exact match for family field */ 534 if (pai->ai_family != ex->e_af) 535 continue; 536 537 if (!MATCH(pai->ai_socktype, ex->e_socktype, 538 WILD_SOCKTYPE(ex))) { 539 continue; 540 } 541 if (!MATCH(pai->ai_protocol, ex->e_protocol, 542 WILD_PROTOCOL(ex))) { 543 continue; 544 } 545 546 if (pai->ai_socktype == ANY && ex->e_socktype != ANY) 547 pai->ai_socktype = ex->e_socktype; 548 if (pai->ai_protocol == ANY && ex->e_protocol != ANY) 549 pai->ai_protocol = ex->e_protocol; 550 551 error = explore_fqdn(pai, hostname, servname, 552 &cur->ai_next); 553 554 while (cur && cur->ai_next) 555 cur = cur->ai_next; 556 } 557 558 /* XXX */ 559 if (sentinel.ai_next) 560 error = 0; 561 562 if (error) 563 goto free; 564 if (error == 0) { 565 if (sentinel.ai_next) { 566 good: 567 *res = sentinel.ai_next; 568 return SUCCESS; 569 } else 570 error = EAI_FAIL; 571 } 572 free: 573 bad: 574 if (sentinel.ai_next) 575 freeaddrinfo(sentinel.ai_next); 576 *res = NULL; 577 return error; 578} 579 580/* 581 * FQDN hostname, DNS lookup 582 */ 583static int 584explore_fqdn(pai, hostname, servname, res) 585 const struct addrinfo *pai; 586 const char *hostname; 587 const char *servname; 588 struct addrinfo **res; 589{ 590 struct addrinfo *result; 591 struct addrinfo *cur; 592 int error = 0; 593 static const ns_dtab dtab[] = { 594 NS_FILES_CB(_files_getaddrinfo, NULL) 595 { NSSRC_DNS, _dns_getaddrinfo, NULL }, /* force -DHESIOD */ 596 NS_NIS_CB(_yp_getaddrinfo, NULL) 597 { 0 } 598 }; 599 600 result = NULL; 601 602 /* 603 * if the servname does not match socktype/protocol, ignore it. 604 */ 605 if (get_portmatch(pai, servname) != 0) 606 return 0; 607 608 switch (nsdispatch(&result, dtab, NSDB_HOSTS, "getaddrinfo", 609 default_dns_files, hostname, pai)) { 610 case NS_TRYAGAIN: 611 error = EAI_AGAIN; 612 goto free; 613 case NS_UNAVAIL: 614 error = EAI_FAIL; 615 goto free; 616 case NS_NOTFOUND: 617 error = EAI_NODATA; 618 goto free; 619 case NS_SUCCESS: 620 error = 0; 621 for (cur = result; cur; cur = cur->ai_next) { 622 GET_PORT(cur, servname); 623 /* canonname should be filled already */ 624 } 625 break; 626 } 627 628 *res = result; 629 630 return 0; 631 632free: 633 if (result) 634 freeaddrinfo(result); 635 return error; 636} 637 638/* 639 * hostname == NULL. 640 * passive socket -> anyaddr (0.0.0.0 or ::) 641 * non-passive socket -> localhost (127.0.0.1 or ::1) 642 */ 643static int 644explore_null(pai, servname, res) 645 const struct addrinfo *pai; 646 const char *servname; 647 struct addrinfo **res; 648{ 649 int s; 650 const struct afd *afd; 651 struct addrinfo *cur; 652 struct addrinfo sentinel; 653 int error; 654 655 *res = NULL; 656 sentinel.ai_next = NULL; 657 cur = &sentinel; 658 659 /* 660 * filter out AFs that are not supported by the kernel 661 * XXX errno? 662 */ 663 s = _socket(pai->ai_family, SOCK_DGRAM, 0); 664 if (s < 0) { 665 if (errno != EMFILE) 666 return 0; 667 } else 668 _close(s); 669 670 /* 671 * if the servname does not match socktype/protocol, ignore it. 672 */ 673 if (get_portmatch(pai, servname) != 0) 674 return 0; 675 676 afd = find_afd(pai->ai_family); 677 if (afd == NULL) 678 return 0; 679 680 if (pai->ai_flags & AI_PASSIVE) { 681 GET_AI(cur->ai_next, afd, afd->a_addrany); 682 /* xxx meaningless? 683 * GET_CANONNAME(cur->ai_next, "anyaddr"); 684 */ 685 GET_PORT(cur->ai_next, servname); 686 } else { 687 GET_AI(cur->ai_next, afd, afd->a_loopback); 688 /* xxx meaningless? 689 * GET_CANONNAME(cur->ai_next, "localhost"); 690 */ 691 GET_PORT(cur->ai_next, servname); 692 } 693 cur = cur->ai_next; 694 695 *res = sentinel.ai_next; 696 return 0; 697 698free: 699 if (sentinel.ai_next) 700 freeaddrinfo(sentinel.ai_next); 701 return error; 702} 703 704/* 705 * numeric hostname 706 */ 707static int 708explore_numeric(pai, hostname, servname, res) 709 const struct addrinfo *pai; 710 const char *hostname; 711 const char *servname; 712 struct addrinfo **res; 713{ 714 const struct afd *afd; 715 struct addrinfo *cur; 716 struct addrinfo sentinel; 717 int error; 718 char pton[PTON_MAX]; 719 720 *res = NULL; 721 sentinel.ai_next = NULL; 722 cur = &sentinel; 723 724 /* 725 * if the servname does not match socktype/protocol, ignore it. 726 */ 727 if (get_portmatch(pai, servname) != 0) 728 return 0; 729 730 afd = find_afd(pai->ai_family); 731 if (afd == NULL) 732 return 0; 733 734 switch (afd->a_af) { 735#if 1 /*X/Open spec*/ 736 case AF_INET: 737 if (inet_aton(hostname, (struct in_addr *)pton) == 1) { 738 if (pai->ai_family == afd->a_af || 739 pai->ai_family == PF_UNSPEC /*?*/) { 740 GET_AI(cur->ai_next, afd, pton); 741 GET_PORT(cur->ai_next, servname); 742 while (cur && cur->ai_next) 743 cur = cur->ai_next; 744 } else 745 ERR(EAI_FAMILY); /*xxx*/ 746 } 747 break; 748#endif 749 default: 750 if (inet_pton(afd->a_af, hostname, pton) == 1) { 751 if (pai->ai_family == afd->a_af || 752 pai->ai_family == PF_UNSPEC /*?*/) { 753 GET_AI(cur->ai_next, afd, pton); 754 GET_PORT(cur->ai_next, servname); 755 while (cur && cur->ai_next) 756 cur = cur->ai_next; 757 } else 758 ERR(EAI_FAMILY); /*xxx*/ 759 } 760 break; 761 } 762 763 *res = sentinel.ai_next; 764 return 0; 765 766free: 767bad: 768 if (sentinel.ai_next) 769 freeaddrinfo(sentinel.ai_next); 770 return error; 771} 772 773/* 774 * numeric hostname with scope 775 */ 776static int 777explore_numeric_scope(pai, hostname, servname, res) 778 const struct addrinfo *pai; 779 const char *hostname; 780 const char *servname; 781 struct addrinfo **res; 782{ 783#if !defined(SCOPE_DELIMITER) || !defined(INET6) 784 return explore_numeric(pai, hostname, servname, res); 785#else 786 const struct afd *afd; 787 struct addrinfo *cur; 788 int error; 789 char *cp, *hostname2 = NULL, *scope, *addr; 790 struct sockaddr_in6 *sin6; 791 792 /* 793 * if the servname does not match socktype/protocol, ignore it. 794 */ 795 if (get_portmatch(pai, servname) != 0) 796 return 0; 797 798 afd = find_afd(pai->ai_family); 799 if (afd == NULL) 800 return 0; 801 802 if (!afd->a_scoped) 803 return explore_numeric(pai, hostname, servname, res); 804 805 cp = strchr(hostname, SCOPE_DELIMITER); 806 if (cp == NULL) 807 return explore_numeric(pai, hostname, servname, res); 808 809 /* 810 * Handle special case of <scoped_address><delimiter><scope id> 811 */ 812 hostname2 = strdup(hostname); 813 if (hostname2 == NULL) 814 return EAI_MEMORY; 815 /* terminate at the delimiter */ 816 hostname2[cp - hostname] = '\0'; 817 addr = hostname2; 818 scope = cp + 1; 819 820 error = explore_numeric(pai, addr, servname, res); 821 if (error == 0) { 822 int scopeid; 823 824 for (cur = *res; cur; cur = cur->ai_next) { 825 if (cur->ai_family != AF_INET6) 826 continue; 827 sin6 = (struct sockaddr_in6 *)(void *)cur->ai_addr; 828 if ((scopeid = ip6_str2scopeid(scope, sin6)) == -1) { 829 free(hostname2); 830 return(EAI_NODATA); /* XXX: is return OK? */ 831 } 832 sin6->sin6_scope_id = scopeid; 833 } 834 } 835 836 free(hostname2); 837 838 return error; 839#endif 840} 841 842static int 843get_canonname(pai, ai, str) 844 const struct addrinfo *pai; 845 struct addrinfo *ai; 846 const char *str; 847{ 848 if ((pai->ai_flags & AI_CANONNAME) != 0) { 849 ai->ai_canonname = (char *)malloc(strlen(str) + 1); 850 if (ai->ai_canonname == NULL) 851 return EAI_MEMORY; 852 strcpy(ai->ai_canonname, str); 853 } 854 return 0; 855} 856 857static struct addrinfo * 858get_ai(pai, afd, addr) 859 const struct addrinfo *pai; 860 const struct afd *afd; 861 const char *addr; 862{ 863 char *p; 864 struct addrinfo *ai; 865#ifdef FAITH 866 struct in6_addr faith_prefix; 867 char *fp_str; 868 int translate = 0; 869#endif 870 871#ifdef FAITH 872 /* 873 * Transfrom an IPv4 addr into a special IPv6 addr format for 874 * IPv6->IPv4 translation gateway. (only TCP is supported now) 875 * 876 * +-----------------------------------+------------+ 877 * | faith prefix part (12 bytes) | embedded | 878 * | | IPv4 addr part (4 bytes) 879 * +-----------------------------------+------------+ 880 * 881 * faith prefix part is specified as ascii IPv6 addr format 882 * in environmental variable GAI. 883 * For FAITH to work correctly, routing to faith prefix must be 884 * setup toward a machine where a FAITH daemon operates. 885 * Also, the machine must enable some mechanizm 886 * (e.g. faith interface hack) to divert those packet with 887 * faith prefixed destination addr to user-land FAITH daemon. 888 */ 889 fp_str = getenv("GAI"); 890 if (fp_str && inet_pton(AF_INET6, fp_str, &faith_prefix) == 1 && 891 afd->a_af == AF_INET && pai->ai_socktype == SOCK_STREAM) { 892 u_int32_t v4a; 893 u_int8_t v4a_top; 894 895 memcpy(&v4a, addr, sizeof v4a); 896 v4a_top = v4a >> IN_CLASSA_NSHIFT; 897 if (!IN_MULTICAST(v4a) && !IN_EXPERIMENTAL(v4a) && 898 v4a_top != 0 && v4a != IN_LOOPBACKNET) { 899 afd = &afdl[N_INET6]; 900 memcpy(&faith_prefix.s6_addr[12], addr, 901 sizeof(struct in_addr)); 902 translate = 1; 903 } 904 } 905#endif 906 907 ai = (struct addrinfo *)malloc(sizeof(struct addrinfo) 908 + (afd->a_socklen)); 909 if (ai == NULL) 910 return NULL; 911 912 memcpy(ai, pai, sizeof(struct addrinfo)); 913 ai->ai_addr = (struct sockaddr *)(void *)(ai + 1); 914 memset(ai->ai_addr, 0, (size_t)afd->a_socklen); 915 ai->ai_addr->sa_len = afd->a_socklen; 916 ai->ai_addrlen = afd->a_socklen; 917 ai->ai_addr->sa_family = ai->ai_family = afd->a_af; 918 p = (char *)(void *)(ai->ai_addr); 919#ifdef FAITH 920 if (translate == 1) 921 memcpy(p + afd->a_off, &faith_prefix, (size_t)afd->a_addrlen); 922 else 923#endif 924 memcpy(p + afd->a_off, addr, (size_t)afd->a_addrlen); 925 return ai; 926} 927 928static int 929get_portmatch(ai, servname) 930 const struct addrinfo *ai; 931 const char *servname; 932{ 933 934 /* get_port does not touch first argument. when matchonly == 1. */ 935 /* LINTED const cast */ 936 return get_port((struct addrinfo *)ai, servname, 1); 937} 938 939static int 940get_port(ai, servname, matchonly) 941 struct addrinfo *ai; 942 const char *servname; 943 int matchonly; 944{ 945 const char *proto; 946 struct servent *sp; 947 int port; 948 int allownumeric; 949 950 if (servname == NULL) 951 return 0; 952 switch (ai->ai_family) { 953 case AF_INET: 954#ifdef AF_INET6 955 case AF_INET6: 956#endif 957 break; 958 default: 959 return 0; 960 } 961 962 switch (ai->ai_socktype) { 963 case SOCK_RAW: 964 return EAI_SERVICE; 965 case SOCK_DGRAM: 966 case SOCK_STREAM: 967 allownumeric = 1; 968 break; 969 case ANY: 970 allownumeric = 0; 971 break; 972 default: 973 return EAI_SOCKTYPE; 974 } 975 976 if (str_isnumber(servname)) { 977 if (!allownumeric) 978 return EAI_SERVICE; 979 port = htons(atoi(servname)); 980 if (port < 0 || port > 65535) 981 return EAI_SERVICE; 982 } else { 983 switch (ai->ai_socktype) { 984 case SOCK_DGRAM: 985 proto = "udp"; 986 break; 987 case SOCK_STREAM: 988 proto = "tcp"; 989 break; 990 default: 991 proto = NULL; 992 break; 993 } 994 995 if ((sp = getservbyname(servname, proto)) == NULL) 996 return EAI_SERVICE; 997 port = sp->s_port; 998 } 999 1000 if (!matchonly) { 1001 switch (ai->ai_family) { 1002 case AF_INET: 1003 ((struct sockaddr_in *)(void *) 1004 ai->ai_addr)->sin_port = port; 1005 break; 1006#ifdef INET6 1007 case AF_INET6: 1008 ((struct sockaddr_in6 *)(void *) 1009 ai->ai_addr)->sin6_port = port; 1010 break; 1011#endif 1012 } 1013 } 1014 1015 return 0; 1016} 1017 1018static const struct afd * 1019find_afd(af) 1020 int af; 1021{ 1022 const struct afd *afd; 1023 1024 if (af == PF_UNSPEC) 1025 return NULL; 1026 for (afd = afdl; afd->a_af; afd++) { 1027 if (afd->a_af == af) 1028 return afd; 1029 } 1030 return NULL; 1031} 1032 1033/* 1034 * post-2553: AI_ADDRCONFIG check. if we use getipnodeby* as backend, backend 1035 * will take care of it. 1036 * the semantics of AI_ADDRCONFIG is not defined well. we are not sure 1037 * if the code is right or not. 1038 * 1039 * XXX PF_UNSPEC -> PF_INET6 + PF_INET mapping needs to be in sync with 1040 * _dns_getaddrinfo. 1041 */ 1042static int 1043addrconfig(pai) 1044 struct addrinfo *pai; 1045{ 1046 int s, af; 1047 1048 /* 1049 * TODO: 1050 * Note that implementation dependent test for address 1051 * configuration should be done everytime called 1052 * (or apropriate interval), 1053 * because addresses will be dynamically assigned or deleted. 1054 */ 1055 af = pai->ai_family; 1056 if (af == AF_UNSPEC) { 1057 if ((s = _socket(AF_INET6, SOCK_DGRAM, 0)) < 0) 1058 af = AF_INET; 1059 else { 1060 _close(s); 1061 if ((s = _socket(AF_INET, SOCK_DGRAM, 0)) < 0) 1062 af = AF_INET6; 1063 else 1064 _close(s); 1065 } 1066 } 1067 if (af != AF_UNSPEC) { 1068 if ((s = _socket(af, SOCK_DGRAM, 0)) < 0) 1069 return 0; 1070 _close(s); 1071 } 1072 pai->ai_family = af; 1073 return 1; 1074} 1075 1076#ifdef INET6 1077/* convert a string to a scope identifier. XXX: IPv6 specific */ 1078static int 1079ip6_str2scopeid(scope, sin6) 1080 char *scope; 1081 struct sockaddr_in6 *sin6; 1082{ 1083 int scopeid; 1084 struct in6_addr *a6 = &sin6->sin6_addr; 1085 char *ep; 1086 1087 /* empty scopeid portion is invalid */ 1088 if (*scope == '\0') 1089 return -1; 1090 1091 if (IN6_IS_ADDR_LINKLOCAL(a6) || IN6_IS_ADDR_MC_LINKLOCAL(a6)) { 1092 /* 1093 * We currently assume a one-to-one mapping between links 1094 * and interfaces, so we simply use interface indices for 1095 * like-local scopes. 1096 */ 1097 scopeid = if_nametoindex(scope); 1098 if (scopeid == 0) 1099 goto trynumeric; 1100 return(scopeid); 1101 } 1102 1103 /* still unclear about literal, allow numeric only - placeholder */ 1104 if (IN6_IS_ADDR_SITELOCAL(a6) || IN6_IS_ADDR_MC_SITELOCAL(a6)) 1105 goto trynumeric; 1106 if (IN6_IS_ADDR_MC_ORGLOCAL(a6)) 1107 goto trynumeric; 1108 else 1109 goto trynumeric; /* global */ 1110 1111 /* try to convert to a numeric id as a last resort */ 1112 trynumeric: 1113 scopeid = (int)strtoul(scope, &ep, 10); 1114 if (*ep == '\0') 1115 return scopeid; 1116 else 1117 return -1; 1118} 1119#endif 1120 1121#ifdef DEBUG 1122static const char AskedForGot[] = 1123 "gethostby*.getanswer: asked for \"%s\", got \"%s\""; 1124#endif 1125static FILE *hostf = NULL; 1126 1127static struct addrinfo * 1128getanswer(answer, anslen, qname, qtype, pai) 1129 const querybuf *answer; 1130 int anslen; 1131 const char *qname; 1132 int qtype; 1133 const struct addrinfo *pai; 1134{ 1135 struct addrinfo sentinel, *cur; 1136 struct addrinfo ai; 1137 const struct afd *afd; 1138 char *canonname; 1139 const HEADER *hp; 1140 const u_char *cp; 1141 int n; 1142 const u_char *eom; 1143 char *bp; 1144 int type, class, buflen, ancount, qdcount; 1145 int haveanswer, had_error; 1146 char tbuf[MAXDNAME]; 1147 int (*name_ok)(const char *); 1148 char hostbuf[8*1024]; 1149 1150 memset(&sentinel, 0, sizeof(sentinel)); 1151 cur = &sentinel; 1152 1153 canonname = NULL; 1154 eom = answer->buf + anslen; 1155 switch (qtype) { 1156 case T_A: 1157 case T_AAAA: 1158 case T_ANY: /*use T_ANY only for T_A/T_AAAA lookup*/ 1159 name_ok = res_hnok; 1160 break; 1161 default: 1162 return (NULL); /* XXX should be abort(); */ 1163 } 1164 /* 1165 * find first satisfactory answer 1166 */ 1167 hp = &answer->hdr; 1168 ancount = ntohs(hp->ancount); 1169 qdcount = ntohs(hp->qdcount); 1170 bp = hostbuf; 1171 buflen = sizeof hostbuf; 1172 cp = answer->buf + HFIXEDSZ; 1173 if (qdcount != 1) { 1174 h_errno = NO_RECOVERY; 1175 return (NULL); 1176 } 1177 n = dn_expand(answer->buf, eom, cp, bp, buflen); 1178 if ((n < 0) || !(*name_ok)(bp)) { 1179 h_errno = NO_RECOVERY; 1180 return (NULL); 1181 } 1182 cp += n + QFIXEDSZ; 1183 if (qtype == T_A || qtype == T_AAAA || qtype == T_ANY) { 1184 /* res_send() has already verified that the query name is the 1185 * same as the one we sent; this just gets the expanded name 1186 * (i.e., with the succeeding search-domain tacked on). 1187 */ 1188 n = strlen(bp) + 1; /* for the \0 */ 1189 if (n >= MAXHOSTNAMELEN) { 1190 h_errno = NO_RECOVERY; 1191 return (NULL); 1192 } 1193 canonname = bp; 1194 bp += n; 1195 buflen -= n; 1196 /* The qname can be abbreviated, but h_name is now absolute. */ 1197 qname = canonname; 1198 } 1199 haveanswer = 0; 1200 had_error = 0; 1201 while (ancount-- > 0 && cp < eom && !had_error) { 1202 n = dn_expand(answer->buf, eom, cp, bp, buflen); 1203 if ((n < 0) || !(*name_ok)(bp)) { 1204 had_error++; 1205 continue; 1206 } 1207 cp += n; /* name */ 1208 type = _getshort(cp); 1209 cp += INT16SZ; /* type */ 1210 class = _getshort(cp); 1211 cp += INT16SZ + INT32SZ; /* class, TTL */ 1212 n = _getshort(cp); 1213 cp += INT16SZ; /* len */ 1214 if (class != C_IN) { 1215 /* XXX - debug? syslog? */ 1216 cp += n; 1217 continue; /* XXX - had_error++ ? */ 1218 } 1219 if ((qtype == T_A || qtype == T_AAAA || qtype == T_ANY) && 1220 type == T_CNAME) { 1221 n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf); 1222 if ((n < 0) || !(*name_ok)(tbuf)) { 1223 had_error++; 1224 continue; 1225 } 1226 cp += n; 1227 /* Get canonical name. */ 1228 n = strlen(tbuf) + 1; /* for the \0 */ 1229 if (n > buflen || n >= MAXHOSTNAMELEN) { 1230 had_error++; 1231 continue; 1232 } 1233 strcpy(bp, tbuf); 1234 canonname = bp; 1235 bp += n; 1236 buflen -= n; 1237 continue; 1238 } 1239 if (qtype == T_ANY) { 1240 if (!(type == T_A || type == T_AAAA)) { 1241 cp += n; 1242 continue; 1243 } 1244 } else if (type != qtype) { 1245#ifdef DEBUG 1246 if (type != T_KEY && type != T_SIG) 1247 syslog(LOG_NOTICE|LOG_AUTH, 1248 "gethostby*.getanswer: asked for \"%s %s %s\", got type \"%s\"", 1249 qname, p_class(C_IN), p_type(qtype), 1250 p_type(type)); 1251#endif 1252 cp += n; 1253 continue; /* XXX - had_error++ ? */ 1254 } 1255 switch (type) { 1256 case T_A: 1257 case T_AAAA: 1258 if (strcasecmp(canonname, bp) != 0) { 1259#ifdef DEBUG 1260 syslog(LOG_NOTICE|LOG_AUTH, 1261 AskedForGot, canonname, bp); 1262#endif 1263 cp += n; 1264 continue; /* XXX - had_error++ ? */ 1265 } 1266 if (type == T_A && n != INADDRSZ) { 1267 cp += n; 1268 continue; 1269 } 1270 if (type == T_AAAA && n != IN6ADDRSZ) { 1271 cp += n; 1272 continue; 1273 } 1274#ifdef FILTER_V4MAPPED 1275 if (type == T_AAAA) { 1276 struct in6_addr in6; 1277 memcpy(&in6, cp, sizeof(in6)); 1278 if (IN6_IS_ADDR_V4MAPPED(&in6)) { 1279 cp += n; 1280 continue; 1281 } 1282 } 1283#endif 1284 if (!haveanswer) { 1285 int nn; 1286 1287 canonname = bp; 1288 nn = strlen(bp) + 1; /* for the \0 */ 1289 bp += nn; 1290 buflen -= nn; 1291 } 1292 1293 /* don't overwrite pai */ 1294 ai = *pai; 1295 ai.ai_family = (type == T_A) ? AF_INET : AF_INET6; 1296 afd = find_afd(ai.ai_family); 1297 if (afd == NULL) { 1298 cp += n; 1299 continue; 1300 } 1301 cur->ai_next = get_ai(&ai, afd, (const char *)cp); 1302 if (cur->ai_next == NULL) 1303 had_error++; 1304 while (cur && cur->ai_next) 1305 cur = cur->ai_next; 1306 cp += n; 1307 break; 1308 default: 1309 abort(); 1310 } 1311 if (!had_error) 1312 haveanswer++; 1313 } 1314 if (haveanswer) { 1315 if (!canonname) 1316 (void)get_canonname(pai, sentinel.ai_next, qname); 1317 else 1318 (void)get_canonname(pai, sentinel.ai_next, canonname); 1319 h_errno = NETDB_SUCCESS; 1320 return sentinel.ai_next; 1321 } 1322 1323 h_errno = NO_RECOVERY; 1324 return NULL; 1325} 1326 1327/*ARGSUSED*/ 1328static int 1329_dns_getaddrinfo(rv, cb_data, ap) 1330 void *rv; 1331 void *cb_data; 1332 va_list ap; 1333{ 1334 struct addrinfo *ai; 1335 querybuf buf, buf2; 1336 const char *name; 1337 const struct addrinfo *pai; 1338 struct addrinfo sentinel, *cur; 1339 struct res_target q, q2; 1340 1341 name = va_arg(ap, char *); 1342 pai = va_arg(ap, const struct addrinfo *); 1343 1344 memset(&q, 0, sizeof(q2)); 1345 memset(&q2, 0, sizeof(q2)); 1346 memset(&sentinel, 0, sizeof(sentinel)); 1347 cur = &sentinel; 1348 1349 switch (pai->ai_family) { 1350 case AF_UNSPEC: 1351 /* prefer IPv6 */ 1352 q.qclass = C_IN; 1353 q.qtype = T_AAAA; 1354 q.answer = buf.buf; 1355 q.anslen = sizeof(buf); 1356 q.next = &q2; 1357 q2.qclass = C_IN; 1358 q2.qtype = T_A; 1359 q2.answer = buf2.buf; 1360 q2.anslen = sizeof(buf2); 1361 break; 1362 case AF_INET: 1363 q.qclass = C_IN; 1364 q.qtype = T_A; 1365 q.answer = buf.buf; 1366 q.anslen = sizeof(buf); 1367 break; 1368 case AF_INET6: 1369 q.qclass = C_IN; 1370 q.qtype = T_AAAA; 1371 q.answer = buf.buf; 1372 q.anslen = sizeof(buf); 1373 break; 1374 default: 1375 return NS_UNAVAIL; 1376 } 1377 if (res_searchN(name, &q) < 0) 1378 return NS_NOTFOUND; 1379 ai = getanswer(&buf, q.n, q.name, q.qtype, pai); 1380 if (ai) { 1381 cur->ai_next = ai; 1382 while (cur && cur->ai_next) 1383 cur = cur->ai_next; 1384 } 1385 if (q.next) { 1386 ai = getanswer(&buf2, q2.n, q2.name, q2.qtype, pai); 1387 if (ai) 1388 cur->ai_next = ai; 1389 } 1390 if (sentinel.ai_next == NULL) 1391 switch (h_errno) { 1392 case HOST_NOT_FOUND: 1393 return NS_NOTFOUND; 1394 case TRY_AGAIN: 1395 return NS_TRYAGAIN; 1396 default: 1397 return NS_UNAVAIL; 1398 } 1399 *((struct addrinfo **)rv) = sentinel.ai_next; 1400 return NS_SUCCESS; 1401} 1402 1403static void 1404_sethtent() 1405{ 1406 if (!hostf) 1407 hostf = fopen(_PATH_HOSTS, "r" ); 1408 else 1409 rewind(hostf); 1410} 1411 1412static void 1413_endhtent() 1414{ 1415 if (hostf) { 1416 (void) fclose(hostf); 1417 hostf = NULL; 1418 } 1419} 1420 1421static struct addrinfo * 1422_gethtent(name, pai) 1423 const char *name; 1424 const struct addrinfo *pai; 1425{ 1426 char *p; 1427 char *cp, *tname, *cname; 1428 struct addrinfo hints, *res0, *res; 1429 int error; 1430 const char *addr; 1431 char hostbuf[8*1024]; 1432 1433 if (!hostf && !(hostf = fopen(_PATH_HOSTS, "r" ))) 1434 return (NULL); 1435 again: 1436 if (!(p = fgets(hostbuf, sizeof hostbuf, hostf))) 1437 return (NULL); 1438 if (*p == '#') 1439 goto again; 1440 if (!(cp = strpbrk(p, "#\n"))) 1441 goto again; 1442 *cp = '\0'; 1443 if (!(cp = strpbrk(p, " \t"))) 1444 goto again; 1445 *cp++ = '\0'; 1446 addr = p; 1447 cname = NULL; 1448 /* if this is not something we're looking for, skip it. */ 1449 while (cp && *cp) { 1450 if (*cp == ' ' || *cp == '\t') { 1451 cp++; 1452 continue; 1453 } 1454 tname = cp; 1455 if (cname == NULL) 1456 cname = cp; 1457 if ((cp = strpbrk(cp, " \t")) != NULL) 1458 *cp++ = '\0'; 1459 if (strcasecmp(name, tname) == 0) 1460 goto found; 1461 } 1462 goto again; 1463 1464found: 1465 hints = *pai; 1466 hints.ai_flags = AI_NUMERICHOST; 1467 error = getaddrinfo(addr, NULL, &hints, &res0); 1468 if (error) 1469 goto again; 1470#ifdef FILTER_V4MAPPED 1471 /* XXX should check all items in the chain */ 1472 if (res0->ai_family == AF_INET6 && 1473 IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)res0->ai_addr)->sin6_addr)) { 1474 freeaddrinfo(res0); 1475 goto again; 1476 } 1477#endif 1478 for (res = res0; res; res = res->ai_next) { 1479 /* cover it up */ 1480 res->ai_flags = pai->ai_flags; 1481 1482 if (pai->ai_flags & AI_CANONNAME) { 1483 if (get_canonname(pai, res, cname) != 0) { 1484 freeaddrinfo(res0); 1485 goto again; 1486 } 1487 } 1488 } 1489 return res0; 1490} 1491 1492/*ARGSUSED*/ 1493static int 1494_files_getaddrinfo(rv, cb_data, ap) 1495 void *rv; 1496 void *cb_data; 1497 va_list ap; 1498{ 1499 const char *name; 1500 const struct addrinfo *pai; 1501 struct addrinfo sentinel, *cur; 1502 struct addrinfo *p; 1503 1504 name = va_arg(ap, char *); 1505 pai = va_arg(ap, struct addrinfo *); 1506 1507 memset(&sentinel, 0, sizeof(sentinel)); 1508 cur = &sentinel; 1509 1510 _sethtent(); 1511 while ((p = _gethtent(name, pai)) != NULL) { 1512 cur->ai_next = p; 1513 while (cur && cur->ai_next) 1514 cur = cur->ai_next; 1515 } 1516 _endhtent(); 1517 1518 *((struct addrinfo **)rv) = sentinel.ai_next; 1519 if (sentinel.ai_next == NULL) 1520 return NS_NOTFOUND; 1521 return NS_SUCCESS; 1522} 1523 1524#ifdef YP 1525static char *__ypdomain; 1526 1527/*ARGSUSED*/ 1528static struct addrinfo * 1529_yphostent(line, pai) 1530 char *line; 1531 const struct addrinfo *pai; 1532{ 1533 struct addrinfo sentinel, *cur; 1534 struct addrinfo hints, *res, *res0; 1535 int error; 1536 char *p = line; 1537 const char *addr, *canonname; 1538 char *nextline; 1539 char *cp; 1540 1541 addr = canonname = NULL; 1542 1543 memset(&sentinel, 0, sizeof(sentinel)); 1544 cur = &sentinel; 1545 1546nextline: 1547 /* terminate line */ 1548 cp = strchr(p, '\n'); 1549 if (cp) { 1550 *cp++ = '\0'; 1551 nextline = cp; 1552 } else 1553 nextline = NULL; 1554 1555 cp = strpbrk(p, " \t"); 1556 if (cp == NULL) { 1557 if (canonname == NULL) 1558 return (NULL); 1559 else 1560 goto done; 1561 } 1562 *cp++ = '\0'; 1563 1564 addr = p; 1565 1566 while (cp && *cp) { 1567 if (*cp == ' ' || *cp == '\t') { 1568 cp++; 1569 continue; 1570 } 1571 if (!canonname) 1572 canonname = cp; 1573 if ((cp = strpbrk(cp, " \t")) != NULL) 1574 *cp++ = '\0'; 1575 } 1576 1577 hints = *pai; 1578 hints.ai_flags = AI_NUMERICHOST; 1579 error = getaddrinfo(addr, NULL, &hints, &res0); 1580 if (error == 0) { 1581 for (res = res0; res; res = res->ai_next) { 1582 /* cover it up */ 1583 res->ai_flags = pai->ai_flags; 1584 1585 if (pai->ai_flags & AI_CANONNAME) 1586 (void)get_canonname(pai, res, canonname); 1587 } 1588 } else 1589 res0 = NULL; 1590 if (res0) { 1591 cur->ai_next = res0; 1592 while (cur && cur->ai_next) 1593 cur = cur->ai_next; 1594 } 1595 1596 if (nextline) { 1597 p = nextline; 1598 goto nextline; 1599 } 1600 1601done: 1602 return sentinel.ai_next; 1603} 1604 1605/*ARGSUSED*/ 1606static int 1607_yp_getaddrinfo(rv, cb_data, ap) 1608 void *rv; 1609 void *cb_data; 1610 va_list ap; 1611{ 1612 struct addrinfo sentinel, *cur; 1613 struct addrinfo *ai = NULL; 1614 static char *__ypcurrent; 1615 int __ypcurrentlen, r; 1616 const char *name; 1617 const struct addrinfo *pai; 1618 1619 name = va_arg(ap, char *); 1620 pai = va_arg(ap, const struct addrinfo *); 1621 1622 memset(&sentinel, 0, sizeof(sentinel)); 1623 cur = &sentinel; 1624 1625 if (!__ypdomain) { 1626 if (_yp_check(&__ypdomain) == 0) 1627 return NS_UNAVAIL; 1628 } 1629 if (__ypcurrent) 1630 free(__ypcurrent); 1631 __ypcurrent = NULL; 1632 1633 /* hosts.byname is only for IPv4 (Solaris8) */ 1634 if (pai->ai_family == PF_UNSPEC || pai->ai_family == PF_INET) { 1635 r = yp_match(__ypdomain, "hosts.byname", name, 1636 (int)strlen(name), &__ypcurrent, &__ypcurrentlen); 1637 if (r == 0) { 1638 struct addrinfo ai4; 1639 1640 ai4 = *pai; 1641 ai4.ai_family = AF_INET; 1642 ai = _yphostent(__ypcurrent, &ai4); 1643 if (ai) { 1644 cur->ai_next = ai; 1645 while (cur && cur->ai_next) 1646 cur = cur->ai_next; 1647 } 1648 } 1649 } 1650 1651 /* ipnodes.byname can hold both IPv4/v6 */ 1652 r = yp_match(__ypdomain, "ipnodes.byname", name, 1653 (int)strlen(name), &__ypcurrent, &__ypcurrentlen); 1654 if (r == 0) { 1655 ai = _yphostent(__ypcurrent, pai); 1656 if (ai) { 1657 cur->ai_next = ai; 1658 while (cur && cur->ai_next) 1659 cur = cur->ai_next; 1660 } 1661 } 1662 1663 if (sentinel.ai_next == NULL) { 1664 h_errno = HOST_NOT_FOUND; 1665 return NS_NOTFOUND; 1666 } 1667 *((struct addrinfo **)rv) = sentinel.ai_next; 1668 return NS_SUCCESS; 1669} 1670#endif 1671 1672/* resolver logic */ 1673 1674extern const char *__hostalias(const char *); 1675extern int h_errno; 1676 1677/* 1678 * Formulate a normal query, send, and await answer. 1679 * Returned answer is placed in supplied buffer "answer". 1680 * Perform preliminary check of answer, returning success only 1681 * if no error is indicated and the answer count is nonzero. 1682 * Return the size of the response on success, -1 on error. 1683 * Error number is left in h_errno. 1684 * 1685 * Caller must parse answer and determine whether it answers the question. 1686 */ 1687static int 1688res_queryN(name, target) 1689 const char *name; /* domain name */ 1690 struct res_target *target; 1691{ 1692 u_char buf[MAXPACKET]; 1693 HEADER *hp; 1694 int n; 1695 struct res_target *t; 1696 int rcode; 1697 int ancount; 1698 1699 rcode = NOERROR; 1700 ancount = 0; 1701 1702 if ((_res.options & RES_INIT) == 0 && res_init() == -1) { 1703 h_errno = NETDB_INTERNAL; 1704 return (-1); 1705 } 1706 1707 for (t = target; t; t = t->next) { 1708 int class, type; 1709 u_char *answer; 1710 int anslen; 1711 1712 hp = (HEADER *)(void *)t->answer; 1713 hp->rcode = NOERROR; /* default */ 1714 1715 /* make it easier... */ 1716 class = t->qclass; 1717 type = t->qtype; 1718 answer = t->answer; 1719 anslen = t->anslen; 1720#ifdef DEBUG 1721 if (_res.options & RES_DEBUG) 1722 printf(";; res_query(%s, %d, %d)\n", name, class, type); 1723#endif 1724 1725 n = res_mkquery(QUERY, name, class, type, NULL, 0, NULL, 1726 buf, sizeof(buf)); 1727 if (n > 0 && (_res.options & RES_USE_EDNS0) != 0) 1728 n = res_opt(n, buf, sizeof(buf), anslen); 1729 if (n <= 0) { 1730#ifdef DEBUG 1731 if (_res.options & RES_DEBUG) 1732 printf(";; res_query: mkquery failed\n"); 1733#endif 1734 h_errno = NO_RECOVERY; 1735 return (n); 1736 } 1737 n = res_send(buf, n, answer, anslen); 1738#if 0 1739 if (n < 0) { 1740#ifdef DEBUG 1741 if (_res.options & RES_DEBUG) 1742 printf(";; res_query: send error\n"); 1743#endif 1744 h_errno = TRY_AGAIN; 1745 return (n); 1746 } 1747#endif 1748 1749 if (n < 0 || hp->rcode != NOERROR || ntohs(hp->ancount) == 0) { 1750 rcode = hp->rcode; /* record most recent error */ 1751#ifdef DEBUG 1752 if (_res.options & RES_DEBUG) 1753 printf(";; rcode = %d, ancount=%d\n", hp->rcode, 1754 ntohs(hp->ancount)); 1755#endif 1756 continue; 1757 } 1758 1759 ancount += ntohs(hp->ancount); 1760 1761 t->n = n; 1762 } 1763 1764 if (ancount == 0) { 1765 switch (rcode) { 1766 case NXDOMAIN: 1767 h_errno = HOST_NOT_FOUND; 1768 break; 1769 case SERVFAIL: 1770 h_errno = TRY_AGAIN; 1771 break; 1772 case NOERROR: 1773 h_errno = NO_DATA; 1774 break; 1775 case FORMERR: 1776 case NOTIMP: 1777 case REFUSED: 1778 default: 1779 h_errno = NO_RECOVERY; 1780 break; 1781 } 1782 return (-1); 1783 } 1784 return (ancount); 1785} 1786 1787/* 1788 * Formulate a normal query, send, and retrieve answer in supplied buffer. 1789 * Return the size of the response on success, -1 on error. 1790 * If enabled, implement search rules until answer or unrecoverable failure 1791 * is detected. Error code, if any, is left in h_errno. 1792 */ 1793static int 1794res_searchN(name, target) 1795 const char *name; /* domain name */ 1796 struct res_target *target; 1797{ 1798 const char *cp, * const *domain; 1799 HEADER *hp = (HEADER *)(void *)target->answer; /*XXX*/ 1800 u_int dots; 1801 int trailing_dot, ret, saved_herrno; 1802 int got_nodata = 0, got_servfail = 0, tried_as_is = 0; 1803 1804 if ((_res.options & RES_INIT) == 0 && res_init() == -1) { 1805 h_errno = NETDB_INTERNAL; 1806 return (-1); 1807 } 1808 1809 errno = 0; 1810 h_errno = HOST_NOT_FOUND; /* default, if we never query */ 1811 dots = 0; 1812 for (cp = name; *cp; cp++) 1813 dots += (*cp == '.'); 1814 trailing_dot = 0; 1815 if (cp > name && *--cp == '.') 1816 trailing_dot++; 1817 1818 /* 1819 * if there aren't any dots, it could be a user-level alias 1820 */ 1821 if (!dots && (cp = __hostalias(name)) != NULL) 1822 return (res_queryN(cp, target)); 1823 1824 /* 1825 * If there are dots in the name already, let's just give it a try 1826 * 'as is'. The threshold can be set with the "ndots" option. 1827 */ 1828 saved_herrno = -1; 1829 if (dots >= _res.ndots) { 1830 ret = res_querydomainN(name, NULL, target); 1831 if (ret > 0) 1832 return (ret); 1833 saved_herrno = h_errno; 1834 tried_as_is++; 1835 } 1836 1837 /* 1838 * We do at least one level of search if 1839 * - there is no dot and RES_DEFNAME is set, or 1840 * - there is at least one dot, there is no trailing dot, 1841 * and RES_DNSRCH is set. 1842 */ 1843 if ((!dots && (_res.options & RES_DEFNAMES)) || 1844 (dots && !trailing_dot && (_res.options & RES_DNSRCH))) { 1845 int done = 0; 1846 1847 for (domain = (const char * const *)_res.dnsrch; 1848 *domain && !done; 1849 domain++) { 1850 1851 ret = res_querydomainN(name, *domain, target); 1852 if (ret > 0) 1853 return (ret); 1854 1855 /* 1856 * If no server present, give up. 1857 * If name isn't found in this domain, 1858 * keep trying higher domains in the search list 1859 * (if that's enabled). 1860 * On a NO_DATA error, keep trying, otherwise 1861 * a wildcard entry of another type could keep us 1862 * from finding this entry higher in the domain. 1863 * If we get some other error (negative answer or 1864 * server failure), then stop searching up, 1865 * but try the input name below in case it's 1866 * fully-qualified. 1867 */ 1868 if (errno == ECONNREFUSED) { 1869 h_errno = TRY_AGAIN; 1870 return (-1); 1871 } 1872 1873 switch (h_errno) { 1874 case NO_DATA: 1875 got_nodata++; 1876 /* FALLTHROUGH */ 1877 case HOST_NOT_FOUND: 1878 /* keep trying */ 1879 break; 1880 case TRY_AGAIN: 1881 if (hp->rcode == SERVFAIL) { 1882 /* try next search element, if any */ 1883 got_servfail++; 1884 break; 1885 } 1886 /* FALLTHROUGH */ 1887 default: 1888 /* anything else implies that we're done */ 1889 done++; 1890 } 1891 /* 1892 * if we got here for some reason other than DNSRCH, 1893 * we only wanted one iteration of the loop, so stop. 1894 */ 1895 if (!(_res.options & RES_DNSRCH)) 1896 done++; 1897 } 1898 } 1899 1900 /* 1901 * if we have not already tried the name "as is", do that now. 1902 * note that we do this regardless of how many dots were in the 1903 * name or whether it ends with a dot. 1904 */ 1905 if (!tried_as_is && (dots || !(_res.options & RES_NOTLDQUERY))) { 1906 ret = res_querydomainN(name, NULL, target); 1907 if (ret > 0) 1908 return (ret); 1909 } 1910 1911 /* 1912 * if we got here, we didn't satisfy the search. 1913 * if we did an initial full query, return that query's h_errno 1914 * (note that we wouldn't be here if that query had succeeded). 1915 * else if we ever got a nodata, send that back as the reason. 1916 * else send back meaningless h_errno, that being the one from 1917 * the last DNSRCH we did. 1918 */ 1919 if (saved_herrno != -1) 1920 h_errno = saved_herrno; 1921 else if (got_nodata) 1922 h_errno = NO_DATA; 1923 else if (got_servfail) 1924 h_errno = TRY_AGAIN; 1925 return (-1); 1926} 1927 1928/* 1929 * Perform a call on res_query on the concatenation of name and domain, 1930 * removing a trailing dot from name if domain is NULL. 1931 */ 1932static int 1933res_querydomainN(name, domain, target) 1934 const char *name, *domain; 1935 struct res_target *target; 1936{ 1937 char nbuf[MAXDNAME]; 1938 const char *longname = nbuf; 1939 size_t n, d; 1940 1941 if ((_res.options & RES_INIT) == 0 && res_init() == -1) { 1942 h_errno = NETDB_INTERNAL; 1943 return (-1); 1944 } 1945#ifdef DEBUG 1946 if (_res.options & RES_DEBUG) 1947 printf(";; res_querydomain(%s, %s)\n", 1948 name, domain?domain:"<Nil>"); 1949#endif 1950 if (domain == NULL) { 1951 /* 1952 * Check for trailing '.'; 1953 * copy without '.' if present. 1954 */ 1955 n = strlen(name); 1956 if (n >= MAXDNAME) { 1957 h_errno = NO_RECOVERY; 1958 return (-1); 1959 } 1960 if (n > 0 && name[--n] == '.') { 1961 strncpy(nbuf, name, n); 1962 nbuf[n] = '\0'; 1963 } else 1964 longname = name; 1965 } else { 1966 n = strlen(name); 1967 d = strlen(domain); 1968 if (n + d + 1 >= MAXDNAME) { 1969 h_errno = NO_RECOVERY; 1970 return (-1); 1971 } 1972 sprintf(nbuf, "%s.%s", name, domain); 1973 } 1974 return (res_queryN(longname, target)); 1975} 1976