memory_datasrc_unittest.cc 67 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598
  1. // Copyright (C) 2010 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // Permission to use, copy, modify, and/or distribute this software for any
  4. // purpose with or without fee is hereby granted, provided that the above
  5. // copyright notice and this permission notice appear in all copies.
  6. //
  7. // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
  8. // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  9. // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
  10. // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  11. // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  12. // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  13. // PERFORMANCE OF THIS SOFTWARE.
  14. #include <sstream>
  15. #include <vector>
  16. #include <boost/bind.hpp>
  17. #include <boost/foreach.hpp>
  18. #include <exceptions/exceptions.h>
  19. #include <dns/masterload.h>
  20. #include <dns/name.h>
  21. #include <dns/rdata.h>
  22. #include <dns/rdataclass.h>
  23. #include <dns/rrclass.h>
  24. #include <dns/rrsetlist.h>
  25. #include <dns/rrttl.h>
  26. #include <dns/masterload.h>
  27. #include <datasrc/memory_datasrc.h>
  28. #include <datasrc/data_source.h>
  29. #include <datasrc/iterator.h>
  30. #include <testutils/dnsmessage_test.h>
  31. #include <gtest/gtest.h>
  32. using namespace std;
  33. using namespace isc::dns;
  34. using namespace isc::dns::rdata;
  35. using namespace isc::datasrc;
  36. using namespace isc::testutils;
  37. namespace {
  38. // Commonly used result codes (Who should write the prefix all the time)
  39. using result::SUCCESS;
  40. using result::EXIST;
  41. class InMemoryClientTest : public ::testing::Test {
  42. protected:
  43. InMemoryClientTest() : rrclass(RRClass::IN())
  44. {}
  45. RRClass rrclass;
  46. InMemoryClient memory_client;
  47. };
  48. TEST_F(InMemoryClientTest, add_find_Zone) {
  49. // test add zone
  50. // Bogus zone (NULL)
  51. EXPECT_THROW(memory_client.addZone(ZoneFinderPtr()),
  52. isc::InvalidParameter);
  53. // add zones with different names one by one
  54. EXPECT_EQ(result::SUCCESS, memory_client.addZone(
  55. ZoneFinderPtr(new InMemoryZoneFinder(RRClass::IN(),
  56. Name("a")))));
  57. EXPECT_EQ(result::SUCCESS, memory_client.addZone(
  58. ZoneFinderPtr(new InMemoryZoneFinder(RRClass::CH(),
  59. Name("b")))));
  60. EXPECT_EQ(result::SUCCESS, memory_client.addZone(
  61. ZoneFinderPtr(new InMemoryZoneFinder(RRClass::IN(),
  62. Name("c")))));
  63. // add zones with the same name suffix
  64. EXPECT_EQ(result::SUCCESS, memory_client.addZone(
  65. ZoneFinderPtr(new InMemoryZoneFinder(RRClass::CH(),
  66. Name("x.d.e.f")))));
  67. EXPECT_EQ(result::SUCCESS, memory_client.addZone(
  68. ZoneFinderPtr(new InMemoryZoneFinder(RRClass::CH(),
  69. Name("o.w.y.d.e.f")))));
  70. EXPECT_EQ(result::SUCCESS, memory_client.addZone(
  71. ZoneFinderPtr(new InMemoryZoneFinder(RRClass::CH(),
  72. Name("p.w.y.d.e.f")))));
  73. EXPECT_EQ(result::SUCCESS, memory_client.addZone(
  74. ZoneFinderPtr(new InMemoryZoneFinder(RRClass::IN(),
  75. Name("q.w.y.d.e.f")))));
  76. // add super zone and its subzone
  77. EXPECT_EQ(result::SUCCESS, memory_client.addZone(
  78. ZoneFinderPtr(new InMemoryZoneFinder(RRClass::CH(),
  79. Name("g.h")))));
  80. EXPECT_EQ(result::SUCCESS, memory_client.addZone(
  81. ZoneFinderPtr(new InMemoryZoneFinder(RRClass::IN(),
  82. Name("i.g.h")))));
  83. EXPECT_EQ(result::SUCCESS, memory_client.addZone(
  84. ZoneFinderPtr(new InMemoryZoneFinder(RRClass::IN(),
  85. Name("z.d.e.f")))));
  86. EXPECT_EQ(result::SUCCESS, memory_client.addZone(
  87. ZoneFinderPtr(new InMemoryZoneFinder(RRClass::IN(),
  88. Name("j.z.d.e.f")))));
  89. // different zone class isn't allowed.
  90. EXPECT_EQ(result::EXIST, memory_client.addZone(
  91. ZoneFinderPtr(new InMemoryZoneFinder(RRClass::CH(),
  92. Name("q.w.y.d.e.f")))));
  93. // names are compared in a case insensitive manner.
  94. EXPECT_EQ(result::EXIST, memory_client.addZone(
  95. ZoneFinderPtr(new InMemoryZoneFinder(RRClass::IN(),
  96. Name("Q.W.Y.d.E.f")))));
  97. // test find zone
  98. EXPECT_EQ(result::SUCCESS, memory_client.findZone(Name("a")).code);
  99. EXPECT_EQ(Name("a"),
  100. memory_client.findZone(Name("a")).zone_finder->getOrigin());
  101. EXPECT_EQ(result::SUCCESS,
  102. memory_client.findZone(Name("j.z.d.e.f")).code);
  103. EXPECT_EQ(Name("j.z.d.e.f"),
  104. memory_client.findZone(Name("j.z.d.e.f")).zone_finder->
  105. getOrigin());
  106. // NOTFOUND
  107. EXPECT_EQ(result::NOTFOUND, memory_client.findZone(Name("d.e.f")).code);
  108. EXPECT_EQ(ConstZoneFinderPtr(),
  109. memory_client.findZone(Name("d.e.f")).zone_finder);
  110. EXPECT_EQ(result::NOTFOUND,
  111. memory_client.findZone(Name("w.y.d.e.f")).code);
  112. EXPECT_EQ(ConstZoneFinderPtr(),
  113. memory_client.findZone(Name("w.y.d.e.f")).zone_finder);
  114. // there's no exact match. the result should be the longest match,
  115. // and the code should be PARTIALMATCH.
  116. EXPECT_EQ(result::PARTIALMATCH,
  117. memory_client.findZone(Name("j.g.h")).code);
  118. EXPECT_EQ(Name("g.h"),
  119. memory_client.findZone(Name("g.h")).zone_finder->getOrigin());
  120. EXPECT_EQ(result::PARTIALMATCH,
  121. memory_client.findZone(Name("z.i.g.h")).code);
  122. EXPECT_EQ(Name("i.g.h"),
  123. memory_client.findZone(Name("z.i.g.h")).zone_finder->
  124. getOrigin());
  125. }
  126. TEST_F(InMemoryClientTest, iterator) {
  127. // Just some preparations of data
  128. boost::shared_ptr<InMemoryZoneFinder>
  129. zone(new InMemoryZoneFinder(RRClass::IN(), Name("a")));
  130. RRsetPtr aRRsetA(new RRset(Name("a"), RRClass::IN(), RRType::A(),
  131. RRTTL(300)));
  132. aRRsetA->addRdata(rdata::in::A("192.0.2.1"));
  133. RRsetPtr aRRsetAAAA(new RRset(Name("a"), RRClass::IN(), RRType::AAAA(),
  134. RRTTL(300)));
  135. aRRsetAAAA->addRdata(rdata::in::AAAA("2001:db8::1"));
  136. aRRsetAAAA->addRdata(rdata::in::AAAA("2001:db8::2"));
  137. RRsetPtr subRRsetA(new RRset(Name("sub.x.a"), RRClass::IN(), RRType::A(),
  138. RRTTL(300)));
  139. subRRsetA->addRdata(rdata::in::A("192.0.2.2"));
  140. EXPECT_EQ(result::SUCCESS, memory_client.addZone(zone));
  141. // First, the zone is not there, so it should throw
  142. EXPECT_THROW(memory_client.getIterator(Name("b")), DataSourceError);
  143. // This zone is not there either, even when there's a zone containing this
  144. EXPECT_THROW(memory_client.getIterator(Name("x.a")), DataSourceError);
  145. // Now, an empty zone
  146. ZoneIteratorPtr iterator(memory_client.getIterator(Name("a")));
  147. EXPECT_EQ(ConstRRsetPtr(), iterator->getNextRRset());
  148. // It throws Unexpected when we are past the end
  149. EXPECT_THROW(iterator->getNextRRset(), isc::Unexpected);
  150. EXPECT_EQ(result::SUCCESS, zone->add(aRRsetA));
  151. EXPECT_EQ(result::SUCCESS, zone->add(aRRsetAAAA));
  152. EXPECT_EQ(result::SUCCESS, zone->add(subRRsetA));
  153. // Check it with full zone, one by one.
  154. // It should be in ascending order in case of InMemory data source
  155. // (isn't guaranteed in general)
  156. iterator = memory_client.getIterator(Name("a"));
  157. EXPECT_EQ(aRRsetA, iterator->getNextRRset());
  158. EXPECT_EQ(aRRsetAAAA, iterator->getNextRRset());
  159. EXPECT_EQ(subRRsetA, iterator->getNextRRset());
  160. EXPECT_EQ(ConstRRsetPtr(), iterator->getNextRRset());
  161. }
  162. TEST_F(InMemoryClientTest, iterator_separate_rrs) {
  163. // Exactly the same tests as for iterator, but now with separate_rrs = true
  164. // For the one that returns actual data, the AAAA should now be split up
  165. boost::shared_ptr<InMemoryZoneFinder>
  166. zone(new InMemoryZoneFinder(RRClass::IN(), Name("a")));
  167. RRsetPtr aRRsetA(new RRset(Name("a"), RRClass::IN(), RRType::A(),
  168. RRTTL(300)));
  169. aRRsetA->addRdata(rdata::in::A("192.0.2.1"));
  170. RRsetPtr aRRsetAAAA(new RRset(Name("a"), RRClass::IN(), RRType::AAAA(),
  171. RRTTL(300)));
  172. aRRsetAAAA->addRdata(rdata::in::AAAA("2001:db8::1"));
  173. aRRsetAAAA->addRdata(rdata::in::AAAA("2001:db8::2"));
  174. RRsetPtr aRRsetAAAA_r1(new RRset(Name("a"), RRClass::IN(), RRType::AAAA(),
  175. RRTTL(300)));
  176. aRRsetAAAA_r1->addRdata(rdata::in::AAAA("2001:db8::1"));
  177. RRsetPtr aRRsetAAAA_r2(new RRset(Name("a"), RRClass::IN(), RRType::AAAA(),
  178. RRTTL(300)));
  179. aRRsetAAAA_r2->addRdata(rdata::in::AAAA("2001:db8::2"));
  180. RRsetPtr subRRsetA(new RRset(Name("sub.x.a"), RRClass::IN(), RRType::A(),
  181. RRTTL(300)));
  182. subRRsetA->addRdata(rdata::in::A("192.0.2.2"));
  183. EXPECT_EQ(result::SUCCESS, memory_client.addZone(zone));
  184. // First, the zone is not there, so it should throw
  185. EXPECT_THROW(memory_client.getIterator(Name("b"), true), DataSourceError);
  186. // This zone is not there either, even when there's a zone containing this
  187. EXPECT_THROW(memory_client.getIterator(Name("x.a")), DataSourceError);
  188. // Now, an empty zone
  189. ZoneIteratorPtr iterator(memory_client.getIterator(Name("a"), true));
  190. EXPECT_EQ(ConstRRsetPtr(), iterator->getNextRRset());
  191. // It throws Unexpected when we are past the end
  192. EXPECT_THROW(iterator->getNextRRset(), isc::Unexpected);
  193. ASSERT_EQ(result::SUCCESS, zone->add(aRRsetA));
  194. ASSERT_EQ(result::SUCCESS, zone->add(aRRsetAAAA));
  195. ASSERT_EQ(result::SUCCESS, zone->add(subRRsetA));
  196. // Check it with full zone, one by one.
  197. // It should be in ascending order in case of InMemory data source
  198. // (isn't guaranteed in general)
  199. iterator = memory_client.getIterator(Name("a"), true);
  200. EXPECT_EQ(aRRsetA->toText(), iterator->getNextRRset()->toText());
  201. EXPECT_EQ(aRRsetAAAA_r1->toText(), iterator->getNextRRset()->toText());
  202. EXPECT_EQ(aRRsetAAAA_r2->toText(), iterator->getNextRRset()->toText());
  203. EXPECT_EQ(subRRsetA->toText(), iterator->getNextRRset()->toText());
  204. EXPECT_EQ(ConstRRsetPtr(), iterator->getNextRRset());
  205. }
  206. TEST_F(InMemoryClientTest, getZoneCount) {
  207. EXPECT_EQ(0, memory_client.getZoneCount());
  208. memory_client.addZone(
  209. ZoneFinderPtr(new InMemoryZoneFinder(rrclass,
  210. Name("example.com"))));
  211. EXPECT_EQ(1, memory_client.getZoneCount());
  212. // duplicate add. counter shouldn't change
  213. memory_client.addZone(
  214. ZoneFinderPtr(new InMemoryZoneFinder(rrclass,
  215. Name("example.com"))));
  216. EXPECT_EQ(1, memory_client.getZoneCount());
  217. // add one more
  218. memory_client.addZone(
  219. ZoneFinderPtr(new InMemoryZoneFinder(rrclass,
  220. Name("example.org"))));
  221. EXPECT_EQ(2, memory_client.getZoneCount());
  222. }
  223. TEST_F(InMemoryClientTest, startUpdateZone) {
  224. EXPECT_THROW(memory_client.getUpdater(Name("example.org"), false),
  225. isc::NotImplemented);
  226. }
  227. // Commonly used RRSIG data
  228. const char* const rrsig_a_txt =
  229. "example.org. 300 IN RRSIG A 5 3 3600 20000101000000 20000201000000 12345 "
  230. "example.org. FAKEFAKEFAKE\n";
  231. const char* const rrsig_ns_txt =
  232. "example.org. 300 IN RRSIG NS 5 3 3600 20000101000000 20000201000000 "
  233. "54321 example.org. FAKEFAKEFAKEFAKE\n";
  234. // This RRset has two RRSIGs
  235. const char* const rrsig_aaaa_txt =
  236. "ns.example.org. 300 IN RRSIG AAAA 5 3 3600 20000101000000 20000201000000 "
  237. "12345 example.org. FAKEFAKEFAKE\n"
  238. "ns.example.org. 300 IN RRSIG AAAA 5 3 3600 20000101000000 20000201000000 "
  239. "54321 example.org. FAKEFAKEFAKEFAKE\n";
  240. // A helper callback of masterLoad() used in InMemoryZoneFinderTest.
  241. void
  242. setRRset(RRsetPtr rrset, vector<RRsetPtr*>::iterator& it) {
  243. *(*it) = rrset;
  244. ++it;
  245. }
  246. /// \brief Test fixture for the InMemoryZoneFinder class
  247. class InMemoryZoneFinderTest : public ::testing::Test {
  248. // A straightforward pair of textual RR(set) and a RRsetPtr variable
  249. // to store the RRset. Used to build test data below.
  250. struct RRsetData {
  251. const char* const text; // textual representation of an RRset
  252. RRsetPtr* rrset;
  253. };
  254. public:
  255. InMemoryZoneFinderTest() :
  256. class_(RRClass::IN()),
  257. origin_("example.org"),
  258. zone_finder_(class_, origin_)
  259. {
  260. // Build test RRsets. Below, we construct an RRset for
  261. // each textual RR(s) of zone_data, and assign it to the corresponding
  262. // rr_xxx.
  263. const RRsetData zone_data[] = {
  264. {"example.org. 300 IN NS ns.example.org.", &rr_ns_},
  265. {"example.org. 300 IN A 192.0.2.1", &rr_a_},
  266. {"ns.example.org. 300 IN A 192.0.2.2", &rr_ns_a_},
  267. {"ns.example.org. 300 IN AAAA 2001:db8::2", &rr_ns_aaaa_},
  268. {"cname.example.org. 300 IN CNAME canonical.example.org",
  269. &rr_cname_},
  270. {"cname.example.org. 300 IN A 192.0.2.3", &rr_cname_a_},
  271. {"dname.example.org. 300 IN DNAME target.example.org.",
  272. &rr_dname_},
  273. {"dname.example.org. 300 IN A 192.0.2.39", &rr_dname_a_},
  274. {"dname.example.org. 300 IN NS ns.dname.example.org.",
  275. &rr_dname_ns_},
  276. {"example.org. 300 IN DNAME example.com.", &rr_dname_apex_},
  277. {"child.example.org. 300 IN NS ns.child.example.org.",
  278. &rr_child_ns_},
  279. {"child.example.org. 300 IN DS 12345 5 1 DEADBEEF",
  280. &rr_child_ds_},
  281. {"ns.child.example.org. 300 IN A 192.0.2.153",
  282. &rr_child_glue_},
  283. {"grand.child.example.org. 300 IN NS ns.grand.child.example.org.",
  284. &rr_grandchild_ns_},
  285. {"ns.grand.child.example.org. 300 IN AAAA 2001:db8::253",
  286. &rr_grandchild_glue_},
  287. {"dname.child.example.org. 300 IN DNAME example.com.",
  288. &rr_child_dname_},
  289. {"example.com. 300 IN A 192.0.2.10", &rr_out_},
  290. {"*.wild.example.org. 300 IN A 192.0.2.1", &rr_wild_},
  291. {"*.cnamewild.example.org. 300 IN CNAME canonial.example.org.",
  292. &rr_cnamewild_},
  293. {"foo.wild.example.org. 300 IN A 192.0.2.3", &rr_under_wild_},
  294. {"wild.*.foo.example.org. 300 IN A 192.0.2.1", &rr_emptywild_},
  295. {"wild.*.foo.*.bar.example.org. 300 IN A 192.0.2.1",
  296. &rr_nested_emptywild_},
  297. {"*.nswild.example.org. 300 IN NS nswild.example.", &rr_nswild_},
  298. {"*.dnamewild.example.org. 300 IN DNAME dnamewild.example.",
  299. &rr_dnamewild_},
  300. {"*.child.example.org. 300 IN A 192.0.2.1", &rr_child_wild_},
  301. {"bar.foo.wild.example.org. 300 IN A 192.0.2.2", &rr_not_wild_},
  302. {"baz.foo.wild.example.org. 300 IN A 192.0.2.3",
  303. &rr_not_wild_another_},
  304. {NULL, NULL}
  305. };
  306. stringstream zone_data_stream;
  307. vector<RRsetPtr*> rrsets;
  308. for (unsigned int i = 0; zone_data[i].text != NULL; ++i) {
  309. zone_data_stream << zone_data[i].text << "\n";
  310. rrsets.push_back(zone_data[i].rrset);
  311. }
  312. masterLoad(zone_data_stream, Name::ROOT_NAME(), class_,
  313. boost::bind(setRRset, _1, rrsets.begin()));
  314. }
  315. // Some data to test with
  316. const RRClass class_;
  317. const Name origin_;
  318. // The zone finder to torture by tests
  319. InMemoryZoneFinder zone_finder_;
  320. // Placeholder for storing RRsets to be checked with rrsetsCheck()
  321. vector<ConstRRsetPtr> actual_rrsets_;
  322. /*
  323. * Some RRsets to put inside the zone.
  324. */
  325. RRsetPtr
  326. // Out of zone RRset
  327. rr_out_,
  328. // NS of example.org
  329. rr_ns_,
  330. // A of ns.example.org
  331. rr_ns_a_,
  332. // AAAA of ns.example.org
  333. rr_ns_aaaa_,
  334. // A of example.org
  335. rr_a_;
  336. RRsetPtr rr_cname_; // CNAME in example.org (RDATA will be added)
  337. RRsetPtr rr_cname_a_; // for mixed CNAME + A case
  338. RRsetPtr rr_dname_; // DNAME in example.org (RDATA will be added)
  339. RRsetPtr rr_dname_a_; // for mixed DNAME + A case
  340. RRsetPtr rr_dname_ns_; // for mixed DNAME + NS case
  341. RRsetPtr rr_dname_apex_; // for mixed DNAME + NS case in the apex
  342. RRsetPtr rr_child_ns_; // NS of a child domain (for delegation)
  343. RRsetPtr rr_child_ds_; // DS of a child domain (for delegation, auth data)
  344. RRsetPtr rr_child_glue_; // glue RR of the child domain
  345. RRsetPtr rr_grandchild_ns_; // NS below a zone cut (unusual)
  346. RRsetPtr rr_grandchild_glue_; // glue RR below a deeper zone cut
  347. RRsetPtr rr_child_dname_; // A DNAME under NS
  348. RRsetPtr rr_wild_; // Wildcard record
  349. RRsetPtr rr_cnamewild_; // CNAME at a wildcard
  350. RRsetPtr rr_emptywild_;
  351. RRsetPtr rr_nested_emptywild_;
  352. RRsetPtr rr_nswild_, rr_dnamewild_;
  353. RRsetPtr rr_child_wild_;
  354. RRsetPtr rr_under_wild_;
  355. RRsetPtr rr_not_wild_;
  356. RRsetPtr rr_not_wild_another_;
  357. /**
  358. * \brief Test one find query to the zone finder.
  359. *
  360. * Asks a query to the zone finder and checks it does not throw and returns
  361. * expected results. It returns nothing, it just signals failures
  362. * to GTEST.
  363. *
  364. * \param name The name to ask for.
  365. * \param rrtype The RRType to ask of.
  366. * \param result The expected code of the result.
  367. * \param check_answer Should a check against equality of the answer be
  368. * done?
  369. * \param answer The expected rrset, if any should be returned.
  370. * \param expected_flags The expected result flags returned via find().
  371. * These can be tested using isWildcard() etc.
  372. * \param zone_finder Check different InMemoryZoneFinder object than
  373. * zone_finder_ (if NULL, uses zone_finder_)
  374. * \param check_wild_answer Checks that the answer has the same RRs, type
  375. * class and TTL as the eqxpected answer and that the name corresponds
  376. * to the one searched. It is meant for checking answers for wildcard
  377. * queries.
  378. */
  379. void findTest(const Name& name, const RRType& rrtype,
  380. ZoneFinder::Result result,
  381. bool check_answer = true,
  382. const ConstRRsetPtr& answer = ConstRRsetPtr(),
  383. ZoneFinder::FindResultFlags expected_flags =
  384. ZoneFinder::RESULT_DEFAULT,
  385. InMemoryZoneFinder* zone_finder = NULL,
  386. ZoneFinder::FindOptions options = ZoneFinder::FIND_DEFAULT,
  387. bool check_wild_answer = false)
  388. {
  389. if (zone_finder == NULL) {
  390. zone_finder = &zone_finder_;
  391. }
  392. // The whole block is inside, because we need to check the result and
  393. // we can't assign to FindResult
  394. EXPECT_NO_THROW({
  395. ZoneFinder::FindResult find_result(zone_finder->find(
  396. name, rrtype, options));
  397. // Check it returns correct answers
  398. EXPECT_EQ(result, find_result.code);
  399. EXPECT_EQ((expected_flags & ZoneFinder::RESULT_WILDCARD) != 0,
  400. find_result.isWildcard());
  401. EXPECT_EQ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED)
  402. != 0, find_result.isNSECSigned());
  403. EXPECT_EQ((expected_flags & ZoneFinder::RESULT_NSEC3_SIGNED)
  404. != 0, find_result.isNSEC3Signed());
  405. if (check_answer) {
  406. if (!answer) {
  407. ASSERT_FALSE(find_result.rrset);
  408. } else {
  409. ASSERT_TRUE(find_result.rrset);
  410. rrsetCheck(answer, find_result.rrset);
  411. }
  412. } else if (check_wild_answer) {
  413. ASSERT_NE(ConstRRsetPtr(), answer) <<
  414. "Wrong test, don't check for wild names if you expect "
  415. "empty answer";
  416. ASSERT_NE(ConstRRsetPtr(), find_result.rrset) <<
  417. "No answer found";
  418. // Build the expected answer using the given name and
  419. // other parameter of the base wildcard RRset.
  420. RRsetPtr wildanswer(new RRset(name, answer->getClass(),
  421. answer->getType(),
  422. answer->getTTL()));
  423. RdataIteratorPtr expectedIt(answer->getRdataIterator());
  424. for (; !expectedIt->isLast(); expectedIt->next()) {
  425. wildanswer->addRdata(expectedIt->getCurrent());
  426. }
  427. rrsetCheck(wildanswer, find_result.rrset);
  428. }
  429. });
  430. }
  431. /**
  432. * \brief Calls the findAll on the finder and checks the result.
  433. */
  434. void findAllTest(const Name& name, ZoneFinder::Result result,
  435. const vector<ConstRRsetPtr>& expected_rrsets,
  436. ZoneFinder::FindResultFlags expected_flags =
  437. ZoneFinder::RESULT_DEFAULT,
  438. InMemoryZoneFinder* finder = NULL,
  439. const ConstRRsetPtr &rrset_result = ConstRRsetPtr(),
  440. ZoneFinder::FindOptions options =
  441. ZoneFinder::FIND_DEFAULT)
  442. {
  443. if (finder == NULL) {
  444. finder = &zone_finder_;
  445. }
  446. std::vector<ConstRRsetPtr> target;
  447. ZoneFinder::FindResult find_result(finder->findAll(name, target,
  448. options));
  449. EXPECT_EQ(result, find_result.code);
  450. if (!rrset_result) {
  451. EXPECT_FALSE(find_result.rrset);
  452. } else {
  453. ASSERT_TRUE(find_result.rrset);
  454. rrsetCheck(rrset_result, find_result.rrset);
  455. }
  456. EXPECT_EQ((expected_flags & ZoneFinder::RESULT_WILDCARD) != 0,
  457. find_result.isWildcard());
  458. EXPECT_EQ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED)
  459. != 0, find_result.isNSECSigned());
  460. EXPECT_EQ((expected_flags & ZoneFinder::RESULT_NSEC3_SIGNED)
  461. != 0, find_result.isNSEC3Signed());
  462. rrsetsCheck(expected_rrsets.begin(), expected_rrsets.end(),
  463. target.begin(), target.end());
  464. }
  465. // Internal part of the cancelWildcard test that is multiple times
  466. void doCancelWildcardTest();
  467. ConstRRsetPtr textToRRset(const string& text_rrset,
  468. const RRClass& rrclass = RRClass::IN()) const
  469. {
  470. stringstream ss(text_rrset);
  471. RRsetPtr rrset;
  472. vector<RRsetPtr*> rrsets;
  473. rrsets.push_back(&rrset);
  474. masterLoad(ss, Name::ROOT_NAME(), rrclass,
  475. boost::bind(setRRset, _1, rrsets.begin()));
  476. return (rrset);
  477. }
  478. };
  479. /**
  480. * \brief Check that findPreviousName throws as it should now.
  481. */
  482. TEST_F(InMemoryZoneFinderTest, findPreviousName) {
  483. EXPECT_THROW(zone_finder_.findPreviousName(Name("www.example.org")),
  484. isc::NotImplemented);
  485. }
  486. /**
  487. * \brief Test InMemoryZoneFinder::InMemoryZoneFinder constructor.
  488. *
  489. * Takes the created zone finder and checks its properties they are the same
  490. * as passed parameters.
  491. */
  492. TEST_F(InMemoryZoneFinderTest, constructor) {
  493. ASSERT_EQ(class_, zone_finder_.getClass());
  494. ASSERT_EQ(origin_, zone_finder_.getOrigin());
  495. }
  496. /**
  497. * \brief Test adding.
  498. *
  499. * We test that it throws at the correct moments and the correct exceptions.
  500. * And we test the return value.
  501. */
  502. TEST_F(InMemoryZoneFinderTest, add) {
  503. // This one does not belong to this zone
  504. EXPECT_THROW(zone_finder_.add(rr_out_), InMemoryZoneFinder::OutOfZone);
  505. // Test null pointer
  506. EXPECT_THROW(zone_finder_.add(ConstRRsetPtr()),
  507. InMemoryZoneFinder::NullRRset);
  508. // Now put all the data we have there. It should throw nothing
  509. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_ns_)));
  510. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_ns_a_)));
  511. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_ns_aaaa_)));
  512. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_a_)));
  513. // Try putting there something twice, it should be rejected
  514. EXPECT_NO_THROW(EXPECT_EQ(EXIST, zone_finder_.add(rr_ns_)));
  515. EXPECT_NO_THROW(EXPECT_EQ(EXIST, zone_finder_.add(rr_ns_a_)));
  516. }
  517. TEST_F(InMemoryZoneFinderTest, addMultipleCNAMEs) {
  518. rr_cname_->addRdata(generic::CNAME("canonical2.example.org."));
  519. EXPECT_THROW(zone_finder_.add(rr_cname_), InMemoryZoneFinder::AddError);
  520. }
  521. TEST_F(InMemoryZoneFinderTest, addCNAMEThenOther) {
  522. EXPECT_EQ(SUCCESS, zone_finder_.add(rr_cname_));
  523. EXPECT_THROW(zone_finder_.add(rr_cname_a_), InMemoryZoneFinder::AddError);
  524. }
  525. TEST_F(InMemoryZoneFinderTest, addOtherThenCNAME) {
  526. EXPECT_EQ(SUCCESS, zone_finder_.add(rr_cname_a_));
  527. EXPECT_THROW(zone_finder_.add(rr_cname_), InMemoryZoneFinder::AddError);
  528. }
  529. TEST_F(InMemoryZoneFinderTest, findCNAME) {
  530. // install CNAME RR
  531. EXPECT_EQ(SUCCESS, zone_finder_.add(rr_cname_));
  532. // Find A RR of the same. Should match the CNAME
  533. findTest(rr_cname_->getName(), RRType::NS(), ZoneFinder::CNAME, true,
  534. rr_cname_);
  535. // Find the CNAME itself. Should result in normal SUCCESS
  536. findTest(rr_cname_->getName(), RRType::CNAME(), ZoneFinder::SUCCESS, true,
  537. rr_cname_);
  538. }
  539. TEST_F(InMemoryZoneFinderTest, findCNAMEUnderZoneCut) {
  540. // There's nothing special when we find a CNAME under a zone cut
  541. // (with FIND_GLUE_OK). The behavior is different from BIND 9,
  542. // so we test this case explicitly.
  543. EXPECT_EQ(SUCCESS, zone_finder_.add(rr_child_ns_));
  544. ConstRRsetPtr rr_cname_under_cut_ = textToRRset(
  545. "cname.child.example.org. 300 IN CNAME target.child.example.org.");
  546. EXPECT_EQ(SUCCESS, zone_finder_.add(rr_cname_under_cut_));
  547. findTest(Name("cname.child.example.org"), RRType::AAAA(),
  548. ZoneFinder::CNAME, true, rr_cname_under_cut_,
  549. ZoneFinder::RESULT_DEFAULT, NULL, ZoneFinder::FIND_GLUE_OK);
  550. }
  551. // Two DNAMEs at single domain are disallowed by RFC 2672, section 3)
  552. // Having a CNAME there is disallowed too, but it is tested by
  553. // addOtherThenCNAME and addCNAMEThenOther.
  554. TEST_F(InMemoryZoneFinderTest, addMultipleDNAMEs) {
  555. rr_dname_->addRdata(generic::DNAME("target2.example.org."));
  556. EXPECT_THROW(zone_finder_.add(rr_dname_), InMemoryZoneFinder::AddError);
  557. }
  558. /*
  559. * These two tests ensure that we can't have DNAME and NS at the same
  560. * node with the exception of the apex of zone (forbidden by RFC 2672)
  561. */
  562. TEST_F(InMemoryZoneFinderTest, addDNAMEThenNS) {
  563. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_dname_)));
  564. EXPECT_THROW(zone_finder_.add(rr_dname_ns_), InMemoryZoneFinder::AddError);
  565. }
  566. TEST_F(InMemoryZoneFinderTest, addNSThenDNAME) {
  567. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_dname_ns_)));
  568. EXPECT_THROW(zone_finder_.add(rr_dname_), InMemoryZoneFinder::AddError);
  569. }
  570. // It is allowed to have NS and DNAME at apex
  571. TEST_F(InMemoryZoneFinderTest, DNAMEAndNSAtApex) {
  572. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_dname_apex_)));
  573. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_ns_)));
  574. // The NS should be possible to be found, below should be DNAME, not
  575. // delegation
  576. findTest(origin_, RRType::NS(), ZoneFinder::SUCCESS, true, rr_ns_);
  577. findTest(rr_child_ns_->getName(), RRType::A(), ZoneFinder::DNAME, true,
  578. rr_dname_apex_);
  579. }
  580. TEST_F(InMemoryZoneFinderTest, NSAndDNAMEAtApex) {
  581. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_ns_)));
  582. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_dname_apex_)));
  583. }
  584. // TODO: Test (and implement) adding data under DNAME. That is forbidden by
  585. // 2672 as well.
  586. // Search under a DNAME record. It should return the DNAME
  587. TEST_F(InMemoryZoneFinderTest, findBelowDNAME) {
  588. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_dname_)));
  589. findTest(Name("below.dname.example.org"), RRType::A(), ZoneFinder::DNAME,
  590. true, rr_dname_);
  591. }
  592. // Search at the domain with DNAME. It should act as DNAME isn't there, DNAME
  593. // influences only the data below (see RFC 2672, section 3)
  594. TEST_F(InMemoryZoneFinderTest, findAtDNAME) {
  595. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_dname_)));
  596. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_dname_a_)));
  597. const Name dname_name(rr_dname_->getName());
  598. findTest(dname_name, RRType::A(), ZoneFinder::SUCCESS, true, rr_dname_a_);
  599. findTest(dname_name, RRType::DNAME(), ZoneFinder::SUCCESS, true,
  600. rr_dname_);
  601. findTest(dname_name, RRType::TXT(), ZoneFinder::NXRRSET, true);
  602. }
  603. // Try searching something that is both under NS and DNAME, without and with
  604. // GLUE_OK mode (it should stop at the NS and DNAME respectively).
  605. TEST_F(InMemoryZoneFinderTest, DNAMEUnderNS) {
  606. zone_finder_.add(rr_child_ns_);
  607. zone_finder_.add(rr_child_dname_);
  608. Name lowName("below.dname.child.example.org.");
  609. findTest(lowName, RRType::A(), ZoneFinder::DELEGATION, true, rr_child_ns_);
  610. findTest(lowName, RRType::A(), ZoneFinder::DNAME, true, rr_child_dname_,
  611. ZoneFinder::RESULT_DEFAULT, NULL, ZoneFinder::FIND_GLUE_OK);
  612. }
  613. // Test adding child zones and zone cut handling
  614. TEST_F(InMemoryZoneFinderTest, delegationNS) {
  615. // add in-zone data
  616. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_ns_)));
  617. // install a zone cut
  618. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_child_ns_)));
  619. // below the zone cut
  620. findTest(Name("www.child.example.org"), RRType::A(),
  621. ZoneFinder::DELEGATION, true, rr_child_ns_);
  622. // at the zone cut
  623. findTest(Name("child.example.org"), RRType::A(), ZoneFinder::DELEGATION,
  624. true, rr_child_ns_);
  625. findTest(Name("child.example.org"), RRType::NS(), ZoneFinder::DELEGATION,
  626. true, rr_child_ns_);
  627. // finding NS for the apex (origin) node. This must not be confused
  628. // with delegation due to the existence of an NS RR.
  629. findTest(origin_, RRType::NS(), ZoneFinder::SUCCESS, true, rr_ns_);
  630. // unusual case of "nested delegation": the highest cut should be used.
  631. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_grandchild_ns_)));
  632. findTest(Name("www.grand.child.example.org"), RRType::A(),
  633. // note: !rr_grandchild_ns_
  634. ZoneFinder::DELEGATION, true, rr_child_ns_);
  635. }
  636. TEST_F(InMemoryZoneFinderTest, delegationWithDS) {
  637. // Similar setup to the previous one, but with DS RR at the delegation
  638. // point.
  639. EXPECT_EQ(SUCCESS, zone_finder_.add(rr_ns_));
  640. EXPECT_EQ(SUCCESS, zone_finder_.add(rr_child_ns_));
  641. EXPECT_EQ(SUCCESS, zone_finder_.add(rr_child_ds_));
  642. // Normal types of query should result in delegation, but DS query
  643. // should be considered in-zone.
  644. findTest(Name("child.example.org"), RRType::A(), ZoneFinder::DELEGATION,
  645. true, rr_child_ns_);
  646. findTest(Name("child.example.org"), RRType::DS(), ZoneFinder::SUCCESS,
  647. true, rr_child_ds_);
  648. // There's nothing special for DS query at the zone apex. It would
  649. // normally result in NXRRSET.
  650. findTest(Name("example.org"), RRType::DS(), ZoneFinder::NXRRSET,
  651. true, ConstRRsetPtr());
  652. }
  653. TEST_F(InMemoryZoneFinderTest, findAny) {
  654. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_a_)));
  655. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_ns_)));
  656. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_child_glue_)));
  657. vector<ConstRRsetPtr> expected_sets;
  658. // origin
  659. expected_sets.push_back(rr_a_);
  660. expected_sets.push_back(rr_ns_);
  661. findAllTest(origin_, ZoneFinder::SUCCESS, expected_sets);
  662. // out zone name
  663. findAllTest(Name("example.com"), ZoneFinder::NXDOMAIN,
  664. vector<ConstRRsetPtr>());
  665. expected_sets.clear();
  666. expected_sets.push_back(rr_child_glue_);
  667. findAllTest(rr_child_glue_->getName(), ZoneFinder::SUCCESS, expected_sets);
  668. // TODO: test NXRRSET case after rbtree non-terminal logic has
  669. // been implemented
  670. // add zone cut
  671. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_child_ns_)));
  672. // zone cut
  673. findAllTest(rr_child_ns_->getName(), ZoneFinder::DELEGATION,
  674. vector<ConstRRsetPtr>(), ZoneFinder::RESULT_DEFAULT,
  675. NULL, rr_child_ns_);
  676. // glue for this zone cut
  677. findAllTest(rr_child_glue_->getName(),ZoneFinder::DELEGATION,
  678. vector<ConstRRsetPtr>(), ZoneFinder::RESULT_DEFAULT,
  679. NULL, rr_child_ns_);
  680. }
  681. TEST_F(InMemoryZoneFinderTest, glue) {
  682. // install zone data:
  683. // a zone cut
  684. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_child_ns_)));
  685. // glue for this cut
  686. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_child_glue_)));
  687. // a nested zone cut (unusual)
  688. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_grandchild_ns_)));
  689. // glue under the deeper zone cut
  690. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_grandchild_glue_)));
  691. // by default glue is hidden due to the zone cut
  692. findTest(rr_child_glue_->getName(), RRType::A(), ZoneFinder::DELEGATION,
  693. true, rr_child_ns_);
  694. // If we do it in the "glue OK" mode, we should find the exact match.
  695. findTest(rr_child_glue_->getName(), RRType::A(), ZoneFinder::SUCCESS, true,
  696. rr_child_glue_, ZoneFinder::RESULT_DEFAULT, NULL,
  697. ZoneFinder::FIND_GLUE_OK);
  698. // glue OK + NXRRSET case
  699. findTest(rr_child_glue_->getName(), RRType::AAAA(), ZoneFinder::NXRRSET,
  700. true, ConstRRsetPtr(), ZoneFinder::RESULT_DEFAULT, NULL,
  701. ZoneFinder::FIND_GLUE_OK);
  702. // glue OK + NXDOMAIN case
  703. findTest(Name("www.child.example.org"), RRType::A(),
  704. ZoneFinder::DELEGATION, true, rr_child_ns_,
  705. ZoneFinder::RESULT_DEFAULT, NULL, ZoneFinder::FIND_GLUE_OK);
  706. // nested cut case. The glue should be found.
  707. findTest(rr_grandchild_glue_->getName(), RRType::AAAA(),
  708. ZoneFinder::SUCCESS,
  709. true, rr_grandchild_glue_, ZoneFinder::RESULT_DEFAULT, NULL,
  710. ZoneFinder::FIND_GLUE_OK);
  711. // A non-existent name in nested cut. This should result in delegation
  712. // at the highest zone cut.
  713. findTest(Name("www.grand.child.example.org"), RRType::TXT(),
  714. ZoneFinder::DELEGATION, true, rr_child_ns_,
  715. ZoneFinder::RESULT_DEFAULT, NULL, ZoneFinder::FIND_GLUE_OK);
  716. }
  717. /**
  718. * \brief Test searching.
  719. *
  720. * Check it finds or does not find correctly and does not throw exceptions.
  721. * \todo This doesn't do any kind of CNAME and so on. If it isn't
  722. * directly there, it just tells it doesn't exist.
  723. */
  724. TEST_F(InMemoryZoneFinderTest, find) {
  725. // Fill some data inside
  726. // Now put all the data we have there. It should throw nothing
  727. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_ns_)));
  728. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_ns_a_)));
  729. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_ns_aaaa_)));
  730. EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_a_)));
  731. // These two should be successful
  732. findTest(origin_, RRType::NS(), ZoneFinder::SUCCESS, true, rr_ns_);
  733. findTest(rr_ns_a_->getName(), RRType::A(), ZoneFinder::SUCCESS, true,
  734. rr_ns_a_);
  735. // These domain exist but don't have the provided RRType
  736. findTest(origin_, RRType::AAAA(), ZoneFinder::NXRRSET);
  737. findTest(rr_ns_a_->getName(), RRType::NS(), ZoneFinder::NXRRSET);
  738. // These domains don't exist (and one is out of the zone)
  739. findTest(Name("nothere.example.org"), RRType::A(), ZoneFinder::NXDOMAIN);
  740. findTest(Name("example.net"), RRType::A(), ZoneFinder::NXDOMAIN);
  741. }
  742. TEST_F(InMemoryZoneFinderTest, emptyNode) {
  743. /*
  744. * The backend RBTree for this test should look like as follows:
  745. * example.org
  746. * |
  747. * baz (empty; easy case)
  748. * / | \
  749. * bar | x.foo ('foo' part is empty; a bit trickier)
  750. * bbb
  751. * /
  752. * aaa
  753. */
  754. // Construct the test zone
  755. const char* const names[] = {
  756. "bar.example.org.", "x.foo.example.org.", "aaa.baz.example.org.",
  757. "bbb.baz.example.org.", NULL};
  758. for (int i = 0; names[i] != NULL; ++i) {
  759. ConstRRsetPtr rrset = textToRRset(string(names[i]) +
  760. " 300 IN A 192.0.2.1");
  761. EXPECT_EQ(SUCCESS, zone_finder_.add(rrset));
  762. }
  763. // empty node matching, easy case: the node for 'baz' exists with
  764. // no data.
  765. findTest(Name("baz.example.org"), RRType::A(), ZoneFinder::NXRRSET);
  766. // empty node matching, a trickier case: the node for 'foo' is part of
  767. // "x.foo", which should be considered an empty node.
  768. findTest(Name("foo.example.org"), RRType::A(), ZoneFinder::NXRRSET);
  769. // "org" is contained in "example.org", but it shouldn't be treated as
  770. // NXRRSET because it's out of zone.
  771. // Note: basically we don't expect such a query to be performed (the common
  772. // operation is to identify the best matching zone first then perform
  773. // search it), but we shouldn't be confused even in the unexpected case.
  774. findTest(Name("org"), RRType::A(), ZoneFinder::NXDOMAIN);
  775. }
  776. TEST_F(InMemoryZoneFinderTest, load) {
  777. // Put some data inside the zone
  778. EXPECT_NO_THROW(EXPECT_EQ(result::SUCCESS, zone_finder_.add(rr_ns_)));
  779. // Loading with different origin should fail
  780. EXPECT_THROW(zone_finder_.load(TEST_DATA_DIR "/root.zone"),
  781. MasterLoadError);
  782. // See the original data is still there, survived the exception
  783. findTest(origin_, RRType::NS(), ZoneFinder::SUCCESS, true, rr_ns_);
  784. // Create correct zone
  785. InMemoryZoneFinder rootzone(class_, Name("."));
  786. // Try putting something inside
  787. EXPECT_NO_THROW(EXPECT_EQ(result::SUCCESS, rootzone.add(rr_ns_aaaa_)));
  788. // Load the zone. It should overwrite/remove the above RRset
  789. EXPECT_NO_THROW(rootzone.load(TEST_DATA_DIR "/root.zone"));
  790. // Now see there are some rrsets (we don't look inside, though)
  791. findTest(Name("."), RRType::SOA(), ZoneFinder::SUCCESS, false,
  792. ConstRRsetPtr(), ZoneFinder::RESULT_DEFAULT, &rootzone);
  793. findTest(Name("."), RRType::NS(), ZoneFinder::SUCCESS, false,
  794. ConstRRsetPtr(), ZoneFinder::RESULT_DEFAULT, &rootzone);
  795. findTest(Name("a.root-servers.net."), RRType::A(), ZoneFinder::SUCCESS,
  796. false, ConstRRsetPtr(), ZoneFinder::RESULT_DEFAULT, &rootzone);
  797. // But this should no longer be here
  798. findTest(rr_ns_a_->getName(), RRType::AAAA(), ZoneFinder::NXDOMAIN, true,
  799. ConstRRsetPtr(), ZoneFinder::RESULT_DEFAULT, &rootzone);
  800. // Try loading zone that is wrong in a different way
  801. EXPECT_THROW(zone_finder_.load(TEST_DATA_DIR "/duplicate_rrset.zone"),
  802. MasterLoadError);
  803. }
  804. /*
  805. * Test that puts a (simple) wildcard into the zone and checks we can
  806. * correctly find the data.
  807. */
  808. TEST_F(InMemoryZoneFinderTest, wildcard) {
  809. /*
  810. * example.org.
  811. * |
  812. * [cname]wild (not *.wild, should have wild mark)
  813. * |
  814. * *
  815. */
  816. EXPECT_EQ(SUCCESS, zone_finder_.add(rr_wild_));
  817. EXPECT_EQ(SUCCESS, zone_finder_.add(rr_cnamewild_));
  818. // Search at the parent. The parent will not have the A, but it will
  819. // be in the wildcard (so check the wildcard isn't matched at the parent)
  820. {
  821. SCOPED_TRACE("Search at parrent");
  822. findTest(Name("wild.example.org"), RRType::A(), ZoneFinder::NXRRSET);
  823. }
  824. // Search the original name of wildcard
  825. {
  826. SCOPED_TRACE("Search directly at *");
  827. findTest(Name("*.wild.example.org"), RRType::A(), ZoneFinder::SUCCESS,
  828. true, rr_wild_);
  829. }
  830. // Search "created" name.
  831. {
  832. SCOPED_TRACE("Search at created child");
  833. findTest(Name("a.wild.example.org"), RRType::A(), ZoneFinder::SUCCESS,
  834. false, rr_wild_, ZoneFinder::RESULT_WILDCARD, NULL,
  835. ZoneFinder::FIND_DEFAULT, true);
  836. // Wildcard match, but no data
  837. findTest(Name("a.wild.example.org"), RRType::AAAA(),
  838. ZoneFinder::NXRRSET, true, ConstRRsetPtr(),
  839. ZoneFinder::RESULT_WILDCARD);
  840. }
  841. // Search name that has CNAME.
  842. {
  843. SCOPED_TRACE("Matching CNAME");
  844. findTest(Name("a.cnamewild.example.org"), RRType::A(),
  845. ZoneFinder::CNAME, false, rr_cnamewild_,
  846. ZoneFinder::RESULT_WILDCARD, NULL, ZoneFinder::FIND_DEFAULT,
  847. true);
  848. }
  849. // Search another created name, this time little bit lower
  850. {
  851. SCOPED_TRACE("Search at created grand-child");
  852. findTest(Name("a.b.wild.example.org"), RRType::A(),
  853. ZoneFinder::SUCCESS, false, rr_wild_,
  854. ZoneFinder::RESULT_WILDCARD, NULL,
  855. ZoneFinder::FIND_DEFAULT, true);
  856. }
  857. EXPECT_EQ(SUCCESS, zone_finder_.add(rr_under_wild_));
  858. {
  859. SCOPED_TRACE("Search under non-wildcard");
  860. findTest(Name("bar.foo.wild.example.org"), RRType::A(),
  861. ZoneFinder::NXDOMAIN);
  862. }
  863. }
  864. /*
  865. * Test that we don't match a wildcard if we get under delegation.
  866. * By 4.3.3 of RFC1034:
  867. * "Wildcard RRs do not apply:
  868. * - When the query is in another zone. That is, delegation cancels
  869. * the wildcard defaults."
  870. */
  871. TEST_F(InMemoryZoneFinderTest, delegatedWildcard) {
  872. EXPECT_EQ(SUCCESS, zone_finder_.add(rr_child_wild_));
  873. EXPECT_EQ(SUCCESS, zone_finder_.add(rr_child_ns_));
  874. {
  875. SCOPED_TRACE("Looking under delegation point");
  876. findTest(Name("a.child.example.org"), RRType::A(),
  877. ZoneFinder::DELEGATION, true, rr_child_ns_);
  878. }
  879. {
  880. SCOPED_TRACE("Looking under delegation point in GLUE_OK mode");
  881. findTest(Name("a.child.example.org"), RRType::A(),
  882. ZoneFinder::DELEGATION, true, rr_child_ns_,
  883. ZoneFinder::RESULT_DEFAULT, NULL, ZoneFinder::FIND_GLUE_OK);
  884. }
  885. }
  886. // Tests combination of wildcard and ANY.
  887. TEST_F(InMemoryZoneFinderTest, anyWildcard) {
  888. EXPECT_EQ(SUCCESS, zone_finder_.add(rr_wild_));
  889. vector<ConstRRsetPtr> expected_sets;
  890. // First try directly the name (normal match)
  891. {
  892. SCOPED_TRACE("Asking direcly for *");
  893. expected_sets.push_back(rr_wild_);
  894. findAllTest(Name("*.wild.example.org"), ZoneFinder::SUCCESS,
  895. expected_sets);
  896. }
  897. // Then a wildcard match
  898. {
  899. SCOPED_TRACE("Asking in the wild way");
  900. expected_sets.clear();
  901. RRsetPtr expected(new RRset(Name("a.wild.example.org"),
  902. rr_wild_->getClass(), rr_wild_->getType(),
  903. rr_wild_->getTTL()));
  904. expected->addRdata(rr_wild_->getRdataIterator()->getCurrent());
  905. expected_sets.push_back(expected);
  906. findAllTest(Name("a.wild.example.org"), ZoneFinder::SUCCESS,
  907. expected_sets, ZoneFinder::RESULT_WILDCARD);
  908. }
  909. }
  910. // Test there's nothing in the wildcard in the middle if we load
  911. // wild.*.foo.example.org.
  912. TEST_F(InMemoryZoneFinderTest, emptyWildcard) {
  913. /*
  914. * example.org.
  915. * foo
  916. * *
  917. * wild
  918. */
  919. EXPECT_EQ(SUCCESS, zone_finder_.add(rr_emptywild_));
  920. {
  921. SCOPED_TRACE("Asking for the original record under wildcard");
  922. findTest(Name("wild.*.foo.example.org"), RRType::A(),
  923. ZoneFinder::SUCCESS, true, rr_emptywild_);
  924. }
  925. {
  926. SCOPED_TRACE("Asking for A record");
  927. findTest(Name("a.foo.example.org"), RRType::A(), ZoneFinder::NXRRSET,
  928. true, ConstRRsetPtr(), ZoneFinder::RESULT_WILDCARD);
  929. findTest(Name("*.foo.example.org"), RRType::A(), ZoneFinder::NXRRSET);
  930. findTest(Name("foo.example.org"), RRType::A(), ZoneFinder::NXRRSET);
  931. }
  932. {
  933. SCOPED_TRACE("Asking for ANY record");
  934. findAllTest(Name("*.foo.example.org"), ZoneFinder::NXRRSET,
  935. vector<ConstRRsetPtr>());
  936. findAllTest(Name("a.foo.example.org"), ZoneFinder::NXRRSET,
  937. vector<ConstRRsetPtr>(), ZoneFinder::RESULT_WILDCARD);
  938. }
  939. {
  940. SCOPED_TRACE("Asking on the non-terminal");
  941. findTest(Name("wild.bar.foo.example.org"), RRType::A(),
  942. ZoneFinder::NXRRSET, true, ConstRRsetPtr(),
  943. ZoneFinder::RESULT_WILDCARD);
  944. }
  945. }
  946. // Same as emptyWildcard, but with multiple * in the path.
  947. TEST_F(InMemoryZoneFinderTest, nestedEmptyWildcard) {
  948. EXPECT_EQ(SUCCESS, zone_finder_.add(rr_nested_emptywild_));
  949. {
  950. SCOPED_TRACE("Asking for the original record under wildcards");
  951. findTest(Name("wild.*.foo.*.bar.example.org"), RRType::A(),
  952. ZoneFinder::SUCCESS, true, rr_nested_emptywild_);
  953. }
  954. {
  955. SCOPED_TRACE("Matching wildcard against empty nonterminal");
  956. const char* names[] = {
  957. "baz.foo.*.bar.example.org",
  958. "baz.foo.baz.bar.example.org",
  959. "*.foo.baz.bar.example.org",
  960. NULL
  961. };
  962. for (const char** name = names; *name != NULL; ++ name) {
  963. SCOPED_TRACE(string("Node ") + *name);
  964. findTest(Name(*name), RRType::A(), ZoneFinder::NXRRSET, true,
  965. ConstRRsetPtr(), ZoneFinder::RESULT_WILDCARD);
  966. }
  967. }
  968. // Domains to test
  969. const char* names[] = {
  970. "*.foo.*.bar.example.org",
  971. "foo.*.bar.example.org",
  972. "*.bar.example.org",
  973. "bar.example.org",
  974. NULL
  975. };
  976. {
  977. SCOPED_TRACE("Asking directly for A on parent nodes");
  978. for (const char** name = names; *name != NULL; ++ name) {
  979. SCOPED_TRACE(string("Node ") + *name);
  980. findTest(Name(*name), RRType::A(), ZoneFinder::NXRRSET);
  981. }
  982. }
  983. {
  984. SCOPED_TRACE("Asking for ANY on parent nodes");
  985. for (const char** name = names; *name != NULL; ++ name) {
  986. SCOPED_TRACE(string("Node ") + *name);
  987. findAllTest(Name(*name), ZoneFinder::NXRRSET,
  988. vector<ConstRRsetPtr>());
  989. }
  990. }
  991. }
  992. // We run this part twice from the below test, in two slightly different
  993. // situations
  994. void
  995. InMemoryZoneFinderTest::doCancelWildcardTest() {
  996. // These should be canceled
  997. {
  998. SCOPED_TRACE("Canceled under foo.wild.example.org");
  999. findTest(Name("aaa.foo.wild.example.org"), RRType::A(),
  1000. ZoneFinder::NXDOMAIN);
  1001. findTest(Name("zzz.foo.wild.example.org"), RRType::A(),
  1002. ZoneFinder::NXDOMAIN);
  1003. }
  1004. // This is existing, non-wildcard domain, shouldn't wildcard at all
  1005. {
  1006. SCOPED_TRACE("Existing domain under foo.wild.example.org");
  1007. findTest(Name("bar.foo.wild.example.org"), RRType::A(),
  1008. ZoneFinder::SUCCESS, true, rr_not_wild_);
  1009. }
  1010. // These should be caught by the wildcard
  1011. {
  1012. SCOPED_TRACE("Neighbor wildcards to foo.wild.example.org");
  1013. const char* names[] = {
  1014. "aaa.bbb.wild.example.org",
  1015. "aaa.zzz.wild.example.org",
  1016. "zzz.wild.example.org",
  1017. NULL
  1018. };
  1019. for (const char** name = names; *name != NULL; ++ name) {
  1020. SCOPED_TRACE(string("Node ") + *name);
  1021. findTest(Name(*name), RRType::A(), ZoneFinder::SUCCESS, false,
  1022. rr_wild_, ZoneFinder::RESULT_WILDCARD, NULL,
  1023. ZoneFinder::FIND_DEFAULT, true);
  1024. }
  1025. }
  1026. // This shouldn't be wildcarded, it's an existing domain
  1027. {
  1028. SCOPED_TRACE("The foo.wild.example.org itself");
  1029. findTest(Name("foo.wild.example.org"), RRType::A(),
  1030. ZoneFinder::NXRRSET);
  1031. }
  1032. }
  1033. /*
  1034. * This tests that if there's a name between the wildcard domain and the
  1035. * searched one, it will not trigger wildcard, for example, if we have
  1036. * *.wild.example.org and bar.foo.wild.example.org, then we know
  1037. * foo.wild.example.org exists and is not wildcard. Therefore, search for
  1038. * aaa.foo.wild.example.org should return NXDOMAIN.
  1039. *
  1040. * Tests few cases "around" the canceled wildcard match, to see something that
  1041. * shouldn't be canceled isn't.
  1042. */
  1043. TEST_F(InMemoryZoneFinderTest, cancelWildcard) {
  1044. EXPECT_EQ(SUCCESS, zone_finder_.add(rr_wild_));
  1045. EXPECT_EQ(SUCCESS, zone_finder_.add(rr_not_wild_));
  1046. {
  1047. SCOPED_TRACE("Runnig with single entry under foo.wild.example.org");
  1048. doCancelWildcardTest();
  1049. }
  1050. // Try putting another one under foo.wild....
  1051. // The result should be the same but it will be done in another way in the
  1052. // code, because the foo.wild.example.org will exist in the tree.
  1053. EXPECT_EQ(SUCCESS, zone_finder_.add(rr_not_wild_another_));
  1054. {
  1055. SCOPED_TRACE("Runnig with two entries under foo.wild.example.org");
  1056. doCancelWildcardTest();
  1057. }
  1058. }
  1059. TEST_F(InMemoryZoneFinderTest, loadBadWildcard) {
  1060. // We reject loading the zone if it contains a wildcard name for
  1061. // NS or DNAME.
  1062. EXPECT_THROW(zone_finder_.add(rr_nswild_), InMemoryZoneFinder::AddError);
  1063. EXPECT_THROW(zone_finder_.add(rr_dnamewild_),
  1064. InMemoryZoneFinder::AddError);
  1065. }
  1066. TEST_F(InMemoryZoneFinderTest, swap) {
  1067. // build one zone finder with some data
  1068. InMemoryZoneFinder finder1(class_, origin_);
  1069. EXPECT_EQ(result::SUCCESS, finder1.add(rr_ns_));
  1070. EXPECT_EQ(result::SUCCESS, finder1.add(rr_ns_aaaa_));
  1071. // build another zone finder of a different RR class with some other data
  1072. const Name other_origin("version.bind");
  1073. ASSERT_NE(origin_, other_origin); // make sure these two are different
  1074. InMemoryZoneFinder finder2(RRClass::CH(), other_origin);
  1075. EXPECT_EQ(result::SUCCESS,
  1076. finder2.add(textToRRset("version.bind. 0 CH TXT \"test\"",
  1077. RRClass::CH())));
  1078. finder1.swap(finder2);
  1079. EXPECT_EQ(other_origin, finder1.getOrigin());
  1080. EXPECT_EQ(origin_, finder2.getOrigin());
  1081. EXPECT_EQ(RRClass::CH(), finder1.getClass());
  1082. EXPECT_EQ(RRClass::IN(), finder2.getClass());
  1083. // make sure the zone data is swapped, too
  1084. findTest(origin_, RRType::NS(), ZoneFinder::NXDOMAIN, false,
  1085. ConstRRsetPtr(), ZoneFinder::RESULT_DEFAULT, &finder1);
  1086. findTest(other_origin, RRType::TXT(), ZoneFinder::SUCCESS, false,
  1087. ConstRRsetPtr(), ZoneFinder::RESULT_DEFAULT, &finder1);
  1088. findTest(origin_, RRType::NS(), ZoneFinder::SUCCESS, false,
  1089. ConstRRsetPtr(), ZoneFinder::RESULT_DEFAULT, &finder2);
  1090. findTest(other_origin, RRType::TXT(), ZoneFinder::NXDOMAIN, false,
  1091. ConstRRsetPtr(), ZoneFinder::RESULT_DEFAULT, &finder2);
  1092. }
  1093. TEST_F(InMemoryZoneFinderTest, getFileName) {
  1094. // for an empty zone the file name should also be empty.
  1095. EXPECT_TRUE(zone_finder_.getFileName().empty());
  1096. // if loading a zone fails the file name shouldn't be set.
  1097. EXPECT_THROW(zone_finder_.load(TEST_DATA_DIR "/root.zone"),
  1098. MasterLoadError);
  1099. EXPECT_TRUE(zone_finder_.getFileName().empty());
  1100. // after a successful load, the specified file name should be set
  1101. InMemoryZoneFinder rootzone(class_, Name("."));
  1102. EXPECT_NO_THROW(rootzone.load(TEST_DATA_DIR "/root.zone"));
  1103. EXPECT_EQ(TEST_DATA_DIR "/root.zone", rootzone.getFileName());
  1104. // overriding load, which will fail
  1105. EXPECT_THROW(rootzone.load(TEST_DATA_DIR "/duplicate_rrset.zone"),
  1106. MasterLoadError);
  1107. // the file name should be intact.
  1108. EXPECT_EQ(TEST_DATA_DIR "/root.zone", rootzone.getFileName());
  1109. // After swap, file names should also be swapped.
  1110. zone_finder_.swap(rootzone);
  1111. EXPECT_EQ(TEST_DATA_DIR "/root.zone", zone_finder_.getFileName());
  1112. EXPECT_TRUE(rootzone.getFileName().empty());
  1113. }
  1114. TEST_F(InMemoryZoneFinderTest, addRRsig) {
  1115. // A simple valid case: adding an RRset to be signed followed by an RRSIG
  1116. // that covers the first RRset
  1117. zone_finder_.add(rr_a_);
  1118. zone_finder_.add(textToRRset(rrsig_a_txt));
  1119. ZoneFinder::FindResult result = zone_finder_.find(origin_, RRType::A(),
  1120. ZoneFinder::FIND_DNSSEC);
  1121. EXPECT_EQ(ZoneFinder::SUCCESS, result.code);
  1122. ASSERT_TRUE(result.rrset);
  1123. ASSERT_TRUE(result.rrset->getRRsig());
  1124. actual_rrsets_.push_back(result.rrset->getRRsig());
  1125. rrsetsCheck(rrsig_a_txt, actual_rrsets_.begin(), actual_rrsets_.end());
  1126. // Confirm a separate RRISG for a different type can be added
  1127. actual_rrsets_.clear();
  1128. zone_finder_.add(rr_ns_);
  1129. zone_finder_.add(textToRRset(rrsig_ns_txt));
  1130. ZoneFinder::FindResult result2 =
  1131. zone_finder_.find(origin_, RRType::NS(), ZoneFinder::FIND_DNSSEC);
  1132. EXPECT_EQ(ZoneFinder::SUCCESS, result2.code);
  1133. ASSERT_TRUE(result2.rrset);
  1134. ASSERT_TRUE(result2.rrset->getRRsig());
  1135. actual_rrsets_.push_back(result2.rrset->getRRsig());
  1136. rrsetsCheck(rrsig_ns_txt, actual_rrsets_.begin(), actual_rrsets_.end());
  1137. // Check a case with multiple RRSIGs
  1138. actual_rrsets_.clear();
  1139. zone_finder_.add(rr_ns_aaaa_);
  1140. zone_finder_.add(textToRRset(rrsig_aaaa_txt));
  1141. ZoneFinder::FindResult result3 =
  1142. zone_finder_.find(Name("ns.example.org"), RRType::AAAA(),
  1143. ZoneFinder::FIND_DNSSEC);
  1144. EXPECT_EQ(ZoneFinder::SUCCESS, result3.code);
  1145. ASSERT_TRUE(result3.rrset);
  1146. ASSERT_TRUE(result3.rrset->getRRsig());
  1147. actual_rrsets_.push_back(result3.rrset->getRRsig());
  1148. rrsetsCheck(rrsig_aaaa_txt, actual_rrsets_.begin(), actual_rrsets_.end());
  1149. }
  1150. TEST_F(InMemoryZoneFinderTest, addRRsigWithoutCovered) {
  1151. // The current implementation rejects attempts of adding RRSIG without
  1152. // covered RRsets already in the zone.
  1153. // Name doesn't exist
  1154. EXPECT_THROW(zone_finder_.add(
  1155. textToRRset("notexist.example.org. 300 IN RRSIG A 5 3 "
  1156. "3600 20000101000000 20000201000000 12345 "
  1157. "example.org. FAKEFAKEFAKE\n")),
  1158. InMemoryZoneFinder::AddError);
  1159. // Name exists, but is empty.
  1160. zone_finder_.add(rr_emptywild_);
  1161. EXPECT_THROW(zone_finder_.add(
  1162. textToRRset("foo.example.org. 300 IN RRSIG A 5 3 "
  1163. "3600 20000101000000 20000201000000 12345 "
  1164. "example.org. FAKEFAKEFAKE\n")),
  1165. InMemoryZoneFinder::AddError);
  1166. // Add RRSIG RRset without covered RR
  1167. zone_finder_.add(rr_a_);
  1168. EXPECT_THROW(zone_finder_.add(textToRRset(rrsig_ns_txt)),
  1169. InMemoryZoneFinder::AddError);
  1170. }
  1171. TEST_F(InMemoryZoneFinderTest, addbadRRsig) {
  1172. // Tests with other types of bogus input
  1173. // Empty RRSIG RRset.
  1174. EXPECT_THROW(zone_finder_.add(RRsetPtr(new RRset(origin_, class_,
  1175. RRType::RRSIG(),
  1176. RRTTL(300)))),
  1177. InMemoryZoneFinder::AddError);
  1178. // RRSIG with mixed covered types
  1179. zone_finder_.add(rr_a_); // make sure the covered name exists
  1180. // textToRRset() doesn't work as intended for this pathological case,
  1181. // so we need to construct the RRset by hand.
  1182. RRsetPtr rrset(new RRset(origin_, class_, RRType::RRSIG(), RRTTL(300)));
  1183. rrset->addRdata(generic::RRSIG("A 5 3 3600 20000101000000 20000201000000 "
  1184. "12345 example.org. FAKEFAKEFAKE"));
  1185. rrset->addRdata(generic::RRSIG("NS 5 3 3600 20000101000000 20000201000000 "
  1186. "54321 example.org. FAKEFAKEFAKEFAKE"));
  1187. EXPECT_THROW(zone_finder_.add(rrset), InMemoryZoneFinder::AddError);
  1188. // An attempt of overriding an existing RRSIG. The current implementation
  1189. // prohibits that.
  1190. zone_finder_.add(textToRRset(rrsig_a_txt));
  1191. EXPECT_THROW(zone_finder_.add(textToRRset(rrsig_a_txt)),
  1192. InMemoryZoneFinder::AddError);
  1193. }
  1194. //
  1195. // (Faked) NSEC3 hash data. Arbitrarily borrowed from RFC515 examples.
  1196. //
  1197. // Commonly used NSEC3 suffix. It's incorrect to use it for all NSEC3s, but
  1198. // doesn't matter for the purpose of our tests.
  1199. const char* const nsec3_common = " 300 IN NSEC3 1 1 12 aabbccdd "
  1200. "2T7B4G4VSA5SMI47K61MV5BV1A22BOJR A RRSIG";
  1201. // Likewise, common RRSIG suffix for NSEC3s.
  1202. const char* const nsec3_rrsig_common = " 300 IN RRSIG NSEC3 5 3 3600 "
  1203. "20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE";
  1204. // For apex (example.org)
  1205. const char* const apex_hash = "0P9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM";
  1206. const char* const apex_hash_lower = "0p9mhaveqvm6t7vbl5lop2u3t2rp3tom";
  1207. // For ns1.example.org
  1208. const char* const ns1_hash = "2T7B4G4VSA5SMI47K61MV5BV1A22BOJR";
  1209. // For x.y.w.example.org (lower-cased)
  1210. const char* const xrw_hash = "2vptu5timamqttgl4luu9kg21e0aor3s";
  1211. void
  1212. nsec3Check(bool expected_matched, const string& expected_rrsets_txt,
  1213. const ZoneFinder::FindNSEC3Result& result,
  1214. bool expected_sig = false)
  1215. {
  1216. vector<ConstRRsetPtr> actual_rrsets;
  1217. EXPECT_EQ(expected_matched, result.matched);
  1218. ASSERT_TRUE(result.closest_proof);
  1219. if (expected_sig) {
  1220. ASSERT_TRUE(result.closest_proof->getRRsig());
  1221. }
  1222. actual_rrsets.push_back(result.closest_proof);
  1223. if (expected_sig) {
  1224. actual_rrsets.push_back(result.closest_proof->getRRsig());
  1225. }
  1226. rrsetsCheck(expected_rrsets_txt, actual_rrsets.begin(),
  1227. actual_rrsets.end());
  1228. }
  1229. // In the following tests we use a temporary faked version of findNSEC3
  1230. // as the real version isn't implemented yet (it's a task for #1577).
  1231. // When #1577 is done the tests should be updated using the real version.
  1232. // If we can use fake hash calculator (see #1575), we should be able to
  1233. // just replace findNSEC3Tmp with findNSEC3.
  1234. TEST_F(InMemoryZoneFinderTest, addNSEC3) {
  1235. const string nsec3_text = string(apex_hash) + ".example.org." +
  1236. string(nsec3_common);
  1237. // This name shouldn't be found in the normal domain tree.
  1238. EXPECT_EQ(result::SUCCESS, zone_finder_.add(textToRRset(nsec3_text)));
  1239. EXPECT_EQ(ZoneFinder::NXDOMAIN,
  1240. zone_finder_.find(Name(string(apex_hash) + ".example.org"),
  1241. RRType::NSEC3()).code);
  1242. // Dedicated NSEC3 find should be able to find it.
  1243. nsec3Check(true, nsec3_text,
  1244. zone_finder_.findNSEC3Tmp(Name("example.org"), false));
  1245. // This implementation rejects duplicate/update add of the same hash name
  1246. EXPECT_EQ(result::EXIST,
  1247. zone_finder_.add(textToRRset(
  1248. string(apex_hash) + ".example.org." +
  1249. string(nsec3_common) + " AAAA")));
  1250. // The original NSEC3 should be intact
  1251. nsec3Check(true, nsec3_text,
  1252. zone_finder_.findNSEC3Tmp(Name("example.org"), false));
  1253. // NSEC3-like name but of ordinary RR type should go to normal tree.
  1254. const string nonsec3_text = string(apex_hash) + ".example.org. " +
  1255. "300 IN A 192.0.2.1";
  1256. EXPECT_EQ(result::SUCCESS, zone_finder_.add(textToRRset(nonsec3_text)));
  1257. EXPECT_EQ(ZoneFinder::SUCCESS,
  1258. zone_finder_.find(Name(string(apex_hash) + ".example.org"),
  1259. RRType::A()).code);
  1260. }
  1261. TEST_F(InMemoryZoneFinderTest, addNSEC3Lower) {
  1262. // Similar to the previous case, but NSEC3 owner name is lower-cased.
  1263. const string nsec3_text = string(apex_hash_lower) + ".example.org." +
  1264. string(nsec3_common);
  1265. EXPECT_EQ(result::SUCCESS, zone_finder_.add(textToRRset(nsec3_text)));
  1266. nsec3Check(true, nsec3_text,
  1267. zone_finder_.findNSEC3Tmp(Name("example.org"), false));
  1268. }
  1269. TEST_F(InMemoryZoneFinderTest, addNSEC3Ordering) {
  1270. // Check that the internal storage ensures comparison based on the NSEC3
  1271. // semantics, regardless of the add order or the letter-case of hash.
  1272. // Adding "0P..", "2v..", then "2T..".
  1273. const string smallest = string(apex_hash) + ".example.org." +
  1274. string(nsec3_common);
  1275. const string middle = string(ns1_hash) + ".example.org." +
  1276. string(nsec3_common);
  1277. const string largest = string(xrw_hash) + ".example.org." +
  1278. string(nsec3_common);
  1279. zone_finder_.add(textToRRset(smallest));
  1280. zone_finder_.add(textToRRset(largest));
  1281. zone_finder_.add(textToRRset(middle));
  1282. // Then look for NSEC3 that covers a name whose hash is "2S.."
  1283. // The covering NSEC3 should be "0P.."
  1284. nsec3Check(false, smallest,
  1285. zone_finder_.findNSEC3Tmp(Name("www.example.org"), false));
  1286. // Look for NSEC3 that covers names whose hash are "Q0.." and "0A.."
  1287. // The covering NSEC3 should be "2v.." in both cases
  1288. nsec3Check(false, largest,
  1289. zone_finder_.findNSEC3Tmp(Name("xxx.example.org"), false));
  1290. nsec3Check(false, largest,
  1291. zone_finder_.findNSEC3Tmp(Name("yyy.example.org"), false));
  1292. }
  1293. TEST_F(InMemoryZoneFinderTest, badNSEC3Name) {
  1294. // Our implementation refuses to load NSEC3 at a wildcard name
  1295. EXPECT_THROW(zone_finder_.add(textToRRset("*.example.org." +
  1296. string(nsec3_common))),
  1297. InMemoryZoneFinder::AddError);
  1298. // Likewise, if the owner name of NSEC3 has too many labels, it's refused.
  1299. EXPECT_THROW(zone_finder_.add(textToRRset("a." + string(apex_hash) +
  1300. ".example.org." +
  1301. string(nsec3_common))),
  1302. InMemoryZoneFinder::AddError);
  1303. }
  1304. TEST_F(InMemoryZoneFinderTest, addMultiNSEC3) {
  1305. // In this current implementation multiple NSEC3 RDATA isn't supported.
  1306. RRsetPtr nsec3(new RRset(Name(string(apex_hash) + ".example.org"),
  1307. RRClass::IN(), RRType::NSEC3(), RRTTL(300)));
  1308. nsec3->addRdata(
  1309. generic::NSEC3("1 0 12 aabbccdd 2T7B4G4VSA5SMI47K61MV5BV1A22BOJR A"));
  1310. nsec3->addRdata(
  1311. generic::NSEC3("1 1 1 ddccbbaa 2T7B4G4VSA5SMI47K61MV5BV1A22BOJR A"));
  1312. EXPECT_THROW(zone_finder_.add(nsec3), InMemoryZoneFinder::AddError);
  1313. }
  1314. TEST_F(InMemoryZoneFinderTest, addNSEC3WithRRSIG) {
  1315. // Adding NSEC3 and its RRSIG
  1316. const string nsec3_text = string(apex_hash) + ".example.org." +
  1317. string(nsec3_common);
  1318. EXPECT_EQ(result::SUCCESS, zone_finder_.add(textToRRset(nsec3_text)));
  1319. const string nsec3_rrsig_text = string(apex_hash) + ".example.org." +
  1320. string(nsec3_rrsig_common);
  1321. EXPECT_EQ(result::SUCCESS, zone_finder_.add(textToRRset(nsec3_rrsig_text)));
  1322. // Then look for it. The NSEC3 should have the RRSIG that was just added.
  1323. nsec3Check(true, nsec3_text + "\n" + nsec3_rrsig_text,
  1324. zone_finder_.findNSEC3Tmp(Name("example.org"), false), true);
  1325. // Duplicate add of RRSIG for the same NSEC3 is prohibited.
  1326. EXPECT_THROW(zone_finder_.add(textToRRset(nsec3_rrsig_text)),
  1327. InMemoryZoneFinder::AddError);
  1328. // Same check using the lower-cased name. This also confirms matching
  1329. // is case-insensitive.
  1330. EXPECT_THROW(zone_finder_.add(textToRRset(string(apex_hash_lower) +
  1331. ".example.org."
  1332. + string(nsec3_rrsig_common))),
  1333. InMemoryZoneFinder::AddError);
  1334. }
  1335. TEST_F(InMemoryZoneFinderTest, badRRsigForNSEC3) {
  1336. // adding RRSIG for NSEC3 even before adding any NSEC3 (internally,
  1337. // a space for NSEC3 namespace isn't yet allocated)
  1338. EXPECT_THROW(zone_finder_.add(textToRRset(string(apex_hash) +
  1339. ".example.org." +
  1340. string(nsec3_rrsig_common))),
  1341. InMemoryZoneFinder::AddError);
  1342. // Add an NSEC3
  1343. EXPECT_EQ(result::SUCCESS, zone_finder_.add(
  1344. textToRRset(string(apex_hash) + ".example.org." +
  1345. string(nsec3_common))));
  1346. // Then add an NSEC3 for a non existent NSEC3. It should fail in the
  1347. // current implementation.
  1348. EXPECT_THROW(zone_finder_.add(textToRRset(string(ns1_hash) +
  1349. ".example.org." +
  1350. string(nsec3_rrsig_common))),
  1351. InMemoryZoneFinder::AddError);
  1352. }
  1353. TEST_F(InMemoryZoneFinderTest, paramConsistencyWithNSEC3PARAM) {
  1354. // First, add an NSEC3PARAM RR
  1355. EXPECT_EQ(result::SUCCESS,
  1356. zone_finder_.add(textToRRset("example.org. 300 IN NSEC3PARAM "
  1357. "1 0 12 aabbccdd")));
  1358. // Adding an NSEC3 that has matching parameters is okay.
  1359. EXPECT_EQ(result::SUCCESS, zone_finder_.add(
  1360. textToRRset(string(apex_hash) + ".example.org." +
  1361. string(nsec3_common))));
  1362. // NSEC3 with inconsistent parameter will be rejected
  1363. EXPECT_THROW(zone_finder_.add(
  1364. textToRRset("a.example.org. 300 IN NSEC3 1 0 1 aabbccdd "
  1365. "2T7B4G4VSA5SMI47K61MV5BV1A22BOJR A RRSIG")),
  1366. InMemoryZoneFinder::AddError);
  1367. }
  1368. TEST_F(InMemoryZoneFinderTest, paramConsistencyWithNSEC3) {
  1369. // Add an NSEC3 without adding NSEC3PARAM
  1370. EXPECT_EQ(result::SUCCESS, zone_finder_.add(
  1371. textToRRset(string(apex_hash) + ".example.org." +
  1372. string(nsec3_common))));
  1373. // Adding an NSEC3 with inconsistent parameter will be rejected at this pt.
  1374. EXPECT_THROW(zone_finder_.add(
  1375. textToRRset("a.example.org. 300 IN NSEC3 1 0 1 aabbccdd "
  1376. "2T7B4G4VSA5SMI47K61MV5BV1A22BOJR A RRSIG")),
  1377. InMemoryZoneFinder::AddError);
  1378. // Likewise, NSEC3PARAM with inconsistent parameter will be rejected.
  1379. EXPECT_THROW(zone_finder_.add(textToRRset("example.org. 300 IN NSEC3PARAM "
  1380. "1 0 1 aabbccdd")),
  1381. InMemoryZoneFinder::AddError);
  1382. }
  1383. TEST_F(InMemoryZoneFinderTest, multiNSEC3PARAM) {
  1384. // In this current implementation multiple NSEC3PARAM isn't supported.
  1385. RRsetPtr nsec3param(new RRset(Name("example.org"), RRClass::IN(),
  1386. RRType::NSEC3PARAM(), RRTTL(300)));
  1387. nsec3param->addRdata(generic::NSEC3PARAM("1 0 12 aabbccdd"));
  1388. nsec3param->addRdata(generic::NSEC3PARAM("1 1 1 ddccbbaa"));
  1389. EXPECT_THROW(zone_finder_.add(nsec3param), InMemoryZoneFinder::AddError);
  1390. }
  1391. TEST_F(InMemoryZoneFinderTest, nonOriginNSEC3PARAM) {
  1392. // This is a normal NSEC3PARAM at the zone origin
  1393. EXPECT_EQ(result::SUCCESS,
  1394. zone_finder_.add(textToRRset("example.org. 300 IN NSEC3PARAM "
  1395. "1 0 12 aabbccdd")));
  1396. // Add another (with different param) at a non origin node. This is
  1397. // awkward, but the implementation accepts it as an ordinary RR.
  1398. EXPECT_EQ(result::SUCCESS,
  1399. zone_finder_.add(textToRRset("a.example.org. 300 IN NSEC3PARAM "
  1400. "1 1 1 aabbccdd")));
  1401. }
  1402. TEST_F(InMemoryZoneFinderTest, loadNSEC3Zone) {
  1403. // Check if it can load validly NSEC3-signed zone. At this moment
  1404. // it's sufficient to see it doesn't crash
  1405. zone_finder_.load(TEST_DATA_DIR "/example.org.nsec3-signed");
  1406. // Reload the zone with a version that doesn't have NSEC3PARAM.
  1407. // This is an abnormal case, but the implementation accepts it.
  1408. zone_finder_.load(TEST_DATA_DIR "/example.org.nsec3-signed-noparam");
  1409. }
  1410. }