recursive_query_unittest.cc 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868
  1. // Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // Permission to use, copy, modify, and/or distribute this software for any
  4. // purpose with or without fee is hereby granted, provided that the above
  5. // copyright notice and this permission notice appear in all copies.
  6. //
  7. // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
  8. // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  9. // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
  10. // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  11. // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  12. // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  13. // PERFORMANCE OF THIS SOFTWARE.
  14. #include <config.h>
  15. #include <sys/socket.h>
  16. #include <sys/time.h>
  17. #include <string.h>
  18. #include <boost/lexical_cast.hpp>
  19. #include <boost/bind.hpp>
  20. #include <boost/date_time/posix_time/posix_time_types.hpp>
  21. #include <gtest/gtest.h>
  22. #include <exceptions/exceptions.h>
  23. #include <dns/tests/unittest_util.h>
  24. #include <dns/rcode.h>
  25. #include <util/buffer.h>
  26. #include <dns/message.h>
  27. #include <nsas/nameserver_address_store.h>
  28. #include <cache/resolver_cache.h>
  29. #include <resolve/resolve.h>
  30. // IMPORTANT: We shouldn't directly use ASIO definitions in this test.
  31. // In particular, we must not include asio.hpp in this file.
  32. // The asiolink module is primarily intended to be a wrapper that hide the
  33. // details of the underlying implementations. We need to test the wrapper
  34. // level behaviors. In addition, some compilers reject to compile this file
  35. // if we include asio.hpp unless we specify a special compiler option.
  36. // If we need to test something at the level of underlying ASIO and need
  37. // their definition, that test should go to asiolink/internal/tests.
  38. #include <resolve/recursive_query.h>
  39. #include <asiodns/dns_lookup.h>
  40. #include <asiolink/io_socket.h>
  41. #include <asiolink/io_service.h>
  42. #include <asiolink/io_message.h>
  43. #include <asiolink/io_error.h>
  44. #include <asiolink/simple_callback.h>
  45. using isc::UnitTestUtil;
  46. using namespace std;
  47. using namespace isc::asiodns;
  48. using namespace isc::asiolink;
  49. using namespace isc::dns;
  50. using namespace isc::util;
  51. namespace {
  52. const char* const TEST_SERVER_PORT = "53535";
  53. const char* const TEST_CLIENT_PORT = "53536";
  54. const char* const TEST_IPV6_ADDR = "::1";
  55. const char* const TEST_IPV4_ADDR = "127.0.0.1";
  56. // This data is intended to be valid as a DNS/TCP-like message: the first
  57. // two octets encode the length of the rest of the data. This is crucial
  58. // for the tests below.
  59. const uint8_t test_data[] = {0, 4, 1, 2, 3, 4};
  60. // This function returns an addrinfo structure for use by tests, using
  61. // different addresses and ports depending on whether we're testing
  62. // IPv4 or v6, TCP or UDP, and client or server operation.
  63. struct addrinfo*
  64. resolveAddress(const int family, const int protocol, const bool client) {
  65. const char* const addr = (family == AF_INET6) ?
  66. TEST_IPV6_ADDR : TEST_IPV4_ADDR;
  67. const char* const port = client ? TEST_CLIENT_PORT : TEST_SERVER_PORT;
  68. struct addrinfo hints;
  69. memset(&hints, 0, sizeof(hints));
  70. hints.ai_family = family;
  71. hints.ai_socktype = (protocol == IPPROTO_UDP) ? SOCK_DGRAM : SOCK_STREAM;
  72. hints.ai_protocol = protocol;
  73. hints.ai_flags = AI_NUMERICSERV;
  74. struct addrinfo* res;
  75. const int error = getaddrinfo(addr, port, &hints, &res);
  76. if (error != 0) {
  77. isc_throw(IOError, "getaddrinfo failed: " << gai_strerror(error));
  78. }
  79. return (res);
  80. }
  81. // This fixture is a framework for various types of network operations
  82. // using the ASIO interfaces. Each test case creates an IOService object,
  83. // opens a local "client" socket for testing, sends data via the local socket
  84. // to the service that would run in the IOService object.
  85. // A mock callback function (an ASIOCallBack object) is registered with the
  86. // IOService object, so the test code should be able to examine the data
  87. // received on the server side. It then checks the received data matches
  88. // expected parameters.
  89. // If initialization parameters of the IOService should be modified, the test
  90. // case can do it using the setDNSService() method.
  91. // Note: the set of tests in RecursiveQueryTest use actual network services and may
  92. // involve undesirable side effects such as blocking.
  93. class RecursiveQueryTest : public ::testing::Test {
  94. protected:
  95. RecursiveQueryTest();
  96. ~RecursiveQueryTest() {
  97. if (res_ != NULL) {
  98. freeaddrinfo(res_);
  99. }
  100. if (sock_ != -1) {
  101. close(sock_);
  102. }
  103. delete dns_service_;
  104. delete callback_;
  105. delete io_service_;
  106. }
  107. // Send a test UDP packet to a mock server
  108. void sendUDP(const int family) {
  109. res_ = resolveAddress(family, IPPROTO_UDP, false);
  110. sock_ = socket(res_->ai_family, res_->ai_socktype, res_->ai_protocol);
  111. if (sock_ < 0) {
  112. isc_throw(IOError, "failed to open test socket");
  113. }
  114. const int cc = sendto(sock_, test_data, sizeof(test_data), 0,
  115. res_->ai_addr, res_->ai_addrlen);
  116. if (cc != sizeof(test_data)) {
  117. isc_throw(IOError, "unexpected sendto result: " << cc);
  118. }
  119. io_service_->run();
  120. }
  121. // Send a test TCP packet to a mock server
  122. void sendTCP(const int family) {
  123. res_ = resolveAddress(family, IPPROTO_TCP, false);
  124. sock_ = socket(res_->ai_family, res_->ai_socktype, res_->ai_protocol);
  125. if (sock_ < 0) {
  126. isc_throw(IOError, "failed to open test socket");
  127. }
  128. if (connect(sock_, res_->ai_addr, res_->ai_addrlen) < 0) {
  129. isc_throw(IOError, "failed to connect to the test server");
  130. }
  131. const int cc = send(sock_, test_data, sizeof(test_data), 0);
  132. if (cc != sizeof(test_data)) {
  133. isc_throw(IOError, "unexpected send result: " << cc);
  134. }
  135. io_service_->run();
  136. }
  137. // Receive a UDP packet from a mock server; used for testing
  138. // recursive lookup. The caller must place a RecursiveQuery
  139. // on the IO Service queue before running this routine.
  140. void recvUDP(const int family, void* buffer, size_t& size) {
  141. res_ = resolveAddress(family, IPPROTO_UDP, true);
  142. sock_ = socket(res_->ai_family, res_->ai_socktype, res_->ai_protocol);
  143. if (sock_ < 0) {
  144. isc_throw(IOError, "failed to open test socket");
  145. }
  146. if (bind(sock_, res_->ai_addr, res_->ai_addrlen) < 0) {
  147. isc_throw(IOError, "bind failed: " << strerror(errno));
  148. }
  149. // The IO service queue should have a RecursiveQuery object scheduled
  150. // to run at this point. This call will cause it to begin an
  151. // async send, then return.
  152. io_service_->run_one();
  153. // ... and this one will block until the send has completed
  154. io_service_->run_one();
  155. // Now we attempt to recv() whatever was sent.
  156. // XXX: there's no guarantee the receiving socket can immediately get
  157. // the packet. Normally we can perform blocking recv to wait for it,
  158. // but in theory it's even possible that the packet is lost.
  159. // In order to prevent the test from hanging in such a worst case
  160. // we add an ad hoc timeout.
  161. const struct timeval timeo = { 10, 0 };
  162. int recv_options = 0;
  163. if (setsockopt(sock_, SOL_SOCKET, SO_RCVTIMEO, &timeo,
  164. sizeof(timeo))) {
  165. if (errno == ENOPROTOOPT) {
  166. // Workaround for Solaris: it doesn't accept SO_RCVTIMEO
  167. // with the error of ENOPROTOOPT. Since this is a workaround
  168. // for rare error cases anyway, we simply switch to the
  169. // "don't wait" mode. If we still find an error in recv()
  170. // can happen often we'll consider a more complete solution.
  171. recv_options = MSG_DONTWAIT;
  172. } else {
  173. isc_throw(IOError, "set RCVTIMEO failed: " << strerror(errno));
  174. }
  175. }
  176. const int ret = recv(sock_, buffer, size, recv_options);
  177. if (ret < 0) {
  178. isc_throw(IOError, "recvfrom failed: " << strerror(errno));
  179. }
  180. // Pass the message size back via the size parameter
  181. size = ret;
  182. }
  183. // Set up an IO Service queue using the specified address
  184. void setDNSService(const char& address) {
  185. delete dns_service_;
  186. dns_service_ = NULL;
  187. delete io_service_;
  188. io_service_ = new IOService();
  189. callback_ = new ASIOCallBack(this);
  190. dns_service_ = new DNSService(*io_service_, *TEST_SERVER_PORT, address, callback_, NULL, NULL);
  191. }
  192. // Set up an IO Service queue using the "any" address, on IPv4 if
  193. // 'use_ipv4' is true and on IPv6 if 'use_ipv6' is true.
  194. void setDNSService(const bool use_ipv4, const bool use_ipv6) {
  195. delete dns_service_;
  196. dns_service_ = NULL;
  197. delete io_service_;
  198. io_service_ = new IOService();
  199. callback_ = new ASIOCallBack(this);
  200. dns_service_ = new DNSService(*io_service_, *TEST_SERVER_PORT, use_ipv4, use_ipv6, callback_,
  201. NULL, NULL);
  202. }
  203. // Set up empty DNS Service
  204. // Set up an IO Service queue without any addresses
  205. void setDNSService() {
  206. delete dns_service_;
  207. dns_service_ = NULL;
  208. delete io_service_;
  209. io_service_ = new IOService();
  210. callback_ = new ASIOCallBack(this);
  211. dns_service_ = new DNSService(*io_service_, callback_, NULL, NULL);
  212. }
  213. // Run a simple server test, on either IPv4 or IPv6, and over either
  214. // UDP or TCP. Calls the sendUDP() or sendTCP() methods, which will
  215. // start the IO Service queue. The UDPServer or TCPServer that was
  216. // created by setIOService() will receive the test packet and issue a
  217. // callback, which enables us to check that the data it received
  218. // matches what we sent.
  219. void doTest(const int family, const int protocol) {
  220. if (protocol == IPPROTO_UDP) {
  221. sendUDP(family);
  222. } else {
  223. sendTCP(family);
  224. }
  225. // There doesn't seem to be an effective test for the validity of
  226. // 'native'.
  227. // One thing we are sure is it must be different from our local socket.
  228. EXPECT_NE(sock_, callback_native_);
  229. EXPECT_EQ(protocol, callback_protocol_);
  230. EXPECT_EQ(family == AF_INET6 ? TEST_IPV6_ADDR : TEST_IPV4_ADDR,
  231. callback_address_);
  232. const uint8_t* expected_data =
  233. protocol == IPPROTO_UDP ? test_data : test_data + 2;
  234. const size_t expected_datasize =
  235. protocol == IPPROTO_UDP ? sizeof(test_data) :
  236. sizeof(test_data) - 2;
  237. EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, &callback_data_[0],
  238. callback_data_.size(),
  239. expected_data, expected_datasize);
  240. }
  241. protected:
  242. // This is a nonfunctional mockup of a DNSServer object. Its purpose
  243. // is to resume after a recursive query or other asynchronous call
  244. // has completed.
  245. class MockServer : public DNSServer {
  246. public:
  247. explicit MockServer(IOService& io_service,
  248. SimpleCallback* checkin = NULL,
  249. DNSLookup* lookup = NULL,
  250. DNSAnswer* answer = NULL) :
  251. io_(io_service),
  252. done_(false),
  253. message_(new Message(Message::PARSE)),
  254. answer_message_(new Message(Message::RENDER)),
  255. respbuf_(new OutputBuffer(0)),
  256. checkin_(checkin), lookup_(lookup), answer_(answer)
  257. {}
  258. void operator()(asio::error_code ec = asio::error_code(),
  259. size_t length = 0)
  260. {}
  261. void resume(const bool) {
  262. // should never be called in our tests
  263. }
  264. DNSServer* clone() {
  265. MockServer* s = new MockServer(*this);
  266. return (s);
  267. }
  268. inline void asyncLookup() {
  269. if (lookup_) {
  270. (*lookup_)(*io_message_, message_, answer_message_,
  271. respbuf_, this);
  272. }
  273. }
  274. protected:
  275. IOService& io_;
  276. bool done_;
  277. private:
  278. // Currently unused; these will be used for testing
  279. // asynchronous lookup calls via the asyncLookup() method
  280. boost::shared_ptr<isc::asiolink::IOMessage> io_message_;
  281. isc::dns::MessagePtr message_;
  282. isc::dns::MessagePtr answer_message_;
  283. isc::util::OutputBufferPtr respbuf_;
  284. // Callback functions provided by the caller
  285. const SimpleCallback* checkin_;
  286. const DNSLookup* lookup_;
  287. const DNSAnswer* answer_;
  288. };
  289. // This version of mock server just stops the io_service when it is resumed
  290. class MockServerStop : public MockServer {
  291. public:
  292. explicit MockServerStop(IOService& io_service, bool* done) :
  293. MockServer(io_service),
  294. done_(done)
  295. {}
  296. void resume(const bool done) {
  297. *done_ = done;
  298. io_.stop();
  299. }
  300. DNSServer* clone() {
  301. return (new MockServerStop(*this));
  302. }
  303. private:
  304. bool* done_;
  305. };
  306. class MockResolver : public isc::resolve::ResolverInterface {
  307. void resolve(const QuestionPtr& question,
  308. const ResolverInterface::CallbackPtr& callback) {
  309. }
  310. };
  311. // This version of mock server just stops the io_service when it is resumed
  312. // the second time. (Used in the clientTimeout test, where resume
  313. // is called initially with the error answer, and later when the
  314. // lookup times out, it is called without an answer to send back)
  315. class MockServerStop2 : public MockServer {
  316. public:
  317. explicit MockServerStop2(IOService& io_service,
  318. bool* done1, bool* done2) :
  319. MockServer(io_service),
  320. done1_(done1),
  321. done2_(done2),
  322. stopped_once_(false)
  323. {}
  324. void resume(const bool done) {
  325. if (stopped_once_) {
  326. *done2_ = done;
  327. io_.stop();
  328. } else {
  329. *done1_ = done;
  330. stopped_once_ = true;
  331. }
  332. }
  333. DNSServer* clone() {
  334. return (new MockServerStop2(*this));
  335. }
  336. private:
  337. bool* done1_;
  338. bool* done2_;
  339. bool stopped_once_;
  340. };
  341. private:
  342. class ASIOCallBack : public SimpleCallback {
  343. public:
  344. ASIOCallBack(RecursiveQueryTest* test_obj) : test_obj_(test_obj) {}
  345. void operator()(const IOMessage& io_message) const {
  346. test_obj_->callBack(io_message);
  347. }
  348. private:
  349. RecursiveQueryTest* test_obj_;
  350. };
  351. void callBack(const IOMessage& io_message) {
  352. callback_protocol_ = io_message.getSocket().getProtocol();
  353. callback_native_ = io_message.getSocket().getNative();
  354. callback_address_ =
  355. io_message.getRemoteEndpoint().getAddress().toText();
  356. callback_data_.assign(
  357. static_cast<const uint8_t*>(io_message.getData()),
  358. static_cast<const uint8_t*>(io_message.getData()) +
  359. io_message.getDataSize());
  360. io_service_->stop();
  361. }
  362. protected:
  363. // We use a pointer for io_service_, because for some tests we
  364. // need to recreate a new one within one onstance of this class
  365. IOService* io_service_;
  366. DNSService* dns_service_;
  367. isc::nsas::NameserverAddressStore* nsas_;
  368. isc::cache::ResolverCache cache_;
  369. ASIOCallBack* callback_;
  370. int callback_protocol_;
  371. int callback_native_;
  372. string callback_address_;
  373. vector<uint8_t> callback_data_;
  374. int sock_;
  375. struct addrinfo* res_;
  376. boost::shared_ptr<MockResolver> mock_resolver_;
  377. };
  378. RecursiveQueryTest::RecursiveQueryTest() :
  379. dns_service_(NULL), callback_(NULL), callback_protocol_(0),
  380. callback_native_(-1), sock_(-1), res_(NULL),
  381. mock_resolver_(new MockResolver())
  382. {
  383. io_service_ = new IOService();
  384. setDNSService(true, true);
  385. nsas_ = new isc::nsas::NameserverAddressStore(mock_resolver_);
  386. }
  387. TEST_F(RecursiveQueryTest, v6UDPSend) {
  388. doTest(AF_INET6, IPPROTO_UDP);
  389. }
  390. TEST_F(RecursiveQueryTest, v6TCPSend) {
  391. doTest(AF_INET6, IPPROTO_TCP);
  392. }
  393. TEST_F(RecursiveQueryTest, v4UDPSend) {
  394. doTest(AF_INET, IPPROTO_UDP);
  395. }
  396. TEST_F(RecursiveQueryTest, v4TCPSend) {
  397. doTest(AF_INET, IPPROTO_TCP);
  398. }
  399. TEST_F(RecursiveQueryTest, v6UDPSendSpecific) {
  400. // Explicitly set a specific address to be bound to the socket.
  401. // The subsequent test does not directly ensures the underlying socket
  402. // is bound to the expected address, but the success of the tests should
  403. // reasonably suggest it works as intended.
  404. // Specifying an address also implicitly means the service runs in a
  405. // single address-family mode. In tests using TCP we can confirm that
  406. // by trying to make a connection and seeing a failure. In UDP, it'd be
  407. // more complicated because we need to use a connected socket and catch
  408. // an error on a subsequent read operation. We could do it, but for
  409. // simplicity we only tests the easier cases for now.
  410. setDNSService(*TEST_IPV6_ADDR);
  411. doTest(AF_INET6, IPPROTO_UDP);
  412. }
  413. TEST_F(RecursiveQueryTest, v6TCPSendSpecific) {
  414. setDNSService(*TEST_IPV6_ADDR);
  415. doTest(AF_INET6, IPPROTO_TCP);
  416. EXPECT_THROW(sendTCP(AF_INET), IOError);
  417. }
  418. TEST_F(RecursiveQueryTest, v4UDPSendSpecific) {
  419. setDNSService(*TEST_IPV4_ADDR);
  420. doTest(AF_INET, IPPROTO_UDP);
  421. }
  422. TEST_F(RecursiveQueryTest, v4TCPSendSpecific) {
  423. setDNSService(*TEST_IPV4_ADDR);
  424. doTest(AF_INET, IPPROTO_TCP);
  425. EXPECT_THROW(sendTCP(AF_INET6), IOError);
  426. }
  427. TEST_F(RecursiveQueryTest, v6AddServer) {
  428. setDNSService();
  429. dns_service_->addServer(*TEST_SERVER_PORT, TEST_IPV6_ADDR);
  430. doTest(AF_INET6, IPPROTO_TCP);
  431. EXPECT_THROW(sendTCP(AF_INET), IOError);
  432. }
  433. TEST_F(RecursiveQueryTest, v4AddServer) {
  434. setDNSService();
  435. dns_service_->addServer(*TEST_SERVER_PORT, TEST_IPV4_ADDR);
  436. doTest(AF_INET, IPPROTO_TCP);
  437. EXPECT_THROW(sendTCP(AF_INET6), IOError);
  438. }
  439. TEST_F(RecursiveQueryTest, clearServers) {
  440. setDNSService();
  441. dns_service_->clearServers();
  442. EXPECT_THROW(sendTCP(AF_INET), IOError);
  443. EXPECT_THROW(sendTCP(AF_INET6), IOError);
  444. }
  445. TEST_F(RecursiveQueryTest, v6TCPOnly) {
  446. // Open only IPv6 TCP socket. A subsequent attempt of establishing an
  447. // IPv4/TCP connection should fail. See above for why we only test this
  448. // for TCP.
  449. setDNSService(false, true);
  450. EXPECT_THROW(sendTCP(AF_INET), IOError);
  451. }
  452. TEST_F(RecursiveQueryTest, v4TCPOnly) {
  453. setDNSService(true, false);
  454. EXPECT_THROW(sendTCP(AF_INET6), IOError);
  455. }
  456. vector<pair<string, uint16_t> >
  457. singleAddress(const string &address, uint16_t port) {
  458. vector<pair<string, uint16_t> > result;
  459. result.push_back(pair<string, uint16_t>(address, port));
  460. return (result);
  461. }
  462. TEST_F(RecursiveQueryTest, recursiveSetupV4) {
  463. setDNSService(true, false);
  464. uint16_t port = boost::lexical_cast<uint16_t>(TEST_CLIENT_PORT);
  465. EXPECT_NO_THROW(RecursiveQuery(*dns_service_,
  466. *nsas_, cache_,
  467. singleAddress(TEST_IPV4_ADDR, port),
  468. singleAddress(TEST_IPV4_ADDR, port)));
  469. }
  470. TEST_F(RecursiveQueryTest, recursiveSetupV6) {
  471. setDNSService(false, true);
  472. uint16_t port = boost::lexical_cast<uint16_t>(TEST_CLIENT_PORT);
  473. EXPECT_NO_THROW(RecursiveQuery(*dns_service_,
  474. *nsas_, cache_,
  475. singleAddress(TEST_IPV6_ADDR, port),
  476. singleAddress(TEST_IPV6_ADDR,port)));
  477. }
  478. // XXX:
  479. // This is very inadequate unit testing. It should be generalized into
  480. // a routine that can do this with variable address family, address, and
  481. // port, and with the various callbacks defined in such a way as to ensure
  482. // full code coverage including error cases.
  483. TEST_F(RecursiveQueryTest, forwarderSend) {
  484. setDNSService(true, false);
  485. // Note: We use the test prot plus one to ensure we aren't binding
  486. // to the same port as the actual server
  487. uint16_t port = boost::lexical_cast<uint16_t>(TEST_CLIENT_PORT);
  488. MockServer server(*io_service_);
  489. RecursiveQuery rq(*dns_service_,
  490. *nsas_, cache_,
  491. singleAddress(TEST_IPV4_ADDR, port),
  492. singleAddress(TEST_IPV4_ADDR, port));
  493. Question q(Name("example.com"), RRClass::IN(), RRType::TXT());
  494. Message query_message(Message::RENDER);
  495. isc::resolve::initResponseMessage(q, query_message);
  496. OutputBufferPtr buffer(new OutputBuffer(0));
  497. MessagePtr answer(new Message(Message::RENDER));
  498. rq.forward(ConstMessagePtr(&query_message), answer, buffer, &server);
  499. char data[4096];
  500. size_t size = sizeof(data);
  501. ASSERT_NO_THROW(recvUDP(AF_INET, data, size));
  502. Message m(Message::PARSE);
  503. InputBuffer ibuf(data, size);
  504. // Make sure we can parse the message that was sent
  505. EXPECT_NO_THROW(m.parseHeader(ibuf));
  506. EXPECT_NO_THROW(m.fromWire(ibuf));
  507. // Check that the question sent matches the one we wanted
  508. QuestionPtr q2 = *m.beginQuestion();
  509. EXPECT_EQ(q.getName(), q2->getName());
  510. EXPECT_EQ(q.getType(), q2->getType());
  511. EXPECT_EQ(q.getClass(), q2->getClass());
  512. }
  513. int
  514. createTestSocket()
  515. {
  516. struct addrinfo* res_ = resolveAddress(AF_INET, IPPROTO_UDP, true);
  517. int sock_ = socket(res_->ai_family, res_->ai_socktype, res_->ai_protocol);
  518. if (sock_ < 0) {
  519. isc_throw(IOError, "failed to open test socket");
  520. }
  521. if (bind(sock_, res_->ai_addr, res_->ai_addrlen) < 0) {
  522. isc_throw(IOError, "failed to bind test socket");
  523. }
  524. return sock_;
  525. }
  526. int
  527. setSocketTimeout(int sock_, size_t tv_sec, size_t tv_usec) {
  528. const struct timeval timeo = { tv_sec, tv_usec };
  529. int recv_options = 0;
  530. if (setsockopt(sock_, SOL_SOCKET, SO_RCVTIMEO, &timeo, sizeof(timeo))) {
  531. if (errno == ENOPROTOOPT) { // see RecursiveQueryTest::recvUDP()
  532. recv_options = MSG_DONTWAIT;
  533. } else {
  534. isc_throw(IOError, "set RCVTIMEO failed: " << strerror(errno));
  535. }
  536. }
  537. return recv_options;
  538. }
  539. // try to read from the socket max time
  540. // *num is incremented for every succesfull read
  541. // returns true if it can read max times, false otherwise
  542. bool tryRead(int sock_, int recv_options, size_t max, int* num) {
  543. size_t i = 0;
  544. do {
  545. char inbuff[512];
  546. if (recv(sock_, inbuff, sizeof(inbuff), recv_options) < 0) {
  547. return false;
  548. } else {
  549. ++i;
  550. ++*num;
  551. }
  552. } while (i < max);
  553. return true;
  554. }
  555. // Mock resolver callback for testing forward query.
  556. class MockResolverCallback : public isc::resolve::ResolverInterface::Callback {
  557. public:
  558. enum ResultValue {
  559. DEFAULT = 0,
  560. SUCCESS = 1,
  561. FAILURE = 2
  562. };
  563. MockResolverCallback(DNSServer* server):
  564. result(DEFAULT),
  565. server_(server->clone())
  566. {}
  567. ~MockResolverCallback() {
  568. delete server_;
  569. }
  570. void success(const isc::dns::MessagePtr response) {
  571. result = SUCCESS;
  572. server_->resume(true);
  573. }
  574. void failure() {
  575. result = FAILURE;
  576. server_->resume(false);
  577. }
  578. uint32_t result;
  579. private:
  580. DNSServer* server_;
  581. };
  582. // Test query timeout, set query timeout is lower than client timeout
  583. // and lookup timeout.
  584. TEST_F(RecursiveQueryTest, forwardQueryTimeout) {
  585. // Prepare the service (we do not use the common setup, we do not answer
  586. setDNSService();
  587. // Prepare the socket
  588. sock_ = createTestSocket();
  589. // Prepare the server
  590. bool done(true);
  591. MockServerStop server(*io_service_, &done);
  592. // Do the answer
  593. const uint16_t port = boost::lexical_cast<uint16_t>(TEST_CLIENT_PORT);
  594. RecursiveQuery query(*dns_service_,
  595. *nsas_, cache_,
  596. singleAddress(TEST_IPV4_ADDR, port),
  597. singleAddress(TEST_IPV4_ADDR, port),
  598. 10, 4000, 3000, 2);
  599. Question question(Name("example.net"), RRClass::IN(), RRType::A());
  600. OutputBufferPtr buffer(new OutputBuffer(0));
  601. MessagePtr answer(new Message(Message::RENDER));
  602. Message query_message(Message::RENDER);
  603. isc::resolve::initResponseMessage(question, query_message);
  604. boost::shared_ptr<MockResolverCallback> callback(new MockResolverCallback(&server));
  605. query.forward(ConstMessagePtr(&query_message), answer, buffer, &server, callback);
  606. // Run the test
  607. io_service_->run();
  608. EXPECT_EQ(callback->result, MockResolverCallback::FAILURE);
  609. }
  610. // If we set client timeout to lower than querytimeout, we should
  611. // get a failure answer
  612. // (no actual answer is given here yet. TODO the returned error message
  613. // should be tested)
  614. TEST_F(RecursiveQueryTest, forwardClientTimeout) {
  615. // Prepare the service (we do not use the common setup, we do not answer
  616. setDNSService();
  617. sock_ = createTestSocket();
  618. // Prepare the server
  619. bool done1(true);
  620. MockServerStop server(*io_service_, &done1);
  621. MessagePtr answer(new Message(Message::RENDER));
  622. // Do the answer
  623. const uint16_t port = boost::lexical_cast<uint16_t>(TEST_CLIENT_PORT);
  624. RecursiveQuery query(*dns_service_,
  625. *nsas_, cache_,
  626. singleAddress(TEST_IPV4_ADDR, port),
  627. singleAddress(TEST_IPV4_ADDR, port),
  628. 1000, 10, 4000, 4);
  629. Question q(Name("example.net"), RRClass::IN(), RRType::A());
  630. OutputBufferPtr buffer(new OutputBuffer(0));
  631. Message query_message(Message::RENDER);
  632. isc::resolve::initResponseMessage(q, query_message);
  633. boost::shared_ptr<MockResolverCallback> callback(new MockResolverCallback(&server));
  634. query.forward(ConstMessagePtr(&query_message), answer, buffer, &server, callback);
  635. // Run the test
  636. io_service_->run();
  637. EXPECT_EQ(callback->result, MockResolverCallback::SUCCESS);
  638. }
  639. // If we set lookup timeout to lower than querytimeout, the lookup
  640. // will fail.
  641. TEST_F(RecursiveQueryTest, forwardLookupTimeout) {
  642. // Prepare the service (we do not use the common setup, we do not answer
  643. setDNSService();
  644. // Prepare the socket
  645. sock_ = createTestSocket();
  646. // Prepare the server
  647. bool done(true);
  648. MockServerStop server(*io_service_, &done);
  649. MessagePtr answer(new Message(Message::RENDER));
  650. // Do the answer
  651. const uint16_t port = boost::lexical_cast<uint16_t>(TEST_CLIENT_PORT);
  652. RecursiveQuery query(*dns_service_,
  653. *nsas_, cache_,
  654. singleAddress(TEST_IPV4_ADDR, port),
  655. singleAddress(TEST_IPV4_ADDR, port),
  656. 1000, 4000, 10, 5);
  657. Question question(Name("example.net"), RRClass::IN(), RRType::A());
  658. OutputBufferPtr buffer(new OutputBuffer(0));
  659. Message query_message(Message::RENDER);
  660. isc::resolve::initResponseMessage(question, query_message);
  661. boost::shared_ptr<MockResolverCallback> callback(new MockResolverCallback(&server));
  662. query.forward(ConstMessagePtr(&query_message), answer, buffer, &server, callback);
  663. // Run the test
  664. io_service_->run();
  665. EXPECT_EQ(callback->result, MockResolverCallback::FAILURE);
  666. }
  667. // Set everything very low and see if this doesn't cause weird
  668. // behaviour
  669. TEST_F(RecursiveQueryTest, lowtimeouts) {
  670. // Prepare the service (we do not use the common setup, we do not answer
  671. setDNSService();
  672. // Prepare the socket
  673. sock_ = createTestSocket();
  674. // Prepare the server
  675. bool done(true);
  676. MockServerStop server(*io_service_, &done);
  677. MessagePtr answer(new Message(Message::RENDER));
  678. // Do the answer
  679. const uint16_t port = boost::lexical_cast<uint16_t>(TEST_CLIENT_PORT);
  680. RecursiveQuery query(*dns_service_,
  681. *nsas_, cache_,
  682. singleAddress(TEST_IPV4_ADDR, port),
  683. singleAddress(TEST_IPV4_ADDR, port),
  684. 1, 1, 1, 1);
  685. Question question(Name("example.net"), RRClass::IN(), RRType::A());
  686. OutputBufferPtr buffer(new OutputBuffer(0));
  687. Message query_message(Message::RENDER);
  688. isc::resolve::initResponseMessage(question, query_message);
  689. boost::shared_ptr<MockResolverCallback> callback(new MockResolverCallback(&server));
  690. query.forward(ConstMessagePtr(&query_message), answer, buffer, &server, callback);
  691. // Run the test
  692. io_service_->run();
  693. EXPECT_EQ(callback->result, MockResolverCallback::FAILURE);
  694. }
  695. // as mentioned above, we need a more better framework for this,
  696. // in addition to that, this sends out queries into the world
  697. // (which we should catch somehow and fake replies for)
  698. // for the skeleton code, it shouldn't be too much of a problem
  699. // Ok so even we don't all have access to the DNS world right now,
  700. // so disabling these tests too.
  701. TEST_F(RecursiveQueryTest, DISABLED_recursiveSendOk) {
  702. setDNSService(true, false);
  703. bool done;
  704. MockServerStop server(*io_service_, &done);
  705. vector<pair<string, uint16_t> > empty_vector;
  706. RecursiveQuery rq(*dns_service_, *nsas_, cache_, empty_vector,
  707. empty_vector, 10000, 0);
  708. Question q(Name("www.isc.org"), RRClass::IN(), RRType::A());
  709. OutputBufferPtr buffer(new OutputBuffer(0));
  710. MessagePtr answer(new Message(Message::RENDER));
  711. rq.resolve(q, answer, buffer, &server);
  712. io_service_->run();
  713. // Check that the answer we got matches the one we wanted
  714. EXPECT_EQ(Rcode::NOERROR(), answer->getRcode());
  715. ASSERT_EQ(1, answer->getRRCount(Message::SECTION_ANSWER));
  716. RRsetPtr a = *answer->beginSection(Message::SECTION_ANSWER);
  717. EXPECT_EQ(q.getName(), a->getName());
  718. EXPECT_EQ(q.getType(), a->getType());
  719. EXPECT_EQ(q.getClass(), a->getClass());
  720. EXPECT_EQ(1, a->getRdataCount());
  721. }
  722. // see comments at previous test
  723. TEST_F(RecursiveQueryTest, DISABLED_recursiveSendNXDOMAIN) {
  724. setDNSService(true, false);
  725. bool done;
  726. MockServerStop server(*io_service_, &done);
  727. vector<pair<string, uint16_t> > empty_vector;
  728. RecursiveQuery rq(*dns_service_, *nsas_, cache_, empty_vector,
  729. empty_vector, 10000, 0);
  730. Question q(Name("wwwdoesnotexist.isc.org"), RRClass::IN(), RRType::A());
  731. OutputBufferPtr buffer(new OutputBuffer(0));
  732. MessagePtr answer(new Message(Message::RENDER));
  733. rq.resolve(q, answer, buffer, &server);
  734. io_service_->run();
  735. // Check that the answer we got matches the one we wanted
  736. EXPECT_EQ(Rcode::NXDOMAIN(), answer->getRcode());
  737. EXPECT_EQ(0, answer->getRRCount(Message::SECTION_ANSWER));
  738. }
  739. // TODO: add tests that check whether the cache is updated on succesfull
  740. // responses, and not updated on failures.
  741. }