10Sstevel@tonic-gate /* $KAME: getaddrinfo.c,v 1.14 2001/01/06 09:41:15 jinmei Exp $ */ 20Sstevel@tonic-gate 30Sstevel@tonic-gate /* 40Sstevel@tonic-gate * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 50Sstevel@tonic-gate * All rights reserved. 60Sstevel@tonic-gate * 70Sstevel@tonic-gate * Redistribution and use in source and binary forms, with or without 80Sstevel@tonic-gate * modification, are permitted provided that the following conditions 90Sstevel@tonic-gate * are met: 100Sstevel@tonic-gate * 1. Redistributions of source code must retain the above copyright 110Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer. 120Sstevel@tonic-gate * 2. Redistributions in binary form must reproduce the above copyright 130Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer in the 140Sstevel@tonic-gate * documentation and/or other materials provided with the distribution. 150Sstevel@tonic-gate * 3. Neither the name of the project nor the names of its contributors 160Sstevel@tonic-gate * may be used to endorse or promote products derived from this software 170Sstevel@tonic-gate * without specific prior written permission. 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 200Sstevel@tonic-gate * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 210Sstevel@tonic-gate * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 220Sstevel@tonic-gate * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 230Sstevel@tonic-gate * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 240Sstevel@tonic-gate * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 250Sstevel@tonic-gate * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 260Sstevel@tonic-gate * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 270Sstevel@tonic-gate * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 280Sstevel@tonic-gate * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 290Sstevel@tonic-gate * SUCH DAMAGE. 300Sstevel@tonic-gate */ 310Sstevel@tonic-gate 32*11038SRao.Shoaib@Sun.COM /*! \file 330Sstevel@tonic-gate * Issues to be discussed: 34*11038SRao.Shoaib@Sun.COM *\li Thread safe-ness must be checked. 35*11038SRao.Shoaib@Sun.COM *\li Return values. There are nonstandard return values defined and used 360Sstevel@tonic-gate * in the source code. This is because RFC2553 is silent about which error 370Sstevel@tonic-gate * code must be returned for which situation. 38*11038SRao.Shoaib@Sun.COM *\li IPv4 classful (shortened) form. RFC2553 is silent about it. XNET 5.2 390Sstevel@tonic-gate * says to use inet_aton() to convert IPv4 numeric to binary (allows 400Sstevel@tonic-gate * classful form as a result). 410Sstevel@tonic-gate * current code - disallow classful form for IPv4 (due to use of inet_pton). 42*11038SRao.Shoaib@Sun.COM *\li freeaddrinfo(NULL). RFC2553 is silent about it. XNET 5.2 says it is 430Sstevel@tonic-gate * invalid. 440Sstevel@tonic-gate * current code - SEGV on freeaddrinfo(NULL) 450Sstevel@tonic-gate * Note: 46*11038SRao.Shoaib@Sun.COM *\li We use getipnodebyname() just for thread-safeness. There's no intent 470Sstevel@tonic-gate * to let it do PF_UNSPEC (actually we never pass PF_UNSPEC to 480Sstevel@tonic-gate * getipnodebyname(). 49*11038SRao.Shoaib@Sun.COM *\li The code filters out AFs that are not supported by the kernel, 500Sstevel@tonic-gate * when globbing NULL hostname (to loopback, or wildcard). Is it the right 510Sstevel@tonic-gate * thing to do? What is the relationship with post-RFC2553 AI_ADDRCONFIG 520Sstevel@tonic-gate * in ai_flags? 53*11038SRao.Shoaib@Sun.COM *\li (post-2553) semantics of AI_ADDRCONFIG itself is too vague. 540Sstevel@tonic-gate * (1) what should we do against numeric hostname (2) what should we do 550Sstevel@tonic-gate * against NULL hostname (3) what is AI_ADDRCONFIG itself. AF not ready? 560Sstevel@tonic-gate * non-loopback address configured? global address configured? 57*11038SRao.Shoaib@Sun.COM * \par Additional Issue: 58*11038SRao.Shoaib@Sun.COM * To avoid search order issue, we have a big amount of code duplicate 590Sstevel@tonic-gate * from gethnamaddr.c and some other places. The issues that there's no 600Sstevel@tonic-gate * lower layer function to lookup "IPv4 or IPv6" record. Calling 610Sstevel@tonic-gate * gethostbyname2 from getaddrinfo will end up in wrong search order, as 620Sstevel@tonic-gate * follows: 63*11038SRao.Shoaib@Sun.COM * \li The code makes use of following calls when asked to resolver with 640Sstevel@tonic-gate * ai_family = PF_UNSPEC: 65*11038SRao.Shoaib@Sun.COM *\code getipnodebyname(host, AF_INET6); 660Sstevel@tonic-gate * getipnodebyname(host, AF_INET); 67*11038SRao.Shoaib@Sun.COM *\endcode 68*11038SRao.Shoaib@Sun.COM * \li This will result in the following queries if the node is configure to 690Sstevel@tonic-gate * prefer /etc/hosts than DNS: 70*11038SRao.Shoaib@Sun.COM *\code 710Sstevel@tonic-gate * lookup /etc/hosts for IPv6 address 720Sstevel@tonic-gate * lookup DNS for IPv6 address 730Sstevel@tonic-gate * lookup /etc/hosts for IPv4 address 740Sstevel@tonic-gate * lookup DNS for IPv4 address 75*11038SRao.Shoaib@Sun.COM *\endcode 760Sstevel@tonic-gate * which may not meet people's requirement. 77*11038SRao.Shoaib@Sun.COM * \li The right thing to happen is to have underlying layer which does 780Sstevel@tonic-gate * PF_UNSPEC lookup (lookup both) and return chain of addrinfos. 790Sstevel@tonic-gate * This would result in a bit of code duplicate with _dns_ghbyname() and 800Sstevel@tonic-gate * friends. 810Sstevel@tonic-gate */ 820Sstevel@tonic-gate 830Sstevel@tonic-gate #include "port_before.h" 840Sstevel@tonic-gate 850Sstevel@tonic-gate #include <sys/types.h> 860Sstevel@tonic-gate #include <sys/param.h> 870Sstevel@tonic-gate #include <sys/socket.h> 880Sstevel@tonic-gate 890Sstevel@tonic-gate #include <net/if.h> 900Sstevel@tonic-gate #include <netinet/in.h> 910Sstevel@tonic-gate 920Sstevel@tonic-gate #include <arpa/inet.h> 930Sstevel@tonic-gate #include <arpa/nameser.h> 940Sstevel@tonic-gate 950Sstevel@tonic-gate #include <netdb.h> 960Sstevel@tonic-gate #include <resolv.h> 970Sstevel@tonic-gate #include <string.h> 980Sstevel@tonic-gate #include <stdlib.h> 990Sstevel@tonic-gate #include <stddef.h> 1000Sstevel@tonic-gate #include <ctype.h> 1010Sstevel@tonic-gate #include <unistd.h> 1020Sstevel@tonic-gate #include <stdio.h> 1030Sstevel@tonic-gate #include <errno.h> 1040Sstevel@tonic-gate 1050Sstevel@tonic-gate #include <stdarg.h> 1060Sstevel@tonic-gate 1070Sstevel@tonic-gate #include <irs.h> 1080Sstevel@tonic-gate #include <isc/assertions.h> 1090Sstevel@tonic-gate 1100Sstevel@tonic-gate #include "port_after.h" 1110Sstevel@tonic-gate 1120Sstevel@tonic-gate #include "irs_data.h" 1130Sstevel@tonic-gate 1140Sstevel@tonic-gate #define SUCCESS 0 1150Sstevel@tonic-gate #define ANY 0 1160Sstevel@tonic-gate #define YES 1 1170Sstevel@tonic-gate #define NO 0 1180Sstevel@tonic-gate 1190Sstevel@tonic-gate static const char in_addrany[] = { 0, 0, 0, 0 }; 1200Sstevel@tonic-gate static const char in6_addrany[] = { 1210Sstevel@tonic-gate 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 1220Sstevel@tonic-gate }; 1230Sstevel@tonic-gate static const char in_loopback[] = { 127, 0, 0, 1 }; 1240Sstevel@tonic-gate static const char in6_loopback[] = { 1250Sstevel@tonic-gate 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 1260Sstevel@tonic-gate }; 1270Sstevel@tonic-gate 1280Sstevel@tonic-gate static const struct afd { 1290Sstevel@tonic-gate int a_af; 1300Sstevel@tonic-gate int a_addrlen; 1310Sstevel@tonic-gate int a_socklen; 1320Sstevel@tonic-gate int a_off; 1330Sstevel@tonic-gate const char *a_addrany; 1340Sstevel@tonic-gate const char *a_loopback; 1350Sstevel@tonic-gate int a_scoped; 1360Sstevel@tonic-gate } afdl [] = { 1370Sstevel@tonic-gate {PF_INET6, sizeof(struct in6_addr), 1380Sstevel@tonic-gate sizeof(struct sockaddr_in6), 1390Sstevel@tonic-gate offsetof(struct sockaddr_in6, sin6_addr), 1400Sstevel@tonic-gate in6_addrany, in6_loopback, 1}, 1410Sstevel@tonic-gate {PF_INET, sizeof(struct in_addr), 1420Sstevel@tonic-gate sizeof(struct sockaddr_in), 1430Sstevel@tonic-gate offsetof(struct sockaddr_in, sin_addr), 1440Sstevel@tonic-gate in_addrany, in_loopback, 0}, 1450Sstevel@tonic-gate {0, 0, 0, 0, NULL, NULL, 0}, 1460Sstevel@tonic-gate }; 1470Sstevel@tonic-gate 1480Sstevel@tonic-gate struct explore { 1490Sstevel@tonic-gate int e_af; 1500Sstevel@tonic-gate int e_socktype; 1510Sstevel@tonic-gate int e_protocol; 1520Sstevel@tonic-gate const char *e_protostr; 1530Sstevel@tonic-gate int e_wild; 1540Sstevel@tonic-gate #define WILD_AF(ex) ((ex)->e_wild & 0x01) 1550Sstevel@tonic-gate #define WILD_SOCKTYPE(ex) ((ex)->e_wild & 0x02) 1560Sstevel@tonic-gate #define WILD_PROTOCOL(ex) ((ex)->e_wild & 0x04) 1570Sstevel@tonic-gate }; 1580Sstevel@tonic-gate 1590Sstevel@tonic-gate static const struct explore explore[] = { 1600Sstevel@tonic-gate #if 0 1610Sstevel@tonic-gate { PF_LOCAL, 0, ANY, ANY, NULL, 0x01 }, 1620Sstevel@tonic-gate #endif 1630Sstevel@tonic-gate { PF_INET6, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 }, 1640Sstevel@tonic-gate { PF_INET6, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 }, 1650Sstevel@tonic-gate { PF_INET6, SOCK_RAW, ANY, NULL, 0x05 }, 1660Sstevel@tonic-gate { PF_INET, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 }, 1670Sstevel@tonic-gate { PF_INET, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 }, 1680Sstevel@tonic-gate { PF_INET, SOCK_RAW, ANY, NULL, 0x05 }, 1690Sstevel@tonic-gate { -1, 0, 0, NULL, 0 }, 1700Sstevel@tonic-gate }; 1710Sstevel@tonic-gate 1720Sstevel@tonic-gate #define PTON_MAX 16 1730Sstevel@tonic-gate 1740Sstevel@tonic-gate static int str_isnumber __P((const char *)); 1750Sstevel@tonic-gate static int explore_fqdn __P((const struct addrinfo *, const char *, 1760Sstevel@tonic-gate const char *, struct addrinfo **)); 1770Sstevel@tonic-gate static int explore_copy __P((const struct addrinfo *, const struct addrinfo *, 1780Sstevel@tonic-gate struct addrinfo **)); 1790Sstevel@tonic-gate static int explore_null __P((const struct addrinfo *, 1800Sstevel@tonic-gate const char *, struct addrinfo **)); 1810Sstevel@tonic-gate static int explore_numeric __P((const struct addrinfo *, const char *, 1820Sstevel@tonic-gate const char *, struct addrinfo **)); 1830Sstevel@tonic-gate static int explore_numeric_scope __P((const struct addrinfo *, const char *, 1840Sstevel@tonic-gate const char *, struct addrinfo **)); 1850Sstevel@tonic-gate static int get_canonname __P((const struct addrinfo *, 1860Sstevel@tonic-gate struct addrinfo *, const char *)); 1870Sstevel@tonic-gate static struct addrinfo *get_ai __P((const struct addrinfo *, 1880Sstevel@tonic-gate const struct afd *, const char *)); 1890Sstevel@tonic-gate static struct addrinfo *copy_ai __P((const struct addrinfo *)); 1900Sstevel@tonic-gate static int get_portmatch __P((const struct addrinfo *, const char *)); 1910Sstevel@tonic-gate static int get_port __P((const struct addrinfo *, const char *, int)); 1920Sstevel@tonic-gate static const struct afd *find_afd __P((int)); 1930Sstevel@tonic-gate static int addrconfig __P((int)); 1940Sstevel@tonic-gate static int ip6_str2scopeid __P((char *, struct sockaddr_in6 *, 1950Sstevel@tonic-gate u_int32_t *scopeidp)); 1960Sstevel@tonic-gate static struct net_data *init __P((void)); 1970Sstevel@tonic-gate 1980Sstevel@tonic-gate struct addrinfo *hostent2addrinfo __P((struct hostent *, 1990Sstevel@tonic-gate const struct addrinfo *)); 2000Sstevel@tonic-gate struct addrinfo *addr2addrinfo __P((const struct addrinfo *, 2010Sstevel@tonic-gate const char *)); 2020Sstevel@tonic-gate 2030Sstevel@tonic-gate #if 0 2040Sstevel@tonic-gate static const char *ai_errlist[] = { 2050Sstevel@tonic-gate "Success", 206*11038SRao.Shoaib@Sun.COM "Address family for hostname not supported", /*%< EAI_ADDRFAMILY */ 207*11038SRao.Shoaib@Sun.COM "Temporary failure in name resolution", /*%< EAI_AGAIN */ 208*11038SRao.Shoaib@Sun.COM "Invalid value for ai_flags", /*%< EAI_BADFLAGS */ 209*11038SRao.Shoaib@Sun.COM "Non-recoverable failure in name resolution", /*%< EAI_FAIL */ 210*11038SRao.Shoaib@Sun.COM "ai_family not supported", /*%< EAI_FAMILY */ 211*11038SRao.Shoaib@Sun.COM "Memory allocation failure", /*%< EAI_MEMORY */ 212*11038SRao.Shoaib@Sun.COM "No address associated with hostname", /*%< EAI_NODATA */ 213*11038SRao.Shoaib@Sun.COM "hostname nor servname provided, or not known", /*%< EAI_NONAME */ 214*11038SRao.Shoaib@Sun.COM "servname not supported for ai_socktype", /*%< EAI_SERVICE */ 215*11038SRao.Shoaib@Sun.COM "ai_socktype not supported", /*%< EAI_SOCKTYPE */ 216*11038SRao.Shoaib@Sun.COM "System error returned in errno", /*%< EAI_SYSTEM */ 217*11038SRao.Shoaib@Sun.COM "Invalid value for hints", /*%< EAI_BADHINTS */ 218*11038SRao.Shoaib@Sun.COM "Resolved protocol is unknown", /*%< EAI_PROTOCOL */ 219*11038SRao.Shoaib@Sun.COM "Unknown error", /*%< EAI_MAX */ 2200Sstevel@tonic-gate }; 2210Sstevel@tonic-gate #endif 2220Sstevel@tonic-gate 2230Sstevel@tonic-gate /* XXX macros that make external reference is BAD. */ 2240Sstevel@tonic-gate 2250Sstevel@tonic-gate #define GET_AI(ai, afd, addr) \ 2260Sstevel@tonic-gate do { \ 2270Sstevel@tonic-gate /* external reference: pai, error, and label free */ \ 2280Sstevel@tonic-gate (ai) = get_ai(pai, (afd), (addr)); \ 2290Sstevel@tonic-gate if ((ai) == NULL) { \ 2300Sstevel@tonic-gate error = EAI_MEMORY; \ 2310Sstevel@tonic-gate goto free; \ 2320Sstevel@tonic-gate } \ 2330Sstevel@tonic-gate } while (/*CONSTCOND*/0) 2340Sstevel@tonic-gate 2350Sstevel@tonic-gate #define GET_PORT(ai, serv) \ 2360Sstevel@tonic-gate do { \ 2370Sstevel@tonic-gate /* external reference: error and label free */ \ 2380Sstevel@tonic-gate error = get_port((ai), (serv), 0); \ 2390Sstevel@tonic-gate if (error != 0) \ 2400Sstevel@tonic-gate goto free; \ 2410Sstevel@tonic-gate } while (/*CONSTCOND*/0) 2420Sstevel@tonic-gate 2430Sstevel@tonic-gate #define GET_CANONNAME(ai, str) \ 2440Sstevel@tonic-gate do { \ 2450Sstevel@tonic-gate /* external reference: pai, error and label free */ \ 2460Sstevel@tonic-gate error = get_canonname(pai, (ai), (str)); \ 2470Sstevel@tonic-gate if (error != 0) \ 2480Sstevel@tonic-gate goto free; \ 2490Sstevel@tonic-gate } while (/*CONSTCOND*/0) 2500Sstevel@tonic-gate 251*11038SRao.Shoaib@Sun.COM #ifndef SOLARIS2 252*11038SRao.Shoaib@Sun.COM #define SETERROR(err) \ 2530Sstevel@tonic-gate do { \ 2540Sstevel@tonic-gate /* external reference: error, and label bad */ \ 2550Sstevel@tonic-gate error = (err); \ 2560Sstevel@tonic-gate goto bad; \ 2570Sstevel@tonic-gate /*NOTREACHED*/ \ 2580Sstevel@tonic-gate } while (/*CONSTCOND*/0) 2590Sstevel@tonic-gate #else 260*11038SRao.Shoaib@Sun.COM #define SETERROR(err) \ 2610Sstevel@tonic-gate do { \ 262*11038SRao.Shoaib@Sun.COM /* external reference: error, and label bad */ \ 2630Sstevel@tonic-gate error = (err); \ 264*11038SRao.Shoaib@Sun.COM if (error == error) \ 265*11038SRao.Shoaib@Sun.COM goto bad; \ 2660Sstevel@tonic-gate } while (/*CONSTCOND*/0) 2670Sstevel@tonic-gate #endif 2680Sstevel@tonic-gate 269*11038SRao.Shoaib@Sun.COM 2700Sstevel@tonic-gate #define MATCH_FAMILY(x, y, w) \ 2710Sstevel@tonic-gate ((x) == (y) || (/*CONSTCOND*/(w) && ((x) == PF_UNSPEC || (y) == PF_UNSPEC))) 2720Sstevel@tonic-gate #define MATCH(x, y, w) \ 2730Sstevel@tonic-gate ((x) == (y) || (/*CONSTCOND*/(w) && ((x) == ANY || (y) == ANY))) 2740Sstevel@tonic-gate 275*11038SRao.Shoaib@Sun.COM #if 0 /*%< bind8 has its own version */ 2760Sstevel@tonic-gate char * 2770Sstevel@tonic-gate gai_strerror(ecode) 2780Sstevel@tonic-gate int ecode; 2790Sstevel@tonic-gate { 2800Sstevel@tonic-gate if (ecode < 0 || ecode > EAI_MAX) 2810Sstevel@tonic-gate ecode = EAI_MAX; 2820Sstevel@tonic-gate return ai_errlist[ecode]; 2830Sstevel@tonic-gate } 2840Sstevel@tonic-gate #endif 2850Sstevel@tonic-gate 2860Sstevel@tonic-gate void 2870Sstevel@tonic-gate freeaddrinfo(ai) 2880Sstevel@tonic-gate struct addrinfo *ai; 2890Sstevel@tonic-gate { 2900Sstevel@tonic-gate struct addrinfo *next; 2910Sstevel@tonic-gate 2920Sstevel@tonic-gate do { 2930Sstevel@tonic-gate next = ai->ai_next; 2940Sstevel@tonic-gate if (ai->ai_canonname) 2950Sstevel@tonic-gate free(ai->ai_canonname); 2960Sstevel@tonic-gate /* no need to free(ai->ai_addr) */ 2970Sstevel@tonic-gate free(ai); 2980Sstevel@tonic-gate ai = next; 2990Sstevel@tonic-gate } while (ai); 3000Sstevel@tonic-gate } 3010Sstevel@tonic-gate 3020Sstevel@tonic-gate static int 3030Sstevel@tonic-gate str_isnumber(p) 3040Sstevel@tonic-gate const char *p; 3050Sstevel@tonic-gate { 3060Sstevel@tonic-gate char *ep; 3070Sstevel@tonic-gate 3080Sstevel@tonic-gate if (*p == '\0') 3090Sstevel@tonic-gate return NO; 3100Sstevel@tonic-gate ep = NULL; 3110Sstevel@tonic-gate errno = 0; 3120Sstevel@tonic-gate (void)strtoul(p, &ep, 10); 3130Sstevel@tonic-gate if (errno == 0 && ep && *ep == '\0') 3140Sstevel@tonic-gate return YES; 3150Sstevel@tonic-gate else 3160Sstevel@tonic-gate return NO; 3170Sstevel@tonic-gate } 3180Sstevel@tonic-gate 3190Sstevel@tonic-gate int 3200Sstevel@tonic-gate getaddrinfo(hostname, servname, hints, res) 3210Sstevel@tonic-gate const char *hostname, *servname; 3220Sstevel@tonic-gate const struct addrinfo *hints; 3230Sstevel@tonic-gate struct addrinfo **res; 3240Sstevel@tonic-gate { 3250Sstevel@tonic-gate struct addrinfo sentinel; 3260Sstevel@tonic-gate struct addrinfo *cur; 3270Sstevel@tonic-gate int error = 0; 3280Sstevel@tonic-gate struct addrinfo ai, ai0, *afai = NULL; 3290Sstevel@tonic-gate struct addrinfo *pai; 3300Sstevel@tonic-gate const struct explore *ex; 3310Sstevel@tonic-gate 3320Sstevel@tonic-gate memset(&sentinel, 0, sizeof(sentinel)); 3330Sstevel@tonic-gate cur = &sentinel; 3340Sstevel@tonic-gate pai = &ai; 3350Sstevel@tonic-gate pai->ai_flags = 0; 3360Sstevel@tonic-gate pai->ai_family = PF_UNSPEC; 3370Sstevel@tonic-gate pai->ai_socktype = ANY; 3380Sstevel@tonic-gate pai->ai_protocol = ANY; 339*11038SRao.Shoaib@Sun.COM #if defined(sun) && defined(_SOCKLEN_T) && defined(__sparcv9) 3400Sstevel@tonic-gate /* 341*11038SRao.Shoaib@Sun.COM * clear _ai_pad to preserve binary 3420Sstevel@tonic-gate * compatibility with previously compiled 64-bit 3430Sstevel@tonic-gate * applications in a pre-SUSv3 environment by 3440Sstevel@tonic-gate * guaranteeing the upper 32-bits are empty. 3450Sstevel@tonic-gate */ 3460Sstevel@tonic-gate pai->_ai_pad = 0; 347*11038SRao.Shoaib@Sun.COM #endif 3480Sstevel@tonic-gate pai->ai_addrlen = 0; 3490Sstevel@tonic-gate pai->ai_canonname = NULL; 3500Sstevel@tonic-gate pai->ai_addr = NULL; 3510Sstevel@tonic-gate pai->ai_next = NULL; 3520Sstevel@tonic-gate 3530Sstevel@tonic-gate if (hostname == NULL && servname == NULL) 3540Sstevel@tonic-gate return EAI_NONAME; 3550Sstevel@tonic-gate if (hints) { 3560Sstevel@tonic-gate /* error check for hints */ 3570Sstevel@tonic-gate if (hints->ai_addrlen || hints->ai_canonname || 358*11038SRao.Shoaib@Sun.COM hints->ai_addr || hints->ai_next) 359*11038SRao.Shoaib@Sun.COM SETERROR(EAI_BADHINTS); /*%< xxx */ 360*11038SRao.Shoaib@Sun.COM if (hints->ai_flags & ~AI_MASK) 361*11038SRao.Shoaib@Sun.COM SETERROR(EAI_BADFLAGS); 3620Sstevel@tonic-gate switch (hints->ai_family) { 3630Sstevel@tonic-gate case PF_UNSPEC: 3640Sstevel@tonic-gate case PF_INET: 3650Sstevel@tonic-gate case PF_INET6: 3660Sstevel@tonic-gate break; 3670Sstevel@tonic-gate default: 368*11038SRao.Shoaib@Sun.COM SETERROR(EAI_FAMILY); 3690Sstevel@tonic-gate } 3700Sstevel@tonic-gate memcpy(pai, hints, sizeof(*pai)); 3710Sstevel@tonic-gate 372*11038SRao.Shoaib@Sun.COM #if defined(sun) && defined(_SOCKLEN_T) && defined(__sparcv9) 3730Sstevel@tonic-gate /* 3740Sstevel@tonic-gate * We need to clear _ai_pad to preserve binary 3750Sstevel@tonic-gate * compatibility. See prior comment. 3760Sstevel@tonic-gate */ 3770Sstevel@tonic-gate pai->_ai_pad = 0; 378*11038SRao.Shoaib@Sun.COM #endif 3790Sstevel@tonic-gate /* 3800Sstevel@tonic-gate * if both socktype/protocol are specified, check if they 3810Sstevel@tonic-gate * are meaningful combination. 3820Sstevel@tonic-gate */ 3830Sstevel@tonic-gate if (pai->ai_socktype != ANY && pai->ai_protocol != ANY) { 3840Sstevel@tonic-gate for (ex = explore; ex->e_af >= 0; ex++) { 3850Sstevel@tonic-gate if (pai->ai_family != ex->e_af) 3860Sstevel@tonic-gate continue; 3870Sstevel@tonic-gate if (ex->e_socktype == ANY) 3880Sstevel@tonic-gate continue; 3890Sstevel@tonic-gate if (ex->e_protocol == ANY) 3900Sstevel@tonic-gate continue; 3910Sstevel@tonic-gate if (pai->ai_socktype == ex->e_socktype && 3920Sstevel@tonic-gate pai->ai_protocol != ex->e_protocol) { 393*11038SRao.Shoaib@Sun.COM SETERROR(EAI_BADHINTS); 3940Sstevel@tonic-gate } 3950Sstevel@tonic-gate } 3960Sstevel@tonic-gate } 3970Sstevel@tonic-gate } 3980Sstevel@tonic-gate 3990Sstevel@tonic-gate /* 4000Sstevel@tonic-gate * post-2553: AI_ALL and AI_V4MAPPED are effective only against 4010Sstevel@tonic-gate * AF_INET6 query. They needs to be ignored if specified in other 4020Sstevel@tonic-gate * occassions. 4030Sstevel@tonic-gate */ 4040Sstevel@tonic-gate switch (pai->ai_flags & (AI_ALL | AI_V4MAPPED)) { 4050Sstevel@tonic-gate case AI_V4MAPPED: 4060Sstevel@tonic-gate case AI_ALL | AI_V4MAPPED: 4070Sstevel@tonic-gate if (pai->ai_family != AF_INET6) 4080Sstevel@tonic-gate pai->ai_flags &= ~(AI_ALL | AI_V4MAPPED); 4090Sstevel@tonic-gate break; 4100Sstevel@tonic-gate case AI_ALL: 4110Sstevel@tonic-gate #if 1 4120Sstevel@tonic-gate /* illegal */ 413*11038SRao.Shoaib@Sun.COM SETERROR(EAI_BADFLAGS); 4140Sstevel@tonic-gate #else 4150Sstevel@tonic-gate pai->ai_flags &= ~(AI_ALL | AI_V4MAPPED); 4160Sstevel@tonic-gate break; 4170Sstevel@tonic-gate #endif 4180Sstevel@tonic-gate } 4190Sstevel@tonic-gate 4200Sstevel@tonic-gate /* 4210Sstevel@tonic-gate * check for special cases. (1) numeric servname is disallowed if 4220Sstevel@tonic-gate * socktype/protocol are left unspecified. (2) servname is disallowed 4230Sstevel@tonic-gate * for raw and other inet{,6} sockets. 4240Sstevel@tonic-gate */ 4250Sstevel@tonic-gate if (MATCH_FAMILY(pai->ai_family, PF_INET, 1) 4260Sstevel@tonic-gate #ifdef PF_INET6 4270Sstevel@tonic-gate || MATCH_FAMILY(pai->ai_family, PF_INET6, 1) 4280Sstevel@tonic-gate #endif 4290Sstevel@tonic-gate ) { 4300Sstevel@tonic-gate ai0 = *pai; /* backup *pai */ 4310Sstevel@tonic-gate 4320Sstevel@tonic-gate if (pai->ai_family == PF_UNSPEC) { 4330Sstevel@tonic-gate #ifdef PF_INET6 4340Sstevel@tonic-gate pai->ai_family = PF_INET6; 4350Sstevel@tonic-gate #else 4360Sstevel@tonic-gate pai->ai_family = PF_INET; 4370Sstevel@tonic-gate #endif 4380Sstevel@tonic-gate } 4390Sstevel@tonic-gate error = get_portmatch(pai, servname); 440*11038SRao.Shoaib@Sun.COM if (error) 441*11038SRao.Shoaib@Sun.COM SETERROR(error); 4420Sstevel@tonic-gate 4430Sstevel@tonic-gate *pai = ai0; 4440Sstevel@tonic-gate } 4450Sstevel@tonic-gate 4460Sstevel@tonic-gate ai0 = *pai; 4470Sstevel@tonic-gate 4480Sstevel@tonic-gate /* NULL hostname, or numeric hostname */ 4490Sstevel@tonic-gate for (ex = explore; ex->e_af >= 0; ex++) { 4500Sstevel@tonic-gate *pai = ai0; 4510Sstevel@tonic-gate 4520Sstevel@tonic-gate if (!MATCH_FAMILY(pai->ai_family, ex->e_af, WILD_AF(ex))) 4530Sstevel@tonic-gate continue; 4540Sstevel@tonic-gate if (!MATCH(pai->ai_socktype, ex->e_socktype, WILD_SOCKTYPE(ex))) 4550Sstevel@tonic-gate continue; 4560Sstevel@tonic-gate if (!MATCH(pai->ai_protocol, ex->e_protocol, WILD_PROTOCOL(ex))) 4570Sstevel@tonic-gate continue; 4580Sstevel@tonic-gate 4590Sstevel@tonic-gate if (pai->ai_family == PF_UNSPEC) 4600Sstevel@tonic-gate pai->ai_family = ex->e_af; 4610Sstevel@tonic-gate if (pai->ai_socktype == ANY && ex->e_socktype != ANY) 4620Sstevel@tonic-gate pai->ai_socktype = ex->e_socktype; 4630Sstevel@tonic-gate if (pai->ai_protocol == ANY && ex->e_protocol != ANY) 4640Sstevel@tonic-gate pai->ai_protocol = ex->e_protocol; 4650Sstevel@tonic-gate 4660Sstevel@tonic-gate /* 4670Sstevel@tonic-gate * if the servname does not match socktype/protocol, ignore it. 4680Sstevel@tonic-gate */ 4690Sstevel@tonic-gate if (get_portmatch(pai, servname) != 0) 4700Sstevel@tonic-gate continue; 4710Sstevel@tonic-gate 4720Sstevel@tonic-gate if (hostname == NULL) { 4730Sstevel@tonic-gate /* 4740Sstevel@tonic-gate * filter out AFs that are not supported by the kernel 4750Sstevel@tonic-gate * XXX errno? 4760Sstevel@tonic-gate */ 4770Sstevel@tonic-gate if (!addrconfig(pai->ai_family)) 4780Sstevel@tonic-gate continue; 4790Sstevel@tonic-gate error = explore_null(pai, servname, &cur->ai_next); 4800Sstevel@tonic-gate } else 4810Sstevel@tonic-gate error = explore_numeric_scope(pai, hostname, servname, 4820Sstevel@tonic-gate &cur->ai_next); 4830Sstevel@tonic-gate 4840Sstevel@tonic-gate if (error) 4850Sstevel@tonic-gate goto free; 4860Sstevel@tonic-gate 4870Sstevel@tonic-gate while (cur && cur->ai_next) 4880Sstevel@tonic-gate cur = cur->ai_next; 4890Sstevel@tonic-gate } 4900Sstevel@tonic-gate 4910Sstevel@tonic-gate /* 4920Sstevel@tonic-gate * XXX 4930Sstevel@tonic-gate * If numreic representation of AF1 can be interpreted as FQDN 4940Sstevel@tonic-gate * representation of AF2, we need to think again about the code below. 4950Sstevel@tonic-gate */ 4960Sstevel@tonic-gate if (sentinel.ai_next) 4970Sstevel@tonic-gate goto good; 4980Sstevel@tonic-gate 499*11038SRao.Shoaib@Sun.COM if (pai->ai_flags & AI_NUMERICHOST) 500*11038SRao.Shoaib@Sun.COM SETERROR(EAI_NONAME); 501*11038SRao.Shoaib@Sun.COM if (hostname == NULL) 502*11038SRao.Shoaib@Sun.COM SETERROR(EAI_NONAME); 5030Sstevel@tonic-gate 5040Sstevel@tonic-gate /* 5050Sstevel@tonic-gate * hostname as alphabetical name. 5060Sstevel@tonic-gate * We'll make sure that 5070Sstevel@tonic-gate * - if returning addrinfo list is empty, return non-zero error 5080Sstevel@tonic-gate * value (already known one or EAI_NONAME). 5090Sstevel@tonic-gate * - otherwise, 5100Sstevel@tonic-gate * + if we haven't had any errors, return 0 (i.e. success). 5110Sstevel@tonic-gate * + if we've had an error, free the list and return the error. 5120Sstevel@tonic-gate * without any assumption on the behavior of explore_fqdn(). 5130Sstevel@tonic-gate */ 5140Sstevel@tonic-gate 5150Sstevel@tonic-gate /* first, try to query DNS for all possible address families. */ 5160Sstevel@tonic-gate *pai = ai0; 5170Sstevel@tonic-gate error = explore_fqdn(pai, hostname, servname, &afai); 5180Sstevel@tonic-gate if (error) { 5190Sstevel@tonic-gate if (afai != NULL) 5200Sstevel@tonic-gate freeaddrinfo(afai); 5210Sstevel@tonic-gate goto free; 5220Sstevel@tonic-gate } 5230Sstevel@tonic-gate if (afai == NULL) { 524*11038SRao.Shoaib@Sun.COM error = EAI_NONAME; /*%< we've had no errors. */ 5250Sstevel@tonic-gate goto free; 5260Sstevel@tonic-gate } 5270Sstevel@tonic-gate 5280Sstevel@tonic-gate /* 5290Sstevel@tonic-gate * we would like to prefer AF_INET6 than AF_INET, so we'll make an 5300Sstevel@tonic-gate * outer loop by AFs. 5310Sstevel@tonic-gate */ 5320Sstevel@tonic-gate for (ex = explore; ex->e_af >= 0; ex++) { 5330Sstevel@tonic-gate *pai = ai0; 5340Sstevel@tonic-gate 5350Sstevel@tonic-gate if (pai->ai_family == PF_UNSPEC) 5360Sstevel@tonic-gate pai->ai_family = ex->e_af; 5370Sstevel@tonic-gate 5380Sstevel@tonic-gate if (!MATCH_FAMILY(pai->ai_family, ex->e_af, WILD_AF(ex))) 5390Sstevel@tonic-gate continue; 5400Sstevel@tonic-gate if (!MATCH(pai->ai_socktype, ex->e_socktype, 5410Sstevel@tonic-gate WILD_SOCKTYPE(ex))) { 5420Sstevel@tonic-gate continue; 5430Sstevel@tonic-gate } 5440Sstevel@tonic-gate if (!MATCH(pai->ai_protocol, ex->e_protocol, 5450Sstevel@tonic-gate WILD_PROTOCOL(ex))) { 5460Sstevel@tonic-gate continue; 5470Sstevel@tonic-gate } 5480Sstevel@tonic-gate 5490Sstevel@tonic-gate #ifdef AI_ADDRCONFIG 5500Sstevel@tonic-gate /* 5510Sstevel@tonic-gate * If AI_ADDRCONFIG is specified, check if we are 5520Sstevel@tonic-gate * expected to return the address family or not. 5530Sstevel@tonic-gate */ 5540Sstevel@tonic-gate if ((pai->ai_flags & AI_ADDRCONFIG) != 0 && 5550Sstevel@tonic-gate !addrconfig(pai->ai_family)) 5560Sstevel@tonic-gate continue; 5570Sstevel@tonic-gate #endif 5580Sstevel@tonic-gate 5590Sstevel@tonic-gate if (pai->ai_family == PF_UNSPEC) 5600Sstevel@tonic-gate pai->ai_family = ex->e_af; 5610Sstevel@tonic-gate if (pai->ai_socktype == ANY && ex->e_socktype != ANY) 5620Sstevel@tonic-gate pai->ai_socktype = ex->e_socktype; 5630Sstevel@tonic-gate if (pai->ai_protocol == ANY && ex->e_protocol != ANY) 5640Sstevel@tonic-gate pai->ai_protocol = ex->e_protocol; 5650Sstevel@tonic-gate 5660Sstevel@tonic-gate /* 5670Sstevel@tonic-gate * if the servname does not match socktype/protocol, ignore it. 5680Sstevel@tonic-gate */ 5690Sstevel@tonic-gate if (get_portmatch(pai, servname) != 0) 5700Sstevel@tonic-gate continue; 5710Sstevel@tonic-gate 5720Sstevel@tonic-gate if ((error = explore_copy(pai, afai, &cur->ai_next)) != 0) { 5730Sstevel@tonic-gate freeaddrinfo(afai); 5740Sstevel@tonic-gate goto free; 5750Sstevel@tonic-gate } 5760Sstevel@tonic-gate 5770Sstevel@tonic-gate while (cur && cur->ai_next) 5780Sstevel@tonic-gate cur = cur->ai_next; 5790Sstevel@tonic-gate } 5800Sstevel@tonic-gate 581*11038SRao.Shoaib@Sun.COM freeaddrinfo(afai); /*%< afai must not be NULL at this point. */ 5820Sstevel@tonic-gate 5830Sstevel@tonic-gate if (sentinel.ai_next) { 5840Sstevel@tonic-gate good: 5850Sstevel@tonic-gate *res = sentinel.ai_next; 5860Sstevel@tonic-gate return(SUCCESS); 5870Sstevel@tonic-gate } else { 5880Sstevel@tonic-gate /* 5890Sstevel@tonic-gate * All the process succeeded, but we've had an empty list. 5900Sstevel@tonic-gate * This can happen if the given hints do not match our 5910Sstevel@tonic-gate * candidates. 5920Sstevel@tonic-gate */ 5930Sstevel@tonic-gate error = EAI_NONAME; 5940Sstevel@tonic-gate } 5950Sstevel@tonic-gate 5960Sstevel@tonic-gate free: 5970Sstevel@tonic-gate bad: 5980Sstevel@tonic-gate if (sentinel.ai_next) 5990Sstevel@tonic-gate freeaddrinfo(sentinel.ai_next); 6000Sstevel@tonic-gate *res = NULL; 6010Sstevel@tonic-gate return(error); 6020Sstevel@tonic-gate } 6030Sstevel@tonic-gate 604*11038SRao.Shoaib@Sun.COM /*% 6050Sstevel@tonic-gate * FQDN hostname, DNS lookup 6060Sstevel@tonic-gate */ 6070Sstevel@tonic-gate static int 6080Sstevel@tonic-gate explore_fqdn(pai, hostname, servname, res) 6090Sstevel@tonic-gate const struct addrinfo *pai; 6100Sstevel@tonic-gate const char *hostname; 6110Sstevel@tonic-gate const char *servname; 6120Sstevel@tonic-gate struct addrinfo **res; 6130Sstevel@tonic-gate { 6140Sstevel@tonic-gate struct addrinfo *result; 6150Sstevel@tonic-gate struct addrinfo *cur; 6160Sstevel@tonic-gate struct net_data *net_data = init(); 6170Sstevel@tonic-gate struct irs_ho *ho; 6180Sstevel@tonic-gate int error = 0; 6190Sstevel@tonic-gate char tmp[NS_MAXDNAME]; 6200Sstevel@tonic-gate const char *cp; 6210Sstevel@tonic-gate 6220Sstevel@tonic-gate INSIST(res != NULL && *res == NULL); 6230Sstevel@tonic-gate 6240Sstevel@tonic-gate /* 6250Sstevel@tonic-gate * if the servname does not match socktype/protocol, ignore it. 6260Sstevel@tonic-gate */ 6270Sstevel@tonic-gate if (get_portmatch(pai, servname) != 0) 6280Sstevel@tonic-gate return(0); 6290Sstevel@tonic-gate 6300Sstevel@tonic-gate if (!net_data || !(ho = net_data->ho)) 6310Sstevel@tonic-gate return(0); 632*11038SRao.Shoaib@Sun.COM #if 0 /*%< XXX (notyet) */ 6330Sstevel@tonic-gate if (net_data->ho_stayopen && net_data->ho_last && 6340Sstevel@tonic-gate net_data->ho_last->h_addrtype == af) { 6350Sstevel@tonic-gate if (ns_samename(name, net_data->ho_last->h_name) == 1) 6360Sstevel@tonic-gate return (net_data->ho_last); 6370Sstevel@tonic-gate for (hap = net_data->ho_last->h_aliases; hap && *hap; hap++) 6380Sstevel@tonic-gate if (ns_samename(name, *hap) == 1) 6390Sstevel@tonic-gate return (net_data->ho_last); 6400Sstevel@tonic-gate } 6410Sstevel@tonic-gate #endif 6420Sstevel@tonic-gate if (!strchr(hostname, '.') && 6430Sstevel@tonic-gate (cp = res_hostalias(net_data->res, hostname, 6440Sstevel@tonic-gate tmp, sizeof(tmp)))) 6450Sstevel@tonic-gate hostname = cp; 6460Sstevel@tonic-gate result = (*ho->addrinfo)(ho, hostname, pai); 6470Sstevel@tonic-gate if (!net_data->ho_stayopen) { 6480Sstevel@tonic-gate (*ho->minimize)(ho); 6490Sstevel@tonic-gate } 6500Sstevel@tonic-gate if (result == NULL) { 6510Sstevel@tonic-gate int e = h_errno; 6520Sstevel@tonic-gate 6530Sstevel@tonic-gate switch(e) { 6540Sstevel@tonic-gate case NETDB_INTERNAL: 6550Sstevel@tonic-gate error = EAI_SYSTEM; 6560Sstevel@tonic-gate break; 6570Sstevel@tonic-gate case TRY_AGAIN: 6580Sstevel@tonic-gate error = EAI_AGAIN; 6590Sstevel@tonic-gate break; 6600Sstevel@tonic-gate case NO_RECOVERY: 6610Sstevel@tonic-gate error = EAI_FAIL; 6620Sstevel@tonic-gate break; 6630Sstevel@tonic-gate case HOST_NOT_FOUND: 6640Sstevel@tonic-gate case NO_DATA: 6650Sstevel@tonic-gate error = EAI_NONAME; 6660Sstevel@tonic-gate break; 6670Sstevel@tonic-gate default: 668*11038SRao.Shoaib@Sun.COM case NETDB_SUCCESS: /*%< should be impossible... */ 6690Sstevel@tonic-gate error = EAI_NONAME; 6700Sstevel@tonic-gate break; 6710Sstevel@tonic-gate } 6720Sstevel@tonic-gate goto free; 6730Sstevel@tonic-gate } 6740Sstevel@tonic-gate 6750Sstevel@tonic-gate for (cur = result; cur; cur = cur->ai_next) { 676*11038SRao.Shoaib@Sun.COM GET_PORT(cur, servname); /*%< XXX: redundant lookups... */ 6770Sstevel@tonic-gate /* canonname should already be filled. */ 6780Sstevel@tonic-gate } 6790Sstevel@tonic-gate 6800Sstevel@tonic-gate *res = result; 6810Sstevel@tonic-gate 6820Sstevel@tonic-gate return(0); 6830Sstevel@tonic-gate 6840Sstevel@tonic-gate free: 6850Sstevel@tonic-gate if (result) 6860Sstevel@tonic-gate freeaddrinfo(result); 6870Sstevel@tonic-gate return error; 6880Sstevel@tonic-gate } 6890Sstevel@tonic-gate 6900Sstevel@tonic-gate static int 6910Sstevel@tonic-gate explore_copy(pai, src0, res) 692*11038SRao.Shoaib@Sun.COM const struct addrinfo *pai; /*%< seed */ 693*11038SRao.Shoaib@Sun.COM const struct addrinfo *src0; /*%< source */ 6940Sstevel@tonic-gate struct addrinfo **res; 6950Sstevel@tonic-gate { 6960Sstevel@tonic-gate int error; 6970Sstevel@tonic-gate struct addrinfo sentinel, *cur; 6980Sstevel@tonic-gate const struct addrinfo *src; 6990Sstevel@tonic-gate 7000Sstevel@tonic-gate error = 0; 7010Sstevel@tonic-gate sentinel.ai_next = NULL; 7020Sstevel@tonic-gate cur = &sentinel; 7030Sstevel@tonic-gate 7040Sstevel@tonic-gate for (src = src0; src != NULL; src = src->ai_next) { 7050Sstevel@tonic-gate if (src->ai_family != pai->ai_family) 7060Sstevel@tonic-gate continue; 7070Sstevel@tonic-gate 7080Sstevel@tonic-gate cur->ai_next = copy_ai(src); 7090Sstevel@tonic-gate if (!cur->ai_next) { 7100Sstevel@tonic-gate error = EAI_MEMORY; 7110Sstevel@tonic-gate goto fail; 7120Sstevel@tonic-gate } 7130Sstevel@tonic-gate 7140Sstevel@tonic-gate cur->ai_next->ai_socktype = pai->ai_socktype; 7150Sstevel@tonic-gate cur->ai_next->ai_protocol = pai->ai_protocol; 7160Sstevel@tonic-gate cur = cur->ai_next; 7170Sstevel@tonic-gate } 7180Sstevel@tonic-gate 7190Sstevel@tonic-gate *res = sentinel.ai_next; 7200Sstevel@tonic-gate return 0; 7210Sstevel@tonic-gate 7220Sstevel@tonic-gate fail: 7230Sstevel@tonic-gate freeaddrinfo(sentinel.ai_next); 7240Sstevel@tonic-gate return error; 7250Sstevel@tonic-gate } 7260Sstevel@tonic-gate 727*11038SRao.Shoaib@Sun.COM /*% 7280Sstevel@tonic-gate * hostname == NULL. 7290Sstevel@tonic-gate * passive socket -> anyaddr (0.0.0.0 or ::) 7300Sstevel@tonic-gate * non-passive socket -> localhost (127.0.0.1 or ::1) 7310Sstevel@tonic-gate */ 7320Sstevel@tonic-gate static int 7330Sstevel@tonic-gate explore_null(pai, servname, res) 7340Sstevel@tonic-gate const struct addrinfo *pai; 7350Sstevel@tonic-gate const char *servname; 7360Sstevel@tonic-gate struct addrinfo **res; 7370Sstevel@tonic-gate { 7380Sstevel@tonic-gate const struct afd *afd; 7390Sstevel@tonic-gate struct addrinfo *cur; 7400Sstevel@tonic-gate struct addrinfo sentinel; 7410Sstevel@tonic-gate int error; 7420Sstevel@tonic-gate 7430Sstevel@tonic-gate *res = NULL; 7440Sstevel@tonic-gate sentinel.ai_next = NULL; 7450Sstevel@tonic-gate cur = &sentinel; 7460Sstevel@tonic-gate 7470Sstevel@tonic-gate afd = find_afd(pai->ai_family); 7480Sstevel@tonic-gate if (afd == NULL) 7490Sstevel@tonic-gate return 0; 7500Sstevel@tonic-gate 7510Sstevel@tonic-gate if (pai->ai_flags & AI_PASSIVE) { 7520Sstevel@tonic-gate GET_AI(cur->ai_next, afd, afd->a_addrany); 7530Sstevel@tonic-gate /* xxx meaningless? 7540Sstevel@tonic-gate * GET_CANONNAME(cur->ai_next, "anyaddr"); 7550Sstevel@tonic-gate */ 7560Sstevel@tonic-gate GET_PORT(cur->ai_next, servname); 7570Sstevel@tonic-gate } else { 7580Sstevel@tonic-gate GET_AI(cur->ai_next, afd, afd->a_loopback); 7590Sstevel@tonic-gate /* xxx meaningless? 7600Sstevel@tonic-gate * GET_CANONNAME(cur->ai_next, "localhost"); 7610Sstevel@tonic-gate */ 7620Sstevel@tonic-gate GET_PORT(cur->ai_next, servname); 7630Sstevel@tonic-gate } 7640Sstevel@tonic-gate cur = cur->ai_next; 7650Sstevel@tonic-gate 7660Sstevel@tonic-gate *res = sentinel.ai_next; 7670Sstevel@tonic-gate return 0; 7680Sstevel@tonic-gate 7690Sstevel@tonic-gate free: 7700Sstevel@tonic-gate if (sentinel.ai_next) 7710Sstevel@tonic-gate freeaddrinfo(sentinel.ai_next); 7720Sstevel@tonic-gate return error; 7730Sstevel@tonic-gate } 7740Sstevel@tonic-gate 775*11038SRao.Shoaib@Sun.COM /*% 7760Sstevel@tonic-gate * numeric hostname 7770Sstevel@tonic-gate */ 7780Sstevel@tonic-gate static int 7790Sstevel@tonic-gate explore_numeric(pai, hostname, servname, res) 7800Sstevel@tonic-gate const struct addrinfo *pai; 7810Sstevel@tonic-gate const char *hostname; 7820Sstevel@tonic-gate const char *servname; 7830Sstevel@tonic-gate struct addrinfo **res; 7840Sstevel@tonic-gate { 7850Sstevel@tonic-gate const struct afd *afd; 7860Sstevel@tonic-gate struct addrinfo *cur; 7870Sstevel@tonic-gate struct addrinfo sentinel; 7880Sstevel@tonic-gate int error; 7890Sstevel@tonic-gate char pton[PTON_MAX]; 7900Sstevel@tonic-gate 7910Sstevel@tonic-gate *res = NULL; 7920Sstevel@tonic-gate sentinel.ai_next = NULL; 7930Sstevel@tonic-gate cur = &sentinel; 7940Sstevel@tonic-gate 7950Sstevel@tonic-gate afd = find_afd(pai->ai_family); 7960Sstevel@tonic-gate if (afd == NULL) 7970Sstevel@tonic-gate return 0; 7980Sstevel@tonic-gate 7990Sstevel@tonic-gate switch (afd->a_af) { 8000Sstevel@tonic-gate #if 0 /*X/Open spec*/ 8010Sstevel@tonic-gate case AF_INET: 8020Sstevel@tonic-gate if (inet_aton(hostname, (struct in_addr *)pton) == 1) { 8030Sstevel@tonic-gate if (pai->ai_family == afd->a_af || 8040Sstevel@tonic-gate pai->ai_family == PF_UNSPEC /*?*/) { 8050Sstevel@tonic-gate GET_AI(cur->ai_next, afd, pton); 8060Sstevel@tonic-gate GET_PORT(cur->ai_next, servname); 807*11038SRao.Shoaib@Sun.COM while (cur->ai_next) 8080Sstevel@tonic-gate cur = cur->ai_next; 8090Sstevel@tonic-gate } else 810*11038SRao.Shoaib@Sun.COM SETERROR(EAI_FAMILY); /*xxx*/ 8110Sstevel@tonic-gate } 8120Sstevel@tonic-gate break; 8130Sstevel@tonic-gate #endif 8140Sstevel@tonic-gate default: 8150Sstevel@tonic-gate if (inet_pton(afd->a_af, hostname, pton) == 1) { 8160Sstevel@tonic-gate if (pai->ai_family == afd->a_af || 8170Sstevel@tonic-gate pai->ai_family == PF_UNSPEC /*?*/) { 8180Sstevel@tonic-gate GET_AI(cur->ai_next, afd, pton); 8190Sstevel@tonic-gate GET_PORT(cur->ai_next, servname); 820*11038SRao.Shoaib@Sun.COM while (cur->ai_next) 8210Sstevel@tonic-gate cur = cur->ai_next; 822*11038SRao.Shoaib@Sun.COM } else 823*11038SRao.Shoaib@Sun.COM SETERROR(EAI_FAMILY); /*xxx*/ 8240Sstevel@tonic-gate } 8250Sstevel@tonic-gate break; 8260Sstevel@tonic-gate } 8270Sstevel@tonic-gate 8280Sstevel@tonic-gate *res = sentinel.ai_next; 8290Sstevel@tonic-gate return 0; 8300Sstevel@tonic-gate 8310Sstevel@tonic-gate free: 8320Sstevel@tonic-gate bad: 8330Sstevel@tonic-gate if (sentinel.ai_next) 8340Sstevel@tonic-gate freeaddrinfo(sentinel.ai_next); 8350Sstevel@tonic-gate return error; 8360Sstevel@tonic-gate } 8370Sstevel@tonic-gate 838*11038SRao.Shoaib@Sun.COM /*% 8390Sstevel@tonic-gate * numeric hostname with scope 8400Sstevel@tonic-gate */ 8410Sstevel@tonic-gate static int 8420Sstevel@tonic-gate explore_numeric_scope(pai, hostname, servname, res) 8430Sstevel@tonic-gate const struct addrinfo *pai; 8440Sstevel@tonic-gate const char *hostname; 8450Sstevel@tonic-gate const char *servname; 8460Sstevel@tonic-gate struct addrinfo **res; 8470Sstevel@tonic-gate { 8480Sstevel@tonic-gate #ifndef SCOPE_DELIMITER 8490Sstevel@tonic-gate return explore_numeric(pai, hostname, servname, res); 8500Sstevel@tonic-gate #else 8510Sstevel@tonic-gate const struct afd *afd; 8520Sstevel@tonic-gate struct addrinfo *cur; 8530Sstevel@tonic-gate int error; 8540Sstevel@tonic-gate char *cp, *hostname2 = NULL, *scope, *addr; 8550Sstevel@tonic-gate struct sockaddr_in6 *sin6; 8560Sstevel@tonic-gate 8570Sstevel@tonic-gate afd = find_afd(pai->ai_family); 8580Sstevel@tonic-gate if (afd == NULL) 8590Sstevel@tonic-gate return 0; 8600Sstevel@tonic-gate 8610Sstevel@tonic-gate if (!afd->a_scoped) 8620Sstevel@tonic-gate return explore_numeric(pai, hostname, servname, res); 8630Sstevel@tonic-gate 8640Sstevel@tonic-gate cp = strchr(hostname, SCOPE_DELIMITER); 8650Sstevel@tonic-gate if (cp == NULL) 8660Sstevel@tonic-gate return explore_numeric(pai, hostname, servname, res); 8670Sstevel@tonic-gate 8680Sstevel@tonic-gate /* 8690Sstevel@tonic-gate * Handle special case of <scoped_address><delimiter><scope id> 8700Sstevel@tonic-gate */ 8710Sstevel@tonic-gate hostname2 = strdup(hostname); 8720Sstevel@tonic-gate if (hostname2 == NULL) 8730Sstevel@tonic-gate return EAI_MEMORY; 8740Sstevel@tonic-gate /* terminate at the delimiter */ 8750Sstevel@tonic-gate hostname2[cp - hostname] = '\0'; 8760Sstevel@tonic-gate addr = hostname2; 8770Sstevel@tonic-gate scope = cp + 1; 8780Sstevel@tonic-gate 8790Sstevel@tonic-gate error = explore_numeric(pai, addr, servname, res); 8800Sstevel@tonic-gate if (error == 0) { 8810Sstevel@tonic-gate u_int32_t scopeid = 0; 8820Sstevel@tonic-gate 8830Sstevel@tonic-gate for (cur = *res; cur; cur = cur->ai_next) { 8840Sstevel@tonic-gate if (cur->ai_family != AF_INET6) 8850Sstevel@tonic-gate continue; 8860Sstevel@tonic-gate sin6 = (struct sockaddr_in6 *)(void *)cur->ai_addr; 8870Sstevel@tonic-gate if (!ip6_str2scopeid(scope, sin6, &scopeid)) { 8880Sstevel@tonic-gate free(hostname2); 889*11038SRao.Shoaib@Sun.COM return(EAI_NONAME); /*%< XXX: is return OK? */ 8900Sstevel@tonic-gate } 8910Sstevel@tonic-gate #ifdef HAVE_SIN6_SCOPE_ID 8920Sstevel@tonic-gate sin6->sin6_scope_id = scopeid; 8930Sstevel@tonic-gate #endif 8940Sstevel@tonic-gate } 8950Sstevel@tonic-gate } 8960Sstevel@tonic-gate 8970Sstevel@tonic-gate free(hostname2); 8980Sstevel@tonic-gate 8990Sstevel@tonic-gate return error; 9000Sstevel@tonic-gate #endif 9010Sstevel@tonic-gate } 9020Sstevel@tonic-gate 9030Sstevel@tonic-gate static int 9040Sstevel@tonic-gate get_canonname(pai, ai, str) 9050Sstevel@tonic-gate const struct addrinfo *pai; 9060Sstevel@tonic-gate struct addrinfo *ai; 9070Sstevel@tonic-gate const char *str; 9080Sstevel@tonic-gate { 9090Sstevel@tonic-gate if ((pai->ai_flags & AI_CANONNAME) != 0) { 9100Sstevel@tonic-gate ai->ai_canonname = (char *)malloc(strlen(str) + 1); 9110Sstevel@tonic-gate if (ai->ai_canonname == NULL) 9120Sstevel@tonic-gate return EAI_MEMORY; 9130Sstevel@tonic-gate strcpy(ai->ai_canonname, str); 9140Sstevel@tonic-gate } 9150Sstevel@tonic-gate return 0; 9160Sstevel@tonic-gate } 9170Sstevel@tonic-gate 9180Sstevel@tonic-gate static struct addrinfo * 9190Sstevel@tonic-gate get_ai(pai, afd, addr) 9200Sstevel@tonic-gate const struct addrinfo *pai; 9210Sstevel@tonic-gate const struct afd *afd; 9220Sstevel@tonic-gate const char *addr; 9230Sstevel@tonic-gate { 9240Sstevel@tonic-gate char *p; 9250Sstevel@tonic-gate struct addrinfo *ai; 9260Sstevel@tonic-gate 9270Sstevel@tonic-gate ai = (struct addrinfo *)malloc(sizeof(struct addrinfo) 9280Sstevel@tonic-gate + (afd->a_socklen)); 9290Sstevel@tonic-gate if (ai == NULL) 9300Sstevel@tonic-gate return NULL; 9310Sstevel@tonic-gate 9320Sstevel@tonic-gate memcpy(ai, pai, sizeof(struct addrinfo)); 9330Sstevel@tonic-gate ai->ai_addr = (struct sockaddr *)(void *)(ai + 1); 9340Sstevel@tonic-gate memset(ai->ai_addr, 0, (size_t)afd->a_socklen); 9350Sstevel@tonic-gate #ifdef HAVE_SA_LEN 9360Sstevel@tonic-gate ai->ai_addr->sa_len = afd->a_socklen; 9370Sstevel@tonic-gate #endif 9380Sstevel@tonic-gate ai->ai_addrlen = afd->a_socklen; 9390Sstevel@tonic-gate ai->ai_addr->sa_family = ai->ai_family = afd->a_af; 9400Sstevel@tonic-gate p = (char *)(void *)(ai->ai_addr); 9410Sstevel@tonic-gate memcpy(p + afd->a_off, addr, (size_t)afd->a_addrlen); 9420Sstevel@tonic-gate return ai; 9430Sstevel@tonic-gate } 9440Sstevel@tonic-gate 9450Sstevel@tonic-gate /* XXX need to malloc() the same way we do from other functions! */ 9460Sstevel@tonic-gate static struct addrinfo * 9470Sstevel@tonic-gate copy_ai(pai) 9480Sstevel@tonic-gate const struct addrinfo *pai; 9490Sstevel@tonic-gate { 9500Sstevel@tonic-gate struct addrinfo *ai; 9510Sstevel@tonic-gate size_t l; 9520Sstevel@tonic-gate 9530Sstevel@tonic-gate l = sizeof(*ai) + pai->ai_addrlen; 9540Sstevel@tonic-gate if ((ai = (struct addrinfo *)malloc(l)) == NULL) 9550Sstevel@tonic-gate return NULL; 9560Sstevel@tonic-gate memset(ai, 0, l); 9570Sstevel@tonic-gate memcpy(ai, pai, sizeof(*ai)); 9580Sstevel@tonic-gate ai->ai_addr = (struct sockaddr *)(void *)(ai + 1); 9590Sstevel@tonic-gate memcpy(ai->ai_addr, pai->ai_addr, pai->ai_addrlen); 9600Sstevel@tonic-gate 9610Sstevel@tonic-gate if (pai->ai_canonname) { 9620Sstevel@tonic-gate l = strlen(pai->ai_canonname) + 1; 9630Sstevel@tonic-gate if ((ai->ai_canonname = malloc(l)) == NULL) { 9640Sstevel@tonic-gate free(ai); 9650Sstevel@tonic-gate return NULL; 9660Sstevel@tonic-gate } 967*11038SRao.Shoaib@Sun.COM strcpy(ai->ai_canonname, pai->ai_canonname); /* (checked) */ 9680Sstevel@tonic-gate } else { 9690Sstevel@tonic-gate /* just to make sure */ 9700Sstevel@tonic-gate ai->ai_canonname = NULL; 9710Sstevel@tonic-gate } 9720Sstevel@tonic-gate 9730Sstevel@tonic-gate ai->ai_next = NULL; 9740Sstevel@tonic-gate 9750Sstevel@tonic-gate return ai; 9760Sstevel@tonic-gate } 9770Sstevel@tonic-gate 9780Sstevel@tonic-gate static int 9790Sstevel@tonic-gate get_portmatch(const struct addrinfo *ai, const char *servname) { 9800Sstevel@tonic-gate 9810Sstevel@tonic-gate /* get_port does not touch first argument. when matchonly == 1. */ 9820Sstevel@tonic-gate /* LINTED const cast */ 9830Sstevel@tonic-gate return get_port((const struct addrinfo *)ai, servname, 1); 9840Sstevel@tonic-gate } 9850Sstevel@tonic-gate 9860Sstevel@tonic-gate static int 9870Sstevel@tonic-gate get_port(const struct addrinfo *ai, const char *servname, int matchonly) { 9880Sstevel@tonic-gate const char *proto; 9890Sstevel@tonic-gate struct servent *sp; 9900Sstevel@tonic-gate int port; 9910Sstevel@tonic-gate int allownumeric; 9920Sstevel@tonic-gate 9930Sstevel@tonic-gate if (servname == NULL) 9940Sstevel@tonic-gate return 0; 9950Sstevel@tonic-gate switch (ai->ai_family) { 9960Sstevel@tonic-gate case AF_INET: 9970Sstevel@tonic-gate #ifdef AF_INET6 9980Sstevel@tonic-gate case AF_INET6: 9990Sstevel@tonic-gate #endif 10000Sstevel@tonic-gate break; 10010Sstevel@tonic-gate default: 10020Sstevel@tonic-gate return 0; 10030Sstevel@tonic-gate } 10040Sstevel@tonic-gate 10050Sstevel@tonic-gate switch (ai->ai_socktype) { 10060Sstevel@tonic-gate case SOCK_RAW: 10070Sstevel@tonic-gate return EAI_SERVICE; 10080Sstevel@tonic-gate case SOCK_DGRAM: 10090Sstevel@tonic-gate case SOCK_STREAM: 10100Sstevel@tonic-gate allownumeric = 1; 10110Sstevel@tonic-gate break; 10120Sstevel@tonic-gate case ANY: 10130Sstevel@tonic-gate switch (ai->ai_family) { 10140Sstevel@tonic-gate case AF_INET: 10150Sstevel@tonic-gate #ifdef AF_INET6 10160Sstevel@tonic-gate case AF_INET6: 10170Sstevel@tonic-gate #endif 10180Sstevel@tonic-gate allownumeric = 1; 10190Sstevel@tonic-gate break; 10200Sstevel@tonic-gate default: 10210Sstevel@tonic-gate allownumeric = 0; 10220Sstevel@tonic-gate break; 10230Sstevel@tonic-gate } 10240Sstevel@tonic-gate break; 10250Sstevel@tonic-gate default: 10260Sstevel@tonic-gate return EAI_SOCKTYPE; 10270Sstevel@tonic-gate } 10280Sstevel@tonic-gate 10290Sstevel@tonic-gate if (str_isnumber(servname)) { 10300Sstevel@tonic-gate if (!allownumeric) 10310Sstevel@tonic-gate return EAI_SERVICE; 10320Sstevel@tonic-gate port = atoi(servname); 10330Sstevel@tonic-gate if (port < 0 || port > 65535) 10340Sstevel@tonic-gate return EAI_SERVICE; 10350Sstevel@tonic-gate port = htons(port); 10360Sstevel@tonic-gate } else { 10370Sstevel@tonic-gate switch (ai->ai_socktype) { 10380Sstevel@tonic-gate case SOCK_DGRAM: 10390Sstevel@tonic-gate proto = "udp"; 10400Sstevel@tonic-gate break; 10410Sstevel@tonic-gate case SOCK_STREAM: 10420Sstevel@tonic-gate proto = "tcp"; 10430Sstevel@tonic-gate break; 10440Sstevel@tonic-gate default: 10450Sstevel@tonic-gate proto = NULL; 10460Sstevel@tonic-gate break; 10470Sstevel@tonic-gate } 10480Sstevel@tonic-gate 10490Sstevel@tonic-gate if ((sp = getservbyname(servname, proto)) == NULL) 10500Sstevel@tonic-gate return EAI_SERVICE; 10510Sstevel@tonic-gate port = sp->s_port; 10520Sstevel@tonic-gate } 10530Sstevel@tonic-gate 10540Sstevel@tonic-gate if (!matchonly) { 10550Sstevel@tonic-gate switch (ai->ai_family) { 10560Sstevel@tonic-gate case AF_INET: 10570Sstevel@tonic-gate ((struct sockaddr_in *)(void *) 10580Sstevel@tonic-gate ai->ai_addr)->sin_port = port; 10590Sstevel@tonic-gate break; 10600Sstevel@tonic-gate case AF_INET6: 10610Sstevel@tonic-gate ((struct sockaddr_in6 *)(void *) 10620Sstevel@tonic-gate ai->ai_addr)->sin6_port = port; 10630Sstevel@tonic-gate break; 10640Sstevel@tonic-gate } 10650Sstevel@tonic-gate } 10660Sstevel@tonic-gate 10670Sstevel@tonic-gate return 0; 10680Sstevel@tonic-gate } 10690Sstevel@tonic-gate 10700Sstevel@tonic-gate static const struct afd * 10710Sstevel@tonic-gate find_afd(af) 10720Sstevel@tonic-gate int af; 10730Sstevel@tonic-gate { 10740Sstevel@tonic-gate const struct afd *afd; 10750Sstevel@tonic-gate 10760Sstevel@tonic-gate if (af == PF_UNSPEC) 10770Sstevel@tonic-gate return NULL; 10780Sstevel@tonic-gate for (afd = afdl; afd->a_af; afd++) { 10790Sstevel@tonic-gate if (afd->a_af == af) 10800Sstevel@tonic-gate return afd; 10810Sstevel@tonic-gate } 10820Sstevel@tonic-gate return NULL; 10830Sstevel@tonic-gate } 10840Sstevel@tonic-gate 1085*11038SRao.Shoaib@Sun.COM /*% 10860Sstevel@tonic-gate * post-2553: AI_ADDRCONFIG check. if we use getipnodeby* as backend, backend 10870Sstevel@tonic-gate * will take care of it. 10880Sstevel@tonic-gate * the semantics of AI_ADDRCONFIG is not defined well. we are not sure 10890Sstevel@tonic-gate * if the code is right or not. 10900Sstevel@tonic-gate */ 10910Sstevel@tonic-gate static int 10920Sstevel@tonic-gate addrconfig(af) 10930Sstevel@tonic-gate int af; 10940Sstevel@tonic-gate { 10950Sstevel@tonic-gate int s; 10960Sstevel@tonic-gate 10970Sstevel@tonic-gate /* XXX errno */ 10980Sstevel@tonic-gate s = socket(af, SOCK_DGRAM, 0); 10990Sstevel@tonic-gate if (s < 0) { 11000Sstevel@tonic-gate if (errno != EMFILE) 11010Sstevel@tonic-gate return 0; 11020Sstevel@tonic-gate } else 11030Sstevel@tonic-gate close(s); 11040Sstevel@tonic-gate return 1; 11050Sstevel@tonic-gate } 11060Sstevel@tonic-gate 11070Sstevel@tonic-gate /* convert a string to a scope identifier. XXX: IPv6 specific */ 11080Sstevel@tonic-gate static int 11090Sstevel@tonic-gate ip6_str2scopeid(char *scope, struct sockaddr_in6 *sin6, 11100Sstevel@tonic-gate u_int32_t *scopeidp) 11110Sstevel@tonic-gate { 11120Sstevel@tonic-gate u_int32_t scopeid; 11130Sstevel@tonic-gate u_long lscopeid; 11140Sstevel@tonic-gate struct in6_addr *a6 = &sin6->sin6_addr; 11150Sstevel@tonic-gate char *ep; 11160Sstevel@tonic-gate 11170Sstevel@tonic-gate /* empty scopeid portion is invalid */ 11180Sstevel@tonic-gate if (*scope == '\0') 11190Sstevel@tonic-gate return (0); 11200Sstevel@tonic-gate 11210Sstevel@tonic-gate #ifdef USE_IFNAMELINKID 1122*11038SRao.Shoaib@Sun.COM if (IN6_IS_ADDR_LINKLOCAL(a6) || IN6_IS_ADDR_MC_LINKLOCAL(a6) || 1123*11038SRao.Shoaib@Sun.COM IN6_IS_ADDR_MC_NODELOCAL(a6)) { 11240Sstevel@tonic-gate /* 11250Sstevel@tonic-gate * Using interface names as link indices can be allowed 11260Sstevel@tonic-gate * only when we can assume a one-to-one mappings between 11270Sstevel@tonic-gate * links and interfaces. See comments in getnameinfo.c. 11280Sstevel@tonic-gate */ 11290Sstevel@tonic-gate scopeid = if_nametoindex(scope); 11300Sstevel@tonic-gate if (scopeid == 0) 11310Sstevel@tonic-gate goto trynumeric; 11320Sstevel@tonic-gate *scopeidp = scopeid; 11330Sstevel@tonic-gate return (1); 11340Sstevel@tonic-gate } 11350Sstevel@tonic-gate #endif 11360Sstevel@tonic-gate 11370Sstevel@tonic-gate /* still unclear about literal, allow numeric only - placeholder */ 11380Sstevel@tonic-gate if (IN6_IS_ADDR_SITELOCAL(a6) || IN6_IS_ADDR_MC_SITELOCAL(a6)) 11390Sstevel@tonic-gate goto trynumeric; 11400Sstevel@tonic-gate if (IN6_IS_ADDR_MC_ORGLOCAL(a6)) 11410Sstevel@tonic-gate goto trynumeric; 11420Sstevel@tonic-gate else 1143*11038SRao.Shoaib@Sun.COM goto trynumeric; /*%< global */ 11440Sstevel@tonic-gate /* try to convert to a numeric id as a last resort */ 11450Sstevel@tonic-gate trynumeric: 11460Sstevel@tonic-gate errno = 0; 11470Sstevel@tonic-gate lscopeid = strtoul(scope, &ep, 10); 11480Sstevel@tonic-gate scopeid = lscopeid & 0xffffffff; 11490Sstevel@tonic-gate if (errno == 0 && ep && *ep == '\0' && scopeid == lscopeid) { 11500Sstevel@tonic-gate *scopeidp = scopeid; 11510Sstevel@tonic-gate return (1); 11520Sstevel@tonic-gate } else 11530Sstevel@tonic-gate return (0); 11540Sstevel@tonic-gate } 11550Sstevel@tonic-gate 11560Sstevel@tonic-gate struct addrinfo * 11570Sstevel@tonic-gate hostent2addrinfo(hp, pai) 11580Sstevel@tonic-gate struct hostent *hp; 11590Sstevel@tonic-gate const struct addrinfo *pai; 11600Sstevel@tonic-gate { 11610Sstevel@tonic-gate int i, af, error = 0; 11620Sstevel@tonic-gate char **aplist = NULL, *ap; 11630Sstevel@tonic-gate struct addrinfo sentinel, *cur; 11640Sstevel@tonic-gate const struct afd *afd; 11650Sstevel@tonic-gate 11660Sstevel@tonic-gate af = hp->h_addrtype; 11670Sstevel@tonic-gate if (pai->ai_family != AF_UNSPEC && af != pai->ai_family) 11680Sstevel@tonic-gate return(NULL); 11690Sstevel@tonic-gate 11700Sstevel@tonic-gate afd = find_afd(af); 11710Sstevel@tonic-gate if (afd == NULL) 11720Sstevel@tonic-gate return(NULL); 11730Sstevel@tonic-gate 11740Sstevel@tonic-gate aplist = hp->h_addr_list; 11750Sstevel@tonic-gate 11760Sstevel@tonic-gate memset(&sentinel, 0, sizeof(sentinel)); 11770Sstevel@tonic-gate cur = &sentinel; 11780Sstevel@tonic-gate 11790Sstevel@tonic-gate for (i = 0; (ap = aplist[i]) != NULL; i++) { 1180*11038SRao.Shoaib@Sun.COM #if 0 /*%< the trick seems too much */ 11810Sstevel@tonic-gate af = hp->h_addr_list; 11820Sstevel@tonic-gate if (af == AF_INET6 && 11830Sstevel@tonic-gate IN6_IS_ADDR_V4MAPPED((struct in6_addr *)ap)) { 11840Sstevel@tonic-gate af = AF_INET; 11850Sstevel@tonic-gate ap = ap + sizeof(struct in6_addr) 11860Sstevel@tonic-gate - sizeof(struct in_addr); 11870Sstevel@tonic-gate } 11880Sstevel@tonic-gate afd = find_afd(af); 11890Sstevel@tonic-gate if (afd == NULL) 11900Sstevel@tonic-gate continue; 11910Sstevel@tonic-gate #endif /* 0 */ 11920Sstevel@tonic-gate 11930Sstevel@tonic-gate GET_AI(cur->ai_next, afd, ap); 11940Sstevel@tonic-gate 11950Sstevel@tonic-gate /* GET_PORT(cur->ai_next, servname); */ 11960Sstevel@tonic-gate if ((pai->ai_flags & AI_CANONNAME) != 0) { 11970Sstevel@tonic-gate /* 11980Sstevel@tonic-gate * RFC2553 says that ai_canonname will be set only for 11990Sstevel@tonic-gate * the first element. we do it for all the elements, 12000Sstevel@tonic-gate * just for convenience. 12010Sstevel@tonic-gate */ 12020Sstevel@tonic-gate GET_CANONNAME(cur->ai_next, hp->h_name); 12030Sstevel@tonic-gate } 1204*11038SRao.Shoaib@Sun.COM while (cur->ai_next) /*%< no need to loop, actually. */ 12050Sstevel@tonic-gate cur = cur->ai_next; 12060Sstevel@tonic-gate continue; 12070Sstevel@tonic-gate 12080Sstevel@tonic-gate free: 12090Sstevel@tonic-gate if (cur->ai_next) 12100Sstevel@tonic-gate freeaddrinfo(cur->ai_next); 12110Sstevel@tonic-gate cur->ai_next = NULL; 12120Sstevel@tonic-gate /* continue, without tht pointer CUR advanced. */ 12130Sstevel@tonic-gate } 12140Sstevel@tonic-gate 12150Sstevel@tonic-gate return(sentinel.ai_next); 12160Sstevel@tonic-gate } 12170Sstevel@tonic-gate 12180Sstevel@tonic-gate struct addrinfo * 12190Sstevel@tonic-gate addr2addrinfo(pai, cp) 12200Sstevel@tonic-gate const struct addrinfo *pai; 12210Sstevel@tonic-gate const char *cp; 12220Sstevel@tonic-gate { 12230Sstevel@tonic-gate const struct afd *afd; 12240Sstevel@tonic-gate 12250Sstevel@tonic-gate afd = find_afd(pai->ai_family); 12260Sstevel@tonic-gate if (afd == NULL) 12270Sstevel@tonic-gate return(NULL); 12280Sstevel@tonic-gate 12290Sstevel@tonic-gate return(get_ai(pai, afd, cp)); 12300Sstevel@tonic-gate } 12310Sstevel@tonic-gate 12320Sstevel@tonic-gate static struct net_data * 12330Sstevel@tonic-gate init() 12340Sstevel@tonic-gate { 12350Sstevel@tonic-gate struct net_data *net_data; 12360Sstevel@tonic-gate 12370Sstevel@tonic-gate if (!(net_data = net_data_init(NULL))) 12380Sstevel@tonic-gate goto error; 12390Sstevel@tonic-gate if (!net_data->ho) { 12400Sstevel@tonic-gate net_data->ho = (*net_data->irs->ho_map)(net_data->irs); 12410Sstevel@tonic-gate if (!net_data->ho || !net_data->res) { 12420Sstevel@tonic-gate error: 12430Sstevel@tonic-gate errno = EIO; 12440Sstevel@tonic-gate if (net_data && net_data->res) 12450Sstevel@tonic-gate RES_SET_H_ERRNO(net_data->res, NETDB_INTERNAL); 12460Sstevel@tonic-gate return (NULL); 12470Sstevel@tonic-gate } 12480Sstevel@tonic-gate 12490Sstevel@tonic-gate (*net_data->ho->res_set)(net_data->ho, net_data->res, NULL); 12500Sstevel@tonic-gate } 12510Sstevel@tonic-gate 12520Sstevel@tonic-gate return (net_data); 12530Sstevel@tonic-gate } 1254