Reland "Track DoH probe results per-context"
Original: crrev.com/c/2001144
Revert: crrev.com/c/2050749
Was reverted due to crashes where
|ResolveContext::doh_server_availability_| size was not matching up with
the number of DoH servers in the config in |current_session_|. Because
the config is const in the session and |doh_server_availability_| is
only and always set when setting |current_session_|, the most plausible
theory I have is that the session pointer comparisons were invalid due
to memory reuse (new session but incorrectly recognized as the old
session because it has the same pointer).
Protected the |current_session_| pointer from reuse via WeakPtr. Not
ideal, but DnsSession ownership is already very loose with both ref
counting and other WeakPtr instances. Also added a bunch of CHECK
validations to help spot similar issues if this continues to or later
crashes similarly.
Bug: 1022059
Change-Id: Ibf030fa06882f02830bbaa13e45d9669815e9c5a
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2050758
Commit-Queue: Eric Orth <[email protected]>
Reviewed-by: Matt Menke <[email protected]>
Cr-Commit-Position: refs/heads/master@{#741180}
diff --git a/net/dns/dns_test_util.cc b/net/dns/dns_test_util.cc
index 00b29f1..3910b7c 100644
--- a/net/dns/dns_test_util.cc
+++ b/net/dns/dns_test_util.cc
@@ -447,8 +447,9 @@
const std::string& hostname,
uint16_t qtype,
bool secure,
+ bool force_doh_server_available,
DnsConfig::SecureDnsMode secure_dns_mode,
- URLRequestContext* url_request_context,
+ ResolveContext* resolve_context,
DnsTransactionFactory::CallbackType callback)
: result_(MockDnsClientRule::FAIL),
hostname_(hostname),
@@ -456,70 +457,77 @@
callback_(std::move(callback)),
started_(false),
delayed_(false) {
- // Find the relevant rule which matches |qtype|, |secure|, prefix of
- // |hostname|, and |url_request_context| (iff the rule context is not
- // null).
- for (size_t i = 0; i < rules.size(); ++i) {
- const std::string& prefix = rules[i].prefix;
- if ((rules[i].qtype == qtype) && (rules[i].secure == secure) &&
- (hostname.size() >= prefix.size()) &&
- (hostname.compare(0, prefix.size(), prefix) == 0) &&
- (!rules[i].context || rules[i].context == url_request_context)) {
- const MockDnsClientRule::Result* result = &rules[i].result;
- result_ = MockDnsClientRule::Result(result->type);
- delayed_ = rules[i].delay;
+ // Do not allow matching any rules if transaction is secure and no DoH
+ // servers are available.
+ if (!secure || force_doh_server_available ||
+ resolve_context->NumAvailableDohServers(
+ resolve_context->current_session_for_testing()) > 0) {
+ // Find the relevant rule which matches |qtype|, |secure|, prefix of
+ // |hostname|, and |url_request_context| (iff the rule context is not
+ // null).
+ for (size_t i = 0; i < rules.size(); ++i) {
+ const std::string& prefix = rules[i].prefix;
+ if ((rules[i].qtype == qtype) && (rules[i].secure == secure) &&
+ (hostname.size() >= prefix.size()) &&
+ (hostname.compare(0, prefix.size(), prefix) == 0) &&
+ (!rules[i].context ||
+ rules[i].context == resolve_context->url_request_context())) {
+ const MockDnsClientRule::Result* result = &rules[i].result;
+ result_ = MockDnsClientRule::Result(result->type);
+ delayed_ = rules[i].delay;
- // Generate a DnsResponse when not provided with the rule.
- std::vector<DnsResourceRecord> authority_records;
- std::string dns_name;
- CHECK(DNSDomainFromDot(hostname_, &dns_name));
- base::Optional<DnsQuery> query(base::in_place, 22 /* id */, dns_name,
- qtype_);
- switch (result->type) {
- case MockDnsClientRule::NODOMAIN:
- case MockDnsClientRule::EMPTY:
- DCHECK(!result->response); // Not expected to be provided.
- authority_records = {BuildSoaRecord(hostname_)};
- result_.response = std::make_unique<DnsResponse>(
- 22 /* id */, false /* is_authoritative */,
- std::vector<DnsResourceRecord>() /* answers */,
- authority_records,
- std::vector<DnsResourceRecord>() /* additional_records */,
- query,
- result->type == MockDnsClientRule::NODOMAIN
- ? dns_protocol::kRcodeNXDOMAIN
- : 0);
- break;
- case MockDnsClientRule::FAIL:
- case MockDnsClientRule::TIMEOUT:
- DCHECK(!result->response); // Not expected to be provided.
- break;
- case MockDnsClientRule::OK:
- if (result->response) {
- // Copy response in case |rules| are destroyed before the
- // transaction completes.
+ // Generate a DnsResponse when not provided with the rule.
+ std::vector<DnsResourceRecord> authority_records;
+ std::string dns_name;
+ CHECK(DNSDomainFromDot(hostname_, &dns_name));
+ base::Optional<DnsQuery> query(base::in_place, 22 /* id */, dns_name,
+ qtype_);
+ switch (result->type) {
+ case MockDnsClientRule::NODOMAIN:
+ case MockDnsClientRule::EMPTY:
+ DCHECK(!result->response); // Not expected to be provided.
+ authority_records = {BuildSoaRecord(hostname_)};
result_.response = std::make_unique<DnsResponse>(
- result->response->io_buffer(),
- result->response->io_buffer_size());
- CHECK(result_.response->InitParseWithoutQuery(
- result->response->io_buffer_size()));
- } else {
- // Generated response only available for address types.
- DCHECK(qtype_ == dns_protocol::kTypeA ||
- qtype_ == dns_protocol::kTypeAAAA);
- result_.response = BuildTestDnsResponse(
- hostname_, qtype_ == dns_protocol::kTypeA
- ? IPAddress::IPv4Localhost()
- : IPAddress::IPv6Localhost());
- }
- break;
- case MockDnsClientRule::MALFORMED:
- DCHECK(!result->response); // Not expected to be provided.
- result_.response = CreateMalformedResponse(hostname_, qtype_);
- break;
- }
+ 22 /* id */, false /* is_authoritative */,
+ std::vector<DnsResourceRecord>() /* answers */,
+ authority_records,
+ std::vector<DnsResourceRecord>() /* additional_records */,
+ query,
+ result->type == MockDnsClientRule::NODOMAIN
+ ? dns_protocol::kRcodeNXDOMAIN
+ : 0);
+ break;
+ case MockDnsClientRule::FAIL:
+ case MockDnsClientRule::TIMEOUT:
+ DCHECK(!result->response); // Not expected to be provided.
+ break;
+ case MockDnsClientRule::OK:
+ if (result->response) {
+ // Copy response in case |rules| are destroyed before the
+ // transaction completes.
+ result_.response = std::make_unique<DnsResponse>(
+ result->response->io_buffer(),
+ result->response->io_buffer_size());
+ CHECK(result_.response->InitParseWithoutQuery(
+ result->response->io_buffer_size()));
+ } else {
+ // Generated response only available for address types.
+ DCHECK(qtype_ == dns_protocol::kTypeA ||
+ qtype_ == dns_protocol::kTypeAAAA);
+ result_.response = BuildTestDnsResponse(
+ hostname_, qtype_ == dns_protocol::kTypeA
+ ? IPAddress::IPv4Localhost()
+ : IPAddress::IPv6Localhost());
+ }
+ break;
+ case MockDnsClientRule::MALFORMED:
+ DCHECK(!result->response); // Not expected to be provided.
+ result_.response = CreateMalformedResponse(hostname_, qtype_);
+ break;
+ }
- break;
+ break;
+ }
}
}
}
@@ -618,8 +626,8 @@
ResolveContext* resolve_context) {
std::unique_ptr<MockTransaction> transaction =
std::make_unique<MockTransaction>(
- rules_, hostname, qtype, secure, secure_dns_mode,
- resolve_context->url_request_context(), std::move(callback));
+ rules_, hostname, qtype, secure, force_doh_server_available_,
+ secure_dns_mode, resolve_context, std::move(callback));
if (transaction->delayed())
delayed_transactions_.push_back(transaction->AsWeakPtr());
return transaction;
@@ -685,7 +693,10 @@
bool MockDnsClient::FallbackFromSecureTransactionPreferred(
ResolveContext* context) const {
- return !CanUseSecureDnsTransactions() || !doh_server_available_;
+ bool doh_server_available =
+ force_doh_server_available_ ||
+ context->NumAvailableDohServers(session_.get()) > 0;
+ return !CanUseSecureDnsTransactions() || !doh_server_available;
}
bool MockDnsClient::FallbackFromInsecureTransactionPreferred() const {
@@ -752,8 +763,6 @@
return overrides_;
}
-void MockDnsClient::SetProbeSuccessForTest(unsigned index, bool success) {}
-
void MockDnsClient::SetTransactionFactoryForTesting(
std::unique_ptr<DnsTransactionFactory> factory) {
NOTREACHED();
@@ -767,6 +776,11 @@
return factory_->CompleteOneDelayedTransactionOfType(type);
}
+void MockDnsClient::SetForceDohServerAvailable(bool available) {
+ force_doh_server_available_ = available;
+ factory_->set_force_doh_server_available(available);
+}
+
base::Optional<DnsConfig> MockDnsClient::BuildEffectiveConfig() {
if (overrides_.OverridesEverything())
return overrides_.ApplyOverrides(DnsConfig());