summaryrefslogtreecommitdiffstats
path: root/lib/libc/net/gethostnamadr.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libc/net/gethostnamadr.c')
-rw-r--r--lib/libc/net/gethostnamadr.c37
1 files changed, 36 insertions, 1 deletions
diff --git a/lib/libc/net/gethostnamadr.c b/lib/libc/net/gethostnamadr.c
index 78b3a7a..8aae192 100644
--- a/lib/libc/net/gethostnamadr.c
+++ b/lib/libc/net/gethostnamadr.c
@@ -252,6 +252,9 @@ int
gethostbyaddr_r(const char *addr, int len, int af, struct hostent *he,
struct hostent_data *hed)
{
+ const u_char *uaddr = (const u_char *)addr;
+ const struct in6_addr *addr6;
+ socklen_t size;
int rval;
static const ns_dtab dtab[] = {
@@ -261,8 +264,40 @@ gethostbyaddr_r(const char *addr, int len, int af, struct hostent *he,
{ 0 }
};
+ if (af == AF_INET6 && len == IN6ADDRSZ) {
+ addr6 = (const struct in6_addr *)(const void *)uaddr;
+ if (IN6_IS_ADDR_LINKLOCAL(addr6)) {
+ h_errno = HOST_NOT_FOUND;
+ return -1;
+ }
+ if (IN6_IS_ADDR_V4MAPPED(addr6) ||
+ IN6_IS_ADDR_V4COMPAT(addr6)) {
+ /* Unmap. */
+ uaddr += IN6ADDRSZ - INADDRSZ;
+ af = AF_INET;
+ len = INADDRSZ;
+ }
+ }
+ switch (af) {
+ case AF_INET:
+ size = INADDRSZ;
+ break;
+ case AF_INET6:
+ size = IN6ADDRSZ;
+ break;
+ default:
+ errno = EAFNOSUPPORT;
+ h_errno = NETDB_INTERNAL;
+ return -1;
+ }
+ if (size != len) {
+ errno = EINVAL;
+ h_errno = NETDB_INTERNAL;
+ return -1;
+ }
+
rval = _nsdispatch(NULL, dtab, NSDB_HOSTS, "gethostbyaddr",
- default_src, addr, len, af, he, hed);
+ default_src, uaddr, len, af, he, hed);
return (rval == NS_SUCCESS) ? 0 : -1;
}
OpenPOWER on IntegriCloud