Browse Source

[2420] handle RRSIG-for-NSEC3 only cases.

JINMEI Tatuya 12 years ago
parent
commit
bedd068396

+ 18 - 4
src/lib/datasrc/memory/zone_data_updater.cc

@@ -243,14 +243,28 @@ ZoneDataUpdater::setupNSEC3(const ConstRRsetPtr rrset) {
 }
 
 void
-ZoneDataUpdater::addNSEC3(const ConstRRsetPtr rrset, const ConstRRsetPtr rrsig)
+ZoneDataUpdater::addNSEC3(const Name& name, const ConstRRsetPtr rrset,
+                          const ConstRRsetPtr rrsig)
 {
-    setupNSEC3<generic::NSEC3>(rrset);
+    if (rrset) {
+        setupNSEC3<generic::NSEC3>(rrset);
+    }
 
     NSEC3Data* nsec3_data = zone_data_.getNSEC3Data();
+    if (nsec3_data == NULL) {
+        // This is some tricky case: an RRSIG for NSEC3 is given without the
+        // covered NSEC3, and we don't even know any NSEC3 related data.
+        // This situation is not necessarily broken, but in our current
+        // implementation it's very difficult to deal with.  So we reject it;
+        // hopefully this case shouldn't happen in practice, at least unless
+        // zone is really broken.
+        assert(!rrset);
+        isc_throw(NotImplemented,
+                  "RRSIG for NSEC3 cannot be added - no known NSEC3 data");
+    }
 
     ZoneNode* node;
-    nsec3_data->insertName(mem_sgmt_, rrset->getName(), &node);
+    nsec3_data->insertName(mem_sgmt_, name, &node);
 
     RdataSet* rdataset = RdataSet::create(mem_sgmt_, encoder_, rrset, rrsig);
     RdataSet* old_rdataset = node->setData(rdataset);
@@ -265,7 +279,7 @@ ZoneDataUpdater::addRdataSet(const Name& name, const RRType& rrtype,
                              const ConstRRsetPtr rrsig)
 {
     if (rrtype == RRType::NSEC3()) {
-        addNSEC3(rrset, rrsig); // TBD: check RRSIG only case
+        addNSEC3(name, rrset, rrsig);
     } else {
         ZoneNode* node;
         zone_data_.insertName(mem_sgmt_, name, &node);

+ 11 - 1
src/lib/datasrc/memory/zone_data_updater.h

@@ -121,9 +121,18 @@ public:
     /// zone is half broken and really contains an RRSIG that doesn't have
     /// any covered RRset.  This implementation supports these cases.
     ///
+    /// There is one tricky case: Due to a limitation of the current
+    /// implementation, it cannot accept an RRSIG for NSEC3 without the covered
+    /// NSEC3, unless at least one NSEC3 or NSEC3PARAM has been added.
+    /// In this case an isc::NotImplemented exception will be thrown.  It
+    /// should be very rare in practice, and hopefully wouldn't be a real
+    /// issue.
+    ///
     /// \throw NullRRset Both \c rrset and sig_rrset is NULL
     /// \throw AddError any of a variety of validation checks fail for the
     /// \c rrset and its associated \c sig_rrset.
+    /// \throw NotImplemented RRSIG for NSEC3 cannot be added due to internal
+    /// restriction.
     ///
     /// \param rrset The RRset to be added.
     /// \param sig_rrset An associated RRSIG RRset for the \c rrset. It
@@ -162,7 +171,8 @@ private:
     const isc::dns::NSEC3Hash* getNSEC3Hash();
     template <typename T>
     void setupNSEC3(const isc::dns::ConstRRsetPtr rrset);
-    void addNSEC3(const isc::dns::ConstRRsetPtr rrset,
+    void addNSEC3(const isc::dns::Name& name,
+                  const isc::dns::ConstRRsetPtr rrset,
                   const isc::dns::ConstRRsetPtr rrsig);
     void addRdataSet(const isc::dns::Name& name,
                      const isc::dns::RRType& rrtype,

+ 68 - 0
src/lib/datasrc/tests/memory/zone_data_updater_unittest.cc

@@ -28,6 +28,8 @@
 
 #include <gtest/gtest.h>
 
+#include <cassert>
+
 using isc::testutils::textToRRset;
 using namespace isc::dns;
 using namespace isc::datasrc::memory;
@@ -47,6 +49,11 @@ protected:
             ZoneData::destroy(mem_sgmt_, zone_data_, zclass_);
         }
     }
+    void clearZoneData() {
+        assert(zone_data_ != NULL);
+        ZoneData::destroy(mem_sgmt_, zone_data_, zclass_);
+        zone_data_ = ZoneData::create(mem_sgmt_, zname_);
+    }
 
     void TearDown() {
         if (zone_data_ != NULL) {
@@ -136,4 +143,65 @@ TEST_F(ZoneDataUpdaterTest, rrisgOnly) {
     EXPECT_FALSE(zone_data_->isSigned());
 }
 
+// Commonly used checks for rrisgForNSEC3Only
+void
+checkNSEC3Rdata(isc::util::MemorySegment& mem_sgmt, const Name& name,
+                ZoneData* zone_data)
+{
+    ZoneNode* node = NULL;
+    zone_data->getNSEC3Data()->insertName(mem_sgmt, name, &node);
+    ASSERT_NE(static_cast<ZoneNode*>(NULL), node);
+    const RdataSet* rdset = node->getData();
+    ASSERT_NE(static_cast<RdataSet*>(NULL), rdset);
+    ASSERT_EQ(RRType::NSEC3(), rdset->type);
+    EXPECT_EQ(0, rdset->getRdataCount());
+    EXPECT_EQ(1, rdset->getSigRdataCount());
+}
+
+TEST_F(ZoneDataUpdaterTest, rrisgForNSEC3Only) {
+    // Adding only RRSIG covering NSEC3 is tricky.  It should go to the
+    // separate NSEC3 tree, but the separate space is only created when
+    // NSEC3 or NSEC3PARAM is added.  So, in many cases RRSIG-only is allowed,
+    // but if no NSEC3 or NSEC3PARAM has been added it will be rejected.
+
+    // Below we use abnormal owner names and RDATA for NSEC3s for brevity,
+    // but that doesn't matter for this test.
+
+    // Add NSEC3PARAM, then RRSIG-only, which is okay.
+    updater_.add(textToRRset(
+                     "example.org. 3600 IN NSEC3PARAM 1 0 12 AABBCCDD"),
+                 textToRRset(
+                     "example.org. 3600 IN RRSIG NSEC3PARAM 5 3 3600 "
+                     "20150420235959 20051021000000 1 example.org. FAKE"));
+    EXPECT_TRUE(zone_data_->isNSEC3Signed());
+    updater_.add(ConstRRsetPtr(),
+                 textToRRset(
+                     "09GM.example.org. 3600 IN RRSIG NSEC3 5 3 3600 "
+                     "20150420235959 20051021000000 1 example.org. FAKE"));
+    checkNSEC3Rdata(mem_sgmt_, Name("09GM.example.org"), zone_data_);
+
+    // Clear the current content of zone, then add NSEC3
+    clearZoneData();
+    updater_.add(textToRRset(
+                     "AABB.example.org. 3600 IN NSEC3 1 0 10 AA 00000000 A"),
+                 textToRRset(
+                     "AABB.example.org. 3600 IN RRSIG NSEC3 5 3 3600 "
+                     "20150420235959 20051021000000 1 example.org. FAKE"));
+    updater_.add(ConstRRsetPtr(),
+                 textToRRset(
+                     "09GM.example.org. 3600 IN RRSIG NSEC3 5 3 3600 "
+                     "20150420235959 20051021000000 1 example.org. FAKE"));
+    checkNSEC3Rdata(mem_sgmt_, Name("09GM.example.org"), zone_data_);
+
+    // If we add only RRSIG without any NSEC3 related data beforehand,
+    // it will be rejected; it's a limitation of the current implementation.
+    clearZoneData();
+    EXPECT_THROW(updater_.add(
+                     ConstRRsetPtr(),
+                     textToRRset(
+                         "09GM.example.org. 3600 IN RRSIG NSEC3 5 3 3600 "
+                         "20150420235959 20051021000000 1 example.org. FAKE")),
+                 isc::NotImplemented);
+}
+
 }