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()));