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: stable/10/lib/libc/net/getaddrinfo.c 327238 2017-12-27 14:50:07Z 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; 210305037Sache int aio_initial_sequence; 211121747Sume}; 212121747Sume 21365532Snectarstatic const ns_src default_dns_files[] = { 21465532Snectar { NSSRC_FILES, NS_SUCCESS }, 21565532Snectar { NSSRC_DNS, NS_SUCCESS }, 21665532Snectar { 0 } 21765532Snectar}; 21865532Snectar 21961877Sumestruct res_target { 22061877Sume struct res_target *next; 22161877Sume const char *name; /* domain name */ 22262614Sitojun int qclass, qtype; /* class and type of query */ 22361877Sume u_char *answer; /* buffer to put answer */ 22461877Sume int anslen; /* size of answer buffer */ 22561877Sume int n; /* result length */ 22661877Sume}; 22761877Sume 228121426Sume#define MAXPACKET (64*1024) 229121426Sume 230121426Sumetypedef union { 231121426Sume HEADER hdr; 232121426Sume u_char buf[MAXPACKET]; 233121426Sume} querybuf; 234121426Sume 235160593Sumestatic int str2number(const char *, int *); 236190525Sumestatic int explore_copy(const struct addrinfo *, const struct addrinfo *, 237190525Sume struct addrinfo **); 23892941Sobrienstatic int explore_null(const struct addrinfo *, 23992941Sobrien const char *, struct addrinfo **); 24092941Sobrienstatic int explore_numeric(const struct addrinfo *, const char *, 241140906Sume const char *, struct addrinfo **, const char *); 24292941Sobrienstatic int explore_numeric_scope(const struct addrinfo *, const char *, 24392941Sobrien const char *, struct addrinfo **); 24492941Sobrienstatic int get_canonname(const struct addrinfo *, 24592941Sobrien struct addrinfo *, const char *); 24692941Sobrienstatic struct addrinfo *get_ai(const struct addrinfo *, 24792941Sobrien const struct afd *, const char *); 248190525Sumestatic struct addrinfo *copy_ai(const struct addrinfo *); 24992905Sobrienstatic int get_portmatch(const struct addrinfo *, const char *); 25092905Sobrienstatic int get_port(struct addrinfo *, const char *, int); 25192905Sobrienstatic const struct afd *find_afd(int); 252121474Sumestatic int addrconfig(struct addrinfo *); 253267874Sume#ifdef INET6 254267874Sumestatic int is_ifdisabled(char *); 255267874Sume#endif 256129901Sumestatic void set_source(struct ai_order *, struct policyhead *); 257121747Sumestatic int comp_dst(const void *, const void *); 25861877Sume#ifdef INET6 259105943Sumestatic int ip6_str2scopeid(char *, struct sockaddr_in6 *, u_int32_t *); 26061877Sume#endif 261121747Sumestatic int gai_addr2scopetype(struct sockaddr *); 26255163Sshin 263121426Sumestatic int explore_fqdn(const struct addrinfo *, const char *, 264121426Sume const char *, struct addrinfo **); 265121426Sume 266121747Sumestatic int reorder(struct addrinfo *); 267121747Sumestatic int get_addrselectpolicy(struct policyhead *); 268121747Sumestatic void free_addrselectpolicy(struct policyhead *); 269121747Sumestatic struct policyqueue *match_addrselectpolicy(struct sockaddr *, 270121747Sume struct policyhead *); 271129901Sumestatic int matchlen(struct sockaddr *, struct sockaddr *); 272121747Sume 27392941Sobrienstatic struct addrinfo *getanswer(const querybuf *, int, const char *, int, 274156960Sume const struct addrinfo *, res_state); 275121426Sume#if defined(RESOLVSORT) 276156960Sumestatic int addr4sort(struct addrinfo *, res_state); 277121426Sume#endif 278105943Sumestatic int _dns_getaddrinfo(void *, void *, va_list); 279144634Sumestatic void _sethtent(FILE **); 280144634Sumestatic void _endhtent(FILE **); 281144634Sumestatic struct addrinfo *_gethtent(FILE **, const char *, 282144634Sume const struct addrinfo *); 28392905Sobrienstatic int _files_getaddrinfo(void *, void *, va_list); 28461877Sume#ifdef YP 28592905Sobrienstatic struct addrinfo *_yphostent(char *, const struct addrinfo *); 28692905Sobrienstatic int _yp_getaddrinfo(void *, void *, va_list); 28761877Sume#endif 288158115Sume#ifdef NS_CACHING 289158115Sumestatic int addrinfo_id_func(char *, size_t *, va_list, void *); 290158115Sumestatic int addrinfo_marshal_func(char *, size_t *, void *, va_list, void *); 291158115Sumestatic int addrinfo_unmarshal_func(char *, size_t, void *, va_list, void *); 292158115Sume#endif 29361877Sume 294156960Sumestatic int res_queryN(const char *, struct res_target *, res_state); 295156960Sumestatic int res_searchN(const char *, struct res_target *, res_state); 29692941Sobrienstatic int res_querydomainN(const char *, const char *, 297156960Sume struct res_target *, res_state); 29861877Sume 29955163Sshin/* XXX macros that make external reference is BAD. */ 30055163Sshin 301105940Sume#define GET_AI(ai, afd, addr) \ 30255163Sshindo { \ 30355163Sshin /* external reference: pai, error, and label free */ \ 30455163Sshin (ai) = get_ai(pai, (afd), (addr)); \ 30555163Sshin if ((ai) == NULL) { \ 30655163Sshin error = EAI_MEMORY; \ 30755163Sshin goto free; \ 30855163Sshin } \ 30961877Sume} while (/*CONSTCOND*/0) 31055163Sshin 311105940Sume#define GET_PORT(ai, serv) \ 31255163Sshindo { \ 31355163Sshin /* external reference: error and label free */ \ 31455163Sshin error = get_port((ai), (serv), 0); \ 31555163Sshin if (error != 0) \ 31655163Sshin goto free; \ 31761877Sume} while (/*CONSTCOND*/0) 31855163Sshin 319105940Sume#define GET_CANONNAME(ai, str) \ 32055163Sshindo { \ 32155163Sshin /* external reference: pai, error and label free */ \ 32255163Sshin error = get_canonname(pai, (ai), (str)); \ 32355163Sshin if (error != 0) \ 32455163Sshin goto free; \ 32561877Sume} while (/*CONSTCOND*/0) 32655163Sshin 327105940Sume#define ERR(err) \ 32855163Sshindo { \ 32955163Sshin /* external reference: error, and label bad */ \ 33055163Sshin error = (err); \ 33155163Sshin goto bad; \ 33261877Sume /*NOTREACHED*/ \ 33361877Sume} while (/*CONSTCOND*/0) 33455163Sshin 335105940Sume#define MATCH_FAMILY(x, y, w) \ 33661877Sume ((x) == (y) || (/*CONSTCOND*/(w) && ((x) == PF_UNSPEC || (y) == PF_UNSPEC))) 337105940Sume#define MATCH(x, y, w) \ 33861877Sume ((x) == (y) || (/*CONSTCOND*/(w) && ((x) == ANY || (y) == ANY))) 33955163Sshin 34055163Sshinvoid 341157119Sumefreeaddrinfo(struct addrinfo *ai) 34255163Sshin{ 34355163Sshin struct addrinfo *next; 34455163Sshin 34555163Sshin do { 34655163Sshin next = ai->ai_next; 34755163Sshin if (ai->ai_canonname) 34855163Sshin free(ai->ai_canonname); 34955163Sshin /* no need to free(ai->ai_addr) */ 35055163Sshin free(ai); 35161877Sume ai = next; 35261877Sume } while (ai); 35355163Sshin} 35455163Sshin 35555163Sshinstatic int 356160593Sumestr2number(const char *p, int *portp) 35755163Sshin{ 35862836Sitojun char *ep; 359140908Sume unsigned long v; 36062836Sitojun 36162836Sitojun if (*p == '\0') 362140908Sume return -1; 36362836Sitojun ep = NULL; 364105943Sume errno = 0; 365140908Sume v = strtoul(p, &ep, 10); 366160593Sume if (errno == 0 && ep && *ep == '\0' && v <= UINT_MAX) { 367160593Sume *portp = v; 368160593Sume return 0; 369160593Sume } else 370140908Sume return -1; 37155163Sshin} 37255163Sshin 37355163Sshinint 374157119Sumegetaddrinfo(const char *hostname, const char *servname, 375157119Sume const struct addrinfo *hints, struct addrinfo **res) 37655163Sshin{ 37755163Sshin struct addrinfo sentinel; 37855163Sshin struct addrinfo *cur; 37955163Sshin int error = 0; 380190525Sume struct addrinfo ai, ai0, *afai; 38155163Sshin struct addrinfo *pai; 382190525Sume const struct afd *afd; 38355163Sshin const struct explore *ex; 384190525Sume struct addrinfo *afailist[sizeof(afdl)/sizeof(afdl[0])]; 385190525Sume struct addrinfo *afai_unspec; 386190525Sume int found; 387121747Sume int numeric = 0; 38855163Sshin 389190525Sume /* ensure we return NULL on errors */ 390190525Sume *res = NULL; 391190525Sume 392190525Sume memset(&ai, 0, sizeof(ai)); 393190525Sume 394190525Sume memset(afailist, 0, sizeof(afailist)); 395190525Sume afai_unspec = NULL; 396190525Sume 39761877Sume memset(&sentinel, 0, sizeof(sentinel)); 39855163Sshin cur = &sentinel; 39955163Sshin pai = &ai; 40055163Sshin pai->ai_flags = 0; 40155163Sshin pai->ai_family = PF_UNSPEC; 40255163Sshin pai->ai_socktype = ANY; 40355163Sshin pai->ai_protocol = ANY; 40455163Sshin pai->ai_addrlen = 0; 40555163Sshin pai->ai_canonname = NULL; 40655163Sshin pai->ai_addr = NULL; 40755163Sshin pai->ai_next = NULL; 40855163Sshin 40955163Sshin if (hostname == NULL && servname == NULL) 41055163Sshin return EAI_NONAME; 41155163Sshin if (hints) { 41255163Sshin /* error check for hints */ 41355163Sshin if (hints->ai_addrlen || hints->ai_canonname || 41455163Sshin hints->ai_addr || hints->ai_next) 41555163Sshin ERR(EAI_BADHINTS); /* xxx */ 41655163Sshin if (hints->ai_flags & ~AI_MASK) 41755163Sshin ERR(EAI_BADFLAGS); 41855163Sshin switch (hints->ai_family) { 41955163Sshin case PF_UNSPEC: 42055163Sshin case PF_INET: 42155163Sshin#ifdef INET6 42255163Sshin case PF_INET6: 42355163Sshin#endif 42455163Sshin break; 42555163Sshin default: 42655163Sshin ERR(EAI_FAMILY); 42755163Sshin } 42855163Sshin memcpy(pai, hints, sizeof(*pai)); 42955163Sshin 43055163Sshin /* 43155163Sshin * if both socktype/protocol are specified, check if they 43255163Sshin * are meaningful combination. 43355163Sshin */ 43455163Sshin if (pai->ai_socktype != ANY && pai->ai_protocol != ANY) { 43561877Sume for (ex = explore; ex->e_af >= 0; ex++) { 436190525Sume if (!MATCH_FAMILY(pai->ai_family, ex->e_af, 437190525Sume WILD_AF(ex))) 43861877Sume continue; 439190525Sume if (!MATCH(pai->ai_socktype, ex->e_socktype, 440190525Sume WILD_SOCKTYPE(ex))) 44155163Sshin continue; 442190525Sume if (!MATCH(pai->ai_protocol, ex->e_protocol, 443190525Sume WILD_PROTOCOL(ex))) 44455163Sshin continue; 445190525Sume 446190525Sume /* matched */ 447190525Sume break; 44855163Sshin } 449190416Sume 450190416Sume if (ex->e_af < 0) 451190416Sume ERR(EAI_BADHINTS); 45255163Sshin } 45355163Sshin } 45455163Sshin 45561877Sume /* 456292722Sume * RFC 3493: AI_ALL and AI_V4MAPPED are effective only against 457292722Sume * AF_INET6 query. They need to be ignored if specified in other 458292722Sume * occassions. 459292722Sume */ 460292722Sume switch (pai->ai_flags & (AI_ALL | AI_V4MAPPED)) { 461292722Sume case AI_V4MAPPED: 462292722Sume case AI_ALL | AI_V4MAPPED: 463292722Sume#ifdef INET6 464292722Sume if (pai->ai_family != AF_INET6) 465292722Sume pai->ai_flags &= ~(AI_ALL | AI_V4MAPPED); 466292722Sume break; 467292722Sume#endif 468292722Sume case AI_ALL: 469292722Sume pai->ai_flags &= ~(AI_ALL | AI_V4MAPPED); 470292722Sume break; 471292722Sume } 472292722Sume 473292722Sume /* 47461877Sume * check for special cases. (1) numeric servname is disallowed if 47561877Sume * socktype/protocol are left unspecified. (2) servname is disallowed 47661877Sume * for raw and other inet{,6} sockets. 47755163Sshin */ 47855163Sshin if (MATCH_FAMILY(pai->ai_family, PF_INET, 1) 47961877Sume#ifdef PF_INET6 480121474Sume || MATCH_FAMILY(pai->ai_family, PF_INET6, 1) 48155163Sshin#endif 48255163Sshin ) { 48361877Sume ai0 = *pai; /* backup *pai */ 48455163Sshin 48561877Sume if (pai->ai_family == PF_UNSPEC) { 48661877Sume#ifdef PF_INET6 48755163Sshin pai->ai_family = PF_INET6; 48855163Sshin#else 48955163Sshin pai->ai_family = PF_INET; 49055163Sshin#endif 49161877Sume } 49255163Sshin error = get_portmatch(pai, servname); 49355163Sshin if (error) 494236695Sdim goto bad; 49561877Sume 49661877Sume *pai = ai0; 49755163Sshin } 49855163Sshin 49961877Sume ai0 = *pai; 50061877Sume 501190525Sume /* 502190525Sume * NULL hostname, or numeric hostname. 503190525Sume * If numeric representation of AF1 can be interpreted as FQDN 504190525Sume * representation of AF2, we need to think again about the code below. 505190525Sume */ 506190525Sume found = 0; 507190525Sume for (afd = afdl; afd->a_af; afd++) { 50855163Sshin *pai = ai0; 50955163Sshin 510190525Sume if (!MATCH_FAMILY(pai->ai_family, afd->a_af, 1)) 51155163Sshin continue; 51261877Sume 51355163Sshin if (pai->ai_family == PF_UNSPEC) 514190525Sume pai->ai_family = afd->a_af; 51555163Sshin 516190525Sume if (hostname == NULL) { 517190525Sume error = explore_null(pai, servname, 518190525Sume &afailist[afd - afdl]); 519190525Sume 520190525Sume /* 521190525Sume * Errors from explore_null should be unexpected and 522190525Sume * be caught to avoid returning an incomplete result. 523190525Sume */ 524190525Sume if (error != 0) 525190525Sume goto bad; 526190525Sume } else { 527140906Sume error = explore_numeric_scope(pai, hostname, servname, 528190525Sume &afailist[afd - afdl]); 52955163Sshin 530190525Sume /* 531190525Sume * explore_numeric_scope returns an error for address 532190525Sume * families that do not match that of hostname. 533190525Sume * Thus we should not catch the error at this moment. 534190525Sume */ 535190525Sume } 536121474Sume 537190525Sume if (!error && afailist[afd - afdl]) 538190525Sume found++; 53955163Sshin } 540190525Sume if (found) { 541121747Sume numeric = 1; 542190525Sume goto globcopy; 543121747Sume } 544121474Sume 545121425Sume if (hostname == NULL) 546121425Sume ERR(EAI_NONAME); /* used to be EAI_NODATA */ 54755163Sshin if (pai->ai_flags & AI_NUMERICHOST) 54890053Sroam ERR(EAI_NONAME); 54955163Sshin 550121474Sume if ((pai->ai_flags & AI_ADDRCONFIG) != 0 && !addrconfig(&ai0)) 551121474Sume ERR(EAI_FAIL); 552121474Sume 55361877Sume /* 55461877Sume * hostname as alphabetical name. 55561877Sume */ 556190525Sume *pai = ai0; 557190525Sume error = explore_fqdn(pai, hostname, servname, &afai_unspec); 558190525Sume 559190525Sumeglobcopy: 56061877Sume for (ex = explore; ex->e_af >= 0; ex++) { 56161877Sume *pai = ai0; 56255163Sshin 563190525Sume if (!MATCH_FAMILY(pai->ai_family, ex->e_af, WILD_AF(ex))) 56461877Sume continue; 565121474Sume if (!MATCH(pai->ai_socktype, ex->e_socktype, 566190525Sume WILD_SOCKTYPE(ex))) 56761877Sume continue; 568121474Sume if (!MATCH(pai->ai_protocol, ex->e_protocol, 569190525Sume WILD_PROTOCOL(ex))) 57061877Sume continue; 57155163Sshin 572190525Sume if (pai->ai_family == PF_UNSPEC) 573190525Sume pai->ai_family = ex->e_af; 57461877Sume if (pai->ai_socktype == ANY && ex->e_socktype != ANY) 57561877Sume pai->ai_socktype = ex->e_socktype; 57661877Sume if (pai->ai_protocol == ANY && ex->e_protocol != ANY) 57761877Sume pai->ai_protocol = ex->e_protocol; 57861877Sume 579190525Sume /* 580190525Sume * if the servname does not match socktype/protocol, ignore it. 581190525Sume */ 582190525Sume if (get_portmatch(pai, servname) != 0) 583190525Sume continue; 58461877Sume 585190525Sume if (afai_unspec) 586190525Sume afai = afai_unspec; 587190525Sume else { 588190525Sume if ((afd = find_afd(pai->ai_family)) == NULL) 589190525Sume continue; 590190525Sume /* XXX assumes that afd points inside afdl[] */ 591190525Sume afai = afailist[afd - afdl]; 592190525Sume } 593190525Sume if (!afai) 594190525Sume continue; 595190525Sume 596190525Sume error = explore_copy(pai, afai, &cur->ai_next); 597190525Sume if (error != 0) 598190525Sume goto bad; 599190525Sume 60061877Sume while (cur && cur->ai_next) 60161877Sume cur = cur->ai_next; 60255163Sshin } 60355163Sshin 604121747Sume /* 605121747Sume * ensure we return either: 606121747Sume * - error == 0, non-NULL *res 607121747Sume * - error != 0, NULL *res 608121747Sume */ 60961877Sume if (error == 0) { 61061877Sume if (sentinel.ai_next) { 611121747Sume /* 612121747Sume * If the returned entry is for an active connection, 613121747Sume * and the given name is not numeric, reorder the 614121747Sume * list, so that the application would try the list 615172052Sjinmei * in the most efficient order. Since the head entry 616172052Sjinmei * of the original list may contain ai_canonname and 617172052Sjinmei * that entry may be moved elsewhere in the new list, 618172052Sjinmei * we keep the pointer and will restore it in the new 619172052Sjinmei * head entry. (Note that RFC3493 requires the head 620172052Sjinmei * entry store it when requested by the caller). 621121747Sume */ 622121747Sume if (hints == NULL || !(hints->ai_flags & AI_PASSIVE)) { 623172052Sjinmei if (!numeric) { 624172052Sjinmei char *canonname; 625172052Sjinmei 626172052Sjinmei canonname = 627172052Sjinmei sentinel.ai_next->ai_canonname; 628172052Sjinmei sentinel.ai_next->ai_canonname = NULL; 629121747Sume (void)reorder(&sentinel); 630172052Sjinmei if (sentinel.ai_next->ai_canonname == 631172052Sjinmei NULL) { 632172052Sjinmei sentinel.ai_next->ai_canonname 633172052Sjinmei = canonname; 634172052Sjinmei } else if (canonname != NULL) 635172052Sjinmei free(canonname); 636172052Sjinmei } 637121747Sume } 63861877Sume *res = sentinel.ai_next; 63961877Sume } else 64061877Sume error = EAI_FAIL; 64155163Sshin } 642190525Sume 643121747Sumebad: 644190525Sume if (afai_unspec) 645190525Sume freeaddrinfo(afai_unspec); 646190525Sume for (afd = afdl; afd->a_af; afd++) { 647190525Sume if (afailist[afd - afdl]) 648190525Sume freeaddrinfo(afailist[afd - afdl]); 649190525Sume } 650190525Sume if (!*res) 651190525Sume if (sentinel.ai_next) 652190525Sume freeaddrinfo(sentinel.ai_next); 653190525Sume 654190525Sume return (error); 65555163Sshin} 65655163Sshin 657121747Sumestatic int 658157119Sumereorder(struct addrinfo *sentinel) 659121747Sume{ 660121747Sume struct addrinfo *ai, **aip; 661121747Sume struct ai_order *aio; 662121747Sume int i, n; 663121747Sume struct policyhead policyhead; 664121747Sume 665121747Sume /* count the number of addrinfo elements for sorting. */ 666121747Sume for (n = 0, ai = sentinel->ai_next; ai != NULL; ai = ai->ai_next, n++) 667121747Sume ; 668121747Sume 669121747Sume /* 670121747Sume * If the number is small enough, we can skip the reordering process. 671121747Sume */ 672121747Sume if (n <= 1) 673121747Sume return(n); 674121747Sume 675121747Sume /* allocate a temporary array for sort and initialization of it. */ 676311718Sngie if ((aio = calloc(n, sizeof(*aio))) == NULL) 677121747Sume return(n); /* give up reordering */ 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); 693305037Sache aio[i].aio_initial_sequence = i; 694121747Sume } 695121747Sume 696121747Sume /* perform sorting. */ 697121747Sume qsort(aio, n, sizeof(*aio), comp_dst); 698121747Sume 699121747Sume /* reorder the addrinfo chain. */ 700121747Sume for (i = 0, aip = &sentinel->ai_next; i < n; i++) { 701121747Sume *aip = aio[i].aio_ai; 702121747Sume aip = &aio[i].aio_ai->ai_next; 703121747Sume } 704121747Sume *aip = NULL; 705121747Sume 706121747Sume /* cleanup and return */ 707121747Sume free(aio); 708121747Sume free_addrselectpolicy(&policyhead); 709121747Sume return(n); 710121747Sume} 711121747Sume 712121747Sumestatic int 713157119Sumeget_addrselectpolicy(struct policyhead *head) 714121747Sume{ 715121747Sume#ifdef INET6 716121747Sume int mib[] = { CTL_NET, PF_INET6, IPPROTO_IPV6, IPV6CTL_ADDRCTLPOLICY }; 717121747Sume size_t l; 718121747Sume char *buf; 719121747Sume struct in6_addrpolicy *pol, *ep; 720121747Sume 721121747Sume if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), NULL, &l, NULL, 0) < 0) 722121747Sume return (0); 723238599Semax if (l == 0) 724238599Semax return (0); 725121747Sume if ((buf = malloc(l)) == NULL) 726121747Sume return (0); 727121747Sume if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), buf, &l, NULL, 0) < 0) { 728121747Sume free(buf); 729121747Sume return (0); 730121747Sume } 731121747Sume 732121747Sume ep = (struct in6_addrpolicy *)(buf + l); 733121747Sume for (pol = (struct in6_addrpolicy *)buf; pol + 1 <= ep; pol++) { 734121747Sume struct policyqueue *new; 735121747Sume 736121747Sume if ((new = malloc(sizeof(*new))) == NULL) { 737121747Sume free_addrselectpolicy(head); /* make the list empty */ 738121747Sume break; 739121747Sume } 740121747Sume new->pc_policy = *pol; 741121747Sume TAILQ_INSERT_TAIL(head, new, pc_entry); 742121747Sume } 743121747Sume 744121747Sume free(buf); 745121747Sume return (1); 746121747Sume#else 747121747Sume return (0); 748121747Sume#endif 749121747Sume} 750121747Sume 751121747Sumestatic void 752157119Sumefree_addrselectpolicy(struct policyhead *head) 753121747Sume{ 754121747Sume struct policyqueue *ent, *nent; 755121747Sume 756121747Sume for (ent = TAILQ_FIRST(head); ent; ent = nent) { 757121747Sume nent = TAILQ_NEXT(ent, pc_entry); 758121747Sume TAILQ_REMOVE(head, ent, pc_entry); 759121747Sume free(ent); 760121747Sume } 761121747Sume} 762121747Sume 763121747Sumestatic struct policyqueue * 764157119Sumematch_addrselectpolicy(struct sockaddr *addr, struct policyhead *head) 765121747Sume{ 766121747Sume#ifdef INET6 767121747Sume struct policyqueue *ent, *bestent = NULL; 768121747Sume struct in6_addrpolicy *pol; 769121747Sume int matchlen, bestmatchlen = -1; 770121747Sume u_char *mp, *ep, *k, *p, m; 771121747Sume struct sockaddr_in6 key; 772121747Sume 773121747Sume switch(addr->sa_family) { 774121747Sume case AF_INET6: 775121747Sume key = *(struct sockaddr_in6 *)addr; 776121747Sume break; 777121747Sume case AF_INET: 778121747Sume /* convert the address into IPv4-mapped IPv6 address. */ 779121747Sume memset(&key, 0, sizeof(key)); 780121747Sume key.sin6_family = AF_INET6; 781121747Sume key.sin6_len = sizeof(key); 782292826Sume _map_v4v6_address( 783292826Sume (char *)&((struct sockaddr_in *)addr)->sin_addr, 784292826Sume (char *)&key.sin6_addr); 785121747Sume break; 786121747Sume default: 787121747Sume return(NULL); 788121747Sume } 789121747Sume 790121747Sume for (ent = TAILQ_FIRST(head); ent; ent = TAILQ_NEXT(ent, pc_entry)) { 791121747Sume pol = &ent->pc_policy; 792121747Sume matchlen = 0; 793121747Sume 794121747Sume mp = (u_char *)&pol->addrmask.sin6_addr; 795121747Sume ep = mp + 16; /* XXX: scope field? */ 796121747Sume k = (u_char *)&key.sin6_addr; 797121747Sume p = (u_char *)&pol->addr.sin6_addr; 798121747Sume for (; mp < ep && *mp; mp++, k++, p++) { 799121747Sume m = *mp; 800121747Sume if ((*k & m) != *p) 801121747Sume goto next; /* not match */ 802121747Sume if (m == 0xff) /* short cut for a typical case */ 803121747Sume matchlen += 8; 804121747Sume else { 805121747Sume while (m >= 0x80) { 806121747Sume matchlen++; 807121747Sume m <<= 1; 808121747Sume } 809121747Sume } 810121747Sume } 811121747Sume 812121747Sume /* matched. check if this is better than the current best. */ 813121747Sume if (matchlen > bestmatchlen) { 814121747Sume bestent = ent; 815121747Sume bestmatchlen = matchlen; 816121747Sume } 817121747Sume 818121747Sume next: 819121747Sume continue; 820121747Sume } 821121747Sume 822121747Sume return(bestent); 823121747Sume#else 824121747Sume return(NULL); 825121747Sume#endif 826121747Sume 827121747Sume} 828121747Sume 829129901Sumestatic void 830157119Sumeset_source(struct ai_order *aio, struct policyhead *ph) 831129901Sume{ 832129901Sume struct addrinfo ai = *aio->aio_ai; 833129901Sume struct sockaddr_storage ss; 834145786Sume socklen_t srclen; 835145786Sume int s; 836129901Sume 837129901Sume /* set unspec ("no source is available"), just in case */ 838129901Sume aio->aio_srcsa.sa_family = AF_UNSPEC; 839129901Sume aio->aio_srcscope = -1; 840129901Sume 841129901Sume switch(ai.ai_family) { 842129901Sume case AF_INET: 843129901Sume#ifdef INET6 844129901Sume case AF_INET6: 845129901Sume#endif 846129901Sume break; 847129901Sume default: /* ignore unsupported AFs explicitly */ 848129901Sume return; 849129901Sume } 850129901Sume 851129901Sume /* XXX: make a dummy addrinfo to call connect() */ 852129901Sume ai.ai_socktype = SOCK_DGRAM; 853129901Sume ai.ai_protocol = IPPROTO_UDP; /* is UDP too specific? */ 854129901Sume ai.ai_next = NULL; 855129901Sume memset(&ss, 0, sizeof(ss)); 856129901Sume memcpy(&ss, ai.ai_addr, ai.ai_addrlen); 857129901Sume ai.ai_addr = (struct sockaddr *)&ss; 858129901Sume get_port(&ai, "1", 0); 859129901Sume 860129901Sume /* open a socket to get the source address for the given dst */ 861255328Sjilles if ((s = _socket(ai.ai_family, ai.ai_socktype | SOCK_CLOEXEC, 862255328Sjilles ai.ai_protocol)) < 0) 863129901Sume return; /* give up */ 864292722Sume#ifdef INET6 865292722Sume if (ai.ai_family == AF_INET6) { 866292722Sume struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)ai.ai_addr; 867292722Sume int off = 0; 868292722Sume 869292722Sume if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) 870292722Sume (void)_setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, 871292722Sume (char *)&off, sizeof(off)); 872292722Sume } 873292722Sume#endif 874129901Sume if (_connect(s, ai.ai_addr, ai.ai_addrlen) < 0) 875129901Sume goto cleanup; 876129901Sume srclen = ai.ai_addrlen; 877129901Sume if (_getsockname(s, &aio->aio_srcsa, &srclen) < 0) { 878129901Sume aio->aio_srcsa.sa_family = AF_UNSPEC; 879129901Sume goto cleanup; 880129901Sume } 881129901Sume aio->aio_srcscope = gai_addr2scopetype(&aio->aio_srcsa); 882129901Sume aio->aio_srcpolicy = match_addrselectpolicy(&aio->aio_srcsa, ph); 883129901Sume aio->aio_matchlen = matchlen(&aio->aio_srcsa, aio->aio_ai->ai_addr); 884129901Sume#ifdef INET6 885129901Sume if (ai.ai_family == AF_INET6) { 886129901Sume struct in6_ifreq ifr6; 887129901Sume u_int32_t flags6; 888129901Sume 889129901Sume memset(&ifr6, 0, sizeof(ifr6)); 890129901Sume memcpy(&ifr6.ifr_addr, ai.ai_addr, ai.ai_addrlen); 891129901Sume if (_ioctl(s, SIOCGIFAFLAG_IN6, &ifr6) == 0) { 892129901Sume flags6 = ifr6.ifr_ifru.ifru_flags6; 893129901Sume if ((flags6 & IN6_IFF_DEPRECATED)) 894129901Sume aio->aio_srcflag |= AIO_SRCFLAG_DEPRECATED; 895129901Sume } 896129901Sume } 897129901Sume#endif 898129901Sume 899129901Sume cleanup: 900129901Sume _close(s); 901129901Sume return; 902129901Sume} 903129901Sume 904121747Sumestatic int 905157119Sumematchlen(struct sockaddr *src, struct sockaddr *dst) 906129901Sume{ 907129901Sume int match = 0; 908129901Sume u_char *s, *d; 909129901Sume u_char *lim, r; 910129901Sume int addrlen; 911129901Sume 912129901Sume switch (src->sa_family) { 913129901Sume#ifdef INET6 914129901Sume case AF_INET6: 915129901Sume s = (u_char *)&((struct sockaddr_in6 *)src)->sin6_addr; 916129901Sume d = (u_char *)&((struct sockaddr_in6 *)dst)->sin6_addr; 917129901Sume addrlen = sizeof(struct in6_addr); 918129901Sume lim = s + addrlen; 919129901Sume break; 920129901Sume#endif 921129901Sume case AF_INET: 922146222Sgnn s = (u_char *)&((struct sockaddr_in *)src)->sin_addr; 923146222Sgnn d = (u_char *)&((struct sockaddr_in *)dst)->sin_addr; 924129901Sume addrlen = sizeof(struct in_addr); 925129901Sume lim = s + addrlen; 926129901Sume break; 927129901Sume default: 928129901Sume return(0); 929129901Sume } 930129901Sume 931129901Sume while (s < lim) 932129901Sume if ((r = (*d++ ^ *s++)) != 0) { 933305401Sache while ((r & 0x80) == 0) { 934129901Sume match++; 935129901Sume r <<= 1; 936129901Sume } 937129901Sume break; 938129901Sume } else 939129901Sume match += 8; 940129901Sume return(match); 941129901Sume} 942129901Sume 943129901Sumestatic int 944157119Sumecomp_dst(const void *arg1, const void *arg2) 945121747Sume{ 946121747Sume const struct ai_order *dst1 = arg1, *dst2 = arg2; 947121747Sume 948121747Sume /* 949121747Sume * Rule 1: Avoid unusable destinations. 950121747Sume * XXX: we currently do not consider if an appropriate route exists. 951121747Sume */ 952121747Sume if (dst1->aio_srcsa.sa_family != AF_UNSPEC && 953121747Sume dst2->aio_srcsa.sa_family == AF_UNSPEC) { 954121747Sume return(-1); 955121747Sume } 956121747Sume if (dst1->aio_srcsa.sa_family == AF_UNSPEC && 957121747Sume dst2->aio_srcsa.sa_family != AF_UNSPEC) { 958121747Sume return(1); 959121747Sume } 960121747Sume 961121747Sume /* Rule 2: Prefer matching scope. */ 962121747Sume if (dst1->aio_dstscope == dst1->aio_srcscope && 963121747Sume dst2->aio_dstscope != dst2->aio_srcscope) { 964121747Sume return(-1); 965121747Sume } 966121747Sume if (dst1->aio_dstscope != dst1->aio_srcscope && 967121747Sume dst2->aio_dstscope == dst2->aio_srcscope) { 968121747Sume return(1); 969121747Sume } 970121747Sume 971121747Sume /* Rule 3: Avoid deprecated addresses. */ 972121747Sume if (dst1->aio_srcsa.sa_family != AF_UNSPEC && 973121747Sume dst2->aio_srcsa.sa_family != AF_UNSPEC) { 974121747Sume if (!(dst1->aio_srcflag & AIO_SRCFLAG_DEPRECATED) && 975121747Sume (dst2->aio_srcflag & AIO_SRCFLAG_DEPRECATED)) { 976121747Sume return(-1); 977121747Sume } 978121747Sume if ((dst1->aio_srcflag & AIO_SRCFLAG_DEPRECATED) && 979121747Sume !(dst2->aio_srcflag & AIO_SRCFLAG_DEPRECATED)) { 980121747Sume return(1); 981121747Sume } 982121747Sume } 983121747Sume 984121747Sume /* Rule 4: Prefer home addresses. */ 985121747Sume /* XXX: not implemented yet */ 986121747Sume 987121747Sume /* Rule 5: Prefer matching label. */ 988121747Sume#ifdef INET6 989121747Sume if (dst1->aio_srcpolicy && dst1->aio_dstpolicy && 990121747Sume dst1->aio_srcpolicy->pc_policy.label == 991121747Sume dst1->aio_dstpolicy->pc_policy.label && 992121747Sume (dst2->aio_srcpolicy == NULL || dst2->aio_dstpolicy == NULL || 993121747Sume dst2->aio_srcpolicy->pc_policy.label != 994121747Sume dst2->aio_dstpolicy->pc_policy.label)) { 995121747Sume return(-1); 996121747Sume } 997121747Sume if (dst2->aio_srcpolicy && dst2->aio_dstpolicy && 998121747Sume dst2->aio_srcpolicy->pc_policy.label == 999121747Sume dst2->aio_dstpolicy->pc_policy.label && 1000121747Sume (dst1->aio_srcpolicy == NULL || dst1->aio_dstpolicy == NULL || 1001121747Sume dst1->aio_srcpolicy->pc_policy.label != 1002121747Sume dst1->aio_dstpolicy->pc_policy.label)) { 1003121747Sume return(1); 1004121747Sume } 1005121747Sume#endif 1006121747Sume 1007121747Sume /* Rule 6: Prefer higher precedence. */ 1008121747Sume#ifdef INET6 1009121747Sume if (dst1->aio_dstpolicy && 1010121747Sume (dst2->aio_dstpolicy == NULL || 1011121747Sume dst1->aio_dstpolicy->pc_policy.preced > 1012121747Sume dst2->aio_dstpolicy->pc_policy.preced)) { 1013121747Sume return(-1); 1014121747Sume } 1015121747Sume if (dst2->aio_dstpolicy && 1016121747Sume (dst1->aio_dstpolicy == NULL || 1017121747Sume dst2->aio_dstpolicy->pc_policy.preced > 1018121747Sume dst1->aio_dstpolicy->pc_policy.preced)) { 1019121747Sume return(1); 1020121747Sume } 1021121747Sume#endif 1022121747Sume 1023121747Sume /* Rule 7: Prefer native transport. */ 1024121747Sume /* XXX: not implemented yet */ 1025121747Sume 1026121747Sume /* Rule 8: Prefer smaller scope. */ 1027121747Sume if (dst1->aio_dstscope >= 0 && 1028121747Sume dst1->aio_dstscope < dst2->aio_dstscope) { 1029121747Sume return(-1); 1030121747Sume } 1031121747Sume if (dst2->aio_dstscope >= 0 && 1032121747Sume dst2->aio_dstscope < dst1->aio_dstscope) { 1033121747Sume return(1); 1034121747Sume } 1035121747Sume 1036121747Sume /* 1037121747Sume * Rule 9: Use longest matching prefix. 1038121747Sume * We compare the match length in a same AF only. 1039121747Sume */ 1040121747Sume if (dst1->aio_ai->ai_addr->sa_family == 1041268051Sume dst2->aio_ai->ai_addr->sa_family && 1042268051Sume dst1->aio_ai->ai_addr->sa_family != AF_INET) { 1043121747Sume if (dst1->aio_matchlen > dst2->aio_matchlen) { 1044121747Sume return(-1); 1045121747Sume } 1046121747Sume if (dst1->aio_matchlen < dst2->aio_matchlen) { 1047121747Sume return(1); 1048121747Sume } 1049121747Sume } 1050121747Sume 1051121747Sume /* Rule 10: Otherwise, leave the order unchanged. */ 1052305037Sache 1053305037Sache /* 1054305037Sache * Note that qsort is unstable; so, we can't return zero and 1055305037Sache * expect the order to be unchanged. 1056305037Sache * That also means we can't depend on the current position of 1057305037Sache * dst2 being after dst1. We must enforce the initial order 1058305037Sache * with an explicit compare on the original position. 1059305037Sache * The qsort specification requires that "When the same objects 1060305037Sache * (consisting of width bytes, irrespective of their current 1061305037Sache * positions in the array) are passed more than once to the 1062305037Sache * comparison function, the results shall be consistent with one 1063305037Sache * another." 1064305037Sache * In other words, If A < B, then we must also return B > A. 1065305037Sache */ 1066305037Sache if (dst2->aio_initial_sequence < dst1->aio_initial_sequence) 1067305037Sache return(1); 1068305037Sache 1069121747Sume return(-1); 1070121747Sume} 1071121747Sume 107255163Sshin/* 1073121747Sume * Copy from scope.c. 1074121747Sume * XXX: we should standardize the functions and link them as standard 1075121747Sume * library. 1076121747Sume */ 1077121747Sumestatic int 1078157119Sumegai_addr2scopetype(struct sockaddr *sa) 1079121747Sume{ 1080121747Sume#ifdef INET6 1081121747Sume struct sockaddr_in6 *sa6; 1082121747Sume#endif 1083121747Sume struct sockaddr_in *sa4; 1084121747Sume 1085121747Sume switch(sa->sa_family) { 1086121747Sume#ifdef INET6 1087121747Sume case AF_INET6: 1088121747Sume sa6 = (struct sockaddr_in6 *)sa; 1089121747Sume if (IN6_IS_ADDR_MULTICAST(&sa6->sin6_addr)) { 1090121747Sume /* just use the scope field of the multicast address */ 1091121747Sume return(sa6->sin6_addr.s6_addr[2] & 0x0f); 1092121747Sume } 1093121747Sume /* 1094121747Sume * Unicast addresses: map scope type to corresponding scope 1095121747Sume * value defined for multcast addresses. 1096121747Sume * XXX: hardcoded scope type values are bad... 1097121747Sume */ 1098121747Sume if (IN6_IS_ADDR_LOOPBACK(&sa6->sin6_addr)) 1099121747Sume return(1); /* node local scope */ 1100121747Sume if (IN6_IS_ADDR_LINKLOCAL(&sa6->sin6_addr)) 1101121747Sume return(2); /* link-local scope */ 1102121747Sume if (IN6_IS_ADDR_SITELOCAL(&sa6->sin6_addr)) 1103121747Sume return(5); /* site-local scope */ 1104121747Sume return(14); /* global scope */ 1105121747Sume break; 1106121747Sume#endif 1107121747Sume case AF_INET: 1108121747Sume /* 1109121747Sume * IPv4 pseudo scoping according to RFC 3484. 1110121747Sume */ 1111121747Sume sa4 = (struct sockaddr_in *)sa; 1112121747Sume /* IPv4 autoconfiguration addresses have link-local scope. */ 1113121747Sume if (((u_char *)&sa4->sin_addr)[0] == 169 && 1114121747Sume ((u_char *)&sa4->sin_addr)[1] == 254) 1115121747Sume return(2); 1116121747Sume /* Private addresses have site-local scope. */ 1117121747Sume if (((u_char *)&sa4->sin_addr)[0] == 10 || 1118121747Sume (((u_char *)&sa4->sin_addr)[0] == 172 && 1119121747Sume (((u_char *)&sa4->sin_addr)[1] & 0xf0) == 16) || 1120121747Sume (((u_char *)&sa4->sin_addr)[0] == 192 && 1121121747Sume ((u_char *)&sa4->sin_addr)[1] == 168)) 1122129905Sume return(14); /* XXX: It should be 5 unless NAT */ 1123121747Sume /* Loopback addresses have link-local scope. */ 1124121747Sume if (((u_char *)&sa4->sin_addr)[0] == 127) 1125121747Sume return(2); 1126121747Sume return(14); 1127121747Sume break; 1128121747Sume default: 1129121747Sume errno = EAFNOSUPPORT; /* is this a good error? */ 1130121747Sume return(-1); 1131121747Sume } 1132121747Sume} 1133121747Sume 1134190525Sumestatic int 1135190525Sumeexplore_copy(const struct addrinfo *pai, const struct addrinfo *src0, 1136190525Sume struct addrinfo **res) 1137190525Sume{ 1138190525Sume int error; 1139190525Sume struct addrinfo sentinel, *cur; 1140190525Sume const struct addrinfo *src; 1141190525Sume 1142190525Sume error = 0; 1143190525Sume sentinel.ai_next = NULL; 1144190525Sume cur = &sentinel; 1145190525Sume 1146190525Sume for (src = src0; src != NULL; src = src->ai_next) { 1147190525Sume if (src->ai_family != pai->ai_family) 1148190525Sume continue; 1149190525Sume 1150190525Sume cur->ai_next = copy_ai(src); 1151190525Sume if (!cur->ai_next) { 1152190525Sume error = EAI_MEMORY; 1153190525Sume goto fail; 1154190525Sume } 1155190525Sume 1156190525Sume cur->ai_next->ai_socktype = pai->ai_socktype; 1157190525Sume cur->ai_next->ai_protocol = pai->ai_protocol; 1158190525Sume cur = cur->ai_next; 1159190525Sume } 1160190525Sume 1161190525Sume *res = sentinel.ai_next; 1162190525Sume return 0; 1163190525Sume 1164190525Sumefail: 1165190525Sume freeaddrinfo(sentinel.ai_next); 1166190525Sume return error; 1167190525Sume} 1168190525Sume 1169121747Sume/* 117055163Sshin * hostname == NULL. 117155163Sshin * passive socket -> anyaddr (0.0.0.0 or ::) 117255163Sshin * non-passive socket -> localhost (127.0.0.1 or ::1) 117355163Sshin */ 117455163Sshinstatic int 1175157119Sumeexplore_null(const struct addrinfo *pai, const char *servname, 1176157119Sume struct addrinfo **res) 117755163Sshin{ 1178121474Sume int s; 117955163Sshin const struct afd *afd; 1180160551Sume struct addrinfo *ai; 118155163Sshin int error; 118255163Sshin 118355163Sshin *res = NULL; 1184160551Sume ai = NULL; 118555163Sshin 118655163Sshin /* 1187121474Sume * filter out AFs that are not supported by the kernel 1188121474Sume * XXX errno? 1189121474Sume */ 1190255328Sjilles s = _socket(pai->ai_family, SOCK_DGRAM | SOCK_CLOEXEC, 0); 1191121474Sume if (s < 0) { 1192121474Sume if (errno != EMFILE) 1193121474Sume return 0; 1194121474Sume } else 1195121474Sume _close(s); 1196121474Sume 119755163Sshin afd = find_afd(pai->ai_family); 119855163Sshin if (afd == NULL) 119955163Sshin return 0; 120055163Sshin 120161877Sume if (pai->ai_flags & AI_PASSIVE) { 1202160551Sume GET_AI(ai, afd, afd->a_addrany); 1203160551Sume GET_PORT(ai, servname); 120461877Sume } else { 1205160551Sume GET_AI(ai, afd, afd->a_loopback); 1206160551Sume GET_PORT(ai, servname); 120761877Sume } 120855163Sshin 1209160551Sume *res = ai; 121055163Sshin return 0; 121155163Sshin 121255163Sshinfree: 1213160551Sume if (ai != NULL) 1214160551Sume freeaddrinfo(ai); 121555163Sshin return error; 121655163Sshin} 121755163Sshin 121855163Sshin/* 121955163Sshin * numeric hostname 122055163Sshin */ 122155163Sshinstatic int 1222157119Sumeexplore_numeric(const struct addrinfo *pai, const char *hostname, 1223157119Sume const char *servname, struct addrinfo **res, const char *canonname) 122455163Sshin{ 122555163Sshin const struct afd *afd; 1226292722Sume struct addrinfo *ai, ai0; 122755163Sshin int error; 122855163Sshin char pton[PTON_MAX]; 122955163Sshin 123055163Sshin *res = NULL; 1231160551Sume ai = NULL; 123255163Sshin 123355163Sshin afd = find_afd(pai->ai_family); 123455163Sshin if (afd == NULL) 123555163Sshin return 0; 123655163Sshin 123762614Sitojun switch (afd->a_af) { 123862614Sitojun case AF_INET: 1239160552Sume /* 1240160552Sume * RFC3493 requires getaddrinfo() to accept AF_INET formats 1241160552Sume * that are accepted by inet_addr() and its family. The 1242160552Sume * accepted forms includes the "classful" one, which inet_pton 1243160552Sume * does not accept. So we need to separate the case for 1244160552Sume * AF_INET. 1245160552Sume */ 1246327238Sume if (inet_aton(hostname, (struct in_addr *)pton) != 1 || 1247327238Sume hostname[strspn(hostname, "0123456789.xabcdefXABCDEF")] != '\0') 1248160553Sume return 0; 124962614Sitojun break; 125062614Sitojun default: 1251292722Sume if (inet_pton(afd->a_af, hostname, pton) != 1) { 1252292722Sume if (pai->ai_family != AF_INET6 || 1253292722Sume (pai->ai_flags & AI_V4MAPPED) != AI_V4MAPPED) 1254292722Sume return 0; 1255292722Sume if (inet_aton(hostname, (struct in_addr *)pton) != 1) 1256292722Sume return 0; 1257292722Sume afd = &afdl[N_INET]; 1258292722Sume ai0 = *pai; 1259292722Sume ai0.ai_family = AF_INET; 1260292722Sume pai = &ai0; 1261292722Sume } 126262614Sitojun break; 126355163Sshin } 126455163Sshin 1265160553Sume if (pai->ai_family == afd->a_af) { 1266160553Sume GET_AI(ai, afd, pton); 1267160553Sume GET_PORT(ai, servname); 1268160553Sume if ((pai->ai_flags & AI_CANONNAME)) { 1269160553Sume /* 1270160553Sume * Set the numeric address itself as the canonical 1271160553Sume * name, based on a clarification in RFC3493. 1272160553Sume */ 1273160553Sume GET_CANONNAME(ai, canonname); 1274160553Sume } 1275160553Sume } else { 1276160553Sume /* 1277160553Sume * XXX: This should not happen since we already matched the AF 1278160553Sume * by find_afd. 1279160553Sume */ 1280160553Sume ERR(EAI_FAMILY); 1281160553Sume } 1282160553Sume 1283160551Sume *res = ai; 128455163Sshin return 0; 128555163Sshin 128655163Sshinfree: 128755163Sshinbad: 1288160551Sume if (ai != NULL) 1289160551Sume freeaddrinfo(ai); 129055163Sshin return error; 129155163Sshin} 129255163Sshin 129355163Sshin/* 129455163Sshin * numeric hostname with scope 129555163Sshin */ 129655163Sshinstatic int 1297157119Sumeexplore_numeric_scope(const struct addrinfo *pai, const char *hostname, 1298157119Sume const char *servname, struct addrinfo **res) 129955163Sshin{ 130061877Sume#if !defined(SCOPE_DELIMITER) || !defined(INET6) 1301140906Sume return explore_numeric(pai, hostname, servname, res, hostname); 130255163Sshin#else 130355163Sshin const struct afd *afd; 130455163Sshin struct addrinfo *cur; 130555163Sshin int error; 130661877Sume char *cp, *hostname2 = NULL, *scope, *addr; 130755163Sshin struct sockaddr_in6 *sin6; 130855163Sshin 130955163Sshin afd = find_afd(pai->ai_family); 131055163Sshin if (afd == NULL) 131155163Sshin return 0; 131265532Snectar 131355163Sshin if (!afd->a_scoped) 1314140906Sume return explore_numeric(pai, hostname, servname, res, hostname); 131555163Sshin 131655163Sshin cp = strchr(hostname, SCOPE_DELIMITER); 131755163Sshin if (cp == NULL) 1318140906Sume return explore_numeric(pai, hostname, servname, res, hostname); 131955163Sshin 132055163Sshin /* 132155163Sshin * Handle special case of <scoped_address><delimiter><scope id> 132255163Sshin */ 132355163Sshin hostname2 = strdup(hostname); 132455163Sshin if (hostname2 == NULL) 132555163Sshin return EAI_MEMORY; 132655163Sshin /* terminate at the delimiter */ 132755163Sshin hostname2[cp - hostname] = '\0'; 132861877Sume addr = hostname2; 132961877Sume scope = cp + 1; 133055163Sshin 1331140906Sume error = explore_numeric(pai, addr, servname, res, hostname); 133261877Sume if (error == 0) { 1333105943Sume u_int32_t scopeid; 133455163Sshin 133555163Sshin for (cur = *res; cur; cur = cur->ai_next) { 133655163Sshin if (cur->ai_family != AF_INET6) 133755163Sshin continue; 133861877Sume sin6 = (struct sockaddr_in6 *)(void *)cur->ai_addr; 1339105943Sume if (ip6_str2scopeid(scope, sin6, &scopeid) == -1) { 134061877Sume free(hostname2); 1341190525Sume freeaddrinfo(*res); 1342190525Sume *res = NULL; 1343121425Sume return(EAI_NONAME); /* XXX: is return OK? */ 134461877Sume } 134561877Sume sin6->sin6_scope_id = scopeid; 134655163Sshin } 134755163Sshin } 134855163Sshin 134955163Sshin free(hostname2); 135055163Sshin 1351190525Sume if (error && *res) { 1352190525Sume freeaddrinfo(*res); 1353190525Sume *res = NULL; 1354190525Sume } 135555163Sshin return error; 135655163Sshin#endif 135755163Sshin} 135855163Sshin 135955163Sshinstatic int 1360157119Sumeget_canonname(const struct addrinfo *pai, struct addrinfo *ai, const char *str) 136155163Sshin{ 136255163Sshin if ((pai->ai_flags & AI_CANONNAME) != 0) { 1363140947Sume ai->ai_canonname = strdup(str); 136455163Sshin if (ai->ai_canonname == NULL) 136555163Sshin return EAI_MEMORY; 136655163Sshin } 136755163Sshin return 0; 136855163Sshin} 136955163Sshin 137055163Sshinstatic struct addrinfo * 1371157119Sumeget_ai(const struct addrinfo *pai, const struct afd *afd, const char *addr) 137255163Sshin{ 137355163Sshin char *p; 137455163Sshin struct addrinfo *ai; 137555163Sshin#ifdef FAITH 137655163Sshin struct in6_addr faith_prefix; 137755163Sshin char *fp_str; 137855163Sshin int translate = 0; 137955163Sshin#endif 1380292722Sume#ifdef INET6 1381292722Sume struct in6_addr mapaddr; 1382292722Sume#endif 138355163Sshin 138455163Sshin#ifdef FAITH 138555163Sshin /* 138655163Sshin * Transfrom an IPv4 addr into a special IPv6 addr format for 138755163Sshin * IPv6->IPv4 translation gateway. (only TCP is supported now) 138855163Sshin * 138955163Sshin * +-----------------------------------+------------+ 139055163Sshin * | faith prefix part (12 bytes) | embedded | 139155163Sshin * | | IPv4 addr part (4 bytes) 139255163Sshin * +-----------------------------------+------------+ 139355163Sshin * 139455163Sshin * faith prefix part is specified as ascii IPv6 addr format 139555163Sshin * in environmental variable GAI. 139655163Sshin * For FAITH to work correctly, routing to faith prefix must be 139755163Sshin * setup toward a machine where a FAITH daemon operates. 139855163Sshin * Also, the machine must enable some mechanizm 139955163Sshin * (e.g. faith interface hack) to divert those packet with 140055163Sshin * faith prefixed destination addr to user-land FAITH daemon. 140155163Sshin */ 140255163Sshin fp_str = getenv("GAI"); 140355163Sshin if (fp_str && inet_pton(AF_INET6, fp_str, &faith_prefix) == 1 && 140455163Sshin afd->a_af == AF_INET && pai->ai_socktype == SOCK_STREAM) { 140555163Sshin u_int32_t v4a; 140655163Sshin u_int8_t v4a_top; 140755163Sshin 140855163Sshin memcpy(&v4a, addr, sizeof v4a); 140955163Sshin v4a_top = v4a >> IN_CLASSA_NSHIFT; 141055163Sshin if (!IN_MULTICAST(v4a) && !IN_EXPERIMENTAL(v4a) && 141155163Sshin v4a_top != 0 && v4a != IN_LOOPBACKNET) { 141255163Sshin afd = &afdl[N_INET6]; 141355163Sshin memcpy(&faith_prefix.s6_addr[12], addr, 141455163Sshin sizeof(struct in_addr)); 141555163Sshin translate = 1; 141655163Sshin } 141755163Sshin } 141855163Sshin#endif 141955163Sshin 1420292722Sume#ifdef INET6 1421292722Sume if (afd->a_af == AF_INET && (pai->ai_flags & AI_V4MAPPED) != 0) { 1422292722Sume afd = &afdl[N_INET6]; 1423292722Sume _map_v4v6_address(addr, (char *)&mapaddr); 1424292722Sume addr = (char *)&mapaddr; 1425292722Sume } 1426292722Sume#endif 1427292722Sume 142855163Sshin ai = (struct addrinfo *)malloc(sizeof(struct addrinfo) 142955163Sshin + (afd->a_socklen)); 143055163Sshin if (ai == NULL) 143155163Sshin return NULL; 143255163Sshin 143355163Sshin memcpy(ai, pai, sizeof(struct addrinfo)); 143461877Sume ai->ai_addr = (struct sockaddr *)(void *)(ai + 1); 143561877Sume memset(ai->ai_addr, 0, (size_t)afd->a_socklen); 143655163Sshin ai->ai_addr->sa_len = afd->a_socklen; 143755163Sshin ai->ai_addrlen = afd->a_socklen; 143855163Sshin ai->ai_addr->sa_family = ai->ai_family = afd->a_af; 143965532Snectar p = (char *)(void *)(ai->ai_addr); 144055163Sshin#ifdef FAITH 144155163Sshin if (translate == 1) 144265532Snectar memcpy(p + afd->a_off, &faith_prefix, (size_t)afd->a_addrlen); 144355163Sshin else 144455163Sshin#endif 144565532Snectar memcpy(p + afd->a_off, addr, (size_t)afd->a_addrlen); 144655163Sshin return ai; 144755163Sshin} 144855163Sshin 1449190525Sume/* XXX need to malloc() the same way we do from other functions! */ 1450190525Sumestatic struct addrinfo * 1451190525Sumecopy_ai(const struct addrinfo *pai) 1452190525Sume{ 1453190525Sume struct addrinfo *ai; 1454190525Sume size_t l; 1455190525Sume 1456190525Sume l = sizeof(*ai) + pai->ai_addrlen; 1457311718Sngie if ((ai = calloc(1, l)) == NULL) 1458190525Sume return NULL; 1459190525Sume memcpy(ai, pai, sizeof(*ai)); 1460190525Sume ai->ai_addr = (struct sockaddr *)(void *)(ai + 1); 1461190525Sume memcpy(ai->ai_addr, pai->ai_addr, pai->ai_addrlen); 1462190525Sume 1463190525Sume if (pai->ai_canonname) { 1464190525Sume l = strlen(pai->ai_canonname) + 1; 1465190525Sume if ((ai->ai_canonname = malloc(l)) == NULL) { 1466190525Sume free(ai); 1467190525Sume return NULL; 1468190525Sume } 1469190525Sume strlcpy(ai->ai_canonname, pai->ai_canonname, l); 1470190525Sume } else { 1471190525Sume /* just to make sure */ 1472190525Sume ai->ai_canonname = NULL; 1473190525Sume } 1474190525Sume 1475190525Sume ai->ai_next = NULL; 1476190525Sume 1477190525Sume return ai; 1478190525Sume} 1479190525Sume 148055163Sshinstatic int 1481157119Sumeget_portmatch(const struct addrinfo *ai, const char *servname) 148255163Sshin{ 148361877Sume 1484140908Sume /* get_port does not touch first argument when matchonly == 1. */ 148561877Sume /* LINTED const cast */ 148655163Sshin return get_port((struct addrinfo *)ai, servname, 1); 148755163Sshin} 148855163Sshin 148955163Sshinstatic int 1490157119Sumeget_port(struct addrinfo *ai, const char *servname, int matchonly) 149155163Sshin{ 149255163Sshin const char *proto; 149355163Sshin struct servent *sp; 1494160593Sume int port, error; 149555163Sshin int allownumeric; 149655163Sshin 149755163Sshin if (servname == NULL) 149855163Sshin return 0; 149961877Sume switch (ai->ai_family) { 150061877Sume case AF_INET: 150161877Sume#ifdef AF_INET6 150261877Sume case AF_INET6: 150355163Sshin#endif 150461877Sume break; 150561877Sume default: 150655163Sshin return 0; 150761877Sume } 150855163Sshin 150955163Sshin switch (ai->ai_socktype) { 151055163Sshin case SOCK_RAW: 151155163Sshin return EAI_SERVICE; 151255163Sshin case SOCK_DGRAM: 151355163Sshin case SOCK_STREAM: 1514190416Sume case SOCK_SEQPACKET: 151555163Sshin allownumeric = 1; 151655163Sshin break; 151755163Sshin case ANY: 1518190382Sume switch (ai->ai_family) { 1519190382Sume case AF_INET: 1520190382Sume#ifdef AF_INET6 1521190382Sume case AF_INET6: 1522190382Sume#endif 1523190382Sume allownumeric = 1; 1524190382Sume break; 1525190382Sume default: 1526190382Sume allownumeric = 0; 1527190382Sume break; 1528190382Sume } 152955163Sshin break; 153055163Sshin default: 153155163Sshin return EAI_SOCKTYPE; 153255163Sshin } 153355163Sshin 1534160593Sume error = str2number(servname, &port); 1535160593Sume if (error == 0) { 153655163Sshin if (!allownumeric) 153755163Sshin return EAI_SERVICE; 153855163Sshin if (port < 0 || port > 65535) 153955163Sshin return EAI_SERVICE; 1540105940Sume port = htons(port); 154155163Sshin } else { 1542140908Sume if (ai->ai_flags & AI_NUMERICSERV) 1543140908Sume return EAI_NONAME; 1544190416Sume 1545190416Sume switch (ai->ai_protocol) { 1546190416Sume case IPPROTO_UDP: 154755163Sshin proto = "udp"; 154855163Sshin break; 1549190416Sume case IPPROTO_TCP: 155055163Sshin proto = "tcp"; 155155163Sshin break; 1552190416Sume case IPPROTO_SCTP: 1553190416Sume proto = "sctp"; 1554190416Sume break; 1555265946Skevlo case IPPROTO_UDPLITE: 1556265946Skevlo proto = "udplite"; 1557265946Skevlo break; 155855163Sshin default: 155955163Sshin proto = NULL; 156055163Sshin break; 156155163Sshin } 156255163Sshin 1563145118Sume if ((sp = getservbyname(servname, proto)) == NULL) 156455163Sshin return EAI_SERVICE; 156555163Sshin port = sp->s_port; 156655163Sshin } 156755163Sshin 156855163Sshin if (!matchonly) { 156955163Sshin switch (ai->ai_family) { 157055163Sshin case AF_INET: 157161877Sume ((struct sockaddr_in *)(void *) 157261877Sume ai->ai_addr)->sin_port = port; 157355163Sshin break; 157455163Sshin#ifdef INET6 157555163Sshin case AF_INET6: 157661877Sume ((struct sockaddr_in6 *)(void *) 157761877Sume ai->ai_addr)->sin6_port = port; 157855163Sshin break; 157955163Sshin#endif 158055163Sshin } 158155163Sshin } 158255163Sshin 158355163Sshin return 0; 158455163Sshin} 158555163Sshin 158655163Sshinstatic const struct afd * 1587157119Sumefind_afd(int af) 158855163Sshin{ 158955163Sshin const struct afd *afd; 159055163Sshin 159155163Sshin if (af == PF_UNSPEC) 159255163Sshin return NULL; 159355163Sshin for (afd = afdl; afd->a_af; afd++) { 159455163Sshin if (afd->a_af == af) 159555163Sshin return afd; 159655163Sshin } 159755163Sshin return NULL; 159855163Sshin} 159961877Sume 160061877Sume/* 1601268216Sume * RFC 3493: AI_ADDRCONFIG check. Determines which address families are 1602267874Sume * configured on the local system and correlates with pai->ai_family value. 1603267874Sume * If an address family is not configured on the system, it will not be 1604267874Sume * queried for. For this purpose, loopback addresses are not considered 1605267874Sume * configured addresses. 1606121474Sume * 1607121474Sume * XXX PF_UNSPEC -> PF_INET6 + PF_INET mapping needs to be in sync with 1608121474Sume * _dns_getaddrinfo. 160961877Sume */ 161061877Sumestatic int 1611157119Sumeaddrconfig(struct addrinfo *pai) 161261877Sume{ 1613267874Sume struct ifaddrs *ifaddrs, *ifa; 1614268216Sume struct sockaddr_in *sin; 1615268216Sume#ifdef INET6 1616268216Sume struct sockaddr_in6 *sin6; 1617268216Sume#endif 1618267874Sume int seen_inet = 0, seen_inet6 = 0; 161961877Sume 1620267874Sume if (getifaddrs(&ifaddrs) != 0) 1621268216Sume return (0); 1622267874Sume 1623267874Sume for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) { 1624267874Sume if (ifa->ifa_addr == NULL || (ifa->ifa_flags & IFF_UP) == 0) 1625267874Sume continue; 1626267874Sume switch (ifa->ifa_addr->sa_family) { 1627267874Sume case AF_INET: 1628268216Sume if (seen_inet) 1629268216Sume continue; 1630268216Sume sin = (struct sockaddr_in *)(ifa->ifa_addr); 1631292456Sume if (htonl(sin->sin_addr.s_addr) == INADDR_LOOPBACK) 1632268216Sume continue; 1633267874Sume seen_inet = 1; 1634267874Sume break; 1635267874Sume#ifdef INET6 1636267874Sume case AF_INET6: 1637268216Sume if (seen_inet6) 1638268216Sume continue; 1639268216Sume sin6 = (struct sockaddr_in6 *)(ifa->ifa_addr); 1640268216Sume if (IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr)) 1641268216Sume continue; 1642268216Sume if ((ifa->ifa_flags & IFT_LOOP) != 0 && 1643268216Sume IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) 1644268216Sume continue; 1645268216Sume if (is_ifdisabled(ifa->ifa_name)) 1646268216Sume continue; 1647268216Sume seen_inet6 = 1; 1648267874Sume break; 1649267874Sume#endif 1650121474Sume } 1651121474Sume } 1652267874Sume freeifaddrs(ifaddrs); 1653267874Sume 1654267874Sume switch(pai->ai_family) { 1655267874Sume case AF_INET6: 1656268216Sume return (seen_inet6); 1657267874Sume case AF_INET: 1658268216Sume return (seen_inet); 1659267874Sume case AF_UNSPEC: 1660267874Sume if (seen_inet == seen_inet6) 1661268216Sume return (seen_inet); 1662267874Sume pai->ai_family = seen_inet ? AF_INET : AF_INET6; 1663268216Sume return (1); 1664121474Sume } 1665268216Sume return (1); 166661877Sume} 166761877Sume 166861877Sume#ifdef INET6 1669267874Sumestatic int 1670267874Sumeis_ifdisabled(char *name) 1671267874Sume{ 1672267874Sume struct in6_ndireq nd; 1673267874Sume int fd; 1674267874Sume 1675267874Sume if ((fd = _socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0)) < 0) 1676268216Sume return (-1); 1677267874Sume memset(&nd, 0, sizeof(nd)); 1678267874Sume strlcpy(nd.ifname, name, sizeof(nd.ifname)); 1679267874Sume if (_ioctl(fd, SIOCGIFINFO_IN6, &nd) < 0) { 1680267874Sume _close(fd); 1681268216Sume return (-1); 1682267874Sume } 1683267874Sume _close(fd); 1684267874Sume return ((nd.ndi.flags & ND6_IFF_IFDISABLED) != 0); 1685267874Sume} 1686267874Sume 168761877Sume/* convert a string to a scope identifier. XXX: IPv6 specific */ 168861877Sumestatic int 1689157119Sumeip6_str2scopeid(char *scope, struct sockaddr_in6 *sin6, u_int32_t *scopeid) 169061877Sume{ 1691105943Sume u_long lscopeid; 1692121474Sume struct in6_addr *a6; 169361877Sume char *ep; 169461877Sume 1695121474Sume a6 = &sin6->sin6_addr; 1696121474Sume 169762836Sitojun /* empty scopeid portion is invalid */ 169862836Sitojun if (*scope == '\0') 169962836Sitojun return -1; 170062836Sitojun 1701229766Sume if (IN6_IS_ADDR_LINKLOCAL(a6) || IN6_IS_ADDR_MC_LINKLOCAL(a6) || 1702229766Sume IN6_IS_ADDR_MC_NODELOCAL(a6)) { 170361877Sume /* 170461877Sume * We currently assume a one-to-one mapping between links 170561877Sume * and interfaces, so we simply use interface indices for 170661877Sume * like-local scopes. 170761877Sume */ 1708105943Sume *scopeid = if_nametoindex(scope); 1709105943Sume if (*scopeid == 0) 171061877Sume goto trynumeric; 1711105943Sume return 0; 171261877Sume } 171361877Sume 171461877Sume /* still unclear about literal, allow numeric only - placeholder */ 171561877Sume if (IN6_IS_ADDR_SITELOCAL(a6) || IN6_IS_ADDR_MC_SITELOCAL(a6)) 171661877Sume goto trynumeric; 171761877Sume if (IN6_IS_ADDR_MC_ORGLOCAL(a6)) 171861877Sume goto trynumeric; 171961877Sume else 172061877Sume goto trynumeric; /* global */ 172161877Sume 172261877Sume /* try to convert to a numeric id as a last resort */ 1723121474Sume trynumeric: 1724105943Sume errno = 0; 1725105943Sume lscopeid = strtoul(scope, &ep, 10); 1726105943Sume *scopeid = (u_int32_t)(lscopeid & 0xffffffffUL); 1727105943Sume if (errno == 0 && ep && *ep == '\0' && *scopeid == lscopeid) 1728105943Sume return 0; 172961877Sume else 173061877Sume return -1; 173161877Sume} 173261877Sume#endif 173361877Sume 1734158115Sume 1735158115Sume#ifdef NS_CACHING 1736158115Sumestatic int 1737158115Sumeaddrinfo_id_func(char *buffer, size_t *buffer_size, va_list ap, 1738158115Sume void *cache_mdata) 1739158115Sume{ 1740158115Sume res_state statp; 1741158115Sume u_long res_options; 1742158115Sume 1743158115Sume const int op_id = 0; /* identifies the getaddrinfo for the cache */ 1744158115Sume char *hostname; 1745158115Sume struct addrinfo *hints; 1746158115Sume 1747158115Sume char *p; 1748158115Sume int ai_flags, ai_family, ai_socktype, ai_protocol; 1749158115Sume size_t desired_size, size; 1750158115Sume 1751158115Sume statp = __res_state(); 1752158115Sume res_options = statp->options & (RES_RECURSE | RES_DEFNAMES | 1753158115Sume RES_DNSRCH | RES_NOALIASES | RES_USE_INET6); 1754158115Sume 1755158115Sume hostname = va_arg(ap, char *); 1756158115Sume hints = va_arg(ap, struct addrinfo *); 1757158115Sume 1758158115Sume desired_size = sizeof(res_options) + sizeof(int) + sizeof(int) * 4; 1759158115Sume if (hostname != NULL) { 1760158115Sume size = strlen(hostname); 1761158115Sume desired_size += size + 1; 1762158115Sume } else 1763158115Sume size = 0; 1764158115Sume 1765158115Sume if (desired_size > *buffer_size) { 1766158115Sume *buffer_size = desired_size; 1767158115Sume return (NS_RETURN); 1768158115Sume } 1769158115Sume 1770158115Sume if (hints == NULL) 1771158115Sume ai_flags = ai_family = ai_socktype = ai_protocol = 0; 1772158115Sume else { 1773158115Sume ai_flags = hints->ai_flags; 1774158115Sume ai_family = hints->ai_family; 1775158115Sume ai_socktype = hints->ai_socktype; 1776158115Sume ai_protocol = hints->ai_protocol; 1777158115Sume } 1778158115Sume 1779158115Sume p = buffer; 1780158115Sume memcpy(p, &res_options, sizeof(res_options)); 1781158115Sume p += sizeof(res_options); 1782158115Sume 1783158115Sume memcpy(p, &op_id, sizeof(int)); 1784158115Sume p += sizeof(int); 1785158115Sume 1786158115Sume memcpy(p, &ai_flags, sizeof(int)); 1787158115Sume p += sizeof(int); 1788158115Sume 1789158115Sume memcpy(p, &ai_family, sizeof(int)); 1790158115Sume p += sizeof(int); 1791158115Sume 1792158115Sume memcpy(p, &ai_socktype, sizeof(int)); 1793158115Sume p += sizeof(int); 1794158115Sume 1795158115Sume memcpy(p, &ai_protocol, sizeof(int)); 1796158115Sume p += sizeof(int); 1797158115Sume 1798158115Sume if (hostname != NULL) 1799158115Sume memcpy(p, hostname, size); 1800158115Sume 1801158115Sume *buffer_size = desired_size; 1802158115Sume return (NS_SUCCESS); 1803158115Sume} 1804158115Sume 1805158115Sumestatic int 1806158115Sumeaddrinfo_marshal_func(char *buffer, size_t *buffer_size, void *retval, 1807158115Sume va_list ap, void *cache_mdata) 1808158115Sume{ 1809158115Sume struct addrinfo *ai, *cai; 1810158115Sume char *p; 1811158115Sume size_t desired_size, size, ai_size; 1812158115Sume 1813158115Sume ai = *((struct addrinfo **)retval); 1814158115Sume 1815158115Sume desired_size = sizeof(size_t); 1816158115Sume ai_size = 0; 1817158115Sume for (cai = ai; cai != NULL; cai = cai->ai_next) { 1818158115Sume desired_size += sizeof(struct addrinfo) + cai->ai_addrlen; 1819158115Sume if (cai->ai_canonname != NULL) 1820158115Sume desired_size += sizeof(size_t) + 1821158115Sume strlen(cai->ai_canonname); 1822158115Sume ++ai_size; 1823158115Sume } 1824158115Sume 1825158115Sume if (desired_size > *buffer_size) { 1826158115Sume /* this assignment is here for future use */ 1827158115Sume errno = ERANGE; 1828158115Sume *buffer_size = desired_size; 1829158115Sume return (NS_RETURN); 1830158115Sume } 1831158115Sume 1832158115Sume memset(buffer, 0, desired_size); 1833158115Sume p = buffer; 1834158115Sume 1835158115Sume memcpy(p, &ai_size, sizeof(size_t)); 1836158115Sume p += sizeof(size_t); 1837158115Sume for (cai = ai; cai != NULL; cai = cai->ai_next) { 1838158115Sume memcpy(p, cai, sizeof(struct addrinfo)); 1839158115Sume p += sizeof(struct addrinfo); 1840158115Sume 1841158115Sume memcpy(p, cai->ai_addr, cai->ai_addrlen); 1842158115Sume p += cai->ai_addrlen; 1843158115Sume 1844158115Sume if (cai->ai_canonname != NULL) { 1845158115Sume size = strlen(cai->ai_canonname); 1846158115Sume memcpy(p, &size, sizeof(size_t)); 1847158115Sume p += sizeof(size_t); 1848158115Sume 1849158115Sume memcpy(p, cai->ai_canonname, size); 1850158115Sume p += size; 1851158115Sume } 1852158115Sume } 1853158115Sume 1854158115Sume return (NS_SUCCESS); 1855158115Sume} 1856158115Sume 1857158115Sumestatic int 1858158115Sumeaddrinfo_unmarshal_func(char *buffer, size_t buffer_size, void *retval, 1859158115Sume va_list ap, void *cache_mdata) 1860158115Sume{ 1861158115Sume struct addrinfo new_ai, *result, *sentinel, *lasts; 1862158115Sume 1863158115Sume char *p; 1864158115Sume size_t ai_size, ai_i, size; 1865158115Sume 1866158115Sume p = buffer; 1867158115Sume memcpy(&ai_size, p, sizeof(size_t)); 1868158115Sume p += sizeof(size_t); 1869158115Sume 1870158115Sume result = NULL; 1871158115Sume lasts = NULL; 1872158115Sume for (ai_i = 0; ai_i < ai_size; ++ai_i) { 1873158115Sume memcpy(&new_ai, p, sizeof(struct addrinfo)); 1874158115Sume p += sizeof(struct addrinfo); 1875158115Sume size = new_ai.ai_addrlen + sizeof(struct addrinfo) + 1876158115Sume _ALIGNBYTES; 1877158115Sume 1878311718Sngie sentinel = calloc(1, size); 1879158115Sume 1880158115Sume memcpy(sentinel, &new_ai, sizeof(struct addrinfo)); 1881158115Sume sentinel->ai_addr = (struct sockaddr *)_ALIGN((char *)sentinel + 1882158115Sume sizeof(struct addrinfo)); 1883158115Sume 1884158115Sume memcpy(sentinel->ai_addr, p, new_ai.ai_addrlen); 1885158115Sume p += new_ai.ai_addrlen; 1886158115Sume 1887158115Sume if (new_ai.ai_canonname != NULL) { 1888158115Sume memcpy(&size, p, sizeof(size_t)); 1889158115Sume p += sizeof(size_t); 1890158115Sume 1891311718Sngie sentinel->ai_canonname = calloc(1, size + 1); 1892158115Sume 1893158115Sume memcpy(sentinel->ai_canonname, p, size); 1894158115Sume p += size; 1895158115Sume } 1896158115Sume 1897158115Sume if (result == NULL) { 1898158115Sume result = sentinel; 1899158115Sume lasts = sentinel; 1900158115Sume } else { 1901158115Sume lasts->ai_next = sentinel; 1902158115Sume lasts = sentinel; 1903158115Sume } 1904158115Sume } 1905158115Sume 1906158115Sume *((struct addrinfo **)retval) = result; 1907158115Sume return (NS_SUCCESS); 1908158115Sume} 1909158115Sume#endif /* NS_CACHING */ 1910158115Sume 1911121426Sume/* 1912121426Sume * FQDN hostname, DNS lookup 1913121426Sume */ 1914102237Spirzykstatic int 1915157119Sumeexplore_fqdn(const struct addrinfo *pai, const char *hostname, 1916157119Sume const char *servname, struct addrinfo **res) 1917102237Spirzyk{ 1918121426Sume struct addrinfo *result; 1919121426Sume struct addrinfo *cur; 1920121426Sume int error = 0; 1921158115Sume 1922158115Sume#ifdef NS_CACHING 1923158115Sume static const nss_cache_info cache_info = 1924158115Sume NS_COMMON_CACHE_INFO_INITIALIZER( 1925158115Sume hosts, NULL, addrinfo_id_func, addrinfo_marshal_func, 1926158115Sume addrinfo_unmarshal_func); 1927158115Sume#endif 1928121426Sume static const ns_dtab dtab[] = { 1929121426Sume NS_FILES_CB(_files_getaddrinfo, NULL) 1930121426Sume { NSSRC_DNS, _dns_getaddrinfo, NULL }, /* force -DHESIOD */ 1931121426Sume NS_NIS_CB(_yp_getaddrinfo, NULL) 1932158115Sume#ifdef NS_CACHING 1933158115Sume NS_CACHE_CB(&cache_info) 1934158115Sume#endif 1935121426Sume { 0 } 1936121426Sume }; 1937102237Spirzyk 1938121426Sume result = NULL; 1939121426Sume 1940121426Sume /* 1941121426Sume * if the servname does not match socktype/protocol, ignore it. 1942121426Sume */ 1943126243Sgreen if (get_portmatch(pai, servname) != 0) 1944102237Spirzyk return 0; 1945102237Spirzyk 1946121426Sume switch (_nsdispatch(&result, dtab, NSDB_HOSTS, "getaddrinfo", 1947121426Sume default_dns_files, hostname, pai)) { 1948121426Sume case NS_TRYAGAIN: 1949121426Sume error = EAI_AGAIN; 1950121426Sume goto free; 1951121426Sume case NS_UNAVAIL: 1952121426Sume error = EAI_FAIL; 1953121426Sume goto free; 1954121426Sume case NS_NOTFOUND: 1955121426Sume error = EAI_NONAME; 1956121426Sume goto free; 1957121426Sume case NS_SUCCESS: 1958121426Sume error = 0; 1959121426Sume for (cur = result; cur; cur = cur->ai_next) { 1960121426Sume GET_PORT(cur, servname); 1961121426Sume /* canonname should be filled already */ 1962121426Sume } 1963121426Sume break; 1964102237Spirzyk } 1965102237Spirzyk 1966121426Sume *res = result; 1967121426Sume 1968102237Spirzyk return 0; 1969121426Sume 1970121426Sumefree: 1971121426Sume if (result) 1972121426Sume freeaddrinfo(result); 1973121426Sume return error; 1974102237Spirzyk} 1975102237Spirzyk 197661877Sume#ifdef DEBUG 197761877Sumestatic const char AskedForGot[] = 197861877Sume "gethostby*.getanswer: asked for \"%s\", got \"%s\""; 197961877Sume#endif 198061877Sume 198161877Sumestatic struct addrinfo * 1982157119Sumegetanswer(const querybuf *answer, int anslen, const char *qname, int qtype, 1983157119Sume const struct addrinfo *pai, res_state res) 198461877Sume{ 198561877Sume struct addrinfo sentinel, *cur; 198661877Sume struct addrinfo ai; 198761877Sume const struct afd *afd; 198861877Sume char *canonname; 198961877Sume const HEADER *hp; 199061877Sume const u_char *cp; 199161877Sume int n; 199261877Sume const u_char *eom; 1993105940Sume char *bp, *ep; 1994105940Sume int type, class, ancount, qdcount; 199561877Sume int haveanswer, had_error; 199661877Sume char tbuf[MAXDNAME]; 199792905Sobrien int (*name_ok)(const char *); 199861877Sume char hostbuf[8*1024]; 199961877Sume 200061877Sume memset(&sentinel, 0, sizeof(sentinel)); 200161877Sume cur = &sentinel; 200261877Sume 200361877Sume canonname = NULL; 200461877Sume eom = answer->buf + anslen; 200561877Sume switch (qtype) { 200661877Sume case T_A: 200761877Sume case T_AAAA: 200861877Sume case T_ANY: /*use T_ANY only for T_A/T_AAAA lookup*/ 200961877Sume name_ok = res_hnok; 201061877Sume break; 201161877Sume default: 201261877Sume return (NULL); /* XXX should be abort(); */ 201361877Sume } 201461877Sume /* 201561877Sume * find first satisfactory answer 201661877Sume */ 201761877Sume hp = &answer->hdr; 201861877Sume ancount = ntohs(hp->ancount); 201961877Sume qdcount = ntohs(hp->qdcount); 202061877Sume bp = hostbuf; 2021105940Sume ep = hostbuf + sizeof hostbuf; 202261877Sume cp = answer->buf + HFIXEDSZ; 202361877Sume if (qdcount != 1) { 2024156960Sume RES_SET_H_ERRNO(res, NO_RECOVERY); 202561877Sume return (NULL); 202661877Sume } 2027105940Sume n = dn_expand(answer->buf, eom, cp, bp, ep - bp); 202861877Sume if ((n < 0) || !(*name_ok)(bp)) { 2029156960Sume RES_SET_H_ERRNO(res, NO_RECOVERY); 203061877Sume return (NULL); 203161877Sume } 203261877Sume cp += n + QFIXEDSZ; 203361877Sume if (qtype == T_A || qtype == T_AAAA || qtype == T_ANY) { 203461877Sume /* res_send() has already verified that the query name is the 203561877Sume * same as the one we sent; this just gets the expanded name 203661877Sume * (i.e., with the succeeding search-domain tacked on). 203761877Sume */ 203861877Sume n = strlen(bp) + 1; /* for the \0 */ 203961877Sume if (n >= MAXHOSTNAMELEN) { 2040156960Sume RES_SET_H_ERRNO(res, NO_RECOVERY); 204161877Sume return (NULL); 204261877Sume } 204361877Sume canonname = bp; 204461877Sume bp += n; 204561877Sume /* The qname can be abbreviated, but h_name is now absolute. */ 204661877Sume qname = canonname; 204761877Sume } 204861877Sume haveanswer = 0; 204961877Sume had_error = 0; 205061877Sume while (ancount-- > 0 && cp < eom && !had_error) { 2051105940Sume n = dn_expand(answer->buf, eom, cp, bp, ep - bp); 205261877Sume if ((n < 0) || !(*name_ok)(bp)) { 205361877Sume had_error++; 205461877Sume continue; 205561877Sume } 205661877Sume cp += n; /* name */ 205761877Sume type = _getshort(cp); 205861877Sume cp += INT16SZ; /* type */ 205961877Sume class = _getshort(cp); 206061877Sume cp += INT16SZ + INT32SZ; /* class, TTL */ 206161877Sume n = _getshort(cp); 206261877Sume cp += INT16SZ; /* len */ 206361877Sume if (class != C_IN) { 206461877Sume /* XXX - debug? syslog? */ 206561877Sume cp += n; 206661877Sume continue; /* XXX - had_error++ ? */ 206761877Sume } 206861877Sume if ((qtype == T_A || qtype == T_AAAA || qtype == T_ANY) && 206961877Sume type == T_CNAME) { 207061877Sume n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf); 207161877Sume if ((n < 0) || !(*name_ok)(tbuf)) { 207261877Sume had_error++; 207361877Sume continue; 207461877Sume } 207561877Sume cp += n; 207661877Sume /* Get canonical name. */ 207761877Sume n = strlen(tbuf) + 1; /* for the \0 */ 2078105940Sume if (n > ep - bp || n >= MAXHOSTNAMELEN) { 207961877Sume had_error++; 208061877Sume continue; 208161877Sume } 2082114443Snectar strlcpy(bp, tbuf, ep - bp); 208361877Sume canonname = bp; 208461877Sume bp += n; 208561877Sume continue; 208661877Sume } 208761877Sume if (qtype == T_ANY) { 208861877Sume if (!(type == T_A || type == T_AAAA)) { 208961877Sume cp += n; 209061877Sume continue; 209161877Sume } 209261877Sume } else if (type != qtype) { 209361877Sume#ifdef DEBUG 2094188316Sume if (type != T_KEY && type != T_SIG && 2095188316Sume type != ns_t_dname) 209661877Sume syslog(LOG_NOTICE|LOG_AUTH, 209761877Sume "gethostby*.getanswer: asked for \"%s %s %s\", got type \"%s\"", 209861877Sume qname, p_class(C_IN), p_type(qtype), 209961877Sume p_type(type)); 210061877Sume#endif 210161877Sume cp += n; 210261877Sume continue; /* XXX - had_error++ ? */ 210361877Sume } 210461877Sume switch (type) { 210561877Sume case T_A: 210661877Sume case T_AAAA: 210761877Sume if (strcasecmp(canonname, bp) != 0) { 210861877Sume#ifdef DEBUG 210961877Sume syslog(LOG_NOTICE|LOG_AUTH, 211061877Sume AskedForGot, canonname, bp); 211161877Sume#endif 211261877Sume cp += n; 211361877Sume continue; /* XXX - had_error++ ? */ 211461877Sume } 211561877Sume if (type == T_A && n != INADDRSZ) { 211661877Sume cp += n; 211761877Sume continue; 211861877Sume } 211961877Sume if (type == T_AAAA && n != IN6ADDRSZ) { 212061877Sume cp += n; 212161877Sume continue; 212261877Sume } 212361877Sume#ifdef FILTER_V4MAPPED 212461877Sume if (type == T_AAAA) { 212561877Sume struct in6_addr in6; 212661877Sume memcpy(&in6, cp, sizeof(in6)); 212761877Sume if (IN6_IS_ADDR_V4MAPPED(&in6)) { 212861877Sume cp += n; 212961877Sume continue; 213061877Sume } 213161877Sume } 213261877Sume#endif 213361877Sume if (!haveanswer) { 213461877Sume int nn; 213561877Sume 213661877Sume canonname = bp; 213761877Sume nn = strlen(bp) + 1; /* for the \0 */ 213861877Sume bp += nn; 213961877Sume } 214061877Sume 214161877Sume /* don't overwrite pai */ 214261877Sume ai = *pai; 214361877Sume ai.ai_family = (type == T_A) ? AF_INET : AF_INET6; 214461877Sume afd = find_afd(ai.ai_family); 214561877Sume if (afd == NULL) { 214661877Sume cp += n; 214761877Sume continue; 214861877Sume } 214961877Sume cur->ai_next = get_ai(&ai, afd, (const char *)cp); 215061877Sume if (cur->ai_next == NULL) 215161877Sume had_error++; 215261877Sume while (cur && cur->ai_next) 215361877Sume cur = cur->ai_next; 215461877Sume cp += n; 215561877Sume break; 215661877Sume default: 215761877Sume abort(); 215861877Sume } 215961877Sume if (!had_error) 216061877Sume haveanswer++; 216161877Sume } 216261877Sume if (haveanswer) { 2163102237Spirzyk#if defined(RESOLVSORT) 2164102237Spirzyk /* 2165102237Spirzyk * We support only IPv4 address for backward 2166102237Spirzyk * compatibility against gethostbyname(3). 2167102237Spirzyk */ 2168156960Sume if (res->nsort && qtype == T_A) { 2169156960Sume if (addr4sort(&sentinel, res) < 0) { 2170102237Spirzyk freeaddrinfo(sentinel.ai_next); 2171156960Sume RES_SET_H_ERRNO(res, NO_RECOVERY); 2172102237Spirzyk return NULL; 2173102237Spirzyk } 2174102237Spirzyk } 2175102237Spirzyk#endif /*RESOLVSORT*/ 217661877Sume if (!canonname) 217761877Sume (void)get_canonname(pai, sentinel.ai_next, qname); 217861877Sume else 217961877Sume (void)get_canonname(pai, sentinel.ai_next, canonname); 2180156960Sume RES_SET_H_ERRNO(res, NETDB_SUCCESS); 218161877Sume return sentinel.ai_next; 218261877Sume } 218361877Sume 2184292824Sume /* 2185292824Sume * We could have walked a CNAME chain, but the ultimate target 2186292824Sume * may not have what we looked for. 2187292824Sume */ 2188292824Sume RES_SET_H_ERRNO(res, ntohs(hp->ancount) > 0 ? NO_DATA : NO_RECOVERY); 218961877Sume return NULL; 219061877Sume} 219161877Sume 2192121426Sume#ifdef RESOLVSORT 2193121426Sumestruct addr_ptr { 2194121426Sume struct addrinfo *ai; 2195121426Sume int aval; 2196121426Sume}; 2197121426Sume 2198121426Sumestatic int 2199156960Sumeaddr4sort(struct addrinfo *sentinel, res_state res) 2200121426Sume{ 2201121426Sume struct addrinfo *ai; 2202121426Sume struct addr_ptr *addrs, addr; 2203121426Sume struct sockaddr_in *sin; 2204121426Sume int naddrs, i, j; 2205121426Sume int needsort = 0; 2206121426Sume 2207121426Sume if (!sentinel) 2208121426Sume return -1; 2209121426Sume naddrs = 0; 2210121426Sume for (ai = sentinel->ai_next; ai; ai = ai->ai_next) 2211121426Sume naddrs++; 2212121426Sume if (naddrs < 2) 2213121426Sume return 0; /* We don't need sorting. */ 2214121426Sume if ((addrs = malloc(sizeof(struct addr_ptr) * naddrs)) == NULL) 2215121426Sume return -1; 2216121426Sume i = 0; 2217121426Sume for (ai = sentinel->ai_next; ai; ai = ai->ai_next) { 2218121426Sume sin = (struct sockaddr_in *)ai->ai_addr; 2219156960Sume for (j = 0; (unsigned)j < res->nsort; j++) { 2220157119Sume if (res->sort_list[j].addr.s_addr == 2221156960Sume (sin->sin_addr.s_addr & res->sort_list[j].mask)) 2222121426Sume break; 2223121426Sume } 2224121426Sume addrs[i].ai = ai; 2225121426Sume addrs[i].aval = j; 2226121426Sume if (needsort == 0 && i > 0 && j < addrs[i - 1].aval) 2227121426Sume needsort = i; 2228121426Sume i++; 2229121426Sume } 2230121426Sume if (!needsort) { 2231121426Sume free(addrs); 2232121426Sume return 0; 2233121426Sume } 2234121426Sume 2235121426Sume while (needsort < naddrs) { 2236157371Sume for (j = needsort - 1; j >= 0; j--) { 2237157371Sume if (addrs[j].aval > addrs[j+1].aval) { 2238157371Sume addr = addrs[j]; 2239157371Sume addrs[j] = addrs[j + 1]; 2240157371Sume addrs[j + 1] = addr; 2241157371Sume } else 2242157371Sume break; 2243157371Sume } 2244157371Sume needsort++; 2245121426Sume } 2246121426Sume 2247121426Sume ai = sentinel; 2248121426Sume for (i = 0; i < naddrs; ++i) { 2249121426Sume ai->ai_next = addrs[i].ai; 2250121426Sume ai = ai->ai_next; 2251121426Sume } 2252121426Sume ai->ai_next = NULL; 2253121426Sume free(addrs); 2254121426Sume return 0; 2255121426Sume} 2256121426Sume#endif /*RESOLVSORT*/ 2257121426Sume 225861877Sume/*ARGSUSED*/ 225961877Sumestatic int 2260157119Sume_dns_getaddrinfo(void *rv, void *cb_data, va_list ap) 226161877Sume{ 2262292722Sume struct addrinfo *ai, ai0; 2263103357Sume querybuf *buf, *buf2; 2264130600Sume const char *hostname; 226565532Snectar const struct addrinfo *pai; 226661877Sume struct addrinfo sentinel, *cur; 226761877Sume struct res_target q, q2; 2268156960Sume res_state res; 226961877Sume 2270304982Sngie ai = NULL; 2271304982Sngie 2272130600Sume hostname = va_arg(ap, char *); 227365532Snectar pai = va_arg(ap, const struct addrinfo *); 227465532Snectar 2275156946Sdelphij memset(&q, 0, sizeof(q)); 227661877Sume memset(&q2, 0, sizeof(q2)); 227761877Sume memset(&sentinel, 0, sizeof(sentinel)); 227861877Sume cur = &sentinel; 227961877Sume 2280292403Sume res = __res_state(); 2281292403Sume 2282103357Sume buf = malloc(sizeof(*buf)); 2283103357Sume if (!buf) { 2284156960Sume RES_SET_H_ERRNO(res, NETDB_INTERNAL); 2285103357Sume return NS_NOTFOUND; 2286103357Sume } 2287103357Sume buf2 = malloc(sizeof(*buf2)); 2288103357Sume if (!buf2) { 2289103357Sume free(buf); 2290156960Sume RES_SET_H_ERRNO(res, NETDB_INTERNAL); 2291103357Sume return NS_NOTFOUND; 2292103357Sume } 2293103357Sume 2294292722Sume if (pai->ai_family == AF_INET6 && 2295292722Sume (pai->ai_flags & AI_V4MAPPED) == AI_V4MAPPED) { 2296292722Sume ai0 = *pai; 2297292722Sume ai0.ai_family = AF_UNSPEC; 2298292722Sume pai = &ai0; 2299292722Sume } 2300292722Sume 230161877Sume switch (pai->ai_family) { 230261877Sume case AF_UNSPEC: 2303130600Sume q.name = hostname; 230462614Sitojun q.qclass = C_IN; 2305140896Sume q.qtype = T_A; 2306103357Sume q.answer = buf->buf; 2307103357Sume q.anslen = sizeof(buf->buf); 230861877Sume q.next = &q2; 2309130600Sume q2.name = hostname; 231062614Sitojun q2.qclass = C_IN; 2311140896Sume q2.qtype = T_AAAA; 2312103357Sume q2.answer = buf2->buf; 2313103357Sume q2.anslen = sizeof(buf2->buf); 231461877Sume break; 231561877Sume case AF_INET: 2316130600Sume q.name = hostname; 231762614Sitojun q.qclass = C_IN; 231862614Sitojun q.qtype = T_A; 2319103357Sume q.answer = buf->buf; 2320103357Sume q.anslen = sizeof(buf->buf); 232161877Sume break; 232261877Sume case AF_INET6: 2323130600Sume q.name = hostname; 232462614Sitojun q.qclass = C_IN; 232562614Sitojun q.qtype = T_AAAA; 2326103357Sume q.answer = buf->buf; 2327103357Sume q.anslen = sizeof(buf->buf); 232861877Sume break; 232961877Sume default: 2330103357Sume free(buf); 2331103357Sume free(buf2); 233265532Snectar return NS_UNAVAIL; 233361877Sume } 2334156960Sume 2335156960Sume if ((res->options & RES_INIT) == 0 && res_ninit(res) == -1) { 2336156960Sume RES_SET_H_ERRNO(res, NETDB_INTERNAL); 2337103357Sume free(buf); 2338103357Sume free(buf2); 233965532Snectar return NS_NOTFOUND; 2340103357Sume } 2341156960Sume 2342156960Sume if (res_searchN(hostname, &q, res) < 0) { 2343156960Sume free(buf); 2344156960Sume free(buf2); 2345156960Sume return NS_NOTFOUND; 2346156960Sume } 2347140896Sume /* prefer IPv6 */ 234861877Sume if (q.next) { 2349156960Sume ai = getanswer(buf2, q2.n, q2.name, q2.qtype, pai, res); 2350304982Sngie if (ai != NULL) { 235161877Sume cur->ai_next = ai; 2352140896Sume while (cur && cur->ai_next) 2353140896Sume cur = cur->ai_next; 2354140896Sume } 235561877Sume } 2356304982Sngie if (ai == NULL || pai->ai_family != AF_UNSPEC || 2357292722Sume (pai->ai_flags & (AI_ALL | AI_V4MAPPED)) != AI_V4MAPPED) { 2358292722Sume ai = getanswer(buf, q.n, q.name, q.qtype, pai, res); 2359304982Sngie if (ai != NULL) 2360292722Sume cur->ai_next = ai; 2361292722Sume } 2362103357Sume free(buf); 2363103357Sume free(buf2); 236461877Sume if (sentinel.ai_next == NULL) 2365156960Sume switch (res->res_h_errno) { 236661877Sume case HOST_NOT_FOUND: 2367292824Sume case NO_DATA: 236865532Snectar return NS_NOTFOUND; 236961877Sume case TRY_AGAIN: 237065532Snectar return NS_TRYAGAIN; 237161877Sume default: 237265532Snectar return NS_UNAVAIL; 237361877Sume } 237465532Snectar *((struct addrinfo **)rv) = sentinel.ai_next; 237565532Snectar return NS_SUCCESS; 237661877Sume} 237761877Sume 237865532Snectarstatic void 2379144634Sume_sethtent(FILE **hostf) 238065532Snectar{ 2381144634Sume if (!*hostf) 2382254700Sjilles *hostf = fopen(_PATH_HOSTS, "re"); 238365532Snectar else 2384144634Sume rewind(*hostf); 238565532Snectar} 238665532Snectar 238765532Snectarstatic void 2388144634Sume_endhtent(FILE **hostf) 238965532Snectar{ 2390144634Sume if (*hostf) { 2391144634Sume (void) fclose(*hostf); 2392144634Sume *hostf = NULL; 239365532Snectar } 239465532Snectar} 239565532Snectar 239661877Sumestatic struct addrinfo * 2397144634Sume_gethtent(FILE **hostf, const char *name, const struct addrinfo *pai) 239861877Sume{ 239961877Sume char *p; 240061877Sume char *cp, *tname, *cname; 240161877Sume struct addrinfo hints, *res0, *res; 240261877Sume int error; 240361877Sume const char *addr; 240461877Sume char hostbuf[8*1024]; 240561877Sume 2406254700Sjilles if (!*hostf && !(*hostf = fopen(_PATH_HOSTS, "re"))) 240765532Snectar return (NULL); 2408105940Sumeagain: 2409144634Sume if (!(p = fgets(hostbuf, sizeof hostbuf, *hostf))) 241061877Sume return (NULL); 241161877Sume if (*p == '#') 241261877Sume goto again; 2413139612Ssobomax cp = strpbrk(p, "#\n"); 2414139612Ssobomax if (cp != NULL) 2415139612Ssobomax *cp = '\0'; 241661877Sume if (!(cp = strpbrk(p, " \t"))) 241761877Sume goto again; 241861877Sume *cp++ = '\0'; 241961877Sume addr = p; 242061877Sume cname = NULL; 242161877Sume /* if this is not something we're looking for, skip it. */ 242261877Sume while (cp && *cp) { 242361877Sume if (*cp == ' ' || *cp == '\t') { 242461877Sume cp++; 242561877Sume continue; 242661877Sume } 242761877Sume tname = cp; 242861877Sume if (cname == NULL) 242961877Sume cname = cp; 243061877Sume if ((cp = strpbrk(cp, " \t")) != NULL) 243161877Sume *cp++ = '\0'; 243261877Sume if (strcasecmp(name, tname) == 0) 243361877Sume goto found; 243461877Sume } 243561877Sume goto again; 243661877Sume 243761877Sumefound: 2438105940Sume /* we should not glob socktype/protocol here */ 2439105940Sume memset(&hints, 0, sizeof(hints)); 2440105940Sume hints.ai_family = pai->ai_family; 2441105940Sume hints.ai_socktype = SOCK_DGRAM; 2442105940Sume hints.ai_protocol = 0; 244361877Sume hints.ai_flags = AI_NUMERICHOST; 2444292722Sume if (pai->ai_family == AF_INET6 && 2445292722Sume (pai->ai_flags & AI_V4MAPPED) == AI_V4MAPPED) 2446292722Sume hints.ai_flags |= AI_V4MAPPED; 2447105940Sume error = getaddrinfo(addr, "0", &hints, &res0); 244861877Sume if (error) 244961877Sume goto again; 245061877Sume#ifdef FILTER_V4MAPPED 245161877Sume /* XXX should check all items in the chain */ 245261877Sume if (res0->ai_family == AF_INET6 && 245361877Sume IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)res0->ai_addr)->sin6_addr)) { 245461877Sume freeaddrinfo(res0); 245561877Sume goto again; 245661877Sume } 245761877Sume#endif 245861877Sume for (res = res0; res; res = res->ai_next) { 245961877Sume /* cover it up */ 246061877Sume res->ai_flags = pai->ai_flags; 2461105940Sume res->ai_socktype = pai->ai_socktype; 2462105940Sume res->ai_protocol = pai->ai_protocol; 246361877Sume 246461877Sume if (pai->ai_flags & AI_CANONNAME) { 246561877Sume if (get_canonname(pai, res, cname) != 0) { 246661877Sume freeaddrinfo(res0); 246761877Sume goto again; 246861877Sume } 246961877Sume } 247061877Sume } 247161877Sume return res0; 247261877Sume} 247361877Sume 2474292722Sumestatic struct addrinfo * 2475292722Sume_getht(FILE **hostf, const char *name, const struct addrinfo *pai, 2476292722Sume struct addrinfo *cur) 2477292722Sume{ 2478292722Sume struct addrinfo *p; 2479292722Sume 2480292722Sume while ((p = _gethtent(hostf, name, pai)) != NULL) { 2481292722Sume cur->ai_next = p; 2482292722Sume while (cur && cur->ai_next) 2483292722Sume cur = cur->ai_next; 2484292722Sume } 2485292722Sume return (cur); 2486292722Sume} 2487292722Sume 248861877Sume/*ARGSUSED*/ 248961877Sumestatic int 2490157119Sume_files_getaddrinfo(void *rv, void *cb_data, va_list ap) 249165532Snectar{ 249265532Snectar const char *name; 249361877Sume const struct addrinfo *pai; 249461877Sume struct addrinfo sentinel, *cur; 2495144634Sume FILE *hostf = NULL; 249661877Sume 249765532Snectar name = va_arg(ap, char *); 249865532Snectar pai = va_arg(ap, struct addrinfo *); 249965532Snectar 250065532Snectar memset(&sentinel, 0, sizeof(sentinel)); 250161877Sume cur = &sentinel; 250261877Sume 2503144634Sume _sethtent(&hostf); 2504292722Sume if (pai->ai_family == AF_INET6 && 2505292722Sume (pai->ai_flags & (AI_ALL | AI_V4MAPPED)) == AI_V4MAPPED) { 2506292722Sume struct addrinfo ai0 = *pai; 2507292722Sume 2508292722Sume ai0.ai_flags &= ~AI_V4MAPPED; 2509292722Sume cur = _getht(&hostf, name, &ai0, cur); 2510292722Sume if (sentinel.ai_next == NULL) { 2511292722Sume _sethtent(&hostf); 2512292722Sume ai0.ai_flags |= AI_V4MAPPED; 2513292722Sume cur = _getht(&hostf, name, &ai0, cur); 2514292722Sume } 2515292722Sume } else 2516292722Sume cur = _getht(&hostf, name, pai, cur); 2517144634Sume _endhtent(&hostf); 251861877Sume 251965532Snectar *((struct addrinfo **)rv) = sentinel.ai_next; 252065532Snectar if (sentinel.ai_next == NULL) 252165532Snectar return NS_NOTFOUND; 252265532Snectar return NS_SUCCESS; 252361877Sume} 252461877Sume 252561877Sume#ifdef YP 252661877Sume/*ARGSUSED*/ 252765532Snectarstatic struct addrinfo * 2528157119Sume_yphostent(char *line, const struct addrinfo *pai) 252961877Sume{ 253061877Sume struct addrinfo sentinel, *cur; 253165532Snectar struct addrinfo hints, *res, *res0; 253261877Sume int error; 253365532Snectar char *p = line; 253465532Snectar const char *addr, *canonname; 253565532Snectar char *nextline; 253665532Snectar char *cp; 253761877Sume 253865532Snectar addr = canonname = NULL; 253965532Snectar 254065532Snectar memset(&sentinel, 0, sizeof(sentinel)); 254161877Sume cur = &sentinel; 254261877Sume 254365532Snectarnextline: 254465532Snectar /* terminate line */ 254565532Snectar cp = strchr(p, '\n'); 254665532Snectar if (cp) { 254765532Snectar *cp++ = '\0'; 254865532Snectar nextline = cp; 254965532Snectar } else 255065532Snectar nextline = NULL; 255161877Sume 255265532Snectar cp = strpbrk(p, " \t"); 255365532Snectar if (cp == NULL) { 255465532Snectar if (canonname == NULL) 255565532Snectar return (NULL); 255665532Snectar else 255765532Snectar goto done; 255861877Sume } 255965532Snectar *cp++ = '\0'; 256061877Sume 256165532Snectar addr = p; 256261877Sume 256365532Snectar while (cp && *cp) { 256465532Snectar if (*cp == ' ' || *cp == '\t') { 256565532Snectar cp++; 256661877Sume continue; 256765532Snectar } 256865532Snectar if (!canonname) 256965532Snectar canonname = cp; 257065532Snectar if ((cp = strpbrk(cp, " \t")) != NULL) 257165532Snectar *cp++ = '\0'; 257265532Snectar } 257361877Sume 2574121474Sume hints = *pai; 257565532Snectar hints.ai_flags = AI_NUMERICHOST; 2576292722Sume if (pai->ai_family == AF_INET6 && 2577292722Sume (pai->ai_flags & AI_V4MAPPED) == AI_V4MAPPED) 2578292722Sume hints.ai_flags |= AI_V4MAPPED; 2579121474Sume error = getaddrinfo(addr, NULL, &hints, &res0); 258065532Snectar if (error == 0) { 258165532Snectar for (res = res0; res; res = res->ai_next) { 258265532Snectar /* cover it up */ 258365532Snectar res->ai_flags = pai->ai_flags; 258461877Sume 258565532Snectar if (pai->ai_flags & AI_CANONNAME) 258665532Snectar (void)get_canonname(pai, res, canonname); 258761877Sume } 258865532Snectar } else 258965532Snectar res0 = NULL; 259065532Snectar if (res0) { 259165532Snectar cur->ai_next = res0; 259261877Sume while (cur && cur->ai_next) 259361877Sume cur = cur->ai_next; 259461877Sume } 259561877Sume 259665532Snectar if (nextline) { 259765532Snectar p = nextline; 259865532Snectar goto nextline; 259965532Snectar } 260061877Sume 260165532Snectardone: 260265532Snectar return sentinel.ai_next; 260361877Sume} 260465532Snectar 260565532Snectar/*ARGSUSED*/ 260665532Snectarstatic int 2607157119Sume_yp_getaddrinfo(void *rv, void *cb_data, va_list ap) 260865532Snectar{ 260965532Snectar struct addrinfo sentinel, *cur; 261065532Snectar struct addrinfo *ai = NULL; 2611144679Sume char *ypbuf; 2612144679Sume int ypbuflen, r; 261365532Snectar const char *name; 261465532Snectar const struct addrinfo *pai; 2615144679Sume char *ypdomain; 261665532Snectar 2617144679Sume if (_yp_check(&ypdomain) == 0) 2618144679Sume return NS_UNAVAIL; 2619144679Sume 262065532Snectar name = va_arg(ap, char *); 262165532Snectar pai = va_arg(ap, const struct addrinfo *); 262265532Snectar 262365532Snectar memset(&sentinel, 0, sizeof(sentinel)); 262465532Snectar cur = &sentinel; 262565532Snectar 2626292722Sume /* ipnodes.byname can hold both IPv4/v6 */ 2627292722Sume r = yp_match(ypdomain, "ipnodes.byname", name, 2628292722Sume (int)strlen(name), &ypbuf, &ypbuflen); 2629292722Sume if (r == 0) { 2630292722Sume ai = _yphostent(ypbuf, pai); 2631292722Sume if (ai) { 2632292722Sume cur->ai_next = ai; 2633292722Sume while (cur && cur->ai_next) 2634292722Sume cur = cur->ai_next; 2635292722Sume } 2636292722Sume free(ypbuf); 2637292722Sume } 2638292722Sume 2639292722Sume if (ai != NULL) { 2640292722Sume struct sockaddr_in6 *sin6; 2641292722Sume 2642292722Sume switch (ai->ai_family) { 2643292722Sume case AF_INET: 2644292722Sume goto done; 2645292722Sume case AF_INET6: 2646292722Sume sin6 = (struct sockaddr_in6 *)ai->ai_addr; 2647292722Sume if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) 2648292722Sume goto done; 2649292722Sume break; 2650292722Sume } 2651292722Sume } 2652292722Sume 265365532Snectar /* hosts.byname is only for IPv4 (Solaris8) */ 2654292722Sume if (pai->ai_family == AF_UNSPEC || pai->ai_family == AF_INET || 2655292722Sume ((pai->ai_family == AF_INET6 && 2656292722Sume (pai->ai_flags & AI_V4MAPPED) == AI_V4MAPPED) && 2657292722Sume (ai == NULL || (pai->ai_flags & AI_ALL) == AI_ALL))) { 2658144679Sume r = yp_match(ypdomain, "hosts.byname", name, 2659144679Sume (int)strlen(name), &ypbuf, &ypbuflen); 266065532Snectar if (r == 0) { 266165532Snectar struct addrinfo ai4; 266265532Snectar 266365532Snectar ai4 = *pai; 2664292722Sume if (pai->ai_family == AF_UNSPEC) 2665292722Sume ai4.ai_family = AF_INET; 2666144679Sume ai = _yphostent(ypbuf, &ai4); 266765532Snectar if (ai) { 266865532Snectar cur->ai_next = ai; 266965532Snectar while (cur && cur->ai_next) 267065532Snectar cur = cur->ai_next; 267165532Snectar } 2672146190Sume free(ypbuf); 267365532Snectar } 267465532Snectar } 267565532Snectar 2676292722Sumedone: 267765532Snectar if (sentinel.ai_next == NULL) { 2678156960Sume RES_SET_H_ERRNO(__res_state(), HOST_NOT_FOUND); 267965532Snectar return NS_NOTFOUND; 268065532Snectar } 268165532Snectar *((struct addrinfo **)rv) = sentinel.ai_next; 268265532Snectar return NS_SUCCESS; 268365532Snectar} 268461877Sume#endif 268561877Sume 268661877Sume/* resolver logic */ 268761877Sume 268861877Sume/* 268961877Sume * Formulate a normal query, send, and await answer. 269061877Sume * Returned answer is placed in supplied buffer "answer". 269161877Sume * Perform preliminary check of answer, returning success only 269261877Sume * if no error is indicated and the answer count is nonzero. 269361877Sume * Return the size of the response on success, -1 on error. 269461877Sume * Error number is left in h_errno. 269561877Sume * 269661877Sume * Caller must parse answer and determine whether it answers the question. 269761877Sume */ 269861877Sumestatic int 2699157119Sumeres_queryN(const char *name, struct res_target *target, res_state res) 270061877Sume{ 2701103357Sume u_char *buf; 270261877Sume HEADER *hp; 270361877Sume int n; 2704157203Sume u_int oflags; 270561877Sume struct res_target *t; 270661877Sume int rcode; 270761877Sume int ancount; 270861877Sume 270961877Sume rcode = NOERROR; 271061877Sume ancount = 0; 271161877Sume 2712103357Sume buf = malloc(MAXPACKET); 2713103357Sume if (!buf) { 2714156960Sume RES_SET_H_ERRNO(res, NETDB_INTERNAL); 2715103357Sume return -1; 2716103357Sume } 2717103357Sume 271861877Sume for (t = target; t; t = t->next) { 271961877Sume int class, type; 272061877Sume u_char *answer; 272161877Sume int anslen; 272261877Sume 272361877Sume hp = (HEADER *)(void *)t->answer; 272461877Sume 272561877Sume /* make it easier... */ 272662614Sitojun class = t->qclass; 272762614Sitojun type = t->qtype; 272861877Sume answer = t->answer; 272961877Sume anslen = t->anslen; 2730157203Sume 2731157203Sume oflags = res->_flags; 2732157203Sume 2733157203Sumeagain: 2734157203Sume hp->rcode = NOERROR; /* default */ 2735157203Sume 273661877Sume#ifdef DEBUG 2737156960Sume if (res->options & RES_DEBUG) 273861877Sume printf(";; res_query(%s, %d, %d)\n", name, class, type); 273961877Sume#endif 274061877Sume 2741156960Sume n = res_nmkquery(res, QUERY, name, class, type, NULL, 0, NULL, 2742103357Sume buf, MAXPACKET); 2743157203Sume if (n > 0 && (res->_flags & RES_F_EDNS0ERR) == 0 && 2744157203Sume (res->options & (RES_USE_EDNS0|RES_USE_DNSSEC)) != 0U) 2745156960Sume n = res_nopt(res, n, buf, MAXPACKET, anslen); 274661877Sume if (n <= 0) { 274761877Sume#ifdef DEBUG 2748156960Sume if (res->options & RES_DEBUG) 274961877Sume printf(";; res_query: mkquery failed\n"); 275061877Sume#endif 2751103357Sume free(buf); 2752156960Sume RES_SET_H_ERRNO(res, NO_RECOVERY); 275361877Sume return (n); 275461877Sume } 2755156960Sume n = res_nsend(res, buf, n, answer, anslen); 275661877Sume if (n < 0) { 2757157203Sume /* 2758157203Sume * if the query choked with EDNS0, retry 2759157203Sume * without EDNS0 2760157203Sume */ 2761157203Sume if ((res->options & (RES_USE_EDNS0|RES_USE_DNSSEC)) 2762157203Sume != 0U && 2763157203Sume ((oflags ^ res->_flags) & RES_F_EDNS0ERR) != 0) { 2764157203Sume res->_flags |= RES_F_EDNS0ERR; 2765157203Sume if (res->options & RES_DEBUG) 2766157203Sume printf(";; res_nquery: retry without EDNS0\n"); 2767157203Sume goto again; 2768157203Sume } 2769157203Sume rcode = hp->rcode; /* record most recent error */ 277061877Sume#ifdef DEBUG 2771156960Sume if (res->options & RES_DEBUG) 277261877Sume printf(";; res_query: send error\n"); 277361877Sume#endif 2774157203Sume continue; 277561877Sume } 277661877Sume 2777157081Sume if (n > anslen) 2778103350Snectar hp->rcode = FORMERR; /* XXX not very informative */ 2779157203Sume if (hp->rcode != NOERROR || ntohs(hp->ancount) == 0) { 278061877Sume rcode = hp->rcode; /* record most recent error */ 278161877Sume#ifdef DEBUG 2782156960Sume if (res->options & RES_DEBUG) 2783105940Sume printf(";; rcode = %u, ancount=%u\n", hp->rcode, 278461877Sume ntohs(hp->ancount)); 278561877Sume#endif 278661877Sume continue; 278761877Sume } 278861877Sume 278961877Sume ancount += ntohs(hp->ancount); 279061877Sume 279161877Sume t->n = n; 279261877Sume } 279361877Sume 2794103357Sume free(buf); 2795103357Sume 279661877Sume if (ancount == 0) { 279761877Sume switch (rcode) { 279861877Sume case NXDOMAIN: 2799156960Sume RES_SET_H_ERRNO(res, HOST_NOT_FOUND); 280061877Sume break; 280161877Sume case SERVFAIL: 2802156960Sume RES_SET_H_ERRNO(res, TRY_AGAIN); 280361877Sume break; 280461877Sume case NOERROR: 2805156960Sume RES_SET_H_ERRNO(res, NO_DATA); 280661877Sume break; 280761877Sume case FORMERR: 280861877Sume case NOTIMP: 280961877Sume case REFUSED: 281061877Sume default: 2811156960Sume RES_SET_H_ERRNO(res, NO_RECOVERY); 281261877Sume break; 281361877Sume } 281461877Sume return (-1); 281561877Sume } 281661877Sume return (ancount); 281761877Sume} 281861877Sume 281961877Sume/* 282061877Sume * Formulate a normal query, send, and retrieve answer in supplied buffer. 282161877Sume * Return the size of the response on success, -1 on error. 282261877Sume * If enabled, implement search rules until answer or unrecoverable failure 282361877Sume * is detected. Error code, if any, is left in h_errno. 282461877Sume */ 282561877Sumestatic int 2826157119Sumeres_searchN(const char *name, struct res_target *target, res_state res) 282761877Sume{ 282861877Sume const char *cp, * const *domain; 282961877Sume HEADER *hp = (HEADER *)(void *)target->answer; /*XXX*/ 283061877Sume u_int dots; 283161877Sume int trailing_dot, ret, saved_herrno; 2832155983Sume int got_nodata = 0, got_servfail = 0, root_on_list = 0; 2833155983Sume int tried_as_is = 0; 2834155983Sume int searched = 0; 2835145113Sume char abuf[MAXDNAME]; 283661877Sume 283761877Sume errno = 0; 2838156960Sume RES_SET_H_ERRNO(res, HOST_NOT_FOUND); /* default, if we never query */ 283961877Sume dots = 0; 284061877Sume for (cp = name; *cp; cp++) 284161877Sume dots += (*cp == '.'); 284261877Sume trailing_dot = 0; 284361877Sume if (cp > name && *--cp == '.') 284461877Sume trailing_dot++; 284561877Sume 284661877Sume /* 284761877Sume * if there aren't any dots, it could be a user-level alias 284861877Sume */ 2849156960Sume if (!dots && 2850156960Sume (cp = res_hostalias(res, name, abuf, sizeof(abuf))) != NULL) 2851156960Sume return (res_queryN(cp, target, res)); 285261877Sume 285361877Sume /* 2854155983Sume * If there are enough dots in the name, let's just give it a 2855155983Sume * try 'as is'. The threshold can be set with the "ndots" option. 2856155983Sume * Also, query 'as is', if there is a trailing dot in the name. 285761877Sume */ 285861877Sume saved_herrno = -1; 2859156960Sume if (dots >= res->ndots || trailing_dot) { 2860156960Sume ret = res_querydomainN(name, NULL, target, res); 2861155983Sume if (ret > 0 || trailing_dot) 286261877Sume return (ret); 2863156155Sume if (errno == ECONNREFUSED) { 2864156960Sume RES_SET_H_ERRNO(res, TRY_AGAIN); 2865156155Sume return (-1); 2866156155Sume } 2867156960Sume switch (res->res_h_errno) { 2868156155Sume case NO_DATA: 2869156155Sume case HOST_NOT_FOUND: 2870156155Sume break; 2871157093Sume case TRY_AGAIN: 2872157093Sume if (hp->rcode == SERVFAIL) 2873157093Sume break; 2874157093Sume /* FALLTHROUGH */ 2875156155Sume default: 2876156155Sume return (-1); 2877156155Sume } 2878156960Sume saved_herrno = res->res_h_errno; 287961877Sume tried_as_is++; 288061877Sume } 288161877Sume 288261877Sume /* 288361877Sume * We do at least one level of search if 288461877Sume * - there is no dot and RES_DEFNAME is set, or 288561877Sume * - there is at least one dot, there is no trailing dot, 288661877Sume * and RES_DNSRCH is set. 288761877Sume */ 2888156960Sume if ((!dots && (res->options & RES_DEFNAMES)) || 2889156960Sume (dots && !trailing_dot && (res->options & RES_DNSRCH))) { 289061877Sume int done = 0; 289161877Sume 2892156960Sume for (domain = (const char * const *)res->dnsrch; 289361877Sume *domain && !done; 289461877Sume domain++) { 2895155983Sume searched = 1; 289661877Sume 2897155983Sume if (domain[0][0] == '\0' || 2898155983Sume (domain[0][0] == '.' && domain[0][1] == '\0')) 2899155983Sume root_on_list++; 2900155983Sume 2901155983Sume if (root_on_list && tried_as_is) 2902155983Sume continue; 2903155983Sume 2904156960Sume ret = res_querydomainN(name, *domain, target, res); 290561877Sume if (ret > 0) 290661877Sume return (ret); 290761877Sume 290861877Sume /* 290961877Sume * If no server present, give up. 291061877Sume * If name isn't found in this domain, 291161877Sume * keep trying higher domains in the search list 291261877Sume * (if that's enabled). 291361877Sume * On a NO_DATA error, keep trying, otherwise 291461877Sume * a wildcard entry of another type could keep us 291561877Sume * from finding this entry higher in the domain. 291661877Sume * If we get some other error (negative answer or 291761877Sume * server failure), then stop searching up, 291861877Sume * but try the input name below in case it's 291961877Sume * fully-qualified. 292061877Sume */ 292161877Sume if (errno == ECONNREFUSED) { 2922156960Sume RES_SET_H_ERRNO(res, TRY_AGAIN); 292361877Sume return (-1); 292461877Sume } 292561877Sume 2926156960Sume switch (res->res_h_errno) { 292761877Sume case NO_DATA: 292861877Sume got_nodata++; 292961877Sume /* FALLTHROUGH */ 293061877Sume case HOST_NOT_FOUND: 293161877Sume /* keep trying */ 293261877Sume break; 293361877Sume case TRY_AGAIN: 2934157093Sume got_servfail++; 293561877Sume if (hp->rcode == SERVFAIL) { 293661877Sume /* try next search element, if any */ 293761877Sume break; 293861877Sume } 293961877Sume /* FALLTHROUGH */ 294061877Sume default: 294161877Sume /* anything else implies that we're done */ 294261877Sume done++; 294361877Sume } 294461877Sume /* 294561877Sume * if we got here for some reason other than DNSRCH, 294661877Sume * we only wanted one iteration of the loop, so stop. 294761877Sume */ 2948156960Sume if (!(res->options & RES_DNSRCH)) 294961877Sume done++; 295061877Sume } 295161877Sume } 295261877Sume 2953156960Sume switch (res->res_h_errno) { 2954156155Sume case NO_DATA: 2955156155Sume case HOST_NOT_FOUND: 2956156155Sume break; 2957157093Sume case TRY_AGAIN: 2958157093Sume if (hp->rcode == SERVFAIL) 2959157093Sume break; 2960157093Sume /* FALLTHROUGH */ 2961156155Sume default: 2962156155Sume goto giveup; 2963156155Sume } 2964156155Sume 296561877Sume /* 2966155983Sume * If the query has not already been tried as is then try it 2967155983Sume * unless RES_NOTLDQUERY is set and there were no dots. 296861877Sume */ 2969156960Sume if ((dots || !searched || !(res->options & RES_NOTLDQUERY)) && 2970155983Sume !(tried_as_is || root_on_list)) { 2971156960Sume ret = res_querydomainN(name, NULL, target, res); 297261877Sume if (ret > 0) 297361877Sume return (ret); 297461877Sume } 297561877Sume 297661877Sume /* 297761877Sume * if we got here, we didn't satisfy the search. 297861877Sume * if we did an initial full query, return that query's h_errno 297961877Sume * (note that we wouldn't be here if that query had succeeded). 298061877Sume * else if we ever got a nodata, send that back as the reason. 298161877Sume * else send back meaningless h_errno, that being the one from 298261877Sume * the last DNSRCH we did. 298361877Sume */ 2984156155Sumegiveup: 298561877Sume if (saved_herrno != -1) 2986156960Sume RES_SET_H_ERRNO(res, saved_herrno); 298761877Sume else if (got_nodata) 2988156960Sume RES_SET_H_ERRNO(res, NO_DATA); 298961877Sume else if (got_servfail) 2990156960Sume RES_SET_H_ERRNO(res, TRY_AGAIN); 299161877Sume return (-1); 299261877Sume} 299361877Sume 299461877Sume/* 299561877Sume * Perform a call on res_query on the concatenation of name and domain, 299661877Sume * removing a trailing dot from name if domain is NULL. 299761877Sume */ 299861877Sumestatic int 2999157119Sumeres_querydomainN(const char *name, const char *domain, 3000157119Sume struct res_target *target, res_state res) 300161877Sume{ 300261877Sume char nbuf[MAXDNAME]; 300361877Sume const char *longname = nbuf; 300461877Sume size_t n, d; 300561877Sume 300661877Sume#ifdef DEBUG 3007156960Sume if (res->options & RES_DEBUG) 300861877Sume printf(";; res_querydomain(%s, %s)\n", 300961877Sume name, domain?domain:"<Nil>"); 301061877Sume#endif 301161877Sume if (domain == NULL) { 301261877Sume /* 301361877Sume * Check for trailing '.'; 301461877Sume * copy without '.' if present. 301561877Sume */ 301661877Sume n = strlen(name); 301761877Sume if (n >= MAXDNAME) { 3018156960Sume RES_SET_H_ERRNO(res, NO_RECOVERY); 301961877Sume return (-1); 302061877Sume } 302161877Sume if (n > 0 && name[--n] == '.') { 302261877Sume strncpy(nbuf, name, n); 302361877Sume nbuf[n] = '\0'; 302461877Sume } else 302561877Sume longname = name; 302661877Sume } else { 302761877Sume n = strlen(name); 302861877Sume d = strlen(domain); 302961877Sume if (n + d + 1 >= MAXDNAME) { 3030156960Sume RES_SET_H_ERRNO(res, NO_RECOVERY); 303161877Sume return (-1); 303261877Sume } 3033105940Sume snprintf(nbuf, sizeof(nbuf), "%s.%s", name, domain); 303461877Sume } 3035156960Sume return (res_queryN(longname, target, res)); 303661877Sume} 3037