Browse Source

checkpoint:
- added code for findCoveringNSEC3()


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

Evan Hunt 15 years ago
parent
commit
cc884a66e8

+ 36 - 0
src/lib/auth/data_source.cc

@@ -20,11 +20,14 @@
 
 #include <boost/foreach.hpp>
 
+#include <dns/base32.h>
+#include <dns/buffer.h>
 #include <dns/message.h>
 #include <dns/name.h>
 #include <dns/rdataclass.h>
 #include <dns/rrset.h>
 #include <dns/rrsetlist.h>
+#include <dns/sha1.h>
 
 #include <cc/data.h>
 
@@ -689,5 +692,38 @@ NameMatch::update(const DataSrc& new_source, const Name& container)
     }
 }
 
+Nsec3Param::Nsec3Param(uint8_t a, uint8_t f, uint16_t i,
+                       std::vector<uint8_t>& s) :
+    algorithm(a), flags(f), iterations(i), salt(s)
+{}
+
+string
+Nsec3Param::getHash(const Name& name) const {
+    OutputBuffer buf(0);
+
+    name.toWire(buf);
+    buf.writeData(&salt[0], salt.size());
+    uint8_t* in = (uint8_t*) buf.getData();
+    size_t inlength = buf.getLength();
+    uint8_t digest[SHA1_HASHSIZE];
+    int n = 0;
+
+    SHA1Context sha;
+    do {
+        SHA1Reset(&sha);
+        SHA1Input(&sha, in, inlength);
+        SHA1Result(&sha, digest);
+        in = digest;
+        inlength = SHA1_HASHSIZE;
+    } while (n++ < iterations);
+
+    vector<uint8_t> result;
+    for (int i = 0; i < SHA1_HASHSIZE; ++i) {
+        result.push_back(digest[i]);
+    }
+
+    return (encodeBase32(result));
+}
+
 }
 }

+ 36 - 0
src/lib/auth/data_source.h

@@ -37,6 +37,7 @@ namespace auth {
 
 class NameMatch;
 class Query;
+class Nsec3Param;
 
 class DataSrc;
 typedef boost::shared_ptr<DataSrc> DataSrcPtr;
@@ -141,6 +142,13 @@ public:
                                     isc::dns::Name& target,
                                     const isc::dns::Name* zonename) const = 0;
 
+   // This MUST be implemented by concrete data sources which support
+   // NSEC3, but is optional for others
+   virtual Result findCoveringNSEC3(const Query& q,
+                                    const Nsec3Param& param,
+                                    const isc::dns::Name& qname,
+                                    const isc::dns::Name& zonename,
+                                    isc::dns::RRsetList& target) const = 0;
 };
 
 // Base class for a DNS Data Source
@@ -205,6 +213,13 @@ public:
                                     const isc::dns::Name& qname,
                                     isc::dns::Name& target,
                                     const isc::dns::Name* zonename) const = 0;
+
+   virtual Result findCoveringNSEC3(const Query& q,
+                                    const Nsec3Param& param,
+                                    const isc::dns::Name& qname,
+                                    const isc::dns::Name& zonename,
+                                    isc::dns::RRsetList& target) const = 0;
+
 private:
     isc::dns::RRClass rrclass;
 };
@@ -278,6 +293,15 @@ public:
         return (NOT_IMPLEMENTED);
     }
 
+   virtual Result findCoveringNSEC3(const Query& q,
+                                    const Nsec3Param& param,
+                                    const isc::dns::Name& qname,
+                                    const isc::dns::Name& zonename,
+                                    isc::dns::RRsetList& target) const
+   {
+       return (NOT_IMPLEMENTED);
+   }
+
 private:
     std::vector<ConstDataSrcPtr> data_sources;
 };
@@ -300,6 +324,18 @@ private:
     const isc::dns::Name qname_;
 };
 
+class Nsec3Param {
+public:
+    Nsec3Param(uint8_t a, uint8_t f, uint16_t i, std::vector<uint8_t>& s);
+
+    const uint8_t algorithm;
+    const uint8_t flags;
+    const uint16_t iterations;
+    const std::vector<uint8_t>& salt;
+
+    std::string getHash(const isc::dns::Name& name) const;
+};
+
 }
 }
 

+ 156 - 8
src/lib/auth/data_source_sqlite3.cc

@@ -15,6 +15,7 @@
 // $Id$
 
 #include "data_source_sqlite3.h"
+
 #include <dns/rrttl.h>
 #include <dns/rdata.h>
 #include <dns/rdataclass.h>
@@ -123,21 +124,21 @@ Sqlite3DataSrc::findRecords(const Name& name, const RRType& rdtype,
 
     rc = sqlite3_bind_int(query, 1, zone_id);
     if (rc != SQLITE_OK) {
-        throw("Could not bind 1 (record)");
+        throw("Could not bind 1 (query)");
     }
     rc = sqlite3_bind_text(query, 2, c_name, -1, SQLITE_STATIC);
     if (rc != SQLITE_OK) {
-        throw("Could not bind 2 (record)");
+        throw("Could not bind 2 (query)");
     }
 
     if (query == q_record) {
         rc = sqlite3_bind_text(query, 3, rdtype.toText().c_str(), -1,
                                SQLITE_STATIC);
         if (rc != SQLITE_OK) {
-            throw("Could not bind 3 (record)");
+            throw("Could not bind 3 (query)");
         }
     }
-
+  
     // loop
     int target_ttl = -1;
     int sig_ttl = -1;
@@ -365,6 +366,26 @@ Sqlite3DataSrc::setupPreparedStatements(void) {
         throw(e);
     }
 
+    const char* q_nsec3_str = "SELECT rdtype, ttl, rdata FROM nsec3 "
+                              "WHERE zone_id=?1 AND hash == $2";
+    try {
+        q_nsec3 = prepare(q_nsec3_str);
+    } catch (const char* e) {
+        cout << e << endl << q_nsec3_str << endl;
+        cout << sqlite3_errmsg(db) << endl;
+        throw(e);
+    }
+
+    const char* q_prevnsec3_str = "SELECT rdtype, ttl, rdata FROM nsec3 "
+                                  "WHERE zone_id=?1 AND hash <= $2 "
+                                  "ORDER BY rhash DESC LIMIT 1";
+    try {
+        q_prevnsec3 = prepare(q_prevnsec3_str);
+    } catch (const char* e) {
+        cout << e << endl << q_prevnsec3_str << endl;
+        cout << sqlite3_errmsg(db) << endl;
+        throw(e);
+    }
 }
 
 void
@@ -392,6 +413,7 @@ Sqlite3DataSrc::checkAndSetupSchema(void) {
                           "name STRING NOT NULL, "
                           "rdclass STRING NOT NULL DEFAULT 'IN', "
                           "dnssec BOOLEAN NOT NULL DEFAULT 0)");
+        execSetupQuery("CREATE INDEX zones_byname ON zones (name)");
         execSetupQuery("CREATE TABLE records ("
                           "id INTEGER PRIMARY KEY, "
                           "zone_id INTEGER NOT NULL, "
@@ -403,7 +425,15 @@ Sqlite3DataSrc::checkAndSetupSchema(void) {
                           "rdata STRING NOT NULL)");
         execSetupQuery("CREATE INDEX records_byname ON records (name)");
         execSetupQuery("CREATE INDEX records_byrname ON records (rname)");
-        execSetupQuery("CREATE INDEX zones_byname ON zones (name)");
+        execSetupQuery("CREATE TABLE nsec3 ("
+                          "id INTEGER PRIMARY KEY, "
+                          "zone_id INTEGER NOT NULL, "
+                          "hash STRING NOT NULL, "
+                          "owner STRING NOT NULL, "
+                          "ttl INTEGER NOT NULL, "
+                          "rdtype STRING NOT NULL, "
+                          "rdata STRING NOT NULL)");
+        execSetupQuery("CREATE INDEX nsec3_byhash ON nsec3 (hash)");
 
         setupPreparedStatements();
         cout << "Created new file and schema" << endl;
@@ -420,6 +450,8 @@ Sqlite3DataSrc::Sqlite3DataSrc() {
     q_any = NULL;
     q_count = NULL;
     q_previous = NULL;
+    q_nsec3 = NULL;
+    q_prevnsec3 = NULL;
 }
 
 Sqlite3DataSrc::~Sqlite3DataSrc() {
@@ -469,14 +501,14 @@ Sqlite3DataSrc::findPreviousName(const Query& q,
 
     int rc = sqlite3_bind_int(q_previous, 1, zone_id);
     if (rc != SQLITE_OK) {
-        throw ("Could not bind 1 (record)");
+        throw ("Could not bind 1 (previous)");
     }
     rc = sqlite3_bind_text(q_previous, 2, qname.reverse().toText().c_str(),
                            -1, SQLITE_STATIC);
     if (rc != SQLITE_OK) {
-        throw ("Could not bind 2 (record)");
+        throw ("Could not bind 2 (previous)");
     }
-
+  
     rc = sqlite3_step(q_previous);
     if (rc != SQLITE_ROW) {
         sqlite3_reset(q_previous);
@@ -490,6 +522,112 @@ Sqlite3DataSrc::findPreviousName(const Query& q,
 }
 
 DataSrc::Result
+Sqlite3DataSrc::findCoveringNSEC3(const Query& q,
+                                  const Nsec3Param& nsec3param,
+                                  const Name& qname,
+                                  const Name& zonename,
+                                  RRsetList& target) const
+{
+    int zone_id = findClosest(zonename.toText().c_str(), NULL);
+    if (zone_id < 0) {
+        return (ERROR);
+    }
+
+    string hashstr = nsec3param.getHash(qname);
+
+    sqlite3_reset(q_prevnsec3);
+    sqlite3_clear_bindings(q_prevnsec3);
+
+    int rc = sqlite3_bind_int(q_prevnsec3, 1, zone_id);
+    if (rc != SQLITE_OK) {
+        throw ("Could not bind 1 (previous NSEC3)");
+    }
+
+    rc = sqlite3_bind_text(q_prevnsec3, 2, hashstr.c_str(), -1, SQLITE_STATIC);
+    if (rc != SQLITE_OK) {
+        throw ("Could not bind 2 (previous NSEC3)");
+    }
+
+    rc = sqlite3_step(q_prevnsec3);
+    const char* hash;
+    if (rc == SQLITE_ROW) {
+        hash = (const char*) sqlite3_column_text(q_prevnsec3, 0);
+    } else {
+        // We need to find the final NSEC3 in the chain.
+        // A valid NSEC3 hash is in base32, which contains no
+        // letters higher than V, so a search for the previous 
+        // NSEC3 from "W" will always find it.
+        sqlite3_reset(q_prevnsec3);
+        rc = sqlite3_bind_text(q_prevnsec3, 2, "W", -1, SQLITE_STATIC);
+        if (rc != SQLITE_OK) {
+            throw ("Could not bind 2 (last NSEC3)");
+        }
+
+        rc = sqlite3_step(q_prevnsec3);
+        if (rc != SQLITE_ROW) {
+            return (ERROR);
+        }
+
+        hash = (const char*) sqlite3_column_text(q_prevnsec3, 0);
+    }
+
+    sqlite3_reset(q_nsec3);
+    sqlite3_clear_bindings(q_nsec3);
+
+    rc = sqlite3_bind_int(q_nsec3, 1, zone_id);
+    if (rc != SQLITE_OK) {
+        throw ("Could not bind 1 (NSEC3)");
+    }
+
+    rc = sqlite3_bind_text(q_nsec3, 2, hash, -1, SQLITE_STATIC);
+    if (rc != SQLITE_OK) {
+        throw ("Could not bind 2 (NSEC3)");
+    }
+
+    int target_ttl = -1;
+    int sig_ttl = -1;
+    const Name& name(Name(hash).concatenate(zonename));
+    RRsetPtr rrset(new RRset(name, RRClass::IN(), RRType::NSEC3(), RRTTL(0)));
+    if (!target[RRType::NSEC3()]) {
+        target.addRRset(rrset);
+    }
+
+    rc = sqlite3_step(q_nsec3);
+    while (rc == SQLITE_ROW) {
+        RRType type((const char*)sqlite3_column_text(q_nsec3, 1));
+        int ttl = sqlite3_column_int(q_nsec3, 2);
+        const char* rdata = (const char*)sqlite3_column_text(q_nsec3, 3);
+
+        if (type == RRType::NSEC3()) {
+            rrset->addRdata(createRdata(type, RRClass::IN(), rdata));
+            if (target_ttl == -1 || target_ttl > ttl) {
+                target_ttl = ttl;
+            }
+            rrset->setTTL(RRTTL(target_ttl));
+        } else {
+            RdataPtr rrsig = createRdata(RRType::RRSIG(), RRClass::IN(), rdata);
+            if (rrset->getRRsig()) {
+                rrset->getRRsig()->addRdata(rrsig);
+            } else {
+                RRsetPtr sigs = RRsetPtr(new RRset(name, RRClass::IN(),
+                                                   RRType::RRSIG(), RRTTL(0)));
+                sigs->addRdata(rrsig);
+                rrset->addRRsig(sigs);
+            }
+        }
+
+        if (sig_ttl == -1 || sig_ttl > ttl) {
+            sig_ttl = ttl;
+        }
+        rrset->getRRsig()->setTTL(RRTTL(sig_ttl));
+        rc = sqlite3_step(q_nsec3);
+    }
+
+    sqlite3_reset(q_nsec3);
+    return (SUCCESS);
+}
+
+DataSrc::Result
 Sqlite3DataSrc::findRRset(const Query& q,
                           const Name& qname,
                           const RRClass& qclass,
@@ -608,6 +746,16 @@ Sqlite3DataSrc::close(void) {
         q_previous = NULL;
     }
 
+    if (q_prevnsec3) {
+        release(q_prevnsec3);
+        q_prevnsec3 = NULL;
+    }
+
+    if (q_nsec3) {
+        release(q_nsec3);
+        q_nsec3 = NULL;
+    }
+
     sqlite3_close(db);
 
     db = NULL;

+ 48 - 39
src/lib/auth/data_source_sqlite3.h

@@ -35,6 +35,7 @@ class RRsetList;
 namespace auth {
 
 class Query;
+class Nsec3Param;
 
 class Sqlite3DataSrc : public DataSrc {
     ///
@@ -48,48 +49,54 @@ private:
     Sqlite3DataSrc& operator=(const Sqlite3DataSrc& source);
 public:
     Sqlite3DataSrc();
-    virtual ~Sqlite3DataSrc();
+    ~Sqlite3DataSrc();
     //@}
 
-    virtual void findClosestEnclosure(NameMatch& match) const;
-
-    virtual Result findRRset(const Query& q,
+    void findClosestEnclosure(NameMatch& match) const;
+
+    Result findRRset(const Query& q,
+                     const isc::dns::Name& qname,
+                     const isc::dns::RRClass& qclass,
+                     const isc::dns::RRType& qtype,
+                     isc::dns::RRsetList& target,
+                     uint32_t& flags,
+                     const isc::dns::Name* zonename) const;
+
+    Result findExactRRset(const Query& q,
+                          const isc::dns::Name& qname,
+                          const isc::dns::RRClass& qclass,
+                          const isc::dns::RRType& qtype,
+                          isc::dns::RRsetList& target,
+                          uint32_t& flags,
+                          const isc::dns::Name* zonename) const;
+
+    Result findAddrs(const Query& q,
+                       const isc::dns::Name& qname,
+                       const isc::dns::RRClass& qclass,
+                       isc::dns::RRsetList& target,
+                       uint32_t& flags,
+                       const isc::dns::Name* zonename) const;
+
+    Result findReferral(const Query& q,
+                        const isc::dns::Name& qname,
+                        const isc::dns::RRClass& qclass,
+                        isc::dns::RRsetList& target,
+                        uint32_t& flags,
+                        const isc::dns::Name* zonename) const;
+
+    DataSrc::Result findPreviousName(const Query& q,
+                                     const isc::dns::Name& qname,
+                                     isc::dns::Name& target,
+                                     const isc::dns::Name* zonename) const;
+
+    Result findCoveringNSEC3(const Query& q,
+                             const Nsec3Param& param,
                              const isc::dns::Name& qname,
-                             const isc::dns::RRClass& qclass,
-                             const isc::dns::RRType& qtype,
-                             isc::dns::RRsetList& target,
-                             uint32_t& flags,
-                             const isc::dns::Name* zonename) const;
-
-    virtual Result findExactRRset(const Query& q,
-                                  const isc::dns::Name& qname,
-                                  const isc::dns::RRClass& qclass,
-                                  const isc::dns::RRType& qtype,
-                                  isc::dns::RRsetList& target,
-                                  uint32_t& flags,
-                                  const isc::dns::Name* zonename) const;
-
-    virtual Result findAddrs(const Query& q,
-                               const isc::dns::Name& qname,
-                               const isc::dns::RRClass& qclass,
-                               isc::dns::RRsetList& target,
-                               uint32_t& flags,
-                               const isc::dns::Name* zonename) const;
-
-    virtual Result findReferral(const Query& q,
-                                const isc::dns::Name& qname,
-                                const isc::dns::RRClass& qclass,
-                                isc::dns::RRsetList& target,
-                                uint32_t& flags,
-                                const isc::dns::Name* zonename) const;
-
-    virtual DataSrc::Result findPreviousName(const Query& q,
-                                             const isc::dns::Name& qname,
-                                             isc::dns::Name& target,
-                                             const isc::dns::Name* zonename) const;
-
-    virtual Result init();
-    virtual Result close();
+                             const isc::dns::Name& zonename,
+                             isc::dns::RRsetList& target) const;
+
+    Result init();
+    Result close();
 
 private:
     enum Mode {
@@ -126,6 +133,8 @@ private:
     sqlite3_stmt *q_any;
     sqlite3_stmt *q_count;
     sqlite3_stmt *q_previous;
+    sqlite3_stmt *q_nsec3;
+    sqlite3_stmt *q_prevnsec3;
 };
 
 }

+ 8 - 0
src/lib/auth/data_source_static.cc

@@ -165,6 +165,14 @@ StaticDataSrc::findPreviousName(const Query& q, const Name& qname,
 }
 
 DataSrc::Result
+StaticDataSrc::findCoveringNSEC3(const Query& q, const Nsec3Param& param,
+                                 const Name& qname, const Name& zonename,
+                                 RRsetList& target) const
+{
+   return (NOT_IMPLEMENTED);
+}
+
+DataSrc::Result
 StaticDataSrc::init()
 {
     return (SUCCESS);

+ 6 - 0
src/lib/auth/data_source_static.h

@@ -80,6 +80,12 @@ public:
                             isc::dns::Name& target,
                             const isc::dns::Name* zonename) const;
 
+   Result findCoveringNSEC3(const Query& q,
+                            const Nsec3Param& param,
+                            const isc::dns::Name& qname,
+                            const isc::dns::Name& zonename,
+                            isc::dns::RRsetList& target) const;
+
     Result init();
     Result close();
 };

+ 10 - 0
src/lib/auth/unittest_ds.cc

@@ -765,5 +765,15 @@ TestDataSrc::findPreviousName(const Query& q,
     return (SUCCESS);
 }
 
+DataSrc::Result
+TestDataSrc::findCoveringNSEC3(const Query& q,
+                               const Nsec3Param& param,
+                               const Name& qname,
+                               const Name& zonename,
+                               RRsetList& target) const
+{
+    return (NOT_IMPLEMENTED);
+}
+
 }
 }

+ 6 - 0
src/lib/auth/unittest_ds.h

@@ -85,6 +85,12 @@ public:
                             isc::dns::Name& target,
                             const isc::dns::Name* zonename) const;
 
+    Result findCoveringNSEC3(const Query& q,
+                             const Nsec3Param& param,
+                             const isc::dns::Name& qname,
+                             const isc::dns::Name& zonename,
+                             isc::dns::RRsetList& target) const;
+
     Result init() { return (SUCCESS); }
     Result close() { return (SUCCESS); }