blob: 17bce0327932ba358407509e1e80c9fe705fa6fd [file] [log] [blame]
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "net/dns/dns_client.h"
#include <utility>
#include "base/bind.h"
#include "base/rand_util.h"
#include "base/test/task_environment.h"
#include "net/base/ip_address.h"
#include "net/base/ip_endpoint.h"
#include "net/dns/dns_config.h"
#include "net/dns/dns_session.h"
#include "net/dns/dns_test_util.h"
#include "net/dns/public/dns_over_https_config.h"
#include "net/dns/resolve_context.h"
#include "net/socket/socket_test_util.h"
#include "net/test/test_with_task_environment.h"
#include "net/url_request/url_request_context.h"
#include "net/url_request/url_request_context_builder.h"
#include "net/url_request/url_request_test_util.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/scheme_host_port.h"
namespace net {
class ClientSocketFactory;
namespace {
class AlwaysFailSocketFactory : public MockClientSocketFactory {
public:
std::unique_ptr<DatagramClientSocket> CreateDatagramClientSocket(
DatagramSocket::BindType bind_type,
NetLog* net_log,
const NetLogSource& source) override {
return std::make_unique<MockUDPClientSocket>();
}
};
class DnsClientTest : public TestWithTaskEnvironment {
protected:
DnsClientTest()
: TestWithTaskEnvironment(
base::test::TaskEnvironment::TimeSource::MOCK_TIME) {}
void SetUp() override {
client_ = DnsClient::CreateClient(nullptr /* net_log */);
auto context_builder = CreateTestURLRequestContextBuilder();
context_builder->set_client_socket_factory_for_testing(&socket_factory_);
request_context_ = context_builder->Build();
resolve_context_ = std::make_unique<ResolveContext>(
request_context_.get(), false /* enable_caching */);
}
DnsConfig BasicValidConfig() {
DnsConfig config;
config.nameservers = {IPEndPoint(IPAddress(2, 3, 4, 5), 123)};
return config;
}
DnsConfig ValidConfigWithDoh(bool doh_only) {
DnsConfig config;
if (!doh_only) {
config = BasicValidConfig();
}
config.doh_config =
*net::DnsOverHttpsConfig::FromString("https://www.doh.com/");
return config;
}
DnsConfigOverrides BasicValidOverrides() {
DnsConfigOverrides config;
config.nameservers.emplace({IPEndPoint(IPAddress(1, 2, 3, 4), 123)});
return config;
}
std::unique_ptr<URLRequestContext> request_context_;
std::unique_ptr<ResolveContext> resolve_context_;
std::unique_ptr<DnsClient> client_;
AlwaysFailSocketFactory socket_factory_;
};
TEST_F(DnsClientTest, NoConfig) {
client_->SetInsecureEnabled(/*enabled=*/true,
/*additional_types_enabled=*/true);
EXPECT_FALSE(client_->CanUseSecureDnsTransactions());
EXPECT_TRUE(
client_->FallbackFromSecureTransactionPreferred(resolve_context_.get()));
EXPECT_FALSE(client_->CanUseInsecureDnsTransactions());
EXPECT_TRUE(client_->FallbackFromInsecureTransactionPreferred());
EXPECT_FALSE(client_->GetEffectiveConfig());
EXPECT_FALSE(client_->GetHosts());
EXPECT_FALSE(client_->GetTransactionFactory());
EXPECT_FALSE(client_->GetCurrentSession());
}
TEST_F(DnsClientTest, InvalidConfig) {
client_->SetInsecureEnabled(/*enabled=*/true,
/*additional_types_enabled=*/true);
client_->SetSystemConfig(DnsConfig());
EXPECT_FALSE(client_->CanUseSecureDnsTransactions());
EXPECT_TRUE(
client_->FallbackFromSecureTransactionPreferred(resolve_context_.get()));
EXPECT_FALSE(client_->CanUseInsecureDnsTransactions());
EXPECT_TRUE(client_->FallbackFromInsecureTransactionPreferred());
EXPECT_FALSE(client_->GetEffectiveConfig());
EXPECT_FALSE(client_->GetHosts());
EXPECT_FALSE(client_->GetTransactionFactory());
EXPECT_FALSE(client_->GetCurrentSession());
}
TEST_F(DnsClientTest, CanUseSecureDnsTransactions_NoDohServers) {
client_->SetInsecureEnabled(/*enabled=*/true,
/*additional_types_enabled=*/true);
client_->SetSystemConfig(BasicValidConfig());
EXPECT_FALSE(client_->CanUseSecureDnsTransactions());
EXPECT_TRUE(
client_->FallbackFromSecureTransactionPreferred(resolve_context_.get()));
EXPECT_TRUE(client_->CanUseInsecureDnsTransactions());
EXPECT_TRUE(client_->CanQueryAdditionalTypesViaInsecureDns());
EXPECT_FALSE(client_->FallbackFromInsecureTransactionPreferred());
EXPECT_THAT(client_->GetEffectiveConfig(),
testing::Pointee(BasicValidConfig()));
EXPECT_TRUE(client_->GetHosts());
EXPECT_TRUE(client_->GetTransactionFactory());
EXPECT_EQ(client_->GetCurrentSession()->config(), BasicValidConfig());
}
TEST_F(DnsClientTest, InsecureNotEnabled) {
client_->SetInsecureEnabled(/*enabled=*/false,
/*additional_types_enabled=*/false);
client_->SetSystemConfig(ValidConfigWithDoh(false /* doh_only */));
EXPECT_TRUE(client_->CanUseSecureDnsTransactions());
EXPECT_TRUE(
client_->FallbackFromSecureTransactionPreferred(resolve_context_.get()));
EXPECT_FALSE(client_->CanUseInsecureDnsTransactions());
EXPECT_TRUE(client_->FallbackFromInsecureTransactionPreferred());
EXPECT_THAT(client_->GetEffectiveConfig(),
testing::Pointee(ValidConfigWithDoh(false /* doh_only */)));
EXPECT_TRUE(client_->GetHosts());
EXPECT_TRUE(client_->GetTransactionFactory());
EXPECT_EQ(client_->GetCurrentSession()->config(),
ValidConfigWithDoh(false /* doh_only */));
}
TEST_F(DnsClientTest, RespectsAdditionalTypesDisabled) {
client_->SetInsecureEnabled(/*enabled=*/true,
/*additional_types_enabled=*/false);
client_->SetSystemConfig(BasicValidConfig());
EXPECT_FALSE(client_->CanUseSecureDnsTransactions());
EXPECT_TRUE(
client_->FallbackFromSecureTransactionPreferred(resolve_context_.get()));
EXPECT_TRUE(client_->CanUseInsecureDnsTransactions());
EXPECT_FALSE(client_->CanQueryAdditionalTypesViaInsecureDns());
EXPECT_FALSE(client_->FallbackFromInsecureTransactionPreferred());
}
TEST_F(DnsClientTest, UnhandledOptions) {
client_->SetInsecureEnabled(/*enabled=*/true,
/*additional_types_enabled=*/true);
DnsConfig config = ValidConfigWithDoh(false /* doh_only */);
config.unhandled_options = true;
client_->SetSystemConfig(config);
EXPECT_TRUE(client_->CanUseSecureDnsTransactions());
EXPECT_TRUE(
client_->FallbackFromSecureTransactionPreferred(resolve_context_.get()));
EXPECT_FALSE(client_->CanUseInsecureDnsTransactions());
EXPECT_TRUE(client_->FallbackFromInsecureTransactionPreferred());
DnsConfig expected_config = config;
expected_config.nameservers.clear();
EXPECT_THAT(client_->GetEffectiveConfig(), testing::Pointee(expected_config));
EXPECT_TRUE(client_->GetHosts());
EXPECT_TRUE(client_->GetTransactionFactory());
EXPECT_EQ(client_->GetCurrentSession()->config(), expected_config);
}
TEST_F(DnsClientTest, CanUseSecureDnsTransactions_ProbeSuccess) {
client_->SetSystemConfig(ValidConfigWithDoh(true /* doh_only */));
resolve_context_->InvalidateCachesAndPerSessionData(
client_->GetCurrentSession(), true /* network_change */);
EXPECT_TRUE(client_->CanUseSecureDnsTransactions());
EXPECT_TRUE(
client_->FallbackFromSecureTransactionPreferred(resolve_context_.get()));
resolve_context_->RecordServerSuccess(0u /* server_index */,
true /* is_doh_server */,
client_->GetCurrentSession());
EXPECT_TRUE(client_->CanUseSecureDnsTransactions());
EXPECT_FALSE(
client_->FallbackFromSecureTransactionPreferred(resolve_context_.get()));
}
TEST_F(DnsClientTest, DnsOverTlsActive) {
client_->SetInsecureEnabled(/*enabled=*/true,
/*additional_types_enabled=*/true);
DnsConfig config = ValidConfigWithDoh(false /* doh_only */);
config.dns_over_tls_active = true;
client_->SetSystemConfig(config);
EXPECT_TRUE(client_->CanUseSecureDnsTransactions());
EXPECT_TRUE(
client_->FallbackFromSecureTransactionPreferred(resolve_context_.get()));
EXPECT_FALSE(client_->CanUseInsecureDnsTransactions());
EXPECT_TRUE(client_->FallbackFromInsecureTransactionPreferred());
EXPECT_THAT(client_->GetEffectiveConfig(), testing::Pointee(config));
EXPECT_TRUE(client_->GetHosts());
EXPECT_TRUE(client_->GetTransactionFactory());
EXPECT_EQ(client_->GetCurrentSession()->config(), config);
}
TEST_F(DnsClientTest, AllAllowed) {
client_->SetInsecureEnabled(/*enabled=*/true,
/*additional_types_enabled=*/true);
client_->SetSystemConfig(ValidConfigWithDoh(false /* doh_only */));
resolve_context_->InvalidateCachesAndPerSessionData(
client_->GetCurrentSession(), false /* network_change */);
resolve_context_->RecordServerSuccess(0u /* server_index */,
true /* is_doh_server */,
client_->GetCurrentSession());
EXPECT_TRUE(client_->CanUseSecureDnsTransactions());
EXPECT_FALSE(
client_->FallbackFromSecureTransactionPreferred(resolve_context_.get()));
EXPECT_TRUE(client_->CanUseInsecureDnsTransactions());
EXPECT_TRUE(client_->CanQueryAdditionalTypesViaInsecureDns());
EXPECT_FALSE(client_->FallbackFromInsecureTransactionPreferred());
EXPECT_THAT(client_->GetEffectiveConfig(),
testing::Pointee(ValidConfigWithDoh(false /* doh_only */)));
EXPECT_TRUE(client_->GetHosts());
EXPECT_TRUE(client_->GetTransactionFactory());
EXPECT_EQ(client_->GetCurrentSession()->config(),
ValidConfigWithDoh(false /* doh_only */));
}
TEST_F(DnsClientTest, FallbackFromInsecureTransactionPreferred_Failures) {
client_->SetInsecureEnabled(/*enabled=*/true,
/*additional_types_enabled=*/true);
client_->SetSystemConfig(ValidConfigWithDoh(false /* doh_only */));
for (int i = 0; i < DnsClient::kMaxInsecureFallbackFailures; ++i) {
EXPECT_TRUE(client_->CanUseSecureDnsTransactions());
EXPECT_TRUE(client_->FallbackFromSecureTransactionPreferred(
resolve_context_.get()));
EXPECT_TRUE(client_->CanUseInsecureDnsTransactions());
EXPECT_TRUE(client_->CanQueryAdditionalTypesViaInsecureDns());
EXPECT_FALSE(client_->FallbackFromInsecureTransactionPreferred());
client_->IncrementInsecureFallbackFailures();
}
EXPECT_TRUE(client_->CanUseSecureDnsTransactions());
EXPECT_TRUE(
client_->FallbackFromSecureTransactionPreferred(resolve_context_.get()));
EXPECT_TRUE(client_->CanUseInsecureDnsTransactions());
EXPECT_TRUE(client_->CanQueryAdditionalTypesViaInsecureDns());
EXPECT_TRUE(client_->FallbackFromInsecureTransactionPreferred());
client_->ClearInsecureFallbackFailures();
EXPECT_TRUE(client_->CanUseSecureDnsTransactions());
EXPECT_TRUE(
client_->FallbackFromSecureTransactionPreferred(resolve_context_.get()));
EXPECT_TRUE(client_->CanUseInsecureDnsTransactions());
EXPECT_TRUE(client_->CanQueryAdditionalTypesViaInsecureDns());
EXPECT_FALSE(client_->FallbackFromInsecureTransactionPreferred());
}
TEST_F(DnsClientTest, GetPresetAddrs) {
DnsConfig config;
config.doh_config = *net::DnsOverHttpsConfig::FromString(R"(
{
"servers": [{
"template": "https://www.doh.com/",
"endpoints": [{
"ips": ["4.3.2.1"]
}, {
"ips": ["4.3.2.2"]
}]
}]
}
)");
client_->SetSystemConfig(config);
EXPECT_FALSE(client_->GetPresetAddrs(
url::SchemeHostPort("https", "otherdomain.com", 443)));
EXPECT_FALSE(
client_->GetPresetAddrs(url::SchemeHostPort("http", "www.doh.com", 443)));
EXPECT_FALSE(client_->GetPresetAddrs(
url::SchemeHostPort("https", "www.doh.com", 9999)));
AddressList expected({{{4, 3, 2, 1}, 443}, {{4, 3, 2, 2}, 443}});
EXPECT_THAT(
client_->GetPresetAddrs(url::SchemeHostPort("https", "www.doh.com", 443)),
testing::Optional(expected));
}
TEST_F(DnsClientTest, Override) {
client_->SetSystemConfig(BasicValidConfig());
EXPECT_THAT(client_->GetEffectiveConfig(),
testing::Pointee(BasicValidConfig()));
EXPECT_EQ(client_->GetCurrentSession()->config(), BasicValidConfig());
client_->SetConfigOverrides(BasicValidOverrides());
EXPECT_THAT(client_->GetEffectiveConfig(),
testing::Pointee(
BasicValidOverrides().ApplyOverrides(BasicValidConfig())));
EXPECT_EQ(client_->GetCurrentSession()->config(),
BasicValidOverrides().ApplyOverrides(BasicValidConfig()));
client_->SetConfigOverrides(DnsConfigOverrides());
EXPECT_THAT(client_->GetEffectiveConfig(),
testing::Pointee(BasicValidConfig()));
EXPECT_EQ(client_->GetCurrentSession()->config(), BasicValidConfig());
}
// Cannot apply overrides without a system config unless everything is
// overridden
TEST_F(DnsClientTest, OverrideNoConfig) {
client_->SetConfigOverrides(BasicValidOverrides());
EXPECT_FALSE(client_->GetEffectiveConfig());
EXPECT_FALSE(client_->GetCurrentSession());
auto override_everything =
DnsConfigOverrides::CreateOverridingEverythingWithDefaults();
override_everything.nameservers.emplace(
{IPEndPoint(IPAddress(1, 2, 3, 4), 123)});
client_->SetConfigOverrides(override_everything);
EXPECT_THAT(
client_->GetEffectiveConfig(),
testing::Pointee(override_everything.ApplyOverrides(DnsConfig())));
EXPECT_EQ(client_->GetCurrentSession()->config(),
override_everything.ApplyOverrides(DnsConfig()));
}
TEST_F(DnsClientTest, OverrideInvalidConfig) {
client_->SetSystemConfig(DnsConfig());
EXPECT_FALSE(client_->GetEffectiveConfig());
EXPECT_FALSE(client_->GetCurrentSession());
client_->SetConfigOverrides(BasicValidOverrides());
EXPECT_THAT(client_->GetEffectiveConfig(),
testing::Pointee(
BasicValidOverrides().ApplyOverrides(BasicValidConfig())));
EXPECT_EQ(client_->GetCurrentSession()->config(),
BasicValidOverrides().ApplyOverrides(DnsConfig()));
}
TEST_F(DnsClientTest, OverrideToInvalid) {
client_->SetSystemConfig(BasicValidConfig());
EXPECT_THAT(client_->GetEffectiveConfig(),
testing::Pointee(BasicValidConfig()));
EXPECT_EQ(client_->GetCurrentSession()->config(), BasicValidConfig());
DnsConfigOverrides overrides;
overrides.nameservers.emplace();
client_->SetConfigOverrides(std::move(overrides));
EXPECT_FALSE(client_->GetEffectiveConfig());
EXPECT_FALSE(client_->GetCurrentSession());
}
TEST_F(DnsClientTest, ReplaceCurrentSession) {
client_->SetSystemConfig(BasicValidConfig());
base::WeakPtr<DnsSession> session_before =
client_->GetCurrentSession()->GetWeakPtr();
ASSERT_TRUE(session_before);
client_->ReplaceCurrentSession();
EXPECT_FALSE(session_before);
EXPECT_TRUE(client_->GetCurrentSession());
}
TEST_F(DnsClientTest, ReplaceCurrentSession_NoSession) {
ASSERT_FALSE(client_->GetCurrentSession());
client_->ReplaceCurrentSession();
EXPECT_FALSE(client_->GetCurrentSession());
}
} // namespace
} // namespace net