BIND 10 master, updated. 28ba8bd71ae4d100cb250fd8d99d80a17a6323a2 [master] Merge branch 'trac1641'

BIND 10 source code commits bind10-changes at lists.isc.org
Mon Feb 13 21:47:03 UTC 2012


The branch, master has been updated
       via  28ba8bd71ae4d100cb250fd8d99d80a17a6323a2 (commit)
       via  0aef7c479e7d127d0c219d6b3a5a4d0f3f701161 (commit)
       via  eaff1f5816bd2ed57a011f658e0b2dd762800079 (commit)
       via  2a29f6b8725bf106dce2f45f2705bac555022c5d (commit)
       via  9ff58bb76e632a8f7a28a4f86f94dd1d77690796 (commit)
       via  a9eadb451bea1a4813a7b3942a7ca2eea97618a5 (commit)
       via  ddaaee4b050468048409170f1bb56530f33567d6 (commit)
       via  9e3c7d57f3144b6992d8967af5a4583aa3d55c62 (commit)
       via  78785509428db0da450a2be7e89a342d1200cf0a (commit)
       via  8e98da42d48e5e847cd12debab6738c585db4740 (commit)
       via  f10604eb75f876d77af25b30b0709d5c554a6b26 (commit)
       via  d9640f6f30078a6b86d7b096ad0563bf45ffeb0f (commit)
       via  5c4967145b426d190fb6086307ade06e8ad093e1 (commit)
       via  4a20cc2eef19a7ada8e2c594724ca44e40be5cf8 (commit)
       via  d72e05e550f443209afbfd0b173d0a1e96dff749 (commit)
       via  e9647bb3c689941916508a663b72df63be7d3963 (commit)
       via  b86f7c330eba5b252adbea0594c2225fbc31e2e2 (commit)
       via  e6532b8bb0bca5d9b2a64c721f99063371055add (commit)
       via  c41cda65e06b6776c7111e65b04c72d5bc84c54f (commit)
       via  5a3853394c09ef698795c3b7fe98661e752e0426 (commit)
      from  185cb45b7ab1a164a7bb0a989c582a74ce50f2f3 (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 28ba8bd71ae4d100cb250fd8d99d80a17a6323a2
Merge: 185cb45 0aef7c4
Author: JINMEI Tatuya <jinmei at isc.org>
Date:   Mon Feb 13 13:45:46 2012 -0800

    [master] Merge branch 'trac1641'

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

Summary of changes:
 src/lib/dns/rdata/generic/detail/nsec_bitmap.cc    |   84 +++++++-
 src/lib/dns/rdata/generic/detail/nsec_bitmap.h     |   63 +++++-
 src/lib/dns/rdata/generic/nsec3_50.cc              |  186 ++++++---------
 src/lib/dns/rdata/generic/nsec_47.cc               |   62 +-----
 src/lib/dns/tests/rdata_nsec3_unittest.cc          |   94 ++++++--
 src/lib/dns/tests/rdata_nsec_unittest.cc           |   29 +++-
 src/lib/dns/tests/rdata_nsecbitmap_unittest.cc     |  253 ++++++++++++++++----
 src/lib/dns/tests/testdata/Makefile.am             |    5 +
 .../dns/tests/testdata/rdata_nsec3_fromWire16.spec |    8 +
 .../dns/tests/testdata/rdata_nsec3_fromWire17.spec |    8 +
 .../dns/tests/testdata/rdata_nsec_fromWire16.spec  |    8 +
 11 files changed, 567 insertions(+), 233 deletions(-)
 create mode 100644 src/lib/dns/tests/testdata/rdata_nsec3_fromWire16.spec
 create mode 100644 src/lib/dns/tests/testdata/rdata_nsec3_fromWire17.spec
 create mode 100644 src/lib/dns/tests/testdata/rdata_nsec_fromWire16.spec

-----------------------------------------------------------------------
diff --git a/src/lib/dns/rdata/generic/detail/nsec_bitmap.cc b/src/lib/dns/rdata/generic/detail/nsec_bitmap.cc
index a72058f..bb48705 100644
--- a/src/lib/dns/rdata/generic/detail/nsec_bitmap.cc
+++ b/src/lib/dns/rdata/generic/detail/nsec_bitmap.cc
@@ -12,11 +12,17 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#include <stdint.h>
-
-#include <vector>
+#include <exceptions/exceptions.h>
 
 #include <dns/exceptions.h>
+#include <dns/rdata.h>
+#include <dns/rrtype.h>
+
+#include <cassert>
+#include <sstream>
+#include <vector>
+#include <cstring>
+#include <stdint.h>
 
 using namespace std;
 
@@ -70,6 +76,78 @@ checkRRTypeBitmaps(const char* const rrtype_name,
         first = false;
     }
 }
+
+void
+buildBitmapsFromText(const char* const rrtype_name,
+                     istringstream& iss, vector<uint8_t>& typebits)
+{
+    uint8_t bitmap[8 * 1024];       // 64k bits
+    memset(bitmap, 0, sizeof(bitmap));
+
+    do {
+        string type;
+        iss >> type;
+        if (iss.bad() || iss.fail()) {
+            isc_throw(InvalidRdataText, "Unexpected input for "
+                      << rrtype_name << " bitmap");
+        }
+        try {
+            const int code = RRType(type).getCode();
+            bitmap[code / 8] |= (0x80 >> (code % 8));
+        } catch (const InvalidRRType&) {
+            isc_throw(InvalidRdataText, "Invalid RRtype in "
+                      << rrtype_name << " bitmap: " << type);
+        }
+    } while (!iss.eof());
+
+    for (int window = 0; window < 256; ++window) {
+        int octet;
+        for (octet = 31; octet >= 0; octet--) {
+            if (bitmap[window * 32 + octet] != 0) {
+                break;
+            }
+        }
+        if (octet < 0) {
+            continue;
+        }
+        typebits.push_back(window);
+        typebits.push_back(octet + 1);
+        for (int i = 0; i <= octet; ++i) {
+            typebits.push_back(bitmap[window * 32 + i]);
+        }
+    }
+}
+
+void
+bitmapsToText(const vector<uint8_t>& typebits, ostringstream& oss) {
+    // In the following loop we use string::at() rather than operator[].
+    // Since the index calculation is a bit complicated, it will be safer
+    // and easier to find a bug (if any).  Note that this conversion method
+    // is generally not expected to be very efficient, so the slight overhead
+    // of at() should be acceptable.
+    const size_t typebits_len = typebits.size();
+    size_t len = 0;
+    for (size_t i = 0; i < typebits_len; i += len) {
+        assert(i + 2 <= typebits.size());
+        const unsigned int block = typebits.at(i);
+        len = typebits.at(i + 1);
+        assert(len > 0 && len <= 32);
+        i += 2;
+        for (size_t j = 0; j < len; ++j) {
+            if (typebits.at(i + j) == 0) {
+                continue;
+            }
+            for (size_t k = 0; k < 8; ++k) {
+                if ((typebits.at(i + j) & (0x80 >> k)) == 0) {
+                    continue;
+                }
+                const unsigned int t = block * 256 + j * 8 + k;
+                assert(t < 65536);
+                oss << " " << RRType(t);
+            }
+        }
+    }
+}
 }
 }
 }
diff --git a/src/lib/dns/rdata/generic/detail/nsec_bitmap.h b/src/lib/dns/rdata/generic/detail/nsec_bitmap.h
index 6431e10..27a5166 100644
--- a/src/lib/dns/rdata/generic/detail/nsec_bitmap.h
+++ b/src/lib/dns/rdata/generic/detail/nsec_bitmap.h
@@ -14,6 +14,7 @@
 
 #include <stdint.h>
 
+#include <sstream>
 #include <vector>
 
 namespace isc {
@@ -22,14 +23,22 @@ namespace rdata {
 namespace generic {
 namespace detail {
 namespace nsec {
-/// Check if a given "type bitmap" for NSEC/NSEC3 is valid.
+
+/// \file
+///
+/// This helper module provides some utilities that handle NSEC and NSEC3
+/// type bitmaps.  The format and processing of the type bitmaps are generally
+/// the same for these two RRs, so it would make sense to consolidate
+/// the processing logic into a single implementation module.
+///
+/// The functions defined here are essentially private and are only expected
+/// to be called from the \c NSEC and \c NSEC3 class implementations.
+
+/// \brief Check if a given "type bitmap" for NSEC/NSEC3 is valid.
 ///
-/// This helper function checks given wire format data (stored in a
+/// This function checks given wire format data (stored in a
 /// \c std::vector) is a valid type bitmaps used for the NSEC and NSEC3 RRs
-/// according to RFC4034 and RFC5155.  The validation logic is the same
-/// for these two RRs, so a unified check function is provided.
-/// This function is essentially private and is only expected to be called
-/// from the \c NSEC and \c NSEC3 class implementations.
+/// according to RFC4034 and RFC5155.
 ///
 /// \exception DNSMessageFORMERR The bitmap is not valid.
 ///
@@ -39,6 +48,48 @@ namespace nsec {
 /// is the total length of the bitmaps.
 void checkRRTypeBitmaps(const char* const rrtype_name,
                         const std::vector<uint8_t>& typebits);
+
+/// \brief Convert textual sequence of RR types into type bitmaps.
+///
+/// This function extracts a sequence of strings, converts each sequence
+/// into an RR type, and builds NSEC/NSEC3 type bitmaps with the corresponding
+/// bits for the extracted types being on.  The resulting bitmaps (which are
+/// in the wire format according to RFC4034 and RFC5155) are stored in the
+/// given vector.  This function expects the given string stream ends with
+/// the sequence.
+///
+/// \exception InvalidRdataText The given input stream does not meet the
+/// assumption (e.g. including invalid form of RR type, not ending with
+/// an RR type string).
+///
+/// \param rrtype_name Either "NSEC" or "NSEC3"; used as part of exception
+/// messages.
+/// \param iss Input stream that consists of a complete sequence of textual
+/// RR types for which the corresponding bits are set.
+/// \param typebits A placeholder for the resulting bitmaps.  Expected to be
+/// empty, but it's not checked.
+void buildBitmapsFromText(const char* const rrtype_name,
+                          std::istringstream& iss,
+                          std::vector<uint8_t>& typebits);
+
+/// \brief Convert type bitmaps to textual sequence of RR types.
+///
+/// This function converts wire-format data of type bitmaps for NSEC/NSEC3
+/// into a sequence of corresponding RR type strings, and inserts them
+/// into the given output stream with separating them by a single space
+/// character.
+///
+/// This function assumes the given bitmaps are valid in terms of RFC4034
+/// and RFC5155 (in practice, it assumes it's from a validly constructed
+/// NSEC or NSEC3 object); if it detects a format error, it aborts the
+/// program with assert().
+///
+/// \param typebits The type bitmaps in wire format.  The size of vector
+/// is the total length of the bitmaps.
+/// \param oss The output stream to which the converted RR type sequence
+/// are to be inserted.
+void bitmapsToText(const std::vector<uint8_t>& typebits,
+                   std::ostringstream& oss);
 }
 }
 }
diff --git a/src/lib/dns/rdata/generic/nsec3_50.cc b/src/lib/dns/rdata/generic/nsec3_50.cc
index 092695c..3817941 100644
--- a/src/lib/dns/rdata/generic/nsec3_50.cc
+++ b/src/lib/dns/rdata/generic/nsec3_50.cc
@@ -53,12 +53,12 @@ struct NSEC3Impl {
         salt_(salt), next_(next), typebits_(typebits)
     {}
 
-    uint8_t hashalg_;
-    uint8_t flags_;
-    uint16_t iterations_;
-    vector<uint8_t> salt_;
-    vector<uint8_t> next_;
-    vector<uint8_t> typebits_;
+    const uint8_t hashalg_;
+    const uint8_t flags_;
+    const uint16_t iterations_;
+    const vector<uint8_t> salt_;
+    const vector<uint8_t> next_;
+    const vector<uint8_t> typebits_;
 };
 
 NSEC3::NSEC3(const string& nsec3_str) :
@@ -116,36 +116,7 @@ NSEC3::NSEC3(const string& nsec3_str) :
     }
 
     vector<uint8_t> typebits;
-    uint8_t bitmap[8 * 1024];       // 64k bits
-    memset(bitmap, 0, sizeof(bitmap));
-    do { 
-        string type;
-        iss >> type;
-        if (type.length() != 0) {
-            try {
-                const int code = RRType(type).getCode();
-                bitmap[code / 8] |= (0x80 >> (code % 8));
-            } catch (...) {
-                isc_throw(InvalidRdataText, "Invalid RRtype in NSEC3");
-            }
-        }
-    } while (!iss.eof());
-
-    for (int window = 0; window < 256; window++) {
-        int octet;
-        for (octet = 31; octet >= 0; octet--) {
-            if (bitmap[window * 32 + octet] != 0) {
-                break;
-            }
-        }
-        if (octet < 0)
-            continue;
-        typebits.push_back(window);
-        typebits.push_back(octet + 1);
-        for (int i = 0; i <= octet; i++) {
-            typebits.push_back(bitmap[window * 32 + i]);
-        }
-    }
+    buildBitmapsFromText("NSEC3", iss, typebits);
 
     impl_ = new NSEC3Impl(hashalg, flags, iterations, salt, next, typebits);
 }
@@ -174,6 +145,10 @@ NSEC3::NSEC3(InputBuffer& buffer, size_t rdata_len) {
         rdata_len -= saltlen;
     }
 
+    if (rdata_len < 1) {
+        isc_throw(DNSMessageFORMERR, "NSEC3 too short to contain hash length, "
+                  "length: " << rdata_len + saltlen + 5);
+    }
     const uint8_t nextlen = buffer.readUint8();
     --rdata_len;
     if (nextlen == 0 || rdata_len < nextlen) {
@@ -220,57 +195,78 @@ NSEC3::~NSEC3() {
 string
 NSEC3::toText() const {
     ostringstream s;
-    int len = 0;
-    for (size_t i = 0; i < impl_->typebits_.size(); i += len) {
-        assert(i + 2 <= impl_->typebits_.size());
-        int window = impl_->typebits_[i];
-        len = impl_->typebits_[i + 1];
-        assert(len >= 0 && len < 32);
-        i += 2;
-        for (int j = 0; j < len; j++) {
-            if (impl_->typebits_[i + j] == 0) {
-                continue;
-            }
-            for (int k = 0; k < 8; k++) {
-                if ((impl_->typebits_[i + j] & (0x80 >> k)) == 0) {
-                    continue;
-                }
-                int t = window * 256 + j * 8 + k;
-                s << " " << RRType(t).toText();
-            }
-        }
-    }
+    bitmapsToText(impl_->typebits_, s);
 
     using namespace boost;
     return (lexical_cast<string>(static_cast<int>(impl_->hashalg_)) +
-        " " + lexical_cast<string>(static_cast<int>(impl_->flags_)) +
-        " " + lexical_cast<string>(static_cast<int>(impl_->iterations_)) +
-        " " + encodeHex(impl_->salt_) +
-        " " + encodeBase32Hex(impl_->next_) + s.str());
+            " " + lexical_cast<string>(static_cast<int>(impl_->flags_)) +
+            " " + lexical_cast<string>(static_cast<int>(impl_->iterations_)) +
+            " " + (impl_->salt_.empty() ? "-" : encodeHex(impl_->salt_)) +
+            " " + encodeBase32Hex(impl_->next_) + s.str());
+}
+
+template <typename OUTPUT_TYPE>
+void
+toWireHelper(const NSEC3Impl& impl, OUTPUT_TYPE& output) {
+    output.writeUint8(impl.hashalg_);
+    output.writeUint8(impl.flags_);
+    output.writeUint16(impl.iterations_);
+    output.writeUint8(impl.salt_.size());
+    if (!impl.salt_.empty()) {
+        output.writeData(&impl.salt_[0], impl.salt_.size());
+    }
+    assert(!impl.next_.empty());
+    output.writeUint8(impl.next_.size());
+    output.writeData(&impl.next_[0], impl.next_.size());
+    if (!impl.typebits_.empty()) {
+        output.writeData(&impl.typebits_[0], impl.typebits_.size());
+    }
 }
 
 void
 NSEC3::toWire(OutputBuffer& buffer) const {
-    buffer.writeUint8(impl_->hashalg_);
-    buffer.writeUint8(impl_->flags_);
-    buffer.writeUint16(impl_->iterations_);
-    buffer.writeUint8(impl_->salt_.size());
-    buffer.writeData(&impl_->salt_[0], impl_->salt_.size());
-    buffer.writeUint8(impl_->next_.size());
-    buffer.writeData(&impl_->next_[0], impl_->next_.size());
-    buffer.writeData(&impl_->typebits_[0], impl_->typebits_.size());
+    toWireHelper(*impl_, buffer);
 }
 
 void
 NSEC3::toWire(AbstractMessageRenderer& renderer) const {
-    renderer.writeUint8(impl_->hashalg_);
-    renderer.writeUint8(impl_->flags_);
-    renderer.writeUint16(impl_->iterations_);
-    renderer.writeUint8(impl_->salt_.size());
-    renderer.writeData(&impl_->salt_[0], impl_->salt_.size());
-    renderer.writeUint8(impl_->next_.size());
-    renderer.writeData(&impl_->next_[0], impl_->next_.size());
-    renderer.writeData(&impl_->typebits_[0], impl_->typebits_.size());
+    toWireHelper(*impl_, renderer);
+}
+
+namespace {
+// This is a helper subroutine for compare().  It compares two binary
+// data stored in vector<uint8_t> objects based on the "Canonical RR Ordering"
+// as defined in Section 6.3 of RFC4034, that is, the data are treated
+// "as a left-justified unsigned octet sequence in which the absence of an
+// octet sorts before a zero octet."
+//
+// If check_length_first is true, it treats the compared data as if they
+// began with a single-octet "length" field whose value is the size of the
+// corresponding vector.  In this case, if the sizes of the two vectors are
+// different the shorter one is always considered the "smaller"; the contents
+// of the vector don't matter.
+//
+// This function returns:
+// -1 if v1 is considered smaller than v2
+// 1 if v1 is considered larger than v2
+// 0 otherwise
+int
+compareVectors(const vector<uint8_t>& v1, const vector<uint8_t>& v2,
+               bool check_length_first = true)
+{
+    const size_t len1 = v1.size();
+    const size_t len2 = v2.size();
+    const size_t cmplen = min(len1, len2);
+    if (check_length_first && len1 != len2) {
+        return (len1 - len2);
+    }
+    const int cmp = cmplen == 0 ? 0 : memcmp(&v1.at(0), &v2.at(0), cmplen);
+    if (cmp != 0) {
+        return (cmp);
+    } else {
+        return (len1 - len2);
+    }
+}
 }
 
 int
@@ -287,44 +283,18 @@ NSEC3::compare(const Rdata& other) const {
         return (impl_->iterations_ < other_nsec3.impl_->iterations_ ? -1 : 1);
     }
 
-    size_t this_len = impl_->salt_.size();
-    size_t other_len = other_nsec3.impl_->salt_.size();
-    size_t cmplen = min(this_len, other_len);
-    int cmp = memcmp(&impl_->salt_[0], &other_nsec3.impl_->salt_[0], cmplen);
+    int cmp = compareVectors(impl_->salt_, other_nsec3.impl_->salt_);
     if (cmp != 0) {
         return (cmp);
-    } else if (this_len < other_len) {
-        return (-1);
-    } else if (this_len > other_len) {
-        return (1);
     }
-
-    this_len = impl_->salt_.size();
-    other_len = other_nsec3.impl_->salt_.size();
-    cmplen = min(this_len, other_len);
-    cmp = memcmp(&impl_->next_[0], &other_nsec3.impl_->next_[0], cmplen);
-    if (cmp != 0) {
-        return (cmp);
-    } else if (this_len < other_len) {
-        return (-1);
-    } else if (this_len > other_len) {
-        return (1);
-    }
-
-    this_len = impl_->typebits_.size();
-    other_len = other_nsec3.impl_->typebits_.size();
-    cmplen = min(this_len, other_len);
-    cmp = memcmp(&impl_->typebits_[0], &other_nsec3.impl_->typebits_[0],
-                 cmplen);
+    cmp = compareVectors(impl_->next_, other_nsec3.impl_->next_);
     if (cmp != 0) {
         return (cmp);
-    } else if (this_len < other_len) {
-        return (-1);
-    } else if (this_len > other_len) {
-        return (1);
-    } else {
-        return (0);
     }
+    // Note that bitmap doesn't have a dedicated length field, so we shouldn't
+    // terminate the comparison just because the lengths are different.
+    return (compareVectors(impl_->typebits_, other_nsec3.impl_->typebits_,
+                           false));
 }
 
 uint8_t
diff --git a/src/lib/dns/rdata/generic/nsec_47.cc b/src/lib/dns/rdata/generic/nsec_47.cc
index a9a9f75..08825db 100644
--- a/src/lib/dns/rdata/generic/nsec_47.cc
+++ b/src/lib/dns/rdata/generic/nsec_47.cc
@@ -54,42 +54,18 @@ NSEC::NSEC(const string& nsec_str) :
 {
     istringstream iss(nsec_str);
     string nextname;
-    uint8_t bitmap[8 * 1024];       // 64k bits
-    vector<uint8_t> typebits;
 
     iss >> nextname;
     if (iss.bad() || iss.fail()) {
         isc_throw(InvalidRdataText, "Invalid NSEC name");
     }
-
-    memset(bitmap, 0, sizeof(bitmap));
-    do { 
-        string type;
-        iss >> type;
-        try {
-            const int code = RRType(type).getCode();
-            bitmap[code / 8] |= (0x80 >> (code % 8));
-        } catch (...) {
-            isc_throw(InvalidRdataText, "Invalid RRtype in NSEC");
-        }
-    } while (!iss.eof());
-
-    for (int window = 0; window < 256; window++) {
-        int octet;
-        for (octet = 31; octet >= 0; octet--) {
-            if (bitmap[window * 32 + octet] != 0) {
-                break;
-            }
-        }
-        if (octet < 0)
-            continue;
-        typebits.push_back(window);
-        typebits.push_back(octet + 1);
-        for (int i = 0; i <= octet; i++) {
-            typebits.push_back(bitmap[window * 32 + i]);
-        }
+    if (iss.eof()) {
+        isc_throw(InvalidRdataText, "NSEC bitmap is missing");
     }
 
+    vector<uint8_t> typebits;
+    buildBitmapsFromText("NSEC", iss, typebits);
+
     impl_ = new NSECImpl(Name(nextname), typebits);
 }
 
@@ -135,34 +111,8 @@ NSEC::~NSEC() {
 string
 NSEC::toText() const {
     ostringstream s;
-    int len = 0;
     s << impl_->nextname_;
-
-    // In the following loop we use string::at() rather than operator[].
-    // Since the index calculation is a bit complicated, it will be safer
-    // and easier to find a bug (if any).  Note that this conversion method
-    // is generally not expected to be very efficient, so the slight overhead
-    // of at() should be acceptable.
-    for (size_t i = 0; i < impl_->typebits_.size(); i += len) {
-        assert(i + 2 <= impl_->typebits_.size());
-        const int block = impl_->typebits_.at(i);
-        len = impl_->typebits_.at(i + 1);
-        assert(len > 0 && len <= 32);
-        i += 2;
-        for (int j = 0; j < len; j++) {
-            if (impl_->typebits_.at(i + j) == 0) {
-                continue;
-            }
-            for (int k = 0; k < 8; k++) {
-                if ((impl_->typebits_.at(i + j) & (0x80 >> k)) == 0) {
-                    continue;
-                }
-                const int t = block * 256 + j * 8 + k;
-                s << " " << RRType(t);
-            }
-        }
-    }
-
+    bitmapsToText(impl_->typebits_, s);
     return (s.str());
 }
 
diff --git a/src/lib/dns/tests/rdata_nsec3_unittest.cc b/src/lib/dns/tests/rdata_nsec3_unittest.cc
index 441c6d8..c8d21cf 100644
--- a/src/lib/dns/tests/rdata_nsec3_unittest.cc
+++ b/src/lib/dns/tests/rdata_nsec3_unittest.cc
@@ -44,8 +44,14 @@ class Rdata_NSEC3_Test : public RdataTest {
 public:
     Rdata_NSEC3_Test() :
         nsec3_txt("1 1 1 D399EAAB H9RSFB7FPF2L8HG35CMPC765TDK23RP6 "
-                  "NS SOA RRSIG DNSKEY NSEC3PARAM") {}
-    string nsec3_txt;
+                  "NS SOA RRSIG DNSKEY NSEC3PARAM"),
+        nsec3_nosalt_txt("1 1 1 - H9RSFB7FPF2L8HG35CMPC765TDK23RP6 A" ),
+        obuffer(0), renderer(obuffer)
+    {}
+    const string nsec3_txt;
+    const string nsec3_nosalt_txt;
+    OutputBuffer obuffer;
+    MessageRenderer renderer;
 };
 
 TEST_F(Rdata_NSEC3_Test, fromText) {
@@ -60,8 +66,7 @@ TEST_F(Rdata_NSEC3_Test, fromText) {
                                    "NS SOA RRSIG DNSKEY NSEC3PARAM"));
 
     // 0-length salt
-    EXPECT_EQ(0, generic::NSEC3("1 1 1 - H9RSFB7FPF2L8HG35CMPC765TDK23RP6 "
-                                "A").getSalt().size());
+    EXPECT_EQ(0, generic::NSEC3(nsec3_nosalt_txt).getSalt().size());
 
     // salt that has the possible max length
     EXPECT_EQ(255, generic::NSEC3("1 1 1 " + string(255 * 2, '0') +
@@ -80,8 +85,12 @@ TEST_F(Rdata_NSEC3_Test, fromText) {
 }
 
 TEST_F(Rdata_NSEC3_Test, toText) {
+    // normal case
     const generic::NSEC3 rdata_nsec3(nsec3_txt);
     EXPECT_EQ(nsec3_txt, rdata_nsec3.toText());
+
+    // empty salt case
+    EXPECT_EQ(nsec3_nosalt_txt, generic::NSEC3(nsec3_nosalt_txt).toText());
 }
 
 TEST_F(Rdata_NSEC3_Test, badText) {
@@ -165,7 +174,11 @@ TEST_F(Rdata_NSEC3_Test, createFromWire) {
                                       "rdata_nsec3_fromWire14.wire"),
                  DNSMessageFORMERR);
 
-    //
+    // RDLEN is too short to hold the hash length field
+    EXPECT_THROW(rdataFactoryFromFile(RRType::NSEC3(), RRClass::IN(),
+                                      "rdata_nsec3_fromWire17.wire"),
+                 DNSMessageFORMERR);
+
     // Short buffer cases.  The data is valid NSEC3 RDATA, but the buffer
     // is trimmed at the end.  All cases should result in an exception from
     // the buffer class.
@@ -180,21 +193,35 @@ TEST_F(Rdata_NSEC3_Test, createFromWire) {
     }
 }
 
-TEST_F(Rdata_NSEC3_Test, toWireRenderer) {
-    renderer.skip(2);
-    const generic::NSEC3 rdata_nsec3(nsec3_txt);
-    rdata_nsec3.toWire(renderer);
-
-    vector<unsigned char> data;
-    UnitTestUtil::readWireData("rdata_nsec3_fromWire1", data);
-    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
-                        static_cast<const uint8_t *>(obuffer.getData()) + 2,
-                        obuffer.getLength() - 2, &data[2], data.size() - 2);
+template <typename OUTPUT_TYPE>
+void
+toWireCheck(OUTPUT_TYPE& output, const char* const data_file) {
+    vector<uint8_t> data;
+    UnitTestUtil::readWireData(data_file, data);
+    InputBuffer buffer(&data[0], data.size());
+    const uint16_t rdlen = buffer.readUint16();
+    const generic::NSEC3 nsec3 =
+        dynamic_cast<const generic::NSEC3&>(*createRdata(
+                                                RRType::NSEC3(), RRClass::IN(),
+                                                buffer, rdlen));
+
+    output.clear();
+    output.writeUint16(rdlen);
+    nsec3.toWire(output);
+    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, output.getData(),
+                        output.getLength(), &data[0], data.size());
 }
 
-TEST_F(Rdata_NSEC3_Test, toWireBuffer) {
-    const generic::NSEC3 rdata_nsec3(nsec3_txt);
-    rdata_nsec3.toWire(obuffer);
+TEST_F(Rdata_NSEC3_Test, toWire) {
+    // normal case
+    toWireCheck(renderer, "rdata_nsec3_fromWire1");
+    toWireCheck(obuffer, "rdata_nsec3_fromWire1");
+
+    // empty salt
+    toWireCheck(renderer, "rdata_nsec3_fromWire13.wire");
+    toWireCheck(obuffer, "rdata_nsec3_fromWire13.wire");
+
+    // empty bitmap case is handled in the bitmap tests
 }
 
 TEST_F(Rdata_NSEC3_Test, assign) {
@@ -203,4 +230,35 @@ TEST_F(Rdata_NSEC3_Test, assign) {
     EXPECT_EQ(0, rdata_nsec3.compare(other_nsec3));
 }
 
+TEST_F(Rdata_NSEC3_Test, compare) {
+    // trivial case: self equivalence
+    EXPECT_EQ(0, generic::NSEC3(nsec3_txt).compare(generic::NSEC3(nsec3_txt)));
+
+    // comparison attempt between incompatible RR types should be rejected
+    EXPECT_THROW(generic::NSEC3(nsec3_txt).compare(*rdata_nomatch),
+                 bad_cast);
+
+    // test RDATAs, sorted in the ascendent order.  We only check comparison
+    // on NSEC3-specific fields.  Bitmap comparison is tested in the bitmap
+    // tests.
+    vector<generic::NSEC3> compare_set;
+    compare_set.push_back(generic::NSEC3("0 0 0 D399EAAB D1K6GQ38"));
+    compare_set.push_back(generic::NSEC3("1 0 0 D399EAAB D1K6GQ38"));
+    compare_set.push_back(generic::NSEC3("1 1 0 D399EAAB D1K6GQ38"));
+    compare_set.push_back(generic::NSEC3("1 1 1 - D1K6GQ38"));
+    compare_set.push_back(generic::NSEC3("1 1 1 D399EAAB D1K6GQ38"));
+    compare_set.push_back(generic::NSEC3("1 1 1 FF99EAAB D1K6GQ38"));
+    compare_set.push_back(generic::NSEC3("1 1 1 FF99EA0000 D1K6GQ38"));
+    compare_set.push_back(generic::NSEC3("1 1 1 FF99EA0000 D1K6GQ0000000000"));
+    compare_set.push_back(generic::NSEC3("1 1 1 FF99EA0000 D1K6GQ00UUUUUUUU"));
+
+    vector<generic::NSEC3>::const_iterator it;
+    const vector<generic::NSEC3>::const_iterator it_end = compare_set.end();
+    for (it = compare_set.begin(); it != it_end - 1; ++it) {
+        SCOPED_TRACE("compare " + it->toText() + " to " + (it + 1)->toText());
+        EXPECT_GT(0, (*it).compare(*(it + 1)));
+        EXPECT_LT(0, (*(it + 1)).compare(*it));
+    }
+}
+
 }
diff --git a/src/lib/dns/tests/rdata_nsec_unittest.cc b/src/lib/dns/tests/rdata_nsec_unittest.cc
index f081cd8..feb70c2 100644
--- a/src/lib/dns/tests/rdata_nsec_unittest.cc
+++ b/src/lib/dns/tests/rdata_nsec_unittest.cc
@@ -38,7 +38,7 @@ class Rdata_NSEC_Test : public RdataTest {
     // there's nothing to specialize
 };
 
-string nsec_txt("www2.isc.org. CNAME RRSIG NSEC");
+const char* const nsec_txt = "www2.isc.org. CNAME RRSIG NSEC";
 
 TEST_F(Rdata_NSEC_Test, toText_NSEC) {
     const generic::NSEC rdata_nsec(nsec_txt);
@@ -95,4 +95,31 @@ TEST_F(Rdata_NSEC_Test, getNextName) {
     EXPECT_EQ(Name("www2.isc.org"), generic::NSEC((nsec_txt)).getNextName());
 }
 
+TEST_F(Rdata_NSEC_Test, compare) {
+    // trivial case: self equivalence
+    EXPECT_EQ(0, generic::NSEC("example A").
+              compare(generic::NSEC("example. A")));
+    EXPECT_EQ(0, generic::NSEC("EXAMPLE A"). // should be case insensitive
+              compare(generic::NSEC("example. A")));
+
+    // comparison attempt between incompatible RR types should be rejected
+    EXPECT_THROW(generic::NSEC(nsec_txt).compare(*rdata_nomatch),
+                 bad_cast);
+
+    // test RDATAs, sorted in the ascendent order.  We only compare the
+    // next name here.  Bitmap comparison is tested in the bitmap tests.
+    // Note that names are compared as wire-format data, not based on the
+    // domain name comparison.
+    vector<generic::NSEC> compare_set;
+    compare_set.push_back(generic::NSEC("a.example. A"));
+    compare_set.push_back(generic::NSEC("example. A"));
+    vector<generic::NSEC>::const_iterator it;
+    const vector<generic::NSEC>::const_iterator it_end = compare_set.end();
+    for (it = compare_set.begin(); it != it_end - 1; ++it) {
+        SCOPED_TRACE("compare " + it->toText() + " to " + (it + 1)->toText());
+        EXPECT_GT(0, (*it).compare(*(it + 1)));
+        EXPECT_LT(0, (*(it + 1)).compare(*it));
+    }
+}
+
 }
diff --git a/src/lib/dns/tests/rdata_nsecbitmap_unittest.cc b/src/lib/dns/tests/rdata_nsecbitmap_unittest.cc
index 8a90878..426a69e 100644
--- a/src/lib/dns/tests/rdata_nsecbitmap_unittest.cc
+++ b/src/lib/dns/tests/rdata_nsecbitmap_unittest.cc
@@ -12,6 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
+#include <dns/tests/unittest_util.h>
+
 #include <dns/exceptions.h>
 #include <dns/rdata.h>
 #include <dns/rdataclass.h>
@@ -22,82 +24,251 @@
 
 #include <dns/tests/rdata_unittest.h>
 
+#include <boost/lexical_cast.hpp>
+
+#include <string>
+#include <vector>
+
+using namespace std;
+using boost::lexical_cast;
+using isc::UnitTestUtil;
 using namespace isc::dns;
 using namespace isc::dns::rdata;
 
 namespace {
-class Rdata_NSECBITMAP_Test : public RdataTest {
-    // there's nothing to specialize
+
+// Template for shared tests for NSEC and NSEC3 bitmaps
+template <typename RDATA_TYPE>
+class NSECLikeBitmapTest : public RdataTest {
+protected:
+    RDATA_TYPE fromText(const string& rdata_text) {
+        return (RDATA_TYPE(rdata_text));
+    }
+
+    vector<RDATA_TYPE> compare_set; // used in compare() tests
+
+    void compareCheck() const {
+        typename vector<RDATA_TYPE>::const_iterator it;
+        typename vector<RDATA_TYPE>::const_iterator const it_end =
+            compare_set.end();
+        for (it = compare_set.begin(); it != it_end - 1; ++it) {
+            SCOPED_TRACE("compare " + it->toText() + " to " +
+                         (it + 1)->toText());
+            EXPECT_GT(0, (*it).compare(*(it + 1)));
+            EXPECT_LT(0, (*(it + 1)).compare(*it));
+        }
+    }
+
+    // These depend on the specific RR type.  We use specialized methods
+    // for them.
+    static RRType getType();    // return either RRType::NSEC() or NSEC3()
+    static string getWireFilePrefix();
+    static string getCommonText(); // commonly used part of textual form
 };
 
+// Instantiate specific typed tests
+typedef ::testing::Types<generic::NSEC, generic::NSEC3> TestRdataTypes;
+TYPED_TEST_CASE(NSECLikeBitmapTest, TestRdataTypes);
+
+// NSEC and NSEC3 bitmaps have some subtle differences, in which case we
+// need to test them separately.  Using these typedef type names with TEST_F
+// will do the trick.
+typedef NSECLikeBitmapTest<generic::NSEC3> NSEC3BitmapTest;
+typedef NSECLikeBitmapTest<generic::NSEC> NSECBitmapTest;
+
+template <>
+string
+NSECLikeBitmapTest<generic::NSEC>::getWireFilePrefix() {
+    return ("rdata_nsec_");
+}
+
+template <>
+RRType
+NSECLikeBitmapTest<generic::NSEC>::getType() {
+    return (RRType::NSEC());
+}
+
+template <>
+string
+NSECLikeBitmapTest<generic::NSEC3>::getWireFilePrefix() {
+    return ("rdata_nsec3_");
+}
+
+template <>
+RRType
+NSECLikeBitmapTest<generic::NSEC3>::getType() {
+    return (RRType::NSEC3());
+}
+
+template <>
+string
+NSECLikeBitmapTest<generic::NSEC>::getCommonText() {
+    return ("next. ");
+}
+
+template <>
+string
+NSECLikeBitmapTest<generic::NSEC3>::getCommonText() {
+    return ("1 1 12 AABBCCDD 2T7B4G4VSA5SMI47K61MV5BV1A22BOJR ");
+}
+
 // Tests against various types of bogus NSEC/NSEC3 type bitmaps.
 // The syntax and semantics are common for both RR types, and our
 // implementation of that part is shared, so in theory it should be sufficient
 // to test for only one RR type.  But we check for both just in case.
-TEST_F(Rdata_NSECBITMAP_Test, createFromWire_NSEC) {
+TYPED_TEST(NSECLikeBitmapTest, createFromWire) {
     // A malformed NSEC bitmap length field that could cause overflow.
-    EXPECT_THROW(rdataFactoryFromFile(RRType::NSEC(), RRClass::IN(),
-                                      "rdata_nsec_fromWire4.wire"),
-                 DNSMessageFORMERR);
-    EXPECT_THROW(rdataFactoryFromFile(RRType::NSEC3(), RRClass::IN(),
-                                      "rdata_nsec3_fromWire4.wire"),
+    EXPECT_THROW(this->rdataFactoryFromFile(this->getType(), RRClass::IN(),
+                                            (this->getWireFilePrefix() +
+                                             "fromWire4.wire").c_str()),
                  DNSMessageFORMERR);
 
     // The bitmap field is incomplete (only the first byte is included)
-    EXPECT_THROW(rdataFactoryFromFile(RRType::NSEC(), RRClass::IN(),
-                                      "rdata_nsec_fromWire5.wire"),
-                 DNSMessageFORMERR);
-    EXPECT_THROW(rdataFactoryFromFile(RRType::NSEC3(), RRClass::IN(),
-                                      "rdata_nsec3_fromWire5.wire"),
+    EXPECT_THROW(this->rdataFactoryFromFile(this->getType(), RRClass::IN(),
+                                            (this->getWireFilePrefix() +
+                                             "fromWire5.wire").c_str()),
                  DNSMessageFORMERR);
 
     // Bitmap length is 0, which is invalid.
-    EXPECT_THROW(rdataFactoryFromFile(RRType::NSEC(), RRClass::IN(),
-                                      "rdata_nsec_fromWire6.wire"),
-                 DNSMessageFORMERR);
-    EXPECT_THROW(rdataFactoryFromFile(RRType::NSEC3(), RRClass::IN(),
-                                      "rdata_nsec3_fromWire6.wire"),
+    EXPECT_THROW(this->rdataFactoryFromFile(this->getType(), RRClass::IN(),
+                                            (this->getWireFilePrefix() +
+                                             "fromWire6.wire").c_str()),
                  DNSMessageFORMERR);
 
     // Too large bitmap length with a short buffer.
-    EXPECT_THROW(rdataFactoryFromFile(RRType::NSEC(), RRClass::IN(),
-                                      "rdata_nsec_fromWire3"),
-                 DNSMessageFORMERR);
-    EXPECT_THROW(rdataFactoryFromFile(RRType::NSEC3(), RRClass::IN(),
-                                      "rdata_nsec3_fromWire3"),
+    EXPECT_THROW(this->rdataFactoryFromFile(this->getType(), RRClass::IN(),
+                                            (this->getWireFilePrefix() +
+                                             "fromWire3").c_str()),
                  DNSMessageFORMERR);
 
     // A boundary case: longest possible bitmaps (32 maps).  This should be
     // accepted.
-    EXPECT_NO_THROW(rdataFactoryFromFile(RRType::NSEC(), RRClass::IN(),
-                                         "rdata_nsec_fromWire7.wire"));
-    EXPECT_NO_THROW(rdataFactoryFromFile(RRType::NSEC3(), RRClass::IN(),
-                                         "rdata_nsec3_fromWire7.wire"));
+    EXPECT_NO_THROW(this->rdataFactoryFromFile(this->getType(), RRClass::IN(),
+                                               (this->getWireFilePrefix() +
+                                                "fromWire7.wire").c_str()));
 
     // Another boundary condition: 33 bitmaps, which should be rejected.
-    EXPECT_THROW(rdataFactoryFromFile(RRType::NSEC(), RRClass::IN(),
-                                      "rdata_nsec_fromWire8.wire"),
-                 DNSMessageFORMERR);
-    EXPECT_THROW(rdataFactoryFromFile(RRType::NSEC3(), RRClass::IN(),
-                                      "rdata_nsec3_fromWire8.wire"),
+    EXPECT_THROW(this->rdataFactoryFromFile(this->getType(), RRClass::IN(),
+                                            (this->getWireFilePrefix() +
+                                             "fromWire8.wire").c_str()),
                  DNSMessageFORMERR);
 
     // Disordered bitmap window blocks.
-    EXPECT_THROW(rdataFactoryFromFile(RRType::NSEC(), RRClass::IN(),
-                                      "rdata_nsec_fromWire9.wire"),
-                 DNSMessageFORMERR);
-    EXPECT_THROW(rdataFactoryFromFile(RRType::NSEC3(), RRClass::IN(),
-                                      "rdata_nsec3_fromWire9.wire"),
+    EXPECT_THROW(this->rdataFactoryFromFile(this->getType(), RRClass::IN(),
+                                            (this->getWireFilePrefix() +
+                                             "fromWire9.wire").c_str()),
                  DNSMessageFORMERR);
 
     // Bitmap ending with all-zero bytes.  Not necessarily harmful except
     // the additional overhead of parsing, but invalid according to the
     // spec anyway.
-    EXPECT_THROW(rdataFactoryFromFile(RRType::NSEC(), RRClass::IN(),
-                                      "rdata_nsec_fromWire10.wire"),
+    EXPECT_THROW(this->rdataFactoryFromFile(this->getType(), RRClass::IN(),
+                                            (this->getWireFilePrefix() +
+                                             "fromWire10.wire").c_str()),
                  DNSMessageFORMERR);
-    EXPECT_THROW(rdataFactoryFromFile(RRType::NSEC3(), RRClass::IN(),
-                                      "rdata_nsec3_fromWire10.wire"),
+}
+
+TYPED_TEST(NSECLikeBitmapTest, badText) {
+    // redundant space after the sequence
+    EXPECT_THROW(this->fromText(this->getCommonText() + "A "),
+                 InvalidRdataText);
+}
+
+// This tests the result of toText() with various kinds of NSEC/NSEC3 bitmaps.
+// It also tests the "from text" constructor as a result.
+TYPED_TEST(NSECLikeBitmapTest, toText) {
+    // A simple case (some commonly seen RR types in NSEC(3) bitmaps)
+    string rdata_text = this->getCommonText() + "NS SOA RRSIG DNSKEY";
+    EXPECT_EQ(rdata_text, this->fromText(rdata_text).toText());
+
+    // Similar to above, but involves more than one bitmap window blocks.
+    rdata_text = this->getCommonText() + "NS DLV";
+    EXPECT_EQ(rdata_text, this->fromText(rdata_text).toText());
+
+    // Make sure all possible bits in a one-octet bitmap field are handled
+    // correctly.
+    // We use the range around 1024 (reasonably higher number) so it's
+    // unlikely that they have predefined mnemonic and can be safely converted
+    // to TYPEnnnn by toText().
+    for (unsigned int i = 1024; i < 1032; ++i) {
+        rdata_text = this->getCommonText() + "TYPE" + lexical_cast<string>(i);
+        EXPECT_EQ(rdata_text, this->fromText(rdata_text).toText());
+    }
+
+    // Make sure all possible 32 octets in a longest possible block are
+    // handled correctly.
+    for (unsigned int i = 1024; i < 1024 + 256; i += 8) {
+        rdata_text = this->getCommonText() + "TYPE" + lexical_cast<string>(i);
+        EXPECT_EQ(rdata_text, this->fromText(rdata_text).toText());
+    }
+
+    // Check for the highest window block.
+    rdata_text = this->getCommonText() + "TYPE65535";
+    EXPECT_EQ(rdata_text, this->fromText(rdata_text).toText());
+}
+
+TYPED_TEST(NSECLikeBitmapTest, compare) {
+    // Bit map: [win=0][len=1] 00000010
+    this->compare_set.push_back(this->fromText(this->getCommonText() + "SOA"));
+    // Bit map: [win=0][len=1] 00000010, [win=4][len=1] 10000000
+    this->compare_set.push_back(this->fromText(this->getCommonText() +
+                                               "SOA TYPE1024"));
+    // Bit map: [win=0][len=1] 00100000
+    this->compare_set.push_back(this->fromText(this->getCommonText() + "NS"));
+    // Bit map: [win=0][len=1] 00100010
+    this->compare_set.push_back(this->fromText(this->getCommonText() +
+                                               "NS SOA"));
+    // Bit map: [win=0][len=2] 00100000, 00000001
+    this->compare_set.push_back(this->fromText(this->getCommonText() +
+                                               "NS MX"));
+    // Bit map: [win=4][len=1] 10000000
+    this->compare_set.push_back(this->fromText(this->getCommonText() +
+                                               "TYPE1024"));
+
+    this->compareCheck();
+}
+
+// NSEC bitmaps must not be empty
+TEST_F(NSECBitmapTest, emptyMap) {
+    EXPECT_THROW(this->fromText("next.example").toText(), InvalidRdataText);
+
+    EXPECT_THROW(this->rdataFactoryFromFile(this->getType(), RRClass::IN(),
+                                            (this->getWireFilePrefix() +
+                                             "fromWire16.wire").c_str()),
                  DNSMessageFORMERR);
 }
+
+// NSEC3 bitmaps can be empty
+TEST_F(NSEC3BitmapTest, emptyMap) {
+    // Read wire data wit an empty NSEC3 bitmap.  This should succeed.
+    vector<uint8_t> data;
+    UnitTestUtil::readWireData((this->getWireFilePrefix() +
+                                "fromWire16.wire").c_str(), data);
+    InputBuffer buffer(&data[0], data.size());
+    const uint16_t rdlen = buffer.readUint16();
+    const generic::NSEC3 empty_nsec3 =
+        dynamic_cast<const generic::NSEC3&>(*createRdata(
+                                                RRType::NSEC3(), RRClass::IN(),
+                                                buffer, rdlen));
+
+    // Check the toText() result.
+    EXPECT_EQ("1 0 1 7373737373 D1K6GQ38D1K6GQ38D1K6GQ38D1K6GQ38",
+              empty_nsec3.toText());
+
+    // Check the toWire() result.
+    OutputBuffer obuffer(0);
+    obuffer.writeUint16(rdlen);
+    empty_nsec3.toWire(obuffer);
+    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, obuffer.getData(),
+                        obuffer.getLength(), &data[0], data.size());
+
+    // Same for MessageRenderer.
+    obuffer.clear();
+    MessageRenderer renderer(obuffer);
+    renderer.writeUint16(rdlen);
+    empty_nsec3.toWire(renderer);
+    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, renderer.getData(),
+                        renderer.getLength(), &data[0], data.size());
+}
+
 }
diff --git a/src/lib/dns/tests/testdata/Makefile.am b/src/lib/dns/tests/testdata/Makefile.am
index 27edf5f..dbff12e 100644
--- a/src/lib/dns/tests/testdata/Makefile.am
+++ b/src/lib/dns/tests/testdata/Makefile.am
@@ -20,6 +20,8 @@ BUILT_SOURCES += rdata_nsec_fromWire4.wire rdata_nsec_fromWire5.wire
 BUILT_SOURCES += rdata_nsec_fromWire6.wire rdata_nsec_fromWire7.wire
 BUILT_SOURCES += rdata_nsec_fromWire8.wire rdata_nsec_fromWire9.wire
 BUILT_SOURCES += rdata_nsec_fromWire10.wire
+# 11-15 are skipped to be consistent with NSEC3 test data
+BUILT_SOURCES += rdata_nsec_fromWire16.wire
 BUILT_SOURCES += rdata_nsec3_fromWire2.wire
 BUILT_SOURCES += rdata_nsec3_fromWire4.wire rdata_nsec3_fromWire5.wire
 BUILT_SOURCES += rdata_nsec3_fromWire6.wire rdata_nsec3_fromWire7.wire
@@ -27,6 +29,7 @@ BUILT_SOURCES += rdata_nsec3_fromWire8.wire rdata_nsec3_fromWire9.wire
 BUILT_SOURCES += rdata_nsec3_fromWire10.wire rdata_nsec3_fromWire11.wire
 BUILT_SOURCES += rdata_nsec3_fromWire12.wire rdata_nsec3_fromWire13.wire
 BUILT_SOURCES += rdata_nsec3_fromWire14.wire rdata_nsec3_fromWire15.wire
+BUILT_SOURCES += rdata_nsec3_fromWire16.wire rdata_nsec3_fromWire17.wire
 BUILT_SOURCES += rdata_rrsig_fromWire2.wire
 BUILT_SOURCES += rdata_minfo_fromWire1.wire rdata_minfo_fromWire2.wire
 BUILT_SOURCES += rdata_minfo_fromWire3.wire rdata_minfo_fromWire4.wire
@@ -99,6 +102,7 @@ EXTRA_DIST += rdata_nsec_fromWire4.spec rdata_nsec_fromWire5.spec
 EXTRA_DIST += rdata_nsec_fromWire6.spec rdata_nsec_fromWire7.spec
 EXTRA_DIST += rdata_nsec_fromWire8.spec rdata_nsec_fromWire9.spec
 EXTRA_DIST += rdata_nsec_fromWire10.spec
+EXTRA_DIST += rdata_nsec_fromWire16.spec rdata_nsec_fromWire17.spec
 EXTRA_DIST += rdata_nsec3param_fromWire1
 EXTRA_DIST += rdata_nsec3_fromWire1
 EXTRA_DIST += rdata_nsec3_fromWire2.spec rdata_nsec3_fromWire3
@@ -108,6 +112,7 @@ EXTRA_DIST += rdata_nsec3_fromWire8.spec rdata_nsec3_fromWire9.spec
 EXTRA_DIST += rdata_nsec3_fromWire10.spec rdata_nsec3_fromWire11.spec
 EXTRA_DIST += rdata_nsec3_fromWire12.spec rdata_nsec3_fromWire13.spec
 EXTRA_DIST += rdata_nsec3_fromWire14.spec rdata_nsec3_fromWire15.spec
+EXTRA_DIST += rdata_nsec3_fromWire16.spec
 EXTRA_DIST += rdata_opt_fromWire rdata_rrsig_fromWire1
 EXTRA_DIST += rdata_rrsig_fromWire2.spec
 EXTRA_DIST += rdata_rp_fromWire1.spec rdata_rp_fromWire2.spec
diff --git a/src/lib/dns/tests/testdata/rdata_nsec3_fromWire16.spec b/src/lib/dns/tests/testdata/rdata_nsec3_fromWire16.spec
new file mode 100644
index 0000000..dac14ea
--- /dev/null
+++ b/src/lib/dns/tests/testdata/rdata_nsec3_fromWire16.spec
@@ -0,0 +1,8 @@
+#
+# NSEC3 RDATA with an empty bitmap
+#
+
+[custom]
+sections: nsec3
+[nsec3]
+nbitmap: 0
diff --git a/src/lib/dns/tests/testdata/rdata_nsec3_fromWire17.spec b/src/lib/dns/tests/testdata/rdata_nsec3_fromWire17.spec
new file mode 100644
index 0000000..4253349
--- /dev/null
+++ b/src/lib/dns/tests/testdata/rdata_nsec3_fromWire17.spec
@@ -0,0 +1,8 @@
+#
+# An invalid NSEC3 RDATA: RDLEN is too short to include the hash len field.
+#
+
+[custom]
+sections: nsec3
+[nsec3]
+rdlen: 10
diff --git a/src/lib/dns/tests/testdata/rdata_nsec_fromWire16.spec b/src/lib/dns/tests/testdata/rdata_nsec_fromWire16.spec
new file mode 100644
index 0000000..d7faeed
--- /dev/null
+++ b/src/lib/dns/tests/testdata/rdata_nsec_fromWire16.spec
@@ -0,0 +1,8 @@
+#
+# An invalid NSEC RDATA: with an empty bitmap
+#
+
+[custom]
+sections: nsec
+[nsec]
+nbitmap: 0




More information about the bind10-changes mailing list