getaddrinfo.c revision 74393
1/* $FreeBSD: head/lib/libc/net/getaddrinfo.c 74393 2001-03-17 14:25:23Z ume $ */ 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 * - EDNS0 support is not available due to resolver differences 83 * - some of FreeBSD style (#define tabify and others) 84 * - classful IPv4 numeric (127.1) is allowed. 85 */ 86 87#include "namespace.h" 88#include <sys/types.h> 89#include <sys/param.h> 90#include <sys/socket.h> 91#include <net/if.h> 92#include <netinet/in.h> 93#include <arpa/inet.h> 94#include <arpa/nameser.h> 95#include <netdb.h> 96#include <resolv.h> 97#include <string.h> 98#include <stdlib.h> 99#include <stddef.h> 100#include <ctype.h> 101#include <unistd.h> 102#include <stdio.h> 103#include <errno.h> 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)); 1721 if (n <= 0) { 1722#ifdef DEBUG 1723 if (_res.options & RES_DEBUG) 1724 printf(";; res_query: mkquery failed\n"); 1725#endif 1726 h_errno = NO_RECOVERY; 1727 return (n); 1728 } 1729 n = res_send(buf, n, answer, anslen); 1730#if 0 1731 if (n < 0) { 1732#ifdef DEBUG 1733 if (_res.options & RES_DEBUG) 1734 printf(";; res_query: send error\n"); 1735#endif 1736 h_errno = TRY_AGAIN; 1737 return (n); 1738 } 1739#endif 1740 1741 if (n < 0 || hp->rcode != NOERROR || ntohs(hp->ancount) == 0) { 1742 rcode = hp->rcode; /* record most recent error */ 1743#ifdef DEBUG 1744 if (_res.options & RES_DEBUG) 1745 printf(";; rcode = %d, ancount=%d\n", hp->rcode, 1746 ntohs(hp->ancount)); 1747#endif 1748 continue; 1749 } 1750 1751 ancount += ntohs(hp->ancount); 1752 1753 t->n = n; 1754 } 1755 1756 if (ancount == 0) { 1757 switch (rcode) { 1758 case NXDOMAIN: 1759 h_errno = HOST_NOT_FOUND; 1760 break; 1761 case SERVFAIL: 1762 h_errno = TRY_AGAIN; 1763 break; 1764 case NOERROR: 1765 h_errno = NO_DATA; 1766 break; 1767 case FORMERR: 1768 case NOTIMP: 1769 case REFUSED: 1770 default: 1771 h_errno = NO_RECOVERY; 1772 break; 1773 } 1774 return (-1); 1775 } 1776 return (ancount); 1777} 1778 1779/* 1780 * Formulate a normal query, send, and retrieve answer in supplied buffer. 1781 * Return the size of the response on success, -1 on error. 1782 * If enabled, implement search rules until answer or unrecoverable failure 1783 * is detected. Error code, if any, is left in h_errno. 1784 */ 1785static int 1786res_searchN(name, target) 1787 const char *name; /* domain name */ 1788 struct res_target *target; 1789{ 1790 const char *cp, * const *domain; 1791 HEADER *hp = (HEADER *)(void *)target->answer; /*XXX*/ 1792 u_int dots; 1793 int trailing_dot, ret, saved_herrno; 1794 int got_nodata = 0, got_servfail = 0, tried_as_is = 0; 1795 1796 if ((_res.options & RES_INIT) == 0 && res_init() == -1) { 1797 h_errno = NETDB_INTERNAL; 1798 return (-1); 1799 } 1800 1801 errno = 0; 1802 h_errno = HOST_NOT_FOUND; /* default, if we never query */ 1803 dots = 0; 1804 for (cp = name; *cp; cp++) 1805 dots += (*cp == '.'); 1806 trailing_dot = 0; 1807 if (cp > name && *--cp == '.') 1808 trailing_dot++; 1809 1810 /* 1811 * if there aren't any dots, it could be a user-level alias 1812 */ 1813 if (!dots && (cp = __hostalias(name)) != NULL) 1814 return (res_queryN(cp, target)); 1815 1816 /* 1817 * If there are dots in the name already, let's just give it a try 1818 * 'as is'. The threshold can be set with the "ndots" option. 1819 */ 1820 saved_herrno = -1; 1821 if (dots >= _res.ndots) { 1822 ret = res_querydomainN(name, NULL, target); 1823 if (ret > 0) 1824 return (ret); 1825 saved_herrno = h_errno; 1826 tried_as_is++; 1827 } 1828 1829 /* 1830 * We do at least one level of search if 1831 * - there is no dot and RES_DEFNAME is set, or 1832 * - there is at least one dot, there is no trailing dot, 1833 * and RES_DNSRCH is set. 1834 */ 1835 if ((!dots && (_res.options & RES_DEFNAMES)) || 1836 (dots && !trailing_dot && (_res.options & RES_DNSRCH))) { 1837 int done = 0; 1838 1839 for (domain = (const char * const *)_res.dnsrch; 1840 *domain && !done; 1841 domain++) { 1842 1843 ret = res_querydomainN(name, *domain, target); 1844 if (ret > 0) 1845 return (ret); 1846 1847 /* 1848 * If no server present, give up. 1849 * If name isn't found in this domain, 1850 * keep trying higher domains in the search list 1851 * (if that's enabled). 1852 * On a NO_DATA error, keep trying, otherwise 1853 * a wildcard entry of another type could keep us 1854 * from finding this entry higher in the domain. 1855 * If we get some other error (negative answer or 1856 * server failure), then stop searching up, 1857 * but try the input name below in case it's 1858 * fully-qualified. 1859 */ 1860 if (errno == ECONNREFUSED) { 1861 h_errno = TRY_AGAIN; 1862 return (-1); 1863 } 1864 1865 switch (h_errno) { 1866 case NO_DATA: 1867 got_nodata++; 1868 /* FALLTHROUGH */ 1869 case HOST_NOT_FOUND: 1870 /* keep trying */ 1871 break; 1872 case TRY_AGAIN: 1873 if (hp->rcode == SERVFAIL) { 1874 /* try next search element, if any */ 1875 got_servfail++; 1876 break; 1877 } 1878 /* FALLTHROUGH */ 1879 default: 1880 /* anything else implies that we're done */ 1881 done++; 1882 } 1883 /* 1884 * if we got here for some reason other than DNSRCH, 1885 * we only wanted one iteration of the loop, so stop. 1886 */ 1887 if (!(_res.options & RES_DNSRCH)) 1888 done++; 1889 } 1890 } 1891 1892 /* 1893 * if we have not already tried the name "as is", do that now. 1894 * note that we do this regardless of how many dots were in the 1895 * name or whether it ends with a dot. 1896 */ 1897 if (!tried_as_is && (dots || !(_res.options & RES_NOTLDQUERY))) { 1898 ret = res_querydomainN(name, NULL, target); 1899 if (ret > 0) 1900 return (ret); 1901 } 1902 1903 /* 1904 * if we got here, we didn't satisfy the search. 1905 * if we did an initial full query, return that query's h_errno 1906 * (note that we wouldn't be here if that query had succeeded). 1907 * else if we ever got a nodata, send that back as the reason. 1908 * else send back meaningless h_errno, that being the one from 1909 * the last DNSRCH we did. 1910 */ 1911 if (saved_herrno != -1) 1912 h_errno = saved_herrno; 1913 else if (got_nodata) 1914 h_errno = NO_DATA; 1915 else if (got_servfail) 1916 h_errno = TRY_AGAIN; 1917 return (-1); 1918} 1919 1920/* 1921 * Perform a call on res_query on the concatenation of name and domain, 1922 * removing a trailing dot from name if domain is NULL. 1923 */ 1924static int 1925res_querydomainN(name, domain, target) 1926 const char *name, *domain; 1927 struct res_target *target; 1928{ 1929 char nbuf[MAXDNAME]; 1930 const char *longname = nbuf; 1931 size_t n, d; 1932 1933 if ((_res.options & RES_INIT) == 0 && res_init() == -1) { 1934 h_errno = NETDB_INTERNAL; 1935 return (-1); 1936 } 1937#ifdef DEBUG 1938 if (_res.options & RES_DEBUG) 1939 printf(";; res_querydomain(%s, %s)\n", 1940 name, domain?domain:"<Nil>"); 1941#endif 1942 if (domain == NULL) { 1943 /* 1944 * Check for trailing '.'; 1945 * copy without '.' if present. 1946 */ 1947 n = strlen(name); 1948 if (n >= MAXDNAME) { 1949 h_errno = NO_RECOVERY; 1950 return (-1); 1951 } 1952 if (n > 0 && name[--n] == '.') { 1953 strncpy(nbuf, name, n); 1954 nbuf[n] = '\0'; 1955 } else 1956 longname = name; 1957 } else { 1958 n = strlen(name); 1959 d = strlen(domain); 1960 if (n + d + 1 >= MAXDNAME) { 1961 h_errno = NO_RECOVERY; 1962 return (-1); 1963 } 1964 sprintf(nbuf, "%s.%s", name, domain); 1965 } 1966 return (res_queryN(longname, target)); 1967} 1968