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 <cstdlib>
11 #include <limits>
12 #include <memory>
13 #include <optional>
14 #include <string_view>
15 #include <utility>
16 #include <vector>
17
18 #include "base/base64url.h"
19 #include "base/containers/circular_deque.h"
20 #include "base/functional/bind.h"
21 #include "base/memory/raw_ptr.h"
22 #include "base/numerics/safe_math.h"
23 #include "base/rand_util.h"
24 #include "base/ranges/algorithm.h"
25 #include "base/run_loop.h"
26 #include "base/strings/string_util.h"
27 #include "base/strings/stringprintf.h"
28 #include "base/sys_byteorder.h"
29 #include "base/task/single_thread_task_runner.h"
30 #include "base/test/bind.h"
31 #include "base/test/metrics/histogram_tester.h"
32 #include "base/time/time.h"
33 #include "base/values.h"
34 #include "net/base/idempotency.h"
35 #include "net/base/ip_address.h"
36 #include "net/base/port_util.h"
37 #include "net/base/upload_bytes_element_reader.h"
38 #include "net/base/url_util.h"
39 #include "net/cookies/cookie_access_result.h"
40 #include "net/cookies/cookie_util.h"
41 #include "net/dns/dns_config.h"
42 #include "net/dns/dns_names_util.h"
43 #include "net/dns/dns_query.h"
44 #include "net/dns/dns_response.h"
45 #include "net/dns/dns_server_iterator.h"
46 #include "net/dns/dns_session.h"
47 #include "net/dns/dns_test_util.h"
48 #include "net/dns/public/dns_over_https_config.h"
49 #include "net/dns/public/dns_over_https_server_config.h"
50 #include "net/dns/public/dns_protocol.h"
51 #include "net/dns/public/secure_dns_policy.h"
52 #include "net/dns/resolve_context.h"
53 #include "net/http/http_util.h"
54 #include "net/log/net_log.h"
55 #include "net/log/net_log_capture_mode.h"
56 #include "net/log/net_log_with_source.h"
57 #include "net/proxy_resolution/proxy_config_service_fixed.h"
58 #include "net/socket/socket_test_util.h"
59 #include "net/test/gtest_util.h"
60 #include "net/test/test_with_task_environment.h"
61 #include "net/test/url_request/url_request_failed_job.h"
62 #include "net/third_party/uri_template/uri_template.h"
63 #include "net/url_request/url_request_context.h"
64 #include "net/url_request/url_request_context_builder.h"
65 #include "net/url_request/url_request_filter.h"
66 #include "net/url_request/url_request_interceptor.h"
67 #include "net/url_request/url_request_test_util.h"
68 #include "testing/gmock/include/gmock/gmock.h"
69 #include "testing/gtest/include/gtest/gtest.h"
70
71 using net::test::IsOk;
72
73 namespace net {
74
75 namespace {
76
77 base::TimeDelta kFallbackPeriod = base::Seconds(1);
78
79 const char kMockHostname[] = "mock.http";
80
DomainFromDot(std::string_view dotted_name)81 std::vector<uint8_t> DomainFromDot(std::string_view dotted_name) {
82 std::optional<std::vector<uint8_t>> dns_name =
83 dns_names_util::DottedNameToNetwork(dotted_name);
84 CHECK(dns_name.has_value());
85 return dns_name.value();
86 }
87
88 enum class Transport { UDP, TCP, HTTPS };
89
90 class NetLogCountingObserver : public net::NetLog::ThreadSafeObserver {
91 public:
92 NetLogCountingObserver() = default;
93
~NetLogCountingObserver()94 ~NetLogCountingObserver() override {
95 if (net_log())
96 net_log()->RemoveObserver(this);
97 }
98
OnAddEntry(const NetLogEntry & entry)99 void OnAddEntry(const NetLogEntry& entry) override {
100 ++count_;
101 if (!entry.params.empty()) {
102 dict_count_++;
103 }
104 }
105
count() const106 int count() const { return count_; }
107
dict_count() const108 int dict_count() const { return dict_count_; }
109
110 private:
111 int count_ = 0;
112 int dict_count_ = 0;
113 };
114
115 // A SocketDataProvider builder.
116 class DnsSocketData {
117 public:
118 // 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)119 DnsSocketData(uint16_t id,
120 const char* dotted_name,
121 uint16_t qtype,
122 IoMode mode,
123 Transport transport,
124 const OptRecordRdata* opt_rdata = nullptr,
125 DnsQuery::PaddingStrategy padding_strategy =
126 DnsQuery::PaddingStrategy::NONE)
127 : query_(std::make_unique<DnsQuery>(id,
128 DomainFromDot(dotted_name),
129 qtype,
130 opt_rdata,
131 padding_strategy)),
132 transport_(transport) {
133 if (Transport::TCP == transport_) {
134 auto length = std::make_unique<uint16_t>();
135 *length = base::HostToNet16(query_->io_buffer()->size());
136 writes_.emplace_back(mode, reinterpret_cast<const char*>(length.get()),
137 sizeof(uint16_t), num_reads_and_writes());
138 lengths_.push_back(std::move(length));
139 }
140 writes_.emplace_back(mode, query_->io_buffer()->data(),
141 query_->io_buffer()->size(), num_reads_and_writes());
142 }
143
144 DnsSocketData(const DnsSocketData&) = delete;
145 DnsSocketData& operator=(const DnsSocketData&) = delete;
146
147 ~DnsSocketData() = default;
148
ClearWrites()149 void ClearWrites() { writes_.clear(); }
150 // All responses must be added before GetProvider.
151
152 // 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)153 void AddResponseWithLength(std::unique_ptr<DnsResponse> response,
154 IoMode mode,
155 uint16_t tcp_length) {
156 CHECK(!provider_.get());
157 if (Transport::TCP == transport_) {
158 auto length = std::make_unique<uint16_t>();
159 *length = base::HostToNet16(tcp_length);
160 reads_.emplace_back(mode, reinterpret_cast<const char*>(length.get()),
161 sizeof(uint16_t), num_reads_and_writes());
162 lengths_.push_back(std::move(length));
163 }
164 reads_.emplace_back(mode, response->io_buffer()->data(),
165 response->io_buffer_size(), num_reads_and_writes());
166 responses_.push_back(std::move(response));
167 }
168
169 // Adds pre-built DnsResponse.
AddResponse(std::unique_ptr<DnsResponse> response,IoMode mode)170 void AddResponse(std::unique_ptr<DnsResponse> response, IoMode mode) {
171 uint16_t tcp_length = response->io_buffer_size();
172 AddResponseWithLength(std::move(response), mode, tcp_length);
173 }
174
175 // Adds pre-built response from |data| buffer.
AddResponseData(const uint8_t * data,size_t length,IoMode mode)176 void AddResponseData(const uint8_t* data, size_t length, IoMode mode) {
177 CHECK(!provider_.get());
178 AddResponse(std::make_unique<DnsResponse>(
179 reinterpret_cast<const char*>(data), length, 0),
180 mode);
181 }
182
183 // Adds pre-built response from |data| buffer.
AddResponseData(const uint8_t * data,size_t length,int offset,IoMode mode)184 void AddResponseData(const uint8_t* data,
185 size_t length,
186 int offset,
187 IoMode mode) {
188 CHECK(!provider_.get());
189 AddResponse(
190 std::make_unique<DnsResponse>(reinterpret_cast<const char*>(data),
191 length - offset, offset),
192 mode);
193 }
194
195 // Add no-answer (RCODE only) response matching the query.
AddRcode(int rcode,IoMode mode)196 void AddRcode(int rcode, IoMode mode) {
197 auto response = std::make_unique<DnsResponse>(
198 query_->io_buffer()->data(), query_->io_buffer()->size(), 0);
199 dns_protocol::Header* header =
200 reinterpret_cast<dns_protocol::Header*>(response->io_buffer()->data());
201 header->flags |= base::HostToNet16(dns_protocol::kFlagResponse | rcode);
202 AddResponse(std::move(response), mode);
203 }
204
205 // Add error response.
AddReadError(int error,IoMode mode)206 void AddReadError(int error, IoMode mode) {
207 reads_.emplace_back(mode, error, num_reads_and_writes());
208 }
209
210 // Build, if needed, and return the SocketDataProvider. No new responses
211 // should be added afterwards.
GetProvider()212 SequencedSocketData* GetProvider() {
213 if (provider_.get())
214 return provider_.get();
215 // Terminate the reads with ERR_IO_PENDING to prevent overrun and default to
216 // timeout.
217 if (transport_ != Transport::HTTPS) {
218 reads_.emplace_back(SYNCHRONOUS, ERR_IO_PENDING,
219 writes_.size() + reads_.size());
220 }
221 provider_ = std::make_unique<SequencedSocketData>(reads_, writes_);
222 if (Transport::TCP == transport_ || Transport::HTTPS == transport_) {
223 provider_->set_connect_data(MockConnect(reads_[0].mode, OK));
224 }
225 return provider_.get();
226 }
227
query_id() const228 uint16_t query_id() const { return query_->id(); }
229
query_buffer()230 IOBufferWithSize* query_buffer() { return query_->io_buffer(); }
231
232 private:
num_reads_and_writes() const233 size_t num_reads_and_writes() const { return reads_.size() + writes_.size(); }
234
235 std::unique_ptr<DnsQuery> query_;
236 Transport transport_;
237 std::vector<std::unique_ptr<uint16_t>> lengths_;
238 std::vector<std::unique_ptr<DnsResponse>> responses_;
239 std::vector<MockWrite> writes_;
240 std::vector<MockRead> reads_;
241 std::unique_ptr<SequencedSocketData> provider_;
242 };
243
244 class TestSocketFactory;
245
246 // A variant of MockUDPClientSocket which always fails to Connect.
247 class FailingUDPClientSocket : public MockUDPClientSocket {
248 public:
FailingUDPClientSocket(SocketDataProvider * data,net::NetLog * net_log)249 FailingUDPClientSocket(SocketDataProvider* data, net::NetLog* net_log)
250 : MockUDPClientSocket(data, net_log) {}
251
252 FailingUDPClientSocket(const FailingUDPClientSocket&) = delete;
253 FailingUDPClientSocket& operator=(const FailingUDPClientSocket&) = delete;
254
255 ~FailingUDPClientSocket() override = default;
Connect(const IPEndPoint & endpoint)256 int Connect(const IPEndPoint& endpoint) override {
257 return ERR_CONNECTION_REFUSED;
258 }
259 };
260
261 // A variant of MockUDPClientSocket which notifies the factory OnConnect.
262 class TestUDPClientSocket : public MockUDPClientSocket {
263 public:
TestUDPClientSocket(TestSocketFactory * factory,SocketDataProvider * data,net::NetLog * net_log)264 TestUDPClientSocket(TestSocketFactory* factory,
265 SocketDataProvider* data,
266 net::NetLog* net_log)
267 : MockUDPClientSocket(data, net_log), factory_(factory) {}
268
269 TestUDPClientSocket(const TestUDPClientSocket&) = delete;
270 TestUDPClientSocket& operator=(const TestUDPClientSocket&) = delete;
271
272 ~TestUDPClientSocket() override = default;
273 int Connect(const IPEndPoint& endpoint) override;
274 int ConnectAsync(const IPEndPoint& address,
275 CompletionOnceCallback callback) override;
276
277 private:
278 raw_ptr<TestSocketFactory> factory_;
279 };
280
281 // Creates TestUDPClientSockets and keeps endpoints reported via OnConnect.
282 class TestSocketFactory : public MockClientSocketFactory {
283 public:
284 TestSocketFactory() = default;
285 ~TestSocketFactory() override = default;
286
CreateDatagramClientSocket(DatagramSocket::BindType bind_type,NetLog * net_log,const NetLogSource & source)287 std::unique_ptr<DatagramClientSocket> CreateDatagramClientSocket(
288 DatagramSocket::BindType bind_type,
289 NetLog* net_log,
290 const NetLogSource& source) override {
291 if (fail_next_socket_) {
292 fail_next_socket_ = false;
293 return std::make_unique<FailingUDPClientSocket>(&empty_data_, net_log);
294 }
295
296 SocketDataProvider* data_provider = mock_data().GetNext();
297 auto socket =
298 std::make_unique<TestUDPClientSocket>(this, data_provider, net_log);
299
300 // Even using DEFAULT_BIND, actual sockets have been measured to very rarely
301 // repeat the same source port multiple times in a row. Need to mimic that
302 // functionality here, so DnsUdpTracker doesn't misdiagnose repeated port
303 // as low entropy.
304 if (diverse_source_ports_)
305 socket->set_source_port(next_source_port_++);
306
307 return socket;
308 }
309
OnConnect(const IPEndPoint & endpoint)310 void OnConnect(const IPEndPoint& endpoint) {
311 remote_endpoints_.emplace_back(endpoint);
312 }
313
314 struct RemoteNameserver {
RemoteNameservernet::__anon98d353a80111::TestSocketFactory::RemoteNameserver315 explicit RemoteNameserver(IPEndPoint insecure_nameserver)
316 : insecure_nameserver(insecure_nameserver) {}
RemoteNameservernet::__anon98d353a80111::TestSocketFactory::RemoteNameserver317 explicit RemoteNameserver(DnsOverHttpsServerConfig secure_nameserver)
318 : secure_nameserver(secure_nameserver) {}
319
320 std::optional<IPEndPoint> insecure_nameserver;
321 std::optional<DnsOverHttpsServerConfig> secure_nameserver;
322 };
323
324 std::vector<RemoteNameserver> remote_endpoints_;
325 bool fail_next_socket_ = false;
326 bool diverse_source_ports_ = true;
327
328 private:
329 StaticSocketDataProvider empty_data_;
330 uint16_t next_source_port_ = 123;
331 };
332
Connect(const IPEndPoint & endpoint)333 int TestUDPClientSocket::Connect(const IPEndPoint& endpoint) {
334 factory_->OnConnect(endpoint);
335 return MockUDPClientSocket::Connect(endpoint);
336 }
337
ConnectAsync(const IPEndPoint & address,CompletionOnceCallback callback)338 int TestUDPClientSocket::ConnectAsync(const IPEndPoint& address,
339 CompletionOnceCallback callback) {
340 factory_->OnConnect(address);
341 return MockUDPClientSocket::ConnectAsync(address, std::move(callback));
342 }
343
344 // Helper class that holds a DnsTransaction and handles OnTransactionComplete.
345 class TransactionHelper {
346 public:
347 // If |expected_answer_count| < 0 then it is the expected net error.
TransactionHelper(int expected_answer_count)348 explicit TransactionHelper(int expected_answer_count)
349 : expected_answer_count_(expected_answer_count) {}
350
351 // Mark that the transaction shall be destroyed immediately upon callback.
set_cancel_in_callback()352 void set_cancel_in_callback() { cancel_in_callback_ = true; }
353
StartTransaction(DnsTransactionFactory * factory,const char * hostname,uint16_t qtype,bool secure,ResolveContext * context)354 void StartTransaction(DnsTransactionFactory* factory,
355 const char* hostname,
356 uint16_t qtype,
357 bool secure,
358 ResolveContext* context) {
359 std::unique_ptr<DnsTransaction> transaction = factory->CreateTransaction(
360 hostname, qtype,
361 NetLogWithSource::Make(net::NetLog::Get(), net::NetLogSourceType::NONE),
362 secure, factory->GetSecureDnsModeForTest(), context,
363 true /* fast_timeout */);
364 transaction->SetRequestPriority(DEFAULT_PRIORITY);
365 EXPECT_EQ(qtype, transaction->GetType());
366 StartTransaction(std::move(transaction));
367 }
368
StartTransaction(std::unique_ptr<DnsTransaction> transaction)369 void StartTransaction(std::unique_ptr<DnsTransaction> transaction) {
370 EXPECT_FALSE(transaction_);
371 transaction_ = std::move(transaction);
372 qtype_ = transaction_->GetType();
373 transaction_->Start(base::BindOnce(
374 &TransactionHelper::OnTransactionComplete, base::Unretained(this)));
375 }
376
Cancel()377 void Cancel() {
378 ASSERT_TRUE(transaction_.get() != nullptr);
379 transaction_.reset(nullptr);
380 }
381
OnTransactionComplete(int rv,const DnsResponse * response)382 void OnTransactionComplete(int rv, const DnsResponse* response) {
383 EXPECT_FALSE(completed_);
384
385 completed_ = true;
386 response_ = response;
387
388 transaction_complete_run_loop_.Quit();
389
390 if (cancel_in_callback_) {
391 Cancel();
392 return;
393 }
394
395 if (response)
396 EXPECT_TRUE(response->IsValid());
397
398 if (expected_answer_count_ >= 0) {
399 ASSERT_THAT(rv, IsOk());
400 ASSERT_TRUE(response != nullptr);
401 EXPECT_EQ(static_cast<unsigned>(expected_answer_count_),
402 response->answer_count());
403 EXPECT_EQ(qtype_, response->GetSingleQType());
404
405 DnsRecordParser parser = response->Parser();
406 DnsResourceRecord record;
407 for (int i = 0; i < expected_answer_count_; ++i) {
408 EXPECT_TRUE(parser.ReadRecord(&record));
409 }
410 } else {
411 EXPECT_EQ(expected_answer_count_, rv);
412 }
413 }
414
has_completed() const415 bool has_completed() const { return completed_; }
response() const416 const DnsResponse* response() const { return response_; }
417
418 // Runs until the completion callback is called. Transaction must have already
419 // been started or this will never complete.
RunUntilComplete()420 void RunUntilComplete() {
421 DCHECK(transaction_);
422 DCHECK(!transaction_complete_run_loop_.running());
423 transaction_complete_run_loop_.Run();
424 DCHECK(has_completed());
425 }
426
427 private:
428 uint16_t qtype_ = 0;
429 std::unique_ptr<DnsTransaction> transaction_;
430 raw_ptr<const DnsResponse, AcrossTasksDanglingUntriaged> response_ = nullptr;
431 int expected_answer_count_;
432 bool cancel_in_callback_ = false;
433 base::RunLoop transaction_complete_run_loop_;
434 bool completed_ = false;
435 };
436
437 // Callback that allows a test to modify HttpResponseinfo
438 // before the response is sent to the requester. This allows
439 // response headers to be changed.
440 using ResponseModifierCallback =
441 base::RepeatingCallback<void(URLRequest* request, HttpResponseInfo* info)>;
442
443 // Callback that allows the test to substitute its own implementation
444 // of URLRequestJob to handle the request.
445 using DohJobMakerCallback = base::RepeatingCallback<std::unique_ptr<
446 URLRequestJob>(URLRequest* request, SocketDataProvider* data_provider)>;
447
448 // Callback to notify that URLRequestJob::Start has been called.
449 using UrlRequestStartedCallback = base::RepeatingCallback<void()>;
450
451 // Subclass of URLRequestJob which takes a SocketDataProvider with data
452 // representing both a DNS over HTTPS query and response.
453 class URLRequestMockDohJob : public URLRequestJob, public AsyncSocket {
454 public:
URLRequestMockDohJob(URLRequest * request,SocketDataProvider * data_provider,ResponseModifierCallback response_modifier=ResponseModifierCallback (),UrlRequestStartedCallback on_start=UrlRequestStartedCallback ())455 URLRequestMockDohJob(
456 URLRequest* request,
457 SocketDataProvider* data_provider,
458 ResponseModifierCallback response_modifier = ResponseModifierCallback(),
459 UrlRequestStartedCallback on_start = UrlRequestStartedCallback())
460 : URLRequestJob(request),
461 data_provider_(data_provider),
462 response_modifier_(response_modifier),
463 on_start_(on_start) {
464 data_provider_->Initialize(this);
465 MatchQueryData(request, data_provider);
466 }
467
468 // Compare the query contained in either the POST body or the body
469 // parameter of the GET query to the write data of the SocketDataProvider.
MatchQueryData(URLRequest * request,SocketDataProvider * data_provider)470 static void MatchQueryData(URLRequest* request,
471 SocketDataProvider* data_provider) {
472 std::string decoded_query;
473 if (request->method() == "GET") {
474 std::string encoded_query;
475 EXPECT_TRUE(GetValueForKeyInQuery(request->url(), "dns", &encoded_query));
476 EXPECT_GT(encoded_query.size(), 0ul);
477
478 EXPECT_TRUE(base::Base64UrlDecode(
479 encoded_query, base::Base64UrlDecodePolicy::IGNORE_PADDING,
480 &decoded_query));
481 } else if (request->method() == "POST") {
482 EXPECT_EQ(IDEMPOTENT, request->GetIdempotency());
483 const UploadDataStream* stream = request->get_upload_for_testing();
484 auto* readers = stream->GetElementReaders();
485 EXPECT_TRUE(readers);
486 EXPECT_FALSE(readers->empty());
487 for (auto& reader : *readers) {
488 const UploadBytesElementReader* byte_reader = reader->AsBytesReader();
489 decoded_query +=
490 std::string(byte_reader->bytes(), byte_reader->length());
491 }
492 }
493
494 std::string query(decoded_query);
495 MockWriteResult result(SYNCHRONOUS, 1);
496 while (result.result > 0 && query.length() > 0) {
497 result = data_provider->OnWrite(query);
498 if (result.result > 0)
499 query = query.substr(result.result);
500 }
501 }
502
GetMockHttpsUrl(const std::string & path)503 static std::string GetMockHttpsUrl(const std::string& path) {
504 return "https://" + (kMockHostname + ("/" + path));
505 }
506
GetMockHttpUrl(const std::string & path)507 static std::string GetMockHttpUrl(const std::string& path) {
508 return "http://" + (kMockHostname + ("/" + path));
509 }
510
511 // URLRequestJob implementation:
Start()512 void Start() override {
513 if (on_start_)
514 on_start_.Run();
515 // Start reading asynchronously so that all error reporting and data
516 // callbacks happen as they would for network requests.
517 base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
518 FROM_HERE, base::BindOnce(&URLRequestMockDohJob::StartAsync,
519 weak_factory_.GetWeakPtr()));
520 }
521
522 URLRequestMockDohJob(const URLRequestMockDohJob&) = delete;
523 URLRequestMockDohJob& operator=(const URLRequestMockDohJob&) = delete;
524
~URLRequestMockDohJob()525 ~URLRequestMockDohJob() override {
526 if (data_provider_)
527 data_provider_->DetachSocket();
528 }
529
ReadRawData(IOBuffer * buf,int buf_size)530 int ReadRawData(IOBuffer* buf, int buf_size) override {
531 if (!data_provider_)
532 return ERR_FAILED;
533 if (leftover_data_len_ > 0) {
534 int rv = DoBufferCopy(leftover_data_, leftover_data_len_, buf, buf_size);
535 return rv;
536 }
537
538 if (data_provider_->AllReadDataConsumed())
539 return 0;
540
541 MockRead read = data_provider_->OnRead();
542
543 if (read.result < ERR_IO_PENDING)
544 return read.result;
545
546 if (read.result == ERR_IO_PENDING) {
547 pending_buf_ = buf;
548 pending_buf_size_ = buf_size;
549 return ERR_IO_PENDING;
550 }
551 return DoBufferCopy(read.data, read.data_len, buf, buf_size);
552 }
553
GetResponseInfo(HttpResponseInfo * info)554 void GetResponseInfo(HttpResponseInfo* info) override {
555 // Send back mock headers.
556 std::string raw_headers;
557 raw_headers.append(
558 "HTTP/1.1 200 OK\n"
559 "Content-type: application/dns-message\n");
560 if (content_length_ > 0) {
561 raw_headers.append(base::StringPrintf("Content-Length: %1d\n",
562 static_cast<int>(content_length_)));
563 }
564 info->headers = base::MakeRefCounted<HttpResponseHeaders>(
565 HttpUtil::AssembleRawHeaders(raw_headers));
566 if (response_modifier_)
567 response_modifier_.Run(request(), info);
568 }
569
570 // AsyncSocket implementation:
OnReadComplete(const MockRead & data)571 void OnReadComplete(const MockRead& data) override {
572 EXPECT_NE(data.result, ERR_IO_PENDING);
573 if (data.result < 0)
574 return ReadRawDataComplete(data.result);
575 ReadRawDataComplete(DoBufferCopy(data.data, data.data_len, pending_buf_,
576 pending_buf_size_));
577 }
OnWriteComplete(int rv)578 void OnWriteComplete(int rv) override {}
OnConnectComplete(const MockConnect & data)579 void OnConnectComplete(const MockConnect& data) override {}
OnDataProviderDestroyed()580 void OnDataProviderDestroyed() override { data_provider_ = nullptr; }
581
582 private:
StartAsync()583 void StartAsync() {
584 if (!request_)
585 return;
586 if (content_length_)
587 set_expected_content_size(content_length_);
588 NotifyHeadersComplete();
589 }
590
DoBufferCopy(const char * data,int data_len,IOBuffer * buf,int buf_size)591 int DoBufferCopy(const char* data,
592 int data_len,
593 IOBuffer* buf,
594 int buf_size) {
595 if (data_len > buf_size) {
596 std::copy(data, data + buf_size, buf->data());
597 leftover_data_ = data + buf_size;
598 leftover_data_len_ = data_len - buf_size;
599 return buf_size;
600 }
601 std::copy(data, data + data_len, buf->data());
602 return data_len;
603 }
604
605 const int content_length_ = 0;
606 const char* leftover_data_;
607 int leftover_data_len_ = 0;
608 raw_ptr<SocketDataProvider> data_provider_;
609 const ResponseModifierCallback response_modifier_;
610 const UrlRequestStartedCallback on_start_;
611 raw_ptr<IOBuffer> pending_buf_;
612 int pending_buf_size_;
613
614 base::WeakPtrFactory<URLRequestMockDohJob> weak_factory_{this};
615 };
616
617 class DnsTransactionTestBase : public testing::Test {
618 public:
619 DnsTransactionTestBase() = default;
620
~DnsTransactionTestBase()621 ~DnsTransactionTestBase() override {
622 // All queued transaction IDs should be used by a transaction calling
623 // GetNextId().
624 CHECK(transaction_ids_.empty());
625 }
626
627 // Generates |nameservers| for DnsConfig.
ConfigureNumServers(size_t num_servers)628 void ConfigureNumServers(size_t num_servers) {
629 CHECK_LE(num_servers, 255u);
630 config_.nameservers.clear();
631 for (size_t i = 0; i < num_servers; ++i) {
632 config_.nameservers.emplace_back(IPAddress(192, 168, 1, i),
633 dns_protocol::kDefaultPort);
634 }
635 }
636
637 // Configures the DnsConfig DNS-over-HTTPS server(s), which either
638 // accept GET or POST requests based on use_post. If a
639 // ResponseModifierCallback is provided it will be called to construct the
640 // HTTPResponse.
ConfigureDohServers(bool use_post,size_t num_doh_servers=1,bool make_available=true)641 void ConfigureDohServers(bool use_post,
642 size_t num_doh_servers = 1,
643 bool make_available = true) {
644 GURL url(URLRequestMockDohJob::GetMockHttpsUrl("doh_test"));
645 URLRequestFilter* filter = URLRequestFilter::GetInstance();
646 filter->AddHostnameInterceptor(url.scheme(), url.host(),
647 std::make_unique<DohJobInterceptor>(this));
648 CHECK_LE(num_doh_servers, 255u);
649 std::vector<string> templates;
650 templates.reserve(num_doh_servers);
651 for (size_t i = 0; i < num_doh_servers; ++i) {
652 templates.push_back(URLRequestMockDohJob::GetMockHttpsUrl(
653 base::StringPrintf("doh_test_%zu", i)) +
654 (use_post ? "" : "{?dns}"));
655 }
656 config_.doh_config =
657 *DnsOverHttpsConfig::FromTemplatesForTesting(std::move(templates));
658 ConfigureFactory();
659
660 if (make_available) {
661 for (size_t server_index = 0; server_index < num_doh_servers;
662 ++server_index) {
663 resolve_context_->RecordServerSuccess(
664 server_index, true /* is_doh_server */, session_.get());
665 }
666 }
667 }
668
669 // Called after fully configuring |config|.
ConfigureFactory()670 void ConfigureFactory() {
671 session_ = base::MakeRefCounted<DnsSession>(
672 config_,
673 base::BindRepeating(&DnsTransactionTestBase::GetNextId,
674 base::Unretained(this)),
675 nullptr /* NetLog */);
676 resolve_context_->InvalidateCachesAndPerSessionData(
677 session_.get(), false /* network_change */);
678 transaction_factory_ = DnsTransactionFactory::CreateFactory(session_.get());
679 }
680
AddSocketData(std::unique_ptr<DnsSocketData> data,bool enqueue_transaction_id=true)681 void AddSocketData(std::unique_ptr<DnsSocketData> data,
682 bool enqueue_transaction_id = true) {
683 CHECK(socket_factory_.get());
684 if (enqueue_transaction_id)
685 transaction_ids_.push_back(data->query_id());
686 socket_factory_->AddSocketDataProvider(data->GetProvider());
687 socket_data_.push_back(std::move(data));
688 }
689
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)690 void AddQueryAndResponseNoWrite(uint16_t id,
691 const char* dotted_name,
692 uint16_t qtype,
693 IoMode mode,
694 Transport transport,
695 const OptRecordRdata* opt_rdata = nullptr,
696 DnsQuery::PaddingStrategy padding_strategy =
697 DnsQuery::PaddingStrategy::NONE) {
698 CHECK(socket_factory_.get());
699 auto data = std::make_unique<DnsSocketData>(
700 id, dotted_name, qtype, mode, transport, opt_rdata, padding_strategy);
701 data->ClearWrites();
702 AddSocketData(std::move(data), true);
703 }
704
705 // Add expected query for |dotted_name| and |qtype| with |id| and response
706 // taken verbatim from |data| of |data_length| bytes. The transaction id in
707 // |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)708 void AddQueryAndResponse(uint16_t id,
709 const char* dotted_name,
710 uint16_t qtype,
711 const uint8_t* response_data,
712 size_t response_length,
713 IoMode mode,
714 Transport transport,
715 const OptRecordRdata* opt_rdata = nullptr,
716 DnsQuery::PaddingStrategy padding_strategy =
717 DnsQuery::PaddingStrategy::NONE,
718 bool enqueue_transaction_id = true) {
719 CHECK(socket_factory_.get());
720 auto data = std::make_unique<DnsSocketData>(
721 id, dotted_name, qtype, mode, transport, opt_rdata, padding_strategy);
722 data->AddResponseData(response_data, response_length, mode);
723 AddSocketData(std::move(data), enqueue_transaction_id);
724 }
725
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)726 void AddQueryAndErrorResponse(uint16_t id,
727 const char* dotted_name,
728 uint16_t qtype,
729 int error,
730 IoMode mode,
731 Transport transport,
732 const OptRecordRdata* opt_rdata = nullptr,
733 DnsQuery::PaddingStrategy padding_strategy =
734 DnsQuery::PaddingStrategy::NONE,
735 bool enqueue_transaction_id = true) {
736 CHECK(socket_factory_.get());
737 auto data = std::make_unique<DnsSocketData>(
738 id, dotted_name, qtype, mode, transport, opt_rdata, padding_strategy);
739 data->AddReadError(error, mode);
740 AddSocketData(std::move(data), enqueue_transaction_id);
741 }
742
AddAsyncQueryAndResponse(uint16_t id,const char * dotted_name,uint16_t qtype,const uint8_t * data,size_t data_length,const OptRecordRdata * opt_rdata=nullptr)743 void AddAsyncQueryAndResponse(uint16_t id,
744 const char* dotted_name,
745 uint16_t qtype,
746 const uint8_t* data,
747 size_t data_length,
748 const OptRecordRdata* opt_rdata = nullptr) {
749 AddQueryAndResponse(id, dotted_name, qtype, data, data_length, ASYNC,
750 Transport::UDP, opt_rdata);
751 }
752
AddSyncQueryAndResponse(uint16_t id,const char * dotted_name,uint16_t qtype,const uint8_t * data,size_t data_length,const OptRecordRdata * opt_rdata=nullptr)753 void AddSyncQueryAndResponse(uint16_t id,
754 const char* dotted_name,
755 uint16_t qtype,
756 const uint8_t* data,
757 size_t data_length,
758 const OptRecordRdata* opt_rdata = nullptr) {
759 AddQueryAndResponse(id, dotted_name, qtype, data, data_length, SYNCHRONOUS,
760 Transport::UDP, opt_rdata);
761 }
762
763 // 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)764 void AddHangingQuery(
765 const char* dotted_name,
766 uint16_t qtype,
767 DnsQuery::PaddingStrategy padding_strategy =
768 DnsQuery::PaddingStrategy::NONE,
769 uint16_t id = base::RandInt(0, std::numeric_limits<uint16_t>::max()),
770 bool enqueue_transaction_id = true) {
771 auto data = std::make_unique<DnsSocketData>(
772 id, dotted_name, qtype, ASYNC, Transport::UDP, nullptr /* opt_rdata */,
773 padding_strategy);
774 AddSocketData(std::move(data), enqueue_transaction_id);
775 }
776
777 // Add expected query of |dotted_name| and |qtype| and matching response with
778 // 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)779 void AddQueryAndRcode(
780 const char* dotted_name,
781 uint16_t qtype,
782 int rcode,
783 IoMode mode,
784 Transport trans,
785 DnsQuery::PaddingStrategy padding_strategy =
786 DnsQuery::PaddingStrategy::NONE,
787 uint16_t id = base::RandInt(0, std::numeric_limits<uint16_t>::max()),
788 bool enqueue_transaction_id = true) {
789 CHECK_NE(dns_protocol::kRcodeNOERROR, rcode);
790 auto data = std::make_unique<DnsSocketData>(id, dotted_name, qtype, mode,
791 trans, nullptr /* opt_rdata */,
792 padding_strategy);
793 data->AddRcode(rcode, mode);
794 AddSocketData(std::move(data), enqueue_transaction_id);
795 }
796
AddAsyncQueryAndRcode(const char * dotted_name,uint16_t qtype,int rcode)797 void AddAsyncQueryAndRcode(const char* dotted_name,
798 uint16_t qtype,
799 int rcode) {
800 AddQueryAndRcode(dotted_name, qtype, rcode, ASYNC, Transport::UDP);
801 }
802
AddSyncQueryAndRcode(const char * dotted_name,uint16_t qtype,int rcode)803 void AddSyncQueryAndRcode(const char* dotted_name,
804 uint16_t qtype,
805 int rcode) {
806 AddQueryAndRcode(dotted_name, qtype, rcode, SYNCHRONOUS, Transport::UDP);
807 }
808
809 // Checks if the sockets were connected in the order matching the indices in
810 // |servers|.
CheckServerOrder(const size_t * servers,size_t num_attempts)811 void CheckServerOrder(const size_t* servers, size_t num_attempts) {
812 ASSERT_EQ(num_attempts, socket_factory_->remote_endpoints_.size());
813 auto num_insecure_nameservers = session_->config().nameservers.size();
814 for (size_t i = 0; i < num_attempts; ++i) {
815 if (servers[i] < num_insecure_nameservers) {
816 // Check insecure server match.
817 EXPECT_EQ(
818 socket_factory_->remote_endpoints_[i].insecure_nameserver.value(),
819 session_->config().nameservers[servers[i]]);
820 } else {
821 // Check secure server match.
822 EXPECT_EQ(
823 socket_factory_->remote_endpoints_[i].secure_nameserver.value(),
824 session_->config()
825 .doh_config.servers()[servers[i] - num_insecure_nameservers]);
826 }
827 }
828 }
829
MaybeInterceptRequest(URLRequest * request)830 std::unique_ptr<URLRequestJob> MaybeInterceptRequest(URLRequest* request) {
831 // If the path indicates a redirect, skip checking the list of
832 // configured servers, because it won't be there and we still want
833 // to handle it.
834 bool server_found = request->url().path() == "/redirect-destination";
835 for (auto server : config_.doh_config.servers()) {
836 if (server_found)
837 break;
838 std::string url_base =
839 GetURLFromTemplateWithoutParameters(server.server_template());
840 if (server.use_post() && request->method() == "POST") {
841 if (url_base == request->url().spec()) {
842 server_found = true;
843 socket_factory_->remote_endpoints_.emplace_back(server);
844 }
845 } else if (!server.use_post() && request->method() == "GET") {
846 std::string prefix = url_base + "?dns=";
847 auto mispair = base::ranges::mismatch(prefix, request->url().spec());
848 if (mispair.first == prefix.end()) {
849 server_found = true;
850 socket_factory_->remote_endpoints_.emplace_back(server);
851 }
852 }
853 }
854 EXPECT_TRUE(server_found);
855
856 EXPECT_TRUE(
857 request->isolation_info().network_isolation_key().IsTransient());
858
859 // All DoH requests for the same ResolveContext should use the same
860 // IsolationInfo, so network objects like sockets can be reused between
861 // requests.
862 if (!expect_multiple_isolation_infos_) {
863 if (!isolation_info_) {
864 isolation_info_ =
865 std::make_unique<IsolationInfo>(request->isolation_info());
866 } else {
867 EXPECT_TRUE(
868 isolation_info_->IsEqualForTesting(request->isolation_info()));
869 }
870 }
871
872 EXPECT_FALSE(request->allow_credentials());
873 EXPECT_EQ(SecureDnsPolicy::kBootstrap, request->secure_dns_policy());
874
875 std::string accept;
876 EXPECT_TRUE(request->extra_request_headers().GetHeader("Accept", &accept));
877 EXPECT_EQ(accept, "application/dns-message");
878
879 std::string language;
880 EXPECT_TRUE(request->extra_request_headers().GetHeader("Accept-Language",
881 &language));
882 EXPECT_EQ(language, "*");
883
884 std::string user_agent;
885 EXPECT_TRUE(
886 request->extra_request_headers().GetHeader("User-Agent", &user_agent));
887 EXPECT_EQ(user_agent, "Chrome");
888
889 SocketDataProvider* provider = socket_factory_->mock_data().GetNext();
890
891 if (doh_job_maker_)
892 return doh_job_maker_.Run(request, provider);
893
894 return std::make_unique<URLRequestMockDohJob>(
895 request, provider, response_modifier_, on_start_);
896 }
897
898 class DohJobInterceptor : public URLRequestInterceptor {
899 public:
DohJobInterceptor(DnsTransactionTestBase * test)900 explicit DohJobInterceptor(DnsTransactionTestBase* test) : test_(test) {}
901
902 DohJobInterceptor(const DohJobInterceptor&) = delete;
903 DohJobInterceptor& operator=(const DohJobInterceptor&) = delete;
904
905 ~DohJobInterceptor() override = default;
906
907 // URLRequestInterceptor implementation:
MaybeInterceptRequest(URLRequest * request) const908 std::unique_ptr<URLRequestJob> MaybeInterceptRequest(
909 URLRequest* request) const override {
910 return test_->MaybeInterceptRequest(request);
911 }
912
913 private:
914 raw_ptr<DnsTransactionTestBase> test_;
915 };
916
SetResponseModifierCallback(ResponseModifierCallback response_modifier)917 void SetResponseModifierCallback(ResponseModifierCallback response_modifier) {
918 response_modifier_ = response_modifier;
919 }
920
SetDohJobMakerCallback(DohJobMakerCallback doh_job_maker)921 void SetDohJobMakerCallback(DohJobMakerCallback doh_job_maker) {
922 doh_job_maker_ = doh_job_maker;
923 }
924
SetUrlRequestStartedCallback(UrlRequestStartedCallback on_start)925 void SetUrlRequestStartedCallback(UrlRequestStartedCallback on_start) {
926 on_start_ = on_start;
927 }
928
SetUp()929 void SetUp() override {
930 // By default set one server,
931 ConfigureNumServers(1);
932 // and no retransmissions,
933 config_.attempts = 1;
934 // and an arbitrary fallback period.
935 config_.fallback_period = kFallbackPeriod;
936 auto context_builder = CreateTestURLRequestContextBuilder();
937 socket_factory_ = std::make_unique<TestSocketFactory>();
938 context_builder->set_client_socket_factory_for_testing(
939 socket_factory_.get());
940 request_context_ = context_builder->Build();
941 resolve_context_ = std::make_unique<ResolveContext>(
942 request_context_.get(), false /* enable_caching */);
943
944 ConfigureFactory();
945 }
946
TearDown()947 void TearDown() override {
948 // Check that all socket data was at least written to.
949 for (size_t i = 0; i < socket_data_.size(); ++i) {
950 EXPECT_TRUE(socket_data_[i]->GetProvider()->AllWriteDataConsumed()) << i;
951 }
952
953 URLRequestFilter* filter = URLRequestFilter::GetInstance();
954 filter->ClearHandlers();
955 }
956
set_expect_multiple_isolation_infos(bool expect_multiple_isolation_infos)957 void set_expect_multiple_isolation_infos(
958 bool expect_multiple_isolation_infos) {
959 expect_multiple_isolation_infos_ = expect_multiple_isolation_infos;
960 }
961
962 protected:
GetNextId(int min,int max)963 int GetNextId(int min, int max) {
964 EXPECT_FALSE(transaction_ids_.empty());
965 int id = transaction_ids_.front();
966 transaction_ids_.pop_front();
967 EXPECT_GE(id, min);
968 EXPECT_LE(id, max);
969 return id;
970 }
971
972 DnsConfig config_;
973
974 std::vector<std::unique_ptr<DnsSocketData>> socket_data_;
975
976 base::circular_deque<int> transaction_ids_;
977 std::unique_ptr<TestSocketFactory> socket_factory_;
978 std::unique_ptr<URLRequestContext> request_context_;
979 std::unique_ptr<ResolveContext> resolve_context_;
980 scoped_refptr<DnsSession> session_;
981 std::unique_ptr<DnsTransactionFactory> transaction_factory_;
982 ResponseModifierCallback response_modifier_;
983 UrlRequestStartedCallback on_start_;
984 DohJobMakerCallback doh_job_maker_;
985
986 // Whether multiple IsolationInfos should be expected (due to there being
987 // multiple RequestContexts in use).
988 bool expect_multiple_isolation_infos_ = false;
989
990 // IsolationInfo used by DoH requests. Populated on first DoH request, and
991 // compared to IsolationInfo used by all subsequent requests, unless
992 // |expect_multiple_isolation_infos_| is true.
993 std::unique_ptr<IsolationInfo> isolation_info_;
994 };
995
996 class DnsTransactionTest : public DnsTransactionTestBase,
997 public WithTaskEnvironment {
998 public:
999 DnsTransactionTest() = default;
1000 ~DnsTransactionTest() override = default;
1001 };
1002
1003 class DnsTransactionTestWithMockTime : public DnsTransactionTestBase,
1004 public WithTaskEnvironment {
1005 protected:
DnsTransactionTestWithMockTime()1006 DnsTransactionTestWithMockTime()
1007 : WithTaskEnvironment(
1008 base::test::TaskEnvironment::TimeSource::MOCK_TIME) {}
1009 ~DnsTransactionTestWithMockTime() override = default;
1010 };
1011
TEST_F(DnsTransactionTest,Lookup)1012 TEST_F(DnsTransactionTest, Lookup) {
1013 AddAsyncQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype,
1014 kT0ResponseDatagram, std::size(kT0ResponseDatagram));
1015
1016 TransactionHelper helper0(kT0RecordCount);
1017 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
1018 false /* secure */, resolve_context_.get());
1019 helper0.RunUntilComplete();
1020 }
1021
TEST_F(DnsTransactionTest,LookupWithLog)1022 TEST_F(DnsTransactionTest, LookupWithLog) {
1023 AddAsyncQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype,
1024 kT0ResponseDatagram, std::size(kT0ResponseDatagram));
1025
1026 TransactionHelper helper0(kT0RecordCount);
1027 NetLogCountingObserver observer;
1028 NetLog::Get()->AddObserver(&observer, NetLogCaptureMode::kEverything);
1029 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
1030 false /* secure */, resolve_context_.get());
1031 helper0.RunUntilComplete();
1032 EXPECT_EQ(observer.count(), 7);
1033 EXPECT_EQ(observer.dict_count(), 5);
1034 }
1035
TEST_F(DnsTransactionTest,LookupWithEDNSOption)1036 TEST_F(DnsTransactionTest, LookupWithEDNSOption) {
1037 OptRecordRdata expected_opt_rdata;
1038
1039 transaction_factory_->AddEDNSOption(
1040 OptRecordRdata::UnknownOpt::CreateForTesting(123, "\xbe\xef"));
1041 expected_opt_rdata.AddOpt(
1042 OptRecordRdata::UnknownOpt::CreateForTesting(123, "\xbe\xef"));
1043
1044 AddAsyncQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype,
1045 kT0ResponseDatagram, std::size(kT0ResponseDatagram),
1046 &expected_opt_rdata);
1047
1048 TransactionHelper helper0(kT0RecordCount);
1049 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
1050 false /* secure */, resolve_context_.get());
1051 helper0.RunUntilComplete();
1052 }
1053
TEST_F(DnsTransactionTest,LookupWithMultipleEDNSOptions)1054 TEST_F(DnsTransactionTest, LookupWithMultipleEDNSOptions) {
1055 OptRecordRdata expected_opt_rdata;
1056
1057 std::vector<std::pair<uint16_t, std::string>> params = {
1058 // Two options with the same code, to check that both are included.
1059 std::pair<uint16_t, std::string>(1, "\xde\xad"),
1060 std::pair<uint16_t, std::string>(1, "\xbe\xef"),
1061 // Try a different code and different length of data.
1062 std::pair<uint16_t, std::string>(2, "\xff")};
1063
1064 for (auto& param : params) {
1065 transaction_factory_->AddEDNSOption(
1066 OptRecordRdata::UnknownOpt::CreateForTesting(param.first,
1067 param.second));
1068 expected_opt_rdata.AddOpt(OptRecordRdata::UnknownOpt::CreateForTesting(
1069 param.first, param.second));
1070 }
1071
1072 AddAsyncQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype,
1073 kT0ResponseDatagram, std::size(kT0ResponseDatagram),
1074 &expected_opt_rdata);
1075
1076 TransactionHelper helper0(kT0RecordCount);
1077 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
1078 false /* secure */, resolve_context_.get());
1079 helper0.RunUntilComplete();
1080 }
1081
1082 // Concurrent lookup tests assume that DnsTransaction::Start immediately
1083 // consumes a socket from ClientSocketFactory.
TEST_F(DnsTransactionTest,ConcurrentLookup)1084 TEST_F(DnsTransactionTest, ConcurrentLookup) {
1085 AddAsyncQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype,
1086 kT0ResponseDatagram, std::size(kT0ResponseDatagram));
1087 AddAsyncQueryAndResponse(1 /* id */, kT1HostName, kT1Qtype,
1088 kT1ResponseDatagram, std::size(kT1ResponseDatagram));
1089
1090 TransactionHelper helper0(kT0RecordCount);
1091 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
1092 false /* secure */, resolve_context_.get());
1093 TransactionHelper helper1(kT1RecordCount);
1094 helper1.StartTransaction(transaction_factory_.get(), kT1HostName, kT1Qtype,
1095 false /* secure */, resolve_context_.get());
1096
1097 base::RunLoop().RunUntilIdle();
1098
1099 EXPECT_TRUE(helper0.has_completed());
1100 EXPECT_TRUE(helper1.has_completed());
1101 }
1102
TEST_F(DnsTransactionTest,CancelLookup)1103 TEST_F(DnsTransactionTest, CancelLookup) {
1104 AddQueryAndResponseNoWrite(0 /* id */, kT0HostName, kT0Qtype, ASYNC,
1105 Transport::UDP, nullptr);
1106
1107 AddAsyncQueryAndResponse(1 /* id */, kT1HostName, kT1Qtype,
1108 kT1ResponseDatagram, std::size(kT1ResponseDatagram));
1109
1110 TransactionHelper helper0(kT0RecordCount);
1111 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
1112 false /* secure */, resolve_context_.get());
1113 TransactionHelper helper1(kT1RecordCount);
1114 helper1.StartTransaction(transaction_factory_.get(), kT1HostName, kT1Qtype,
1115 false /* secure */, resolve_context_.get());
1116
1117 helper0.Cancel();
1118
1119 base::RunLoop().RunUntilIdle();
1120
1121 EXPECT_FALSE(helper0.has_completed());
1122 EXPECT_TRUE(helper1.has_completed());
1123 }
1124
TEST_F(DnsTransactionTest,DestroyFactory)1125 TEST_F(DnsTransactionTest, DestroyFactory) {
1126 AddAsyncQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype,
1127 kT0ResponseDatagram, std::size(kT0ResponseDatagram));
1128
1129 TransactionHelper helper0(kT0RecordCount);
1130 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
1131 false /* secure */, resolve_context_.get());
1132
1133 // Destroying the client does not affect running requests.
1134 transaction_factory_.reset(nullptr);
1135
1136 helper0.RunUntilComplete();
1137 }
1138
TEST_F(DnsTransactionTest,CancelFromCallback)1139 TEST_F(DnsTransactionTest, CancelFromCallback) {
1140 AddAsyncQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype,
1141 kT0ResponseDatagram, std::size(kT0ResponseDatagram));
1142
1143 TransactionHelper helper0(kT0RecordCount);
1144 helper0.set_cancel_in_callback();
1145
1146 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
1147 false /* secure */, resolve_context_.get());
1148 helper0.RunUntilComplete();
1149 }
1150
TEST_F(DnsTransactionTest,MismatchedResponseSync)1151 TEST_F(DnsTransactionTest, MismatchedResponseSync) {
1152 config_.attempts = 2;
1153 ConfigureFactory();
1154
1155 // First attempt receives mismatched response synchronously.
1156 auto data = std::make_unique<DnsSocketData>(0 /* id */, kT0HostName, kT0Qtype,
1157 SYNCHRONOUS, Transport::UDP);
1158 data->AddResponseData(kT1ResponseDatagram, std::size(kT1ResponseDatagram),
1159 SYNCHRONOUS);
1160 AddSocketData(std::move(data));
1161
1162 // Second attempt receives valid response synchronously.
1163 auto data1 = std::make_unique<DnsSocketData>(
1164 0 /* id */, kT0HostName, kT0Qtype, SYNCHRONOUS, Transport::UDP);
1165 data1->AddResponseData(kT0ResponseDatagram, std::size(kT0ResponseDatagram),
1166 SYNCHRONOUS);
1167 AddSocketData(std::move(data1));
1168
1169 TransactionHelper helper0(kT0RecordCount);
1170 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
1171 false /* secure */, resolve_context_.get());
1172 helper0.RunUntilComplete();
1173 }
1174
TEST_F(DnsTransactionTest,MismatchedResponseAsync)1175 TEST_F(DnsTransactionTest, MismatchedResponseAsync) {
1176 config_.attempts = 2;
1177 ConfigureFactory();
1178
1179 // First attempt receives mismatched response asynchronously.
1180 auto data0 = std::make_unique<DnsSocketData>(0 /* id */, kT0HostName,
1181 kT0Qtype, ASYNC, Transport::UDP);
1182 data0->AddResponseData(kT1ResponseDatagram, std::size(kT1ResponseDatagram),
1183 ASYNC);
1184 AddSocketData(std::move(data0));
1185
1186 // Second attempt receives valid response asynchronously.
1187 auto data1 = std::make_unique<DnsSocketData>(0 /* id */, kT0HostName,
1188 kT0Qtype, ASYNC, Transport::UDP);
1189 data1->AddResponseData(kT0ResponseDatagram, std::size(kT0ResponseDatagram),
1190 ASYNC);
1191 AddSocketData(std::move(data1));
1192
1193 TransactionHelper helper0(kT0RecordCount);
1194 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
1195 false /* secure */, resolve_context_.get());
1196 helper0.RunUntilComplete();
1197 }
1198
1199 // Test that responses are not accepted when only the response ID mismatches.
1200 // Tests against incorrect transaction ID validation, which is anti-pattern #1
1201 // from the "NAME:WRECK" report:
1202 // https://www.forescout.com/company/resources/namewreck-breaking-and-fixing-dns-implementations/
TEST_F(DnsTransactionTest,MismatchedResponseFail)1203 TEST_F(DnsTransactionTest, MismatchedResponseFail) {
1204 ConfigureFactory();
1205
1206 // Attempt receives mismatched response and fails because only one attempt is
1207 // allowed.
1208 AddAsyncQueryAndResponse(1 /* id */, kT0HostName, kT0Qtype,
1209 kT0ResponseDatagram, std::size(kT0ResponseDatagram));
1210
1211 TransactionHelper helper0(ERR_DNS_MALFORMED_RESPONSE);
1212 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
1213 false /* secure */, resolve_context_.get());
1214 helper0.RunUntilComplete();
1215 }
1216
TEST_F(DnsTransactionTest,MismatchedResponseNxdomain)1217 TEST_F(DnsTransactionTest, MismatchedResponseNxdomain) {
1218 config_.attempts = 2;
1219 ConfigureFactory();
1220
1221 // First attempt receives mismatched response followed by valid NXDOMAIN
1222 // response.
1223 // Second attempt receives valid NXDOMAIN response.
1224 auto data = std::make_unique<DnsSocketData>(0 /* id */, kT0HostName, kT0Qtype,
1225 SYNCHRONOUS, Transport::UDP);
1226 data->AddResponseData(kT1ResponseDatagram, std::size(kT1ResponseDatagram),
1227 SYNCHRONOUS);
1228 data->AddRcode(dns_protocol::kRcodeNXDOMAIN, ASYNC);
1229 AddSocketData(std::move(data));
1230 AddSyncQueryAndRcode(kT0HostName, kT0Qtype, dns_protocol::kRcodeNXDOMAIN);
1231
1232 TransactionHelper helper0(ERR_NAME_NOT_RESOLVED);
1233 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
1234 false /* secure */, resolve_context_.get());
1235 helper0.RunUntilComplete();
1236 }
1237
1238 // This is a regression test for https://crbug.com/1410442.
TEST_F(DnsTransactionTest,ZeroSizeResponseAsync)1239 TEST_F(DnsTransactionTest, ZeroSizeResponseAsync) {
1240 config_.attempts = 2;
1241 ConfigureFactory();
1242
1243 // First attempt receives zero size response asynchronously.
1244 auto data0 = std::make_unique<DnsSocketData>(/*id=*/0, kT0HostName, kT0Qtype,
1245 ASYNC, Transport::UDP);
1246 data0->AddReadError(0, ASYNC);
1247 AddSocketData(std::move(data0));
1248
1249 // Second attempt receives valid response asynchronously.
1250 auto data1 = std::make_unique<DnsSocketData>(/*id=*/0, kT0HostName, kT0Qtype,
1251 ASYNC, Transport::UDP);
1252 data1->AddResponseData(kT0ResponseDatagram, std::size(kT0ResponseDatagram),
1253 ASYNC);
1254 AddSocketData(std::move(data1));
1255
1256 TransactionHelper helper0(kT0RecordCount);
1257 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
1258 /*secure=*/false, resolve_context_.get());
1259 helper0.RunUntilComplete();
1260 }
1261
TEST_F(DnsTransactionTest,ServerFail)1262 TEST_F(DnsTransactionTest, ServerFail) {
1263 AddAsyncQueryAndRcode(kT0HostName, kT0Qtype, dns_protocol::kRcodeSERVFAIL);
1264
1265 TransactionHelper helper0(ERR_DNS_SERVER_FAILED);
1266 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
1267 false /* secure */, resolve_context_.get());
1268 helper0.RunUntilComplete();
1269
1270 ASSERT_NE(helper0.response(), nullptr);
1271 EXPECT_EQ(helper0.response()->rcode(), dns_protocol::kRcodeSERVFAIL);
1272 }
1273
TEST_F(DnsTransactionTest,NoDomain)1274 TEST_F(DnsTransactionTest, NoDomain) {
1275 AddAsyncQueryAndRcode(kT0HostName, kT0Qtype, dns_protocol::kRcodeNXDOMAIN);
1276
1277 TransactionHelper helper0(ERR_NAME_NOT_RESOLVED);
1278 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
1279 false /* secure */, resolve_context_.get());
1280 helper0.RunUntilComplete();
1281 }
1282
TEST_F(DnsTransactionTestWithMockTime,Timeout_FastTimeout)1283 TEST_F(DnsTransactionTestWithMockTime, Timeout_FastTimeout) {
1284 config_.attempts = 3;
1285 ConfigureFactory();
1286
1287 AddHangingQuery(kT0HostName, kT0Qtype);
1288 AddHangingQuery(kT0HostName, kT0Qtype);
1289 AddHangingQuery(kT0HostName, kT0Qtype);
1290
1291 TransactionHelper helper0(ERR_DNS_TIMED_OUT);
1292 std::unique_ptr<DnsTransaction> transaction =
1293 transaction_factory_->CreateTransaction(
1294 kT0HostName, kT0Qtype, NetLogWithSource(), false /* secure */,
1295 SecureDnsMode::kOff, resolve_context_.get(), true /* fast_timeout */);
1296
1297 helper0.StartTransaction(std::move(transaction));
1298
1299 // Finish when the third attempt expires its fallback period.
1300 base::RunLoop().RunUntilIdle();
1301 EXPECT_FALSE(helper0.has_completed());
1302 FastForwardBy(
1303 resolve_context_->NextClassicFallbackPeriod(0, 0, session_.get()));
1304 EXPECT_FALSE(helper0.has_completed());
1305 FastForwardBy(
1306 resolve_context_->NextClassicFallbackPeriod(0, 1, session_.get()));
1307 EXPECT_FALSE(helper0.has_completed());
1308 FastForwardBy(
1309 resolve_context_->NextClassicFallbackPeriod(0, 2, session_.get()));
1310 EXPECT_TRUE(helper0.has_completed());
1311 }
1312
TEST_F(DnsTransactionTestWithMockTime,ServerFallbackAndRotate)1313 TEST_F(DnsTransactionTestWithMockTime, ServerFallbackAndRotate) {
1314 // Test that we fallback on both server failure and fallback period
1315 // expiration.
1316 config_.attempts = 2;
1317 // The next request should start from the next server.
1318 config_.rotate = true;
1319 ConfigureNumServers(3);
1320 ConfigureFactory();
1321
1322 // Responses for first request.
1323 AddHangingQuery(kT0HostName, kT0Qtype);
1324 AddAsyncQueryAndRcode(kT0HostName, kT0Qtype, dns_protocol::kRcodeSERVFAIL);
1325 AddHangingQuery(kT0HostName, kT0Qtype);
1326 AddAsyncQueryAndRcode(kT0HostName, kT0Qtype, dns_protocol::kRcodeSERVFAIL);
1327 AddAsyncQueryAndRcode(kT0HostName, kT0Qtype, dns_protocol::kRcodeNXDOMAIN);
1328 // Responses for second request.
1329 AddAsyncQueryAndRcode(kT1HostName, kT1Qtype, dns_protocol::kRcodeSERVFAIL);
1330 AddAsyncQueryAndRcode(kT1HostName, kT1Qtype, dns_protocol::kRcodeSERVFAIL);
1331 AddAsyncQueryAndRcode(kT1HostName, kT1Qtype, dns_protocol::kRcodeNXDOMAIN);
1332
1333 TransactionHelper helper0(ERR_NAME_NOT_RESOLVED);
1334 TransactionHelper helper1(ERR_NAME_NOT_RESOLVED);
1335
1336 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
1337 false /* secure */, resolve_context_.get());
1338 base::RunLoop().RunUntilIdle();
1339 EXPECT_FALSE(helper0.has_completed());
1340 FastForwardUntilNoTasksRemain();
1341 EXPECT_TRUE(helper0.has_completed());
1342
1343 helper1.StartTransaction(transaction_factory_.get(), kT1HostName, kT1Qtype,
1344 false /* secure */, resolve_context_.get());
1345 helper1.RunUntilComplete();
1346
1347 size_t kOrder[] = {
1348 // The first transaction.
1349 0,
1350 1,
1351 2,
1352 0,
1353 1,
1354 // The second transaction starts from the next server, and 0 is skipped
1355 // because it already has 2 consecutive failures.
1356 1,
1357 2,
1358 1,
1359 };
1360 CheckServerOrder(kOrder, std::size(kOrder));
1361 }
1362
TEST_F(DnsTransactionTest,SuffixSearchAboveNdots)1363 TEST_F(DnsTransactionTest, SuffixSearchAboveNdots) {
1364 config_.ndots = 2;
1365 config_.search.push_back("a");
1366 config_.search.push_back("b");
1367 config_.search.push_back("c");
1368 config_.rotate = true;
1369 ConfigureNumServers(2);
1370 ConfigureFactory();
1371
1372 AddAsyncQueryAndRcode("x.y.z", dns_protocol::kTypeA,
1373 dns_protocol::kRcodeNXDOMAIN);
1374 AddAsyncQueryAndRcode("x.y.z.a", dns_protocol::kTypeA,
1375 dns_protocol::kRcodeNXDOMAIN);
1376 AddAsyncQueryAndRcode("x.y.z.b", dns_protocol::kTypeA,
1377 dns_protocol::kRcodeNXDOMAIN);
1378 AddAsyncQueryAndRcode("x.y.z.c", dns_protocol::kTypeA,
1379 dns_protocol::kRcodeNXDOMAIN);
1380
1381 TransactionHelper helper0(ERR_NAME_NOT_RESOLVED);
1382
1383 helper0.StartTransaction(transaction_factory_.get(), "x.y.z",
1384 dns_protocol::kTypeA, false /* secure */,
1385 resolve_context_.get());
1386 helper0.RunUntilComplete();
1387
1388 // Also check if suffix search causes server rotation.
1389 size_t kOrder0[] = {0, 1, 0, 1};
1390 CheckServerOrder(kOrder0, std::size(kOrder0));
1391 }
1392
TEST_F(DnsTransactionTest,SuffixSearchBelowNdots)1393 TEST_F(DnsTransactionTest, SuffixSearchBelowNdots) {
1394 config_.ndots = 2;
1395 config_.search.push_back("a");
1396 config_.search.push_back("b");
1397 config_.search.push_back("c");
1398 ConfigureFactory();
1399
1400 // Responses for first transaction.
1401 AddAsyncQueryAndRcode("x.y.a", dns_protocol::kTypeA,
1402 dns_protocol::kRcodeNXDOMAIN);
1403 AddAsyncQueryAndRcode("x.y.b", dns_protocol::kTypeA,
1404 dns_protocol::kRcodeNXDOMAIN);
1405 AddAsyncQueryAndRcode("x.y.c", dns_protocol::kTypeA,
1406 dns_protocol::kRcodeNXDOMAIN);
1407 AddAsyncQueryAndRcode("x.y", dns_protocol::kTypeA,
1408 dns_protocol::kRcodeNXDOMAIN);
1409 // Responses for second transaction.
1410 AddAsyncQueryAndRcode("x.a", dns_protocol::kTypeA,
1411 dns_protocol::kRcodeNXDOMAIN);
1412 AddAsyncQueryAndRcode("x.b", dns_protocol::kTypeA,
1413 dns_protocol::kRcodeNXDOMAIN);
1414 AddAsyncQueryAndRcode("x.c", dns_protocol::kTypeA,
1415 dns_protocol::kRcodeNXDOMAIN);
1416 // Responses for third transaction.
1417 AddAsyncQueryAndRcode("x", dns_protocol::kTypeAAAA,
1418 dns_protocol::kRcodeNXDOMAIN);
1419
1420 TransactionHelper helper0(ERR_NAME_NOT_RESOLVED);
1421 helper0.StartTransaction(transaction_factory_.get(), "x.y",
1422 dns_protocol::kTypeA, false /* secure */,
1423 resolve_context_.get());
1424 helper0.RunUntilComplete();
1425
1426 // A single-label name.
1427 TransactionHelper helper1(ERR_NAME_NOT_RESOLVED);
1428 helper1.StartTransaction(transaction_factory_.get(), "x",
1429 dns_protocol::kTypeA, false /* secure */,
1430 resolve_context_.get());
1431 helper1.RunUntilComplete();
1432
1433 // A fully-qualified name.
1434 TransactionHelper helper2(ERR_NAME_NOT_RESOLVED);
1435 helper2.StartTransaction(transaction_factory_.get(), "x.",
1436 dns_protocol::kTypeAAAA, false /* secure */,
1437 resolve_context_.get());
1438 helper2.RunUntilComplete();
1439 }
1440
TEST_F(DnsTransactionTest,EmptySuffixSearch)1441 TEST_F(DnsTransactionTest, EmptySuffixSearch) {
1442 // Responses for first transaction.
1443 AddAsyncQueryAndRcode("x", dns_protocol::kTypeA,
1444 dns_protocol::kRcodeNXDOMAIN);
1445
1446 // A fully-qualified name.
1447 TransactionHelper helper0(ERR_NAME_NOT_RESOLVED);
1448 helper0.StartTransaction(transaction_factory_.get(), "x.",
1449 dns_protocol::kTypeA, false /* secure */,
1450 resolve_context_.get());
1451 helper0.RunUntilComplete();
1452
1453 // A single label name is not even attempted.
1454 TransactionHelper helper1(ERR_DNS_SEARCH_EMPTY);
1455 helper1.StartTransaction(transaction_factory_.get(), "singlelabel",
1456 dns_protocol::kTypeA, false /* secure */,
1457 resolve_context_.get());
1458 helper1.RunUntilComplete();
1459 }
1460
TEST_F(DnsTransactionTest,DontAppendToMultiLabelName)1461 TEST_F(DnsTransactionTest, DontAppendToMultiLabelName) {
1462 config_.search.push_back("a");
1463 config_.search.push_back("b");
1464 config_.search.push_back("c");
1465 config_.append_to_multi_label_name = false;
1466 ConfigureFactory();
1467
1468 // Responses for first transaction.
1469 AddAsyncQueryAndRcode("x.y.z", dns_protocol::kTypeA,
1470 dns_protocol::kRcodeNXDOMAIN);
1471 // Responses for second transaction.
1472 AddAsyncQueryAndRcode("x.y", dns_protocol::kTypeA,
1473 dns_protocol::kRcodeNXDOMAIN);
1474 // Responses for third transaction.
1475 AddAsyncQueryAndRcode("x.a", dns_protocol::kTypeA,
1476 dns_protocol::kRcodeNXDOMAIN);
1477 AddAsyncQueryAndRcode("x.b", dns_protocol::kTypeA,
1478 dns_protocol::kRcodeNXDOMAIN);
1479 AddAsyncQueryAndRcode("x.c", dns_protocol::kTypeA,
1480 dns_protocol::kRcodeNXDOMAIN);
1481
1482 TransactionHelper helper0(ERR_NAME_NOT_RESOLVED);
1483 helper0.StartTransaction(transaction_factory_.get(), "x.y.z",
1484 dns_protocol::kTypeA, false /* secure */,
1485 resolve_context_.get());
1486 helper0.RunUntilComplete();
1487
1488 TransactionHelper helper1(ERR_NAME_NOT_RESOLVED);
1489 helper1.StartTransaction(transaction_factory_.get(), "x.y",
1490 dns_protocol::kTypeA, false /* secure */,
1491 resolve_context_.get());
1492 helper1.RunUntilComplete();
1493
1494 TransactionHelper helper2(ERR_NAME_NOT_RESOLVED);
1495 helper2.StartTransaction(transaction_factory_.get(), "x",
1496 dns_protocol::kTypeA, false /* secure */,
1497 resolve_context_.get());
1498 helper2.RunUntilComplete();
1499 }
1500
1501 const uint8_t kResponseNoData[] = {
1502 0x00, 0x00, 0x81, 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
1503 // Question
1504 0x01, 'x', 0x01, 'y', 0x01, 'z', 0x01, 'b', 0x00, 0x00, 0x01, 0x00, 0x01,
1505 // Authority section, SOA record, TTL 0x3E6
1506 0x01, 'z', 0x00, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x03, 0xE6,
1507 // Minimal RDATA, 18 bytes
1508 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1509 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1510 };
1511
TEST_F(DnsTransactionTest,SuffixSearchStop)1512 TEST_F(DnsTransactionTest, SuffixSearchStop) {
1513 config_.ndots = 2;
1514 config_.search.push_back("a");
1515 config_.search.push_back("b");
1516 config_.search.push_back("c");
1517 ConfigureFactory();
1518
1519 AddAsyncQueryAndRcode("x.y.z", dns_protocol::kTypeA,
1520 dns_protocol::kRcodeNXDOMAIN);
1521 AddAsyncQueryAndRcode("x.y.z.a", dns_protocol::kTypeA,
1522 dns_protocol::kRcodeNXDOMAIN);
1523 AddAsyncQueryAndResponse(0 /* id */, "x.y.z.b", dns_protocol::kTypeA,
1524 kResponseNoData, std::size(kResponseNoData));
1525
1526 TransactionHelper helper0(0 /* answers */);
1527
1528 helper0.StartTransaction(transaction_factory_.get(), "x.y.z",
1529 dns_protocol::kTypeA, false /* secure */,
1530 resolve_context_.get());
1531 helper0.RunUntilComplete();
1532 }
1533
TEST_F(DnsTransactionTest,SyncFirstQuery)1534 TEST_F(DnsTransactionTest, SyncFirstQuery) {
1535 config_.search.push_back("lab.ccs.neu.edu");
1536 config_.search.push_back("ccs.neu.edu");
1537 ConfigureFactory();
1538
1539 AddSyncQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype,
1540 kT0ResponseDatagram, std::size(kT0ResponseDatagram));
1541
1542 TransactionHelper helper0(kT0RecordCount);
1543 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
1544 false /* secure */, resolve_context_.get());
1545 helper0.RunUntilComplete();
1546 }
1547
TEST_F(DnsTransactionTest,SyncFirstQueryWithSearch)1548 TEST_F(DnsTransactionTest, SyncFirstQueryWithSearch) {
1549 config_.search.push_back("lab.ccs.neu.edu");
1550 config_.search.push_back("ccs.neu.edu");
1551 ConfigureFactory();
1552
1553 AddSyncQueryAndRcode("www.lab.ccs.neu.edu", kT2Qtype,
1554 dns_protocol::kRcodeNXDOMAIN);
1555 // "www.ccs.neu.edu"
1556 AddAsyncQueryAndResponse(2 /* id */, kT2HostName, kT2Qtype,
1557 kT2ResponseDatagram, std::size(kT2ResponseDatagram));
1558
1559 TransactionHelper helper0(kT2RecordCount);
1560 helper0.StartTransaction(transaction_factory_.get(), "www", kT2Qtype,
1561 false /* secure */, resolve_context_.get());
1562 helper0.RunUntilComplete();
1563 }
1564
TEST_F(DnsTransactionTest,SyncSearchQuery)1565 TEST_F(DnsTransactionTest, SyncSearchQuery) {
1566 config_.search.push_back("lab.ccs.neu.edu");
1567 config_.search.push_back("ccs.neu.edu");
1568 ConfigureFactory();
1569
1570 AddAsyncQueryAndRcode("www.lab.ccs.neu.edu", dns_protocol::kTypeA,
1571 dns_protocol::kRcodeNXDOMAIN);
1572 AddSyncQueryAndResponse(2 /* id */, kT2HostName, kT2Qtype,
1573 kT2ResponseDatagram, std::size(kT2ResponseDatagram));
1574
1575 TransactionHelper helper0(kT2RecordCount);
1576 helper0.StartTransaction(transaction_factory_.get(), "www", kT2Qtype,
1577 false /* secure */, resolve_context_.get());
1578 helper0.RunUntilComplete();
1579 }
1580
TEST_F(DnsTransactionTest,ConnectFailure)1581 TEST_F(DnsTransactionTest, ConnectFailure) {
1582 // Prep socket factory for a single socket with connection failure.
1583 MockConnect connect_data;
1584 connect_data.result = ERR_FAILED;
1585 StaticSocketDataProvider data_provider;
1586 data_provider.set_connect_data(connect_data);
1587 socket_factory_->AddSocketDataProvider(&data_provider);
1588
1589 transaction_ids_.push_back(0); // Needed to make a DnsUDPAttempt.
1590 TransactionHelper helper0(ERR_CONNECTION_REFUSED);
1591
1592 helper0.StartTransaction(transaction_factory_.get(), "www.chromium.org",
1593 dns_protocol::kTypeA, false /* secure */,
1594 resolve_context_.get());
1595 helper0.RunUntilComplete();
1596
1597 EXPECT_FALSE(helper0.response());
1598 EXPECT_FALSE(session_->udp_tracker()->low_entropy());
1599 }
1600
TEST_F(DnsTransactionTest,ConnectFailure_SocketLimitReached)1601 TEST_F(DnsTransactionTest, ConnectFailure_SocketLimitReached) {
1602 // Prep socket factory for a single socket with connection failure.
1603 MockConnect connect_data;
1604 connect_data.result = ERR_INSUFFICIENT_RESOURCES;
1605 StaticSocketDataProvider data_provider;
1606 data_provider.set_connect_data(connect_data);
1607 socket_factory_->AddSocketDataProvider(&data_provider);
1608
1609 transaction_ids_.push_back(0); // Needed to make a DnsUDPAttempt.
1610 TransactionHelper helper0(ERR_CONNECTION_REFUSED);
1611
1612 helper0.StartTransaction(transaction_factory_.get(), "www.chromium.org",
1613 dns_protocol::kTypeA, false /* secure */,
1614 resolve_context_.get());
1615 helper0.RunUntilComplete();
1616
1617 EXPECT_FALSE(helper0.response());
1618 EXPECT_TRUE(session_->udp_tracker()->low_entropy());
1619 }
1620
TEST_F(DnsTransactionTest,ConnectFailureFollowedBySuccess)1621 TEST_F(DnsTransactionTest, ConnectFailureFollowedBySuccess) {
1622 // Retry after server failure.
1623 config_.attempts = 2;
1624 ConfigureFactory();
1625 // First server connection attempt fails.
1626 transaction_ids_.push_back(0); // Needed to make a DnsUDPAttempt.
1627 socket_factory_->fail_next_socket_ = true;
1628 // Second DNS query succeeds.
1629 AddAsyncQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype,
1630 kT0ResponseDatagram, std::size(kT0ResponseDatagram));
1631 TransactionHelper helper0(kT0RecordCount);
1632 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
1633 false /* secure */, resolve_context_.get());
1634 helper0.RunUntilComplete();
1635 }
1636
TEST_F(DnsTransactionTest,HttpsGetLookup)1637 TEST_F(DnsTransactionTest, HttpsGetLookup) {
1638 ConfigureDohServers(false /* use_post */);
1639 AddQueryAndResponse(0, kT0HostName, kT0Qtype, kT0ResponseDatagram,
1640 std::size(kT0ResponseDatagram), SYNCHRONOUS,
1641 Transport::HTTPS, nullptr /* opt_rdata */,
1642 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
1643 false /* enqueue_transaction_id */);
1644 TransactionHelper helper0(kT0RecordCount);
1645 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
1646 true /* secure */, resolve_context_.get());
1647 helper0.RunUntilComplete();
1648 }
1649
TEST_F(DnsTransactionTest,HttpsGetFailure)1650 TEST_F(DnsTransactionTest, HttpsGetFailure) {
1651 ConfigureDohServers(false /* use_post */);
1652 AddQueryAndRcode(kT0HostName, kT0Qtype, dns_protocol::kRcodeSERVFAIL,
1653 SYNCHRONOUS, Transport::HTTPS,
1654 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128, 0 /* id */,
1655 false /* enqueue_transaction_id */);
1656
1657 TransactionHelper helper0(ERR_DNS_SERVER_FAILED);
1658 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
1659 true /* secure */, resolve_context_.get());
1660 helper0.RunUntilComplete();
1661 ASSERT_NE(helper0.response(), nullptr);
1662 EXPECT_EQ(helper0.response()->rcode(), dns_protocol::kRcodeSERVFAIL);
1663 }
1664
TEST_F(DnsTransactionTest,HttpsGetMalformed)1665 TEST_F(DnsTransactionTest, HttpsGetMalformed) {
1666 ConfigureDohServers(false /* use_post */);
1667 // Use T1 response, which is malformed for a T0 request.
1668 AddQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype, kT1ResponseDatagram,
1669 std::size(kT1ResponseDatagram), SYNCHRONOUS,
1670 Transport::HTTPS, nullptr /* opt_rdata */,
1671 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
1672 false /* enqueue_transaction_id */);
1673 TransactionHelper helper0(ERR_DNS_MALFORMED_RESPONSE);
1674 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
1675 true /* secure */, resolve_context_.get());
1676 helper0.RunUntilComplete();
1677 }
1678
TEST_F(DnsTransactionTest,HttpsPostLookup)1679 TEST_F(DnsTransactionTest, HttpsPostLookup) {
1680 ConfigureDohServers(true /* use_post */);
1681 AddQueryAndResponse(0, kT0HostName, kT0Qtype, kT0ResponseDatagram,
1682 std::size(kT0ResponseDatagram), SYNCHRONOUS,
1683 Transport::HTTPS, nullptr /* opt_rdata */,
1684 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
1685 false /* enqueue_transaction_id */);
1686 TransactionHelper helper0(kT0RecordCount);
1687 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
1688 true /* secure */, resolve_context_.get());
1689 helper0.RunUntilComplete();
1690 }
1691
TEST_F(DnsTransactionTest,HttpsPostFailure)1692 TEST_F(DnsTransactionTest, HttpsPostFailure) {
1693 ConfigureDohServers(true /* use_post */);
1694 AddQueryAndRcode(kT0HostName, kT0Qtype, dns_protocol::kRcodeSERVFAIL,
1695 SYNCHRONOUS, Transport::HTTPS,
1696 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128, 0 /* id */,
1697 false /* enqueue_transaction_id */);
1698
1699 TransactionHelper helper0(ERR_DNS_SERVER_FAILED);
1700 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
1701 true /* secure */, resolve_context_.get());
1702 helper0.RunUntilComplete();
1703 ASSERT_NE(helper0.response(), nullptr);
1704 EXPECT_EQ(helper0.response()->rcode(), dns_protocol::kRcodeSERVFAIL);
1705 }
1706
TEST_F(DnsTransactionTest,HttpsPostMalformed)1707 TEST_F(DnsTransactionTest, HttpsPostMalformed) {
1708 ConfigureDohServers(true /* use_post */);
1709 // Use T1 response, which is malformed for a T0 request.
1710 AddQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype, kT1ResponseDatagram,
1711 std::size(kT1ResponseDatagram), SYNCHRONOUS,
1712 Transport::HTTPS, nullptr /* opt_rdata */,
1713 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
1714 false /* enqueue_transaction_id */);
1715
1716 TransactionHelper helper0(ERR_DNS_MALFORMED_RESPONSE);
1717 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
1718 true /* secure */, resolve_context_.get());
1719 helper0.RunUntilComplete();
1720 }
1721
TEST_F(DnsTransactionTest,HttpsPostLookupAsync)1722 TEST_F(DnsTransactionTest, HttpsPostLookupAsync) {
1723 ConfigureDohServers(true /* use_post */);
1724 AddQueryAndResponse(0, kT0HostName, kT0Qtype, kT0ResponseDatagram,
1725 std::size(kT0ResponseDatagram), ASYNC, Transport::HTTPS,
1726 nullptr /* opt_rdata */,
1727 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
1728 false /* enqueue_transaction_id */);
1729 TransactionHelper helper0(kT0RecordCount);
1730 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
1731 true /* secure */, resolve_context_.get());
1732 helper0.RunUntilComplete();
1733 }
1734
DohJobMakerCallbackFailLookup(URLRequest * request,SocketDataProvider * data)1735 std::unique_ptr<URLRequestJob> DohJobMakerCallbackFailLookup(
1736 URLRequest* request,
1737 SocketDataProvider* data) {
1738 URLRequestMockDohJob::MatchQueryData(request, data);
1739 return std::make_unique<URLRequestFailedJob>(
1740 request, URLRequestFailedJob::START, ERR_NAME_NOT_RESOLVED);
1741 }
1742
TEST_F(DnsTransactionTest,HttpsPostLookupFailDohServerLookup)1743 TEST_F(DnsTransactionTest, HttpsPostLookupFailDohServerLookup) {
1744 ConfigureDohServers(true /* use_post */);
1745 AddQueryAndResponse(0, kT0HostName, kT0Qtype, kT0ResponseDatagram,
1746 std::size(kT0ResponseDatagram), SYNCHRONOUS,
1747 Transport::HTTPS, nullptr /* opt_rdata */,
1748 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
1749 false /* enqueue_transaction_id */);
1750 TransactionHelper helper0(ERR_DNS_SECURE_RESOLVER_HOSTNAME_RESOLUTION_FAILED);
1751 SetDohJobMakerCallback(base::BindRepeating(DohJobMakerCallbackFailLookup));
1752 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
1753 true /* secure */, resolve_context_.get());
1754 helper0.RunUntilComplete();
1755 }
1756
DohJobMakerCallbackFailStart(URLRequest * request,SocketDataProvider * data)1757 std::unique_ptr<URLRequestJob> DohJobMakerCallbackFailStart(
1758 URLRequest* request,
1759 SocketDataProvider* data) {
1760 URLRequestMockDohJob::MatchQueryData(request, data);
1761 return std::make_unique<URLRequestFailedJob>(
1762 request, URLRequestFailedJob::START, ERR_FAILED);
1763 }
1764
TEST_F(DnsTransactionTest,HttpsPostLookupFailStart)1765 TEST_F(DnsTransactionTest, HttpsPostLookupFailStart) {
1766 ConfigureDohServers(true /* use_post */);
1767 AddQueryAndResponse(0, kT0HostName, kT0Qtype, kT0ResponseDatagram,
1768 std::size(kT0ResponseDatagram), SYNCHRONOUS,
1769 Transport::HTTPS, nullptr /* opt_rdata */,
1770 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
1771 false /* enqueue_transaction_id */);
1772 TransactionHelper helper0(ERR_FAILED);
1773 SetDohJobMakerCallback(base::BindRepeating(DohJobMakerCallbackFailStart));
1774 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
1775 true /* secure */, resolve_context_.get());
1776 helper0.RunUntilComplete();
1777 }
1778
DohJobMakerCallbackFailSync(URLRequest * request,SocketDataProvider * data)1779 std::unique_ptr<URLRequestJob> DohJobMakerCallbackFailSync(
1780 URLRequest* request,
1781 SocketDataProvider* data) {
1782 URLRequestMockDohJob::MatchQueryData(request, data);
1783 return std::make_unique<URLRequestFailedJob>(
1784 request, URLRequestFailedJob::READ_SYNC, ERR_FAILED);
1785 }
1786
TEST_F(DnsTransactionTest,HttpsPostLookupFailSync)1787 TEST_F(DnsTransactionTest, HttpsPostLookupFailSync) {
1788 ConfigureDohServers(true /* use_post */);
1789 auto data = std::make_unique<DnsSocketData>(
1790 0, kT0HostName, kT0Qtype, SYNCHRONOUS, Transport::HTTPS,
1791 nullptr /* opt_rdata */, DnsQuery::PaddingStrategy::BLOCK_LENGTH_128);
1792 data->AddResponseWithLength(std::make_unique<DnsResponse>(), SYNCHRONOUS, 0);
1793 AddSocketData(std::move(data), false /* enqueue_transaction_id */);
1794 TransactionHelper helper0(ERR_DNS_MALFORMED_RESPONSE);
1795 SetDohJobMakerCallback(base::BindRepeating(DohJobMakerCallbackFailSync));
1796 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
1797 true /* secure */, resolve_context_.get());
1798 helper0.RunUntilComplete();
1799 }
1800
DohJobMakerCallbackFailAsync(URLRequest * request,SocketDataProvider * data)1801 std::unique_ptr<URLRequestJob> DohJobMakerCallbackFailAsync(
1802 URLRequest* request,
1803 SocketDataProvider* data) {
1804 URLRequestMockDohJob::MatchQueryData(request, data);
1805 return std::make_unique<URLRequestFailedJob>(
1806 request, URLRequestFailedJob::READ_ASYNC, ERR_FAILED);
1807 }
1808
TEST_F(DnsTransactionTest,HttpsPostLookupFailAsync)1809 TEST_F(DnsTransactionTest, HttpsPostLookupFailAsync) {
1810 ConfigureDohServers(true /* use_post */);
1811 AddQueryAndResponse(0, kT0HostName, kT0Qtype, kT0ResponseDatagram,
1812 std::size(kT0ResponseDatagram), SYNCHRONOUS,
1813 Transport::HTTPS, nullptr /* opt_rdata */,
1814 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
1815 false /* enqueue_transaction_id */);
1816 TransactionHelper helper0(ERR_DNS_MALFORMED_RESPONSE);
1817 SetDohJobMakerCallback(base::BindRepeating(DohJobMakerCallbackFailAsync));
1818 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
1819 true /* secure */, resolve_context_.get());
1820 helper0.RunUntilComplete();
1821 }
1822
TEST_F(DnsTransactionTest,HttpsPostLookup2Sync)1823 TEST_F(DnsTransactionTest, HttpsPostLookup2Sync) {
1824 ConfigureDohServers(true /* use_post */);
1825 auto data = std::make_unique<DnsSocketData>(
1826 0, kT0HostName, kT0Qtype, SYNCHRONOUS, Transport::HTTPS,
1827 nullptr /* opt_rdata */, DnsQuery::PaddingStrategy::BLOCK_LENGTH_128);
1828 data->AddResponseData(kT0ResponseDatagram, 20, SYNCHRONOUS);
1829 data->AddResponseData(kT0ResponseDatagram + 20,
1830 std::size(kT0ResponseDatagram) - 20, SYNCHRONOUS);
1831 AddSocketData(std::move(data), false /* enqueue_transaction_id */);
1832 TransactionHelper helper0(kT0RecordCount);
1833 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
1834 true /* secure */, resolve_context_.get());
1835 helper0.RunUntilComplete();
1836 }
1837
TEST_F(DnsTransactionTest,HttpsPostLookup2Async)1838 TEST_F(DnsTransactionTest, HttpsPostLookup2Async) {
1839 ConfigureDohServers(true /* use_post */);
1840 auto data = std::make_unique<DnsSocketData>(
1841 0, kT0HostName, kT0Qtype, SYNCHRONOUS, Transport::HTTPS,
1842 nullptr /* opt_rdata */, DnsQuery::PaddingStrategy::BLOCK_LENGTH_128);
1843 data->AddResponseData(kT0ResponseDatagram, 20, ASYNC);
1844 data->AddResponseData(kT0ResponseDatagram + 20,
1845 std::size(kT0ResponseDatagram) - 20, ASYNC);
1846 AddSocketData(std::move(data), false /* enqueue_transaction_id */);
1847 TransactionHelper helper0(kT0RecordCount);
1848 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
1849 true /* secure */, resolve_context_.get());
1850 helper0.RunUntilComplete();
1851 }
1852
TEST_F(DnsTransactionTest,HttpsPostLookupAsyncWithAsyncZeroRead)1853 TEST_F(DnsTransactionTest, HttpsPostLookupAsyncWithAsyncZeroRead) {
1854 ConfigureDohServers(true /* use_post */);
1855 auto data = std::make_unique<DnsSocketData>(
1856 0, kT0HostName, kT0Qtype, SYNCHRONOUS, Transport::HTTPS,
1857 nullptr /* opt_rdata */, DnsQuery::PaddingStrategy::BLOCK_LENGTH_128);
1858 data->AddResponseData(kT0ResponseDatagram, std::size(kT0ResponseDatagram),
1859 ASYNC);
1860 data->AddResponseData(kT0ResponseDatagram, 0, ASYNC);
1861 AddSocketData(std::move(data), false /* enqueue_transaction_id */);
1862 TransactionHelper helper0(kT0RecordCount);
1863 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
1864 true /* secure */, resolve_context_.get());
1865 helper0.RunUntilComplete();
1866 }
1867
TEST_F(DnsTransactionTest,HttpsPostLookupSyncWithAsyncZeroRead)1868 TEST_F(DnsTransactionTest, HttpsPostLookupSyncWithAsyncZeroRead) {
1869 ConfigureDohServers(true /* use_post */);
1870 auto data = std::make_unique<DnsSocketData>(
1871 0, kT0HostName, kT0Qtype, SYNCHRONOUS, Transport::HTTPS,
1872 nullptr /* opt_rdata */, DnsQuery::PaddingStrategy::BLOCK_LENGTH_128);
1873 data->AddResponseData(kT0ResponseDatagram, std::size(kT0ResponseDatagram),
1874 SYNCHRONOUS);
1875 data->AddResponseData(kT0ResponseDatagram, 0, ASYNC);
1876 AddSocketData(std::move(data), false /* enqueue_transaction_id */);
1877 TransactionHelper helper0(kT0RecordCount);
1878 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
1879 true /* secure */, resolve_context_.get());
1880 helper0.RunUntilComplete();
1881 }
1882
TEST_F(DnsTransactionTest,HttpsPostLookupAsyncThenSync)1883 TEST_F(DnsTransactionTest, HttpsPostLookupAsyncThenSync) {
1884 ConfigureDohServers(true /* use_post */);
1885 auto data = std::make_unique<DnsSocketData>(
1886 0, kT0HostName, kT0Qtype, SYNCHRONOUS, Transport::HTTPS,
1887 nullptr /* opt_rdata */, DnsQuery::PaddingStrategy::BLOCK_LENGTH_128);
1888 data->AddResponseData(kT0ResponseDatagram, 20, ASYNC);
1889 data->AddResponseData(kT0ResponseDatagram + 20,
1890 std::size(kT0ResponseDatagram) - 20, SYNCHRONOUS);
1891 AddSocketData(std::move(data), false /* enqueue_transaction_id */);
1892 TransactionHelper helper0(kT0RecordCount);
1893 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
1894 true /* secure */, resolve_context_.get());
1895 helper0.RunUntilComplete();
1896 }
1897
TEST_F(DnsTransactionTest,HttpsPostLookupAsyncThenSyncError)1898 TEST_F(DnsTransactionTest, HttpsPostLookupAsyncThenSyncError) {
1899 ConfigureDohServers(true /* use_post */);
1900 auto data = std::make_unique<DnsSocketData>(
1901 0, kT0HostName, kT0Qtype, SYNCHRONOUS, Transport::HTTPS,
1902 nullptr /* opt_rdata */, DnsQuery::PaddingStrategy::BLOCK_LENGTH_128);
1903 data->AddResponseData(kT0ResponseDatagram, 20, ASYNC);
1904 data->AddReadError(ERR_FAILED, SYNCHRONOUS);
1905 AddSocketData(std::move(data), false /* enqueue_transaction_id */);
1906 TransactionHelper helper0(ERR_FAILED);
1907 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
1908 true /* secure */, resolve_context_.get());
1909 helper0.RunUntilComplete();
1910 }
1911
TEST_F(DnsTransactionTest,HttpsPostLookupAsyncThenAsyncError)1912 TEST_F(DnsTransactionTest, HttpsPostLookupAsyncThenAsyncError) {
1913 ConfigureDohServers(true /* use_post */);
1914 auto data = std::make_unique<DnsSocketData>(
1915 0, kT0HostName, kT0Qtype, SYNCHRONOUS, Transport::HTTPS,
1916 nullptr /* opt_rdata */, DnsQuery::PaddingStrategy::BLOCK_LENGTH_128);
1917 data->AddResponseData(kT0ResponseDatagram, 20, ASYNC);
1918 data->AddReadError(ERR_FAILED, ASYNC);
1919 AddSocketData(std::move(data), false /* enqueue_transaction_id */);
1920 TransactionHelper helper0(ERR_FAILED);
1921 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
1922 true /* secure */, resolve_context_.get());
1923 helper0.RunUntilComplete();
1924 }
1925
TEST_F(DnsTransactionTest,HttpsPostLookupSyncThenAsyncError)1926 TEST_F(DnsTransactionTest, HttpsPostLookupSyncThenAsyncError) {
1927 ConfigureDohServers(true /* use_post */);
1928 auto data = std::make_unique<DnsSocketData>(
1929 0, kT0HostName, kT0Qtype, SYNCHRONOUS, Transport::HTTPS,
1930 nullptr /* opt_rdata */, DnsQuery::PaddingStrategy::BLOCK_LENGTH_128);
1931 data->AddResponseData(kT0ResponseDatagram, 20, SYNCHRONOUS);
1932 data->AddReadError(ERR_FAILED, ASYNC);
1933 AddSocketData(std::move(data), false /* enqueue_transaction_id */);
1934 TransactionHelper helper0(ERR_FAILED);
1935 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
1936 true /* secure */, resolve_context_.get());
1937 helper0.RunUntilComplete();
1938 }
1939
TEST_F(DnsTransactionTest,HttpsPostLookupSyncThenSyncError)1940 TEST_F(DnsTransactionTest, HttpsPostLookupSyncThenSyncError) {
1941 ConfigureDohServers(true /* use_post */);
1942 auto data = std::make_unique<DnsSocketData>(
1943 0, kT0HostName, kT0Qtype, SYNCHRONOUS, Transport::HTTPS,
1944 nullptr /* opt_rdata */, DnsQuery::PaddingStrategy::BLOCK_LENGTH_128);
1945 data->AddResponseData(kT0ResponseDatagram, 20, SYNCHRONOUS);
1946 data->AddReadError(ERR_FAILED, SYNCHRONOUS);
1947 AddSocketData(std::move(data), false /* enqueue_transaction_id */);
1948 TransactionHelper helper0(ERR_FAILED);
1949 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
1950 true /* secure */, resolve_context_.get());
1951 helper0.RunUntilComplete();
1952 }
1953
TEST_F(DnsTransactionTest,HttpsNotAvailable)1954 TEST_F(DnsTransactionTest, HttpsNotAvailable) {
1955 ConfigureDohServers(true /* use_post */, 1 /* num_doh_servers */,
1956 false /* make_available */);
1957 ASSERT_FALSE(resolve_context_->GetDohServerAvailability(
1958 0u /* doh_server_index */, session_.get()));
1959
1960 TransactionHelper helper0(ERR_BLOCKED_BY_CLIENT);
1961 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
1962 true /* secure */, resolve_context_.get());
1963 helper0.RunUntilComplete();
1964 }
1965
TEST_F(DnsTransactionTest,HttpsMarkHttpsBad)1966 TEST_F(DnsTransactionTest, HttpsMarkHttpsBad) {
1967 config_.attempts = 1;
1968 ConfigureDohServers(true /* use_post */, 3);
1969 AddQueryAndErrorResponse(0, kT0HostName, kT0Qtype, ERR_CONNECTION_REFUSED,
1970 SYNCHRONOUS, Transport::HTTPS,
1971 nullptr /* opt_rdata */,
1972 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
1973 false /* enqueue_transaction_id */);
1974 AddQueryAndErrorResponse(0, kT0HostName, kT0Qtype, ERR_CONNECTION_REFUSED,
1975 SYNCHRONOUS, Transport::HTTPS,
1976 nullptr /* opt_rdata */,
1977 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
1978 false /* enqueue_transaction_id */);
1979 AddQueryAndResponse(0, kT0HostName, kT0Qtype, kT0ResponseDatagram,
1980 std::size(kT0ResponseDatagram), ASYNC, Transport::HTTPS,
1981 nullptr /* opt_rdata */,
1982 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
1983 false /* enqueue_transaction_id */);
1984 AddQueryAndErrorResponse(0 /* id */, kT0HostName, kT0Qtype,
1985 ERR_CONNECTION_REFUSED, SYNCHRONOUS,
1986 Transport::HTTPS, nullptr /* opt_rdata */,
1987 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
1988 false /* enqueue_transaction_id */);
1989 AddQueryAndErrorResponse(0 /* id */, kT0HostName, kT0Qtype,
1990 ERR_CONNECTION_REFUSED, SYNCHRONOUS,
1991 Transport::HTTPS, nullptr /* opt_rdata */,
1992 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
1993 false /* enqueue_transaction_id */);
1994 AddQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype, kT0ResponseDatagram,
1995 std::size(kT0ResponseDatagram), ASYNC, Transport::HTTPS,
1996 nullptr /* opt_rdata */,
1997 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
1998 false /* enqueue_transaction_id */);
1999
2000 TransactionHelper helper0(kT0RecordCount);
2001 TransactionHelper helper1(kT0RecordCount);
2002
2003 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
2004 true /* secure */, resolve_context_.get());
2005 helper0.RunUntilComplete();
2006
2007 // UDP server 0 is our only UDP server, so it will be good. HTTPS
2008 // servers 0 and 1 failed and will be marked bad. HTTPS server 2 succeeded
2009 // so it will be good.
2010 // The expected order of the HTTPS servers is therefore 2, 0, then 1.
2011 {
2012 std::unique_ptr<DnsServerIterator> classic_itr =
2013 resolve_context_->GetClassicDnsIterator(session_->config(),
2014 session_.get());
2015 std::unique_ptr<DnsServerIterator> doh_itr =
2016 resolve_context_->GetDohIterator(
2017 session_->config(), SecureDnsMode::kAutomatic, session_.get());
2018 EXPECT_TRUE(classic_itr->AttemptAvailable());
2019 EXPECT_EQ(classic_itr->GetNextAttemptIndex(), 0u);
2020 ASSERT_TRUE(doh_itr->AttemptAvailable());
2021 EXPECT_EQ(doh_itr->GetNextAttemptIndex(), 2u);
2022 ASSERT_TRUE(doh_itr->AttemptAvailable());
2023 EXPECT_EQ(doh_itr->GetNextAttemptIndex(), 0u);
2024 ASSERT_TRUE(doh_itr->AttemptAvailable());
2025 EXPECT_EQ(doh_itr->GetNextAttemptIndex(), 1u);
2026 }
2027 size_t kOrder0[] = {1, 2, 3};
2028 CheckServerOrder(kOrder0, std::size(kOrder0));
2029
2030 helper1.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
2031 true /* secure */, resolve_context_.get());
2032 helper1.RunUntilComplete();
2033 // UDP server 0 is still our only UDP server, so it will be good by
2034 // definition. HTTPS server 2 started out as good, so it was tried first and
2035 // failed. HTTPS server 0 then had the oldest failure so it would be the next
2036 // good server and then it failed so it's marked bad. Next attempt was HTTPS
2037 // server 1, which succeeded so it's good. The expected order of the HTTPS
2038 // servers is therefore 1, 2, then 0.
2039
2040 {
2041 std::unique_ptr<DnsServerIterator> classic_itr =
2042 resolve_context_->GetClassicDnsIterator(session_->config(),
2043 session_.get());
2044 std::unique_ptr<DnsServerIterator> doh_itr =
2045 resolve_context_->GetDohIterator(
2046 session_->config(), SecureDnsMode::kAutomatic, session_.get());
2047
2048 EXPECT_EQ(classic_itr->GetNextAttemptIndex(), 0u);
2049 ASSERT_TRUE(doh_itr->AttemptAvailable());
2050 EXPECT_EQ(doh_itr->GetNextAttemptIndex(), 1u);
2051 EXPECT_EQ(doh_itr->GetNextAttemptIndex(), 2u);
2052 EXPECT_EQ(doh_itr->GetNextAttemptIndex(), 0u);
2053 }
2054
2055 size_t kOrder1[] = {
2056 1, 2, 3, /* transaction0 */
2057 3, 1, 2 /* transaction1 */
2058 };
2059 CheckServerOrder(kOrder1, std::size(kOrder1));
2060 }
2061
TEST_F(DnsTransactionTest,HttpsPostFailThenHTTPFallback)2062 TEST_F(DnsTransactionTest, HttpsPostFailThenHTTPFallback) {
2063 ConfigureDohServers(true /* use_post */, 2);
2064 AddQueryAndRcode(kT0HostName, kT0Qtype, dns_protocol::kRcodeSERVFAIL, ASYNC,
2065 Transport::HTTPS,
2066 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128, 0 /* id */,
2067 false /* enqueue_transaction_id */);
2068 AddQueryAndResponse(0, kT0HostName, kT0Qtype, kT0ResponseDatagram,
2069 std::size(kT0ResponseDatagram), SYNCHRONOUS,
2070 Transport::HTTPS, nullptr /* opt_rdata */,
2071 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
2072 false /* enqueue_transaction_id */);
2073 TransactionHelper helper0(kT0RecordCount);
2074 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
2075 true /* secure */, resolve_context_.get());
2076 helper0.RunUntilComplete();
2077 size_t kOrder0[] = {1, 2};
2078 CheckServerOrder(kOrder0, std::size(kOrder0));
2079 }
2080
TEST_F(DnsTransactionTest,HttpsPostFailTwice)2081 TEST_F(DnsTransactionTest, HttpsPostFailTwice) {
2082 config_.attempts = 3;
2083 ConfigureDohServers(true /* use_post */, 2);
2084 AddQueryAndResponse(0, kT0HostName, kT0Qtype, kT0ResponseDatagram,
2085 std::size(kT0ResponseDatagram), SYNCHRONOUS,
2086 Transport::HTTPS, nullptr /* opt_rdata */,
2087 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
2088 false /* enqueue_transaction_id */);
2089 AddQueryAndResponse(0, kT0HostName, kT0Qtype, kT0ResponseDatagram,
2090 std::size(kT0ResponseDatagram), SYNCHRONOUS,
2091 Transport::HTTPS, nullptr /* opt_rdata */,
2092 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
2093 false /* enqueue_transaction_id */);
2094 TransactionHelper helper0(ERR_FAILED);
2095 SetDohJobMakerCallback(base::BindRepeating(DohJobMakerCallbackFailStart));
2096 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
2097 true /* secure */, resolve_context_.get());
2098 helper0.RunUntilComplete();
2099 size_t kOrder0[] = {1, 2};
2100 CheckServerOrder(kOrder0, std::size(kOrder0));
2101 }
2102
TEST_F(DnsTransactionTest,HttpsNotAvailableThenHttpFallback)2103 TEST_F(DnsTransactionTest, HttpsNotAvailableThenHttpFallback) {
2104 ConfigureDohServers(true /* use_post */, 2 /* num_doh_servers */,
2105 false /* make_available */);
2106
2107 // Make just server 1 available.
2108 resolve_context_->RecordServerSuccess(
2109 1u /* server_index */, true /* is_doh_server*/, session_.get());
2110
2111 {
2112 std::unique_ptr<DnsServerIterator> doh_itr =
2113 resolve_context_->GetDohIterator(
2114 session_->config(), SecureDnsMode::kAutomatic, session_.get());
2115
2116 ASSERT_TRUE(doh_itr->AttemptAvailable());
2117 EXPECT_EQ(doh_itr->GetNextAttemptIndex(), 1u);
2118 EXPECT_FALSE(doh_itr->AttemptAvailable());
2119 }
2120 AddQueryAndResponse(0, kT0HostName, kT0Qtype, kT0ResponseDatagram,
2121 std::size(kT0ResponseDatagram), SYNCHRONOUS,
2122 Transport::HTTPS, nullptr /* opt_rdata */,
2123 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
2124 false /* enqueue_transaction_id */);
2125 TransactionHelper helper0(kT0RecordCount);
2126 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
2127 true /* secure */, resolve_context_.get());
2128 helper0.RunUntilComplete();
2129 size_t kOrder0[] = {2};
2130 CheckServerOrder(kOrder0, std::size(kOrder0));
2131 {
2132 std::unique_ptr<DnsServerIterator> doh_itr =
2133 resolve_context_->GetDohIterator(
2134 session_->config(), SecureDnsMode::kAutomatic, session_.get());
2135
2136 ASSERT_TRUE(doh_itr->AttemptAvailable());
2137 EXPECT_EQ(doh_itr->GetNextAttemptIndex(), 1u);
2138 EXPECT_FALSE(doh_itr->AttemptAvailable());
2139 }
2140 }
2141
2142 // Fail first DoH server, then no fallbacks marked available in AUTOMATIC mode.
TEST_F(DnsTransactionTest,HttpsFailureThenNotAvailable_Automatic)2143 TEST_F(DnsTransactionTest, HttpsFailureThenNotAvailable_Automatic) {
2144 config_.secure_dns_mode = SecureDnsMode::kAutomatic;
2145 ConfigureDohServers(true /* use_post */, 3 /* num_doh_servers */,
2146 false /* make_available */);
2147
2148 // Make just server 0 available.
2149 resolve_context_->RecordServerSuccess(
2150 0u /* server_index */, true /* is_doh_server*/, session_.get());
2151
2152 {
2153 std::unique_ptr<DnsServerIterator> doh_itr =
2154 resolve_context_->GetDohIterator(
2155 session_->config(), SecureDnsMode::kAutomatic, session_.get());
2156
2157 ASSERT_TRUE(doh_itr->AttemptAvailable());
2158 EXPECT_EQ(doh_itr->GetNextAttemptIndex(), 0u);
2159 EXPECT_FALSE(doh_itr->AttemptAvailable());
2160 }
2161
2162 AddQueryAndErrorResponse(0, kT0HostName, kT0Qtype, ERR_CONNECTION_REFUSED,
2163 SYNCHRONOUS, Transport::HTTPS,
2164 nullptr /* opt_rdata */,
2165 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
2166 false /* enqueue_transaction_id */);
2167 TransactionHelper helper0(ERR_CONNECTION_REFUSED);
2168 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
2169 true /* secure */, resolve_context_.get());
2170 helper0.RunUntilComplete();
2171
2172 // Expect fallback not attempted because other servers not available in
2173 // AUTOMATIC mode until they have recorded a success.
2174 size_t kOrder0[] = {1};
2175 CheckServerOrder(kOrder0, std::size(kOrder0));
2176
2177 {
2178 std::unique_ptr<DnsServerIterator> doh_itr =
2179 resolve_context_->GetDohIterator(
2180 session_->config(), SecureDnsMode::kAutomatic, session_.get());
2181
2182 ASSERT_TRUE(doh_itr->AttemptAvailable());
2183 EXPECT_EQ(doh_itr->GetNextAttemptIndex(), 0u);
2184 EXPECT_FALSE(doh_itr->AttemptAvailable());
2185 }
2186 }
2187
2188 // Test a secure transaction failure in SECURE mode when other DoH servers are
2189 // only available for fallback because of
TEST_F(DnsTransactionTest,HttpsFailureThenNotAvailable_Secure)2190 TEST_F(DnsTransactionTest, HttpsFailureThenNotAvailable_Secure) {
2191 config_.secure_dns_mode = SecureDnsMode::kSecure;
2192 ConfigureDohServers(true /* use_post */, 3 /* num_doh_servers */,
2193 false /* make_available */);
2194
2195 // Make just server 0 available.
2196 resolve_context_->RecordServerSuccess(
2197 0u /* server_index */, true /* is_doh_server*/, session_.get());
2198
2199 {
2200 std::unique_ptr<DnsServerIterator> doh_itr =
2201 resolve_context_->GetDohIterator(
2202 session_->config(), SecureDnsMode::kSecure, session_.get());
2203
2204 ASSERT_TRUE(doh_itr->AttemptAvailable());
2205 EXPECT_EQ(doh_itr->GetNextAttemptIndex(), 0u);
2206 ASSERT_TRUE(doh_itr->AttemptAvailable());
2207 EXPECT_EQ(doh_itr->GetNextAttemptIndex(), 1u);
2208 ASSERT_TRUE(doh_itr->AttemptAvailable());
2209 EXPECT_EQ(doh_itr->GetNextAttemptIndex(), 2u);
2210 }
2211
2212 AddQueryAndErrorResponse(0, kT0HostName, kT0Qtype, ERR_CONNECTION_REFUSED,
2213 SYNCHRONOUS, Transport::HTTPS,
2214 nullptr /* opt_rdata */,
2215 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
2216 false /* enqueue_transaction_id */);
2217 AddQueryAndErrorResponse(0, kT0HostName, kT0Qtype, ERR_CONNECTION_REFUSED,
2218 SYNCHRONOUS, Transport::HTTPS,
2219 nullptr /* opt_rdata */,
2220 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
2221 false /* enqueue_transaction_id */);
2222 AddQueryAndErrorResponse(0, kT0HostName, kT0Qtype, ERR_CONNECTION_REFUSED,
2223 SYNCHRONOUS, Transport::HTTPS,
2224 nullptr /* opt_rdata */,
2225 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
2226 false /* enqueue_transaction_id */);
2227 TransactionHelper helper0(ERR_CONNECTION_REFUSED);
2228 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
2229 true /* secure */, resolve_context_.get());
2230 helper0.RunUntilComplete();
2231
2232 // Expect fallback to attempt all servers because SECURE mode does not require
2233 // server availability.
2234 size_t kOrder0[] = {1, 2, 3};
2235 CheckServerOrder(kOrder0, std::size(kOrder0));
2236
2237 // Expect server 0 to be preferred due to least recent failure.
2238 {
2239 std::unique_ptr<DnsServerIterator> doh_itr =
2240 resolve_context_->GetDohIterator(
2241 session_->config(), SecureDnsMode::kSecure, session_.get());
2242
2243 ASSERT_TRUE(doh_itr->AttemptAvailable());
2244 EXPECT_EQ(doh_itr->GetNextAttemptIndex(), 0u);
2245 }
2246 }
2247
TEST_F(DnsTransactionTest,MaxHttpsFailures_NonConsecutive)2248 TEST_F(DnsTransactionTest, MaxHttpsFailures_NonConsecutive) {
2249 config_.attempts = 1;
2250 ConfigureDohServers(false /* use_post */);
2251 {
2252 std::unique_ptr<DnsServerIterator> doh_itr =
2253 resolve_context_->GetDohIterator(
2254 session_->config(), SecureDnsMode::kAutomatic, session_.get());
2255
2256 ASSERT_TRUE(doh_itr->AttemptAvailable());
2257 EXPECT_EQ(doh_itr->GetNextAttemptIndex(), 0u);
2258 }
2259
2260 for (size_t i = 0; i < ResolveContext::kAutomaticModeFailureLimit - 1; i++) {
2261 AddQueryAndErrorResponse(0, kT0HostName, kT0Qtype, ERR_CONNECTION_REFUSED,
2262 SYNCHRONOUS, Transport::HTTPS,
2263 nullptr /* opt_rdata */,
2264 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
2265 false /* enqueue_transaction_id */);
2266 TransactionHelper failure(ERR_CONNECTION_REFUSED);
2267 failure.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
2268 true /* secure */, resolve_context_.get());
2269 failure.RunUntilComplete();
2270
2271 std::unique_ptr<DnsServerIterator> doh_itr =
2272 resolve_context_->GetDohIterator(
2273 session_->config(), SecureDnsMode::kAutomatic, session_.get());
2274
2275 ASSERT_TRUE(doh_itr->AttemptAvailable());
2276 EXPECT_EQ(doh_itr->GetNextAttemptIndex(), 0u);
2277 }
2278
2279 // A success should reset the failure counter for DoH.
2280 AddQueryAndResponse(0, kT0HostName, kT0Qtype, kT0ResponseDatagram,
2281 std::size(kT0ResponseDatagram), SYNCHRONOUS,
2282 Transport::HTTPS, nullptr /* opt_rdata */,
2283 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
2284 false /* enqueue_transaction_id */);
2285 TransactionHelper success(kT0RecordCount);
2286 success.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
2287 true /* secure */, resolve_context_.get());
2288 success.RunUntilComplete();
2289 {
2290 std::unique_ptr<DnsServerIterator> doh_itr =
2291 resolve_context_->GetDohIterator(
2292 session_->config(), SecureDnsMode::kAutomatic, session_.get());
2293
2294 ASSERT_TRUE(doh_itr->AttemptAvailable());
2295 EXPECT_EQ(doh_itr->GetNextAttemptIndex(), 0u);
2296 }
2297
2298 // One more failure should not pass the threshold because failures were reset.
2299 AddQueryAndErrorResponse(0, kT0HostName, kT0Qtype, ERR_CONNECTION_REFUSED,
2300 SYNCHRONOUS, Transport::HTTPS,
2301 nullptr /* opt_rdata */,
2302 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
2303 false /* enqueue_transaction_id */);
2304 TransactionHelper last_failure(ERR_CONNECTION_REFUSED);
2305 last_failure.StartTransaction(transaction_factory_.get(), kT0HostName,
2306 kT0Qtype, true /* secure */,
2307 resolve_context_.get());
2308 last_failure.RunUntilComplete();
2309 {
2310 std::unique_ptr<DnsServerIterator> doh_itr =
2311 resolve_context_->GetDohIterator(
2312 session_->config(), SecureDnsMode::kAutomatic, session_.get());
2313
2314 ASSERT_TRUE(doh_itr->AttemptAvailable());
2315 EXPECT_EQ(doh_itr->GetNextAttemptIndex(), 0u);
2316 }
2317 }
2318
TEST_F(DnsTransactionTest,MaxHttpsFailures_Consecutive)2319 TEST_F(DnsTransactionTest, MaxHttpsFailures_Consecutive) {
2320 config_.attempts = 1;
2321 ConfigureDohServers(false /* use_post */);
2322 {
2323 std::unique_ptr<DnsServerIterator> doh_itr =
2324 resolve_context_->GetDohIterator(
2325 session_->config(), SecureDnsMode::kAutomatic, session_.get());
2326
2327 ASSERT_TRUE(doh_itr->AttemptAvailable());
2328 EXPECT_EQ(doh_itr->GetNextAttemptIndex(), 0u);
2329 }
2330
2331 for (size_t i = 0; i < ResolveContext::kAutomaticModeFailureLimit - 1; i++) {
2332 AddQueryAndErrorResponse(0, kT0HostName, kT0Qtype, ERR_CONNECTION_REFUSED,
2333 SYNCHRONOUS, Transport::HTTPS,
2334 nullptr /* opt_rdata */,
2335 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
2336 false /* enqueue_transaction_id */);
2337 TransactionHelper failure(ERR_CONNECTION_REFUSED);
2338 failure.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
2339 true /* secure */, resolve_context_.get());
2340 failure.RunUntilComplete();
2341 std::unique_ptr<DnsServerIterator> doh_itr =
2342 resolve_context_->GetDohIterator(
2343 session_->config(), SecureDnsMode::kAutomatic, session_.get());
2344
2345 ASSERT_TRUE(doh_itr->AttemptAvailable());
2346 EXPECT_EQ(doh_itr->GetNextAttemptIndex(), 0u);
2347 }
2348
2349 // One more failure should pass the threshold.
2350 AddQueryAndErrorResponse(0, kT0HostName, kT0Qtype, ERR_CONNECTION_REFUSED,
2351 SYNCHRONOUS, Transport::HTTPS,
2352 nullptr /* opt_rdata */,
2353 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
2354 false /* enqueue_transaction_id */);
2355 TransactionHelper last_failure(ERR_CONNECTION_REFUSED);
2356 last_failure.StartTransaction(transaction_factory_.get(), kT0HostName,
2357 kT0Qtype, true /* secure */,
2358 resolve_context_.get());
2359 last_failure.RunUntilComplete();
2360 {
2361 std::unique_ptr<DnsServerIterator> doh_itr =
2362 resolve_context_->GetDohIterator(
2363 session_->config(), SecureDnsMode::kAutomatic, session_.get());
2364
2365 EXPECT_FALSE(doh_itr->AttemptAvailable());
2366 }
2367 }
2368
2369 // Test that a secure transaction started before a DoH server becomes
2370 // unavailable can complete and make the server available again.
TEST_F(DnsTransactionTest,SuccessfulTransactionStartedBeforeUnavailable)2371 TEST_F(DnsTransactionTest, SuccessfulTransactionStartedBeforeUnavailable) {
2372 ConfigureDohServers(false /* use_post */);
2373 {
2374 std::unique_ptr<DnsServerIterator> doh_itr =
2375 resolve_context_->GetDohIterator(
2376 session_->config(), SecureDnsMode::kAutomatic, session_.get());
2377
2378 ASSERT_TRUE(doh_itr->AttemptAvailable());
2379 EXPECT_EQ(doh_itr->GetNextAttemptIndex(), 0u);
2380 }
2381
2382 // Create a socket data to first return ERR_IO_PENDING. This will pause the
2383 // response and not return the second response until
2384 // SequencedSocketData::Resume() is called.
2385 auto data = std::make_unique<DnsSocketData>(
2386 0, kT0HostName, kT0Qtype, ASYNC, Transport::HTTPS,
2387 nullptr /* opt_rdata */, DnsQuery::PaddingStrategy::BLOCK_LENGTH_128);
2388 data->AddReadError(ERR_IO_PENDING, ASYNC);
2389 data->AddResponseData(kT0ResponseDatagram, std::size(kT0ResponseDatagram),
2390 ASYNC);
2391 SequencedSocketData* sequenced_socket_data = data->GetProvider();
2392 AddSocketData(std::move(data), false /* enqueue_transaction_id */);
2393
2394 TransactionHelper delayed_success(kT0RecordCount);
2395 delayed_success.StartTransaction(transaction_factory_.get(), kT0HostName,
2396 kT0Qtype, true /* secure */,
2397 resolve_context_.get());
2398 base::RunLoop().RunUntilIdle();
2399 EXPECT_FALSE(delayed_success.has_completed());
2400
2401 // Trigger DoH server unavailability with a bunch of failures.
2402 for (size_t i = 0; i < ResolveContext::kAutomaticModeFailureLimit; i++) {
2403 AddQueryAndErrorResponse(0, kT0HostName, kT0Qtype, ERR_CONNECTION_REFUSED,
2404 SYNCHRONOUS, Transport::HTTPS,
2405 nullptr /* opt_rdata */,
2406 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
2407 false /* enqueue_transaction_id */);
2408 TransactionHelper failure(ERR_CONNECTION_REFUSED);
2409 failure.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
2410 true /* secure */, resolve_context_.get());
2411 failure.RunUntilComplete();
2412 }
2413 EXPECT_FALSE(resolve_context_->GetDohServerAvailability(
2414 0u /* doh_server_index */, session_.get()));
2415
2416 // Resume first query.
2417 ASSERT_FALSE(delayed_success.has_completed());
2418 sequenced_socket_data->Resume();
2419 delayed_success.RunUntilComplete();
2420
2421 // Expect DoH server is available again.
2422 EXPECT_TRUE(resolve_context_->GetDohServerAvailability(
2423 0u /* doh_server_index */, session_.get()));
2424 }
2425
MakeResponseWithCookie(URLRequest * request,HttpResponseInfo * info)2426 void MakeResponseWithCookie(URLRequest* request, HttpResponseInfo* info) {
2427 info->headers->AddHeader("Set-Cookie", "test-cookie=you-fail");
2428 }
2429
2430 class CookieCallback {
2431 public:
CookieCallback()2432 CookieCallback() : loop_to_quit_(std::make_unique<base::RunLoop>()) {}
2433
SetCookieCallback(CookieAccessResult result)2434 void SetCookieCallback(CookieAccessResult result) {
2435 result_ = result.status.IsInclude();
2436 loop_to_quit_->Quit();
2437 }
2438
2439 CookieCallback(const CookieCallback&) = delete;
2440 CookieCallback& operator=(const CookieCallback&) = delete;
2441
GetCookieListCallback(const net::CookieAccessResultList & list,const net::CookieAccessResultList & excluded_cookies)2442 void GetCookieListCallback(
2443 const net::CookieAccessResultList& list,
2444 const net::CookieAccessResultList& excluded_cookies) {
2445 list_ = cookie_util::StripAccessResults(list);
2446 loop_to_quit_->Quit();
2447 }
2448
Reset()2449 void Reset() { loop_to_quit_ = std::make_unique<base::RunLoop>(); }
2450
WaitUntilDone()2451 void WaitUntilDone() { loop_to_quit_->Run(); }
2452
cookie_list_size()2453 size_t cookie_list_size() { return list_.size(); }
2454
2455 private:
2456 net::CookieList list_;
2457 bool result_ = false;
2458 std::unique_ptr<base::RunLoop> loop_to_quit_;
2459 };
2460
TEST_F(DnsTransactionTest,HttpsPostTestNoCookies)2461 TEST_F(DnsTransactionTest, HttpsPostTestNoCookies) {
2462 ConfigureDohServers(true /* use_post */);
2463 AddQueryAndResponse(0, kT0HostName, kT0Qtype, kT0ResponseDatagram,
2464 std::size(kT0ResponseDatagram), SYNCHRONOUS,
2465 Transport::HTTPS, nullptr /* opt_rdata */,
2466 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
2467 false /* enqueue_transaction_id */);
2468 AddQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype, kT0ResponseDatagram,
2469 std::size(kT0ResponseDatagram), SYNCHRONOUS,
2470 Transport::HTTPS, nullptr /* opt_rdata */,
2471 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
2472 false /* enqueue_transaction_id */);
2473 TransactionHelper helper0(kT0RecordCount);
2474 TransactionHelper helper1(kT0RecordCount);
2475 SetResponseModifierCallback(base::BindRepeating(MakeResponseWithCookie));
2476
2477 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
2478 true /* secure */, resolve_context_.get());
2479 helper0.RunUntilComplete();
2480
2481 CookieCallback callback;
2482 request_context_->cookie_store()->GetCookieListWithOptionsAsync(
2483 GURL(GetURLFromTemplateWithoutParameters(
2484 config_.doh_config.servers()[0].server_template())),
2485 CookieOptions::MakeAllInclusive(), CookiePartitionKeyCollection(),
2486 base::BindOnce(&CookieCallback::GetCookieListCallback,
2487 base::Unretained(&callback)));
2488 callback.WaitUntilDone();
2489 EXPECT_EQ(0u, callback.cookie_list_size());
2490 callback.Reset();
2491 GURL cookie_url(GetURLFromTemplateWithoutParameters(
2492 config_.doh_config.servers()[0].server_template()));
2493 auto cookie = CanonicalCookie::CreateForTesting(
2494 cookie_url, "test-cookie=you-still-fail", base::Time::Now());
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 ASSERT_EQ(kDohProbeHostname, kT4HostName);
3478 AddQueryAndErrorResponse(0 /* id */, kT4HostName, kT4Qtype,
3479 ERR_CONNECTION_REFUSED, SYNCHRONOUS,
3480 Transport::HTTPS, nullptr /* opt_rdata */,
3481 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
3482 false /* enqueue_transaction_id */);
3483 AddQueryAndErrorResponse(0 /* id */, kT4HostName, kT4Qtype,
3484 ERR_CONNECTION_REFUSED, SYNCHRONOUS,
3485 Transport::HTTPS, nullptr /* opt_rdata */,
3486 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
3487 false /* enqueue_transaction_id */);
3488 AddQueryAndResponse(0 /* id */, kT4HostName, kT4Qtype, kT4ResponseDatagram,
3489 std::size(kT4ResponseDatagram), ASYNC, Transport::HTTPS,
3490 nullptr /* opt_rdata */,
3491 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
3492 false /* enqueue_transaction_id */);
3493
3494 std::unique_ptr<DnsProbeRunner> runner =
3495 transaction_factory_->CreateDohProbeRunner(resolve_context_.get());
3496 runner->Start(false /* network_change */);
3497
3498 // The first probe happens without any delay.
3499 RunUntilIdle();
3500 std::unique_ptr<DnsServerIterator> doh_itr = resolve_context_->GetDohIterator(
3501 session_->config(), SecureDnsMode::kAutomatic, session_.get());
3502
3503 EXPECT_FALSE(doh_itr->AttemptAvailable());
3504
3505 // Expect the server to still be unavailable after the second probe.
3506 FastForwardBy(runner->GetDelayUntilNextProbeForTest(0));
3507 EXPECT_FALSE(doh_itr->AttemptAvailable());
3508
3509 // Expect the server to be available after the successful third probe.
3510 FastForwardBy(runner->GetDelayUntilNextProbeForTest(0));
3511 ASSERT_TRUE(doh_itr->AttemptAvailable());
3512 EXPECT_EQ(doh_itr->GetNextAttemptIndex(), 0u);
3513 }
3514
TEST_F(DnsTransactionTestWithMockTime,ProbeCreationTriggersSuccessMetric)3515 TEST_F(DnsTransactionTestWithMockTime, ProbeCreationTriggersSuccessMetric) {
3516 config_.secure_dns_mode = SecureDnsMode::kAutomatic;
3517 ConfigureDohServers(/*use_post=*/true, /*num_doh_servers=*/1,
3518 /*make_available=*/false);
3519 ASSERT_EQ(kDohProbeHostname, kT4HostName);
3520 AddQueryAndResponse(/*id=*/0, kT4HostName, kT4Qtype, kT4ResponseDatagram,
3521 std::size(kT4ResponseDatagram), ASYNC, Transport::HTTPS,
3522 /*opt_rdata=*/nullptr,
3523 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
3524 /*enqueue_transaction_id=*/false);
3525
3526 // The metric timer should not have started yet.
3527 EXPECT_FALSE(
3528 resolve_context_->doh_autoupgrade_metrics_timer_is_running_for_testing());
3529
3530 base::HistogramTester histogram_tester;
3531 std::unique_ptr<DnsProbeRunner> runner =
3532 transaction_factory_->CreateDohProbeRunner(resolve_context_.get());
3533 runner->Start(/*network_change=*/false);
3534
3535 // Ensure that calling `CreateDohProbeRunner()` causes metrics to be emitted
3536 // after the timeout.
3537 EXPECT_TRUE(
3538 resolve_context_->doh_autoupgrade_metrics_timer_is_running_for_testing());
3539
3540 // Fast-forward by enough time for the timer to trigger. Add one millisecond
3541 // just to make it clear that afterwards the timeout should definitely have
3542 // occurred (although this may not be strictly necessary).
3543 FastForwardBy(ResolveContext::kDohAutoupgradeSuccessMetricTimeout +
3544 base::Milliseconds(1));
3545
3546 EXPECT_FALSE(
3547 resolve_context_->doh_autoupgrade_metrics_timer_is_running_for_testing());
3548
3549 histogram_tester.ExpectUniqueSample(
3550 "Net.DNS.ResolveContext.DohAutoupgrade.Other.Status",
3551 DohServerAutoupgradeStatus::kSuccessWithNoPriorFailures, 1);
3552 }
3553
TEST_F(DnsTransactionTestWithMockTime,ProbeAttemptConnectionFailureAffectsHistograms)3554 TEST_F(DnsTransactionTestWithMockTime,
3555 ProbeAttemptConnectionFailureAffectsHistograms) {
3556 config_.secure_dns_mode = SecureDnsMode::kAutomatic;
3557 ConfigureDohServers(/*use_post=*/true, /*num_doh_servers=*/1,
3558 /*make_available=*/false);
3559 ASSERT_EQ(kDohProbeHostname, kT4HostName);
3560 AddQueryAndErrorResponse(/*id=*/0, kT4HostName, kT4Qtype,
3561 ERR_CONNECTION_REFUSED, SYNCHRONOUS,
3562 Transport::HTTPS, /*opt_rdata=*/nullptr,
3563 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
3564 /*enqueue_transaction_id=*/false);
3565
3566 base::HistogramTester histogram_tester;
3567 std::unique_ptr<DnsProbeRunner> runner =
3568 transaction_factory_->CreateDohProbeRunner(resolve_context_.get());
3569 runner->Start(/*network_change=*/false);
3570
3571 // Consume the one failure response and then destroy the probe so it doesn't
3572 // continue to make requests.
3573 RunUntilIdle();
3574 runner = nullptr;
3575
3576 FastForwardBy(ResolveContext::kDohAutoupgradeSuccessMetricTimeout +
3577 base::Milliseconds(1));
3578 histogram_tester.ExpectUniqueSample(
3579 "Net.DNS.ResolveContext.DohAutoupgrade.Other.Status",
3580 DohServerAutoupgradeStatus::kFailureWithNoPriorSuccesses, 1);
3581 histogram_tester.ExpectUniqueSample(
3582 "Net.DNS.DnsTransaction.SecureNotValidated.Other.FailureError",
3583 std::abs(Error::ERR_CONNECTION_REFUSED), 1);
3584 }
3585
TEST_F(DnsTransactionTestWithMockTime,ProbeAttemptServFailAffectsHistograms)3586 TEST_F(DnsTransactionTestWithMockTime, ProbeAttemptServFailAffectsHistograms) {
3587 config_.secure_dns_mode = SecureDnsMode::kAutomatic;
3588 ConfigureDohServers(/*use_post=*/true, /*num_doh_servers=*/1,
3589 /*make_available=*/false);
3590 ASSERT_EQ(kDohProbeHostname, kT4HostName);
3591 AddQueryAndRcode(kT4HostName, kT4Qtype, dns_protocol::kRcodeSERVFAIL,
3592 SYNCHRONOUS, Transport::HTTPS,
3593 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128, /*id=*/0,
3594 /*enqueue_transaction_id=*/false);
3595
3596 base::HistogramTester histogram_tester;
3597 std::unique_ptr<DnsProbeRunner> runner =
3598 transaction_factory_->CreateDohProbeRunner(resolve_context_.get());
3599 runner->Start(/*network_change=*/false);
3600
3601 RunUntilIdle();
3602 runner = nullptr;
3603
3604 FastForwardBy(ResolveContext::kDohAutoupgradeSuccessMetricTimeout +
3605 base::Milliseconds(1));
3606 histogram_tester.ExpectUniqueSample(
3607 "Net.DNS.ResolveContext.DohAutoupgrade.Other.Status",
3608 DohServerAutoupgradeStatus::kFailureWithNoPriorSuccesses, 1);
3609 histogram_tester.ExpectUniqueSample(
3610 "Net.DNS.DnsTransaction.SecureNotValidated.Other.FailureError",
3611 std::abs(Error::ERR_DNS_SERVER_FAILED), 1);
3612 }
3613
TEST_F(DnsTransactionTestWithMockTime,ProbeAttemptEmptyResponseAffectsHistograms)3614 TEST_F(DnsTransactionTestWithMockTime,
3615 ProbeAttemptEmptyResponseAffectsHistograms) {
3616 config_.secure_dns_mode = SecureDnsMode::kAutomatic;
3617 ConfigureDohServers(/*use_post=*/true, /*num_doh_servers=*/1,
3618 /*make_available=*/false);
3619 ASSERT_EQ(kDohProbeHostname, kT4HostName);
3620 auto response = std::make_unique<DnsResponse>(
3621 BuildTestDnsResponse(kT4HostName, dns_protocol::kTypeA,
3622 /*answers=*/{}));
3623 auto data = std::make_unique<DnsSocketData>(
3624 /*id=*/0, kT4HostName, dns_protocol::kTypeA, SYNCHRONOUS,
3625 Transport::HTTPS, /*opt_rdata=*/nullptr,
3626 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128);
3627 data->AddResponse(std::move(response), SYNCHRONOUS);
3628 AddSocketData(std::move(data), /*enqueue_transaction_id=*/false);
3629
3630 base::HistogramTester histogram_tester;
3631 std::unique_ptr<DnsProbeRunner> runner =
3632 transaction_factory_->CreateDohProbeRunner(resolve_context_.get());
3633 runner->Start(/*network_change=*/false);
3634
3635 RunUntilIdle();
3636 runner = nullptr;
3637
3638 FastForwardBy(ResolveContext::kDohAutoupgradeSuccessMetricTimeout +
3639 base::Milliseconds(1));
3640 histogram_tester.ExpectUniqueSample(
3641 "Net.DNS.ResolveContext.DohAutoupgrade.Other.Status",
3642 DohServerAutoupgradeStatus::kFailureWithNoPriorSuccesses, 1);
3643 histogram_tester.ExpectUniqueSample(
3644 "Net.DNS.DnsTransaction.SecureNotValidated.Other.FailureError",
3645 std::abs(Error::ERR_DNS_SECURE_PROBE_RECORD_INVALID), 1);
3646 }
3647
3648 // Test that if a probe attempt hangs, additional probes will still run on
3649 // schedule
TEST_F(DnsTransactionTestWithMockTime,HungProbe)3650 TEST_F(DnsTransactionTestWithMockTime, HungProbe) {
3651 ConfigureDohServers(true /* use_post */, 1 /* num_doh_servers */,
3652 false /* make_available */);
3653
3654 // Create a socket data to first return ERR_IO_PENDING. This will pause the
3655 // probe and not return the error until SequencedSocketData::Resume() is
3656 // called.
3657 auto data = std::make_unique<DnsSocketData>(
3658 0 /* id */, kT4HostName, kT4Qtype, ASYNC, Transport::HTTPS,
3659 nullptr /* opt_rdata */, DnsQuery::PaddingStrategy::BLOCK_LENGTH_128);
3660 data->AddReadError(ERR_IO_PENDING, ASYNC);
3661 data->AddReadError(ERR_CONNECTION_REFUSED, ASYNC);
3662 data->AddResponseData(kT4ResponseDatagram, std::size(kT4ResponseDatagram),
3663 ASYNC);
3664 SequencedSocketData* sequenced_socket_data = data->GetProvider();
3665 AddSocketData(std::move(data), false /* enqueue_transaction_id */);
3666
3667 // Add success for second probe.
3668 AddQueryAndResponse(0 /* id */, kT4HostName, kT4Qtype, kT4ResponseDatagram,
3669 std::size(kT4ResponseDatagram), ASYNC, Transport::HTTPS,
3670 nullptr /* opt_rdata */,
3671 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
3672 false /* enqueue_transaction_id */);
3673
3674 std::unique_ptr<DnsProbeRunner> runner =
3675 transaction_factory_->CreateDohProbeRunner(resolve_context_.get());
3676 runner->Start(false /* network_change */);
3677
3678 // The first probe starts without any delay, but doesn't finish.
3679 RunUntilIdle();
3680 EXPECT_FALSE(resolve_context_->GetDohServerAvailability(
3681 0u /* doh_server_index */, session_.get()));
3682
3683 // Second probe succeeds.
3684 FastForwardBy(runner->GetDelayUntilNextProbeForTest(0));
3685 EXPECT_TRUE(resolve_context_->GetDohServerAvailability(
3686 0u /* doh_server_index */, session_.get()));
3687
3688 // Probe runner self-cancels on next cycle.
3689 FastForwardBy(runner->GetDelayUntilNextProbeForTest(0));
3690 EXPECT_EQ(runner->GetDelayUntilNextProbeForTest(0), base::TimeDelta());
3691
3692 // Expect no effect when the hung probe wakes up and fails.
3693 sequenced_socket_data->Resume();
3694 RunUntilIdle();
3695 EXPECT_TRUE(resolve_context_->GetDohServerAvailability(
3696 0u /* doh_server_index */, session_.get()));
3697 EXPECT_EQ(runner->GetDelayUntilNextProbeForTest(0), base::TimeDelta());
3698 }
3699
TEST_F(DnsTransactionTestWithMockTime,ProbeMultipleServers)3700 TEST_F(DnsTransactionTestWithMockTime, ProbeMultipleServers) {
3701 ConfigureDohServers(true /* use_post */, 2 /* num_doh_servers */,
3702 false /* make_available */);
3703 AddQueryAndResponse(0 /* id */, kT4HostName, kT4Qtype, kT4ResponseDatagram,
3704 std::size(kT4ResponseDatagram), ASYNC, Transport::HTTPS,
3705 nullptr /* opt_rdata */,
3706 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
3707 false /* enqueue_transaction_id */);
3708 AddQueryAndErrorResponse(0 /* id */, kT4HostName, kT4Qtype,
3709 ERR_CONNECTION_REFUSED, SYNCHRONOUS,
3710 Transport::HTTPS, nullptr /* opt_rdata */,
3711 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
3712 false /* enqueue_transaction_id */);
3713 AddQueryAndResponse(0 /* id */, kT4HostName, kT4Qtype, kT4ResponseDatagram,
3714 std::size(kT4ResponseDatagram), ASYNC, Transport::HTTPS,
3715 nullptr /* opt_rdata */,
3716 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
3717 false /* enqueue_transaction_id */);
3718
3719 ASSERT_FALSE(resolve_context_->GetDohServerAvailability(
3720 0u /* doh_server_index */, session_.get()));
3721 ASSERT_FALSE(resolve_context_->GetDohServerAvailability(
3722 1u /* doh_server_index */, session_.get()));
3723
3724 std::unique_ptr<DnsProbeRunner> runner =
3725 transaction_factory_->CreateDohProbeRunner(resolve_context_.get());
3726 runner->Start(true /* network_change */);
3727
3728 // The first probes happens without any delay and succeeds for only one server
3729 RunUntilIdle();
3730 EXPECT_TRUE(resolve_context_->GetDohServerAvailability(
3731 0u /* doh_server_index */, session_.get()));
3732 EXPECT_FALSE(resolve_context_->GetDohServerAvailability(
3733 1u /* doh_server_index */, session_.get()));
3734
3735 // On second round of probing, probes for first server should self-cancel and
3736 // second server should become available.
3737 FastForwardBy(
3738 runner->GetDelayUntilNextProbeForTest(0u /* doh_server_index */));
3739 EXPECT_EQ(runner->GetDelayUntilNextProbeForTest(0u /* doh_server_index */),
3740 base::TimeDelta());
3741 FastForwardBy(
3742 runner->GetDelayUntilNextProbeForTest(1u /* doh_server_index */));
3743 EXPECT_TRUE(resolve_context_->GetDohServerAvailability(
3744 1u /* doh_server_index */, session_.get()));
3745
3746 // Expect server 2 probes to self-cancel on next cycle.
3747 FastForwardBy(runner->GetDelayUntilNextProbeForTest(1u));
3748 EXPECT_EQ(runner->GetDelayUntilNextProbeForTest(1u), base::TimeDelta());
3749 }
3750
TEST_F(DnsTransactionTestWithMockTime,MultipleProbeRunners)3751 TEST_F(DnsTransactionTestWithMockTime, MultipleProbeRunners) {
3752 ConfigureDohServers(true /* use_post */, 1 /* num_doh_servers */,
3753 false /* make_available */);
3754 AddQueryAndResponse(0 /* id */, kT4HostName, kT4Qtype, kT4ResponseDatagram,
3755 std::size(kT4ResponseDatagram), ASYNC, Transport::HTTPS,
3756 nullptr /* opt_rdata */,
3757 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
3758 false /* enqueue_transaction_id */);
3759 AddQueryAndResponse(0 /* id */, kT4HostName, kT4Qtype, kT4ResponseDatagram,
3760 std::size(kT4ResponseDatagram), ASYNC, Transport::HTTPS,
3761 nullptr /* opt_rdata */,
3762 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
3763 false /* enqueue_transaction_id */);
3764
3765 std::unique_ptr<DnsProbeRunner> runner1 =
3766 transaction_factory_->CreateDohProbeRunner(resolve_context_.get());
3767 std::unique_ptr<DnsProbeRunner> runner2 =
3768 transaction_factory_->CreateDohProbeRunner(resolve_context_.get());
3769 runner1->Start(true /* network_change */);
3770 runner2->Start(true /* network_change */);
3771
3772 // The first two probes (one for each runner) happen without any delay
3773 // and mark the first server good.
3774 RunUntilIdle();
3775 {
3776 std::unique_ptr<DnsServerIterator> doh_itr =
3777 resolve_context_->GetDohIterator(
3778 session_->config(), SecureDnsMode::kAutomatic, session_.get());
3779
3780 ASSERT_TRUE(doh_itr->AttemptAvailable());
3781 EXPECT_EQ(doh_itr->GetNextAttemptIndex(), 0u);
3782 }
3783
3784 // Both probes expected to self-cancel on next scheduled run.
3785 FastForwardBy(runner1->GetDelayUntilNextProbeForTest(0));
3786 FastForwardBy(runner2->GetDelayUntilNextProbeForTest(0));
3787 EXPECT_EQ(runner1->GetDelayUntilNextProbeForTest(0), base::TimeDelta());
3788 EXPECT_EQ(runner2->GetDelayUntilNextProbeForTest(0), base::TimeDelta());
3789 }
3790
TEST_F(DnsTransactionTestWithMockTime,MultipleProbeRunners_SeparateContexts)3791 TEST_F(DnsTransactionTestWithMockTime, MultipleProbeRunners_SeparateContexts) {
3792 // Each RequestContext uses its own transient IsolationInfo. Since there's
3793 // typically only one RequestContext per URLRequestContext, there's no
3794 // advantage in using the same IsolationInfo across RequestContexts.
3795 set_expect_multiple_isolation_infos(true);
3796
3797 ConfigureDohServers(true /* use_post */, 1 /* num_doh_servers */,
3798 false /* make_available */);
3799 AddQueryAndResponse(0 /* id */, kT4HostName, kT4Qtype, kT4ResponseDatagram,
3800 std::size(kT4ResponseDatagram), ASYNC, Transport::HTTPS,
3801 nullptr /* opt_rdata */,
3802 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
3803 false /* enqueue_transaction_id */);
3804 AddQueryAndErrorResponse(0 /* id */, kT4HostName, kT4Qtype,
3805 ERR_CONNECTION_REFUSED, SYNCHRONOUS,
3806 Transport::HTTPS, nullptr /* opt_rdata */,
3807 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
3808 false /* enqueue_transaction_id */);
3809 AddQueryAndResponse(0 /* id */, kT4HostName, kT4Qtype, kT4ResponseDatagram,
3810 std::size(kT4ResponseDatagram), ASYNC, Transport::HTTPS,
3811 nullptr /* opt_rdata */,
3812 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
3813 false /* enqueue_transaction_id */);
3814
3815 auto request_context2 = CreateTestURLRequestContextBuilder()->Build();
3816 ResolveContext context2(request_context2.get(), false /* enable_caching */);
3817 context2.InvalidateCachesAndPerSessionData(session_.get(),
3818 false /* network_change */);
3819
3820 std::unique_ptr<DnsProbeRunner> runner1 =
3821 transaction_factory_->CreateDohProbeRunner(resolve_context_.get());
3822 std::unique_ptr<DnsProbeRunner> runner2 =
3823 transaction_factory_->CreateDohProbeRunner(&context2);
3824 runner1->Start(false /* network_change */);
3825 runner2->Start(false /* network_change */);
3826
3827 // The first two probes (one for each runner) happen without any delay.
3828 // Probe for first context succeeds and second fails.
3829 RunUntilIdle();
3830 {
3831 std::unique_ptr<DnsServerIterator> doh_itr =
3832 resolve_context_->GetDohIterator(
3833 session_->config(), SecureDnsMode::kAutomatic, session_.get());
3834
3835 ASSERT_TRUE(doh_itr->AttemptAvailable());
3836 EXPECT_EQ(doh_itr->GetNextAttemptIndex(), 0u);
3837 }
3838 {
3839 std::unique_ptr<DnsServerIterator> doh_itr2 = context2.GetDohIterator(
3840 session_->config(), SecureDnsMode::kAutomatic, session_.get());
3841
3842 EXPECT_FALSE(doh_itr2->AttemptAvailable());
3843 }
3844
3845 // First probe runner expected to be compete and self-cancel on next run.
3846 FastForwardBy(runner1->GetDelayUntilNextProbeForTest(0));
3847 EXPECT_EQ(runner1->GetDelayUntilNextProbeForTest(0), base::TimeDelta());
3848
3849 // Expect second runner to succeed on its second probe.
3850 FastForwardBy(runner2->GetDelayUntilNextProbeForTest(0));
3851 {
3852 std::unique_ptr<DnsServerIterator> doh_itr2 = context2.GetDohIterator(
3853 session_->config(), SecureDnsMode::kAutomatic, session_.get());
3854
3855 ASSERT_TRUE(doh_itr2->AttemptAvailable());
3856 EXPECT_EQ(doh_itr2->GetNextAttemptIndex(), 0u);
3857 }
3858 FastForwardBy(runner2->GetDelayUntilNextProbeForTest(0));
3859 EXPECT_EQ(runner2->GetDelayUntilNextProbeForTest(0), base::TimeDelta());
3860 }
3861
TEST_F(DnsTransactionTestWithMockTime,CancelDohProbeOnDestruction)3862 TEST_F(DnsTransactionTestWithMockTime, CancelDohProbeOnDestruction) {
3863 ConfigureDohServers(/*use_post=*/true, /*num_doh_servers=*/1,
3864 /*make_available=*/false);
3865 AddQueryAndErrorResponse(/*id=*/0, kT4HostName, kT4Qtype,
3866 ERR_CONNECTION_REFUSED, SYNCHRONOUS,
3867 Transport::HTTPS, /*opt_rdata=*/nullptr,
3868 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
3869 /*enqueue_transaction_id=*/false);
3870 AddQueryAndErrorResponse(/*id=*/0, kT4HostName, kT4Qtype,
3871 ERR_CONNECTION_REFUSED, SYNCHRONOUS,
3872 Transport::HTTPS, /*opt_rdata=*/nullptr,
3873 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
3874 /* enqueue_transaction_id=*/false);
3875
3876 std::unique_ptr<DnsProbeRunner> runner =
3877 transaction_factory_->CreateDohProbeRunner(resolve_context_.get());
3878 runner->Start(/*network_change=*/false);
3879
3880 // The first probe happens without any delay.
3881 RunUntilIdle();
3882 std::unique_ptr<DnsServerIterator> doh_itr = resolve_context_->GetDohIterator(
3883 session_->config(), SecureDnsMode::kAutomatic, session_.get());
3884
3885 EXPECT_FALSE(doh_itr->AttemptAvailable());
3886
3887 // Expect the server to still be unavailable after the second probe.
3888 FastForwardBy(runner->GetDelayUntilNextProbeForTest(0));
3889
3890 EXPECT_FALSE(doh_itr->AttemptAvailable());
3891
3892 base::TimeDelta next_delay = runner->GetDelayUntilNextProbeForTest(0);
3893 runner.reset();
3894
3895 // Server stays unavailable because probe canceled before (non-existent)
3896 // success. No success result is added, so this FastForward will cause a
3897 // failure if probes attempt to run.
3898 FastForwardBy(next_delay);
3899
3900 EXPECT_FALSE(doh_itr->AttemptAvailable());
3901 }
3902
TEST_F(DnsTransactionTestWithMockTime,CancelDohProbeOnContextDestruction)3903 TEST_F(DnsTransactionTestWithMockTime, CancelDohProbeOnContextDestruction) {
3904 ConfigureDohServers(/*use_post=*/true, /*num_doh_servers=*/1,
3905 /*make_available=*/false);
3906 AddQueryAndErrorResponse(/*id=*/0, kT4HostName, kT4Qtype,
3907 ERR_CONNECTION_REFUSED, SYNCHRONOUS,
3908 Transport::HTTPS, /*opt_rdata=*/nullptr,
3909 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
3910 /*enqueue_transaction_id=*/false);
3911 AddQueryAndErrorResponse(/*id=*/0, kT4HostName, kT4Qtype,
3912 ERR_CONNECTION_REFUSED, SYNCHRONOUS,
3913 Transport::HTTPS, /*opt_rdata=*/nullptr,
3914 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
3915 /* enqueue_transaction_id=*/false);
3916
3917 std::unique_ptr<DnsProbeRunner> runner =
3918 transaction_factory_->CreateDohProbeRunner(resolve_context_.get());
3919 runner->Start(/*network_change=*/false);
3920
3921 // The first probe happens without any delay.
3922 RunUntilIdle();
3923 std::unique_ptr<DnsServerIterator> doh_itr = resolve_context_->GetDohIterator(
3924 session_->config(), SecureDnsMode::kAutomatic, session_.get());
3925
3926 EXPECT_FALSE(doh_itr->AttemptAvailable());
3927
3928 // Expect the server to still be unavailable after the second probe.
3929 FastForwardBy(runner->GetDelayUntilNextProbeForTest(0));
3930
3931 EXPECT_FALSE(doh_itr->AttemptAvailable());
3932
3933 base::TimeDelta next_delay = runner->GetDelayUntilNextProbeForTest(0);
3934 resolve_context_.reset();
3935
3936 // The probe detects that the context no longer exists and stops running.
3937 FastForwardBy(next_delay);
3938
3939 // There are no more probes to run.
3940 EXPECT_EQ(base::TimeDelta(), runner->GetDelayUntilNextProbeForTest(0));
3941 }
3942
TEST_F(DnsTransactionTestWithMockTime,CancelOneOfMultipleProbeRunners)3943 TEST_F(DnsTransactionTestWithMockTime, CancelOneOfMultipleProbeRunners) {
3944 ConfigureDohServers(true /* use_post */, 1 /* num_doh_servers */,
3945 false /* make_available */);
3946 AddQueryAndErrorResponse(0 /* id */, kT4HostName, kT4Qtype,
3947 ERR_CONNECTION_REFUSED, SYNCHRONOUS,
3948 Transport::HTTPS, nullptr /* opt_rdata */,
3949 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
3950 false /* enqueue_transaction_id */);
3951 AddQueryAndErrorResponse(0 /* id */, kT4HostName, kT4Qtype,
3952 ERR_CONNECTION_REFUSED, SYNCHRONOUS,
3953 Transport::HTTPS, nullptr /* opt_rdata */,
3954 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
3955 false /* enqueue_transaction_id */);
3956 AddQueryAndResponse(0 /* id */, kT4HostName, kT4Qtype, kT4ResponseDatagram,
3957 std::size(kT4ResponseDatagram), ASYNC, Transport::HTTPS,
3958 nullptr /* opt_rdata */,
3959 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
3960 false /* enqueue_transaction_id */);
3961
3962 std::unique_ptr<DnsProbeRunner> runner1 =
3963 transaction_factory_->CreateDohProbeRunner(resolve_context_.get());
3964 std::unique_ptr<DnsProbeRunner> runner2 =
3965 transaction_factory_->CreateDohProbeRunner(resolve_context_.get());
3966 runner1->Start(true /* network_change */);
3967 runner2->Start(true /* network_change */);
3968
3969 // The first two probes (one for each runner) happen without any delay.
3970 RunUntilIdle();
3971 std::unique_ptr<DnsServerIterator> doh_itr = resolve_context_->GetDohIterator(
3972 session_->config(), SecureDnsMode::kAutomatic, session_.get());
3973
3974 EXPECT_FALSE(doh_itr->AttemptAvailable());
3975 EXPECT_GT(runner1->GetDelayUntilNextProbeForTest(0), base::TimeDelta());
3976 EXPECT_GT(runner2->GetDelayUntilNextProbeForTest(0), base::TimeDelta());
3977
3978 // Cancel only one probe runner.
3979 runner1.reset();
3980
3981 // Expect the server to be available after the successful third probe.
3982 FastForwardBy(runner2->GetDelayUntilNextProbeForTest(0));
3983
3984 ASSERT_TRUE(doh_itr->AttemptAvailable());
3985 EXPECT_EQ(doh_itr->GetNextAttemptIndex(), 0u);
3986 FastForwardBy(runner2->GetDelayUntilNextProbeForTest(0));
3987 EXPECT_EQ(runner2->GetDelayUntilNextProbeForTest(0), base::TimeDelta());
3988 }
3989
TEST_F(DnsTransactionTestWithMockTime,CancelAllOfMultipleProbeRunners)3990 TEST_F(DnsTransactionTestWithMockTime, CancelAllOfMultipleProbeRunners) {
3991 ConfigureDohServers(true /* use_post */, 1 /* num_doh_servers */,
3992 false /* make_available */);
3993 AddQueryAndErrorResponse(0 /* id */, kT4HostName, kT4Qtype,
3994 ERR_CONNECTION_REFUSED, SYNCHRONOUS,
3995 Transport::HTTPS, nullptr /* opt_rdata */,
3996 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
3997 false /* enqueue_transaction_id */);
3998 AddQueryAndErrorResponse(0 /* id */, kT4HostName, kT4Qtype,
3999 ERR_CONNECTION_REFUSED, SYNCHRONOUS,
4000 Transport::HTTPS, nullptr /* opt_rdata */,
4001 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
4002 false /* enqueue_transaction_id */);
4003
4004 std::unique_ptr<DnsProbeRunner> runner1 =
4005 transaction_factory_->CreateDohProbeRunner(resolve_context_.get());
4006 std::unique_ptr<DnsProbeRunner> runner2 =
4007 transaction_factory_->CreateDohProbeRunner(resolve_context_.get());
4008 runner1->Start(false /* network_change */);
4009 runner2->Start(false /* network_change */);
4010
4011 // The first two probes (one for each runner) happen without any delay.
4012 RunUntilIdle();
4013 std::unique_ptr<DnsServerIterator> doh_itr = resolve_context_->GetDohIterator(
4014 session_->config(), SecureDnsMode::kAutomatic, session_.get());
4015
4016 EXPECT_FALSE(doh_itr->AttemptAvailable());
4017 EXPECT_GT(runner1->GetDelayUntilNextProbeForTest(0), base::TimeDelta());
4018 EXPECT_GT(runner2->GetDelayUntilNextProbeForTest(0), base::TimeDelta());
4019
4020 base::TimeDelta next_delay = runner1->GetDelayUntilNextProbeForTest(0);
4021 runner1.reset();
4022 runner2.reset();
4023
4024 // Server stays unavailable because probe canceled before (non-existent)
4025 // success. No success result is added, so this FastForward will cause a
4026 // failure if probes attempt to run.
4027 FastForwardBy(next_delay);
4028 EXPECT_FALSE(doh_itr->AttemptAvailable());
4029 }
4030
TEST_F(DnsTransactionTestWithMockTime,CancelDohProbe_AfterSuccess)4031 TEST_F(DnsTransactionTestWithMockTime, CancelDohProbe_AfterSuccess) {
4032 ConfigureDohServers(true /* use_post */, 1 /* num_doh_servers */,
4033 false /* make_available */);
4034 AddQueryAndResponse(0 /* id */, kT4HostName, kT4Qtype, kT4ResponseDatagram,
4035 std::size(kT4ResponseDatagram), SYNCHRONOUS,
4036 Transport::HTTPS, nullptr /* opt_rdata */,
4037 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
4038 false /* enqueue_transaction_id */);
4039
4040 std::unique_ptr<DnsProbeRunner> runner =
4041 transaction_factory_->CreateDohProbeRunner(resolve_context_.get());
4042 runner->Start(true /* network_change */);
4043
4044 // The first probe happens without any delay, and immediately succeeds.
4045 RunUntilIdle();
4046 {
4047 std::unique_ptr<DnsServerIterator> doh_itr =
4048 resolve_context_->GetDohIterator(
4049 session_->config(), SecureDnsMode::kAutomatic, session_.get());
4050
4051 ASSERT_TRUE(doh_itr->AttemptAvailable());
4052 EXPECT_EQ(doh_itr->GetNextAttemptIndex(), 0u);
4053 }
4054
4055 runner.reset();
4056
4057 // No change expected after cancellation.
4058 RunUntilIdle();
4059 {
4060 std::unique_ptr<DnsServerIterator> doh_itr =
4061 resolve_context_->GetDohIterator(
4062 session_->config(), SecureDnsMode::kAutomatic, session_.get());
4063
4064 ASSERT_TRUE(doh_itr->AttemptAvailable());
4065 EXPECT_EQ(doh_itr->GetNextAttemptIndex(), 0u);
4066 }
4067 }
4068
TEST_F(DnsTransactionTestWithMockTime,DestroyFactoryAfterStartingDohProbe)4069 TEST_F(DnsTransactionTestWithMockTime, DestroyFactoryAfterStartingDohProbe) {
4070 ConfigureDohServers(true /* use_post */, 1 /* num_doh_servers */,
4071 false /* make_available */);
4072 AddQueryAndErrorResponse(0 /* id */, kT4HostName, kT4Qtype,
4073 ERR_CONNECTION_REFUSED, SYNCHRONOUS,
4074 Transport::HTTPS, nullptr /* opt_rdata */,
4075 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
4076 false /* enqueue_transaction_id */);
4077
4078 std::unique_ptr<DnsProbeRunner> runner =
4079 transaction_factory_->CreateDohProbeRunner(resolve_context_.get());
4080 runner->Start(false /* network_change */);
4081
4082 // The first probe happens without any delay.
4083 RunUntilIdle();
4084 std::unique_ptr<DnsServerIterator> doh_itr = resolve_context_->GetDohIterator(
4085 session_->config(), SecureDnsMode::kAutomatic, session_.get());
4086
4087 EXPECT_FALSE(doh_itr->AttemptAvailable());
4088
4089 // Destroy factory and session.
4090 transaction_factory_.reset();
4091 ASSERT_TRUE(session_->HasOneRef());
4092 session_.reset();
4093
4094 // Probe should not encounter issues and should stop running.
4095 FastForwardBy(runner->GetDelayUntilNextProbeForTest(0));
4096 EXPECT_EQ(runner->GetDelayUntilNextProbeForTest(0), base::TimeDelta());
4097 }
4098
TEST_F(DnsTransactionTestWithMockTime,StartWhileRunning)4099 TEST_F(DnsTransactionTestWithMockTime, StartWhileRunning) {
4100 ConfigureDohServers(true /* use_post */, 1 /* num_doh_servers */,
4101 false /* make_available */);
4102 AddQueryAndErrorResponse(0 /* id */, kT4HostName, kT4Qtype,
4103 ERR_CONNECTION_REFUSED, SYNCHRONOUS,
4104 Transport::HTTPS, nullptr /* opt_rdata */,
4105 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
4106 false /* enqueue_transaction_id */);
4107 AddQueryAndResponse(0 /* id */, kT4HostName, kT4Qtype, kT4ResponseDatagram,
4108 std::size(kT4ResponseDatagram), ASYNC, Transport::HTTPS,
4109 nullptr /* opt_rdata */,
4110 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
4111 false /* enqueue_transaction_id */);
4112
4113 std::unique_ptr<DnsProbeRunner> runner =
4114 transaction_factory_->CreateDohProbeRunner(resolve_context_.get());
4115 runner->Start(false /* network_change */);
4116
4117 // The first probe happens without any delay.
4118 RunUntilIdle();
4119 EXPECT_FALSE(resolve_context_->GetDohServerAvailability(
4120 0u /* doh_server_index */, session_.get()));
4121
4122 // Extra Start() call should have no effect because runner is already running.
4123 runner->Start(true /* network_change */);
4124 RunUntilIdle();
4125 EXPECT_FALSE(resolve_context_->GetDohServerAvailability(
4126 0u /* doh_server_index */, session_.get()));
4127
4128 // Expect the server to be available after the successful second probe.
4129 FastForwardBy(runner->GetDelayUntilNextProbeForTest(0));
4130 EXPECT_TRUE(resolve_context_->GetDohServerAvailability(
4131 0u /* doh_server_index */, session_.get()));
4132 }
4133
TEST_F(DnsTransactionTestWithMockTime,RestartFinishedProbe)4134 TEST_F(DnsTransactionTestWithMockTime, RestartFinishedProbe) {
4135 ConfigureDohServers(true /* use_post */, 1 /* num_doh_servers */,
4136 false /* make_available */);
4137 AddQueryAndResponse(0 /* id */, kT4HostName, kT4Qtype, kT4ResponseDatagram,
4138 std::size(kT4ResponseDatagram), ASYNC, Transport::HTTPS,
4139 nullptr /* opt_rdata */,
4140 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
4141 false /* enqueue_transaction_id */);
4142 AddQueryAndResponse(0 /* id */, kT4HostName, kT4Qtype, kT4ResponseDatagram,
4143 std::size(kT4ResponseDatagram), ASYNC, Transport::HTTPS,
4144 nullptr /* opt_rdata */,
4145 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
4146 false /* enqueue_transaction_id */);
4147
4148 std::unique_ptr<DnsProbeRunner> runner =
4149 transaction_factory_->CreateDohProbeRunner(resolve_context_.get());
4150 runner->Start(true /* network_change */);
4151
4152 // The first probe happens without any delay and succeeds.
4153 RunUntilIdle();
4154 EXPECT_TRUE(resolve_context_->GetDohServerAvailability(
4155 0u /* doh_server_index */, session_.get()));
4156
4157 // Expect runner to self-cancel on next cycle.
4158 FastForwardBy(runner->GetDelayUntilNextProbeForTest(0u));
4159 EXPECT_EQ(runner->GetDelayUntilNextProbeForTest(0u), base::TimeDelta());
4160
4161 // Mark server unavailabe and restart runner.
4162 for (int i = 0; i < ResolveContext::kAutomaticModeFailureLimit; ++i) {
4163 resolve_context_->RecordServerFailure(0u /* server_index */,
4164 true /* is_doh_server */, ERR_FAILED,
4165 session_.get());
4166 }
4167 ASSERT_FALSE(resolve_context_->GetDohServerAvailability(
4168 0u /* doh_server_index */, session_.get()));
4169 runner->Start(false /* network_change */);
4170
4171 // Expect the server to be available again after a successful immediately-run
4172 // probe.
4173 RunUntilIdle();
4174 EXPECT_TRUE(resolve_context_->GetDohServerAvailability(
4175 0u /* doh_server_index */, session_.get()));
4176
4177 // Expect self-cancel again.
4178 FastForwardBy(runner->GetDelayUntilNextProbeForTest(0u));
4179 EXPECT_EQ(runner->GetDelayUntilNextProbeForTest(0u), base::TimeDelta());
4180 }
4181
4182 // Test that a probe runner keeps running on the same schedule if it completes
4183 // but the server is marked unavailable again before the next scheduled probe.
TEST_F(DnsTransactionTestWithMockTime,FastProbeRestart)4184 TEST_F(DnsTransactionTestWithMockTime, FastProbeRestart) {
4185 ConfigureDohServers(true /* use_post */, 1 /* num_doh_servers */,
4186 false /* make_available */);
4187 AddQueryAndResponse(0 /* id */, kT4HostName, kT4Qtype, kT4ResponseDatagram,
4188 std::size(kT4ResponseDatagram), ASYNC, Transport::HTTPS,
4189 nullptr /* opt_rdata */,
4190 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
4191 false /* enqueue_transaction_id */);
4192 AddQueryAndResponse(0 /* id */, kT4HostName, kT4Qtype, kT4ResponseDatagram,
4193 std::size(kT4ResponseDatagram), ASYNC, Transport::HTTPS,
4194 nullptr /* opt_rdata */,
4195 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
4196 false /* enqueue_transaction_id */);
4197
4198 std::unique_ptr<DnsProbeRunner> runner =
4199 transaction_factory_->CreateDohProbeRunner(resolve_context_.get());
4200 runner->Start(true /* network_change */);
4201
4202 // The first probe happens without any delay and succeeds.
4203 RunUntilIdle();
4204 EXPECT_TRUE(resolve_context_->GetDohServerAvailability(
4205 0u /* doh_server_index */, session_.get()));
4206
4207 base::TimeDelta scheduled_delay = runner->GetDelayUntilNextProbeForTest(0);
4208 EXPECT_GT(scheduled_delay, base::TimeDelta());
4209
4210 // Mark server unavailabe and restart runner. Note that restarting the runner
4211 // is unnecessary, but a Start() call should always happen on a server
4212 // becoming unavailable and might as well replecate real behavior for the
4213 // test.
4214 for (int i = 0; i < ResolveContext::kAutomaticModeFailureLimit; ++i) {
4215 resolve_context_->RecordServerFailure(0u /* server_index */,
4216 true /* is_doh_server */, ERR_FAILED,
4217 session_.get());
4218 }
4219 ASSERT_FALSE(resolve_context_->GetDohServerAvailability(
4220 0u /* doh_server_index */, session_.get()));
4221 runner->Start(false /* network_change */);
4222
4223 // Probe should not run until scheduled delay.
4224 RunUntilIdle();
4225 EXPECT_FALSE(resolve_context_->GetDohServerAvailability(
4226 0u /* doh_server_index */, session_.get()));
4227
4228 // Expect the probe to run again and succeed after scheduled delay.
4229 FastForwardBy(scheduled_delay);
4230 EXPECT_TRUE(resolve_context_->GetDohServerAvailability(
4231 0u /* doh_server_index */, session_.get()));
4232 }
4233
4234 // Test that queries cannot be sent when they contain a too-long name.
4235 // Tests against incorrect name length validation, which is anti-pattern #3 from
4236 // the "NAME:WRECK" report:
4237 // https://www.forescout.com/company/resources/namewreck-breaking-and-fixing-dns-implementations/
TEST_F(DnsTransactionTestWithMockTime,RejectsQueryingLongNames)4238 TEST_F(DnsTransactionTestWithMockTime, RejectsQueryingLongNames) {
4239 std::string long_dotted_name;
4240 while (long_dotted_name.size() <= dns_protocol::kMaxNameLength) {
4241 long_dotted_name.append("naaaaaamelabel.");
4242 }
4243 long_dotted_name.append("test");
4244
4245 TransactionHelper helper0(ERR_INVALID_ARGUMENT);
4246 helper0.StartTransaction(transaction_factory_.get(), long_dotted_name.c_str(),
4247 dns_protocol::kTypeA, false /* secure */,
4248 resolve_context_.get());
4249 helper0.RunUntilComplete();
4250 }
4251
4252 // Test that ERR_CONNECTION_REFUSED error after fallback of DnsTCPAttempt
4253 // should not cause DCHECK failure (https://crbug.com/1334250).
TEST_F(DnsTransactionTestWithMockTime,TcpConnectionRefusedAfterFallback)4254 TEST_F(DnsTransactionTestWithMockTime, TcpConnectionRefusedAfterFallback) {
4255 ConfigureNumServers(2);
4256 ConfigureFactory();
4257 socket_factory_->diverse_source_ports_ = false;
4258
4259 // Data for UDP attempts to set `low_entropy` flag.
4260 for (int i = 0; i <= DnsUdpTracker::kPortReuseThreshold; ++i) {
4261 AddQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype, kT0ResponseDatagram,
4262 std::size(kT0ResponseDatagram), ASYNC, Transport::UDP);
4263 }
4264
4265 // Data for TCP attempt.
4266 auto data1 = std::make_unique<DnsSocketData>(0 /* id */, kT0HostName,
4267 kT0Qtype, ASYNC, Transport::TCP);
4268 data1->AddReadError(ERR_IO_PENDING, ASYNC);
4269 data1->AddReadError(ERR_CONNECTION_REFUSED, ASYNC);
4270 SequencedSocketData* sequenced_socket_data1 = data1->GetProvider();
4271 AddSocketData(std::move(data1));
4272
4273 auto data2 = std::make_unique<DnsSocketData>(0 /* id */, kT0HostName,
4274 kT0Qtype, ASYNC, Transport::TCP);
4275 data2->AddReadError(ERR_IO_PENDING, ASYNC);
4276 data2->AddResponseData(kT0ResponseDatagram, std::size(kT0ResponseDatagram),
4277 ASYNC);
4278 SequencedSocketData* sequenced_socket_data2 = data2->GetProvider();
4279 AddSocketData(std::move(data2));
4280
4281 // DNS transactions for UDP attempts to set `low_entropy` flag.
4282 for (int i = 0; i <= DnsUdpTracker::kPortReuseThreshold; ++i) {
4283 TransactionHelper udp_helper(kT0RecordCount);
4284 udp_helper.StartTransaction(transaction_factory_.get(), kT0HostName,
4285 kT0Qtype, false /* secure */,
4286 resolve_context_.get());
4287 udp_helper.RunUntilComplete();
4288 }
4289
4290 ASSERT_TRUE(session_->udp_tracker()->low_entropy());
4291
4292 // DNS transactions for TCP attempt.
4293 TransactionHelper helper0(kT0RecordCount);
4294 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
4295 false /* secure */, resolve_context_.get());
4296 base::RunLoop().RunUntilIdle();
4297 EXPECT_FALSE(helper0.has_completed());
4298
4299 base::TimeDelta timeout = resolve_context_->NextClassicFallbackPeriod(
4300 0 /* classic_server_index */, 0 /* attempt */, session_.get());
4301 FastForwardBy(timeout);
4302
4303 // Resume the first query.
4304 sequenced_socket_data1->Resume();
4305
4306 base::RunLoop().RunUntilIdle();
4307 EXPECT_FALSE(helper0.has_completed());
4308
4309 // Resume the second query.
4310 sequenced_socket_data2->Resume();
4311 base::RunLoop().RunUntilIdle();
4312
4313 EXPECT_TRUE(helper0.has_completed());
4314 }
4315
4316 // Test that ERR_CONNECTION_REFUSED error after fallback of DnsHTTPAttempt
4317 // should not cause DCHECK failure (https://crbug.com/1334250).
TEST_F(DnsTransactionTestWithMockTime,HttpsConnectionRefusedAfterFallback)4318 TEST_F(DnsTransactionTestWithMockTime, HttpsConnectionRefusedAfterFallback) {
4319 ConfigureDohServers(false /* use_post */, 2 /* num_doh_servers */,
4320 true /* make_available */);
4321
4322 auto data1 = std::make_unique<DnsSocketData>(
4323 0 /* id */, kT0HostName, kT0Qtype, ASYNC, Transport::HTTPS,
4324 nullptr /* opt_rdata */, DnsQuery::PaddingStrategy::BLOCK_LENGTH_128);
4325 data1->AddReadError(ERR_IO_PENDING, ASYNC);
4326 data1->AddReadError(ERR_CONNECTION_REFUSED, ASYNC);
4327 SequencedSocketData* sequenced_socket_data1 = data1->GetProvider();
4328 AddSocketData(std::move(data1), false /* enqueue_transaction_id */);
4329
4330 auto data2 = std::make_unique<DnsSocketData>(
4331 0 /* id */, kT0HostName, kT0Qtype, ASYNC, Transport::HTTPS,
4332 nullptr /* opt_rdata */, DnsQuery::PaddingStrategy::BLOCK_LENGTH_128);
4333 data2->AddReadError(ERR_IO_PENDING, ASYNC);
4334 data2->AddResponseData(kT0ResponseDatagram, std::size(kT0ResponseDatagram),
4335 ASYNC);
4336 SequencedSocketData* sequenced_socket_data2 = data2->GetProvider();
4337 AddSocketData(std::move(data2), false /* enqueue_transaction_id */);
4338
4339 TransactionHelper helper0(kT0RecordCount);
4340 helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
4341 true /* secure */, resolve_context_.get());
4342 base::RunLoop().RunUntilIdle();
4343 EXPECT_FALSE(helper0.has_completed());
4344
4345 base::TimeDelta timeout = resolve_context_->NextDohFallbackPeriod(
4346 0 /* doh_server_index */, session_.get());
4347 FastForwardBy(timeout);
4348
4349 // Resume the first query.
4350 sequenced_socket_data1->Resume();
4351
4352 base::RunLoop().RunUntilIdle();
4353 EXPECT_FALSE(helper0.has_completed());
4354
4355 // Resume the second query.
4356 sequenced_socket_data2->Resume();
4357
4358 EXPECT_TRUE(helper0.has_completed());
4359 }
4360
4361 } // namespace
4362
4363 } // namespace net
4364