// Owner names of NSEC3 have special format as defined in RFC5155,
// and cannot be a wildcard name or must be one label longer than
// the zone origin. While the RFC doesn't prohibit other forms of
- // names, no sane zone wouldn't have such names for NSEC3.
+ // names, no sane zone would have such names for NSEC3.
// BIND 9 also refuses NSEC3 at wildcard.
if (rrset->getType() == RRType::NSEC3() &&
(rrset->getName().isWildcard() ||
result::Result addRRsig(const ConstRRsetPtr sig_rrset, ZoneData& zone_data)
{
- DomainNode* node = NULL;
- if (zone_data.domains_.find(sig_rrset->getName(), &node) !=
- DomainTree::EXACTMATCH || node == NULL || !node->getData()) {
- isc_throw(AddError,
- "RRSIG is being added, but no RR to be covered: "
- << sig_rrset->getName());
- }
-
// Check consistency of the type covered.
// We know the RRset isn't empty, so the following check is safe.
RdataIteratorPtr rit = sig_rrset->getRdataIterator();
// Find the RRset to be covered; if not found, treat it as an error
// for now.
- const Domain::const_iterator it = node->getData()->find(covered);
- if (it == node->getData()->end()) {
- isc_throw(AddError,
- "RRSIG is being added, but no RR of covered type found: "
- << sig_rrset->toText());
+ ConstRRsetPtr covered_rrset;
+ if (covered != RRType::NSEC3()) {
+ DomainNode* node = NULL;
+ if (zone_data.domains_.find(sig_rrset->getName(), &node) !=
+ DomainTree::EXACTMATCH || node == NULL || !node->getData()) {
+ isc_throw(AddError,
+ "RRSIG is being added, but no RR to be covered: "
+ << sig_rrset->getName());
+ }
+ const Domain::const_iterator it = node->getData()->find(covered);
+ if (it != node->getData()->end()) {
+ covered_rrset = it->second;
+ }
+ } else {
+ // In case of NSEC3 if something is found it must be NSEC3 RRset
+ // under the assumption of our current implementation.
+ if (zone_data.nsec3_data_) {
+ string fst_label = sig_rrset->getName().split(0, 1).
+ toText(true);
+ transform(fst_label.begin(), fst_label.end(),
+ fst_label.begin(), ToUpper());
+ NSEC3Map::const_iterator found =
+ zone_data.nsec3_data_->map_.find(fst_label);
+ if (found != zone_data.nsec3_data_->map_.end()) {
+ covered_rrset = found->second;
+ assert(covered_rrset->getType() == covered);
+ }
+ }
+ }
+ if (!covered_rrset) {
+ isc_throw(AddError, "RRSIG is being added, but no RR of "
+ "covered type found: " << sig_rrset->toText());
}
// The current implementation doesn't allow an existing RRSIG to be
// overridden (or updated with additional ones).
- if ((it->second)->getRRsig()) {
+ if (covered_rrset->getRRsig()) {
isc_throw(AddError,
"RRSIG is being added to override an existing one: "
<< sig_rrset->toText());
// Note: there's a slight chance of getting an exception.
// As noted in add(), we give up strong exception guarantee in such
// cases.
- boost::const_pointer_cast<RRset>(it->second)->addRRsig(sig_rrset);
+ boost::const_pointer_cast<RRset>(covered_rrset)->addRRsig(sig_rrset);
return (result::SUCCESS);
}
// doesn't matter for the purpose of our tests.
const char* const nsec3_common = " 300 IN NSEC3 1 1 12 aabbccdd "
"2T7B4G4VSA5SMI47K61MV5BV1A22BOJR A RRSIG";
+// Likewise, common RRSIG suffix for NSEC3s.
+const char* const nsec3_rrsig_common = " 300 IN RRSIG NSEC3 5 3 3600 "
+ "20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE";
+
// For apex (example.org)
const char* const apex_hash = "0P9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM";
-const char* const apex_hash_down = "0p9mhaveqvm6t7vbl5lop2u3t2rp3tom";
+const char* const apex_hash_lower = "0p9mhaveqvm6t7vbl5lop2u3t2rp3tom";
+// For ns1.example.org
+const char* const ns1_hash = "2t7b4g4vsa5smi47k61mv5bv1a22bojr";
TEST_F(InMemoryZoneFinderTest, addNSEC3) {
const string nsec3_text = string(apex_hash) + ".example.org." +
zone_finder_.findNSEC3Tmp(Name("example.org"), false);
actual_rrsets_.push_back(result2.closest_proof);
rrsetsCheck(nsec3_text, actual_rrsets_.begin(), actual_rrsets_.end());
+
+ // 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) {
// Similar to the previous case, but NSEC3 owner name is lower-cased.
- const string nsec3_text = string(apex_hash_down) + ".example.org." +
+ const string nsec3_text = string(apex_hash_lower) + ".example.org." +
string(nsec3_common);
EXPECT_EQ(result::SUCCESS, zone_finder_.add(textToRRset(nsec3_text)));
ZoneFinder::FindNSEC3Result result =
".example.org." +
string(nsec3_common))),
InMemoryZoneFinder::AddError);
+}
+
+TEST_F(InMemoryZoneFinderTest, addNSEC3WithRRSIG) {
+ // 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.
+ ZoneFinder::FindNSEC3Result result =
+ zone_finder_.findNSEC3Tmp(Name("example.org"), false);
+ EXPECT_TRUE(result.matched);
+ ASSERT_TRUE(result.closest_proof);
+ ASSERT_TRUE(result.closest_proof->getRRsig());
+ actual_rrsets_.push_back(result.closest_proof);
+ actual_rrsets_.push_back(result.closest_proof->getRRsig());
+ rrsetsCheck(nsec3_text + "\n" + nsec3_rrsig_text, actual_rrsets_.begin(),
+ actual_rrsets_.end());
+
+ // 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);
+}
- // - adding RRSIG for NSEC3
- // - case where the main tree has NSEC3 name
// - parameter consistency
// - existence of NSEC3PARAM
// - parameter consistency with NSEC3PARAM
// - add NSEC3PARAM first/second
}
-}