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