blob: ba756c07621137da6a69035ddf42a83518e9852c [file] [log] [blame] [edit]
// Copyright 2021 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "dns-proxy/resolver.h"
#include <memory>
#include <utility>
#include <vector>
#include <base/files/scoped_file.h>
#include <base/functional/callback.h>
#include <base/test/task_environment.h>
#include <base/time/time.h>
#include <chromeos/net-base/mock_socket.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include "dns-proxy/ares_client.h"
#include "dns-proxy/doh_curl_client.h"
using testing::_;
using testing::ElementsAre;
using testing::ElementsAreArray;
using testing::Return;
using testing::UnorderedElementsAreArray;
namespace dns_proxy {
namespace {
const std::vector<std::string> kTestNameServers{"8.8.8.8", "8.8.4.4"};
const std::vector<std::string> kTestDoHProviders{
"https://dns.google/dns-query", "https://dns2.google/dns-query"};
constexpr base::TimeDelta kTimeout = base::Seconds(3);
// Example of a valid DNS TCP fragment:
// - first 2 bytes are a TCP header containing the size of the DNS query
// (0x0102 == 258).
// - next bytes are the DNS query with the length equals to the TCP
// header.
constexpr uint8_t kDNSTCPFragment[] = {
0x01, 0x02, 0xbe, 0x64, 0x4b, 0xdd, 0x74, 0xd6, 0x7d, 0x4c, 0x45, 0xe4,
0x25, 0x25, 0x48, 0x53, 0x5a, 0x42, 0xc2, 0x32, 0xd7, 0xf5, 0x63, 0xcf,
0x60, 0xd5, 0x51, 0x78, 0x18, 0x82, 0x39, 0xed, 0x81, 0x92, 0xaf, 0x4b,
0x7c, 0xc2, 0x5a, 0x61, 0xd6, 0xf0, 0x0b, 0x5a, 0xbe, 0xb8, 0xc5, 0x80,
0xeb, 0x36, 0x7f, 0xe4, 0x75, 0xa2, 0xdc, 0xc1, 0x34, 0x65, 0xb3, 0x52,
0x34, 0x34, 0xe7, 0x60, 0x6b, 0x95, 0xeb, 0xa2, 0x69, 0x29, 0xd5, 0xd2,
0x5d, 0x81, 0xa9, 0x42, 0x65, 0x40, 0xee, 0xd8, 0x78, 0xf5, 0xdc, 0xd4,
0xa9, 0x62, 0xe9, 0x27, 0x1d, 0xb4, 0x22, 0xad, 0x59, 0xd6, 0x75, 0xb7,
0x9a, 0x4c, 0x6e, 0x82, 0x44, 0x1c, 0x2e, 0xbc, 0xd8, 0x6c, 0xa5, 0x5b,
0xa4, 0xa2, 0x9e, 0x41, 0x8e, 0x95, 0x4d, 0x75, 0x07, 0xef, 0x99, 0x10,
0x4d, 0x64, 0x77, 0x0c, 0x1d, 0x84, 0x8d, 0xad, 0x39, 0xef, 0x86, 0x15,
0x44, 0x3f, 0xf8, 0x7a, 0x7e, 0xc8, 0xc6, 0x96, 0x5c, 0x5c, 0x29, 0xc7,
0xab, 0xfd, 0xff, 0x25, 0xb3, 0x4a, 0xec, 0x0d, 0x5d, 0x3a, 0x97, 0x1b,
0x98, 0x5f, 0x9d, 0x4b, 0x99, 0x11, 0x6a, 0x21, 0x11, 0x11, 0xb7, 0x69,
0xd2, 0x03, 0x6c, 0x22, 0x59, 0x11, 0xf1, 0x4e, 0xa5, 0xdd, 0x60, 0x24,
0xa6, 0xf2, 0x55, 0xf1, 0xa7, 0x58, 0x16, 0x21, 0xac, 0xc5, 0x3f, 0xb9,
0x77, 0xf7, 0x20, 0x08, 0xa1, 0x99, 0x3f, 0x96, 0x76, 0xae, 0x63, 0xb6,
0xce, 0xac, 0x36, 0xda, 0x23, 0xa8, 0x13, 0xd3, 0x4e, 0x25, 0xa5, 0x85,
0xd1, 0x28, 0x77, 0xdc, 0xd1, 0xb9, 0x09, 0x55, 0x78, 0x81, 0x61, 0x9b,
0x67, 0x64, 0xe8, 0xb6, 0x6f, 0xfc, 0x0c, 0xd6, 0xf3, 0x33, 0xcf, 0xea,
0x9d, 0x05, 0x62, 0x14, 0x21, 0xaf, 0xf7, 0xfd, 0x92, 0xd6, 0xac, 0x06,
0x7d, 0x2d, 0xe2, 0x9b, 0x19, 0xaa, 0xfc, 0x79};
class MockDoHCurlClient : public DoHCurlClient {
public:
MockDoHCurlClient() : DoHCurlClient(kTimeout) {}
~MockDoHCurlClient() = default;
MOCK_METHOD5(Resolve,
bool(const base::span<const char>& query,
const QueryCallback& callback,
const std::vector<std::string>&,
const std::string&,
std::string_view));
};
class MockAresClient : public AresClient {
public:
MockAresClient() : AresClient(kTimeout) {}
~MockAresClient() = default;
MOCK_METHOD5(Resolve,
bool(const base::span<const unsigned char>& query,
const QueryCallback& callback,
const std::string& name_server,
std::string_view,
int type));
};
} // namespace
class ResolverTest : public testing::Test {
public:
void SetNameServers(const std::vector<std::string>& name_servers,
bool validate = false) {
resolver_->SetNameServers(name_servers);
if (!validate) {
return;
}
// Validate name servers.
for (const auto& name_server : name_servers) {
auto probe_state =
std::make_unique<Resolver::ProbeState>(name_server, /*doh=*/false);
resolver_->HandleDo53ProbeResult(probe_state->weak_factory.GetWeakPtr(),
{}, ARES_SUCCESS, {});
}
}
void SetDoHProviders(const std::vector<std::string>& doh_providers,
bool validate = false,
bool always_on_doh = false) {
resolver_->SetDoHProviders(doh_providers, always_on_doh);
if (!validate) {
return;
}
// Validate DoH providers.
for (const auto& doh_provider : doh_providers) {
DoHCurlClient::CurlResult res(CURLE_OK, 200 /* http_code */,
0 /* timeout */);
auto probe_state =
std::make_unique<Resolver::ProbeState>(doh_provider, /*doh=*/true);
resolver_->HandleDoHProbeResult(probe_state->weak_factory.GetWeakPtr(),
{}, res, {});
}
}
void ValidateNameServer(const std::string& name_server) {
auto probe_state =
std::make_unique<Resolver::ProbeState>(name_server, /*doh=*/false);
resolver_->HandleDo53ProbeResult(probe_state->weak_factory.GetWeakPtr(), {},
ARES_SUCCESS, {});
}
void ValidateDoHProvider(const std::string& doh_provider) {
DoHCurlClient::CurlResult res(CURLE_OK, 200 /* http_code */,
0 /* timeout */);
auto probe_state =
std::make_unique<Resolver::ProbeState>(doh_provider, /*doh=*/true);
resolver_->HandleDoHProbeResult(probe_state->weak_factory.GetWeakPtr(), {},
res, {});
}
void InvalidateNameServer(const std::string& name_server) {
// Resolve returns failure.
auto sock_fd = std::make_unique<Resolver::SocketFd>(SOCK_DGRAM, 0);
auto probe_state = std::make_unique<Resolver::ProbeState>(
name_server, /*doh=*/false, /*validated=*/true);
resolver_->HandleAresResult(sock_fd->weak_factory.GetWeakPtr(),
probe_state->weak_factory.GetWeakPtr(),
ARES_ETIMEOUT, {});
}
void InvalidateDoHProvider(const std::string& doh_provider) {
// Resolve returns failure.
auto sock_fd = std::make_unique<Resolver::SocketFd>(SOCK_DGRAM, 0);
auto probe_state = std::make_unique<Resolver::ProbeState>(
doh_provider, /*doh=*/true, /*validated=*/true);
resolver_->HandleCurlResult(
sock_fd->weak_factory.GetWeakPtr(),
probe_state->weak_factory.GetWeakPtr(),
DoHCurlClient::CurlResult(CURLE_OUT_OF_MEMORY, /*http_code=*/0,
/*retry_delay_ms=*/0),
{});
}
protected:
void SetUp() override {
auto scoped_ares_client = std::make_unique<MockAresClient>();
auto scoped_curl_client = std::make_unique<MockDoHCurlClient>();
auto socket_factory = std::make_unique<net_base::MockSocketFactory>();
ares_client_ = scoped_ares_client.get();
curl_client_ = scoped_curl_client.get();
socket_factory_ = socket_factory.get();
resolver_ = std::make_unique<Resolver>(std::move(scoped_ares_client),
std::move(scoped_curl_client),
std::move(socket_factory));
}
base::test::TaskEnvironment task_environment_{
base::test::TaskEnvironment::MainThreadType::IO};
MockAresClient* ares_client_;
MockDoHCurlClient* curl_client_;
net_base::MockSocketFactory* socket_factory_;
std::unique_ptr<Resolver> resolver_;
};
TEST_F(ResolverTest, ListenTCP) {
struct sockaddr_in6 addr;
memset(&addr, 0, sizeof(addr));
addr.sin6_family = AF_INET6;
addr.sin6_port = 13568;
addr.sin6_addr = in6addr_any;
EXPECT_CALL(*socket_factory_,
Create(AF_INET6, SOCK_STREAM | SOCK_NONBLOCK, _))
.WillOnce([]() {
auto socket = std::make_unique<net_base::MockSocket>();
EXPECT_CALL(*socket, Bind(_, sizeof(struct sockaddr_in6)))
.WillOnce(Return(true));
EXPECT_CALL(*socket, Listen).WillOnce(Return(true));
return socket;
});
EXPECT_TRUE(resolver_->ListenTCP(reinterpret_cast<struct sockaddr*>(&addr)));
}
TEST_F(ResolverTest, ListenUDP) {
struct sockaddr_in6 addr;
memset(&addr, 0, sizeof(addr));
addr.sin6_family = AF_INET6;
addr.sin6_port = 13568;
addr.sin6_addr = in6addr_any;
EXPECT_CALL(*socket_factory_, Create(AF_INET6, SOCK_DGRAM | SOCK_NONBLOCK, _))
.WillOnce([]() {
auto socket = std::make_unique<net_base::MockSocket>();
EXPECT_CALL(*socket, Bind(_, sizeof(struct sockaddr_in6)))
.WillOnce(Return(true));
return socket;
});
EXPECT_TRUE(resolver_->ListenUDP(reinterpret_cast<struct sockaddr*>(&addr)));
}
TEST_F(ResolverTest, SetNameServers) {
for (const auto& name_server : kTestNameServers) {
EXPECT_CALL(*ares_client_, Resolve(_, _, name_server, _, _))
.WillOnce(Return(true));
}
SetNameServers(kTestNameServers, /*validate=*/true);
auto sock_fd = std::make_unique<Resolver::SocketFd>(SOCK_STREAM, 0);
resolver_->Resolve(sock_fd->weak_factory.GetWeakPtr());
}
TEST_F(ResolverTest, SetDoHProviders) {
for (const auto& doh_provider : kTestDoHProviders) {
EXPECT_CALL(*curl_client_,
Resolve(_, _, UnorderedElementsAreArray(kTestNameServers),
doh_provider, _))
.WillOnce(Return(true));
}
SetNameServers(kTestNameServers, /*validate=*/true);
SetDoHProviders(kTestDoHProviders, /*validate=*/true, /*always_on_doh=*/true);
auto sock_fd = std::make_unique<Resolver::SocketFd>(SOCK_STREAM, 0);
resolver_->Resolve(sock_fd->weak_factory.GetWeakPtr());
}
TEST_F(ResolverTest, Resolve_DNSDoHServersNotValidated) {
SetNameServers(kTestNameServers);
SetDoHProviders(kTestDoHProviders);
EXPECT_CALL(*ares_client_, Resolve(_, _, _, _, _))
.Times(kTestNameServers.size())
.WillRepeatedly(Return(true));
EXPECT_CALL(*curl_client_, Resolve(_, _, _, _, _)).Times(0);
auto sock_fd = std::make_unique<Resolver::SocketFd>(SOCK_STREAM, 0);
resolver_->Resolve(sock_fd->weak_factory.GetWeakPtr());
EXPECT_GT(sock_fd->num_active_queries, 0);
}
TEST_F(ResolverTest, Resolve_DNSDoHServersPartiallyValidated) {
SetNameServers(kTestNameServers);
SetDoHProviders(kTestDoHProviders);
const auto& validated_doh_provider = kTestDoHProviders.front();
ValidateDoHProvider(validated_doh_provider);
// Expect resolving to be only be done using the validated provider.
EXPECT_CALL(*ares_client_, Resolve(_, _, _, _, _)).Times(0);
EXPECT_CALL(*curl_client_, Resolve(_, _, _, validated_doh_provider, _))
.WillOnce(Return(true));
auto sock_fd = std::make_unique<Resolver::SocketFd>(SOCK_STREAM, 0);
resolver_->Resolve(sock_fd->weak_factory.GetWeakPtr());
EXPECT_GT(sock_fd->num_active_queries, 0);
}
TEST_F(ResolverTest, Resolve_DNSDoHServersValidated) {
SetNameServers(kTestNameServers, /*validate=*/true);
SetDoHProviders(kTestDoHProviders, /*validate=*/true);
// Expect resolving to be be done using all validated providers.
EXPECT_CALL(*ares_client_, Resolve(_, _, _, _, _)).Times(0);
EXPECT_CALL(*curl_client_, Resolve(_, _, _, _, _))
.Times(kTestDoHProviders.size())
.WillRepeatedly(Return(true));
auto sock_fd = std::make_unique<Resolver::SocketFd>(SOCK_STREAM, 0);
resolver_->Resolve(sock_fd->weak_factory.GetWeakPtr());
EXPECT_GT(sock_fd->num_active_queries, 0);
}
TEST_F(ResolverTest, Resolve_DNSServers) {
SetNameServers(kTestNameServers, /*validate=*/true);
// Expect resolving to be be done using all validated name servers.
EXPECT_CALL(*ares_client_, Resolve(_, _, _, _, _))
.Times(kTestNameServers.size())
.WillRepeatedly(Return(true));
EXPECT_CALL(*curl_client_, Resolve(_, _, _, _, _)).Times(0);
auto sock_fd = std::make_unique<Resolver::SocketFd>(SOCK_STREAM, 0);
resolver_->Resolve(sock_fd->weak_factory.GetWeakPtr());
EXPECT_GT(sock_fd->num_active_queries, 0);
}
TEST_F(ResolverTest, Resolve_DNSDoHServersFallbackNotValidated) {
SetNameServers(kTestNameServers);
SetDoHProviders(kTestDoHProviders);
// Expect resolving to be be done using all name servers when nothing is
// validated.
EXPECT_CALL(*ares_client_, Resolve(_, _, _, _, _))
.Times(kTestNameServers.size())
.WillRepeatedly(Return(true));
EXPECT_CALL(*curl_client_, Resolve(_, _, _, _, _)).Times(0);
auto sock_fd = std::make_unique<Resolver::SocketFd>(SOCK_STREAM, 0);
resolver_->Resolve(sock_fd->weak_factory.GetWeakPtr());
EXPECT_GT(sock_fd->num_active_queries, 0);
}
TEST_F(ResolverTest, Resolve_DNSDoHServersFallbackPartiallyValidated) {
SetNameServers(kTestNameServers);
SetDoHProviders(kTestDoHProviders);
const auto& validated_name_server = kTestNameServers.front();
ValidateNameServer(validated_name_server);
// Expect resolving to be only be done using the validated name server.
EXPECT_CALL(*ares_client_, Resolve(_, _, validated_name_server, _, _))
.WillOnce(Return(true));
EXPECT_CALL(*curl_client_, Resolve(_, _, _, _, _)).Times(0);
auto sock_fd = std::make_unique<Resolver::SocketFd>(SOCK_STREAM, 0);
resolver_->Resolve(sock_fd->weak_factory.GetWeakPtr());
EXPECT_GT(sock_fd->num_active_queries, 0);
}
TEST_F(ResolverTest, Resolve_DNSDoHServersFallbackValidated) {
SetNameServers(kTestNameServers, /*validate=*/true);
SetDoHProviders(kTestDoHProviders, /*validate=*/true);
// Expect fallback resolving to be done using validated name servers.
EXPECT_CALL(*ares_client_, Resolve(_, _, _, _, _))
.Times(kTestNameServers.size())
.WillRepeatedly(Return(true));
EXPECT_CALL(*curl_client_, Resolve(_, _, _, _, _)).Times(0);
auto sock_fd = std::make_unique<Resolver::SocketFd>(SOCK_STREAM, 0);
resolver_->Resolve(sock_fd->weak_factory.GetWeakPtr(), true);
EXPECT_GT(sock_fd->num_active_queries, 0);
}
TEST_F(ResolverTest, CurlResult_CURLFail) {
SetNameServers(kTestNameServers, /*validate=*/true);
SetDoHProviders(kTestDoHProviders, /*validate=*/true);
EXPECT_CALL(*curl_client_, Resolve(_, _, _, _, _))
.WillRepeatedly(Return(true));
auto sock_fd = std::make_unique<Resolver::SocketFd>(SOCK_STREAM, 0);
resolver_->Resolve(sock_fd->weak_factory.GetWeakPtr());
EXPECT_GT(sock_fd->num_active_queries, 0);
// Expect query to be done with Do53.
EXPECT_CALL(*ares_client_, Resolve(_, _, _, _, _))
.Times(kTestNameServers.size())
.WillRepeatedly(Return(true));
EXPECT_CALL(*curl_client_, Resolve(_, _, _, _, _)).Times(0);
// All curl results failed with curl error.
DoHCurlClient::CurlResult res(CURLE_COULDNT_CONNECT, 0 /* http_code */,
0 /* timeout */);
for (int i = 0; i < kTestDoHProviders.size(); i++) {
resolver_->HandleCurlResult(sock_fd->weak_factory.GetWeakPtr(), nullptr,
res, {});
}
task_environment_.RunUntilIdle();
}
TEST_F(ResolverTest, CurlResult_HTTPError) {
SetNameServers(kTestNameServers, /*validate=*/true);
SetDoHProviders(kTestDoHProviders, /*validate=*/true);
EXPECT_CALL(*curl_client_, Resolve(_, _, _, _, _))
.WillRepeatedly(Return(true));
auto sock_fd = std::make_unique<Resolver::SocketFd>(SOCK_STREAM, 0);
resolver_->Resolve(sock_fd->weak_factory.GetWeakPtr());
EXPECT_GT(sock_fd->num_active_queries, 0);
// Expect query to be done with Do53.
EXPECT_CALL(*ares_client_, Resolve(_, _, _, _, _))
.Times(kTestNameServers.size())
.WillRepeatedly(Return(true));
EXPECT_CALL(*curl_client_, Resolve(_, _, _, _, _)).Times(0);
// All curl results failed with a HTTP error.
DoHCurlClient::CurlResult res(CURLE_OK, 403 /* http_code */, 0 /*timeout*/);
for (int i = 0; i < kTestDoHProviders.size(); i++) {
resolver_->HandleCurlResult(sock_fd->weak_factory.GetWeakPtr(), nullptr,
res, {});
}
task_environment_.RunUntilIdle();
}
TEST_F(ResolverTest, CurlResult_SuccessNoRetry) {
SetNameServers(kTestNameServers, /*validate=*/true);
SetDoHProviders(kTestDoHProviders, /*validate=*/true);
EXPECT_CALL(*curl_client_, Resolve(_, _, _, _, _))
.WillRepeatedly(Return(true));
auto sock_fd = std::make_unique<Resolver::SocketFd>(SOCK_STREAM, 0);
resolver_->Resolve(sock_fd->weak_factory.GetWeakPtr());
EXPECT_GT(sock_fd->num_active_queries, 0);
// Expect no more queries.
EXPECT_CALL(*ares_client_, Resolve(_, _, _, _, _)).Times(0);
EXPECT_CALL(*curl_client_, Resolve(_, _, _, _, _)).Times(0);
DoHCurlClient::CurlResult res(CURLE_OK, 200 /* http_code */, 0 /*timeout*/);
for (int i = 0; i < kTestDoHProviders.size(); i++) {
resolver_->HandleCurlResult(sock_fd->weak_factory.GetWeakPtr(), nullptr,
res, {});
}
task_environment_.RunUntilIdle();
}
TEST_F(ResolverTest, CurlResult_CurlErrorNoRetry) {
SetNameServers(kTestNameServers, /*validate=*/true);
SetDoHProviders(kTestDoHProviders, /*validate=*/true, /*always_on_doh=*/true);
EXPECT_CALL(*curl_client_, Resolve(_, _, _, _, _))
.WillRepeatedly(Return(true));
auto sock_fd = std::make_unique<Resolver::SocketFd>(SOCK_STREAM, 0);
resolver_->Resolve(sock_fd->weak_factory.GetWeakPtr());
EXPECT_GT(sock_fd->num_active_queries, 0);
// Expect no more queries.
EXPECT_CALL(*ares_client_, Resolve(_, _, _, _, _)).Times(0);
EXPECT_CALL(*curl_client_, Resolve(_, _, _, _, _)).Times(0);
DoHCurlClient::CurlResult res(CURLE_OUT_OF_MEMORY, 0 /* http_code */,
0 /* timeout */);
for (int i = 0; i < kTestDoHProviders.size(); i++) {
resolver_->HandleCurlResult(sock_fd->weak_factory.GetWeakPtr(), nullptr,
res, {});
}
task_environment_.RunUntilIdle();
}
TEST_F(ResolverTest, CurlResult_HTTPErrorNoRetry) {
SetNameServers(kTestNameServers, /*validate=*/true);
SetDoHProviders(kTestDoHProviders, /*validate=*/true, /*always_on_doh=*/true);
EXPECT_CALL(*curl_client_, Resolve(_, _, _, _, _))
.WillRepeatedly(Return(true));
auto sock_fd = std::make_unique<Resolver::SocketFd>(SOCK_STREAM, 0);
resolver_->Resolve(sock_fd->weak_factory.GetWeakPtr());
EXPECT_GT(sock_fd->num_active_queries, 0);
// Expect no more queries.
EXPECT_CALL(*ares_client_, Resolve(_, _, _, _, _)).Times(0);
EXPECT_CALL(*curl_client_, Resolve(_, _, _, _, _)).Times(0);
DoHCurlClient::CurlResult res(CURLE_OK, 403 /* http_code */, 0 /* timeout*/);
for (int i = 0; i < kTestDoHProviders.size(); i++) {
resolver_->HandleCurlResult(sock_fd->weak_factory.GetWeakPtr(), nullptr,
res, {});
}
task_environment_.RunUntilIdle();
}
TEST_F(ResolverTest, CurlResult_FailTooManyRetries) {
SetNameServers(kTestNameServers, /*validate=*/true);
SetDoHProviders(kTestDoHProviders, /*validate=*/true);
EXPECT_CALL(*ares_client_, Resolve(_, _, _, _, _)).Times(0);
EXPECT_CALL(*curl_client_, Resolve(_, _, _, _, _))
.WillRepeatedly(Return(true));
auto sock_fd = std::make_unique<Resolver::SocketFd>(SOCK_STREAM, 0);
resolver_->Resolve(sock_fd->weak_factory.GetWeakPtr());
EXPECT_GT(sock_fd->num_active_queries, 0);
// Expect no more queries.
EXPECT_CALL(*ares_client_, Resolve(_, _, _, _, _)).Times(0);
EXPECT_CALL(*curl_client_, Resolve(_, _, _, _, _)).Times(0);
sock_fd->num_retries = INT_MAX;
DoHCurlClient::CurlResult res(CURLE_OK, 429 /* http_code */, 0 /*timeout*/);
for (int i = 0; i < kTestDoHProviders.size(); i++) {
resolver_->HandleCurlResult(sock_fd->weak_factory.GetWeakPtr(), nullptr,
res, {});
}
task_environment_.RunUntilIdle();
}
TEST_F(ResolverTest, HandleAresResult_Success) {
SetNameServers(kTestNameServers, /*validate=*/true);
EXPECT_CALL(*ares_client_, Resolve(_, _, _, _, _))
.WillRepeatedly(Return(true));
auto sock_fd = std::make_unique<Resolver::SocketFd>(SOCK_DGRAM, 0);
resolver_->Resolve(sock_fd->weak_factory.GetWeakPtr());
EXPECT_GT(sock_fd->num_active_queries, 0);
// Expect no more queries.
EXPECT_CALL(*ares_client_, Resolve(_, _, _, _, _)).Times(0);
EXPECT_CALL(*curl_client_, Resolve(_, _, _, _, _)).Times(0);
sock_fd->num_retries = INT_MAX;
for (int i = 0; i < kTestNameServers.size(); i++) {
resolver_->HandleAresResult(sock_fd->weak_factory.GetWeakPtr(), nullptr,
ARES_SUCCESS, {});
}
task_environment_.RunUntilIdle();
}
TEST_F(ResolverTest, ConstructServFailResponse_ValidQuery) {
const char kDnsQuery[] = {'J', 'G', '\x01', ' ', '\x00', '\x01',
'\x00', '\x00', '\x00', '\x00', '\x00', '\x01',
'\x06', 'g', 'o', 'o', 'g', 'l',
'e', '\x03', 'c', 'o', 'm', '\x00',
'\x00', '\x01', '\x00', '\x01'};
const char kServFailResponse[] = {
'J', 'G', '\x80', '\x02', '\x00', '\x01', '\x00',
'\x00', '\x00', '\x00', '\x00', '\x00', '\x06', 'g',
'o', 'o', 'g', 'l', 'e', '\x03', 'c',
'o', 'm', '\x00', '\x00', '\x01', '\x00', '\x01'};
patchpanel::DnsResponse response = resolver_->ConstructServFailResponse(
base::span<const char>(kDnsQuery, sizeof(kDnsQuery)));
std::vector<char> response_data(
response.io_buffer()->data(),
response.io_buffer()->data() + response.io_buffer_size());
EXPECT_THAT(response_data, ElementsAreArray(kServFailResponse));
}
TEST_F(ResolverTest, ConstructServFailResponse_BadLength) {
const char kDnsQuery[] = {};
const char kServFailResponse[] = {'\x00', '\x00', '\x80', '\x02',
'\x00', '\x00', '\x00', '\x00',
'\x00', '\x00', '\x00', '\x00'};
patchpanel::DnsResponse response = resolver_->ConstructServFailResponse(
base::span<const char>(kDnsQuery, sizeof(kDnsQuery)));
std::vector<char> response_data(
response.io_buffer()->data(),
response.io_buffer()->data() + response.io_buffer_size());
EXPECT_THAT(response_data, ElementsAreArray(kServFailResponse));
}
TEST_F(ResolverTest, ConstructServFailResponse_BadQuery) {
const char kDnsQuery[] = {'g', 'o', 'o', 'g', 'l',
'e', '\x03', 'c', 'o', 'm'};
const char kServFailResponse[] = {'\x00', '\x00', '\x80', '\x02',
'\x00', '\x00', '\x00', '\x00',
'\x00', '\x00', '\x00', '\x00'};
patchpanel::DnsResponse response = resolver_->ConstructServFailResponse(
base::span<const char>(kDnsQuery, sizeof(kDnsQuery)));
std::vector<char> response_data(
response.io_buffer()->data(),
response.io_buffer()->data() + response.io_buffer_size());
EXPECT_THAT(response_data, ElementsAreArray(kServFailResponse));
}
TEST_F(ResolverTest, Probe_Started) {
resolver_->SetProbingEnabled(true);
for (const auto& name_server : kTestNameServers) {
EXPECT_CALL(*ares_client_, Resolve(_, _, name_server, _, _))
.WillOnce(Return(true));
}
for (const auto& doh_provider : kTestDoHProviders) {
EXPECT_CALL(*curl_client_, Resolve(_, _, _, doh_provider, _))
.WillOnce(Return(true));
}
SetNameServers(kTestNameServers);
SetDoHProviders(kTestDoHProviders);
}
TEST_F(ResolverTest, Probe_SetNameServers) {
resolver_->SetProbingEnabled(true);
auto name_servers = kTestNameServers;
for (const auto& name_server : name_servers) {
EXPECT_CALL(*ares_client_, Resolve(_, _, name_server, _, _))
.WillOnce(Return(true));
}
const auto& new_name_server = "9.9.9.9";
EXPECT_CALL(*ares_client_, Resolve(_, _, new_name_server, _, _)).Times(0);
SetNameServers(name_servers);
name_servers.push_back(new_name_server);
// Check that only the newly added name servers are probed.
for (const auto& name_server : name_servers) {
EXPECT_CALL(*ares_client_, Resolve(_, _, name_server, _, _)).Times(0);
}
EXPECT_CALL(*ares_client_, Resolve(_, _, new_name_server, _, _))
.WillOnce(Return(true));
SetNameServers(name_servers);
}
TEST_F(ResolverTest, Probe_SetDoHProviders) {
resolver_->SetProbingEnabled(true);
auto doh_providers = kTestDoHProviders;
for (const auto& doh_provider : doh_providers) {
EXPECT_CALL(*curl_client_, Resolve(_, _, _, doh_provider, _))
.WillOnce(Return(true));
}
const auto& new_doh_provider = "https://dns3.google/dns-query";
EXPECT_CALL(*curl_client_, Resolve(_, _, _, new_doh_provider, _)).Times(0);
SetNameServers(kTestNameServers);
SetDoHProviders(doh_providers);
doh_providers.push_back(new_doh_provider);
// Check that only the newly added DoH providers and name servers are probed.
for (const auto& doh_provider : doh_providers) {
EXPECT_CALL(*curl_client_, Resolve(_, _, _, doh_provider, _)).Times(0);
}
EXPECT_CALL(*curl_client_, Resolve(_, _, _, new_doh_provider, _))
.WillOnce(Return(true));
SetDoHProviders(doh_providers);
}
TEST_F(ResolverTest, Probe_InvalidateNameServer) {
auto name_servers = kTestNameServers;
SetNameServers(name_servers, /*validate=*/true);
// Invalidate a name server.
auto invalidated_name_server = name_servers.back();
name_servers.pop_back();
InvalidateNameServer(invalidated_name_server);
// Query should be done using all name servers except the invalidated one.
EXPECT_CALL(*ares_client_, Resolve(_, _, invalidated_name_server, _, _))
.Times(0);
for (const auto& name_server : name_servers) {
EXPECT_CALL(*ares_client_, Resolve(_, _, name_server, _, _))
.WillOnce(Return(true));
}
auto fd_check = std::make_unique<Resolver::SocketFd>(SOCK_DGRAM, 0);
resolver_->Resolve(fd_check->weak_factory.GetWeakPtr());
EXPECT_GT(fd_check->num_active_queries, 0);
}
TEST_F(ResolverTest, Probe_InvalidateDoHProvider) {
auto doh_providers = kTestDoHProviders;
SetNameServers(kTestNameServers);
SetDoHProviders(doh_providers, /*validate=*/true);
// Invalidate a DoH provider.
auto invalidated_doh_provider = doh_providers.back();
doh_providers.pop_back();
InvalidateDoHProvider(invalidated_doh_provider);
// Query should be done using all DoH providers except the invalidated one.
EXPECT_CALL(*curl_client_, Resolve(_, _, _, invalidated_doh_provider, _))
.Times(0);
for (const auto& doh_provider : doh_providers) {
EXPECT_CALL(*curl_client_, Resolve(_, _, _, doh_provider, _))
.WillOnce(Return(true));
}
auto fd_check = std::make_unique<Resolver::SocketFd>(SOCK_DGRAM, 0);
resolver_->Resolve(fd_check->weak_factory.GetWeakPtr());
EXPECT_GT(fd_check->num_active_queries, 0);
}
TEST_F(ResolverTest, Probe_Do53ProbeRestarted) {
auto name_servers = kTestNameServers;
SetNameServers(name_servers, /*validate=*/true);
auto invalidated_name_server = name_servers.back();
name_servers.pop_back();
// Expect probe to be restarted only for the invalidated name server.
EXPECT_CALL(*ares_client_, Resolve(_, _, invalidated_name_server, _, _))
.WillOnce(Return(true));
for (const auto& name_server : name_servers) {
EXPECT_CALL(*ares_client_, Resolve(_, _, name_server, _, _)).Times(0);
}
resolver_->SetProbingEnabled(true);
// Invalidate a name server.
InvalidateNameServer(invalidated_name_server);
}
TEST_F(ResolverTest, Probe_DoHProbeRestarted) {
auto doh_providers = kTestDoHProviders;
SetNameServers(kTestNameServers);
SetDoHProviders(doh_providers, /*validate=*/true);
auto invalidated_doh_provider = doh_providers.back();
doh_providers.pop_back();
// Expect probe to be restarted only for the invalidated DoH provider.
EXPECT_CALL(*curl_client_, Resolve(_, _, _, invalidated_doh_provider, _))
.WillOnce(Return(true));
for (const auto& doh_provider : doh_providers) {
EXPECT_CALL(*curl_client_, Resolve(_, _, _, doh_provider, _)).Times(0);
}
resolver_->SetProbingEnabled(true);
// Invalidate a DoH provider.
InvalidateDoHProvider(invalidated_doh_provider);
}
TEST_F(ResolverTest, Resolve_HandleUDPQuery) {
SetNameServers(kTestNameServers);
for (const auto& name_server : kTestNameServers) {
EXPECT_CALL(*ares_client_, Resolve(_, _, name_server, _, SOCK_DGRAM))
.WillOnce(Return(true));
}
auto sock_fd = std::make_unique<Resolver::SocketFd>(SOCK_DGRAM, /*fd=*/0);
resolver_->HandleDNSQuery(std::move(sock_fd));
}
TEST_F(ResolverTest, Resolve_HandleTCPQuery) {
SetNameServers(kTestNameServers);
auto sock_fd = std::make_unique<Resolver::SocketFd>(SOCK_STREAM, /*fd=*/0);
memcpy(sock_fd->msg, kDNSTCPFragment, sizeof(kDNSTCPFragment));
sock_fd->len = sizeof(kDNSTCPFragment);
for (const auto& name_server : kTestNameServers) {
EXPECT_CALL(*ares_client_, Resolve(_, _, name_server, _, SOCK_STREAM))
.WillOnce(Return(true));
}
resolver_->HandleDNSQuery(std::move(sock_fd));
}
TEST_F(ResolverTest, Resolve_HandleChunkedTCPQuery) {
SetNameServers(kTestNameServers);
int partial_len = 15;
ASSERT_LT(partial_len, sizeof(kDNSTCPFragment));
// Send partial TCP data.
auto sock_fd = std::make_unique<Resolver::SocketFd>(SOCK_STREAM, /*fd=*/0);
sock_fd->buf.resize(kTCPBufferPaddingLength + sizeof(kDNSTCPFragment));
memcpy(sock_fd->msg, kDNSTCPFragment, partial_len);
sock_fd->len = partial_len;
EXPECT_CALL(*ares_client_, Resolve(_, _, _, _, _)).Times(0);
resolver_->HandleDNSQuery(std::move(sock_fd));
// Send remaining TCP data.
sock_fd = resolver_->PopPendingSocketFd(/*fd=*/0);
memcpy(sock_fd->msg + partial_len, kDNSTCPFragment + partial_len,
sizeof(kDNSTCPFragment) - partial_len);
sock_fd->len += sizeof(kDNSTCPFragment) - partial_len;
for (const auto& name_server : kTestNameServers) {
EXPECT_CALL(*ares_client_, Resolve(_, _, name_server, _, SOCK_STREAM))
.WillOnce(Return(true));
}
resolver_->HandleDNSQuery(std::move(sock_fd));
}
TEST_F(ResolverTest, Resolve_HandleMultipleTCPQueries) {
SetNameServers(kTestNameServers);
// Send 2 TCP DNS queries.
auto sock_fd = std::make_unique<Resolver::SocketFd>(SOCK_STREAM, /*fd=*/0);
sock_fd->buf.resize(kTCPBufferPaddingLength + 2 * sizeof(kDNSTCPFragment));
memcpy(sock_fd->msg, kDNSTCPFragment, sizeof(kDNSTCPFragment));
memcpy(sock_fd->msg + sizeof(kDNSTCPFragment), kDNSTCPFragment,
sizeof(kDNSTCPFragment));
sock_fd->len = 2 * sizeof(kDNSTCPFragment);
for (const auto& name_server : kTestNameServers) {
EXPECT_CALL(*ares_client_, Resolve(_, _, name_server, _, SOCK_STREAM))
.Times(2)
.WillRepeatedly(Return(true));
}
resolver_->HandleDNSQuery(std::move(sock_fd));
}
TEST_F(ResolverTest, Resolve_ChunkedTCPQueryNotResolved) {
SetNameServers(kTestNameServers);
// Expect no resolving.
EXPECT_CALL(*ares_client_, Resolve(_, _, _, _, _)).Times(0);
// Receive 1-byte at a time.
auto sock_fd = std::make_unique<Resolver::SocketFd>(SOCK_STREAM, /*fd=*/0);
sock_fd->buf.resize(kTCPBufferPaddingLength + sizeof(kDNSTCPFragment));
memcpy(sock_fd->msg, kDNSTCPFragment, 1);
sock_fd->len += 1;
// Receive all data except for the last byte.
while (sock_fd->len < sizeof(kDNSTCPFragment)) {
resolver_->HandleDNSQuery(std::move(sock_fd));
sock_fd = resolver_->PopPendingSocketFd(/*fd=*/0);
memcpy(sock_fd->msg + sock_fd->len, kDNSTCPFragment + sock_fd->len, 1);
sock_fd->len += 1;
}
}
TEST_F(ResolverTest, SocketFd_Resize) {
for (const int sock_type : {SOCK_STREAM, SOCK_DGRAM}) {
auto sock_fd = std::make_unique<Resolver::SocketFd>(sock_type, /*fd=*/0);
// Expects buffer size to not grow when not full.
int cur_size = sock_fd->try_resize();
EXPECT_EQ(sock_fd->buf.size(), cur_size);
// Expects buffer size to grow.
while (cur_size < kMaxDNSBufSize) {
sock_fd->len = sock_fd->buf.size();
if (sock_fd->type == SOCK_STREAM) {
sock_fd->len -= kTCPBufferPaddingLength;
}
EXPECT_GT(sock_fd->try_resize(), cur_size);
cur_size = sock_fd->buf.size();
}
EXPECT_EQ(sock_fd->buf.size(), kMaxDNSBufSize);
// Expects buffer size to no longer grow after maximum size.
EXPECT_EQ(sock_fd->try_resize(), kMaxDNSBufSize);
}
}
TEST_F(ResolverTest, IsNXDOMAIN_NXDOMAIN) {
const char kDnsResponse[] = {'\x00', '\x01', '\x81', '\x83', '\x00', '\x01',
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
'\x06', 'g', 'o', 'o', 'g', 'l',
'e', '\x03', 'c', 'o', 'm', '\x00',
'\x00', '\x01', '\x00', '\x01'};
EXPECT_TRUE(resolver_->IsNXDOMAIN(base::span<const unsigned char>(
reinterpret_cast<const unsigned char*>(kDnsResponse),
sizeof(kDnsResponse))));
}
TEST_F(ResolverTest, IsNXDOMAIN_NotNXDOMAIN) {
const char kDnsResponse[] = {'\x00', '\x01', '\x81', '\x81', '\x00', '\x01',
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
'\x06', 'g', 'o', 'o', 'g', 'l',
'e', '\x03', 'c', 'o', 'm', '\x00',
'\x00', '\x01', '\x00', '\x01'};
EXPECT_FALSE(resolver_->IsNXDOMAIN(base::span<const unsigned char>(
reinterpret_cast<const unsigned char*>(kDnsResponse),
sizeof(kDnsResponse))));
}
TEST_F(ResolverTest, IsNXDOMAIN_BadResponse) {
const char kDnsResponse[] = {'\x00', '\x01', '\x02', '\x03', '\x04', '\x05'};
EXPECT_FALSE(resolver_->IsNXDOMAIN(base::span<const unsigned char>(
reinterpret_cast<const unsigned char*>(kDnsResponse),
sizeof(kDnsResponse))));
}
TEST_F(ResolverTest, BypassDoH_LiteralMatch) {
std::vector<std::string> doh_excluded_domains = {"google.com"};
resolver_->SetDomainDoHConfigs(/*doh_included_domains=*/{},
doh_excluded_domains);
EXPECT_TRUE(resolver_->BypassDoH("google.com"));
EXPECT_FALSE(resolver_->BypassDoH("a.google.com"));
}
TEST_F(ResolverTest, BypassDoH_SuffixMatch) {
std::vector<std::string> doh_excluded_domains = {"*.google.com"};
resolver_->SetDomainDoHConfigs(/*doh_included_domains=*/{},
doh_excluded_domains);
EXPECT_FALSE(resolver_->BypassDoH("google.com"));
EXPECT_TRUE(resolver_->BypassDoH("a.google.com"));
}
TEST_F(ResolverTest, BypassDoH_PreferMoreSpecificMatch) {
std::vector<std::string> doh_excluded_domains = {"*.exclude",
"exclude.include"};
std::vector<std::string> doh_included_domains = {"*.include",
"include.exclude"};
resolver_->SetDomainDoHConfigs(doh_included_domains, doh_excluded_domains);
EXPECT_TRUE(resolver_->BypassDoH("test.exclude"));
EXPECT_FALSE(resolver_->BypassDoH("test.include"));
EXPECT_TRUE(resolver_->BypassDoH("exclude.include"));
EXPECT_FALSE(resolver_->BypassDoH("include.exclude"));
}
TEST_F(ResolverTest, BypassDoH_IncludeOverExclude) {
std::vector<std::string> doh_excluded_domains = {"*.google.com",
"google.com"};
std::vector<std::string> doh_included_domains = {"*.google.com",
"google.com"};
resolver_->SetDomainDoHConfigs(doh_included_domains, doh_excluded_domains);
EXPECT_FALSE(resolver_->BypassDoH("google.com"));
EXPECT_FALSE(resolver_->BypassDoH("a.google.com"));
}
TEST_F(ResolverTest, BypassDoH_DefaultsToInclude) {
std::vector<std::string> doh_excluded_domains = {"unused"};
resolver_->SetDomainDoHConfigs(/*doh_included_domains=*/{},
doh_excluded_domains);
EXPECT_FALSE(resolver_->BypassDoH("google.com"));
}
TEST_F(ResolverTest, BypassDoH_ExcludeNotIncludedDomains) {
std::vector<std::string> doh_included_domains = {"google.com"};
resolver_->SetDomainDoHConfigs(doh_included_domains,
/*doh_excluded_domains=*/{});
EXPECT_TRUE(resolver_->BypassDoH("test.com"));
EXPECT_FALSE(resolver_->BypassDoH("google.com"));
}
TEST_F(ResolverTest, GetDNSQuestionName_ValidQuery) {
const uint8_t kDnsQuery[] = {'J', 'G', '\x01', ' ', '\x00', '\x01',
'\x00', '\x00', '\x00', '\x00', '\x00', '\x01',
'\x06', 'g', 'o', 'o', 'g', 'l',
'e', '\x03', 'c', 'o', 'm', '\x00',
'\x00', '\x01', '\x00', '\x01'};
EXPECT_EQ("google.com",
resolver_->GetDNSQuestionName(
base::span<const uint8_t>(kDnsQuery, sizeof(kDnsQuery))));
}
TEST_F(ResolverTest, GetDNSQuestionName_InvalidQuery) {
const uint8_t kDnsQuery[] = {'J', 'G', '\x01', ' ', '\x00', '\x01',
'\x00', '\x00', '\x00', '\x00', '\x00', '\x01',
'\x06', 'g', 'o', 'o', 'g', 'l',
'e', '\x03', 'c', 'o', 'm', '\x09',
'\x00', '\x01', '\x00', '\x01'};
EXPECT_EQ(std::nullopt,
resolver_->GetDNSQuestionName(
base::span<const uint8_t>(kDnsQuery, sizeof(kDnsQuery))));
}
TEST_F(ResolverTest, GetDNSQuestionName_InvalidCharacter) {
const uint8_t kDnsQuery[] = {'J', 'G', '\x01', ' ', '\x00', '\x01',
'\x00', '\x00', '\x00', '\x00', '\x00', '\x01',
'\x06', 'g', 'o', 'o', 'g', 'l',
'e', '\x03', 'c', 'o', '*', '\x00',
'\x00', '\x01', '\x00', '\x01'};
EXPECT_EQ(std::nullopt,
resolver_->GetDNSQuestionName(
base::span<const uint8_t>(kDnsQuery, sizeof(kDnsQuery))));
}
TEST_F(ResolverTest, GetDNSQuestionName_QueryTooShort) {
const uint8_t kDnsQuery[] = {'a'};
EXPECT_EQ(std::nullopt,
resolver_->GetDNSQuestionName(
base::span<const uint8_t>(kDnsQuery, sizeof(kDnsQuery))));
}
TEST_F(ResolverTest, GetDNSQuestionName_QueryTooLong) {
const uint8_t kDnsQuery[] = {
'J', 'G', '\x01', ' ', '\x00', '\x01', '\x00', '\x00', '\x00',
'\x00', '\x00', '\x01', '\x30', 'a', 'a', 'a', 'a', 'a',
'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
'a', 'a', 'a', 'a', 'a', 'a', 'a', '\x30', 'a',
'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
'a', 'a', '\x30', 'a', 'a', 'a', 'a', 'a', 'a',
'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
'a', 'a', 'a', 'a', 'a', 'a', '\x30', 'a', 'a',
'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
'a', '\x30', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
'a', 'a', 'a', 'a', 'a', '\x30', 'a', 'a', 'a',
'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
'\x00', '\x00', '\x01', '\x00', '\x01'};
EXPECT_EQ(std::nullopt,
resolver_->GetDNSQuestionName(
base::span<const uint8_t>(kDnsQuery, sizeof(kDnsQuery))));
}
TEST_F(ResolverTest, ValidateQuery_ValidQuery) {
const uint8_t kDnsQuery[] = {'J', 'G', '\x01', ' ', '\x00', '\x01',
'\x00', '\x00', '\x00', '\x00', '\x00', '\x01',
'\x06', 'g', 'o', 'o', 'g', 'l',
'e', '\x03', 'c', 'o', 'm', '\x00',
'\x00', '\x01', '\x00', '\x01'};
EXPECT_TRUE(resolver_->ValidateQuery(
base::span<const uint8_t>(kDnsQuery, sizeof(kDnsQuery))));
}
TEST_F(ResolverTest, ValidateQuery_InvalidQuery) {
const uint8_t kDnsQuery[] = {'J', 'G', '\x01', ' ', '\x00', '\x01',
'\x00', '\x00', '\x00', '\x00', '\x00', '\x01',
'\x06', 'g', 'o', 'o', 'g', 'l',
'e', '\x03', 'c', 'o', 'm', '\x09',
'\x00', '\x01', '\x00', '\x01'};
EXPECT_FALSE(resolver_->ValidateQuery(
base::span<const uint8_t>(kDnsQuery, sizeof(kDnsQuery))));
}
TEST_F(ResolverTest, ValidateQuery_QueryTooShort) {
const uint8_t kDnsQuery[] = {'a'};
EXPECT_FALSE(resolver_->ValidateQuery(
base::span<const uint8_t>(kDnsQuery, sizeof(kDnsQuery))));
}
TEST_F(ResolverTest, ValidateQuery_QueryTooLong) {
const uint8_t kDnsQuery[] = {
'J', 'G', '\x01', ' ', '\x00', '\x01', '\x00', '\x00', '\x00',
'\x00', '\x00', '\x01', '\x30', 'a', 'a', 'a', 'a', 'a',
'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
'a', 'a', 'a', 'a', 'a', 'a', 'a', '\x30', 'a',
'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
'a', 'a', '\x30', 'a', 'a', 'a', 'a', 'a', 'a',
'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
'a', 'a', 'a', 'a', 'a', 'a', '\x30', 'a', 'a',
'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
'a', '\x30', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
'a', 'a', 'a', 'a', 'a', '\x30', 'a', 'a', 'a',
'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
'\x00', '\x00', '\x01', '\x00', '\x01'};
EXPECT_FALSE(resolver_->ValidateQuery(
base::span<const uint8_t>(kDnsQuery, sizeof(kDnsQuery))));
}
} // namespace dns_proxy