Browse Source

[1638] consolidated common logic of parsing text/wire NSEC3/NSEC3PARAM RDATA
into a shared helper module.

JINMEI Tatuya 13 years ago
parent
commit
001717c6ba

+ 4 - 0
src/lib/dns/Makefile.am

@@ -23,6 +23,8 @@ EXTRA_DIST += rdata/generic/cname_5.cc
 EXTRA_DIST += rdata/generic/cname_5.h
 EXTRA_DIST += rdata/generic/detail/nsec_bitmap.cc
 EXTRA_DIST += rdata/generic/detail/nsec_bitmap.h
+EXTRA_DIST += rdata/generic/detail/nsec3param_common.cc
+EXTRA_DIST += rdata/generic/detail/nsec3param_common.h
 EXTRA_DIST += rdata/generic/detail/txt_like.h
 EXTRA_DIST += rdata/generic/detail/ds_like.h
 EXTRA_DIST += rdata/generic/dlv_32769.cc
@@ -113,6 +115,8 @@ libdns___la_SOURCES += tsigrecord.h tsigrecord.cc
 libdns___la_SOURCES += character_string.h character_string.cc
 libdns___la_SOURCES += rdata/generic/detail/nsec_bitmap.h
 libdns___la_SOURCES += rdata/generic/detail/nsec_bitmap.cc
+libdns___la_SOURCES += rdata/generic/detail/nsec3param_common.cc
+libdns___la_SOURCES += rdata/generic/detail/nsec3param_common.h
 libdns___la_SOURCES += rdata/generic/detail/txt_like.h
 libdns___la_SOURCES += rdata/generic/detail/ds_like.h
 

+ 127 - 0
src/lib/dns/rdata/generic/detail/nsec3param_common.cc

@@ -0,0 +1,127 @@
+// Copyright (C) 2012  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <exceptions/exceptions.h>
+
+#include <util/encode/hex.h>
+#include <util/buffer.h>
+
+#include <dns/exceptions.h>
+#include <dns/rdata.h>
+#include <dns/rdata/generic/detail/nsec3param_common.h>
+
+#include <boost/lexical_cast.hpp>
+
+#include <sstream>
+#include <vector>
+#include <stdint.h>
+
+using namespace std;
+using namespace isc::util;
+using namespace isc::util::encode;
+
+namespace isc {
+namespace dns {
+namespace rdata {
+namespace generic {
+namespace detail {
+namespace nsec3 {
+
+ParseNSEC3ParamResult
+parseNSEC3ParamText(const char* const rrtype_name,
+                    const string& rdata_str, istringstream& iss, 
+                    vector<uint8_t>& salt)
+{
+    unsigned int hashalg, flags, iterations;
+    string iterations_str, salthex;
+
+    iss >> hashalg >> flags >> iterations_str >> salthex;
+    if (iss.bad() || iss.fail()) {
+        isc_throw(InvalidRdataText, "Invalid " << rrtype_name <<
+                  " text: " << rdata_str);
+    }
+    if (hashalg > 0xff) {
+        isc_throw(InvalidRdataText, rrtype_name <<
+                  " hash algorithm out of range: " << hashalg);
+    }
+    if (flags > 0xff) {
+        isc_throw(InvalidRdataText, rrtype_name << " flags out of range: " <<
+                  flags);
+    }
+    // Convert iteration.  To reject an invalid case where there's no space
+    // between iteration and salt, we extract this field as string and convert
+    // to integer.
+    try {
+        iterations = boost::lexical_cast<unsigned int>(iterations_str);
+    } catch (const boost::bad_lexical_cast&) {
+        isc_throw(InvalidRdataText, "Bad " << rrtype_name <<
+                  " iteration: " << iterations_str);
+    }
+    if (iterations > 0xffff) {
+        isc_throw(InvalidRdataText, rrtype_name <<
+                  " iterations out of range: " <<
+            iterations);
+    }
+
+    if (salthex != "-") {       // "-" means a 0-length salt
+        decodeHex(salthex, salt);
+    }
+    if (salt.size() > 255) {
+        isc_throw(InvalidRdataText, rrtype_name << " salt is too long: "
+                  << salt.size() << " bytes");
+    }
+
+    return (ParseNSEC3ParamResult(hashalg, flags, iterations));
+}
+
+ParseNSEC3ParamResult
+parseNSEC3ParamWire(const char* const rrtype_name,
+                    InputBuffer& buffer,
+                    size_t& rdata_len, std::vector<uint8_t>& salt)
+{
+    // NSEC3/NSEC3PARAM RR must have at least 5 octets:
+    // hash algorithm(1), flags(1), iteration(2), saltlen(1)
+    if (rdata_len < 5) {
+        isc_throw(DNSMessageFORMERR, rrtype_name << " too short, length: "
+                  << rdata_len);
+    }
+
+    const uint8_t hashalg = buffer.readUint8();
+    const uint8_t flags = buffer.readUint8();
+    const uint16_t iterations = buffer.readUint16();
+
+    const uint8_t saltlen = buffer.readUint8();
+    rdata_len -= 5;
+    if (rdata_len < saltlen) {
+        isc_throw(DNSMessageFORMERR, rrtype_name <<
+                  " salt length is too large: " <<
+                  static_cast<unsigned int>(saltlen));
+    }
+
+    salt.resize(saltlen);
+    if (saltlen > 0) {
+        buffer.readData(&salt[0], saltlen);
+        rdata_len -= saltlen;
+    }
+
+    return (ParseNSEC3ParamResult(hashalg, flags, iterations));
+}
+
+} // end of nsec3
+} // end of detail
+} // end of generic
+} // end of rdata
+} // end of dns
+} // end of isc
+

+ 134 - 0
src/lib/dns/rdata/generic/detail/nsec3param_common.h

@@ -0,0 +1,134 @@
+// Copyright (C) 2012  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef __NSEC3PARAM_COMMON_H
+#define __NSEC3PARAM_COMMON_H 1
+
+#include <util/buffer.h>
+
+#include <stdint.h>
+
+#include <sstream>
+#include <string>
+#include <vector>
+
+namespace isc {
+namespace dns {
+namespace rdata {
+namespace generic {
+namespace detail {
+namespace nsec3 {
+
+/// \file
+///
+/// This helper module provides some utilities that handle NSEC3 and
+/// NSEC3PARAM RDATA.  They share the first few fields, and some operations
+/// on these fields are sufficiently complicated, 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 NSEC3 and \c NSEC3PARAM class implementations.
+
+/// \brief Result values of the utilities.
+///
+/// This structure encapsulates a tuple of NSEC3/NSEC3PARAM algorithm,
+/// flags and iterations field values.  This is used as the return value
+/// of the utility functions defined in this module so the caller can
+/// use it for constructing the corresponding RDATA.
+struct ParseNSEC3ParamResult {
+    ParseNSEC3ParamResult(uint8_t param_algorithm, uint8_t param_flags,
+                          uint16_t param_iterations) :
+        algorithm(param_algorithm), flags(param_flags),
+        iterations(param_iterations)
+    {}
+    const uint8_t algorithm;
+    const uint8_t flags;
+    const uint16_t iterations;
+};
+
+/// \brief Convert textual representation of NSEC3 parameters.
+///
+/// This function takes an input string stream that consists of a complete
+/// textual representation of an NSEC3 or NSEC3PARAM RDATA and parses it
+/// extracting the hash algorithm, flags, iterations, and salt fields.
+///
+/// The first three fields are returned as the return value of this function.
+/// The salt will be stored in the given vector.  The vector is expected
+/// to be empty, but if not, the existing content will be overridden.
+///
+/// On successful return the given input stream will reach the end of the
+/// salt field.
+///
+/// \exception isc::BadValue The salt is not a valid hex string.
+/// \exception InvalidRdataText The given string is otherwise invalid for
+/// NSEC3 or NSEC3PARAM fields.
+///
+/// \param rrtype_name Either "NSEC3" or "NSEC3PARAM"; used as part of
+/// exception messages.
+/// \param rdata_str A complete textual string of the RDATA; used as part of
+/// exception messages.
+/// \param iss Input stream that consists of a complete textual string of
+/// the RDATA.
+/// \param salt A placeholder for the salt field value of the RDATA.
+/// Expected to be empty, but it's not checked (and will be overridden).
+///
+/// \return The hash algorithm, flags, iterations in the form of
+/// ParseNSEC3ParamResult.
+ParseNSEC3ParamResult parseNSEC3ParamText(const char* const rrtype_name,
+                                          const std::string& rdata_str,
+                                          std::istringstream& iss,
+                                          std::vector<uint8_t>& salt);
+
+/// \brief Extract NSEC3 parameters from wire-format data.
+///
+/// This function takes an input buffer that stores wire-format NSEC3 or
+/// NSEC3PARAM RDATA and parses it extracting the hash algorithm, flags,
+/// iterations, and salt fields.
+///
+/// The first three fields are returned as the return value of this function.
+/// The salt will be stored in the given vector.  The vector is expected
+/// to be empty, but if not, the existing content will be overridden.
+///
+/// On successful return the input buffer will point to the end of the
+/// salt field; rdata_len will be the length of the rest of RDATA
+/// (in the case of a valid NSEC3PARAM, it should be 0).
+///
+/// \exception DNSMessageFORMERR The wire data is invalid.
+///
+/// \param rrtype_name Either "NSEC3" or "NSEC3PARAM"; used as part of
+/// exception messages.
+/// \param buffer An input buffer that stores wire-format RDATA.  It must
+/// point to the beginning of the data.
+/// \param rdata_len The total length of the RDATA.
+/// \param salt A placeholder for the salt field value of the RDATA.
+/// Expected to be empty, but it's not checked (and will be overridden).
+///
+/// \return The hash algorithm, flags, iterations in the form of
+/// ParseNSEC3ParamResult.
+ParseNSEC3ParamResult parseNSEC3ParamWire(const char* const rrtype_name,
+                                          isc::util::InputBuffer& buffer,
+                                          size_t& rdata_len,
+                                          std::vector<uint8_t>& salt);
+}
+}
+}
+}
+}
+}
+
+#endif  // __NSEC3PARAM_COMMON_H
+
+// Local Variables:
+// mode: c++
+// End:

+ 5 - 0
src/lib/dns/rdata/generic/detail/nsec_bitmap.h

@@ -12,6 +12,9 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
+#ifndef __NSECBITMAP_H
+#define __NSECBITMAP_H 1
+
 #include <stdint.h>
 
 #include <sstream>
@@ -97,6 +100,8 @@ void bitmapsToText(const std::vector<uint8_t>& typebits,
 }
 }
 
+#endif  // __NSECBITMAP_H
+
 // Local Variables:
 // mode: c++
 // End:

+ 18 - 59
src/lib/dns/rdata/generic/nsec3_50.cc

@@ -33,12 +33,14 @@
 #include <dns/rdata.h>
 #include <dns/rdataclass.h>
 #include <dns/rdata/generic/detail/nsec_bitmap.h>
+#include <dns/rdata/generic/detail/nsec3param_common.h>
 
 #include <stdio.h>
 #include <time.h>
 
 using namespace std;
 using namespace isc::dns::rdata::generic::detail::nsec;
+using namespace isc::dns::rdata::generic::detail::nsec3;
 using namespace isc::util::encode;
 using namespace isc::util;
 
@@ -66,43 +68,16 @@ NSEC3::NSEC3(const string& nsec3_str) :
     impl_(NULL)
 {
     istringstream iss(nsec3_str);
-    unsigned int hashalg, flags, iterations;
-    string iterations_str, salthex, nexthash;
+    vector<uint8_t> salt;
+    const ParseNSEC3ParamResult params =
+        parseNSEC3ParamText("NSEC3", nsec3_str, iss, salt);
 
-    iss >> hashalg >> flags >> iterations_str >> salthex >> nexthash;
+    // Extract Next hash.  It must not be a padded base32hex string.
+    string nexthash;
+    iss >> nexthash;
     if (iss.bad() || iss.fail()) {
         isc_throw(InvalidRdataText, "Invalid NSEC3 text: " << nsec3_str);
     }
-    if (hashalg > 0xff) {
-        isc_throw(InvalidRdataText,
-                  "NSEC3 hash algorithm out of range: " << hashalg);
-    }
-    if (flags > 0xff) {
-        isc_throw(InvalidRdataText, "NSEC3 flags out of range: " << flags);
-    }
-    // Convert iteration.  To reject an invalid case where there's no space
-    // between iteration and salt, we extract this field as string and convert
-    // to integer.
-    try {
-        iterations = boost::lexical_cast<unsigned int>(iterations_str);
-    } catch (const boost::bad_lexical_cast&) {
-        isc_throw(InvalidRdataText, "Bad NSEC3 iteration: " << iterations_str);
-    }
-    if (iterations > 0xffff) {
-        isc_throw(InvalidRdataText, "NSEC3 iterations out of range: " <<
-            iterations);
-    }
-
-    vector<uint8_t> salt;
-    if (salthex != "-") {       // "-" means a 0-length salt
-        decodeHex(salthex, salt);
-    }
-    if (salt.size() > 255) {
-        isc_throw(InvalidRdataText, "NSEC3 salt is too long: "
-                  << salt.size() << " bytes");
-    }
-
-    // Next hash must not be a padded base32hex string.
     assert(!nexthash.empty());
     if (*nexthash.rbegin() == '=') {
         isc_throw(InvalidRdataText, "NSEC3 hash has padding: " << nsec3_str);
@@ -116,7 +91,8 @@ NSEC3::NSEC3(const string& nsec3_str) :
 
     // For NSEC3 empty bitmap is possible and allowed.
     if (iss.eof()) {
-        impl_ = new NSEC3Impl(hashalg, flags, iterations, salt, next,
+        impl_ = new NSEC3Impl(params.algorithm, params.flags,
+                              params.iterations, salt, next,
                               vector<uint8_t>());
         return;
     }
@@ -124,36 +100,18 @@ NSEC3::NSEC3(const string& nsec3_str) :
     vector<uint8_t> typebits;
     buildBitmapsFromText("NSEC3", iss, typebits);
 
-    impl_ = new NSEC3Impl(hashalg, flags, iterations, salt, next, typebits);
+    impl_ = new NSEC3Impl(params.algorithm, params.flags, params.iterations,
+                          salt, next, typebits);
 }
 
 NSEC3::NSEC3(InputBuffer& buffer, size_t rdata_len) {
-    // NSEC3 RR must have at least 5 octets:
-    // hash algorithm(1), flags(1), iteration(2), saltlen(1)
-    if (rdata_len < 5) {
-        isc_throw(DNSMessageFORMERR, "NSEC3 too short, length: " << rdata_len);
-    }
-
-    const uint8_t hashalg = buffer.readUint8();
-    const uint8_t flags = buffer.readUint8();
-    const uint16_t iterations = buffer.readUint16();
-
-    const uint8_t saltlen = buffer.readUint8();
-    rdata_len -= 5;
-    if (rdata_len < saltlen) {
-        isc_throw(DNSMessageFORMERR, "NSEC3 salt length is too large: " <<
-                  static_cast<unsigned int>(saltlen));
-    }
-
-    vector<uint8_t> salt(saltlen);
-    if (saltlen > 0) {
-        buffer.readData(&salt[0], saltlen);
-        rdata_len -= saltlen;
-    }
+    vector<uint8_t> salt;
+    const ParseNSEC3ParamResult params =
+        parseNSEC3ParamWire("NSEC3", buffer, rdata_len, salt);
 
     if (rdata_len < 1) {
         isc_throw(DNSMessageFORMERR, "NSEC3 too short to contain hash length, "
-                  "length: " << rdata_len + saltlen + 5);
+                  "length: " << rdata_len + salt.size() + 5);
     }
     const uint8_t nextlen = buffer.readUint8();
     --rdata_len;
@@ -174,7 +132,8 @@ NSEC3::NSEC3(InputBuffer& buffer, size_t rdata_len) {
         checkRRTypeBitmaps("NSEC3", typebits);
     }
 
-    impl_ = new NSEC3Impl(hashalg, flags, iterations, salt, next, typebits);
+    impl_ = new NSEC3Impl(params.algorithm, params.flags, params.iterations,
+                          salt, next, typebits);
 }
 
 NSEC3::NSEC3(const NSEC3& source) :

+ 16 - 69
src/lib/dns/rdata/generic/nsec3param_51.cc

@@ -12,22 +12,19 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#include <iostream>
-#include <string>
-#include <sstream>
-#include <vector>
-
-#include <boost/lexical_cast.hpp>
-
 #include <util/buffer.h>
 #include <util/encode/hex.h>
+
 #include <dns/messagerenderer.h>
-#include <dns/name.h>
 #include <dns/rdata.h>
 #include <dns/rdataclass.h>
+#include <dns/rdata/generic/detail/nsec3param_common.h>
 
-#include <stdio.h>
-#include <time.h>
+#include <boost/lexical_cast.hpp>
+
+#include <string>
+#include <sstream>
+#include <vector>
 
 using namespace std;
 using namespace isc::util;
@@ -53,75 +50,26 @@ NSEC3PARAM::NSEC3PARAM(const string& nsec3param_str) :
     impl_(NULL)
 {
     istringstream iss(nsec3param_str);
-    unsigned int hashalg, flags, iterations;
-    string iterations_str, salt_str;
-
-    iss >> hashalg >> flags >> iterations_str >> salt_str;
-    if (iss.bad() || iss.fail()) {
-        isc_throw(InvalidRdataText, "Invalid NSEC3PARAM text");
-    }
-    if (hashalg > 0xff) {
-        isc_throw(InvalidRdataText, "NSEC3PARAM hash algorithm out of range");
-    }
-    if (flags > 0xff) {
-        isc_throw(InvalidRdataText, "NSEC3PARAM flags out of range");
-    }
-    // Convert iteration.  To reject an invalid case where there's no space
-    // between iteration and salt, we extract this field as string and convert
-    // to integer.
-    try {
-        iterations = boost::lexical_cast<unsigned int>(iterations_str);
-    } catch (const boost::bad_lexical_cast&) {
-        isc_throw(InvalidRdataText, "Bad NSEC3PARAM iteration: " <<
-                  iterations_str);
-    }
-    if (iterations > 0xffff) {
-        isc_throw(InvalidRdataText, "NSEC3PARAM iterations out of range: " <<
-            iterations);
-    }
-
     vector<uint8_t> salt;
-    if (salt_str != "-") { // "-" means an empty salt, no need to touch vector
-        decodeHex(salt_str, salt);
-    }
-    if (salt.size() > 255) {
-        isc_throw(InvalidRdataText, "NSEC3PARAM salt is too long: "
-                  << salt.size() << " bytes");
-    }
+    const ParseNSEC3ParamResult params =
+        parseNSEC3ParamText("NSEC3PARAM", nsec3param_str, iss, salt);
 
     if (!iss.eof()) {
         isc_throw(InvalidRdataText, "Invalid NSEC3PARAM (redundant text): "
                   << nsec3param_str);
     }
 
-    impl_ = new NSEC3PARAMImpl(hashalg, flags, iterations, salt);
+    impl_ = new NSEC3PARAMImpl(params.algorithm, params.flags,
+                               params.iterations, salt);
 }
 
 NSEC3PARAM::NSEC3PARAM(InputBuffer& buffer, size_t rdata_len) {
-    // NSEC3 RR must have at least 5 octets:
-    // hash algorithm(1), flags(1), iteration(2), saltlen(1)
-    if (rdata_len < 5) {
-        isc_throw(DNSMessageFORMERR, "NSEC3PARAM too short, length: "
-                  << rdata_len);
-    }
-
-    const uint8_t hashalg = buffer.readUint8();
-    const uint8_t flags = buffer.readUint8();
-    const uint16_t iterations = buffer.readUint16();
-
-    const uint8_t saltlen = buffer.readUint8();
-    rdata_len -= 5;
-    if (rdata_len < saltlen) {
-        isc_throw(DNSMessageFORMERR, "NSEC3PARAM salt length is too large: "
-                  << static_cast<unsigned int>(saltlen));
-    }
-
-    vector<uint8_t> salt(saltlen);
-    if (saltlen > 0) {
-        buffer.readData(&salt[0], saltlen);
-    }
+    vector<uint8_t> salt;
+    const ParseNSEC3ParamResult params =
+        parseNSEC3ParamWire("NSEC3PARAM", buffer, rdata_len, salt);
 
-    impl_ = new NSEC3PARAMImpl(hashalg, flags, iterations, salt);
+    impl_ = new NSEC3PARAMImpl(params.algorithm, params.flags,
+                               params.iterations, salt);
 }
 
 NSEC3PARAM::NSEC3PARAM(const NSEC3PARAM& source) :
@@ -225,6 +173,5 @@ NSEC3PARAM::getSalt() const {
     return (impl_->salt_);
 }
 
-
 // END_RDATA_NAMESPACE
 // END_ISC_NAMESPACE