zone_finder_context_unittest.cc 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321
  1. // Copyright (C) 2012 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 <dns/masterload.h>
  15. #include <dns/name.h>
  16. #include <dns/rrclass.h>
  17. #include <datasrc/zone.h>
  18. #include <datasrc/memory_datasrc.h>
  19. #include <datasrc/database.h>
  20. #include <datasrc/sqlite3_accessor.h>
  21. #include <testutils/dnsmessage_test.h>
  22. #include <gtest/gtest.h>
  23. #include <boost/bind.hpp>
  24. #include <boost/foreach.hpp>
  25. #include <boost/shared_ptr.hpp>
  26. #include <cstdlib>
  27. #include <vector>
  28. using namespace std;
  29. using boost::shared_ptr;
  30. using namespace isc::dns;
  31. using namespace isc::datasrc;
  32. using namespace isc::testutils;
  33. namespace {
  34. // Commonly used test zone file.
  35. const char* const TEST_ZONE_FILE = TEST_DATA_DIR "/contexttest.zone";
  36. // Convenient shortcut
  37. typedef shared_ptr<DataSourceClient> DataSourceClientPtr;
  38. // This is the type used as the test parameter. Note that this is
  39. // intentionally a plain old type (i.e. a function pointer), not a class;
  40. // otherwise it could cause initialization fiasco at the instantiation time.
  41. typedef DataSourceClientPtr (*ClientCreator)(RRClass, const Name&);
  42. // Creator for the in-memory client to be tested
  43. DataSourceClientPtr
  44. createInMemoryClient(RRClass zclass, const Name& zname) {
  45. shared_ptr<InMemoryClient> client(new InMemoryClient);
  46. shared_ptr<InMemoryZoneFinder> finder(
  47. new InMemoryZoneFinder(zclass, zname));
  48. finder->load(TEST_ZONE_FILE);
  49. client->addZone(finder);
  50. return (client);
  51. }
  52. // Creator for the SQLite3 client to be tested. addRRset() is a helper
  53. // subroutine.
  54. void
  55. addRRset(ZoneUpdaterPtr updater, ConstRRsetPtr rrset) {
  56. updater->addRRset(*rrset);
  57. }
  58. DataSourceClientPtr
  59. createSQLite3Client(RRClass zclass, const Name& zname) {
  60. // We always begin with an empty template SQLite3 DB file and install
  61. // the zone data from the zone file to ensure both cases have the
  62. // same test data.
  63. const char* const install_cmd = INSTALL_PROG " " TEST_DATA_DIR
  64. "/rwtest.sqlite3 " TEST_DATA_BUILDDIR "/contexttest.sqlite3.copied";
  65. if (system(install_cmd) != 0) {
  66. isc_throw(isc::Unexpected,
  67. "Error setting up; command failed: " << install_cmd);
  68. }
  69. shared_ptr<SQLite3Accessor> accessor(
  70. new SQLite3Accessor(TEST_DATA_BUILDDIR "/contexttest.sqlite3.copied",
  71. zclass.toText()));
  72. shared_ptr<DatabaseClient> client(new DatabaseClient(zclass, accessor));
  73. ZoneUpdaterPtr updater = client->getUpdater(zname, true);
  74. masterLoad(TEST_ZONE_FILE, zname, zclass, boost::bind(addRRset, updater,
  75. _1));
  76. // Insert an out-of-zone name to test if it's incorrectly returned.
  77. // Note that neither updater nor SQLite3 accessor checks this condition,
  78. // so this should succeed.
  79. stringstream ss("ns.example.com. 3600 IN A 192.0.2.7");
  80. masterLoad(ss, Name::ROOT_NAME(), zclass,
  81. boost::bind(addRRset, updater, _1));
  82. updater->commit();
  83. return (client);
  84. }
  85. // The test class. Its parameterized so we can share the test scnearios
  86. // for any concrete data source implementaitons.
  87. class ZoneFinderContextTest :
  88. public ::testing::TestWithParam<ClientCreator>
  89. {
  90. protected:
  91. ZoneFinderContextTest() : qclass_(RRClass::IN()), qzone_("example.org") {
  92. client_ = (*GetParam())(qclass_, qzone_);
  93. REQUESTED_A.push_back(RRType::A());
  94. REQUESTED_AAAA.push_back(RRType::AAAA());
  95. REQUESTED_BOTH.push_back(RRType::A());
  96. REQUESTED_BOTH.push_back(RRType::AAAA());
  97. }
  98. void SetUp() {
  99. finder_ = client_->findZone(qzone_).zone_finder;
  100. ASSERT_TRUE(finder_);
  101. }
  102. const RRClass qclass_;
  103. const Name qzone_;
  104. DataSourceClientPtr client_;
  105. ZoneFinderPtr finder_;
  106. vector<RRType> requested_types_;
  107. vector<RRType> REQUESTED_A;
  108. vector<RRType> REQUESTED_AAAA;
  109. vector<RRType> REQUESTED_BOTH;
  110. vector<ConstRRsetPtr> result_sets_;
  111. };
  112. // We test the in-memory and SQLite3 data source implementations.
  113. INSTANTIATE_TEST_CASE_P(, ZoneFinderContextTest,
  114. ::testing::Values(createInMemoryClient,
  115. createSQLite3Client));
  116. TEST_P(ZoneFinderContextTest, getAdditionalAuthNS) {
  117. ZoneFinderContextPtr ctx = finder_->find(qzone_, RRType::NS());
  118. EXPECT_EQ(ZoneFinder::SUCCESS, ctx->code);
  119. // Getting both A and AAAA NS addresses
  120. ctx->getAdditional(REQUESTED_BOTH, result_sets_);
  121. rrsetsCheck("ns1.example.org. 3600 IN A 192.0.2.1\n"
  122. "ns1.example.org. 3600 IN AAAA 2001:db8::1\n"
  123. "ns2.example.org. 3600 IN A 192.0.2.2\n",
  124. result_sets_.begin(), result_sets_.end());
  125. // Getting only A
  126. result_sets_.clear();
  127. ctx->getAdditional(REQUESTED_A, result_sets_);
  128. rrsetsCheck("ns1.example.org. 3600 IN A 192.0.2.1\n"
  129. "ns2.example.org. 3600 IN A 192.0.2.2\n",
  130. result_sets_.begin(), result_sets_.end());
  131. // Getting only AAAA
  132. result_sets_.clear();
  133. ctx->getAdditional(REQUESTED_AAAA, result_sets_);
  134. rrsetsCheck("ns1.example.org. 3600 IN AAAA 2001:db8::1\n",
  135. result_sets_.begin(), result_sets_.end());
  136. // Getting A again, without clearing the result sets. This confirms
  137. // getAdditional() doesn't change the existing vector content.
  138. ctx->getAdditional(REQUESTED_A, result_sets_);
  139. // The first element should be the existing AAAA RR, followed by the A's.
  140. EXPECT_EQ(RRType::AAAA(), result_sets_[0]->getType());
  141. rrsetsCheck("ns1.example.org. 3600 IN AAAA 2001:db8::1\n"
  142. "ns1.example.org. 3600 IN A 192.0.2.1\n"
  143. "ns2.example.org. 3600 IN A 192.0.2.2\n",
  144. result_sets_.begin(), result_sets_.end());
  145. // Normally expected type set contain only A and/or AAAA, but others aren't
  146. // excluded.
  147. result_sets_.clear();
  148. requested_types_.push_back(RRType::TXT());
  149. ctx->getAdditional(requested_types_, result_sets_);
  150. rrsetsCheck("ns2.example.org. 3600 IN TXT \"text data\"",
  151. result_sets_.begin(), result_sets_.end());
  152. // Even empty set is okay. The result should also be empty.
  153. result_sets_.clear();
  154. ctx->getAdditional(vector<RRType>(), result_sets_);
  155. EXPECT_TRUE(result_sets_.empty());
  156. }
  157. TEST_P(ZoneFinderContextTest, getAdditionalDelegation) {
  158. // Basically similar to the AuthNS case, but NS names are glues.
  159. // It contains an out-of-zone NS name. Its address (even if it's somehow
  160. // inserted to the zone data) shouldn't be returned.
  161. const Name qname("www.a.example.org");
  162. ZoneFinderContextPtr ctx = finder_->find(qname, RRType::AAAA());
  163. EXPECT_EQ(ZoneFinder::DELEGATION, ctx->code);
  164. ctx->getAdditional(REQUESTED_BOTH, result_sets_);
  165. rrsetsCheck("ns1.a.example.org. 3600 IN A 192.0.2.5\n"
  166. "ns2.a.example.org. 3600 IN A 192.0.2.6\n"
  167. "ns2.a.example.org. 3600 IN AAAA 2001:db8::6\n",
  168. result_sets_.begin(), result_sets_.end());
  169. result_sets_.clear();
  170. ctx->getAdditional(REQUESTED_A, result_sets_);
  171. rrsetsCheck("ns1.a.example.org. 3600 IN A 192.0.2.5\n"
  172. "ns2.a.example.org. 3600 IN A 192.0.2.6\n",
  173. result_sets_.begin(), result_sets_.end());
  174. result_sets_.clear();
  175. ctx->getAdditional(REQUESTED_AAAA, result_sets_);
  176. rrsetsCheck("ns2.a.example.org. 3600 IN AAAA 2001:db8::6\n",
  177. result_sets_.begin(), result_sets_.end());
  178. }
  179. TEST_P(ZoneFinderContextTest, getAdditionalMX) {
  180. // Similar to the previous cases, but for MX addresses. The test zone
  181. // contains MX name under a zone cut. Its address shouldn't be returned.
  182. ZoneFinderContextPtr ctx = finder_->find(qzone_, RRType::MX());
  183. EXPECT_EQ(ZoneFinder::SUCCESS, ctx->code);
  184. // Getting both A and AAAA NS addresses
  185. ctx->getAdditional(REQUESTED_BOTH, result_sets_);
  186. rrsetsCheck("mx1.example.org. 3600 IN A 192.0.2.10\n"
  187. "mx2.example.org. 3600 IN AAAA 2001:db8::10\n",
  188. result_sets_.begin(), result_sets_.end());
  189. // Getting only A
  190. result_sets_.clear();
  191. ctx->getAdditional(REQUESTED_A, result_sets_);
  192. rrsetsCheck("mx1.example.org. 3600 IN A 192.0.2.10\n",
  193. result_sets_.begin(), result_sets_.end());
  194. // Getting only AAAA
  195. result_sets_.clear();
  196. ctx->getAdditional(REQUESTED_AAAA, result_sets_);
  197. rrsetsCheck("mx2.example.org. 3600 IN AAAA 2001:db8::10\n",
  198. result_sets_.begin(), result_sets_.end());
  199. }
  200. TEST_P(ZoneFinderContextTest, getAdditionalWithSIG) {
  201. // Similar to the AuthNS test, but the original find() requested DNSSEC
  202. // RRSIGs. Then additional records will also have RRSIGs.
  203. ZoneFinderContextPtr ctx = finder_->find(qzone_, RRType::NS(),
  204. ZoneFinder::FIND_DNSSEC);
  205. EXPECT_EQ(ZoneFinder::SUCCESS, ctx->code);
  206. ctx->getAdditional(REQUESTED_BOTH, result_sets_);
  207. rrsetsCheck("ns1.example.org. 3600 IN A 192.0.2.1\n"
  208. "ns1.example.org. 3600 IN AAAA 2001:db8::1\n"
  209. "ns2.example.org. 3600 IN A 192.0.2.2\n",
  210. result_sets_.begin(), result_sets_.end());
  211. vector<ConstRRsetPtr> sigresult_sets;
  212. BOOST_FOREACH(ConstRRsetPtr rrset, result_sets_) {
  213. ConstRRsetPtr sig_rrset = rrset->getRRsig();
  214. if (sig_rrset) {
  215. sigresult_sets.push_back(sig_rrset);
  216. }
  217. }
  218. rrsetsCheck("ns1.example.org. 3600 IN RRSIG A 7 3 3600 20150420235959 "
  219. "20051021000000 40430 example.org. FAKEFAKE\n"
  220. "ns1.example.org. 3600 IN RRSIG AAAA 7 3 3600 20150420235959 "
  221. "20051021000000 40430 example.org. FAKEFAKEFAKE\n",
  222. sigresult_sets.begin(), sigresult_sets.end());
  223. }
  224. TEST_P(ZoneFinderContextTest, getAdditionalNoOP) {
  225. // getAdditional() is only meaningful after SUCCESS or DELEGATION.
  226. ZoneFinderContextPtr ctx = finder_->find(Name("nxdomain.example.org"),
  227. RRType::NS());
  228. EXPECT_EQ(ZoneFinder::NXDOMAIN, ctx->code);
  229. ctx->getAdditional(REQUESTED_BOTH, result_sets_);
  230. EXPECT_TRUE(result_sets_.empty());
  231. ctx = finder_->find(qzone_, RRType::TXT());
  232. EXPECT_EQ(ZoneFinder::NXRRSET, ctx->code);
  233. ctx->getAdditional(REQUESTED_BOTH, result_sets_);
  234. EXPECT_TRUE(result_sets_.empty());
  235. ctx = finder_->find(Name("alias.example.org."), RRType::A());
  236. EXPECT_EQ(ZoneFinder::CNAME, ctx->code);
  237. ctx->getAdditional(REQUESTED_BOTH, result_sets_);
  238. EXPECT_TRUE(result_sets_.empty());
  239. ctx = finder_->find(Name("www.dname.example.org."), RRType::A());
  240. EXPECT_EQ(ZoneFinder::DNAME, ctx->code);
  241. ctx->getAdditional(REQUESTED_BOTH, result_sets_);
  242. EXPECT_TRUE(result_sets_.empty());
  243. }
  244. TEST_P(ZoneFinderContextTest, getAdditionalForAny) {
  245. // getAdditional() after successful type ANY query should return
  246. // the additional records of all returned RRsets.
  247. vector<ConstRRsetPtr> all_rrsets;
  248. ZoneFinderContextPtr ctx = finder_->findAll(qzone_, all_rrsets);
  249. EXPECT_EQ(ZoneFinder::SUCCESS, ctx->code);
  250. ctx->getAdditional(REQUESTED_BOTH, result_sets_);
  251. rrsetsCheck("ns1.example.org. 3600 IN A 192.0.2.1\n"
  252. "ns1.example.org. 3600 IN AAAA 2001:db8::1\n"
  253. "ns2.example.org. 3600 IN A 192.0.2.2\n"
  254. "mx1.example.org. 3600 IN A 192.0.2.10\n"
  255. "mx2.example.org. 3600 IN AAAA 2001:db8::10\n",
  256. result_sets_.begin(), result_sets_.end());
  257. // If the type ANY query results in DELEGATION, the result should be the
  258. // same as normal query.
  259. all_rrsets.clear();
  260. result_sets_.clear();
  261. ctx = finder_->findAll(Name("www.a.example.org"), all_rrsets);
  262. EXPECT_EQ(ZoneFinder::DELEGATION, ctx->code);
  263. ctx->getAdditional(REQUESTED_BOTH, result_sets_);
  264. rrsetsCheck("ns1.a.example.org. 3600 IN A 192.0.2.5\n"
  265. "ns2.a.example.org. 3600 IN A 192.0.2.6\n"
  266. "ns2.a.example.org. 3600 IN AAAA 2001:db8::6\n",
  267. result_sets_.begin(), result_sets_.end());
  268. }
  269. }