xref: /titanic_51/usr/src/lib/libsocket/inet/getaddrinfo.c (revision 2f443e27e5988131d8b57bec58ee15f9227e0899)
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 
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate 
297c478bd9Sstevel@tonic-gate #include <netdb.h>
307c478bd9Sstevel@tonic-gate #include <arpa/inet.h>
317c478bd9Sstevel@tonic-gate #include <nss_dbdefs.h>
327c478bd9Sstevel@tonic-gate #include <netinet/in.h>
337c478bd9Sstevel@tonic-gate #include <sys/socket.h>
347c478bd9Sstevel@tonic-gate #include <string.h>
357c478bd9Sstevel@tonic-gate #include <strings.h>
367c478bd9Sstevel@tonic-gate #include <stdio.h>
377c478bd9Sstevel@tonic-gate #include <ctype.h>
387c478bd9Sstevel@tonic-gate #include <sys/types.h>
397c478bd9Sstevel@tonic-gate #include <stdlib.h>
407257d1b4Sraf #include <libintl.h>
417c478bd9Sstevel@tonic-gate #include <net/if.h>
427c478bd9Sstevel@tonic-gate 
437c478bd9Sstevel@tonic-gate #define	ai2sin(x)	((struct sockaddr_in *)((x)->ai_addr))
447c478bd9Sstevel@tonic-gate #define	ai2sin6(x)	((struct sockaddr_in6 *)((x)->ai_addr))
457c478bd9Sstevel@tonic-gate 
467c478bd9Sstevel@tonic-gate #define	HOST_BROADCAST	"255.255.255.255"
477c478bd9Sstevel@tonic-gate 
487c478bd9Sstevel@tonic-gate /*
497c478bd9Sstevel@tonic-gate  * getaddrinfo() returns EAI_NONAME in some cases, however
507c478bd9Sstevel@tonic-gate  * since EAI_NONAME is not part of SUSv3 it needed to be
517c478bd9Sstevel@tonic-gate  * masked in the standards compliant environment.
527c478bd9Sstevel@tonic-gate  * GAIV_DEFAULT and GAIV_XPG6 accomplish this.
537c478bd9Sstevel@tonic-gate  */
547c478bd9Sstevel@tonic-gate #define	GAIV_DEFAULT	0
557c478bd9Sstevel@tonic-gate #define	GAIV_XPG6	1
567c478bd9Sstevel@tonic-gate 
577c478bd9Sstevel@tonic-gate /*
587c478bd9Sstevel@tonic-gate  * Storage allocation for global variables in6addr_any and
597c478bd9Sstevel@tonic-gate  * in6addr_loopback.  The extern declarations for these
607c478bd9Sstevel@tonic-gate  * variables are defined in <netinet/in.h>.  These two
617c478bd9Sstevel@tonic-gate  * variables could have been defined in any of the "C" files
627c478bd9Sstevel@tonic-gate  * in libsocket. They are defined here with other IPv6
637c478bd9Sstevel@tonic-gate  * 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
72*2f443e27SRobert Mustacchi 
73*2f443e27SRobert Mustacchi /*
74*2f443e27SRobert Mustacchi  * This is a private, undocumented, flag that getaddrinfo() uses for
75*2f443e27SRobert Mustacchi  * getipnodebyname(). In the case of AI_ADDRCONFIG && AI_V4MAPPED, if there are
76*2f443e27SRobert Mustacchi  * no IPv6 addresses, getaddrinfo() should return non-IPv4 mapped addresses. On
77*2f443e27SRobert Mustacchi  * the flip side, getipnodebyname() is defined by RFC 2553 to explicitly do so.
78*2f443e27SRobert Mustacchi  * Therefore this private flag indicates to getaddrinfo that we shouldn't do
79*2f443e27SRobert Mustacchi  * this.
80*2f443e27SRobert Mustacchi  */
81*2f443e27SRobert Mustacchi #define	AI_ADDRINFO	0x8000
82*2f443e27SRobert Mustacchi 
837c478bd9Sstevel@tonic-gate /* function prototypes for used by getaddrinfo() routine */
847c478bd9Sstevel@tonic-gate static int get_addr(int family, const char *hostname, struct addrinfo *aip,
857c478bd9Sstevel@tonic-gate 	struct addrinfo *cur, ushort_t port, int version);
867c478bd9Sstevel@tonic-gate static uint_t getscopeidfromzone(const struct sockaddr_in6 *sa,
877c478bd9Sstevel@tonic-gate     const char *zone, uint32_t *sin6_scope_id);
887c478bd9Sstevel@tonic-gate static boolean_t str_isnumber(const char *p);
897c478bd9Sstevel@tonic-gate 
907c478bd9Sstevel@tonic-gate /*
917c478bd9Sstevel@tonic-gate  * getaddrinfo:
927c478bd9Sstevel@tonic-gate  *
937c478bd9Sstevel@tonic-gate  * Purpose:
947c478bd9Sstevel@tonic-gate  *   Routine for performing Address-to-nodename in a
957c478bd9Sstevel@tonic-gate  *   protocol-independent fashion.
967c478bd9Sstevel@tonic-gate  * Description and history of the routine:
977c478bd9Sstevel@tonic-gate  *   Nodename-to-address translation is done in a protocol-
987c478bd9Sstevel@tonic-gate  *   independent fashion using the getaddrinfo() function
997c478bd9Sstevel@tonic-gate  *   that is taken from the IEEE POSIX 1003.1g.
1007c478bd9Sstevel@tonic-gate  *
1017c478bd9Sstevel@tonic-gate  *   The official specification for this function will be the
1027c478bd9Sstevel@tonic-gate  *   final POSIX standard, with the following additional
1037c478bd9Sstevel@tonic-gate  *   requirements:
1047c478bd9Sstevel@tonic-gate  *
1057c478bd9Sstevel@tonic-gate  *   - getaddrinfo() must be thread safe
1067c478bd9Sstevel@tonic-gate  *   - The AI_NUMERICHOST is new.
1077c478bd9Sstevel@tonic-gate  *   - All fields in socket address structures returned by
1087c478bd9Sstevel@tonic-gate  *
1097c478bd9Sstevel@tonic-gate  *  getaddrinfo() that are not filled in through an explicit
1107c478bd9Sstevel@tonic-gate  *  argument (e.g., sin6_flowinfo and sin_zero) must be set to 0.
1117c478bd9Sstevel@tonic-gate  *  (This makes it easier to compare socket address structures).
1127c478bd9Sstevel@tonic-gate  *
1137c478bd9Sstevel@tonic-gate  * Input Parameters:
1147c478bd9Sstevel@tonic-gate  *  nodename  - pointer to null-terminated strings that represents
1157c478bd9Sstevel@tonic-gate  *              a hostname or literal ip address (IPv4/IPv6) or this
1167c478bd9Sstevel@tonic-gate  *              pointer can be NULL.
1177c478bd9Sstevel@tonic-gate  *  servname  - pointer to null-terminated strings that represents
1187c478bd9Sstevel@tonic-gate  *              a servicename or literal port number or this
1197c478bd9Sstevel@tonic-gate  *              pointer can be NULL.
1207c478bd9Sstevel@tonic-gate  *  hints     - optional argument that points to an addrinfo structure
1217c478bd9Sstevel@tonic-gate  *              to provide hints on the type of socket that the caller
1227c478bd9Sstevel@tonic-gate  *              supports.
1237c478bd9Sstevel@tonic-gate  *   Possible setting of the ai_flags member of the hints structure:
1247c478bd9Sstevel@tonic-gate  *   AI_PASSIVE -     If set, the caller plans to use the returned socket
1257c478bd9Sstevel@tonic-gate  *                    address in a call to bind().  In this case, it the
1267c478bd9Sstevel@tonic-gate  *                    nodename argument is NULL, then the IP address portion
1277c478bd9Sstevel@tonic-gate  *                    of the socket address structure will be set to
1287c478bd9Sstevel@tonic-gate  *                    INADDR_ANY for IPv4 or IN6ADDR_ANY_INIT for IPv6.
1297c478bd9Sstevel@tonic-gate  *   AI_PASSIVE -     If not set, then the returned socket address will be
1307c478bd9Sstevel@tonic-gate  *                    ready for a call to connect() (for conn-oriented) or
1317c478bd9Sstevel@tonic-gate  *                    connect(), sendto(), or sendmsg() (for connectionless).
1327c478bd9Sstevel@tonic-gate  *                    In this case, if nodename is NULL, then the IP address
1337c478bd9Sstevel@tonic-gate  *                    portion of the socket address structure will be set to
1347c478bd9Sstevel@tonic-gate  *                    the loopback address.
1357c478bd9Sstevel@tonic-gate  *   AI_CANONNAME -   If set, then upon successful return the ai_canonname
1367c478bd9Sstevel@tonic-gate  *                    field of the first addrinfo structure in the linked
1377c478bd9Sstevel@tonic-gate  *                    list will point to a NULL-terminated string
1387c478bd9Sstevel@tonic-gate  *                    containing the canonical name of the specified nodename.
1397c478bd9Sstevel@tonic-gate  *   AI_NUMERICHOST - If set, then a non-NULL nodename string must be a numeric
1407c478bd9Sstevel@tonic-gate  *                    host address string.  Otherwise an error of EAI_NONAME
1417c478bd9Sstevel@tonic-gate  *                    is returned.  This flag prevents any type of name
1427c478bd9Sstevel@tonic-gate  *                    resolution service from being called.
1437c478bd9Sstevel@tonic-gate  *   AI_NUMERICSERV - If set, then a non-null servname string supplied shall
1447c478bd9Sstevel@tonic-gate  *                    be a numeric port string. Otherwise, an [EAI_NONAME]
1457c478bd9Sstevel@tonic-gate  *                    error shall be returned. This flag shall prevent any
1467c478bd9Sstevel@tonic-gate  *                    type of name resolution service from being invoked.
1477c478bd9Sstevel@tonic-gate  *   AI_V4MAPPED -    If set, along with an ai_family of AF_INET6, then
1487c478bd9Sstevel@tonic-gate  *                    getaddrinfo() shall return IPv4-mapped IPv6 addresses
1497c478bd9Sstevel@tonic-gate  *                    on finding no matching IPv6 addresses ( ai_addrlen shall
1507c478bd9Sstevel@tonic-gate  *                    be 16). The AI_V4MAPPED flag shall be ignored unless
1517c478bd9Sstevel@tonic-gate  *                    ai_family equals AF_INET6.
1527c478bd9Sstevel@tonic-gate  *   AI_ALL -	      If the AI_ALL flag is used with the AI_V4MAPPED flag,
1537c478bd9Sstevel@tonic-gate  *		      then getaddrinfo() shall return all matching IPv6 and
1547c478bd9Sstevel@tonic-gate  *		      IPv4 addresses. The AI_ALL flag without the AI_V4MAPPED
1557c478bd9Sstevel@tonic-gate  *		      flag is ignored.
1567c478bd9Sstevel@tonic-gate  * Output Parameters:
1577c478bd9Sstevel@tonic-gate  *  res       - upon successful return a pointer to a linked list of one
1587c478bd9Sstevel@tonic-gate  *              or more addrinfo structures is returned through this
1597c478bd9Sstevel@tonic-gate  *              argument.  The caller can process each addrinfo structures
1607c478bd9Sstevel@tonic-gate  *              in this list by following the ai_next pointer, until a
1617c478bd9Sstevel@tonic-gate  *              NULL pointer is encountered.  In each returned addrinfo
1627c478bd9Sstevel@tonic-gate  *              structure the three members ai_family, ai_socktype, and
1637c478bd9Sstevel@tonic-gate  *              ai_protocol are corresponding arguments for a call to the
1647c478bd9Sstevel@tonic-gate  *              socket() function.  In each addrinfo structure the ai_addr
1657c478bd9Sstevel@tonic-gate  *              field points to filled-in socket address structure whose
1667c478bd9Sstevel@tonic-gate  *              length is specified by the ai_addrlen member.
1677c478bd9Sstevel@tonic-gate  *
1687c478bd9Sstevel@tonic-gate  * Return Value:
1697c478bd9Sstevel@tonic-gate  *  This function returns 0 upon success or a nonzero error code.  The
1707c478bd9Sstevel@tonic-gate  *  following names are nonzero error codes from getaddrinfo(), and are
1717c478bd9Sstevel@tonic-gate  *  defined in <netdb.h>.
1727c478bd9Sstevel@tonic-gate  *  EAI_ADDRFAMILY - address family not supported
1737c478bd9Sstevel@tonic-gate  *  EAI_AGAIN      - DNS temporary failure
1747c478bd9Sstevel@tonic-gate  *  EAI_BADFLAGS   - invalid ai_flags
1757c478bd9Sstevel@tonic-gate  *  EAI_FAIL       - DNS non-recoverable failure
1767c478bd9Sstevel@tonic-gate  *  EAI_FAMILY     - ai_family not supported
1777c478bd9Sstevel@tonic-gate  *  EAI_MEMORY     - memory allocation failure
1787c478bd9Sstevel@tonic-gate  *  EAI_NODATA     - no address associated with nodename
1797c478bd9Sstevel@tonic-gate  *  EAI_NONAME     - host/servname not known
1807c478bd9Sstevel@tonic-gate  *  EAI_SERVICE    - servname not supported for ai_socktype
1817c478bd9Sstevel@tonic-gate  *  EAI_SOCKTYPE   - ai_socktype not supported
1827c478bd9Sstevel@tonic-gate  *  EAI_SYSTEM     - system error in errno
1837c478bd9Sstevel@tonic-gate  *
1847c478bd9Sstevel@tonic-gate  * Memory Allocation:
1857c478bd9Sstevel@tonic-gate  *  All of the information returned by getaddrinfo() is dynamically
1867c478bd9Sstevel@tonic-gate  *  allocated:  the addrinfo structures, and the socket address
1877c478bd9Sstevel@tonic-gate  *  structures and canonical node name strings pointed to by the
1887c478bd9Sstevel@tonic-gate  *  addrinfo structures.
1897c478bd9Sstevel@tonic-gate  */
1907c478bd9Sstevel@tonic-gate 
1917c478bd9Sstevel@tonic-gate 
1927c478bd9Sstevel@tonic-gate static int
1937c478bd9Sstevel@tonic-gate _getaddrinfo(const char *hostname, const char *servname,
1947c478bd9Sstevel@tonic-gate 	const struct addrinfo *hints, struct addrinfo **res, int version)
1957c478bd9Sstevel@tonic-gate {
1967c478bd9Sstevel@tonic-gate 	struct addrinfo *cur;
1977c478bd9Sstevel@tonic-gate 	struct addrinfo *aip;
1987c478bd9Sstevel@tonic-gate 	struct addrinfo ai;
1997c478bd9Sstevel@tonic-gate 	int		error;
2007c478bd9Sstevel@tonic-gate 	ushort_t	port;
2017c478bd9Sstevel@tonic-gate 
2027c478bd9Sstevel@tonic-gate 	cur = &ai;
2037c478bd9Sstevel@tonic-gate 	aip = &ai;
2047c478bd9Sstevel@tonic-gate 
2057c478bd9Sstevel@tonic-gate 	aip->ai_flags = 0;
2067c478bd9Sstevel@tonic-gate 	aip->ai_family = PF_UNSPEC;
2077c478bd9Sstevel@tonic-gate 	aip->ai_socktype = 0;
2087c478bd9Sstevel@tonic-gate 	aip->ai_protocol = 0;
2097c478bd9Sstevel@tonic-gate #ifdef __sparcv9
2107c478bd9Sstevel@tonic-gate 	/*
2117c478bd9Sstevel@tonic-gate 	 * We need to clear _ai_pad to preserve binary
2127c478bd9Sstevel@tonic-gate 	 * compatibility with previously compiled 64-bit
2137c478bd9Sstevel@tonic-gate 	 * applications by guaranteeing the upper 32-bits
2147c478bd9Sstevel@tonic-gate 	 * are empty.
2157c478bd9Sstevel@tonic-gate 	 */
2167c478bd9Sstevel@tonic-gate 	aip->_ai_pad = 0;
2177c478bd9Sstevel@tonic-gate #endif /* __sparcv9 */
2187c478bd9Sstevel@tonic-gate 	aip->ai_addrlen = 0;
2197c478bd9Sstevel@tonic-gate 	aip->ai_canonname = NULL;
2207c478bd9Sstevel@tonic-gate 	aip->ai_addr = NULL;
2217c478bd9Sstevel@tonic-gate 	aip->ai_next = NULL;
2227c478bd9Sstevel@tonic-gate 	port = 0;
2237c478bd9Sstevel@tonic-gate 
2247c478bd9Sstevel@tonic-gate 	/* if nodename nor servname provided */
2257c478bd9Sstevel@tonic-gate 	if (hostname == NULL && servname == NULL) {
2267c478bd9Sstevel@tonic-gate 		*res = NULL;
2277c478bd9Sstevel@tonic-gate 		return (EAI_NONAME);
2287c478bd9Sstevel@tonic-gate 	}
2297c478bd9Sstevel@tonic-gate 	if (hints != NULL) {
2307c478bd9Sstevel@tonic-gate 		/* check for bad flags in hints */
2317c478bd9Sstevel@tonic-gate 		if ((hints->ai_flags != 0) && (hints->ai_flags & ~AI_MASK)) {
2327c478bd9Sstevel@tonic-gate 			*res = NULL;
2337c478bd9Sstevel@tonic-gate 			return (EAI_BADFLAGS);
2347c478bd9Sstevel@tonic-gate 		}
2357c478bd9Sstevel@tonic-gate 		if ((hostname == NULL || *hostname == '\0') &&
2367c478bd9Sstevel@tonic-gate 		    (hints->ai_flags & AI_CANONNAME)) {
2377c478bd9Sstevel@tonic-gate 				*res = NULL;
2387c478bd9Sstevel@tonic-gate 				return (EAI_BADFLAGS);
2397c478bd9Sstevel@tonic-gate 		}
2407c478bd9Sstevel@tonic-gate 		if (hints->ai_family != PF_UNSPEC &&
2417c478bd9Sstevel@tonic-gate 		    hints->ai_family != PF_INET &&
2427c478bd9Sstevel@tonic-gate 		    hints->ai_family != PF_INET6) {
2437c478bd9Sstevel@tonic-gate 			*res = NULL;
2447c478bd9Sstevel@tonic-gate 			return (EAI_FAMILY);
2457c478bd9Sstevel@tonic-gate 		}
2467c478bd9Sstevel@tonic-gate 
2477c478bd9Sstevel@tonic-gate 		(void) memcpy(aip, hints, sizeof (*aip));
2487c478bd9Sstevel@tonic-gate #ifdef __sparcv9
2497c478bd9Sstevel@tonic-gate 		/*
2507c478bd9Sstevel@tonic-gate 		 * We need to clear _ai_pad to preserve binary
2517c478bd9Sstevel@tonic-gate 		 * compatibility.  See prior comment.
2527c478bd9Sstevel@tonic-gate 		 */
2537c478bd9Sstevel@tonic-gate 		aip->_ai_pad = 0;
2547c478bd9Sstevel@tonic-gate #endif /* __sparcv9 */
2557c478bd9Sstevel@tonic-gate 		switch (aip->ai_socktype) {
2567c478bd9Sstevel@tonic-gate 		case ANY:
2577c478bd9Sstevel@tonic-gate 			switch (aip->ai_protocol) {
2587c478bd9Sstevel@tonic-gate 			case ANY:
2597c478bd9Sstevel@tonic-gate 				break;
2607c478bd9Sstevel@tonic-gate 			case IPPROTO_UDP:
2617c478bd9Sstevel@tonic-gate 				aip->ai_socktype = SOCK_DGRAM;
2627c478bd9Sstevel@tonic-gate 				break;
2637c478bd9Sstevel@tonic-gate 			case IPPROTO_TCP:
264558fbd03Skcpoon 			case IPPROTO_SCTP:
2657c478bd9Sstevel@tonic-gate 				aip->ai_socktype = SOCK_STREAM;
2667c478bd9Sstevel@tonic-gate 				break;
2677c478bd9Sstevel@tonic-gate 			default:
2687c478bd9Sstevel@tonic-gate 				aip->ai_socktype = SOCK_RAW;
2697c478bd9Sstevel@tonic-gate 				break;
2707c478bd9Sstevel@tonic-gate 			}
2717c478bd9Sstevel@tonic-gate 			break;
2727c478bd9Sstevel@tonic-gate 		case SOCK_RAW:
2737c478bd9Sstevel@tonic-gate 			break;
274558fbd03Skcpoon 		case SOCK_SEQPACKET:
275558fbd03Skcpoon 			/*
276558fbd03Skcpoon 			 * If the hint does not have a preference on the
277558fbd03Skcpoon 			 * protocol, use SCTP as the default for
278558fbd03Skcpoon 			 * SOCK_SEQPACKET.
279558fbd03Skcpoon 			 */
280558fbd03Skcpoon 			if (aip->ai_protocol == ANY)
281558fbd03Skcpoon 				aip->ai_protocol = IPPROTO_SCTP;
282558fbd03Skcpoon 			break;
2837c478bd9Sstevel@tonic-gate 		case SOCK_DGRAM:
2847c478bd9Sstevel@tonic-gate 			aip->ai_protocol = IPPROTO_UDP;
2857c478bd9Sstevel@tonic-gate 			break;
2867c478bd9Sstevel@tonic-gate 		case SOCK_STREAM:
287558fbd03Skcpoon 			/*
288558fbd03Skcpoon 			 * If the hint does not have a preference on the
289558fbd03Skcpoon 			 * protocol, use TCP as the default for SOCK_STREAM.
290558fbd03Skcpoon 			 */
291558fbd03Skcpoon 			if (aip->ai_protocol == ANY)
2927c478bd9Sstevel@tonic-gate 				aip->ai_protocol = IPPROTO_TCP;
2937c478bd9Sstevel@tonic-gate 			break;
2947c478bd9Sstevel@tonic-gate 		default:
2957c478bd9Sstevel@tonic-gate 			*res = NULL;
2967c478bd9Sstevel@tonic-gate 			return (EAI_SOCKTYPE);
2977c478bd9Sstevel@tonic-gate 		}
2987c478bd9Sstevel@tonic-gate 	}
2997c478bd9Sstevel@tonic-gate 
3007c478bd9Sstevel@tonic-gate 	/*
3017c478bd9Sstevel@tonic-gate 	 *  Get the service.
3027c478bd9Sstevel@tonic-gate 	 */
3037c478bd9Sstevel@tonic-gate 
3047c478bd9Sstevel@tonic-gate 	if (servname != NULL) {
3057c478bd9Sstevel@tonic-gate 		struct servent result;
3067c478bd9Sstevel@tonic-gate 		int bufsize = 128;
3077c478bd9Sstevel@tonic-gate 		char *buf = NULL;
3087c478bd9Sstevel@tonic-gate 		struct servent *sp;
3097c478bd9Sstevel@tonic-gate 		char *proto = NULL;
3107c478bd9Sstevel@tonic-gate 
3117c478bd9Sstevel@tonic-gate 		switch (aip->ai_socktype) {
3127c478bd9Sstevel@tonic-gate 		case ANY:
3137c478bd9Sstevel@tonic-gate 			proto = NULL;
3147c478bd9Sstevel@tonic-gate 			break;
3157c478bd9Sstevel@tonic-gate 		case SOCK_DGRAM:
3167c478bd9Sstevel@tonic-gate 			proto = "udp";
3177c478bd9Sstevel@tonic-gate 			break;
3187c478bd9Sstevel@tonic-gate 		case SOCK_STREAM:
319558fbd03Skcpoon 			/*
320558fbd03Skcpoon 			 * If there is no hint given, use TCP as the default
321558fbd03Skcpoon 			 * protocol.
322558fbd03Skcpoon 			 */
323558fbd03Skcpoon 			switch (aip->ai_protocol) {
324558fbd03Skcpoon 			case ANY:
325558fbd03Skcpoon 			case IPPROTO_TCP:
326558fbd03Skcpoon 			default:
3277c478bd9Sstevel@tonic-gate 				proto = "tcp";
3287c478bd9Sstevel@tonic-gate 				break;
329558fbd03Skcpoon 			case IPPROTO_SCTP:
330558fbd03Skcpoon 				proto = "sctp";
331558fbd03Skcpoon 				break;
332558fbd03Skcpoon 			}
333558fbd03Skcpoon 			break;
334558fbd03Skcpoon 		case SOCK_SEQPACKET:
335558fbd03Skcpoon 			/* Default to SCTP if no hint given. */
336558fbd03Skcpoon 			switch (aip->ai_protocol) {
337558fbd03Skcpoon 			case ANY:
338558fbd03Skcpoon 			default:
339558fbd03Skcpoon 				proto = "sctp";
340558fbd03Skcpoon 				break;
341558fbd03Skcpoon 			}
342558fbd03Skcpoon 			break;
3437c478bd9Sstevel@tonic-gate 		}
3447c478bd9Sstevel@tonic-gate 		/*
3457c478bd9Sstevel@tonic-gate 		 * Servname string can be a decimal port number.
3467c478bd9Sstevel@tonic-gate 		 * If we already know the socket type there is no need
3477c478bd9Sstevel@tonic-gate 		 * to call getservbyport.
3487c478bd9Sstevel@tonic-gate 		 */
3497c478bd9Sstevel@tonic-gate 		if (aip->ai_flags & AI_NUMERICSERV) {
3507c478bd9Sstevel@tonic-gate 			if (!str_isnumber(servname)) {
3517c478bd9Sstevel@tonic-gate 				return (EAI_NONAME);
3527c478bd9Sstevel@tonic-gate 			}
3537c478bd9Sstevel@tonic-gate 			port = htons(atoi(servname));
3547c478bd9Sstevel@tonic-gate 		} else if (str_isnumber(servname)) {
3557c478bd9Sstevel@tonic-gate 			port = htons(atoi(servname));
3567c478bd9Sstevel@tonic-gate 			if (aip->ai_socktype == ANY) {
3577c478bd9Sstevel@tonic-gate 				do {
3587c478bd9Sstevel@tonic-gate 					if (buf != NULL)
3597c478bd9Sstevel@tonic-gate 						free(buf);
3607c478bd9Sstevel@tonic-gate 					bufsize *= 2;
3617c478bd9Sstevel@tonic-gate 					buf = malloc(bufsize);
3627c478bd9Sstevel@tonic-gate 					if (buf == NULL) {
3637c478bd9Sstevel@tonic-gate 						*res = NULL;
3647c478bd9Sstevel@tonic-gate 						return (EAI_MEMORY);
3657c478bd9Sstevel@tonic-gate 					}
3667c478bd9Sstevel@tonic-gate 
3677c478bd9Sstevel@tonic-gate 					sp = getservbyport_r(port, proto,
3687c478bd9Sstevel@tonic-gate 					    &result, buf, bufsize);
3697c478bd9Sstevel@tonic-gate 					if (sp == NULL && errno != ERANGE) {
3707c478bd9Sstevel@tonic-gate 						free(buf);
3717c478bd9Sstevel@tonic-gate 						*res = NULL;
3727c478bd9Sstevel@tonic-gate 						return (EAI_SERVICE);
3737c478bd9Sstevel@tonic-gate 					}
3747c478bd9Sstevel@tonic-gate 				/*
3757c478bd9Sstevel@tonic-gate 				 * errno == ERANGE so our scratch buffer space
3767c478bd9Sstevel@tonic-gate 				 * wasn't big enough.  Double it and try
3777c478bd9Sstevel@tonic-gate 				 * again.
3787c478bd9Sstevel@tonic-gate 				 */
3797c478bd9Sstevel@tonic-gate 				} while (sp == NULL);
3807c478bd9Sstevel@tonic-gate 			}
3817c478bd9Sstevel@tonic-gate 		} else {
3827c478bd9Sstevel@tonic-gate 			do {
3837c478bd9Sstevel@tonic-gate 				if (buf != NULL)
3847c478bd9Sstevel@tonic-gate 					free(buf);
3857c478bd9Sstevel@tonic-gate 				bufsize *= 2;
3867c478bd9Sstevel@tonic-gate 				buf = malloc(bufsize);
3877c478bd9Sstevel@tonic-gate 				if (buf == NULL) {
3887c478bd9Sstevel@tonic-gate 					*res = NULL;
3897c478bd9Sstevel@tonic-gate 					return (EAI_MEMORY);
3907c478bd9Sstevel@tonic-gate 				}
3917c478bd9Sstevel@tonic-gate 
3927c478bd9Sstevel@tonic-gate 				sp = getservbyname_r(servname, proto, &result,
3937c478bd9Sstevel@tonic-gate 				    buf, bufsize);
3947c478bd9Sstevel@tonic-gate 				if (sp == NULL && errno != ERANGE) {
3957c478bd9Sstevel@tonic-gate 					free(buf);
3967c478bd9Sstevel@tonic-gate 					*res = NULL;
3977c478bd9Sstevel@tonic-gate 					return (EAI_SERVICE);
3987c478bd9Sstevel@tonic-gate 				}
3997c478bd9Sstevel@tonic-gate 			/*
4007c478bd9Sstevel@tonic-gate 			 * errno == ERANGE so our scratch buffer space wasn't
4017c478bd9Sstevel@tonic-gate 			 * big enough.  Double it and try again.
4027c478bd9Sstevel@tonic-gate 			 */
4037c478bd9Sstevel@tonic-gate 			} while (sp == NULL);
4047c478bd9Sstevel@tonic-gate 
4057c478bd9Sstevel@tonic-gate 			port = sp->s_port;
4067c478bd9Sstevel@tonic-gate 		}
4077c478bd9Sstevel@tonic-gate 		if (aip->ai_socktype == ANY) {
4087c478bd9Sstevel@tonic-gate 			if (aip->ai_flags & AI_NUMERICSERV) {
4097c478bd9Sstevel@tonic-gate 				/*
4107c478bd9Sstevel@tonic-gate 				 * RFC 2553bis doesn't allow us to use the
4117c478bd9Sstevel@tonic-gate 				 * any resolver to find out if there is a
4127c478bd9Sstevel@tonic-gate 				 * match.  We could walk the service file
4137c478bd9Sstevel@tonic-gate 				 * with *servent().  Given the commonality of
4147c478bd9Sstevel@tonic-gate 				 * calling getaddrinfo() with a number and
4157c478bd9Sstevel@tonic-gate 				 * ANY protocol we won't add that at this time.
4167c478bd9Sstevel@tonic-gate 				 */
4177c478bd9Sstevel@tonic-gate 				return (EAI_NONAME);
4187c478bd9Sstevel@tonic-gate 			}
4197c478bd9Sstevel@tonic-gate 
4207c478bd9Sstevel@tonic-gate 			if (strcmp(sp->s_proto, "udp") == 0) {
4217c478bd9Sstevel@tonic-gate 				aip->ai_socktype = SOCK_DGRAM;
4227c478bd9Sstevel@tonic-gate 				aip->ai_protocol = IPPROTO_UDP;
4237c478bd9Sstevel@tonic-gate 			} else if (strcmp(sp->s_proto, "tcp") == 0) {
4247c478bd9Sstevel@tonic-gate 				aip->ai_socktype = SOCK_STREAM;
4257c478bd9Sstevel@tonic-gate 				aip->ai_protocol = IPPROTO_TCP;
426558fbd03Skcpoon 			} else if (strcmp(sp->s_proto, "sctp") == 0) {
427558fbd03Skcpoon 				aip->ai_socktype = SOCK_STREAM;
428558fbd03Skcpoon 				aip->ai_protocol = IPPROTO_SCTP;
4297c478bd9Sstevel@tonic-gate 			} else {
4307c478bd9Sstevel@tonic-gate 				if (buf != NULL)
4317c478bd9Sstevel@tonic-gate 					free(buf);
4327c478bd9Sstevel@tonic-gate 
4337c478bd9Sstevel@tonic-gate 				*res = NULL;
4347c478bd9Sstevel@tonic-gate 				errno = EPROTONOSUPPORT;
4357c478bd9Sstevel@tonic-gate 				return (EAI_SYSTEM);
4367c478bd9Sstevel@tonic-gate 			}
4377c478bd9Sstevel@tonic-gate 		}
4387c478bd9Sstevel@tonic-gate 
4397c478bd9Sstevel@tonic-gate 		if (buf != NULL)
4407c478bd9Sstevel@tonic-gate 			free(buf);
4417c478bd9Sstevel@tonic-gate 	}
4427c478bd9Sstevel@tonic-gate 
4437c478bd9Sstevel@tonic-gate 	/*
4447c478bd9Sstevel@tonic-gate 	 * hostname is NULL
4457c478bd9Sstevel@tonic-gate 	 * case 1: AI_PASSIVE bit set : anyaddr 0.0.0.0 or ::
4467c478bd9Sstevel@tonic-gate 	 * case 2: AI_PASSIVE bit not set : localhost 127.0.0.1 or ::1
4477c478bd9Sstevel@tonic-gate 	 */
4487c478bd9Sstevel@tonic-gate 
4497c478bd9Sstevel@tonic-gate 	if (hostname == NULL) {
4507c478bd9Sstevel@tonic-gate 		struct addrinfo *nai;
4517c478bd9Sstevel@tonic-gate 		socklen_t addrlen;
4527c478bd9Sstevel@tonic-gate 		char *canonname;
4537c478bd9Sstevel@tonic-gate 
4547c478bd9Sstevel@tonic-gate 		if (aip->ai_family == PF_INET)
4557c478bd9Sstevel@tonic-gate 			goto v4only;
4567c478bd9Sstevel@tonic-gate 		/* create IPv6 addrinfo */
4577c478bd9Sstevel@tonic-gate 		nai = malloc(sizeof (struct addrinfo));
4587c478bd9Sstevel@tonic-gate 		if (nai == NULL)
4597c478bd9Sstevel@tonic-gate 			goto nomem;
4607c478bd9Sstevel@tonic-gate 		*nai = *aip;
4617c478bd9Sstevel@tonic-gate 		addrlen = sizeof (struct sockaddr_in6);
4627c478bd9Sstevel@tonic-gate 		nai->ai_addr = malloc(addrlen);
4637c478bd9Sstevel@tonic-gate 		if (nai->ai_addr == NULL) {
4647c478bd9Sstevel@tonic-gate 			freeaddrinfo(nai);
4657c478bd9Sstevel@tonic-gate 			goto nomem;
4667c478bd9Sstevel@tonic-gate 		}
4677c478bd9Sstevel@tonic-gate 		bzero(nai->ai_addr, addrlen);
4687c478bd9Sstevel@tonic-gate 		nai->ai_addrlen = addrlen;
4697c478bd9Sstevel@tonic-gate 		nai->ai_family = PF_INET6;
4707c478bd9Sstevel@tonic-gate 		nai->ai_canonname = NULL;
4717c478bd9Sstevel@tonic-gate 		if (nai->ai_flags & AI_PASSIVE) {
4727c478bd9Sstevel@tonic-gate 			ai2sin6(nai)->sin6_addr = in6addr_any;
4737c478bd9Sstevel@tonic-gate 		} else {
4747c478bd9Sstevel@tonic-gate 			ai2sin6(nai)->sin6_addr = in6addr_loopback;
4757c478bd9Sstevel@tonic-gate 			if (nai->ai_flags & AI_CANONNAME) {
4767c478bd9Sstevel@tonic-gate 				canonname = strdup("loopback");
4777c478bd9Sstevel@tonic-gate 				if (canonname == NULL) {
4787c478bd9Sstevel@tonic-gate 					freeaddrinfo(nai);
4797c478bd9Sstevel@tonic-gate 					goto nomem;
4807c478bd9Sstevel@tonic-gate 				}
4817c478bd9Sstevel@tonic-gate 				nai->ai_canonname = canonname;
4827c478bd9Sstevel@tonic-gate 			}
4837c478bd9Sstevel@tonic-gate 		}
4847c478bd9Sstevel@tonic-gate 		ai2sin6(nai)->sin6_family = PF_INET6;
4857c478bd9Sstevel@tonic-gate 		ai2sin6(nai)->sin6_port = port;
4867c478bd9Sstevel@tonic-gate 		cur->ai_next = nai;
4877c478bd9Sstevel@tonic-gate 		cur = nai;
4887c478bd9Sstevel@tonic-gate 		if (aip->ai_family == PF_INET6) {
4897c478bd9Sstevel@tonic-gate 			cur->ai_next = NULL;
4907c478bd9Sstevel@tonic-gate 			goto success;
4917c478bd9Sstevel@tonic-gate 		}
4927c478bd9Sstevel@tonic-gate 		/* If address family is PF_UNSPEC or PF_INET */
4937c478bd9Sstevel@tonic-gate v4only:
4947c478bd9Sstevel@tonic-gate 		/* create IPv4 addrinfo */
4957c478bd9Sstevel@tonic-gate 		nai = malloc(sizeof (struct addrinfo));
4967c478bd9Sstevel@tonic-gate 		if (nai == NULL)
4977c478bd9Sstevel@tonic-gate 			goto nomem;
4987c478bd9Sstevel@tonic-gate 		*nai = *aip;
4997c478bd9Sstevel@tonic-gate 		addrlen = sizeof (struct sockaddr_in);
5007c478bd9Sstevel@tonic-gate 		nai->ai_addr = malloc(addrlen);
5017c478bd9Sstevel@tonic-gate 		if (nai->ai_addr == NULL) {
5027c478bd9Sstevel@tonic-gate 			freeaddrinfo(nai);
5037c478bd9Sstevel@tonic-gate 			goto nomem;
5047c478bd9Sstevel@tonic-gate 		}
5057c478bd9Sstevel@tonic-gate 		bzero(nai->ai_addr, addrlen);
5067c478bd9Sstevel@tonic-gate 		nai->ai_addrlen = addrlen;
5077c478bd9Sstevel@tonic-gate 		nai->ai_family = PF_INET;
5087c478bd9Sstevel@tonic-gate 		nai->ai_canonname = NULL;
5097c478bd9Sstevel@tonic-gate 		if (nai->ai_flags & AI_PASSIVE) {
5107c478bd9Sstevel@tonic-gate 			ai2sin(nai)->sin_addr.s_addr = INADDR_ANY;
5117c478bd9Sstevel@tonic-gate 		} else {
5127c478bd9Sstevel@tonic-gate 			ai2sin(nai)->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
5137c478bd9Sstevel@tonic-gate 			if (nai->ai_flags & AI_CANONNAME &&
5147c478bd9Sstevel@tonic-gate 			    nai->ai_family != PF_UNSPEC) {
5157c478bd9Sstevel@tonic-gate 				canonname = strdup("loopback");
5167c478bd9Sstevel@tonic-gate 				if (canonname == NULL) {
5177c478bd9Sstevel@tonic-gate 					freeaddrinfo(nai);
5187c478bd9Sstevel@tonic-gate 					goto nomem;
5197c478bd9Sstevel@tonic-gate 				}
5207c478bd9Sstevel@tonic-gate 				nai->ai_canonname = canonname;
5217c478bd9Sstevel@tonic-gate 			}
5227c478bd9Sstevel@tonic-gate 		}
5237c478bd9Sstevel@tonic-gate 		ai2sin(nai)->sin_family = PF_INET;
5247c478bd9Sstevel@tonic-gate 		ai2sin(nai)->sin_port = port;
5257c478bd9Sstevel@tonic-gate 		cur->ai_next = nai;
5267c478bd9Sstevel@tonic-gate 		cur = nai;
5277c478bd9Sstevel@tonic-gate 		cur->ai_next = NULL;
5287c478bd9Sstevel@tonic-gate 		goto success;
5297c478bd9Sstevel@tonic-gate 	}
5307c478bd9Sstevel@tonic-gate 
5317c478bd9Sstevel@tonic-gate 	/* hostname string is a literal address or an alphabetical name */
5327c478bd9Sstevel@tonic-gate 	error = get_addr(aip->ai_family, hostname, aip, cur, port, version);
5337c478bd9Sstevel@tonic-gate 	if (error) {
5347c478bd9Sstevel@tonic-gate 		*res = NULL;
5357c478bd9Sstevel@tonic-gate 		return (error);
5367c478bd9Sstevel@tonic-gate 	}
5377c478bd9Sstevel@tonic-gate 
5387c478bd9Sstevel@tonic-gate success:
5397c478bd9Sstevel@tonic-gate 	*res = aip->ai_next;
5407c478bd9Sstevel@tonic-gate 	return (0);
5417c478bd9Sstevel@tonic-gate 
5427c478bd9Sstevel@tonic-gate nomem:
5437c478bd9Sstevel@tonic-gate 	return (EAI_MEMORY);
5447c478bd9Sstevel@tonic-gate }
5457c478bd9Sstevel@tonic-gate 
5467c478bd9Sstevel@tonic-gate int
5477c478bd9Sstevel@tonic-gate getaddrinfo(const char *hostname, const char *servname,
5487c478bd9Sstevel@tonic-gate 	const struct addrinfo *hints, struct addrinfo **res)
5497c478bd9Sstevel@tonic-gate {
5507c478bd9Sstevel@tonic-gate 	return (_getaddrinfo(hostname, servname, hints, res, GAIV_DEFAULT));
5517c478bd9Sstevel@tonic-gate }
5527c478bd9Sstevel@tonic-gate 
5537c478bd9Sstevel@tonic-gate int
5547c478bd9Sstevel@tonic-gate __xnet_getaddrinfo(const char *hostname, const char *servname,
5557c478bd9Sstevel@tonic-gate 	const struct addrinfo *hints, struct addrinfo **res)
5567c478bd9Sstevel@tonic-gate {
5577c478bd9Sstevel@tonic-gate 	return (_getaddrinfo(hostname, servname, hints, res, GAIV_XPG6));
5587c478bd9Sstevel@tonic-gate }
5597c478bd9Sstevel@tonic-gate 
5607c478bd9Sstevel@tonic-gate static int
5617c478bd9Sstevel@tonic-gate get_addr(int family, const char *hostname, struct addrinfo *aip, struct
5627c478bd9Sstevel@tonic-gate 	addrinfo *cur, ushort_t port, int version)
5637c478bd9Sstevel@tonic-gate {
5647c478bd9Sstevel@tonic-gate 	struct hostent		*hp;
5657c478bd9Sstevel@tonic-gate 	char			_hostname[MAXHOSTNAMELEN];
5667c478bd9Sstevel@tonic-gate 	int			i, errnum;
5677c478bd9Sstevel@tonic-gate 	struct addrinfo		*nai;
5687c478bd9Sstevel@tonic-gate 	int			addrlen;
5697c478bd9Sstevel@tonic-gate 	char			*canonname;
5707c478bd9Sstevel@tonic-gate 	boolean_t		firsttime = B_TRUE;
5717c478bd9Sstevel@tonic-gate 	boolean_t		create_v6_addrinfo;
5727c478bd9Sstevel@tonic-gate 	struct in_addr		v4addr;
5737c478bd9Sstevel@tonic-gate 	struct in6_addr		v6addr;
5747c478bd9Sstevel@tonic-gate 	struct in6_addr		*v6addrp;
5757c478bd9Sstevel@tonic-gate 	char			*zonestr = NULL;
5767c478bd9Sstevel@tonic-gate 
5777c478bd9Sstevel@tonic-gate 	/*
5787c478bd9Sstevel@tonic-gate 	 * Check for existence of address-zoneid delimiter '%'
5797c478bd9Sstevel@tonic-gate 	 * If the delimiter exists, parse the zoneid portion of
5807c478bd9Sstevel@tonic-gate 	 * <addr>%<zone_id>
5817c478bd9Sstevel@tonic-gate 	 */
5827c478bd9Sstevel@tonic-gate 	if ((zonestr = strchr(hostname, '%')) != NULL) {
5837c478bd9Sstevel@tonic-gate 		/* make sure we have room for <addr> portion of hostname */
5847c478bd9Sstevel@tonic-gate 		if (((zonestr - hostname) + 1) > sizeof (_hostname)) {
5857c478bd9Sstevel@tonic-gate 			return (EAI_MEMORY);
5867c478bd9Sstevel@tonic-gate 		}
5877c478bd9Sstevel@tonic-gate 
5887c478bd9Sstevel@tonic-gate 		/* chop off and save <zone_id> portion */
5897c478bd9Sstevel@tonic-gate 		(void) strlcpy(_hostname, hostname, (zonestr - hostname) + 1);
5907c478bd9Sstevel@tonic-gate 		++zonestr;	/* make zonestr point at start of <zone-id> */
5917c478bd9Sstevel@tonic-gate 		/* ensure zone is valid */
5927c478bd9Sstevel@tonic-gate 		if ((*zonestr == '\0') || (strlen(zonestr) > LIFNAMSIZ))  {
5937c478bd9Sstevel@tonic-gate 			return (EAI_NONAME);
5947c478bd9Sstevel@tonic-gate 		}
5957c478bd9Sstevel@tonic-gate 	} else {
5967c478bd9Sstevel@tonic-gate 		size_t hlen = sizeof (_hostname);
5977c478bd9Sstevel@tonic-gate 
5987c478bd9Sstevel@tonic-gate 		if (strlcpy(_hostname, hostname, hlen) >= hlen) {
5997c478bd9Sstevel@tonic-gate 			return (EAI_MEMORY);
6007c478bd9Sstevel@tonic-gate 		}
6017c478bd9Sstevel@tonic-gate 	}
6027c478bd9Sstevel@tonic-gate 
6037c478bd9Sstevel@tonic-gate 	/* Check to see if AI_NUMERICHOST bit is set */
6047c478bd9Sstevel@tonic-gate 	if (aip->ai_flags & AI_NUMERICHOST) {
6057c478bd9Sstevel@tonic-gate 		/* check to see if _hostname points to a literal IP address */
6067c478bd9Sstevel@tonic-gate 		if (!((inet_addr(_hostname) != ((in_addr_t)-1)) ||
6077c478bd9Sstevel@tonic-gate 		    (strcmp(_hostname, HOST_BROADCAST) == 0) ||
6087c478bd9Sstevel@tonic-gate 		    (inet_pton(AF_INET6, _hostname, &v6addr) > 0))) {
6097c478bd9Sstevel@tonic-gate 			return (EAI_NONAME);
6107c478bd9Sstevel@tonic-gate 		}
6117c478bd9Sstevel@tonic-gate 	}
6127c478bd9Sstevel@tonic-gate 
6137c478bd9Sstevel@tonic-gate 	/* if hostname argument is literal, name service doesn't get called */
6147c478bd9Sstevel@tonic-gate 	if (family == PF_UNSPEC) {
6157c478bd9Sstevel@tonic-gate 		hp = getipnodebyname(_hostname, AF_INET6, AI_ALL |
616*2f443e27SRobert Mustacchi 		    aip->ai_flags | AI_V4MAPPED | AI_ADDRINFO, &errnum);
6177c478bd9Sstevel@tonic-gate 	} else {
6187c478bd9Sstevel@tonic-gate 		hp = getipnodebyname(_hostname, family, aip->ai_flags, &errnum);
6197c478bd9Sstevel@tonic-gate 	}
6207c478bd9Sstevel@tonic-gate 
6217c478bd9Sstevel@tonic-gate 	if (hp == NULL) {
6227c478bd9Sstevel@tonic-gate 		switch (errnum) {
6237c478bd9Sstevel@tonic-gate 		case HOST_NOT_FOUND:
6247c478bd9Sstevel@tonic-gate 			return (EAI_NONAME);
6257c478bd9Sstevel@tonic-gate 		case TRY_AGAIN:
6267c478bd9Sstevel@tonic-gate 			return (EAI_AGAIN);
6277c478bd9Sstevel@tonic-gate 		case NO_RECOVERY:
6287c478bd9Sstevel@tonic-gate 			return (EAI_FAIL);
6297c478bd9Sstevel@tonic-gate 		case NO_ADDRESS:
6307c478bd9Sstevel@tonic-gate 			if (version == GAIV_XPG6)
6317c478bd9Sstevel@tonic-gate 				return (EAI_NONAME);
6327c478bd9Sstevel@tonic-gate 			return (EAI_NODATA);
6337c478bd9Sstevel@tonic-gate 		default:
6347c478bd9Sstevel@tonic-gate 		return (EAI_SYSTEM);
6357c478bd9Sstevel@tonic-gate 		}
6367c478bd9Sstevel@tonic-gate 	}
6377c478bd9Sstevel@tonic-gate 
6387c478bd9Sstevel@tonic-gate 	for (i = 0; hp->h_addr_list[i]; i++) {
6397c478bd9Sstevel@tonic-gate 		/* Determine if an IPv6 addrinfo structure should be created */
6407c478bd9Sstevel@tonic-gate 		create_v6_addrinfo = B_TRUE;
6417c478bd9Sstevel@tonic-gate 		if (hp->h_addrtype == AF_INET6) {
6427c478bd9Sstevel@tonic-gate 			v6addrp = (struct in6_addr *)hp->h_addr_list[i];
6437c478bd9Sstevel@tonic-gate 			if (!(aip->ai_flags & AI_V4MAPPED) &&
6447c478bd9Sstevel@tonic-gate 			    IN6_IS_ADDR_V4MAPPED(v6addrp)) {
6457c478bd9Sstevel@tonic-gate 				create_v6_addrinfo = B_FALSE;
6467c478bd9Sstevel@tonic-gate 				IN6_V4MAPPED_TO_INADDR(v6addrp, &v4addr);
6477c478bd9Sstevel@tonic-gate 			}
6487c478bd9Sstevel@tonic-gate 		} else	if (hp->h_addrtype == AF_INET) {
6497c478bd9Sstevel@tonic-gate 			create_v6_addrinfo = B_FALSE;
6507c478bd9Sstevel@tonic-gate 			(void) memcpy(&v4addr, hp->h_addr_list[i],
6517c478bd9Sstevel@tonic-gate 			    sizeof (struct in_addr));
6527c478bd9Sstevel@tonic-gate 		} else {
6537c478bd9Sstevel@tonic-gate 			return (EAI_SYSTEM);
6547c478bd9Sstevel@tonic-gate 		}
6557c478bd9Sstevel@tonic-gate 
6567c478bd9Sstevel@tonic-gate 		if (create_v6_addrinfo) {
6577c478bd9Sstevel@tonic-gate 			/* create IPv6 addrinfo */
6587c478bd9Sstevel@tonic-gate 			nai = malloc(sizeof (struct addrinfo));
6597c478bd9Sstevel@tonic-gate 			if (nai == NULL)
6607c478bd9Sstevel@tonic-gate 				goto nomem;
6617c478bd9Sstevel@tonic-gate 			*nai = *aip;
6627c478bd9Sstevel@tonic-gate 			addrlen = sizeof (struct sockaddr_in6);
6637c478bd9Sstevel@tonic-gate 			nai->ai_addr = malloc(addrlen);
6647c478bd9Sstevel@tonic-gate 			if (nai->ai_addr == NULL) {
6657c478bd9Sstevel@tonic-gate 				freeaddrinfo(nai);
6667c478bd9Sstevel@tonic-gate 				goto nomem;
6677c478bd9Sstevel@tonic-gate 			}
6687c478bd9Sstevel@tonic-gate 			bzero(nai->ai_addr, addrlen);
6697c478bd9Sstevel@tonic-gate 			nai->ai_addrlen = addrlen;
6707c478bd9Sstevel@tonic-gate 			nai->ai_family = PF_INET6;
6717c478bd9Sstevel@tonic-gate 
6727c478bd9Sstevel@tonic-gate 			(void) memcpy(ai2sin6(nai)->sin6_addr.s6_addr,
6737c478bd9Sstevel@tonic-gate 			    hp->h_addr_list[i], sizeof (struct in6_addr));
6747c478bd9Sstevel@tonic-gate 			nai->ai_canonname = NULL;
6757c478bd9Sstevel@tonic-gate 			if ((nai->ai_flags & AI_CANONNAME) && firsttime) {
6767c478bd9Sstevel@tonic-gate 				canonname = strdup(hp->h_name);
6777c478bd9Sstevel@tonic-gate 				if (canonname == NULL) {
6787c478bd9Sstevel@tonic-gate 					freeaddrinfo(nai);
6797c478bd9Sstevel@tonic-gate 					goto nomem;
6807c478bd9Sstevel@tonic-gate 				}
6817c478bd9Sstevel@tonic-gate 				nai->ai_canonname = canonname;
6827c478bd9Sstevel@tonic-gate 				firsttime = B_FALSE;
6837c478bd9Sstevel@tonic-gate 			}
6847c478bd9Sstevel@tonic-gate 			ai2sin6(nai)->sin6_family = PF_INET6;
6857c478bd9Sstevel@tonic-gate 			ai2sin6(nai)->sin6_port = port;
6867c478bd9Sstevel@tonic-gate 			/* set sin6_scope_id */
6877c478bd9Sstevel@tonic-gate 			if (zonestr != NULL) {
6887c478bd9Sstevel@tonic-gate 				/*
6897c478bd9Sstevel@tonic-gate 				 * Translate 'zonestr' into a valid
6907c478bd9Sstevel@tonic-gate 				 * sin6_scope_id.
6917c478bd9Sstevel@tonic-gate 				 */
6927c478bd9Sstevel@tonic-gate 				if ((errnum =
6937c478bd9Sstevel@tonic-gate 				    getscopeidfromzone(ai2sin6(nai), zonestr,
6947c478bd9Sstevel@tonic-gate 				    &ai2sin6(nai)->sin6_scope_id)) != 0) {
6957c478bd9Sstevel@tonic-gate 					return (errnum);
6967c478bd9Sstevel@tonic-gate 				}
6977c478bd9Sstevel@tonic-gate 			} else {
6987c478bd9Sstevel@tonic-gate 				ai2sin6(nai)->sin6_scope_id = 0;
6997c478bd9Sstevel@tonic-gate 			}
7007c478bd9Sstevel@tonic-gate 		} else {
7017c478bd9Sstevel@tonic-gate 			/* create IPv4 addrinfo */
7027c478bd9Sstevel@tonic-gate 			nai = malloc(sizeof (struct addrinfo));
7037c478bd9Sstevel@tonic-gate 			if (nai == NULL)
7047c478bd9Sstevel@tonic-gate 				goto nomem;
7057c478bd9Sstevel@tonic-gate 			*nai = *aip;
7067c478bd9Sstevel@tonic-gate 			addrlen = sizeof (struct sockaddr_in);
7077c478bd9Sstevel@tonic-gate 			nai->ai_addr = malloc(addrlen);
7087c478bd9Sstevel@tonic-gate 			if (nai->ai_addr == NULL) {
7097c478bd9Sstevel@tonic-gate 				freeaddrinfo(nai);
7107c478bd9Sstevel@tonic-gate 				goto nomem;
7117c478bd9Sstevel@tonic-gate 			}
7127c478bd9Sstevel@tonic-gate 			bzero(nai->ai_addr, addrlen);
7137c478bd9Sstevel@tonic-gate 			nai->ai_addrlen = addrlen;
7147c478bd9Sstevel@tonic-gate 			nai->ai_family = PF_INET;
7157c478bd9Sstevel@tonic-gate 			(void) memcpy(&(ai2sin(nai)->sin_addr.s_addr),
7167c478bd9Sstevel@tonic-gate 			    &v4addr, sizeof (struct in_addr));
7177c478bd9Sstevel@tonic-gate 			nai->ai_canonname = NULL;
7187c478bd9Sstevel@tonic-gate 			if (nai->ai_flags & AI_CANONNAME && firsttime) {
7197c478bd9Sstevel@tonic-gate 				canonname = strdup(hp->h_name);
7207c478bd9Sstevel@tonic-gate 				if (canonname == NULL) {
7217c478bd9Sstevel@tonic-gate 					freeaddrinfo(nai);
7227c478bd9Sstevel@tonic-gate 					goto nomem;
7237c478bd9Sstevel@tonic-gate 				}
7247c478bd9Sstevel@tonic-gate 				nai->ai_canonname = canonname;
7257c478bd9Sstevel@tonic-gate 				firsttime = B_FALSE;
7267c478bd9Sstevel@tonic-gate 			}
7277c478bd9Sstevel@tonic-gate 			ai2sin(nai)->sin_family = PF_INET;
7287c478bd9Sstevel@tonic-gate 			ai2sin(nai)->sin_port = port;
7297c478bd9Sstevel@tonic-gate 		}
7307c478bd9Sstevel@tonic-gate 
7317c478bd9Sstevel@tonic-gate 		cur->ai_next = nai;
7327c478bd9Sstevel@tonic-gate 		cur = nai;
7337c478bd9Sstevel@tonic-gate 	}
7347c478bd9Sstevel@tonic-gate 	cur->ai_next = NULL;
7357c478bd9Sstevel@tonic-gate 	freehostent(hp);
7367c478bd9Sstevel@tonic-gate 	return (0);
7377c478bd9Sstevel@tonic-gate 
7387c478bd9Sstevel@tonic-gate nomem:
7397c478bd9Sstevel@tonic-gate 	freehostent(hp);
7407c478bd9Sstevel@tonic-gate 	return (EAI_MEMORY);
7417c478bd9Sstevel@tonic-gate 
7427c478bd9Sstevel@tonic-gate }
7437c478bd9Sstevel@tonic-gate 
7447c478bd9Sstevel@tonic-gate /*
7457c478bd9Sstevel@tonic-gate  * getscopeidfromzone(sa, zone, sin6_scope_id)
7467c478bd9Sstevel@tonic-gate  *
7477c478bd9Sstevel@tonic-gate  * Converts the string pointed to by 'zone' into a sin6_scope_id.
7487c478bd9Sstevel@tonic-gate  * 'zone' will either be a pointer to an interface name or will
7497c478bd9Sstevel@tonic-gate  * be a literal sin6_scope_id.
7507c478bd9Sstevel@tonic-gate  *
7517c478bd9Sstevel@tonic-gate  * 0 is returned on success and the output parameter 'sin6_scope_id' will
7527c478bd9Sstevel@tonic-gate  *   be set to a valid sin6_scope_id.
7537c478bd9Sstevel@tonic-gate  * EAI_NONAME is returned for either of two reasons:
7547c478bd9Sstevel@tonic-gate  *	1.  The IPv6 address pointed to by sa->sin6_addr is not
7557c478bd9Sstevel@tonic-gate  *	    part of the 'link scope' (ie link local, nodelocal multicast or
7567c478bd9Sstevel@tonic-gate  *	    linklocal multicast address)
7577c478bd9Sstevel@tonic-gate  *	2.  The string pointed to by 'zone' can not be translate to a valid
7587c478bd9Sstevel@tonic-gate  *	    sin6_scope_id.
7597c478bd9Sstevel@tonic-gate  */
7607c478bd9Sstevel@tonic-gate static uint_t
7617c478bd9Sstevel@tonic-gate getscopeidfromzone(const struct sockaddr_in6 *sa, const char *zone,
7627c478bd9Sstevel@tonic-gate     uint32_t *sin6_scope_id) {
7637c478bd9Sstevel@tonic-gate 	const in6_addr_t *addr = &sa->sin6_addr;
7647c478bd9Sstevel@tonic-gate 	ulong_t ul_scope_id;
7657c478bd9Sstevel@tonic-gate 	char *endp;
7667c478bd9Sstevel@tonic-gate 
7677c478bd9Sstevel@tonic-gate 	if (IN6_IS_ADDR_LINKSCOPE(addr)) {
7687c478bd9Sstevel@tonic-gate 		/*
7697c478bd9Sstevel@tonic-gate 		 * Look up interface index associated with interface name
7707c478bd9Sstevel@tonic-gate 		 * pointed to by 'zone'.  Since the address is part of the link
7717c478bd9Sstevel@tonic-gate 		 * scope, there is a one-to-one relationship between interface
7727c478bd9Sstevel@tonic-gate 		 * index and sin6_scope_id.
7737c478bd9Sstevel@tonic-gate 		 * If an interface index can not be found for 'zone', then
7747c478bd9Sstevel@tonic-gate 		 * treat 'zone' as a literal sin6_scope_id value.
7757c478bd9Sstevel@tonic-gate 		 */
7767c478bd9Sstevel@tonic-gate 		if ((*sin6_scope_id = if_nametoindex(zone)) != 0) {
7777c478bd9Sstevel@tonic-gate 			return (0);
7787c478bd9Sstevel@tonic-gate 		} else {
7797c478bd9Sstevel@tonic-gate 			if ((ul_scope_id = strtoul(zone, &endp, 10)) != 0) {
7807c478bd9Sstevel@tonic-gate 				/* check that entire string was read */
7817c478bd9Sstevel@tonic-gate 				if (*endp != '\0') {
7827c478bd9Sstevel@tonic-gate 					return (EAI_NONAME);
7837c478bd9Sstevel@tonic-gate 				}
7847c478bd9Sstevel@tonic-gate 				*sin6_scope_id =
7857c478bd9Sstevel@tonic-gate 				    (uint32_t)(ul_scope_id & 0xffffffffUL);
7867c478bd9Sstevel@tonic-gate 			} else {
7877c478bd9Sstevel@tonic-gate 				return (EAI_NONAME);
7887c478bd9Sstevel@tonic-gate 			}
7897c478bd9Sstevel@tonic-gate 		}
7907c478bd9Sstevel@tonic-gate 	} else {
7917c478bd9Sstevel@tonic-gate 		return (EAI_NONAME);
7927c478bd9Sstevel@tonic-gate 	}
7937c478bd9Sstevel@tonic-gate 	return (0);
7947c478bd9Sstevel@tonic-gate }
7957c478bd9Sstevel@tonic-gate 
7967c478bd9Sstevel@tonic-gate 
7977c478bd9Sstevel@tonic-gate void
7987c478bd9Sstevel@tonic-gate freeaddrinfo(struct addrinfo *ai)
7997c478bd9Sstevel@tonic-gate {
8007c478bd9Sstevel@tonic-gate 	struct addrinfo *next;
8017c478bd9Sstevel@tonic-gate 
8027c478bd9Sstevel@tonic-gate 	do {
8037c478bd9Sstevel@tonic-gate 		next = ai->ai_next;
8047c478bd9Sstevel@tonic-gate 		if (ai->ai_canonname)
8057c478bd9Sstevel@tonic-gate 			free(ai->ai_canonname);
8067c478bd9Sstevel@tonic-gate 		if (ai->ai_addr)
8077c478bd9Sstevel@tonic-gate 			free(ai->ai_addr);
8087c478bd9Sstevel@tonic-gate 		free(ai);
8097c478bd9Sstevel@tonic-gate 		ai = next;
8107c478bd9Sstevel@tonic-gate 	} while (ai != NULL);
8117c478bd9Sstevel@tonic-gate }
8127c478bd9Sstevel@tonic-gate 
8137c478bd9Sstevel@tonic-gate static boolean_t
8147c478bd9Sstevel@tonic-gate str_isnumber(const char *p)
8157c478bd9Sstevel@tonic-gate {
8167c478bd9Sstevel@tonic-gate 	char *q = (char *)p;
8177c478bd9Sstevel@tonic-gate 	while (*q) {
8187c478bd9Sstevel@tonic-gate 		if (!isdigit(*q))
8197c478bd9Sstevel@tonic-gate 			return (B_FALSE);
8207c478bd9Sstevel@tonic-gate 		q++;
8217c478bd9Sstevel@tonic-gate 	}
8227c478bd9Sstevel@tonic-gate 	return (B_TRUE);
8237c478bd9Sstevel@tonic-gate }
8247c478bd9Sstevel@tonic-gate static const char *gai_errlist[] = {
8257c478bd9Sstevel@tonic-gate 	"name translation error 0 (no error)",		/* 0 */
8267c478bd9Sstevel@tonic-gate 	"specified address family not supported",	/* 1 EAI_ADDRFAMILY */
8277c478bd9Sstevel@tonic-gate 	"temporary name resolution failure",		/* 2 EAI_AGAIN */
8287c478bd9Sstevel@tonic-gate 	"invalid flags",				/* 3 EAI_BADFLAGS */
8297c478bd9Sstevel@tonic-gate 	"non-recoverable name resolution failure",	/* 4 EAI_FAIL */
8307c478bd9Sstevel@tonic-gate 	"specified address family not supported",	/* 5 EAI_FAMILY */
8317c478bd9Sstevel@tonic-gate 	"memory allocation failure",			/* 6 EAI_MEMORY */
8327c478bd9Sstevel@tonic-gate 	"no address for the specified node name",	/* 7 EAI_NODATA */
8337c478bd9Sstevel@tonic-gate 	"node name or service name not known",		/* 8 EAI_NONAME */
8347c478bd9Sstevel@tonic-gate 	"service name not available for the specified socket type",
8357c478bd9Sstevel@tonic-gate 							/* 9 EAI_SERVICE */
8367c478bd9Sstevel@tonic-gate 	"specified socket type not supported",		/* 10 EAI_SOCKTYPE */
8377c478bd9Sstevel@tonic-gate 	"system error",					/* 11 EAI_SYSTEM */
8387c478bd9Sstevel@tonic-gate };
8397c478bd9Sstevel@tonic-gate static int gai_nerr = { sizeof (gai_errlist)/sizeof (gai_errlist[0]) };
8407c478bd9Sstevel@tonic-gate 
8417c478bd9Sstevel@tonic-gate const char *
8427c478bd9Sstevel@tonic-gate gai_strerror(int ecode)
8437c478bd9Sstevel@tonic-gate {
8447c478bd9Sstevel@tonic-gate 	if (ecode < 0)
8457257d1b4Sraf 		return (dgettext(TEXT_DOMAIN,
8467c478bd9Sstevel@tonic-gate 		    "name translation internal error"));
8477c478bd9Sstevel@tonic-gate 	else if (ecode < gai_nerr)
8487257d1b4Sraf 		return (dgettext(TEXT_DOMAIN, gai_errlist[ecode]));
8497257d1b4Sraf 	return (dgettext(TEXT_DOMAIN, "unknown name translation error"));
8507c478bd9Sstevel@tonic-gate }
851