zone_finder_unittest.cc 62 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572
  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 "memory_segment_test.h"
  15. // NOTE: this faked_nsec3 inclusion (and all related code below)
  16. // was ported during #2109 for the convenience of implementing #2218
  17. // In #2218 the NSEC3 test code in this file is expected to be finalized.
  18. // In #2219 the original is expected to be removed, and this file should
  19. // probably be moved here (and any leftover code not handled in #2218 should
  20. // be cleaned up)
  21. #include "../../tests/faked_nsec3.h"
  22. #include <datasrc/memory/zone_finder.h>
  23. #include <datasrc/memory/rdata_serialization.h>
  24. #include <datasrc/data_source.h>
  25. #include <testutils/dnsmessage_test.h>
  26. #include <boost/foreach.hpp>
  27. #include <gtest/gtest.h>
  28. #include <string>
  29. using namespace std;
  30. using namespace isc::dns;
  31. using namespace isc::dns::rdata;
  32. using namespace isc::datasrc;
  33. using namespace isc::testutils;
  34. using boost::shared_ptr;
  35. using namespace isc::datasrc::test;
  36. using namespace isc::datasrc::memory::test;
  37. using namespace isc::datasrc::memory;
  38. namespace {
  39. // Commonly used result codes (Who should write the prefix all the time)
  40. using result::SUCCESS;
  41. using result::EXIST;
  42. // Proxy accessor for faked NSEC3 mapping for tests. map isn't a trivial
  43. // type, so it's safer to get access to it via a proxy to avoid initialization
  44. // fiasco.
  45. NSEC3HashMap&
  46. getNSEC3HashMap() {
  47. static NSEC3HashMap nsec3_hash_map;
  48. return (nsec3_hash_map);
  49. }
  50. // A faked NSEC3 hash calculator for convenience. Tests that need to use
  51. // the faked hashed values should call setFakeNSEC3Calculate() on the
  52. // MyZoneFinder object at the beginning of the test (at least before
  53. // adding any NSEC3/NSEC3PARAM RR).
  54. std::string
  55. fakeNSEC3Calculate(const Name& name,
  56. const uint16_t,
  57. const uint8_t*,
  58. size_t)
  59. {
  60. const NSEC3HashMap::const_iterator found = getNSEC3HashMap().find(name);
  61. if (found != getNSEC3HashMap().end()) {
  62. return (found->second);
  63. }
  64. isc_throw(isc::Unexpected,
  65. "unexpected name for NSEC3 test: " << name);
  66. }
  67. class MyZoneFinder : public memory::InMemoryZoneFinder {
  68. public:
  69. MyZoneFinder(const ZoneData& zone_data,
  70. const isc::dns::RRClass& rrclass) :
  71. memory::InMemoryZoneFinder(zone_data, rrclass)
  72. {
  73. buildFakeNSEC3Map(getNSEC3HashMap());
  74. }
  75. void setFakeNSEC3Calculate() {
  76. nsec3_calculate_ = fakeNSEC3Calculate;
  77. }
  78. };
  79. /// \brief expensive rrset converter
  80. ///
  81. /// converts any specialized rrset (which may not have implemented some
  82. /// methods for efficiency) into a 'full' RRsetPtr, for easy use in test
  83. /// checks.
  84. ///
  85. /// Done very inefficiently through text representation, speed should not
  86. /// be a concern here.
  87. ConstRRsetPtr
  88. convertRRset(ConstRRsetPtr src) {
  89. return (textToRRset(src->toText()));
  90. }
  91. /// \brief Test fixture for the InMemoryZoneFinder class
  92. class InMemoryZoneFinderTest : public ::testing::Test {
  93. // A straightforward pair of textual RR(set) and a RRsetPtr variable
  94. // to store the RRset. Used to build test data below.
  95. struct RRsetData {
  96. const char* const text; // textual representation of an RRset
  97. RRsetPtr* rrset;
  98. };
  99. protected:
  100. // The following sub tests are shared by multiple test cases, changing
  101. // the zone's DNSSEC status (unsigned, NSEC-signed or NSEC3-signed).
  102. // expected_flags is set to either RESULT_NSEC_SIGNED or
  103. // RESULT_NSEC3_SIGNED when it's NSEC/NSEC3 signed respectively and
  104. // find() is expected to set the corresponding flags.
  105. // find_options should be set to FIND_DNSSEC for NSEC-signed case when
  106. // NSEC is expected to be returned.
  107. void findCheck(ZoneFinder::FindResultFlags expected_flags =
  108. ZoneFinder::RESULT_DEFAULT,
  109. ZoneFinder::FindOptions find_options =
  110. ZoneFinder::FIND_DEFAULT);
  111. void emptyNodeCheck(ZoneFinder::FindResultFlags expected_flags =
  112. ZoneFinder::RESULT_DEFAULT);
  113. void wildcardCheck(ZoneFinder::FindResultFlags expected_flags =
  114. ZoneFinder::RESULT_DEFAULT,
  115. ZoneFinder::FindOptions find_options =
  116. ZoneFinder::FIND_DEFAULT);
  117. void doCancelWildcardCheck(ZoneFinder::FindResultFlags expected_flags =
  118. ZoneFinder::RESULT_DEFAULT,
  119. ZoneFinder::FindOptions find_options =
  120. ZoneFinder::FIND_DEFAULT);
  121. void anyWildcardCheck(ZoneFinder::FindResultFlags expected_flags =
  122. ZoneFinder::RESULT_DEFAULT);
  123. void emptyWildcardCheck(ZoneFinder::FindResultFlags expected_flags =
  124. ZoneFinder::RESULT_DEFAULT);
  125. void findNSECENTCheck(const Name& ent_name,
  126. ConstRRsetPtr expected_nsec,
  127. ZoneFinder::FindResultFlags expected_flags =
  128. ZoneFinder::RESULT_DEFAULT);
  129. public:
  130. InMemoryZoneFinderTest() :
  131. class_(RRClass::IN()),
  132. origin_("example.org"),
  133. zone_data_(ZoneData::create(mem_sgmt_, origin_)),
  134. zone_finder_(*zone_data_, class_)
  135. {
  136. // Build test RRsets. Below, we construct an RRset for
  137. // each textual RR(s) of zone_data, and assign it to the corresponding
  138. // rr_xxx.
  139. // Note that this contains an out-of-zone RR, and due to the
  140. // validation check of masterLoad() used below, we cannot add SOA.
  141. const RRsetData zone_data[] = {
  142. {"example.org. 300 IN NS ns.example.org.", &rr_ns_},
  143. {"example.org. 300 IN A 192.0.2.1", &rr_a_},
  144. {"ns.example.org. 300 IN A 192.0.2.2", &rr_ns_a_},
  145. {"ns.example.org. 300 IN AAAA 2001:db8::2", &rr_ns_aaaa_},
  146. {"cname.example.org. 300 IN CNAME canonical.example.org",
  147. &rr_cname_},
  148. {"cname.example.org. 300 IN A 192.0.2.3", &rr_cname_a_},
  149. {"dname.example.org. 300 IN DNAME target.example.org.",
  150. &rr_dname_},
  151. {"dname.example.org. 300 IN A 192.0.2.39", &rr_dname_a_},
  152. {"dname.example.org. 300 IN NS ns.dname.example.org.",
  153. &rr_dname_ns_},
  154. {"example.org. 300 IN DNAME example.com.", &rr_dname_apex_},
  155. {"child.example.org. 300 IN NS ns.child.example.org.",
  156. &rr_child_ns_},
  157. {"child.example.org. 300 IN DS 12345 5 1 DEADBEEF",
  158. &rr_child_ds_},
  159. {"ns.child.example.org. 300 IN A 192.0.2.153",
  160. &rr_child_glue_},
  161. {"grand.child.example.org. 300 IN NS ns.grand.child.example.org.",
  162. &rr_grandchild_ns_},
  163. {"ns.grand.child.example.org. 300 IN AAAA 2001:db8::253",
  164. &rr_grandchild_glue_},
  165. {"dname.child.example.org. 300 IN DNAME example.com.",
  166. &rr_child_dname_},
  167. {"example.com. 300 IN A 192.0.2.10", &rr_out_},
  168. {"*.wild.example.org. 300 IN A 192.0.2.1", &rr_wild_},
  169. {"*.cnamewild.example.org. 300 IN CNAME canonial.example.org.",
  170. &rr_cnamewild_},
  171. {"foo.wild.example.org. 300 IN A 192.0.2.3", &rr_under_wild_},
  172. {"wild.*.foo.example.org. 300 IN A 192.0.2.1", &rr_emptywild_},
  173. {"wild.*.foo.*.bar.example.org. 300 IN A 192.0.2.1",
  174. &rr_nested_emptywild_},
  175. {"*.nswild.example.org. 300 IN NS nswild.example.", &rr_nswild_},
  176. {"*.dnamewild.example.org. 300 IN DNAME dnamewild.example.",
  177. &rr_dnamewild_},
  178. {"*.child.example.org. 300 IN A 192.0.2.1", &rr_child_wild_},
  179. {"bar.foo.wild.example.org. 300 IN A 192.0.2.2", &rr_not_wild_},
  180. {"baz.foo.wild.example.org. 300 IN A 192.0.2.3",
  181. &rr_not_wild_another_},
  182. {"0P9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM.example.org. 300 IN "
  183. "NSEC3 1 1 12 aabbccdd 2T7B4G4VSA5SMI47K61MV5BV1A22BOJR A RRSIG",
  184. &rr_nsec3_},
  185. {"example.org. 300 IN NSEC wild.*.foo.example.org. "
  186. "NS SOA RRSIG NSEC DNSKEY", &rr_nsec_},
  187. // Together with the apex NSEC, these next NSECs make a complete
  188. // chain in the case of the zone for the emptyNonterminal tests
  189. // (We may want to clean up this generator code and/or masterLoad
  190. // so that we can prepare conflicting datasets better)
  191. {"wild.*.foo.example.org. 3600 IN NSEC ns.example.org. "
  192. "A RRSIG NSEC", &rr_ent_nsec2_},
  193. {"ns.example.org. 3600 IN NSEC foo.wild.example.org. A RRSIG NSEC",
  194. &rr_ent_nsec3_},
  195. {"foo.wild.example.org. 3600 IN NSEC example.org. A RRSIG NSEC",
  196. &rr_ent_nsec4_},
  197. // And these are NSECs used in different tests
  198. {"ns.example.org. 300 IN NSEC *.nswild.example.org. A AAAA NSEC",
  199. &rr_ns_nsec_},
  200. {"*.wild.example.org. 300 IN NSEC foo.wild.example.org. A NSEC",
  201. &rr_wild_nsec_},
  202. {NULL, NULL}
  203. };
  204. for (unsigned int i = 0; zone_data[i].text != NULL; ++i) {
  205. *zone_data[i].rrset = textToRRset(zone_data[i].text);
  206. }
  207. }
  208. ~InMemoryZoneFinderTest() {
  209. // Make sure we reset the hash creator to the default
  210. setNSEC3HashCreator(NULL);
  211. ZoneData::destroy(mem_sgmt_, zone_data_, RRClass::IN());
  212. }
  213. // NSEC3-specific call for 'loading' data
  214. void addZoneDataNSEC3(const ConstRRsetPtr rrset) {
  215. assert(rrset->getType() == RRType::NSEC3());
  216. const generic::NSEC3& nsec3_rdata =
  217. dynamic_cast<const generic::NSEC3&>(
  218. rrset->getRdataIterator()->getCurrent());
  219. NSEC3Data* nsec3_data = zone_data_->getNSEC3Data();
  220. if (nsec3_data == NULL) {
  221. nsec3_data = NSEC3Data::create(mem_sgmt_, nsec3_rdata);
  222. zone_data_->setNSEC3Data(nsec3_data);
  223. } else {
  224. const size_t salt_len = nsec3_data->getSaltLen();
  225. const uint8_t* salt_data = nsec3_data->getSaltData();
  226. const vector<uint8_t>& salt_data_2 = nsec3_rdata.getSalt();
  227. if ((nsec3_rdata.getHashalg() != nsec3_data->hashalg) ||
  228. (nsec3_rdata.getIterations() != nsec3_data->iterations) ||
  229. (salt_data_2.size() != salt_len)) {
  230. isc_throw(isc::Unexpected,
  231. "NSEC3 with inconsistent parameters: " <<
  232. rrset->toText());
  233. }
  234. if ((salt_len > 0) &&
  235. (std::memcmp(&salt_data_2[0], salt_data, salt_len) != 0)) {
  236. isc_throw(isc::Unexpected,
  237. "NSEC3 with inconsistent parameters: " <<
  238. rrset->toText());
  239. }
  240. }
  241. ZoneNode* node;
  242. nsec3_data->insertName(mem_sgmt_, rrset->getName(), &node);
  243. RdataSet* rdset = RdataSet::create(mem_sgmt_, encoder_,
  244. rrset, ConstRRsetPtr());
  245. RdataSet* old_rdset = node->setData(rdset);
  246. if (old_rdset != NULL) {
  247. RdataSet::destroy(mem_sgmt_, class_, old_rdset);
  248. }
  249. zone_data_->setSigned(true);
  250. }
  251. // simplified version of 'loading' data
  252. void addZoneData(const ConstRRsetPtr rrset) {
  253. ZoneNode* node = NULL;
  254. if (rrset->getType() == RRType::NSEC3()) {
  255. return (addZoneDataNSEC3(rrset));
  256. } else if (rrset->getType() == RRType::NSEC()) {
  257. zone_data_->setSigned(true);
  258. }
  259. zone_data_->insertName(mem_sgmt_, rrset->getName(), &node);
  260. if (rrset->getType() == RRType::NS() &&
  261. rrset->getName() != zone_data_->getOriginNode()->getName()) {
  262. node->setFlag(DomainTreeNode<RdataSet>::FLAG_CALLBACK);
  263. } else if (rrset->getType() == RRType::DNAME()) {
  264. node->setFlag(DomainTreeNode<RdataSet>::FLAG_CALLBACK);
  265. }
  266. RdataSet* next_rds = node->getData();
  267. RdataSet* rdataset =
  268. RdataSet::create(mem_sgmt_, encoder_, rrset, rrset->getRRsig());
  269. rdataset->next = next_rds;
  270. node->setData(rdataset);
  271. // find wildcard nodes in name (go through all of them in case there
  272. // is a nonterminal one)
  273. // Note that this method is pretty much equal to the 'real' loader;
  274. // but less efficient
  275. Name name(rrset->getName());
  276. while (name.getLabelCount() > 1) {
  277. if (name.isWildcard()) {
  278. ZoneNode* wnode = NULL;
  279. // add Wild node
  280. zone_data_->insertName(mem_sgmt_, name.split(1), &wnode);
  281. wnode->setFlag(ZoneData::WILDCARD_NODE);
  282. // add wildcard name itself too
  283. zone_data_->insertName(mem_sgmt_, name, &wnode);
  284. }
  285. name = name.split(1);
  286. }
  287. }
  288. // Some data to test with
  289. const RRClass class_;
  290. const Name origin_;
  291. // The zone finder to torture by tests
  292. MemorySegmentTest mem_sgmt_;
  293. memory::ZoneData* zone_data_;
  294. MyZoneFinder zone_finder_;
  295. isc::datasrc::memory::RdataEncoder encoder_;
  296. // Placeholder for storing RRsets to be checked with rrsetsCheck()
  297. vector<ConstRRsetPtr> actual_rrsets_;
  298. /*
  299. * Some RRsets to put inside the zone.
  300. */
  301. RRsetPtr
  302. // Out of zone RRset
  303. rr_out_,
  304. // NS of example.org
  305. rr_ns_,
  306. // A of ns.example.org
  307. rr_ns_a_,
  308. // AAAA of ns.example.org
  309. rr_ns_aaaa_,
  310. // A of example.org
  311. rr_a_;
  312. RRsetPtr rr_cname_; // CNAME in example.org (RDATA will be added)
  313. RRsetPtr rr_cname_a_; // for mixed CNAME + A case
  314. RRsetPtr rr_dname_; // DNAME in example.org (RDATA will be added)
  315. RRsetPtr rr_dname_a_; // for mixed DNAME + A case
  316. RRsetPtr rr_dname_ns_; // for mixed DNAME + NS case
  317. RRsetPtr rr_dname_apex_; // for mixed DNAME + NS case in the apex
  318. RRsetPtr rr_child_ns_; // NS of a child domain (for delegation)
  319. RRsetPtr rr_child_ds_; // DS of a child domain (for delegation, auth data)
  320. RRsetPtr rr_child_glue_; // glue RR of the child domain
  321. RRsetPtr rr_grandchild_ns_; // NS below a zone cut (unusual)
  322. RRsetPtr rr_grandchild_glue_; // glue RR below a deeper zone cut
  323. RRsetPtr rr_child_dname_; // A DNAME under NS
  324. RRsetPtr rr_wild_; // Wildcard record
  325. RRsetPtr rr_cnamewild_; // CNAME at a wildcard
  326. RRsetPtr rr_emptywild_;
  327. RRsetPtr rr_nested_emptywild_;
  328. RRsetPtr rr_nswild_, rr_dnamewild_;
  329. RRsetPtr rr_child_wild_;
  330. RRsetPtr rr_under_wild_;
  331. RRsetPtr rr_not_wild_;
  332. RRsetPtr rr_not_wild_another_;
  333. RRsetPtr rr_nsec3_;
  334. RRsetPtr rr_nsec_;
  335. RRsetPtr rr_ent_nsec2_;
  336. RRsetPtr rr_ent_nsec3_;
  337. RRsetPtr rr_ent_nsec4_;
  338. RRsetPtr rr_ns_nsec_;
  339. RRsetPtr rr_wild_nsec_;
  340. /**
  341. * \brief Test one find query to the zone finder.
  342. *
  343. * Asks a query to the zone finder and checks it does not throw and returns
  344. * expected results. It returns nothing, it just signals failures
  345. * to GTEST.
  346. *
  347. * \param name The name to ask for.
  348. * \param rrtype The RRType to ask of.
  349. * \param result The expected code of the result.
  350. * \param check_answer Should a check against equality of the answer be
  351. * done?
  352. * \param answer The expected rrset, if any should be returned.
  353. * \param expected_flags The expected result flags returned via find().
  354. * These can be tested using isWildcard() etc.
  355. * \param zone_finder Check different InMemoryZoneFinder object than
  356. * zone_finder_ (if NULL, uses zone_finder_)
  357. * \param check_wild_answer Checks that the answer has the same RRs, type
  358. * class and TTL as the eqxpected answer and that the name corresponds
  359. * to the one searched. It is meant for checking answers for wildcard
  360. * queries.
  361. */
  362. void findTest(const Name& name, const RRType& rrtype,
  363. ZoneFinder::Result result,
  364. bool check_answer = true,
  365. const ConstRRsetPtr& answer = ConstRRsetPtr(),
  366. ZoneFinder::FindResultFlags expected_flags =
  367. ZoneFinder::RESULT_DEFAULT,
  368. memory::InMemoryZoneFinder* zone_finder = NULL,
  369. ZoneFinder::FindOptions options = ZoneFinder::FIND_DEFAULT,
  370. bool check_wild_answer = false)
  371. {
  372. SCOPED_TRACE("findTest for " + name.toText() + "/" + rrtype.toText());
  373. if (zone_finder == NULL) {
  374. zone_finder = &zone_finder_;
  375. }
  376. const ConstRRsetPtr answer_sig = answer ? answer->getRRsig() :
  377. RRsetPtr(); // note we use the same type as of retval of getRRsig()
  378. // The whole block is inside, because we need to check the result and
  379. // we can't assign to FindResult
  380. EXPECT_NO_THROW({
  381. ZoneFinderContextPtr find_result(zone_finder->find(
  382. name, rrtype, options));
  383. // Check it returns correct answers
  384. EXPECT_EQ(result, find_result->code);
  385. EXPECT_EQ((expected_flags & ZoneFinder::RESULT_WILDCARD) != 0,
  386. find_result->isWildcard());
  387. EXPECT_EQ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED)
  388. != 0, find_result->isNSECSigned());
  389. EXPECT_EQ((expected_flags & ZoneFinder::RESULT_NSEC3_SIGNED)
  390. != 0, find_result->isNSEC3Signed());
  391. if (check_answer) {
  392. if (!answer) {
  393. ASSERT_FALSE(find_result->rrset);
  394. } else {
  395. ASSERT_TRUE(find_result->rrset);
  396. ConstRRsetPtr result_rrset(
  397. convertRRset(find_result->rrset));
  398. rrsetCheck(answer, result_rrset);
  399. if (answer_sig) {
  400. ASSERT_TRUE(result_rrset->getRRsig());
  401. rrsetCheck(answer_sig, result_rrset->getRRsig());
  402. }
  403. }
  404. } else if (check_wild_answer) {
  405. ASSERT_NE(ConstRRsetPtr(), answer) <<
  406. "Wrong test, don't check for wild names if you expect "
  407. "empty answer";
  408. ASSERT_NE(ConstRRsetPtr(), find_result->rrset) <<
  409. "No answer found";
  410. // Build the expected answer using the given name and
  411. // other parameter of the base wildcard RRset.
  412. RRsetPtr wildanswer(new RRset(name, answer->getClass(),
  413. answer->getType(),
  414. answer->getTTL()));
  415. RdataIteratorPtr expectedIt(answer->getRdataIterator());
  416. for (; !expectedIt->isLast(); expectedIt->next()) {
  417. wildanswer->addRdata(expectedIt->getCurrent());
  418. }
  419. ConstRRsetPtr result_rrset(
  420. convertRRset(find_result->rrset));
  421. rrsetCheck(wildanswer, result_rrset);
  422. // Same for the RRSIG, if any.
  423. if (answer_sig) {
  424. ASSERT_TRUE(result_rrset->getRRsig());
  425. RRsetPtr wildsig(new RRset(name,
  426. answer_sig->getClass(),
  427. RRType::RRSIG(),
  428. answer_sig->getTTL()));
  429. RdataIteratorPtr expectedIt(
  430. answer_sig->getRdataIterator());
  431. for (; !expectedIt->isLast(); expectedIt->next()) {
  432. wildsig->addRdata(expectedIt->getCurrent());
  433. }
  434. rrsetCheck(wildsig, result_rrset->getRRsig());
  435. }
  436. }
  437. });
  438. }
  439. /**
  440. * \brief Calls the findAll on the finder and checks the result.
  441. */
  442. void findAllTest(const Name& name, ZoneFinder::Result result,
  443. const vector<ConstRRsetPtr>& expected_rrsets,
  444. ZoneFinder::FindResultFlags expected_flags =
  445. ZoneFinder::RESULT_DEFAULT,
  446. memory::InMemoryZoneFinder* finder = NULL,
  447. const ConstRRsetPtr &rrset_result = ConstRRsetPtr(),
  448. ZoneFinder::FindOptions options =
  449. ZoneFinder::FIND_DEFAULT)
  450. {
  451. if (finder == NULL) {
  452. finder = &zone_finder_;
  453. }
  454. std::vector<ConstRRsetPtr> target;
  455. ZoneFinderContextPtr find_result(finder->findAll(name, target,
  456. options));
  457. EXPECT_EQ(result, find_result->code);
  458. if (!rrset_result) {
  459. EXPECT_FALSE(find_result->rrset);
  460. } else {
  461. ASSERT_TRUE(find_result->rrset);
  462. rrsetCheck(rrset_result, convertRRset(find_result->rrset));
  463. }
  464. EXPECT_EQ((expected_flags & ZoneFinder::RESULT_WILDCARD) != 0,
  465. find_result->isWildcard());
  466. EXPECT_EQ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED)
  467. != 0, find_result->isNSECSigned());
  468. EXPECT_EQ((expected_flags & ZoneFinder::RESULT_NSEC3_SIGNED)
  469. != 0, find_result->isNSEC3Signed());
  470. // Convert all rrsets to 'full' ones before checking
  471. std::vector<ConstRRsetPtr> converted_rrsets;
  472. BOOST_FOREACH(ConstRRsetPtr cur_rrset, target) {
  473. converted_rrsets.push_back(convertRRset(cur_rrset));
  474. }
  475. rrsetsCheck(expected_rrsets.begin(), expected_rrsets.end(),
  476. converted_rrsets.begin(), converted_rrsets.end());
  477. }
  478. };
  479. /**
  480. * \brief Test InMemoryZoneFinder::InMemoryZoneFinder constructor.
  481. *
  482. * Takes the created zone finder and checks its properties they are the same
  483. * as passed parameters.
  484. */
  485. TEST_F(InMemoryZoneFinderTest, constructor) {
  486. ASSERT_EQ(origin_, zone_finder_.getOrigin());
  487. }
  488. TEST_F(InMemoryZoneFinderTest, findCNAME) {
  489. // install CNAME RR
  490. addZoneData(rr_cname_);
  491. // Find A RR of the same. Should match the CNAME
  492. findTest(rr_cname_->getName(), RRType::NS(), ZoneFinder::CNAME, true,
  493. rr_cname_);
  494. // Find the CNAME itself. Should result in normal SUCCESS
  495. findTest(rr_cname_->getName(), RRType::CNAME(), ZoneFinder::SUCCESS, true,
  496. rr_cname_);
  497. }
  498. TEST_F(InMemoryZoneFinderTest, findCNAMEUnderZoneCut) {
  499. // There's nothing special when we find a CNAME under a zone cut
  500. // (with FIND_GLUE_OK). The behavior is different from BIND 9,
  501. // so we test this case explicitly.
  502. addZoneData(rr_child_ns_);
  503. ConstRRsetPtr rr_cname_under_cut_ = textToRRset(
  504. "cname.child.example.org. 300 IN CNAME target.child.example.org.");
  505. addZoneData(rr_cname_under_cut_);
  506. findTest(Name("cname.child.example.org"), RRType::AAAA(),
  507. ZoneFinder::CNAME, true, rr_cname_under_cut_,
  508. ZoneFinder::RESULT_DEFAULT, NULL, ZoneFinder::FIND_GLUE_OK);
  509. }
  510. // Search under a DNAME record. It should return the DNAME
  511. TEST_F(InMemoryZoneFinderTest, findBelowDNAME) {
  512. EXPECT_NO_THROW(addZoneData(rr_dname_));
  513. findTest(Name("below.dname.example.org"), RRType::A(), ZoneFinder::DNAME,
  514. true, rr_dname_);
  515. }
  516. // Search at the domain with DNAME. It should act as DNAME isn't there, DNAME
  517. // influences only the data below (see RFC 2672, section 3)
  518. TEST_F(InMemoryZoneFinderTest, findAtDNAME) {
  519. EXPECT_NO_THROW(addZoneData(rr_dname_));
  520. EXPECT_NO_THROW(addZoneData(rr_dname_a_));
  521. const Name dname_name(rr_dname_->getName());
  522. findTest(dname_name, RRType::A(), ZoneFinder::SUCCESS, true, rr_dname_a_);
  523. findTest(dname_name, RRType::DNAME(), ZoneFinder::SUCCESS, true,
  524. rr_dname_);
  525. findTest(dname_name, RRType::TXT(), ZoneFinder::NXRRSET, true);
  526. }
  527. // Try searching something that is both under NS and DNAME, without and with
  528. // GLUE_OK mode (it should stop at the NS and DNAME respectively).
  529. TEST_F(InMemoryZoneFinderTest, DNAMEUnderNS) {
  530. addZoneData(rr_child_ns_);
  531. addZoneData(rr_child_dname_);
  532. Name lowName("below.dname.child.example.org.");
  533. findTest(lowName, RRType::A(), ZoneFinder::DELEGATION, true, rr_child_ns_);
  534. findTest(lowName, RRType::A(), ZoneFinder::DNAME, true, rr_child_dname_,
  535. ZoneFinder::RESULT_DEFAULT, NULL, ZoneFinder::FIND_GLUE_OK);
  536. }
  537. // Test adding child zones and zone cut handling
  538. TEST_F(InMemoryZoneFinderTest, delegationNS) {
  539. // add in-zone data
  540. EXPECT_NO_THROW(addZoneData(rr_ns_));
  541. // install a zone cut
  542. EXPECT_NO_THROW(addZoneData(rr_child_ns_));
  543. // below the zone cut
  544. findTest(Name("www.child.example.org"), RRType::A(),
  545. ZoneFinder::DELEGATION, true, rr_child_ns_);
  546. // at the zone cut
  547. findTest(Name("child.example.org"), RRType::A(), ZoneFinder::DELEGATION,
  548. true, rr_child_ns_);
  549. findTest(Name("child.example.org"), RRType::NS(), ZoneFinder::DELEGATION,
  550. true, rr_child_ns_);
  551. // finding NS for the apex (origin) node. This must not be confused
  552. // with delegation due to the existence of an NS RR.
  553. findTest(origin_, RRType::NS(), ZoneFinder::SUCCESS, true, rr_ns_);
  554. // unusual case of "nested delegation": the highest cut should be used.
  555. EXPECT_NO_THROW(addZoneData(rr_grandchild_ns_));
  556. findTest(Name("www.grand.child.example.org"), RRType::A(),
  557. // note: !rr_grandchild_ns_
  558. ZoneFinder::DELEGATION, true, rr_child_ns_);
  559. }
  560. TEST_F(InMemoryZoneFinderTest, delegationWithDS) {
  561. // Similar setup to the previous one, but with DS RR at the delegation
  562. // point.
  563. addZoneData(rr_ns_);
  564. addZoneData(rr_child_ns_);
  565. addZoneData(rr_child_ds_);
  566. // Normal types of query should result in delegation, but DS query
  567. // should be considered in-zone (but only exactly at the delegation point).
  568. findTest(Name("child.example.org"), RRType::A(), ZoneFinder::DELEGATION,
  569. true, rr_child_ns_);
  570. findTest(Name("child.example.org"), RRType::DS(), ZoneFinder::SUCCESS,
  571. true, rr_child_ds_);
  572. findTest(Name("grand.child.example.org"), RRType::DS(),
  573. ZoneFinder::DELEGATION, true, rr_child_ns_);
  574. // There's nothing special for DS query at the zone apex. It would
  575. // normally result in NXRRSET.
  576. findTest(Name("example.org"), RRType::DS(), ZoneFinder::NXRRSET,
  577. true, ConstRRsetPtr());
  578. }
  579. TEST_F(InMemoryZoneFinderTest, findAny) {
  580. EXPECT_NO_THROW(addZoneData(rr_a_));
  581. EXPECT_NO_THROW(addZoneData(rr_ns_));
  582. EXPECT_NO_THROW(addZoneData(rr_child_glue_));
  583. vector<ConstRRsetPtr> expected_sets;
  584. // origin
  585. expected_sets.push_back(rr_a_);
  586. expected_sets.push_back(rr_ns_);
  587. findAllTest(origin_, ZoneFinder::SUCCESS, expected_sets);
  588. // out zone name
  589. EXPECT_THROW(findAllTest(Name("example.com"), ZoneFinder::NXDOMAIN,
  590. vector<ConstRRsetPtr>()),
  591. OutOfZone);
  592. expected_sets.clear();
  593. expected_sets.push_back(rr_child_glue_);
  594. findAllTest(rr_child_glue_->getName(), ZoneFinder::SUCCESS, expected_sets);
  595. // add zone cut
  596. EXPECT_NO_THROW(addZoneData(rr_child_ns_));
  597. // zone cut
  598. findAllTest(rr_child_ns_->getName(), ZoneFinder::DELEGATION,
  599. vector<ConstRRsetPtr>(), ZoneFinder::RESULT_DEFAULT,
  600. NULL, rr_child_ns_);
  601. // glue for this zone cut
  602. findAllTest(rr_child_glue_->getName(),ZoneFinder::DELEGATION,
  603. vector<ConstRRsetPtr>(), ZoneFinder::RESULT_DEFAULT,
  604. NULL, rr_child_ns_);
  605. }
  606. TEST_F(InMemoryZoneFinderTest, glue) {
  607. // install zone data:
  608. // a zone cut
  609. EXPECT_NO_THROW(addZoneData(rr_child_ns_));
  610. // glue for this cut
  611. EXPECT_NO_THROW(addZoneData(rr_child_glue_));
  612. // a nested zone cut (unusual)
  613. EXPECT_NO_THROW(addZoneData(rr_grandchild_ns_));
  614. // glue under the deeper zone cut
  615. EXPECT_NO_THROW(addZoneData(rr_grandchild_glue_));
  616. // by default glue is hidden due to the zone cut
  617. findTest(rr_child_glue_->getName(), RRType::A(), ZoneFinder::DELEGATION,
  618. true, rr_child_ns_);
  619. // If we do it in the "glue OK" mode, we should find the exact match.
  620. findTest(rr_child_glue_->getName(), RRType::A(), ZoneFinder::SUCCESS, true,
  621. rr_child_glue_, ZoneFinder::RESULT_DEFAULT, NULL,
  622. ZoneFinder::FIND_GLUE_OK);
  623. // glue OK + NXRRSET case
  624. findTest(rr_child_glue_->getName(), RRType::AAAA(), ZoneFinder::NXRRSET,
  625. true, ConstRRsetPtr(), ZoneFinder::RESULT_DEFAULT, NULL,
  626. ZoneFinder::FIND_GLUE_OK);
  627. // glue OK + NXDOMAIN case
  628. findTest(Name("www.child.example.org"), RRType::A(),
  629. ZoneFinder::DELEGATION, true, rr_child_ns_,
  630. ZoneFinder::RESULT_DEFAULT, NULL, ZoneFinder::FIND_GLUE_OK);
  631. // nested cut case. The glue should be found.
  632. findTest(rr_grandchild_glue_->getName(), RRType::AAAA(),
  633. ZoneFinder::SUCCESS,
  634. true, rr_grandchild_glue_, ZoneFinder::RESULT_DEFAULT, NULL,
  635. ZoneFinder::FIND_GLUE_OK);
  636. // A non-existent name in nested cut. This should result in delegation
  637. // at the highest zone cut.
  638. findTest(Name("www.grand.child.example.org"), RRType::TXT(),
  639. ZoneFinder::DELEGATION, true, rr_child_ns_,
  640. ZoneFinder::RESULT_DEFAULT, NULL, ZoneFinder::FIND_GLUE_OK);
  641. }
  642. /**
  643. * \brief Test searching.
  644. *
  645. * Check it finds or does not find correctly and does not throw exceptions.
  646. */
  647. void
  648. InMemoryZoneFinderTest::findCheck(ZoneFinder::FindResultFlags expected_flags,
  649. ZoneFinder::FindOptions find_options)
  650. {
  651. // Fill some data inside
  652. // Now put all the data we have there. It should throw nothing
  653. EXPECT_NO_THROW(addZoneData(rr_ns_));
  654. EXPECT_NO_THROW(addZoneData(rr_ns_a_));
  655. EXPECT_NO_THROW(addZoneData(rr_ns_aaaa_));
  656. EXPECT_NO_THROW(addZoneData(rr_a_));
  657. if ((expected_flags & ZoneFinder::RESULT_NSEC3_SIGNED) != 0) {
  658. addZoneData(rr_nsec3_);
  659. zone_data_->setSigned(true);
  660. }
  661. if ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED) != 0) {
  662. addZoneData(rr_nsec_);
  663. zone_data_->setSigned(true);
  664. }
  665. // These two should be successful
  666. findTest(origin_, RRType::NS(), ZoneFinder::SUCCESS, true, rr_ns_);
  667. findTest(rr_ns_a_->getName(), RRType::A(), ZoneFinder::SUCCESS, true,
  668. rr_ns_a_);
  669. // These domains don't exist. (and one is out of the zone). In an
  670. // NSEC-signed zone with DNSSEC records requested, it should return the
  671. // covering NSEC for the query name (the actual NSEC in the test data may
  672. // not really "cover" it, but for the purpose of this test it's okay).
  673. ConstRRsetPtr expected_nsec; // by default it's NULL
  674. if ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED) != 0 &&
  675. (find_options & ZoneFinder::FIND_DNSSEC) != 0) {
  676. expected_nsec = rr_nsec_;
  677. }
  678. // There's no other name between this one and the origin, so when NSEC
  679. // is to be returned it should be the origin NSEC.
  680. findTest(Name("nothere.example.org"), RRType::A(),
  681. ZoneFinder::NXDOMAIN, true, expected_nsec, expected_flags,
  682. NULL, find_options);
  683. // The previous name in the zone is "ns.example.org", but it doesn't
  684. // have an NSEC. It should be skipped and the origin NSEC will be
  685. // returned as the "closest NSEC".
  686. findTest(Name("nxdomain.example.org"), RRType::A(),
  687. ZoneFinder::NXDOMAIN, true, expected_nsec, expected_flags,
  688. NULL, find_options);
  689. EXPECT_THROW(zone_finder_.find(Name("example.net"), RRType::A()),
  690. OutOfZone);
  691. // These domain exist but don't have the provided RRType. For the latter
  692. // one we now add its NSEC (which was delayed so that it wouldn't break
  693. // other cases above).
  694. findTest(origin_, RRType::AAAA(), ZoneFinder::NXRRSET, true,
  695. expected_nsec, expected_flags, NULL, find_options);
  696. if ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED) != 0) {
  697. addZoneData(rr_ns_nsec_);
  698. zone_data_->setSigned(true);
  699. if ((find_options & ZoneFinder::FIND_DNSSEC) != 0) {
  700. expected_nsec = rr_ns_nsec_;
  701. }
  702. }
  703. findTest(rr_ns_a_->getName(), RRType::NS(), ZoneFinder::NXRRSET, true,
  704. expected_nsec, expected_flags, NULL, find_options);
  705. }
  706. TEST_F(InMemoryZoneFinderTest, find) {
  707. findCheck();
  708. }
  709. TEST_F(InMemoryZoneFinderTest, findNSEC3Signed) {
  710. findCheck(ZoneFinder::RESULT_NSEC3_SIGNED);
  711. }
  712. TEST_F(InMemoryZoneFinderTest, findNSEC3SignedWithDNSSEC) {
  713. // For NSEC3-signed zones, specifying the DNSSEC option shouldn't change
  714. // anything (the NSEC3_SIGNED flag is always set, and no records are
  715. // returned for negative cases regardless).
  716. findCheck(ZoneFinder::RESULT_NSEC3_SIGNED, ZoneFinder::FIND_DNSSEC);
  717. }
  718. TEST_F(InMemoryZoneFinderTest, findNSECSigned) {
  719. // NSEC-signed zone, without requesting DNSSEC (no NSEC should be provided)
  720. findCheck(ZoneFinder::RESULT_NSEC_SIGNED);
  721. }
  722. // Generalized test for Empty Nonterminal (ENT) cases with NSEC
  723. void
  724. InMemoryZoneFinderTest::findNSECENTCheck(const Name& ent_name,
  725. ConstRRsetPtr expected_nsec,
  726. ZoneFinder::FindResultFlags expected_flags)
  727. {
  728. addZoneData(rr_emptywild_);
  729. addZoneData(rr_under_wild_);
  730. // Sanity check: Should result in NXRRSET
  731. findTest(ent_name, RRType::A(), ZoneFinder::NXRRSET, true,
  732. ConstRRsetPtr(), expected_flags);
  733. // Sanity check: No NSEC added yet
  734. findTest(ent_name, RRType::A(), ZoneFinder::NXRRSET, true,
  735. ConstRRsetPtr(), expected_flags,
  736. NULL, ZoneFinder::FIND_DNSSEC);
  737. // Now add the NSEC rrs making it a 'complete' zone (in terms of NSEC,
  738. // there are no sigs)
  739. addZoneData(rr_nsec_);
  740. addZoneData(rr_ent_nsec2_);
  741. addZoneData(rr_ent_nsec3_);
  742. addZoneData(rr_ent_nsec4_);
  743. zone_data_->setSigned(true);
  744. // Should result in NXRRSET, and RESULT_NSEC_SIGNED
  745. findTest(ent_name, RRType::A(), ZoneFinder::NXRRSET, true,
  746. ConstRRsetPtr(),
  747. expected_flags | ZoneFinder::RESULT_NSEC_SIGNED);
  748. // And check for the NSEC if DNSSEC_OK
  749. findTest(ent_name, RRType::A(), ZoneFinder::NXRRSET, true,
  750. expected_nsec, expected_flags | ZoneFinder::RESULT_NSEC_SIGNED,
  751. NULL, ZoneFinder::FIND_DNSSEC);
  752. }
  753. TEST_F(InMemoryZoneFinderTest,findNSECEmptyNonterminal) {
  754. // Non-wildcard case
  755. findNSECENTCheck(Name("wild.example.org"), rr_ent_nsec3_);
  756. }
  757. TEST_F(InMemoryZoneFinderTest, findNSECEmptyNonterminalWildcard) {
  758. // Wildcard case, above actual wildcard
  759. findNSECENTCheck(Name("foo.example.org"), rr_nsec_);
  760. }
  761. TEST_F(InMemoryZoneFinderTest, findNSECEmptyNonterminalAtWildcard) {
  762. // Wildcard case, at actual wildcard
  763. findNSECENTCheck(Name("bar.foo.example.org"), rr_nsec_,
  764. ZoneFinder::RESULT_WILDCARD);
  765. }
  766. TEST_F(InMemoryZoneFinderTest, findNSECSignedWithDNSSEC) {
  767. // NSEC-signed zone, requesting DNSSEC (NSEC should be provided)
  768. findCheck(ZoneFinder::RESULT_NSEC_SIGNED, ZoneFinder::FIND_DNSSEC);
  769. }
  770. void
  771. InMemoryZoneFinderTest::emptyNodeCheck(
  772. ZoneFinder::FindResultFlags expected_flags)
  773. {
  774. /*
  775. * The backend RBTree for this test should look like as follows:
  776. * example.org
  777. * |
  778. * baz (empty; easy case)
  779. * / | \
  780. * bar | x.foo ('foo' part is empty; a bit trickier)
  781. * bbb
  782. * /
  783. * aaa
  784. */
  785. // Construct the test zone
  786. const char* const names[] = {
  787. "bar.example.org.", "x.foo.example.org.", "aaa.baz.example.org.",
  788. "bbb.baz.example.org.", NULL};
  789. for (int i = 0; names[i] != NULL; ++i) {
  790. ConstRRsetPtr rrset = textToRRset(string(names[i]) +
  791. " 300 IN A 192.0.2.1");
  792. addZoneData(rrset);
  793. }
  794. if ((expected_flags & ZoneFinder::RESULT_NSEC3_SIGNED) != 0) {
  795. addZoneData(rr_nsec3_);
  796. zone_data_->setSigned(true);
  797. }
  798. if ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED) != 0) {
  799. addZoneData(rr_nsec_);
  800. zone_data_->setSigned(true);
  801. }
  802. // empty node matching, easy case: the node for 'baz' exists with
  803. // no data.
  804. findTest(Name("baz.example.org"), RRType::A(), ZoneFinder::NXRRSET, true,
  805. ConstRRsetPtr(), expected_flags);
  806. // empty node matching, a trickier case: the node for 'foo' is part of
  807. // "x.foo", which should be considered an empty node.
  808. findTest(Name("foo.example.org"), RRType::A(), ZoneFinder::NXRRSET, true,
  809. ConstRRsetPtr(), expected_flags);
  810. // "org" is contained in "example.org", but it shouldn't be treated as
  811. // NXRRSET because it's out of zone.
  812. // Note: basically we don't expect such a query to be performed (the common
  813. // operation is to identify the best matching zone first then perform
  814. // search it), but we shouldn't be confused even in the unexpected case.
  815. EXPECT_THROW(zone_finder_.find(Name("org"), RRType::A()), OutOfZone);
  816. }
  817. TEST_F(InMemoryZoneFinderTest, emptyNode) {
  818. emptyNodeCheck();
  819. }
  820. TEST_F(InMemoryZoneFinderTest, emptyNodeNSEC3) {
  821. emptyNodeCheck(ZoneFinder::RESULT_NSEC3_SIGNED);
  822. }
  823. TEST_F(InMemoryZoneFinderTest, emptyNodeNSEC) {
  824. emptyNodeCheck(ZoneFinder::RESULT_NSEC_SIGNED);
  825. }
  826. /*
  827. * Test that puts a (simple) wildcard into the zone and checks we can
  828. * correctly find the data.
  829. */
  830. void
  831. InMemoryZoneFinderTest::wildcardCheck(
  832. ZoneFinder::FindResultFlags expected_flags,
  833. ZoneFinder::FindOptions find_options)
  834. {
  835. /*
  836. * example.org.
  837. * |
  838. * [cname]wild (not *.wild, should have wild mark)
  839. * |
  840. * *
  841. */
  842. // If the zone is "signed" (detecting it by the NSEC/NSEC3 signed flags),
  843. // add RRSIGs to the records.
  844. if ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED) != 0 ||
  845. (expected_flags & ZoneFinder::RESULT_NSEC3_SIGNED) != 0) {
  846. // Convenience shortcut. The RDATA is not really validatable, but
  847. // it doesn't matter for our tests.
  848. const char* const rrsig_common = "5 3 3600 "
  849. "20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE";
  850. find_options = find_options | ZoneFinder::FIND_DNSSEC;
  851. rr_wild_->addRRsig(textToRRset("*.wild.example.org. 300 IN RRSIG A " +
  852. string(rrsig_common)));
  853. rr_cnamewild_->addRRsig(textToRRset("*.cnamewild.example.org. 300 IN "
  854. "RRSIG CNAME " +
  855. string(rrsig_common)));
  856. }
  857. addZoneData(rr_wild_);
  858. addZoneData(rr_cnamewild_);
  859. // If the zone is expected to be "signed" with NSEC3, add an NSEC3.
  860. // (the content of the NSEC3 shouldn't matter)
  861. if ((expected_flags & ZoneFinder::RESULT_NSEC3_SIGNED) != 0) {
  862. addZoneData(rr_nsec3_);
  863. }
  864. if ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED) != 0) {
  865. addZoneData(rr_nsec_);
  866. }
  867. // Search at the parent. The parent will not have the A, but it will
  868. // be in the wildcard (so check the wildcard isn't matched at the parent)
  869. {
  870. SCOPED_TRACE("Search at parent");
  871. if ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED) != 0) {
  872. findTest(Name("wild.example.org"), RRType::A(),
  873. ZoneFinder::NXRRSET, true, rr_nsec_, expected_flags,
  874. NULL, find_options);
  875. } else {
  876. findTest(Name("wild.example.org"), RRType::A(),
  877. ZoneFinder::NXRRSET, true, ConstRRsetPtr(),
  878. expected_flags, NULL, find_options);
  879. }
  880. }
  881. // For the test setup of "NSEC-signed" zone, we might expect it will
  882. // be returned with a negative result, either because wildcard match is
  883. // disabled by the search option or because wildcard match is canceled
  884. // per protocol.
  885. ConstRRsetPtr expected_nsec; // by default it's NULL
  886. if ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED) != 0 &&
  887. (find_options & ZoneFinder::FIND_DNSSEC) != 0) {
  888. expected_nsec = rr_nsec_;
  889. }
  890. // Explicitly converting the following to const pointers; some compilers
  891. // would complain about mixed use of const and non const in ?: below.
  892. const ConstRRsetPtr rr_wild = rr_wild_;
  893. const ConstRRsetPtr rr_cnamewild = rr_cnamewild_;
  894. // Search the original name of wildcard
  895. {
  896. SCOPED_TRACE("Search directly at *");
  897. findTest(Name("*.wild.example.org"), RRType::A(), ZoneFinder::SUCCESS,
  898. true, rr_wild_, ZoneFinder::RESULT_DEFAULT, NULL,
  899. find_options);
  900. }
  901. // Below some of the test cases will normally result in a wildcard match;
  902. // if NO_WILDCARD is specified, it should result in NXDOMAIN instead,
  903. // and, when available and requested, the covering NSEC will be returned.
  904. // The following are shortcut parameters to unify these cases.
  905. const bool wild_ok = ((find_options & ZoneFinder::NO_WILDCARD) == 0);
  906. const ZoneFinder::FindResultFlags wild_expected_flags =
  907. wild_ok ? (ZoneFinder::RESULT_WILDCARD | expected_flags) :
  908. expected_flags;
  909. // Search "created" name.
  910. {
  911. SCOPED_TRACE("Search at created child");
  912. findTest(Name("a.wild.example.org"), RRType::A(),
  913. wild_ok ? ZoneFinder::SUCCESS : ZoneFinder::NXDOMAIN, false,
  914. wild_ok ? rr_wild : expected_nsec,
  915. wild_expected_flags, NULL, find_options, wild_ok);
  916. }
  917. // Search name that has CNAME.
  918. {
  919. SCOPED_TRACE("Matching CNAME");
  920. findTest(Name("a.cnamewild.example.org"), RRType::A(),
  921. wild_ok ? ZoneFinder::CNAME : ZoneFinder::NXDOMAIN, false,
  922. wild_ok ? rr_cnamewild : expected_nsec,
  923. wild_expected_flags, NULL, find_options, wild_ok);
  924. }
  925. // Search another created name, this time little bit lower
  926. {
  927. SCOPED_TRACE("Search at created grand-child");
  928. findTest(Name("a.b.wild.example.org"), RRType::A(),
  929. wild_ok ? ZoneFinder::SUCCESS : ZoneFinder::NXDOMAIN, false,
  930. wild_ok ? rr_wild : expected_nsec,
  931. wild_expected_flags, NULL, find_options, wild_ok);
  932. }
  933. addZoneData(rr_under_wild_);
  934. {
  935. SCOPED_TRACE("Search under non-wildcard");
  936. findTest(Name("bar.foo.wild.example.org"), RRType::A(),
  937. ZoneFinder::NXDOMAIN, true, expected_nsec, expected_flags,
  938. NULL, find_options);
  939. }
  940. // Wildcard match, but no data. We add the additional NSEC at the wildcard
  941. // at this point so that it wouldn't break other tests above. Note also
  942. // that in the NO_WILDCARD case the resulting NSEC is the same. Ideally
  943. // we could use a more tricky setup so we can distinguish these cases,
  944. // but for this purpose it's not bad; what we'd like to test here is that
  945. // wildcard substitution doesn't happen for either case, and the
  946. // NO_WILDCARD effect itself can be checked by the result code (NXDOMAIN).
  947. ConstRRsetPtr expected_wild_nsec; // by default it's NULL
  948. if ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED) != 0) {
  949. addZoneData(rr_wild_nsec_);
  950. expected_wild_nsec = rr_wild_nsec_;
  951. }
  952. {
  953. SCOPED_TRACE("Search at wildcard, no data");
  954. findTest(Name("a.wild.example.org"), RRType::AAAA(),
  955. wild_ok ? ZoneFinder::NXRRSET : ZoneFinder::NXDOMAIN, true,
  956. wild_ok ? expected_wild_nsec : expected_wild_nsec,
  957. wild_expected_flags, NULL, find_options);
  958. }
  959. }
  960. TEST_F(InMemoryZoneFinderTest, wildcard) {
  961. // Normal case
  962. wildcardCheck();
  963. }
  964. TEST_F(InMemoryZoneFinderTest, wildcardDisabledWithNSEC) {
  965. // Wildcard is disabled. In practice, this is used as part of query
  966. // processing for an NSEC-signed zone, so we test that case specifically.
  967. wildcardCheck(ZoneFinder::RESULT_NSEC_SIGNED, ZoneFinder::NO_WILDCARD);
  968. }
  969. TEST_F(InMemoryZoneFinderTest, wildcardDisabledWithoutNSEC) {
  970. // Similar to the previous once, but check the behavior for a non signed
  971. // zone just in case.
  972. wildcardCheck(ZoneFinder::RESULT_DEFAULT, ZoneFinder::NO_WILDCARD);
  973. }
  974. /*
  975. * Test that we don't match a wildcard if we get under delegation.
  976. * By 4.3.3 of RFC1034:
  977. * "Wildcard RRs do not apply:
  978. * - When the query is in another zone. That is, delegation cancels
  979. * the wildcard defaults."
  980. */
  981. TEST_F(InMemoryZoneFinderTest, delegatedWildcard) {
  982. addZoneData(rr_child_wild_);
  983. addZoneData(rr_child_ns_);
  984. {
  985. SCOPED_TRACE("Looking under delegation point");
  986. findTest(Name("a.child.example.org"), RRType::A(),
  987. ZoneFinder::DELEGATION, true, rr_child_ns_);
  988. }
  989. {
  990. SCOPED_TRACE("Looking under delegation point in GLUE_OK mode");
  991. findTest(Name("a.child.example.org"), RRType::A(),
  992. ZoneFinder::DELEGATION, true, rr_child_ns_,
  993. ZoneFinder::RESULT_DEFAULT, NULL, ZoneFinder::FIND_GLUE_OK);
  994. }
  995. }
  996. // Tests combination of wildcard and ANY.
  997. void
  998. InMemoryZoneFinderTest::anyWildcardCheck(
  999. ZoneFinder::FindResultFlags expected_flags)
  1000. {
  1001. addZoneData(rr_wild_);
  1002. if ((expected_flags & ZoneFinder::RESULT_NSEC3_SIGNED) != 0) {
  1003. addZoneData(rr_nsec3_);
  1004. }
  1005. if ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED) != 0) {
  1006. addZoneData(rr_nsec_);
  1007. }
  1008. vector<ConstRRsetPtr> expected_sets;
  1009. // First try directly the name (normal match)
  1010. {
  1011. SCOPED_TRACE("Asking directly for *");
  1012. expected_sets.push_back(rr_wild_);
  1013. findAllTest(Name("*.wild.example.org"), ZoneFinder::SUCCESS,
  1014. expected_sets);
  1015. }
  1016. // Then a wildcard match
  1017. {
  1018. SCOPED_TRACE("Asking in the wild way");
  1019. expected_sets.clear();
  1020. RRsetPtr expected(new RRset(Name("a.wild.example.org"),
  1021. rr_wild_->getClass(), rr_wild_->getType(),
  1022. rr_wild_->getTTL()));
  1023. expected->addRdata(rr_wild_->getRdataIterator()->getCurrent());
  1024. expected_sets.push_back(expected);
  1025. findAllTest(Name("a.wild.example.org"), ZoneFinder::SUCCESS,
  1026. expected_sets,
  1027. ZoneFinder::RESULT_WILDCARD | expected_flags);
  1028. }
  1029. }
  1030. TEST_F(InMemoryZoneFinderTest, anyWildcard) {
  1031. anyWildcardCheck();
  1032. }
  1033. TEST_F(InMemoryZoneFinderTest, anyWildcardNSEC3) {
  1034. anyWildcardCheck(ZoneFinder::RESULT_NSEC3_SIGNED);
  1035. }
  1036. TEST_F(InMemoryZoneFinderTest, anyWildcardNSEC) {
  1037. anyWildcardCheck(ZoneFinder::RESULT_NSEC_SIGNED);
  1038. }
  1039. // Test there's nothing in the wildcard in the middle if we load
  1040. // wild.*.foo.example.org.
  1041. void
  1042. InMemoryZoneFinderTest::emptyWildcardCheck(
  1043. ZoneFinder::FindResultFlags expected_flags)
  1044. {
  1045. /*
  1046. * example.org.
  1047. * foo
  1048. * *
  1049. * wild
  1050. */
  1051. addZoneData(rr_emptywild_);
  1052. if ((expected_flags & ZoneFinder::RESULT_NSEC3_SIGNED) != 0) {
  1053. addZoneData(rr_nsec3_);
  1054. }
  1055. if ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED) != 0) {
  1056. addZoneData(rr_nsec_);
  1057. }
  1058. {
  1059. SCOPED_TRACE("Asking for the original record under wildcard");
  1060. findTest(Name("wild.*.foo.example.org"), RRType::A(),
  1061. ZoneFinder::SUCCESS, true, rr_emptywild_);
  1062. }
  1063. {
  1064. SCOPED_TRACE("Asking for A record");
  1065. findTest(Name("a.foo.example.org"), RRType::A(), ZoneFinder::NXRRSET,
  1066. true, ConstRRsetPtr(),
  1067. ZoneFinder::RESULT_WILDCARD | expected_flags);
  1068. findTest(Name("*.foo.example.org"), RRType::A(), ZoneFinder::NXRRSET,
  1069. true, ConstRRsetPtr(), expected_flags);
  1070. findTest(Name("foo.example.org"), RRType::A(), ZoneFinder::NXRRSET,
  1071. true, ConstRRsetPtr(), expected_flags);
  1072. }
  1073. {
  1074. SCOPED_TRACE("Asking for ANY record");
  1075. findAllTest(Name("*.foo.example.org"), ZoneFinder::NXRRSET,
  1076. vector<ConstRRsetPtr>(), expected_flags);
  1077. findAllTest(Name("a.foo.example.org"), ZoneFinder::NXRRSET,
  1078. vector<ConstRRsetPtr>(),
  1079. ZoneFinder::RESULT_WILDCARD | expected_flags);
  1080. }
  1081. {
  1082. SCOPED_TRACE("Asking on the non-terminal");
  1083. findTest(Name("wild.bar.foo.example.org"), RRType::A(),
  1084. ZoneFinder::NXRRSET, true, ConstRRsetPtr(),
  1085. ZoneFinder::RESULT_WILDCARD | expected_flags);
  1086. }
  1087. }
  1088. TEST_F(InMemoryZoneFinderTest, emptyWildcard) {
  1089. emptyWildcardCheck();
  1090. }
  1091. TEST_F(InMemoryZoneFinderTest, emptyWildcardNSEC3) {
  1092. emptyWildcardCheck(ZoneFinder::RESULT_NSEC3_SIGNED);
  1093. }
  1094. TEST_F(InMemoryZoneFinderTest, emptyWildcardNSEC) {
  1095. emptyWildcardCheck(ZoneFinder::RESULT_NSEC_SIGNED);
  1096. }
  1097. // Same as emptyWildcard, but with multiple * in the path.
  1098. TEST_F(InMemoryZoneFinderTest, nestedEmptyWildcard) {
  1099. addZoneData(rr_nested_emptywild_);
  1100. {
  1101. SCOPED_TRACE("Asking for the original record under wildcards");
  1102. findTest(Name("wild.*.foo.*.bar.example.org"), RRType::A(),
  1103. ZoneFinder::SUCCESS, true, rr_nested_emptywild_);
  1104. }
  1105. {
  1106. SCOPED_TRACE("Matching wildcard against empty nonterminal");
  1107. const char* names[] = {
  1108. "baz.foo.*.bar.example.org",
  1109. "baz.foo.baz.bar.example.org",
  1110. "*.foo.baz.bar.example.org",
  1111. NULL
  1112. };
  1113. for (const char** name = names; *name != NULL; ++ name) {
  1114. SCOPED_TRACE(string("Node ") + *name);
  1115. findTest(Name(*name), RRType::A(), ZoneFinder::NXRRSET, true,
  1116. ConstRRsetPtr(), ZoneFinder::RESULT_WILDCARD);
  1117. }
  1118. }
  1119. // Domains to test
  1120. const char* names[] = {
  1121. "*.foo.*.bar.example.org",
  1122. "foo.*.bar.example.org",
  1123. "*.bar.example.org",
  1124. "bar.example.org",
  1125. NULL
  1126. };
  1127. {
  1128. SCOPED_TRACE("Asking directly for A on parent nodes");
  1129. for (const char** name = names; *name != NULL; ++ name) {
  1130. SCOPED_TRACE(string("Node ") + *name);
  1131. findTest(Name(*name), RRType::A(), ZoneFinder::NXRRSET);
  1132. }
  1133. }
  1134. {
  1135. SCOPED_TRACE("Asking for ANY on parent nodes");
  1136. for (const char** name = names; *name != NULL; ++ name) {
  1137. SCOPED_TRACE(string("Node ") + *name);
  1138. findAllTest(Name(*name), ZoneFinder::NXRRSET,
  1139. vector<ConstRRsetPtr>());
  1140. }
  1141. }
  1142. }
  1143. // We run this part twice from the below test, in two slightly different
  1144. // situations
  1145. void
  1146. InMemoryZoneFinderTest::doCancelWildcardCheck(
  1147. ZoneFinder::FindResultFlags expected_flags,
  1148. ZoneFinder::FindOptions find_options)
  1149. {
  1150. // These should be canceled
  1151. {
  1152. SCOPED_TRACE("Canceled under foo.wild.example.org");
  1153. // For an NSEC-signed zone with DNSSEC requested, the covering NSEC
  1154. // should be returned. The expected NSEC is actually just the only
  1155. // NSEC in the test data, but in this context it doesn't matter;
  1156. // it's sufficient just to check any NSEC is returned (or not).
  1157. ConstRRsetPtr expected_nsec; // by default it's NULL
  1158. if ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED) != 0 &&
  1159. (find_options & ZoneFinder::FIND_DNSSEC)) {
  1160. expected_nsec = rr_nsec_;
  1161. }
  1162. findTest(Name("aaa.foo.wild.example.org"), RRType::A(),
  1163. ZoneFinder::NXDOMAIN, true, expected_nsec, expected_flags,
  1164. NULL, find_options);
  1165. findTest(Name("zzz.foo.wild.example.org"), RRType::A(),
  1166. ZoneFinder::NXDOMAIN, true, expected_nsec, expected_flags,
  1167. NULL, find_options);
  1168. }
  1169. // This is existing, non-wildcard domain, shouldn't wildcard at all
  1170. {
  1171. SCOPED_TRACE("Existing domain under foo.wild.example.org");
  1172. findTest(Name("bar.foo.wild.example.org"), RRType::A(),
  1173. ZoneFinder::SUCCESS, true, rr_not_wild_);
  1174. }
  1175. // These should be caught by the wildcard
  1176. {
  1177. SCOPED_TRACE("Neighbor wildcards to foo.wild.example.org");
  1178. const char* names[] = {
  1179. "aaa.bbb.wild.example.org",
  1180. "aaa.zzz.wild.example.org",
  1181. "zzz.wild.example.org",
  1182. NULL
  1183. };
  1184. for (const char** name = names; *name != NULL; ++ name) {
  1185. SCOPED_TRACE(string("Node ") + *name);
  1186. findTest(Name(*name), RRType::A(), ZoneFinder::SUCCESS, false,
  1187. rr_wild_,
  1188. ZoneFinder::RESULT_WILDCARD | expected_flags, NULL,
  1189. ZoneFinder::FIND_DEFAULT, true);
  1190. }
  1191. }
  1192. // This shouldn't be wildcarded, it's an existing domain
  1193. {
  1194. SCOPED_TRACE("The foo.wild.example.org itself");
  1195. findTest(Name("foo.wild.example.org"), RRType::A(),
  1196. ZoneFinder::NXRRSET, true, ConstRRsetPtr(), expected_flags);
  1197. }
  1198. }
  1199. /*
  1200. * This tests that if there's a name between the wildcard domain and the
  1201. * searched one, it will not trigger wildcard, for example, if we have
  1202. * *.wild.example.org and bar.foo.wild.example.org, then we know
  1203. * foo.wild.example.org exists and is not wildcard. Therefore, search for
  1204. * aaa.foo.wild.example.org should return NXDOMAIN.
  1205. *
  1206. * Tests few cases "around" the canceled wildcard match, to see something that
  1207. * shouldn't be canceled isn't.
  1208. */
  1209. TEST_F(InMemoryZoneFinderTest, cancelWildcard) {
  1210. addZoneData(rr_wild_);
  1211. addZoneData(rr_not_wild_);
  1212. {
  1213. SCOPED_TRACE("Runnig with single entry under foo.wild.example.org");
  1214. doCancelWildcardCheck();
  1215. }
  1216. // Try putting another one under foo.wild....
  1217. // The result should be the same but it will be done in another way in the
  1218. // code, because the foo.wild.example.org will exist in the tree.
  1219. addZoneData(rr_not_wild_another_);
  1220. {
  1221. SCOPED_TRACE("Runnig with two entries under foo.wild.example.org");
  1222. doCancelWildcardCheck();
  1223. }
  1224. }
  1225. // Same tests as cancelWildcard for NSEC3-signed zone
  1226. TEST_F(InMemoryZoneFinderTest, cancelWildcardNSEC3) {
  1227. addZoneData(rr_wild_);
  1228. addZoneData(rr_not_wild_);
  1229. addZoneData(rr_nsec3_);
  1230. {
  1231. SCOPED_TRACE("Runnig with single entry under foo.wild.example.org");
  1232. doCancelWildcardCheck(ZoneFinder::RESULT_NSEC3_SIGNED);
  1233. }
  1234. addZoneData(rr_not_wild_another_);
  1235. {
  1236. SCOPED_TRACE("Runnig with two entries under foo.wild.example.org");
  1237. doCancelWildcardCheck(ZoneFinder::RESULT_NSEC3_SIGNED);
  1238. }
  1239. }
  1240. // Same tests as cancelWildcard for NSEC-signed zone. Check both cases with
  1241. // or without FIND_DNSSEC option. NSEC should be returned only when the option
  1242. // is given.
  1243. TEST_F(InMemoryZoneFinderTest, cancelWildcardNSEC) {
  1244. addZoneData(rr_wild_);
  1245. addZoneData(rr_not_wild_);
  1246. addZoneData(rr_nsec_);
  1247. {
  1248. SCOPED_TRACE("Runnig with single entry under foo.wild.example.org");
  1249. doCancelWildcardCheck(ZoneFinder::RESULT_NSEC_SIGNED,
  1250. ZoneFinder::FIND_DNSSEC);
  1251. doCancelWildcardCheck(ZoneFinder::RESULT_NSEC_SIGNED);
  1252. }
  1253. addZoneData(rr_not_wild_another_);
  1254. {
  1255. SCOPED_TRACE("Runnig with two entries under foo.wild.example.org");
  1256. doCancelWildcardCheck(ZoneFinder::RESULT_NSEC_SIGNED,
  1257. ZoneFinder::FIND_DNSSEC);
  1258. doCancelWildcardCheck(ZoneFinder::RESULT_NSEC_SIGNED);
  1259. }
  1260. }
  1261. TEST_F(InMemoryZoneFinderTest, findNSEC3ForBadZone) {
  1262. // Set up the faked hash calculator.
  1263. zone_finder_.setFakeNSEC3Calculate();
  1264. // If the zone has nothing about NSEC3 (neither NSEC3 or NSEC3PARAM),
  1265. // findNSEC3() should be rejected.
  1266. EXPECT_THROW(zone_finder_.findNSEC3(Name("www.example.org"), true),
  1267. DataSourceError);
  1268. // Only having NSEC3PARAM isn't enough
  1269. addZoneData(textToRRset("example.org. 300 IN NSEC3PARAM "
  1270. "1 0 12 aabbccdd"));
  1271. EXPECT_THROW(zone_finder_.findNSEC3(Name("www.example.org"), true),
  1272. DataSourceError);
  1273. // Unless NSEC3 for apex is added the result in the recursive mode
  1274. // is guaranteed.
  1275. const string ns1_nsec3_text = string(ns1_hash) + ".example.org." +
  1276. string(nsec3_common);
  1277. addZoneData(textToRRset(ns1_nsec3_text));
  1278. EXPECT_THROW(zone_finder_.findNSEC3(Name("www.example.org"), true),
  1279. DataSourceError);
  1280. }
  1281. /// \brief NSEC3 specific tests fixture for the InMemoryZoneFinder class
  1282. class InMemoryZoneFinderNSEC3Test : public InMemoryZoneFinderTest {
  1283. public:
  1284. InMemoryZoneFinderNSEC3Test() {
  1285. // Set up the faked hash calculator.
  1286. zone_finder_.setFakeNSEC3Calculate();
  1287. // Add a few NSEC3 records:
  1288. // apex (example.org.): hash=0P..
  1289. // ns1.example.org: hash=2T..
  1290. // w.example.org: hash=01..
  1291. // zzz.example.org: hash=R5..
  1292. const string apex_nsec3_text = string(apex_hash) + ".example.org." +
  1293. string(nsec3_common);
  1294. addZoneData(textToRRset(apex_nsec3_text));
  1295. const string ns1_nsec3_text = string(ns1_hash) + ".example.org." +
  1296. string(nsec3_common);
  1297. addZoneData(textToRRset(ns1_nsec3_text));
  1298. const string w_nsec3_text = string(w_hash) + ".example.org." +
  1299. string(nsec3_common);
  1300. addZoneData(textToRRset(w_nsec3_text));
  1301. const string zzz_nsec3_text = string(zzz_hash) + ".example.org." +
  1302. string(nsec3_common);
  1303. addZoneData(textToRRset(zzz_nsec3_text));
  1304. }
  1305. };
  1306. TEST_F(InMemoryZoneFinderNSEC3Test, findNSEC3) {
  1307. performNSEC3Test(zone_finder_);
  1308. }
  1309. struct TestData {
  1310. // String for the name passed to findNSEC3() (concatenated with
  1311. // "example.org.")
  1312. const char* const name;
  1313. // Should recursive findNSEC3() be performed?
  1314. const bool recursive;
  1315. // The following are members of the FindNSEC3Result returned by
  1316. // findNSEC3(). The proofs are given as char*, which are converted
  1317. // to Name objects and checked against getName() on the returned
  1318. // ConstRRsetPtr. If any of these is NULL, then it's expected that
  1319. // ConstRRsetPtr() will be returned.
  1320. const bool matched;
  1321. const uint8_t closest_labels;
  1322. const char* const closest_proof;
  1323. const char* const next_proof;
  1324. };
  1325. const TestData nsec3_data[] = {
  1326. // ==== These are non-recursive tests.
  1327. {"n0", false, false, 4, "R53BQ7CC2UVMUBFU5OCMM6PERS9TK9EN", NULL},
  1328. {"n1", false, true, 4, "01UDEMVP1J2F7EG6JEBPS17VP3N8I58H", NULL},
  1329. {"n2", false, false, 4, "01UDEMVP1J2F7EG6JEBPS17VP3N8I58H", NULL},
  1330. {"n3", false, true, 4, "0P9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM", NULL},
  1331. {"n4", false, false, 4, "0P9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM", NULL},
  1332. {"n5", false, true, 4, "2T7B4G4VSA5SMI47K61MV5BV1A22BOJR", NULL},
  1333. {"n6", false, false, 4, "2T7B4G4VSA5SMI47K61MV5BV1A22BOJR", NULL},
  1334. {"n7", false, true, 4, "R53BQ7CC2UVMUBFU5OCMM6PERS9TK9EN", NULL},
  1335. {"n8", false, false, 4, "R53BQ7CC2UVMUBFU5OCMM6PERS9TK9EN", NULL},
  1336. // ==== These are recursive tests.
  1337. {"n0", true, true, 3, "0P9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM",
  1338. "R53BQ7CC2UVMUBFU5OCMM6PERS9TK9EN"},
  1339. {"n1", true, true, 4, "01UDEMVP1J2F7EG6JEBPS17VP3N8I58H", NULL},
  1340. {"n2", true, true, 3, "0P9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM",
  1341. "01UDEMVP1J2F7EG6JEBPS17VP3N8I58H"},
  1342. {"n3", true, true, 4, "0P9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM", NULL},
  1343. {"n4", true, true, 3, "0P9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM",
  1344. "0P9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM"},
  1345. {"n5", true, true, 4, "2T7B4G4VSA5SMI47K61MV5BV1A22BOJR", NULL},
  1346. {"n6", true, true, 3, "0P9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM",
  1347. "2T7B4G4VSA5SMI47K61MV5BV1A22BOJR"},
  1348. {"n7", true, true, 4, "R53BQ7CC2UVMUBFU5OCMM6PERS9TK9EN", NULL},
  1349. {"n8", true, true, 3, "0P9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM",
  1350. "R53BQ7CC2UVMUBFU5OCMM6PERS9TK9EN"}
  1351. };
  1352. const size_t data_count(sizeof(nsec3_data) / sizeof(*nsec3_data));
  1353. TEST_F(InMemoryZoneFinderNSEC3Test, findNSEC3Walk) {
  1354. // This test basically uses nsec3_data[] declared above along with
  1355. // the fake hash setup to walk the NSEC3 tree. The names and fake
  1356. // hash calculation is specially setup so that the tree search
  1357. // terminates at specific locations in the tree. We findNSEC3() on
  1358. // each of the nsec3_data[], which is setup such that the hash
  1359. // results in the search terminating on either side of each node of
  1360. // the NSEC3 tree. This way, we check what result is returned in
  1361. // every search termination case in the NSEC3 tree.
  1362. const Name origin("example.org");
  1363. for (size_t i = 0; i < data_count; ++i) {
  1364. const Name name = Name(nsec3_data[i].name).concatenate(origin);
  1365. SCOPED_TRACE(name.toText() + (nsec3_data[i].recursive ?
  1366. ", recursive" :
  1367. ", non-recursive"));
  1368. const ZoneFinder::FindNSEC3Result result =
  1369. zone_finder_.findNSEC3(name, nsec3_data[i].recursive);
  1370. EXPECT_EQ(nsec3_data[i].matched, result.matched);
  1371. EXPECT_EQ(nsec3_data[i].closest_labels, result.closest_labels);
  1372. if (nsec3_data[i].closest_proof != NULL) {
  1373. ASSERT_TRUE(result.closest_proof);
  1374. EXPECT_EQ(Name(nsec3_data[i].closest_proof).concatenate(origin),
  1375. result.closest_proof->getName());
  1376. } else {
  1377. EXPECT_FALSE(result.closest_proof);
  1378. }
  1379. if (nsec3_data[i].next_proof != NULL) {
  1380. ASSERT_TRUE(result.next_proof);
  1381. EXPECT_EQ(Name(nsec3_data[i].next_proof).concatenate(origin),
  1382. result.next_proof->getName());
  1383. } else {
  1384. EXPECT_FALSE(result.next_proof);
  1385. }
  1386. }
  1387. }
  1388. }