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 for MockUDPClientSocket. Each socket used by a
35 // DnsTransaction expects only one write and zero or more reads.
38 // The ctor takes parameters for the DnsQuery.
39 DnsSocketData(uint16 id
, const char* dotted_name
, uint16 qtype
, IoMode mode
)
40 : query_(new DnsQuery(id
, DomainFromDot(dotted_name
), qtype
)),
41 write_(mode
, query_
->io_buffer()->data(), query_
->io_buffer()->size()) {
45 // All responses must be added before GetProvider.
47 // Add pre-built DnsResponse.
48 void AddResponse(scoped_ptr
<DnsResponse
> response
, IoMode mode
) {
49 CHECK(!provider_
.get());
50 reads_
.push_back(MockRead(mode
,
51 response
->io_buffer()->data(),
52 response
->io_buffer()->size()));
53 responses_
.push_back(response
.release());
56 // Adds pre-built response from |data| buffer.
57 void AddResponseData(const uint8
* data
, size_t length
, IoMode mode
) {
58 CHECK(!provider_
.get());
59 AddResponse(make_scoped_ptr(
60 new DnsResponse(reinterpret_cast<const char*>(data
), length
, 0)), mode
);
63 // Add no-answer (RCODE only) response matching the query.
64 void AddRcode(int rcode
, IoMode mode
) {
65 scoped_ptr
<DnsResponse
> response(
66 new DnsResponse(query_
->io_buffer()->data(),
67 query_
->io_buffer()->size(),
69 dns_protocol::Header
* header
=
70 reinterpret_cast<dns_protocol::Header
*>(response
->io_buffer()->data());
71 header
->flags
|= base::HostToNet16(dns_protocol::kFlagResponse
| rcode
);
72 AddResponse(response
.Pass(), mode
);
75 // Build, if needed, and return the SocketDataProvider. No new responses
76 // should be added afterwards.
77 SocketDataProvider
* GetProvider() {
79 return provider_
.get();
82 provider_
.reset(new DelayedSocketData(2, NULL
, 0, &write_
, 1));
84 // Terminate the reads with ERR_IO_PENDING to prevent overrun.
85 reads_
.push_back(MockRead(ASYNC
, ERR_IO_PENDING
));
86 provider_
.reset(new DelayedSocketData(1, &reads_
[0], reads_
.size(),
89 return provider_
.get();
92 uint16
query_id() const {
96 // Returns true if the expected query was written to the socket.
97 bool was_written() const {
98 CHECK(provider_
.get());
99 return provider_
->write_index() > 0;
103 scoped_ptr
<DnsQuery
> query_
;
104 ScopedVector
<DnsResponse
> responses_
;
106 std::vector
<MockRead
> reads_
;
107 scoped_ptr
<DelayedSocketData
> provider_
;
109 DISALLOW_COPY_AND_ASSIGN(DnsSocketData
);
112 class TestSocketFactory
;
114 // A variant of MockUDPClientSocket which always fails to Connect.
115 class FailingUDPClientSocket
: public MockUDPClientSocket
{
117 FailingUDPClientSocket(SocketDataProvider
* data
,
118 net::NetLog
* net_log
)
119 : MockUDPClientSocket(data
, net_log
) {
121 virtual ~FailingUDPClientSocket() {}
122 virtual int Connect(const IPEndPoint
& endpoint
) OVERRIDE
{
123 return ERR_CONNECTION_REFUSED
;
127 DISALLOW_COPY_AND_ASSIGN(FailingUDPClientSocket
);
130 // A variant of MockUDPClientSocket which notifies the factory OnConnect.
131 class TestUDPClientSocket
: public MockUDPClientSocket
{
133 TestUDPClientSocket(TestSocketFactory
* factory
,
134 SocketDataProvider
* data
,
135 net::NetLog
* net_log
)
136 : MockUDPClientSocket(data
, net_log
), factory_(factory
) {
138 virtual ~TestUDPClientSocket() {}
139 virtual int Connect(const IPEndPoint
& endpoint
) OVERRIDE
;
142 TestSocketFactory
* factory_
;
144 DISALLOW_COPY_AND_ASSIGN(TestUDPClientSocket
);
147 // Creates TestUDPClientSockets and keeps endpoints reported via OnConnect.
148 class TestSocketFactory
: public MockClientSocketFactory
{
150 TestSocketFactory() : create_failing_sockets_(false) {}
151 virtual ~TestSocketFactory() {}
153 virtual DatagramClientSocket
* CreateDatagramClientSocket(
154 DatagramSocket::BindType bind_type
,
155 const RandIntCallback
& rand_int_cb
,
156 net::NetLog
* net_log
,
157 const net::NetLog::Source
& source
) OVERRIDE
{
158 if (create_failing_sockets_
)
159 return new FailingUDPClientSocket(&empty_data_
, net_log
);
160 SocketDataProvider
* data_provider
= mock_data().GetNext();
161 TestUDPClientSocket
* socket
= new TestUDPClientSocket(this,
164 data_provider
->set_socket(socket
);
168 void OnConnect(const IPEndPoint
& endpoint
) {
169 remote_endpoints_
.push_back(endpoint
);
172 std::vector
<IPEndPoint
> remote_endpoints_
;
173 bool create_failing_sockets_
;
176 StaticSocketDataProvider empty_data_
;
178 DISALLOW_COPY_AND_ASSIGN(TestSocketFactory
);
181 int TestUDPClientSocket::Connect(const IPEndPoint
& endpoint
) {
182 factory_
->OnConnect(endpoint
);
183 return MockUDPClientSocket::Connect(endpoint
);
186 // Helper class that holds a DnsTransaction and handles OnTransactionComplete.
187 class TransactionHelper
{
189 // If |expected_answer_count| < 0 then it is the expected net error.
190 TransactionHelper(const char* hostname
,
192 int expected_answer_count
)
193 : hostname_(hostname
),
195 expected_answer_count_(expected_answer_count
),
196 cancel_in_callback_(false),
197 quit_in_callback_(false),
201 // Mark that the transaction shall be destroyed immediately upon callback.
202 void set_cancel_in_callback() {
203 cancel_in_callback_
= true;
206 // Mark to call MessageLoop::Quit() upon callback.
207 void set_quit_in_callback() {
208 quit_in_callback_
= true;
211 void StartTransaction(DnsTransactionFactory
* factory
) {
212 EXPECT_EQ(NULL
, transaction_
.get());
213 transaction_
= factory
->CreateTransaction(
216 base::Bind(&TransactionHelper::OnTransactionComplete
,
217 base::Unretained(this)),
219 EXPECT_EQ(hostname_
, transaction_
->GetHostname());
220 EXPECT_EQ(qtype_
, transaction_
->GetType());
221 int rv
= transaction_
->Start();
222 if (rv
!= ERR_IO_PENDING
) {
224 EXPECT_EQ(expected_answer_count_
, rv
);
230 ASSERT_TRUE(transaction_
.get() != NULL
);
231 transaction_
.reset(NULL
);
234 void OnTransactionComplete(DnsTransaction
* t
,
236 const DnsResponse
* response
) {
237 EXPECT_FALSE(completed_
);
238 EXPECT_EQ(transaction_
.get(), t
);
242 if (cancel_in_callback_
) {
247 // Tell MessageLoop to quit now, in case any ASSERT_* fails.
248 if (quit_in_callback_
)
249 MessageLoop::current()->Quit();
251 if (expected_answer_count_
>= 0) {
253 ASSERT_TRUE(response
!= NULL
);
254 EXPECT_EQ(static_cast<unsigned>(expected_answer_count_
),
255 response
->answer_count());
256 EXPECT_EQ(qtype_
, response
->qtype());
258 DnsRecordParser parser
= response
->Parser();
259 DnsResourceRecord record
;
260 for (int i
= 0; i
< expected_answer_count_
; ++i
) {
261 EXPECT_TRUE(parser
.ReadRecord(&record
));
264 EXPECT_EQ(expected_answer_count_
, rv
);
268 bool has_completed() const {
272 // Shorthands for commonly used commands.
274 bool Run(DnsTransactionFactory
* factory
) {
275 StartTransaction(factory
);
276 MessageLoop::current()->RunUntilIdle();
277 return has_completed();
280 // Use when some of the responses are timeouts.
281 bool RunUntilDone(DnsTransactionFactory
* factory
) {
282 set_quit_in_callback();
283 StartTransaction(factory
);
284 MessageLoop::current()->Run();
285 return has_completed();
289 std::string hostname_
;
291 scoped_ptr
<DnsTransaction
> transaction_
;
292 int expected_answer_count_
;
293 bool cancel_in_callback_
;
294 bool quit_in_callback_
;
299 class DnsTransactionTest
: public testing::Test
{
301 DnsTransactionTest() : socket_factory_(NULL
) {}
303 // Generates |nameservers| for DnsConfig.
304 void ConfigureNumServers(unsigned num_servers
) {
305 CHECK_LE(num_servers
, 255u);
306 config_
.nameservers
.clear();
307 IPAddressNumber dns_ip
;
309 bool rv
= ParseIPLiteralToNumber("192.168.1.0", &dns_ip
);
312 for (unsigned i
= 0; i
< num_servers
; ++i
) {
314 config_
.nameservers
.push_back(IPEndPoint(dns_ip
,
315 dns_protocol::kDefaultPort
));
319 // Called after fully configuring |config|.
320 void ConfigureFactory() {
321 socket_factory_
.reset(new TestSocketFactory());
322 session_
= new DnsSession(
324 socket_factory_
.get(),
325 base::Bind(&DnsTransactionTest::GetNextId
, base::Unretained(this)),
327 transaction_factory_
= DnsTransactionFactory::CreateFactory(session_
.get());
330 void AddSocketData(scoped_ptr
<DnsSocketData
> data
) {
331 transaction_ids_
.push_back(data
->query_id());
332 socket_factory_
->AddSocketDataProvider(data
->GetProvider());
333 socket_data_
.push_back(data
.release());
336 // Add expected query for |dotted_name| and |qtype| with |id| and response
337 // taken verbatim from |data| of |data_length| bytes. The transaction id in
338 // |data| should equal |id|, unless testing mismatched response.
339 void AddQueryAndResponse(uint16 id
,
340 const char* dotted_name
,
342 const uint8
* response_data
,
343 size_t response_length
,
345 CHECK(socket_factory_
.get());
346 scoped_ptr
<DnsSocketData
> data(
347 new DnsSocketData(id
, dotted_name
, qtype
, mode
));
348 data
->AddResponseData(response_data
, response_length
, mode
);
349 AddSocketData(data
.Pass());
352 void AddAsyncQueryAndResponse(uint16 id
,
353 const char* dotted_name
,
356 size_t data_length
) {
357 AddQueryAndResponse(id
, dotted_name
, qtype
, data
, data_length
, ASYNC
);
360 void AddSyncQueryAndResponse(uint16 id
,
361 const char* dotted_name
,
364 size_t data_length
) {
365 AddQueryAndResponse(id
, dotted_name
, qtype
, data
, data_length
, SYNCHRONOUS
);
368 // Add expected query of |dotted_name| and |qtype| and no response.
369 void AddQueryAndTimeout(const char* dotted_name
, uint16 qtype
) {
370 CHECK(socket_factory_
.get());
371 uint16 id
= base::RandInt(0, kuint16max
);
372 scoped_ptr
<DnsSocketData
> data(
373 new DnsSocketData(id
, dotted_name
, qtype
, ASYNC
));
374 AddSocketData(data
.Pass());
377 // Add expected query of |dotted_name| and |qtype| and matching response with
378 // no answer and RCODE set to |rcode|. The id will be generated randomly.
379 void AddQueryAndRcode(const char* dotted_name
,
383 CHECK(socket_factory_
.get());
384 CHECK_NE(dns_protocol::kRcodeNOERROR
, rcode
);
385 uint16 id
= base::RandInt(0, kuint16max
);
386 scoped_ptr
<DnsSocketData
> data(
387 new DnsSocketData(id
, dotted_name
, qtype
, mode
));
388 data
->AddRcode(rcode
, mode
);
389 AddSocketData(data
.Pass());
392 void AddAsyncQueryAndRcode(const char* dotted_name
, uint16 qtype
, int rcode
) {
393 AddQueryAndRcode(dotted_name
, qtype
, rcode
, ASYNC
);
396 void AddSyncQueryAndRcode(const char* dotted_name
, uint16 qtype
, int rcode
) {
397 AddQueryAndRcode(dotted_name
, qtype
, rcode
, SYNCHRONOUS
);
400 // Checks if the sockets were connected in the order matching the indices in
402 void CheckServerOrder(const unsigned* servers
, size_t num_attempts
) {
403 ASSERT_EQ(num_attempts
, socket_factory_
->remote_endpoints_
.size());
404 for (size_t i
= 0; i
< num_attempts
; ++i
) {
405 EXPECT_EQ(socket_factory_
->remote_endpoints_
[i
],
406 session_
->config().nameservers
[servers
[i
]]);
410 void SetUp() OVERRIDE
{
411 // By default set one server,
412 ConfigureNumServers(1);
413 // and no retransmissions,
414 config_
.attempts
= 1;
415 // but long enough timeout for memory tests.
416 config_
.timeout
= TestTimeouts::action_timeout();
420 void TearDown() OVERRIDE
{
421 // Check that all socket data was at least written to.
422 for (size_t i
= 0; i
< socket_data_
.size(); ++i
) {
423 EXPECT_TRUE(socket_data_
[i
]->was_written()) << i
;
428 int GetNextId(int min
, int max
) {
429 EXPECT_FALSE(transaction_ids_
.empty());
430 int id
= transaction_ids_
.front();
431 transaction_ids_
.pop_front();
439 ScopedVector
<DnsSocketData
> socket_data_
;
441 std::deque
<int> transaction_ids_
;
442 scoped_ptr
<TestSocketFactory
> socket_factory_
;
443 scoped_refptr
<DnsSession
> session_
;
444 scoped_ptr
<DnsTransactionFactory
> transaction_factory_
;
447 TEST_F(DnsTransactionTest
, Lookup
) {
448 AddAsyncQueryAndResponse(0 /* id */, kT0HostName
, kT0Qtype
,
449 kT0ResponseDatagram
, arraysize(kT0ResponseDatagram
));
451 TransactionHelper
helper0(kT0HostName
, kT0Qtype
, kT0RecordCount
);
452 EXPECT_TRUE(helper0
.Run(transaction_factory_
.get()));
455 // Concurrent lookup tests assume that DnsTransaction::Start immediately
456 // consumes a socket from ClientSocketFactory.
457 TEST_F(DnsTransactionTest
, ConcurrentLookup
) {
458 AddAsyncQueryAndResponse(0 /* id */, kT0HostName
, kT0Qtype
,
459 kT0ResponseDatagram
, arraysize(kT0ResponseDatagram
));
460 AddAsyncQueryAndResponse(1 /* id */, kT1HostName
, kT1Qtype
,
461 kT1ResponseDatagram
, arraysize(kT1ResponseDatagram
));
463 TransactionHelper
helper0(kT0HostName
, kT0Qtype
, kT0RecordCount
);
464 helper0
.StartTransaction(transaction_factory_
.get());
465 TransactionHelper
helper1(kT1HostName
, kT1Qtype
, kT1RecordCount
);
466 helper1
.StartTransaction(transaction_factory_
.get());
468 MessageLoop::current()->RunUntilIdle();
470 EXPECT_TRUE(helper0
.has_completed());
471 EXPECT_TRUE(helper1
.has_completed());
474 TEST_F(DnsTransactionTest
, CancelLookup
) {
475 AddAsyncQueryAndResponse(0 /* id */, kT0HostName
, kT0Qtype
,
476 kT0ResponseDatagram
, arraysize(kT0ResponseDatagram
));
477 AddAsyncQueryAndResponse(1 /* id */, kT1HostName
, kT1Qtype
,
478 kT1ResponseDatagram
, arraysize(kT1ResponseDatagram
));
480 TransactionHelper
helper0(kT0HostName
, kT0Qtype
, kT0RecordCount
);
481 helper0
.StartTransaction(transaction_factory_
.get());
482 TransactionHelper
helper1(kT1HostName
, kT1Qtype
, kT1RecordCount
);
483 helper1
.StartTransaction(transaction_factory_
.get());
487 MessageLoop::current()->RunUntilIdle();
489 EXPECT_FALSE(helper0
.has_completed());
490 EXPECT_TRUE(helper1
.has_completed());
493 TEST_F(DnsTransactionTest
, DestroyFactory
) {
494 AddAsyncQueryAndResponse(0 /* id */, kT0HostName
, kT0Qtype
,
495 kT0ResponseDatagram
, arraysize(kT0ResponseDatagram
));
497 TransactionHelper
helper0(kT0HostName
, kT0Qtype
, kT0RecordCount
);
498 helper0
.StartTransaction(transaction_factory_
.get());
500 // Destroying the client does not affect running requests.
501 transaction_factory_
.reset(NULL
);
503 MessageLoop::current()->RunUntilIdle();
505 EXPECT_TRUE(helper0
.has_completed());
508 TEST_F(DnsTransactionTest
, CancelFromCallback
) {
509 AddAsyncQueryAndResponse(0 /* id */, kT0HostName
, kT0Qtype
,
510 kT0ResponseDatagram
, arraysize(kT0ResponseDatagram
));
512 TransactionHelper
helper0(kT0HostName
, kT0Qtype
, kT0RecordCount
);
513 helper0
.set_cancel_in_callback();
514 EXPECT_TRUE(helper0
.Run(transaction_factory_
.get()));
517 TEST_F(DnsTransactionTest
, MismatchedResponseSync
) {
518 config_
.attempts
= 2;
519 config_
.timeout
= TestTimeouts::tiny_timeout();
522 // Attempt receives mismatched response followed by valid response.
523 scoped_ptr
<DnsSocketData
> data(
524 new DnsSocketData(0 /* id */, kT0HostName
, kT0Qtype
, SYNCHRONOUS
));
525 data
->AddResponseData(kT1ResponseDatagram
,
526 arraysize(kT1ResponseDatagram
), SYNCHRONOUS
);
527 data
->AddResponseData(kT0ResponseDatagram
,
528 arraysize(kT0ResponseDatagram
), SYNCHRONOUS
);
529 AddSocketData(data
.Pass());
531 TransactionHelper
helper0(kT0HostName
, kT0Qtype
, kT0RecordCount
);
532 EXPECT_TRUE(helper0
.RunUntilDone(transaction_factory_
.get()));
535 TEST_F(DnsTransactionTest
, MismatchedResponseAsync
) {
536 config_
.attempts
= 2;
537 config_
.timeout
= TestTimeouts::tiny_timeout();
540 // First attempt receives mismatched response followed by valid response.
541 // Second attempt times out.
542 scoped_ptr
<DnsSocketData
> data(
543 new DnsSocketData(0 /* id */, kT0HostName
, kT0Qtype
, ASYNC
));
544 data
->AddResponseData(kT1ResponseDatagram
,
545 arraysize(kT1ResponseDatagram
), ASYNC
);
546 data
->AddResponseData(kT0ResponseDatagram
,
547 arraysize(kT0ResponseDatagram
), ASYNC
);
548 AddSocketData(data
.Pass());
549 AddQueryAndTimeout(kT0HostName
, kT0Qtype
);
551 TransactionHelper
helper0(kT0HostName
, kT0Qtype
, kT0RecordCount
);
552 EXPECT_TRUE(helper0
.RunUntilDone(transaction_factory_
.get()));
555 TEST_F(DnsTransactionTest
, MismatchedResponseFail
) {
556 config_
.timeout
= TestTimeouts::tiny_timeout();
559 // Attempt receives mismatched response but times out because only one attempt
561 AddAsyncQueryAndResponse(1 /* id */, kT0HostName
, kT0Qtype
,
562 kT0ResponseDatagram
, arraysize(kT0ResponseDatagram
));
564 TransactionHelper
helper0(kT0HostName
, kT0Qtype
, ERR_DNS_TIMED_OUT
);
565 EXPECT_TRUE(helper0
.RunUntilDone(transaction_factory_
.get()));
568 TEST_F(DnsTransactionTest
, ServerFail
) {
569 AddAsyncQueryAndRcode(kT0HostName
, kT0Qtype
, dns_protocol::kRcodeSERVFAIL
);
571 TransactionHelper
helper0(kT0HostName
, kT0Qtype
, ERR_DNS_SERVER_FAILED
);
572 EXPECT_TRUE(helper0
.Run(transaction_factory_
.get()));
575 TEST_F(DnsTransactionTest
, NoDomain
) {
576 AddAsyncQueryAndRcode(kT0HostName
, kT0Qtype
, dns_protocol::kRcodeNXDOMAIN
);
578 TransactionHelper
helper0(kT0HostName
, kT0Qtype
, ERR_NAME_NOT_RESOLVED
);
579 EXPECT_TRUE(helper0
.Run(transaction_factory_
.get()));
582 TEST_F(DnsTransactionTest
, Timeout
) {
583 config_
.attempts
= 3;
584 // Use short timeout to speed up the test.
585 config_
.timeout
= TestTimeouts::tiny_timeout();
588 AddQueryAndTimeout(kT0HostName
, kT0Qtype
);
589 AddQueryAndTimeout(kT0HostName
, kT0Qtype
);
590 AddQueryAndTimeout(kT0HostName
, kT0Qtype
);
592 TransactionHelper
helper0(kT0HostName
, kT0Qtype
, ERR_DNS_TIMED_OUT
);
593 EXPECT_TRUE(helper0
.RunUntilDone(transaction_factory_
.get()));
594 MessageLoop::current()->AssertIdle();
597 TEST_F(DnsTransactionTest
, ServerFallbackAndRotate
) {
598 // Test that we fallback on both server failure and timeout.
599 config_
.attempts
= 2;
600 // The next request should start from the next server.
601 config_
.rotate
= true;
602 ConfigureNumServers(3);
603 // Use short timeout to speed up the test.
604 config_
.timeout
= TestTimeouts::tiny_timeout();
607 // Responses for first request.
608 AddQueryAndTimeout(kT0HostName
, kT0Qtype
);
609 AddAsyncQueryAndRcode(kT0HostName
, kT0Qtype
, dns_protocol::kRcodeSERVFAIL
);
610 AddQueryAndTimeout(kT0HostName
, kT0Qtype
);
611 AddAsyncQueryAndRcode(kT0HostName
, kT0Qtype
, dns_protocol::kRcodeSERVFAIL
);
612 AddAsyncQueryAndRcode(kT0HostName
, kT0Qtype
, dns_protocol::kRcodeNXDOMAIN
);
613 // Responses for second request.
614 AddAsyncQueryAndRcode(kT1HostName
, kT1Qtype
, dns_protocol::kRcodeSERVFAIL
);
615 AddAsyncQueryAndRcode(kT1HostName
, kT1Qtype
, dns_protocol::kRcodeNXDOMAIN
);
617 TransactionHelper
helper0(kT0HostName
, kT0Qtype
, ERR_NAME_NOT_RESOLVED
);
618 TransactionHelper
helper1(kT1HostName
, kT1Qtype
, ERR_NAME_NOT_RESOLVED
);
620 EXPECT_TRUE(helper0
.RunUntilDone(transaction_factory_
.get()));
621 EXPECT_TRUE(helper1
.Run(transaction_factory_
.get()));
623 unsigned kOrder
[] = {
624 0, 1, 2, 0, 1, // The first transaction.
625 1, 2, // The second transaction starts from the next server.
627 CheckServerOrder(kOrder
, arraysize(kOrder
));
630 TEST_F(DnsTransactionTest
, SuffixSearchAboveNdots
) {
632 config_
.search
.push_back("a");
633 config_
.search
.push_back("b");
634 config_
.search
.push_back("c");
635 config_
.rotate
= true;
636 ConfigureNumServers(2);
639 AddAsyncQueryAndRcode("x.y.z", dns_protocol::kTypeA
,
640 dns_protocol::kRcodeNXDOMAIN
);
641 AddAsyncQueryAndRcode("x.y.z.a", dns_protocol::kTypeA
,
642 dns_protocol::kRcodeNXDOMAIN
);
643 AddAsyncQueryAndRcode("x.y.z.b", dns_protocol::kTypeA
,
644 dns_protocol::kRcodeNXDOMAIN
);
645 AddAsyncQueryAndRcode("x.y.z.c", dns_protocol::kTypeA
,
646 dns_protocol::kRcodeNXDOMAIN
);
648 TransactionHelper
helper0("x.y.z", dns_protocol::kTypeA
,
649 ERR_NAME_NOT_RESOLVED
);
651 EXPECT_TRUE(helper0
.Run(transaction_factory_
.get()));
653 // Also check if suffix search causes server rotation.
654 unsigned kOrder0
[] = { 0, 1, 0, 1 };
655 CheckServerOrder(kOrder0
, arraysize(kOrder0
));
658 TEST_F(DnsTransactionTest
, SuffixSearchBelowNdots
) {
660 config_
.search
.push_back("a");
661 config_
.search
.push_back("b");
662 config_
.search
.push_back("c");
665 // Responses for first transaction.
666 AddAsyncQueryAndRcode("x.y.a", dns_protocol::kTypeA
,
667 dns_protocol::kRcodeNXDOMAIN
);
668 AddAsyncQueryAndRcode("x.y.b", dns_protocol::kTypeA
,
669 dns_protocol::kRcodeNXDOMAIN
);
670 AddAsyncQueryAndRcode("x.y.c", dns_protocol::kTypeA
,
671 dns_protocol::kRcodeNXDOMAIN
);
672 AddAsyncQueryAndRcode("x.y", dns_protocol::kTypeA
,
673 dns_protocol::kRcodeNXDOMAIN
);
674 // Responses for second transaction.
675 AddAsyncQueryAndRcode("x.a", dns_protocol::kTypeA
,
676 dns_protocol::kRcodeNXDOMAIN
);
677 AddAsyncQueryAndRcode("x.b", dns_protocol::kTypeA
,
678 dns_protocol::kRcodeNXDOMAIN
);
679 AddAsyncQueryAndRcode("x.c", dns_protocol::kTypeA
,
680 dns_protocol::kRcodeNXDOMAIN
);
681 // Responses for third transaction.
682 AddAsyncQueryAndRcode("x", dns_protocol::kTypeAAAA
,
683 dns_protocol::kRcodeNXDOMAIN
);
685 TransactionHelper
helper0("x.y", dns_protocol::kTypeA
, ERR_NAME_NOT_RESOLVED
);
687 EXPECT_TRUE(helper0
.Run(transaction_factory_
.get()));
689 // A single-label name.
690 TransactionHelper
helper1("x", dns_protocol::kTypeA
, ERR_NAME_NOT_RESOLVED
);
692 EXPECT_TRUE(helper1
.Run(transaction_factory_
.get()));
694 // A fully-qualified name.
695 TransactionHelper
helper2("x.", dns_protocol::kTypeAAAA
,
696 ERR_NAME_NOT_RESOLVED
);
698 EXPECT_TRUE(helper2
.Run(transaction_factory_
.get()));
701 TEST_F(DnsTransactionTest
, EmptySuffixSearch
) {
702 // Responses for first transaction.
703 AddAsyncQueryAndRcode("x", dns_protocol::kTypeA
,
704 dns_protocol::kRcodeNXDOMAIN
);
706 // A fully-qualified name.
707 TransactionHelper
helper0("x.", dns_protocol::kTypeA
, ERR_NAME_NOT_RESOLVED
);
709 EXPECT_TRUE(helper0
.Run(transaction_factory_
.get()));
711 // A single label name is not even attempted.
712 TransactionHelper
helper1("singlelabel", dns_protocol::kTypeA
,
713 ERR_DNS_SEARCH_EMPTY
);
715 helper1
.StartTransaction(transaction_factory_
.get());
716 EXPECT_TRUE(helper1
.has_completed());
719 TEST_F(DnsTransactionTest
, DontAppendToMultiLabelName
) {
720 config_
.search
.push_back("a");
721 config_
.search
.push_back("b");
722 config_
.search
.push_back("c");
723 config_
.append_to_multi_label_name
= false;
726 // Responses for first transaction.
727 AddAsyncQueryAndRcode("x.y.z", dns_protocol::kTypeA
,
728 dns_protocol::kRcodeNXDOMAIN
);
729 // Responses for second transaction.
730 AddAsyncQueryAndRcode("x.y", dns_protocol::kTypeA
,
731 dns_protocol::kRcodeNXDOMAIN
);
732 // Responses for third transaction.
733 AddAsyncQueryAndRcode("x.a", dns_protocol::kTypeA
,
734 dns_protocol::kRcodeNXDOMAIN
);
735 AddAsyncQueryAndRcode("x.b", dns_protocol::kTypeA
,
736 dns_protocol::kRcodeNXDOMAIN
);
737 AddAsyncQueryAndRcode("x.c", dns_protocol::kTypeA
,
738 dns_protocol::kRcodeNXDOMAIN
);
740 TransactionHelper
helper0("x.y.z", dns_protocol::kTypeA
,
741 ERR_NAME_NOT_RESOLVED
);
742 EXPECT_TRUE(helper0
.Run(transaction_factory_
.get()));
744 TransactionHelper
helper1("x.y", dns_protocol::kTypeA
, ERR_NAME_NOT_RESOLVED
);
745 EXPECT_TRUE(helper1
.Run(transaction_factory_
.get()));
747 TransactionHelper
helper2("x", dns_protocol::kTypeA
, ERR_NAME_NOT_RESOLVED
);
748 EXPECT_TRUE(helper2
.Run(transaction_factory_
.get()));
751 const uint8 kResponseNoData
[] = {
752 0x00, 0x00, 0x81, 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
754 0x01, 'x', 0x01, 'y', 0x01, 'z', 0x01, 'b', 0x00, 0x00, 0x01, 0x00, 0x01,
755 // Authority section, SOA record, TTL 0x3E6
756 0x01, 'z', 0x00, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x03, 0xE6,
757 // Minimal RDATA, 18 bytes
760 0x00, 0x00, 0x00, 0x00,
761 0x00, 0x00, 0x00, 0x00,
762 0x00, 0x00, 0x00, 0x00,
763 0x00, 0x00, 0x00, 0x00,
766 TEST_F(DnsTransactionTest
, SuffixSearchStop
) {
768 config_
.search
.push_back("a");
769 config_
.search
.push_back("b");
770 config_
.search
.push_back("c");
773 AddAsyncQueryAndRcode("x.y.z", dns_protocol::kTypeA
,
774 dns_protocol::kRcodeNXDOMAIN
);
775 AddAsyncQueryAndRcode("x.y.z.a", dns_protocol::kTypeA
,
776 dns_protocol::kRcodeNXDOMAIN
);
777 AddAsyncQueryAndResponse(0 /* id */, "x.y.z.b", dns_protocol::kTypeA
,
778 kResponseNoData
, arraysize(kResponseNoData
));
780 TransactionHelper
helper0("x.y.z", dns_protocol::kTypeA
, 0 /* answers */);
782 EXPECT_TRUE(helper0
.Run(transaction_factory_
.get()));
785 TEST_F(DnsTransactionTest
, SyncFirstQuery
) {
786 config_
.search
.push_back("lab.ccs.neu.edu");
787 config_
.search
.push_back("ccs.neu.edu");
790 AddSyncQueryAndResponse(0 /* id */, kT0HostName
, kT0Qtype
,
791 kT0ResponseDatagram
, arraysize(kT0ResponseDatagram
));
793 TransactionHelper
helper0(kT0HostName
, kT0Qtype
, kT0RecordCount
);
794 EXPECT_TRUE(helper0
.Run(transaction_factory_
.get()));
797 TEST_F(DnsTransactionTest
, SyncFirstQueryWithSearch
) {
798 config_
.search
.push_back("lab.ccs.neu.edu");
799 config_
.search
.push_back("ccs.neu.edu");
802 AddSyncQueryAndRcode("www.lab.ccs.neu.edu", kT2Qtype
,
803 dns_protocol::kRcodeNXDOMAIN
);
805 AddAsyncQueryAndResponse(2 /* id */, kT2HostName
, kT2Qtype
,
806 kT2ResponseDatagram
, arraysize(kT2ResponseDatagram
));
808 TransactionHelper
helper0("www", kT2Qtype
, kT2RecordCount
);
809 EXPECT_TRUE(helper0
.Run(transaction_factory_
.get()));
812 TEST_F(DnsTransactionTest
, SyncSearchQuery
) {
813 config_
.search
.push_back("lab.ccs.neu.edu");
814 config_
.search
.push_back("ccs.neu.edu");
817 AddAsyncQueryAndRcode("www.lab.ccs.neu.edu", dns_protocol::kTypeA
,
818 dns_protocol::kRcodeNXDOMAIN
);
819 AddSyncQueryAndResponse(2 /* id */, kT2HostName
, kT2Qtype
,
820 kT2ResponseDatagram
, arraysize(kT2ResponseDatagram
));
822 TransactionHelper
helper0("www", kT2Qtype
, kT2RecordCount
);
823 EXPECT_TRUE(helper0
.Run(transaction_factory_
.get()));
826 TEST_F(DnsTransactionTest
, ConnectFailure
) {
827 socket_factory_
->create_failing_sockets_
= true;
828 transaction_ids_
.push_back(0); // Needed to make a DnsUDPAttempt.
829 TransactionHelper
helper0("www.chromium.org", dns_protocol::kTypeA
,
830 ERR_CONNECTION_REFUSED
);
831 EXPECT_TRUE(helper0
.Run(transaction_factory_
.get()));