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