1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 3*0Sstevel@tonic-gate * Use is subject to license terms. 4*0Sstevel@tonic-gate */ 5*0Sstevel@tonic-gate 6*0Sstevel@tonic-gate /* $KAME: getaddrinfo.c,v 1.14 2001/01/06 09:41:15 jinmei Exp $ */ 7*0Sstevel@tonic-gate 8*0Sstevel@tonic-gate /* 9*0Sstevel@tonic-gate * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 10*0Sstevel@tonic-gate * All rights reserved. 11*0Sstevel@tonic-gate * 12*0Sstevel@tonic-gate * Redistribution and use in source and binary forms, with or without 13*0Sstevel@tonic-gate * modification, are permitted provided that the following conditions 14*0Sstevel@tonic-gate * are met: 15*0Sstevel@tonic-gate * 1. Redistributions of source code must retain the above copyright 16*0Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer. 17*0Sstevel@tonic-gate * 2. Redistributions in binary form must reproduce the above copyright 18*0Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer in the 19*0Sstevel@tonic-gate * documentation and/or other materials provided with the distribution. 20*0Sstevel@tonic-gate * 3. Neither the name of the project nor the names of its contributors 21*0Sstevel@tonic-gate * may be used to endorse or promote products derived from this software 22*0Sstevel@tonic-gate * without specific prior written permission. 23*0Sstevel@tonic-gate * 24*0Sstevel@tonic-gate * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 25*0Sstevel@tonic-gate * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26*0Sstevel@tonic-gate * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27*0Sstevel@tonic-gate * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 28*0Sstevel@tonic-gate * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29*0Sstevel@tonic-gate * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30*0Sstevel@tonic-gate * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31*0Sstevel@tonic-gate * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32*0Sstevel@tonic-gate * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33*0Sstevel@tonic-gate * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34*0Sstevel@tonic-gate * SUCH DAMAGE. 35*0Sstevel@tonic-gate */ 36*0Sstevel@tonic-gate 37*0Sstevel@tonic-gate /* 38*0Sstevel@tonic-gate * Issues to be discussed: 39*0Sstevel@tonic-gate * - Thread safe-ness must be checked. 40*0Sstevel@tonic-gate * - Return values. There are nonstandard return values defined and used 41*0Sstevel@tonic-gate * in the source code. This is because RFC2553 is silent about which error 42*0Sstevel@tonic-gate * code must be returned for which situation. 43*0Sstevel@tonic-gate * - IPv4 classful (shortened) form. RFC2553 is silent about it. XNET 5.2 44*0Sstevel@tonic-gate * says to use inet_aton() to convert IPv4 numeric to binary (allows 45*0Sstevel@tonic-gate * classful form as a result). 46*0Sstevel@tonic-gate * current code - disallow classful form for IPv4 (due to use of inet_pton). 47*0Sstevel@tonic-gate * - freeaddrinfo(NULL). RFC2553 is silent about it. XNET 5.2 says it is 48*0Sstevel@tonic-gate * invalid. 49*0Sstevel@tonic-gate * current code - SEGV on freeaddrinfo(NULL) 50*0Sstevel@tonic-gate * Note: 51*0Sstevel@tonic-gate * - We use getipnodebyname() just for thread-safeness. There's no intent 52*0Sstevel@tonic-gate * to let it do PF_UNSPEC (actually we never pass PF_UNSPEC to 53*0Sstevel@tonic-gate * getipnodebyname(). 54*0Sstevel@tonic-gate * - The code filters out AFs that are not supported by the kernel, 55*0Sstevel@tonic-gate * when globbing NULL hostname (to loopback, or wildcard). Is it the right 56*0Sstevel@tonic-gate * thing to do? What is the relationship with post-RFC2553 AI_ADDRCONFIG 57*0Sstevel@tonic-gate * in ai_flags? 58*0Sstevel@tonic-gate * - (post-2553) semantics of AI_ADDRCONFIG itself is too vague. 59*0Sstevel@tonic-gate * (1) what should we do against numeric hostname (2) what should we do 60*0Sstevel@tonic-gate * against NULL hostname (3) what is AI_ADDRCONFIG itself. AF not ready? 61*0Sstevel@tonic-gate * non-loopback address configured? global address configured? 62*0Sstevel@tonic-gate * - To avoid search order issue, we have a big amount of code duplicate 63*0Sstevel@tonic-gate * from gethnamaddr.c and some other places. The issues that there's no 64*0Sstevel@tonic-gate * lower layer function to lookup "IPv4 or IPv6" record. Calling 65*0Sstevel@tonic-gate * gethostbyname2 from getaddrinfo will end up in wrong search order, as 66*0Sstevel@tonic-gate * follows: 67*0Sstevel@tonic-gate * - The code makes use of following calls when asked to resolver with 68*0Sstevel@tonic-gate * ai_family = PF_UNSPEC: 69*0Sstevel@tonic-gate * getipnodebyname(host, AF_INET6); 70*0Sstevel@tonic-gate * getipnodebyname(host, AF_INET); 71*0Sstevel@tonic-gate * This will result in the following queries if the node is configure to 72*0Sstevel@tonic-gate * prefer /etc/hosts than DNS: 73*0Sstevel@tonic-gate * lookup /etc/hosts for IPv6 address 74*0Sstevel@tonic-gate * lookup DNS for IPv6 address 75*0Sstevel@tonic-gate * lookup /etc/hosts for IPv4 address 76*0Sstevel@tonic-gate * lookup DNS for IPv4 address 77*0Sstevel@tonic-gate * which may not meet people's requirement. 78*0Sstevel@tonic-gate * The right thing to happen is to have underlying layer which does 79*0Sstevel@tonic-gate * PF_UNSPEC lookup (lookup both) and return chain of addrinfos. 80*0Sstevel@tonic-gate * This would result in a bit of code duplicate with _dns_ghbyname() and 81*0Sstevel@tonic-gate * friends. 82*0Sstevel@tonic-gate */ 83*0Sstevel@tonic-gate 84*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 85*0Sstevel@tonic-gate 86*0Sstevel@tonic-gate #include "port_before.h" 87*0Sstevel@tonic-gate 88*0Sstevel@tonic-gate #include <sys/types.h> 89*0Sstevel@tonic-gate #include <sys/param.h> 90*0Sstevel@tonic-gate #include <sys/socket.h> 91*0Sstevel@tonic-gate 92*0Sstevel@tonic-gate #include <net/if.h> 93*0Sstevel@tonic-gate #include <netinet/in.h> 94*0Sstevel@tonic-gate 95*0Sstevel@tonic-gate #include <arpa/inet.h> 96*0Sstevel@tonic-gate #include <arpa/nameser.h> 97*0Sstevel@tonic-gate 98*0Sstevel@tonic-gate #include <netdb.h> 99*0Sstevel@tonic-gate #include <resolv.h> 100*0Sstevel@tonic-gate #include <string.h> 101*0Sstevel@tonic-gate #include <stdlib.h> 102*0Sstevel@tonic-gate #include <stddef.h> 103*0Sstevel@tonic-gate #include <ctype.h> 104*0Sstevel@tonic-gate #include <unistd.h> 105*0Sstevel@tonic-gate #include <stdio.h> 106*0Sstevel@tonic-gate #include <errno.h> 107*0Sstevel@tonic-gate 108*0Sstevel@tonic-gate #include <stdarg.h> 109*0Sstevel@tonic-gate 110*0Sstevel@tonic-gate #include <irs.h> 111*0Sstevel@tonic-gate #include <isc/assertions.h> 112*0Sstevel@tonic-gate 113*0Sstevel@tonic-gate #include "port_after.h" 114*0Sstevel@tonic-gate 115*0Sstevel@tonic-gate #include "irs_data.h" 116*0Sstevel@tonic-gate 117*0Sstevel@tonic-gate #define SUCCESS 0 118*0Sstevel@tonic-gate #define ANY 0 119*0Sstevel@tonic-gate #define YES 1 120*0Sstevel@tonic-gate #define NO 0 121*0Sstevel@tonic-gate 122*0Sstevel@tonic-gate static const char in_addrany[] = { 0, 0, 0, 0 }; 123*0Sstevel@tonic-gate static const char in6_addrany[] = { 124*0Sstevel@tonic-gate 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 125*0Sstevel@tonic-gate }; 126*0Sstevel@tonic-gate static const char in_loopback[] = { 127, 0, 0, 1 }; 127*0Sstevel@tonic-gate static const char in6_loopback[] = { 128*0Sstevel@tonic-gate 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 129*0Sstevel@tonic-gate }; 130*0Sstevel@tonic-gate 131*0Sstevel@tonic-gate static const struct afd { 132*0Sstevel@tonic-gate int a_af; 133*0Sstevel@tonic-gate int a_addrlen; 134*0Sstevel@tonic-gate int a_socklen; 135*0Sstevel@tonic-gate int a_off; 136*0Sstevel@tonic-gate const char *a_addrany; 137*0Sstevel@tonic-gate const char *a_loopback; 138*0Sstevel@tonic-gate int a_scoped; 139*0Sstevel@tonic-gate } afdl [] = { 140*0Sstevel@tonic-gate {PF_INET6, sizeof(struct in6_addr), 141*0Sstevel@tonic-gate sizeof(struct sockaddr_in6), 142*0Sstevel@tonic-gate offsetof(struct sockaddr_in6, sin6_addr), 143*0Sstevel@tonic-gate in6_addrany, in6_loopback, 1}, 144*0Sstevel@tonic-gate {PF_INET, sizeof(struct in_addr), 145*0Sstevel@tonic-gate sizeof(struct sockaddr_in), 146*0Sstevel@tonic-gate offsetof(struct sockaddr_in, sin_addr), 147*0Sstevel@tonic-gate in_addrany, in_loopback, 0}, 148*0Sstevel@tonic-gate {0, 0, 0, 0, NULL, NULL, 0}, 149*0Sstevel@tonic-gate }; 150*0Sstevel@tonic-gate 151*0Sstevel@tonic-gate struct explore { 152*0Sstevel@tonic-gate int e_af; 153*0Sstevel@tonic-gate int e_socktype; 154*0Sstevel@tonic-gate int e_protocol; 155*0Sstevel@tonic-gate const char *e_protostr; 156*0Sstevel@tonic-gate int e_wild; 157*0Sstevel@tonic-gate #define WILD_AF(ex) ((ex)->e_wild & 0x01) 158*0Sstevel@tonic-gate #define WILD_SOCKTYPE(ex) ((ex)->e_wild & 0x02) 159*0Sstevel@tonic-gate #define WILD_PROTOCOL(ex) ((ex)->e_wild & 0x04) 160*0Sstevel@tonic-gate }; 161*0Sstevel@tonic-gate 162*0Sstevel@tonic-gate static const struct explore explore[] = { 163*0Sstevel@tonic-gate #if 0 164*0Sstevel@tonic-gate { PF_LOCAL, 0, ANY, ANY, NULL, 0x01 }, 165*0Sstevel@tonic-gate #endif 166*0Sstevel@tonic-gate { PF_INET6, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 }, 167*0Sstevel@tonic-gate { PF_INET6, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 }, 168*0Sstevel@tonic-gate { PF_INET6, SOCK_RAW, ANY, NULL, 0x05 }, 169*0Sstevel@tonic-gate { PF_INET, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 }, 170*0Sstevel@tonic-gate { PF_INET, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 }, 171*0Sstevel@tonic-gate { PF_INET, SOCK_RAW, ANY, NULL, 0x05 }, 172*0Sstevel@tonic-gate { -1, 0, 0, NULL, 0 }, 173*0Sstevel@tonic-gate }; 174*0Sstevel@tonic-gate 175*0Sstevel@tonic-gate #define PTON_MAX 16 176*0Sstevel@tonic-gate 177*0Sstevel@tonic-gate static int str_isnumber __P((const char *)); 178*0Sstevel@tonic-gate static int explore_fqdn __P((const struct addrinfo *, const char *, 179*0Sstevel@tonic-gate const char *, struct addrinfo **)); 180*0Sstevel@tonic-gate static int explore_copy __P((const struct addrinfo *, const struct addrinfo *, 181*0Sstevel@tonic-gate struct addrinfo **)); 182*0Sstevel@tonic-gate static int explore_null __P((const struct addrinfo *, 183*0Sstevel@tonic-gate const char *, struct addrinfo **)); 184*0Sstevel@tonic-gate static int explore_numeric __P((const struct addrinfo *, const char *, 185*0Sstevel@tonic-gate const char *, struct addrinfo **)); 186*0Sstevel@tonic-gate static int explore_numeric_scope __P((const struct addrinfo *, const char *, 187*0Sstevel@tonic-gate const char *, struct addrinfo **)); 188*0Sstevel@tonic-gate static int get_canonname __P((const struct addrinfo *, 189*0Sstevel@tonic-gate struct addrinfo *, const char *)); 190*0Sstevel@tonic-gate static struct addrinfo *get_ai __P((const struct addrinfo *, 191*0Sstevel@tonic-gate const struct afd *, const char *)); 192*0Sstevel@tonic-gate static struct addrinfo *copy_ai __P((const struct addrinfo *)); 193*0Sstevel@tonic-gate static int get_portmatch __P((const struct addrinfo *, const char *)); 194*0Sstevel@tonic-gate static int get_port __P((const struct addrinfo *, const char *, int)); 195*0Sstevel@tonic-gate static const struct afd *find_afd __P((int)); 196*0Sstevel@tonic-gate static int addrconfig __P((int)); 197*0Sstevel@tonic-gate static int ip6_str2scopeid __P((char *, struct sockaddr_in6 *, 198*0Sstevel@tonic-gate u_int32_t *scopeidp)); 199*0Sstevel@tonic-gate static struct net_data *init __P((void)); 200*0Sstevel@tonic-gate 201*0Sstevel@tonic-gate struct addrinfo *hostent2addrinfo __P((struct hostent *, 202*0Sstevel@tonic-gate const struct addrinfo *)); 203*0Sstevel@tonic-gate struct addrinfo *addr2addrinfo __P((const struct addrinfo *, 204*0Sstevel@tonic-gate const char *)); 205*0Sstevel@tonic-gate 206*0Sstevel@tonic-gate #if 0 207*0Sstevel@tonic-gate static const char *ai_errlist[] = { 208*0Sstevel@tonic-gate "Success", 209*0Sstevel@tonic-gate "Address family for hostname not supported", /* EAI_ADDRFAMILY */ 210*0Sstevel@tonic-gate "Temporary failure in name resolution", /* EAI_AGAIN */ 211*0Sstevel@tonic-gate "Invalid value for ai_flags", /* EAI_BADFLAGS */ 212*0Sstevel@tonic-gate "Non-recoverable failure in name resolution", /* EAI_FAIL */ 213*0Sstevel@tonic-gate "ai_family not supported", /* EAI_FAMILY */ 214*0Sstevel@tonic-gate "Memory allocation failure", /* EAI_MEMORY */ 215*0Sstevel@tonic-gate "No address associated with hostname", /* EAI_NODATA */ 216*0Sstevel@tonic-gate "hostname nor servname provided, or not known", /* EAI_NONAME */ 217*0Sstevel@tonic-gate "servname not supported for ai_socktype", /* EAI_SERVICE */ 218*0Sstevel@tonic-gate "ai_socktype not supported", /* EAI_SOCKTYPE */ 219*0Sstevel@tonic-gate "System error returned in errno", /* EAI_SYSTEM */ 220*0Sstevel@tonic-gate "Invalid value for hints", /* EAI_BADHINTS */ 221*0Sstevel@tonic-gate "Resolved protocol is unknown", /* EAI_PROTOCOL */ 222*0Sstevel@tonic-gate "Unknown error", /* EAI_MAX */ 223*0Sstevel@tonic-gate }; 224*0Sstevel@tonic-gate #endif 225*0Sstevel@tonic-gate 226*0Sstevel@tonic-gate /* XXX macros that make external reference is BAD. */ 227*0Sstevel@tonic-gate 228*0Sstevel@tonic-gate #define GET_AI(ai, afd, addr) \ 229*0Sstevel@tonic-gate do { \ 230*0Sstevel@tonic-gate /* external reference: pai, error, and label free */ \ 231*0Sstevel@tonic-gate (ai) = get_ai(pai, (afd), (addr)); \ 232*0Sstevel@tonic-gate if ((ai) == NULL) { \ 233*0Sstevel@tonic-gate error = EAI_MEMORY; \ 234*0Sstevel@tonic-gate goto free; \ 235*0Sstevel@tonic-gate } \ 236*0Sstevel@tonic-gate } while (/*CONSTCOND*/0) 237*0Sstevel@tonic-gate 238*0Sstevel@tonic-gate #define GET_PORT(ai, serv) \ 239*0Sstevel@tonic-gate do { \ 240*0Sstevel@tonic-gate /* external reference: error and label free */ \ 241*0Sstevel@tonic-gate error = get_port((ai), (serv), 0); \ 242*0Sstevel@tonic-gate if (error != 0) \ 243*0Sstevel@tonic-gate goto free; \ 244*0Sstevel@tonic-gate } while (/*CONSTCOND*/0) 245*0Sstevel@tonic-gate 246*0Sstevel@tonic-gate #define GET_CANONNAME(ai, str) \ 247*0Sstevel@tonic-gate do { \ 248*0Sstevel@tonic-gate /* external reference: pai, error and label free */ \ 249*0Sstevel@tonic-gate error = get_canonname(pai, (ai), (str)); \ 250*0Sstevel@tonic-gate if (error != 0) \ 251*0Sstevel@tonic-gate goto free; \ 252*0Sstevel@tonic-gate } while (/*CONSTCOND*/0) 253*0Sstevel@tonic-gate 254*0Sstevel@tonic-gate /* 255*0Sstevel@tonic-gate * Our compiler does not like an unconditional branch out of a loop, 256*0Sstevel@tonic-gate * especially one defined in a macro! 257*0Sstevel@tonic-gate */ 258*0Sstevel@tonic-gate #ifdef ORIGINAL_ISC_CODE 259*0Sstevel@tonic-gate #define ERR(err) \ 260*0Sstevel@tonic-gate do { \ 261*0Sstevel@tonic-gate /* external reference: error, and label bad */ \ 262*0Sstevel@tonic-gate error = (err); \ 263*0Sstevel@tonic-gate goto bad; \ 264*0Sstevel@tonic-gate /*NOTREACHED*/ \ 265*0Sstevel@tonic-gate } while (/*CONSTCOND*/0) 266*0Sstevel@tonic-gate #else 267*0Sstevel@tonic-gate #define ERR(err) \ 268*0Sstevel@tonic-gate do { \ 269*0Sstevel@tonic-gate /* external reference: error */ \ 270*0Sstevel@tonic-gate error = (err); \ 271*0Sstevel@tonic-gate /*NOTREACHED*/ \ 272*0Sstevel@tonic-gate } while (/*CONSTCOND*/0) 273*0Sstevel@tonic-gate #endif 274*0Sstevel@tonic-gate 275*0Sstevel@tonic-gate #define MATCH_FAMILY(x, y, w) \ 276*0Sstevel@tonic-gate ((x) == (y) || (/*CONSTCOND*/(w) && ((x) == PF_UNSPEC || (y) == PF_UNSPEC))) 277*0Sstevel@tonic-gate #define MATCH(x, y, w) \ 278*0Sstevel@tonic-gate ((x) == (y) || (/*CONSTCOND*/(w) && ((x) == ANY || (y) == ANY))) 279*0Sstevel@tonic-gate 280*0Sstevel@tonic-gate #if 0 /* bind8 has its own version */ 281*0Sstevel@tonic-gate char * 282*0Sstevel@tonic-gate gai_strerror(ecode) 283*0Sstevel@tonic-gate int ecode; 284*0Sstevel@tonic-gate { 285*0Sstevel@tonic-gate if (ecode < 0 || ecode > EAI_MAX) 286*0Sstevel@tonic-gate ecode = EAI_MAX; 287*0Sstevel@tonic-gate return ai_errlist[ecode]; 288*0Sstevel@tonic-gate } 289*0Sstevel@tonic-gate #endif 290*0Sstevel@tonic-gate 291*0Sstevel@tonic-gate void 292*0Sstevel@tonic-gate freeaddrinfo(ai) 293*0Sstevel@tonic-gate struct addrinfo *ai; 294*0Sstevel@tonic-gate { 295*0Sstevel@tonic-gate struct addrinfo *next; 296*0Sstevel@tonic-gate 297*0Sstevel@tonic-gate do { 298*0Sstevel@tonic-gate next = ai->ai_next; 299*0Sstevel@tonic-gate if (ai->ai_canonname) 300*0Sstevel@tonic-gate free(ai->ai_canonname); 301*0Sstevel@tonic-gate /* no need to free(ai->ai_addr) */ 302*0Sstevel@tonic-gate free(ai); 303*0Sstevel@tonic-gate ai = next; 304*0Sstevel@tonic-gate } while (ai); 305*0Sstevel@tonic-gate } 306*0Sstevel@tonic-gate 307*0Sstevel@tonic-gate static int 308*0Sstevel@tonic-gate str_isnumber(p) 309*0Sstevel@tonic-gate const char *p; 310*0Sstevel@tonic-gate { 311*0Sstevel@tonic-gate char *ep; 312*0Sstevel@tonic-gate 313*0Sstevel@tonic-gate if (*p == '\0') 314*0Sstevel@tonic-gate return NO; 315*0Sstevel@tonic-gate ep = NULL; 316*0Sstevel@tonic-gate errno = 0; 317*0Sstevel@tonic-gate (void)strtoul(p, &ep, 10); 318*0Sstevel@tonic-gate if (errno == 0 && ep && *ep == '\0') 319*0Sstevel@tonic-gate return YES; 320*0Sstevel@tonic-gate else 321*0Sstevel@tonic-gate return NO; 322*0Sstevel@tonic-gate } 323*0Sstevel@tonic-gate 324*0Sstevel@tonic-gate int 325*0Sstevel@tonic-gate getaddrinfo(hostname, servname, hints, res) 326*0Sstevel@tonic-gate const char *hostname, *servname; 327*0Sstevel@tonic-gate const struct addrinfo *hints; 328*0Sstevel@tonic-gate struct addrinfo **res; 329*0Sstevel@tonic-gate { 330*0Sstevel@tonic-gate struct addrinfo sentinel; 331*0Sstevel@tonic-gate struct addrinfo *cur; 332*0Sstevel@tonic-gate int error = 0; 333*0Sstevel@tonic-gate struct addrinfo ai, ai0, *afai = NULL; 334*0Sstevel@tonic-gate struct addrinfo *pai; 335*0Sstevel@tonic-gate const struct explore *ex; 336*0Sstevel@tonic-gate 337*0Sstevel@tonic-gate memset(&sentinel, 0, sizeof(sentinel)); 338*0Sstevel@tonic-gate cur = &sentinel; 339*0Sstevel@tonic-gate pai = &ai; 340*0Sstevel@tonic-gate pai->ai_flags = 0; 341*0Sstevel@tonic-gate pai->ai_family = PF_UNSPEC; 342*0Sstevel@tonic-gate pai->ai_socktype = ANY; 343*0Sstevel@tonic-gate pai->ai_protocol = ANY; 344*0Sstevel@tonic-gate #ifndef ORIGINAL_ISC_CODE 345*0Sstevel@tonic-gate #ifdef __sparcv9 346*0Sstevel@tonic-gate /* 347*0Sstevel@tonic-gate * We need to clear _ai_pad to preserve binary 348*0Sstevel@tonic-gate * compatibility with previously compiled 64-bit 349*0Sstevel@tonic-gate * applications in a pre-SUSv3 environment by 350*0Sstevel@tonic-gate * guaranteeing the upper 32-bits are empty. 351*0Sstevel@tonic-gate */ 352*0Sstevel@tonic-gate pai->_ai_pad = 0; 353*0Sstevel@tonic-gate #endif /* __sparcv9 */ 354*0Sstevel@tonic-gate #endif /* ORIGINAL_ISC_CODE */ 355*0Sstevel@tonic-gate pai->ai_addrlen = 0; 356*0Sstevel@tonic-gate pai->ai_canonname = NULL; 357*0Sstevel@tonic-gate pai->ai_addr = NULL; 358*0Sstevel@tonic-gate pai->ai_next = NULL; 359*0Sstevel@tonic-gate 360*0Sstevel@tonic-gate if (hostname == NULL && servname == NULL) 361*0Sstevel@tonic-gate return EAI_NONAME; 362*0Sstevel@tonic-gate if (hints) { 363*0Sstevel@tonic-gate /* error check for hints */ 364*0Sstevel@tonic-gate if (hints->ai_addrlen || hints->ai_canonname || 365*0Sstevel@tonic-gate hints->ai_addr || hints->ai_next) { 366*0Sstevel@tonic-gate ERR(EAI_BADHINTS); /* xxx */ 367*0Sstevel@tonic-gate #if !defined(ORIGINAL_ISC_CODE) 368*0Sstevel@tonic-gate goto bad; 369*0Sstevel@tonic-gate #endif 370*0Sstevel@tonic-gate } 371*0Sstevel@tonic-gate /* 372*0Sstevel@tonic-gate * The AI_ macros defined by ISC are different than those defined by Solaris. 373*0Sstevel@tonic-gate * AI_MASK is defined by ISC to check the range of their flags and doesn't work 374*0Sstevel@tonic-gate * with Solaris. 375*0Sstevel@tonic-gate */ 376*0Sstevel@tonic-gate #ifdef ORIGINAL_ISC_CODE 377*0Sstevel@tonic-gate if (hints->ai_flags & ~AI_MASK) { 378*0Sstevel@tonic-gate ERR(EAI_BADFLAGS); 379*0Sstevel@tonic-gate } 380*0Sstevel@tonic-gate #endif 381*0Sstevel@tonic-gate switch (hints->ai_family) { 382*0Sstevel@tonic-gate case PF_UNSPEC: 383*0Sstevel@tonic-gate case PF_INET: 384*0Sstevel@tonic-gate case PF_INET6: 385*0Sstevel@tonic-gate break; 386*0Sstevel@tonic-gate default: 387*0Sstevel@tonic-gate ERR(EAI_FAMILY); 388*0Sstevel@tonic-gate #if !defined(ORIGINAL_ISC_CODE) 389*0Sstevel@tonic-gate goto bad; 390*0Sstevel@tonic-gate #endif 391*0Sstevel@tonic-gate } 392*0Sstevel@tonic-gate memcpy(pai, hints, sizeof(*pai)); 393*0Sstevel@tonic-gate 394*0Sstevel@tonic-gate #ifndef ORIGINAL_ISC_CODE 395*0Sstevel@tonic-gate #ifdef __sparcv9 396*0Sstevel@tonic-gate /* 397*0Sstevel@tonic-gate * We need to clear _ai_pad to preserve binary 398*0Sstevel@tonic-gate * compatibility. See prior comment. 399*0Sstevel@tonic-gate */ 400*0Sstevel@tonic-gate pai->_ai_pad = 0; 401*0Sstevel@tonic-gate #endif /* __sparcv9 */ 402*0Sstevel@tonic-gate #endif /* ORIGINAL_ISC_CODE */ 403*0Sstevel@tonic-gate /* 404*0Sstevel@tonic-gate * if both socktype/protocol are specified, check if they 405*0Sstevel@tonic-gate * are meaningful combination. 406*0Sstevel@tonic-gate */ 407*0Sstevel@tonic-gate if (pai->ai_socktype != ANY && pai->ai_protocol != ANY) { 408*0Sstevel@tonic-gate for (ex = explore; ex->e_af >= 0; ex++) { 409*0Sstevel@tonic-gate if (pai->ai_family != ex->e_af) 410*0Sstevel@tonic-gate continue; 411*0Sstevel@tonic-gate if (ex->e_socktype == ANY) 412*0Sstevel@tonic-gate continue; 413*0Sstevel@tonic-gate if (ex->e_protocol == ANY) 414*0Sstevel@tonic-gate continue; 415*0Sstevel@tonic-gate if (pai->ai_socktype == ex->e_socktype && 416*0Sstevel@tonic-gate pai->ai_protocol != ex->e_protocol) { 417*0Sstevel@tonic-gate ERR(EAI_BADHINTS); 418*0Sstevel@tonic-gate #if !defined(ORIGINAL_ISC_CODE) 419*0Sstevel@tonic-gate goto bad; 420*0Sstevel@tonic-gate #endif 421*0Sstevel@tonic-gate } 422*0Sstevel@tonic-gate } 423*0Sstevel@tonic-gate } 424*0Sstevel@tonic-gate } 425*0Sstevel@tonic-gate 426*0Sstevel@tonic-gate /* 427*0Sstevel@tonic-gate * post-2553: AI_ALL and AI_V4MAPPED are effective only against 428*0Sstevel@tonic-gate * AF_INET6 query. They needs to be ignored if specified in other 429*0Sstevel@tonic-gate * occassions. 430*0Sstevel@tonic-gate */ 431*0Sstevel@tonic-gate switch (pai->ai_flags & (AI_ALL | AI_V4MAPPED)) { 432*0Sstevel@tonic-gate case AI_V4MAPPED: 433*0Sstevel@tonic-gate case AI_ALL | AI_V4MAPPED: 434*0Sstevel@tonic-gate if (pai->ai_family != AF_INET6) 435*0Sstevel@tonic-gate pai->ai_flags &= ~(AI_ALL | AI_V4MAPPED); 436*0Sstevel@tonic-gate break; 437*0Sstevel@tonic-gate case AI_ALL: 438*0Sstevel@tonic-gate #if 1 439*0Sstevel@tonic-gate /* illegal */ 440*0Sstevel@tonic-gate ERR(EAI_BADFLAGS); 441*0Sstevel@tonic-gate #if !defined(ORIGINAL_ISC_CODE) 442*0Sstevel@tonic-gate goto bad; 443*0Sstevel@tonic-gate #endif 444*0Sstevel@tonic-gate #else 445*0Sstevel@tonic-gate pai->ai_flags &= ~(AI_ALL | AI_V4MAPPED); 446*0Sstevel@tonic-gate break; 447*0Sstevel@tonic-gate #endif 448*0Sstevel@tonic-gate } 449*0Sstevel@tonic-gate 450*0Sstevel@tonic-gate /* 451*0Sstevel@tonic-gate * check for special cases. (1) numeric servname is disallowed if 452*0Sstevel@tonic-gate * socktype/protocol are left unspecified. (2) servname is disallowed 453*0Sstevel@tonic-gate * for raw and other inet{,6} sockets. 454*0Sstevel@tonic-gate */ 455*0Sstevel@tonic-gate if (MATCH_FAMILY(pai->ai_family, PF_INET, 1) 456*0Sstevel@tonic-gate #ifdef PF_INET6 457*0Sstevel@tonic-gate || MATCH_FAMILY(pai->ai_family, PF_INET6, 1) 458*0Sstevel@tonic-gate #endif 459*0Sstevel@tonic-gate ) { 460*0Sstevel@tonic-gate ai0 = *pai; /* backup *pai */ 461*0Sstevel@tonic-gate 462*0Sstevel@tonic-gate if (pai->ai_family == PF_UNSPEC) { 463*0Sstevel@tonic-gate #ifdef PF_INET6 464*0Sstevel@tonic-gate pai->ai_family = PF_INET6; 465*0Sstevel@tonic-gate #else 466*0Sstevel@tonic-gate pai->ai_family = PF_INET; 467*0Sstevel@tonic-gate #endif 468*0Sstevel@tonic-gate } 469*0Sstevel@tonic-gate error = get_portmatch(pai, servname); 470*0Sstevel@tonic-gate if (error) { 471*0Sstevel@tonic-gate ERR(error); 472*0Sstevel@tonic-gate #if !defined(ORIGINAL_ISC_CODE) 473*0Sstevel@tonic-gate goto bad; 474*0Sstevel@tonic-gate #endif 475*0Sstevel@tonic-gate } 476*0Sstevel@tonic-gate 477*0Sstevel@tonic-gate *pai = ai0; 478*0Sstevel@tonic-gate } 479*0Sstevel@tonic-gate 480*0Sstevel@tonic-gate ai0 = *pai; 481*0Sstevel@tonic-gate 482*0Sstevel@tonic-gate /* NULL hostname, or numeric hostname */ 483*0Sstevel@tonic-gate for (ex = explore; ex->e_af >= 0; ex++) { 484*0Sstevel@tonic-gate *pai = ai0; 485*0Sstevel@tonic-gate 486*0Sstevel@tonic-gate if (!MATCH_FAMILY(pai->ai_family, ex->e_af, WILD_AF(ex))) 487*0Sstevel@tonic-gate continue; 488*0Sstevel@tonic-gate if (!MATCH(pai->ai_socktype, ex->e_socktype, WILD_SOCKTYPE(ex))) 489*0Sstevel@tonic-gate continue; 490*0Sstevel@tonic-gate if (!MATCH(pai->ai_protocol, ex->e_protocol, WILD_PROTOCOL(ex))) 491*0Sstevel@tonic-gate continue; 492*0Sstevel@tonic-gate 493*0Sstevel@tonic-gate if (pai->ai_family == PF_UNSPEC) 494*0Sstevel@tonic-gate pai->ai_family = ex->e_af; 495*0Sstevel@tonic-gate if (pai->ai_socktype == ANY && ex->e_socktype != ANY) 496*0Sstevel@tonic-gate pai->ai_socktype = ex->e_socktype; 497*0Sstevel@tonic-gate if (pai->ai_protocol == ANY && ex->e_protocol != ANY) 498*0Sstevel@tonic-gate pai->ai_protocol = ex->e_protocol; 499*0Sstevel@tonic-gate 500*0Sstevel@tonic-gate /* 501*0Sstevel@tonic-gate * if the servname does not match socktype/protocol, ignore it. 502*0Sstevel@tonic-gate */ 503*0Sstevel@tonic-gate if (get_portmatch(pai, servname) != 0) 504*0Sstevel@tonic-gate continue; 505*0Sstevel@tonic-gate 506*0Sstevel@tonic-gate if (hostname == NULL) { 507*0Sstevel@tonic-gate /* 508*0Sstevel@tonic-gate * filter out AFs that are not supported by the kernel 509*0Sstevel@tonic-gate * XXX errno? 510*0Sstevel@tonic-gate */ 511*0Sstevel@tonic-gate if (!addrconfig(pai->ai_family)) 512*0Sstevel@tonic-gate continue; 513*0Sstevel@tonic-gate error = explore_null(pai, servname, &cur->ai_next); 514*0Sstevel@tonic-gate } else 515*0Sstevel@tonic-gate error = explore_numeric_scope(pai, hostname, servname, 516*0Sstevel@tonic-gate &cur->ai_next); 517*0Sstevel@tonic-gate 518*0Sstevel@tonic-gate if (error) 519*0Sstevel@tonic-gate goto free; 520*0Sstevel@tonic-gate 521*0Sstevel@tonic-gate while (cur && cur->ai_next) 522*0Sstevel@tonic-gate cur = cur->ai_next; 523*0Sstevel@tonic-gate } 524*0Sstevel@tonic-gate 525*0Sstevel@tonic-gate /* 526*0Sstevel@tonic-gate * XXX 527*0Sstevel@tonic-gate * If numreic representation of AF1 can be interpreted as FQDN 528*0Sstevel@tonic-gate * representation of AF2, we need to think again about the code below. 529*0Sstevel@tonic-gate */ 530*0Sstevel@tonic-gate if (sentinel.ai_next) 531*0Sstevel@tonic-gate goto good; 532*0Sstevel@tonic-gate 533*0Sstevel@tonic-gate if (pai->ai_flags & AI_NUMERICHOST) { 534*0Sstevel@tonic-gate ERR(EAI_NONAME); 535*0Sstevel@tonic-gate #if !defined(ORIGINAL_ISC_CODE) 536*0Sstevel@tonic-gate goto bad; 537*0Sstevel@tonic-gate #endif 538*0Sstevel@tonic-gate } 539*0Sstevel@tonic-gate if (hostname == NULL) { 540*0Sstevel@tonic-gate ERR(EAI_NONAME); 541*0Sstevel@tonic-gate #if !defined(ORIGINAL_ISC_CODE) 542*0Sstevel@tonic-gate goto bad; 543*0Sstevel@tonic-gate #endif 544*0Sstevel@tonic-gate } 545*0Sstevel@tonic-gate 546*0Sstevel@tonic-gate /* 547*0Sstevel@tonic-gate * hostname as alphabetical name. 548*0Sstevel@tonic-gate * We'll make sure that 549*0Sstevel@tonic-gate * - if returning addrinfo list is empty, return non-zero error 550*0Sstevel@tonic-gate * value (already known one or EAI_NONAME). 551*0Sstevel@tonic-gate * - otherwise, 552*0Sstevel@tonic-gate * + if we haven't had any errors, return 0 (i.e. success). 553*0Sstevel@tonic-gate * + if we've had an error, free the list and return the error. 554*0Sstevel@tonic-gate * without any assumption on the behavior of explore_fqdn(). 555*0Sstevel@tonic-gate */ 556*0Sstevel@tonic-gate 557*0Sstevel@tonic-gate /* first, try to query DNS for all possible address families. */ 558*0Sstevel@tonic-gate *pai = ai0; 559*0Sstevel@tonic-gate error = explore_fqdn(pai, hostname, servname, &afai); 560*0Sstevel@tonic-gate if (error) { 561*0Sstevel@tonic-gate if (afai != NULL) 562*0Sstevel@tonic-gate freeaddrinfo(afai); 563*0Sstevel@tonic-gate goto free; 564*0Sstevel@tonic-gate } 565*0Sstevel@tonic-gate if (afai == NULL) { 566*0Sstevel@tonic-gate error = EAI_NONAME; /* we've had no errors. */ 567*0Sstevel@tonic-gate goto free; 568*0Sstevel@tonic-gate } 569*0Sstevel@tonic-gate 570*0Sstevel@tonic-gate /* 571*0Sstevel@tonic-gate * we would like to prefer AF_INET6 than AF_INET, so we'll make an 572*0Sstevel@tonic-gate * outer loop by AFs. 573*0Sstevel@tonic-gate */ 574*0Sstevel@tonic-gate for (ex = explore; ex->e_af >= 0; ex++) { 575*0Sstevel@tonic-gate *pai = ai0; 576*0Sstevel@tonic-gate 577*0Sstevel@tonic-gate if (pai->ai_family == PF_UNSPEC) 578*0Sstevel@tonic-gate pai->ai_family = ex->e_af; 579*0Sstevel@tonic-gate 580*0Sstevel@tonic-gate if (!MATCH_FAMILY(pai->ai_family, ex->e_af, WILD_AF(ex))) 581*0Sstevel@tonic-gate continue; 582*0Sstevel@tonic-gate if (!MATCH(pai->ai_socktype, ex->e_socktype, 583*0Sstevel@tonic-gate WILD_SOCKTYPE(ex))) { 584*0Sstevel@tonic-gate continue; 585*0Sstevel@tonic-gate } 586*0Sstevel@tonic-gate if (!MATCH(pai->ai_protocol, ex->e_protocol, 587*0Sstevel@tonic-gate WILD_PROTOCOL(ex))) { 588*0Sstevel@tonic-gate continue; 589*0Sstevel@tonic-gate } 590*0Sstevel@tonic-gate 591*0Sstevel@tonic-gate #ifdef AI_ADDRCONFIG 592*0Sstevel@tonic-gate /* 593*0Sstevel@tonic-gate * If AI_ADDRCONFIG is specified, check if we are 594*0Sstevel@tonic-gate * expected to return the address family or not. 595*0Sstevel@tonic-gate */ 596*0Sstevel@tonic-gate if ((pai->ai_flags & AI_ADDRCONFIG) != 0 && 597*0Sstevel@tonic-gate !addrconfig(pai->ai_family)) 598*0Sstevel@tonic-gate continue; 599*0Sstevel@tonic-gate #endif 600*0Sstevel@tonic-gate 601*0Sstevel@tonic-gate if (pai->ai_family == PF_UNSPEC) 602*0Sstevel@tonic-gate pai->ai_family = ex->e_af; 603*0Sstevel@tonic-gate if (pai->ai_socktype == ANY && ex->e_socktype != ANY) 604*0Sstevel@tonic-gate pai->ai_socktype = ex->e_socktype; 605*0Sstevel@tonic-gate if (pai->ai_protocol == ANY && ex->e_protocol != ANY) 606*0Sstevel@tonic-gate pai->ai_protocol = ex->e_protocol; 607*0Sstevel@tonic-gate 608*0Sstevel@tonic-gate /* 609*0Sstevel@tonic-gate * if the servname does not match socktype/protocol, ignore it. 610*0Sstevel@tonic-gate */ 611*0Sstevel@tonic-gate if (get_portmatch(pai, servname) != 0) 612*0Sstevel@tonic-gate continue; 613*0Sstevel@tonic-gate 614*0Sstevel@tonic-gate if ((error = explore_copy(pai, afai, &cur->ai_next)) != 0) { 615*0Sstevel@tonic-gate freeaddrinfo(afai); 616*0Sstevel@tonic-gate goto free; 617*0Sstevel@tonic-gate } 618*0Sstevel@tonic-gate 619*0Sstevel@tonic-gate while (cur && cur->ai_next) 620*0Sstevel@tonic-gate cur = cur->ai_next; 621*0Sstevel@tonic-gate } 622*0Sstevel@tonic-gate 623*0Sstevel@tonic-gate freeaddrinfo(afai); /* afai must not be NULL at this point. */ 624*0Sstevel@tonic-gate 625*0Sstevel@tonic-gate /* we must not have got any errors. */ 626*0Sstevel@tonic-gate if (error != 0) /* just for diagnosis */ 627*0Sstevel@tonic-gate abort(); 628*0Sstevel@tonic-gate 629*0Sstevel@tonic-gate if (sentinel.ai_next) { 630*0Sstevel@tonic-gate good: 631*0Sstevel@tonic-gate *res = sentinel.ai_next; 632*0Sstevel@tonic-gate return(SUCCESS); 633*0Sstevel@tonic-gate } else { 634*0Sstevel@tonic-gate /* 635*0Sstevel@tonic-gate * All the process succeeded, but we've had an empty list. 636*0Sstevel@tonic-gate * This can happen if the given hints do not match our 637*0Sstevel@tonic-gate * candidates. 638*0Sstevel@tonic-gate */ 639*0Sstevel@tonic-gate error = EAI_NONAME; 640*0Sstevel@tonic-gate } 641*0Sstevel@tonic-gate 642*0Sstevel@tonic-gate free: 643*0Sstevel@tonic-gate bad: 644*0Sstevel@tonic-gate if (sentinel.ai_next) 645*0Sstevel@tonic-gate freeaddrinfo(sentinel.ai_next); 646*0Sstevel@tonic-gate *res = NULL; 647*0Sstevel@tonic-gate return(error); 648*0Sstevel@tonic-gate } 649*0Sstevel@tonic-gate 650*0Sstevel@tonic-gate /* 651*0Sstevel@tonic-gate * FQDN hostname, DNS lookup 652*0Sstevel@tonic-gate */ 653*0Sstevel@tonic-gate static int 654*0Sstevel@tonic-gate explore_fqdn(pai, hostname, servname, res) 655*0Sstevel@tonic-gate const struct addrinfo *pai; 656*0Sstevel@tonic-gate const char *hostname; 657*0Sstevel@tonic-gate const char *servname; 658*0Sstevel@tonic-gate struct addrinfo **res; 659*0Sstevel@tonic-gate { 660*0Sstevel@tonic-gate struct addrinfo *result; 661*0Sstevel@tonic-gate struct addrinfo *cur; 662*0Sstevel@tonic-gate struct net_data *net_data = init(); 663*0Sstevel@tonic-gate struct irs_ho *ho; 664*0Sstevel@tonic-gate int error = 0; 665*0Sstevel@tonic-gate char tmp[NS_MAXDNAME]; 666*0Sstevel@tonic-gate const char *cp; 667*0Sstevel@tonic-gate 668*0Sstevel@tonic-gate INSIST(res != NULL && *res == NULL); 669*0Sstevel@tonic-gate 670*0Sstevel@tonic-gate /* 671*0Sstevel@tonic-gate * if the servname does not match socktype/protocol, ignore it. 672*0Sstevel@tonic-gate */ 673*0Sstevel@tonic-gate if (get_portmatch(pai, servname) != 0) 674*0Sstevel@tonic-gate return(0); 675*0Sstevel@tonic-gate 676*0Sstevel@tonic-gate if (!net_data || !(ho = net_data->ho)) 677*0Sstevel@tonic-gate return(0); 678*0Sstevel@tonic-gate #if 0 /* XXX (notyet) */ 679*0Sstevel@tonic-gate if (net_data->ho_stayopen && net_data->ho_last && 680*0Sstevel@tonic-gate net_data->ho_last->h_addrtype == af) { 681*0Sstevel@tonic-gate if (ns_samename(name, net_data->ho_last->h_name) == 1) 682*0Sstevel@tonic-gate return (net_data->ho_last); 683*0Sstevel@tonic-gate for (hap = net_data->ho_last->h_aliases; hap && *hap; hap++) 684*0Sstevel@tonic-gate if (ns_samename(name, *hap) == 1) 685*0Sstevel@tonic-gate return (net_data->ho_last); 686*0Sstevel@tonic-gate } 687*0Sstevel@tonic-gate #endif 688*0Sstevel@tonic-gate if (!strchr(hostname, '.') && 689*0Sstevel@tonic-gate (cp = res_hostalias(net_data->res, hostname, 690*0Sstevel@tonic-gate tmp, sizeof(tmp)))) 691*0Sstevel@tonic-gate hostname = cp; 692*0Sstevel@tonic-gate result = (*ho->addrinfo)(ho, hostname, pai); 693*0Sstevel@tonic-gate if (!net_data->ho_stayopen) { 694*0Sstevel@tonic-gate (*ho->minimize)(ho); 695*0Sstevel@tonic-gate } 696*0Sstevel@tonic-gate if (result == NULL) { 697*0Sstevel@tonic-gate int e = h_errno; 698*0Sstevel@tonic-gate 699*0Sstevel@tonic-gate switch(e) { 700*0Sstevel@tonic-gate case NETDB_INTERNAL: 701*0Sstevel@tonic-gate error = EAI_SYSTEM; 702*0Sstevel@tonic-gate break; 703*0Sstevel@tonic-gate case TRY_AGAIN: 704*0Sstevel@tonic-gate error = EAI_AGAIN; 705*0Sstevel@tonic-gate break; 706*0Sstevel@tonic-gate case NO_RECOVERY: 707*0Sstevel@tonic-gate error = EAI_FAIL; 708*0Sstevel@tonic-gate break; 709*0Sstevel@tonic-gate case HOST_NOT_FOUND: 710*0Sstevel@tonic-gate case NO_DATA: 711*0Sstevel@tonic-gate error = EAI_NONAME; 712*0Sstevel@tonic-gate break; 713*0Sstevel@tonic-gate default: 714*0Sstevel@tonic-gate case NETDB_SUCCESS: /* should be impossible... */ 715*0Sstevel@tonic-gate error = EAI_NONAME; 716*0Sstevel@tonic-gate break; 717*0Sstevel@tonic-gate } 718*0Sstevel@tonic-gate goto free; 719*0Sstevel@tonic-gate } 720*0Sstevel@tonic-gate 721*0Sstevel@tonic-gate for (cur = result; cur; cur = cur->ai_next) { 722*0Sstevel@tonic-gate GET_PORT(cur, servname); /* XXX: redundant lookups... */ 723*0Sstevel@tonic-gate /* canonname should already be filled. */ 724*0Sstevel@tonic-gate } 725*0Sstevel@tonic-gate 726*0Sstevel@tonic-gate *res = result; 727*0Sstevel@tonic-gate 728*0Sstevel@tonic-gate return(0); 729*0Sstevel@tonic-gate 730*0Sstevel@tonic-gate free: 731*0Sstevel@tonic-gate if (result) 732*0Sstevel@tonic-gate freeaddrinfo(result); 733*0Sstevel@tonic-gate return error; 734*0Sstevel@tonic-gate } 735*0Sstevel@tonic-gate 736*0Sstevel@tonic-gate static int 737*0Sstevel@tonic-gate explore_copy(pai, src0, res) 738*0Sstevel@tonic-gate const struct addrinfo *pai; /* seed */ 739*0Sstevel@tonic-gate const struct addrinfo *src0; /* source */ 740*0Sstevel@tonic-gate struct addrinfo **res; 741*0Sstevel@tonic-gate { 742*0Sstevel@tonic-gate int error; 743*0Sstevel@tonic-gate struct addrinfo sentinel, *cur; 744*0Sstevel@tonic-gate const struct addrinfo *src; 745*0Sstevel@tonic-gate 746*0Sstevel@tonic-gate error = 0; 747*0Sstevel@tonic-gate sentinel.ai_next = NULL; 748*0Sstevel@tonic-gate cur = &sentinel; 749*0Sstevel@tonic-gate 750*0Sstevel@tonic-gate for (src = src0; src != NULL; src = src->ai_next) { 751*0Sstevel@tonic-gate if (src->ai_family != pai->ai_family) 752*0Sstevel@tonic-gate continue; 753*0Sstevel@tonic-gate 754*0Sstevel@tonic-gate cur->ai_next = copy_ai(src); 755*0Sstevel@tonic-gate if (!cur->ai_next) { 756*0Sstevel@tonic-gate error = EAI_MEMORY; 757*0Sstevel@tonic-gate goto fail; 758*0Sstevel@tonic-gate } 759*0Sstevel@tonic-gate 760*0Sstevel@tonic-gate cur->ai_next->ai_socktype = pai->ai_socktype; 761*0Sstevel@tonic-gate cur->ai_next->ai_protocol = pai->ai_protocol; 762*0Sstevel@tonic-gate cur = cur->ai_next; 763*0Sstevel@tonic-gate } 764*0Sstevel@tonic-gate 765*0Sstevel@tonic-gate *res = sentinel.ai_next; 766*0Sstevel@tonic-gate return 0; 767*0Sstevel@tonic-gate 768*0Sstevel@tonic-gate fail: 769*0Sstevel@tonic-gate freeaddrinfo(sentinel.ai_next); 770*0Sstevel@tonic-gate return error; 771*0Sstevel@tonic-gate } 772*0Sstevel@tonic-gate 773*0Sstevel@tonic-gate /* 774*0Sstevel@tonic-gate * hostname == NULL. 775*0Sstevel@tonic-gate * passive socket -> anyaddr (0.0.0.0 or ::) 776*0Sstevel@tonic-gate * non-passive socket -> localhost (127.0.0.1 or ::1) 777*0Sstevel@tonic-gate */ 778*0Sstevel@tonic-gate static int 779*0Sstevel@tonic-gate explore_null(pai, servname, res) 780*0Sstevel@tonic-gate const struct addrinfo *pai; 781*0Sstevel@tonic-gate const char *servname; 782*0Sstevel@tonic-gate struct addrinfo **res; 783*0Sstevel@tonic-gate { 784*0Sstevel@tonic-gate const struct afd *afd; 785*0Sstevel@tonic-gate struct addrinfo *cur; 786*0Sstevel@tonic-gate struct addrinfo sentinel; 787*0Sstevel@tonic-gate int error; 788*0Sstevel@tonic-gate 789*0Sstevel@tonic-gate *res = NULL; 790*0Sstevel@tonic-gate sentinel.ai_next = NULL; 791*0Sstevel@tonic-gate cur = &sentinel; 792*0Sstevel@tonic-gate 793*0Sstevel@tonic-gate afd = find_afd(pai->ai_family); 794*0Sstevel@tonic-gate if (afd == NULL) 795*0Sstevel@tonic-gate return 0; 796*0Sstevel@tonic-gate 797*0Sstevel@tonic-gate if (pai->ai_flags & AI_PASSIVE) { 798*0Sstevel@tonic-gate GET_AI(cur->ai_next, afd, afd->a_addrany); 799*0Sstevel@tonic-gate /* xxx meaningless? 800*0Sstevel@tonic-gate * GET_CANONNAME(cur->ai_next, "anyaddr"); 801*0Sstevel@tonic-gate */ 802*0Sstevel@tonic-gate GET_PORT(cur->ai_next, servname); 803*0Sstevel@tonic-gate } else { 804*0Sstevel@tonic-gate GET_AI(cur->ai_next, afd, afd->a_loopback); 805*0Sstevel@tonic-gate /* xxx meaningless? 806*0Sstevel@tonic-gate * GET_CANONNAME(cur->ai_next, "localhost"); 807*0Sstevel@tonic-gate */ 808*0Sstevel@tonic-gate GET_PORT(cur->ai_next, servname); 809*0Sstevel@tonic-gate } 810*0Sstevel@tonic-gate cur = cur->ai_next; 811*0Sstevel@tonic-gate 812*0Sstevel@tonic-gate *res = sentinel.ai_next; 813*0Sstevel@tonic-gate return 0; 814*0Sstevel@tonic-gate 815*0Sstevel@tonic-gate free: 816*0Sstevel@tonic-gate if (sentinel.ai_next) 817*0Sstevel@tonic-gate freeaddrinfo(sentinel.ai_next); 818*0Sstevel@tonic-gate return error; 819*0Sstevel@tonic-gate } 820*0Sstevel@tonic-gate 821*0Sstevel@tonic-gate /* 822*0Sstevel@tonic-gate * numeric hostname 823*0Sstevel@tonic-gate */ 824*0Sstevel@tonic-gate static int 825*0Sstevel@tonic-gate explore_numeric(pai, hostname, servname, res) 826*0Sstevel@tonic-gate const struct addrinfo *pai; 827*0Sstevel@tonic-gate const char *hostname; 828*0Sstevel@tonic-gate const char *servname; 829*0Sstevel@tonic-gate struct addrinfo **res; 830*0Sstevel@tonic-gate { 831*0Sstevel@tonic-gate const struct afd *afd; 832*0Sstevel@tonic-gate struct addrinfo *cur; 833*0Sstevel@tonic-gate struct addrinfo sentinel; 834*0Sstevel@tonic-gate int error; 835*0Sstevel@tonic-gate char pton[PTON_MAX]; 836*0Sstevel@tonic-gate 837*0Sstevel@tonic-gate *res = NULL; 838*0Sstevel@tonic-gate sentinel.ai_next = NULL; 839*0Sstevel@tonic-gate cur = &sentinel; 840*0Sstevel@tonic-gate 841*0Sstevel@tonic-gate afd = find_afd(pai->ai_family); 842*0Sstevel@tonic-gate if (afd == NULL) 843*0Sstevel@tonic-gate return 0; 844*0Sstevel@tonic-gate 845*0Sstevel@tonic-gate switch (afd->a_af) { 846*0Sstevel@tonic-gate #if 0 /*X/Open spec*/ 847*0Sstevel@tonic-gate case AF_INET: 848*0Sstevel@tonic-gate if (inet_aton(hostname, (struct in_addr *)pton) == 1) { 849*0Sstevel@tonic-gate if (pai->ai_family == afd->a_af || 850*0Sstevel@tonic-gate pai->ai_family == PF_UNSPEC /*?*/) { 851*0Sstevel@tonic-gate GET_AI(cur->ai_next, afd, pton); 852*0Sstevel@tonic-gate GET_PORT(cur->ai_next, servname); 853*0Sstevel@tonic-gate while (cur && cur->ai_next) 854*0Sstevel@tonic-gate cur = cur->ai_next; 855*0Sstevel@tonic-gate } else 856*0Sstevel@tonic-gate ERR(EAI_FAMILY); /*xxx*/ 857*0Sstevel@tonic-gate } 858*0Sstevel@tonic-gate break; 859*0Sstevel@tonic-gate #endif 860*0Sstevel@tonic-gate default: 861*0Sstevel@tonic-gate if (inet_pton(afd->a_af, hostname, pton) == 1) { 862*0Sstevel@tonic-gate if (pai->ai_family == afd->a_af || 863*0Sstevel@tonic-gate pai->ai_family == PF_UNSPEC /*?*/) { 864*0Sstevel@tonic-gate GET_AI(cur->ai_next, afd, pton); 865*0Sstevel@tonic-gate GET_PORT(cur->ai_next, servname); 866*0Sstevel@tonic-gate while (cur && cur->ai_next) 867*0Sstevel@tonic-gate cur = cur->ai_next; 868*0Sstevel@tonic-gate } else { 869*0Sstevel@tonic-gate ERR(EAI_FAMILY); /*xxx*/ 870*0Sstevel@tonic-gate #if !defined(ORIGINAL_ISC_CODE) 871*0Sstevel@tonic-gate goto bad; 872*0Sstevel@tonic-gate #endif 873*0Sstevel@tonic-gate } 874*0Sstevel@tonic-gate } 875*0Sstevel@tonic-gate break; 876*0Sstevel@tonic-gate } 877*0Sstevel@tonic-gate 878*0Sstevel@tonic-gate *res = sentinel.ai_next; 879*0Sstevel@tonic-gate return 0; 880*0Sstevel@tonic-gate 881*0Sstevel@tonic-gate free: 882*0Sstevel@tonic-gate bad: 883*0Sstevel@tonic-gate if (sentinel.ai_next) 884*0Sstevel@tonic-gate freeaddrinfo(sentinel.ai_next); 885*0Sstevel@tonic-gate return error; 886*0Sstevel@tonic-gate } 887*0Sstevel@tonic-gate 888*0Sstevel@tonic-gate /* 889*0Sstevel@tonic-gate * numeric hostname with scope 890*0Sstevel@tonic-gate */ 891*0Sstevel@tonic-gate static int 892*0Sstevel@tonic-gate explore_numeric_scope(pai, hostname, servname, res) 893*0Sstevel@tonic-gate const struct addrinfo *pai; 894*0Sstevel@tonic-gate const char *hostname; 895*0Sstevel@tonic-gate const char *servname; 896*0Sstevel@tonic-gate struct addrinfo **res; 897*0Sstevel@tonic-gate { 898*0Sstevel@tonic-gate #ifndef SCOPE_DELIMITER 899*0Sstevel@tonic-gate return explore_numeric(pai, hostname, servname, res); 900*0Sstevel@tonic-gate #else 901*0Sstevel@tonic-gate const struct afd *afd; 902*0Sstevel@tonic-gate struct addrinfo *cur; 903*0Sstevel@tonic-gate int error; 904*0Sstevel@tonic-gate char *cp, *hostname2 = NULL, *scope, *addr; 905*0Sstevel@tonic-gate struct sockaddr_in6 *sin6; 906*0Sstevel@tonic-gate 907*0Sstevel@tonic-gate afd = find_afd(pai->ai_family); 908*0Sstevel@tonic-gate if (afd == NULL) 909*0Sstevel@tonic-gate return 0; 910*0Sstevel@tonic-gate 911*0Sstevel@tonic-gate if (!afd->a_scoped) 912*0Sstevel@tonic-gate return explore_numeric(pai, hostname, servname, res); 913*0Sstevel@tonic-gate 914*0Sstevel@tonic-gate cp = strchr(hostname, SCOPE_DELIMITER); 915*0Sstevel@tonic-gate if (cp == NULL) 916*0Sstevel@tonic-gate return explore_numeric(pai, hostname, servname, res); 917*0Sstevel@tonic-gate 918*0Sstevel@tonic-gate /* 919*0Sstevel@tonic-gate * Handle special case of <scoped_address><delimiter><scope id> 920*0Sstevel@tonic-gate */ 921*0Sstevel@tonic-gate hostname2 = strdup(hostname); 922*0Sstevel@tonic-gate if (hostname2 == NULL) 923*0Sstevel@tonic-gate return EAI_MEMORY; 924*0Sstevel@tonic-gate /* terminate at the delimiter */ 925*0Sstevel@tonic-gate hostname2[cp - hostname] = '\0'; 926*0Sstevel@tonic-gate addr = hostname2; 927*0Sstevel@tonic-gate scope = cp + 1; 928*0Sstevel@tonic-gate 929*0Sstevel@tonic-gate error = explore_numeric(pai, addr, servname, res); 930*0Sstevel@tonic-gate if (error == 0) { 931*0Sstevel@tonic-gate u_int32_t scopeid = 0; 932*0Sstevel@tonic-gate 933*0Sstevel@tonic-gate for (cur = *res; cur; cur = cur->ai_next) { 934*0Sstevel@tonic-gate if (cur->ai_family != AF_INET6) 935*0Sstevel@tonic-gate continue; 936*0Sstevel@tonic-gate sin6 = (struct sockaddr_in6 *)(void *)cur->ai_addr; 937*0Sstevel@tonic-gate if (!ip6_str2scopeid(scope, sin6, &scopeid)) { 938*0Sstevel@tonic-gate free(hostname2); 939*0Sstevel@tonic-gate return(EAI_NONAME); /* XXX: is return OK? */ 940*0Sstevel@tonic-gate } 941*0Sstevel@tonic-gate #ifdef HAVE_SIN6_SCOPE_ID 942*0Sstevel@tonic-gate sin6->sin6_scope_id = scopeid; 943*0Sstevel@tonic-gate #endif 944*0Sstevel@tonic-gate } 945*0Sstevel@tonic-gate } 946*0Sstevel@tonic-gate 947*0Sstevel@tonic-gate free(hostname2); 948*0Sstevel@tonic-gate 949*0Sstevel@tonic-gate return error; 950*0Sstevel@tonic-gate #endif 951*0Sstevel@tonic-gate } 952*0Sstevel@tonic-gate 953*0Sstevel@tonic-gate static int 954*0Sstevel@tonic-gate get_canonname(pai, ai, str) 955*0Sstevel@tonic-gate const struct addrinfo *pai; 956*0Sstevel@tonic-gate struct addrinfo *ai; 957*0Sstevel@tonic-gate const char *str; 958*0Sstevel@tonic-gate { 959*0Sstevel@tonic-gate if ((pai->ai_flags & AI_CANONNAME) != 0) { 960*0Sstevel@tonic-gate ai->ai_canonname = (char *)malloc(strlen(str) + 1); 961*0Sstevel@tonic-gate if (ai->ai_canonname == NULL) 962*0Sstevel@tonic-gate return EAI_MEMORY; 963*0Sstevel@tonic-gate strcpy(ai->ai_canonname, str); 964*0Sstevel@tonic-gate } 965*0Sstevel@tonic-gate return 0; 966*0Sstevel@tonic-gate } 967*0Sstevel@tonic-gate 968*0Sstevel@tonic-gate static struct addrinfo * 969*0Sstevel@tonic-gate get_ai(pai, afd, addr) 970*0Sstevel@tonic-gate const struct addrinfo *pai; 971*0Sstevel@tonic-gate const struct afd *afd; 972*0Sstevel@tonic-gate const char *addr; 973*0Sstevel@tonic-gate { 974*0Sstevel@tonic-gate char *p; 975*0Sstevel@tonic-gate struct addrinfo *ai; 976*0Sstevel@tonic-gate 977*0Sstevel@tonic-gate ai = (struct addrinfo *)malloc(sizeof(struct addrinfo) 978*0Sstevel@tonic-gate + (afd->a_socklen)); 979*0Sstevel@tonic-gate if (ai == NULL) 980*0Sstevel@tonic-gate return NULL; 981*0Sstevel@tonic-gate 982*0Sstevel@tonic-gate memcpy(ai, pai, sizeof(struct addrinfo)); 983*0Sstevel@tonic-gate ai->ai_addr = (struct sockaddr *)(void *)(ai + 1); 984*0Sstevel@tonic-gate memset(ai->ai_addr, 0, (size_t)afd->a_socklen); 985*0Sstevel@tonic-gate #ifdef HAVE_SA_LEN 986*0Sstevel@tonic-gate ai->ai_addr->sa_len = afd->a_socklen; 987*0Sstevel@tonic-gate #endif 988*0Sstevel@tonic-gate ai->ai_addrlen = afd->a_socklen; 989*0Sstevel@tonic-gate ai->ai_addr->sa_family = ai->ai_family = afd->a_af; 990*0Sstevel@tonic-gate p = (char *)(void *)(ai->ai_addr); 991*0Sstevel@tonic-gate memcpy(p + afd->a_off, addr, (size_t)afd->a_addrlen); 992*0Sstevel@tonic-gate return ai; 993*0Sstevel@tonic-gate } 994*0Sstevel@tonic-gate 995*0Sstevel@tonic-gate /* XXX need to malloc() the same way we do from other functions! */ 996*0Sstevel@tonic-gate static struct addrinfo * 997*0Sstevel@tonic-gate copy_ai(pai) 998*0Sstevel@tonic-gate const struct addrinfo *pai; 999*0Sstevel@tonic-gate { 1000*0Sstevel@tonic-gate struct addrinfo *ai; 1001*0Sstevel@tonic-gate size_t l; 1002*0Sstevel@tonic-gate 1003*0Sstevel@tonic-gate l = sizeof(*ai) + pai->ai_addrlen; 1004*0Sstevel@tonic-gate if ((ai = (struct addrinfo *)malloc(l)) == NULL) 1005*0Sstevel@tonic-gate return NULL; 1006*0Sstevel@tonic-gate memset(ai, 0, l); 1007*0Sstevel@tonic-gate memcpy(ai, pai, sizeof(*ai)); 1008*0Sstevel@tonic-gate ai->ai_addr = (struct sockaddr *)(void *)(ai + 1); 1009*0Sstevel@tonic-gate memcpy(ai->ai_addr, pai->ai_addr, pai->ai_addrlen); 1010*0Sstevel@tonic-gate 1011*0Sstevel@tonic-gate if (pai->ai_canonname) { 1012*0Sstevel@tonic-gate l = strlen(pai->ai_canonname) + 1; 1013*0Sstevel@tonic-gate if ((ai->ai_canonname = malloc(l)) == NULL) { 1014*0Sstevel@tonic-gate free(ai); 1015*0Sstevel@tonic-gate return NULL; 1016*0Sstevel@tonic-gate } 1017*0Sstevel@tonic-gate #ifdef HAVE_STRLCPY 1018*0Sstevel@tonic-gate strlcpy(ai->ai_canonname, pai->ai_canonname, l); 1019*0Sstevel@tonic-gate #else 1020*0Sstevel@tonic-gate strncpy(ai->ai_canonname, pai->ai_canonname, l); 1021*0Sstevel@tonic-gate #endif 1022*0Sstevel@tonic-gate } else { 1023*0Sstevel@tonic-gate /* just to make sure */ 1024*0Sstevel@tonic-gate ai->ai_canonname = NULL; 1025*0Sstevel@tonic-gate } 1026*0Sstevel@tonic-gate 1027*0Sstevel@tonic-gate ai->ai_next = NULL; 1028*0Sstevel@tonic-gate 1029*0Sstevel@tonic-gate return ai; 1030*0Sstevel@tonic-gate } 1031*0Sstevel@tonic-gate 1032*0Sstevel@tonic-gate static int 1033*0Sstevel@tonic-gate get_portmatch(const struct addrinfo *ai, const char *servname) { 1034*0Sstevel@tonic-gate 1035*0Sstevel@tonic-gate /* get_port does not touch first argument. when matchonly == 1. */ 1036*0Sstevel@tonic-gate /* LINTED const cast */ 1037*0Sstevel@tonic-gate return get_port((const struct addrinfo *)ai, servname, 1); 1038*0Sstevel@tonic-gate } 1039*0Sstevel@tonic-gate 1040*0Sstevel@tonic-gate static int 1041*0Sstevel@tonic-gate get_port(const struct addrinfo *ai, const char *servname, int matchonly) { 1042*0Sstevel@tonic-gate const char *proto; 1043*0Sstevel@tonic-gate struct servent *sp; 1044*0Sstevel@tonic-gate int port; 1045*0Sstevel@tonic-gate int allownumeric; 1046*0Sstevel@tonic-gate 1047*0Sstevel@tonic-gate if (servname == NULL) 1048*0Sstevel@tonic-gate return 0; 1049*0Sstevel@tonic-gate switch (ai->ai_family) { 1050*0Sstevel@tonic-gate case AF_INET: 1051*0Sstevel@tonic-gate #ifdef AF_INET6 1052*0Sstevel@tonic-gate case AF_INET6: 1053*0Sstevel@tonic-gate #endif 1054*0Sstevel@tonic-gate break; 1055*0Sstevel@tonic-gate default: 1056*0Sstevel@tonic-gate return 0; 1057*0Sstevel@tonic-gate } 1058*0Sstevel@tonic-gate 1059*0Sstevel@tonic-gate switch (ai->ai_socktype) { 1060*0Sstevel@tonic-gate case SOCK_RAW: 1061*0Sstevel@tonic-gate return EAI_SERVICE; 1062*0Sstevel@tonic-gate case SOCK_DGRAM: 1063*0Sstevel@tonic-gate case SOCK_STREAM: 1064*0Sstevel@tonic-gate allownumeric = 1; 1065*0Sstevel@tonic-gate break; 1066*0Sstevel@tonic-gate case ANY: 1067*0Sstevel@tonic-gate switch (ai->ai_family) { 1068*0Sstevel@tonic-gate case AF_INET: 1069*0Sstevel@tonic-gate #ifdef AF_INET6 1070*0Sstevel@tonic-gate case AF_INET6: 1071*0Sstevel@tonic-gate #endif 1072*0Sstevel@tonic-gate allownumeric = 1; 1073*0Sstevel@tonic-gate break; 1074*0Sstevel@tonic-gate default: 1075*0Sstevel@tonic-gate allownumeric = 0; 1076*0Sstevel@tonic-gate break; 1077*0Sstevel@tonic-gate } 1078*0Sstevel@tonic-gate break; 1079*0Sstevel@tonic-gate default: 1080*0Sstevel@tonic-gate return EAI_SOCKTYPE; 1081*0Sstevel@tonic-gate } 1082*0Sstevel@tonic-gate 1083*0Sstevel@tonic-gate if (str_isnumber(servname)) { 1084*0Sstevel@tonic-gate if (!allownumeric) 1085*0Sstevel@tonic-gate return EAI_SERVICE; 1086*0Sstevel@tonic-gate port = atoi(servname); 1087*0Sstevel@tonic-gate if (port < 0 || port > 65535) 1088*0Sstevel@tonic-gate return EAI_SERVICE; 1089*0Sstevel@tonic-gate port = htons(port); 1090*0Sstevel@tonic-gate } else { 1091*0Sstevel@tonic-gate switch (ai->ai_socktype) { 1092*0Sstevel@tonic-gate case SOCK_DGRAM: 1093*0Sstevel@tonic-gate proto = "udp"; 1094*0Sstevel@tonic-gate break; 1095*0Sstevel@tonic-gate case SOCK_STREAM: 1096*0Sstevel@tonic-gate proto = "tcp"; 1097*0Sstevel@tonic-gate break; 1098*0Sstevel@tonic-gate default: 1099*0Sstevel@tonic-gate proto = NULL; 1100*0Sstevel@tonic-gate break; 1101*0Sstevel@tonic-gate } 1102*0Sstevel@tonic-gate 1103*0Sstevel@tonic-gate if ((sp = getservbyname(servname, proto)) == NULL) 1104*0Sstevel@tonic-gate return EAI_SERVICE; 1105*0Sstevel@tonic-gate port = sp->s_port; 1106*0Sstevel@tonic-gate } 1107*0Sstevel@tonic-gate 1108*0Sstevel@tonic-gate if (!matchonly) { 1109*0Sstevel@tonic-gate switch (ai->ai_family) { 1110*0Sstevel@tonic-gate case AF_INET: 1111*0Sstevel@tonic-gate ((struct sockaddr_in *)(void *) 1112*0Sstevel@tonic-gate ai->ai_addr)->sin_port = port; 1113*0Sstevel@tonic-gate break; 1114*0Sstevel@tonic-gate case AF_INET6: 1115*0Sstevel@tonic-gate ((struct sockaddr_in6 *)(void *) 1116*0Sstevel@tonic-gate ai->ai_addr)->sin6_port = port; 1117*0Sstevel@tonic-gate break; 1118*0Sstevel@tonic-gate } 1119*0Sstevel@tonic-gate } 1120*0Sstevel@tonic-gate 1121*0Sstevel@tonic-gate return 0; 1122*0Sstevel@tonic-gate } 1123*0Sstevel@tonic-gate 1124*0Sstevel@tonic-gate static const struct afd * 1125*0Sstevel@tonic-gate find_afd(af) 1126*0Sstevel@tonic-gate int af; 1127*0Sstevel@tonic-gate { 1128*0Sstevel@tonic-gate const struct afd *afd; 1129*0Sstevel@tonic-gate 1130*0Sstevel@tonic-gate if (af == PF_UNSPEC) 1131*0Sstevel@tonic-gate return NULL; 1132*0Sstevel@tonic-gate for (afd = afdl; afd->a_af; afd++) { 1133*0Sstevel@tonic-gate if (afd->a_af == af) 1134*0Sstevel@tonic-gate return afd; 1135*0Sstevel@tonic-gate } 1136*0Sstevel@tonic-gate return NULL; 1137*0Sstevel@tonic-gate } 1138*0Sstevel@tonic-gate 1139*0Sstevel@tonic-gate /* 1140*0Sstevel@tonic-gate * post-2553: AI_ADDRCONFIG check. if we use getipnodeby* as backend, backend 1141*0Sstevel@tonic-gate * will take care of it. 1142*0Sstevel@tonic-gate * the semantics of AI_ADDRCONFIG is not defined well. we are not sure 1143*0Sstevel@tonic-gate * if the code is right or not. 1144*0Sstevel@tonic-gate */ 1145*0Sstevel@tonic-gate static int 1146*0Sstevel@tonic-gate addrconfig(af) 1147*0Sstevel@tonic-gate int af; 1148*0Sstevel@tonic-gate { 1149*0Sstevel@tonic-gate int s; 1150*0Sstevel@tonic-gate 1151*0Sstevel@tonic-gate /* XXX errno */ 1152*0Sstevel@tonic-gate s = socket(af, SOCK_DGRAM, 0); 1153*0Sstevel@tonic-gate if (s < 0) { 1154*0Sstevel@tonic-gate if (errno != EMFILE) 1155*0Sstevel@tonic-gate return 0; 1156*0Sstevel@tonic-gate } else 1157*0Sstevel@tonic-gate close(s); 1158*0Sstevel@tonic-gate return 1; 1159*0Sstevel@tonic-gate } 1160*0Sstevel@tonic-gate 1161*0Sstevel@tonic-gate /* convert a string to a scope identifier. XXX: IPv6 specific */ 1162*0Sstevel@tonic-gate static int 1163*0Sstevel@tonic-gate ip6_str2scopeid(char *scope, struct sockaddr_in6 *sin6, 1164*0Sstevel@tonic-gate u_int32_t *scopeidp) 1165*0Sstevel@tonic-gate { 1166*0Sstevel@tonic-gate u_int32_t scopeid; 1167*0Sstevel@tonic-gate u_long lscopeid; 1168*0Sstevel@tonic-gate struct in6_addr *a6 = &sin6->sin6_addr; 1169*0Sstevel@tonic-gate char *ep; 1170*0Sstevel@tonic-gate 1171*0Sstevel@tonic-gate /* empty scopeid portion is invalid */ 1172*0Sstevel@tonic-gate if (*scope == '\0') 1173*0Sstevel@tonic-gate return (0); 1174*0Sstevel@tonic-gate 1175*0Sstevel@tonic-gate #ifdef USE_IFNAMELINKID 1176*0Sstevel@tonic-gate if (IN6_IS_ADDR_LINKLOCAL(a6) || IN6_IS_ADDR_MC_LINKLOCAL(a6)) { 1177*0Sstevel@tonic-gate /* 1178*0Sstevel@tonic-gate * Using interface names as link indices can be allowed 1179*0Sstevel@tonic-gate * only when we can assume a one-to-one mappings between 1180*0Sstevel@tonic-gate * links and interfaces. See comments in getnameinfo.c. 1181*0Sstevel@tonic-gate */ 1182*0Sstevel@tonic-gate scopeid = if_nametoindex(scope); 1183*0Sstevel@tonic-gate if (scopeid == 0) 1184*0Sstevel@tonic-gate goto trynumeric; 1185*0Sstevel@tonic-gate *scopeidp = scopeid; 1186*0Sstevel@tonic-gate return (1); 1187*0Sstevel@tonic-gate } 1188*0Sstevel@tonic-gate #endif 1189*0Sstevel@tonic-gate 1190*0Sstevel@tonic-gate /* still unclear about literal, allow numeric only - placeholder */ 1191*0Sstevel@tonic-gate if (IN6_IS_ADDR_SITELOCAL(a6) || IN6_IS_ADDR_MC_SITELOCAL(a6)) 1192*0Sstevel@tonic-gate goto trynumeric; 1193*0Sstevel@tonic-gate if (IN6_IS_ADDR_MC_ORGLOCAL(a6)) 1194*0Sstevel@tonic-gate goto trynumeric; 1195*0Sstevel@tonic-gate else 1196*0Sstevel@tonic-gate goto trynumeric; /* global */ 1197*0Sstevel@tonic-gate 1198*0Sstevel@tonic-gate /* try to convert to a numeric id as a last resort */ 1199*0Sstevel@tonic-gate trynumeric: 1200*0Sstevel@tonic-gate errno = 0; 1201*0Sstevel@tonic-gate lscopeid = strtoul(scope, &ep, 10); 1202*0Sstevel@tonic-gate scopeid = lscopeid & 0xffffffff; 1203*0Sstevel@tonic-gate if (errno == 0 && ep && *ep == '\0' && scopeid == lscopeid) { 1204*0Sstevel@tonic-gate *scopeidp = scopeid; 1205*0Sstevel@tonic-gate return (1); 1206*0Sstevel@tonic-gate } else 1207*0Sstevel@tonic-gate return (0); 1208*0Sstevel@tonic-gate } 1209*0Sstevel@tonic-gate 1210*0Sstevel@tonic-gate struct addrinfo * 1211*0Sstevel@tonic-gate hostent2addrinfo(hp, pai) 1212*0Sstevel@tonic-gate struct hostent *hp; 1213*0Sstevel@tonic-gate const struct addrinfo *pai; 1214*0Sstevel@tonic-gate { 1215*0Sstevel@tonic-gate int i, af, error = 0; 1216*0Sstevel@tonic-gate char **aplist = NULL, *ap; 1217*0Sstevel@tonic-gate struct addrinfo sentinel, *cur; 1218*0Sstevel@tonic-gate const struct afd *afd; 1219*0Sstevel@tonic-gate 1220*0Sstevel@tonic-gate af = hp->h_addrtype; 1221*0Sstevel@tonic-gate if (pai->ai_family != AF_UNSPEC && af != pai->ai_family) 1222*0Sstevel@tonic-gate return(NULL); 1223*0Sstevel@tonic-gate 1224*0Sstevel@tonic-gate afd = find_afd(af); 1225*0Sstevel@tonic-gate if (afd == NULL) 1226*0Sstevel@tonic-gate return(NULL); 1227*0Sstevel@tonic-gate 1228*0Sstevel@tonic-gate aplist = hp->h_addr_list; 1229*0Sstevel@tonic-gate 1230*0Sstevel@tonic-gate memset(&sentinel, 0, sizeof(sentinel)); 1231*0Sstevel@tonic-gate cur = &sentinel; 1232*0Sstevel@tonic-gate 1233*0Sstevel@tonic-gate for (i = 0; (ap = aplist[i]) != NULL; i++) { 1234*0Sstevel@tonic-gate #if 0 /* the trick seems too much */ 1235*0Sstevel@tonic-gate af = hp->h_addr_list; 1236*0Sstevel@tonic-gate if (af == AF_INET6 && 1237*0Sstevel@tonic-gate IN6_IS_ADDR_V4MAPPED((struct in6_addr *)ap)) { 1238*0Sstevel@tonic-gate af = AF_INET; 1239*0Sstevel@tonic-gate ap = ap + sizeof(struct in6_addr) 1240*0Sstevel@tonic-gate - sizeof(struct in_addr); 1241*0Sstevel@tonic-gate } 1242*0Sstevel@tonic-gate afd = find_afd(af); 1243*0Sstevel@tonic-gate if (afd == NULL) 1244*0Sstevel@tonic-gate continue; 1245*0Sstevel@tonic-gate #endif /* 0 */ 1246*0Sstevel@tonic-gate 1247*0Sstevel@tonic-gate GET_AI(cur->ai_next, afd, ap); 1248*0Sstevel@tonic-gate 1249*0Sstevel@tonic-gate /* GET_PORT(cur->ai_next, servname); */ 1250*0Sstevel@tonic-gate if ((pai->ai_flags & AI_CANONNAME) != 0) { 1251*0Sstevel@tonic-gate /* 1252*0Sstevel@tonic-gate * RFC2553 says that ai_canonname will be set only for 1253*0Sstevel@tonic-gate * the first element. we do it for all the elements, 1254*0Sstevel@tonic-gate * just for convenience. 1255*0Sstevel@tonic-gate */ 1256*0Sstevel@tonic-gate GET_CANONNAME(cur->ai_next, hp->h_name); 1257*0Sstevel@tonic-gate } 1258*0Sstevel@tonic-gate while (cur && cur->ai_next) /* no need to loop, actually. */ 1259*0Sstevel@tonic-gate cur = cur->ai_next; 1260*0Sstevel@tonic-gate continue; 1261*0Sstevel@tonic-gate 1262*0Sstevel@tonic-gate free: 1263*0Sstevel@tonic-gate if (cur->ai_next) 1264*0Sstevel@tonic-gate freeaddrinfo(cur->ai_next); 1265*0Sstevel@tonic-gate cur->ai_next = NULL; 1266*0Sstevel@tonic-gate /* continue, without tht pointer CUR advanced. */ 1267*0Sstevel@tonic-gate } 1268*0Sstevel@tonic-gate 1269*0Sstevel@tonic-gate return(sentinel.ai_next); 1270*0Sstevel@tonic-gate } 1271*0Sstevel@tonic-gate 1272*0Sstevel@tonic-gate struct addrinfo * 1273*0Sstevel@tonic-gate addr2addrinfo(pai, cp) 1274*0Sstevel@tonic-gate const struct addrinfo *pai; 1275*0Sstevel@tonic-gate const char *cp; 1276*0Sstevel@tonic-gate { 1277*0Sstevel@tonic-gate const struct afd *afd; 1278*0Sstevel@tonic-gate 1279*0Sstevel@tonic-gate afd = find_afd(pai->ai_family); 1280*0Sstevel@tonic-gate if (afd == NULL) 1281*0Sstevel@tonic-gate return(NULL); 1282*0Sstevel@tonic-gate 1283*0Sstevel@tonic-gate return(get_ai(pai, afd, cp)); 1284*0Sstevel@tonic-gate } 1285*0Sstevel@tonic-gate 1286*0Sstevel@tonic-gate static struct net_data * 1287*0Sstevel@tonic-gate init() 1288*0Sstevel@tonic-gate { 1289*0Sstevel@tonic-gate struct net_data *net_data; 1290*0Sstevel@tonic-gate 1291*0Sstevel@tonic-gate if (!(net_data = net_data_init(NULL))) 1292*0Sstevel@tonic-gate goto error; 1293*0Sstevel@tonic-gate if (!net_data->ho) { 1294*0Sstevel@tonic-gate net_data->ho = (*net_data->irs->ho_map)(net_data->irs); 1295*0Sstevel@tonic-gate if (!net_data->ho || !net_data->res) { 1296*0Sstevel@tonic-gate error: 1297*0Sstevel@tonic-gate errno = EIO; 1298*0Sstevel@tonic-gate if (net_data && net_data->res) 1299*0Sstevel@tonic-gate RES_SET_H_ERRNO(net_data->res, NETDB_INTERNAL); 1300*0Sstevel@tonic-gate return (NULL); 1301*0Sstevel@tonic-gate } 1302*0Sstevel@tonic-gate 1303*0Sstevel@tonic-gate (*net_data->ho->res_set)(net_data->ho, net_data->res, NULL); 1304*0Sstevel@tonic-gate } 1305*0Sstevel@tonic-gate 1306*0Sstevel@tonic-gate return (net_data); 1307*0Sstevel@tonic-gate } 1308