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