treenode_rrset_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 <util/buffer.h>
  15. #include <util/memory_segment_local.h>
  16. #include <datasrc/memory/treenode_rrset.h>
  17. #include <datasrc/memory/rdataset.h>
  18. #include <datasrc/memory/rdata_serialization.h>
  19. #include <datasrc/memory/zone_data.h>
  20. #include <util/unittests/wiredata.h>
  21. #include <testutils/dnsmessage_test.h>
  22. #include <gtest/gtest.h>
  23. #include <string>
  24. #include <vector>
  25. using std::vector;
  26. using std::string;
  27. using namespace isc::dns;
  28. using namespace isc::dns::rdata;
  29. using namespace isc::datasrc::memory;
  30. using namespace isc::testutils;
  31. using isc::util::unittests::matchWireData;
  32. using isc::util::OutputBuffer;
  33. namespace {
  34. class TreeNodeRRsetTest : public ::testing::Test {
  35. protected:
  36. TreeNodeRRsetTest() :
  37. rrclass_(RRClass::IN()),
  38. origin_name_("example.com"), www_name_("www.example.com"),
  39. ns_rrset_(textToRRset("example.com. 3600 IN NS ns.example.com.")),
  40. a_rrset_(textToRRset("www.example.com. 3600 IN A 192.0.2.1\n"
  41. "www.example.com. 3600 IN A 192.0.2.2")),
  42. aaaa_rrset_(textToRRset("www.example.com. 3600 IN AAAA "
  43. "2001:db8::1\n")),
  44. dname_rrset_(textToRRset("example.com. 3600 IN DNAME d.example.org.")),
  45. a_rrsig_rrset_(textToRRset("www.example.com. 3600 IN RRSIG "
  46. "A 5 2 3600 20120814220826 20120715220826 "
  47. "1234 example.com. FAKE")),
  48. aaaa_rrsig_rrset_(textToRRset("www.example.com. 3600 IN RRSIG AAAA 5 2"
  49. " 3600 20120814220826 20120715220826 "
  50. "1234 example.com. FAKE\n"
  51. "www.example.com. 3600 IN RRSIG AAAA 5 2"
  52. " 3600 20120814220826 20120715220826 "
  53. "4321 example.com. FAKE\n")),
  54. zone_data_(NULL)
  55. {}
  56. void SetUp() {
  57. // We create some common test data here in SetUp() so it will be
  58. // as exception safe as possible.
  59. zone_data_ = ZoneData::create(mem_sgmt_, origin_name_);
  60. zone_data_->insertName(mem_sgmt_, origin_name_, &origin_node_);
  61. ns_rdataset_ = RdataSet::create(mem_sgmt_, encoder_, ns_rrset_,
  62. ConstRRsetPtr());
  63. origin_node_->setData(ns_rdataset_);
  64. dname_rdataset_ = RdataSet::create(mem_sgmt_, encoder_, dname_rrset_,
  65. ConstRRsetPtr());
  66. ns_rdataset_->next = dname_rdataset_;
  67. zone_data_->insertName(mem_sgmt_, www_name_, &www_node_);
  68. a_rdataset_ = RdataSet::create(mem_sgmt_, encoder_, a_rrset_,
  69. a_rrsig_rrset_);
  70. www_node_->setData(a_rdataset_);
  71. aaaa_rdataset_ = RdataSet::create(mem_sgmt_, encoder_, aaaa_rrset_,
  72. aaaa_rrsig_rrset_);
  73. a_rdataset_->next = aaaa_rdataset_;
  74. }
  75. void TearDown() {
  76. ZoneData::destroy(mem_sgmt_, zone_data_, rrclass_);
  77. // detect any memory leak
  78. EXPECT_TRUE(mem_sgmt_.allMemoryDeallocated());
  79. }
  80. const RRClass rrclass_;
  81. const Name origin_name_, www_name_;
  82. isc::util::MemorySegmentLocal mem_sgmt_;
  83. RdataEncoder encoder_;
  84. MessageRenderer renderer_, renderer_expected_;
  85. ConstRRsetPtr ns_rrset_, a_rrset_, aaaa_rrset_, dname_rrset_,
  86. a_rrsig_rrset_, aaaa_rrsig_rrset_;
  87. ZoneData* zone_data_;
  88. ZoneNode* origin_node_;
  89. ZoneNode* www_node_;
  90. RdataSet* ns_rdataset_;
  91. RdataSet* dname_rdataset_;
  92. RdataSet* a_rdataset_;
  93. RdataSet* aaaa_rdataset_;
  94. };
  95. // Check some trivial fields of a constructed TreeNodeRRset (passed as
  96. // AbstractRRset as we'd normally use it in polymorphic way).
  97. // Other complicated fields are checked through rendering tests.
  98. void
  99. checkBasicFields(const AbstractRRset& actual_rrset, const Name& expected_name,
  100. const RRClass& expected_class, const RRType& expected_type,
  101. size_t expected_rdatacount, size_t expected_sigcount)
  102. {
  103. EXPECT_EQ(expected_name, actual_rrset.getName());
  104. EXPECT_EQ(expected_class, actual_rrset.getClass());
  105. EXPECT_EQ(expected_type, actual_rrset.getType());
  106. EXPECT_EQ(expected_rdatacount, actual_rrset.getRdataCount());
  107. EXPECT_EQ(expected_sigcount, actual_rrset.getRRsigDataCount());
  108. }
  109. TEST_F(TreeNodeRRsetTest, create) {
  110. // Constructed with RRSIG, and it should be visible.
  111. checkBasicFields(TreeNodeRRset(rrclass_, www_node_, a_rdataset_, true),
  112. www_name_, rrclass_, RRType::A(), 2, 1);
  113. // Constructed with RRSIG, and it should be invisible.
  114. checkBasicFields(TreeNodeRRset(rrclass_, www_node_, a_rdataset_, false),
  115. www_name_, rrclass_, RRType::A(), 2, 0);
  116. // Constructed without RRSIG, and it would be visible (but of course won't)
  117. checkBasicFields(TreeNodeRRset(rrclass_, origin_node_, ns_rdataset_, true),
  118. origin_name_, rrclass_, RRType::NS(), 1, 0);
  119. // Constructed without RRSIG, and it should be visible
  120. checkBasicFields(TreeNodeRRset(rrclass_, origin_node_, ns_rdataset_,
  121. false),
  122. origin_name_, rrclass_, RRType::NS(), 1, 0);
  123. }
  124. // Templated if and when we support OutputBuffer version of toWire().
  125. // Right now, we take a minimalist approach, only implementing testing the
  126. // renderer version.
  127. template <typename OutputType>
  128. void
  129. checkToWireResult(OutputType& expected_output, OutputType& actual_output,
  130. const AbstractRRset& actual_rrset,
  131. const Name& prepended_name,
  132. ConstRRsetPtr rrset, ConstRRsetPtr rrsig_rrset,
  133. bool dnssec_ok)
  134. {
  135. expected_output.clear();
  136. actual_output.clear();
  137. // Prepare "actual" rendered data. We prepend a name to confirm the
  138. // owner name should be compressed in both cases.
  139. prepended_name.toWire(actual_output);
  140. const int expected_ret = (dnssec_ok && rrsig_rrset) ?
  141. rrset->getRdataCount() + rrsig_rrset->getRdataCount() :
  142. rrset->getRdataCount();
  143. EXPECT_EQ(expected_ret, actual_rrset.toWire(actual_output));
  144. // Prepare "expected" data.
  145. prepended_name.toWire(expected_output);
  146. rrset->toWire(expected_output);
  147. if (dnssec_ok && rrsig_rrset) {
  148. rrsig_rrset->toWire(expected_output);
  149. }
  150. // Compare the two.
  151. matchWireData(expected_output.getData(), expected_output.getLength(),
  152. actual_output.getData(), actual_output.getLength());
  153. }
  154. TEST_F(TreeNodeRRsetTest, toWire) {
  155. MessageRenderer expected_renderer, actual_renderer;
  156. {
  157. SCOPED_TRACE("with RRSIG, DNSSEC OK");
  158. const TreeNodeRRset rrset1(rrclass_, www_node_, a_rdataset_, true);
  159. checkToWireResult(expected_renderer, actual_renderer, rrset1,
  160. www_name_, a_rrset_, a_rrsig_rrset_, true);
  161. }
  162. {
  163. SCOPED_TRACE("with RRSIG, DNSSEC not OK");
  164. const TreeNodeRRset rrset2(rrclass_, www_node_, a_rdataset_, false);
  165. checkToWireResult(expected_renderer, actual_renderer, rrset2,
  166. www_name_, a_rrset_, a_rrsig_rrset_, false);
  167. }
  168. {
  169. SCOPED_TRACE("without RRSIG, DNSSEC OK");
  170. const TreeNodeRRset rrset3(rrclass_, origin_node_, ns_rdataset_, true);
  171. checkToWireResult(expected_renderer, actual_renderer, rrset3,
  172. origin_name_, ns_rrset_, ConstRRsetPtr(), true);
  173. }
  174. {
  175. SCOPED_TRACE("without RRSIG, DNSSEC not OK");
  176. const TreeNodeRRset rrset4(rrclass_, origin_node_, ns_rdataset_,
  177. false);
  178. checkToWireResult(expected_renderer, actual_renderer, rrset4,
  179. origin_name_, ns_rrset_, ConstRRsetPtr(), false);
  180. }
  181. {
  182. // RDATA of DNAME DR shouldn't be compressed. Prepending "example.org"
  183. // will check that.
  184. SCOPED_TRACE("uncompressed RDATA");
  185. const TreeNodeRRset rrset5(rrclass_, origin_node_, dname_rdataset_,
  186. false);
  187. checkToWireResult(expected_renderer, actual_renderer, rrset5,
  188. Name("example.org"), dname_rrset_, ConstRRsetPtr(),
  189. false);
  190. }
  191. }
  192. void
  193. checkTruncationResult(MessageRenderer& expected_renderer,
  194. MessageRenderer& actual_renderer,
  195. const AbstractRRset& actual_rrset,
  196. ConstRRsetPtr rrset, ConstRRsetPtr rrsig_rrset,
  197. bool dnssec_ok, size_t len_limit, size_t expected_result)
  198. {
  199. expected_renderer.clear();
  200. actual_renderer.clear();
  201. actual_renderer.setLengthLimit(len_limit);
  202. EXPECT_EQ(expected_result, actual_rrset.toWire(actual_renderer));
  203. EXPECT_TRUE(actual_renderer.isTruncated()); // always true in this test
  204. expected_renderer.setLengthLimit(len_limit);
  205. rrset->toWire(expected_renderer);
  206. if (!expected_renderer.isTruncated() && dnssec_ok && rrsig_rrset) {
  207. rrsig_rrset->toWire(expected_renderer);
  208. }
  209. matchWireData(expected_renderer.getData(), expected_renderer.getLength(),
  210. actual_renderer.getData(), actual_renderer.getLength());
  211. }
  212. TEST_F(TreeNodeRRsetTest, toWireTruncated) {
  213. MessageRenderer expected_renderer, actual_renderer;
  214. // Set the truncation limit to name len + 14 bytes of fixed data for A RR
  215. // (type, class, TTL, rdlen, and 4-byte IPv4 address). Then we can only
  216. // render just one RR, without any garbage trailing data.
  217. checkTruncationResult(expected_renderer, actual_renderer,
  218. TreeNodeRRset(rrclass_, www_node_, a_rdataset_,
  219. true),
  220. a_rrset_, a_rrsig_rrset_, true,
  221. www_name_.getLength() + 14,
  222. 1); // 1 main RR, no RRSIG
  223. // The first main RRs should fit in the renderer (the name will be
  224. // fully compressed, so its size is 2 bytes), but the RRSIG doesn't.
  225. checkTruncationResult(expected_renderer, actual_renderer,
  226. TreeNodeRRset(rrclass_, www_node_, a_rdataset_,
  227. true),
  228. a_rrset_, a_rrsig_rrset_, true,
  229. www_name_.getLength() + 14 + 2 + 14,
  230. 2); // 2 main RR, no RRSIG
  231. // This RRset has one main RR and two RRSIGs. Rendering the second RRSIG
  232. // causes truncation.
  233. // First, compute the rendered length for the main RR and a single RRSIG.
  234. // The length of the RRSIG should be the same if we "accidentally"
  235. // rendered the RRSIG for the A RR (which only contains one RRSIG).
  236. expected_renderer.clear();
  237. aaaa_rrset_->toWire(expected_renderer);
  238. a_rrsig_rrset_->toWire(expected_renderer);
  239. const size_t limit_len = expected_renderer.getLength();
  240. // Then perform the test
  241. checkTruncationResult(expected_renderer, actual_renderer,
  242. TreeNodeRRset(rrclass_, www_node_, aaaa_rdataset_,
  243. true),
  244. aaaa_rrset_, aaaa_rrsig_rrset_, true, limit_len,
  245. 2); // 1 main RR, 1 RRSIG
  246. }
  247. void
  248. checkRdataIterator(const vector<string>& expected, RdataIteratorPtr rit) {
  249. for (vector<string>::const_iterator it = expected.begin();
  250. it != expected.end();
  251. ++it)
  252. {
  253. ASSERT_FALSE(rit->isLast());
  254. EXPECT_EQ(*it, rit->getCurrent().toText());
  255. rit->next();
  256. }
  257. // We should have reached the end of RDATA
  258. EXPECT_TRUE(rit->isLast());
  259. // move to the first RDATA again, and check the value.
  260. rit->first();
  261. EXPECT_EQ(expected[0], rit->getCurrent().toText());
  262. }
  263. TEST_F(TreeNodeRRsetTest, getRdataIterator) {
  264. // This RRset should have 2 A RDATAs
  265. vector<string> expected;
  266. expected.push_back("192.0.2.1");
  267. expected.push_back("192.0.2.2");
  268. checkRdataIterator(expected,
  269. TreeNodeRRset(rrclass_, www_node_, a_rdataset_, true).
  270. getRdataIterator());
  271. // The iterator shouldn't work different with or without RRSIG
  272. checkRdataIterator(expected,
  273. TreeNodeRRset(rrclass_, www_node_, a_rdataset_, false).
  274. getRdataIterator());
  275. // This RRset should have 1 NS RDATA (containing name field)
  276. expected.clear();
  277. expected.push_back("ns.example.com.");
  278. checkRdataIterator(expected,
  279. TreeNodeRRset(rrclass_, origin_node_, ns_rdataset_,
  280. false).getRdataIterator());
  281. }
  282. }