xref: /titanic_52/usr/src/lib/libsocket/inet/getaddrinfo.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate 
23*7c478bd9Sstevel@tonic-gate /*
24*7c478bd9Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
25*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
26*7c478bd9Sstevel@tonic-gate  */
27*7c478bd9Sstevel@tonic-gate 
28*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
29*7c478bd9Sstevel@tonic-gate 
30*7c478bd9Sstevel@tonic-gate 
31*7c478bd9Sstevel@tonic-gate #include <netdb.h>
32*7c478bd9Sstevel@tonic-gate #include <arpa/inet.h>
33*7c478bd9Sstevel@tonic-gate #include <nss_dbdefs.h>
34*7c478bd9Sstevel@tonic-gate #include <netinet/in.h>
35*7c478bd9Sstevel@tonic-gate #include <sys/socket.h>
36*7c478bd9Sstevel@tonic-gate #include <string.h>
37*7c478bd9Sstevel@tonic-gate #include <strings.h>
38*7c478bd9Sstevel@tonic-gate #include <stdio.h>
39*7c478bd9Sstevel@tonic-gate #include <ctype.h>
40*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
41*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
42*7c478bd9Sstevel@tonic-gate #include <net/if.h>
43*7c478bd9Sstevel@tonic-gate 
44*7c478bd9Sstevel@tonic-gate extern char *_dgettext(const char *, const char *);
45*7c478bd9Sstevel@tonic-gate 
46*7c478bd9Sstevel@tonic-gate #define	ai2sin(x)	((struct sockaddr_in *)((x)->ai_addr))
47*7c478bd9Sstevel@tonic-gate #define	ai2sin6(x)	((struct sockaddr_in6 *)((x)->ai_addr))
48*7c478bd9Sstevel@tonic-gate 
49*7c478bd9Sstevel@tonic-gate #define	HOST_BROADCAST	"255.255.255.255"
50*7c478bd9Sstevel@tonic-gate 
51*7c478bd9Sstevel@tonic-gate /*
52*7c478bd9Sstevel@tonic-gate  * getaddrinfo() returns EAI_NONAME in some cases, however
53*7c478bd9Sstevel@tonic-gate  * since EAI_NONAME is not part of SUSv3 it needed to be
54*7c478bd9Sstevel@tonic-gate  * masked in the standards compliant environment.
55*7c478bd9Sstevel@tonic-gate  * GAIV_DEFAULT and GAIV_XPG6 accomplish this.
56*7c478bd9Sstevel@tonic-gate  */
57*7c478bd9Sstevel@tonic-gate #define	GAIV_DEFAULT	0
58*7c478bd9Sstevel@tonic-gate #define	GAIV_XPG6	1
59*7c478bd9Sstevel@tonic-gate 
60*7c478bd9Sstevel@tonic-gate /*
61*7c478bd9Sstevel@tonic-gate  * Storage allocation for global variables in6addr_any and
62*7c478bd9Sstevel@tonic-gate  * in6addr_loopback.  The extern declarations for these
63*7c478bd9Sstevel@tonic-gate  * variables are defined in <netinet/in.h>.  These two
64*7c478bd9Sstevel@tonic-gate  * variables could have been defined in any of the "C" files
65*7c478bd9Sstevel@tonic-gate  * in libsocket. They are defined here with other IPv6
66*7c478bd9Sstevel@tonic-gate  * related interfaces.
67*7c478bd9Sstevel@tonic-gate  */
68*7c478bd9Sstevel@tonic-gate const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT;
69*7c478bd9Sstevel@tonic-gate const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT;
70*7c478bd9Sstevel@tonic-gate 
71*7c478bd9Sstevel@tonic-gate /* AI_MASK:  all valid flags for addrinfo */
72*7c478bd9Sstevel@tonic-gate #define	AI_MASK		(AI_PASSIVE | AI_CANONNAME | AI_NUMERICHOST \
73*7c478bd9Sstevel@tonic-gate 	| AI_ADDRCONFIG | AI_NUMERICSERV | AI_V4MAPPED | AI_ALL)
74*7c478bd9Sstevel@tonic-gate #define	ANY		0
75*7c478bd9Sstevel@tonic-gate /* function prototypes for used by getaddrinfo() routine */
76*7c478bd9Sstevel@tonic-gate static int get_addr(int family, const char *hostname, struct addrinfo *aip,
77*7c478bd9Sstevel@tonic-gate 	struct addrinfo *cur, ushort_t port, int version);
78*7c478bd9Sstevel@tonic-gate static uint_t getscopeidfromzone(const struct sockaddr_in6 *sa,
79*7c478bd9Sstevel@tonic-gate     const char *zone, uint32_t *sin6_scope_id);
80*7c478bd9Sstevel@tonic-gate static boolean_t str_isnumber(const char *p);
81*7c478bd9Sstevel@tonic-gate 
82*7c478bd9Sstevel@tonic-gate /*
83*7c478bd9Sstevel@tonic-gate  * getaddrinfo:
84*7c478bd9Sstevel@tonic-gate  *
85*7c478bd9Sstevel@tonic-gate  * Purpose:
86*7c478bd9Sstevel@tonic-gate  *   Routine for performing Address-to-nodename in a
87*7c478bd9Sstevel@tonic-gate  *   protocol-independent fashion.
88*7c478bd9Sstevel@tonic-gate  * Description and history of the routine:
89*7c478bd9Sstevel@tonic-gate  *   Nodename-to-address translation is done in a protocol-
90*7c478bd9Sstevel@tonic-gate  *   independent fashion using the getaddrinfo() function
91*7c478bd9Sstevel@tonic-gate  *   that is taken from the IEEE POSIX 1003.1g.
92*7c478bd9Sstevel@tonic-gate  *
93*7c478bd9Sstevel@tonic-gate  *   The official specification for this function will be the
94*7c478bd9Sstevel@tonic-gate  *   final POSIX standard, with the following additional
95*7c478bd9Sstevel@tonic-gate  *   requirements:
96*7c478bd9Sstevel@tonic-gate  *
97*7c478bd9Sstevel@tonic-gate  *   - getaddrinfo() must be thread safe
98*7c478bd9Sstevel@tonic-gate  *   - The AI_NUMERICHOST is new.
99*7c478bd9Sstevel@tonic-gate  *   - All fields in socket address structures returned by
100*7c478bd9Sstevel@tonic-gate  *
101*7c478bd9Sstevel@tonic-gate  *  getaddrinfo() that are not filled in through an explicit
102*7c478bd9Sstevel@tonic-gate  *  argument (e.g., sin6_flowinfo and sin_zero) must be set to 0.
103*7c478bd9Sstevel@tonic-gate  *  (This makes it easier to compare socket address structures).
104*7c478bd9Sstevel@tonic-gate  *
105*7c478bd9Sstevel@tonic-gate  * Input Parameters:
106*7c478bd9Sstevel@tonic-gate  *  nodename  - pointer to null-terminated strings that represents
107*7c478bd9Sstevel@tonic-gate  *              a hostname or literal ip address (IPv4/IPv6) or this
108*7c478bd9Sstevel@tonic-gate  *              pointer can be NULL.
109*7c478bd9Sstevel@tonic-gate  *  servname  - pointer to null-terminated strings that represents
110*7c478bd9Sstevel@tonic-gate  *              a servicename or literal port number or this
111*7c478bd9Sstevel@tonic-gate  *              pointer can be NULL.
112*7c478bd9Sstevel@tonic-gate  *  hints     - optional argument that points to an addrinfo structure
113*7c478bd9Sstevel@tonic-gate  *              to provide hints on the type of socket that the caller
114*7c478bd9Sstevel@tonic-gate  *              supports.
115*7c478bd9Sstevel@tonic-gate  *   Possible setting of the ai_flags member of the hints structure:
116*7c478bd9Sstevel@tonic-gate  *   AI_PASSIVE -     If set, the caller plans to use the returned socket
117*7c478bd9Sstevel@tonic-gate  *                    address in a call to bind().  In this case, it the
118*7c478bd9Sstevel@tonic-gate  *                    nodename argument is NULL, then the IP address portion
119*7c478bd9Sstevel@tonic-gate  *                    of the socket address structure will be set to
120*7c478bd9Sstevel@tonic-gate  *                    INADDR_ANY for IPv4 or IN6ADDR_ANY_INIT for IPv6.
121*7c478bd9Sstevel@tonic-gate  *   AI_PASSIVE -     If not set, then the returned socket address will be
122*7c478bd9Sstevel@tonic-gate  *                    ready for a call to connect() (for conn-oriented) or
123*7c478bd9Sstevel@tonic-gate  *                    connect(), sendto(), or sendmsg() (for connectionless).
124*7c478bd9Sstevel@tonic-gate  *                    In this case, if nodename is NULL, then the IP address
125*7c478bd9Sstevel@tonic-gate  *                    portion of the socket address structure will be set to
126*7c478bd9Sstevel@tonic-gate  *                    the loopback address.
127*7c478bd9Sstevel@tonic-gate  *   AI_CANONNAME -   If set, then upon successful return the ai_canonname
128*7c478bd9Sstevel@tonic-gate  *                    field of the first addrinfo structure in the linked
129*7c478bd9Sstevel@tonic-gate  *                    list will point to a NULL-terminated string
130*7c478bd9Sstevel@tonic-gate  *                    containing the canonical name of the specified nodename.
131*7c478bd9Sstevel@tonic-gate  *   AI_NUMERICHOST - If set, then a non-NULL nodename string must be a numeric
132*7c478bd9Sstevel@tonic-gate  *                    host address string.  Otherwise an error of EAI_NONAME
133*7c478bd9Sstevel@tonic-gate  *                    is returned.  This flag prevents any type of name
134*7c478bd9Sstevel@tonic-gate  *                    resolution service from being called.
135*7c478bd9Sstevel@tonic-gate  *   AI_NUMERICSERV - If set, then a non-null servname string supplied shall
136*7c478bd9Sstevel@tonic-gate  *                    be a numeric port string. Otherwise, an [EAI_NONAME]
137*7c478bd9Sstevel@tonic-gate  *                    error shall be returned. This flag shall prevent any
138*7c478bd9Sstevel@tonic-gate  *                    type of name resolution service from being invoked.
139*7c478bd9Sstevel@tonic-gate  *   AI_V4MAPPED -    If set, along with an ai_family of AF_INET6, then
140*7c478bd9Sstevel@tonic-gate  *                    getaddrinfo() shall return IPv4-mapped IPv6 addresses
141*7c478bd9Sstevel@tonic-gate  *                    on finding no matching IPv6 addresses ( ai_addrlen shall
142*7c478bd9Sstevel@tonic-gate  *                    be 16). The AI_V4MAPPED flag shall be ignored unless
143*7c478bd9Sstevel@tonic-gate  *                    ai_family equals AF_INET6.
144*7c478bd9Sstevel@tonic-gate  *   AI_ALL -	      If the AI_ALL flag is used with the AI_V4MAPPED flag,
145*7c478bd9Sstevel@tonic-gate  *		      then getaddrinfo() shall return all matching IPv6 and
146*7c478bd9Sstevel@tonic-gate  *		      IPv4 addresses. The AI_ALL flag without the AI_V4MAPPED
147*7c478bd9Sstevel@tonic-gate  *		      flag is ignored.
148*7c478bd9Sstevel@tonic-gate  * Output Parameters:
149*7c478bd9Sstevel@tonic-gate  *  res       - upon successful return a pointer to a linked list of one
150*7c478bd9Sstevel@tonic-gate  *              or more addrinfo structures is returned through this
151*7c478bd9Sstevel@tonic-gate  *              argument.  The caller can process each addrinfo structures
152*7c478bd9Sstevel@tonic-gate  *              in this list by following the ai_next pointer, until a
153*7c478bd9Sstevel@tonic-gate  *              NULL pointer is encountered.  In each returned addrinfo
154*7c478bd9Sstevel@tonic-gate  *              structure the three members ai_family, ai_socktype, and
155*7c478bd9Sstevel@tonic-gate  *              ai_protocol are corresponding arguments for a call to the
156*7c478bd9Sstevel@tonic-gate  *              socket() function.  In each addrinfo structure the ai_addr
157*7c478bd9Sstevel@tonic-gate  *              field points to filled-in socket address structure whose
158*7c478bd9Sstevel@tonic-gate  *              length is specified by the ai_addrlen member.
159*7c478bd9Sstevel@tonic-gate  *
160*7c478bd9Sstevel@tonic-gate  * Return Value:
161*7c478bd9Sstevel@tonic-gate  *  This function returns 0 upon success or a nonzero error code.  The
162*7c478bd9Sstevel@tonic-gate  *  following names are nonzero error codes from getaddrinfo(), and are
163*7c478bd9Sstevel@tonic-gate  *  defined in <netdb.h>.
164*7c478bd9Sstevel@tonic-gate  *  EAI_ADDRFAMILY - address family not supported
165*7c478bd9Sstevel@tonic-gate  *  EAI_AGAIN      - DNS temporary failure
166*7c478bd9Sstevel@tonic-gate  *  EAI_BADFLAGS   - invalid ai_flags
167*7c478bd9Sstevel@tonic-gate  *  EAI_FAIL       - DNS non-recoverable failure
168*7c478bd9Sstevel@tonic-gate  *  EAI_FAMILY     - ai_family not supported
169*7c478bd9Sstevel@tonic-gate  *  EAI_MEMORY     - memory allocation failure
170*7c478bd9Sstevel@tonic-gate  *  EAI_NODATA     - no address associated with nodename
171*7c478bd9Sstevel@tonic-gate  *  EAI_NONAME     - host/servname not known
172*7c478bd9Sstevel@tonic-gate  *  EAI_SERVICE    - servname not supported for ai_socktype
173*7c478bd9Sstevel@tonic-gate  *  EAI_SOCKTYPE   - ai_socktype not supported
174*7c478bd9Sstevel@tonic-gate  *  EAI_SYSTEM     - system error in errno
175*7c478bd9Sstevel@tonic-gate  *
176*7c478bd9Sstevel@tonic-gate  * Memory Allocation:
177*7c478bd9Sstevel@tonic-gate  *  All of the information returned by getaddrinfo() is dynamically
178*7c478bd9Sstevel@tonic-gate  *  allocated:  the addrinfo structures, and the socket address
179*7c478bd9Sstevel@tonic-gate  *  structures and canonical node name strings pointed to by the
180*7c478bd9Sstevel@tonic-gate  *  addrinfo structures.
181*7c478bd9Sstevel@tonic-gate  */
182*7c478bd9Sstevel@tonic-gate 
183*7c478bd9Sstevel@tonic-gate 
184*7c478bd9Sstevel@tonic-gate static int
185*7c478bd9Sstevel@tonic-gate _getaddrinfo(const char *hostname, const char *servname,
186*7c478bd9Sstevel@tonic-gate 	const struct addrinfo *hints, struct addrinfo **res, int version)
187*7c478bd9Sstevel@tonic-gate {
188*7c478bd9Sstevel@tonic-gate 	struct addrinfo *cur;
189*7c478bd9Sstevel@tonic-gate 	struct addrinfo *aip;
190*7c478bd9Sstevel@tonic-gate 	struct addrinfo ai;
191*7c478bd9Sstevel@tonic-gate 	int		error;
192*7c478bd9Sstevel@tonic-gate 	ushort_t	port;
193*7c478bd9Sstevel@tonic-gate 
194*7c478bd9Sstevel@tonic-gate 	cur = &ai;
195*7c478bd9Sstevel@tonic-gate 	aip = &ai;
196*7c478bd9Sstevel@tonic-gate 
197*7c478bd9Sstevel@tonic-gate 	aip->ai_flags = 0;
198*7c478bd9Sstevel@tonic-gate 	aip->ai_family = PF_UNSPEC;
199*7c478bd9Sstevel@tonic-gate 	aip->ai_socktype = 0;
200*7c478bd9Sstevel@tonic-gate 	aip->ai_protocol = 0;
201*7c478bd9Sstevel@tonic-gate #ifdef __sparcv9
202*7c478bd9Sstevel@tonic-gate 	/*
203*7c478bd9Sstevel@tonic-gate 	 * We need to clear _ai_pad to preserve binary
204*7c478bd9Sstevel@tonic-gate 	 * compatibility with previously compiled 64-bit
205*7c478bd9Sstevel@tonic-gate 	 * applications by guaranteeing the upper 32-bits
206*7c478bd9Sstevel@tonic-gate 	 * are empty.
207*7c478bd9Sstevel@tonic-gate 	 */
208*7c478bd9Sstevel@tonic-gate 	aip->_ai_pad = 0;
209*7c478bd9Sstevel@tonic-gate #endif /* __sparcv9 */
210*7c478bd9Sstevel@tonic-gate 	aip->ai_addrlen = 0;
211*7c478bd9Sstevel@tonic-gate 	aip->ai_canonname = NULL;
212*7c478bd9Sstevel@tonic-gate 	aip->ai_addr = NULL;
213*7c478bd9Sstevel@tonic-gate 	aip->ai_next = NULL;
214*7c478bd9Sstevel@tonic-gate 	port = 0;
215*7c478bd9Sstevel@tonic-gate 
216*7c478bd9Sstevel@tonic-gate 	/* if nodename nor servname provided */
217*7c478bd9Sstevel@tonic-gate 	if (hostname == NULL && servname == NULL) {
218*7c478bd9Sstevel@tonic-gate 		*res = NULL;
219*7c478bd9Sstevel@tonic-gate 		return (EAI_NONAME);
220*7c478bd9Sstevel@tonic-gate 	}
221*7c478bd9Sstevel@tonic-gate 	if (hints != NULL) {
222*7c478bd9Sstevel@tonic-gate 		/* check for bad flags in hints */
223*7c478bd9Sstevel@tonic-gate 		if ((hints->ai_flags != 0) && (hints->ai_flags & ~AI_MASK)) {
224*7c478bd9Sstevel@tonic-gate 			*res = NULL;
225*7c478bd9Sstevel@tonic-gate 			return (EAI_BADFLAGS);
226*7c478bd9Sstevel@tonic-gate 		}
227*7c478bd9Sstevel@tonic-gate 		if ((hostname == NULL || *hostname == '\0') &&
228*7c478bd9Sstevel@tonic-gate 			(hints->ai_flags & AI_CANONNAME)) {
229*7c478bd9Sstevel@tonic-gate 				*res = NULL;
230*7c478bd9Sstevel@tonic-gate 				return (EAI_BADFLAGS);
231*7c478bd9Sstevel@tonic-gate 		}
232*7c478bd9Sstevel@tonic-gate 		if (hints->ai_family != PF_UNSPEC &&
233*7c478bd9Sstevel@tonic-gate 		    hints->ai_family != PF_INET &&
234*7c478bd9Sstevel@tonic-gate 		    hints->ai_family != PF_INET6) {
235*7c478bd9Sstevel@tonic-gate 			*res = NULL;
236*7c478bd9Sstevel@tonic-gate 			return (EAI_FAMILY);
237*7c478bd9Sstevel@tonic-gate 		}
238*7c478bd9Sstevel@tonic-gate 
239*7c478bd9Sstevel@tonic-gate 		(void) memcpy(aip, hints, sizeof (*aip));
240*7c478bd9Sstevel@tonic-gate #ifdef __sparcv9
241*7c478bd9Sstevel@tonic-gate 		/*
242*7c478bd9Sstevel@tonic-gate 		 * We need to clear _ai_pad to preserve binary
243*7c478bd9Sstevel@tonic-gate 		 * compatibility.  See prior comment.
244*7c478bd9Sstevel@tonic-gate 		 */
245*7c478bd9Sstevel@tonic-gate 		aip->_ai_pad = 0;
246*7c478bd9Sstevel@tonic-gate #endif /* __sparcv9 */
247*7c478bd9Sstevel@tonic-gate 		switch (aip->ai_socktype) {
248*7c478bd9Sstevel@tonic-gate 		case ANY:
249*7c478bd9Sstevel@tonic-gate 			switch (aip->ai_protocol) {
250*7c478bd9Sstevel@tonic-gate 			case ANY:
251*7c478bd9Sstevel@tonic-gate 				break;
252*7c478bd9Sstevel@tonic-gate 			case IPPROTO_UDP:
253*7c478bd9Sstevel@tonic-gate 				aip->ai_socktype = SOCK_DGRAM;
254*7c478bd9Sstevel@tonic-gate 				break;
255*7c478bd9Sstevel@tonic-gate 			case IPPROTO_TCP:
256*7c478bd9Sstevel@tonic-gate 				aip->ai_socktype = SOCK_STREAM;
257*7c478bd9Sstevel@tonic-gate 				break;
258*7c478bd9Sstevel@tonic-gate 			default:
259*7c478bd9Sstevel@tonic-gate 				aip->ai_socktype = SOCK_RAW;
260*7c478bd9Sstevel@tonic-gate 				break;
261*7c478bd9Sstevel@tonic-gate 			}
262*7c478bd9Sstevel@tonic-gate 			break;
263*7c478bd9Sstevel@tonic-gate 		case SOCK_RAW:
264*7c478bd9Sstevel@tonic-gate 			break;
265*7c478bd9Sstevel@tonic-gate 		case SOCK_DGRAM:
266*7c478bd9Sstevel@tonic-gate 			aip->ai_protocol = IPPROTO_UDP;
267*7c478bd9Sstevel@tonic-gate 			break;
268*7c478bd9Sstevel@tonic-gate 		case SOCK_STREAM:
269*7c478bd9Sstevel@tonic-gate 			aip->ai_protocol = IPPROTO_TCP;
270*7c478bd9Sstevel@tonic-gate 			break;
271*7c478bd9Sstevel@tonic-gate 		default:
272*7c478bd9Sstevel@tonic-gate 			*res = NULL;
273*7c478bd9Sstevel@tonic-gate 			return (EAI_SOCKTYPE);
274*7c478bd9Sstevel@tonic-gate 		}
275*7c478bd9Sstevel@tonic-gate 	}
276*7c478bd9Sstevel@tonic-gate 
277*7c478bd9Sstevel@tonic-gate 	/*
278*7c478bd9Sstevel@tonic-gate 	 *  Get the service.
279*7c478bd9Sstevel@tonic-gate 	 */
280*7c478bd9Sstevel@tonic-gate 
281*7c478bd9Sstevel@tonic-gate 	if (servname != NULL) {
282*7c478bd9Sstevel@tonic-gate 		struct servent result;
283*7c478bd9Sstevel@tonic-gate 		int bufsize = 128;
284*7c478bd9Sstevel@tonic-gate 		char *buf = NULL;
285*7c478bd9Sstevel@tonic-gate 		struct servent *sp;
286*7c478bd9Sstevel@tonic-gate 		char *proto = NULL;
287*7c478bd9Sstevel@tonic-gate 
288*7c478bd9Sstevel@tonic-gate 		switch (aip->ai_socktype) {
289*7c478bd9Sstevel@tonic-gate 		case ANY:
290*7c478bd9Sstevel@tonic-gate 			proto = NULL;
291*7c478bd9Sstevel@tonic-gate 			break;
292*7c478bd9Sstevel@tonic-gate 		case SOCK_DGRAM:
293*7c478bd9Sstevel@tonic-gate 			proto = "udp";
294*7c478bd9Sstevel@tonic-gate 			break;
295*7c478bd9Sstevel@tonic-gate 		case SOCK_STREAM:
296*7c478bd9Sstevel@tonic-gate 			proto = "tcp";
297*7c478bd9Sstevel@tonic-gate 			break;
298*7c478bd9Sstevel@tonic-gate 		}
299*7c478bd9Sstevel@tonic-gate 		/*
300*7c478bd9Sstevel@tonic-gate 		 * Servname string can be a decimal port number.
301*7c478bd9Sstevel@tonic-gate 		 * If we already know the socket type there is no need
302*7c478bd9Sstevel@tonic-gate 		 * to call getservbyport.
303*7c478bd9Sstevel@tonic-gate 		 */
304*7c478bd9Sstevel@tonic-gate 		if (aip->ai_flags & AI_NUMERICSERV) {
305*7c478bd9Sstevel@tonic-gate 			if (!str_isnumber(servname)) {
306*7c478bd9Sstevel@tonic-gate 				return (EAI_NONAME);
307*7c478bd9Sstevel@tonic-gate 			}
308*7c478bd9Sstevel@tonic-gate 			port = htons(atoi(servname));
309*7c478bd9Sstevel@tonic-gate 		} else if (str_isnumber(servname)) {
310*7c478bd9Sstevel@tonic-gate 			port = htons(atoi(servname));
311*7c478bd9Sstevel@tonic-gate 			if (aip->ai_socktype == ANY) {
312*7c478bd9Sstevel@tonic-gate 				do {
313*7c478bd9Sstevel@tonic-gate 					if (buf != NULL)
314*7c478bd9Sstevel@tonic-gate 						free(buf);
315*7c478bd9Sstevel@tonic-gate 					bufsize *= 2;
316*7c478bd9Sstevel@tonic-gate 					buf = malloc(bufsize);
317*7c478bd9Sstevel@tonic-gate 					if (buf == NULL) {
318*7c478bd9Sstevel@tonic-gate 						*res = NULL;
319*7c478bd9Sstevel@tonic-gate 						return (EAI_MEMORY);
320*7c478bd9Sstevel@tonic-gate 					}
321*7c478bd9Sstevel@tonic-gate 
322*7c478bd9Sstevel@tonic-gate 					sp = getservbyport_r(port, proto,
323*7c478bd9Sstevel@tonic-gate 					    &result, buf, bufsize);
324*7c478bd9Sstevel@tonic-gate 					if (sp == NULL && errno != ERANGE) {
325*7c478bd9Sstevel@tonic-gate 						free(buf);
326*7c478bd9Sstevel@tonic-gate 						*res = NULL;
327*7c478bd9Sstevel@tonic-gate 						return (EAI_SERVICE);
328*7c478bd9Sstevel@tonic-gate 					}
329*7c478bd9Sstevel@tonic-gate 				/*
330*7c478bd9Sstevel@tonic-gate 				 * errno == ERANGE so our scratch buffer space
331*7c478bd9Sstevel@tonic-gate 				 * wasn't big enough.  Double it and try
332*7c478bd9Sstevel@tonic-gate 				 * again.
333*7c478bd9Sstevel@tonic-gate 				 */
334*7c478bd9Sstevel@tonic-gate 				} while (sp == NULL);
335*7c478bd9Sstevel@tonic-gate 			}
336*7c478bd9Sstevel@tonic-gate 		} else {
337*7c478bd9Sstevel@tonic-gate 			do {
338*7c478bd9Sstevel@tonic-gate 				if (buf != NULL)
339*7c478bd9Sstevel@tonic-gate 					free(buf);
340*7c478bd9Sstevel@tonic-gate 				bufsize *= 2;
341*7c478bd9Sstevel@tonic-gate 				buf = malloc(bufsize);
342*7c478bd9Sstevel@tonic-gate 				if (buf == NULL) {
343*7c478bd9Sstevel@tonic-gate 					*res = NULL;
344*7c478bd9Sstevel@tonic-gate 					return (EAI_MEMORY);
345*7c478bd9Sstevel@tonic-gate 				}
346*7c478bd9Sstevel@tonic-gate 
347*7c478bd9Sstevel@tonic-gate 				sp = getservbyname_r(servname, proto, &result,
348*7c478bd9Sstevel@tonic-gate 				    buf, bufsize);
349*7c478bd9Sstevel@tonic-gate 				if (sp == NULL && errno != ERANGE) {
350*7c478bd9Sstevel@tonic-gate 					free(buf);
351*7c478bd9Sstevel@tonic-gate 					*res = NULL;
352*7c478bd9Sstevel@tonic-gate 					return (EAI_SERVICE);
353*7c478bd9Sstevel@tonic-gate 				}
354*7c478bd9Sstevel@tonic-gate 			/*
355*7c478bd9Sstevel@tonic-gate 			 * errno == ERANGE so our scratch buffer space wasn't
356*7c478bd9Sstevel@tonic-gate 			 * big enough.  Double it and try again.
357*7c478bd9Sstevel@tonic-gate 			 */
358*7c478bd9Sstevel@tonic-gate 			} while (sp == NULL);
359*7c478bd9Sstevel@tonic-gate 
360*7c478bd9Sstevel@tonic-gate 			port = sp->s_port;
361*7c478bd9Sstevel@tonic-gate 		}
362*7c478bd9Sstevel@tonic-gate 		if (aip->ai_socktype == ANY) {
363*7c478bd9Sstevel@tonic-gate 			if (aip->ai_flags & AI_NUMERICSERV) {
364*7c478bd9Sstevel@tonic-gate 				/*
365*7c478bd9Sstevel@tonic-gate 				 * RFC 2553bis doesn't allow us to use the
366*7c478bd9Sstevel@tonic-gate 				 * any resolver to find out if there is a
367*7c478bd9Sstevel@tonic-gate 				 * match.  We could walk the service file
368*7c478bd9Sstevel@tonic-gate 				 * with *servent().  Given the commonality of
369*7c478bd9Sstevel@tonic-gate 				 * calling getaddrinfo() with a number and
370*7c478bd9Sstevel@tonic-gate 				 * ANY protocol we won't add that at this time.
371*7c478bd9Sstevel@tonic-gate 				 */
372*7c478bd9Sstevel@tonic-gate 				return (EAI_NONAME);
373*7c478bd9Sstevel@tonic-gate 			}
374*7c478bd9Sstevel@tonic-gate 
375*7c478bd9Sstevel@tonic-gate 			if (strcmp(sp->s_proto, "udp") == 0) {
376*7c478bd9Sstevel@tonic-gate 				aip->ai_socktype = SOCK_DGRAM;
377*7c478bd9Sstevel@tonic-gate 				aip->ai_protocol = IPPROTO_UDP;
378*7c478bd9Sstevel@tonic-gate 			} else if (strcmp(sp->s_proto, "tcp") == 0) {
379*7c478bd9Sstevel@tonic-gate 				aip->ai_socktype = SOCK_STREAM;
380*7c478bd9Sstevel@tonic-gate 				aip->ai_protocol = IPPROTO_TCP;
381*7c478bd9Sstevel@tonic-gate 			} else {
382*7c478bd9Sstevel@tonic-gate 				if (buf != NULL)
383*7c478bd9Sstevel@tonic-gate 					free(buf);
384*7c478bd9Sstevel@tonic-gate 
385*7c478bd9Sstevel@tonic-gate 				*res = NULL;
386*7c478bd9Sstevel@tonic-gate 				errno = EPROTONOSUPPORT;
387*7c478bd9Sstevel@tonic-gate 				return (EAI_SYSTEM);
388*7c478bd9Sstevel@tonic-gate 			}
389*7c478bd9Sstevel@tonic-gate 		}
390*7c478bd9Sstevel@tonic-gate 
391*7c478bd9Sstevel@tonic-gate 		if (buf != NULL)
392*7c478bd9Sstevel@tonic-gate 			free(buf);
393*7c478bd9Sstevel@tonic-gate 	}
394*7c478bd9Sstevel@tonic-gate 
395*7c478bd9Sstevel@tonic-gate 	/*
396*7c478bd9Sstevel@tonic-gate 	 * hostname is NULL
397*7c478bd9Sstevel@tonic-gate 	 * case 1: AI_PASSIVE bit set : anyaddr 0.0.0.0 or ::
398*7c478bd9Sstevel@tonic-gate 	 * case 2: AI_PASSIVE bit not set : localhost 127.0.0.1 or ::1
399*7c478bd9Sstevel@tonic-gate 	 */
400*7c478bd9Sstevel@tonic-gate 
401*7c478bd9Sstevel@tonic-gate 	if (hostname == NULL) {
402*7c478bd9Sstevel@tonic-gate 		struct addrinfo *nai;
403*7c478bd9Sstevel@tonic-gate 		socklen_t addrlen;
404*7c478bd9Sstevel@tonic-gate 		char *canonname;
405*7c478bd9Sstevel@tonic-gate 
406*7c478bd9Sstevel@tonic-gate 		if (aip->ai_family == PF_INET)
407*7c478bd9Sstevel@tonic-gate 			goto v4only;
408*7c478bd9Sstevel@tonic-gate 		/* create IPv6 addrinfo */
409*7c478bd9Sstevel@tonic-gate 		nai = malloc(sizeof (struct addrinfo));
410*7c478bd9Sstevel@tonic-gate 		if (nai == NULL)
411*7c478bd9Sstevel@tonic-gate 			goto nomem;
412*7c478bd9Sstevel@tonic-gate 		*nai = *aip;
413*7c478bd9Sstevel@tonic-gate 		addrlen = sizeof (struct sockaddr_in6);
414*7c478bd9Sstevel@tonic-gate 		nai->ai_addr = malloc(addrlen);
415*7c478bd9Sstevel@tonic-gate 		if (nai->ai_addr == NULL) {
416*7c478bd9Sstevel@tonic-gate 			freeaddrinfo(nai);
417*7c478bd9Sstevel@tonic-gate 			goto nomem;
418*7c478bd9Sstevel@tonic-gate 		}
419*7c478bd9Sstevel@tonic-gate 		bzero(nai->ai_addr, addrlen);
420*7c478bd9Sstevel@tonic-gate 		nai->ai_addrlen = addrlen;
421*7c478bd9Sstevel@tonic-gate 		nai->ai_family = PF_INET6;
422*7c478bd9Sstevel@tonic-gate 		nai->ai_protocol = 0;
423*7c478bd9Sstevel@tonic-gate 		nai->ai_canonname = NULL;
424*7c478bd9Sstevel@tonic-gate 		if (nai->ai_flags & AI_PASSIVE) {
425*7c478bd9Sstevel@tonic-gate 			ai2sin6(nai)->sin6_addr = in6addr_any;
426*7c478bd9Sstevel@tonic-gate 		} else {
427*7c478bd9Sstevel@tonic-gate 			ai2sin6(nai)->sin6_addr = in6addr_loopback;
428*7c478bd9Sstevel@tonic-gate 			if (nai->ai_flags & AI_CANONNAME) {
429*7c478bd9Sstevel@tonic-gate 				canonname = strdup("loopback");
430*7c478bd9Sstevel@tonic-gate 				if (canonname == NULL) {
431*7c478bd9Sstevel@tonic-gate 					freeaddrinfo(nai);
432*7c478bd9Sstevel@tonic-gate 					goto nomem;
433*7c478bd9Sstevel@tonic-gate 				}
434*7c478bd9Sstevel@tonic-gate 				nai->ai_canonname = canonname;
435*7c478bd9Sstevel@tonic-gate 			}
436*7c478bd9Sstevel@tonic-gate 		}
437*7c478bd9Sstevel@tonic-gate 		ai2sin6(nai)->sin6_family = PF_INET6;
438*7c478bd9Sstevel@tonic-gate 		ai2sin6(nai)->sin6_port = port;
439*7c478bd9Sstevel@tonic-gate 		cur->ai_next = nai;
440*7c478bd9Sstevel@tonic-gate 		cur = nai;
441*7c478bd9Sstevel@tonic-gate 		if (aip->ai_family == PF_INET6) {
442*7c478bd9Sstevel@tonic-gate 			cur->ai_next = NULL;
443*7c478bd9Sstevel@tonic-gate 			goto success;
444*7c478bd9Sstevel@tonic-gate 		}
445*7c478bd9Sstevel@tonic-gate 		/* If address family is PF_UNSPEC or PF_INET */
446*7c478bd9Sstevel@tonic-gate v4only:
447*7c478bd9Sstevel@tonic-gate 		/* create IPv4 addrinfo */
448*7c478bd9Sstevel@tonic-gate 		nai = malloc(sizeof (struct addrinfo));
449*7c478bd9Sstevel@tonic-gate 		if (nai == NULL)
450*7c478bd9Sstevel@tonic-gate 			goto nomem;
451*7c478bd9Sstevel@tonic-gate 		*nai = *aip;
452*7c478bd9Sstevel@tonic-gate 		addrlen = sizeof (struct sockaddr_in);
453*7c478bd9Sstevel@tonic-gate 		nai->ai_addr = malloc(addrlen);
454*7c478bd9Sstevel@tonic-gate 		if (nai->ai_addr == NULL) {
455*7c478bd9Sstevel@tonic-gate 			freeaddrinfo(nai);
456*7c478bd9Sstevel@tonic-gate 			goto nomem;
457*7c478bd9Sstevel@tonic-gate 		}
458*7c478bd9Sstevel@tonic-gate 		bzero(nai->ai_addr, addrlen);
459*7c478bd9Sstevel@tonic-gate 		nai->ai_addrlen = addrlen;
460*7c478bd9Sstevel@tonic-gate 		nai->ai_family = PF_INET;
461*7c478bd9Sstevel@tonic-gate 		nai->ai_protocol = 0;
462*7c478bd9Sstevel@tonic-gate 		nai->ai_canonname = NULL;
463*7c478bd9Sstevel@tonic-gate 		if (nai->ai_flags & AI_PASSIVE) {
464*7c478bd9Sstevel@tonic-gate 			ai2sin(nai)->sin_addr.s_addr = INADDR_ANY;
465*7c478bd9Sstevel@tonic-gate 		} else {
466*7c478bd9Sstevel@tonic-gate 			ai2sin(nai)->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
467*7c478bd9Sstevel@tonic-gate 			if (nai->ai_flags & AI_CANONNAME &&
468*7c478bd9Sstevel@tonic-gate 			    nai->ai_family != PF_UNSPEC) {
469*7c478bd9Sstevel@tonic-gate 				canonname = strdup("loopback");
470*7c478bd9Sstevel@tonic-gate 				if (canonname == NULL) {
471*7c478bd9Sstevel@tonic-gate 					freeaddrinfo(nai);
472*7c478bd9Sstevel@tonic-gate 					goto nomem;
473*7c478bd9Sstevel@tonic-gate 				}
474*7c478bd9Sstevel@tonic-gate 				nai->ai_canonname = canonname;
475*7c478bd9Sstevel@tonic-gate 			}
476*7c478bd9Sstevel@tonic-gate 		}
477*7c478bd9Sstevel@tonic-gate 		ai2sin(nai)->sin_family = PF_INET;
478*7c478bd9Sstevel@tonic-gate 		ai2sin(nai)->sin_port = port;
479*7c478bd9Sstevel@tonic-gate 		cur->ai_next = nai;
480*7c478bd9Sstevel@tonic-gate 		cur = nai;
481*7c478bd9Sstevel@tonic-gate 		cur->ai_next = NULL;
482*7c478bd9Sstevel@tonic-gate 		goto success;
483*7c478bd9Sstevel@tonic-gate 	}
484*7c478bd9Sstevel@tonic-gate 
485*7c478bd9Sstevel@tonic-gate 	/* hostname string is a literal address or an alphabetical name */
486*7c478bd9Sstevel@tonic-gate 	error = get_addr(aip->ai_family, hostname, aip, cur, port, version);
487*7c478bd9Sstevel@tonic-gate 	if (error) {
488*7c478bd9Sstevel@tonic-gate 		*res = NULL;
489*7c478bd9Sstevel@tonic-gate 		return (error);
490*7c478bd9Sstevel@tonic-gate 	}
491*7c478bd9Sstevel@tonic-gate 
492*7c478bd9Sstevel@tonic-gate success:
493*7c478bd9Sstevel@tonic-gate 	*res = aip->ai_next;
494*7c478bd9Sstevel@tonic-gate 	return (0);
495*7c478bd9Sstevel@tonic-gate 
496*7c478bd9Sstevel@tonic-gate nomem:
497*7c478bd9Sstevel@tonic-gate 	return (EAI_MEMORY);
498*7c478bd9Sstevel@tonic-gate }
499*7c478bd9Sstevel@tonic-gate 
500*7c478bd9Sstevel@tonic-gate int
501*7c478bd9Sstevel@tonic-gate getaddrinfo(const char *hostname, const char *servname,
502*7c478bd9Sstevel@tonic-gate 	const struct addrinfo *hints, struct addrinfo **res)
503*7c478bd9Sstevel@tonic-gate {
504*7c478bd9Sstevel@tonic-gate 	return (_getaddrinfo(hostname, servname, hints, res, GAIV_DEFAULT));
505*7c478bd9Sstevel@tonic-gate }
506*7c478bd9Sstevel@tonic-gate 
507*7c478bd9Sstevel@tonic-gate int
508*7c478bd9Sstevel@tonic-gate __xnet_getaddrinfo(const char *hostname, const char *servname,
509*7c478bd9Sstevel@tonic-gate 	const struct addrinfo *hints, struct addrinfo **res)
510*7c478bd9Sstevel@tonic-gate {
511*7c478bd9Sstevel@tonic-gate 	return (_getaddrinfo(hostname, servname, hints, res, GAIV_XPG6));
512*7c478bd9Sstevel@tonic-gate }
513*7c478bd9Sstevel@tonic-gate 
514*7c478bd9Sstevel@tonic-gate static int
515*7c478bd9Sstevel@tonic-gate get_addr(int family, const char *hostname, struct addrinfo *aip, struct
516*7c478bd9Sstevel@tonic-gate 	addrinfo *cur, ushort_t port, int version)
517*7c478bd9Sstevel@tonic-gate {
518*7c478bd9Sstevel@tonic-gate 	struct hostent		*hp;
519*7c478bd9Sstevel@tonic-gate 	char			_hostname[MAXHOSTNAMELEN];
520*7c478bd9Sstevel@tonic-gate 	int			i, errnum;
521*7c478bd9Sstevel@tonic-gate 	struct addrinfo		*nai;
522*7c478bd9Sstevel@tonic-gate 	int			addrlen;
523*7c478bd9Sstevel@tonic-gate 	char			*canonname;
524*7c478bd9Sstevel@tonic-gate 	boolean_t		firsttime = B_TRUE;
525*7c478bd9Sstevel@tonic-gate 	boolean_t		create_v6_addrinfo;
526*7c478bd9Sstevel@tonic-gate 	struct in_addr		v4addr;
527*7c478bd9Sstevel@tonic-gate 	struct in6_addr		v6addr;
528*7c478bd9Sstevel@tonic-gate 	struct in6_addr		*v6addrp;
529*7c478bd9Sstevel@tonic-gate 	char			*zonestr = NULL;
530*7c478bd9Sstevel@tonic-gate 
531*7c478bd9Sstevel@tonic-gate 	/*
532*7c478bd9Sstevel@tonic-gate 	 * Check for existence of address-zoneid delimiter '%'
533*7c478bd9Sstevel@tonic-gate 	 * If the delimiter exists, parse the zoneid portion of
534*7c478bd9Sstevel@tonic-gate 	 * <addr>%<zone_id>
535*7c478bd9Sstevel@tonic-gate 	 */
536*7c478bd9Sstevel@tonic-gate 	if ((zonestr = strchr(hostname, '%')) != NULL) {
537*7c478bd9Sstevel@tonic-gate 		/* make sure we have room for <addr> portion of hostname */
538*7c478bd9Sstevel@tonic-gate 		if (((zonestr - hostname) + 1) > sizeof (_hostname)) {
539*7c478bd9Sstevel@tonic-gate 			return (EAI_MEMORY);
540*7c478bd9Sstevel@tonic-gate 		}
541*7c478bd9Sstevel@tonic-gate 
542*7c478bd9Sstevel@tonic-gate 		/* chop off and save <zone_id> portion */
543*7c478bd9Sstevel@tonic-gate 		(void) strlcpy(_hostname, hostname, (zonestr - hostname) + 1);
544*7c478bd9Sstevel@tonic-gate 		++zonestr;	/* make zonestr point at start of <zone-id> */
545*7c478bd9Sstevel@tonic-gate 		/* ensure zone is valid */
546*7c478bd9Sstevel@tonic-gate 		if ((*zonestr == '\0') || (strlen(zonestr) > LIFNAMSIZ))  {
547*7c478bd9Sstevel@tonic-gate 			return (EAI_NONAME);
548*7c478bd9Sstevel@tonic-gate 		}
549*7c478bd9Sstevel@tonic-gate 	} else {
550*7c478bd9Sstevel@tonic-gate 		size_t hlen = sizeof (_hostname);
551*7c478bd9Sstevel@tonic-gate 
552*7c478bd9Sstevel@tonic-gate 		if (strlcpy(_hostname, hostname, hlen) >= hlen) {
553*7c478bd9Sstevel@tonic-gate 			return (EAI_MEMORY);
554*7c478bd9Sstevel@tonic-gate 		}
555*7c478bd9Sstevel@tonic-gate 	}
556*7c478bd9Sstevel@tonic-gate 
557*7c478bd9Sstevel@tonic-gate 	/* Check to see if AI_NUMERICHOST bit is set */
558*7c478bd9Sstevel@tonic-gate 	if (aip->ai_flags & AI_NUMERICHOST) {
559*7c478bd9Sstevel@tonic-gate 		/* check to see if _hostname points to a literal IP address */
560*7c478bd9Sstevel@tonic-gate 		if (!((inet_addr(_hostname) != ((in_addr_t)-1)) ||
561*7c478bd9Sstevel@tonic-gate 		    (strcmp(_hostname, HOST_BROADCAST) == 0) ||
562*7c478bd9Sstevel@tonic-gate 		    (inet_pton(AF_INET6, _hostname, &v6addr) > 0))) {
563*7c478bd9Sstevel@tonic-gate 			return (EAI_NONAME);
564*7c478bd9Sstevel@tonic-gate 		}
565*7c478bd9Sstevel@tonic-gate 	}
566*7c478bd9Sstevel@tonic-gate 
567*7c478bd9Sstevel@tonic-gate 	/* if hostname argument is literal, name service doesn't get called */
568*7c478bd9Sstevel@tonic-gate 	if (family == PF_UNSPEC) {
569*7c478bd9Sstevel@tonic-gate 		hp = getipnodebyname(_hostname, AF_INET6, AI_ALL |
570*7c478bd9Sstevel@tonic-gate 		    aip->ai_flags | AI_V4MAPPED, &errnum);
571*7c478bd9Sstevel@tonic-gate 	} else {
572*7c478bd9Sstevel@tonic-gate 		hp = getipnodebyname(_hostname, family, aip->ai_flags, &errnum);
573*7c478bd9Sstevel@tonic-gate 	}
574*7c478bd9Sstevel@tonic-gate 
575*7c478bd9Sstevel@tonic-gate 	if (hp == NULL) {
576*7c478bd9Sstevel@tonic-gate 		switch (errnum) {
577*7c478bd9Sstevel@tonic-gate 		case HOST_NOT_FOUND:
578*7c478bd9Sstevel@tonic-gate 			return (EAI_NONAME);
579*7c478bd9Sstevel@tonic-gate 		case TRY_AGAIN:
580*7c478bd9Sstevel@tonic-gate 			return (EAI_AGAIN);
581*7c478bd9Sstevel@tonic-gate 		case NO_RECOVERY:
582*7c478bd9Sstevel@tonic-gate 			return (EAI_FAIL);
583*7c478bd9Sstevel@tonic-gate 		case NO_ADDRESS:
584*7c478bd9Sstevel@tonic-gate 			if (version == GAIV_XPG6)
585*7c478bd9Sstevel@tonic-gate 				return (EAI_NONAME);
586*7c478bd9Sstevel@tonic-gate 			return (EAI_NODATA);
587*7c478bd9Sstevel@tonic-gate 		default:
588*7c478bd9Sstevel@tonic-gate 		return (EAI_SYSTEM);
589*7c478bd9Sstevel@tonic-gate 		}
590*7c478bd9Sstevel@tonic-gate 	}
591*7c478bd9Sstevel@tonic-gate 
592*7c478bd9Sstevel@tonic-gate 	for (i = 0; hp->h_addr_list[i]; i++) {
593*7c478bd9Sstevel@tonic-gate 		/* Determine if an IPv6 addrinfo structure should be created */
594*7c478bd9Sstevel@tonic-gate 		create_v6_addrinfo = B_TRUE;
595*7c478bd9Sstevel@tonic-gate 		if (hp->h_addrtype == AF_INET6) {
596*7c478bd9Sstevel@tonic-gate 			v6addrp = (struct in6_addr *)hp->h_addr_list[i];
597*7c478bd9Sstevel@tonic-gate 			if (!(aip->ai_flags & AI_V4MAPPED) &&
598*7c478bd9Sstevel@tonic-gate 			    IN6_IS_ADDR_V4MAPPED(v6addrp)) {
599*7c478bd9Sstevel@tonic-gate 				create_v6_addrinfo = B_FALSE;
600*7c478bd9Sstevel@tonic-gate 				IN6_V4MAPPED_TO_INADDR(v6addrp, &v4addr);
601*7c478bd9Sstevel@tonic-gate 			}
602*7c478bd9Sstevel@tonic-gate 		} else	if (hp->h_addrtype == AF_INET) {
603*7c478bd9Sstevel@tonic-gate 			create_v6_addrinfo = B_FALSE;
604*7c478bd9Sstevel@tonic-gate 			(void) memcpy(&v4addr, hp->h_addr_list[i],
605*7c478bd9Sstevel@tonic-gate 			    sizeof (struct in_addr));
606*7c478bd9Sstevel@tonic-gate 		} else {
607*7c478bd9Sstevel@tonic-gate 			return (EAI_SYSTEM);
608*7c478bd9Sstevel@tonic-gate 		}
609*7c478bd9Sstevel@tonic-gate 
610*7c478bd9Sstevel@tonic-gate 		if (create_v6_addrinfo) {
611*7c478bd9Sstevel@tonic-gate 			/* create IPv6 addrinfo */
612*7c478bd9Sstevel@tonic-gate 			nai = malloc(sizeof (struct addrinfo));
613*7c478bd9Sstevel@tonic-gate 			if (nai == NULL)
614*7c478bd9Sstevel@tonic-gate 				goto nomem;
615*7c478bd9Sstevel@tonic-gate 			*nai = *aip;
616*7c478bd9Sstevel@tonic-gate 			addrlen = sizeof (struct sockaddr_in6);
617*7c478bd9Sstevel@tonic-gate 			nai->ai_addr = malloc(addrlen);
618*7c478bd9Sstevel@tonic-gate 			if (nai->ai_addr == NULL) {
619*7c478bd9Sstevel@tonic-gate 				freeaddrinfo(nai);
620*7c478bd9Sstevel@tonic-gate 				goto nomem;
621*7c478bd9Sstevel@tonic-gate 			}
622*7c478bd9Sstevel@tonic-gate 			bzero(nai->ai_addr, addrlen);
623*7c478bd9Sstevel@tonic-gate 			nai->ai_addrlen = addrlen;
624*7c478bd9Sstevel@tonic-gate 			nai->ai_family = PF_INET6;
625*7c478bd9Sstevel@tonic-gate 			nai->ai_protocol = 0;
626*7c478bd9Sstevel@tonic-gate 
627*7c478bd9Sstevel@tonic-gate 			(void) memcpy(ai2sin6(nai)->sin6_addr.s6_addr,
628*7c478bd9Sstevel@tonic-gate 			    hp->h_addr_list[i], sizeof (struct in6_addr));
629*7c478bd9Sstevel@tonic-gate 			nai->ai_canonname = NULL;
630*7c478bd9Sstevel@tonic-gate 			if ((nai->ai_flags & AI_CANONNAME) && firsttime) {
631*7c478bd9Sstevel@tonic-gate 				canonname = strdup(hp->h_name);
632*7c478bd9Sstevel@tonic-gate 				if (canonname == NULL) {
633*7c478bd9Sstevel@tonic-gate 					freeaddrinfo(nai);
634*7c478bd9Sstevel@tonic-gate 					goto nomem;
635*7c478bd9Sstevel@tonic-gate 				}
636*7c478bd9Sstevel@tonic-gate 				nai->ai_canonname = canonname;
637*7c478bd9Sstevel@tonic-gate 				firsttime = B_FALSE;
638*7c478bd9Sstevel@tonic-gate 			}
639*7c478bd9Sstevel@tonic-gate 			ai2sin6(nai)->sin6_family = PF_INET6;
640*7c478bd9Sstevel@tonic-gate 			ai2sin6(nai)->sin6_port = port;
641*7c478bd9Sstevel@tonic-gate 			/* set sin6_scope_id */
642*7c478bd9Sstevel@tonic-gate 			if (zonestr != NULL) {
643*7c478bd9Sstevel@tonic-gate 				/*
644*7c478bd9Sstevel@tonic-gate 				 * Translate 'zonestr' into a valid
645*7c478bd9Sstevel@tonic-gate 				 * sin6_scope_id.
646*7c478bd9Sstevel@tonic-gate 				 */
647*7c478bd9Sstevel@tonic-gate 				if ((errnum =
648*7c478bd9Sstevel@tonic-gate 				    getscopeidfromzone(ai2sin6(nai), zonestr,
649*7c478bd9Sstevel@tonic-gate 					&ai2sin6(nai)->sin6_scope_id)) != 0) {
650*7c478bd9Sstevel@tonic-gate 					return (errnum);
651*7c478bd9Sstevel@tonic-gate 				}
652*7c478bd9Sstevel@tonic-gate 			} else {
653*7c478bd9Sstevel@tonic-gate 				ai2sin6(nai)->sin6_scope_id = 0;
654*7c478bd9Sstevel@tonic-gate 			}
655*7c478bd9Sstevel@tonic-gate 		} else {
656*7c478bd9Sstevel@tonic-gate 			/* create IPv4 addrinfo */
657*7c478bd9Sstevel@tonic-gate 			nai = malloc(sizeof (struct addrinfo));
658*7c478bd9Sstevel@tonic-gate 			if (nai == NULL)
659*7c478bd9Sstevel@tonic-gate 				goto nomem;
660*7c478bd9Sstevel@tonic-gate 			*nai = *aip;
661*7c478bd9Sstevel@tonic-gate 			addrlen = sizeof (struct sockaddr_in);
662*7c478bd9Sstevel@tonic-gate 			nai->ai_addr = malloc(addrlen);
663*7c478bd9Sstevel@tonic-gate 			if (nai->ai_addr == NULL) {
664*7c478bd9Sstevel@tonic-gate 				freeaddrinfo(nai);
665*7c478bd9Sstevel@tonic-gate 				goto nomem;
666*7c478bd9Sstevel@tonic-gate 			}
667*7c478bd9Sstevel@tonic-gate 			bzero(nai->ai_addr, addrlen);
668*7c478bd9Sstevel@tonic-gate 			nai->ai_addrlen = addrlen;
669*7c478bd9Sstevel@tonic-gate 			nai->ai_family = PF_INET;
670*7c478bd9Sstevel@tonic-gate 			nai->ai_protocol = 0;
671*7c478bd9Sstevel@tonic-gate 			(void) memcpy(&(ai2sin(nai)->sin_addr.s_addr),
672*7c478bd9Sstevel@tonic-gate 			    &v4addr, sizeof (struct in_addr));
673*7c478bd9Sstevel@tonic-gate 			nai->ai_canonname = NULL;
674*7c478bd9Sstevel@tonic-gate 			if (nai->ai_flags & AI_CANONNAME && firsttime) {
675*7c478bd9Sstevel@tonic-gate 				canonname = strdup(hp->h_name);
676*7c478bd9Sstevel@tonic-gate 				if (canonname == NULL) {
677*7c478bd9Sstevel@tonic-gate 					freeaddrinfo(nai);
678*7c478bd9Sstevel@tonic-gate 					goto nomem;
679*7c478bd9Sstevel@tonic-gate 				}
680*7c478bd9Sstevel@tonic-gate 				nai->ai_canonname = canonname;
681*7c478bd9Sstevel@tonic-gate 				firsttime = B_FALSE;
682*7c478bd9Sstevel@tonic-gate 			}
683*7c478bd9Sstevel@tonic-gate 			ai2sin(nai)->sin_family = PF_INET;
684*7c478bd9Sstevel@tonic-gate 			ai2sin(nai)->sin_port = port;
685*7c478bd9Sstevel@tonic-gate 		}
686*7c478bd9Sstevel@tonic-gate 
687*7c478bd9Sstevel@tonic-gate 		cur->ai_next = nai;
688*7c478bd9Sstevel@tonic-gate 		cur = nai;
689*7c478bd9Sstevel@tonic-gate 	}
690*7c478bd9Sstevel@tonic-gate 	cur->ai_next = NULL;
691*7c478bd9Sstevel@tonic-gate 	freehostent(hp);
692*7c478bd9Sstevel@tonic-gate 	return (0);
693*7c478bd9Sstevel@tonic-gate 
694*7c478bd9Sstevel@tonic-gate nomem:
695*7c478bd9Sstevel@tonic-gate 	freehostent(hp);
696*7c478bd9Sstevel@tonic-gate 	return (EAI_MEMORY);
697*7c478bd9Sstevel@tonic-gate 
698*7c478bd9Sstevel@tonic-gate }
699*7c478bd9Sstevel@tonic-gate 
700*7c478bd9Sstevel@tonic-gate /*
701*7c478bd9Sstevel@tonic-gate  * getscopeidfromzone(sa, zone, sin6_scope_id)
702*7c478bd9Sstevel@tonic-gate  *
703*7c478bd9Sstevel@tonic-gate  * Converts the string pointed to by 'zone' into a sin6_scope_id.
704*7c478bd9Sstevel@tonic-gate  * 'zone' will either be a pointer to an interface name or will
705*7c478bd9Sstevel@tonic-gate  * be a literal sin6_scope_id.
706*7c478bd9Sstevel@tonic-gate  *
707*7c478bd9Sstevel@tonic-gate  * 0 is returned on success and the output parameter 'sin6_scope_id' will
708*7c478bd9Sstevel@tonic-gate  *   be set to a valid sin6_scope_id.
709*7c478bd9Sstevel@tonic-gate  * EAI_NONAME is returned for either of two reasons:
710*7c478bd9Sstevel@tonic-gate  *	1.  The IPv6 address pointed to by sa->sin6_addr is not
711*7c478bd9Sstevel@tonic-gate  *	    part of the 'link scope' (ie link local, nodelocal multicast or
712*7c478bd9Sstevel@tonic-gate  *	    linklocal multicast address)
713*7c478bd9Sstevel@tonic-gate  *	2.  The string pointed to by 'zone' can not be translate to a valid
714*7c478bd9Sstevel@tonic-gate  *	    sin6_scope_id.
715*7c478bd9Sstevel@tonic-gate  */
716*7c478bd9Sstevel@tonic-gate static uint_t
717*7c478bd9Sstevel@tonic-gate getscopeidfromzone(const struct sockaddr_in6 *sa, const char *zone,
718*7c478bd9Sstevel@tonic-gate     uint32_t *sin6_scope_id) {
719*7c478bd9Sstevel@tonic-gate 	const in6_addr_t *addr = &sa->sin6_addr;
720*7c478bd9Sstevel@tonic-gate 	ulong_t ul_scope_id;
721*7c478bd9Sstevel@tonic-gate 	char *endp;
722*7c478bd9Sstevel@tonic-gate 
723*7c478bd9Sstevel@tonic-gate 	if (IN6_IS_ADDR_LINKSCOPE(addr)) {
724*7c478bd9Sstevel@tonic-gate 		/*
725*7c478bd9Sstevel@tonic-gate 		 * Look up interface index associated with interface name
726*7c478bd9Sstevel@tonic-gate 		 * pointed to by 'zone'.  Since the address is part of the link
727*7c478bd9Sstevel@tonic-gate 		 * scope, there is a one-to-one relationship between interface
728*7c478bd9Sstevel@tonic-gate 		 * index and sin6_scope_id.
729*7c478bd9Sstevel@tonic-gate 		 * If an interface index can not be found for 'zone', then
730*7c478bd9Sstevel@tonic-gate 		 * treat 'zone' as a literal sin6_scope_id value.
731*7c478bd9Sstevel@tonic-gate 		 */
732*7c478bd9Sstevel@tonic-gate 		if ((*sin6_scope_id = if_nametoindex(zone)) != 0) {
733*7c478bd9Sstevel@tonic-gate 			return (0);
734*7c478bd9Sstevel@tonic-gate 		} else {
735*7c478bd9Sstevel@tonic-gate 			if ((ul_scope_id = strtoul(zone, &endp, 10)) != 0) {
736*7c478bd9Sstevel@tonic-gate 				/* check that entire string was read */
737*7c478bd9Sstevel@tonic-gate 				if (*endp != '\0') {
738*7c478bd9Sstevel@tonic-gate 					return (EAI_NONAME);
739*7c478bd9Sstevel@tonic-gate 				}
740*7c478bd9Sstevel@tonic-gate 				*sin6_scope_id =
741*7c478bd9Sstevel@tonic-gate 				    (uint32_t)(ul_scope_id & 0xffffffffUL);
742*7c478bd9Sstevel@tonic-gate 			} else {
743*7c478bd9Sstevel@tonic-gate 				return (EAI_NONAME);
744*7c478bd9Sstevel@tonic-gate 			}
745*7c478bd9Sstevel@tonic-gate 		}
746*7c478bd9Sstevel@tonic-gate 	} else {
747*7c478bd9Sstevel@tonic-gate 		return (EAI_NONAME);
748*7c478bd9Sstevel@tonic-gate 	}
749*7c478bd9Sstevel@tonic-gate 	return (0);
750*7c478bd9Sstevel@tonic-gate }
751*7c478bd9Sstevel@tonic-gate 
752*7c478bd9Sstevel@tonic-gate 
753*7c478bd9Sstevel@tonic-gate void
754*7c478bd9Sstevel@tonic-gate freeaddrinfo(struct addrinfo *ai)
755*7c478bd9Sstevel@tonic-gate {
756*7c478bd9Sstevel@tonic-gate 	struct addrinfo *next;
757*7c478bd9Sstevel@tonic-gate 
758*7c478bd9Sstevel@tonic-gate 	do {
759*7c478bd9Sstevel@tonic-gate 		next = ai->ai_next;
760*7c478bd9Sstevel@tonic-gate 		if (ai->ai_canonname)
761*7c478bd9Sstevel@tonic-gate 			free(ai->ai_canonname);
762*7c478bd9Sstevel@tonic-gate 		if (ai->ai_addr)
763*7c478bd9Sstevel@tonic-gate 			free(ai->ai_addr);
764*7c478bd9Sstevel@tonic-gate 		free(ai);
765*7c478bd9Sstevel@tonic-gate 		ai = next;
766*7c478bd9Sstevel@tonic-gate 	} while (ai != NULL);
767*7c478bd9Sstevel@tonic-gate }
768*7c478bd9Sstevel@tonic-gate 
769*7c478bd9Sstevel@tonic-gate static boolean_t
770*7c478bd9Sstevel@tonic-gate str_isnumber(const char *p)
771*7c478bd9Sstevel@tonic-gate {
772*7c478bd9Sstevel@tonic-gate 	char *q = (char *)p;
773*7c478bd9Sstevel@tonic-gate 	while (*q) {
774*7c478bd9Sstevel@tonic-gate 		if (!isdigit(*q))
775*7c478bd9Sstevel@tonic-gate 			return (B_FALSE);
776*7c478bd9Sstevel@tonic-gate 		q++;
777*7c478bd9Sstevel@tonic-gate 	}
778*7c478bd9Sstevel@tonic-gate 	return (B_TRUE);
779*7c478bd9Sstevel@tonic-gate }
780*7c478bd9Sstevel@tonic-gate static const char *gai_errlist[] = {
781*7c478bd9Sstevel@tonic-gate 	"name translation error 0 (no error)",		/* 0 */
782*7c478bd9Sstevel@tonic-gate 	"specified address family not supported",	/* 1 EAI_ADDRFAMILY */
783*7c478bd9Sstevel@tonic-gate 	"temporary name resolution failure",		/* 2 EAI_AGAIN */
784*7c478bd9Sstevel@tonic-gate 	"invalid flags",				/* 3 EAI_BADFLAGS */
785*7c478bd9Sstevel@tonic-gate 	"non-recoverable name resolution failure",	/* 4 EAI_FAIL */
786*7c478bd9Sstevel@tonic-gate 	"specified address family not supported",	/* 5 EAI_FAMILY */
787*7c478bd9Sstevel@tonic-gate 	"memory allocation failure",			/* 6 EAI_MEMORY */
788*7c478bd9Sstevel@tonic-gate 	"no address for the specified node name",	/* 7 EAI_NODATA */
789*7c478bd9Sstevel@tonic-gate 	"node name or service name not known",		/* 8 EAI_NONAME */
790*7c478bd9Sstevel@tonic-gate 	"service name not available for the specified socket type",
791*7c478bd9Sstevel@tonic-gate 							/* 9 EAI_SERVICE */
792*7c478bd9Sstevel@tonic-gate 	"specified socket type not supported",		/* 10 EAI_SOCKTYPE */
793*7c478bd9Sstevel@tonic-gate 	"system error",					/* 11 EAI_SYSTEM */
794*7c478bd9Sstevel@tonic-gate };
795*7c478bd9Sstevel@tonic-gate static int gai_nerr = { sizeof (gai_errlist)/sizeof (gai_errlist[0]) };
796*7c478bd9Sstevel@tonic-gate 
797*7c478bd9Sstevel@tonic-gate const char *
798*7c478bd9Sstevel@tonic-gate gai_strerror(int ecode)
799*7c478bd9Sstevel@tonic-gate {
800*7c478bd9Sstevel@tonic-gate 	if (ecode < 0)
801*7c478bd9Sstevel@tonic-gate 		return (_dgettext(TEXT_DOMAIN,
802*7c478bd9Sstevel@tonic-gate 		    "name translation internal error"));
803*7c478bd9Sstevel@tonic-gate 	else if (ecode < gai_nerr)
804*7c478bd9Sstevel@tonic-gate 		return (_dgettext(TEXT_DOMAIN, gai_errlist[ecode]));
805*7c478bd9Sstevel@tonic-gate 	return (_dgettext(TEXT_DOMAIN, "unknown name translation error"));
806*7c478bd9Sstevel@tonic-gate }
807