dnsmessage_test.h 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409
  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. #ifndef __ISC_TESTUTILS_DNSMESSAGETEST_H
  15. #define __ISC_TESTUTILS_DNSMESSAGETEST_H 1
  16. #include <algorithm>
  17. #include <functional>
  18. #include <iosfwd>
  19. #include <string>
  20. #include <vector>
  21. #include <dns/message.h>
  22. #include <dns/name.h>
  23. #include <dns/masterload.h>
  24. #include <dns/rdataclass.h>
  25. #include <dns/rrclass.h>
  26. #include <dns/rrset.h>
  27. #include <gtest/gtest.h>
  28. namespace isc {
  29. namespace testutils {
  30. ///
  31. /// \name Header flags
  32. ///
  33. /// These are flags to indicate whether the corresponding flag bit of the
  34. /// DNS header is to be set in the test cases using \c headerCheck().
  35. /// (The flag values is irrelevant to their wire-format values).
  36. /// The meaning of the flags should be obvious from the variable names.
  37. //@{
  38. extern const unsigned int QR_FLAG;
  39. extern const unsigned int AA_FLAG;
  40. extern const unsigned int TC_FLAG;
  41. extern const unsigned int RD_FLAG;
  42. extern const unsigned int RA_FLAG;
  43. extern const unsigned int AD_FLAG;
  44. extern const unsigned int CD_FLAG;
  45. //@}
  46. /// Set of unit tests to examine a DNS message header.
  47. ///
  48. /// This function takes a dns::Message object and performs various tests
  49. /// to confirm if the header fields of the message have the given specified
  50. /// value. The \c message parameter is the Message object to be tested,
  51. /// and the remaining parameters specify the expected values of the fields.
  52. ///
  53. /// If all fields have the expected values the test will be considered
  54. /// successful. Otherwise, some of the tests will indicate a failure, which
  55. /// will make the test case that calls this function fail.
  56. ///
  57. /// The meaning of the parameters should be obvious, but here are some notes
  58. /// that may not be so trivial:
  59. /// - \c opcode is an integer, not an \c dns::Opcode object. This is because
  60. /// we can easily iterate over all possible OPCODEs in a test.
  61. /// - \c flags is a bitmask so that we can specify a set of header flags
  62. /// via a single parameter. For example, when we expect the message has
  63. /// QR and AA flags are on and others are off, we'd set this parameter to
  64. /// <code>(QR_FLAG | AA_FLAG)</code>.
  65. ///
  66. /// \param message The DNS message to be tested.
  67. /// \param qid The expected QID
  68. /// \param rcode The expected RCODE
  69. /// \param opcodeval The code value of the expected OPCODE
  70. /// \param flags Bit flags specifying header flags that are expected to be set
  71. /// \param qdcount The expected value of QDCOUNT
  72. /// \param ancount The expected value of ANCOUNT
  73. /// \param nscount The expected value of NSCOUNT
  74. /// \param arcount The expected value of ARCOUNT
  75. void
  76. headerCheck(const isc::dns::Message& message, const isc::dns::qid_t qid,
  77. const isc::dns::Rcode& rcode,
  78. const uint16_t opcodeval, const unsigned int flags,
  79. const unsigned int qdcount,
  80. const unsigned int ancount, const unsigned int nscount,
  81. const unsigned int arcount);
  82. /// Set of unit tests to check equality of two RRsets
  83. ///
  84. /// This function takes two RRset objects and performs detailed tests to
  85. /// check if these two are "equal", where equal means:
  86. /// - The owner name, RR class, RR type and TTL are all equal. Names are
  87. /// compared in case-insensitive manner.
  88. /// - The number of RRs (more accurately RDATAs) is the same.
  89. /// - RDATAs are equal as a sequence. That is, the first RDATA of
  90. /// \c expected_rrset is equal to the first RDATA of \c actual_rrset,
  91. /// the second RDATA of \c expected_rrset is equal to the second RDATA
  92. /// of \c actual_rrset, and so on. Two RDATAs are equal iff they have
  93. /// the same DNSSEC sorting order as defined in RFC4034.
  94. ///
  95. /// Some of the tests will fail if any of the above isn't met.
  96. ///
  97. /// \note In future we may want to allow more flexible matching for RDATAs.
  98. /// For example, we may want to allow comparison as "sets", i.e., comparing
  99. /// RDATAs regardless of the ordering; we may also want to support suppressing
  100. /// duplicate RDATA. For now, it's caller's responsibility to match the
  101. /// ordering (and any duplicates) between the expected and actual sets.
  102. /// Even if and when we support the flexible behavior, this "strict mode"
  103. /// will still be useful.
  104. ///
  105. /// \param expected_rrset The expected RRset
  106. /// \param actual_rrset The RRset to be tested
  107. void rrsetCheck(isc::dns::ConstRRsetPtr expected_rrset,
  108. isc::dns::ConstRRsetPtr actual_rrset);
  109. /// The definitions in this name space are not supposed to be used publicly,
  110. /// but are given here because they are used in templated functions.
  111. namespace detail {
  112. // Helper matching class used in rrsetsCheck(). Basically we only have to
  113. // check the equality of name, RR type and RR class, but for RRSIGs we need
  114. // special additional checks because they are essentially different if their
  115. // 'type covered' are different. For simplicity, we only compare the types
  116. // of the first RRSIG RDATAs (and only check when they exist); if there's
  117. // further difference in the RDATA, the main comparison checks will detect it.
  118. struct RRsetMatch : public std::unary_function<isc::dns::ConstRRsetPtr, bool> {
  119. RRsetMatch(isc::dns::ConstRRsetPtr target) : target_(target) {}
  120. bool operator()(isc::dns::ConstRRsetPtr rrset) const {
  121. if (rrset->getType() != target_->getType() ||
  122. rrset->getClass() != target_->getClass() ||
  123. rrset->getName() != target_->getName()) {
  124. return (false);
  125. }
  126. if (rrset->getType() != isc::dns::RRType::RRSIG()) {
  127. return (true);
  128. }
  129. if (rrset->getRdataCount() == 0 || target_->getRdataCount() == 0) {
  130. return (true);
  131. }
  132. isc::dns::RdataIteratorPtr rdit = rrset->getRdataIterator();
  133. isc::dns::RdataIteratorPtr targetit = target_->getRdataIterator();
  134. return (dynamic_cast<const isc::dns::rdata::generic::RRSIG&>(
  135. rdit->getCurrent()).typeCovered() ==
  136. dynamic_cast<const isc::dns::rdata::generic::RRSIG&>(
  137. targetit->getCurrent()).typeCovered());
  138. }
  139. const isc::dns::ConstRRsetPtr target_;
  140. };
  141. // Helper callback functor for masterLoad() used in rrsetsCheck (stream
  142. // version)
  143. class RRsetInserter {
  144. public:
  145. RRsetInserter(std::vector<isc::dns::ConstRRsetPtr>& rrsets) :
  146. rrsets_(rrsets)
  147. {}
  148. void operator()(isc::dns::ConstRRsetPtr rrset) const {
  149. rrsets_.push_back(rrset);
  150. }
  151. private:
  152. std::vector<isc::dns::ConstRRsetPtr>& rrsets_;
  153. };
  154. class RRsetDumper {
  155. public:
  156. RRsetDumper(std::string& output) :
  157. output_(output)
  158. {}
  159. void operator()(isc::dns::ConstRRsetPtr rrset) {
  160. output_ += " " + rrset->toText();
  161. if (rrset->getRRsig()) {
  162. output_ += " " + rrset->getRRsig()->toText();
  163. }
  164. }
  165. private:
  166. std::string& output_;
  167. };
  168. }
  169. namespace {
  170. /// \brief Specialized counter for both RRsets and signatures
  171. ///
  172. /// \param begin start of iterator (of any RRset type)
  173. /// \param begin end of iterator (of any RRset type)
  174. ///
  175. /// \return the number of RRsets in the given iterator, plus
  176. /// the number of signature RRsets (each RRset with signatures
  177. /// is counted as 2 'rrsets', as if the signatures over an RRset
  178. /// are a separate RRset in the original iterator)
  179. template<typename ITERATOR_TYPE>
  180. size_t
  181. countRRsetsAndSigs(ITERATOR_TYPE begin, ITERATOR_TYPE end) {
  182. size_t count = 0;
  183. for (ITERATOR_TYPE it = begin; it != end; ++it) {
  184. if ((*it)->getRRsig()) {
  185. ++count;
  186. }
  187. ++count;
  188. }
  189. return count;
  190. }
  191. } // end anonymous namespace
  192. /// \brief A converter from a string to RRset.
  193. ///
  194. /// This is a convenient shortcut for tests that need to create an RRset
  195. /// from textual representation with a single call to a function.
  196. ///
  197. /// An RRset consisting of multiple RRs can be constructed, but only one
  198. /// RRset is allowed. If the given string contains mixed types of RRs
  199. /// it throws an \c isc::Unexpected exception.
  200. ///
  201. /// \param text_rrset A complete textual representation of an RRset.
  202. /// It must meets the assumption of the \c dns::masterLoad() function.
  203. /// \param rrclass The RR class of the RRset. Note that \c text_rrset should
  204. /// contain the RR class, but it's needed for \c dns::masterLoad().
  205. /// \param origin The zone origin where the RR is expected to belong. This
  206. /// parameter normally doesn't have to be specified, but for an SOA RR it
  207. /// must be set to its owner name, due to the internal check of
  208. /// \c dns::masterLoad().
  209. isc::dns::RRsetPtr textToRRset(const std::string& text_rrset,
  210. const isc::dns::RRClass& rrclass =
  211. isc::dns::RRClass::IN(),
  212. const isc::dns::Name& origin =
  213. isc::dns::Name::ROOT_NAME());
  214. /// Set of unit tests to check if two sets of RRsets are identical.
  215. ///
  216. /// This templated function takes two sets of sequences, each defined by
  217. /// two input iterators pointing to \c ConstRRsetPtr (begin and end).
  218. /// This function compares these two sets of RRsets as "sets", and considers
  219. /// they are equal when:
  220. /// - The number of RRsets are the same.
  221. /// - For any RRset in one set, there is an equivalent RRset in the other set,
  222. /// and vice versa, where the equivalence of two RRsets is tested using
  223. /// \c rrsetCheck().
  224. ///
  225. /// Note that the sets of RRsets are compared as "sets", i.e, they don't have
  226. /// to be listed in the same order.
  227. ///
  228. /// The entire tests will pass if the two sets are identical. Otherwise
  229. /// some of the tests will indicate a failure.
  230. ///
  231. /// \note
  232. /// - There is one known restriction: each set of RRsets must not have more
  233. /// than one RRsets for the same name, RR type and RR class. If this
  234. /// condition isn't met, some of the tests will fail either against an
  235. /// explicit duplication check or as a result of counter mismatch.
  236. /// - This function uses linear searches on the expected and actual sequences,
  237. /// and won't be scalable for large input. For the purpose of testing it
  238. /// should be acceptable, but be aware of the size of test data.
  239. ///
  240. /// \param expected_begin The beginning of the expected set of RRsets
  241. /// \param expected_end The end of the expected set of RRsets
  242. /// \param actual_begin The beginning of the set of RRsets to be tested
  243. /// \param actual_end The end of the set of RRsets to be tested
  244. template<typename EXPECTED_ITERATOR, typename ACTUAL_ITERATOR>
  245. void
  246. rrsetsCheck(EXPECTED_ITERATOR expected_begin, EXPECTED_ITERATOR expected_end,
  247. ACTUAL_ITERATOR actual_begin, ACTUAL_ITERATOR actual_end)
  248. {
  249. std::vector<isc::dns::ConstRRsetPtr> checked_rrsets; // for duplicate check
  250. std::string expected_text, actual_text;
  251. std::for_each(expected_begin, expected_end,
  252. detail::RRsetDumper(expected_text));
  253. std::for_each(actual_begin, actual_end, detail::RRsetDumper(actual_text));
  254. unsigned int rrset_matched = 0;
  255. ACTUAL_ITERATOR it;
  256. for (it = actual_begin; it != actual_end; ++it) {
  257. // Make sure there's no duplicate RRset in actual (using a naive
  258. // search). Since the actual set is guaranteed to be unique, we can
  259. // detect it if the expected data has a duplicate by the match/size
  260. // checks at the end of the function.
  261. // Note: we cannot use EXPECT_EQ for iterators
  262. EXPECT_TRUE(checked_rrsets.end() ==
  263. std::find_if(checked_rrsets.begin(), checked_rrsets.end(),
  264. detail::RRsetMatch(*it)));
  265. checked_rrsets.push_back(*it);
  266. EXPECTED_ITERATOR found_rrset_it =
  267. std::find_if(expected_begin, expected_end,
  268. detail::RRsetMatch(*it));
  269. if (found_rrset_it != expected_end) {
  270. rrsetCheck(*found_rrset_it, *it);
  271. ++rrset_matched;
  272. rrset_matched += (*it)->getRRsigDataCount();
  273. }
  274. }
  275. {
  276. SCOPED_TRACE(std::string("Comparing two RRsets:\n") +
  277. "Actual:\n" + actual_text +
  278. "Expected:\n" + expected_text);
  279. // make sure all expected RRsets are in actual sets
  280. EXPECT_EQ(std::distance(expected_begin, expected_end), rrset_matched);
  281. // make sure rrsets only contains expected RRsets
  282. //
  283. // Any rrset in actual has been found in expected by the code above,
  284. // so to determine whether there are no other rrsets present, we
  285. // simply need to compare their sizes. However, signatures can be
  286. // in-lined (as part of an RRset), or added as separate RRsets.
  287. // So we count the number of rrsets + the number of rrsets that
  288. // have signatures.
  289. EXPECT_EQ(countRRsetsAndSigs(expected_begin, expected_end),
  290. countRRsetsAndSigs(actual_begin, actual_end));
  291. }
  292. }
  293. /// Set of unit tests to check if two sets of RRsets are identical using
  294. /// streamed expected data.
  295. ///
  296. /// This templated function takes a standard input stream that produces
  297. /// a sequence of textural RRs and compares the entire set of RRsets
  298. /// with the range of RRsets specified by two input iterators.
  299. ///
  300. /// This function is actually a convenient wrapper for the other version
  301. /// of function; it internally builds a standard vector of RRsets
  302. /// from the input stream and uses iterators of the vector as the expected
  303. /// input iterators for the backend function.
  304. /// Expected data in the form of input stream would be useful for testing
  305. /// as it can be easily hardcoded in test cases using string streams or
  306. /// given from a data source file.
  307. ///
  308. /// One common use case of this function is to test whether a particular
  309. /// section of a DNS message contains an expected set of RRsets.
  310. /// For example, when \c message is an \c dns::Message object, the following
  311. /// test code will check if the additional section of \c message contains
  312. /// the hardcoded two RRsets (2 A RRs and 1 AAAA RR) and only contains these
  313. /// RRsets:
  314. /// \code std::stringstream expected;
  315. /// expected << "foo.example.com. 3600 IN A 192.0.2.1\n"
  316. /// << "foo.example.com. 3600 IN A 192.0.2.2\n"
  317. /// << "foo.example.com. 7200 IN AAAA 2001:db8::1\n"
  318. /// rrsetsCheck(expected, message.beginSection(Message::SECTION_ADDITIONAL),
  319. /// message.endSection(Message::SECTION_ADDITIONAL));
  320. /// \endcode
  321. ///
  322. /// The input stream is parsed using the \c dns::masterLoad() function,
  323. /// and notes and restrictions of that function apply.
  324. /// This is also the reason why this function takes \c origin and \c rrclass
  325. /// parameters. The default values of these parameters should just work
  326. /// in many cases for usual tests, but due to a validity check on the SOA RR
  327. /// in \c dns::masterLoad(), if the input stream contains an SOA RR, the
  328. /// \c origin parameter will have to be set to the owner name of the SOA
  329. /// explicitly. Likewise, all RRsets must have the same RR class.
  330. /// (We may have to modify \c dns::masterLoad() so that it can
  331. /// have an option to be more generous about these points if it turns out
  332. /// to be too restrictive).
  333. ///
  334. /// \param expected_stream An input stream object that is to emit expected set
  335. /// of RRsets
  336. /// \param actual_begin The beginning of the set of RRsets to be tested
  337. /// \param actual_end The end of the set of RRsets to be tested
  338. /// \param origin A domain name that is a super domain of the owner name
  339. /// of all RRsets contained in the stream.
  340. /// \param rrclass The RR class of the RRsets contained in the stream.
  341. template<typename ACTUAL_ITERATOR>
  342. void
  343. rrsetsCheck(std::istream& expected_stream,
  344. ACTUAL_ITERATOR actual_begin, ACTUAL_ITERATOR actual_end,
  345. const isc::dns::Name& origin = isc::dns::Name::ROOT_NAME(),
  346. const isc::dns::RRClass& rrclass = isc::dns::RRClass::IN())
  347. {
  348. std::vector<isc::dns::ConstRRsetPtr> expected;
  349. isc::dns::masterLoad(expected_stream, origin, rrclass,
  350. detail::RRsetInserter(expected));
  351. rrsetsCheck(expected.begin(), expected.end(), actual_begin, actual_end);
  352. }
  353. /// Set of unit tests to check if two sets of RRsets are identical using
  354. /// expected data as string.
  355. ///
  356. /// This function is a wrapper for the input stream version:
  357. /// \c rrsetsCheck(std::istream&, ACTUAL_ITERATOR, ACTUAL_ITERATOR, const isc::dns::Name&, const isc::dns::RRClass&)(),
  358. /// and takes a string object instead of a stream.
  359. /// While the stream version is more generic, this version would be more
  360. /// convenient for tests using hardcoded expected data. Using this version,
  361. /// the example test case shown for the stream version would look as follows:
  362. /// \code
  363. /// rrsetsCheck("foo.example.com. 3600 IN A 192.0.2.1\n"
  364. /// "foo.example.com. 3600 IN A 192.0.2.2\n"
  365. /// "foo.example.com. 7200 IN AAAA 2001:db8::1\n",
  366. /// message.beginSection(Message::SECTION_ADDITIONAL),
  367. /// message.endSection(Message::SECTION_ADDITIONAL));
  368. /// \endcode
  369. ///
  370. /// The semantics of parameters is the same as that of the stream version
  371. /// except that \c expected is a string of expected sets of RRsets.
  372. template<typename ACTUAL_ITERATOR>
  373. void
  374. rrsetsCheck(const std::string& expected,
  375. ACTUAL_ITERATOR actual_begin, ACTUAL_ITERATOR actual_end,
  376. const isc::dns::Name& origin = isc::dns::Name::ROOT_NAME(),
  377. const isc::dns::RRClass& rrclass = isc::dns::RRClass::IN())
  378. {
  379. std::stringstream expected_stream(expected);
  380. rrsetsCheck(expected_stream, actual_begin, actual_end, origin,
  381. rrclass);
  382. }
  383. } // end of namespace testutils
  384. } // end of namespace isc
  385. #endif // __ISC_TESTUTILS_DNSMESSAGETEST_H
  386. // Local Variables:
  387. // mode: c++
  388. // End: