Commit 2c421b58 authored by JINMEI Tatuya's avatar JINMEI Tatuya
Browse files

[master] Merge branch 'trac1575'

parents 789a5935 80a2fbfd
......@@ -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
......
// 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
// 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:
......@@ -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.
......
// 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
// 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:
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
......@@ -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);
}