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
getnameinfo(sa,salen,host,hostlen,serv,servlen,flags)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
ip6_parsenumeric(const struct sockaddr * sa,const char * addr,char * host,size_t hostlen,int flags)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
ip6_sa2str(const struct sockaddr_in6 * sa6,char * buf,size_t bufsiz,int flags)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