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/base/net_log.h"
15 #include "net/dns/dns_protocol.h"
16 #include "net/dns/dns_query.h"
17 #include "net/dns/dns_response.h"
18 #include "net/dns/dns_session.h"
19 #include "net/dns/dns_test_util.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()),
50 lengths_
.push_back(length
.release());
52 writes_
.push_back(MockWrite(mode
,
53 query_
->io_buffer()->data(),
54 query_
->io_buffer()->size()));
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()),
70 lengths_
.push_back(length
.release());
72 reads_
.push_back(MockRead(mode
,
73 response
->io_buffer()->data(),
74 response
->io_buffer()->size()));
75 responses_
.push_back(response
.release());
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
));
108 // Build, if needed, and return the SocketDataProvider. No new responses
109 // should be added afterwards.
110 SocketDataProvider
* GetProvider() {
112 return provider_
.get();
113 // Terminate the reads with ERR_IO_PENDING to prevent overrun and default to
115 reads_
.push_back(MockRead(ASYNC
, ERR_IO_PENDING
));
116 provider_
.reset(new DelayedSocketData(1, &reads_
[0], reads_
.size(),
117 &writes_
[0], writes_
.size()));
119 provider_
->set_connect_data(MockConnect(reads_
[0].mode
, OK
));
121 return provider_
.get();
124 uint16
query_id() const {
128 // Returns true if the expected query was written to the socket.
129 bool was_written() const {
130 CHECK(provider_
.get());
131 return provider_
->write_index() > 0;
135 scoped_ptr
<DnsQuery
> query_
;
137 ScopedVector
<uint16
> lengths_
;
138 ScopedVector
<DnsResponse
> responses_
;
139 std::vector
<MockWrite
> writes_
;
140 std::vector
<MockRead
> reads_
;
141 scoped_ptr
<DelayedSocketData
> provider_
;
143 DISALLOW_COPY_AND_ASSIGN(DnsSocketData
);
146 class TestSocketFactory
;
148 // A variant of MockUDPClientSocket which always fails to Connect.
149 class FailingUDPClientSocket
: public MockUDPClientSocket
{
151 FailingUDPClientSocket(SocketDataProvider
* data
,
152 net::NetLog
* net_log
)
153 : MockUDPClientSocket(data
, net_log
) {
155 virtual ~FailingUDPClientSocket() {}
156 virtual int Connect(const IPEndPoint
& endpoint
) OVERRIDE
{
157 return ERR_CONNECTION_REFUSED
;
161 DISALLOW_COPY_AND_ASSIGN(FailingUDPClientSocket
);
164 // A variant of MockUDPClientSocket which notifies the factory OnConnect.
165 class TestUDPClientSocket
: public MockUDPClientSocket
{
167 TestUDPClientSocket(TestSocketFactory
* factory
,
168 SocketDataProvider
* data
,
169 net::NetLog
* net_log
)
170 : MockUDPClientSocket(data
, net_log
), factory_(factory
) {
172 virtual ~TestUDPClientSocket() {}
173 virtual int Connect(const IPEndPoint
& endpoint
) OVERRIDE
;
176 TestSocketFactory
* factory_
;
178 DISALLOW_COPY_AND_ASSIGN(TestUDPClientSocket
);
181 // Creates TestUDPClientSockets and keeps endpoints reported via OnConnect.
182 class TestSocketFactory
: public MockClientSocketFactory
{
184 TestSocketFactory() : fail_next_socket_(false) {}
185 virtual ~TestSocketFactory() {}
187 virtual scoped_ptr
<DatagramClientSocket
> CreateDatagramClientSocket(
188 DatagramSocket::BindType bind_type
,
189 const RandIntCallback
& rand_int_cb
,
190 net::NetLog
* net_log
,
191 const net::NetLog::Source
& source
) OVERRIDE
{
192 if (fail_next_socket_
) {
193 fail_next_socket_
= false;
194 return scoped_ptr
<DatagramClientSocket
>(
195 new FailingUDPClientSocket(&empty_data_
, net_log
));
197 SocketDataProvider
* data_provider
= mock_data().GetNext();
198 scoped_ptr
<TestUDPClientSocket
> socket(
199 new TestUDPClientSocket(this, data_provider
, net_log
));
200 data_provider
->set_socket(socket
.get());
201 return socket
.PassAs
<DatagramClientSocket
>();
204 void OnConnect(const IPEndPoint
& endpoint
) {
205 remote_endpoints_
.push_back(endpoint
);
208 std::vector
<IPEndPoint
> remote_endpoints_
;
209 bool fail_next_socket_
;
212 StaticSocketDataProvider empty_data_
;
214 DISALLOW_COPY_AND_ASSIGN(TestSocketFactory
);
217 int TestUDPClientSocket::Connect(const IPEndPoint
& endpoint
) {
218 factory_
->OnConnect(endpoint
);
219 return MockUDPClientSocket::Connect(endpoint
);
222 // Helper class that holds a DnsTransaction and handles OnTransactionComplete.
223 class TransactionHelper
{
225 // If |expected_answer_count| < 0 then it is the expected net error.
226 TransactionHelper(const char* hostname
,
228 int expected_answer_count
)
229 : hostname_(hostname
),
231 expected_answer_count_(expected_answer_count
),
232 cancel_in_callback_(false),
233 quit_in_callback_(false),
237 // Mark that the transaction shall be destroyed immediately upon callback.
238 void set_cancel_in_callback() {
239 cancel_in_callback_
= true;
242 // Mark to call MessageLoop::Quit() upon callback.
243 void set_quit_in_callback() {
244 quit_in_callback_
= true;
247 void StartTransaction(DnsTransactionFactory
* factory
) {
248 EXPECT_EQ(NULL
, transaction_
.get());
249 transaction_
= factory
->CreateTransaction(
252 base::Bind(&TransactionHelper::OnTransactionComplete
,
253 base::Unretained(this)),
255 EXPECT_EQ(hostname_
, transaction_
->GetHostname());
256 EXPECT_EQ(qtype_
, transaction_
->GetType());
257 transaction_
->Start();
261 ASSERT_TRUE(transaction_
.get() != NULL
);
262 transaction_
.reset(NULL
);
265 void OnTransactionComplete(DnsTransaction
* t
,
267 const DnsResponse
* response
) {
268 EXPECT_FALSE(completed_
);
269 EXPECT_EQ(transaction_
.get(), t
);
273 if (cancel_in_callback_
) {
278 // Tell MessageLoop to quit now, in case any ASSERT_* fails.
279 if (quit_in_callback_
)
280 base::MessageLoop::current()->Quit();
282 if (expected_answer_count_
>= 0) {
284 ASSERT_TRUE(response
!= NULL
);
285 EXPECT_EQ(static_cast<unsigned>(expected_answer_count_
),
286 response
->answer_count());
287 EXPECT_EQ(qtype_
, response
->qtype());
289 DnsRecordParser parser
= response
->Parser();
290 DnsResourceRecord record
;
291 for (int i
= 0; i
< expected_answer_count_
; ++i
) {
292 EXPECT_TRUE(parser
.ReadRecord(&record
));
295 EXPECT_EQ(expected_answer_count_
, rv
);
299 bool has_completed() const {
303 // Shorthands for commonly used commands.
305 bool Run(DnsTransactionFactory
* factory
) {
306 StartTransaction(factory
);
307 base::MessageLoop::current()->RunUntilIdle();
308 return has_completed();
311 // Use when some of the responses are timeouts.
312 bool RunUntilDone(DnsTransactionFactory
* factory
) {
313 set_quit_in_callback();
314 StartTransaction(factory
);
315 base::MessageLoop::current()->Run();
316 return has_completed();
320 std::string hostname_
;
322 scoped_ptr
<DnsTransaction
> transaction_
;
323 int expected_answer_count_
;
324 bool cancel_in_callback_
;
325 bool quit_in_callback_
;
330 class DnsTransactionTest
: public testing::Test
{
332 DnsTransactionTest() {}
334 // Generates |nameservers| for DnsConfig.
335 void ConfigureNumServers(unsigned num_servers
) {
336 CHECK_LE(num_servers
, 255u);
337 config_
.nameservers
.clear();
338 IPAddressNumber dns_ip
;
340 bool rv
= ParseIPLiteralToNumber("192.168.1.0", &dns_ip
);
343 for (unsigned i
= 0; i
< num_servers
; ++i
) {
345 config_
.nameservers
.push_back(IPEndPoint(dns_ip
,
346 dns_protocol::kDefaultPort
));
350 // Called after fully configuring |config|.
351 void ConfigureFactory() {
352 socket_factory_
.reset(new TestSocketFactory());
353 session_
= new DnsSession(
355 DnsSocketPool::CreateNull(socket_factory_
.get()),
356 base::Bind(&DnsTransactionTest::GetNextId
, base::Unretained(this)),
358 transaction_factory_
= DnsTransactionFactory::CreateFactory(session_
.get());
361 void AddSocketData(scoped_ptr
<DnsSocketData
> data
) {
362 CHECK(socket_factory_
.get());
363 transaction_ids_
.push_back(data
->query_id());
364 socket_factory_
->AddSocketDataProvider(data
->GetProvider());
365 socket_data_
.push_back(data
.release());
368 // Add expected query for |dotted_name| and |qtype| with |id| and response
369 // taken verbatim from |data| of |data_length| bytes. The transaction id in
370 // |data| should equal |id|, unless testing mismatched response.
371 void AddQueryAndResponse(uint16 id
,
372 const char* dotted_name
,
374 const uint8
* response_data
,
375 size_t response_length
,
378 CHECK(socket_factory_
.get());
379 scoped_ptr
<DnsSocketData
> data(
380 new DnsSocketData(id
, dotted_name
, qtype
, mode
, use_tcp
));
381 data
->AddResponseData(response_data
, response_length
, mode
);
382 AddSocketData(data
.Pass());
385 void AddAsyncQueryAndResponse(uint16 id
,
386 const char* dotted_name
,
389 size_t data_length
) {
390 AddQueryAndResponse(id
, dotted_name
, qtype
, data
, data_length
, ASYNC
,
394 void AddSyncQueryAndResponse(uint16 id
,
395 const char* dotted_name
,
398 size_t data_length
) {
399 AddQueryAndResponse(id
, dotted_name
, qtype
, data
, data_length
, SYNCHRONOUS
,
403 // Add expected query of |dotted_name| and |qtype| and no response.
404 void AddQueryAndTimeout(const char* dotted_name
, uint16 qtype
) {
405 uint16 id
= base::RandInt(0, kuint16max
);
406 scoped_ptr
<DnsSocketData
> data(
407 new DnsSocketData(id
, dotted_name
, qtype
, ASYNC
, false));
408 AddSocketData(data
.Pass());
411 // Add expected query of |dotted_name| and |qtype| and matching response with
412 // no answer and RCODE set to |rcode|. The id will be generated randomly.
413 void AddQueryAndRcode(const char* dotted_name
,
418 CHECK_NE(dns_protocol::kRcodeNOERROR
, rcode
);
419 uint16 id
= base::RandInt(0, kuint16max
);
420 scoped_ptr
<DnsSocketData
> data(
421 new DnsSocketData(id
, dotted_name
, qtype
, mode
, use_tcp
));
422 data
->AddRcode(rcode
, mode
);
423 AddSocketData(data
.Pass());
426 void AddAsyncQueryAndRcode(const char* dotted_name
, uint16 qtype
, int rcode
) {
427 AddQueryAndRcode(dotted_name
, qtype
, rcode
, ASYNC
, false);
430 void AddSyncQueryAndRcode(const char* dotted_name
, uint16 qtype
, int rcode
) {
431 AddQueryAndRcode(dotted_name
, qtype
, rcode
, SYNCHRONOUS
, false);
434 // Checks if the sockets were connected in the order matching the indices in
436 void CheckServerOrder(const unsigned* servers
, size_t num_attempts
) {
437 ASSERT_EQ(num_attempts
, socket_factory_
->remote_endpoints_
.size());
438 for (size_t i
= 0; i
< num_attempts
; ++i
) {
439 EXPECT_EQ(socket_factory_
->remote_endpoints_
[i
],
440 session_
->config().nameservers
[servers
[i
]]);
444 virtual void SetUp() OVERRIDE
{
445 // By default set one server,
446 ConfigureNumServers(1);
447 // and no retransmissions,
448 config_
.attempts
= 1;
449 // but long enough timeout for memory tests.
450 config_
.timeout
= TestTimeouts::action_timeout();
454 virtual void TearDown() OVERRIDE
{
455 // Check that all socket data was at least written to.
456 for (size_t i
= 0; i
< socket_data_
.size(); ++i
) {
457 EXPECT_TRUE(socket_data_
[i
]->was_written()) << i
;
462 int GetNextId(int min
, int max
) {
463 EXPECT_FALSE(transaction_ids_
.empty());
464 int id
= transaction_ids_
.front();
465 transaction_ids_
.pop_front();
473 ScopedVector
<DnsSocketData
> socket_data_
;
475 std::deque
<int> transaction_ids_
;
476 scoped_ptr
<TestSocketFactory
> socket_factory_
;
477 scoped_refptr
<DnsSession
> session_
;
478 scoped_ptr
<DnsTransactionFactory
> transaction_factory_
;
481 TEST_F(DnsTransactionTest
, Lookup
) {
482 AddAsyncQueryAndResponse(0 /* id */, kT0HostName
, kT0Qtype
,
483 kT0ResponseDatagram
, arraysize(kT0ResponseDatagram
));
485 TransactionHelper
helper0(kT0HostName
, kT0Qtype
, kT0RecordCount
);
486 EXPECT_TRUE(helper0
.Run(transaction_factory_
.get()));
489 // Concurrent lookup tests assume that DnsTransaction::Start immediately
490 // consumes a socket from ClientSocketFactory.
491 TEST_F(DnsTransactionTest
, ConcurrentLookup
) {
492 AddAsyncQueryAndResponse(0 /* id */, kT0HostName
, kT0Qtype
,
493 kT0ResponseDatagram
, arraysize(kT0ResponseDatagram
));
494 AddAsyncQueryAndResponse(1 /* id */, kT1HostName
, kT1Qtype
,
495 kT1ResponseDatagram
, arraysize(kT1ResponseDatagram
));
497 TransactionHelper
helper0(kT0HostName
, kT0Qtype
, kT0RecordCount
);
498 helper0
.StartTransaction(transaction_factory_
.get());
499 TransactionHelper
helper1(kT1HostName
, kT1Qtype
, kT1RecordCount
);
500 helper1
.StartTransaction(transaction_factory_
.get());
502 base::MessageLoop::current()->RunUntilIdle();
504 EXPECT_TRUE(helper0
.has_completed());
505 EXPECT_TRUE(helper1
.has_completed());
508 TEST_F(DnsTransactionTest
, CancelLookup
) {
509 AddAsyncQueryAndResponse(0 /* id */, kT0HostName
, kT0Qtype
,
510 kT0ResponseDatagram
, arraysize(kT0ResponseDatagram
));
511 AddAsyncQueryAndResponse(1 /* id */, kT1HostName
, kT1Qtype
,
512 kT1ResponseDatagram
, arraysize(kT1ResponseDatagram
));
514 TransactionHelper
helper0(kT0HostName
, kT0Qtype
, kT0RecordCount
);
515 helper0
.StartTransaction(transaction_factory_
.get());
516 TransactionHelper
helper1(kT1HostName
, kT1Qtype
, kT1RecordCount
);
517 helper1
.StartTransaction(transaction_factory_
.get());
521 base::MessageLoop::current()->RunUntilIdle();
523 EXPECT_FALSE(helper0
.has_completed());
524 EXPECT_TRUE(helper1
.has_completed());
527 TEST_F(DnsTransactionTest
, DestroyFactory
) {
528 AddAsyncQueryAndResponse(0 /* id */, kT0HostName
, kT0Qtype
,
529 kT0ResponseDatagram
, arraysize(kT0ResponseDatagram
));
531 TransactionHelper
helper0(kT0HostName
, kT0Qtype
, kT0RecordCount
);
532 helper0
.StartTransaction(transaction_factory_
.get());
534 // Destroying the client does not affect running requests.
535 transaction_factory_
.reset(NULL
);
537 base::MessageLoop::current()->RunUntilIdle();
539 EXPECT_TRUE(helper0
.has_completed());
542 TEST_F(DnsTransactionTest
, CancelFromCallback
) {
543 AddAsyncQueryAndResponse(0 /* id */, kT0HostName
, kT0Qtype
,
544 kT0ResponseDatagram
, arraysize(kT0ResponseDatagram
));
546 TransactionHelper
helper0(kT0HostName
, kT0Qtype
, kT0RecordCount
);
547 helper0
.set_cancel_in_callback();
548 EXPECT_TRUE(helper0
.Run(transaction_factory_
.get()));
551 TEST_F(DnsTransactionTest
, MismatchedResponseSync
) {
552 config_
.attempts
= 2;
553 config_
.timeout
= TestTimeouts::tiny_timeout();
556 // Attempt receives mismatched response followed by valid response.
557 scoped_ptr
<DnsSocketData
> data(
558 new DnsSocketData(0 /* id */, kT0HostName
, kT0Qtype
, SYNCHRONOUS
, false));
559 data
->AddResponseData(kT1ResponseDatagram
,
560 arraysize(kT1ResponseDatagram
), SYNCHRONOUS
);
561 data
->AddResponseData(kT0ResponseDatagram
,
562 arraysize(kT0ResponseDatagram
), SYNCHRONOUS
);
563 AddSocketData(data
.Pass());
565 TransactionHelper
helper0(kT0HostName
, kT0Qtype
, kT0RecordCount
);
566 EXPECT_TRUE(helper0
.RunUntilDone(transaction_factory_
.get()));
569 TEST_F(DnsTransactionTest
, MismatchedResponseAsync
) {
570 config_
.attempts
= 2;
571 config_
.timeout
= TestTimeouts::tiny_timeout();
574 // First attempt receives mismatched response followed by valid response.
575 // Second attempt times out.
576 scoped_ptr
<DnsSocketData
> data(
577 new DnsSocketData(0 /* id */, kT0HostName
, kT0Qtype
, ASYNC
, false));
578 data
->AddResponseData(kT1ResponseDatagram
,
579 arraysize(kT1ResponseDatagram
), ASYNC
);
580 data
->AddResponseData(kT0ResponseDatagram
,
581 arraysize(kT0ResponseDatagram
), ASYNC
);
582 AddSocketData(data
.Pass());
583 AddQueryAndTimeout(kT0HostName
, kT0Qtype
);
585 TransactionHelper
helper0(kT0HostName
, kT0Qtype
, kT0RecordCount
);
586 EXPECT_TRUE(helper0
.RunUntilDone(transaction_factory_
.get()));
589 TEST_F(DnsTransactionTest
, MismatchedResponseFail
) {
590 config_
.timeout
= TestTimeouts::tiny_timeout();
593 // Attempt receives mismatched response but times out because only one attempt
595 AddAsyncQueryAndResponse(1 /* id */, kT0HostName
, kT0Qtype
,
596 kT0ResponseDatagram
, arraysize(kT0ResponseDatagram
));
598 TransactionHelper
helper0(kT0HostName
, kT0Qtype
, ERR_DNS_TIMED_OUT
);
599 EXPECT_TRUE(helper0
.RunUntilDone(transaction_factory_
.get()));
602 TEST_F(DnsTransactionTest
, ServerFail
) {
603 AddAsyncQueryAndRcode(kT0HostName
, kT0Qtype
, dns_protocol::kRcodeSERVFAIL
);
605 TransactionHelper
helper0(kT0HostName
, kT0Qtype
, ERR_DNS_SERVER_FAILED
);
606 EXPECT_TRUE(helper0
.Run(transaction_factory_
.get()));
609 TEST_F(DnsTransactionTest
, NoDomain
) {
610 AddAsyncQueryAndRcode(kT0HostName
, kT0Qtype
, dns_protocol::kRcodeNXDOMAIN
);
612 TransactionHelper
helper0(kT0HostName
, kT0Qtype
, ERR_NAME_NOT_RESOLVED
);
613 EXPECT_TRUE(helper0
.Run(transaction_factory_
.get()));
616 TEST_F(DnsTransactionTest
, Timeout
) {
617 config_
.attempts
= 3;
618 // Use short timeout to speed up the test.
619 config_
.timeout
= TestTimeouts::tiny_timeout();
622 AddQueryAndTimeout(kT0HostName
, kT0Qtype
);
623 AddQueryAndTimeout(kT0HostName
, kT0Qtype
);
624 AddQueryAndTimeout(kT0HostName
, kT0Qtype
);
626 TransactionHelper
helper0(kT0HostName
, kT0Qtype
, ERR_DNS_TIMED_OUT
);
627 EXPECT_TRUE(helper0
.RunUntilDone(transaction_factory_
.get()));
628 EXPECT_TRUE(base::MessageLoop::current()->IsIdleForTesting());
631 TEST_F(DnsTransactionTest
, ServerFallbackAndRotate
) {
632 // Test that we fallback on both server failure and timeout.
633 config_
.attempts
= 2;
634 // The next request should start from the next server.
635 config_
.rotate
= true;
636 ConfigureNumServers(3);
637 // Use short timeout to speed up the test.
638 config_
.timeout
= TestTimeouts::tiny_timeout();
641 // Responses for first request.
642 AddQueryAndTimeout(kT0HostName
, kT0Qtype
);
643 AddAsyncQueryAndRcode(kT0HostName
, kT0Qtype
, dns_protocol::kRcodeSERVFAIL
);
644 AddQueryAndTimeout(kT0HostName
, kT0Qtype
);
645 AddAsyncQueryAndRcode(kT0HostName
, kT0Qtype
, dns_protocol::kRcodeSERVFAIL
);
646 AddAsyncQueryAndRcode(kT0HostName
, kT0Qtype
, dns_protocol::kRcodeNXDOMAIN
);
647 // Responses for second request.
648 AddAsyncQueryAndRcode(kT1HostName
, kT1Qtype
, dns_protocol::kRcodeSERVFAIL
);
649 AddAsyncQueryAndRcode(kT1HostName
, kT1Qtype
, dns_protocol::kRcodeSERVFAIL
);
650 AddAsyncQueryAndRcode(kT1HostName
, kT1Qtype
, dns_protocol::kRcodeNXDOMAIN
);
652 TransactionHelper
helper0(kT0HostName
, kT0Qtype
, ERR_NAME_NOT_RESOLVED
);
653 TransactionHelper
helper1(kT1HostName
, kT1Qtype
, ERR_NAME_NOT_RESOLVED
);
655 EXPECT_TRUE(helper0
.RunUntilDone(transaction_factory_
.get()));
656 EXPECT_TRUE(helper1
.Run(transaction_factory_
.get()));
658 unsigned kOrder
[] = {
659 0, 1, 2, 0, 1, // The first transaction.
660 1, 2, 0, // The second transaction starts from the next server.
662 CheckServerOrder(kOrder
, arraysize(kOrder
));
665 TEST_F(DnsTransactionTest
, SuffixSearchAboveNdots
) {
667 config_
.search
.push_back("a");
668 config_
.search
.push_back("b");
669 config_
.search
.push_back("c");
670 config_
.rotate
= true;
671 ConfigureNumServers(2);
674 AddAsyncQueryAndRcode("x.y.z", dns_protocol::kTypeA
,
675 dns_protocol::kRcodeNXDOMAIN
);
676 AddAsyncQueryAndRcode("x.y.z.a", dns_protocol::kTypeA
,
677 dns_protocol::kRcodeNXDOMAIN
);
678 AddAsyncQueryAndRcode("x.y.z.b", dns_protocol::kTypeA
,
679 dns_protocol::kRcodeNXDOMAIN
);
680 AddAsyncQueryAndRcode("x.y.z.c", dns_protocol::kTypeA
,
681 dns_protocol::kRcodeNXDOMAIN
);
683 TransactionHelper
helper0("x.y.z", dns_protocol::kTypeA
,
684 ERR_NAME_NOT_RESOLVED
);
686 EXPECT_TRUE(helper0
.Run(transaction_factory_
.get()));
688 // Also check if suffix search causes server rotation.
689 unsigned kOrder0
[] = { 0, 1, 0, 1 };
690 CheckServerOrder(kOrder0
, arraysize(kOrder0
));
693 TEST_F(DnsTransactionTest
, SuffixSearchBelowNdots
) {
695 config_
.search
.push_back("a");
696 config_
.search
.push_back("b");
697 config_
.search
.push_back("c");
700 // Responses for first transaction.
701 AddAsyncQueryAndRcode("x.y.a", dns_protocol::kTypeA
,
702 dns_protocol::kRcodeNXDOMAIN
);
703 AddAsyncQueryAndRcode("x.y.b", dns_protocol::kTypeA
,
704 dns_protocol::kRcodeNXDOMAIN
);
705 AddAsyncQueryAndRcode("x.y.c", dns_protocol::kTypeA
,
706 dns_protocol::kRcodeNXDOMAIN
);
707 AddAsyncQueryAndRcode("x.y", dns_protocol::kTypeA
,
708 dns_protocol::kRcodeNXDOMAIN
);
709 // Responses for second transaction.
710 AddAsyncQueryAndRcode("x.a", dns_protocol::kTypeA
,
711 dns_protocol::kRcodeNXDOMAIN
);
712 AddAsyncQueryAndRcode("x.b", dns_protocol::kTypeA
,
713 dns_protocol::kRcodeNXDOMAIN
);
714 AddAsyncQueryAndRcode("x.c", dns_protocol::kTypeA
,
715 dns_protocol::kRcodeNXDOMAIN
);
716 // Responses for third transaction.
717 AddAsyncQueryAndRcode("x", dns_protocol::kTypeAAAA
,
718 dns_protocol::kRcodeNXDOMAIN
);
720 TransactionHelper
helper0("x.y", dns_protocol::kTypeA
, ERR_NAME_NOT_RESOLVED
);
722 EXPECT_TRUE(helper0
.Run(transaction_factory_
.get()));
724 // A single-label name.
725 TransactionHelper
helper1("x", dns_protocol::kTypeA
, ERR_NAME_NOT_RESOLVED
);
727 EXPECT_TRUE(helper1
.Run(transaction_factory_
.get()));
729 // A fully-qualified name.
730 TransactionHelper
helper2("x.", dns_protocol::kTypeAAAA
,
731 ERR_NAME_NOT_RESOLVED
);
733 EXPECT_TRUE(helper2
.Run(transaction_factory_
.get()));
736 TEST_F(DnsTransactionTest
, EmptySuffixSearch
) {
737 // Responses for first transaction.
738 AddAsyncQueryAndRcode("x", dns_protocol::kTypeA
,
739 dns_protocol::kRcodeNXDOMAIN
);
741 // A fully-qualified name.
742 TransactionHelper
helper0("x.", dns_protocol::kTypeA
, ERR_NAME_NOT_RESOLVED
);
744 EXPECT_TRUE(helper0
.Run(transaction_factory_
.get()));
746 // A single label name is not even attempted.
747 TransactionHelper
helper1("singlelabel", dns_protocol::kTypeA
,
748 ERR_DNS_SEARCH_EMPTY
);
750 helper1
.Run(transaction_factory_
.get());
751 EXPECT_TRUE(helper1
.has_completed());
754 TEST_F(DnsTransactionTest
, DontAppendToMultiLabelName
) {
755 config_
.search
.push_back("a");
756 config_
.search
.push_back("b");
757 config_
.search
.push_back("c");
758 config_
.append_to_multi_label_name
= false;
761 // Responses for first transaction.
762 AddAsyncQueryAndRcode("x.y.z", dns_protocol::kTypeA
,
763 dns_protocol::kRcodeNXDOMAIN
);
764 // Responses for second transaction.
765 AddAsyncQueryAndRcode("x.y", dns_protocol::kTypeA
,
766 dns_protocol::kRcodeNXDOMAIN
);
767 // Responses for third transaction.
768 AddAsyncQueryAndRcode("x.a", dns_protocol::kTypeA
,
769 dns_protocol::kRcodeNXDOMAIN
);
770 AddAsyncQueryAndRcode("x.b", dns_protocol::kTypeA
,
771 dns_protocol::kRcodeNXDOMAIN
);
772 AddAsyncQueryAndRcode("x.c", dns_protocol::kTypeA
,
773 dns_protocol::kRcodeNXDOMAIN
);
775 TransactionHelper
helper0("x.y.z", dns_protocol::kTypeA
,
776 ERR_NAME_NOT_RESOLVED
);
777 EXPECT_TRUE(helper0
.Run(transaction_factory_
.get()));
779 TransactionHelper
helper1("x.y", dns_protocol::kTypeA
, ERR_NAME_NOT_RESOLVED
);
780 EXPECT_TRUE(helper1
.Run(transaction_factory_
.get()));
782 TransactionHelper
helper2("x", dns_protocol::kTypeA
, ERR_NAME_NOT_RESOLVED
);
783 EXPECT_TRUE(helper2
.Run(transaction_factory_
.get()));
786 const uint8 kResponseNoData
[] = {
787 0x00, 0x00, 0x81, 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
789 0x01, 'x', 0x01, 'y', 0x01, 'z', 0x01, 'b', 0x00, 0x00, 0x01, 0x00, 0x01,
790 // Authority section, SOA record, TTL 0x3E6
791 0x01, 'z', 0x00, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x03, 0xE6,
792 // Minimal RDATA, 18 bytes
795 0x00, 0x00, 0x00, 0x00,
796 0x00, 0x00, 0x00, 0x00,
797 0x00, 0x00, 0x00, 0x00,
798 0x00, 0x00, 0x00, 0x00,
801 TEST_F(DnsTransactionTest
, SuffixSearchStop
) {
803 config_
.search
.push_back("a");
804 config_
.search
.push_back("b");
805 config_
.search
.push_back("c");
808 AddAsyncQueryAndRcode("x.y.z", dns_protocol::kTypeA
,
809 dns_protocol::kRcodeNXDOMAIN
);
810 AddAsyncQueryAndRcode("x.y.z.a", dns_protocol::kTypeA
,
811 dns_protocol::kRcodeNXDOMAIN
);
812 AddAsyncQueryAndResponse(0 /* id */, "x.y.z.b", dns_protocol::kTypeA
,
813 kResponseNoData
, arraysize(kResponseNoData
));
815 TransactionHelper
helper0("x.y.z", dns_protocol::kTypeA
, 0 /* answers */);
817 EXPECT_TRUE(helper0
.Run(transaction_factory_
.get()));
820 TEST_F(DnsTransactionTest
, SyncFirstQuery
) {
821 config_
.search
.push_back("lab.ccs.neu.edu");
822 config_
.search
.push_back("ccs.neu.edu");
825 AddSyncQueryAndResponse(0 /* id */, kT0HostName
, kT0Qtype
,
826 kT0ResponseDatagram
, arraysize(kT0ResponseDatagram
));
828 TransactionHelper
helper0(kT0HostName
, kT0Qtype
, kT0RecordCount
);
829 EXPECT_TRUE(helper0
.Run(transaction_factory_
.get()));
832 TEST_F(DnsTransactionTest
, SyncFirstQueryWithSearch
) {
833 config_
.search
.push_back("lab.ccs.neu.edu");
834 config_
.search
.push_back("ccs.neu.edu");
837 AddSyncQueryAndRcode("www.lab.ccs.neu.edu", kT2Qtype
,
838 dns_protocol::kRcodeNXDOMAIN
);
840 AddAsyncQueryAndResponse(2 /* id */, kT2HostName
, kT2Qtype
,
841 kT2ResponseDatagram
, arraysize(kT2ResponseDatagram
));
843 TransactionHelper
helper0("www", kT2Qtype
, kT2RecordCount
);
844 EXPECT_TRUE(helper0
.Run(transaction_factory_
.get()));
847 TEST_F(DnsTransactionTest
, SyncSearchQuery
) {
848 config_
.search
.push_back("lab.ccs.neu.edu");
849 config_
.search
.push_back("ccs.neu.edu");
852 AddAsyncQueryAndRcode("www.lab.ccs.neu.edu", dns_protocol::kTypeA
,
853 dns_protocol::kRcodeNXDOMAIN
);
854 AddSyncQueryAndResponse(2 /* id */, kT2HostName
, kT2Qtype
,
855 kT2ResponseDatagram
, arraysize(kT2ResponseDatagram
));
857 TransactionHelper
helper0("www", kT2Qtype
, kT2RecordCount
);
858 EXPECT_TRUE(helper0
.Run(transaction_factory_
.get()));
861 TEST_F(DnsTransactionTest
, ConnectFailure
) {
862 socket_factory_
->fail_next_socket_
= true;
863 transaction_ids_
.push_back(0); // Needed to make a DnsUDPAttempt.
864 TransactionHelper
helper0("www.chromium.org", dns_protocol::kTypeA
,
865 ERR_CONNECTION_REFUSED
);
866 EXPECT_TRUE(helper0
.Run(transaction_factory_
.get()));
869 TEST_F(DnsTransactionTest
, ConnectFailureFollowedBySuccess
) {
870 // Retry after server failure.
871 config_
.attempts
= 2;
873 // First server connection attempt fails.
874 transaction_ids_
.push_back(0); // Needed to make a DnsUDPAttempt.
875 socket_factory_
->fail_next_socket_
= true;
876 // Second DNS query succeeds.
877 AddAsyncQueryAndResponse(0 /* id */, kT0HostName
, kT0Qtype
,
878 kT0ResponseDatagram
, arraysize(kT0ResponseDatagram
));
879 TransactionHelper
helper0(kT0HostName
, kT0Qtype
, kT0RecordCount
);
880 EXPECT_TRUE(helper0
.Run(transaction_factory_
.get()));
883 TEST_F(DnsTransactionTest
, TCPLookup
) {
884 AddAsyncQueryAndRcode(kT0HostName
, kT0Qtype
,
885 dns_protocol::kRcodeNOERROR
| dns_protocol::kFlagTC
);
886 AddQueryAndResponse(0 /* id */, kT0HostName
, kT0Qtype
,
887 kT0ResponseDatagram
, arraysize(kT0ResponseDatagram
),
888 ASYNC
, true /* use_tcp */);
890 TransactionHelper
helper0(kT0HostName
, kT0Qtype
, kT0RecordCount
);
891 EXPECT_TRUE(helper0
.Run(transaction_factory_
.get()));
894 TEST_F(DnsTransactionTest
, TCPFailure
) {
895 AddAsyncQueryAndRcode(kT0HostName
, kT0Qtype
,
896 dns_protocol::kRcodeNOERROR
| dns_protocol::kFlagTC
);
897 AddQueryAndRcode(kT0HostName
, kT0Qtype
, dns_protocol::kRcodeSERVFAIL
,
898 ASYNC
, true /* use_tcp */);
900 TransactionHelper
helper0(kT0HostName
, kT0Qtype
, ERR_DNS_SERVER_FAILED
);
901 EXPECT_TRUE(helper0
.Run(transaction_factory_
.get()));
904 TEST_F(DnsTransactionTest
, TCPMalformed
) {
905 AddAsyncQueryAndRcode(kT0HostName
, kT0Qtype
,
906 dns_protocol::kRcodeNOERROR
| dns_protocol::kFlagTC
);
907 scoped_ptr
<DnsSocketData
> data(
908 new DnsSocketData(0 /* id */, kT0HostName
, kT0Qtype
, ASYNC
, true));
909 // Valid response but length too short.
910 // This must be truncated in the question section. The DnsResponse doesn't
911 // examine the answer section until asked to parse it, so truncating it in
912 // the answer section would result in the DnsTransaction itself succeeding.
913 data
->AddResponseWithLength(
915 new DnsResponse(reinterpret_cast<const char*>(kT0ResponseDatagram
),
916 arraysize(kT0ResponseDatagram
), 0)),
918 static_cast<uint16
>(kT0QuerySize
- 1));
919 AddSocketData(data
.Pass());
921 TransactionHelper
helper0(kT0HostName
, kT0Qtype
, ERR_DNS_MALFORMED_RESPONSE
);
922 EXPECT_TRUE(helper0
.Run(transaction_factory_
.get()));
925 TEST_F(DnsTransactionTest
, TCPTimeout
) {
926 config_
.timeout
= TestTimeouts::tiny_timeout();
928 AddAsyncQueryAndRcode(kT0HostName
, kT0Qtype
,
929 dns_protocol::kRcodeNOERROR
| dns_protocol::kFlagTC
);
930 AddSocketData(make_scoped_ptr(
931 new DnsSocketData(1 /* id */, kT0HostName
, kT0Qtype
, ASYNC
, true)));
933 TransactionHelper
helper0(kT0HostName
, kT0Qtype
, ERR_DNS_TIMED_OUT
);
934 EXPECT_TRUE(helper0
.RunUntilDone(transaction_factory_
.get()));
937 TEST_F(DnsTransactionTest
, TCPReadReturnsZeroAsync
) {
938 AddAsyncQueryAndRcode(kT0HostName
, kT0Qtype
,
939 dns_protocol::kRcodeNOERROR
| dns_protocol::kFlagTC
);
940 scoped_ptr
<DnsSocketData
> data(
941 new DnsSocketData(0 /* id */, kT0HostName
, kT0Qtype
, ASYNC
, true));
942 // Return all but the last byte of the response.
943 data
->AddResponseWithLength(
945 new DnsResponse(reinterpret_cast<const char*>(kT0ResponseDatagram
),
946 arraysize(kT0ResponseDatagram
) - 1, 0)),
948 static_cast<uint16
>(arraysize(kT0ResponseDatagram
)));
949 // Then return a 0-length read.
950 data
->AddReadError(0, ASYNC
);
951 AddSocketData(data
.Pass());
953 TransactionHelper
helper0(kT0HostName
, kT0Qtype
, ERR_CONNECTION_CLOSED
);
954 EXPECT_TRUE(helper0
.Run(transaction_factory_
.get()));
957 TEST_F(DnsTransactionTest
, TCPReadReturnsZeroSynchronous
) {
958 AddAsyncQueryAndRcode(kT0HostName
, kT0Qtype
,
959 dns_protocol::kRcodeNOERROR
| dns_protocol::kFlagTC
);
960 scoped_ptr
<DnsSocketData
> data(
961 new DnsSocketData(0 /* id */, kT0HostName
, kT0Qtype
, ASYNC
, true));
962 // Return all but the last byte of the response.
963 data
->AddResponseWithLength(
965 new DnsResponse(reinterpret_cast<const char*>(kT0ResponseDatagram
),
966 arraysize(kT0ResponseDatagram
) - 1, 0)),
968 static_cast<uint16
>(arraysize(kT0ResponseDatagram
)));
969 // Then return a 0-length read.
970 data
->AddReadError(0, SYNCHRONOUS
);
971 AddSocketData(data
.Pass());
973 TransactionHelper
helper0(kT0HostName
, kT0Qtype
, ERR_CONNECTION_CLOSED
);
974 EXPECT_TRUE(helper0
.Run(transaction_factory_
.get()));
977 TEST_F(DnsTransactionTest
, TCPConnectionClosedAsync
) {
978 AddAsyncQueryAndRcode(kT0HostName
, kT0Qtype
,
979 dns_protocol::kRcodeNOERROR
| dns_protocol::kFlagTC
);
980 scoped_ptr
<DnsSocketData
> data(
981 new DnsSocketData(0 /* id */, kT0HostName
, kT0Qtype
, ASYNC
, true));
982 data
->AddReadError(ERR_CONNECTION_CLOSED
, ASYNC
);
983 AddSocketData(data
.Pass());
985 TransactionHelper
helper0(kT0HostName
, kT0Qtype
, ERR_CONNECTION_CLOSED
);
986 EXPECT_TRUE(helper0
.Run(transaction_factory_
.get()));
989 TEST_F(DnsTransactionTest
, TCPConnectionClosedSynchronous
) {
990 AddAsyncQueryAndRcode(kT0HostName
, kT0Qtype
,
991 dns_protocol::kRcodeNOERROR
| dns_protocol::kFlagTC
);
992 scoped_ptr
<DnsSocketData
> data(
993 new DnsSocketData(0 /* id */, kT0HostName
, kT0Qtype
, ASYNC
, true));
994 data
->AddReadError(ERR_CONNECTION_CLOSED
, SYNCHRONOUS
);
995 AddSocketData(data
.Pass());
997 TransactionHelper
helper0(kT0HostName
, kT0Qtype
, ERR_CONNECTION_CLOSED
);
998 EXPECT_TRUE(helper0
.Run(transaction_factory_
.get()));
1001 TEST_F(DnsTransactionTest
, InvalidQuery
) {
1002 config_
.timeout
= TestTimeouts::tiny_timeout();
1005 TransactionHelper
helper0(".", dns_protocol::kTypeA
, ERR_INVALID_ARGUMENT
);
1006 EXPECT_TRUE(helper0
.Run(transaction_factory_
.get()));