Expose DNS timeout error to netd
For resolver stats, RCODE_TIMEOUT has been used for catching DNS timeout
error. This change adds the Support for reporting NETD_RESOLV_TIMEOUT to
frameworks.
Also clean up res_data.cpp as these functions are not used.
- res_init
- res_mkquery
- res_query
- res_send
- res_search
Bug: 113916551
Test: as follows
- built and flash netd
- system/netd/tests/runtests.sh passed
- silently drop packets by iptables, the return error is correct
Change-Id: I62ba6759b519d42aef62ae5b756a3c1ae3cb00d8
diff --git a/resolv/res_send.cpp b/resolv/res_send.cpp
index 4c0ca1a..174f0c8 100644
--- a/resolv/res_send.cpp
+++ b/resolv/res_send.cpp
@@ -140,8 +140,6 @@
}
#endif // DEBUG
-typedef enum { res_goahead, res_nextns, res_modified, res_done, res_error } res_sendhookact;
-
static DnsTlsDispatcher sDnsTlsDispatcher;
static int get_salen(const struct sockaddr*);
@@ -156,7 +154,8 @@
static int connect_with_timeout(int sock, const struct sockaddr* nsap, socklen_t salen,
const struct timespec timeout);
static int retrying_poll(const int sock, short events, const struct timespec* finish);
-static res_sendhookact res_tls_send(res_state, const Slice query, const Slice answer, int* resplen);
+static int res_tls_send(res_state, const Slice query, const Slice answer, int* error,
+ bool* fallback);
/* BIONIC-BEGIN: implement source port randomization */
@@ -389,7 +388,7 @@
return (1);
}
-int res_nsend(res_state statp, const u_char* buf, int buflen, u_char* ans, int anssiz) {
+int res_nsend(res_state statp, const u_char* buf, int buflen, u_char* ans, int anssiz, int* rcode) {
int gotsomewhere, terrno, v_circuit, resplen, n;
ResolvCacheStatus cache_status = RESOLV_CACHE_UNSUPPORTED;
@@ -517,48 +516,31 @@
struct sockaddr* nsap;
int nsaplen;
time_t now = 0;
- int rcode = RCODE_INTERNAL_ERROR;
int delay = 0;
+ *rcode = RCODE_INTERNAL_ERROR;
nsap = get_nsaddr(statp, (size_t) ns);
nsaplen = get_salen(nsap);
statp->_flags &= ~RES_F_LASTMASK;
statp->_flags |= (ns << RES_F_LASTSHIFT);
same_ns:
- int done = 0, loops = 0;
-
- do {
- res_sendhookact act;
-
- // TODO: This function tries to query on all of private DNS servers. Putting
- // it here is strange since we should expect there is only one DNS server
- // being queried. Consider moving it to other reasonable place. In addition,
- // enum res_sendhookact can be removed.
- act = res_tls_send(statp, Slice(const_cast<u_char*>(buf), buflen),
- Slice(ans, anssiz), &resplen);
- switch (act) {
- case res_goahead:
- done = 1;
- break;
- case res_nextns:
- res_nclose(statp);
- goto next_ns;
- case res_done:
- if (cache_status == RESOLV_CACHE_NOTFOUND) {
- _resolv_cache_add(statp->netid, buf, buflen, ans, resplen);
- }
- return (resplen);
- case res_modified:
- /* give the hook another try */
- if (++loops < 42) /*doug adams*/
- break;
- [[fallthrough]];
- case res_error:
- [[fallthrough]];
- default:
- goto fail;
+ // TODO: Since we expect there is only one DNS server being queried here while this
+ // function tries to query all of private DNS servers. Consider moving it to other
+ // reasonable place. In addition, maybe add stats for private DNS.
+ if (!statp->use_local_nameserver) {
+ bool fallback = false;
+ resplen = res_tls_send(statp, Slice(const_cast<u_char*>(buf), buflen),
+ Slice(ans, anssiz), rcode, &fallback);
+ if (resplen > 0) {
+ if (cache_status == RESOLV_CACHE_NOTFOUND) {
+ _resolv_cache_add(statp->netid, buf, buflen, ans, resplen);
+ }
+ return resplen;
}
- } while (!done);
+ if (!fallback) {
+ goto fail;
+ }
+ }
[[maybe_unused]] static const int niflags = NI_NUMERICHOST | NI_NUMERICSERV;
[[maybe_unused]] char abuf[NI_MAXHOST];
@@ -571,7 +553,7 @@
/* Use VC; at most one attempt per server. */
attempt = statp->retry;
- n = send_vc(statp, ¶ms, buf, buflen, ans, anssiz, &terrno, ns, &now, &rcode,
+ n = send_vc(statp, ¶ms, buf, buflen, ans, anssiz, &terrno, ns, &now, rcode,
&delay);
/*
@@ -581,7 +563,7 @@
*/
if (attempt == 0) {
res_sample sample;
- _res_stats_set_sample(&sample, now, rcode, delay);
+ _res_stats_set_sample(&sample, now, *rcode, delay);
_resolv_cache_add_resolver_stats_sample(statp->netid, revision_id, ns, &sample,
params.max_samples);
}
@@ -596,12 +578,12 @@
VLOG << "using send_dg";
n = send_dg(statp, ¶ms, buf, buflen, ans, anssiz, &terrno, ns, &v_circuit,
- &gotsomewhere, &now, &rcode, &delay);
+ &gotsomewhere, &now, rcode, &delay);
/* Only record stats the first time we try a query. See above. */
if (attempt == 0) {
res_sample sample;
- _res_stats_set_sample(&sample, now, rcode, delay);
+ _res_stats_set_sample(&sample, now, *rcode, delay);
_resolv_cache_add_resolver_stats_sample(statp->netid, revision_id, ns, &sample,
params.max_samples);
}
@@ -719,7 +701,6 @@
u_char* ans, int anssiz, int* terrno, int ns, time_t* at, int* rcode,
int* delay) {
*at = time(NULL);
- *rcode = RCODE_INTERNAL_ERROR;
*delay = 0;
const HEADER* hp = (const HEADER*) (const void*) buf;
HEADER* anhp = (HEADER*) (void*) ans;
@@ -989,7 +970,6 @@
u_char* ans, int anssiz, int* terrno, int ns, int* v_circuit, int* gotsomewhere,
time_t* at, int* rcode, int* delay) {
*at = time(NULL);
- *rcode = RCODE_INTERNAL_ERROR;
*delay = 0;
const HEADER* hp = (const HEADER*) (const void*) buf;
HEADER* anhp = (HEADER*) (void*) ans;
@@ -1237,58 +1217,77 @@
}
}
-res_sendhookact res_tls_send(res_state statp, const Slice query, const Slice answer, int* resplen) {
+static int res_tls_send(res_state statp, const Slice query, const Slice answer, int* error,
+ bool* fallback) {
+ int resplen = 0;
const unsigned netId = statp->netid;
const unsigned mark = statp->_mark;
- // TLS bypass
- if (statp->use_local_nameserver) {
- return res_goahead;
+ PrivateDnsStatus privateDnsStatus = gPrivateDnsConfiguration.getStatus(netId);
+
+ if (privateDnsStatus.mode == PrivateDnsMode::OFF) {
+ *fallback = true;
+ return -1;
}
- const auto privateDnsStatus = gPrivateDnsConfiguration.getStatus(netId);
-
- if (privateDnsStatus.mode == PrivateDnsMode::OFF) return res_goahead;
-
if (privateDnsStatus.validatedServers.empty()) {
if (privateDnsStatus.mode == PrivateDnsMode::OPPORTUNISTIC) {
- return res_goahead;
+ *fallback = true;
+ return -1;
} else {
// Sleep and iterate some small number of times checking for the
// arrival of resolved and validated server IP addresses, instead
// of returning an immediate error.
- using namespace std::chrono_literals;
- std::this_thread::sleep_for(100ms);
- return res_modified;
+ for (int i = 0; i < 42; i++) {
+ std::this_thread::sleep_for(std::chrono::milliseconds(100));
+ if (!gPrivateDnsConfiguration.getStatus(netId).validatedServers.empty()) {
+ privateDnsStatus = gPrivateDnsConfiguration.getStatus(netId);
+ break;
+ }
+ }
+ if (privateDnsStatus.validatedServers.empty()) {
+ return -1;
+ }
}
}
VLOG << __func__ << ": performing query over TLS";
const auto response = sDnsTlsDispatcher.query(privateDnsStatus.validatedServers, mark, query,
- answer, resplen);
- if (response == DnsTlsTransport::Response::success) {
- VLOG << __func__ << ": success";
- return res_done;
- }
+ answer, &resplen);
- VLOG << __func__ << ": abort: TLS query failed: " << static_cast<int>(response);
+ VLOG << __func__ << ": TLS query result: " << static_cast<int>(response);
if (privateDnsStatus.mode == PrivateDnsMode::OPPORTUNISTIC) {
// In opportunistic mode, handle falling back to cleartext in some
// cases (DNS shouldn't fail if a validated opportunistic mode server
// becomes unreachable for some reason).
switch (response) {
+ case DnsTlsTransport::Response::success:
+ return resplen;
case DnsTlsTransport::Response::network_error:
+ // No need to set the error timeout here since it will fallback to UDP.
case DnsTlsTransport::Response::internal_error:
// Note: this will cause cleartext queries to be emitted, with
// all of the EDNS0 goodness enabled. Fingers crossed. :-/
- return res_goahead;
+ *fallback = true;
+ [[fallthrough]];
default:
- break;
+ return -1;
+ }
+ } else {
+ // Strict mode
+ switch (response) {
+ case DnsTlsTransport::Response::success:
+ return resplen;
+ case DnsTlsTransport::Response::network_error:
+ // This case happens when the query stored in DnsTlsTransport is expired since
+ // either 1) the query has been tried for 3 times but no response or 2) fail to
+ // establish the connection with the server.
+ *error = RCODE_TIMEOUT;
+ [[fallthrough]];
+ default:
+ return -1;
}
}
-
- // There was an internal error. Fail hard.
- return res_error;
}