summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--libc/docs/OVERVIEW.TXT13
-rw-r--r--libc/include/netdb.h4
-rw-r--r--libc/netbsd/gethnamaddr.c215
-rw-r--r--libc/netbsd/net/getaddrinfo.c76
-rw-r--r--libc/netbsd/net/getnameinfo.c137
-rw-r--r--libc/netbsd/resolv/res_cache.c342
-rw-r--r--libc/netbsd/resolv/res_data.c6
-rw-r--r--libc/netbsd/resolv/res_init.c149
-rw-r--r--libc/netbsd/resolv/res_send.c35
-rw-r--r--libc/netbsd/resolv/res_state.c2
-rw-r--r--libc/private/resolv_cache.h20
-rw-r--r--libc/private/resolv_iface.h15
-rw-r--r--libc/private/resolv_private.h4
13 files changed, 671 insertions, 347 deletions
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 @@ DNS resolver:
- 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 endprotoent(void);
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 sethostent(int);
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..1ab987e 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 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);
+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 @@ gethostbyname(const char *name)
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,120 @@ gethostbyname(const char *name)
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 FILE* android_open_proxy()
+{
+ int sock;
+ const int one = 1;
+ struct sockaddr_un proxy_addr;
+
+ 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;
+ }
+
+ return fdopen(sock, "r+");
+}
+
+static struct hostent *
+android_read_hostent(FILE* proxy)
+{
+ uint32_t size;
+ char buf[4];
+ if (fread(buf, 1, sizeof(buf), proxy) != sizeof(buf)) return NULL;
+
+ /* This is reading serialized data from system/netd/DnsProxyListener.cpp
+ * and changes here need to be matched there */
+ int result_code = strtol(buf, NULL, 10);
+ if (result_code != DnsProxyQueryResult) {
+ fread(&size, 1, sizeof(size), proxy);
+ 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;
+
+ if (fread(ptr, 1, size, proxy) != size) return NULL;
+ ptr += size;
+ rs->host.h_name = rs->hostbuf;
+
+ char **aliases = rs->host_aliases;
+ rs->host.h_aliases = rs->host_aliases;
+ while (1) {
+ if (fread(&size, 1, sizeof(size), proxy) != sizeof(size)) return NULL;
+ size = ntohl(size);
+
+ if (size == 0) {
+ *aliases = NULL;
+ break;
+ }
+ if (fread(ptr, 1, size, proxy) != size) return NULL;
+ *aliases++ = ptr;
+ ptr += size;
+ }
+
+ if (fread(&size, 1, sizeof(size), proxy) != sizeof(size)) return NULL;
+ rs->host.h_addrtype = ntohl(size);
+
+ if (fread(&size, 1, sizeof(size), proxy) != sizeof(size)) return NULL;
+ 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(&size, 1, sizeof(size), proxy) != sizeof(size)) return NULL;
+ size = ntohl(size);
+ if (size == 0) {
+ *addrs = NULL;
+ break;
+ }
+ if (fread(ptr, 1, size, proxy) != size) return NULL;
+ *addrs++ = ptr;
+ ptr += size;
+ }
+
+ return &rs->host;
+}
+
+
static struct hostent *
-gethostbyname_internal(const char *name, int af, res_state res)
+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)
@@ -632,14 +733,84 @@ gethostbyname_internal(const char *name, int af, res_state res)
if (nsdispatch(&hp, dtab, NSDB_HOSTS, "gethostbyname",
default_dns_files, name, strlen(name), af) != NS_SUCCESS) {
return NULL;
- }
+ }
h_errno = 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, const char *iface)
+{
+ const char *cache_mode = getenv("ANDROID_DNS_MODE");
+ FILE* proxy = NULL;
+ struct hostent *result = NULL;
+
+ if (cache_mode != NULL && strcmp(cache_mode, "local") == 0) {
+ res_setiface(res, iface);
+ return gethostbyname_internal_real(name, af, res);
+ }
+
+ proxy = android_open_proxy();
+
+ /* This is writing to system/netd/DnsProxyListener.cpp and changes
+ * here need to be matched there */
+ if (fprintf(proxy, "gethostbyname %d %s %s %d",
+ getpid(),
+ iface == NULL ? "^" : iface,
+ name == NULL ? "^" : name,
+ af) < 0) {
+ goto exit;
+ }
+
+ if (fputc(0, proxy) == EOF || fflush(proxy) != 0) {
+ goto exit;
+ }
+
+ result = android_read_hostent(proxy);
+
+exit:
+ if (proxy != NULL) {
+ fclose(proxy);
+ }
+ return result;
+}
+
+
+struct hostent *
+android_gethostbyaddrforiface_proxy(const void *addr,
+ socklen_t len, int af, const char* iface)
+{
+ struct hostent *result = NULL;
+ FILE* proxy = android_open_proxy();
+
+ if (proxy == NULL) goto exit;
+
+ char buf[INET6_ADDRSTRLEN]; //big enough for IPv4 and IPv6
+ const char * addrStr = inet_ntop(af, addr, buf, sizeof(buf));
+ if (addrStr == NULL) goto exit;
+
+ if (fprintf(proxy, "gethostbyaddr %s %d %d %d %s",
+ addrStr, len, af, getpid(), iface == NULL ? "^" : iface) < 0) {
+ goto exit;
+ }
+
+ if (fputc(0, proxy) == EOF || fflush(proxy) != 0) {
+ goto exit;
+ }
+
+ result = android_read_hostent(proxy);
+exit:
+ if (proxy != NULL) {
+ fclose(proxy);
+ }
+ return result;
+}
+
struct hostent *
-gethostbyaddr(const void *addr,
- socklen_t len, int af)
+android_gethostbyaddrforiface_real(const void *addr,
+ socklen_t len, int af, const char* iface)
{
const u_char *uaddr = (const u_char *)addr;
socklen_t size;
@@ -687,12 +858,31 @@ gethostbyaddr(const void *addr,
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;
}
+struct hostent *
+android_gethostbyaddrforiface(const void *addr, socklen_t len, int af, const char* iface)
+{
+ const char *cache_mode = getenv("ANDROID_DNS_MODE");
+
+ if (cache_mode == NULL || strcmp(cache_mode, "local") != 0) {
+ return android_gethostbyaddrforiface_proxy(addr, len, af, iface);
+ } else {
+ return android_gethostbyaddrforiface_real(addr,len, af,iface);
+ }
+}
+
+struct hostent *
+gethostbyaddr(const void *addr, socklen_t len, int af)
+{
+ return android_gethostbyaddrforiface(addr, len, af, NULL);
+}
+
+
static void
_sethtent(int f)
{
@@ -1124,6 +1314,7 @@ _dns_gethtbyaddr(void *rv, void *cb_data, va_list ap)
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 +1322,7 @@ _dns_gethtbyaddr(void *rv, void *cb_data, va_list ap)
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 +1364,7 @@ _dns_gethtbyaddr(void *rv, void *cb_data, va_list ap)
free(buf);
return NS_NOTFOUND;
}
+ res_setiface(res, iface);
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..aed6b94 100644
--- a/libc/netbsd/net/getaddrinfo.c
+++ b/libc/netbsd/net/getaddrinfo.c
@@ -214,7 +214,7 @@ struct res_target {
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 @@ _have_ipv4() {
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 @@ android_getaddrinfo_proxy(
// 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 @@ android_getaddrinfo_proxy(
(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
@@ -488,6 +472,7 @@ android_getaddrinfo_proxy(
int result_code = (int)strtol(buf, NULL, 10);
// verify the code itself
if (result_code != DnsProxyQueryResult ) {
+ fread(buf, 1, sizeof(buf), proxy);
goto exit;
}
@@ -580,20 +565,26 @@ exit:
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 +592,12 @@ getaddrinfo(const char *hostname, const char *servname,
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 +730,10 @@ getaddrinfo(const char *hostname, const char *servname,
/*
* 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 +762,7 @@ getaddrinfo(const char *hostname, const char *servname,
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 +795,7 @@ getaddrinfo(const char *hostname, const char *servname,
*/
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 +821,7 @@ explore_fqdn(const struct addrinfo *pai, const char *hostname,
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 +1889,11 @@ _dns_getaddrinfo(void *rv, void *cb_data, va_list ap)
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 +1975,12 @@ _dns_getaddrinfo(void *rv, void *cb_data, va_list ap)
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..16ff0cb 100644
--- a/libc/netbsd/net/getnameinfo.c
+++ b/libc/netbsd/net/getnameinfo.c
@@ -98,8 +98,14 @@ struct sockinet {
u_short si_port;
};
+#if defined(ANDROID_CHANGES)
+static int getnameinfo_inet __P((const struct sockaddr *, socklen_t, char *,
+ socklen_t, char *, socklen_t, int, const char*));
+#else
static int getnameinfo_inet __P((const struct sockaddr *, socklen_t, char *,
socklen_t, char *, socklen_t, int));
+#endif
+
#ifdef INET6
static int ip6_parsenumeric __P((const struct sockaddr *, const char *, char *,
socklen_t, int));
@@ -122,15 +128,26 @@ static const int DnsProxyQueryResult = 222;
*/
int getnameinfo(const struct sockaddr* sa, socklen_t salen, char* host, size_t hostlen, char* serv, size_t servlen, int flags)
{
+#ifdef ANDROID_CHANGES
+ 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)
+{
+#endif /* ANDROID_CHANGES */
switch (sa->sa_family) {
case AF_INET:
case AF_INET6:
return getnameinfo_inet(sa, salen, host, hostlen,
+#ifdef ANDROID_CHANGES
+ serv, servlen, flags, iface);
+#else
serv, servlen, flags);
+#endif
#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;
@@ -143,108 +160,35 @@ int getnameinfo(const struct sockaddr* sa, socklen_t salen, char* host, size_t h
* 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) {
-
- int sock;
- const int one = 1;
- struct sockaddr_un proxy_addr;
- const char* cache_mode = getenv("ANDROID_DNS_MODE");
- FILE* proxy = NULL;
- int result = -1;
-
- 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;
- }
- // create socket
- sock = socket(AF_UNIX, SOCK_STREAM, 0);
- if (sock < 0) {
- return -1;
- }
-
- 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*) (void*) &proxy_addr,
- sizeof(proxy_addr))) != 0) {
- close(sock);
- return -1;
- }
-
- // send request to DnsProxyListener
- proxy = fdopen(sock,"r+");
- if (proxy == NULL) {
- goto exit;
- }
-
- char buf[INET6_ADDRSTRLEN]; // big enough for IPv4 and IPv6
- const char* addrStr = inet_ntop(addrFamily, addr, buf, sizeof(buf));
- if (addrStr == NULL) {
- goto exit;
- }
- if (fprintf(proxy, "gethostbyaddr %s %d %d", addrStr, addrLen, addrFamily) < 0) {
- goto exit;
- }
-
- // literal NULL byte at end, required by FrameworkListener
- if (fputc(0, proxy) == EOF || fflush(proxy) != 0) {
- goto exit;
- }
-
- result = 0;
- char msg_buf[4];
- // read result code for gethostbyaddr
- if (fread(msg_buf, 1, sizeof(msg_buf), proxy) != sizeof(msg_buf)) {
- goto exit;
- }
-
- int result_code = (int)strtol(msg_buf, NULL, 10);
- // verify the code itself
- if (result_code != DnsProxyQueryResult) {
- goto exit;
- }
-
- uint32_t name_len;
- if (fread(&name_len, sizeof(name_len), 1, proxy) != 1) {
- goto exit;
- }
-
- name_len = ntohl(name_len);
- if (name_len <= 0 || name_len >= nameBufLen) {
- goto exit;
- }
-
- if (fread(nameBuf, name_len, 1, proxy) != 1) {
- goto exit;
- }
+android_gethostbyaddr_proxy(char* nameBuf, size_t nameBufLen, const void *addr, socklen_t addrLen, int addrFamily, const char* iface)
+{
+ struct hostent *hostResult =
+ android_gethostbyaddrforiface_proxy(addr, addrLen, addrFamily, iface);
- result = name_len;
+ if (hostResult == NULL) return 0;
- exit:
- if (proxy != NULL) {
- fclose(proxy);
- }
+ int lengthResult = strlen(hostResult->h_name);
- return result;
+ if (nameBuf) strncpy(nameBuf, hostResult->h_name, nameBufLen);
+ return lengthResult;
}
#endif
/*
* getnameinfo_inet():
* Format an IPv4 or IPv6 sockaddr into a printable string.
*/
+#ifdef ANDROID_CHANGES
+static int
+getnameinfo_inet(sa, salen, host, hostlen, serv, servlen, flags, iface)
+ const struct sockaddr *sa;
+ socklen_t salen;
+ char *host;
+ socklen_t hostlen;
+ char *serv;
+ socklen_t servlen;
+ int flags;
+ const char* iface;
+#else
static int
getnameinfo_inet(sa, salen, host, hostlen, serv, servlen, flags)
const struct sockaddr *sa;
@@ -254,6 +198,7 @@ getnameinfo_inet(sa, salen, host, hostlen, serv, servlen, flags)
char *serv;
socklen_t servlen;
int flags;
+#endif
{
const struct afd *afd;
struct servent *sp;
@@ -398,14 +343,14 @@ getnameinfo_inet(sa, salen, host, hostlen, serv, servlen, flags)
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 afc9a36..08a2557 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.
*
@@ -1249,9 +1250,16 @@ typedef struct resolv_cache_info {
struct resolv_cache_info* next;
char* nameservers[MAXNS +1];
struct addrinfo* nsaddrinfo[MAXNS + 1];
- char* domains;
+ 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
@@ -1304,6 +1312,7 @@ _cache_check_pending_request_locked( struct resolv_cache* cache, Entry* key )
}
} else {
struct timespec ts = {0,0};
+ XLOG("Waiting for previous request");
ts.tv_sec = _time_now() + PENDING_REQUEST_TIMEOUT;
pthread_cond_timedwait(&ri->cond, &cache->lock, &ts);
}
@@ -1399,9 +1408,8 @@ _res_cache_get_max_entries( void )
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) {
@@ -1540,7 +1548,7 @@ _cache_lookup_p( Cache* cache,
pnode = &node->hlink;
}
- return pnode;
+ return pnode;
}
/* Add a new entry to the hash table. 'lookup' must be the
@@ -1781,20 +1789,28 @@ Exit:
/****************************************************************************/
/****************************************************************************/
-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 */
@@ -1815,8 +1831,14 @@ static int _get_nameserver_locked(const char* ifname, int n, char* addr, int add
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)
@@ -1830,37 +1852,36 @@ _res_cache_init(void)
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;
}
@@ -2016,11 +2037,29 @@ _find_cache_info_locked(const char* ifname)
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)
{
@@ -2044,16 +2083,19 @@ _resolv_set_nameservers_for_iface(const char* ifname, char** servers, int numser
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);
@@ -2069,15 +2111,68 @@ _resolv_set_nameservers_for_iface(const char* ifname, char** servers, int numser
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;
}
}
- cache_info->domains = strdup(domains);
+
+ // 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)
{
@@ -2220,3 +2315,196 @@ _get_addr_locked(const char * ifname)
}
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(); // never null, but may be empty
+
+ // if default interface not set. Get first cache with an interface
+ if (ifname[0] == '\0') {
+ ifname = _find_any_iface_name_locked(); // may be null
+ }
+
+ // if we got the default iface or if (no-default) the find_any call gave an answer
+ 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) {
+ pthread_mutex_unlock(&_res_cache_list_lock);
+ 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 @@ extern struct __res_state _nres;
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 @@ __RCSID("$NetBSD: res_init.c,v 1.8 2006/03/19 03:10:08 christos Exp $");
/* 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 @@ res_ninit(res_state statp) {
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 @@ __res_vinit(res_state statp, int preinit) {
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 @@ __res_vinit(res_state statp, int preinit) {
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 @@ res_getservers(res_state statp, union res_sockaddr_union *set, int cnt) {
}
#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);
- }
- }
- 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;
+ 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;
- } else {
- return 0;
}
}
#endif /* ANDROID_CHANGES */
diff --git a/libc/netbsd/resolv/res_send.c b/libc/netbsd/resolv/res_send.c
index f3ee539..ceb2c77 100644
--- a/libc/netbsd/resolv/res_send.c
+++ b/libc/netbsd/resolv/res_send.c
@@ -370,10 +370,13 @@ res_nsend(res_state statp,
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,17 +388,27 @@ res_nsend(res_state statp,
terrno = ETIMEDOUT;
#if USE_RESOLV_CACHE
- cache = __get_res_cache();
- if (cache != NULL) {
- int anslen = 0;
- cache_status = _resolv_cache_lookup(
- cache, buf, buflen,
- ans, anssiz, &anslen);
-
- if (cache_status == RESOLV_CACHE_FOUND) {
- return anslen;
- }
- }
+ // get the cache associated with the interface
+ cache = __get_res_cache(statp->iface);
+ if (cache != NULL) {
+ int anslen = 0;
+ cache_status = _resolv_cache_lookup(
+ cache, buf, buflen,
+ ans, anssiz, &anslen);
+
+ 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 @@ extern struct in_addr* _resolv_get_addr_of_default_iface();
/* 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 3fe586e..bf5abad 100644
--- a/libc/private/resolv_iface.h
+++ b/libc/private/resolv_iface.h
@@ -60,6 +60,21 @@ extern void _resolv_flush_cache_for_default_iface();
/* 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_sym {
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 @@ void res_setservers(res_state,
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