10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
55586Skcpoon * Common Development and Distribution License (the "License").
65586Skcpoon * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
210Sstevel@tonic-gate
220Sstevel@tonic-gate /*
23*11945SY.Zhang@Sun.COM * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
240Sstevel@tonic-gate * Use is subject to license terms.
250Sstevel@tonic-gate */
260Sstevel@tonic-gate
270Sstevel@tonic-gate
280Sstevel@tonic-gate
290Sstevel@tonic-gate #include <netdb.h>
300Sstevel@tonic-gate #include <arpa/inet.h>
310Sstevel@tonic-gate #include <nss_dbdefs.h>
320Sstevel@tonic-gate #include <netinet/in.h>
330Sstevel@tonic-gate #include <sys/socket.h>
340Sstevel@tonic-gate #include <string.h>
350Sstevel@tonic-gate #include <strings.h>
360Sstevel@tonic-gate #include <stdio.h>
370Sstevel@tonic-gate #include <ctype.h>
380Sstevel@tonic-gate #include <sys/types.h>
390Sstevel@tonic-gate #include <stdlib.h>
406812Sraf #include <libintl.h>
410Sstevel@tonic-gate #include <net/if.h>
420Sstevel@tonic-gate
430Sstevel@tonic-gate #define ai2sin(x) ((struct sockaddr_in *)((x)->ai_addr))
440Sstevel@tonic-gate #define ai2sin6(x) ((struct sockaddr_in6 *)((x)->ai_addr))
450Sstevel@tonic-gate
460Sstevel@tonic-gate #define HOST_BROADCAST "255.255.255.255"
470Sstevel@tonic-gate
480Sstevel@tonic-gate /*
490Sstevel@tonic-gate * getaddrinfo() returns EAI_NONAME in some cases, however
500Sstevel@tonic-gate * since EAI_NONAME is not part of SUSv3 it needed to be
510Sstevel@tonic-gate * masked in the standards compliant environment.
520Sstevel@tonic-gate * GAIV_DEFAULT and GAIV_XPG6 accomplish this.
530Sstevel@tonic-gate */
540Sstevel@tonic-gate #define GAIV_DEFAULT 0
550Sstevel@tonic-gate #define GAIV_XPG6 1
560Sstevel@tonic-gate
570Sstevel@tonic-gate /*
580Sstevel@tonic-gate * Storage allocation for global variables in6addr_any and
590Sstevel@tonic-gate * in6addr_loopback. The extern declarations for these
600Sstevel@tonic-gate * variables are defined in <netinet/in.h>. These two
610Sstevel@tonic-gate * variables could have been defined in any of the "C" files
620Sstevel@tonic-gate * in libsocket. They are defined here with other IPv6
630Sstevel@tonic-gate * related interfaces.
640Sstevel@tonic-gate */
650Sstevel@tonic-gate const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT;
660Sstevel@tonic-gate const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT;
670Sstevel@tonic-gate
680Sstevel@tonic-gate /* AI_MASK: all valid flags for addrinfo */
690Sstevel@tonic-gate #define AI_MASK (AI_PASSIVE | AI_CANONNAME | AI_NUMERICHOST \
700Sstevel@tonic-gate | AI_ADDRCONFIG | AI_NUMERICSERV | AI_V4MAPPED | AI_ALL)
710Sstevel@tonic-gate #define ANY 0
720Sstevel@tonic-gate /* function prototypes for used by getaddrinfo() routine */
730Sstevel@tonic-gate static int get_addr(int family, const char *hostname, struct addrinfo *aip,
740Sstevel@tonic-gate struct addrinfo *cur, ushort_t port, int version);
750Sstevel@tonic-gate static uint_t getscopeidfromzone(const struct sockaddr_in6 *sa,
760Sstevel@tonic-gate const char *zone, uint32_t *sin6_scope_id);
770Sstevel@tonic-gate static boolean_t str_isnumber(const char *p);
780Sstevel@tonic-gate
790Sstevel@tonic-gate /*
800Sstevel@tonic-gate * getaddrinfo:
810Sstevel@tonic-gate *
820Sstevel@tonic-gate * Purpose:
830Sstevel@tonic-gate * Routine for performing Address-to-nodename in a
840Sstevel@tonic-gate * protocol-independent fashion.
850Sstevel@tonic-gate * Description and history of the routine:
860Sstevel@tonic-gate * Nodename-to-address translation is done in a protocol-
870Sstevel@tonic-gate * independent fashion using the getaddrinfo() function
880Sstevel@tonic-gate * that is taken from the IEEE POSIX 1003.1g.
890Sstevel@tonic-gate *
900Sstevel@tonic-gate * The official specification for this function will be the
910Sstevel@tonic-gate * final POSIX standard, with the following additional
920Sstevel@tonic-gate * requirements:
930Sstevel@tonic-gate *
940Sstevel@tonic-gate * - getaddrinfo() must be thread safe
950Sstevel@tonic-gate * - The AI_NUMERICHOST is new.
960Sstevel@tonic-gate * - All fields in socket address structures returned by
970Sstevel@tonic-gate *
980Sstevel@tonic-gate * getaddrinfo() that are not filled in through an explicit
990Sstevel@tonic-gate * argument (e.g., sin6_flowinfo and sin_zero) must be set to 0.
1000Sstevel@tonic-gate * (This makes it easier to compare socket address structures).
1010Sstevel@tonic-gate *
1020Sstevel@tonic-gate * Input Parameters:
1030Sstevel@tonic-gate * nodename - pointer to null-terminated strings that represents
1040Sstevel@tonic-gate * a hostname or literal ip address (IPv4/IPv6) or this
1050Sstevel@tonic-gate * pointer can be NULL.
1060Sstevel@tonic-gate * servname - pointer to null-terminated strings that represents
1070Sstevel@tonic-gate * a servicename or literal port number or this
1080Sstevel@tonic-gate * pointer can be NULL.
1090Sstevel@tonic-gate * hints - optional argument that points to an addrinfo structure
1100Sstevel@tonic-gate * to provide hints on the type of socket that the caller
1110Sstevel@tonic-gate * supports.
1120Sstevel@tonic-gate * Possible setting of the ai_flags member of the hints structure:
1130Sstevel@tonic-gate * AI_PASSIVE - If set, the caller plans to use the returned socket
1140Sstevel@tonic-gate * address in a call to bind(). In this case, it the
1150Sstevel@tonic-gate * nodename argument is NULL, then the IP address portion
1160Sstevel@tonic-gate * of the socket address structure will be set to
1170Sstevel@tonic-gate * INADDR_ANY for IPv4 or IN6ADDR_ANY_INIT for IPv6.
1180Sstevel@tonic-gate * AI_PASSIVE - If not set, then the returned socket address will be
1190Sstevel@tonic-gate * ready for a call to connect() (for conn-oriented) or
1200Sstevel@tonic-gate * connect(), sendto(), or sendmsg() (for connectionless).
1210Sstevel@tonic-gate * In this case, if nodename is NULL, then the IP address
1220Sstevel@tonic-gate * portion of the socket address structure will be set to
1230Sstevel@tonic-gate * the loopback address.
1240Sstevel@tonic-gate * AI_CANONNAME - If set, then upon successful return the ai_canonname
1250Sstevel@tonic-gate * field of the first addrinfo structure in the linked
1260Sstevel@tonic-gate * list will point to a NULL-terminated string
1270Sstevel@tonic-gate * containing the canonical name of the specified nodename.
1280Sstevel@tonic-gate * AI_NUMERICHOST - If set, then a non-NULL nodename string must be a numeric
1290Sstevel@tonic-gate * host address string. Otherwise an error of EAI_NONAME
1300Sstevel@tonic-gate * is returned. This flag prevents any type of name
1310Sstevel@tonic-gate * resolution service from being called.
1320Sstevel@tonic-gate * AI_NUMERICSERV - If set, then a non-null servname string supplied shall
1330Sstevel@tonic-gate * be a numeric port string. Otherwise, an [EAI_NONAME]
1340Sstevel@tonic-gate * error shall be returned. This flag shall prevent any
1350Sstevel@tonic-gate * type of name resolution service from being invoked.
1360Sstevel@tonic-gate * AI_V4MAPPED - If set, along with an ai_family of AF_INET6, then
1370Sstevel@tonic-gate * getaddrinfo() shall return IPv4-mapped IPv6 addresses
1380Sstevel@tonic-gate * on finding no matching IPv6 addresses ( ai_addrlen shall
1390Sstevel@tonic-gate * be 16). The AI_V4MAPPED flag shall be ignored unless
1400Sstevel@tonic-gate * ai_family equals AF_INET6.
1410Sstevel@tonic-gate * AI_ALL - If the AI_ALL flag is used with the AI_V4MAPPED flag,
1420Sstevel@tonic-gate * then getaddrinfo() shall return all matching IPv6 and
1430Sstevel@tonic-gate * IPv4 addresses. The AI_ALL flag without the AI_V4MAPPED
1440Sstevel@tonic-gate * flag is ignored.
1450Sstevel@tonic-gate * Output Parameters:
1460Sstevel@tonic-gate * res - upon successful return a pointer to a linked list of one
1470Sstevel@tonic-gate * or more addrinfo structures is returned through this
1480Sstevel@tonic-gate * argument. The caller can process each addrinfo structures
1490Sstevel@tonic-gate * in this list by following the ai_next pointer, until a
1500Sstevel@tonic-gate * NULL pointer is encountered. In each returned addrinfo
1510Sstevel@tonic-gate * structure the three members ai_family, ai_socktype, and
1520Sstevel@tonic-gate * ai_protocol are corresponding arguments for a call to the
1530Sstevel@tonic-gate * socket() function. In each addrinfo structure the ai_addr
1540Sstevel@tonic-gate * field points to filled-in socket address structure whose
1550Sstevel@tonic-gate * length is specified by the ai_addrlen member.
1560Sstevel@tonic-gate *
1570Sstevel@tonic-gate * Return Value:
1580Sstevel@tonic-gate * This function returns 0 upon success or a nonzero error code. The
1590Sstevel@tonic-gate * following names are nonzero error codes from getaddrinfo(), and are
1600Sstevel@tonic-gate * defined in <netdb.h>.
1610Sstevel@tonic-gate * EAI_ADDRFAMILY - address family not supported
1620Sstevel@tonic-gate * EAI_AGAIN - DNS temporary failure
1630Sstevel@tonic-gate * EAI_BADFLAGS - invalid ai_flags
1640Sstevel@tonic-gate * EAI_FAIL - DNS non-recoverable failure
1650Sstevel@tonic-gate * EAI_FAMILY - ai_family not supported
1660Sstevel@tonic-gate * EAI_MEMORY - memory allocation failure
1670Sstevel@tonic-gate * EAI_NODATA - no address associated with nodename
1680Sstevel@tonic-gate * EAI_NONAME - host/servname not known
1690Sstevel@tonic-gate * EAI_SERVICE - servname not supported for ai_socktype
1700Sstevel@tonic-gate * EAI_SOCKTYPE - ai_socktype not supported
1710Sstevel@tonic-gate * EAI_SYSTEM - system error in errno
1720Sstevel@tonic-gate *
1730Sstevel@tonic-gate * Memory Allocation:
1740Sstevel@tonic-gate * All of the information returned by getaddrinfo() is dynamically
1750Sstevel@tonic-gate * allocated: the addrinfo structures, and the socket address
1760Sstevel@tonic-gate * structures and canonical node name strings pointed to by the
1770Sstevel@tonic-gate * addrinfo structures.
1780Sstevel@tonic-gate */
1790Sstevel@tonic-gate
1800Sstevel@tonic-gate
1810Sstevel@tonic-gate static int
_getaddrinfo(const char * hostname,const char * servname,const struct addrinfo * hints,struct addrinfo ** res,int version)1820Sstevel@tonic-gate _getaddrinfo(const char *hostname, const char *servname,
1830Sstevel@tonic-gate const struct addrinfo *hints, struct addrinfo **res, int version)
1840Sstevel@tonic-gate {
1850Sstevel@tonic-gate struct addrinfo *cur;
1860Sstevel@tonic-gate struct addrinfo *aip;
1870Sstevel@tonic-gate struct addrinfo ai;
1880Sstevel@tonic-gate int error;
1890Sstevel@tonic-gate ushort_t port;
1900Sstevel@tonic-gate
1910Sstevel@tonic-gate cur = &ai;
1920Sstevel@tonic-gate aip = &ai;
1930Sstevel@tonic-gate
1940Sstevel@tonic-gate aip->ai_flags = 0;
1950Sstevel@tonic-gate aip->ai_family = PF_UNSPEC;
1960Sstevel@tonic-gate aip->ai_socktype = 0;
1970Sstevel@tonic-gate aip->ai_protocol = 0;
1980Sstevel@tonic-gate #ifdef __sparcv9
1990Sstevel@tonic-gate /*
2000Sstevel@tonic-gate * We need to clear _ai_pad to preserve binary
2010Sstevel@tonic-gate * compatibility with previously compiled 64-bit
2020Sstevel@tonic-gate * applications by guaranteeing the upper 32-bits
2030Sstevel@tonic-gate * are empty.
2040Sstevel@tonic-gate */
2050Sstevel@tonic-gate aip->_ai_pad = 0;
2060Sstevel@tonic-gate #endif /* __sparcv9 */
2070Sstevel@tonic-gate aip->ai_addrlen = 0;
2080Sstevel@tonic-gate aip->ai_canonname = NULL;
2090Sstevel@tonic-gate aip->ai_addr = NULL;
2100Sstevel@tonic-gate aip->ai_next = NULL;
2110Sstevel@tonic-gate port = 0;
2120Sstevel@tonic-gate
2130Sstevel@tonic-gate /* if nodename nor servname provided */
2140Sstevel@tonic-gate if (hostname == NULL && servname == NULL) {
2150Sstevel@tonic-gate *res = NULL;
2160Sstevel@tonic-gate return (EAI_NONAME);
2170Sstevel@tonic-gate }
2180Sstevel@tonic-gate if (hints != NULL) {
2190Sstevel@tonic-gate /* check for bad flags in hints */
2200Sstevel@tonic-gate if ((hints->ai_flags != 0) && (hints->ai_flags & ~AI_MASK)) {
2210Sstevel@tonic-gate *res = NULL;
2220Sstevel@tonic-gate return (EAI_BADFLAGS);
2230Sstevel@tonic-gate }
2240Sstevel@tonic-gate if ((hostname == NULL || *hostname == '\0') &&
2255586Skcpoon (hints->ai_flags & AI_CANONNAME)) {
2260Sstevel@tonic-gate *res = NULL;
2270Sstevel@tonic-gate return (EAI_BADFLAGS);
2280Sstevel@tonic-gate }
2290Sstevel@tonic-gate if (hints->ai_family != PF_UNSPEC &&
2300Sstevel@tonic-gate hints->ai_family != PF_INET &&
2310Sstevel@tonic-gate hints->ai_family != PF_INET6) {
2320Sstevel@tonic-gate *res = NULL;
2330Sstevel@tonic-gate return (EAI_FAMILY);
2340Sstevel@tonic-gate }
2350Sstevel@tonic-gate
2360Sstevel@tonic-gate (void) memcpy(aip, hints, sizeof (*aip));
2370Sstevel@tonic-gate #ifdef __sparcv9
2380Sstevel@tonic-gate /*
2390Sstevel@tonic-gate * We need to clear _ai_pad to preserve binary
2400Sstevel@tonic-gate * compatibility. See prior comment.
2410Sstevel@tonic-gate */
2420Sstevel@tonic-gate aip->_ai_pad = 0;
2430Sstevel@tonic-gate #endif /* __sparcv9 */
2440Sstevel@tonic-gate switch (aip->ai_socktype) {
2450Sstevel@tonic-gate case ANY:
2460Sstevel@tonic-gate switch (aip->ai_protocol) {
2470Sstevel@tonic-gate case ANY:
2480Sstevel@tonic-gate break;
2490Sstevel@tonic-gate case IPPROTO_UDP:
2500Sstevel@tonic-gate aip->ai_socktype = SOCK_DGRAM;
2510Sstevel@tonic-gate break;
2520Sstevel@tonic-gate case IPPROTO_TCP:
2535586Skcpoon case IPPROTO_SCTP:
2540Sstevel@tonic-gate aip->ai_socktype = SOCK_STREAM;
2550Sstevel@tonic-gate break;
2560Sstevel@tonic-gate default:
2570Sstevel@tonic-gate aip->ai_socktype = SOCK_RAW;
2580Sstevel@tonic-gate break;
2590Sstevel@tonic-gate }
2600Sstevel@tonic-gate break;
2610Sstevel@tonic-gate case SOCK_RAW:
2620Sstevel@tonic-gate break;
2635586Skcpoon case SOCK_SEQPACKET:
2645586Skcpoon /*
2655586Skcpoon * If the hint does not have a preference on the
2665586Skcpoon * protocol, use SCTP as the default for
2675586Skcpoon * SOCK_SEQPACKET.
2685586Skcpoon */
2695586Skcpoon if (aip->ai_protocol == ANY)
2705586Skcpoon aip->ai_protocol = IPPROTO_SCTP;
2715586Skcpoon break;
2720Sstevel@tonic-gate case SOCK_DGRAM:
2730Sstevel@tonic-gate aip->ai_protocol = IPPROTO_UDP;
2740Sstevel@tonic-gate break;
2750Sstevel@tonic-gate case SOCK_STREAM:
2765586Skcpoon /*
2775586Skcpoon * If the hint does not have a preference on the
2785586Skcpoon * protocol, use TCP as the default for SOCK_STREAM.
2795586Skcpoon */
2805586Skcpoon if (aip->ai_protocol == ANY)
2815586Skcpoon aip->ai_protocol = IPPROTO_TCP;
2820Sstevel@tonic-gate break;
2830Sstevel@tonic-gate default:
2840Sstevel@tonic-gate *res = NULL;
2850Sstevel@tonic-gate return (EAI_SOCKTYPE);
2860Sstevel@tonic-gate }
2870Sstevel@tonic-gate }
2880Sstevel@tonic-gate
2890Sstevel@tonic-gate /*
2900Sstevel@tonic-gate * Get the service.
2910Sstevel@tonic-gate */
2920Sstevel@tonic-gate
2930Sstevel@tonic-gate if (servname != NULL) {
2940Sstevel@tonic-gate struct servent result;
2950Sstevel@tonic-gate int bufsize = 128;
2960Sstevel@tonic-gate char *buf = NULL;
2970Sstevel@tonic-gate struct servent *sp;
2980Sstevel@tonic-gate char *proto = NULL;
2990Sstevel@tonic-gate
3000Sstevel@tonic-gate switch (aip->ai_socktype) {
3010Sstevel@tonic-gate case ANY:
3020Sstevel@tonic-gate proto = NULL;
3030Sstevel@tonic-gate break;
3040Sstevel@tonic-gate case SOCK_DGRAM:
3050Sstevel@tonic-gate proto = "udp";
3060Sstevel@tonic-gate break;
3070Sstevel@tonic-gate case SOCK_STREAM:
3085586Skcpoon /*
3095586Skcpoon * If there is no hint given, use TCP as the default
3105586Skcpoon * protocol.
3115586Skcpoon */
3125586Skcpoon switch (aip->ai_protocol) {
3135586Skcpoon case ANY:
3145586Skcpoon case IPPROTO_TCP:
3155586Skcpoon default:
3165586Skcpoon proto = "tcp";
3175586Skcpoon break;
3185586Skcpoon case IPPROTO_SCTP:
3195586Skcpoon proto = "sctp";
3205586Skcpoon break;
3215586Skcpoon }
3225586Skcpoon break;
3235586Skcpoon case SOCK_SEQPACKET:
3245586Skcpoon /* Default to SCTP if no hint given. */
3255586Skcpoon switch (aip->ai_protocol) {
3265586Skcpoon case ANY:
3275586Skcpoon default:
3285586Skcpoon proto = "sctp";
3295586Skcpoon break;
3305586Skcpoon }
3310Sstevel@tonic-gate break;
3320Sstevel@tonic-gate }
3330Sstevel@tonic-gate /*
3340Sstevel@tonic-gate * Servname string can be a decimal port number.
3350Sstevel@tonic-gate * If we already know the socket type there is no need
3360Sstevel@tonic-gate * to call getservbyport.
3370Sstevel@tonic-gate */
3380Sstevel@tonic-gate if (aip->ai_flags & AI_NUMERICSERV) {
3390Sstevel@tonic-gate if (!str_isnumber(servname)) {
3400Sstevel@tonic-gate return (EAI_NONAME);
3410Sstevel@tonic-gate }
3420Sstevel@tonic-gate port = htons(atoi(servname));
3430Sstevel@tonic-gate } else if (str_isnumber(servname)) {
3440Sstevel@tonic-gate port = htons(atoi(servname));
3450Sstevel@tonic-gate if (aip->ai_socktype == ANY) {
3460Sstevel@tonic-gate do {
3470Sstevel@tonic-gate if (buf != NULL)
3480Sstevel@tonic-gate free(buf);
3490Sstevel@tonic-gate bufsize *= 2;
3500Sstevel@tonic-gate buf = malloc(bufsize);
3510Sstevel@tonic-gate if (buf == NULL) {
3520Sstevel@tonic-gate *res = NULL;
3530Sstevel@tonic-gate return (EAI_MEMORY);
3540Sstevel@tonic-gate }
3550Sstevel@tonic-gate
3560Sstevel@tonic-gate sp = getservbyport_r(port, proto,
3570Sstevel@tonic-gate &result, buf, bufsize);
3580Sstevel@tonic-gate if (sp == NULL && errno != ERANGE) {
3590Sstevel@tonic-gate free(buf);
3600Sstevel@tonic-gate *res = NULL;
3610Sstevel@tonic-gate return (EAI_SERVICE);
3620Sstevel@tonic-gate }
3630Sstevel@tonic-gate /*
3640Sstevel@tonic-gate * errno == ERANGE so our scratch buffer space
3650Sstevel@tonic-gate * wasn't big enough. Double it and try
3660Sstevel@tonic-gate * again.
3670Sstevel@tonic-gate */
3680Sstevel@tonic-gate } while (sp == NULL);
3690Sstevel@tonic-gate }
3700Sstevel@tonic-gate } else {
3710Sstevel@tonic-gate do {
3720Sstevel@tonic-gate if (buf != NULL)
3730Sstevel@tonic-gate free(buf);
3740Sstevel@tonic-gate bufsize *= 2;
3750Sstevel@tonic-gate buf = malloc(bufsize);
3760Sstevel@tonic-gate if (buf == NULL) {
3770Sstevel@tonic-gate *res = NULL;
3780Sstevel@tonic-gate return (EAI_MEMORY);
3790Sstevel@tonic-gate }
3800Sstevel@tonic-gate
3810Sstevel@tonic-gate sp = getservbyname_r(servname, proto, &result,
3820Sstevel@tonic-gate buf, bufsize);
3830Sstevel@tonic-gate if (sp == NULL && errno != ERANGE) {
3840Sstevel@tonic-gate free(buf);
3850Sstevel@tonic-gate *res = NULL;
3860Sstevel@tonic-gate return (EAI_SERVICE);
3870Sstevel@tonic-gate }
3880Sstevel@tonic-gate /*
3890Sstevel@tonic-gate * errno == ERANGE so our scratch buffer space wasn't
3900Sstevel@tonic-gate * big enough. Double it and try again.
3910Sstevel@tonic-gate */
3920Sstevel@tonic-gate } while (sp == NULL);
3930Sstevel@tonic-gate
3940Sstevel@tonic-gate port = sp->s_port;
3950Sstevel@tonic-gate }
3960Sstevel@tonic-gate if (aip->ai_socktype == ANY) {
3970Sstevel@tonic-gate if (aip->ai_flags & AI_NUMERICSERV) {
3980Sstevel@tonic-gate /*
3990Sstevel@tonic-gate * RFC 2553bis doesn't allow us to use the
4000Sstevel@tonic-gate * any resolver to find out if there is a
4010Sstevel@tonic-gate * match. We could walk the service file
4020Sstevel@tonic-gate * with *servent(). Given the commonality of
4030Sstevel@tonic-gate * calling getaddrinfo() with a number and
4040Sstevel@tonic-gate * ANY protocol we won't add that at this time.
4050Sstevel@tonic-gate */
4060Sstevel@tonic-gate return (EAI_NONAME);
4070Sstevel@tonic-gate }
4080Sstevel@tonic-gate
4090Sstevel@tonic-gate if (strcmp(sp->s_proto, "udp") == 0) {
4100Sstevel@tonic-gate aip->ai_socktype = SOCK_DGRAM;
4110Sstevel@tonic-gate aip->ai_protocol = IPPROTO_UDP;
4120Sstevel@tonic-gate } else if (strcmp(sp->s_proto, "tcp") == 0) {
4130Sstevel@tonic-gate aip->ai_socktype = SOCK_STREAM;
4140Sstevel@tonic-gate aip->ai_protocol = IPPROTO_TCP;
4155586Skcpoon } else if (strcmp(sp->s_proto, "sctp") == 0) {
4165586Skcpoon aip->ai_socktype = SOCK_STREAM;
4175586Skcpoon aip->ai_protocol = IPPROTO_SCTP;
4180Sstevel@tonic-gate } else {
4190Sstevel@tonic-gate if (buf != NULL)
4200Sstevel@tonic-gate free(buf);
4210Sstevel@tonic-gate
4220Sstevel@tonic-gate *res = NULL;
4230Sstevel@tonic-gate errno = EPROTONOSUPPORT;
4240Sstevel@tonic-gate return (EAI_SYSTEM);
4250Sstevel@tonic-gate }
4260Sstevel@tonic-gate }
4270Sstevel@tonic-gate
4280Sstevel@tonic-gate if (buf != NULL)
4290Sstevel@tonic-gate free(buf);
4300Sstevel@tonic-gate }
4310Sstevel@tonic-gate
4320Sstevel@tonic-gate /*
4330Sstevel@tonic-gate * hostname is NULL
4340Sstevel@tonic-gate * case 1: AI_PASSIVE bit set : anyaddr 0.0.0.0 or ::
4350Sstevel@tonic-gate * case 2: AI_PASSIVE bit not set : localhost 127.0.0.1 or ::1
4360Sstevel@tonic-gate */
4370Sstevel@tonic-gate
4380Sstevel@tonic-gate if (hostname == NULL) {
4390Sstevel@tonic-gate struct addrinfo *nai;
4400Sstevel@tonic-gate socklen_t addrlen;
4410Sstevel@tonic-gate char *canonname;
4420Sstevel@tonic-gate
4430Sstevel@tonic-gate if (aip->ai_family == PF_INET)
4440Sstevel@tonic-gate goto v4only;
4450Sstevel@tonic-gate /* create IPv6 addrinfo */
4460Sstevel@tonic-gate nai = malloc(sizeof (struct addrinfo));
4470Sstevel@tonic-gate if (nai == NULL)
4480Sstevel@tonic-gate goto nomem;
4490Sstevel@tonic-gate *nai = *aip;
4500Sstevel@tonic-gate addrlen = sizeof (struct sockaddr_in6);
4510Sstevel@tonic-gate nai->ai_addr = malloc(addrlen);
4520Sstevel@tonic-gate if (nai->ai_addr == NULL) {
4530Sstevel@tonic-gate freeaddrinfo(nai);
4540Sstevel@tonic-gate goto nomem;
4550Sstevel@tonic-gate }
4560Sstevel@tonic-gate bzero(nai->ai_addr, addrlen);
4570Sstevel@tonic-gate nai->ai_addrlen = addrlen;
4580Sstevel@tonic-gate nai->ai_family = PF_INET6;
4590Sstevel@tonic-gate nai->ai_canonname = NULL;
4600Sstevel@tonic-gate if (nai->ai_flags & AI_PASSIVE) {
4610Sstevel@tonic-gate ai2sin6(nai)->sin6_addr = in6addr_any;
4620Sstevel@tonic-gate } else {
4630Sstevel@tonic-gate ai2sin6(nai)->sin6_addr = in6addr_loopback;
4640Sstevel@tonic-gate if (nai->ai_flags & AI_CANONNAME) {
4650Sstevel@tonic-gate canonname = strdup("loopback");
4660Sstevel@tonic-gate if (canonname == NULL) {
4670Sstevel@tonic-gate freeaddrinfo(nai);
4680Sstevel@tonic-gate goto nomem;
4690Sstevel@tonic-gate }
4700Sstevel@tonic-gate nai->ai_canonname = canonname;
4710Sstevel@tonic-gate }
4720Sstevel@tonic-gate }
4730Sstevel@tonic-gate ai2sin6(nai)->sin6_family = PF_INET6;
4740Sstevel@tonic-gate ai2sin6(nai)->sin6_port = port;
4750Sstevel@tonic-gate cur->ai_next = nai;
4760Sstevel@tonic-gate cur = nai;
4770Sstevel@tonic-gate if (aip->ai_family == PF_INET6) {
4780Sstevel@tonic-gate cur->ai_next = NULL;
4790Sstevel@tonic-gate goto success;
4800Sstevel@tonic-gate }
4810Sstevel@tonic-gate /* If address family is PF_UNSPEC or PF_INET */
4820Sstevel@tonic-gate v4only:
4830Sstevel@tonic-gate /* create IPv4 addrinfo */
4840Sstevel@tonic-gate nai = malloc(sizeof (struct addrinfo));
4850Sstevel@tonic-gate if (nai == NULL)
4860Sstevel@tonic-gate goto nomem;
4870Sstevel@tonic-gate *nai = *aip;
4880Sstevel@tonic-gate addrlen = sizeof (struct sockaddr_in);
4890Sstevel@tonic-gate nai->ai_addr = malloc(addrlen);
4900Sstevel@tonic-gate if (nai->ai_addr == NULL) {
4910Sstevel@tonic-gate freeaddrinfo(nai);
4920Sstevel@tonic-gate goto nomem;
4930Sstevel@tonic-gate }
4940Sstevel@tonic-gate bzero(nai->ai_addr, addrlen);
4950Sstevel@tonic-gate nai->ai_addrlen = addrlen;
4960Sstevel@tonic-gate nai->ai_family = PF_INET;
4970Sstevel@tonic-gate nai->ai_canonname = NULL;
4980Sstevel@tonic-gate if (nai->ai_flags & AI_PASSIVE) {
4990Sstevel@tonic-gate ai2sin(nai)->sin_addr.s_addr = INADDR_ANY;
5000Sstevel@tonic-gate } else {
5010Sstevel@tonic-gate ai2sin(nai)->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
5020Sstevel@tonic-gate if (nai->ai_flags & AI_CANONNAME &&
5030Sstevel@tonic-gate nai->ai_family != PF_UNSPEC) {
5040Sstevel@tonic-gate canonname = strdup("loopback");
5050Sstevel@tonic-gate if (canonname == NULL) {
5060Sstevel@tonic-gate freeaddrinfo(nai);
5070Sstevel@tonic-gate goto nomem;
5080Sstevel@tonic-gate }
5090Sstevel@tonic-gate nai->ai_canonname = canonname;
5100Sstevel@tonic-gate }
5110Sstevel@tonic-gate }
5120Sstevel@tonic-gate ai2sin(nai)->sin_family = PF_INET;
5130Sstevel@tonic-gate ai2sin(nai)->sin_port = port;
5140Sstevel@tonic-gate cur->ai_next = nai;
5150Sstevel@tonic-gate cur = nai;
5160Sstevel@tonic-gate cur->ai_next = NULL;
5170Sstevel@tonic-gate goto success;
5180Sstevel@tonic-gate }
5190Sstevel@tonic-gate
5200Sstevel@tonic-gate /* hostname string is a literal address or an alphabetical name */
5210Sstevel@tonic-gate error = get_addr(aip->ai_family, hostname, aip, cur, port, version);
5220Sstevel@tonic-gate if (error) {
5230Sstevel@tonic-gate *res = NULL;
5240Sstevel@tonic-gate return (error);
5250Sstevel@tonic-gate }
5260Sstevel@tonic-gate
5270Sstevel@tonic-gate success:
5280Sstevel@tonic-gate *res = aip->ai_next;
5290Sstevel@tonic-gate return (0);
5300Sstevel@tonic-gate
5310Sstevel@tonic-gate nomem:
5320Sstevel@tonic-gate return (EAI_MEMORY);
5330Sstevel@tonic-gate }
5340Sstevel@tonic-gate
5350Sstevel@tonic-gate int
getaddrinfo(const char * hostname,const char * servname,const struct addrinfo * hints,struct addrinfo ** res)5360Sstevel@tonic-gate getaddrinfo(const char *hostname, const char *servname,
5370Sstevel@tonic-gate const struct addrinfo *hints, struct addrinfo **res)
5380Sstevel@tonic-gate {
5390Sstevel@tonic-gate return (_getaddrinfo(hostname, servname, hints, res, GAIV_DEFAULT));
5400Sstevel@tonic-gate }
5410Sstevel@tonic-gate
5420Sstevel@tonic-gate int
__xnet_getaddrinfo(const char * hostname,const char * servname,const struct addrinfo * hints,struct addrinfo ** res)5430Sstevel@tonic-gate __xnet_getaddrinfo(const char *hostname, const char *servname,
5440Sstevel@tonic-gate const struct addrinfo *hints, struct addrinfo **res)
5450Sstevel@tonic-gate {
5460Sstevel@tonic-gate return (_getaddrinfo(hostname, servname, hints, res, GAIV_XPG6));
5470Sstevel@tonic-gate }
5480Sstevel@tonic-gate
5490Sstevel@tonic-gate static int
get_addr(int family,const char * hostname,struct addrinfo * aip,struct addrinfo * cur,ushort_t port,int version)5500Sstevel@tonic-gate get_addr(int family, const char *hostname, struct addrinfo *aip, struct
5510Sstevel@tonic-gate addrinfo *cur, ushort_t port, int version)
5520Sstevel@tonic-gate {
5530Sstevel@tonic-gate struct hostent *hp;
5540Sstevel@tonic-gate char _hostname[MAXHOSTNAMELEN];
5550Sstevel@tonic-gate int i, errnum;
5560Sstevel@tonic-gate struct addrinfo *nai;
5570Sstevel@tonic-gate int addrlen;
5580Sstevel@tonic-gate char *canonname;
5590Sstevel@tonic-gate boolean_t firsttime = B_TRUE;
5600Sstevel@tonic-gate boolean_t create_v6_addrinfo;
5610Sstevel@tonic-gate struct in_addr v4addr;
5620Sstevel@tonic-gate struct in6_addr v6addr;
5630Sstevel@tonic-gate struct in6_addr *v6addrp;
5640Sstevel@tonic-gate char *zonestr = NULL;
5650Sstevel@tonic-gate
5660Sstevel@tonic-gate /*
5670Sstevel@tonic-gate * Check for existence of address-zoneid delimiter '%'
5680Sstevel@tonic-gate * If the delimiter exists, parse the zoneid portion of
5690Sstevel@tonic-gate * <addr>%<zone_id>
5700Sstevel@tonic-gate */
5710Sstevel@tonic-gate if ((zonestr = strchr(hostname, '%')) != NULL) {
5720Sstevel@tonic-gate /* make sure we have room for <addr> portion of hostname */
5730Sstevel@tonic-gate if (((zonestr - hostname) + 1) > sizeof (_hostname)) {
5740Sstevel@tonic-gate return (EAI_MEMORY);
5750Sstevel@tonic-gate }
5760Sstevel@tonic-gate
5770Sstevel@tonic-gate /* chop off and save <zone_id> portion */
5780Sstevel@tonic-gate (void) strlcpy(_hostname, hostname, (zonestr - hostname) + 1);
5790Sstevel@tonic-gate ++zonestr; /* make zonestr point at start of <zone-id> */
5800Sstevel@tonic-gate /* ensure zone is valid */
5810Sstevel@tonic-gate if ((*zonestr == '\0') || (strlen(zonestr) > LIFNAMSIZ)) {
5820Sstevel@tonic-gate return (EAI_NONAME);
5830Sstevel@tonic-gate }
5840Sstevel@tonic-gate } else {
5850Sstevel@tonic-gate size_t hlen = sizeof (_hostname);
5860Sstevel@tonic-gate
5870Sstevel@tonic-gate if (strlcpy(_hostname, hostname, hlen) >= hlen) {
5880Sstevel@tonic-gate return (EAI_MEMORY);
5890Sstevel@tonic-gate }
5900Sstevel@tonic-gate }
5910Sstevel@tonic-gate
5920Sstevel@tonic-gate /* Check to see if AI_NUMERICHOST bit is set */
5930Sstevel@tonic-gate if (aip->ai_flags & AI_NUMERICHOST) {
5940Sstevel@tonic-gate /* check to see if _hostname points to a literal IP address */
5950Sstevel@tonic-gate if (!((inet_addr(_hostname) != ((in_addr_t)-1)) ||
5960Sstevel@tonic-gate (strcmp(_hostname, HOST_BROADCAST) == 0) ||
5970Sstevel@tonic-gate (inet_pton(AF_INET6, _hostname, &v6addr) > 0))) {
5980Sstevel@tonic-gate return (EAI_NONAME);
5990Sstevel@tonic-gate }
6000Sstevel@tonic-gate }
6010Sstevel@tonic-gate
6020Sstevel@tonic-gate /* if hostname argument is literal, name service doesn't get called */
6030Sstevel@tonic-gate if (family == PF_UNSPEC) {
6040Sstevel@tonic-gate hp = getipnodebyname(_hostname, AF_INET6, AI_ALL |
6050Sstevel@tonic-gate aip->ai_flags | AI_V4MAPPED, &errnum);
6060Sstevel@tonic-gate } else {
6070Sstevel@tonic-gate hp = getipnodebyname(_hostname, family, aip->ai_flags, &errnum);
6080Sstevel@tonic-gate }
6090Sstevel@tonic-gate
6100Sstevel@tonic-gate if (hp == NULL) {
6110Sstevel@tonic-gate switch (errnum) {
6120Sstevel@tonic-gate case HOST_NOT_FOUND:
6130Sstevel@tonic-gate return (EAI_NONAME);
6140Sstevel@tonic-gate case TRY_AGAIN:
6150Sstevel@tonic-gate return (EAI_AGAIN);
6160Sstevel@tonic-gate case NO_RECOVERY:
6170Sstevel@tonic-gate return (EAI_FAIL);
6180Sstevel@tonic-gate case NO_ADDRESS:
6190Sstevel@tonic-gate if (version == GAIV_XPG6)
6200Sstevel@tonic-gate return (EAI_NONAME);
6210Sstevel@tonic-gate return (EAI_NODATA);
6220Sstevel@tonic-gate default:
6230Sstevel@tonic-gate return (EAI_SYSTEM);
6240Sstevel@tonic-gate }
6250Sstevel@tonic-gate }
6260Sstevel@tonic-gate
6270Sstevel@tonic-gate for (i = 0; hp->h_addr_list[i]; i++) {
6280Sstevel@tonic-gate /* Determine if an IPv6 addrinfo structure should be created */
6290Sstevel@tonic-gate create_v6_addrinfo = B_TRUE;
6300Sstevel@tonic-gate if (hp->h_addrtype == AF_INET6) {
6310Sstevel@tonic-gate v6addrp = (struct in6_addr *)hp->h_addr_list[i];
6320Sstevel@tonic-gate if (!(aip->ai_flags & AI_V4MAPPED) &&
6330Sstevel@tonic-gate IN6_IS_ADDR_V4MAPPED(v6addrp)) {
6340Sstevel@tonic-gate create_v6_addrinfo = B_FALSE;
6350Sstevel@tonic-gate IN6_V4MAPPED_TO_INADDR(v6addrp, &v4addr);
6360Sstevel@tonic-gate }
6370Sstevel@tonic-gate } else if (hp->h_addrtype == AF_INET) {
6380Sstevel@tonic-gate create_v6_addrinfo = B_FALSE;
6390Sstevel@tonic-gate (void) memcpy(&v4addr, hp->h_addr_list[i],
6400Sstevel@tonic-gate sizeof (struct in_addr));
6410Sstevel@tonic-gate } else {
6420Sstevel@tonic-gate return (EAI_SYSTEM);
6430Sstevel@tonic-gate }
6440Sstevel@tonic-gate
6450Sstevel@tonic-gate if (create_v6_addrinfo) {
6460Sstevel@tonic-gate /* create IPv6 addrinfo */
6470Sstevel@tonic-gate nai = malloc(sizeof (struct addrinfo));
6480Sstevel@tonic-gate if (nai == NULL)
6490Sstevel@tonic-gate goto nomem;
6500Sstevel@tonic-gate *nai = *aip;
6510Sstevel@tonic-gate addrlen = sizeof (struct sockaddr_in6);
6520Sstevel@tonic-gate nai->ai_addr = malloc(addrlen);
6530Sstevel@tonic-gate if (nai->ai_addr == NULL) {
6540Sstevel@tonic-gate freeaddrinfo(nai);
6550Sstevel@tonic-gate goto nomem;
6560Sstevel@tonic-gate }
6570Sstevel@tonic-gate bzero(nai->ai_addr, addrlen);
6580Sstevel@tonic-gate nai->ai_addrlen = addrlen;
6590Sstevel@tonic-gate nai->ai_family = PF_INET6;
6600Sstevel@tonic-gate
6610Sstevel@tonic-gate (void) memcpy(ai2sin6(nai)->sin6_addr.s6_addr,
6620Sstevel@tonic-gate hp->h_addr_list[i], sizeof (struct in6_addr));
6630Sstevel@tonic-gate nai->ai_canonname = NULL;
6640Sstevel@tonic-gate if ((nai->ai_flags & AI_CANONNAME) && firsttime) {
6650Sstevel@tonic-gate canonname = strdup(hp->h_name);
6660Sstevel@tonic-gate if (canonname == NULL) {
6670Sstevel@tonic-gate freeaddrinfo(nai);
6680Sstevel@tonic-gate goto nomem;
6690Sstevel@tonic-gate }
6700Sstevel@tonic-gate nai->ai_canonname = canonname;
6710Sstevel@tonic-gate firsttime = B_FALSE;
6720Sstevel@tonic-gate }
6730Sstevel@tonic-gate ai2sin6(nai)->sin6_family = PF_INET6;
6740Sstevel@tonic-gate ai2sin6(nai)->sin6_port = port;
6750Sstevel@tonic-gate /* set sin6_scope_id */
6760Sstevel@tonic-gate if (zonestr != NULL) {
6770Sstevel@tonic-gate /*
6780Sstevel@tonic-gate * Translate 'zonestr' into a valid
6790Sstevel@tonic-gate * sin6_scope_id.
6800Sstevel@tonic-gate */
6810Sstevel@tonic-gate if ((errnum =
6820Sstevel@tonic-gate getscopeidfromzone(ai2sin6(nai), zonestr,
6835586Skcpoon &ai2sin6(nai)->sin6_scope_id)) != 0) {
6840Sstevel@tonic-gate return (errnum);
6850Sstevel@tonic-gate }
6860Sstevel@tonic-gate } else {
6870Sstevel@tonic-gate ai2sin6(nai)->sin6_scope_id = 0;
6880Sstevel@tonic-gate }
6890Sstevel@tonic-gate } else {
6900Sstevel@tonic-gate /* create IPv4 addrinfo */
6910Sstevel@tonic-gate nai = malloc(sizeof (struct addrinfo));
6920Sstevel@tonic-gate if (nai == NULL)
6930Sstevel@tonic-gate goto nomem;
6940Sstevel@tonic-gate *nai = *aip;
6950Sstevel@tonic-gate addrlen = sizeof (struct sockaddr_in);
6960Sstevel@tonic-gate nai->ai_addr = malloc(addrlen);
6970Sstevel@tonic-gate if (nai->ai_addr == NULL) {
6980Sstevel@tonic-gate freeaddrinfo(nai);
6990Sstevel@tonic-gate goto nomem;
7000Sstevel@tonic-gate }
7010Sstevel@tonic-gate bzero(nai->ai_addr, addrlen);
7020Sstevel@tonic-gate nai->ai_addrlen = addrlen;
7030Sstevel@tonic-gate nai->ai_family = PF_INET;
7040Sstevel@tonic-gate (void) memcpy(&(ai2sin(nai)->sin_addr.s_addr),
7050Sstevel@tonic-gate &v4addr, sizeof (struct in_addr));
7060Sstevel@tonic-gate nai->ai_canonname = NULL;
7070Sstevel@tonic-gate if (nai->ai_flags & AI_CANONNAME && firsttime) {
7080Sstevel@tonic-gate canonname = strdup(hp->h_name);
7090Sstevel@tonic-gate if (canonname == NULL) {
7100Sstevel@tonic-gate freeaddrinfo(nai);
7110Sstevel@tonic-gate goto nomem;
7120Sstevel@tonic-gate }
7130Sstevel@tonic-gate nai->ai_canonname = canonname;
7140Sstevel@tonic-gate firsttime = B_FALSE;
7150Sstevel@tonic-gate }
7160Sstevel@tonic-gate ai2sin(nai)->sin_family = PF_INET;
7170Sstevel@tonic-gate ai2sin(nai)->sin_port = port;
7180Sstevel@tonic-gate }
7190Sstevel@tonic-gate
7200Sstevel@tonic-gate cur->ai_next = nai;
7210Sstevel@tonic-gate cur = nai;
7220Sstevel@tonic-gate }
7230Sstevel@tonic-gate cur->ai_next = NULL;
7240Sstevel@tonic-gate freehostent(hp);
7250Sstevel@tonic-gate return (0);
7260Sstevel@tonic-gate
7270Sstevel@tonic-gate nomem:
7280Sstevel@tonic-gate freehostent(hp);
7290Sstevel@tonic-gate return (EAI_MEMORY);
7300Sstevel@tonic-gate
7310Sstevel@tonic-gate }
7320Sstevel@tonic-gate
7330Sstevel@tonic-gate /*
7340Sstevel@tonic-gate * getscopeidfromzone(sa, zone, sin6_scope_id)
7350Sstevel@tonic-gate *
7360Sstevel@tonic-gate * Converts the string pointed to by 'zone' into a sin6_scope_id.
7370Sstevel@tonic-gate * 'zone' will either be a pointer to an interface name or will
7380Sstevel@tonic-gate * be a literal sin6_scope_id.
7390Sstevel@tonic-gate *
7400Sstevel@tonic-gate * 0 is returned on success and the output parameter 'sin6_scope_id' will
7410Sstevel@tonic-gate * be set to a valid sin6_scope_id.
7420Sstevel@tonic-gate * EAI_NONAME is returned for either of two reasons:
7430Sstevel@tonic-gate * 1. The IPv6 address pointed to by sa->sin6_addr is not
7440Sstevel@tonic-gate * part of the 'link scope' (ie link local, nodelocal multicast or
7450Sstevel@tonic-gate * linklocal multicast address)
7460Sstevel@tonic-gate * 2. The string pointed to by 'zone' can not be translate to a valid
7470Sstevel@tonic-gate * sin6_scope_id.
7480Sstevel@tonic-gate */
7490Sstevel@tonic-gate static uint_t
getscopeidfromzone(const struct sockaddr_in6 * sa,const char * zone,uint32_t * sin6_scope_id)7500Sstevel@tonic-gate getscopeidfromzone(const struct sockaddr_in6 *sa, const char *zone,
7510Sstevel@tonic-gate uint32_t *sin6_scope_id) {
7520Sstevel@tonic-gate const in6_addr_t *addr = &sa->sin6_addr;
7530Sstevel@tonic-gate ulong_t ul_scope_id;
7540Sstevel@tonic-gate char *endp;
7550Sstevel@tonic-gate
7560Sstevel@tonic-gate if (IN6_IS_ADDR_LINKSCOPE(addr)) {
7570Sstevel@tonic-gate /*
7580Sstevel@tonic-gate * Look up interface index associated with interface name
7590Sstevel@tonic-gate * pointed to by 'zone'. Since the address is part of the link
7600Sstevel@tonic-gate * scope, there is a one-to-one relationship between interface
7610Sstevel@tonic-gate * index and sin6_scope_id.
7620Sstevel@tonic-gate * If an interface index can not be found for 'zone', then
7630Sstevel@tonic-gate * treat 'zone' as a literal sin6_scope_id value.
7640Sstevel@tonic-gate */
7650Sstevel@tonic-gate if ((*sin6_scope_id = if_nametoindex(zone)) != 0) {
7660Sstevel@tonic-gate return (0);
7670Sstevel@tonic-gate } else {
7680Sstevel@tonic-gate if ((ul_scope_id = strtoul(zone, &endp, 10)) != 0) {
7690Sstevel@tonic-gate /* check that entire string was read */
7700Sstevel@tonic-gate if (*endp != '\0') {
7710Sstevel@tonic-gate return (EAI_NONAME);
7720Sstevel@tonic-gate }
7730Sstevel@tonic-gate *sin6_scope_id =
7740Sstevel@tonic-gate (uint32_t)(ul_scope_id & 0xffffffffUL);
7750Sstevel@tonic-gate } else {
7760Sstevel@tonic-gate return (EAI_NONAME);
7770Sstevel@tonic-gate }
7780Sstevel@tonic-gate }
7790Sstevel@tonic-gate } else {
7800Sstevel@tonic-gate return (EAI_NONAME);
7810Sstevel@tonic-gate }
7820Sstevel@tonic-gate return (0);
7830Sstevel@tonic-gate }
7840Sstevel@tonic-gate
7850Sstevel@tonic-gate
7860Sstevel@tonic-gate void
freeaddrinfo(struct addrinfo * ai)7870Sstevel@tonic-gate freeaddrinfo(struct addrinfo *ai)
7880Sstevel@tonic-gate {
7890Sstevel@tonic-gate struct addrinfo *next;
7900Sstevel@tonic-gate
7910Sstevel@tonic-gate do {
7920Sstevel@tonic-gate next = ai->ai_next;
7930Sstevel@tonic-gate if (ai->ai_canonname)
7940Sstevel@tonic-gate free(ai->ai_canonname);
7950Sstevel@tonic-gate if (ai->ai_addr)
7960Sstevel@tonic-gate free(ai->ai_addr);
7970Sstevel@tonic-gate free(ai);
7980Sstevel@tonic-gate ai = next;
7990Sstevel@tonic-gate } while (ai != NULL);
8000Sstevel@tonic-gate }
8010Sstevel@tonic-gate
8020Sstevel@tonic-gate static boolean_t
str_isnumber(const char * p)8030Sstevel@tonic-gate str_isnumber(const char *p)
8040Sstevel@tonic-gate {
8050Sstevel@tonic-gate char *q = (char *)p;
8060Sstevel@tonic-gate while (*q) {
8070Sstevel@tonic-gate if (!isdigit(*q))
8080Sstevel@tonic-gate return (B_FALSE);
8090Sstevel@tonic-gate q++;
8100Sstevel@tonic-gate }
8110Sstevel@tonic-gate return (B_TRUE);
8120Sstevel@tonic-gate }
8130Sstevel@tonic-gate static const char *gai_errlist[] = {
8140Sstevel@tonic-gate "name translation error 0 (no error)", /* 0 */
8150Sstevel@tonic-gate "specified address family not supported", /* 1 EAI_ADDRFAMILY */
8160Sstevel@tonic-gate "temporary name resolution failure", /* 2 EAI_AGAIN */
8170Sstevel@tonic-gate "invalid flags", /* 3 EAI_BADFLAGS */
8180Sstevel@tonic-gate "non-recoverable name resolution failure", /* 4 EAI_FAIL */
8190Sstevel@tonic-gate "specified address family not supported", /* 5 EAI_FAMILY */
8200Sstevel@tonic-gate "memory allocation failure", /* 6 EAI_MEMORY */
8210Sstevel@tonic-gate "no address for the specified node name", /* 7 EAI_NODATA */
8220Sstevel@tonic-gate "node name or service name not known", /* 8 EAI_NONAME */
8230Sstevel@tonic-gate "service name not available for the specified socket type",
8240Sstevel@tonic-gate /* 9 EAI_SERVICE */
8250Sstevel@tonic-gate "specified socket type not supported", /* 10 EAI_SOCKTYPE */
8260Sstevel@tonic-gate "system error", /* 11 EAI_SYSTEM */
8270Sstevel@tonic-gate };
8280Sstevel@tonic-gate static int gai_nerr = { sizeof (gai_errlist)/sizeof (gai_errlist[0]) };
8290Sstevel@tonic-gate
8300Sstevel@tonic-gate const char *
gai_strerror(int ecode)8310Sstevel@tonic-gate gai_strerror(int ecode)
8320Sstevel@tonic-gate {
8330Sstevel@tonic-gate if (ecode < 0)
8346812Sraf return (dgettext(TEXT_DOMAIN,
8350Sstevel@tonic-gate "name translation internal error"));
8360Sstevel@tonic-gate else if (ecode < gai_nerr)
8376812Sraf return (dgettext(TEXT_DOMAIN, gai_errlist[ecode]));
8386812Sraf return (dgettext(TEXT_DOMAIN, "unknown name translation error"));
8390Sstevel@tonic-gate }
840