memory_datasrc_unittest.cc 83 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004
  1. // Copyright (C) 2010 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 <sstream>
  15. #include <vector>
  16. #include <boost/bind.hpp>
  17. #include <boost/foreach.hpp>
  18. #include <exceptions/exceptions.h>
  19. #include <dns/masterload.h>
  20. #include <dns/name.h>
  21. #include <dns/nsec3hash.h>
  22. #include <dns/rdata.h>
  23. #include <dns/rdataclass.h>
  24. #include <dns/rrclass.h>
  25. #include <dns/rrsetlist.h>
  26. #include <dns/rrttl.h>
  27. #include <dns/masterload.h>
  28. #include <datasrc/memory_datasrc.h>
  29. #include <datasrc/data_source.h>
  30. #include <datasrc/iterator.h>
  31. #include <testutils/dnsmessage_test.h>
  32. #include <gtest/gtest.h>
  33. using namespace std;
  34. using namespace isc::dns;
  35. using namespace isc::dns::rdata;
  36. using namespace isc::datasrc;
  37. using namespace isc::testutils;
  38. namespace {
  39. // Commonly used result codes (Who should write the prefix all the time)
  40. using result::SUCCESS;
  41. using result::EXIST;
  42. class InMemoryClientTest : public ::testing::Test {
  43. protected:
  44. InMemoryClientTest() : rrclass(RRClass::IN())
  45. {}
  46. RRClass rrclass;
  47. InMemoryClient memory_client;
  48. };
  49. TEST_F(InMemoryClientTest, add_find_Zone) {
  50. // test add zone
  51. // Bogus zone (NULL)
  52. EXPECT_THROW(memory_client.addZone(ZoneFinderPtr()),
  53. isc::InvalidParameter);
  54. // add zones with different names one by one
  55. EXPECT_EQ(result::SUCCESS, memory_client.addZone(
  56. ZoneFinderPtr(new InMemoryZoneFinder(RRClass::IN(),
  57. Name("a")))));
  58. EXPECT_EQ(result::SUCCESS, memory_client.addZone(
  59. ZoneFinderPtr(new InMemoryZoneFinder(RRClass::CH(),
  60. Name("b")))));
  61. EXPECT_EQ(result::SUCCESS, memory_client.addZone(
  62. ZoneFinderPtr(new InMemoryZoneFinder(RRClass::IN(),
  63. Name("c")))));
  64. // add zones with the same name suffix
  65. EXPECT_EQ(result::SUCCESS, memory_client.addZone(
  66. ZoneFinderPtr(new InMemoryZoneFinder(RRClass::CH(),
  67. Name("x.d.e.f")))));
  68. EXPECT_EQ(result::SUCCESS, memory_client.addZone(
  69. ZoneFinderPtr(new InMemoryZoneFinder(RRClass::CH(),
  70. Name("o.w.y.d.e.f")))));
  71. EXPECT_EQ(result::SUCCESS, memory_client.addZone(
  72. ZoneFinderPtr(new InMemoryZoneFinder(RRClass::CH(),
  73. Name("p.w.y.d.e.f")))));
  74. EXPECT_EQ(result::SUCCESS, memory_client.addZone(
  75. ZoneFinderPtr(new InMemoryZoneFinder(RRClass::IN(),
  76. Name("q.w.y.d.e.f")))));
  77. // add super zone and its subzone
  78. EXPECT_EQ(result::SUCCESS, memory_client.addZone(
  79. ZoneFinderPtr(new InMemoryZoneFinder(RRClass::CH(),
  80. Name("g.h")))));
  81. EXPECT_EQ(result::SUCCESS, memory_client.addZone(
  82. ZoneFinderPtr(new InMemoryZoneFinder(RRClass::IN(),
  83. Name("i.g.h")))));
  84. EXPECT_EQ(result::SUCCESS, memory_client.addZone(
  85. ZoneFinderPtr(new InMemoryZoneFinder(RRClass::IN(),
  86. Name("z.d.e.f")))));
  87. EXPECT_EQ(result::SUCCESS, memory_client.addZone(
  88. ZoneFinderPtr(new InMemoryZoneFinder(RRClass::IN(),
  89. Name("j.z.d.e.f")))));
  90. // different zone class isn't allowed.
  91. EXPECT_EQ(result::EXIST, memory_client.addZone(
  92. ZoneFinderPtr(new InMemoryZoneFinder(RRClass::CH(),
  93. Name("q.w.y.d.e.f")))));
  94. // names are compared in a case insensitive manner.
  95. EXPECT_EQ(result::EXIST, memory_client.addZone(
  96. ZoneFinderPtr(new InMemoryZoneFinder(RRClass::IN(),
  97. Name("Q.W.Y.d.E.f")))));
  98. // test find zone
  99. EXPECT_EQ(result::SUCCESS, memory_client.findZone(Name("a")).code);
  100. EXPECT_EQ(Name("a"),
  101. memory_client.findZone(Name("a")).zone_finder->getOrigin());
  102. EXPECT_EQ(result::SUCCESS,
  103. memory_client.findZone(Name("j.z.d.e.f")).code);
  104. EXPECT_EQ(Name("j.z.d.e.f"),
  105. memory_client.findZone(Name("j.z.d.e.f")).zone_finder->
  106. getOrigin());
  107. // NOTFOUND
  108. EXPECT_EQ(result::NOTFOUND, memory_client.findZone(Name("d.e.f")).code);
  109. EXPECT_EQ(ConstZoneFinderPtr(),
  110. memory_client.findZone(Name("d.e.f")).zone_finder);
  111. EXPECT_EQ(result::NOTFOUND,
  112. memory_client.findZone(Name("w.y.d.e.f")).code);
  113. EXPECT_EQ(ConstZoneFinderPtr(),
  114. memory_client.findZone(Name("w.y.d.e.f")).zone_finder);
  115. // there's no exact match. the result should be the longest match,
  116. // and the code should be PARTIALMATCH.
  117. EXPECT_EQ(result::PARTIALMATCH,
  118. memory_client.findZone(Name("j.g.h")).code);
  119. EXPECT_EQ(Name("g.h"),
  120. memory_client.findZone(Name("g.h")).zone_finder->getOrigin());
  121. EXPECT_EQ(result::PARTIALMATCH,
  122. memory_client.findZone(Name("z.i.g.h")).code);
  123. EXPECT_EQ(Name("i.g.h"),
  124. memory_client.findZone(Name("z.i.g.h")).zone_finder->
  125. getOrigin());
  126. }
  127. TEST_F(InMemoryClientTest, iterator) {
  128. // Just some preparations of data
  129. boost::shared_ptr<InMemoryZoneFinder>
  130. zone(new InMemoryZoneFinder(RRClass::IN(), Name("a")));
  131. RRsetPtr aRRsetA(new RRset(Name("a"), RRClass::IN(), RRType::A(),
  132. RRTTL(300)));
  133. aRRsetA->addRdata(rdata::in::A("192.0.2.1"));
  134. RRsetPtr aRRsetAAAA(new RRset(Name("a"), RRClass::IN(), RRType::AAAA(),
  135. RRTTL(300)));
  136. aRRsetAAAA->addRdata(rdata::in::AAAA("2001:db8::1"));
  137. aRRsetAAAA->addRdata(rdata::in::AAAA("2001:db8::2"));
  138. RRsetPtr subRRsetA(new RRset(Name("sub.x.a"), RRClass::IN(), RRType::A(),
  139. RRTTL(300)));
  140. subRRsetA->addRdata(rdata::in::A("192.0.2.2"));
  141. EXPECT_EQ(result::SUCCESS, memory_client.addZone(zone));
  142. // First, the zone is not there, so it should throw
  143. EXPECT_THROW(memory_client.getIterator(Name("b")), DataSourceError);
  144. // This zone is not there either, even when there's a zone containing this
  145. EXPECT_THROW(memory_client.getIterator(Name("x.a")), DataSourceError);
  146. // Now, an empty zone
  147. ZoneIteratorPtr iterator(memory_client.getIterator(Name("a")));
  148. EXPECT_EQ(ConstRRsetPtr(), iterator->getNextRRset());
  149. // It throws Unexpected when we are past the end
  150. EXPECT_THROW(iterator->getNextRRset(), isc::Unexpected);
  151. EXPECT_EQ(result::SUCCESS, zone->add(aRRsetA));
  152. EXPECT_EQ(result::SUCCESS, zone->add(aRRsetAAAA));
  153. EXPECT_EQ(result::SUCCESS, zone->add(subRRsetA));
  154. // Check it with full zone, one by one.
  155. // It should be in ascending order in case of InMemory data source
  156. // (isn't guaranteed in general)
  157. iterator = memory_client.getIterator(Name("a"));
  158. EXPECT_EQ(aRRsetA, iterator->getNextRRset());
  159. EXPECT_EQ(aRRsetAAAA, iterator->getNextRRset());
  160. EXPECT_EQ(subRRsetA, iterator->getNextRRset());
  161. EXPECT_EQ(ConstRRsetPtr(), iterator->getNextRRset());
  162. }
  163. TEST_F(InMemoryClientTest, iterator_separate_rrs) {
  164. // Exactly the same tests as for iterator, but now with separate_rrs = true
  165. // For the one that returns actual data, the AAAA should now be split up
  166. boost::shared_ptr<InMemoryZoneFinder>
  167. zone(new InMemoryZoneFinder(RRClass::IN(), Name("a")));
  168. RRsetPtr aRRsetA(new RRset(Name("a"), RRClass::IN(), RRType::A(),
  169. RRTTL(300)));
  170. aRRsetA->addRdata(rdata::in::A("192.0.2.1"));
  171. RRsetPtr aRRsetAAAA(new RRset(Name("a"), RRClass::IN(), RRType::AAAA(),
  172. RRTTL(300)));
  173. aRRsetAAAA->addRdata(rdata::in::AAAA("2001:db8::1"));
  174. aRRsetAAAA->addRdata(rdata::in::AAAA("2001:db8::2"));
  175. RRsetPtr aRRsetAAAA_r1(new RRset(Name("a"), RRClass::IN(), RRType::AAAA(),
  176. RRTTL(300)));
  177. aRRsetAAAA_r1->addRdata(rdata::in::AAAA("2001:db8::1"));
  178. RRsetPtr aRRsetAAAA_r2(new RRset(Name("a"), RRClass::IN(), RRType::AAAA(),
  179. RRTTL(300)));
  180. aRRsetAAAA_r2->addRdata(rdata::in::AAAA("2001:db8::2"));
  181. RRsetPtr subRRsetA(new RRset(Name("sub.x.a"), RRClass::IN(), RRType::A(),
  182. RRTTL(300)));
  183. subRRsetA->addRdata(rdata::in::A("192.0.2.2"));
  184. EXPECT_EQ(result::SUCCESS, memory_client.addZone(zone));
  185. // First, the zone is not there, so it should throw
  186. EXPECT_THROW(memory_client.getIterator(Name("b"), true), DataSourceError);
  187. // This zone is not there either, even when there's a zone containing this
  188. EXPECT_THROW(memory_client.getIterator(Name("x.a")), DataSourceError);
  189. // Now, an empty zone
  190. ZoneIteratorPtr iterator(memory_client.getIterator(Name("a"), true));
  191. EXPECT_EQ(ConstRRsetPtr(), iterator->getNextRRset());
  192. // It throws Unexpected when we are past the end
  193. EXPECT_THROW(iterator->getNextRRset(), isc::Unexpected);
  194. ASSERT_EQ(result::SUCCESS, zone->add(aRRsetA));
  195. ASSERT_EQ(result::SUCCESS, zone->add(aRRsetAAAA));
  196. ASSERT_EQ(result::SUCCESS, zone->add(subRRsetA));
  197. // Check it with full zone, one by one.
  198. // It should be in ascending order in case of InMemory data source
  199. // (isn't guaranteed in general)
  200. iterator = memory_client.getIterator(Name("a"), true);
  201. EXPECT_EQ(aRRsetA->toText(), iterator->getNextRRset()->toText());
  202. EXPECT_EQ(aRRsetAAAA_r1->toText(), iterator->getNextRRset()->toText());
  203. EXPECT_EQ(aRRsetAAAA_r2->toText(), iterator->getNextRRset()->toText());
  204. EXPECT_EQ(subRRsetA->toText(), iterator->getNextRRset()->toText());
  205. EXPECT_EQ(ConstRRsetPtr(), iterator->getNextRRset());
  206. }
  207. TEST_F(InMemoryClientTest, getZoneCount) {
  208. EXPECT_EQ(0, memory_client.getZoneCount());
  209. memory_client.addZone(
  210. ZoneFinderPtr(new InMemoryZoneFinder(rrclass,
  211. Name("example.com"))));
  212. EXPECT_EQ(1, memory_client.getZoneCount());
  213. // duplicate add. counter shouldn't change
  214. memory_client.addZone(
  215. ZoneFinderPtr(new InMemoryZoneFinder(rrclass,
  216. Name("example.com"))));
  217. EXPECT_EQ(1, memory_client.getZoneCount());
  218. // add one more
  219. memory_client.addZone(
  220. ZoneFinderPtr(new InMemoryZoneFinder(rrclass,
  221. Name("example.org"))));
  222. EXPECT_EQ(2, memory_client.getZoneCount());
  223. }
  224. TEST_F(InMemoryClientTest, startUpdateZone) {
  225. EXPECT_THROW(memory_client.getUpdater(Name("example.org"), false),
  226. isc::NotImplemented);
  227. }
  228. // Commonly used RRSIG data
  229. const char* const rrsig_a_txt =
  230. "example.org. 300 IN RRSIG A 5 3 3600 20000101000000 20000201000000 12345 "
  231. "example.org. FAKEFAKEFAKE\n";
  232. const char* const rrsig_ns_txt =
  233. "example.org. 300 IN RRSIG NS 5 3 3600 20000101000000 20000201000000 "
  234. "54321 example.org. FAKEFAKEFAKEFAKE\n";
  235. // This RRset has two RRSIGs
  236. const char* const rrsig_aaaa_txt =
  237. "ns.example.org. 300 IN RRSIG AAAA 5 3 3600 20000101000000 20000201000000 "
  238. "12345 example.org. FAKEFAKEFAKE\n"
  239. "ns.example.org. 300 IN RRSIG AAAA 5 3 3600 20000101000000 20000201000000 "
  240. "54321 example.org. FAKEFAKEFAKEFAKE\n";
  241. // A helper callback of masterLoad() used in InMemoryZoneFinderTest.
  242. void
  243. setRRset(RRsetPtr rrset, vector<RRsetPtr*>::iterator& it) {
  244. *(*it) = rrset;
  245. ++it;
  246. }
  247. ConstRRsetPtr
  248. textToRRset(const string& text_rrset, const RRClass& rrclass = RRClass::IN()) {
  249. stringstream ss(text_rrset);
  250. RRsetPtr rrset;
  251. vector<RRsetPtr*> rrsets;
  252. rrsets.push_back(&rrset);
  253. masterLoad(ss, Name::ROOT_NAME(), rrclass,
  254. boost::bind(setRRset, _1, rrsets.begin()));
  255. return (rrset);
  256. }
  257. // Some faked NSEC3 hash values commonly used in tests and the faked NSEC3Hash
  258. // object.
  259. //
  260. // For apex (example.org)
  261. const char* const apex_hash = "0P9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM";
  262. const char* const apex_hash_lower = "0p9mhaveqvm6t7vbl5lop2u3t2rp3tom";
  263. // For ns1.example.org
  264. const char* const ns1_hash = "2T7B4G4VSA5SMI47K61MV5BV1A22BOJR";
  265. // For w.example.org
  266. const char* const w_hash = "01UDEMVP1J2F7EG6JEBPS17VP3N8I58H";
  267. // For x.y.w.example.org (lower-cased)
  268. const char* const xyw_hash = "2vptu5timamqttgl4luu9kg21e0aor3s";
  269. // For zzz.example.org.
  270. const char* const zzz_hash = "R53BQ7CC2UVMUBFU5OCMM6PERS9TK9EN";
  271. // A simple faked NSEC3 hash calculator with a dedicated creator for it.
  272. //
  273. // This is used in some NSEC3-related tests below.
  274. class TestNSEC3HashCreator : public NSEC3HashCreator {
  275. class TestNSEC3Hash : public NSEC3Hash {
  276. private:
  277. typedef map<Name, string> NSEC3HashMap;
  278. typedef NSEC3HashMap::value_type NSEC3HashPair;
  279. NSEC3HashMap map_;
  280. public:
  281. TestNSEC3Hash() {
  282. // Build pre-defined hash
  283. map_[Name("example.org")] = apex_hash;
  284. map_[Name("www.example.org")] = "2S9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM";
  285. map_[Name("xxx.example.org")] = "Q09MHAVEQVM6T7VBL5LOP2U3T2RP3TOM";
  286. map_[Name("yyy.example.org")] = "0A9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM";
  287. map_[Name("x.y.w.example.org")] =
  288. "2VPTU5TIMAMQTTGL4LUU9KG21E0AOR3S";
  289. map_[Name("y.w.example.org")] = "K8UDEMVP1J2F7EG6JEBPS17VP3N8I58H";
  290. map_[Name("w.example.org")] = w_hash;
  291. map_[Name("zzz.example.org")] = zzz_hash;
  292. map_[Name("smallest.example.org")] =
  293. "00000000000000000000000000000000";
  294. map_[Name("largest.example.org")] =
  295. "UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU";
  296. }
  297. virtual string calculate(const Name& name) const {
  298. const NSEC3HashMap::const_iterator found = map_.find(name);
  299. if (found != map_.end()) {
  300. return (found->second);
  301. }
  302. isc_throw(isc::Unexpected, "unexpected name for NSEC3 test: "
  303. << name);
  304. }
  305. virtual bool match(const generic::NSEC3PARAM&) const {
  306. return (true);
  307. }
  308. virtual bool match(const generic::NSEC3&) const {
  309. return (true);
  310. }
  311. };
  312. public:
  313. virtual NSEC3Hash* create(const generic::NSEC3PARAM&) const {
  314. return (new TestNSEC3Hash);
  315. }
  316. virtual NSEC3Hash* create(const generic::NSEC3&) const {
  317. return (new TestNSEC3Hash);
  318. }
  319. };
  320. /// \brief Test fixture for the InMemoryZoneFinder class
  321. class InMemoryZoneFinderTest : public ::testing::Test {
  322. // A straightforward pair of textual RR(set) and a RRsetPtr variable
  323. // to store the RRset. Used to build test data below.
  324. struct RRsetData {
  325. const char* const text; // textual representation of an RRset
  326. RRsetPtr* rrset;
  327. };
  328. protected:
  329. // The following sub tests are shared by multiple test cases, changing
  330. // the zone's DNSSEC status (unsigned, NSEC-signed or NSEC3-signed).
  331. // expected_flags is set to either RESULT_NSEC_SIGNED or
  332. // RESULT_NSEC3_SIGNED when it's NSEC/NSEC3 signed respectively and
  333. // find() is expected to set the corresponding flags.
  334. void findCheck(ZoneFinder::FindResultFlags expected_flags =
  335. ZoneFinder::RESULT_DEFAULT);
  336. void emptyNodeCheck(ZoneFinder::FindResultFlags expected_flags =
  337. ZoneFinder::RESULT_DEFAULT);
  338. void wildcardCheck(ZoneFinder::FindResultFlags expected_flags =
  339. ZoneFinder::RESULT_DEFAULT);
  340. void doCancelWildcardCheck(ZoneFinder::FindResultFlags expected_flags =
  341. ZoneFinder::RESULT_DEFAULT);
  342. void anyWildcardCheck(ZoneFinder::FindResultFlags expected_flags =
  343. ZoneFinder::RESULT_DEFAULT);
  344. void emptyWildcardCheck(ZoneFinder::FindResultFlags expected_flags =
  345. ZoneFinder::RESULT_DEFAULT);
  346. public:
  347. InMemoryZoneFinderTest() :
  348. class_(RRClass::IN()),
  349. origin_("example.org"),
  350. zone_finder_(class_, origin_)
  351. {
  352. // Build test RRsets. Below, we construct an RRset for
  353. // each textual RR(s) of zone_data, and assign it to the corresponding
  354. // rr_xxx.
  355. const RRsetData zone_data[] = {
  356. {"example.org. 300 IN NS ns.example.org.", &rr_ns_},
  357. {"example.org. 300 IN A 192.0.2.1", &rr_a_},
  358. {"ns.example.org. 300 IN A 192.0.2.2", &rr_ns_a_},
  359. {"ns.example.org. 300 IN AAAA 2001:db8::2", &rr_ns_aaaa_},
  360. {"cname.example.org. 300 IN CNAME canonical.example.org",
  361. &rr_cname_},
  362. {"cname.example.org. 300 IN A 192.0.2.3", &rr_cname_a_},
  363. {"dname.example.org. 300 IN DNAME target.example.org.",
  364. &rr_dname_},
  365. {"dname.example.org. 300 IN A 192.0.2.39", &rr_dname_a_},
  366. {"dname.example.org. 300 IN NS ns.dname.example.org.",
  367. &rr_dname_ns_},
  368. {"example.org. 300 IN DNAME example.com.", &rr_dname_apex_},
  369. {"child.example.org. 300 IN NS ns.child.example.org.",
  370. &rr_child_ns_},
  371. {"child.example.org. 300 IN DS 12345 5 1 DEADBEEF",
  372. &rr_child_ds_},
  373. {"ns.child.example.org. 300 IN A 192.0.2.153",
  374. &rr_child_glue_},
  375. {"grand.child.example.org. 300 IN NS ns.grand.child.example.org.",
  376. &rr_grandchild_ns_},
  377. {"ns.grand.child.example.org. 300 IN AAAA 2001:db8::253",
  378. &rr_grandchild_glue_},
  379. {"dname.child.example.org. 300 IN DNAME example.com.",
  380. &rr_child_dname_},
  381. {"example.com. 300 IN A 192.0.2.10", &rr_out_},
  382. {"*.wild.example.org. 300 IN A 192.0.2.1", &rr_wild_},
  383. {"*.cnamewild.example.org. 300 IN CNAME canonial.example.org.",
  384. &rr_cnamewild_},
  385. {"foo.wild.example.org. 300 IN A 192.0.2.3", &rr_under_wild_},
  386. {"wild.*.foo.example.org. 300 IN A 192.0.2.1", &rr_emptywild_},
  387. {"wild.*.foo.*.bar.example.org. 300 IN A 192.0.2.1",
  388. &rr_nested_emptywild_},
  389. {"*.nswild.example.org. 300 IN NS nswild.example.", &rr_nswild_},
  390. {"*.dnamewild.example.org. 300 IN DNAME dnamewild.example.",
  391. &rr_dnamewild_},
  392. {"*.child.example.org. 300 IN A 192.0.2.1", &rr_child_wild_},
  393. {"bar.foo.wild.example.org. 300 IN A 192.0.2.2", &rr_not_wild_},
  394. {"baz.foo.wild.example.org. 300 IN A 192.0.2.3",
  395. &rr_not_wild_another_},
  396. {"0P9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM.example.org. 300 IN "
  397. "NSEC3 1 1 12 aabbccdd 2T7B4G4VSA5SMI47K61MV5BV1A22BOJR A RRSIG",
  398. &rr_nsec3_},
  399. {NULL, NULL}
  400. };
  401. stringstream zone_data_stream;
  402. vector<RRsetPtr*> rrsets;
  403. for (unsigned int i = 0; zone_data[i].text != NULL; ++i) {
  404. zone_data_stream << zone_data[i].text << "\n";
  405. rrsets.push_back(zone_data[i].rrset);
  406. }
  407. masterLoad(zone_data_stream, Name::ROOT_NAME(), class_,
  408. boost::bind(setRRset, _1, rrsets.begin()));
  409. }
  410. ~InMemoryZoneFinderTest() {
  411. // Make sure we reset the hash creator to the default
  412. setNSEC3HashCreator(NULL);
  413. }
  414. // Some data to test with
  415. const RRClass class_;
  416. const Name origin_;
  417. // The zone finder to torture by tests
  418. InMemoryZoneFinder zone_finder_;
  419. // Placeholder for storing RRsets to be checked with rrsetsCheck()
  420. vector<ConstRRsetPtr> actual_rrsets_;
  421. /*
  422. * Some RRsets to put inside the zone.
  423. */
  424. RRsetPtr
  425. // Out of zone RRset
  426. rr_out_,
  427. // NS of example.org
  428. rr_ns_,
  429. // A of ns.example.org
  430. rr_ns_a_,
  431. // AAAA of ns.example.org
  432. rr_ns_aaaa_,
  433. // A of example.org
  434. rr_a_;
  435. RRsetPtr rr_cname_; // CNAME in example.org (RDATA will be added)
  436. RRsetPtr rr_cname_a_; // for mixed CNAME + A case
  437. RRsetPtr rr_dname_; // DNAME in example.org (RDATA will be added)
  438. RRsetPtr rr_dname_a_; // for mixed DNAME + A case
  439. RRsetPtr rr_dname_ns_; // for mixed DNAME + NS case
  440. RRsetPtr rr_dname_apex_; // for mixed DNAME + NS case in the apex
  441. RRsetPtr rr_child_ns_; // NS of a child domain (for delegation)
  442. RRsetPtr rr_child_ds_; // DS of a child domain (for delegation, auth data)
  443. RRsetPtr rr_child_glue_; // glue RR of the child domain
  444. RRsetPtr rr_grandchild_ns_; // NS below a zone cut (unusual)
  445. RRsetPtr rr_grandchild_glue_; // glue RR below a deeper zone cut
  446. RRsetPtr rr_child_dname_; // A DNAME under NS
  447. RRsetPtr rr_wild_; // Wildcard record
  448. RRsetPtr rr_cnamewild_; // CNAME at a wildcard
  449. RRsetPtr rr_emptywild_;
  450. RRsetPtr rr_nested_emptywild_;
  451. RRsetPtr rr_nswild_, rr_dnamewild_;
  452. RRsetPtr rr_child_wild_;
  453. RRsetPtr rr_under_wild_;
  454. RRsetPtr rr_not_wild_;
  455. RRsetPtr rr_not_wild_another_;
  456. RRsetPtr rr_nsec3_;
  457. // A faked NSEC3 hash calculator for convenience.
  458. // Tests that need to use the faked hashed values should call
  459. // setNSEC3HashCreator() with a pointer to this variable at the beginning
  460. // of the test (at least before adding any NSEC3/NSEC3PARAM RR).
  461. TestNSEC3HashCreator nsec3_hash_creator_;
  462. /**
  463. * \brief Test one find query to the zone finder.
  464. *
  465. * Asks a query to the zone finder and checks it does not throw and returns
  466. * expected results. It returns nothing, it just signals failures
  467. * to GTEST.
  468. *
  469. * \param name The name to ask for.
  470. * \param rrtype The RRType to ask of.
  471. * \param result The expected code of the result.
  472. * \param check_answer Should a check against equality of the answer be
  473. * done?
  474. * \param answer The expected rrset, if any should be returned.
  475. * \param expected_flags The expected result flags returned via find().
  476. * These can be tested using isWildcard() etc.
  477. * \param zone_finder Check different InMemoryZoneFinder object than
  478. * zone_finder_ (if NULL, uses zone_finder_)
  479. * \param check_wild_answer Checks that the answer has the same RRs, type
  480. * class and TTL as the eqxpected answer and that the name corresponds
  481. * to the one searched. It is meant for checking answers for wildcard
  482. * queries.
  483. */
  484. void findTest(const Name& name, const RRType& rrtype,
  485. ZoneFinder::Result result,
  486. bool check_answer = true,
  487. const ConstRRsetPtr& answer = ConstRRsetPtr(),
  488. ZoneFinder::FindResultFlags expected_flags =
  489. ZoneFinder::RESULT_DEFAULT,
  490. InMemoryZoneFinder* zone_finder = NULL,
  491. ZoneFinder::FindOptions options = ZoneFinder::FIND_DEFAULT,
  492. bool check_wild_answer = false)
  493. {
  494. if (zone_finder == NULL) {
  495. zone_finder = &zone_finder_;
  496. }
  497. // The whole block is inside, because we need to check the result and
  498. // we can't assign to FindResult
  499. EXPECT_NO_THROW({
  500. ZoneFinder::FindResult find_result(zone_finder->find(
  501. name, rrtype, options));
  502. // Check it returns correct answers
  503. EXPECT_EQ(result, find_result.code);
  504. EXPECT_EQ((expected_flags & ZoneFinder::RESULT_WILDCARD) != 0,
  505. find_result.isWildcard());
  506. EXPECT_EQ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED)
  507. != 0, find_result.isNSECSigned());
  508. EXPECT_EQ((expected_flags & ZoneFinder::RESULT_NSEC3_SIGNED)
  509. != 0, find_result.isNSEC3Signed());
  510. if (check_answer) {
  511. if (!answer) {
  512. ASSERT_FALSE(find_result.rrset);
  513. } else {
  514. ASSERT_TRUE(find_result.rrset);
  515. rrsetCheck(answer, find_result.rrset);
  516. }
  517. } else if (check_wild_answer) {
  518. ASSERT_NE(ConstRRsetPtr(), answer) <<
  519. "Wrong test, don't check for wild names if you expect "
  520. "empty answer";
  521. ASSERT_NE(ConstRRsetPtr(), find_result.rrset) <<
  522. "No answer found";
  523. // Build the expected answer using the given name and
  524. // other parameter of the base wildcard RRset.
  525. RRsetPtr wildanswer(new RRset(name, answer->getClass(),
  526. answer->getType(),
  527. answer->getTTL()));
  528. RdataIteratorPtr expectedIt(answer->getRdataIterator());
  529. for (; !expectedIt->isLast(); expectedIt->next()) {
  530. wildanswer->addRdata(expectedIt->getCurrent());
  531. }
  532. rrsetCheck(wildanswer, find_result.rrset);
  533. }
  534. });
  535. }
  536. /**
  537. * \brief Calls the findAll on the finder and checks the result.
  538. */
  539. void findAllTest(const Name& name, ZoneFinder::Result result,
  540. const vector<ConstRRsetPtr>& expected_rrsets,
  541. ZoneFinder::FindResultFlags expected_flags =
  542. ZoneFinder::RESULT_DEFAULT,
  543. InMemoryZoneFinder* finder = NULL,
  544. const ConstRRsetPtr &rrset_result = ConstRRsetPtr(),
  545. ZoneFinder::FindOptions options =
  546. ZoneFinder::FIND_DEFAULT)
  547. {
  548. if (finder == NULL) {
  549. finder = &zone_finder_;
  550. }
  551. std::vector<ConstRRsetPtr> target;
  552. ZoneFinder::FindResult find_result(finder->findAll(name, target,
  553. options));
  554. EXPECT_EQ(result, find_result.code);
  555. if (!rrset_result) {
  556. EXPECT_FALSE(find_result.rrset);
  557. } else {
  558. ASSERT_TRUE(find_result.rrset);
  559. rrsetCheck(rrset_result, find_result.rrset);
  560. }
  561. EXPECT_EQ((expected_flags & ZoneFinder::RESULT_WILDCARD) != 0,
  562. find_result.isWildcard());
  563. EXPECT_EQ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED)
  564. != 0, find_result.isNSECSigned());
  565. EXPECT_EQ((expected_flags & ZoneFinder::RESULT_NSEC3_SIGNED)
  566. != 0, find_result.isNSEC3Signed());
  567. rrsetsCheck(expected_rrsets.begin(), expected_rrsets.end(),
  568. target.begin(), target.end());
  569. }
  570. };
  571. /**
  572. * \brief Check that findPreviousName throws as it should now.
  573. */
  574. TEST_F(InMemoryZoneFinderTest, findPreviousName) {
  575. EXPECT_THROW(zone_finder_.findPreviousName(Name("www.example.org")),
  576. isc::NotImplemented);
  577. }
  578. /**
  579. * \brief Test InMemoryZoneFinder::InMemoryZoneFinder constructor.
  580. *
  581. * Takes the created zone finder and checks its properties they are the same
  582. * as passed parameters.
  583. */
  584. TEST_F(InMemoryZoneFinderTest, constructor) {
  585. ASSERT_EQ(class_, zone_finder_.getClass());
  586. ASSERT_EQ(origin_, zone_finder_.getOrigin());
  587. }
  588. /**
  589. * \brief Test adding.
  590. *
  591. * We test that it throws at the correct moments and the correct exceptions.
  592. * And we test the return value.
  593. */
  594. TEST_F(InMemoryZoneFinderTest, add) {
  595. // This one does not belong to this zone
  596. EXPECT_THROW(zone_finder_.add(rr_out_), InMemoryZoneFinder::OutOfZone);
  597. // Test null pointer
  598. EXPECT_THROW(zone_finder_.add(ConstRRsetPtr()),
  599. InMemoryZoneFinder::NullRRset);
  600. // Now put all the data we have there. It should throw nothing
  601. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_ns_)));
  602. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_ns_a_)));
  603. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_ns_aaaa_)));
  604. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_a_)));
  605. // Try putting there something twice, it should be rejected
  606. EXPECT_NO_THROW(EXPECT_EQ(EXIST, zone_finder_.add(rr_ns_)));
  607. EXPECT_NO_THROW(EXPECT_EQ(EXIST, zone_finder_.add(rr_ns_a_)));
  608. }
  609. TEST_F(InMemoryZoneFinderTest, addMultipleCNAMEs) {
  610. rr_cname_->addRdata(generic::CNAME("canonical2.example.org."));
  611. EXPECT_THROW(zone_finder_.add(rr_cname_), InMemoryZoneFinder::AddError);
  612. }
  613. TEST_F(InMemoryZoneFinderTest, addCNAMEThenOther) {
  614. EXPECT_EQ(SUCCESS, zone_finder_.add(rr_cname_));
  615. EXPECT_THROW(zone_finder_.add(rr_cname_a_), InMemoryZoneFinder::AddError);
  616. }
  617. TEST_F(InMemoryZoneFinderTest, addOtherThenCNAME) {
  618. EXPECT_EQ(SUCCESS, zone_finder_.add(rr_cname_a_));
  619. EXPECT_THROW(zone_finder_.add(rr_cname_), InMemoryZoneFinder::AddError);
  620. }
  621. TEST_F(InMemoryZoneFinderTest, addCNAMEAndDNSSECRecords) {
  622. // CNAME and RRSIG can coexist
  623. EXPECT_EQ(SUCCESS, zone_finder_.add(rr_cname_));
  624. EXPECT_EQ(SUCCESS, zone_finder_.add(
  625. textToRRset("cname.example.org. 300 IN RRSIG CNAME 5 3 "
  626. "3600 20000101000000 20000201000000 12345 "
  627. "example.org. FAKEFAKEFAKE")));
  628. // Same for NSEC
  629. EXPECT_EQ(SUCCESS, zone_finder_.add(
  630. textToRRset("cname.example.org. 300 IN NSEC "
  631. "dname.example.org. CNAME RRSIG NSEC")));
  632. // Same as above, but adding NSEC first.
  633. EXPECT_EQ(SUCCESS, zone_finder_.add(
  634. textToRRset("cname2.example.org. 300 IN NSEC "
  635. "dname.example.org. CNAME RRSIG NSEC")));
  636. EXPECT_EQ(SUCCESS, zone_finder_.add(
  637. textToRRset("cname2.example.org. 300 IN CNAME c.example.")));
  638. // If there's another type of RRset with NSEC, it should still fail.
  639. EXPECT_EQ(SUCCESS, zone_finder_.add(
  640. textToRRset("cname3.example.org. 300 IN A 192.0.2.1")));
  641. EXPECT_EQ(SUCCESS, zone_finder_.add(
  642. textToRRset("cname3.example.org. 300 IN NSEC "
  643. "dname.example.org. CNAME RRSIG NSEC")));
  644. EXPECT_THROW(zone_finder_.add(textToRRset("cname3.example.org. 300 "
  645. "IN CNAME c.example.")),
  646. InMemoryZoneFinder::AddError);
  647. }
  648. TEST_F(InMemoryZoneFinderTest, findCNAME) {
  649. // install CNAME RR
  650. EXPECT_EQ(SUCCESS, zone_finder_.add(rr_cname_));
  651. // Find A RR of the same. Should match the CNAME
  652. findTest(rr_cname_->getName(), RRType::NS(), ZoneFinder::CNAME, true,
  653. rr_cname_);
  654. // Find the CNAME itself. Should result in normal SUCCESS
  655. findTest(rr_cname_->getName(), RRType::CNAME(), ZoneFinder::SUCCESS, true,
  656. rr_cname_);
  657. }
  658. TEST_F(InMemoryZoneFinderTest, findCNAMEUnderZoneCut) {
  659. // There's nothing special when we find a CNAME under a zone cut
  660. // (with FIND_GLUE_OK). The behavior is different from BIND 9,
  661. // so we test this case explicitly.
  662. EXPECT_EQ(SUCCESS, zone_finder_.add(rr_child_ns_));
  663. ConstRRsetPtr rr_cname_under_cut_ = textToRRset(
  664. "cname.child.example.org. 300 IN CNAME target.child.example.org.");
  665. EXPECT_EQ(SUCCESS, zone_finder_.add(rr_cname_under_cut_));
  666. findTest(Name("cname.child.example.org"), RRType::AAAA(),
  667. ZoneFinder::CNAME, true, rr_cname_under_cut_,
  668. ZoneFinder::RESULT_DEFAULT, NULL, ZoneFinder::FIND_GLUE_OK);
  669. }
  670. // Two DNAMEs at single domain are disallowed by RFC 2672, section 3)
  671. // Having a CNAME there is disallowed too, but it is tested by
  672. // addOtherThenCNAME and addCNAMEThenOther.
  673. TEST_F(InMemoryZoneFinderTest, addMultipleDNAMEs) {
  674. rr_dname_->addRdata(generic::DNAME("target2.example.org."));
  675. EXPECT_THROW(zone_finder_.add(rr_dname_), InMemoryZoneFinder::AddError);
  676. }
  677. /*
  678. * These two tests ensure that we can't have DNAME and NS at the same
  679. * node with the exception of the apex of zone (forbidden by RFC 2672)
  680. */
  681. TEST_F(InMemoryZoneFinderTest, addDNAMEThenNS) {
  682. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_dname_)));
  683. EXPECT_THROW(zone_finder_.add(rr_dname_ns_), InMemoryZoneFinder::AddError);
  684. }
  685. TEST_F(InMemoryZoneFinderTest, addNSThenDNAME) {
  686. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_dname_ns_)));
  687. EXPECT_THROW(zone_finder_.add(rr_dname_), InMemoryZoneFinder::AddError);
  688. }
  689. // It is allowed to have NS and DNAME at apex
  690. TEST_F(InMemoryZoneFinderTest, DNAMEAndNSAtApex) {
  691. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_dname_apex_)));
  692. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_ns_)));
  693. // The NS should be possible to be found, below should be DNAME, not
  694. // delegation
  695. findTest(origin_, RRType::NS(), ZoneFinder::SUCCESS, true, rr_ns_);
  696. findTest(rr_child_ns_->getName(), RRType::A(), ZoneFinder::DNAME, true,
  697. rr_dname_apex_);
  698. }
  699. TEST_F(InMemoryZoneFinderTest, NSAndDNAMEAtApex) {
  700. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_ns_)));
  701. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_dname_apex_)));
  702. }
  703. // TODO: Test (and implement) adding data under DNAME. That is forbidden by
  704. // 2672 as well.
  705. // Search under a DNAME record. It should return the DNAME
  706. TEST_F(InMemoryZoneFinderTest, findBelowDNAME) {
  707. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_dname_)));
  708. findTest(Name("below.dname.example.org"), RRType::A(), ZoneFinder::DNAME,
  709. true, rr_dname_);
  710. }
  711. // Search at the domain with DNAME. It should act as DNAME isn't there, DNAME
  712. // influences only the data below (see RFC 2672, section 3)
  713. TEST_F(InMemoryZoneFinderTest, findAtDNAME) {
  714. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_dname_)));
  715. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_dname_a_)));
  716. const Name dname_name(rr_dname_->getName());
  717. findTest(dname_name, RRType::A(), ZoneFinder::SUCCESS, true, rr_dname_a_);
  718. findTest(dname_name, RRType::DNAME(), ZoneFinder::SUCCESS, true,
  719. rr_dname_);
  720. findTest(dname_name, RRType::TXT(), ZoneFinder::NXRRSET, true);
  721. }
  722. // Try searching something that is both under NS and DNAME, without and with
  723. // GLUE_OK mode (it should stop at the NS and DNAME respectively).
  724. TEST_F(InMemoryZoneFinderTest, DNAMEUnderNS) {
  725. zone_finder_.add(rr_child_ns_);
  726. zone_finder_.add(rr_child_dname_);
  727. Name lowName("below.dname.child.example.org.");
  728. findTest(lowName, RRType::A(), ZoneFinder::DELEGATION, true, rr_child_ns_);
  729. findTest(lowName, RRType::A(), ZoneFinder::DNAME, true, rr_child_dname_,
  730. ZoneFinder::RESULT_DEFAULT, NULL, ZoneFinder::FIND_GLUE_OK);
  731. }
  732. // Test adding child zones and zone cut handling
  733. TEST_F(InMemoryZoneFinderTest, delegationNS) {
  734. // add in-zone data
  735. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_ns_)));
  736. // install a zone cut
  737. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_child_ns_)));
  738. // below the zone cut
  739. findTest(Name("www.child.example.org"), RRType::A(),
  740. ZoneFinder::DELEGATION, true, rr_child_ns_);
  741. // at the zone cut
  742. findTest(Name("child.example.org"), RRType::A(), ZoneFinder::DELEGATION,
  743. true, rr_child_ns_);
  744. findTest(Name("child.example.org"), RRType::NS(), ZoneFinder::DELEGATION,
  745. true, rr_child_ns_);
  746. // finding NS for the apex (origin) node. This must not be confused
  747. // with delegation due to the existence of an NS RR.
  748. findTest(origin_, RRType::NS(), ZoneFinder::SUCCESS, true, rr_ns_);
  749. // unusual case of "nested delegation": the highest cut should be used.
  750. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_grandchild_ns_)));
  751. findTest(Name("www.grand.child.example.org"), RRType::A(),
  752. // note: !rr_grandchild_ns_
  753. ZoneFinder::DELEGATION, true, rr_child_ns_);
  754. }
  755. TEST_F(InMemoryZoneFinderTest, delegationWithDS) {
  756. // Similar setup to the previous one, but with DS RR at the delegation
  757. // point.
  758. EXPECT_EQ(SUCCESS, zone_finder_.add(rr_ns_));
  759. EXPECT_EQ(SUCCESS, zone_finder_.add(rr_child_ns_));
  760. EXPECT_EQ(SUCCESS, zone_finder_.add(rr_child_ds_));
  761. // Normal types of query should result in delegation, but DS query
  762. // should be considered in-zone.
  763. findTest(Name("child.example.org"), RRType::A(), ZoneFinder::DELEGATION,
  764. true, rr_child_ns_);
  765. findTest(Name("child.example.org"), RRType::DS(), ZoneFinder::SUCCESS,
  766. true, rr_child_ds_);
  767. // There's nothing special for DS query at the zone apex. It would
  768. // normally result in NXRRSET.
  769. findTest(Name("example.org"), RRType::DS(), ZoneFinder::NXRRSET,
  770. true, ConstRRsetPtr());
  771. }
  772. TEST_F(InMemoryZoneFinderTest, findAny) {
  773. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_a_)));
  774. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_ns_)));
  775. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_child_glue_)));
  776. vector<ConstRRsetPtr> expected_sets;
  777. // origin
  778. expected_sets.push_back(rr_a_);
  779. expected_sets.push_back(rr_ns_);
  780. findAllTest(origin_, ZoneFinder::SUCCESS, expected_sets);
  781. // out zone name
  782. findAllTest(Name("example.com"), ZoneFinder::NXDOMAIN,
  783. vector<ConstRRsetPtr>());
  784. expected_sets.clear();
  785. expected_sets.push_back(rr_child_glue_);
  786. findAllTest(rr_child_glue_->getName(), ZoneFinder::SUCCESS, expected_sets);
  787. // add zone cut
  788. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_child_ns_)));
  789. // zone cut
  790. findAllTest(rr_child_ns_->getName(), ZoneFinder::DELEGATION,
  791. vector<ConstRRsetPtr>(), ZoneFinder::RESULT_DEFAULT,
  792. NULL, rr_child_ns_);
  793. // glue for this zone cut
  794. findAllTest(rr_child_glue_->getName(),ZoneFinder::DELEGATION,
  795. vector<ConstRRsetPtr>(), ZoneFinder::RESULT_DEFAULT,
  796. NULL, rr_child_ns_);
  797. }
  798. TEST_F(InMemoryZoneFinderTest, glue) {
  799. // install zone data:
  800. // a zone cut
  801. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_child_ns_)));
  802. // glue for this cut
  803. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_child_glue_)));
  804. // a nested zone cut (unusual)
  805. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_grandchild_ns_)));
  806. // glue under the deeper zone cut
  807. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_grandchild_glue_)));
  808. // by default glue is hidden due to the zone cut
  809. findTest(rr_child_glue_->getName(), RRType::A(), ZoneFinder::DELEGATION,
  810. true, rr_child_ns_);
  811. // If we do it in the "glue OK" mode, we should find the exact match.
  812. findTest(rr_child_glue_->getName(), RRType::A(), ZoneFinder::SUCCESS, true,
  813. rr_child_glue_, ZoneFinder::RESULT_DEFAULT, NULL,
  814. ZoneFinder::FIND_GLUE_OK);
  815. // glue OK + NXRRSET case
  816. findTest(rr_child_glue_->getName(), RRType::AAAA(), ZoneFinder::NXRRSET,
  817. true, ConstRRsetPtr(), ZoneFinder::RESULT_DEFAULT, NULL,
  818. ZoneFinder::FIND_GLUE_OK);
  819. // glue OK + NXDOMAIN case
  820. findTest(Name("www.child.example.org"), RRType::A(),
  821. ZoneFinder::DELEGATION, true, rr_child_ns_,
  822. ZoneFinder::RESULT_DEFAULT, NULL, ZoneFinder::FIND_GLUE_OK);
  823. // nested cut case. The glue should be found.
  824. findTest(rr_grandchild_glue_->getName(), RRType::AAAA(),
  825. ZoneFinder::SUCCESS,
  826. true, rr_grandchild_glue_, ZoneFinder::RESULT_DEFAULT, NULL,
  827. ZoneFinder::FIND_GLUE_OK);
  828. // A non-existent name in nested cut. This should result in delegation
  829. // at the highest zone cut.
  830. findTest(Name("www.grand.child.example.org"), RRType::TXT(),
  831. ZoneFinder::DELEGATION, true, rr_child_ns_,
  832. ZoneFinder::RESULT_DEFAULT, NULL, ZoneFinder::FIND_GLUE_OK);
  833. }
  834. /**
  835. * \brief Test searching.
  836. *
  837. * Check it finds or does not find correctly and does not throw exceptions.
  838. * \todo This doesn't do any kind of CNAME and so on. If it isn't
  839. * directly there, it just tells it doesn't exist.
  840. */
  841. void
  842. InMemoryZoneFinderTest::findCheck(ZoneFinder::FindResultFlags expected_flags) {
  843. // Fill some data inside
  844. // Now put all the data we have there. It should throw nothing
  845. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_ns_)));
  846. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_ns_a_)));
  847. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_ns_aaaa_)));
  848. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_a_)));
  849. if ((expected_flags & ZoneFinder::RESULT_NSEC3_SIGNED) != 0) {
  850. EXPECT_EQ(SUCCESS, zone_finder_.add(rr_nsec3_));
  851. }
  852. // These two should be successful
  853. findTest(origin_, RRType::NS(), ZoneFinder::SUCCESS, true, rr_ns_);
  854. findTest(rr_ns_a_->getName(), RRType::A(), ZoneFinder::SUCCESS, true,
  855. rr_ns_a_);
  856. // These domain exist but don't have the provided RRType
  857. findTest(origin_, RRType::AAAA(), ZoneFinder::NXRRSET, true,
  858. ConstRRsetPtr(), expected_flags);
  859. findTest(rr_ns_a_->getName(), RRType::NS(), ZoneFinder::NXRRSET, true,
  860. ConstRRsetPtr(), expected_flags);
  861. // These domains don't exist (and one is out of the zone)
  862. findTest(Name("nothere.example.org"), RRType::A(), ZoneFinder::NXDOMAIN,
  863. true, ConstRRsetPtr(), expected_flags);
  864. findTest(Name("example.net"), RRType::A(), ZoneFinder::NXDOMAIN, true,
  865. ConstRRsetPtr(), expected_flags);
  866. }
  867. TEST_F(InMemoryZoneFinderTest, find) {
  868. findCheck();
  869. }
  870. TEST_F(InMemoryZoneFinderTest, findNSEC3Signed) {
  871. findCheck(ZoneFinder::RESULT_NSEC3_SIGNED);
  872. }
  873. void
  874. InMemoryZoneFinderTest::emptyNodeCheck(
  875. ZoneFinder::FindResultFlags expected_flags)
  876. {
  877. /*
  878. * The backend RBTree for this test should look like as follows:
  879. * example.org
  880. * |
  881. * baz (empty; easy case)
  882. * / | \
  883. * bar | x.foo ('foo' part is empty; a bit trickier)
  884. * bbb
  885. * /
  886. * aaa
  887. */
  888. // Construct the test zone
  889. const char* const names[] = {
  890. "bar.example.org.", "x.foo.example.org.", "aaa.baz.example.org.",
  891. "bbb.baz.example.org.", NULL};
  892. for (int i = 0; names[i] != NULL; ++i) {
  893. ConstRRsetPtr rrset = textToRRset(string(names[i]) +
  894. " 300 IN A 192.0.2.1");
  895. EXPECT_EQ(SUCCESS, zone_finder_.add(rrset));
  896. }
  897. if ((expected_flags & ZoneFinder::RESULT_NSEC3_SIGNED) != 0) {
  898. EXPECT_EQ(SUCCESS, zone_finder_.add(rr_nsec3_));
  899. }
  900. // empty node matching, easy case: the node for 'baz' exists with
  901. // no data.
  902. findTest(Name("baz.example.org"), RRType::A(), ZoneFinder::NXRRSET, true,
  903. ConstRRsetPtr(), expected_flags);
  904. // empty node matching, a trickier case: the node for 'foo' is part of
  905. // "x.foo", which should be considered an empty node.
  906. findTest(Name("foo.example.org"), RRType::A(), ZoneFinder::NXRRSET, true,
  907. ConstRRsetPtr(), expected_flags);
  908. // "org" is contained in "example.org", but it shouldn't be treated as
  909. // NXRRSET because it's out of zone.
  910. // Note: basically we don't expect such a query to be performed (the common
  911. // operation is to identify the best matching zone first then perform
  912. // search it), but we shouldn't be confused even in the unexpected case.
  913. findTest(Name("org"), RRType::A(), ZoneFinder::NXDOMAIN, true,
  914. ConstRRsetPtr(), expected_flags);
  915. }
  916. TEST_F(InMemoryZoneFinderTest, emptyNode) {
  917. emptyNodeCheck();
  918. }
  919. TEST_F(InMemoryZoneFinderTest, emptyNodeNSEC3) {
  920. emptyNodeCheck(ZoneFinder::RESULT_NSEC3_SIGNED);
  921. }
  922. TEST_F(InMemoryZoneFinderTest, load) {
  923. // Put some data inside the zone
  924. EXPECT_NO_THROW(EXPECT_EQ(result::SUCCESS, zone_finder_.add(rr_ns_)));
  925. // Loading with different origin should fail
  926. EXPECT_THROW(zone_finder_.load(TEST_DATA_DIR "/root.zone"),
  927. MasterLoadError);
  928. // See the original data is still there, survived the exception
  929. findTest(origin_, RRType::NS(), ZoneFinder::SUCCESS, true, rr_ns_);
  930. // Create correct zone
  931. InMemoryZoneFinder rootzone(class_, Name("."));
  932. // Try putting something inside
  933. EXPECT_NO_THROW(EXPECT_EQ(result::SUCCESS, rootzone.add(rr_ns_aaaa_)));
  934. // Load the zone. It should overwrite/remove the above RRset
  935. EXPECT_NO_THROW(rootzone.load(TEST_DATA_DIR "/root.zone"));
  936. // Now see there are some rrsets (we don't look inside, though)
  937. findTest(Name("."), RRType::SOA(), ZoneFinder::SUCCESS, false,
  938. ConstRRsetPtr(), ZoneFinder::RESULT_DEFAULT, &rootzone);
  939. findTest(Name("."), RRType::NS(), ZoneFinder::SUCCESS, false,
  940. ConstRRsetPtr(), ZoneFinder::RESULT_DEFAULT, &rootzone);
  941. findTest(Name("a.root-servers.net."), RRType::A(), ZoneFinder::SUCCESS,
  942. false, ConstRRsetPtr(), ZoneFinder::RESULT_DEFAULT, &rootzone);
  943. // But this should no longer be here
  944. findTest(rr_ns_a_->getName(), RRType::AAAA(), ZoneFinder::NXDOMAIN, true,
  945. ConstRRsetPtr(), ZoneFinder::RESULT_DEFAULT, &rootzone);
  946. // Try loading zone that is wrong in a different way
  947. EXPECT_THROW(zone_finder_.load(TEST_DATA_DIR "/duplicate_rrset.zone"),
  948. MasterLoadError);
  949. }
  950. /*
  951. * Test that puts a (simple) wildcard into the zone and checks we can
  952. * correctly find the data.
  953. */
  954. void
  955. InMemoryZoneFinderTest::wildcardCheck(
  956. ZoneFinder::FindResultFlags expected_flags)
  957. {
  958. /*
  959. * example.org.
  960. * |
  961. * [cname]wild (not *.wild, should have wild mark)
  962. * |
  963. * *
  964. */
  965. EXPECT_EQ(SUCCESS, zone_finder_.add(rr_wild_));
  966. EXPECT_EQ(SUCCESS, zone_finder_.add(rr_cnamewild_));
  967. // If the zone is expected to be "signed" with NSEC3, add an NSEC3.
  968. // (the content of the NSEC3 shouldn't matter)
  969. if ((expected_flags & ZoneFinder::RESULT_NSEC3_SIGNED) != 0) {
  970. EXPECT_EQ(SUCCESS, zone_finder_.add(rr_nsec3_));
  971. }
  972. // Search at the parent. The parent will not have the A, but it will
  973. // be in the wildcard (so check the wildcard isn't matched at the parent)
  974. {
  975. SCOPED_TRACE("Search at parent");
  976. findTest(Name("wild.example.org"), RRType::A(), ZoneFinder::NXRRSET,
  977. true, ConstRRsetPtr(), expected_flags);
  978. }
  979. // Search the original name of wildcard
  980. {
  981. SCOPED_TRACE("Search directly at *");
  982. findTest(Name("*.wild.example.org"), RRType::A(), ZoneFinder::SUCCESS,
  983. true, rr_wild_);
  984. }
  985. // Search "created" name.
  986. {
  987. SCOPED_TRACE("Search at created child");
  988. findTest(Name("a.wild.example.org"), RRType::A(), ZoneFinder::SUCCESS,
  989. false, rr_wild_,
  990. ZoneFinder::RESULT_WILDCARD | expected_flags, NULL,
  991. ZoneFinder::FIND_DEFAULT, true);
  992. // Wildcard match, but no data
  993. findTest(Name("a.wild.example.org"), RRType::AAAA(),
  994. ZoneFinder::NXRRSET, true, ConstRRsetPtr(),
  995. ZoneFinder::RESULT_WILDCARD | expected_flags);
  996. }
  997. // Search name that has CNAME.
  998. {
  999. SCOPED_TRACE("Matching CNAME");
  1000. findTest(Name("a.cnamewild.example.org"), RRType::A(),
  1001. ZoneFinder::CNAME, false, rr_cnamewild_,
  1002. ZoneFinder::RESULT_WILDCARD | expected_flags, NULL,
  1003. ZoneFinder::FIND_DEFAULT, true);
  1004. }
  1005. // Search another created name, this time little bit lower
  1006. {
  1007. SCOPED_TRACE("Search at created grand-child");
  1008. findTest(Name("a.b.wild.example.org"), RRType::A(),
  1009. ZoneFinder::SUCCESS, false, rr_wild_,
  1010. ZoneFinder::RESULT_WILDCARD | expected_flags, NULL,
  1011. ZoneFinder::FIND_DEFAULT, true);
  1012. }
  1013. EXPECT_EQ(SUCCESS, zone_finder_.add(rr_under_wild_));
  1014. {
  1015. SCOPED_TRACE("Search under non-wildcard");
  1016. findTest(Name("bar.foo.wild.example.org"), RRType::A(),
  1017. ZoneFinder::NXDOMAIN, true, ConstRRsetPtr(), expected_flags);
  1018. }
  1019. }
  1020. TEST_F(InMemoryZoneFinderTest, wildcard) {
  1021. // Normal case
  1022. wildcardCheck();
  1023. }
  1024. TEST_F(InMemoryZoneFinderTest, wildcardNSEC3) {
  1025. // Similar to the previous one, but the zone signed with NSEC3
  1026. wildcardCheck(ZoneFinder::RESULT_NSEC3_SIGNED);
  1027. }
  1028. /*
  1029. * Test that we don't match a wildcard if we get under delegation.
  1030. * By 4.3.3 of RFC1034:
  1031. * "Wildcard RRs do not apply:
  1032. * - When the query is in another zone. That is, delegation cancels
  1033. * the wildcard defaults."
  1034. */
  1035. TEST_F(InMemoryZoneFinderTest, delegatedWildcard) {
  1036. EXPECT_EQ(SUCCESS, zone_finder_.add(rr_child_wild_));
  1037. EXPECT_EQ(SUCCESS, zone_finder_.add(rr_child_ns_));
  1038. {
  1039. SCOPED_TRACE("Looking under delegation point");
  1040. findTest(Name("a.child.example.org"), RRType::A(),
  1041. ZoneFinder::DELEGATION, true, rr_child_ns_);
  1042. }
  1043. {
  1044. SCOPED_TRACE("Looking under delegation point in GLUE_OK mode");
  1045. findTest(Name("a.child.example.org"), RRType::A(),
  1046. ZoneFinder::DELEGATION, true, rr_child_ns_,
  1047. ZoneFinder::RESULT_DEFAULT, NULL, ZoneFinder::FIND_GLUE_OK);
  1048. }
  1049. }
  1050. // Tests combination of wildcard and ANY.
  1051. void
  1052. InMemoryZoneFinderTest::anyWildcardCheck(
  1053. ZoneFinder::FindResultFlags expected_flags)
  1054. {
  1055. EXPECT_EQ(SUCCESS, zone_finder_.add(rr_wild_));
  1056. if ((expected_flags & ZoneFinder::RESULT_NSEC3_SIGNED) != 0) {
  1057. EXPECT_EQ(SUCCESS, zone_finder_.add(rr_nsec3_));
  1058. }
  1059. vector<ConstRRsetPtr> expected_sets;
  1060. // First try directly the name (normal match)
  1061. {
  1062. SCOPED_TRACE("Asking direcly for *");
  1063. expected_sets.push_back(rr_wild_);
  1064. findAllTest(Name("*.wild.example.org"), ZoneFinder::SUCCESS,
  1065. expected_sets);
  1066. }
  1067. // Then a wildcard match
  1068. {
  1069. SCOPED_TRACE("Asking in the wild way");
  1070. expected_sets.clear();
  1071. RRsetPtr expected(new RRset(Name("a.wild.example.org"),
  1072. rr_wild_->getClass(), rr_wild_->getType(),
  1073. rr_wild_->getTTL()));
  1074. expected->addRdata(rr_wild_->getRdataIterator()->getCurrent());
  1075. expected_sets.push_back(expected);
  1076. findAllTest(Name("a.wild.example.org"), ZoneFinder::SUCCESS,
  1077. expected_sets,
  1078. ZoneFinder::RESULT_WILDCARD | expected_flags);
  1079. }
  1080. }
  1081. TEST_F(InMemoryZoneFinderTest, anyWildcard) {
  1082. anyWildcardCheck();
  1083. }
  1084. TEST_F(InMemoryZoneFinderTest, anyWildcardNSEC3) {
  1085. anyWildcardCheck(ZoneFinder::RESULT_NSEC3_SIGNED);
  1086. }
  1087. // Test there's nothing in the wildcard in the middle if we load
  1088. // wild.*.foo.example.org.
  1089. void
  1090. InMemoryZoneFinderTest::emptyWildcardCheck(
  1091. ZoneFinder::FindResultFlags expected_flags)
  1092. {
  1093. /*
  1094. * example.org.
  1095. * foo
  1096. * *
  1097. * wild
  1098. */
  1099. EXPECT_EQ(SUCCESS, zone_finder_.add(rr_emptywild_));
  1100. if ((expected_flags & ZoneFinder::RESULT_NSEC3_SIGNED) != 0) {
  1101. EXPECT_EQ(SUCCESS, zone_finder_.add(rr_nsec3_));
  1102. }
  1103. {
  1104. SCOPED_TRACE("Asking for the original record under wildcard");
  1105. findTest(Name("wild.*.foo.example.org"), RRType::A(),
  1106. ZoneFinder::SUCCESS, true, rr_emptywild_);
  1107. }
  1108. {
  1109. SCOPED_TRACE("Asking for A record");
  1110. findTest(Name("a.foo.example.org"), RRType::A(), ZoneFinder::NXRRSET,
  1111. true, ConstRRsetPtr(),
  1112. ZoneFinder::RESULT_WILDCARD | expected_flags);
  1113. findTest(Name("*.foo.example.org"), RRType::A(), ZoneFinder::NXRRSET,
  1114. true, ConstRRsetPtr(), expected_flags);
  1115. findTest(Name("foo.example.org"), RRType::A(), ZoneFinder::NXRRSET,
  1116. true, ConstRRsetPtr(), expected_flags);
  1117. }
  1118. {
  1119. SCOPED_TRACE("Asking for ANY record");
  1120. findAllTest(Name("*.foo.example.org"), ZoneFinder::NXRRSET,
  1121. vector<ConstRRsetPtr>(), expected_flags);
  1122. findAllTest(Name("a.foo.example.org"), ZoneFinder::NXRRSET,
  1123. vector<ConstRRsetPtr>(),
  1124. ZoneFinder::RESULT_WILDCARD | expected_flags);
  1125. }
  1126. {
  1127. SCOPED_TRACE("Asking on the non-terminal");
  1128. findTest(Name("wild.bar.foo.example.org"), RRType::A(),
  1129. ZoneFinder::NXRRSET, true, ConstRRsetPtr(),
  1130. ZoneFinder::RESULT_WILDCARD | expected_flags);
  1131. }
  1132. }
  1133. TEST_F(InMemoryZoneFinderTest, emptyWildcard) {
  1134. emptyWildcardCheck();
  1135. }
  1136. TEST_F(InMemoryZoneFinderTest, emptyWildcardNSEC3) {
  1137. emptyWildcardCheck(ZoneFinder::RESULT_NSEC3_SIGNED);
  1138. }
  1139. // Same as emptyWildcard, but with multiple * in the path.
  1140. TEST_F(InMemoryZoneFinderTest, nestedEmptyWildcard) {
  1141. EXPECT_EQ(SUCCESS, zone_finder_.add(rr_nested_emptywild_));
  1142. {
  1143. SCOPED_TRACE("Asking for the original record under wildcards");
  1144. findTest(Name("wild.*.foo.*.bar.example.org"), RRType::A(),
  1145. ZoneFinder::SUCCESS, true, rr_nested_emptywild_);
  1146. }
  1147. {
  1148. SCOPED_TRACE("Matching wildcard against empty nonterminal");
  1149. const char* names[] = {
  1150. "baz.foo.*.bar.example.org",
  1151. "baz.foo.baz.bar.example.org",
  1152. "*.foo.baz.bar.example.org",
  1153. NULL
  1154. };
  1155. for (const char** name = names; *name != NULL; ++ name) {
  1156. SCOPED_TRACE(string("Node ") + *name);
  1157. findTest(Name(*name), RRType::A(), ZoneFinder::NXRRSET, true,
  1158. ConstRRsetPtr(), ZoneFinder::RESULT_WILDCARD);
  1159. }
  1160. }
  1161. // Domains to test
  1162. const char* names[] = {
  1163. "*.foo.*.bar.example.org",
  1164. "foo.*.bar.example.org",
  1165. "*.bar.example.org",
  1166. "bar.example.org",
  1167. NULL
  1168. };
  1169. {
  1170. SCOPED_TRACE("Asking directly for A on parent nodes");
  1171. for (const char** name = names; *name != NULL; ++ name) {
  1172. SCOPED_TRACE(string("Node ") + *name);
  1173. findTest(Name(*name), RRType::A(), ZoneFinder::NXRRSET);
  1174. }
  1175. }
  1176. {
  1177. SCOPED_TRACE("Asking for ANY on parent nodes");
  1178. for (const char** name = names; *name != NULL; ++ name) {
  1179. SCOPED_TRACE(string("Node ") + *name);
  1180. findAllTest(Name(*name), ZoneFinder::NXRRSET,
  1181. vector<ConstRRsetPtr>());
  1182. }
  1183. }
  1184. }
  1185. // We run this part twice from the below test, in two slightly different
  1186. // situations
  1187. void
  1188. InMemoryZoneFinderTest::doCancelWildcardCheck(
  1189. ZoneFinder::FindResultFlags expected_flags)
  1190. {
  1191. // These should be canceled
  1192. {
  1193. SCOPED_TRACE("Canceled under foo.wild.example.org");
  1194. findTest(Name("aaa.foo.wild.example.org"), RRType::A(),
  1195. ZoneFinder::NXDOMAIN, true, ConstRRsetPtr(), expected_flags);
  1196. findTest(Name("zzz.foo.wild.example.org"), RRType::A(),
  1197. ZoneFinder::NXDOMAIN, true, ConstRRsetPtr(), expected_flags);
  1198. }
  1199. // This is existing, non-wildcard domain, shouldn't wildcard at all
  1200. {
  1201. SCOPED_TRACE("Existing domain under foo.wild.example.org");
  1202. findTest(Name("bar.foo.wild.example.org"), RRType::A(),
  1203. ZoneFinder::SUCCESS, true, rr_not_wild_);
  1204. }
  1205. // These should be caught by the wildcard
  1206. {
  1207. SCOPED_TRACE("Neighbor wildcards to foo.wild.example.org");
  1208. const char* names[] = {
  1209. "aaa.bbb.wild.example.org",
  1210. "aaa.zzz.wild.example.org",
  1211. "zzz.wild.example.org",
  1212. NULL
  1213. };
  1214. for (const char** name = names; *name != NULL; ++ name) {
  1215. SCOPED_TRACE(string("Node ") + *name);
  1216. findTest(Name(*name), RRType::A(), ZoneFinder::SUCCESS, false,
  1217. rr_wild_,
  1218. ZoneFinder::RESULT_WILDCARD | expected_flags, NULL,
  1219. ZoneFinder::FIND_DEFAULT, true);
  1220. }
  1221. }
  1222. // This shouldn't be wildcarded, it's an existing domain
  1223. {
  1224. SCOPED_TRACE("The foo.wild.example.org itself");
  1225. findTest(Name("foo.wild.example.org"), RRType::A(),
  1226. ZoneFinder::NXRRSET, true, ConstRRsetPtr(), expected_flags);
  1227. }
  1228. }
  1229. /*
  1230. * This tests that if there's a name between the wildcard domain and the
  1231. * searched one, it will not trigger wildcard, for example, if we have
  1232. * *.wild.example.org and bar.foo.wild.example.org, then we know
  1233. * foo.wild.example.org exists and is not wildcard. Therefore, search for
  1234. * aaa.foo.wild.example.org should return NXDOMAIN.
  1235. *
  1236. * Tests few cases "around" the canceled wildcard match, to see something that
  1237. * shouldn't be canceled isn't.
  1238. */
  1239. TEST_F(InMemoryZoneFinderTest, cancelWildcard) {
  1240. EXPECT_EQ(SUCCESS, zone_finder_.add(rr_wild_));
  1241. EXPECT_EQ(SUCCESS, zone_finder_.add(rr_not_wild_));
  1242. {
  1243. SCOPED_TRACE("Runnig with single entry under foo.wild.example.org");
  1244. doCancelWildcardCheck();
  1245. }
  1246. // Try putting another one under foo.wild....
  1247. // The result should be the same but it will be done in another way in the
  1248. // code, because the foo.wild.example.org will exist in the tree.
  1249. EXPECT_EQ(SUCCESS, zone_finder_.add(rr_not_wild_another_));
  1250. {
  1251. SCOPED_TRACE("Runnig with two entries under foo.wild.example.org");
  1252. doCancelWildcardCheck();
  1253. }
  1254. }
  1255. TEST_F(InMemoryZoneFinderTest, cancelWildcardNSEC3) {
  1256. EXPECT_EQ(SUCCESS, zone_finder_.add(rr_wild_));
  1257. EXPECT_EQ(SUCCESS, zone_finder_.add(rr_not_wild_));
  1258. EXPECT_EQ(SUCCESS, zone_finder_.add(rr_nsec3_));
  1259. {
  1260. SCOPED_TRACE("Runnig with single entry under foo.wild.example.org");
  1261. doCancelWildcardCheck(ZoneFinder::RESULT_NSEC3_SIGNED);
  1262. }
  1263. EXPECT_EQ(SUCCESS, zone_finder_.add(rr_not_wild_another_));
  1264. {
  1265. SCOPED_TRACE("Runnig with two entries under foo.wild.example.org");
  1266. doCancelWildcardCheck(ZoneFinder::RESULT_NSEC3_SIGNED);
  1267. }
  1268. }
  1269. TEST_F(InMemoryZoneFinderTest, loadBadWildcard) {
  1270. // We reject loading the zone if it contains a wildcard name for
  1271. // NS or DNAME.
  1272. EXPECT_THROW(zone_finder_.add(rr_nswild_), InMemoryZoneFinder::AddError);
  1273. EXPECT_THROW(zone_finder_.add(rr_dnamewild_),
  1274. InMemoryZoneFinder::AddError);
  1275. }
  1276. TEST_F(InMemoryZoneFinderTest, swap) {
  1277. // build one zone finder with some data
  1278. InMemoryZoneFinder finder1(class_, origin_);
  1279. EXPECT_EQ(result::SUCCESS, finder1.add(rr_ns_));
  1280. EXPECT_EQ(result::SUCCESS, finder1.add(rr_ns_aaaa_));
  1281. // build another zone finder of a different RR class with some other data
  1282. const Name other_origin("version.bind");
  1283. ASSERT_NE(origin_, other_origin); // make sure these two are different
  1284. InMemoryZoneFinder finder2(RRClass::CH(), other_origin);
  1285. EXPECT_EQ(result::SUCCESS,
  1286. finder2.add(textToRRset("version.bind. 0 CH TXT \"test\"",
  1287. RRClass::CH())));
  1288. finder1.swap(finder2);
  1289. EXPECT_EQ(other_origin, finder1.getOrigin());
  1290. EXPECT_EQ(origin_, finder2.getOrigin());
  1291. EXPECT_EQ(RRClass::CH(), finder1.getClass());
  1292. EXPECT_EQ(RRClass::IN(), finder2.getClass());
  1293. // make sure the zone data is swapped, too
  1294. findTest(origin_, RRType::NS(), ZoneFinder::NXDOMAIN, false,
  1295. ConstRRsetPtr(), ZoneFinder::RESULT_DEFAULT, &finder1);
  1296. findTest(other_origin, RRType::TXT(), ZoneFinder::SUCCESS, false,
  1297. ConstRRsetPtr(), ZoneFinder::RESULT_DEFAULT, &finder1);
  1298. findTest(origin_, RRType::NS(), ZoneFinder::SUCCESS, false,
  1299. ConstRRsetPtr(), ZoneFinder::RESULT_DEFAULT, &finder2);
  1300. findTest(other_origin, RRType::TXT(), ZoneFinder::NXDOMAIN, false,
  1301. ConstRRsetPtr(), ZoneFinder::RESULT_DEFAULT, &finder2);
  1302. }
  1303. TEST_F(InMemoryZoneFinderTest, getFileName) {
  1304. // for an empty zone the file name should also be empty.
  1305. EXPECT_TRUE(zone_finder_.getFileName().empty());
  1306. // if loading a zone fails the file name shouldn't be set.
  1307. EXPECT_THROW(zone_finder_.load(TEST_DATA_DIR "/root.zone"),
  1308. MasterLoadError);
  1309. EXPECT_TRUE(zone_finder_.getFileName().empty());
  1310. // after a successful load, the specified file name should be set
  1311. InMemoryZoneFinder rootzone(class_, Name("."));
  1312. EXPECT_NO_THROW(rootzone.load(TEST_DATA_DIR "/root.zone"));
  1313. EXPECT_EQ(TEST_DATA_DIR "/root.zone", rootzone.getFileName());
  1314. // overriding load, which will fail
  1315. EXPECT_THROW(rootzone.load(TEST_DATA_DIR "/duplicate_rrset.zone"),
  1316. MasterLoadError);
  1317. // the file name should be intact.
  1318. EXPECT_EQ(TEST_DATA_DIR "/root.zone", rootzone.getFileName());
  1319. // After swap, file names should also be swapped.
  1320. zone_finder_.swap(rootzone);
  1321. EXPECT_EQ(TEST_DATA_DIR "/root.zone", zone_finder_.getFileName());
  1322. EXPECT_TRUE(rootzone.getFileName().empty());
  1323. }
  1324. TEST_F(InMemoryZoneFinderTest, addRRsig) {
  1325. // A simple valid case: adding an RRset to be signed followed by an RRSIG
  1326. // that covers the first RRset
  1327. zone_finder_.add(rr_a_);
  1328. zone_finder_.add(textToRRset(rrsig_a_txt));
  1329. ZoneFinder::FindResult result = zone_finder_.find(origin_, RRType::A(),
  1330. ZoneFinder::FIND_DNSSEC);
  1331. EXPECT_EQ(ZoneFinder::SUCCESS, result.code);
  1332. ASSERT_TRUE(result.rrset);
  1333. ASSERT_TRUE(result.rrset->getRRsig());
  1334. actual_rrsets_.push_back(result.rrset->getRRsig());
  1335. rrsetsCheck(rrsig_a_txt, actual_rrsets_.begin(), actual_rrsets_.end());
  1336. // Confirm a separate RRISG for a different type can be added
  1337. actual_rrsets_.clear();
  1338. zone_finder_.add(rr_ns_);
  1339. zone_finder_.add(textToRRset(rrsig_ns_txt));
  1340. ZoneFinder::FindResult result2 =
  1341. zone_finder_.find(origin_, RRType::NS(), ZoneFinder::FIND_DNSSEC);
  1342. EXPECT_EQ(ZoneFinder::SUCCESS, result2.code);
  1343. ASSERT_TRUE(result2.rrset);
  1344. ASSERT_TRUE(result2.rrset->getRRsig());
  1345. actual_rrsets_.push_back(result2.rrset->getRRsig());
  1346. rrsetsCheck(rrsig_ns_txt, actual_rrsets_.begin(), actual_rrsets_.end());
  1347. // Check a case with multiple RRSIGs
  1348. actual_rrsets_.clear();
  1349. zone_finder_.add(rr_ns_aaaa_);
  1350. zone_finder_.add(textToRRset(rrsig_aaaa_txt));
  1351. ZoneFinder::FindResult result3 =
  1352. zone_finder_.find(Name("ns.example.org"), RRType::AAAA(),
  1353. ZoneFinder::FIND_DNSSEC);
  1354. EXPECT_EQ(ZoneFinder::SUCCESS, result3.code);
  1355. ASSERT_TRUE(result3.rrset);
  1356. ASSERT_TRUE(result3.rrset->getRRsig());
  1357. actual_rrsets_.push_back(result3.rrset->getRRsig());
  1358. rrsetsCheck(rrsig_aaaa_txt, actual_rrsets_.begin(), actual_rrsets_.end());
  1359. }
  1360. TEST_F(InMemoryZoneFinderTest, addRRsigWithoutCovered) {
  1361. // The current implementation rejects attempts of adding RRSIG without
  1362. // covered RRsets already in the zone.
  1363. // Name doesn't exist
  1364. EXPECT_THROW(zone_finder_.add(
  1365. textToRRset("notexist.example.org. 300 IN RRSIG A 5 3 "
  1366. "3600 20000101000000 20000201000000 12345 "
  1367. "example.org. FAKEFAKEFAKE\n")),
  1368. InMemoryZoneFinder::AddError);
  1369. // Name exists, but is empty.
  1370. zone_finder_.add(rr_emptywild_);
  1371. EXPECT_THROW(zone_finder_.add(
  1372. textToRRset("foo.example.org. 300 IN RRSIG A 5 3 "
  1373. "3600 20000101000000 20000201000000 12345 "
  1374. "example.org. FAKEFAKEFAKE\n")),
  1375. InMemoryZoneFinder::AddError);
  1376. // Add RRSIG RRset without covered RR
  1377. zone_finder_.add(rr_a_);
  1378. EXPECT_THROW(zone_finder_.add(textToRRset(rrsig_ns_txt)),
  1379. InMemoryZoneFinder::AddError);
  1380. }
  1381. TEST_F(InMemoryZoneFinderTest, addbadRRsig) {
  1382. // Tests with other types of bogus input
  1383. // Empty RRSIG RRset.
  1384. EXPECT_THROW(zone_finder_.add(RRsetPtr(new RRset(origin_, class_,
  1385. RRType::RRSIG(),
  1386. RRTTL(300)))),
  1387. InMemoryZoneFinder::AddError);
  1388. // RRSIG with mixed covered types
  1389. zone_finder_.add(rr_a_); // make sure the covered name exists
  1390. // textToRRset() doesn't work as intended for this pathological case,
  1391. // so we need to construct the RRset by hand.
  1392. RRsetPtr rrset(new RRset(origin_, class_, RRType::RRSIG(), RRTTL(300)));
  1393. rrset->addRdata(generic::RRSIG("A 5 3 3600 20000101000000 20000201000000 "
  1394. "12345 example.org. FAKEFAKEFAKE"));
  1395. rrset->addRdata(generic::RRSIG("NS 5 3 3600 20000101000000 20000201000000 "
  1396. "54321 example.org. FAKEFAKEFAKEFAKE"));
  1397. EXPECT_THROW(zone_finder_.add(rrset), InMemoryZoneFinder::AddError);
  1398. // An attempt of overriding an existing RRSIG. The current implementation
  1399. // prohibits that.
  1400. zone_finder_.add(textToRRset(rrsig_a_txt));
  1401. EXPECT_THROW(zone_finder_.add(textToRRset(rrsig_a_txt)),
  1402. InMemoryZoneFinder::AddError);
  1403. }
  1404. //
  1405. // (Faked) NSEC3 hash data. Arbitrarily borrowed from RFC515 examples.
  1406. //
  1407. // Commonly used NSEC3 suffix. It's incorrect to use it for all NSEC3s, but
  1408. // doesn't matter for the purpose of our tests.
  1409. const char* const nsec3_common = " 300 IN NSEC3 1 1 12 aabbccdd "
  1410. "2T7B4G4VSA5SMI47K61MV5BV1A22BOJR A RRSIG";
  1411. // Likewise, common RRSIG suffix for NSEC3s.
  1412. const char* const nsec3_rrsig_common = " 300 IN RRSIG NSEC3 5 3 3600 "
  1413. "20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE";
  1414. void
  1415. findNSEC3Check(bool expected_matched, uint8_t expected_labels,
  1416. const string& expected_closest,
  1417. const string& expected_next,
  1418. const ZoneFinder::FindNSEC3Result& result,
  1419. bool expected_sig = false)
  1420. {
  1421. EXPECT_EQ(expected_matched, result.matched);
  1422. // Convert to int so the error messages would be more readable:
  1423. EXPECT_EQ(static_cast<int>(expected_labels),
  1424. static_cast<int>(result.closest_labels));
  1425. vector<ConstRRsetPtr> actual_rrsets;
  1426. ASSERT_TRUE(result.closest_proof);
  1427. actual_rrsets.push_back(result.closest_proof);
  1428. if (expected_sig) {
  1429. actual_rrsets.push_back(result.closest_proof->getRRsig());
  1430. }
  1431. rrsetsCheck(expected_closest, actual_rrsets.begin(),
  1432. actual_rrsets.end());
  1433. actual_rrsets.clear();
  1434. if (expected_next.empty()) {
  1435. EXPECT_FALSE(result.next_proof);
  1436. } else {
  1437. ASSERT_TRUE(result.next_proof);
  1438. actual_rrsets.push_back(result.next_proof);
  1439. if (expected_sig) {
  1440. actual_rrsets.push_back(result.next_proof->getRRsig());
  1441. }
  1442. rrsetsCheck(expected_next, actual_rrsets.begin(),
  1443. actual_rrsets.end());
  1444. }
  1445. }
  1446. TEST_F(InMemoryZoneFinderTest, addNSEC3) {
  1447. // Set up the faked hash calculator.
  1448. setNSEC3HashCreator(&nsec3_hash_creator_);
  1449. const string nsec3_text = string(apex_hash) + ".example.org." +
  1450. string(nsec3_common);
  1451. // This name shouldn't be found in the normal domain tree.
  1452. EXPECT_EQ(result::SUCCESS, zone_finder_.add(textToRRset(nsec3_text)));
  1453. EXPECT_EQ(ZoneFinder::NXDOMAIN,
  1454. zone_finder_.find(Name(string(apex_hash) + ".example.org"),
  1455. RRType::NSEC3()).code);
  1456. // Dedicated NSEC3 find should be able to find it.
  1457. findNSEC3Check(true, origin_.getLabelCount(), nsec3_text, "",
  1458. zone_finder_.findNSEC3(Name("example.org"), false));
  1459. // This implementation rejects duplicate/update add of the same hash name
  1460. EXPECT_EQ(result::EXIST,
  1461. zone_finder_.add(textToRRset(
  1462. string(apex_hash) + ".example.org." +
  1463. string(nsec3_common) + " AAAA")));
  1464. // The original NSEC3 should be intact
  1465. findNSEC3Check(true, origin_.getLabelCount(), nsec3_text, "",
  1466. zone_finder_.findNSEC3(Name("example.org"), false));
  1467. // NSEC3-like name but of ordinary RR type should go to normal tree.
  1468. const string nonsec3_text = string(apex_hash) + ".example.org. " +
  1469. "300 IN A 192.0.2.1";
  1470. EXPECT_EQ(result::SUCCESS, zone_finder_.add(textToRRset(nonsec3_text)));
  1471. EXPECT_EQ(ZoneFinder::SUCCESS,
  1472. zone_finder_.find(Name(string(apex_hash) + ".example.org"),
  1473. RRType::A()).code);
  1474. }
  1475. TEST_F(InMemoryZoneFinderTest, addNSEC3Lower) {
  1476. // Set up the faked hash calculator.
  1477. setNSEC3HashCreator(&nsec3_hash_creator_);
  1478. // Similar to the previous case, but NSEC3 owner name is lower-cased.
  1479. const string nsec3_text = string(apex_hash_lower) + ".example.org." +
  1480. string(nsec3_common);
  1481. EXPECT_EQ(result::SUCCESS, zone_finder_.add(textToRRset(nsec3_text)));
  1482. findNSEC3Check(true, origin_.getLabelCount(), nsec3_text, "",
  1483. zone_finder_.findNSEC3(Name("example.org"), false));
  1484. }
  1485. TEST_F(InMemoryZoneFinderTest, addNSEC3Ordering) {
  1486. // Set up the faked hash calculator.
  1487. setNSEC3HashCreator(&nsec3_hash_creator_);
  1488. // Check that the internal storage ensures comparison based on the NSEC3
  1489. // semantics, regardless of the add order or the letter-case of hash.
  1490. // Adding "0P..", "2v..", then "2T..".
  1491. const string smallest = string(apex_hash) + ".example.org." +
  1492. string(nsec3_common);
  1493. const string middle = string(ns1_hash) + ".example.org." +
  1494. string(nsec3_common);
  1495. const string largest = string(xyw_hash) + ".example.org." +
  1496. string(nsec3_common);
  1497. zone_finder_.add(textToRRset(smallest));
  1498. zone_finder_.add(textToRRset(largest));
  1499. zone_finder_.add(textToRRset(middle));
  1500. // Then look for NSEC3 that covers a name whose hash is "2S.."
  1501. // The covering NSEC3 should be "0P.."
  1502. findNSEC3Check(false, 4, smallest, "",
  1503. zone_finder_.findNSEC3(Name("www.example.org"), false));
  1504. // Look for NSEC3 that covers names whose hash are "Q0.." and "0A.."
  1505. // The covering NSEC3 should be "2v.." in both cases
  1506. findNSEC3Check(false, 4, largest, "",
  1507. zone_finder_.findNSEC3(Name("xxx.example.org"), false));
  1508. findNSEC3Check(false, 4, largest, "",
  1509. zone_finder_.findNSEC3(Name("yyy.example.org"), false));
  1510. }
  1511. TEST_F(InMemoryZoneFinderTest, badNSEC3Name) {
  1512. // Our implementation refuses to load NSEC3 at a wildcard name
  1513. EXPECT_THROW(zone_finder_.add(textToRRset("*.example.org." +
  1514. string(nsec3_common))),
  1515. InMemoryZoneFinder::AddError);
  1516. // Likewise, if the owner name of NSEC3 has too many labels, it's refused.
  1517. EXPECT_THROW(zone_finder_.add(textToRRset("a." + string(apex_hash) +
  1518. ".example.org." +
  1519. string(nsec3_common))),
  1520. InMemoryZoneFinder::AddError);
  1521. }
  1522. TEST_F(InMemoryZoneFinderTest, addMultiNSEC3) {
  1523. // In this current implementation multiple NSEC3 RDATA isn't supported.
  1524. RRsetPtr nsec3(new RRset(Name(string(apex_hash) + ".example.org"),
  1525. RRClass::IN(), RRType::NSEC3(), RRTTL(300)));
  1526. nsec3->addRdata(
  1527. generic::NSEC3("1 0 12 aabbccdd 2T7B4G4VSA5SMI47K61MV5BV1A22BOJR A"));
  1528. nsec3->addRdata(
  1529. generic::NSEC3("1 1 1 ddccbbaa 2T7B4G4VSA5SMI47K61MV5BV1A22BOJR A"));
  1530. EXPECT_THROW(zone_finder_.add(nsec3), InMemoryZoneFinder::AddError);
  1531. }
  1532. TEST_F(InMemoryZoneFinderTest, addNSEC3WithRRSIG) {
  1533. // Set up the faked hash calculator.
  1534. setNSEC3HashCreator(&nsec3_hash_creator_);
  1535. // Adding NSEC3 and its RRSIG
  1536. const string nsec3_text = string(apex_hash) + ".example.org." +
  1537. string(nsec3_common);
  1538. EXPECT_EQ(result::SUCCESS, zone_finder_.add(textToRRset(nsec3_text)));
  1539. const string nsec3_rrsig_text = string(apex_hash) + ".example.org." +
  1540. string(nsec3_rrsig_common);
  1541. EXPECT_EQ(result::SUCCESS, zone_finder_.add(textToRRset(nsec3_rrsig_text)));
  1542. // Then look for it. The NSEC3 should have the RRSIG that was just added.
  1543. findNSEC3Check(true, origin_.getLabelCount(),
  1544. nsec3_text + "\n" + nsec3_rrsig_text, "",
  1545. zone_finder_.findNSEC3(Name("example.org"), false), true);
  1546. // Duplicate add of RRSIG for the same NSEC3 is prohibited.
  1547. EXPECT_THROW(zone_finder_.add(textToRRset(nsec3_rrsig_text)),
  1548. InMemoryZoneFinder::AddError);
  1549. // Same check using the lower-cased name. This also confirms matching
  1550. // is case-insensitive.
  1551. EXPECT_THROW(zone_finder_.add(textToRRset(string(apex_hash_lower) +
  1552. ".example.org."
  1553. + string(nsec3_rrsig_common))),
  1554. InMemoryZoneFinder::AddError);
  1555. }
  1556. TEST_F(InMemoryZoneFinderTest, badRRsigForNSEC3) {
  1557. // adding RRSIG for NSEC3 even before adding any NSEC3 (internally,
  1558. // a space for NSEC3 namespace isn't yet allocated)
  1559. EXPECT_THROW(zone_finder_.add(textToRRset(string(apex_hash) +
  1560. ".example.org." +
  1561. string(nsec3_rrsig_common))),
  1562. InMemoryZoneFinder::AddError);
  1563. // Add an NSEC3
  1564. EXPECT_EQ(result::SUCCESS, zone_finder_.add(
  1565. textToRRset(string(apex_hash) + ".example.org." +
  1566. string(nsec3_common))));
  1567. // Then add an NSEC3 for a non existent NSEC3. It should fail in the
  1568. // current implementation.
  1569. EXPECT_THROW(zone_finder_.add(textToRRset(string(ns1_hash) +
  1570. ".example.org." +
  1571. string(nsec3_rrsig_common))),
  1572. InMemoryZoneFinder::AddError);
  1573. }
  1574. TEST_F(InMemoryZoneFinderTest, paramConsistencyWithNSEC3PARAM) {
  1575. // First, add an NSEC3PARAM RR
  1576. EXPECT_EQ(result::SUCCESS,
  1577. zone_finder_.add(textToRRset("example.org. 300 IN NSEC3PARAM "
  1578. "1 0 12 aabbccdd")));
  1579. // Adding an NSEC3 that has matching parameters is okay.
  1580. EXPECT_EQ(result::SUCCESS, zone_finder_.add(
  1581. textToRRset(string(apex_hash) + ".example.org." +
  1582. string(nsec3_common))));
  1583. // NSEC3 with inconsistent parameter will be rejected
  1584. EXPECT_THROW(zone_finder_.add(
  1585. textToRRset("a.example.org. 300 IN NSEC3 1 0 1 aabbccdd "
  1586. "2T7B4G4VSA5SMI47K61MV5BV1A22BOJR A RRSIG")),
  1587. InMemoryZoneFinder::AddError);
  1588. }
  1589. TEST_F(InMemoryZoneFinderTest, paramConsistencyWithNSEC3) {
  1590. // Add an NSEC3 without adding NSEC3PARAM
  1591. EXPECT_EQ(result::SUCCESS, zone_finder_.add(
  1592. textToRRset(string(apex_hash) + ".example.org." +
  1593. string(nsec3_common))));
  1594. // Adding an NSEC3 with inconsistent parameter will be rejected at this pt.
  1595. EXPECT_THROW(zone_finder_.add(
  1596. textToRRset("a.example.org. 300 IN NSEC3 1 0 1 aabbccdd "
  1597. "2T7B4G4VSA5SMI47K61MV5BV1A22BOJR A RRSIG")),
  1598. InMemoryZoneFinder::AddError);
  1599. // Likewise, NSEC3PARAM with inconsistent parameter will be rejected.
  1600. EXPECT_THROW(zone_finder_.add(textToRRset("example.org. 300 IN NSEC3PARAM "
  1601. "1 0 1 aabbccdd")),
  1602. InMemoryZoneFinder::AddError);
  1603. }
  1604. TEST_F(InMemoryZoneFinderTest, multiNSEC3PARAM) {
  1605. // In this current implementation multiple NSEC3PARAM isn't supported.
  1606. RRsetPtr nsec3param(new RRset(Name("example.org"), RRClass::IN(),
  1607. RRType::NSEC3PARAM(), RRTTL(300)));
  1608. nsec3param->addRdata(generic::NSEC3PARAM("1 0 12 aabbccdd"));
  1609. nsec3param->addRdata(generic::NSEC3PARAM("1 1 1 ddccbbaa"));
  1610. EXPECT_THROW(zone_finder_.add(nsec3param), InMemoryZoneFinder::AddError);
  1611. }
  1612. TEST_F(InMemoryZoneFinderTest, nonOriginNSEC3PARAM) {
  1613. // This is a normal NSEC3PARAM at the zone origin
  1614. EXPECT_EQ(result::SUCCESS,
  1615. zone_finder_.add(textToRRset("example.org. 300 IN NSEC3PARAM "
  1616. "1 0 12 aabbccdd")));
  1617. // Add another (with different param) at a non origin node. This is
  1618. // awkward, but the implementation accepts it as an ordinary RR.
  1619. EXPECT_EQ(result::SUCCESS,
  1620. zone_finder_.add(textToRRset("a.example.org. 300 IN NSEC3PARAM "
  1621. "1 1 1 aabbccdd")));
  1622. }
  1623. TEST_F(InMemoryZoneFinderTest, loadNSEC3Zone) {
  1624. // Check if it can load validly NSEC3-signed zone. At this moment
  1625. // it's sufficient to see it doesn't crash
  1626. zone_finder_.load(TEST_DATA_DIR "/example.org.nsec3-signed");
  1627. // Reload the zone with a version that doesn't have NSEC3PARAM.
  1628. // This is an abnormal case, but the implementation accepts it.
  1629. zone_finder_.load(TEST_DATA_DIR "/example.org.nsec3-signed-noparam");
  1630. }
  1631. TEST_F(InMemoryZoneFinderTest, findNSEC3) {
  1632. // Set up the faked hash calculator.
  1633. setNSEC3HashCreator(&nsec3_hash_creator_);
  1634. // Add a few NSEC3 records:
  1635. // apex (example.org.): hash=0P..
  1636. // ns1.example.org: hash=2T..
  1637. // w.example.org: hash=01..
  1638. // zzz.example.org: hash=R5..
  1639. const string apex_nsec3_text = string(apex_hash) + ".example.org." +
  1640. string(nsec3_common);
  1641. EXPECT_EQ(result::SUCCESS, zone_finder_.add(textToRRset(apex_nsec3_text)));
  1642. const string ns1_nsec3_text = string(ns1_hash) + ".example.org." +
  1643. string(nsec3_common);
  1644. EXPECT_EQ(result::SUCCESS, zone_finder_.add(textToRRset(ns1_nsec3_text)));
  1645. const string w_nsec3_text = string(w_hash) + ".example.org." +
  1646. string(nsec3_common);
  1647. EXPECT_EQ(result::SUCCESS, zone_finder_.add(textToRRset(w_nsec3_text)));
  1648. const string zzz_nsec3_text = string(zzz_hash) + ".example.org." +
  1649. string(nsec3_common);
  1650. EXPECT_EQ(result::SUCCESS, zone_finder_.add(textToRRset(zzz_nsec3_text)));
  1651. // Parameter validation: the query name must be in or below the zone
  1652. EXPECT_THROW(zone_finder_.findNSEC3(Name("example.com"), false),
  1653. isc::InvalidParameter);
  1654. EXPECT_THROW(zone_finder_.findNSEC3(Name("org"), true),
  1655. isc::InvalidParameter);
  1656. // Apex name. It should have a matching NSEC3.
  1657. {
  1658. SCOPED_TRACE("apex, non recursive mode");
  1659. findNSEC3Check(true, origin_.getLabelCount(), apex_nsec3_text, "",
  1660. zone_finder_.findNSEC3(origin_, false));
  1661. }
  1662. // Recursive mode doesn't change the result in this case.
  1663. {
  1664. SCOPED_TRACE("apex, recursive mode");
  1665. findNSEC3Check(true, origin_.getLabelCount(), apex_nsec3_text, "",
  1666. zone_finder_.findNSEC3(origin_, true));
  1667. }
  1668. // Non existent name. Disabling recursion, a covering NSEC3 should be
  1669. // returned.
  1670. const Name www_name("www.example.org");
  1671. {
  1672. SCOPED_TRACE("non existent name, non recursive mode");
  1673. findNSEC3Check(false, www_name.getLabelCount(), apex_nsec3_text, "",
  1674. zone_finder_.findNSEC3(www_name, false));
  1675. }
  1676. // Non existent name. The closest provable encloser is the apex,
  1677. // and next closer is the query name itself (which NSEC3 for ns1
  1678. // covers)
  1679. // H(ns1) = 2T... < H(xxx) = Q0... < H(zzz) = R5...
  1680. {
  1681. SCOPED_TRACE("non existent name, recursive mode");
  1682. findNSEC3Check(true, origin_.getLabelCount(), apex_nsec3_text,
  1683. ns1_nsec3_text,
  1684. zone_finder_.findNSEC3(Name("xxx.example.org"), true));
  1685. }
  1686. // Similar to the previous case, but next closer name is different
  1687. // from the query name. The closet encloser is w.example.org, and
  1688. // next closer is y.w.example.org.
  1689. // H(ns1) = 2T.. < H(y.w) = K8.. < H(zzz) = R5
  1690. {
  1691. SCOPED_TRACE("non existent name, non qname next closer");
  1692. findNSEC3Check(true, Name("w.example.org").getLabelCount(),
  1693. w_nsec3_text, ns1_nsec3_text,
  1694. zone_finder_.findNSEC3(Name("x.y.w.example.org"),
  1695. true));
  1696. }
  1697. // In the rest of test we check hash comparison for wrap around cases.
  1698. {
  1699. SCOPED_TRACE("very small hash");
  1700. const Name smallest_name("smallest.example.org");
  1701. findNSEC3Check(false, smallest_name.getLabelCount(),
  1702. zzz_nsec3_text, "",
  1703. zone_finder_.findNSEC3(smallest_name, false));
  1704. }
  1705. {
  1706. SCOPED_TRACE("very large hash");
  1707. const Name largest_name("largest.example.org");
  1708. findNSEC3Check(false, largest_name.getLabelCount(),
  1709. zzz_nsec3_text, "",
  1710. zone_finder_.findNSEC3(largest_name, false));
  1711. }
  1712. }
  1713. TEST_F(InMemoryZoneFinderTest, findNSEC3ForBadZone) {
  1714. // Set up the faked hash calculator.
  1715. setNSEC3HashCreator(&nsec3_hash_creator_);
  1716. // If the zone has nothing about NSEC3 (neither NSEC3 or NSEC3PARAM),
  1717. // findNSEC3() should be rejected.
  1718. EXPECT_THROW(zone_finder_.findNSEC3(Name("www.example.org"), true),
  1719. DataSourceError);
  1720. // Only having NSEC3PARAM isn't enough
  1721. EXPECT_EQ(result::SUCCESS,
  1722. zone_finder_.add(textToRRset("example.org. 300 IN NSEC3PARAM "
  1723. "1 0 12 aabbccdd")));
  1724. EXPECT_THROW(zone_finder_.findNSEC3(Name("www.example.org"), true),
  1725. DataSourceError);
  1726. // Unless NSEC3 for apex is added the result in the recursive mode
  1727. // is guaranteed.
  1728. const string ns1_nsec3_text = string(ns1_hash) + ".example.org." +
  1729. string(nsec3_common);
  1730. EXPECT_EQ(result::SUCCESS, zone_finder_.add(textToRRset(ns1_nsec3_text)));
  1731. EXPECT_THROW(zone_finder_.findNSEC3(Name("www.example.org"), true),
  1732. DataSourceError);
  1733. }
  1734. TEST_F(InMemoryZoneFinderTest, loadAndFindNSEC3) {
  1735. // Using more realistic example, borrowed from RFC5155, with compliant
  1736. // hash calculator. We only confirm the data source can load it
  1737. // successfully and find correct NSEC3 RRs for some selected cases
  1738. // (detailed tests have been done above).
  1739. InMemoryZoneFinder finder(class_, Name("example"));
  1740. finder.load(TEST_DATA_DIR "/rfc5155-example.zone.signed");
  1741. // See RFC5155 B.1
  1742. ZoneFinder::FindNSEC3Result result1 =
  1743. finder.findNSEC3(Name("c.x.w.example"), true);
  1744. ASSERT_TRUE(result1.closest_proof);
  1745. // We compare closest_labels as int so the error report will be more
  1746. // readable in case it fails.
  1747. EXPECT_EQ(4, static_cast<int>(result1.closest_labels));
  1748. EXPECT_EQ(Name("b4um86eghhds6nea196smvmlo4ors995.example"),
  1749. result1.closest_proof->getName());
  1750. ASSERT_TRUE(result1.next_proof);
  1751. EXPECT_EQ(Name("0p9mhaveqvm6t7vbl5lop2u3t2rp3tom.example"),
  1752. result1.next_proof->getName());
  1753. // See RFC5155 B.2.
  1754. ZoneFinder::FindNSEC3Result result2 =
  1755. finder.findNSEC3(Name("ns1.example"), true);
  1756. ASSERT_TRUE(result2.closest_proof);
  1757. EXPECT_EQ(3, static_cast<int>(result2.closest_labels));
  1758. EXPECT_EQ(Name("2t7b4g4vsa5smi47k61mv5bv1a22bojr.example"),
  1759. result2.closest_proof->getName());
  1760. ASSERT_FALSE(result2.next_proof);
  1761. // See RFC5155 B.5.
  1762. ZoneFinder::FindNSEC3Result result3 =
  1763. finder.findNSEC3(Name("a.z.w.example"), true);
  1764. ASSERT_TRUE(result3.closest_proof);
  1765. EXPECT_EQ(3, static_cast<int>(result3.closest_labels));
  1766. EXPECT_EQ(Name("k8udemvp1j2f7eg6jebps17vp3n8i58h.example"),
  1767. result3.closest_proof->getName());
  1768. ASSERT_TRUE(result3.next_proof);
  1769. EXPECT_EQ(Name("q04jkcevqvmu85r014c7dkba38o0ji5r.example"),
  1770. result3.next_proof->getName());
  1771. }
  1772. }