1 // Copyright 2012 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "net/dns/dns_transaction.h"
6
7 #include <stdint.h>
8
9 #include <algorithm>
10 #include <limits>
11 #include <memory>
12 #include <utility>
13 #include <vector>
14
15 #include "base/base64url.h"
16 #include "base/containers/circular_deque.h"
17 #include "base/functional/bind.h"
18 #include "base/memory/raw_ptr.h"
19 #include "base/numerics/safe_math.h"
20 #include "base/rand_util.h"
21 #include "base/ranges/algorithm.h"
22 #include "base/run_loop.h"
23 #include "base/strings/string_util.h"
24 #include "base/strings/stringprintf.h"
25 #include "base/sys_byteorder.h"
26 #include "base/task/single_thread_task_runner.h"
27 #include "base/test/bind.h"
28 #include "base/test/metrics/histogram_tester.h"
29 #include "base/time/time.h"
30 #include "base/values.h"
31 #include "net/base/idempotency.h"
32 #include "net/base/ip_address.h"
33 #include "net/base/port_util.h"
34 #include "net/base/upload_bytes_element_reader.h"
35 #include "net/base/url_util.h"
36 #include "net/cookies/cookie_access_result.h"
37 #include "net/cookies/cookie_util.h"
38 #include "net/dns/dns_config.h"
39 #include "net/dns/dns_names_util.h"
40 #include "net/dns/dns_query.h"
41 #include "net/dns/dns_response.h"
42 #include "net/dns/dns_server_iterator.h"
43 #include "net/dns/dns_session.h"
44 #include "net/dns/dns_test_util.h"
45 #include "net/dns/public/dns_over_https_config.h"
46 #include "net/dns/public/dns_over_https_server_config.h"
47 #include "net/dns/public/dns_protocol.h"
48 #include "net/dns/public/secure_dns_policy.h"
49 #include "net/dns/resolve_context.h"
50 #include "net/http/http_util.h"
51 #include "net/log/net_log.h"
52 #include "net/log/net_log_capture_mode.h"
53 #include "net/log/net_log_with_source.h"
54 #include "net/proxy_resolution/proxy_config_service_fixed.h"
55 #include "net/socket/socket_test_util.h"
56 #include "net/test/gtest_util.h"
57 #include "net/test/test_with_task_environment.h"
58 #include "net/test/url_request/url_request_failed_job.h"
59 #include "net/third_party/uri_template/uri_template.h"
60 #include "net/url_request/url_request_context.h"
61 #include "net/url_request/url_request_context_builder.h"
62 #include "net/url_request/url_request_filter.h"
63 #include "net/url_request/url_request_interceptor.h"
64 #include "net/url_request/url_request_test_util.h"
65 #include "testing/gmock/include/gmock/gmock.h"
66 #include "testing/gtest/include/gtest/gtest.h"
67 #include "third_party/abseil-cpp/absl/types/optional.h"
68
69 using net::test::IsOk;
70
71 namespace net {
72
73 namespace {
74
75 base::TimeDelta kFallbackPeriod = base::Seconds(1);
76
77 const char kMockHostname[] = "mock.http";
78
DomainFromDot(base::StringPiece dotted_name)79 std::vector<uint8_t> DomainFromDot(base::StringPiece dotted_name) {
80 absl::optional<std::vector<uint8_t>> dns_name =
81 dns_names_util::DottedNameToNetwork(dotted_name);
82 CHECK(dns_name.has_value());
83 return dns_name.value();
84 }
85
86 enum class Transport { UDP, TCP, HTTPS };
87
88 class NetLogCountingObserver : public net::NetLog::ThreadSafeObserver {
89 public:
90 NetLogCountingObserver() = default;
91
~NetLogCountingObserver()92 ~NetLogCountingObserver() override {
93 if (net_log())
94 net_log()->RemoveObserver(this);
95 }
96
OnAddEntry(const NetLogEntry & entry)97 void OnAddEntry(const NetLogEntry& entry) override {
98 ++count_;
99 if (!entry.params.empty()) {
100 dict_count_++;
101 }
102 }
103
count() const104 int count() const { return count_; }
105
dict_count() const106 int dict_count() const { return dict_count_; }
107
108 private:
109 int count_ = 0;
110 int dict_count_ = 0;
111 };
112
113 // A SocketDataProvider builder.
114 class DnsSocketData {
115 public:
116 // The ctor takes parameters for the DnsQuery.
DnsSocketData(uint16_t id,const char * dotted_name,uint16_t qtype,IoMode mode,Transport transport,const OptRecordRdata * opt_rdata=nullptr,DnsQuery::PaddingStrategy padding_strategy=DnsQuery::PaddingStrategy::NONE)117 DnsSocketData(uint16_t id,
118 const char* dotted_name,
119 uint16_t qtype,
120 IoMode mode,
121 Transport transport,
122 const OptRecordRdata* opt_rdata = nullptr,
123 DnsQuery::PaddingStrategy padding_strategy =
124 DnsQuery::PaddingStrategy::NONE)
125 : query_(std::make_unique<DnsQuery>(id,
126 DomainFromDot(dotted_name),
127 qtype,
128 opt_rdata,
129 padding_strategy)),
130 transport_(transport) {
131 if (Transport::TCP == transport_) {
132 auto length = std::make_unique<uint16_t>();
133 *length = base::HostToNet16(query_->io_buffer()->size());
134 writes_.emplace_back(mode, reinterpret_cast<const char*>(length.get()),
135 sizeof(uint16_t), num_reads_and_writes());
136 lengths_.push_back(std::move(length));
137 }
138 writes_.emplace_back(mode, query_->io_buffer()->data(),
139 query_->io_buffer()->size(), num_reads_and_writes());
140 }
141
142 DnsSocketData(const DnsSocketData&) = delete;
143 DnsSocketData& operator=(const DnsSocketData&) = delete;
144
145 ~DnsSocketData() = default;
146
ClearWrites()147 void ClearWrites() { writes_.clear(); }
148 // All responses must be added before GetProvider.
149
150 // Adds pre-built DnsResponse. |tcp_length| will be used in TCP mode only.
AddResponseWithLength(std::unique_ptr<DnsResponse> response,IoMode mode,uint16_t tcp_length)151 void AddResponseWithLength(std::unique_ptr<DnsResponse> response,
152 IoMode mode,
153 uint16_t tcp_length) {
154 CHECK(!provider_.get());
155 if (Transport::TCP == transport_) {
156 auto length = std::make_unique<uint16_t>();
157 *length = base::HostToNet16(tcp_length);
158 reads_.emplace_back(mode, reinterpret_cast<const char*>(length.get()),
159 sizeof(uint16_t), num_reads_and_writes());
160 lengths_.push_back(std::move(length));
161 }
162 reads_.emplace_back(mode, response->io_buffer()->data(),
163 response->io_buffer_size(), num_reads_and_writes());
164 responses_.push_back(std::move(response));
165 }
166
167 // Adds pre-built DnsResponse.
AddResponse(std::unique_ptr<DnsResponse> response,IoMode mode)168 void AddResponse(std::unique_ptr<DnsResponse> response, IoMode mode) {
169 uint16_t tcp_length = response->io_buffer_size();
170 AddResponseWithLength(std::move(response), mode, tcp_length);
171 }
172
173 // Adds pre-built response from |data| buffer.
AddResponseData(const uint8_t * data,size_t length,IoMode mode)174 void AddResponseData(const uint8_t* data, size_t length, IoMode mode) {
175 CHECK(!provider_.get());
176 AddResponse(std::make_unique<DnsResponse>(
177 reinterpret_cast<const char*>(data), length, 0),
178 mode);
179 }
180
181 // Adds pre-built response from |data| buffer.
AddResponseData(const uint8_t * data,size_t length,int offset,IoMode mode)182 void AddResponseData(const uint8_t* data,
183 size_t length,
184 int offset,
185 IoMode mode) {
186 CHECK(!provider_.get());
187 AddResponse(
188 std::make_unique<DnsResponse>(reinterpret_cast<const char*>(data),
189 length - offset, offset),
190 mode);
191 }
192
193 // Add no-answer (RCODE only) response matching the query.
AddRcode(int rcode,IoMode mode)194 void AddRcode(int rcode, IoMode mode) {
195 auto response = std::make_unique<DnsResponse>(
196 query_->io_buffer()->data(), query_->io_buffer()->size(), 0);
197 dns_protocol::Header* header =
198 reinterpret_cast<dns_protocol::Header*>(response->io_buffer()->data());
199 header->flags |= base::HostToNet16(dns_protocol::kFlagResponse | rcode);
200 AddResponse(std::move(response), mode);
201 }
202
203 // Add error response.
AddReadError(int error,IoMode mode)204 void AddReadError(int error, IoMode mode) {
205 reads_.emplace_back(mode, error, num_reads_and_writes());
206 }
207
208 // Build, if needed, and return the SocketDataProvider. No new responses
209 // should be added afterwards.
GetProvider()210 SequencedSocketData* GetProvider() {
211 if (provider_.get())
212 return provider_.get();
213 // Terminate the reads with ERR_IO_PENDING to prevent overrun and default to
214 // timeout.
215 if (transport_ != Transport::HTTPS) {
216 reads_.emplace_back(SYNCHRONOUS, ERR_IO_PENDING,
217 writes_.size() + reads_.size());
218 }
219 provider_ = std::make_unique<SequencedSocketData>(reads_, writes_);
220 if (Transport::TCP == transport_ || Transport::HTTPS == transport_) {
221 provider_->set_connect_data(MockConnect(reads_[0].mode, OK));
222 }
223 return provider_.get();
224 }
225
query_id() const226 uint16_t query_id() const { return query_->id(); }
227
query_buffer()228 IOBufferWithSize* query_buffer() { return query_->io_buffer(); }
229
230 private:
num_reads_and_writes() const231 size_t num_reads_and_writes() const { return reads_.size() + writes_.size(); }
232
233 std::unique_ptr<DnsQuery> query_;
234 Transport transport_;
235 std::vector<std::unique_ptr<uint16_t>> lengths_;
236 std::vector<std::unique_ptr<DnsResponse>> responses_;
237 std::vector<MockWrite> writes_;
238 std::vector<MockRead> reads_;
239 std::unique_ptr<SequencedSocketData> provider_;
240 };
241
242 class TestSocketFactory;
243
244 // A variant of MockUDPClientSocket which always fails to Connect.
245 class FailingUDPClientSocket : public MockUDPClientSocket {
246 public:
FailingUDPClientSocket(SocketDataProvider * data,net::NetLog * net_log)247 FailingUDPClientSocket(SocketDataProvider* data, net::NetLog* net_log)
248 : MockUDPClientSocket(data, net_log) {}
249
250 FailingUDPClientSocket(const FailingUDPClientSocket&) = delete;
251 FailingUDPClientSocket& operator=(const FailingUDPClientSocket&) = delete;
252
253 ~FailingUDPClientSocket() override = default;
Connect(const IPEndPoint & endpoint)254 int Connect(const IPEndPoint& endpoint) override {
255 return ERR_CONNECTION_REFUSED;
256 }
257 };
258
259 // A variant of MockUDPClientSocket which notifies the factory OnConnect.
260 class TestUDPClientSocket : public MockUDPClientSocket {
261 public:
TestUDPClientSocket(TestSocketFactory * factory,SocketDataProvider * data,net::NetLog * net_log)262 TestUDPClientSocket(TestSocketFactory* factory,
263 SocketDataProvider* data,
264 net::NetLog* net_log)
265 : MockUDPClientSocket(data, net_log), factory_(factory) {}
266
267 TestUDPClientSocket(const TestUDPClientSocket&) = delete;
268 TestUDPClientSocket& operator=(const TestUDPClientSocket&) = delete;
269
270 ~TestUDPClientSocket() override = default;
271 int Connect(const IPEndPoint& endpoint) override;
272 int ConnectAsync(const IPEndPoint& address,
273 CompletionOnceCallback callback) override;
274
275 private:
276 raw_ptr<TestSocketFactory> factory_;
277 };
278
279 // Creates TestUDPClientSockets and keeps endpoints reported via OnConnect.
280 class TestSocketFactory : public MockClientSocketFactory {
281 public:
282 TestSocketFactory() = default;
283 ~TestSocketFactory() override = default;
284
CreateDatagramClientSocket(DatagramSocket::BindType bind_type,NetLog * net_log,const NetLogSource & source)285 std::unique_ptr<DatagramClientSocket> CreateDatagramClientSocket(
286 DatagramSocket::BindType bind_type,
287 NetLog* net_log,
288 const NetLogSource& source) override {
289 if (fail_next_socket_) {
290 fail_next_socket_ = false;
291 return std::make_unique<FailingUDPClientSocket>(&empty_data_, net_log);
292 }
293
294 SocketDataProvider* data_provider = mock_data().GetNext();
295 auto socket =
296 std::make_unique<TestUDPClientSocket>(this, data_provider, net_log);
297
298 // Even using DEFAULT_BIND, actual sockets have been measured to very rarely
299 // repeat the same source port multiple times in a row. Need to mimic that
300 // functionality here, so DnsUdpTracker doesn't misdiagnose repeated port
301 // as low entropy.
302 if (diverse_source_ports_)
303 socket->set_source_port(next_source_port_++);
304
305 return socket;
306 }
307
OnConnect(const IPEndPoint & endpoint)308 void OnConnect(const IPEndPoint& endpoint) {
309 remote_endpoints_.emplace_back(endpoint);
310 }
311
312 struct RemoteNameserver {
RemoteNameservernet::__anon8fcd5c460111::TestSocketFactory::RemoteNameserver313 explicit RemoteNameserver(IPEndPoint insecure_nameserver)
314 : insecure_nameserver(insecure_nameserver) {}
RemoteNameservernet::__anon8fcd5c460111::TestSocketFactory::RemoteNameserver315 explicit RemoteNameserver(DnsOverHttpsServerConfig secure_nameserver)
316 : secure_nameserver(secure_nameserver) {}
317
318 absl::optional<IPEndPoint> insecure_nameserver;
319 absl::optional<DnsOverHttpsServerConfig> secure_nameserver;
320 };
321
322 std::vector<RemoteNameserver> remote_endpoints_;
323 bool fail_next_socket_ = false;
324 bool diverse_source_ports_ = true;
325
326 private:
327 StaticSocketDataProvider empty_data_;
328 uint16_t next_source_port_ = 123;
329 };
330
Connect(const IPEndPoint & endpoint)331 int TestUDPClientSocket::Connect(const IPEndPoint& endpoint) {
332 factory_->OnConnect(endpoint);
333 return MockUDPClientSocket::Connect(endpoint);
334 }
335
ConnectAsync(const IPEndPoint & address,CompletionOnceCallback callback)336 int TestUDPClientSocket::ConnectAsync(const IPEndPoint& address,
337 CompletionOnceCallback callback) {
338 factory_->OnConnect(address);
339 return MockUDPClientSocket::ConnectAsync(address, std::move(callback));
340 }
341
342 // Helper class that holds a DnsTransaction and handles OnTransactionComplete.
343 class TransactionHelper {
344 public:
345 // If |expected_answer_count| < 0 then it is the expected net error.
TransactionHelper(int expected_answer_count)346 explicit TransactionHelper(int expected_answer_count)
347 : expected_answer_count_(expected_answer_count) {}
348
349 // Mark that the transaction shall be destroyed immediately upon callback.
set_cancel_in_callback()350 void set_cancel_in_callback() { cancel_in_callback_ = true; }
351
StartTransaction(DnsTransactionFactory * factory,const char * hostname,uint16_t qtype,bool secure,ResolveContext * context)352 void StartTransaction(DnsTransactionFactory* factory,
353 const char* hostname,
354 uint16_t qtype,
355 bool secure,
356 ResolveContext* context) {
357 std::unique_ptr<DnsTransaction> transaction = factory->CreateTransaction(
358 hostname, qtype,
359 NetLogWithSource::Make(net::NetLog::Get(), net::NetLogSourceType::NONE),
360 secure, factory->GetSecureDnsModeForTest(), context,
361 true /* fast_timeout */);
362 transaction->SetRequestPriority(DEFAULT_PRIORITY);
363 EXPECT_EQ(qtype, transaction->GetType());
364 StartTransaction(std::move(transaction));
365 }
366
StartTransaction(std::unique_ptr<DnsTransaction> transaction)367 void StartTransaction(std::unique_ptr<DnsTransaction> transaction) {
368 EXPECT_FALSE(transaction_);
369 transaction_ = std::move(transaction);
370 qtype_ = transaction_->GetType();
371 transaction_->Start(base::BindOnce(
372 &TransactionHelper::OnTransactionComplete, base::Unretained(this)));
373 }
374
Cancel()375 void Cancel() {
376 ASSERT_TRUE(transaction_.get() != nullptr);
377 transaction_.reset(nullptr);
378 }
379
OnTransactionComplete(int rv,const DnsResponse * response)380 void OnTransactionComplete(int rv, const DnsResponse* response) {
381 EXPECT_FALSE(completed_);
382
383 completed_ = true;
384 response_ = response;
385
386 transaction_complete_run_loop_.Quit();
387
388 if (cancel_in_callback_) {
389 Cancel();
390 return;
391 }
392
393 if (response)
394 EXPECT_TRUE(response->IsValid());
395
396 if (expected_answer_count_ >= 0) {
397 ASSERT_THAT(rv, IsOk());
398 ASSERT_TRUE(response != nullptr);
399 EXPECT_EQ(static_cast<unsigned>(expected_answer_count_),
400 response->answer_count());
401 EXPECT_EQ(qtype_, response->GetSingleQType());
402
403 DnsRecordParser parser = response->Parser();
404 DnsResourceRecord record;
405 for (int i = 0; i < expected_answer_count_; ++i) {
406 EXPECT_TRUE(parser.ReadRecord(&record));
407 }
408 } else {
409 EXPECT_EQ(expected_answer_count_, rv);
410 }
411 }
412
has_completed() const413 bool has_completed() const { return completed_; }
response() const414 const DnsResponse* response() const { return response_; }
415
416 // Runs until the completion callback is called. Transaction must have already
417 // been started or this will never complete.
RunUntilComplete()418 void RunUntilComplete() {
419 DCHECK(transaction_);
420 DCHECK(!transaction_complete_run_loop_.running());
421 transaction_complete_run_loop_.Run();
422 DCHECK(has_completed());
423 }
424
425 private:
426 uint16_t qtype_ = 0;
427 std::unique_ptr<DnsTransaction> transaction_;
428 raw_ptr<const DnsResponse, AcrossTasksDanglingUntriaged> response_ = nullptr;
429 int expected_answer_count_;
430 bool cancel_in_callback_ = false;
431 base::RunLoop transaction_complete_run_loop_;
432 bool completed_ = false;
433 };
434
435 // Callback that allows a test to modify HttpResponseinfo
436 // before the response is sent to the requester. This allows
437 // response headers to be changed.
438 using ResponseModifierCallback =
439 base::RepeatingCallback<void(URLRequest* request, HttpResponseInfo* info)>;
440
441 // Callback that allows the test to substitute its own implementation
442 // of URLRequestJob to handle the request.
443 using DohJobMakerCallback = base::RepeatingCallback<std::unique_ptr<
444 URLRequestJob>(URLRequest* request, SocketDataProvider* data_provider)>;
445
446 // Callback to notify that URLRequestJob::Start has been called.
447 using UrlRequestStartedCallback = base::RepeatingCallback<void()>;
448
449 // Subclass of URLRequestJob which takes a SocketDataProvider with data
450 // representing both a DNS over HTTPS query and response.
451 class URLRequestMockDohJob : public URLRequestJob, public AsyncSocket {
452 public:
URLRequestMockDohJob(URLRequest * request,SocketDataProvider * data_provider,ResponseModifierCallback response_modifier=ResponseModifierCallback (),UrlRequestStartedCallback on_start=UrlRequestStartedCallback ())453 URLRequestMockDohJob(
454 URLRequest* request,
455 SocketDataProvider* data_provider,
456 ResponseModifierCallback response_modifier = ResponseModifierCallback(),
457 UrlRequestStartedCallback on_start = UrlRequestStartedCallback())
458 : URLRequestJob(request),
459 data_provider_(data_provider),
460 response_modifier_(response_modifier),
461 on_start_(on_start) {
462 data_provider_->Initialize(this);
463 MatchQueryData(request, data_provider);
464 }
465
466 // Compare the query contained in either the POST body or the body
467 // parameter of the GET query to the write data of the SocketDataProvider.
MatchQueryData(URLRequest * request,SocketDataProvider * data_provider)468 static void MatchQueryData(URLRequest* request,
469 SocketDataProvider* data_provider) {
470 std::string decoded_query;
471 if (request->method() == "GET") {
472 std::string encoded_query;
473 EXPECT_TRUE(GetValueForKeyInQuery(request->url(), "dns", &encoded_query));
474 EXPECT_GT(encoded_query.size(), 0ul);
475
476 EXPECT_TRUE(base::Base64UrlDecode(
477 encoded_query, base::Base64UrlDecodePolicy::IGNORE_PADDING,
478 &decoded_query));
479 } else if (request->method() == "POST") {
480 EXPECT_EQ(IDEMPOTENT, request->GetIdempotency());
481 const UploadDataStream* stream = request->get_upload_for_testing();
482 auto* readers = stream->GetElementReaders();
483 EXPECT_TRUE(readers);
484 EXPECT_FALSE(readers->empty());
485 for (auto& reader : *readers) {
486 const UploadBytesElementReader* byte_reader = reader->AsBytesReader();
487 decoded_query +=
488 std::string(byte_reader->bytes(), byte_reader->length());
489 }
490 }
491
492 std::string query(decoded_query);
493 MockWriteResult result(SYNCHRONOUS, 1);
494 while (result.result > 0 && query.length() > 0) {
495 result = data_provider->OnWrite(query);
496 if (result.result > 0)
497 query = query.substr(result.result);
498 }
499 }
500
GetMockHttpsUrl(const std::string & path)501 static std::string GetMockHttpsUrl(const std::string& path) {
502 return "https://" + (kMockHostname + ("/" + path));
503 }
504
GetMockHttpUrl(const std::string & path)505 static std::string GetMockHttpUrl(const std::string& path) {
506 return "http://" + (kMockHostname + ("/" + path));
507 }
508
509 // URLRequestJob implementation:
Start()510 void Start() override {
511 if (on_start_)
512 on_start_.Run();
513 // Start reading asynchronously so that all error reporting and data
514 // callbacks happen as they would for network requests.
515 base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
516 FROM_HERE, base::BindOnce(&URLRequestMockDohJob::StartAsync,
517 weak_factory_.GetWeakPtr()));
518 }
519
520 URLRequestMockDohJob(const URLRequestMockDohJob&) = delete;
521 URLRequestMockDohJob& operator=(const URLRequestMockDohJob&) = delete;
522
~URLRequestMockDohJob()523 ~URLRequestMockDohJob() override {
524 if (data_provider_)
525 data_provider_->DetachSocket();
526 }
527
ReadRawData(IOBuffer * buf,int buf_size)528 int ReadRawData(IOBuffer* buf, int buf_size) override {
529 if (!data_provider_)
530 return ERR_FAILED;
531 if (leftover_data_len_ > 0) {
532 int rv = DoBufferCopy(leftover_data_, leftover_data_len_, buf, buf_size);
533 return rv;
534 }
535
536 if (data_provider_->AllReadDataConsumed())
537 return 0;
538
539 MockRead read = data_provider_->OnRead();
540
541 if (read.result < ERR_IO_PENDING)
542 return read.result;
543
544 if (read.result == ERR_IO_PENDING) {
545 pending_buf_ = buf;
546 pending_buf_size_ = buf_size;
547 return ERR_IO_PENDING;
548 }
549 return DoBufferCopy(read.data, read.data_len, buf, buf_size);
550 }
551
GetResponseInfo(HttpResponseInfo * info)552 void GetResponseInfo(HttpResponseInfo* info) override {
553 // Send back mock headers.
554 std::string raw_headers;
555 raw_headers.append(
556 "HTTP/1.1 200 OK\n"
557 "Content-type: application/dns-message\n");
558 if (content_length_ > 0) {
559 raw_headers.append(base::StringPrintf("Content-Length: %1d\n",
560 static_cast<int>(content_length_)));
561 }
562 info->headers = base::MakeRefCounted<HttpResponseHeaders>(
563 HttpUtil::AssembleRawHeaders(raw_headers));
564 if (response_modifier_)
565 response_modifier_.Run(request(), info);
566 }
567
568 // AsyncSocket implementation:
OnReadComplete(const MockRead & data)569 void OnReadComplete(const MockRead& data) override {
570 EXPECT_NE(data.result, ERR_IO_PENDING);
571 if (data.result < 0)
572 return ReadRawDataComplete(data.result);
573 ReadRawDataComplete(DoBufferCopy(data.data, data.data_len, pending_buf_,
574 pending_buf_size_));
575 }
OnWriteComplete(int rv)576 void OnWriteComplete(int rv) override {}
OnConnectComplete(const MockConnect & data)577 void OnConnectComplete(const MockConnect& data) override {}
OnDataProviderDestroyed()578 void OnDataProviderDestroyed() override { data_provider_ = nullptr; }
579
580 private:
StartAsync()581 void StartAsync() {
582 if (!request_)
583 return;
584 if (content_length_)
585 set_expected_content_size(content_length_);
586 NotifyHeadersComplete();
587 }
588
DoBufferCopy(const char * data,int data_len,IOBuffer * buf,int buf_size)589 int DoBufferCopy(const char* data,
590 int data_len,
591 IOBuffer* buf,
592 int buf_size) {
593 if (data_len > buf_size) {
594 std::copy(data, data + buf_size, buf->data());
595 leftover_data_ = data + buf_size;
596 leftover_data_len_ = data_len - buf_size;
597 return buf_size;
598 }
599 std::copy(data, data + data_len, buf->data());
600 return data_len;
601 }
602
603 const int content_length_ = 0;
604 const char* leftover_data_;
605 int leftover_data_len_ = 0;
606 raw_ptr<SocketDataProvider> data_provider_;
607 const ResponseModifierCallback response_modifier_;
608 const UrlRequestStartedCallback on_start_;
609 raw_ptr<IOBuffer> pending_buf_;
610 int pending_buf_size_;
611
612 base::WeakPtrFactory<URLRequestMockDohJob> weak_factory_{this};
613 };
614
615 class DnsTransactionTestBase : public testing::Test {
616 public:
617 DnsTransactionTestBase() = default;
618
~DnsTransactionTestBase()619 ~DnsTransactionTestBase() override {
620 // All queued transaction IDs should be used by a transaction calling
621 // GetNextId().
622 CHECK(transaction_ids_.empty());
623 }
624
625 // Generates |nameservers| for DnsConfig.
ConfigureNumServers(size_t num_servers)626 void ConfigureNumServers(size_t num_servers) {
627 CHECK_LE(num_servers, 255u);
628 config_.nameservers.clear();
629 for (size_t i = 0; i < num_servers; ++i) {
630 config_.nameservers.emplace_back(IPAddress(192, 168, 1, i),
631 dns_protocol::kDefaultPort);
632 }
633 }
634
635 // Configures the DnsConfig DNS-over-HTTPS server(s), which either
636 // accept GET or POST requests based on use_post. If a
637 // ResponseModifierCallback is provided it will be called to construct the
638 // HTTPResponse.
ConfigureDohServers(bool use_post,size_t num_doh_servers=1,bool make_available=true)639 void ConfigureDohServers(bool use_post,
640 size_t num_doh_servers = 1,
641 bool make_available = true) {
642 GURL url(URLRequestMockDohJob::GetMockHttpsUrl("doh_test"));
643 URLRequestFilter* filter = URLRequestFilter::GetInstance();
644 filter->AddHostnameInterceptor(url.scheme(), url.host(),
645 std::make_unique<DohJobInterceptor>(this));
646 CHECK_LE(num_doh_servers, 255u);
647 std::vector<string> templates;
648 templates.reserve(num_doh_servers);
649 for (size_t i = 0; i < num_doh_servers; ++i) {
650 templates.push_back(URLRequestMockDohJob::GetMockHttpsUrl(
651 base::StringPrintf("doh_test_%zu", i)) +
652 (use_post ? "" : "{?dns}"));
653 }
654 config_.doh_config =
655 *DnsOverHttpsConfig::FromTemplatesForTesting(std::move(templates));
656 ConfigureFactory();
657
658 if (make_available) {
659 for (size_t server_index = 0; server_index < num_doh_servers;
660 ++server_index) {
661 resolve_context_->RecordServerSuccess(
662 server_index, true /* is_doh_server */, session_.get());
663 }
664 }
665 }
666
667 // Called after fully configuring |config|.
ConfigureFactory()668 void ConfigureFactory() {
669 session_ = base::MakeRefCounted<DnsSession>(
670 config_,
671 base::BindRepeating(&DnsTransactionTestBase::GetNextId,
672 base::Unretained(this)),
673 nullptr /* NetLog */);
674 resolve_context_->InvalidateCachesAndPerSessionData(
675 session_.get(), false /* network_change */);
676 transaction_factory_ = DnsTransactionFactory::CreateFactory(session_.get());
677 }
678
AddSocketData(std::unique_ptr<DnsSocketData> data,bool enqueue_transaction_id=true)679 void AddSocketData(std::unique_ptr<DnsSocketData> data,
680 bool enqueue_transaction_id = true) {
681 CHECK(socket_factory_.get());
682 if (enqueue_transaction_id)
683 transaction_ids_.push_back(data->query_id());
684 socket_factory_->AddSocketDataProvider(data->GetProvider());
685 socket_data_.push_back(std::move(data));
686 }
687
AddQueryAndResponseNoWrite(uint16_t id,const char * dotted_name,uint16_t qtype,IoMode mode,Transport transport,const OptRecordRdata * opt_rdata=nullptr,DnsQuery::PaddingStrategy padding_strategy=DnsQuery::PaddingStrategy::NONE)688 void AddQueryAndResponseNoWrite(uint16_t id,
689 const char* dotted_name,
690 uint16_t qtype,
691 IoMode mode,
692 Transport transport,
693 const OptRecordRdata* opt_rdata = nullptr,
694 DnsQuery::PaddingStrategy padding_strategy =
695 DnsQuery::PaddingStrategy::NONE) {
696 CHECK(socket_factory_.get());
697 auto data = std::make_unique<DnsSocketData>(
698 id, dotted_name, qtype, mode, transport, opt_rdata, padding_strategy);
699 data->ClearWrites();
700 AddSocketData(std::move(data), true);
701 }
702
703 // Add expected query for |dotted_name| and |qtype| with |id| and response
704 // taken verbatim from |data| of |data_length| bytes. The transaction id in
705 // |data| should equal |id|, unless testing mismatched response.
AddQueryAndResponse(uint16_t id,const char * dotted_name,uint16_t qtype,const uint8_t * response_data,size_t response_length,IoMode mode,Transport transport,const OptRecordRdata * opt_rdata=nullptr,DnsQuery::PaddingStrategy padding_strategy=DnsQuery::PaddingStrategy::NONE,bool enqueue_transaction_id=true)706 void AddQueryAndResponse(uint16_t id,
707 const char* dotted_name,
708 uint16_t qtype,
709 const uint8_t* response_data,
710 size_t response_length,
711 IoMode mode,
712 Transport transport,
713 const OptRecordRdata* opt_rdata = nullptr,
714 DnsQuery::PaddingStrategy padding_strategy =
715 DnsQuery::PaddingStrategy::NONE,
716 bool enqueue_transaction_id = true) {
717 CHECK(socket_factory_.get());
718 auto data = std::make_unique<DnsSocketData>(
719 id, dotted_name, qtype, mode, transport, opt_rdata, padding_strategy);
720 data->AddResponseData(response_data, response_length, mode);
721 AddSocketData(std::move(data), enqueue_transaction_id);
722 }
723
AddQueryAndErrorResponse(uint16_t id,const char * dotted_name,uint16_t qtype,int error,IoMode mode,Transport transport,const OptRecordRdata * opt_rdata=nullptr,DnsQuery::PaddingStrategy padding_strategy=DnsQuery::PaddingStrategy::NONE,bool enqueue_transaction_id=true)724 void AddQueryAndErrorResponse(uint16_t id,
725 const char* dotted_name,
726 uint16_t qtype,
727 int error,
728 IoMode mode,
729 Transport transport,
730 const OptRecordRdata* opt_rdata = nullptr,
731 DnsQuery::PaddingStrategy padding_strategy =
732 DnsQuery::PaddingStrategy::NONE,
733 bool enqueue_transaction_id = true) {
734 CHECK(socket_factory_.get());
735 auto data = std::make_unique<DnsSocketData>(
736 id, dotted_name, qtype, mode, transport, opt_rdata, padding_strategy);
737 data->AddReadError(error, mode);
738 AddSocketData(std::move(data), enqueue_transaction_id);
739 }
740
AddAsyncQueryAndResponse(uint16_t id,const char * dotted_name,uint16_t qtype,const uint8_t * data,size_t data_length,const OptRecordRdata * opt_rdata=nullptr)741 void AddAsyncQueryAndResponse(uint16_t id,
742 const char* dotted_name,
743 uint16_t qtype,
744 const uint8_t* data,
745 size_t data_length,
746 const OptRecordRdata* opt_rdata = nullptr) {
747 AddQueryAndResponse(id, dotted_name, qtype, data, data_length, ASYNC,
748 Transport::UDP, opt_rdata);
749 }
750
AddSyncQueryAndResponse(uint16_t id,const char * dotted_name,uint16_t qtype,const uint8_t * data,size_t data_length,const OptRecordRdata * opt_rdata=nullptr)751 void AddSyncQueryAndResponse(uint16_t id,
752 const char* dotted_name,
753 uint16_t qtype,
754 const uint8_t* data,
755 size_t data_length,
756 const OptRecordRdata* opt_rdata = nullptr) {
757 AddQueryAndResponse(id, dotted_name, qtype, data, data_length, SYNCHRONOUS,
758 Transport::UDP, opt_rdata);
759 }
760
761 // Add expected query of |dotted_name| and |qtype| and no response.
AddHangingQuery(const char * dotted_name,uint16_t qtype,DnsQuery::PaddingStrategy padding_strategy=DnsQuery::PaddingStrategy::NONE,uint16_t id=base::RandInt (0,std::numeric_limits<uint16_t>::max ()),bool enqueue_transaction_id=true)762 void AddHangingQuery(
763 const char* dotted_name,
764 uint16_t qtype,
765 DnsQuery::PaddingStrategy padding_strategy =
766 DnsQuery::PaddingStrategy::NONE,
767 uint16_t id = base::RandInt(0, std::numeric_limits<uint16_t>::max()),
768 bool enqueue_transaction_id = true) {
769 auto data = std::make_unique<DnsSocketData>(
770 id, dotted_name, qtype, ASYNC, Transport::UDP, nullptr /* opt_rdata */,
771 padding_strategy);
772 AddSocketData(std::move(data), enqueue_transaction_id);
773 }
774
775 // Add expected query of |dotted_name| and |qtype| and matching response with
776 // no answer and RCODE set to |rcode|. The id will be generated randomly.
AddQueryAndRcode(const char * dotted_name,uint16_t qtype,int rcode,IoMode mode,Transport trans,DnsQuery::PaddingStrategy padding_strategy=DnsQuery::PaddingStrategy::NONE,uint16_t id=base::RandInt (0,std::numeric_limits<uint16_t>::max ()),bool enqueue_transaction_id=true)777 void AddQueryAndRcode(
778 const char* dotted_name,
779 uint16_t qtype,
780 int rcode,
781 IoMode mode,
782 Transport trans,
783 DnsQuery::PaddingStrategy padding_strategy =
784 DnsQuery::PaddingStrategy::NONE,
785 uint16_t id = base::RandInt(0, std::numeric_limits<uint16_t>::max()),
786 bool enqueue_transaction_id = true) {
787 CHECK_NE(dns_protocol::kRcodeNOERROR, rcode);
788 auto data = std::make_unique<DnsSocketData>(id, dotted_name, qtype, mode,
789 trans, nullptr /* opt_rdata */,
790 padding_strategy);
791 data->AddRcode(rcode, mode);
792 AddSocketData(std::move(data), enqueue_transaction_id);
793 }
794
AddAsyncQueryAndRcode(const char * dotted_name,uint16_t qtype,int rcode)795 void AddAsyncQueryAndRcode(const char* dotted_name,
796 uint16_t qtype,
797 int rcode) {
798 AddQueryAndRcode(dotted_name, qtype, rcode, ASYNC, Transport::UDP);
799 }
800
AddSyncQueryAndRcode(const char * dotted_name,uint16_t qtype,int rcode)801 void AddSyncQueryAndRcode(const char* dotted_name,
802 uint16_t qtype,
803 int rcode) {
804 AddQueryAndRcode(dotted_name, qtype, rcode, SYNCHRONOUS, Transport::UDP);
805 }
806
807 // Checks if the sockets were connected in the order matching the indices in
808 // |servers|.
CheckServerOrder(const size_t * servers,size_t num_attempts)809 void CheckServerOrder(const size_t* servers, size_t num_attempts) {
810 ASSERT_EQ(num_attempts, socket_factory_->remote_endpoints_.size());
811 auto num_insecure_nameservers = session_->config().nameservers.size();
812 for (size_t i = 0; i < num_attempts; ++i) {
813 if (servers[i] < num_insecure_nameservers) {
814 // Check insecure server match.
815 EXPECT_EQ(
816 socket_factory_->remote_endpoints_[i].insecure_nameserver.value(),
817 session_->config().nameservers[servers[i]]);
818 } else {
819 // Check secure server match.
820 EXPECT_EQ(
821 socket_factory_->remote_endpoints_[i].secure_nameserver.value(),
822 session_->config()
823 .doh_config.servers()[servers[i] - num_insecure_nameservers]);
824 }
825 }
826 }
827
MaybeInterceptRequest(URLRequest * request)828 std::unique_ptr<URLRequestJob> MaybeInterceptRequest(URLRequest* request) {
829 // If the path indicates a redirect, skip checking the list of
830 // configured servers, because it won't be there and we still want
831 // to handle it.
832 bool server_found = request->url().path() == "/redirect-destination";
833 for (auto server : config_.doh_config.servers()) {
834 if (server_found)
835 break;
836 std::string url_base =
837 GetURLFromTemplateWithoutParameters(server.server_template());
838 if (server.use_post() && request->method() == "POST") {
839 if (url_base == request->url().spec()) {
840 server_found = true;
841 socket_factory_->remote_endpoints_.emplace_back(server);
842 }
843 } else if (!server.use_post() && request->method() == "GET") {
844 std::string prefix = url_base + "?dns=";
845 auto mispair = base::ranges::mismatch(prefix, request->url().spec());
846 if (mispair.first == prefix.end()) {
847 server_found = true;
848 socket_factory_->remote_endpoints_.emplace_back(server);
849 }
850 }
851 }
852 EXPECT_TRUE(server_found);
853
854 EXPECT_TRUE(
855 request->isolation_info().network_isolation_key().IsTransient());
856
857 // All DoH requests for the same ResolveContext should use the same
858 // IsolationInfo, so network objects like sockets can be reused between
859 // requests.
860 if (!expect_multiple_isolation_infos_) {
861 if (!isolation_info_) {
862 isolation_info_ =
863 std::make_unique<IsolationInfo>(request->isolation_info());
864 } else {
865 EXPECT_TRUE(
866 isolation_info_->IsEqualForTesting(request->isolation_info()));
867 }
868 }
869
870 EXPECT_FALSE(request->allow_credentials());
871 EXPECT_EQ(SecureDnsPolicy::kBootstrap, request->secure_dns_policy());
872
873 std::string accept;
874 EXPECT_TRUE(request->extra_request_headers().GetHeader("Accept", &accept));
875 EXPECT_EQ(accept, "application/dns-message");
876
877 std::string language;
878 EXPECT_TRUE(request->extra_request_headers().GetHeader("Accept-Language",
879 &language));
880 EXPECT_EQ(language, "*");
881
882 std::string user_agent;
883 EXPECT_TRUE(
884 request->extra_request_headers().GetHeader("User-Agent", &user_agent));
885 EXPECT_EQ(user_agent, "Chrome");
886
887 SocketDataProvider* provider = socket_factory_->mock_data().GetNext();
888
889 if (doh_job_maker_)
890 return doh_job_maker_.Run(request, provider);
891
892 return std::make_unique<URLRequestMockDohJob>(
893 request, provider, response_modifier_, on_start_);
894 }
895
896 class DohJobInterceptor : public URLRequestInterceptor {
897 public:
DohJobInterceptor(DnsTransactionTestBase * test)898 explicit DohJobInterceptor(DnsTransactionTestBase* test) : test_(test) {}
899
900 DohJobInterceptor(const DohJobInterceptor&) = delete;
901 DohJobInterceptor& operator=(const DohJobInterceptor&) = delete;
902
903 ~DohJobInterceptor() override = default;
904
905 // URLRequestInterceptor implementation:
MaybeInterceptRequest(URLRequest * request) const906 std::unique_ptr<URLRequestJob> MaybeInterceptRequest(
907 URLRequest* request) const override {
908 return test_->MaybeInterceptRequest(request);
909 }
910
911 private:
912 raw_ptr<DnsTransactionTestBase> test_;
913 };
914
SetResponseModifierCallback(ResponseModifierCallback response_modifier)915 void SetResponseModifierCallback(ResponseModifierCallback response_modifier) {
916 response_modifier_ = response_modifier;
917 }
918
SetDohJobMakerCallback(DohJobMakerCallback doh_job_maker)919 void SetDohJobMakerCallback(DohJobMakerCallback doh_job_maker) {
920 doh_job_maker_ = doh_job_maker;
921 }
922
SetUrlRequestStartedCallback(UrlRequestStartedCallback on_start)923 void SetUrlRequestStartedCallback(UrlRequestStartedCallback on_start) {
924 on_start_ = on_start;
925 }
926
SetUp()927 void SetUp() override {
928 // By default set one server,
929 ConfigureNumServers(1);
930 // and no retransmissions,
931 config_.attempts = 1;
932 // and an arbitrary fallback period.
933 config_.fallback_period = kFallbackPeriod;
934 auto context_builder = CreateTestURLRequestContextBuilder();
935 socket_factory_ = std::make_unique<TestSocketFactory>();
936 context_builder->set_client_socket_factory_for_testing(
937 socket_factory_.get());
938 request_context_ = context_builder->Build();
939 resolve_context_ = std::make_unique<ResolveContext>(
940 request_context_.get(), false /* enable_caching */);
941
942 ConfigureFactory();
943 }
944
TearDown()945 void TearDown() override {
946 // Check that all socket data was at least written to.
947 for (size_t i = 0; i < socket_data_.size(); ++i) {
948 EXPECT_TRUE(socket_data_[i]->GetProvider()->AllWriteDataConsumed()) << i;
949 }
950
951 URLRequestFilter* filter = URLRequestFilter::GetInstance();
952 filter->ClearHandlers();
953 }
954
set_expect_multiple_isolation_infos(bool expect_multiple_isolation_infos)955 void set_expect_multiple_isolation_infos(
956 bool expect_multiple_isolation_infos) {
957 expect_multiple_isolation_infos_ = expect_multiple_isolation_infos;
958 }
959
960 protected:
GetNextId(int min,int max)961 int GetNextId(int min, int max) {
962 EXPECT_FALSE(transaction_ids_.empty());
963 int id = transaction_ids_.front();
964 transaction_ids_.pop_front();
965 EXPECT_GE(id, min);
966 EXPECT_LE(id, max);
967 return id;
968 }
969
970 DnsConfig config_;
971
972 std::vector<std::unique_ptr<DnsSocketData>> socket_data_;
973
974 base::circular_deque<int> transaction_ids_;
975 std::unique_ptr<TestSocketFactory> socket_factory_;
976 std::unique_ptr<URLRequestContext> request_context_;
977 std::unique_ptr<ResolveContext> resolve_context_;
978 scoped_refptr<DnsSession> session_;
979 std::unique_ptr<DnsTransactionFactory> transaction_factory_;
980 ResponseModifierCallback response_modifier_;
981 UrlRequestStartedCallback on_start_;
982 DohJobMakerCallback doh_job_maker_;
983
984 // Whether multiple IsolationInfos should be expected (due to there being
985 // multiple RequestContexts in use).
986 bool expect_multiple_isolation_infos_ = false;
987
988 // IsolationInfo used by DoH requests. Populated on first DoH request, and
989 // compared to IsolationInfo used by all subsequent requests, unless
990 // |expect_multiple_isolation_infos_| is true.
991 std::unique_ptr<IsolationInfo> isolation_info_;
992 };
993
994 class DnsTransactionTest : public DnsTransactionTestBase,
995 public WithTaskEnvironment {
996 public:
997 DnsTransactionTest() = default;
998 ~DnsTransactionTest() override = default;
999 };
1000
1001 class DnsTransactionTestWithMockTime : public DnsTransactionTestBase,
1002 public WithTaskEnvironment {
1003 protected:
DnsTransactionTestWithMockTime()1004 DnsTransactionTestWithMockTime()
1005 : WithTaskEnvironment(
1006 base::test::TaskEnvironment::TimeSource::MOCK_TIME) {}
1007 ~DnsTransactionTestWithMockTime() override = default;
1008 };
1009
TEST_F(DnsTransactionTest,Lookup)1010 TEST_F(DnsTransactionTest, Lookup) {
1011 AddAsyncQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype,
1012 kT0ResponseDatagram, std::size(kT0ResponseDatagram));
1013
1014 TransactionHelper helper0(kT0RecordCount);
1015 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
1016 false /* secure */, resolve_context_.get());
1017 helper0.RunUntilComplete();
1018 }
1019
TEST_F(DnsTransactionTest,LookupWithLog)1020 TEST_F(DnsTransactionTest, LookupWithLog) {
1021 AddAsyncQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype,
1022 kT0ResponseDatagram, std::size(kT0ResponseDatagram));
1023
1024 TransactionHelper helper0(kT0RecordCount);
1025 NetLogCountingObserver observer;
1026 NetLog::Get()->AddObserver(&observer, NetLogCaptureMode::kEverything);
1027 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
1028 false /* secure */, resolve_context_.get());
1029 helper0.RunUntilComplete();
1030 EXPECT_EQ(observer.count(), 7);
1031 EXPECT_EQ(observer.dict_count(), 5);
1032 }
1033
TEST_F(DnsTransactionTest,LookupWithEDNSOption)1034 TEST_F(DnsTransactionTest, LookupWithEDNSOption) {
1035 OptRecordRdata expected_opt_rdata;
1036
1037 transaction_factory_->AddEDNSOption(
1038 OptRecordRdata::UnknownOpt::CreateForTesting(123, "\xbe\xef"));
1039 expected_opt_rdata.AddOpt(
1040 OptRecordRdata::UnknownOpt::CreateForTesting(123, "\xbe\xef"));
1041
1042 AddAsyncQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype,
1043 kT0ResponseDatagram, std::size(kT0ResponseDatagram),
1044 &expected_opt_rdata);
1045
1046 TransactionHelper helper0(kT0RecordCount);
1047 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
1048 false /* secure */, resolve_context_.get());
1049 helper0.RunUntilComplete();
1050 }
1051
TEST_F(DnsTransactionTest,LookupWithMultipleEDNSOptions)1052 TEST_F(DnsTransactionTest, LookupWithMultipleEDNSOptions) {
1053 OptRecordRdata expected_opt_rdata;
1054
1055 std::vector<std::pair<uint16_t, std::string>> params = {
1056 // Two options with the same code, to check that both are included.
1057 std::pair<uint16_t, std::string>(1, "\xde\xad"),
1058 std::pair<uint16_t, std::string>(1, "\xbe\xef"),
1059 // Try a different code and different length of data.
1060 std::pair<uint16_t, std::string>(2, "\xff")};
1061
1062 for (auto& param : params) {
1063 transaction_factory_->AddEDNSOption(
1064 OptRecordRdata::UnknownOpt::CreateForTesting(param.first,
1065 param.second));
1066 expected_opt_rdata.AddOpt(OptRecordRdata::UnknownOpt::CreateForTesting(
1067 param.first, param.second));
1068 }
1069
1070 AddAsyncQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype,
1071 kT0ResponseDatagram, std::size(kT0ResponseDatagram),
1072 &expected_opt_rdata);
1073
1074 TransactionHelper helper0(kT0RecordCount);
1075 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
1076 false /* secure */, resolve_context_.get());
1077 helper0.RunUntilComplete();
1078 }
1079
1080 // Concurrent lookup tests assume that DnsTransaction::Start immediately
1081 // consumes a socket from ClientSocketFactory.
TEST_F(DnsTransactionTest,ConcurrentLookup)1082 TEST_F(DnsTransactionTest, ConcurrentLookup) {
1083 AddAsyncQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype,
1084 kT0ResponseDatagram, std::size(kT0ResponseDatagram));
1085 AddAsyncQueryAndResponse(1 /* id */, kT1HostName, kT1Qtype,
1086 kT1ResponseDatagram, std::size(kT1ResponseDatagram));
1087
1088 TransactionHelper helper0(kT0RecordCount);
1089 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
1090 false /* secure */, resolve_context_.get());
1091 TransactionHelper helper1(kT1RecordCount);
1092 helper1.StartTransaction(transaction_factory_.get(), kT1HostName, kT1Qtype,
1093 false /* secure */, resolve_context_.get());
1094
1095 base::RunLoop().RunUntilIdle();
1096
1097 EXPECT_TRUE(helper0.has_completed());
1098 EXPECT_TRUE(helper1.has_completed());
1099 }
1100
TEST_F(DnsTransactionTest,CancelLookup)1101 TEST_F(DnsTransactionTest, CancelLookup) {
1102 AddQueryAndResponseNoWrite(0 /* id */, kT0HostName, kT0Qtype, ASYNC,
1103 Transport::UDP, nullptr);
1104
1105 AddAsyncQueryAndResponse(1 /* id */, kT1HostName, kT1Qtype,
1106 kT1ResponseDatagram, std::size(kT1ResponseDatagram));
1107
1108 TransactionHelper helper0(kT0RecordCount);
1109 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
1110 false /* secure */, resolve_context_.get());
1111 TransactionHelper helper1(kT1RecordCount);
1112 helper1.StartTransaction(transaction_factory_.get(), kT1HostName, kT1Qtype,
1113 false /* secure */, resolve_context_.get());
1114
1115 helper0.Cancel();
1116
1117 base::RunLoop().RunUntilIdle();
1118
1119 EXPECT_FALSE(helper0.has_completed());
1120 EXPECT_TRUE(helper1.has_completed());
1121 }
1122
TEST_F(DnsTransactionTest,DestroyFactory)1123 TEST_F(DnsTransactionTest, DestroyFactory) {
1124 AddAsyncQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype,
1125 kT0ResponseDatagram, std::size(kT0ResponseDatagram));
1126
1127 TransactionHelper helper0(kT0RecordCount);
1128 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
1129 false /* secure */, resolve_context_.get());
1130
1131 // Destroying the client does not affect running requests.
1132 transaction_factory_.reset(nullptr);
1133
1134 helper0.RunUntilComplete();
1135 }
1136
TEST_F(DnsTransactionTest,CancelFromCallback)1137 TEST_F(DnsTransactionTest, CancelFromCallback) {
1138 AddAsyncQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype,
1139 kT0ResponseDatagram, std::size(kT0ResponseDatagram));
1140
1141 TransactionHelper helper0(kT0RecordCount);
1142 helper0.set_cancel_in_callback();
1143
1144 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
1145 false /* secure */, resolve_context_.get());
1146 helper0.RunUntilComplete();
1147 }
1148
TEST_F(DnsTransactionTest,MismatchedResponseSync)1149 TEST_F(DnsTransactionTest, MismatchedResponseSync) {
1150 config_.attempts = 2;
1151 ConfigureFactory();
1152
1153 // First attempt receives mismatched response synchronously.
1154 auto data = std::make_unique<DnsSocketData>(0 /* id */, kT0HostName, kT0Qtype,
1155 SYNCHRONOUS, Transport::UDP);
1156 data->AddResponseData(kT1ResponseDatagram, std::size(kT1ResponseDatagram),
1157 SYNCHRONOUS);
1158 AddSocketData(std::move(data));
1159
1160 // Second attempt receives valid response synchronously.
1161 auto data1 = std::make_unique<DnsSocketData>(
1162 0 /* id */, kT0HostName, kT0Qtype, SYNCHRONOUS, Transport::UDP);
1163 data1->AddResponseData(kT0ResponseDatagram, std::size(kT0ResponseDatagram),
1164 SYNCHRONOUS);
1165 AddSocketData(std::move(data1));
1166
1167 TransactionHelper helper0(kT0RecordCount);
1168 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
1169 false /* secure */, resolve_context_.get());
1170 helper0.RunUntilComplete();
1171 }
1172
TEST_F(DnsTransactionTest,MismatchedResponseAsync)1173 TEST_F(DnsTransactionTest, MismatchedResponseAsync) {
1174 config_.attempts = 2;
1175 ConfigureFactory();
1176
1177 // First attempt receives mismatched response asynchronously.
1178 auto data0 = std::make_unique<DnsSocketData>(0 /* id */, kT0HostName,
1179 kT0Qtype, ASYNC, Transport::UDP);
1180 data0->AddResponseData(kT1ResponseDatagram, std::size(kT1ResponseDatagram),
1181 ASYNC);
1182 AddSocketData(std::move(data0));
1183
1184 // Second attempt receives valid response asynchronously.
1185 auto data1 = std::make_unique<DnsSocketData>(0 /* id */, kT0HostName,
1186 kT0Qtype, ASYNC, Transport::UDP);
1187 data1->AddResponseData(kT0ResponseDatagram, std::size(kT0ResponseDatagram),
1188 ASYNC);
1189 AddSocketData(std::move(data1));
1190
1191 TransactionHelper helper0(kT0RecordCount);
1192 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
1193 false /* secure */, resolve_context_.get());
1194 helper0.RunUntilComplete();
1195 }
1196
1197 // Test that responses are not accepted when only the response ID mismatches.
1198 // Tests against incorrect transaction ID validation, which is anti-pattern #1
1199 // from the "NAME:WRECK" report:
1200 // https://www.forescout.com/company/resources/namewreck-breaking-and-fixing-dns-implementations/
TEST_F(DnsTransactionTest,MismatchedResponseFail)1201 TEST_F(DnsTransactionTest, MismatchedResponseFail) {
1202 ConfigureFactory();
1203
1204 // Attempt receives mismatched response and fails because only one attempt is
1205 // allowed.
1206 AddAsyncQueryAndResponse(1 /* id */, kT0HostName, kT0Qtype,
1207 kT0ResponseDatagram, std::size(kT0ResponseDatagram));
1208
1209 TransactionHelper helper0(ERR_DNS_MALFORMED_RESPONSE);
1210 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
1211 false /* secure */, resolve_context_.get());
1212 helper0.RunUntilComplete();
1213 }
1214
TEST_F(DnsTransactionTest,MismatchedResponseNxdomain)1215 TEST_F(DnsTransactionTest, MismatchedResponseNxdomain) {
1216 config_.attempts = 2;
1217 ConfigureFactory();
1218
1219 // First attempt receives mismatched response followed by valid NXDOMAIN
1220 // response.
1221 // Second attempt receives valid NXDOMAIN response.
1222 auto data = std::make_unique<DnsSocketData>(0 /* id */, kT0HostName, kT0Qtype,
1223 SYNCHRONOUS, Transport::UDP);
1224 data->AddResponseData(kT1ResponseDatagram, std::size(kT1ResponseDatagram),
1225 SYNCHRONOUS);
1226 data->AddRcode(dns_protocol::kRcodeNXDOMAIN, ASYNC);
1227 AddSocketData(std::move(data));
1228 AddSyncQueryAndRcode(kT0HostName, kT0Qtype, dns_protocol::kRcodeNXDOMAIN);
1229
1230 TransactionHelper helper0(ERR_NAME_NOT_RESOLVED);
1231 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
1232 false /* secure */, resolve_context_.get());
1233 helper0.RunUntilComplete();
1234 }
1235
1236 // This is a regression test for https://crbug.com/1410442.
TEST_F(DnsTransactionTest,ZeroSizeResponseAsync)1237 TEST_F(DnsTransactionTest, ZeroSizeResponseAsync) {
1238 config_.attempts = 2;
1239 ConfigureFactory();
1240
1241 // First attempt receives zero size response asynchronously.
1242 auto data0 = std::make_unique<DnsSocketData>(/*id=*/0, kT0HostName, kT0Qtype,
1243 ASYNC, Transport::UDP);
1244 data0->AddReadError(0, ASYNC);
1245 AddSocketData(std::move(data0));
1246
1247 // Second attempt receives valid response asynchronously.
1248 auto data1 = std::make_unique<DnsSocketData>(/*id=*/0, kT0HostName, kT0Qtype,
1249 ASYNC, Transport::UDP);
1250 data1->AddResponseData(kT0ResponseDatagram, std::size(kT0ResponseDatagram),
1251 ASYNC);
1252 AddSocketData(std::move(data1));
1253
1254 TransactionHelper helper0(kT0RecordCount);
1255 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
1256 /*secure=*/false, resolve_context_.get());
1257 helper0.RunUntilComplete();
1258 }
1259
TEST_F(DnsTransactionTest,ServerFail)1260 TEST_F(DnsTransactionTest, ServerFail) {
1261 AddAsyncQueryAndRcode(kT0HostName, kT0Qtype, dns_protocol::kRcodeSERVFAIL);
1262
1263 TransactionHelper helper0(ERR_DNS_SERVER_FAILED);
1264 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
1265 false /* secure */, resolve_context_.get());
1266 helper0.RunUntilComplete();
1267
1268 ASSERT_NE(helper0.response(), nullptr);
1269 EXPECT_EQ(helper0.response()->rcode(), dns_protocol::kRcodeSERVFAIL);
1270 }
1271
TEST_F(DnsTransactionTest,NoDomain)1272 TEST_F(DnsTransactionTest, NoDomain) {
1273 AddAsyncQueryAndRcode(kT0HostName, kT0Qtype, dns_protocol::kRcodeNXDOMAIN);
1274
1275 TransactionHelper helper0(ERR_NAME_NOT_RESOLVED);
1276 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
1277 false /* secure */, resolve_context_.get());
1278 helper0.RunUntilComplete();
1279 }
1280
TEST_F(DnsTransactionTestWithMockTime,Timeout_FastTimeout)1281 TEST_F(DnsTransactionTestWithMockTime, Timeout_FastTimeout) {
1282 config_.attempts = 3;
1283 ConfigureFactory();
1284
1285 AddHangingQuery(kT0HostName, kT0Qtype);
1286 AddHangingQuery(kT0HostName, kT0Qtype);
1287 AddHangingQuery(kT0HostName, kT0Qtype);
1288
1289 TransactionHelper helper0(ERR_DNS_TIMED_OUT);
1290 std::unique_ptr<DnsTransaction> transaction =
1291 transaction_factory_->CreateTransaction(
1292 kT0HostName, kT0Qtype, NetLogWithSource(), false /* secure */,
1293 SecureDnsMode::kOff, resolve_context_.get(), true /* fast_timeout */);
1294
1295 helper0.StartTransaction(std::move(transaction));
1296
1297 // Finish when the third attempt expires its fallback period.
1298 base::RunLoop().RunUntilIdle();
1299 EXPECT_FALSE(helper0.has_completed());
1300 FastForwardBy(
1301 resolve_context_->NextClassicFallbackPeriod(0, 0, session_.get()));
1302 EXPECT_FALSE(helper0.has_completed());
1303 FastForwardBy(
1304 resolve_context_->NextClassicFallbackPeriod(0, 1, session_.get()));
1305 EXPECT_FALSE(helper0.has_completed());
1306 FastForwardBy(
1307 resolve_context_->NextClassicFallbackPeriod(0, 2, session_.get()));
1308 EXPECT_TRUE(helper0.has_completed());
1309 }
1310
TEST_F(DnsTransactionTestWithMockTime,ServerFallbackAndRotate)1311 TEST_F(DnsTransactionTestWithMockTime, ServerFallbackAndRotate) {
1312 // Test that we fallback on both server failure and fallback period
1313 // expiration.
1314 config_.attempts = 2;
1315 // The next request should start from the next server.
1316 config_.rotate = true;
1317 ConfigureNumServers(3);
1318 ConfigureFactory();
1319
1320 // Responses for first request.
1321 AddHangingQuery(kT0HostName, kT0Qtype);
1322 AddAsyncQueryAndRcode(kT0HostName, kT0Qtype, dns_protocol::kRcodeSERVFAIL);
1323 AddHangingQuery(kT0HostName, kT0Qtype);
1324 AddAsyncQueryAndRcode(kT0HostName, kT0Qtype, dns_protocol::kRcodeSERVFAIL);
1325 AddAsyncQueryAndRcode(kT0HostName, kT0Qtype, dns_protocol::kRcodeNXDOMAIN);
1326 // Responses for second request.
1327 AddAsyncQueryAndRcode(kT1HostName, kT1Qtype, dns_protocol::kRcodeSERVFAIL);
1328 AddAsyncQueryAndRcode(kT1HostName, kT1Qtype, dns_protocol::kRcodeSERVFAIL);
1329 AddAsyncQueryAndRcode(kT1HostName, kT1Qtype, dns_protocol::kRcodeNXDOMAIN);
1330
1331 TransactionHelper helper0(ERR_NAME_NOT_RESOLVED);
1332 TransactionHelper helper1(ERR_NAME_NOT_RESOLVED);
1333
1334 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
1335 false /* secure */, resolve_context_.get());
1336 base::RunLoop().RunUntilIdle();
1337 EXPECT_FALSE(helper0.has_completed());
1338 FastForwardUntilNoTasksRemain();
1339 EXPECT_TRUE(helper0.has_completed());
1340
1341 helper1.StartTransaction(transaction_factory_.get(), kT1HostName, kT1Qtype,
1342 false /* secure */, resolve_context_.get());
1343 helper1.RunUntilComplete();
1344
1345 size_t kOrder[] = {
1346 // The first transaction.
1347 0,
1348 1,
1349 2,
1350 0,
1351 1,
1352 // The second transaction starts from the next server, and 0 is skipped
1353 // because it already has 2 consecutive failures.
1354 1,
1355 2,
1356 1,
1357 };
1358 CheckServerOrder(kOrder, std::size(kOrder));
1359 }
1360
TEST_F(DnsTransactionTest,SuffixSearchAboveNdots)1361 TEST_F(DnsTransactionTest, SuffixSearchAboveNdots) {
1362 config_.ndots = 2;
1363 config_.search.push_back("a");
1364 config_.search.push_back("b");
1365 config_.search.push_back("c");
1366 config_.rotate = true;
1367 ConfigureNumServers(2);
1368 ConfigureFactory();
1369
1370 AddAsyncQueryAndRcode("x.y.z", dns_protocol::kTypeA,
1371 dns_protocol::kRcodeNXDOMAIN);
1372 AddAsyncQueryAndRcode("x.y.z.a", dns_protocol::kTypeA,
1373 dns_protocol::kRcodeNXDOMAIN);
1374 AddAsyncQueryAndRcode("x.y.z.b", dns_protocol::kTypeA,
1375 dns_protocol::kRcodeNXDOMAIN);
1376 AddAsyncQueryAndRcode("x.y.z.c", dns_protocol::kTypeA,
1377 dns_protocol::kRcodeNXDOMAIN);
1378
1379 TransactionHelper helper0(ERR_NAME_NOT_RESOLVED);
1380
1381 helper0.StartTransaction(transaction_factory_.get(), "x.y.z",
1382 dns_protocol::kTypeA, false /* secure */,
1383 resolve_context_.get());
1384 helper0.RunUntilComplete();
1385
1386 // Also check if suffix search causes server rotation.
1387 size_t kOrder0[] = {0, 1, 0, 1};
1388 CheckServerOrder(kOrder0, std::size(kOrder0));
1389 }
1390
TEST_F(DnsTransactionTest,SuffixSearchBelowNdots)1391 TEST_F(DnsTransactionTest, SuffixSearchBelowNdots) {
1392 config_.ndots = 2;
1393 config_.search.push_back("a");
1394 config_.search.push_back("b");
1395 config_.search.push_back("c");
1396 ConfigureFactory();
1397
1398 // Responses for first transaction.
1399 AddAsyncQueryAndRcode("x.y.a", dns_protocol::kTypeA,
1400 dns_protocol::kRcodeNXDOMAIN);
1401 AddAsyncQueryAndRcode("x.y.b", dns_protocol::kTypeA,
1402 dns_protocol::kRcodeNXDOMAIN);
1403 AddAsyncQueryAndRcode("x.y.c", dns_protocol::kTypeA,
1404 dns_protocol::kRcodeNXDOMAIN);
1405 AddAsyncQueryAndRcode("x.y", dns_protocol::kTypeA,
1406 dns_protocol::kRcodeNXDOMAIN);
1407 // Responses for second transaction.
1408 AddAsyncQueryAndRcode("x.a", dns_protocol::kTypeA,
1409 dns_protocol::kRcodeNXDOMAIN);
1410 AddAsyncQueryAndRcode("x.b", dns_protocol::kTypeA,
1411 dns_protocol::kRcodeNXDOMAIN);
1412 AddAsyncQueryAndRcode("x.c", dns_protocol::kTypeA,
1413 dns_protocol::kRcodeNXDOMAIN);
1414 // Responses for third transaction.
1415 AddAsyncQueryAndRcode("x", dns_protocol::kTypeAAAA,
1416 dns_protocol::kRcodeNXDOMAIN);
1417
1418 TransactionHelper helper0(ERR_NAME_NOT_RESOLVED);
1419 helper0.StartTransaction(transaction_factory_.get(), "x.y",
1420 dns_protocol::kTypeA, false /* secure */,
1421 resolve_context_.get());
1422 helper0.RunUntilComplete();
1423
1424 // A single-label name.
1425 TransactionHelper helper1(ERR_NAME_NOT_RESOLVED);
1426 helper1.StartTransaction(transaction_factory_.get(), "x",
1427 dns_protocol::kTypeA, false /* secure */,
1428 resolve_context_.get());
1429 helper1.RunUntilComplete();
1430
1431 // A fully-qualified name.
1432 TransactionHelper helper2(ERR_NAME_NOT_RESOLVED);
1433 helper2.StartTransaction(transaction_factory_.get(), "x.",
1434 dns_protocol::kTypeAAAA, false /* secure */,
1435 resolve_context_.get());
1436 helper2.RunUntilComplete();
1437 }
1438
TEST_F(DnsTransactionTest,EmptySuffixSearch)1439 TEST_F(DnsTransactionTest, EmptySuffixSearch) {
1440 // Responses for first transaction.
1441 AddAsyncQueryAndRcode("x", dns_protocol::kTypeA,
1442 dns_protocol::kRcodeNXDOMAIN);
1443
1444 // A fully-qualified name.
1445 TransactionHelper helper0(ERR_NAME_NOT_RESOLVED);
1446 helper0.StartTransaction(transaction_factory_.get(), "x.",
1447 dns_protocol::kTypeA, false /* secure */,
1448 resolve_context_.get());
1449 helper0.RunUntilComplete();
1450
1451 // A single label name is not even attempted.
1452 TransactionHelper helper1(ERR_DNS_SEARCH_EMPTY);
1453 helper1.StartTransaction(transaction_factory_.get(), "singlelabel",
1454 dns_protocol::kTypeA, false /* secure */,
1455 resolve_context_.get());
1456 helper1.RunUntilComplete();
1457 }
1458
TEST_F(DnsTransactionTest,DontAppendToMultiLabelName)1459 TEST_F(DnsTransactionTest, DontAppendToMultiLabelName) {
1460 config_.search.push_back("a");
1461 config_.search.push_back("b");
1462 config_.search.push_back("c");
1463 config_.append_to_multi_label_name = false;
1464 ConfigureFactory();
1465
1466 // Responses for first transaction.
1467 AddAsyncQueryAndRcode("x.y.z", dns_protocol::kTypeA,
1468 dns_protocol::kRcodeNXDOMAIN);
1469 // Responses for second transaction.
1470 AddAsyncQueryAndRcode("x.y", dns_protocol::kTypeA,
1471 dns_protocol::kRcodeNXDOMAIN);
1472 // Responses for third transaction.
1473 AddAsyncQueryAndRcode("x.a", dns_protocol::kTypeA,
1474 dns_protocol::kRcodeNXDOMAIN);
1475 AddAsyncQueryAndRcode("x.b", dns_protocol::kTypeA,
1476 dns_protocol::kRcodeNXDOMAIN);
1477 AddAsyncQueryAndRcode("x.c", dns_protocol::kTypeA,
1478 dns_protocol::kRcodeNXDOMAIN);
1479
1480 TransactionHelper helper0(ERR_NAME_NOT_RESOLVED);
1481 helper0.StartTransaction(transaction_factory_.get(), "x.y.z",
1482 dns_protocol::kTypeA, false /* secure */,
1483 resolve_context_.get());
1484 helper0.RunUntilComplete();
1485
1486 TransactionHelper helper1(ERR_NAME_NOT_RESOLVED);
1487 helper1.StartTransaction(transaction_factory_.get(), "x.y",
1488 dns_protocol::kTypeA, false /* secure */,
1489 resolve_context_.get());
1490 helper1.RunUntilComplete();
1491
1492 TransactionHelper helper2(ERR_NAME_NOT_RESOLVED);
1493 helper2.StartTransaction(transaction_factory_.get(), "x",
1494 dns_protocol::kTypeA, false /* secure */,
1495 resolve_context_.get());
1496 helper2.RunUntilComplete();
1497 }
1498
1499 const uint8_t kResponseNoData[] = {
1500 0x00, 0x00, 0x81, 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
1501 // Question
1502 0x01, 'x', 0x01, 'y', 0x01, 'z', 0x01, 'b', 0x00, 0x00, 0x01, 0x00, 0x01,
1503 // Authority section, SOA record, TTL 0x3E6
1504 0x01, 'z', 0x00, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x03, 0xE6,
1505 // Minimal RDATA, 18 bytes
1506 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1507 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1508 };
1509
TEST_F(DnsTransactionTest,SuffixSearchStop)1510 TEST_F(DnsTransactionTest, SuffixSearchStop) {
1511 config_.ndots = 2;
1512 config_.search.push_back("a");
1513 config_.search.push_back("b");
1514 config_.search.push_back("c");
1515 ConfigureFactory();
1516
1517 AddAsyncQueryAndRcode("x.y.z", dns_protocol::kTypeA,
1518 dns_protocol::kRcodeNXDOMAIN);
1519 AddAsyncQueryAndRcode("x.y.z.a", dns_protocol::kTypeA,
1520 dns_protocol::kRcodeNXDOMAIN);
1521 AddAsyncQueryAndResponse(0 /* id */, "x.y.z.b", dns_protocol::kTypeA,
1522 kResponseNoData, std::size(kResponseNoData));
1523
1524 TransactionHelper helper0(0 /* answers */);
1525
1526 helper0.StartTransaction(transaction_factory_.get(), "x.y.z",
1527 dns_protocol::kTypeA, false /* secure */,
1528 resolve_context_.get());
1529 helper0.RunUntilComplete();
1530 }
1531
TEST_F(DnsTransactionTest,SyncFirstQuery)1532 TEST_F(DnsTransactionTest, SyncFirstQuery) {
1533 config_.search.push_back("lab.ccs.neu.edu");
1534 config_.search.push_back("ccs.neu.edu");
1535 ConfigureFactory();
1536
1537 AddSyncQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype,
1538 kT0ResponseDatagram, std::size(kT0ResponseDatagram));
1539
1540 TransactionHelper helper0(kT0RecordCount);
1541 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
1542 false /* secure */, resolve_context_.get());
1543 helper0.RunUntilComplete();
1544 }
1545
TEST_F(DnsTransactionTest,SyncFirstQueryWithSearch)1546 TEST_F(DnsTransactionTest, SyncFirstQueryWithSearch) {
1547 config_.search.push_back("lab.ccs.neu.edu");
1548 config_.search.push_back("ccs.neu.edu");
1549 ConfigureFactory();
1550
1551 AddSyncQueryAndRcode("www.lab.ccs.neu.edu", kT2Qtype,
1552 dns_protocol::kRcodeNXDOMAIN);
1553 // "www.ccs.neu.edu"
1554 AddAsyncQueryAndResponse(2 /* id */, kT2HostName, kT2Qtype,
1555 kT2ResponseDatagram, std::size(kT2ResponseDatagram));
1556
1557 TransactionHelper helper0(kT2RecordCount);
1558 helper0.StartTransaction(transaction_factory_.get(), "www", kT2Qtype,
1559 false /* secure */, resolve_context_.get());
1560 helper0.RunUntilComplete();
1561 }
1562
TEST_F(DnsTransactionTest,SyncSearchQuery)1563 TEST_F(DnsTransactionTest, SyncSearchQuery) {
1564 config_.search.push_back("lab.ccs.neu.edu");
1565 config_.search.push_back("ccs.neu.edu");
1566 ConfigureFactory();
1567
1568 AddAsyncQueryAndRcode("www.lab.ccs.neu.edu", dns_protocol::kTypeA,
1569 dns_protocol::kRcodeNXDOMAIN);
1570 AddSyncQueryAndResponse(2 /* id */, kT2HostName, kT2Qtype,
1571 kT2ResponseDatagram, std::size(kT2ResponseDatagram));
1572
1573 TransactionHelper helper0(kT2RecordCount);
1574 helper0.StartTransaction(transaction_factory_.get(), "www", kT2Qtype,
1575 false /* secure */, resolve_context_.get());
1576 helper0.RunUntilComplete();
1577 }
1578
TEST_F(DnsTransactionTest,ConnectFailure)1579 TEST_F(DnsTransactionTest, ConnectFailure) {
1580 // Prep socket factory for a single socket with connection failure.
1581 MockConnect connect_data;
1582 connect_data.result = ERR_FAILED;
1583 StaticSocketDataProvider data_provider;
1584 data_provider.set_connect_data(connect_data);
1585 socket_factory_->AddSocketDataProvider(&data_provider);
1586
1587 transaction_ids_.push_back(0); // Needed to make a DnsUDPAttempt.
1588 TransactionHelper helper0(ERR_CONNECTION_REFUSED);
1589
1590 helper0.StartTransaction(transaction_factory_.get(), "www.chromium.org",
1591 dns_protocol::kTypeA, false /* secure */,
1592 resolve_context_.get());
1593 helper0.RunUntilComplete();
1594
1595 EXPECT_FALSE(helper0.response());
1596 EXPECT_FALSE(session_->udp_tracker()->low_entropy());
1597 }
1598
TEST_F(DnsTransactionTest,ConnectFailure_SocketLimitReached)1599 TEST_F(DnsTransactionTest, ConnectFailure_SocketLimitReached) {
1600 // Prep socket factory for a single socket with connection failure.
1601 MockConnect connect_data;
1602 connect_data.result = ERR_INSUFFICIENT_RESOURCES;
1603 StaticSocketDataProvider data_provider;
1604 data_provider.set_connect_data(connect_data);
1605 socket_factory_->AddSocketDataProvider(&data_provider);
1606
1607 transaction_ids_.push_back(0); // Needed to make a DnsUDPAttempt.
1608 TransactionHelper helper0(ERR_CONNECTION_REFUSED);
1609
1610 helper0.StartTransaction(transaction_factory_.get(), "www.chromium.org",
1611 dns_protocol::kTypeA, false /* secure */,
1612 resolve_context_.get());
1613 helper0.RunUntilComplete();
1614
1615 EXPECT_FALSE(helper0.response());
1616 EXPECT_TRUE(session_->udp_tracker()->low_entropy());
1617 }
1618
TEST_F(DnsTransactionTest,ConnectFailureFollowedBySuccess)1619 TEST_F(DnsTransactionTest, ConnectFailureFollowedBySuccess) {
1620 // Retry after server failure.
1621 config_.attempts = 2;
1622 ConfigureFactory();
1623 // First server connection attempt fails.
1624 transaction_ids_.push_back(0); // Needed to make a DnsUDPAttempt.
1625 socket_factory_->fail_next_socket_ = true;
1626 // Second DNS query succeeds.
1627 AddAsyncQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype,
1628 kT0ResponseDatagram, std::size(kT0ResponseDatagram));
1629 TransactionHelper helper0(kT0RecordCount);
1630 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
1631 false /* secure */, resolve_context_.get());
1632 helper0.RunUntilComplete();
1633 }
1634
TEST_F(DnsTransactionTest,HttpsGetLookup)1635 TEST_F(DnsTransactionTest, HttpsGetLookup) {
1636 ConfigureDohServers(false /* use_post */);
1637 AddQueryAndResponse(0, kT0HostName, kT0Qtype, kT0ResponseDatagram,
1638 std::size(kT0ResponseDatagram), SYNCHRONOUS,
1639 Transport::HTTPS, nullptr /* opt_rdata */,
1640 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
1641 false /* enqueue_transaction_id */);
1642 TransactionHelper helper0(kT0RecordCount);
1643 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
1644 true /* secure */, resolve_context_.get());
1645 helper0.RunUntilComplete();
1646 }
1647
TEST_F(DnsTransactionTest,HttpsGetFailure)1648 TEST_F(DnsTransactionTest, HttpsGetFailure) {
1649 ConfigureDohServers(false /* use_post */);
1650 AddQueryAndRcode(kT0HostName, kT0Qtype, dns_protocol::kRcodeSERVFAIL,
1651 SYNCHRONOUS, Transport::HTTPS,
1652 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128, 0 /* id */,
1653 false /* enqueue_transaction_id */);
1654
1655 TransactionHelper helper0(ERR_DNS_SERVER_FAILED);
1656 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
1657 true /* secure */, resolve_context_.get());
1658 helper0.RunUntilComplete();
1659 ASSERT_NE(helper0.response(), nullptr);
1660 EXPECT_EQ(helper0.response()->rcode(), dns_protocol::kRcodeSERVFAIL);
1661 }
1662
TEST_F(DnsTransactionTest,HttpsGetMalformed)1663 TEST_F(DnsTransactionTest, HttpsGetMalformed) {
1664 ConfigureDohServers(false /* use_post */);
1665 // Use T1 response, which is malformed for a T0 request.
1666 AddQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype, kT1ResponseDatagram,
1667 std::size(kT1ResponseDatagram), SYNCHRONOUS,
1668 Transport::HTTPS, nullptr /* opt_rdata */,
1669 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
1670 false /* enqueue_transaction_id */);
1671 TransactionHelper helper0(ERR_DNS_MALFORMED_RESPONSE);
1672 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
1673 true /* secure */, resolve_context_.get());
1674 helper0.RunUntilComplete();
1675 }
1676
TEST_F(DnsTransactionTest,HttpsPostLookup)1677 TEST_F(DnsTransactionTest, HttpsPostLookup) {
1678 ConfigureDohServers(true /* use_post */);
1679 AddQueryAndResponse(0, kT0HostName, kT0Qtype, kT0ResponseDatagram,
1680 std::size(kT0ResponseDatagram), SYNCHRONOUS,
1681 Transport::HTTPS, nullptr /* opt_rdata */,
1682 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
1683 false /* enqueue_transaction_id */);
1684 TransactionHelper helper0(kT0RecordCount);
1685 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
1686 true /* secure */, resolve_context_.get());
1687 helper0.RunUntilComplete();
1688 }
1689
TEST_F(DnsTransactionTest,HttpsPostFailure)1690 TEST_F(DnsTransactionTest, HttpsPostFailure) {
1691 ConfigureDohServers(true /* use_post */);
1692 AddQueryAndRcode(kT0HostName, kT0Qtype, dns_protocol::kRcodeSERVFAIL,
1693 SYNCHRONOUS, Transport::HTTPS,
1694 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128, 0 /* id */,
1695 false /* enqueue_transaction_id */);
1696
1697 TransactionHelper helper0(ERR_DNS_SERVER_FAILED);
1698 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
1699 true /* secure */, resolve_context_.get());
1700 helper0.RunUntilComplete();
1701 ASSERT_NE(helper0.response(), nullptr);
1702 EXPECT_EQ(helper0.response()->rcode(), dns_protocol::kRcodeSERVFAIL);
1703 }
1704
TEST_F(DnsTransactionTest,HttpsPostMalformed)1705 TEST_F(DnsTransactionTest, HttpsPostMalformed) {
1706 ConfigureDohServers(true /* use_post */);
1707 // Use T1 response, which is malformed for a T0 request.
1708 AddQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype, kT1ResponseDatagram,
1709 std::size(kT1ResponseDatagram), SYNCHRONOUS,
1710 Transport::HTTPS, nullptr /* opt_rdata */,
1711 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
1712 false /* enqueue_transaction_id */);
1713
1714 TransactionHelper helper0(ERR_DNS_MALFORMED_RESPONSE);
1715 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
1716 true /* secure */, resolve_context_.get());
1717 helper0.RunUntilComplete();
1718 }
1719
TEST_F(DnsTransactionTest,HttpsPostLookupAsync)1720 TEST_F(DnsTransactionTest, HttpsPostLookupAsync) {
1721 ConfigureDohServers(true /* use_post */);
1722 AddQueryAndResponse(0, kT0HostName, kT0Qtype, kT0ResponseDatagram,
1723 std::size(kT0ResponseDatagram), ASYNC, Transport::HTTPS,
1724 nullptr /* opt_rdata */,
1725 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
1726 false /* enqueue_transaction_id */);
1727 TransactionHelper helper0(kT0RecordCount);
1728 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
1729 true /* secure */, resolve_context_.get());
1730 helper0.RunUntilComplete();
1731 }
1732
DohJobMakerCallbackFailLookup(URLRequest * request,SocketDataProvider * data)1733 std::unique_ptr<URLRequestJob> DohJobMakerCallbackFailLookup(
1734 URLRequest* request,
1735 SocketDataProvider* data) {
1736 URLRequestMockDohJob::MatchQueryData(request, data);
1737 return std::make_unique<URLRequestFailedJob>(
1738 request, URLRequestFailedJob::START, ERR_NAME_NOT_RESOLVED);
1739 }
1740
TEST_F(DnsTransactionTest,HttpsPostLookupFailDohServerLookup)1741 TEST_F(DnsTransactionTest, HttpsPostLookupFailDohServerLookup) {
1742 ConfigureDohServers(true /* use_post */);
1743 AddQueryAndResponse(0, kT0HostName, kT0Qtype, kT0ResponseDatagram,
1744 std::size(kT0ResponseDatagram), SYNCHRONOUS,
1745 Transport::HTTPS, nullptr /* opt_rdata */,
1746 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
1747 false /* enqueue_transaction_id */);
1748 TransactionHelper helper0(ERR_DNS_SECURE_RESOLVER_HOSTNAME_RESOLUTION_FAILED);
1749 SetDohJobMakerCallback(base::BindRepeating(DohJobMakerCallbackFailLookup));
1750 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
1751 true /* secure */, resolve_context_.get());
1752 helper0.RunUntilComplete();
1753 }
1754
DohJobMakerCallbackFailStart(URLRequest * request,SocketDataProvider * data)1755 std::unique_ptr<URLRequestJob> DohJobMakerCallbackFailStart(
1756 URLRequest* request,
1757 SocketDataProvider* data) {
1758 URLRequestMockDohJob::MatchQueryData(request, data);
1759 return std::make_unique<URLRequestFailedJob>(
1760 request, URLRequestFailedJob::START, ERR_FAILED);
1761 }
1762
TEST_F(DnsTransactionTest,HttpsPostLookupFailStart)1763 TEST_F(DnsTransactionTest, HttpsPostLookupFailStart) {
1764 ConfigureDohServers(true /* use_post */);
1765 AddQueryAndResponse(0, kT0HostName, kT0Qtype, kT0ResponseDatagram,
1766 std::size(kT0ResponseDatagram), SYNCHRONOUS,
1767 Transport::HTTPS, nullptr /* opt_rdata */,
1768 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
1769 false /* enqueue_transaction_id */);
1770 TransactionHelper helper0(ERR_FAILED);
1771 SetDohJobMakerCallback(base::BindRepeating(DohJobMakerCallbackFailStart));
1772 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
1773 true /* secure */, resolve_context_.get());
1774 helper0.RunUntilComplete();
1775 }
1776
DohJobMakerCallbackFailSync(URLRequest * request,SocketDataProvider * data)1777 std::unique_ptr<URLRequestJob> DohJobMakerCallbackFailSync(
1778 URLRequest* request,
1779 SocketDataProvider* data) {
1780 URLRequestMockDohJob::MatchQueryData(request, data);
1781 return std::make_unique<URLRequestFailedJob>(
1782 request, URLRequestFailedJob::READ_SYNC, ERR_FAILED);
1783 }
1784
TEST_F(DnsTransactionTest,HttpsPostLookupFailSync)1785 TEST_F(DnsTransactionTest, HttpsPostLookupFailSync) {
1786 ConfigureDohServers(true /* use_post */);
1787 auto data = std::make_unique<DnsSocketData>(
1788 0, kT0HostName, kT0Qtype, SYNCHRONOUS, Transport::HTTPS,
1789 nullptr /* opt_rdata */, DnsQuery::PaddingStrategy::BLOCK_LENGTH_128);
1790 data->AddResponseWithLength(std::make_unique<DnsResponse>(), SYNCHRONOUS, 0);
1791 AddSocketData(std::move(data), false /* enqueue_transaction_id */);
1792 TransactionHelper helper0(ERR_DNS_MALFORMED_RESPONSE);
1793 SetDohJobMakerCallback(base::BindRepeating(DohJobMakerCallbackFailSync));
1794 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
1795 true /* secure */, resolve_context_.get());
1796 helper0.RunUntilComplete();
1797 }
1798
DohJobMakerCallbackFailAsync(URLRequest * request,SocketDataProvider * data)1799 std::unique_ptr<URLRequestJob> DohJobMakerCallbackFailAsync(
1800 URLRequest* request,
1801 SocketDataProvider* data) {
1802 URLRequestMockDohJob::MatchQueryData(request, data);
1803 return std::make_unique<URLRequestFailedJob>(
1804 request, URLRequestFailedJob::READ_ASYNC, ERR_FAILED);
1805 }
1806
TEST_F(DnsTransactionTest,HttpsPostLookupFailAsync)1807 TEST_F(DnsTransactionTest, HttpsPostLookupFailAsync) {
1808 ConfigureDohServers(true /* use_post */);
1809 AddQueryAndResponse(0, kT0HostName, kT0Qtype, kT0ResponseDatagram,
1810 std::size(kT0ResponseDatagram), SYNCHRONOUS,
1811 Transport::HTTPS, nullptr /* opt_rdata */,
1812 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
1813 false /* enqueue_transaction_id */);
1814 TransactionHelper helper0(ERR_DNS_MALFORMED_RESPONSE);
1815 SetDohJobMakerCallback(base::BindRepeating(DohJobMakerCallbackFailAsync));
1816 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
1817 true /* secure */, resolve_context_.get());
1818 helper0.RunUntilComplete();
1819 }
1820
TEST_F(DnsTransactionTest,HttpsPostLookup2Sync)1821 TEST_F(DnsTransactionTest, HttpsPostLookup2Sync) {
1822 ConfigureDohServers(true /* use_post */);
1823 auto data = std::make_unique<DnsSocketData>(
1824 0, kT0HostName, kT0Qtype, SYNCHRONOUS, Transport::HTTPS,
1825 nullptr /* opt_rdata */, DnsQuery::PaddingStrategy::BLOCK_LENGTH_128);
1826 data->AddResponseData(kT0ResponseDatagram, 20, SYNCHRONOUS);
1827 data->AddResponseData(kT0ResponseDatagram + 20,
1828 std::size(kT0ResponseDatagram) - 20, SYNCHRONOUS);
1829 AddSocketData(std::move(data), false /* enqueue_transaction_id */);
1830 TransactionHelper helper0(kT0RecordCount);
1831 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
1832 true /* secure */, resolve_context_.get());
1833 helper0.RunUntilComplete();
1834 }
1835
TEST_F(DnsTransactionTest,HttpsPostLookup2Async)1836 TEST_F(DnsTransactionTest, HttpsPostLookup2Async) {
1837 ConfigureDohServers(true /* use_post */);
1838 auto data = std::make_unique<DnsSocketData>(
1839 0, kT0HostName, kT0Qtype, SYNCHRONOUS, Transport::HTTPS,
1840 nullptr /* opt_rdata */, DnsQuery::PaddingStrategy::BLOCK_LENGTH_128);
1841 data->AddResponseData(kT0ResponseDatagram, 20, ASYNC);
1842 data->AddResponseData(kT0ResponseDatagram + 20,
1843 std::size(kT0ResponseDatagram) - 20, ASYNC);
1844 AddSocketData(std::move(data), false /* enqueue_transaction_id */);
1845 TransactionHelper helper0(kT0RecordCount);
1846 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
1847 true /* secure */, resolve_context_.get());
1848 helper0.RunUntilComplete();
1849 }
1850
TEST_F(DnsTransactionTest,HttpsPostLookupAsyncWithAsyncZeroRead)1851 TEST_F(DnsTransactionTest, HttpsPostLookupAsyncWithAsyncZeroRead) {
1852 ConfigureDohServers(true /* use_post */);
1853 auto data = std::make_unique<DnsSocketData>(
1854 0, kT0HostName, kT0Qtype, SYNCHRONOUS, Transport::HTTPS,
1855 nullptr /* opt_rdata */, DnsQuery::PaddingStrategy::BLOCK_LENGTH_128);
1856 data->AddResponseData(kT0ResponseDatagram, std::size(kT0ResponseDatagram),
1857 ASYNC);
1858 data->AddResponseData(kT0ResponseDatagram, 0, ASYNC);
1859 AddSocketData(std::move(data), false /* enqueue_transaction_id */);
1860 TransactionHelper helper0(kT0RecordCount);
1861 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
1862 true /* secure */, resolve_context_.get());
1863 helper0.RunUntilComplete();
1864 }
1865
TEST_F(DnsTransactionTest,HttpsPostLookupSyncWithAsyncZeroRead)1866 TEST_F(DnsTransactionTest, HttpsPostLookupSyncWithAsyncZeroRead) {
1867 ConfigureDohServers(true /* use_post */);
1868 auto data = std::make_unique<DnsSocketData>(
1869 0, kT0HostName, kT0Qtype, SYNCHRONOUS, Transport::HTTPS,
1870 nullptr /* opt_rdata */, DnsQuery::PaddingStrategy::BLOCK_LENGTH_128);
1871 data->AddResponseData(kT0ResponseDatagram, std::size(kT0ResponseDatagram),
1872 SYNCHRONOUS);
1873 data->AddResponseData(kT0ResponseDatagram, 0, ASYNC);
1874 AddSocketData(std::move(data), false /* enqueue_transaction_id */);
1875 TransactionHelper helper0(kT0RecordCount);
1876 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
1877 true /* secure */, resolve_context_.get());
1878 helper0.RunUntilComplete();
1879 }
1880
TEST_F(DnsTransactionTest,HttpsPostLookupAsyncThenSync)1881 TEST_F(DnsTransactionTest, HttpsPostLookupAsyncThenSync) {
1882 ConfigureDohServers(true /* use_post */);
1883 auto data = std::make_unique<DnsSocketData>(
1884 0, kT0HostName, kT0Qtype, SYNCHRONOUS, Transport::HTTPS,
1885 nullptr /* opt_rdata */, DnsQuery::PaddingStrategy::BLOCK_LENGTH_128);
1886 data->AddResponseData(kT0ResponseDatagram, 20, ASYNC);
1887 data->AddResponseData(kT0ResponseDatagram + 20,
1888 std::size(kT0ResponseDatagram) - 20, SYNCHRONOUS);
1889 AddSocketData(std::move(data), false /* enqueue_transaction_id */);
1890 TransactionHelper helper0(kT0RecordCount);
1891 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
1892 true /* secure */, resolve_context_.get());
1893 helper0.RunUntilComplete();
1894 }
1895
TEST_F(DnsTransactionTest,HttpsPostLookupAsyncThenSyncError)1896 TEST_F(DnsTransactionTest, HttpsPostLookupAsyncThenSyncError) {
1897 ConfigureDohServers(true /* use_post */);
1898 auto data = std::make_unique<DnsSocketData>(
1899 0, kT0HostName, kT0Qtype, SYNCHRONOUS, Transport::HTTPS,
1900 nullptr /* opt_rdata */, DnsQuery::PaddingStrategy::BLOCK_LENGTH_128);
1901 data->AddResponseData(kT0ResponseDatagram, 20, ASYNC);
1902 data->AddReadError(ERR_FAILED, SYNCHRONOUS);
1903 AddSocketData(std::move(data), false /* enqueue_transaction_id */);
1904 TransactionHelper helper0(ERR_FAILED);
1905 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
1906 true /* secure */, resolve_context_.get());
1907 helper0.RunUntilComplete();
1908 }
1909
TEST_F(DnsTransactionTest,HttpsPostLookupAsyncThenAsyncError)1910 TEST_F(DnsTransactionTest, HttpsPostLookupAsyncThenAsyncError) {
1911 ConfigureDohServers(true /* use_post */);
1912 auto data = std::make_unique<DnsSocketData>(
1913 0, kT0HostName, kT0Qtype, SYNCHRONOUS, Transport::HTTPS,
1914 nullptr /* opt_rdata */, DnsQuery::PaddingStrategy::BLOCK_LENGTH_128);
1915 data->AddResponseData(kT0ResponseDatagram, 20, ASYNC);
1916 data->AddReadError(ERR_FAILED, ASYNC);
1917 AddSocketData(std::move(data), false /* enqueue_transaction_id */);
1918 TransactionHelper helper0(ERR_FAILED);
1919 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
1920 true /* secure */, resolve_context_.get());
1921 helper0.RunUntilComplete();
1922 }
1923
TEST_F(DnsTransactionTest,HttpsPostLookupSyncThenAsyncError)1924 TEST_F(DnsTransactionTest, HttpsPostLookupSyncThenAsyncError) {
1925 ConfigureDohServers(true /* use_post */);
1926 auto data = std::make_unique<DnsSocketData>(
1927 0, kT0HostName, kT0Qtype, SYNCHRONOUS, Transport::HTTPS,
1928 nullptr /* opt_rdata */, DnsQuery::PaddingStrategy::BLOCK_LENGTH_128);
1929 data->AddResponseData(kT0ResponseDatagram, 20, SYNCHRONOUS);
1930 data->AddReadError(ERR_FAILED, ASYNC);
1931 AddSocketData(std::move(data), false /* enqueue_transaction_id */);
1932 TransactionHelper helper0(ERR_FAILED);
1933 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
1934 true /* secure */, resolve_context_.get());
1935 helper0.RunUntilComplete();
1936 }
1937
TEST_F(DnsTransactionTest,HttpsPostLookupSyncThenSyncError)1938 TEST_F(DnsTransactionTest, HttpsPostLookupSyncThenSyncError) {
1939 ConfigureDohServers(true /* use_post */);
1940 auto data = std::make_unique<DnsSocketData>(
1941 0, kT0HostName, kT0Qtype, SYNCHRONOUS, Transport::HTTPS,
1942 nullptr /* opt_rdata */, DnsQuery::PaddingStrategy::BLOCK_LENGTH_128);
1943 data->AddResponseData(kT0ResponseDatagram, 20, SYNCHRONOUS);
1944 data->AddReadError(ERR_FAILED, SYNCHRONOUS);
1945 AddSocketData(std::move(data), false /* enqueue_transaction_id */);
1946 TransactionHelper helper0(ERR_FAILED);
1947 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
1948 true /* secure */, resolve_context_.get());
1949 helper0.RunUntilComplete();
1950 }
1951
TEST_F(DnsTransactionTest,HttpsNotAvailable)1952 TEST_F(DnsTransactionTest, HttpsNotAvailable) {
1953 ConfigureDohServers(true /* use_post */, 1 /* num_doh_servers */,
1954 false /* make_available */);
1955 ASSERT_FALSE(resolve_context_->GetDohServerAvailability(
1956 0u /* doh_server_index */, session_.get()));
1957
1958 TransactionHelper helper0(ERR_BLOCKED_BY_CLIENT);
1959 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
1960 true /* secure */, resolve_context_.get());
1961 helper0.RunUntilComplete();
1962 }
1963
TEST_F(DnsTransactionTest,HttpsMarkHttpsBad)1964 TEST_F(DnsTransactionTest, HttpsMarkHttpsBad) {
1965 config_.attempts = 1;
1966 ConfigureDohServers(true /* use_post */, 3);
1967 AddQueryAndErrorResponse(0, kT0HostName, kT0Qtype, ERR_CONNECTION_REFUSED,
1968 SYNCHRONOUS, Transport::HTTPS,
1969 nullptr /* opt_rdata */,
1970 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
1971 false /* enqueue_transaction_id */);
1972 AddQueryAndErrorResponse(0, kT0HostName, kT0Qtype, ERR_CONNECTION_REFUSED,
1973 SYNCHRONOUS, Transport::HTTPS,
1974 nullptr /* opt_rdata */,
1975 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
1976 false /* enqueue_transaction_id */);
1977 AddQueryAndResponse(0, kT0HostName, kT0Qtype, kT0ResponseDatagram,
1978 std::size(kT0ResponseDatagram), ASYNC, Transport::HTTPS,
1979 nullptr /* opt_rdata */,
1980 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
1981 false /* enqueue_transaction_id */);
1982 AddQueryAndErrorResponse(0 /* id */, kT0HostName, kT0Qtype,
1983 ERR_CONNECTION_REFUSED, SYNCHRONOUS,
1984 Transport::HTTPS, nullptr /* opt_rdata */,
1985 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
1986 false /* enqueue_transaction_id */);
1987 AddQueryAndErrorResponse(0 /* id */, kT0HostName, kT0Qtype,
1988 ERR_CONNECTION_REFUSED, SYNCHRONOUS,
1989 Transport::HTTPS, nullptr /* opt_rdata */,
1990 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
1991 false /* enqueue_transaction_id */);
1992 AddQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype, kT0ResponseDatagram,
1993 std::size(kT0ResponseDatagram), ASYNC, Transport::HTTPS,
1994 nullptr /* opt_rdata */,
1995 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
1996 false /* enqueue_transaction_id */);
1997
1998 TransactionHelper helper0(kT0RecordCount);
1999 TransactionHelper helper1(kT0RecordCount);
2000
2001 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
2002 true /* secure */, resolve_context_.get());
2003 helper0.RunUntilComplete();
2004
2005 // UDP server 0 is our only UDP server, so it will be good. HTTPS
2006 // servers 0 and 1 failed and will be marked bad. HTTPS server 2 succeeded
2007 // so it will be good.
2008 // The expected order of the HTTPS servers is therefore 2, 0, then 1.
2009 {
2010 std::unique_ptr<DnsServerIterator> classic_itr =
2011 resolve_context_->GetClassicDnsIterator(session_->config(),
2012 session_.get());
2013 std::unique_ptr<DnsServerIterator> doh_itr =
2014 resolve_context_->GetDohIterator(
2015 session_->config(), SecureDnsMode::kAutomatic, session_.get());
2016 EXPECT_TRUE(classic_itr->AttemptAvailable());
2017 EXPECT_EQ(classic_itr->GetNextAttemptIndex(), 0u);
2018 ASSERT_TRUE(doh_itr->AttemptAvailable());
2019 EXPECT_EQ(doh_itr->GetNextAttemptIndex(), 2u);
2020 ASSERT_TRUE(doh_itr->AttemptAvailable());
2021 EXPECT_EQ(doh_itr->GetNextAttemptIndex(), 0u);
2022 ASSERT_TRUE(doh_itr->AttemptAvailable());
2023 EXPECT_EQ(doh_itr->GetNextAttemptIndex(), 1u);
2024 }
2025 size_t kOrder0[] = {1, 2, 3};
2026 CheckServerOrder(kOrder0, std::size(kOrder0));
2027
2028 helper1.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
2029 true /* secure */, resolve_context_.get());
2030 helper1.RunUntilComplete();
2031 // UDP server 0 is still our only UDP server, so it will be good by
2032 // definition. HTTPS server 2 started out as good, so it was tried first and
2033 // failed. HTTPS server 0 then had the oldest failure so it would be the next
2034 // good server and then it failed so it's marked bad. Next attempt was HTTPS
2035 // server 1, which succeeded so it's good. The expected order of the HTTPS
2036 // servers is therefore 1, 2, then 0.
2037
2038 {
2039 std::unique_ptr<DnsServerIterator> classic_itr =
2040 resolve_context_->GetClassicDnsIterator(session_->config(),
2041 session_.get());
2042 std::unique_ptr<DnsServerIterator> doh_itr =
2043 resolve_context_->GetDohIterator(
2044 session_->config(), SecureDnsMode::kAutomatic, session_.get());
2045
2046 EXPECT_EQ(classic_itr->GetNextAttemptIndex(), 0u);
2047 ASSERT_TRUE(doh_itr->AttemptAvailable());
2048 EXPECT_EQ(doh_itr->GetNextAttemptIndex(), 1u);
2049 EXPECT_EQ(doh_itr->GetNextAttemptIndex(), 2u);
2050 EXPECT_EQ(doh_itr->GetNextAttemptIndex(), 0u);
2051 }
2052
2053 size_t kOrder1[] = {
2054 1, 2, 3, /* transaction0 */
2055 3, 1, 2 /* transaction1 */
2056 };
2057 CheckServerOrder(kOrder1, std::size(kOrder1));
2058 }
2059
TEST_F(DnsTransactionTest,HttpsPostFailThenHTTPFallback)2060 TEST_F(DnsTransactionTest, HttpsPostFailThenHTTPFallback) {
2061 ConfigureDohServers(true /* use_post */, 2);
2062 AddQueryAndRcode(kT0HostName, kT0Qtype, dns_protocol::kRcodeSERVFAIL, ASYNC,
2063 Transport::HTTPS,
2064 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128, 0 /* id */,
2065 false /* enqueue_transaction_id */);
2066 AddQueryAndResponse(0, kT0HostName, kT0Qtype, kT0ResponseDatagram,
2067 std::size(kT0ResponseDatagram), SYNCHRONOUS,
2068 Transport::HTTPS, nullptr /* opt_rdata */,
2069 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
2070 false /* enqueue_transaction_id */);
2071 TransactionHelper helper0(kT0RecordCount);
2072 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
2073 true /* secure */, resolve_context_.get());
2074 helper0.RunUntilComplete();
2075 size_t kOrder0[] = {1, 2};
2076 CheckServerOrder(kOrder0, std::size(kOrder0));
2077 }
2078
TEST_F(DnsTransactionTest,HttpsPostFailTwice)2079 TEST_F(DnsTransactionTest, HttpsPostFailTwice) {
2080 config_.attempts = 3;
2081 ConfigureDohServers(true /* use_post */, 2);
2082 AddQueryAndResponse(0, kT0HostName, kT0Qtype, kT0ResponseDatagram,
2083 std::size(kT0ResponseDatagram), SYNCHRONOUS,
2084 Transport::HTTPS, nullptr /* opt_rdata */,
2085 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
2086 false /* enqueue_transaction_id */);
2087 AddQueryAndResponse(0, kT0HostName, kT0Qtype, kT0ResponseDatagram,
2088 std::size(kT0ResponseDatagram), SYNCHRONOUS,
2089 Transport::HTTPS, nullptr /* opt_rdata */,
2090 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
2091 false /* enqueue_transaction_id */);
2092 TransactionHelper helper0(ERR_FAILED);
2093 SetDohJobMakerCallback(base::BindRepeating(DohJobMakerCallbackFailStart));
2094 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
2095 true /* secure */, resolve_context_.get());
2096 helper0.RunUntilComplete();
2097 size_t kOrder0[] = {1, 2};
2098 CheckServerOrder(kOrder0, std::size(kOrder0));
2099 }
2100
TEST_F(DnsTransactionTest,HttpsNotAvailableThenHttpFallback)2101 TEST_F(DnsTransactionTest, HttpsNotAvailableThenHttpFallback) {
2102 ConfigureDohServers(true /* use_post */, 2 /* num_doh_servers */,
2103 false /* make_available */);
2104
2105 // Make just server 1 available.
2106 resolve_context_->RecordServerSuccess(
2107 1u /* server_index */, true /* is_doh_server*/, session_.get());
2108
2109 {
2110 std::unique_ptr<DnsServerIterator> doh_itr =
2111 resolve_context_->GetDohIterator(
2112 session_->config(), SecureDnsMode::kAutomatic, session_.get());
2113
2114 ASSERT_TRUE(doh_itr->AttemptAvailable());
2115 EXPECT_EQ(doh_itr->GetNextAttemptIndex(), 1u);
2116 EXPECT_FALSE(doh_itr->AttemptAvailable());
2117 }
2118 AddQueryAndResponse(0, kT0HostName, kT0Qtype, kT0ResponseDatagram,
2119 std::size(kT0ResponseDatagram), SYNCHRONOUS,
2120 Transport::HTTPS, nullptr /* opt_rdata */,
2121 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
2122 false /* enqueue_transaction_id */);
2123 TransactionHelper helper0(kT0RecordCount);
2124 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
2125 true /* secure */, resolve_context_.get());
2126 helper0.RunUntilComplete();
2127 size_t kOrder0[] = {2};
2128 CheckServerOrder(kOrder0, std::size(kOrder0));
2129 {
2130 std::unique_ptr<DnsServerIterator> doh_itr =
2131 resolve_context_->GetDohIterator(
2132 session_->config(), SecureDnsMode::kAutomatic, session_.get());
2133
2134 ASSERT_TRUE(doh_itr->AttemptAvailable());
2135 EXPECT_EQ(doh_itr->GetNextAttemptIndex(), 1u);
2136 EXPECT_FALSE(doh_itr->AttemptAvailable());
2137 }
2138 }
2139
2140 // Fail first DoH server, then no fallbacks marked available in AUTOMATIC mode.
TEST_F(DnsTransactionTest,HttpsFailureThenNotAvailable_Automatic)2141 TEST_F(DnsTransactionTest, HttpsFailureThenNotAvailable_Automatic) {
2142 config_.secure_dns_mode = SecureDnsMode::kAutomatic;
2143 ConfigureDohServers(true /* use_post */, 3 /* num_doh_servers */,
2144 false /* make_available */);
2145
2146 // Make just server 0 available.
2147 resolve_context_->RecordServerSuccess(
2148 0u /* server_index */, true /* is_doh_server*/, session_.get());
2149
2150 {
2151 std::unique_ptr<DnsServerIterator> doh_itr =
2152 resolve_context_->GetDohIterator(
2153 session_->config(), SecureDnsMode::kAutomatic, session_.get());
2154
2155 ASSERT_TRUE(doh_itr->AttemptAvailable());
2156 EXPECT_EQ(doh_itr->GetNextAttemptIndex(), 0u);
2157 EXPECT_FALSE(doh_itr->AttemptAvailable());
2158 }
2159
2160 AddQueryAndErrorResponse(0, kT0HostName, kT0Qtype, ERR_CONNECTION_REFUSED,
2161 SYNCHRONOUS, Transport::HTTPS,
2162 nullptr /* opt_rdata */,
2163 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
2164 false /* enqueue_transaction_id */);
2165 TransactionHelper helper0(ERR_CONNECTION_REFUSED);
2166 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
2167 true /* secure */, resolve_context_.get());
2168 helper0.RunUntilComplete();
2169
2170 // Expect fallback not attempted because other servers not available in
2171 // AUTOMATIC mode until they have recorded a success.
2172 size_t kOrder0[] = {1};
2173 CheckServerOrder(kOrder0, std::size(kOrder0));
2174
2175 {
2176 std::unique_ptr<DnsServerIterator> doh_itr =
2177 resolve_context_->GetDohIterator(
2178 session_->config(), SecureDnsMode::kAutomatic, session_.get());
2179
2180 ASSERT_TRUE(doh_itr->AttemptAvailable());
2181 EXPECT_EQ(doh_itr->GetNextAttemptIndex(), 0u);
2182 EXPECT_FALSE(doh_itr->AttemptAvailable());
2183 }
2184 }
2185
2186 // Test a secure transaction failure in SECURE mode when other DoH servers are
2187 // only available for fallback because of
TEST_F(DnsTransactionTest,HttpsFailureThenNotAvailable_Secure)2188 TEST_F(DnsTransactionTest, HttpsFailureThenNotAvailable_Secure) {
2189 config_.secure_dns_mode = SecureDnsMode::kSecure;
2190 ConfigureDohServers(true /* use_post */, 3 /* num_doh_servers */,
2191 false /* make_available */);
2192
2193 // Make just server 0 available.
2194 resolve_context_->RecordServerSuccess(
2195 0u /* server_index */, true /* is_doh_server*/, session_.get());
2196
2197 {
2198 std::unique_ptr<DnsServerIterator> doh_itr =
2199 resolve_context_->GetDohIterator(
2200 session_->config(), SecureDnsMode::kSecure, session_.get());
2201
2202 ASSERT_TRUE(doh_itr->AttemptAvailable());
2203 EXPECT_EQ(doh_itr->GetNextAttemptIndex(), 0u);
2204 ASSERT_TRUE(doh_itr->AttemptAvailable());
2205 EXPECT_EQ(doh_itr->GetNextAttemptIndex(), 1u);
2206 ASSERT_TRUE(doh_itr->AttemptAvailable());
2207 EXPECT_EQ(doh_itr->GetNextAttemptIndex(), 2u);
2208 }
2209
2210 AddQueryAndErrorResponse(0, kT0HostName, kT0Qtype, ERR_CONNECTION_REFUSED,
2211 SYNCHRONOUS, Transport::HTTPS,
2212 nullptr /* opt_rdata */,
2213 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
2214 false /* enqueue_transaction_id */);
2215 AddQueryAndErrorResponse(0, kT0HostName, kT0Qtype, ERR_CONNECTION_REFUSED,
2216 SYNCHRONOUS, Transport::HTTPS,
2217 nullptr /* opt_rdata */,
2218 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
2219 false /* enqueue_transaction_id */);
2220 AddQueryAndErrorResponse(0, kT0HostName, kT0Qtype, ERR_CONNECTION_REFUSED,
2221 SYNCHRONOUS, Transport::HTTPS,
2222 nullptr /* opt_rdata */,
2223 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
2224 false /* enqueue_transaction_id */);
2225 TransactionHelper helper0(ERR_CONNECTION_REFUSED);
2226 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
2227 true /* secure */, resolve_context_.get());
2228 helper0.RunUntilComplete();
2229
2230 // Expect fallback to attempt all servers because SECURE mode does not require
2231 // server availability.
2232 size_t kOrder0[] = {1, 2, 3};
2233 CheckServerOrder(kOrder0, std::size(kOrder0));
2234
2235 // Expect server 0 to be preferred due to least recent failure.
2236 {
2237 std::unique_ptr<DnsServerIterator> doh_itr =
2238 resolve_context_->GetDohIterator(
2239 session_->config(), SecureDnsMode::kSecure, session_.get());
2240
2241 ASSERT_TRUE(doh_itr->AttemptAvailable());
2242 EXPECT_EQ(doh_itr->GetNextAttemptIndex(), 0u);
2243 }
2244 }
2245
TEST_F(DnsTransactionTest,MaxHttpsFailures_NonConsecutive)2246 TEST_F(DnsTransactionTest, MaxHttpsFailures_NonConsecutive) {
2247 config_.attempts = 1;
2248 ConfigureDohServers(false /* use_post */);
2249 {
2250 std::unique_ptr<DnsServerIterator> doh_itr =
2251 resolve_context_->GetDohIterator(
2252 session_->config(), SecureDnsMode::kAutomatic, session_.get());
2253
2254 ASSERT_TRUE(doh_itr->AttemptAvailable());
2255 EXPECT_EQ(doh_itr->GetNextAttemptIndex(), 0u);
2256 }
2257
2258 for (size_t i = 0; i < ResolveContext::kAutomaticModeFailureLimit - 1; i++) {
2259 AddQueryAndErrorResponse(0, kT0HostName, kT0Qtype, ERR_CONNECTION_REFUSED,
2260 SYNCHRONOUS, Transport::HTTPS,
2261 nullptr /* opt_rdata */,
2262 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
2263 false /* enqueue_transaction_id */);
2264 TransactionHelper failure(ERR_CONNECTION_REFUSED);
2265 failure.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
2266 true /* secure */, resolve_context_.get());
2267 failure.RunUntilComplete();
2268
2269 std::unique_ptr<DnsServerIterator> doh_itr =
2270 resolve_context_->GetDohIterator(
2271 session_->config(), SecureDnsMode::kAutomatic, session_.get());
2272
2273 ASSERT_TRUE(doh_itr->AttemptAvailable());
2274 EXPECT_EQ(doh_itr->GetNextAttemptIndex(), 0u);
2275 }
2276
2277 // A success should reset the failure counter for DoH.
2278 AddQueryAndResponse(0, kT0HostName, kT0Qtype, kT0ResponseDatagram,
2279 std::size(kT0ResponseDatagram), SYNCHRONOUS,
2280 Transport::HTTPS, nullptr /* opt_rdata */,
2281 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
2282 false /* enqueue_transaction_id */);
2283 TransactionHelper success(kT0RecordCount);
2284 success.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
2285 true /* secure */, resolve_context_.get());
2286 success.RunUntilComplete();
2287 {
2288 std::unique_ptr<DnsServerIterator> doh_itr =
2289 resolve_context_->GetDohIterator(
2290 session_->config(), SecureDnsMode::kAutomatic, session_.get());
2291
2292 ASSERT_TRUE(doh_itr->AttemptAvailable());
2293 EXPECT_EQ(doh_itr->GetNextAttemptIndex(), 0u);
2294 }
2295
2296 // One more failure should not pass the threshold because failures were reset.
2297 AddQueryAndErrorResponse(0, kT0HostName, kT0Qtype, ERR_CONNECTION_REFUSED,
2298 SYNCHRONOUS, Transport::HTTPS,
2299 nullptr /* opt_rdata */,
2300 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
2301 false /* enqueue_transaction_id */);
2302 TransactionHelper last_failure(ERR_CONNECTION_REFUSED);
2303 last_failure.StartTransaction(transaction_factory_.get(), kT0HostName,
2304 kT0Qtype, true /* secure */,
2305 resolve_context_.get());
2306 last_failure.RunUntilComplete();
2307 {
2308 std::unique_ptr<DnsServerIterator> doh_itr =
2309 resolve_context_->GetDohIterator(
2310 session_->config(), SecureDnsMode::kAutomatic, session_.get());
2311
2312 ASSERT_TRUE(doh_itr->AttemptAvailable());
2313 EXPECT_EQ(doh_itr->GetNextAttemptIndex(), 0u);
2314 }
2315 }
2316
TEST_F(DnsTransactionTest,MaxHttpsFailures_Consecutive)2317 TEST_F(DnsTransactionTest, MaxHttpsFailures_Consecutive) {
2318 config_.attempts = 1;
2319 ConfigureDohServers(false /* use_post */);
2320 {
2321 std::unique_ptr<DnsServerIterator> doh_itr =
2322 resolve_context_->GetDohIterator(
2323 session_->config(), SecureDnsMode::kAutomatic, session_.get());
2324
2325 ASSERT_TRUE(doh_itr->AttemptAvailable());
2326 EXPECT_EQ(doh_itr->GetNextAttemptIndex(), 0u);
2327 }
2328
2329 for (size_t i = 0; i < ResolveContext::kAutomaticModeFailureLimit - 1; i++) {
2330 AddQueryAndErrorResponse(0, kT0HostName, kT0Qtype, ERR_CONNECTION_REFUSED,
2331 SYNCHRONOUS, Transport::HTTPS,
2332 nullptr /* opt_rdata */,
2333 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
2334 false /* enqueue_transaction_id */);
2335 TransactionHelper failure(ERR_CONNECTION_REFUSED);
2336 failure.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
2337 true /* secure */, resolve_context_.get());
2338 failure.RunUntilComplete();
2339 std::unique_ptr<DnsServerIterator> doh_itr =
2340 resolve_context_->GetDohIterator(
2341 session_->config(), SecureDnsMode::kAutomatic, session_.get());
2342
2343 ASSERT_TRUE(doh_itr->AttemptAvailable());
2344 EXPECT_EQ(doh_itr->GetNextAttemptIndex(), 0u);
2345 }
2346
2347 // One more failure should pass the threshold.
2348 AddQueryAndErrorResponse(0, kT0HostName, kT0Qtype, ERR_CONNECTION_REFUSED,
2349 SYNCHRONOUS, Transport::HTTPS,
2350 nullptr /* opt_rdata */,
2351 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
2352 false /* enqueue_transaction_id */);
2353 TransactionHelper last_failure(ERR_CONNECTION_REFUSED);
2354 last_failure.StartTransaction(transaction_factory_.get(), kT0HostName,
2355 kT0Qtype, true /* secure */,
2356 resolve_context_.get());
2357 last_failure.RunUntilComplete();
2358 {
2359 std::unique_ptr<DnsServerIterator> doh_itr =
2360 resolve_context_->GetDohIterator(
2361 session_->config(), SecureDnsMode::kAutomatic, session_.get());
2362
2363 EXPECT_FALSE(doh_itr->AttemptAvailable());
2364 }
2365 }
2366
2367 // Test that a secure transaction started before a DoH server becomes
2368 // unavailable can complete and make the server available again.
TEST_F(DnsTransactionTest,SuccessfulTransactionStartedBeforeUnavailable)2369 TEST_F(DnsTransactionTest, SuccessfulTransactionStartedBeforeUnavailable) {
2370 ConfigureDohServers(false /* use_post */);
2371 {
2372 std::unique_ptr<DnsServerIterator> doh_itr =
2373 resolve_context_->GetDohIterator(
2374 session_->config(), SecureDnsMode::kAutomatic, session_.get());
2375
2376 ASSERT_TRUE(doh_itr->AttemptAvailable());
2377 EXPECT_EQ(doh_itr->GetNextAttemptIndex(), 0u);
2378 }
2379
2380 // Create a socket data to first return ERR_IO_PENDING. This will pause the
2381 // response and not return the second response until
2382 // SequencedSocketData::Resume() is called.
2383 auto data = std::make_unique<DnsSocketData>(
2384 0, kT0HostName, kT0Qtype, ASYNC, Transport::HTTPS,
2385 nullptr /* opt_rdata */, DnsQuery::PaddingStrategy::BLOCK_LENGTH_128);
2386 data->AddReadError(ERR_IO_PENDING, ASYNC);
2387 data->AddResponseData(kT0ResponseDatagram, std::size(kT0ResponseDatagram),
2388 ASYNC);
2389 SequencedSocketData* sequenced_socket_data = data->GetProvider();
2390 AddSocketData(std::move(data), false /* enqueue_transaction_id */);
2391
2392 TransactionHelper delayed_success(kT0RecordCount);
2393 delayed_success.StartTransaction(transaction_factory_.get(), kT0HostName,
2394 kT0Qtype, true /* secure */,
2395 resolve_context_.get());
2396 base::RunLoop().RunUntilIdle();
2397 EXPECT_FALSE(delayed_success.has_completed());
2398
2399 // Trigger DoH server unavailability with a bunch of failures.
2400 for (size_t i = 0; i < ResolveContext::kAutomaticModeFailureLimit; i++) {
2401 AddQueryAndErrorResponse(0, kT0HostName, kT0Qtype, ERR_CONNECTION_REFUSED,
2402 SYNCHRONOUS, Transport::HTTPS,
2403 nullptr /* opt_rdata */,
2404 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
2405 false /* enqueue_transaction_id */);
2406 TransactionHelper failure(ERR_CONNECTION_REFUSED);
2407 failure.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
2408 true /* secure */, resolve_context_.get());
2409 failure.RunUntilComplete();
2410 }
2411 EXPECT_FALSE(resolve_context_->GetDohServerAvailability(
2412 0u /* doh_server_index */, session_.get()));
2413
2414 // Resume first query.
2415 ASSERT_FALSE(delayed_success.has_completed());
2416 sequenced_socket_data->Resume();
2417 delayed_success.RunUntilComplete();
2418
2419 // Expect DoH server is available again.
2420 EXPECT_TRUE(resolve_context_->GetDohServerAvailability(
2421 0u /* doh_server_index */, session_.get()));
2422 }
2423
MakeResponseWithCookie(URLRequest * request,HttpResponseInfo * info)2424 void MakeResponseWithCookie(URLRequest* request, HttpResponseInfo* info) {
2425 info->headers->AddHeader("Set-Cookie", "test-cookie=you-fail");
2426 }
2427
2428 class CookieCallback {
2429 public:
CookieCallback()2430 CookieCallback() : loop_to_quit_(std::make_unique<base::RunLoop>()) {}
2431
SetCookieCallback(CookieAccessResult result)2432 void SetCookieCallback(CookieAccessResult result) {
2433 result_ = result.status.IsInclude();
2434 loop_to_quit_->Quit();
2435 }
2436
2437 CookieCallback(const CookieCallback&) = delete;
2438 CookieCallback& operator=(const CookieCallback&) = delete;
2439
GetCookieListCallback(const net::CookieAccessResultList & list,const net::CookieAccessResultList & excluded_cookies)2440 void GetCookieListCallback(
2441 const net::CookieAccessResultList& list,
2442 const net::CookieAccessResultList& excluded_cookies) {
2443 list_ = cookie_util::StripAccessResults(list);
2444 loop_to_quit_->Quit();
2445 }
2446
Reset()2447 void Reset() { loop_to_quit_ = std::make_unique<base::RunLoop>(); }
2448
WaitUntilDone()2449 void WaitUntilDone() { loop_to_quit_->Run(); }
2450
cookie_list_size()2451 size_t cookie_list_size() { return list_.size(); }
2452
2453 private:
2454 net::CookieList list_;
2455 bool result_ = false;
2456 std::unique_ptr<base::RunLoop> loop_to_quit_;
2457 };
2458
TEST_F(DnsTransactionTest,HttpsPostTestNoCookies)2459 TEST_F(DnsTransactionTest, HttpsPostTestNoCookies) {
2460 ConfigureDohServers(true /* use_post */);
2461 AddQueryAndResponse(0, kT0HostName, kT0Qtype, kT0ResponseDatagram,
2462 std::size(kT0ResponseDatagram), SYNCHRONOUS,
2463 Transport::HTTPS, nullptr /* opt_rdata */,
2464 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
2465 false /* enqueue_transaction_id */);
2466 AddQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype, kT0ResponseDatagram,
2467 std::size(kT0ResponseDatagram), SYNCHRONOUS,
2468 Transport::HTTPS, nullptr /* opt_rdata */,
2469 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
2470 false /* enqueue_transaction_id */);
2471 TransactionHelper helper0(kT0RecordCount);
2472 TransactionHelper helper1(kT0RecordCount);
2473 SetResponseModifierCallback(base::BindRepeating(MakeResponseWithCookie));
2474
2475 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
2476 true /* secure */, resolve_context_.get());
2477 helper0.RunUntilComplete();
2478
2479 CookieCallback callback;
2480 request_context_->cookie_store()->GetCookieListWithOptionsAsync(
2481 GURL(GetURLFromTemplateWithoutParameters(
2482 config_.doh_config.servers()[0].server_template())),
2483 CookieOptions::MakeAllInclusive(), CookiePartitionKeyCollection(),
2484 base::BindOnce(&CookieCallback::GetCookieListCallback,
2485 base::Unretained(&callback)));
2486 callback.WaitUntilDone();
2487 EXPECT_EQ(0u, callback.cookie_list_size());
2488 callback.Reset();
2489 GURL cookie_url(GetURLFromTemplateWithoutParameters(
2490 config_.doh_config.servers()[0].server_template()));
2491 auto cookie = CanonicalCookie::Create(
2492 cookie_url, "test-cookie=you-still-fail", base::Time::Now(),
2493 absl::nullopt /* server_time */,
2494 absl::nullopt /* cookie_partition_key */);
2495 request_context_->cookie_store()->SetCanonicalCookieAsync(
2496 std::move(cookie), cookie_url, CookieOptions(),
2497 base::BindOnce(&CookieCallback::SetCookieCallback,
2498 base::Unretained(&callback)));
2499 helper1.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
2500 true /* secure */, resolve_context_.get());
2501 helper1.RunUntilComplete();
2502 }
2503
MakeResponseWithoutLength(URLRequest * request,HttpResponseInfo * info)2504 void MakeResponseWithoutLength(URLRequest* request, HttpResponseInfo* info) {
2505 info->headers->RemoveHeader("Content-Length");
2506 }
2507
TEST_F(DnsTransactionTest,HttpsPostNoContentLength)2508 TEST_F(DnsTransactionTest, HttpsPostNoContentLength) {
2509 ConfigureDohServers(true /* use_post */);
2510 AddQueryAndResponse(0, kT0HostName, kT0Qtype, kT0ResponseDatagram,
2511 std::size(kT0ResponseDatagram), SYNCHRONOUS,
2512 Transport::HTTPS, nullptr /* opt_rdata */,
2513 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
2514 false /* enqueue_transaction_id */);
2515 TransactionHelper helper0(kT0RecordCount);
2516 SetResponseModifierCallback(base::BindRepeating(MakeResponseWithoutLength));
2517 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
2518 true /* secure */, resolve_context_.get());
2519 helper0.RunUntilComplete();
2520 }
2521
MakeResponseWithBadRequestResponse(URLRequest * request,HttpResponseInfo * info)2522 void MakeResponseWithBadRequestResponse(URLRequest* request,
2523 HttpResponseInfo* info) {
2524 info->headers->ReplaceStatusLine("HTTP/1.1 400 Bad Request");
2525 }
2526
TEST_F(DnsTransactionTest,HttpsPostWithBadRequestResponse)2527 TEST_F(DnsTransactionTest, HttpsPostWithBadRequestResponse) {
2528 ConfigureDohServers(true /* use_post */);
2529 AddQueryAndResponse(0, kT0HostName, kT0Qtype, kT0ResponseDatagram,
2530 std::size(kT0ResponseDatagram), SYNCHRONOUS,
2531 Transport::HTTPS, nullptr /* opt_rdata */,
2532 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
2533 false /* enqueue_transaction_id */);
2534 TransactionHelper helper0(ERR_DNS_MALFORMED_RESPONSE);
2535 SetResponseModifierCallback(
2536 base::BindRepeating(MakeResponseWithBadRequestResponse));
2537 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
2538 true /* secure */, resolve_context_.get());
2539 helper0.RunUntilComplete();
2540 }
2541
MakeResponseWrongType(URLRequest * request,HttpResponseInfo * info)2542 void MakeResponseWrongType(URLRequest* request, HttpResponseInfo* info) {
2543 info->headers->RemoveHeader("Content-Type");
2544 info->headers->AddHeader("Content-Type", "text/html");
2545 }
2546
TEST_F(DnsTransactionTest,HttpsPostWithWrongType)2547 TEST_F(DnsTransactionTest, HttpsPostWithWrongType) {
2548 ConfigureDohServers(true /* use_post */);
2549 AddQueryAndResponse(0, kT0HostName, kT0Qtype, kT0ResponseDatagram,
2550 std::size(kT0ResponseDatagram), SYNCHRONOUS,
2551 Transport::HTTPS, nullptr /* opt_rdata */,
2552 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
2553 false /* enqueue_transaction_id */);
2554 TransactionHelper helper0(ERR_DNS_MALFORMED_RESPONSE);
2555 SetResponseModifierCallback(base::BindRepeating(MakeResponseWrongType));
2556 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
2557 true /* secure */, resolve_context_.get());
2558 helper0.RunUntilComplete();
2559 }
2560
MakeResponseRedirect(URLRequest * request,HttpResponseInfo * info)2561 void MakeResponseRedirect(URLRequest* request, HttpResponseInfo* info) {
2562 if (request->url_chain().size() < 2) {
2563 info->headers->ReplaceStatusLine("HTTP/1.1 302 Found");
2564 info->headers->AddHeader("Location",
2565 "/redirect-destination?" + request->url().query());
2566 }
2567 }
2568
TEST_F(DnsTransactionTest,HttpsGetRedirect)2569 TEST_F(DnsTransactionTest, HttpsGetRedirect) {
2570 ConfigureDohServers(false /* use_post */);
2571 AddQueryAndResponse(0, kT0HostName, kT0Qtype, kT0ResponseDatagram,
2572 std::size(kT0ResponseDatagram), SYNCHRONOUS,
2573 Transport::HTTPS, nullptr /* opt_rdata */,
2574 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
2575 false /* enqueue_transaction_id */);
2576 AddQueryAndResponse(0, kT0HostName, kT0Qtype, kT0ResponseDatagram,
2577 std::size(kT0ResponseDatagram), SYNCHRONOUS,
2578 Transport::HTTPS, nullptr /* opt_rdata */,
2579 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
2580 false /* enqueue_transaction_id */);
2581 TransactionHelper helper0(kT0RecordCount);
2582 SetResponseModifierCallback(base::BindRepeating(MakeResponseRedirect));
2583 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
2584 true /* secure */, resolve_context_.get());
2585 helper0.RunUntilComplete();
2586 }
2587
MakeResponseInsecureRedirect(URLRequest * request,HttpResponseInfo * info)2588 void MakeResponseInsecureRedirect(URLRequest* request, HttpResponseInfo* info) {
2589 if (request->url_chain().size() < 2) {
2590 info->headers->ReplaceStatusLine("HTTP/1.1 302 Found");
2591 const std::string location = URLRequestMockDohJob::GetMockHttpUrl(
2592 "/redirect-destination?" + request->url().query());
2593 info->headers->AddHeader("Location", location);
2594 }
2595 }
2596
TEST_F(DnsTransactionTest,HttpsGetRedirectToInsecureProtocol)2597 TEST_F(DnsTransactionTest, HttpsGetRedirectToInsecureProtocol) {
2598 ConfigureDohServers(/*use_post=*/false);
2599 AddQueryAndResponse(0, kT0HostName, kT0Qtype, kT0ResponseDatagram,
2600 std::size(kT0ResponseDatagram), SYNCHRONOUS,
2601 Transport::HTTPS, /*opt_rdata=*/nullptr,
2602 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
2603 /*enqueue_transaction_id=*/false);
2604 TransactionHelper helper0(ERR_ABORTED);
2605 SetResponseModifierCallback(
2606 base::BindRepeating(MakeResponseInsecureRedirect));
2607 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
2608 /*secure=*/true, resolve_context_.get());
2609 helper0.RunUntilComplete();
2610 ASSERT_EQ(helper0.response(), nullptr);
2611 }
2612
TEST_F(DnsTransactionTest,HttpsGetContentLengthTooLarge)2613 TEST_F(DnsTransactionTest, HttpsGetContentLengthTooLarge) {
2614 ConfigureDohServers(/*use_post=*/false);
2615 AddQueryAndResponse(0, kT0HostName, kT0Qtype, kT0ResponseDatagram,
2616 std::size(kT0ResponseDatagram), SYNCHRONOUS,
2617 Transport::HTTPS, /*opt_rdata=*/nullptr,
2618 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
2619 /*enqueue_transaction_id=*/false);
2620 TransactionHelper helper0(ERR_DNS_MALFORMED_RESPONSE);
2621 SetResponseModifierCallback(base::BindLambdaForTesting(
2622 [](URLRequest* request, HttpResponseInfo* info) {
2623 info->headers->AddHeader("Content-Length", "65536");
2624 }));
2625 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
2626 /*secure=*/true, resolve_context_.get());
2627 helper0.RunUntilComplete();
2628 ASSERT_EQ(helper0.response(), nullptr);
2629 }
2630
TEST_F(DnsTransactionTest,HttpsGetResponseTooLargeWithoutContentLength)2631 TEST_F(DnsTransactionTest, HttpsGetResponseTooLargeWithoutContentLength) {
2632 ConfigureDohServers(/*use_post=*/false);
2633 std::vector<uint8_t> large_response(65536, 0);
2634 AddQueryAndResponse(0, kT0HostName, kT0Qtype, large_response.data(),
2635 large_response.size(), SYNCHRONOUS, Transport::HTTPS,
2636 /*opt_rdata=*/nullptr,
2637 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
2638 /*enqueue_transaction_id=*/false);
2639 TransactionHelper helper0(ERR_DNS_MALFORMED_RESPONSE);
2640 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
2641 /*secure=*/true, resolve_context_.get());
2642 helper0.RunUntilComplete();
2643 ASSERT_EQ(helper0.response(), nullptr);
2644 }
2645
MakeResponseNoType(URLRequest * request,HttpResponseInfo * info)2646 void MakeResponseNoType(URLRequest* request, HttpResponseInfo* info) {
2647 info->headers->RemoveHeader("Content-Type");
2648 }
2649
TEST_F(DnsTransactionTest,HttpsPostWithNoType)2650 TEST_F(DnsTransactionTest, HttpsPostWithNoType) {
2651 ConfigureDohServers(true /* use_post */);
2652 AddQueryAndResponse(0, kT0HostName, kT0Qtype, kT0ResponseDatagram,
2653 std::size(kT0ResponseDatagram), SYNCHRONOUS,
2654 Transport::HTTPS, nullptr /* opt_rdata */,
2655 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
2656 false /* enqueue_transaction_id */);
2657 TransactionHelper helper0(ERR_DNS_MALFORMED_RESPONSE);
2658 SetResponseModifierCallback(base::BindRepeating(MakeResponseNoType));
2659 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
2660 true /* secure */, resolve_context_.get());
2661 helper0.RunUntilComplete();
2662 }
2663
TEST_F(DnsTransactionTest,CanLookupDohServerName)2664 TEST_F(DnsTransactionTest, CanLookupDohServerName) {
2665 config_.search.push_back("http");
2666 ConfigureDohServers(true /* use_post */);
2667 AddQueryAndErrorResponse(0, kMockHostname, dns_protocol::kTypeA,
2668 ERR_NAME_NOT_RESOLVED, SYNCHRONOUS, Transport::HTTPS,
2669 nullptr /* opt_rdata */,
2670 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
2671 false /* enqueue_transaction_id */);
2672 TransactionHelper helper0(ERR_NAME_NOT_RESOLVED);
2673 helper0.StartTransaction(transaction_factory_.get(), "mock",
2674 dns_protocol::kTypeA, true /* secure */,
2675 resolve_context_.get());
2676 helper0.RunUntilComplete();
2677 }
2678
TEST_F(DnsTransactionTest,HttpsPostLookupWithLog)2679 TEST_F(DnsTransactionTest, HttpsPostLookupWithLog) {
2680 ConfigureDohServers(true /* use_post */);
2681 AddQueryAndResponse(0, kT0HostName, kT0Qtype, kT0ResponseDatagram,
2682 std::size(kT0ResponseDatagram), SYNCHRONOUS,
2683 Transport::HTTPS, nullptr /* opt_rdata */,
2684 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
2685 false /* enqueue_transaction_id */);
2686 TransactionHelper helper0(kT0RecordCount);
2687 NetLogCountingObserver observer;
2688 NetLog::Get()->AddObserver(&observer, NetLogCaptureMode::kEverything);
2689 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
2690 true /* secure */, resolve_context_.get());
2691 helper0.RunUntilComplete();
2692 base::RunLoop().RunUntilIdle();
2693 EXPECT_EQ(observer.count(), 19);
2694 EXPECT_EQ(observer.dict_count(), 10);
2695 }
2696
2697 // Test for when a slow DoH response is delayed until after the initial fallback
2698 // period (but succeeds before the full timeout period).
TEST_F(DnsTransactionTestWithMockTime,SlowHttpsResponse_SingleAttempt)2699 TEST_F(DnsTransactionTestWithMockTime, SlowHttpsResponse_SingleAttempt) {
2700 config_.doh_attempts = 1;
2701 ConfigureDohServers(false /* use_post */);
2702
2703 // Assume fallback period is less than timeout.
2704 ASSERT_LT(resolve_context_->NextDohFallbackPeriod(0 /* doh_server_index */,
2705 session_.get()),
2706 resolve_context_->SecureTransactionTimeout(SecureDnsMode::kSecure,
2707 session_.get()));
2708
2709 // Simulate a slow response by using an ERR_IO_PENDING read error to delay
2710 // until SequencedSocketData::Resume() is called.
2711 auto data = std::make_unique<DnsSocketData>(
2712 0 /* id */, kT0HostName, kT0Qtype, ASYNC, Transport::HTTPS,
2713 nullptr /* opt_rdata */, DnsQuery::PaddingStrategy::BLOCK_LENGTH_128);
2714 data->AddReadError(ERR_IO_PENDING, ASYNC);
2715 data->AddResponseData(kT0ResponseDatagram, std::size(kT0ResponseDatagram),
2716 ASYNC);
2717 SequencedSocketData* sequenced_socket_data = data->GetProvider();
2718 AddSocketData(std::move(data), false /* enqueue_transaction_id */);
2719
2720 TransactionHelper helper(kT0RecordCount);
2721 std::unique_ptr<DnsTransaction> transaction =
2722 transaction_factory_->CreateTransaction(
2723 kT0HostName, kT0Qtype, NetLogWithSource(), true /* secure */,
2724 SecureDnsMode::kSecure, resolve_context_.get(),
2725 false /* fast_timeout */);
2726
2727 helper.StartTransaction(std::move(transaction));
2728 base::RunLoop().RunUntilIdle();
2729 ASSERT_FALSE(helper.has_completed());
2730 FastForwardBy(resolve_context_->NextDohFallbackPeriod(
2731 0 /* doh_server_index */, session_.get()));
2732 EXPECT_FALSE(helper.has_completed());
2733
2734 sequenced_socket_data->Resume();
2735 helper.RunUntilComplete();
2736 }
2737
2738 // Test for when a slow DoH response is delayed until after the initial fallback
2739 // period but fast timeout is enabled, resulting in timeout failure.
TEST_F(DnsTransactionTestWithMockTime,SlowHttpsResponse_SingleAttempt_FastTimeout)2740 TEST_F(DnsTransactionTestWithMockTime,
2741 SlowHttpsResponse_SingleAttempt_FastTimeout) {
2742 config_.doh_attempts = 1;
2743 ConfigureDohServers(false /* use_post */);
2744
2745 AddHangingQuery(kT0HostName, kT0Qtype,
2746 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128, 0 /* id */,
2747 false /* enqueue_transaction_id */);
2748
2749 TransactionHelper helper(ERR_DNS_TIMED_OUT);
2750 std::unique_ptr<DnsTransaction> transaction =
2751 transaction_factory_->CreateTransaction(
2752 kT0HostName, kT0Qtype, NetLogWithSource(), true /* secure */,
2753 SecureDnsMode::kSecure, resolve_context_.get(),
2754 true /* fast_timeout */);
2755 helper.StartTransaction(std::move(transaction));
2756 base::RunLoop().RunUntilIdle();
2757 ASSERT_FALSE(helper.has_completed());
2758
2759 // Only one attempt configured and fast timeout enabled, so expect immediate
2760 // failure after fallback period.
2761 FastForwardBy(resolve_context_->NextDohFallbackPeriod(
2762 0 /* doh_server_index */, session_.get()));
2763 EXPECT_TRUE(helper.has_completed());
2764 }
2765
2766 // Test for when a slow DoH response is delayed until after the initial fallback
2767 // period but a retry is configured.
TEST_F(DnsTransactionTestWithMockTime,SlowHttpsResponse_TwoAttempts)2768 TEST_F(DnsTransactionTestWithMockTime, SlowHttpsResponse_TwoAttempts) {
2769 config_.doh_attempts = 2;
2770 ConfigureDohServers(false /* use_post */);
2771
2772 // Simulate a slow response by using an ERR_IO_PENDING read error to delay
2773 // until SequencedSocketData::Resume() is called.
2774 auto data = std::make_unique<DnsSocketData>(
2775 0 /* id */, kT0HostName, kT0Qtype, ASYNC, Transport::HTTPS,
2776 nullptr /* opt_rdata */, DnsQuery::PaddingStrategy::BLOCK_LENGTH_128);
2777 data->AddReadError(ERR_IO_PENDING, ASYNC);
2778 data->AddResponseData(kT0ResponseDatagram, std::size(kT0ResponseDatagram),
2779 ASYNC);
2780 SequencedSocketData* sequenced_socket_data = data->GetProvider();
2781 AddSocketData(std::move(data), false /* enqueue_transaction_id */);
2782
2783 TransactionHelper helper(kT0RecordCount);
2784 std::unique_ptr<DnsTransaction> transaction =
2785 transaction_factory_->CreateTransaction(
2786 kT0HostName, kT0Qtype, NetLogWithSource(), true /* secure */,
2787 SecureDnsMode::kSecure, resolve_context_.get(),
2788 false /* fast_timeout */);
2789
2790 helper.StartTransaction(std::move(transaction));
2791 base::RunLoop().RunUntilIdle();
2792 ASSERT_FALSE(helper.has_completed());
2793 ASSERT_TRUE(sequenced_socket_data->IsPaused());
2794
2795 // Another attempt configured, so transaction should not fail after initial
2796 // fallback period. Setup the second attempt to never receive a response.
2797 AddHangingQuery(kT0HostName, kT0Qtype,
2798 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128, 0 /* id */,
2799 false /* enqueue_transaction_id */);
2800 FastForwardBy(resolve_context_->NextDohFallbackPeriod(
2801 0 /* doh_server_index */, session_.get()));
2802 EXPECT_FALSE(helper.has_completed());
2803
2804 // Expect first attempt to continue in parallel with retry, so expect the
2805 // transaction to complete when the first query is allowed to resume.
2806 sequenced_socket_data->Resume();
2807 helper.RunUntilComplete();
2808 }
2809
2810 // Test for when a slow DoH response is delayed until after the full timeout
2811 // period.
TEST_F(DnsTransactionTestWithMockTime,HttpsTimeout)2812 TEST_F(DnsTransactionTestWithMockTime, HttpsTimeout) {
2813 config_.doh_attempts = 1;
2814 ConfigureDohServers(false /* use_post */);
2815
2816 // Assume fallback period is less than timeout.
2817 ASSERT_LT(resolve_context_->NextDohFallbackPeriod(0 /* doh_server_index */,
2818 session_.get()),
2819 resolve_context_->SecureTransactionTimeout(SecureDnsMode::kSecure,
2820 session_.get()));
2821
2822 AddHangingQuery(kT0HostName, kT0Qtype,
2823 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128, 0 /* id */,
2824 false /* enqueue_transaction_id */);
2825
2826 TransactionHelper helper(ERR_DNS_TIMED_OUT);
2827 std::unique_ptr<DnsTransaction> transaction =
2828 transaction_factory_->CreateTransaction(
2829 kT0HostName, kT0Qtype, NetLogWithSource(), true /* secure */,
2830 SecureDnsMode::kSecure, resolve_context_.get(),
2831 false /* fast_timeout */);
2832 helper.StartTransaction(std::move(transaction));
2833 base::RunLoop().RunUntilIdle();
2834 ASSERT_FALSE(helper.has_completed());
2835
2836 // Stop a tiny bit short to ensure transaction doesn't finish early.
2837 const base::TimeDelta kTimeHoldback = base::Milliseconds(5);
2838 base::TimeDelta timeout = resolve_context_->SecureTransactionTimeout(
2839 SecureDnsMode::kSecure, session_.get());
2840 ASSERT_LT(kTimeHoldback, timeout);
2841 FastForwardBy(timeout - kTimeHoldback);
2842 EXPECT_FALSE(helper.has_completed());
2843
2844 FastForwardBy(kTimeHoldback);
2845 EXPECT_TRUE(helper.has_completed());
2846 }
2847
2848 // Test for when two slow DoH responses are delayed until after the full timeout
2849 // period.
TEST_F(DnsTransactionTestWithMockTime,HttpsTimeout2)2850 TEST_F(DnsTransactionTestWithMockTime, HttpsTimeout2) {
2851 config_.doh_attempts = 2;
2852 ConfigureDohServers(false /* use_post */);
2853
2854 // Assume fallback period is less than timeout.
2855 ASSERT_LT(resolve_context_->NextDohFallbackPeriod(0 /* doh_server_index */,
2856 session_.get()),
2857 resolve_context_->SecureTransactionTimeout(SecureDnsMode::kSecure,
2858 session_.get()));
2859
2860 AddHangingQuery(kT0HostName, kT0Qtype,
2861 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128, 0 /* id */,
2862 false /* enqueue_transaction_id */);
2863 AddHangingQuery(kT0HostName, kT0Qtype,
2864 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128, 0 /* id */,
2865 false /* enqueue_transaction_id */);
2866
2867 TransactionHelper helper(ERR_DNS_TIMED_OUT);
2868 std::unique_ptr<DnsTransaction> transaction =
2869 transaction_factory_->CreateTransaction(
2870 kT0HostName, kT0Qtype, NetLogWithSource(), true /* secure */,
2871 SecureDnsMode::kSecure, resolve_context_.get(),
2872 false /* fast_timeout */);
2873 helper.StartTransaction(std::move(transaction));
2874 base::RunLoop().RunUntilIdle();
2875 ASSERT_FALSE(helper.has_completed());
2876
2877 base::TimeDelta fallback_period = resolve_context_->NextDohFallbackPeriod(
2878 0 /* doh_server_index */, session_.get());
2879 FastForwardBy(fallback_period);
2880 EXPECT_FALSE(helper.has_completed());
2881
2882 // Timeout is from start of transaction, so need to keep track of the
2883 // remainder after other fast forwards.
2884 base::TimeDelta timeout = resolve_context_->SecureTransactionTimeout(
2885 SecureDnsMode::kSecure, session_.get());
2886 base::TimeDelta timeout_remainder = timeout - fallback_period;
2887
2888 // Fallback period for second attempt.
2889 fallback_period = resolve_context_->NextDohFallbackPeriod(
2890 0 /* doh_server_index */, session_.get());
2891 ASSERT_LT(fallback_period, timeout_remainder);
2892 FastForwardBy(fallback_period);
2893 EXPECT_FALSE(helper.has_completed());
2894 timeout_remainder -= fallback_period;
2895
2896 // Stop a tiny bit short to ensure transaction doesn't finish early.
2897 const base::TimeDelta kTimeHoldback = base::Milliseconds(5);
2898 ASSERT_LT(kTimeHoldback, timeout_remainder);
2899 FastForwardBy(timeout_remainder - kTimeHoldback);
2900 EXPECT_FALSE(helper.has_completed());
2901
2902 FastForwardBy(kTimeHoldback);
2903 EXPECT_TRUE(helper.has_completed());
2904 }
2905
2906 // Test for when attempt fallback periods go beyond the full timeout period.
TEST_F(DnsTransactionTestWithMockTime,LongHttpsTimeouts)2907 TEST_F(DnsTransactionTestWithMockTime, LongHttpsTimeouts) {
2908 const int kNumAttempts = 20;
2909 config_.doh_attempts = kNumAttempts;
2910 ConfigureDohServers(false /* use_post */);
2911
2912 // Assume sum of fallback periods is greater than timeout.
2913 ASSERT_GT(kNumAttempts * resolve_context_->NextDohFallbackPeriod(
2914 0 /* doh_server_index */, session_.get()),
2915 resolve_context_->SecureTransactionTimeout(SecureDnsMode::kSecure,
2916 session_.get()));
2917
2918 for (int i = 0; i < kNumAttempts; ++i) {
2919 AddHangingQuery(kT0HostName, kT0Qtype,
2920 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128, 0 /* id */,
2921 false /* enqueue_transaction_id */);
2922 }
2923
2924 TransactionHelper helper(ERR_DNS_TIMED_OUT);
2925 std::unique_ptr<DnsTransaction> transaction =
2926 transaction_factory_->CreateTransaction(
2927 kT0HostName, kT0Qtype, NetLogWithSource(), true /* secure */,
2928 SecureDnsMode::kSecure, resolve_context_.get(),
2929 false /* fast_timeout */);
2930 helper.StartTransaction(std::move(transaction));
2931 base::RunLoop().RunUntilIdle();
2932 ASSERT_FALSE(helper.has_completed());
2933
2934 for (int i = 0; i < kNumAttempts - 1; ++i) {
2935 FastForwardBy(resolve_context_->NextDohFallbackPeriod(
2936 0 /* doh_server_index */, session_.get()));
2937 EXPECT_FALSE(helper.has_completed());
2938 }
2939
2940 // Expect transaction to time out immediately after the last fallback period.
2941 FastForwardBy(resolve_context_->NextDohFallbackPeriod(
2942 0 /* doh_server_index */, session_.get()));
2943 EXPECT_TRUE(helper.has_completed());
2944 }
2945
2946 // Test for when the last of multiple HTTPS attempts fails (SERVFAIL) before
2947 // a previous attempt succeeds.
TEST_F(DnsTransactionTestWithMockTime,LastHttpsAttemptFails)2948 TEST_F(DnsTransactionTestWithMockTime, LastHttpsAttemptFails) {
2949 config_.doh_attempts = 2;
2950 ConfigureDohServers(false /* use_post */);
2951
2952 // Simulate a slow response by using an ERR_IO_PENDING read error to delay
2953 // until SequencedSocketData::Resume() is called.
2954 auto data = std::make_unique<DnsSocketData>(
2955 0 /* id */, kT0HostName, kT0Qtype, ASYNC, Transport::HTTPS,
2956 nullptr /* opt_rdata */, DnsQuery::PaddingStrategy::BLOCK_LENGTH_128);
2957 data->AddReadError(ERR_IO_PENDING, ASYNC);
2958 data->AddResponseData(kT0ResponseDatagram, std::size(kT0ResponseDatagram),
2959 ASYNC);
2960 SequencedSocketData* sequenced_socket_data = data->GetProvider();
2961 AddSocketData(std::move(data), false /* enqueue_transaction_id */);
2962
2963 AddQueryAndRcode(kT0HostName, kT0Qtype, dns_protocol::kRcodeSERVFAIL,
2964 SYNCHRONOUS, Transport::HTTPS,
2965 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128, 0 /* id */,
2966 false /* enqueue_transaction_id */);
2967
2968 TransactionHelper helper(kT0RecordCount);
2969 std::unique_ptr<DnsTransaction> transaction =
2970 transaction_factory_->CreateTransaction(
2971 kT0HostName, kT0Qtype, NetLogWithSource(), true /* secure */,
2972 SecureDnsMode::kSecure, resolve_context_.get(),
2973 false /* fast_timeout */);
2974 helper.StartTransaction(std::move(transaction));
2975
2976 // Wait for one timeout period to start (and fail) the second attempt.
2977 FastForwardBy(resolve_context_->NextDohFallbackPeriod(
2978 0 /* doh_server_index */, session_.get()));
2979 EXPECT_FALSE(helper.has_completed());
2980
2981 // Complete the first attempt and expect immediate success.
2982 sequenced_socket_data->Resume();
2983 helper.RunUntilComplete();
2984 }
2985
2986 // Test for when the last of multiple HTTPS attempts fails (SERVFAIL), and a
2987 // previous attempt never completes.
TEST_F(DnsTransactionTestWithMockTime,LastHttpsAttemptFails_Timeout)2988 TEST_F(DnsTransactionTestWithMockTime, LastHttpsAttemptFails_Timeout) {
2989 config_.doh_attempts = 2;
2990 ConfigureDohServers(false /* use_post */);
2991
2992 AddHangingQuery(kT0HostName, kT0Qtype,
2993 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128, 0 /* id */,
2994 false /* enqueue_transaction_id */);
2995 AddQueryAndRcode(kT0HostName, kT0Qtype, dns_protocol::kRcodeSERVFAIL,
2996 SYNCHRONOUS, Transport::HTTPS,
2997 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128, 0 /* id */,
2998 false /* enqueue_transaction_id */);
2999
3000 TransactionHelper helper(ERR_DNS_TIMED_OUT);
3001 std::unique_ptr<DnsTransaction> transaction =
3002 transaction_factory_->CreateTransaction(
3003 kT0HostName, kT0Qtype, NetLogWithSource(), true /* secure */,
3004 SecureDnsMode::kSecure, resolve_context_.get(),
3005 false /* fast_timeout */);
3006
3007 helper.StartTransaction(std::move(transaction));
3008 base::RunLoop().RunUntilIdle();
3009 EXPECT_FALSE(helper.has_completed());
3010
3011 // Second attempt fails immediately after first fallback period, but because
3012 // fast timeout is disabled, the transaction will attempt to wait for the
3013 // first attempt.
3014 base::TimeDelta fallback_period = resolve_context_->NextDohFallbackPeriod(
3015 0 /* doh_server_index */, session_.get());
3016 FastForwardBy(fallback_period);
3017 EXPECT_FALSE(helper.has_completed());
3018
3019 // Timeout is from start of transaction, so need to keep track of the
3020 // remainder after other fast forwards.
3021 base::TimeDelta timeout = resolve_context_->SecureTransactionTimeout(
3022 SecureDnsMode::kSecure, session_.get());
3023 base::TimeDelta timeout_remainder = timeout - fallback_period;
3024
3025 // Stop a tiny bit short to ensure transaction doesn't finish early.
3026 const base::TimeDelta kTimeHoldback = base::Milliseconds(5);
3027 ASSERT_LT(kTimeHoldback, timeout_remainder);
3028 FastForwardBy(timeout_remainder - kTimeHoldback);
3029 EXPECT_FALSE(helper.has_completed());
3030
3031 FastForwardBy(kTimeHoldback);
3032 EXPECT_TRUE(helper.has_completed());
3033 }
3034
3035 // Test for when the last of multiple HTTPS attempts fails (SERVFAIL) before
3036 // a previous attempt can complete, but fast timeouts is enabled.
TEST_F(DnsTransactionTestWithMockTime,LastHttpsAttemptFails_FastTimeout)3037 TEST_F(DnsTransactionTestWithMockTime, LastHttpsAttemptFails_FastTimeout) {
3038 config_.doh_attempts = 2;
3039 ConfigureDohServers(false /* use_post */);
3040
3041 AddHangingQuery(kT0HostName, kT0Qtype,
3042 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128, 0 /* id */,
3043 false /* enqueue_transaction_id */);
3044 AddQueryAndRcode(kT0HostName, kT0Qtype, dns_protocol::kRcodeSERVFAIL,
3045 SYNCHRONOUS, Transport::HTTPS,
3046 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128, 0 /* id */,
3047 false /* enqueue_transaction_id */);
3048
3049 TransactionHelper helper(ERR_DNS_SERVER_FAILED);
3050 std::unique_ptr<DnsTransaction> transaction =
3051 transaction_factory_->CreateTransaction(
3052 kT0HostName, kT0Qtype, NetLogWithSource(), true /* secure */,
3053 SecureDnsMode::kSecure, resolve_context_.get(),
3054 true /* fast_timeout */);
3055
3056 helper.StartTransaction(std::move(transaction));
3057 base::RunLoop().RunUntilIdle();
3058 EXPECT_FALSE(helper.has_completed());
3059
3060 // With fast timeout enabled, expect the transaction to complete with failure
3061 // immediately on failure of the last transaction.
3062 FastForwardBy(resolve_context_->NextDohFallbackPeriod(
3063 0 /* doh_server_index */, session_.get()));
3064 EXPECT_TRUE(helper.has_completed());
3065 }
3066
3067 // Test for when the last of multiple HTTPS attempts fails (SERVFAIL) before
3068 // a previous attempt later fails as well.
TEST_F(DnsTransactionTestWithMockTime,LastHttpsAttemptFailsFirst)3069 TEST_F(DnsTransactionTestWithMockTime, LastHttpsAttemptFailsFirst) {
3070 config_.doh_attempts = 2;
3071 ConfigureDohServers(false /* use_post */);
3072
3073 // Simulate a slow response by using an ERR_IO_PENDING read error to delay
3074 // until SequencedSocketData::Resume() is called.
3075 auto data = std::make_unique<DnsSocketData>(
3076 0 /* id */, kT0HostName, kT0Qtype, ASYNC, Transport::HTTPS,
3077 nullptr /* opt_rdata */, DnsQuery::PaddingStrategy::BLOCK_LENGTH_128);
3078 data->AddReadError(ERR_IO_PENDING, ASYNC);
3079 data->AddRcode(dns_protocol::kRcodeSERVFAIL, ASYNC);
3080 SequencedSocketData* sequenced_socket_data = data->GetProvider();
3081 AddSocketData(std::move(data), false /* enqueue_transaction_id */);
3082
3083 AddQueryAndRcode(kT0HostName, kT0Qtype, dns_protocol::kRcodeSERVFAIL,
3084 SYNCHRONOUS, Transport::HTTPS,
3085 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128, 0 /* id */,
3086 false /* enqueue_transaction_id */);
3087
3088 TransactionHelper helper(ERR_DNS_SERVER_FAILED);
3089 std::unique_ptr<DnsTransaction> transaction =
3090 transaction_factory_->CreateTransaction(
3091 kT0HostName, kT0Qtype, NetLogWithSource(), true /* secure */,
3092 SecureDnsMode::kSecure, resolve_context_.get(),
3093 false /* fast_timeout */);
3094 helper.StartTransaction(std::move(transaction));
3095
3096 // Wait for one timeout period to start (and fail) the second attempt.
3097 FastForwardBy(resolve_context_->NextDohFallbackPeriod(
3098 0 /* doh_server_index */, session_.get()));
3099 EXPECT_FALSE(helper.has_completed());
3100
3101 // Complete the first attempt and expect immediate completion.
3102 sequenced_socket_data->Resume();
3103 helper.RunUntilComplete();
3104 }
3105
3106 // Test for when multiple HTTPS attempts fail (SERVFAIL) in order, making the
3107 // last started attempt also the last attempt to be pending.
TEST_F(DnsTransactionTestWithMockTime,LastHttpsAttemptFailsLast)3108 TEST_F(DnsTransactionTestWithMockTime, LastHttpsAttemptFailsLast) {
3109 config_.doh_attempts = 2;
3110 ConfigureDohServers(false /* use_post */);
3111
3112 AddQueryAndRcode(kT0HostName, kT0Qtype, dns_protocol::kRcodeSERVFAIL,
3113 SYNCHRONOUS, Transport::HTTPS,
3114 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128, 0 /* id */,
3115 false /* enqueue_transaction_id */);
3116 AddQueryAndRcode(kT0HostName, kT0Qtype, dns_protocol::kRcodeSERVFAIL,
3117 SYNCHRONOUS, Transport::HTTPS,
3118 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128, 0 /* id */,
3119 false /* enqueue_transaction_id */);
3120
3121 TransactionHelper helper(ERR_DNS_SERVER_FAILED);
3122 std::unique_ptr<DnsTransaction> transaction =
3123 transaction_factory_->CreateTransaction(
3124 kT0HostName, kT0Qtype, NetLogWithSource(), true /* secure */,
3125 SecureDnsMode::kSecure, resolve_context_.get(),
3126 false /* fast_timeout */);
3127 helper.StartTransaction(std::move(transaction));
3128
3129 // Expect both attempts will run quickly without waiting for fallbacks or
3130 // transaction timeout.
3131 helper.RunUntilComplete();
3132 }
3133
TEST_F(DnsTransactionTest,TcpLookup_UdpRetry)3134 TEST_F(DnsTransactionTest, TcpLookup_UdpRetry) {
3135 AddAsyncQueryAndRcode(kT0HostName, kT0Qtype,
3136 dns_protocol::kRcodeNOERROR | dns_protocol::kFlagTC);
3137 AddQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype, kT0ResponseDatagram,
3138 std::size(kT0ResponseDatagram), ASYNC, Transport::TCP);
3139
3140 TransactionHelper helper0(kT0RecordCount);
3141 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
3142 false /* secure */, resolve_context_.get());
3143 helper0.RunUntilComplete();
3144 }
3145
TEST_F(DnsTransactionTest,TcpLookup_UdpRetry_WithLog)3146 TEST_F(DnsTransactionTest, TcpLookup_UdpRetry_WithLog) {
3147 AddAsyncQueryAndRcode(kT0HostName, kT0Qtype,
3148 dns_protocol::kRcodeNOERROR | dns_protocol::kFlagTC);
3149 AddQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype, kT0ResponseDatagram,
3150 std::size(kT0ResponseDatagram), ASYNC, Transport::TCP);
3151
3152 TransactionHelper helper0(kT0RecordCount);
3153 NetLogCountingObserver observer;
3154 NetLog::Get()->AddObserver(&observer, NetLogCaptureMode::kEverything);
3155 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
3156 false /* secure */, resolve_context_.get());
3157 helper0.RunUntilComplete();
3158 EXPECT_EQ(observer.count(), 9);
3159 EXPECT_EQ(observer.dict_count(), 7);
3160 }
3161
TEST_F(DnsTransactionTest,TcpLookup_LowEntropy)3162 TEST_F(DnsTransactionTest, TcpLookup_LowEntropy) {
3163 socket_factory_->diverse_source_ports_ = false;
3164
3165 for (int i = 0; i <= DnsUdpTracker::kPortReuseThreshold; ++i) {
3166 AddQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype, kT0ResponseDatagram,
3167 std::size(kT0ResponseDatagram), ASYNC, Transport::UDP);
3168 }
3169
3170 AddQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype, kT0ResponseDatagram,
3171 std::size(kT0ResponseDatagram), ASYNC, Transport::TCP);
3172
3173 for (int i = 0; i <= DnsUdpTracker::kPortReuseThreshold; ++i) {
3174 TransactionHelper udp_helper(kT0RecordCount);
3175 udp_helper.StartTransaction(transaction_factory_.get(), kT0HostName,
3176 kT0Qtype, false /* secure */,
3177 resolve_context_.get());
3178 udp_helper.RunUntilComplete();
3179 }
3180
3181 ASSERT_TRUE(session_->udp_tracker()->low_entropy());
3182
3183 TransactionHelper helper0(kT0RecordCount);
3184 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
3185 false /* secure */, resolve_context_.get());
3186 helper0.RunUntilComplete();
3187 EXPECT_TRUE(session_->udp_tracker()->low_entropy());
3188 }
3189
TEST_F(DnsTransactionTest,TCPFailure)3190 TEST_F(DnsTransactionTest, TCPFailure) {
3191 AddAsyncQueryAndRcode(kT0HostName, kT0Qtype,
3192 dns_protocol::kRcodeNOERROR | dns_protocol::kFlagTC);
3193 AddQueryAndRcode(kT0HostName, kT0Qtype, dns_protocol::kRcodeSERVFAIL, ASYNC,
3194 Transport::TCP);
3195
3196 TransactionHelper helper0(ERR_DNS_SERVER_FAILED);
3197 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
3198 false /* secure */, resolve_context_.get());
3199 helper0.RunUntilComplete();
3200 ASSERT_NE(helper0.response(), nullptr);
3201 EXPECT_EQ(helper0.response()->rcode(), dns_protocol::kRcodeSERVFAIL);
3202 }
3203
TEST_F(DnsTransactionTest,TCPMalformed)3204 TEST_F(DnsTransactionTest, TCPMalformed) {
3205 AddAsyncQueryAndRcode(kT0HostName, kT0Qtype,
3206 dns_protocol::kRcodeNOERROR | dns_protocol::kFlagTC);
3207 auto data = std::make_unique<DnsSocketData>(0 /* id */, kT0HostName, kT0Qtype,
3208 ASYNC, Transport::TCP);
3209 // Valid response but length too short.
3210 // This must be truncated in the question section. The DnsResponse doesn't
3211 // examine the answer section until asked to parse it, so truncating it in
3212 // the answer section would result in the DnsTransaction itself succeeding.
3213 data->AddResponseWithLength(
3214 std::make_unique<DnsResponse>(
3215 reinterpret_cast<const char*>(kT0ResponseDatagram),
3216 std::size(kT0ResponseDatagram), 0),
3217 ASYNC, static_cast<uint16_t>(kT0QuerySize - 1));
3218 AddSocketData(std::move(data));
3219
3220 TransactionHelper helper0(ERR_DNS_MALFORMED_RESPONSE);
3221 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
3222 false /* secure */, resolve_context_.get());
3223 helper0.RunUntilComplete();
3224 }
3225
TEST_F(DnsTransactionTestWithMockTime,TcpTimeout_UdpRetry)3226 TEST_F(DnsTransactionTestWithMockTime, TcpTimeout_UdpRetry) {
3227 ConfigureFactory();
3228 AddAsyncQueryAndRcode(kT0HostName, kT0Qtype,
3229 dns_protocol::kRcodeNOERROR | dns_protocol::kFlagTC);
3230 AddSocketData(std::make_unique<DnsSocketData>(
3231 1 /* id */, kT0HostName, kT0Qtype, ASYNC, Transport::TCP));
3232
3233 TransactionHelper helper0(ERR_DNS_TIMED_OUT);
3234 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
3235 false /* secure */, resolve_context_.get());
3236 base::RunLoop().RunUntilIdle();
3237 EXPECT_FALSE(helper0.has_completed());
3238 FastForwardUntilNoTasksRemain();
3239 EXPECT_TRUE(helper0.has_completed());
3240 }
3241
TEST_F(DnsTransactionTestWithMockTime,TcpTimeout_LowEntropy)3242 TEST_F(DnsTransactionTestWithMockTime, TcpTimeout_LowEntropy) {
3243 ConfigureFactory();
3244 socket_factory_->diverse_source_ports_ = false;
3245
3246 for (int i = 0; i <= DnsUdpTracker::kPortReuseThreshold; ++i) {
3247 AddQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype, kT0ResponseDatagram,
3248 std::size(kT0ResponseDatagram), ASYNC, Transport::UDP);
3249 }
3250
3251 AddSocketData(std::make_unique<DnsSocketData>(
3252 1 /* id */, kT0HostName, kT0Qtype, ASYNC, Transport::TCP));
3253
3254 for (int i = 0; i <= DnsUdpTracker::kPortReuseThreshold; ++i) {
3255 TransactionHelper udp_helper(kT0RecordCount);
3256 udp_helper.StartTransaction(transaction_factory_.get(), kT0HostName,
3257 kT0Qtype, false /* secure */,
3258 resolve_context_.get());
3259 udp_helper.RunUntilComplete();
3260 }
3261
3262 ASSERT_TRUE(session_->udp_tracker()->low_entropy());
3263
3264 TransactionHelper helper0(ERR_DNS_TIMED_OUT);
3265 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
3266 false /* secure */, resolve_context_.get());
3267 base::RunLoop().RunUntilIdle();
3268 EXPECT_FALSE(helper0.has_completed());
3269 FastForwardUntilNoTasksRemain();
3270 EXPECT_TRUE(helper0.has_completed());
3271 }
3272
TEST_F(DnsTransactionTest,TCPReadReturnsZeroAsync)3273 TEST_F(DnsTransactionTest, TCPReadReturnsZeroAsync) {
3274 AddAsyncQueryAndRcode(kT0HostName, kT0Qtype,
3275 dns_protocol::kRcodeNOERROR | dns_protocol::kFlagTC);
3276 auto data = std::make_unique<DnsSocketData>(0 /* id */, kT0HostName, kT0Qtype,
3277 ASYNC, Transport::TCP);
3278 // Return all but the last byte of the response.
3279 data->AddResponseWithLength(
3280 std::make_unique<DnsResponse>(
3281 reinterpret_cast<const char*>(kT0ResponseDatagram),
3282 std::size(kT0ResponseDatagram) - 1, 0),
3283 ASYNC, static_cast<uint16_t>(std::size(kT0ResponseDatagram)));
3284 // Then return a 0-length read.
3285 data->AddReadError(0, ASYNC);
3286 AddSocketData(std::move(data));
3287
3288 TransactionHelper helper0(ERR_CONNECTION_CLOSED);
3289 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
3290 false /* secure */, resolve_context_.get());
3291 helper0.RunUntilComplete();
3292 }
3293
TEST_F(DnsTransactionTest,TCPReadReturnsZeroSynchronous)3294 TEST_F(DnsTransactionTest, TCPReadReturnsZeroSynchronous) {
3295 AddAsyncQueryAndRcode(kT0HostName, kT0Qtype,
3296 dns_protocol::kRcodeNOERROR | dns_protocol::kFlagTC);
3297 auto data = std::make_unique<DnsSocketData>(0 /* id */, kT0HostName, kT0Qtype,
3298 ASYNC, Transport::TCP);
3299 // Return all but the last byte of the response.
3300 data->AddResponseWithLength(
3301 std::make_unique<DnsResponse>(
3302 reinterpret_cast<const char*>(kT0ResponseDatagram),
3303 std::size(kT0ResponseDatagram) - 1, 0),
3304 SYNCHRONOUS, static_cast<uint16_t>(std::size(kT0ResponseDatagram)));
3305 // Then return a 0-length read.
3306 data->AddReadError(0, SYNCHRONOUS);
3307 AddSocketData(std::move(data));
3308
3309 TransactionHelper helper0(ERR_CONNECTION_CLOSED);
3310 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
3311 false /* secure */, resolve_context_.get());
3312 helper0.RunUntilComplete();
3313 }
3314
TEST_F(DnsTransactionTest,TCPConnectionClosedAsync)3315 TEST_F(DnsTransactionTest, TCPConnectionClosedAsync) {
3316 AddAsyncQueryAndRcode(kT0HostName, kT0Qtype,
3317 dns_protocol::kRcodeNOERROR | dns_protocol::kFlagTC);
3318 auto data = std::make_unique<DnsSocketData>(0 /* id */, kT0HostName, kT0Qtype,
3319 ASYNC, Transport::TCP);
3320 data->AddReadError(ERR_CONNECTION_CLOSED, ASYNC);
3321 AddSocketData(std::move(data));
3322
3323 TransactionHelper helper0(ERR_CONNECTION_CLOSED);
3324 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
3325 false /* secure */, resolve_context_.get());
3326 helper0.RunUntilComplete();
3327 }
3328
TEST_F(DnsTransactionTest,TCPConnectionClosedSynchronous)3329 TEST_F(DnsTransactionTest, TCPConnectionClosedSynchronous) {
3330 AddAsyncQueryAndRcode(kT0HostName, kT0Qtype,
3331 dns_protocol::kRcodeNOERROR | dns_protocol::kFlagTC);
3332 auto data = std::make_unique<DnsSocketData>(0 /* id */, kT0HostName, kT0Qtype,
3333 ASYNC, Transport::TCP);
3334 data->AddReadError(ERR_CONNECTION_CLOSED, SYNCHRONOUS);
3335 AddSocketData(std::move(data));
3336
3337 TransactionHelper helper0(ERR_CONNECTION_CLOSED);
3338 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
3339 false /* secure */, resolve_context_.get());
3340 helper0.RunUntilComplete();
3341 }
3342
TEST_F(DnsTransactionTest,MismatchedThenNxdomainThenTCP)3343 TEST_F(DnsTransactionTest, MismatchedThenNxdomainThenTCP) {
3344 config_.attempts = 2;
3345 ConfigureFactory();
3346 auto data = std::make_unique<DnsSocketData>(0 /* id */, kT0HostName, kT0Qtype,
3347 SYNCHRONOUS, Transport::UDP);
3348 // First attempt gets a mismatched response.
3349 data->AddResponseData(kT1ResponseDatagram, std::size(kT1ResponseDatagram),
3350 SYNCHRONOUS);
3351 // Second read from first attempt gets TCP required.
3352 data->AddRcode(dns_protocol::kFlagTC, ASYNC);
3353 AddSocketData(std::move(data));
3354 // Second attempt gets NXDOMAIN, which happens before the TCP required.
3355 AddSyncQueryAndRcode(kT0HostName, kT0Qtype, dns_protocol::kRcodeNXDOMAIN);
3356
3357 TransactionHelper helper0(ERR_NAME_NOT_RESOLVED);
3358 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
3359 false /* secure */, resolve_context_.get());
3360 helper0.RunUntilComplete();
3361 }
3362
TEST_F(DnsTransactionTest,MismatchedThenOkThenTCP)3363 TEST_F(DnsTransactionTest, MismatchedThenOkThenTCP) {
3364 config_.attempts = 2;
3365 ConfigureFactory();
3366 auto data = std::make_unique<DnsSocketData>(0 /* id */, kT0HostName, kT0Qtype,
3367 SYNCHRONOUS, Transport::UDP);
3368 // First attempt gets a mismatched response.
3369 data->AddResponseData(kT1ResponseDatagram, std::size(kT1ResponseDatagram),
3370 SYNCHRONOUS);
3371 // Second read from first attempt gets TCP required.
3372 data->AddRcode(dns_protocol::kFlagTC, ASYNC);
3373 AddSocketData(std::move(data));
3374 // Second attempt gets a valid response, which happens before the TCP
3375 // required.
3376 AddSyncQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype,
3377 kT0ResponseDatagram, std::size(kT0ResponseDatagram));
3378
3379 TransactionHelper helper0(kT0RecordCount);
3380 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
3381 false /* secure */, resolve_context_.get());
3382 helper0.RunUntilComplete();
3383 }
3384
TEST_F(DnsTransactionTest,MismatchedThenRefusedThenTCP)3385 TEST_F(DnsTransactionTest, MismatchedThenRefusedThenTCP) {
3386 // Set up the expected sequence of events:
3387 // 1) First attempt (UDP) gets a synchronous mismatched response. On such
3388 // malformed responses, DnsTransaction triggers an immediate retry to read
3389 // again from the socket within the same "attempt".
3390 // 2) Second read (within the first attempt) starts. Test is configured to
3391 // give an asynchronous TCP required response which will complete later.
3392 // On asynchronous action after a malformed response, the attempt will
3393 // immediately produce a retriable error result while the retry continues,
3394 // thus forking the running attempts.
3395 // 3) Error result triggers a second attempt (UDP) which test gives a
3396 // synchronous ERR_CONNECTION_REFUSED, which is a retriable error, but
3397 // DnsTransaction has exhausted max retries (2 attempts), so this result
3398 // gets posted as the result of the transaction and other running attempts
3399 // should be cancelled.
3400 // 4) First attempt should be cancelled when the transaction result is posted,
3401 // so first attempt's second read should never complete. If it did
3402 // complete, it would complete with a TCP-required error, and
3403 // DnsTransaction would start a TCP attempt and clear previous attempts. It
3404 // would be very bad if that then cleared the attempt posted as the final
3405 // result, as result handling does not expect that memory to go away.
3406
3407 config_.attempts = 2;
3408 ConfigureFactory();
3409
3410 // Attempt 1.
3411 auto data = std::make_unique<DnsSocketData>(0 /* id */, kT0HostName, kT0Qtype,
3412 SYNCHRONOUS, Transport::UDP);
3413 data->AddResponseData(kT1ResponseDatagram, std::size(kT1ResponseDatagram),
3414 SYNCHRONOUS);
3415 data->AddRcode(dns_protocol::kFlagTC, ASYNC);
3416 AddSocketData(std::move(data));
3417
3418 // Attempt 2.
3419 AddQueryAndErrorResponse(0 /* id */, kT0HostName, kT0Qtype,
3420 ERR_CONNECTION_REFUSED, SYNCHRONOUS, Transport::UDP);
3421
3422 TransactionHelper helper0(ERR_CONNECTION_REFUSED);
3423 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
3424 false /* secure */, resolve_context_.get());
3425 helper0.RunUntilComplete();
3426 }
3427
TEST_F(DnsTransactionTest,InvalidQuery)3428 TEST_F(DnsTransactionTest, InvalidQuery) {
3429 ConfigureFactory();
3430
3431 TransactionHelper helper0(ERR_INVALID_ARGUMENT);
3432 helper0.StartTransaction(transaction_factory_.get(), ".",
3433 dns_protocol::kTypeA, false /* secure */,
3434 resolve_context_.get());
3435 helper0.RunUntilComplete();
3436
3437 TransactionHelper helper1(ERR_INVALID_ARGUMENT);
3438 helper1.StartTransaction(transaction_factory_.get(), "foo,bar.com",
3439 dns_protocol::kTypeA, false /* secure */,
3440 resolve_context_.get());
3441 helper1.RunUntilComplete();
3442 }
3443
TEST_F(DnsTransactionTest,CheckAsync)3444 TEST_F(DnsTransactionTest, CheckAsync) {
3445 ConfigureDohServers(false /* use_post */);
3446 AddQueryAndResponse(0, kT0HostName, kT0Qtype, kT0ResponseDatagram,
3447 std::size(kT0ResponseDatagram), SYNCHRONOUS,
3448 Transport::HTTPS, nullptr /* opt_rdata */,
3449 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
3450 false /* enqueue_transaction_id */);
3451 TransactionHelper helper0(kT0RecordCount);
3452 bool started = false;
3453 SetUrlRequestStartedCallback(
3454 base::BindLambdaForTesting([&] { started = true; }));
3455 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
3456 true /* secure */, resolve_context_.get());
3457 EXPECT_FALSE(started);
3458 EXPECT_FALSE(helper0.has_completed());
3459 helper0.RunUntilComplete();
3460 EXPECT_TRUE(started);
3461 }
3462
TEST_F(DnsTransactionTest,EarlyCancel)3463 TEST_F(DnsTransactionTest, EarlyCancel) {
3464 ConfigureDohServers(false /* use_post */);
3465 TransactionHelper helper0(0);
3466 SetUrlRequestStartedCallback(base::BindRepeating([] { FAIL(); }));
3467 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
3468 true /* secure */, resolve_context_.get());
3469 EXPECT_FALSE(helper0.has_completed());
3470 helper0.Cancel();
3471 base::RunLoop().RunUntilIdle();
3472 }
3473
TEST_F(DnsTransactionTestWithMockTime,ProbeUntilSuccess)3474 TEST_F(DnsTransactionTestWithMockTime, ProbeUntilSuccess) {
3475 ConfigureDohServers(true /* use_post */, 1 /* num_doh_servers */,
3476 false /* make_available */);
3477 AddQueryAndErrorResponse(0 /* id */, kT4HostName, kT4Qtype,
3478 ERR_CONNECTION_REFUSED, SYNCHRONOUS,
3479 Transport::HTTPS, nullptr /* opt_rdata */,
3480 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
3481 false /* enqueue_transaction_id */);
3482 AddQueryAndErrorResponse(0 /* id */, kT4HostName, kT4Qtype,
3483 ERR_CONNECTION_REFUSED, SYNCHRONOUS,
3484 Transport::HTTPS, nullptr /* opt_rdata */,
3485 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
3486 false /* enqueue_transaction_id */);
3487 AddQueryAndResponse(0 /* id */, kT4HostName, kT4Qtype, kT4ResponseDatagram,
3488 std::size(kT4ResponseDatagram), ASYNC, Transport::HTTPS,
3489 nullptr /* opt_rdata */,
3490 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
3491 false /* enqueue_transaction_id */);
3492
3493 std::unique_ptr<DnsProbeRunner> runner =
3494 transaction_factory_->CreateDohProbeRunner(resolve_context_.get());
3495 runner->Start(false /* network_change */);
3496
3497 // The first probe happens without any delay.
3498 RunUntilIdle();
3499 std::unique_ptr<DnsServerIterator> doh_itr = resolve_context_->GetDohIterator(
3500 session_->config(), SecureDnsMode::kAutomatic, session_.get());
3501
3502 EXPECT_FALSE(doh_itr->AttemptAvailable());
3503
3504 // Expect the server to still be unavailable after the second probe.
3505 FastForwardBy(runner->GetDelayUntilNextProbeForTest(0));
3506 EXPECT_FALSE(doh_itr->AttemptAvailable());
3507
3508 // Expect the server to be available after the successful third probe.
3509 FastForwardBy(runner->GetDelayUntilNextProbeForTest(0));
3510 ASSERT_TRUE(doh_itr->AttemptAvailable());
3511 EXPECT_EQ(doh_itr->GetNextAttemptIndex(), 0u);
3512 }
3513
TEST_F(DnsTransactionTestWithMockTime,ProbeCreationTriggersSuccessMetric)3514 TEST_F(DnsTransactionTestWithMockTime, ProbeCreationTriggersSuccessMetric) {
3515 ConfigureDohServers(/*use_post=*/true, /*num_doh_servers=*/1,
3516 /*make_available=*/false);
3517 AddQueryAndResponse(/*id=*/0, kT4HostName, kT4Qtype, kT4ResponseDatagram,
3518 std::size(kT4ResponseDatagram), ASYNC, Transport::HTTPS,
3519 /*opt_rdata=*/nullptr,
3520 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
3521 /*enqueue_transaction_id=*/false);
3522
3523 // The metric timer should not have started yet.
3524 EXPECT_FALSE(
3525 resolve_context_->doh_autoupgrade_metrics_timer_is_running_for_testing());
3526
3527 std::unique_ptr<DnsProbeRunner> runner =
3528 transaction_factory_->CreateDohProbeRunner(resolve_context_.get());
3529 runner->Start(/*network_change=*/false);
3530
3531 // Ensure that calling `CreateDohProbeRunner()` causes metrics to be emitted
3532 // after the timeout.
3533 EXPECT_TRUE(
3534 resolve_context_->doh_autoupgrade_metrics_timer_is_running_for_testing());
3535
3536 // Fast-forward by enough time for the timer to trigger. Add one millisecond
3537 // just to make it clear that afterwards the timeout should definitely have
3538 // occurred (although this may not be strictly necessary).
3539 FastForwardBy(ResolveContext::kDohAutoupgradeSuccessMetricTimeout +
3540 base::Milliseconds(1));
3541
3542 EXPECT_FALSE(
3543 resolve_context_->doh_autoupgrade_metrics_timer_is_running_for_testing());
3544 }
3545
3546 // Test that if a probe attempt hangs, additional probes will still run on
3547 // schedule
TEST_F(DnsTransactionTestWithMockTime,HungProbe)3548 TEST_F(DnsTransactionTestWithMockTime, HungProbe) {
3549 ConfigureDohServers(true /* use_post */, 1 /* num_doh_servers */,
3550 false /* make_available */);
3551
3552 // Create a socket data to first return ERR_IO_PENDING. This will pause the
3553 // probe and not return the error until SequencedSocketData::Resume() is
3554 // called.
3555 auto data = std::make_unique<DnsSocketData>(
3556 0 /* id */, kT4HostName, kT4Qtype, ASYNC, Transport::HTTPS,
3557 nullptr /* opt_rdata */, DnsQuery::PaddingStrategy::BLOCK_LENGTH_128);
3558 data->AddReadError(ERR_IO_PENDING, ASYNC);
3559 data->AddReadError(ERR_CONNECTION_REFUSED, ASYNC);
3560 data->AddResponseData(kT4ResponseDatagram, std::size(kT4ResponseDatagram),
3561 ASYNC);
3562 SequencedSocketData* sequenced_socket_data = data->GetProvider();
3563 AddSocketData(std::move(data), false /* enqueue_transaction_id */);
3564
3565 // Add success for second probe.
3566 AddQueryAndResponse(0 /* id */, kT4HostName, kT4Qtype, kT4ResponseDatagram,
3567 std::size(kT4ResponseDatagram), ASYNC, Transport::HTTPS,
3568 nullptr /* opt_rdata */,
3569 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
3570 false /* enqueue_transaction_id */);
3571
3572 std::unique_ptr<DnsProbeRunner> runner =
3573 transaction_factory_->CreateDohProbeRunner(resolve_context_.get());
3574 runner->Start(false /* network_change */);
3575
3576 // The first probe starts without any delay, but doesn't finish.
3577 RunUntilIdle();
3578 EXPECT_FALSE(resolve_context_->GetDohServerAvailability(
3579 0u /* doh_server_index */, session_.get()));
3580
3581 // Second probe succeeds.
3582 FastForwardBy(runner->GetDelayUntilNextProbeForTest(0));
3583 EXPECT_TRUE(resolve_context_->GetDohServerAvailability(
3584 0u /* doh_server_index */, session_.get()));
3585
3586 // Probe runner self-cancels on next cycle.
3587 FastForwardBy(runner->GetDelayUntilNextProbeForTest(0));
3588 EXPECT_EQ(runner->GetDelayUntilNextProbeForTest(0), base::TimeDelta());
3589
3590 // Expect no effect when the hung probe wakes up and fails.
3591 sequenced_socket_data->Resume();
3592 RunUntilIdle();
3593 EXPECT_TRUE(resolve_context_->GetDohServerAvailability(
3594 0u /* doh_server_index */, session_.get()));
3595 EXPECT_EQ(runner->GetDelayUntilNextProbeForTest(0), base::TimeDelta());
3596 }
3597
TEST_F(DnsTransactionTestWithMockTime,ProbeMultipleServers)3598 TEST_F(DnsTransactionTestWithMockTime, ProbeMultipleServers) {
3599 ConfigureDohServers(true /* use_post */, 2 /* num_doh_servers */,
3600 false /* make_available */);
3601 AddQueryAndResponse(0 /* id */, kT4HostName, kT4Qtype, kT4ResponseDatagram,
3602 std::size(kT4ResponseDatagram), ASYNC, Transport::HTTPS,
3603 nullptr /* opt_rdata */,
3604 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
3605 false /* enqueue_transaction_id */);
3606 AddQueryAndErrorResponse(0 /* id */, kT4HostName, kT4Qtype,
3607 ERR_CONNECTION_REFUSED, SYNCHRONOUS,
3608 Transport::HTTPS, nullptr /* opt_rdata */,
3609 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
3610 false /* enqueue_transaction_id */);
3611 AddQueryAndResponse(0 /* id */, kT4HostName, kT4Qtype, kT4ResponseDatagram,
3612 std::size(kT4ResponseDatagram), ASYNC, Transport::HTTPS,
3613 nullptr /* opt_rdata */,
3614 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
3615 false /* enqueue_transaction_id */);
3616
3617 ASSERT_FALSE(resolve_context_->GetDohServerAvailability(
3618 0u /* doh_server_index */, session_.get()));
3619 ASSERT_FALSE(resolve_context_->GetDohServerAvailability(
3620 1u /* doh_server_index */, session_.get()));
3621
3622 std::unique_ptr<DnsProbeRunner> runner =
3623 transaction_factory_->CreateDohProbeRunner(resolve_context_.get());
3624 runner->Start(true /* network_change */);
3625
3626 // The first probes happens without any delay and succeeds for only one server
3627 RunUntilIdle();
3628 EXPECT_TRUE(resolve_context_->GetDohServerAvailability(
3629 0u /* doh_server_index */, session_.get()));
3630 EXPECT_FALSE(resolve_context_->GetDohServerAvailability(
3631 1u /* doh_server_index */, session_.get()));
3632
3633 // On second round of probing, probes for first server should self-cancel and
3634 // second server should become available.
3635 FastForwardBy(
3636 runner->GetDelayUntilNextProbeForTest(0u /* doh_server_index */));
3637 EXPECT_EQ(runner->GetDelayUntilNextProbeForTest(0u /* doh_server_index */),
3638 base::TimeDelta());
3639 FastForwardBy(
3640 runner->GetDelayUntilNextProbeForTest(1u /* doh_server_index */));
3641 EXPECT_TRUE(resolve_context_->GetDohServerAvailability(
3642 1u /* doh_server_index */, session_.get()));
3643
3644 // Expect server 2 probes to self-cancel on next cycle.
3645 FastForwardBy(runner->GetDelayUntilNextProbeForTest(1u));
3646 EXPECT_EQ(runner->GetDelayUntilNextProbeForTest(1u), base::TimeDelta());
3647 }
3648
TEST_F(DnsTransactionTestWithMockTime,MultipleProbeRunners)3649 TEST_F(DnsTransactionTestWithMockTime, MultipleProbeRunners) {
3650 ConfigureDohServers(true /* use_post */, 1 /* num_doh_servers */,
3651 false /* make_available */);
3652 AddQueryAndResponse(0 /* id */, kT4HostName, kT4Qtype, kT4ResponseDatagram,
3653 std::size(kT4ResponseDatagram), ASYNC, Transport::HTTPS,
3654 nullptr /* opt_rdata */,
3655 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
3656 false /* enqueue_transaction_id */);
3657 AddQueryAndResponse(0 /* id */, kT4HostName, kT4Qtype, kT4ResponseDatagram,
3658 std::size(kT4ResponseDatagram), ASYNC, Transport::HTTPS,
3659 nullptr /* opt_rdata */,
3660 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
3661 false /* enqueue_transaction_id */);
3662
3663 std::unique_ptr<DnsProbeRunner> runner1 =
3664 transaction_factory_->CreateDohProbeRunner(resolve_context_.get());
3665 std::unique_ptr<DnsProbeRunner> runner2 =
3666 transaction_factory_->CreateDohProbeRunner(resolve_context_.get());
3667 runner1->Start(true /* network_change */);
3668 runner2->Start(true /* network_change */);
3669
3670 // The first two probes (one for each runner) happen without any delay
3671 // and mark the first server good.
3672 RunUntilIdle();
3673 {
3674 std::unique_ptr<DnsServerIterator> doh_itr =
3675 resolve_context_->GetDohIterator(
3676 session_->config(), SecureDnsMode::kAutomatic, session_.get());
3677
3678 ASSERT_TRUE(doh_itr->AttemptAvailable());
3679 EXPECT_EQ(doh_itr->GetNextAttemptIndex(), 0u);
3680 }
3681
3682 // Both probes expected to self-cancel on next scheduled run.
3683 FastForwardBy(runner1->GetDelayUntilNextProbeForTest(0));
3684 FastForwardBy(runner2->GetDelayUntilNextProbeForTest(0));
3685 EXPECT_EQ(runner1->GetDelayUntilNextProbeForTest(0), base::TimeDelta());
3686 EXPECT_EQ(runner2->GetDelayUntilNextProbeForTest(0), base::TimeDelta());
3687 }
3688
TEST_F(DnsTransactionTestWithMockTime,MultipleProbeRunners_SeparateContexts)3689 TEST_F(DnsTransactionTestWithMockTime, MultipleProbeRunners_SeparateContexts) {
3690 // Each RequestContext uses its own transient IsolationInfo. Since there's
3691 // typically only one RequestContext per URLRequestContext, there's no
3692 // advantage in using the same IsolationInfo across RequestContexts.
3693 set_expect_multiple_isolation_infos(true);
3694
3695 ConfigureDohServers(true /* use_post */, 1 /* num_doh_servers */,
3696 false /* make_available */);
3697 AddQueryAndResponse(0 /* id */, kT4HostName, kT4Qtype, kT4ResponseDatagram,
3698 std::size(kT4ResponseDatagram), ASYNC, Transport::HTTPS,
3699 nullptr /* opt_rdata */,
3700 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
3701 false /* enqueue_transaction_id */);
3702 AddQueryAndErrorResponse(0 /* id */, kT4HostName, kT4Qtype,
3703 ERR_CONNECTION_REFUSED, SYNCHRONOUS,
3704 Transport::HTTPS, nullptr /* opt_rdata */,
3705 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
3706 false /* enqueue_transaction_id */);
3707 AddQueryAndResponse(0 /* id */, kT4HostName, kT4Qtype, kT4ResponseDatagram,
3708 std::size(kT4ResponseDatagram), ASYNC, Transport::HTTPS,
3709 nullptr /* opt_rdata */,
3710 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
3711 false /* enqueue_transaction_id */);
3712
3713 auto request_context2 = CreateTestURLRequestContextBuilder()->Build();
3714 ResolveContext context2(request_context2.get(), false /* enable_caching */);
3715 context2.InvalidateCachesAndPerSessionData(session_.get(),
3716 false /* network_change */);
3717
3718 std::unique_ptr<DnsProbeRunner> runner1 =
3719 transaction_factory_->CreateDohProbeRunner(resolve_context_.get());
3720 std::unique_ptr<DnsProbeRunner> runner2 =
3721 transaction_factory_->CreateDohProbeRunner(&context2);
3722 runner1->Start(false /* network_change */);
3723 runner2->Start(false /* network_change */);
3724
3725 // The first two probes (one for each runner) happen without any delay.
3726 // Probe for first context succeeds and second fails.
3727 RunUntilIdle();
3728 {
3729 std::unique_ptr<DnsServerIterator> doh_itr =
3730 resolve_context_->GetDohIterator(
3731 session_->config(), SecureDnsMode::kAutomatic, session_.get());
3732
3733 ASSERT_TRUE(doh_itr->AttemptAvailable());
3734 EXPECT_EQ(doh_itr->GetNextAttemptIndex(), 0u);
3735 }
3736 {
3737 std::unique_ptr<DnsServerIterator> doh_itr2 = context2.GetDohIterator(
3738 session_->config(), SecureDnsMode::kAutomatic, session_.get());
3739
3740 EXPECT_FALSE(doh_itr2->AttemptAvailable());
3741 }
3742
3743 // First probe runner expected to be compete and self-cancel on next run.
3744 FastForwardBy(runner1->GetDelayUntilNextProbeForTest(0));
3745 EXPECT_EQ(runner1->GetDelayUntilNextProbeForTest(0), base::TimeDelta());
3746
3747 // Expect second runner to succeed on its second probe.
3748 FastForwardBy(runner2->GetDelayUntilNextProbeForTest(0));
3749 {
3750 std::unique_ptr<DnsServerIterator> doh_itr2 = context2.GetDohIterator(
3751 session_->config(), SecureDnsMode::kAutomatic, session_.get());
3752
3753 ASSERT_TRUE(doh_itr2->AttemptAvailable());
3754 EXPECT_EQ(doh_itr2->GetNextAttemptIndex(), 0u);
3755 }
3756 FastForwardBy(runner2->GetDelayUntilNextProbeForTest(0));
3757 EXPECT_EQ(runner2->GetDelayUntilNextProbeForTest(0), base::TimeDelta());
3758 }
3759
TEST_F(DnsTransactionTestWithMockTime,CancelDohProbeOnDestruction)3760 TEST_F(DnsTransactionTestWithMockTime, CancelDohProbeOnDestruction) {
3761 ConfigureDohServers(/*use_post=*/true, /*num_doh_servers=*/1,
3762 /*make_available=*/false);
3763 AddQueryAndErrorResponse(/*id=*/0, kT4HostName, kT4Qtype,
3764 ERR_CONNECTION_REFUSED, SYNCHRONOUS,
3765 Transport::HTTPS, /*opt_rdata=*/nullptr,
3766 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
3767 /*enqueue_transaction_id=*/false);
3768 AddQueryAndErrorResponse(/*id=*/0, kT4HostName, kT4Qtype,
3769 ERR_CONNECTION_REFUSED, SYNCHRONOUS,
3770 Transport::HTTPS, /*opt_rdata=*/nullptr,
3771 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
3772 /* enqueue_transaction_id=*/false);
3773
3774 std::unique_ptr<DnsProbeRunner> runner =
3775 transaction_factory_->CreateDohProbeRunner(resolve_context_.get());
3776 runner->Start(/*network_change=*/false);
3777
3778 // The first probe happens without any delay.
3779 RunUntilIdle();
3780 std::unique_ptr<DnsServerIterator> doh_itr = resolve_context_->GetDohIterator(
3781 session_->config(), SecureDnsMode::kAutomatic, session_.get());
3782
3783 EXPECT_FALSE(doh_itr->AttemptAvailable());
3784
3785 // Expect the server to still be unavailable after the second probe.
3786 FastForwardBy(runner->GetDelayUntilNextProbeForTest(0));
3787
3788 EXPECT_FALSE(doh_itr->AttemptAvailable());
3789
3790 base::TimeDelta next_delay = runner->GetDelayUntilNextProbeForTest(0);
3791 runner.reset();
3792
3793 // Server stays unavailable because probe canceled before (non-existent)
3794 // success. No success result is added, so this FastForward will cause a
3795 // failure if probes attempt to run.
3796 FastForwardBy(next_delay);
3797
3798 EXPECT_FALSE(doh_itr->AttemptAvailable());
3799 }
3800
TEST_F(DnsTransactionTestWithMockTime,CancelDohProbeOnContextDestruction)3801 TEST_F(DnsTransactionTestWithMockTime, CancelDohProbeOnContextDestruction) {
3802 ConfigureDohServers(/*use_post=*/true, /*num_doh_servers=*/1,
3803 /*make_available=*/false);
3804 AddQueryAndErrorResponse(/*id=*/0, kT4HostName, kT4Qtype,
3805 ERR_CONNECTION_REFUSED, SYNCHRONOUS,
3806 Transport::HTTPS, /*opt_rdata=*/nullptr,
3807 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
3808 /*enqueue_transaction_id=*/false);
3809 AddQueryAndErrorResponse(/*id=*/0, kT4HostName, kT4Qtype,
3810 ERR_CONNECTION_REFUSED, SYNCHRONOUS,
3811 Transport::HTTPS, /*opt_rdata=*/nullptr,
3812 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
3813 /* enqueue_transaction_id=*/false);
3814
3815 std::unique_ptr<DnsProbeRunner> runner =
3816 transaction_factory_->CreateDohProbeRunner(resolve_context_.get());
3817 runner->Start(/*network_change=*/false);
3818
3819 // The first probe happens without any delay.
3820 RunUntilIdle();
3821 std::unique_ptr<DnsServerIterator> doh_itr = resolve_context_->GetDohIterator(
3822 session_->config(), SecureDnsMode::kAutomatic, session_.get());
3823
3824 EXPECT_FALSE(doh_itr->AttemptAvailable());
3825
3826 // Expect the server to still be unavailable after the second probe.
3827 FastForwardBy(runner->GetDelayUntilNextProbeForTest(0));
3828
3829 EXPECT_FALSE(doh_itr->AttemptAvailable());
3830
3831 base::TimeDelta next_delay = runner->GetDelayUntilNextProbeForTest(0);
3832 resolve_context_.reset();
3833
3834 // The probe detects that the context no longer exists and stops running.
3835 FastForwardBy(next_delay);
3836
3837 // There are no more probes to run.
3838 EXPECT_EQ(base::TimeDelta(), runner->GetDelayUntilNextProbeForTest(0));
3839 }
3840
TEST_F(DnsTransactionTestWithMockTime,CancelOneOfMultipleProbeRunners)3841 TEST_F(DnsTransactionTestWithMockTime, CancelOneOfMultipleProbeRunners) {
3842 ConfigureDohServers(true /* use_post */, 1 /* num_doh_servers */,
3843 false /* make_available */);
3844 AddQueryAndErrorResponse(0 /* id */, kT4HostName, kT4Qtype,
3845 ERR_CONNECTION_REFUSED, SYNCHRONOUS,
3846 Transport::HTTPS, nullptr /* opt_rdata */,
3847 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
3848 false /* enqueue_transaction_id */);
3849 AddQueryAndErrorResponse(0 /* id */, kT4HostName, kT4Qtype,
3850 ERR_CONNECTION_REFUSED, SYNCHRONOUS,
3851 Transport::HTTPS, nullptr /* opt_rdata */,
3852 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
3853 false /* enqueue_transaction_id */);
3854 AddQueryAndResponse(0 /* id */, kT4HostName, kT4Qtype, kT4ResponseDatagram,
3855 std::size(kT4ResponseDatagram), ASYNC, Transport::HTTPS,
3856 nullptr /* opt_rdata */,
3857 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
3858 false /* enqueue_transaction_id */);
3859
3860 std::unique_ptr<DnsProbeRunner> runner1 =
3861 transaction_factory_->CreateDohProbeRunner(resolve_context_.get());
3862 std::unique_ptr<DnsProbeRunner> runner2 =
3863 transaction_factory_->CreateDohProbeRunner(resolve_context_.get());
3864 runner1->Start(true /* network_change */);
3865 runner2->Start(true /* network_change */);
3866
3867 // The first two probes (one for each runner) happen without any delay.
3868 RunUntilIdle();
3869 std::unique_ptr<DnsServerIterator> doh_itr = resolve_context_->GetDohIterator(
3870 session_->config(), SecureDnsMode::kAutomatic, session_.get());
3871
3872 EXPECT_FALSE(doh_itr->AttemptAvailable());
3873 EXPECT_GT(runner1->GetDelayUntilNextProbeForTest(0), base::TimeDelta());
3874 EXPECT_GT(runner2->GetDelayUntilNextProbeForTest(0), base::TimeDelta());
3875
3876 // Cancel only one probe runner.
3877 runner1.reset();
3878
3879 // Expect the server to be available after the successful third probe.
3880 FastForwardBy(runner2->GetDelayUntilNextProbeForTest(0));
3881
3882 ASSERT_TRUE(doh_itr->AttemptAvailable());
3883 EXPECT_EQ(doh_itr->GetNextAttemptIndex(), 0u);
3884 FastForwardBy(runner2->GetDelayUntilNextProbeForTest(0));
3885 EXPECT_EQ(runner2->GetDelayUntilNextProbeForTest(0), base::TimeDelta());
3886 }
3887
TEST_F(DnsTransactionTestWithMockTime,CancelAllOfMultipleProbeRunners)3888 TEST_F(DnsTransactionTestWithMockTime, CancelAllOfMultipleProbeRunners) {
3889 ConfigureDohServers(true /* use_post */, 1 /* num_doh_servers */,
3890 false /* make_available */);
3891 AddQueryAndErrorResponse(0 /* id */, kT4HostName, kT4Qtype,
3892 ERR_CONNECTION_REFUSED, SYNCHRONOUS,
3893 Transport::HTTPS, nullptr /* opt_rdata */,
3894 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
3895 false /* enqueue_transaction_id */);
3896 AddQueryAndErrorResponse(0 /* id */, kT4HostName, kT4Qtype,
3897 ERR_CONNECTION_REFUSED, SYNCHRONOUS,
3898 Transport::HTTPS, nullptr /* opt_rdata */,
3899 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
3900 false /* enqueue_transaction_id */);
3901
3902 std::unique_ptr<DnsProbeRunner> runner1 =
3903 transaction_factory_->CreateDohProbeRunner(resolve_context_.get());
3904 std::unique_ptr<DnsProbeRunner> runner2 =
3905 transaction_factory_->CreateDohProbeRunner(resolve_context_.get());
3906 runner1->Start(false /* network_change */);
3907 runner2->Start(false /* network_change */);
3908
3909 // The first two probes (one for each runner) happen without any delay.
3910 RunUntilIdle();
3911 std::unique_ptr<DnsServerIterator> doh_itr = resolve_context_->GetDohIterator(
3912 session_->config(), SecureDnsMode::kAutomatic, session_.get());
3913
3914 EXPECT_FALSE(doh_itr->AttemptAvailable());
3915 EXPECT_GT(runner1->GetDelayUntilNextProbeForTest(0), base::TimeDelta());
3916 EXPECT_GT(runner2->GetDelayUntilNextProbeForTest(0), base::TimeDelta());
3917
3918 base::TimeDelta next_delay = runner1->GetDelayUntilNextProbeForTest(0);
3919 runner1.reset();
3920 runner2.reset();
3921
3922 // Server stays unavailable because probe canceled before (non-existent)
3923 // success. No success result is added, so this FastForward will cause a
3924 // failure if probes attempt to run.
3925 FastForwardBy(next_delay);
3926 EXPECT_FALSE(doh_itr->AttemptAvailable());
3927 }
3928
TEST_F(DnsTransactionTestWithMockTime,CancelDohProbe_AfterSuccess)3929 TEST_F(DnsTransactionTestWithMockTime, CancelDohProbe_AfterSuccess) {
3930 ConfigureDohServers(true /* use_post */, 1 /* num_doh_servers */,
3931 false /* make_available */);
3932 AddQueryAndResponse(0 /* id */, kT4HostName, kT4Qtype, kT4ResponseDatagram,
3933 std::size(kT4ResponseDatagram), SYNCHRONOUS,
3934 Transport::HTTPS, nullptr /* opt_rdata */,
3935 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
3936 false /* enqueue_transaction_id */);
3937
3938 std::unique_ptr<DnsProbeRunner> runner =
3939 transaction_factory_->CreateDohProbeRunner(resolve_context_.get());
3940 runner->Start(true /* network_change */);
3941
3942 // The first probe happens without any delay, and immediately succeeds.
3943 RunUntilIdle();
3944 {
3945 std::unique_ptr<DnsServerIterator> doh_itr =
3946 resolve_context_->GetDohIterator(
3947 session_->config(), SecureDnsMode::kAutomatic, session_.get());
3948
3949 ASSERT_TRUE(doh_itr->AttemptAvailable());
3950 EXPECT_EQ(doh_itr->GetNextAttemptIndex(), 0u);
3951 }
3952
3953 runner.reset();
3954
3955 // No change expected after cancellation.
3956 RunUntilIdle();
3957 {
3958 std::unique_ptr<DnsServerIterator> doh_itr =
3959 resolve_context_->GetDohIterator(
3960 session_->config(), SecureDnsMode::kAutomatic, session_.get());
3961
3962 ASSERT_TRUE(doh_itr->AttemptAvailable());
3963 EXPECT_EQ(doh_itr->GetNextAttemptIndex(), 0u);
3964 }
3965 }
3966
TEST_F(DnsTransactionTestWithMockTime,DestroyFactoryAfterStartingDohProbe)3967 TEST_F(DnsTransactionTestWithMockTime, DestroyFactoryAfterStartingDohProbe) {
3968 ConfigureDohServers(true /* use_post */, 1 /* num_doh_servers */,
3969 false /* make_available */);
3970 AddQueryAndErrorResponse(0 /* id */, kT4HostName, kT4Qtype,
3971 ERR_CONNECTION_REFUSED, SYNCHRONOUS,
3972 Transport::HTTPS, nullptr /* opt_rdata */,
3973 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
3974 false /* enqueue_transaction_id */);
3975
3976 std::unique_ptr<DnsProbeRunner> runner =
3977 transaction_factory_->CreateDohProbeRunner(resolve_context_.get());
3978 runner->Start(false /* network_change */);
3979
3980 // The first probe happens without any delay.
3981 RunUntilIdle();
3982 std::unique_ptr<DnsServerIterator> doh_itr = resolve_context_->GetDohIterator(
3983 session_->config(), SecureDnsMode::kAutomatic, session_.get());
3984
3985 EXPECT_FALSE(doh_itr->AttemptAvailable());
3986
3987 // Destroy factory and session.
3988 transaction_factory_.reset();
3989 ASSERT_TRUE(session_->HasOneRef());
3990 session_.reset();
3991
3992 // Probe should not encounter issues and should stop running.
3993 FastForwardBy(runner->GetDelayUntilNextProbeForTest(0));
3994 EXPECT_EQ(runner->GetDelayUntilNextProbeForTest(0), base::TimeDelta());
3995 }
3996
TEST_F(DnsTransactionTestWithMockTime,StartWhileRunning)3997 TEST_F(DnsTransactionTestWithMockTime, StartWhileRunning) {
3998 ConfigureDohServers(true /* use_post */, 1 /* num_doh_servers */,
3999 false /* make_available */);
4000 AddQueryAndErrorResponse(0 /* id */, kT4HostName, kT4Qtype,
4001 ERR_CONNECTION_REFUSED, SYNCHRONOUS,
4002 Transport::HTTPS, nullptr /* opt_rdata */,
4003 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
4004 false /* enqueue_transaction_id */);
4005 AddQueryAndResponse(0 /* id */, kT4HostName, kT4Qtype, kT4ResponseDatagram,
4006 std::size(kT4ResponseDatagram), ASYNC, Transport::HTTPS,
4007 nullptr /* opt_rdata */,
4008 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
4009 false /* enqueue_transaction_id */);
4010
4011 std::unique_ptr<DnsProbeRunner> runner =
4012 transaction_factory_->CreateDohProbeRunner(resolve_context_.get());
4013 runner->Start(false /* network_change */);
4014
4015 // The first probe happens without any delay.
4016 RunUntilIdle();
4017 EXPECT_FALSE(resolve_context_->GetDohServerAvailability(
4018 0u /* doh_server_index */, session_.get()));
4019
4020 // Extra Start() call should have no effect because runner is already running.
4021 runner->Start(true /* network_change */);
4022 RunUntilIdle();
4023 EXPECT_FALSE(resolve_context_->GetDohServerAvailability(
4024 0u /* doh_server_index */, session_.get()));
4025
4026 // Expect the server to be available after the successful second probe.
4027 FastForwardBy(runner->GetDelayUntilNextProbeForTest(0));
4028 EXPECT_TRUE(resolve_context_->GetDohServerAvailability(
4029 0u /* doh_server_index */, session_.get()));
4030 }
4031
TEST_F(DnsTransactionTestWithMockTime,RestartFinishedProbe)4032 TEST_F(DnsTransactionTestWithMockTime, RestartFinishedProbe) {
4033 ConfigureDohServers(true /* use_post */, 1 /* num_doh_servers */,
4034 false /* make_available */);
4035 AddQueryAndResponse(0 /* id */, kT4HostName, kT4Qtype, kT4ResponseDatagram,
4036 std::size(kT4ResponseDatagram), ASYNC, Transport::HTTPS,
4037 nullptr /* opt_rdata */,
4038 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
4039 false /* enqueue_transaction_id */);
4040 AddQueryAndResponse(0 /* id */, kT4HostName, kT4Qtype, kT4ResponseDatagram,
4041 std::size(kT4ResponseDatagram), ASYNC, Transport::HTTPS,
4042 nullptr /* opt_rdata */,
4043 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
4044 false /* enqueue_transaction_id */);
4045
4046 std::unique_ptr<DnsProbeRunner> runner =
4047 transaction_factory_->CreateDohProbeRunner(resolve_context_.get());
4048 runner->Start(true /* network_change */);
4049
4050 // The first probe happens without any delay and succeeds.
4051 RunUntilIdle();
4052 EXPECT_TRUE(resolve_context_->GetDohServerAvailability(
4053 0u /* doh_server_index */, session_.get()));
4054
4055 // Expect runner to self-cancel on next cycle.
4056 FastForwardBy(runner->GetDelayUntilNextProbeForTest(0u));
4057 EXPECT_EQ(runner->GetDelayUntilNextProbeForTest(0u), base::TimeDelta());
4058
4059 // Mark server unavailabe and restart runner.
4060 for (int i = 0; i < ResolveContext::kAutomaticModeFailureLimit; ++i) {
4061 resolve_context_->RecordServerFailure(0u /* server_index */,
4062 true /* is_doh_server */, ERR_FAILED,
4063 session_.get());
4064 }
4065 ASSERT_FALSE(resolve_context_->GetDohServerAvailability(
4066 0u /* doh_server_index */, session_.get()));
4067 runner->Start(false /* network_change */);
4068
4069 // Expect the server to be available again after a successful immediately-run
4070 // probe.
4071 RunUntilIdle();
4072 EXPECT_TRUE(resolve_context_->GetDohServerAvailability(
4073 0u /* doh_server_index */, session_.get()));
4074
4075 // Expect self-cancel again.
4076 FastForwardBy(runner->GetDelayUntilNextProbeForTest(0u));
4077 EXPECT_EQ(runner->GetDelayUntilNextProbeForTest(0u), base::TimeDelta());
4078 }
4079
4080 // Test that a probe runner keeps running on the same schedule if it completes
4081 // but the server is marked unavailable again before the next scheduled probe.
TEST_F(DnsTransactionTestWithMockTime,FastProbeRestart)4082 TEST_F(DnsTransactionTestWithMockTime, FastProbeRestart) {
4083 ConfigureDohServers(true /* use_post */, 1 /* num_doh_servers */,
4084 false /* make_available */);
4085 AddQueryAndResponse(0 /* id */, kT4HostName, kT4Qtype, kT4ResponseDatagram,
4086 std::size(kT4ResponseDatagram), ASYNC, Transport::HTTPS,
4087 nullptr /* opt_rdata */,
4088 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
4089 false /* enqueue_transaction_id */);
4090 AddQueryAndResponse(0 /* id */, kT4HostName, kT4Qtype, kT4ResponseDatagram,
4091 std::size(kT4ResponseDatagram), ASYNC, Transport::HTTPS,
4092 nullptr /* opt_rdata */,
4093 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
4094 false /* enqueue_transaction_id */);
4095
4096 std::unique_ptr<DnsProbeRunner> runner =
4097 transaction_factory_->CreateDohProbeRunner(resolve_context_.get());
4098 runner->Start(true /* network_change */);
4099
4100 // The first probe happens without any delay and succeeds.
4101 RunUntilIdle();
4102 EXPECT_TRUE(resolve_context_->GetDohServerAvailability(
4103 0u /* doh_server_index */, session_.get()));
4104
4105 base::TimeDelta scheduled_delay = runner->GetDelayUntilNextProbeForTest(0);
4106 EXPECT_GT(scheduled_delay, base::TimeDelta());
4107
4108 // Mark server unavailabe and restart runner. Note that restarting the runner
4109 // is unnecessary, but a Start() call should always happen on a server
4110 // becoming unavailable and might as well replecate real behavior for the
4111 // test.
4112 for (int i = 0; i < ResolveContext::kAutomaticModeFailureLimit; ++i) {
4113 resolve_context_->RecordServerFailure(0u /* server_index */,
4114 true /* is_doh_server */, ERR_FAILED,
4115 session_.get());
4116 }
4117 ASSERT_FALSE(resolve_context_->GetDohServerAvailability(
4118 0u /* doh_server_index */, session_.get()));
4119 runner->Start(false /* network_change */);
4120
4121 // Probe should not run until scheduled delay.
4122 RunUntilIdle();
4123 EXPECT_FALSE(resolve_context_->GetDohServerAvailability(
4124 0u /* doh_server_index */, session_.get()));
4125
4126 // Expect the probe to run again and succeed after scheduled delay.
4127 FastForwardBy(scheduled_delay);
4128 EXPECT_TRUE(resolve_context_->GetDohServerAvailability(
4129 0u /* doh_server_index */, session_.get()));
4130 }
4131
4132 // Test that queries cannot be sent when they contain a too-long name.
4133 // Tests against incorrect name length validation, which is anti-pattern #3 from
4134 // the "NAME:WRECK" report:
4135 // https://www.forescout.com/company/resources/namewreck-breaking-and-fixing-dns-implementations/
TEST_F(DnsTransactionTestWithMockTime,RejectsQueryingLongNames)4136 TEST_F(DnsTransactionTestWithMockTime, RejectsQueryingLongNames) {
4137 std::string long_dotted_name;
4138 while (long_dotted_name.size() <= dns_protocol::kMaxNameLength) {
4139 long_dotted_name.append("naaaaaamelabel.");
4140 }
4141 long_dotted_name.append("test");
4142
4143 TransactionHelper helper0(ERR_INVALID_ARGUMENT);
4144 helper0.StartTransaction(transaction_factory_.get(), long_dotted_name.c_str(),
4145 dns_protocol::kTypeA, false /* secure */,
4146 resolve_context_.get());
4147 helper0.RunUntilComplete();
4148 }
4149
4150 // Test that ERR_CONNECTION_REFUSED error after fallback of DnsTCPAttempt
4151 // should not cause DCHECK failure (https://crbug.com/1334250).
TEST_F(DnsTransactionTestWithMockTime,TcpConnectionRefusedAfterFallback)4152 TEST_F(DnsTransactionTestWithMockTime, TcpConnectionRefusedAfterFallback) {
4153 ConfigureNumServers(2);
4154 ConfigureFactory();
4155 socket_factory_->diverse_source_ports_ = false;
4156
4157 // Data for UDP attempts to set `low_entropy` flag.
4158 for (int i = 0; i <= DnsUdpTracker::kPortReuseThreshold; ++i) {
4159 AddQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype, kT0ResponseDatagram,
4160 std::size(kT0ResponseDatagram), ASYNC, Transport::UDP);
4161 }
4162
4163 // Data for TCP attempt.
4164 auto data1 = std::make_unique<DnsSocketData>(0 /* id */, kT0HostName,
4165 kT0Qtype, ASYNC, Transport::TCP);
4166 data1->AddReadError(ERR_IO_PENDING, ASYNC);
4167 data1->AddReadError(ERR_CONNECTION_REFUSED, ASYNC);
4168 SequencedSocketData* sequenced_socket_data1 = data1->GetProvider();
4169 AddSocketData(std::move(data1));
4170
4171 auto data2 = std::make_unique<DnsSocketData>(0 /* id */, kT0HostName,
4172 kT0Qtype, ASYNC, Transport::TCP);
4173 data2->AddReadError(ERR_IO_PENDING, ASYNC);
4174 data2->AddResponseData(kT0ResponseDatagram, std::size(kT0ResponseDatagram),
4175 ASYNC);
4176 SequencedSocketData* sequenced_socket_data2 = data2->GetProvider();
4177 AddSocketData(std::move(data2));
4178
4179 // DNS transactions for UDP attempts to set `low_entropy` flag.
4180 for (int i = 0; i <= DnsUdpTracker::kPortReuseThreshold; ++i) {
4181 TransactionHelper udp_helper(kT0RecordCount);
4182 udp_helper.StartTransaction(transaction_factory_.get(), kT0HostName,
4183 kT0Qtype, false /* secure */,
4184 resolve_context_.get());
4185 udp_helper.RunUntilComplete();
4186 }
4187
4188 ASSERT_TRUE(session_->udp_tracker()->low_entropy());
4189
4190 // DNS transactions for TCP attempt.
4191 TransactionHelper helper0(kT0RecordCount);
4192 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
4193 false /* secure */, resolve_context_.get());
4194 base::RunLoop().RunUntilIdle();
4195 EXPECT_FALSE(helper0.has_completed());
4196
4197 base::TimeDelta timeout = resolve_context_->NextClassicFallbackPeriod(
4198 0 /* classic_server_index */, 0 /* attempt */, session_.get());
4199 FastForwardBy(timeout);
4200
4201 // Resume the first query.
4202 sequenced_socket_data1->Resume();
4203
4204 base::RunLoop().RunUntilIdle();
4205 EXPECT_FALSE(helper0.has_completed());
4206
4207 // Resume the second query.
4208 sequenced_socket_data2->Resume();
4209 base::RunLoop().RunUntilIdle();
4210
4211 EXPECT_TRUE(helper0.has_completed());
4212 }
4213
4214 // Test that ERR_CONNECTION_REFUSED error after fallback of DnsHTTPAttempt
4215 // should not cause DCHECK failure (https://crbug.com/1334250).
TEST_F(DnsTransactionTestWithMockTime,HttpsConnectionRefusedAfterFallback)4216 TEST_F(DnsTransactionTestWithMockTime, HttpsConnectionRefusedAfterFallback) {
4217 ConfigureDohServers(false /* use_post */, 2 /* num_doh_servers */,
4218 true /* make_available */);
4219
4220 auto data1 = std::make_unique<DnsSocketData>(
4221 0 /* id */, kT0HostName, kT0Qtype, ASYNC, Transport::HTTPS,
4222 nullptr /* opt_rdata */, DnsQuery::PaddingStrategy::BLOCK_LENGTH_128);
4223 data1->AddReadError(ERR_IO_PENDING, ASYNC);
4224 data1->AddReadError(ERR_CONNECTION_REFUSED, ASYNC);
4225 SequencedSocketData* sequenced_socket_data1 = data1->GetProvider();
4226 AddSocketData(std::move(data1), false /* enqueue_transaction_id */);
4227
4228 auto data2 = std::make_unique<DnsSocketData>(
4229 0 /* id */, kT0HostName, kT0Qtype, ASYNC, Transport::HTTPS,
4230 nullptr /* opt_rdata */, DnsQuery::PaddingStrategy::BLOCK_LENGTH_128);
4231 data2->AddReadError(ERR_IO_PENDING, ASYNC);
4232 data2->AddResponseData(kT0ResponseDatagram, std::size(kT0ResponseDatagram),
4233 ASYNC);
4234 SequencedSocketData* sequenced_socket_data2 = data2->GetProvider();
4235 AddSocketData(std::move(data2), false /* enqueue_transaction_id */);
4236
4237 TransactionHelper helper0(kT0RecordCount);
4238 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
4239 true /* secure */, resolve_context_.get());
4240 base::RunLoop().RunUntilIdle();
4241 EXPECT_FALSE(helper0.has_completed());
4242
4243 base::TimeDelta timeout = resolve_context_->NextDohFallbackPeriod(
4244 0 /* doh_server_index */, session_.get());
4245 FastForwardBy(timeout);
4246
4247 // Resume the first query.
4248 sequenced_socket_data1->Resume();
4249
4250 base::RunLoop().RunUntilIdle();
4251 EXPECT_FALSE(helper0.has_completed());
4252
4253 // Resume the second query.
4254 sequenced_socket_data2->Resume();
4255
4256 EXPECT_TRUE(helper0.has_completed());
4257 }
4258
4259 } // namespace
4260
4261 } // namespace net
4262