Merge "Disable ASAN for more of our libraries."
diff --git a/libc/dns/gethnamaddr.c b/libc/dns/gethnamaddr.c
index 736858f..63a6a60 100644
--- a/libc/dns/gethnamaddr.c
+++ b/libc/dns/gethnamaddr.c
@@ -1,4 +1,4 @@
-/*	$NetBSD: gethnamaddr.c,v 1.70 2006/03/22 00:03:51 christos Exp $	*/
+/*	$NetBSD: gethnamaddr.c,v 1.91 2014/06/19 15:08:18 christos Exp $	*/
 
 /*
  * ++Copyright++ 1985, 1988, 1993
@@ -88,6 +88,31 @@
 #include <stdlib.h>
 #include <string.h>
 
+#include "hostent.h"
+
+#define maybe_ok(res, nm, ok) (((res)->options & RES_NOCHECKNAME) != 0U || \
+                               (ok)(nm) != 0)
+#define maybe_hnok(res, hn) maybe_ok((res), (hn), res_hnok)
+#define maybe_dnok(res, dn) maybe_ok((res), (dn), res_dnok)
+
+#define addalias(d, s, arr, siz) do {			\
+	if (d >= &arr[siz]) {				\
+		char **xptr = realloc(arr, (siz + 10) * sizeof(*arr)); \
+		if (xptr == NULL)			\
+			goto nospc;			\
+		d = xptr + (d - arr);			\
+		arr = xptr;				\
+		siz += 10;				\
+	}						\
+	*d++ = s;					\
+} while (/*CONSTCOND*/0)
+
+#define setup(arr, siz) do {				\
+	arr = malloc((siz = 10) * sizeof(*arr)); 	\
+	if (arr == NULL)				\
+		goto nospc;				\
+} while (/*CONSTCOND*/0)
+
 // This should be synchronized to ResponseCode.h
 static const int DnsProxyQueryResult = 222;
 
@@ -107,18 +132,15 @@
 } align;
 
 #ifdef DEBUG
-static void dprintf(const char *, res_state, ...)
+static void debugprintf(const char *, res_state, ...)
 	__attribute__((__format__(__printf__, 1, 3)));
 #endif
 static struct hostent *getanswer(const querybuf *, int, const char *, int,
-    res_state);
+    res_state, struct hostent *, char *, size_t, int *);
 static void map_v4v6_address(const char *, char *);
 static void map_v4v6_hostent(struct hostent *, char **, char *);
 static void addrsort(char **, int, res_state);
 
-static void _sethtent(int);
-static void _endhtent(void);
-static struct hostent *_gethtent(void);
 void ht_sethostent(int);
 void ht_endhostent(void);
 struct hostent *ht_gethostbyname(char *);
@@ -126,13 +148,13 @@
 void dns_service(void);
 #undef dn_skipname
 int dn_skipname(const u_char *, const u_char *);
-static int _gethtbyaddr(void *, void *, va_list);
-static int _gethtbyname(void *, void *, va_list);
-static struct hostent *_gethtbyname2(const char *, int);
 static int _dns_gethtbyaddr(void *, void *, va_list);
 static int _dns_gethtbyname(void *, void *, va_list);
 
-static struct hostent *gethostbyname_internal(const char *, int, res_state, unsigned, unsigned);
+static struct hostent *gethostbyname_internal(const char *, int, res_state,
+    struct hostent *, char *, size_t, int *, unsigned, unsigned);
+static struct hostent* android_gethostbyaddrfornet_proxy_internal(const void*, socklen_t,
+    int, struct hostent *, char *, size_t, int *, unsigned, unsigned);
 
 static const ns_src default_dns_files[] = {
 	{ NSSRC_FILES, 	NS_SUCCESS },
@@ -143,9 +165,9 @@
 
 #ifdef DEBUG
 static void
-dprintf(const char *msg, res_state res, ...)
+debugprintf(const char *msg, res_state res, ...)
 {
-	assert(msg != NULL);
+	_DIAGASSERT(msg != NULL);
 
 	if (res->options & RES_DEBUG) {
 		int save = errno;
@@ -159,48 +181,47 @@
 	}
 }
 #else
-# define dprintf(msg, res, num) ((void)0) /*nada*/
+# define debugprintf(msg, res, num) /*nada*/
 #endif
 
 #define BOUNDED_INCR(x) \
 	do { \
 		cp += (x); \
-		if (cp > eom) { \
-			h_errno = NO_RECOVERY; \
-			return NULL; \
-		} \
+		if (cp > eom) \
+			goto no_recovery; \
 	} while (/*CONSTCOND*/0)
 
 #define BOUNDS_CHECK(ptr, count) \
 	do { \
-		if ((ptr) + (count) > eom) { \
-			h_errno = NO_RECOVERY; \
-			return NULL; \
-		} \
+		if ((ptr) + (count) > eom) \
+			goto no_recovery; \
 	} while (/*CONSTCOND*/0)
 
 static struct hostent *
 getanswer(const querybuf *answer, int anslen, const char *qname, int qtype,
-    res_state res)
+    res_state res, struct hostent *hent, char *buf, size_t buflen, int *he)
 {
 	const HEADER *hp;
 	const u_char *cp;
 	int n;
+	size_t qlen;
 	const u_char *eom, *erdata;
 	char *bp, **ap, **hap, *ep;
 	int type, class, ancount, qdcount;
 	int haveanswer, had_error;
 	int toobig = 0;
 	char tbuf[MAXDNAME];
+	char **aliases;
+	size_t maxaliases;
+	char *addr_ptrs[MAXADDRS];
 	const char *tname;
 	int (*name_ok)(const char *);
-	res_static  rs = __res_get_static();
 
-	assert(answer != NULL);
-	assert(qname != NULL);
+	_DIAGASSERT(answer != NULL);
+	_DIAGASSERT(qname != NULL);
 
 	tname = qname;
-	rs->host.h_name = NULL;
+	hent->h_name = NULL;
 	eom = answer->buf + anslen;
 	switch (qtype) {
 	case T_A:
@@ -211,54 +232,51 @@
 		name_ok = res_dnok;
 		break;
 	default:
+	  *he = NO_RECOVERY;
 		return NULL;	/* XXX should be abort(); */
 	}
+
+	setup(aliases, maxaliases);
 	/*
 	 * find first satisfactory answer
 	 */
 	hp = &answer->hdr;
 	ancount = ntohs(hp->ancount);
 	qdcount = ntohs(hp->qdcount);
-	bp = rs->hostbuf;
-	ep = rs->hostbuf + sizeof rs->hostbuf;
+	bp = buf;
+	ep = buf + buflen;
 	cp = answer->buf;
 	BOUNDED_INCR(HFIXEDSZ);
-	if (qdcount != 1) {
-		h_errno = NO_RECOVERY;
-		return NULL;
-	}
-	n = dn_expand(answer->buf, eom, cp, bp, ep - bp);
-	if ((n < 0) || !(*name_ok)(bp)) {
-		h_errno = NO_RECOVERY;
-		return NULL;
-	}
+	if (qdcount != 1)
+		goto no_recovery;
+
+	n = dn_expand(answer->buf, eom, cp, bp, (int)(ep - bp));
+	if ((n < 0) || !maybe_ok(res, bp, name_ok))
+		goto no_recovery;
+
 	BOUNDED_INCR(n + QFIXEDSZ);
 	if (qtype == T_A || qtype == T_AAAA) {
 		/* res_send() has already verified that the query name is the
 		 * same as the one we sent; this just gets the expanded name
 		 * (i.e., with the succeeding search-domain tacked on).
 		 */
-		n = strlen(bp) + 1;		/* for the \0 */
-		if (n >= MAXHOSTNAMELEN) {
-			h_errno = NO_RECOVERY;
-			return NULL;
-		}
-		rs->host.h_name = bp;
+		n = (int)strlen(bp) + 1;		/* for the \0 */
+		if (n >= MAXHOSTNAMELEN)
+			goto no_recovery;
+		hent->h_name = bp;
 		bp += n;
 		/* The qname can be abbreviated, but h_name is now absolute. */
-		qname = rs->host.h_name;
+		qname = hent->h_name;
 	}
-	ap = rs->host_aliases;
+	hent->h_aliases = ap = aliases;
+	hent->h_addr_list = hap = addr_ptrs;
 	*ap = NULL;
-	rs->host.h_aliases = rs->host_aliases;
-	hap = rs->h_addr_ptrs;
 	*hap = NULL;
-	rs->host.h_addr_list = rs->h_addr_ptrs;
 	haveanswer = 0;
 	had_error = 0;
 	while (ancount-- > 0 && cp < eom && !had_error) {
-		n = dn_expand(answer->buf, eom, cp, bp, ep - bp);
-		if ((n < 0) || !(*name_ok)(bp)) {
+		n = dn_expand(answer->buf, eom, cp, bp, (int)(ep - bp));
+		if ((n < 0) || !maybe_ok(res, bp, name_ok)) {
 			had_error++;
 			continue;
 		}
@@ -278,50 +296,46 @@
 			continue;		/* XXX - had_error++ ? */
 		}
 		if ((qtype == T_A || qtype == T_AAAA) && type == T_CNAME) {
-			if (ap >= &rs->host_aliases[MAXALIASES-1])
-				continue;
-			n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf);
-			if ((n < 0) || !(*name_ok)(tbuf)) {
+			n = dn_expand(answer->buf, eom, cp, tbuf,
+			    (int)sizeof tbuf);
+			if ((n < 0) || !maybe_ok(res, tbuf, name_ok)) {
 				had_error++;
 				continue;
 			}
 			cp += n;
-			if (cp != erdata) {
-				h_errno = NO_RECOVERY;
-				return NULL;
-			}
+			if (cp != erdata)
+				goto no_recovery;
 			/* Store alias. */
-			*ap++ = bp;
-			n = strlen(bp) + 1;	/* for the \0 */
+			addalias(ap, bp, aliases, maxaliases);
+			n = (int)strlen(bp) + 1;	/* for the \0 */
 			if (n >= MAXHOSTNAMELEN) {
 				had_error++;
 				continue;
 			}
 			bp += n;
 			/* Get canonical name. */
-			n = strlen(tbuf) + 1;	/* for the \0 */
+			n = (int)strlen(tbuf) + 1;	/* for the \0 */
 			if (n > ep - bp || n >= MAXHOSTNAMELEN) {
 				had_error++;
 				continue;
 			}
 			strlcpy(bp, tbuf, (size_t)(ep - bp));
-			rs->host.h_name = bp;
+			hent->h_name = bp;
 			bp += n;
 			continue;
 		}
 		if (qtype == T_PTR && type == T_CNAME) {
-			n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf);
-			if (n < 0 || !res_dnok(tbuf)) {
+			n = dn_expand(answer->buf, eom, cp, tbuf,
+			    (int)sizeof tbuf);
+			if (n < 0 || !maybe_dnok(res, tbuf)) {
 				had_error++;
 				continue;
 			}
 			cp += n;
-			if (cp != erdata) {
-				h_errno = NO_RECOVERY;
-				return NULL;
-			}
+			if (cp != erdata)
+				goto no_recovery;
 			/* Get canonical name. */
-			n = strlen(tbuf) + 1;	/* for the \0 */
+			n = (int)strlen(tbuf) + 1;	/* for the \0 */
 			if (n > ep - bp || n >= MAXHOSTNAMELEN) {
 				had_error++;
 				continue;
@@ -348,25 +362,21 @@
 				cp += n;
 				continue;	/* XXX - had_error++ ? */
 			}
-			n = dn_expand(answer->buf, eom, cp, bp, ep - bp);
-			if ((n < 0) || !res_hnok(bp)) {
+			n = dn_expand(answer->buf, eom, cp, bp, (int)(ep - bp));
+			if ((n < 0) || !maybe_hnok(res, bp)) {
 				had_error++;
 				break;
 			}
 #if MULTI_PTRS_ARE_ALIASES
 			cp += n;
-			if (cp != erdata) {
-				h_errno = NO_RECOVERY;
-				return NULL;
-			}
+			if (cp != erdata)
+				goto no_recovery;
 			if (!haveanswer)
-				rs->host.h_name = bp;
-			else if (ap < &rs->host_aliases[MAXALIASES-1])
-				*ap++ = bp;
+				hent->h_name = bp;
 			else
-				n = -1;
+				addalias(ap, bp, aliases, maxaliases);
 			if (n != -1) {
-				n = strlen(bp) + 1;	/* for the \0 */
+				n = (int)strlen(bp) + 1;	/* for the \0 */
 				if (n >= MAXHOSTNAMELEN) {
 					had_error++;
 					break;
@@ -375,7 +385,7 @@
 			}
 			break;
 #else
-			rs->host.h_name = bp;
+			hent->h_name = bp;
 			if (res->options & RES_USE_INET6) {
 				n = strlen(bp) + 1;	/* for the \0 */
 				if (n >= MAXHOSTNAMELEN) {
@@ -383,26 +393,25 @@
 					break;
 				}
 				bp += n;
-				map_v4v6_hostent(&rs->host, &bp, ep);
+				map_v4v6_hostent(hent, &bp, ep);
 			}
-			h_errno = NETDB_SUCCESS;
-			return &rs->host;
+			goto success;
 #endif
 		case T_A:
 		case T_AAAA:
-			if (strcasecmp(rs->host.h_name, bp) != 0) {
+			if (strcasecmp(hent->h_name, bp) != 0) {
 				syslog(LOG_NOTICE|LOG_AUTH,
-				       AskedForGot, rs->host.h_name, bp);
+				       AskedForGot, hent->h_name, bp);
 				cp += n;
 				continue;	/* XXX - had_error++ ? */
 			}
-			if (n != rs->host.h_length) {
+			if (n != hent->h_length) {
 				cp += n;
 				continue;
 			}
 			if (type == T_AAAA) {
 				struct in6_addr in6;
-				memcpy(&in6, cp, IN6ADDRSZ);
+				memcpy(&in6, cp, NS_IN6ADDRSZ);
 				if (IN6_IS_ADDR_V4MAPPED(&in6)) {
 					cp += n;
 					continue;
@@ -411,33 +420,32 @@
 			if (!haveanswer) {
 				int nn;
 
-				rs->host.h_name = bp;
-				nn = strlen(bp) + 1;	/* for the \0 */
+				hent->h_name = bp;
+				nn = (int)strlen(bp) + 1;	/* for the \0 */
 				bp += nn;
 			}
 
 			bp += sizeof(align) -
 			    (size_t)((u_long)bp % sizeof(align));
 
-			if (bp + n >= &rs->hostbuf[sizeof rs->hostbuf]) {
-				dprintf("size (%d) too big\n", res, n);
+			if (bp + n >= ep) {
+				debugprintf("size (%d) too big\n", res, n);
 				had_error++;
 				continue;
 			}
-			if (hap >= &rs->h_addr_ptrs[MAXADDRS-1]) {
-				if (!toobig++)
-					dprintf("Too many addresses (%d)\n",
+			if (hap >= &addr_ptrs[MAXADDRS - 1]) {
+				if (!toobig++) {
+					debugprintf("Too many addresses (%d)\n",
 						res, MAXADDRS);
+				}
 				cp += n;
 				continue;
 			}
 			(void)memcpy(*hap++ = bp, cp, (size_t)n);
 			bp += n;
 			cp += n;
-			if (cp != erdata) {
-				h_errno = NO_RECOVERY;
-				return NULL;
-			}
+			if (cp != erdata)
+				goto no_recovery;
 			break;
 		default:
 			abort();
@@ -454,83 +462,103 @@
 		 * address in that case, not some random one
 		 */
 		if (res->nsort && haveanswer > 1 && qtype == T_A)
-			addrsort(rs->h_addr_ptrs, haveanswer, res);
-		if (!rs->host.h_name) {
-			n = strlen(qname) + 1;	/* for the \0 */
+			addrsort(addr_ptrs, haveanswer, res);
+		if (!hent->h_name) {
+			n = (int)strlen(qname) + 1;	/* for the \0 */
 			if (n > ep - bp || n >= MAXHOSTNAMELEN)
 				goto no_recovery;
 			strlcpy(bp, qname, (size_t)(ep - bp));
-			rs->host.h_name = bp;
+			hent->h_name = bp;
 			bp += n;
 		}
 		if (res->options & RES_USE_INET6)
-			map_v4v6_hostent(&rs->host, &bp, ep);
-		h_errno = NETDB_SUCCESS;
-		return &rs->host;
+			map_v4v6_hostent(hent, &bp, ep);
+	  goto success;
 	}
- no_recovery:
-	h_errno = NO_RECOVERY;
+no_recovery:
+	free(aliases);
+	*he = NO_RECOVERY;
+	return NULL;
+success:
+	bp = (char *)ALIGN(bp);
+	n = (int)(ap - aliases);
+	qlen = (n + 1) * sizeof(*hent->h_aliases);
+	if ((size_t)(ep - bp) < qlen)
+		goto nospc;
+	hent->h_aliases = (void *)bp;
+	memcpy(bp, aliases, qlen);
+	free(aliases);
+	aliases = NULL;
+
+	bp += qlen;
+	n = (int)(hap - addr_ptrs);
+	qlen = (n + 1) * sizeof(*hent->h_addr_list);
+	if ((size_t)(ep - bp) < qlen)
+		goto nospc;
+	hent->h_addr_list = (void *)bp;
+	memcpy(bp, addr_ptrs, qlen);
+	*he = NETDB_SUCCESS;
+	return hent;
+nospc:
+	free(aliases);
+	errno = ENOSPC;
+	*he = NETDB_INTERNAL;
 	return NULL;
 }
 
+/* The prototype of gethostbyname_r is from glibc, not that in netbsd. */
 int
 gethostbyname_r(const char *name, struct hostent *hp, char *buf, size_t buflen,
-    struct hostent**result, int *errorp)
+    struct hostent **result, int *errorp)
 {
-        struct hostent *res;
-
-        res = gethostbyname(name);
-        *errorp = h_errno;
-        if (res == NULL) {
-                *result = NULL;
-                return -1;
-        }
-        memcpy(hp, res, sizeof *hp);
-        *result = hp;
-        return 0;
-}
-
-struct hostent *
-gethostbyname(const char *name)
-{
-	struct hostent *hp;
 	res_state res = __res_get_state();
 
-	if (res == NULL)
-		return NULL;
+	if (res == NULL) {
+	  *result = NULL;
+		*errorp = NETDB_INTERNAL;
+		return -1;
+	}
 
-	assert(name != NULL);
+	_DIAGASSERT(name != NULL);
 
-	/* try IPv6 first - if that fails do IPv4 */
 	if (res->options & RES_USE_INET6) {
-		hp = gethostbyname_internal(name, AF_INET6, res, NETID_UNSET, MARK_UNSET);
-		if (hp) {
+		*result = gethostbyname_internal(name, AF_INET6, res, hp, buf, buflen, errorp, NETID_UNSET,
+		                                 MARK_UNSET);
+		if (*result) {
 			__res_put_state(res);
-			return hp;
+			return 0;
 		}
 	}
-	hp = gethostbyname_internal(name, AF_INET, res, NETID_UNSET, MARK_UNSET);
+	*result = gethostbyname_internal(name, AF_INET, res, hp, buf, buflen, errorp, NETID_UNSET,
+	                                 MARK_UNSET);
 	__res_put_state(res);
-	return hp;
+	if (!*result && errno == ENOSPC) {
+	  errno = ERANGE;
+	  return ERANGE; /* Return error as in linux manual page. */
+	}
+	return (*result) ? 0 : -1;
 }
 
-struct hostent *
-gethostbyname2(const char *name, int af)
+/* The prototype of gethostbyname2_r is from glibc, not that in netbsd. */
+int
+gethostbyname2_r(const char *name, int af, struct hostent *hp, char *buf,
+    size_t buflen, struct hostent **result, int *errorp)
 {
-	return android_gethostbynamefornet(name, af, NETID_UNSET, MARK_UNSET);
-}
-
-struct hostent *
-android_gethostbynamefornet(const char *name, int af, unsigned netid, unsigned mark)
-{
-	struct hostent *hp;
 	res_state res = __res_get_state();
 
-	if (res == NULL)
-		return NULL;
-	hp = gethostbyname_internal(name, af, res, netid, mark);
+	if (res == NULL) {
+		*result = NULL;
+		*errorp = NETDB_INTERNAL;
+		return -1;
+	}
+	*result = gethostbyname_internal(name, af, res, hp, buf, buflen, errorp, NETID_UNSET,
+	                                 MARK_UNSET);
 	__res_put_state(res);
-	return hp;
+	if (!*result && errno == ENOSPC) {
+		errno = ERANGE;
+		return ERANGE;
+	}
+	return (*result) ? 0 : -1;
 }
 
 __LIBC_HIDDEN__ FILE* android_open_proxy() {
@@ -562,7 +590,7 @@
 }
 
 static struct hostent *
-android_read_hostent(FILE* proxy)
+android_read_hostent(FILE* proxy, struct hostent* hp, char* hbuf, size_t hbuflen, int *he)
 {
 	uint32_t size;
 	char buf[4];
@@ -573,21 +601,27 @@
 	int result_code = strtol(buf, NULL, 10);
 	if (result_code != DnsProxyQueryResult) {
 		fread(&size, 1, sizeof(size), proxy);
+		*he = HOST_NOT_FOUND;
 		return NULL;
 	}
 
 	if (fread(&size, 1, sizeof(size), proxy) != sizeof(size)) return NULL;
 	size = ntohl(size);
-	res_static rs = __res_get_static();
-	memset(&rs->host, 0, sizeof(rs->host));
-	char *ptr = rs->hostbuf;
 
+	memset(hp, 0, sizeof(*hp));
+	char *ptr = hbuf;
+	char *hbuf_end = hbuf + hbuflen;
+
+	if (ptr + size > hbuf_end) {
+		goto nospc;
+	}
 	if (fread(ptr, 1, size, proxy) != size) return NULL;
+	hp->h_name = ptr;
 	ptr += size;
-	rs->host.h_name = rs->hostbuf;
 
-	char **aliases = rs->host_aliases;
-	rs->host.h_aliases = rs->host_aliases;
+	char *aliases_ptrs[MAXALIASES];
+	char **aliases = &aliases_ptrs[0];
+
 	while (1) {
 		if (fread(&size, 1, sizeof(size), proxy) != sizeof(size)) return NULL;
 		size = ntohl(size);
@@ -596,74 +630,107 @@
 			*aliases = NULL;
 			break;
 		}
+		if (ptr + size > hbuf_end) {
+		  goto nospc;
+		}
 		if (fread(ptr, 1, size, proxy) != size) return NULL;
-		*aliases++ = ptr;
+		if (aliases < &aliases_ptrs[MAXALIASES - 1]) {
+		  *aliases++ = ptr;
+		}
 		ptr += size;
 	}
 
-	if (fread(&size, 1, sizeof(size), proxy) != sizeof(size)) return NULL;
-	rs->host.h_addrtype = ntohl(size);
+	int aliases_len = ((int)(aliases - aliases_ptrs) + 1) * sizeof(*hp->h_aliases);
+	if (ptr + aliases_len > hbuf_end) {
+		goto nospc;
+	}
+	hp->h_aliases = (void*)ptr;
+	memcpy(ptr, aliases_ptrs, aliases_len);
+	ptr += aliases_len;
 
 	if (fread(&size, 1, sizeof(size), proxy) != sizeof(size)) return NULL;
-	rs->host.h_length = ntohl(size);
+	hp->h_addrtype = ntohl(size);
 
-	char **addrs = rs->h_addr_ptrs;
-	rs->host.h_addr_list = rs->h_addr_ptrs;
+	if (fread(&size, 1, sizeof(size), proxy) != sizeof(size)) return NULL;
+	hp->h_length = ntohl(size);
+
+	char *addr_ptrs[MAXADDRS];
+	char **addr_p = &addr_ptrs[0];
+
 	while (1) {
 		if (fread(&size, 1, sizeof(size), proxy) != sizeof(size)) return NULL;
 		size = ntohl(size);
 		if (size == 0) {
-			*addrs = NULL;
+			*addr_p = NULL;
 			break;
 		}
+		if (ptr + size > hbuf_end) {
+		  goto nospc;
+		}
 		if (fread(ptr, 1, size, proxy) != size) return NULL;
-		*addrs++ = ptr;
+		if (addr_p < &addr_ptrs[MAXADDRS - 1]) {
+		  *addr_p++ = ptr;
+		}
 		ptr += size;
 	}
 
-	return &rs->host;
+	int addrs_len = ((int)(addr_p - addr_ptrs) + 1) * sizeof(*hp->h_addr_list);
+	if (ptr + addrs_len > hbuf_end) {
+		goto nospc;
+	}
+	hp->h_addr_list = (void*)ptr;
+	memcpy(ptr, addr_ptrs, addrs_len);
+	*he = NETDB_SUCCESS;
+	return hp;
+
+nospc:
+	*he = NETDB_INTERNAL;
+	errno = ENOSPC;
+	return NULL;
 }
 
-
 static struct hostent *
-gethostbyname_internal_real(const char *name, int af, res_state res)
+gethostbyname_internal_real(const char *name, int af, res_state res, struct hostent *hp, char *buf,
+                            size_t buflen, int *he)
 {
 	const char *cp;
-	char *bp, *ep;
-	int size;
-	struct hostent *hp;
-	res_static rs = __res_get_static();
-
+	struct getnamaddr info;
+	char hbuf[MAXHOSTNAMELEN];
+	size_t size;
 	static const ns_dtab dtab[] = {
-		NS_FILES_CB(_gethtbyname, NULL)
+		NS_FILES_CB(_hf_gethtbyname, NULL)
 		{ NSSRC_DNS, _dns_gethtbyname, NULL },	/* force -DHESIOD */
-		{ 0, 0, 0 }
+		NS_NIS_CB(_yp_gethtbyname, NULL)
+		NS_NULL_CB
 	};
 
-	assert(name != NULL);
+	_DIAGASSERT(name != NULL);
 
 	switch (af) {
 	case AF_INET:
-		size = INADDRSZ;
+		size = NS_INADDRSZ;
 		break;
 	case AF_INET6:
-		size = IN6ADDRSZ;
+		size = NS_IN6ADDRSZ;
 		break;
 	default:
-		h_errno = NETDB_INTERNAL;
+		*he = NETDB_INTERNAL;
 		errno = EAFNOSUPPORT;
 		return NULL;
 	}
+	if (buflen < size)
+		goto nospc;
 
-	rs->host.h_addrtype = af;
-	rs->host.h_length = size;
+	hp->h_addrtype = af;
+	hp->h_length = (int)size;
 
 	/*
 	 * if there aren't any dots, it could be a user-level alias.
 	 * this is also done in res_nquery() since we are not the only
 	 * function that looks up host names.
 	 */
-	if (!strchr(name, '.') && (cp = __hostalias(name)))
+	if (!strchr(name, '.') && (cp = res_hostalias(res, name,
+	    hbuf, sizeof(hbuf))))
 		name = cp;
 
 	/*
@@ -680,25 +747,7 @@
 				 * Fake up a hostent as if we'd actually
 				 * done a lookup.
 				 */
-				if (inet_pton(af, name,
-				    (char *)(void *)rs->host_addr) <= 0) {
-					h_errno = HOST_NOT_FOUND;
-					return NULL;
-				}
-				strncpy(rs->hostbuf, name, MAXDNAME);
-				rs->hostbuf[MAXDNAME] = '\0';
-				bp = rs->hostbuf + MAXDNAME;
-				ep = rs->hostbuf + sizeof rs->hostbuf;
-				rs->host.h_name = rs->hostbuf;
-				rs->host.h_aliases = rs->host_aliases;
-				rs->host_aliases[0] = NULL;
-				rs->h_addr_ptrs[0] = (char *)(void *)rs->host_addr;
-				rs->h_addr_ptrs[1] = NULL;
-				rs->host.h_addr_list = rs->h_addr_ptrs;
-				if (res->options & RES_USE_INET6)
-					map_v4v6_hostent(&rs->host, &bp, ep);
-				h_errno = NETDB_SUCCESS;
-				return &rs->host;
+				goto fake;
 			}
 			if (!isdigit((u_char) *cp) && *cp != '.')
 				break;
@@ -714,49 +763,60 @@
 				 * Fake up a hostent as if we'd actually
 				 * done a lookup.
 				 */
-				if (inet_pton(af, name,
-				    (char *)(void *)rs->host_addr) <= 0) {
-					h_errno = HOST_NOT_FOUND;
-					return NULL;
-				}
-				strncpy(rs->hostbuf, name, MAXDNAME);
-				rs->hostbuf[MAXDNAME] = '\0';
-				bp = rs->hostbuf + MAXDNAME;
-				ep = rs->hostbuf + sizeof rs->hostbuf;
-				rs->host.h_name = rs->hostbuf;
-				rs->host.h_aliases = rs->host_aliases;
-				rs->host_aliases[0] = NULL;
-				rs->h_addr_ptrs[0] = (char *)(void *)rs->host_addr;
-				rs->h_addr_ptrs[1] = NULL;
-				rs->host.h_addr_list = rs->h_addr_ptrs;
-				h_errno = NETDB_SUCCESS;
-				return &rs->host;
+				goto fake;
 			}
 			if (!isxdigit((u_char) *cp) && *cp != ':' && *cp != '.')
 				break;
 		}
 
-	hp = NULL;
-	h_errno = NETDB_INTERNAL;
-	if (nsdispatch(&hp, dtab, NSDB_HOSTS, "gethostbyname",
-	    default_dns_files, name, strlen(name), af) != NS_SUCCESS) {
+	*he = NETDB_INTERNAL;
+	info.hp = hp;
+	info.buf = buf;
+	info.buflen = buflen;
+	info.he = he;
+	if (nsdispatch(&info, dtab, NSDB_HOSTS, "gethostbyname",
+	    default_dns_files, name, strlen(name), af) != NS_SUCCESS)
+		return NULL;
+	*he = NETDB_SUCCESS;
+	return hp;
+nospc:
+	*he = NETDB_INTERNAL;
+	errno = ENOSPC;
+	return NULL;
+fake:
+	HENT_ARRAY(hp->h_addr_list, 1, buf, buflen);
+	HENT_ARRAY(hp->h_aliases, 0, buf, buflen);
+
+	hp->h_aliases[0] = NULL;
+	if (size > buflen)
+		goto nospc;
+
+	if (inet_pton(af, name, buf) <= 0) {
+		*he = HOST_NOT_FOUND;
 		return NULL;
 	}
-	h_errno = NETDB_SUCCESS;
+	hp->h_addr_list[0] = buf;
+	hp->h_addr_list[1] = NULL;
+	buf += size;
+	buflen -= size;
+	HENT_SCOPY(hp->h_name, name, buf, buflen);
+	if (res->options & RES_USE_INET6)
+		map_v4v6_hostent(hp, &buf, buf + buflen);
+	*he = NETDB_SUCCESS;
 	return hp;
 }
 
-
 // very similar in proxy-ness to android_getaddrinfo_proxy
 static struct hostent *
-gethostbyname_internal(const char *name, int af, res_state res, unsigned netid, unsigned mark)
+gethostbyname_internal(const char *name, int af, res_state res, struct hostent *hp, char *hbuf,
+                       size_t hbuflen, int *errorp, unsigned netid, unsigned mark)
 {
 	FILE* proxy = android_open_proxy();
 	if (proxy == NULL) {
 		// Either we're not supposed to be using the proxy or the proxy is unavailable.
 		res_setnetid(res, netid);
 		res_setmark(res, mark);
-		return gethostbyname_internal_real(name, af, res);
+		return gethostbyname_internal_real(name, af, res, hp, hbuf, hbuflen, errorp);
 	}
 
 	netid = __netdClientDispatch.netIdForResolv(netid);
@@ -776,29 +836,44 @@
 		return NULL;
 	}
 
-	struct hostent* result = android_read_hostent(proxy);
+	struct hostent* result = android_read_hostent(proxy, hp, hbuf, hbuflen, errorp);
 	fclose(proxy);
 	return result;
 }
 
+/* The prototype of gethostbyaddr_r is from glibc, not that in netbsd. */
+int gethostbyaddr_r(const void *addr, socklen_t len, int af, struct hostent *hp, char *buf,
+                    size_t buflen, struct hostent **result, int *h_errnop)
+{
+	*result = android_gethostbyaddrfornet_proxy_internal(addr, len, af, hp, buf, buflen, h_errnop,
+                                                       NETID_UNSET, MARK_UNSET);
+	if (!*result && errno == ENOSPC) {
+		errno = ERANGE;
+		return ERANGE;
+	}
+	return (*result) ? 0 : -1;
+}
 
 static struct hostent *
-android_gethostbyaddrfornet_real(const void *addr, socklen_t len, int af, unsigned netid, unsigned mark) {
+android_gethostbyaddrfornet_real(const void *addr, socklen_t len, int af, struct hostent *hp,
+                                 char *buf, size_t buflen, int *he, unsigned netid, unsigned mark)
+{
 	const u_char *uaddr = (const u_char *)addr;
 	socklen_t size;
-	struct hostent *hp;
+	struct getnamaddr info;
 	static const ns_dtab dtab[] = {
-		NS_FILES_CB(_gethtbyaddr, NULL)
+		NS_FILES_CB(_hf_gethtbyaddr, NULL)
 		{ NSSRC_DNS, _dns_gethtbyaddr, NULL },	/* force -DHESIOD */
-		{ 0, 0, 0 }
+		NS_NIS_CB(_yp_gethtbyaddr, NULL)
+		NS_NULL_CB
 	};
 
-	assert(addr != NULL);
+	_DIAGASSERT(addr != NULL);
 
 	if (af == AF_INET6 && len == NS_IN6ADDRSZ &&
 	    (IN6_IS_ADDR_LINKLOCAL((const struct in6_addr *)addr) ||
 	     IN6_IS_ADDR_SITELOCAL((const struct in6_addr *)addr))) {
-		h_errno = HOST_NOT_FOUND;
+		*he = HOST_NOT_FOUND;
 		return NULL;
 	}
 	if (af == AF_INET6 && len == NS_IN6ADDRSZ &&
@@ -819,29 +894,35 @@
 		break;
 	default:
 		errno = EAFNOSUPPORT;
-		h_errno = NETDB_INTERNAL;
+		*he = NETDB_INTERNAL;
 		return NULL;
 	}
 	if (size != len) {
 		errno = EINVAL;
-		h_errno = NETDB_INTERNAL;
+		*he = NETDB_INTERNAL;
 		return NULL;
 	}
-	hp = NULL;
-	h_errno = NETDB_INTERNAL;
-	if (nsdispatch(&hp, dtab, NSDB_HOSTS, "gethostbyaddr",
-		default_dns_files, uaddr, len, af, netid, mark) != NS_SUCCESS)
+	info.hp = hp;
+	info.buf = buf;
+	info.buflen = buflen;
+	info.he = he;
+	*he = NETDB_INTERNAL;
+	if (nsdispatch(&info, dtab, NSDB_HOSTS, "gethostbyaddr",
+	    default_dns_files, uaddr, len, af, netid, mark) != NS_SUCCESS)
 		return NULL;
-	h_errno = NETDB_SUCCESS;
+	*he = NETDB_SUCCESS;
 	return hp;
 }
 
-__LIBC_HIDDEN__ struct hostent*
-android_gethostbyaddrfornet_proxy(const void* addr, socklen_t len, int af, unsigned netid, unsigned mark) {
+static struct hostent*
+android_gethostbyaddrfornet_proxy_internal(const void* addr, socklen_t len, int af,
+                             struct hostent *hp, char *hbuf, size_t hbuflen, int *he,
+                             unsigned netid, unsigned mark)
+{
 	FILE* proxy = android_open_proxy();
 	if (proxy == NULL) {
 		// Either we're not supposed to be using the proxy or the proxy is unavailable.
-		return android_gethostbyaddrfornet_real(addr,len, af, netid, mark);
+		return android_gethostbyaddrfornet_real(addr,len, af, hp, hbuf, hbuflen, he, netid, mark);
 	}
 
 	char buf[INET6_ADDRSTRLEN];  //big enough for IPv4 and IPv6
@@ -864,302 +945,144 @@
 		return NULL;
 	}
 
-	struct hostent *result = android_read_hostent(proxy);
+	struct hostent *result = android_read_hostent(proxy, hp, hbuf, hbuflen, he);
 	fclose(proxy);
 	return result;
 }
 
-struct hostent *
-android_gethostbyaddrfornet(const void *addr, socklen_t len, int af, unsigned netid, unsigned mark)
+struct hostent*
+netbsd_gethostent_r(FILE *hf, struct hostent *hent, char *buf, size_t buflen, int *he)
 {
-	return android_gethostbyaddrfornet_proxy(addr, len, af, netid, mark);
-}
-
-struct hostent *
-gethostbyaddr(const void *addr, socklen_t len, int af)
-{
-	return android_gethostbyaddrfornet(addr, len, af, NETID_UNSET, MARK_UNSET);
-}
-
-
-static void
-_sethtent(int f)
-{
-    res_static  rs = __res_get_static();
-    if (rs == NULL) return;
-	if (!rs->hostf)
-		rs->hostf = fopen(_PATH_HOSTS, "re" );
-	else
-		rewind(rs->hostf);
-	rs->stayopen = f;
-}
-
-static void
-_endhtent(void)
-{
-    res_static  rs = __res_get_static();
-    if (rs == NULL) return;
-
-	if (rs->hostf && !rs->stayopen) {
-		(void) fclose(rs->hostf);
-		rs->hostf = NULL;
-	}
-}
-
-static struct hostent *
-_gethtent(void)
-{
-	char *p;
+	char *p, *name;
 	char *cp, **q;
 	int af, len;
-	res_static  rs = __res_get_static();
+	size_t anum;
+	char **aliases;
+	size_t maxaliases;
+	struct in6_addr host_addr;
 
-	if (!rs->hostf && !(rs->hostf = fopen(_PATH_HOSTS, "re" ))) {
-		h_errno = NETDB_INTERNAL;
+	if (hf == NULL) {
+		*he = NETDB_INTERNAL;
+		errno = EINVAL;
 		return NULL;
 	}
- again:
-	if (!(p = fgets(rs->hostbuf, sizeof rs->hostbuf, rs->hostf))) {
-		h_errno = HOST_NOT_FOUND;
-		return NULL;
+	p = NULL;
+	setup(aliases, maxaliases);
+
+	/* Allocate a new space to read file lines like upstream does.
+	 * To keep reentrancy we cannot use __res_get_static()->hostbuf here,
+	 * as the buffer may be used to store content for a previous hostent
+	 * returned by non-reentrant functions like gethostbyname().
+	 */
+	const size_t line_buf_size = sizeof(__res_get_static()->hostbuf);
+	if ((p = malloc(line_buf_size)) == NULL) {
+	  goto nospc;
 	}
-	if (*p == '#')
-		goto again;
-	if (!(cp = strpbrk(p, "#\n")))
-		goto again;
-	*cp = '\0';
-	if (!(cp = strpbrk(p, " \t")))
-		goto again;
-	*cp++ = '\0';
-	if (inet_pton(AF_INET6, p, (char *)(void *)rs->host_addr) > 0) {
-		af = AF_INET6;
-		len = IN6ADDRSZ;
-	} else if (inet_pton(AF_INET, p, (char *)(void *)rs->host_addr) > 0) {
-		res_state res = __res_get_state();
-		if (res == NULL)
+	for (;;) {
+		if (!fgets(p, line_buf_size, hf)) {
+			free(p);
+			free(aliases);
+			*he = HOST_NOT_FOUND;
 			return NULL;
-		if (res->options & RES_USE_INET6) {
-			map_v4v6_address((char *)(void *)rs->host_addr,
-			    (char *)(void *)rs->host_addr);
-			af = AF_INET6;
-			len = IN6ADDRSZ;
-		} else {
-			af = AF_INET;
-			len = INADDRSZ;
+    		}
+		if (*p == '#') {
+			continue;
 		}
-		__res_put_state(res);
-	} else {
-		goto again;
-	}
-	/* if this is not something we're looking for, skip it. */
-	if (rs->host.h_addrtype != 0 && rs->host.h_addrtype != af)
-		goto again;
-	if (rs->host.h_length != 0 && rs->host.h_length != len)
-		goto again;
-	rs->h_addr_ptrs[0] = (char *)(void *)rs->host_addr;
-	rs->h_addr_ptrs[1] = NULL;
-	rs->host.h_addr_list = rs->h_addr_ptrs;
-	rs->host.h_length = len;
-	rs->host.h_addrtype = af;
-	while (*cp == ' ' || *cp == '\t')
-		cp++;
-	rs->host.h_name = cp;
-	q = rs->host.h_aliases = rs->host_aliases;
-	if ((cp = strpbrk(cp, " \t")) != NULL)
+		if (!(cp = strpbrk(p, "#\n"))) {
+			continue;
+		}
+		*cp = '\0';
+		if (!(cp = strpbrk(p, " \t")))
+			continue;
 		*cp++ = '\0';
-	while (cp && *cp) {
-		if (*cp == ' ' || *cp == '\t') {
+		if (inet_pton(AF_INET6, p, &host_addr) > 0) {
+			af = AF_INET6;
+			len = NS_IN6ADDRSZ;
+		} else {
+			if (inet_pton(AF_INET, p, &host_addr) <= 0)
+				continue;
+
+			res_state res = __res_get_state();
+			if (res == NULL)
+				goto nospc;
+			if (res->options & RES_USE_INET6) {
+				map_v4v6_address(buf, buf);
+				af = AF_INET6;
+				len = NS_IN6ADDRSZ;
+			} else {
+				af = AF_INET;
+				len = NS_INADDRSZ;
+			}
+			__res_put_state(res);
+		}
+
+		/* if this is not something we're looking for, skip it. */
+		if (hent->h_addrtype != 0 && hent->h_addrtype != af)
+			continue;
+		if (hent->h_length != 0 && hent->h_length != len)
+			continue;
+
+		while (*cp == ' ' || *cp == '\t')
 			cp++;
-			continue;
-		}
-		if (q < &rs->host_aliases[MAXALIASES - 1])
-			*q++ = cp;
-		if ((cp = strpbrk(cp, " \t")) != NULL)
+		if ((cp = strpbrk(name = cp, " \t")) != NULL)
 			*cp++ = '\0';
-	}
-	*q = NULL;
-	h_errno = NETDB_SUCCESS;
-	return &rs->host;
-}
-
-/*ARGSUSED*/
-int
-_gethtbyname(void *rv, void *cb_data, va_list ap)
-{
-	struct hostent *hp;
-	const char *name;
-	int af;
-
-	assert(rv != NULL);
-
-	name = va_arg(ap, char *);
-	/* NOSTRICT skip len */(void)va_arg(ap, int);
-	af = va_arg(ap, int);
-
-	hp = NULL;
-#if 0
-	{
-		res_state res = __res_get_state();
-		if (res == NULL)
-			return NS_NOTFOUND;
-		if (res->options & RES_USE_INET6)
-			hp = _gethtbyname2(name, AF_INET6);
-		if (hp==NULL)
-			hp = _gethtbyname2(name, AF_INET);
-		__res_put_state(res);
-	}
-#else
-	hp = _gethtbyname2(name, af);
-#endif
-	*((struct hostent **)rv) = hp;
-	if (hp == NULL) {
-		h_errno = HOST_NOT_FOUND;
-		return NS_NOTFOUND;
-	}
-	return NS_SUCCESS;
-}
-
-static struct hostent *
-_gethtbyname2(const char *name, int af)
-{
-	struct hostent *p;
-	char *tmpbuf, *ptr, **cp;
-	int num;
-	size_t len;
-	res_static rs = __res_get_static();
-
-	assert(name != NULL);
-
-	_sethtent(rs->stayopen);
-	ptr = tmpbuf = NULL;
-	num = 0;
-	while ((p = _gethtent()) != NULL && num < MAXADDRS) {
-		if (p->h_addrtype != af)
-			continue;
-		if (strcasecmp(p->h_name, name) != 0) {
-			for (cp = p->h_aliases; *cp != NULL; cp++)
-				if (strcasecmp(*cp, name) == 0)
-					break;
-			if (*cp == NULL) continue;
-		}
-
-		if (num == 0) {
-			size_t bufsize;
-			char *src;
-
-			bufsize = strlen(p->h_name) + 2 +
-				  MAXADDRS * p->h_length +
-				  ALIGNBYTES;
-			for (cp = p->h_aliases; *cp != NULL; cp++)
-				bufsize += strlen(*cp) + 1;
-
-			if ((tmpbuf = malloc(bufsize)) == NULL) {
-				h_errno = NETDB_INTERNAL;
-				return NULL;
+		q = aliases;
+		while (cp && *cp) {
+			if (*cp == ' ' || *cp == '\t') {
+				cp++;
+				continue;
 			}
-
-			ptr = tmpbuf;
-			src = p->h_name;
-			while ((*ptr++ = *src++) != '\0');
-			for (cp = p->h_aliases; *cp != NULL; cp++) {
-				src = *cp;
-				while ((*ptr++ = *src++) != '\0');
-			}
-			*ptr++ = '\0';
-
-			ptr = (char *)(void *)ALIGN(ptr);
+			addalias(q, cp, aliases, maxaliases);
+			if ((cp = strpbrk(cp, " \t")) != NULL)
+				*cp++ = '\0';
 		}
-
-		(void)memcpy(ptr, p->h_addr_list[0], (size_t)p->h_length);
-		ptr += p->h_length;
-		num++;
+		break;
 	}
-	_endhtent();
-	if (num == 0) return NULL;
+	hent->h_length = len;
+	hent->h_addrtype = af;
+	HENT_ARRAY(hent->h_addr_list, 1, buf, buflen);
+	anum = (size_t)(q - aliases);
+	HENT_ARRAY(hent->h_aliases, anum, buf, buflen);
+	HENT_COPY(hent->h_addr_list[0], &host_addr, hent->h_length, buf,
+	    buflen);
+	hent->h_addr_list[1] = NULL;
 
-	len = ptr - tmpbuf;
-	if (len > (sizeof(rs->hostbuf) - ALIGNBYTES)) {
-		free(tmpbuf);
-		errno = ENOSPC;
-		h_errno = NETDB_INTERNAL;
-		return NULL;
-	}
-	ptr = memcpy((void *)ALIGN(rs->hostbuf), tmpbuf, len);
-	free(tmpbuf);
+	HENT_SCOPY(hent->h_name, name, buf, buflen);
+	for (size_t i = 0; i < anum; i++)
+		HENT_SCOPY(hent->h_aliases[i], aliases[i], buf, buflen);
+	hent->h_aliases[anum] = NULL;
 
-	rs->host.h_name = ptr;
-	while (*ptr++);
-
-	cp = rs->host_aliases;
-	while (*ptr) {
-		*cp++ = ptr;
-		while (*ptr++);
-	}
-	ptr++;
-	*cp = NULL;
-
-	ptr = (char *)(void *)ALIGN(ptr);
-	cp = rs->h_addr_ptrs;
-	while (num--) {
-		*cp++ = ptr;
-		ptr += rs->host.h_length;
-	}
-	*cp = NULL;
-
-	return &rs->host;
-}
-
-/*ARGSUSED*/
-static int
-_gethtbyaddr(void *rv, void *cb_data, va_list ap)
-{
-	struct hostent *p;
-	const unsigned char *addr;
-	int len, af;
-	res_static  rs = __res_get_static();
-
-	assert(rv != NULL);
-
-	addr = va_arg(ap, unsigned char *);
-	len = va_arg(ap, int);
-	af = va_arg(ap, int);
-
-	rs->host.h_length = len;
-	rs->host.h_addrtype = af;
-
-	_sethtent(rs->stayopen);
-	while ((p = _gethtent()) != NULL)
-		if (p->h_addrtype == af && !memcmp(p->h_addr, addr,
-		    (size_t)len))
-			break;
-	_endhtent();
-	*((struct hostent **)rv) = p;
-	if (p==NULL) {
-		h_errno = HOST_NOT_FOUND;
-		return NS_NOTFOUND;
-	}
-	return NS_SUCCESS;
+	*he = NETDB_SUCCESS;
+	free(p);
+	free(aliases);
+	return hent;
+nospc:
+	free(p);
+	free(aliases);
+	errno = ENOSPC;
+	*he = NETDB_INTERNAL;
+	return NULL;
 }
 
 static void
 map_v4v6_address(const char *src, char *dst)
 {
 	u_char *p = (u_char *)dst;
-	char tmp[INADDRSZ];
+	char tmp[NS_INADDRSZ];
 	int i;
 
-	assert(src != NULL);
-	assert(dst != NULL);
+	_DIAGASSERT(src != NULL);
+	_DIAGASSERT(dst != NULL);
 
 	/* Stash a temporary copy so our caller can update in place. */
-	(void)memcpy(tmp, src, INADDRSZ);
+	(void)memcpy(tmp, src, NS_INADDRSZ);
 	/* Mark this ipv6 addr as a mapped ipv4. */
 	for (i = 0; i < 10; i++)
 		*p++ = 0x00;
 	*p++ = 0xff;
 	*p++ = 0xff;
 	/* Retrieve the saved copy and we're done. */
-	(void)memcpy((void *)p, tmp, INADDRSZ);
+	(void)memcpy(p, tmp, NS_INADDRSZ);
 }
 
 static void
@@ -1167,18 +1090,19 @@
 {
 	char **ap;
 
-	assert(hp != NULL);
-	assert(bpp != NULL);
-	assert(ep != NULL);
+	_DIAGASSERT(hp != NULL);
+	_DIAGASSERT(bpp != NULL);
+	_DIAGASSERT(ep != NULL);
 
-	if (hp->h_addrtype != AF_INET || hp->h_length != INADDRSZ)
+	if (hp->h_addrtype != AF_INET || hp->h_length != NS_INADDRSZ)
 		return;
 	hp->h_addrtype = AF_INET6;
-	hp->h_length = IN6ADDRSZ;
+	hp->h_length = NS_IN6ADDRSZ;
 	for (ap = hp->h_addr_list; *ap; ap++) {
-		int i = sizeof(align) - (size_t)((u_long)*bpp % sizeof(align));
+		int i = (int)(sizeof(align) -
+		    (size_t)((u_long)*bpp % sizeof(align)));
 
-		if (ep - *bpp < (i + IN6ADDRSZ)) {
+		if (ep - *bpp < (i + NS_IN6ADDRSZ)) {
 			/* Out of memory.  Truncate address list here.  XXX */
 			*ap = NULL;
 			return;
@@ -1186,7 +1110,7 @@
 		*bpp += i;
 		map_v4v6_address(*ap, *bpp);
 		*ap = *bpp;
-		*bpp += IN6ADDRSZ;
+		*bpp += NS_IN6ADDRSZ;
 	}
 }
 
@@ -1198,7 +1122,7 @@
 	short aval[MAXADDRS];
 	int needsort = 0;
 
-	assert(ap != NULL);
+	_DIAGASSERT(ap != NULL);
 
 	p = ap;
 	for (i = 0; i < num; i++, p++) {
@@ -1233,15 +1157,6 @@
 	}
 }
 
-struct hostent *
-gethostent(void)
-{
-    res_static  rs = __res_get_static();
-	rs->host.h_addrtype = 0;
-	rs->host.h_length = 0;
-	return _gethtent();
-}
-
 /*ARGSUSED*/
 static int
 _dns_gethtbyname(void *rv, void *cb_data, va_list ap)
@@ -1250,20 +1165,22 @@
 	int n, type;
 	struct hostent *hp;
 	const char *name;
-	int af;
 	res_state res;
+	struct getnamaddr *info = rv;
 
-	assert(rv != NULL);
+	_DIAGASSERT(rv != NULL);
 
 	name = va_arg(ap, char *);
-	/* NOSTRICT skip len */(void)va_arg(ap, int);
-	af = va_arg(ap, int);
+	/* NOSTRICT skip string len */(void)va_arg(ap, int);
+	info->hp->h_addrtype = va_arg(ap, int);
 
-	switch (af) {
+	switch (info->hp->h_addrtype) {
 	case AF_INET:
+		info->hp->h_length = NS_INADDRSZ;
 		type = T_A;
 		break;
 	case AF_INET6:
+		info->hp->h_length = NS_IN6ADDRSZ;
 		type = T_AAAA;
 		break;
 	default:
@@ -1271,7 +1188,7 @@
 	}
 	buf = malloc(sizeof(*buf));
 	if (buf == NULL) {
-		h_errno = NETDB_INTERNAL;
+		*info->he = NETDB_INTERNAL;
 		return NS_NOTFOUND;
 	}
 	res = __res_get_state();
@@ -1279,14 +1196,15 @@
 		free(buf);
 		return NS_NOTFOUND;
 	}
-	n = res_nsearch(res, name, C_IN, type, buf->buf, sizeof(buf->buf));
+	n = res_nsearch(res, name, C_IN, type, buf->buf, (int)sizeof(buf->buf));
 	if (n < 0) {
 		free(buf);
-		dprintf("res_nsearch failed (%d)\n", res, n);
+		debugprintf("res_nsearch failed (%d)\n", res, n);
 		__res_put_state(res);
 		return NS_NOTFOUND;
 	}
-	hp = getanswer(buf, n, name, type, res);
+	hp = getanswer(buf, n, name, type, res, info->hp, info->buf,
+	    info->buflen, info->he);
 	free(buf);
 	__res_put_state(res);
 	if (hp == NULL)
@@ -1298,7 +1216,6 @@
 		default:
 			return NS_UNAVAIL;
 		}
-	*((struct hostent **)rv) = hp;
 	return NS_SUCCESS;
 }
 
@@ -1311,20 +1228,22 @@
 	querybuf *buf;
 	struct hostent *hp;
 	const unsigned char *uaddr;
-	int len, af, advance;
+	int advance;
 	res_state res;
+	char *bf;
+	size_t blen;
+	struct getnamaddr *info = rv;
 	unsigned netid, mark;
-	res_static rs = __res_get_static();
 
-	assert(rv != NULL);
+	_DIAGASSERT(rv != NULL);
 
 	uaddr = va_arg(ap, unsigned char *);
-	len = va_arg(ap, int);
-	af = va_arg(ap, int);
+	info->hp->h_length = va_arg(ap, int);
+	info->hp->h_addrtype = va_arg(ap, int);
 	netid = va_arg(ap, unsigned);
 	mark = va_arg(ap, unsigned);
 
-	switch (af) {
+	switch (info->hp->h_addrtype) {
 	case AF_INET:
 		(void)snprintf(qbuf, sizeof(qbuf), "%u.%u.%u.%u.in-addr.arpa",
 		    (uaddr[3] & 0xff), (uaddr[2] & 0xff),
@@ -1334,29 +1253,29 @@
 	case AF_INET6:
 		qp = qbuf;
 		ep = qbuf + sizeof(qbuf) - 1;
-		for (n = IN6ADDRSZ - 1; n >= 0; n--) {
+		for (n = NS_IN6ADDRSZ - 1; n >= 0; n--) {
 			advance = snprintf(qp, (size_t)(ep - qp), "%x.%x.",
 			    uaddr[n] & 0xf,
 			    ((unsigned int)uaddr[n] >> 4) & 0xf);
 			if (advance > 0 && qp + advance < ep)
 				qp += advance;
 			else {
-				h_errno = NETDB_INTERNAL;
+				*info->he = NETDB_INTERNAL;
 				return NS_NOTFOUND;
 			}
 		}
 		if (strlcat(qbuf, "ip6.arpa", sizeof(qbuf)) >= sizeof(qbuf)) {
-			h_errno = NETDB_INTERNAL;
+			*info->he = NETDB_INTERNAL;
 			return NS_NOTFOUND;
 		}
 		break;
 	default:
-		abort();
+		return NS_UNAVAIL;
 	}
 
 	buf = malloc(sizeof(*buf));
 	if (buf == NULL) {
-		h_errno = NETDB_INTERNAL;
+		*info->he = NETDB_INTERNAL;
 		return NS_NOTFOUND;
 	}
 	res = __res_get_state();
@@ -1366,18 +1285,19 @@
 	}
 	res_setnetid(res, netid);
 	res_setmark(res, mark);
-	n = res_nquery(res, qbuf, C_IN, T_PTR, buf->buf, sizeof(buf->buf));
+	n = res_nquery(res, qbuf, C_IN, T_PTR, buf->buf, (int)sizeof(buf->buf));
 	if (n < 0) {
 		free(buf);
-		dprintf("res_nquery failed (%d)\n", res, n);
+		debugprintf("res_nquery failed (%d)\n", res, n);
 		__res_put_state(res);
 		return NS_NOTFOUND;
 	}
-	hp = getanswer(buf, n, qbuf, T_PTR, res);
+	hp = getanswer(buf, n, qbuf, T_PTR, res, info->hp, info->buf,
+	    info->buflen, info->he);
 	free(buf);
 	if (hp == NULL) {
 		__res_put_state(res);
-		switch (h_errno) {
+		switch (*info->he) {
 		case HOST_NOT_FOUND:
 			return NS_NOTFOUND;
 		case TRY_AGAIN:
@@ -1386,20 +1306,325 @@
 			return NS_UNAVAIL;
 		}
 	}
-	hp->h_addrtype = af;
-	hp->h_length = len;
-	(void)memcpy(rs->host_addr, uaddr, (size_t)len);
-	rs->h_addr_ptrs[0] = (char *)(void *)rs->host_addr;
-	rs->h_addr_ptrs[1] = NULL;
-	if (af == AF_INET && (res->options & RES_USE_INET6)) {
-		map_v4v6_address((char *)(void *)rs->host_addr,
-		    (char *)(void *)rs->host_addr);
+
+	bf = (void *)(hp->h_addr_list + 2);
+	blen = (size_t)(bf - info->buf);
+	if (blen + info->hp->h_length > info->buflen)
+		goto nospc;
+	hp->h_addr_list[0] = bf;
+	hp->h_addr_list[1] = NULL;
+	(void)memcpy(bf, uaddr, (size_t)info->hp->h_length);
+	if (info->hp->h_addrtype == AF_INET && (res->options & RES_USE_INET6)) {
+		if (blen + NS_IN6ADDRSZ > info->buflen)
+			goto nospc;
+		map_v4v6_address(bf, bf);
 		hp->h_addrtype = AF_INET6;
-		hp->h_length = IN6ADDRSZ;
+		hp->h_length = NS_IN6ADDRSZ;
 	}
 
 	__res_put_state(res);
-	*((struct hostent **)rv) = hp;
-	h_errno = NETDB_SUCCESS;
+	*info->he = NETDB_SUCCESS;
 	return NS_SUCCESS;
+nospc:
+	*info->he = NETDB_INTERNAL;
+	return NS_UNAVAIL;
+}
+
+#ifdef YP
+/*ARGSUSED*/
+static struct hostent *
+_yp_hostent(char *line, int af, struct getnamaddr *info)
+{
+	struct in6_addr host_addrs[MAXADDRS];
+	char **aliases;
+	size_t maxaliases;
+	char *p = line;
+	char *cp, **q, *ptr;
+	size_t len, anum, i;
+	int addrok;
+	int more;
+	size_t naddrs;
+	struct hostent *hp = info->hp;
+
+	_DIAGASSERT(line != NULL);
+
+	hp->h_name = NULL;
+	hp->h_addrtype = af;
+	switch (af) {
+	case AF_INET:
+		hp->h_length = NS_INADDRSZ;
+		break;
+	case AF_INET6:
+		hp->h_length = NS_IN6ADDRSZ;
+		break;
+	default:
+		return NULL;
+	}
+	setup(aliases, maxaliases);
+	naddrs = 0;
+	q = aliases;
+
+nextline:
+	/* check for host_addrs overflow */
+	if (naddrs >= __arraycount(host_addrs))
+		goto done;
+
+	more = 0;
+	cp = strpbrk(p, " \t");
+	if (cp == NULL)
+		goto done;
+	*cp++ = '\0';
+
+	/* p has should have an address */
+	addrok = inet_pton(af, p, &host_addrs[naddrs]);
+	if (addrok != 1) {
+		/* skip to the next line */
+		while (cp && *cp) {
+			if (*cp == '\n') {
+				cp++;
+				goto nextline;
+			}
+			cp++;
+		}
+		goto done;
+	}
+	naddrs++;
+
+	while (*cp == ' ' || *cp == '\t')
+		cp++;
+	p = cp;
+	cp = strpbrk(p, " \t\n");
+	if (cp != NULL) {
+		if (*cp == '\n')
+			more = 1;
+		*cp++ = '\0';
+	}
+	if (!hp->h_name)
+		hp->h_name = p;
+	else if (strcmp(hp->h_name, p) == 0)
+		;
+	else
+		addalias(q, p, aliases, maxaliases);
+	p = cp;
+	if (more)
+		goto nextline;
+
+	while (cp && *cp) {
+		if (*cp == ' ' || *cp == '\t') {
+			cp++;
+			continue;
+		}
+		if (*cp == '\n') {
+			cp++;
+			goto nextline;
+		}
+		addalias(q, cp, aliases, maxaliases);
+		cp = strpbrk(cp, " \t");
+		if (cp != NULL)
+			*cp++ = '\0';
+	}
+
+done:
+	if (hp->h_name == NULL) {
+		free(aliases);
+		return NULL;
+	}
+
+	ptr = info->buf;
+	len = info->buflen;
+
+	anum = (size_t)(q - aliases);
+	HENT_ARRAY(hp->h_addr_list, naddrs, ptr, len);
+	HENT_ARRAY(hp->h_aliases, anum, ptr, len);
+
+	for (i = 0; i < naddrs; i++)
+		HENT_COPY(hp->h_addr_list[i], &host_addrs[i], hp->h_length,
+		    ptr, len);
+	hp->h_addr_list[naddrs] = NULL;
+
+	HENT_SCOPY(hp->h_name, hp->h_name, ptr, len);
+
+	for (i = 0; i < anum; i++)
+		HENT_SCOPY(hp->h_aliases[i], aliases[i], ptr, len);
+	hp->h_aliases[anum] = NULL;
+	free(aliases);
+
+	return hp;
+nospc:
+	free(aliases);
+	*info->he = NETDB_INTERNAL;
+	errno = ENOSPC;
+	return NULL;
+}
+
+/*ARGSUSED*/
+int
+_yp_gethtbyaddr(void *rv, void *cb_data, va_list ap)
+{
+	struct hostent *hp = NULL;
+	char *ypcurrent;
+	int ypcurrentlen, r;
+	char name[INET6_ADDRSTRLEN];	/* XXX enough? */
+	const unsigned char *uaddr;
+	int af;
+	const char *map;
+	struct getnamaddr *info = rv;
+
+	_DIAGASSERT(rv != NULL);
+
+	uaddr = va_arg(ap, unsigned char *);
+	/* NOSTRICT skip len */(void)va_arg(ap, int);
+	af = va_arg(ap, int);
+
+	if (!__ypdomain) {
+		if (_yp_check(&__ypdomain) == 0)
+			return NS_UNAVAIL;
+	}
+	/*
+	 * XXX unfortunately, we cannot support IPv6 extended scoped address
+	 * notation here.  gethostbyaddr() is not scope-aware.  too bad.
+	 */
+	if (inet_ntop(af, uaddr, name, (socklen_t)sizeof(name)) == NULL)
+		return NS_UNAVAIL;
+	switch (af) {
+	case AF_INET:
+		map = "hosts.byaddr";
+		break;
+	default:
+		map = "ipnodes.byaddr";
+		break;
+	}
+	ypcurrent = NULL;
+	r = yp_match(__ypdomain, map, name,
+		(int)strlen(name), &ypcurrent, &ypcurrentlen);
+	if (r == 0)
+		hp = _yp_hostent(ypcurrent, af, info);
+	else
+		hp = NULL;
+	free(ypcurrent);
+	if (hp == NULL) {
+		*info->he = HOST_NOT_FOUND;
+		return NS_NOTFOUND;
+	}
+	return NS_SUCCESS;
+}
+
+/*ARGSUSED*/
+int
+_yp_gethtbyname(void *rv, void *cb_data, va_list ap)
+{
+	struct hostent *hp;
+	char *ypcurrent;
+	int ypcurrentlen, r;
+	const char *name;
+	int af;
+	const char *map;
+	struct getnamaddr *info = rv;
+
+	_DIAGASSERT(rv != NULL);
+
+	name = va_arg(ap, char *);
+	/* NOSTRICT skip string len */(void)va_arg(ap, int);
+	af = va_arg(ap, int);
+
+	if (!__ypdomain) {
+		if (_yp_check(&__ypdomain) == 0)
+			return NS_UNAVAIL;
+	}
+	switch (af) {
+	case AF_INET:
+		map = "hosts.byname";
+		break;
+	default:
+		map = "ipnodes.byname";
+		break;
+	}
+	ypcurrent = NULL;
+	r = yp_match(__ypdomain, map, name,
+		(int)strlen(name), &ypcurrent, &ypcurrentlen);
+	if (r == 0)
+		hp = _yp_hostent(ypcurrent, af, info);
+	else
+		hp = NULL;
+	free(ypcurrent);
+	if (hp == NULL) {
+		*info->he = HOST_NOT_FOUND;
+		return NS_NOTFOUND;
+	}
+	return NS_SUCCESS;
+}
+#endif
+
+/*
+ * Non-reentrant versions.
+ */
+
+struct hostent *
+gethostbyname(const char *name)
+{
+	struct hostent *result = NULL;
+	res_static rs = __res_get_static(); /* Use res_static to provide thread-safety. */
+
+	gethostbyname_r(name, &rs->host, rs->hostbuf, sizeof(rs->hostbuf), &result, &h_errno);
+	return result;
+}
+
+struct hostent *
+gethostbyname2(const char *name, int af)
+{
+	struct hostent *result = NULL;
+	res_static rs = __res_get_static(); /* Use res_static to provide thread-safety. */
+
+	gethostbyname2_r(name, af, &rs->host, rs->hostbuf, sizeof(rs->hostbuf), &result, &h_errno);
+	return result;
+}
+
+struct hostent *
+android_gethostbynamefornet(const char *name, int af, unsigned netid, unsigned mark)
+{
+	struct hostent *hp;
+	res_state res = __res_get_state();
+	if (res == NULL)
+		return NULL;
+	res_static rs = __res_get_static(); /* Use res_static to provide thread-safety. */
+	hp = gethostbyname_internal(name, af, res, &rs->host, rs->hostbuf, sizeof(rs->hostbuf),
+	                            &h_errno, netid, mark);
+	__res_put_state(res);
+	return hp;
+}
+
+struct hostent *
+gethostbyaddr(const void *addr, socklen_t len, int af)
+{
+	return android_gethostbyaddrfornet_proxy(addr, len, af, NETID_UNSET, MARK_UNSET);
+}
+
+struct hostent *
+android_gethostbyaddrfornet(const void *addr, socklen_t len, int af, unsigned netid, unsigned mark)
+{
+	return android_gethostbyaddrfornet_proxy(addr, len, af, netid, mark);
+}
+
+__LIBC_HIDDEN__ struct hostent*
+android_gethostbyaddrfornet_proxy(const void* addr, socklen_t len, int af,
+                                  unsigned netid, unsigned mark)
+{
+	res_static rs = __res_get_static(); /* Use res_static to provide thread-safety. */
+	return android_gethostbyaddrfornet_proxy_internal(addr, len, af, &rs->host, rs->hostbuf,
+                                                    sizeof(rs->hostbuf), &h_errno, netid, mark);
+}
+
+struct hostent *
+gethostent(void)
+{
+  res_static  rs = __res_get_static();
+	if (!rs->hostf) {
+	  sethostent_r(&rs->hostf);
+	  if (!rs->hostf) {
+	    h_errno = NETDB_INTERNAL;
+	    return NULL;
+	  }
+	}
+	memset(&rs->host, 0, sizeof(rs->host));
+	return netbsd_gethostent_r(rs->hostf, &rs->host, rs->hostbuf, sizeof(rs->hostbuf), &h_errno);
 }
diff --git a/libc/dns/include/hostent.h b/libc/dns/include/hostent.h
new file mode 100644
index 0000000..8b9a637
--- /dev/null
+++ b/libc/dns/include/hostent.h
@@ -0,0 +1,93 @@
+/*	$NetBSD: hostent.h,v 1.2 2013/08/27 09:56:12 christos Exp $	*/
+
+/*-
+ * Copyright (c) 2013 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Christos Zoulas.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT 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.
+ */
+#ifndef _DNS_NET_HOSTENT_H
+#define _DNS_NET_HOSTENT_H
+
+#include <stdio.h>
+#include <netdb.h>
+#include <stdarg.h>
+
+/*
+ * These are not being advertised because the interfaces are non-standard.
+ * There are versions by linux, aix, qnx, sun, etc. Our versions are used
+ * internally to provide thread safety; they mostly resemble qnx.
+ */
+void sethostent_r(FILE **);
+struct hostent	*netbsd_gethostent_r(FILE *, struct hostent *, char *, size_t, int *);
+void endhostent_r(FILE **);
+
+/*
+ * The following are internal API's and are used only for testing.
+ */
+struct getnamaddr {
+	struct hostent *hp;
+	char *buf;
+	size_t buflen;
+	int *he;
+};
+
+/* /etc/hosts lookup */
+int _hf_gethtbyaddr(void *, void *, va_list);
+int _hf_gethtbyname(void *, void *, va_list);
+
+#ifdef YP
+/* NIS lookup */
+int _yp_gethtbyaddr(void *, void *, va_list);
+int _yp_gethtbyname(void *, void *, va_list);
+#endif
+
+#define HENT_ARRAY(dst, anum, ptr, len) \
+	do { \
+		size_t _len = (anum + 1) * sizeof(*dst); \
+		if (_len > len) \
+			goto nospc; \
+		dst = (void *)ptr; \
+		ptr += _len; \
+		len -= _len; \
+	} while (/*CONSTCOND*/0)
+
+#define HENT_COPY(dst, src, slen, ptr, len) \
+	do { \
+		if ((size_t)slen > len) \
+			goto nospc; \
+		memcpy(ptr, src, (size_t)slen); \
+		dst = ptr; \
+		ptr += slen; \
+		len -= slen; \
+	} while (/* CONSTCOND */0)
+
+#define HENT_SCOPY(dst, src, ptr, len) \
+	do { \
+		size_t _len = strlen(src) + 1; \
+		HENT_COPY(dst, src, _len, ptr, len); \
+	} while (/* CONSTCOND */0)
+
+#endif /* _DNS_NET_HOSTENT_H */
diff --git a/libc/dns/net/sethostent.c b/libc/dns/net/sethostent.c
new file mode 100644
index 0000000..f501c8b
--- /dev/null
+++ b/libc/dns/net/sethostent.c
@@ -0,0 +1,266 @@
+/*	$NetBSD: sethostent.c,v 1.20 2014/03/17 13:24:23 christos Exp $	*/
+
+/*
+ * Copyright (c) 1985, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 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. Neither the name of the University 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
+ * 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
+ * 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)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+#if defined(LIBC_SCCS) && !defined(lint)
+#if 0
+static char sccsid[] = "@(#)sethostent.c	8.1 (Berkeley) 6/4/93";
+static char rcsid[] = "Id: sethostent.c,v 8.5 1996/09/28 06:51:07 vixie Exp ";
+#else
+__RCSID("$NetBSD: sethostent.c,v 1.20 2014/03/17 13:24:23 christos Exp $");
+#endif
+#endif /* LIBC_SCCS and not lint */
+
+#include "namespace.h"
+#include <sys/param.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+#include <assert.h>
+#include <string.h>
+#include <nsswitch.h>
+#include <netdb.h>
+#include <resolv.h>
+#include <errno.h>
+#include <stdlib.h>
+
+#include "hostent.h"
+#include "resolv_private.h"
+
+#define ALIGNBYTES (sizeof(uintptr_t) - 1)
+#define ALIGN(p) (((uintptr_t)(p) + ALIGNBYTES) &~ ALIGNBYTES)
+
+#ifndef _REENTRANT
+void	res_close(void);
+#endif
+
+static struct hostent *_hf_gethtbyname2(const char *, int, struct getnamaddr *);
+
+static const char *_h_hosts = _PATH_HOSTS;
+
+void
+sethostent_r(FILE **hf)
+{
+	if (!*hf)
+		*hf = fopen(_h_hosts, "re");
+	else
+		rewind(*hf);
+}
+
+void
+endhostent_r(FILE **hf)
+{
+	if (*hf) {
+		(void)fclose(*hf);
+		*hf = NULL;
+	}
+}
+
+/*ARGSUSED*/
+int
+_hf_gethtbyname(void *rv, void *cb_data, va_list ap)
+{
+	struct hostent *hp;
+	const char *name;
+	int af;
+	struct getnamaddr *info = rv;
+
+	_DIAGASSERT(rv != NULL);
+
+	name = va_arg(ap, char *);
+	/* NOSTRICT skip string len */(void)va_arg(ap, int);
+	af = va_arg(ap, int);
+
+#if 0
+	{
+		res_state res = __res_get_state();
+		if (res == NULL)
+			return NS_NOTFOUND;
+		if (res->options & RES_USE_INET6)
+			hp = _hf_gethtbyname2(name, AF_INET6, info);
+		else
+			hp = NULL;
+		if (hp == NULL)
+			hp = _hf_gethtbyname2(name, AF_INET, info);
+		__res_put_state(res);
+	}
+#else
+	hp = _hf_gethtbyname2(name, af, info);
+#endif
+	if (hp == NULL) {
+		*info->he = HOST_NOT_FOUND;
+		return NS_NOTFOUND;
+	}
+	return NS_SUCCESS;
+}
+
+static struct hostent *
+_hf_gethtbyname2(const char *name, int af, struct getnamaddr *info)
+{
+	struct hostent *hp, hent;
+	char *buf, *ptr;
+	size_t len, anum, num, i;
+	FILE *hf;
+	char *aliases[MAXALIASES];
+	char *addr_ptrs[MAXADDRS];
+
+	_DIAGASSERT(name != NULL);
+
+	hf = NULL;
+	sethostent_r(&hf);
+	if (hf == NULL) {
+		errno = EINVAL;
+		*info->he = NETDB_INTERNAL;
+		return NULL;
+	}
+
+	if ((ptr = buf = malloc(len = info->buflen)) == NULL) {
+		endhostent_r(&hf);
+		*info->he = NETDB_INTERNAL;
+		return NULL;
+	}
+
+	anum = 0;		/* XXX: gcc */
+	hent.h_name = NULL;	/* XXX: gcc */
+	hent.h_addrtype = 0;	/* XXX: gcc */
+	hent.h_length = 0;	/* XXX: gcc */
+
+	for (num = 0; num < MAXADDRS;) {
+		info->hp->h_addrtype = af;
+		info->hp->h_length = 0;
+
+		hp = netbsd_gethostent_r(hf, info->hp, info->buf, info->buflen,
+		    info->he);
+		if (hp == NULL)
+			break;
+
+		if (strcasecmp(hp->h_name, name) != 0) {
+			char **cp;
+			for (cp = hp->h_aliases; *cp != NULL; cp++)
+				if (strcasecmp(*cp, name) == 0)
+					break;
+			if (*cp == NULL) continue;
+		}
+
+		if (num == 0) {
+			hent.h_addrtype = af = hp->h_addrtype;
+			hent.h_length = hp->h_length;
+
+			HENT_SCOPY(hent.h_name, hp->h_name, ptr, len);
+			for (anum = 0; hp->h_aliases[anum]; anum++) {
+				if (anum >= MAXALIASES)
+					goto nospc;
+				HENT_SCOPY(aliases[anum], hp->h_aliases[anum],
+				    ptr, len);
+			}
+			ptr = (void *)ALIGN(ptr);
+			if ((size_t)(ptr - buf) >= info->buflen)
+				goto nospc;
+		}
+
+		if (num >= MAXADDRS)
+			goto nospc;
+		HENT_COPY(addr_ptrs[num], hp->h_addr_list[0], hp->h_length, ptr,
+		    len);
+		num++;
+	}
+	endhostent_r(&hf);
+
+	if (num == 0) {
+		*info->he = HOST_NOT_FOUND;
+		free(buf);
+		return NULL;
+	}
+
+	hp = info->hp;
+	ptr = info->buf;
+	len = info->buflen;
+
+	hp->h_addrtype = hent.h_addrtype;
+	hp->h_length = hent.h_length;
+
+	HENT_ARRAY(hp->h_aliases, anum, ptr, len);
+	HENT_ARRAY(hp->h_addr_list, num, ptr, len);
+
+	for (i = 0; i < num; i++)
+		HENT_COPY(hp->h_addr_list[i], addr_ptrs[i], hp->h_length, ptr,
+		    len);
+	hp->h_addr_list[num] = NULL;
+
+	HENT_SCOPY(hp->h_name, hent.h_name, ptr, len);
+
+	for (i = 0; i < anum; i++)
+		HENT_SCOPY(hp->h_aliases[i], aliases[i], ptr, len);
+	hp->h_aliases[anum] = NULL;
+
+	free(buf);
+	return hp;
+nospc:
+	endhostent_r(&hf);
+	*info->he = NETDB_INTERNAL;
+	free(buf);
+	errno = ENOSPC;
+	return NULL;
+}
+
+/*ARGSUSED*/
+int
+_hf_gethtbyaddr(void *rv, void *cb_data, va_list ap)
+{
+	struct hostent *hp;
+	const unsigned char *addr;
+	struct getnamaddr *info = rv;
+	FILE *hf;
+
+	_DIAGASSERT(rv != NULL);
+
+	addr = va_arg(ap, unsigned char *);
+	info->hp->h_length = va_arg(ap, int);
+	info->hp->h_addrtype = va_arg(ap, int);
+
+	hf = NULL;
+	sethostent_r(&hf);
+	if (hf == NULL) {
+		*info->he = NETDB_INTERNAL;
+		return NS_UNAVAIL;
+	}
+	while ((hp = netbsd_gethostent_r(hf, info->hp, info->buf, info->buflen,
+	    info->he)) != NULL)
+		if (!memcmp(hp->h_addr_list[0], addr, (size_t)hp->h_length))
+			break;
+	endhostent_r(&hf);
+
+	if (hp == NULL) {
+		*info->he = HOST_NOT_FOUND;
+		return NS_NOTFOUND;
+	}
+	return NS_SUCCESS;
+}
diff --git a/libc/include/netdb.h b/libc/include/netdb.h
index 527d5c1..e165376 100644
--- a/libc/include/netdb.h
+++ b/libc/include/netdb.h
@@ -209,7 +209,7 @@
 void endservent(void);
 void freehostent(struct hostent *);
 struct hostent	*gethostbyaddr(const void *, socklen_t, int);
-int gethostbyaddr_r(const void *, int, int, struct hostent *, char *, size_t, struct hostent **, int *);
+int gethostbyaddr_r(const void *, socklen_t, int, struct hostent *, char *, size_t, struct hostent **, int *);
 struct hostent	*gethostbyname(const char *);
 int gethostbyname_r(const char *, struct hostent *, char *, size_t, struct hostent **, int *);
 struct hostent	*gethostbyname2(const char *, int);
diff --git a/tests/netdb_test.cpp b/tests/netdb_test.cpp
index 0cebe4e..ab5b487 100644
--- a/tests/netdb_test.cpp
+++ b/tests/netdb_test.cpp
@@ -14,11 +14,13 @@
  * limitations under the License.
  */
 
+#include <netdb.h>
+
 #include <gtest/gtest.h>
 
+#include <arpa/inet.h>
 #include <sys/types.h>
 #include <sys/socket.h>
-#include <netdb.h>
 #include <netinet/in.h>
 
 TEST(netdb, getaddrinfo_NULL_host) {
@@ -114,8 +116,7 @@
   ASSERT_EQ(EAI_FAMILY, getnameinfo(sa, too_little, tmp, sizeof(tmp), NULL, 0, NI_NUMERICHOST));
 }
 
-TEST(netdb, gethostbyname) {
-  hostent* hent = gethostbyname("localhost");
+void VerifyLocalhost(hostent *hent) {
   ASSERT_TRUE(hent != NULL);
   ASSERT_EQ(hent->h_addrtype, AF_INET);
   ASSERT_EQ(hent->h_addr[0], 127);
@@ -124,6 +125,125 @@
   ASSERT_EQ(hent->h_addr[3], 1);
 }
 
+TEST(netdb, gethostbyname) {
+  hostent* hp = gethostbyname("localhost");
+  VerifyLocalhost(hp);
+}
+
+TEST(netdb, gethostbyname2) {
+  hostent* hp = gethostbyname2("localhost", AF_INET);
+  VerifyLocalhost(hp);
+}
+
+TEST(netdb, gethostbyname_r) {
+  hostent hent;
+  hostent *hp;
+  char buf[512];
+  int err;
+  int result = gethostbyname_r("localhost", &hent, buf, sizeof(buf), &hp, &err);
+  ASSERT_EQ(0, result);
+  VerifyLocalhost(hp);
+
+  // Change hp->h_addr to test reentrancy.
+  hp->h_addr[0] = 0;
+
+  hostent hent2;
+  hostent *hp2;
+  char buf2[512];
+  result = gethostbyname_r("localhost", &hent2, buf2, sizeof(buf2), &hp2, &err);
+  ASSERT_EQ(0, result);
+  VerifyLocalhost(hp2);
+
+  ASSERT_EQ(0, hp->h_addr[0]);
+}
+
+TEST(netdb, gethostbyname2_r) {
+  hostent hent;
+  hostent *hp;
+  char buf[512];
+  int err;
+  int result = gethostbyname2_r("localhost", AF_INET, &hent, buf, sizeof(buf), &hp, &err);
+  ASSERT_EQ(0, result);
+  VerifyLocalhost(hp);
+
+  // Change hp->h_addr to test reentrancy.
+  hp->h_addr[0] = 0;
+
+  hostent hent2;
+  hostent *hp2;
+  char buf2[512];
+  result = gethostbyname2_r("localhost", AF_INET, &hent2, buf2, sizeof(buf2), &hp2, &err);
+  ASSERT_EQ(0, result);
+  VerifyLocalhost(hp2);
+
+  ASSERT_EQ(0, hp->h_addr[0]);
+}
+
+TEST(netdb, gethostbyaddr) {
+  char addr[4];
+  ASSERT_EQ(1, inet_pton(AF_INET, "127.0.0.1", addr));
+  hostent *hp = gethostbyaddr(addr, sizeof(addr), AF_INET);
+  VerifyLocalhost(hp);
+}
+
+TEST(netdb, gethostbyaddr_r) {
+  char addr[4];
+  ASSERT_EQ(1, inet_pton(AF_INET, "127.0.0.1", addr));
+
+  hostent hent;
+  hostent *hp;
+  char buf[512];
+  int err;
+  int result = gethostbyaddr_r(addr, sizeof(addr), AF_INET, &hent, buf, sizeof(buf), &hp, &err);
+  ASSERT_EQ(0, result);
+  VerifyLocalhost(hp);
+
+  // Change hp->h_addr to test reentrancy.
+  hp->h_addr[0] = 0;
+
+  hostent hent2;
+  hostent *hp2;
+  char buf2[512];
+  result = gethostbyaddr_r(addr, sizeof(addr), AF_INET, &hent2, buf2, sizeof(buf2), &hp2, &err);
+  ASSERT_EQ(0, result);
+  VerifyLocalhost(hp2);
+
+  ASSERT_EQ(0, hp->h_addr[0]);
+}
+
+TEST(netdb, gethostbyname_r_ERANGE) {
+  hostent hent;
+  hostent *hp;
+  char buf[4]; // Use too small buffer.
+  int err;
+  int result = gethostbyname_r("localhost", &hent, buf, sizeof(buf), &hp, &err);
+  ASSERT_EQ(ERANGE, result);
+  ASSERT_EQ(NULL, hp);
+}
+
+TEST(netdb, gethostbyname2_r_ERANGE) {
+  hostent hent;
+  hostent *hp;
+  char buf[4]; // Use too small buffer.
+  int err;
+  int result = gethostbyname2_r("localhost", AF_INET, &hent, buf, sizeof(buf), &hp, &err);
+  ASSERT_EQ(ERANGE, result);
+  ASSERT_EQ(NULL, hp);
+}
+
+TEST(netdb, gethostbyaddr_r_ERANGE) {
+  char addr[4];
+  ASSERT_EQ(1, inet_pton(AF_INET, "127.0.0.1", addr));
+
+  hostent hent;
+  hostent *hp;
+  char buf[4]; // Use too small buffer.
+  int err;
+  int result = gethostbyaddr_r(addr, sizeof(addr), AF_INET, &hent, buf, sizeof(buf), &hp, &err);
+  ASSERT_EQ(ERANGE, result);
+  ASSERT_EQ(NULL, hp);
+}
+
 TEST(netdb, getservbyname) {
   // smtp is TCP-only, so we know we'll get 25/tcp back.
   servent* s = getservbyname("smtp", NULL);