BIND 10 master, updated. 2c421b58e810028b303d328e4e2f5b74ea124839 [master] Merge branch 'trac1575'
BIND 10 source code commits
bind10-changes at lists.isc.org
Mon Jan 30 18:32:02 UTC 2012
The branch, master has been updated
via 2c421b58e810028b303d328e4e2f5b74ea124839 (commit)
via 80a2fbfd0db2b19beb0e18b3b3dc166ccdae76f6 (commit)
via 47c87e9c2cb3239284a64f9e029e52693106dccd (commit)
via ea2af1351e60e715bb70fb1b021c87e47add5d24 (commit)
via 45baff8527758f9c3610f75308d9262452c713b0 (commit)
via 81e5f0caa91e4be3b3e97d97ea6f56d92333bc16 (commit)
via 8d8a836667898774e1472eb94ea83175fbd76e52 (commit)
via f9f0ce117a1905e633489bf476bd22c673aff323 (commit)
via 5b11239e580e3a283e0f120da4119f9dd7604257 (commit)
via 0d483e15ebb9339797ba6a29dc96edb8cba2ec07 (commit)
via da9546a3569e096c68bdc9c5dda7c317cd0a77bf (commit)
via b8c42f3562a1d73a425118c1e3fcab3589c44228 (commit)
via 08796619c96ac087417929a43c1c1c71a4aa76f0 (commit)
via 9a6b7baf300a6b7e9c9c71709614348b9bdbf029 (commit)
via 745181fc6da942a22525cbe1b952e7ba4b967864 (commit)
from 789a59358ffa4f403bf84016f703f5cedafa22ab (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 2c421b58e810028b303d328e4e2f5b74ea124839
Merge: 789a593 80a2fbf
Author: JINMEI Tatuya <jinmei at isc.org>
Date: Mon Jan 30 10:24:48 2012 -0800
[master] Merge branch 'trac1575'
-----------------------------------------------------------------------
Summary of changes:
src/lib/dns/Makefile.am | 1 +
src/lib/dns/nsec3hash.cc | 129 +++++++++++++++++
src/lib/dns/nsec3hash.h | 134 +++++++++++++++++
src/lib/dns/python/Makefile.am | 2 +
.../python/nsec3hash_python.cc} | 152 ++++++++++++--------
.../python/nsec3hash_python.h} | 27 ++--
src/lib/dns/python/nsec3hash_python_inc.cc | 45 ++++++
src/lib/dns/python/pydnspp.cc | 9 ++
src/lib/dns/python/tests/Makefile.am | 1 +
src/lib/dns/python/tests/nsec3hash_python_test.py | 77 ++++++++++
src/lib/dns/rdata/generic/nsec3param_51.cc | 5 +-
src/lib/dns/tests/Makefile.am | 1 +
src/lib/dns/tests/nsec3hash_unittest.cc | 73 ++++++++++
src/lib/dns/tests/rdata_nsec3param_unittest.cc | 15 ++-
src/lib/util/python/wrapper_template.cc | 17 ++-
15 files changed, 603 insertions(+), 85 deletions(-)
create mode 100644 src/lib/dns/nsec3hash.cc
create mode 100644 src/lib/dns/nsec3hash.h
copy src/lib/{python/isc/acl/dns_requestacl_python.cc => dns/python/nsec3hash_python.cc} (53%)
copy src/lib/{python/isc/acl/dns_requestloader_python.h => dns/python/nsec3hash_python.h} (70%)
create mode 100644 src/lib/dns/python/nsec3hash_python_inc.cc
create mode 100644 src/lib/dns/python/tests/nsec3hash_python_test.py
create mode 100644 src/lib/dns/tests/nsec3hash_unittest.cc
-----------------------------------------------------------------------
diff --git a/src/lib/dns/Makefile.am b/src/lib/dns/Makefile.am
index 5b93f75..5e2a48d 100644
--- a/src/lib/dns/Makefile.am
+++ b/src/lib/dns/Makefile.am
@@ -93,6 +93,7 @@ libdns___la_SOURCES += masterload.h masterload.cc
libdns___la_SOURCES += message.h message.cc
libdns___la_SOURCES += messagerenderer.h messagerenderer.cc
libdns___la_SOURCES += name.h name.cc
+libdns___la_SOURCES += nsec3hash.h nsec3hash.cc
libdns___la_SOURCES += opcode.h opcode.cc
libdns___la_SOURCES += rcode.h rcode.cc
libdns___la_SOURCES += rdata.h rdata.cc
diff --git a/src/lib/dns/nsec3hash.cc b/src/lib/dns/nsec3hash.cc
new file mode 100644
index 0000000..3217c67
--- /dev/null
+++ b/src/lib/dns/nsec3hash.cc
@@ -0,0 +1,129 @@
+// 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 <stdint.h>
+
+#include <cassert>
+#include <string>
+#include <vector>
+
+#include <boost/noncopyable.hpp>
+
+#include <exceptions/exceptions.h>
+
+#include <util/buffer.h>
+#include <util/encode/base32hex.h>
+#include <util/hash/sha1.h>
+
+#include <dns/name.h>
+#include <dns/nsec3hash.h>
+#include <dns/rdataclass.h>
+
+using namespace std;
+using namespace isc::util;
+using namespace isc::util::encode;
+using namespace isc::util::hash;
+using namespace isc::dns;
+using namespace isc::dns::rdata;
+
+namespace {
+
+/// \brief A derived class of \c NSEC3Hash that implements the standard hash
+/// calculation specified in RFC5155.
+///
+/// Currently the only pre-defined algorithm in the RFC is SHA1. So we don't
+/// over-generalize it at the moment, and rather hardocde it and assume that
+/// specific algorithm.
+///
+/// The implementation details are only open within this file, but to avoid
+/// an accidental error in this implementation we explicitly make it non
+/// copyable.
+class NSEC3HashRFC5155 : boost::noncopyable, public NSEC3Hash {
+private:
+ // This is the algorithm number for SHA1/NSEC3 as defined in RFC5155.
+ static const uint8_t NSEC3_HASH_SHA1 = 1;
+
+public:
+ NSEC3HashRFC5155(const generic::NSEC3PARAM& param) :
+ algorithm_(param.getHashalg()),
+ iterations_(param.getIterations()),
+ salt_(param.getSalt()), digest_(SHA1_HASHSIZE), obuf_(Name::MAX_WIRE)
+ {
+ if (algorithm_ != NSEC3_HASH_SHA1) {
+ isc_throw(UnknownNSEC3HashAlgorithm, "Unknown NSEC3 algorithm: " <<
+ static_cast<unsigned int>(algorithm_));
+ }
+ SHA1Reset(&sha1_ctx_);
+ }
+
+ virtual std::string calculate(const Name& name) const;
+
+private:
+ const uint8_t algorithm_;
+ const uint16_t iterations_;
+ const vector<uint8_t> salt_;
+
+ // The following members are placeholder of work place and don't hold
+ // any state over multiple calls so can be mutable without breaking
+ // constness.
+ mutable SHA1Context sha1_ctx_;
+ mutable vector<uint8_t> digest_;
+ mutable OutputBuffer obuf_;
+};
+
+inline void
+iterateSHA1(SHA1Context* ctx, const uint8_t* input, size_t inlength,
+ const uint8_t* salt, size_t saltlen,
+ uint8_t output[SHA1_HASHSIZE])
+{
+ SHA1Reset(ctx);
+ SHA1Input(ctx, input, inlength);
+ SHA1Input(ctx, salt, saltlen); // this works whether saltlen == or > 0
+ SHA1Result(ctx, output);
+}
+
+string
+NSEC3HashRFC5155::calculate(const Name& name) const {
+ // We first need to normalize the name by converting all upper case
+ // characters in the labels to lower ones.
+ obuf_.clear();
+ Name name_copy(name);
+ name_copy.downcase();
+ name_copy.toWire(obuf_);
+
+ const uint8_t saltlen = salt_.size();
+ const uint8_t* const salt = (saltlen > 0) ? &salt_[0] : NULL;
+ uint8_t* const digest = &digest_[0];
+ assert(digest_.size() == SHA1_HASHSIZE);
+
+ iterateSHA1(&sha1_ctx_, static_cast<const uint8_t*>(obuf_.getData()),
+ obuf_.getLength(), salt, saltlen, digest);
+ for (unsigned int n = 0; n < iterations_; ++n) {
+ iterateSHA1(&sha1_ctx_, digest, SHA1_HASHSIZE, salt, saltlen, digest);
+ }
+
+ return (encodeBase32Hex(digest_));
+}
+} // end of unnamed namespace
+
+namespace isc {
+namespace dns {
+
+NSEC3Hash*
+NSEC3Hash::create(const generic::NSEC3PARAM& param) {
+ return (new NSEC3HashRFC5155(param));
+}
+
+} // namespace dns
+} // namespace isc
diff --git a/src/lib/dns/nsec3hash.h b/src/lib/dns/nsec3hash.h
new file mode 100644
index 0000000..9f39172
--- /dev/null
+++ b/src/lib/dns/nsec3hash.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 __NSEC3HASH_H
+#define __NSEC3HASH_H 1
+
+#include <string>
+
+#include <exceptions/exceptions.h>
+
+namespace isc {
+namespace dns {
+class Name;
+
+namespace rdata {
+namespace generic {
+class NSEC3PARAM;
+}
+}
+
+/// \brief An exception that is thrown for when an \c NSEC3Hash object is
+/// constructed with an unknown hash algorithm.
+///
+/// A specific exception class is used so that the caller can selectively
+/// catch this exception, e.g., while loading a zone, and handle it
+/// accordingly.
+class UnknownNSEC3HashAlgorithm : public isc::Exception {
+public:
+ UnknownNSEC3HashAlgorithm(const char* file, size_t line,
+ const char* what) :
+ isc::Exception(file, line, what) {}
+};
+
+/// \brief A calculator of NSEC3 hashes.
+///
+/// This is an abstract base class that defines a simple interface to
+/// calculating NSEC3 hash values as defined in RFC5155.
+///
+/// (Derived classes of) this class is designed to be "stateless" in that it
+/// basically doesn't hold mutable state once constructed, and hash
+/// calculation solely depends on the parameters given on construction and
+/// input to the \c calculate() method. In that sense this could be a
+/// single free function rather than a class, but we decided to provide the
+/// functionality as a class for two reasons: NSEC3 hash calculations would
+/// often take place more than one time in a single query or validation
+/// process, so it would be more efficient if we could hold some internal
+/// resources used for the calculation and reuse it over multiple calls to
+/// \c calculate() (a concrete implementation in this library actually does
+/// this); Second, we may want to customize the hash calculation logic for
+/// testing purposes or for other future extensions. For example, we may
+/// want to use a fake calculator for tests that returns pre-defined hash
+/// values (so a slight change to the test input wouldn't affect the test
+/// result). Using classes from this base would make it possible more
+/// transparently to the application.
+///
+/// A specific derived class instance must be created by the factory method,
+/// \c create().
+///
+/// There can be several ways to extend this class in future. Those include:
+/// - Allow customizing the factory method so the application change the
+/// behavior dynamically.
+/// - Allow to construct the class from a tuple of parameters, that is,
+/// integers for algorithm, iterations and flags, and opaque salt data.
+/// For example, we might want to use that version for validators.
+/// - Allow producing hash value as binary data
+/// - Allow updating NSEC3 parameters of a class object so we can still reuse
+/// the internal resources for different sets of parameters.
+class NSEC3Hash {
+protected:
+ /// \brief The default constructor.
+ ///
+ /// This is defined as protected to prevent this class from being directly
+ /// instantiated even if the class definition is modified (accidentally
+ /// or intentionally) to have no pure virtual methods.
+ NSEC3Hash() {}
+
+public:
+ /// \brief Factory method of NSECHash from NSEC3PARAM RDATA.
+ ///
+ /// The hash algorithm given via \c param must be known to the
+ /// implementation. Otherwise \c UnknownNSEC3HashAlgorithm exception
+ /// will be thrown.
+ ///
+ /// This method creates an \c NSEC3Hash object using \c new. The caller
+ /// is responsible for releasing it with \c delete that is compatible to
+ /// the one used in this library. In practice, the application would
+ /// generally need to store the returned pointer in some form of smart
+ /// pointer; otherwise the resulting code will be quite fragile against
+ /// exceptions (and in this case the application doesn't have to worry
+ /// about explicit \c delete).
+ ///
+ /// \throw UnknownNSEC3HashAlgorithm The specified algorithm in \c param
+ /// is unknown.
+ /// \throw std::bad_alloc Internal resource allocation failure.
+ ///
+ /// \param param NSEC3 parameters used for subsequent calculation.
+ /// \return A pointer to a concrete derived object of \c NSEC3Hash.
+ static NSEC3Hash* create(const rdata::generic::NSEC3PARAM& param);
+
+ /// \brief The destructor.
+ virtual ~NSEC3Hash() {}
+
+ /// \brief Calculate the NSEC3 hash.
+ ///
+ /// This method calculates the NSEC3 hash value for the given \c name
+ /// with the hash parameters (algorithm, iterations and salt) given at
+ /// construction, and returns the value as a base32hex-encoded string
+ /// (without containing any white spaces). All US-ASCII letters in the
+ /// string will be upper cased.
+ ///
+ /// \param name The domain name for which the hash value is to be
+ /// calculated.
+ /// \return Base32hex-encoded string of the hash value.
+ virtual std::string calculate(const Name& name) const = 0;
+};
+
+}
+}
+#endif // __NSEC3HASH_H
+
+// Local Variables:
+// mode: c++
+// End:
diff --git a/src/lib/dns/python/Makefile.am b/src/lib/dns/python/Makefile.am
index dd14991..780b464 100644
--- a/src/lib/dns/python/Makefile.am
+++ b/src/lib/dns/python/Makefile.am
@@ -7,6 +7,7 @@ AM_CXXFLAGS = $(B10_CXXFLAGS)
lib_LTLIBRARIES = libpydnspp.la
libpydnspp_la_SOURCES = pydnspp_common.cc pydnspp_common.h pydnspp_towire.h
libpydnspp_la_SOURCES += name_python.cc name_python.h
+libpydnspp_la_SOURCES += nsec3hash_python.cc nsec3hash_python.h
libpydnspp_la_SOURCES += rrset_python.cc rrset_python.h
libpydnspp_la_SOURCES += rrclass_python.cc rrclass_python.h
libpydnspp_la_SOURCES += rrtype_python.cc rrtype_python.h
@@ -41,6 +42,7 @@ pydnspp_la_LDFLAGS = $(PYTHON_LDFLAGS)
EXTRA_DIST = tsigerror_python_inc.cc
EXTRA_DIST += message_python_inc.cc
+EXTRA_DIST += nsec3hash_python_inc.cc
# Python prefers .so, while some OSes (specifically MacOS) use a different
# suffix for dynamic objects. -module is necessary to work this around.
diff --git a/src/lib/dns/python/nsec3hash_python.cc b/src/lib/dns/python/nsec3hash_python.cc
new file mode 100644
index 0000000..cd97a80
--- /dev/null
+++ b/src/lib/dns/python/nsec3hash_python.cc
@@ -0,0 +1,214 @@
+// 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.
+
+// Enable this if you use s# variants with PyArg_ParseTuple(), see
+// http://docs.python.org/py3k/c-api/arg.html#strings-and-buffers
+//#define PY_SSIZE_T_CLEAN
+
+// Python.h needs to be placed at the head of the program file, see:
+// http://docs.python.org/py3k/extending/extending.html#a-simple-example
+#include <Python.h>
+
+#include <string>
+#include <stdexcept>
+
+#include <util/python/pycppwrapper_util.h>
+
+#include <dns/nsec3hash.h>
+#include <dns/rdataclass.h>
+
+#include "pydnspp_common.h"
+#include "name_python.h"
+#include "nsec3hash_python.h"
+#include "rdata_python.h"
+
+using namespace std;
+using namespace isc::util::python;
+using namespace isc::dns;
+using namespace isc::dns::rdata;
+using namespace isc::dns::python;
+
+// Import pydoc text
+#include "nsec3hash_python_inc.cc"
+
+// Trivial constructor.
+s_NSEC3Hash::s_NSEC3Hash() : cppobj(NULL) {
+}
+
+namespace {
+int
+NSEC3Hash_init(PyObject* po_self, PyObject* args, PyObject*) {
+ s_NSEC3Hash* const self = static_cast<s_NSEC3Hash*>(po_self);
+ try {
+ PyObject* po_rdata;
+ if (PyArg_ParseTuple(args, "O", &po_rdata)) {
+ if (!PyRdata_Check(po_rdata)) {
+ PyErr_Format(PyExc_TypeError,
+ "param must be an Rdata of type NSEC3HASH, "
+ "not %.200s", po_rdata->ob_type->tp_name);
+ return (-1);
+ }
+ self->cppobj = NSEC3Hash::create(
+ dynamic_cast<const generic::NSEC3PARAM&>(
+ PyRdata_ToRdata(po_rdata)));
+ return (0);
+ }
+ } catch (const UnknownNSEC3HashAlgorithm& ex) {
+ PyErr_SetString(po_UnknownNSEC3HashAlgorithm, ex.what());
+ return (-1);
+ } catch (const exception& ex) {
+ const string ex_what = "Failed to construct NSEC3Hash object: " +
+ string(ex.what());
+ PyErr_SetString(po_IscException, ex_what.c_str());
+ return (-1);
+ } catch (...) {
+ PyErr_SetString(PyExc_SystemError, "Unexpected C++ exception");
+ return (-1);
+ }
+
+ return (-1);
+}
+
+void
+NSEC3Hash_destroy(PyObject* po_self) {
+ s_NSEC3Hash* self = static_cast<s_NSEC3Hash*>(po_self);
+ delete self->cppobj;
+ self->cppobj = NULL;
+ Py_TYPE(self)->tp_free(self);
+}
+
+PyObject*
+NSEC3Hash_calculate(PyObject* po_self, PyObject* args) {
+ s_NSEC3Hash* const self = static_cast<s_NSEC3Hash*>(po_self);
+
+ try {
+ PyObject* po_name;
+ if (PyArg_ParseTuple(args, "O", &po_name)) {
+ if (!PyName_Check(po_name)) {
+ PyErr_Format(PyExc_TypeError,
+ "name must be a Name, not %.200s",
+ po_name->ob_type->tp_name);
+ return (NULL);
+ }
+ const string hash =
+ self->cppobj->calculate(PyName_ToName(po_name));
+ return (Py_BuildValue("s", hash.c_str()));
+ }
+ } catch (const exception& ex) {
+ const string ex_what = "Unexpected failure in NSEC3Hash.calculate: " +
+ string(ex.what());
+ PyErr_SetString(po_IscException, ex_what.c_str());
+ return (NULL);
+ } catch (...) {
+ PyErr_SetString(PyExc_SystemError, "Unexpected C++ exception");
+ return (NULL);
+ }
+
+ return (NULL);
+}
+
+// This list contains the actual set of functions we have in
+// python. Each entry has
+// 1. Python method name
+// 2. Our static function here
+// 3. Argument type
+// 4. Documentation
+PyMethodDef NSEC3Hash_methods[] = {
+ { "calculate", NSEC3Hash_calculate, METH_VARARGS, NSEC3Hash_calculate_doc },
+ { NULL, NULL, 0, NULL }
+};
+} // end of unnamed namespace
+
+namespace isc {
+namespace dns {
+namespace python {
+//
+// Declaration of the custom exceptions
+// Initialization and addition of these go in pydnspp.cc
+//
+PyObject* po_UnknownNSEC3HashAlgorithm;
+
+// This defines the complete type for reflection in python and
+// parsing of PyObject* to s_NSEC3Hash
+// Most of the functions are not actually implemented and NULL here.
+PyTypeObject nsec3hash_type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "dns.NSEC3Hash",
+ sizeof(s_NSEC3Hash), // tp_basicsize
+ 0, // tp_itemsize
+ NSEC3Hash_destroy, // tp_dealloc
+ NULL, // tp_print
+ NULL, // tp_getattr
+ NULL, // tp_setattr
+ NULL, // tp_reserved
+ NULL, // tp_repr
+ NULL, // tp_as_number
+ NULL, // tp_as_sequence
+ NULL, // tp_as_mapping
+ NULL, // tp_hash
+ NULL, // tp_call
+ NULL, // tp_str
+ NULL, // tp_getattro
+ NULL, // tp_setattro
+ NULL, // tp_as_buffer
+ Py_TPFLAGS_DEFAULT, // tp_flags
+ NSEC3Hash_doc,
+ NULL, // tp_traverse
+ NULL, // tp_clear
+ NULL, // tp_richcompare
+ 0, // tp_weaklistoffset
+ NULL, // tp_iter
+ NULL, // tp_iternext
+ NSEC3Hash_methods, // tp_methods
+ NULL, // tp_members
+ NULL, // tp_getset
+ NULL, // tp_base
+ NULL, // tp_dict
+ NULL, // tp_descr_get
+ NULL, // tp_descr_set
+ 0, // tp_dictoffset
+ NSEC3Hash_init, // tp_init
+ NULL, // tp_alloc
+ PyType_GenericNew, // tp_new
+ NULL, // tp_free
+ NULL, // tp_is_gc
+ NULL, // tp_bases
+ NULL, // tp_mro
+ NULL, // tp_cache
+ NULL, // tp_subclasses
+ NULL, // tp_weaklist
+ NULL, // tp_del
+ 0 // tp_version_tag
+};
+
+// Module Initialization, all statics (nothing right now) are initialized here
+bool
+initModulePart_NSEC3Hash(PyObject* mod) {
+ // We initialize the static description object with PyType_Ready(),
+ // then add it to the module. This is not just a check! (leaving
+ // this out results in segmentation faults)
+ if (PyType_Ready(&nsec3hash_type) < 0) {
+ return (false);
+ }
+ void* p = &nsec3hash_type;
+ if (PyModule_AddObject(mod, "NSEC3Hash", static_cast<PyObject*>(p)) < 0) {
+ return (false);
+ }
+ Py_INCREF(&nsec3hash_type);
+
+ return (true);
+}
+} // namespace python
+} // namespace dns
+} // namespace isc
diff --git a/src/lib/dns/python/nsec3hash_python.h b/src/lib/dns/python/nsec3hash_python.h
new file mode 100644
index 0000000..fa9b9b6
--- /dev/null
+++ b/src/lib/dns/python/nsec3hash_python.h
@@ -0,0 +1,47 @@
+// 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 __PYTHON_NSEC3HASH_H
+#define __PYTHON_NSEC3HASH_H 1
+
+#include <Python.h>
+
+namespace isc {
+namespace dns {
+class NSEC3Hash;
+
+namespace python {
+
+// The s_* Class simply covers one instantiation of the object
+class s_NSEC3Hash : public PyObject {
+public:
+ s_NSEC3Hash();
+ NSEC3Hash* cppobj;
+};
+
+extern PyTypeObject nsec3hash_type;
+
+// Public exception object.
+extern PyObject* po_UnknownNSEC3HashAlgorithm;
+
+bool initModulePart_NSEC3Hash(PyObject* mod);
+
+} // namespace python
+} // namespace dns
+} // namespace isc
+#endif // __PYTHON_NSEC3HASH_H
+
+// Local Variables:
+// mode: c++
+// End:
diff --git a/src/lib/dns/python/nsec3hash_python_inc.cc b/src/lib/dns/python/nsec3hash_python_inc.cc
new file mode 100644
index 0000000..9e8640f
--- /dev/null
+++ b/src/lib/dns/python/nsec3hash_python_inc.cc
@@ -0,0 +1,45 @@
+namespace {
+// Modifications
+// - removed intermediate details note, mainly for brevity
+// - removed std::bad_alloc
+const char* const NSEC3Hash_doc = "\
+A calculator of NSEC3 hashes.\n\
+\n\
+This is a simple class that encapsulates the algorithm of calculating\n\
+NSEC3 hash values as defined in RFC5155.\n\
+\n\
+NSEC3Hash(param)\n\
+\n\
+ Constructor from NSEC3PARAM RDATA.\n\
+\n\
+ The hash algorithm given via param must be known to the\n\
+ implementation. Otherwise UnknownNSEC3HashAlgorithm exception will\n\
+ be thrown.\n\
+\n\
+ Exceptions:\n\
+ UnknownNSEC3HashAlgorithm The specified algorithm in param is\n\
+ unknown.\n\
+\n\
+ Parameters:\n\
+ param NSEC3 parameters used for subsequent calculation.\n\
+\n\
+";
+
+const char* const NSEC3Hash_calculate_doc = "\
+calculate(Name) -> string\n\
+\n\
+Calculate the NSEC3 hash.\n\
+\n\
+This method calculates the NSEC3 hash value for the given name with\n\
+the hash parameters (algorithm, iterations and salt) given at\n\
+construction, and returns the value in a base32hex-encoded string\n\
+(without containing any white spaces). All US-ASCII letters in the\n\
+string will be upper cased.\n\
+\n\
+Parameters:\n\
+ name The domain name for which the hash value is to be\n\
+ calculated.\n\
+\n\
+Return Value(s): Base32hex-encoded string of the hash value.\n\
+";
+} // unnamed namespace
diff --git a/src/lib/dns/python/pydnspp.cc b/src/lib/dns/python/pydnspp.cc
index 212141c..64e3cae 100644
--- a/src/lib/dns/python/pydnspp.cc
+++ b/src/lib/dns/python/pydnspp.cc
@@ -39,6 +39,7 @@
#include "message_python.h"
#include "messagerenderer_python.h"
#include "name_python.h"
+#include "nsec3hash_python.h"
#include "opcode_python.h"
#include "pydnspp_common.h"
#include "pydnspp_towire.h"
@@ -164,6 +165,10 @@ initModulePart_Message(PyObject* mod) {
PyErr_NewException("pydnspp.DNSMessageBADVERS", NULL, NULL);
PyObjectContainer(po_DNSMessageBADVERS).installToModule(
mod, "DNSMessageBADVERS");
+ po_UnknownNSEC3HashAlgorithm =
+ PyErr_NewException("pydnspp.UnknownNSEC3HashAlgorithm", NULL, NULL);
+ PyObjectContainer(po_UnknownNSEC3HashAlgorithm).installToModule(
+ mod, "UnknownNSEC3HashAlgorithm");
} catch (const std::exception& ex) {
const std::string ex_what =
"Unexpected failure in Message initialization: " +
@@ -777,6 +782,10 @@ PyInit_pydnspp(void) {
return (NULL);
}
+ if (!initModulePart_NSEC3Hash(mod)) {
+ return (NULL);
+ }
+
if (!initModulePart_RRClass(mod)) {
return (NULL);
}
diff --git a/src/lib/dns/python/tests/Makefile.am b/src/lib/dns/python/tests/Makefile.am
index 3338727..4b0ea9f 100644
--- a/src/lib/dns/python/tests/Makefile.am
+++ b/src/lib/dns/python/tests/Makefile.am
@@ -3,6 +3,7 @@ PYTESTS = edns_python_test.py
PYTESTS += message_python_test.py
PYTESTS += messagerenderer_python_test.py
PYTESTS += name_python_test.py
+PYTESTS += nsec3hash_python_test.py
PYTESTS += question_python_test.py
PYTESTS += opcode_python_test.py
PYTESTS += rcode_python_test.py
diff --git a/src/lib/dns/python/tests/nsec3hash_python_test.py b/src/lib/dns/python/tests/nsec3hash_python_test.py
new file mode 100644
index 0000000..41b163e
--- /dev/null
+++ b/src/lib/dns/python/tests/nsec3hash_python_test.py
@@ -0,0 +1,77 @@
+# Copyright (C) 2012 Internet Systems Consortium.
+#
+# Permission to use, copy, modify, and 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 INTERNET SYSTEMS CONSORTIUM
+# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+# INTERNET SYSTEMS CONSORTIUM 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.
+
+import unittest
+from pydnspp import *
+
+class NSEC3HashTest(unittest.TestCase):
+ '''These tests are mostly straightforward conversion of C++ tests
+ except for python specific type checks.
+
+ '''
+
+ def setUp(self):
+ self.test_hash = NSEC3Hash(Rdata(RRType.NSEC3PARAM(), RRClass.IN(),
+ "1 0 12 aabbccdd"))
+
+ def test_bad_construct(self):
+ # missing parameter
+ self.assertRaises(TypeError, NSEC3Hash)
+
+ # invalid type of argument
+ self.assertRaises(TypeError, NSEC3Hash, "1 0 12 aabbccdd")
+
+ # additional parameter
+ self.assertRaises(TypeError, NSEC3Hash, Rdata(RRType.NSEC3PARAM(),
+ RRClass.IN(),
+ "1 0 12 aabbccdd"), 1)
+
+ def test_unknown_algorithm(self):
+ self.assertRaises(UnknownNSEC3HashAlgorithm, NSEC3Hash,
+ Rdata(RRType.NSEC3PARAM(), RRClass.IN(),
+ "2 0 12 aabbccdd"))
+
+ def test_calculate(self):
+ # A couple of normal cases from the RFC5155 example.
+ self.assertEqual("0P9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM",
+ self.test_hash.calculate(Name("example")))
+ self.assertEqual("35MTHGPGCU1QG68FAB165KLNSNK3DPVL",
+ self.test_hash.calculate(Name("a.example")))
+
+ # Check case-insensitiveness
+ self.assertEqual("0P9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM",
+ self.test_hash.calculate(Name("EXAMPLE")))
+
+ # Some boundary cases: 0-iteration and empty salt. Borrowed from the
+ # .com zone data.
+ self.test_hash = NSEC3Hash(Rdata(RRType.NSEC3PARAM(),
+ RRClass.IN(),"1 0 0 -"))
+ self.assertEqual("CK0POJMG874LJREF7EFN8430QVIT8BSM",
+ self.test_hash.calculate(Name("com")))
+
+ # Using unusually large iterations, something larger than the 8-bit
+ #range. (expected hash value generated by BIND 9's dnssec-signzone)
+ self.test_hash = NSEC3Hash(Rdata(RRType.NSEC3PARAM(),
+ RRClass.IN(), "1 0 256 AABBCCDD"))
+ self.assertEqual("COG6A52MJ96MNMV3QUCAGGCO0RHCC2Q3",
+ self.test_hash.calculate(Name("example.org")))
+
+ def test_calculate_badparam(self):
+ self.assertRaises(TypeError, self.test_hash.calculate, "example")
+ self.assertRaises(TypeError, self.test_hash.calculate)
+ self.assertRaises(TypeError, self.test_hash.calculate, Name("."), 1)
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/src/lib/dns/rdata/generic/nsec3param_51.cc b/src/lib/dns/rdata/generic/nsec3param_51.cc
index 49f666b..850be14 100644
--- a/src/lib/dns/rdata/generic/nsec3param_51.cc
+++ b/src/lib/dns/rdata/generic/nsec3param_51.cc
@@ -67,8 +67,11 @@ NSEC3PARAM::NSEC3PARAM(const string& nsec3param_str) :
isc_throw(InvalidRdataText, "NSEC3PARAM flags out of range");
}
+ const string salt_str = saltbuf.str();
vector<uint8_t> salt;
- decodeHex(saltbuf.str(), salt);
+ if (salt_str != "-") { // "-" means an empty salt, no need to touch vector
+ decodeHex(saltbuf.str(), salt);
+ }
impl_ = new NSEC3PARAMImpl(hashalg, flags, iterations, salt);
}
diff --git a/src/lib/dns/tests/Makefile.am b/src/lib/dns/tests/Makefile.am
index cfd1286..7f7ab59 100644
--- a/src/lib/dns/tests/Makefile.am
+++ b/src/lib/dns/tests/Makefile.am
@@ -21,6 +21,7 @@ run_unittests_SOURCES = unittest_util.h unittest_util.cc
run_unittests_SOURCES += edns_unittest.cc
run_unittests_SOURCES += messagerenderer_unittest.cc
run_unittests_SOURCES += name_unittest.cc
+run_unittests_SOURCES += nsec3hash_unittest.cc
run_unittests_SOURCES += rrclass_unittest.cc rrtype_unittest.cc
run_unittests_SOURCES += rrttl_unittest.cc
run_unittests_SOURCES += opcode_unittest.cc
diff --git a/src/lib/dns/tests/nsec3hash_unittest.cc b/src/lib/dns/tests/nsec3hash_unittest.cc
new file mode 100644
index 0000000..c0fc9d9
--- /dev/null
+++ b/src/lib/dns/tests/nsec3hash_unittest.cc
@@ -0,0 +1,73 @@
+// 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 <gtest/gtest.h>
+
+#include <boost/scoped_ptr.hpp>
+
+#include <dns/nsec3hash.h>
+#include <dns/rdataclass.h>
+
+using boost::scoped_ptr;
+using namespace isc::dns;
+using namespace isc::dns::rdata;
+
+namespace {
+typedef scoped_ptr<NSEC3Hash> NSEC3HashPtr;
+
+class NSEC3HashTest : public ::testing::Test {
+protected:
+ NSEC3HashTest() :
+ test_hash(NSEC3Hash::create(generic::NSEC3PARAM("1 0 12 aabbccdd")))
+ {}
+
+ // An NSEC3Hash object commonly used in tests. Parameters are borrowed
+ // from the RFC5155 example. Construction of this object implicitly
+ // checks a successful case of the creation.
+ NSEC3HashPtr test_hash;
+};
+
+TEST_F(NSEC3HashTest, unknownAlgorithm) {
+ EXPECT_THROW(NSEC3HashPtr(
+ NSEC3Hash::create(
+ generic::NSEC3PARAM("2 0 12 aabbccdd"))),
+ UnknownNSEC3HashAlgorithm);
+}
+
+TEST_F(NSEC3HashTest, calculate) {
+ // A couple of normal cases from the RFC5155 example.
+ EXPECT_EQ("0P9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM",
+ test_hash->calculate(Name("example")));
+ EXPECT_EQ("35MTHGPGCU1QG68FAB165KLNSNK3DPVL",
+ test_hash->calculate(Name("a.example")));
+
+ // Check case-insensitiveness
+ EXPECT_EQ("0P9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM",
+ test_hash->calculate(Name("EXAMPLE")));
+
+ // Some boundary cases: 0-iteration and empty salt. Borrowed from the
+ // .com zone data.
+ EXPECT_EQ("CK0POJMG874LJREF7EFN8430QVIT8BSM",
+ NSEC3HashPtr(NSEC3Hash::create(generic::NSEC3PARAM("1 0 0 -")))
+ ->calculate(Name("com")));
+
+ // Using unusually large iterations, something larger than the 8-bit range.
+ // (expected hash value generated by BIND 9's dnssec-signzone)
+ EXPECT_EQ("COG6A52MJ96MNMV3QUCAGGCO0RHCC2Q3",
+ NSEC3HashPtr(NSEC3Hash::create(
+ generic::NSEC3PARAM("1 0 256 AABBCCDD")))
+ ->calculate(Name("example.org")));
+}
+
+} // end namespace
diff --git a/src/lib/dns/tests/rdata_nsec3param_unittest.cc b/src/lib/dns/tests/rdata_nsec3param_unittest.cc
index 8d802d6..bcbc0d7 100644
--- a/src/lib/dns/tests/rdata_nsec3param_unittest.cc
+++ b/src/lib/dns/tests/rdata_nsec3param_unittest.cc
@@ -40,9 +40,20 @@ using namespace isc::dns::rdata;
namespace {
class Rdata_NSEC3PARAM_Test : public RdataTest {
- // there's nothing to specialize
+public:
+ Rdata_NSEC3PARAM_Test() : nsec3param_txt("1 0 1 D399EAAB") {}
+ const string nsec3param_txt;
};
-string nsec3param_txt("1 0 1 D399EAAB");
+
+TEST_F(Rdata_NSEC3PARAM_Test, fromText) {
+ // With a salt
+ EXPECT_EQ(1, generic::NSEC3PARAM(nsec3param_txt).getHashalg());
+ EXPECT_EQ(0, generic::NSEC3PARAM(nsec3param_txt).getFlags());
+ // (salt is checked in the toText test)
+
+ // With an empty salt
+ EXPECT_EQ(0, generic::NSEC3PARAM("1 0 0 -").getSalt().size());
+}
TEST_F(Rdata_NSEC3PARAM_Test, toText) {
const generic::NSEC3PARAM rdata_nsec3param(nsec3param_txt);
diff --git a/src/lib/util/python/wrapper_template.cc b/src/lib/util/python/wrapper_template.cc
index 1a67a88..780e695 100644
--- a/src/lib/util/python/wrapper_template.cc
+++ b/src/lib/util/python/wrapper_template.cc
@@ -33,14 +33,6 @@ using namespace isc::@MODULE@;
using namespace isc::@MODULE@::python;
//
-// Definition of the classes
-//
-
-// For each class, we need a struct, a helper functions (init, destroy,
-// and static wrappers around the methods we export), a list of methods,
-// and a type description
-
-//
// @CPPCLASS@
//
@@ -52,6 +44,7 @@ namespace {
// Shortcut type which would be convenient for adding class variables safely.
typedef CPPPyObjectContainer<s_ at CPPCLASS@, @CPPCLASS@> @CPPCLASS at Container;
+ at REMOVE_THIS_ON_RELEASE@
// This is a template of typical code logic of python class initialization
// with C++ backend. You'll need to adjust it according to details of the
// actual C++ class.
@@ -60,6 +53,7 @@ int
s_ at CPPCLASS@* self = static_cast<s_ at CPPCLASS@*>(po_self);
try {
if (PyArg_ParseTuple(args, "REPLACE ME")) {
+ @REMOVE_THIS_ON_RELEASE@
// YOU'LL NEED SOME VALIDATION, PREPARATION, ETC, HERE.
self->cppobj = new @CPPCLASS@(/*NECESSARY PARAMS*/);
return (0);
@@ -74,6 +68,7 @@ int
return (-1);
}
+ @REMOVE_THIS_ON_RELEASE@
// If we are here PyArg_ParseTuple() failed and TypeError should have
// been set. If the constructor is more complicated and the control
// could reach this point for other reasons, an appropriate Python
@@ -82,6 +77,7 @@ int
return (-1);
}
+ at REMOVE_THIS_ON_RELEASE@
// This is a template of typical code logic of python object destructor.
// In many cases you can use it without modification, but check that carefully.
void
@@ -92,6 +88,7 @@ void
Py_TYPE(self)->tp_free(self);
}
+ at REMOVE_THIS_ON_RELEASE@
// This should be able to be used without modification as long as the
// underlying C++ class has toText().
PyObject*
@@ -119,6 +116,7 @@ PyObject*
const_cast<char*>("")));
}
+ at REMOVE_THIS_ON_RELEASE@
// This is quite specific isc.dns. For other wrappers this should probably
// be removed.
PyObject* @CPPCLASS at _toWire(PyObject* self, PyObject* args) {
@@ -175,6 +173,8 @@ PyObject*
PyMethodDef @CPPCLASS at _methods[] = {
{ "to_text", @CPPCLASS at _toText, METH_NOARGS,
@CPPCLASS at _toText_doc },
+
+ @REMOVE_THIS_ON_RELEASE@
// This is quite specific isc.dns. For other wrappers this should probably
// be removed:
{ "to_wire", @CPPCLASS at _toWire, METH_VARARGS,
@@ -256,6 +256,7 @@ initModulePart_ at CPPCLASS@(PyObject* mod) {
}
Py_INCREF(&@cppclass at _type);
+ @REMOVE_THIS_ON_RELEASE@
// The following template is the typical procedure for installing class
// variables. If the class doesn't have a class variable, remove the
// entire try-catch clauses.
More information about the bind10-changes
mailing list