Commit 08796619 authored by JINMEI Tatuya's avatar JINMEI Tatuya
Browse files

[1575] added python binding of NSEC3Hash.

parent 9a6b7baf
......@@ -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 {
// 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.
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_SetString(PyExc_TypeError,
"function must be given NSEC3HASH Rdata");
return (-1);
}
self->cppobj = new NSEC3Hash(
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_SetString(PyExc_TypeError,
"function must be given Name object");
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 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 alphabets in the string\n\
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);
}
if (!initModulePart_NSEC3Hash(mod)) {
return (NULL);
}
if (!initModulePart_RRClass(mod)) {
return (NULL);
}
......
......@@ -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
......
# 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()
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment