xref: /onnv-gate/usr/src/lib/libresolv2/common/irs/getaddrinfo.c (revision 11038:74b12212b8a2)
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
freeaddrinfo(ai)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
str_isnumber(p)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
getaddrinfo(hostname,servname,hints,res)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
explore_fqdn(pai,hostname,servname,res)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
explore_copy(pai,src0,res)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
explore_null(pai,servname,res)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
explore_numeric(pai,hostname,servname,res)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
explore_numeric_scope(pai,hostname,servname,res)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
get_canonname(pai,ai,str)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 *
get_ai(pai,afd,addr)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 *
copy_ai(pai)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
get_portmatch(const struct addrinfo * ai,const char * servname)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
get_port(const struct addrinfo * ai,const char * servname,int matchonly)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 *
find_afd(af)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
addrconfig(af)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
ip6_str2scopeid(char * scope,struct sockaddr_in6 * sin6,u_int32_t * scopeidp)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 *
hostent2addrinfo(hp,pai)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 *
addr2addrinfo(pai,cp)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 *
init()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