-/* $OpenBSD: getnameinfo.c,v 1.12 2000/03/13 02:22:12 itojun Exp $ */
+/* $OpenBSD: getnameinfo.c,v 1.13 2000/04/26 14:46:47 itojun Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
* - 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
*/
+#ifndef INET6
#define INET6
+#endif
#include <sys/types.h>
#include <sys/socket.h>
};
#ifdef INET6
-static char *ip6_sa2str __P((struct sockaddr_in6 *, char *, int));
+static int ip6_parsenumeric __P((const struct sockaddr *, char *, char *,
+ int, int));
+static int ip6_sa2str __P((struct sockaddr_in6 *, char *, size_t, int));
#endif
#define ENI_NOSOCKET 0
/* 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;
- numaddrlen = strlen(numaddr);
- if (numaddrlen + 1 > hostlen) /* don't forget terminator */
- 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 scopebuf[MAXHOSTNAMELEN], *s;
- int scopelen;
-
- if ((s = ip6_sa2str((struct sockaddr_in6 *)sa,
- scopebuf, 0)) == NULL)
- /* XXX what should we do? */
- strcpy(scopebuf, "0");
- scopelen = strlen(scopebuf);
- if (scopelen + 1 + numaddrlen + 1 > hostlen)
- return ENI_MEMORY;
+ switch(afd->a_af) {
+#ifdef INET6
+ case AF_INET6:
+ {
+ int error;
-#if 0
- /*
- * construct <scopeid><delim><numeric-addr>
- */
- /*
- * Shift the host string to allocate
- * space for the scope ID part.
- */
- memmove(host + scopelen + 1, host,
- numaddrlen);
- /* copy the scope ID and the delimiter */
- memcpy(host, scopebuf, scopelen);
- host[scopelen] = SCOPE_DELIMITER;
- host[scopelen + 1 + numaddrlen] = '\0';
-#else
- /*
- * construct <numeric-addr><delim><scopeid>
- */
- memcpy(host + numaddrlen + 1, scopebuf,
- scopelen);
- host[numaddrlen] = SCOPE_DELIMITER;
- host[numaddrlen + 1 + scopelen] = '\0';
+ 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 = gethostbyaddr(addr, afd->a_addrlen, afd->a_af);
h_error = h_errno;
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';
} 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;
+ char *addr, *host;
+ int flags, hostlen;
+{
+ 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 (((struct sockaddr_in6 *)sa)->sin6_scope_id) {
+ if (flags & NI_WITHSCOPEID)
+ {
+ char scopebuf[MAXHOSTNAMELEN];
+ int scopelen;
+
+ /* ip6_sa2str never fails */
+ scopelen = ip6_sa2str((struct sockaddr_in6 *)sa,
+ scopebuf, sizeof(scopebuf),
+ 0);
+ 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 char *
-ip6_sa2str(sa6, buf, flags)
+static int
+ip6_sa2str(sa6, buf, bufsiz, flags)
struct sockaddr_in6 *sa6;
char *buf;
+ size_t bufsiz;
int flags;
{
unsigned int ifindex = (unsigned int)sa6->sin6_scope_id;
#ifdef notyet
if (flags & NI_NUMERICSCOPE) {
- sprintf(buf, "%d", sa6->sin6_scope_id);
- return(buf);
+ return(snprintf(buf, bufsiz, "%d", sa6->sin6_scope_id));
}
#endif
- if (IN6_IS_ADDR_LINKLOCAL(a6) || IN6_IS_ADDR_MC_LINKLOCAL(a6))
- return(if_indextoname(ifindex, buf));
-
- if (IN6_IS_ADDR_SITELOCAL(a6) || IN6_IS_ADDR_MC_SITELOCAL(a6))
- return(NULL); /* XXX */
- if (IN6_IS_ADDR_MC_ORGLOCAL(a6))
- return(NULL); /* XXX */
+ /* 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));
+ }
+ }
- return(NULL); /* XXX */
+ /* last resort */
+ return(snprintf(buf, bufsiz, "%u", sa6->sin6_scope_id));
}
-#endif
+#endif /* INET6 */