From d9056b0e3240e176c6cfdfc13ac1cf384b0a04fd Mon Sep 17 00:00:00 2001 From: itojun <> Date: Thu, 30 Dec 1999 08:54:20 +0000 Subject: replace NRL get{addr,name}info with KAME get{addr,name}info. removed functionality: new code will not return AF_LOCAL addrinfo struct. added funtionality: SOCK_RAW is permitted as ai_socktype (no servname allowed). draft-ietf-ipngwg-scopedaddr-format-00.txt --- src/lib/libc/net/getnameinfo.c | 446 +++++++++++++++++++++-------------------- 1 file changed, 233 insertions(+), 213 deletions(-) (limited to 'src/lib/libc/net/getnameinfo.c') diff --git a/src/lib/libc/net/getnameinfo.c b/src/lib/libc/net/getnameinfo.c index 62c4b9d928..787beec9c6 100644 --- a/src/lib/libc/net/getnameinfo.c +++ b/src/lib/libc/net/getnameinfo.c @@ -1,7 +1,9 @@ +/* $OpenBSD: getnameinfo.c,v 1.5 1999/12/30 08:54:20 itojun Exp $ */ + /* - * %%% copyright-cmetz-96-bsd - * Copyright (c) 1996-1999, Craig Metz, All rights reserved. - * + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -10,18 +12,14 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Craig Metz and - * by other contributors. - * 4. Neither the name of the author nor the names of contributors + * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) @@ -29,236 +27,258 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. - * */ -/* getnameinfo() v1.38 */ +/* + * Issues to be discussed: + * - Thread safe-ness must be checked + * - Return values. There seems to be no standard for return value (RFC2553) + * but INRIA implementation returns EAI_xxx defined for getaddrinfo(). + * - RFC2553 says that we should raise error on short buffer. X/Open says + * we need to truncate the result. We obey RFC2553 (and X/Open should be + * modified). + */ + +#if 0 +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#else +#define HAVE_SA_LEN +#define INET6 +#endif #include #include +#include #include -#include -#include -#include #include -#include -#include +#include +#include #include +#include +#include -#ifndef min -#define min(x,y) (((x) > (y)) ? (y) : (x)) -#endif /* min */ - -static int -netdb_lookup_name(int family, void *addr, int addrlen, char *name, - int namelen, int flags) -{ - struct hostent *hostent; - char *c, *c2; - int i; - - if (!(hostent = gethostbyaddr(addr, addrlen, family))) { - switch (h_errno) { - case NETDB_INTERNAL: - return(EAI_SYSTEM); - case HOST_NOT_FOUND: - return(1); - case TRY_AGAIN: - return(EAI_AGAIN); - case NO_RECOVERY: - return(EAI_FAIL); - case NO_DATA: - return(1); - default: - return(EAI_FAIL); - } - } - - endhostent(); - - c = hostent->h_name; - if ((flags & NI_NOFQDN) && (_res.options & RES_INIT) && _res.defdname[0] && - (c2 = strstr(c + 1, _res.defdname)) && (*(--c2) == '.')) { - *c2 = 0; - i = min(c2 - c, namelen); - strlcpy(name, c, i); - } else - strlcpy(name, c, namelen); - return 0; -} - -int -getnameinfo(const struct sockaddr *sa, size_t addrlen, char *host, - size_t hostlen, char *serv, size_t servlen, int flags) -{ - int rval; - int saved_errno; - - if (sa == NULL || addrlen != sa->sa_len) - return EAI_FAIL; - saved_errno = errno; +#if 0 +#ifndef HAVE_PORTABLE_PROTOTYPE +#include "cdecl_ext.h" +#endif - if (host && hostlen > 0) { - switch (sa->sa_family) { - case AF_INET6: - { - struct sockaddr_in6 *sin6 = (void *)sa; +#ifndef HAVE_ADDRINFO +#include "addrinfo.h" +#endif +#endif - if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { - if (flags & NI_NUMERICHOST) - goto inet6_noname; - strlcpy(host, "*", hostlen); - break; - } +#define SUCCESS 0 +#define ANY 0 +#define YES 1 +#define NO 0 - if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { - struct sockaddr_in sin; +static struct afd { + int a_af; + int a_addrlen; + int a_socklen; + int a_off; +} afdl [] = { +#ifdef INET6 + {PF_INET6, sizeof(struct in6_addr), sizeof(struct sockaddr_in6), + offsetof(struct sockaddr_in6, sin6_addr)}, +#endif + {PF_INET, sizeof(struct in_addr), sizeof(struct sockaddr_in), + offsetof(struct sockaddr_in, sin_addr)}, + {0, 0, 0}, +}; - memset(&sin, 0, sizeof(struct sockaddr_in)); - sin.sin_len = sizeof(struct sockaddr_in); - sin.sin_family = AF_INET; - sin.sin_port = sin6->sin6_port; - sin.sin_addr.s_addr = - ((u_int32_t *)&sin6->sin6_addr)[3]; - if (!(rval = getnameinfo((struct sockaddr *)&sin, - sizeof(struct sockaddr_in), host, hostlen, - serv, servlen, flags | NI_NAMEREQD))) - goto ret; - if (rval != EAI_NONAME) - goto ret; - goto inet6_noname; - } +struct sockinet { + u_char si_len; + u_char si_family; + u_short si_port; +}; - if (flags & NI_NUMERICHOST) - goto inet6_noname; - if ((rval = netdb_lookup_name(AF_INET6, - &sin6->sin6_addr, sizeof(struct in6_addr), - host, hostlen, flags)) < 0) - goto ret; +#define ENI_NOSOCKET 0 +#define ENI_NOSERVNAME 1 +#define ENI_NOHOSTNAME 2 +#define ENI_MEMORY 3 +#define ENI_SYSTEM 4 +#define ENI_FAMILY 5 +#define ENI_SALEN 6 - if (!rval) - break; - inet6_noname: - if (flags & NI_NAMEREQD) { - rval = EAI_NONAME; - goto ret; - } - if (!inet_ntop(AF_INET6, &sin6->sin6_addr, host, hostlen)) { - rval = EAI_NONAME; - goto ret; - } - break; - } - case AF_INET: - { - struct sockaddr_in *sin = (void *)sa; +int +getnameinfo(sa, salen, host, hostlen, serv, servlen, flags) + const struct sockaddr *sa; + size_t salen; + char *host; + size_t hostlen; + char *serv; + size_t servlen; + int flags; +{ + struct afd *afd; + struct servent *sp; + struct hostent *hp; + u_short port; + int family, i; + char *addr, *p; + u_int32_t v4a; + int h_error; + char numserv[512]; + char numaddr[512]; - if (flags & NI_NUMERICHOST) - goto inet_noname; + if (sa == NULL) + return ENI_NOSOCKET; - if (sin->sin_addr.s_addr == 0) { - strlcpy(host, "*", hostlen); - break; - } +#ifdef HAVE_SA_LEN /*XXX*/ + if (sa->sa_len != salen) + return ENI_SALEN; +#endif + + family = sa->sa_family; + for (i = 0; afdl[i].a_af; i++) + if (afdl[i].a_af == family) { + afd = &afdl[i]; + goto found; + } + return ENI_FAMILY; + + found: + if (salen != afd->a_socklen) + return ENI_SALEN; + + port = ((struct sockinet *)sa)->si_port; /* network byte order */ + addr = (char *)sa + afd->a_off; - if ((rval = netdb_lookup_name(AF_INET, - &sin->sin_addr, sizeof(struct in_addr), - host, hostlen, flags)) < 0) - goto ret; + if (serv == NULL || servlen == 0) { + /* + * do nothing in this case. + * in case you are wondering if "&&" is more correct than + * "||" here: RFC2553 says that serv == NULL OR servlen == 0 + * means that the caller does not want the result. + */ + } else { + if (flags & NI_NUMERICSERV) + sp = NULL; + else { + sp = getservbyport(port, + (flags & NI_DGRAM) ? "udp" : "tcp"); + } + if (sp) { + if (strlen(sp->s_name) > servlen) + return ENI_MEMORY; + strcpy(serv, sp->s_name); + } else { + snprintf(numserv, sizeof(numserv), "%d", ntohs(port)); + if (strlen(numserv) > servlen) + return ENI_MEMORY; + strcpy(serv, numserv); + } + } - if (!rval) - break; - inet_noname: - if (flags & NI_NAMEREQD) { - rval = EAI_NONAME; - goto ret; - } - if (!inet_ntop(AF_INET, &sin->sin_addr, host, hostlen)) { - rval = EAI_NONAME; - goto ret; - } + switch (sa->sa_family) { + case AF_INET: + v4a = (u_int32_t) + ntohl(((struct sockaddr_in *)sa)->sin_addr.s_addr); + if (IN_MULTICAST(v4a) || IN_EXPERIMENTAL(v4a)) + flags |= NI_NUMERICHOST; + v4a >>= IN_CLASSA_NSHIFT; + if (v4a == 0 || v4a == IN_LOOPBACKNET) + flags |= NI_NUMERICHOST; + break; +#ifdef INET6 + case AF_INET6: + { + struct sockaddr_in6 *sin6; + sin6 = (struct sockaddr_in6 *)sa; + switch (sin6->sin6_addr.s6_addr[0]) { + case 0x00: + if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) + ; + else if (IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr)) + ; + else + flags |= NI_NUMERICHOST; break; - } - case AF_LOCAL: - if (!(flags & NI_NUMERICHOST)) { - struct utsname utsname; - - if (!uname(&utsname)) { - strlcpy(host, utsname.nodename, hostlen); - break; - } - } - - if (flags & NI_NAMEREQD) { - rval = EAI_NONAME; - goto ret; + default: + if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) { + flags |= NI_NUMERICHOST; } - - strlcpy(host, "localhost", hostlen); + else if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) + flags |= NI_NUMERICHOST; break; - default: - rval = EAI_FAMILY; - goto ret; } + } + break; +#endif } + if (host == NULL || hostlen == 0) { + /* + * do nothing in this case. + * in case you are wondering if "&&" is more correct than + * "||" here: RFC2553 says that host == NULL OR hostlen == 0 + * means that the caller does not want the result. + */ + } else if (flags & NI_NUMERICHOST) { + /* NUMERICHOST and NAMEREQD conflicts with each other */ + if (flags & NI_NAMEREQD) + return ENI_NOHOSTNAME; + if (inet_ntop(afd->a_af, addr, numaddr, sizeof(numaddr)) + == NULL) + return ENI_SYSTEM; + if (strlen(numaddr) > hostlen) + return ENI_MEMORY; + strcpy(host, numaddr); +#if defined(INET6) && defined(NI_WITHSCOPEID) + if (afd->a_af == AF_INET6 && + (IN6_IS_ADDR_LINKLOCAL((struct in6_addr *)addr) || + IN6_IS_ADDR_MULTICAST((struct in6_addr *)addr)) && + ((struct sockaddr_in6 *)sa)->sin6_scope_id) { +#ifndef ALWAYS_WITHSCOPE + if (flags & NI_WITHSCOPEID) +#endif /* !ALWAYS_WITHSCOPE */ + { + char *ep = strchr(host, '\0'); + unsigned int ifindex = + ((struct sockaddr_in6 *)sa)->sin6_scope_id; - if (serv && servlen > 0) { - switch (sa->sa_family) { - case AF_INET: - { - struct sockaddr_in *sin = (void *)sa; - struct servent *s; - - if ((flags & NI_NUMERICSERV) == 0) { - s = getservbyport(sin->sin_port, - (flags & NI_DGRAM) ? "udp" : "tcp"); - if (s) { - strlcpy(serv, s->s_name, servlen); - break; - } - if (sin->sin_port == 0) { - strlcpy(serv, "*", servlen); - break; - } + *ep = SCOPE_DELIMITER; + if ((if_indextoname(ifindex, ep + 1)) == NULL) + /* XXX what should we do? */ + strncpy(ep + 1, "???", 3); } - snprintf(serv, servlen, "%d", ntohs(sin->sin_port)); - break; - } - case AF_INET6: - { - struct sockaddr_in6 *sin6 = (void *)sa; - struct servent *s; - - if ((flags & NI_NUMERICSERV) == 0) { + } +#endif /* INET6 */ + } else { +#ifdef USE_GETIPNODEBY + hp = getipnodebyaddr(addr, afd->a_addrlen, afd->a_af, &h_error); +#else + hp = gethostbyaddr(addr, afd->a_addrlen, afd->a_af); + h_error = h_errno; +#endif - s = getservbyport(sin6->sin6_port, - (flags & NI_DGRAM) ? "udp" : "tcp"); - if (s) { - strlcpy(serv, s->s_name, servlen); - break; - } - if (sin6->sin6_port == 0) { - strlcpy(serv, "*", servlen); - break; - } + if (hp) { + if (flags & NI_NOFQDN) { + p = strchr(hp->h_name, '.'); + if (p) *p = '\0'; } - snprintf(serv, servlen, "%d", ntohs(sin6->sin6_port)); - break; - } - case AF_LOCAL: - { - struct sockaddr_un *sun = (void *)sa; - - strlcpy(serv, sun->sun_path, servlen); - break; - } + if (strlen(hp->h_name) > hostlen) { +#ifdef USE_GETIPNODEBY + freehostent(hp); +#endif + return ENI_MEMORY; + } + strcpy(host, hp->h_name); +#ifdef USE_GETIPNODEBY + freehostent(hp); +#endif + } else { + if (flags & NI_NAMEREQD) + return ENI_NOHOSTNAME; + if (inet_ntop(afd->a_af, addr, numaddr, sizeof(numaddr)) + == NULL) + return ENI_NOHOSTNAME; + if (strlen(numaddr) > hostlen) + return ENI_MEMORY; + strcpy(host, numaddr); } } - rval = 0; - -ret: - if (rval == 1) - rval = EAI_FAIL; - errno = saved_errno; - return (rval); + return SUCCESS; } -- cgit v1.2.3-55-g6feb