diff options
author | Mike Yu <yumike@google.com> | 2020-12-02 21:04:40 +0800 |
---|---|---|
committer | Mike Yu <yumike@google.com> | 2021-04-26 03:10:44 +0000 |
commit | 82ae84b9490e898eb839d0b807de23da27437c5b (patch) | |
tree | f356d3612e202044d1c5fb7d0080978e9f770c2c /PrivateDnsConfiguration.cpp | |
parent | 9310ca2278d55dc53b7173ed21b85d1b523057da (diff) | |
download | DnsResolver-82ae84b9490e898eb839d0b807de23da27437c5b.tar.gz |
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
Diffstat (limited to 'PrivateDnsConfiguration.cpp')
-rw-r--r-- | PrivateDnsConfiguration.cpp | 61 |
1 files changed, 41 insertions, 20 deletions
diff --git a/PrivateDnsConfiguration.cpp b/PrivateDnsConfiguration.cpp index c8b070a2..610d55b2 100644 --- a/PrivateDnsConfiguration.cpp +++ b/PrivateDnsConfiguration.cpp @@ -110,14 +110,14 @@ int PrivateDnsConfiguration::set(int32_t netId, uint32_t mark, 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 @@ void PrivateDnsConfiguration::clear(unsigned netId) { 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 @@ void PrivateDnsConfiguration::startValidation(const DnsTlsServer& server, unsign 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 @@ void PrivateDnsConfiguration::sendPrivateDnsValidationEvent(const DnsTlsServer& } 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 @@ bool PrivateDnsConfiguration::recordPrivateDnsValidation(const DnsTlsServer& ser 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); |