Commit 80f19c31 authored by JINMEI Tatuya's avatar JINMEI Tatuya
Browse files

[1431] implemented FindNSEC3() for MockZoneFinder used in auth Query tests.

while doing so, revisisted the interface and the method now returns both
the closest enclosure proof and next closer proof in a single call.
parent 0e93f4c1
......@@ -19,6 +19,8 @@
#include <boost/bind.hpp>
#include <boost/scoped_ptr.hpp>
#include <exceptions/exceptions.h>
#include <dns/masterload.h>
#include <dns/message.h>
#include <dns/name.h>
......@@ -153,6 +155,14 @@ const char* const nsec_www_txt =
// Authoritative data without NSEC
const char* const nonsec_a_txt = "nonsec.example.com. 3600 IN A 192.0.2.0\n";
// NSEC3 RRs. You may also need to add mapping to MockZoneFinder::hash_map_.
const char* const nsec3_apex_txt =
"0p9mhaveqvm6t7vbl5lop2u3t2rp3tom.example.com. 3600 IN NSEC3 1 1 12 "
"aabbccdd 2t7b4g4vsa5smi47k61mv5bv1a22bojr NS SOA NSEC3PARAM RRSIG\n";
const char* const nsec3_www_txt =
"q04jkcevqvmu85r014c7dkba38o0ji5r.example.com. 3600 IN NSEC3 1 1 12 "
"aabbccdd r53bq7cc2uvmubfu5ocmm6pers9tk9en A RRSIG\n";
// A helper function that generates a textual representation of RRSIG RDATA
// for the given covered type. The resulting RRSIG may not necessarily make
// sense in terms of the DNSSEC protocol, but for our testing purposes it's
......@@ -197,7 +207,8 @@ public:
wild_txt << nsec_wild_txt << cnamewild_txt << nsec_cnamewild_txt <<
wild_txt_nxrrset << nsec_wild_txt_nxrrset << wild_txt_next <<
nsec_wild_txt_next << empty_txt << nsec_empty_txt <<
empty_prev_txt << nsec_empty_prev_txt;
empty_prev_txt << nsec_empty_prev_txt <<
nsec3_apex_txt << nsec3_www_txt;
masterLoad(zone_stream, origin_, rrclass_,
boost::bind(&MockZoneFinder::loadRRset, this, _1));
......@@ -206,6 +217,17 @@ public:
RRClass::IN(),
RRType::NSEC(),
RRTTL(3600)));
// (Faked) NSEC3 hash map. For convenience we use hardcoded built-in
// map instead of calculating and using actual hash.
// The used hash values are borrowed from RFC5155 examples.
hash_map_[Name("example.com")] = "0p9mhaveqvm6t7vbl5lop2u3t2rp3tom";
hash_map_[Name("nxdomain.example.com")] =
"v644ebqk9bibcna874givr6joj62mlhv";
hash_map_[Name("nxdomain2.example.com")] =
"q00jkcevqvmu85r014c7dkba38o0ji5r";
hash_map_[Name("nxdomain3.example.com")] =
"009mhaveqvm6t7vbl5lop2u3t2rp3tom";
}
virtual isc::dns::Name getOrigin() const { return (origin_); }
virtual isc::dns::RRClass getClass() const { return (rrclass_); }
......@@ -216,10 +238,8 @@ public:
std::vector<ConstRRsetPtr>& target,
const FindOptions options = FIND_DEFAULT);
virtual pair<bool, ConstRRsetPtr>
findNSEC3(const Name& /*name*/, bool /*recursive*/) {
throw 42; // temporary
}
virtual ZoneFinder::FindNSEC3Result
findNSEC3(const Name& name, bool recursive);
// If false is passed, it makes the zone broken as if it didn't have the
// SOA.
......@@ -254,7 +274,19 @@ private:
typedef map<RRType, ConstRRsetPtr> RRsetStore;
typedef map<Name, RRsetStore> Domains;
Domains domains_;
Domains nsec3_domains_;
void loadRRset(RRsetPtr rrset) {
if (rrset->getType() == RRType::NSEC3()) {
// NSEC3 should go to the dedicated table
nsec3_domains_[rrset->getName()][rrset->getType()] = rrset;
// By nature it should have RRSIG. (We may want to selectively
// omit this to test pathological cases).
rrset->addRRsig(RdataPtr(new generic::RRSIG(
getCommonRRSIGText(rrset->getType().
toText()))));
return;
}
domains_[rrset->getName()][rrset->getType()] = rrset;
if (rrset->getName() == delegation_name_ &&
rrset->getType() == RRType::NS()) {
......@@ -291,6 +323,7 @@ private:
// The following two will be used for faked NSEC cases
Name nsec_name_;
boost::scoped_ptr<ZoneFinder::FindResult> nsec_result_;
map<Name, string> hash_map_;
};
// A helper function that generates a new RRset based on "wild_rrset",
......@@ -332,6 +365,49 @@ MockZoneFinder::findAll(const Name& name, std::vector<ConstRRsetPtr>& target,
return (result);
}
ZoneFinder::FindNSEC3Result
MockZoneFinder::findNSEC3(const Name& name, bool recursive) {
ConstRRsetPtr covering_proof;
const int labels = name.getLabelCount();
// For brevity, we assume several things below: maps should have an
// expected entry when operator[] is used; maps are not empty.
for (int i = 0; i < labels; ++i) {
const string hlabel = hash_map_[name.split(i, labels - i)];
const Name hname = Name(hlabel + ".example.com");
// We don't use const_iterator so that we can use operator[] below
Domains::iterator found_domain = nsec3_domains_.lower_bound(hname);
// If the given hash is larger than the largest stored hash or
// the first label doesn't match the target, identify the "previous"
// hash value and remember it as the candidate next closer proof.
if (found_domain == nsec3_domains_.end() ||
found_domain->first.split(0, 1).toText(true) != hlabel) {
// If the given hash is larger or smaller than everything,
// the covering proof is the NSEC3 that has the largest hash.
if (found_domain == nsec3_domains_.end() ||
found_domain == nsec3_domains_.begin()) {
covering_proof =
nsec3_domains_.rbegin()->second[RRType::NSEC3()];
} else {
// Otherwise, H(found_domain-1) < given_hash < H(found_domain)
// The covering proof is the first one.
covering_proof = (--found_domain)->second[RRType::NSEC3()];
}
if (!recursive) { // in non recursive mode, we are done.
return (ZoneFinder::FindNSEC3Result(false, covering_proof,
ConstRRsetPtr()));
}
} else { // exact match
return (ZoneFinder::FindNSEC3Result(
true,
found_domain->second[RRType::NSEC3()],
covering_proof));
}
}
isc_throw(isc::Unexpected, "findNSEC3() isn't expected to fail");
}
ZoneFinder::FindResult
MockZoneFinder::find(const Name& name, const RRType& type,
const FindOptions options)
......@@ -367,7 +443,7 @@ MockZoneFinder::find(const Name& name, const RRType& type,
ConstRRsetPtr rrset;
// Strip whatever signature there is in case DNSSEC is not required
// Just to make sure the Query asks for it when it is needed
if (options & ZoneFinder::FIND_DNSSEC ||
if ((options & ZoneFinder::FIND_DNSSEC) != 0 ||
include_rrsig_anyway_ ||
!found_rrset->second->getRRsig()) {
rrset = found_rrset->second;
......@@ -1322,4 +1398,65 @@ TEST_F(QueryTest, MaxLenDNAME) {
EXPECT_TRUE(ok) << "The synthetized CNAME not found";
}
// Test for this test module itself
TEST_F(QueryTest, findNSEC3) {
typedef ZoneFinder::FindNSEC3Result FindNSEC3Result; // for brevity
vector<ConstRRsetPtr> actual;
// Apex name. It should have a matching NSEC3
const FindNSEC3Result result1 =
mock_finder->findNSEC3(Name("example.com"), false);
ASSERT_TRUE(result1.matched);
actual.push_back(result1.closest_proof);
rrsetsCheck(nsec3_apex_txt, actual.begin(), actual.end());
EXPECT_FALSE(result1.next_proof);
// Recursive mode doesn't change the result in this case.
actual.clear();
const FindNSEC3Result result2 =
mock_finder->findNSEC3(Name("example.com"), true);
ASSERT_TRUE(result2.matched);
actual.push_back(result2.closest_proof);
rrsetsCheck(nsec3_apex_txt, actual.begin(), actual.end());
EXPECT_FALSE(result2.next_proof);
// Non existent name. Disabling recursive, a covering NSEC3 should be
// returned.
actual.clear();
const FindNSEC3Result result3 =
mock_finder->findNSEC3(Name("nxdomain.example.com"), false);
ASSERT_FALSE(result3.matched);
actual.push_back(result3.closest_proof);
rrsetsCheck(nsec3_www_txt, actual.begin(), actual.end());
EXPECT_FALSE(result3.next_proof);
// Non existent name. The closest provable enclosure is the apex,
// and next closer is the query name.
actual.clear();
const FindNSEC3Result result4 =
mock_finder->findNSEC3(Name("nxdomain.example.com"), true);
ASSERT_TRUE(result4.matched);
actual.push_back(result4.closest_proof);
actual.push_back(result4.next_proof);
rrsetsCheck(string(nsec3_apex_txt) + string(nsec3_www_txt), actual.begin(),
actual.end());
// In the rest of test we check hash comparison for wrap around cases.
actual.clear();
const FindNSEC3Result result5 =
mock_finder->findNSEC3(Name("nxdomain2.example.com"), false);
ASSERT_FALSE(result5.matched);
actual.push_back(result5.closest_proof);
rrsetsCheck(nsec3_apex_txt, actual.begin(), actual.end());
EXPECT_FALSE(result5.next_proof);
actual.clear();
const FindNSEC3Result result6 =
mock_finder->findNSEC3(Name("nxdomain3.example.com"), false);
ASSERT_FALSE(result6.matched);
actual.push_back(result6.closest_proof);
rrsetsCheck(nsec3_www_txt, actual.begin(), actual.end());
EXPECT_FALSE(result6.next_proof);
}
}
......@@ -892,7 +892,7 @@ DatabaseClient::Finder::findInternal(const isc::dns::Name& name,
}
}
pair<bool, isc::dns::ConstRRsetPtr>
ZoneFinder::FindNSEC3Result
DatabaseClient::Finder::findNSEC3(const isc::dns::Name&, bool) {
isc_throw(NotImplemented, "findNSEC3 is not yet implemented for database "
"data source");
......
......@@ -755,8 +755,8 @@ public:
const;
/// TBD
virtual std::pair<bool, isc::dns::ConstRRsetPtr>
findNSEC3(const isc::dns::Name& name, bool recursive);
virtual FindNSEC3Result
findNSEC3(const isc::dns::Name& name, bool recursive);
/// \brief The zone ID
///
......
......@@ -641,7 +641,7 @@ InMemoryZoneFinder::findAll(const Name& name,
return (impl_->find(name, RRType::ANY(), &target, options));
}
pair<bool, isc::dns::ConstRRsetPtr>
ZoneFinder::FindNSEC3Result
InMemoryZoneFinder::findNSEC3(const isc::dns::Name&, bool) {
isc_throw(NotImplemented, "findNSEC3 is not yet implemented for in memory "
"data source");
......
......@@ -84,7 +84,7 @@ public:
const FindOptions options = FIND_DEFAULT);
/// TBD
virtual std::pair<bool, isc::dns::ConstRRsetPtr>
virtual FindNSEC3Result
findNSEC3(const isc::dns::Name& name, bool recursive);
/// \brief Imelementation of the ZoneFinder::findPreviousName method
......
......@@ -310,7 +310,20 @@ public:
const FindOptions options = FIND_DEFAULT) = 0;
/// TBD
virtual std::pair<bool, isc::dns::ConstRRsetPtr>
struct FindNSEC3Result {
FindNSEC3Result(bool param_matched,
isc::dns::ConstRRsetPtr param_closest_proof,
isc::dns::ConstRRsetPtr param_next_proof) :
matched(param_matched), closest_proof(param_closest_proof),
next_proof(param_next_proof)
{}
const bool matched;
const isc::dns::ConstRRsetPtr closest_proof;
const isc::dns::ConstRRsetPtr next_proof;
};
/// TBD
virtual FindNSEC3Result
findNSEC3(const isc::dns::Name& name, bool recursive) = 0;
/// \brief Get previous name in the zone
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment