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