memory_datasrc_unittest.cc 88 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101
  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. const ConstRRsetPtr answer_sig = answer ? answer->getRRsig() : answer;
  498. // The whole block is inside, because we need to check the result and
  499. // we can't assign to FindResult
  500. EXPECT_NO_THROW({
  501. ZoneFinder::FindResult find_result(zone_finder->find(
  502. name, rrtype, options));
  503. // Check it returns correct answers
  504. EXPECT_EQ(result, find_result.code);
  505. EXPECT_EQ((expected_flags & ZoneFinder::RESULT_WILDCARD) != 0,
  506. find_result.isWildcard());
  507. EXPECT_EQ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED)
  508. != 0, find_result.isNSECSigned());
  509. EXPECT_EQ((expected_flags & ZoneFinder::RESULT_NSEC3_SIGNED)
  510. != 0, find_result.isNSEC3Signed());
  511. if (check_answer) {
  512. if (!answer) {
  513. ASSERT_FALSE(find_result.rrset);
  514. } else {
  515. ASSERT_TRUE(find_result.rrset);
  516. rrsetCheck(answer, find_result.rrset);
  517. if (answer_sig) {
  518. ASSERT_TRUE(find_result.rrset->getRRsig());
  519. rrsetCheck(answer_sig,
  520. find_result.rrset->getRRsig());
  521. }
  522. }
  523. } else if (check_wild_answer) {
  524. ASSERT_NE(ConstRRsetPtr(), answer) <<
  525. "Wrong test, don't check for wild names if you expect "
  526. "empty answer";
  527. ASSERT_NE(ConstRRsetPtr(), find_result.rrset) <<
  528. "No answer found";
  529. // Build the expected answer using the given name and
  530. // other parameter of the base wildcard RRset.
  531. RRsetPtr wildanswer(new RRset(name, answer->getClass(),
  532. answer->getType(),
  533. answer->getTTL()));
  534. RdataIteratorPtr expectedIt(answer->getRdataIterator());
  535. for (; !expectedIt->isLast(); expectedIt->next()) {
  536. wildanswer->addRdata(expectedIt->getCurrent());
  537. }
  538. rrsetCheck(wildanswer, find_result.rrset);
  539. // Same for the RRSIG, if any.
  540. if (answer_sig) {
  541. ASSERT_TRUE(find_result.rrset->getRRsig());
  542. RRsetPtr wildsig(new RRset(name,
  543. answer_sig->getClass(),
  544. RRType::RRSIG(),
  545. answer_sig->getTTL()));
  546. RdataIteratorPtr expectedIt(
  547. answer_sig->getRdataIterator());
  548. for (; !expectedIt->isLast(); expectedIt->next()) {
  549. wildsig->addRdata(expectedIt->getCurrent());
  550. }
  551. rrsetCheck(wildsig, find_result.rrset->getRRsig());
  552. }
  553. }
  554. });
  555. }
  556. /**
  557. * \brief Calls the findAll on the finder and checks the result.
  558. */
  559. void findAllTest(const Name& name, ZoneFinder::Result result,
  560. const vector<ConstRRsetPtr>& expected_rrsets,
  561. ZoneFinder::FindResultFlags expected_flags =
  562. ZoneFinder::RESULT_DEFAULT,
  563. InMemoryZoneFinder* finder = NULL,
  564. const ConstRRsetPtr &rrset_result = ConstRRsetPtr(),
  565. ZoneFinder::FindOptions options =
  566. ZoneFinder::FIND_DEFAULT)
  567. {
  568. if (finder == NULL) {
  569. finder = &zone_finder_;
  570. }
  571. std::vector<ConstRRsetPtr> target;
  572. ZoneFinder::FindResult find_result(finder->findAll(name, target,
  573. options));
  574. EXPECT_EQ(result, find_result.code);
  575. if (!rrset_result) {
  576. EXPECT_FALSE(find_result.rrset);
  577. } else {
  578. ASSERT_TRUE(find_result.rrset);
  579. rrsetCheck(rrset_result, find_result.rrset);
  580. }
  581. EXPECT_EQ((expected_flags & ZoneFinder::RESULT_WILDCARD) != 0,
  582. find_result.isWildcard());
  583. EXPECT_EQ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED)
  584. != 0, find_result.isNSECSigned());
  585. EXPECT_EQ((expected_flags & ZoneFinder::RESULT_NSEC3_SIGNED)
  586. != 0, find_result.isNSEC3Signed());
  587. rrsetsCheck(expected_rrsets.begin(), expected_rrsets.end(),
  588. target.begin(), target.end());
  589. }
  590. };
  591. /**
  592. * \brief Check that findPreviousName throws as it should now.
  593. */
  594. TEST_F(InMemoryZoneFinderTest, findPreviousName) {
  595. EXPECT_THROW(zone_finder_.findPreviousName(Name("www.example.org")),
  596. isc::NotImplemented);
  597. }
  598. /**
  599. * \brief Test InMemoryZoneFinder::InMemoryZoneFinder constructor.
  600. *
  601. * Takes the created zone finder and checks its properties they are the same
  602. * as passed parameters.
  603. */
  604. TEST_F(InMemoryZoneFinderTest, constructor) {
  605. ASSERT_EQ(class_, zone_finder_.getClass());
  606. ASSERT_EQ(origin_, zone_finder_.getOrigin());
  607. }
  608. /**
  609. * \brief Test adding.
  610. *
  611. * We test that it throws at the correct moments and the correct exceptions.
  612. * And we test the return value.
  613. */
  614. TEST_F(InMemoryZoneFinderTest, add) {
  615. // This one does not belong to this zone
  616. EXPECT_THROW(zone_finder_.add(rr_out_), InMemoryZoneFinder::OutOfZone);
  617. // Test null pointer
  618. EXPECT_THROW(zone_finder_.add(ConstRRsetPtr()),
  619. InMemoryZoneFinder::NullRRset);
  620. // Now put all the data we have there. It should throw nothing
  621. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_ns_)));
  622. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_ns_a_)));
  623. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_ns_aaaa_)));
  624. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_a_)));
  625. // Try putting there something twice, it should be rejected
  626. EXPECT_NO_THROW(EXPECT_EQ(EXIST, zone_finder_.add(rr_ns_)));
  627. EXPECT_NO_THROW(EXPECT_EQ(EXIST, zone_finder_.add(rr_ns_a_)));
  628. }
  629. TEST_F(InMemoryZoneFinderTest, addMultipleCNAMEs) {
  630. rr_cname_->addRdata(generic::CNAME("canonical2.example.org."));
  631. EXPECT_THROW(zone_finder_.add(rr_cname_), InMemoryZoneFinder::AddError);
  632. }
  633. TEST_F(InMemoryZoneFinderTest, addCNAMEThenOther) {
  634. EXPECT_EQ(SUCCESS, zone_finder_.add(rr_cname_));
  635. EXPECT_THROW(zone_finder_.add(rr_cname_a_), InMemoryZoneFinder::AddError);
  636. }
  637. TEST_F(InMemoryZoneFinderTest, addOtherThenCNAME) {
  638. EXPECT_EQ(SUCCESS, zone_finder_.add(rr_cname_a_));
  639. EXPECT_THROW(zone_finder_.add(rr_cname_), InMemoryZoneFinder::AddError);
  640. }
  641. TEST_F(InMemoryZoneFinderTest, addCNAMEAndDNSSECRecords) {
  642. // CNAME and RRSIG can coexist
  643. EXPECT_EQ(SUCCESS, zone_finder_.add(rr_cname_));
  644. EXPECT_EQ(SUCCESS, zone_finder_.add(
  645. textToRRset("cname.example.org. 300 IN RRSIG CNAME 5 3 "
  646. "3600 20000101000000 20000201000000 12345 "
  647. "example.org. FAKEFAKEFAKE")));
  648. // Same for NSEC
  649. EXPECT_EQ(SUCCESS, zone_finder_.add(
  650. textToRRset("cname.example.org. 300 IN NSEC "
  651. "dname.example.org. CNAME RRSIG NSEC")));
  652. // Same as above, but adding NSEC first.
  653. EXPECT_EQ(SUCCESS, zone_finder_.add(
  654. textToRRset("cname2.example.org. 300 IN NSEC "
  655. "dname.example.org. CNAME RRSIG NSEC")));
  656. EXPECT_EQ(SUCCESS, zone_finder_.add(
  657. textToRRset("cname2.example.org. 300 IN CNAME c.example.")));
  658. // If there's another type of RRset with NSEC, it should still fail.
  659. EXPECT_EQ(SUCCESS, zone_finder_.add(
  660. textToRRset("cname3.example.org. 300 IN A 192.0.2.1")));
  661. EXPECT_EQ(SUCCESS, zone_finder_.add(
  662. textToRRset("cname3.example.org. 300 IN NSEC "
  663. "dname.example.org. CNAME RRSIG NSEC")));
  664. EXPECT_THROW(zone_finder_.add(textToRRset("cname3.example.org. 300 "
  665. "IN CNAME c.example.")),
  666. InMemoryZoneFinder::AddError);
  667. }
  668. TEST_F(InMemoryZoneFinderTest, findCNAME) {
  669. // install CNAME RR
  670. EXPECT_EQ(SUCCESS, zone_finder_.add(rr_cname_));
  671. // Find A RR of the same. Should match the CNAME
  672. findTest(rr_cname_->getName(), RRType::NS(), ZoneFinder::CNAME, true,
  673. rr_cname_);
  674. // Find the CNAME itself. Should result in normal SUCCESS
  675. findTest(rr_cname_->getName(), RRType::CNAME(), ZoneFinder::SUCCESS, true,
  676. rr_cname_);
  677. }
  678. TEST_F(InMemoryZoneFinderTest, findCNAMEUnderZoneCut) {
  679. // There's nothing special when we find a CNAME under a zone cut
  680. // (with FIND_GLUE_OK). The behavior is different from BIND 9,
  681. // so we test this case explicitly.
  682. EXPECT_EQ(SUCCESS, zone_finder_.add(rr_child_ns_));
  683. ConstRRsetPtr rr_cname_under_cut_ = textToRRset(
  684. "cname.child.example.org. 300 IN CNAME target.child.example.org.");
  685. EXPECT_EQ(SUCCESS, zone_finder_.add(rr_cname_under_cut_));
  686. findTest(Name("cname.child.example.org"), RRType::AAAA(),
  687. ZoneFinder::CNAME, true, rr_cname_under_cut_,
  688. ZoneFinder::RESULT_DEFAULT, NULL, ZoneFinder::FIND_GLUE_OK);
  689. }
  690. // Two DNAMEs at single domain are disallowed by RFC 2672, section 3)
  691. // Having a CNAME there is disallowed too, but it is tested by
  692. // addOtherThenCNAME and addCNAMEThenOther.
  693. TEST_F(InMemoryZoneFinderTest, addMultipleDNAMEs) {
  694. rr_dname_->addRdata(generic::DNAME("target2.example.org."));
  695. EXPECT_THROW(zone_finder_.add(rr_dname_), InMemoryZoneFinder::AddError);
  696. }
  697. /*
  698. * These two tests ensure that we can't have DNAME and NS at the same
  699. * node with the exception of the apex of zone (forbidden by RFC 2672)
  700. */
  701. TEST_F(InMemoryZoneFinderTest, addDNAMEThenNS) {
  702. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_dname_)));
  703. EXPECT_THROW(zone_finder_.add(rr_dname_ns_), InMemoryZoneFinder::AddError);
  704. }
  705. TEST_F(InMemoryZoneFinderTest, addNSThenDNAME) {
  706. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_dname_ns_)));
  707. EXPECT_THROW(zone_finder_.add(rr_dname_), InMemoryZoneFinder::AddError);
  708. }
  709. // It is allowed to have NS and DNAME at apex
  710. TEST_F(InMemoryZoneFinderTest, DNAMEAndNSAtApex) {
  711. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_dname_apex_)));
  712. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_ns_)));
  713. // The NS should be possible to be found, below should be DNAME, not
  714. // delegation
  715. findTest(origin_, RRType::NS(), ZoneFinder::SUCCESS, true, rr_ns_);
  716. findTest(rr_child_ns_->getName(), RRType::A(), ZoneFinder::DNAME, true,
  717. rr_dname_apex_);
  718. }
  719. TEST_F(InMemoryZoneFinderTest, NSAndDNAMEAtApex) {
  720. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_ns_)));
  721. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_dname_apex_)));
  722. }
  723. // TODO: Test (and implement) adding data under DNAME. That is forbidden by
  724. // 2672 as well.
  725. // Search under a DNAME record. It should return the DNAME
  726. TEST_F(InMemoryZoneFinderTest, findBelowDNAME) {
  727. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_dname_)));
  728. findTest(Name("below.dname.example.org"), RRType::A(), ZoneFinder::DNAME,
  729. true, rr_dname_);
  730. }
  731. // Search at the domain with DNAME. It should act as DNAME isn't there, DNAME
  732. // influences only the data below (see RFC 2672, section 3)
  733. TEST_F(InMemoryZoneFinderTest, findAtDNAME) {
  734. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_dname_)));
  735. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_dname_a_)));
  736. const Name dname_name(rr_dname_->getName());
  737. findTest(dname_name, RRType::A(), ZoneFinder::SUCCESS, true, rr_dname_a_);
  738. findTest(dname_name, RRType::DNAME(), ZoneFinder::SUCCESS, true,
  739. rr_dname_);
  740. findTest(dname_name, RRType::TXT(), ZoneFinder::NXRRSET, true);
  741. }
  742. // Try searching something that is both under NS and DNAME, without and with
  743. // GLUE_OK mode (it should stop at the NS and DNAME respectively).
  744. TEST_F(InMemoryZoneFinderTest, DNAMEUnderNS) {
  745. zone_finder_.add(rr_child_ns_);
  746. zone_finder_.add(rr_child_dname_);
  747. Name lowName("below.dname.child.example.org.");
  748. findTest(lowName, RRType::A(), ZoneFinder::DELEGATION, true, rr_child_ns_);
  749. findTest(lowName, RRType::A(), ZoneFinder::DNAME, true, rr_child_dname_,
  750. ZoneFinder::RESULT_DEFAULT, NULL, ZoneFinder::FIND_GLUE_OK);
  751. }
  752. // Test adding child zones and zone cut handling
  753. TEST_F(InMemoryZoneFinderTest, delegationNS) {
  754. // add in-zone data
  755. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_ns_)));
  756. // install a zone cut
  757. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_child_ns_)));
  758. // below the zone cut
  759. findTest(Name("www.child.example.org"), RRType::A(),
  760. ZoneFinder::DELEGATION, true, rr_child_ns_);
  761. // at the zone cut
  762. findTest(Name("child.example.org"), RRType::A(), ZoneFinder::DELEGATION,
  763. true, rr_child_ns_);
  764. findTest(Name("child.example.org"), RRType::NS(), ZoneFinder::DELEGATION,
  765. true, rr_child_ns_);
  766. // finding NS for the apex (origin) node. This must not be confused
  767. // with delegation due to the existence of an NS RR.
  768. findTest(origin_, RRType::NS(), ZoneFinder::SUCCESS, true, rr_ns_);
  769. // unusual case of "nested delegation": the highest cut should be used.
  770. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_grandchild_ns_)));
  771. findTest(Name("www.grand.child.example.org"), RRType::A(),
  772. // note: !rr_grandchild_ns_
  773. ZoneFinder::DELEGATION, true, rr_child_ns_);
  774. }
  775. TEST_F(InMemoryZoneFinderTest, delegationWithDS) {
  776. // Similar setup to the previous one, but with DS RR at the delegation
  777. // point.
  778. EXPECT_EQ(SUCCESS, zone_finder_.add(rr_ns_));
  779. EXPECT_EQ(SUCCESS, zone_finder_.add(rr_child_ns_));
  780. EXPECT_EQ(SUCCESS, zone_finder_.add(rr_child_ds_));
  781. // Normal types of query should result in delegation, but DS query
  782. // should be considered in-zone (but only exactly at the delegation point).
  783. findTest(Name("child.example.org"), RRType::A(), ZoneFinder::DELEGATION,
  784. true, rr_child_ns_);
  785. findTest(Name("child.example.org"), RRType::DS(), ZoneFinder::SUCCESS,
  786. true, rr_child_ds_);
  787. findTest(Name("grand.child.example.org"), RRType::DS(),
  788. ZoneFinder::DELEGATION, true, rr_child_ns_);
  789. // There's nothing special for DS query at the zone apex. It would
  790. // normally result in NXRRSET.
  791. findTest(Name("example.org"), RRType::DS(), ZoneFinder::NXRRSET,
  792. true, ConstRRsetPtr());
  793. }
  794. TEST_F(InMemoryZoneFinderTest, findAny) {
  795. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_a_)));
  796. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_ns_)));
  797. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_child_glue_)));
  798. vector<ConstRRsetPtr> expected_sets;
  799. // origin
  800. expected_sets.push_back(rr_a_);
  801. expected_sets.push_back(rr_ns_);
  802. findAllTest(origin_, ZoneFinder::SUCCESS, expected_sets);
  803. // out zone name
  804. findAllTest(Name("example.com"), ZoneFinder::NXDOMAIN,
  805. vector<ConstRRsetPtr>());
  806. expected_sets.clear();
  807. expected_sets.push_back(rr_child_glue_);
  808. findAllTest(rr_child_glue_->getName(), ZoneFinder::SUCCESS, expected_sets);
  809. // add zone cut
  810. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_child_ns_)));
  811. // zone cut
  812. findAllTest(rr_child_ns_->getName(), ZoneFinder::DELEGATION,
  813. vector<ConstRRsetPtr>(), ZoneFinder::RESULT_DEFAULT,
  814. NULL, rr_child_ns_);
  815. // glue for this zone cut
  816. findAllTest(rr_child_glue_->getName(),ZoneFinder::DELEGATION,
  817. vector<ConstRRsetPtr>(), ZoneFinder::RESULT_DEFAULT,
  818. NULL, rr_child_ns_);
  819. }
  820. TEST_F(InMemoryZoneFinderTest, glue) {
  821. // install zone data:
  822. // a zone cut
  823. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_child_ns_)));
  824. // glue for this cut
  825. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_child_glue_)));
  826. // a nested zone cut (unusual)
  827. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_grandchild_ns_)));
  828. // glue under the deeper zone cut
  829. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_grandchild_glue_)));
  830. // by default glue is hidden due to the zone cut
  831. findTest(rr_child_glue_->getName(), RRType::A(), ZoneFinder::DELEGATION,
  832. true, rr_child_ns_);
  833. // If we do it in the "glue OK" mode, we should find the exact match.
  834. findTest(rr_child_glue_->getName(), RRType::A(), ZoneFinder::SUCCESS, true,
  835. rr_child_glue_, ZoneFinder::RESULT_DEFAULT, NULL,
  836. ZoneFinder::FIND_GLUE_OK);
  837. // glue OK + NXRRSET case
  838. findTest(rr_child_glue_->getName(), RRType::AAAA(), ZoneFinder::NXRRSET,
  839. true, ConstRRsetPtr(), ZoneFinder::RESULT_DEFAULT, NULL,
  840. ZoneFinder::FIND_GLUE_OK);
  841. // glue OK + NXDOMAIN case
  842. findTest(Name("www.child.example.org"), RRType::A(),
  843. ZoneFinder::DELEGATION, true, rr_child_ns_,
  844. ZoneFinder::RESULT_DEFAULT, NULL, ZoneFinder::FIND_GLUE_OK);
  845. // nested cut case. The glue should be found.
  846. findTest(rr_grandchild_glue_->getName(), RRType::AAAA(),
  847. ZoneFinder::SUCCESS,
  848. true, rr_grandchild_glue_, ZoneFinder::RESULT_DEFAULT, NULL,
  849. ZoneFinder::FIND_GLUE_OK);
  850. // A non-existent name in nested cut. This should result in delegation
  851. // at the highest zone cut.
  852. findTest(Name("www.grand.child.example.org"), RRType::TXT(),
  853. ZoneFinder::DELEGATION, true, rr_child_ns_,
  854. ZoneFinder::RESULT_DEFAULT, NULL, ZoneFinder::FIND_GLUE_OK);
  855. }
  856. /**
  857. * \brief Test searching.
  858. *
  859. * Check it finds or does not find correctly and does not throw exceptions.
  860. * \todo This doesn't do any kind of CNAME and so on. If it isn't
  861. * directly there, it just tells it doesn't exist.
  862. */
  863. void
  864. InMemoryZoneFinderTest::findCheck(ZoneFinder::FindResultFlags expected_flags) {
  865. // Fill some data inside
  866. // Now put all the data we have there. It should throw nothing
  867. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_ns_)));
  868. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_ns_a_)));
  869. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_ns_aaaa_)));
  870. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_a_)));
  871. if ((expected_flags & ZoneFinder::RESULT_NSEC3_SIGNED) != 0) {
  872. EXPECT_EQ(SUCCESS, zone_finder_.add(rr_nsec3_));
  873. }
  874. // These two should be successful
  875. findTest(origin_, RRType::NS(), ZoneFinder::SUCCESS, true, rr_ns_);
  876. findTest(rr_ns_a_->getName(), RRType::A(), ZoneFinder::SUCCESS, true,
  877. rr_ns_a_);
  878. // These domain exist but don't have the provided RRType
  879. findTest(origin_, RRType::AAAA(), ZoneFinder::NXRRSET, true,
  880. ConstRRsetPtr(), expected_flags);
  881. findTest(rr_ns_a_->getName(), RRType::NS(), ZoneFinder::NXRRSET, true,
  882. ConstRRsetPtr(), expected_flags);
  883. // These domains don't exist (and one is out of the zone)
  884. findTest(Name("nothere.example.org"), RRType::A(), ZoneFinder::NXDOMAIN,
  885. true, ConstRRsetPtr(), expected_flags);
  886. findTest(Name("example.net"), RRType::A(), ZoneFinder::NXDOMAIN, true,
  887. ConstRRsetPtr(), expected_flags);
  888. }
  889. TEST_F(InMemoryZoneFinderTest, find) {
  890. findCheck();
  891. }
  892. TEST_F(InMemoryZoneFinderTest, findNSEC3Signed) {
  893. findCheck(ZoneFinder::RESULT_NSEC3_SIGNED);
  894. }
  895. void
  896. InMemoryZoneFinderTest::emptyNodeCheck(
  897. ZoneFinder::FindResultFlags expected_flags)
  898. {
  899. /*
  900. * The backend RBTree for this test should look like as follows:
  901. * example.org
  902. * |
  903. * baz (empty; easy case)
  904. * / | \
  905. * bar | x.foo ('foo' part is empty; a bit trickier)
  906. * bbb
  907. * /
  908. * aaa
  909. */
  910. // Construct the test zone
  911. const char* const names[] = {
  912. "bar.example.org.", "x.foo.example.org.", "aaa.baz.example.org.",
  913. "bbb.baz.example.org.", NULL};
  914. for (int i = 0; names[i] != NULL; ++i) {
  915. ConstRRsetPtr rrset = textToRRset(string(names[i]) +
  916. " 300 IN A 192.0.2.1");
  917. EXPECT_EQ(SUCCESS, zone_finder_.add(rrset));
  918. }
  919. if ((expected_flags & ZoneFinder::RESULT_NSEC3_SIGNED) != 0) {
  920. EXPECT_EQ(SUCCESS, zone_finder_.add(rr_nsec3_));
  921. }
  922. // empty node matching, easy case: the node for 'baz' exists with
  923. // no data.
  924. findTest(Name("baz.example.org"), RRType::A(), ZoneFinder::NXRRSET, true,
  925. ConstRRsetPtr(), expected_flags);
  926. // empty node matching, a trickier case: the node for 'foo' is part of
  927. // "x.foo", which should be considered an empty node.
  928. findTest(Name("foo.example.org"), RRType::A(), ZoneFinder::NXRRSET, true,
  929. ConstRRsetPtr(), expected_flags);
  930. // "org" is contained in "example.org", but it shouldn't be treated as
  931. // NXRRSET because it's out of zone.
  932. // Note: basically we don't expect such a query to be performed (the common
  933. // operation is to identify the best matching zone first then perform
  934. // search it), but we shouldn't be confused even in the unexpected case.
  935. findTest(Name("org"), RRType::A(), ZoneFinder::NXDOMAIN, true,
  936. ConstRRsetPtr(), expected_flags);
  937. }
  938. TEST_F(InMemoryZoneFinderTest, emptyNode) {
  939. emptyNodeCheck();
  940. }
  941. TEST_F(InMemoryZoneFinderTest, emptyNodeNSEC3) {
  942. emptyNodeCheck(ZoneFinder::RESULT_NSEC3_SIGNED);
  943. }
  944. TEST_F(InMemoryZoneFinderTest, load) {
  945. // Put some data inside the zone
  946. EXPECT_NO_THROW(EXPECT_EQ(result::SUCCESS, zone_finder_.add(rr_ns_)));
  947. // Loading with different origin should fail
  948. EXPECT_THROW(zone_finder_.load(TEST_DATA_DIR "/root.zone"),
  949. MasterLoadError);
  950. // See the original data is still there, survived the exception
  951. findTest(origin_, RRType::NS(), ZoneFinder::SUCCESS, true, rr_ns_);
  952. // Create correct zone
  953. InMemoryZoneFinder rootzone(class_, Name("."));
  954. // Try putting something inside
  955. EXPECT_NO_THROW(EXPECT_EQ(result::SUCCESS, rootzone.add(rr_ns_aaaa_)));
  956. // Load the zone. It should overwrite/remove the above RRset
  957. EXPECT_NO_THROW(rootzone.load(TEST_DATA_DIR "/root.zone"));
  958. // Now see there are some rrsets (we don't look inside, though)
  959. findTest(Name("."), RRType::SOA(), ZoneFinder::SUCCESS, false,
  960. ConstRRsetPtr(), ZoneFinder::RESULT_DEFAULT, &rootzone);
  961. findTest(Name("."), RRType::NS(), ZoneFinder::SUCCESS, false,
  962. ConstRRsetPtr(), ZoneFinder::RESULT_DEFAULT, &rootzone);
  963. findTest(Name("a.root-servers.net."), RRType::A(), ZoneFinder::SUCCESS,
  964. false, ConstRRsetPtr(), ZoneFinder::RESULT_DEFAULT, &rootzone);
  965. // But this should no longer be here
  966. findTest(rr_ns_a_->getName(), RRType::AAAA(), ZoneFinder::NXDOMAIN, true,
  967. ConstRRsetPtr(), ZoneFinder::RESULT_DEFAULT, &rootzone);
  968. // Try loading zone that is wrong in a different way
  969. EXPECT_THROW(zone_finder_.load(TEST_DATA_DIR "/duplicate_rrset.zone"),
  970. MasterLoadError);
  971. }
  972. /*
  973. * Test that puts a (simple) wildcard into the zone and checks we can
  974. * correctly find the data.
  975. */
  976. void
  977. InMemoryZoneFinderTest::wildcardCheck(
  978. ZoneFinder::FindResultFlags expected_flags)
  979. {
  980. /*
  981. * example.org.
  982. * |
  983. * [cname]wild (not *.wild, should have wild mark)
  984. * |
  985. * *
  986. */
  987. // If the zone is "signed" (detecting it by the NSEC/NSEC3 signed flags),
  988. // add RRSIGs to the records.
  989. ZoneFinder::FindOptions find_options = ZoneFinder::FIND_DEFAULT;
  990. if ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED) != 0 ||
  991. (expected_flags & ZoneFinder::RESULT_NSEC3_SIGNED) != 0) {
  992. // Convenience shortcut. The RDATA is not really validatable, but
  993. // it doesn't matter for our tests.
  994. const char* const rrsig_common = "5 3 3600 "
  995. "20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE";
  996. find_options = find_options | ZoneFinder::FIND_DNSSEC;
  997. rr_wild_->addRRsig(textToRRset("*.wild.example.org. 300 IN RRSIG A " +
  998. string(rrsig_common)));
  999. rr_cnamewild_->addRRsig(textToRRset("*.cnamewild.example.org. 300 IN "
  1000. "RRSIG CNAME " +
  1001. string(rrsig_common)));
  1002. }
  1003. EXPECT_EQ(SUCCESS, zone_finder_.add(rr_wild_));
  1004. EXPECT_EQ(SUCCESS, zone_finder_.add(rr_cnamewild_));
  1005. // If the zone is expected to be "signed" with NSEC3, add an NSEC3.
  1006. // (the content of the NSEC3 shouldn't matter)
  1007. if ((expected_flags & ZoneFinder::RESULT_NSEC3_SIGNED) != 0) {
  1008. EXPECT_EQ(SUCCESS, zone_finder_.add(rr_nsec3_));
  1009. }
  1010. // Search at the parent. The parent will not have the A, but it will
  1011. // be in the wildcard (so check the wildcard isn't matched at the parent)
  1012. {
  1013. SCOPED_TRACE("Search at parent");
  1014. findTest(Name("wild.example.org"), RRType::A(), ZoneFinder::NXRRSET,
  1015. true, ConstRRsetPtr(), expected_flags, NULL, find_options);
  1016. }
  1017. // Search the original name of wildcard
  1018. {
  1019. SCOPED_TRACE("Search directly at *");
  1020. findTest(Name("*.wild.example.org"), RRType::A(), ZoneFinder::SUCCESS,
  1021. true, rr_wild_, ZoneFinder::RESULT_DEFAULT, NULL,
  1022. find_options);
  1023. }
  1024. // Search "created" name.
  1025. {
  1026. SCOPED_TRACE("Search at created child");
  1027. findTest(Name("a.wild.example.org"), RRType::A(), ZoneFinder::SUCCESS,
  1028. false, rr_wild_,
  1029. ZoneFinder::RESULT_WILDCARD | expected_flags, NULL,
  1030. find_options, true);
  1031. // Wildcard match, but no data
  1032. findTest(Name("a.wild.example.org"), RRType::AAAA(),
  1033. ZoneFinder::NXRRSET, true, ConstRRsetPtr(),
  1034. ZoneFinder::RESULT_WILDCARD | expected_flags, NULL,
  1035. find_options);
  1036. }
  1037. // Search name that has CNAME.
  1038. {
  1039. SCOPED_TRACE("Matching CNAME");
  1040. findTest(Name("a.cnamewild.example.org"), RRType::A(),
  1041. ZoneFinder::CNAME, false, rr_cnamewild_,
  1042. ZoneFinder::RESULT_WILDCARD | expected_flags, NULL,
  1043. find_options, true);
  1044. }
  1045. // Search another created name, this time little bit lower
  1046. {
  1047. SCOPED_TRACE("Search at created grand-child");
  1048. findTest(Name("a.b.wild.example.org"), RRType::A(),
  1049. ZoneFinder::SUCCESS, false, rr_wild_,
  1050. ZoneFinder::RESULT_WILDCARD | expected_flags, NULL,
  1051. find_options, true);
  1052. }
  1053. EXPECT_EQ(SUCCESS, zone_finder_.add(rr_under_wild_));
  1054. {
  1055. SCOPED_TRACE("Search under non-wildcard");
  1056. findTest(Name("bar.foo.wild.example.org"), RRType::A(),
  1057. ZoneFinder::NXDOMAIN, true, ConstRRsetPtr(), expected_flags,
  1058. NULL, find_options);
  1059. }
  1060. }
  1061. TEST_F(InMemoryZoneFinderTest, wildcard) {
  1062. // Normal case
  1063. wildcardCheck();
  1064. }
  1065. TEST_F(InMemoryZoneFinderTest, wildcardNSEC3) {
  1066. // Similar to the previous one, but the zone signed with NSEC3
  1067. wildcardCheck(ZoneFinder::RESULT_NSEC3_SIGNED);
  1068. }
  1069. /*
  1070. * Test that we don't match a wildcard if we get under delegation.
  1071. * By 4.3.3 of RFC1034:
  1072. * "Wildcard RRs do not apply:
  1073. * - When the query is in another zone. That is, delegation cancels
  1074. * the wildcard defaults."
  1075. */
  1076. TEST_F(InMemoryZoneFinderTest, delegatedWildcard) {
  1077. EXPECT_EQ(SUCCESS, zone_finder_.add(rr_child_wild_));
  1078. EXPECT_EQ(SUCCESS, zone_finder_.add(rr_child_ns_));
  1079. {
  1080. SCOPED_TRACE("Looking under delegation point");
  1081. findTest(Name("a.child.example.org"), RRType::A(),
  1082. ZoneFinder::DELEGATION, true, rr_child_ns_);
  1083. }
  1084. {
  1085. SCOPED_TRACE("Looking under delegation point in GLUE_OK mode");
  1086. findTest(Name("a.child.example.org"), RRType::A(),
  1087. ZoneFinder::DELEGATION, true, rr_child_ns_,
  1088. ZoneFinder::RESULT_DEFAULT, NULL, ZoneFinder::FIND_GLUE_OK);
  1089. }
  1090. }
  1091. // Tests combination of wildcard and ANY.
  1092. void
  1093. InMemoryZoneFinderTest::anyWildcardCheck(
  1094. ZoneFinder::FindResultFlags expected_flags)
  1095. {
  1096. EXPECT_EQ(SUCCESS, zone_finder_.add(rr_wild_));
  1097. if ((expected_flags & ZoneFinder::RESULT_NSEC3_SIGNED) != 0) {
  1098. EXPECT_EQ(SUCCESS, zone_finder_.add(rr_nsec3_));
  1099. }
  1100. vector<ConstRRsetPtr> expected_sets;
  1101. // First try directly the name (normal match)
  1102. {
  1103. SCOPED_TRACE("Asking direcly for *");
  1104. expected_sets.push_back(rr_wild_);
  1105. findAllTest(Name("*.wild.example.org"), ZoneFinder::SUCCESS,
  1106. expected_sets);
  1107. }
  1108. // Then a wildcard match
  1109. {
  1110. SCOPED_TRACE("Asking in the wild way");
  1111. expected_sets.clear();
  1112. RRsetPtr expected(new RRset(Name("a.wild.example.org"),
  1113. rr_wild_->getClass(), rr_wild_->getType(),
  1114. rr_wild_->getTTL()));
  1115. expected->addRdata(rr_wild_->getRdataIterator()->getCurrent());
  1116. expected_sets.push_back(expected);
  1117. findAllTest(Name("a.wild.example.org"), ZoneFinder::SUCCESS,
  1118. expected_sets,
  1119. ZoneFinder::RESULT_WILDCARD | expected_flags);
  1120. }
  1121. }
  1122. TEST_F(InMemoryZoneFinderTest, anyWildcard) {
  1123. anyWildcardCheck();
  1124. }
  1125. TEST_F(InMemoryZoneFinderTest, anyWildcardNSEC3) {
  1126. anyWildcardCheck(ZoneFinder::RESULT_NSEC3_SIGNED);
  1127. }
  1128. // Test there's nothing in the wildcard in the middle if we load
  1129. // wild.*.foo.example.org.
  1130. void
  1131. InMemoryZoneFinderTest::emptyWildcardCheck(
  1132. ZoneFinder::FindResultFlags expected_flags)
  1133. {
  1134. /*
  1135. * example.org.
  1136. * foo
  1137. * *
  1138. * wild
  1139. */
  1140. EXPECT_EQ(SUCCESS, zone_finder_.add(rr_emptywild_));
  1141. if ((expected_flags & ZoneFinder::RESULT_NSEC3_SIGNED) != 0) {
  1142. EXPECT_EQ(SUCCESS, zone_finder_.add(rr_nsec3_));
  1143. }
  1144. {
  1145. SCOPED_TRACE("Asking for the original record under wildcard");
  1146. findTest(Name("wild.*.foo.example.org"), RRType::A(),
  1147. ZoneFinder::SUCCESS, true, rr_emptywild_);
  1148. }
  1149. {
  1150. SCOPED_TRACE("Asking for A record");
  1151. findTest(Name("a.foo.example.org"), RRType::A(), ZoneFinder::NXRRSET,
  1152. true, ConstRRsetPtr(),
  1153. ZoneFinder::RESULT_WILDCARD | expected_flags);
  1154. findTest(Name("*.foo.example.org"), RRType::A(), ZoneFinder::NXRRSET,
  1155. true, ConstRRsetPtr(), expected_flags);
  1156. findTest(Name("foo.example.org"), RRType::A(), ZoneFinder::NXRRSET,
  1157. true, ConstRRsetPtr(), expected_flags);
  1158. }
  1159. {
  1160. SCOPED_TRACE("Asking for ANY record");
  1161. findAllTest(Name("*.foo.example.org"), ZoneFinder::NXRRSET,
  1162. vector<ConstRRsetPtr>(), expected_flags);
  1163. findAllTest(Name("a.foo.example.org"), ZoneFinder::NXRRSET,
  1164. vector<ConstRRsetPtr>(),
  1165. ZoneFinder::RESULT_WILDCARD | expected_flags);
  1166. }
  1167. {
  1168. SCOPED_TRACE("Asking on the non-terminal");
  1169. findTest(Name("wild.bar.foo.example.org"), RRType::A(),
  1170. ZoneFinder::NXRRSET, true, ConstRRsetPtr(),
  1171. ZoneFinder::RESULT_WILDCARD | expected_flags);
  1172. }
  1173. }
  1174. TEST_F(InMemoryZoneFinderTest, emptyWildcard) {
  1175. emptyWildcardCheck();
  1176. }
  1177. TEST_F(InMemoryZoneFinderTest, emptyWildcardNSEC3) {
  1178. emptyWildcardCheck(ZoneFinder::RESULT_NSEC3_SIGNED);
  1179. }
  1180. // Same as emptyWildcard, but with multiple * in the path.
  1181. TEST_F(InMemoryZoneFinderTest, nestedEmptyWildcard) {
  1182. EXPECT_EQ(SUCCESS, zone_finder_.add(rr_nested_emptywild_));
  1183. {
  1184. SCOPED_TRACE("Asking for the original record under wildcards");
  1185. findTest(Name("wild.*.foo.*.bar.example.org"), RRType::A(),
  1186. ZoneFinder::SUCCESS, true, rr_nested_emptywild_);
  1187. }
  1188. {
  1189. SCOPED_TRACE("Matching wildcard against empty nonterminal");
  1190. const char* names[] = {
  1191. "baz.foo.*.bar.example.org",
  1192. "baz.foo.baz.bar.example.org",
  1193. "*.foo.baz.bar.example.org",
  1194. NULL
  1195. };
  1196. for (const char** name = names; *name != NULL; ++ name) {
  1197. SCOPED_TRACE(string("Node ") + *name);
  1198. findTest(Name(*name), RRType::A(), ZoneFinder::NXRRSET, true,
  1199. ConstRRsetPtr(), ZoneFinder::RESULT_WILDCARD);
  1200. }
  1201. }
  1202. // Domains to test
  1203. const char* names[] = {
  1204. "*.foo.*.bar.example.org",
  1205. "foo.*.bar.example.org",
  1206. "*.bar.example.org",
  1207. "bar.example.org",
  1208. NULL
  1209. };
  1210. {
  1211. SCOPED_TRACE("Asking directly for A on parent nodes");
  1212. for (const char** name = names; *name != NULL; ++ name) {
  1213. SCOPED_TRACE(string("Node ") + *name);
  1214. findTest(Name(*name), RRType::A(), ZoneFinder::NXRRSET);
  1215. }
  1216. }
  1217. {
  1218. SCOPED_TRACE("Asking for ANY on parent nodes");
  1219. for (const char** name = names; *name != NULL; ++ name) {
  1220. SCOPED_TRACE(string("Node ") + *name);
  1221. findAllTest(Name(*name), ZoneFinder::NXRRSET,
  1222. vector<ConstRRsetPtr>());
  1223. }
  1224. }
  1225. }
  1226. // We run this part twice from the below test, in two slightly different
  1227. // situations
  1228. void
  1229. InMemoryZoneFinderTest::doCancelWildcardCheck(
  1230. ZoneFinder::FindResultFlags expected_flags)
  1231. {
  1232. // These should be canceled
  1233. {
  1234. SCOPED_TRACE("Canceled under foo.wild.example.org");
  1235. findTest(Name("aaa.foo.wild.example.org"), RRType::A(),
  1236. ZoneFinder::NXDOMAIN, true, ConstRRsetPtr(), expected_flags);
  1237. findTest(Name("zzz.foo.wild.example.org"), RRType::A(),
  1238. ZoneFinder::NXDOMAIN, true, ConstRRsetPtr(), expected_flags);
  1239. }
  1240. // This is existing, non-wildcard domain, shouldn't wildcard at all
  1241. {
  1242. SCOPED_TRACE("Existing domain under foo.wild.example.org");
  1243. findTest(Name("bar.foo.wild.example.org"), RRType::A(),
  1244. ZoneFinder::SUCCESS, true, rr_not_wild_);
  1245. }
  1246. // These should be caught by the wildcard
  1247. {
  1248. SCOPED_TRACE("Neighbor wildcards to foo.wild.example.org");
  1249. const char* names[] = {
  1250. "aaa.bbb.wild.example.org",
  1251. "aaa.zzz.wild.example.org",
  1252. "zzz.wild.example.org",
  1253. NULL
  1254. };
  1255. for (const char** name = names; *name != NULL; ++ name) {
  1256. SCOPED_TRACE(string("Node ") + *name);
  1257. findTest(Name(*name), RRType::A(), ZoneFinder::SUCCESS, false,
  1258. rr_wild_,
  1259. ZoneFinder::RESULT_WILDCARD | expected_flags, NULL,
  1260. ZoneFinder::FIND_DEFAULT, true);
  1261. }
  1262. }
  1263. // This shouldn't be wildcarded, it's an existing domain
  1264. {
  1265. SCOPED_TRACE("The foo.wild.example.org itself");
  1266. findTest(Name("foo.wild.example.org"), RRType::A(),
  1267. ZoneFinder::NXRRSET, true, ConstRRsetPtr(), expected_flags);
  1268. }
  1269. }
  1270. /*
  1271. * This tests that if there's a name between the wildcard domain and the
  1272. * searched one, it will not trigger wildcard, for example, if we have
  1273. * *.wild.example.org and bar.foo.wild.example.org, then we know
  1274. * foo.wild.example.org exists and is not wildcard. Therefore, search for
  1275. * aaa.foo.wild.example.org should return NXDOMAIN.
  1276. *
  1277. * Tests few cases "around" the canceled wildcard match, to see something that
  1278. * shouldn't be canceled isn't.
  1279. */
  1280. TEST_F(InMemoryZoneFinderTest, cancelWildcard) {
  1281. EXPECT_EQ(SUCCESS, zone_finder_.add(rr_wild_));
  1282. EXPECT_EQ(SUCCESS, zone_finder_.add(rr_not_wild_));
  1283. {
  1284. SCOPED_TRACE("Runnig with single entry under foo.wild.example.org");
  1285. doCancelWildcardCheck();
  1286. }
  1287. // Try putting another one under foo.wild....
  1288. // The result should be the same but it will be done in another way in the
  1289. // code, because the foo.wild.example.org will exist in the tree.
  1290. EXPECT_EQ(SUCCESS, zone_finder_.add(rr_not_wild_another_));
  1291. {
  1292. SCOPED_TRACE("Runnig with two entries under foo.wild.example.org");
  1293. doCancelWildcardCheck();
  1294. }
  1295. }
  1296. TEST_F(InMemoryZoneFinderTest, cancelWildcardNSEC3) {
  1297. EXPECT_EQ(SUCCESS, zone_finder_.add(rr_wild_));
  1298. EXPECT_EQ(SUCCESS, zone_finder_.add(rr_not_wild_));
  1299. EXPECT_EQ(SUCCESS, zone_finder_.add(rr_nsec3_));
  1300. {
  1301. SCOPED_TRACE("Runnig with single entry under foo.wild.example.org");
  1302. doCancelWildcardCheck(ZoneFinder::RESULT_NSEC3_SIGNED);
  1303. }
  1304. EXPECT_EQ(SUCCESS, zone_finder_.add(rr_not_wild_another_));
  1305. {
  1306. SCOPED_TRACE("Runnig with two entries under foo.wild.example.org");
  1307. doCancelWildcardCheck(ZoneFinder::RESULT_NSEC3_SIGNED);
  1308. }
  1309. }
  1310. TEST_F(InMemoryZoneFinderTest, loadBadWildcard) {
  1311. // We reject loading the zone if it contains a wildcard name for
  1312. // NS or DNAME.
  1313. EXPECT_THROW(zone_finder_.add(rr_nswild_), InMemoryZoneFinder::AddError);
  1314. EXPECT_THROW(zone_finder_.add(rr_dnamewild_),
  1315. InMemoryZoneFinder::AddError);
  1316. }
  1317. TEST_F(InMemoryZoneFinderTest, swap) {
  1318. // build one zone finder with some data
  1319. InMemoryZoneFinder finder1(class_, origin_);
  1320. EXPECT_EQ(result::SUCCESS, finder1.add(rr_ns_));
  1321. EXPECT_EQ(result::SUCCESS, finder1.add(rr_ns_aaaa_));
  1322. // build another zone finder of a different RR class with some other data
  1323. const Name other_origin("version.bind");
  1324. ASSERT_NE(origin_, other_origin); // make sure these two are different
  1325. InMemoryZoneFinder finder2(RRClass::CH(), other_origin);
  1326. EXPECT_EQ(result::SUCCESS,
  1327. finder2.add(textToRRset("version.bind. 0 CH TXT \"test\"",
  1328. RRClass::CH())));
  1329. finder1.swap(finder2);
  1330. EXPECT_EQ(other_origin, finder1.getOrigin());
  1331. EXPECT_EQ(origin_, finder2.getOrigin());
  1332. EXPECT_EQ(RRClass::CH(), finder1.getClass());
  1333. EXPECT_EQ(RRClass::IN(), finder2.getClass());
  1334. // make sure the zone data is swapped, too
  1335. findTest(origin_, RRType::NS(), ZoneFinder::NXDOMAIN, false,
  1336. ConstRRsetPtr(), ZoneFinder::RESULT_DEFAULT, &finder1);
  1337. findTest(other_origin, RRType::TXT(), ZoneFinder::SUCCESS, false,
  1338. ConstRRsetPtr(), ZoneFinder::RESULT_DEFAULT, &finder1);
  1339. findTest(origin_, RRType::NS(), ZoneFinder::SUCCESS, false,
  1340. ConstRRsetPtr(), ZoneFinder::RESULT_DEFAULT, &finder2);
  1341. findTest(other_origin, RRType::TXT(), ZoneFinder::NXDOMAIN, false,
  1342. ConstRRsetPtr(), ZoneFinder::RESULT_DEFAULT, &finder2);
  1343. }
  1344. TEST_F(InMemoryZoneFinderTest, getFileName) {
  1345. // for an empty zone the file name should also be empty.
  1346. EXPECT_TRUE(zone_finder_.getFileName().empty());
  1347. // if loading a zone fails the file name shouldn't be set.
  1348. EXPECT_THROW(zone_finder_.load(TEST_DATA_DIR "/root.zone"),
  1349. MasterLoadError);
  1350. EXPECT_TRUE(zone_finder_.getFileName().empty());
  1351. // after a successful load, the specified file name should be set
  1352. InMemoryZoneFinder rootzone(class_, Name("."));
  1353. EXPECT_NO_THROW(rootzone.load(TEST_DATA_DIR "/root.zone"));
  1354. EXPECT_EQ(TEST_DATA_DIR "/root.zone", rootzone.getFileName());
  1355. // overriding load, which will fail
  1356. EXPECT_THROW(rootzone.load(TEST_DATA_DIR "/duplicate_rrset.zone"),
  1357. MasterLoadError);
  1358. // the file name should be intact.
  1359. EXPECT_EQ(TEST_DATA_DIR "/root.zone", rootzone.getFileName());
  1360. // After swap, file names should also be swapped.
  1361. zone_finder_.swap(rootzone);
  1362. EXPECT_EQ(TEST_DATA_DIR "/root.zone", zone_finder_.getFileName());
  1363. EXPECT_TRUE(rootzone.getFileName().empty());
  1364. }
  1365. TEST_F(InMemoryZoneFinderTest, addRRsig) {
  1366. // A simple valid case: adding an RRset to be signed followed by an RRSIG
  1367. // that covers the first RRset
  1368. zone_finder_.add(rr_a_);
  1369. zone_finder_.add(textToRRset(rrsig_a_txt));
  1370. ZoneFinder::FindResult result = zone_finder_.find(origin_, RRType::A(),
  1371. ZoneFinder::FIND_DNSSEC);
  1372. EXPECT_EQ(ZoneFinder::SUCCESS, result.code);
  1373. ASSERT_TRUE(result.rrset);
  1374. ASSERT_TRUE(result.rrset->getRRsig());
  1375. actual_rrsets_.push_back(result.rrset->getRRsig());
  1376. rrsetsCheck(rrsig_a_txt, actual_rrsets_.begin(), actual_rrsets_.end());
  1377. // Confirm a separate RRISG for a different type can be added
  1378. actual_rrsets_.clear();
  1379. zone_finder_.add(rr_ns_);
  1380. zone_finder_.add(textToRRset(rrsig_ns_txt));
  1381. ZoneFinder::FindResult result2 =
  1382. zone_finder_.find(origin_, RRType::NS(), ZoneFinder::FIND_DNSSEC);
  1383. EXPECT_EQ(ZoneFinder::SUCCESS, result2.code);
  1384. ASSERT_TRUE(result2.rrset);
  1385. ASSERT_TRUE(result2.rrset->getRRsig());
  1386. actual_rrsets_.push_back(result2.rrset->getRRsig());
  1387. rrsetsCheck(rrsig_ns_txt, actual_rrsets_.begin(), actual_rrsets_.end());
  1388. // Check a case with multiple RRSIGs
  1389. actual_rrsets_.clear();
  1390. zone_finder_.add(rr_ns_aaaa_);
  1391. zone_finder_.add(textToRRset(rrsig_aaaa_txt));
  1392. ZoneFinder::FindResult result3 =
  1393. zone_finder_.find(Name("ns.example.org"), RRType::AAAA(),
  1394. ZoneFinder::FIND_DNSSEC);
  1395. EXPECT_EQ(ZoneFinder::SUCCESS, result3.code);
  1396. ASSERT_TRUE(result3.rrset);
  1397. ASSERT_TRUE(result3.rrset->getRRsig());
  1398. actual_rrsets_.push_back(result3.rrset->getRRsig());
  1399. rrsetsCheck(rrsig_aaaa_txt, actual_rrsets_.begin(), actual_rrsets_.end());
  1400. }
  1401. TEST_F(InMemoryZoneFinderTest, addRRsigWithoutCovered) {
  1402. // The current implementation rejects attempts of adding RRSIG without
  1403. // covered RRsets already in the zone.
  1404. // Name doesn't exist
  1405. EXPECT_THROW(zone_finder_.add(
  1406. textToRRset("notexist.example.org. 300 IN RRSIG A 5 3 "
  1407. "3600 20000101000000 20000201000000 12345 "
  1408. "example.org. FAKEFAKEFAKE\n")),
  1409. InMemoryZoneFinder::AddError);
  1410. // Name exists, but is empty.
  1411. zone_finder_.add(rr_emptywild_);
  1412. EXPECT_THROW(zone_finder_.add(
  1413. textToRRset("foo.example.org. 300 IN RRSIG A 5 3 "
  1414. "3600 20000101000000 20000201000000 12345 "
  1415. "example.org. FAKEFAKEFAKE\n")),
  1416. InMemoryZoneFinder::AddError);
  1417. // Add RRSIG RRset without covered RR
  1418. zone_finder_.add(rr_a_);
  1419. EXPECT_THROW(zone_finder_.add(textToRRset(rrsig_ns_txt)),
  1420. InMemoryZoneFinder::AddError);
  1421. }
  1422. TEST_F(InMemoryZoneFinderTest, addbadRRsig) {
  1423. // Tests with other types of bogus input
  1424. // Empty RRSIG RRset.
  1425. EXPECT_THROW(zone_finder_.add(RRsetPtr(new RRset(origin_, class_,
  1426. RRType::RRSIG(),
  1427. RRTTL(300)))),
  1428. InMemoryZoneFinder::AddError);
  1429. // RRSIG with mixed covered types
  1430. zone_finder_.add(rr_a_); // make sure the covered name exists
  1431. // textToRRset() doesn't work as intended for this pathological case,
  1432. // so we need to construct the RRset by hand.
  1433. RRsetPtr rrset(new RRset(origin_, class_, RRType::RRSIG(), RRTTL(300)));
  1434. rrset->addRdata(generic::RRSIG("A 5 3 3600 20000101000000 20000201000000 "
  1435. "12345 example.org. FAKEFAKEFAKE"));
  1436. rrset->addRdata(generic::RRSIG("NS 5 3 3600 20000101000000 20000201000000 "
  1437. "54321 example.org. FAKEFAKEFAKEFAKE"));
  1438. EXPECT_THROW(zone_finder_.add(rrset), InMemoryZoneFinder::AddError);
  1439. // An attempt of overriding an existing RRSIG. The current implementation
  1440. // prohibits that.
  1441. zone_finder_.add(textToRRset(rrsig_a_txt));
  1442. EXPECT_THROW(zone_finder_.add(textToRRset(rrsig_a_txt)),
  1443. InMemoryZoneFinder::AddError);
  1444. }
  1445. //
  1446. // (Faked) NSEC3 hash data. Arbitrarily borrowed from RFC515 examples.
  1447. //
  1448. // Commonly used NSEC3 suffix. It's incorrect to use it for all NSEC3s, but
  1449. // doesn't matter for the purpose of our tests.
  1450. const char* const nsec3_common = " 300 IN NSEC3 1 1 12 aabbccdd "
  1451. "2T7B4G4VSA5SMI47K61MV5BV1A22BOJR A RRSIG";
  1452. // Likewise, common RRSIG suffix for NSEC3s.
  1453. const char* const nsec3_rrsig_common = " 300 IN RRSIG NSEC3 5 3 3600 "
  1454. "20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE";
  1455. void
  1456. findNSEC3Check(bool expected_matched, uint8_t expected_labels,
  1457. const string& expected_closest,
  1458. const string& expected_next,
  1459. const ZoneFinder::FindNSEC3Result& result,
  1460. bool expected_sig = false)
  1461. {
  1462. EXPECT_EQ(expected_matched, result.matched);
  1463. // Convert to int so the error messages would be more readable:
  1464. EXPECT_EQ(static_cast<int>(expected_labels),
  1465. static_cast<int>(result.closest_labels));
  1466. vector<ConstRRsetPtr> actual_rrsets;
  1467. ASSERT_TRUE(result.closest_proof);
  1468. actual_rrsets.push_back(result.closest_proof);
  1469. if (expected_sig) {
  1470. actual_rrsets.push_back(result.closest_proof->getRRsig());
  1471. }
  1472. rrsetsCheck(expected_closest, actual_rrsets.begin(),
  1473. actual_rrsets.end());
  1474. actual_rrsets.clear();
  1475. if (expected_next.empty()) {
  1476. EXPECT_FALSE(result.next_proof);
  1477. } else {
  1478. ASSERT_TRUE(result.next_proof);
  1479. actual_rrsets.push_back(result.next_proof);
  1480. if (expected_sig) {
  1481. actual_rrsets.push_back(result.next_proof->getRRsig());
  1482. }
  1483. rrsetsCheck(expected_next, actual_rrsets.begin(),
  1484. actual_rrsets.end());
  1485. }
  1486. }
  1487. TEST_F(InMemoryZoneFinderTest, addNSEC3) {
  1488. // Set up the faked hash calculator.
  1489. setNSEC3HashCreator(&nsec3_hash_creator_);
  1490. const string nsec3_text = string(apex_hash) + ".example.org." +
  1491. string(nsec3_common);
  1492. // This name shouldn't be found in the normal domain tree.
  1493. EXPECT_EQ(result::SUCCESS, zone_finder_.add(textToRRset(nsec3_text)));
  1494. EXPECT_EQ(ZoneFinder::NXDOMAIN,
  1495. zone_finder_.find(Name(string(apex_hash) + ".example.org"),
  1496. RRType::NSEC3()).code);
  1497. // Dedicated NSEC3 find should be able to find it.
  1498. findNSEC3Check(true, origin_.getLabelCount(), nsec3_text, "",
  1499. zone_finder_.findNSEC3(Name("example.org"), false));
  1500. // This implementation rejects duplicate/update add of the same hash name
  1501. EXPECT_EQ(result::EXIST,
  1502. zone_finder_.add(textToRRset(
  1503. string(apex_hash) + ".example.org." +
  1504. string(nsec3_common) + " AAAA")));
  1505. // The original NSEC3 should be intact
  1506. findNSEC3Check(true, origin_.getLabelCount(), nsec3_text, "",
  1507. zone_finder_.findNSEC3(Name("example.org"), false));
  1508. // NSEC3-like name but of ordinary RR type should go to normal tree.
  1509. const string nonsec3_text = string(apex_hash) + ".example.org. " +
  1510. "300 IN A 192.0.2.1";
  1511. EXPECT_EQ(result::SUCCESS, zone_finder_.add(textToRRset(nonsec3_text)));
  1512. EXPECT_EQ(ZoneFinder::SUCCESS,
  1513. zone_finder_.find(Name(string(apex_hash) + ".example.org"),
  1514. RRType::A()).code);
  1515. }
  1516. TEST_F(InMemoryZoneFinderTest, addNSEC3Lower) {
  1517. // Set up the faked hash calculator.
  1518. setNSEC3HashCreator(&nsec3_hash_creator_);
  1519. // Similar to the previous case, but NSEC3 owner name is lower-cased.
  1520. const string nsec3_text = string(apex_hash_lower) + ".example.org." +
  1521. string(nsec3_common);
  1522. EXPECT_EQ(result::SUCCESS, zone_finder_.add(textToRRset(nsec3_text)));
  1523. findNSEC3Check(true, origin_.getLabelCount(), nsec3_text, "",
  1524. zone_finder_.findNSEC3(Name("example.org"), false));
  1525. }
  1526. TEST_F(InMemoryZoneFinderTest, addNSEC3Ordering) {
  1527. // Set up the faked hash calculator.
  1528. setNSEC3HashCreator(&nsec3_hash_creator_);
  1529. // Check that the internal storage ensures comparison based on the NSEC3
  1530. // semantics, regardless of the add order or the letter-case of hash.
  1531. // Adding "0P..", "2v..", then "2T..".
  1532. const string smallest = string(apex_hash) + ".example.org." +
  1533. string(nsec3_common);
  1534. const string middle = string(ns1_hash) + ".example.org." +
  1535. string(nsec3_common);
  1536. const string largest = string(xyw_hash) + ".example.org." +
  1537. string(nsec3_common);
  1538. zone_finder_.add(textToRRset(smallest));
  1539. zone_finder_.add(textToRRset(largest));
  1540. zone_finder_.add(textToRRset(middle));
  1541. // Then look for NSEC3 that covers a name whose hash is "2S.."
  1542. // The covering NSEC3 should be "0P.."
  1543. findNSEC3Check(false, 4, smallest, "",
  1544. zone_finder_.findNSEC3(Name("www.example.org"), false));
  1545. // Look for NSEC3 that covers names whose hash are "Q0.." and "0A.."
  1546. // The covering NSEC3 should be "2v.." in both cases
  1547. findNSEC3Check(false, 4, largest, "",
  1548. zone_finder_.findNSEC3(Name("xxx.example.org"), false));
  1549. findNSEC3Check(false, 4, largest, "",
  1550. zone_finder_.findNSEC3(Name("yyy.example.org"), false));
  1551. }
  1552. TEST_F(InMemoryZoneFinderTest, badNSEC3Name) {
  1553. // Our implementation refuses to load NSEC3 at a wildcard name
  1554. EXPECT_THROW(zone_finder_.add(textToRRset("*.example.org." +
  1555. string(nsec3_common))),
  1556. InMemoryZoneFinder::AddError);
  1557. // Likewise, if the owner name of NSEC3 has too many labels, it's refused.
  1558. EXPECT_THROW(zone_finder_.add(textToRRset("a." + string(apex_hash) +
  1559. ".example.org." +
  1560. string(nsec3_common))),
  1561. InMemoryZoneFinder::AddError);
  1562. }
  1563. TEST_F(InMemoryZoneFinderTest, addMultiNSEC3) {
  1564. // In this current implementation multiple NSEC3 RDATA isn't supported.
  1565. RRsetPtr nsec3(new RRset(Name(string(apex_hash) + ".example.org"),
  1566. RRClass::IN(), RRType::NSEC3(), RRTTL(300)));
  1567. nsec3->addRdata(
  1568. generic::NSEC3("1 0 12 aabbccdd 2T7B4G4VSA5SMI47K61MV5BV1A22BOJR A"));
  1569. nsec3->addRdata(
  1570. generic::NSEC3("1 1 1 ddccbbaa 2T7B4G4VSA5SMI47K61MV5BV1A22BOJR A"));
  1571. EXPECT_THROW(zone_finder_.add(nsec3), InMemoryZoneFinder::AddError);
  1572. }
  1573. TEST_F(InMemoryZoneFinderTest, addNSEC3WithRRSIG) {
  1574. // Set up the faked hash calculator.
  1575. setNSEC3HashCreator(&nsec3_hash_creator_);
  1576. // Adding NSEC3 and its RRSIG
  1577. const string nsec3_text = string(apex_hash) + ".example.org." +
  1578. string(nsec3_common);
  1579. EXPECT_EQ(result::SUCCESS, zone_finder_.add(textToRRset(nsec3_text)));
  1580. const string nsec3_rrsig_text = string(apex_hash) + ".example.org." +
  1581. string(nsec3_rrsig_common);
  1582. EXPECT_EQ(result::SUCCESS, zone_finder_.add(textToRRset(nsec3_rrsig_text)));
  1583. // Then look for it. The NSEC3 should have the RRSIG that was just added.
  1584. findNSEC3Check(true, origin_.getLabelCount(),
  1585. nsec3_text + "\n" + nsec3_rrsig_text, "",
  1586. zone_finder_.findNSEC3(Name("example.org"), false), true);
  1587. // Duplicate add of RRSIG for the same NSEC3 is prohibited.
  1588. EXPECT_THROW(zone_finder_.add(textToRRset(nsec3_rrsig_text)),
  1589. InMemoryZoneFinder::AddError);
  1590. // Same check using the lower-cased name. This also confirms matching
  1591. // is case-insensitive.
  1592. EXPECT_THROW(zone_finder_.add(textToRRset(string(apex_hash_lower) +
  1593. ".example.org."
  1594. + string(nsec3_rrsig_common))),
  1595. InMemoryZoneFinder::AddError);
  1596. }
  1597. TEST_F(InMemoryZoneFinderTest, badRRsigForNSEC3) {
  1598. // adding RRSIG for NSEC3 even before adding any NSEC3 (internally,
  1599. // a space for NSEC3 namespace isn't yet allocated)
  1600. EXPECT_THROW(zone_finder_.add(textToRRset(string(apex_hash) +
  1601. ".example.org." +
  1602. string(nsec3_rrsig_common))),
  1603. InMemoryZoneFinder::AddError);
  1604. // Add an NSEC3
  1605. EXPECT_EQ(result::SUCCESS, zone_finder_.add(
  1606. textToRRset(string(apex_hash) + ".example.org." +
  1607. string(nsec3_common))));
  1608. // Then add an NSEC3 for a non existent NSEC3. It should fail in the
  1609. // current implementation.
  1610. EXPECT_THROW(zone_finder_.add(textToRRset(string(ns1_hash) +
  1611. ".example.org." +
  1612. string(nsec3_rrsig_common))),
  1613. InMemoryZoneFinder::AddError);
  1614. }
  1615. TEST_F(InMemoryZoneFinderTest, paramConsistencyWithNSEC3PARAM) {
  1616. // First, add an NSEC3PARAM RR
  1617. EXPECT_EQ(result::SUCCESS,
  1618. zone_finder_.add(textToRRset("example.org. 300 IN NSEC3PARAM "
  1619. "1 0 12 aabbccdd")));
  1620. // Adding an NSEC3 that has matching parameters is okay.
  1621. EXPECT_EQ(result::SUCCESS, zone_finder_.add(
  1622. textToRRset(string(apex_hash) + ".example.org." +
  1623. string(nsec3_common))));
  1624. // NSEC3 with inconsistent parameter will be rejected
  1625. EXPECT_THROW(zone_finder_.add(
  1626. textToRRset("a.example.org. 300 IN NSEC3 1 0 1 aabbccdd "
  1627. "2T7B4G4VSA5SMI47K61MV5BV1A22BOJR A RRSIG")),
  1628. InMemoryZoneFinder::AddError);
  1629. }
  1630. TEST_F(InMemoryZoneFinderTest, paramConsistencyWithNSEC3) {
  1631. // Add an NSEC3 without adding NSEC3PARAM
  1632. EXPECT_EQ(result::SUCCESS, zone_finder_.add(
  1633. textToRRset(string(apex_hash) + ".example.org." +
  1634. string(nsec3_common))));
  1635. // Adding an NSEC3 with inconsistent parameter will be rejected at this pt.
  1636. EXPECT_THROW(zone_finder_.add(
  1637. textToRRset("a.example.org. 300 IN NSEC3 1 0 1 aabbccdd "
  1638. "2T7B4G4VSA5SMI47K61MV5BV1A22BOJR A RRSIG")),
  1639. InMemoryZoneFinder::AddError);
  1640. // Likewise, NSEC3PARAM with inconsistent parameter will be rejected.
  1641. EXPECT_THROW(zone_finder_.add(textToRRset("example.org. 300 IN NSEC3PARAM "
  1642. "1 0 1 aabbccdd")),
  1643. InMemoryZoneFinder::AddError);
  1644. }
  1645. TEST_F(InMemoryZoneFinderTest, multiNSEC3PARAM) {
  1646. // In this current implementation multiple NSEC3PARAM isn't supported.
  1647. RRsetPtr nsec3param(new RRset(Name("example.org"), RRClass::IN(),
  1648. RRType::NSEC3PARAM(), RRTTL(300)));
  1649. nsec3param->addRdata(generic::NSEC3PARAM("1 0 12 aabbccdd"));
  1650. nsec3param->addRdata(generic::NSEC3PARAM("1 1 1 ddccbbaa"));
  1651. EXPECT_THROW(zone_finder_.add(nsec3param), InMemoryZoneFinder::AddError);
  1652. }
  1653. TEST_F(InMemoryZoneFinderTest, nonOriginNSEC3PARAM) {
  1654. // This is a normal NSEC3PARAM at the zone origin
  1655. EXPECT_EQ(result::SUCCESS,
  1656. zone_finder_.add(textToRRset("example.org. 300 IN NSEC3PARAM "
  1657. "1 0 12 aabbccdd")));
  1658. // Add another (with different param) at a non origin node. This is
  1659. // awkward, but the implementation accepts it as an ordinary RR.
  1660. EXPECT_EQ(result::SUCCESS,
  1661. zone_finder_.add(textToRRset("a.example.org. 300 IN NSEC3PARAM "
  1662. "1 1 1 aabbccdd")));
  1663. }
  1664. TEST_F(InMemoryZoneFinderTest, loadNSEC3Zone) {
  1665. // Check if it can load validly NSEC3-signed zone. At this moment
  1666. // it's sufficient to see it doesn't crash
  1667. zone_finder_.load(TEST_DATA_DIR "/example.org.nsec3-signed");
  1668. // Reload the zone with a version that doesn't have NSEC3PARAM.
  1669. // This is an abnormal case, but the implementation accepts it.
  1670. zone_finder_.load(TEST_DATA_DIR "/example.org.nsec3-signed-noparam");
  1671. }
  1672. // This test checks that the NSEC3 names don't really exist in the real
  1673. // namespace.
  1674. TEST_F(InMemoryZoneFinderTest, queryToNSEC3Name) {
  1675. // Add the NSEC3 and NSEC3PARAM there.
  1676. EXPECT_EQ(result::SUCCESS,
  1677. zone_finder_.add(textToRRset("example.org. 300 IN NSEC3PARAM "
  1678. "1 0 12 aabbccdd")));
  1679. const Name nsec3domain(string(apex_hash) + ".example.org.");
  1680. // Adding an NSEC3 that has matching parameters is okay.
  1681. EXPECT_EQ(result::SUCCESS, zone_finder_.add(
  1682. textToRRset(string(apex_hash) + ".example.org." +
  1683. string(nsec3_common))));
  1684. // Now, the domain should not exist
  1685. findTest(nsec3domain, RRType::AAAA(), ZoneFinder::NXDOMAIN, false,
  1686. ConstRRsetPtr(), ZoneFinder::RESULT_NSEC3_SIGNED, &zone_finder_,
  1687. ZoneFinder::FIND_DNSSEC);
  1688. // If we add an A record, the domain should exist
  1689. ConstRRsetPtr rrset(textToRRset(string(apex_hash) +
  1690. ".example.org. 300 IN A 192.0.2.1"));
  1691. EXPECT_EQ(result::SUCCESS, zone_finder_.add(rrset));
  1692. // Searching for a different RRType will tell us this RRset doesn't exist
  1693. findTest(nsec3domain, RRType::AAAA(), ZoneFinder::NXRRSET, false,
  1694. ConstRRsetPtr(), ZoneFinder::RESULT_NSEC3_SIGNED, &zone_finder_,
  1695. ZoneFinder::FIND_DNSSEC);
  1696. // Searching for the A record would find it
  1697. findTest(nsec3domain, RRType::A(), ZoneFinder::SUCCESS, true,
  1698. rrset, ZoneFinder::RESULT_DEFAULT, &zone_finder_,
  1699. ZoneFinder::FIND_DNSSEC);
  1700. }
  1701. // Continuation of the previous test (queryToNSEC3Name), we check we don't break
  1702. // the empty nonterminal case by existence of NSEC3 record with that name.
  1703. TEST_F(InMemoryZoneFinderTest, queryToNSEC3NameNonterminal) {
  1704. // Add the NSEC3 and NSEC3PARAM there.
  1705. EXPECT_EQ(result::SUCCESS,
  1706. zone_finder_.add(textToRRset("example.org. 300 IN NSEC3PARAM "
  1707. "1 0 12 aabbccdd")));
  1708. const Name nsec3domain(string(apex_hash) + ".example.org.");
  1709. // Adding an NSEC3 that has matching parameters is okay.
  1710. EXPECT_EQ(result::SUCCESS, zone_finder_.add(
  1711. textToRRset(string(apex_hash) + ".example.org." +
  1712. string(nsec3_common))));
  1713. // Something below the name
  1714. ConstRRsetPtr rrset(textToRRset("below." + string(apex_hash) +
  1715. ".example.org. 300 IN A 192.0.2.1"));
  1716. EXPECT_EQ(result::SUCCESS, zone_finder_.add(rrset));
  1717. // Now, the node is empty non-terminal.
  1718. findTest(nsec3domain, RRType::AAAA(), ZoneFinder::NXRRSET, false,
  1719. ConstRRsetPtr(), ZoneFinder::RESULT_NSEC3_SIGNED, &zone_finder_,
  1720. ZoneFinder::FIND_DNSSEC);
  1721. }
  1722. TEST_F(InMemoryZoneFinderTest, findNSEC3) {
  1723. // Set up the faked hash calculator.
  1724. setNSEC3HashCreator(&nsec3_hash_creator_);
  1725. // Add a few NSEC3 records:
  1726. // apex (example.org.): hash=0P..
  1727. // ns1.example.org: hash=2T..
  1728. // w.example.org: hash=01..
  1729. // zzz.example.org: hash=R5..
  1730. const string apex_nsec3_text = string(apex_hash) + ".example.org." +
  1731. string(nsec3_common);
  1732. EXPECT_EQ(result::SUCCESS, zone_finder_.add(textToRRset(apex_nsec3_text)));
  1733. const string ns1_nsec3_text = string(ns1_hash) + ".example.org." +
  1734. string(nsec3_common);
  1735. EXPECT_EQ(result::SUCCESS, zone_finder_.add(textToRRset(ns1_nsec3_text)));
  1736. const string w_nsec3_text = string(w_hash) + ".example.org." +
  1737. string(nsec3_common);
  1738. EXPECT_EQ(result::SUCCESS, zone_finder_.add(textToRRset(w_nsec3_text)));
  1739. const string zzz_nsec3_text = string(zzz_hash) + ".example.org." +
  1740. string(nsec3_common);
  1741. EXPECT_EQ(result::SUCCESS, zone_finder_.add(textToRRset(zzz_nsec3_text)));
  1742. // Parameter validation: the query name must be in or below the zone
  1743. EXPECT_THROW(zone_finder_.findNSEC3(Name("example.com"), false),
  1744. isc::InvalidParameter);
  1745. EXPECT_THROW(zone_finder_.findNSEC3(Name("org"), true),
  1746. isc::InvalidParameter);
  1747. // Apex name. It should have a matching NSEC3.
  1748. {
  1749. SCOPED_TRACE("apex, non recursive mode");
  1750. findNSEC3Check(true, origin_.getLabelCount(), apex_nsec3_text, "",
  1751. zone_finder_.findNSEC3(origin_, false));
  1752. }
  1753. // Recursive mode doesn't change the result in this case.
  1754. {
  1755. SCOPED_TRACE("apex, recursive mode");
  1756. findNSEC3Check(true, origin_.getLabelCount(), apex_nsec3_text, "",
  1757. zone_finder_.findNSEC3(origin_, true));
  1758. }
  1759. // Non existent name. Disabling recursion, a covering NSEC3 should be
  1760. // returned.
  1761. const Name www_name("www.example.org");
  1762. {
  1763. SCOPED_TRACE("non existent name, non recursive mode");
  1764. findNSEC3Check(false, www_name.getLabelCount(), apex_nsec3_text, "",
  1765. zone_finder_.findNSEC3(www_name, false));
  1766. }
  1767. // Non existent name. The closest provable encloser is the apex,
  1768. // and next closer is the query name itself (which NSEC3 for ns1
  1769. // covers)
  1770. // H(ns1) = 2T... < H(xxx) = Q0... < H(zzz) = R5...
  1771. {
  1772. SCOPED_TRACE("non existent name, recursive mode");
  1773. findNSEC3Check(true, origin_.getLabelCount(), apex_nsec3_text,
  1774. ns1_nsec3_text,
  1775. zone_finder_.findNSEC3(Name("xxx.example.org"), true));
  1776. }
  1777. // Similar to the previous case, but next closer name is different
  1778. // from the query name. The closet encloser is w.example.org, and
  1779. // next closer is y.w.example.org.
  1780. // H(ns1) = 2T.. < H(y.w) = K8.. < H(zzz) = R5
  1781. {
  1782. SCOPED_TRACE("non existent name, non qname next closer");
  1783. findNSEC3Check(true, Name("w.example.org").getLabelCount(),
  1784. w_nsec3_text, ns1_nsec3_text,
  1785. zone_finder_.findNSEC3(Name("x.y.w.example.org"),
  1786. true));
  1787. }
  1788. // In the rest of test we check hash comparison for wrap around cases.
  1789. {
  1790. SCOPED_TRACE("very small hash");
  1791. const Name smallest_name("smallest.example.org");
  1792. findNSEC3Check(false, smallest_name.getLabelCount(),
  1793. zzz_nsec3_text, "",
  1794. zone_finder_.findNSEC3(smallest_name, false));
  1795. }
  1796. {
  1797. SCOPED_TRACE("very large hash");
  1798. const Name largest_name("largest.example.org");
  1799. findNSEC3Check(false, largest_name.getLabelCount(),
  1800. zzz_nsec3_text, "",
  1801. zone_finder_.findNSEC3(largest_name, false));
  1802. }
  1803. }
  1804. TEST_F(InMemoryZoneFinderTest, findNSEC3ForBadZone) {
  1805. // Set up the faked hash calculator.
  1806. setNSEC3HashCreator(&nsec3_hash_creator_);
  1807. // If the zone has nothing about NSEC3 (neither NSEC3 or NSEC3PARAM),
  1808. // findNSEC3() should be rejected.
  1809. EXPECT_THROW(zone_finder_.findNSEC3(Name("www.example.org"), true),
  1810. DataSourceError);
  1811. // Only having NSEC3PARAM isn't enough
  1812. EXPECT_EQ(result::SUCCESS,
  1813. zone_finder_.add(textToRRset("example.org. 300 IN NSEC3PARAM "
  1814. "1 0 12 aabbccdd")));
  1815. EXPECT_THROW(zone_finder_.findNSEC3(Name("www.example.org"), true),
  1816. DataSourceError);
  1817. // Unless NSEC3 for apex is added the result in the recursive mode
  1818. // is guaranteed.
  1819. const string ns1_nsec3_text = string(ns1_hash) + ".example.org." +
  1820. string(nsec3_common);
  1821. EXPECT_EQ(result::SUCCESS, zone_finder_.add(textToRRset(ns1_nsec3_text)));
  1822. EXPECT_THROW(zone_finder_.findNSEC3(Name("www.example.org"), true),
  1823. DataSourceError);
  1824. }
  1825. TEST_F(InMemoryZoneFinderTest, loadAndFindNSEC3) {
  1826. // Using more realistic example, borrowed from RFC5155, with compliant
  1827. // hash calculator. We only confirm the data source can load it
  1828. // successfully and find correct NSEC3 RRs for some selected cases
  1829. // (detailed tests have been done above).
  1830. InMemoryZoneFinder finder(class_, Name("example"));
  1831. finder.load(TEST_DATA_COMMONDIR "/rfc5155-example.zone.signed");
  1832. // See RFC5155 B.1
  1833. ZoneFinder::FindNSEC3Result result1 =
  1834. finder.findNSEC3(Name("c.x.w.example"), true);
  1835. ASSERT_TRUE(result1.closest_proof);
  1836. // We compare closest_labels as int so the error report will be more
  1837. // readable in case it fails.
  1838. EXPECT_EQ(4, static_cast<int>(result1.closest_labels));
  1839. EXPECT_EQ(Name("b4um86eghhds6nea196smvmlo4ors995.example"),
  1840. result1.closest_proof->getName());
  1841. ASSERT_TRUE(result1.next_proof);
  1842. EXPECT_EQ(Name("0p9mhaveqvm6t7vbl5lop2u3t2rp3tom.example"),
  1843. result1.next_proof->getName());
  1844. // See RFC5155 B.2.
  1845. ZoneFinder::FindNSEC3Result result2 =
  1846. finder.findNSEC3(Name("ns1.example"), true);
  1847. ASSERT_TRUE(result2.closest_proof);
  1848. EXPECT_EQ(3, static_cast<int>(result2.closest_labels));
  1849. EXPECT_EQ(Name("2t7b4g4vsa5smi47k61mv5bv1a22bojr.example"),
  1850. result2.closest_proof->getName());
  1851. ASSERT_FALSE(result2.next_proof);
  1852. // See RFC5155 B.5.
  1853. ZoneFinder::FindNSEC3Result result3 =
  1854. finder.findNSEC3(Name("a.z.w.example"), true);
  1855. ASSERT_TRUE(result3.closest_proof);
  1856. EXPECT_EQ(3, static_cast<int>(result3.closest_labels));
  1857. EXPECT_EQ(Name("k8udemvp1j2f7eg6jebps17vp3n8i58h.example"),
  1858. result3.closest_proof->getName());
  1859. ASSERT_TRUE(result3.next_proof);
  1860. EXPECT_EQ(Name("q04jkcevqvmu85r014c7dkba38o0ji5r.example"),
  1861. result3.next_proof->getName());
  1862. }
  1863. }