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/big_endian.h"
14 #include "net/base/dns_util.h"
15 #include "net/base/net_log.h"
16 #include "net/dns/dns_protocol.h"
17 #include "net/dns/dns_query.h"
18 #include "net/dns/dns_response.h"
19 #include "net/dns/dns_session.h"
20 #include "net/dns/dns_test_util.h"
21 #include "net/socket/socket_test_util.h"
22 #include "testing/gtest/include/gtest/gtest.h"
28 std::string
DomainFromDot(const base::StringPiece
& dotted
) {
30 EXPECT_TRUE(DNSDomainFromDot(dotted
, &out
));
34 // A SocketDataProvider builder.
37 // The ctor takes parameters for the DnsQuery.
38 DnsSocketData(uint16 id
,
39 const char* dotted_name
,
43 : query_(new DnsQuery(id
, DomainFromDot(dotted_name
), qtype
)),
46 scoped_ptr
<uint16
> length(new uint16
);
47 *length
= base::HostToNet16(query_
->io_buffer()->size());
48 writes_
.push_back(MockWrite(mode
,
49 reinterpret_cast<const char*>(length
.get()),
51 lengths_
.push_back(length
.release());
53 writes_
.push_back(MockWrite(mode
,
54 query_
->io_buffer()->data(),
55 query_
->io_buffer()->size()));
59 // All responses must be added before GetProvider.
61 // Adds pre-built DnsResponse. |tcp_length| will be used in TCP mode only.
62 void AddResponseWithLength(scoped_ptr
<DnsResponse
> response
, IoMode mode
,
64 CHECK(!provider_
.get());
66 scoped_ptr
<uint16
> length(new uint16
);
67 *length
= base::HostToNet16(tcp_length
);
68 reads_
.push_back(MockRead(mode
,
69 reinterpret_cast<const char*>(length
.get()),
71 lengths_
.push_back(length
.release());
73 reads_
.push_back(MockRead(mode
,
74 response
->io_buffer()->data(),
75 response
->io_buffer()->size()));
76 responses_
.push_back(response
.release());
79 // Adds pre-built DnsResponse.
80 void AddResponse(scoped_ptr
<DnsResponse
> response
, IoMode mode
) {
81 uint16 tcp_length
= response
->io_buffer()->size();
82 AddResponseWithLength(response
.Pass(), mode
, tcp_length
);
85 // Adds pre-built response from |data| buffer.
86 void AddResponseData(const uint8
* data
, size_t length
, IoMode mode
) {
87 CHECK(!provider_
.get());
88 AddResponse(make_scoped_ptr(
89 new DnsResponse(reinterpret_cast<const char*>(data
), length
, 0)), mode
);
92 // Add no-answer (RCODE only) response matching the query.
93 void AddRcode(int rcode
, IoMode mode
) {
94 scoped_ptr
<DnsResponse
> response(
95 new DnsResponse(query_
->io_buffer()->data(),
96 query_
->io_buffer()->size(),
98 dns_protocol::Header
* header
=
99 reinterpret_cast<dns_protocol::Header
*>(response
->io_buffer()->data());
100 header
->flags
|= base::HostToNet16(dns_protocol::kFlagResponse
| rcode
);
101 AddResponse(response
.Pass(), mode
);
104 // Build, if needed, and return the SocketDataProvider. No new responses
105 // should be added afterwards.
106 SocketDataProvider
* GetProvider() {
108 return provider_
.get();
109 // Terminate the reads with ERR_IO_PENDING to prevent overrun and default to
111 reads_
.push_back(MockRead(ASYNC
, ERR_IO_PENDING
));
112 provider_
.reset(new DelayedSocketData(1, &reads_
[0], reads_
.size(),
113 &writes_
[0], writes_
.size()));
115 provider_
->set_connect_data(MockConnect(reads_
[0].mode
, OK
));
117 return provider_
.get();
120 uint16
query_id() const {
124 // Returns true if the expected query was written to the socket.
125 bool was_written() const {
126 CHECK(provider_
.get());
127 return provider_
->write_index() > 0;
131 scoped_ptr
<DnsQuery
> query_
;
133 ScopedVector
<uint16
> lengths_
;
134 ScopedVector
<DnsResponse
> responses_
;
135 std::vector
<MockWrite
> writes_
;
136 std::vector
<MockRead
> reads_
;
137 scoped_ptr
<DelayedSocketData
> provider_
;
139 DISALLOW_COPY_AND_ASSIGN(DnsSocketData
);
142 class TestSocketFactory
;
144 // A variant of MockUDPClientSocket which always fails to Connect.
145 class FailingUDPClientSocket
: public MockUDPClientSocket
{
147 FailingUDPClientSocket(SocketDataProvider
* data
,
148 net::NetLog
* net_log
)
149 : MockUDPClientSocket(data
, net_log
) {
151 virtual ~FailingUDPClientSocket() {}
152 virtual int Connect(const IPEndPoint
& endpoint
) OVERRIDE
{
153 return ERR_CONNECTION_REFUSED
;
157 DISALLOW_COPY_AND_ASSIGN(FailingUDPClientSocket
);
160 // A variant of MockUDPClientSocket which notifies the factory OnConnect.
161 class TestUDPClientSocket
: public MockUDPClientSocket
{
163 TestUDPClientSocket(TestSocketFactory
* factory
,
164 SocketDataProvider
* data
,
165 net::NetLog
* net_log
)
166 : MockUDPClientSocket(data
, net_log
), factory_(factory
) {
168 virtual ~TestUDPClientSocket() {}
169 virtual int Connect(const IPEndPoint
& endpoint
) OVERRIDE
;
172 TestSocketFactory
* factory_
;
174 DISALLOW_COPY_AND_ASSIGN(TestUDPClientSocket
);
177 // Creates TestUDPClientSockets and keeps endpoints reported via OnConnect.
178 class TestSocketFactory
: public MockClientSocketFactory
{
180 TestSocketFactory() : fail_next_socket_(false) {}
181 virtual ~TestSocketFactory() {}
183 virtual scoped_ptr
<DatagramClientSocket
> CreateDatagramClientSocket(
184 DatagramSocket::BindType bind_type
,
185 const RandIntCallback
& rand_int_cb
,
186 net::NetLog
* net_log
,
187 const net::NetLog::Source
& source
) OVERRIDE
{
188 if (fail_next_socket_
) {
189 fail_next_socket_
= false;
190 return scoped_ptr
<DatagramClientSocket
>(
191 new FailingUDPClientSocket(&empty_data_
, net_log
));
193 SocketDataProvider
* data_provider
= mock_data().GetNext();
194 scoped_ptr
<TestUDPClientSocket
> socket(
195 new TestUDPClientSocket(this, data_provider
, net_log
));
196 data_provider
->set_socket(socket
.get());
197 return socket
.PassAs
<DatagramClientSocket
>();
200 void OnConnect(const IPEndPoint
& endpoint
) {
201 remote_endpoints_
.push_back(endpoint
);
204 std::vector
<IPEndPoint
> remote_endpoints_
;
205 bool fail_next_socket_
;
208 StaticSocketDataProvider empty_data_
;
210 DISALLOW_COPY_AND_ASSIGN(TestSocketFactory
);
213 int TestUDPClientSocket::Connect(const IPEndPoint
& endpoint
) {
214 factory_
->OnConnect(endpoint
);
215 return MockUDPClientSocket::Connect(endpoint
);
218 // Helper class that holds a DnsTransaction and handles OnTransactionComplete.
219 class TransactionHelper
{
221 // If |expected_answer_count| < 0 then it is the expected net error.
222 TransactionHelper(const char* hostname
,
224 int expected_answer_count
)
225 : hostname_(hostname
),
227 expected_answer_count_(expected_answer_count
),
228 cancel_in_callback_(false),
229 quit_in_callback_(false),
233 // Mark that the transaction shall be destroyed immediately upon callback.
234 void set_cancel_in_callback() {
235 cancel_in_callback_
= true;
238 // Mark to call MessageLoop::Quit() upon callback.
239 void set_quit_in_callback() {
240 quit_in_callback_
= true;
243 void StartTransaction(DnsTransactionFactory
* factory
) {
244 EXPECT_EQ(NULL
, transaction_
.get());
245 transaction_
= factory
->CreateTransaction(
248 base::Bind(&TransactionHelper::OnTransactionComplete
,
249 base::Unretained(this)),
251 EXPECT_EQ(hostname_
, transaction_
->GetHostname());
252 EXPECT_EQ(qtype_
, transaction_
->GetType());
253 transaction_
->Start();
257 ASSERT_TRUE(transaction_
.get() != NULL
);
258 transaction_
.reset(NULL
);
261 void OnTransactionComplete(DnsTransaction
* t
,
263 const DnsResponse
* response
) {
264 EXPECT_FALSE(completed_
);
265 EXPECT_EQ(transaction_
.get(), t
);
269 if (cancel_in_callback_
) {
274 // Tell MessageLoop to quit now, in case any ASSERT_* fails.
275 if (quit_in_callback_
)
276 base::MessageLoop::current()->Quit();
278 if (expected_answer_count_
>= 0) {
280 ASSERT_TRUE(response
!= NULL
);
281 EXPECT_EQ(static_cast<unsigned>(expected_answer_count_
),
282 response
->answer_count());
283 EXPECT_EQ(qtype_
, response
->qtype());
285 DnsRecordParser parser
= response
->Parser();
286 DnsResourceRecord record
;
287 for (int i
= 0; i
< expected_answer_count_
; ++i
) {
288 EXPECT_TRUE(parser
.ReadRecord(&record
));
291 EXPECT_EQ(expected_answer_count_
, rv
);
295 bool has_completed() const {
299 // Shorthands for commonly used commands.
301 bool Run(DnsTransactionFactory
* factory
) {
302 StartTransaction(factory
);
303 base::MessageLoop::current()->RunUntilIdle();
304 return has_completed();
307 // Use when some of the responses are timeouts.
308 bool RunUntilDone(DnsTransactionFactory
* factory
) {
309 set_quit_in_callback();
310 StartTransaction(factory
);
311 base::MessageLoop::current()->Run();
312 return has_completed();
316 std::string hostname_
;
318 scoped_ptr
<DnsTransaction
> transaction_
;
319 int expected_answer_count_
;
320 bool cancel_in_callback_
;
321 bool quit_in_callback_
;
326 class DnsTransactionTest
: public testing::Test
{
328 DnsTransactionTest() {}
330 // Generates |nameservers| for DnsConfig.
331 void ConfigureNumServers(unsigned num_servers
) {
332 CHECK_LE(num_servers
, 255u);
333 config_
.nameservers
.clear();
334 IPAddressNumber dns_ip
;
336 bool rv
= ParseIPLiteralToNumber("192.168.1.0", &dns_ip
);
339 for (unsigned i
= 0; i
< num_servers
; ++i
) {
341 config_
.nameservers
.push_back(IPEndPoint(dns_ip
,
342 dns_protocol::kDefaultPort
));
346 // Called after fully configuring |config|.
347 void ConfigureFactory() {
348 socket_factory_
.reset(new TestSocketFactory());
349 session_
= new DnsSession(
351 DnsSocketPool::CreateNull(socket_factory_
.get()),
352 base::Bind(&DnsTransactionTest::GetNextId
, base::Unretained(this)),
354 transaction_factory_
= DnsTransactionFactory::CreateFactory(session_
.get());
357 void AddSocketData(scoped_ptr
<DnsSocketData
> data
) {
358 CHECK(socket_factory_
.get());
359 transaction_ids_
.push_back(data
->query_id());
360 socket_factory_
->AddSocketDataProvider(data
->GetProvider());
361 socket_data_
.push_back(data
.release());
364 // Add expected query for |dotted_name| and |qtype| with |id| and response
365 // taken verbatim from |data| of |data_length| bytes. The transaction id in
366 // |data| should equal |id|, unless testing mismatched response.
367 void AddQueryAndResponse(uint16 id
,
368 const char* dotted_name
,
370 const uint8
* response_data
,
371 size_t response_length
,
374 CHECK(socket_factory_
.get());
375 scoped_ptr
<DnsSocketData
> data(
376 new DnsSocketData(id
, dotted_name
, qtype
, mode
, use_tcp
));
377 data
->AddResponseData(response_data
, response_length
, mode
);
378 AddSocketData(data
.Pass());
381 void AddAsyncQueryAndResponse(uint16 id
,
382 const char* dotted_name
,
385 size_t data_length
) {
386 AddQueryAndResponse(id
, dotted_name
, qtype
, data
, data_length
, ASYNC
,
390 void AddSyncQueryAndResponse(uint16 id
,
391 const char* dotted_name
,
394 size_t data_length
) {
395 AddQueryAndResponse(id
, dotted_name
, qtype
, data
, data_length
, SYNCHRONOUS
,
399 // Add expected query of |dotted_name| and |qtype| and no response.
400 void AddQueryAndTimeout(const char* dotted_name
, uint16 qtype
) {
401 uint16 id
= base::RandInt(0, kuint16max
);
402 scoped_ptr
<DnsSocketData
> data(
403 new DnsSocketData(id
, dotted_name
, qtype
, ASYNC
, false));
404 AddSocketData(data
.Pass());
407 // Add expected query of |dotted_name| and |qtype| and matching response with
408 // no answer and RCODE set to |rcode|. The id will be generated randomly.
409 void AddQueryAndRcode(const char* dotted_name
,
414 CHECK_NE(dns_protocol::kRcodeNOERROR
, rcode
);
415 uint16 id
= base::RandInt(0, kuint16max
);
416 scoped_ptr
<DnsSocketData
> data(
417 new DnsSocketData(id
, dotted_name
, qtype
, mode
, use_tcp
));
418 data
->AddRcode(rcode
, mode
);
419 AddSocketData(data
.Pass());
422 void AddAsyncQueryAndRcode(const char* dotted_name
, uint16 qtype
, int rcode
) {
423 AddQueryAndRcode(dotted_name
, qtype
, rcode
, ASYNC
, false);
426 void AddSyncQueryAndRcode(const char* dotted_name
, uint16 qtype
, int rcode
) {
427 AddQueryAndRcode(dotted_name
, qtype
, rcode
, SYNCHRONOUS
, false);
430 // Checks if the sockets were connected in the order matching the indices in
432 void CheckServerOrder(const unsigned* servers
, size_t num_attempts
) {
433 ASSERT_EQ(num_attempts
, socket_factory_
->remote_endpoints_
.size());
434 for (size_t i
= 0; i
< num_attempts
; ++i
) {
435 EXPECT_EQ(socket_factory_
->remote_endpoints_
[i
],
436 session_
->config().nameservers
[servers
[i
]]);
440 virtual void SetUp() OVERRIDE
{
441 // By default set one server,
442 ConfigureNumServers(1);
443 // and no retransmissions,
444 config_
.attempts
= 1;
445 // but long enough timeout for memory tests.
446 config_
.timeout
= TestTimeouts::action_timeout();
450 virtual void TearDown() OVERRIDE
{
451 // Check that all socket data was at least written to.
452 for (size_t i
= 0; i
< socket_data_
.size(); ++i
) {
453 EXPECT_TRUE(socket_data_
[i
]->was_written()) << i
;
458 int GetNextId(int min
, int max
) {
459 EXPECT_FALSE(transaction_ids_
.empty());
460 int id
= transaction_ids_
.front();
461 transaction_ids_
.pop_front();
469 ScopedVector
<DnsSocketData
> socket_data_
;
471 std::deque
<int> transaction_ids_
;
472 scoped_ptr
<TestSocketFactory
> socket_factory_
;
473 scoped_refptr
<DnsSession
> session_
;
474 scoped_ptr
<DnsTransactionFactory
> transaction_factory_
;
477 TEST_F(DnsTransactionTest
, Lookup
) {
478 AddAsyncQueryAndResponse(0 /* id */, kT0HostName
, kT0Qtype
,
479 kT0ResponseDatagram
, arraysize(kT0ResponseDatagram
));
481 TransactionHelper
helper0(kT0HostName
, kT0Qtype
, kT0RecordCount
);
482 EXPECT_TRUE(helper0
.Run(transaction_factory_
.get()));
485 // Concurrent lookup tests assume that DnsTransaction::Start immediately
486 // consumes a socket from ClientSocketFactory.
487 TEST_F(DnsTransactionTest
, ConcurrentLookup
) {
488 AddAsyncQueryAndResponse(0 /* id */, kT0HostName
, kT0Qtype
,
489 kT0ResponseDatagram
, arraysize(kT0ResponseDatagram
));
490 AddAsyncQueryAndResponse(1 /* id */, kT1HostName
, kT1Qtype
,
491 kT1ResponseDatagram
, arraysize(kT1ResponseDatagram
));
493 TransactionHelper
helper0(kT0HostName
, kT0Qtype
, kT0RecordCount
);
494 helper0
.StartTransaction(transaction_factory_
.get());
495 TransactionHelper
helper1(kT1HostName
, kT1Qtype
, kT1RecordCount
);
496 helper1
.StartTransaction(transaction_factory_
.get());
498 base::MessageLoop::current()->RunUntilIdle();
500 EXPECT_TRUE(helper0
.has_completed());
501 EXPECT_TRUE(helper1
.has_completed());
504 TEST_F(DnsTransactionTest
, CancelLookup
) {
505 AddAsyncQueryAndResponse(0 /* id */, kT0HostName
, kT0Qtype
,
506 kT0ResponseDatagram
, arraysize(kT0ResponseDatagram
));
507 AddAsyncQueryAndResponse(1 /* id */, kT1HostName
, kT1Qtype
,
508 kT1ResponseDatagram
, arraysize(kT1ResponseDatagram
));
510 TransactionHelper
helper0(kT0HostName
, kT0Qtype
, kT0RecordCount
);
511 helper0
.StartTransaction(transaction_factory_
.get());
512 TransactionHelper
helper1(kT1HostName
, kT1Qtype
, kT1RecordCount
);
513 helper1
.StartTransaction(transaction_factory_
.get());
517 base::MessageLoop::current()->RunUntilIdle();
519 EXPECT_FALSE(helper0
.has_completed());
520 EXPECT_TRUE(helper1
.has_completed());
523 TEST_F(DnsTransactionTest
, DestroyFactory
) {
524 AddAsyncQueryAndResponse(0 /* id */, kT0HostName
, kT0Qtype
,
525 kT0ResponseDatagram
, arraysize(kT0ResponseDatagram
));
527 TransactionHelper
helper0(kT0HostName
, kT0Qtype
, kT0RecordCount
);
528 helper0
.StartTransaction(transaction_factory_
.get());
530 // Destroying the client does not affect running requests.
531 transaction_factory_
.reset(NULL
);
533 base::MessageLoop::current()->RunUntilIdle();
535 EXPECT_TRUE(helper0
.has_completed());
538 TEST_F(DnsTransactionTest
, CancelFromCallback
) {
539 AddAsyncQueryAndResponse(0 /* id */, kT0HostName
, kT0Qtype
,
540 kT0ResponseDatagram
, arraysize(kT0ResponseDatagram
));
542 TransactionHelper
helper0(kT0HostName
, kT0Qtype
, kT0RecordCount
);
543 helper0
.set_cancel_in_callback();
544 EXPECT_TRUE(helper0
.Run(transaction_factory_
.get()));
547 TEST_F(DnsTransactionTest
, MismatchedResponseSync
) {
548 config_
.attempts
= 2;
549 config_
.timeout
= TestTimeouts::tiny_timeout();
552 // Attempt receives mismatched response followed by valid response.
553 scoped_ptr
<DnsSocketData
> data(
554 new DnsSocketData(0 /* id */, kT0HostName
, kT0Qtype
, SYNCHRONOUS
, false));
555 data
->AddResponseData(kT1ResponseDatagram
,
556 arraysize(kT1ResponseDatagram
), SYNCHRONOUS
);
557 data
->AddResponseData(kT0ResponseDatagram
,
558 arraysize(kT0ResponseDatagram
), SYNCHRONOUS
);
559 AddSocketData(data
.Pass());
561 TransactionHelper
helper0(kT0HostName
, kT0Qtype
, kT0RecordCount
);
562 EXPECT_TRUE(helper0
.RunUntilDone(transaction_factory_
.get()));
565 TEST_F(DnsTransactionTest
, MismatchedResponseAsync
) {
566 config_
.attempts
= 2;
567 config_
.timeout
= TestTimeouts::tiny_timeout();
570 // First attempt receives mismatched response followed by valid response.
571 // Second attempt times out.
572 scoped_ptr
<DnsSocketData
> data(
573 new DnsSocketData(0 /* id */, kT0HostName
, kT0Qtype
, ASYNC
, false));
574 data
->AddResponseData(kT1ResponseDatagram
,
575 arraysize(kT1ResponseDatagram
), ASYNC
);
576 data
->AddResponseData(kT0ResponseDatagram
,
577 arraysize(kT0ResponseDatagram
), ASYNC
);
578 AddSocketData(data
.Pass());
579 AddQueryAndTimeout(kT0HostName
, kT0Qtype
);
581 TransactionHelper
helper0(kT0HostName
, kT0Qtype
, kT0RecordCount
);
582 EXPECT_TRUE(helper0
.RunUntilDone(transaction_factory_
.get()));
585 TEST_F(DnsTransactionTest
, MismatchedResponseFail
) {
586 config_
.timeout
= TestTimeouts::tiny_timeout();
589 // Attempt receives mismatched response but times out because only one attempt
591 AddAsyncQueryAndResponse(1 /* id */, kT0HostName
, kT0Qtype
,
592 kT0ResponseDatagram
, arraysize(kT0ResponseDatagram
));
594 TransactionHelper
helper0(kT0HostName
, kT0Qtype
, ERR_DNS_TIMED_OUT
);
595 EXPECT_TRUE(helper0
.RunUntilDone(transaction_factory_
.get()));
598 TEST_F(DnsTransactionTest
, ServerFail
) {
599 AddAsyncQueryAndRcode(kT0HostName
, kT0Qtype
, dns_protocol::kRcodeSERVFAIL
);
601 TransactionHelper
helper0(kT0HostName
, kT0Qtype
, ERR_DNS_SERVER_FAILED
);
602 EXPECT_TRUE(helper0
.Run(transaction_factory_
.get()));
605 TEST_F(DnsTransactionTest
, NoDomain
) {
606 AddAsyncQueryAndRcode(kT0HostName
, kT0Qtype
, dns_protocol::kRcodeNXDOMAIN
);
608 TransactionHelper
helper0(kT0HostName
, kT0Qtype
, ERR_NAME_NOT_RESOLVED
);
609 EXPECT_TRUE(helper0
.Run(transaction_factory_
.get()));
612 TEST_F(DnsTransactionTest
, Timeout
) {
613 config_
.attempts
= 3;
614 // Use short timeout to speed up the test.
615 config_
.timeout
= TestTimeouts::tiny_timeout();
618 AddQueryAndTimeout(kT0HostName
, kT0Qtype
);
619 AddQueryAndTimeout(kT0HostName
, kT0Qtype
);
620 AddQueryAndTimeout(kT0HostName
, kT0Qtype
);
622 TransactionHelper
helper0(kT0HostName
, kT0Qtype
, ERR_DNS_TIMED_OUT
);
623 EXPECT_TRUE(helper0
.RunUntilDone(transaction_factory_
.get()));
624 EXPECT_TRUE(base::MessageLoop::current()->IsIdleForTesting());
627 TEST_F(DnsTransactionTest
, ServerFallbackAndRotate
) {
628 // Test that we fallback on both server failure and timeout.
629 config_
.attempts
= 2;
630 // The next request should start from the next server.
631 config_
.rotate
= true;
632 ConfigureNumServers(3);
633 // Use short timeout to speed up the test.
634 config_
.timeout
= TestTimeouts::tiny_timeout();
637 // Responses for first request.
638 AddQueryAndTimeout(kT0HostName
, kT0Qtype
);
639 AddAsyncQueryAndRcode(kT0HostName
, kT0Qtype
, dns_protocol::kRcodeSERVFAIL
);
640 AddQueryAndTimeout(kT0HostName
, kT0Qtype
);
641 AddAsyncQueryAndRcode(kT0HostName
, kT0Qtype
, dns_protocol::kRcodeSERVFAIL
);
642 AddAsyncQueryAndRcode(kT0HostName
, kT0Qtype
, dns_protocol::kRcodeNXDOMAIN
);
643 // Responses for second request.
644 AddAsyncQueryAndRcode(kT1HostName
, kT1Qtype
, dns_protocol::kRcodeSERVFAIL
);
645 AddAsyncQueryAndRcode(kT1HostName
, kT1Qtype
, dns_protocol::kRcodeSERVFAIL
);
646 AddAsyncQueryAndRcode(kT1HostName
, kT1Qtype
, dns_protocol::kRcodeNXDOMAIN
);
648 TransactionHelper
helper0(kT0HostName
, kT0Qtype
, ERR_NAME_NOT_RESOLVED
);
649 TransactionHelper
helper1(kT1HostName
, kT1Qtype
, ERR_NAME_NOT_RESOLVED
);
651 EXPECT_TRUE(helper0
.RunUntilDone(transaction_factory_
.get()));
652 EXPECT_TRUE(helper1
.Run(transaction_factory_
.get()));
654 unsigned kOrder
[] = {
655 0, 1, 2, 0, 1, // The first transaction.
656 1, 2, 0, // The second transaction starts from the next server.
658 CheckServerOrder(kOrder
, arraysize(kOrder
));
661 TEST_F(DnsTransactionTest
, SuffixSearchAboveNdots
) {
663 config_
.search
.push_back("a");
664 config_
.search
.push_back("b");
665 config_
.search
.push_back("c");
666 config_
.rotate
= true;
667 ConfigureNumServers(2);
670 AddAsyncQueryAndRcode("x.y.z", dns_protocol::kTypeA
,
671 dns_protocol::kRcodeNXDOMAIN
);
672 AddAsyncQueryAndRcode("x.y.z.a", dns_protocol::kTypeA
,
673 dns_protocol::kRcodeNXDOMAIN
);
674 AddAsyncQueryAndRcode("x.y.z.b", dns_protocol::kTypeA
,
675 dns_protocol::kRcodeNXDOMAIN
);
676 AddAsyncQueryAndRcode("x.y.z.c", dns_protocol::kTypeA
,
677 dns_protocol::kRcodeNXDOMAIN
);
679 TransactionHelper
helper0("x.y.z", dns_protocol::kTypeA
,
680 ERR_NAME_NOT_RESOLVED
);
682 EXPECT_TRUE(helper0
.Run(transaction_factory_
.get()));
684 // Also check if suffix search causes server rotation.
685 unsigned kOrder0
[] = { 0, 1, 0, 1 };
686 CheckServerOrder(kOrder0
, arraysize(kOrder0
));
689 TEST_F(DnsTransactionTest
, SuffixSearchBelowNdots
) {
691 config_
.search
.push_back("a");
692 config_
.search
.push_back("b");
693 config_
.search
.push_back("c");
696 // Responses for first transaction.
697 AddAsyncQueryAndRcode("x.y.a", dns_protocol::kTypeA
,
698 dns_protocol::kRcodeNXDOMAIN
);
699 AddAsyncQueryAndRcode("x.y.b", dns_protocol::kTypeA
,
700 dns_protocol::kRcodeNXDOMAIN
);
701 AddAsyncQueryAndRcode("x.y.c", dns_protocol::kTypeA
,
702 dns_protocol::kRcodeNXDOMAIN
);
703 AddAsyncQueryAndRcode("x.y", dns_protocol::kTypeA
,
704 dns_protocol::kRcodeNXDOMAIN
);
705 // Responses for second transaction.
706 AddAsyncQueryAndRcode("x.a", dns_protocol::kTypeA
,
707 dns_protocol::kRcodeNXDOMAIN
);
708 AddAsyncQueryAndRcode("x.b", dns_protocol::kTypeA
,
709 dns_protocol::kRcodeNXDOMAIN
);
710 AddAsyncQueryAndRcode("x.c", dns_protocol::kTypeA
,
711 dns_protocol::kRcodeNXDOMAIN
);
712 // Responses for third transaction.
713 AddAsyncQueryAndRcode("x", dns_protocol::kTypeAAAA
,
714 dns_protocol::kRcodeNXDOMAIN
);
716 TransactionHelper
helper0("x.y", dns_protocol::kTypeA
, ERR_NAME_NOT_RESOLVED
);
718 EXPECT_TRUE(helper0
.Run(transaction_factory_
.get()));
720 // A single-label name.
721 TransactionHelper
helper1("x", dns_protocol::kTypeA
, ERR_NAME_NOT_RESOLVED
);
723 EXPECT_TRUE(helper1
.Run(transaction_factory_
.get()));
725 // A fully-qualified name.
726 TransactionHelper
helper2("x.", dns_protocol::kTypeAAAA
,
727 ERR_NAME_NOT_RESOLVED
);
729 EXPECT_TRUE(helper2
.Run(transaction_factory_
.get()));
732 TEST_F(DnsTransactionTest
, EmptySuffixSearch
) {
733 // Responses for first transaction.
734 AddAsyncQueryAndRcode("x", dns_protocol::kTypeA
,
735 dns_protocol::kRcodeNXDOMAIN
);
737 // A fully-qualified name.
738 TransactionHelper
helper0("x.", dns_protocol::kTypeA
, ERR_NAME_NOT_RESOLVED
);
740 EXPECT_TRUE(helper0
.Run(transaction_factory_
.get()));
742 // A single label name is not even attempted.
743 TransactionHelper
helper1("singlelabel", dns_protocol::kTypeA
,
744 ERR_DNS_SEARCH_EMPTY
);
746 helper1
.Run(transaction_factory_
.get());
747 EXPECT_TRUE(helper1
.has_completed());
750 TEST_F(DnsTransactionTest
, DontAppendToMultiLabelName
) {
751 config_
.search
.push_back("a");
752 config_
.search
.push_back("b");
753 config_
.search
.push_back("c");
754 config_
.append_to_multi_label_name
= false;
757 // Responses for first transaction.
758 AddAsyncQueryAndRcode("x.y.z", dns_protocol::kTypeA
,
759 dns_protocol::kRcodeNXDOMAIN
);
760 // Responses for second transaction.
761 AddAsyncQueryAndRcode("x.y", dns_protocol::kTypeA
,
762 dns_protocol::kRcodeNXDOMAIN
);
763 // Responses for third transaction.
764 AddAsyncQueryAndRcode("x.a", dns_protocol::kTypeA
,
765 dns_protocol::kRcodeNXDOMAIN
);
766 AddAsyncQueryAndRcode("x.b", dns_protocol::kTypeA
,
767 dns_protocol::kRcodeNXDOMAIN
);
768 AddAsyncQueryAndRcode("x.c", dns_protocol::kTypeA
,
769 dns_protocol::kRcodeNXDOMAIN
);
771 TransactionHelper
helper0("x.y.z", dns_protocol::kTypeA
,
772 ERR_NAME_NOT_RESOLVED
);
773 EXPECT_TRUE(helper0
.Run(transaction_factory_
.get()));
775 TransactionHelper
helper1("x.y", dns_protocol::kTypeA
, ERR_NAME_NOT_RESOLVED
);
776 EXPECT_TRUE(helper1
.Run(transaction_factory_
.get()));
778 TransactionHelper
helper2("x", dns_protocol::kTypeA
, ERR_NAME_NOT_RESOLVED
);
779 EXPECT_TRUE(helper2
.Run(transaction_factory_
.get()));
782 const uint8 kResponseNoData
[] = {
783 0x00, 0x00, 0x81, 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
785 0x01, 'x', 0x01, 'y', 0x01, 'z', 0x01, 'b', 0x00, 0x00, 0x01, 0x00, 0x01,
786 // Authority section, SOA record, TTL 0x3E6
787 0x01, 'z', 0x00, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x03, 0xE6,
788 // Minimal RDATA, 18 bytes
791 0x00, 0x00, 0x00, 0x00,
792 0x00, 0x00, 0x00, 0x00,
793 0x00, 0x00, 0x00, 0x00,
794 0x00, 0x00, 0x00, 0x00,
797 TEST_F(DnsTransactionTest
, SuffixSearchStop
) {
799 config_
.search
.push_back("a");
800 config_
.search
.push_back("b");
801 config_
.search
.push_back("c");
804 AddAsyncQueryAndRcode("x.y.z", dns_protocol::kTypeA
,
805 dns_protocol::kRcodeNXDOMAIN
);
806 AddAsyncQueryAndRcode("x.y.z.a", dns_protocol::kTypeA
,
807 dns_protocol::kRcodeNXDOMAIN
);
808 AddAsyncQueryAndResponse(0 /* id */, "x.y.z.b", dns_protocol::kTypeA
,
809 kResponseNoData
, arraysize(kResponseNoData
));
811 TransactionHelper
helper0("x.y.z", dns_protocol::kTypeA
, 0 /* answers */);
813 EXPECT_TRUE(helper0
.Run(transaction_factory_
.get()));
816 TEST_F(DnsTransactionTest
, SyncFirstQuery
) {
817 config_
.search
.push_back("lab.ccs.neu.edu");
818 config_
.search
.push_back("ccs.neu.edu");
821 AddSyncQueryAndResponse(0 /* id */, kT0HostName
, kT0Qtype
,
822 kT0ResponseDatagram
, arraysize(kT0ResponseDatagram
));
824 TransactionHelper
helper0(kT0HostName
, kT0Qtype
, kT0RecordCount
);
825 EXPECT_TRUE(helper0
.Run(transaction_factory_
.get()));
828 TEST_F(DnsTransactionTest
, SyncFirstQueryWithSearch
) {
829 config_
.search
.push_back("lab.ccs.neu.edu");
830 config_
.search
.push_back("ccs.neu.edu");
833 AddSyncQueryAndRcode("www.lab.ccs.neu.edu", kT2Qtype
,
834 dns_protocol::kRcodeNXDOMAIN
);
836 AddAsyncQueryAndResponse(2 /* id */, kT2HostName
, kT2Qtype
,
837 kT2ResponseDatagram
, arraysize(kT2ResponseDatagram
));
839 TransactionHelper
helper0("www", kT2Qtype
, kT2RecordCount
);
840 EXPECT_TRUE(helper0
.Run(transaction_factory_
.get()));
843 TEST_F(DnsTransactionTest
, SyncSearchQuery
) {
844 config_
.search
.push_back("lab.ccs.neu.edu");
845 config_
.search
.push_back("ccs.neu.edu");
848 AddAsyncQueryAndRcode("www.lab.ccs.neu.edu", dns_protocol::kTypeA
,
849 dns_protocol::kRcodeNXDOMAIN
);
850 AddSyncQueryAndResponse(2 /* id */, kT2HostName
, kT2Qtype
,
851 kT2ResponseDatagram
, arraysize(kT2ResponseDatagram
));
853 TransactionHelper
helper0("www", kT2Qtype
, kT2RecordCount
);
854 EXPECT_TRUE(helper0
.Run(transaction_factory_
.get()));
857 TEST_F(DnsTransactionTest
, ConnectFailure
) {
858 socket_factory_
->fail_next_socket_
= true;
859 transaction_ids_
.push_back(0); // Needed to make a DnsUDPAttempt.
860 TransactionHelper
helper0("www.chromium.org", dns_protocol::kTypeA
,
861 ERR_CONNECTION_REFUSED
);
862 EXPECT_TRUE(helper0
.Run(transaction_factory_
.get()));
865 TEST_F(DnsTransactionTest
, ConnectFailureFollowedBySuccess
) {
866 // Retry after server failure.
867 config_
.attempts
= 2;
869 // First server connection attempt fails.
870 transaction_ids_
.push_back(0); // Needed to make a DnsUDPAttempt.
871 socket_factory_
->fail_next_socket_
= true;
872 // Second DNS query succeeds.
873 AddAsyncQueryAndResponse(0 /* id */, kT0HostName
, kT0Qtype
,
874 kT0ResponseDatagram
, arraysize(kT0ResponseDatagram
));
875 TransactionHelper
helper0(kT0HostName
, kT0Qtype
, kT0RecordCount
);
876 EXPECT_TRUE(helper0
.Run(transaction_factory_
.get()));
879 TEST_F(DnsTransactionTest
, TCPLookup
) {
880 AddAsyncQueryAndRcode(kT0HostName
, kT0Qtype
,
881 dns_protocol::kRcodeNOERROR
| dns_protocol::kFlagTC
);
882 AddQueryAndResponse(0 /* id */, kT0HostName
, kT0Qtype
,
883 kT0ResponseDatagram
, arraysize(kT0ResponseDatagram
),
884 ASYNC
, true /* use_tcp */);
886 TransactionHelper
helper0(kT0HostName
, kT0Qtype
, kT0RecordCount
);
887 EXPECT_TRUE(helper0
.Run(transaction_factory_
.get()));
890 TEST_F(DnsTransactionTest
, TCPFailure
) {
891 AddAsyncQueryAndRcode(kT0HostName
, kT0Qtype
,
892 dns_protocol::kRcodeNOERROR
| dns_protocol::kFlagTC
);
893 AddQueryAndRcode(kT0HostName
, kT0Qtype
, dns_protocol::kRcodeSERVFAIL
,
894 ASYNC
, true /* use_tcp */);
896 TransactionHelper
helper0(kT0HostName
, kT0Qtype
, ERR_DNS_SERVER_FAILED
);
897 EXPECT_TRUE(helper0
.Run(transaction_factory_
.get()));
900 TEST_F(DnsTransactionTest
, TCPMalformed
) {
901 AddAsyncQueryAndRcode(kT0HostName
, kT0Qtype
,
902 dns_protocol::kRcodeNOERROR
| dns_protocol::kFlagTC
);
903 scoped_ptr
<DnsSocketData
> data(
904 new DnsSocketData(0 /* id */, kT0HostName
, kT0Qtype
, ASYNC
, true));
905 // Valid response but length too short.
906 data
->AddResponseWithLength(
908 new DnsResponse(reinterpret_cast<const char*>(kT0ResponseDatagram
),
909 arraysize(kT0ResponseDatagram
), 0)),
911 static_cast<uint16
>(kT0QuerySize
- 1));
912 AddSocketData(data
.Pass());
914 TransactionHelper
helper0(kT0HostName
, kT0Qtype
, ERR_DNS_MALFORMED_RESPONSE
);
915 EXPECT_TRUE(helper0
.Run(transaction_factory_
.get()));
918 TEST_F(DnsTransactionTest
, TCPTimeout
) {
919 config_
.timeout
= TestTimeouts::tiny_timeout();
921 AddAsyncQueryAndRcode(kT0HostName
, kT0Qtype
,
922 dns_protocol::kRcodeNOERROR
| dns_protocol::kFlagTC
);
923 AddSocketData(make_scoped_ptr(
924 new DnsSocketData(1 /* id */, kT0HostName
, kT0Qtype
, ASYNC
, true)));
926 TransactionHelper
helper0(kT0HostName
, kT0Qtype
, ERR_DNS_TIMED_OUT
);
927 EXPECT_TRUE(helper0
.RunUntilDone(transaction_factory_
.get()));
930 TEST_F(DnsTransactionTest
, InvalidQuery
) {
931 config_
.timeout
= TestTimeouts::tiny_timeout();
934 TransactionHelper
helper0(".", dns_protocol::kTypeA
, ERR_INVALID_ARGUMENT
);
935 EXPECT_TRUE(helper0
.Run(transaction_factory_
.get()));