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 // Build, if needed, and return the SocketDataProvider. No new responses
104 // should be added afterwards.
105 SocketDataProvider
* GetProvider() {
107 return provider_
.get();
108 // Terminate the reads with ERR_IO_PENDING to prevent overrun and default to
110 reads_
.push_back(MockRead(ASYNC
, ERR_IO_PENDING
));
111 provider_
.reset(new DelayedSocketData(1, &reads_
[0], reads_
.size(),
112 &writes_
[0], writes_
.size()));
114 provider_
->set_connect_data(MockConnect(reads_
[0].mode
, OK
));
116 return provider_
.get();
119 uint16
query_id() const {
123 // Returns true if the expected query was written to the socket.
124 bool was_written() const {
125 CHECK(provider_
.get());
126 return provider_
->write_index() > 0;
130 scoped_ptr
<DnsQuery
> query_
;
132 ScopedVector
<uint16
> lengths_
;
133 ScopedVector
<DnsResponse
> responses_
;
134 std::vector
<MockWrite
> writes_
;
135 std::vector
<MockRead
> reads_
;
136 scoped_ptr
<DelayedSocketData
> provider_
;
138 DISALLOW_COPY_AND_ASSIGN(DnsSocketData
);
141 class TestSocketFactory
;
143 // A variant of MockUDPClientSocket which always fails to Connect.
144 class FailingUDPClientSocket
: public MockUDPClientSocket
{
146 FailingUDPClientSocket(SocketDataProvider
* data
,
147 net::NetLog
* net_log
)
148 : MockUDPClientSocket(data
, net_log
) {
150 virtual ~FailingUDPClientSocket() {}
151 virtual int Connect(const IPEndPoint
& endpoint
) OVERRIDE
{
152 return ERR_CONNECTION_REFUSED
;
156 DISALLOW_COPY_AND_ASSIGN(FailingUDPClientSocket
);
159 // A variant of MockUDPClientSocket which notifies the factory OnConnect.
160 class TestUDPClientSocket
: public MockUDPClientSocket
{
162 TestUDPClientSocket(TestSocketFactory
* factory
,
163 SocketDataProvider
* data
,
164 net::NetLog
* net_log
)
165 : MockUDPClientSocket(data
, net_log
), factory_(factory
) {
167 virtual ~TestUDPClientSocket() {}
168 virtual int Connect(const IPEndPoint
& endpoint
) OVERRIDE
;
171 TestSocketFactory
* factory_
;
173 DISALLOW_COPY_AND_ASSIGN(TestUDPClientSocket
);
176 // Creates TestUDPClientSockets and keeps endpoints reported via OnConnect.
177 class TestSocketFactory
: public MockClientSocketFactory
{
179 TestSocketFactory() : fail_next_socket_(false) {}
180 virtual ~TestSocketFactory() {}
182 virtual scoped_ptr
<DatagramClientSocket
> CreateDatagramClientSocket(
183 DatagramSocket::BindType bind_type
,
184 const RandIntCallback
& rand_int_cb
,
185 net::NetLog
* net_log
,
186 const net::NetLog::Source
& source
) OVERRIDE
{
187 if (fail_next_socket_
) {
188 fail_next_socket_
= false;
189 return scoped_ptr
<DatagramClientSocket
>(
190 new FailingUDPClientSocket(&empty_data_
, net_log
));
192 SocketDataProvider
* data_provider
= mock_data().GetNext();
193 scoped_ptr
<TestUDPClientSocket
> socket(
194 new TestUDPClientSocket(this, data_provider
, net_log
));
195 data_provider
->set_socket(socket
.get());
196 return socket
.PassAs
<DatagramClientSocket
>();
199 void OnConnect(const IPEndPoint
& endpoint
) {
200 remote_endpoints_
.push_back(endpoint
);
203 std::vector
<IPEndPoint
> remote_endpoints_
;
204 bool fail_next_socket_
;
207 StaticSocketDataProvider empty_data_
;
209 DISALLOW_COPY_AND_ASSIGN(TestSocketFactory
);
212 int TestUDPClientSocket::Connect(const IPEndPoint
& endpoint
) {
213 factory_
->OnConnect(endpoint
);
214 return MockUDPClientSocket::Connect(endpoint
);
217 // Helper class that holds a DnsTransaction and handles OnTransactionComplete.
218 class TransactionHelper
{
220 // If |expected_answer_count| < 0 then it is the expected net error.
221 TransactionHelper(const char* hostname
,
223 int expected_answer_count
)
224 : hostname_(hostname
),
226 expected_answer_count_(expected_answer_count
),
227 cancel_in_callback_(false),
228 quit_in_callback_(false),
232 // Mark that the transaction shall be destroyed immediately upon callback.
233 void set_cancel_in_callback() {
234 cancel_in_callback_
= true;
237 // Mark to call MessageLoop::Quit() upon callback.
238 void set_quit_in_callback() {
239 quit_in_callback_
= true;
242 void StartTransaction(DnsTransactionFactory
* factory
) {
243 EXPECT_EQ(NULL
, transaction_
.get());
244 transaction_
= factory
->CreateTransaction(
247 base::Bind(&TransactionHelper::OnTransactionComplete
,
248 base::Unretained(this)),
250 EXPECT_EQ(hostname_
, transaction_
->GetHostname());
251 EXPECT_EQ(qtype_
, transaction_
->GetType());
252 transaction_
->Start();
256 ASSERT_TRUE(transaction_
.get() != NULL
);
257 transaction_
.reset(NULL
);
260 void OnTransactionComplete(DnsTransaction
* t
,
262 const DnsResponse
* response
) {
263 EXPECT_FALSE(completed_
);
264 EXPECT_EQ(transaction_
.get(), t
);
268 if (cancel_in_callback_
) {
273 // Tell MessageLoop to quit now, in case any ASSERT_* fails.
274 if (quit_in_callback_
)
275 base::MessageLoop::current()->Quit();
277 if (expected_answer_count_
>= 0) {
279 ASSERT_TRUE(response
!= NULL
);
280 EXPECT_EQ(static_cast<unsigned>(expected_answer_count_
),
281 response
->answer_count());
282 EXPECT_EQ(qtype_
, response
->qtype());
284 DnsRecordParser parser
= response
->Parser();
285 DnsResourceRecord record
;
286 for (int i
= 0; i
< expected_answer_count_
; ++i
) {
287 EXPECT_TRUE(parser
.ReadRecord(&record
));
290 EXPECT_EQ(expected_answer_count_
, rv
);
294 bool has_completed() const {
298 // Shorthands for commonly used commands.
300 bool Run(DnsTransactionFactory
* factory
) {
301 StartTransaction(factory
);
302 base::MessageLoop::current()->RunUntilIdle();
303 return has_completed();
306 // Use when some of the responses are timeouts.
307 bool RunUntilDone(DnsTransactionFactory
* factory
) {
308 set_quit_in_callback();
309 StartTransaction(factory
);
310 base::MessageLoop::current()->Run();
311 return has_completed();
315 std::string hostname_
;
317 scoped_ptr
<DnsTransaction
> transaction_
;
318 int expected_answer_count_
;
319 bool cancel_in_callback_
;
320 bool quit_in_callback_
;
325 class DnsTransactionTest
: public testing::Test
{
327 DnsTransactionTest() {}
329 // Generates |nameservers| for DnsConfig.
330 void ConfigureNumServers(unsigned num_servers
) {
331 CHECK_LE(num_servers
, 255u);
332 config_
.nameservers
.clear();
333 IPAddressNumber dns_ip
;
335 bool rv
= ParseIPLiteralToNumber("192.168.1.0", &dns_ip
);
338 for (unsigned i
= 0; i
< num_servers
; ++i
) {
340 config_
.nameservers
.push_back(IPEndPoint(dns_ip
,
341 dns_protocol::kDefaultPort
));
345 // Called after fully configuring |config|.
346 void ConfigureFactory() {
347 socket_factory_
.reset(new TestSocketFactory());
348 session_
= new DnsSession(
350 DnsSocketPool::CreateNull(socket_factory_
.get()),
351 base::Bind(&DnsTransactionTest::GetNextId
, base::Unretained(this)),
353 transaction_factory_
= DnsTransactionFactory::CreateFactory(session_
.get());
356 void AddSocketData(scoped_ptr
<DnsSocketData
> data
) {
357 CHECK(socket_factory_
.get());
358 transaction_ids_
.push_back(data
->query_id());
359 socket_factory_
->AddSocketDataProvider(data
->GetProvider());
360 socket_data_
.push_back(data
.release());
363 // Add expected query for |dotted_name| and |qtype| with |id| and response
364 // taken verbatim from |data| of |data_length| bytes. The transaction id in
365 // |data| should equal |id|, unless testing mismatched response.
366 void AddQueryAndResponse(uint16 id
,
367 const char* dotted_name
,
369 const uint8
* response_data
,
370 size_t response_length
,
373 CHECK(socket_factory_
.get());
374 scoped_ptr
<DnsSocketData
> data(
375 new DnsSocketData(id
, dotted_name
, qtype
, mode
, use_tcp
));
376 data
->AddResponseData(response_data
, response_length
, mode
);
377 AddSocketData(data
.Pass());
380 void AddAsyncQueryAndResponse(uint16 id
,
381 const char* dotted_name
,
384 size_t data_length
) {
385 AddQueryAndResponse(id
, dotted_name
, qtype
, data
, data_length
, ASYNC
,
389 void AddSyncQueryAndResponse(uint16 id
,
390 const char* dotted_name
,
393 size_t data_length
) {
394 AddQueryAndResponse(id
, dotted_name
, qtype
, data
, data_length
, SYNCHRONOUS
,
398 // Add expected query of |dotted_name| and |qtype| and no response.
399 void AddQueryAndTimeout(const char* dotted_name
, uint16 qtype
) {
400 uint16 id
= base::RandInt(0, kuint16max
);
401 scoped_ptr
<DnsSocketData
> data(
402 new DnsSocketData(id
, dotted_name
, qtype
, ASYNC
, false));
403 AddSocketData(data
.Pass());
406 // Add expected query of |dotted_name| and |qtype| and matching response with
407 // no answer and RCODE set to |rcode|. The id will be generated randomly.
408 void AddQueryAndRcode(const char* dotted_name
,
413 CHECK_NE(dns_protocol::kRcodeNOERROR
, rcode
);
414 uint16 id
= base::RandInt(0, kuint16max
);
415 scoped_ptr
<DnsSocketData
> data(
416 new DnsSocketData(id
, dotted_name
, qtype
, mode
, use_tcp
));
417 data
->AddRcode(rcode
, mode
);
418 AddSocketData(data
.Pass());
421 void AddAsyncQueryAndRcode(const char* dotted_name
, uint16 qtype
, int rcode
) {
422 AddQueryAndRcode(dotted_name
, qtype
, rcode
, ASYNC
, false);
425 void AddSyncQueryAndRcode(const char* dotted_name
, uint16 qtype
, int rcode
) {
426 AddQueryAndRcode(dotted_name
, qtype
, rcode
, SYNCHRONOUS
, false);
429 // Checks if the sockets were connected in the order matching the indices in
431 void CheckServerOrder(const unsigned* servers
, size_t num_attempts
) {
432 ASSERT_EQ(num_attempts
, socket_factory_
->remote_endpoints_
.size());
433 for (size_t i
= 0; i
< num_attempts
; ++i
) {
434 EXPECT_EQ(socket_factory_
->remote_endpoints_
[i
],
435 session_
->config().nameservers
[servers
[i
]]);
439 virtual void SetUp() OVERRIDE
{
440 // By default set one server,
441 ConfigureNumServers(1);
442 // and no retransmissions,
443 config_
.attempts
= 1;
444 // but long enough timeout for memory tests.
445 config_
.timeout
= TestTimeouts::action_timeout();
449 virtual void TearDown() OVERRIDE
{
450 // Check that all socket data was at least written to.
451 for (size_t i
= 0; i
< socket_data_
.size(); ++i
) {
452 EXPECT_TRUE(socket_data_
[i
]->was_written()) << i
;
457 int GetNextId(int min
, int max
) {
458 EXPECT_FALSE(transaction_ids_
.empty());
459 int id
= transaction_ids_
.front();
460 transaction_ids_
.pop_front();
468 ScopedVector
<DnsSocketData
> socket_data_
;
470 std::deque
<int> transaction_ids_
;
471 scoped_ptr
<TestSocketFactory
> socket_factory_
;
472 scoped_refptr
<DnsSession
> session_
;
473 scoped_ptr
<DnsTransactionFactory
> transaction_factory_
;
476 TEST_F(DnsTransactionTest
, Lookup
) {
477 AddAsyncQueryAndResponse(0 /* id */, kT0HostName
, kT0Qtype
,
478 kT0ResponseDatagram
, arraysize(kT0ResponseDatagram
));
480 TransactionHelper
helper0(kT0HostName
, kT0Qtype
, kT0RecordCount
);
481 EXPECT_TRUE(helper0
.Run(transaction_factory_
.get()));
484 // Concurrent lookup tests assume that DnsTransaction::Start immediately
485 // consumes a socket from ClientSocketFactory.
486 TEST_F(DnsTransactionTest
, ConcurrentLookup
) {
487 AddAsyncQueryAndResponse(0 /* id */, kT0HostName
, kT0Qtype
,
488 kT0ResponseDatagram
, arraysize(kT0ResponseDatagram
));
489 AddAsyncQueryAndResponse(1 /* id */, kT1HostName
, kT1Qtype
,
490 kT1ResponseDatagram
, arraysize(kT1ResponseDatagram
));
492 TransactionHelper
helper0(kT0HostName
, kT0Qtype
, kT0RecordCount
);
493 helper0
.StartTransaction(transaction_factory_
.get());
494 TransactionHelper
helper1(kT1HostName
, kT1Qtype
, kT1RecordCount
);
495 helper1
.StartTransaction(transaction_factory_
.get());
497 base::MessageLoop::current()->RunUntilIdle();
499 EXPECT_TRUE(helper0
.has_completed());
500 EXPECT_TRUE(helper1
.has_completed());
503 TEST_F(DnsTransactionTest
, CancelLookup
) {
504 AddAsyncQueryAndResponse(0 /* id */, kT0HostName
, kT0Qtype
,
505 kT0ResponseDatagram
, arraysize(kT0ResponseDatagram
));
506 AddAsyncQueryAndResponse(1 /* id */, kT1HostName
, kT1Qtype
,
507 kT1ResponseDatagram
, arraysize(kT1ResponseDatagram
));
509 TransactionHelper
helper0(kT0HostName
, kT0Qtype
, kT0RecordCount
);
510 helper0
.StartTransaction(transaction_factory_
.get());
511 TransactionHelper
helper1(kT1HostName
, kT1Qtype
, kT1RecordCount
);
512 helper1
.StartTransaction(transaction_factory_
.get());
516 base::MessageLoop::current()->RunUntilIdle();
518 EXPECT_FALSE(helper0
.has_completed());
519 EXPECT_TRUE(helper1
.has_completed());
522 TEST_F(DnsTransactionTest
, DestroyFactory
) {
523 AddAsyncQueryAndResponse(0 /* id */, kT0HostName
, kT0Qtype
,
524 kT0ResponseDatagram
, arraysize(kT0ResponseDatagram
));
526 TransactionHelper
helper0(kT0HostName
, kT0Qtype
, kT0RecordCount
);
527 helper0
.StartTransaction(transaction_factory_
.get());
529 // Destroying the client does not affect running requests.
530 transaction_factory_
.reset(NULL
);
532 base::MessageLoop::current()->RunUntilIdle();
534 EXPECT_TRUE(helper0
.has_completed());
537 TEST_F(DnsTransactionTest
, CancelFromCallback
) {
538 AddAsyncQueryAndResponse(0 /* id */, kT0HostName
, kT0Qtype
,
539 kT0ResponseDatagram
, arraysize(kT0ResponseDatagram
));
541 TransactionHelper
helper0(kT0HostName
, kT0Qtype
, kT0RecordCount
);
542 helper0
.set_cancel_in_callback();
543 EXPECT_TRUE(helper0
.Run(transaction_factory_
.get()));
546 TEST_F(DnsTransactionTest
, MismatchedResponseSync
) {
547 config_
.attempts
= 2;
548 config_
.timeout
= TestTimeouts::tiny_timeout();
551 // Attempt receives mismatched response followed by valid response.
552 scoped_ptr
<DnsSocketData
> data(
553 new DnsSocketData(0 /* id */, kT0HostName
, kT0Qtype
, SYNCHRONOUS
, false));
554 data
->AddResponseData(kT1ResponseDatagram
,
555 arraysize(kT1ResponseDatagram
), SYNCHRONOUS
);
556 data
->AddResponseData(kT0ResponseDatagram
,
557 arraysize(kT0ResponseDatagram
), SYNCHRONOUS
);
558 AddSocketData(data
.Pass());
560 TransactionHelper
helper0(kT0HostName
, kT0Qtype
, kT0RecordCount
);
561 EXPECT_TRUE(helper0
.RunUntilDone(transaction_factory_
.get()));
564 TEST_F(DnsTransactionTest
, MismatchedResponseAsync
) {
565 config_
.attempts
= 2;
566 config_
.timeout
= TestTimeouts::tiny_timeout();
569 // First attempt receives mismatched response followed by valid response.
570 // Second attempt times out.
571 scoped_ptr
<DnsSocketData
> data(
572 new DnsSocketData(0 /* id */, kT0HostName
, kT0Qtype
, ASYNC
, false));
573 data
->AddResponseData(kT1ResponseDatagram
,
574 arraysize(kT1ResponseDatagram
), ASYNC
);
575 data
->AddResponseData(kT0ResponseDatagram
,
576 arraysize(kT0ResponseDatagram
), ASYNC
);
577 AddSocketData(data
.Pass());
578 AddQueryAndTimeout(kT0HostName
, kT0Qtype
);
580 TransactionHelper
helper0(kT0HostName
, kT0Qtype
, kT0RecordCount
);
581 EXPECT_TRUE(helper0
.RunUntilDone(transaction_factory_
.get()));
584 TEST_F(DnsTransactionTest
, MismatchedResponseFail
) {
585 config_
.timeout
= TestTimeouts::tiny_timeout();
588 // Attempt receives mismatched response but times out because only one attempt
590 AddAsyncQueryAndResponse(1 /* id */, kT0HostName
, kT0Qtype
,
591 kT0ResponseDatagram
, arraysize(kT0ResponseDatagram
));
593 TransactionHelper
helper0(kT0HostName
, kT0Qtype
, ERR_DNS_TIMED_OUT
);
594 EXPECT_TRUE(helper0
.RunUntilDone(transaction_factory_
.get()));
597 TEST_F(DnsTransactionTest
, ServerFail
) {
598 AddAsyncQueryAndRcode(kT0HostName
, kT0Qtype
, dns_protocol::kRcodeSERVFAIL
);
600 TransactionHelper
helper0(kT0HostName
, kT0Qtype
, ERR_DNS_SERVER_FAILED
);
601 EXPECT_TRUE(helper0
.Run(transaction_factory_
.get()));
604 TEST_F(DnsTransactionTest
, NoDomain
) {
605 AddAsyncQueryAndRcode(kT0HostName
, kT0Qtype
, dns_protocol::kRcodeNXDOMAIN
);
607 TransactionHelper
helper0(kT0HostName
, kT0Qtype
, ERR_NAME_NOT_RESOLVED
);
608 EXPECT_TRUE(helper0
.Run(transaction_factory_
.get()));
611 TEST_F(DnsTransactionTest
, Timeout
) {
612 config_
.attempts
= 3;
613 // Use short timeout to speed up the test.
614 config_
.timeout
= TestTimeouts::tiny_timeout();
617 AddQueryAndTimeout(kT0HostName
, kT0Qtype
);
618 AddQueryAndTimeout(kT0HostName
, kT0Qtype
);
619 AddQueryAndTimeout(kT0HostName
, kT0Qtype
);
621 TransactionHelper
helper0(kT0HostName
, kT0Qtype
, ERR_DNS_TIMED_OUT
);
622 EXPECT_TRUE(helper0
.RunUntilDone(transaction_factory_
.get()));
623 EXPECT_TRUE(base::MessageLoop::current()->IsIdleForTesting());
626 TEST_F(DnsTransactionTest
, ServerFallbackAndRotate
) {
627 // Test that we fallback on both server failure and timeout.
628 config_
.attempts
= 2;
629 // The next request should start from the next server.
630 config_
.rotate
= true;
631 ConfigureNumServers(3);
632 // Use short timeout to speed up the test.
633 config_
.timeout
= TestTimeouts::tiny_timeout();
636 // Responses for first request.
637 AddQueryAndTimeout(kT0HostName
, kT0Qtype
);
638 AddAsyncQueryAndRcode(kT0HostName
, kT0Qtype
, dns_protocol::kRcodeSERVFAIL
);
639 AddQueryAndTimeout(kT0HostName
, kT0Qtype
);
640 AddAsyncQueryAndRcode(kT0HostName
, kT0Qtype
, dns_protocol::kRcodeSERVFAIL
);
641 AddAsyncQueryAndRcode(kT0HostName
, kT0Qtype
, dns_protocol::kRcodeNXDOMAIN
);
642 // Responses for second request.
643 AddAsyncQueryAndRcode(kT1HostName
, kT1Qtype
, dns_protocol::kRcodeSERVFAIL
);
644 AddAsyncQueryAndRcode(kT1HostName
, kT1Qtype
, dns_protocol::kRcodeSERVFAIL
);
645 AddAsyncQueryAndRcode(kT1HostName
, kT1Qtype
, dns_protocol::kRcodeNXDOMAIN
);
647 TransactionHelper
helper0(kT0HostName
, kT0Qtype
, ERR_NAME_NOT_RESOLVED
);
648 TransactionHelper
helper1(kT1HostName
, kT1Qtype
, ERR_NAME_NOT_RESOLVED
);
650 EXPECT_TRUE(helper0
.RunUntilDone(transaction_factory_
.get()));
651 EXPECT_TRUE(helper1
.Run(transaction_factory_
.get()));
653 unsigned kOrder
[] = {
654 0, 1, 2, 0, 1, // The first transaction.
655 1, 2, 0, // The second transaction starts from the next server.
657 CheckServerOrder(kOrder
, arraysize(kOrder
));
660 TEST_F(DnsTransactionTest
, SuffixSearchAboveNdots
) {
662 config_
.search
.push_back("a");
663 config_
.search
.push_back("b");
664 config_
.search
.push_back("c");
665 config_
.rotate
= true;
666 ConfigureNumServers(2);
669 AddAsyncQueryAndRcode("x.y.z", dns_protocol::kTypeA
,
670 dns_protocol::kRcodeNXDOMAIN
);
671 AddAsyncQueryAndRcode("x.y.z.a", dns_protocol::kTypeA
,
672 dns_protocol::kRcodeNXDOMAIN
);
673 AddAsyncQueryAndRcode("x.y.z.b", dns_protocol::kTypeA
,
674 dns_protocol::kRcodeNXDOMAIN
);
675 AddAsyncQueryAndRcode("x.y.z.c", dns_protocol::kTypeA
,
676 dns_protocol::kRcodeNXDOMAIN
);
678 TransactionHelper
helper0("x.y.z", dns_protocol::kTypeA
,
679 ERR_NAME_NOT_RESOLVED
);
681 EXPECT_TRUE(helper0
.Run(transaction_factory_
.get()));
683 // Also check if suffix search causes server rotation.
684 unsigned kOrder0
[] = { 0, 1, 0, 1 };
685 CheckServerOrder(kOrder0
, arraysize(kOrder0
));
688 TEST_F(DnsTransactionTest
, SuffixSearchBelowNdots
) {
690 config_
.search
.push_back("a");
691 config_
.search
.push_back("b");
692 config_
.search
.push_back("c");
695 // Responses for first transaction.
696 AddAsyncQueryAndRcode("x.y.a", dns_protocol::kTypeA
,
697 dns_protocol::kRcodeNXDOMAIN
);
698 AddAsyncQueryAndRcode("x.y.b", dns_protocol::kTypeA
,
699 dns_protocol::kRcodeNXDOMAIN
);
700 AddAsyncQueryAndRcode("x.y.c", dns_protocol::kTypeA
,
701 dns_protocol::kRcodeNXDOMAIN
);
702 AddAsyncQueryAndRcode("x.y", dns_protocol::kTypeA
,
703 dns_protocol::kRcodeNXDOMAIN
);
704 // Responses for second transaction.
705 AddAsyncQueryAndRcode("x.a", dns_protocol::kTypeA
,
706 dns_protocol::kRcodeNXDOMAIN
);
707 AddAsyncQueryAndRcode("x.b", dns_protocol::kTypeA
,
708 dns_protocol::kRcodeNXDOMAIN
);
709 AddAsyncQueryAndRcode("x.c", dns_protocol::kTypeA
,
710 dns_protocol::kRcodeNXDOMAIN
);
711 // Responses for third transaction.
712 AddAsyncQueryAndRcode("x", dns_protocol::kTypeAAAA
,
713 dns_protocol::kRcodeNXDOMAIN
);
715 TransactionHelper
helper0("x.y", dns_protocol::kTypeA
, ERR_NAME_NOT_RESOLVED
);
717 EXPECT_TRUE(helper0
.Run(transaction_factory_
.get()));
719 // A single-label name.
720 TransactionHelper
helper1("x", dns_protocol::kTypeA
, ERR_NAME_NOT_RESOLVED
);
722 EXPECT_TRUE(helper1
.Run(transaction_factory_
.get()));
724 // A fully-qualified name.
725 TransactionHelper
helper2("x.", dns_protocol::kTypeAAAA
,
726 ERR_NAME_NOT_RESOLVED
);
728 EXPECT_TRUE(helper2
.Run(transaction_factory_
.get()));
731 TEST_F(DnsTransactionTest
, EmptySuffixSearch
) {
732 // Responses for first transaction.
733 AddAsyncQueryAndRcode("x", dns_protocol::kTypeA
,
734 dns_protocol::kRcodeNXDOMAIN
);
736 // A fully-qualified name.
737 TransactionHelper
helper0("x.", dns_protocol::kTypeA
, ERR_NAME_NOT_RESOLVED
);
739 EXPECT_TRUE(helper0
.Run(transaction_factory_
.get()));
741 // A single label name is not even attempted.
742 TransactionHelper
helper1("singlelabel", dns_protocol::kTypeA
,
743 ERR_DNS_SEARCH_EMPTY
);
745 helper1
.Run(transaction_factory_
.get());
746 EXPECT_TRUE(helper1
.has_completed());
749 TEST_F(DnsTransactionTest
, DontAppendToMultiLabelName
) {
750 config_
.search
.push_back("a");
751 config_
.search
.push_back("b");
752 config_
.search
.push_back("c");
753 config_
.append_to_multi_label_name
= false;
756 // Responses for first transaction.
757 AddAsyncQueryAndRcode("x.y.z", dns_protocol::kTypeA
,
758 dns_protocol::kRcodeNXDOMAIN
);
759 // Responses for second transaction.
760 AddAsyncQueryAndRcode("x.y", dns_protocol::kTypeA
,
761 dns_protocol::kRcodeNXDOMAIN
);
762 // Responses for third transaction.
763 AddAsyncQueryAndRcode("x.a", dns_protocol::kTypeA
,
764 dns_protocol::kRcodeNXDOMAIN
);
765 AddAsyncQueryAndRcode("x.b", dns_protocol::kTypeA
,
766 dns_protocol::kRcodeNXDOMAIN
);
767 AddAsyncQueryAndRcode("x.c", dns_protocol::kTypeA
,
768 dns_protocol::kRcodeNXDOMAIN
);
770 TransactionHelper
helper0("x.y.z", dns_protocol::kTypeA
,
771 ERR_NAME_NOT_RESOLVED
);
772 EXPECT_TRUE(helper0
.Run(transaction_factory_
.get()));
774 TransactionHelper
helper1("x.y", dns_protocol::kTypeA
, ERR_NAME_NOT_RESOLVED
);
775 EXPECT_TRUE(helper1
.Run(transaction_factory_
.get()));
777 TransactionHelper
helper2("x", dns_protocol::kTypeA
, ERR_NAME_NOT_RESOLVED
);
778 EXPECT_TRUE(helper2
.Run(transaction_factory_
.get()));
781 const uint8 kResponseNoData
[] = {
782 0x00, 0x00, 0x81, 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
784 0x01, 'x', 0x01, 'y', 0x01, 'z', 0x01, 'b', 0x00, 0x00, 0x01, 0x00, 0x01,
785 // Authority section, SOA record, TTL 0x3E6
786 0x01, 'z', 0x00, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x03, 0xE6,
787 // Minimal RDATA, 18 bytes
790 0x00, 0x00, 0x00, 0x00,
791 0x00, 0x00, 0x00, 0x00,
792 0x00, 0x00, 0x00, 0x00,
793 0x00, 0x00, 0x00, 0x00,
796 TEST_F(DnsTransactionTest
, SuffixSearchStop
) {
798 config_
.search
.push_back("a");
799 config_
.search
.push_back("b");
800 config_
.search
.push_back("c");
803 AddAsyncQueryAndRcode("x.y.z", dns_protocol::kTypeA
,
804 dns_protocol::kRcodeNXDOMAIN
);
805 AddAsyncQueryAndRcode("x.y.z.a", dns_protocol::kTypeA
,
806 dns_protocol::kRcodeNXDOMAIN
);
807 AddAsyncQueryAndResponse(0 /* id */, "x.y.z.b", dns_protocol::kTypeA
,
808 kResponseNoData
, arraysize(kResponseNoData
));
810 TransactionHelper
helper0("x.y.z", dns_protocol::kTypeA
, 0 /* answers */);
812 EXPECT_TRUE(helper0
.Run(transaction_factory_
.get()));
815 TEST_F(DnsTransactionTest
, SyncFirstQuery
) {
816 config_
.search
.push_back("lab.ccs.neu.edu");
817 config_
.search
.push_back("ccs.neu.edu");
820 AddSyncQueryAndResponse(0 /* id */, kT0HostName
, kT0Qtype
,
821 kT0ResponseDatagram
, arraysize(kT0ResponseDatagram
));
823 TransactionHelper
helper0(kT0HostName
, kT0Qtype
, kT0RecordCount
);
824 EXPECT_TRUE(helper0
.Run(transaction_factory_
.get()));
827 TEST_F(DnsTransactionTest
, SyncFirstQueryWithSearch
) {
828 config_
.search
.push_back("lab.ccs.neu.edu");
829 config_
.search
.push_back("ccs.neu.edu");
832 AddSyncQueryAndRcode("www.lab.ccs.neu.edu", kT2Qtype
,
833 dns_protocol::kRcodeNXDOMAIN
);
835 AddAsyncQueryAndResponse(2 /* id */, kT2HostName
, kT2Qtype
,
836 kT2ResponseDatagram
, arraysize(kT2ResponseDatagram
));
838 TransactionHelper
helper0("www", kT2Qtype
, kT2RecordCount
);
839 EXPECT_TRUE(helper0
.Run(transaction_factory_
.get()));
842 TEST_F(DnsTransactionTest
, SyncSearchQuery
) {
843 config_
.search
.push_back("lab.ccs.neu.edu");
844 config_
.search
.push_back("ccs.neu.edu");
847 AddAsyncQueryAndRcode("www.lab.ccs.neu.edu", dns_protocol::kTypeA
,
848 dns_protocol::kRcodeNXDOMAIN
);
849 AddSyncQueryAndResponse(2 /* id */, kT2HostName
, kT2Qtype
,
850 kT2ResponseDatagram
, arraysize(kT2ResponseDatagram
));
852 TransactionHelper
helper0("www", kT2Qtype
, kT2RecordCount
);
853 EXPECT_TRUE(helper0
.Run(transaction_factory_
.get()));
856 TEST_F(DnsTransactionTest
, ConnectFailure
) {
857 socket_factory_
->fail_next_socket_
= true;
858 transaction_ids_
.push_back(0); // Needed to make a DnsUDPAttempt.
859 TransactionHelper
helper0("www.chromium.org", dns_protocol::kTypeA
,
860 ERR_CONNECTION_REFUSED
);
861 EXPECT_TRUE(helper0
.Run(transaction_factory_
.get()));
864 TEST_F(DnsTransactionTest
, ConnectFailureFollowedBySuccess
) {
865 // Retry after server failure.
866 config_
.attempts
= 2;
868 // First server connection attempt fails.
869 transaction_ids_
.push_back(0); // Needed to make a DnsUDPAttempt.
870 socket_factory_
->fail_next_socket_
= true;
871 // Second DNS query succeeds.
872 AddAsyncQueryAndResponse(0 /* id */, kT0HostName
, kT0Qtype
,
873 kT0ResponseDatagram
, arraysize(kT0ResponseDatagram
));
874 TransactionHelper
helper0(kT0HostName
, kT0Qtype
, kT0RecordCount
);
875 EXPECT_TRUE(helper0
.Run(transaction_factory_
.get()));
878 TEST_F(DnsTransactionTest
, TCPLookup
) {
879 AddAsyncQueryAndRcode(kT0HostName
, kT0Qtype
,
880 dns_protocol::kRcodeNOERROR
| dns_protocol::kFlagTC
);
881 AddQueryAndResponse(0 /* id */, kT0HostName
, kT0Qtype
,
882 kT0ResponseDatagram
, arraysize(kT0ResponseDatagram
),
883 ASYNC
, true /* use_tcp */);
885 TransactionHelper
helper0(kT0HostName
, kT0Qtype
, kT0RecordCount
);
886 EXPECT_TRUE(helper0
.Run(transaction_factory_
.get()));
889 TEST_F(DnsTransactionTest
, TCPFailure
) {
890 AddAsyncQueryAndRcode(kT0HostName
, kT0Qtype
,
891 dns_protocol::kRcodeNOERROR
| dns_protocol::kFlagTC
);
892 AddQueryAndRcode(kT0HostName
, kT0Qtype
, dns_protocol::kRcodeSERVFAIL
,
893 ASYNC
, true /* use_tcp */);
895 TransactionHelper
helper0(kT0HostName
, kT0Qtype
, ERR_DNS_SERVER_FAILED
);
896 EXPECT_TRUE(helper0
.Run(transaction_factory_
.get()));
899 TEST_F(DnsTransactionTest
, TCPMalformed
) {
900 AddAsyncQueryAndRcode(kT0HostName
, kT0Qtype
,
901 dns_protocol::kRcodeNOERROR
| dns_protocol::kFlagTC
);
902 scoped_ptr
<DnsSocketData
> data(
903 new DnsSocketData(0 /* id */, kT0HostName
, kT0Qtype
, ASYNC
, true));
904 // Valid response but length too short.
905 data
->AddResponseWithLength(
907 new DnsResponse(reinterpret_cast<const char*>(kT0ResponseDatagram
),
908 arraysize(kT0ResponseDatagram
), 0)),
910 static_cast<uint16
>(kT0QuerySize
- 1));
911 AddSocketData(data
.Pass());
913 TransactionHelper
helper0(kT0HostName
, kT0Qtype
, ERR_DNS_MALFORMED_RESPONSE
);
914 EXPECT_TRUE(helper0
.Run(transaction_factory_
.get()));
917 TEST_F(DnsTransactionTest
, TCPTimeout
) {
918 config_
.timeout
= TestTimeouts::tiny_timeout();
920 AddAsyncQueryAndRcode(kT0HostName
, kT0Qtype
,
921 dns_protocol::kRcodeNOERROR
| dns_protocol::kFlagTC
);
922 AddSocketData(make_scoped_ptr(
923 new DnsSocketData(1 /* id */, kT0HostName
, kT0Qtype
, ASYNC
, true)));
925 TransactionHelper
helper0(kT0HostName
, kT0Qtype
, ERR_DNS_TIMED_OUT
);
926 EXPECT_TRUE(helper0
.RunUntilDone(transaction_factory_
.get()));
929 TEST_F(DnsTransactionTest
, InvalidQuery
) {
930 config_
.timeout
= TestTimeouts::tiny_timeout();
933 TransactionHelper
helper0(".", dns_protocol::kTypeA
, ERR_INVALID_ARGUMENT
);
934 EXPECT_TRUE(helper0
.Run(transaction_factory_
.get()));