Commit 3f5a7569 authored by robpercival's avatar robpercival Committed by Commit bot

Automatically update LogDnsClient's DNS config

No need to pre-configure the net::DnsClient and it will pick up changes to the
system DNS config automatically via net::NetworkChangeNotifier.

BUG=612439

Review-Url: https://codereview.chromium.org/2152143003
Cr-Commit-Position: refs/heads/master@{#407170}
parent d2e65efb
...@@ -13,11 +13,13 @@ ...@@ -13,11 +13,13 @@
#include "base/strings/string_util.h" #include "base/strings/string_util.h"
#include "base/threading/thread_task_runner_handle.h" #include "base/threading/thread_task_runner_handle.h"
#include "base/time/time.h" #include "base/time/time.h"
#include "base/values.h"
#include "components/base32/base32.h" #include "components/base32/base32.h"
#include "crypto/sha2.h" #include "crypto/sha2.h"
#include "net/base/net_errors.h" #include "net/base/net_errors.h"
#include "net/cert/merkle_audit_proof.h" #include "net/cert/merkle_audit_proof.h"
#include "net/dns/dns_client.h" #include "net/dns/dns_client.h"
#include "net/dns/dns_config_service.h"
#include "net/dns/dns_protocol.h" #include "net/dns/dns_protocol.h"
#include "net/dns/dns_response.h" #include "net/dns/dns_response.h"
#include "net/dns/dns_transaction.h" #include "net/dns/dns_transaction.h"
...@@ -86,9 +88,21 @@ LogDnsClient::LogDnsClient(std::unique_ptr<net::DnsClient> dns_client, ...@@ -86,9 +88,21 @@ LogDnsClient::LogDnsClient(std::unique_ptr<net::DnsClient> dns_client,
net_log_(net_log), net_log_(net_log),
weak_ptr_factory_(this) { weak_ptr_factory_(this) {
CHECK(dns_client_); CHECK(dns_client_);
net::NetworkChangeNotifier::AddDNSObserver(this);
UpdateDnsConfig();
} }
LogDnsClient::~LogDnsClient() {} LogDnsClient::~LogDnsClient() {
net::NetworkChangeNotifier::RemoveDNSObserver(this);
}
void LogDnsClient::OnDNSChanged() {
UpdateDnsConfig();
}
void LogDnsClient::OnInitialDNSConfigRead() {
UpdateDnsConfig();
}
void LogDnsClient::QueryLeafIndex(base::StringPiece domain_for_log, void LogDnsClient::QueryLeafIndex(base::StringPiece domain_for_log,
base::StringPiece leaf_hash, base::StringPiece leaf_hash,
...@@ -291,4 +305,11 @@ void LogDnsClient::QueryAuditProofNodesComplete( ...@@ -291,4 +305,11 @@ void LogDnsClient::QueryAuditProofNodesComplete(
base::Bind(query.callback, net::OK, base::Passed(std::move(proof)))); base::Bind(query.callback, net::OK, base::Passed(std::move(proof))));
} }
void LogDnsClient::UpdateDnsConfig() {
net::DnsConfig config;
net::NetworkChangeNotifier::GetDnsConfig(&config);
if (config.IsValid())
dns_client_->SetConfig(config);
}
} // namespace certificate_transparency } // namespace certificate_transparency
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include "base/callback.h" #include "base/callback.h"
#include "base/macros.h" #include "base/macros.h"
#include "base/strings/string_piece.h" #include "base/strings/string_piece.h"
#include "net/base/network_change_notifier.h"
#include "net/log/net_log.h" #include "net/log/net_log.h"
namespace net { namespace net {
...@@ -30,7 +31,8 @@ namespace certificate_transparency { ...@@ -30,7 +31,8 @@ namespace certificate_transparency {
// All queries are performed asynchronously. // All queries are performed asynchronously.
// For more information, see // For more information, see
// https://github.com/google/certificate-transparency-rfcs/blob/master/dns/draft-ct-over-dns.md. // https://github.com/google/certificate-transparency-rfcs/blob/master/dns/draft-ct-over-dns.md.
class LogDnsClient { // It must be created and deleted on the same thread. It is not thread-safe.
class LogDnsClient : public net::NetworkChangeNotifier::DNSObserver {
public: public:
// Invoked when a leaf index query completes. // Invoked when a leaf index query completes.
// If an error occured, |net_error| will be a net::Error code, otherwise it // If an error occured, |net_error| will be a net::Error code, otherwise it
...@@ -48,9 +50,20 @@ class LogDnsClient { ...@@ -48,9 +50,20 @@ class LogDnsClient {
// Creates a log client that will take ownership of |dns_client| and use it // Creates a log client that will take ownership of |dns_client| and use it
// to perform DNS queries. Queries will be logged to |net_log|. // to perform DNS queries. Queries will be logged to |net_log|.
// The |dns_client| does not need to be configured first - this will be done
// automatically as needed.
LogDnsClient(std::unique_ptr<net::DnsClient> dns_client, LogDnsClient(std::unique_ptr<net::DnsClient> dns_client,
const net::BoundNetLog& net_log); const net::BoundNetLog& net_log);
virtual ~LogDnsClient(); // Must be deleted on the same thread that it was created on.
~LogDnsClient() override;
// Called by NetworkChangeNotifier when the DNS config changes.
// The DnsClient's config will be updated in response.
void OnDNSChanged() override;
// Called by NetworkChangeNotifier when the DNS config is first read.
// The DnsClient's config will be updated in response.
void OnInitialDNSConfigRead() override;
// Queries a CT log to discover the index of the leaf with |leaf_hash|. // Queries a CT log to discover the index of the leaf with |leaf_hash|.
// The log is identified by |domain_for_log|, which is the DNS name used as a // The log is identified by |domain_for_log|, which is the DNS name used as a
...@@ -95,6 +108,9 @@ class LogDnsClient { ...@@ -95,6 +108,9 @@ class LogDnsClient {
int net_error, int net_error,
const net::DnsResponse* response); const net::DnsResponse* response);
// Updates the |dns_client_| config using NetworkChangeNotifier.
void UpdateDnsConfig();
// A DNS query that is in flight. // A DNS query that is in flight.
template <typename CallbackType> template <typename CallbackType>
struct Query { struct Query {
......
...@@ -32,7 +32,9 @@ ...@@ -32,7 +32,9 @@
namespace certificate_transparency { namespace certificate_transparency {
namespace { namespace {
using ::testing::IsEmpty;
using ::testing::IsNull; using ::testing::IsNull;
using ::testing::Not;
using ::testing::NotNull; using ::testing::NotNull;
using net::test::IsError; using net::test::IsError;
using net::test::IsOk; using net::test::IsOk;
...@@ -41,6 +43,18 @@ constexpr char kLeafHash[] = ...@@ -41,6 +43,18 @@ constexpr char kLeafHash[] =
"\x1f\x25\xe1\xca\xba\x4f\xf9\xb8\x27\x24\x83\x0f\xca\x60\xe4\xc2\xbe\xa8" "\x1f\x25\xe1\xca\xba\x4f\xf9\xb8\x27\x24\x83\x0f\xca\x60\xe4\xc2\xbe\xa8"
"\xc3\xa9\x44\x1c\x27\xb0\xb4\x3e\x6a\x96\x94\xc7\xb8\x04"; "\xc3\xa9\x44\x1c\x27\xb0\xb4\x3e\x6a\x96\x94\xc7\xb8\x04";
// Necessary to expose SetDnsConfig for testing.
class DnsChangeNotifier : public net::NetworkChangeNotifier {
public:
static void SetInitialDnsConfig(const net::DnsConfig& config) {
net::NetworkChangeNotifier::SetInitialDnsConfig(config);
}
static void SetDnsConfig(const net::DnsConfig& config) {
net::NetworkChangeNotifier::SetDnsConfig(config);
}
};
// Always return min, to simplify testing. // Always return min, to simplify testing.
// This should result in the DNS query ID always being 0. // This should result in the DNS query ID always being 0.
int FakeRandInt(int min, int max) { int FakeRandInt(int min, int max) {
...@@ -259,19 +273,23 @@ const net::MockRead MockSocketData::eof_(net::SYNCHRONOUS, ...@@ -259,19 +273,23 @@ const net::MockRead MockSocketData::eof_(net::SYNCHRONOUS,
class LogDnsClientTest : public ::testing::TestWithParam<net::IoMode> { class LogDnsClientTest : public ::testing::TestWithParam<net::IoMode> {
protected: protected:
LogDnsClientTest() { LogDnsClientTest() :
network_change_notifier_(net::NetworkChangeNotifier::CreateMock()) {
net::DnsConfig dns_config;
// Use an invalid nameserver address. This prevents the tests accidentally // Use an invalid nameserver address. This prevents the tests accidentally
// sending real DNS queries. The mock sockets don't care that the address // sending real DNS queries. The mock sockets don't care that the address
// is invalid. // is invalid.
dns_config_.nameservers.push_back(net::IPEndPoint()); dns_config.nameservers.push_back(net::IPEndPoint());
// Don't attempt retransmissions - just fail. // Don't attempt retransmissions - just fail.
dns_config_.attempts = 1; dns_config.attempts = 1;
// This ensures timeouts are long enough for memory tests. // This ensures timeouts are long enough for memory tests.
dns_config_.timeout = TestTimeouts::action_timeout(); dns_config.timeout = TestTimeouts::action_timeout();
// Simplify testing - don't require random numbers for the source port. // Simplify testing - don't require random numbers for the source port.
// This means our FakeRandInt function should only be called to get query // This means our FakeRandInt function should only be called to get query
// IDs. // IDs.
dns_config_.randomize_ports = false; dns_config.randomize_ports = false;
DnsChangeNotifier::SetInitialDnsConfig(dns_config);
} }
void ExpectRequestAndErrorResponse(base::StringPiece qname, uint8_t rcode) { void ExpectRequestAndErrorResponse(base::StringPiece qname, uint8_t rcode) {
...@@ -299,7 +317,10 @@ class LogDnsClientTest : public ::testing::TestWithParam<net::IoMode> { ...@@ -299,7 +317,10 @@ class LogDnsClientTest : public ::testing::TestWithParam<net::IoMode> {
mock_socket_data_.back()->AddToFactory(&socket_factory_); mock_socket_data_.back()->AddToFactory(&socket_factory_);
// Speed up timeout tests. // Speed up timeout tests.
dns_config_.timeout = TestTimeouts::tiny_timeout(); net::DnsConfig dns_config;
DnsChangeNotifier::GetDnsConfig(&dns_config);
dns_config.timeout = TestTimeouts::tiny_timeout();
DnsChangeNotifier::SetDnsConfig(dns_config);
} }
void ExpectLeafIndexRequestAndResponse(base::StringPiece qname, void ExpectLeafIndexRequestAndResponse(base::StringPiece qname,
...@@ -332,6 +353,7 @@ class LogDnsClientTest : public ::testing::TestWithParam<net::IoMode> { ...@@ -332,6 +353,7 @@ class LogDnsClientTest : public ::testing::TestWithParam<net::IoMode> {
MockLeafIndexCallback* callback) { MockLeafIndexCallback* callback) {
std::unique_ptr<net::DnsClient> dns_client = CreateDnsClient(); std::unique_ptr<net::DnsClient> dns_client = CreateDnsClient();
LogDnsClient log_client(std::move(dns_client), net::BoundNetLog()); LogDnsClient log_client(std::move(dns_client), net::BoundNetLog());
net::NetworkChangeNotifier::NotifyObserversOfInitialDNSConfigReadForTests();
log_client.QueryLeafIndex(log_domain, leaf_hash, callback->AsCallback()); log_client.QueryLeafIndex(log_domain, leaf_hash, callback->AsCallback());
callback->WaitUntilRun(); callback->WaitUntilRun();
...@@ -343,21 +365,20 @@ class LogDnsClientTest : public ::testing::TestWithParam<net::IoMode> { ...@@ -343,21 +365,20 @@ class LogDnsClientTest : public ::testing::TestWithParam<net::IoMode> {
MockAuditProofCallback* callback) { MockAuditProofCallback* callback) {
std::unique_ptr<net::DnsClient> dns_client = CreateDnsClient(); std::unique_ptr<net::DnsClient> dns_client = CreateDnsClient();
LogDnsClient log_client(std::move(dns_client), net::BoundNetLog()); LogDnsClient log_client(std::move(dns_client), net::BoundNetLog());
net::NetworkChangeNotifier::NotifyObserversOfInitialDNSConfigReadForTests();
log_client.QueryAuditProof(log_domain, leaf_index, tree_size, log_client.QueryAuditProof(log_domain, leaf_index, tree_size,
callback->AsCallback()); callback->AsCallback());
callback->WaitUntilRun(); callback->WaitUntilRun();
} }
private:
std::unique_ptr<net::DnsClient> CreateDnsClient() { std::unique_ptr<net::DnsClient> CreateDnsClient() {
std::unique_ptr<net::DnsClient> client = return net::DnsClient::CreateClientForTesting(nullptr, &socket_factory_,
net::DnsClient::CreateClientForTesting(nullptr, &socket_factory_, base::Bind(&FakeRandInt));
base::Bind(&FakeRandInt));
client->SetConfig(dns_config_);
return client;
} }
private:
void ExpectRequestAndResponse(base::StringPiece qname, void ExpectRequestAndResponse(base::StringPiece qname,
base::StringPiece answer) { base::StringPiece answer) {
std::vector<char> request = CreateDnsTxtRequest(qname); std::vector<char> request = CreateDnsTxtRequest(qname);
...@@ -368,9 +389,16 @@ class LogDnsClientTest : public ::testing::TestWithParam<net::IoMode> { ...@@ -368,9 +389,16 @@ class LogDnsClientTest : public ::testing::TestWithParam<net::IoMode> {
mock_socket_data_.back()->AddToFactory(&socket_factory_); mock_socket_data_.back()->AddToFactory(&socket_factory_);
} }
net::DnsConfig dns_config_; // This will be the NetworkChangeNotifier singleton for the duration of the
// test. It is accessed statically by LogDnsClient.
std::unique_ptr<net::NetworkChangeNotifier> network_change_notifier_;
// Queues and handles asynchronous DNS tasks. Indirectly used by LogDnsClient,
// the underlying net::DnsClient, and NetworkChangeNotifier.
base::MessageLoopForIO message_loop_; base::MessageLoopForIO message_loop_;
// One MockSocketData for each socket that is created. This corresponds to one
// for each DNS request sent.
std::vector<std::unique_ptr<MockSocketData>> mock_socket_data_; std::vector<std::unique_ptr<MockSocketData>> mock_socket_data_;
// Provides as many mock sockets as there are entries in |mock_socket_data_|.
net::MockClientSocketFactory socket_factory_; net::MockClientSocketFactory socket_factory_;
}; };
...@@ -737,6 +765,38 @@ TEST_P(LogDnsClientTest, QueryAuditProofReportsTimeout) { ...@@ -737,6 +765,38 @@ TEST_P(LogDnsClientTest, QueryAuditProofReportsTimeout) {
EXPECT_THAT(callback.proof(), IsNull()); EXPECT_THAT(callback.proof(), IsNull());
} }
TEST_P(LogDnsClientTest, AdoptsLatestDnsConfigIfValid) {
std::unique_ptr<net::DnsClient> tmp = CreateDnsClient();
net::DnsClient* dns_client = tmp.get();
LogDnsClient log_client(std::move(tmp), net::BoundNetLog());
// Get the current DNS config, modify it and broadcast the update.
net::DnsConfig config(*dns_client->GetConfig());
ASSERT_NE(123, config.attempts);
config.attempts = 123;
DnsChangeNotifier::SetDnsConfig(config);
// Let the DNS config change propogate.
base::RunLoop().RunUntilIdle();
EXPECT_EQ(123, dns_client->GetConfig()->attempts);
}
TEST_P(LogDnsClientTest, IgnoresLatestDnsConfigIfInvalid) {
std::unique_ptr<net::DnsClient> tmp = CreateDnsClient();
net::DnsClient* dns_client = tmp.get();
LogDnsClient log_client(std::move(tmp), net::BoundNetLog());
// Get the current DNS config, modify it and broadcast the update.
net::DnsConfig config(*dns_client->GetConfig());
ASSERT_THAT(config.nameservers, Not(IsEmpty()));
config.nameservers.clear(); // Makes config invalid
DnsChangeNotifier::SetDnsConfig(config);
// Let the DNS config change propogate.
base::RunLoop().RunUntilIdle();
EXPECT_THAT(dns_client->GetConfig()->nameservers, Not(IsEmpty()));
}
INSTANTIATE_TEST_CASE_P(ReadMode, INSTANTIATE_TEST_CASE_P(ReadMode,
LogDnsClientTest, LogDnsClientTest,
::testing::Values(net::IoMode::ASYNC, ::testing::Values(net::IoMode::ASYNC,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment