summaryrefslogtreecommitdiffstats
path: root/libc/netbsd/resolv
diff options
context:
space:
mode:
authorMattias Falk <mattias.falk@sonyericsson.com>2011-08-23 14:34:14 +0200
committerRobert Greenwalt <rgreenwalt@google.com>2013-02-07 09:40:16 -0800
commitc63e59039d28c352e3053bb81319e960c392dbd4 (patch)
treef19b68ec83b6e17201473b1ff197d9525e75a664 /libc/netbsd/resolv
parent8db7a4cb20a7e90feb981736c1618f91a27bfff8 (diff)
downloadbionic-c63e59039d28c352e3053bb81319e960c392dbd4.zip
bionic-c63e59039d28c352e3053bb81319e960c392dbd4.tar.gz
bionic-c63e59039d28c352e3053bb81319e960c392dbd4.tar.bz2
dns cache per interface iteration 2
name server addresses are read from the dns cache associated wih the interface on which the request shall be done. processes which has requested to issue dns request using specific interface are now proxied to netd. added methods to attach/detach a process to a specific dns cache/interface. added getaddrinfoforinface method which takes an interface as an argument. bug:4815099 bug:5465296 Change-Id: I7a8fe1980cdf99d4d296ddc5c6411f0c72162263
Diffstat (limited to 'libc/netbsd/resolv')
-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
5 files changed, 350 insertions, 184 deletions
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;