1121474Sume/* $KAME: getaddrinfo.c,v 1.15 2000/07/09 04:37:24 itojun Exp $ */ 262614Sitojun 355163Sshin/* 455163Sshin * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 555163Sshin * All rights reserved. 655163Sshin * 755163Sshin * Redistribution and use in source and binary forms, with or without 855163Sshin * modification, are permitted provided that the following conditions 955163Sshin * are met: 1055163Sshin * 1. Redistributions of source code must retain the above copyright 1155163Sshin * notice, this list of conditions and the following disclaimer. 1255163Sshin * 2. Redistributions in binary form must reproduce the above copyright 1355163Sshin * notice, this list of conditions and the following disclaimer in the 1455163Sshin * documentation and/or other materials provided with the distribution. 1555163Sshin * 3. Neither the name of the project nor the names of its contributors 1655163Sshin * may be used to endorse or promote products derived from this software 1755163Sshin * without specific prior written permission. 1855163Sshin * 1955163Sshin * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 2055163Sshin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2155163Sshin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2255163Sshin * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 2355163Sshin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2455163Sshin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2555163Sshin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2655163Sshin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2755163Sshin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2855163Sshin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2955163Sshin * SUCH DAMAGE. 3055163Sshin */ 3155163Sshin 3255163Sshin/* 3355163Sshin * "#ifdef FAITH" part is local hack for supporting IPv4-v6 translator. 3455163Sshin * 3555163Sshin * Issues to be discussed: 3655163Sshin * - Return values. There are nonstandard return values defined and used 3755163Sshin * in the source code. This is because RFC2553 is silent about which error 3855163Sshin * code must be returned for which situation. 3961877Sume * - freeaddrinfo(NULL). RFC2553 is silent about it. XNET 5.2 says it is 40105940Sume * invalid. current code - SEGV on freeaddrinfo(NULL) 41105940Sume * 4256627Sshin * Note: 4356627Sshin * - The code filters out AFs that are not supported by the kernel, 4456627Sshin * when globbing NULL hostname (to loopback, or wildcard). Is it the right 4556627Sshin * thing to do? What is the relationship with post-RFC2553 AI_ADDRCONFIG 4656627Sshin * in ai_flags? 4761877Sume * - (post-2553) semantics of AI_ADDRCONFIG itself is too vague. 4861877Sume * (1) what should we do against numeric hostname (2) what should we do 4961877Sume * against NULL hostname (3) what is AI_ADDRCONFIG itself. AF not ready? 5061877Sume * non-loopback address configured? global address configured? 51105940Sume * 52105940Sume * OS specific notes for freebsd4: 53105940Sume * - FreeBSD supported $GAI. The code does not. 5455163Sshin */ 5555163Sshin 5692986Sobrien#include <sys/cdefs.h> 5792986Sobrien__FBSDID("$FreeBSD: releng/10.3/lib/libc/net/getaddrinfo.c 292826 2015-12-28 03:37:13Z ume $"); 5892986Sobrien 5971579Sdeischen#include "namespace.h" 6055163Sshin#include <sys/types.h> 6155163Sshin#include <sys/param.h> 6255163Sshin#include <sys/socket.h> 6355163Sshin#include <net/if.h> 6455163Sshin#include <netinet/in.h> 65267874Sume#include <net/if_types.h> 66267874Sume#include <ifaddrs.h> 67121747Sume#include <sys/queue.h> 68121747Sume#ifdef INET6 69121747Sume#include <net/if_var.h> 70121747Sume#include <sys/sysctl.h> 71129901Sume#include <sys/ioctl.h> 72267874Sume#include <netinet6/in6_var.h> 73267874Sume#include <netinet6/nd6.h> 74121747Sume#endif 7555163Sshin#include <arpa/inet.h> 7655163Sshin#include <arpa/nameser.h> 77121474Sume#include <rpc/rpc.h> 78121474Sume#include <rpcsvc/yp_prot.h> 79121474Sume#include <rpcsvc/ypclnt.h> 8055163Sshin#include <netdb.h> 8155163Sshin#include <resolv.h> 8255163Sshin#include <string.h> 8355163Sshin#include <stdlib.h> 8455163Sshin#include <stddef.h> 8555163Sshin#include <ctype.h> 8655163Sshin#include <unistd.h> 8755163Sshin#include <stdio.h> 8861877Sume#include <errno.h> 89102237Spirzyk 90102237Spirzyk#include "res_config.h" 91102237Spirzyk 9278012Sume#ifdef DEBUG 9378012Sume#include <syslog.h> 9478012Sume#endif 9555163Sshin 9665532Snectar#include <stdarg.h> 9765532Snectar#include <nsswitch.h> 9871579Sdeischen#include "un-namespace.h" 99292722Sume#include "netdb_private.h" 100111618Snectar#include "libc_private.h" 101158115Sume#ifdef NS_CACHING 102158115Sume#include "nscache.h" 103158115Sume#endif 10465532Snectar 10555163Sshin#if defined(__KAME__) && defined(INET6) 10655163Sshin# define FAITH 10755163Sshin#endif 10855163Sshin 109105940Sume#define ANY 0 110105940Sume#define YES 1 111105940Sume#define NO 0 11255163Sshin 11355163Sshinstatic const char in_addrany[] = { 0, 0, 0, 0 }; 114105940Sumestatic const char in_loopback[] = { 127, 0, 0, 1 }; 115105940Sume#ifdef INET6 11655163Sshinstatic const char in6_addrany[] = { 11755163Sshin 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 11855163Sshin}; 11955163Sshinstatic const char in6_loopback[] = { 12055163Sshin 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 12155163Sshin}; 122105940Sume#endif 12355163Sshin 124121747Sumestruct policyqueue { 125121747Sume TAILQ_ENTRY(policyqueue) pc_entry; 126121747Sume#ifdef INET6 127121747Sume struct in6_addrpolicy pc_policy; 128121747Sume#endif 129121747Sume}; 130121747SumeTAILQ_HEAD(policyhead, policyqueue); 131121747Sume 13255163Sshinstatic const struct afd { 13355163Sshin int a_af; 13455163Sshin int a_addrlen; 135146244Sume socklen_t a_socklen; 13655163Sshin int a_off; 13755163Sshin const char *a_addrany; 13873665Sobrien const char *a_loopback; 13955163Sshin int a_scoped; 14055163Sshin} afdl [] = { 14155163Sshin#ifdef INET6 14255163Sshin#define N_INET6 0 14355163Sshin {PF_INET6, sizeof(struct in6_addr), 14455163Sshin sizeof(struct sockaddr_in6), 14555163Sshin offsetof(struct sockaddr_in6, sin6_addr), 14655163Sshin in6_addrany, in6_loopback, 1}, 14755163Sshin#define N_INET 1 14855163Sshin#else 14955163Sshin#define N_INET 0 15055163Sshin#endif 15155163Sshin {PF_INET, sizeof(struct in_addr), 15255163Sshin sizeof(struct sockaddr_in), 15355163Sshin offsetof(struct sockaddr_in, sin_addr), 15455163Sshin in_addrany, in_loopback, 0}, 15555163Sshin {0, 0, 0, 0, NULL, NULL, 0}, 15655163Sshin}; 15755163Sshin 15855163Sshinstruct explore { 15961877Sume int e_af; 16055163Sshin int e_socktype; 16155163Sshin int e_protocol; 16255163Sshin int e_wild; 163105940Sume#define WILD_AF(ex) ((ex)->e_wild & 0x01) 164105940Sume#define WILD_SOCKTYPE(ex) ((ex)->e_wild & 0x02) 165105940Sume#define WILD_PROTOCOL(ex) ((ex)->e_wild & 0x04) 16655163Sshin}; 16755163Sshin 16855163Sshinstatic const struct explore explore[] = { 16961877Sume#if 0 170238504Sjilles { PF_LOCAL, ANY, ANY, 0x01 }, 17161877Sume#endif 17261877Sume#ifdef INET6 173238504Sjilles { PF_INET6, SOCK_DGRAM, IPPROTO_UDP, 0x07 }, 174238504Sjilles { PF_INET6, SOCK_STREAM, IPPROTO_TCP, 0x07 }, 175238504Sjilles { PF_INET6, SOCK_STREAM, IPPROTO_SCTP, 0x03 }, 176238504Sjilles { PF_INET6, SOCK_SEQPACKET, IPPROTO_SCTP, 0x07 }, 177265946Skevlo { PF_INET6, SOCK_DGRAM, IPPROTO_UDPLITE, 0x03 }, 178238504Sjilles { PF_INET6, SOCK_RAW, ANY, 0x05 }, 17961877Sume#endif 180238504Sjilles { PF_INET, SOCK_DGRAM, IPPROTO_UDP, 0x07 }, 181238504Sjilles { PF_INET, SOCK_STREAM, IPPROTO_TCP, 0x07 }, 182238504Sjilles { PF_INET, SOCK_STREAM, IPPROTO_SCTP, 0x03 }, 183238504Sjilles { PF_INET, SOCK_SEQPACKET, IPPROTO_SCTP, 0x07 }, 184265946Skevlo { PF_INET, SOCK_DGRAM, IPPROTO_UDPLITE, 0x03 }, 185238504Sjilles { PF_INET, SOCK_RAW, ANY, 0x05 }, 186238504Sjilles { -1, 0, 0, 0 }, 18755163Sshin}; 18855163Sshin 18955163Sshin#ifdef INET6 190105940Sume#define PTON_MAX 16 19155163Sshin#else 192105940Sume#define PTON_MAX 4 19355163Sshin#endif 19455163Sshin 195121747Sume#define AIO_SRCFLAG_DEPRECATED 0x1 196121747Sume 197121747Sumestruct ai_order { 198121747Sume union { 199121747Sume struct sockaddr_storage aiou_ss; 200121747Sume struct sockaddr aiou_sa; 201121747Sume } aio_src_un; 202121747Sume#define aio_srcsa aio_src_un.aiou_sa 203121747Sume u_int32_t aio_srcflag; 204121747Sume int aio_srcscope; 205121747Sume int aio_dstscope; 206121747Sume struct policyqueue *aio_srcpolicy; 207121747Sume struct policyqueue *aio_dstpolicy; 208121747Sume struct addrinfo *aio_ai; 209121747Sume int aio_matchlen; 210121747Sume}; 211121747Sume 21265532Snectarstatic const ns_src default_dns_files[] = { 21365532Snectar { NSSRC_FILES, NS_SUCCESS }, 21465532Snectar { NSSRC_DNS, NS_SUCCESS }, 21565532Snectar { 0 } 21665532Snectar}; 21765532Snectar 21861877Sumestruct res_target { 21961877Sume struct res_target *next; 22061877Sume const char *name; /* domain name */ 22162614Sitojun int qclass, qtype; /* class and type of query */ 22261877Sume u_char *answer; /* buffer to put answer */ 22361877Sume int anslen; /* size of answer buffer */ 22461877Sume int n; /* result length */ 22561877Sume}; 22661877Sume 227121426Sume#define MAXPACKET (64*1024) 228121426Sume 229121426Sumetypedef union { 230121426Sume HEADER hdr; 231121426Sume u_char buf[MAXPACKET]; 232121426Sume} querybuf; 233121426Sume 234160593Sumestatic int str2number(const char *, int *); 235190525Sumestatic int explore_copy(const struct addrinfo *, const struct addrinfo *, 236190525Sume struct addrinfo **); 23792941Sobrienstatic int explore_null(const struct addrinfo *, 23892941Sobrien const char *, struct addrinfo **); 23992941Sobrienstatic int explore_numeric(const struct addrinfo *, const char *, 240140906Sume const char *, struct addrinfo **, const char *); 24192941Sobrienstatic int explore_numeric_scope(const struct addrinfo *, const char *, 24292941Sobrien const char *, struct addrinfo **); 24392941Sobrienstatic int get_canonname(const struct addrinfo *, 24492941Sobrien struct addrinfo *, const char *); 24592941Sobrienstatic struct addrinfo *get_ai(const struct addrinfo *, 24692941Sobrien const struct afd *, const char *); 247190525Sumestatic struct addrinfo *copy_ai(const struct addrinfo *); 24892905Sobrienstatic int get_portmatch(const struct addrinfo *, const char *); 24992905Sobrienstatic int get_port(struct addrinfo *, const char *, int); 25092905Sobrienstatic const struct afd *find_afd(int); 251121474Sumestatic int addrconfig(struct addrinfo *); 252267874Sume#ifdef INET6 253267874Sumestatic int is_ifdisabled(char *); 254267874Sume#endif 255129901Sumestatic void set_source(struct ai_order *, struct policyhead *); 256121747Sumestatic int comp_dst(const void *, const void *); 25761877Sume#ifdef INET6 258105943Sumestatic int ip6_str2scopeid(char *, struct sockaddr_in6 *, u_int32_t *); 25961877Sume#endif 260121747Sumestatic int gai_addr2scopetype(struct sockaddr *); 26155163Sshin 262121426Sumestatic int explore_fqdn(const struct addrinfo *, const char *, 263121426Sume const char *, struct addrinfo **); 264121426Sume 265121747Sumestatic int reorder(struct addrinfo *); 266121747Sumestatic int get_addrselectpolicy(struct policyhead *); 267121747Sumestatic void free_addrselectpolicy(struct policyhead *); 268121747Sumestatic struct policyqueue *match_addrselectpolicy(struct sockaddr *, 269121747Sume struct policyhead *); 270129901Sumestatic int matchlen(struct sockaddr *, struct sockaddr *); 271121747Sume 27292941Sobrienstatic struct addrinfo *getanswer(const querybuf *, int, const char *, int, 273156960Sume const struct addrinfo *, res_state); 274121426Sume#if defined(RESOLVSORT) 275156960Sumestatic int addr4sort(struct addrinfo *, res_state); 276121426Sume#endif 277105943Sumestatic int _dns_getaddrinfo(void *, void *, va_list); 278144634Sumestatic void _sethtent(FILE **); 279144634Sumestatic void _endhtent(FILE **); 280144634Sumestatic struct addrinfo *_gethtent(FILE **, const char *, 281144634Sume const struct addrinfo *); 28292905Sobrienstatic int _files_getaddrinfo(void *, void *, va_list); 28361877Sume#ifdef YP 28492905Sobrienstatic struct addrinfo *_yphostent(char *, const struct addrinfo *); 28592905Sobrienstatic int _yp_getaddrinfo(void *, void *, va_list); 28661877Sume#endif 287158115Sume#ifdef NS_CACHING 288158115Sumestatic int addrinfo_id_func(char *, size_t *, va_list, void *); 289158115Sumestatic int addrinfo_marshal_func(char *, size_t *, void *, va_list, void *); 290158115Sumestatic int addrinfo_unmarshal_func(char *, size_t, void *, va_list, void *); 291158115Sume#endif 29261877Sume 293156960Sumestatic int res_queryN(const char *, struct res_target *, res_state); 294156960Sumestatic int res_searchN(const char *, struct res_target *, res_state); 29592941Sobrienstatic int res_querydomainN(const char *, const char *, 296156960Sume struct res_target *, res_state); 29761877Sume 29855163Sshin/* XXX macros that make external reference is BAD. */ 29955163Sshin 300105940Sume#define GET_AI(ai, afd, addr) \ 30155163Sshindo { \ 30255163Sshin /* external reference: pai, error, and label free */ \ 30355163Sshin (ai) = get_ai(pai, (afd), (addr)); \ 30455163Sshin if ((ai) == NULL) { \ 30555163Sshin error = EAI_MEMORY; \ 30655163Sshin goto free; \ 30755163Sshin } \ 30861877Sume} while (/*CONSTCOND*/0) 30955163Sshin 310105940Sume#define GET_PORT(ai, serv) \ 31155163Sshindo { \ 31255163Sshin /* external reference: error and label free */ \ 31355163Sshin error = get_port((ai), (serv), 0); \ 31455163Sshin if (error != 0) \ 31555163Sshin goto free; \ 31661877Sume} while (/*CONSTCOND*/0) 31755163Sshin 318105940Sume#define GET_CANONNAME(ai, str) \ 31955163Sshindo { \ 32055163Sshin /* external reference: pai, error and label free */ \ 32155163Sshin error = get_canonname(pai, (ai), (str)); \ 32255163Sshin if (error != 0) \ 32355163Sshin goto free; \ 32461877Sume} while (/*CONSTCOND*/0) 32555163Sshin 326105940Sume#define ERR(err) \ 32755163Sshindo { \ 32855163Sshin /* external reference: error, and label bad */ \ 32955163Sshin error = (err); \ 33055163Sshin goto bad; \ 33161877Sume /*NOTREACHED*/ \ 33261877Sume} while (/*CONSTCOND*/0) 33355163Sshin 334105940Sume#define MATCH_FAMILY(x, y, w) \ 33561877Sume ((x) == (y) || (/*CONSTCOND*/(w) && ((x) == PF_UNSPEC || (y) == PF_UNSPEC))) 336105940Sume#define MATCH(x, y, w) \ 33761877Sume ((x) == (y) || (/*CONSTCOND*/(w) && ((x) == ANY || (y) == ANY))) 33855163Sshin 33955163Sshinvoid 340157119Sumefreeaddrinfo(struct addrinfo *ai) 34155163Sshin{ 34255163Sshin struct addrinfo *next; 34355163Sshin 34455163Sshin do { 34555163Sshin next = ai->ai_next; 34655163Sshin if (ai->ai_canonname) 34755163Sshin free(ai->ai_canonname); 34855163Sshin /* no need to free(ai->ai_addr) */ 34955163Sshin free(ai); 35061877Sume ai = next; 35161877Sume } while (ai); 35255163Sshin} 35355163Sshin 35455163Sshinstatic int 355160593Sumestr2number(const char *p, int *portp) 35655163Sshin{ 35762836Sitojun char *ep; 358140908Sume unsigned long v; 35962836Sitojun 36062836Sitojun if (*p == '\0') 361140908Sume return -1; 36262836Sitojun ep = NULL; 363105943Sume errno = 0; 364140908Sume v = strtoul(p, &ep, 10); 365160593Sume if (errno == 0 && ep && *ep == '\0' && v <= UINT_MAX) { 366160593Sume *portp = v; 367160593Sume return 0; 368160593Sume } else 369140908Sume return -1; 37055163Sshin} 37155163Sshin 37255163Sshinint 373157119Sumegetaddrinfo(const char *hostname, const char *servname, 374157119Sume const struct addrinfo *hints, struct addrinfo **res) 37555163Sshin{ 37655163Sshin struct addrinfo sentinel; 37755163Sshin struct addrinfo *cur; 37855163Sshin int error = 0; 379190525Sume struct addrinfo ai, ai0, *afai; 38055163Sshin struct addrinfo *pai; 381190525Sume const struct afd *afd; 38255163Sshin const struct explore *ex; 383190525Sume struct addrinfo *afailist[sizeof(afdl)/sizeof(afdl[0])]; 384190525Sume struct addrinfo *afai_unspec; 385190525Sume int found; 386121747Sume int numeric = 0; 38755163Sshin 388190525Sume /* ensure we return NULL on errors */ 389190525Sume *res = NULL; 390190525Sume 391190525Sume memset(&ai, 0, sizeof(ai)); 392190525Sume 393190525Sume memset(afailist, 0, sizeof(afailist)); 394190525Sume afai_unspec = NULL; 395190525Sume 39661877Sume memset(&sentinel, 0, sizeof(sentinel)); 39755163Sshin cur = &sentinel; 39855163Sshin pai = &ai; 39955163Sshin pai->ai_flags = 0; 40055163Sshin pai->ai_family = PF_UNSPEC; 40155163Sshin pai->ai_socktype = ANY; 40255163Sshin pai->ai_protocol = ANY; 40355163Sshin pai->ai_addrlen = 0; 40455163Sshin pai->ai_canonname = NULL; 40555163Sshin pai->ai_addr = NULL; 40655163Sshin pai->ai_next = NULL; 40755163Sshin 40855163Sshin if (hostname == NULL && servname == NULL) 40955163Sshin return EAI_NONAME; 41055163Sshin if (hints) { 41155163Sshin /* error check for hints */ 41255163Sshin if (hints->ai_addrlen || hints->ai_canonname || 41355163Sshin hints->ai_addr || hints->ai_next) 41455163Sshin ERR(EAI_BADHINTS); /* xxx */ 41555163Sshin if (hints->ai_flags & ~AI_MASK) 41655163Sshin ERR(EAI_BADFLAGS); 41755163Sshin switch (hints->ai_family) { 41855163Sshin case PF_UNSPEC: 41955163Sshin case PF_INET: 42055163Sshin#ifdef INET6 42155163Sshin case PF_INET6: 42255163Sshin#endif 42355163Sshin break; 42455163Sshin default: 42555163Sshin ERR(EAI_FAMILY); 42655163Sshin } 42755163Sshin memcpy(pai, hints, sizeof(*pai)); 42855163Sshin 42955163Sshin /* 43055163Sshin * if both socktype/protocol are specified, check if they 43155163Sshin * are meaningful combination. 43255163Sshin */ 43355163Sshin if (pai->ai_socktype != ANY && pai->ai_protocol != ANY) { 43461877Sume for (ex = explore; ex->e_af >= 0; ex++) { 435190525Sume if (!MATCH_FAMILY(pai->ai_family, ex->e_af, 436190525Sume WILD_AF(ex))) 43761877Sume continue; 438190525Sume if (!MATCH(pai->ai_socktype, ex->e_socktype, 439190525Sume WILD_SOCKTYPE(ex))) 44055163Sshin continue; 441190525Sume if (!MATCH(pai->ai_protocol, ex->e_protocol, 442190525Sume WILD_PROTOCOL(ex))) 44355163Sshin continue; 444190525Sume 445190525Sume /* matched */ 446190525Sume break; 44755163Sshin } 448190416Sume 449190416Sume if (ex->e_af < 0) 450190416Sume ERR(EAI_BADHINTS); 45155163Sshin } 45255163Sshin } 45355163Sshin 45461877Sume /* 455292722Sume * RFC 3493: AI_ALL and AI_V4MAPPED are effective only against 456292722Sume * AF_INET6 query. They need to be ignored if specified in other 457292722Sume * occassions. 458292722Sume */ 459292722Sume switch (pai->ai_flags & (AI_ALL | AI_V4MAPPED)) { 460292722Sume case AI_V4MAPPED: 461292722Sume case AI_ALL | AI_V4MAPPED: 462292722Sume#ifdef INET6 463292722Sume if (pai->ai_family != AF_INET6) 464292722Sume pai->ai_flags &= ~(AI_ALL | AI_V4MAPPED); 465292722Sume break; 466292722Sume#endif 467292722Sume case AI_ALL: 468292722Sume pai->ai_flags &= ~(AI_ALL | AI_V4MAPPED); 469292722Sume break; 470292722Sume } 471292722Sume 472292722Sume /* 47361877Sume * check for special cases. (1) numeric servname is disallowed if 47461877Sume * socktype/protocol are left unspecified. (2) servname is disallowed 47561877Sume * for raw and other inet{,6} sockets. 47655163Sshin */ 47755163Sshin if (MATCH_FAMILY(pai->ai_family, PF_INET, 1) 47861877Sume#ifdef PF_INET6 479121474Sume || MATCH_FAMILY(pai->ai_family, PF_INET6, 1) 48055163Sshin#endif 48155163Sshin ) { 48261877Sume ai0 = *pai; /* backup *pai */ 48355163Sshin 48461877Sume if (pai->ai_family == PF_UNSPEC) { 48561877Sume#ifdef PF_INET6 48655163Sshin pai->ai_family = PF_INET6; 48755163Sshin#else 48855163Sshin pai->ai_family = PF_INET; 48955163Sshin#endif 49061877Sume } 49155163Sshin error = get_portmatch(pai, servname); 49255163Sshin if (error) 493236695Sdim goto bad; 49461877Sume 49561877Sume *pai = ai0; 49655163Sshin } 49755163Sshin 49861877Sume ai0 = *pai; 49961877Sume 500190525Sume /* 501190525Sume * NULL hostname, or numeric hostname. 502190525Sume * If numeric representation of AF1 can be interpreted as FQDN 503190525Sume * representation of AF2, we need to think again about the code below. 504190525Sume */ 505190525Sume found = 0; 506190525Sume for (afd = afdl; afd->a_af; afd++) { 50755163Sshin *pai = ai0; 50855163Sshin 509190525Sume if (!MATCH_FAMILY(pai->ai_family, afd->a_af, 1)) 51055163Sshin continue; 51161877Sume 51255163Sshin if (pai->ai_family == PF_UNSPEC) 513190525Sume pai->ai_family = afd->a_af; 51455163Sshin 515190525Sume if (hostname == NULL) { 516190525Sume error = explore_null(pai, servname, 517190525Sume &afailist[afd - afdl]); 518190525Sume 519190525Sume /* 520190525Sume * Errors from explore_null should be unexpected and 521190525Sume * be caught to avoid returning an incomplete result. 522190525Sume */ 523190525Sume if (error != 0) 524190525Sume goto bad; 525190525Sume } else { 526140906Sume error = explore_numeric_scope(pai, hostname, servname, 527190525Sume &afailist[afd - afdl]); 52855163Sshin 529190525Sume /* 530190525Sume * explore_numeric_scope returns an error for address 531190525Sume * families that do not match that of hostname. 532190525Sume * Thus we should not catch the error at this moment. 533190525Sume */ 534190525Sume } 535121474Sume 536190525Sume if (!error && afailist[afd - afdl]) 537190525Sume found++; 53855163Sshin } 539190525Sume if (found) { 540121747Sume numeric = 1; 541190525Sume goto globcopy; 542121747Sume } 543121474Sume 544121425Sume if (hostname == NULL) 545121425Sume ERR(EAI_NONAME); /* used to be EAI_NODATA */ 54655163Sshin if (pai->ai_flags & AI_NUMERICHOST) 54790053Sroam ERR(EAI_NONAME); 54855163Sshin 549121474Sume if ((pai->ai_flags & AI_ADDRCONFIG) != 0 && !addrconfig(&ai0)) 550121474Sume ERR(EAI_FAIL); 551121474Sume 55261877Sume /* 55361877Sume * hostname as alphabetical name. 55461877Sume */ 555190525Sume *pai = ai0; 556190525Sume error = explore_fqdn(pai, hostname, servname, &afai_unspec); 557190525Sume 558190525Sumeglobcopy: 55961877Sume for (ex = explore; ex->e_af >= 0; ex++) { 56061877Sume *pai = ai0; 56155163Sshin 562190525Sume if (!MATCH_FAMILY(pai->ai_family, ex->e_af, WILD_AF(ex))) 56361877Sume continue; 564121474Sume if (!MATCH(pai->ai_socktype, ex->e_socktype, 565190525Sume WILD_SOCKTYPE(ex))) 56661877Sume continue; 567121474Sume if (!MATCH(pai->ai_protocol, ex->e_protocol, 568190525Sume WILD_PROTOCOL(ex))) 56961877Sume continue; 57055163Sshin 571190525Sume if (pai->ai_family == PF_UNSPEC) 572190525Sume pai->ai_family = ex->e_af; 57361877Sume if (pai->ai_socktype == ANY && ex->e_socktype != ANY) 57461877Sume pai->ai_socktype = ex->e_socktype; 57561877Sume if (pai->ai_protocol == ANY && ex->e_protocol != ANY) 57661877Sume pai->ai_protocol = ex->e_protocol; 57761877Sume 578190525Sume /* 579190525Sume * if the servname does not match socktype/protocol, ignore it. 580190525Sume */ 581190525Sume if (get_portmatch(pai, servname) != 0) 582190525Sume continue; 58361877Sume 584190525Sume if (afai_unspec) 585190525Sume afai = afai_unspec; 586190525Sume else { 587190525Sume if ((afd = find_afd(pai->ai_family)) == NULL) 588190525Sume continue; 589190525Sume /* XXX assumes that afd points inside afdl[] */ 590190525Sume afai = afailist[afd - afdl]; 591190525Sume } 592190525Sume if (!afai) 593190525Sume continue; 594190525Sume 595190525Sume error = explore_copy(pai, afai, &cur->ai_next); 596190525Sume if (error != 0) 597190525Sume goto bad; 598190525Sume 59961877Sume while (cur && cur->ai_next) 60061877Sume cur = cur->ai_next; 60155163Sshin } 60255163Sshin 603121747Sume /* 604121747Sume * ensure we return either: 605121747Sume * - error == 0, non-NULL *res 606121747Sume * - error != 0, NULL *res 607121747Sume */ 60861877Sume if (error == 0) { 60961877Sume if (sentinel.ai_next) { 610121747Sume /* 611121747Sume * If the returned entry is for an active connection, 612121747Sume * and the given name is not numeric, reorder the 613121747Sume * list, so that the application would try the list 614172052Sjinmei * in the most efficient order. Since the head entry 615172052Sjinmei * of the original list may contain ai_canonname and 616172052Sjinmei * that entry may be moved elsewhere in the new list, 617172052Sjinmei * we keep the pointer and will restore it in the new 618172052Sjinmei * head entry. (Note that RFC3493 requires the head 619172052Sjinmei * entry store it when requested by the caller). 620121747Sume */ 621121747Sume if (hints == NULL || !(hints->ai_flags & AI_PASSIVE)) { 622172052Sjinmei if (!numeric) { 623172052Sjinmei char *canonname; 624172052Sjinmei 625172052Sjinmei canonname = 626172052Sjinmei sentinel.ai_next->ai_canonname; 627172052Sjinmei sentinel.ai_next->ai_canonname = NULL; 628121747Sume (void)reorder(&sentinel); 629172052Sjinmei if (sentinel.ai_next->ai_canonname == 630172052Sjinmei NULL) { 631172052Sjinmei sentinel.ai_next->ai_canonname 632172052Sjinmei = canonname; 633172052Sjinmei } else if (canonname != NULL) 634172052Sjinmei free(canonname); 635172052Sjinmei } 636121747Sume } 63761877Sume *res = sentinel.ai_next; 63861877Sume } else 63961877Sume error = EAI_FAIL; 64055163Sshin } 641190525Sume 642121747Sumebad: 643190525Sume if (afai_unspec) 644190525Sume freeaddrinfo(afai_unspec); 645190525Sume for (afd = afdl; afd->a_af; afd++) { 646190525Sume if (afailist[afd - afdl]) 647190525Sume freeaddrinfo(afailist[afd - afdl]); 648190525Sume } 649190525Sume if (!*res) 650190525Sume if (sentinel.ai_next) 651190525Sume freeaddrinfo(sentinel.ai_next); 652190525Sume 653190525Sume return (error); 65455163Sshin} 65555163Sshin 656121747Sumestatic int 657157119Sumereorder(struct addrinfo *sentinel) 658121747Sume{ 659121747Sume struct addrinfo *ai, **aip; 660121747Sume struct ai_order *aio; 661121747Sume int i, n; 662121747Sume struct policyhead policyhead; 663121747Sume 664121747Sume /* count the number of addrinfo elements for sorting. */ 665121747Sume for (n = 0, ai = sentinel->ai_next; ai != NULL; ai = ai->ai_next, n++) 666121747Sume ; 667121747Sume 668121747Sume /* 669121747Sume * If the number is small enough, we can skip the reordering process. 670121747Sume */ 671121747Sume if (n <= 1) 672121747Sume return(n); 673121747Sume 674121747Sume /* allocate a temporary array for sort and initialization of it. */ 675121747Sume if ((aio = malloc(sizeof(*aio) * n)) == NULL) 676121747Sume return(n); /* give up reordering */ 677121747Sume memset(aio, 0, sizeof(*aio) * n); 678121747Sume 679121747Sume /* retrieve address selection policy from the kernel */ 680121747Sume TAILQ_INIT(&policyhead); 681121747Sume if (!get_addrselectpolicy(&policyhead)) { 682121747Sume /* no policy is installed into kernel, we don't sort. */ 683121747Sume free(aio); 684121747Sume return (n); 685121747Sume } 686121747Sume 687121747Sume for (i = 0, ai = sentinel->ai_next; i < n; ai = ai->ai_next, i++) { 688121747Sume aio[i].aio_ai = ai; 689121747Sume aio[i].aio_dstscope = gai_addr2scopetype(ai->ai_addr); 690121747Sume aio[i].aio_dstpolicy = match_addrselectpolicy(ai->ai_addr, 691121747Sume &policyhead); 692129901Sume set_source(&aio[i], &policyhead); 693121747Sume } 694121747Sume 695121747Sume /* perform sorting. */ 696121747Sume qsort(aio, n, sizeof(*aio), comp_dst); 697121747Sume 698121747Sume /* reorder the addrinfo chain. */ 699121747Sume for (i = 0, aip = &sentinel->ai_next; i < n; i++) { 700121747Sume *aip = aio[i].aio_ai; 701121747Sume aip = &aio[i].aio_ai->ai_next; 702121747Sume } 703121747Sume *aip = NULL; 704121747Sume 705121747Sume /* cleanup and return */ 706121747Sume free(aio); 707121747Sume free_addrselectpolicy(&policyhead); 708121747Sume return(n); 709121747Sume} 710121747Sume 711121747Sumestatic int 712157119Sumeget_addrselectpolicy(struct policyhead *head) 713121747Sume{ 714121747Sume#ifdef INET6 715121747Sume int mib[] = { CTL_NET, PF_INET6, IPPROTO_IPV6, IPV6CTL_ADDRCTLPOLICY }; 716121747Sume size_t l; 717121747Sume char *buf; 718121747Sume struct in6_addrpolicy *pol, *ep; 719121747Sume 720121747Sume if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), NULL, &l, NULL, 0) < 0) 721121747Sume return (0); 722238599Semax if (l == 0) 723238599Semax return (0); 724121747Sume if ((buf = malloc(l)) == NULL) 725121747Sume return (0); 726121747Sume if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), buf, &l, NULL, 0) < 0) { 727121747Sume free(buf); 728121747Sume return (0); 729121747Sume } 730121747Sume 731121747Sume ep = (struct in6_addrpolicy *)(buf + l); 732121747Sume for (pol = (struct in6_addrpolicy *)buf; pol + 1 <= ep; pol++) { 733121747Sume struct policyqueue *new; 734121747Sume 735121747Sume if ((new = malloc(sizeof(*new))) == NULL) { 736121747Sume free_addrselectpolicy(head); /* make the list empty */ 737121747Sume break; 738121747Sume } 739121747Sume new->pc_policy = *pol; 740121747Sume TAILQ_INSERT_TAIL(head, new, pc_entry); 741121747Sume } 742121747Sume 743121747Sume free(buf); 744121747Sume return (1); 745121747Sume#else 746121747Sume return (0); 747121747Sume#endif 748121747Sume} 749121747Sume 750121747Sumestatic void 751157119Sumefree_addrselectpolicy(struct policyhead *head) 752121747Sume{ 753121747Sume struct policyqueue *ent, *nent; 754121747Sume 755121747Sume for (ent = TAILQ_FIRST(head); ent; ent = nent) { 756121747Sume nent = TAILQ_NEXT(ent, pc_entry); 757121747Sume TAILQ_REMOVE(head, ent, pc_entry); 758121747Sume free(ent); 759121747Sume } 760121747Sume} 761121747Sume 762121747Sumestatic struct policyqueue * 763157119Sumematch_addrselectpolicy(struct sockaddr *addr, struct policyhead *head) 764121747Sume{ 765121747Sume#ifdef INET6 766121747Sume struct policyqueue *ent, *bestent = NULL; 767121747Sume struct in6_addrpolicy *pol; 768121747Sume int matchlen, bestmatchlen = -1; 769121747Sume u_char *mp, *ep, *k, *p, m; 770121747Sume struct sockaddr_in6 key; 771121747Sume 772121747Sume switch(addr->sa_family) { 773121747Sume case AF_INET6: 774121747Sume key = *(struct sockaddr_in6 *)addr; 775121747Sume break; 776121747Sume case AF_INET: 777121747Sume /* convert the address into IPv4-mapped IPv6 address. */ 778121747Sume memset(&key, 0, sizeof(key)); 779121747Sume key.sin6_family = AF_INET6; 780121747Sume key.sin6_len = sizeof(key); 781292826Sume _map_v4v6_address( 782292826Sume (char *)&((struct sockaddr_in *)addr)->sin_addr, 783292826Sume (char *)&key.sin6_addr); 784121747Sume break; 785121747Sume default: 786121747Sume return(NULL); 787121747Sume } 788121747Sume 789121747Sume for (ent = TAILQ_FIRST(head); ent; ent = TAILQ_NEXT(ent, pc_entry)) { 790121747Sume pol = &ent->pc_policy; 791121747Sume matchlen = 0; 792121747Sume 793121747Sume mp = (u_char *)&pol->addrmask.sin6_addr; 794121747Sume ep = mp + 16; /* XXX: scope field? */ 795121747Sume k = (u_char *)&key.sin6_addr; 796121747Sume p = (u_char *)&pol->addr.sin6_addr; 797121747Sume for (; mp < ep && *mp; mp++, k++, p++) { 798121747Sume m = *mp; 799121747Sume if ((*k & m) != *p) 800121747Sume goto next; /* not match */ 801121747Sume if (m == 0xff) /* short cut for a typical case */ 802121747Sume matchlen += 8; 803121747Sume else { 804121747Sume while (m >= 0x80) { 805121747Sume matchlen++; 806121747Sume m <<= 1; 807121747Sume } 808121747Sume } 809121747Sume } 810121747Sume 811121747Sume /* matched. check if this is better than the current best. */ 812121747Sume if (matchlen > bestmatchlen) { 813121747Sume bestent = ent; 814121747Sume bestmatchlen = matchlen; 815121747Sume } 816121747Sume 817121747Sume next: 818121747Sume continue; 819121747Sume } 820121747Sume 821121747Sume return(bestent); 822121747Sume#else 823121747Sume return(NULL); 824121747Sume#endif 825121747Sume 826121747Sume} 827121747Sume 828129901Sumestatic void 829157119Sumeset_source(struct ai_order *aio, struct policyhead *ph) 830129901Sume{ 831129901Sume struct addrinfo ai = *aio->aio_ai; 832129901Sume struct sockaddr_storage ss; 833145786Sume socklen_t srclen; 834145786Sume int s; 835129901Sume 836129901Sume /* set unspec ("no source is available"), just in case */ 837129901Sume aio->aio_srcsa.sa_family = AF_UNSPEC; 838129901Sume aio->aio_srcscope = -1; 839129901Sume 840129901Sume switch(ai.ai_family) { 841129901Sume case AF_INET: 842129901Sume#ifdef INET6 843129901Sume case AF_INET6: 844129901Sume#endif 845129901Sume break; 846129901Sume default: /* ignore unsupported AFs explicitly */ 847129901Sume return; 848129901Sume } 849129901Sume 850129901Sume /* XXX: make a dummy addrinfo to call connect() */ 851129901Sume ai.ai_socktype = SOCK_DGRAM; 852129901Sume ai.ai_protocol = IPPROTO_UDP; /* is UDP too specific? */ 853129901Sume ai.ai_next = NULL; 854129901Sume memset(&ss, 0, sizeof(ss)); 855129901Sume memcpy(&ss, ai.ai_addr, ai.ai_addrlen); 856129901Sume ai.ai_addr = (struct sockaddr *)&ss; 857129901Sume get_port(&ai, "1", 0); 858129901Sume 859129901Sume /* open a socket to get the source address for the given dst */ 860255328Sjilles if ((s = _socket(ai.ai_family, ai.ai_socktype | SOCK_CLOEXEC, 861255328Sjilles ai.ai_protocol)) < 0) 862129901Sume return; /* give up */ 863292722Sume#ifdef INET6 864292722Sume if (ai.ai_family == AF_INET6) { 865292722Sume struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)ai.ai_addr; 866292722Sume int off = 0; 867292722Sume 868292722Sume if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) 869292722Sume (void)_setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, 870292722Sume (char *)&off, sizeof(off)); 871292722Sume } 872292722Sume#endif 873129901Sume if (_connect(s, ai.ai_addr, ai.ai_addrlen) < 0) 874129901Sume goto cleanup; 875129901Sume srclen = ai.ai_addrlen; 876129901Sume if (_getsockname(s, &aio->aio_srcsa, &srclen) < 0) { 877129901Sume aio->aio_srcsa.sa_family = AF_UNSPEC; 878129901Sume goto cleanup; 879129901Sume } 880129901Sume aio->aio_srcscope = gai_addr2scopetype(&aio->aio_srcsa); 881129901Sume aio->aio_srcpolicy = match_addrselectpolicy(&aio->aio_srcsa, ph); 882129901Sume aio->aio_matchlen = matchlen(&aio->aio_srcsa, aio->aio_ai->ai_addr); 883129901Sume#ifdef INET6 884129901Sume if (ai.ai_family == AF_INET6) { 885129901Sume struct in6_ifreq ifr6; 886129901Sume u_int32_t flags6; 887129901Sume 888129901Sume memset(&ifr6, 0, sizeof(ifr6)); 889129901Sume memcpy(&ifr6.ifr_addr, ai.ai_addr, ai.ai_addrlen); 890129901Sume if (_ioctl(s, SIOCGIFAFLAG_IN6, &ifr6) == 0) { 891129901Sume flags6 = ifr6.ifr_ifru.ifru_flags6; 892129901Sume if ((flags6 & IN6_IFF_DEPRECATED)) 893129901Sume aio->aio_srcflag |= AIO_SRCFLAG_DEPRECATED; 894129901Sume } 895129901Sume } 896129901Sume#endif 897129901Sume 898129901Sume cleanup: 899129901Sume _close(s); 900129901Sume return; 901129901Sume} 902129901Sume 903121747Sumestatic int 904157119Sumematchlen(struct sockaddr *src, struct sockaddr *dst) 905129901Sume{ 906129901Sume int match = 0; 907129901Sume u_char *s, *d; 908129901Sume u_char *lim, r; 909129901Sume int addrlen; 910129901Sume 911129901Sume switch (src->sa_family) { 912129901Sume#ifdef INET6 913129901Sume case AF_INET6: 914129901Sume s = (u_char *)&((struct sockaddr_in6 *)src)->sin6_addr; 915129901Sume d = (u_char *)&((struct sockaddr_in6 *)dst)->sin6_addr; 916129901Sume addrlen = sizeof(struct in6_addr); 917129901Sume lim = s + addrlen; 918129901Sume break; 919129901Sume#endif 920129901Sume case AF_INET: 921146222Sgnn s = (u_char *)&((struct sockaddr_in *)src)->sin_addr; 922146222Sgnn d = (u_char *)&((struct sockaddr_in *)dst)->sin_addr; 923129901Sume addrlen = sizeof(struct in_addr); 924129901Sume lim = s + addrlen; 925129901Sume break; 926129901Sume default: 927129901Sume return(0); 928129901Sume } 929129901Sume 930129901Sume while (s < lim) 931129901Sume if ((r = (*d++ ^ *s++)) != 0) { 932129901Sume while (r < addrlen * 8) { 933129901Sume match++; 934129901Sume r <<= 1; 935129901Sume } 936129901Sume break; 937129901Sume } else 938129901Sume match += 8; 939129901Sume return(match); 940129901Sume} 941129901Sume 942129901Sumestatic int 943157119Sumecomp_dst(const void *arg1, const void *arg2) 944121747Sume{ 945121747Sume const struct ai_order *dst1 = arg1, *dst2 = arg2; 946121747Sume 947121747Sume /* 948121747Sume * Rule 1: Avoid unusable destinations. 949121747Sume * XXX: we currently do not consider if an appropriate route exists. 950121747Sume */ 951121747Sume if (dst1->aio_srcsa.sa_family != AF_UNSPEC && 952121747Sume dst2->aio_srcsa.sa_family == AF_UNSPEC) { 953121747Sume return(-1); 954121747Sume } 955121747Sume if (dst1->aio_srcsa.sa_family == AF_UNSPEC && 956121747Sume dst2->aio_srcsa.sa_family != AF_UNSPEC) { 957121747Sume return(1); 958121747Sume } 959121747Sume 960121747Sume /* Rule 2: Prefer matching scope. */ 961121747Sume if (dst1->aio_dstscope == dst1->aio_srcscope && 962121747Sume dst2->aio_dstscope != dst2->aio_srcscope) { 963121747Sume return(-1); 964121747Sume } 965121747Sume if (dst1->aio_dstscope != dst1->aio_srcscope && 966121747Sume dst2->aio_dstscope == dst2->aio_srcscope) { 967121747Sume return(1); 968121747Sume } 969121747Sume 970121747Sume /* Rule 3: Avoid deprecated addresses. */ 971121747Sume if (dst1->aio_srcsa.sa_family != AF_UNSPEC && 972121747Sume dst2->aio_srcsa.sa_family != AF_UNSPEC) { 973121747Sume if (!(dst1->aio_srcflag & AIO_SRCFLAG_DEPRECATED) && 974121747Sume (dst2->aio_srcflag & AIO_SRCFLAG_DEPRECATED)) { 975121747Sume return(-1); 976121747Sume } 977121747Sume if ((dst1->aio_srcflag & AIO_SRCFLAG_DEPRECATED) && 978121747Sume !(dst2->aio_srcflag & AIO_SRCFLAG_DEPRECATED)) { 979121747Sume return(1); 980121747Sume } 981121747Sume } 982121747Sume 983121747Sume /* Rule 4: Prefer home addresses. */ 984121747Sume /* XXX: not implemented yet */ 985121747Sume 986121747Sume /* Rule 5: Prefer matching label. */ 987121747Sume#ifdef INET6 988121747Sume if (dst1->aio_srcpolicy && dst1->aio_dstpolicy && 989121747Sume dst1->aio_srcpolicy->pc_policy.label == 990121747Sume dst1->aio_dstpolicy->pc_policy.label && 991121747Sume (dst2->aio_srcpolicy == NULL || dst2->aio_dstpolicy == NULL || 992121747Sume dst2->aio_srcpolicy->pc_policy.label != 993121747Sume dst2->aio_dstpolicy->pc_policy.label)) { 994121747Sume return(-1); 995121747Sume } 996121747Sume if (dst2->aio_srcpolicy && dst2->aio_dstpolicy && 997121747Sume dst2->aio_srcpolicy->pc_policy.label == 998121747Sume dst2->aio_dstpolicy->pc_policy.label && 999121747Sume (dst1->aio_srcpolicy == NULL || dst1->aio_dstpolicy == NULL || 1000121747Sume dst1->aio_srcpolicy->pc_policy.label != 1001121747Sume dst1->aio_dstpolicy->pc_policy.label)) { 1002121747Sume return(1); 1003121747Sume } 1004121747Sume#endif 1005121747Sume 1006121747Sume /* Rule 6: Prefer higher precedence. */ 1007121747Sume#ifdef INET6 1008121747Sume if (dst1->aio_dstpolicy && 1009121747Sume (dst2->aio_dstpolicy == NULL || 1010121747Sume dst1->aio_dstpolicy->pc_policy.preced > 1011121747Sume dst2->aio_dstpolicy->pc_policy.preced)) { 1012121747Sume return(-1); 1013121747Sume } 1014121747Sume if (dst2->aio_dstpolicy && 1015121747Sume (dst1->aio_dstpolicy == NULL || 1016121747Sume dst2->aio_dstpolicy->pc_policy.preced > 1017121747Sume dst1->aio_dstpolicy->pc_policy.preced)) { 1018121747Sume return(1); 1019121747Sume } 1020121747Sume#endif 1021121747Sume 1022121747Sume /* Rule 7: Prefer native transport. */ 1023121747Sume /* XXX: not implemented yet */ 1024121747Sume 1025121747Sume /* Rule 8: Prefer smaller scope. */ 1026121747Sume if (dst1->aio_dstscope >= 0 && 1027121747Sume dst1->aio_dstscope < dst2->aio_dstscope) { 1028121747Sume return(-1); 1029121747Sume } 1030121747Sume if (dst2->aio_dstscope >= 0 && 1031121747Sume dst2->aio_dstscope < dst1->aio_dstscope) { 1032121747Sume return(1); 1033121747Sume } 1034121747Sume 1035121747Sume /* 1036121747Sume * Rule 9: Use longest matching prefix. 1037121747Sume * We compare the match length in a same AF only. 1038121747Sume */ 1039121747Sume if (dst1->aio_ai->ai_addr->sa_family == 1040268051Sume dst2->aio_ai->ai_addr->sa_family && 1041268051Sume dst1->aio_ai->ai_addr->sa_family != AF_INET) { 1042121747Sume if (dst1->aio_matchlen > dst2->aio_matchlen) { 1043121747Sume return(-1); 1044121747Sume } 1045121747Sume if (dst1->aio_matchlen < dst2->aio_matchlen) { 1046121747Sume return(1); 1047121747Sume } 1048121747Sume } 1049121747Sume 1050121747Sume /* Rule 10: Otherwise, leave the order unchanged. */ 1051121747Sume return(-1); 1052121747Sume} 1053121747Sume 105455163Sshin/* 1055121747Sume * Copy from scope.c. 1056121747Sume * XXX: we should standardize the functions and link them as standard 1057121747Sume * library. 1058121747Sume */ 1059121747Sumestatic int 1060157119Sumegai_addr2scopetype(struct sockaddr *sa) 1061121747Sume{ 1062121747Sume#ifdef INET6 1063121747Sume struct sockaddr_in6 *sa6; 1064121747Sume#endif 1065121747Sume struct sockaddr_in *sa4; 1066121747Sume 1067121747Sume switch(sa->sa_family) { 1068121747Sume#ifdef INET6 1069121747Sume case AF_INET6: 1070121747Sume sa6 = (struct sockaddr_in6 *)sa; 1071121747Sume if (IN6_IS_ADDR_MULTICAST(&sa6->sin6_addr)) { 1072121747Sume /* just use the scope field of the multicast address */ 1073121747Sume return(sa6->sin6_addr.s6_addr[2] & 0x0f); 1074121747Sume } 1075121747Sume /* 1076121747Sume * Unicast addresses: map scope type to corresponding scope 1077121747Sume * value defined for multcast addresses. 1078121747Sume * XXX: hardcoded scope type values are bad... 1079121747Sume */ 1080121747Sume if (IN6_IS_ADDR_LOOPBACK(&sa6->sin6_addr)) 1081121747Sume return(1); /* node local scope */ 1082121747Sume if (IN6_IS_ADDR_LINKLOCAL(&sa6->sin6_addr)) 1083121747Sume return(2); /* link-local scope */ 1084121747Sume if (IN6_IS_ADDR_SITELOCAL(&sa6->sin6_addr)) 1085121747Sume return(5); /* site-local scope */ 1086121747Sume return(14); /* global scope */ 1087121747Sume break; 1088121747Sume#endif 1089121747Sume case AF_INET: 1090121747Sume /* 1091121747Sume * IPv4 pseudo scoping according to RFC 3484. 1092121747Sume */ 1093121747Sume sa4 = (struct sockaddr_in *)sa; 1094121747Sume /* IPv4 autoconfiguration addresses have link-local scope. */ 1095121747Sume if (((u_char *)&sa4->sin_addr)[0] == 169 && 1096121747Sume ((u_char *)&sa4->sin_addr)[1] == 254) 1097121747Sume return(2); 1098121747Sume /* Private addresses have site-local scope. */ 1099121747Sume if (((u_char *)&sa4->sin_addr)[0] == 10 || 1100121747Sume (((u_char *)&sa4->sin_addr)[0] == 172 && 1101121747Sume (((u_char *)&sa4->sin_addr)[1] & 0xf0) == 16) || 1102121747Sume (((u_char *)&sa4->sin_addr)[0] == 192 && 1103121747Sume ((u_char *)&sa4->sin_addr)[1] == 168)) 1104129905Sume return(14); /* XXX: It should be 5 unless NAT */ 1105121747Sume /* Loopback addresses have link-local scope. */ 1106121747Sume if (((u_char *)&sa4->sin_addr)[0] == 127) 1107121747Sume return(2); 1108121747Sume return(14); 1109121747Sume break; 1110121747Sume default: 1111121747Sume errno = EAFNOSUPPORT; /* is this a good error? */ 1112121747Sume return(-1); 1113121747Sume } 1114121747Sume} 1115121747Sume 1116190525Sumestatic int 1117190525Sumeexplore_copy(const struct addrinfo *pai, const struct addrinfo *src0, 1118190525Sume struct addrinfo **res) 1119190525Sume{ 1120190525Sume int error; 1121190525Sume struct addrinfo sentinel, *cur; 1122190525Sume const struct addrinfo *src; 1123190525Sume 1124190525Sume error = 0; 1125190525Sume sentinel.ai_next = NULL; 1126190525Sume cur = &sentinel; 1127190525Sume 1128190525Sume for (src = src0; src != NULL; src = src->ai_next) { 1129190525Sume if (src->ai_family != pai->ai_family) 1130190525Sume continue; 1131190525Sume 1132190525Sume cur->ai_next = copy_ai(src); 1133190525Sume if (!cur->ai_next) { 1134190525Sume error = EAI_MEMORY; 1135190525Sume goto fail; 1136190525Sume } 1137190525Sume 1138190525Sume cur->ai_next->ai_socktype = pai->ai_socktype; 1139190525Sume cur->ai_next->ai_protocol = pai->ai_protocol; 1140190525Sume cur = cur->ai_next; 1141190525Sume } 1142190525Sume 1143190525Sume *res = sentinel.ai_next; 1144190525Sume return 0; 1145190525Sume 1146190525Sumefail: 1147190525Sume freeaddrinfo(sentinel.ai_next); 1148190525Sume return error; 1149190525Sume} 1150190525Sume 1151121747Sume/* 115255163Sshin * hostname == NULL. 115355163Sshin * passive socket -> anyaddr (0.0.0.0 or ::) 115455163Sshin * non-passive socket -> localhost (127.0.0.1 or ::1) 115555163Sshin */ 115655163Sshinstatic int 1157157119Sumeexplore_null(const struct addrinfo *pai, const char *servname, 1158157119Sume struct addrinfo **res) 115955163Sshin{ 1160121474Sume int s; 116155163Sshin const struct afd *afd; 1162160551Sume struct addrinfo *ai; 116355163Sshin int error; 116455163Sshin 116555163Sshin *res = NULL; 1166160551Sume ai = NULL; 116755163Sshin 116855163Sshin /* 1169121474Sume * filter out AFs that are not supported by the kernel 1170121474Sume * XXX errno? 1171121474Sume */ 1172255328Sjilles s = _socket(pai->ai_family, SOCK_DGRAM | SOCK_CLOEXEC, 0); 1173121474Sume if (s < 0) { 1174121474Sume if (errno != EMFILE) 1175121474Sume return 0; 1176121474Sume } else 1177121474Sume _close(s); 1178121474Sume 117955163Sshin afd = find_afd(pai->ai_family); 118055163Sshin if (afd == NULL) 118155163Sshin return 0; 118255163Sshin 118361877Sume if (pai->ai_flags & AI_PASSIVE) { 1184160551Sume GET_AI(ai, afd, afd->a_addrany); 1185160551Sume GET_PORT(ai, servname); 118661877Sume } else { 1187160551Sume GET_AI(ai, afd, afd->a_loopback); 1188160551Sume GET_PORT(ai, servname); 118961877Sume } 119055163Sshin 1191160551Sume *res = ai; 119255163Sshin return 0; 119355163Sshin 119455163Sshinfree: 1195160551Sume if (ai != NULL) 1196160551Sume freeaddrinfo(ai); 119755163Sshin return error; 119855163Sshin} 119955163Sshin 120055163Sshin/* 120155163Sshin * numeric hostname 120255163Sshin */ 120355163Sshinstatic int 1204157119Sumeexplore_numeric(const struct addrinfo *pai, const char *hostname, 1205157119Sume const char *servname, struct addrinfo **res, const char *canonname) 120655163Sshin{ 120755163Sshin const struct afd *afd; 1208292722Sume struct addrinfo *ai, ai0; 120955163Sshin int error; 121055163Sshin char pton[PTON_MAX]; 121155163Sshin 121255163Sshin *res = NULL; 1213160551Sume ai = NULL; 121455163Sshin 121555163Sshin afd = find_afd(pai->ai_family); 121655163Sshin if (afd == NULL) 121755163Sshin return 0; 121855163Sshin 121962614Sitojun switch (afd->a_af) { 122062614Sitojun case AF_INET: 1221160552Sume /* 1222160552Sume * RFC3493 requires getaddrinfo() to accept AF_INET formats 1223160552Sume * that are accepted by inet_addr() and its family. The 1224160552Sume * accepted forms includes the "classful" one, which inet_pton 1225160552Sume * does not accept. So we need to separate the case for 1226160552Sume * AF_INET. 1227160552Sume */ 1228160553Sume if (inet_aton(hostname, (struct in_addr *)pton) != 1) 1229160553Sume return 0; 123062614Sitojun break; 123162614Sitojun default: 1232292722Sume if (inet_pton(afd->a_af, hostname, pton) != 1) { 1233292722Sume if (pai->ai_family != AF_INET6 || 1234292722Sume (pai->ai_flags & AI_V4MAPPED) != AI_V4MAPPED) 1235292722Sume return 0; 1236292722Sume if (inet_aton(hostname, (struct in_addr *)pton) != 1) 1237292722Sume return 0; 1238292722Sume afd = &afdl[N_INET]; 1239292722Sume ai0 = *pai; 1240292722Sume ai0.ai_family = AF_INET; 1241292722Sume pai = &ai0; 1242292722Sume } 124362614Sitojun break; 124455163Sshin } 124555163Sshin 1246160553Sume if (pai->ai_family == afd->a_af) { 1247160553Sume GET_AI(ai, afd, pton); 1248160553Sume GET_PORT(ai, servname); 1249160553Sume if ((pai->ai_flags & AI_CANONNAME)) { 1250160553Sume /* 1251160553Sume * Set the numeric address itself as the canonical 1252160553Sume * name, based on a clarification in RFC3493. 1253160553Sume */ 1254160553Sume GET_CANONNAME(ai, canonname); 1255160553Sume } 1256160553Sume } else { 1257160553Sume /* 1258160553Sume * XXX: This should not happen since we already matched the AF 1259160553Sume * by find_afd. 1260160553Sume */ 1261160553Sume ERR(EAI_FAMILY); 1262160553Sume } 1263160553Sume 1264160551Sume *res = ai; 126555163Sshin return 0; 126655163Sshin 126755163Sshinfree: 126855163Sshinbad: 1269160551Sume if (ai != NULL) 1270160551Sume freeaddrinfo(ai); 127155163Sshin return error; 127255163Sshin} 127355163Sshin 127455163Sshin/* 127555163Sshin * numeric hostname with scope 127655163Sshin */ 127755163Sshinstatic int 1278157119Sumeexplore_numeric_scope(const struct addrinfo *pai, const char *hostname, 1279157119Sume const char *servname, struct addrinfo **res) 128055163Sshin{ 128161877Sume#if !defined(SCOPE_DELIMITER) || !defined(INET6) 1282140906Sume return explore_numeric(pai, hostname, servname, res, hostname); 128355163Sshin#else 128455163Sshin const struct afd *afd; 128555163Sshin struct addrinfo *cur; 128655163Sshin int error; 128761877Sume char *cp, *hostname2 = NULL, *scope, *addr; 128855163Sshin struct sockaddr_in6 *sin6; 128955163Sshin 129055163Sshin afd = find_afd(pai->ai_family); 129155163Sshin if (afd == NULL) 129255163Sshin return 0; 129365532Snectar 129455163Sshin if (!afd->a_scoped) 1295140906Sume return explore_numeric(pai, hostname, servname, res, hostname); 129655163Sshin 129755163Sshin cp = strchr(hostname, SCOPE_DELIMITER); 129855163Sshin if (cp == NULL) 1299140906Sume return explore_numeric(pai, hostname, servname, res, hostname); 130055163Sshin 130155163Sshin /* 130255163Sshin * Handle special case of <scoped_address><delimiter><scope id> 130355163Sshin */ 130455163Sshin hostname2 = strdup(hostname); 130555163Sshin if (hostname2 == NULL) 130655163Sshin return EAI_MEMORY; 130755163Sshin /* terminate at the delimiter */ 130855163Sshin hostname2[cp - hostname] = '\0'; 130961877Sume addr = hostname2; 131061877Sume scope = cp + 1; 131155163Sshin 1312140906Sume error = explore_numeric(pai, addr, servname, res, hostname); 131361877Sume if (error == 0) { 1314105943Sume u_int32_t scopeid; 131555163Sshin 131655163Sshin for (cur = *res; cur; cur = cur->ai_next) { 131755163Sshin if (cur->ai_family != AF_INET6) 131855163Sshin continue; 131961877Sume sin6 = (struct sockaddr_in6 *)(void *)cur->ai_addr; 1320105943Sume if (ip6_str2scopeid(scope, sin6, &scopeid) == -1) { 132161877Sume free(hostname2); 1322190525Sume freeaddrinfo(*res); 1323190525Sume *res = NULL; 1324121425Sume return(EAI_NONAME); /* XXX: is return OK? */ 132561877Sume } 132661877Sume sin6->sin6_scope_id = scopeid; 132755163Sshin } 132855163Sshin } 132955163Sshin 133055163Sshin free(hostname2); 133155163Sshin 1332190525Sume if (error && *res) { 1333190525Sume freeaddrinfo(*res); 1334190525Sume *res = NULL; 1335190525Sume } 133655163Sshin return error; 133755163Sshin#endif 133855163Sshin} 133955163Sshin 134055163Sshinstatic int 1341157119Sumeget_canonname(const struct addrinfo *pai, struct addrinfo *ai, const char *str) 134255163Sshin{ 134355163Sshin if ((pai->ai_flags & AI_CANONNAME) != 0) { 1344140947Sume ai->ai_canonname = strdup(str); 134555163Sshin if (ai->ai_canonname == NULL) 134655163Sshin return EAI_MEMORY; 134755163Sshin } 134855163Sshin return 0; 134955163Sshin} 135055163Sshin 135155163Sshinstatic struct addrinfo * 1352157119Sumeget_ai(const struct addrinfo *pai, const struct afd *afd, const char *addr) 135355163Sshin{ 135455163Sshin char *p; 135555163Sshin struct addrinfo *ai; 135655163Sshin#ifdef FAITH 135755163Sshin struct in6_addr faith_prefix; 135855163Sshin char *fp_str; 135955163Sshin int translate = 0; 136055163Sshin#endif 1361292722Sume#ifdef INET6 1362292722Sume struct in6_addr mapaddr; 1363292722Sume#endif 136455163Sshin 136555163Sshin#ifdef FAITH 136655163Sshin /* 136755163Sshin * Transfrom an IPv4 addr into a special IPv6 addr format for 136855163Sshin * IPv6->IPv4 translation gateway. (only TCP is supported now) 136955163Sshin * 137055163Sshin * +-----------------------------------+------------+ 137155163Sshin * | faith prefix part (12 bytes) | embedded | 137255163Sshin * | | IPv4 addr part (4 bytes) 137355163Sshin * +-----------------------------------+------------+ 137455163Sshin * 137555163Sshin * faith prefix part is specified as ascii IPv6 addr format 137655163Sshin * in environmental variable GAI. 137755163Sshin * For FAITH to work correctly, routing to faith prefix must be 137855163Sshin * setup toward a machine where a FAITH daemon operates. 137955163Sshin * Also, the machine must enable some mechanizm 138055163Sshin * (e.g. faith interface hack) to divert those packet with 138155163Sshin * faith prefixed destination addr to user-land FAITH daemon. 138255163Sshin */ 138355163Sshin fp_str = getenv("GAI"); 138455163Sshin if (fp_str && inet_pton(AF_INET6, fp_str, &faith_prefix) == 1 && 138555163Sshin afd->a_af == AF_INET && pai->ai_socktype == SOCK_STREAM) { 138655163Sshin u_int32_t v4a; 138755163Sshin u_int8_t v4a_top; 138855163Sshin 138955163Sshin memcpy(&v4a, addr, sizeof v4a); 139055163Sshin v4a_top = v4a >> IN_CLASSA_NSHIFT; 139155163Sshin if (!IN_MULTICAST(v4a) && !IN_EXPERIMENTAL(v4a) && 139255163Sshin v4a_top != 0 && v4a != IN_LOOPBACKNET) { 139355163Sshin afd = &afdl[N_INET6]; 139455163Sshin memcpy(&faith_prefix.s6_addr[12], addr, 139555163Sshin sizeof(struct in_addr)); 139655163Sshin translate = 1; 139755163Sshin } 139855163Sshin } 139955163Sshin#endif 140055163Sshin 1401292722Sume#ifdef INET6 1402292722Sume if (afd->a_af == AF_INET && (pai->ai_flags & AI_V4MAPPED) != 0) { 1403292722Sume afd = &afdl[N_INET6]; 1404292722Sume _map_v4v6_address(addr, (char *)&mapaddr); 1405292722Sume addr = (char *)&mapaddr; 1406292722Sume } 1407292722Sume#endif 1408292722Sume 140955163Sshin ai = (struct addrinfo *)malloc(sizeof(struct addrinfo) 141055163Sshin + (afd->a_socklen)); 141155163Sshin if (ai == NULL) 141255163Sshin return NULL; 141355163Sshin 141455163Sshin memcpy(ai, pai, sizeof(struct addrinfo)); 141561877Sume ai->ai_addr = (struct sockaddr *)(void *)(ai + 1); 141661877Sume memset(ai->ai_addr, 0, (size_t)afd->a_socklen); 141755163Sshin ai->ai_addr->sa_len = afd->a_socklen; 141855163Sshin ai->ai_addrlen = afd->a_socklen; 141955163Sshin ai->ai_addr->sa_family = ai->ai_family = afd->a_af; 142065532Snectar p = (char *)(void *)(ai->ai_addr); 142155163Sshin#ifdef FAITH 142255163Sshin if (translate == 1) 142365532Snectar memcpy(p + afd->a_off, &faith_prefix, (size_t)afd->a_addrlen); 142455163Sshin else 142555163Sshin#endif 142665532Snectar memcpy(p + afd->a_off, addr, (size_t)afd->a_addrlen); 142755163Sshin return ai; 142855163Sshin} 142955163Sshin 1430190525Sume/* XXX need to malloc() the same way we do from other functions! */ 1431190525Sumestatic struct addrinfo * 1432190525Sumecopy_ai(const struct addrinfo *pai) 1433190525Sume{ 1434190525Sume struct addrinfo *ai; 1435190525Sume size_t l; 1436190525Sume 1437190525Sume l = sizeof(*ai) + pai->ai_addrlen; 1438190525Sume if ((ai = (struct addrinfo *)malloc(l)) == NULL) 1439190525Sume return NULL; 1440190525Sume memset(ai, 0, l); 1441190525Sume memcpy(ai, pai, sizeof(*ai)); 1442190525Sume ai->ai_addr = (struct sockaddr *)(void *)(ai + 1); 1443190525Sume memcpy(ai->ai_addr, pai->ai_addr, pai->ai_addrlen); 1444190525Sume 1445190525Sume if (pai->ai_canonname) { 1446190525Sume l = strlen(pai->ai_canonname) + 1; 1447190525Sume if ((ai->ai_canonname = malloc(l)) == NULL) { 1448190525Sume free(ai); 1449190525Sume return NULL; 1450190525Sume } 1451190525Sume strlcpy(ai->ai_canonname, pai->ai_canonname, l); 1452190525Sume } else { 1453190525Sume /* just to make sure */ 1454190525Sume ai->ai_canonname = NULL; 1455190525Sume } 1456190525Sume 1457190525Sume ai->ai_next = NULL; 1458190525Sume 1459190525Sume return ai; 1460190525Sume} 1461190525Sume 146255163Sshinstatic int 1463157119Sumeget_portmatch(const struct addrinfo *ai, const char *servname) 146455163Sshin{ 146561877Sume 1466140908Sume /* get_port does not touch first argument when matchonly == 1. */ 146761877Sume /* LINTED const cast */ 146855163Sshin return get_port((struct addrinfo *)ai, servname, 1); 146955163Sshin} 147055163Sshin 147155163Sshinstatic int 1472157119Sumeget_port(struct addrinfo *ai, const char *servname, int matchonly) 147355163Sshin{ 147455163Sshin const char *proto; 147555163Sshin struct servent *sp; 1476160593Sume int port, error; 147755163Sshin int allownumeric; 147855163Sshin 147955163Sshin if (servname == NULL) 148055163Sshin return 0; 148161877Sume switch (ai->ai_family) { 148261877Sume case AF_INET: 148361877Sume#ifdef AF_INET6 148461877Sume case AF_INET6: 148555163Sshin#endif 148661877Sume break; 148761877Sume default: 148855163Sshin return 0; 148961877Sume } 149055163Sshin 149155163Sshin switch (ai->ai_socktype) { 149255163Sshin case SOCK_RAW: 149355163Sshin return EAI_SERVICE; 149455163Sshin case SOCK_DGRAM: 149555163Sshin case SOCK_STREAM: 1496190416Sume case SOCK_SEQPACKET: 149755163Sshin allownumeric = 1; 149855163Sshin break; 149955163Sshin case ANY: 1500190382Sume switch (ai->ai_family) { 1501190382Sume case AF_INET: 1502190382Sume#ifdef AF_INET6 1503190382Sume case AF_INET6: 1504190382Sume#endif 1505190382Sume allownumeric = 1; 1506190382Sume break; 1507190382Sume default: 1508190382Sume allownumeric = 0; 1509190382Sume break; 1510190382Sume } 151155163Sshin break; 151255163Sshin default: 151355163Sshin return EAI_SOCKTYPE; 151455163Sshin } 151555163Sshin 1516160593Sume error = str2number(servname, &port); 1517160593Sume if (error == 0) { 151855163Sshin if (!allownumeric) 151955163Sshin return EAI_SERVICE; 152055163Sshin if (port < 0 || port > 65535) 152155163Sshin return EAI_SERVICE; 1522105940Sume port = htons(port); 152355163Sshin } else { 1524140908Sume if (ai->ai_flags & AI_NUMERICSERV) 1525140908Sume return EAI_NONAME; 1526190416Sume 1527190416Sume switch (ai->ai_protocol) { 1528190416Sume case IPPROTO_UDP: 152955163Sshin proto = "udp"; 153055163Sshin break; 1531190416Sume case IPPROTO_TCP: 153255163Sshin proto = "tcp"; 153355163Sshin break; 1534190416Sume case IPPROTO_SCTP: 1535190416Sume proto = "sctp"; 1536190416Sume break; 1537265946Skevlo case IPPROTO_UDPLITE: 1538265946Skevlo proto = "udplite"; 1539265946Skevlo break; 154055163Sshin default: 154155163Sshin proto = NULL; 154255163Sshin break; 154355163Sshin } 154455163Sshin 1545145118Sume if ((sp = getservbyname(servname, proto)) == NULL) 154655163Sshin return EAI_SERVICE; 154755163Sshin port = sp->s_port; 154855163Sshin } 154955163Sshin 155055163Sshin if (!matchonly) { 155155163Sshin switch (ai->ai_family) { 155255163Sshin case AF_INET: 155361877Sume ((struct sockaddr_in *)(void *) 155461877Sume ai->ai_addr)->sin_port = port; 155555163Sshin break; 155655163Sshin#ifdef INET6 155755163Sshin case AF_INET6: 155861877Sume ((struct sockaddr_in6 *)(void *) 155961877Sume ai->ai_addr)->sin6_port = port; 156055163Sshin break; 156155163Sshin#endif 156255163Sshin } 156355163Sshin } 156455163Sshin 156555163Sshin return 0; 156655163Sshin} 156755163Sshin 156855163Sshinstatic const struct afd * 1569157119Sumefind_afd(int af) 157055163Sshin{ 157155163Sshin const struct afd *afd; 157255163Sshin 157355163Sshin if (af == PF_UNSPEC) 157455163Sshin return NULL; 157555163Sshin for (afd = afdl; afd->a_af; afd++) { 157655163Sshin if (afd->a_af == af) 157755163Sshin return afd; 157855163Sshin } 157955163Sshin return NULL; 158055163Sshin} 158161877Sume 158261877Sume/* 1583268216Sume * RFC 3493: AI_ADDRCONFIG check. Determines which address families are 1584267874Sume * configured on the local system and correlates with pai->ai_family value. 1585267874Sume * If an address family is not configured on the system, it will not be 1586267874Sume * queried for. For this purpose, loopback addresses are not considered 1587267874Sume * configured addresses. 1588121474Sume * 1589121474Sume * XXX PF_UNSPEC -> PF_INET6 + PF_INET mapping needs to be in sync with 1590121474Sume * _dns_getaddrinfo. 159161877Sume */ 159261877Sumestatic int 1593157119Sumeaddrconfig(struct addrinfo *pai) 159461877Sume{ 1595267874Sume struct ifaddrs *ifaddrs, *ifa; 1596268216Sume struct sockaddr_in *sin; 1597268216Sume#ifdef INET6 1598268216Sume struct sockaddr_in6 *sin6; 1599268216Sume#endif 1600267874Sume int seen_inet = 0, seen_inet6 = 0; 160161877Sume 1602267874Sume if (getifaddrs(&ifaddrs) != 0) 1603268216Sume return (0); 1604267874Sume 1605267874Sume for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) { 1606267874Sume if (ifa->ifa_addr == NULL || (ifa->ifa_flags & IFF_UP) == 0) 1607267874Sume continue; 1608267874Sume switch (ifa->ifa_addr->sa_family) { 1609267874Sume case AF_INET: 1610268216Sume if (seen_inet) 1611268216Sume continue; 1612268216Sume sin = (struct sockaddr_in *)(ifa->ifa_addr); 1613292456Sume if (htonl(sin->sin_addr.s_addr) == INADDR_LOOPBACK) 1614268216Sume continue; 1615267874Sume seen_inet = 1; 1616267874Sume break; 1617267874Sume#ifdef INET6 1618267874Sume case AF_INET6: 1619268216Sume if (seen_inet6) 1620268216Sume continue; 1621268216Sume sin6 = (struct sockaddr_in6 *)(ifa->ifa_addr); 1622268216Sume if (IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr)) 1623268216Sume continue; 1624268216Sume if ((ifa->ifa_flags & IFT_LOOP) != 0 && 1625268216Sume IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) 1626268216Sume continue; 1627268216Sume if (is_ifdisabled(ifa->ifa_name)) 1628268216Sume continue; 1629268216Sume seen_inet6 = 1; 1630267874Sume break; 1631267874Sume#endif 1632121474Sume } 1633121474Sume } 1634267874Sume freeifaddrs(ifaddrs); 1635267874Sume 1636267874Sume switch(pai->ai_family) { 1637267874Sume case AF_INET6: 1638268216Sume return (seen_inet6); 1639267874Sume case AF_INET: 1640268216Sume return (seen_inet); 1641267874Sume case AF_UNSPEC: 1642267874Sume if (seen_inet == seen_inet6) 1643268216Sume return (seen_inet); 1644267874Sume pai->ai_family = seen_inet ? AF_INET : AF_INET6; 1645268216Sume return (1); 1646121474Sume } 1647268216Sume return (1); 164861877Sume} 164961877Sume 165061877Sume#ifdef INET6 1651267874Sumestatic int 1652267874Sumeis_ifdisabled(char *name) 1653267874Sume{ 1654267874Sume struct in6_ndireq nd; 1655267874Sume int fd; 1656267874Sume 1657267874Sume if ((fd = _socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0)) < 0) 1658268216Sume return (-1); 1659267874Sume memset(&nd, 0, sizeof(nd)); 1660267874Sume strlcpy(nd.ifname, name, sizeof(nd.ifname)); 1661267874Sume if (_ioctl(fd, SIOCGIFINFO_IN6, &nd) < 0) { 1662267874Sume _close(fd); 1663268216Sume return (-1); 1664267874Sume } 1665267874Sume _close(fd); 1666267874Sume return ((nd.ndi.flags & ND6_IFF_IFDISABLED) != 0); 1667267874Sume} 1668267874Sume 166961877Sume/* convert a string to a scope identifier. XXX: IPv6 specific */ 167061877Sumestatic int 1671157119Sumeip6_str2scopeid(char *scope, struct sockaddr_in6 *sin6, u_int32_t *scopeid) 167261877Sume{ 1673105943Sume u_long lscopeid; 1674121474Sume struct in6_addr *a6; 167561877Sume char *ep; 167661877Sume 1677121474Sume a6 = &sin6->sin6_addr; 1678121474Sume 167962836Sitojun /* empty scopeid portion is invalid */ 168062836Sitojun if (*scope == '\0') 168162836Sitojun return -1; 168262836Sitojun 1683229766Sume if (IN6_IS_ADDR_LINKLOCAL(a6) || IN6_IS_ADDR_MC_LINKLOCAL(a6) || 1684229766Sume IN6_IS_ADDR_MC_NODELOCAL(a6)) { 168561877Sume /* 168661877Sume * We currently assume a one-to-one mapping between links 168761877Sume * and interfaces, so we simply use interface indices for 168861877Sume * like-local scopes. 168961877Sume */ 1690105943Sume *scopeid = if_nametoindex(scope); 1691105943Sume if (*scopeid == 0) 169261877Sume goto trynumeric; 1693105943Sume return 0; 169461877Sume } 169561877Sume 169661877Sume /* still unclear about literal, allow numeric only - placeholder */ 169761877Sume if (IN6_IS_ADDR_SITELOCAL(a6) || IN6_IS_ADDR_MC_SITELOCAL(a6)) 169861877Sume goto trynumeric; 169961877Sume if (IN6_IS_ADDR_MC_ORGLOCAL(a6)) 170061877Sume goto trynumeric; 170161877Sume else 170261877Sume goto trynumeric; /* global */ 170361877Sume 170461877Sume /* try to convert to a numeric id as a last resort */ 1705121474Sume trynumeric: 1706105943Sume errno = 0; 1707105943Sume lscopeid = strtoul(scope, &ep, 10); 1708105943Sume *scopeid = (u_int32_t)(lscopeid & 0xffffffffUL); 1709105943Sume if (errno == 0 && ep && *ep == '\0' && *scopeid == lscopeid) 1710105943Sume return 0; 171161877Sume else 171261877Sume return -1; 171361877Sume} 171461877Sume#endif 171561877Sume 1716158115Sume 1717158115Sume#ifdef NS_CACHING 1718158115Sumestatic int 1719158115Sumeaddrinfo_id_func(char *buffer, size_t *buffer_size, va_list ap, 1720158115Sume void *cache_mdata) 1721158115Sume{ 1722158115Sume res_state statp; 1723158115Sume u_long res_options; 1724158115Sume 1725158115Sume const int op_id = 0; /* identifies the getaddrinfo for the cache */ 1726158115Sume char *hostname; 1727158115Sume struct addrinfo *hints; 1728158115Sume 1729158115Sume char *p; 1730158115Sume int ai_flags, ai_family, ai_socktype, ai_protocol; 1731158115Sume size_t desired_size, size; 1732158115Sume 1733158115Sume statp = __res_state(); 1734158115Sume res_options = statp->options & (RES_RECURSE | RES_DEFNAMES | 1735158115Sume RES_DNSRCH | RES_NOALIASES | RES_USE_INET6); 1736158115Sume 1737158115Sume hostname = va_arg(ap, char *); 1738158115Sume hints = va_arg(ap, struct addrinfo *); 1739158115Sume 1740158115Sume desired_size = sizeof(res_options) + sizeof(int) + sizeof(int) * 4; 1741158115Sume if (hostname != NULL) { 1742158115Sume size = strlen(hostname); 1743158115Sume desired_size += size + 1; 1744158115Sume } else 1745158115Sume size = 0; 1746158115Sume 1747158115Sume if (desired_size > *buffer_size) { 1748158115Sume *buffer_size = desired_size; 1749158115Sume return (NS_RETURN); 1750158115Sume } 1751158115Sume 1752158115Sume if (hints == NULL) 1753158115Sume ai_flags = ai_family = ai_socktype = ai_protocol = 0; 1754158115Sume else { 1755158115Sume ai_flags = hints->ai_flags; 1756158115Sume ai_family = hints->ai_family; 1757158115Sume ai_socktype = hints->ai_socktype; 1758158115Sume ai_protocol = hints->ai_protocol; 1759158115Sume } 1760158115Sume 1761158115Sume p = buffer; 1762158115Sume memcpy(p, &res_options, sizeof(res_options)); 1763158115Sume p += sizeof(res_options); 1764158115Sume 1765158115Sume memcpy(p, &op_id, sizeof(int)); 1766158115Sume p += sizeof(int); 1767158115Sume 1768158115Sume memcpy(p, &ai_flags, sizeof(int)); 1769158115Sume p += sizeof(int); 1770158115Sume 1771158115Sume memcpy(p, &ai_family, sizeof(int)); 1772158115Sume p += sizeof(int); 1773158115Sume 1774158115Sume memcpy(p, &ai_socktype, sizeof(int)); 1775158115Sume p += sizeof(int); 1776158115Sume 1777158115Sume memcpy(p, &ai_protocol, sizeof(int)); 1778158115Sume p += sizeof(int); 1779158115Sume 1780158115Sume if (hostname != NULL) 1781158115Sume memcpy(p, hostname, size); 1782158115Sume 1783158115Sume *buffer_size = desired_size; 1784158115Sume return (NS_SUCCESS); 1785158115Sume} 1786158115Sume 1787158115Sumestatic int 1788158115Sumeaddrinfo_marshal_func(char *buffer, size_t *buffer_size, void *retval, 1789158115Sume va_list ap, void *cache_mdata) 1790158115Sume{ 1791158115Sume struct addrinfo *ai, *cai; 1792158115Sume char *p; 1793158115Sume size_t desired_size, size, ai_size; 1794158115Sume 1795158115Sume ai = *((struct addrinfo **)retval); 1796158115Sume 1797158115Sume desired_size = sizeof(size_t); 1798158115Sume ai_size = 0; 1799158115Sume for (cai = ai; cai != NULL; cai = cai->ai_next) { 1800158115Sume desired_size += sizeof(struct addrinfo) + cai->ai_addrlen; 1801158115Sume if (cai->ai_canonname != NULL) 1802158115Sume desired_size += sizeof(size_t) + 1803158115Sume strlen(cai->ai_canonname); 1804158115Sume ++ai_size; 1805158115Sume } 1806158115Sume 1807158115Sume if (desired_size > *buffer_size) { 1808158115Sume /* this assignment is here for future use */ 1809158115Sume errno = ERANGE; 1810158115Sume *buffer_size = desired_size; 1811158115Sume return (NS_RETURN); 1812158115Sume } 1813158115Sume 1814158115Sume memset(buffer, 0, desired_size); 1815158115Sume p = buffer; 1816158115Sume 1817158115Sume memcpy(p, &ai_size, sizeof(size_t)); 1818158115Sume p += sizeof(size_t); 1819158115Sume for (cai = ai; cai != NULL; cai = cai->ai_next) { 1820158115Sume memcpy(p, cai, sizeof(struct addrinfo)); 1821158115Sume p += sizeof(struct addrinfo); 1822158115Sume 1823158115Sume memcpy(p, cai->ai_addr, cai->ai_addrlen); 1824158115Sume p += cai->ai_addrlen; 1825158115Sume 1826158115Sume if (cai->ai_canonname != NULL) { 1827158115Sume size = strlen(cai->ai_canonname); 1828158115Sume memcpy(p, &size, sizeof(size_t)); 1829158115Sume p += sizeof(size_t); 1830158115Sume 1831158115Sume memcpy(p, cai->ai_canonname, size); 1832158115Sume p += size; 1833158115Sume } 1834158115Sume } 1835158115Sume 1836158115Sume return (NS_SUCCESS); 1837158115Sume} 1838158115Sume 1839158115Sumestatic int 1840158115Sumeaddrinfo_unmarshal_func(char *buffer, size_t buffer_size, void *retval, 1841158115Sume va_list ap, void *cache_mdata) 1842158115Sume{ 1843158115Sume struct addrinfo new_ai, *result, *sentinel, *lasts; 1844158115Sume 1845158115Sume char *p; 1846158115Sume size_t ai_size, ai_i, size; 1847158115Sume 1848158115Sume p = buffer; 1849158115Sume memcpy(&ai_size, p, sizeof(size_t)); 1850158115Sume p += sizeof(size_t); 1851158115Sume 1852158115Sume result = NULL; 1853158115Sume lasts = NULL; 1854158115Sume for (ai_i = 0; ai_i < ai_size; ++ai_i) { 1855158115Sume memcpy(&new_ai, p, sizeof(struct addrinfo)); 1856158115Sume p += sizeof(struct addrinfo); 1857158115Sume size = new_ai.ai_addrlen + sizeof(struct addrinfo) + 1858158115Sume _ALIGNBYTES; 1859158115Sume 1860158115Sume sentinel = (struct addrinfo *)malloc(size); 1861158115Sume memset(sentinel, 0, size); 1862158115Sume 1863158115Sume memcpy(sentinel, &new_ai, sizeof(struct addrinfo)); 1864158115Sume sentinel->ai_addr = (struct sockaddr *)_ALIGN((char *)sentinel + 1865158115Sume sizeof(struct addrinfo)); 1866158115Sume 1867158115Sume memcpy(sentinel->ai_addr, p, new_ai.ai_addrlen); 1868158115Sume p += new_ai.ai_addrlen; 1869158115Sume 1870158115Sume if (new_ai.ai_canonname != NULL) { 1871158115Sume memcpy(&size, p, sizeof(size_t)); 1872158115Sume p += sizeof(size_t); 1873158115Sume 1874158115Sume sentinel->ai_canonname = (char *)malloc(size + 1); 1875158115Sume memset(sentinel->ai_canonname, 0, size + 1); 1876158115Sume 1877158115Sume memcpy(sentinel->ai_canonname, p, size); 1878158115Sume p += size; 1879158115Sume } 1880158115Sume 1881158115Sume if (result == NULL) { 1882158115Sume result = sentinel; 1883158115Sume lasts = sentinel; 1884158115Sume } else { 1885158115Sume lasts->ai_next = sentinel; 1886158115Sume lasts = sentinel; 1887158115Sume } 1888158115Sume } 1889158115Sume 1890158115Sume *((struct addrinfo **)retval) = result; 1891158115Sume return (NS_SUCCESS); 1892158115Sume} 1893158115Sume#endif /* NS_CACHING */ 1894158115Sume 1895121426Sume/* 1896121426Sume * FQDN hostname, DNS lookup 1897121426Sume */ 1898102237Spirzykstatic int 1899157119Sumeexplore_fqdn(const struct addrinfo *pai, const char *hostname, 1900157119Sume const char *servname, struct addrinfo **res) 1901102237Spirzyk{ 1902121426Sume struct addrinfo *result; 1903121426Sume struct addrinfo *cur; 1904121426Sume int error = 0; 1905158115Sume 1906158115Sume#ifdef NS_CACHING 1907158115Sume static const nss_cache_info cache_info = 1908158115Sume NS_COMMON_CACHE_INFO_INITIALIZER( 1909158115Sume hosts, NULL, addrinfo_id_func, addrinfo_marshal_func, 1910158115Sume addrinfo_unmarshal_func); 1911158115Sume#endif 1912121426Sume static const ns_dtab dtab[] = { 1913121426Sume NS_FILES_CB(_files_getaddrinfo, NULL) 1914121426Sume { NSSRC_DNS, _dns_getaddrinfo, NULL }, /* force -DHESIOD */ 1915121426Sume NS_NIS_CB(_yp_getaddrinfo, NULL) 1916158115Sume#ifdef NS_CACHING 1917158115Sume NS_CACHE_CB(&cache_info) 1918158115Sume#endif 1919121426Sume { 0 } 1920121426Sume }; 1921102237Spirzyk 1922121426Sume result = NULL; 1923121426Sume 1924121426Sume /* 1925121426Sume * if the servname does not match socktype/protocol, ignore it. 1926121426Sume */ 1927126243Sgreen if (get_portmatch(pai, servname) != 0) 1928102237Spirzyk return 0; 1929102237Spirzyk 1930121426Sume switch (_nsdispatch(&result, dtab, NSDB_HOSTS, "getaddrinfo", 1931121426Sume default_dns_files, hostname, pai)) { 1932121426Sume case NS_TRYAGAIN: 1933121426Sume error = EAI_AGAIN; 1934121426Sume goto free; 1935121426Sume case NS_UNAVAIL: 1936121426Sume error = EAI_FAIL; 1937121426Sume goto free; 1938121426Sume case NS_NOTFOUND: 1939121426Sume error = EAI_NONAME; 1940121426Sume goto free; 1941121426Sume case NS_SUCCESS: 1942121426Sume error = 0; 1943121426Sume for (cur = result; cur; cur = cur->ai_next) { 1944121426Sume GET_PORT(cur, servname); 1945121426Sume /* canonname should be filled already */ 1946121426Sume } 1947121426Sume break; 1948102237Spirzyk } 1949102237Spirzyk 1950121426Sume *res = result; 1951121426Sume 1952102237Spirzyk return 0; 1953121426Sume 1954121426Sumefree: 1955121426Sume if (result) 1956121426Sume freeaddrinfo(result); 1957121426Sume return error; 1958102237Spirzyk} 1959102237Spirzyk 196061877Sume#ifdef DEBUG 196161877Sumestatic const char AskedForGot[] = 196261877Sume "gethostby*.getanswer: asked for \"%s\", got \"%s\""; 196361877Sume#endif 196461877Sume 196561877Sumestatic struct addrinfo * 1966157119Sumegetanswer(const querybuf *answer, int anslen, const char *qname, int qtype, 1967157119Sume const struct addrinfo *pai, res_state res) 196861877Sume{ 196961877Sume struct addrinfo sentinel, *cur; 197061877Sume struct addrinfo ai; 197161877Sume const struct afd *afd; 197261877Sume char *canonname; 197361877Sume const HEADER *hp; 197461877Sume const u_char *cp; 197561877Sume int n; 197661877Sume const u_char *eom; 1977105940Sume char *bp, *ep; 1978105940Sume int type, class, ancount, qdcount; 197961877Sume int haveanswer, had_error; 198061877Sume char tbuf[MAXDNAME]; 198192905Sobrien int (*name_ok)(const char *); 198261877Sume char hostbuf[8*1024]; 198361877Sume 198461877Sume memset(&sentinel, 0, sizeof(sentinel)); 198561877Sume cur = &sentinel; 198661877Sume 198761877Sume canonname = NULL; 198861877Sume eom = answer->buf + anslen; 198961877Sume switch (qtype) { 199061877Sume case T_A: 199161877Sume case T_AAAA: 199261877Sume case T_ANY: /*use T_ANY only for T_A/T_AAAA lookup*/ 199361877Sume name_ok = res_hnok; 199461877Sume break; 199561877Sume default: 199661877Sume return (NULL); /* XXX should be abort(); */ 199761877Sume } 199861877Sume /* 199961877Sume * find first satisfactory answer 200061877Sume */ 200161877Sume hp = &answer->hdr; 200261877Sume ancount = ntohs(hp->ancount); 200361877Sume qdcount = ntohs(hp->qdcount); 200461877Sume bp = hostbuf; 2005105940Sume ep = hostbuf + sizeof hostbuf; 200661877Sume cp = answer->buf + HFIXEDSZ; 200761877Sume if (qdcount != 1) { 2008156960Sume RES_SET_H_ERRNO(res, NO_RECOVERY); 200961877Sume return (NULL); 201061877Sume } 2011105940Sume n = dn_expand(answer->buf, eom, cp, bp, ep - bp); 201261877Sume if ((n < 0) || !(*name_ok)(bp)) { 2013156960Sume RES_SET_H_ERRNO(res, NO_RECOVERY); 201461877Sume return (NULL); 201561877Sume } 201661877Sume cp += n + QFIXEDSZ; 201761877Sume if (qtype == T_A || qtype == T_AAAA || qtype == T_ANY) { 201861877Sume /* res_send() has already verified that the query name is the 201961877Sume * same as the one we sent; this just gets the expanded name 202061877Sume * (i.e., with the succeeding search-domain tacked on). 202161877Sume */ 202261877Sume n = strlen(bp) + 1; /* for the \0 */ 202361877Sume if (n >= MAXHOSTNAMELEN) { 2024156960Sume RES_SET_H_ERRNO(res, NO_RECOVERY); 202561877Sume return (NULL); 202661877Sume } 202761877Sume canonname = bp; 202861877Sume bp += n; 202961877Sume /* The qname can be abbreviated, but h_name is now absolute. */ 203061877Sume qname = canonname; 203161877Sume } 203261877Sume haveanswer = 0; 203361877Sume had_error = 0; 203461877Sume while (ancount-- > 0 && cp < eom && !had_error) { 2035105940Sume n = dn_expand(answer->buf, eom, cp, bp, ep - bp); 203661877Sume if ((n < 0) || !(*name_ok)(bp)) { 203761877Sume had_error++; 203861877Sume continue; 203961877Sume } 204061877Sume cp += n; /* name */ 204161877Sume type = _getshort(cp); 204261877Sume cp += INT16SZ; /* type */ 204361877Sume class = _getshort(cp); 204461877Sume cp += INT16SZ + INT32SZ; /* class, TTL */ 204561877Sume n = _getshort(cp); 204661877Sume cp += INT16SZ; /* len */ 204761877Sume if (class != C_IN) { 204861877Sume /* XXX - debug? syslog? */ 204961877Sume cp += n; 205061877Sume continue; /* XXX - had_error++ ? */ 205161877Sume } 205261877Sume if ((qtype == T_A || qtype == T_AAAA || qtype == T_ANY) && 205361877Sume type == T_CNAME) { 205461877Sume n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf); 205561877Sume if ((n < 0) || !(*name_ok)(tbuf)) { 205661877Sume had_error++; 205761877Sume continue; 205861877Sume } 205961877Sume cp += n; 206061877Sume /* Get canonical name. */ 206161877Sume n = strlen(tbuf) + 1; /* for the \0 */ 2062105940Sume if (n > ep - bp || n >= MAXHOSTNAMELEN) { 206361877Sume had_error++; 206461877Sume continue; 206561877Sume } 2066114443Snectar strlcpy(bp, tbuf, ep - bp); 206761877Sume canonname = bp; 206861877Sume bp += n; 206961877Sume continue; 207061877Sume } 207161877Sume if (qtype == T_ANY) { 207261877Sume if (!(type == T_A || type == T_AAAA)) { 207361877Sume cp += n; 207461877Sume continue; 207561877Sume } 207661877Sume } else if (type != qtype) { 207761877Sume#ifdef DEBUG 2078188316Sume if (type != T_KEY && type != T_SIG && 2079188316Sume type != ns_t_dname) 208061877Sume syslog(LOG_NOTICE|LOG_AUTH, 208161877Sume "gethostby*.getanswer: asked for \"%s %s %s\", got type \"%s\"", 208261877Sume qname, p_class(C_IN), p_type(qtype), 208361877Sume p_type(type)); 208461877Sume#endif 208561877Sume cp += n; 208661877Sume continue; /* XXX - had_error++ ? */ 208761877Sume } 208861877Sume switch (type) { 208961877Sume case T_A: 209061877Sume case T_AAAA: 209161877Sume if (strcasecmp(canonname, bp) != 0) { 209261877Sume#ifdef DEBUG 209361877Sume syslog(LOG_NOTICE|LOG_AUTH, 209461877Sume AskedForGot, canonname, bp); 209561877Sume#endif 209661877Sume cp += n; 209761877Sume continue; /* XXX - had_error++ ? */ 209861877Sume } 209961877Sume if (type == T_A && n != INADDRSZ) { 210061877Sume cp += n; 210161877Sume continue; 210261877Sume } 210361877Sume if (type == T_AAAA && n != IN6ADDRSZ) { 210461877Sume cp += n; 210561877Sume continue; 210661877Sume } 210761877Sume#ifdef FILTER_V4MAPPED 210861877Sume if (type == T_AAAA) { 210961877Sume struct in6_addr in6; 211061877Sume memcpy(&in6, cp, sizeof(in6)); 211161877Sume if (IN6_IS_ADDR_V4MAPPED(&in6)) { 211261877Sume cp += n; 211361877Sume continue; 211461877Sume } 211561877Sume } 211661877Sume#endif 211761877Sume if (!haveanswer) { 211861877Sume int nn; 211961877Sume 212061877Sume canonname = bp; 212161877Sume nn = strlen(bp) + 1; /* for the \0 */ 212261877Sume bp += nn; 212361877Sume } 212461877Sume 212561877Sume /* don't overwrite pai */ 212661877Sume ai = *pai; 212761877Sume ai.ai_family = (type == T_A) ? AF_INET : AF_INET6; 212861877Sume afd = find_afd(ai.ai_family); 212961877Sume if (afd == NULL) { 213061877Sume cp += n; 213161877Sume continue; 213261877Sume } 213361877Sume cur->ai_next = get_ai(&ai, afd, (const char *)cp); 213461877Sume if (cur->ai_next == NULL) 213561877Sume had_error++; 213661877Sume while (cur && cur->ai_next) 213761877Sume cur = cur->ai_next; 213861877Sume cp += n; 213961877Sume break; 214061877Sume default: 214161877Sume abort(); 214261877Sume } 214361877Sume if (!had_error) 214461877Sume haveanswer++; 214561877Sume } 214661877Sume if (haveanswer) { 2147102237Spirzyk#if defined(RESOLVSORT) 2148102237Spirzyk /* 2149102237Spirzyk * We support only IPv4 address for backward 2150102237Spirzyk * compatibility against gethostbyname(3). 2151102237Spirzyk */ 2152156960Sume if (res->nsort && qtype == T_A) { 2153156960Sume if (addr4sort(&sentinel, res) < 0) { 2154102237Spirzyk freeaddrinfo(sentinel.ai_next); 2155156960Sume RES_SET_H_ERRNO(res, NO_RECOVERY); 2156102237Spirzyk return NULL; 2157102237Spirzyk } 2158102237Spirzyk } 2159102237Spirzyk#endif /*RESOLVSORT*/ 216061877Sume if (!canonname) 216161877Sume (void)get_canonname(pai, sentinel.ai_next, qname); 216261877Sume else 216361877Sume (void)get_canonname(pai, sentinel.ai_next, canonname); 2164156960Sume RES_SET_H_ERRNO(res, NETDB_SUCCESS); 216561877Sume return sentinel.ai_next; 216661877Sume } 216761877Sume 2168292824Sume /* 2169292824Sume * We could have walked a CNAME chain, but the ultimate target 2170292824Sume * may not have what we looked for. 2171292824Sume */ 2172292824Sume RES_SET_H_ERRNO(res, ntohs(hp->ancount) > 0 ? NO_DATA : NO_RECOVERY); 217361877Sume return NULL; 217461877Sume} 217561877Sume 2176121426Sume#ifdef RESOLVSORT 2177121426Sumestruct addr_ptr { 2178121426Sume struct addrinfo *ai; 2179121426Sume int aval; 2180121426Sume}; 2181121426Sume 2182121426Sumestatic int 2183156960Sumeaddr4sort(struct addrinfo *sentinel, res_state res) 2184121426Sume{ 2185121426Sume struct addrinfo *ai; 2186121426Sume struct addr_ptr *addrs, addr; 2187121426Sume struct sockaddr_in *sin; 2188121426Sume int naddrs, i, j; 2189121426Sume int needsort = 0; 2190121426Sume 2191121426Sume if (!sentinel) 2192121426Sume return -1; 2193121426Sume naddrs = 0; 2194121426Sume for (ai = sentinel->ai_next; ai; ai = ai->ai_next) 2195121426Sume naddrs++; 2196121426Sume if (naddrs < 2) 2197121426Sume return 0; /* We don't need sorting. */ 2198121426Sume if ((addrs = malloc(sizeof(struct addr_ptr) * naddrs)) == NULL) 2199121426Sume return -1; 2200121426Sume i = 0; 2201121426Sume for (ai = sentinel->ai_next; ai; ai = ai->ai_next) { 2202121426Sume sin = (struct sockaddr_in *)ai->ai_addr; 2203156960Sume for (j = 0; (unsigned)j < res->nsort; j++) { 2204157119Sume if (res->sort_list[j].addr.s_addr == 2205156960Sume (sin->sin_addr.s_addr & res->sort_list[j].mask)) 2206121426Sume break; 2207121426Sume } 2208121426Sume addrs[i].ai = ai; 2209121426Sume addrs[i].aval = j; 2210121426Sume if (needsort == 0 && i > 0 && j < addrs[i - 1].aval) 2211121426Sume needsort = i; 2212121426Sume i++; 2213121426Sume } 2214121426Sume if (!needsort) { 2215121426Sume free(addrs); 2216121426Sume return 0; 2217121426Sume } 2218121426Sume 2219121426Sume while (needsort < naddrs) { 2220157371Sume for (j = needsort - 1; j >= 0; j--) { 2221157371Sume if (addrs[j].aval > addrs[j+1].aval) { 2222157371Sume addr = addrs[j]; 2223157371Sume addrs[j] = addrs[j + 1]; 2224157371Sume addrs[j + 1] = addr; 2225157371Sume } else 2226157371Sume break; 2227157371Sume } 2228157371Sume needsort++; 2229121426Sume } 2230121426Sume 2231121426Sume ai = sentinel; 2232121426Sume for (i = 0; i < naddrs; ++i) { 2233121426Sume ai->ai_next = addrs[i].ai; 2234121426Sume ai = ai->ai_next; 2235121426Sume } 2236121426Sume ai->ai_next = NULL; 2237121426Sume free(addrs); 2238121426Sume return 0; 2239121426Sume} 2240121426Sume#endif /*RESOLVSORT*/ 2241121426Sume 224261877Sume/*ARGSUSED*/ 224361877Sumestatic int 2244157119Sume_dns_getaddrinfo(void *rv, void *cb_data, va_list ap) 224561877Sume{ 2246292722Sume struct addrinfo *ai, ai0; 2247103357Sume querybuf *buf, *buf2; 2248130600Sume const char *hostname; 224965532Snectar const struct addrinfo *pai; 225061877Sume struct addrinfo sentinel, *cur; 225161877Sume struct res_target q, q2; 2252156960Sume res_state res; 225361877Sume 2254130600Sume hostname = va_arg(ap, char *); 225565532Snectar pai = va_arg(ap, const struct addrinfo *); 225665532Snectar 2257156946Sdelphij memset(&q, 0, sizeof(q)); 225861877Sume memset(&q2, 0, sizeof(q2)); 225961877Sume memset(&sentinel, 0, sizeof(sentinel)); 226061877Sume cur = &sentinel; 226161877Sume 2262292403Sume res = __res_state(); 2263292403Sume 2264103357Sume buf = malloc(sizeof(*buf)); 2265103357Sume if (!buf) { 2266156960Sume RES_SET_H_ERRNO(res, NETDB_INTERNAL); 2267103357Sume return NS_NOTFOUND; 2268103357Sume } 2269103357Sume buf2 = malloc(sizeof(*buf2)); 2270103357Sume if (!buf2) { 2271103357Sume free(buf); 2272156960Sume RES_SET_H_ERRNO(res, NETDB_INTERNAL); 2273103357Sume return NS_NOTFOUND; 2274103357Sume } 2275103357Sume 2276292722Sume if (pai->ai_family == AF_INET6 && 2277292722Sume (pai->ai_flags & AI_V4MAPPED) == AI_V4MAPPED) { 2278292722Sume ai0 = *pai; 2279292722Sume ai0.ai_family = AF_UNSPEC; 2280292722Sume pai = &ai0; 2281292722Sume } 2282292722Sume 228361877Sume switch (pai->ai_family) { 228461877Sume case AF_UNSPEC: 2285130600Sume q.name = hostname; 228662614Sitojun q.qclass = C_IN; 2287140896Sume q.qtype = T_A; 2288103357Sume q.answer = buf->buf; 2289103357Sume q.anslen = sizeof(buf->buf); 229061877Sume q.next = &q2; 2291130600Sume q2.name = hostname; 229262614Sitojun q2.qclass = C_IN; 2293140896Sume q2.qtype = T_AAAA; 2294103357Sume q2.answer = buf2->buf; 2295103357Sume q2.anslen = sizeof(buf2->buf); 229661877Sume break; 229761877Sume case AF_INET: 2298130600Sume q.name = hostname; 229962614Sitojun q.qclass = C_IN; 230062614Sitojun q.qtype = T_A; 2301103357Sume q.answer = buf->buf; 2302103357Sume q.anslen = sizeof(buf->buf); 230361877Sume break; 230461877Sume case AF_INET6: 2305130600Sume q.name = hostname; 230662614Sitojun q.qclass = C_IN; 230762614Sitojun q.qtype = T_AAAA; 2308103357Sume q.answer = buf->buf; 2309103357Sume q.anslen = sizeof(buf->buf); 231061877Sume break; 231161877Sume default: 2312103357Sume free(buf); 2313103357Sume free(buf2); 231465532Snectar return NS_UNAVAIL; 231561877Sume } 2316156960Sume 2317156960Sume if ((res->options & RES_INIT) == 0 && res_ninit(res) == -1) { 2318156960Sume RES_SET_H_ERRNO(res, NETDB_INTERNAL); 2319103357Sume free(buf); 2320103357Sume free(buf2); 232165532Snectar return NS_NOTFOUND; 2322103357Sume } 2323156960Sume 2324156960Sume if (res_searchN(hostname, &q, res) < 0) { 2325156960Sume free(buf); 2326156960Sume free(buf2); 2327156960Sume return NS_NOTFOUND; 2328156960Sume } 2329140896Sume /* prefer IPv6 */ 233061877Sume if (q.next) { 2331156960Sume ai = getanswer(buf2, q2.n, q2.name, q2.qtype, pai, res); 2332140896Sume if (ai) { 233361877Sume cur->ai_next = ai; 2334140896Sume while (cur && cur->ai_next) 2335140896Sume cur = cur->ai_next; 2336140896Sume } 233761877Sume } 2338292722Sume if (!ai || pai->ai_family != AF_UNSPEC || 2339292722Sume (pai->ai_flags & (AI_ALL | AI_V4MAPPED)) != AI_V4MAPPED) { 2340292722Sume ai = getanswer(buf, q.n, q.name, q.qtype, pai, res); 2341292722Sume if (ai) 2342292722Sume cur->ai_next = ai; 2343292722Sume } 2344103357Sume free(buf); 2345103357Sume free(buf2); 234661877Sume if (sentinel.ai_next == NULL) 2347156960Sume switch (res->res_h_errno) { 234861877Sume case HOST_NOT_FOUND: 2349292824Sume case NO_DATA: 235065532Snectar return NS_NOTFOUND; 235161877Sume case TRY_AGAIN: 235265532Snectar return NS_TRYAGAIN; 235361877Sume default: 235465532Snectar return NS_UNAVAIL; 235561877Sume } 235665532Snectar *((struct addrinfo **)rv) = sentinel.ai_next; 235765532Snectar return NS_SUCCESS; 235861877Sume} 235961877Sume 236065532Snectarstatic void 2361144634Sume_sethtent(FILE **hostf) 236265532Snectar{ 2363144634Sume if (!*hostf) 2364254700Sjilles *hostf = fopen(_PATH_HOSTS, "re"); 236565532Snectar else 2366144634Sume rewind(*hostf); 236765532Snectar} 236865532Snectar 236965532Snectarstatic void 2370144634Sume_endhtent(FILE **hostf) 237165532Snectar{ 2372144634Sume if (*hostf) { 2373144634Sume (void) fclose(*hostf); 2374144634Sume *hostf = NULL; 237565532Snectar } 237665532Snectar} 237765532Snectar 237861877Sumestatic struct addrinfo * 2379144634Sume_gethtent(FILE **hostf, const char *name, const struct addrinfo *pai) 238061877Sume{ 238161877Sume char *p; 238261877Sume char *cp, *tname, *cname; 238361877Sume struct addrinfo hints, *res0, *res; 238461877Sume int error; 238561877Sume const char *addr; 238661877Sume char hostbuf[8*1024]; 238761877Sume 2388254700Sjilles if (!*hostf && !(*hostf = fopen(_PATH_HOSTS, "re"))) 238965532Snectar return (NULL); 2390105940Sumeagain: 2391144634Sume if (!(p = fgets(hostbuf, sizeof hostbuf, *hostf))) 239261877Sume return (NULL); 239361877Sume if (*p == '#') 239461877Sume goto again; 2395139612Ssobomax cp = strpbrk(p, "#\n"); 2396139612Ssobomax if (cp != NULL) 2397139612Ssobomax *cp = '\0'; 239861877Sume if (!(cp = strpbrk(p, " \t"))) 239961877Sume goto again; 240061877Sume *cp++ = '\0'; 240161877Sume addr = p; 240261877Sume cname = NULL; 240361877Sume /* if this is not something we're looking for, skip it. */ 240461877Sume while (cp && *cp) { 240561877Sume if (*cp == ' ' || *cp == '\t') { 240661877Sume cp++; 240761877Sume continue; 240861877Sume } 240961877Sume tname = cp; 241061877Sume if (cname == NULL) 241161877Sume cname = cp; 241261877Sume if ((cp = strpbrk(cp, " \t")) != NULL) 241361877Sume *cp++ = '\0'; 241461877Sume if (strcasecmp(name, tname) == 0) 241561877Sume goto found; 241661877Sume } 241761877Sume goto again; 241861877Sume 241961877Sumefound: 2420105940Sume /* we should not glob socktype/protocol here */ 2421105940Sume memset(&hints, 0, sizeof(hints)); 2422105940Sume hints.ai_family = pai->ai_family; 2423105940Sume hints.ai_socktype = SOCK_DGRAM; 2424105940Sume hints.ai_protocol = 0; 242561877Sume hints.ai_flags = AI_NUMERICHOST; 2426292722Sume if (pai->ai_family == AF_INET6 && 2427292722Sume (pai->ai_flags & AI_V4MAPPED) == AI_V4MAPPED) 2428292722Sume hints.ai_flags |= AI_V4MAPPED; 2429105940Sume error = getaddrinfo(addr, "0", &hints, &res0); 243061877Sume if (error) 243161877Sume goto again; 243261877Sume#ifdef FILTER_V4MAPPED 243361877Sume /* XXX should check all items in the chain */ 243461877Sume if (res0->ai_family == AF_INET6 && 243561877Sume IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)res0->ai_addr)->sin6_addr)) { 243661877Sume freeaddrinfo(res0); 243761877Sume goto again; 243861877Sume } 243961877Sume#endif 244061877Sume for (res = res0; res; res = res->ai_next) { 244161877Sume /* cover it up */ 244261877Sume res->ai_flags = pai->ai_flags; 2443105940Sume res->ai_socktype = pai->ai_socktype; 2444105940Sume res->ai_protocol = pai->ai_protocol; 244561877Sume 244661877Sume if (pai->ai_flags & AI_CANONNAME) { 244761877Sume if (get_canonname(pai, res, cname) != 0) { 244861877Sume freeaddrinfo(res0); 244961877Sume goto again; 245061877Sume } 245161877Sume } 245261877Sume } 245361877Sume return res0; 245461877Sume} 245561877Sume 2456292722Sumestatic struct addrinfo * 2457292722Sume_getht(FILE **hostf, const char *name, const struct addrinfo *pai, 2458292722Sume struct addrinfo *cur) 2459292722Sume{ 2460292722Sume struct addrinfo *p; 2461292722Sume 2462292722Sume while ((p = _gethtent(hostf, name, pai)) != NULL) { 2463292722Sume cur->ai_next = p; 2464292722Sume while (cur && cur->ai_next) 2465292722Sume cur = cur->ai_next; 2466292722Sume } 2467292722Sume return (cur); 2468292722Sume} 2469292722Sume 247061877Sume/*ARGSUSED*/ 247161877Sumestatic int 2472157119Sume_files_getaddrinfo(void *rv, void *cb_data, va_list ap) 247365532Snectar{ 247465532Snectar const char *name; 247561877Sume const struct addrinfo *pai; 247661877Sume struct addrinfo sentinel, *cur; 2477144634Sume FILE *hostf = NULL; 247861877Sume 247965532Snectar name = va_arg(ap, char *); 248065532Snectar pai = va_arg(ap, struct addrinfo *); 248165532Snectar 248265532Snectar memset(&sentinel, 0, sizeof(sentinel)); 248361877Sume cur = &sentinel; 248461877Sume 2485144634Sume _sethtent(&hostf); 2486292722Sume if (pai->ai_family == AF_INET6 && 2487292722Sume (pai->ai_flags & (AI_ALL | AI_V4MAPPED)) == AI_V4MAPPED) { 2488292722Sume struct addrinfo ai0 = *pai; 2489292722Sume 2490292722Sume ai0.ai_flags &= ~AI_V4MAPPED; 2491292722Sume cur = _getht(&hostf, name, &ai0, cur); 2492292722Sume if (sentinel.ai_next == NULL) { 2493292722Sume _sethtent(&hostf); 2494292722Sume ai0.ai_flags |= AI_V4MAPPED; 2495292722Sume cur = _getht(&hostf, name, &ai0, cur); 2496292722Sume } 2497292722Sume } else 2498292722Sume cur = _getht(&hostf, name, pai, cur); 2499144634Sume _endhtent(&hostf); 250061877Sume 250165532Snectar *((struct addrinfo **)rv) = sentinel.ai_next; 250265532Snectar if (sentinel.ai_next == NULL) 250365532Snectar return NS_NOTFOUND; 250465532Snectar return NS_SUCCESS; 250561877Sume} 250661877Sume 250761877Sume#ifdef YP 250861877Sume/*ARGSUSED*/ 250965532Snectarstatic struct addrinfo * 2510157119Sume_yphostent(char *line, const struct addrinfo *pai) 251161877Sume{ 251261877Sume struct addrinfo sentinel, *cur; 251365532Snectar struct addrinfo hints, *res, *res0; 251461877Sume int error; 251565532Snectar char *p = line; 251665532Snectar const char *addr, *canonname; 251765532Snectar char *nextline; 251865532Snectar char *cp; 251961877Sume 252065532Snectar addr = canonname = NULL; 252165532Snectar 252265532Snectar memset(&sentinel, 0, sizeof(sentinel)); 252361877Sume cur = &sentinel; 252461877Sume 252565532Snectarnextline: 252665532Snectar /* terminate line */ 252765532Snectar cp = strchr(p, '\n'); 252865532Snectar if (cp) { 252965532Snectar *cp++ = '\0'; 253065532Snectar nextline = cp; 253165532Snectar } else 253265532Snectar nextline = NULL; 253361877Sume 253465532Snectar cp = strpbrk(p, " \t"); 253565532Snectar if (cp == NULL) { 253665532Snectar if (canonname == NULL) 253765532Snectar return (NULL); 253865532Snectar else 253965532Snectar goto done; 254061877Sume } 254165532Snectar *cp++ = '\0'; 254261877Sume 254365532Snectar addr = p; 254461877Sume 254565532Snectar while (cp && *cp) { 254665532Snectar if (*cp == ' ' || *cp == '\t') { 254765532Snectar cp++; 254861877Sume continue; 254965532Snectar } 255065532Snectar if (!canonname) 255165532Snectar canonname = cp; 255265532Snectar if ((cp = strpbrk(cp, " \t")) != NULL) 255365532Snectar *cp++ = '\0'; 255465532Snectar } 255561877Sume 2556121474Sume hints = *pai; 255765532Snectar hints.ai_flags = AI_NUMERICHOST; 2558292722Sume if (pai->ai_family == AF_INET6 && 2559292722Sume (pai->ai_flags & AI_V4MAPPED) == AI_V4MAPPED) 2560292722Sume hints.ai_flags |= AI_V4MAPPED; 2561121474Sume error = getaddrinfo(addr, NULL, &hints, &res0); 256265532Snectar if (error == 0) { 256365532Snectar for (res = res0; res; res = res->ai_next) { 256465532Snectar /* cover it up */ 256565532Snectar res->ai_flags = pai->ai_flags; 256661877Sume 256765532Snectar if (pai->ai_flags & AI_CANONNAME) 256865532Snectar (void)get_canonname(pai, res, canonname); 256961877Sume } 257065532Snectar } else 257165532Snectar res0 = NULL; 257265532Snectar if (res0) { 257365532Snectar cur->ai_next = res0; 257461877Sume while (cur && cur->ai_next) 257561877Sume cur = cur->ai_next; 257661877Sume } 257761877Sume 257865532Snectar if (nextline) { 257965532Snectar p = nextline; 258065532Snectar goto nextline; 258165532Snectar } 258261877Sume 258365532Snectardone: 258465532Snectar return sentinel.ai_next; 258561877Sume} 258665532Snectar 258765532Snectar/*ARGSUSED*/ 258865532Snectarstatic int 2589157119Sume_yp_getaddrinfo(void *rv, void *cb_data, va_list ap) 259065532Snectar{ 259165532Snectar struct addrinfo sentinel, *cur; 259265532Snectar struct addrinfo *ai = NULL; 2593144679Sume char *ypbuf; 2594144679Sume int ypbuflen, r; 259565532Snectar const char *name; 259665532Snectar const struct addrinfo *pai; 2597144679Sume char *ypdomain; 259865532Snectar 2599144679Sume if (_yp_check(&ypdomain) == 0) 2600144679Sume return NS_UNAVAIL; 2601144679Sume 260265532Snectar name = va_arg(ap, char *); 260365532Snectar pai = va_arg(ap, const struct addrinfo *); 260465532Snectar 260565532Snectar memset(&sentinel, 0, sizeof(sentinel)); 260665532Snectar cur = &sentinel; 260765532Snectar 2608292722Sume /* ipnodes.byname can hold both IPv4/v6 */ 2609292722Sume r = yp_match(ypdomain, "ipnodes.byname", name, 2610292722Sume (int)strlen(name), &ypbuf, &ypbuflen); 2611292722Sume if (r == 0) { 2612292722Sume ai = _yphostent(ypbuf, pai); 2613292722Sume if (ai) { 2614292722Sume cur->ai_next = ai; 2615292722Sume while (cur && cur->ai_next) 2616292722Sume cur = cur->ai_next; 2617292722Sume } 2618292722Sume free(ypbuf); 2619292722Sume } 2620292722Sume 2621292722Sume if (ai != NULL) { 2622292722Sume struct sockaddr_in6 *sin6; 2623292722Sume 2624292722Sume switch (ai->ai_family) { 2625292722Sume case AF_INET: 2626292722Sume goto done; 2627292722Sume case AF_INET6: 2628292722Sume sin6 = (struct sockaddr_in6 *)ai->ai_addr; 2629292722Sume if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) 2630292722Sume goto done; 2631292722Sume break; 2632292722Sume } 2633292722Sume } 2634292722Sume 263565532Snectar /* hosts.byname is only for IPv4 (Solaris8) */ 2636292722Sume if (pai->ai_family == AF_UNSPEC || pai->ai_family == AF_INET || 2637292722Sume ((pai->ai_family == AF_INET6 && 2638292722Sume (pai->ai_flags & AI_V4MAPPED) == AI_V4MAPPED) && 2639292722Sume (ai == NULL || (pai->ai_flags & AI_ALL) == AI_ALL))) { 2640144679Sume r = yp_match(ypdomain, "hosts.byname", name, 2641144679Sume (int)strlen(name), &ypbuf, &ypbuflen); 264265532Snectar if (r == 0) { 264365532Snectar struct addrinfo ai4; 264465532Snectar 264565532Snectar ai4 = *pai; 2646292722Sume if (pai->ai_family == AF_UNSPEC) 2647292722Sume ai4.ai_family = AF_INET; 2648144679Sume ai = _yphostent(ypbuf, &ai4); 264965532Snectar if (ai) { 265065532Snectar cur->ai_next = ai; 265165532Snectar while (cur && cur->ai_next) 265265532Snectar cur = cur->ai_next; 265365532Snectar } 2654146190Sume free(ypbuf); 265565532Snectar } 265665532Snectar } 265765532Snectar 2658292722Sumedone: 265965532Snectar if (sentinel.ai_next == NULL) { 2660156960Sume RES_SET_H_ERRNO(__res_state(), HOST_NOT_FOUND); 266165532Snectar return NS_NOTFOUND; 266265532Snectar } 266365532Snectar *((struct addrinfo **)rv) = sentinel.ai_next; 266465532Snectar return NS_SUCCESS; 266565532Snectar} 266661877Sume#endif 266761877Sume 266861877Sume/* resolver logic */ 266961877Sume 267061877Sume/* 267161877Sume * Formulate a normal query, send, and await answer. 267261877Sume * Returned answer is placed in supplied buffer "answer". 267361877Sume * Perform preliminary check of answer, returning success only 267461877Sume * if no error is indicated and the answer count is nonzero. 267561877Sume * Return the size of the response on success, -1 on error. 267661877Sume * Error number is left in h_errno. 267761877Sume * 267861877Sume * Caller must parse answer and determine whether it answers the question. 267961877Sume */ 268061877Sumestatic int 2681157119Sumeres_queryN(const char *name, struct res_target *target, res_state res) 268261877Sume{ 2683103357Sume u_char *buf; 268461877Sume HEADER *hp; 268561877Sume int n; 2686157203Sume u_int oflags; 268761877Sume struct res_target *t; 268861877Sume int rcode; 268961877Sume int ancount; 269061877Sume 269161877Sume rcode = NOERROR; 269261877Sume ancount = 0; 269361877Sume 2694103357Sume buf = malloc(MAXPACKET); 2695103357Sume if (!buf) { 2696156960Sume RES_SET_H_ERRNO(res, NETDB_INTERNAL); 2697103357Sume return -1; 2698103357Sume } 2699103357Sume 270061877Sume for (t = target; t; t = t->next) { 270161877Sume int class, type; 270261877Sume u_char *answer; 270361877Sume int anslen; 270461877Sume 270561877Sume hp = (HEADER *)(void *)t->answer; 270661877Sume 270761877Sume /* make it easier... */ 270862614Sitojun class = t->qclass; 270962614Sitojun type = t->qtype; 271061877Sume answer = t->answer; 271161877Sume anslen = t->anslen; 2712157203Sume 2713157203Sume oflags = res->_flags; 2714157203Sume 2715157203Sumeagain: 2716157203Sume hp->rcode = NOERROR; /* default */ 2717157203Sume 271861877Sume#ifdef DEBUG 2719156960Sume if (res->options & RES_DEBUG) 272061877Sume printf(";; res_query(%s, %d, %d)\n", name, class, type); 272161877Sume#endif 272261877Sume 2723156960Sume n = res_nmkquery(res, QUERY, name, class, type, NULL, 0, NULL, 2724103357Sume buf, MAXPACKET); 2725157203Sume if (n > 0 && (res->_flags & RES_F_EDNS0ERR) == 0 && 2726157203Sume (res->options & (RES_USE_EDNS0|RES_USE_DNSSEC)) != 0U) 2727156960Sume n = res_nopt(res, n, buf, MAXPACKET, anslen); 272861877Sume if (n <= 0) { 272961877Sume#ifdef DEBUG 2730156960Sume if (res->options & RES_DEBUG) 273161877Sume printf(";; res_query: mkquery failed\n"); 273261877Sume#endif 2733103357Sume free(buf); 2734156960Sume RES_SET_H_ERRNO(res, NO_RECOVERY); 273561877Sume return (n); 273661877Sume } 2737156960Sume n = res_nsend(res, buf, n, answer, anslen); 273861877Sume if (n < 0) { 2739157203Sume /* 2740157203Sume * if the query choked with EDNS0, retry 2741157203Sume * without EDNS0 2742157203Sume */ 2743157203Sume if ((res->options & (RES_USE_EDNS0|RES_USE_DNSSEC)) 2744157203Sume != 0U && 2745157203Sume ((oflags ^ res->_flags) & RES_F_EDNS0ERR) != 0) { 2746157203Sume res->_flags |= RES_F_EDNS0ERR; 2747157203Sume if (res->options & RES_DEBUG) 2748157203Sume printf(";; res_nquery: retry without EDNS0\n"); 2749157203Sume goto again; 2750157203Sume } 2751157203Sume rcode = hp->rcode; /* record most recent error */ 275261877Sume#ifdef DEBUG 2753156960Sume if (res->options & RES_DEBUG) 275461877Sume printf(";; res_query: send error\n"); 275561877Sume#endif 2756157203Sume continue; 275761877Sume } 275861877Sume 2759157081Sume if (n > anslen) 2760103350Snectar hp->rcode = FORMERR; /* XXX not very informative */ 2761157203Sume if (hp->rcode != NOERROR || ntohs(hp->ancount) == 0) { 276261877Sume rcode = hp->rcode; /* record most recent error */ 276361877Sume#ifdef DEBUG 2764156960Sume if (res->options & RES_DEBUG) 2765105940Sume printf(";; rcode = %u, ancount=%u\n", hp->rcode, 276661877Sume ntohs(hp->ancount)); 276761877Sume#endif 276861877Sume continue; 276961877Sume } 277061877Sume 277161877Sume ancount += ntohs(hp->ancount); 277261877Sume 277361877Sume t->n = n; 277461877Sume } 277561877Sume 2776103357Sume free(buf); 2777103357Sume 277861877Sume if (ancount == 0) { 277961877Sume switch (rcode) { 278061877Sume case NXDOMAIN: 2781156960Sume RES_SET_H_ERRNO(res, HOST_NOT_FOUND); 278261877Sume break; 278361877Sume case SERVFAIL: 2784156960Sume RES_SET_H_ERRNO(res, TRY_AGAIN); 278561877Sume break; 278661877Sume case NOERROR: 2787156960Sume RES_SET_H_ERRNO(res, NO_DATA); 278861877Sume break; 278961877Sume case FORMERR: 279061877Sume case NOTIMP: 279161877Sume case REFUSED: 279261877Sume default: 2793156960Sume RES_SET_H_ERRNO(res, NO_RECOVERY); 279461877Sume break; 279561877Sume } 279661877Sume return (-1); 279761877Sume } 279861877Sume return (ancount); 279961877Sume} 280061877Sume 280161877Sume/* 280261877Sume * Formulate a normal query, send, and retrieve answer in supplied buffer. 280361877Sume * Return the size of the response on success, -1 on error. 280461877Sume * If enabled, implement search rules until answer or unrecoverable failure 280561877Sume * is detected. Error code, if any, is left in h_errno. 280661877Sume */ 280761877Sumestatic int 2808157119Sumeres_searchN(const char *name, struct res_target *target, res_state res) 280961877Sume{ 281061877Sume const char *cp, * const *domain; 281161877Sume HEADER *hp = (HEADER *)(void *)target->answer; /*XXX*/ 281261877Sume u_int dots; 281361877Sume int trailing_dot, ret, saved_herrno; 2814155983Sume int got_nodata = 0, got_servfail = 0, root_on_list = 0; 2815155983Sume int tried_as_is = 0; 2816155983Sume int searched = 0; 2817145113Sume char abuf[MAXDNAME]; 281861877Sume 281961877Sume errno = 0; 2820156960Sume RES_SET_H_ERRNO(res, HOST_NOT_FOUND); /* default, if we never query */ 282161877Sume dots = 0; 282261877Sume for (cp = name; *cp; cp++) 282361877Sume dots += (*cp == '.'); 282461877Sume trailing_dot = 0; 282561877Sume if (cp > name && *--cp == '.') 282661877Sume trailing_dot++; 282761877Sume 282861877Sume /* 282961877Sume * if there aren't any dots, it could be a user-level alias 283061877Sume */ 2831156960Sume if (!dots && 2832156960Sume (cp = res_hostalias(res, name, abuf, sizeof(abuf))) != NULL) 2833156960Sume return (res_queryN(cp, target, res)); 283461877Sume 283561877Sume /* 2836155983Sume * If there are enough dots in the name, let's just give it a 2837155983Sume * try 'as is'. The threshold can be set with the "ndots" option. 2838155983Sume * Also, query 'as is', if there is a trailing dot in the name. 283961877Sume */ 284061877Sume saved_herrno = -1; 2841156960Sume if (dots >= res->ndots || trailing_dot) { 2842156960Sume ret = res_querydomainN(name, NULL, target, res); 2843155983Sume if (ret > 0 || trailing_dot) 284461877Sume return (ret); 2845156155Sume if (errno == ECONNREFUSED) { 2846156960Sume RES_SET_H_ERRNO(res, TRY_AGAIN); 2847156155Sume return (-1); 2848156155Sume } 2849156960Sume switch (res->res_h_errno) { 2850156155Sume case NO_DATA: 2851156155Sume case HOST_NOT_FOUND: 2852156155Sume break; 2853157093Sume case TRY_AGAIN: 2854157093Sume if (hp->rcode == SERVFAIL) 2855157093Sume break; 2856157093Sume /* FALLTHROUGH */ 2857156155Sume default: 2858156155Sume return (-1); 2859156155Sume } 2860156960Sume saved_herrno = res->res_h_errno; 286161877Sume tried_as_is++; 286261877Sume } 286361877Sume 286461877Sume /* 286561877Sume * We do at least one level of search if 286661877Sume * - there is no dot and RES_DEFNAME is set, or 286761877Sume * - there is at least one dot, there is no trailing dot, 286861877Sume * and RES_DNSRCH is set. 286961877Sume */ 2870156960Sume if ((!dots && (res->options & RES_DEFNAMES)) || 2871156960Sume (dots && !trailing_dot && (res->options & RES_DNSRCH))) { 287261877Sume int done = 0; 287361877Sume 2874156960Sume for (domain = (const char * const *)res->dnsrch; 287561877Sume *domain && !done; 287661877Sume domain++) { 2877155983Sume searched = 1; 287861877Sume 2879155983Sume if (domain[0][0] == '\0' || 2880155983Sume (domain[0][0] == '.' && domain[0][1] == '\0')) 2881155983Sume root_on_list++; 2882155983Sume 2883155983Sume if (root_on_list && tried_as_is) 2884155983Sume continue; 2885155983Sume 2886156960Sume ret = res_querydomainN(name, *domain, target, res); 288761877Sume if (ret > 0) 288861877Sume return (ret); 288961877Sume 289061877Sume /* 289161877Sume * If no server present, give up. 289261877Sume * If name isn't found in this domain, 289361877Sume * keep trying higher domains in the search list 289461877Sume * (if that's enabled). 289561877Sume * On a NO_DATA error, keep trying, otherwise 289661877Sume * a wildcard entry of another type could keep us 289761877Sume * from finding this entry higher in the domain. 289861877Sume * If we get some other error (negative answer or 289961877Sume * server failure), then stop searching up, 290061877Sume * but try the input name below in case it's 290161877Sume * fully-qualified. 290261877Sume */ 290361877Sume if (errno == ECONNREFUSED) { 2904156960Sume RES_SET_H_ERRNO(res, TRY_AGAIN); 290561877Sume return (-1); 290661877Sume } 290761877Sume 2908156960Sume switch (res->res_h_errno) { 290961877Sume case NO_DATA: 291061877Sume got_nodata++; 291161877Sume /* FALLTHROUGH */ 291261877Sume case HOST_NOT_FOUND: 291361877Sume /* keep trying */ 291461877Sume break; 291561877Sume case TRY_AGAIN: 2916157093Sume got_servfail++; 291761877Sume if (hp->rcode == SERVFAIL) { 291861877Sume /* try next search element, if any */ 291961877Sume break; 292061877Sume } 292161877Sume /* FALLTHROUGH */ 292261877Sume default: 292361877Sume /* anything else implies that we're done */ 292461877Sume done++; 292561877Sume } 292661877Sume /* 292761877Sume * if we got here for some reason other than DNSRCH, 292861877Sume * we only wanted one iteration of the loop, so stop. 292961877Sume */ 2930156960Sume if (!(res->options & RES_DNSRCH)) 293161877Sume done++; 293261877Sume } 293361877Sume } 293461877Sume 2935156960Sume switch (res->res_h_errno) { 2936156155Sume case NO_DATA: 2937156155Sume case HOST_NOT_FOUND: 2938156155Sume break; 2939157093Sume case TRY_AGAIN: 2940157093Sume if (hp->rcode == SERVFAIL) 2941157093Sume break; 2942157093Sume /* FALLTHROUGH */ 2943156155Sume default: 2944156155Sume goto giveup; 2945156155Sume } 2946156155Sume 294761877Sume /* 2948155983Sume * If the query has not already been tried as is then try it 2949155983Sume * unless RES_NOTLDQUERY is set and there were no dots. 295061877Sume */ 2951156960Sume if ((dots || !searched || !(res->options & RES_NOTLDQUERY)) && 2952155983Sume !(tried_as_is || root_on_list)) { 2953156960Sume ret = res_querydomainN(name, NULL, target, res); 295461877Sume if (ret > 0) 295561877Sume return (ret); 295661877Sume } 295761877Sume 295861877Sume /* 295961877Sume * if we got here, we didn't satisfy the search. 296061877Sume * if we did an initial full query, return that query's h_errno 296161877Sume * (note that we wouldn't be here if that query had succeeded). 296261877Sume * else if we ever got a nodata, send that back as the reason. 296361877Sume * else send back meaningless h_errno, that being the one from 296461877Sume * the last DNSRCH we did. 296561877Sume */ 2966156155Sumegiveup: 296761877Sume if (saved_herrno != -1) 2968156960Sume RES_SET_H_ERRNO(res, saved_herrno); 296961877Sume else if (got_nodata) 2970156960Sume RES_SET_H_ERRNO(res, NO_DATA); 297161877Sume else if (got_servfail) 2972156960Sume RES_SET_H_ERRNO(res, TRY_AGAIN); 297361877Sume return (-1); 297461877Sume} 297561877Sume 297661877Sume/* 297761877Sume * Perform a call on res_query on the concatenation of name and domain, 297861877Sume * removing a trailing dot from name if domain is NULL. 297961877Sume */ 298061877Sumestatic int 2981157119Sumeres_querydomainN(const char *name, const char *domain, 2982157119Sume struct res_target *target, res_state res) 298361877Sume{ 298461877Sume char nbuf[MAXDNAME]; 298561877Sume const char *longname = nbuf; 298661877Sume size_t n, d; 298761877Sume 298861877Sume#ifdef DEBUG 2989156960Sume if (res->options & RES_DEBUG) 299061877Sume printf(";; res_querydomain(%s, %s)\n", 299161877Sume name, domain?domain:"<Nil>"); 299261877Sume#endif 299361877Sume if (domain == NULL) { 299461877Sume /* 299561877Sume * Check for trailing '.'; 299661877Sume * copy without '.' if present. 299761877Sume */ 299861877Sume n = strlen(name); 299961877Sume if (n >= MAXDNAME) { 3000156960Sume RES_SET_H_ERRNO(res, NO_RECOVERY); 300161877Sume return (-1); 300261877Sume } 300361877Sume if (n > 0 && name[--n] == '.') { 300461877Sume strncpy(nbuf, name, n); 300561877Sume nbuf[n] = '\0'; 300661877Sume } else 300761877Sume longname = name; 300861877Sume } else { 300961877Sume n = strlen(name); 301061877Sume d = strlen(domain); 301161877Sume if (n + d + 1 >= MAXDNAME) { 3012156960Sume RES_SET_H_ERRNO(res, NO_RECOVERY); 301361877Sume return (-1); 301461877Sume } 3015105940Sume snprintf(nbuf, sizeof(nbuf), "%s.%s", name, domain); 301661877Sume } 3017156960Sume return (res_queryN(longname, target, res)); 301861877Sume} 3019