getaddrinfo.c revision 268051
1130803Smarcel/* $KAME: getaddrinfo.c,v 1.15 2000/07/09 04:37:24 itojun Exp $ */ 2130803Smarcel 3130803Smarcel/* 4130803Smarcel * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 5130803Smarcel * All rights reserved. 6130803Smarcel * 7130803Smarcel * Redistribution and use in source and binary forms, with or without 8130803Smarcel * modification, are permitted provided that the following conditions 9130803Smarcel * are met: 10130803Smarcel * 1. Redistributions of source code must retain the above copyright 11130803Smarcel * notice, this list of conditions and the following disclaimer. 12130803Smarcel * 2. Redistributions in binary form must reproduce the above copyright 13130803Smarcel * notice, this list of conditions and the following disclaimer in the 14130803Smarcel * documentation and/or other materials provided with the distribution. 15130803Smarcel * 3. Neither the name of the project nor the names of its contributors 16130803Smarcel * may be used to endorse or promote products derived from this software 17130803Smarcel * without specific prior written permission. 18130803Smarcel * 19130803Smarcel * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 20130803Smarcel * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21130803Smarcel * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22130803Smarcel * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 23130803Smarcel * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24130803Smarcel * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25130803Smarcel * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26130803Smarcel * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27130803Smarcel * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28130803Smarcel * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29130803Smarcel * SUCH DAMAGE. 30130803Smarcel */ 31130803Smarcel 32130803Smarcel/* 33130803Smarcel * "#ifdef FAITH" part is local hack for supporting IPv4-v6 translator. 34130803Smarcel * 35130803Smarcel * Issues to be discussed: 36130803Smarcel * - Return values. There are nonstandard return values defined and used 37130803Smarcel * in the source code. This is because RFC2553 is silent about which error 38130803Smarcel * code must be returned for which situation. 39130803Smarcel * - freeaddrinfo(NULL). RFC2553 is silent about it. XNET 5.2 says it is 40130803Smarcel * invalid. current code - SEGV on freeaddrinfo(NULL) 41130803Smarcel * 42130803Smarcel * Note: 43130803Smarcel * - The code filters out AFs that are not supported by the kernel, 44130803Smarcel * when globbing NULL hostname (to loopback, or wildcard). Is it the right 45130803Smarcel * thing to do? What is the relationship with post-RFC2553 AI_ADDRCONFIG 46130803Smarcel * in ai_flags? 47130803Smarcel * - (post-2553) semantics of AI_ADDRCONFIG itself is too vague. 48130803Smarcel * (1) what should we do against numeric hostname (2) what should we do 49130803Smarcel * against NULL hostname (3) what is AI_ADDRCONFIG itself. AF not ready? 50130803Smarcel * non-loopback address configured? global address configured? 51130803Smarcel * 52130803Smarcel * OS specific notes for freebsd4: 53130803Smarcel * - FreeBSD supported $GAI. The code does not. 54130803Smarcel */ 55130803Smarcel 56130803Smarcel#include <sys/cdefs.h> 57130803Smarcel__FBSDID("$FreeBSD: stable/10/lib/libc/net/getaddrinfo.c 268051 2014-06-30 16:53:12Z ume $"); 58130803Smarcel 59130803Smarcel#include "namespace.h" 60130803Smarcel#include <sys/types.h> 61130803Smarcel#include <sys/param.h> 62130803Smarcel#include <sys/socket.h> 63130803Smarcel#include <net/if.h> 64130803Smarcel#include <netinet/in.h> 65130803Smarcel#include <net/if_types.h> 66130803Smarcel#include <ifaddrs.h> 67130803Smarcel#include <sys/queue.h> 68130803Smarcel#ifdef INET6 69130803Smarcel#include <net/if_var.h> 70130803Smarcel#include <sys/sysctl.h> 71130803Smarcel#include <sys/ioctl.h> 72130803Smarcel#include <netinet6/in6_var.h> 73130803Smarcel#include <netinet6/nd6.h> 74130803Smarcel#endif 75130803Smarcel#include <arpa/inet.h> 76130803Smarcel#include <arpa/nameser.h> 77130803Smarcel#include <rpc/rpc.h> 78130803Smarcel#include <rpcsvc/yp_prot.h> 79130803Smarcel#include <rpcsvc/ypclnt.h> 80130803Smarcel#include <netdb.h> 81130803Smarcel#include <resolv.h> 82130803Smarcel#include <string.h> 83130803Smarcel#include <stdlib.h> 84130803Smarcel#include <stddef.h> 85130803Smarcel#include <ctype.h> 86130803Smarcel#include <unistd.h> 87130803Smarcel#include <stdio.h> 88130803Smarcel#include <errno.h> 89130803Smarcel 90130803Smarcel#include "res_config.h" 91130803Smarcel 92130803Smarcel#ifdef DEBUG 93130803Smarcel#include <syslog.h> 94130803Smarcel#endif 95130803Smarcel 96130803Smarcel#include <stdarg.h> 97130803Smarcel#include <nsswitch.h> 98130803Smarcel#include "un-namespace.h" 99130803Smarcel#include "libc_private.h" 100130803Smarcel#ifdef NS_CACHING 101130803Smarcel#include "nscache.h" 102130803Smarcel#endif 103130803Smarcel 104130803Smarcel#if defined(__KAME__) && defined(INET6) 105130803Smarcel# define FAITH 106130803Smarcel#endif 107130803Smarcel 108130803Smarcel#define ANY 0 109130803Smarcel#define YES 1 110130803Smarcel#define NO 0 111130803Smarcel 112130803Smarcelstatic const char in_addrany[] = { 0, 0, 0, 0 }; 113130803Smarcelstatic const char in_loopback[] = { 127, 0, 0, 1 }; 114130803Smarcel#ifdef INET6 115130803Smarcelstatic const char in6_addrany[] = { 116130803Smarcel 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 117130803Smarcel}; 118130803Smarcelstatic const char in6_loopback[] = { 119130803Smarcel 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 120130803Smarcel}; 121130803Smarcel#endif 122130803Smarcel 123130803Smarcelstruct policyqueue { 124130803Smarcel TAILQ_ENTRY(policyqueue) pc_entry; 125130803Smarcel#ifdef INET6 126130803Smarcel struct in6_addrpolicy pc_policy; 127130803Smarcel#endif 128130803Smarcel}; 129130803SmarcelTAILQ_HEAD(policyhead, policyqueue); 130130803Smarcel 131130803Smarcelstatic const struct afd { 132130803Smarcel int a_af; 133130803Smarcel int a_addrlen; 134130803Smarcel socklen_t a_socklen; 135130803Smarcel int a_off; 136130803Smarcel const char *a_addrany; 137130803Smarcel const char *a_loopback; 138130803Smarcel int a_scoped; 139130803Smarcel} afdl [] = { 140130803Smarcel#ifdef INET6 141130803Smarcel#define N_INET6 0 142130803Smarcel {PF_INET6, sizeof(struct in6_addr), 143130803Smarcel sizeof(struct sockaddr_in6), 144130803Smarcel offsetof(struct sockaddr_in6, sin6_addr), 145130803Smarcel in6_addrany, in6_loopback, 1}, 146130803Smarcel#define N_INET 1 147130803Smarcel#else 148130803Smarcel#define N_INET 0 149130803Smarcel#endif 150130803Smarcel {PF_INET, sizeof(struct in_addr), 151130803Smarcel sizeof(struct sockaddr_in), 152130803Smarcel offsetof(struct sockaddr_in, sin_addr), 153130803Smarcel in_addrany, in_loopback, 0}, 154130803Smarcel {0, 0, 0, 0, NULL, NULL, 0}, 155130803Smarcel}; 156130803Smarcel 157130803Smarcelstruct explore { 158130803Smarcel int e_af; 159130803Smarcel int e_socktype; 160130803Smarcel int e_protocol; 161130803Smarcel int e_wild; 162130803Smarcel#define WILD_AF(ex) ((ex)->e_wild & 0x01) 163130803Smarcel#define WILD_SOCKTYPE(ex) ((ex)->e_wild & 0x02) 164130803Smarcel#define WILD_PROTOCOL(ex) ((ex)->e_wild & 0x04) 165130803Smarcel}; 166130803Smarcel 167130803Smarcelstatic const struct explore explore[] = { 168130803Smarcel#if 0 169130803Smarcel { PF_LOCAL, ANY, ANY, 0x01 }, 170130803Smarcel#endif 171130803Smarcel#ifdef INET6 172130803Smarcel { PF_INET6, SOCK_DGRAM, IPPROTO_UDP, 0x07 }, 173130803Smarcel { PF_INET6, SOCK_STREAM, IPPROTO_TCP, 0x07 }, 174130803Smarcel { PF_INET6, SOCK_STREAM, IPPROTO_SCTP, 0x03 }, 175130803Smarcel { PF_INET6, SOCK_SEQPACKET, IPPROTO_SCTP, 0x07 }, 176130803Smarcel { PF_INET6, SOCK_DGRAM, IPPROTO_UDPLITE, 0x03 }, 177130803Smarcel { PF_INET6, SOCK_RAW, ANY, 0x05 }, 178130803Smarcel#endif 179130803Smarcel { PF_INET, SOCK_DGRAM, IPPROTO_UDP, 0x07 }, 180130803Smarcel { PF_INET, SOCK_STREAM, IPPROTO_TCP, 0x07 }, 181130803Smarcel { PF_INET, SOCK_STREAM, IPPROTO_SCTP, 0x03 }, 182130803Smarcel { PF_INET, SOCK_SEQPACKET, IPPROTO_SCTP, 0x07 }, 183130803Smarcel { PF_INET, SOCK_DGRAM, IPPROTO_UDPLITE, 0x03 }, 184130803Smarcel { PF_INET, SOCK_RAW, ANY, 0x05 }, 185130803Smarcel { -1, 0, 0, 0 }, 186130803Smarcel}; 187130803Smarcel 188130803Smarcel#ifdef INET6 189130803Smarcel#define PTON_MAX 16 190130803Smarcel#else 191130803Smarcel#define PTON_MAX 4 192130803Smarcel#endif 193130803Smarcel 194130803Smarcel#define AIO_SRCFLAG_DEPRECATED 0x1 195130803Smarcel 196130803Smarcelstruct ai_order { 197130803Smarcel union { 198130803Smarcel struct sockaddr_storage aiou_ss; 199130803Smarcel struct sockaddr aiou_sa; 200130803Smarcel } aio_src_un; 201130803Smarcel#define aio_srcsa aio_src_un.aiou_sa 202130803Smarcel u_int32_t aio_srcflag; 203130803Smarcel int aio_srcscope; 204130803Smarcel int aio_dstscope; 205130803Smarcel struct policyqueue *aio_srcpolicy; 206130803Smarcel struct policyqueue *aio_dstpolicy; 207130803Smarcel struct addrinfo *aio_ai; 208130803Smarcel int aio_matchlen; 209130803Smarcel}; 210130803Smarcel 211130803Smarcelstatic const ns_src default_dns_files[] = { 212130803Smarcel { NSSRC_FILES, NS_SUCCESS }, 213130803Smarcel { NSSRC_DNS, NS_SUCCESS }, 214130803Smarcel { 0 } 215130803Smarcel}; 216130803Smarcel 217130803Smarcelstruct res_target { 218130803Smarcel struct res_target *next; 219130803Smarcel const char *name; /* domain name */ 220130803Smarcel int qclass, qtype; /* class and type of query */ 221130803Smarcel u_char *answer; /* buffer to put answer */ 222130803Smarcel int anslen; /* size of answer buffer */ 223130803Smarcel int n; /* result length */ 224130803Smarcel}; 225130803Smarcel 226130803Smarcel#define MAXPACKET (64*1024) 227130803Smarcel 228130803Smarceltypedef union { 229130803Smarcel HEADER hdr; 230130803Smarcel u_char buf[MAXPACKET]; 231130803Smarcel} querybuf; 232130803Smarcel 233130803Smarcelstatic int str2number(const char *, int *); 234130803Smarcelstatic int explore_copy(const struct addrinfo *, const struct addrinfo *, 235130803Smarcel struct addrinfo **); 236130803Smarcelstatic int explore_null(const struct addrinfo *, 237130803Smarcel const char *, struct addrinfo **); 238130803Smarcelstatic int explore_numeric(const struct addrinfo *, const char *, 239130803Smarcel const char *, struct addrinfo **, const char *); 240130803Smarcelstatic int explore_numeric_scope(const struct addrinfo *, const char *, 241130803Smarcel const char *, struct addrinfo **); 242130803Smarcelstatic int get_canonname(const struct addrinfo *, 243130803Smarcel struct addrinfo *, const char *); 244130803Smarcelstatic struct addrinfo *get_ai(const struct addrinfo *, 245130803Smarcel const struct afd *, const char *); 246130803Smarcelstatic struct addrinfo *copy_ai(const struct addrinfo *); 247130803Smarcelstatic int get_portmatch(const struct addrinfo *, const char *); 248130803Smarcelstatic int get_port(struct addrinfo *, const char *, int); 249130803Smarcelstatic const struct afd *find_afd(int); 250130803Smarcelstatic int addrconfig(struct addrinfo *); 251130803Smarcel#ifdef INET6 252130803Smarcelstatic int is_ifdisabled(char *); 253130803Smarcel#endif 254130803Smarcelstatic void set_source(struct ai_order *, struct policyhead *); 255130803Smarcelstatic int comp_dst(const void *, const void *); 256130803Smarcel#ifdef INET6 257130803Smarcelstatic int ip6_str2scopeid(char *, struct sockaddr_in6 *, u_int32_t *); 258130803Smarcel#endif 259130803Smarcelstatic int gai_addr2scopetype(struct sockaddr *); 260130803Smarcel 261130803Smarcelstatic int explore_fqdn(const struct addrinfo *, const char *, 262130803Smarcel const char *, struct addrinfo **); 263130803Smarcel 264130803Smarcelstatic int reorder(struct addrinfo *); 265130803Smarcelstatic int get_addrselectpolicy(struct policyhead *); 266130803Smarcelstatic void free_addrselectpolicy(struct policyhead *); 267130803Smarcelstatic struct policyqueue *match_addrselectpolicy(struct sockaddr *, 268130803Smarcel struct policyhead *); 269130803Smarcelstatic int matchlen(struct sockaddr *, struct sockaddr *); 270130803Smarcel 271130803Smarcelstatic struct addrinfo *getanswer(const querybuf *, int, const char *, int, 272130803Smarcel const struct addrinfo *, res_state); 273130803Smarcel#if defined(RESOLVSORT) 274130803Smarcelstatic int addr4sort(struct addrinfo *, res_state); 275130803Smarcel#endif 276130803Smarcelstatic int _dns_getaddrinfo(void *, void *, va_list); 277130803Smarcelstatic void _sethtent(FILE **); 278130803Smarcelstatic void _endhtent(FILE **); 279130803Smarcelstatic struct addrinfo *_gethtent(FILE **, const char *, 280130803Smarcel const struct addrinfo *); 281130803Smarcelstatic int _files_getaddrinfo(void *, void *, va_list); 282130803Smarcel#ifdef YP 283130803Smarcelstatic struct addrinfo *_yphostent(char *, const struct addrinfo *); 284130803Smarcelstatic int _yp_getaddrinfo(void *, void *, va_list); 285130803Smarcel#endif 286130803Smarcel#ifdef NS_CACHING 287130803Smarcelstatic int addrinfo_id_func(char *, size_t *, va_list, void *); 288130803Smarcelstatic int addrinfo_marshal_func(char *, size_t *, void *, va_list, void *); 289130803Smarcelstatic int addrinfo_unmarshal_func(char *, size_t, void *, va_list, void *); 290130803Smarcel#endif 291130803Smarcel 292130803Smarcelstatic int res_queryN(const char *, struct res_target *, res_state); 293130803Smarcelstatic int res_searchN(const char *, struct res_target *, res_state); 294130803Smarcelstatic int res_querydomainN(const char *, const char *, 295130803Smarcel struct res_target *, res_state); 296130803Smarcel 297130803Smarcel/* XXX macros that make external reference is BAD. */ 298130803Smarcel 299130803Smarcel#define GET_AI(ai, afd, addr) \ 300130803Smarceldo { \ 301130803Smarcel /* external reference: pai, error, and label free */ \ 302130803Smarcel (ai) = get_ai(pai, (afd), (addr)); \ 303130803Smarcel if ((ai) == NULL) { \ 304130803Smarcel error = EAI_MEMORY; \ 305130803Smarcel goto free; \ 306130803Smarcel } \ 307130803Smarcel} while (/*CONSTCOND*/0) 308130803Smarcel 309130803Smarcel#define GET_PORT(ai, serv) \ 310130803Smarceldo { \ 311130803Smarcel /* external reference: error and label free */ \ 312130803Smarcel error = get_port((ai), (serv), 0); \ 313130803Smarcel if (error != 0) \ 314130803Smarcel goto free; \ 315130803Smarcel} while (/*CONSTCOND*/0) 316130803Smarcel 317130803Smarcel#define GET_CANONNAME(ai, str) \ 318130803Smarceldo { \ 319130803Smarcel /* external reference: pai, error and label free */ \ 320130803Smarcel error = get_canonname(pai, (ai), (str)); \ 321130803Smarcel if (error != 0) \ 322130803Smarcel goto free; \ 323130803Smarcel} while (/*CONSTCOND*/0) 324130803Smarcel 325130803Smarcel#define ERR(err) \ 326130803Smarceldo { \ 327130803Smarcel /* external reference: error, and label bad */ \ 328130803Smarcel error = (err); \ 329130803Smarcel goto bad; \ 330130803Smarcel /*NOTREACHED*/ \ 331130803Smarcel} while (/*CONSTCOND*/0) 332130803Smarcel 333130803Smarcel#define MATCH_FAMILY(x, y, w) \ 334130803Smarcel ((x) == (y) || (/*CONSTCOND*/(w) && ((x) == PF_UNSPEC || (y) == PF_UNSPEC))) 335130803Smarcel#define MATCH(x, y, w) \ 336130803Smarcel ((x) == (y) || (/*CONSTCOND*/(w) && ((x) == ANY || (y) == ANY))) 337130803Smarcel 338130803Smarcelvoid 339130803Smarcelfreeaddrinfo(struct addrinfo *ai) 340130803Smarcel{ 341130803Smarcel struct addrinfo *next; 342130803Smarcel 343130803Smarcel do { 344130803Smarcel next = ai->ai_next; 345130803Smarcel if (ai->ai_canonname) 346130803Smarcel free(ai->ai_canonname); 347130803Smarcel /* no need to free(ai->ai_addr) */ 348130803Smarcel free(ai); 349130803Smarcel ai = next; 350130803Smarcel } while (ai); 351130803Smarcel} 352130803Smarcel 353130803Smarcelstatic int 354130803Smarcelstr2number(const char *p, int *portp) 355130803Smarcel{ 356130803Smarcel char *ep; 357130803Smarcel unsigned long v; 358130803Smarcel 359130803Smarcel if (*p == '\0') 360130803Smarcel return -1; 361130803Smarcel ep = NULL; 362130803Smarcel errno = 0; 363130803Smarcel v = strtoul(p, &ep, 10); 364130803Smarcel if (errno == 0 && ep && *ep == '\0' && v <= UINT_MAX) { 365130803Smarcel *portp = v; 366130803Smarcel return 0; 367130803Smarcel } else 368130803Smarcel return -1; 369130803Smarcel} 370130803Smarcel 371130803Smarcelint 372130803Smarcelgetaddrinfo(const char *hostname, const char *servname, 373130803Smarcel const struct addrinfo *hints, struct addrinfo **res) 374130803Smarcel{ 375130803Smarcel struct addrinfo sentinel; 376130803Smarcel struct addrinfo *cur; 377130803Smarcel int error = 0; 378130803Smarcel struct addrinfo ai, ai0, *afai; 379130803Smarcel struct addrinfo *pai; 380130803Smarcel const struct afd *afd; 381130803Smarcel const struct explore *ex; 382130803Smarcel struct addrinfo *afailist[sizeof(afdl)/sizeof(afdl[0])]; 383130803Smarcel struct addrinfo *afai_unspec; 384130803Smarcel int found; 385130803Smarcel int numeric = 0; 386130803Smarcel 387130803Smarcel /* ensure we return NULL on errors */ 388130803Smarcel *res = NULL; 389130803Smarcel 390130803Smarcel memset(&ai, 0, sizeof(ai)); 391130803Smarcel 392130803Smarcel memset(afailist, 0, sizeof(afailist)); 393130803Smarcel afai_unspec = NULL; 394130803Smarcel 395130803Smarcel memset(&sentinel, 0, sizeof(sentinel)); 396130803Smarcel cur = &sentinel; 397130803Smarcel pai = &ai; 398130803Smarcel pai->ai_flags = 0; 399130803Smarcel pai->ai_family = PF_UNSPEC; 400130803Smarcel pai->ai_socktype = ANY; 401130803Smarcel pai->ai_protocol = ANY; 402130803Smarcel pai->ai_addrlen = 0; 403130803Smarcel pai->ai_canonname = NULL; 404130803Smarcel pai->ai_addr = NULL; 405130803Smarcel pai->ai_next = NULL; 406130803Smarcel 407130803Smarcel if (hostname == NULL && servname == NULL) 408130803Smarcel return EAI_NONAME; 409130803Smarcel if (hints) { 410130803Smarcel /* error check for hints */ 411130803Smarcel if (hints->ai_addrlen || hints->ai_canonname || 412130803Smarcel hints->ai_addr || hints->ai_next) 413130803Smarcel ERR(EAI_BADHINTS); /* xxx */ 414130803Smarcel if (hints->ai_flags & ~AI_MASK) 415130803Smarcel ERR(EAI_BADFLAGS); 416130803Smarcel switch (hints->ai_family) { 417130803Smarcel case PF_UNSPEC: 418130803Smarcel case PF_INET: 419130803Smarcel#ifdef INET6 420130803Smarcel case PF_INET6: 421130803Smarcel#endif 422130803Smarcel break; 423130803Smarcel default: 424130803Smarcel ERR(EAI_FAMILY); 425130803Smarcel } 426130803Smarcel memcpy(pai, hints, sizeof(*pai)); 427130803Smarcel 428130803Smarcel /* 429130803Smarcel * if both socktype/protocol are specified, check if they 430130803Smarcel * are meaningful combination. 431130803Smarcel */ 432130803Smarcel if (pai->ai_socktype != ANY && pai->ai_protocol != ANY) { 433130803Smarcel for (ex = explore; ex->e_af >= 0; ex++) { 434130803Smarcel if (!MATCH_FAMILY(pai->ai_family, ex->e_af, 435130803Smarcel WILD_AF(ex))) 436130803Smarcel continue; 437130803Smarcel if (!MATCH(pai->ai_socktype, ex->e_socktype, 438130803Smarcel WILD_SOCKTYPE(ex))) 439130803Smarcel continue; 440130803Smarcel if (!MATCH(pai->ai_protocol, ex->e_protocol, 441130803Smarcel WILD_PROTOCOL(ex))) 442130803Smarcel continue; 443130803Smarcel 444130803Smarcel /* matched */ 445130803Smarcel break; 446130803Smarcel } 447130803Smarcel 448130803Smarcel if (ex->e_af < 0) 449130803Smarcel ERR(EAI_BADHINTS); 450130803Smarcel } 451130803Smarcel } 452130803Smarcel 453130803Smarcel /* 454130803Smarcel * check for special cases. (1) numeric servname is disallowed if 455130803Smarcel * socktype/protocol are left unspecified. (2) servname is disallowed 456130803Smarcel * for raw and other inet{,6} sockets. 457130803Smarcel */ 458130803Smarcel if (MATCH_FAMILY(pai->ai_family, PF_INET, 1) 459130803Smarcel#ifdef PF_INET6 460130803Smarcel || MATCH_FAMILY(pai->ai_family, PF_INET6, 1) 461130803Smarcel#endif 462130803Smarcel ) { 463130803Smarcel ai0 = *pai; /* backup *pai */ 464130803Smarcel 465130803Smarcel if (pai->ai_family == PF_UNSPEC) { 466130803Smarcel#ifdef PF_INET6 467130803Smarcel pai->ai_family = PF_INET6; 468130803Smarcel#else 469130803Smarcel pai->ai_family = PF_INET; 470130803Smarcel#endif 471130803Smarcel } 472130803Smarcel error = get_portmatch(pai, servname); 473130803Smarcel if (error) 474130803Smarcel goto bad; 475130803Smarcel 476130803Smarcel *pai = ai0; 477130803Smarcel } 478130803Smarcel 479130803Smarcel ai0 = *pai; 480130803Smarcel 481130803Smarcel /* 482130803Smarcel * NULL hostname, or numeric hostname. 483130803Smarcel * If numeric representation of AF1 can be interpreted as FQDN 484130803Smarcel * representation of AF2, we need to think again about the code below. 485130803Smarcel */ 486130803Smarcel found = 0; 487130803Smarcel for (afd = afdl; afd->a_af; afd++) { 488130803Smarcel *pai = ai0; 489130803Smarcel 490130803Smarcel if (!MATCH_FAMILY(pai->ai_family, afd->a_af, 1)) 491130803Smarcel continue; 492130803Smarcel 493130803Smarcel if (pai->ai_family == PF_UNSPEC) 494130803Smarcel pai->ai_family = afd->a_af; 495130803Smarcel 496130803Smarcel if (hostname == NULL) { 497130803Smarcel error = explore_null(pai, servname, 498130803Smarcel &afailist[afd - afdl]); 499130803Smarcel 500130803Smarcel /* 501130803Smarcel * Errors from explore_null should be unexpected and 502130803Smarcel * be caught to avoid returning an incomplete result. 503130803Smarcel */ 504130803Smarcel if (error != 0) 505130803Smarcel goto bad; 506130803Smarcel } else { 507130803Smarcel error = explore_numeric_scope(pai, hostname, servname, 508130803Smarcel &afailist[afd - afdl]); 509130803Smarcel 510130803Smarcel /* 511130803Smarcel * explore_numeric_scope returns an error for address 512130803Smarcel * families that do not match that of hostname. 513130803Smarcel * Thus we should not catch the error at this moment. 514130803Smarcel */ 515130803Smarcel } 516130803Smarcel 517130803Smarcel if (!error && afailist[afd - afdl]) 518130803Smarcel found++; 519130803Smarcel } 520130803Smarcel if (found) { 521130803Smarcel numeric = 1; 522130803Smarcel goto globcopy; 523130803Smarcel } 524130803Smarcel 525130803Smarcel if (hostname == NULL) 526130803Smarcel ERR(EAI_NONAME); /* used to be EAI_NODATA */ 527130803Smarcel if (pai->ai_flags & AI_NUMERICHOST) 528130803Smarcel ERR(EAI_NONAME); 529130803Smarcel 530130803Smarcel if ((pai->ai_flags & AI_ADDRCONFIG) != 0 && !addrconfig(&ai0)) 531130803Smarcel ERR(EAI_FAIL); 532130803Smarcel 533130803Smarcel /* 534130803Smarcel * hostname as alphabetical name. 535130803Smarcel */ 536130803Smarcel *pai = ai0; 537130803Smarcel error = explore_fqdn(pai, hostname, servname, &afai_unspec); 538130803Smarcel 539130803Smarcelglobcopy: 540130803Smarcel for (ex = explore; ex->e_af >= 0; ex++) { 541130803Smarcel *pai = ai0; 542130803Smarcel 543130803Smarcel if (!MATCH_FAMILY(pai->ai_family, ex->e_af, WILD_AF(ex))) 544130803Smarcel continue; 545130803Smarcel if (!MATCH(pai->ai_socktype, ex->e_socktype, 546130803Smarcel WILD_SOCKTYPE(ex))) 547130803Smarcel continue; 548130803Smarcel if (!MATCH(pai->ai_protocol, ex->e_protocol, 549130803Smarcel WILD_PROTOCOL(ex))) 550130803Smarcel continue; 551130803Smarcel 552130803Smarcel if (pai->ai_family == PF_UNSPEC) 553130803Smarcel pai->ai_family = ex->e_af; 554130803Smarcel if (pai->ai_socktype == ANY && ex->e_socktype != ANY) 555130803Smarcel pai->ai_socktype = ex->e_socktype; 556130803Smarcel if (pai->ai_protocol == ANY && ex->e_protocol != ANY) 557130803Smarcel pai->ai_protocol = ex->e_protocol; 558130803Smarcel 559130803Smarcel /* 560130803Smarcel * if the servname does not match socktype/protocol, ignore it. 561130803Smarcel */ 562130803Smarcel if (get_portmatch(pai, servname) != 0) 563130803Smarcel continue; 564130803Smarcel 565130803Smarcel if (afai_unspec) 566130803Smarcel afai = afai_unspec; 567130803Smarcel else { 568130803Smarcel if ((afd = find_afd(pai->ai_family)) == NULL) 569130803Smarcel continue; 570130803Smarcel /* XXX assumes that afd points inside afdl[] */ 571130803Smarcel afai = afailist[afd - afdl]; 572130803Smarcel } 573130803Smarcel if (!afai) 574130803Smarcel continue; 575130803Smarcel 576130803Smarcel error = explore_copy(pai, afai, &cur->ai_next); 577130803Smarcel if (error != 0) 578130803Smarcel goto bad; 579130803Smarcel 580130803Smarcel while (cur && cur->ai_next) 581130803Smarcel cur = cur->ai_next; 582130803Smarcel } 583130803Smarcel 584130803Smarcel /* 585130803Smarcel * ensure we return either: 586130803Smarcel * - error == 0, non-NULL *res 587130803Smarcel * - error != 0, NULL *res 588130803Smarcel */ 589130803Smarcel if (error == 0) { 590130803Smarcel if (sentinel.ai_next) { 591130803Smarcel /* 592130803Smarcel * If the returned entry is for an active connection, 593130803Smarcel * and the given name is not numeric, reorder the 594130803Smarcel * list, so that the application would try the list 595130803Smarcel * in the most efficient order. Since the head entry 596130803Smarcel * of the original list may contain ai_canonname and 597130803Smarcel * that entry may be moved elsewhere in the new list, 598130803Smarcel * we keep the pointer and will restore it in the new 599130803Smarcel * head entry. (Note that RFC3493 requires the head 600130803Smarcel * entry store it when requested by the caller). 601130803Smarcel */ 602130803Smarcel if (hints == NULL || !(hints->ai_flags & AI_PASSIVE)) { 603130803Smarcel if (!numeric) { 604130803Smarcel char *canonname; 605130803Smarcel 606130803Smarcel canonname = 607130803Smarcel sentinel.ai_next->ai_canonname; 608130803Smarcel sentinel.ai_next->ai_canonname = NULL; 609130803Smarcel (void)reorder(&sentinel); 610130803Smarcel if (sentinel.ai_next->ai_canonname == 611130803Smarcel NULL) { 612130803Smarcel sentinel.ai_next->ai_canonname 613130803Smarcel = canonname; 614130803Smarcel } else if (canonname != NULL) 615130803Smarcel free(canonname); 616130803Smarcel } 617130803Smarcel } 618130803Smarcel *res = sentinel.ai_next; 619130803Smarcel } else 620130803Smarcel error = EAI_FAIL; 621130803Smarcel } 622130803Smarcel 623130803Smarcelbad: 624130803Smarcel if (afai_unspec) 625130803Smarcel freeaddrinfo(afai_unspec); 626130803Smarcel for (afd = afdl; afd->a_af; afd++) { 627130803Smarcel if (afailist[afd - afdl]) 628130803Smarcel freeaddrinfo(afailist[afd - afdl]); 629130803Smarcel } 630130803Smarcel if (!*res) 631130803Smarcel if (sentinel.ai_next) 632130803Smarcel freeaddrinfo(sentinel.ai_next); 633130803Smarcel 634130803Smarcel return (error); 635130803Smarcel} 636130803Smarcel 637130803Smarcelstatic int 638130803Smarcelreorder(struct addrinfo *sentinel) 639130803Smarcel{ 640130803Smarcel struct addrinfo *ai, **aip; 641130803Smarcel struct ai_order *aio; 642130803Smarcel int i, n; 643130803Smarcel struct policyhead policyhead; 644130803Smarcel 645130803Smarcel /* count the number of addrinfo elements for sorting. */ 646130803Smarcel for (n = 0, ai = sentinel->ai_next; ai != NULL; ai = ai->ai_next, n++) 647130803Smarcel ; 648130803Smarcel 649130803Smarcel /* 650130803Smarcel * If the number is small enough, we can skip the reordering process. 651130803Smarcel */ 652130803Smarcel if (n <= 1) 653130803Smarcel return(n); 654130803Smarcel 655130803Smarcel /* allocate a temporary array for sort and initialization of it. */ 656130803Smarcel if ((aio = malloc(sizeof(*aio) * n)) == NULL) 657130803Smarcel return(n); /* give up reordering */ 658130803Smarcel memset(aio, 0, sizeof(*aio) * n); 659130803Smarcel 660130803Smarcel /* retrieve address selection policy from the kernel */ 661130803Smarcel TAILQ_INIT(&policyhead); 662130803Smarcel if (!get_addrselectpolicy(&policyhead)) { 663130803Smarcel /* no policy is installed into kernel, we don't sort. */ 664130803Smarcel free(aio); 665130803Smarcel return (n); 666130803Smarcel } 667130803Smarcel 668130803Smarcel for (i = 0, ai = sentinel->ai_next; i < n; ai = ai->ai_next, i++) { 669130803Smarcel aio[i].aio_ai = ai; 670130803Smarcel aio[i].aio_dstscope = gai_addr2scopetype(ai->ai_addr); 671130803Smarcel aio[i].aio_dstpolicy = match_addrselectpolicy(ai->ai_addr, 672130803Smarcel &policyhead); 673130803Smarcel set_source(&aio[i], &policyhead); 674130803Smarcel } 675130803Smarcel 676130803Smarcel /* perform sorting. */ 677130803Smarcel qsort(aio, n, sizeof(*aio), comp_dst); 678130803Smarcel 679130803Smarcel /* reorder the addrinfo chain. */ 680130803Smarcel for (i = 0, aip = &sentinel->ai_next; i < n; i++) { 681130803Smarcel *aip = aio[i].aio_ai; 682130803Smarcel aip = &aio[i].aio_ai->ai_next; 683130803Smarcel } 684130803Smarcel *aip = NULL; 685130803Smarcel 686130803Smarcel /* cleanup and return */ 687130803Smarcel free(aio); 688130803Smarcel free_addrselectpolicy(&policyhead); 689130803Smarcel return(n); 690130803Smarcel} 691130803Smarcel 692130803Smarcelstatic int 693130803Smarcelget_addrselectpolicy(struct policyhead *head) 694130803Smarcel{ 695130803Smarcel#ifdef INET6 696130803Smarcel int mib[] = { CTL_NET, PF_INET6, IPPROTO_IPV6, IPV6CTL_ADDRCTLPOLICY }; 697130803Smarcel size_t l; 698130803Smarcel char *buf; 699130803Smarcel struct in6_addrpolicy *pol, *ep; 700130803Smarcel 701130803Smarcel if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), NULL, &l, NULL, 0) < 0) 702130803Smarcel return (0); 703130803Smarcel if (l == 0) 704130803Smarcel return (0); 705130803Smarcel if ((buf = malloc(l)) == NULL) 706130803Smarcel return (0); 707130803Smarcel if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), buf, &l, NULL, 0) < 0) { 708130803Smarcel free(buf); 709130803Smarcel return (0); 710130803Smarcel } 711130803Smarcel 712130803Smarcel ep = (struct in6_addrpolicy *)(buf + l); 713130803Smarcel for (pol = (struct in6_addrpolicy *)buf; pol + 1 <= ep; pol++) { 714130803Smarcel struct policyqueue *new; 715130803Smarcel 716130803Smarcel if ((new = malloc(sizeof(*new))) == NULL) { 717130803Smarcel free_addrselectpolicy(head); /* make the list empty */ 718130803Smarcel break; 719130803Smarcel } 720130803Smarcel new->pc_policy = *pol; 721130803Smarcel TAILQ_INSERT_TAIL(head, new, pc_entry); 722130803Smarcel } 723130803Smarcel 724130803Smarcel free(buf); 725130803Smarcel return (1); 726130803Smarcel#else 727130803Smarcel return (0); 728130803Smarcel#endif 729130803Smarcel} 730130803Smarcel 731130803Smarcelstatic void 732130803Smarcelfree_addrselectpolicy(struct policyhead *head) 733130803Smarcel{ 734130803Smarcel struct policyqueue *ent, *nent; 735130803Smarcel 736130803Smarcel for (ent = TAILQ_FIRST(head); ent; ent = nent) { 737130803Smarcel nent = TAILQ_NEXT(ent, pc_entry); 738130803Smarcel TAILQ_REMOVE(head, ent, pc_entry); 739130803Smarcel free(ent); 740130803Smarcel } 741130803Smarcel} 742130803Smarcel 743130803Smarcelstatic struct policyqueue * 744130803Smarcelmatch_addrselectpolicy(struct sockaddr *addr, struct policyhead *head) 745130803Smarcel{ 746130803Smarcel#ifdef INET6 747130803Smarcel struct policyqueue *ent, *bestent = NULL; 748130803Smarcel struct in6_addrpolicy *pol; 749130803Smarcel int matchlen, bestmatchlen = -1; 750130803Smarcel u_char *mp, *ep, *k, *p, m; 751130803Smarcel struct sockaddr_in6 key; 752130803Smarcel 753130803Smarcel switch(addr->sa_family) { 754130803Smarcel case AF_INET6: 755130803Smarcel key = *(struct sockaddr_in6 *)addr; 756130803Smarcel break; 757130803Smarcel case AF_INET: 758130803Smarcel /* convert the address into IPv4-mapped IPv6 address. */ 759130803Smarcel memset(&key, 0, sizeof(key)); 760130803Smarcel key.sin6_family = AF_INET6; 761130803Smarcel key.sin6_len = sizeof(key); 762130803Smarcel key.sin6_addr.s6_addr[10] = 0xff; 763130803Smarcel key.sin6_addr.s6_addr[11] = 0xff; 764130803Smarcel memcpy(&key.sin6_addr.s6_addr[12], 765130803Smarcel &((struct sockaddr_in *)addr)->sin_addr, 4); 766130803Smarcel break; 767130803Smarcel default: 768130803Smarcel return(NULL); 769130803Smarcel } 770130803Smarcel 771130803Smarcel for (ent = TAILQ_FIRST(head); ent; ent = TAILQ_NEXT(ent, pc_entry)) { 772130803Smarcel pol = &ent->pc_policy; 773130803Smarcel matchlen = 0; 774130803Smarcel 775130803Smarcel mp = (u_char *)&pol->addrmask.sin6_addr; 776130803Smarcel ep = mp + 16; /* XXX: scope field? */ 777130803Smarcel k = (u_char *)&key.sin6_addr; 778130803Smarcel p = (u_char *)&pol->addr.sin6_addr; 779130803Smarcel for (; mp < ep && *mp; mp++, k++, p++) { 780130803Smarcel m = *mp; 781130803Smarcel if ((*k & m) != *p) 782130803Smarcel goto next; /* not match */ 783130803Smarcel if (m == 0xff) /* short cut for a typical case */ 784130803Smarcel matchlen += 8; 785130803Smarcel else { 786130803Smarcel while (m >= 0x80) { 787130803Smarcel matchlen++; 788130803Smarcel m <<= 1; 789130803Smarcel } 790130803Smarcel } 791130803Smarcel } 792130803Smarcel 793130803Smarcel /* matched. check if this is better than the current best. */ 794130803Smarcel if (matchlen > bestmatchlen) { 795130803Smarcel bestent = ent; 796130803Smarcel bestmatchlen = matchlen; 797130803Smarcel } 798130803Smarcel 799130803Smarcel next: 800130803Smarcel continue; 801130803Smarcel } 802130803Smarcel 803130803Smarcel return(bestent); 804130803Smarcel#else 805130803Smarcel return(NULL); 806130803Smarcel#endif 807130803Smarcel 808130803Smarcel} 809130803Smarcel 810130803Smarcelstatic void 811130803Smarcelset_source(struct ai_order *aio, struct policyhead *ph) 812130803Smarcel{ 813130803Smarcel struct addrinfo ai = *aio->aio_ai; 814130803Smarcel struct sockaddr_storage ss; 815130803Smarcel socklen_t srclen; 816130803Smarcel int s; 817130803Smarcel 818130803Smarcel /* set unspec ("no source is available"), just in case */ 819130803Smarcel aio->aio_srcsa.sa_family = AF_UNSPEC; 820130803Smarcel aio->aio_srcscope = -1; 821130803Smarcel 822130803Smarcel switch(ai.ai_family) { 823130803Smarcel case AF_INET: 824130803Smarcel#ifdef INET6 825130803Smarcel case AF_INET6: 826130803Smarcel#endif 827130803Smarcel break; 828130803Smarcel default: /* ignore unsupported AFs explicitly */ 829130803Smarcel return; 830130803Smarcel } 831130803Smarcel 832130803Smarcel /* XXX: make a dummy addrinfo to call connect() */ 833130803Smarcel ai.ai_socktype = SOCK_DGRAM; 834130803Smarcel ai.ai_protocol = IPPROTO_UDP; /* is UDP too specific? */ 835130803Smarcel ai.ai_next = NULL; 836130803Smarcel memset(&ss, 0, sizeof(ss)); 837130803Smarcel memcpy(&ss, ai.ai_addr, ai.ai_addrlen); 838130803Smarcel ai.ai_addr = (struct sockaddr *)&ss; 839130803Smarcel get_port(&ai, "1", 0); 840130803Smarcel 841130803Smarcel /* open a socket to get the source address for the given dst */ 842130803Smarcel if ((s = _socket(ai.ai_family, ai.ai_socktype | SOCK_CLOEXEC, 843130803Smarcel ai.ai_protocol)) < 0) 844130803Smarcel return; /* give up */ 845130803Smarcel if (_connect(s, ai.ai_addr, ai.ai_addrlen) < 0) 846130803Smarcel goto cleanup; 847130803Smarcel srclen = ai.ai_addrlen; 848130803Smarcel if (_getsockname(s, &aio->aio_srcsa, &srclen) < 0) { 849130803Smarcel aio->aio_srcsa.sa_family = AF_UNSPEC; 850130803Smarcel goto cleanup; 851130803Smarcel } 852130803Smarcel aio->aio_srcscope = gai_addr2scopetype(&aio->aio_srcsa); 853130803Smarcel aio->aio_srcpolicy = match_addrselectpolicy(&aio->aio_srcsa, ph); 854130803Smarcel aio->aio_matchlen = matchlen(&aio->aio_srcsa, aio->aio_ai->ai_addr); 855130803Smarcel#ifdef INET6 856130803Smarcel if (ai.ai_family == AF_INET6) { 857130803Smarcel struct in6_ifreq ifr6; 858130803Smarcel u_int32_t flags6; 859130803Smarcel 860130803Smarcel memset(&ifr6, 0, sizeof(ifr6)); 861130803Smarcel memcpy(&ifr6.ifr_addr, ai.ai_addr, ai.ai_addrlen); 862130803Smarcel if (_ioctl(s, SIOCGIFAFLAG_IN6, &ifr6) == 0) { 863130803Smarcel flags6 = ifr6.ifr_ifru.ifru_flags6; 864130803Smarcel if ((flags6 & IN6_IFF_DEPRECATED)) 865130803Smarcel aio->aio_srcflag |= AIO_SRCFLAG_DEPRECATED; 866130803Smarcel } 867130803Smarcel } 868130803Smarcel#endif 869130803Smarcel 870130803Smarcel cleanup: 871130803Smarcel _close(s); 872130803Smarcel return; 873130803Smarcel} 874130803Smarcel 875130803Smarcelstatic int 876130803Smarcelmatchlen(struct sockaddr *src, struct sockaddr *dst) 877130803Smarcel{ 878130803Smarcel int match = 0; 879130803Smarcel u_char *s, *d; 880130803Smarcel u_char *lim, r; 881130803Smarcel int addrlen; 882130803Smarcel 883130803Smarcel switch (src->sa_family) { 884130803Smarcel#ifdef INET6 885130803Smarcel case AF_INET6: 886130803Smarcel s = (u_char *)&((struct sockaddr_in6 *)src)->sin6_addr; 887130803Smarcel d = (u_char *)&((struct sockaddr_in6 *)dst)->sin6_addr; 888130803Smarcel addrlen = sizeof(struct in6_addr); 889130803Smarcel lim = s + addrlen; 890130803Smarcel break; 891130803Smarcel#endif 892130803Smarcel case AF_INET: 893130803Smarcel s = (u_char *)&((struct sockaddr_in *)src)->sin_addr; 894130803Smarcel d = (u_char *)&((struct sockaddr_in *)dst)->sin_addr; 895130803Smarcel addrlen = sizeof(struct in_addr); 896130803Smarcel lim = s + addrlen; 897130803Smarcel break; 898130803Smarcel default: 899130803Smarcel return(0); 900130803Smarcel } 901130803Smarcel 902130803Smarcel while (s < lim) 903130803Smarcel if ((r = (*d++ ^ *s++)) != 0) { 904130803Smarcel while (r < addrlen * 8) { 905130803Smarcel match++; 906130803Smarcel r <<= 1; 907130803Smarcel } 908130803Smarcel break; 909130803Smarcel } else 910130803Smarcel match += 8; 911130803Smarcel return(match); 912130803Smarcel} 913130803Smarcel 914130803Smarcelstatic int 915130803Smarcelcomp_dst(const void *arg1, const void *arg2) 916130803Smarcel{ 917130803Smarcel const struct ai_order *dst1 = arg1, *dst2 = arg2; 918130803Smarcel 919130803Smarcel /* 920130803Smarcel * Rule 1: Avoid unusable destinations. 921130803Smarcel * XXX: we currently do not consider if an appropriate route exists. 922130803Smarcel */ 923130803Smarcel if (dst1->aio_srcsa.sa_family != AF_UNSPEC && 924130803Smarcel dst2->aio_srcsa.sa_family == AF_UNSPEC) { 925130803Smarcel return(-1); 926130803Smarcel } 927130803Smarcel if (dst1->aio_srcsa.sa_family == AF_UNSPEC && 928130803Smarcel dst2->aio_srcsa.sa_family != AF_UNSPEC) { 929130803Smarcel return(1); 930130803Smarcel } 931130803Smarcel 932130803Smarcel /* Rule 2: Prefer matching scope. */ 933130803Smarcel if (dst1->aio_dstscope == dst1->aio_srcscope && 934130803Smarcel dst2->aio_dstscope != dst2->aio_srcscope) { 935130803Smarcel return(-1); 936130803Smarcel } 937130803Smarcel if (dst1->aio_dstscope != dst1->aio_srcscope && 938130803Smarcel dst2->aio_dstscope == dst2->aio_srcscope) { 939130803Smarcel return(1); 940130803Smarcel } 941130803Smarcel 942130803Smarcel /* Rule 3: Avoid deprecated addresses. */ 943130803Smarcel if (dst1->aio_srcsa.sa_family != AF_UNSPEC && 944130803Smarcel dst2->aio_srcsa.sa_family != AF_UNSPEC) { 945130803Smarcel if (!(dst1->aio_srcflag & AIO_SRCFLAG_DEPRECATED) && 946130803Smarcel (dst2->aio_srcflag & AIO_SRCFLAG_DEPRECATED)) { 947130803Smarcel return(-1); 948130803Smarcel } 949130803Smarcel if ((dst1->aio_srcflag & AIO_SRCFLAG_DEPRECATED) && 950130803Smarcel !(dst2->aio_srcflag & AIO_SRCFLAG_DEPRECATED)) { 951130803Smarcel return(1); 952130803Smarcel } 953130803Smarcel } 954130803Smarcel 955130803Smarcel /* Rule 4: Prefer home addresses. */ 956130803Smarcel /* XXX: not implemented yet */ 957130803Smarcel 958130803Smarcel /* Rule 5: Prefer matching label. */ 959130803Smarcel#ifdef INET6 960130803Smarcel if (dst1->aio_srcpolicy && dst1->aio_dstpolicy && 961130803Smarcel dst1->aio_srcpolicy->pc_policy.label == 962130803Smarcel dst1->aio_dstpolicy->pc_policy.label && 963130803Smarcel (dst2->aio_srcpolicy == NULL || dst2->aio_dstpolicy == NULL || 964130803Smarcel dst2->aio_srcpolicy->pc_policy.label != 965130803Smarcel dst2->aio_dstpolicy->pc_policy.label)) { 966130803Smarcel return(-1); 967130803Smarcel } 968130803Smarcel if (dst2->aio_srcpolicy && dst2->aio_dstpolicy && 969130803Smarcel dst2->aio_srcpolicy->pc_policy.label == 970130803Smarcel dst2->aio_dstpolicy->pc_policy.label && 971130803Smarcel (dst1->aio_srcpolicy == NULL || dst1->aio_dstpolicy == NULL || 972130803Smarcel dst1->aio_srcpolicy->pc_policy.label != 973130803Smarcel dst1->aio_dstpolicy->pc_policy.label)) { 974130803Smarcel return(1); 975130803Smarcel } 976130803Smarcel#endif 977130803Smarcel 978130803Smarcel /* Rule 6: Prefer higher precedence. */ 979130803Smarcel#ifdef INET6 980130803Smarcel if (dst1->aio_dstpolicy && 981130803Smarcel (dst2->aio_dstpolicy == NULL || 982130803Smarcel dst1->aio_dstpolicy->pc_policy.preced > 983130803Smarcel dst2->aio_dstpolicy->pc_policy.preced)) { 984130803Smarcel return(-1); 985130803Smarcel } 986130803Smarcel if (dst2->aio_dstpolicy && 987130803Smarcel (dst1->aio_dstpolicy == NULL || 988130803Smarcel dst2->aio_dstpolicy->pc_policy.preced > 989130803Smarcel dst1->aio_dstpolicy->pc_policy.preced)) { 990130803Smarcel return(1); 991130803Smarcel } 992130803Smarcel#endif 993130803Smarcel 994130803Smarcel /* Rule 7: Prefer native transport. */ 995130803Smarcel /* XXX: not implemented yet */ 996130803Smarcel 997130803Smarcel /* Rule 8: Prefer smaller scope. */ 998130803Smarcel if (dst1->aio_dstscope >= 0 && 999130803Smarcel dst1->aio_dstscope < dst2->aio_dstscope) { 1000130803Smarcel return(-1); 1001130803Smarcel } 1002130803Smarcel if (dst2->aio_dstscope >= 0 && 1003130803Smarcel dst2->aio_dstscope < dst1->aio_dstscope) { 1004130803Smarcel return(1); 1005130803Smarcel } 1006130803Smarcel 1007130803Smarcel /* 1008130803Smarcel * Rule 9: Use longest matching prefix. 1009130803Smarcel * We compare the match length in a same AF only. 1010130803Smarcel */ 1011130803Smarcel if (dst1->aio_ai->ai_addr->sa_family == 1012130803Smarcel dst2->aio_ai->ai_addr->sa_family && 1013130803Smarcel dst1->aio_ai->ai_addr->sa_family != AF_INET) { 1014130803Smarcel if (dst1->aio_matchlen > dst2->aio_matchlen) { 1015130803Smarcel return(-1); 1016130803Smarcel } 1017130803Smarcel if (dst1->aio_matchlen < dst2->aio_matchlen) { 1018130803Smarcel return(1); 1019130803Smarcel } 1020130803Smarcel } 1021130803Smarcel 1022130803Smarcel /* Rule 10: Otherwise, leave the order unchanged. */ 1023130803Smarcel return(-1); 1024130803Smarcel} 1025130803Smarcel 1026130803Smarcel/* 1027130803Smarcel * Copy from scope.c. 1028130803Smarcel * XXX: we should standardize the functions and link them as standard 1029130803Smarcel * library. 1030130803Smarcel */ 1031130803Smarcelstatic int 1032130803Smarcelgai_addr2scopetype(struct sockaddr *sa) 1033130803Smarcel{ 1034130803Smarcel#ifdef INET6 1035130803Smarcel struct sockaddr_in6 *sa6; 1036130803Smarcel#endif 1037130803Smarcel struct sockaddr_in *sa4; 1038130803Smarcel 1039130803Smarcel switch(sa->sa_family) { 1040130803Smarcel#ifdef INET6 1041130803Smarcel case AF_INET6: 1042130803Smarcel sa6 = (struct sockaddr_in6 *)sa; 1043130803Smarcel if (IN6_IS_ADDR_MULTICAST(&sa6->sin6_addr)) { 1044130803Smarcel /* just use the scope field of the multicast address */ 1045130803Smarcel return(sa6->sin6_addr.s6_addr[2] & 0x0f); 1046130803Smarcel } 1047130803Smarcel /* 1048130803Smarcel * Unicast addresses: map scope type to corresponding scope 1049130803Smarcel * value defined for multcast addresses. 1050130803Smarcel * XXX: hardcoded scope type values are bad... 1051130803Smarcel */ 1052130803Smarcel if (IN6_IS_ADDR_LOOPBACK(&sa6->sin6_addr)) 1053130803Smarcel return(1); /* node local scope */ 1054130803Smarcel if (IN6_IS_ADDR_LINKLOCAL(&sa6->sin6_addr)) 1055130803Smarcel return(2); /* link-local scope */ 1056130803Smarcel if (IN6_IS_ADDR_SITELOCAL(&sa6->sin6_addr)) 1057130803Smarcel return(5); /* site-local scope */ 1058130803Smarcel return(14); /* global scope */ 1059130803Smarcel break; 1060130803Smarcel#endif 1061130803Smarcel case AF_INET: 1062130803Smarcel /* 1063130803Smarcel * IPv4 pseudo scoping according to RFC 3484. 1064130803Smarcel */ 1065130803Smarcel sa4 = (struct sockaddr_in *)sa; 1066130803Smarcel /* IPv4 autoconfiguration addresses have link-local scope. */ 1067130803Smarcel if (((u_char *)&sa4->sin_addr)[0] == 169 && 1068130803Smarcel ((u_char *)&sa4->sin_addr)[1] == 254) 1069130803Smarcel return(2); 1070130803Smarcel /* Private addresses have site-local scope. */ 1071130803Smarcel if (((u_char *)&sa4->sin_addr)[0] == 10 || 1072130803Smarcel (((u_char *)&sa4->sin_addr)[0] == 172 && 1073130803Smarcel (((u_char *)&sa4->sin_addr)[1] & 0xf0) == 16) || 1074130803Smarcel (((u_char *)&sa4->sin_addr)[0] == 192 && 1075130803Smarcel ((u_char *)&sa4->sin_addr)[1] == 168)) 1076130803Smarcel return(14); /* XXX: It should be 5 unless NAT */ 1077130803Smarcel /* Loopback addresses have link-local scope. */ 1078130803Smarcel if (((u_char *)&sa4->sin_addr)[0] == 127) 1079130803Smarcel return(2); 1080130803Smarcel return(14); 1081130803Smarcel break; 1082130803Smarcel default: 1083130803Smarcel errno = EAFNOSUPPORT; /* is this a good error? */ 1084130803Smarcel return(-1); 1085130803Smarcel } 1086130803Smarcel} 1087130803Smarcel 1088130803Smarcelstatic int 1089130803Smarcelexplore_copy(const struct addrinfo *pai, const struct addrinfo *src0, 1090130803Smarcel struct addrinfo **res) 1091130803Smarcel{ 1092130803Smarcel int error; 1093130803Smarcel struct addrinfo sentinel, *cur; 1094130803Smarcel const struct addrinfo *src; 1095130803Smarcel 1096130803Smarcel error = 0; 1097130803Smarcel sentinel.ai_next = NULL; 1098130803Smarcel cur = &sentinel; 1099130803Smarcel 1100130803Smarcel for (src = src0; src != NULL; src = src->ai_next) { 1101130803Smarcel if (src->ai_family != pai->ai_family) 1102130803Smarcel continue; 1103130803Smarcel 1104130803Smarcel cur->ai_next = copy_ai(src); 1105130803Smarcel if (!cur->ai_next) { 1106130803Smarcel error = EAI_MEMORY; 1107130803Smarcel goto fail; 1108130803Smarcel } 1109130803Smarcel 1110130803Smarcel cur->ai_next->ai_socktype = pai->ai_socktype; 1111130803Smarcel cur->ai_next->ai_protocol = pai->ai_protocol; 1112130803Smarcel cur = cur->ai_next; 1113130803Smarcel } 1114130803Smarcel 1115130803Smarcel *res = sentinel.ai_next; 1116130803Smarcel return 0; 1117130803Smarcel 1118130803Smarcelfail: 1119130803Smarcel freeaddrinfo(sentinel.ai_next); 1120130803Smarcel return error; 1121130803Smarcel} 1122130803Smarcel 1123130803Smarcel/* 1124130803Smarcel * hostname == NULL. 1125130803Smarcel * passive socket -> anyaddr (0.0.0.0 or ::) 1126130803Smarcel * non-passive socket -> localhost (127.0.0.1 or ::1) 1127130803Smarcel */ 1128130803Smarcelstatic int 1129130803Smarcelexplore_null(const struct addrinfo *pai, const char *servname, 1130130803Smarcel struct addrinfo **res) 1131130803Smarcel{ 1132130803Smarcel int s; 1133130803Smarcel const struct afd *afd; 1134130803Smarcel struct addrinfo *ai; 1135130803Smarcel int error; 1136130803Smarcel 1137130803Smarcel *res = NULL; 1138130803Smarcel ai = NULL; 1139130803Smarcel 1140130803Smarcel /* 1141130803Smarcel * filter out AFs that are not supported by the kernel 1142130803Smarcel * XXX errno? 1143130803Smarcel */ 1144130803Smarcel s = _socket(pai->ai_family, SOCK_DGRAM | SOCK_CLOEXEC, 0); 1145130803Smarcel if (s < 0) { 1146130803Smarcel if (errno != EMFILE) 1147130803Smarcel return 0; 1148130803Smarcel } else 1149130803Smarcel _close(s); 1150130803Smarcel 1151130803Smarcel afd = find_afd(pai->ai_family); 1152130803Smarcel if (afd == NULL) 1153130803Smarcel return 0; 1154130803Smarcel 1155130803Smarcel if (pai->ai_flags & AI_PASSIVE) { 1156130803Smarcel GET_AI(ai, afd, afd->a_addrany); 1157130803Smarcel GET_PORT(ai, servname); 1158130803Smarcel } else { 1159130803Smarcel GET_AI(ai, afd, afd->a_loopback); 1160130803Smarcel GET_PORT(ai, servname); 1161130803Smarcel } 1162130803Smarcel 1163130803Smarcel *res = ai; 1164130803Smarcel return 0; 1165130803Smarcel 1166130803Smarcelfree: 1167130803Smarcel if (ai != NULL) 1168130803Smarcel freeaddrinfo(ai); 1169130803Smarcel return error; 1170130803Smarcel} 1171130803Smarcel 1172130803Smarcel/* 1173130803Smarcel * numeric hostname 1174130803Smarcel */ 1175130803Smarcelstatic int 1176130803Smarcelexplore_numeric(const struct addrinfo *pai, const char *hostname, 1177130803Smarcel const char *servname, struct addrinfo **res, const char *canonname) 1178130803Smarcel{ 1179130803Smarcel const struct afd *afd; 1180130803Smarcel struct addrinfo *ai; 1181130803Smarcel int error; 1182130803Smarcel char pton[PTON_MAX]; 1183130803Smarcel 1184130803Smarcel *res = NULL; 1185130803Smarcel ai = NULL; 1186130803Smarcel 1187130803Smarcel afd = find_afd(pai->ai_family); 1188130803Smarcel if (afd == NULL) 1189130803Smarcel return 0; 1190130803Smarcel 1191130803Smarcel switch (afd->a_af) { 1192130803Smarcel case AF_INET: 1193130803Smarcel /* 1194130803Smarcel * RFC3493 requires getaddrinfo() to accept AF_INET formats 1195130803Smarcel * that are accepted by inet_addr() and its family. The 1196130803Smarcel * accepted forms includes the "classful" one, which inet_pton 1197130803Smarcel * does not accept. So we need to separate the case for 1198130803Smarcel * AF_INET. 1199130803Smarcel */ 1200130803Smarcel if (inet_aton(hostname, (struct in_addr *)pton) != 1) 1201130803Smarcel return 0; 1202130803Smarcel break; 1203130803Smarcel default: 1204130803Smarcel if (inet_pton(afd->a_af, hostname, pton) != 1) 1205130803Smarcel return 0; 1206130803Smarcel break; 1207130803Smarcel } 1208130803Smarcel 1209130803Smarcel if (pai->ai_family == afd->a_af) { 1210130803Smarcel GET_AI(ai, afd, pton); 1211130803Smarcel GET_PORT(ai, servname); 1212130803Smarcel if ((pai->ai_flags & AI_CANONNAME)) { 1213130803Smarcel /* 1214130803Smarcel * Set the numeric address itself as the canonical 1215130803Smarcel * name, based on a clarification in RFC3493. 1216130803Smarcel */ 1217130803Smarcel GET_CANONNAME(ai, canonname); 1218130803Smarcel } 1219130803Smarcel } else { 1220130803Smarcel /* 1221130803Smarcel * XXX: This should not happen since we already matched the AF 1222130803Smarcel * by find_afd. 1223130803Smarcel */ 1224130803Smarcel ERR(EAI_FAMILY); 1225130803Smarcel } 1226130803Smarcel 1227130803Smarcel *res = ai; 1228130803Smarcel return 0; 1229130803Smarcel 1230130803Smarcelfree: 1231130803Smarcelbad: 1232130803Smarcel if (ai != NULL) 1233130803Smarcel freeaddrinfo(ai); 1234130803Smarcel return error; 1235130803Smarcel} 1236130803Smarcel 1237130803Smarcel/* 1238130803Smarcel * numeric hostname with scope 1239130803Smarcel */ 1240130803Smarcelstatic int 1241130803Smarcelexplore_numeric_scope(const struct addrinfo *pai, const char *hostname, 1242130803Smarcel const char *servname, struct addrinfo **res) 1243130803Smarcel{ 1244130803Smarcel#if !defined(SCOPE_DELIMITER) || !defined(INET6) 1245130803Smarcel return explore_numeric(pai, hostname, servname, res, hostname); 1246130803Smarcel#else 1247130803Smarcel const struct afd *afd; 1248 struct addrinfo *cur; 1249 int error; 1250 char *cp, *hostname2 = NULL, *scope, *addr; 1251 struct sockaddr_in6 *sin6; 1252 1253 afd = find_afd(pai->ai_family); 1254 if (afd == NULL) 1255 return 0; 1256 1257 if (!afd->a_scoped) 1258 return explore_numeric(pai, hostname, servname, res, hostname); 1259 1260 cp = strchr(hostname, SCOPE_DELIMITER); 1261 if (cp == NULL) 1262 return explore_numeric(pai, hostname, servname, res, hostname); 1263 1264 /* 1265 * Handle special case of <scoped_address><delimiter><scope id> 1266 */ 1267 hostname2 = strdup(hostname); 1268 if (hostname2 == NULL) 1269 return EAI_MEMORY; 1270 /* terminate at the delimiter */ 1271 hostname2[cp - hostname] = '\0'; 1272 addr = hostname2; 1273 scope = cp + 1; 1274 1275 error = explore_numeric(pai, addr, servname, res, hostname); 1276 if (error == 0) { 1277 u_int32_t scopeid; 1278 1279 for (cur = *res; cur; cur = cur->ai_next) { 1280 if (cur->ai_family != AF_INET6) 1281 continue; 1282 sin6 = (struct sockaddr_in6 *)(void *)cur->ai_addr; 1283 if (ip6_str2scopeid(scope, sin6, &scopeid) == -1) { 1284 free(hostname2); 1285 freeaddrinfo(*res); 1286 *res = NULL; 1287 return(EAI_NONAME); /* XXX: is return OK? */ 1288 } 1289 sin6->sin6_scope_id = scopeid; 1290 } 1291 } 1292 1293 free(hostname2); 1294 1295 if (error && *res) { 1296 freeaddrinfo(*res); 1297 *res = NULL; 1298 } 1299 return error; 1300#endif 1301} 1302 1303static int 1304get_canonname(const struct addrinfo *pai, struct addrinfo *ai, const char *str) 1305{ 1306 if ((pai->ai_flags & AI_CANONNAME) != 0) { 1307 ai->ai_canonname = strdup(str); 1308 if (ai->ai_canonname == NULL) 1309 return EAI_MEMORY; 1310 } 1311 return 0; 1312} 1313 1314static struct addrinfo * 1315get_ai(const struct addrinfo *pai, const struct afd *afd, const char *addr) 1316{ 1317 char *p; 1318 struct addrinfo *ai; 1319#ifdef FAITH 1320 struct in6_addr faith_prefix; 1321 char *fp_str; 1322 int translate = 0; 1323#endif 1324 1325#ifdef FAITH 1326 /* 1327 * Transfrom an IPv4 addr into a special IPv6 addr format for 1328 * IPv6->IPv4 translation gateway. (only TCP is supported now) 1329 * 1330 * +-----------------------------------+------------+ 1331 * | faith prefix part (12 bytes) | embedded | 1332 * | | IPv4 addr part (4 bytes) 1333 * +-----------------------------------+------------+ 1334 * 1335 * faith prefix part is specified as ascii IPv6 addr format 1336 * in environmental variable GAI. 1337 * For FAITH to work correctly, routing to faith prefix must be 1338 * setup toward a machine where a FAITH daemon operates. 1339 * Also, the machine must enable some mechanizm 1340 * (e.g. faith interface hack) to divert those packet with 1341 * faith prefixed destination addr to user-land FAITH daemon. 1342 */ 1343 fp_str = getenv("GAI"); 1344 if (fp_str && inet_pton(AF_INET6, fp_str, &faith_prefix) == 1 && 1345 afd->a_af == AF_INET && pai->ai_socktype == SOCK_STREAM) { 1346 u_int32_t v4a; 1347 u_int8_t v4a_top; 1348 1349 memcpy(&v4a, addr, sizeof v4a); 1350 v4a_top = v4a >> IN_CLASSA_NSHIFT; 1351 if (!IN_MULTICAST(v4a) && !IN_EXPERIMENTAL(v4a) && 1352 v4a_top != 0 && v4a != IN_LOOPBACKNET) { 1353 afd = &afdl[N_INET6]; 1354 memcpy(&faith_prefix.s6_addr[12], addr, 1355 sizeof(struct in_addr)); 1356 translate = 1; 1357 } 1358 } 1359#endif 1360 1361 ai = (struct addrinfo *)malloc(sizeof(struct addrinfo) 1362 + (afd->a_socklen)); 1363 if (ai == NULL) 1364 return NULL; 1365 1366 memcpy(ai, pai, sizeof(struct addrinfo)); 1367 ai->ai_addr = (struct sockaddr *)(void *)(ai + 1); 1368 memset(ai->ai_addr, 0, (size_t)afd->a_socklen); 1369 ai->ai_addr->sa_len = afd->a_socklen; 1370 ai->ai_addrlen = afd->a_socklen; 1371 ai->ai_addr->sa_family = ai->ai_family = afd->a_af; 1372 p = (char *)(void *)(ai->ai_addr); 1373#ifdef FAITH 1374 if (translate == 1) 1375 memcpy(p + afd->a_off, &faith_prefix, (size_t)afd->a_addrlen); 1376 else 1377#endif 1378 memcpy(p + afd->a_off, addr, (size_t)afd->a_addrlen); 1379 return ai; 1380} 1381 1382/* XXX need to malloc() the same way we do from other functions! */ 1383static struct addrinfo * 1384copy_ai(const struct addrinfo *pai) 1385{ 1386 struct addrinfo *ai; 1387 size_t l; 1388 1389 l = sizeof(*ai) + pai->ai_addrlen; 1390 if ((ai = (struct addrinfo *)malloc(l)) == NULL) 1391 return NULL; 1392 memset(ai, 0, l); 1393 memcpy(ai, pai, sizeof(*ai)); 1394 ai->ai_addr = (struct sockaddr *)(void *)(ai + 1); 1395 memcpy(ai->ai_addr, pai->ai_addr, pai->ai_addrlen); 1396 1397 if (pai->ai_canonname) { 1398 l = strlen(pai->ai_canonname) + 1; 1399 if ((ai->ai_canonname = malloc(l)) == NULL) { 1400 free(ai); 1401 return NULL; 1402 } 1403 strlcpy(ai->ai_canonname, pai->ai_canonname, l); 1404 } else { 1405 /* just to make sure */ 1406 ai->ai_canonname = NULL; 1407 } 1408 1409 ai->ai_next = NULL; 1410 1411 return ai; 1412} 1413 1414static int 1415get_portmatch(const struct addrinfo *ai, const char *servname) 1416{ 1417 1418 /* get_port does not touch first argument when matchonly == 1. */ 1419 /* LINTED const cast */ 1420 return get_port((struct addrinfo *)ai, servname, 1); 1421} 1422 1423static int 1424get_port(struct addrinfo *ai, const char *servname, int matchonly) 1425{ 1426 const char *proto; 1427 struct servent *sp; 1428 int port, error; 1429 int allownumeric; 1430 1431 if (servname == NULL) 1432 return 0; 1433 switch (ai->ai_family) { 1434 case AF_INET: 1435#ifdef AF_INET6 1436 case AF_INET6: 1437#endif 1438 break; 1439 default: 1440 return 0; 1441 } 1442 1443 switch (ai->ai_socktype) { 1444 case SOCK_RAW: 1445 return EAI_SERVICE; 1446 case SOCK_DGRAM: 1447 case SOCK_STREAM: 1448 case SOCK_SEQPACKET: 1449 allownumeric = 1; 1450 break; 1451 case ANY: 1452 switch (ai->ai_family) { 1453 case AF_INET: 1454#ifdef AF_INET6 1455 case AF_INET6: 1456#endif 1457 allownumeric = 1; 1458 break; 1459 default: 1460 allownumeric = 0; 1461 break; 1462 } 1463 break; 1464 default: 1465 return EAI_SOCKTYPE; 1466 } 1467 1468 error = str2number(servname, &port); 1469 if (error == 0) { 1470 if (!allownumeric) 1471 return EAI_SERVICE; 1472 if (port < 0 || port > 65535) 1473 return EAI_SERVICE; 1474 port = htons(port); 1475 } else { 1476 if (ai->ai_flags & AI_NUMERICSERV) 1477 return EAI_NONAME; 1478 1479 switch (ai->ai_protocol) { 1480 case IPPROTO_UDP: 1481 proto = "udp"; 1482 break; 1483 case IPPROTO_TCP: 1484 proto = "tcp"; 1485 break; 1486 case IPPROTO_SCTP: 1487 proto = "sctp"; 1488 break; 1489 case IPPROTO_UDPLITE: 1490 proto = "udplite"; 1491 break; 1492 default: 1493 proto = NULL; 1494 break; 1495 } 1496 1497 if ((sp = getservbyname(servname, proto)) == NULL) 1498 return EAI_SERVICE; 1499 port = sp->s_port; 1500 } 1501 1502 if (!matchonly) { 1503 switch (ai->ai_family) { 1504 case AF_INET: 1505 ((struct sockaddr_in *)(void *) 1506 ai->ai_addr)->sin_port = port; 1507 break; 1508#ifdef INET6 1509 case AF_INET6: 1510 ((struct sockaddr_in6 *)(void *) 1511 ai->ai_addr)->sin6_port = port; 1512 break; 1513#endif 1514 } 1515 } 1516 1517 return 0; 1518} 1519 1520static const struct afd * 1521find_afd(int af) 1522{ 1523 const struct afd *afd; 1524 1525 if (af == PF_UNSPEC) 1526 return NULL; 1527 for (afd = afdl; afd->a_af; afd++) { 1528 if (afd->a_af == af) 1529 return afd; 1530 } 1531 return NULL; 1532} 1533 1534/* 1535 * post-2553: AI_ADDRCONFIG check. Determines which address families are 1536 * configured on the local system and correlates with pai->ai_family value. 1537 * If an address family is not configured on the system, it will not be 1538 * queried for. For this purpose, loopback addresses are not considered 1539 * configured addresses. 1540 * 1541 * XXX PF_UNSPEC -> PF_INET6 + PF_INET mapping needs to be in sync with 1542 * _dns_getaddrinfo. 1543 */ 1544static int 1545addrconfig(struct addrinfo *pai) 1546{ 1547 struct ifaddrs *ifaddrs, *ifa; 1548 int seen_inet = 0, seen_inet6 = 0; 1549 1550 if (getifaddrs(&ifaddrs) != 0) 1551 return 0; 1552 1553 for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) { 1554 if (ifa->ifa_addr == NULL || (ifa->ifa_flags & IFF_UP) == 0) 1555 continue; 1556 if ((ifa->ifa_flags & IFT_LOOP) != 0) 1557 continue; 1558 switch (ifa->ifa_addr->sa_family) { 1559 case AF_INET: 1560 seen_inet = 1; 1561 break; 1562#ifdef INET6 1563 case AF_INET6: 1564 if (!seen_inet6 && !is_ifdisabled(ifa->ifa_name)) 1565 seen_inet6 = 1; 1566 break; 1567#endif 1568 } 1569 } 1570 freeifaddrs(ifaddrs); 1571 1572 switch(pai->ai_family) { 1573 case AF_INET6: 1574 return seen_inet6; 1575 case AF_INET: 1576 return seen_inet; 1577 case AF_UNSPEC: 1578 if (seen_inet == seen_inet6) 1579 return seen_inet; 1580 pai->ai_family = seen_inet ? AF_INET : AF_INET6; 1581 return 1; 1582 } 1583 return 1; 1584} 1585 1586#ifdef INET6 1587static int 1588is_ifdisabled(char *name) 1589{ 1590 struct in6_ndireq nd; 1591 int fd; 1592 1593 if ((fd = _socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0)) < 0) 1594 return -1; 1595 memset(&nd, 0, sizeof(nd)); 1596 strlcpy(nd.ifname, name, sizeof(nd.ifname)); 1597 if (_ioctl(fd, SIOCGIFINFO_IN6, &nd) < 0) { 1598 _close(fd); 1599 return -1; 1600 } 1601 _close(fd); 1602 return ((nd.ndi.flags & ND6_IFF_IFDISABLED) != 0); 1603} 1604 1605/* convert a string to a scope identifier. XXX: IPv6 specific */ 1606static int 1607ip6_str2scopeid(char *scope, struct sockaddr_in6 *sin6, u_int32_t *scopeid) 1608{ 1609 u_long lscopeid; 1610 struct in6_addr *a6; 1611 char *ep; 1612 1613 a6 = &sin6->sin6_addr; 1614 1615 /* empty scopeid portion is invalid */ 1616 if (*scope == '\0') 1617 return -1; 1618 1619 if (IN6_IS_ADDR_LINKLOCAL(a6) || IN6_IS_ADDR_MC_LINKLOCAL(a6) || 1620 IN6_IS_ADDR_MC_NODELOCAL(a6)) { 1621 /* 1622 * We currently assume a one-to-one mapping between links 1623 * and interfaces, so we simply use interface indices for 1624 * like-local scopes. 1625 */ 1626 *scopeid = if_nametoindex(scope); 1627 if (*scopeid == 0) 1628 goto trynumeric; 1629 return 0; 1630 } 1631 1632 /* still unclear about literal, allow numeric only - placeholder */ 1633 if (IN6_IS_ADDR_SITELOCAL(a6) || IN6_IS_ADDR_MC_SITELOCAL(a6)) 1634 goto trynumeric; 1635 if (IN6_IS_ADDR_MC_ORGLOCAL(a6)) 1636 goto trynumeric; 1637 else 1638 goto trynumeric; /* global */ 1639 1640 /* try to convert to a numeric id as a last resort */ 1641 trynumeric: 1642 errno = 0; 1643 lscopeid = strtoul(scope, &ep, 10); 1644 *scopeid = (u_int32_t)(lscopeid & 0xffffffffUL); 1645 if (errno == 0 && ep && *ep == '\0' && *scopeid == lscopeid) 1646 return 0; 1647 else 1648 return -1; 1649} 1650#endif 1651 1652 1653#ifdef NS_CACHING 1654static int 1655addrinfo_id_func(char *buffer, size_t *buffer_size, va_list ap, 1656 void *cache_mdata) 1657{ 1658 res_state statp; 1659 u_long res_options; 1660 1661 const int op_id = 0; /* identifies the getaddrinfo for the cache */ 1662 char *hostname; 1663 struct addrinfo *hints; 1664 1665 char *p; 1666 int ai_flags, ai_family, ai_socktype, ai_protocol; 1667 size_t desired_size, size; 1668 1669 statp = __res_state(); 1670 res_options = statp->options & (RES_RECURSE | RES_DEFNAMES | 1671 RES_DNSRCH | RES_NOALIASES | RES_USE_INET6); 1672 1673 hostname = va_arg(ap, char *); 1674 hints = va_arg(ap, struct addrinfo *); 1675 1676 desired_size = sizeof(res_options) + sizeof(int) + sizeof(int) * 4; 1677 if (hostname != NULL) { 1678 size = strlen(hostname); 1679 desired_size += size + 1; 1680 } else 1681 size = 0; 1682 1683 if (desired_size > *buffer_size) { 1684 *buffer_size = desired_size; 1685 return (NS_RETURN); 1686 } 1687 1688 if (hints == NULL) 1689 ai_flags = ai_family = ai_socktype = ai_protocol = 0; 1690 else { 1691 ai_flags = hints->ai_flags; 1692 ai_family = hints->ai_family; 1693 ai_socktype = hints->ai_socktype; 1694 ai_protocol = hints->ai_protocol; 1695 } 1696 1697 p = buffer; 1698 memcpy(p, &res_options, sizeof(res_options)); 1699 p += sizeof(res_options); 1700 1701 memcpy(p, &op_id, sizeof(int)); 1702 p += sizeof(int); 1703 1704 memcpy(p, &ai_flags, sizeof(int)); 1705 p += sizeof(int); 1706 1707 memcpy(p, &ai_family, sizeof(int)); 1708 p += sizeof(int); 1709 1710 memcpy(p, &ai_socktype, sizeof(int)); 1711 p += sizeof(int); 1712 1713 memcpy(p, &ai_protocol, sizeof(int)); 1714 p += sizeof(int); 1715 1716 if (hostname != NULL) 1717 memcpy(p, hostname, size); 1718 1719 *buffer_size = desired_size; 1720 return (NS_SUCCESS); 1721} 1722 1723static int 1724addrinfo_marshal_func(char *buffer, size_t *buffer_size, void *retval, 1725 va_list ap, void *cache_mdata) 1726{ 1727 struct addrinfo *ai, *cai; 1728 char *p; 1729 size_t desired_size, size, ai_size; 1730 1731 ai = *((struct addrinfo **)retval); 1732 1733 desired_size = sizeof(size_t); 1734 ai_size = 0; 1735 for (cai = ai; cai != NULL; cai = cai->ai_next) { 1736 desired_size += sizeof(struct addrinfo) + cai->ai_addrlen; 1737 if (cai->ai_canonname != NULL) 1738 desired_size += sizeof(size_t) + 1739 strlen(cai->ai_canonname); 1740 ++ai_size; 1741 } 1742 1743 if (desired_size > *buffer_size) { 1744 /* this assignment is here for future use */ 1745 errno = ERANGE; 1746 *buffer_size = desired_size; 1747 return (NS_RETURN); 1748 } 1749 1750 memset(buffer, 0, desired_size); 1751 p = buffer; 1752 1753 memcpy(p, &ai_size, sizeof(size_t)); 1754 p += sizeof(size_t); 1755 for (cai = ai; cai != NULL; cai = cai->ai_next) { 1756 memcpy(p, cai, sizeof(struct addrinfo)); 1757 p += sizeof(struct addrinfo); 1758 1759 memcpy(p, cai->ai_addr, cai->ai_addrlen); 1760 p += cai->ai_addrlen; 1761 1762 if (cai->ai_canonname != NULL) { 1763 size = strlen(cai->ai_canonname); 1764 memcpy(p, &size, sizeof(size_t)); 1765 p += sizeof(size_t); 1766 1767 memcpy(p, cai->ai_canonname, size); 1768 p += size; 1769 } 1770 } 1771 1772 return (NS_SUCCESS); 1773} 1774 1775static int 1776addrinfo_unmarshal_func(char *buffer, size_t buffer_size, void *retval, 1777 va_list ap, void *cache_mdata) 1778{ 1779 struct addrinfo new_ai, *result, *sentinel, *lasts; 1780 1781 char *p; 1782 size_t ai_size, ai_i, size; 1783 1784 p = buffer; 1785 memcpy(&ai_size, p, sizeof(size_t)); 1786 p += sizeof(size_t); 1787 1788 result = NULL; 1789 lasts = NULL; 1790 for (ai_i = 0; ai_i < ai_size; ++ai_i) { 1791 memcpy(&new_ai, p, sizeof(struct addrinfo)); 1792 p += sizeof(struct addrinfo); 1793 size = new_ai.ai_addrlen + sizeof(struct addrinfo) + 1794 _ALIGNBYTES; 1795 1796 sentinel = (struct addrinfo *)malloc(size); 1797 memset(sentinel, 0, size); 1798 1799 memcpy(sentinel, &new_ai, sizeof(struct addrinfo)); 1800 sentinel->ai_addr = (struct sockaddr *)_ALIGN((char *)sentinel + 1801 sizeof(struct addrinfo)); 1802 1803 memcpy(sentinel->ai_addr, p, new_ai.ai_addrlen); 1804 p += new_ai.ai_addrlen; 1805 1806 if (new_ai.ai_canonname != NULL) { 1807 memcpy(&size, p, sizeof(size_t)); 1808 p += sizeof(size_t); 1809 1810 sentinel->ai_canonname = (char *)malloc(size + 1); 1811 memset(sentinel->ai_canonname, 0, size + 1); 1812 1813 memcpy(sentinel->ai_canonname, p, size); 1814 p += size; 1815 } 1816 1817 if (result == NULL) { 1818 result = sentinel; 1819 lasts = sentinel; 1820 } else { 1821 lasts->ai_next = sentinel; 1822 lasts = sentinel; 1823 } 1824 } 1825 1826 *((struct addrinfo **)retval) = result; 1827 return (NS_SUCCESS); 1828} 1829#endif /* NS_CACHING */ 1830 1831/* 1832 * FQDN hostname, DNS lookup 1833 */ 1834static int 1835explore_fqdn(const struct addrinfo *pai, const char *hostname, 1836 const char *servname, struct addrinfo **res) 1837{ 1838 struct addrinfo *result; 1839 struct addrinfo *cur; 1840 int error = 0; 1841 1842#ifdef NS_CACHING 1843 static const nss_cache_info cache_info = 1844 NS_COMMON_CACHE_INFO_INITIALIZER( 1845 hosts, NULL, addrinfo_id_func, addrinfo_marshal_func, 1846 addrinfo_unmarshal_func); 1847#endif 1848 static const ns_dtab dtab[] = { 1849 NS_FILES_CB(_files_getaddrinfo, NULL) 1850 { NSSRC_DNS, _dns_getaddrinfo, NULL }, /* force -DHESIOD */ 1851 NS_NIS_CB(_yp_getaddrinfo, NULL) 1852#ifdef NS_CACHING 1853 NS_CACHE_CB(&cache_info) 1854#endif 1855 { 0 } 1856 }; 1857 1858 result = NULL; 1859 1860 /* 1861 * if the servname does not match socktype/protocol, ignore it. 1862 */ 1863 if (get_portmatch(pai, servname) != 0) 1864 return 0; 1865 1866 switch (_nsdispatch(&result, dtab, NSDB_HOSTS, "getaddrinfo", 1867 default_dns_files, hostname, pai)) { 1868 case NS_TRYAGAIN: 1869 error = EAI_AGAIN; 1870 goto free; 1871 case NS_UNAVAIL: 1872 error = EAI_FAIL; 1873 goto free; 1874 case NS_NOTFOUND: 1875 error = EAI_NONAME; 1876 goto free; 1877 case NS_SUCCESS: 1878 error = 0; 1879 for (cur = result; cur; cur = cur->ai_next) { 1880 GET_PORT(cur, servname); 1881 /* canonname should be filled already */ 1882 } 1883 break; 1884 } 1885 1886 *res = result; 1887 1888 return 0; 1889 1890free: 1891 if (result) 1892 freeaddrinfo(result); 1893 return error; 1894} 1895 1896#ifdef DEBUG 1897static const char AskedForGot[] = 1898 "gethostby*.getanswer: asked for \"%s\", got \"%s\""; 1899#endif 1900 1901static struct addrinfo * 1902getanswer(const querybuf *answer, int anslen, const char *qname, int qtype, 1903 const struct addrinfo *pai, res_state res) 1904{ 1905 struct addrinfo sentinel, *cur; 1906 struct addrinfo ai; 1907 const struct afd *afd; 1908 char *canonname; 1909 const HEADER *hp; 1910 const u_char *cp; 1911 int n; 1912 const u_char *eom; 1913 char *bp, *ep; 1914 int type, class, ancount, qdcount; 1915 int haveanswer, had_error; 1916 char tbuf[MAXDNAME]; 1917 int (*name_ok)(const char *); 1918 char hostbuf[8*1024]; 1919 1920 memset(&sentinel, 0, sizeof(sentinel)); 1921 cur = &sentinel; 1922 1923 canonname = NULL; 1924 eom = answer->buf + anslen; 1925 switch (qtype) { 1926 case T_A: 1927 case T_AAAA: 1928 case T_ANY: /*use T_ANY only for T_A/T_AAAA lookup*/ 1929 name_ok = res_hnok; 1930 break; 1931 default: 1932 return (NULL); /* XXX should be abort(); */ 1933 } 1934 /* 1935 * find first satisfactory answer 1936 */ 1937 hp = &answer->hdr; 1938 ancount = ntohs(hp->ancount); 1939 qdcount = ntohs(hp->qdcount); 1940 bp = hostbuf; 1941 ep = hostbuf + sizeof hostbuf; 1942 cp = answer->buf + HFIXEDSZ; 1943 if (qdcount != 1) { 1944 RES_SET_H_ERRNO(res, NO_RECOVERY); 1945 return (NULL); 1946 } 1947 n = dn_expand(answer->buf, eom, cp, bp, ep - bp); 1948 if ((n < 0) || !(*name_ok)(bp)) { 1949 RES_SET_H_ERRNO(res, NO_RECOVERY); 1950 return (NULL); 1951 } 1952 cp += n + QFIXEDSZ; 1953 if (qtype == T_A || qtype == T_AAAA || qtype == T_ANY) { 1954 /* res_send() has already verified that the query name is the 1955 * same as the one we sent; this just gets the expanded name 1956 * (i.e., with the succeeding search-domain tacked on). 1957 */ 1958 n = strlen(bp) + 1; /* for the \0 */ 1959 if (n >= MAXHOSTNAMELEN) { 1960 RES_SET_H_ERRNO(res, NO_RECOVERY); 1961 return (NULL); 1962 } 1963 canonname = bp; 1964 bp += n; 1965 /* The qname can be abbreviated, but h_name is now absolute. */ 1966 qname = canonname; 1967 } 1968 haveanswer = 0; 1969 had_error = 0; 1970 while (ancount-- > 0 && cp < eom && !had_error) { 1971 n = dn_expand(answer->buf, eom, cp, bp, ep - bp); 1972 if ((n < 0) || !(*name_ok)(bp)) { 1973 had_error++; 1974 continue; 1975 } 1976 cp += n; /* name */ 1977 type = _getshort(cp); 1978 cp += INT16SZ; /* type */ 1979 class = _getshort(cp); 1980 cp += INT16SZ + INT32SZ; /* class, TTL */ 1981 n = _getshort(cp); 1982 cp += INT16SZ; /* len */ 1983 if (class != C_IN) { 1984 /* XXX - debug? syslog? */ 1985 cp += n; 1986 continue; /* XXX - had_error++ ? */ 1987 } 1988 if ((qtype == T_A || qtype == T_AAAA || qtype == T_ANY) && 1989 type == T_CNAME) { 1990 n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf); 1991 if ((n < 0) || !(*name_ok)(tbuf)) { 1992 had_error++; 1993 continue; 1994 } 1995 cp += n; 1996 /* Get canonical name. */ 1997 n = strlen(tbuf) + 1; /* for the \0 */ 1998 if (n > ep - bp || n >= MAXHOSTNAMELEN) { 1999 had_error++; 2000 continue; 2001 } 2002 strlcpy(bp, tbuf, ep - bp); 2003 canonname = bp; 2004 bp += n; 2005 continue; 2006 } 2007 if (qtype == T_ANY) { 2008 if (!(type == T_A || type == T_AAAA)) { 2009 cp += n; 2010 continue; 2011 } 2012 } else if (type != qtype) { 2013#ifdef DEBUG 2014 if (type != T_KEY && type != T_SIG && 2015 type != ns_t_dname) 2016 syslog(LOG_NOTICE|LOG_AUTH, 2017 "gethostby*.getanswer: asked for \"%s %s %s\", got type \"%s\"", 2018 qname, p_class(C_IN), p_type(qtype), 2019 p_type(type)); 2020#endif 2021 cp += n; 2022 continue; /* XXX - had_error++ ? */ 2023 } 2024 switch (type) { 2025 case T_A: 2026 case T_AAAA: 2027 if (strcasecmp(canonname, bp) != 0) { 2028#ifdef DEBUG 2029 syslog(LOG_NOTICE|LOG_AUTH, 2030 AskedForGot, canonname, bp); 2031#endif 2032 cp += n; 2033 continue; /* XXX - had_error++ ? */ 2034 } 2035 if (type == T_A && n != INADDRSZ) { 2036 cp += n; 2037 continue; 2038 } 2039 if (type == T_AAAA && n != IN6ADDRSZ) { 2040 cp += n; 2041 continue; 2042 } 2043#ifdef FILTER_V4MAPPED 2044 if (type == T_AAAA) { 2045 struct in6_addr in6; 2046 memcpy(&in6, cp, sizeof(in6)); 2047 if (IN6_IS_ADDR_V4MAPPED(&in6)) { 2048 cp += n; 2049 continue; 2050 } 2051 } 2052#endif 2053 if (!haveanswer) { 2054 int nn; 2055 2056 canonname = bp; 2057 nn = strlen(bp) + 1; /* for the \0 */ 2058 bp += nn; 2059 } 2060 2061 /* don't overwrite pai */ 2062 ai = *pai; 2063 ai.ai_family = (type == T_A) ? AF_INET : AF_INET6; 2064 afd = find_afd(ai.ai_family); 2065 if (afd == NULL) { 2066 cp += n; 2067 continue; 2068 } 2069 cur->ai_next = get_ai(&ai, afd, (const char *)cp); 2070 if (cur->ai_next == NULL) 2071 had_error++; 2072 while (cur && cur->ai_next) 2073 cur = cur->ai_next; 2074 cp += n; 2075 break; 2076 default: 2077 abort(); 2078 } 2079 if (!had_error) 2080 haveanswer++; 2081 } 2082 if (haveanswer) { 2083#if defined(RESOLVSORT) 2084 /* 2085 * We support only IPv4 address for backward 2086 * compatibility against gethostbyname(3). 2087 */ 2088 if (res->nsort && qtype == T_A) { 2089 if (addr4sort(&sentinel, res) < 0) { 2090 freeaddrinfo(sentinel.ai_next); 2091 RES_SET_H_ERRNO(res, NO_RECOVERY); 2092 return NULL; 2093 } 2094 } 2095#endif /*RESOLVSORT*/ 2096 if (!canonname) 2097 (void)get_canonname(pai, sentinel.ai_next, qname); 2098 else 2099 (void)get_canonname(pai, sentinel.ai_next, canonname); 2100 RES_SET_H_ERRNO(res, NETDB_SUCCESS); 2101 return sentinel.ai_next; 2102 } 2103 2104 RES_SET_H_ERRNO(res, NO_RECOVERY); 2105 return NULL; 2106} 2107 2108#ifdef RESOLVSORT 2109struct addr_ptr { 2110 struct addrinfo *ai; 2111 int aval; 2112}; 2113 2114static int 2115addr4sort(struct addrinfo *sentinel, res_state res) 2116{ 2117 struct addrinfo *ai; 2118 struct addr_ptr *addrs, addr; 2119 struct sockaddr_in *sin; 2120 int naddrs, i, j; 2121 int needsort = 0; 2122 2123 if (!sentinel) 2124 return -1; 2125 naddrs = 0; 2126 for (ai = sentinel->ai_next; ai; ai = ai->ai_next) 2127 naddrs++; 2128 if (naddrs < 2) 2129 return 0; /* We don't need sorting. */ 2130 if ((addrs = malloc(sizeof(struct addr_ptr) * naddrs)) == NULL) 2131 return -1; 2132 i = 0; 2133 for (ai = sentinel->ai_next; ai; ai = ai->ai_next) { 2134 sin = (struct sockaddr_in *)ai->ai_addr; 2135 for (j = 0; (unsigned)j < res->nsort; j++) { 2136 if (res->sort_list[j].addr.s_addr == 2137 (sin->sin_addr.s_addr & res->sort_list[j].mask)) 2138 break; 2139 } 2140 addrs[i].ai = ai; 2141 addrs[i].aval = j; 2142 if (needsort == 0 && i > 0 && j < addrs[i - 1].aval) 2143 needsort = i; 2144 i++; 2145 } 2146 if (!needsort) { 2147 free(addrs); 2148 return 0; 2149 } 2150 2151 while (needsort < naddrs) { 2152 for (j = needsort - 1; j >= 0; j--) { 2153 if (addrs[j].aval > addrs[j+1].aval) { 2154 addr = addrs[j]; 2155 addrs[j] = addrs[j + 1]; 2156 addrs[j + 1] = addr; 2157 } else 2158 break; 2159 } 2160 needsort++; 2161 } 2162 2163 ai = sentinel; 2164 for (i = 0; i < naddrs; ++i) { 2165 ai->ai_next = addrs[i].ai; 2166 ai = ai->ai_next; 2167 } 2168 ai->ai_next = NULL; 2169 free(addrs); 2170 return 0; 2171} 2172#endif /*RESOLVSORT*/ 2173 2174/*ARGSUSED*/ 2175static int 2176_dns_getaddrinfo(void *rv, void *cb_data, va_list ap) 2177{ 2178 struct addrinfo *ai; 2179 querybuf *buf, *buf2; 2180 const char *hostname; 2181 const struct addrinfo *pai; 2182 struct addrinfo sentinel, *cur; 2183 struct res_target q, q2; 2184 res_state res; 2185 2186 hostname = va_arg(ap, char *); 2187 pai = va_arg(ap, const struct addrinfo *); 2188 2189 memset(&q, 0, sizeof(q)); 2190 memset(&q2, 0, sizeof(q2)); 2191 memset(&sentinel, 0, sizeof(sentinel)); 2192 cur = &sentinel; 2193 2194 buf = malloc(sizeof(*buf)); 2195 if (!buf) { 2196 RES_SET_H_ERRNO(res, NETDB_INTERNAL); 2197 return NS_NOTFOUND; 2198 } 2199 buf2 = malloc(sizeof(*buf2)); 2200 if (!buf2) { 2201 free(buf); 2202 RES_SET_H_ERRNO(res, NETDB_INTERNAL); 2203 return NS_NOTFOUND; 2204 } 2205 2206 switch (pai->ai_family) { 2207 case AF_UNSPEC: 2208 q.name = hostname; 2209 q.qclass = C_IN; 2210 q.qtype = T_A; 2211 q.answer = buf->buf; 2212 q.anslen = sizeof(buf->buf); 2213 q.next = &q2; 2214 q2.name = hostname; 2215 q2.qclass = C_IN; 2216 q2.qtype = T_AAAA; 2217 q2.answer = buf2->buf; 2218 q2.anslen = sizeof(buf2->buf); 2219 break; 2220 case AF_INET: 2221 q.name = hostname; 2222 q.qclass = C_IN; 2223 q.qtype = T_A; 2224 q.answer = buf->buf; 2225 q.anslen = sizeof(buf->buf); 2226 break; 2227 case AF_INET6: 2228 q.name = hostname; 2229 q.qclass = C_IN; 2230 q.qtype = T_AAAA; 2231 q.answer = buf->buf; 2232 q.anslen = sizeof(buf->buf); 2233 break; 2234 default: 2235 free(buf); 2236 free(buf2); 2237 return NS_UNAVAIL; 2238 } 2239 2240 res = __res_state(); 2241 if ((res->options & RES_INIT) == 0 && res_ninit(res) == -1) { 2242 RES_SET_H_ERRNO(res, NETDB_INTERNAL); 2243 free(buf); 2244 free(buf2); 2245 return NS_NOTFOUND; 2246 } 2247 2248 if (res_searchN(hostname, &q, res) < 0) { 2249 free(buf); 2250 free(buf2); 2251 return NS_NOTFOUND; 2252 } 2253 /* prefer IPv6 */ 2254 if (q.next) { 2255 ai = getanswer(buf2, q2.n, q2.name, q2.qtype, pai, res); 2256 if (ai) { 2257 cur->ai_next = ai; 2258 while (cur && cur->ai_next) 2259 cur = cur->ai_next; 2260 } 2261 } 2262 ai = getanswer(buf, q.n, q.name, q.qtype, pai, res); 2263 if (ai) 2264 cur->ai_next = ai; 2265 free(buf); 2266 free(buf2); 2267 if (sentinel.ai_next == NULL) 2268 switch (res->res_h_errno) { 2269 case HOST_NOT_FOUND: 2270 return NS_NOTFOUND; 2271 case TRY_AGAIN: 2272 return NS_TRYAGAIN; 2273 default: 2274 return NS_UNAVAIL; 2275 } 2276 *((struct addrinfo **)rv) = sentinel.ai_next; 2277 return NS_SUCCESS; 2278} 2279 2280static void 2281_sethtent(FILE **hostf) 2282{ 2283 if (!*hostf) 2284 *hostf = fopen(_PATH_HOSTS, "re"); 2285 else 2286 rewind(*hostf); 2287} 2288 2289static void 2290_endhtent(FILE **hostf) 2291{ 2292 if (*hostf) { 2293 (void) fclose(*hostf); 2294 *hostf = NULL; 2295 } 2296} 2297 2298static struct addrinfo * 2299_gethtent(FILE **hostf, const char *name, const struct addrinfo *pai) 2300{ 2301 char *p; 2302 char *cp, *tname, *cname; 2303 struct addrinfo hints, *res0, *res; 2304 int error; 2305 const char *addr; 2306 char hostbuf[8*1024]; 2307 2308 if (!*hostf && !(*hostf = fopen(_PATH_HOSTS, "re"))) 2309 return (NULL); 2310again: 2311 if (!(p = fgets(hostbuf, sizeof hostbuf, *hostf))) 2312 return (NULL); 2313 if (*p == '#') 2314 goto again; 2315 cp = strpbrk(p, "#\n"); 2316 if (cp != NULL) 2317 *cp = '\0'; 2318 if (!(cp = strpbrk(p, " \t"))) 2319 goto again; 2320 *cp++ = '\0'; 2321 addr = p; 2322 cname = NULL; 2323 /* if this is not something we're looking for, skip it. */ 2324 while (cp && *cp) { 2325 if (*cp == ' ' || *cp == '\t') { 2326 cp++; 2327 continue; 2328 } 2329 tname = cp; 2330 if (cname == NULL) 2331 cname = cp; 2332 if ((cp = strpbrk(cp, " \t")) != NULL) 2333 *cp++ = '\0'; 2334 if (strcasecmp(name, tname) == 0) 2335 goto found; 2336 } 2337 goto again; 2338 2339found: 2340 /* we should not glob socktype/protocol here */ 2341 memset(&hints, 0, sizeof(hints)); 2342 hints.ai_family = pai->ai_family; 2343 hints.ai_socktype = SOCK_DGRAM; 2344 hints.ai_protocol = 0; 2345 hints.ai_flags = AI_NUMERICHOST; 2346 error = getaddrinfo(addr, "0", &hints, &res0); 2347 if (error) 2348 goto again; 2349#ifdef FILTER_V4MAPPED 2350 /* XXX should check all items in the chain */ 2351 if (res0->ai_family == AF_INET6 && 2352 IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)res0->ai_addr)->sin6_addr)) { 2353 freeaddrinfo(res0); 2354 goto again; 2355 } 2356#endif 2357 for (res = res0; res; res = res->ai_next) { 2358 /* cover it up */ 2359 res->ai_flags = pai->ai_flags; 2360 res->ai_socktype = pai->ai_socktype; 2361 res->ai_protocol = pai->ai_protocol; 2362 2363 if (pai->ai_flags & AI_CANONNAME) { 2364 if (get_canonname(pai, res, cname) != 0) { 2365 freeaddrinfo(res0); 2366 goto again; 2367 } 2368 } 2369 } 2370 return res0; 2371} 2372 2373/*ARGSUSED*/ 2374static int 2375_files_getaddrinfo(void *rv, void *cb_data, va_list ap) 2376{ 2377 const char *name; 2378 const struct addrinfo *pai; 2379 struct addrinfo sentinel, *cur; 2380 struct addrinfo *p; 2381 FILE *hostf = NULL; 2382 2383 name = va_arg(ap, char *); 2384 pai = va_arg(ap, struct addrinfo *); 2385 2386 memset(&sentinel, 0, sizeof(sentinel)); 2387 cur = &sentinel; 2388 2389 _sethtent(&hostf); 2390 while ((p = _gethtent(&hostf, name, pai)) != NULL) { 2391 cur->ai_next = p; 2392 while (cur && cur->ai_next) 2393 cur = cur->ai_next; 2394 } 2395 _endhtent(&hostf); 2396 2397 *((struct addrinfo **)rv) = sentinel.ai_next; 2398 if (sentinel.ai_next == NULL) 2399 return NS_NOTFOUND; 2400 return NS_SUCCESS; 2401} 2402 2403#ifdef YP 2404/*ARGSUSED*/ 2405static struct addrinfo * 2406_yphostent(char *line, const struct addrinfo *pai) 2407{ 2408 struct addrinfo sentinel, *cur; 2409 struct addrinfo hints, *res, *res0; 2410 int error; 2411 char *p = line; 2412 const char *addr, *canonname; 2413 char *nextline; 2414 char *cp; 2415 2416 addr = canonname = NULL; 2417 2418 memset(&sentinel, 0, sizeof(sentinel)); 2419 cur = &sentinel; 2420 2421nextline: 2422 /* terminate line */ 2423 cp = strchr(p, '\n'); 2424 if (cp) { 2425 *cp++ = '\0'; 2426 nextline = cp; 2427 } else 2428 nextline = NULL; 2429 2430 cp = strpbrk(p, " \t"); 2431 if (cp == NULL) { 2432 if (canonname == NULL) 2433 return (NULL); 2434 else 2435 goto done; 2436 } 2437 *cp++ = '\0'; 2438 2439 addr = p; 2440 2441 while (cp && *cp) { 2442 if (*cp == ' ' || *cp == '\t') { 2443 cp++; 2444 continue; 2445 } 2446 if (!canonname) 2447 canonname = cp; 2448 if ((cp = strpbrk(cp, " \t")) != NULL) 2449 *cp++ = '\0'; 2450 } 2451 2452 hints = *pai; 2453 hints.ai_flags = AI_NUMERICHOST; 2454 error = getaddrinfo(addr, NULL, &hints, &res0); 2455 if (error == 0) { 2456 for (res = res0; res; res = res->ai_next) { 2457 /* cover it up */ 2458 res->ai_flags = pai->ai_flags; 2459 2460 if (pai->ai_flags & AI_CANONNAME) 2461 (void)get_canonname(pai, res, canonname); 2462 } 2463 } else 2464 res0 = NULL; 2465 if (res0) { 2466 cur->ai_next = res0; 2467 while (cur && cur->ai_next) 2468 cur = cur->ai_next; 2469 } 2470 2471 if (nextline) { 2472 p = nextline; 2473 goto nextline; 2474 } 2475 2476done: 2477 return sentinel.ai_next; 2478} 2479 2480/*ARGSUSED*/ 2481static int 2482_yp_getaddrinfo(void *rv, void *cb_data, va_list ap) 2483{ 2484 struct addrinfo sentinel, *cur; 2485 struct addrinfo *ai = NULL; 2486 char *ypbuf; 2487 int ypbuflen, r; 2488 const char *name; 2489 const struct addrinfo *pai; 2490 char *ypdomain; 2491 2492 if (_yp_check(&ypdomain) == 0) 2493 return NS_UNAVAIL; 2494 2495 name = va_arg(ap, char *); 2496 pai = va_arg(ap, const struct addrinfo *); 2497 2498 memset(&sentinel, 0, sizeof(sentinel)); 2499 cur = &sentinel; 2500 2501 /* hosts.byname is only for IPv4 (Solaris8) */ 2502 if (pai->ai_family == PF_UNSPEC || pai->ai_family == PF_INET) { 2503 r = yp_match(ypdomain, "hosts.byname", name, 2504 (int)strlen(name), &ypbuf, &ypbuflen); 2505 if (r == 0) { 2506 struct addrinfo ai4; 2507 2508 ai4 = *pai; 2509 ai4.ai_family = AF_INET; 2510 ai = _yphostent(ypbuf, &ai4); 2511 if (ai) { 2512 cur->ai_next = ai; 2513 while (cur && cur->ai_next) 2514 cur = cur->ai_next; 2515 } 2516 free(ypbuf); 2517 } 2518 } 2519 2520 /* ipnodes.byname can hold both IPv4/v6 */ 2521 r = yp_match(ypdomain, "ipnodes.byname", name, 2522 (int)strlen(name), &ypbuf, &ypbuflen); 2523 if (r == 0) { 2524 ai = _yphostent(ypbuf, pai); 2525 if (ai) 2526 cur->ai_next = ai; 2527 free(ypbuf); 2528 } 2529 2530 if (sentinel.ai_next == NULL) { 2531 RES_SET_H_ERRNO(__res_state(), HOST_NOT_FOUND); 2532 return NS_NOTFOUND; 2533 } 2534 *((struct addrinfo **)rv) = sentinel.ai_next; 2535 return NS_SUCCESS; 2536} 2537#endif 2538 2539/* resolver logic */ 2540 2541/* 2542 * Formulate a normal query, send, and await answer. 2543 * Returned answer is placed in supplied buffer "answer". 2544 * Perform preliminary check of answer, returning success only 2545 * if no error is indicated and the answer count is nonzero. 2546 * Return the size of the response on success, -1 on error. 2547 * Error number is left in h_errno. 2548 * 2549 * Caller must parse answer and determine whether it answers the question. 2550 */ 2551static int 2552res_queryN(const char *name, struct res_target *target, res_state res) 2553{ 2554 u_char *buf; 2555 HEADER *hp; 2556 int n; 2557 u_int oflags; 2558 struct res_target *t; 2559 int rcode; 2560 int ancount; 2561 2562 rcode = NOERROR; 2563 ancount = 0; 2564 2565 buf = malloc(MAXPACKET); 2566 if (!buf) { 2567 RES_SET_H_ERRNO(res, NETDB_INTERNAL); 2568 return -1; 2569 } 2570 2571 for (t = target; t; t = t->next) { 2572 int class, type; 2573 u_char *answer; 2574 int anslen; 2575 2576 hp = (HEADER *)(void *)t->answer; 2577 2578 /* make it easier... */ 2579 class = t->qclass; 2580 type = t->qtype; 2581 answer = t->answer; 2582 anslen = t->anslen; 2583 2584 oflags = res->_flags; 2585 2586again: 2587 hp->rcode = NOERROR; /* default */ 2588 2589#ifdef DEBUG 2590 if (res->options & RES_DEBUG) 2591 printf(";; res_query(%s, %d, %d)\n", name, class, type); 2592#endif 2593 2594 n = res_nmkquery(res, QUERY, name, class, type, NULL, 0, NULL, 2595 buf, MAXPACKET); 2596 if (n > 0 && (res->_flags & RES_F_EDNS0ERR) == 0 && 2597 (res->options & (RES_USE_EDNS0|RES_USE_DNSSEC)) != 0U) 2598 n = res_nopt(res, n, buf, MAXPACKET, anslen); 2599 if (n <= 0) { 2600#ifdef DEBUG 2601 if (res->options & RES_DEBUG) 2602 printf(";; res_query: mkquery failed\n"); 2603#endif 2604 free(buf); 2605 RES_SET_H_ERRNO(res, NO_RECOVERY); 2606 return (n); 2607 } 2608 n = res_nsend(res, buf, n, answer, anslen); 2609 if (n < 0) { 2610 /* 2611 * if the query choked with EDNS0, retry 2612 * without EDNS0 2613 */ 2614 if ((res->options & (RES_USE_EDNS0|RES_USE_DNSSEC)) 2615 != 0U && 2616 ((oflags ^ res->_flags) & RES_F_EDNS0ERR) != 0) { 2617 res->_flags |= RES_F_EDNS0ERR; 2618 if (res->options & RES_DEBUG) 2619 printf(";; res_nquery: retry without EDNS0\n"); 2620 goto again; 2621 } 2622 rcode = hp->rcode; /* record most recent error */ 2623#ifdef DEBUG 2624 if (res->options & RES_DEBUG) 2625 printf(";; res_query: send error\n"); 2626#endif 2627 continue; 2628 } 2629 2630 if (n > anslen) 2631 hp->rcode = FORMERR; /* XXX not very informative */ 2632 if (hp->rcode != NOERROR || ntohs(hp->ancount) == 0) { 2633 rcode = hp->rcode; /* record most recent error */ 2634#ifdef DEBUG 2635 if (res->options & RES_DEBUG) 2636 printf(";; rcode = %u, ancount=%u\n", hp->rcode, 2637 ntohs(hp->ancount)); 2638#endif 2639 continue; 2640 } 2641 2642 ancount += ntohs(hp->ancount); 2643 2644 t->n = n; 2645 } 2646 2647 free(buf); 2648 2649 if (ancount == 0) { 2650 switch (rcode) { 2651 case NXDOMAIN: 2652 RES_SET_H_ERRNO(res, HOST_NOT_FOUND); 2653 break; 2654 case SERVFAIL: 2655 RES_SET_H_ERRNO(res, TRY_AGAIN); 2656 break; 2657 case NOERROR: 2658 RES_SET_H_ERRNO(res, NO_DATA); 2659 break; 2660 case FORMERR: 2661 case NOTIMP: 2662 case REFUSED: 2663 default: 2664 RES_SET_H_ERRNO(res, NO_RECOVERY); 2665 break; 2666 } 2667 return (-1); 2668 } 2669 return (ancount); 2670} 2671 2672/* 2673 * Formulate a normal query, send, and retrieve answer in supplied buffer. 2674 * Return the size of the response on success, -1 on error. 2675 * If enabled, implement search rules until answer or unrecoverable failure 2676 * is detected. Error code, if any, is left in h_errno. 2677 */ 2678static int 2679res_searchN(const char *name, struct res_target *target, res_state res) 2680{ 2681 const char *cp, * const *domain; 2682 HEADER *hp = (HEADER *)(void *)target->answer; /*XXX*/ 2683 u_int dots; 2684 int trailing_dot, ret, saved_herrno; 2685 int got_nodata = 0, got_servfail = 0, root_on_list = 0; 2686 int tried_as_is = 0; 2687 int searched = 0; 2688 char abuf[MAXDNAME]; 2689 2690 errno = 0; 2691 RES_SET_H_ERRNO(res, HOST_NOT_FOUND); /* default, if we never query */ 2692 dots = 0; 2693 for (cp = name; *cp; cp++) 2694 dots += (*cp == '.'); 2695 trailing_dot = 0; 2696 if (cp > name && *--cp == '.') 2697 trailing_dot++; 2698 2699 /* 2700 * if there aren't any dots, it could be a user-level alias 2701 */ 2702 if (!dots && 2703 (cp = res_hostalias(res, name, abuf, sizeof(abuf))) != NULL) 2704 return (res_queryN(cp, target, res)); 2705 2706 /* 2707 * If there are enough dots in the name, let's just give it a 2708 * try 'as is'. The threshold can be set with the "ndots" option. 2709 * Also, query 'as is', if there is a trailing dot in the name. 2710 */ 2711 saved_herrno = -1; 2712 if (dots >= res->ndots || trailing_dot) { 2713 ret = res_querydomainN(name, NULL, target, res); 2714 if (ret > 0 || trailing_dot) 2715 return (ret); 2716 if (errno == ECONNREFUSED) { 2717 RES_SET_H_ERRNO(res, TRY_AGAIN); 2718 return (-1); 2719 } 2720 switch (res->res_h_errno) { 2721 case NO_DATA: 2722 case HOST_NOT_FOUND: 2723 break; 2724 case TRY_AGAIN: 2725 if (hp->rcode == SERVFAIL) 2726 break; 2727 /* FALLTHROUGH */ 2728 default: 2729 return (-1); 2730 } 2731 saved_herrno = res->res_h_errno; 2732 tried_as_is++; 2733 } 2734 2735 /* 2736 * We do at least one level of search if 2737 * - there is no dot and RES_DEFNAME is set, or 2738 * - there is at least one dot, there is no trailing dot, 2739 * and RES_DNSRCH is set. 2740 */ 2741 if ((!dots && (res->options & RES_DEFNAMES)) || 2742 (dots && !trailing_dot && (res->options & RES_DNSRCH))) { 2743 int done = 0; 2744 2745 for (domain = (const char * const *)res->dnsrch; 2746 *domain && !done; 2747 domain++) { 2748 searched = 1; 2749 2750 if (domain[0][0] == '\0' || 2751 (domain[0][0] == '.' && domain[0][1] == '\0')) 2752 root_on_list++; 2753 2754 if (root_on_list && tried_as_is) 2755 continue; 2756 2757 ret = res_querydomainN(name, *domain, target, res); 2758 if (ret > 0) 2759 return (ret); 2760 2761 /* 2762 * If no server present, give up. 2763 * If name isn't found in this domain, 2764 * keep trying higher domains in the search list 2765 * (if that's enabled). 2766 * On a NO_DATA error, keep trying, otherwise 2767 * a wildcard entry of another type could keep us 2768 * from finding this entry higher in the domain. 2769 * If we get some other error (negative answer or 2770 * server failure), then stop searching up, 2771 * but try the input name below in case it's 2772 * fully-qualified. 2773 */ 2774 if (errno == ECONNREFUSED) { 2775 RES_SET_H_ERRNO(res, TRY_AGAIN); 2776 return (-1); 2777 } 2778 2779 switch (res->res_h_errno) { 2780 case NO_DATA: 2781 got_nodata++; 2782 /* FALLTHROUGH */ 2783 case HOST_NOT_FOUND: 2784 /* keep trying */ 2785 break; 2786 case TRY_AGAIN: 2787 got_servfail++; 2788 if (hp->rcode == SERVFAIL) { 2789 /* try next search element, if any */ 2790 break; 2791 } 2792 /* FALLTHROUGH */ 2793 default: 2794 /* anything else implies that we're done */ 2795 done++; 2796 } 2797 /* 2798 * if we got here for some reason other than DNSRCH, 2799 * we only wanted one iteration of the loop, so stop. 2800 */ 2801 if (!(res->options & RES_DNSRCH)) 2802 done++; 2803 } 2804 } 2805 2806 switch (res->res_h_errno) { 2807 case NO_DATA: 2808 case HOST_NOT_FOUND: 2809 break; 2810 case TRY_AGAIN: 2811 if (hp->rcode == SERVFAIL) 2812 break; 2813 /* FALLTHROUGH */ 2814 default: 2815 goto giveup; 2816 } 2817 2818 /* 2819 * If the query has not already been tried as is then try it 2820 * unless RES_NOTLDQUERY is set and there were no dots. 2821 */ 2822 if ((dots || !searched || !(res->options & RES_NOTLDQUERY)) && 2823 !(tried_as_is || root_on_list)) { 2824 ret = res_querydomainN(name, NULL, target, res); 2825 if (ret > 0) 2826 return (ret); 2827 } 2828 2829 /* 2830 * if we got here, we didn't satisfy the search. 2831 * if we did an initial full query, return that query's h_errno 2832 * (note that we wouldn't be here if that query had succeeded). 2833 * else if we ever got a nodata, send that back as the reason. 2834 * else send back meaningless h_errno, that being the one from 2835 * the last DNSRCH we did. 2836 */ 2837giveup: 2838 if (saved_herrno != -1) 2839 RES_SET_H_ERRNO(res, saved_herrno); 2840 else if (got_nodata) 2841 RES_SET_H_ERRNO(res, NO_DATA); 2842 else if (got_servfail) 2843 RES_SET_H_ERRNO(res, TRY_AGAIN); 2844 return (-1); 2845} 2846 2847/* 2848 * Perform a call on res_query on the concatenation of name and domain, 2849 * removing a trailing dot from name if domain is NULL. 2850 */ 2851static int 2852res_querydomainN(const char *name, const char *domain, 2853 struct res_target *target, res_state res) 2854{ 2855 char nbuf[MAXDNAME]; 2856 const char *longname = nbuf; 2857 size_t n, d; 2858 2859#ifdef DEBUG 2860 if (res->options & RES_DEBUG) 2861 printf(";; res_querydomain(%s, %s)\n", 2862 name, domain?domain:"<Nil>"); 2863#endif 2864 if (domain == NULL) { 2865 /* 2866 * Check for trailing '.'; 2867 * copy without '.' if present. 2868 */ 2869 n = strlen(name); 2870 if (n >= MAXDNAME) { 2871 RES_SET_H_ERRNO(res, NO_RECOVERY); 2872 return (-1); 2873 } 2874 if (n > 0 && name[--n] == '.') { 2875 strncpy(nbuf, name, n); 2876 nbuf[n] = '\0'; 2877 } else 2878 longname = name; 2879 } else { 2880 n = strlen(name); 2881 d = strlen(domain); 2882 if (n + d + 1 >= MAXDNAME) { 2883 RES_SET_H_ERRNO(res, NO_RECOVERY); 2884 return (-1); 2885 } 2886 snprintf(nbuf, sizeof(nbuf), "%s.%s", name, domain); 2887 } 2888 return (res_queryN(longname, target, res)); 2889} 2890