Merge changes I6059b68e,I11a7257a
* changes:
Add new info functions to resolver for use by Netd.
Store DNS server count in resolv_cache.
diff --git a/libc/dns/include/resolv_netid.h b/libc/dns/include/resolv_netid.h
index 09c5498..266193a 100644
--- a/libc/dns/include/resolv_netid.h
+++ b/libc/dns/include/resolv_netid.h
@@ -87,8 +87,8 @@
const struct android_net_context *, struct addrinfo **) __used_in_netd;
/* set name servers for a network */
-extern void _resolv_set_nameservers_for_net(unsigned netid, const char** servers, int numservers,
- const char *domains, const struct __res_params* params) __used_in_netd;
+extern int _resolv_set_nameservers_for_net(unsigned netid, const char** servers,
+ unsigned numservers, const char *domains, const struct __res_params* params) __used_in_netd;
/* flush the cache associated with a certain network */
extern void _resolv_flush_cache_for_net(unsigned netid) __used_in_netd;
diff --git a/libc/dns/include/resolv_params.h b/libc/dns/include/resolv_params.h
index 353ae4d..5ee265f 100644
--- a/libc/dns/include/resolv_params.h
+++ b/libc/dns/include/resolv_params.h
@@ -20,11 +20,13 @@
#include <stdint.h>
/* Hard-coded defines */
-#define MAXNS 3 /* max # name servers we'll track */
-#define MAXNSSAMPLES 64 /* max # samples to store per server */
+#define MAXNS 4 /* max # name servers we'll track */
+#define MAXDNSRCH 6 /* max # domains in search path */
+#define MAXDNSRCHPATH 256 /* max length of domain search paths */
+#define MAXNSSAMPLES 64 /* max # samples to store per server */
/* Defaults used for initializing __res_params */
-#define SUCCESS_THRESHOLD 75 /* if successes * 100 / total_samples is less than
+#define SUCCESS_THRESHOLD 75 /* if successes * 100 / total_samples is less than
* this value, the server is considered failing
*/
#define NSSAMPLE_VALIDITY 1800 /* Sample validity in seconds.
diff --git a/libc/dns/include/resolv_private.h b/libc/dns/include/resolv_private.h
index 8cdcc2e..3ab8ea6 100644
--- a/libc/dns/include/resolv_private.h
+++ b/libc/dns/include/resolv_private.h
@@ -140,7 +140,6 @@
* Global defines and variables for resolver stub.
*/
#define MAXDFLSRCH 3 /* # default domain levels to try */
-#define MAXDNSRCH 6 /* max # domains in search path */
#define LOCALDOMAINPARTS 2 /* min levels in name that is "local" */
#define RES_TIMEOUT 5 /* min. seconds between retries */
diff --git a/libc/dns/include/resolv_stats.h b/libc/dns/include/resolv_stats.h
index aaf6bd8..c7901d7 100644
--- a/libc/dns/include/resolv_stats.h
+++ b/libc/dns/include/resolv_stats.h
@@ -17,6 +17,7 @@
#ifndef _RES_STATS_H
#define _RES_STATS_H
+#include <sys/socket.h>
#include <stdbool.h>
#include <stdint.h>
#include <time.h>
@@ -46,18 +47,13 @@
};
/* Calculate the round-trip-time from start time t0 and end time t1. */
-int
+extern int
_res_stats_calculate_rtt(const struct timespec* t1, const struct timespec* t0);
/* Initialize a sample for calculating server reachability statistics. */
extern void
_res_stats_set_sample(struct __res_sample* sample, time_t now, int rcode, int rtt);
-/* Aggregates the reachability statistics for the given server based on on the stored samples. */
-extern void
-_res_stats_aggregate(struct __res_stats* stats, int* successes, int* errors, int* timeouts,
- int* internal_errors, int* rtt_avg, time_t* last_sample_time);
-
/* Returns true if the server is considered unusable, i.e. if the success rate is not lower than the
* threshold for the stored stored samples. If not enough samples are stored, the server is
* considered usable.
@@ -65,9 +61,24 @@
extern bool
_res_stats_usable_server(const struct __res_params* params, struct __res_stats* stats);
+__BEGIN_DECLS
+/* Aggregates the reachability statistics for the given server based on on the stored samples. */
+extern void
+android_net_res_stats_aggregate(struct __res_stats* stats, int* successes, int* errors,
+ int* timeouts, int* internal_errors, int* rtt_avg, time_t* last_sample_time)
+ __attribute__((visibility ("default")));
+
+extern int
+android_net_res_stats_get_info_for_net(unsigned netid, int* nscount,
+ struct sockaddr_storage servers[MAXNS], int* dcount, char domains[MAXDNSRCH][MAXDNSRCHPATH],
+ struct __res_params* params, struct __res_stats stats[MAXNS])
+ __attribute__((visibility ("default")));
+
/* Returns an array of bools indicating which servers are considered good */
extern void
-_res_stats_get_usable_servers(const struct __res_params* params, struct __res_stats stats[],
- int nscount, bool valid_servers[]);
+android_net_res_stats_get_usable_servers(const struct __res_params* params,
+ struct __res_stats stats[], int nscount, bool valid_servers[])
+ __attribute__((visibility ("default")));
+__END_DECLS
#endif // _RES_STATS_H
diff --git a/libc/dns/resolv/res_cache.c b/libc/dns/resolv/res_cache.c
index 15f9aa4..02887f2 100644
--- a/libc/dns/resolv/res_cache.c
+++ b/libc/dns/resolv/res_cache.c
@@ -27,6 +27,7 @@
*/
#include "resolv_cache.h"
+
#include <resolv.h>
#include <stdarg.h>
#include <stdio.h>
@@ -1228,19 +1229,17 @@
PendingReqInfo pending_requests;
} Cache;
-// The nameservers[], nsaddrinfo[] and nsstats[] are containing MAXNS + 1 elements, because the
-// number of nameservers is not known and the code relies on the n+1-st entry to be null to
-// recognize the end.
struct resolv_cache_info {
unsigned netid;
Cache* cache;
struct resolv_cache_info* next;
- char* nameservers[MAXNS + 1];
- struct addrinfo* nsaddrinfo[MAXNS + 1];
+ int nscount;
+ char* nameservers[MAXNS];
+ struct addrinfo* nsaddrinfo[MAXNS];
int revision_id; // # times the nameservers have been replaced
struct __res_params params;
- struct __res_stats nsstats[MAXNS + 1];
- char defdname[256];
+ struct __res_stats nsstats[MAXNS];
+ char defdname[MAXDNSRCHPATH];
int dnsrch_offset[MAXDNSRCH+1]; // offsets into defdname
};
@@ -1949,15 +1948,40 @@
params->max_samples = 0;
}
-void
-_resolv_set_nameservers_for_net(unsigned netid, const char** servers, int numservers,
+int
+_resolv_set_nameservers_for_net(unsigned netid, const char** servers, unsigned numservers,
const char *domains, const struct __res_params* params)
{
- int i, rt, index;
- struct addrinfo hints;
char sbuf[NI_MAXSERV];
register char *cp;
int *offset;
+ struct addrinfo* nsaddrinfo[MAXNS];
+
+ if (numservers > MAXNS) {
+ XLOG("%s: numservers=%u, MAXNS=%u", __FUNCTION__, numservers, MAXNS);
+ return E2BIG;
+ }
+
+ // Parse the addresses before actually locking or changing any state, in case there is an error.
+ // As a side effect this also reduces the time the lock is kept.
+ struct addrinfo hints = {
+ .ai_family = AF_UNSPEC,
+ .ai_socktype = SOCK_DGRAM,
+ .ai_flags = AI_NUMERICHOST
+ };
+ snprintf(sbuf, sizeof(sbuf), "%u", NAMESERVER_PORT);
+ for (unsigned i = 0; i < numservers; i++) {
+ // The addrinfo structures allocated here are freed in _free_nameservers_locked().
+ int rt = getaddrinfo(servers[i], sbuf, &hints, &nsaddrinfo[i]);
+ if (rt != 0) {
+ for (unsigned j = 0 ; j < i ; j++) {
+ freeaddrinfo(nsaddrinfo[j]);
+ nsaddrinfo[j] = NULL;
+ }
+ XLOG("%s: getaddrinfo(%s)=%s", __FUNCTION__, servers[i], gai_strerror(rt));
+ return EINVAL;
+ }
+ }
pthread_once(&_res_cache_once, _res_cache_init);
pthread_mutex_lock(&_res_cache_list_lock);
@@ -1978,24 +2002,13 @@
if (!_resolv_is_nameservers_equal_locked(cache_info, servers, numservers)) {
// free current before adding new
_free_nameservers_locked(cache_info);
-
- memset(&hints, 0, sizeof(hints));
- hints.ai_family = PF_UNSPEC;
- hints.ai_socktype = SOCK_DGRAM; /*dummy*/
- hints.ai_flags = AI_NUMERICHOST;
- snprintf(sbuf, sizeof(sbuf), "%u", NAMESERVER_PORT);
-
- index = 0;
- for (i = 0; i < numservers && i < MAXNS; i++) {
- rt = getaddrinfo(servers[i], sbuf, &hints, &cache_info->nsaddrinfo[index]);
- if (rt == 0) {
- cache_info->nameservers[index] = strdup(servers[i]);
- index++;
- XLOG("%s: netid = %u, addr = %s\n", __FUNCTION__, netid, servers[i]);
- } else {
- cache_info->nsaddrinfo[index] = NULL;
- }
+ unsigned i;
+ for (i = 0; i < numservers; i++) {
+ cache_info->nsaddrinfo[i] = nsaddrinfo[i];
+ cache_info->nameservers[i] = strdup(servers[i]);
+ XLOG("%s: netid = %u, addr = %s\n", __FUNCTION__, netid, servers[i]);
}
+ cache_info->nscount = numservers;
// code moved from res_init.c, load_domain_search_list
strlcpy(cache_info->defdname, domains, sizeof(cache_info->defdname));
@@ -2040,26 +2053,16 @@
}
pthread_mutex_unlock(&_res_cache_list_lock);
+ return 0;
}
static int
_resolv_is_nameservers_equal_locked(struct resolv_cache_info* cache_info,
const char** servers, int numservers)
{
- int i;
- char** ns;
- int currentservers;
- int equal = 1;
-
- if (numservers > MAXNS) numservers = MAXNS;
-
- // Find out how many nameservers we had before.
- currentservers = 0;
- for (ns = cache_info->nameservers; *ns; ns++)
- currentservers++;
-
- if (currentservers != numservers)
+ if (cache_info->nscount != numservers) {
return 0;
+ }
// Compare each name server against current name servers.
// TODO: this is incorrect if the list of current or previous nameservers
@@ -2067,26 +2070,25 @@
// filters out duplicates, but we should probably fix it. It's also
// insensitive to the order of the nameservers; we should probably fix that
// too.
- for (i = 0; i < numservers && equal; i++) {
- ns = cache_info->nameservers;
- equal = 0;
- while(*ns) {
- if (strcmp(*ns, servers[i]) == 0) {
- equal = 1;
+ for (int i = 0; i < numservers; i++) {
+ for (int j = 0 ; ; j++) {
+ if (j >= numservers) {
+ return 0;
+ }
+ if (strcmp(cache_info->nameservers[i], servers[j]) == 0) {
break;
}
- ns++;
}
}
- return equal;
+ return 1;
}
static void
_free_nameservers_locked(struct resolv_cache_info* cache_info)
{
int i;
- for (i = 0; i <= MAXNS; i++) {
+ for (i = 0; i < cache_info->nscount; i++) {
free(cache_info->nameservers[i]);
cache_info->nameservers[i] = NULL;
if (cache_info->nsaddrinfo[i] != NULL) {
@@ -2096,6 +2098,7 @@
cache_info->nsstats[i].sample_count =
cache_info->nsstats[i].sample_next = 0;
}
+ cache_info->nscount = 0;
_res_cache_clear_stats_locked(cache_info);
++cache_info->revision_id;
}
@@ -2180,9 +2183,70 @@
}
int
+android_net_res_stats_get_info_for_net(unsigned netid, int* nscount,
+ struct sockaddr_storage servers[MAXNS], int* dcount, char domains[MAXDNSRCH][MAXDNSRCHPATH],
+ struct __res_params* params, struct __res_stats stats[MAXNS]) {
+ int revision_id = -1;
+ pthread_mutex_lock(&_res_cache_list_lock);
+
+ struct resolv_cache_info* info = _find_cache_info_locked(netid);
+ if (info) {
+ if (info->nscount > MAXNS) {
+ pthread_mutex_unlock(&_res_cache_list_lock);
+ XLOG("%s: nscount %d > MAXNS %d", __FUNCTION__, info->nscount, MAXNS);
+ errno = EFAULT;
+ return -1;
+ }
+ int i;
+ for (i = 0; i < info->nscount; i++) {
+ // Verify that the following assumptions are held, failure indicates corruption:
+ // - getaddrinfo() may never return a sockaddr > sockaddr_storage
+ // - all addresses are valid
+ // - there is only one address per addrinfo thanks to numeric resolution
+ int addrlen = info->nsaddrinfo[i]->ai_addrlen;
+ if (addrlen < (int) sizeof(struct sockaddr) ||
+ addrlen > (int) sizeof(servers[0])) {
+ pthread_mutex_unlock(&_res_cache_list_lock);
+ XLOG("%s: nsaddrinfo[%d].ai_addrlen == %d", __FUNCTION__, i, addrlen);
+ errno = EMSGSIZE;
+ return -1;
+ }
+ if (info->nsaddrinfo[i]->ai_addr == NULL) {
+ pthread_mutex_unlock(&_res_cache_list_lock);
+ XLOG("%s: nsaddrinfo[%d].ai_addr == NULL", __FUNCTION__, i);
+ errno = ENOENT;
+ return -1;
+ }
+ if (info->nsaddrinfo[i]->ai_next != NULL) {
+ pthread_mutex_unlock(&_res_cache_list_lock);
+ XLOG("%s: nsaddrinfo[%d].ai_next != NULL", __FUNCTION__, i);
+ errno = ENOTUNIQ;
+ return -1;
+ }
+ }
+ *nscount = info->nscount;
+ for (i = 0; i < info->nscount; i++) {
+ memcpy(&servers[i], info->nsaddrinfo[i]->ai_addr, info->nsaddrinfo[i]->ai_addrlen);
+ stats[i] = info->nsstats[i];
+ }
+ for (i = 0; i < MAXDNSRCH; i++) {
+ if (info->dnsrch_offset[i] == -1) {
+ break;
+ }
+ strlcpy(domains[i], info->defdname + info->dnsrch_offset[i], MAXDNSRCHPATH);
+ }
+ *dcount = i;
+ *params = info->params;
+ revision_id = info->revision_id;
+ }
+
+ pthread_mutex_unlock(&_res_cache_list_lock);
+ return revision_id;
+}
+
+int
_resolv_cache_get_resolver_stats( unsigned netid, struct __res_params* params,
struct __res_stats stats[MAXNS]) {
-
int revision_id = -1;
pthread_mutex_lock(&_res_cache_list_lock);
diff --git a/libc/dns/resolv/res_send.c b/libc/dns/resolv/res_send.c
index 9ceeeb7..0e30b28 100644
--- a/libc/dns/resolv/res_send.c
+++ b/libc/dns/resolv/res_send.c
@@ -488,11 +488,12 @@
* Send request, RETRY times, or until successful.
*/
for (try = 0; try < statp->retry; try++) {
- struct __res_stats stats[MAXNS + 1];
+ struct __res_stats stats[MAXNS];
struct __res_params params;
int revision_id = _resolv_cache_get_resolver_stats(statp->netid, ¶ms, stats);
- bool usable_servers[MAXNS + 1];
- _res_stats_get_usable_servers(¶ms, stats, statp->nscount, usable_servers);
+ bool usable_servers[MAXNS];
+ android_net_res_stats_get_usable_servers(¶ms, stats, statp->nscount,
+ usable_servers);
for (ns = 0; ns < statp->nscount; ns++) {
if (!usable_servers[ns]) continue;
diff --git a/libc/dns/resolv/res_state.c b/libc/dns/resolv/res_state.c
index afccd99..0e02a8f 100644
--- a/libc/dns/resolv/res_state.c
+++ b/libc/dns/resolv/res_state.c
@@ -128,7 +128,7 @@
rt->_pi = (struct prop_info*) __system_property_find("net.change");
if (rt->_pi == NULL) {
/* Still nothing, return current state */
- D("%s: exiting for tid=%d rt=%d since system property not found",
+ D("%s: exiting for tid=%d rt=%p since system property not found",
__FUNCTION__, gettid(), rt);
return rt;
}
diff --git a/libc/dns/resolv/res_stats.c b/libc/dns/resolv/res_stats.c
index 5cc592e..99c79e4 100644
--- a/libc/dns/resolv/res_stats.c
+++ b/libc/dns/resolv/res_stats.c
@@ -54,8 +54,8 @@
/* Aggregates the reachability statistics for the given server based on on the stored samples. */
void
-_res_stats_aggregate(struct __res_stats* stats, int* successes, int* errors, int* timeouts,
- int* internal_errors, int* rtt_avg, time_t* last_sample_time)
+android_net_res_stats_aggregate(struct __res_stats* stats, int* successes, int* errors,
+ int* timeouts, int* internal_errors, int* rtt_avg, time_t* last_sample_time)
{
int s = 0; // successes
int e = 0; // errors
@@ -123,8 +123,8 @@
int internal_errors = -1;
int rtt_avg = -1;
time_t last_sample_time = 0;
- _res_stats_aggregate(stats, &successes, &errors, &timeouts, &internal_errors, &rtt_avg,
- &last_sample_time);
+ android_net_res_stats_aggregate(stats, &successes, &errors, &timeouts, &internal_errors,
+ &rtt_avg, &last_sample_time);
if (successes >= 0 && errors >= 0 && timeouts >= 0) {
int total = successes + errors + timeouts;
if (DBG) {
@@ -164,8 +164,8 @@
}
void
-_res_stats_get_usable_servers(const struct __res_params* params, struct __res_stats stats[],
- int nscount, bool usable_servers[]) {
+android_net_res_stats_get_usable_servers(const struct __res_params* params,
+ struct __res_stats stats[], int nscount, bool usable_servers[]) {
unsigned usable_servers_found = 0;
for (int ns = 0; ns < nscount; ns++) {
bool usable = _res_stats_usable_server(params, &stats[ns]);
diff --git a/libc/libc.arm.brillo.map b/libc/libc.arm.brillo.map
index 541dbb2..b0c8299 100644
--- a/libc/libc.arm.brillo.map
+++ b/libc/libc.arm.brillo.map
@@ -1468,3 +1468,10 @@
SHA1Transform; # arm x86 mips
SHA1Update; # arm x86 mips
} LIBC_O;
+
+LIBC_PLATFORM {
+ global:
+ android_net_res_stats_get_info_for_net;
+ android_net_res_stats_aggregate;
+ android_net_res_stats_get_usable_servers;
+} LIBC_O;
diff --git a/libc/libc.arm.map b/libc/libc.arm.map
index 1784b95..7a3b8bd 100644
--- a/libc/libc.arm.map
+++ b/libc/libc.arm.map
@@ -1507,3 +1507,10 @@
wait3; # arm x86 mips nobrillo
wcswcs; # arm x86 mips nobrillo
} LIBC_O;
+
+LIBC_PLATFORM {
+ global:
+ android_net_res_stats_get_info_for_net;
+ android_net_res_stats_aggregate;
+ android_net_res_stats_get_usable_servers;
+} LIBC_O;
diff --git a/libc/libc.arm64.map b/libc/libc.arm64.map
index 7daa557..217d95e 100644
--- a/libc/libc.arm64.map
+++ b/libc/libc.arm64.map
@@ -1222,3 +1222,10 @@
get_malloc_leak_info;
gMallocLeakZygoteChild;
} LIBC_O;
+
+LIBC_PLATFORM {
+ global:
+ android_net_res_stats_get_info_for_net;
+ android_net_res_stats_aggregate;
+ android_net_res_stats_get_usable_servers;
+} LIBC_O;
diff --git a/libc/libc.map.txt b/libc/libc.map.txt
index f51c5d3..c7f9058 100644
--- a/libc/libc.map.txt
+++ b/libc/libc.map.txt
@@ -1533,3 +1533,10 @@
wait3; # arm x86 mips nobrillo
wcswcs; # arm x86 mips nobrillo
} LIBC_O;
+
+LIBC_PLATFORM {
+ global:
+ android_net_res_stats_get_info_for_net;
+ android_net_res_stats_aggregate;
+ android_net_res_stats_get_usable_servers;
+} LIBC_O;
diff --git a/libc/libc.mips.brillo.map b/libc/libc.mips.brillo.map
index 953fc29..2b92162 100644
--- a/libc/libc.mips.brillo.map
+++ b/libc/libc.mips.brillo.map
@@ -1309,3 +1309,10 @@
SHA1Transform; # arm x86 mips
SHA1Update; # arm x86 mips
} LIBC_O;
+
+LIBC_PLATFORM {
+ global:
+ android_net_res_stats_get_info_for_net;
+ android_net_res_stats_aggregate;
+ android_net_res_stats_get_usable_servers;
+} LIBC_O;
diff --git a/libc/libc.mips.map b/libc/libc.mips.map
index 90db79d..934b23b 100644
--- a/libc/libc.mips.map
+++ b/libc/libc.mips.map
@@ -1348,3 +1348,10 @@
wait3; # arm x86 mips nobrillo
wcswcs; # arm x86 mips nobrillo
} LIBC_O;
+
+LIBC_PLATFORM {
+ global:
+ android_net_res_stats_get_info_for_net;
+ android_net_res_stats_aggregate;
+ android_net_res_stats_get_usable_servers;
+} LIBC_O;
diff --git a/libc/libc.mips64.map b/libc/libc.mips64.map
index 7daa557..217d95e 100644
--- a/libc/libc.mips64.map
+++ b/libc/libc.mips64.map
@@ -1222,3 +1222,10 @@
get_malloc_leak_info;
gMallocLeakZygoteChild;
} LIBC_O;
+
+LIBC_PLATFORM {
+ global:
+ android_net_res_stats_get_info_for_net;
+ android_net_res_stats_aggregate;
+ android_net_res_stats_get_usable_servers;
+} LIBC_O;
diff --git a/libc/libc.x86.brillo.map b/libc/libc.x86.brillo.map
index 9f6cc52..d973ac1 100644
--- a/libc/libc.x86.brillo.map
+++ b/libc/libc.x86.brillo.map
@@ -1308,3 +1308,10 @@
SHA1Transform; # arm x86 mips
SHA1Update; # arm x86 mips
} LIBC_O;
+
+LIBC_PLATFORM {
+ global:
+ android_net_res_stats_get_info_for_net;
+ android_net_res_stats_aggregate;
+ android_net_res_stats_get_usable_servers;
+} LIBC_O;
diff --git a/libc/libc.x86.map b/libc/libc.x86.map
index 4443731..b3f9394 100644
--- a/libc/libc.x86.map
+++ b/libc/libc.x86.map
@@ -1347,3 +1347,10 @@
wait3; # arm x86 mips nobrillo
wcswcs; # arm x86 mips nobrillo
} LIBC_O;
+
+LIBC_PLATFORM {
+ global:
+ android_net_res_stats_get_info_for_net;
+ android_net_res_stats_aggregate;
+ android_net_res_stats_get_usable_servers;
+} LIBC_O;
diff --git a/libc/libc.x86_64.map b/libc/libc.x86_64.map
index 7daa557..217d95e 100644
--- a/libc/libc.x86_64.map
+++ b/libc/libc.x86_64.map
@@ -1222,3 +1222,10 @@
get_malloc_leak_info;
gMallocLeakZygoteChild;
} LIBC_O;
+
+LIBC_PLATFORM {
+ global:
+ android_net_res_stats_get_info_for_net;
+ android_net_res_stats_aggregate;
+ android_net_res_stats_get_usable_servers;
+} LIBC_O;