17d56d374SYoshinobu Inoue /* 27d56d374SYoshinobu Inoue * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 37d56d374SYoshinobu Inoue * All rights reserved. 47d56d374SYoshinobu Inoue * 57d56d374SYoshinobu Inoue * Redistribution and use in source and binary forms, with or without 67d56d374SYoshinobu Inoue * modification, are permitted provided that the following conditions 77d56d374SYoshinobu Inoue * are met: 87d56d374SYoshinobu Inoue * 1. Redistributions of source code must retain the above copyright 97d56d374SYoshinobu Inoue * notice, this list of conditions and the following disclaimer. 107d56d374SYoshinobu Inoue * 2. Redistributions in binary form must reproduce the above copyright 117d56d374SYoshinobu Inoue * notice, this list of conditions and the following disclaimer in the 127d56d374SYoshinobu Inoue * documentation and/or other materials provided with the distribution. 137d56d374SYoshinobu Inoue * 3. Neither the name of the project nor the names of its contributors 147d56d374SYoshinobu Inoue * may be used to endorse or promote products derived from this software 157d56d374SYoshinobu Inoue * without specific prior written permission. 167d56d374SYoshinobu Inoue * 177d56d374SYoshinobu Inoue * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 187d56d374SYoshinobu Inoue * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 197d56d374SYoshinobu Inoue * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 207d56d374SYoshinobu Inoue * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 217d56d374SYoshinobu Inoue * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 227d56d374SYoshinobu Inoue * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 237d56d374SYoshinobu Inoue * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 247d56d374SYoshinobu Inoue * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 257d56d374SYoshinobu Inoue * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 267d56d374SYoshinobu Inoue * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 277d56d374SYoshinobu Inoue * SUCH DAMAGE. 287d56d374SYoshinobu Inoue * 297d56d374SYoshinobu Inoue * $FreeBSD$ 307d56d374SYoshinobu Inoue */ 317d56d374SYoshinobu Inoue 327d56d374SYoshinobu Inoue /* 337d56d374SYoshinobu Inoue * Issues to be discussed: 347d56d374SYoshinobu Inoue * - Thread safe-ness must be checked 357d56d374SYoshinobu Inoue * - Return values. There seems to be no standard for return value (RFC2553) 367d56d374SYoshinobu Inoue * but INRIA implementation returns EAI_xxx defined for getaddrinfo(). 377d56d374SYoshinobu Inoue */ 387d56d374SYoshinobu Inoue 397d56d374SYoshinobu Inoue #include <sys/types.h> 407d56d374SYoshinobu Inoue #include <sys/socket.h> 417d56d374SYoshinobu Inoue #include <net/if.h> 427d56d374SYoshinobu Inoue #include <netinet/in.h> 437d56d374SYoshinobu Inoue #include <arpa/inet.h> 447d56d374SYoshinobu Inoue #include <arpa/nameser.h> 457d56d374SYoshinobu Inoue #include <netdb.h> 467d56d374SYoshinobu Inoue #include <resolv.h> 477d56d374SYoshinobu Inoue #include <string.h> 487d56d374SYoshinobu Inoue #include <stddef.h> 497d56d374SYoshinobu Inoue 507d56d374SYoshinobu Inoue #define SUCCESS 0 517d56d374SYoshinobu Inoue #define ANY 0 527d56d374SYoshinobu Inoue #define YES 1 537d56d374SYoshinobu Inoue #define NO 0 547d56d374SYoshinobu Inoue 557d56d374SYoshinobu Inoue static struct afd { 567d56d374SYoshinobu Inoue int a_af; 577d56d374SYoshinobu Inoue int a_addrlen; 587d56d374SYoshinobu Inoue int a_socklen; 597d56d374SYoshinobu Inoue int a_off; 607d56d374SYoshinobu Inoue } afdl [] = { 617d56d374SYoshinobu Inoue #ifdef INET6 627d56d374SYoshinobu Inoue {PF_INET6, sizeof(struct in6_addr), sizeof(struct sockaddr_in6), 637d56d374SYoshinobu Inoue offsetof(struct sockaddr_in6, sin6_addr)}, 647d56d374SYoshinobu Inoue #endif 657d56d374SYoshinobu Inoue {PF_INET, sizeof(struct in_addr), sizeof(struct sockaddr_in), 667d56d374SYoshinobu Inoue offsetof(struct sockaddr_in, sin_addr)}, 677d56d374SYoshinobu Inoue {0, 0, 0}, 687d56d374SYoshinobu Inoue }; 697d56d374SYoshinobu Inoue 707d56d374SYoshinobu Inoue struct sockinet { 717d56d374SYoshinobu Inoue u_char si_len; 727d56d374SYoshinobu Inoue u_char si_family; 737d56d374SYoshinobu Inoue u_short si_port; 747d56d374SYoshinobu Inoue }; 757d56d374SYoshinobu Inoue 767d56d374SYoshinobu Inoue #define ENI_NOSOCKET 0 777d56d374SYoshinobu Inoue #define ENI_NOSERVHOST 1 787d56d374SYoshinobu Inoue #define ENI_NOHOSTNAME 2 797d56d374SYoshinobu Inoue #define ENI_MEMORY 3 807d56d374SYoshinobu Inoue #define ENI_SYSTEM 4 817d56d374SYoshinobu Inoue #define ENI_FAMILY 5 827d56d374SYoshinobu Inoue #define ENI_SALEN 6 837d56d374SYoshinobu Inoue 847d56d374SYoshinobu Inoue int 857d56d374SYoshinobu Inoue getnameinfo(sa, salen, host, hostlen, serv, servlen, flags) 867d56d374SYoshinobu Inoue const struct sockaddr *sa; 877d56d374SYoshinobu Inoue size_t salen; 887d56d374SYoshinobu Inoue char *host; 897d56d374SYoshinobu Inoue size_t hostlen; 907d56d374SYoshinobu Inoue char *serv; 917d56d374SYoshinobu Inoue size_t servlen; 927d56d374SYoshinobu Inoue int flags; 937d56d374SYoshinobu Inoue { 947d56d374SYoshinobu Inoue struct afd *afd; 957d56d374SYoshinobu Inoue struct servent *sp; 967d56d374SYoshinobu Inoue struct hostent *hp; 977d56d374SYoshinobu Inoue u_short port; 987d56d374SYoshinobu Inoue int family, i; 997d56d374SYoshinobu Inoue char *addr, *p; 1007d56d374SYoshinobu Inoue u_long v4a; 1017d56d374SYoshinobu Inoue int h_error; 1027d56d374SYoshinobu Inoue char numserv[512]; 1037d56d374SYoshinobu Inoue char numaddr[512]; 1047d56d374SYoshinobu Inoue int noserv = 0; 1057d56d374SYoshinobu Inoue 1067d56d374SYoshinobu Inoue if (sa == NULL) 1077d56d374SYoshinobu Inoue return ENI_NOSOCKET; 1087d56d374SYoshinobu Inoue 1097d56d374SYoshinobu Inoue if (sa->sa_len != salen) 1107d56d374SYoshinobu Inoue return ENI_SALEN; 1117d56d374SYoshinobu Inoue 1127d56d374SYoshinobu Inoue family = sa->sa_family; 1137d56d374SYoshinobu Inoue for (i = 0; afdl[i].a_af; i++) 1147d56d374SYoshinobu Inoue if (afdl[i].a_af == family) { 1157d56d374SYoshinobu Inoue afd = &afdl[i]; 1167d56d374SYoshinobu Inoue goto found; 1177d56d374SYoshinobu Inoue } 1187d56d374SYoshinobu Inoue return ENI_FAMILY; 1197d56d374SYoshinobu Inoue 1207d56d374SYoshinobu Inoue found: 1217d56d374SYoshinobu Inoue if (salen != afd->a_socklen) 1227d56d374SYoshinobu Inoue return ENI_SALEN; 1237d56d374SYoshinobu Inoue 1247d56d374SYoshinobu Inoue port = ((struct sockinet *)sa)->si_port; /* network byte order */ 1257d56d374SYoshinobu Inoue addr = (char *)sa + afd->a_off; 1267d56d374SYoshinobu Inoue 1277d56d374SYoshinobu Inoue if (serv == NULL || servlen == 0) { 1287d56d374SYoshinobu Inoue noserv = 1; 1297d56d374SYoshinobu Inoue } else { 1307d56d374SYoshinobu Inoue if (flags & NI_NUMERICSERV) 1317d56d374SYoshinobu Inoue sp = NULL; 1327d56d374SYoshinobu Inoue else { 1337d56d374SYoshinobu Inoue sp = getservbyport(port, 1347d56d374SYoshinobu Inoue (flags & NI_DGRAM) ? "udp" : "tcp"); 1357d56d374SYoshinobu Inoue } 1367d56d374SYoshinobu Inoue if (sp) { 1377d56d374SYoshinobu Inoue if (strlen(sp->s_name) > servlen) 1387d56d374SYoshinobu Inoue return ENI_MEMORY; 1397d56d374SYoshinobu Inoue strcpy(serv, sp->s_name); 1407d56d374SYoshinobu Inoue } else { 1417d56d374SYoshinobu Inoue snprintf(numserv, sizeof(numserv), "%d", ntohs(port)); 1427d56d374SYoshinobu Inoue if (strlen(numserv) > servlen) 1437d56d374SYoshinobu Inoue return ENI_MEMORY; 1447d56d374SYoshinobu Inoue strcpy(serv, numserv); 1457d56d374SYoshinobu Inoue } 1467d56d374SYoshinobu Inoue } 1477d56d374SYoshinobu Inoue 1487d56d374SYoshinobu Inoue switch (sa->sa_family) { 1497d56d374SYoshinobu Inoue case AF_INET: 1507d56d374SYoshinobu Inoue v4a = ntohl(((struct sockaddr_in *)sa)->sin_addr.s_addr); 1517d56d374SYoshinobu Inoue if (IN_MULTICAST(v4a) || IN_EXPERIMENTAL(v4a)) 1527d56d374SYoshinobu Inoue flags |= NI_NUMERICHOST; 1537d56d374SYoshinobu Inoue v4a >>= IN_CLASSA_NSHIFT; 1547d56d374SYoshinobu Inoue if (v4a == 0 || v4a == IN_LOOPBACKNET) 1557d56d374SYoshinobu Inoue flags |= NI_NUMERICHOST; 1567d56d374SYoshinobu Inoue break; 1577d56d374SYoshinobu Inoue #ifdef INET6 1587d56d374SYoshinobu Inoue case AF_INET6: 1597d56d374SYoshinobu Inoue { 1607d56d374SYoshinobu Inoue struct sockaddr_in6 *sin6; 1617d56d374SYoshinobu Inoue sin6 = (struct sockaddr_in6 *)sa; 1627d56d374SYoshinobu Inoue if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) || 1637d56d374SYoshinobu Inoue IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) 1647d56d374SYoshinobu Inoue flags |= NI_NUMERICHOST; 1657d56d374SYoshinobu Inoue } 1667d56d374SYoshinobu Inoue break; 1677d56d374SYoshinobu Inoue #endif 1687d56d374SYoshinobu Inoue } 1697d56d374SYoshinobu Inoue if (host == NULL || hostlen == 0) { 1707d56d374SYoshinobu Inoue if (noserv == 1) 1717d56d374SYoshinobu Inoue return ENI_NOSERVHOST; 1727d56d374SYoshinobu Inoue } else if (flags & NI_NUMERICHOST) { 1737d56d374SYoshinobu Inoue /* NUMERICHOST and NAMEREQD conflicts with each other */ 1747d56d374SYoshinobu Inoue if (flags & NI_NAMEREQD) 1757d56d374SYoshinobu Inoue return ENI_NOHOSTNAME; 1767d56d374SYoshinobu Inoue if (inet_ntop(afd->a_af, addr, numaddr, sizeof(numaddr)) 1777d56d374SYoshinobu Inoue == NULL) 1787d56d374SYoshinobu Inoue return ENI_SYSTEM; 1797d56d374SYoshinobu Inoue if (strlen(numaddr) > hostlen) 1807d56d374SYoshinobu Inoue return ENI_MEMORY; 1817d56d374SYoshinobu Inoue strcpy(host, numaddr); 1827d56d374SYoshinobu Inoue #ifdef INET6 1837d56d374SYoshinobu Inoue if (afd->a_af == AF_INET6 && 1847d56d374SYoshinobu Inoue (IN6_IS_ADDR_LINKLOCAL((struct in6_addr *)addr) || 1857d56d374SYoshinobu Inoue IN6_IS_ADDR_MULTICAST((struct in6_addr *)addr)) && 1867d56d374SYoshinobu Inoue ((struct sockaddr_in6 *)sa)->sin6_scope_id) { 1877d56d374SYoshinobu Inoue if (flags & NI_WITHSCOPEID) { 1887d56d374SYoshinobu Inoue char *ep = strchr(host, '\0'); 1897d56d374SYoshinobu Inoue unsigned int ifindex = 1907d56d374SYoshinobu Inoue ((struct sockaddr_in6 *)sa)->sin6_scope_id; 1917d56d374SYoshinobu Inoue char ifname[IF_NAMESIZE * 2 /* for safety */]; 1927d56d374SYoshinobu Inoue 1937d56d374SYoshinobu Inoue if ((if_indextoname(ifindex, ifname)) == NULL) 1947d56d374SYoshinobu Inoue return ENI_SYSTEM; 1957d56d374SYoshinobu Inoue if (strlen(host) + 1 /* SCOPE_DELIMITER */ 1967d56d374SYoshinobu Inoue + strlen(ifname) > hostlen) 1977d56d374SYoshinobu Inoue return ENI_MEMORY; 1987d56d374SYoshinobu Inoue *ep = SCOPE_DELIMITER; 1997d56d374SYoshinobu Inoue strcpy(ep + 1, ifname); 2007d56d374SYoshinobu Inoue } 2017d56d374SYoshinobu Inoue } 2027d56d374SYoshinobu Inoue #endif /* INET6 */ 2037d56d374SYoshinobu Inoue } else { 2047d56d374SYoshinobu Inoue hp = getipnodebyaddr(addr, afd->a_addrlen, afd->a_af, &h_error); 2057d56d374SYoshinobu Inoue if (hp) { 2067d56d374SYoshinobu Inoue if (flags & NI_NOFQDN) { 2077d56d374SYoshinobu Inoue p = strchr(hp->h_name, '.'); 2087d56d374SYoshinobu Inoue if (p) *p = '\0'; 2097d56d374SYoshinobu Inoue } 2107d56d374SYoshinobu Inoue if (strlen(hp->h_name) > hostlen) { 2117d56d374SYoshinobu Inoue freehostent(hp); 2127d56d374SYoshinobu Inoue return ENI_MEMORY; 2137d56d374SYoshinobu Inoue } 2147d56d374SYoshinobu Inoue strcpy(host, hp->h_name); 2157d56d374SYoshinobu Inoue freehostent(hp); 2167d56d374SYoshinobu Inoue } else { 2177d56d374SYoshinobu Inoue if (flags & NI_NAMEREQD) 2187d56d374SYoshinobu Inoue return ENI_NOHOSTNAME; 2197d56d374SYoshinobu Inoue if (inet_ntop(afd->a_af, addr, numaddr, sizeof(numaddr)) 2207d56d374SYoshinobu Inoue == NULL) 2217d56d374SYoshinobu Inoue return ENI_NOHOSTNAME; 2227d56d374SYoshinobu Inoue if (strlen(numaddr) > hostlen) 2237d56d374SYoshinobu Inoue return ENI_MEMORY; 2247d56d374SYoshinobu Inoue strcpy(host, numaddr); 2257d56d374SYoshinobu Inoue } 2267d56d374SYoshinobu Inoue } 2277d56d374SYoshinobu Inoue return SUCCESS; 2287d56d374SYoshinobu Inoue } 229