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