Browse Source

[1577] Port the in-memory loop to database findNSEC3

The high-level logic of finding it is similar, so we take the loop from
the in-memory data source and adapt it to the database.
Michal 'vorner' Vaner 13 years ago
parent
commit
a29df11575
3 changed files with 86 additions and 28 deletions
  1. 59 12
      src/lib/datasrc/database.cc
  2. 1 1
      src/lib/datasrc/database.h
  3. 26 15
      src/lib/datasrc/tests/database_unittest.cc

+ 59 - 12
src/lib/datasrc/database.cc

@@ -940,7 +940,7 @@ DatabaseClient::Finder::findInternal(const Name& name, const RRType& type,
 }
 
 ZoneFinder::FindNSEC3Result
-DatabaseClient::Finder::findNSEC3(const Name& name, bool) {
+DatabaseClient::Finder::findNSEC3(const Name& name, bool recursive) {
     // TODO: Some logging.
 
     // First, validate the input
@@ -969,19 +969,66 @@ DatabaseClient::Finder::findNSEC3(const Name& name, bool) {
         dynamic_cast<const generic::NSEC3PARAM&>(
             param->second->getRdataIterator()->getCurrent())));
 
-    // Compute the hash and find the corresponding NSEC3
-    const string hash(calculator->calculate(name));
-    DatabaseAccessor::IteratorContextPtr
-        context(accessor_->getNSEC3Records(hash, zone_id_));
+    const unsigned olabels(getOrigin().getLabelCount());
+    const unsigned qlabels(name.getLabelCount());
+
+    const string otext(getOrigin().toText());
+
+    ConstRRsetPtr covering_proof;
+
+    for (unsigned labels(qlabels); labels >= olabels; -- labels) {
+        const string hash(calculator->calculate(labels == qlabels ? name :
+                                                name.split(qlabels - labels,
+                                                           labels)));
+
+        DatabaseAccessor::IteratorContextPtr
+            context(accessor_->getNSEC3Records(hash, zone_id_));
 
-    const FoundRRsets nsec3(getRRsets(hash + "." + getOrigin().toText(),
-                                      NSEC3_TYPES(), false, NULL, false,
-                                      context));
+        if (!context) {
+            isc_throw(Unexpected, "Iterator context null for hash " + hash);
+        }
+
+        const FoundRRsets nsec3(getRRsets(hash + "." + otext, NSEC3_TYPES(),
+                                          false, NULL, false, context));
+
+        if (nsec3.first) {
+            // We found an exact match against the current label.
+            const FoundIterator it(nsec3.second.find(RRType::NSEC3()));
+            if (it == nsec3.second.end()) {
+                isc_throw(DataSourceError, "Hash " + hash +
+                          "exists, but no NSEC3 there");
+            }
+
+            return (FindNSEC3Result(true, labels, it->second, covering_proof));
+        } else {
+            const string prevHash(accessor_->findPreviousNSEC3Hash(zone_id_,
+                                                                   hash));
+            context = accessor_->getNSEC3Records(prevHash, zone_id_);
+            const FoundRRsets prev_nsec3(getRRsets(prevHash + "." + otext,
+                                                   NSEC3_TYPES(), false, NULL,
+                                                   false, context));
+
+            if (!prev_nsec3.first) {
+                isc_throw(DataSourceError, "Hash " + prevHash + " returned "
+                          "from findPreviousNSEC3Hash, but it is empty");
+            }
+            const FoundIterator
+                prev_it(prev_nsec3.second.find(RRType::NSEC3()));
+            if (prev_it == prev_nsec3.second.end()) {
+                isc_throw(DataSourceError, "The previous hash " + prevHash +
+                          "exists, but does not contain the NSEC3");
+            }
+
+            covering_proof = prev_it->second;
+            if (!recursive) {
+                return (FindNSEC3Result(false, labels, covering_proof,
+                                        ConstRRsetPtr()));
+            }
+        }
+    }
 
-    // Return an expected exact match for now
-    return (FindNSEC3Result(true, name.getLabelCount(),
-                            nsec3.second.find(RRType::NSEC3())->second,
-                            ConstRRsetPtr()));
+    isc_throw(DataSourceError, "recursive findNSEC3 mode didn't stop, likely a "
+              "broken NSEC3 zone: " << otext << "/" << getClass());
 }
 
 Name

+ 1 - 1
src/lib/datasrc/database.h

@@ -684,7 +684,7 @@ public:
     /// This is used to find previous NSEC3 hashes, to find covering NSEC3 in
     /// case none match exactly.
     ///
-    /// In case a hash before before the lowest or the lowest is provided,
+    /// In case a hash before the lowest or the lowest is provided,
     /// this should return the largest one in the zone (NSEC3 needs a
     /// wrap-around semantics).
     ///

+ 26 - 15
src/lib/datasrc/tests/database_unittest.cc

@@ -211,8 +211,14 @@ const char* const TEST_RECORDS[][5] = {
 
 // FIXME: Taken from a different test. Fill with proper data when creating a test.
 const char* TEST_NSEC3_RECORDS[][5] = {
-    {"0P9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM", "NSEC3", "300", "", "1 1 12 AABBCCDD 2T7B4G4VSA5SMI47K61MV5BV1A22BOJR A RRSIG"},
-    {"0P9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM", "RRSIG", "300", "", "NSEC3 5 4 7200 20100410172647 20100311172647 63192 example.org. gNIVj4T8t51fEU6kOPpvK7HOGBFZGbalN5ZK mInyrww6UWZsUNdw07ge6/U6HfG+/s61RZ/L is2M6yUWHyXbNbj/QqwqgadG5dhxTArfuR02 xP600x0fWX8LXzW4yLMdKVxGbzYT+vvGz71o 8gHSY5vYTtothcZQa4BMKhmGQEk="},
+    {apex_hash, "NSEC3", "300", "", "1 1 12 AABBCCDD 2T7B4G4VSA5SMI47K61MV5BV1A22BOJR A RRSIG"},
+    {apex_hash, "RRSIG", "300", "", "NSEC3 5 4 7200 20100410172647 20100311172647 63192 example.org. gNIVj4T8t51fEU6kOPpvK7HOGBFZGbalN5ZK mInyrww6UWZsUNdw07ge6/U6HfG+/s61RZ/L is2M6yUWHyXbNbj/QqwqgadG5dhxTArfuR02 xP600x0fWX8LXzW4yLMdKVxGbzYT+vvGz71o 8gHSY5vYTtothcZQa4BMKhmGQEk="},
+    {ns1_hash, "NSEC3", "300", "", "1 1 12 AABBCCDD 2T7B4G4VSA5SMI47K61MV5BV1A22BOJR A RRSIG"},
+    {ns1_hash, "RRSIG", "300", "", "NSEC3 5 4 7200 20100410172647 20100311172647 63192 example.org. gNIVj4T8t51fEU6kOPpvK7HOGBFZGbalN5ZK mInyrww6UWZsUNdw07ge6/U6HfG+/s61RZ/L is2M6yUWHyXbNbj/QqwqgadG5dhxTArfuR02 xP600x0fWX8LXzW4yLMdKVxGbzYT+vvGz71o 8gHSY5vYTtothcZQa4BMKhmGQEk="},
+    {w_hash, "NSEC3", "300", "", "1 1 12 AABBCCDD 2T7B4G4VSA5SMI47K61MV5BV1A22BOJR A RRSIG"},
+    {w_hash, "RRSIG", "300", "", "NSEC3 5 4 7200 20100410172647 20100311172647 63192 example.org. gNIVj4T8t51fEU6kOPpvK7HOGBFZGbalN5ZK mInyrww6UWZsUNdw07ge6/U6HfG+/s61RZ/L is2M6yUWHyXbNbj/QqwqgadG5dhxTArfuR02 xP600x0fWX8LXzW4yLMdKVxGbzYT+vvGz71o 8gHSY5vYTtothcZQa4BMKhmGQEk="},
+    {zzz_hash, "NSEC3", "300", "", "1 1 12 AABBCCDD 2T7B4G4VSA5SMI47K61MV5BV1A22BOJR A RRSIG"},
+    {zzz_hash, "RRSIG", "300", "", "NSEC3 5 4 7200 20100410172647 20100311172647 63192 example.org. gNIVj4T8t51fEU6kOPpvK7HOGBFZGbalN5ZK mInyrww6UWZsUNdw07ge6/U6HfG+/s61RZ/L is2M6yUWHyXbNbj/QqwqgadG5dhxTArfuR02 xP600x0fWX8LXzW4yLMdKVxGbzYT+vvGz71o 8gHSY5vYTtothcZQa4BMKhmGQEk="},
     {NULL, NULL, NULL, NULL, NULL}
 };
 
@@ -3595,6 +3601,12 @@ TEST_F(MockDatabaseClientTest, findNSEC3) {
     Name origin("example.org");
     const string apex_nsec3_text = string(apex_hash) + ".example.org." +
         string(nsec3_common);
+    const string ns1_nsec3_text = string(ns1_hash) + ".example.org." +
+        string(nsec3_common);
+    const string w_nsec3_text = string(w_hash) + ".example.org." +
+        string(nsec3_common);
+    const string zzz_nsec3_text = string(zzz_hash) + ".example.org." +
+        string(nsec3_common);
 
     // Apex name.  It should have a matching NSEC3.
     {
@@ -3603,21 +3615,21 @@ TEST_F(MockDatabaseClientTest, findNSEC3) {
                        finder->findNSEC3(origin, false));
     }
 
-#if 0
     // Recursive mode doesn't change the result in this case.
     {
         SCOPED_TRACE("apex, recursive mode");
-        findNSEC3Check(true, origin_.getLabelCount(), apex_nsec3_text, "",
-                       zone_finder_.findNSEC3(origin_, true));
+        findNSEC3Check(true, origin.getLabelCount(), apex_nsec3_text, "",
+                       finder->findNSEC3(origin, true));
     }
 
-    // Non existent name.  Disabling recursion, a covering NSEC3 should be
-    // returned.
+    // Non existent name (in the NSEC3 namespace -- the findNSEC3 does
+    // not look into the normal data).  Disabling recursion, a covering
+    // NSEC3 should be returned.
     const Name www_name("www.example.org");
     {
         SCOPED_TRACE("non existent name, non recursive mode");
         findNSEC3Check(false, www_name.getLabelCount(), apex_nsec3_text, "",
-                       zone_finder_.findNSEC3(www_name, false));
+                       finder->findNSEC3(www_name, false));
     }
 
     // Non existent name.  The closest provable encloser is the apex,
@@ -3626,9 +3638,9 @@ TEST_F(MockDatabaseClientTest, findNSEC3) {
     // H(ns1) = 2T... < H(xxx) = Q0... < H(zzz) = R5...
     {
         SCOPED_TRACE("non existent name, recursive mode");
-        findNSEC3Check(true, origin_.getLabelCount(), apex_nsec3_text,
+        findNSEC3Check(true, origin.getLabelCount(), apex_nsec3_text,
                        ns1_nsec3_text,
-                       zone_finder_.findNSEC3(Name("xxx.example.org"), true));
+                       finder->findNSEC3(Name("xxx.example.org"), true));
     }
 
     // Similar to the previous case, but next closer name is different
@@ -3639,8 +3651,8 @@ TEST_F(MockDatabaseClientTest, findNSEC3) {
         SCOPED_TRACE("non existent name, non qname next closer");
         findNSEC3Check(true, Name("w.example.org").getLabelCount(),
                        w_nsec3_text, ns1_nsec3_text,
-                       zone_finder_.findNSEC3(Name("x.y.w.example.org"),
-                                              true));
+                       finder->findNSEC3(Name("x.y.w.example.org"),
+                                         true));
     }
 
     // In the rest of test we check hash comparison for wrap around cases.
@@ -3649,16 +3661,15 @@ TEST_F(MockDatabaseClientTest, findNSEC3) {
         const Name smallest_name("smallest.example.org");
         findNSEC3Check(false, smallest_name.getLabelCount(),
                        zzz_nsec3_text, "",
-                       zone_finder_.findNSEC3(smallest_name, false));
+                       finder->findNSEC3(smallest_name, false));
     }
     {
         SCOPED_TRACE("very large hash");
         const Name largest_name("largest.example.org");
         findNSEC3Check(false, largest_name.getLabelCount(),
                        zzz_nsec3_text, "",
-                       zone_finder_.findNSEC3(largest_name, false));
+                       finder->findNSEC3(largest_name, false));
     }
-#endif
 }
 
 }