zone_finder_unittest.cc 73 KB

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