1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "net/dns/dns_transaction.h"
8 #include "base/memory/scoped_ptr.h"
9 #include "base/memory/scoped_vector.h"
10 #include "base/rand_util.h"
11 #include "base/sys_byteorder.h"
12 #include "base/test/test_timeouts.h"
13 #include "net/base/dns_util.h"
14 #include "net/dns/dns_protocol.h"
15 #include "net/dns/dns_query.h"
16 #include "net/dns/dns_response.h"
17 #include "net/dns/dns_session.h"
18 #include "net/dns/dns_test_util.h"
19 #include "net/log/net_log.h"
20 #include "net/socket/socket_test_util.h"
21 #include "testing/gtest/include/gtest/gtest.h"
27 std::string
DomainFromDot(const base::StringPiece
& dotted
) {
29 EXPECT_TRUE(DNSDomainFromDot(dotted
, &out
));
33 // A SocketDataProvider builder.
36 // The ctor takes parameters for the DnsQuery.
37 DnsSocketData(uint16 id
,
38 const char* dotted_name
,
42 : query_(new DnsQuery(id
, DomainFromDot(dotted_name
), qtype
)),
45 scoped_ptr
<uint16
> length(new uint16
);
46 *length
= base::HostToNet16(query_
->io_buffer()->size());
47 writes_
.push_back(MockWrite(mode
,
48 reinterpret_cast<const char*>(length
.get()),
49 sizeof(uint16
), num_reads_and_writes()));
50 lengths_
.push_back(length
.Pass());
52 writes_
.push_back(MockWrite(mode
, query_
->io_buffer()->data(),
53 query_
->io_buffer()->size(),
54 num_reads_and_writes()));
58 // All responses must be added before GetProvider.
60 // Adds pre-built DnsResponse. |tcp_length| will be used in TCP mode only.
61 void AddResponseWithLength(scoped_ptr
<DnsResponse
> response
, IoMode mode
,
63 CHECK(!provider_
.get());
65 scoped_ptr
<uint16
> length(new uint16
);
66 *length
= base::HostToNet16(tcp_length
);
67 reads_
.push_back(MockRead(mode
,
68 reinterpret_cast<const char*>(length
.get()),
69 sizeof(uint16
), num_reads_and_writes()));
70 lengths_
.push_back(length
.Pass());
72 reads_
.push_back(MockRead(mode
, response
->io_buffer()->data(),
73 response
->io_buffer()->size(),
74 num_reads_and_writes()));
75 responses_
.push_back(response
.Pass());
78 // Adds pre-built DnsResponse.
79 void AddResponse(scoped_ptr
<DnsResponse
> response
, IoMode mode
) {
80 uint16 tcp_length
= response
->io_buffer()->size();
81 AddResponseWithLength(response
.Pass(), mode
, tcp_length
);
84 // Adds pre-built response from |data| buffer.
85 void AddResponseData(const uint8
* data
, size_t length
, IoMode mode
) {
86 CHECK(!provider_
.get());
87 AddResponse(make_scoped_ptr(
88 new DnsResponse(reinterpret_cast<const char*>(data
), length
, 0)), mode
);
91 // Add no-answer (RCODE only) response matching the query.
92 void AddRcode(int rcode
, IoMode mode
) {
93 scoped_ptr
<DnsResponse
> response(
94 new DnsResponse(query_
->io_buffer()->data(),
95 query_
->io_buffer()->size(),
97 dns_protocol::Header
* header
=
98 reinterpret_cast<dns_protocol::Header
*>(response
->io_buffer()->data());
99 header
->flags
|= base::HostToNet16(dns_protocol::kFlagResponse
| rcode
);
100 AddResponse(response
.Pass(), mode
);
103 // Add error response.
104 void AddReadError(int error
, IoMode mode
) {
105 reads_
.push_back(MockRead(mode
, error
, num_reads_and_writes()));
108 // Build, if needed, and return the SocketDataProvider. No new responses
109 // should be added afterwards.
110 SequencedSocketData
* GetProvider() {
112 return provider_
.get();
113 // Terminate the reads with ERR_IO_PENDING to prevent overrun and default to
116 MockRead(ASYNC
, ERR_IO_PENDING
, writes_
.size() + reads_
.size()));
117 provider_
.reset(new SequencedSocketData(&reads_
[0], reads_
.size(),
118 &writes_
[0], writes_
.size()));
120 provider_
->set_connect_data(MockConnect(reads_
[0].mode
, OK
));
122 return provider_
.get();
125 uint16
query_id() const {
130 size_t num_reads_and_writes() const { return reads_
.size() + writes_
.size(); }
132 scoped_ptr
<DnsQuery
> query_
;
134 ScopedVector
<uint16
> lengths_
;
135 ScopedVector
<DnsResponse
> responses_
;
136 std::vector
<MockWrite
> writes_
;
137 std::vector
<MockRead
> reads_
;
138 scoped_ptr
<SequencedSocketData
> provider_
;
140 DISALLOW_COPY_AND_ASSIGN(DnsSocketData
);
143 class TestSocketFactory
;
145 // A variant of MockUDPClientSocket which always fails to Connect.
146 class FailingUDPClientSocket
: public MockUDPClientSocket
{
148 FailingUDPClientSocket(SocketDataProvider
* data
,
149 net::NetLog
* net_log
)
150 : MockUDPClientSocket(data
, net_log
) {
152 ~FailingUDPClientSocket() override
{}
153 int Connect(const IPEndPoint
& endpoint
) override
{
154 return ERR_CONNECTION_REFUSED
;
158 DISALLOW_COPY_AND_ASSIGN(FailingUDPClientSocket
);
161 // A variant of MockUDPClientSocket which notifies the factory OnConnect.
162 class TestUDPClientSocket
: public MockUDPClientSocket
{
164 TestUDPClientSocket(TestSocketFactory
* factory
,
165 SocketDataProvider
* data
,
166 net::NetLog
* net_log
)
167 : MockUDPClientSocket(data
, net_log
), factory_(factory
) {
169 ~TestUDPClientSocket() override
{}
170 int Connect(const IPEndPoint
& endpoint
) override
;
173 TestSocketFactory
* factory_
;
175 DISALLOW_COPY_AND_ASSIGN(TestUDPClientSocket
);
178 // Creates TestUDPClientSockets and keeps endpoints reported via OnConnect.
179 class TestSocketFactory
: public MockClientSocketFactory
{
181 TestSocketFactory() : fail_next_socket_(false) {}
182 ~TestSocketFactory() override
{}
184 scoped_ptr
<DatagramClientSocket
> CreateDatagramClientSocket(
185 DatagramSocket::BindType bind_type
,
186 const RandIntCallback
& rand_int_cb
,
188 const NetLog::Source
& source
) override
{
189 if (fail_next_socket_
) {
190 fail_next_socket_
= false;
191 return scoped_ptr
<DatagramClientSocket
>(
192 new FailingUDPClientSocket(&empty_data_
, net_log
));
194 SocketDataProvider
* data_provider
= mock_data().GetNext();
195 scoped_ptr
<TestUDPClientSocket
> socket(
196 new TestUDPClientSocket(this, data_provider
, net_log
));
197 data_provider
->set_socket(socket
.get());
198 return socket
.Pass();
201 void OnConnect(const IPEndPoint
& endpoint
) {
202 remote_endpoints_
.push_back(endpoint
);
205 std::vector
<IPEndPoint
> remote_endpoints_
;
206 bool fail_next_socket_
;
209 StaticSocketDataProvider empty_data_
;
211 DISALLOW_COPY_AND_ASSIGN(TestSocketFactory
);
214 int TestUDPClientSocket::Connect(const IPEndPoint
& endpoint
) {
215 factory_
->OnConnect(endpoint
);
216 return MockUDPClientSocket::Connect(endpoint
);
219 // Helper class that holds a DnsTransaction and handles OnTransactionComplete.
220 class TransactionHelper
{
222 // If |expected_answer_count| < 0 then it is the expected net error.
223 TransactionHelper(const char* hostname
,
225 int expected_answer_count
)
226 : hostname_(hostname
),
228 expected_answer_count_(expected_answer_count
),
229 cancel_in_callback_(false),
230 quit_in_callback_(false),
234 // Mark that the transaction shall be destroyed immediately upon callback.
235 void set_cancel_in_callback() {
236 cancel_in_callback_
= true;
239 // Mark to call MessageLoop::Quit() upon callback.
240 void set_quit_in_callback() {
241 quit_in_callback_
= true;
244 void StartTransaction(DnsTransactionFactory
* factory
) {
245 EXPECT_EQ(NULL
, transaction_
.get());
246 transaction_
= factory
->CreateTransaction(
249 base::Bind(&TransactionHelper::OnTransactionComplete
,
250 base::Unretained(this)),
252 EXPECT_EQ(hostname_
, transaction_
->GetHostname());
253 EXPECT_EQ(qtype_
, transaction_
->GetType());
254 transaction_
->Start();
258 ASSERT_TRUE(transaction_
.get() != NULL
);
259 transaction_
.reset(NULL
);
262 void OnTransactionComplete(DnsTransaction
* t
,
264 const DnsResponse
* response
) {
265 EXPECT_FALSE(completed_
);
266 EXPECT_EQ(transaction_
.get(), t
);
270 if (cancel_in_callback_
) {
275 // Tell MessageLoop to quit now, in case any ASSERT_* fails.
276 if (quit_in_callback_
)
277 base::MessageLoop::current()->Quit();
279 if (expected_answer_count_
>= 0) {
281 ASSERT_TRUE(response
!= NULL
);
282 EXPECT_EQ(static_cast<unsigned>(expected_answer_count_
),
283 response
->answer_count());
284 EXPECT_EQ(qtype_
, response
->qtype());
286 DnsRecordParser parser
= response
->Parser();
287 DnsResourceRecord record
;
288 for (int i
= 0; i
< expected_answer_count_
; ++i
) {
289 EXPECT_TRUE(parser
.ReadRecord(&record
));
292 EXPECT_EQ(expected_answer_count_
, rv
);
296 bool has_completed() const {
300 // Shorthands for commonly used commands.
302 bool Run(DnsTransactionFactory
* factory
) {
303 StartTransaction(factory
);
304 base::MessageLoop::current()->RunUntilIdle();
305 return has_completed();
308 // Use when some of the responses are timeouts.
309 bool RunUntilDone(DnsTransactionFactory
* factory
) {
310 set_quit_in_callback();
311 StartTransaction(factory
);
312 base::MessageLoop::current()->Run();
313 return has_completed();
317 std::string hostname_
;
319 scoped_ptr
<DnsTransaction
> transaction_
;
320 int expected_answer_count_
;
321 bool cancel_in_callback_
;
322 bool quit_in_callback_
;
327 class DnsTransactionTest
: public testing::Test
{
329 DnsTransactionTest() {}
331 // Generates |nameservers| for DnsConfig.
332 void ConfigureNumServers(unsigned num_servers
) {
333 CHECK_LE(num_servers
, 255u);
334 config_
.nameservers
.clear();
335 IPAddressNumber dns_ip
;
337 bool rv
= ParseIPLiteralToNumber("192.168.1.0", &dns_ip
);
340 for (unsigned i
= 0; i
< num_servers
; ++i
) {
342 config_
.nameservers
.push_back(IPEndPoint(dns_ip
,
343 dns_protocol::kDefaultPort
));
347 // Called after fully configuring |config|.
348 void ConfigureFactory() {
349 socket_factory_
.reset(new TestSocketFactory());
350 session_
= new DnsSession(
352 DnsSocketPool::CreateNull(socket_factory_
.get()),
353 base::Bind(&DnsTransactionTest::GetNextId
, base::Unretained(this)),
355 transaction_factory_
= DnsTransactionFactory::CreateFactory(session_
.get());
358 void AddSocketData(scoped_ptr
<DnsSocketData
> data
) {
359 CHECK(socket_factory_
.get());
360 transaction_ids_
.push_back(data
->query_id());
361 socket_factory_
->AddSocketDataProvider(data
->GetProvider());
362 socket_data_
.push_back(data
.Pass());
365 // Add expected query for |dotted_name| and |qtype| with |id| and response
366 // taken verbatim from |data| of |data_length| bytes. The transaction id in
367 // |data| should equal |id|, unless testing mismatched response.
368 void AddQueryAndResponse(uint16 id
,
369 const char* dotted_name
,
371 const uint8
* response_data
,
372 size_t response_length
,
375 CHECK(socket_factory_
.get());
376 scoped_ptr
<DnsSocketData
> data(
377 new DnsSocketData(id
, dotted_name
, qtype
, mode
, use_tcp
));
378 data
->AddResponseData(response_data
, response_length
, mode
);
379 AddSocketData(data
.Pass());
382 void AddAsyncQueryAndResponse(uint16 id
,
383 const char* dotted_name
,
386 size_t data_length
) {
387 AddQueryAndResponse(id
, dotted_name
, qtype
, data
, data_length
, ASYNC
,
391 void AddSyncQueryAndResponse(uint16 id
,
392 const char* dotted_name
,
395 size_t data_length
) {
396 AddQueryAndResponse(id
, dotted_name
, qtype
, data
, data_length
, SYNCHRONOUS
,
400 // Add expected query of |dotted_name| and |qtype| and no response.
401 void AddQueryAndTimeout(const char* dotted_name
, uint16 qtype
) {
402 uint16 id
= base::RandInt(0, kuint16max
);
403 scoped_ptr
<DnsSocketData
> data(
404 new DnsSocketData(id
, dotted_name
, qtype
, ASYNC
, false));
405 AddSocketData(data
.Pass());
408 // Add expected query of |dotted_name| and |qtype| and matching response with
409 // no answer and RCODE set to |rcode|. The id will be generated randomly.
410 void AddQueryAndRcode(const char* dotted_name
,
415 CHECK_NE(dns_protocol::kRcodeNOERROR
, rcode
);
416 uint16 id
= base::RandInt(0, kuint16max
);
417 scoped_ptr
<DnsSocketData
> data(
418 new DnsSocketData(id
, dotted_name
, qtype
, mode
, use_tcp
));
419 data
->AddRcode(rcode
, mode
);
420 AddSocketData(data
.Pass());
423 void AddAsyncQueryAndRcode(const char* dotted_name
, uint16 qtype
, int rcode
) {
424 AddQueryAndRcode(dotted_name
, qtype
, rcode
, ASYNC
, false);
427 void AddSyncQueryAndRcode(const char* dotted_name
, uint16 qtype
, int rcode
) {
428 AddQueryAndRcode(dotted_name
, qtype
, rcode
, SYNCHRONOUS
, false);
431 // Checks if the sockets were connected in the order matching the indices in
433 void CheckServerOrder(const unsigned* servers
, size_t num_attempts
) {
434 ASSERT_EQ(num_attempts
, socket_factory_
->remote_endpoints_
.size());
435 for (size_t i
= 0; i
< num_attempts
; ++i
) {
436 EXPECT_EQ(socket_factory_
->remote_endpoints_
[i
],
437 session_
->config().nameservers
[servers
[i
]]);
441 void SetUp() override
{
442 // By default set one server,
443 ConfigureNumServers(1);
444 // and no retransmissions,
445 config_
.attempts
= 1;
446 // but long enough timeout for memory tests.
447 config_
.timeout
= TestTimeouts::action_timeout();
451 void TearDown() override
{
452 // Check that all socket data was at least written to.
453 for (size_t i
= 0; i
< socket_data_
.size(); ++i
) {
454 EXPECT_TRUE(socket_data_
[i
]->GetProvider()->AllWriteDataConsumed()) << i
;
459 int GetNextId(int min
, int max
) {
460 EXPECT_FALSE(transaction_ids_
.empty());
461 int id
= transaction_ids_
.front();
462 transaction_ids_
.pop_front();
470 ScopedVector
<DnsSocketData
> socket_data_
;
472 std::deque
<int> transaction_ids_
;
473 scoped_ptr
<TestSocketFactory
> socket_factory_
;
474 scoped_refptr
<DnsSession
> session_
;
475 scoped_ptr
<DnsTransactionFactory
> transaction_factory_
;
478 TEST_F(DnsTransactionTest
, Lookup
) {
479 AddAsyncQueryAndResponse(0 /* id */, kT0HostName
, kT0Qtype
,
480 kT0ResponseDatagram
, arraysize(kT0ResponseDatagram
));
482 TransactionHelper
helper0(kT0HostName
, kT0Qtype
, kT0RecordCount
);
483 EXPECT_TRUE(helper0
.Run(transaction_factory_
.get()));
486 // Concurrent lookup tests assume that DnsTransaction::Start immediately
487 // consumes a socket from ClientSocketFactory.
488 TEST_F(DnsTransactionTest
, ConcurrentLookup
) {
489 AddAsyncQueryAndResponse(0 /* id */, kT0HostName
, kT0Qtype
,
490 kT0ResponseDatagram
, arraysize(kT0ResponseDatagram
));
491 AddAsyncQueryAndResponse(1 /* id */, kT1HostName
, kT1Qtype
,
492 kT1ResponseDatagram
, arraysize(kT1ResponseDatagram
));
494 TransactionHelper
helper0(kT0HostName
, kT0Qtype
, kT0RecordCount
);
495 helper0
.StartTransaction(transaction_factory_
.get());
496 TransactionHelper
helper1(kT1HostName
, kT1Qtype
, kT1RecordCount
);
497 helper1
.StartTransaction(transaction_factory_
.get());
499 base::MessageLoop::current()->RunUntilIdle();
501 EXPECT_TRUE(helper0
.has_completed());
502 EXPECT_TRUE(helper1
.has_completed());
505 TEST_F(DnsTransactionTest
, CancelLookup
) {
506 AddAsyncQueryAndResponse(0 /* id */, kT0HostName
, kT0Qtype
,
507 kT0ResponseDatagram
, arraysize(kT0ResponseDatagram
));
508 AddAsyncQueryAndResponse(1 /* id */, kT1HostName
, kT1Qtype
,
509 kT1ResponseDatagram
, arraysize(kT1ResponseDatagram
));
511 TransactionHelper
helper0(kT0HostName
, kT0Qtype
, kT0RecordCount
);
512 helper0
.StartTransaction(transaction_factory_
.get());
513 TransactionHelper
helper1(kT1HostName
, kT1Qtype
, kT1RecordCount
);
514 helper1
.StartTransaction(transaction_factory_
.get());
517 // Since the transaction has been cancelled, the assocaited socket has been
518 // destroyed, so make sure the data provide does not attempt to callback
520 // TODO(rch): Make the SocketDataProvider and MockSocket do this by default.
521 socket_data_
[0]->GetProvider()->set_socket(nullptr);
523 base::MessageLoop::current()->RunUntilIdle();
525 EXPECT_FALSE(helper0
.has_completed());
526 EXPECT_TRUE(helper1
.has_completed());
529 TEST_F(DnsTransactionTest
, DestroyFactory
) {
530 AddAsyncQueryAndResponse(0 /* id */, kT0HostName
, kT0Qtype
,
531 kT0ResponseDatagram
, arraysize(kT0ResponseDatagram
));
533 TransactionHelper
helper0(kT0HostName
, kT0Qtype
, kT0RecordCount
);
534 helper0
.StartTransaction(transaction_factory_
.get());
536 // Destroying the client does not affect running requests.
537 transaction_factory_
.reset(NULL
);
539 base::MessageLoop::current()->RunUntilIdle();
541 EXPECT_TRUE(helper0
.has_completed());
544 TEST_F(DnsTransactionTest
, CancelFromCallback
) {
545 AddAsyncQueryAndResponse(0 /* id */, kT0HostName
, kT0Qtype
,
546 kT0ResponseDatagram
, arraysize(kT0ResponseDatagram
));
548 TransactionHelper
helper0(kT0HostName
, kT0Qtype
, kT0RecordCount
);
549 helper0
.set_cancel_in_callback();
550 EXPECT_TRUE(helper0
.Run(transaction_factory_
.get()));
553 TEST_F(DnsTransactionTest
, MismatchedResponseSync
) {
554 config_
.attempts
= 2;
555 config_
.timeout
= TestTimeouts::tiny_timeout();
558 // Attempt receives mismatched response followed by valid response.
559 scoped_ptr
<DnsSocketData
> data(
560 new DnsSocketData(0 /* id */, kT0HostName
, kT0Qtype
, SYNCHRONOUS
, false));
561 data
->AddResponseData(kT1ResponseDatagram
,
562 arraysize(kT1ResponseDatagram
), SYNCHRONOUS
);
563 data
->AddResponseData(kT0ResponseDatagram
,
564 arraysize(kT0ResponseDatagram
), SYNCHRONOUS
);
565 AddSocketData(data
.Pass());
567 TransactionHelper
helper0(kT0HostName
, kT0Qtype
, kT0RecordCount
);
568 EXPECT_TRUE(helper0
.RunUntilDone(transaction_factory_
.get()));
571 TEST_F(DnsTransactionTest
, MismatchedResponseAsync
) {
572 config_
.attempts
= 2;
573 config_
.timeout
= TestTimeouts::tiny_timeout();
576 // First attempt receives mismatched response followed by valid response.
577 // Second attempt times out.
578 scoped_ptr
<DnsSocketData
> data(
579 new DnsSocketData(0 /* id */, kT0HostName
, kT0Qtype
, ASYNC
, false));
580 data
->AddResponseData(kT1ResponseDatagram
,
581 arraysize(kT1ResponseDatagram
), ASYNC
);
582 data
->AddResponseData(kT0ResponseDatagram
,
583 arraysize(kT0ResponseDatagram
), ASYNC
);
584 AddSocketData(data
.Pass());
585 AddQueryAndTimeout(kT0HostName
, kT0Qtype
);
587 TransactionHelper
helper0(kT0HostName
, kT0Qtype
, kT0RecordCount
);
588 EXPECT_TRUE(helper0
.RunUntilDone(transaction_factory_
.get()));
591 TEST_F(DnsTransactionTest
, MismatchedResponseFail
) {
592 config_
.timeout
= TestTimeouts::tiny_timeout();
595 // Attempt receives mismatched response but times out because only one attempt
597 AddAsyncQueryAndResponse(1 /* id */, kT0HostName
, kT0Qtype
,
598 kT0ResponseDatagram
, arraysize(kT0ResponseDatagram
));
600 TransactionHelper
helper0(kT0HostName
, kT0Qtype
, ERR_DNS_TIMED_OUT
);
601 EXPECT_TRUE(helper0
.RunUntilDone(transaction_factory_
.get()));
604 TEST_F(DnsTransactionTest
, ServerFail
) {
605 AddAsyncQueryAndRcode(kT0HostName
, kT0Qtype
, dns_protocol::kRcodeSERVFAIL
);
607 TransactionHelper
helper0(kT0HostName
, kT0Qtype
, ERR_DNS_SERVER_FAILED
);
608 EXPECT_TRUE(helper0
.Run(transaction_factory_
.get()));
611 TEST_F(DnsTransactionTest
, NoDomain
) {
612 AddAsyncQueryAndRcode(kT0HostName
, kT0Qtype
, dns_protocol::kRcodeNXDOMAIN
);
614 TransactionHelper
helper0(kT0HostName
, kT0Qtype
, ERR_NAME_NOT_RESOLVED
);
615 EXPECT_TRUE(helper0
.Run(transaction_factory_
.get()));
618 TEST_F(DnsTransactionTest
, Timeout
) {
619 config_
.attempts
= 3;
620 // Use short timeout to speed up the test.
621 config_
.timeout
= TestTimeouts::tiny_timeout();
624 AddQueryAndTimeout(kT0HostName
, kT0Qtype
);
625 AddQueryAndTimeout(kT0HostName
, kT0Qtype
);
626 AddQueryAndTimeout(kT0HostName
, kT0Qtype
);
628 TransactionHelper
helper0(kT0HostName
, kT0Qtype
, ERR_DNS_TIMED_OUT
);
629 EXPECT_TRUE(helper0
.RunUntilDone(transaction_factory_
.get()));
630 EXPECT_TRUE(base::MessageLoop::current()->IsIdleForTesting());
633 TEST_F(DnsTransactionTest
, ServerFallbackAndRotate
) {
634 // Test that we fallback on both server failure and timeout.
635 config_
.attempts
= 2;
636 // The next request should start from the next server.
637 config_
.rotate
= true;
638 ConfigureNumServers(3);
639 // Use short timeout to speed up the test.
640 config_
.timeout
= TestTimeouts::tiny_timeout();
643 // Responses for first request.
644 AddQueryAndTimeout(kT0HostName
, kT0Qtype
);
645 AddAsyncQueryAndRcode(kT0HostName
, kT0Qtype
, dns_protocol::kRcodeSERVFAIL
);
646 AddQueryAndTimeout(kT0HostName
, kT0Qtype
);
647 AddAsyncQueryAndRcode(kT0HostName
, kT0Qtype
, dns_protocol::kRcodeSERVFAIL
);
648 AddAsyncQueryAndRcode(kT0HostName
, kT0Qtype
, dns_protocol::kRcodeNXDOMAIN
);
649 // Responses for second request.
650 AddAsyncQueryAndRcode(kT1HostName
, kT1Qtype
, dns_protocol::kRcodeSERVFAIL
);
651 AddAsyncQueryAndRcode(kT1HostName
, kT1Qtype
, dns_protocol::kRcodeSERVFAIL
);
652 AddAsyncQueryAndRcode(kT1HostName
, kT1Qtype
, dns_protocol::kRcodeNXDOMAIN
);
654 TransactionHelper
helper0(kT0HostName
, kT0Qtype
, ERR_NAME_NOT_RESOLVED
);
655 TransactionHelper
helper1(kT1HostName
, kT1Qtype
, ERR_NAME_NOT_RESOLVED
);
657 EXPECT_TRUE(helper0
.RunUntilDone(transaction_factory_
.get()));
658 EXPECT_TRUE(helper1
.Run(transaction_factory_
.get()));
660 unsigned kOrder
[] = {
661 0, 1, 2, 0, 1, // The first transaction.
662 1, 2, 0, // The second transaction starts from the next server.
664 CheckServerOrder(kOrder
, arraysize(kOrder
));
667 TEST_F(DnsTransactionTest
, SuffixSearchAboveNdots
) {
669 config_
.search
.push_back("a");
670 config_
.search
.push_back("b");
671 config_
.search
.push_back("c");
672 config_
.rotate
= true;
673 ConfigureNumServers(2);
676 AddAsyncQueryAndRcode("x.y.z", dns_protocol::kTypeA
,
677 dns_protocol::kRcodeNXDOMAIN
);
678 AddAsyncQueryAndRcode("x.y.z.a", dns_protocol::kTypeA
,
679 dns_protocol::kRcodeNXDOMAIN
);
680 AddAsyncQueryAndRcode("x.y.z.b", dns_protocol::kTypeA
,
681 dns_protocol::kRcodeNXDOMAIN
);
682 AddAsyncQueryAndRcode("x.y.z.c", dns_protocol::kTypeA
,
683 dns_protocol::kRcodeNXDOMAIN
);
685 TransactionHelper
helper0("x.y.z", dns_protocol::kTypeA
,
686 ERR_NAME_NOT_RESOLVED
);
688 EXPECT_TRUE(helper0
.Run(transaction_factory_
.get()));
690 // Also check if suffix search causes server rotation.
691 unsigned kOrder0
[] = { 0, 1, 0, 1 };
692 CheckServerOrder(kOrder0
, arraysize(kOrder0
));
695 TEST_F(DnsTransactionTest
, SuffixSearchBelowNdots
) {
697 config_
.search
.push_back("a");
698 config_
.search
.push_back("b");
699 config_
.search
.push_back("c");
702 // Responses for first transaction.
703 AddAsyncQueryAndRcode("x.y.a", dns_protocol::kTypeA
,
704 dns_protocol::kRcodeNXDOMAIN
);
705 AddAsyncQueryAndRcode("x.y.b", dns_protocol::kTypeA
,
706 dns_protocol::kRcodeNXDOMAIN
);
707 AddAsyncQueryAndRcode("x.y.c", dns_protocol::kTypeA
,
708 dns_protocol::kRcodeNXDOMAIN
);
709 AddAsyncQueryAndRcode("x.y", dns_protocol::kTypeA
,
710 dns_protocol::kRcodeNXDOMAIN
);
711 // Responses for second transaction.
712 AddAsyncQueryAndRcode("x.a", dns_protocol::kTypeA
,
713 dns_protocol::kRcodeNXDOMAIN
);
714 AddAsyncQueryAndRcode("x.b", dns_protocol::kTypeA
,
715 dns_protocol::kRcodeNXDOMAIN
);
716 AddAsyncQueryAndRcode("x.c", dns_protocol::kTypeA
,
717 dns_protocol::kRcodeNXDOMAIN
);
718 // Responses for third transaction.
719 AddAsyncQueryAndRcode("x", dns_protocol::kTypeAAAA
,
720 dns_protocol::kRcodeNXDOMAIN
);
722 TransactionHelper
helper0("x.y", dns_protocol::kTypeA
, ERR_NAME_NOT_RESOLVED
);
724 EXPECT_TRUE(helper0
.Run(transaction_factory_
.get()));
726 // A single-label name.
727 TransactionHelper
helper1("x", dns_protocol::kTypeA
, ERR_NAME_NOT_RESOLVED
);
729 EXPECT_TRUE(helper1
.Run(transaction_factory_
.get()));
731 // A fully-qualified name.
732 TransactionHelper
helper2("x.", dns_protocol::kTypeAAAA
,
733 ERR_NAME_NOT_RESOLVED
);
735 EXPECT_TRUE(helper2
.Run(transaction_factory_
.get()));
738 TEST_F(DnsTransactionTest
, EmptySuffixSearch
) {
739 // Responses for first transaction.
740 AddAsyncQueryAndRcode("x", dns_protocol::kTypeA
,
741 dns_protocol::kRcodeNXDOMAIN
);
743 // A fully-qualified name.
744 TransactionHelper
helper0("x.", dns_protocol::kTypeA
, ERR_NAME_NOT_RESOLVED
);
746 EXPECT_TRUE(helper0
.Run(transaction_factory_
.get()));
748 // A single label name is not even attempted.
749 TransactionHelper
helper1("singlelabel", dns_protocol::kTypeA
,
750 ERR_DNS_SEARCH_EMPTY
);
752 helper1
.Run(transaction_factory_
.get());
753 EXPECT_TRUE(helper1
.has_completed());
756 TEST_F(DnsTransactionTest
, DontAppendToMultiLabelName
) {
757 config_
.search
.push_back("a");
758 config_
.search
.push_back("b");
759 config_
.search
.push_back("c");
760 config_
.append_to_multi_label_name
= false;
763 // Responses for first transaction.
764 AddAsyncQueryAndRcode("x.y.z", dns_protocol::kTypeA
,
765 dns_protocol::kRcodeNXDOMAIN
);
766 // Responses for second transaction.
767 AddAsyncQueryAndRcode("x.y", dns_protocol::kTypeA
,
768 dns_protocol::kRcodeNXDOMAIN
);
769 // Responses for third transaction.
770 AddAsyncQueryAndRcode("x.a", dns_protocol::kTypeA
,
771 dns_protocol::kRcodeNXDOMAIN
);
772 AddAsyncQueryAndRcode("x.b", dns_protocol::kTypeA
,
773 dns_protocol::kRcodeNXDOMAIN
);
774 AddAsyncQueryAndRcode("x.c", dns_protocol::kTypeA
,
775 dns_protocol::kRcodeNXDOMAIN
);
777 TransactionHelper
helper0("x.y.z", dns_protocol::kTypeA
,
778 ERR_NAME_NOT_RESOLVED
);
779 EXPECT_TRUE(helper0
.Run(transaction_factory_
.get()));
781 TransactionHelper
helper1("x.y", dns_protocol::kTypeA
, ERR_NAME_NOT_RESOLVED
);
782 EXPECT_TRUE(helper1
.Run(transaction_factory_
.get()));
784 TransactionHelper
helper2("x", dns_protocol::kTypeA
, ERR_NAME_NOT_RESOLVED
);
785 EXPECT_TRUE(helper2
.Run(transaction_factory_
.get()));
788 const uint8 kResponseNoData
[] = {
789 0x00, 0x00, 0x81, 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
791 0x01, 'x', 0x01, 'y', 0x01, 'z', 0x01, 'b', 0x00, 0x00, 0x01, 0x00, 0x01,
792 // Authority section, SOA record, TTL 0x3E6
793 0x01, 'z', 0x00, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x03, 0xE6,
794 // Minimal RDATA, 18 bytes
797 0x00, 0x00, 0x00, 0x00,
798 0x00, 0x00, 0x00, 0x00,
799 0x00, 0x00, 0x00, 0x00,
800 0x00, 0x00, 0x00, 0x00,
803 TEST_F(DnsTransactionTest
, SuffixSearchStop
) {
805 config_
.search
.push_back("a");
806 config_
.search
.push_back("b");
807 config_
.search
.push_back("c");
810 AddAsyncQueryAndRcode("x.y.z", dns_protocol::kTypeA
,
811 dns_protocol::kRcodeNXDOMAIN
);
812 AddAsyncQueryAndRcode("x.y.z.a", dns_protocol::kTypeA
,
813 dns_protocol::kRcodeNXDOMAIN
);
814 AddAsyncQueryAndResponse(0 /* id */, "x.y.z.b", dns_protocol::kTypeA
,
815 kResponseNoData
, arraysize(kResponseNoData
));
817 TransactionHelper
helper0("x.y.z", dns_protocol::kTypeA
, 0 /* answers */);
819 EXPECT_TRUE(helper0
.Run(transaction_factory_
.get()));
822 TEST_F(DnsTransactionTest
, SyncFirstQuery
) {
823 config_
.search
.push_back("lab.ccs.neu.edu");
824 config_
.search
.push_back("ccs.neu.edu");
827 AddSyncQueryAndResponse(0 /* id */, kT0HostName
, kT0Qtype
,
828 kT0ResponseDatagram
, arraysize(kT0ResponseDatagram
));
830 TransactionHelper
helper0(kT0HostName
, kT0Qtype
, kT0RecordCount
);
831 EXPECT_TRUE(helper0
.Run(transaction_factory_
.get()));
834 TEST_F(DnsTransactionTest
, SyncFirstQueryWithSearch
) {
835 config_
.search
.push_back("lab.ccs.neu.edu");
836 config_
.search
.push_back("ccs.neu.edu");
839 AddSyncQueryAndRcode("www.lab.ccs.neu.edu", kT2Qtype
,
840 dns_protocol::kRcodeNXDOMAIN
);
842 AddAsyncQueryAndResponse(2 /* id */, kT2HostName
, kT2Qtype
,
843 kT2ResponseDatagram
, arraysize(kT2ResponseDatagram
));
845 TransactionHelper
helper0("www", kT2Qtype
, kT2RecordCount
);
846 EXPECT_TRUE(helper0
.Run(transaction_factory_
.get()));
849 TEST_F(DnsTransactionTest
, SyncSearchQuery
) {
850 config_
.search
.push_back("lab.ccs.neu.edu");
851 config_
.search
.push_back("ccs.neu.edu");
854 AddAsyncQueryAndRcode("www.lab.ccs.neu.edu", dns_protocol::kTypeA
,
855 dns_protocol::kRcodeNXDOMAIN
);
856 AddSyncQueryAndResponse(2 /* id */, kT2HostName
, kT2Qtype
,
857 kT2ResponseDatagram
, arraysize(kT2ResponseDatagram
));
859 TransactionHelper
helper0("www", kT2Qtype
, kT2RecordCount
);
860 EXPECT_TRUE(helper0
.Run(transaction_factory_
.get()));
863 TEST_F(DnsTransactionTest
, ConnectFailure
) {
864 socket_factory_
->fail_next_socket_
= true;
865 transaction_ids_
.push_back(0); // Needed to make a DnsUDPAttempt.
866 TransactionHelper
helper0("www.chromium.org", dns_protocol::kTypeA
,
867 ERR_CONNECTION_REFUSED
);
868 EXPECT_TRUE(helper0
.Run(transaction_factory_
.get()));
871 TEST_F(DnsTransactionTest
, ConnectFailureFollowedBySuccess
) {
872 // Retry after server failure.
873 config_
.attempts
= 2;
875 // First server connection attempt fails.
876 transaction_ids_
.push_back(0); // Needed to make a DnsUDPAttempt.
877 socket_factory_
->fail_next_socket_
= true;
878 // Second DNS query succeeds.
879 AddAsyncQueryAndResponse(0 /* id */, kT0HostName
, kT0Qtype
,
880 kT0ResponseDatagram
, arraysize(kT0ResponseDatagram
));
881 TransactionHelper
helper0(kT0HostName
, kT0Qtype
, kT0RecordCount
);
882 EXPECT_TRUE(helper0
.Run(transaction_factory_
.get()));
885 TEST_F(DnsTransactionTest
, TCPLookup
) {
886 AddAsyncQueryAndRcode(kT0HostName
, kT0Qtype
,
887 dns_protocol::kRcodeNOERROR
| dns_protocol::kFlagTC
);
888 AddQueryAndResponse(0 /* id */, kT0HostName
, kT0Qtype
,
889 kT0ResponseDatagram
, arraysize(kT0ResponseDatagram
),
890 ASYNC
, true /* use_tcp */);
892 TransactionHelper
helper0(kT0HostName
, kT0Qtype
, kT0RecordCount
);
893 EXPECT_TRUE(helper0
.Run(transaction_factory_
.get()));
896 TEST_F(DnsTransactionTest
, TCPFailure
) {
897 AddAsyncQueryAndRcode(kT0HostName
, kT0Qtype
,
898 dns_protocol::kRcodeNOERROR
| dns_protocol::kFlagTC
);
899 AddQueryAndRcode(kT0HostName
, kT0Qtype
, dns_protocol::kRcodeSERVFAIL
,
900 ASYNC
, true /* use_tcp */);
902 TransactionHelper
helper0(kT0HostName
, kT0Qtype
, ERR_DNS_SERVER_FAILED
);
903 EXPECT_TRUE(helper0
.Run(transaction_factory_
.get()));
906 TEST_F(DnsTransactionTest
, TCPMalformed
) {
907 AddAsyncQueryAndRcode(kT0HostName
, kT0Qtype
,
908 dns_protocol::kRcodeNOERROR
| dns_protocol::kFlagTC
);
909 scoped_ptr
<DnsSocketData
> data(
910 new DnsSocketData(0 /* id */, kT0HostName
, kT0Qtype
, ASYNC
, true));
911 // Valid response but length too short.
912 // This must be truncated in the question section. The DnsResponse doesn't
913 // examine the answer section until asked to parse it, so truncating it in
914 // the answer section would result in the DnsTransaction itself succeeding.
915 data
->AddResponseWithLength(
917 new DnsResponse(reinterpret_cast<const char*>(kT0ResponseDatagram
),
918 arraysize(kT0ResponseDatagram
), 0)),
920 static_cast<uint16
>(kT0QuerySize
- 1));
921 AddSocketData(data
.Pass());
923 TransactionHelper
helper0(kT0HostName
, kT0Qtype
, ERR_DNS_MALFORMED_RESPONSE
);
924 EXPECT_TRUE(helper0
.Run(transaction_factory_
.get()));
927 TEST_F(DnsTransactionTest
, TCPTimeout
) {
928 config_
.timeout
= TestTimeouts::tiny_timeout();
930 AddAsyncQueryAndRcode(kT0HostName
, kT0Qtype
,
931 dns_protocol::kRcodeNOERROR
| dns_protocol::kFlagTC
);
932 AddSocketData(make_scoped_ptr(
933 new DnsSocketData(1 /* id */, kT0HostName
, kT0Qtype
, ASYNC
, true)));
935 TransactionHelper
helper0(kT0HostName
, kT0Qtype
, ERR_DNS_TIMED_OUT
);
936 EXPECT_TRUE(helper0
.RunUntilDone(transaction_factory_
.get()));
939 TEST_F(DnsTransactionTest
, TCPReadReturnsZeroAsync
) {
940 AddAsyncQueryAndRcode(kT0HostName
, kT0Qtype
,
941 dns_protocol::kRcodeNOERROR
| dns_protocol::kFlagTC
);
942 scoped_ptr
<DnsSocketData
> data(
943 new DnsSocketData(0 /* id */, kT0HostName
, kT0Qtype
, ASYNC
, true));
944 // Return all but the last byte of the response.
945 data
->AddResponseWithLength(
947 new DnsResponse(reinterpret_cast<const char*>(kT0ResponseDatagram
),
948 arraysize(kT0ResponseDatagram
) - 1, 0)),
950 static_cast<uint16
>(arraysize(kT0ResponseDatagram
)));
951 // Then return a 0-length read.
952 data
->AddReadError(0, ASYNC
);
953 AddSocketData(data
.Pass());
955 TransactionHelper
helper0(kT0HostName
, kT0Qtype
, ERR_CONNECTION_CLOSED
);
956 EXPECT_TRUE(helper0
.Run(transaction_factory_
.get()));
959 TEST_F(DnsTransactionTest
, TCPReadReturnsZeroSynchronous
) {
960 AddAsyncQueryAndRcode(kT0HostName
, kT0Qtype
,
961 dns_protocol::kRcodeNOERROR
| dns_protocol::kFlagTC
);
962 scoped_ptr
<DnsSocketData
> data(
963 new DnsSocketData(0 /* id */, kT0HostName
, kT0Qtype
, ASYNC
, true));
964 // Return all but the last byte of the response.
965 data
->AddResponseWithLength(
967 new DnsResponse(reinterpret_cast<const char*>(kT0ResponseDatagram
),
968 arraysize(kT0ResponseDatagram
) - 1, 0)),
970 static_cast<uint16
>(arraysize(kT0ResponseDatagram
)));
971 // Then return a 0-length read.
972 data
->AddReadError(0, SYNCHRONOUS
);
973 AddSocketData(data
.Pass());
975 TransactionHelper
helper0(kT0HostName
, kT0Qtype
, ERR_CONNECTION_CLOSED
);
976 EXPECT_TRUE(helper0
.Run(transaction_factory_
.get()));
979 TEST_F(DnsTransactionTest
, TCPConnectionClosedAsync
) {
980 AddAsyncQueryAndRcode(kT0HostName
, kT0Qtype
,
981 dns_protocol::kRcodeNOERROR
| dns_protocol::kFlagTC
);
982 scoped_ptr
<DnsSocketData
> data(
983 new DnsSocketData(0 /* id */, kT0HostName
, kT0Qtype
, ASYNC
, true));
984 data
->AddReadError(ERR_CONNECTION_CLOSED
, ASYNC
);
985 AddSocketData(data
.Pass());
987 TransactionHelper
helper0(kT0HostName
, kT0Qtype
, ERR_CONNECTION_CLOSED
);
988 EXPECT_TRUE(helper0
.Run(transaction_factory_
.get()));
991 TEST_F(DnsTransactionTest
, TCPConnectionClosedSynchronous
) {
992 AddAsyncQueryAndRcode(kT0HostName
, kT0Qtype
,
993 dns_protocol::kRcodeNOERROR
| dns_protocol::kFlagTC
);
994 scoped_ptr
<DnsSocketData
> data(
995 new DnsSocketData(0 /* id */, kT0HostName
, kT0Qtype
, ASYNC
, true));
996 data
->AddReadError(ERR_CONNECTION_CLOSED
, SYNCHRONOUS
);
997 AddSocketData(data
.Pass());
999 TransactionHelper
helper0(kT0HostName
, kT0Qtype
, ERR_CONNECTION_CLOSED
);
1000 EXPECT_TRUE(helper0
.Run(transaction_factory_
.get()));
1003 TEST_F(DnsTransactionTest
, InvalidQuery
) {
1004 config_
.timeout
= TestTimeouts::tiny_timeout();
1007 TransactionHelper
helper0(".", dns_protocol::kTypeA
, ERR_INVALID_ARGUMENT
);
1008 EXPECT_TRUE(helper0
.Run(transaction_factory_
.get()));