xref: /illumos-gate/usr/src/lib/libresolv2/common/irs/getaddrinfo.c (revision 55fea89dcaa64928bed4327112404dcb3e07b79f)
17c478bd9Sstevel@tonic-gate /*	$KAME: getaddrinfo.c,v 1.14 2001/01/06 09:41:15 jinmei Exp $	*/
27c478bd9Sstevel@tonic-gate 
37c478bd9Sstevel@tonic-gate /*
47c478bd9Sstevel@tonic-gate  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
57c478bd9Sstevel@tonic-gate  * All rights reserved.
67c478bd9Sstevel@tonic-gate  *
77c478bd9Sstevel@tonic-gate  * Redistribution and use in source and binary forms, with or without
87c478bd9Sstevel@tonic-gate  * modification, are permitted provided that the following conditions
97c478bd9Sstevel@tonic-gate  * are met:
107c478bd9Sstevel@tonic-gate  * 1. Redistributions of source code must retain the above copyright
117c478bd9Sstevel@tonic-gate  *    notice, this list of conditions and the following disclaimer.
127c478bd9Sstevel@tonic-gate  * 2. Redistributions in binary form must reproduce the above copyright
137c478bd9Sstevel@tonic-gate  *    notice, this list of conditions and the following disclaimer in the
147c478bd9Sstevel@tonic-gate  *    documentation and/or other materials provided with the distribution.
157c478bd9Sstevel@tonic-gate  * 3. Neither the name of the project nor the names of its contributors
167c478bd9Sstevel@tonic-gate  *    may be used to endorse or promote products derived from this software
177c478bd9Sstevel@tonic-gate  *    without specific prior written permission.
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
207c478bd9Sstevel@tonic-gate  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
217c478bd9Sstevel@tonic-gate  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
227c478bd9Sstevel@tonic-gate  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
237c478bd9Sstevel@tonic-gate  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
247c478bd9Sstevel@tonic-gate  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
257c478bd9Sstevel@tonic-gate  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
267c478bd9Sstevel@tonic-gate  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
277c478bd9Sstevel@tonic-gate  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
287c478bd9Sstevel@tonic-gate  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
297c478bd9Sstevel@tonic-gate  * SUCH DAMAGE.
307c478bd9Sstevel@tonic-gate  */
317c478bd9Sstevel@tonic-gate 
32*9525b14bSRao Shoaib /*! \file
337c478bd9Sstevel@tonic-gate  * Issues to be discussed:
34*9525b14bSRao Shoaib  *\li  Thread safe-ness must be checked.
35*9525b14bSRao Shoaib  *\li  Return values.  There are nonstandard return values defined and used
367c478bd9Sstevel@tonic-gate  *   in the source code.  This is because RFC2553 is silent about which error
377c478bd9Sstevel@tonic-gate  *   code must be returned for which situation.
38*9525b14bSRao Shoaib  *\li  IPv4 classful (shortened) form.  RFC2553 is silent about it.  XNET 5.2
397c478bd9Sstevel@tonic-gate  *   says to use inet_aton() to convert IPv4 numeric to binary (allows
407c478bd9Sstevel@tonic-gate  *   classful form as a result).
417c478bd9Sstevel@tonic-gate  *   current code - disallow classful form for IPv4 (due to use of inet_pton).
42*9525b14bSRao Shoaib  *\li  freeaddrinfo(NULL).  RFC2553 is silent about it.  XNET 5.2 says it is
437c478bd9Sstevel@tonic-gate  *   invalid.
447c478bd9Sstevel@tonic-gate  *   current code - SEGV on freeaddrinfo(NULL)
457c478bd9Sstevel@tonic-gate  * Note:
46*9525b14bSRao Shoaib  *\li  We use getipnodebyname() just for thread-safeness.  There's no intent
477c478bd9Sstevel@tonic-gate  *   to let it do PF_UNSPEC (actually we never pass PF_UNSPEC to
487c478bd9Sstevel@tonic-gate  *   getipnodebyname().
49*9525b14bSRao Shoaib  *\li  The code filters out AFs that are not supported by the kernel,
507c478bd9Sstevel@tonic-gate  *   when globbing NULL hostname (to loopback, or wildcard).  Is it the right
517c478bd9Sstevel@tonic-gate  *   thing to do?  What is the relationship with post-RFC2553 AI_ADDRCONFIG
527c478bd9Sstevel@tonic-gate  *   in ai_flags?
53*9525b14bSRao Shoaib  *\li  (post-2553) semantics of AI_ADDRCONFIG itself is too vague.
547c478bd9Sstevel@tonic-gate  *   (1) what should we do against numeric hostname (2) what should we do
557c478bd9Sstevel@tonic-gate  *   against NULL hostname (3) what is AI_ADDRCONFIG itself.  AF not ready?
567c478bd9Sstevel@tonic-gate  *   non-loopback address configured?  global address configured?
57*9525b14bSRao Shoaib  * \par Additional Issue:
58*9525b14bSRao Shoaib  *  To avoid search order issue, we have a big amount of code duplicate
597c478bd9Sstevel@tonic-gate  *   from gethnamaddr.c and some other places.  The issues that there's no
607c478bd9Sstevel@tonic-gate  *   lower layer function to lookup "IPv4 or IPv6" record.  Calling
617c478bd9Sstevel@tonic-gate  *   gethostbyname2 from getaddrinfo will end up in wrong search order, as
627c478bd9Sstevel@tonic-gate  *   follows:
63*9525b14bSRao Shoaib  *	\li The code makes use of following calls when asked to resolver with
647c478bd9Sstevel@tonic-gate  *	  ai_family  = PF_UNSPEC:
65*9525b14bSRao Shoaib  *\code		getipnodebyname(host, AF_INET6);
667c478bd9Sstevel@tonic-gate  *		getipnodebyname(host, AF_INET);
67*9525b14bSRao Shoaib  *\endcode
68*9525b14bSRao Shoaib  *	\li  This will result in the following queries if the node is configure to
697c478bd9Sstevel@tonic-gate  *	  prefer /etc/hosts than DNS:
70*9525b14bSRao Shoaib  *\code
717c478bd9Sstevel@tonic-gate  *		lookup /etc/hosts for IPv6 address
727c478bd9Sstevel@tonic-gate  *		lookup DNS for IPv6 address
737c478bd9Sstevel@tonic-gate  *		lookup /etc/hosts for IPv4 address
747c478bd9Sstevel@tonic-gate  *		lookup DNS for IPv4 address
75*9525b14bSRao Shoaib  *\endcode
767c478bd9Sstevel@tonic-gate  *	  which may not meet people's requirement.
77*9525b14bSRao Shoaib  *	 \li The right thing to happen is to have underlying layer which does
787c478bd9Sstevel@tonic-gate  *	  PF_UNSPEC lookup (lookup both) and return chain of addrinfos.
797c478bd9Sstevel@tonic-gate  *	  This would result in a bit of code duplicate with _dns_ghbyname() and
807c478bd9Sstevel@tonic-gate  *	  friends.
817c478bd9Sstevel@tonic-gate  */
827c478bd9Sstevel@tonic-gate 
837c478bd9Sstevel@tonic-gate #include "port_before.h"
847c478bd9Sstevel@tonic-gate 
857c478bd9Sstevel@tonic-gate #include <sys/types.h>
867c478bd9Sstevel@tonic-gate #include <sys/param.h>
877c478bd9Sstevel@tonic-gate #include <sys/socket.h>
887c478bd9Sstevel@tonic-gate 
897c478bd9Sstevel@tonic-gate #include <net/if.h>
907c478bd9Sstevel@tonic-gate #include <netinet/in.h>
917c478bd9Sstevel@tonic-gate 
927c478bd9Sstevel@tonic-gate #include <arpa/inet.h>
937c478bd9Sstevel@tonic-gate #include <arpa/nameser.h>
947c478bd9Sstevel@tonic-gate 
957c478bd9Sstevel@tonic-gate #include <netdb.h>
967c478bd9Sstevel@tonic-gate #include <resolv.h>
977c478bd9Sstevel@tonic-gate #include <string.h>
987c478bd9Sstevel@tonic-gate #include <stdlib.h>
997c478bd9Sstevel@tonic-gate #include <stddef.h>
1007c478bd9Sstevel@tonic-gate #include <ctype.h>
1017c478bd9Sstevel@tonic-gate #include <unistd.h>
1027c478bd9Sstevel@tonic-gate #include <stdio.h>
1037c478bd9Sstevel@tonic-gate #include <errno.h>
1047c478bd9Sstevel@tonic-gate 
1057c478bd9Sstevel@tonic-gate #include <stdarg.h>
1067c478bd9Sstevel@tonic-gate 
1077c478bd9Sstevel@tonic-gate #include <irs.h>
1087c478bd9Sstevel@tonic-gate #include <isc/assertions.h>
1097c478bd9Sstevel@tonic-gate 
1107c478bd9Sstevel@tonic-gate #include "port_after.h"
1117c478bd9Sstevel@tonic-gate 
1127c478bd9Sstevel@tonic-gate #include "irs_data.h"
1137c478bd9Sstevel@tonic-gate 
1147c478bd9Sstevel@tonic-gate #define SUCCESS 0
1157c478bd9Sstevel@tonic-gate #define ANY 0
1167c478bd9Sstevel@tonic-gate #define YES 1
1177c478bd9Sstevel@tonic-gate #define NO  0
1187c478bd9Sstevel@tonic-gate 
1197c478bd9Sstevel@tonic-gate static const char in_addrany[] = { 0, 0, 0, 0 };
1207c478bd9Sstevel@tonic-gate static const char in6_addrany[] = {
1217c478bd9Sstevel@tonic-gate 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
1227c478bd9Sstevel@tonic-gate };
1237c478bd9Sstevel@tonic-gate static const char in_loopback[] = { 127, 0, 0, 1 };
1247c478bd9Sstevel@tonic-gate static const char in6_loopback[] = {
1257c478bd9Sstevel@tonic-gate 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
1267c478bd9Sstevel@tonic-gate };
1277c478bd9Sstevel@tonic-gate 
1287c478bd9Sstevel@tonic-gate static const struct afd {
1297c478bd9Sstevel@tonic-gate 	int a_af;
1307c478bd9Sstevel@tonic-gate 	int a_addrlen;
1317c478bd9Sstevel@tonic-gate 	int a_socklen;
1327c478bd9Sstevel@tonic-gate 	int a_off;
1337c478bd9Sstevel@tonic-gate 	const char *a_addrany;
1347c478bd9Sstevel@tonic-gate 	const char *a_loopback;
1357c478bd9Sstevel@tonic-gate 	int a_scoped;
1367c478bd9Sstevel@tonic-gate } afdl [] = {
1377c478bd9Sstevel@tonic-gate 	{PF_INET6, sizeof(struct in6_addr),
1387c478bd9Sstevel@tonic-gate 	 sizeof(struct sockaddr_in6),
1397c478bd9Sstevel@tonic-gate 	 offsetof(struct sockaddr_in6, sin6_addr),
1407c478bd9Sstevel@tonic-gate 	 in6_addrany, in6_loopback, 1},
1417c478bd9Sstevel@tonic-gate 	{PF_INET, sizeof(struct in_addr),
1427c478bd9Sstevel@tonic-gate 	 sizeof(struct sockaddr_in),
1437c478bd9Sstevel@tonic-gate 	 offsetof(struct sockaddr_in, sin_addr),
1447c478bd9Sstevel@tonic-gate 	 in_addrany, in_loopback, 0},
1457c478bd9Sstevel@tonic-gate 	{0, 0, 0, 0, NULL, NULL, 0},
1467c478bd9Sstevel@tonic-gate };
1477c478bd9Sstevel@tonic-gate 
1487c478bd9Sstevel@tonic-gate struct explore {
1497c478bd9Sstevel@tonic-gate 	int e_af;
1507c478bd9Sstevel@tonic-gate 	int e_socktype;
1517c478bd9Sstevel@tonic-gate 	int e_protocol;
1527c478bd9Sstevel@tonic-gate 	const char *e_protostr;
1537c478bd9Sstevel@tonic-gate 	int e_wild;
1547c478bd9Sstevel@tonic-gate #define WILD_AF(ex)		((ex)->e_wild & 0x01)
1557c478bd9Sstevel@tonic-gate #define WILD_SOCKTYPE(ex)	((ex)->e_wild & 0x02)
1567c478bd9Sstevel@tonic-gate #define WILD_PROTOCOL(ex)	((ex)->e_wild & 0x04)
1577c478bd9Sstevel@tonic-gate };
1587c478bd9Sstevel@tonic-gate 
1597c478bd9Sstevel@tonic-gate static const struct explore explore[] = {
1607c478bd9Sstevel@tonic-gate #if 0
1617c478bd9Sstevel@tonic-gate 	{ PF_LOCAL, 0, ANY, ANY, NULL, 0x01 },
1627c478bd9Sstevel@tonic-gate #endif
1637c478bd9Sstevel@tonic-gate 	{ PF_INET6, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 },
1647c478bd9Sstevel@tonic-gate 	{ PF_INET6, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 },
1657c478bd9Sstevel@tonic-gate 	{ PF_INET6, SOCK_RAW, ANY, NULL, 0x05 },
1667c478bd9Sstevel@tonic-gate 	{ PF_INET, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 },
1677c478bd9Sstevel@tonic-gate 	{ PF_INET, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 },
1687c478bd9Sstevel@tonic-gate 	{ PF_INET, SOCK_RAW, ANY, NULL, 0x05 },
1697c478bd9Sstevel@tonic-gate 	{ -1, 0, 0, NULL, 0 },
1707c478bd9Sstevel@tonic-gate };
1717c478bd9Sstevel@tonic-gate 
1727c478bd9Sstevel@tonic-gate #define PTON_MAX	16
1737c478bd9Sstevel@tonic-gate 
1747c478bd9Sstevel@tonic-gate static int str_isnumber __P((const char *));
1757c478bd9Sstevel@tonic-gate static int explore_fqdn __P((const struct addrinfo *, const char *,
1767c478bd9Sstevel@tonic-gate 	const char *, struct addrinfo **));
1777c478bd9Sstevel@tonic-gate static int explore_copy __P((const struct addrinfo *, const struct addrinfo *,
1787c478bd9Sstevel@tonic-gate 	struct addrinfo **));
1797c478bd9Sstevel@tonic-gate static int explore_null __P((const struct addrinfo *,
1807c478bd9Sstevel@tonic-gate 	const char *, struct addrinfo **));
1817c478bd9Sstevel@tonic-gate static int explore_numeric __P((const struct addrinfo *, const char *,
1827c478bd9Sstevel@tonic-gate 	const char *, struct addrinfo **));
1837c478bd9Sstevel@tonic-gate static int explore_numeric_scope __P((const struct addrinfo *, const char *,
1847c478bd9Sstevel@tonic-gate 	const char *, struct addrinfo **));
1857c478bd9Sstevel@tonic-gate static int get_canonname __P((const struct addrinfo *,
1867c478bd9Sstevel@tonic-gate 	struct addrinfo *, const char *));
1877c478bd9Sstevel@tonic-gate static struct addrinfo *get_ai __P((const struct addrinfo *,
1887c478bd9Sstevel@tonic-gate 	const struct afd *, const char *));
1897c478bd9Sstevel@tonic-gate static struct addrinfo *copy_ai __P((const struct addrinfo *));
1907c478bd9Sstevel@tonic-gate static int get_portmatch __P((const struct addrinfo *, const char *));
1917c478bd9Sstevel@tonic-gate static int get_port __P((const struct addrinfo *, const char *, int));
1927c478bd9Sstevel@tonic-gate static const struct afd *find_afd __P((int));
1937c478bd9Sstevel@tonic-gate static int addrconfig __P((int));
1947c478bd9Sstevel@tonic-gate static int ip6_str2scopeid __P((char *, struct sockaddr_in6 *,
1957c478bd9Sstevel@tonic-gate 				u_int32_t *scopeidp));
1967c478bd9Sstevel@tonic-gate static struct net_data *init __P((void));
1977c478bd9Sstevel@tonic-gate 
1987c478bd9Sstevel@tonic-gate struct addrinfo *hostent2addrinfo __P((struct hostent *,
1997c478bd9Sstevel@tonic-gate 				       const struct addrinfo *));
2007c478bd9Sstevel@tonic-gate struct addrinfo *addr2addrinfo __P((const struct addrinfo *,
2017c478bd9Sstevel@tonic-gate 				    const char *));
2027c478bd9Sstevel@tonic-gate 
2037c478bd9Sstevel@tonic-gate #if 0
2047c478bd9Sstevel@tonic-gate static const char *ai_errlist[] = {
2057c478bd9Sstevel@tonic-gate 	"Success",
206*9525b14bSRao Shoaib 	"Address family for hostname not supported",	/*%< EAI_ADDRFAMILY */
207*9525b14bSRao Shoaib 	"Temporary failure in name resolution",		/*%< EAI_AGAIN */
208*9525b14bSRao Shoaib 	"Invalid value for ai_flags",		       	/*%< EAI_BADFLAGS */
209*9525b14bSRao Shoaib 	"Non-recoverable failure in name resolution", 	/*%< EAI_FAIL */
210*9525b14bSRao Shoaib 	"ai_family not supported",			/*%< EAI_FAMILY */
211*9525b14bSRao Shoaib 	"Memory allocation failure", 			/*%< EAI_MEMORY */
212*9525b14bSRao Shoaib 	"No address associated with hostname", 		/*%< EAI_NODATA */
213*9525b14bSRao Shoaib 	"hostname nor servname provided, or not known",	/*%< EAI_NONAME */
214*9525b14bSRao Shoaib 	"servname not supported for ai_socktype",	/*%< EAI_SERVICE */
215*9525b14bSRao Shoaib 	"ai_socktype not supported", 			/*%< EAI_SOCKTYPE */
216*9525b14bSRao Shoaib 	"System error returned in errno", 		/*%< EAI_SYSTEM */
217*9525b14bSRao Shoaib 	"Invalid value for hints",			/*%< EAI_BADHINTS */
218*9525b14bSRao Shoaib 	"Resolved protocol is unknown",			/*%< EAI_PROTOCOL */
219*9525b14bSRao Shoaib 	"Unknown error", 				/*%< EAI_MAX */
2207c478bd9Sstevel@tonic-gate };
2217c478bd9Sstevel@tonic-gate #endif
2227c478bd9Sstevel@tonic-gate 
2237c478bd9Sstevel@tonic-gate /* XXX macros that make external reference is BAD. */
2247c478bd9Sstevel@tonic-gate 
2257c478bd9Sstevel@tonic-gate #define GET_AI(ai, afd, addr) \
2267c478bd9Sstevel@tonic-gate do { \
2277c478bd9Sstevel@tonic-gate 	/* external reference: pai, error, and label free */ \
2287c478bd9Sstevel@tonic-gate 	(ai) = get_ai(pai, (afd), (addr)); \
2297c478bd9Sstevel@tonic-gate 	if ((ai) == NULL) { \
2307c478bd9Sstevel@tonic-gate 		error = EAI_MEMORY; \
2317c478bd9Sstevel@tonic-gate 		goto free; \
2327c478bd9Sstevel@tonic-gate 	} \
2337c478bd9Sstevel@tonic-gate } while (/*CONSTCOND*/0)
2347c478bd9Sstevel@tonic-gate 
2357c478bd9Sstevel@tonic-gate #define GET_PORT(ai, serv) \
2367c478bd9Sstevel@tonic-gate do { \
2377c478bd9Sstevel@tonic-gate 	/* external reference: error and label free */ \
2387c478bd9Sstevel@tonic-gate 	error = get_port((ai), (serv), 0); \
2397c478bd9Sstevel@tonic-gate 	if (error != 0) \
2407c478bd9Sstevel@tonic-gate 		goto free; \
2417c478bd9Sstevel@tonic-gate } while (/*CONSTCOND*/0)
2427c478bd9Sstevel@tonic-gate 
2437c478bd9Sstevel@tonic-gate #define GET_CANONNAME(ai, str) \
2447c478bd9Sstevel@tonic-gate do { \
2457c478bd9Sstevel@tonic-gate 	/* external reference: pai, error and label free */ \
2467c478bd9Sstevel@tonic-gate 	error = get_canonname(pai, (ai), (str)); \
2477c478bd9Sstevel@tonic-gate 	if (error != 0) \
2487c478bd9Sstevel@tonic-gate 		goto free; \
2497c478bd9Sstevel@tonic-gate } while (/*CONSTCOND*/0)
2507c478bd9Sstevel@tonic-gate 
251*9525b14bSRao Shoaib #ifndef SOLARIS2
252*9525b14bSRao Shoaib #define SETERROR(err) \
2537c478bd9Sstevel@tonic-gate do { \
2547c478bd9Sstevel@tonic-gate 	/* external reference: error, and label bad */ \
2557c478bd9Sstevel@tonic-gate 	error = (err); \
2567c478bd9Sstevel@tonic-gate 	goto bad; \
2577c478bd9Sstevel@tonic-gate 	/*NOTREACHED*/ \
2587c478bd9Sstevel@tonic-gate } while (/*CONSTCOND*/0)
2597c478bd9Sstevel@tonic-gate #else
260*9525b14bSRao Shoaib #define SETERROR(err) \
2617c478bd9Sstevel@tonic-gate do { \
262*9525b14bSRao Shoaib 	/* external reference: error, and label bad */ \
2637c478bd9Sstevel@tonic-gate 	error = (err); \
264*9525b14bSRao Shoaib 	if (error == error) \
265*9525b14bSRao Shoaib 		goto bad; \
2667c478bd9Sstevel@tonic-gate } while (/*CONSTCOND*/0)
2677c478bd9Sstevel@tonic-gate #endif
2687c478bd9Sstevel@tonic-gate 
269*9525b14bSRao Shoaib 
2707c478bd9Sstevel@tonic-gate #define MATCH_FAMILY(x, y, w) \
2717c478bd9Sstevel@tonic-gate 	((x) == (y) || (/*CONSTCOND*/(w) && ((x) == PF_UNSPEC || (y) == PF_UNSPEC)))
2727c478bd9Sstevel@tonic-gate #define MATCH(x, y, w) \
2737c478bd9Sstevel@tonic-gate 	((x) == (y) || (/*CONSTCOND*/(w) && ((x) == ANY || (y) == ANY)))
2747c478bd9Sstevel@tonic-gate 
275*9525b14bSRao Shoaib #if 0				/*%< bind8 has its own version */
2767c478bd9Sstevel@tonic-gate char *
2777c478bd9Sstevel@tonic-gate gai_strerror(ecode)
2787c478bd9Sstevel@tonic-gate 	int ecode;
2797c478bd9Sstevel@tonic-gate {
2807c478bd9Sstevel@tonic-gate 	if (ecode < 0 || ecode > EAI_MAX)
2817c478bd9Sstevel@tonic-gate 		ecode = EAI_MAX;
2827c478bd9Sstevel@tonic-gate 	return ai_errlist[ecode];
2837c478bd9Sstevel@tonic-gate }
2847c478bd9Sstevel@tonic-gate #endif
2857c478bd9Sstevel@tonic-gate 
2867c478bd9Sstevel@tonic-gate void
freeaddrinfo(ai)2877c478bd9Sstevel@tonic-gate freeaddrinfo(ai)
2887c478bd9Sstevel@tonic-gate 	struct addrinfo *ai;
2897c478bd9Sstevel@tonic-gate {
2907c478bd9Sstevel@tonic-gate 	struct addrinfo *next;
2917c478bd9Sstevel@tonic-gate 
2927c478bd9Sstevel@tonic-gate 	do {
2937c478bd9Sstevel@tonic-gate 		next = ai->ai_next;
2947c478bd9Sstevel@tonic-gate 		if (ai->ai_canonname)
2957c478bd9Sstevel@tonic-gate 			free(ai->ai_canonname);
2967c478bd9Sstevel@tonic-gate 		/* no need to free(ai->ai_addr) */
2977c478bd9Sstevel@tonic-gate 		free(ai);
2987c478bd9Sstevel@tonic-gate 		ai = next;
2997c478bd9Sstevel@tonic-gate 	} while (ai);
3007c478bd9Sstevel@tonic-gate }
3017c478bd9Sstevel@tonic-gate 
3027c478bd9Sstevel@tonic-gate static int
str_isnumber(p)3037c478bd9Sstevel@tonic-gate str_isnumber(p)
3047c478bd9Sstevel@tonic-gate 	const char *p;
3057c478bd9Sstevel@tonic-gate {
3067c478bd9Sstevel@tonic-gate 	char *ep;
3077c478bd9Sstevel@tonic-gate 
3087c478bd9Sstevel@tonic-gate 	if (*p == '\0')
3097c478bd9Sstevel@tonic-gate 		return NO;
3107c478bd9Sstevel@tonic-gate 	ep = NULL;
3117c478bd9Sstevel@tonic-gate 	errno = 0;
3127c478bd9Sstevel@tonic-gate 	(void)strtoul(p, &ep, 10);
3137c478bd9Sstevel@tonic-gate 	if (errno == 0 && ep && *ep == '\0')
3147c478bd9Sstevel@tonic-gate 		return YES;
3157c478bd9Sstevel@tonic-gate 	else
3167c478bd9Sstevel@tonic-gate 		return NO;
3177c478bd9Sstevel@tonic-gate }
3187c478bd9Sstevel@tonic-gate 
3197c478bd9Sstevel@tonic-gate int
getaddrinfo(hostname,servname,hints,res)3207c478bd9Sstevel@tonic-gate getaddrinfo(hostname, servname, hints, res)
3217c478bd9Sstevel@tonic-gate 	const char *hostname, *servname;
3227c478bd9Sstevel@tonic-gate 	const struct addrinfo *hints;
3237c478bd9Sstevel@tonic-gate 	struct addrinfo **res;
3247c478bd9Sstevel@tonic-gate {
3257c478bd9Sstevel@tonic-gate 	struct addrinfo sentinel;
3267c478bd9Sstevel@tonic-gate 	struct addrinfo *cur;
3277c478bd9Sstevel@tonic-gate 	int error = 0;
3287c478bd9Sstevel@tonic-gate 	struct addrinfo ai, ai0, *afai = NULL;
3297c478bd9Sstevel@tonic-gate 	struct addrinfo *pai;
3307c478bd9Sstevel@tonic-gate 	const struct explore *ex;
3317c478bd9Sstevel@tonic-gate 
3327c478bd9Sstevel@tonic-gate 	memset(&sentinel, 0, sizeof(sentinel));
3337c478bd9Sstevel@tonic-gate 	cur = &sentinel;
3347c478bd9Sstevel@tonic-gate 	pai = &ai;
3357c478bd9Sstevel@tonic-gate 	pai->ai_flags = 0;
3367c478bd9Sstevel@tonic-gate 	pai->ai_family = PF_UNSPEC;
3377c478bd9Sstevel@tonic-gate 	pai->ai_socktype = ANY;
3387c478bd9Sstevel@tonic-gate 	pai->ai_protocol = ANY;
339*9525b14bSRao Shoaib #if defined(sun) && defined(_SOCKLEN_T) && defined(__sparcv9)
3407c478bd9Sstevel@tonic-gate 	/*
341*9525b14bSRao Shoaib 	 * clear _ai_pad to preserve binary
3427c478bd9Sstevel@tonic-gate 	 * compatibility with previously compiled 64-bit
3437c478bd9Sstevel@tonic-gate 	 * applications in a pre-SUSv3 environment by
3447c478bd9Sstevel@tonic-gate 	 * guaranteeing the upper 32-bits are empty.
3457c478bd9Sstevel@tonic-gate 	 */
3467c478bd9Sstevel@tonic-gate 	pai->_ai_pad = 0;
347*9525b14bSRao Shoaib #endif
3487c478bd9Sstevel@tonic-gate 	pai->ai_addrlen = 0;
3497c478bd9Sstevel@tonic-gate 	pai->ai_canonname = NULL;
3507c478bd9Sstevel@tonic-gate 	pai->ai_addr = NULL;
3517c478bd9Sstevel@tonic-gate 	pai->ai_next = NULL;
3527c478bd9Sstevel@tonic-gate 
3537c478bd9Sstevel@tonic-gate 	if (hostname == NULL && servname == NULL)
3547c478bd9Sstevel@tonic-gate 		return EAI_NONAME;
3557c478bd9Sstevel@tonic-gate 	if (hints) {
3567c478bd9Sstevel@tonic-gate 		/* error check for hints */
3577c478bd9Sstevel@tonic-gate 		if (hints->ai_addrlen || hints->ai_canonname ||
358*9525b14bSRao Shoaib 		    hints->ai_addr || hints->ai_next)
359*9525b14bSRao Shoaib 			SETERROR(EAI_BADHINTS); /*%< xxx */
360*9525b14bSRao Shoaib 		if (hints->ai_flags & ~AI_MASK)
361*9525b14bSRao Shoaib 			SETERROR(EAI_BADFLAGS);
3627c478bd9Sstevel@tonic-gate 		switch (hints->ai_family) {
3637c478bd9Sstevel@tonic-gate 		case PF_UNSPEC:
3647c478bd9Sstevel@tonic-gate 		case PF_INET:
3657c478bd9Sstevel@tonic-gate 		case PF_INET6:
3667c478bd9Sstevel@tonic-gate 			break;
3677c478bd9Sstevel@tonic-gate 		default:
368*9525b14bSRao Shoaib 			SETERROR(EAI_FAMILY);
3697c478bd9Sstevel@tonic-gate 		}
3707c478bd9Sstevel@tonic-gate 		memcpy(pai, hints, sizeof(*pai));
3717c478bd9Sstevel@tonic-gate 
372*9525b14bSRao Shoaib #if defined(sun) && defined(_SOCKLEN_T) && defined(__sparcv9)
3737c478bd9Sstevel@tonic-gate 		/*
3747c478bd9Sstevel@tonic-gate 		 * We need to clear _ai_pad to preserve binary
3757c478bd9Sstevel@tonic-gate 		 * compatibility.  See prior comment.
3767c478bd9Sstevel@tonic-gate 		 */
3777c478bd9Sstevel@tonic-gate 		pai->_ai_pad = 0;
378*9525b14bSRao Shoaib #endif
3797c478bd9Sstevel@tonic-gate 		/*
3807c478bd9Sstevel@tonic-gate 		 * if both socktype/protocol are specified, check if they
3817c478bd9Sstevel@tonic-gate 		 * are meaningful combination.
3827c478bd9Sstevel@tonic-gate 		 */
3837c478bd9Sstevel@tonic-gate 		if (pai->ai_socktype != ANY && pai->ai_protocol != ANY) {
3847c478bd9Sstevel@tonic-gate 			for (ex = explore; ex->e_af >= 0; ex++) {
3857c478bd9Sstevel@tonic-gate 				if (pai->ai_family != ex->e_af)
3867c478bd9Sstevel@tonic-gate 					continue;
3877c478bd9Sstevel@tonic-gate 				if (ex->e_socktype == ANY)
3887c478bd9Sstevel@tonic-gate 					continue;
3897c478bd9Sstevel@tonic-gate 				if (ex->e_protocol == ANY)
3907c478bd9Sstevel@tonic-gate 					continue;
3917c478bd9Sstevel@tonic-gate 				if (pai->ai_socktype == ex->e_socktype &&
3927c478bd9Sstevel@tonic-gate 				    pai->ai_protocol != ex->e_protocol) {
393*9525b14bSRao Shoaib 					SETERROR(EAI_BADHINTS);
3947c478bd9Sstevel@tonic-gate 				}
3957c478bd9Sstevel@tonic-gate 			}
3967c478bd9Sstevel@tonic-gate 		}
3977c478bd9Sstevel@tonic-gate 	}
3987c478bd9Sstevel@tonic-gate 
3997c478bd9Sstevel@tonic-gate 	/*
4007c478bd9Sstevel@tonic-gate 	 * post-2553: AI_ALL and AI_V4MAPPED are effective only against
4017c478bd9Sstevel@tonic-gate 	 * AF_INET6 query.  They needs to be ignored if specified in other
4027c478bd9Sstevel@tonic-gate 	 * occassions.
4037c478bd9Sstevel@tonic-gate 	 */
4047c478bd9Sstevel@tonic-gate 	switch (pai->ai_flags & (AI_ALL | AI_V4MAPPED)) {
4057c478bd9Sstevel@tonic-gate 	case AI_V4MAPPED:
4067c478bd9Sstevel@tonic-gate 	case AI_ALL | AI_V4MAPPED:
4077c478bd9Sstevel@tonic-gate 		if (pai->ai_family != AF_INET6)
4087c478bd9Sstevel@tonic-gate 			pai->ai_flags &= ~(AI_ALL | AI_V4MAPPED);
4097c478bd9Sstevel@tonic-gate 		break;
4107c478bd9Sstevel@tonic-gate 	case AI_ALL:
4117c478bd9Sstevel@tonic-gate #if 1
4127c478bd9Sstevel@tonic-gate 		/* illegal */
413*9525b14bSRao Shoaib 		SETERROR(EAI_BADFLAGS);
4147c478bd9Sstevel@tonic-gate #else
4157c478bd9Sstevel@tonic-gate 		pai->ai_flags &= ~(AI_ALL | AI_V4MAPPED);
4167c478bd9Sstevel@tonic-gate 		break;
4177c478bd9Sstevel@tonic-gate #endif
4187c478bd9Sstevel@tonic-gate 	}
4197c478bd9Sstevel@tonic-gate 
4207c478bd9Sstevel@tonic-gate 	/*
4217c478bd9Sstevel@tonic-gate 	 * check for special cases.  (1) numeric servname is disallowed if
4227c478bd9Sstevel@tonic-gate 	 * socktype/protocol are left unspecified. (2) servname is disallowed
4237c478bd9Sstevel@tonic-gate 	 * for raw and other inet{,6} sockets.
4247c478bd9Sstevel@tonic-gate 	 */
4257c478bd9Sstevel@tonic-gate 	if (MATCH_FAMILY(pai->ai_family, PF_INET, 1)
4267c478bd9Sstevel@tonic-gate #ifdef PF_INET6
4277c478bd9Sstevel@tonic-gate 	 || MATCH_FAMILY(pai->ai_family, PF_INET6, 1)
4287c478bd9Sstevel@tonic-gate #endif
4297c478bd9Sstevel@tonic-gate 	    ) {
4307c478bd9Sstevel@tonic-gate 		ai0 = *pai;	/* backup *pai */
4317c478bd9Sstevel@tonic-gate 
4327c478bd9Sstevel@tonic-gate 		if (pai->ai_family == PF_UNSPEC) {
4337c478bd9Sstevel@tonic-gate #ifdef PF_INET6
4347c478bd9Sstevel@tonic-gate 			pai->ai_family = PF_INET6;
4357c478bd9Sstevel@tonic-gate #else
4367c478bd9Sstevel@tonic-gate 			pai->ai_family = PF_INET;
4377c478bd9Sstevel@tonic-gate #endif
4387c478bd9Sstevel@tonic-gate 		}
4397c478bd9Sstevel@tonic-gate 		error = get_portmatch(pai, servname);
440*9525b14bSRao Shoaib 		if (error)
441*9525b14bSRao Shoaib 			SETERROR(error);
4427c478bd9Sstevel@tonic-gate 
4437c478bd9Sstevel@tonic-gate 		*pai = ai0;
4447c478bd9Sstevel@tonic-gate 	}
4457c478bd9Sstevel@tonic-gate 
4467c478bd9Sstevel@tonic-gate 	ai0 = *pai;
4477c478bd9Sstevel@tonic-gate 
4487c478bd9Sstevel@tonic-gate 	/* NULL hostname, or numeric hostname */
4497c478bd9Sstevel@tonic-gate 	for (ex = explore; ex->e_af >= 0; ex++) {
4507c478bd9Sstevel@tonic-gate 		*pai = ai0;
4517c478bd9Sstevel@tonic-gate 
4527c478bd9Sstevel@tonic-gate 		if (!MATCH_FAMILY(pai->ai_family, ex->e_af, WILD_AF(ex)))
4537c478bd9Sstevel@tonic-gate 			continue;
4547c478bd9Sstevel@tonic-gate 		if (!MATCH(pai->ai_socktype, ex->e_socktype, WILD_SOCKTYPE(ex)))
4557c478bd9Sstevel@tonic-gate 			continue;
4567c478bd9Sstevel@tonic-gate 		if (!MATCH(pai->ai_protocol, ex->e_protocol, WILD_PROTOCOL(ex)))
4577c478bd9Sstevel@tonic-gate 			continue;
4587c478bd9Sstevel@tonic-gate 
4597c478bd9Sstevel@tonic-gate 		if (pai->ai_family == PF_UNSPEC)
4607c478bd9Sstevel@tonic-gate 			pai->ai_family = ex->e_af;
4617c478bd9Sstevel@tonic-gate 		if (pai->ai_socktype == ANY && ex->e_socktype != ANY)
4627c478bd9Sstevel@tonic-gate 			pai->ai_socktype = ex->e_socktype;
4637c478bd9Sstevel@tonic-gate 		if (pai->ai_protocol == ANY && ex->e_protocol != ANY)
4647c478bd9Sstevel@tonic-gate 			pai->ai_protocol = ex->e_protocol;
4657c478bd9Sstevel@tonic-gate 
4667c478bd9Sstevel@tonic-gate 		/*
4677c478bd9Sstevel@tonic-gate 		 * if the servname does not match socktype/protocol, ignore it.
4687c478bd9Sstevel@tonic-gate 		 */
4697c478bd9Sstevel@tonic-gate 		if (get_portmatch(pai, servname) != 0)
4707c478bd9Sstevel@tonic-gate 			continue;
4717c478bd9Sstevel@tonic-gate 
4727c478bd9Sstevel@tonic-gate 		if (hostname == NULL) {
4737c478bd9Sstevel@tonic-gate 			/*
4747c478bd9Sstevel@tonic-gate 			 * filter out AFs that are not supported by the kernel
4757c478bd9Sstevel@tonic-gate 			 * XXX errno?
4767c478bd9Sstevel@tonic-gate 			 */
4777c478bd9Sstevel@tonic-gate 			if (!addrconfig(pai->ai_family))
4787c478bd9Sstevel@tonic-gate 				continue;
4797c478bd9Sstevel@tonic-gate 			error = explore_null(pai, servname, &cur->ai_next);
4807c478bd9Sstevel@tonic-gate 		} else
4817c478bd9Sstevel@tonic-gate 			error = explore_numeric_scope(pai, hostname, servname,
4827c478bd9Sstevel@tonic-gate 			    &cur->ai_next);
4837c478bd9Sstevel@tonic-gate 
4847c478bd9Sstevel@tonic-gate 		if (error)
4857c478bd9Sstevel@tonic-gate 			goto free;
4867c478bd9Sstevel@tonic-gate 
4877c478bd9Sstevel@tonic-gate 		while (cur && cur->ai_next)
4887c478bd9Sstevel@tonic-gate 			cur = cur->ai_next;
4897c478bd9Sstevel@tonic-gate 	}
4907c478bd9Sstevel@tonic-gate 
4917c478bd9Sstevel@tonic-gate 	/*
4927c478bd9Sstevel@tonic-gate 	 * XXX
4937c478bd9Sstevel@tonic-gate 	 * If numreic representation of AF1 can be interpreted as FQDN
4947c478bd9Sstevel@tonic-gate 	 * representation of AF2, we need to think again about the code below.
4957c478bd9Sstevel@tonic-gate 	 */
4967c478bd9Sstevel@tonic-gate 	if (sentinel.ai_next)
4977c478bd9Sstevel@tonic-gate 		goto good;
4987c478bd9Sstevel@tonic-gate 
499*9525b14bSRao Shoaib 	if (pai->ai_flags & AI_NUMERICHOST)
500*9525b14bSRao Shoaib 		SETERROR(EAI_NONAME);
501*9525b14bSRao Shoaib 	if (hostname == NULL)
502*9525b14bSRao Shoaib 		SETERROR(EAI_NONAME);
5037c478bd9Sstevel@tonic-gate 
5047c478bd9Sstevel@tonic-gate 	/*
5057c478bd9Sstevel@tonic-gate 	 * hostname as alphabetical name.
5067c478bd9Sstevel@tonic-gate 	 * We'll make sure that
5077c478bd9Sstevel@tonic-gate 	 * - if returning addrinfo list is empty, return non-zero error
5087c478bd9Sstevel@tonic-gate 	 *   value (already known one or EAI_NONAME).
5097c478bd9Sstevel@tonic-gate 	 * - otherwise,
5107c478bd9Sstevel@tonic-gate 	 *   + if we haven't had any errors, return 0 (i.e. success).
5117c478bd9Sstevel@tonic-gate 	 *   + if we've had an error, free the list and return the error.
5127c478bd9Sstevel@tonic-gate 	 * without any assumption on the behavior of explore_fqdn().
5137c478bd9Sstevel@tonic-gate 	 */
5147c478bd9Sstevel@tonic-gate 
5157c478bd9Sstevel@tonic-gate 	/* first, try to query DNS for all possible address families. */
5167c478bd9Sstevel@tonic-gate 	*pai = ai0;
5177c478bd9Sstevel@tonic-gate 	error = explore_fqdn(pai, hostname, servname, &afai);
5187c478bd9Sstevel@tonic-gate 	if (error) {
5197c478bd9Sstevel@tonic-gate 		if (afai != NULL)
5207c478bd9Sstevel@tonic-gate 			freeaddrinfo(afai);
5217c478bd9Sstevel@tonic-gate 		goto free;
5227c478bd9Sstevel@tonic-gate 	}
5237c478bd9Sstevel@tonic-gate 	if (afai == NULL) {
524*9525b14bSRao Shoaib 		error = EAI_NONAME; /*%< we've had no errors. */
5257c478bd9Sstevel@tonic-gate 		goto free;
5267c478bd9Sstevel@tonic-gate 	}
5277c478bd9Sstevel@tonic-gate 
5287c478bd9Sstevel@tonic-gate 	/*
5297c478bd9Sstevel@tonic-gate 	 * we would like to prefer AF_INET6 than AF_INET, so we'll make an
5307c478bd9Sstevel@tonic-gate 	 * outer loop by AFs.
5317c478bd9Sstevel@tonic-gate 	 */
5327c478bd9Sstevel@tonic-gate 	for (ex = explore; ex->e_af >= 0; ex++) {
5337c478bd9Sstevel@tonic-gate 		*pai = ai0;
5347c478bd9Sstevel@tonic-gate 
5357c478bd9Sstevel@tonic-gate 		if (pai->ai_family == PF_UNSPEC)
5367c478bd9Sstevel@tonic-gate 			pai->ai_family = ex->e_af;
5377c478bd9Sstevel@tonic-gate 
5387c478bd9Sstevel@tonic-gate 		if (!MATCH_FAMILY(pai->ai_family, ex->e_af, WILD_AF(ex)))
5397c478bd9Sstevel@tonic-gate 			continue;
5407c478bd9Sstevel@tonic-gate 		if (!MATCH(pai->ai_socktype, ex->e_socktype,
5417c478bd9Sstevel@tonic-gate 			   WILD_SOCKTYPE(ex))) {
5427c478bd9Sstevel@tonic-gate 			continue;
5437c478bd9Sstevel@tonic-gate 		}
5447c478bd9Sstevel@tonic-gate 		if (!MATCH(pai->ai_protocol, ex->e_protocol,
5457c478bd9Sstevel@tonic-gate 			   WILD_PROTOCOL(ex))) {
5467c478bd9Sstevel@tonic-gate 			continue;
5477c478bd9Sstevel@tonic-gate 		}
5487c478bd9Sstevel@tonic-gate 
5497c478bd9Sstevel@tonic-gate #ifdef AI_ADDRCONFIG
5507c478bd9Sstevel@tonic-gate 		/*
5517c478bd9Sstevel@tonic-gate 		 * If AI_ADDRCONFIG is specified, check if we are
5527c478bd9Sstevel@tonic-gate 		 * expected to return the address family or not.
5537c478bd9Sstevel@tonic-gate 		 */
5547c478bd9Sstevel@tonic-gate 		if ((pai->ai_flags & AI_ADDRCONFIG) != 0 &&
5557c478bd9Sstevel@tonic-gate 		    !addrconfig(pai->ai_family))
5567c478bd9Sstevel@tonic-gate 			continue;
5577c478bd9Sstevel@tonic-gate #endif
5587c478bd9Sstevel@tonic-gate 
5597c478bd9Sstevel@tonic-gate 		if (pai->ai_family == PF_UNSPEC)
5607c478bd9Sstevel@tonic-gate 			pai->ai_family = ex->e_af;
5617c478bd9Sstevel@tonic-gate 		if (pai->ai_socktype == ANY && ex->e_socktype != ANY)
5627c478bd9Sstevel@tonic-gate 			pai->ai_socktype = ex->e_socktype;
5637c478bd9Sstevel@tonic-gate 		if (pai->ai_protocol == ANY && ex->e_protocol != ANY)
5647c478bd9Sstevel@tonic-gate 			pai->ai_protocol = ex->e_protocol;
5657c478bd9Sstevel@tonic-gate 
5667c478bd9Sstevel@tonic-gate 		/*
5677c478bd9Sstevel@tonic-gate 		 * if the servname does not match socktype/protocol, ignore it.
5687c478bd9Sstevel@tonic-gate 		 */
5697c478bd9Sstevel@tonic-gate 		if (get_portmatch(pai, servname) != 0)
5707c478bd9Sstevel@tonic-gate 			continue;
5717c478bd9Sstevel@tonic-gate 
5727c478bd9Sstevel@tonic-gate 		if ((error = explore_copy(pai, afai, &cur->ai_next)) != 0) {
5737c478bd9Sstevel@tonic-gate 			freeaddrinfo(afai);
5747c478bd9Sstevel@tonic-gate 			goto free;
5757c478bd9Sstevel@tonic-gate 		}
5767c478bd9Sstevel@tonic-gate 
5777c478bd9Sstevel@tonic-gate 		while (cur && cur->ai_next)
5787c478bd9Sstevel@tonic-gate 			cur = cur->ai_next;
5797c478bd9Sstevel@tonic-gate 	}
5807c478bd9Sstevel@tonic-gate 
581*9525b14bSRao Shoaib 	freeaddrinfo(afai);	/*%< afai must not be NULL at this point. */
5827c478bd9Sstevel@tonic-gate 
5837c478bd9Sstevel@tonic-gate 	if (sentinel.ai_next) {
5847c478bd9Sstevel@tonic-gate good:
5857c478bd9Sstevel@tonic-gate 		*res = sentinel.ai_next;
5867c478bd9Sstevel@tonic-gate 		return(SUCCESS);
5877c478bd9Sstevel@tonic-gate 	} else {
5887c478bd9Sstevel@tonic-gate 		/*
5897c478bd9Sstevel@tonic-gate 		 * All the process succeeded, but we've had an empty list.
5907c478bd9Sstevel@tonic-gate 		 * This can happen if the given hints do not match our
5917c478bd9Sstevel@tonic-gate 		 * candidates.
5927c478bd9Sstevel@tonic-gate 		 */
5937c478bd9Sstevel@tonic-gate 		error = EAI_NONAME;
5947c478bd9Sstevel@tonic-gate 	}
5957c478bd9Sstevel@tonic-gate 
5967c478bd9Sstevel@tonic-gate free:
5977c478bd9Sstevel@tonic-gate bad:
5987c478bd9Sstevel@tonic-gate 	if (sentinel.ai_next)
5997c478bd9Sstevel@tonic-gate 		freeaddrinfo(sentinel.ai_next);
6007c478bd9Sstevel@tonic-gate 	*res = NULL;
6017c478bd9Sstevel@tonic-gate 	return(error);
6027c478bd9Sstevel@tonic-gate }
6037c478bd9Sstevel@tonic-gate 
604*9525b14bSRao Shoaib /*%
6057c478bd9Sstevel@tonic-gate  * FQDN hostname, DNS lookup
6067c478bd9Sstevel@tonic-gate  */
6077c478bd9Sstevel@tonic-gate static int
explore_fqdn(pai,hostname,servname,res)6087c478bd9Sstevel@tonic-gate explore_fqdn(pai, hostname, servname, res)
6097c478bd9Sstevel@tonic-gate 	const struct addrinfo *pai;
6107c478bd9Sstevel@tonic-gate 	const char *hostname;
6117c478bd9Sstevel@tonic-gate 	const char *servname;
6127c478bd9Sstevel@tonic-gate 	struct addrinfo **res;
6137c478bd9Sstevel@tonic-gate {
6147c478bd9Sstevel@tonic-gate 	struct addrinfo *result;
6157c478bd9Sstevel@tonic-gate 	struct addrinfo *cur;
6167c478bd9Sstevel@tonic-gate 	struct net_data *net_data = init();
6177c478bd9Sstevel@tonic-gate 	struct irs_ho *ho;
6187c478bd9Sstevel@tonic-gate 	int error = 0;
6197c478bd9Sstevel@tonic-gate 	char tmp[NS_MAXDNAME];
6207c478bd9Sstevel@tonic-gate 	const char *cp;
6217c478bd9Sstevel@tonic-gate 
6227c478bd9Sstevel@tonic-gate 	INSIST(res != NULL && *res == NULL);
6237c478bd9Sstevel@tonic-gate 
6247c478bd9Sstevel@tonic-gate 	/*
6257c478bd9Sstevel@tonic-gate 	 * if the servname does not match socktype/protocol, ignore it.
6267c478bd9Sstevel@tonic-gate 	 */
6277c478bd9Sstevel@tonic-gate 	if (get_portmatch(pai, servname) != 0)
6287c478bd9Sstevel@tonic-gate 		return(0);
6297c478bd9Sstevel@tonic-gate 
6307c478bd9Sstevel@tonic-gate 	if (!net_data || !(ho = net_data->ho))
6317c478bd9Sstevel@tonic-gate 		return(0);
632*9525b14bSRao Shoaib #if 0				/*%< XXX (notyet) */
6337c478bd9Sstevel@tonic-gate 	if (net_data->ho_stayopen && net_data->ho_last &&
6347c478bd9Sstevel@tonic-gate 	    net_data->ho_last->h_addrtype == af) {
6357c478bd9Sstevel@tonic-gate 		if (ns_samename(name, net_data->ho_last->h_name) == 1)
6367c478bd9Sstevel@tonic-gate 			return (net_data->ho_last);
6377c478bd9Sstevel@tonic-gate 		for (hap = net_data->ho_last->h_aliases; hap && *hap; hap++)
6387c478bd9Sstevel@tonic-gate 			if (ns_samename(name, *hap) == 1)
6397c478bd9Sstevel@tonic-gate 				return (net_data->ho_last);
6407c478bd9Sstevel@tonic-gate 	}
6417c478bd9Sstevel@tonic-gate #endif
6427c478bd9Sstevel@tonic-gate 	if (!strchr(hostname, '.') &&
6437c478bd9Sstevel@tonic-gate 	    (cp = res_hostalias(net_data->res, hostname,
6447c478bd9Sstevel@tonic-gate 				tmp, sizeof(tmp))))
6457c478bd9Sstevel@tonic-gate 		hostname = cp;
6467c478bd9Sstevel@tonic-gate 	result = (*ho->addrinfo)(ho, hostname, pai);
6477c478bd9Sstevel@tonic-gate 	if (!net_data->ho_stayopen) {
6487c478bd9Sstevel@tonic-gate 		(*ho->minimize)(ho);
6497c478bd9Sstevel@tonic-gate 	}
6507c478bd9Sstevel@tonic-gate 	if (result == NULL) {
6517c478bd9Sstevel@tonic-gate 		int e = h_errno;
6527c478bd9Sstevel@tonic-gate 
6537c478bd9Sstevel@tonic-gate 		switch(e) {
6547c478bd9Sstevel@tonic-gate 		case NETDB_INTERNAL:
6557c478bd9Sstevel@tonic-gate 			error = EAI_SYSTEM;
6567c478bd9Sstevel@tonic-gate 			break;
6577c478bd9Sstevel@tonic-gate 		case TRY_AGAIN:
6587c478bd9Sstevel@tonic-gate 			error = EAI_AGAIN;
6597c478bd9Sstevel@tonic-gate 			break;
6607c478bd9Sstevel@tonic-gate 		case NO_RECOVERY:
6617c478bd9Sstevel@tonic-gate 			error = EAI_FAIL;
6627c478bd9Sstevel@tonic-gate 			break;
6637c478bd9Sstevel@tonic-gate 		case HOST_NOT_FOUND:
6647c478bd9Sstevel@tonic-gate 		case NO_DATA:
6657c478bd9Sstevel@tonic-gate 			error = EAI_NONAME;
6667c478bd9Sstevel@tonic-gate 			break;
6677c478bd9Sstevel@tonic-gate 		default:
668*9525b14bSRao Shoaib 		case NETDB_SUCCESS: /*%< should be impossible... */
6697c478bd9Sstevel@tonic-gate 			error = EAI_NONAME;
6707c478bd9Sstevel@tonic-gate 			break;
6717c478bd9Sstevel@tonic-gate 		}
6727c478bd9Sstevel@tonic-gate 		goto free;
6737c478bd9Sstevel@tonic-gate 	}
6747c478bd9Sstevel@tonic-gate 
6757c478bd9Sstevel@tonic-gate 	for (cur = result; cur; cur = cur->ai_next) {
676*9525b14bSRao Shoaib 		GET_PORT(cur, servname); /*%< XXX: redundant lookups... */
6777c478bd9Sstevel@tonic-gate 		/* canonname should already be filled. */
6787c478bd9Sstevel@tonic-gate 	}
6797c478bd9Sstevel@tonic-gate 
6807c478bd9Sstevel@tonic-gate 	*res = result;
6817c478bd9Sstevel@tonic-gate 
6827c478bd9Sstevel@tonic-gate 	return(0);
6837c478bd9Sstevel@tonic-gate 
6847c478bd9Sstevel@tonic-gate free:
6857c478bd9Sstevel@tonic-gate 	if (result)
6867c478bd9Sstevel@tonic-gate 		freeaddrinfo(result);
6877c478bd9Sstevel@tonic-gate 	return error;
6887c478bd9Sstevel@tonic-gate }
6897c478bd9Sstevel@tonic-gate 
6907c478bd9Sstevel@tonic-gate static int
explore_copy(pai,src0,res)6917c478bd9Sstevel@tonic-gate explore_copy(pai, src0, res)
692*9525b14bSRao Shoaib 	const struct addrinfo *pai;	/*%< seed */
693*9525b14bSRao Shoaib 	const struct addrinfo *src0;	/*%< source */
6947c478bd9Sstevel@tonic-gate 	struct addrinfo **res;
6957c478bd9Sstevel@tonic-gate {
6967c478bd9Sstevel@tonic-gate 	int error;
6977c478bd9Sstevel@tonic-gate 	struct addrinfo sentinel, *cur;
6987c478bd9Sstevel@tonic-gate 	const struct addrinfo *src;
6997c478bd9Sstevel@tonic-gate 
7007c478bd9Sstevel@tonic-gate 	error = 0;
7017c478bd9Sstevel@tonic-gate 	sentinel.ai_next = NULL;
7027c478bd9Sstevel@tonic-gate 	cur = &sentinel;
7037c478bd9Sstevel@tonic-gate 
7047c478bd9Sstevel@tonic-gate 	for (src = src0; src != NULL; src = src->ai_next) {
7057c478bd9Sstevel@tonic-gate 		if (src->ai_family != pai->ai_family)
7067c478bd9Sstevel@tonic-gate 			continue;
7077c478bd9Sstevel@tonic-gate 
7087c478bd9Sstevel@tonic-gate 		cur->ai_next = copy_ai(src);
7097c478bd9Sstevel@tonic-gate 		if (!cur->ai_next) {
7107c478bd9Sstevel@tonic-gate 			error = EAI_MEMORY;
7117c478bd9Sstevel@tonic-gate 			goto fail;
7127c478bd9Sstevel@tonic-gate 		}
7137c478bd9Sstevel@tonic-gate 
7147c478bd9Sstevel@tonic-gate 		cur->ai_next->ai_socktype = pai->ai_socktype;
7157c478bd9Sstevel@tonic-gate 		cur->ai_next->ai_protocol = pai->ai_protocol;
7167c478bd9Sstevel@tonic-gate 		cur = cur->ai_next;
7177c478bd9Sstevel@tonic-gate 	}
7187c478bd9Sstevel@tonic-gate 
7197c478bd9Sstevel@tonic-gate 	*res = sentinel.ai_next;
7207c478bd9Sstevel@tonic-gate 	return 0;
7217c478bd9Sstevel@tonic-gate 
7227c478bd9Sstevel@tonic-gate fail:
7237c478bd9Sstevel@tonic-gate 	freeaddrinfo(sentinel.ai_next);
7247c478bd9Sstevel@tonic-gate 	return error;
7257c478bd9Sstevel@tonic-gate }
7267c478bd9Sstevel@tonic-gate 
727*9525b14bSRao Shoaib /*%
7287c478bd9Sstevel@tonic-gate  * hostname == NULL.
7297c478bd9Sstevel@tonic-gate  * passive socket -> anyaddr (0.0.0.0 or ::)
7307c478bd9Sstevel@tonic-gate  * non-passive socket -> localhost (127.0.0.1 or ::1)
7317c478bd9Sstevel@tonic-gate  */
7327c478bd9Sstevel@tonic-gate static int
explore_null(pai,servname,res)7337c478bd9Sstevel@tonic-gate explore_null(pai, servname, res)
7347c478bd9Sstevel@tonic-gate 	const struct addrinfo *pai;
7357c478bd9Sstevel@tonic-gate 	const char *servname;
7367c478bd9Sstevel@tonic-gate 	struct addrinfo **res;
7377c478bd9Sstevel@tonic-gate {
7387c478bd9Sstevel@tonic-gate 	const struct afd *afd;
7397c478bd9Sstevel@tonic-gate 	struct addrinfo *cur;
7407c478bd9Sstevel@tonic-gate 	struct addrinfo sentinel;
7417c478bd9Sstevel@tonic-gate 	int error;
7427c478bd9Sstevel@tonic-gate 
7437c478bd9Sstevel@tonic-gate 	*res = NULL;
7447c478bd9Sstevel@tonic-gate 	sentinel.ai_next = NULL;
7457c478bd9Sstevel@tonic-gate 	cur = &sentinel;
7467c478bd9Sstevel@tonic-gate 
7477c478bd9Sstevel@tonic-gate 	afd = find_afd(pai->ai_family);
7487c478bd9Sstevel@tonic-gate 	if (afd == NULL)
7497c478bd9Sstevel@tonic-gate 		return 0;
7507c478bd9Sstevel@tonic-gate 
7517c478bd9Sstevel@tonic-gate 	if (pai->ai_flags & AI_PASSIVE) {
7527c478bd9Sstevel@tonic-gate 		GET_AI(cur->ai_next, afd, afd->a_addrany);
7537c478bd9Sstevel@tonic-gate 		/* xxx meaningless?
7547c478bd9Sstevel@tonic-gate 		 * GET_CANONNAME(cur->ai_next, "anyaddr");
7557c478bd9Sstevel@tonic-gate 		 */
7567c478bd9Sstevel@tonic-gate 		GET_PORT(cur->ai_next, servname);
7577c478bd9Sstevel@tonic-gate 	} else {
7587c478bd9Sstevel@tonic-gate 		GET_AI(cur->ai_next, afd, afd->a_loopback);
7597c478bd9Sstevel@tonic-gate 		/* xxx meaningless?
7607c478bd9Sstevel@tonic-gate 		 * GET_CANONNAME(cur->ai_next, "localhost");
7617c478bd9Sstevel@tonic-gate 		 */
7627c478bd9Sstevel@tonic-gate 		GET_PORT(cur->ai_next, servname);
7637c478bd9Sstevel@tonic-gate 	}
7647c478bd9Sstevel@tonic-gate 	cur = cur->ai_next;
7657c478bd9Sstevel@tonic-gate 
7667c478bd9Sstevel@tonic-gate 	*res = sentinel.ai_next;
7677c478bd9Sstevel@tonic-gate 	return 0;
7687c478bd9Sstevel@tonic-gate 
7697c478bd9Sstevel@tonic-gate free:
7707c478bd9Sstevel@tonic-gate 	if (sentinel.ai_next)
7717c478bd9Sstevel@tonic-gate 		freeaddrinfo(sentinel.ai_next);
7727c478bd9Sstevel@tonic-gate 	return error;
7737c478bd9Sstevel@tonic-gate }
7747c478bd9Sstevel@tonic-gate 
775*9525b14bSRao Shoaib /*%
7767c478bd9Sstevel@tonic-gate  * numeric hostname
7777c478bd9Sstevel@tonic-gate  */
7787c478bd9Sstevel@tonic-gate static int
explore_numeric(pai,hostname,servname,res)7797c478bd9Sstevel@tonic-gate explore_numeric(pai, hostname, servname, res)
7807c478bd9Sstevel@tonic-gate 	const struct addrinfo *pai;
7817c478bd9Sstevel@tonic-gate 	const char *hostname;
7827c478bd9Sstevel@tonic-gate 	const char *servname;
7837c478bd9Sstevel@tonic-gate 	struct addrinfo **res;
7847c478bd9Sstevel@tonic-gate {
7857c478bd9Sstevel@tonic-gate 	const struct afd *afd;
7867c478bd9Sstevel@tonic-gate 	struct addrinfo *cur;
7877c478bd9Sstevel@tonic-gate 	struct addrinfo sentinel;
7887c478bd9Sstevel@tonic-gate 	int error;
7897c478bd9Sstevel@tonic-gate 	char pton[PTON_MAX];
7907c478bd9Sstevel@tonic-gate 
7917c478bd9Sstevel@tonic-gate 	*res = NULL;
7927c478bd9Sstevel@tonic-gate 	sentinel.ai_next = NULL;
7937c478bd9Sstevel@tonic-gate 	cur = &sentinel;
7947c478bd9Sstevel@tonic-gate 
7957c478bd9Sstevel@tonic-gate 	afd = find_afd(pai->ai_family);
7967c478bd9Sstevel@tonic-gate 	if (afd == NULL)
7977c478bd9Sstevel@tonic-gate 		return 0;
7987c478bd9Sstevel@tonic-gate 
7997c478bd9Sstevel@tonic-gate 	switch (afd->a_af) {
8007c478bd9Sstevel@tonic-gate #if 0 /*X/Open spec*/
8017c478bd9Sstevel@tonic-gate 	case AF_INET:
8027c478bd9Sstevel@tonic-gate 		if (inet_aton(hostname, (struct in_addr *)pton) == 1) {
8037c478bd9Sstevel@tonic-gate 			if (pai->ai_family == afd->a_af ||
8047c478bd9Sstevel@tonic-gate 			    pai->ai_family == PF_UNSPEC /*?*/) {
8057c478bd9Sstevel@tonic-gate 				GET_AI(cur->ai_next, afd, pton);
8067c478bd9Sstevel@tonic-gate 				GET_PORT(cur->ai_next, servname);
807*9525b14bSRao Shoaib 				while (cur->ai_next)
8087c478bd9Sstevel@tonic-gate 					cur = cur->ai_next;
8097c478bd9Sstevel@tonic-gate 			} else
810*9525b14bSRao Shoaib 				SETERROR(EAI_FAMILY);	/*xxx*/
8117c478bd9Sstevel@tonic-gate 		}
8127c478bd9Sstevel@tonic-gate 		break;
8137c478bd9Sstevel@tonic-gate #endif
8147c478bd9Sstevel@tonic-gate 	default:
8157c478bd9Sstevel@tonic-gate 		if (inet_pton(afd->a_af, hostname, pton) == 1) {
8167c478bd9Sstevel@tonic-gate 			if (pai->ai_family == afd->a_af ||
8177c478bd9Sstevel@tonic-gate 			    pai->ai_family == PF_UNSPEC /*?*/) {
8187c478bd9Sstevel@tonic-gate 				GET_AI(cur->ai_next, afd, pton);
8197c478bd9Sstevel@tonic-gate 				GET_PORT(cur->ai_next, servname);
820*9525b14bSRao Shoaib 				while (cur->ai_next)
8217c478bd9Sstevel@tonic-gate 					cur = cur->ai_next;
822*9525b14bSRao Shoaib 			} else
823*9525b14bSRao Shoaib 				SETERROR(EAI_FAMILY);	/*xxx*/
8247c478bd9Sstevel@tonic-gate 		}
8257c478bd9Sstevel@tonic-gate 		break;
8267c478bd9Sstevel@tonic-gate 	}
8277c478bd9Sstevel@tonic-gate 
8287c478bd9Sstevel@tonic-gate 	*res = sentinel.ai_next;
8297c478bd9Sstevel@tonic-gate 	return 0;
8307c478bd9Sstevel@tonic-gate 
8317c478bd9Sstevel@tonic-gate free:
8327c478bd9Sstevel@tonic-gate bad:
8337c478bd9Sstevel@tonic-gate 	if (sentinel.ai_next)
8347c478bd9Sstevel@tonic-gate 		freeaddrinfo(sentinel.ai_next);
8357c478bd9Sstevel@tonic-gate 	return error;
8367c478bd9Sstevel@tonic-gate }
8377c478bd9Sstevel@tonic-gate 
838*9525b14bSRao Shoaib /*%
8397c478bd9Sstevel@tonic-gate  * numeric hostname with scope
8407c478bd9Sstevel@tonic-gate  */
8417c478bd9Sstevel@tonic-gate static int
explore_numeric_scope(pai,hostname,servname,res)8427c478bd9Sstevel@tonic-gate explore_numeric_scope(pai, hostname, servname, res)
8437c478bd9Sstevel@tonic-gate 	const struct addrinfo *pai;
8447c478bd9Sstevel@tonic-gate 	const char *hostname;
8457c478bd9Sstevel@tonic-gate 	const char *servname;
8467c478bd9Sstevel@tonic-gate 	struct addrinfo **res;
8477c478bd9Sstevel@tonic-gate {
8487c478bd9Sstevel@tonic-gate #ifndef SCOPE_DELIMITER
8497c478bd9Sstevel@tonic-gate 	return explore_numeric(pai, hostname, servname, res);
8507c478bd9Sstevel@tonic-gate #else
8517c478bd9Sstevel@tonic-gate 	const struct afd *afd;
8527c478bd9Sstevel@tonic-gate 	struct addrinfo *cur;
8537c478bd9Sstevel@tonic-gate 	int error;
8547c478bd9Sstevel@tonic-gate 	char *cp, *hostname2 = NULL, *scope, *addr;
8557c478bd9Sstevel@tonic-gate 	struct sockaddr_in6 *sin6;
8567c478bd9Sstevel@tonic-gate 
8577c478bd9Sstevel@tonic-gate 	afd = find_afd(pai->ai_family);
8587c478bd9Sstevel@tonic-gate 	if (afd == NULL)
8597c478bd9Sstevel@tonic-gate 		return 0;
8607c478bd9Sstevel@tonic-gate 
8617c478bd9Sstevel@tonic-gate 	if (!afd->a_scoped)
8627c478bd9Sstevel@tonic-gate 		return explore_numeric(pai, hostname, servname, res);
8637c478bd9Sstevel@tonic-gate 
8647c478bd9Sstevel@tonic-gate 	cp = strchr(hostname, SCOPE_DELIMITER);
8657c478bd9Sstevel@tonic-gate 	if (cp == NULL)
8667c478bd9Sstevel@tonic-gate 		return explore_numeric(pai, hostname, servname, res);
8677c478bd9Sstevel@tonic-gate 
8687c478bd9Sstevel@tonic-gate 	/*
8697c478bd9Sstevel@tonic-gate 	 * Handle special case of <scoped_address><delimiter><scope id>
8707c478bd9Sstevel@tonic-gate 	 */
8717c478bd9Sstevel@tonic-gate 	hostname2 = strdup(hostname);
8727c478bd9Sstevel@tonic-gate 	if (hostname2 == NULL)
8737c478bd9Sstevel@tonic-gate 		return EAI_MEMORY;
8747c478bd9Sstevel@tonic-gate 	/* terminate at the delimiter */
8757c478bd9Sstevel@tonic-gate 	hostname2[cp - hostname] = '\0';
8767c478bd9Sstevel@tonic-gate 	addr = hostname2;
8777c478bd9Sstevel@tonic-gate 	scope = cp + 1;
8787c478bd9Sstevel@tonic-gate 
8797c478bd9Sstevel@tonic-gate 	error = explore_numeric(pai, addr, servname, res);
8807c478bd9Sstevel@tonic-gate 	if (error == 0) {
8817c478bd9Sstevel@tonic-gate 		u_int32_t scopeid = 0;
8827c478bd9Sstevel@tonic-gate 
8837c478bd9Sstevel@tonic-gate 		for (cur = *res; cur; cur = cur->ai_next) {
8847c478bd9Sstevel@tonic-gate 			if (cur->ai_family != AF_INET6)
8857c478bd9Sstevel@tonic-gate 				continue;
8867c478bd9Sstevel@tonic-gate 			sin6 = (struct sockaddr_in6 *)(void *)cur->ai_addr;
8877c478bd9Sstevel@tonic-gate 			if (!ip6_str2scopeid(scope, sin6, &scopeid)) {
8887c478bd9Sstevel@tonic-gate 				free(hostname2);
889*9525b14bSRao Shoaib 				return(EAI_NONAME); /*%< XXX: is return OK? */
8907c478bd9Sstevel@tonic-gate 			}
8917c478bd9Sstevel@tonic-gate #ifdef HAVE_SIN6_SCOPE_ID
8927c478bd9Sstevel@tonic-gate 			sin6->sin6_scope_id = scopeid;
8937c478bd9Sstevel@tonic-gate #endif
8947c478bd9Sstevel@tonic-gate 		}
8957c478bd9Sstevel@tonic-gate 	}
8967c478bd9Sstevel@tonic-gate 
8977c478bd9Sstevel@tonic-gate 	free(hostname2);
8987c478bd9Sstevel@tonic-gate 
8997c478bd9Sstevel@tonic-gate 	return error;
9007c478bd9Sstevel@tonic-gate #endif
9017c478bd9Sstevel@tonic-gate }
9027c478bd9Sstevel@tonic-gate 
9037c478bd9Sstevel@tonic-gate static int
get_canonname(pai,ai,str)9047c478bd9Sstevel@tonic-gate get_canonname(pai, ai, str)
9057c478bd9Sstevel@tonic-gate 	const struct addrinfo *pai;
9067c478bd9Sstevel@tonic-gate 	struct addrinfo *ai;
9077c478bd9Sstevel@tonic-gate 	const char *str;
9087c478bd9Sstevel@tonic-gate {
9097c478bd9Sstevel@tonic-gate 	if ((pai->ai_flags & AI_CANONNAME) != 0) {
9107c478bd9Sstevel@tonic-gate 		ai->ai_canonname = (char *)malloc(strlen(str) + 1);
9117c478bd9Sstevel@tonic-gate 		if (ai->ai_canonname == NULL)
9127c478bd9Sstevel@tonic-gate 			return EAI_MEMORY;
9137c478bd9Sstevel@tonic-gate 		strcpy(ai->ai_canonname, str);
9147c478bd9Sstevel@tonic-gate 	}
9157c478bd9Sstevel@tonic-gate 	return 0;
9167c478bd9Sstevel@tonic-gate }
9177c478bd9Sstevel@tonic-gate 
9187c478bd9Sstevel@tonic-gate static struct addrinfo *
get_ai(pai,afd,addr)9197c478bd9Sstevel@tonic-gate get_ai(pai, afd, addr)
9207c478bd9Sstevel@tonic-gate 	const struct addrinfo *pai;
9217c478bd9Sstevel@tonic-gate 	const struct afd *afd;
9227c478bd9Sstevel@tonic-gate 	const char *addr;
9237c478bd9Sstevel@tonic-gate {
9247c478bd9Sstevel@tonic-gate 	char *p;
9257c478bd9Sstevel@tonic-gate 	struct addrinfo *ai;
9267c478bd9Sstevel@tonic-gate 
9277c478bd9Sstevel@tonic-gate 	ai = (struct addrinfo *)malloc(sizeof(struct addrinfo)
9287c478bd9Sstevel@tonic-gate 		+ (afd->a_socklen));
9297c478bd9Sstevel@tonic-gate 	if (ai == NULL)
9307c478bd9Sstevel@tonic-gate 		return NULL;
9317c478bd9Sstevel@tonic-gate 
9327c478bd9Sstevel@tonic-gate 	memcpy(ai, pai, sizeof(struct addrinfo));
9337c478bd9Sstevel@tonic-gate 	ai->ai_addr = (struct sockaddr *)(void *)(ai + 1);
9347c478bd9Sstevel@tonic-gate 	memset(ai->ai_addr, 0, (size_t)afd->a_socklen);
9357c478bd9Sstevel@tonic-gate #ifdef HAVE_SA_LEN
9367c478bd9Sstevel@tonic-gate 	ai->ai_addr->sa_len = afd->a_socklen;
9377c478bd9Sstevel@tonic-gate #endif
9387c478bd9Sstevel@tonic-gate 	ai->ai_addrlen = afd->a_socklen;
9397c478bd9Sstevel@tonic-gate 	ai->ai_addr->sa_family = ai->ai_family = afd->a_af;
9407c478bd9Sstevel@tonic-gate 	p = (char *)(void *)(ai->ai_addr);
9417c478bd9Sstevel@tonic-gate 	memcpy(p + afd->a_off, addr, (size_t)afd->a_addrlen);
9427c478bd9Sstevel@tonic-gate 	return ai;
9437c478bd9Sstevel@tonic-gate }
9447c478bd9Sstevel@tonic-gate 
9457c478bd9Sstevel@tonic-gate /* XXX need to malloc() the same way we do from other functions! */
9467c478bd9Sstevel@tonic-gate static struct addrinfo *
copy_ai(pai)9477c478bd9Sstevel@tonic-gate copy_ai(pai)
9487c478bd9Sstevel@tonic-gate 	const struct addrinfo *pai;
9497c478bd9Sstevel@tonic-gate {
9507c478bd9Sstevel@tonic-gate 	struct addrinfo *ai;
9517c478bd9Sstevel@tonic-gate 	size_t l;
9527c478bd9Sstevel@tonic-gate 
9537c478bd9Sstevel@tonic-gate 	l = sizeof(*ai) + pai->ai_addrlen;
9547c478bd9Sstevel@tonic-gate 	if ((ai = (struct addrinfo *)malloc(l)) == NULL)
9557c478bd9Sstevel@tonic-gate 		return NULL;
9567c478bd9Sstevel@tonic-gate 	memset(ai, 0, l);
9577c478bd9Sstevel@tonic-gate 	memcpy(ai, pai, sizeof(*ai));
9587c478bd9Sstevel@tonic-gate 	ai->ai_addr = (struct sockaddr *)(void *)(ai + 1);
9597c478bd9Sstevel@tonic-gate 	memcpy(ai->ai_addr, pai->ai_addr, pai->ai_addrlen);
9607c478bd9Sstevel@tonic-gate 
9617c478bd9Sstevel@tonic-gate 	if (pai->ai_canonname) {
9627c478bd9Sstevel@tonic-gate 		l = strlen(pai->ai_canonname) + 1;
9637c478bd9Sstevel@tonic-gate 		if ((ai->ai_canonname = malloc(l)) == NULL) {
9647c478bd9Sstevel@tonic-gate 			free(ai);
9657c478bd9Sstevel@tonic-gate 			return NULL;
9667c478bd9Sstevel@tonic-gate 		}
967*9525b14bSRao Shoaib 		strcpy(ai->ai_canonname, pai->ai_canonname);	/* (checked) */
9687c478bd9Sstevel@tonic-gate 	} else {
9697c478bd9Sstevel@tonic-gate 		/* just to make sure */
9707c478bd9Sstevel@tonic-gate 		ai->ai_canonname = NULL;
9717c478bd9Sstevel@tonic-gate 	}
9727c478bd9Sstevel@tonic-gate 
9737c478bd9Sstevel@tonic-gate 	ai->ai_next = NULL;
9747c478bd9Sstevel@tonic-gate 
9757c478bd9Sstevel@tonic-gate 	return ai;
9767c478bd9Sstevel@tonic-gate }
9777c478bd9Sstevel@tonic-gate 
9787c478bd9Sstevel@tonic-gate static int
get_portmatch(const struct addrinfo * ai,const char * servname)9797c478bd9Sstevel@tonic-gate get_portmatch(const struct addrinfo *ai, const char *servname) {
9807c478bd9Sstevel@tonic-gate 
9817c478bd9Sstevel@tonic-gate 	/* get_port does not touch first argument. when matchonly == 1. */
9827c478bd9Sstevel@tonic-gate 	/* LINTED const cast */
9837c478bd9Sstevel@tonic-gate 	return get_port((const struct addrinfo *)ai, servname, 1);
9847c478bd9Sstevel@tonic-gate }
9857c478bd9Sstevel@tonic-gate 
9867c478bd9Sstevel@tonic-gate static int
get_port(const struct addrinfo * ai,const char * servname,int matchonly)9877c478bd9Sstevel@tonic-gate get_port(const struct addrinfo *ai, const char *servname, int matchonly) {
9887c478bd9Sstevel@tonic-gate 	const char *proto;
9897c478bd9Sstevel@tonic-gate 	struct servent *sp;
9907c478bd9Sstevel@tonic-gate 	int port;
9917c478bd9Sstevel@tonic-gate 	int allownumeric;
9927c478bd9Sstevel@tonic-gate 
9937c478bd9Sstevel@tonic-gate 	if (servname == NULL)
9947c478bd9Sstevel@tonic-gate 		return 0;
9957c478bd9Sstevel@tonic-gate 	switch (ai->ai_family) {
9967c478bd9Sstevel@tonic-gate 	case AF_INET:
9977c478bd9Sstevel@tonic-gate #ifdef AF_INET6
9987c478bd9Sstevel@tonic-gate 	case AF_INET6:
9997c478bd9Sstevel@tonic-gate #endif
10007c478bd9Sstevel@tonic-gate 		break;
10017c478bd9Sstevel@tonic-gate 	default:
10027c478bd9Sstevel@tonic-gate 		return 0;
10037c478bd9Sstevel@tonic-gate 	}
10047c478bd9Sstevel@tonic-gate 
10057c478bd9Sstevel@tonic-gate 	switch (ai->ai_socktype) {
10067c478bd9Sstevel@tonic-gate 	case SOCK_RAW:
10077c478bd9Sstevel@tonic-gate 		return EAI_SERVICE;
10087c478bd9Sstevel@tonic-gate 	case SOCK_DGRAM:
10097c478bd9Sstevel@tonic-gate 	case SOCK_STREAM:
10107c478bd9Sstevel@tonic-gate 		allownumeric = 1;
10117c478bd9Sstevel@tonic-gate 		break;
10127c478bd9Sstevel@tonic-gate 	case ANY:
10137c478bd9Sstevel@tonic-gate 		switch (ai->ai_family) {
10147c478bd9Sstevel@tonic-gate 		case AF_INET:
10157c478bd9Sstevel@tonic-gate #ifdef AF_INET6
10167c478bd9Sstevel@tonic-gate 		case AF_INET6:
10177c478bd9Sstevel@tonic-gate #endif
10187c478bd9Sstevel@tonic-gate 			allownumeric = 1;
10197c478bd9Sstevel@tonic-gate 			break;
10207c478bd9Sstevel@tonic-gate 		default:
10217c478bd9Sstevel@tonic-gate 			allownumeric = 0;
10227c478bd9Sstevel@tonic-gate 			break;
10237c478bd9Sstevel@tonic-gate 		}
10247c478bd9Sstevel@tonic-gate 		break;
10257c478bd9Sstevel@tonic-gate 	default:
10267c478bd9Sstevel@tonic-gate 		return EAI_SOCKTYPE;
10277c478bd9Sstevel@tonic-gate 	}
10287c478bd9Sstevel@tonic-gate 
10297c478bd9Sstevel@tonic-gate 	if (str_isnumber(servname)) {
10307c478bd9Sstevel@tonic-gate 		if (!allownumeric)
10317c478bd9Sstevel@tonic-gate 			return EAI_SERVICE;
10327c478bd9Sstevel@tonic-gate 		port = atoi(servname);
10337c478bd9Sstevel@tonic-gate 		if (port < 0 || port > 65535)
10347c478bd9Sstevel@tonic-gate 			return EAI_SERVICE;
10357c478bd9Sstevel@tonic-gate 		port = htons(port);
10367c478bd9Sstevel@tonic-gate 	} else {
10377c478bd9Sstevel@tonic-gate 		switch (ai->ai_socktype) {
10387c478bd9Sstevel@tonic-gate 		case SOCK_DGRAM:
10397c478bd9Sstevel@tonic-gate 			proto = "udp";
10407c478bd9Sstevel@tonic-gate 			break;
10417c478bd9Sstevel@tonic-gate 		case SOCK_STREAM:
10427c478bd9Sstevel@tonic-gate 			proto = "tcp";
10437c478bd9Sstevel@tonic-gate 			break;
10447c478bd9Sstevel@tonic-gate 		default:
10457c478bd9Sstevel@tonic-gate 			proto = NULL;
10467c478bd9Sstevel@tonic-gate 			break;
10477c478bd9Sstevel@tonic-gate 		}
10487c478bd9Sstevel@tonic-gate 
10497c478bd9Sstevel@tonic-gate 		if ((sp = getservbyname(servname, proto)) == NULL)
10507c478bd9Sstevel@tonic-gate 			return EAI_SERVICE;
10517c478bd9Sstevel@tonic-gate 		port = sp->s_port;
10527c478bd9Sstevel@tonic-gate 	}
10537c478bd9Sstevel@tonic-gate 
10547c478bd9Sstevel@tonic-gate 	if (!matchonly) {
10557c478bd9Sstevel@tonic-gate 		switch (ai->ai_family) {
10567c478bd9Sstevel@tonic-gate 		case AF_INET:
10577c478bd9Sstevel@tonic-gate 			((struct sockaddr_in *)(void *)
10587c478bd9Sstevel@tonic-gate 			    ai->ai_addr)->sin_port = port;
10597c478bd9Sstevel@tonic-gate 			break;
10607c478bd9Sstevel@tonic-gate 		case AF_INET6:
10617c478bd9Sstevel@tonic-gate 			((struct sockaddr_in6 *)(void *)
10627c478bd9Sstevel@tonic-gate 			    ai->ai_addr)->sin6_port = port;
10637c478bd9Sstevel@tonic-gate 			break;
10647c478bd9Sstevel@tonic-gate 		}
10657c478bd9Sstevel@tonic-gate 	}
10667c478bd9Sstevel@tonic-gate 
10677c478bd9Sstevel@tonic-gate 	return 0;
10687c478bd9Sstevel@tonic-gate }
10697c478bd9Sstevel@tonic-gate 
10707c478bd9Sstevel@tonic-gate static const struct afd *
find_afd(af)10717c478bd9Sstevel@tonic-gate find_afd(af)
10727c478bd9Sstevel@tonic-gate 	int af;
10737c478bd9Sstevel@tonic-gate {
10747c478bd9Sstevel@tonic-gate 	const struct afd *afd;
10757c478bd9Sstevel@tonic-gate 
10767c478bd9Sstevel@tonic-gate 	if (af == PF_UNSPEC)
10777c478bd9Sstevel@tonic-gate 		return NULL;
10787c478bd9Sstevel@tonic-gate 	for (afd = afdl; afd->a_af; afd++) {
10797c478bd9Sstevel@tonic-gate 		if (afd->a_af == af)
10807c478bd9Sstevel@tonic-gate 			return afd;
10817c478bd9Sstevel@tonic-gate 	}
10827c478bd9Sstevel@tonic-gate 	return NULL;
10837c478bd9Sstevel@tonic-gate }
10847c478bd9Sstevel@tonic-gate 
1085*9525b14bSRao Shoaib /*%
10867c478bd9Sstevel@tonic-gate  * post-2553: AI_ADDRCONFIG check.  if we use getipnodeby* as backend, backend
10877c478bd9Sstevel@tonic-gate  * will take care of it.
10887c478bd9Sstevel@tonic-gate  * the semantics of AI_ADDRCONFIG is not defined well.  we are not sure
10897c478bd9Sstevel@tonic-gate  * if the code is right or not.
10907c478bd9Sstevel@tonic-gate  */
10917c478bd9Sstevel@tonic-gate static int
addrconfig(af)10927c478bd9Sstevel@tonic-gate addrconfig(af)
10937c478bd9Sstevel@tonic-gate 	int af;
10947c478bd9Sstevel@tonic-gate {
10957c478bd9Sstevel@tonic-gate 	int s;
10967c478bd9Sstevel@tonic-gate 
10977c478bd9Sstevel@tonic-gate 	/* XXX errno */
10987c478bd9Sstevel@tonic-gate 	s = socket(af, SOCK_DGRAM, 0);
10997c478bd9Sstevel@tonic-gate 	if (s < 0) {
11007c478bd9Sstevel@tonic-gate 		if (errno != EMFILE)
11017c478bd9Sstevel@tonic-gate 			return 0;
11027c478bd9Sstevel@tonic-gate 	} else
11037c478bd9Sstevel@tonic-gate 		close(s);
11047c478bd9Sstevel@tonic-gate 	return 1;
11057c478bd9Sstevel@tonic-gate }
11067c478bd9Sstevel@tonic-gate 
11077c478bd9Sstevel@tonic-gate /* convert a string to a scope identifier. XXX: IPv6 specific */
11087c478bd9Sstevel@tonic-gate static int
ip6_str2scopeid(char * scope,struct sockaddr_in6 * sin6,u_int32_t * scopeidp)11097c478bd9Sstevel@tonic-gate ip6_str2scopeid(char *scope, struct sockaddr_in6 *sin6,
11107c478bd9Sstevel@tonic-gate 		u_int32_t *scopeidp)
11117c478bd9Sstevel@tonic-gate {
11127c478bd9Sstevel@tonic-gate 	u_int32_t scopeid;
11137c478bd9Sstevel@tonic-gate 	u_long lscopeid;
11147c478bd9Sstevel@tonic-gate 	struct in6_addr *a6 = &sin6->sin6_addr;
11157c478bd9Sstevel@tonic-gate 	char *ep;
11167c478bd9Sstevel@tonic-gate 
11177c478bd9Sstevel@tonic-gate 	/* empty scopeid portion is invalid */
11187c478bd9Sstevel@tonic-gate 	if (*scope == '\0')
11197c478bd9Sstevel@tonic-gate 		return (0);
11207c478bd9Sstevel@tonic-gate 
11217c478bd9Sstevel@tonic-gate #ifdef USE_IFNAMELINKID
1122*9525b14bSRao Shoaib 	if (IN6_IS_ADDR_LINKLOCAL(a6) || IN6_IS_ADDR_MC_LINKLOCAL(a6) ||
1123*9525b14bSRao Shoaib 	    IN6_IS_ADDR_MC_NODELOCAL(a6)) {
11247c478bd9Sstevel@tonic-gate 		/*
11257c478bd9Sstevel@tonic-gate 		 * Using interface names as link indices can be allowed
11267c478bd9Sstevel@tonic-gate 		 * only when we can assume a one-to-one mappings between
11277c478bd9Sstevel@tonic-gate 		 * links and interfaces.  See comments in getnameinfo.c.
11287c478bd9Sstevel@tonic-gate 		 */
11297c478bd9Sstevel@tonic-gate 		scopeid = if_nametoindex(scope);
11307c478bd9Sstevel@tonic-gate 		if (scopeid == 0)
11317c478bd9Sstevel@tonic-gate 			goto trynumeric;
11327c478bd9Sstevel@tonic-gate 		*scopeidp = scopeid;
11337c478bd9Sstevel@tonic-gate 		return (1);
11347c478bd9Sstevel@tonic-gate 	}
11357c478bd9Sstevel@tonic-gate #endif
11367c478bd9Sstevel@tonic-gate 
11377c478bd9Sstevel@tonic-gate 	/* still unclear about literal, allow numeric only - placeholder */
11387c478bd9Sstevel@tonic-gate 	if (IN6_IS_ADDR_SITELOCAL(a6) || IN6_IS_ADDR_MC_SITELOCAL(a6))
11397c478bd9Sstevel@tonic-gate 		goto trynumeric;
11407c478bd9Sstevel@tonic-gate 	if (IN6_IS_ADDR_MC_ORGLOCAL(a6))
11417c478bd9Sstevel@tonic-gate 		goto trynumeric;
11427c478bd9Sstevel@tonic-gate 	else
1143*9525b14bSRao Shoaib 		goto trynumeric;	/*%< global */
11447c478bd9Sstevel@tonic-gate 	/* try to convert to a numeric id as a last resort */
11457c478bd9Sstevel@tonic-gate trynumeric:
11467c478bd9Sstevel@tonic-gate 	errno = 0;
11477c478bd9Sstevel@tonic-gate 	lscopeid = strtoul(scope, &ep, 10);
11487c478bd9Sstevel@tonic-gate 	scopeid = lscopeid & 0xffffffff;
11497c478bd9Sstevel@tonic-gate 	if (errno == 0 && ep && *ep == '\0' && scopeid == lscopeid) {
11507c478bd9Sstevel@tonic-gate 		*scopeidp = scopeid;
11517c478bd9Sstevel@tonic-gate 		return (1);
11527c478bd9Sstevel@tonic-gate 	} else
11537c478bd9Sstevel@tonic-gate 		return (0);
11547c478bd9Sstevel@tonic-gate }
11557c478bd9Sstevel@tonic-gate 
11567c478bd9Sstevel@tonic-gate struct addrinfo *
hostent2addrinfo(hp,pai)11577c478bd9Sstevel@tonic-gate hostent2addrinfo(hp, pai)
11587c478bd9Sstevel@tonic-gate 	struct hostent *hp;
11597c478bd9Sstevel@tonic-gate 	const struct addrinfo *pai;
11607c478bd9Sstevel@tonic-gate {
11617c478bd9Sstevel@tonic-gate 	int i, af, error = 0;
11627c478bd9Sstevel@tonic-gate 	char **aplist = NULL, *ap;
11637c478bd9Sstevel@tonic-gate 	struct addrinfo sentinel, *cur;
11647c478bd9Sstevel@tonic-gate 	const struct afd *afd;
11657c478bd9Sstevel@tonic-gate 
11667c478bd9Sstevel@tonic-gate 	af = hp->h_addrtype;
11677c478bd9Sstevel@tonic-gate 	if (pai->ai_family != AF_UNSPEC && af != pai->ai_family)
11687c478bd9Sstevel@tonic-gate 		return(NULL);
11697c478bd9Sstevel@tonic-gate 
11707c478bd9Sstevel@tonic-gate 	afd = find_afd(af);
11717c478bd9Sstevel@tonic-gate 	if (afd == NULL)
11727c478bd9Sstevel@tonic-gate 		return(NULL);
11737c478bd9Sstevel@tonic-gate 
11747c478bd9Sstevel@tonic-gate 	aplist = hp->h_addr_list;
11757c478bd9Sstevel@tonic-gate 
11767c478bd9Sstevel@tonic-gate 	memset(&sentinel, 0, sizeof(sentinel));
11777c478bd9Sstevel@tonic-gate 	cur = &sentinel;
11787c478bd9Sstevel@tonic-gate 
11797c478bd9Sstevel@tonic-gate 	for (i = 0; (ap = aplist[i]) != NULL; i++) {
1180*9525b14bSRao Shoaib #if 0				/*%< the trick seems too much */
11817c478bd9Sstevel@tonic-gate 		af = hp->h_addr_list;
11827c478bd9Sstevel@tonic-gate 		if (af == AF_INET6 &&
11837c478bd9Sstevel@tonic-gate 		    IN6_IS_ADDR_V4MAPPED((struct in6_addr *)ap)) {
11847c478bd9Sstevel@tonic-gate 			af = AF_INET;
11857c478bd9Sstevel@tonic-gate 			ap = ap + sizeof(struct in6_addr)
11867c478bd9Sstevel@tonic-gate 				- sizeof(struct in_addr);
11877c478bd9Sstevel@tonic-gate 		}
11887c478bd9Sstevel@tonic-gate 		afd = find_afd(af);
11897c478bd9Sstevel@tonic-gate 		if (afd == NULL)
11907c478bd9Sstevel@tonic-gate 			continue;
11917c478bd9Sstevel@tonic-gate #endif /* 0 */
11927c478bd9Sstevel@tonic-gate 
11937c478bd9Sstevel@tonic-gate 		GET_AI(cur->ai_next, afd, ap);
11947c478bd9Sstevel@tonic-gate 
11957c478bd9Sstevel@tonic-gate 		/* GET_PORT(cur->ai_next, servname); */
11967c478bd9Sstevel@tonic-gate 		if ((pai->ai_flags & AI_CANONNAME) != 0) {
11977c478bd9Sstevel@tonic-gate 			/*
11987c478bd9Sstevel@tonic-gate 			 * RFC2553 says that ai_canonname will be set only for
11997c478bd9Sstevel@tonic-gate 			 * the first element.  we do it for all the elements,
12007c478bd9Sstevel@tonic-gate 			 * just for convenience.
12017c478bd9Sstevel@tonic-gate 			 */
12027c478bd9Sstevel@tonic-gate 			GET_CANONNAME(cur->ai_next, hp->h_name);
12037c478bd9Sstevel@tonic-gate 		}
1204*9525b14bSRao Shoaib 		while (cur->ai_next) /*%< no need to loop, actually. */
12057c478bd9Sstevel@tonic-gate 			cur = cur->ai_next;
12067c478bd9Sstevel@tonic-gate 		continue;
12077c478bd9Sstevel@tonic-gate 
12087c478bd9Sstevel@tonic-gate 	free:
12097c478bd9Sstevel@tonic-gate 		if (cur->ai_next)
12107c478bd9Sstevel@tonic-gate 			freeaddrinfo(cur->ai_next);
12117c478bd9Sstevel@tonic-gate 		cur->ai_next = NULL;
12127c478bd9Sstevel@tonic-gate 		/* continue, without tht pointer CUR advanced. */
12137c478bd9Sstevel@tonic-gate 	}
12147c478bd9Sstevel@tonic-gate 
12157c478bd9Sstevel@tonic-gate 	return(sentinel.ai_next);
12167c478bd9Sstevel@tonic-gate }
12177c478bd9Sstevel@tonic-gate 
12187c478bd9Sstevel@tonic-gate struct addrinfo *
addr2addrinfo(pai,cp)12197c478bd9Sstevel@tonic-gate addr2addrinfo(pai, cp)
12207c478bd9Sstevel@tonic-gate 	const struct addrinfo *pai;
12217c478bd9Sstevel@tonic-gate 	const char *cp;
12227c478bd9Sstevel@tonic-gate {
12237c478bd9Sstevel@tonic-gate 	const struct afd *afd;
12247c478bd9Sstevel@tonic-gate 
12257c478bd9Sstevel@tonic-gate 	afd = find_afd(pai->ai_family);
12267c478bd9Sstevel@tonic-gate 	if (afd == NULL)
12277c478bd9Sstevel@tonic-gate 		return(NULL);
12287c478bd9Sstevel@tonic-gate 
12297c478bd9Sstevel@tonic-gate 	return(get_ai(pai, afd, cp));
12307c478bd9Sstevel@tonic-gate }
12317c478bd9Sstevel@tonic-gate 
12327c478bd9Sstevel@tonic-gate static struct net_data *
init()12337c478bd9Sstevel@tonic-gate init()
12347c478bd9Sstevel@tonic-gate {
12357c478bd9Sstevel@tonic-gate 	struct net_data *net_data;
12367c478bd9Sstevel@tonic-gate 
12377c478bd9Sstevel@tonic-gate 	if (!(net_data = net_data_init(NULL)))
12387c478bd9Sstevel@tonic-gate 		goto error;
12397c478bd9Sstevel@tonic-gate 	if (!net_data->ho) {
12407c478bd9Sstevel@tonic-gate 		net_data->ho = (*net_data->irs->ho_map)(net_data->irs);
12417c478bd9Sstevel@tonic-gate 		if (!net_data->ho || !net_data->res) {
12427c478bd9Sstevel@tonic-gate error:
12437c478bd9Sstevel@tonic-gate 			errno = EIO;
12447c478bd9Sstevel@tonic-gate 			if (net_data && net_data->res)
12457c478bd9Sstevel@tonic-gate 				RES_SET_H_ERRNO(net_data->res, NETDB_INTERNAL);
12467c478bd9Sstevel@tonic-gate 			return (NULL);
12477c478bd9Sstevel@tonic-gate 		}
12487c478bd9Sstevel@tonic-gate 
12497c478bd9Sstevel@tonic-gate 		(*net_data->ho->res_set)(net_data->ho, net_data->res, NULL);
12507c478bd9Sstevel@tonic-gate 	}
12517c478bd9Sstevel@tonic-gate 
12527c478bd9Sstevel@tonic-gate 	return (net_data);
12537c478bd9Sstevel@tonic-gate }
1254