memory_datasrc_unittest.cc 89 KB

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