Ignore unreliable DNS servers.
Collect statistics about DNS query success state and delay. Ignore
servers that have been tried at least five times and have a success rate
of < 0.25. Retry these servers once every 180s.
Bug: 25731675
Change-Id: I78e24f43e388dca82fb81835e1796f4c7dce8da3
diff --git a/libc/dns/include/resolv_netid.h b/libc/dns/include/resolv_netid.h
index d364645..09c5498 100644
--- a/libc/dns/include/resolv_netid.h
+++ b/libc/dns/include/resolv_netid.h
@@ -49,6 +49,7 @@
__BEGIN_DECLS
+struct __res_params;
struct addrinfo;
#define __used_in_netd __attribute__((visibility ("default")))
@@ -86,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) __used_in_netd;
+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;
/* 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
new file mode 100644
index 0000000..353ae4d
--- /dev/null
+++ b/libc/dns/include/resolv_params.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _RESOLV_PARAMS_H
+#define _RESOLV_PARAMS_H
+
+#include <stdint.h>
+
+/* Hard-coded defines */
+#define MAXNS 3 /* max # name servers we'll track */
+#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
+ * this value, the server is considered failing
+ */
+#define NSSAMPLE_VALIDITY 1800 /* Sample validity in seconds.
+ * Set to -1 to disable skipping failing
+ * servers.
+ */
+
+/* per-netid configuration parameters passed from netd to the resolver */
+struct __res_params {
+ uint16_t sample_validity; // sample lifetime in s
+ // threshold of success / total samples below which a server is considered broken
+ uint8_t success_threshold; // 0: disable, value / 100 otherwise
+ uint8_t min_samples; // min # samples needed for statistics to be considered meaningful
+ uint8_t max_samples; // max # samples taken into account for statistics
+} __attribute__((__packed__));
+
+#endif // _RESOLV_PARAMS_H
diff --git a/libc/dns/include/resolv_private.h b/libc/dns/include/resolv_private.h
index 9484d0e..8cdcc2e 100644
--- a/libc/dns/include/resolv_private.h
+++ b/libc/dns/include/resolv_private.h
@@ -58,7 +58,10 @@
#include <resolv.h>
#include "resolv_static.h"
+#include "resolv_params.h"
+#include "resolv_stats.h"
#include <net/if.h>
+#include <time.h>
/* Despite this file's name, it's part of libresolv. On Android, that means it's part of libc :-( */
#pragma GCC visibility push(default)
@@ -136,7 +139,6 @@
/*
* Global defines and variables for resolver stub.
*/
-#define MAXNS 3 /* max # name servers we'll track */
#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" */
@@ -205,6 +207,24 @@
typedef struct __res_state *res_state;
+/* Retrieve a local copy of the stats for the given netid. The buffer must have space for
+ * MAXNS __resolver_stats. Returns the revision id of the resolvers used.
+ */
+__LIBC_HIDDEN__
+extern int
+_resolv_cache_get_resolver_stats( unsigned netid, struct __res_params* params,
+ struct __res_stats stats[MAXNS]);
+
+/* Add a sample to the shared struct for the given netid and server, provided that the
+ * revision_id of the stored servers has not changed.
+ */
+__LIBC_HIDDEN__
+extern void
+_resolv_cache_add_resolver_stats_sample( unsigned netid, int revision_id, int ns,
+ const struct __res_sample* sample, int max_samples);
+
+/* End of stats related definitions */
+
union res_sockaddr_union {
struct sockaddr_in sin;
#ifdef IN6ADDR_ANY_INIT
diff --git a/libc/dns/include/resolv_stats.h b/libc/dns/include/resolv_stats.h
new file mode 100644
index 0000000..2aab958
--- /dev/null
+++ b/libc/dns/include/resolv_stats.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _RES_STATS_H
+#define _RES_STATS_H
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <time.h>
+
+#include "resolv_params.h"
+
+#define RCODE_INTERNAL_ERROR 254
+#define RCODE_TIMEOUT 255
+
+/*
+ * Resolver reachability statistics and run-time parameters.
+ */
+
+struct __res_sample {
+ time_t at; // time in s at which the sample was recorded
+ uint16_t rtt; // round-trip time in ms
+ uint8_t rcode; // the DNS rcode or RCODE_XXX defined above
+};
+
+struct __res_stats {
+ // Stats of the last <sample_count> queries.
+ struct __res_sample samples[MAXNSSAMPLES];
+ // The number of samples stored.
+ uint8_t sample_count;
+ // The next sample to modify.
+ uint8_t sample_next;
+};
+
+/* Calculate the round-trip-time from start time t0 and end time t1. */
+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.
+ */
+extern bool
+_res_stats_usable_server(const struct __res_params* params, struct __res_stats* stats);
+
+/* 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[MAXNS],
+ int nscount, bool valid_servers[MAXNS]);
+
+#endif // _RES_STATS_H