• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4 
5 #include "net/dns/dns_transaction.h"
6 
7 #include "base/bind.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"
22 
23 namespace net {
24 
25 namespace {
26 
DomainFromDot(const base::StringPiece & dotted)27 std::string DomainFromDot(const base::StringPiece& dotted) {
28   std::string out;
29   EXPECT_TRUE(DNSDomainFromDot(dotted, &out));
30   return out;
31 }
32 
33 // A SocketDataProvider builder.
34 class DnsSocketData {
35  public:
36   // The ctor takes parameters for the DnsQuery.
DnsSocketData(uint16 id,const char * dotted_name,uint16 qtype,IoMode mode,bool use_tcp)37   DnsSocketData(uint16 id,
38                 const char* dotted_name,
39                 uint16 qtype,
40                 IoMode mode,
41                 bool use_tcp)
42       : query_(new DnsQuery(id, DomainFromDot(dotted_name), qtype)),
43         use_tcp_(use_tcp) {
44     if (use_tcp_) {
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()),
49                                   sizeof(uint16)));
50       lengths_.push_back(length.release());
51     }
52     writes_.push_back(MockWrite(mode,
53                                 query_->io_buffer()->data(),
54                                 query_->io_buffer()->size()));
55   }
~DnsSocketData()56   ~DnsSocketData() {}
57 
58   // All responses must be added before GetProvider.
59 
60   // Adds pre-built DnsResponse. |tcp_length| will be used in TCP mode only.
AddResponseWithLength(scoped_ptr<DnsResponse> response,IoMode mode,uint16 tcp_length)61   void AddResponseWithLength(scoped_ptr<DnsResponse> response, IoMode mode,
62                              uint16 tcp_length) {
63     CHECK(!provider_.get());
64     if (use_tcp_) {
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()),
69                                 sizeof(uint16)));
70       lengths_.push_back(length.release());
71     }
72     reads_.push_back(MockRead(mode,
73                               response->io_buffer()->data(),
74                               response->io_buffer()->size()));
75     responses_.push_back(response.release());
76   }
77 
78   // Adds pre-built DnsResponse.
AddResponse(scoped_ptr<DnsResponse> response,IoMode mode)79   void AddResponse(scoped_ptr<DnsResponse> response, IoMode mode) {
80     uint16 tcp_length = response->io_buffer()->size();
81     AddResponseWithLength(response.Pass(), mode, tcp_length);
82   }
83 
84   // Adds pre-built response from |data| buffer.
AddResponseData(const uint8 * data,size_t length,IoMode mode)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);
89   }
90 
91   // Add no-answer (RCODE only) response matching the query.
AddRcode(int rcode,IoMode mode)92   void AddRcode(int rcode, IoMode mode) {
93     scoped_ptr<DnsResponse> response(
94         new DnsResponse(query_->io_buffer()->data(),
95                         query_->io_buffer()->size(),
96                         0));
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);
101   }
102 
103   // Build, if needed, and return the SocketDataProvider. No new responses
104   // should be added afterwards.
GetProvider()105   SocketDataProvider* GetProvider() {
106     if (provider_.get())
107       return provider_.get();
108     // Terminate the reads with ERR_IO_PENDING to prevent overrun and default to
109     // timeout.
110     reads_.push_back(MockRead(ASYNC, ERR_IO_PENDING));
111     provider_.reset(new DelayedSocketData(1, &reads_[0], reads_.size(),
112                                           &writes_[0], writes_.size()));
113     if (use_tcp_) {
114       provider_->set_connect_data(MockConnect(reads_[0].mode, OK));
115     }
116     return provider_.get();
117   }
118 
query_id() const119   uint16 query_id() const {
120     return query_->id();
121   }
122 
123   // Returns true if the expected query was written to the socket.
was_written() const124   bool was_written() const {
125     CHECK(provider_.get());
126     return provider_->write_index() > 0;
127   }
128 
129  private:
130   scoped_ptr<DnsQuery> query_;
131   bool use_tcp_;
132   ScopedVector<uint16> lengths_;
133   ScopedVector<DnsResponse> responses_;
134   std::vector<MockWrite> writes_;
135   std::vector<MockRead> reads_;
136   scoped_ptr<DelayedSocketData> provider_;
137 
138   DISALLOW_COPY_AND_ASSIGN(DnsSocketData);
139 };
140 
141 class TestSocketFactory;
142 
143 // A variant of MockUDPClientSocket which always fails to Connect.
144 class FailingUDPClientSocket : public MockUDPClientSocket {
145  public:
FailingUDPClientSocket(SocketDataProvider * data,net::NetLog * net_log)146   FailingUDPClientSocket(SocketDataProvider* data,
147                          net::NetLog* net_log)
148       : MockUDPClientSocket(data, net_log) {
149   }
~FailingUDPClientSocket()150   virtual ~FailingUDPClientSocket() {}
Connect(const IPEndPoint & endpoint)151   virtual int Connect(const IPEndPoint& endpoint) OVERRIDE {
152     return ERR_CONNECTION_REFUSED;
153   }
154 
155  private:
156   DISALLOW_COPY_AND_ASSIGN(FailingUDPClientSocket);
157 };
158 
159 // A variant of MockUDPClientSocket which notifies the factory OnConnect.
160 class TestUDPClientSocket : public MockUDPClientSocket {
161  public:
TestUDPClientSocket(TestSocketFactory * factory,SocketDataProvider * data,net::NetLog * net_log)162   TestUDPClientSocket(TestSocketFactory* factory,
163                       SocketDataProvider* data,
164                       net::NetLog* net_log)
165       : MockUDPClientSocket(data, net_log), factory_(factory) {
166   }
~TestUDPClientSocket()167   virtual ~TestUDPClientSocket() {}
168   virtual int Connect(const IPEndPoint& endpoint) OVERRIDE;
169 
170  private:
171   TestSocketFactory* factory_;
172 
173   DISALLOW_COPY_AND_ASSIGN(TestUDPClientSocket);
174 };
175 
176 // Creates TestUDPClientSockets and keeps endpoints reported via OnConnect.
177 class TestSocketFactory : public MockClientSocketFactory {
178  public:
TestSocketFactory()179   TestSocketFactory() : fail_next_socket_(false) {}
~TestSocketFactory()180   virtual ~TestSocketFactory() {}
181 
CreateDatagramClientSocket(DatagramSocket::BindType bind_type,const RandIntCallback & rand_int_cb,net::NetLog * net_log,const net::NetLog::Source & source)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));
191     }
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>();
197   }
198 
OnConnect(const IPEndPoint & endpoint)199   void OnConnect(const IPEndPoint& endpoint) {
200     remote_endpoints_.push_back(endpoint);
201   }
202 
203   std::vector<IPEndPoint> remote_endpoints_;
204   bool fail_next_socket_;
205 
206  private:
207   StaticSocketDataProvider empty_data_;
208 
209   DISALLOW_COPY_AND_ASSIGN(TestSocketFactory);
210 };
211 
Connect(const IPEndPoint & endpoint)212 int TestUDPClientSocket::Connect(const IPEndPoint& endpoint) {
213   factory_->OnConnect(endpoint);
214   return MockUDPClientSocket::Connect(endpoint);
215 }
216 
217 // Helper class that holds a DnsTransaction and handles OnTransactionComplete.
218 class TransactionHelper {
219  public:
220   // If |expected_answer_count| < 0 then it is the expected net error.
TransactionHelper(const char * hostname,uint16 qtype,int expected_answer_count)221   TransactionHelper(const char* hostname,
222                     uint16 qtype,
223                     int expected_answer_count)
224       : hostname_(hostname),
225         qtype_(qtype),
226         expected_answer_count_(expected_answer_count),
227         cancel_in_callback_(false),
228         quit_in_callback_(false),
229         completed_(false) {
230   }
231 
232   // Mark that the transaction shall be destroyed immediately upon callback.
set_cancel_in_callback()233   void set_cancel_in_callback() {
234     cancel_in_callback_ = true;
235   }
236 
237   // Mark to call MessageLoop::Quit() upon callback.
set_quit_in_callback()238   void set_quit_in_callback() {
239     quit_in_callback_ = true;
240   }
241 
StartTransaction(DnsTransactionFactory * factory)242   void StartTransaction(DnsTransactionFactory* factory) {
243     EXPECT_EQ(NULL, transaction_.get());
244     transaction_ = factory->CreateTransaction(
245         hostname_,
246         qtype_,
247         base::Bind(&TransactionHelper::OnTransactionComplete,
248                    base::Unretained(this)),
249         BoundNetLog());
250     EXPECT_EQ(hostname_, transaction_->GetHostname());
251     EXPECT_EQ(qtype_, transaction_->GetType());
252     transaction_->Start();
253   }
254 
Cancel()255   void Cancel() {
256     ASSERT_TRUE(transaction_.get() != NULL);
257     transaction_.reset(NULL);
258   }
259 
OnTransactionComplete(DnsTransaction * t,int rv,const DnsResponse * response)260   void OnTransactionComplete(DnsTransaction* t,
261                              int rv,
262                              const DnsResponse* response) {
263     EXPECT_FALSE(completed_);
264     EXPECT_EQ(transaction_.get(), t);
265 
266     completed_ = true;
267 
268     if (cancel_in_callback_) {
269       Cancel();
270       return;
271     }
272 
273     // Tell MessageLoop to quit now, in case any ASSERT_* fails.
274     if (quit_in_callback_)
275       base::MessageLoop::current()->Quit();
276 
277     if (expected_answer_count_ >= 0) {
278       ASSERT_EQ(OK, rv);
279       ASSERT_TRUE(response != NULL);
280       EXPECT_EQ(static_cast<unsigned>(expected_answer_count_),
281                 response->answer_count());
282       EXPECT_EQ(qtype_, response->qtype());
283 
284       DnsRecordParser parser = response->Parser();
285       DnsResourceRecord record;
286       for (int i = 0; i < expected_answer_count_; ++i) {
287         EXPECT_TRUE(parser.ReadRecord(&record));
288       }
289     } else {
290       EXPECT_EQ(expected_answer_count_, rv);
291     }
292   }
293 
has_completed() const294   bool has_completed() const {
295     return completed_;
296   }
297 
298   // Shorthands for commonly used commands.
299 
Run(DnsTransactionFactory * factory)300   bool Run(DnsTransactionFactory* factory) {
301     StartTransaction(factory);
302     base::MessageLoop::current()->RunUntilIdle();
303     return has_completed();
304   }
305 
306   // Use when some of the responses are timeouts.
RunUntilDone(DnsTransactionFactory * factory)307   bool RunUntilDone(DnsTransactionFactory* factory) {
308     set_quit_in_callback();
309     StartTransaction(factory);
310     base::MessageLoop::current()->Run();
311     return has_completed();
312   }
313 
314  private:
315   std::string hostname_;
316   uint16 qtype_;
317   scoped_ptr<DnsTransaction> transaction_;
318   int expected_answer_count_;
319   bool cancel_in_callback_;
320   bool quit_in_callback_;
321 
322   bool completed_;
323 };
324 
325 class DnsTransactionTest : public testing::Test {
326  public:
DnsTransactionTest()327   DnsTransactionTest() {}
328 
329   // Generates |nameservers| for DnsConfig.
ConfigureNumServers(unsigned num_servers)330   void ConfigureNumServers(unsigned num_servers) {
331     CHECK_LE(num_servers, 255u);
332     config_.nameservers.clear();
333     IPAddressNumber dns_ip;
334     {
335       bool rv = ParseIPLiteralToNumber("192.168.1.0", &dns_ip);
336       EXPECT_TRUE(rv);
337     }
338     for (unsigned i = 0; i < num_servers; ++i) {
339       dns_ip[3] = i;
340       config_.nameservers.push_back(IPEndPoint(dns_ip,
341                                                dns_protocol::kDefaultPort));
342     }
343   }
344 
345   // Called after fully configuring |config|.
ConfigureFactory()346   void ConfigureFactory() {
347     socket_factory_.reset(new TestSocketFactory());
348     session_ = new DnsSession(
349         config_,
350         DnsSocketPool::CreateNull(socket_factory_.get()),
351         base::Bind(&DnsTransactionTest::GetNextId, base::Unretained(this)),
352         NULL /* NetLog */);
353     transaction_factory_ = DnsTransactionFactory::CreateFactory(session_.get());
354   }
355 
AddSocketData(scoped_ptr<DnsSocketData> data)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());
361   }
362 
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.
AddQueryAndResponse(uint16 id,const char * dotted_name,uint16 qtype,const uint8 * response_data,size_t response_length,IoMode mode,bool use_tcp)366   void AddQueryAndResponse(uint16 id,
367                            const char* dotted_name,
368                            uint16 qtype,
369                            const uint8* response_data,
370                            size_t response_length,
371                            IoMode mode,
372                            bool use_tcp) {
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());
378   }
379 
AddAsyncQueryAndResponse(uint16 id,const char * dotted_name,uint16 qtype,const uint8 * data,size_t data_length)380   void AddAsyncQueryAndResponse(uint16 id,
381                                 const char* dotted_name,
382                                 uint16 qtype,
383                                 const uint8* data,
384                                 size_t data_length) {
385     AddQueryAndResponse(id, dotted_name, qtype, data, data_length, ASYNC,
386                         false);
387   }
388 
AddSyncQueryAndResponse(uint16 id,const char * dotted_name,uint16 qtype,const uint8 * data,size_t data_length)389   void AddSyncQueryAndResponse(uint16 id,
390                                const char* dotted_name,
391                                uint16 qtype,
392                                const uint8* data,
393                                size_t data_length) {
394     AddQueryAndResponse(id, dotted_name, qtype, data, data_length, SYNCHRONOUS,
395                         false);
396   }
397 
398   // Add expected query of |dotted_name| and |qtype| and no response.
AddQueryAndTimeout(const char * dotted_name,uint16 qtype)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());
404   }
405 
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.
AddQueryAndRcode(const char * dotted_name,uint16 qtype,int rcode,IoMode mode,bool use_tcp)408   void AddQueryAndRcode(const char* dotted_name,
409                         uint16 qtype,
410                         int rcode,
411                         IoMode mode,
412                         bool use_tcp) {
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());
419   }
420 
AddAsyncQueryAndRcode(const char * dotted_name,uint16 qtype,int rcode)421   void AddAsyncQueryAndRcode(const char* dotted_name, uint16 qtype, int rcode) {
422     AddQueryAndRcode(dotted_name, qtype, rcode, ASYNC, false);
423   }
424 
AddSyncQueryAndRcode(const char * dotted_name,uint16 qtype,int rcode)425   void AddSyncQueryAndRcode(const char* dotted_name, uint16 qtype, int rcode) {
426     AddQueryAndRcode(dotted_name, qtype, rcode, SYNCHRONOUS, false);
427   }
428 
429   // Checks if the sockets were connected in the order matching the indices in
430   // |servers|.
CheckServerOrder(const unsigned * servers,size_t num_attempts)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]]);
436     }
437   }
438 
SetUp()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();
446     ConfigureFactory();
447   }
448 
TearDown()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;
453     }
454   }
455 
456  protected:
GetNextId(int min,int max)457   int GetNextId(int min, int max) {
458     EXPECT_FALSE(transaction_ids_.empty());
459     int id = transaction_ids_.front();
460     transaction_ids_.pop_front();
461     EXPECT_GE(id, min);
462     EXPECT_LE(id, max);
463     return id;
464   }
465 
466   DnsConfig config_;
467 
468   ScopedVector<DnsSocketData> socket_data_;
469 
470   std::deque<int> transaction_ids_;
471   scoped_ptr<TestSocketFactory> socket_factory_;
472   scoped_refptr<DnsSession> session_;
473   scoped_ptr<DnsTransactionFactory> transaction_factory_;
474 };
475 
TEST_F(DnsTransactionTest,Lookup)476 TEST_F(DnsTransactionTest, Lookup) {
477   AddAsyncQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype,
478                            kT0ResponseDatagram, arraysize(kT0ResponseDatagram));
479 
480   TransactionHelper helper0(kT0HostName, kT0Qtype, kT0RecordCount);
481   EXPECT_TRUE(helper0.Run(transaction_factory_.get()));
482 }
483 
484 // Concurrent lookup tests assume that DnsTransaction::Start immediately
485 // consumes a socket from ClientSocketFactory.
TEST_F(DnsTransactionTest,ConcurrentLookup)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));
491 
492   TransactionHelper helper0(kT0HostName, kT0Qtype, kT0RecordCount);
493   helper0.StartTransaction(transaction_factory_.get());
494   TransactionHelper helper1(kT1HostName, kT1Qtype, kT1RecordCount);
495   helper1.StartTransaction(transaction_factory_.get());
496 
497   base::MessageLoop::current()->RunUntilIdle();
498 
499   EXPECT_TRUE(helper0.has_completed());
500   EXPECT_TRUE(helper1.has_completed());
501 }
502 
TEST_F(DnsTransactionTest,CancelLookup)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));
508 
509   TransactionHelper helper0(kT0HostName, kT0Qtype, kT0RecordCount);
510   helper0.StartTransaction(transaction_factory_.get());
511   TransactionHelper helper1(kT1HostName, kT1Qtype, kT1RecordCount);
512   helper1.StartTransaction(transaction_factory_.get());
513 
514   helper0.Cancel();
515 
516   base::MessageLoop::current()->RunUntilIdle();
517 
518   EXPECT_FALSE(helper0.has_completed());
519   EXPECT_TRUE(helper1.has_completed());
520 }
521 
TEST_F(DnsTransactionTest,DestroyFactory)522 TEST_F(DnsTransactionTest, DestroyFactory) {
523   AddAsyncQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype,
524                            kT0ResponseDatagram, arraysize(kT0ResponseDatagram));
525 
526   TransactionHelper helper0(kT0HostName, kT0Qtype, kT0RecordCount);
527   helper0.StartTransaction(transaction_factory_.get());
528 
529   // Destroying the client does not affect running requests.
530   transaction_factory_.reset(NULL);
531 
532   base::MessageLoop::current()->RunUntilIdle();
533 
534   EXPECT_TRUE(helper0.has_completed());
535 }
536 
TEST_F(DnsTransactionTest,CancelFromCallback)537 TEST_F(DnsTransactionTest, CancelFromCallback) {
538   AddAsyncQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype,
539                            kT0ResponseDatagram, arraysize(kT0ResponseDatagram));
540 
541   TransactionHelper helper0(kT0HostName, kT0Qtype, kT0RecordCount);
542   helper0.set_cancel_in_callback();
543   EXPECT_TRUE(helper0.Run(transaction_factory_.get()));
544 }
545 
TEST_F(DnsTransactionTest,MismatchedResponseSync)546 TEST_F(DnsTransactionTest, MismatchedResponseSync) {
547   config_.attempts = 2;
548   config_.timeout = TestTimeouts::tiny_timeout();
549   ConfigureFactory();
550 
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());
559 
560   TransactionHelper helper0(kT0HostName, kT0Qtype, kT0RecordCount);
561   EXPECT_TRUE(helper0.RunUntilDone(transaction_factory_.get()));
562 }
563 
TEST_F(DnsTransactionTest,MismatchedResponseAsync)564 TEST_F(DnsTransactionTest, MismatchedResponseAsync) {
565   config_.attempts = 2;
566   config_.timeout = TestTimeouts::tiny_timeout();
567   ConfigureFactory();
568 
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);
579 
580   TransactionHelper helper0(kT0HostName, kT0Qtype, kT0RecordCount);
581   EXPECT_TRUE(helper0.RunUntilDone(transaction_factory_.get()));
582 }
583 
TEST_F(DnsTransactionTest,MismatchedResponseFail)584 TEST_F(DnsTransactionTest, MismatchedResponseFail) {
585   config_.timeout = TestTimeouts::tiny_timeout();
586   ConfigureFactory();
587 
588   // Attempt receives mismatched response but times out because only one attempt
589   // is allowed.
590   AddAsyncQueryAndResponse(1 /* id */, kT0HostName, kT0Qtype,
591                            kT0ResponseDatagram, arraysize(kT0ResponseDatagram));
592 
593   TransactionHelper helper0(kT0HostName, kT0Qtype, ERR_DNS_TIMED_OUT);
594   EXPECT_TRUE(helper0.RunUntilDone(transaction_factory_.get()));
595 }
596 
TEST_F(DnsTransactionTest,ServerFail)597 TEST_F(DnsTransactionTest, ServerFail) {
598   AddAsyncQueryAndRcode(kT0HostName, kT0Qtype, dns_protocol::kRcodeSERVFAIL);
599 
600   TransactionHelper helper0(kT0HostName, kT0Qtype, ERR_DNS_SERVER_FAILED);
601   EXPECT_TRUE(helper0.Run(transaction_factory_.get()));
602 }
603 
TEST_F(DnsTransactionTest,NoDomain)604 TEST_F(DnsTransactionTest, NoDomain) {
605   AddAsyncQueryAndRcode(kT0HostName, kT0Qtype, dns_protocol::kRcodeNXDOMAIN);
606 
607   TransactionHelper helper0(kT0HostName, kT0Qtype, ERR_NAME_NOT_RESOLVED);
608   EXPECT_TRUE(helper0.Run(transaction_factory_.get()));
609 }
610 
TEST_F(DnsTransactionTest,Timeout)611 TEST_F(DnsTransactionTest, Timeout) {
612   config_.attempts = 3;
613   // Use short timeout to speed up the test.
614   config_.timeout = TestTimeouts::tiny_timeout();
615   ConfigureFactory();
616 
617   AddQueryAndTimeout(kT0HostName, kT0Qtype);
618   AddQueryAndTimeout(kT0HostName, kT0Qtype);
619   AddQueryAndTimeout(kT0HostName, kT0Qtype);
620 
621   TransactionHelper helper0(kT0HostName, kT0Qtype, ERR_DNS_TIMED_OUT);
622   EXPECT_TRUE(helper0.RunUntilDone(transaction_factory_.get()));
623   EXPECT_TRUE(base::MessageLoop::current()->IsIdleForTesting());
624 }
625 
TEST_F(DnsTransactionTest,ServerFallbackAndRotate)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();
634   ConfigureFactory();
635 
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);
646 
647   TransactionHelper helper0(kT0HostName, kT0Qtype, ERR_NAME_NOT_RESOLVED);
648   TransactionHelper helper1(kT1HostName, kT1Qtype, ERR_NAME_NOT_RESOLVED);
649 
650   EXPECT_TRUE(helper0.RunUntilDone(transaction_factory_.get()));
651   EXPECT_TRUE(helper1.Run(transaction_factory_.get()));
652 
653   unsigned kOrder[] = {
654       0, 1, 2, 0, 1,    // The first transaction.
655       1, 2, 0,          // The second transaction starts from the next server.
656   };
657   CheckServerOrder(kOrder, arraysize(kOrder));
658 }
659 
TEST_F(DnsTransactionTest,SuffixSearchAboveNdots)660 TEST_F(DnsTransactionTest, SuffixSearchAboveNdots) {
661   config_.ndots = 2;
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);
667   ConfigureFactory();
668 
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);
677 
678   TransactionHelper helper0("x.y.z", dns_protocol::kTypeA,
679                             ERR_NAME_NOT_RESOLVED);
680 
681   EXPECT_TRUE(helper0.Run(transaction_factory_.get()));
682 
683   // Also check if suffix search causes server rotation.
684   unsigned kOrder0[] = { 0, 1, 0, 1 };
685   CheckServerOrder(kOrder0, arraysize(kOrder0));
686 }
687 
TEST_F(DnsTransactionTest,SuffixSearchBelowNdots)688 TEST_F(DnsTransactionTest, SuffixSearchBelowNdots) {
689   config_.ndots = 2;
690   config_.search.push_back("a");
691   config_.search.push_back("b");
692   config_.search.push_back("c");
693   ConfigureFactory();
694 
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);
714 
715   TransactionHelper helper0("x.y", dns_protocol::kTypeA, ERR_NAME_NOT_RESOLVED);
716 
717   EXPECT_TRUE(helper0.Run(transaction_factory_.get()));
718 
719   // A single-label name.
720   TransactionHelper helper1("x", dns_protocol::kTypeA, ERR_NAME_NOT_RESOLVED);
721 
722   EXPECT_TRUE(helper1.Run(transaction_factory_.get()));
723 
724   // A fully-qualified name.
725   TransactionHelper helper2("x.", dns_protocol::kTypeAAAA,
726                             ERR_NAME_NOT_RESOLVED);
727 
728   EXPECT_TRUE(helper2.Run(transaction_factory_.get()));
729 }
730 
TEST_F(DnsTransactionTest,EmptySuffixSearch)731 TEST_F(DnsTransactionTest, EmptySuffixSearch) {
732   // Responses for first transaction.
733   AddAsyncQueryAndRcode("x", dns_protocol::kTypeA,
734                         dns_protocol::kRcodeNXDOMAIN);
735 
736   // A fully-qualified name.
737   TransactionHelper helper0("x.", dns_protocol::kTypeA, ERR_NAME_NOT_RESOLVED);
738 
739   EXPECT_TRUE(helper0.Run(transaction_factory_.get()));
740 
741   // A single label name is not even attempted.
742   TransactionHelper helper1("singlelabel", dns_protocol::kTypeA,
743                             ERR_DNS_SEARCH_EMPTY);
744 
745   helper1.Run(transaction_factory_.get());
746   EXPECT_TRUE(helper1.has_completed());
747 }
748 
TEST_F(DnsTransactionTest,DontAppendToMultiLabelName)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;
754   ConfigureFactory();
755 
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);
769 
770   TransactionHelper helper0("x.y.z", dns_protocol::kTypeA,
771                             ERR_NAME_NOT_RESOLVED);
772   EXPECT_TRUE(helper0.Run(transaction_factory_.get()));
773 
774   TransactionHelper helper1("x.y", dns_protocol::kTypeA, ERR_NAME_NOT_RESOLVED);
775   EXPECT_TRUE(helper1.Run(transaction_factory_.get()));
776 
777   TransactionHelper helper2("x", dns_protocol::kTypeA, ERR_NAME_NOT_RESOLVED);
778   EXPECT_TRUE(helper2.Run(transaction_factory_.get()));
779 }
780 
781 const uint8 kResponseNoData[] = {
782   0x00, 0x00, 0x81, 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
783   // Question
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
788   0x00, 0x12,
789   0x00, 0x00,
790   0x00, 0x00, 0x00, 0x00,
791   0x00, 0x00, 0x00, 0x00,
792   0x00, 0x00, 0x00, 0x00,
793   0x00, 0x00, 0x00, 0x00,
794 };
795 
TEST_F(DnsTransactionTest,SuffixSearchStop)796 TEST_F(DnsTransactionTest, SuffixSearchStop) {
797   config_.ndots = 2;
798   config_.search.push_back("a");
799   config_.search.push_back("b");
800   config_.search.push_back("c");
801   ConfigureFactory();
802 
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));
809 
810   TransactionHelper helper0("x.y.z", dns_protocol::kTypeA, 0 /* answers */);
811 
812   EXPECT_TRUE(helper0.Run(transaction_factory_.get()));
813 }
814 
TEST_F(DnsTransactionTest,SyncFirstQuery)815 TEST_F(DnsTransactionTest, SyncFirstQuery) {
816   config_.search.push_back("lab.ccs.neu.edu");
817   config_.search.push_back("ccs.neu.edu");
818   ConfigureFactory();
819 
820   AddSyncQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype,
821                           kT0ResponseDatagram, arraysize(kT0ResponseDatagram));
822 
823   TransactionHelper helper0(kT0HostName, kT0Qtype, kT0RecordCount);
824   EXPECT_TRUE(helper0.Run(transaction_factory_.get()));
825 }
826 
TEST_F(DnsTransactionTest,SyncFirstQueryWithSearch)827 TEST_F(DnsTransactionTest, SyncFirstQueryWithSearch) {
828   config_.search.push_back("lab.ccs.neu.edu");
829   config_.search.push_back("ccs.neu.edu");
830   ConfigureFactory();
831 
832   AddSyncQueryAndRcode("www.lab.ccs.neu.edu", kT2Qtype,
833                        dns_protocol::kRcodeNXDOMAIN);
834   // "www.ccs.neu.edu"
835   AddAsyncQueryAndResponse(2 /* id */, kT2HostName, kT2Qtype,
836                            kT2ResponseDatagram, arraysize(kT2ResponseDatagram));
837 
838   TransactionHelper helper0("www", kT2Qtype, kT2RecordCount);
839   EXPECT_TRUE(helper0.Run(transaction_factory_.get()));
840 }
841 
TEST_F(DnsTransactionTest,SyncSearchQuery)842 TEST_F(DnsTransactionTest, SyncSearchQuery) {
843   config_.search.push_back("lab.ccs.neu.edu");
844   config_.search.push_back("ccs.neu.edu");
845   ConfigureFactory();
846 
847   AddAsyncQueryAndRcode("www.lab.ccs.neu.edu", dns_protocol::kTypeA,
848                         dns_protocol::kRcodeNXDOMAIN);
849   AddSyncQueryAndResponse(2 /* id */, kT2HostName, kT2Qtype,
850                           kT2ResponseDatagram, arraysize(kT2ResponseDatagram));
851 
852   TransactionHelper helper0("www", kT2Qtype, kT2RecordCount);
853   EXPECT_TRUE(helper0.Run(transaction_factory_.get()));
854 }
855 
TEST_F(DnsTransactionTest,ConnectFailure)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()));
862 }
863 
TEST_F(DnsTransactionTest,ConnectFailureFollowedBySuccess)864 TEST_F(DnsTransactionTest, ConnectFailureFollowedBySuccess) {
865   // Retry after server failure.
866   config_.attempts = 2;
867   ConfigureFactory();
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()));
876 }
877 
TEST_F(DnsTransactionTest,TCPLookup)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 */);
884 
885   TransactionHelper helper0(kT0HostName, kT0Qtype, kT0RecordCount);
886   EXPECT_TRUE(helper0.Run(transaction_factory_.get()));
887 }
888 
TEST_F(DnsTransactionTest,TCPFailure)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 */);
894 
895   TransactionHelper helper0(kT0HostName, kT0Qtype, ERR_DNS_SERVER_FAILED);
896   EXPECT_TRUE(helper0.Run(transaction_factory_.get()));
897 }
898 
TEST_F(DnsTransactionTest,TCPMalformed)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(
906       make_scoped_ptr(
907           new DnsResponse(reinterpret_cast<const char*>(kT0ResponseDatagram),
908                           arraysize(kT0ResponseDatagram), 0)),
909       ASYNC,
910       static_cast<uint16>(kT0QuerySize - 1));
911   AddSocketData(data.Pass());
912 
913   TransactionHelper helper0(kT0HostName, kT0Qtype, ERR_DNS_MALFORMED_RESPONSE);
914   EXPECT_TRUE(helper0.Run(transaction_factory_.get()));
915 }
916 
TEST_F(DnsTransactionTest,TCPTimeout)917 TEST_F(DnsTransactionTest, TCPTimeout) {
918   config_.timeout = TestTimeouts::tiny_timeout();
919   ConfigureFactory();
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)));
924 
925   TransactionHelper helper0(kT0HostName, kT0Qtype, ERR_DNS_TIMED_OUT);
926   EXPECT_TRUE(helper0.RunUntilDone(transaction_factory_.get()));
927 }
928 
TEST_F(DnsTransactionTest,InvalidQuery)929 TEST_F(DnsTransactionTest, InvalidQuery) {
930   config_.timeout = TestTimeouts::tiny_timeout();
931   ConfigureFactory();
932 
933   TransactionHelper helper0(".", dns_protocol::kTypeA, ERR_INVALID_ARGUMENT);
934   EXPECT_TRUE(helper0.Run(transaction_factory_.get()));
935 }
936 
937 }  // namespace
938 
939 }  // namespace net
940