zone_finder_unittest.cc 63 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565
  1. // Copyright (C) 2012 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 "memory_segment_test.h"
  15. // NOTE: this faked_nsec3 inclusion (and all related code below)
  16. // was ported during #2109 for the convenience of implementing #2218
  17. // In #2218 the NSEC3 test code in this file is expected to be finalized.
  18. // In #2219 the original is expected to be removed, and this file should
  19. // probably be moved here (and any leftover code not handled in #2218 should
  20. // be cleaned up)
  21. #include "../../tests/faked_nsec3.h"
  22. #include <datasrc/memory/zone_finder.h>
  23. #include <datasrc/memory/zone_data_updater.h>
  24. #include <datasrc/memory/rdata_serialization.h>
  25. #include <datasrc/data_source.h>
  26. #include <testutils/dnsmessage_test.h>
  27. #include <boost/foreach.hpp>
  28. #include <gtest/gtest.h>
  29. #include <string>
  30. using namespace std;
  31. using namespace isc::dns;
  32. using namespace isc::dns::rdata;
  33. using namespace isc::datasrc;
  34. using namespace isc::testutils;
  35. using boost::shared_ptr;
  36. using namespace isc::datasrc::test;
  37. using namespace isc::datasrc::memory::test;
  38. using namespace isc::datasrc::memory;
  39. namespace {
  40. // Commonly used result codes (Who should write the prefix all the time)
  41. using result::SUCCESS;
  42. using result::EXIST;
  43. /// \brief expensive rrset converter
  44. ///
  45. /// converts any specialized rrset (which may not have implemented some
  46. /// methods for efficiency) into a 'full' RRsetPtr, for easy use in test
  47. /// checks.
  48. ///
  49. /// Done very inefficiently through text representation, speed should not
  50. /// be a concern here.
  51. ConstRRsetPtr
  52. convertRRset(ConstRRsetPtr src) {
  53. return (textToRRset(src->toText()));
  54. }
  55. /// \brief Test fixture for the InMemoryZoneFinder class
  56. class InMemoryZoneFinderTest : public ::testing::Test {
  57. // A straightforward pair of textual RR(set) and a RRsetPtr variable
  58. // to store the RRset. Used to build test data below.
  59. struct RRsetData {
  60. const char* const text; // textual representation of an RRset
  61. RRsetPtr* rrset;
  62. };
  63. protected:
  64. // The following sub tests are shared by multiple test cases, changing
  65. // the zone's DNSSEC status (unsigned, NSEC-signed or NSEC3-signed).
  66. // expected_flags is set to either RESULT_NSEC_SIGNED or
  67. // RESULT_NSEC3_SIGNED when it's NSEC/NSEC3 signed respectively and
  68. // find() is expected to set the corresponding flags.
  69. // find_options should be set to FIND_DNSSEC for NSEC-signed case when
  70. // NSEC is expected to be returned.
  71. void findCheck(ZoneFinder::FindResultFlags expected_flags =
  72. ZoneFinder::RESULT_DEFAULT,
  73. ZoneFinder::FindOptions find_options =
  74. ZoneFinder::FIND_DEFAULT);
  75. void emptyNodeCheck(ZoneFinder::FindResultFlags expected_flags =
  76. ZoneFinder::RESULT_DEFAULT);
  77. void wildcardCheck(ZoneFinder::FindResultFlags expected_flags =
  78. ZoneFinder::RESULT_DEFAULT,
  79. ZoneFinder::FindOptions find_options =
  80. ZoneFinder::FIND_DEFAULT);
  81. void doCancelWildcardCheck(ZoneFinder::FindResultFlags expected_flags =
  82. ZoneFinder::RESULT_DEFAULT,
  83. ZoneFinder::FindOptions find_options =
  84. ZoneFinder::FIND_DEFAULT);
  85. void anyWildcardCheck(ZoneFinder::FindResultFlags expected_flags =
  86. ZoneFinder::RESULT_DEFAULT);
  87. void emptyWildcardCheck(ZoneFinder::FindResultFlags expected_flags =
  88. ZoneFinder::RESULT_DEFAULT);
  89. void findNSECENTCheck(const Name& ent_name,
  90. ConstRRsetPtr expected_nsec,
  91. ZoneFinder::FindResultFlags expected_flags =
  92. ZoneFinder::RESULT_DEFAULT);
  93. public:
  94. InMemoryZoneFinderTest() :
  95. class_(RRClass::IN()),
  96. origin_("example.org"),
  97. zone_data_(ZoneData::create(mem_sgmt_, origin_)),
  98. zone_finder_(*zone_data_, class_),
  99. updater_(mem_sgmt_, class_, origin_, *zone_data_)
  100. {
  101. // Build test RRsets. Below, we construct an RRset for
  102. // each textual RR(s) of zone_data, and assign it to the corresponding
  103. // rr_xxx.
  104. // Note that this contains an out-of-zone RR, and due to the
  105. // validation check of masterLoad() used below, we cannot add SOA.
  106. const RRsetData zone_data[] = {
  107. {"example.org. 300 IN NS ns.example.org.", &rr_ns_},
  108. {"example.org. 300 IN A 192.0.2.1", &rr_a_},
  109. {"ns.example.org. 300 IN A 192.0.2.2", &rr_ns_a_},
  110. // This one will place rr_ns_a_ at a zone cut, making it a glue:
  111. {"ns.example.org. 300 IN NS 192.0.2.2", &rr_ns_ns_},
  112. {"ns.example.org. 300 IN AAAA 2001:db8::2", &rr_ns_aaaa_},
  113. {"cname.example.org. 300 IN CNAME canonical.example.org",
  114. &rr_cname_},
  115. {"cname.example.org. 300 IN A 192.0.2.3", &rr_cname_a_},
  116. {"dname.example.org. 300 IN DNAME target.example.org.",
  117. &rr_dname_},
  118. {"dname.example.org. 300 IN A 192.0.2.39", &rr_dname_a_},
  119. {"dname.example.org. 300 IN NS ns.dname.example.org.",
  120. &rr_dname_ns_},
  121. {"example.org. 300 IN DNAME example.com.", &rr_dname_apex_},
  122. {"child.example.org. 300 IN NS ns.child.example.org.",
  123. &rr_child_ns_},
  124. {"child.example.org. 300 IN DS 12345 5 1 DEADBEEF",
  125. &rr_child_ds_},
  126. {"ns.child.example.org. 300 IN A 192.0.2.153",
  127. &rr_child_glue_},
  128. {"grand.child.example.org. 300 IN NS ns.grand.child.example.org.",
  129. &rr_grandchild_ns_},
  130. {"ns.grand.child.example.org. 300 IN AAAA 2001:db8::253",
  131. &rr_grandchild_glue_},
  132. {"dname.child.example.org. 300 IN DNAME example.com.",
  133. &rr_child_dname_},
  134. {"example.com. 300 IN A 192.0.2.10", &rr_out_},
  135. {"*.wild.example.org. 300 IN A 192.0.2.1", &rr_wild_},
  136. {"*.cnamewild.example.org. 300 IN CNAME canonial.example.org.",
  137. &rr_cnamewild_},
  138. {"foo.wild.example.org. 300 IN A 192.0.2.3", &rr_under_wild_},
  139. {"wild.*.foo.example.org. 300 IN A 192.0.2.1", &rr_emptywild_},
  140. {"wild.*.foo.*.bar.example.org. 300 IN A 192.0.2.1",
  141. &rr_nested_emptywild_},
  142. {"*.nswild.example.org. 300 IN NS nswild.example.", &rr_nswild_},
  143. {"*.dnamewild.example.org. 300 IN DNAME dnamewild.example.",
  144. &rr_dnamewild_},
  145. {"*.child.example.org. 300 IN A 192.0.2.1", &rr_child_wild_},
  146. {"bar.foo.wild.example.org. 300 IN A 192.0.2.2", &rr_not_wild_},
  147. {"baz.foo.wild.example.org. 300 IN A 192.0.2.3",
  148. &rr_not_wild_another_},
  149. {"0P9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM.example.org. 300 IN "
  150. "NSEC3 1 1 12 aabbccdd 2T7B4G4VSA5SMI47K61MV5BV1A22BOJR A RRSIG",
  151. &rr_nsec3_},
  152. {"example.org. 300 IN NSEC wild.*.foo.example.org. "
  153. "NS SOA RRSIG NSEC DNSKEY", &rr_nsec_},
  154. // Together with the apex NSEC, these next NSECs make a complete
  155. // chain in the case of the zone for the emptyNonterminal tests
  156. // (We may want to clean up this generator code and/or masterLoad
  157. // so that we can prepare conflicting datasets better)
  158. {"wild.*.foo.example.org. 3600 IN NSEC ns.example.org. "
  159. "A RRSIG NSEC", &rr_ent_nsec2_},
  160. {"ns.example.org. 3600 IN NSEC foo.wild.example.org. A RRSIG NSEC",
  161. &rr_ent_nsec3_},
  162. {"foo.wild.example.org. 3600 IN NSEC example.org. A RRSIG NSEC",
  163. &rr_ent_nsec4_},
  164. // And these are NSECs used in different tests
  165. {"ns.example.org. 300 IN NSEC *.nswild.example.org. A AAAA NSEC",
  166. &rr_ns_nsec_},
  167. {"*.wild.example.org. 300 IN NSEC foo.wild.example.org. A NSEC",
  168. &rr_wild_nsec_},
  169. {NULL, NULL}
  170. };
  171. for (unsigned int i = 0; zone_data[i].text != NULL; ++i) {
  172. *zone_data[i].rrset = textToRRset(zone_data[i].text);
  173. }
  174. }
  175. ~InMemoryZoneFinderTest() {
  176. // Make sure we reset the hash creator to the default
  177. setNSEC3HashCreator(NULL);
  178. ZoneData::destroy(mem_sgmt_, zone_data_, RRClass::IN());
  179. }
  180. void addToZoneData(const ConstRRsetPtr rrset) {
  181. updater_.add(rrset, rrset->getRRsig());
  182. }
  183. // Some data to test with
  184. const RRClass class_;
  185. const Name origin_;
  186. // The zone finder to torture by tests
  187. MemorySegmentTest mem_sgmt_;
  188. memory::ZoneData* zone_data_;
  189. memory::InMemoryZoneFinder zone_finder_;
  190. ZoneDataUpdater updater_;
  191. // Placeholder for storing RRsets to be checked with rrsetsCheck()
  192. vector<ConstRRsetPtr> actual_rrsets_;
  193. /*
  194. * Some RRsets to put inside the zone.
  195. */
  196. RRsetPtr
  197. // Out of zone RRset
  198. rr_out_,
  199. // NS of example.org
  200. rr_ns_,
  201. // A of ns.example.org
  202. rr_ns_a_,
  203. // AAAA of ns.example.org
  204. rr_ns_aaaa_,
  205. // A of example.org
  206. rr_a_;
  207. RRsetPtr rr_ns_ns_; // used to make rr_ns_a_ a glue.
  208. RRsetPtr rr_cname_; // CNAME in example.org (RDATA will be added)
  209. RRsetPtr rr_cname_a_; // for mixed CNAME + A case
  210. RRsetPtr rr_dname_; // DNAME in example.org (RDATA will be added)
  211. RRsetPtr rr_dname_a_; // for mixed DNAME + A case
  212. RRsetPtr rr_dname_ns_; // for mixed DNAME + NS case
  213. RRsetPtr rr_dname_apex_; // for mixed DNAME + NS case in the apex
  214. RRsetPtr rr_child_ns_; // NS of a child domain (for delegation)
  215. RRsetPtr rr_child_ds_; // DS of a child domain (for delegation, auth data)
  216. RRsetPtr rr_child_glue_; // glue RR of the child domain
  217. RRsetPtr rr_grandchild_ns_; // NS below a zone cut (unusual)
  218. RRsetPtr rr_grandchild_glue_; // glue RR below a deeper zone cut
  219. RRsetPtr rr_child_dname_; // A DNAME under NS
  220. RRsetPtr rr_wild_; // Wildcard record
  221. RRsetPtr rr_cnamewild_; // CNAME at a wildcard
  222. RRsetPtr rr_emptywild_;
  223. RRsetPtr rr_nested_emptywild_;
  224. RRsetPtr rr_nswild_, rr_dnamewild_;
  225. RRsetPtr rr_child_wild_;
  226. RRsetPtr rr_under_wild_;
  227. RRsetPtr rr_not_wild_;
  228. RRsetPtr rr_not_wild_another_;
  229. RRsetPtr rr_nsec3_;
  230. RRsetPtr rr_nsec_;
  231. RRsetPtr rr_ent_nsec2_;
  232. RRsetPtr rr_ent_nsec3_;
  233. RRsetPtr rr_ent_nsec4_;
  234. RRsetPtr rr_ns_nsec_;
  235. RRsetPtr rr_wild_nsec_;
  236. /**
  237. * \brief Test one find query to the zone finder.
  238. *
  239. * Asks a query to the zone finder and checks it does not throw and returns
  240. * expected results. It returns nothing, it just signals failures
  241. * to GTEST.
  242. *
  243. * \param name The name to ask for.
  244. * \param rrtype The RRType to ask of.
  245. * \param result The expected code of the result.
  246. * \param check_answer Should a check against equality of the answer be
  247. * done?
  248. * \param answer The expected rrset, if any should be returned.
  249. * \param expected_flags The expected result flags returned via find().
  250. * These can be tested using isWildcard() etc.
  251. * \param zone_finder Check different InMemoryZoneFinder object than
  252. * zone_finder_ (if NULL, uses zone_finder_)
  253. * \param check_wild_answer Checks that the answer has the same RRs, type
  254. * class and TTL as the eqxpected answer and that the name corresponds
  255. * to the one searched. It is meant for checking answers for wildcard
  256. * queries.
  257. */
  258. void findTest(const Name& name, const RRType& rrtype,
  259. ZoneFinder::Result result,
  260. bool check_answer = true,
  261. const ConstRRsetPtr& answer = ConstRRsetPtr(),
  262. ZoneFinder::FindResultFlags expected_flags =
  263. ZoneFinder::RESULT_DEFAULT,
  264. memory::InMemoryZoneFinder* zone_finder = NULL,
  265. ZoneFinder::FindOptions options = ZoneFinder::FIND_DEFAULT,
  266. bool check_wild_answer = false)
  267. {
  268. SCOPED_TRACE("findTest for " + name.toText() + "/" + rrtype.toText());
  269. if (zone_finder == NULL) {
  270. zone_finder = &zone_finder_;
  271. }
  272. const ConstRRsetPtr answer_sig = answer ? answer->getRRsig() :
  273. RRsetPtr(); // note we use the same type as of retval of getRRsig()
  274. // The whole block is inside, because we need to check the result and
  275. // we can't assign to FindResult
  276. EXPECT_NO_THROW({
  277. ZoneFinderContextPtr find_result(zone_finder->find(
  278. name, rrtype, options));
  279. // Check it returns correct answers
  280. EXPECT_EQ(result, find_result->code);
  281. EXPECT_EQ((expected_flags & ZoneFinder::RESULT_WILDCARD) != 0,
  282. find_result->isWildcard());
  283. EXPECT_EQ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED)
  284. != 0, find_result->isNSECSigned());
  285. EXPECT_EQ((expected_flags & ZoneFinder::RESULT_NSEC3_SIGNED)
  286. != 0, find_result->isNSEC3Signed());
  287. if (check_answer) {
  288. if (!answer) {
  289. ASSERT_FALSE(find_result->rrset);
  290. } else {
  291. ASSERT_TRUE(find_result->rrset);
  292. ConstRRsetPtr result_rrset(
  293. convertRRset(find_result->rrset));
  294. rrsetCheck(answer, result_rrset);
  295. if (answer_sig &&
  296. (options & ZoneFinder::FIND_DNSSEC) != 0) {
  297. ASSERT_TRUE(result_rrset->getRRsig());
  298. rrsetCheck(answer_sig, result_rrset->getRRsig());
  299. } else {
  300. EXPECT_FALSE(result_rrset->getRRsig());
  301. }
  302. }
  303. } else if (check_wild_answer) {
  304. ASSERT_NE(ConstRRsetPtr(), answer) <<
  305. "Wrong test, don't check for wild names if you expect "
  306. "empty answer";
  307. ASSERT_NE(ConstRRsetPtr(), find_result->rrset) <<
  308. "No answer found";
  309. // Build the expected answer using the given name and
  310. // other parameter of the base wildcard RRset.
  311. RRsetPtr wildanswer(new RRset(name, answer->getClass(),
  312. answer->getType(),
  313. answer->getTTL()));
  314. RdataIteratorPtr expectedIt(answer->getRdataIterator());
  315. for (; !expectedIt->isLast(); expectedIt->next()) {
  316. wildanswer->addRdata(expectedIt->getCurrent());
  317. }
  318. ConstRRsetPtr result_rrset(
  319. convertRRset(find_result->rrset));
  320. rrsetCheck(wildanswer, result_rrset);
  321. // Same for the RRSIG, if any.
  322. if (answer_sig) {
  323. ASSERT_TRUE(result_rrset->getRRsig());
  324. RRsetPtr wildsig(new RRset(name,
  325. answer_sig->getClass(),
  326. RRType::RRSIG(),
  327. answer_sig->getTTL()));
  328. RdataIteratorPtr expectedIt(
  329. answer_sig->getRdataIterator());
  330. for (; !expectedIt->isLast(); expectedIt->next()) {
  331. wildsig->addRdata(expectedIt->getCurrent());
  332. }
  333. rrsetCheck(wildsig, result_rrset->getRRsig());
  334. }
  335. }
  336. });
  337. }
  338. /**
  339. * \brief Calls the findAll on the finder and checks the result.
  340. */
  341. void findAllTest(const Name& name, ZoneFinder::Result result,
  342. const vector<ConstRRsetPtr>& expected_rrsets,
  343. ZoneFinder::FindResultFlags expected_flags =
  344. ZoneFinder::RESULT_DEFAULT,
  345. memory::InMemoryZoneFinder* finder = NULL,
  346. const ConstRRsetPtr &rrset_result = ConstRRsetPtr(),
  347. ZoneFinder::FindOptions options =
  348. ZoneFinder::FIND_DEFAULT)
  349. {
  350. if (finder == NULL) {
  351. finder = &zone_finder_;
  352. }
  353. std::vector<ConstRRsetPtr> target;
  354. ZoneFinderContextPtr find_result(finder->findAll(name, target,
  355. options));
  356. EXPECT_EQ(result, find_result->code);
  357. if (!rrset_result) {
  358. EXPECT_FALSE(find_result->rrset);
  359. } else {
  360. ASSERT_TRUE(find_result->rrset);
  361. rrsetCheck(rrset_result, convertRRset(find_result->rrset));
  362. }
  363. EXPECT_EQ((expected_flags & ZoneFinder::RESULT_WILDCARD) != 0,
  364. find_result->isWildcard());
  365. EXPECT_EQ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED)
  366. != 0, find_result->isNSECSigned());
  367. EXPECT_EQ((expected_flags & ZoneFinder::RESULT_NSEC3_SIGNED)
  368. != 0, find_result->isNSEC3Signed());
  369. // Convert all rrsets to 'full' ones before checking
  370. std::vector<ConstRRsetPtr> converted_rrsets;
  371. BOOST_FOREACH(ConstRRsetPtr cur_rrset, target) {
  372. converted_rrsets.push_back(convertRRset(cur_rrset));
  373. }
  374. rrsetsCheck(expected_rrsets.begin(), expected_rrsets.end(),
  375. converted_rrsets.begin(), converted_rrsets.end());
  376. }
  377. };
  378. /**
  379. * \brief Test InMemoryZoneFinder::InMemoryZoneFinder constructor.
  380. *
  381. * Takes the created zone finder and checks its properties they are the same
  382. * as passed parameters.
  383. */
  384. TEST_F(InMemoryZoneFinderTest, constructor) {
  385. ASSERT_EQ(origin_, zone_finder_.getOrigin());
  386. // Some unusual (abnormal case): if we add a super domain name of the
  387. // zone somehow, the label of the origin node won't be absolute.
  388. // getOrigin() should still be the correct one.
  389. ZoneNode *node;
  390. zone_data_->insertName(mem_sgmt_, Name("org"), &node);
  391. ASSERT_EQ(origin_, zone_finder_.getOrigin());
  392. }
  393. TEST_F(InMemoryZoneFinderTest, findCNAME) {
  394. // install CNAME RR
  395. addToZoneData(rr_cname_);
  396. // Find A RR of the same. Should match the CNAME
  397. findTest(rr_cname_->getName(), RRType::NS(), ZoneFinder::CNAME, true,
  398. rr_cname_);
  399. // Find the CNAME itself. Should result in normal SUCCESS
  400. findTest(rr_cname_->getName(), RRType::CNAME(), ZoneFinder::SUCCESS, true,
  401. rr_cname_);
  402. }
  403. TEST_F(InMemoryZoneFinderTest, findCNAMEUnderZoneCut) {
  404. // There's nothing special when we find a CNAME under a zone cut
  405. // (with FIND_GLUE_OK). The behavior is different from BIND 9,
  406. // so we test this case explicitly.
  407. addToZoneData(rr_child_ns_);
  408. ConstRRsetPtr rr_cname_under_cut_ = textToRRset(
  409. "cname.child.example.org. 300 IN CNAME target.child.example.org.");
  410. addToZoneData(rr_cname_under_cut_);
  411. findTest(Name("cname.child.example.org"), RRType::AAAA(),
  412. ZoneFinder::CNAME, true, rr_cname_under_cut_,
  413. ZoneFinder::RESULT_DEFAULT, NULL, ZoneFinder::FIND_GLUE_OK);
  414. }
  415. // Search under a DNAME record. It should return the DNAME
  416. TEST_F(InMemoryZoneFinderTest, findBelowDNAME) {
  417. EXPECT_NO_THROW(addToZoneData(rr_dname_));
  418. findTest(Name("below.dname.example.org"), RRType::A(), ZoneFinder::DNAME,
  419. true, rr_dname_);
  420. }
  421. // Search at the domain with DNAME. It should act as DNAME isn't there, DNAME
  422. // influences only the data below (see RFC 2672, section 3)
  423. TEST_F(InMemoryZoneFinderTest, findAtDNAME) {
  424. EXPECT_NO_THROW(addToZoneData(rr_dname_));
  425. EXPECT_NO_THROW(addToZoneData(rr_dname_a_));
  426. const Name dname_name(rr_dname_->getName());
  427. findTest(dname_name, RRType::A(), ZoneFinder::SUCCESS, true, rr_dname_a_);
  428. findTest(dname_name, RRType::DNAME(), ZoneFinder::SUCCESS, true,
  429. rr_dname_);
  430. findTest(dname_name, RRType::TXT(), ZoneFinder::NXRRSET, true);
  431. }
  432. // Try searching something that is both under NS and DNAME, without and with
  433. // GLUE_OK mode (it should stop at the NS and DNAME respectively).
  434. TEST_F(InMemoryZoneFinderTest, DNAMEUnderNS) {
  435. addToZoneData(rr_child_ns_);
  436. addToZoneData(rr_child_dname_);
  437. Name lowName("below.dname.child.example.org.");
  438. findTest(lowName, RRType::A(), ZoneFinder::DELEGATION, true, rr_child_ns_);
  439. findTest(lowName, RRType::A(), ZoneFinder::DNAME, true, rr_child_dname_,
  440. ZoneFinder::RESULT_DEFAULT, NULL, ZoneFinder::FIND_GLUE_OK);
  441. }
  442. // Test adding child zones and zone cut handling
  443. TEST_F(InMemoryZoneFinderTest, delegationNS) {
  444. // add in-zone data
  445. EXPECT_NO_THROW(addToZoneData(rr_ns_));
  446. // install a zone cut
  447. EXPECT_NO_THROW(addToZoneData(rr_child_ns_));
  448. // below the zone cut
  449. findTest(Name("www.child.example.org"), RRType::A(),
  450. ZoneFinder::DELEGATION, true, rr_child_ns_);
  451. // at the zone cut
  452. findTest(Name("child.example.org"), RRType::A(), ZoneFinder::DELEGATION,
  453. true, rr_child_ns_);
  454. findTest(Name("child.example.org"), RRType::NS(), ZoneFinder::DELEGATION,
  455. true, rr_child_ns_);
  456. // finding NS for the apex (origin) node. This must not be confused
  457. // with delegation due to the existence of an NS RR.
  458. findTest(origin_, RRType::NS(), ZoneFinder::SUCCESS, true, rr_ns_);
  459. // unusual case of "nested delegation": the highest cut should be used.
  460. EXPECT_NO_THROW(addToZoneData(rr_grandchild_ns_));
  461. findTest(Name("www.grand.child.example.org"), RRType::A(),
  462. // note: !rr_grandchild_ns_
  463. ZoneFinder::DELEGATION, true, rr_child_ns_);
  464. }
  465. TEST_F(InMemoryZoneFinderTest, delegationWithDS) {
  466. // Similar setup to the previous one, but with DS RR at the delegation
  467. // point.
  468. addToZoneData(rr_ns_);
  469. addToZoneData(rr_child_ns_);
  470. addToZoneData(rr_child_ds_);
  471. // Normal types of query should result in delegation, but DS query
  472. // should be considered in-zone (but only exactly at the delegation point).
  473. findTest(Name("child.example.org"), RRType::A(), ZoneFinder::DELEGATION,
  474. true, rr_child_ns_);
  475. findTest(Name("child.example.org"), RRType::DS(), ZoneFinder::SUCCESS,
  476. true, rr_child_ds_);
  477. findTest(Name("grand.child.example.org"), RRType::DS(),
  478. ZoneFinder::DELEGATION, true, rr_child_ns_);
  479. // There's nothing special for DS query at the zone apex. It would
  480. // normally result in NXRRSET.
  481. findTest(Name("example.org"), RRType::DS(), ZoneFinder::NXRRSET,
  482. true, ConstRRsetPtr());
  483. }
  484. TEST_F(InMemoryZoneFinderTest, findAny) {
  485. EXPECT_NO_THROW(addToZoneData(rr_a_));
  486. EXPECT_NO_THROW(addToZoneData(rr_ns_));
  487. EXPECT_NO_THROW(addToZoneData(rr_child_glue_));
  488. vector<ConstRRsetPtr> expected_sets;
  489. // origin
  490. expected_sets.push_back(rr_a_);
  491. expected_sets.push_back(rr_ns_);
  492. findAllTest(origin_, ZoneFinder::SUCCESS, expected_sets);
  493. // out zone name
  494. EXPECT_THROW(findAllTest(Name("example.com"), ZoneFinder::NXDOMAIN,
  495. vector<ConstRRsetPtr>()),
  496. OutOfZone);
  497. expected_sets.clear();
  498. expected_sets.push_back(rr_child_glue_);
  499. findAllTest(rr_child_glue_->getName(), ZoneFinder::SUCCESS, expected_sets);
  500. // add zone cut
  501. EXPECT_NO_THROW(addToZoneData(rr_child_ns_));
  502. // zone cut
  503. findAllTest(rr_child_ns_->getName(), ZoneFinder::DELEGATION,
  504. vector<ConstRRsetPtr>(), ZoneFinder::RESULT_DEFAULT,
  505. NULL, rr_child_ns_);
  506. // glue for this zone cut
  507. findAllTest(rr_child_glue_->getName(),ZoneFinder::DELEGATION,
  508. vector<ConstRRsetPtr>(), ZoneFinder::RESULT_DEFAULT,
  509. NULL, rr_child_ns_);
  510. }
  511. TEST_F(InMemoryZoneFinderTest, glue) {
  512. // install zone data:
  513. // a zone cut
  514. EXPECT_NO_THROW(addToZoneData(rr_child_ns_));
  515. // glue for this cut
  516. EXPECT_NO_THROW(addToZoneData(rr_child_glue_));
  517. // a nested zone cut (unusual)
  518. EXPECT_NO_THROW(addToZoneData(rr_grandchild_ns_));
  519. // glue under the deeper zone cut
  520. EXPECT_NO_THROW(addToZoneData(rr_grandchild_glue_));
  521. // glue 'at the' zone cut
  522. EXPECT_NO_THROW(addToZoneData(rr_ns_a_));
  523. EXPECT_NO_THROW(addToZoneData(rr_ns_ns_));
  524. // by default glue is hidden due to the zone cut
  525. findTest(rr_child_glue_->getName(), RRType::A(), ZoneFinder::DELEGATION,
  526. true, rr_child_ns_);
  527. // If we do it in the "glue OK" mode, we should find the exact match.
  528. findTest(rr_child_glue_->getName(), RRType::A(), ZoneFinder::SUCCESS, true,
  529. rr_child_glue_, ZoneFinder::RESULT_DEFAULT, NULL,
  530. ZoneFinder::FIND_GLUE_OK);
  531. // glue OK + NXRRSET case
  532. findTest(rr_child_glue_->getName(), RRType::AAAA(), ZoneFinder::NXRRSET,
  533. true, ConstRRsetPtr(), ZoneFinder::RESULT_DEFAULT, NULL,
  534. ZoneFinder::FIND_GLUE_OK);
  535. // glue OK + NXDOMAIN case
  536. findTest(Name("www.child.example.org"), RRType::A(),
  537. ZoneFinder::DELEGATION, true, rr_child_ns_,
  538. ZoneFinder::RESULT_DEFAULT, NULL, ZoneFinder::FIND_GLUE_OK);
  539. // nested cut case. The glue should be found.
  540. findTest(rr_grandchild_glue_->getName(), RRType::AAAA(),
  541. ZoneFinder::SUCCESS,
  542. true, rr_grandchild_glue_, ZoneFinder::RESULT_DEFAULT, NULL,
  543. ZoneFinder::FIND_GLUE_OK);
  544. // A non-existent name in nested cut. This should result in delegation
  545. // at the highest zone cut.
  546. findTest(Name("www.grand.child.example.org"), RRType::TXT(),
  547. ZoneFinder::DELEGATION, true, rr_child_ns_,
  548. ZoneFinder::RESULT_DEFAULT, NULL, ZoneFinder::FIND_GLUE_OK);
  549. // Glue at a zone cut
  550. findTest(Name("ns.example.org"), RRType::A(),
  551. ZoneFinder::DELEGATION, true, rr_ns_ns_);
  552. findTest(Name("ns.example.org"), RRType::A(), ZoneFinder::SUCCESS,
  553. true, rr_ns_a_, ZoneFinder::RESULT_DEFAULT,
  554. NULL, ZoneFinder::FIND_GLUE_OK);
  555. }
  556. /**
  557. * \brief Test searching.
  558. *
  559. * Check it finds or does not find correctly and does not throw exceptions.
  560. */
  561. void
  562. InMemoryZoneFinderTest::findCheck(ZoneFinder::FindResultFlags expected_flags,
  563. ZoneFinder::FindOptions find_options)
  564. {
  565. // Fill some data inside
  566. // Now put all the data we have there. It should throw nothing
  567. rr_a_->addRRsig(createRdata(RRType::RRSIG(), RRClass::IN(),
  568. "A 5 3 3600 20120814220826 20120715220826 "
  569. "1234 example.com. FAKE"));
  570. EXPECT_NO_THROW(addToZoneData(rr_ns_));
  571. EXPECT_NO_THROW(addToZoneData(rr_ns_a_));
  572. EXPECT_NO_THROW(addToZoneData(rr_ns_aaaa_));
  573. EXPECT_NO_THROW(addToZoneData(rr_a_));
  574. if ((expected_flags & ZoneFinder::RESULT_NSEC3_SIGNED) != 0) {
  575. addToZoneData(rr_nsec3_);
  576. zone_data_->setSigned(true);
  577. }
  578. if ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED) != 0) {
  579. addToZoneData(rr_nsec_);
  580. zone_data_->setSigned(true);
  581. }
  582. // These two should be successful
  583. findTest(origin_, RRType::NS(), ZoneFinder::SUCCESS, true, rr_ns_);
  584. findTest(rr_ns_a_->getName(), RRType::A(), ZoneFinder::SUCCESS, true,
  585. rr_ns_a_);
  586. // Similar test for a signed RRset. We should see the RRSIG iff
  587. // FIND_DNSSEC option is specified.
  588. findTest(rr_a_->getName(), RRType::A(), ZoneFinder::SUCCESS, true, rr_a_);
  589. findTest(rr_a_->getName(), RRType::A(), ZoneFinder::SUCCESS, true,
  590. rr_a_, ZoneFinder::RESULT_DEFAULT, NULL, ZoneFinder::FIND_DNSSEC);
  591. // These domains don't exist. (and one is out of the zone). In an
  592. // NSEC-signed zone with DNSSEC records requested, it should return the
  593. // covering NSEC for the query name (the actual NSEC in the test data may
  594. // not really "cover" it, but for the purpose of this test it's okay).
  595. ConstRRsetPtr expected_nsec; // by default it's NULL
  596. if ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED) != 0 &&
  597. (find_options & ZoneFinder::FIND_DNSSEC) != 0) {
  598. expected_nsec = rr_nsec_;
  599. }
  600. // There's no other name between this one and the origin, so when NSEC
  601. // is to be returned it should be the origin NSEC.
  602. findTest(Name("nothere.example.org"), RRType::A(),
  603. ZoneFinder::NXDOMAIN, true, expected_nsec, expected_flags,
  604. NULL, find_options);
  605. // The previous name in the zone is "ns.example.org", but it doesn't
  606. // have an NSEC. It should be skipped and the origin NSEC will be
  607. // returned as the "closest NSEC".
  608. findTest(Name("nxdomain.example.org"), RRType::A(),
  609. ZoneFinder::NXDOMAIN, true, expected_nsec, expected_flags,
  610. NULL, find_options);
  611. EXPECT_THROW(zone_finder_.find(Name("example.net"), RRType::A()),
  612. OutOfZone);
  613. // These domain exist but don't have the provided RRType. For the latter
  614. // one we now add its NSEC (which was delayed so that it wouldn't break
  615. // other cases above).
  616. findTest(origin_, RRType::AAAA(), ZoneFinder::NXRRSET, true,
  617. expected_nsec, expected_flags, NULL, find_options);
  618. if ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED) != 0) {
  619. addToZoneData(rr_ns_nsec_);
  620. zone_data_->setSigned(true);
  621. if ((find_options & ZoneFinder::FIND_DNSSEC) != 0) {
  622. expected_nsec = rr_ns_nsec_;
  623. }
  624. }
  625. findTest(rr_ns_a_->getName(), RRType::NS(), ZoneFinder::NXRRSET, true,
  626. expected_nsec, expected_flags, NULL, find_options);
  627. }
  628. TEST_F(InMemoryZoneFinderTest, find) {
  629. findCheck();
  630. }
  631. TEST_F(InMemoryZoneFinderTest, findNSEC3Signed) {
  632. findCheck(ZoneFinder::RESULT_NSEC3_SIGNED);
  633. }
  634. TEST_F(InMemoryZoneFinderTest, findNSEC3SignedWithDNSSEC) {
  635. // For NSEC3-signed zones, specifying the DNSSEC option shouldn't change
  636. // anything (the NSEC3_SIGNED flag is always set, and no records are
  637. // returned for negative cases regardless).
  638. findCheck(ZoneFinder::RESULT_NSEC3_SIGNED, ZoneFinder::FIND_DNSSEC);
  639. }
  640. TEST_F(InMemoryZoneFinderTest, findNSECSigned) {
  641. // NSEC-signed zone, without requesting DNSSEC (no NSEC should be provided)
  642. findCheck(ZoneFinder::RESULT_NSEC_SIGNED);
  643. }
  644. // Generalized test for Empty Nonterminal (ENT) cases with NSEC
  645. void
  646. InMemoryZoneFinderTest::findNSECENTCheck(const Name& ent_name,
  647. ConstRRsetPtr expected_nsec,
  648. ZoneFinder::FindResultFlags expected_flags)
  649. {
  650. addToZoneData(rr_emptywild_);
  651. addToZoneData(rr_under_wild_);
  652. // Sanity check: Should result in NXRRSET
  653. findTest(ent_name, RRType::A(), ZoneFinder::NXRRSET, true,
  654. ConstRRsetPtr(), expected_flags);
  655. // Sanity check: No NSEC added yet
  656. findTest(ent_name, RRType::A(), ZoneFinder::NXRRSET, true,
  657. ConstRRsetPtr(), expected_flags,
  658. NULL, ZoneFinder::FIND_DNSSEC);
  659. // Now add the NSEC rrs making it a 'complete' zone (in terms of NSEC,
  660. // there are no sigs)
  661. addToZoneData(rr_nsec_);
  662. addToZoneData(rr_ent_nsec2_);
  663. addToZoneData(rr_ent_nsec3_);
  664. addToZoneData(rr_ent_nsec4_);
  665. zone_data_->setSigned(true);
  666. // Should result in NXRRSET, and RESULT_NSEC_SIGNED
  667. findTest(ent_name, RRType::A(), ZoneFinder::NXRRSET, true,
  668. ConstRRsetPtr(),
  669. expected_flags | ZoneFinder::RESULT_NSEC_SIGNED);
  670. // And check for the NSEC if DNSSEC_OK
  671. findTest(ent_name, RRType::A(), ZoneFinder::NXRRSET, true,
  672. expected_nsec, expected_flags | ZoneFinder::RESULT_NSEC_SIGNED,
  673. NULL, ZoneFinder::FIND_DNSSEC);
  674. }
  675. TEST_F(InMemoryZoneFinderTest,findNSECEmptyNonterminal) {
  676. // Non-wildcard case
  677. findNSECENTCheck(Name("wild.example.org"), rr_ent_nsec3_);
  678. }
  679. TEST_F(InMemoryZoneFinderTest, findNSECEmptyNonterminalWildcard) {
  680. // Wildcard case, above actual wildcard
  681. findNSECENTCheck(Name("foo.example.org"), rr_nsec_);
  682. }
  683. TEST_F(InMemoryZoneFinderTest, findNSECEmptyNonterminalAtWildcard) {
  684. // Wildcard case, at actual wildcard
  685. findNSECENTCheck(Name("bar.foo.example.org"), rr_nsec_,
  686. ZoneFinder::RESULT_WILDCARD);
  687. }
  688. TEST_F(InMemoryZoneFinderTest, findNSECSignedWithDNSSEC) {
  689. // NSEC-signed zone, requesting DNSSEC (NSEC should be provided)
  690. findCheck(ZoneFinder::RESULT_NSEC_SIGNED, ZoneFinder::FIND_DNSSEC);
  691. }
  692. void
  693. InMemoryZoneFinderTest::emptyNodeCheck(
  694. ZoneFinder::FindResultFlags expected_flags)
  695. {
  696. /*
  697. * The backend ZoneTree for this test should look like as follows:
  698. * example.org
  699. * |
  700. * baz (empty; easy case)
  701. * / | \
  702. * bar | x.foo ('foo' part is empty; a bit trickier)
  703. * bbb
  704. * /
  705. * aaa
  706. */
  707. // Construct the test zone
  708. const char* const names[] = {
  709. "bar.example.org.", "x.foo.example.org.", "aaa.baz.example.org.",
  710. "bbb.baz.example.org.", NULL};
  711. for (int i = 0; names[i] != NULL; ++i) {
  712. ConstRRsetPtr rrset = textToRRset(string(names[i]) +
  713. " 300 IN A 192.0.2.1");
  714. addToZoneData(rrset);
  715. }
  716. if ((expected_flags & ZoneFinder::RESULT_NSEC3_SIGNED) != 0) {
  717. addToZoneData(rr_nsec3_);
  718. zone_data_->setSigned(true);
  719. }
  720. if ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED) != 0) {
  721. addToZoneData(rr_nsec_);
  722. zone_data_->setSigned(true);
  723. }
  724. // empty node matching, easy case: the node for 'baz' exists with
  725. // no data.
  726. findTest(Name("baz.example.org"), RRType::A(), ZoneFinder::NXRRSET, true,
  727. ConstRRsetPtr(), expected_flags);
  728. // empty node matching, a trickier case: the node for 'foo' is part of
  729. // "x.foo", which should be considered an empty node.
  730. findTest(Name("foo.example.org"), RRType::A(), ZoneFinder::NXRRSET, true,
  731. ConstRRsetPtr(), expected_flags);
  732. // "org" is contained in "example.org", but it shouldn't be treated as
  733. // NXRRSET because it's out of zone.
  734. // Note: basically we don't expect such a query to be performed (the common
  735. // operation is to identify the best matching zone first then perform
  736. // search it), but we shouldn't be confused even in the unexpected case.
  737. EXPECT_THROW(zone_finder_.find(Name("org"), RRType::A()), OutOfZone);
  738. }
  739. TEST_F(InMemoryZoneFinderTest, emptyNode) {
  740. emptyNodeCheck();
  741. }
  742. TEST_F(InMemoryZoneFinderTest, emptyNodeNSEC3) {
  743. emptyNodeCheck(ZoneFinder::RESULT_NSEC3_SIGNED);
  744. }
  745. TEST_F(InMemoryZoneFinderTest, emptyNodeNSEC) {
  746. emptyNodeCheck(ZoneFinder::RESULT_NSEC_SIGNED);
  747. }
  748. /*
  749. * Test that puts a (simple) wildcard into the zone and checks we can
  750. * correctly find the data.
  751. */
  752. void
  753. InMemoryZoneFinderTest::wildcardCheck(
  754. ZoneFinder::FindResultFlags expected_flags,
  755. ZoneFinder::FindOptions find_options)
  756. {
  757. /*
  758. * example.org.
  759. * |
  760. * [cname]wild (not *.wild, should have wild mark)
  761. * |
  762. * *
  763. */
  764. // If the zone is "signed" (detecting it by the NSEC/NSEC3 signed flags),
  765. // add RRSIGs to the records.
  766. if ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED) != 0 ||
  767. (expected_flags & ZoneFinder::RESULT_NSEC3_SIGNED) != 0) {
  768. // Convenience shortcut. The RDATA is not really validatable, but
  769. // it doesn't matter for our tests.
  770. const char* const rrsig_common = "5 3 3600 "
  771. "20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE";
  772. find_options = find_options | ZoneFinder::FIND_DNSSEC;
  773. rr_wild_->addRRsig(textToRRset("*.wild.example.org. 300 IN RRSIG A " +
  774. string(rrsig_common)));
  775. rr_cnamewild_->addRRsig(textToRRset("*.cnamewild.example.org. 300 IN "
  776. "RRSIG CNAME " +
  777. string(rrsig_common)));
  778. }
  779. addToZoneData(rr_wild_);
  780. addToZoneData(rr_cnamewild_);
  781. // If the zone is expected to be "signed" with NSEC3, add an NSEC3.
  782. // (the content of the NSEC3 shouldn't matter)
  783. if ((expected_flags & ZoneFinder::RESULT_NSEC3_SIGNED) != 0) {
  784. addToZoneData(rr_nsec3_);
  785. }
  786. if ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED) != 0) {
  787. addToZoneData(rr_nsec_);
  788. }
  789. // Search at the parent. The parent will not have the A, but it will
  790. // be in the wildcard (so check the wildcard isn't matched at the parent)
  791. {
  792. SCOPED_TRACE("Search at parent");
  793. if ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED) != 0) {
  794. findTest(Name("wild.example.org"), RRType::A(),
  795. ZoneFinder::NXRRSET, true, rr_nsec_, expected_flags,
  796. NULL, find_options);
  797. } else {
  798. findTest(Name("wild.example.org"), RRType::A(),
  799. ZoneFinder::NXRRSET, true, ConstRRsetPtr(),
  800. expected_flags, NULL, find_options);
  801. }
  802. }
  803. // For the test setup of "NSEC-signed" zone, we might expect it will
  804. // be returned with a negative result, either because wildcard match is
  805. // disabled by the search option or because wildcard match is canceled
  806. // per protocol.
  807. ConstRRsetPtr expected_nsec; // by default it's NULL
  808. if ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED) != 0 &&
  809. (find_options & ZoneFinder::FIND_DNSSEC) != 0) {
  810. expected_nsec = rr_nsec_;
  811. }
  812. // Explicitly converting the following to const pointers; some compilers
  813. // would complain about mixed use of const and non const in ?: below.
  814. const ConstRRsetPtr rr_wild = rr_wild_;
  815. const ConstRRsetPtr rr_cnamewild = rr_cnamewild_;
  816. // Search the original name of wildcard
  817. {
  818. SCOPED_TRACE("Search directly at *");
  819. findTest(Name("*.wild.example.org"), RRType::A(), ZoneFinder::SUCCESS,
  820. true, rr_wild_, ZoneFinder::RESULT_DEFAULT, NULL,
  821. find_options);
  822. }
  823. // Below some of the test cases will normally result in a wildcard match;
  824. // if NO_WILDCARD is specified, it should result in NXDOMAIN instead,
  825. // and, when available and requested, the covering NSEC will be returned.
  826. // The following are shortcut parameters to unify these cases.
  827. const bool wild_ok = ((find_options & ZoneFinder::NO_WILDCARD) == 0);
  828. const ZoneFinder::FindResultFlags wild_expected_flags =
  829. wild_ok ? (ZoneFinder::RESULT_WILDCARD | expected_flags) :
  830. expected_flags;
  831. // Search "created" name.
  832. {
  833. SCOPED_TRACE("Search at created child");
  834. findTest(Name("a.wild.example.org"), RRType::A(),
  835. wild_ok ? ZoneFinder::SUCCESS : ZoneFinder::NXDOMAIN, false,
  836. wild_ok ? rr_wild : expected_nsec,
  837. wild_expected_flags, NULL, find_options, wild_ok);
  838. }
  839. // Search name that has CNAME.
  840. {
  841. SCOPED_TRACE("Matching CNAME");
  842. findTest(Name("a.cnamewild.example.org"), RRType::A(),
  843. wild_ok ? ZoneFinder::CNAME : ZoneFinder::NXDOMAIN, false,
  844. wild_ok ? rr_cnamewild : expected_nsec,
  845. wild_expected_flags, NULL, find_options, wild_ok);
  846. }
  847. // Search another created name, this time little bit lower
  848. {
  849. SCOPED_TRACE("Search at created grand-child");
  850. findTest(Name("a.b.wild.example.org"), RRType::A(),
  851. wild_ok ? ZoneFinder::SUCCESS : ZoneFinder::NXDOMAIN, false,
  852. wild_ok ? rr_wild : expected_nsec,
  853. wild_expected_flags, NULL, find_options, wild_ok);
  854. }
  855. addToZoneData(rr_under_wild_);
  856. {
  857. SCOPED_TRACE("Search under non-wildcard");
  858. findTest(Name("bar.foo.wild.example.org"), RRType::A(),
  859. ZoneFinder::NXDOMAIN, true, expected_nsec, expected_flags,
  860. NULL, find_options);
  861. }
  862. // Wildcard match, but no data. We add the additional NSEC at the wildcard
  863. // at this point so that it wouldn't break other tests above. Note also
  864. // that in the NO_WILDCARD case the resulting NSEC is the same. Ideally
  865. // we could use a more tricky setup so we can distinguish these cases,
  866. // but for this purpose it's not bad; what we'd like to test here is that
  867. // wildcard substitution doesn't happen for either case, and the
  868. // NO_WILDCARD effect itself can be checked by the result code (NXDOMAIN).
  869. ConstRRsetPtr expected_wild_nsec; // by default it's NULL
  870. if ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED) != 0) {
  871. addToZoneData(rr_wild_nsec_);
  872. expected_wild_nsec = rr_wild_nsec_;
  873. }
  874. {
  875. SCOPED_TRACE("Search at wildcard, no data");
  876. findTest(Name("a.wild.example.org"), RRType::AAAA(),
  877. wild_ok ? ZoneFinder::NXRRSET : ZoneFinder::NXDOMAIN, true,
  878. wild_ok ? expected_wild_nsec : expected_wild_nsec,
  879. wild_expected_flags, NULL, find_options);
  880. }
  881. }
  882. TEST_F(InMemoryZoneFinderTest, wildcard) {
  883. // Normal case
  884. wildcardCheck();
  885. }
  886. TEST_F(InMemoryZoneFinderTest, wildcardDisabledWithNSEC) {
  887. // Wildcard is disabled. In practice, this is used as part of query
  888. // processing for an NSEC-signed zone, so we test that case specifically.
  889. wildcardCheck(ZoneFinder::RESULT_NSEC_SIGNED, ZoneFinder::NO_WILDCARD);
  890. }
  891. TEST_F(InMemoryZoneFinderTest, wildcardDisabledWithoutNSEC) {
  892. // Similar to the previous once, but check the behavior for a non signed
  893. // zone just in case.
  894. wildcardCheck(ZoneFinder::RESULT_DEFAULT, ZoneFinder::NO_WILDCARD);
  895. }
  896. /*
  897. * Test that we don't match a wildcard if we get under delegation.
  898. * By 4.3.3 of RFC1034:
  899. * "Wildcard RRs do not apply:
  900. * - When the query is in another zone. That is, delegation cancels
  901. * the wildcard defaults."
  902. */
  903. TEST_F(InMemoryZoneFinderTest, delegatedWildcard) {
  904. addToZoneData(rr_child_wild_);
  905. addToZoneData(rr_child_ns_);
  906. {
  907. SCOPED_TRACE("Looking under delegation point");
  908. findTest(Name("a.child.example.org"), RRType::A(),
  909. ZoneFinder::DELEGATION, true, rr_child_ns_);
  910. }
  911. {
  912. SCOPED_TRACE("Looking under delegation point in GLUE_OK mode");
  913. findTest(Name("a.child.example.org"), RRType::A(),
  914. ZoneFinder::DELEGATION, true, rr_child_ns_,
  915. ZoneFinder::RESULT_DEFAULT, NULL, ZoneFinder::FIND_GLUE_OK);
  916. }
  917. }
  918. // Tests combination of wildcard and ANY.
  919. void
  920. InMemoryZoneFinderTest::anyWildcardCheck(
  921. ZoneFinder::FindResultFlags expected_flags)
  922. {
  923. addToZoneData(rr_wild_);
  924. if ((expected_flags & ZoneFinder::RESULT_NSEC3_SIGNED) != 0) {
  925. addToZoneData(rr_nsec3_);
  926. }
  927. if ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED) != 0) {
  928. addToZoneData(rr_nsec_);
  929. }
  930. vector<ConstRRsetPtr> expected_sets;
  931. // First try directly the name (normal match)
  932. {
  933. SCOPED_TRACE("Asking directly for *");
  934. expected_sets.push_back(rr_wild_);
  935. findAllTest(Name("*.wild.example.org"), ZoneFinder::SUCCESS,
  936. expected_sets);
  937. }
  938. // Then a wildcard match
  939. {
  940. SCOPED_TRACE("Asking in the wild way");
  941. expected_sets.clear();
  942. RRsetPtr expected(new RRset(Name("a.wild.example.org"),
  943. rr_wild_->getClass(), rr_wild_->getType(),
  944. rr_wild_->getTTL()));
  945. expected->addRdata(rr_wild_->getRdataIterator()->getCurrent());
  946. expected_sets.push_back(expected);
  947. findAllTest(Name("a.wild.example.org"), ZoneFinder::SUCCESS,
  948. expected_sets,
  949. ZoneFinder::RESULT_WILDCARD | expected_flags);
  950. }
  951. }
  952. TEST_F(InMemoryZoneFinderTest, anyWildcard) {
  953. anyWildcardCheck();
  954. }
  955. TEST_F(InMemoryZoneFinderTest, anyWildcardNSEC3) {
  956. anyWildcardCheck(ZoneFinder::RESULT_NSEC3_SIGNED);
  957. }
  958. TEST_F(InMemoryZoneFinderTest, anyWildcardNSEC) {
  959. anyWildcardCheck(ZoneFinder::RESULT_NSEC_SIGNED);
  960. }
  961. // Test there's nothing in the wildcard in the middle if we load
  962. // wild.*.foo.example.org.
  963. void
  964. InMemoryZoneFinderTest::emptyWildcardCheck(
  965. ZoneFinder::FindResultFlags expected_flags)
  966. {
  967. /*
  968. * example.org.
  969. * foo
  970. * *
  971. * wild
  972. */
  973. addToZoneData(rr_emptywild_);
  974. if ((expected_flags & ZoneFinder::RESULT_NSEC3_SIGNED) != 0) {
  975. addToZoneData(rr_nsec3_);
  976. }
  977. if ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED) != 0) {
  978. addToZoneData(rr_nsec_);
  979. }
  980. {
  981. SCOPED_TRACE("Asking for the original record under wildcard");
  982. findTest(Name("wild.*.foo.example.org"), RRType::A(),
  983. ZoneFinder::SUCCESS, true, rr_emptywild_);
  984. }
  985. {
  986. SCOPED_TRACE("Asking for A record");
  987. findTest(Name("a.foo.example.org"), RRType::A(), ZoneFinder::NXRRSET,
  988. true, ConstRRsetPtr(),
  989. ZoneFinder::RESULT_WILDCARD | expected_flags);
  990. findTest(Name("*.foo.example.org"), RRType::A(), ZoneFinder::NXRRSET,
  991. true, ConstRRsetPtr(), expected_flags);
  992. findTest(Name("foo.example.org"), RRType::A(), ZoneFinder::NXRRSET,
  993. true, ConstRRsetPtr(), expected_flags);
  994. }
  995. {
  996. SCOPED_TRACE("Asking for ANY record");
  997. findAllTest(Name("*.foo.example.org"), ZoneFinder::NXRRSET,
  998. vector<ConstRRsetPtr>(), expected_flags);
  999. findAllTest(Name("a.foo.example.org"), ZoneFinder::NXRRSET,
  1000. vector<ConstRRsetPtr>(),
  1001. ZoneFinder::RESULT_WILDCARD | expected_flags);
  1002. }
  1003. {
  1004. SCOPED_TRACE("Asking on the non-terminal");
  1005. findTest(Name("wild.bar.foo.example.org"), RRType::A(),
  1006. ZoneFinder::NXRRSET, true, ConstRRsetPtr(),
  1007. ZoneFinder::RESULT_WILDCARD | expected_flags);
  1008. }
  1009. }
  1010. TEST_F(InMemoryZoneFinderTest, emptyWildcard) {
  1011. emptyWildcardCheck();
  1012. }
  1013. TEST_F(InMemoryZoneFinderTest, emptyWildcardNSEC3) {
  1014. emptyWildcardCheck(ZoneFinder::RESULT_NSEC3_SIGNED);
  1015. }
  1016. TEST_F(InMemoryZoneFinderTest, emptyWildcardNSEC) {
  1017. emptyWildcardCheck(ZoneFinder::RESULT_NSEC_SIGNED);
  1018. }
  1019. // Same as emptyWildcard, but with multiple * in the path.
  1020. TEST_F(InMemoryZoneFinderTest, nestedEmptyWildcard) {
  1021. addToZoneData(rr_nested_emptywild_);
  1022. {
  1023. SCOPED_TRACE("Asking for the original record under wildcards");
  1024. findTest(Name("wild.*.foo.*.bar.example.org"), RRType::A(),
  1025. ZoneFinder::SUCCESS, true, rr_nested_emptywild_);
  1026. }
  1027. {
  1028. SCOPED_TRACE("Matching wildcard against empty nonterminal");
  1029. const char* names[] = {
  1030. "baz.foo.*.bar.example.org",
  1031. "baz.foo.baz.bar.example.org",
  1032. "*.foo.baz.bar.example.org",
  1033. NULL
  1034. };
  1035. for (const char** name = names; *name != NULL; ++ name) {
  1036. SCOPED_TRACE(string("Node ") + *name);
  1037. findTest(Name(*name), RRType::A(), ZoneFinder::NXRRSET, true,
  1038. ConstRRsetPtr(), ZoneFinder::RESULT_WILDCARD);
  1039. }
  1040. }
  1041. // Domains to test
  1042. const char* names[] = {
  1043. "*.foo.*.bar.example.org",
  1044. "foo.*.bar.example.org",
  1045. "*.bar.example.org",
  1046. "bar.example.org",
  1047. NULL
  1048. };
  1049. {
  1050. SCOPED_TRACE("Asking directly for A on parent nodes");
  1051. for (const char** name = names; *name != NULL; ++ name) {
  1052. SCOPED_TRACE(string("Node ") + *name);
  1053. findTest(Name(*name), RRType::A(), ZoneFinder::NXRRSET);
  1054. }
  1055. }
  1056. {
  1057. SCOPED_TRACE("Asking for ANY on parent nodes");
  1058. for (const char** name = names; *name != NULL; ++ name) {
  1059. SCOPED_TRACE(string("Node ") + *name);
  1060. findAllTest(Name(*name), ZoneFinder::NXRRSET,
  1061. vector<ConstRRsetPtr>());
  1062. }
  1063. }
  1064. }
  1065. // We run this part twice from the below test, in two slightly different
  1066. // situations
  1067. void
  1068. InMemoryZoneFinderTest::doCancelWildcardCheck(
  1069. ZoneFinder::FindResultFlags expected_flags,
  1070. ZoneFinder::FindOptions find_options)
  1071. {
  1072. // These should be canceled
  1073. {
  1074. SCOPED_TRACE("Canceled under foo.wild.example.org");
  1075. // For an NSEC-signed zone with DNSSEC requested, the covering NSEC
  1076. // should be returned. The expected NSEC is actually just the only
  1077. // NSEC in the test data, but in this context it doesn't matter;
  1078. // it's sufficient just to check any NSEC is returned (or not).
  1079. ConstRRsetPtr expected_nsec; // by default it's NULL
  1080. if ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED) != 0 &&
  1081. (find_options & ZoneFinder::FIND_DNSSEC)) {
  1082. expected_nsec = rr_nsec_;
  1083. }
  1084. findTest(Name("aaa.foo.wild.example.org"), RRType::A(),
  1085. ZoneFinder::NXDOMAIN, true, expected_nsec, expected_flags,
  1086. NULL, find_options);
  1087. findTest(Name("zzz.foo.wild.example.org"), RRType::A(),
  1088. ZoneFinder::NXDOMAIN, true, expected_nsec, expected_flags,
  1089. NULL, find_options);
  1090. }
  1091. // This is existing, non-wildcard domain, shouldn't wildcard at all
  1092. {
  1093. SCOPED_TRACE("Existing domain under foo.wild.example.org");
  1094. findTest(Name("bar.foo.wild.example.org"), RRType::A(),
  1095. ZoneFinder::SUCCESS, true, rr_not_wild_);
  1096. }
  1097. // These should be caught by the wildcard
  1098. {
  1099. SCOPED_TRACE("Neighbor wildcards to foo.wild.example.org");
  1100. const char* names[] = {
  1101. "aaa.bbb.wild.example.org",
  1102. "aaa.zzz.wild.example.org",
  1103. "zzz.wild.example.org",
  1104. NULL
  1105. };
  1106. for (const char** name = names; *name != NULL; ++ name) {
  1107. SCOPED_TRACE(string("Node ") + *name);
  1108. findTest(Name(*name), RRType::A(), ZoneFinder::SUCCESS, false,
  1109. rr_wild_,
  1110. ZoneFinder::RESULT_WILDCARD | expected_flags, NULL,
  1111. ZoneFinder::FIND_DEFAULT, true);
  1112. }
  1113. }
  1114. // This shouldn't be wildcarded, it's an existing domain
  1115. {
  1116. SCOPED_TRACE("The foo.wild.example.org itself");
  1117. findTest(Name("foo.wild.example.org"), RRType::A(),
  1118. ZoneFinder::NXRRSET, true, ConstRRsetPtr(), expected_flags);
  1119. }
  1120. }
  1121. /*
  1122. * This tests that if there's a name between the wildcard domain and the
  1123. * searched one, it will not trigger wildcard, for example, if we have
  1124. * *.wild.example.org and bar.foo.wild.example.org, then we know
  1125. * foo.wild.example.org exists and is not wildcard. Therefore, search for
  1126. * aaa.foo.wild.example.org should return NXDOMAIN.
  1127. *
  1128. * Tests few cases "around" the canceled wildcard match, to see something that
  1129. * shouldn't be canceled isn't.
  1130. */
  1131. TEST_F(InMemoryZoneFinderTest, cancelWildcard) {
  1132. addToZoneData(rr_wild_);
  1133. addToZoneData(rr_not_wild_);
  1134. {
  1135. SCOPED_TRACE("Runnig with single entry under foo.wild.example.org");
  1136. doCancelWildcardCheck();
  1137. }
  1138. // Try putting another one under foo.wild....
  1139. // The result should be the same but it will be done in another way in the
  1140. // code, because the foo.wild.example.org will exist in the tree.
  1141. addToZoneData(rr_not_wild_another_);
  1142. {
  1143. SCOPED_TRACE("Runnig with two entries under foo.wild.example.org");
  1144. doCancelWildcardCheck();
  1145. }
  1146. }
  1147. // Same tests as cancelWildcard for NSEC3-signed zone
  1148. TEST_F(InMemoryZoneFinderTest, cancelWildcardNSEC3) {
  1149. addToZoneData(rr_wild_);
  1150. addToZoneData(rr_not_wild_);
  1151. addToZoneData(rr_nsec3_);
  1152. {
  1153. SCOPED_TRACE("Runnig with single entry under foo.wild.example.org");
  1154. doCancelWildcardCheck(ZoneFinder::RESULT_NSEC3_SIGNED);
  1155. }
  1156. addToZoneData(rr_not_wild_another_);
  1157. {
  1158. SCOPED_TRACE("Runnig with two entries under foo.wild.example.org");
  1159. doCancelWildcardCheck(ZoneFinder::RESULT_NSEC3_SIGNED);
  1160. }
  1161. }
  1162. // Same tests as cancelWildcard for NSEC-signed zone. Check both cases with
  1163. // or without FIND_DNSSEC option. NSEC should be returned only when the option
  1164. // is given.
  1165. TEST_F(InMemoryZoneFinderTest, cancelWildcardNSEC) {
  1166. addToZoneData(rr_wild_);
  1167. addToZoneData(rr_not_wild_);
  1168. addToZoneData(rr_nsec_);
  1169. {
  1170. SCOPED_TRACE("Runnig with single entry under foo.wild.example.org");
  1171. doCancelWildcardCheck(ZoneFinder::RESULT_NSEC_SIGNED,
  1172. ZoneFinder::FIND_DNSSEC);
  1173. doCancelWildcardCheck(ZoneFinder::RESULT_NSEC_SIGNED);
  1174. }
  1175. addToZoneData(rr_not_wild_another_);
  1176. {
  1177. SCOPED_TRACE("Runnig with two entries under foo.wild.example.org");
  1178. doCancelWildcardCheck(ZoneFinder::RESULT_NSEC_SIGNED,
  1179. ZoneFinder::FIND_DNSSEC);
  1180. doCancelWildcardCheck(ZoneFinder::RESULT_NSEC_SIGNED);
  1181. }
  1182. }
  1183. TEST_F(InMemoryZoneFinderTest, findNSEC3ForBadZone) {
  1184. // Set up the faked hash calculator.
  1185. const TestNSEC3HashCreator creator;
  1186. setNSEC3HashCreator(&creator);
  1187. // If the zone has nothing about NSEC3 (neither NSEC3 or NSEC3PARAM),
  1188. // findNSEC3() should be rejected.
  1189. EXPECT_THROW(zone_finder_.findNSEC3(Name("www.example.org"), true),
  1190. DataSourceError);
  1191. // Only having NSEC3PARAM isn't enough
  1192. addToZoneData(textToRRset("example.org. 300 IN NSEC3PARAM "
  1193. "1 0 12 aabbccdd"));
  1194. EXPECT_THROW(zone_finder_.findNSEC3(Name("www.example.org"), true),
  1195. DataSourceError);
  1196. // Unless NSEC3 for apex is added the result in the recursive mode
  1197. // is guaranteed.
  1198. const string ns1_nsec3_text = string(ns1_hash) + ".example.org." +
  1199. string(nsec3_common);
  1200. addToZoneData(textToRRset(ns1_nsec3_text));
  1201. EXPECT_THROW(zone_finder_.findNSEC3(Name("www.example.org"), true),
  1202. DataSourceError);
  1203. }
  1204. TEST_F(InMemoryZoneFinderTest, findOrphanRRSIG) {
  1205. // Make the zone "NSEC signed"
  1206. addToZoneData(rr_nsec_);
  1207. const ZoneFinder::FindResultFlags expected_flags =
  1208. ZoneFinder::RESULT_NSEC_SIGNED;
  1209. // Add A for ns.example.org, and RRSIG-only covering TXT for the same name.
  1210. // query for the TXT should result in NXRRSET.
  1211. addToZoneData(rr_ns_a_);
  1212. updater_.add(ConstRRsetPtr(),
  1213. textToRRset(
  1214. "ns.example.org. 300 IN RRSIG TXT 5 3 300 20120814220826 "
  1215. "20120715220826 1234 example.com. FAKE"));
  1216. findTest(Name("ns.example.org"), RRType::TXT(),
  1217. ZoneFinder::NXRRSET, true, ConstRRsetPtr(), expected_flags);
  1218. // Add RRSIG-only covering NSEC. This shouldn't be returned when NSEC is
  1219. // requested, whether it's for NXRRSET or NXDOMAIN
  1220. updater_.add(ConstRRsetPtr(),
  1221. textToRRset(
  1222. "ns.example.org. 300 IN RRSIG NSEC 5 3 300 "
  1223. "20120814220826 20120715220826 1234 example.com. FAKE"));
  1224. // The added RRSIG for NSEC could be used for NXRRSET but shouldn't
  1225. findTest(Name("ns.example.org"), RRType::TXT(),
  1226. ZoneFinder::NXRRSET, true, ConstRRsetPtr(),
  1227. expected_flags, NULL, ZoneFinder::FIND_DNSSEC);
  1228. // The added RRSIG for NSEC could be used for NXDOMAIN but shouldn't
  1229. findTest(Name("nz.example.org"), RRType::A(),
  1230. ZoneFinder::NXDOMAIN, true, rr_nsec_,
  1231. expected_flags, NULL, ZoneFinder::FIND_DNSSEC);
  1232. // RRSIG-only CNAME shouldn't be accidentally confused with real CNAME.
  1233. updater_.add(ConstRRsetPtr(),
  1234. textToRRset(
  1235. "nocname.example.org. 300 IN RRSIG CNAME 5 3 300 "
  1236. "20120814220826 20120715220826 1234 example.com. FAKE"));
  1237. findTest(Name("nocname.example.org"), RRType::A(),
  1238. ZoneFinder::NXRRSET, true, ConstRRsetPtr(), expected_flags);
  1239. // RRSIG-only for NS wouldn't invoke delegation anyway, but we check this
  1240. // case explicitly.
  1241. updater_.add(ConstRRsetPtr(),
  1242. textToRRset(
  1243. "nodelegation.example.org. 300 IN RRSIG NS 5 3 300 "
  1244. "20120814220826 20120715220826 1234 example.com. FAKE"));
  1245. findTest(Name("nodelegation.example.org"), RRType::A(),
  1246. ZoneFinder::NXRRSET, true, ConstRRsetPtr(), expected_flags);
  1247. findTest(Name("www.nodelegation.example.org"), RRType::A(),
  1248. ZoneFinder::NXDOMAIN, true, ConstRRsetPtr(), expected_flags);
  1249. // Same for RRSIG-only for DNAME
  1250. updater_.add(ConstRRsetPtr(),
  1251. textToRRset(
  1252. "nodname.example.org. 300 IN RRSIG DNAME 5 3 300 "
  1253. "20120814220826 20120715220826 1234 example.com. FAKE"));
  1254. findTest(Name("www.nodname.example.org"), RRType::A(),
  1255. ZoneFinder::NXDOMAIN, true, ConstRRsetPtr(), expected_flags);
  1256. // If we have a delegation NS at this node, it will be a bit trickier,
  1257. // because the zonecut processing actually takes place at the node.
  1258. // But the RRSIG-only for DNAME shouldn't confuse the process and the NS
  1259. // should win.
  1260. ConstRRsetPtr ns_rrset =
  1261. textToRRset("nodname.example.org. 300 IN NS ns.nodname.example.org.");
  1262. addToZoneData(ns_rrset);
  1263. findTest(Name("www.nodname.example.org"), RRType::A(),
  1264. ZoneFinder::DELEGATION, true, ns_rrset);
  1265. }
  1266. /// \brief NSEC3 specific tests fixture for the InMemoryZoneFinder class
  1267. class InMemoryZoneFinderNSEC3Test : public InMemoryZoneFinderTest {
  1268. public:
  1269. InMemoryZoneFinderNSEC3Test() {
  1270. // Set up the faked hash calculator.
  1271. setNSEC3HashCreator(&creator_);
  1272. // Add a few NSEC3 records:
  1273. // apex (example.org.): hash=0P..
  1274. // ns1.example.org: hash=2T..
  1275. // w.example.org: hash=01..
  1276. // zzz.example.org: hash=R5..
  1277. const string apex_nsec3_text = string(apex_hash) + ".example.org." +
  1278. string(nsec3_common);
  1279. addToZoneData(textToRRset(apex_nsec3_text));
  1280. const string ns1_nsec3_text = string(ns1_hash) + ".example.org." +
  1281. string(nsec3_common);
  1282. addToZoneData(textToRRset(ns1_nsec3_text));
  1283. const string w_nsec3_text = string(w_hash) + ".example.org." +
  1284. string(nsec3_common);
  1285. addToZoneData(textToRRset(w_nsec3_text));
  1286. const string zzz_nsec3_text = string(zzz_hash) + ".example.org." +
  1287. string(nsec3_common);
  1288. addToZoneData(textToRRset(zzz_nsec3_text));
  1289. }
  1290. private:
  1291. const TestNSEC3HashCreator creator_;
  1292. };
  1293. TEST_F(InMemoryZoneFinderNSEC3Test, findNSEC3) {
  1294. performNSEC3Test(zone_finder_);
  1295. }
  1296. struct TestData {
  1297. // String for the name passed to findNSEC3() (concatenated with
  1298. // "example.org.")
  1299. const char* const name;
  1300. // Should recursive findNSEC3() be performed?
  1301. const bool recursive;
  1302. // The following are members of the FindNSEC3Result returned by
  1303. // findNSEC3(). The proofs are given as char*, which are converted
  1304. // to Name objects and checked against getName() on the returned
  1305. // ConstRRsetPtr. If any of these is NULL, then it's expected that
  1306. // ConstRRsetPtr() will be returned.
  1307. const bool matched;
  1308. const uint8_t closest_labels;
  1309. const char* const closest_proof;
  1310. const char* const next_proof;
  1311. };
  1312. const TestData nsec3_data[] = {
  1313. // ==== These are non-recursive tests.
  1314. {"n0", false, false, 4, "R53BQ7CC2UVMUBFU5OCMM6PERS9TK9EN", NULL},
  1315. {"n1", false, true, 4, "01UDEMVP1J2F7EG6JEBPS17VP3N8I58H", NULL},
  1316. {"n2", false, false, 4, "01UDEMVP1J2F7EG6JEBPS17VP3N8I58H", NULL},
  1317. {"n3", false, true, 4, "0P9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM", NULL},
  1318. {"n4", false, false, 4, "0P9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM", NULL},
  1319. {"n5", false, true, 4, "2T7B4G4VSA5SMI47K61MV5BV1A22BOJR", NULL},
  1320. {"n6", false, false, 4, "2T7B4G4VSA5SMI47K61MV5BV1A22BOJR", NULL},
  1321. {"n7", false, true, 4, "R53BQ7CC2UVMUBFU5OCMM6PERS9TK9EN", NULL},
  1322. {"n8", false, false, 4, "R53BQ7CC2UVMUBFU5OCMM6PERS9TK9EN", NULL},
  1323. // ==== These are recursive tests.
  1324. {"n0", true, true, 3, "0P9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM",
  1325. "R53BQ7CC2UVMUBFU5OCMM6PERS9TK9EN"},
  1326. {"n1", true, true, 4, "01UDEMVP1J2F7EG6JEBPS17VP3N8I58H", NULL},
  1327. {"n2", true, true, 3, "0P9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM",
  1328. "01UDEMVP1J2F7EG6JEBPS17VP3N8I58H"},
  1329. {"n3", true, true, 4, "0P9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM", NULL},
  1330. {"n4", true, true, 3, "0P9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM",
  1331. "0P9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM"},
  1332. {"n5", true, true, 4, "2T7B4G4VSA5SMI47K61MV5BV1A22BOJR", NULL},
  1333. {"n6", true, true, 3, "0P9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM",
  1334. "2T7B4G4VSA5SMI47K61MV5BV1A22BOJR"},
  1335. {"n7", true, true, 4, "R53BQ7CC2UVMUBFU5OCMM6PERS9TK9EN", NULL},
  1336. {"n8", true, true, 3, "0P9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM",
  1337. "R53BQ7CC2UVMUBFU5OCMM6PERS9TK9EN"}
  1338. };
  1339. const size_t data_count(sizeof(nsec3_data) / sizeof(*nsec3_data));
  1340. TEST_F(InMemoryZoneFinderNSEC3Test, findNSEC3Walk) {
  1341. // This test basically uses nsec3_data[] declared above along with
  1342. // the fake hash setup to walk the NSEC3 tree. The names and fake
  1343. // hash calculation is specially setup so that the tree search
  1344. // terminates at specific locations in the tree. We findNSEC3() on
  1345. // each of the nsec3_data[], which is setup such that the hash
  1346. // results in the search terminating on either side of each node of
  1347. // the NSEC3 tree. This way, we check what result is returned in
  1348. // every search termination case in the NSEC3 tree.
  1349. const Name origin("example.org");
  1350. for (size_t i = 0; i < data_count; ++i) {
  1351. const Name name = Name(nsec3_data[i].name).concatenate(origin);
  1352. SCOPED_TRACE(name.toText() + (nsec3_data[i].recursive ?
  1353. ", recursive" :
  1354. ", non-recursive"));
  1355. const ZoneFinder::FindNSEC3Result result =
  1356. zone_finder_.findNSEC3(name, nsec3_data[i].recursive);
  1357. EXPECT_EQ(nsec3_data[i].matched, result.matched);
  1358. EXPECT_EQ(nsec3_data[i].closest_labels, result.closest_labels);
  1359. if (nsec3_data[i].closest_proof != NULL) {
  1360. ASSERT_TRUE(result.closest_proof);
  1361. EXPECT_EQ(Name(nsec3_data[i].closest_proof).concatenate(origin),
  1362. result.closest_proof->getName());
  1363. } else {
  1364. EXPECT_FALSE(result.closest_proof);
  1365. }
  1366. if (nsec3_data[i].next_proof != NULL) {
  1367. ASSERT_TRUE(result.next_proof);
  1368. EXPECT_EQ(Name(nsec3_data[i].next_proof).concatenate(origin),
  1369. result.next_proof->getName());
  1370. } else {
  1371. EXPECT_FALSE(result.next_proof);
  1372. }
  1373. }
  1374. }
  1375. TEST_F(InMemoryZoneFinderNSEC3Test, RRSIGOnly) {
  1376. // add an RRSIG-only NSEC3 to the NSEC3 space, and try to find it; it
  1377. // should result in an exception.
  1378. const string n8_hash = "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ";
  1379. updater_.add(ConstRRsetPtr(),
  1380. textToRRset(
  1381. n8_hash + ".example.org. 300 IN RRSIG NSEC3 5 3 300 "
  1382. "20120814220826 20120715220826 1234 example.com. FAKE"));
  1383. EXPECT_THROW(zone_finder_.findNSEC3(Name("n8.example.org"), false),
  1384. DataSourceError);
  1385. }
  1386. }