BIND 10 master, updated. 56bd002f57d397ec4c1fffb40c499425e36b21de Merge #1577

BIND 10 source code commits bind10-changes at lists.isc.org
Mon Apr 16 10:33:02 UTC 2012


The branch, master has been updated
       via  56bd002f57d397ec4c1fffb40c499425e36b21de (commit)
       via  4108ca766cb9bce434bfbb786436b7c08adb87a4 (commit)
       via  de9ccf5df44c42526b2cd8e7f078d6073729c35a (commit)
       via  c47c4c3541a5a9ed7a77f47610d8f14c29295969 (commit)
       via  7130e28820b2e9e603f64546deebf12b410b897d (commit)
       via  a29df11575ac9b1aa036ab212b49f4706ba1e607 (commit)
       via  a98fc15799b0d8898ab3b5071ba55dd8935d45dc (commit)
       via  b407617f16ae9d672ef0e7812a8eb9e18509b6e6 (commit)
       via  76f364b152f174c57982f294f97274a212684121 (commit)
       via  7ef140c77fa2ddd4194ffdc344781a55232d68b3 (commit)
       via  16a1358aa2960039e192ac66d504150a55b374fe (commit)
       via  c02b9f4c1f0970cd50c5486f739dd750046ae97b (commit)
      from  4653281fb863709e2ab9ca26514fe9e31cd8444d (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 56bd002f57d397ec4c1fffb40c499425e36b21de
Merge: 4653281fb863709e2ab9ca26514fe9e31cd8444d 4108ca766cb9bce434bfbb786436b7c08adb87a4
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date:   Mon Apr 16 12:14:54 2012 +0200

    Merge #1577
    
    Conflicts:
    	src/lib/datasrc/tests/memory_datasrc_unittest.cc

commit 4108ca766cb9bce434bfbb786436b7c08adb87a4
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date:   Sat Apr 14 16:51:44 2012 +0200

    [1577] Logging messages fixes
    
    One missing placeholder and one explanation in the text.

commit de9ccf5df44c42526b2cd8e7f078d6073729c35a
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date:   Sat Apr 14 16:49:00 2012 +0200

    [1577] Share some test code
    
    As it had two copies (one in in-memory tests and one in database ones),
    it can be moved to a separate function.

commit c47c4c3541a5a9ed7a77f47610d8f14c29295969
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date:   Thu Apr 12 14:58:52 2012 +0200

    [1577] Code comments for findNSEC3

commit 7130e28820b2e9e603f64546deebf12b410b897d
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date:   Thu Apr 12 14:36:45 2012 +0200

    [1577] Logging for findNSEC3

commit a29df11575ac9b1aa036ab212b49f4706ba1e607
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date:   Thu Apr 12 14:11:25 2012 +0200

    [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.

commit a98fc15799b0d8898ab3b5071ba55dd8935d45dc
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date:   Wed Apr 11 16:57:40 2012 +0200

    [1577] Reuse more code in findNSEC3
    
    The internal function used to create normal RRs when looking them up is
    reused for the ones from NSEC3 namespace as well.

commit b407617f16ae9d672ef0e7812a8eb9e18509b6e6
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date:   Wed Apr 11 10:46:16 2012 +0200

    [1577] Test findNSEC3 throws on non-NSEC3 zone
    
    Just confirming it throws in case there's no NSEC3PARAM to compute the
    hash by.

commit 76f364b152f174c57982f294f97274a212684121
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date:   Wed Apr 11 10:35:49 2012 +0200

    [1577] First shot at the findNSEC3 implementation
    
    This one is wrong in many ways. It assumes (without checking) it gets an
    exact match, it does not check any wrong data, it expects given order of
    results. But it passes the minimal test now, and can be used as a base
    for improving the implementation.

commit 7ef140c77fa2ddd4194ffdc344781a55232d68b3
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date:   Tue Apr 10 15:58:33 2012 +0200

    [1577] Validate the findNSEC3 input
    
    We check the name comes from inside the zone.

commit 16a1358aa2960039e192ac66d504150a55b374fe
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date:   Mon Apr 9 16:46:03 2012 +0200

    [1577] Port a NSEC3 test from memory to database
    
    One test is taken and ported to the database. It does compile partially
    (the rest is commented out for now) and does not pass. Also, another
    function moved to common file.

commit c02b9f4c1f0970cd50c5486f739dd750046ae97b
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date:   Mon Apr 9 15:21:33 2012 +0200

    [1577] Move TestNSEC3HashCreator to separate file
    
    I want to reuse it in another test, so taking the help mock class out.

-----------------------------------------------------------------------

Summary of changes:
 src/lib/datasrc/database.cc                      |  146 +++++++++++++++-
 src/lib/datasrc/database.h                       |    9 +-
 src/lib/datasrc/datasrc_messages.mes             |   29 ++++
 src/lib/datasrc/tests/Makefile.am                |    1 +
 src/lib/datasrc/tests/database_unittest.cc       |   70 ++++++++-
 src/lib/datasrc/tests/faked_nsec3.cc             |  196 ++++++++++++++++++++++
 src/lib/datasrc/tests/faked_nsec3.h              |   86 ++++++++++
 src/lib/datasrc/tests/memory_datasrc_unittest.cc |  181 +-------------------
 8 files changed, 527 insertions(+), 191 deletions(-)
 create mode 100644 src/lib/datasrc/tests/faked_nsec3.cc
 create mode 100644 src/lib/datasrc/tests/faked_nsec3.h

-----------------------------------------------------------------------
diff --git a/src/lib/datasrc/database.cc b/src/lib/datasrc/database.cc
index d71ed8b..fcb2971 100644
--- a/src/lib/datasrc/database.cc
+++ b/src/lib/datasrc/database.cc
@@ -27,15 +27,18 @@
 #include <dns/rrset.h>
 #include <dns/rdata.h>
 #include <dns/rdataclass.h>
+#include <dns/nsec3hash.h>
 
 #include <datasrc/data_source.h>
 #include <datasrc/logger.h>
 
 #include <boost/foreach.hpp>
+#include <boost/scoped_ptr.hpp>
 
 using namespace isc::dns;
 using namespace std;
 using namespace isc::dns::rdata;
+using namespace boost;
 
 namespace isc {
 namespace datasrc {
@@ -177,15 +180,17 @@ private:
 DatabaseClient::Finder::FoundRRsets
 DatabaseClient::Finder::getRRsets(const string& name, const WantedTypes& types,
                                   bool check_ns, const string* construct_name,
-                                  bool any)
+                                  bool any,
+                                  DatabaseAccessor::IteratorContextPtr context)
 {
     RRsigStore sig_store;
     bool records_found = false;
     std::map<RRType, RRsetPtr> result;
 
-    // Request the context
-    DatabaseAccessor::IteratorContextPtr
-        context(accessor_->getRecords(name, zone_id_));
+    // Request the context in case we didn't get one
+    if (!context) {
+        context = accessor_->getRecords(name, zone_id_);
+    }
     // It must not return NULL, that's a bug of the implementation
     if (!context) {
         isc_throw(isc::Unexpected, "Iterator context null at " + name);
@@ -316,12 +321,12 @@ namespace {
 typedef std::set<RRType> WantedTypes;
 
 const WantedTypes&
-NSEC_TYPES() {
+NSEC3_TYPES() {
     static bool initialized(false);
     static WantedTypes result;
 
     if (!initialized) {
-        result.insert(RRType::NSEC());
+        result.insert(RRType::NSEC3());
         initialized = true;
     }
     return (result);
@@ -331,6 +336,7 @@ const WantedTypes&
 NSEC3PARAM_TYPES() {
     static bool initialized(false);
     static WantedTypes result;
+
     if (!initialized) {
         result.insert(RRType::NSEC3PARAM());
         initialized = true;
@@ -339,6 +345,18 @@ NSEC3PARAM_TYPES() {
 }
 
 const WantedTypes&
+NSEC_TYPES() {
+    static bool initialized(false);
+    static WantedTypes result;
+
+    if (!initialized) {
+        result.insert(RRType::NSEC());
+        initialized = true;
+    }
+    return (result);
+}
+
+const WantedTypes&
 DELEGATION_TYPES() {
     static bool initialized(false);
     static WantedTypes result;
@@ -968,10 +986,120 @@ DatabaseClient::Finder::findInternal(const Name& name, const RRType& type,
     }
 }
 
+// The behaviour is inspired by the one in the in-memory implementation.
 ZoneFinder::FindNSEC3Result
-DatabaseClient::Finder::findNSEC3(const Name&, bool) {
-    isc_throw(NotImplemented, "findNSEC3 is not yet implemented for database "
-              "data source");
+DatabaseClient::Finder::findNSEC3(const Name& name, bool recursive) {
+    LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_DATABASE_FINDNSEC3).arg(name).
+        arg(recursive ? "recursive" : "non-recursive");
+
+    // First, validate the input
+    const NameComparisonResult cmp_result(name.compare(getOrigin()));
+    if (cmp_result.getRelation() != NameComparisonResult::EQUAL &&
+        cmp_result.getRelation() != NameComparisonResult::SUBDOMAIN) {
+        isc_throw(OutOfZone, "findNSEC3 attempt for out-of-zone name: " <<
+                  name << ", zone: " << getOrigin() << "/" << getClass());
+    }
+
+    // Now, we need to get the NSEC3 params from the apex and create the hash
+    // creator for it.
+    const FoundRRsets nsec3param(getRRsets(getOrigin().toText(),
+                                 NSEC3PARAM_TYPES(), false));
+    const FoundIterator param(nsec3param.second.find(RRType::NSEC3PARAM()));
+    if (!nsec3param.first || param == nsec3param.second.end()) {
+        // No NSEC3 params? :-(
+        isc_throw(DataSourceError, "findNSEC3 attempt for non NSEC3 signed " <<
+                  "zone: " << getOrigin() << "/" << getClass());
+    }
+    // This takes the RRset received from the find method, takes the first RR
+    // in it, casts it to NSEC3PARAM (as it should be that one) and then creates
+    // the hash calculator class from it.
+    const scoped_ptr<NSEC3Hash> calculator(NSEC3Hash::create(
+        dynamic_cast<const generic::NSEC3PARAM&>(
+            param->second->getRdataIterator()->getCurrent())));
+
+    // Few shortcut variables
+    const unsigned olabels(getOrigin().getLabelCount());
+    const unsigned qlabels(name.getLabelCount());
+    const string otext(getOrigin().toText());
+
+    // This will be set to the one covering the query name
+    ConstRRsetPtr covering_proof;
+
+    // We keep stripping the leftmost label until we find something.
+    // In case it is recursive, we'll exit the loop at the first iteration.
+    for (unsigned labels(qlabels); labels >= olabels; -- labels) {
+        const string hash(calculator->calculate(labels == qlabels ? name :
+                                                name.split(qlabels - labels,
+                                                           labels)));
+        // Get the exact match for the name.
+        LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_DATABASE_FINDNSEC3_TRYHASH).
+            arg(name).arg(labels).arg(hash);
+
+        DatabaseAccessor::IteratorContextPtr
+            context(accessor_->getNSEC3Records(hash, zone_id_));
+
+        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");
+            }
+
+            LOG_DEBUG(logger, DBG_TRACE_BASIC,
+                      DATASRC_DATABASE_FINDNSEC3_MATCH).arg(name).arg(labels).
+                arg(*it->second);
+            // Yes, we win
+            return (FindNSEC3Result(true, labels, it->second, covering_proof));
+        } else {
+            // There's no exact match. We try a previous one. We must find it
+            // (if the zone is properly signed).
+            const string prevHash(accessor_->findPreviousNSEC3Hash(zone_id_,
+                                                                   hash));
+            LOG_DEBUG(logger, DBG_TRACE_BASIC,
+                      DATASRC_DATABASE_FINDNSEC3_TRYHASH_PREV).arg(name).
+                arg(labels).arg(prevHash);
+            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;
+            // In case it is recursive, we try to get an exact match a level
+            // up. If it is not recursive, the caller is ok with a covering
+            // one, so we just return it.
+            if (!recursive) {
+                LOG_DEBUG(logger, DBG_TRACE_BASIC,
+                          DATASRC_DATABASE_FINDNSEC3_COVER).arg(name).
+                    arg(labels).arg(*covering_proof);
+                return (FindNSEC3Result(false, labels, covering_proof,
+                                        ConstRRsetPtr()));
+            }
+        }
+    }
+
+    // The zone must contain at least the apex and that one should match
+    // exactly. If that doesn't happen, we have a problem.
+    isc_throw(DataSourceError, "recursive findNSEC3 mode didn't stop, likely a "
+              "broken NSEC3 zone: " << otext << "/" << getClass());
 }
 
 Name
diff --git a/src/lib/datasrc/database.h b/src/lib/datasrc/database.h
index 0318589..40134fc 100644
--- a/src/lib/datasrc/database.h
+++ b/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).
     ///
@@ -889,6 +889,9 @@ public:
         ///     ones requested by types. It also puts a NULL pointer under the
         ///     ANY type into the result, if it finds any RRs at all, to easy the
         ///     identification of success.
+        /// \param srcContext This can be set to non-NULL value to override the
+        ///     iterator context used for obtaining the data. This can be used,
+        ///     for example, to get data from the NSEC3 namespace.
         /// \return A pair, where the first element indicates if the domain
         ///     contains any RRs at all (not only the requested, it may happen
         ///     this is set to true, but the second part is empty). The second
@@ -900,7 +903,9 @@ public:
         FoundRRsets getRRsets(const std::string& name,
                               const WantedTypes& types, bool check_ns,
                               const std::string* construct_name = NULL,
-                              bool any = false);
+                              bool any = false,
+                              DatabaseAccessor::IteratorContextPtr srcContext =
+                              DatabaseAccessor::IteratorContextPtr());
 
         /// \brief DNSSEC related context for ZoneFinder::findInternal.
         ///
diff --git a/src/lib/datasrc/datasrc_messages.mes b/src/lib/datasrc/datasrc_messages.mes
index 3801a41..a9870d6 100644
--- a/src/lib/datasrc/datasrc_messages.mes
+++ b/src/lib/datasrc/datasrc_messages.mes
@@ -75,6 +75,35 @@ The datasource tried to provide an NSEC proof that the named domain does not
 exist, but the database backend doesn't support DNSSEC. No proof is included
 in the answer as a result.
 
+% DATASRC_DATABASE_FINDNSEC3 Looking for NSEC3 for %1 in %2 mode
+Debug information. A search in an database data source for NSEC3 that
+matches or covers the given name is being started.
+
+% DATASRC_DATABASE_FINDNSEC3_COVER found a covering NSEC3 for %1: %2
+Debug information. An NSEC3 that covers the given name is found and
+being returned.  The found NSEC3 RRset is also displayed.
+
+% DATASRC_DATABASE_FINDNSEC3_MATCH found a matching NSEC3 for %1 at label count %2: %3
+Debug information. An NSEC3 that matches (a possibly superdomain of)
+the given name is found and being returned.  When the shown label
+count is smaller than that of the given name, the matching NSEC3 is
+for a superdomain of the given name (see DATASRC_DATABSE_FINDNSEC3_TRYHASH).
+The found NSEC3 RRset is also displayed.
+
+% DATASRC_DATABASE_FINDNSEC3_TRYHASH looking for NSEC3 for %1 at label count %2 (hash %3)
+Debug information. In an attempt of finding an NSEC3 for the give name,
+(a possibly superdomain of) the name is hashed and searched for in the
+NSEC3 name space.  When the shown label count is smaller than that of the
+shown name, the search tries the superdomain name that share the shown
+(higher) label count of the shown name (e.g., for
+www.example.com. with shown label count of 3, example.com. is being
+tried, as "." is 1 label long).
+
+% DATASRC_DATABASE_FINDNSEC3_TRYHASH_PREV looking for previous NSEC3 for %1 at label count %2 (hash %3)
+Debug information. An exact match on hash (see
+DATASRC_DATABASE_FINDNSEC3_TRYHASH) was unsuccessful. We get the previous hash
+to that one instead.
+
 % DATASRC_DATABASE_FIND_RECORDS looking in datasource %1 for record %2/%3/%4
 Debug information. The database data source is looking up records with the given
 name and type in the database.
diff --git a/src/lib/datasrc/tests/Makefile.am b/src/lib/datasrc/tests/Makefile.am
index c635c33..1728f22 100644
--- a/src/lib/datasrc/tests/Makefile.am
+++ b/src/lib/datasrc/tests/Makefile.am
@@ -59,6 +59,7 @@ run_unittests_SOURCES += sqlite3_accessor_unittest.cc
 run_unittests_SOURCES += memory_datasrc_unittest.cc
 run_unittests_SOURCES += rbnode_rrset_unittest.cc
 run_unittests_SOURCES += zone_finder_context_unittest.cc
+run_unittests_SOURCES += faked_nsec3.h faked_nsec3.cc
 
 # We need the actual module implementation in the tests (they are not part
 # of libdatasrc)
diff --git a/src/lib/datasrc/tests/database_unittest.cc b/src/lib/datasrc/tests/database_unittest.cc
index cd844e4..e09082d 100644
--- a/src/lib/datasrc/tests/database_unittest.cc
+++ b/src/lib/datasrc/tests/database_unittest.cc
@@ -12,6 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
+#include "faked_nsec3.h"
+
 #include <stdlib.h>
 
 #include <boost/shared_ptr.hpp>
@@ -24,6 +26,7 @@
 #include <dns/name.h>
 #include <dns/rrttl.h>
 #include <dns/rrset.h>
+#include <dns/nsec3hash.h>
 #include <exceptions/exceptions.h>
 
 #include <datasrc/database.h>
@@ -44,6 +47,7 @@ using namespace std;
 using boost::dynamic_pointer_cast;
 using boost::lexical_cast;
 using namespace isc::dns;
+using namespace isc::datasrc::test;
 
 namespace {
 
@@ -210,8 +214,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] = {
-    {"1BB7SO0452U1QHL98UISNDD9218GELR5", "NSEC3", "3600", "", "1 0 10 FEEDABEE 4KLSVDE8KH8G95VU68R7AHBE1CPQN38J"},
-    {"1BB7SO0452U1QHL98UISNDD9218GELR5", "RRSIG", "3600", "", "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}
 };
 
@@ -955,7 +965,7 @@ private:
              i = cur_name_.begin(); i != cur_name_.end(); ++ i) {
             i->push_back(hash);
         }
-        (*readonly_records_)[hash] = cur_name_;
+        nsec3_namespace_[hash] = cur_name_;
         cur_name_.clear();
     }
 
@@ -993,6 +1003,31 @@ private:
         }
         addCurHash(prev_name);
     }
+
+public:
+    // This adds the NSEC3PARAM into the apex, so we can perform some NSEC3
+    // tests. Note that the NSEC3 namespace is available in other tests, but
+    // it should not be accessed at that time.
+    void enableNSEC3() {
+        // We place the signature first, so it's in the block with the other
+        // signatures
+        vector<string> signature;
+        signature.push_back("RRSIG");
+        signature.push_back("3600");
+        signature.push_back("");
+        signature.push_back("NSEC3PARAM 5 3 3600 20000101000000 20000201000000 "
+                            "12345 example.org. FAKEFAKEFAKE");
+        signature.push_back("exmaple.org.");
+        (*readonly_records_)["example.org."].push_back(signature);
+        // Now the NSEC3 param itself
+        vector<string> param;
+        param.push_back("NSEC3PARAM");
+        param.push_back("3600");
+        param.push_back("");
+        param.push_back("1 0 12 aabbccdd");
+        param.push_back("example.org.");
+        (*readonly_records_)["example.org."].push_back(param);
+    }
 };
 
 // This tests the default getRecords behaviour, throwing NotImplemented
@@ -1046,6 +1081,11 @@ public:
                                                "FAKEFAKEFAKE"));
     }
 
+    ~ DatabaseClientTest() {
+        // Make sure we return the default creator no matter if we set it or not
+        setNSEC3HashCreator(NULL);
+    }
+
     /*
      * We initialize the client from a function, so we can call it multiple
      * times per test.
@@ -1206,6 +1246,9 @@ public:
     const std::vector<std::string> empty_rdatas_; // for NXRRSET/NXDOMAIN
     std::vector<std::string> expected_rdatas_;
     std::vector<std::string> expected_sig_rdatas_;
+
+    // A creator for use in several NSEC3 related tests.
+    TestNSEC3HashCreator test_nsec3_hash_creator_;
 };
 
 class TestSQLite3Accessor : public SQLite3Accessor {
@@ -3742,4 +3785,25 @@ TEST_F(MockDatabaseClientTest, journalWithBadData) {
                  second->getNextDiff(), DataSourceError);
 }
 
+/// Let us test a little bit of NSEC3.
+TEST_F(MockDatabaseClientTest, findNSEC3) {
+    // Set up the faked hash calculator.
+    setNSEC3HashCreator(&test_nsec3_hash_creator_);
+
+    DataSourceClient::FindResult
+        zone(this->client_->findZone(Name("example.org")));
+    ASSERT_EQ(result::SUCCESS, zone.code);
+    boost::shared_ptr<DatabaseClient::Finder> finder(
+        dynamic_pointer_cast<DatabaseClient::Finder>(zone.zone_finder));
+
+    // It'll complain if there is no NSEC3PARAM yet
+    EXPECT_THROW(finder->findNSEC3(Name("example.org"), false),
+                 DataSourceError);
+    // And enable NSEC3 in the zone.
+    this->current_accessor_->enableNSEC3();
+
+    // The rest is in the function, it is shared with in-memory tests
+    performNSEC3Test(*finder);
+}
+
 }
diff --git a/src/lib/datasrc/tests/faked_nsec3.cc b/src/lib/datasrc/tests/faked_nsec3.cc
new file mode 100644
index 0000000..4ca22a5
--- /dev/null
+++ b/src/lib/datasrc/tests/faked_nsec3.cc
@@ -0,0 +1,196 @@
+// Copyright (C) 2011  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 <dns/name.h>
+#include <testutils/dnsmessage_test.h>
+
+#include <map>
+#include <gtest/gtest.h>
+
+using namespace std;
+using namespace isc::dns;
+using namespace isc::testutils;
+
+namespace isc {
+namespace datasrc {
+namespace test {
+
+class TestNSEC3HashCreator::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 rdata::generic::NSEC3PARAM&) const {
+        return (true);
+    }
+    virtual bool match(const rdata::generic::NSEC3&) const {
+        return (true);
+    }
+};
+
+NSEC3Hash* TestNSEC3HashCreator::create(const rdata::generic::NSEC3PARAM&)
+    const
+{
+    return (new TestNSEC3Hash);
+}
+
+NSEC3Hash* TestNSEC3HashCreator::create(const rdata::generic::NSEC3&) const {
+    return (new TestNSEC3Hash);
+}
+
+void
+findNSEC3Check(bool expected_matched, uint8_t expected_labels,
+               const string& expected_closest,
+               const string& expected_next,
+               const ZoneFinder::FindNSEC3Result& result,
+               bool expected_sig)
+{
+    EXPECT_EQ(expected_matched, result.matched);
+    // Convert to int so the error messages would be more readable:
+    EXPECT_EQ(static_cast<int>(expected_labels),
+              static_cast<int>(result.closest_labels));
+
+    vector<ConstRRsetPtr> actual_rrsets;
+    ASSERT_TRUE(result.closest_proof);
+    actual_rrsets.push_back(result.closest_proof);
+    if (expected_sig) {
+        actual_rrsets.push_back(result.closest_proof->getRRsig());
+    }
+    rrsetsCheck(expected_closest, actual_rrsets.begin(),
+                actual_rrsets.end());
+
+    actual_rrsets.clear();
+    if (expected_next.empty()) {
+        EXPECT_FALSE(result.next_proof);
+    } else {
+        ASSERT_TRUE(result.next_proof);
+        actual_rrsets.push_back(result.next_proof);
+        if (expected_sig) {
+            actual_rrsets.push_back(result.next_proof->getRRsig());
+        }
+        rrsetsCheck(expected_next, actual_rrsets.begin(),
+                    actual_rrsets.end());
+    }
+}
+
+void
+performNSEC3Test(ZoneFinder &finder) {
+    // Parameter validation: the query name must be in or below the zone
+    EXPECT_THROW(finder.findNSEC3(Name("example.com"), false), OutOfZone);
+    EXPECT_THROW(finder.findNSEC3(Name("org"), true), OutOfZone);
+
+    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.
+    {
+        SCOPED_TRACE("apex, non recursive mode");
+        findNSEC3Check(true, origin.getLabelCount(), apex_nsec3_text, "",
+                       finder.findNSEC3(origin, false));
+    }
+
+    // Recursive mode doesn't change the result in this case.
+    {
+        SCOPED_TRACE("apex, recursive mode");
+        findNSEC3Check(true, origin.getLabelCount(), apex_nsec3_text, "",
+                       finder.findNSEC3(origin, true));
+    }
+
+    // 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, "",
+                       finder.findNSEC3(www_name, false));
+    }
+
+    // Non existent name.  The closest provable encloser is the apex,
+    // and next closer is the query name itself (which NSEC3 for ns1
+    // covers)
+    // H(ns1) = 2T... < H(xxx) = Q0... < H(zzz) = R5...
+    {
+        SCOPED_TRACE("non existent name, recursive mode");
+        findNSEC3Check(true, origin.getLabelCount(), apex_nsec3_text,
+                       ns1_nsec3_text,
+                       finder.findNSEC3(Name("xxx.example.org"), true));
+    }
+
+    // Similar to the previous case, but next closer name is different
+    // from the query name.  The closet encloser is w.example.org, and
+    // next closer is y.w.example.org.
+    // H(ns1) = 2T.. < H(y.w) = K8.. < H(zzz) = R5
+    {
+        SCOPED_TRACE("non existent name, non qname next closer");
+        findNSEC3Check(true, Name("w.example.org").getLabelCount(),
+                       w_nsec3_text, ns1_nsec3_text,
+                       finder.findNSEC3(Name("x.y.w.example.org"),
+                                         true));
+    }
+
+    // In the rest of test we check hash comparison for wrap around cases.
+    {
+        SCOPED_TRACE("very small hash");
+        const Name smallest_name("smallest.example.org");
+        findNSEC3Check(false, smallest_name.getLabelCount(),
+                       zzz_nsec3_text, "",
+                       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, "",
+                       finder.findNSEC3(largest_name, false));
+    }
+}
+
+}
+}
+}
diff --git a/src/lib/datasrc/tests/faked_nsec3.h b/src/lib/datasrc/tests/faked_nsec3.h
new file mode 100644
index 0000000..51b4059
--- /dev/null
+++ b/src/lib/datasrc/tests/faked_nsec3.h
@@ -0,0 +1,86 @@
+// Copyright (C) 2011  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.
+
+#ifndef FAKED_NSEC3_H
+#define FAKED_NSEC3_H
+
+#include <datasrc/zone.h>
+
+#include <dns/nsec3hash.h>
+
+#include <stdint.h>
+#include <string>
+
+namespace isc {
+namespace datasrc {
+namespace test {
+
+//
+// (Faked) NSEC3 hash data.  Arbitrarily borrowed from RFC515 examples.
+//
+// Commonly used NSEC3 suffix.  It's incorrect to use it for all NSEC3s, but
+// 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";
+
+// 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 isc::dns::NSEC3HashCreator {
+private:
+    class TestNSEC3Hash;
+public:
+    virtual isc::dns::NSEC3Hash* create(const
+                                        isc::dns::rdata::generic::NSEC3PARAM&)
+        const;
+    virtual isc::dns::NSEC3Hash* create(const isc::dns::rdata::generic::NSEC3&)
+        const;
+};
+
+// Check the result against expected values. It directly calls EXPECT_ macros
+void
+findNSEC3Check(bool expected_matched, uint8_t expected_labels,
+               const std::string& expected_closest,
+               const std::string& expected_next,
+               const isc::datasrc::ZoneFinder::FindNSEC3Result& result,
+               bool expected_sig = false);
+
+// Perform the shared part of NSEC3 test (shared between in-memory and database
+// tests).
+void
+performNSEC3Test(ZoneFinder &finder);
+
+}
+}
+}
+
+#endif
diff --git a/src/lib/datasrc/tests/memory_datasrc_unittest.cc b/src/lib/datasrc/tests/memory_datasrc_unittest.cc
index e480b0b..a7d13d5 100644
--- a/src/lib/datasrc/tests/memory_datasrc_unittest.cc
+++ b/src/lib/datasrc/tests/memory_datasrc_unittest.cc
@@ -12,6 +12,8 @@
 // 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>
@@ -48,6 +50,7 @@ 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)
@@ -302,72 +305,6 @@ textToRRset(const string& text_rrset, const RRClass& rrclass = RRClass::IN(),
     return (rrset);
 }
 
-// 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
@@ -1707,52 +1644,6 @@ TEST_F(InMemoryZoneFinderTest, addbadRRsig) {
                  InMemoryZoneFinder::AddError);
 }
 
-//
-// (Faked) NSEC3 hash data.  Arbitrarily borrowed from RFC515 examples.
-//
-// Commonly used NSEC3 suffix.  It's incorrect to use it for all NSEC3s, but
-// 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";
-
-void
-findNSEC3Check(bool expected_matched, uint8_t expected_labels,
-               const string& expected_closest,
-               const string& expected_next,
-               const ZoneFinder::FindNSEC3Result& result,
-               bool expected_sig = false)
-{
-    EXPECT_EQ(expected_matched, result.matched);
-    // Convert to int so the error messages would be more readable:
-    EXPECT_EQ(static_cast<int>(expected_labels),
-              static_cast<int>(result.closest_labels));
-
-    vector<ConstRRsetPtr> actual_rrsets;
-    ASSERT_TRUE(result.closest_proof);
-    actual_rrsets.push_back(result.closest_proof);
-    if (expected_sig) {
-        actual_rrsets.push_back(result.closest_proof->getRRsig());
-    }
-    rrsetsCheck(expected_closest, actual_rrsets.begin(),
-                actual_rrsets.end());
-
-    actual_rrsets.clear();
-    if (expected_next.empty()) {
-        EXPECT_FALSE(result.next_proof);
-    } else {
-        ASSERT_TRUE(result.next_proof);
-        actual_rrsets.push_back(result.next_proof);
-        if (expected_sig) {
-            actual_rrsets.push_back(result.next_proof->getRRsig());
-        }
-        rrsetsCheck(expected_next, actual_rrsets.begin(),
-                    actual_rrsets.end());
-    }
-}
-
 TEST_F(InMemoryZoneFinderTest, addNSEC3) {
     // Set up the faked hash calculator.
     setNSEC3HashCreator(&nsec3_hash_creator_);
@@ -2041,71 +1932,7 @@ 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), OutOfZone);
-    EXPECT_THROW(zone_finder_.findNSEC3(Name("org"), true), OutOfZone);
-
-    // Apex name.  It should have a matching NSEC3.
-    {
-        SCOPED_TRACE("apex, non recursive mode");
-        findNSEC3Check(true, origin_.getLabelCount(), apex_nsec3_text, "",
-                       zone_finder_.findNSEC3(origin_, false));
-    }
-
-    // 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));
-    }
-
-    // Non existent name.  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));
-    }
-
-    // Non existent name.  The closest provable encloser is the apex,
-    // and next closer is the query name itself (which NSEC3 for ns1
-    // covers)
-    // H(ns1) = 2T... < H(xxx) = Q0... < H(zzz) = R5...
-    {
-        SCOPED_TRACE("non existent name, recursive mode");
-        findNSEC3Check(true, origin_.getLabelCount(), apex_nsec3_text,
-                       ns1_nsec3_text,
-                       zone_finder_.findNSEC3(Name("xxx.example.org"), true));
-    }
-
-    // Similar to the previous case, but next closer name is different
-    // from the query name.  The closet encloser is w.example.org, and
-    // next closer is y.w.example.org.
-    // H(ns1) = 2T.. < H(y.w) = K8.. < H(zzz) = R5
-    {
-        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));
-    }
-
-    // In the rest of test we check hash comparison for wrap around cases.
-    {
-        SCOPED_TRACE("very small hash");
-        const Name smallest_name("smallest.example.org");
-        findNSEC3Check(false, smallest_name.getLabelCount(),
-                       zzz_nsec3_text, "",
-                       zone_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));
-    }
+    performNSEC3Test(zone_finder_);
 }
 
 TEST_F(InMemoryZoneFinderTest, findNSEC3ForBadZone) {



More information about the bind10-changes mailing list