123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232 |
- // Copyright (C) 2010 Internet Systems Consortium, Inc. ("ISC")
- //
- // Permission to use, copy, modify, and/or distribute this software for any
- // purpose with or without fee is hereby granted, provided that the above
- // copyright notice and this permission notice appear in all copies.
- //
- // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
- // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
- // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
- // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
- // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
- // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- // PERFORMANCE OF THIS SOFTWARE.
- #include "faked_nsec3.h"
- #include <exceptions/exceptions.h>
- #include <dns/masterload.h>
- #include <dns/name.h>
- #include <dns/nsec3hash.h>
- #include <dns/rdata.h>
- #include <dns/rdataclass.h>
- #include <dns/rrclass.h>
- #include <dns/rrsetlist.h>
- #include <dns/rrttl.h>
- #include <dns/masterload.h>
- #include <datasrc/client.h>
- #include <datasrc/memory_datasrc.h>
- #include <datasrc/data_source.h>
- #include <datasrc/iterator.h>
- #include "test_client.h"
- #include <testutils/dnsmessage_test.h>
- #include <gtest/gtest.h>
- #include <boost/bind.hpp>
- #include <boost/foreach.hpp>
- #include <boost/shared_ptr.hpp>
- #include <sstream>
- #include <vector>
- using namespace std;
- using namespace isc::dns;
- using namespace isc::dns::rdata;
- using namespace isc::datasrc;
- using namespace isc::testutils;
- using boost::shared_ptr;
- using namespace isc::datasrc::test;
- namespace {
- // Commonly used result codes (Who should write the prefix all the time)
- using result::SUCCESS;
- using result::EXIST;
- class InMemoryClientTest : public ::testing::Test {
- protected:
- InMemoryClientTest() : rrclass(RRClass::IN())
- {}
- RRClass rrclass;
- InMemoryClient memory_client;
- };
- TEST_F(InMemoryClientTest, add_find_Zone) {
- // test add zone
- // Bogus zone (NULL)
- EXPECT_THROW(memory_client.addZone(ZoneFinderPtr()),
- isc::InvalidParameter);
- // add zones with different names one by one
- EXPECT_EQ(result::SUCCESS, memory_client.addZone(
- ZoneFinderPtr(new InMemoryZoneFinder(RRClass::IN(),
- Name("a")))));
- EXPECT_EQ(result::SUCCESS, memory_client.addZone(
- ZoneFinderPtr(new InMemoryZoneFinder(RRClass::CH(),
- Name("b")))));
- EXPECT_EQ(result::SUCCESS, memory_client.addZone(
- ZoneFinderPtr(new InMemoryZoneFinder(RRClass::IN(),
- Name("c")))));
- // add zones with the same name suffix
- EXPECT_EQ(result::SUCCESS, memory_client.addZone(
- ZoneFinderPtr(new InMemoryZoneFinder(RRClass::CH(),
- Name("x.d.e.f")))));
- EXPECT_EQ(result::SUCCESS, memory_client.addZone(
- ZoneFinderPtr(new InMemoryZoneFinder(RRClass::CH(),
- Name("o.w.y.d.e.f")))));
- EXPECT_EQ(result::SUCCESS, memory_client.addZone(
- ZoneFinderPtr(new InMemoryZoneFinder(RRClass::CH(),
- Name("p.w.y.d.e.f")))));
- EXPECT_EQ(result::SUCCESS, memory_client.addZone(
- ZoneFinderPtr(new InMemoryZoneFinder(RRClass::IN(),
- Name("q.w.y.d.e.f")))));
- // add super zone and its subzone
- EXPECT_EQ(result::SUCCESS, memory_client.addZone(
- ZoneFinderPtr(new InMemoryZoneFinder(RRClass::CH(),
- Name("g.h")))));
- EXPECT_EQ(result::SUCCESS, memory_client.addZone(
- ZoneFinderPtr(new InMemoryZoneFinder(RRClass::IN(),
- Name("i.g.h")))));
- EXPECT_EQ(result::SUCCESS, memory_client.addZone(
- ZoneFinderPtr(new InMemoryZoneFinder(RRClass::IN(),
- Name("z.d.e.f")))));
- EXPECT_EQ(result::SUCCESS, memory_client.addZone(
- ZoneFinderPtr(new InMemoryZoneFinder(RRClass::IN(),
- Name("j.z.d.e.f")))));
- // different zone class isn't allowed.
- EXPECT_EQ(result::EXIST, memory_client.addZone(
- ZoneFinderPtr(new InMemoryZoneFinder(RRClass::CH(),
- Name("q.w.y.d.e.f")))));
- // names are compared in a case insensitive manner.
- EXPECT_EQ(result::EXIST, memory_client.addZone(
- ZoneFinderPtr(new InMemoryZoneFinder(RRClass::IN(),
- Name("Q.W.Y.d.E.f")))));
- // test find zone
- EXPECT_EQ(result::SUCCESS, memory_client.findZone(Name("a")).code);
- EXPECT_EQ(Name("a"),
- memory_client.findZone(Name("a")).zone_finder->getOrigin());
- EXPECT_EQ(result::SUCCESS,
- memory_client.findZone(Name("j.z.d.e.f")).code);
- EXPECT_EQ(Name("j.z.d.e.f"),
- memory_client.findZone(Name("j.z.d.e.f")).zone_finder->
- getOrigin());
- // NOTFOUND
- EXPECT_EQ(result::NOTFOUND, memory_client.findZone(Name("d.e.f")).code);
- EXPECT_EQ(ConstZoneFinderPtr(),
- memory_client.findZone(Name("d.e.f")).zone_finder);
- EXPECT_EQ(result::NOTFOUND,
- memory_client.findZone(Name("w.y.d.e.f")).code);
- EXPECT_EQ(ConstZoneFinderPtr(),
- memory_client.findZone(Name("w.y.d.e.f")).zone_finder);
- // there's no exact match. the result should be the longest match,
- // and the code should be PARTIALMATCH.
- EXPECT_EQ(result::PARTIALMATCH,
- memory_client.findZone(Name("j.g.h")).code);
- EXPECT_EQ(Name("g.h"),
- memory_client.findZone(Name("g.h")).zone_finder->getOrigin());
- EXPECT_EQ(result::PARTIALMATCH,
- memory_client.findZone(Name("z.i.g.h")).code);
- EXPECT_EQ(Name("i.g.h"),
- memory_client.findZone(Name("z.i.g.h")).zone_finder->
- getOrigin());
- }
- TEST_F(InMemoryClientTest, iterator) {
- // Just some preparations of data
- boost::shared_ptr<InMemoryZoneFinder>
- zone(new InMemoryZoneFinder(RRClass::IN(), Name("a")));
- RRsetPtr aRRsetA(new RRset(Name("a"), RRClass::IN(), RRType::A(),
- RRTTL(300)));
- aRRsetA->addRdata(rdata::in::A("192.0.2.1"));
- RRsetPtr aRRsetAAAA(new RRset(Name("a"), RRClass::IN(), RRType::AAAA(),
- RRTTL(300)));
- aRRsetAAAA->addRdata(rdata::in::AAAA("2001:db8::1"));
- aRRsetAAAA->addRdata(rdata::in::AAAA("2001:db8::2"));
- RRsetPtr subRRsetA(new RRset(Name("sub.x.a"), RRClass::IN(), RRType::A(),
- RRTTL(300)));
- subRRsetA->addRdata(rdata::in::A("192.0.2.2"));
- EXPECT_EQ(result::SUCCESS, memory_client.addZone(zone));
- // First, the zone is not there, so it should throw
- EXPECT_THROW(memory_client.getIterator(Name("b")), DataSourceError);
- // This zone is not there either, even when there's a zone containing this
- EXPECT_THROW(memory_client.getIterator(Name("x.a")), DataSourceError);
- // Now, an empty zone
- ZoneIteratorPtr iterator(memory_client.getIterator(Name("a")));
- EXPECT_EQ(ConstRRsetPtr(), iterator->getNextRRset());
- // It throws Unexpected when we are past the end
- EXPECT_THROW(iterator->getNextRRset(), isc::Unexpected);
- EXPECT_EQ(result::SUCCESS, zone->add(aRRsetA));
- EXPECT_EQ(result::SUCCESS, zone->add(aRRsetAAAA));
- EXPECT_EQ(result::SUCCESS, zone->add(subRRsetA));
- // Check it with full zone.
- vector<ConstRRsetPtr> expected_rrsets;
- expected_rrsets.push_back(aRRsetA);
- expected_rrsets.push_back(aRRsetAAAA);
- expected_rrsets.push_back(subRRsetA);
- iterator = memory_client.getIterator(Name("a"));
- vector<ConstRRsetPtr> actual_rrsets;
- ConstRRsetPtr actual;
- while ((actual = iterator->getNextRRset()) != NULL) {
- actual_rrsets.push_back(actual);
- }
- rrsetsCheck(expected_rrsets.begin(), expected_rrsets.end(),
- actual_rrsets.begin(), actual_rrsets.end());
- }
- TEST_F(InMemoryClientTest, iterator_separate_rrs) {
- // Exactly the same tests as for iterator, but now with separate_rrs = true
- // For the one that returns actual data, the AAAA should now be split up
- boost::shared_ptr<InMemoryZoneFinder>
- zone(new InMemoryZoneFinder(RRClass::IN(), Name("a")));
- RRsetPtr aRRsetA(new RRset(Name("a"), RRClass::IN(), RRType::A(),
- RRTTL(300)));
- aRRsetA->addRdata(rdata::in::A("192.0.2.1"));
- RRsetPtr aRRsetAAAA(new RRset(Name("a"), RRClass::IN(), RRType::AAAA(),
- RRTTL(300)));
- aRRsetAAAA->addRdata(rdata::in::AAAA("2001:db8::1"));
- aRRsetAAAA->addRdata(rdata::in::AAAA("2001:db8::2"));
- RRsetPtr aRRsetAAAA_r1(new RRset(Name("a"), RRClass::IN(), RRType::AAAA(),
- RRTTL(300)));
- aRRsetAAAA_r1->addRdata(rdata::in::AAAA("2001:db8::1"));
- RRsetPtr aRRsetAAAA_r2(new RRset(Name("a"), RRClass::IN(), RRType::AAAA(),
- RRTTL(300)));
- aRRsetAAAA_r2->addRdata(rdata::in::AAAA("2001:db8::2"));
- RRsetPtr subRRsetA(new RRset(Name("sub.x.a"), RRClass::IN(), RRType::A(),
- RRTTL(300)));
- subRRsetA->addRdata(rdata::in::A("192.0.2.2"));
- EXPECT_EQ(result::SUCCESS, memory_client.addZone(zone));
- // First, the zone is not there, so it should throw
- EXPECT_THROW(memory_client.getIterator(Name("b"), true), DataSourceError);
- // This zone is not there either, even when there's a zone containing this
- EXPECT_THROW(memory_client.getIterator(Name("x.a")), DataSourceError);
- // Now, an empty zone
- ZoneIteratorPtr iterator(memory_client.getIterator(Name("a"), true));
- EXPECT_EQ(ConstRRsetPtr(), iterator->getNextRRset());
- // It throws Unexpected when we are past the end
- EXPECT_THROW(iterator->getNextRRset(), isc::Unexpected);
- ASSERT_EQ(result::SUCCESS, zone->add(aRRsetA));
- ASSERT_EQ(result::SUCCESS, zone->add(aRRsetAAAA));
- ASSERT_EQ(result::SUCCESS, zone->add(subRRsetA));
- // Check it with full zone, one by one.
- // It should be in ascending order in case of InMemory data source
- // (isn't guaranteed in general)
- iterator = memory_client.getIterator(Name("a"), true);
- EXPECT_EQ(aRRsetA->toText(), iterator->getNextRRset()->toText());
- EXPECT_EQ(aRRsetAAAA_r1->toText(), iterator->getNextRRset()->toText());
- EXPECT_EQ(aRRsetAAAA_r2->toText(), iterator->getNextRRset()->toText());
- EXPECT_EQ(subRRsetA->toText(), iterator->getNextRRset()->toText());
- EXPECT_EQ(ConstRRsetPtr(), iterator->getNextRRset());
- }
- TEST_F(InMemoryClientTest, getZoneCount) {
- EXPECT_EQ(0, memory_client.getZoneCount());
- memory_client.addZone(
- ZoneFinderPtr(new InMemoryZoneFinder(rrclass,
- Name("example.com"))));
- EXPECT_EQ(1, memory_client.getZoneCount());
- // duplicate add. counter shouldn't change
- memory_client.addZone(
- ZoneFinderPtr(new InMemoryZoneFinder(rrclass,
- Name("example.com"))));
- EXPECT_EQ(1, memory_client.getZoneCount());
- // add one more
- memory_client.addZone(
- ZoneFinderPtr(new InMemoryZoneFinder(rrclass,
- Name("example.org"))));
- EXPECT_EQ(2, memory_client.getZoneCount());
- }
- TEST_F(InMemoryClientTest, startUpdateZone) {
- EXPECT_THROW(memory_client.getUpdater(Name("example.org"), false),
- isc::NotImplemented);
- }
- // Commonly used RRSIG data
- const char* const rrsig_a_txt =
- "example.org. 300 IN RRSIG A 5 3 3600 20000101000000 20000201000000 12345 "
- "example.org. FAKEFAKEFAKE\n";
- const char* const rrsig_ns_txt =
- "example.org. 300 IN RRSIG NS 5 3 3600 20000101000000 20000201000000 "
- "54321 example.org. FAKEFAKEFAKEFAKE\n";
- // This RRset has two RRSIGs
- const char* const rrsig_aaaa_txt =
- "ns.example.org. 300 IN RRSIG AAAA 5 3 3600 20000101000000 20000201000000 "
- "12345 example.org. FAKEFAKEFAKE\n"
- "ns.example.org. 300 IN RRSIG AAAA 5 3 3600 20000101000000 20000201000000 "
- "54321 example.org. FAKEFAKEFAKEFAKE\n";
- // A helper callback of masterLoad() used in InMemoryZoneFinderTest.
- void
- setRRset(RRsetPtr rrset, vector<RRsetPtr*>::iterator& it) {
- *(*it) = rrset;
- ++it;
- }
- // Some faked NSEC3 hash values commonly used in tests and the faked NSEC3Hash
- // object.
- //
- // For apex (example.org)
- const char* const apex_hash = "0P9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM";
- const char* const apex_hash_lower = "0p9mhaveqvm6t7vbl5lop2u3t2rp3tom";
- // For ns1.example.org
- const char* const ns1_hash = "2T7B4G4VSA5SMI47K61MV5BV1A22BOJR";
- // For w.example.org
- const char* const w_hash = "01UDEMVP1J2F7EG6JEBPS17VP3N8I58H";
- // For x.y.w.example.org (lower-cased)
- const char* const xyw_hash = "2vptu5timamqttgl4luu9kg21e0aor3s";
- // For zzz.example.org.
- const char* const zzz_hash = "R53BQ7CC2UVMUBFU5OCMM6PERS9TK9EN";
- // A simple faked NSEC3 hash calculator with a dedicated creator for it.
- //
- // This is used in some NSEC3-related tests below.
- class TestNSEC3HashCreator : public NSEC3HashCreator {
- class TestNSEC3Hash : public NSEC3Hash {
- private:
- typedef map<Name, string> NSEC3HashMap;
- typedef NSEC3HashMap::value_type NSEC3HashPair;
- NSEC3HashMap map_;
- public:
- TestNSEC3Hash() {
- // Build pre-defined hash
- map_[Name("example.org")] = apex_hash;
- map_[Name("www.example.org")] = "2S9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM";
- map_[Name("xxx.example.org")] = "Q09MHAVEQVM6T7VBL5LOP2U3T2RP3TOM";
- map_[Name("yyy.example.org")] = "0A9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM";
- map_[Name("x.y.w.example.org")] =
- "2VPTU5TIMAMQTTGL4LUU9KG21E0AOR3S";
- map_[Name("y.w.example.org")] = "K8UDEMVP1J2F7EG6JEBPS17VP3N8I58H";
- map_[Name("w.example.org")] = w_hash;
- map_[Name("zzz.example.org")] = zzz_hash;
- map_[Name("smallest.example.org")] =
- "00000000000000000000000000000000";
- map_[Name("largest.example.org")] =
- "UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU";
- }
- virtual string calculate(const Name& name) const {
- const NSEC3HashMap::const_iterator found = map_.find(name);
- if (found != map_.end()) {
- return (found->second);
- }
- isc_throw(isc::Unexpected, "unexpected name for NSEC3 test: "
- << name);
- }
- virtual bool match(const generic::NSEC3PARAM&) const {
- return (true);
- }
- virtual bool match(const generic::NSEC3&) const {
- return (true);
- }
- };
- public:
- virtual NSEC3Hash* create(const generic::NSEC3PARAM&) const {
- return (new TestNSEC3Hash);
- }
- virtual NSEC3Hash* create(const generic::NSEC3&) const {
- return (new TestNSEC3Hash);
- }
- };
- /// \brief Test fixture for the InMemoryZoneFinder class
- class InMemoryZoneFinderTest : public ::testing::Test {
- // A straightforward pair of textual RR(set) and a RRsetPtr variable
- // to store the RRset. Used to build test data below.
- struct RRsetData {
- const char* const text; // textual representation of an RRset
- RRsetPtr* rrset;
- };
- protected:
- // The following sub tests are shared by multiple test cases, changing
- // the zone's DNSSEC status (unsigned, NSEC-signed or NSEC3-signed).
- // expected_flags is set to either RESULT_NSEC_SIGNED or
- // RESULT_NSEC3_SIGNED when it's NSEC/NSEC3 signed respectively and
- // find() is expected to set the corresponding flags.
- // find_options should be set to FIND_DNSSEC for NSEC-signed case when
- // NSEC is expected to be returned.
- void findCheck(ZoneFinder::FindResultFlags expected_flags =
- ZoneFinder::RESULT_DEFAULT,
- ZoneFinder::FindOptions find_options =
- ZoneFinder::FIND_DEFAULT);
- void emptyNodeCheck(ZoneFinder::FindResultFlags expected_flags =
- ZoneFinder::RESULT_DEFAULT);
- void wildcardCheck(ZoneFinder::FindResultFlags expected_flags =
- ZoneFinder::RESULT_DEFAULT,
- ZoneFinder::FindOptions find_options =
- ZoneFinder::FIND_DEFAULT);
- void doCancelWildcardCheck(ZoneFinder::FindResultFlags expected_flags =
- ZoneFinder::RESULT_DEFAULT,
- ZoneFinder::FindOptions find_options =
- ZoneFinder::FIND_DEFAULT);
- void anyWildcardCheck(ZoneFinder::FindResultFlags expected_flags =
- ZoneFinder::RESULT_DEFAULT);
- void emptyWildcardCheck(ZoneFinder::FindResultFlags expected_flags =
- ZoneFinder::RESULT_DEFAULT);
- public:
- InMemoryZoneFinderTest() :
- class_(RRClass::IN()),
- origin_("example.org"),
- zone_finder_(class_, origin_)
- {
- // Build test RRsets. Below, we construct an RRset for
- // each textual RR(s) of zone_data, and assign it to the corresponding
- // rr_xxx.
- // Note that this contains an out-of-zone RR, and due to the
- // validation check of masterLoad() used below, we cannot add SOA.
- const RRsetData zone_data[] = {
- {"example.org. 300 IN NS ns.example.org.", &rr_ns_},
- {"example.org. 300 IN A 192.0.2.1", &rr_a_},
- {"ns.example.org. 300 IN A 192.0.2.2", &rr_ns_a_},
- {"ns.example.org. 300 IN AAAA 2001:db8::2", &rr_ns_aaaa_},
- {"cname.example.org. 300 IN CNAME canonical.example.org",
- &rr_cname_},
- {"cname.example.org. 300 IN A 192.0.2.3", &rr_cname_a_},
- {"dname.example.org. 300 IN DNAME target.example.org.",
- &rr_dname_},
- {"dname.example.org. 300 IN A 192.0.2.39", &rr_dname_a_},
- {"dname.example.org. 300 IN NS ns.dname.example.org.",
- &rr_dname_ns_},
- {"example.org. 300 IN DNAME example.com.", &rr_dname_apex_},
- {"child.example.org. 300 IN NS ns.child.example.org.",
- &rr_child_ns_},
- {"child.example.org. 300 IN DS 12345 5 1 DEADBEEF",
- &rr_child_ds_},
- {"ns.child.example.org. 300 IN A 192.0.2.153",
- &rr_child_glue_},
- {"grand.child.example.org. 300 IN NS ns.grand.child.example.org.",
- &rr_grandchild_ns_},
- {"ns.grand.child.example.org. 300 IN AAAA 2001:db8::253",
- &rr_grandchild_glue_},
- {"dname.child.example.org. 300 IN DNAME example.com.",
- &rr_child_dname_},
- {"example.com. 300 IN A 192.0.2.10", &rr_out_},
- {"*.wild.example.org. 300 IN A 192.0.2.1", &rr_wild_},
- {"*.cnamewild.example.org. 300 IN CNAME canonial.example.org.",
- &rr_cnamewild_},
- {"foo.wild.example.org. 300 IN A 192.0.2.3", &rr_under_wild_},
- {"wild.*.foo.example.org. 300 IN A 192.0.2.1", &rr_emptywild_},
- {"wild.*.foo.*.bar.example.org. 300 IN A 192.0.2.1",
- &rr_nested_emptywild_},
- {"*.nswild.example.org. 300 IN NS nswild.example.", &rr_nswild_},
- {"*.dnamewild.example.org. 300 IN DNAME dnamewild.example.",
- &rr_dnamewild_},
- {"*.child.example.org. 300 IN A 192.0.2.1", &rr_child_wild_},
- {"bar.foo.wild.example.org. 300 IN A 192.0.2.2", &rr_not_wild_},
- {"baz.foo.wild.example.org. 300 IN A 192.0.2.3",
- &rr_not_wild_another_},
- {"0P9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM.example.org. 300 IN "
- "NSEC3 1 1 12 aabbccdd 2T7B4G4VSA5SMI47K61MV5BV1A22BOJR A RRSIG",
- &rr_nsec3_},
- {"example.org. 300 IN NSEC cname.example.org. A NS NSEC",
- &rr_nsec_},
- {"ns.example.org. 300 IN NSEC *.nswild.example.org. A AAAA NSEC",
- &rr_ns_nsec_},
- {NULL, NULL}
- };
- stringstream zone_data_stream;
- vector<RRsetPtr*> rrsets;
- for (unsigned int i = 0; zone_data[i].text != NULL; ++i) {
- zone_data_stream << zone_data[i].text << "\n";
- rrsets.push_back(zone_data[i].rrset);
- }
- masterLoad(zone_data_stream, Name::ROOT_NAME(), class_,
- boost::bind(setRRset, _1, rrsets.begin()));
- }
- ~InMemoryZoneFinderTest() {
- // Make sure we reset the hash creator to the default
- setNSEC3HashCreator(NULL);
- }
- // Some data to test with
- const RRClass class_;
- const Name origin_;
- // The zone finder to torture by tests
- InMemoryZoneFinder zone_finder_;
- // Placeholder for storing RRsets to be checked with rrsetsCheck()
- vector<ConstRRsetPtr> actual_rrsets_;
- /*
- * Some RRsets to put inside the zone.
- */
- RRsetPtr
- // Out of zone RRset
- rr_out_,
- // NS of example.org
- rr_ns_,
- // A of ns.example.org
- rr_ns_a_,
- // AAAA of ns.example.org
- rr_ns_aaaa_,
- // A of example.org
- rr_a_;
- RRsetPtr rr_cname_; // CNAME in example.org (RDATA will be added)
- RRsetPtr rr_cname_a_; // for mixed CNAME + A case
- RRsetPtr rr_dname_; // DNAME in example.org (RDATA will be added)
- RRsetPtr rr_dname_a_; // for mixed DNAME + A case
- RRsetPtr rr_dname_ns_; // for mixed DNAME + NS case
- RRsetPtr rr_dname_apex_; // for mixed DNAME + NS case in the apex
- RRsetPtr rr_child_ns_; // NS of a child domain (for delegation)
- RRsetPtr rr_child_ds_; // DS of a child domain (for delegation, auth data)
- RRsetPtr rr_child_glue_; // glue RR of the child domain
- RRsetPtr rr_grandchild_ns_; // NS below a zone cut (unusual)
- RRsetPtr rr_grandchild_glue_; // glue RR below a deeper zone cut
- RRsetPtr rr_child_dname_; // A DNAME under NS
- RRsetPtr rr_wild_; // Wildcard record
- RRsetPtr rr_cnamewild_; // CNAME at a wildcard
- RRsetPtr rr_emptywild_;
- RRsetPtr rr_nested_emptywild_;
- RRsetPtr rr_nswild_, rr_dnamewild_;
- RRsetPtr rr_child_wild_;
- RRsetPtr rr_under_wild_;
- RRsetPtr rr_not_wild_;
- RRsetPtr rr_not_wild_another_;
- RRsetPtr rr_nsec3_;
- RRsetPtr rr_nsec_;
- RRsetPtr rr_ns_nsec_;
- // A faked NSEC3 hash calculator for convenience.
- // Tests that need to use the faked hashed values should call
- // setNSEC3HashCreator() with a pointer to this variable at the beginning
- // of the test (at least before adding any NSEC3/NSEC3PARAM RR).
- TestNSEC3HashCreator nsec3_hash_creator_;
- /**
- * \brief Test one find query to the zone finder.
- *
- * Asks a query to the zone finder and checks it does not throw and returns
- * expected results. It returns nothing, it just signals failures
- * to GTEST.
- *
- * \param name The name to ask for.
- * \param rrtype The RRType to ask of.
- * \param result The expected code of the result.
- * \param check_answer Should a check against equality of the answer be
- * done?
- * \param answer The expected rrset, if any should be returned.
- * \param expected_flags The expected result flags returned via find().
- * These can be tested using isWildcard() etc.
- * \param zone_finder Check different InMemoryZoneFinder object than
- * zone_finder_ (if NULL, uses zone_finder_)
- * \param check_wild_answer Checks that the answer has the same RRs, type
- * class and TTL as the eqxpected answer and that the name corresponds
- * to the one searched. It is meant for checking answers for wildcard
- * queries.
- */
- void findTest(const Name& name, const RRType& rrtype,
- ZoneFinder::Result result,
- bool check_answer = true,
- const ConstRRsetPtr& answer = ConstRRsetPtr(),
- ZoneFinder::FindResultFlags expected_flags =
- ZoneFinder::RESULT_DEFAULT,
- InMemoryZoneFinder* zone_finder = NULL,
- ZoneFinder::FindOptions options = ZoneFinder::FIND_DEFAULT,
- bool check_wild_answer = false)
- {
- SCOPED_TRACE("findTest for " + name.toText() + "/" + rrtype.toText());
- if (zone_finder == NULL) {
- zone_finder = &zone_finder_;
- }
- const ConstRRsetPtr answer_sig = answer ? answer->getRRsig() :
- RRsetPtr(); // note we use the same type as of retval of getRRsig()
- // The whole block is inside, because we need to check the result and
- // we can't assign to FindResult
- EXPECT_NO_THROW({
- ZoneFinderContextPtr find_result(zone_finder->find(
- name, rrtype, options));
- // Check it returns correct answers
- EXPECT_EQ(result, find_result->code);
- EXPECT_EQ((expected_flags & ZoneFinder::RESULT_WILDCARD) != 0,
- find_result->isWildcard());
- EXPECT_EQ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED)
- != 0, find_result->isNSECSigned());
- EXPECT_EQ((expected_flags & ZoneFinder::RESULT_NSEC3_SIGNED)
- != 0, find_result->isNSEC3Signed());
- if (check_answer) {
- if (!answer) {
- ASSERT_FALSE(find_result->rrset);
- } else {
- ASSERT_TRUE(find_result->rrset);
- rrsetCheck(answer, find_result->rrset);
- if (answer_sig) {
- ASSERT_TRUE(find_result->rrset->getRRsig());
- rrsetCheck(answer_sig,
- find_result->rrset->getRRsig());
- }
- }
- } else if (check_wild_answer) {
- ASSERT_NE(ConstRRsetPtr(), answer) <<
- "Wrong test, don't check for wild names if you expect "
- "empty answer";
- ASSERT_NE(ConstRRsetPtr(), find_result->rrset) <<
- "No answer found";
- // Build the expected answer using the given name and
- // other parameter of the base wildcard RRset.
- RRsetPtr wildanswer(new RRset(name, answer->getClass(),
- answer->getType(),
- answer->getTTL()));
- RdataIteratorPtr expectedIt(answer->getRdataIterator());
- for (; !expectedIt->isLast(); expectedIt->next()) {
- wildanswer->addRdata(expectedIt->getCurrent());
- }
- rrsetCheck(wildanswer, find_result->rrset);
- // Same for the RRSIG, if any.
- if (answer_sig) {
- ASSERT_TRUE(find_result->rrset->getRRsig());
- RRsetPtr wildsig(new RRset(name,
- answer_sig->getClass(),
- RRType::RRSIG(),
- answer_sig->getTTL()));
- RdataIteratorPtr expectedIt(
- answer_sig->getRdataIterator());
- for (; !expectedIt->isLast(); expectedIt->next()) {
- wildsig->addRdata(expectedIt->getCurrent());
- }
- rrsetCheck(wildsig, find_result->rrset->getRRsig());
- }
- }
- });
- }
- /**
- * \brief Calls the findAll on the finder and checks the result.
- */
- void findAllTest(const Name& name, ZoneFinder::Result result,
- const vector<ConstRRsetPtr>& expected_rrsets,
- ZoneFinder::FindResultFlags expected_flags =
- ZoneFinder::RESULT_DEFAULT,
- InMemoryZoneFinder* finder = NULL,
- const ConstRRsetPtr &rrset_result = ConstRRsetPtr(),
- ZoneFinder::FindOptions options =
- ZoneFinder::FIND_DEFAULT)
- {
- if (finder == NULL) {
- finder = &zone_finder_;
- }
- std::vector<ConstRRsetPtr> target;
- ZoneFinderContextPtr find_result(finder->findAll(name, target,
- options));
- EXPECT_EQ(result, find_result->code);
- if (!rrset_result) {
- EXPECT_FALSE(find_result->rrset);
- } else {
- ASSERT_TRUE(find_result->rrset);
- rrsetCheck(rrset_result, find_result->rrset);
- }
- EXPECT_EQ((expected_flags & ZoneFinder::RESULT_WILDCARD) != 0,
- find_result->isWildcard());
- EXPECT_EQ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED)
- != 0, find_result->isNSECSigned());
- EXPECT_EQ((expected_flags & ZoneFinder::RESULT_NSEC3_SIGNED)
- != 0, find_result->isNSEC3Signed());
- rrsetsCheck(expected_rrsets.begin(), expected_rrsets.end(),
- target.begin(), target.end());
- }
- };
- /**
- * \brief Check that findPreviousName throws as it should now.
- */
- TEST_F(InMemoryZoneFinderTest, findPreviousName) {
- EXPECT_THROW(zone_finder_.findPreviousName(Name("www.example.org")),
- isc::NotImplemented);
- }
- /**
- * \brief Test InMemoryZoneFinder::InMemoryZoneFinder constructor.
- *
- * Takes the created zone finder and checks its properties they are the same
- * as passed parameters.
- */
- TEST_F(InMemoryZoneFinderTest, constructor) {
- ASSERT_EQ(class_, zone_finder_.getClass());
- ASSERT_EQ(origin_, zone_finder_.getOrigin());
- }
- /**
- * \brief Test adding.
- *
- * We test that it throws at the correct moments and the correct exceptions.
- * And we test the return value.
- */
- TEST_F(InMemoryZoneFinderTest, add) {
- // This one does not belong to this zone
- EXPECT_THROW(zone_finder_.add(rr_out_), OutOfZone);
- // Test null pointer
- EXPECT_THROW(zone_finder_.add(ConstRRsetPtr()),
- InMemoryZoneFinder::NullRRset);
- // Now put all the data we have there. It should throw nothing
- EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_ns_)));
- EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_ns_a_)));
- EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_ns_aaaa_)));
- EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_a_)));
- // Try putting there something twice, it should be rejected
- EXPECT_NO_THROW(EXPECT_EQ(EXIST, zone_finder_.add(rr_ns_)));
- EXPECT_NO_THROW(EXPECT_EQ(EXIST, zone_finder_.add(rr_ns_a_)));
- }
- TEST_F(InMemoryZoneFinderTest, addMultipleCNAMEs) {
- rr_cname_->addRdata(generic::CNAME("canonical2.example.org."));
- EXPECT_THROW(zone_finder_.add(rr_cname_), InMemoryZoneFinder::AddError);
- }
- TEST_F(InMemoryZoneFinderTest, addCNAMEThenOther) {
- EXPECT_EQ(SUCCESS, zone_finder_.add(rr_cname_));
- EXPECT_THROW(zone_finder_.add(rr_cname_a_), InMemoryZoneFinder::AddError);
- }
- TEST_F(InMemoryZoneFinderTest, addOtherThenCNAME) {
- EXPECT_EQ(SUCCESS, zone_finder_.add(rr_cname_a_));
- EXPECT_THROW(zone_finder_.add(rr_cname_), InMemoryZoneFinder::AddError);
- }
- TEST_F(InMemoryZoneFinderTest, addCNAMEAndDNSSECRecords) {
- // CNAME and RRSIG can coexist
- EXPECT_EQ(SUCCESS, zone_finder_.add(rr_cname_));
- EXPECT_EQ(SUCCESS, zone_finder_.add(
- textToRRset("cname.example.org. 300 IN RRSIG CNAME 5 3 "
- "3600 20000101000000 20000201000000 12345 "
- "example.org. FAKEFAKEFAKE")));
- // Same for NSEC
- EXPECT_EQ(SUCCESS, zone_finder_.add(
- textToRRset("cname.example.org. 300 IN NSEC "
- "dname.example.org. CNAME RRSIG NSEC")));
- // Same as above, but adding NSEC first.
- EXPECT_EQ(SUCCESS, zone_finder_.add(
- textToRRset("cname2.example.org. 300 IN NSEC "
- "dname.example.org. CNAME RRSIG NSEC")));
- EXPECT_EQ(SUCCESS, zone_finder_.add(
- textToRRset("cname2.example.org. 300 IN CNAME c.example.")));
- // If there's another type of RRset with NSEC, it should still fail.
- EXPECT_EQ(SUCCESS, zone_finder_.add(
- textToRRset("cname3.example.org. 300 IN A 192.0.2.1")));
- EXPECT_EQ(SUCCESS, zone_finder_.add(
- textToRRset("cname3.example.org. 300 IN NSEC "
- "dname.example.org. CNAME RRSIG NSEC")));
- EXPECT_THROW(zone_finder_.add(textToRRset("cname3.example.org. 300 "
- "IN CNAME c.example.")),
- InMemoryZoneFinder::AddError);
- }
- TEST_F(InMemoryZoneFinderTest, findCNAME) {
- // install CNAME RR
- EXPECT_EQ(SUCCESS, zone_finder_.add(rr_cname_));
- // Find A RR of the same. Should match the CNAME
- findTest(rr_cname_->getName(), RRType::NS(), ZoneFinder::CNAME, true,
- rr_cname_);
- // Find the CNAME itself. Should result in normal SUCCESS
- findTest(rr_cname_->getName(), RRType::CNAME(), ZoneFinder::SUCCESS, true,
- rr_cname_);
- }
- TEST_F(InMemoryZoneFinderTest, findCNAMEUnderZoneCut) {
- // There's nothing special when we find a CNAME under a zone cut
- // (with FIND_GLUE_OK). The behavior is different from BIND 9,
- // so we test this case explicitly.
- EXPECT_EQ(SUCCESS, zone_finder_.add(rr_child_ns_));
- ConstRRsetPtr rr_cname_under_cut_ = textToRRset(
- "cname.child.example.org. 300 IN CNAME target.child.example.org.");
- EXPECT_EQ(SUCCESS, zone_finder_.add(rr_cname_under_cut_));
- findTest(Name("cname.child.example.org"), RRType::AAAA(),
- ZoneFinder::CNAME, true, rr_cname_under_cut_,
- ZoneFinder::RESULT_DEFAULT, NULL, ZoneFinder::FIND_GLUE_OK);
- }
- // Two DNAMEs at single domain are disallowed by RFC 2672, section 3)
- // Having a CNAME there is disallowed too, but it is tested by
- // addOtherThenCNAME and addCNAMEThenOther.
- TEST_F(InMemoryZoneFinderTest, addMultipleDNAMEs) {
- rr_dname_->addRdata(generic::DNAME("target2.example.org."));
- EXPECT_THROW(zone_finder_.add(rr_dname_), InMemoryZoneFinder::AddError);
- }
- /*
- * These two tests ensure that we can't have DNAME and NS at the same
- * node with the exception of the apex of zone (forbidden by RFC 2672)
- */
- TEST_F(InMemoryZoneFinderTest, addDNAMEThenNS) {
- EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_dname_)));
- EXPECT_THROW(zone_finder_.add(rr_dname_ns_), InMemoryZoneFinder::AddError);
- }
- TEST_F(InMemoryZoneFinderTest, addNSThenDNAME) {
- EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_dname_ns_)));
- EXPECT_THROW(zone_finder_.add(rr_dname_), InMemoryZoneFinder::AddError);
- }
- // It is allowed to have NS and DNAME at apex
- TEST_F(InMemoryZoneFinderTest, DNAMEAndNSAtApex) {
- EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_dname_apex_)));
- EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_ns_)));
- // The NS should be possible to be found, below should be DNAME, not
- // delegation
- findTest(origin_, RRType::NS(), ZoneFinder::SUCCESS, true, rr_ns_);
- findTest(rr_child_ns_->getName(), RRType::A(), ZoneFinder::DNAME, true,
- rr_dname_apex_);
- }
- TEST_F(InMemoryZoneFinderTest, NSAndDNAMEAtApex) {
- EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_ns_)));
- EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_dname_apex_)));
- }
- // TODO: Test (and implement) adding data under DNAME. That is forbidden by
- // 2672 as well.
- // Search under a DNAME record. It should return the DNAME
- TEST_F(InMemoryZoneFinderTest, findBelowDNAME) {
- EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_dname_)));
- findTest(Name("below.dname.example.org"), RRType::A(), ZoneFinder::DNAME,
- true, rr_dname_);
- }
- // Search at the domain with DNAME. It should act as DNAME isn't there, DNAME
- // influences only the data below (see RFC 2672, section 3)
- TEST_F(InMemoryZoneFinderTest, findAtDNAME) {
- EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_dname_)));
- EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_dname_a_)));
- const Name dname_name(rr_dname_->getName());
- findTest(dname_name, RRType::A(), ZoneFinder::SUCCESS, true, rr_dname_a_);
- findTest(dname_name, RRType::DNAME(), ZoneFinder::SUCCESS, true,
- rr_dname_);
- findTest(dname_name, RRType::TXT(), ZoneFinder::NXRRSET, true);
- }
- // Try searching something that is both under NS and DNAME, without and with
- // GLUE_OK mode (it should stop at the NS and DNAME respectively).
- TEST_F(InMemoryZoneFinderTest, DNAMEUnderNS) {
- zone_finder_.add(rr_child_ns_);
- zone_finder_.add(rr_child_dname_);
- Name lowName("below.dname.child.example.org.");
- findTest(lowName, RRType::A(), ZoneFinder::DELEGATION, true, rr_child_ns_);
- findTest(lowName, RRType::A(), ZoneFinder::DNAME, true, rr_child_dname_,
- ZoneFinder::RESULT_DEFAULT, NULL, ZoneFinder::FIND_GLUE_OK);
- }
- // Test adding child zones and zone cut handling
- TEST_F(InMemoryZoneFinderTest, delegationNS) {
- // add in-zone data
- EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_ns_)));
- // install a zone cut
- EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_child_ns_)));
- // below the zone cut
- findTest(Name("www.child.example.org"), RRType::A(),
- ZoneFinder::DELEGATION, true, rr_child_ns_);
- // at the zone cut
- findTest(Name("child.example.org"), RRType::A(), ZoneFinder::DELEGATION,
- true, rr_child_ns_);
- findTest(Name("child.example.org"), RRType::NS(), ZoneFinder::DELEGATION,
- true, rr_child_ns_);
- // finding NS for the apex (origin) node. This must not be confused
- // with delegation due to the existence of an NS RR.
- findTest(origin_, RRType::NS(), ZoneFinder::SUCCESS, true, rr_ns_);
- // unusual case of "nested delegation": the highest cut should be used.
- EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_grandchild_ns_)));
- findTest(Name("www.grand.child.example.org"), RRType::A(),
- // note: !rr_grandchild_ns_
- ZoneFinder::DELEGATION, true, rr_child_ns_);
- }
- TEST_F(InMemoryZoneFinderTest, delegationWithDS) {
- // Similar setup to the previous one, but with DS RR at the delegation
- // point.
- EXPECT_EQ(SUCCESS, zone_finder_.add(rr_ns_));
- EXPECT_EQ(SUCCESS, zone_finder_.add(rr_child_ns_));
- EXPECT_EQ(SUCCESS, zone_finder_.add(rr_child_ds_));
- // Normal types of query should result in delegation, but DS query
- // should be considered in-zone (but only exactly at the delegation point).
- findTest(Name("child.example.org"), RRType::A(), ZoneFinder::DELEGATION,
- true, rr_child_ns_);
- findTest(Name("child.example.org"), RRType::DS(), ZoneFinder::SUCCESS,
- true, rr_child_ds_);
- findTest(Name("grand.child.example.org"), RRType::DS(),
- ZoneFinder::DELEGATION, true, rr_child_ns_);
- // There's nothing special for DS query at the zone apex. It would
- // normally result in NXRRSET.
- findTest(Name("example.org"), RRType::DS(), ZoneFinder::NXRRSET,
- true, ConstRRsetPtr());
- }
- TEST_F(InMemoryZoneFinderTest, findAny) {
- EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_a_)));
- EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_ns_)));
- EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_child_glue_)));
- vector<ConstRRsetPtr> expected_sets;
- // origin
- expected_sets.push_back(rr_a_);
- expected_sets.push_back(rr_ns_);
- findAllTest(origin_, ZoneFinder::SUCCESS, expected_sets);
- // out zone name
- EXPECT_THROW(findAllTest(Name("example.com"), ZoneFinder::NXDOMAIN,
- vector<ConstRRsetPtr>()),
- OutOfZone);
- expected_sets.clear();
- expected_sets.push_back(rr_child_glue_);
- findAllTest(rr_child_glue_->getName(), ZoneFinder::SUCCESS, expected_sets);
- // add zone cut
- EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_child_ns_)));
- // zone cut
- findAllTest(rr_child_ns_->getName(), ZoneFinder::DELEGATION,
- vector<ConstRRsetPtr>(), ZoneFinder::RESULT_DEFAULT,
- NULL, rr_child_ns_);
- // glue for this zone cut
- findAllTest(rr_child_glue_->getName(),ZoneFinder::DELEGATION,
- vector<ConstRRsetPtr>(), ZoneFinder::RESULT_DEFAULT,
- NULL, rr_child_ns_);
- }
- TEST_F(InMemoryZoneFinderTest, glue) {
- // install zone data:
- // a zone cut
- EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_child_ns_)));
- // glue for this cut
- EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_child_glue_)));
- // a nested zone cut (unusual)
- EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_grandchild_ns_)));
- // glue under the deeper zone cut
- EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_grandchild_glue_)));
- // by default glue is hidden due to the zone cut
- findTest(rr_child_glue_->getName(), RRType::A(), ZoneFinder::DELEGATION,
- true, rr_child_ns_);
- // If we do it in the "glue OK" mode, we should find the exact match.
- findTest(rr_child_glue_->getName(), RRType::A(), ZoneFinder::SUCCESS, true,
- rr_child_glue_, ZoneFinder::RESULT_DEFAULT, NULL,
- ZoneFinder::FIND_GLUE_OK);
- // glue OK + NXRRSET case
- findTest(rr_child_glue_->getName(), RRType::AAAA(), ZoneFinder::NXRRSET,
- true, ConstRRsetPtr(), ZoneFinder::RESULT_DEFAULT, NULL,
- ZoneFinder::FIND_GLUE_OK);
- // glue OK + NXDOMAIN case
- findTest(Name("www.child.example.org"), RRType::A(),
- ZoneFinder::DELEGATION, true, rr_child_ns_,
- ZoneFinder::RESULT_DEFAULT, NULL, ZoneFinder::FIND_GLUE_OK);
- // nested cut case. The glue should be found.
- findTest(rr_grandchild_glue_->getName(), RRType::AAAA(),
- ZoneFinder::SUCCESS,
- true, rr_grandchild_glue_, ZoneFinder::RESULT_DEFAULT, NULL,
- ZoneFinder::FIND_GLUE_OK);
- // A non-existent name in nested cut. This should result in delegation
- // at the highest zone cut.
- findTest(Name("www.grand.child.example.org"), RRType::TXT(),
- ZoneFinder::DELEGATION, true, rr_child_ns_,
- ZoneFinder::RESULT_DEFAULT, NULL, ZoneFinder::FIND_GLUE_OK);
- }
- /**
- * \brief Test searching.
- *
- * Check it finds or does not find correctly and does not throw exceptions.
- * \todo This doesn't do any kind of CNAME and so on. If it isn't
- * directly there, it just tells it doesn't exist.
- */
- void
- InMemoryZoneFinderTest::findCheck(ZoneFinder::FindResultFlags expected_flags,
- ZoneFinder::FindOptions find_options)
- {
- // Fill some data inside
- // Now put all the data we have there. It should throw nothing
- EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_ns_)));
- EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_ns_a_)));
- EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_ns_aaaa_)));
- EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_a_)));
- if ((expected_flags & ZoneFinder::RESULT_NSEC3_SIGNED) != 0) {
- EXPECT_EQ(SUCCESS, zone_finder_.add(rr_nsec3_));
- }
- if ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED) != 0) {
- EXPECT_EQ(SUCCESS, zone_finder_.add(rr_nsec_));
- }
- // These two should be successful
- findTest(origin_, RRType::NS(), ZoneFinder::SUCCESS, true, rr_ns_);
- findTest(rr_ns_a_->getName(), RRType::A(), ZoneFinder::SUCCESS, true,
- rr_ns_a_);
- // These domains don't exist. (and one is out of the zone). In an
- // NSEC-signed zone with DNSSEC records requested, it should return the
- // covering NSEC for the query name (the actual NSEC in the test data may
- // not really "cover" it, but for the purpose of this test it's okay).
- ConstRRsetPtr expected_nsec; // by default it's NULL
- if ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED) != 0 &&
- (find_options & ZoneFinder::FIND_DNSSEC) != 0) {
- expected_nsec = rr_nsec_;
- }
- // There's no other name between this one and the origin, so when NSEC
- // is to be returned it should be the origin NSEC.
- findTest(Name("nothere.example.org"), RRType::A(),
- ZoneFinder::NXDOMAIN, true, expected_nsec, expected_flags,
- NULL, find_options);
- // The previous name in the zone is "ns.example.org", but it doesn't
- // have an NSEC. It should be skipped and the origin NSEC will be
- // returned as the "closest NSEC".
- findTest(Name("nxdomain.example.org"), RRType::A(),
- ZoneFinder::NXDOMAIN, true, expected_nsec, expected_flags,
- NULL, find_options);
- EXPECT_THROW(zone_finder_.find(Name("example.net"), RRType::A()),
- OutOfZone);
- // These domain exist but don't have the provided RRType. For the latter
- // one we now add its NSEC (which was delayed so that it wouldn't break
- // other cases above).
- findTest(origin_, RRType::AAAA(), ZoneFinder::NXRRSET, true,
- expected_nsec, expected_flags, NULL, find_options);
- if ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED) != 0) {
- EXPECT_EQ(SUCCESS, zone_finder_.add(rr_ns_nsec_));
- if ((find_options & ZoneFinder::FIND_DNSSEC) != 0) {
- expected_nsec = rr_ns_nsec_;
- }
- }
- findTest(rr_ns_a_->getName(), RRType::NS(), ZoneFinder::NXRRSET, true,
- expected_nsec, expected_flags, NULL, find_options);
- }
- // Test if NSEC works
- TEST_F(InMemoryZoneFinderTest, NSEC4NXRRSET) {
- findTest(origin_, RRType::TXT(), ZoneFinder::NXRRSET, true,
- ConstRRsetPtr());
- EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_nsec_)));
- findTest(origin_, RRType::A(), ZoneFinder::NXRRSET, true,
- rr_nsec_, ZoneFinder::RESULT_NSEC_SIGNED, NULL,
- ZoneFinder::FIND_DNSSEC);
- }
- TEST_F(InMemoryZoneFinderTest, find) {
- findCheck();
- }
- TEST_F(InMemoryZoneFinderTest, findNSEC3Signe) {
- findCheck(ZoneFinder::RESULT_NSEC3_SIGNED);
- }
- TEST_F(InMemoryZoneFinderTest, findNSEC3SignedWithDNSSEC) {
- // For NSEC3-signed zones, specifying the DNSSEC option shouldn't change
- // anything (the NSEC3_SIGNED flag is always set, and no records are
- // returned for negative cases regardless).
- findCheck(ZoneFinder::RESULT_NSEC3_SIGNED, ZoneFinder::FIND_DNSSEC);
- }
- TEST_F(InMemoryZoneFinderTest, findNSECSigned) {
- // NSEC-signed zone, without requesting DNSSEC (no NSEC should be provided)
- findCheck(ZoneFinder::RESULT_NSEC_SIGNED);
- }
- TEST_F(InMemoryZoneFinderTest, findNSECSignedWithDNSSEC) {
- // NSEC-signed zone, requesting DNSSEC (NSEC should be provided)
- findCheck(ZoneFinder::RESULT_NSEC_SIGNED, ZoneFinder::FIND_DNSSEC);
- }
- void
- InMemoryZoneFinderTest::emptyNodeCheck(
- ZoneFinder::FindResultFlags expected_flags)
- {
- /*
- * The backend RBTree for this test should look like as follows:
- * example.org
- * |
- * baz (empty; easy case)
- * / | \
- * bar | x.foo ('foo' part is empty; a bit trickier)
- * bbb
- * /
- * aaa
- */
- // Construct the test zone
- const char* const names[] = {
- "bar.example.org.", "x.foo.example.org.", "aaa.baz.example.org.",
- "bbb.baz.example.org.", NULL};
- for (int i = 0; names[i] != NULL; ++i) {
- ConstRRsetPtr rrset = textToRRset(string(names[i]) +
- " 300 IN A 192.0.2.1");
- EXPECT_EQ(SUCCESS, zone_finder_.add(rrset));
- }
- if ((expected_flags & ZoneFinder::RESULT_NSEC3_SIGNED) != 0) {
- EXPECT_EQ(SUCCESS, zone_finder_.add(rr_nsec3_));
- }
- if ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED) != 0) {
- EXPECT_EQ(SUCCESS, zone_finder_.add(rr_nsec_));
- }
- // empty node matching, easy case: the node for 'baz' exists with
- // no data.
- findTest(Name("baz.example.org"), RRType::A(), ZoneFinder::NXRRSET, true,
- ConstRRsetPtr(), expected_flags);
- // empty node matching, a trickier case: the node for 'foo' is part of
- // "x.foo", which should be considered an empty node.
- findTest(Name("foo.example.org"), RRType::A(), ZoneFinder::NXRRSET, true,
- ConstRRsetPtr(), expected_flags);
- // "org" is contained in "example.org", but it shouldn't be treated as
- // NXRRSET because it's out of zone.
- // Note: basically we don't expect such a query to be performed (the common
- // operation is to identify the best matching zone first then perform
- // search it), but we shouldn't be confused even in the unexpected case.
- EXPECT_THROW(zone_finder_.find(Name("org"), RRType::A()), OutOfZone);
- }
- TEST_F(InMemoryZoneFinderTest, emptyNode) {
- emptyNodeCheck();
- }
- TEST_F(InMemoryZoneFinderTest, emptyNodeNSEC3) {
- emptyNodeCheck(ZoneFinder::RESULT_NSEC3_SIGNED);
- }
- TEST_F(InMemoryZoneFinderTest, emptyNodeNSEC) {
- emptyNodeCheck(ZoneFinder::RESULT_NSEC_SIGNED);
- }
- TEST_F(InMemoryZoneFinderTest, load) {
- // Put some data inside the zone
- EXPECT_NO_THROW(EXPECT_EQ(result::SUCCESS, zone_finder_.add(rr_ns_)));
- // Loading with different origin should fail
- EXPECT_THROW(zone_finder_.load(TEST_DATA_DIR "/root.zone"),
- MasterLoadError);
- // See the original data is still there, survived the exception
- findTest(origin_, RRType::NS(), ZoneFinder::SUCCESS, true, rr_ns_);
- // Create correct zone
- InMemoryZoneFinder rootzone(class_, Name("."));
- // Try putting something inside
- EXPECT_NO_THROW(EXPECT_EQ(result::SUCCESS, rootzone.add(rr_ns_aaaa_)));
- // Load the zone. It should overwrite/remove the above RRset
- EXPECT_NO_THROW(rootzone.load(TEST_DATA_DIR "/root.zone"));
- // Now see there are some rrsets (we don't look inside, though)
- findTest(Name("."), RRType::SOA(), ZoneFinder::SUCCESS, false,
- ConstRRsetPtr(), ZoneFinder::RESULT_DEFAULT, &rootzone);
- findTest(Name("."), RRType::NS(), ZoneFinder::SUCCESS, false,
- ConstRRsetPtr(), ZoneFinder::RESULT_DEFAULT, &rootzone);
- findTest(Name("a.root-servers.net."), RRType::A(), ZoneFinder::SUCCESS,
- false, ConstRRsetPtr(), ZoneFinder::RESULT_DEFAULT, &rootzone);
- // But this should no longer be here
- findTest(rr_ns_a_->getName(), RRType::AAAA(), ZoneFinder::NXDOMAIN, true,
- ConstRRsetPtr(), ZoneFinder::RESULT_DEFAULT, &rootzone);
- // Try loading zone that is wrong in a different way
- EXPECT_THROW(zone_finder_.load(TEST_DATA_DIR "/duplicate_rrset.zone"),
- MasterLoadError);
- }
- TEST_F(InMemoryZoneFinderTest, loadFromIterator) {
- // The initial test set doesn't have SOA at the apex.
- findTest(origin_, RRType::SOA(), ZoneFinder::NXRRSET, false,
- ConstRRsetPtr());
- // The content of the new version of zone to be first installed to
- // the SQLite3 data source, then to in-memory via SQLite3. The data are
- // chosen to cover major check points of the implementation:
- // - the previously non-existent record is added (SOA)
- // - An RRSIG is given from the iterator before the RRset it covers
- // (RRSIG for SOA, because they are sorted by name then rrtype as text)
- // - An RRset containing multiple RRs (ns1/A)
- // - RRSIGs for different owner names
- stringstream ss;
- const char* const soa_txt = "example.org. 300 IN SOA . . 0 0 0 0 0\n";
- const char* const soa_sig_txt = "example.org. 300 IN RRSIG SOA 5 3 300 "
- "20000101000000 20000201000000 12345 example.org. FAKEFAKE\n";
- const char* const a_txt =
- "ns1.example.org. 300 IN A 192.0.2.1\n"
- "ns1.example.org. 300 IN A 192.0.2.2\n";
- const char* const a_sig_txt = "ns1.example.org. 300 IN RRSIG A 5 3 300 "
- "20000101000000 20000201000000 12345 example.org. FAKEFAKE\n";
- ss << soa_txt << soa_sig_txt << a_txt << a_sig_txt;
- shared_ptr<DataSourceClient> db_client = unittest::createSQLite3Client(
- class_, origin_, TEST_DATA_BUILDDIR "/contexttest.sqlite3.copied", ss);
- zone_finder_.load(*db_client->getIterator(origin_));
- // The new content should be visible, including the previously-nonexistent
- // SOA.
- RRsetPtr expected_answer = textToRRset(soa_txt, RRClass::IN(), origin_);
- expected_answer->addRRsig(textToRRset(soa_sig_txt));
- findTest(origin_, RRType::SOA(), ZoneFinder::SUCCESS, true,
- expected_answer);
- expected_answer = textToRRset(a_txt);
- expected_answer->addRRsig(textToRRset(a_sig_txt));
- findTest(Name("ns1.example.org"), RRType::A(), ZoneFinder::SUCCESS, true,
- expected_answer);
- // File name should be (re)set to empty.
- EXPECT_TRUE(zone_finder_.getFileName().empty());
- // Loading the zone with an iterator separating RRs of the same RRset
- // will fail because the resulting sequence doesn't meet assumptions of
- // the (current) in-memory implementation.
- EXPECT_THROW(zone_finder_.load(*db_client->getIterator(origin_, true)),
- MasterLoadError);
- // Load the zone from a file that contains more realistic data (borrowed
- // from a different test). There's nothing special in this case for the
- // purpose of this test, so it should just succeed.
- db_client = unittest::createSQLite3Client(
- class_, origin_, TEST_DATA_BUILDDIR "/contexttest.sqlite3.copied",
- TEST_DATA_DIR "/contexttest.zone");
- zone_finder_.load(*db_client->getIterator(origin_));
- // just checking a couple of RRs in the new version of zone.
- findTest(Name("mx1.example.org"), RRType::A(), ZoneFinder::SUCCESS, true,
- textToRRset("mx1.example.org. 3600 IN A 192.0.2.10"));
- findTest(Name("ns1.example.org"), RRType::AAAA(), ZoneFinder::SUCCESS,
- true, textToRRset("ns1.example.org. 3600 IN AAAA 2001:db8::1"));
- }
- /*
- * Test that puts a (simple) wildcard into the zone and checks we can
- * correctly find the data.
- */
- void
- InMemoryZoneFinderTest::wildcardCheck(
- ZoneFinder::FindResultFlags expected_flags,
- ZoneFinder::FindOptions find_options)
- {
- /*
- * example.org.
- * |
- * [cname]wild (not *.wild, should have wild mark)
- * |
- * *
- */
- // If the zone is "signed" (detecting it by the NSEC/NSEC3 signed flags),
- // add RRSIGs to the records.
- if ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED) != 0 ||
- (expected_flags & ZoneFinder::RESULT_NSEC3_SIGNED) != 0) {
- // Convenience shortcut. The RDATA is not really validatable, but
- // it doesn't matter for our tests.
- const char* const rrsig_common = "5 3 3600 "
- "20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE";
- find_options = find_options | ZoneFinder::FIND_DNSSEC;
- rr_wild_->addRRsig(textToRRset("*.wild.example.org. 300 IN RRSIG A " +
- string(rrsig_common)));
- rr_cnamewild_->addRRsig(textToRRset("*.cnamewild.example.org. 300 IN "
- "RRSIG CNAME " +
- string(rrsig_common)));
- }
- EXPECT_EQ(SUCCESS, zone_finder_.add(rr_wild_));
- EXPECT_EQ(SUCCESS, zone_finder_.add(rr_cnamewild_));
- // If the zone is expected to be "signed" with NSEC3, add an NSEC3.
- // (the content of the NSEC3 shouldn't matter)
- if ((expected_flags & ZoneFinder::RESULT_NSEC3_SIGNED) != 0) {
- EXPECT_EQ(SUCCESS, zone_finder_.add(rr_nsec3_));
- }
- if ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED) != 0) {
- EXPECT_EQ(SUCCESS, zone_finder_.add(rr_nsec_));
- }
- // Search at the parent. The parent will not have the A, but it will
- // be in the wildcard (so check the wildcard isn't matched at the parent)
- {
- SCOPED_TRACE("Search at parent");
- findTest(Name("wild.example.org"), RRType::A(), ZoneFinder::NXRRSET,
- true, ConstRRsetPtr(), expected_flags, NULL, find_options);
- }
- // For the test setup of "NSEC-signed" zone, we might expect it will
- // be returned with a negative result, either because wildcard match is
- // disabled by the search option or because wildcard match is canceled
- // per protocol.
- ConstRRsetPtr expected_nsec; // by default it's NULL
- if ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED) != 0 &&
- (find_options & ZoneFinder::FIND_DNSSEC) != 0) {
- expected_nsec = rr_nsec_;
- }
- // Search the original name of wildcard
- {
- SCOPED_TRACE("Search directly at *");
- findTest(Name("*.wild.example.org"), RRType::A(), ZoneFinder::SUCCESS,
- true, rr_wild_, ZoneFinder::RESULT_DEFAULT, NULL,
- find_options);
- }
- // Below some of the test cases will normally result in a wildcard match;
- // if NO_WILDCARD is specified, it should result in NXDOMAIN instead,
- // and, when available and requested, the covering NSEC will be returned.
- // The following are shortcut parameters to unify these cases.
- const bool wild_ok = ((find_options & ZoneFinder::NO_WILDCARD) == 0);
- const ZoneFinder::FindResultFlags wild_expected_flags =
- wild_ok ? (ZoneFinder::RESULT_WILDCARD | expected_flags) :
- expected_flags;
- // Search "created" name.
- {
- SCOPED_TRACE("Search at created child");
- findTest(Name("a.wild.example.org"), RRType::A(),
- wild_ok ? ZoneFinder::SUCCESS : ZoneFinder::NXDOMAIN, false,
- wild_ok ? rr_wild_ : expected_nsec,
- wild_expected_flags, NULL, find_options, wild_ok);
- // Wildcard match, but no data
- findTest(Name("a.wild.example.org"), RRType::AAAA(),
- wild_ok ? ZoneFinder::NXRRSET : ZoneFinder::NXDOMAIN, true,
- wild_ok ? ConstRRsetPtr() : expected_nsec,
- wild_expected_flags, NULL, find_options);
- }
- // Search name that has CNAME.
- {
- SCOPED_TRACE("Matching CNAME");
- findTest(Name("a.cnamewild.example.org"), RRType::A(),
- wild_ok ? ZoneFinder::CNAME : ZoneFinder::NXDOMAIN, false,
- wild_ok ? rr_cnamewild_ : expected_nsec,
- wild_expected_flags, NULL, find_options, wild_ok);
- }
- // Search another created name, this time little bit lower
- {
- SCOPED_TRACE("Search at created grand-child");
- findTest(Name("a.b.wild.example.org"), RRType::A(),
- wild_ok ? ZoneFinder::SUCCESS : ZoneFinder::NXDOMAIN, false,
- wild_ok ? rr_wild_ : expected_nsec,
- wild_expected_flags, NULL, find_options, wild_ok);
- }
- EXPECT_EQ(SUCCESS, zone_finder_.add(rr_under_wild_));
- {
- SCOPED_TRACE("Search under non-wildcard");
- findTest(Name("bar.foo.wild.example.org"), RRType::A(),
- ZoneFinder::NXDOMAIN, true, expected_nsec, expected_flags,
- NULL, find_options);
- }
- }
- TEST_F(InMemoryZoneFinderTest, wildcard) {
- // Normal case
- wildcardCheck();
- }
- TEST_F(InMemoryZoneFinderTest, wildcardNSEC3) {
- // Similar to the previous one, but the zone signed with NSEC3
- wildcardCheck(ZoneFinder::RESULT_NSEC3_SIGNED);
- }
- TEST_F(InMemoryZoneFinderTest, wildcardNSEC) {
- // Similar to the previous one, but the zone signed with NSEC
- wildcardCheck(ZoneFinder::RESULT_NSEC_SIGNED);
- }
- TEST_F(InMemoryZoneFinderTest, wildcardDisabledWithNSEC) {
- // Wildcard is disabled. In practice, this is used as part of query
- // processing for an NSEC-signed zone, so we test that case specifically.
- wildcardCheck(ZoneFinder::RESULT_NSEC_SIGNED, ZoneFinder::NO_WILDCARD);
- }
- TEST_F(InMemoryZoneFinderTest, wildcardDisabledWithoutNSEC) {
- // Similar to the previous once, but check the behavior for a non signed
- // zone just in case.
- wildcardCheck(ZoneFinder::RESULT_DEFAULT, ZoneFinder::NO_WILDCARD);
- }
- /*
- * Test that we don't match a wildcard if we get under delegation.
- * By 4.3.3 of RFC1034:
- * "Wildcard RRs do not apply:
- * - When the query is in another zone. That is, delegation cancels
- * the wildcard defaults."
- */
- TEST_F(InMemoryZoneFinderTest, delegatedWildcard) {
- EXPECT_EQ(SUCCESS, zone_finder_.add(rr_child_wild_));
- EXPECT_EQ(SUCCESS, zone_finder_.add(rr_child_ns_));
- {
- SCOPED_TRACE("Looking under delegation point");
- findTest(Name("a.child.example.org"), RRType::A(),
- ZoneFinder::DELEGATION, true, rr_child_ns_);
- }
- {
- SCOPED_TRACE("Looking under delegation point in GLUE_OK mode");
- findTest(Name("a.child.example.org"), RRType::A(),
- ZoneFinder::DELEGATION, true, rr_child_ns_,
- ZoneFinder::RESULT_DEFAULT, NULL, ZoneFinder::FIND_GLUE_OK);
- }
- }
- // Tests combination of wildcard and ANY.
- void
- InMemoryZoneFinderTest::anyWildcardCheck(
- ZoneFinder::FindResultFlags expected_flags)
- {
- EXPECT_EQ(SUCCESS, zone_finder_.add(rr_wild_));
- if ((expected_flags & ZoneFinder::RESULT_NSEC3_SIGNED) != 0) {
- EXPECT_EQ(SUCCESS, zone_finder_.add(rr_nsec3_));
- }
- if ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED) != 0) {
- EXPECT_EQ(SUCCESS, zone_finder_.add(rr_nsec_));
- }
- vector<ConstRRsetPtr> expected_sets;
- // First try directly the name (normal match)
- {
- SCOPED_TRACE("Asking direcly for *");
- expected_sets.push_back(rr_wild_);
- findAllTest(Name("*.wild.example.org"), ZoneFinder::SUCCESS,
- expected_sets);
- }
- // Then a wildcard match
- {
- SCOPED_TRACE("Asking in the wild way");
- expected_sets.clear();
- RRsetPtr expected(new RRset(Name("a.wild.example.org"),
- rr_wild_->getClass(), rr_wild_->getType(),
- rr_wild_->getTTL()));
- expected->addRdata(rr_wild_->getRdataIterator()->getCurrent());
- expected_sets.push_back(expected);
- findAllTest(Name("a.wild.example.org"), ZoneFinder::SUCCESS,
- expected_sets,
- ZoneFinder::RESULT_WILDCARD | expected_flags);
- }
- }
- TEST_F(InMemoryZoneFinderTest, anyWildcard) {
- anyWildcardCheck();
- }
- TEST_F(InMemoryZoneFinderTest, anyWildcardNSEC3) {
- anyWildcardCheck(ZoneFinder::RESULT_NSEC3_SIGNED);
- }
- TEST_F(InMemoryZoneFinderTest, anyWildcardNSEC) {
- anyWildcardCheck(ZoneFinder::RESULT_NSEC_SIGNED);
- }
- // Test there's nothing in the wildcard in the middle if we load
- // wild.*.foo.example.org.
- void
- InMemoryZoneFinderTest::emptyWildcardCheck(
- ZoneFinder::FindResultFlags expected_flags)
- {
- /*
- * example.org.
- * foo
- * *
- * wild
- */
- EXPECT_EQ(SUCCESS, zone_finder_.add(rr_emptywild_));
- if ((expected_flags & ZoneFinder::RESULT_NSEC3_SIGNED) != 0) {
- EXPECT_EQ(SUCCESS, zone_finder_.add(rr_nsec3_));
- }
- if ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED) != 0) {
- EXPECT_EQ(SUCCESS, zone_finder_.add(rr_nsec_));
- }
- {
- SCOPED_TRACE("Asking for the original record under wildcard");
- findTest(Name("wild.*.foo.example.org"), RRType::A(),
- ZoneFinder::SUCCESS, true, rr_emptywild_);
- }
- {
- SCOPED_TRACE("Asking for A record");
- findTest(Name("a.foo.example.org"), RRType::A(), ZoneFinder::NXRRSET,
- true, ConstRRsetPtr(),
- ZoneFinder::RESULT_WILDCARD | expected_flags);
- findTest(Name("*.foo.example.org"), RRType::A(), ZoneFinder::NXRRSET,
- true, ConstRRsetPtr(), expected_flags);
- findTest(Name("foo.example.org"), RRType::A(), ZoneFinder::NXRRSET,
- true, ConstRRsetPtr(), expected_flags);
- }
- {
- SCOPED_TRACE("Asking for ANY record");
- findAllTest(Name("*.foo.example.org"), ZoneFinder::NXRRSET,
- vector<ConstRRsetPtr>(), expected_flags);
- findAllTest(Name("a.foo.example.org"), ZoneFinder::NXRRSET,
- vector<ConstRRsetPtr>(),
- ZoneFinder::RESULT_WILDCARD | expected_flags);
- }
- {
- SCOPED_TRACE("Asking on the non-terminal");
- findTest(Name("wild.bar.foo.example.org"), RRType::A(),
- ZoneFinder::NXRRSET, true, ConstRRsetPtr(),
- ZoneFinder::RESULT_WILDCARD | expected_flags);
- }
- }
- TEST_F(InMemoryZoneFinderTest, emptyWildcard) {
- emptyWildcardCheck();
- }
- TEST_F(InMemoryZoneFinderTest, emptyWildcardNSEC3) {
- emptyWildcardCheck(ZoneFinder::RESULT_NSEC3_SIGNED);
- }
- TEST_F(InMemoryZoneFinderTest, emptyWildcardNSEC) {
- emptyWildcardCheck(ZoneFinder::RESULT_NSEC_SIGNED);
- }
- // Same as emptyWildcard, but with multiple * in the path.
- TEST_F(InMemoryZoneFinderTest, nestedEmptyWildcard) {
- EXPECT_EQ(SUCCESS, zone_finder_.add(rr_nested_emptywild_));
- {
- SCOPED_TRACE("Asking for the original record under wildcards");
- findTest(Name("wild.*.foo.*.bar.example.org"), RRType::A(),
- ZoneFinder::SUCCESS, true, rr_nested_emptywild_);
- }
- {
- SCOPED_TRACE("Matching wildcard against empty nonterminal");
- const char* names[] = {
- "baz.foo.*.bar.example.org",
- "baz.foo.baz.bar.example.org",
- "*.foo.baz.bar.example.org",
- NULL
- };
- for (const char** name = names; *name != NULL; ++ name) {
- SCOPED_TRACE(string("Node ") + *name);
- findTest(Name(*name), RRType::A(), ZoneFinder::NXRRSET, true,
- ConstRRsetPtr(), ZoneFinder::RESULT_WILDCARD);
- }
- }
- // Domains to test
- const char* names[] = {
- "*.foo.*.bar.example.org",
- "foo.*.bar.example.org",
- "*.bar.example.org",
- "bar.example.org",
- NULL
- };
- {
- SCOPED_TRACE("Asking directly for A on parent nodes");
- for (const char** name = names; *name != NULL; ++ name) {
- SCOPED_TRACE(string("Node ") + *name);
- findTest(Name(*name), RRType::A(), ZoneFinder::NXRRSET);
- }
- }
- {
- SCOPED_TRACE("Asking for ANY on parent nodes");
- for (const char** name = names; *name != NULL; ++ name) {
- SCOPED_TRACE(string("Node ") + *name);
- findAllTest(Name(*name), ZoneFinder::NXRRSET,
- vector<ConstRRsetPtr>());
- }
- }
- }
- // We run this part twice from the below test, in two slightly different
- // situations
- void
- InMemoryZoneFinderTest::doCancelWildcardCheck(
- ZoneFinder::FindResultFlags expected_flags,
- ZoneFinder::FindOptions find_options)
- {
- // These should be canceled
- {
- SCOPED_TRACE("Canceled under foo.wild.example.org");
- // For an NSEC-signed zone with DNSSEC requested, the covering NSEC
- // should be returned. The expected NSEC is actually just the only
- // NSEC in the test data, but in this context it doesn't matter;
- // it's sufficient just to check any NSEC is returned (or not).
- ConstRRsetPtr expected_nsec; // by default it's NULL
- if ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED) != 0 &&
- (find_options & ZoneFinder::FIND_DNSSEC)) {
- expected_nsec = rr_nsec_;
- }
- findTest(Name("aaa.foo.wild.example.org"), RRType::A(),
- ZoneFinder::NXDOMAIN, true, expected_nsec, expected_flags,
- NULL, find_options);
- findTest(Name("zzz.foo.wild.example.org"), RRType::A(),
- ZoneFinder::NXDOMAIN, true, expected_nsec, expected_flags,
- NULL, find_options);
- }
- // This is existing, non-wildcard domain, shouldn't wildcard at all
- {
- SCOPED_TRACE("Existing domain under foo.wild.example.org");
- findTest(Name("bar.foo.wild.example.org"), RRType::A(),
- ZoneFinder::SUCCESS, true, rr_not_wild_);
- }
- // These should be caught by the wildcard
- {
- SCOPED_TRACE("Neighbor wildcards to foo.wild.example.org");
- const char* names[] = {
- "aaa.bbb.wild.example.org",
- "aaa.zzz.wild.example.org",
- "zzz.wild.example.org",
- NULL
- };
- for (const char** name = names; *name != NULL; ++ name) {
- SCOPED_TRACE(string("Node ") + *name);
- findTest(Name(*name), RRType::A(), ZoneFinder::SUCCESS, false,
- rr_wild_,
- ZoneFinder::RESULT_WILDCARD | expected_flags, NULL,
- ZoneFinder::FIND_DEFAULT, true);
- }
- }
- // This shouldn't be wildcarded, it's an existing domain
- {
- SCOPED_TRACE("The foo.wild.example.org itself");
- findTest(Name("foo.wild.example.org"), RRType::A(),
- ZoneFinder::NXRRSET, true, ConstRRsetPtr(), expected_flags);
- }
- }
- /*
- * This tests that if there's a name between the wildcard domain and the
- * searched one, it will not trigger wildcard, for example, if we have
- * *.wild.example.org and bar.foo.wild.example.org, then we know
- * foo.wild.example.org exists and is not wildcard. Therefore, search for
- * aaa.foo.wild.example.org should return NXDOMAIN.
- *
- * Tests few cases "around" the canceled wildcard match, to see something that
- * shouldn't be canceled isn't.
- */
- TEST_F(InMemoryZoneFinderTest, cancelWildcard) {
- EXPECT_EQ(SUCCESS, zone_finder_.add(rr_wild_));
- EXPECT_EQ(SUCCESS, zone_finder_.add(rr_not_wild_));
- {
- SCOPED_TRACE("Runnig with single entry under foo.wild.example.org");
- doCancelWildcardCheck();
- }
- // Try putting another one under foo.wild....
- // The result should be the same but it will be done in another way in the
- // code, because the foo.wild.example.org will exist in the tree.
- EXPECT_EQ(SUCCESS, zone_finder_.add(rr_not_wild_another_));
- {
- SCOPED_TRACE("Runnig with two entries under foo.wild.example.org");
- doCancelWildcardCheck();
- }
- }
- // Same tests as cancelWildcard for NSEC3-signed zone
- TEST_F(InMemoryZoneFinderTest, cancelWildcardNSEC3) {
- EXPECT_EQ(SUCCESS, zone_finder_.add(rr_wild_));
- EXPECT_EQ(SUCCESS, zone_finder_.add(rr_not_wild_));
- EXPECT_EQ(SUCCESS, zone_finder_.add(rr_nsec3_));
- {
- SCOPED_TRACE("Runnig with single entry under foo.wild.example.org");
- doCancelWildcardCheck(ZoneFinder::RESULT_NSEC3_SIGNED);
- }
- EXPECT_EQ(SUCCESS, zone_finder_.add(rr_not_wild_another_));
- {
- SCOPED_TRACE("Runnig with two entries under foo.wild.example.org");
- doCancelWildcardCheck(ZoneFinder::RESULT_NSEC3_SIGNED);
- }
- }
- // Same tests as cancelWildcard for NSEC-signed zone. Check both cases with
- // or without FIND_DNSSEC option. NSEC should be returned only when the option
- // is given.
- TEST_F(InMemoryZoneFinderTest, cancelWildcardNSEC) {
- EXPECT_EQ(SUCCESS, zone_finder_.add(rr_wild_));
- EXPECT_EQ(SUCCESS, zone_finder_.add(rr_not_wild_));
- EXPECT_EQ(SUCCESS, zone_finder_.add(rr_nsec_));
- {
- SCOPED_TRACE("Runnig with single entry under foo.wild.example.org");
- doCancelWildcardCheck(ZoneFinder::RESULT_NSEC_SIGNED,
- ZoneFinder::FIND_DNSSEC);
- doCancelWildcardCheck(ZoneFinder::RESULT_NSEC_SIGNED);
- }
- EXPECT_EQ(SUCCESS, zone_finder_.add(rr_not_wild_another_));
- {
- SCOPED_TRACE("Runnig with two entries under foo.wild.example.org");
- doCancelWildcardCheck(ZoneFinder::RESULT_NSEC_SIGNED,
- ZoneFinder::FIND_DNSSEC);
- doCancelWildcardCheck(ZoneFinder::RESULT_NSEC_SIGNED);
- }
- }
- TEST_F(InMemoryZoneFinderTest, loadBadWildcard) {
- // We reject loading the zone if it contains a wildcard name for
- // NS or DNAME.
- EXPECT_THROW(zone_finder_.add(rr_nswild_), InMemoryZoneFinder::AddError);
- EXPECT_THROW(zone_finder_.add(rr_dnamewild_),
- InMemoryZoneFinder::AddError);
- }
- TEST_F(InMemoryZoneFinderTest, swap) {
- // build one zone finder with some data
- InMemoryZoneFinder finder1(class_, origin_);
- EXPECT_EQ(result::SUCCESS, finder1.add(rr_ns_));
- EXPECT_EQ(result::SUCCESS, finder1.add(rr_ns_aaaa_));
- // build another zone finder of a different RR class with some other data
- const Name other_origin("version.bind");
- ASSERT_NE(origin_, other_origin); // make sure these two are different
- InMemoryZoneFinder finder2(RRClass::CH(), other_origin);
- EXPECT_EQ(result::SUCCESS,
- finder2.add(textToRRset("version.bind. 0 CH TXT \"test\"",
- RRClass::CH())));
- finder1.swap(finder2);
- EXPECT_EQ(other_origin, finder1.getOrigin());
- EXPECT_EQ(origin_, finder2.getOrigin());
- EXPECT_EQ(RRClass::CH(), finder1.getClass());
- EXPECT_EQ(RRClass::IN(), finder2.getClass());
- // make sure the zone data is swapped, too
- EXPECT_THROW(finder1.find(origin_, RRType::NS()), OutOfZone);
- findTest(other_origin, RRType::TXT(), ZoneFinder::SUCCESS, false,
- ConstRRsetPtr(), ZoneFinder::RESULT_DEFAULT, &finder1);
- findTest(origin_, RRType::NS(), ZoneFinder::SUCCESS, false,
- ConstRRsetPtr(), ZoneFinder::RESULT_DEFAULT, &finder2);
- EXPECT_THROW(finder2.find(other_origin, RRType::TXT()), OutOfZone);
- }
- TEST_F(InMemoryZoneFinderTest, getFileName) {
- // for an empty zone the file name should also be empty.
- EXPECT_TRUE(zone_finder_.getFileName().empty());
- // if loading a zone fails the file name shouldn't be set.
- EXPECT_THROW(zone_finder_.load(TEST_DATA_DIR "/root.zone"),
- MasterLoadError);
- EXPECT_TRUE(zone_finder_.getFileName().empty());
- // after a successful load, the specified file name should be set
- InMemoryZoneFinder rootzone(class_, Name("."));
- EXPECT_NO_THROW(rootzone.load(TEST_DATA_DIR "/root.zone"));
- EXPECT_EQ(TEST_DATA_DIR "/root.zone", rootzone.getFileName());
- // overriding load, which will fail
- EXPECT_THROW(rootzone.load(TEST_DATA_DIR "/duplicate_rrset.zone"),
- MasterLoadError);
- // the file name should be intact.
- EXPECT_EQ(TEST_DATA_DIR "/root.zone", rootzone.getFileName());
- // After swap, file names should also be swapped.
- zone_finder_.swap(rootzone);
- EXPECT_EQ(TEST_DATA_DIR "/root.zone", zone_finder_.getFileName());
- EXPECT_TRUE(rootzone.getFileName().empty());
- }
- TEST_F(InMemoryZoneFinderTest, addRRsig) {
- // A simple valid case: adding an RRset to be signed followed by an RRSIG
- // that covers the first RRset
- zone_finder_.add(rr_a_);
- zone_finder_.add(textToRRset(rrsig_a_txt));
- ZoneFinderContextPtr result = zone_finder_.find(origin_, RRType::A(),
- ZoneFinder::FIND_DNSSEC);
- EXPECT_EQ(ZoneFinder::SUCCESS, result->code);
- ASSERT_TRUE(result->rrset);
- ASSERT_TRUE(result->rrset->getRRsig());
- actual_rrsets_.push_back(result->rrset->getRRsig());
- rrsetsCheck(rrsig_a_txt, actual_rrsets_.begin(), actual_rrsets_.end());
- // Confirm a separate RRISG for a different type can be added
- actual_rrsets_.clear();
- zone_finder_.add(rr_ns_);
- zone_finder_.add(textToRRset(rrsig_ns_txt));
- result = zone_finder_.find(origin_, RRType::NS(), ZoneFinder::FIND_DNSSEC);
- EXPECT_EQ(ZoneFinder::SUCCESS, result->code);
- ASSERT_TRUE(result->rrset);
- ASSERT_TRUE(result->rrset->getRRsig());
- actual_rrsets_.push_back(result->rrset->getRRsig());
- rrsetsCheck(rrsig_ns_txt, actual_rrsets_.begin(), actual_rrsets_.end());
- // Check a case with multiple RRSIGs
- actual_rrsets_.clear();
- zone_finder_.add(rr_ns_aaaa_);
- zone_finder_.add(textToRRset(rrsig_aaaa_txt));
- result = zone_finder_.find(Name("ns.example.org"), RRType::AAAA(),
- ZoneFinder::FIND_DNSSEC);
- EXPECT_EQ(ZoneFinder::SUCCESS, result->code);
- ASSERT_TRUE(result->rrset);
- ASSERT_TRUE(result->rrset->getRRsig());
- actual_rrsets_.push_back(result->rrset->getRRsig());
- rrsetsCheck(rrsig_aaaa_txt, actual_rrsets_.begin(), actual_rrsets_.end());
- }
- TEST_F(InMemoryZoneFinderTest, addRRsigWithoutCovered) {
- // The current implementation rejects attempts of adding RRSIG without
- // covered RRsets already in the zone.
- // Name doesn't exist
- EXPECT_THROW(zone_finder_.add(
- textToRRset("notexist.example.org. 300 IN RRSIG A 5 3 "
- "3600 20000101000000 20000201000000 12345 "
- "example.org. FAKEFAKEFAKE\n")),
- InMemoryZoneFinder::AddError);
- // Name exists, but is empty.
- zone_finder_.add(rr_emptywild_);
- EXPECT_THROW(zone_finder_.add(
- textToRRset("foo.example.org. 300 IN RRSIG A 5 3 "
- "3600 20000101000000 20000201000000 12345 "
- "example.org. FAKEFAKEFAKE\n")),
- InMemoryZoneFinder::AddError);
- // Add RRSIG RRset without covered RR
- zone_finder_.add(rr_a_);
- EXPECT_THROW(zone_finder_.add(textToRRset(rrsig_ns_txt)),
- InMemoryZoneFinder::AddError);
- }
- TEST_F(InMemoryZoneFinderTest, addbadRRsig) {
- // Tests with other types of bogus input
- // Empty RRSIG RRset.
- EXPECT_THROW(zone_finder_.add(RRsetPtr(new RRset(origin_, class_,
- RRType::RRSIG(),
- RRTTL(300)))),
- InMemoryZoneFinder::AddError);
- // RRSIG with mixed covered types
- zone_finder_.add(rr_a_); // make sure the covered name exists
- // textToRRset() doesn't work as intended for this pathological case,
- // so we need to construct the RRset by hand.
- RRsetPtr rrset(new RRset(origin_, class_, RRType::RRSIG(), RRTTL(300)));
- rrset->addRdata(generic::RRSIG("A 5 3 3600 20000101000000 20000201000000 "
- "12345 example.org. FAKEFAKEFAKE"));
- rrset->addRdata(generic::RRSIG("NS 5 3 3600 20000101000000 20000201000000 "
- "54321 example.org. FAKEFAKEFAKEFAKE"));
- EXPECT_THROW(zone_finder_.add(rrset), InMemoryZoneFinder::AddError);
- // An attempt of overriding an existing RRSIG. The current implementation
- // prohibits that.
- zone_finder_.add(textToRRset(rrsig_a_txt));
- EXPECT_THROW(zone_finder_.add(textToRRset(rrsig_a_txt)),
- InMemoryZoneFinder::AddError);
- }
- TEST_F(InMemoryZoneFinderTest, addNSEC3) {
- // Set up the faked hash calculator.
- setNSEC3HashCreator(&nsec3_hash_creator_);
- const string nsec3_text = string(apex_hash) + ".example.org." +
- string(nsec3_common);
- // This name shouldn't be found in the normal domain tree.
- EXPECT_EQ(result::SUCCESS, zone_finder_.add(textToRRset(nsec3_text)));
- EXPECT_EQ(ZoneFinder::NXDOMAIN,
- zone_finder_.find(Name(string(apex_hash) + ".example.org"),
- RRType::NSEC3())->code);
- // Dedicated NSEC3 find should be able to find it.
- findNSEC3Check(true, origin_.getLabelCount(), nsec3_text, "",
- zone_finder_.findNSEC3(Name("example.org"), false));
- // This implementation rejects duplicate/update add of the same hash name
- EXPECT_EQ(result::EXIST,
- zone_finder_.add(textToRRset(
- string(apex_hash) + ".example.org." +
- string(nsec3_common) + " AAAA")));
- // The original NSEC3 should be intact
- findNSEC3Check(true, origin_.getLabelCount(), nsec3_text, "",
- zone_finder_.findNSEC3(Name("example.org"), false));
- // NSEC3-like name but of ordinary RR type should go to normal tree.
- const string nonsec3_text = string(apex_hash) + ".example.org. " +
- "300 IN A 192.0.2.1";
- EXPECT_EQ(result::SUCCESS, zone_finder_.add(textToRRset(nonsec3_text)));
- EXPECT_EQ(ZoneFinder::SUCCESS,
- zone_finder_.find(Name(string(apex_hash) + ".example.org"),
- RRType::A())->code);
- }
- TEST_F(InMemoryZoneFinderTest, addNSEC3Lower) {
- // Set up the faked hash calculator.
- setNSEC3HashCreator(&nsec3_hash_creator_);
- // Similar to the previous case, but NSEC3 owner name is lower-cased.
- const string nsec3_text = string(apex_hash_lower) + ".example.org." +
- string(nsec3_common);
- EXPECT_EQ(result::SUCCESS, zone_finder_.add(textToRRset(nsec3_text)));
- findNSEC3Check(true, origin_.getLabelCount(), nsec3_text, "",
- zone_finder_.findNSEC3(Name("example.org"), false));
- }
- TEST_F(InMemoryZoneFinderTest, addNSEC3Ordering) {
- // Set up the faked hash calculator.
- setNSEC3HashCreator(&nsec3_hash_creator_);
- // Check that the internal storage ensures comparison based on the NSEC3
- // semantics, regardless of the add order or the letter-case of hash.
- // Adding "0P..", "2v..", then "2T..".
- const string smallest = string(apex_hash) + ".example.org." +
- string(nsec3_common);
- const string middle = string(ns1_hash) + ".example.org." +
- string(nsec3_common);
- const string largest = string(xyw_hash) + ".example.org." +
- string(nsec3_common);
- zone_finder_.add(textToRRset(smallest));
- zone_finder_.add(textToRRset(largest));
- zone_finder_.add(textToRRset(middle));
- // Then look for NSEC3 that covers a name whose hash is "2S.."
- // The covering NSEC3 should be "0P.."
- findNSEC3Check(false, 4, smallest, "",
- zone_finder_.findNSEC3(Name("www.example.org"), false));
- // Look for NSEC3 that covers names whose hash are "Q0.." and "0A.."
- // The covering NSEC3 should be "2v.." in both cases
- findNSEC3Check(false, 4, largest, "",
- zone_finder_.findNSEC3(Name("xxx.example.org"), false));
- findNSEC3Check(false, 4, largest, "",
- zone_finder_.findNSEC3(Name("yyy.example.org"), false));
- }
- TEST_F(InMemoryZoneFinderTest, badNSEC3Name) {
- // Our implementation refuses to load NSEC3 at a wildcard name
- EXPECT_THROW(zone_finder_.add(textToRRset("*.example.org." +
- string(nsec3_common))),
- InMemoryZoneFinder::AddError);
- // Likewise, if the owner name of NSEC3 has too many labels, it's refused.
- EXPECT_THROW(zone_finder_.add(textToRRset("a." + string(apex_hash) +
- ".example.org." +
- string(nsec3_common))),
- InMemoryZoneFinder::AddError);
- }
- TEST_F(InMemoryZoneFinderTest, addMultiNSEC3) {
- // In this current implementation multiple NSEC3 RDATA isn't supported.
- RRsetPtr nsec3(new RRset(Name(string(apex_hash) + ".example.org"),
- RRClass::IN(), RRType::NSEC3(), RRTTL(300)));
- nsec3->addRdata(
- generic::NSEC3("1 0 12 aabbccdd 2T7B4G4VSA5SMI47K61MV5BV1A22BOJR A"));
- nsec3->addRdata(
- generic::NSEC3("1 1 1 ddccbbaa 2T7B4G4VSA5SMI47K61MV5BV1A22BOJR A"));
- EXPECT_THROW(zone_finder_.add(nsec3), InMemoryZoneFinder::AddError);
- }
- TEST_F(InMemoryZoneFinderTest, addNSEC3WithRRSIG) {
- // Set up the faked hash calculator.
- setNSEC3HashCreator(&nsec3_hash_creator_);
- // Adding NSEC3 and its RRSIG
- const string nsec3_text = string(apex_hash) + ".example.org." +
- string(nsec3_common);
- EXPECT_EQ(result::SUCCESS, zone_finder_.add(textToRRset(nsec3_text)));
- const string nsec3_rrsig_text = string(apex_hash) + ".example.org." +
- string(nsec3_rrsig_common);
- EXPECT_EQ(result::SUCCESS, zone_finder_.add(textToRRset(nsec3_rrsig_text)));
- // Then look for it. The NSEC3 should have the RRSIG that was just added.
- findNSEC3Check(true, origin_.getLabelCount(),
- nsec3_text + "\n" + nsec3_rrsig_text, "",
- zone_finder_.findNSEC3(Name("example.org"), false), true);
- // Duplicate add of RRSIG for the same NSEC3 is prohibited.
- EXPECT_THROW(zone_finder_.add(textToRRset(nsec3_rrsig_text)),
- InMemoryZoneFinder::AddError);
- // Same check using the lower-cased name. This also confirms matching
- // is case-insensitive.
- EXPECT_THROW(zone_finder_.add(textToRRset(string(apex_hash_lower) +
- ".example.org."
- + string(nsec3_rrsig_common))),
- InMemoryZoneFinder::AddError);
- }
- TEST_F(InMemoryZoneFinderTest, badRRsigForNSEC3) {
- // adding RRSIG for NSEC3 even before adding any NSEC3 (internally,
- // a space for NSEC3 namespace isn't yet allocated)
- EXPECT_THROW(zone_finder_.add(textToRRset(string(apex_hash) +
- ".example.org." +
- string(nsec3_rrsig_common))),
- InMemoryZoneFinder::AddError);
- // Add an NSEC3
- EXPECT_EQ(result::SUCCESS, zone_finder_.add(
- textToRRset(string(apex_hash) + ".example.org." +
- string(nsec3_common))));
- // Then add an NSEC3 for a non existent NSEC3. It should fail in the
- // current implementation.
- EXPECT_THROW(zone_finder_.add(textToRRset(string(ns1_hash) +
- ".example.org." +
- string(nsec3_rrsig_common))),
- InMemoryZoneFinder::AddError);
- }
- TEST_F(InMemoryZoneFinderTest, paramConsistencyWithNSEC3PARAM) {
- // First, add an NSEC3PARAM RR
- EXPECT_EQ(result::SUCCESS,
- zone_finder_.add(textToRRset("example.org. 300 IN NSEC3PARAM "
- "1 0 12 aabbccdd")));
- // Adding an NSEC3 that has matching parameters is okay.
- EXPECT_EQ(result::SUCCESS, zone_finder_.add(
- textToRRset(string(apex_hash) + ".example.org." +
- string(nsec3_common))));
- // NSEC3 with inconsistent parameter will be rejected
- EXPECT_THROW(zone_finder_.add(
- textToRRset("a.example.org. 300 IN NSEC3 1 0 1 aabbccdd "
- "2T7B4G4VSA5SMI47K61MV5BV1A22BOJR A RRSIG")),
- InMemoryZoneFinder::AddError);
- }
- TEST_F(InMemoryZoneFinderTest, paramConsistencyWithNSEC3) {
- // Add an NSEC3 without adding NSEC3PARAM
- EXPECT_EQ(result::SUCCESS, zone_finder_.add(
- textToRRset(string(apex_hash) + ".example.org." +
- string(nsec3_common))));
- // Adding an NSEC3 with inconsistent parameter will be rejected at this pt.
- EXPECT_THROW(zone_finder_.add(
- textToRRset("a.example.org. 300 IN NSEC3 1 0 1 aabbccdd "
- "2T7B4G4VSA5SMI47K61MV5BV1A22BOJR A RRSIG")),
- InMemoryZoneFinder::AddError);
- // Likewise, NSEC3PARAM with inconsistent parameter will be rejected.
- EXPECT_THROW(zone_finder_.add(textToRRset("example.org. 300 IN NSEC3PARAM "
- "1 0 1 aabbccdd")),
- InMemoryZoneFinder::AddError);
- }
- TEST_F(InMemoryZoneFinderTest, multiNSEC3PARAM) {
- // In this current implementation multiple NSEC3PARAM isn't supported.
- RRsetPtr nsec3param(new RRset(Name("example.org"), RRClass::IN(),
- RRType::NSEC3PARAM(), RRTTL(300)));
- nsec3param->addRdata(generic::NSEC3PARAM("1 0 12 aabbccdd"));
- nsec3param->addRdata(generic::NSEC3PARAM("1 1 1 ddccbbaa"));
- EXPECT_THROW(zone_finder_.add(nsec3param), InMemoryZoneFinder::AddError);
- }
- TEST_F(InMemoryZoneFinderTest, nonOriginNSEC3PARAM) {
- // This is a normal NSEC3PARAM at the zone origin
- EXPECT_EQ(result::SUCCESS,
- zone_finder_.add(textToRRset("example.org. 300 IN NSEC3PARAM "
- "1 0 12 aabbccdd")));
- // Add another (with different param) at a non origin node. This is
- // awkward, but the implementation accepts it as an ordinary RR.
- EXPECT_EQ(result::SUCCESS,
- zone_finder_.add(textToRRset("a.example.org. 300 IN NSEC3PARAM "
- "1 1 1 aabbccdd")));
- }
- TEST_F(InMemoryZoneFinderTest, loadNSEC3Zone) {
- // Check if it can load validly NSEC3-signed zone. At this moment
- // it's sufficient to see it doesn't crash
- zone_finder_.load(TEST_DATA_DIR "/example.org.nsec3-signed");
- // Reload the zone with a version that doesn't have NSEC3PARAM.
- // This is an abnormal case, but the implementation accepts it.
- zone_finder_.load(TEST_DATA_DIR "/example.org.nsec3-signed-noparam");
- }
- // This test checks that the NSEC3 names don't really exist in the real
- // namespace.
- TEST_F(InMemoryZoneFinderTest, queryToNSEC3Name) {
- // Add the NSEC3 and NSEC3PARAM there.
- EXPECT_EQ(result::SUCCESS,
- zone_finder_.add(textToRRset("example.org. 300 IN NSEC3PARAM "
- "1 0 12 aabbccdd")));
- const Name nsec3domain(string(apex_hash) + ".example.org.");
- // Adding an NSEC3 that has matching parameters is okay.
- EXPECT_EQ(result::SUCCESS, zone_finder_.add(
- textToRRset(string(apex_hash) + ".example.org." +
- string(nsec3_common))));
- // Now, the domain should not exist
- findTest(nsec3domain, RRType::AAAA(), ZoneFinder::NXDOMAIN, false,
- ConstRRsetPtr(), ZoneFinder::RESULT_NSEC3_SIGNED, &zone_finder_,
- ZoneFinder::FIND_DNSSEC);
- // If we add an A record, the domain should exist
- ConstRRsetPtr rrset(textToRRset(string(apex_hash) +
- ".example.org. 300 IN A 192.0.2.1"));
- EXPECT_EQ(result::SUCCESS, zone_finder_.add(rrset));
- // Searching for a different RRType will tell us this RRset doesn't exist
- findTest(nsec3domain, RRType::AAAA(), ZoneFinder::NXRRSET, false,
- ConstRRsetPtr(), ZoneFinder::RESULT_NSEC3_SIGNED, &zone_finder_,
- ZoneFinder::FIND_DNSSEC);
- // Searching for the A record would find it
- findTest(nsec3domain, RRType::A(), ZoneFinder::SUCCESS, true,
- rrset, ZoneFinder::RESULT_DEFAULT, &zone_finder_,
- ZoneFinder::FIND_DNSSEC);
- }
- // Continuation of the previous test (queryToNSEC3Name), we check we don't break
- // the empty nonterminal case by existence of NSEC3 record with that name.
- TEST_F(InMemoryZoneFinderTest, queryToNSEC3NameNonterminal) {
- // Add the NSEC3 and NSEC3PARAM there.
- EXPECT_EQ(result::SUCCESS,
- zone_finder_.add(textToRRset("example.org. 300 IN NSEC3PARAM "
- "1 0 12 aabbccdd")));
- const Name nsec3domain(string(apex_hash) + ".example.org.");
- // Adding an NSEC3 that has matching parameters is okay.
- EXPECT_EQ(result::SUCCESS, zone_finder_.add(
- textToRRset(string(apex_hash) + ".example.org." +
- string(nsec3_common))));
- // Something below the name
- ConstRRsetPtr rrset(textToRRset("below." + string(apex_hash) +
- ".example.org. 300 IN A 192.0.2.1"));
- EXPECT_EQ(result::SUCCESS, zone_finder_.add(rrset));
- // Now, the node is empty non-terminal.
- findTest(nsec3domain, RRType::AAAA(), ZoneFinder::NXRRSET, false,
- ConstRRsetPtr(), ZoneFinder::RESULT_NSEC3_SIGNED, &zone_finder_,
- ZoneFinder::FIND_DNSSEC);
- }
- TEST_F(InMemoryZoneFinderTest, findNSEC3) {
- // Set up the faked hash calculator.
- setNSEC3HashCreator(&nsec3_hash_creator_);
- // Add a few NSEC3 records:
- // apex (example.org.): hash=0P..
- // ns1.example.org: hash=2T..
- // w.example.org: hash=01..
- // zzz.example.org: hash=R5..
- const string apex_nsec3_text = string(apex_hash) + ".example.org." +
- string(nsec3_common);
- EXPECT_EQ(result::SUCCESS, zone_finder_.add(textToRRset(apex_nsec3_text)));
- const string ns1_nsec3_text = string(ns1_hash) + ".example.org." +
- string(nsec3_common);
- EXPECT_EQ(result::SUCCESS, zone_finder_.add(textToRRset(ns1_nsec3_text)));
- const string w_nsec3_text = string(w_hash) + ".example.org." +
- string(nsec3_common);
- EXPECT_EQ(result::SUCCESS, zone_finder_.add(textToRRset(w_nsec3_text)));
- const string zzz_nsec3_text = string(zzz_hash) + ".example.org." +
- string(nsec3_common);
- EXPECT_EQ(result::SUCCESS, zone_finder_.add(textToRRset(zzz_nsec3_text)));
- performNSEC3Test(zone_finder_);
- }
- TEST_F(InMemoryZoneFinderTest, findNSEC3ForBadZone) {
- // Set up the faked hash calculator.
- setNSEC3HashCreator(&nsec3_hash_creator_);
- // If the zone has nothing about NSEC3 (neither NSEC3 or NSEC3PARAM),
- // findNSEC3() should be rejected.
- EXPECT_THROW(zone_finder_.findNSEC3(Name("www.example.org"), true),
- DataSourceError);
- // Only having NSEC3PARAM isn't enough
- EXPECT_EQ(result::SUCCESS,
- zone_finder_.add(textToRRset("example.org. 300 IN NSEC3PARAM "
- "1 0 12 aabbccdd")));
- EXPECT_THROW(zone_finder_.findNSEC3(Name("www.example.org"), true),
- DataSourceError);
- // Unless NSEC3 for apex is added the result in the recursive mode
- // is guaranteed.
- const string ns1_nsec3_text = string(ns1_hash) + ".example.org." +
- string(nsec3_common);
- EXPECT_EQ(result::SUCCESS, zone_finder_.add(textToRRset(ns1_nsec3_text)));
- EXPECT_THROW(zone_finder_.findNSEC3(Name("www.example.org"), true),
- DataSourceError);
- }
- TEST_F(InMemoryZoneFinderTest, loadAndFindNSEC3) {
- // Using more realistic example, borrowed from RFC5155, with compliant
- // hash calculator. We only confirm the data source can load it
- // successfully and find correct NSEC3 RRs for some selected cases
- // (detailed tests have been done above).
- InMemoryZoneFinder finder(class_, Name("example"));
- finder.load(TEST_DATA_COMMONDIR "/rfc5155-example.zone.signed");
- // See RFC5155 B.1
- ZoneFinder::FindNSEC3Result result1 =
- finder.findNSEC3(Name("c.x.w.example"), true);
- ASSERT_TRUE(result1.closest_proof);
- // We compare closest_labels as int so the error report will be more
- // readable in case it fails.
- EXPECT_EQ(4, static_cast<int>(result1.closest_labels));
- EXPECT_EQ(Name("b4um86eghhds6nea196smvmlo4ors995.example"),
- result1.closest_proof->getName());
- ASSERT_TRUE(result1.next_proof);
- EXPECT_EQ(Name("0p9mhaveqvm6t7vbl5lop2u3t2rp3tom.example"),
- result1.next_proof->getName());
- // See RFC5155 B.2.
- ZoneFinder::FindNSEC3Result result2 =
- finder.findNSEC3(Name("ns1.example"), true);
- ASSERT_TRUE(result2.closest_proof);
- EXPECT_EQ(3, static_cast<int>(result2.closest_labels));
- EXPECT_EQ(Name("2t7b4g4vsa5smi47k61mv5bv1a22bojr.example"),
- result2.closest_proof->getName());
- ASSERT_FALSE(result2.next_proof);
- // See RFC5155 B.5.
- ZoneFinder::FindNSEC3Result result3 =
- finder.findNSEC3(Name("a.z.w.example"), true);
- ASSERT_TRUE(result3.closest_proof);
- EXPECT_EQ(3, static_cast<int>(result3.closest_labels));
- EXPECT_EQ(Name("k8udemvp1j2f7eg6jebps17vp3n8i58h.example"),
- result3.closest_proof->getName());
- ASSERT_TRUE(result3.next_proof);
- EXPECT_EQ(Name("q04jkcevqvmu85r014c7dkba38o0ji5r.example"),
- result3.next_proof->getName());
- }
- }
|