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