am a4723742: am 261e9d08: am e4ca88d9: Merge "Add functionlity to the scripts to replace tokens in kernel headers based on architecture."

* commit 'a4723742c1ee0daa2ec17a148334c548b5edf3a8':
  Add functionlity to the scripts to replace tokens in kernel headers based on architecture.
diff --git a/libc/Android.mk b/libc/Android.mk
index c98d2ff..4bf996b 100644
--- a/libc/Android.mk
+++ b/libc/Android.mk
@@ -805,6 +805,9 @@
 LOCAL_WHOLE_STATIC_LIBRARIES := libbionic_ssp libc_bionic libc_netbsd
 LOCAL_SYSTEM_SHARED_LIBRARIES :=
 
+# TODO: split out the asflags.
+LOCAL_ASFLAGS := $(LOCAL_CFLAGS)
+
 include $(BUILD_STATIC_LIBRARY)
 
 
diff --git a/libc/docs/OVERVIEW.TXT b/libc/docs/OVERVIEW.TXT
index 753e48a..a0a3493 100644
--- a/libc/docs/OVERVIEW.TXT
+++ b/libc/docs/OVERVIEW.TXT
@@ -282,16 +282,9 @@
 
      - read /system/etc/resolv.conf instead of /etc/resolv.conf
 
-     - read the list of servers from system properties. the code looks for
-       'net.dns1', 'net.dns2', etc.. Each property should contain the IP
-       address of a DNS server.
-
-       these properties are set/modified by other parts of the Android system
-       (e.g. the dhcpd daemon).
-
-       the implementation also supports per-process DNS server list, using the
-       properties 'net.dns1.<pid>', 'net.dns2.<pid>', etc... Where <pid> stands
-       for the numerical ID of the current process.
+     - get the list of servers and the search domains for this process's
+       current interface from the dns cache.  This information is sent
+       from the framework via cache functions.
 
      - when performing a query, use a properly randomized Query ID (instead of
        a incremented one), for increased security.
diff --git a/libc/include/netdb.h b/libc/include/netdb.h
index ead5954..3ea512c 100644
--- a/libc/include/netdb.h
+++ b/libc/include/netdb.h
@@ -207,11 +207,13 @@
 void endservent(void);
 void freehostent(struct hostent *);
 struct hostent	*gethostbyaddr(const void *, socklen_t, int);
+struct hostent	*android_gethostbyaddrforiface(const void *, socklen_t, int, const char*);
 int gethostbyaddr_r(const void *, int, 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);
 int gethostbyname2_r(const char *, int, struct hostent *, char *, size_t, struct hostent **, int *);
+struct hostent	*android_gethostbynameforiface(const char *, int, const char *);
 struct hostent	*gethostent(void);
 int gethostent_r(struct hostent *, char *, size_t, struct hostent **, int *);
 struct hostent	*getipnodebyaddr(const void *, size_t, int, int *);
@@ -239,7 +241,9 @@
 void setnetent(int);
 void setprotoent(int);
 int getaddrinfo(const char *, const char *, const struct addrinfo *, struct addrinfo **);
+int android_getaddrinfoforiface(const char *, const char *, const struct addrinfo *, const char *, struct addrinfo **);
 int getnameinfo(const struct sockaddr *, socklen_t, char *, size_t, char *, size_t, int);
+int android_getnameinfoforiface(const struct sockaddr *, socklen_t, char *, size_t, char *, size_t, int, const char *);
 void freeaddrinfo(struct addrinfo *);
 const char	*gai_strerror(int);
 void setnetgrent(const char *);
diff --git a/libc/netbsd/gethnamaddr.c b/libc/netbsd/gethnamaddr.c
index 9a9f6e2..c59d1f1 100644
--- a/libc/netbsd/gethnamaddr.c
+++ b/libc/netbsd/gethnamaddr.c
@@ -56,6 +56,7 @@
 
 #include <sys/param.h>
 #include <sys/socket.h>
+#include <sys/un.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
 #include "arpa_nameser.h"
@@ -69,6 +70,7 @@
 #include <stdio.h>
 #include <strings.h>
 #include <syslog.h>
+#include <unistd.h>
 
 #ifndef LOG_AUTH
 # define LOG_AUTH 0
@@ -80,6 +82,9 @@
 #include <stdlib.h>
 #include <string.h>
 
+// This should be synchronized to ResponseCode.h
+static const int DnsProxyQueryResult = 222;
+
 static const char const AskedForGot[] =
 			  "gethostby*.getanswer: asked for \"%s\", got \"%s\"";
 
@@ -121,7 +126,7 @@
 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);
+static struct hostent *gethostbyname_internal(const char *, int, res_state, const char *);
 
 static const ns_src default_dns_files[] = {
 	{ NSSRC_FILES, 	NS_SUCCESS },
@@ -490,14 +495,15 @@
 
 	assert(name != NULL);
 
+	/* try IPv6 first - if that fails do IPv4 */
 	if (res->options & RES_USE_INET6) {
-		hp = gethostbyname_internal(name, AF_INET6, res);
+		hp = gethostbyname_internal(name, AF_INET6, res, NULL);
 		if (hp) {
 			__res_put_state(res);
 			return hp;
 		}
 	}
-	hp = gethostbyname_internal(name, AF_INET, res);
+	hp = gethostbyname_internal(name, AF_INET, res, NULL);
 	__res_put_state(res);
 	return hp;
 }
@@ -505,25 +511,145 @@
 struct hostent *
 gethostbyname2(const char *name, int af)
 {
+	return android_gethostbynameforiface(name, af, NULL);
+}
+
+struct hostent *
+android_gethostbynameforiface(const char *name, int af, const char *iface)
+{
 	struct hostent *hp;
 	res_state res = __res_get_state();
 
 	if (res == NULL)
 		return NULL;
-	hp = gethostbyname_internal(name, af, res);
+	hp = gethostbyname_internal(name, af, res, iface);
 	__res_put_state(res);
 	return hp;
 }
 
+static struct hostent *gethostbyname_internal_real(const char *name, int af, res_state res);
+
+// very similar in proxy-ness to android_getaddrinfo_proxy
 static struct hostent *
-gethostbyname_internal(const char *name, int af, res_state res)
+gethostbyname_internal(const char *name, int af, res_state res, const char *iface)
+{
+	int sock;
+	const int one = 1;
+	struct sockaddr_un proxy_addr;
+	const char *cache_mode = getenv("ANDROID_DNS_MODE");
+	FILE* proxy = NULL;
+
+	if (cache_mode != NULL && strcmp(cache_mode, "local") == 0) {
+		res_setiface(res, iface);
+		return gethostbyname_internal_real(name, af, res);
+	}
+
+	sock = socket(AF_UNIX, SOCK_STREAM, 0);
+	if (sock < 0) {
+		return NULL;
+	}
+
+	setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
+	memset(&proxy_addr, 0, sizeof(proxy_addr));
+	proxy_addr.sun_family = AF_UNIX;
+	strlcpy(proxy_addr.sun_path, "/dev/socket/dnsproxyd", sizeof(proxy_addr.sun_path));
+	if (TEMP_FAILURE_RETRY(connect(sock,
+				       (const struct sockaddr*) &proxy_addr,
+				       sizeof(proxy_addr))) != 0) {
+		close(sock);
+		return NULL;
+	}
+
+	proxy = fdopen(sock, "r+");
+	/* This is writing to system/netd/DnsProxyListener.cpp and changes
+	 * here need to be matched there */
+	if (fprintf(proxy, "gethostbyname %d %s %d",
+		    getpid(),
+		    iface == NULL ? "^" : iface,
+		    name == NULL ? "^" : name,
+		    af) < 0) {
+		goto exit;
+	}
+
+	if (fputc(0, proxy) == EOF || fflush(proxy) != 0) {
+		goto exit;
+	}
+
+	uint32_t size;
+	char *buf = (char *)&size;
+	if (fread(buf, 1, sizeof(size), proxy) != 1) {
+		goto exit;
+	}
+
+	/* This is reading serialized data from system/netd/DnsProxyListener.cpp
+	 * and changes here need to be matched there */
+	int result_code = (int)strtol(buf, NULL, 10);
+	if (result_code != DnsProxyQueryResult) goto exit;
+
+	if (fread(buf, 1, sizeof(size), proxy) != 1) goto exit;
+	size = ntohl(size);
+
+	res_static rs = __res_get_static();
+	memset(&rs->host, 0, sizeof(rs->host));
+	char *ptr = rs->hostbuf;
+
+	if (fread(ptr, 1, size, proxy) != 1) goto exit;
+	ptr += size;
+	rs->host.h_name = rs->hostbuf;
+
+	char **aliases = rs->host_aliases;
+	rs->host.h_aliases = rs->host_aliases;
+	while (1) {
+		if (fread(buf, 1, sizeof(size), proxy) != 1) goto exit;
+		size = ntohl(size);
+		if (fread(ptr, 1, size, proxy) != 1) goto exit;
+		if (size == 1) {
+			*aliases = NULL;
+			break;
+		}
+		*aliases++ = ptr;
+		ptr += size;
+	}
+
+	if (fread(buf, 1, sizeof(size), proxy) != 1) goto exit;
+	rs->host.h_addrtype = ntohl(size);
+
+	if (fread(buf, 1, sizeof(size), proxy) != 1) goto exit;
+	rs->host.h_length = ntohl(size);
+
+	char **addrs = rs->h_addr_ptrs;
+	rs->host.h_addr_list = rs->h_addr_ptrs;
+	while (1) {
+		if (fread(buf, 1, sizeof(size), proxy) != 1) goto exit;
+		size = ntohl(size);
+		if (fread(ptr, 1, size, proxy) != 1) goto exit;
+		if (size == 1) {
+		    *addrs = NULL;
+		    break;
+		}
+		*addrs++ = ptr;
+		ptr += size;
+	}
+
+	fclose(proxy);
+	return &rs->host;
+
+exit:
+	if (proxy != NULL) {
+		fclose(proxy);
+	}
+	return NULL;
+}
+
+
+static struct hostent *
+gethostbyname_internal_real(const char *name, int af, res_state res)
 {
 	const char *cp;
 	char *bp, *ep;
 	int size;
 	struct hostent *hp;
-        struct resolv_cache*  cache;
-        res_static  rs = __res_get_static();
+	res_static rs = __res_get_static();
 
 	static const ns_dtab dtab[] = {
 		NS_FILES_CB(_gethtbyname, NULL)
@@ -641,6 +767,13 @@
 gethostbyaddr(const void *addr,
     socklen_t len, int af)
 {
+	return android_gethostbyaddrforiface(addr, len, af, NULL);
+}
+
+struct hostent *
+android_gethostbyaddrforiface(const void *addr,
+    socklen_t len, int af, const char* iface)
+{
 	const u_char *uaddr = (const u_char *)addr;
 	socklen_t size;
 	struct hostent *hp;
@@ -687,7 +820,7 @@
 	hp = NULL;
 	h_errno = NETDB_INTERNAL;
 	if (nsdispatch(&hp, dtab, NSDB_HOSTS, "gethostbyaddr",
-	    default_dns_files, uaddr, len, af) != NS_SUCCESS)
+	    default_dns_files, uaddr, len, af, iface) != NS_SUCCESS)
 		return NULL;
 	h_errno = NETDB_SUCCESS;
 	return hp;
@@ -1124,6 +1257,7 @@
 	const unsigned char *uaddr;
 	int len, af, advance;
 	res_state res;
+	const char* iface;
 	res_static rs = __res_get_static();
 
 	assert(rv != NULL);
@@ -1131,6 +1265,7 @@
 	uaddr = va_arg(ap, unsigned char *);
 	len = va_arg(ap, int);
 	af = va_arg(ap, int);
+	iface = va_arg(ap, char *);
 
 	switch (af) {
 	case AF_INET:
@@ -1172,6 +1307,8 @@
 		free(buf);
 		return NS_NOTFOUND;
 	}
+	res_setiface(res, iface);
+	_resolv_populate_res_for_iface(res);
 	n = res_nquery(res, qbuf, C_IN, T_PTR, buf->buf, sizeof(buf->buf));
 	if (n < 0) {
 		free(buf);
diff --git a/libc/netbsd/net/getaddrinfo.c b/libc/netbsd/net/getaddrinfo.c
index 326b09c..4e23132 100644
--- a/libc/netbsd/net/getaddrinfo.c
+++ b/libc/netbsd/net/getaddrinfo.c
@@ -214,7 +214,7 @@
 
 static int str2number(const char *);
 static int explore_fqdn(const struct addrinfo *, const char *,
-	const char *, struct addrinfo **);
+	const char *, struct addrinfo **, const char *iface);
 static int explore_null(const struct addrinfo *,
 	const char *, struct addrinfo **);
 static int explore_numeric(const struct addrinfo *, const char *,
@@ -402,17 +402,15 @@
         return _test_connect(PF_INET, &addr.generic, sizeof(addr.in));
 }
 
-// Returns 0 on success, else returns non-zero on error (in which case
-// getaddrinfo should continue as normal)
+// Returns 0 on success, else returns on error.
 static int
 android_getaddrinfo_proxy(
     const char *hostname, const char *servname,
-    const struct addrinfo *hints, struct addrinfo **res)
+    const struct addrinfo *hints, struct addrinfo **res, const char *iface)
 {
 	int sock;
 	const int one = 1;
 	struct sockaddr_un proxy_addr;
-	const char* cache_mode = getenv("ANDROID_DNS_MODE");
 	FILE* proxy = NULL;
 	int success = 0;
 
@@ -421,33 +419,17 @@
 	// allocated in the process (before failing).
 	*res = NULL;
 
-	if (cache_mode != NULL && strcmp(cache_mode, "local") == 0) {
-		// Don't use the proxy in local mode.  This is used by the
-		// proxy itself.
-		return -1;
-	}
-
-	// Temporary cautious hack to disable the DNS proxy for processes
-	// requesting special treatment.  Ideally the DNS proxy should
-	// accomodate these apps, though.
-	char propname[PROP_NAME_MAX];
-	char propvalue[PROP_VALUE_MAX];
-	snprintf(propname, sizeof(propname), "net.dns1.%d", getpid());
-	if (__system_property_get(propname, propvalue) > 0) {
-		return -1;
-	}
-
-	// Bogus things we can't serialize.  Don't use the proxy.
+	// Bogus things we can't serialize.  Don't use the proxy.  These will fail - let them.
 	if ((hostname != NULL &&
 	     strcspn(hostname, " \n\r\t^'\"") != strlen(hostname)) ||
 	    (servname != NULL &&
 	     strcspn(servname, " \n\r\t^'\"") != strlen(servname))) {
-		return -1;
+		return EAI_NODATA;
 	}
 
 	sock = socket(AF_UNIX, SOCK_STREAM, 0);
 	if (sock < 0) {
-		return -1;
+		return EAI_NODATA;
 	}
 
 	setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
@@ -459,18 +441,20 @@
 				       (const struct sockaddr*) &proxy_addr,
 				       sizeof(proxy_addr))) != 0) {
 		close(sock);
-		return -1;
+		return EAI_NODATA;
 	}
 
 	// Send the request.
 	proxy = fdopen(sock, "r+");
-	if (fprintf(proxy, "getaddrinfo %s %s %d %d %d %d",
+	if (fprintf(proxy, "getaddrinfo %s %s %d %d %d %d %s %d",
 		    hostname == NULL ? "^" : hostname,
 		    servname == NULL ? "^" : servname,
 		    hints == NULL ? -1 : hints->ai_flags,
 		    hints == NULL ? -1 : hints->ai_family,
 		    hints == NULL ? -1 : hints->ai_socktype,
-		    hints == NULL ? -1 : hints->ai_protocol) < 0) {
+		    hints == NULL ? -1 : hints->ai_protocol,
+		    iface == NULL ? "^" : iface,
+		    getpid()) < 0) {
 		goto exit;
 	}
 	// literal NULL byte at end, required by FrameworkListener
@@ -580,20 +564,26 @@
 		return 0;
 	}
 
-	// Proxy failed; fall through to local
-	// resolver case.  But first clean up any
-	// memory we might've allocated.
+	// Proxy failed;
+	// clean up memory we might've allocated.
 	if (*res) {
 		freeaddrinfo(*res);
 		*res = NULL;
 	}
-	return -1;
+	return EAI_NODATA;
 }
 
 int
 getaddrinfo(const char *hostname, const char *servname,
     const struct addrinfo *hints, struct addrinfo **res)
 {
+	return android_getaddrinfoforiface(hostname, servname, hints, NULL, res);
+}
+
+int
+android_getaddrinfoforiface(const char *hostname, const char *servname,
+    const struct addrinfo *hints, const char *iface, struct addrinfo **res)
+{
 	struct addrinfo sentinel;
 	struct addrinfo *cur;
 	int error = 0;
@@ -601,12 +591,12 @@
 	struct addrinfo ai0;
 	struct addrinfo *pai;
 	const struct explore *ex;
+	const char* cache_mode = getenv("ANDROID_DNS_MODE");
 
 	/* hostname is allowed to be NULL */
 	/* servname is allowed to be NULL */
 	/* hints is allowed to be NULL */
 	assert(res != NULL);
-
 	memset(&sentinel, 0, sizeof(sentinel));
 	cur = &sentinel;
 	pai = &ai;
@@ -739,9 +729,10 @@
         /*
          * BEGIN ANDROID CHANGES; proxying to the cache
          */
-        if (android_getaddrinfo_proxy(hostname, servname, hints, res) == 0) {
-            return 0;
-        }
+	if (cache_mode == NULL || strcmp(cache_mode, "local") != 0) {
+		// we're not the proxy - pass the request to them
+		return android_getaddrinfo_proxy(hostname, servname, hints, res, iface);
+	}
 
 	/*
 	 * hostname as alphabetical name.
@@ -770,7 +761,7 @@
 			pai->ai_protocol = ex->e_protocol;
 
 		error = explore_fqdn(pai, hostname, servname,
-			&cur->ai_next);
+			&cur->ai_next, iface);
 
 		while (cur && cur->ai_next)
 			cur = cur->ai_next;
@@ -803,7 +794,7 @@
  */
 static int
 explore_fqdn(const struct addrinfo *pai, const char *hostname,
-    const char *servname, struct addrinfo **res)
+    const char *servname, struct addrinfo **res, const char *iface)
 {
 	struct addrinfo *result;
 	struct addrinfo *cur;
@@ -829,7 +820,7 @@
 		return 0;
 
 	switch (nsdispatch(&result, dtab, NSDB_HOSTS, "getaddrinfo",
-			default_dns_files, hostname, pai)) {
+			default_dns_files, hostname, pai, iface)) {
 	case NS_TRYAGAIN:
 		error = EAI_AGAIN;
 		goto free;
@@ -1897,9 +1888,11 @@
 	struct addrinfo sentinel, *cur;
 	struct res_target q, q2;
 	res_state res;
+	const char* iface;
 
 	name = va_arg(ap, char *);
 	pai = va_arg(ap, const struct addrinfo *);
+	iface = va_arg(ap, char *);
 	//fprintf(stderr, "_dns_getaddrinfo() name = '%s'\n", name);
 
 	memset(&q, 0, sizeof(q));
@@ -1981,6 +1974,12 @@
 		return NS_NOTFOUND;
 	}
 
+	/* this just sets our iface val in the thread private data so we don't have to
+	 * modify the api's all the way down to res_send.c's res_nsend.  We could
+	 * fully populate the thread private data here, but if we get down there
+	 * and have a cache hit that would be wasted, so we do the rest there on miss
+	 */
+	res_setiface(res, iface);
 	if (res_searchN(name, &q, res) < 0) {
 		__res_put_state(res);
 		free(buf);
diff --git a/libc/netbsd/net/getnameinfo.c b/libc/netbsd/net/getnameinfo.c
index d8ac037..7ab48e6 100644
--- a/libc/netbsd/net/getnameinfo.c
+++ b/libc/netbsd/net/getnameinfo.c
@@ -99,7 +99,7 @@
 };
 
 static int getnameinfo_inet __P((const struct sockaddr *, socklen_t, char *,
-    socklen_t, char *, socklen_t, int));
+    socklen_t, char *, socklen_t, int, const char*));
 #ifdef INET6
 static int ip6_parsenumeric __P((const struct sockaddr *, const char *, char *,
 				 socklen_t, int));
@@ -122,28 +122,33 @@
  */
 int getnameinfo(const struct sockaddr* sa, socklen_t salen, char* host, size_t hostlen, char* serv, size_t servlen, int flags)
 {
+	return android_getnameinfoforiface(sa, salen, host, hostlen, serv, servlen, flags, NULL);
+}
+
+int android_getnameinfoforiface(const struct sockaddr* sa, socklen_t salen, char* host, size_t hostlen, char* serv, size_t servlen, int flags, const char* iface)
+{
 	switch (sa->sa_family) {
 	case AF_INET:
 	case AF_INET6:
 		return getnameinfo_inet(sa, salen, host, hostlen,
-		    serv, servlen, flags);
+				serv, servlen, flags, iface);
 #if defined(ANDROID_CHANGES) && defined(AF_LINK)
 	case AF_LINK:
 		return getnameinfo_link(sa, salen, host, hostlen,
-		    serv, servlen, flags);
+				serv, servlen, flags);
 #endif
 	default:
 		return EAI_FAMILY;
 	}
 }
-
 #ifdef ANDROID_CHANGES
 /* On success length of the host name is returned. A return
  * value of 0 means there's no host name associated with
  * the address. On failure -1 is returned in which case
  * normal execution flow shall continue. */
 static int
-android_gethostbyaddr_proxy(char* nameBuf, size_t nameBufLen, const void *addr, socklen_t addrLen, int addrFamily) {
+android_gethostbyaddr_proxy(char* nameBuf, size_t nameBufLen, const void *addr, socklen_t addrLen, int addrFamily, const char* iface)
+{
 
 	int sock;
 	const int one = 1;
@@ -158,15 +163,6 @@
 		return -1;
 	}
 
-	// Temporary cautious hack to disable the DNS proxy for processes
-	// requesting special treatment.  Ideally the DNS proxy should
-	// accomodate these apps, though.
-	char propname[PROP_NAME_MAX];
-	char propvalue[PROP_VALUE_MAX];
-	snprintf(propname, sizeof(propname), "net.dns1.%d", getpid());
-	if (__system_property_get(propname, propvalue) > 0) {
-		return -1;
-	}
 	// create socket
 	sock = socket(AF_UNIX, SOCK_STREAM, 0);
 	if (sock < 0) {
@@ -195,7 +191,8 @@
 	if (addrStr == NULL) {
 		goto exit;
 	}
-	if (fprintf(proxy, "gethostbyaddr %s %d %d", addrStr, addrLen, addrFamily) < 0) {
+	if (fprintf(proxy, "gethostbyaddr %s %d %d %d %s",
+			addrStr, addrLen, addrFamily, getpid(), iface == NULL ? "^" : iface) < 0) {
 		goto exit;
 	}
 
@@ -246,7 +243,7 @@
  * Format an IPv4 or IPv6 sockaddr into a printable string.
  */
 static int
-getnameinfo_inet(sa, salen, host, hostlen, serv, servlen, flags)
+getnameinfo_inet(sa, salen, host, hostlen, serv, servlen, flags, iface)
 	const struct sockaddr *sa;
 	socklen_t salen;
 	char *host;
@@ -254,6 +251,7 @@
 	char *serv;
 	socklen_t servlen;
 	int flags;
+	const char* iface;
 {
 	const struct afd *afd;
 	struct servent *sp;
@@ -398,14 +396,14 @@
 		char android_proxy_buf[MAXDNAME];
 
 		int hostnamelen = android_gethostbyaddr_proxy(android_proxy_buf,
-				MAXDNAME, addr, afd->a_addrlen, afd->a_af);
+				MAXDNAME, addr, afd->a_addrlen, afd->a_af, iface);
 		if (hostnamelen > 0) {
 			hp = &android_proxy_hostent;
 			hp->h_name = android_proxy_buf;
 		} else if (!hostnamelen) {
 			hp = NULL;
 		} else {
-			hp = gethostbyaddr(addr, afd->a_addrlen, afd->a_af);
+			hp = android_gethostbyaddrforiface(addr, afd->a_addrlen, afd->a_af, iface);
 		}
 #else
 		hp = gethostbyaddr(addr, afd->a_addrlen, afd->a_af);
diff --git a/libc/netbsd/resolv/res_cache.c b/libc/netbsd/resolv/res_cache.c
index 838e084..23f5c24 100644
--- a/libc/netbsd/resolv/res_cache.c
+++ b/libc/netbsd/resolv/res_cache.c
@@ -43,6 +43,7 @@
 #include <arpa/inet.h>
 #include "resolv_private.h"
 #include "resolv_iface.h"
+#include "res_private.h"
 
 /* This code implements a small and *simple* DNS resolver cache.
  *
@@ -572,8 +573,6 @@
 static int
 _dnsPacket_checkQR( DnsPacket*  packet )
 {
-    int  len;
-
     if (!_dnsPacket_checkQName(packet))
         return 0;
 
@@ -832,8 +831,6 @@
 static unsigned
 _dnsPacket_hashQR( DnsPacket*  packet, unsigned  hash )
 {
-    int   len;
-
     hash = _dnsPacket_hashQName(packet, hash);
     hash = _dnsPacket_hashBytes(packet, 4, hash); /* TYPE and CLASS */
     return hash;
@@ -1020,8 +1017,58 @@
 } Entry;
 
 /**
- * Parse the answer records and find the smallest
- * TTL among the answer records.
+ * Find the TTL for a negative DNS result.  This is defined as the minimum
+ * of the SOA records TTL and the MINIMUM-TTL field (RFC-2308).
+ *
+ * Return 0 if not found.
+ */
+static u_long
+answer_getNegativeTTL(ns_msg handle) {
+    int n, nscount;
+    u_long result = 0;
+    ns_rr rr;
+
+    nscount = ns_msg_count(handle, ns_s_ns);
+    for (n = 0; n < nscount; n++) {
+        if ((ns_parserr(&handle, ns_s_ns, n, &rr) == 0) && (ns_rr_type(rr) == ns_t_soa)) {
+            const u_char *rdata = ns_rr_rdata(rr); // find the data
+            const u_char *edata = rdata + ns_rr_rdlen(rr); // add the len to find the end
+            int len;
+            u_long ttl, rec_result = ns_rr_ttl(rr);
+
+            // find the MINIMUM-TTL field from the blob of binary data for this record
+            // skip the server name
+            len = dn_skipname(rdata, edata);
+            if (len == -1) continue; // error skipping
+            rdata += len;
+
+            // skip the admin name
+            len = dn_skipname(rdata, edata);
+            if (len == -1) continue; // error skipping
+            rdata += len;
+
+            if (edata - rdata != 5*NS_INT32SZ) continue;
+            // skip: serial number + refresh interval + retry interval + expiry
+            rdata += NS_INT32SZ * 4;
+            // finally read the MINIMUM TTL
+            ttl = ns_get32(rdata);
+            if (ttl < rec_result) {
+                rec_result = ttl;
+            }
+            // Now that the record is read successfully, apply the new min TTL
+            if (n == 0 || rec_result < result) {
+                result = rec_result;
+            }
+        }
+    }
+    return result;
+}
+
+/**
+ * Parse the answer records and find the appropriate
+ * smallest TTL among the records.  This might be from
+ * the answer records if found or from the SOA record
+ * if it's a negative result.
  *
  * The returned TTL is the number of seconds to
  * keep the answer in the cache.
@@ -1041,14 +1088,20 @@
     if (ns_initparse(answer, answerlen, &handle) >= 0) {
         // get number of answer records
         ancount = ns_msg_count(handle, ns_s_an);
-        for (n = 0; n < ancount; n++) {
-            if (ns_parserr(&handle, ns_s_an, n, &rr) == 0) {
-                ttl = ns_rr_ttl(rr);
-                if (n == 0 || ttl < result) {
-                    result = ttl;
+
+        if (ancount == 0) {
+            // a response with no answers?  Cache this negative result.
+            result = answer_getNegativeTTL(handle);
+        } else {
+            for (n = 0; n < ancount; n++) {
+                if (ns_parserr(&handle, ns_s_an, n, &rr) == 0) {
+                    ttl = ns_rr_ttl(rr);
+                    if (n == 0 || ttl < result) {
+                        result = ttl;
+                    }
+                } else {
+                    XLOG("ns_parserr failed ancount no = %d. errno = %s\n", n, strerror(errno));
                 }
-            } else {
-                XLOG("ns_parserr failed ancount no = %d. errno = %s\n", n, strerror(errno));
             }
         }
     } else {
@@ -1197,8 +1250,16 @@
     struct resolv_cache_info*   next;
     char*                       nameservers[MAXNS +1];
     struct addrinfo*            nsaddrinfo[MAXNS + 1];
+    char                        defdname[256];
+    int                         dnsrch_offset[MAXDNSRCH+1];  // offsets into defdname
 } CacheInfo;
 
+typedef struct resolv_pidiface_info {
+    int                             pid;
+    char                            ifname[IF_NAMESIZE + 1];
+    struct resolv_pidiface_info*    next;
+} PidIfaceInfo;
+
 #define  HTABLE_VALID(x)  ((x) != NULL && (x) != HTABLE_DELETED)
 
 static void
@@ -1251,8 +1312,9 @@
             }
         } else {
             struct timespec ts = {0,0};
+            XLOG("Waiting for previous request");
             ts.tv_sec = _time_now() + PENDING_REQUEST_TIMEOUT;
-            int rv = pthread_cond_timedwait(&ri->cond, &cache->lock, &ts);
+            pthread_cond_timedwait(&ri->cond, &cache->lock, &ts);
         }
     }
 
@@ -1306,7 +1368,6 @@
 _cache_flush_locked( Cache*  cache )
 {
     int     nn;
-    time_t  now = _time_now();
 
     for (nn = 0; nn < cache->max_entries; nn++)
     {
@@ -1347,9 +1408,8 @@
     if (cache_mode == NULL || strcmp(cache_mode, "local") != 0) {
         // Don't use the cache in local mode.  This is used by the
         // proxy itself.
-        // TODO - change this to 0 when all dns stuff uses proxy (5918973)
-        XLOG("setup cache for non-cache process. size=1");
-        return 1;
+        XLOG("setup cache for non-cache process. size=0, %s", cache_mode);
+        return 0;
     }
 
     if (__system_property_get(DNS_CACHE_SIZE_PROP_NAME, cache_size) > 0) {
@@ -1442,6 +1502,7 @@
         remove("/data/reslog.txt");
     }
     else {
+        errno = 0; // else debug is introducing error signals
         XLOG("_dump_answer: can't open file\n");
     }
 }
@@ -1487,7 +1548,7 @@
 
         pnode = &node->hlink;
     }
-    return pnode; 
+    return pnode;
 }
 
 /* Add a new entry to the hash table. 'lookup' must be the
@@ -1577,9 +1638,7 @@
                       int                   answersize,
                       int                  *answerlen )
 {
-    DnsPacket  pack[1];
     Entry      key[1];
-    int        index;
     Entry**    lookup;
     Entry*     e;
     time_t     now;
@@ -1730,20 +1789,28 @@
 /****************************************************************************/
 /****************************************************************************/
 
-static pthread_once_t        _res_cache_once;
+static pthread_once_t        _res_cache_once = PTHREAD_ONCE_INIT;
 
 // Head of the list of caches.  Protected by _res_cache_list_lock.
 static struct resolv_cache_info _res_cache_list;
 
+// List of pid iface pairs
+static struct resolv_pidiface_info _res_pidiface_list;
+
 // name of the current default inteface
 static char            _res_default_ifname[IF_NAMESIZE + 1];
 
 // lock protecting everything in the _resolve_cache_info structs (next ptr, etc)
 static pthread_mutex_t _res_cache_list_lock;
 
+// lock protecting the _res_pid_iface_list
+static pthread_mutex_t _res_pidiface_list_lock;
 
 /* lookup the default interface name */
 static char *_get_default_iface_locked();
+/* find the first cache that has an associated interface and return the name of the interface */
+static char* _find_any_iface_name_locked( void );
+
 /* insert resolv_cache_info into the list of resolv_cache_infos */
 static void _insert_cache_info_locked(struct resolv_cache_info* cache_info);
 /* creates a resolv_cache_info */
@@ -1752,8 +1819,6 @@
 static struct resolv_cache* _find_named_cache_locked(const char* ifname);
 /* gets a resolv_cache_info associated with an interface name, or NULL if not found */
 static struct resolv_cache_info* _find_cache_info_locked(const char* ifname);
-/* free dns name server list of a resolv_cache_info structure */
-static void _free_nameservers(struct resolv_cache_info* cache_info);
 /* look up the named cache, and creates one if needed */
 static struct resolv_cache* _get_res_cache_for_iface_locked(const char* ifname);
 /* empty the named cache */
@@ -1766,8 +1831,14 @@
 static struct addrinfo* _get_nameserver_addr_locked(const char* ifname, int n);
 /* lookup the inteface's address */
 static struct in_addr* _get_addr_locked(const char * ifname);
-
-
+/* return 1 if the provided list of name servers differs from the list of name servers
+ * currently attached to the provided cache_info */
+static int _resolv_is_nameservers_equal_locked(struct resolv_cache_info* cache_info,
+        char** servers, int numservers);
+/* remove a resolv_pidiface_info structure from _res_pidiface_list */
+static void _remove_pidiface_info_locked(int pid);
+/* get a resolv_pidiface_info structure from _res_pidiface_list with a certain pid */
+static struct resolv_pidiface_info* _get_pid_iface_info_locked(int pid);
 
 static void
 _res_cache_init(void)
@@ -1781,37 +1852,36 @@
 
     memset(&_res_default_ifname, 0, sizeof(_res_default_ifname));
     memset(&_res_cache_list, 0, sizeof(_res_cache_list));
+    memset(&_res_pidiface_list, 0, sizeof(_res_pidiface_list));
     pthread_mutex_init(&_res_cache_list_lock, NULL);
+    pthread_mutex_init(&_res_pidiface_list_lock, NULL);
 }
 
 struct resolv_cache*
-__get_res_cache(void)
+__get_res_cache(const char* ifname)
 {
     struct resolv_cache *cache;
 
     pthread_once(&_res_cache_once, _res_cache_init);
-
     pthread_mutex_lock(&_res_cache_list_lock);
 
-    char* ifname = _get_default_iface_locked();
-
-    // if default interface not set then use the first cache
-    // associated with an interface as the default one.
-    if (ifname[0] == '\0') {
-        struct resolv_cache_info* cache_info = _res_cache_list.next;
-        while (cache_info) {
-            if (cache_info->ifname[0] != '\0') {
-                ifname = cache_info->ifname;
-                break;
+    char* iface;
+    if (ifname == NULL || ifname[0] == '\0') {
+        iface = _get_default_iface_locked();
+        if (iface[0] == '\0') {
+            char* tmp = _find_any_iface_name_locked();
+            if (tmp) {
+                iface = tmp;
             }
-
-            cache_info = cache_info->next;
         }
+    } else {
+        iface = (char *) ifname;
     }
-    cache = _get_res_cache_for_iface_locked(ifname);
+
+    cache = _get_res_cache_for_iface_locked(iface);
 
     pthread_mutex_unlock(&_res_cache_list_lock);
-    XLOG("_get_res_cache. default_ifname = %s\n", ifname);
+    XLOG("_get_res_cache: iface = %s, cache=%p\n", iface, cache);
     return cache;
 }
 
@@ -1967,11 +2037,29 @@
 static char*
 _get_default_iface_locked(void)
 {
+
     char* iface = _res_default_ifname;
 
     return iface;
 }
 
+static char*
+_find_any_iface_name_locked( void ) {
+    char* ifname = NULL;
+
+    struct resolv_cache_info* cache_info = _res_cache_list.next;
+    while (cache_info) {
+        if (cache_info->ifname[0] != '\0') {
+            ifname = cache_info->ifname;
+            break;
+        }
+
+        cache_info = cache_info->next;
+    }
+
+    return ifname;
+}
+
 void
 _resolv_set_default_iface(const char* ifname)
 {
@@ -1989,21 +2077,25 @@
 }
 
 void
-_resolv_set_nameservers_for_iface(const char* ifname, char** servers, int numservers)
+_resolv_set_nameservers_for_iface(const char* ifname, char** servers, int numservers,
+        const char *domains)
 {
     int i, rt, index;
     struct addrinfo hints;
     char sbuf[NI_MAXSERV];
+    register char *cp;
+    int *offset;
 
     pthread_once(&_res_cache_once, _res_cache_init);
-
     pthread_mutex_lock(&_res_cache_list_lock);
+
     // creates the cache if not created
     _get_res_cache_for_iface_locked(ifname);
 
     struct resolv_cache_info* cache_info = _find_cache_info_locked(ifname);
 
-    if (cache_info != NULL) {
+    if (cache_info != NULL &&
+            !_resolv_is_nameservers_equal_locked(cache_info, servers, numservers)) {
         // free current before adding new
         _free_nameservers_locked(cache_info);
 
@@ -2019,14 +2111,68 @@
             if (rt == 0) {
                 cache_info->nameservers[index] = strdup(servers[i]);
                 index++;
+                XLOG("_resolv_set_nameservers_for_iface: iface = %s, addr = %s\n",
+                        ifname, servers[i]);
             } else {
                 cache_info->nsaddrinfo[index] = NULL;
             }
         }
+
+        // code moved from res_init.c, load_domain_search_list
+        strlcpy(cache_info->defdname, domains, sizeof(cache_info->defdname));
+        if ((cp = strchr(cache_info->defdname, '\n')) != NULL)
+            *cp = '\0';
+        cp = cache_info->defdname;
+        offset = cache_info->dnsrch_offset;
+        while (offset < cache_info->dnsrch_offset + MAXDNSRCH) {
+            while (*cp == ' ' || *cp == '\t') /* skip leading white space */
+                cp++;
+            if (*cp == '\0') /* stop if nothing more to do */
+                break;
+            *offset++ = cp - cache_info->defdname; /* record this search domain */
+            while (*cp) { /* zero-terminate it */
+                if (*cp == ' '|| *cp == '\t') {
+                    *cp++ = '\0';
+                    break;
+                }
+                cp++;
+            }
+        }
+        *offset = -1; /* cache_info->dnsrch_offset has MAXDNSRCH+1 items */
+
+        // flush cache since new settings
+        _flush_cache_for_iface_locked(ifname);
+
     }
+
     pthread_mutex_unlock(&_res_cache_list_lock);
 }
 
+static int
+_resolv_is_nameservers_equal_locked(struct resolv_cache_info* cache_info,
+        char** servers, int numservers)
+{
+    int i;
+    char** ns;
+    int equal = 1;
+
+    // compare each name server against current name servers
+    if (numservers > MAXNS) numservers = MAXNS;
+    for (i = 0; i < numservers && equal; i++) {
+        ns = cache_info->nameservers;
+        equal = 0;
+        while(*ns) {
+            if (strcmp(*ns, servers[i]) == 0) {
+                equal = 1;
+                break;
+            }
+            ns++;
+        }
+    }
+
+    return equal;
+}
+
 static void
 _free_nameservers_locked(struct resolv_cache_info* cache_info)
 {
@@ -2169,3 +2315,192 @@
     }
     return NULL;
 }
+
+static void
+_remove_pidiface_info_locked(int pid) {
+    struct resolv_pidiface_info* result = &_res_pidiface_list;
+    struct resolv_pidiface_info* prev = NULL;
+
+    while (result != NULL && result->pid != pid) {
+        prev = result;
+        result = result->next;
+    }
+    if (prev != NULL && result != NULL) {
+        prev->next = result->next;
+        free(result);
+    }
+}
+
+static struct resolv_pidiface_info*
+_get_pid_iface_info_locked(int pid)
+{
+    struct resolv_pidiface_info* result = &_res_pidiface_list;
+    while (result != NULL && result->pid != pid) {
+        result = result->next;
+    }
+
+    return result;
+}
+
+void
+_resolv_set_iface_for_pid(const char* ifname, int pid)
+{
+    // make sure the pid iface list is created
+    pthread_once(&_res_cache_once, _res_cache_init);
+    pthread_mutex_lock(&_res_pidiface_list_lock);
+
+    struct resolv_pidiface_info* pidiface_info = _get_pid_iface_info_locked(pid);
+    if (!pidiface_info) {
+        pidiface_info = calloc(sizeof(*pidiface_info), 1);
+        if (pidiface_info) {
+            pidiface_info->pid = pid;
+            int len = sizeof(pidiface_info->ifname);
+            strncpy(pidiface_info->ifname, ifname, len - 1);
+            pidiface_info->ifname[len - 1] = '\0';
+
+            pidiface_info->next = _res_pidiface_list.next;
+            _res_pidiface_list.next = pidiface_info;
+
+            XLOG("_resolv_set_iface_for_pid: pid %d , iface %s\n", pid, ifname);
+        } else {
+            XLOG("_resolv_set_iface_for_pid failing calloc");
+        }
+    }
+
+    pthread_mutex_unlock(&_res_pidiface_list_lock);
+}
+
+void
+_resolv_clear_iface_for_pid(int pid)
+{
+    pthread_once(&_res_cache_once, _res_cache_init);
+    pthread_mutex_lock(&_res_pidiface_list_lock);
+
+    _remove_pidiface_info_locked(pid);
+
+    XLOG("_resolv_clear_iface_for_pid: pid %d\n", pid);
+
+    pthread_mutex_unlock(&_res_pidiface_list_lock);
+}
+
+int
+_resolv_get_pids_associated_interface(int pid, char* buff, int buffLen)
+{
+    int len = 0;
+
+    if (!buff) {
+        return -1;
+    }
+
+    pthread_once(&_res_cache_once, _res_cache_init);
+    pthread_mutex_lock(&_res_pidiface_list_lock);
+
+    struct resolv_pidiface_info* pidiface_info = _get_pid_iface_info_locked(pid);
+    buff[0] = '\0';
+    if (pidiface_info) {
+        len = strlen(pidiface_info->ifname);
+        if (len < buffLen) {
+            strncpy(buff, pidiface_info->ifname, len);
+            buff[len] = '\0';
+        }
+    }
+
+    XLOG("_resolv_get_pids_associated_interface buff: %s\n", buff);
+
+    pthread_mutex_unlock(&_res_pidiface_list_lock);
+
+    return len;
+}
+
+int
+_resolv_get_default_iface(char* buff, int buffLen)
+{
+    char* ifname;
+    int len = 0;
+
+    if (!buff || buffLen == 0) {
+        return -1;
+    }
+
+    pthread_once(&_res_cache_once, _res_cache_init);
+    pthread_mutex_lock(&_res_cache_list_lock);
+
+    ifname = _get_default_iface_locked();
+
+    // if default interface not set. Get first cache with an interface
+    if (ifname[0] == '\0') {
+        ifname = _find_any_iface_name_locked();
+    }
+
+    if (ifname) {
+        len = strlen(ifname);
+        if (len < buffLen) {
+            strncpy(buff, ifname, len);
+            buff[len] = '\0';
+        }
+    } else {
+        buff[0] = '\0';
+    }
+
+    pthread_mutex_unlock(&_res_cache_list_lock);
+
+    return len;
+}
+
+int
+_resolv_populate_res_for_iface(res_state statp)
+{
+    int nserv;
+    struct resolv_cache_info* info = NULL;
+
+    if (statp) {
+        struct addrinfo* ai;
+
+        if (statp->iface[0] == '\0') { // no interface set assign default
+            _resolv_get_default_iface(statp->iface, sizeof(statp->iface));
+        }
+
+        pthread_once(&_res_cache_once, _res_cache_init);
+        pthread_mutex_lock(&_res_cache_list_lock);
+        info = _find_cache_info_locked(statp->iface);
+
+        if (info == NULL) return 0;
+
+        XLOG("_resolv_populate_res_for_iface: %s\n", statp->iface);
+        for (nserv = 0; nserv < MAXNS; nserv++) {
+            ai = info->nsaddrinfo[nserv];
+            if (ai == NULL) {
+                break;
+            }
+
+            if ((size_t) ai->ai_addrlen <= sizeof(statp->_u._ext.ext->nsaddrs[0])) {
+                if (statp->_u._ext.ext != NULL) {
+                    memcpy(&statp->_u._ext.ext->nsaddrs[nserv], ai->ai_addr, ai->ai_addrlen);
+                    statp->nsaddr_list[nserv].sin_family = AF_UNSPEC;
+                } else {
+                    if ((size_t) ai->ai_addrlen
+                            <= sizeof(statp->nsaddr_list[0])) {
+                        memcpy(&statp->nsaddr_list[nserv], ai->ai_addr,
+                                ai->ai_addrlen);
+                    } else {
+                        statp->nsaddr_list[nserv].sin_family = AF_UNSPEC;
+                    }
+                }
+            } else {
+                XLOG("_resolv_populate_res_for_iface found too long addrlen");
+            }
+        }
+        statp->nscount = nserv;
+        // now do search domains.  Note that we cache the offsets as this code runs alot
+        // but the setting/offset-computer only runs when set/changed
+        strlcpy(statp->defdname, info->defdname, sizeof(statp->defdname));
+        register char **pp = statp->dnsrch;
+        register int *p = info->dnsrch_offset;
+        while (pp < statp->dnsrch + MAXDNSRCH && *p != -1) {
+            *pp++ = &statp->defdname + *p++;
+        }
+
+        pthread_mutex_unlock(&_res_cache_list_lock);
+    }
+    return nserv;
+}
diff --git a/libc/netbsd/resolv/res_data.c b/libc/netbsd/resolv/res_data.c
index 014c99b..7e5a308 100644
--- a/libc/netbsd/resolv/res_data.c
+++ b/libc/netbsd/resolv/res_data.c
@@ -82,13 +82,7 @@
 
 int  res_ourserver_p(const res_state, const struct sockaddr *);
 
-#ifdef ANDROID_CHANGES
-static int res_need_init() {
-	return ((_nres.options & RES_INIT) == 0U) || res_get_dns_changed();
-}
-#else
 #define res_need_init()   ((_nres.options & RES_INIT) == 0U)
-#endif
 
 int
 res_init(void) {
diff --git a/libc/netbsd/resolv/res_init.c b/libc/netbsd/resolv/res_init.c
index 56a25af..ff65299 100644
--- a/libc/netbsd/resolv/res_init.c
+++ b/libc/netbsd/resolv/res_init.c
@@ -111,13 +111,6 @@
 /* ensure that sockaddr_in6 and IN6ADDR_ANY_INIT are declared / defined */
 #ifdef ANDROID_CHANGES
 #include "resolv_private.h"
-#define MAX_DNS_PROPERTIES 8
-#define DNS_PROP_NAME_PREFIX "net.dns"
-#define DNS_CHANGE_PROP_NAME "net.dnschange"
-#define DNS_SEARCH_PROP_NAME "net.dns.search"
-static const prop_info *dns_change_prop;
-static int dns_last_change_counter;
-static int _get_dns_change_count();
 #else
 #include <resolv.h>
 #endif
@@ -171,41 +164,6 @@
 	return (__res_vinit(statp, 0));
 }
 
-#ifdef ANDROID_CHANGES
-static int load_domain_search_list(res_state statp) {
-	char propvalue[PROP_VALUE_MAX];
-	register char *cp, **pp;
-
-	if(__system_property_get(DNS_SEARCH_PROP_NAME, propvalue) >= 1) {
-		strlcpy(statp->defdname, propvalue, sizeof(statp->defdname));
-		if ((cp = strchr(statp->defdname, '\n')) != NULL)
-			*cp = '\0';
-		cp = statp->defdname;
-		pp = statp->dnsrch;
-		while ( pp < statp->dnsrch + MAXDNSRCH ) {
-			while (*cp == ' ' || *cp == '\t') /* skip leading white space */
-				cp++;
-			if (*cp == '\0')  /* stop if nothing more */
-				break;
-			*pp++ = cp;  /* record this search domain */
-			while (*cp) { /* zero-terminate it */
-				if (*cp == ' ' || *cp == '\t') {
-					*cp++ = '\0';
-					break;
-				}
-				cp++;
-			}
-		}
-		*pp = NULL; /* statp->dnsrch has MAXDNSRCH+1 items */
-		if (pp > statp->dnsrch)
-			return 1;
-	}
-	statp->defdname[0] = '\0';  /* no default domain name on Android */
-	statp->dnsrch[0] = NULL;
-	return 0;
-}
-#endif
-
 /* This function has to be reachable by res_data.c but not publicly. */
 int
 __res_vinit(res_state statp, int preinit) {
@@ -220,12 +178,6 @@
 	char *net;
 	int dots;
 	union res_sockaddr_union u[2];
-#ifdef ANDROID_CHANGES
-        pid_t mypid = getpid();
-        int use_proc_props = 0;
-        int found_prop;
-	char dnsProperty[PROP_VALUE_MAX];
-#endif
 
         if ((statp->options & RES_INIT) != 0U)
                 res_ndestroy(statp);
@@ -318,74 +270,8 @@
 	if (nserv > 0)
 		statp->nscount = nserv;
 #endif
-#ifdef ANDROID_CHANGES /* READ FROM SYSTEM PROPERTIES */
-	dns_last_change_counter = _get_dns_change_count();
 
-	nserv = 0;
-	for(n = 1; n <= MAX_DNS_PROPERTIES && nserv < MAXNS; n++) {
-		char propname[PROP_NAME_MAX];
-		char propvalue[PROP_VALUE_MAX];
-
-		struct addrinfo hints, *ai;
-		char sbuf[NI_MAXSERV];
-		const size_t minsiz = sizeof(statp->_u._ext.ext->nsaddrs[0]);
-
-		/*
-		 * Check first for process-specific properties, and if those don't
-		 * exist, try the generic properties.
-		 */
-		found_prop = 0;
-		if (n == 1 || use_proc_props) {
-			snprintf(propname, sizeof(propname), "%s%d.%d", DNS_PROP_NAME_PREFIX, n, mypid);
-			if(__system_property_get(propname, propvalue) < 1) {
-				if (use_proc_props) {
-					break;
-				}
-			} else {
-				found_prop = 1;
-				use_proc_props = 1;
-			}
-		}
-		if (!found_prop) {
-			snprintf(propname, sizeof(propname), "%s%d", DNS_PROP_NAME_PREFIX, n);
-			if(__system_property_get(propname, propvalue) < 1) {
-				break;
-			}
-		}
-
-		cp = propvalue;
-
-		while (*cp == ' ' || *cp == '\t')
-			cp++;
-		cp[strcspn(cp, ";# \t\n")] = '\0';
-		if ((*cp != '\0') && (*cp != '\n')) {
-			memset(&hints, 0, sizeof(hints));
-			hints.ai_family = PF_UNSPEC;
-			hints.ai_socktype = SOCK_DGRAM;	/*dummy*/
-			hints.ai_flags = AI_NUMERICHOST;
-			sprintf(sbuf, "%u", NAMESERVER_PORT);
-			if (getaddrinfo(cp, sbuf, &hints, &ai) == 0 &&
-			    (size_t)ai->ai_addrlen <= minsiz) {
-				if (statp->_u._ext.ext != NULL) {
-					memcpy(&statp->_u._ext.ext->nsaddrs[nserv],
-					       ai->ai_addr, ai->ai_addrlen);
-				}
-				if ((size_t)ai->ai_addrlen <=
-				    sizeof(statp->nsaddr_list[nserv])) {
-					memcpy(&statp->nsaddr_list[nserv],
-					       ai->ai_addr, ai->ai_addrlen);
-				} else {
-					statp->nsaddr_list[nserv].sin_family = 0;
-				}
-				freeaddrinfo(ai);
-				nserv++;
-			}
-		}
-	}
-
-	/* Add the domain search list */
-	havesearch = load_domain_search_list(statp);
-#else /* !ANDROID_CHANGES - IGNORE resolv.conf in Android */
+#ifndef ANDROID_CHANGES /* !ANDROID_CHANGES - IGNORE resolv.conf in Android */
 #define	MATCH(line, name) \
 	(!strncmp(line, name, sizeof(name) - 1) && \
 	(line[sizeof(name) - 1] == ' ' || \
@@ -907,32 +793,17 @@
 }
 
 #ifdef ANDROID_CHANGES
-static int _get_dns_change_count()
+void res_setiface(res_state statp, const char* iface)
 {
-	if (dns_change_prop == NULL) {
-		dns_change_prop = __system_property_find(DNS_CHANGE_PROP_NAME);
-	}
-	if (dns_change_prop != NULL) {
-		char propvalue[PROP_VALUE_MAX];
-		if (__system_property_read(dns_change_prop, NULL, propvalue) >= 1) {
-			return atoi(propvalue);
+	if (statp != NULL) {
+		// set interface
+		if (iface && iface[0] != '\0') {
+			int len = sizeof(statp->iface);
+			strncpy(statp->iface, iface, len - 1);
+			statp->iface[len - 1] = '\0';
+		} else {
+			statp->iface[0] = '\0';
 		}
 	}
-	return -1;
-}
-
-int res_get_dns_changed()
-{
-	int change_count;
-
-	change_count = _get_dns_change_count();
-	if (change_count != dns_last_change_counter) {
-		if (change_count != -1) {
-			dns_last_change_counter = change_count;
-		}
-		return 1;
-	} else {
-		return 0;
-	}
 }
 #endif /* ANDROID_CHANGES */
diff --git a/libc/netbsd/resolv/res_send.c b/libc/netbsd/resolv/res_send.c
index f3ee539..0be6e8e 100644
--- a/libc/netbsd/resolv/res_send.c
+++ b/libc/netbsd/resolv/res_send.c
@@ -370,10 +370,13 @@
         ResolvCacheStatus     cache_status = RESOLV_CACHE_UNSUPPORTED;
 #endif
 
+#if !USE_RESOLV_CACHE
 	if (statp->nscount == 0) {
 		errno = ESRCH;
 		return (-1);
 	}
+#endif
+
 	if (anssiz < HFIXEDSZ) {
 		errno = EINVAL;
 		return (-1);
@@ -385,7 +388,8 @@
 	terrno = ETIMEDOUT;
 
 #if USE_RESOLV_CACHE
-        cache = __get_res_cache();
+        // get the cache associated with the interface
+        cache = __get_res_cache(statp->iface);
         if (cache != NULL) {
             int  anslen = 0;
             cache_status = _resolv_cache_lookup(
@@ -394,8 +398,17 @@
 
             if (cache_status == RESOLV_CACHE_FOUND) {
                 return anslen;
+            } else {
+                // had a cache miss for a known interface, so populate the thread private
+                // data so the normal resolve path can do its thing
+                _resolv_populate_res_for_iface(statp);
             }
         }
+
+        if (statp->nscount == 0) {
+            errno = ESRCH;
+            return (-1);
+        }
 #endif
 
 	/*
diff --git a/libc/netbsd/resolv/res_state.c b/libc/netbsd/resolv/res_state.c
index e05846a..efaa519 100644
--- a/libc/netbsd/resolv/res_state.c
+++ b/libc/netbsd/resolv/res_state.c
@@ -50,7 +50,7 @@
 #endif
 
 static pthread_key_t   _res_key;
-static pthread_once_t  _res_once;
+static pthread_once_t  _res_once = PTHREAD_ONCE_INIT;
 
 typedef struct {
     int                  _h_errno;
diff --git a/libc/private/resolv_cache.h b/libc/private/resolv_cache.h
index 1dcc53f..4f32fb7 100644
--- a/libc/private/resolv_cache.h
+++ b/libc/private/resolv_cache.h
@@ -28,13 +28,13 @@
 #ifndef _RESOLV_CACHE_H_
 #define _RESOLV_CACHE_H_
 
+struct __res_state;
 struct resolv_cache;  /* forward */
 
-/* gets the cache for the default interface. Might be NULL*/
-extern struct resolv_cache*  __get_res_cache(void);
-
-/* get the cache for a specified interface. Can be NULL*/
-extern struct resolv_cache* __get_res_cache_for_iface(const char* ifname);
+/* gets the cache for an interface. Set ifname argument to NULL or
+ * empty buffer ('\0') to get cache for default interface.
+ * returned cache might be NULL*/
+extern struct resolv_cache*  __get_res_cache(const char* ifname);
 
 /* this gets called everytime we detect some changes in the DNS configuration
  * and will flush the cache */
@@ -67,8 +67,14 @@
 /* gets the address associated with the specified interface */
 extern struct in_addr* _resolv_get_addr_of_iface(const char* ifname);
 
-/* Get name of default interface */
-extern char* _resolv_get_default_iface();
+/* Copy the name of the default interface to provided buffer.
+ * Return length of buffer on success on failure -1 is returned */
+extern int _resolv_get_default_iface(char* buff, int buffLen);
+
+/* sets the name server addresses to the provided res_state structure. The
+ * name servers are retrieved from the cache which is associated
+ * with the interface to which the res_state structure is associated */
+extern int _resolv_populate_res_for_iface(struct __res_state* statp);
 
 typedef enum {
     RESOLV_CACHE_UNSUPPORTED,  /* the cache can't handle that kind of queries */
diff --git a/libc/private/resolv_iface.h b/libc/private/resolv_iface.h
index f562687..bf5abad 100644
--- a/libc/private/resolv_iface.h
+++ b/libc/private/resolv_iface.h
@@ -48,7 +48,8 @@
 extern void _resolv_set_default_iface(const char* ifname);
 
 /* set name servers for an interface */
-extern void _resolv_set_nameservers_for_iface(const char* ifname, char** servers, int numservers);
+extern void _resolv_set_nameservers_for_iface(const char* ifname, char** servers, int numservers,
+        const char *domains);
 
 /* tell resolver of the address of an interface */
 extern void _resolv_set_addr_of_iface(const char* ifname, struct in_addr* addr);
@@ -59,6 +60,21 @@
 /* flush the cache associated with a certain interface */
 extern void _resolv_flush_cache_for_iface(const char* ifname);
 
+/* set a pid to use the name servers of the specified interface */
+extern void _resolv_set_iface_for_pid(const char* ifname, int pid);
+
+/* clear pid from being associated with an interface */
+extern void _resolv_clear_iface_for_pid(int pid);
+
+/** Gets the name of the interface to which the pid is attached.
+ *  On error, -1 is returned.
+ *  If no interface is found, 0 is returned and buff is set to empty ('\0').
+ *  If an interface is found, the name is copied to buff and the length of the name is returned.
+ *  Arguments:   pid The pid to find an interface for
+ *               buff A buffer to copy the result to
+ *               buffLen Length of buff. An interface is at most IF_NAMESIZE in length */
+extern int _resolv_get_pids_associated_interface(int pid, char* buff, int buffLen);
+
 #endif /* _BIONIC_RESOLV_IFACE_FUNCTIONS_DECLARED */
 
 __END_DECLS
diff --git a/libc/private/resolv_private.h b/libc/private/resolv_private.h
index 0f3c6c0..1c3c1a2 100644
--- a/libc/private/resolv_private.h
+++ b/libc/private/resolv_private.h
@@ -56,6 +56,7 @@
 
 #include <resolv.h>
 #include "resolv_static.h"
+#include <net/if.h>
 
 /*
  * Revision information.  This is the release date in YYYYMMDD format.
@@ -139,6 +140,7 @@
 struct __res_state_ext;
 
 struct __res_state {
+	char	iface[IF_NAMESIZE+1];
 	int	retrans;	 	/* retransmission time interval */
 	int	retry;			/* number of times to retransmit */
 #ifdef sun
@@ -491,7 +493,7 @@
 int		res_getservers(res_state,
 				    union res_sockaddr_union *, int);
 
-int res_get_dns_changed();
+void res_setiface();
 u_int  res_randomid(void);
 
 __END_DECLS
diff --git a/linker/Android.mk b/linker/Android.mk
index c85b09e..dfa77e9 100644
--- a/linker/Android.mk
+++ b/linker/Android.mk
@@ -67,6 +67,9 @@
 # just for this module
 LOCAL_NO_CRT := true
 
+# TODO: split out the asflags.
+LOCAL_ASFLAGS := $(LOCAL_CFLAGS)
+
 include $(BUILD_SYSTEM)/dynamic_binary.mk
 
 # See build/core/executable.mk