memory_datasrc_unittest.cc 92 KB

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