Commit 3acee4c7 authored by Eric Orth's avatar Eric Orth Committed by Commit Bot

Record queries in DnsUdpTracker

Bug: 1093369
Change-Id: Ia04f5a7f3b44c34aa543919ff7c8a8d6468f1792
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2238376
Commit-Queue: Eric Orth <ericorth@chromium.org>
Reviewed-by: default avatarDan McArdle <dmcardle@chromium.org>
Cr-Commit-Position: refs/heads/master@{#777249}
parent f07fe53f
...@@ -365,8 +365,13 @@ bool DnsResponse::InitParse(size_t nbytes, const DnsQuery& query) { ...@@ -365,8 +365,13 @@ bool DnsResponse::InitParse(size_t nbytes, const DnsQuery& query) {
return false; return false;
} }
// At this point, it has been validated that the response is at least large
// enough to read the ID field.
id_available_ = true;
// Match the query id. // Match the query id.
if (base::NetToHost16(header()->id) != query.id()) DCHECK(id());
if (id().value() != query.id())
return false; return false;
// Not a response? // Not a response?
...@@ -393,6 +398,7 @@ bool DnsResponse::InitParseWithoutQuery(size_t nbytes) { ...@@ -393,6 +398,7 @@ bool DnsResponse::InitParseWithoutQuery(size_t nbytes) {
if (nbytes < kHeaderSize || nbytes > io_buffer_size_) { if (nbytes < kHeaderSize || nbytes > io_buffer_size_) {
return false; return false;
} }
id_available_ = true;
parser_ = DnsRecordParser(io_buffer_->data(), nbytes, kHeaderSize); parser_ = DnsRecordParser(io_buffer_->data(), nbytes, kHeaderSize);
...@@ -411,6 +417,13 @@ bool DnsResponse::InitParseWithoutQuery(size_t nbytes) { ...@@ -411,6 +417,13 @@ bool DnsResponse::InitParseWithoutQuery(size_t nbytes) {
return true; return true;
} }
base::Optional<uint16_t> DnsResponse::id() const {
if (!id_available_)
return base::nullopt;
return base::NetToHost16(header()->id);
}
bool DnsResponse::IsValid() const { bool DnsResponse::IsValid() const {
return parser_.IsValid(); return parser_.IsValid();
} }
......
...@@ -169,6 +169,12 @@ class NET_EXPORT_PRIVATE DnsResponse { ...@@ -169,6 +169,12 @@ class NET_EXPORT_PRIVATE DnsResponse {
// if the response is constructed from a raw buffer. // if the response is constructed from a raw buffer.
bool InitParseWithoutQuery(size_t nbytes); bool InitParseWithoutQuery(size_t nbytes);
// Does not require the response to be fully parsed and valid, but will return
// nullopt if the ID is unknown. The ID will only be known if the response is
// successfully constructed from data or if InitParse...() has been able to
// parse at least as far as the ID (not necessarily a fully successful parse).
base::Optional<uint16_t> id() const;
// Returns true if response is valid, that is, after successful InitParse, or // Returns true if response is valid, that is, after successful InitParse, or
// after successful construction of a new response from data. // after successful construction of a new response from data.
bool IsValid() const; bool IsValid() const;
...@@ -220,6 +226,7 @@ class NET_EXPORT_PRIVATE DnsResponse { ...@@ -220,6 +226,7 @@ class NET_EXPORT_PRIVATE DnsResponse {
// Iterator constructed after InitParse positioned at the answer section. // Iterator constructed after InitParse positioned at the answer section.
// It is never updated afterwards, so can be used in accessors. // It is never updated afterwards, so can be used in accessors.
DnsRecordParser parser_; DnsRecordParser parser_;
bool id_available_ = false;
DISALLOW_COPY_AND_ASSIGN(DnsResponse); DISALLOW_COPY_AND_ASSIGN(DnsResponse);
}; };
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
#include "net/dns/dns_response.h" #include "net/dns/dns_response.h"
#include <algorithm>
#include <memory> #include <memory>
#include "base/big_endian.h" #include "base/big_endian.h"
...@@ -17,6 +18,7 @@ ...@@ -17,6 +18,7 @@
#include "net/dns/dns_util.h" #include "net/dns/dns_util.h"
#include "net/dns/public/dns_protocol.h" #include "net/dns/public/dns_protocol.h"
#include "net/dns/record_rdata.h" #include "net/dns/record_rdata.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
namespace net { namespace net {
...@@ -297,26 +299,32 @@ TEST(DnsResponseTest, InitParse) { ...@@ -297,26 +299,32 @@ TEST(DnsResponseTest, InitParse) {
DnsResponse resp; DnsResponse resp;
memcpy(resp.io_buffer()->data(), response_data, sizeof(response_data)); memcpy(resp.io_buffer()->data(), response_data, sizeof(response_data));
EXPECT_FALSE(resp.id());
// Reject too short. // Reject too short.
EXPECT_FALSE(resp.InitParse(query->io_buffer()->size() - 1, *query)); EXPECT_FALSE(resp.InitParse(query->io_buffer()->size() - 1, *query));
EXPECT_FALSE(resp.IsValid()); EXPECT_FALSE(resp.IsValid());
EXPECT_FALSE(resp.id());
// Reject wrong id. // Reject wrong id.
std::unique_ptr<DnsQuery> other_query = query->CloneWithNewId(0xbeef); std::unique_ptr<DnsQuery> other_query = query->CloneWithNewId(0xbeef);
EXPECT_FALSE(resp.InitParse(sizeof(response_data), *other_query)); EXPECT_FALSE(resp.InitParse(sizeof(response_data), *other_query));
EXPECT_FALSE(resp.IsValid()); EXPECT_FALSE(resp.IsValid());
EXPECT_THAT(resp.id(), testing::Optional(0xcafe));
// Reject wrong question. // Reject wrong question.
std::unique_ptr<DnsQuery> wrong_query( std::unique_ptr<DnsQuery> wrong_query(
new DnsQuery(0xcafe, qname, dns_protocol::kTypeCNAME)); new DnsQuery(0xcafe, qname, dns_protocol::kTypeCNAME));
EXPECT_FALSE(resp.InitParse(sizeof(response_data), *wrong_query)); EXPECT_FALSE(resp.InitParse(sizeof(response_data), *wrong_query));
EXPECT_FALSE(resp.IsValid()); EXPECT_FALSE(resp.IsValid());
EXPECT_THAT(resp.id(), testing::Optional(0xcafe));
// Accept matching question. // Accept matching question.
EXPECT_TRUE(resp.InitParse(sizeof(response_data), *query)); EXPECT_TRUE(resp.InitParse(sizeof(response_data), *query));
EXPECT_TRUE(resp.IsValid()); EXPECT_TRUE(resp.IsValid());
// Check header access. // Check header access.
EXPECT_THAT(resp.id(), testing::Optional(0xcafe));
EXPECT_EQ(0x8180, resp.flags()); EXPECT_EQ(0x8180, resp.flags());
EXPECT_EQ(0x0, resp.rcode()); EXPECT_EQ(0x0, resp.rcode());
EXPECT_EQ(2u, resp.answer_count()); EXPECT_EQ(2u, resp.answer_count());
...@@ -384,6 +392,7 @@ TEST(DnsResponseTest, InitParseInvalidFlags) { ...@@ -384,6 +392,7 @@ TEST(DnsResponseTest, InitParseInvalidFlags) {
EXPECT_FALSE(resp.InitParse(sizeof(response_data), *query)); EXPECT_FALSE(resp.InitParse(sizeof(response_data), *query));
EXPECT_FALSE(resp.IsValid()); EXPECT_FALSE(resp.IsValid());
EXPECT_THAT(resp.id(), testing::Optional(0xcafe));
} }
TEST(DnsResponseTest, InitParseWithoutQuery) { TEST(DnsResponseTest, InitParseWithoutQuery) {
...@@ -441,6 +450,7 @@ TEST(DnsResponseTest, InitParseWithoutQueryNoQuestions) { ...@@ -441,6 +450,7 @@ TEST(DnsResponseTest, InitParseWithoutQueryNoQuestions) {
EXPECT_TRUE(resp.InitParseWithoutQuery(sizeof(response_data))); EXPECT_TRUE(resp.InitParseWithoutQuery(sizeof(response_data)));
// Check header access. // Check header access.
EXPECT_THAT(resp.id(), testing::Optional(0xcafe));
EXPECT_EQ(0x8180, resp.flags()); EXPECT_EQ(0x8180, resp.flags());
EXPECT_EQ(0x0, resp.rcode()); EXPECT_EQ(0x0, resp.rcode());
EXPECT_EQ(0x1u, resp.answer_count()); EXPECT_EQ(0x1u, resp.answer_count());
...@@ -483,6 +493,7 @@ TEST(DnsResponseTest, InitParseWithoutQueryInvalidFlags) { ...@@ -483,6 +493,7 @@ TEST(DnsResponseTest, InitParseWithoutQueryInvalidFlags) {
memcpy(resp.io_buffer()->data(), response_data, sizeof(response_data)); memcpy(resp.io_buffer()->data(), response_data, sizeof(response_data));
EXPECT_FALSE(resp.InitParseWithoutQuery(sizeof(response_data))); EXPECT_FALSE(resp.InitParseWithoutQuery(sizeof(response_data)));
EXPECT_THAT(resp.id(), testing::Optional(0xcafe));
} }
TEST(DnsResponseTest, InitParseWithoutQueryTwoQuestions) { TEST(DnsResponseTest, InitParseWithoutQueryTwoQuestions) {
...@@ -1181,6 +1192,7 @@ TEST(DnsResponseWriteTest, WrittenResponseCanBeParsed) { ...@@ -1181,6 +1192,7 @@ TEST(DnsResponseWriteTest, WrittenResponseCanBeParsed) {
base::nullopt); base::nullopt);
ASSERT_NE(nullptr, response.io_buffer()); ASSERT_NE(nullptr, response.io_buffer());
EXPECT_TRUE(response.IsValid()); EXPECT_TRUE(response.IsValid());
EXPECT_THAT(response.id(), testing::Optional(0x1234));
EXPECT_EQ(1u, response.answer_count()); EXPECT_EQ(1u, response.answer_count());
EXPECT_EQ(1u, response.additional_answer_count()); EXPECT_EQ(1u, response.additional_answer_count());
auto parser = response.Parser(); auto parser = response.Parser();
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include "net/base/rand_callback.h" #include "net/base/rand_callback.h"
#include "net/dns/dns_config.h" #include "net/dns/dns_config.h"
#include "net/dns/dns_socket_pool.h" #include "net/dns/dns_socket_pool.h"
#include "net/dns/dns_udp_tracker.h"
namespace net { namespace net {
...@@ -62,6 +63,7 @@ class NET_EXPORT_PRIVATE DnsSession : public base::RefCounted<DnsSession> { ...@@ -62,6 +63,7 @@ class NET_EXPORT_PRIVATE DnsSession : public base::RefCounted<DnsSession> {
NetLog* net_log); NetLog* net_log);
const DnsConfig& config() const { return config_; } const DnsConfig& config() const { return config_; }
DnsUdpTracker* udp_tracker() { return &udp_tracker_; }
NetLog* net_log() const { return net_log_; } NetLog* net_log() const { return net_log_; }
// Return the next random query ID. // Return the next random query ID.
...@@ -98,6 +100,7 @@ class NET_EXPORT_PRIVATE DnsSession : public base::RefCounted<DnsSession> { ...@@ -98,6 +100,7 @@ class NET_EXPORT_PRIVATE DnsSession : public base::RefCounted<DnsSession> {
const DnsConfig config_; const DnsConfig config_;
std::unique_ptr<DnsSocketPool> socket_pool_; std::unique_ptr<DnsSocketPool> socket_pool_;
DnsUdpTracker udp_tracker_;
RandCallback rand_callback_; RandCallback rand_callback_;
NetLog* net_log_; NetLog* net_log_;
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include "base/memory/weak_ptr.h" #include "base/memory/weak_ptr.h"
#include "base/metrics/histogram_functions.h" #include "base/metrics/histogram_functions.h"
#include "base/metrics/histogram_macros.h" #include "base/metrics/histogram_macros.h"
#include "base/optional.h"
#include "base/rand_util.h" #include "base/rand_util.h"
#include "base/single_thread_task_runner.h" #include "base/single_thread_task_runner.h"
#include "base/stl_util.h" #include "base/stl_util.h"
...@@ -47,6 +48,7 @@ ...@@ -47,6 +48,7 @@
#include "net/dns/dns_response.h" #include "net/dns/dns_response.h"
#include "net/dns/dns_server_iterator.h" #include "net/dns/dns_server_iterator.h"
#include "net/dns/dns_session.h" #include "net/dns/dns_session.h"
#include "net/dns/dns_udp_tracker.h"
#include "net/dns/dns_util.h" #include "net/dns/dns_util.h"
#include "net/dns/public/dns_over_https_server_config.h" #include "net/dns/public/dns_over_https_server_config.h"
#include "net/dns/public/dns_protocol.h" #include "net/dns/public/dns_protocol.h"
...@@ -186,11 +188,13 @@ class DnsUDPAttempt : public DnsAttempt { ...@@ -186,11 +188,13 @@ class DnsUDPAttempt : public DnsAttempt {
public: public:
DnsUDPAttempt(size_t server_index, DnsUDPAttempt(size_t server_index,
std::unique_ptr<DnsSession::SocketLease> socket_lease, std::unique_ptr<DnsSession::SocketLease> socket_lease,
std::unique_ptr<DnsQuery> query) std::unique_ptr<DnsQuery> query,
DnsUdpTracker* udp_tracker)
: DnsAttempt(server_index), : DnsAttempt(server_index),
next_state_(STATE_NONE), next_state_(STATE_NONE),
socket_lease_(std::move(socket_lease)), socket_lease_(std::move(socket_lease)),
query_(std::move(query)) {} query_(std::move(query)),
udp_tracker_(udp_tracker) {}
// DnsAttempt methods. // DnsAttempt methods.
...@@ -199,6 +203,11 @@ class DnsUDPAttempt : public DnsAttempt { ...@@ -199,6 +203,11 @@ class DnsUDPAttempt : public DnsAttempt {
callback_ = std::move(callback); callback_ = std::move(callback);
start_time_ = base::TimeTicks::Now(); start_time_ = base::TimeTicks::Now();
next_state_ = STATE_SEND_QUERY; next_state_ = STATE_SEND_QUERY;
IPEndPoint local_address;
if (socket_lease_->socket()->GetLocalAddress(&local_address) == OK)
udp_tracker_->RecordQuery(local_address.port(), query_->id());
return DoLoop(OK); return DoLoop(OK);
} }
...@@ -294,7 +303,11 @@ class DnsUDPAttempt : public DnsAttempt { ...@@ -294,7 +303,11 @@ class DnsUDPAttempt : public DnsAttempt {
return rv; return rv;
DCHECK(rv); DCHECK(rv);
if (!response_->InitParse(rv, *query_)) bool parse_result = response_->InitParse(rv, *query_);
if (response_->id())
udp_tracker_->RecordResponseId(query_->id(), response_->id().value());
if (!parse_result)
return ERR_DNS_MALFORMED_RESPONSE; return ERR_DNS_MALFORMED_RESPONSE;
if (response_->flags() & dns_protocol::kFlagTC) if (response_->flags() & dns_protocol::kFlagTC)
return ERR_DNS_SERVER_REQUIRES_TCP; return ERR_DNS_SERVER_REQUIRES_TCP;
...@@ -318,6 +331,10 @@ class DnsUDPAttempt : public DnsAttempt { ...@@ -318,6 +331,10 @@ class DnsUDPAttempt : public DnsAttempt {
std::unique_ptr<DnsSession::SocketLease> socket_lease_; std::unique_ptr<DnsSession::SocketLease> socket_lease_;
std::unique_ptr<DnsQuery> query_; std::unique_ptr<DnsQuery> query_;
// Should be owned by the DnsSession, to which the transaction should own a
// reference.
DnsUdpTracker* const udp_tracker_;
std::unique_ptr<DnsResponse> response_; std::unique_ptr<DnsResponse> response_;
CompletionOnceCallback callback_; CompletionOnceCallback callback_;
...@@ -1202,8 +1219,9 @@ class DnsTransactionImpl : public DnsTransaction, ...@@ -1202,8 +1219,9 @@ class DnsTransactionImpl : public DnsTransaction,
bool got_socket = !!lease.get(); bool got_socket = !!lease.get();
DnsUDPAttempt* attempt = new DnsUDPAttempt( DnsUDPAttempt* attempt =
non_doh_server_index, std::move(lease), std::move(query)); new DnsUDPAttempt(non_doh_server_index, std::move(lease),
std::move(query), session_->udp_tracker());
attempts_.push_back(base::WrapUnique(attempt)); attempts_.push_back(base::WrapUnique(attempt));
++attempts_count_; ++attempts_count_;
......
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