Browse Source

[2310] update ZoneData so it can store/return the "minimum" TTL.

JINMEI Tatuya 12 years ago
parent
commit
6ff25a392e

+ 27 - 0
src/lib/datasrc/memory/zone_data.cc

@@ -134,6 +134,28 @@ NSEC3Data::insertName(util::MemorySegment& mem_sgmt, const Name& name,
             result == ZoneTree::ALREADYEXISTS) && node != NULL);
 }
 
+namespace {
+// A helper to convert a TTL value in network byte order and set it in
+// ZoneData::min_ttl_.  We can use util::OutputBuffer, but copy the logic
+// here to guarantee it is exception free.
+void
+setTTLInNetOrder(uint32_t val, uint32_t* result) {
+    uint8_t buf[4];
+    buf[0] = static_cast<uint8_t>((val & 0xff000000) >> 24);
+    buf[1] = static_cast<uint8_t>((val & 0x00ff0000) >> 16);
+    buf[2] = static_cast<uint8_t>((val & 0x0000ff00) >> 8);
+    buf[3] = static_cast<uint8_t>(val & 0x000000ff);
+    std::memcpy(result, buf, sizeof(*result));
+}
+}
+
+ZoneData::ZoneData(ZoneTree* zone_tree, ZoneNode* origin_node) :
+    zone_tree_(zone_tree), origin_node_(origin_node),
+    min_ttl_(0)          // tentatively set to silence static checkers
+{
+    setTTLInNetOrder(RRTTL::MAX_TTL().getValue(), &min_ttl_);
+}
+
 ZoneData*
 ZoneData::create(util::MemorySegment& mem_sgmt, const Name& zone_origin) {
     // ZoneTree::insert() and ZoneData allocation can throw.  See also
@@ -178,6 +200,11 @@ ZoneData::insertName(util::MemorySegment& mem_sgmt, const Name& name,
             result == ZoneTree::ALREADYEXISTS) && node != NULL);
 }
 
+void
+ZoneData::setMinTTL(uint32_t min_ttl_val) {
+    setTTLInNetOrder(min_ttl_val, &min_ttl_);
+}
+
 } // namespace memory
 } // namespace datasrc
 } // datasrc isc

+ 51 - 4
src/lib/datasrc/memory/zone_data.h

@@ -287,7 +287,7 @@ private:
 /// from NSEC to NSEC3 or vice versa, support incremental signing, or support
 /// multiple sets of NSEC3 parameters.
 ///
-/// One last type of meta data is the status of the zone in terms of DNSSEC
+/// One other type of meta data is the status of the zone in terms of DNSSEC
 /// signing.  This class supports the following concepts:
 /// - Whether the zone is signed or not, either with NSEC records or NSEC3
 ///   records.
@@ -315,6 +315,15 @@ private:
 /// because we won't have to change the application code when we implement
 /// the future separation.
 ///
+/// One last type of meta data is the zone's "minimum" TTL.  It's expected
+/// to be a shortcut copy of the minimum field of the zone's SOA RDATA,
+/// and is expected to be used to create an SOA RR for a negative response,
+/// whose RR TTL may have to be set to this value according to RFC2308.
+/// This class is not aware of such usage, however, and only provides a
+/// simple getter and setter method for this value: \c getMinTTLData() and
+/// \c setMinTTL().  The user of this class is responsible for setting the
+/// value with \c setMinTTL() when it loads or updates the SOA RR.
+///
 /// The intended usage of these two status concepts is to implement the
 /// \c ZoneFinder::Context::isNSECSigned() and
 /// \c ZoneFinder::Context::isNSEC3Signed() methods.  A possible implementation
@@ -349,9 +358,7 @@ private:
     /// allocator (\c create()), so the constructor is hidden as private.
     ///
     /// It never throws an exception.
-    ZoneData(ZoneTree* zone_tree, ZoneNode* origin_node) :
-        zone_tree_(zone_tree), origin_node_(origin_node)
-    {}
+    ZoneData(ZoneTree* zone_tree, ZoneNode* origin_node);
 
     // Zone node flags.
 private:
@@ -456,6 +463,26 @@ public:
     ///
     /// \throw none
     const NSEC3Data* getNSEC3Data() const { return (nsec3_data_.get()); }
+
+    /// \brief Return a pointer to the zone's minimum TTL data.
+    ///
+    /// The returned pointer points to a memory region that is valid at least
+    /// for 32 bits, storing the zone's minimum TTL in the network byte
+    /// order.  The corresponding 32-bit value as an integer is initially
+    /// set to the value of \c dns::RRTTL::MAX_TTL(), and, once
+    /// \c setMinTTL() is called, set to the value specified at the latest
+    /// call to \c setMinTTL().
+    ///
+    /// It returns opaque data to make it clear that unless the wire
+    /// format data is necessary (e.g., when rendering it in a DNS message),
+    /// it should be converted to, e.g., an \c RRTTL object explicitly.
+    ///
+    /// The returned pointer is valid as long as the \c ZoneData is valid,
+    /// and the corresponding 32-bit data are the same until \c setMinTTL()
+    /// is called.
+    ///
+    /// \throw none
+    const void* getMinTTLData() const { return (&min_ttl_); }
     //@}
 
     ///
@@ -552,12 +579,32 @@ public:
         nsec3_data_ = nsec3_data;
         return (old);
     }
+
+    /// \brief Set the zone's "minimum" TTL.
+    ///
+    /// This method updates the recorded minimum TTL of the zone data.
+    /// It's expected to be identical to the value of the Minimum field
+    /// of the SOA RR at the zone apex, but this method does not check the
+    /// consistency; it's the caller's responsibility.
+    ///
+    /// While RFC2181 specifies the max TTL value to be 2^31-1, this method
+    /// does not check the range; it accepts any unsigned 32-bit integer
+    /// value.  In practice, this shouldn't cause a problem, however, because
+    /// the only expected usage of this value is to use the minimum of this
+    /// value and SOA RR's TTL, and the latter is expected to be in the
+    /// valid range.
+    ///
+    /// \throw None
+    /// \param min_ttl_val The minimum TTL value as unsigned 32-bit integer
+    /// in the host byte order.
+    void setMinTTL(uint32_t min_ttl_val);
     //@}
 
 private:
     const boost::interprocess::offset_ptr<ZoneTree> zone_tree_;
     const boost::interprocess::offset_ptr<ZoneNode> origin_node_;
     boost::interprocess::offset_ptr<NSEC3Data> nsec3_data_;
+    uint32_t min_ttl_;
 };
 
 } // namespace memory

+ 24 - 4
src/lib/datasrc/tests/memory/zone_data_unittest.cc

@@ -12,19 +12,22 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
+#include <datasrc/memory/zone_data.h>
+#include <datasrc/memory/rdata_serialization.h>
+#include <datasrc/memory/rdataset.h>
+
 #include "memory_segment_test.h"
 
 #include <dns/rdataclass.h>
 
 #include <exceptions/exceptions.h>
 
+#include <util/buffer.h>
+
 #include <dns/name.h>
 #include <dns/labelsequence.h>
 #include <dns/rrclass.h>
-
-#include <datasrc/memory/rdata_serialization.h>
-#include <datasrc/memory/rdataset.h>
-#include <datasrc/memory/zone_data.h>
+#include <dns/rrttl.h>
 
 #include <testutils/dnsmessage_test.h>
 
@@ -258,4 +261,21 @@ TEST_F(ZoneDataTest, isSigned) {
     zone_data_->setSigned(false);
     EXPECT_FALSE(zone_data_->isSigned());
 }
+
+// A simple wrapper to reconstruct an RRTTL object from wire-format TTL
+// data (32 bits)
+RRTTL
+createRRTTL(const void* ttl_data) {
+    isc::util::InputBuffer b(ttl_data, sizeof(uint32_t));
+    return (RRTTL(b));
+}
+
+TEST_F(ZoneDataTest, minTTL) {
+    // By default it's tentatively set to "max TTL"
+    EXPECT_EQ(RRTTL::MAX_TTL(), createRRTTL(zone_data_->getMinTTLData()));
+
+    // Explicitly set, then retrieve it.
+    zone_data_->setMinTTL(1200);
+    EXPECT_EQ(RRTTL(1200), createRRTTL(zone_data_->getMinTTLData()));
+}
 }