getaddrinfo.c revision 103357
1/* $KAME: getaddrinfo.c,v 1.15 2000/07/09 04:37:24 itojun Exp $ */ 2 3/* 4 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the project nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32/* 33 * "#ifdef FAITH" part is local hack for supporting IPv4-v6 translator. 34 * 35 * Issues to be discussed: 36 * - Thread safe-ness must be checked. 37 * - Return values. There are nonstandard return values defined and used 38 * in the source code. This is because RFC2553 is silent about which error 39 * code must be returned for which situation. 40 * - freeaddrinfo(NULL). RFC2553 is silent about it. XNET 5.2 says it is 41 * invalid. 42 * current code - SEGV on freeaddrinfo(NULL) 43 * Note: 44 * - We use getipnodebyname() just for thread-safeness. There's no intent 45 * to let it do PF_UNSPEC (actually we never pass PF_UNSPEC to 46 * getipnodebyname(). 47 * - The code filters out AFs that are not supported by the kernel, 48 * when globbing NULL hostname (to loopback, or wildcard). Is it the right 49 * thing to do? What is the relationship with post-RFC2553 AI_ADDRCONFIG 50 * in ai_flags? 51 * - (post-2553) semantics of AI_ADDRCONFIG itself is too vague. 52 * (1) what should we do against numeric hostname (2) what should we do 53 * against NULL hostname (3) what is AI_ADDRCONFIG itself. AF not ready? 54 * non-loopback address configured? global address configured? 55 * - To avoid search order issue, we have a big amount of code duplicate 56 * from gethnamaddr.c and some other places. The issues that there's no 57 * lower layer function to lookup "IPv4 or IPv6" record. Calling 58 * gethostbyname2 from getaddrinfo will end up in wrong search order, as 59 * follows: 60 * - The code makes use of following calls when asked to resolver with 61 * ai_family = PF_UNSPEC: 62 * getipnodebyname(host, AF_INET6); 63 * getipnodebyname(host, AF_INET); 64 * This will result in the following queries if the node is configure to 65 * prefer /etc/hosts than DNS: 66 * lookup /etc/hosts for IPv6 address 67 * lookup DNS for IPv6 address 68 * lookup /etc/hosts for IPv4 address 69 * lookup DNS for IPv4 address 70 * which may not meet people's requirement. 71 * The right thing to happen is to have underlying layer which does 72 * PF_UNSPEC lookup (lookup both) and return chain of addrinfos. 73 * This would result in a bit of code duplicate with _dns_ghbyname() and 74 * friends. 75 */ 76/* 77 * diffs with other KAME platforms: 78 * - other KAME platforms already nuked FAITH ($GAI), but as FreeBSD 79 * 4.0-RELEASE supplies it, we still have the code here. 80 * - AI_ADDRCONFIG support is supplied 81 * - some of FreeBSD style (#define tabify and others) 82 * - classful IPv4 numeric (127.1) is allowed. 83 */ 84 85#include <sys/cdefs.h> 86__FBSDID("$FreeBSD: head/lib/libc/net/getaddrinfo.c 103357 2002-09-15 20:36:38Z ume $"); 87 88#include "namespace.h" 89#include <sys/types.h> 90#include <sys/param.h> 91#include <sys/socket.h> 92#include <net/if.h> 93#include <netinet/in.h> 94#include <arpa/inet.h> 95#include <arpa/nameser.h> 96#include <rpc/rpc.h> 97#include <rpcsvc/yp_prot.h> 98#include <rpcsvc/ypclnt.h> 99#include <netdb.h> 100#include <resolv.h> 101#include <string.h> 102#include <stdlib.h> 103#include <stddef.h> 104#include <ctype.h> 105#include <unistd.h> 106#include <stdio.h> 107#include <errno.h> 108 109#include "res_config.h" 110 111#ifdef DEBUG 112#include <syslog.h> 113#endif 114 115#include <stdarg.h> 116#include <nsswitch.h> 117#include "un-namespace.h" 118 119#if defined(__KAME__) && defined(INET6) 120# define FAITH 121#endif 122 123#define SUCCESS 0 124#define ANY 0 125#define YES 1 126#define NO 0 127 128static const char in_addrany[] = { 0, 0, 0, 0 }; 129static const char in6_addrany[] = { 130 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 131}; 132static const char in_loopback[] = { 127, 0, 0, 1 }; 133static const char in6_loopback[] = { 134 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 135}; 136 137static const struct afd { 138 int a_af; 139 int a_addrlen; 140 int a_socklen; 141 int a_off; 142 const char *a_addrany; 143 const char *a_loopback; 144 int a_scoped; 145} afdl [] = { 146#ifdef INET6 147#define N_INET6 0 148 {PF_INET6, sizeof(struct in6_addr), 149 sizeof(struct sockaddr_in6), 150 offsetof(struct sockaddr_in6, sin6_addr), 151 in6_addrany, in6_loopback, 1}, 152#define N_INET 1 153#else 154#define N_INET 0 155#endif 156 {PF_INET, sizeof(struct in_addr), 157 sizeof(struct sockaddr_in), 158 offsetof(struct sockaddr_in, sin_addr), 159 in_addrany, in_loopback, 0}, 160 {0, 0, 0, 0, NULL, NULL, 0}, 161}; 162 163struct explore { 164 int e_af; 165 int e_socktype; 166 int e_protocol; 167 const char *e_protostr; 168 int e_wild; 169#define WILD_AF(ex) ((ex)->e_wild & 0x01) 170#define WILD_SOCKTYPE(ex) ((ex)->e_wild & 0x02) 171#define WILD_PROTOCOL(ex) ((ex)->e_wild & 0x04) 172}; 173 174static const struct explore explore[] = { 175#if 0 176 { PF_LOCAL, 0, ANY, ANY, NULL, 0x01 }, 177#endif 178#ifdef INET6 179 { PF_INET6, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 }, 180 { PF_INET6, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 }, 181 { PF_INET6, SOCK_RAW, ANY, NULL, 0x05 }, 182#endif 183 { PF_INET, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 }, 184 { PF_INET, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 }, 185 { PF_INET, SOCK_RAW, ANY, NULL, 0x05 }, 186 { PF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 }, 187 { PF_UNSPEC, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 }, 188 { PF_UNSPEC, SOCK_RAW, ANY, NULL, 0x05 }, 189 { -1, 0, 0, NULL, 0 }, 190}; 191 192#ifdef INET6 193#define PTON_MAX 16 194#else 195#define PTON_MAX 4 196#endif 197 198static const ns_src default_dns_files[] = { 199 { NSSRC_FILES, NS_SUCCESS }, 200 { NSSRC_DNS, NS_SUCCESS }, 201 { 0 } 202}; 203 204#define MAXPACKET (64*1024) 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(const struct addrinfo *, const char *, 222 const char *, struct addrinfo **); 223static int explore_null(const struct addrinfo *, 224 const char *, struct addrinfo **); 225static int explore_numeric(const struct addrinfo *, const char *, 226 const char *, struct addrinfo **); 227static int explore_numeric_scope(const struct addrinfo *, const char *, 228 const char *, struct addrinfo **); 229static int get_canonname(const struct addrinfo *, 230 struct addrinfo *, const char *); 231static struct addrinfo *get_ai(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(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(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 RESOLVSORT 1122struct addr_ptr { 1123 struct addrinfo *ai; 1124 int aval; 1125}; 1126 1127static int 1128addr4sort(struct addrinfo *sentinel) 1129{ 1130 struct addrinfo *ai; 1131 struct addr_ptr *addrs, addr; 1132 struct sockaddr_in *sin; 1133 int naddrs, i, j; 1134 int needsort = 0; 1135 1136 if (!sentinel) 1137 return -1; 1138 naddrs = 0; 1139 for (ai = sentinel->ai_next; ai; ai = ai->ai_next) 1140 naddrs++; 1141 if (naddrs < 2) 1142 return 0; /* We don't need sorting. */ 1143 if ((addrs = malloc(sizeof(struct addr_ptr) * naddrs)) == NULL) 1144 return -1; 1145 i = 0; 1146 for (ai = sentinel->ai_next; ai; ai = ai->ai_next) { 1147 sin = (struct sockaddr_in *)ai->ai_addr; 1148 for (j = 0; (unsigned)j < _res.nsort; j++) { 1149 if (_res.sort_list[j].addr.s_addr == 1150 (sin->sin_addr.s_addr & _res.sort_list[j].mask)) 1151 break; 1152 } 1153 addrs[i].ai = ai; 1154 addrs[i].aval = j; 1155 if (needsort == 0 && i > 0 && j < addrs[i - 1].aval) 1156 needsort = i; 1157 i++; 1158 } 1159 if (!needsort) { 1160 free(addrs); 1161 return 0; 1162 } 1163 1164 while (needsort < naddrs) { 1165 for (j = needsort - 1; j >= 0; j--) { 1166 if (addrs[j].aval > addrs[j+1].aval) { 1167 addr = addrs[j]; 1168 addrs[j] = addrs[j + 1]; 1169 addrs[j + 1] = addr; 1170 } else 1171 break; 1172 } 1173 needsort++; 1174 } 1175 1176 ai = sentinel; 1177 for (i = 0; i < naddrs; ++i) { 1178 ai->ai_next = addrs[i].ai; 1179 ai = ai->ai_next; 1180 } 1181 ai->ai_next = NULL; 1182 free(addrs); 1183 return 0; 1184} 1185#endif /*RESOLVSORT*/ 1186 1187#ifdef DEBUG 1188static const char AskedForGot[] = 1189 "gethostby*.getanswer: asked for \"%s\", got \"%s\""; 1190#endif 1191static FILE *hostf = NULL; 1192 1193static struct addrinfo * 1194getanswer(answer, anslen, qname, qtype, pai) 1195 const querybuf *answer; 1196 int anslen; 1197 const char *qname; 1198 int qtype; 1199 const struct addrinfo *pai; 1200{ 1201 struct addrinfo sentinel, *cur; 1202 struct addrinfo ai; 1203 const struct afd *afd; 1204 char *canonname; 1205 const HEADER *hp; 1206 const u_char *cp; 1207 int n; 1208 const u_char *eom; 1209 char *bp; 1210 int type, class, buflen, ancount, qdcount; 1211 int haveanswer, had_error; 1212 char tbuf[MAXDNAME]; 1213 int (*name_ok)(const char *); 1214 char hostbuf[8*1024]; 1215 1216 memset(&sentinel, 0, sizeof(sentinel)); 1217 cur = &sentinel; 1218 1219 canonname = NULL; 1220 eom = answer->buf + anslen; 1221 switch (qtype) { 1222 case T_A: 1223 case T_AAAA: 1224 case T_ANY: /*use T_ANY only for T_A/T_AAAA lookup*/ 1225 name_ok = res_hnok; 1226 break; 1227 default: 1228 return (NULL); /* XXX should be abort(); */ 1229 } 1230 /* 1231 * find first satisfactory answer 1232 */ 1233 hp = &answer->hdr; 1234 ancount = ntohs(hp->ancount); 1235 qdcount = ntohs(hp->qdcount); 1236 bp = hostbuf; 1237 buflen = sizeof hostbuf; 1238 cp = answer->buf + HFIXEDSZ; 1239 if (qdcount != 1) { 1240 h_errno = NO_RECOVERY; 1241 return (NULL); 1242 } 1243 n = dn_expand(answer->buf, eom, cp, bp, buflen); 1244 if ((n < 0) || !(*name_ok)(bp)) { 1245 h_errno = NO_RECOVERY; 1246 return (NULL); 1247 } 1248 cp += n + QFIXEDSZ; 1249 if (qtype == T_A || qtype == T_AAAA || qtype == T_ANY) { 1250 /* res_send() has already verified that the query name is the 1251 * same as the one we sent; this just gets the expanded name 1252 * (i.e., with the succeeding search-domain tacked on). 1253 */ 1254 n = strlen(bp) + 1; /* for the \0 */ 1255 if (n >= MAXHOSTNAMELEN) { 1256 h_errno = NO_RECOVERY; 1257 return (NULL); 1258 } 1259 canonname = bp; 1260 bp += n; 1261 buflen -= n; 1262 /* The qname can be abbreviated, but h_name is now absolute. */ 1263 qname = canonname; 1264 } 1265 haveanswer = 0; 1266 had_error = 0; 1267 while (ancount-- > 0 && cp < eom && !had_error) { 1268 n = dn_expand(answer->buf, eom, cp, bp, buflen); 1269 if ((n < 0) || !(*name_ok)(bp)) { 1270 had_error++; 1271 continue; 1272 } 1273 cp += n; /* name */ 1274 type = _getshort(cp); 1275 cp += INT16SZ; /* type */ 1276 class = _getshort(cp); 1277 cp += INT16SZ + INT32SZ; /* class, TTL */ 1278 n = _getshort(cp); 1279 cp += INT16SZ; /* len */ 1280 if (class != C_IN) { 1281 /* XXX - debug? syslog? */ 1282 cp += n; 1283 continue; /* XXX - had_error++ ? */ 1284 } 1285 if ((qtype == T_A || qtype == T_AAAA || qtype == T_ANY) && 1286 type == T_CNAME) { 1287 n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf); 1288 if ((n < 0) || !(*name_ok)(tbuf)) { 1289 had_error++; 1290 continue; 1291 } 1292 cp += n; 1293 /* Get canonical name. */ 1294 n = strlen(tbuf) + 1; /* for the \0 */ 1295 if (n > buflen || n >= MAXHOSTNAMELEN) { 1296 had_error++; 1297 continue; 1298 } 1299 strcpy(bp, tbuf); 1300 canonname = bp; 1301 bp += n; 1302 buflen -= n; 1303 continue; 1304 } 1305 if (qtype == T_ANY) { 1306 if (!(type == T_A || type == T_AAAA)) { 1307 cp += n; 1308 continue; 1309 } 1310 } else if (type != qtype) { 1311#ifdef DEBUG 1312 if (type != T_KEY && type != T_SIG) 1313 syslog(LOG_NOTICE|LOG_AUTH, 1314 "gethostby*.getanswer: asked for \"%s %s %s\", got type \"%s\"", 1315 qname, p_class(C_IN), p_type(qtype), 1316 p_type(type)); 1317#endif 1318 cp += n; 1319 continue; /* XXX - had_error++ ? */ 1320 } 1321 switch (type) { 1322 case T_A: 1323 case T_AAAA: 1324 if (strcasecmp(canonname, bp) != 0) { 1325#ifdef DEBUG 1326 syslog(LOG_NOTICE|LOG_AUTH, 1327 AskedForGot, canonname, bp); 1328#endif 1329 cp += n; 1330 continue; /* XXX - had_error++ ? */ 1331 } 1332 if (type == T_A && n != INADDRSZ) { 1333 cp += n; 1334 continue; 1335 } 1336 if (type == T_AAAA && n != IN6ADDRSZ) { 1337 cp += n; 1338 continue; 1339 } 1340#ifdef FILTER_V4MAPPED 1341 if (type == T_AAAA) { 1342 struct in6_addr in6; 1343 memcpy(&in6, cp, sizeof(in6)); 1344 if (IN6_IS_ADDR_V4MAPPED(&in6)) { 1345 cp += n; 1346 continue; 1347 } 1348 } 1349#endif 1350 if (!haveanswer) { 1351 int nn; 1352 1353 canonname = bp; 1354 nn = strlen(bp) + 1; /* for the \0 */ 1355 bp += nn; 1356 buflen -= nn; 1357 } 1358 1359 /* don't overwrite pai */ 1360 ai = *pai; 1361 ai.ai_family = (type == T_A) ? AF_INET : AF_INET6; 1362 afd = find_afd(ai.ai_family); 1363 if (afd == NULL) { 1364 cp += n; 1365 continue; 1366 } 1367 cur->ai_next = get_ai(&ai, afd, (const char *)cp); 1368 if (cur->ai_next == NULL) 1369 had_error++; 1370 while (cur && cur->ai_next) 1371 cur = cur->ai_next; 1372 cp += n; 1373 break; 1374 default: 1375 abort(); 1376 } 1377 if (!had_error) 1378 haveanswer++; 1379 } 1380 if (haveanswer) { 1381#if defined(RESOLVSORT) 1382 /* 1383 * We support only IPv4 address for backward 1384 * compatibility against gethostbyname(3). 1385 */ 1386 if (_res.nsort && qtype == T_A) { 1387 if (addr4sort(&sentinel) < 0) { 1388 freeaddrinfo(sentinel.ai_next); 1389 h_errno = NO_RECOVERY; 1390 return NULL; 1391 } 1392 } 1393#endif /*RESOLVSORT*/ 1394 if (!canonname) 1395 (void)get_canonname(pai, sentinel.ai_next, qname); 1396 else 1397 (void)get_canonname(pai, sentinel.ai_next, canonname); 1398 h_errno = NETDB_SUCCESS; 1399 return sentinel.ai_next; 1400 } 1401 1402 h_errno = NO_RECOVERY; 1403 return NULL; 1404} 1405 1406/*ARGSUSED*/ 1407static int 1408_dns_getaddrinfo(rv, cb_data, ap) 1409 void *rv; 1410 void *cb_data; 1411 va_list ap; 1412{ 1413 struct addrinfo *ai; 1414 querybuf *buf, *buf2; 1415 const char *name; 1416 const struct addrinfo *pai; 1417 struct addrinfo sentinel, *cur; 1418 struct res_target q, q2; 1419 1420 name = va_arg(ap, char *); 1421 pai = va_arg(ap, const struct addrinfo *); 1422 1423 memset(&q, 0, sizeof(q2)); 1424 memset(&q2, 0, sizeof(q2)); 1425 memset(&sentinel, 0, sizeof(sentinel)); 1426 cur = &sentinel; 1427 1428 buf = malloc(sizeof(*buf)); 1429 if (!buf) { 1430 h_errno = NETDB_INTERNAL; 1431 return NS_NOTFOUND; 1432 } 1433 buf2 = malloc(sizeof(*buf2)); 1434 if (!buf2) { 1435 free(buf); 1436 h_errno = NETDB_INTERNAL; 1437 return NS_NOTFOUND; 1438 } 1439 1440 switch (pai->ai_family) { 1441 case AF_UNSPEC: 1442 /* prefer IPv6 */ 1443 q.qclass = C_IN; 1444 q.qtype = T_AAAA; 1445 q.answer = buf->buf; 1446 q.anslen = sizeof(buf->buf); 1447 q.next = &q2; 1448 q2.qclass = C_IN; 1449 q2.qtype = T_A; 1450 q2.answer = buf2->buf; 1451 q2.anslen = sizeof(buf2->buf); 1452 break; 1453 case AF_INET: 1454 q.qclass = C_IN; 1455 q.qtype = T_A; 1456 q.answer = buf->buf; 1457 q.anslen = sizeof(buf->buf); 1458 break; 1459 case AF_INET6: 1460 q.qclass = C_IN; 1461 q.qtype = T_AAAA; 1462 q.answer = buf->buf; 1463 q.anslen = sizeof(buf->buf); 1464 break; 1465 default: 1466 free(buf); 1467 free(buf2); 1468 return NS_UNAVAIL; 1469 } 1470 if (res_searchN(name, &q) < 0) { 1471 free(buf); 1472 free(buf2); 1473 return NS_NOTFOUND; 1474 } 1475 ai = getanswer(buf, q.n, q.name, q.qtype, pai); 1476 if (ai) { 1477 cur->ai_next = ai; 1478 while (cur && cur->ai_next) 1479 cur = cur->ai_next; 1480 } 1481 if (q.next) { 1482 ai = getanswer(buf2, q2.n, q2.name, q2.qtype, pai); 1483 if (ai) 1484 cur->ai_next = ai; 1485 } 1486 free(buf); 1487 free(buf2); 1488 if (sentinel.ai_next == NULL) 1489 switch (h_errno) { 1490 case HOST_NOT_FOUND: 1491 return NS_NOTFOUND; 1492 case TRY_AGAIN: 1493 return NS_TRYAGAIN; 1494 default: 1495 return NS_UNAVAIL; 1496 } 1497 *((struct addrinfo **)rv) = sentinel.ai_next; 1498 return NS_SUCCESS; 1499} 1500 1501static void 1502_sethtent() 1503{ 1504 if (!hostf) 1505 hostf = fopen(_PATH_HOSTS, "r" ); 1506 else 1507 rewind(hostf); 1508} 1509 1510static void 1511_endhtent() 1512{ 1513 if (hostf) { 1514 (void) fclose(hostf); 1515 hostf = NULL; 1516 } 1517} 1518 1519static struct addrinfo * 1520_gethtent(name, pai) 1521 const char *name; 1522 const struct addrinfo *pai; 1523{ 1524 char *p; 1525 char *cp, *tname, *cname; 1526 struct addrinfo hints, *res0, *res; 1527 int error; 1528 const char *addr; 1529 char hostbuf[8*1024]; 1530 1531 if (!hostf && !(hostf = fopen(_PATH_HOSTS, "r" ))) 1532 return (NULL); 1533 again: 1534 if (!(p = fgets(hostbuf, sizeof hostbuf, hostf))) 1535 return (NULL); 1536 if (*p == '#') 1537 goto again; 1538 if (!(cp = strpbrk(p, "#\n"))) 1539 goto again; 1540 *cp = '\0'; 1541 if (!(cp = strpbrk(p, " \t"))) 1542 goto again; 1543 *cp++ = '\0'; 1544 addr = p; 1545 cname = NULL; 1546 /* if this is not something we're looking for, skip it. */ 1547 while (cp && *cp) { 1548 if (*cp == ' ' || *cp == '\t') { 1549 cp++; 1550 continue; 1551 } 1552 tname = cp; 1553 if (cname == NULL) 1554 cname = cp; 1555 if ((cp = strpbrk(cp, " \t")) != NULL) 1556 *cp++ = '\0'; 1557 if (strcasecmp(name, tname) == 0) 1558 goto found; 1559 } 1560 goto again; 1561 1562found: 1563 hints = *pai; 1564 hints.ai_flags = AI_NUMERICHOST; 1565 error = getaddrinfo(addr, NULL, &hints, &res0); 1566 if (error) 1567 goto again; 1568#ifdef FILTER_V4MAPPED 1569 /* XXX should check all items in the chain */ 1570 if (res0->ai_family == AF_INET6 && 1571 IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)res0->ai_addr)->sin6_addr)) { 1572 freeaddrinfo(res0); 1573 goto again; 1574 } 1575#endif 1576 for (res = res0; res; res = res->ai_next) { 1577 /* cover it up */ 1578 res->ai_flags = pai->ai_flags; 1579 1580 if (pai->ai_flags & AI_CANONNAME) { 1581 if (get_canonname(pai, res, cname) != 0) { 1582 freeaddrinfo(res0); 1583 goto again; 1584 } 1585 } 1586 } 1587 return res0; 1588} 1589 1590/*ARGSUSED*/ 1591static int 1592_files_getaddrinfo(rv, cb_data, ap) 1593 void *rv; 1594 void *cb_data; 1595 va_list ap; 1596{ 1597 const char *name; 1598 const struct addrinfo *pai; 1599 struct addrinfo sentinel, *cur; 1600 struct addrinfo *p; 1601 1602 name = va_arg(ap, char *); 1603 pai = va_arg(ap, struct addrinfo *); 1604 1605 memset(&sentinel, 0, sizeof(sentinel)); 1606 cur = &sentinel; 1607 1608 _sethtent(); 1609 while ((p = _gethtent(name, pai)) != NULL) { 1610 cur->ai_next = p; 1611 while (cur && cur->ai_next) 1612 cur = cur->ai_next; 1613 } 1614 _endhtent(); 1615 1616 *((struct addrinfo **)rv) = sentinel.ai_next; 1617 if (sentinel.ai_next == NULL) 1618 return NS_NOTFOUND; 1619 return NS_SUCCESS; 1620} 1621 1622#ifdef YP 1623static char *__ypdomain; 1624 1625/*ARGSUSED*/ 1626static struct addrinfo * 1627_yphostent(line, pai) 1628 char *line; 1629 const struct addrinfo *pai; 1630{ 1631 struct addrinfo sentinel, *cur; 1632 struct addrinfo hints, *res, *res0; 1633 int error; 1634 char *p = line; 1635 const char *addr, *canonname; 1636 char *nextline; 1637 char *cp; 1638 1639 addr = canonname = NULL; 1640 1641 memset(&sentinel, 0, sizeof(sentinel)); 1642 cur = &sentinel; 1643 1644nextline: 1645 /* terminate line */ 1646 cp = strchr(p, '\n'); 1647 if (cp) { 1648 *cp++ = '\0'; 1649 nextline = cp; 1650 } else 1651 nextline = NULL; 1652 1653 cp = strpbrk(p, " \t"); 1654 if (cp == NULL) { 1655 if (canonname == NULL) 1656 return (NULL); 1657 else 1658 goto done; 1659 } 1660 *cp++ = '\0'; 1661 1662 addr = p; 1663 1664 while (cp && *cp) { 1665 if (*cp == ' ' || *cp == '\t') { 1666 cp++; 1667 continue; 1668 } 1669 if (!canonname) 1670 canonname = cp; 1671 if ((cp = strpbrk(cp, " \t")) != NULL) 1672 *cp++ = '\0'; 1673 } 1674 1675 hints = *pai; 1676 hints.ai_flags = AI_NUMERICHOST; 1677 error = getaddrinfo(addr, NULL, &hints, &res0); 1678 if (error == 0) { 1679 for (res = res0; res; res = res->ai_next) { 1680 /* cover it up */ 1681 res->ai_flags = pai->ai_flags; 1682 1683 if (pai->ai_flags & AI_CANONNAME) 1684 (void)get_canonname(pai, res, canonname); 1685 } 1686 } else 1687 res0 = NULL; 1688 if (res0) { 1689 cur->ai_next = res0; 1690 while (cur && cur->ai_next) 1691 cur = cur->ai_next; 1692 } 1693 1694 if (nextline) { 1695 p = nextline; 1696 goto nextline; 1697 } 1698 1699done: 1700 return sentinel.ai_next; 1701} 1702 1703/*ARGSUSED*/ 1704static int 1705_yp_getaddrinfo(rv, cb_data, ap) 1706 void *rv; 1707 void *cb_data; 1708 va_list ap; 1709{ 1710 struct addrinfo sentinel, *cur; 1711 struct addrinfo *ai = NULL; 1712 static char *__ypcurrent; 1713 int __ypcurrentlen, r; 1714 const char *name; 1715 const struct addrinfo *pai; 1716 1717 name = va_arg(ap, char *); 1718 pai = va_arg(ap, const struct addrinfo *); 1719 1720 memset(&sentinel, 0, sizeof(sentinel)); 1721 cur = &sentinel; 1722 1723 if (!__ypdomain) { 1724 if (_yp_check(&__ypdomain) == 0) 1725 return NS_UNAVAIL; 1726 } 1727 if (__ypcurrent) 1728 free(__ypcurrent); 1729 __ypcurrent = NULL; 1730 1731 /* hosts.byname is only for IPv4 (Solaris8) */ 1732 if (pai->ai_family == PF_UNSPEC || pai->ai_family == PF_INET) { 1733 r = yp_match(__ypdomain, "hosts.byname", name, 1734 (int)strlen(name), &__ypcurrent, &__ypcurrentlen); 1735 if (r == 0) { 1736 struct addrinfo ai4; 1737 1738 ai4 = *pai; 1739 ai4.ai_family = AF_INET; 1740 ai = _yphostent(__ypcurrent, &ai4); 1741 if (ai) { 1742 cur->ai_next = ai; 1743 while (cur && cur->ai_next) 1744 cur = cur->ai_next; 1745 } 1746 } 1747 } 1748 1749 /* ipnodes.byname can hold both IPv4/v6 */ 1750 r = yp_match(__ypdomain, "ipnodes.byname", name, 1751 (int)strlen(name), &__ypcurrent, &__ypcurrentlen); 1752 if (r == 0) { 1753 ai = _yphostent(__ypcurrent, pai); 1754 if (ai) { 1755 cur->ai_next = ai; 1756 while (cur && cur->ai_next) 1757 cur = cur->ai_next; 1758 } 1759 } 1760 1761 if (sentinel.ai_next == NULL) { 1762 h_errno = HOST_NOT_FOUND; 1763 return NS_NOTFOUND; 1764 } 1765 *((struct addrinfo **)rv) = sentinel.ai_next; 1766 return NS_SUCCESS; 1767} 1768#endif 1769 1770/* resolver logic */ 1771 1772extern const char *__hostalias(const char *); 1773extern int h_errno; 1774 1775/* 1776 * Formulate a normal query, send, and await answer. 1777 * Returned answer is placed in supplied buffer "answer". 1778 * Perform preliminary check of answer, returning success only 1779 * if no error is indicated and the answer count is nonzero. 1780 * Return the size of the response on success, -1 on error. 1781 * Error number is left in h_errno. 1782 * 1783 * Caller must parse answer and determine whether it answers the question. 1784 */ 1785static int 1786res_queryN(name, target) 1787 const char *name; /* domain name */ 1788 struct res_target *target; 1789{ 1790 u_char *buf; 1791 HEADER *hp; 1792 int n; 1793 struct res_target *t; 1794 int rcode; 1795 int ancount; 1796 1797 rcode = NOERROR; 1798 ancount = 0; 1799 1800 if ((_res.options & RES_INIT) == 0 && res_init() == -1) { 1801 h_errno = NETDB_INTERNAL; 1802 return (-1); 1803 } 1804 1805 buf = malloc(MAXPACKET); 1806 if (!buf) { 1807 h_errno = NETDB_INTERNAL; 1808 return -1; 1809 } 1810 1811 for (t = target; t; t = t->next) { 1812 int class, type; 1813 u_char *answer; 1814 int anslen; 1815 1816 hp = (HEADER *)(void *)t->answer; 1817 hp->rcode = NOERROR; /* default */ 1818 1819 /* make it easier... */ 1820 class = t->qclass; 1821 type = t->qtype; 1822 answer = t->answer; 1823 anslen = t->anslen; 1824#ifdef DEBUG 1825 if (_res.options & RES_DEBUG) 1826 printf(";; res_query(%s, %d, %d)\n", name, class, type); 1827#endif 1828 1829 n = res_mkquery(QUERY, name, class, type, NULL, 0, NULL, 1830 buf, MAXPACKET); 1831 if (n > 0 && (_res.options & RES_USE_EDNS0) != 0) 1832 n = res_opt(n, buf, MAXPACKET, anslen); 1833 if (n <= 0) { 1834#ifdef DEBUG 1835 if (_res.options & RES_DEBUG) 1836 printf(";; res_query: mkquery failed\n"); 1837#endif 1838 free(buf); 1839 h_errno = NO_RECOVERY; 1840 return (n); 1841 } 1842 n = res_send(buf, n, answer, anslen); 1843#if 0 1844 if (n < 0) { 1845#ifdef DEBUG 1846 if (_res.options & RES_DEBUG) 1847 printf(";; res_query: send error\n"); 1848#endif 1849 free(buf); 1850 h_errno = TRY_AGAIN; 1851 return (n); 1852 } 1853#endif 1854 1855 if (n < 0 || n > anslen) 1856 hp->rcode = FORMERR; /* XXX not very informative */ 1857 if (hp->rcode != NOERROR || ntohs(hp->ancount) == 0) { 1858 rcode = hp->rcode; /* record most recent error */ 1859#ifdef DEBUG 1860 if (_res.options & RES_DEBUG) 1861 printf(";; rcode = %d, ancount=%d\n", hp->rcode, 1862 ntohs(hp->ancount)); 1863#endif 1864 continue; 1865 } 1866 1867 ancount += ntohs(hp->ancount); 1868 1869 t->n = n; 1870 } 1871 1872 free(buf); 1873 1874 if (ancount == 0) { 1875 switch (rcode) { 1876 case NXDOMAIN: 1877 h_errno = HOST_NOT_FOUND; 1878 break; 1879 case SERVFAIL: 1880 h_errno = TRY_AGAIN; 1881 break; 1882 case NOERROR: 1883 h_errno = NO_DATA; 1884 break; 1885 case FORMERR: 1886 case NOTIMP: 1887 case REFUSED: 1888 default: 1889 h_errno = NO_RECOVERY; 1890 break; 1891 } 1892 return (-1); 1893 } 1894 return (ancount); 1895} 1896 1897/* 1898 * Formulate a normal query, send, and retrieve answer in supplied buffer. 1899 * Return the size of the response on success, -1 on error. 1900 * If enabled, implement search rules until answer or unrecoverable failure 1901 * is detected. Error code, if any, is left in h_errno. 1902 */ 1903static int 1904res_searchN(name, target) 1905 const char *name; /* domain name */ 1906 struct res_target *target; 1907{ 1908 const char *cp, * const *domain; 1909 HEADER *hp = (HEADER *)(void *)target->answer; /*XXX*/ 1910 u_int dots; 1911 int trailing_dot, ret, saved_herrno; 1912 int got_nodata = 0, got_servfail = 0, tried_as_is = 0; 1913 1914 if ((_res.options & RES_INIT) == 0 && res_init() == -1) { 1915 h_errno = NETDB_INTERNAL; 1916 return (-1); 1917 } 1918 1919 errno = 0; 1920 h_errno = HOST_NOT_FOUND; /* default, if we never query */ 1921 dots = 0; 1922 for (cp = name; *cp; cp++) 1923 dots += (*cp == '.'); 1924 trailing_dot = 0; 1925 if (cp > name && *--cp == '.') 1926 trailing_dot++; 1927 1928 /* 1929 * if there aren't any dots, it could be a user-level alias 1930 */ 1931 if (!dots && (cp = __hostalias(name)) != NULL) 1932 return (res_queryN(cp, target)); 1933 1934 /* 1935 * If there are dots in the name already, let's just give it a try 1936 * 'as is'. The threshold can be set with the "ndots" option. 1937 */ 1938 saved_herrno = -1; 1939 if (dots >= _res.ndots) { 1940 ret = res_querydomainN(name, NULL, target); 1941 if (ret > 0) 1942 return (ret); 1943 saved_herrno = h_errno; 1944 tried_as_is++; 1945 } 1946 1947 /* 1948 * We do at least one level of search if 1949 * - there is no dot and RES_DEFNAME is set, or 1950 * - there is at least one dot, there is no trailing dot, 1951 * and RES_DNSRCH is set. 1952 */ 1953 if ((!dots && (_res.options & RES_DEFNAMES)) || 1954 (dots && !trailing_dot && (_res.options & RES_DNSRCH))) { 1955 int done = 0; 1956 1957 for (domain = (const char * const *)_res.dnsrch; 1958 *domain && !done; 1959 domain++) { 1960 1961 ret = res_querydomainN(name, *domain, target); 1962 if (ret > 0) 1963 return (ret); 1964 1965 /* 1966 * If no server present, give up. 1967 * If name isn't found in this domain, 1968 * keep trying higher domains in the search list 1969 * (if that's enabled). 1970 * On a NO_DATA error, keep trying, otherwise 1971 * a wildcard entry of another type could keep us 1972 * from finding this entry higher in the domain. 1973 * If we get some other error (negative answer or 1974 * server failure), then stop searching up, 1975 * but try the input name below in case it's 1976 * fully-qualified. 1977 */ 1978 if (errno == ECONNREFUSED) { 1979 h_errno = TRY_AGAIN; 1980 return (-1); 1981 } 1982 1983 switch (h_errno) { 1984 case NO_DATA: 1985 got_nodata++; 1986 /* FALLTHROUGH */ 1987 case HOST_NOT_FOUND: 1988 /* keep trying */ 1989 break; 1990 case TRY_AGAIN: 1991 if (hp->rcode == SERVFAIL) { 1992 /* try next search element, if any */ 1993 got_servfail++; 1994 break; 1995 } 1996 /* FALLTHROUGH */ 1997 default: 1998 /* anything else implies that we're done */ 1999 done++; 2000 } 2001 /* 2002 * if we got here for some reason other than DNSRCH, 2003 * we only wanted one iteration of the loop, so stop. 2004 */ 2005 if (!(_res.options & RES_DNSRCH)) 2006 done++; 2007 } 2008 } 2009 2010 /* 2011 * if we have not already tried the name "as is", do that now. 2012 * note that we do this regardless of how many dots were in the 2013 * name or whether it ends with a dot. 2014 */ 2015 if (!tried_as_is && (dots || !(_res.options & RES_NOTLDQUERY))) { 2016 ret = res_querydomainN(name, NULL, target); 2017 if (ret > 0) 2018 return (ret); 2019 } 2020 2021 /* 2022 * if we got here, we didn't satisfy the search. 2023 * if we did an initial full query, return that query's h_errno 2024 * (note that we wouldn't be here if that query had succeeded). 2025 * else if we ever got a nodata, send that back as the reason. 2026 * else send back meaningless h_errno, that being the one from 2027 * the last DNSRCH we did. 2028 */ 2029 if (saved_herrno != -1) 2030 h_errno = saved_herrno; 2031 else if (got_nodata) 2032 h_errno = NO_DATA; 2033 else if (got_servfail) 2034 h_errno = TRY_AGAIN; 2035 return (-1); 2036} 2037 2038/* 2039 * Perform a call on res_query on the concatenation of name and domain, 2040 * removing a trailing dot from name if domain is NULL. 2041 */ 2042static int 2043res_querydomainN(name, domain, target) 2044 const char *name, *domain; 2045 struct res_target *target; 2046{ 2047 char nbuf[MAXDNAME]; 2048 const char *longname = nbuf; 2049 size_t n, d; 2050 2051 if ((_res.options & RES_INIT) == 0 && res_init() == -1) { 2052 h_errno = NETDB_INTERNAL; 2053 return (-1); 2054 } 2055#ifdef DEBUG 2056 if (_res.options & RES_DEBUG) 2057 printf(";; res_querydomain(%s, %s)\n", 2058 name, domain?domain:"<Nil>"); 2059#endif 2060 if (domain == NULL) { 2061 /* 2062 * Check for trailing '.'; 2063 * copy without '.' if present. 2064 */ 2065 n = strlen(name); 2066 if (n >= MAXDNAME) { 2067 h_errno = NO_RECOVERY; 2068 return (-1); 2069 } 2070 if (n > 0 && name[--n] == '.') { 2071 strncpy(nbuf, name, n); 2072 nbuf[n] = '\0'; 2073 } else 2074 longname = name; 2075 } else { 2076 n = strlen(name); 2077 d = strlen(domain); 2078 if (n + d + 1 >= MAXDNAME) { 2079 h_errno = NO_RECOVERY; 2080 return (-1); 2081 } 2082 sprintf(nbuf, "%s.%s", name, domain); 2083 } 2084 return (res_queryN(longname, target)); 2085} 2086