17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5558fbd03Skcpoon  * Common Development and Distribution License (the "License").
6558fbd03Skcpoon  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate 
227c478bd9Sstevel@tonic-gate /*
231bb3da97Syan zhang - Sun Microsystems - Menlo Park United States  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
27*1071d9ffSAndy Fiddaman /*
28*1071d9ffSAndy Fiddaman  * Copyright 2023 Oxide Computer Company
29*1071d9ffSAndy Fiddaman  */
307c478bd9Sstevel@tonic-gate 
317c478bd9Sstevel@tonic-gate #include <netdb.h>
327c478bd9Sstevel@tonic-gate #include <arpa/inet.h>
337c478bd9Sstevel@tonic-gate #include <nss_dbdefs.h>
347c478bd9Sstevel@tonic-gate #include <netinet/in.h>
35*1071d9ffSAndy Fiddaman #include <sys/debug.h>
367c478bd9Sstevel@tonic-gate #include <sys/socket.h>
377c478bd9Sstevel@tonic-gate #include <string.h>
387c478bd9Sstevel@tonic-gate #include <strings.h>
397c478bd9Sstevel@tonic-gate #include <stdio.h>
407c478bd9Sstevel@tonic-gate #include <ctype.h>
417c478bd9Sstevel@tonic-gate #include <sys/types.h>
427c478bd9Sstevel@tonic-gate #include <stdlib.h>
437257d1b4Sraf #include <libintl.h>
447c478bd9Sstevel@tonic-gate #include <net/if.h>
457c478bd9Sstevel@tonic-gate 
467c478bd9Sstevel@tonic-gate #define	ai2sin(x)	((struct sockaddr_in *)((x)->ai_addr))
477c478bd9Sstevel@tonic-gate #define	ai2sin6(x)	((struct sockaddr_in6 *)((x)->ai_addr))
487c478bd9Sstevel@tonic-gate 
497c478bd9Sstevel@tonic-gate #define	HOST_BROADCAST	"255.255.255.255"
507c478bd9Sstevel@tonic-gate 
517c478bd9Sstevel@tonic-gate /*
52*1071d9ffSAndy Fiddaman  * getaddrinfo() returns EAI_NONAME in some cases, however since EAI_NONAME is
53*1071d9ffSAndy Fiddaman  * not part of SUSv3 it needed to be masked in the standards compliant
54*1071d9ffSAndy Fiddaman  * environment. GAIV_DEFAULT and GAIV_XPG6 accomplish this.
557c478bd9Sstevel@tonic-gate  */
567c478bd9Sstevel@tonic-gate #define	GAIV_DEFAULT	0
577c478bd9Sstevel@tonic-gate #define	GAIV_XPG6	1
587c478bd9Sstevel@tonic-gate 
597c478bd9Sstevel@tonic-gate /*
60*1071d9ffSAndy Fiddaman  * Storage allocation for global variables in6addr_any and in6addr_loopback.
61*1071d9ffSAndy Fiddaman  * The extern declarations for these variables are defined in <netinet/in.h>.
62*1071d9ffSAndy Fiddaman  * These two variables could have been defined in any of the "C" files in
63*1071d9ffSAndy Fiddaman  * libsocket. They are defined here with other IPv6 related interfaces.
647c478bd9Sstevel@tonic-gate  */
657c478bd9Sstevel@tonic-gate const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT;
667c478bd9Sstevel@tonic-gate const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT;
677c478bd9Sstevel@tonic-gate 
687c478bd9Sstevel@tonic-gate /* AI_MASK:  all valid flags for addrinfo */
697c478bd9Sstevel@tonic-gate #define	AI_MASK		(AI_PASSIVE | AI_CANONNAME | AI_NUMERICHOST \
707c478bd9Sstevel@tonic-gate 	| AI_ADDRCONFIG | AI_NUMERICSERV | AI_V4MAPPED | AI_ALL)
717c478bd9Sstevel@tonic-gate #define	ANY		0
722f443e27SRobert Mustacchi 
732f443e27SRobert Mustacchi /*
742f443e27SRobert Mustacchi  * This is a private, undocumented, flag that getaddrinfo() uses for
752f443e27SRobert Mustacchi  * getipnodebyname(). In the case of AI_ADDRCONFIG && AI_V4MAPPED, if there are
762f443e27SRobert Mustacchi  * no IPv6 addresses, getaddrinfo() should return non-IPv4 mapped addresses. On
772f443e27SRobert Mustacchi  * the flip side, getipnodebyname() is defined by RFC 2553 to explicitly do so.
782f443e27SRobert Mustacchi  * Therefore this private flag indicates to getaddrinfo that we shouldn't do
792f443e27SRobert Mustacchi  * this.
802f443e27SRobert Mustacchi  */
812f443e27SRobert Mustacchi #define	AI_ADDRINFO	0x8000
822f443e27SRobert Mustacchi 
83*1071d9ffSAndy Fiddaman typedef struct {
84*1071d9ffSAndy Fiddaman 	int		si_socktype;
85*1071d9ffSAndy Fiddaman 	int		si_protocol;
86*1071d9ffSAndy Fiddaman 	ushort_t	si_port;
87*1071d9ffSAndy Fiddaman } spinfo_t;
88*1071d9ffSAndy Fiddaman 
897c478bd9Sstevel@tonic-gate /* function prototypes for used by getaddrinfo() routine */
90*1071d9ffSAndy Fiddaman static int get_addr(int, const char *, struct addrinfo *,
91*1071d9ffSAndy Fiddaman 	struct addrinfo *, spinfo_t *, uint_t, int);
92*1071d9ffSAndy Fiddaman static uint_t getscopeidfromzone(const struct sockaddr_in6 *,
93*1071d9ffSAndy Fiddaman     const char *, uint32_t *);
94*1071d9ffSAndy Fiddaman static void servtype(const char *, int *, int *);
95*1071d9ffSAndy Fiddaman static boolean_t str_isnumber(const char *);
967c478bd9Sstevel@tonic-gate 
977c478bd9Sstevel@tonic-gate /*
987c478bd9Sstevel@tonic-gate  * getaddrinfo:
997c478bd9Sstevel@tonic-gate  *
1007c478bd9Sstevel@tonic-gate  * Purpose:
101*1071d9ffSAndy Fiddaman  *   Routine for performing Address-to-nodename in a protocol-independent
102*1071d9ffSAndy Fiddaman  *   fashion.
1037c478bd9Sstevel@tonic-gate  * Description and history of the routine:
104*1071d9ffSAndy Fiddaman  *   Nodename-to-address translation is done in a protocol- independent fashion
105*1071d9ffSAndy Fiddaman  *   using the getaddrinfo() function that is taken from IEEE POSIX 1003.1g.
1067c478bd9Sstevel@tonic-gate  *
107*1071d9ffSAndy Fiddaman  *   The official specification for this function will be the final POSIX
108*1071d9ffSAndy Fiddaman  *   standard, with the following additional requirements:
1097c478bd9Sstevel@tonic-gate  *
1107c478bd9Sstevel@tonic-gate  *   - getaddrinfo() must be thread safe
1117c478bd9Sstevel@tonic-gate  *   - The AI_NUMERICHOST is new.
112*1071d9ffSAndy Fiddaman  *   - All fields in socket address structures returned by getaddrinfo() that
113*1071d9ffSAndy Fiddaman  *     are not filled in through an explicit argument (e.g., sin6_flowinfo and
114*1071d9ffSAndy Fiddaman  *     sin_zero) must be set to 0. (This makes it easier to compare socket
115*1071d9ffSAndy Fiddaman  *     address structures).
1167c478bd9Sstevel@tonic-gate  *
1177c478bd9Sstevel@tonic-gate  * Input Parameters:
118*1071d9ffSAndy Fiddaman  *
119*1071d9ffSAndy Fiddaman  *   nodename       - pointer to a null-terminated string that represents
120*1071d9ffSAndy Fiddaman  *                    a hostname or literal ip address (IPv4/IPv6), or this
121*1071d9ffSAndy Fiddaman  *                    pointer can be NULL.
122*1071d9ffSAndy Fiddaman  *   servname       - pointer to a null-terminated string that represents
123*1071d9ffSAndy Fiddaman  *                    a servicename or literal port number, or this
124*1071d9ffSAndy Fiddaman  *                    pointer can be NULL.
125*1071d9ffSAndy Fiddaman  *   hints          - optional argument that points to an addrinfo structure
126*1071d9ffSAndy Fiddaman  *                    to provide hints on the type of socket that the caller
127*1071d9ffSAndy Fiddaman  *                    supports.
128*1071d9ffSAndy Fiddaman  *
129*1071d9ffSAndy Fiddaman  * Possible setting of the ai_flags member of the hints structure:
130*1071d9ffSAndy Fiddaman  *
131*1071d9ffSAndy Fiddaman  *   AI_PASSIVE     - If set, the caller plans to use the returned socket
1327c478bd9Sstevel@tonic-gate  *                    address in a call to bind().  In this case, it the
1337c478bd9Sstevel@tonic-gate  *                    nodename argument is NULL, then the IP address portion
1347c478bd9Sstevel@tonic-gate  *                    of the socket address structure will be set to
1357c478bd9Sstevel@tonic-gate  *                    INADDR_ANY for IPv4 or IN6ADDR_ANY_INIT for IPv6.
136*1071d9ffSAndy Fiddaman  *                    If not set, then the returned socket address will be
1377c478bd9Sstevel@tonic-gate  *                    ready for a call to connect() (for conn-oriented) or
1387c478bd9Sstevel@tonic-gate  *                    connect(), sendto(), or sendmsg() (for connectionless).
1397c478bd9Sstevel@tonic-gate  *                    In this case, if nodename is NULL, then the IP address
1407c478bd9Sstevel@tonic-gate  *                    portion of the socket address structure will be set to
1417c478bd9Sstevel@tonic-gate  *                    the loopback address.
142*1071d9ffSAndy Fiddaman  *   AI_CANONNAME   - If set, then upon successful return the ai_canonname
1437c478bd9Sstevel@tonic-gate  *                    field of the first addrinfo structure in the linked
1447c478bd9Sstevel@tonic-gate  *                    list will point to a NULL-terminated string
1457c478bd9Sstevel@tonic-gate  *                    containing the canonical name of the specified nodename.
1467c478bd9Sstevel@tonic-gate  *   AI_NUMERICHOST - If set, then a non-NULL nodename string must be a numeric
1477c478bd9Sstevel@tonic-gate  *                    host address string.  Otherwise an error of EAI_NONAME
1487c478bd9Sstevel@tonic-gate  *                    is returned.  This flag prevents any type of name
1497c478bd9Sstevel@tonic-gate  *                    resolution service from being called.
1507c478bd9Sstevel@tonic-gate  *   AI_NUMERICSERV - If set, then a non-null servname string supplied shall
1517c478bd9Sstevel@tonic-gate  *                    be a numeric port string. Otherwise, an [EAI_NONAME]
1527c478bd9Sstevel@tonic-gate  *                    error shall be returned. This flag shall prevent any
1537c478bd9Sstevel@tonic-gate  *                    type of name resolution service from being invoked.
154*1071d9ffSAndy Fiddaman  *   AI_ADDRCONFIG  - If set, IPv4 addresses are returned only if an IPv4
155*1071d9ffSAndy Fiddaman  *                    address is configured on the local system, and IPv6
156*1071d9ffSAndy Fiddaman  *                    addresses are returned only if an IPv6 address is
157*1071d9ffSAndy Fiddaman  *                    configured on the local system.
158*1071d9ffSAndy Fiddaman  *   AI_V4MAPPED    - If set, along with an ai_family of AF_INET6, then
1597c478bd9Sstevel@tonic-gate  *                    getaddrinfo() shall return IPv4-mapped IPv6 addresses
160*1071d9ffSAndy Fiddaman  *                    on finding no matching IPv6 addresses (ai_addrlen shall
1617c478bd9Sstevel@tonic-gate  *                    be 16). The AI_V4MAPPED flag shall be ignored unless
1627c478bd9Sstevel@tonic-gate  *                    ai_family equals AF_INET6.
163*1071d9ffSAndy Fiddaman  *   AI_ALL         - If the AI_ALL flag is used with the AI_V4MAPPED flag,
1647c478bd9Sstevel@tonic-gate  *		      then getaddrinfo() shall return all matching IPv6 and
1657c478bd9Sstevel@tonic-gate  *		      IPv4 addresses. The AI_ALL flag without the AI_V4MAPPED
1667c478bd9Sstevel@tonic-gate  *		      flag is ignored.
167*1071d9ffSAndy Fiddaman  *
1687c478bd9Sstevel@tonic-gate  * Output Parameters:
169*1071d9ffSAndy Fiddaman  *
170*1071d9ffSAndy Fiddaman  *   res            - upon successful return a pointer to a linked list of one
171*1071d9ffSAndy Fiddaman  *                    or more addrinfo structures is returned through this
172*1071d9ffSAndy Fiddaman  *                    argument.  The caller can process each addrinfo structures
173*1071d9ffSAndy Fiddaman  *                    in this list by following the ai_next pointer, until a
174*1071d9ffSAndy Fiddaman  *                    NULL pointer is encountered.  In each returned addrinfo
175*1071d9ffSAndy Fiddaman  *                    structure the three members ai_family, ai_socktype, and
176*1071d9ffSAndy Fiddaman  *                    ai_protocol are corresponding arguments for a call to the
177*1071d9ffSAndy Fiddaman  *                    socket() function.  In each addrinfo structure the ai_addr
178*1071d9ffSAndy Fiddaman  *                    field points to filled-in socket address structure whose
179*1071d9ffSAndy Fiddaman  *                    length is specified by the ai_addrlen member.
1807c478bd9Sstevel@tonic-gate  *
1817c478bd9Sstevel@tonic-gate  * Return Value:
1827c478bd9Sstevel@tonic-gate  *  This function returns 0 upon success or a nonzero error code.  The
1837c478bd9Sstevel@tonic-gate  *  following names are nonzero error codes from getaddrinfo(), and are
1847c478bd9Sstevel@tonic-gate  *  defined in <netdb.h>.
185*1071d9ffSAndy Fiddaman  *      EAI_ADDRFAMILY - address family not supported
186*1071d9ffSAndy Fiddaman  *      EAI_AGAIN      - DNS temporary failure
187*1071d9ffSAndy Fiddaman  *      EAI_BADFLAGS   - invalid ai_flags
188*1071d9ffSAndy Fiddaman  *      EAI_FAIL       - DNS non-recoverable failure
189*1071d9ffSAndy Fiddaman  *      EAI_FAMILY     - ai_family not supported
190*1071d9ffSAndy Fiddaman  *      EAI_MEMORY     - memory allocation failure
191*1071d9ffSAndy Fiddaman  *      EAI_NODATA     - no address associated with nodename
192*1071d9ffSAndy Fiddaman  *      EAI_NONAME     - host/servname not known
193*1071d9ffSAndy Fiddaman  *      EAI_SERVICE    - servname not supported for ai_socktype
194*1071d9ffSAndy Fiddaman  *      EAI_SOCKTYPE   - ai_socktype not supported
195*1071d9ffSAndy Fiddaman  *      EAI_SYSTEM     - system error in errno
1967c478bd9Sstevel@tonic-gate  *
1977c478bd9Sstevel@tonic-gate  * Memory Allocation:
1987c478bd9Sstevel@tonic-gate  *  All of the information returned by getaddrinfo() is dynamically
1997c478bd9Sstevel@tonic-gate  *  allocated:  the addrinfo structures, and the socket address
2007c478bd9Sstevel@tonic-gate  *  structures and canonical node name strings pointed to by the
2017c478bd9Sstevel@tonic-gate  *  addrinfo structures.
2027c478bd9Sstevel@tonic-gate  */
2037c478bd9Sstevel@tonic-gate 
2047c478bd9Sstevel@tonic-gate static int
_getaddrinfo(const char * hostname,const char * servname,const struct addrinfo * hints,struct addrinfo ** res,int version)2057c478bd9Sstevel@tonic-gate _getaddrinfo(const char *hostname, const char *servname,
206*1071d9ffSAndy Fiddaman     const struct addrinfo *hints, struct addrinfo **res, int version)
2077c478bd9Sstevel@tonic-gate {
2087c478bd9Sstevel@tonic-gate 	struct addrinfo *cur;
2097c478bd9Sstevel@tonic-gate 	struct addrinfo *aip;
2107c478bd9Sstevel@tonic-gate 	struct addrinfo ai;
211*1071d9ffSAndy Fiddaman 	int error;
212*1071d9ffSAndy Fiddaman 	uint_t i;
213*1071d9ffSAndy Fiddaman 
214*1071d9ffSAndy Fiddaman 	/*
215*1071d9ffSAndy Fiddaman 	 * We currently accumulate three services in the
216*1071d9ffSAndy Fiddaman 	 * SOCKTYPE_ANY/AI_NUMERICSERV case and one otherwise. If the logic in
217*1071d9ffSAndy Fiddaman 	 * this function is extended to return all matches from the services
218*1071d9ffSAndy Fiddaman 	 * database when AI_NUMERICSERV is not specified, this will need
219*1071d9ffSAndy Fiddaman 	 * revisiting.
220*1071d9ffSAndy Fiddaman 	 */
221*1071d9ffSAndy Fiddaman #define	SPINFO_SIZE 3
222*1071d9ffSAndy Fiddaman 	spinfo_t spinfo[SPINFO_SIZE];
223*1071d9ffSAndy Fiddaman 	uint_t spidx = 0;
224*1071d9ffSAndy Fiddaman 	/* Note that these macros require spinfo and spidx to be in scope */
225*1071d9ffSAndy Fiddaman #define	SP_ADDX(type, proto, port) \
226*1071d9ffSAndy Fiddaman 	do { \
227*1071d9ffSAndy Fiddaman 		ASSERT3U(spidx, <, SPINFO_SIZE); \
228*1071d9ffSAndy Fiddaman 		spinfo[spidx].si_socktype = (type); \
229*1071d9ffSAndy Fiddaman 		spinfo[spidx].si_protocol = (proto); \
230*1071d9ffSAndy Fiddaman 		spinfo[spidx].si_port = (port); \
231*1071d9ffSAndy Fiddaman 		spidx++; \
232*1071d9ffSAndy Fiddaman 	} while (0)
233*1071d9ffSAndy Fiddaman #define	SP_ADD(sp) \
234*1071d9ffSAndy Fiddaman 	do { \
235*1071d9ffSAndy Fiddaman 		int _type, _proto; \
236*1071d9ffSAndy Fiddaman 		servtype((sp)->s_proto, &_type, &_proto); \
237*1071d9ffSAndy Fiddaman 		SP_ADDX(_type, _proto, (sp)->s_port); \
238*1071d9ffSAndy Fiddaman 	} while (0)
239*1071d9ffSAndy Fiddaman 
240*1071d9ffSAndy Fiddaman 	*res = NULL;
241*1071d9ffSAndy Fiddaman 
242*1071d9ffSAndy Fiddaman 	if (hostname == NULL && servname == NULL)
243*1071d9ffSAndy Fiddaman 		return (EAI_NONAME);
2447c478bd9Sstevel@tonic-gate 
2457c478bd9Sstevel@tonic-gate 	cur = &ai;
2467c478bd9Sstevel@tonic-gate 	aip = &ai;
2477c478bd9Sstevel@tonic-gate 
248*1071d9ffSAndy Fiddaman 	if (hints == NULL) {
249*1071d9ffSAndy Fiddaman 		aip->ai_flags = 0;
250*1071d9ffSAndy Fiddaman 		aip->ai_family = PF_UNSPEC;
251*1071d9ffSAndy Fiddaman 		aip->ai_socktype = ANY;
252*1071d9ffSAndy Fiddaman 		aip->ai_protocol = ANY;
253*1071d9ffSAndy Fiddaman 	} else {
254*1071d9ffSAndy Fiddaman 		(void) memcpy(aip, hints, sizeof (*aip));
2557c478bd9Sstevel@tonic-gate 
2567c478bd9Sstevel@tonic-gate 		/* check for bad flags in hints */
257*1071d9ffSAndy Fiddaman 		if (hints->ai_flags != 0 && (hints->ai_flags & ~AI_MASK))
2587c478bd9Sstevel@tonic-gate 			return (EAI_BADFLAGS);
259*1071d9ffSAndy Fiddaman 
2607c478bd9Sstevel@tonic-gate 		if ((hostname == NULL || *hostname == '\0') &&
261558fbd03Skcpoon 		    (hints->ai_flags & AI_CANONNAME)) {
262*1071d9ffSAndy Fiddaman 			return (EAI_BADFLAGS);
2637c478bd9Sstevel@tonic-gate 		}
264*1071d9ffSAndy Fiddaman 
2657c478bd9Sstevel@tonic-gate 		if (hints->ai_family != PF_UNSPEC &&
2667c478bd9Sstevel@tonic-gate 		    hints->ai_family != PF_INET &&
2677c478bd9Sstevel@tonic-gate 		    hints->ai_family != PF_INET6) {
2687c478bd9Sstevel@tonic-gate 			return (EAI_FAMILY);
2697c478bd9Sstevel@tonic-gate 		}
2707c478bd9Sstevel@tonic-gate 
2717c478bd9Sstevel@tonic-gate 		switch (aip->ai_socktype) {
2727c478bd9Sstevel@tonic-gate 		case ANY:
2737c478bd9Sstevel@tonic-gate 			switch (aip->ai_protocol) {
2747c478bd9Sstevel@tonic-gate 			case ANY:
2757c478bd9Sstevel@tonic-gate 				break;
2767c478bd9Sstevel@tonic-gate 			case IPPROTO_UDP:
2777c478bd9Sstevel@tonic-gate 				aip->ai_socktype = SOCK_DGRAM;
2787c478bd9Sstevel@tonic-gate 				break;
2797c478bd9Sstevel@tonic-gate 			case IPPROTO_TCP:
280558fbd03Skcpoon 			case IPPROTO_SCTP:
2817c478bd9Sstevel@tonic-gate 				aip->ai_socktype = SOCK_STREAM;
2827c478bd9Sstevel@tonic-gate 				break;
2837c478bd9Sstevel@tonic-gate 			default:
2847c478bd9Sstevel@tonic-gate 				aip->ai_socktype = SOCK_RAW;
2857c478bd9Sstevel@tonic-gate 				break;
2867c478bd9Sstevel@tonic-gate 			}
2877c478bd9Sstevel@tonic-gate 			break;
2887c478bd9Sstevel@tonic-gate 		case SOCK_RAW:
2897c478bd9Sstevel@tonic-gate 			break;
290558fbd03Skcpoon 		case SOCK_SEQPACKET:
291558fbd03Skcpoon 			/*
292558fbd03Skcpoon 			 * If the hint does not have a preference on the
293558fbd03Skcpoon 			 * protocol, use SCTP as the default for
294558fbd03Skcpoon 			 * SOCK_SEQPACKET.
295558fbd03Skcpoon 			 */
296558fbd03Skcpoon 			if (aip->ai_protocol == ANY)
297558fbd03Skcpoon 				aip->ai_protocol = IPPROTO_SCTP;
298558fbd03Skcpoon 			break;
2997c478bd9Sstevel@tonic-gate 		case SOCK_DGRAM:
3007c478bd9Sstevel@tonic-gate 			aip->ai_protocol = IPPROTO_UDP;
3017c478bd9Sstevel@tonic-gate 			break;
3027c478bd9Sstevel@tonic-gate 		case SOCK_STREAM:
303558fbd03Skcpoon 			/*
304558fbd03Skcpoon 			 * If the hint does not have a preference on the
305558fbd03Skcpoon 			 * protocol, use TCP as the default for SOCK_STREAM.
306558fbd03Skcpoon 			 */
307558fbd03Skcpoon 			if (aip->ai_protocol == ANY)
308558fbd03Skcpoon 				aip->ai_protocol = IPPROTO_TCP;
3097c478bd9Sstevel@tonic-gate 			break;
3107c478bd9Sstevel@tonic-gate 		default:
3117c478bd9Sstevel@tonic-gate 			return (EAI_SOCKTYPE);
3127c478bd9Sstevel@tonic-gate 		}
3137c478bd9Sstevel@tonic-gate 	}
3147c478bd9Sstevel@tonic-gate 
315*1071d9ffSAndy Fiddaman 	aip->ai_addrlen = 0;
316*1071d9ffSAndy Fiddaman 	aip->ai_canonname = NULL;
317*1071d9ffSAndy Fiddaman 	aip->ai_addr = NULL;
318*1071d9ffSAndy Fiddaman 	aip->ai_next = NULL;
319*1071d9ffSAndy Fiddaman #ifdef __sparcv9
320*1071d9ffSAndy Fiddaman 	/*
321*1071d9ffSAndy Fiddaman 	 * We need to clear _ai_pad to preserve binary compatibility with
322*1071d9ffSAndy Fiddaman 	 * previously compiled 64-bit applications by guaranteeing the upper
323*1071d9ffSAndy Fiddaman 	 * 32-bits are empty.
324*1071d9ffSAndy Fiddaman 	 */
325*1071d9ffSAndy Fiddaman 	aip->_ai_pad = 0;
326*1071d9ffSAndy Fiddaman #endif /* __sparcv9 */
327*1071d9ffSAndy Fiddaman 
3287c478bd9Sstevel@tonic-gate 	/*
329*1071d9ffSAndy Fiddaman 	 * Get the service.
3307c478bd9Sstevel@tonic-gate 	 */
3317c478bd9Sstevel@tonic-gate 
3327c478bd9Sstevel@tonic-gate 	if (servname != NULL) {
3337c478bd9Sstevel@tonic-gate 		struct servent result;
3347c478bd9Sstevel@tonic-gate 		int bufsize = 128;
3357c478bd9Sstevel@tonic-gate 		char *buf = NULL;
3367c478bd9Sstevel@tonic-gate 		struct servent *sp;
337*1071d9ffSAndy Fiddaman 		const char *proto = NULL;
3387c478bd9Sstevel@tonic-gate 
3397c478bd9Sstevel@tonic-gate 		switch (aip->ai_socktype) {
3407c478bd9Sstevel@tonic-gate 		case ANY:
341*1071d9ffSAndy Fiddaman 		case SOCK_RAW:
3427c478bd9Sstevel@tonic-gate 			proto = NULL;
3437c478bd9Sstevel@tonic-gate 			break;
3447c478bd9Sstevel@tonic-gate 		case SOCK_DGRAM:
3457c478bd9Sstevel@tonic-gate 			proto = "udp";
3467c478bd9Sstevel@tonic-gate 			break;
3477c478bd9Sstevel@tonic-gate 		case SOCK_STREAM:
348558fbd03Skcpoon 			/*
349558fbd03Skcpoon 			 * If there is no hint given, use TCP as the default
350558fbd03Skcpoon 			 * protocol.
351558fbd03Skcpoon 			 */
352558fbd03Skcpoon 			switch (aip->ai_protocol) {
353558fbd03Skcpoon 			case ANY:
354558fbd03Skcpoon 			case IPPROTO_TCP:
355558fbd03Skcpoon 			default:
356558fbd03Skcpoon 				proto = "tcp";
357558fbd03Skcpoon 				break;
358558fbd03Skcpoon 			case IPPROTO_SCTP:
359558fbd03Skcpoon 				proto = "sctp";
360558fbd03Skcpoon 				break;
361558fbd03Skcpoon 			}
362558fbd03Skcpoon 			break;
363558fbd03Skcpoon 		case SOCK_SEQPACKET:
364558fbd03Skcpoon 			/* Default to SCTP if no hint given. */
365558fbd03Skcpoon 			switch (aip->ai_protocol) {
366558fbd03Skcpoon 			case ANY:
367558fbd03Skcpoon 			default:
368558fbd03Skcpoon 				proto = "sctp";
369558fbd03Skcpoon 				break;
370558fbd03Skcpoon 			}
3717c478bd9Sstevel@tonic-gate 			break;
3727c478bd9Sstevel@tonic-gate 		}
3737c478bd9Sstevel@tonic-gate 		/*
3747c478bd9Sstevel@tonic-gate 		 * Servname string can be a decimal port number.
3757c478bd9Sstevel@tonic-gate 		 */
3767c478bd9Sstevel@tonic-gate 		if (aip->ai_flags & AI_NUMERICSERV) {
377*1071d9ffSAndy Fiddaman 			ushort_t port;
378*1071d9ffSAndy Fiddaman 
379*1071d9ffSAndy Fiddaman 			if (!str_isnumber(servname))
3807c478bd9Sstevel@tonic-gate 				return (EAI_NONAME);
381*1071d9ffSAndy Fiddaman 
3827c478bd9Sstevel@tonic-gate 			port = htons(atoi(servname));
3837c478bd9Sstevel@tonic-gate 			if (aip->ai_socktype == ANY) {
384*1071d9ffSAndy Fiddaman 				/*
385*1071d9ffSAndy Fiddaman 				 * We cannot perform any name service lookups
386*1071d9ffSAndy Fiddaman 				 * here, per RFC3493, and so we return one
387*1071d9ffSAndy Fiddaman 				 * result for each of these types.
388*1071d9ffSAndy Fiddaman 				 */
389*1071d9ffSAndy Fiddaman 				SP_ADDX(SOCK_STREAM, IPPROTO_TCP, port);
390*1071d9ffSAndy Fiddaman 				SP_ADDX(SOCK_DGRAM, IPPROTO_UDP, port);
391*1071d9ffSAndy Fiddaman 				SP_ADDX(SOCK_STREAM, IPPROTO_SCTP, port);
392*1071d9ffSAndy Fiddaman 			} else {
393*1071d9ffSAndy Fiddaman 				SP_ADDX(aip->ai_socktype, aip->ai_protocol,
394*1071d9ffSAndy Fiddaman 				    port);
395*1071d9ffSAndy Fiddaman 			}
396*1071d9ffSAndy Fiddaman 		} else if (str_isnumber(servname)) {
397*1071d9ffSAndy Fiddaman 			ushort_t port = htons(atoi(servname));
398*1071d9ffSAndy Fiddaman 
399*1071d9ffSAndy Fiddaman 			if (aip->ai_socktype != ANY) {
400*1071d9ffSAndy Fiddaman 				/*
401*1071d9ffSAndy Fiddaman 				 * If we already know the socket type there is
402*1071d9ffSAndy Fiddaman 				 * no need to call getservbyport.
403*1071d9ffSAndy Fiddaman 				 */
404*1071d9ffSAndy Fiddaman 				SP_ADDX(aip->ai_socktype, aip->ai_protocol,
405*1071d9ffSAndy Fiddaman 				    port);
406*1071d9ffSAndy Fiddaman 			} else {
4077c478bd9Sstevel@tonic-gate 				do {
408*1071d9ffSAndy Fiddaman 					buf = reallocf(buf, bufsize);
409*1071d9ffSAndy Fiddaman 					if (buf == NULL)
4107c478bd9Sstevel@tonic-gate 						return (EAI_MEMORY);
4117c478bd9Sstevel@tonic-gate 
4127c478bd9Sstevel@tonic-gate 					sp = getservbyport_r(port, proto,
4137c478bd9Sstevel@tonic-gate 					    &result, buf, bufsize);
4147c478bd9Sstevel@tonic-gate 					if (sp == NULL && errno != ERANGE) {
4157c478bd9Sstevel@tonic-gate 						free(buf);
4167c478bd9Sstevel@tonic-gate 						return (EAI_SERVICE);
4177c478bd9Sstevel@tonic-gate 					}
418*1071d9ffSAndy Fiddaman 					/*
419*1071d9ffSAndy Fiddaman 					 * errno == ERANGE so our scratch
420*1071d9ffSAndy Fiddaman 					 * buffer space wasn't big enough.
421*1071d9ffSAndy Fiddaman 					 * Double it and try again.
422*1071d9ffSAndy Fiddaman 					 */
423*1071d9ffSAndy Fiddaman 					bufsize *= 2;
4247c478bd9Sstevel@tonic-gate 				} while (sp == NULL);
425*1071d9ffSAndy Fiddaman 				SP_ADD(sp);
4267c478bd9Sstevel@tonic-gate 			}
4277c478bd9Sstevel@tonic-gate 		} else {
428*1071d9ffSAndy Fiddaman 			/*
429*1071d9ffSAndy Fiddaman 			 * Look up the provided service name in the service
430*1071d9ffSAndy Fiddaman 			 * database.
431*1071d9ffSAndy Fiddaman 			 */
4327c478bd9Sstevel@tonic-gate 			do {
433*1071d9ffSAndy Fiddaman 				buf = reallocf(buf, bufsize);
434*1071d9ffSAndy Fiddaman 				if (buf == NULL)
4357c478bd9Sstevel@tonic-gate 					return (EAI_MEMORY);
4367c478bd9Sstevel@tonic-gate 
4377c478bd9Sstevel@tonic-gate 				sp = getservbyname_r(servname, proto, &result,
4387c478bd9Sstevel@tonic-gate 				    buf, bufsize);
4397c478bd9Sstevel@tonic-gate 				if (sp == NULL && errno != ERANGE) {
4407c478bd9Sstevel@tonic-gate 					free(buf);
4417c478bd9Sstevel@tonic-gate 					return (EAI_SERVICE);
4427c478bd9Sstevel@tonic-gate 				}
4437c478bd9Sstevel@tonic-gate 				/*
444*1071d9ffSAndy Fiddaman 				 * errno == ERANGE so our scratch buffer space
445*1071d9ffSAndy Fiddaman 				 * wasn't big enough.  Double it and try again.
4467c478bd9Sstevel@tonic-gate 				 */
447*1071d9ffSAndy Fiddaman 				bufsize *= 2;
448*1071d9ffSAndy Fiddaman 			} while (sp == NULL);
449*1071d9ffSAndy Fiddaman 			if (aip->ai_socktype != ANY) {
450*1071d9ffSAndy Fiddaman 				SP_ADDX(aip->ai_socktype, aip->ai_protocol,
451*1071d9ffSAndy Fiddaman 				    sp->s_port);
4527c478bd9Sstevel@tonic-gate 			} else {
453*1071d9ffSAndy Fiddaman 				SP_ADD(sp);
4547c478bd9Sstevel@tonic-gate 			}
4557c478bd9Sstevel@tonic-gate 		}
456*1071d9ffSAndy Fiddaman 		free(buf);
4577c478bd9Sstevel@tonic-gate 
458*1071d9ffSAndy Fiddaman 		if (spidx == 0)
459*1071d9ffSAndy Fiddaman 			return (EAI_SERVICE);
460*1071d9ffSAndy Fiddaman 	} else {
461*1071d9ffSAndy Fiddaman 		SP_ADDX(aip->ai_socktype, aip->ai_protocol, 0);
4627c478bd9Sstevel@tonic-gate 	}
4637c478bd9Sstevel@tonic-gate 
464*1071d9ffSAndy Fiddaman 	error = get_addr(aip->ai_family, hostname, aip, cur,
465*1071d9ffSAndy Fiddaman 	    spinfo, spidx, version);
4667c478bd9Sstevel@tonic-gate 
467*1071d9ffSAndy Fiddaman 	if (error != 0) {
468*1071d9ffSAndy Fiddaman 		if (aip->ai_next != NULL)
469*1071d9ffSAndy Fiddaman 			freeaddrinfo(aip->ai_next);
4707c478bd9Sstevel@tonic-gate 		return (error);
4717c478bd9Sstevel@tonic-gate 	}
4727c478bd9Sstevel@tonic-gate 
4737c478bd9Sstevel@tonic-gate 	*res = aip->ai_next;
4747c478bd9Sstevel@tonic-gate 	return (0);
4757c478bd9Sstevel@tonic-gate }
476*1071d9ffSAndy Fiddaman #undef SP_ADD
477*1071d9ffSAndy Fiddaman #undef SP_ADDX
4787c478bd9Sstevel@tonic-gate 
4797c478bd9Sstevel@tonic-gate int
getaddrinfo(const char * hostname,const char * servname,const struct addrinfo * hints,struct addrinfo ** res)4807c478bd9Sstevel@tonic-gate getaddrinfo(const char *hostname, const char *servname,
481*1071d9ffSAndy Fiddaman     const struct addrinfo *hints, struct addrinfo **res)
4827c478bd9Sstevel@tonic-gate {
4837c478bd9Sstevel@tonic-gate 	return (_getaddrinfo(hostname, servname, hints, res, GAIV_DEFAULT));
4847c478bd9Sstevel@tonic-gate }
4857c478bd9Sstevel@tonic-gate 
4867c478bd9Sstevel@tonic-gate int
__xnet_getaddrinfo(const char * hostname,const char * servname,const struct addrinfo * hints,struct addrinfo ** res)4877c478bd9Sstevel@tonic-gate __xnet_getaddrinfo(const char *hostname, const char *servname,
488*1071d9ffSAndy Fiddaman     const struct addrinfo *hints, struct addrinfo **res)
4897c478bd9Sstevel@tonic-gate {
4907c478bd9Sstevel@tonic-gate 	return (_getaddrinfo(hostname, servname, hints, res, GAIV_XPG6));
4917c478bd9Sstevel@tonic-gate }
4927c478bd9Sstevel@tonic-gate 
4937c478bd9Sstevel@tonic-gate static int
add_address4(struct addrinfo * aip,struct addrinfo ** cur,struct in_addr * addr,const char * canonname,spinfo_t * info)494*1071d9ffSAndy Fiddaman add_address4(struct addrinfo *aip, struct addrinfo **cur,
495*1071d9ffSAndy Fiddaman     struct in_addr *addr, const char *canonname, spinfo_t *info)
496*1071d9ffSAndy Fiddaman {
497*1071d9ffSAndy Fiddaman 	struct addrinfo *nai;
498*1071d9ffSAndy Fiddaman 	int addrlen;
499*1071d9ffSAndy Fiddaman 
500*1071d9ffSAndy Fiddaman 	nai = malloc(sizeof (struct addrinfo));
501*1071d9ffSAndy Fiddaman 	if (nai == NULL)
502*1071d9ffSAndy Fiddaman 		return (EAI_MEMORY);
503*1071d9ffSAndy Fiddaman 
504*1071d9ffSAndy Fiddaman 	*nai = *aip;
505*1071d9ffSAndy Fiddaman 	nai->ai_next = NULL;
506*1071d9ffSAndy Fiddaman 	addrlen = sizeof (struct sockaddr_in);
507*1071d9ffSAndy Fiddaman 
508*1071d9ffSAndy Fiddaman 	nai->ai_addr = malloc(addrlen);
509*1071d9ffSAndy Fiddaman 	if (nai->ai_addr == NULL) {
510*1071d9ffSAndy Fiddaman 		freeaddrinfo(nai);
511*1071d9ffSAndy Fiddaman 		return (EAI_MEMORY);
512*1071d9ffSAndy Fiddaman 	}
513*1071d9ffSAndy Fiddaman 
514*1071d9ffSAndy Fiddaman 	bzero(nai->ai_addr, addrlen);
515*1071d9ffSAndy Fiddaman 	nai->ai_addrlen = addrlen;
516*1071d9ffSAndy Fiddaman 	nai->ai_family = PF_INET;
517*1071d9ffSAndy Fiddaman 
518*1071d9ffSAndy Fiddaman 	(void) memcpy(&ai2sin(nai)->sin_addr, addr, sizeof (struct in_addr));
519*1071d9ffSAndy Fiddaman 	nai->ai_canonname = NULL;
520*1071d9ffSAndy Fiddaman 	if ((nai->ai_flags & AI_CANONNAME) && canonname != NULL) {
521*1071d9ffSAndy Fiddaman 		canonname = strdup(canonname);
522*1071d9ffSAndy Fiddaman 		if (canonname == NULL) {
523*1071d9ffSAndy Fiddaman 			freeaddrinfo(nai);
524*1071d9ffSAndy Fiddaman 			return (EAI_MEMORY);
525*1071d9ffSAndy Fiddaman 		}
526*1071d9ffSAndy Fiddaman 		nai->ai_canonname = (char *)canonname;
527*1071d9ffSAndy Fiddaman 	}
528*1071d9ffSAndy Fiddaman 	ai2sin(nai)->sin_family = PF_INET;
529*1071d9ffSAndy Fiddaman 	ai2sin(nai)->sin_port = info->si_port;
530*1071d9ffSAndy Fiddaman 	nai->ai_socktype = info->si_socktype;
531*1071d9ffSAndy Fiddaman 	nai->ai_protocol = info->si_protocol;
532*1071d9ffSAndy Fiddaman 
533*1071d9ffSAndy Fiddaman 	(*cur)->ai_next = nai;
534*1071d9ffSAndy Fiddaman 	*cur = nai;
535*1071d9ffSAndy Fiddaman 
536*1071d9ffSAndy Fiddaman 	return (0);
537*1071d9ffSAndy Fiddaman }
538*1071d9ffSAndy Fiddaman 
539*1071d9ffSAndy Fiddaman static int
add_address6(struct addrinfo * aip,struct addrinfo ** cur,struct in6_addr * addr,const char * zonestr,const char * canonname,spinfo_t * info)540*1071d9ffSAndy Fiddaman add_address6(struct addrinfo *aip, struct addrinfo **cur,
541*1071d9ffSAndy Fiddaman     struct in6_addr *addr, const char *zonestr, const char *canonname,
542*1071d9ffSAndy Fiddaman     spinfo_t *info)
543*1071d9ffSAndy Fiddaman {
544*1071d9ffSAndy Fiddaman 	struct addrinfo *nai;
545*1071d9ffSAndy Fiddaman 	int addrlen;
546*1071d9ffSAndy Fiddaman 
547*1071d9ffSAndy Fiddaman 	nai = malloc(sizeof (struct addrinfo));
548*1071d9ffSAndy Fiddaman 	if (nai == NULL)
549*1071d9ffSAndy Fiddaman 		return (EAI_MEMORY);
550*1071d9ffSAndy Fiddaman 
551*1071d9ffSAndy Fiddaman 	*nai = *aip;
552*1071d9ffSAndy Fiddaman 	nai->ai_next = NULL;
553*1071d9ffSAndy Fiddaman 	addrlen = sizeof (struct sockaddr_in6);
554*1071d9ffSAndy Fiddaman 
555*1071d9ffSAndy Fiddaman 	nai->ai_addr = malloc(addrlen);
556*1071d9ffSAndy Fiddaman 	if (nai->ai_addr == NULL) {
557*1071d9ffSAndy Fiddaman 		freeaddrinfo(nai);
558*1071d9ffSAndy Fiddaman 		return (EAI_MEMORY);
559*1071d9ffSAndy Fiddaman 	}
560*1071d9ffSAndy Fiddaman 
561*1071d9ffSAndy Fiddaman 	bzero(nai->ai_addr, addrlen);
562*1071d9ffSAndy Fiddaman 	nai->ai_addrlen = addrlen;
563*1071d9ffSAndy Fiddaman 	nai->ai_family = PF_INET6;
564*1071d9ffSAndy Fiddaman 
565*1071d9ffSAndy Fiddaman 	(void) memcpy(ai2sin6(nai)->sin6_addr.s6_addr,
566*1071d9ffSAndy Fiddaman 	    &addr->s6_addr, sizeof (struct in6_addr));
567*1071d9ffSAndy Fiddaman 	nai->ai_canonname = NULL;
568*1071d9ffSAndy Fiddaman 	if ((nai->ai_flags & AI_CANONNAME) && canonname != NULL) {
569*1071d9ffSAndy Fiddaman 		canonname = strdup(canonname);
570*1071d9ffSAndy Fiddaman 		if (canonname == NULL) {
571*1071d9ffSAndy Fiddaman 			freeaddrinfo(nai);
572*1071d9ffSAndy Fiddaman 			return (EAI_MEMORY);
573*1071d9ffSAndy Fiddaman 		}
574*1071d9ffSAndy Fiddaman 		nai->ai_canonname = (char *)canonname;
575*1071d9ffSAndy Fiddaman 	}
576*1071d9ffSAndy Fiddaman 	ai2sin6(nai)->sin6_family = PF_INET6;
577*1071d9ffSAndy Fiddaman 	ai2sin6(nai)->sin6_port = info->si_port;
578*1071d9ffSAndy Fiddaman 	nai->ai_socktype = info->si_socktype;
579*1071d9ffSAndy Fiddaman 	nai->ai_protocol = info->si_protocol;
580*1071d9ffSAndy Fiddaman 
581*1071d9ffSAndy Fiddaman 	/* set sin6_scope_id */
582*1071d9ffSAndy Fiddaman 	if (zonestr != NULL) {
583*1071d9ffSAndy Fiddaman 		/* Translate 'zonestr' into a valid sin6_scope_id. */
584*1071d9ffSAndy Fiddaman 		int err = getscopeidfromzone(ai2sin6(nai), zonestr,
585*1071d9ffSAndy Fiddaman 		    &ai2sin6(nai)->sin6_scope_id);
586*1071d9ffSAndy Fiddaman 		if (err != 0) {
587*1071d9ffSAndy Fiddaman 			freeaddrinfo(nai);
588*1071d9ffSAndy Fiddaman 			return (err);
589*1071d9ffSAndy Fiddaman 		}
590*1071d9ffSAndy Fiddaman 	} else {
591*1071d9ffSAndy Fiddaman 		ai2sin6(nai)->sin6_scope_id = 0;
592*1071d9ffSAndy Fiddaman 	}
593*1071d9ffSAndy Fiddaman 
594*1071d9ffSAndy Fiddaman 	(*cur)->ai_next = nai;
595*1071d9ffSAndy Fiddaman 	*cur = nai;
596*1071d9ffSAndy Fiddaman 
597*1071d9ffSAndy Fiddaman 	return (0);
598*1071d9ffSAndy Fiddaman }
599*1071d9ffSAndy Fiddaman 
600*1071d9ffSAndy Fiddaman static int
get_addr(int family,const char * hostname,struct addrinfo * aip,struct addrinfo * cur,spinfo_t * ports,uint_t nport,int version)601*1071d9ffSAndy Fiddaman get_addr(int family, const char *hostname, struct addrinfo *aip,
602*1071d9ffSAndy Fiddaman     struct addrinfo *cur, spinfo_t *ports, uint_t nport, int version)
6037c478bd9Sstevel@tonic-gate {
6047c478bd9Sstevel@tonic-gate 	struct hostent		*hp;
6057c478bd9Sstevel@tonic-gate 	char			_hostname[MAXHOSTNAMELEN];
606*1071d9ffSAndy Fiddaman 	int			errnum;
6077c478bd9Sstevel@tonic-gate 	boolean_t		firsttime = B_TRUE;
6087c478bd9Sstevel@tonic-gate 	char			*zonestr = NULL;
609*1071d9ffSAndy Fiddaman 	uint_t			i;
610*1071d9ffSAndy Fiddaman 
611*1071d9ffSAndy Fiddaman 	if (hostname == NULL) {
612*1071d9ffSAndy Fiddaman 		/*
613*1071d9ffSAndy Fiddaman 		 * case 1: AI_PASSIVE bit set : anyaddr 0.0.0.0 or ::
614*1071d9ffSAndy Fiddaman 		 * case 2: AI_PASSIVE bit not set : localhost 127.0.0.1 or ::1
615*1071d9ffSAndy Fiddaman 		 */
616*1071d9ffSAndy Fiddaman 		const char *canon = "loopback";
617*1071d9ffSAndy Fiddaman 		errnum = 0;
618*1071d9ffSAndy Fiddaman 
619*1071d9ffSAndy Fiddaman 		/*
620*1071d9ffSAndy Fiddaman 		 * PF_INET gets IPv4 only, PF_INET6 gets IPv6 only.
621*1071d9ffSAndy Fiddaman 		 * PF_UNSPEC gets both.
622*1071d9ffSAndy Fiddaman 		 */
623*1071d9ffSAndy Fiddaman 		if (family != PF_INET) {
624*1071d9ffSAndy Fiddaman 			struct in6_addr v6addr;
625*1071d9ffSAndy Fiddaman 
626*1071d9ffSAndy Fiddaman 			if (aip->ai_flags & AI_PASSIVE) {
627*1071d9ffSAndy Fiddaman 				(void) memcpy(&v6addr.s6_addr,
628*1071d9ffSAndy Fiddaman 				    in6addr_any.s6_addr,
629*1071d9ffSAndy Fiddaman 				    sizeof (struct in6_addr));
630*1071d9ffSAndy Fiddaman 				canon = NULL;
631*1071d9ffSAndy Fiddaman 			} else {
632*1071d9ffSAndy Fiddaman 				(void) memcpy(&v6addr.s6_addr,
633*1071d9ffSAndy Fiddaman 				    in6addr_loopback.s6_addr,
634*1071d9ffSAndy Fiddaman 				    sizeof (struct in6_addr));
635*1071d9ffSAndy Fiddaman 			}
636*1071d9ffSAndy Fiddaman 
637*1071d9ffSAndy Fiddaman 			for (i = 0; i < nport; i++) {
638*1071d9ffSAndy Fiddaman 				errnum = add_address6(aip, &cur, &v6addr, NULL,
639*1071d9ffSAndy Fiddaman 				    canon, &ports[i]);
640*1071d9ffSAndy Fiddaman 				canon = NULL;
641*1071d9ffSAndy Fiddaman 				if (errnum != 0)
642*1071d9ffSAndy Fiddaman 					break;
643*1071d9ffSAndy Fiddaman 			}
644*1071d9ffSAndy Fiddaman 		}
645*1071d9ffSAndy Fiddaman 
646*1071d9ffSAndy Fiddaman 		if (errnum == 0 && family != PF_INET6) {
647*1071d9ffSAndy Fiddaman 			struct in_addr addr;
648*1071d9ffSAndy Fiddaman 
649*1071d9ffSAndy Fiddaman 			if (aip->ai_flags & AI_PASSIVE) {
650*1071d9ffSAndy Fiddaman 				addr.s_addr = INADDR_ANY;
651*1071d9ffSAndy Fiddaman 				canon = NULL;
652*1071d9ffSAndy Fiddaman 			} else {
653*1071d9ffSAndy Fiddaman 				addr.s_addr = htonl(INADDR_LOOPBACK);
654*1071d9ffSAndy Fiddaman 			}
655*1071d9ffSAndy Fiddaman 
656*1071d9ffSAndy Fiddaman 			for (i = 0; i < nport; i++) {
657*1071d9ffSAndy Fiddaman 				errnum = add_address4(aip, &cur, &addr, canon,
658*1071d9ffSAndy Fiddaman 				    &ports[i]);
659*1071d9ffSAndy Fiddaman 				canon = NULL;
660*1071d9ffSAndy Fiddaman 				if (errnum != 0)
661*1071d9ffSAndy Fiddaman 					break;
662*1071d9ffSAndy Fiddaman 			}
663*1071d9ffSAndy Fiddaman 		}
664*1071d9ffSAndy Fiddaman 
665*1071d9ffSAndy Fiddaman 		return (errnum);
666*1071d9ffSAndy Fiddaman 	}
6677c478bd9Sstevel@tonic-gate 
6687c478bd9Sstevel@tonic-gate 	/*
6697c478bd9Sstevel@tonic-gate 	 * Check for existence of address-zoneid delimiter '%'
6707c478bd9Sstevel@tonic-gate 	 * If the delimiter exists, parse the zoneid portion of
6717c478bd9Sstevel@tonic-gate 	 * <addr>%<zone_id>
6727c478bd9Sstevel@tonic-gate 	 */
6737c478bd9Sstevel@tonic-gate 	if ((zonestr = strchr(hostname, '%')) != NULL) {
6747c478bd9Sstevel@tonic-gate 		/* make sure we have room for <addr> portion of hostname */
675*1071d9ffSAndy Fiddaman 		if ((zonestr - hostname) + 1 > sizeof (_hostname))
6767c478bd9Sstevel@tonic-gate 			return (EAI_MEMORY);
6777c478bd9Sstevel@tonic-gate 
6787c478bd9Sstevel@tonic-gate 		/* chop off and save <zone_id> portion */
6797c478bd9Sstevel@tonic-gate 		(void) strlcpy(_hostname, hostname, (zonestr - hostname) + 1);
6807c478bd9Sstevel@tonic-gate 		++zonestr;	/* make zonestr point at start of <zone-id> */
6817c478bd9Sstevel@tonic-gate 		/* ensure zone is valid */
682*1071d9ffSAndy Fiddaman 		if (*zonestr == '\0' || strlen(zonestr) > LIFNAMSIZ)
6837c478bd9Sstevel@tonic-gate 			return (EAI_NONAME);
6847c478bd9Sstevel@tonic-gate 	} else {
6857c478bd9Sstevel@tonic-gate 		size_t hlen = sizeof (_hostname);
6867c478bd9Sstevel@tonic-gate 
687*1071d9ffSAndy Fiddaman 		if (strlcpy(_hostname, hostname, hlen) >= hlen)
6887c478bd9Sstevel@tonic-gate 			return (EAI_MEMORY);
6897c478bd9Sstevel@tonic-gate 	}
6907c478bd9Sstevel@tonic-gate 
6917c478bd9Sstevel@tonic-gate 	/* Check to see if AI_NUMERICHOST bit is set */
6927c478bd9Sstevel@tonic-gate 	if (aip->ai_flags & AI_NUMERICHOST) {
693*1071d9ffSAndy Fiddaman 		struct in6_addr v6addr;
694*1071d9ffSAndy Fiddaman 
6957c478bd9Sstevel@tonic-gate 		/* check to see if _hostname points to a literal IP address */
696*1071d9ffSAndy Fiddaman 		if (!(inet_addr(_hostname) != ((in_addr_t)-1) ||
697*1071d9ffSAndy Fiddaman 		    strcmp(_hostname, HOST_BROADCAST) == 0 ||
698*1071d9ffSAndy Fiddaman 		    inet_pton(AF_INET6, _hostname, &v6addr) > 0)) {
6997c478bd9Sstevel@tonic-gate 			return (EAI_NONAME);
7007c478bd9Sstevel@tonic-gate 		}
7017c478bd9Sstevel@tonic-gate 	}
7027c478bd9Sstevel@tonic-gate 
7037c478bd9Sstevel@tonic-gate 	/* if hostname argument is literal, name service doesn't get called */
7047c478bd9Sstevel@tonic-gate 	if (family == PF_UNSPEC) {
705*1071d9ffSAndy Fiddaman 		hp = getipnodebyname(_hostname, AF_INET6,
706*1071d9ffSAndy Fiddaman 		    AI_ALL | aip->ai_flags | AI_V4MAPPED | AI_ADDRINFO,
707*1071d9ffSAndy Fiddaman 		    &errnum);
7087c478bd9Sstevel@tonic-gate 	} else {
7097c478bd9Sstevel@tonic-gate 		hp = getipnodebyname(_hostname, family, aip->ai_flags, &errnum);
7107c478bd9Sstevel@tonic-gate 	}
7117c478bd9Sstevel@tonic-gate 
7127c478bd9Sstevel@tonic-gate 	if (hp == NULL) {
7137c478bd9Sstevel@tonic-gate 		switch (errnum) {
7147c478bd9Sstevel@tonic-gate 		case HOST_NOT_FOUND:
7157c478bd9Sstevel@tonic-gate 			return (EAI_NONAME);
7167c478bd9Sstevel@tonic-gate 		case TRY_AGAIN:
7177c478bd9Sstevel@tonic-gate 			return (EAI_AGAIN);
7187c478bd9Sstevel@tonic-gate 		case NO_RECOVERY:
7197c478bd9Sstevel@tonic-gate 			return (EAI_FAIL);
7207c478bd9Sstevel@tonic-gate 		case NO_ADDRESS:
7217c478bd9Sstevel@tonic-gate 			if (version == GAIV_XPG6)
7227c478bd9Sstevel@tonic-gate 				return (EAI_NONAME);
7237c478bd9Sstevel@tonic-gate 			return (EAI_NODATA);
7247c478bd9Sstevel@tonic-gate 		default:
725*1071d9ffSAndy Fiddaman 			return (EAI_SYSTEM);
7267c478bd9Sstevel@tonic-gate 		}
7277c478bd9Sstevel@tonic-gate 	}
7287c478bd9Sstevel@tonic-gate 
7297c478bd9Sstevel@tonic-gate 	for (i = 0; hp->h_addr_list[i]; i++) {
730*1071d9ffSAndy Fiddaman 		boolean_t create_v6_addrinfo = B_TRUE;
731*1071d9ffSAndy Fiddaman 		struct in_addr v4addr;
732*1071d9ffSAndy Fiddaman 		struct in6_addr v6addr;
733*1071d9ffSAndy Fiddaman 		uint_t j;
734*1071d9ffSAndy Fiddaman 
7357c478bd9Sstevel@tonic-gate 		/* Determine if an IPv6 addrinfo structure should be created */
7367c478bd9Sstevel@tonic-gate 		if (hp->h_addrtype == AF_INET6) {
737*1071d9ffSAndy Fiddaman 			struct in6_addr *v6addrp;
738*1071d9ffSAndy Fiddaman 
7397c478bd9Sstevel@tonic-gate 			v6addrp = (struct in6_addr *)hp->h_addr_list[i];
7407c478bd9Sstevel@tonic-gate 			if (!(aip->ai_flags & AI_V4MAPPED) &&
7417c478bd9Sstevel@tonic-gate 			    IN6_IS_ADDR_V4MAPPED(v6addrp)) {
7427c478bd9Sstevel@tonic-gate 				create_v6_addrinfo = B_FALSE;
7437c478bd9Sstevel@tonic-gate 				IN6_V4MAPPED_TO_INADDR(v6addrp, &v4addr);
744*1071d9ffSAndy Fiddaman 			} else {
745*1071d9ffSAndy Fiddaman 				(void) memcpy(&v6addr.s6_addr,
746*1071d9ffSAndy Fiddaman 				    hp->h_addr_list[i],
747*1071d9ffSAndy Fiddaman 				    sizeof (struct in6_addr));
7487c478bd9Sstevel@tonic-gate 			}
749*1071d9ffSAndy Fiddaman 		} else if (hp->h_addrtype == AF_INET) {
7507c478bd9Sstevel@tonic-gate 			create_v6_addrinfo = B_FALSE;
751*1071d9ffSAndy Fiddaman 			(void) memcpy(&v4addr.s_addr, hp->h_addr_list[i],
7527c478bd9Sstevel@tonic-gate 			    sizeof (struct in_addr));
7537c478bd9Sstevel@tonic-gate 		} else {
7547c478bd9Sstevel@tonic-gate 			return (EAI_SYSTEM);
7557c478bd9Sstevel@tonic-gate 		}
7567c478bd9Sstevel@tonic-gate 
757*1071d9ffSAndy Fiddaman 		for (j = 0; j < nport; j++) {
758*1071d9ffSAndy Fiddaman 			if (create_v6_addrinfo) {
759*1071d9ffSAndy Fiddaman 				errnum = add_address6(aip, &cur, &v6addr,
760*1071d9ffSAndy Fiddaman 				    zonestr, firsttime ? hp->h_name : NULL,
761*1071d9ffSAndy Fiddaman 				    &ports[j]);
7627c478bd9Sstevel@tonic-gate 			} else {
763*1071d9ffSAndy Fiddaman 				errnum = add_address4(aip, &cur, &v4addr,
764*1071d9ffSAndy Fiddaman 				    firsttime ? hp->h_name : NULL,
765*1071d9ffSAndy Fiddaman 				    &ports[j]);
7667c478bd9Sstevel@tonic-gate 			}
767*1071d9ffSAndy Fiddaman 			firsttime = B_FALSE;
768*1071d9ffSAndy Fiddaman 			if (errnum != 0) {
769*1071d9ffSAndy Fiddaman 				freehostent(hp);
770*1071d9ffSAndy Fiddaman 				return (errnum);
7717c478bd9Sstevel@tonic-gate 			}
7727c478bd9Sstevel@tonic-gate 		}
7737c478bd9Sstevel@tonic-gate 	}
7747c478bd9Sstevel@tonic-gate 	freehostent(hp);
7757c478bd9Sstevel@tonic-gate 	return (0);
7767c478bd9Sstevel@tonic-gate }
7777c478bd9Sstevel@tonic-gate 
7787c478bd9Sstevel@tonic-gate /*
7797c478bd9Sstevel@tonic-gate  * getscopeidfromzone(sa, zone, sin6_scope_id)
7807c478bd9Sstevel@tonic-gate  *
7817c478bd9Sstevel@tonic-gate  * Converts the string pointed to by 'zone' into a sin6_scope_id.
7827c478bd9Sstevel@tonic-gate  * 'zone' will either be a pointer to an interface name or will
7837c478bd9Sstevel@tonic-gate  * be a literal sin6_scope_id.
7847c478bd9Sstevel@tonic-gate  *
7857c478bd9Sstevel@tonic-gate  * 0 is returned on success and the output parameter 'sin6_scope_id' will
7867c478bd9Sstevel@tonic-gate  *   be set to a valid sin6_scope_id.
7877c478bd9Sstevel@tonic-gate  * EAI_NONAME is returned for either of two reasons:
7887c478bd9Sstevel@tonic-gate  *	1.  The IPv6 address pointed to by sa->sin6_addr is not
7897c478bd9Sstevel@tonic-gate  *	    part of the 'link scope' (ie link local, nodelocal multicast or
7907c478bd9Sstevel@tonic-gate  *	    linklocal multicast address)
7917c478bd9Sstevel@tonic-gate  *	2.  The string pointed to by 'zone' can not be translate to a valid
7927c478bd9Sstevel@tonic-gate  *	    sin6_scope_id.
7937c478bd9Sstevel@tonic-gate  */
7947c478bd9Sstevel@tonic-gate static uint_t
getscopeidfromzone(const struct sockaddr_in6 * sa,const char * zone,uint32_t * sin6_scope_id)7957c478bd9Sstevel@tonic-gate getscopeidfromzone(const struct sockaddr_in6 *sa, const char *zone,
796*1071d9ffSAndy Fiddaman     uint32_t *sin6_scope_id)
797*1071d9ffSAndy Fiddaman {
7987c478bd9Sstevel@tonic-gate 	const in6_addr_t *addr = &sa->sin6_addr;
7997c478bd9Sstevel@tonic-gate 	ulong_t ul_scope_id;
8007c478bd9Sstevel@tonic-gate 	char *endp;
8017c478bd9Sstevel@tonic-gate 
8027c478bd9Sstevel@tonic-gate 	if (IN6_IS_ADDR_LINKSCOPE(addr)) {
8037c478bd9Sstevel@tonic-gate 		/*
8047c478bd9Sstevel@tonic-gate 		 * Look up interface index associated with interface name
8057c478bd9Sstevel@tonic-gate 		 * pointed to by 'zone'.  Since the address is part of the link
8067c478bd9Sstevel@tonic-gate 		 * scope, there is a one-to-one relationship between interface
8077c478bd9Sstevel@tonic-gate 		 * index and sin6_scope_id.
8087c478bd9Sstevel@tonic-gate 		 * If an interface index can not be found for 'zone', then
8097c478bd9Sstevel@tonic-gate 		 * treat 'zone' as a literal sin6_scope_id value.
8107c478bd9Sstevel@tonic-gate 		 */
8117c478bd9Sstevel@tonic-gate 		if ((*sin6_scope_id = if_nametoindex(zone)) != 0) {
8127c478bd9Sstevel@tonic-gate 			return (0);
8137c478bd9Sstevel@tonic-gate 		} else {
8147c478bd9Sstevel@tonic-gate 			if ((ul_scope_id = strtoul(zone, &endp, 10)) != 0) {
8157c478bd9Sstevel@tonic-gate 				/* check that entire string was read */
8167c478bd9Sstevel@tonic-gate 				if (*endp != '\0') {
8177c478bd9Sstevel@tonic-gate 					return (EAI_NONAME);
8187c478bd9Sstevel@tonic-gate 				}
8197c478bd9Sstevel@tonic-gate 				*sin6_scope_id =
8207c478bd9Sstevel@tonic-gate 				    (uint32_t)(ul_scope_id & 0xffffffffUL);
8217c478bd9Sstevel@tonic-gate 			} else {
8227c478bd9Sstevel@tonic-gate 				return (EAI_NONAME);
8237c478bd9Sstevel@tonic-gate 			}
8247c478bd9Sstevel@tonic-gate 		}
8257c478bd9Sstevel@tonic-gate 	} else {
8267c478bd9Sstevel@tonic-gate 		return (EAI_NONAME);
8277c478bd9Sstevel@tonic-gate 	}
8287c478bd9Sstevel@tonic-gate 	return (0);
8297c478bd9Sstevel@tonic-gate }
8307c478bd9Sstevel@tonic-gate 
8317c478bd9Sstevel@tonic-gate void
freeaddrinfo(struct addrinfo * ai)8327c478bd9Sstevel@tonic-gate freeaddrinfo(struct addrinfo *ai)
8337c478bd9Sstevel@tonic-gate {
8347c478bd9Sstevel@tonic-gate 	struct addrinfo *next;
8357c478bd9Sstevel@tonic-gate 
8367c478bd9Sstevel@tonic-gate 	do {
8377c478bd9Sstevel@tonic-gate 		next = ai->ai_next;
838*1071d9ffSAndy Fiddaman 		free(ai->ai_canonname);
839*1071d9ffSAndy Fiddaman 		free(ai->ai_addr);
8407c478bd9Sstevel@tonic-gate 		free(ai);
8417c478bd9Sstevel@tonic-gate 		ai = next;
8427c478bd9Sstevel@tonic-gate 	} while (ai != NULL);
8437c478bd9Sstevel@tonic-gate }
8447c478bd9Sstevel@tonic-gate 
845*1071d9ffSAndy Fiddaman static void
servtype(const char * tag,int * type,int * proto)846*1071d9ffSAndy Fiddaman servtype(const char *tag, int *type, int *proto)
847*1071d9ffSAndy Fiddaman {
848*1071d9ffSAndy Fiddaman 	*type = *proto = 0;
849*1071d9ffSAndy Fiddaman 	if (strcmp(tag, "udp") == 0) {
850*1071d9ffSAndy Fiddaman 		*type = SOCK_DGRAM;
851*1071d9ffSAndy Fiddaman 		*proto = IPPROTO_UDP;
852*1071d9ffSAndy Fiddaman 	} else if (strcmp(tag, "tcp") == 0) {
853*1071d9ffSAndy Fiddaman 		*type = SOCK_STREAM;
854*1071d9ffSAndy Fiddaman 		*proto = IPPROTO_TCP;
855*1071d9ffSAndy Fiddaman 	} else if (strcmp(tag, "sctp") == 0) {
856*1071d9ffSAndy Fiddaman 		*type = SOCK_STREAM;
857*1071d9ffSAndy Fiddaman 		*proto = IPPROTO_SCTP;
858*1071d9ffSAndy Fiddaman 	}
859*1071d9ffSAndy Fiddaman }
860*1071d9ffSAndy Fiddaman 
8617c478bd9Sstevel@tonic-gate static boolean_t
str_isnumber(const char * p)8627c478bd9Sstevel@tonic-gate str_isnumber(const char *p)
8637c478bd9Sstevel@tonic-gate {
8647c478bd9Sstevel@tonic-gate 	char *q = (char *)p;
865*1071d9ffSAndy Fiddaman 	while (*q != '\0') {
8667c478bd9Sstevel@tonic-gate 		if (!isdigit(*q))
8677c478bd9Sstevel@tonic-gate 			return (B_FALSE);
8687c478bd9Sstevel@tonic-gate 		q++;
8697c478bd9Sstevel@tonic-gate 	}
8707c478bd9Sstevel@tonic-gate 	return (B_TRUE);
8717c478bd9Sstevel@tonic-gate }
872*1071d9ffSAndy Fiddaman 
8737c478bd9Sstevel@tonic-gate static const char *gai_errlist[] = {
8747c478bd9Sstevel@tonic-gate 	"name translation error 0 (no error)",		/* 0 */
8757c478bd9Sstevel@tonic-gate 	"specified address family not supported",	/* 1 EAI_ADDRFAMILY */
8767c478bd9Sstevel@tonic-gate 	"temporary name resolution failure",		/* 2 EAI_AGAIN */
8777c478bd9Sstevel@tonic-gate 	"invalid flags",				/* 3 EAI_BADFLAGS */
8787c478bd9Sstevel@tonic-gate 	"non-recoverable name resolution failure",	/* 4 EAI_FAIL */
8797c478bd9Sstevel@tonic-gate 	"specified address family not supported",	/* 5 EAI_FAMILY */
8807c478bd9Sstevel@tonic-gate 	"memory allocation failure",			/* 6 EAI_MEMORY */
8817c478bd9Sstevel@tonic-gate 	"no address for the specified node name",	/* 7 EAI_NODATA */
8827c478bd9Sstevel@tonic-gate 	"node name or service name not known",		/* 8 EAI_NONAME */
8837c478bd9Sstevel@tonic-gate 	"service name not available for the specified socket type",
8847c478bd9Sstevel@tonic-gate 							/* 9 EAI_SERVICE */
8857c478bd9Sstevel@tonic-gate 	"specified socket type not supported",		/* 10 EAI_SOCKTYPE */
8867c478bd9Sstevel@tonic-gate 	"system error",					/* 11 EAI_SYSTEM */
8877c478bd9Sstevel@tonic-gate };
8887c478bd9Sstevel@tonic-gate static int gai_nerr = { sizeof (gai_errlist)/sizeof (gai_errlist[0]) };
8897c478bd9Sstevel@tonic-gate 
8907c478bd9Sstevel@tonic-gate const char *
gai_strerror(int ecode)8917c478bd9Sstevel@tonic-gate gai_strerror(int ecode)
8927c478bd9Sstevel@tonic-gate {
8937c478bd9Sstevel@tonic-gate 	if (ecode < 0)
8947257d1b4Sraf 		return (dgettext(TEXT_DOMAIN,
8957c478bd9Sstevel@tonic-gate 		    "name translation internal error"));
8967c478bd9Sstevel@tonic-gate 	else if (ecode < gai_nerr)
8977257d1b4Sraf 		return (dgettext(TEXT_DOMAIN, gai_errlist[ecode]));
8987257d1b4Sraf 	return (dgettext(TEXT_DOMAIN, "unknown name translation error"));
8997c478bd9Sstevel@tonic-gate }
900