10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * Issues to be discussed: 30Sstevel@tonic-gate * - Thread safe-ness must be checked 40Sstevel@tonic-gate */ 50Sstevel@tonic-gate 6*11038SRao.Shoaib@Sun.COM #if ( defined(__linux__) || defined(__linux) || defined(LINUX) ) 7*11038SRao.Shoaib@Sun.COM #ifndef IF_NAMESIZE 8*11038SRao.Shoaib@Sun.COM # ifdef IFNAMSIZ 9*11038SRao.Shoaib@Sun.COM # define IF_NAMESIZE IFNAMSIZ 10*11038SRao.Shoaib@Sun.COM # else 11*11038SRao.Shoaib@Sun.COM # define IF_NAMESIZE 16 12*11038SRao.Shoaib@Sun.COM # endif 13*11038SRao.Shoaib@Sun.COM #endif 14*11038SRao.Shoaib@Sun.COM #endif 15*11038SRao.Shoaib@Sun.COM 160Sstevel@tonic-gate /* 170Sstevel@tonic-gate * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 180Sstevel@tonic-gate * All rights reserved. 190Sstevel@tonic-gate * 200Sstevel@tonic-gate * Redistribution and use in source and binary forms, with or without 210Sstevel@tonic-gate * modification, are permitted provided that the following conditions 220Sstevel@tonic-gate * are met: 230Sstevel@tonic-gate * 1. Redistributions of source code must retain the above copyright 240Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer. 250Sstevel@tonic-gate * 2. Redistributions in binary form must reproduce the above copyright 260Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer in the 270Sstevel@tonic-gate * documentation and/or other materials provided with the distribution. 280Sstevel@tonic-gate * 3. All advertising materials mentioning features or use of this software 290Sstevel@tonic-gate * must display the following acknowledgement: 300Sstevel@tonic-gate * This product includes software developed by WIDE Project and 310Sstevel@tonic-gate * its contributors. 320Sstevel@tonic-gate * 4. Neither the name of the project nor the names of its contributors 330Sstevel@tonic-gate * may be used to endorse or promote products derived from this software 340Sstevel@tonic-gate * without specific prior written permission. 350Sstevel@tonic-gate * 360Sstevel@tonic-gate * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 370Sstevel@tonic-gate * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 380Sstevel@tonic-gate * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 390Sstevel@tonic-gate * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 400Sstevel@tonic-gate * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 410Sstevel@tonic-gate * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 420Sstevel@tonic-gate * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 430Sstevel@tonic-gate * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 440Sstevel@tonic-gate * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 450Sstevel@tonic-gate * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 460Sstevel@tonic-gate * SUCH DAMAGE. 470Sstevel@tonic-gate */ 480Sstevel@tonic-gate 490Sstevel@tonic-gate #include <port_before.h> 500Sstevel@tonic-gate 510Sstevel@tonic-gate #include <sys/types.h> 520Sstevel@tonic-gate #include <sys/socket.h> 530Sstevel@tonic-gate 540Sstevel@tonic-gate #include <netinet/in.h> 550Sstevel@tonic-gate #include <arpa/nameser.h> 560Sstevel@tonic-gate #include <arpa/inet.h> 570Sstevel@tonic-gate #include <net/if.h> 580Sstevel@tonic-gate 590Sstevel@tonic-gate #include <netdb.h> 600Sstevel@tonic-gate #include <resolv.h> 610Sstevel@tonic-gate #include <string.h> 620Sstevel@tonic-gate #include <stddef.h> 630Sstevel@tonic-gate 640Sstevel@tonic-gate #include <port_after.h> 650Sstevel@tonic-gate 66*11038SRao.Shoaib@Sun.COM /*% 670Sstevel@tonic-gate * Note that a_off will be dynamically adjusted so that to be consistent 680Sstevel@tonic-gate * with the definition of sockaddr_in{,6}. 690Sstevel@tonic-gate * The value presented below is just a guess. 700Sstevel@tonic-gate */ 710Sstevel@tonic-gate static struct afd { 720Sstevel@tonic-gate int a_af; 730Sstevel@tonic-gate int a_addrlen; 740Sstevel@tonic-gate size_t a_socklen; 750Sstevel@tonic-gate int a_off; 760Sstevel@tonic-gate } afdl [] = { 770Sstevel@tonic-gate /* first entry is linked last... */ 780Sstevel@tonic-gate {PF_INET, sizeof(struct in_addr), sizeof(struct sockaddr_in), 790Sstevel@tonic-gate offsetof(struct sockaddr_in, sin_addr)}, 800Sstevel@tonic-gate {PF_INET6, sizeof(struct in6_addr), sizeof(struct sockaddr_in6), 810Sstevel@tonic-gate offsetof(struct sockaddr_in6, sin6_addr)}, 820Sstevel@tonic-gate {0, 0, 0, 0}, 830Sstevel@tonic-gate }; 840Sstevel@tonic-gate 850Sstevel@tonic-gate struct sockinet { 860Sstevel@tonic-gate #ifdef HAVE_SA_LEN 870Sstevel@tonic-gate u_char si_len; 880Sstevel@tonic-gate #endif 890Sstevel@tonic-gate u_char si_family; 900Sstevel@tonic-gate u_short si_port; 910Sstevel@tonic-gate }; 920Sstevel@tonic-gate 930Sstevel@tonic-gate static int ip6_parsenumeric __P((const struct sockaddr *, const char *, char *, 940Sstevel@tonic-gate size_t, int)); 950Sstevel@tonic-gate #ifdef HAVE_SIN6_SCOPE_ID 960Sstevel@tonic-gate static int ip6_sa2str __P((const struct sockaddr_in6 *, char *, size_t, int)); 970Sstevel@tonic-gate #endif 980Sstevel@tonic-gate 990Sstevel@tonic-gate int 1000Sstevel@tonic-gate getnameinfo(sa, salen, host, hostlen, serv, servlen, flags) 1010Sstevel@tonic-gate const struct sockaddr *sa; 1020Sstevel@tonic-gate size_t salen; 1030Sstevel@tonic-gate char *host; 1040Sstevel@tonic-gate size_t hostlen; 1050Sstevel@tonic-gate char *serv; 1060Sstevel@tonic-gate size_t servlen; 1070Sstevel@tonic-gate int flags; 1080Sstevel@tonic-gate { 1090Sstevel@tonic-gate struct afd *afd; 1100Sstevel@tonic-gate struct servent *sp; 1110Sstevel@tonic-gate struct hostent *hp; 1120Sstevel@tonic-gate u_short port; 1130Sstevel@tonic-gate #ifdef HAVE_SA_LEN 1140Sstevel@tonic-gate size_t len; 1150Sstevel@tonic-gate #endif 1160Sstevel@tonic-gate int family, i; 1170Sstevel@tonic-gate const char *addr; 1180Sstevel@tonic-gate char *p; 1190Sstevel@tonic-gate char numserv[512]; 1200Sstevel@tonic-gate char numaddr[512]; 1210Sstevel@tonic-gate const struct sockaddr_in6 *sin6; 1220Sstevel@tonic-gate 1230Sstevel@tonic-gate if (sa == NULL) 1240Sstevel@tonic-gate return EAI_FAIL; 1250Sstevel@tonic-gate 1260Sstevel@tonic-gate #ifdef HAVE_SA_LEN 1270Sstevel@tonic-gate len = sa->sa_len; 1280Sstevel@tonic-gate if (len != salen) return EAI_FAIL; 1290Sstevel@tonic-gate #endif 1300Sstevel@tonic-gate 1310Sstevel@tonic-gate family = sa->sa_family; 1320Sstevel@tonic-gate for (i = 0; afdl[i].a_af; i++) 1330Sstevel@tonic-gate if (afdl[i].a_af == family) { 1340Sstevel@tonic-gate afd = &afdl[i]; 1350Sstevel@tonic-gate goto found; 1360Sstevel@tonic-gate } 1370Sstevel@tonic-gate return EAI_FAMILY; 1380Sstevel@tonic-gate 1390Sstevel@tonic-gate found: 1400Sstevel@tonic-gate if (salen != afd->a_socklen) return EAI_FAIL; 1410Sstevel@tonic-gate 142*11038SRao.Shoaib@Sun.COM port = ((const struct sockinet *)sa)->si_port; /*%< network byte order */ 1430Sstevel@tonic-gate addr = (const char *)sa + afd->a_off; 1440Sstevel@tonic-gate 145*11038SRao.Shoaib@Sun.COM if (serv == NULL || servlen == 0U) { 1460Sstevel@tonic-gate /* 1470Sstevel@tonic-gate * rfc2553bis says that serv == NULL or servlen == 0 means that 1480Sstevel@tonic-gate * the caller does not want the result. 1490Sstevel@tonic-gate */ 1500Sstevel@tonic-gate } else if (flags & NI_NUMERICSERV) { 1510Sstevel@tonic-gate sprintf(numserv, "%d", ntohs(port)); 1520Sstevel@tonic-gate if (strlen(numserv) > servlen) 1530Sstevel@tonic-gate return EAI_MEMORY; 1540Sstevel@tonic-gate strcpy(serv, numserv); 1550Sstevel@tonic-gate } else { 1560Sstevel@tonic-gate sp = getservbyport(port, (flags & NI_DGRAM) ? "udp" : "tcp"); 1570Sstevel@tonic-gate if (sp) { 1580Sstevel@tonic-gate if (strlen(sp->s_name) + 1 > servlen) 1590Sstevel@tonic-gate return EAI_MEMORY; 1600Sstevel@tonic-gate strcpy(serv, sp->s_name); 1610Sstevel@tonic-gate } else 1620Sstevel@tonic-gate return EAI_NONAME; 1630Sstevel@tonic-gate } 1640Sstevel@tonic-gate 1650Sstevel@tonic-gate switch (sa->sa_family) { 1660Sstevel@tonic-gate case AF_INET: 167*11038SRao.Shoaib@Sun.COM if (ntohl(*(const u_int32_t *)addr) >> IN_CLASSA_NSHIFT == 0) 1680Sstevel@tonic-gate flags |= NI_NUMERICHOST; 1690Sstevel@tonic-gate break; 1700Sstevel@tonic-gate case AF_INET6: 1710Sstevel@tonic-gate sin6 = (const struct sockaddr_in6 *)sa; 1720Sstevel@tonic-gate switch (sin6->sin6_addr.s6_addr[0]) { 1730Sstevel@tonic-gate case 0x00: 1740Sstevel@tonic-gate if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) 1750Sstevel@tonic-gate ; 1760Sstevel@tonic-gate else if (IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr)) 1770Sstevel@tonic-gate ; 1780Sstevel@tonic-gate else 1790Sstevel@tonic-gate flags |= NI_NUMERICHOST; 1800Sstevel@tonic-gate break; 1810Sstevel@tonic-gate default: 1820Sstevel@tonic-gate if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) 1830Sstevel@tonic-gate flags |= NI_NUMERICHOST; 1840Sstevel@tonic-gate else if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) 1850Sstevel@tonic-gate flags |= NI_NUMERICHOST; 1860Sstevel@tonic-gate break; 1870Sstevel@tonic-gate } 1880Sstevel@tonic-gate break; 1890Sstevel@tonic-gate } 190*11038SRao.Shoaib@Sun.COM if (host == NULL || hostlen == 0U) { 1910Sstevel@tonic-gate /* 1920Sstevel@tonic-gate * rfc2553bis says that host == NULL or hostlen == 0 means that 1930Sstevel@tonic-gate * the caller does not want the result. 1940Sstevel@tonic-gate */ 1950Sstevel@tonic-gate } else if (flags & NI_NUMERICHOST) { 1960Sstevel@tonic-gate goto numeric; 1970Sstevel@tonic-gate } else { 1980Sstevel@tonic-gate hp = gethostbyaddr(addr, afd->a_addrlen, afd->a_af); 1990Sstevel@tonic-gate 2000Sstevel@tonic-gate if (hp) { 2010Sstevel@tonic-gate if (flags & NI_NOFQDN) { 2020Sstevel@tonic-gate p = strchr(hp->h_name, '.'); 2030Sstevel@tonic-gate if (p) *p = '\0'; 2040Sstevel@tonic-gate } 2050Sstevel@tonic-gate if (strlen(hp->h_name) + 1 > hostlen) 2060Sstevel@tonic-gate return EAI_MEMORY; 2070Sstevel@tonic-gate strcpy(host, hp->h_name); 2080Sstevel@tonic-gate } else { 2090Sstevel@tonic-gate if (flags & NI_NAMEREQD) 2100Sstevel@tonic-gate return EAI_NONAME; 2110Sstevel@tonic-gate numeric: 2120Sstevel@tonic-gate switch(afd->a_af) { 2130Sstevel@tonic-gate case AF_INET6: 2140Sstevel@tonic-gate { 2150Sstevel@tonic-gate int error; 2160Sstevel@tonic-gate 2170Sstevel@tonic-gate if ((error = ip6_parsenumeric(sa, addr, host, 2180Sstevel@tonic-gate hostlen, 2190Sstevel@tonic-gate flags)) != 0) 2200Sstevel@tonic-gate return(error); 2210Sstevel@tonic-gate break; 2220Sstevel@tonic-gate } 2230Sstevel@tonic-gate 2240Sstevel@tonic-gate default: 2250Sstevel@tonic-gate if (inet_ntop(afd->a_af, addr, numaddr, 2260Sstevel@tonic-gate sizeof(numaddr)) == NULL) 2270Sstevel@tonic-gate return EAI_NONAME; 2280Sstevel@tonic-gate if (strlen(numaddr) + 1 > hostlen) 2290Sstevel@tonic-gate return EAI_MEMORY; 2300Sstevel@tonic-gate strcpy(host, numaddr); 2310Sstevel@tonic-gate } 2320Sstevel@tonic-gate } 2330Sstevel@tonic-gate } 2340Sstevel@tonic-gate return(0); 2350Sstevel@tonic-gate } 2360Sstevel@tonic-gate 2370Sstevel@tonic-gate static int 2380Sstevel@tonic-gate ip6_parsenumeric(const struct sockaddr *sa, const char *addr, char *host, 2390Sstevel@tonic-gate size_t hostlen, int flags) 2400Sstevel@tonic-gate { 2410Sstevel@tonic-gate size_t numaddrlen; 2420Sstevel@tonic-gate char numaddr[512]; 2430Sstevel@tonic-gate 2440Sstevel@tonic-gate #ifndef HAVE_SIN6_SCOPE_ID 2450Sstevel@tonic-gate UNUSED(sa); 2460Sstevel@tonic-gate UNUSED(flags); 2470Sstevel@tonic-gate #endif 2480Sstevel@tonic-gate 2490Sstevel@tonic-gate if (inet_ntop(AF_INET6, addr, numaddr, sizeof(numaddr)) 2500Sstevel@tonic-gate == NULL) 2510Sstevel@tonic-gate return EAI_SYSTEM; 2520Sstevel@tonic-gate 2530Sstevel@tonic-gate numaddrlen = strlen(numaddr); 254*11038SRao.Shoaib@Sun.COM if (numaddrlen + 1 > hostlen) /*%< don't forget terminator */ 2550Sstevel@tonic-gate return EAI_MEMORY; 2560Sstevel@tonic-gate strcpy(host, numaddr); 2570Sstevel@tonic-gate 2580Sstevel@tonic-gate #ifdef HAVE_SIN6_SCOPE_ID 2590Sstevel@tonic-gate if (((const struct sockaddr_in6 *)sa)->sin6_scope_id) { 260*11038SRao.Shoaib@Sun.COM char scopebuf[MAXHOSTNAMELEN]; /*%< XXX */ 2610Sstevel@tonic-gate int scopelen; 2620Sstevel@tonic-gate 2630Sstevel@tonic-gate /* ip6_sa2str never fails */ 2640Sstevel@tonic-gate scopelen = ip6_sa2str((const struct sockaddr_in6 *)sa, 2650Sstevel@tonic-gate scopebuf, sizeof(scopebuf), flags); 2660Sstevel@tonic-gate 2670Sstevel@tonic-gate if (scopelen + 1 + numaddrlen + 1 > hostlen) 2680Sstevel@tonic-gate return EAI_MEMORY; 2690Sstevel@tonic-gate 2700Sstevel@tonic-gate /* construct <numeric-addr><delim><scopeid> */ 2710Sstevel@tonic-gate memcpy(host + numaddrlen + 1, scopebuf, 2720Sstevel@tonic-gate scopelen); 2730Sstevel@tonic-gate host[numaddrlen] = SCOPE_DELIMITER; 2740Sstevel@tonic-gate host[numaddrlen + 1 + scopelen] = '\0'; 2750Sstevel@tonic-gate } 2760Sstevel@tonic-gate #endif 2770Sstevel@tonic-gate 2780Sstevel@tonic-gate return 0; 2790Sstevel@tonic-gate } 2800Sstevel@tonic-gate 2810Sstevel@tonic-gate #ifdef HAVE_SIN6_SCOPE_ID 2820Sstevel@tonic-gate /* ARGSUSED */ 2830Sstevel@tonic-gate static int 2840Sstevel@tonic-gate ip6_sa2str(const struct sockaddr_in6 *sa6, char *buf, 2850Sstevel@tonic-gate size_t bufsiz, int flags) 2860Sstevel@tonic-gate { 2870Sstevel@tonic-gate #ifdef USE_IFNAMELINKID 2880Sstevel@tonic-gate unsigned int ifindex = (unsigned int)sa6->sin6_scope_id; 2890Sstevel@tonic-gate const struct in6_addr *a6 = &sa6->sin6_addr; 2900Sstevel@tonic-gate #endif 2910Sstevel@tonic-gate char tmp[64]; 2920Sstevel@tonic-gate 2930Sstevel@tonic-gate #ifdef NI_NUMERICSCOPE 2940Sstevel@tonic-gate if (flags & NI_NUMERICSCOPE) { 2950Sstevel@tonic-gate sprintf(tmp, "%u", sa6->sin6_scope_id); 296*11038SRao.Shoaib@Sun.COM if (bufsiz != 0U) { 2970Sstevel@tonic-gate strncpy(buf, tmp, bufsiz - 1); 2980Sstevel@tonic-gate buf[bufsiz - 1] = '\0'; 2990Sstevel@tonic-gate } 3000Sstevel@tonic-gate return(strlen(tmp)); 3010Sstevel@tonic-gate } 3020Sstevel@tonic-gate #endif 3030Sstevel@tonic-gate 3040Sstevel@tonic-gate #ifdef USE_IFNAMELINKID 3050Sstevel@tonic-gate /* 3060Sstevel@tonic-gate * For a link-local address, convert the index to an interface 3070Sstevel@tonic-gate * name, assuming a one-to-one mapping between links and interfaces. 3080Sstevel@tonic-gate * Note, however, that this assumption is stronger than the 3090Sstevel@tonic-gate * specification of the scoped address architecture; the 3100Sstevel@tonic-gate * specficication says that more than one interfaces can belong to 3110Sstevel@tonic-gate * a single link. 3120Sstevel@tonic-gate */ 3130Sstevel@tonic-gate 3140Sstevel@tonic-gate /* if_indextoname() does not take buffer size. not a good api... */ 3150Sstevel@tonic-gate if ((IN6_IS_ADDR_LINKLOCAL(a6) || IN6_IS_ADDR_MC_LINKLOCAL(a6)) && 3160Sstevel@tonic-gate bufsiz >= IF_NAMESIZE) { 3170Sstevel@tonic-gate char *p = if_indextoname(ifindex, buf); 3180Sstevel@tonic-gate if (p) { 3190Sstevel@tonic-gate return(strlen(p)); 3200Sstevel@tonic-gate } 3210Sstevel@tonic-gate } 3220Sstevel@tonic-gate #endif 3230Sstevel@tonic-gate 3240Sstevel@tonic-gate /* last resort */ 3250Sstevel@tonic-gate sprintf(tmp, "%u", sa6->sin6_scope_id); 326*11038SRao.Shoaib@Sun.COM if (bufsiz != 0U) { 3270Sstevel@tonic-gate strncpy(buf, tmp, bufsiz - 1); 3280Sstevel@tonic-gate buf[bufsiz - 1] = '\0'; 3290Sstevel@tonic-gate } 3300Sstevel@tonic-gate return(strlen(tmp)); 3310Sstevel@tonic-gate } 3320Sstevel@tonic-gate #endif 333*11038SRao.Shoaib@Sun.COM 334*11038SRao.Shoaib@Sun.COM /*! \file */ 335