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() : create_failing_sockets_(false) {}
181 virtual ~TestSocketFactory() {}
183 virtual 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 (create_failing_sockets_
)
189 return new FailingUDPClientSocket(&empty_data_
, net_log
);
190 SocketDataProvider
* data_provider
= mock_data().GetNext();
191 TestUDPClientSocket
* socket
= new TestUDPClientSocket(this,
194 data_provider
->set_socket(socket
);
198 void OnConnect(const IPEndPoint
& endpoint
) {
199 remote_endpoints_
.push_back(endpoint
);
202 std::vector
<IPEndPoint
> remote_endpoints_
;
203 bool create_failing_sockets_
;
206 StaticSocketDataProvider empty_data_
;
208 DISALLOW_COPY_AND_ASSIGN(TestSocketFactory
);
211 int TestUDPClientSocket::Connect(const IPEndPoint
& endpoint
) {
212 factory_
->OnConnect(endpoint
);
213 return MockUDPClientSocket::Connect(endpoint
);
216 // Helper class that holds a DnsTransaction and handles OnTransactionComplete.
217 class TransactionHelper
{
219 // If |expected_answer_count| < 0 then it is the expected net error.
220 TransactionHelper(const char* hostname
,
222 int expected_answer_count
)
223 : hostname_(hostname
),
225 expected_answer_count_(expected_answer_count
),
226 cancel_in_callback_(false),
227 quit_in_callback_(false),
231 // Mark that the transaction shall be destroyed immediately upon callback.
232 void set_cancel_in_callback() {
233 cancel_in_callback_
= true;
236 // Mark to call MessageLoop::Quit() upon callback.
237 void set_quit_in_callback() {
238 quit_in_callback_
= true;
241 void StartTransaction(DnsTransactionFactory
* factory
) {
242 EXPECT_EQ(NULL
, transaction_
.get());
243 transaction_
= factory
->CreateTransaction(
246 base::Bind(&TransactionHelper::OnTransactionComplete
,
247 base::Unretained(this)),
249 EXPECT_EQ(hostname_
, transaction_
->GetHostname());
250 EXPECT_EQ(qtype_
, transaction_
->GetType());
251 int rv
= transaction_
->Start();
252 if (rv
!= ERR_IO_PENDING
) {
254 EXPECT_EQ(expected_answer_count_
, rv
);
260 ASSERT_TRUE(transaction_
.get() != NULL
);
261 transaction_
.reset(NULL
);
264 void OnTransactionComplete(DnsTransaction
* t
,
266 const DnsResponse
* response
) {
267 EXPECT_FALSE(completed_
);
268 EXPECT_EQ(transaction_
.get(), t
);
272 if (cancel_in_callback_
) {
277 // Tell MessageLoop to quit now, in case any ASSERT_* fails.
278 if (quit_in_callback_
)
279 MessageLoop::current()->Quit();
281 if (expected_answer_count_
>= 0) {
283 ASSERT_TRUE(response
!= NULL
);
284 EXPECT_EQ(static_cast<unsigned>(expected_answer_count_
),
285 response
->answer_count());
286 EXPECT_EQ(qtype_
, response
->qtype());
288 DnsRecordParser parser
= response
->Parser();
289 DnsResourceRecord record
;
290 for (int i
= 0; i
< expected_answer_count_
; ++i
) {
291 EXPECT_TRUE(parser
.ReadRecord(&record
));
294 EXPECT_EQ(expected_answer_count_
, rv
);
298 bool has_completed() const {
302 // Shorthands for commonly used commands.
304 bool Run(DnsTransactionFactory
* factory
) {
305 StartTransaction(factory
);
306 MessageLoop::current()->RunUntilIdle();
307 return has_completed();
310 // Use when some of the responses are timeouts.
311 bool RunUntilDone(DnsTransactionFactory
* factory
) {
312 set_quit_in_callback();
313 StartTransaction(factory
);
314 MessageLoop::current()->Run();
315 return has_completed();
319 std::string hostname_
;
321 scoped_ptr
<DnsTransaction
> transaction_
;
322 int expected_answer_count_
;
323 bool cancel_in_callback_
;
324 bool quit_in_callback_
;
329 class DnsTransactionTest
: public testing::Test
{
331 DnsTransactionTest() : socket_factory_(NULL
) {}
333 // Generates |nameservers| for DnsConfig.
334 void ConfigureNumServers(unsigned num_servers
) {
335 CHECK_LE(num_servers
, 255u);
336 config_
.nameservers
.clear();
337 IPAddressNumber dns_ip
;
339 bool rv
= ParseIPLiteralToNumber("192.168.1.0", &dns_ip
);
342 for (unsigned i
= 0; i
< num_servers
; ++i
) {
344 config_
.nameservers
.push_back(IPEndPoint(dns_ip
,
345 dns_protocol::kDefaultPort
));
349 // Called after fully configuring |config|.
350 void ConfigureFactory() {
351 socket_factory_
.reset(new TestSocketFactory());
352 session_
= new DnsSession(
354 DnsSocketPool::CreateNull(socket_factory_
.get()),
355 base::Bind(&DnsTransactionTest::GetNextId
, base::Unretained(this)),
357 transaction_factory_
= DnsTransactionFactory::CreateFactory(session_
.get());
360 void AddSocketData(scoped_ptr
<DnsSocketData
> data
) {
361 CHECK(socket_factory_
.get());
362 transaction_ids_
.push_back(data
->query_id());
363 socket_factory_
->AddSocketDataProvider(data
->GetProvider());
364 socket_data_
.push_back(data
.release());
367 // Add expected query for |dotted_name| and |qtype| with |id| and response
368 // taken verbatim from |data| of |data_length| bytes. The transaction id in
369 // |data| should equal |id|, unless testing mismatched response.
370 void AddQueryAndResponse(uint16 id
,
371 const char* dotted_name
,
373 const uint8
* response_data
,
374 size_t response_length
,
377 CHECK(socket_factory_
.get());
378 scoped_ptr
<DnsSocketData
> data(
379 new DnsSocketData(id
, dotted_name
, qtype
, mode
, use_tcp
));
380 data
->AddResponseData(response_data
, response_length
, mode
);
381 AddSocketData(data
.Pass());
384 void AddAsyncQueryAndResponse(uint16 id
,
385 const char* dotted_name
,
388 size_t data_length
) {
389 AddQueryAndResponse(id
, dotted_name
, qtype
, data
, data_length
, ASYNC
,
393 void AddSyncQueryAndResponse(uint16 id
,
394 const char* dotted_name
,
397 size_t data_length
) {
398 AddQueryAndResponse(id
, dotted_name
, qtype
, data
, data_length
, SYNCHRONOUS
,
402 // Add expected query of |dotted_name| and |qtype| and no response.
403 void AddQueryAndTimeout(const char* dotted_name
, uint16 qtype
) {
404 uint16 id
= base::RandInt(0, kuint16max
);
405 scoped_ptr
<DnsSocketData
> data(
406 new DnsSocketData(id
, dotted_name
, qtype
, ASYNC
, false));
407 AddSocketData(data
.Pass());
410 // Add expected query of |dotted_name| and |qtype| and matching response with
411 // no answer and RCODE set to |rcode|. The id will be generated randomly.
412 void AddQueryAndRcode(const char* dotted_name
,
417 CHECK_NE(dns_protocol::kRcodeNOERROR
, rcode
);
418 uint16 id
= base::RandInt(0, kuint16max
);
419 scoped_ptr
<DnsSocketData
> data(
420 new DnsSocketData(id
, dotted_name
, qtype
, mode
, use_tcp
));
421 data
->AddRcode(rcode
, mode
);
422 AddSocketData(data
.Pass());
425 void AddAsyncQueryAndRcode(const char* dotted_name
, uint16 qtype
, int rcode
) {
426 AddQueryAndRcode(dotted_name
, qtype
, rcode
, ASYNC
, false);
429 void AddSyncQueryAndRcode(const char* dotted_name
, uint16 qtype
, int rcode
) {
430 AddQueryAndRcode(dotted_name
, qtype
, rcode
, SYNCHRONOUS
, false);
433 // Checks if the sockets were connected in the order matching the indices in
435 void CheckServerOrder(const unsigned* servers
, size_t num_attempts
) {
436 ASSERT_EQ(num_attempts
, socket_factory_
->remote_endpoints_
.size());
437 for (size_t i
= 0; i
< num_attempts
; ++i
) {
438 EXPECT_EQ(socket_factory_
->remote_endpoints_
[i
],
439 session_
->config().nameservers
[servers
[i
]]);
443 void SetUp() OVERRIDE
{
444 // By default set one server,
445 ConfigureNumServers(1);
446 // and no retransmissions,
447 config_
.attempts
= 1;
448 // but long enough timeout for memory tests.
449 config_
.timeout
= TestTimeouts::action_timeout();
453 void TearDown() OVERRIDE
{
454 // Check that all socket data was at least written to.
455 for (size_t i
= 0; i
< socket_data_
.size(); ++i
) {
456 EXPECT_TRUE(socket_data_
[i
]->was_written()) << i
;
461 int GetNextId(int min
, int max
) {
462 EXPECT_FALSE(transaction_ids_
.empty());
463 int id
= transaction_ids_
.front();
464 transaction_ids_
.pop_front();
472 ScopedVector
<DnsSocketData
> socket_data_
;
474 std::deque
<int> transaction_ids_
;
475 scoped_ptr
<TestSocketFactory
> socket_factory_
;
476 scoped_refptr
<DnsSession
> session_
;
477 scoped_ptr
<DnsTransactionFactory
> transaction_factory_
;
480 TEST_F(DnsTransactionTest
, Lookup
) {
481 AddAsyncQueryAndResponse(0 /* id */, kT0HostName
, kT0Qtype
,
482 kT0ResponseDatagram
, arraysize(kT0ResponseDatagram
));
484 TransactionHelper
helper0(kT0HostName
, kT0Qtype
, kT0RecordCount
);
485 EXPECT_TRUE(helper0
.Run(transaction_factory_
.get()));
488 // Concurrent lookup tests assume that DnsTransaction::Start immediately
489 // consumes a socket from ClientSocketFactory.
490 TEST_F(DnsTransactionTest
, ConcurrentLookup
) {
491 AddAsyncQueryAndResponse(0 /* id */, kT0HostName
, kT0Qtype
,
492 kT0ResponseDatagram
, arraysize(kT0ResponseDatagram
));
493 AddAsyncQueryAndResponse(1 /* id */, kT1HostName
, kT1Qtype
,
494 kT1ResponseDatagram
, arraysize(kT1ResponseDatagram
));
496 TransactionHelper
helper0(kT0HostName
, kT0Qtype
, kT0RecordCount
);
497 helper0
.StartTransaction(transaction_factory_
.get());
498 TransactionHelper
helper1(kT1HostName
, kT1Qtype
, kT1RecordCount
);
499 helper1
.StartTransaction(transaction_factory_
.get());
501 MessageLoop::current()->RunUntilIdle();
503 EXPECT_TRUE(helper0
.has_completed());
504 EXPECT_TRUE(helper1
.has_completed());
507 TEST_F(DnsTransactionTest
, CancelLookup
) {
508 AddAsyncQueryAndResponse(0 /* id */, kT0HostName
, kT0Qtype
,
509 kT0ResponseDatagram
, arraysize(kT0ResponseDatagram
));
510 AddAsyncQueryAndResponse(1 /* id */, kT1HostName
, kT1Qtype
,
511 kT1ResponseDatagram
, arraysize(kT1ResponseDatagram
));
513 TransactionHelper
helper0(kT0HostName
, kT0Qtype
, kT0RecordCount
);
514 helper0
.StartTransaction(transaction_factory_
.get());
515 TransactionHelper
helper1(kT1HostName
, kT1Qtype
, kT1RecordCount
);
516 helper1
.StartTransaction(transaction_factory_
.get());
520 MessageLoop::current()->RunUntilIdle();
522 EXPECT_FALSE(helper0
.has_completed());
523 EXPECT_TRUE(helper1
.has_completed());
526 TEST_F(DnsTransactionTest
, DestroyFactory
) {
527 AddAsyncQueryAndResponse(0 /* id */, kT0HostName
, kT0Qtype
,
528 kT0ResponseDatagram
, arraysize(kT0ResponseDatagram
));
530 TransactionHelper
helper0(kT0HostName
, kT0Qtype
, kT0RecordCount
);
531 helper0
.StartTransaction(transaction_factory_
.get());
533 // Destroying the client does not affect running requests.
534 transaction_factory_
.reset(NULL
);
536 MessageLoop::current()->RunUntilIdle();
538 EXPECT_TRUE(helper0
.has_completed());
541 TEST_F(DnsTransactionTest
, CancelFromCallback
) {
542 AddAsyncQueryAndResponse(0 /* id */, kT0HostName
, kT0Qtype
,
543 kT0ResponseDatagram
, arraysize(kT0ResponseDatagram
));
545 TransactionHelper
helper0(kT0HostName
, kT0Qtype
, kT0RecordCount
);
546 helper0
.set_cancel_in_callback();
547 EXPECT_TRUE(helper0
.Run(transaction_factory_
.get()));
550 TEST_F(DnsTransactionTest
, MismatchedResponseSync
) {
551 config_
.attempts
= 2;
552 config_
.timeout
= TestTimeouts::tiny_timeout();
555 // Attempt receives mismatched response followed by valid response.
556 scoped_ptr
<DnsSocketData
> data(
557 new DnsSocketData(0 /* id */, kT0HostName
, kT0Qtype
, SYNCHRONOUS
, false));
558 data
->AddResponseData(kT1ResponseDatagram
,
559 arraysize(kT1ResponseDatagram
), SYNCHRONOUS
);
560 data
->AddResponseData(kT0ResponseDatagram
,
561 arraysize(kT0ResponseDatagram
), SYNCHRONOUS
);
562 AddSocketData(data
.Pass());
564 TransactionHelper
helper0(kT0HostName
, kT0Qtype
, kT0RecordCount
);
565 EXPECT_TRUE(helper0
.RunUntilDone(transaction_factory_
.get()));
568 TEST_F(DnsTransactionTest
, MismatchedResponseAsync
) {
569 config_
.attempts
= 2;
570 config_
.timeout
= TestTimeouts::tiny_timeout();
573 // First attempt receives mismatched response followed by valid response.
574 // Second attempt times out.
575 scoped_ptr
<DnsSocketData
> data(
576 new DnsSocketData(0 /* id */, kT0HostName
, kT0Qtype
, ASYNC
, false));
577 data
->AddResponseData(kT1ResponseDatagram
,
578 arraysize(kT1ResponseDatagram
), ASYNC
);
579 data
->AddResponseData(kT0ResponseDatagram
,
580 arraysize(kT0ResponseDatagram
), ASYNC
);
581 AddSocketData(data
.Pass());
582 AddQueryAndTimeout(kT0HostName
, kT0Qtype
);
584 TransactionHelper
helper0(kT0HostName
, kT0Qtype
, kT0RecordCount
);
585 EXPECT_TRUE(helper0
.RunUntilDone(transaction_factory_
.get()));
588 TEST_F(DnsTransactionTest
, MismatchedResponseFail
) {
589 config_
.timeout
= TestTimeouts::tiny_timeout();
592 // Attempt receives mismatched response but times out because only one attempt
594 AddAsyncQueryAndResponse(1 /* id */, kT0HostName
, kT0Qtype
,
595 kT0ResponseDatagram
, arraysize(kT0ResponseDatagram
));
597 TransactionHelper
helper0(kT0HostName
, kT0Qtype
, ERR_DNS_TIMED_OUT
);
598 EXPECT_TRUE(helper0
.RunUntilDone(transaction_factory_
.get()));
601 TEST_F(DnsTransactionTest
, ServerFail
) {
602 AddAsyncQueryAndRcode(kT0HostName
, kT0Qtype
, dns_protocol::kRcodeSERVFAIL
);
604 TransactionHelper
helper0(kT0HostName
, kT0Qtype
, ERR_DNS_SERVER_FAILED
);
605 EXPECT_TRUE(helper0
.Run(transaction_factory_
.get()));
608 TEST_F(DnsTransactionTest
, NoDomain
) {
609 AddAsyncQueryAndRcode(kT0HostName
, kT0Qtype
, dns_protocol::kRcodeNXDOMAIN
);
611 TransactionHelper
helper0(kT0HostName
, kT0Qtype
, ERR_NAME_NOT_RESOLVED
);
612 EXPECT_TRUE(helper0
.Run(transaction_factory_
.get()));
615 TEST_F(DnsTransactionTest
, Timeout
) {
616 config_
.attempts
= 3;
617 // Use short timeout to speed up the test.
618 config_
.timeout
= TestTimeouts::tiny_timeout();
621 AddQueryAndTimeout(kT0HostName
, kT0Qtype
);
622 AddQueryAndTimeout(kT0HostName
, kT0Qtype
);
623 AddQueryAndTimeout(kT0HostName
, kT0Qtype
);
625 TransactionHelper
helper0(kT0HostName
, kT0Qtype
, ERR_DNS_TIMED_OUT
);
626 EXPECT_TRUE(helper0
.RunUntilDone(transaction_factory_
.get()));
627 MessageLoop::current()->AssertIdle();
630 TEST_F(DnsTransactionTest
, ServerFallbackAndRotate
) {
631 // Test that we fallback on both server failure and timeout.
632 config_
.attempts
= 2;
633 // The next request should start from the next server.
634 config_
.rotate
= true;
635 ConfigureNumServers(3);
636 // Use short timeout to speed up the test.
637 config_
.timeout
= TestTimeouts::tiny_timeout();
640 // Responses for first request.
641 AddQueryAndTimeout(kT0HostName
, kT0Qtype
);
642 AddAsyncQueryAndRcode(kT0HostName
, kT0Qtype
, dns_protocol::kRcodeSERVFAIL
);
643 AddQueryAndTimeout(kT0HostName
, kT0Qtype
);
644 AddAsyncQueryAndRcode(kT0HostName
, kT0Qtype
, dns_protocol::kRcodeSERVFAIL
);
645 AddAsyncQueryAndRcode(kT0HostName
, kT0Qtype
, dns_protocol::kRcodeNXDOMAIN
);
646 // Responses for second request.
647 AddAsyncQueryAndRcode(kT1HostName
, kT1Qtype
, dns_protocol::kRcodeSERVFAIL
);
648 AddAsyncQueryAndRcode(kT1HostName
, kT1Qtype
, dns_protocol::kRcodeNXDOMAIN
);
650 TransactionHelper
helper0(kT0HostName
, kT0Qtype
, ERR_NAME_NOT_RESOLVED
);
651 TransactionHelper
helper1(kT1HostName
, kT1Qtype
, ERR_NAME_NOT_RESOLVED
);
653 EXPECT_TRUE(helper0
.RunUntilDone(transaction_factory_
.get()));
654 EXPECT_TRUE(helper1
.Run(transaction_factory_
.get()));
656 unsigned kOrder
[] = {
657 0, 1, 2, 0, 1, // The first transaction.
658 1, 2, // The second transaction starts from the next server.
660 CheckServerOrder(kOrder
, arraysize(kOrder
));
663 TEST_F(DnsTransactionTest
, SuffixSearchAboveNdots
) {
665 config_
.search
.push_back("a");
666 config_
.search
.push_back("b");
667 config_
.search
.push_back("c");
668 config_
.rotate
= true;
669 ConfigureNumServers(2);
672 AddAsyncQueryAndRcode("x.y.z", dns_protocol::kTypeA
,
673 dns_protocol::kRcodeNXDOMAIN
);
674 AddAsyncQueryAndRcode("x.y.z.a", dns_protocol::kTypeA
,
675 dns_protocol::kRcodeNXDOMAIN
);
676 AddAsyncQueryAndRcode("x.y.z.b", dns_protocol::kTypeA
,
677 dns_protocol::kRcodeNXDOMAIN
);
678 AddAsyncQueryAndRcode("x.y.z.c", dns_protocol::kTypeA
,
679 dns_protocol::kRcodeNXDOMAIN
);
681 TransactionHelper
helper0("x.y.z", dns_protocol::kTypeA
,
682 ERR_NAME_NOT_RESOLVED
);
684 EXPECT_TRUE(helper0
.Run(transaction_factory_
.get()));
686 // Also check if suffix search causes server rotation.
687 unsigned kOrder0
[] = { 0, 1, 0, 1 };
688 CheckServerOrder(kOrder0
, arraysize(kOrder0
));
691 TEST_F(DnsTransactionTest
, SuffixSearchBelowNdots
) {
693 config_
.search
.push_back("a");
694 config_
.search
.push_back("b");
695 config_
.search
.push_back("c");
698 // Responses for first transaction.
699 AddAsyncQueryAndRcode("x.y.a", dns_protocol::kTypeA
,
700 dns_protocol::kRcodeNXDOMAIN
);
701 AddAsyncQueryAndRcode("x.y.b", dns_protocol::kTypeA
,
702 dns_protocol::kRcodeNXDOMAIN
);
703 AddAsyncQueryAndRcode("x.y.c", dns_protocol::kTypeA
,
704 dns_protocol::kRcodeNXDOMAIN
);
705 AddAsyncQueryAndRcode("x.y", dns_protocol::kTypeA
,
706 dns_protocol::kRcodeNXDOMAIN
);
707 // Responses for second transaction.
708 AddAsyncQueryAndRcode("x.a", dns_protocol::kTypeA
,
709 dns_protocol::kRcodeNXDOMAIN
);
710 AddAsyncQueryAndRcode("x.b", dns_protocol::kTypeA
,
711 dns_protocol::kRcodeNXDOMAIN
);
712 AddAsyncQueryAndRcode("x.c", dns_protocol::kTypeA
,
713 dns_protocol::kRcodeNXDOMAIN
);
714 // Responses for third transaction.
715 AddAsyncQueryAndRcode("x", dns_protocol::kTypeAAAA
,
716 dns_protocol::kRcodeNXDOMAIN
);
718 TransactionHelper
helper0("x.y", dns_protocol::kTypeA
, ERR_NAME_NOT_RESOLVED
);
720 EXPECT_TRUE(helper0
.Run(transaction_factory_
.get()));
722 // A single-label name.
723 TransactionHelper
helper1("x", dns_protocol::kTypeA
, ERR_NAME_NOT_RESOLVED
);
725 EXPECT_TRUE(helper1
.Run(transaction_factory_
.get()));
727 // A fully-qualified name.
728 TransactionHelper
helper2("x.", dns_protocol::kTypeAAAA
,
729 ERR_NAME_NOT_RESOLVED
);
731 EXPECT_TRUE(helper2
.Run(transaction_factory_
.get()));
734 TEST_F(DnsTransactionTest
, EmptySuffixSearch
) {
735 // Responses for first transaction.
736 AddAsyncQueryAndRcode("x", dns_protocol::kTypeA
,
737 dns_protocol::kRcodeNXDOMAIN
);
739 // A fully-qualified name.
740 TransactionHelper
helper0("x.", dns_protocol::kTypeA
, ERR_NAME_NOT_RESOLVED
);
742 EXPECT_TRUE(helper0
.Run(transaction_factory_
.get()));
744 // A single label name is not even attempted.
745 TransactionHelper
helper1("singlelabel", dns_protocol::kTypeA
,
746 ERR_DNS_SEARCH_EMPTY
);
748 helper1
.StartTransaction(transaction_factory_
.get());
749 EXPECT_TRUE(helper1
.has_completed());
752 TEST_F(DnsTransactionTest
, DontAppendToMultiLabelName
) {
753 config_
.search
.push_back("a");
754 config_
.search
.push_back("b");
755 config_
.search
.push_back("c");
756 config_
.append_to_multi_label_name
= false;
759 // Responses for first transaction.
760 AddAsyncQueryAndRcode("x.y.z", dns_protocol::kTypeA
,
761 dns_protocol::kRcodeNXDOMAIN
);
762 // Responses for second transaction.
763 AddAsyncQueryAndRcode("x.y", dns_protocol::kTypeA
,
764 dns_protocol::kRcodeNXDOMAIN
);
765 // Responses for third transaction.
766 AddAsyncQueryAndRcode("x.a", dns_protocol::kTypeA
,
767 dns_protocol::kRcodeNXDOMAIN
);
768 AddAsyncQueryAndRcode("x.b", dns_protocol::kTypeA
,
769 dns_protocol::kRcodeNXDOMAIN
);
770 AddAsyncQueryAndRcode("x.c", dns_protocol::kTypeA
,
771 dns_protocol::kRcodeNXDOMAIN
);
773 TransactionHelper
helper0("x.y.z", dns_protocol::kTypeA
,
774 ERR_NAME_NOT_RESOLVED
);
775 EXPECT_TRUE(helper0
.Run(transaction_factory_
.get()));
777 TransactionHelper
helper1("x.y", dns_protocol::kTypeA
, ERR_NAME_NOT_RESOLVED
);
778 EXPECT_TRUE(helper1
.Run(transaction_factory_
.get()));
780 TransactionHelper
helper2("x", dns_protocol::kTypeA
, ERR_NAME_NOT_RESOLVED
);
781 EXPECT_TRUE(helper2
.Run(transaction_factory_
.get()));
784 const uint8 kResponseNoData
[] = {
785 0x00, 0x00, 0x81, 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
787 0x01, 'x', 0x01, 'y', 0x01, 'z', 0x01, 'b', 0x00, 0x00, 0x01, 0x00, 0x01,
788 // Authority section, SOA record, TTL 0x3E6
789 0x01, 'z', 0x00, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x03, 0xE6,
790 // Minimal RDATA, 18 bytes
793 0x00, 0x00, 0x00, 0x00,
794 0x00, 0x00, 0x00, 0x00,
795 0x00, 0x00, 0x00, 0x00,
796 0x00, 0x00, 0x00, 0x00,
799 TEST_F(DnsTransactionTest
, SuffixSearchStop
) {
801 config_
.search
.push_back("a");
802 config_
.search
.push_back("b");
803 config_
.search
.push_back("c");
806 AddAsyncQueryAndRcode("x.y.z", dns_protocol::kTypeA
,
807 dns_protocol::kRcodeNXDOMAIN
);
808 AddAsyncQueryAndRcode("x.y.z.a", dns_protocol::kTypeA
,
809 dns_protocol::kRcodeNXDOMAIN
);
810 AddAsyncQueryAndResponse(0 /* id */, "x.y.z.b", dns_protocol::kTypeA
,
811 kResponseNoData
, arraysize(kResponseNoData
));
813 TransactionHelper
helper0("x.y.z", dns_protocol::kTypeA
, 0 /* answers */);
815 EXPECT_TRUE(helper0
.Run(transaction_factory_
.get()));
818 TEST_F(DnsTransactionTest
, SyncFirstQuery
) {
819 config_
.search
.push_back("lab.ccs.neu.edu");
820 config_
.search
.push_back("ccs.neu.edu");
823 AddSyncQueryAndResponse(0 /* id */, kT0HostName
, kT0Qtype
,
824 kT0ResponseDatagram
, arraysize(kT0ResponseDatagram
));
826 TransactionHelper
helper0(kT0HostName
, kT0Qtype
, kT0RecordCount
);
827 EXPECT_TRUE(helper0
.Run(transaction_factory_
.get()));
830 TEST_F(DnsTransactionTest
, SyncFirstQueryWithSearch
) {
831 config_
.search
.push_back("lab.ccs.neu.edu");
832 config_
.search
.push_back("ccs.neu.edu");
835 AddSyncQueryAndRcode("www.lab.ccs.neu.edu", kT2Qtype
,
836 dns_protocol::kRcodeNXDOMAIN
);
838 AddAsyncQueryAndResponse(2 /* id */, kT2HostName
, kT2Qtype
,
839 kT2ResponseDatagram
, arraysize(kT2ResponseDatagram
));
841 TransactionHelper
helper0("www", kT2Qtype
, kT2RecordCount
);
842 EXPECT_TRUE(helper0
.Run(transaction_factory_
.get()));
845 TEST_F(DnsTransactionTest
, SyncSearchQuery
) {
846 config_
.search
.push_back("lab.ccs.neu.edu");
847 config_
.search
.push_back("ccs.neu.edu");
850 AddAsyncQueryAndRcode("www.lab.ccs.neu.edu", dns_protocol::kTypeA
,
851 dns_protocol::kRcodeNXDOMAIN
);
852 AddSyncQueryAndResponse(2 /* id */, kT2HostName
, kT2Qtype
,
853 kT2ResponseDatagram
, arraysize(kT2ResponseDatagram
));
855 TransactionHelper
helper0("www", kT2Qtype
, kT2RecordCount
);
856 EXPECT_TRUE(helper0
.Run(transaction_factory_
.get()));
859 TEST_F(DnsTransactionTest
, ConnectFailure
) {
860 socket_factory_
->create_failing_sockets_
= true;
861 transaction_ids_
.push_back(0); // Needed to make a DnsUDPAttempt.
862 TransactionHelper
helper0("www.chromium.org", dns_protocol::kTypeA
,
863 ERR_CONNECTION_REFUSED
);
864 EXPECT_TRUE(helper0
.Run(transaction_factory_
.get()));
867 TEST_F(DnsTransactionTest
, TCPLookup
) {
868 AddAsyncQueryAndRcode(kT0HostName
, kT0Qtype
,
869 dns_protocol::kRcodeNOERROR
| dns_protocol::kFlagTC
);
870 AddQueryAndResponse(0 /* id */, kT0HostName
, kT0Qtype
,
871 kT0ResponseDatagram
, arraysize(kT0ResponseDatagram
),
872 ASYNC
, true /* use_tcp */);
874 TransactionHelper
helper0(kT0HostName
, kT0Qtype
, kT0RecordCount
);
875 EXPECT_TRUE(helper0
.Run(transaction_factory_
.get()));
878 TEST_F(DnsTransactionTest
, TCPFailure
) {
879 AddAsyncQueryAndRcode(kT0HostName
, kT0Qtype
,
880 dns_protocol::kRcodeNOERROR
| dns_protocol::kFlagTC
);
881 AddQueryAndRcode(kT0HostName
, kT0Qtype
, dns_protocol::kRcodeSERVFAIL
,
882 ASYNC
, true /* use_tcp */);
884 TransactionHelper
helper0(kT0HostName
, kT0Qtype
, ERR_DNS_SERVER_FAILED
);
885 EXPECT_TRUE(helper0
.Run(transaction_factory_
.get()));
888 TEST_F(DnsTransactionTest
, TCPMalformed
) {
889 AddAsyncQueryAndRcode(kT0HostName
, kT0Qtype
,
890 dns_protocol::kRcodeNOERROR
| dns_protocol::kFlagTC
);
891 scoped_ptr
<DnsSocketData
> data(
892 new DnsSocketData(0 /* id */, kT0HostName
, kT0Qtype
, ASYNC
, true));
893 // Valid response but length too short.
894 data
->AddResponseWithLength(
896 new DnsResponse(reinterpret_cast<const char*>(kT0ResponseDatagram
),
897 arraysize(kT0ResponseDatagram
), 0)),
899 static_cast<uint16
>(kT0QuerySize
- 1));
900 AddSocketData(data
.Pass());
902 TransactionHelper
helper0(kT0HostName
, kT0Qtype
, ERR_DNS_MALFORMED_RESPONSE
);
903 EXPECT_TRUE(helper0
.Run(transaction_factory_
.get()));
906 TEST_F(DnsTransactionTest
, TCPTimeout
) {
907 config_
.timeout
= TestTimeouts::tiny_timeout();
909 AddAsyncQueryAndRcode(kT0HostName
, kT0Qtype
,
910 dns_protocol::kRcodeNOERROR
| dns_protocol::kFlagTC
);
911 AddSocketData(make_scoped_ptr(
912 new DnsSocketData(1 /* id */, kT0HostName
, kT0Qtype
, ASYNC
, true)));
914 TransactionHelper
helper0(kT0HostName
, kT0Qtype
, ERR_DNS_TIMED_OUT
);
915 EXPECT_TRUE(helper0
.RunUntilDone(transaction_factory_
.get()));