From: JINMEI Tatuya Date: Wed, 8 Feb 2012 02:24:43 +0000 (-0800) Subject: [1576] covered bogus cases of findNSEC3(). X-Git-Tag: trac2351_base~97^2~35^2~8 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=88aa930fd6189c121c784b2175aab519d72ed5ab;p=thirdparty%2Fkea.git [1576] covered bogus cases of findNSEC3(). --- diff --git a/src/lib/datasrc/memory_datasrc.cc b/src/lib/datasrc/memory_datasrc.cc index be513dc7d6..9a3ec316df 100644 --- a/src/lib/datasrc/memory_datasrc.cc +++ b/src/lib/datasrc/memory_datasrc.cc @@ -882,27 +882,46 @@ InMemoryZoneFinder::findAll(const Name& name, ZoneFinder::FindNSEC3Result InMemoryZoneFinder::findNSEC3(const Name& name, bool recursive) { - // TODO validation (no NSEC3 case, out of zone name) - - const NSEC3Hash& nsec3hash = *impl_->zone_data_->nsec3_data_->hash_; + if (!impl_->zone_data_->nsec3_data_) { + isc_throw(DataSourceError, + "findNSEC3 attempt for non NSEC3 signed zone: " << + impl_->origin_ << "/" << impl_->zone_class_); + } const NSEC3Map& map = impl_->zone_data_->nsec3_data_->map_; + if (map.empty()) { + isc_throw(DataSourceError, + "findNSEC3 attempt but zone has no NSEC3 RR: " << + impl_->origin_ << "/" << impl_->zone_class_); + } + const NameComparisonResult cmp_result = name.compare(impl_->origin_); + if (cmp_result.getRelation() != NameComparisonResult::EQUAL && + cmp_result.getRelation() != NameComparisonResult::SUBDOMAIN) { + isc_throw(InvalidParameter, "findNSEC3 attempt for out-of-zone name: " + << name << ", zone: " << impl_->origin_ << "/" + << impl_->zone_class_); + } - ConstRRsetPtr covering_proof; // placeholder of the next closer proof + // Convenient shortcuts + const NSEC3Hash& nsec3hash = *impl_->zone_data_->nsec3_data_->hash_; const unsigned int olabels = impl_->origin_.getLabelCount(); const unsigned int qlabels = name.getLabelCount(); + + ConstRRsetPtr covering_proof; // placeholder of the next closer proof + // Examine all names from the query name to the origin name, stripping + // the deepest label one by one, until we find a name that has a matching + // NSEC3 hash. for (unsigned int labels = qlabels; labels >= olabels; --labels) { const string hlabel = nsec3hash.calculate( labels == qlabels ? name : name.split(qlabels - labels, labels)); - NSEC3Map::const_iterator found = map.lower_bound(hlabel); // 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 == map.end() || found->first != hlabel) { - // If the given hash is larger (or smaller than everything, TBD) + // If the given hash is larger or smaller than everything, // the covering proof is the NSEC3 that has the largest hash. - // Note that we know the map isn't empty (TBD), so rbegin() is + // Note that we know the map isn't empty, so rbegin() is // safe. if (found == map.end() || found == map.begin()) { covering_proof = map.rbegin()->second; @@ -922,7 +941,9 @@ InMemoryZoneFinder::findNSEC3(const Name& name, bool recursive) { } } - isc_throw(Unexpected, "uncovered test case"); + isc_throw(DataSourceError, "recursive findNSEC3 mode didn't stop, likely " + "a broken NSEC3 zone: " << impl_->origin_ << "/" + << impl_->zone_class_); } ZoneFinder::FindNSEC3Result diff --git a/src/lib/datasrc/tests/memory_datasrc_unittest.cc b/src/lib/datasrc/tests/memory_datasrc_unittest.cc index fda5f89cef..3078b8d9e3 100644 --- a/src/lib/datasrc/tests/memory_datasrc_unittest.cc +++ b/src/lib/datasrc/tests/memory_datasrc_unittest.cc @@ -1862,6 +1862,12 @@ TEST_F(InMemoryZoneFinderTest, findNSEC3) { string(nsec3_common); EXPECT_EQ(result::SUCCESS, zone_finder_.add(textToRRset(zzz_nsec3_text))); + // Parameter validation: the query name must be in or below the zone + EXPECT_THROW(zone_finder_.findNSEC3(Name("example.com"), false), + isc::InvalidParameter); + EXPECT_THROW(zone_finder_.findNSEC3(Name("org"), true), + isc::InvalidParameter); + // Apex name. It should have a matching NSEC3. { SCOPED_TRACE("apex, non recursive mode"); @@ -1924,4 +1930,26 @@ TEST_F(InMemoryZoneFinderTest, findNSEC3) { zone_finder_.findNSEC3(largest_name, false)); } } + +TEST_F(InMemoryZoneFinderTest, findNSEC3ForWithoutNSEC3) { + // 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 isn't 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); +} }