BIND 10 master, updated. 2002e7a128f2b4d84d0f67a45e8e0fec2bf541c3 Merge branch 'trac1396'

BIND 10 source code commits bind10-changes at lists.isc.org
Wed Jan 29 10:58:06 UTC 2014


The branch, master has been updated
       via  2002e7a128f2b4d84d0f67a45e8e0fec2bf541c3 (commit)
       via  1e762fa3653c39e649f1b8cf66f17c0bdd8bdfa7 (commit)
       via  63eca991aef43dac723b6aec44345c7747b5939a (commit)
       via  6f177a3d2719a0b08501d22cdd725ff5824bb688 (commit)
       via  5410f9ce9d90585e00828253cedce1e024ad4524 (commit)
       via  000f7efd1c2d316c3ee02902713cedc355efefba (commit)
       via  7f9bc84501ca5a850e4975db715eae07234e7c25 (commit)
       via  4b77db4d8be806ebfb82ef5403fae266c56b1c89 (commit)
      from  f0a7b4ecbb0e6360ec2686bb08c3bb92682bc8c3 (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 2002e7a128f2b4d84d0f67a45e8e0fec2bf541c3
Merge: f0a7b4e 1e762fa
Author: Mukund Sivaraman <muks at isc.org>
Date:   Wed Jan 29 16:18:29 2014 +0530

    Merge branch 'trac1396'

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

Summary of changes:
 src/bin/xfrout/xfrout.py.in                        |    6 +-
 src/lib/datasrc/memory/treenode_rrset.cc           |   75 ++++++++++++++++++++
 src/lib/datasrc/memory/treenode_rrset.h            |    4 +-
 .../tests/memory/treenode_rrset_unittest.cc        |   31 ++++++++
 src/lib/dns/python/rrset_python.cc                 |   15 ++++
 src/lib/dns/python/tests/rrset_python_test.py      |   18 +++++
 src/lib/dns/rdata.cc                               |    9 +++
 src/lib/dns/rdata.h                                |   15 ++++
 src/lib/dns/rrset.cc                               |   59 +++++++++++++++
 src/lib/dns/rrset.h                                |   28 ++++++++
 src/lib/dns/tests/rdata_unittest.cc                |    8 +++
 src/lib/dns/tests/rrset_unittest.cc                |   58 +++++++++++++++
 12 files changed, 322 insertions(+), 4 deletions(-)

-----------------------------------------------------------------------
diff --git a/src/bin/xfrout/xfrout.py.in b/src/bin/xfrout/xfrout.py.in
index aa84587..a776690 100755
--- a/src/bin/xfrout/xfrout.py.in
+++ b/src/bin/xfrout/xfrout.py.in
@@ -143,11 +143,11 @@ def format_addrinfo(addrinfo):
         raise TypeError("addrinfo argument to format_addrinfo() does not "
                         "appear to be consisting of (family, socktype, (addr, port))")
 
+# This function is not inlined as it is replaced with a mock function
+# during testing.
 def get_rrset_len(rrset):
     """Returns the wire length of the given RRset"""
-    bytes = bytearray()
-    rrset.to_wire(bytes)
-    return len(bytes)
+    return rrset.get_length()
 
 def get_soa_serial(soa_rdata):
     '''Extract the serial field of an SOA RDATA and returns it as an Serial object.
diff --git a/src/lib/datasrc/memory/treenode_rrset.cc b/src/lib/datasrc/memory/treenode_rrset.cc
index 4734e04..1d468ef 100644
--- a/src/lib/datasrc/memory/treenode_rrset.cc
+++ b/src/lib/datasrc/memory/treenode_rrset.cc
@@ -101,6 +101,19 @@ TreeNodeRRset::toText() const {
 
 namespace {
 void
+sizeupName(const LabelSequence& name_labels, RdataNameAttributes,
+           size_t* length)
+{
+    *length += name_labels.getDataLength();
+}
+
+void
+sizeupData(const void*, size_t data_len, size_t* length)
+{
+    *length += data_len;
+}
+
+void
 renderName(const LabelSequence& name_labels, RdataNameAttributes attr,
            AbstractMessageRenderer* renderer)
 {
@@ -114,6 +127,35 @@ renderData(const void* data, size_t data_len,
     renderer->writeData(data, data_len);
 }
 
+// Helper for calculating wire data length of a single (etiher main or
+// RRSIG) RRset.
+uint16_t
+getLengthHelper(size_t* rlength, size_t rr_count, uint16_t name_labels_size,
+                RdataReader& reader, bool (RdataReader::* rdata_iterate_fn)())
+{
+    uint16_t length = 0;
+
+    for (size_t i = 0; i < rr_count; ++i) {
+        size_t rrlen = 0;
+
+        rrlen += name_labels_size;
+        rrlen += 2; // TYPE field
+        rrlen += 2; // CLASS field
+        rrlen += 4; // TTL field
+        rrlen += 2; // RDLENGTH field
+
+        *rlength = 0;
+        const bool rendered = (reader.*rdata_iterate_fn)();
+        assert(rendered == true);
+
+        rrlen += *rlength;
+        assert(length + rrlen < 65536);
+        length += rrlen;
+    }
+
+    return (length);
+}
+
 // Common code logic for rendering a single (either main or RRSIG) RRset.
 size_t
 writeRRs(AbstractMessageRenderer& renderer, size_t rr_count,
@@ -149,6 +191,39 @@ writeRRs(AbstractMessageRenderer& renderer, size_t rr_count,
 }
 }
 
+uint16_t
+TreeNodeRRset::getLength() const {
+    size_t rlength = 0;
+    RdataReader reader(rrclass_, rdataset_->type, rdataset_->getDataBuf(),
+                       rdataset_->getRdataCount(), rrsig_count_,
+                       boost::bind(sizeupName, _1, _2, &rlength),
+                       boost::bind(sizeupData, _1, _2, &rlength));
+
+    // Get the owner name of the RRset in the form of LabelSequence.
+    uint8_t labels_buf[LabelSequence::MAX_SERIALIZED_LENGTH];
+    const LabelSequence name_labels = getOwnerLabels(labels_buf);
+    const uint16_t name_labels_size = name_labels.getDataLength();
+
+    // Find the length of the main (non RRSIG) RRs
+    const uint16_t rrset_length =
+        getLengthHelper(&rlength, rdataset_->getRdataCount(), name_labels_size,
+                        reader, &RdataReader::iterateRdata);
+
+    rlength = 0;
+    const bool rendered = reader.iterateRdata();
+    assert(rendered == false); // we should've reached the end
+
+    // Find the length of any RRSIGs, if we supposed to do so
+    const uint16_t rrsig_length = dnssec_ok_ ?
+        getLengthHelper(&rlength, rrsig_count_, name_labels_size,
+                        reader, &RdataReader::iterateSingleSig) : 0;
+
+    // the uint16_ts are promoted to ints during addition below, so it
+    // won't overflow a 16-bit register.
+    assert(rrset_length + rrsig_length < 65536);
+    return (rrset_length + rrsig_length);
+}
+
 unsigned int
 TreeNodeRRset::toWire(AbstractMessageRenderer& renderer) const {
     RdataReader reader(rrclass_, rdataset_->type, rdataset_->getDataBuf(),
diff --git a/src/lib/datasrc/memory/treenode_rrset.h b/src/lib/datasrc/memory/treenode_rrset.h
index 640c972..51e1eed 100644
--- a/src/lib/datasrc/memory/treenode_rrset.h
+++ b/src/lib/datasrc/memory/treenode_rrset.h
@@ -155,7 +155,7 @@ public:
         node_(node), rdataset_(rdataset),
         rrsig_count_(rdataset_->getSigRdataCount()), rrclass_(rrclass),
         dnssec_ok_(dnssec_ok), name_(NULL), realname_(new dns::Name(realname)),
-	ttl_data_(rdataset->getTTLData()), ttl_(NULL)
+        ttl_data_(rdataset->getTTLData()), ttl_(NULL)
     {}
 
     virtual ~TreeNodeRRset() {
@@ -168,6 +168,8 @@ public:
         return (rdataset_->getRdataCount());
     }
 
+    virtual uint16_t getLength() const;
+
     virtual const dns::Name& getName() const;
     virtual const dns::RRClass& getClass() const {
         return (rrclass_);
diff --git a/src/lib/datasrc/tests/memory/treenode_rrset_unittest.cc b/src/lib/datasrc/tests/memory/treenode_rrset_unittest.cc
index 4d1f6e1..451a91a 100644
--- a/src/lib/datasrc/tests/memory/treenode_rrset_unittest.cc
+++ b/src/lib/datasrc/tests/memory/treenode_rrset_unittest.cc
@@ -333,6 +333,37 @@ checkToWireResult(OutputType& expected_output, OutputType& actual_output,
                   actual_output.getData(), actual_output.getLength());
 }
 
+TEST_F(TreeNodeRRsetTest, getLength) {
+    // A RR
+    // www.example.com = 1 + 3 + 1 + 7 + 1 + 3 + 1 = 17 octets
+    // TYPE field = 2 octets
+    // CLASS field = 2 octets
+    // TTL field = 4 octets
+    // RDLENGTH field = 2 octets
+    // A RDATA = 4 octets
+    // Total = 17 + 2 + 2 + 4 + 2 + 4 = 31 octets
+
+    // RRSIG RR
+    // www.example.com = 1 + 4 + 1 + 7 + 1 + 3 + 1 = 17 octets
+    // TYPE field = 2 octets
+    // CLASS field = 2 octets
+    // TTL field = 4 octets
+    // RDLENGTH field = 2 octets
+    // RRSIG RDATA = 18 + [1 + 7 + 1 + 3 + 1 (example.com)] + 3 (base64
+    //               decode of FAKE) octets
+    // Total = 17 + 2 + 2 + 4 + 2 + 34 = 61 octets
+
+    // 1. with RRSIG, DNSSEC not OK
+    // ` 2 A RRs + 0 RRSIG RRs
+    const TreeNodeRRset rrset1(rrclass_, www_node_, a_rdataset_, false);
+    EXPECT_EQ(31 + 31, rrset1.getLength());
+
+    // 2. with RRSIG, DNSSEC OK
+    // ` 2 A RRs + 1 RRSIG RR
+    const TreeNodeRRset rrset2(rrclass_, www_node_, a_rdataset_, true);
+    EXPECT_EQ(31 + 31 + 61, rrset2.getLength());
+}
+
 TEST_F(TreeNodeRRsetTest, toWire) {
     MessageRenderer expected_renderer, actual_renderer;
     OutputBuffer expected_buffer(0), actual_buffer(0);
diff --git a/src/lib/dns/python/rrset_python.cc b/src/lib/dns/python/rrset_python.cc
index de5925a..07af4ea 100644
--- a/src/lib/dns/python/rrset_python.cc
+++ b/src/lib/dns/python/rrset_python.cc
@@ -53,6 +53,7 @@ int RRset_init(s_RRset* self, PyObject* args);
 void RRset_destroy(s_RRset* self);
 
 PyObject* RRset_getRdataCount(PyObject* self, PyObject* args);
+PyObject* RRset_getLength(PyObject* self, PyObject* args);
 PyObject* RRset_getName(PyObject* self, PyObject* args);
 PyObject* RRset_getClass(PyObject* self, PyObject* args);
 PyObject* RRset_getType(PyObject* self, PyObject* args);
@@ -70,6 +71,8 @@ PyObject* RRset_removeRRsig(PyObject* self, PyObject* args);
 PyMethodDef RRset_methods[] = {
     { "get_rdata_count", RRset_getRdataCount, METH_NOARGS,
       "Returns the number of rdata fields." },
+    { "get_length", RRset_getLength, METH_NOARGS,
+      "Returns the wire format length of the RRset." },
     { "get_name", RRset_getName, METH_NOARGS,
       "Returns the name of the RRset, as a Name object." },
     { "get_class", RRset_getClass, METH_NOARGS,
@@ -136,6 +139,18 @@ RRset_getRdataCount(PyObject* self, PyObject*) {
 }
 
 PyObject*
+RRset_getLength(PyObject* self, PyObject*) {
+    try {
+        return (Py_BuildValue("H", static_cast<const s_RRset*>(self)->cppobj->
+                              getLength()));
+    } catch (const EmptyRRset& ers) {
+        PyErr_Clear();
+        PyErr_SetString(po_EmptyRRset, ers.what());
+        return (NULL);
+    }
+}
+
+PyObject*
 RRset_getName(PyObject* self, PyObject*) {
     try {
         return (createNameObject(static_cast<const s_RRset*>(self)->cppobj->
diff --git a/src/lib/dns/python/tests/rrset_python_test.py b/src/lib/dns/python/tests/rrset_python_test.py
index 9592b42..d848d27 100644
--- a/src/lib/dns/python/tests/rrset_python_test.py
+++ b/src/lib/dns/python/tests/rrset_python_test.py
@@ -45,6 +45,24 @@ class TestModuleSpec(unittest.TestCase):
             self.assertEqual(i, self.rrset_a_empty.get_rdata_count())
             self.rrset_a_empty.add_rdata(Rdata(RRType("A"), RRClass("IN"), "192.0.2.1"))
 
+    def test_get_length(self):
+        # Empty RRset should throw
+        self.assertRaises(EmptyRRset, self.rrset_a_empty.get_length);
+
+        # Unless it is type ANY or NONE:
+        # test.example.com = 1 + 4 + 1 + 7 + 1 + 3 + 1 = 18 octets
+        # TYPE field = 2 octets
+        # CLASS field = 2 octets
+        # TTL field = 4 octets
+        # RDLENGTH field = 2 octets
+        # Total = 18 + 2 + 2 + 4 + 2 = 28 octets
+        self.assertEqual(28, self.rrset_any_a_empty.get_length())
+
+        # Single A RR:
+        # 28 octets (above) + 4 octets (A RDATA) = 32 octets
+        # With 2 A RRs:
+        self.assertEqual(32 + 32, self.rrset_a.get_length())
+
     def test_get_name(self):
         self.assertEqual(self.test_name, self.rrset_a.get_name())
         self.assertEqual(self.test_domain, self.rrset_ns.get_name())
diff --git a/src/lib/dns/rdata.cc b/src/lib/dns/rdata.cc
index f42c349..ff95fee 100644
--- a/src/lib/dns/rdata.cc
+++ b/src/lib/dns/rdata.cc
@@ -46,6 +46,15 @@ namespace isc {
 namespace dns {
 namespace rdata {
 
+uint16_t
+Rdata::getLength() const {
+    OutputBuffer obuffer(0);
+
+    toWire(obuffer);
+
+    return (obuffer.getLength());
+}
+
 // XXX: we need to specify std:: for string to help doxygen match the
 // function signature with that given in the header file.
 RdataPtr
diff --git a/src/lib/dns/rdata.h b/src/lib/dns/rdata.h
index 3fe0c74..79ca641 100644
--- a/src/lib/dns/rdata.h
+++ b/src/lib/dns/rdata.h
@@ -221,6 +221,21 @@ public:
     /// \return > 0 if \c this would be sorted after \c other.
     virtual int compare(const Rdata& other) const = 0;
     //@}
+
+    /// \brief Get the wire format length of an Rdata.
+    ///
+    /// IMPLEMENTATION NOTE: Currently this base class implementation is
+    /// non-optimal as it renders the wire data to a buffer and returns
+    /// the buffer's length. What would perform better is to add
+    /// implementations of \c getLength() method to every RDATA
+    /// type. This is why this method is virtual. Once all Rdata types
+    /// have \c getLength() implementations, this base class
+    /// implementation must be removed and the method should become a
+    /// pure interface.
+    ///
+    /// \return The length of the wire format representation of the
+    /// RDATA.
+    virtual uint16_t getLength() const;
 };
 
 namespace generic {
diff --git a/src/lib/dns/rrset.cc b/src/lib/dns/rrset.cc
index 8dfe884..8b9f4c4 100644
--- a/src/lib/dns/rrset.cc
+++ b/src/lib/dns/rrset.cc
@@ -289,6 +289,50 @@ BasicRRset::toText() const {
     return (AbstractRRset::toText());
 }
 
+uint16_t
+BasicRRset::getLength() const {
+    uint16_t length = 0;
+    RdataIteratorPtr it = getRdataIterator();
+
+    if (it->isLast()) {
+        // empty rrsets are only allowed for classes ANY and NONE
+        if (getClass() != RRClass::ANY() &&
+            getClass() != RRClass::NONE()) {
+            isc_throw(EmptyRRset, "getLength() is attempted for an empty RRset");
+        }
+
+        // For an empty RRset, write the name, type, class and TTL once,
+        // followed by empty rdata.
+        length += getName().getLength();
+        length += 2; // TYPE field
+        length += 2; // CLASS field
+        length += 4; // TTL field
+        length += 2; // RDLENGTH field (=0 in wire format)
+
+        return (length);
+    }
+
+    do {
+        // This is a size_t as some of the following additions may
+        // overflow due to a programming mistake somewhere.
+        size_t rrlen = 0;
+
+        rrlen += getName().getLength();
+        rrlen += 2; // TYPE field
+        rrlen += 2; // CLASS field
+        rrlen += 4; // TTL field
+        rrlen += 2; // RDLENGTH field
+        rrlen += it->getCurrent().getLength();
+
+        assert(length + rrlen < 65536);
+        length += rrlen;
+
+        it->next();
+    } while (!it->isLast());
+
+    return (length);
+}
+
 unsigned int
 BasicRRset::toWire(OutputBuffer& buffer) const {
     return (AbstractRRset::toWire(buffer));
@@ -322,6 +366,21 @@ RRset::getRRsigDataCount() const {
     }
 }
 
+uint16_t
+RRset::getLength() const {
+    uint16_t length = BasicRRset::getLength();
+
+    if (rrsig_) {
+        const uint16_t rrsigs_length = rrsig_->getLength();
+        // the uint16_ts are promoted to ints during addition below, so
+        // it won't overflow a 16-bit register.
+        assert(length + rrsigs_length < 65536);
+        length += rrsigs_length;
+    }
+
+    return (length);
+}
+
 unsigned int
 RRset::toWire(OutputBuffer& buffer) const {
     unsigned int rrs_written = BasicRRset::toWire(buffer);
diff --git a/src/lib/dns/rrset.h b/src/lib/dns/rrset.h
index e2301d6..42b890d 100644
--- a/src/lib/dns/rrset.h
+++ b/src/lib/dns/rrset.h
@@ -206,6 +206,20 @@ public:
     /// \return The number of \c Rdata objects contained.
     virtual unsigned int getRdataCount() const = 0;
 
+    /// \brief Get the wire format length of the \c AbstractRRset.
+    ///
+    /// This method returns the wire format length of the
+    /// \c AbstractRRset, which is calculated by summing the individual
+    /// lengths of the various fields that make up each RR.
+    ///
+    /// NOTE: When including name lengths, the allocation for
+    /// uncompressed name wire format representation is used.
+    ///
+    /// \return The length of the wire format representation of the
+    /// \c AbstractRRset.
+    /// \throw \c EmptyRRset if the \c AbstractRRset is empty.
+    virtual uint16_t getLength() const = 0;
+
     /// \brief Returns the owner name of the \c RRset.
     ///
     /// \return A reference to a \c Name class object corresponding to the
@@ -649,6 +663,13 @@ public:
     /// \return The number of \c Rdata objects contained.
     virtual unsigned int getRdataCount() const;
 
+    /// \brief Get the wire format length of the \c BasicRRset.
+    ///
+    /// \return The length of the wire format representation of the
+    /// \c BasicRRset.
+    /// \throw \c EmptyRRset if the \c BasicRRset is empty.
+    virtual uint16_t getLength() const;
+
     /// \brief Returns the owner name of the \c RRset.
     ///
     /// This method never throws an exception.
@@ -820,6 +841,13 @@ public:
 
     virtual ~RRset();
 
+    /// \brief Get the wire format length of the \c RRset.
+    ///
+    /// \return The length of the wire format representation of the
+    /// \c RRset.
+    /// \throw \c EmptyRRset if the \c RRset is empty.
+    virtual uint16_t getLength() const;
+
     /// \brief Render the RRset in the wire format with name compression and
     /// truncation handling.
     ///
diff --git a/src/lib/dns/tests/rdata_unittest.cc b/src/lib/dns/tests/rdata_unittest.cc
index 3839fbd..1678f0b 100644
--- a/src/lib/dns/tests/rdata_unittest.cc
+++ b/src/lib/dns/tests/rdata_unittest.cc
@@ -211,6 +211,14 @@ TEST_F(RdataTest, createRdataWithLexer) {
                    "file does not end with newline");
 }
 
+TEST_F(RdataTest, getLength) {
+    const in::AAAA aaaa_rdata("2001:db8::1");
+    EXPECT_EQ(16, aaaa_rdata.getLength());
+
+    const generic::TXT txt_rdata("Hello World");
+    EXPECT_EQ(12, txt_rdata.getLength());
+}
+
 }
 }
 }
diff --git a/src/lib/dns/tests/rrset_unittest.cc b/src/lib/dns/tests/rrset_unittest.cc
index 3e140bd..6e7e788 100644
--- a/src/lib/dns/tests/rrset_unittest.cc
+++ b/src/lib/dns/tests/rrset_unittest.cc
@@ -212,6 +212,30 @@ TEST_F(RRsetTest, toText) {
               rrset_none_a_empty.toText());
 }
 
+TEST_F(RRsetTest, getLength) {
+    // Empty RRset should throw
+    EXPECT_THROW(rrset_a_empty.getLength(), EmptyRRset);
+
+    // Unless it is type ANY or NONE:
+    // test.example.com = 1 + 4 + 1 + 7 + 1 + 3 + 1 = 18 octets
+    // TYPE field = 2 octets
+    // CLASS field = 2 octets
+    // TTL field = 4 octets
+    // RDLENGTH field = 2 octets
+    // Total = 18 + 2 + 2 + 4 + 2 = 28 octets
+    EXPECT_EQ(28, rrset_any_a_empty.getLength());
+    EXPECT_EQ(28, rrset_none_a_empty.getLength());
+
+    // RRset with single RDATA
+    // 28 (above) + 4 octets (A RDATA) = 32 octets
+    rrset_a_empty.addRdata(in::A("192.0.2.1"));
+    EXPECT_EQ(32, rrset_a_empty.getLength());
+
+    // 2 A RRs
+    rrset_a_empty.addRdata(in::A("192.0.2.2"));
+    EXPECT_EQ(32 + 32, rrset_a_empty.getLength());
+}
+
 TEST_F(RRsetTest, toWireBuffer) {
     rrset_a.toWire(buffer);
 
@@ -373,4 +397,38 @@ TEST_F(RRsetRRSIGTest, toText) {
               "20100322084538 20100220084538 1 example.com. FAKEFAKEFAKEFAKE\n",
               rrset_aaaa->toText());
 }
+
+TEST_F(RRsetRRSIGTest, getLength) {
+    // A RR
+    // test.example.com = 1 + 4 + 1 + 7 + 1 + 3 + 1 = 18 octets
+    // TYPE field = 2 octets
+    // CLASS field = 2 octets
+    // TTL field = 4 octets
+    // RDLENGTH field = 2 octets
+    // A RDATA = 4 octets
+    // Total = 18 + 2 + 2 + 4 + 2 + 4 = 32 octets
+
+    // 2 A RRs
+    EXPECT_EQ(32 + 32, rrset_a->getLength());
+
+    // RRSIG
+    // test.example.com = 1 + 4 + 1 + 7 + 1 + 3 + 1 = 18 octets
+    // TYPE field = 2 octets
+    // CLASS field = 2 octets
+    // TTL field = 4 octets
+    // RDLENGTH field = 2 octets
+    // RRSIG RDATA = 40 octets
+    // Total = 18 + 2 + 2 + 4 + 2 + 40 = 68 octets
+    RRsetPtr my_rrsig(new RRset(test_name, RRClass::IN(),
+                                RRType::RRSIG(), RRTTL(3600)));
+    my_rrsig->addRdata(generic::RRSIG("A 4 3 3600 "
+                                      "20000101000000 20000201000000 "
+                                      "12345 example.com. FAKEFAKEFAKE"));
+    EXPECT_EQ(68, my_rrsig->getLength());
+
+    // RRset with attached RRSIG
+    rrset_a->addRRsig(my_rrsig);
+
+    EXPECT_EQ(32 + 32 + 68, rrset_a->getLength());
+}
 }



More information about the bind10-changes mailing list