Browse Source

Corrected NSEC3 logic. When returning NXDOMAIN for a node that isn't
directly under the zone apex (i.e., a.b.c.d.e.foo.com), we need to return
the NSEC3 covering the closest enclosing name, not for the zone name
itself. We also need to avoid sending multiple copies of the same NSEC3.


git-svn-id: svn://bind10.isc.org/svn/bind10/trunk@1184 e5f2f494-b856-4b98-b285-d166d9295462

Evan Hunt 15 years ago
parent
commit
7ca848e3c5

+ 0 - 4
src/lib/auth/TODO

@@ -1,6 +1,2 @@
 - change filenames so we don't have everything starting with "data_source_"?
 - change filenames so we don't have everything starting with "data_source_"?
 - store rdata in the database as binary blobs instead of text
 - store rdata in the database as binary blobs instead of text
-- correct NSEC3 logic:
-  - closest encloser proof is incorrect; need to send covering NSEC3
-    for the "next closest" name, not necessarily for the name itself
-  - need to check for duplication in the resulting NSEC3's

+ 48 - 19
src/lib/auth/data_source.cc

@@ -293,18 +293,18 @@ addNSEC(Query& q, const QueryTaskPtr task, const Name& name,
 }
 }
 
 
 static inline DataSrc::Result
 static inline DataSrc::Result
-addNSEC3(const string& hash, Query& q, const DataSrc* ds, const Name& zonename)
+getNsec3(Query& q, const DataSrc* ds, const Name& zonename, string& hash, 
+         RRsetPtr target)
 {
 {
-    RRsetList nsec3;
-    Message& m = q.message();
     DataSrc::Result result;
     DataSrc::Result result;
+    RRsetList rl;
 
 
-    result = ds->findCoveringNSEC3(q, hash, zonename, nsec3);
+    result = ds->findCoveringNSEC3(q, zonename, hash, rl);
     if (result != DataSrc::SUCCESS) {
     if (result != DataSrc::SUCCESS) {
-        return (DataSrc::ERROR);
+        return (result);
     }
     }
 
 
-    m.addRRset(Section::AUTHORITY(), nsec3[RRType::NSEC3()], true);
+    target = rl[RRType::NSEC3()];
     return (DataSrc::SUCCESS);
     return (DataSrc::SUCCESS);
 }
 }
 
 
@@ -344,31 +344,60 @@ getNsec3Param(Query& q, const DataSrc* ds, const Name& zonename) {
 static inline DataSrc::Result
 static inline DataSrc::Result
 proveNX(Query& q, QueryTaskPtr task, const DataSrc* ds, const Name& zonename)
 proveNX(Query& q, QueryTaskPtr task, const DataSrc* ds, const Name& zonename)
 {
 {
+    Message& m = q.message();
     DataSrc::Result result;
     DataSrc::Result result;
+
     ConstNsec3ParamPtr nsec3 = getNsec3Param(q, ds, zonename);
     ConstNsec3ParamPtr nsec3 = getNsec3Param(q, ds, zonename);
     if (nsec3 != NULL) {
     if (nsec3 != NULL) {
-        string node(nsec3->getHash(task->qname));
-        result = addNSEC3(node, q, ds, zonename);
+        // Attach the NSEC3 record covering the QNAME
+        RRsetPtr rrset;
+        string hash1(nsec3->getHash(task->qname));
+        result = getNsec3(q, ds, zonename, hash1, rrset);
         if (result != DataSrc::SUCCESS) {
         if (result != DataSrc::SUCCESS) {
             return (result);
             return (result);
         }
         }
+        m.addRRset(Section::AUTHORITY(), rrset, true);
+
+        // If this is an NXRRSET or NOERROR/NODATA, we're done
+        if ((task->flags & DataSrc::TYPE_NOT_FOUND) != 0) {
+            return (DataSrc::SUCCESS);
+        }
+
+        // Find the closest provable enclosing name for QNAME
+        Name enclosure(zonename);
+        int nlen = task->qname.getLabelCount();
+        int diff = nlen - enclosure.getLabelCount();
+        for (int i = 1; i <= diff; ++i) {
+            enclosure = task->qname.split(i, nlen - i);
+            string nodehash(nsec3->getHash(enclosure));
+            if (nodehash == hash1) {
+                break;
+            }
+            hash2 = nodehash;
+            RRsetList rl;
 
 
-        string apex(nsec3->getHash(zonename));
-        if (node != apex) {
-            result = addNSEC3(apex, q, ds, zonename);
+            // hash2 will be overwritten with the actual hash found;
+            // we don't want to use one until we find an exact match
+            result = getNsec3(q, ds, zonename, hash2, rrset);
             if (result != DataSrc::SUCCESS) {
             if (result != DataSrc::SUCCESS) {
-                return (result);
+                return (DataSrc::ERROR);
+            }
+
+            if (hash2 == nodehash) {
+                m.addRRset(Section::AUTHORITY(), rrset, true);
+                break;
             }
             }
         }
         }
 
 
-        if ((task->flags & DataSrc::NAME_NOT_FOUND) != 0) {
-            string wild(nsec3->getHash(Name("*").concatenate(zonename)));
-            if (node != wild) {
-                result = addNSEC3(wild, q, ds, zonename);
-                if (result != DataSrc::SUCCESS) {
-                    return (result);
-                }
+        // Now add a covering NSEC3 for a wildcard under the
+        // closest provable enclosing name
+        string hash3(nsec3->getHash(Name("*").concatenate(enclosure)));
+        if (wild != hash1 && wild != hash2) {
+            result = getNsec3(q, ds, zonename, wild, rrset);
+            if (result != DataSrc::SUCCESS) {
+                return (result);
             }
             }
+            m.addRRset(Section::AUTHORITY(), rrset, true);
         }
         }
     } else {
     } else {
         Name nsecname(task->qname);
         Name nsecname(task->qname);

+ 3 - 3
src/lib/auth/data_source.h

@@ -146,8 +146,8 @@ public:
    // This MUST be implemented by concrete data sources which support
    // This MUST be implemented by concrete data sources which support
    // NSEC3, but is optional for others
    // NSEC3, but is optional for others
    virtual Result findCoveringNSEC3(const Query& q,
    virtual Result findCoveringNSEC3(const Query& q,
-                                    const std::string& hash,
                                     const isc::dns::Name& zonename,
                                     const isc::dns::Name& zonename,
+                                    std::string& hash,
                                     isc::dns::RRsetList& target) const = 0;
                                     isc::dns::RRsetList& target) const = 0;
 };
 };
 
 
@@ -215,8 +215,8 @@ public:
                                     const isc::dns::Name* zonename) const = 0;
                                     const isc::dns::Name* zonename) const = 0;
 
 
    virtual Result findCoveringNSEC3(const Query& q,
    virtual Result findCoveringNSEC3(const Query& q,
-                                    const std::string& hash,
                                     const isc::dns::Name& zonename,
                                     const isc::dns::Name& zonename,
+                                    std::string& hash,
                                     isc::dns::RRsetList& target) const = 0;
                                     isc::dns::RRsetList& target) const = 0;
 
 
 private:
 private:
@@ -293,8 +293,8 @@ public:
     }
     }
 
 
    virtual Result findCoveringNSEC3(const Query& q,
    virtual Result findCoveringNSEC3(const Query& q,
-                                    const std::string& qname,
                                     const isc::dns::Name& zonename,
                                     const isc::dns::Name& zonename,
+                                    std::string& hash,
                                     isc::dns::RRsetList& target) const
                                     isc::dns::RRsetList& target) const
    {
    {
        return (NOT_IMPLEMENTED);
        return (NOT_IMPLEMENTED);

+ 2 - 2
src/lib/auth/data_source_sqlite3.cc

@@ -549,8 +549,8 @@ Sqlite3DataSrc::findPreviousName(const Query& q,
 
 
 DataSrc::Result
 DataSrc::Result
 Sqlite3DataSrc::findCoveringNSEC3(const Query& q,
 Sqlite3DataSrc::findCoveringNSEC3(const Query& q,
-                                  const string& hashstr,
                                   const Name& zonename,
                                   const Name& zonename,
+                                  string& hashstr,
                                   RRsetList& target) const
                                   RRsetList& target) const
 {
 {
     int zone_id = findClosest(zonename.toText().c_str(), NULL);
     int zone_id = findClosest(zonename.toText().c_str(), NULL);
@@ -614,7 +614,7 @@ Sqlite3DataSrc::findCoveringNSEC3(const Query& q,
                           flags) == 0 || flags != 0) {
                           flags) == 0 || flags != 0) {
         result = ERROR;
         result = ERROR;
     }
     }
-
+    hashstr = string(hash);
     sqlite3_reset(q_nsec3);
     sqlite3_reset(q_nsec3);
     return (result);
     return (result);
 }
 }

+ 1 - 1
src/lib/auth/data_source_sqlite3.h

@@ -89,8 +89,8 @@ public:
                                      const isc::dns::Name* zonename) const;
                                      const isc::dns::Name* zonename) const;
 
 
     Result findCoveringNSEC3(const Query& q,
     Result findCoveringNSEC3(const Query& q,
-                             const std::string& hash,
                              const isc::dns::Name& zonename,
                              const isc::dns::Name& zonename,
+                             std::string& hash,
                              isc::dns::RRsetList& target) const;
                              isc::dns::RRsetList& target) const;
 
 
     Result init();
     Result init();

+ 2 - 2
src/lib/auth/data_source_sqlite3_unittest.cc

@@ -677,8 +677,8 @@ TEST_F(Sqlite3DataSourceTest, findRRsetNSEC3) {
 
 
     const Name nsec3_zonename("sql2.example.com");
     const Name nsec3_zonename("sql2.example.com");
     EXPECT_EQ(DataSrc::SUCCESS,
     EXPECT_EQ(DataSrc::SUCCESS,
-              data_source.findCoveringNSEC3(*query, hashstr, nsec3_zonename,
-                                            result_sets));
+              data_source.findCoveringNSEC3(*query, nsec3_zonename,
+                                            hashstr, result_sets));
     RRsetList::iterator it = result_sets.begin();
     RRsetList::iterator it = result_sets.begin();
     checkRRset(*it, Name(hashstr).concatenate(nsec3_zonename), RRClass::IN(),
     checkRRset(*it, Name(hashstr).concatenate(nsec3_zonename), RRClass::IN(),
                RRType::NSEC3(), RRTTL(7200), nsec3_data, &nsec3_sig_data);
                RRType::NSEC3(), RRTTL(7200), nsec3_data, &nsec3_sig_data);

+ 2 - 2
src/lib/auth/data_source_static.cc

@@ -175,8 +175,8 @@ StaticDataSrc::findPreviousName(const Query& q, const Name& qname,
 }
 }
 
 
 DataSrc::Result
 DataSrc::Result
-StaticDataSrc::findCoveringNSEC3(const Query& q, const string& hash,
-                                 const Name& zonename, RRsetList& target) const
+StaticDataSrc::findCoveringNSEC3(const Query& q, const Name& zonename,
+                                 string& hash, RRsetList& target) const
 {
 {
    return (NOT_IMPLEMENTED);
    return (NOT_IMPLEMENTED);
 }
 }

+ 1 - 1
src/lib/auth/data_source_static.h

@@ -82,8 +82,8 @@ public:
                             const isc::dns::Name* zonename) const;
                             const isc::dns::Name* zonename) const;
 
 
    Result findCoveringNSEC3(const Query& q,
    Result findCoveringNSEC3(const Query& q,
-                            const std::string& hash,
                             const isc::dns::Name& zonename,
                             const isc::dns::Name& zonename,
+                            std::string& hash,
                             isc::dns::RRsetList& target) const;
                             isc::dns::RRsetList& target) const;
 
 
     Result init();
     Result init();

+ 1 - 1
src/lib/auth/unittest_ds.cc

@@ -775,8 +775,8 @@ TestDataSrc::findPreviousName(const Query& q,
 
 
 DataSrc::Result
 DataSrc::Result
 TestDataSrc::findCoveringNSEC3(const Query& q,
 TestDataSrc::findCoveringNSEC3(const Query& q,
-                               const string& hash,
                                const Name& zonename,
                                const Name& zonename,
+                               string& hash,
                                RRsetList& target) const
                                RRsetList& target) const
 {
 {
     return (NOT_IMPLEMENTED);
     return (NOT_IMPLEMENTED);

+ 1 - 1
src/lib/auth/unittest_ds.h

@@ -86,8 +86,8 @@ public:
                             const isc::dns::Name* zonename) const;
                             const isc::dns::Name* zonename) const;
 
 
     Result findCoveringNSEC3(const Query& q,
     Result findCoveringNSEC3(const Query& q,
-                             const std::string& hash,
                              const isc::dns::Name& zonename,
                              const isc::dns::Name& zonename,
+                             std::string& hash,
                              isc::dns::RRsetList& target) const;
                              isc::dns::RRsetList& target) const;
 
 
     Result init();
     Result init();