summaryrefslogtreecommitdiffstats
path: root/lib/libc/net
diff options
context:
space:
mode:
authoritojun <itojun@FreeBSD.org>2000-07-05 05:09:17 +0000
committeritojun <itojun@FreeBSD.org>2000-07-05 05:09:17 +0000
commit8d388020866f9b77f7906b4db0957cc970038e08 (patch)
tree4a2ae9bfaa97dd8aeb116cefda0c2100fcaab7ab /lib/libc/net
parent50e0123ddd812133b34fdd9ab98657d517842c8b (diff)
downloadFreeBSD-src-8d388020866f9b77f7906b4db0957cc970038e08.zip
FreeBSD-src-8d388020866f9b77f7906b4db0957cc970038e08.tar.gz
sync with latest kame.
- permit numeric scopeid, be more careful about buffer size TODO: 2nd arg type should be socklen_t for RFC2553 conformance, but due to include file dependency it is not a easy thing to do (netdb.h does not have socklen_t)
Diffstat (limited to 'lib/libc/net')
-rw-r--r--lib/libc/net/getnameinfo.c278
1 files changed, 208 insertions, 70 deletions
diff --git a/lib/libc/net/getnameinfo.c b/lib/libc/net/getnameinfo.c
index 5edcffb..2dbd81f 100644
--- a/lib/libc/net/getnameinfo.c
+++ b/lib/libc/net/getnameinfo.c
@@ -1,3 +1,6 @@
+/* $FreeBSD$ */
+/* $KAME: getnameinfo.c,v 1.43 2000/06/12 04:27:03 itojun Exp $ */
+
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
* All rights reserved.
@@ -25,8 +28,6 @@
* 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.
- *
- * $FreeBSD$
*/
/*
@@ -34,6 +35,13 @@
* - 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).
+ * - What is "local" in NI_FQDN?
+ * - NI_NAMEREQD and NI_NUMERICHOST conflict with each other.
+ * - (KAME extension) NI_WITHSCOPEID when called with global address,
+ * and sin6_scope_id filled
*/
#include <sys/types.h>
@@ -46,11 +54,12 @@
#include <resolv.h>
#include <string.h>
#include <stddef.h>
+#include <errno.h>
-#define SUCCESS 0
-#define ANY 0
-#define YES 1
-#define NO 0
+#define SUCCESS 0
+#define ANY 0
+#define YES 1
+#define NO 0
static struct afd {
int a_af;
@@ -73,13 +82,19 @@ struct sockinet {
u_short si_port;
};
-#define ENI_NOSOCKET 0
-#define ENI_NOSERVHOST 1
-#define ENI_NOHOSTNAME 2
-#define ENI_MEMORY 3
-#define ENI_SYSTEM 4
-#define ENI_FAMILY 5
-#define ENI_SALEN 6
+#ifdef INET6
+static int ip6_parsenumeric __P((const struct sockaddr *, const char *, char *,
+ size_t, int));
+static int ip6_sa2str __P((const struct sockaddr_in6 *, char *, size_t, int));
+#endif
+
+#define ENI_NOSOCKET EAI_FAIL /*XXX*/
+#define ENI_NOSERVNAME EAI_NONAME
+#define ENI_NOHOSTNAME EAI_NONAME
+#define ENI_MEMORY EAI_MEMORY
+#define ENI_SYSTEM EAI_SYSTEM
+#define ENI_FAMILY EAI_FAMILY
+#define ENI_SALEN EAI_FAMILY
int
getnameinfo(sa, salen, host, hostlen, serv, servlen, flags)
@@ -96,19 +111,18 @@ getnameinfo(sa, salen, host, hostlen, serv, servlen, flags)
struct hostent *hp;
u_short port;
int family, i;
- char *addr, *p;
- u_long v4a;
+ const char *addr;
+ u_int32_t v4a;
int h_error;
char numserv[512];
char numaddr[512];
- int noserv = 0;
if (sa == NULL)
return ENI_NOSOCKET;
if (sa->sa_len != salen)
return ENI_SALEN;
-
+
family = sa->sa_family;
for (i = 0; afdl[i].a_af; i++)
if (afdl[i].a_af == family) {
@@ -116,16 +130,22 @@ getnameinfo(sa, salen, host, hostlen, serv, servlen, flags)
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;
+
+ /* network byte order */
+ port = ((const struct sockinet *)sa)->si_port;
+ addr = (const char *)sa + afd->a_off;
if (serv == NULL || servlen == 0) {
- noserv = 1;
+ /*
+ * 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;
@@ -147,73 +167,92 @@ getnameinfo(sa, salen, host, hostlen, serv, servlen, flags)
switch (sa->sa_family) {
case AF_INET:
- v4a = ntohl(((struct sockaddr_in *)sa)->sin_addr.s_addr);
+ v4a = (u_int32_t)
+ ntohl(((const 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)
- flags |= NI_NUMERICHOST;
+ flags |= NI_NUMERICHOST;
break;
#ifdef INET6
case AF_INET6:
{
- struct sockaddr_in6 *sin6;
- sin6 = (struct sockaddr_in6 *)sa;
- if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) ||
- IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))
- flags |= NI_NUMERICHOST;
+ const struct sockaddr_in6 *sin6;
+ sin6 = (const 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;
+ default:
+ if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
+ flags |= NI_NUMERICHOST;
+ }
+ else if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))
+ flags |= NI_NUMERICHOST;
+ break;
+ }
}
break;
#endif
}
if (host == NULL || hostlen == 0) {
- if (noserv == 1)
- return ENI_NOSERVHOST;
+ /*
+ * 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) {
+ int numaddrlen;
+
/* 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);
+
+ switch(afd->a_af) {
#ifdef INET6
- 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) {
- if (flags & NI_WITHSCOPEID) {
- char *ep = strchr(host, '\0');
- unsigned int ifindex =
- ((struct sockaddr_in6 *)sa)->sin6_scope_id;
- char ifname[IF_NAMESIZE * 2 /* for safety */];
- int scopelen, numaddrlen;
-
- if ((if_indextoname(ifindex, ifname)) == NULL)
- return ENI_SYSTEM;
- scopelen = strlen(ifname);
- numaddrlen = strlen(host);
- if (numaddrlen + 1 /* SCOPE_DELIMITER */
- + scopelen > hostlen)
- return ENI_MEMORY;
- /*
- * Construct <numeric-addr><delim><scopeid>
- */
- memcpy(host + numaddrlen + 1, ifname, scopelen);
- host[numaddrlen] = SCOPE_DELIMITER;
- host[numaddrlen + 1 + scopelen] = '\0';
- }
+ case AF_INET6:
+ {
+ int error;
+
+ if ((error = ip6_parsenumeric(sa, addr, host,
+ hostlen, flags)) != 0)
+ return(error);
+ break;
+ }
+#endif
+ default:
+ if (inet_ntop(afd->a_af, addr, numaddr, sizeof(numaddr))
+ == NULL)
+ return ENI_SYSTEM;
+ numaddrlen = strlen(numaddr);
+ if (numaddrlen + 1 > hostlen) /* don't forget terminator */
+ return ENI_MEMORY;
+ strcpy(host, numaddr);
+ break;
}
-#endif /* INET6 */
} else {
hp = getipnodebyaddr(addr, afd->a_addrlen, afd->a_af, &h_error);
+
if (hp) {
+#if 0
+ /*
+ * commented out, since "for local host" is not
+ * implemented here - see RFC2553 p30
+ */
if (flags & NI_NOFQDN) {
+ char *p;
p = strchr(hp->h_name, '.');
- if (p) *p = '\0';
+ if (p)
+ *p = '\0';
}
+#endif
if (strlen(hp->h_name) > hostlen) {
freehostent(hp);
return ENI_MEMORY;
@@ -223,13 +262,112 @@ getnameinfo(sa, salen, host, hostlen, serv, servlen, flags)
} 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);
+ switch(afd->a_af) {
+#ifdef INET6
+ case AF_INET6:
+ {
+ int error;
+
+ if ((error = ip6_parsenumeric(sa, addr, host,
+ hostlen,
+ flags)) != 0)
+ return(error);
+ break;
+ }
+#endif
+ default:
+ if (inet_ntop(afd->a_af, addr, host,
+ hostlen) == NULL)
+ return ENI_SYSTEM;
+ break;
+ }
}
}
return SUCCESS;
}
+
+#ifdef INET6
+static int
+ip6_parsenumeric(sa, addr, host, hostlen, flags)
+ const struct sockaddr *sa;
+ const char *addr;
+ char *host;
+ size_t hostlen;
+ int flags;
+{
+ int numaddrlen;
+ char numaddr[512];
+
+ if (inet_ntop(AF_INET6, addr, numaddr, sizeof(numaddr))
+ == NULL)
+ return ENI_SYSTEM;
+
+ numaddrlen = strlen(numaddr);
+ if (numaddrlen + 1 > hostlen) /* don't forget terminator */
+ return ENI_MEMORY;
+ strcpy(host, numaddr);
+
+#ifdef NI_WITHSCOPEID
+ if (
+#ifdef DONT_OPAQUE_SCOPEID
+ (IN6_IS_ADDR_LINKLOCAL((struct in6_addr *)addr) ||
+ IN6_IS_ADDR_MULTICAST((struct in6_addr *)addr)) &&
+#endif
+ ((const struct sockaddr_in6 *)sa)->sin6_scope_id) {
+#ifndef ALWAYS_WITHSCOPE
+ if (flags & NI_WITHSCOPEID)
+#endif /* !ALWAYS_WITHSCOPE */
+ {
+ char scopebuf[MAXHOSTNAMELEN];
+ int scopelen;
+
+ /* ip6_sa2str never fails */
+ scopelen = ip6_sa2str((const struct sockaddr_in6 *)sa,
+ scopebuf, sizeof(scopebuf),
+ flags);
+ if (scopelen + 1 + numaddrlen + 1 > hostlen)
+ return ENI_MEMORY;
+ /*
+ * construct <numeric-addr><delim><scopeid>
+ */
+ memcpy(host + numaddrlen + 1, scopebuf,
+ scopelen);
+ host[numaddrlen] = SCOPE_DELIMITER;
+ host[numaddrlen + 1 + scopelen] = '\0';
+ }
+ }
+#endif /* NI_WITHSCOPEID */
+
+ return 0;
+}
+
+/* ARGSUSED */
+static int
+ip6_sa2str(sa6, buf, bufsiz, flags)
+ const struct sockaddr_in6 *sa6;
+ char *buf;
+ size_t bufsiz;
+ int flags;
+{
+ unsigned int ifindex = (unsigned int)sa6->sin6_scope_id;
+ const struct in6_addr *a6 = &sa6->sin6_addr;
+
+#ifdef NI_NUMERICSCOPE
+ if (flags & NI_NUMERICSCOPE) {
+ return(snprintf(buf, bufsiz, "%d", sa6->sin6_scope_id));
+ }
+#endif
+
+ /* if_indextoname() does not take buffer size. not a good api... */
+ if ((IN6_IS_ADDR_LINKLOCAL(a6) || IN6_IS_ADDR_MC_LINKLOCAL(a6)) &&
+ bufsiz >= IF_NAMESIZE) {
+ char *p = if_indextoname(ifindex, buf);
+ if (p) {
+ return(strlen(p));
+ }
+ }
+
+ /* last resort */
+ return(snprintf(buf, bufsiz, "%u", sa6->sin6_scope_id));
+}
+#endif /* INET6 */
OpenPOWER on IntegriCloud