Implement DoT revalidation
The revalidation starts from DnsTlsDispatcher which uses a counter
for counting the number of continuous network_error failures of a
DoT server. The mechanics works for private DNS opportunistic mode.
- Once the counter reaches dot_revalidation_threshold, DnsTlsDispatcher
sends a revalidation request to PrivateDnsConfiguration to validate
the DoT server.
- Once the counter reaches dot_xport_unusable_threshold, DnsTlsDispatcher
marks the transport of the DoT server as unusable. The DoT server
won't be used for at least 5 minutes.
DoT revalidation runs when the followings are met:
[1] the private DNS setting is opportunistic mode
[2] the requested DoT server is valid to be used on the network
[3] the requested DoT server is currently marked as Validation::success
The above mechanics runs when the feature flag "dot_revalidation_threshold"
is a positive and zon-zero value, and is -1 when the mechanics is
disabled.
Bug: 79727473
Test: atest when all the flags off
dot_revalidation_threshold: -1
dot_async_handshake: 0
dot_xport_unusable_threshold: -1
dot_maxtries: 3
parallel_lookup_sleep_time: 2
dot_connect_timeout_ms: 127000
parallel_lookup_release: 0
sort_nameservers: 0
keep_listening_udp: 0
Test: atest when all the flags on
dot_revalidation_threshold: 10
dot_async_handshake: 1
dot_xport_unusable_threshold: 20
dot_maxtries: 1
parallel_lookup_sleep_time: 2
dot_connect_timeout_ms: 10000
parallel_lookup_release: 1
sort_nameservers: 1
keep_listening_udp: 1
Change-Id: Id442529468d63156a9aebf30ea5f142dfa689a97
diff --git a/PrivateDnsConfiguration.cpp b/PrivateDnsConfiguration.cpp
index c8b070a..610d55b 100644
--- a/PrivateDnsConfiguration.cpp
+++ b/PrivateDnsConfiguration.cpp
@@ -110,14 +110,14 @@
if (needsValidation(server)) {
updateServerState(identity, Validation::in_process, netId);
- startValidation(server, netId);
+ startValidation(server, netId, false);
}
}
return 0;
}
-PrivateDnsStatus PrivateDnsConfiguration::getStatus(unsigned netId) {
+PrivateDnsStatus PrivateDnsConfiguration::getStatus(unsigned netId) const {
PrivateDnsStatus status{PrivateDnsMode::OFF, {}};
std::lock_guard guard(mPrivateDnsLock);
@@ -144,41 +144,55 @@
mPrivateDnsTransports.erase(netId);
}
-bool PrivateDnsConfiguration::requestValidation(unsigned netId, const DnsTlsServer& server,
- uint32_t mark) {
+base::Result<void> PrivateDnsConfiguration::requestValidation(unsigned netId,
+ const DnsTlsServer& server,
+ uint32_t mark) {
std::lock_guard guard(mPrivateDnsLock);
+
+ // Running revalidation requires to mark the server as in_process, which means the server
+ // won't be used until the validation passes. It's necessary and safe to run revalidation
+ // when in private DNS opportunistic mode, because there's a fallback mechanics even if
+ // all of the private DNS servers are in in_process state.
+ if (auto it = mPrivateDnsModes.find(netId); it == mPrivateDnsModes.end()) {
+ return Errorf("NetId not found in mPrivateDnsModes");
+ } else if (it->second != PrivateDnsMode::OPPORTUNISTIC) {
+ return Errorf("Private DNS setting is not opportunistic mode");
+ }
+
auto netPair = mPrivateDnsTransports.find(netId);
if (netPair == mPrivateDnsTransports.end()) {
- return false;
+ return Errorf("NetId not found in mPrivateDnsTransports");
}
auto& tracker = netPair->second;
const ServerIdentity identity = ServerIdentity(server);
auto it = tracker.find(identity);
if (it == tracker.end()) {
- return false;
+ return Errorf("Server was removed");
}
const DnsTlsServer& target = it->second;
- if (!target.active()) return false;
+ if (!target.active()) return Errorf("Server is not active");
- if (target.validationState() != Validation::success) return false;
+ if (target.validationState() != Validation::success) {
+ return Errorf("Server validation state mismatched");
+ }
// Don't run the validation if |mark| (from android_net_context.dns_mark) is different.
// This is to protect validation from running on unexpected marks.
// Validation should be associated with a mark gotten by system permission.
- if (target.mark != mark) return false;
+ if (target.mark != mark) return Errorf("Socket mark mismatched");
updateServerState(identity, Validation::in_process, netId);
- startValidation(target, netId);
- return true;
+ startValidation(target, netId, true);
+ return {};
}
-void PrivateDnsConfiguration::startValidation(const DnsTlsServer& server, unsigned netId)
- REQUIRES(mPrivateDnsLock) {
- // Note that capturing |server| and |netId| in this lambda create copies.
- std::thread validate_thread([this, server, netId] {
+void PrivateDnsConfiguration::startValidation(const DnsTlsServer& server, unsigned netId,
+ bool isRevalidation) REQUIRES(mPrivateDnsLock) {
+ // Note that capturing |server|, |netId|, and |isRevalidation| in this lambda create copies.
+ std::thread validate_thread([this, server, netId, isRevalidation] {
setThreadName(StringPrintf("TlsVerify_%u", netId).c_str());
// cat /proc/sys/net/ipv4/tcp_syn_retries yields "6".
@@ -208,7 +222,9 @@
LOG(WARNING) << "validateDnsTlsServer returned " << success << " for "
<< server.toIpString();
- const bool needs_reeval = this->recordPrivateDnsValidation(server, netId, success);
+ const bool needs_reeval =
+ this->recordPrivateDnsValidation(server, netId, success, isRevalidation);
+
if (!needs_reeval) {
break;
}
@@ -254,7 +270,7 @@
}
bool PrivateDnsConfiguration::recordPrivateDnsValidation(const DnsTlsServer& server, unsigned netId,
- bool success) {
+ bool success, bool isRevalidation) {
constexpr bool NEEDS_REEVALUATION = true;
constexpr bool DONT_REEVALUATE = false;
const ServerIdentity identity = ServerIdentity(server);
@@ -274,10 +290,15 @@
notifyValidationStateUpdate(identity.ip.toString(), Validation::fail, netId);
return DONT_REEVALUATE;
}
- const bool modeDoesReevaluation = (mode->second == PrivateDnsMode::STRICT);
- bool reevaluationStatus =
- (success || !modeDoesReevaluation) ? DONT_REEVALUATE : NEEDS_REEVALUATION;
+ bool reevaluationStatus = NEEDS_REEVALUATION;
+ if (success) {
+ reevaluationStatus = DONT_REEVALUATE;
+ } else if (mode->second == PrivateDnsMode::OFF) {
+ reevaluationStatus = DONT_REEVALUATE;
+ } else if (mode->second == PrivateDnsMode::OPPORTUNISTIC && !isRevalidation) {
+ reevaluationStatus = DONT_REEVALUATE;
+ }
auto& tracker = netPair->second;
auto serverPair = tracker.find(identity);