mirror of
https://gitlab.isc.org/isc-projects/kea
synced 2025-08-31 05:55:28 +00:00
imoprted Francis's python binding code
git-svn-id: svn://bind10.isc.org/svn/bind10/experiments/python-binding@1671 e5f2f494-b856-4b98-b285-d166d9295462
This commit is contained in:
@@ -373,6 +373,7 @@ AC_CONFIG_FILES([Makefile
|
||||
src/lib/config/tests/Makefile
|
||||
src/lib/dns/Makefile
|
||||
src/lib/dns/tests/Makefile
|
||||
src/lib/dns-python/Makefile
|
||||
src/lib/exceptions/Makefile
|
||||
src/lib/auth/Makefile
|
||||
src/lib/auth/tests/Makefile
|
||||
|
@@ -1,4 +1,4 @@
|
||||
SUBDIRS = exceptions dns cc config auth python
|
||||
SUBDIRS = exceptions dns cc config auth dns-python python
|
||||
if HAVE_BOOST_PYTHON
|
||||
if HAVE_BOOST_SYSTEM
|
||||
SUBDIRS += xfr
|
||||
|
15
src/lib/dns-python/Makefile.am
Normal file
15
src/lib/dns-python/Makefile.am
Normal file
@@ -0,0 +1,15 @@
|
||||
AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
|
||||
if GCC_WERROR_OK
|
||||
AM_CPPFLAGS += -Werror
|
||||
endif
|
||||
|
||||
pyexec_LTLIBRARIES = bind10_dns_noboost.la
|
||||
bind10_dns_noboost_la_SOURCES = cpp_binding.cc
|
||||
bind10_dns_noboost_la_CPPFLAGS = $(AM_CPPFLAGS) $(PYTHON_INCLUDES)
|
||||
bind10_dns_noboost_la_LDFLAGS = $(PYTHON_LDFLAGS)
|
||||
# Python prefers .so, while some OSes (specifically MacOS) use a different
|
||||
# suffix for dynamic objects. -module is necessary to work this around.
|
||||
bind10_dns_noboost_la_LDFLAGS += -module
|
||||
bind10_dns_noboost_la_LIBADD = $(top_builddir)/src/lib/dns/libdns.la
|
||||
bind10_dns_noboost_la_LIBADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
|
||||
bind10_dns_noboost_la_LIBADD += $(PYTHON_LIB)
|
768
src/lib/dns-python/cpp_binding.cc
Normal file
768
src/lib/dns-python/cpp_binding.cc
Normal file
@@ -0,0 +1,768 @@
|
||||
// Copyright (C) 2010 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.
|
||||
|
||||
// $Id$
|
||||
|
||||
/* isc::dns::Name Python bindings */
|
||||
|
||||
#define PY_SSIZE_T_CLEAN
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <Python.h>
|
||||
#include <structmember.h>
|
||||
|
||||
#include <exceptions/exceptions.h>
|
||||
|
||||
#include <dns/buffer.h>
|
||||
#include <dns/exceptions.h>
|
||||
#include <dns/name.h>
|
||||
#include <dns/messagerenderer.h>
|
||||
|
||||
#include <cassert>
|
||||
|
||||
using isc::OutOfRange;
|
||||
using isc::dns::DNSMessageFORMERR;
|
||||
using isc::dns::InvalidBufferPosition;
|
||||
using isc::dns::InputBuffer;
|
||||
using isc::dns::OutputBuffer;
|
||||
using isc::dns::EmptyLabel;
|
||||
using isc::dns::TooLongName;
|
||||
using isc::dns::TooLongLabel;
|
||||
using isc::dns::BadLabelType;
|
||||
using isc::dns::BadEscape;
|
||||
using isc::dns::IncompleteName;
|
||||
using isc::dns::NameComparisonResult;
|
||||
using isc::dns::Name;
|
||||
using isc::dns::MessageRenderer;
|
||||
|
||||
static PyObject *cName_Exception;
|
||||
static PyObject *cName_Relation;
|
||||
static PyObject *cName_MAX_WIRE;
|
||||
static PyObject *cName_MAX_LABELS;
|
||||
static PyObject *cName_MAX_LABELLEN;
|
||||
static PyObject *cName_MAX_COMPRESS_POINTER;
|
||||
static PyObject *cName_COMPRESS_POINTER_MARK8;
|
||||
static PyObject *cName_COMPRESS_POINTER_MARK16;
|
||||
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
NameComparisonResult *ncr;
|
||||
} cNCR;
|
||||
|
||||
static void cNCR_dealloc(cNCR *self);
|
||||
static int cNCR_init(cNCR *self, PyObject *args);
|
||||
static PyObject *cNCR_getOrder(cNCR *self);
|
||||
static PyObject *cNCR_getCommonLabels(cNCR *self);
|
||||
static PyObject *cNCR_getRelation(cNCR *self);
|
||||
|
||||
static PyMethodDef cNCR_Methods[] = {
|
||||
{ "getOrder", (PyCFunction)cNCR_getOrder, METH_NOARGS,
|
||||
"Return the ordering of the comparison result" },
|
||||
{ "getCommonLabels", (PyCFunction)cNCR_getCommonLabels, METH_NOARGS,
|
||||
"Return the number of common labels of the comparison result" },
|
||||
{ "getRelation", (PyCFunction)cNCR_getRelation, METH_NOARGS,
|
||||
"Return the NameRelation of the comparison result" },
|
||||
{ NULL, NULL, 0, NULL }
|
||||
};
|
||||
|
||||
static PyTypeObject cNCR_Type = {
|
||||
PyVarObject_HEAD_INIT(NULL, 0)
|
||||
"bind10_dns_noboost.cNameComparisonResult", /* tp_name */
|
||||
sizeof(cNCR), /* tp_basicsize */
|
||||
0, /* tp_itemsize */
|
||||
(destructor)cNCR_dealloc, /* 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 */
|
||||
"C++ NameComparisonResult Object", /* tp_doc */
|
||||
NULL, /* tp_traverse */
|
||||
NULL, /* tp_clear */
|
||||
NULL, /* tp_richcompare */
|
||||
0, /* tp_weaklistoffset */
|
||||
NULL, /* tp_iter */
|
||||
NULL, /* tp_iternext */
|
||||
cNCR_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 */
|
||||
(initproc)cNCR_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 */
|
||||
// Note: not sure if the following are correct. Added them just to
|
||||
// make the compiler happy.
|
||||
NULL, /* tp_del */
|
||||
0 /* tp_version_tag */
|
||||
};
|
||||
|
||||
static void
|
||||
cNCR_dealloc(cNCR *self) {
|
||||
if (self->ncr != NULL)
|
||||
delete self->ncr;
|
||||
self->ncr = NULL;
|
||||
Py_TYPE(self)->tp_free(self);
|
||||
}
|
||||
|
||||
static int
|
||||
cNCR_init(cNCR *self UNUSED_PARAM, PyObject *args UNUSED_PARAM) {
|
||||
PyErr_SetString(PyExc_NotImplementedError,
|
||||
"cNameComparisonResult can't be built");
|
||||
return -1;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
cNCR_getOrder(cNCR *self) {
|
||||
return Py_BuildValue("i", self->ncr->getOrder());
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
cNCR_getCommonLabels(cNCR *self) {
|
||||
return Py_BuildValue("I", self->ncr->getCommonLabels());
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
cNCR_getRelation(cNCR *self) {
|
||||
return Py_BuildValue("i", (int) self->ncr->getRelation());
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
Name *name;
|
||||
size_t position;
|
||||
} cName;
|
||||
|
||||
static void cName_dealloc(cName *self);
|
||||
static int cName_init(cName *self, PyObject *args);
|
||||
static PyObject *cName_getLength(cName *self);
|
||||
static PyObject *cName_getLabelCount(cName *self);
|
||||
static PyObject *cName_toText(cName *self, PyObject *args);
|
||||
static PyObject *cName_toWire(cName *self, PyObject *args);
|
||||
static PyObject *cName_compare(cName *self, PyObject *args);
|
||||
static PyObject *cName_equals(cName *self, PyObject *args);
|
||||
static PyObject *cName_nequals(cName *self, PyObject *args);
|
||||
static PyObject *cName_richcmp(cName *n1, cName *n2, int op);
|
||||
static PyObject *cName_split(cName *self, PyObject *args);
|
||||
static PyObject *cName_concatenate(cName *self, PyObject *args);
|
||||
static PyObject *cName_downcase(cName *self);
|
||||
static PyObject *cName_isWildcard(cName *self);
|
||||
static PyObject *cName_getPosition(cName *self);
|
||||
static PyObject *cName_clone(cName *self, PyObject *args);
|
||||
|
||||
static PyMethodDef cName_Methods[] = {
|
||||
{ "getLength", (PyCFunction)cName_getLength, METH_NOARGS,
|
||||
"Return the length of the Name" },
|
||||
{ "getLabelCount", (PyCFunction)cName_getLabelCount, METH_NOARGS,
|
||||
"Return the number of labels" },
|
||||
{ "toText", (PyCFunction)cName_toText, METH_VARARGS,
|
||||
"Convert the Name to a string" },
|
||||
{ "toWire", (PyCFunction)cName_toWire, METH_VARARGS,
|
||||
"Render the Name in the wire format" },
|
||||
{ "compare", (PyCFunction)cName_compare, METH_VARARGS,
|
||||
"Compare two Names" },
|
||||
{ "equals", (PyCFunction)cName_equals, METH_VARARGS,
|
||||
"Return true iff two Names are equal" },
|
||||
{ "nequals", (PyCFunction)cName_nequals, METH_VARARGS,
|
||||
"Return true iff two Names are not equal" },
|
||||
{ "split", (PyCFunction)cName_split, METH_VARARGS,
|
||||
"Extract a specified subpart of Name" },
|
||||
{ "concatenate", (PyCFunction)cName_concatenate, METH_VARARGS,
|
||||
"Concatenate two Names" },
|
||||
{ "downcase", (PyCFunction)cName_downcase, METH_NOARGS,
|
||||
"Downcase the calling object" },
|
||||
{ "isWildcard", (PyCFunction)cName_isWildcard, METH_NOARGS,
|
||||
"Test if this is a wildcard Name" },
|
||||
{ "getPosition", (PyCFunction)cName_getPosition, METH_NOARGS,
|
||||
"Return the end position in the wire buffer" },
|
||||
{ "clone", (PyCFunction)cName_clone, METH_NOARGS,
|
||||
"Clone a Name" },
|
||||
{ NULL, NULL, 0, NULL }
|
||||
};
|
||||
|
||||
static PyTypeObject cName_Type = {
|
||||
PyVarObject_HEAD_INIT(NULL, 0)
|
||||
"bind10_dns_noboost.cName", /* tp_name */
|
||||
sizeof(cName), /* tp_basicsize */
|
||||
0, /* tp_itemsize */
|
||||
(destructor)cName_dealloc, /* 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|Py_TPFLAGS_BASETYPE, /* tp_flags */
|
||||
"C++ Name Object", /* tp_doc */
|
||||
NULL, /* tp_traverse */
|
||||
NULL, /* tp_clear */
|
||||
(richcmpfunc)cName_richcmp, /* tp_richcompare */
|
||||
0, /* tp_weaklistoffset */
|
||||
NULL, /* tp_iter */
|
||||
NULL, /* tp_iternext */
|
||||
cName_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 */
|
||||
(initproc)cName_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 */
|
||||
// Note: not sure if the following are correct. Added them just to
|
||||
// make the compiler happy.
|
||||
NULL, /* tp_del */
|
||||
0 /* tp_version_tag */
|
||||
};
|
||||
|
||||
static void
|
||||
cName_dealloc(cName *self) {
|
||||
if (self->name != NULL)
|
||||
delete self->name;
|
||||
self->name = NULL;
|
||||
Py_TYPE(self)->tp_free(self);
|
||||
}
|
||||
|
||||
static int
|
||||
cName_init(cName *self, PyObject *args) {
|
||||
const char *s;
|
||||
PyObject *downcase = Py_False;
|
||||
|
||||
/* fromText */
|
||||
if (PyArg_ParseTuple(args, "s|O!", &s, &PyBool_Type, &downcase)) {
|
||||
try {
|
||||
const std::string n(s);
|
||||
|
||||
self->name = new Name(n, downcase == Py_True);
|
||||
self->position = 0;
|
||||
} catch (EmptyLabel) {
|
||||
PyErr_SetString(cName_Exception, "EmptyLabel");
|
||||
return -1;
|
||||
} catch (TooLongLabel) {
|
||||
PyErr_SetString(cName_Exception, "TooLongLabel");
|
||||
return -1;
|
||||
} catch (BadLabelType) {
|
||||
PyErr_SetString(cName_Exception, "BadLabelType");
|
||||
return -1;
|
||||
} catch (BadEscape) {
|
||||
PyErr_SetString(cName_Exception, "BadEscape");
|
||||
return -1;
|
||||
} catch (TooLongName) {
|
||||
PyErr_SetString(cName_Exception, "TooLongName");
|
||||
return -1;
|
||||
} catch (IncompleteName) {
|
||||
PyErr_SetString(cName_Exception, "IncompleteName");
|
||||
return -1;
|
||||
#ifdef CATCHMEMERR
|
||||
} catch (std::bad_alloc) {
|
||||
PyErr_NoMemory();
|
||||
return -1;
|
||||
#endif
|
||||
} catch (...) {
|
||||
PyErr_SetString(cName_Exception, "Unexpected?!");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
PyErr_Clear();
|
||||
|
||||
const char *b;
|
||||
Py_ssize_t len;
|
||||
unsigned int position;
|
||||
|
||||
/* fromWire */
|
||||
if (PyArg_ParseTuple(args, "y#I|O!", &b, &len, &position,
|
||||
&PyBool_Type, &downcase)) {
|
||||
try {
|
||||
InputBuffer buffer(b, len);
|
||||
|
||||
buffer.setPosition(position);
|
||||
self->name = new Name(buffer, downcase == Py_True);
|
||||
self->position = buffer.getPosition();
|
||||
} catch (InvalidBufferPosition) {
|
||||
PyErr_SetString(cName_Exception,
|
||||
"InvalidBufferPosition");
|
||||
return -1;
|
||||
} catch (TooLongName) {
|
||||
PyErr_SetString(cName_Exception, "TooLongName");
|
||||
return -1;
|
||||
} catch (BadLabelType) {
|
||||
PyErr_SetString(cName_Exception, "BadLabelType");
|
||||
return -1;
|
||||
} catch (DNSMessageFORMERR) {
|
||||
PyErr_SetString(cName_Exception, "DNSMessageFORMERR");
|
||||
return -1;
|
||||
} catch (IncompleteName) {
|
||||
PyErr_SetString(cName_Exception, "IncompleteName");
|
||||
return -1;
|
||||
#ifdef CATCHMEMERR
|
||||
} catch (std::bad_alloc) {
|
||||
PyErr_NoMemory();
|
||||
return -1;
|
||||
#endif
|
||||
} catch (...) {
|
||||
PyErr_SetString(cName_Exception, "Unexpected?!");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
PyErr_Clear();
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"fromText and fromWire Name constructors don't match");
|
||||
return -1;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
cName_getLength(cName *self) {
|
||||
return Py_BuildValue("I", (unsigned int) self->name->getLength());
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
cName_getLabelCount(cName *self) {
|
||||
return Py_BuildValue("I", self->name->getLabelCount());
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
cName_toText(cName *self, PyObject *args) {
|
||||
PyObject *omit = Py_False;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "|O!", &PyBool_Type, &omit))
|
||||
return NULL;
|
||||
|
||||
try {
|
||||
std::string s = self->name->toText(omit == Py_True);
|
||||
|
||||
return Py_BuildValue("s", s.c_str());
|
||||
} catch (BadLabelType) {
|
||||
PyErr_SetString(cName_Exception, "BadLabelType");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
cName_toWire(cName *self, PyObject *args) {
|
||||
if (!PyArg_ParseTuple(args, ""))
|
||||
return NULL;
|
||||
|
||||
OutputBuffer buffer(255);
|
||||
|
||||
self->name->toWire(buffer);
|
||||
return Py_BuildValue("y#", buffer.getData(),
|
||||
(Py_ssize_t) buffer.getLength());
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
cName_compare(cName *self, PyObject *args) {
|
||||
cName *other;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "O!", &cName_Type, (PyObject **) &other))
|
||||
return NULL;
|
||||
|
||||
cNCR *ret = PyObject_New(cNCR, &cNCR_Type);
|
||||
if (ret != NULL) {
|
||||
ret->ncr = new NameComparisonResult(
|
||||
self->name->compare(*other->name));
|
||||
if (ret->ncr == NULL) {
|
||||
Py_DECREF(ret);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
return (PyObject *) ret;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
cName_equals(cName *self, PyObject *args) {
|
||||
cName *other;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "O!", &cName_Type, (PyObject **) &other))
|
||||
return NULL;
|
||||
|
||||
if (self->name->equals(*other->name))
|
||||
Py_RETURN_TRUE;
|
||||
else
|
||||
Py_RETURN_FALSE;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
cName_nequals(cName *self, PyObject *args) {
|
||||
cName *other;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "O!", &cName_Type, (PyObject **) &other))
|
||||
return NULL;
|
||||
|
||||
if (self->name->nequals(*other->name))
|
||||
Py_RETURN_TRUE;
|
||||
else
|
||||
Py_RETURN_FALSE;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
cName_richcmp(cName *n1, cName *n2, int op) {
|
||||
bool c;
|
||||
|
||||
switch (op) {
|
||||
case Py_LT:
|
||||
c = n1->name->lthan(*n2->name);
|
||||
break;
|
||||
case Py_LE:
|
||||
c = n1->name->leq(*n2->name);
|
||||
break;
|
||||
case Py_EQ:
|
||||
c = n1->name->equals(*n2->name);
|
||||
break;
|
||||
case Py_NE:
|
||||
c = n1->name->nequals(*n2->name);
|
||||
break;
|
||||
case Py_GT:
|
||||
c = n1->name->gthan(*n2->name);
|
||||
break;
|
||||
case Py_GE:
|
||||
c = n1->name->geq(*n2->name);
|
||||
break;
|
||||
default:
|
||||
assert(0); // XXX: should trigger an exception
|
||||
}
|
||||
if (c)
|
||||
Py_RETURN_TRUE;
|
||||
else
|
||||
Py_RETURN_FALSE;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
cName_split(cName *self, PyObject *args) {
|
||||
unsigned int first, n;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "II", &first, &n))
|
||||
return NULL;
|
||||
|
||||
cName *ret = PyObject_New(cName, &cName_Type);
|
||||
if (ret != NULL) {
|
||||
ret->name = NULL;
|
||||
try {
|
||||
ret->name = new Name(self->name->split(first, n));
|
||||
} catch(OutOfRange) {
|
||||
PyErr_SetString(cName_Exception, "OutOfRange");
|
||||
}
|
||||
if (ret->name == NULL) {
|
||||
Py_DECREF(ret);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
return (PyObject *) ret;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
cName_concatenate(cName *self, PyObject *args) {
|
||||
cName *suffix;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "O!", &cName_Type, (PyObject **) &suffix))
|
||||
return NULL;
|
||||
|
||||
cName *ret = PyObject_New(cName, &cName_Type);
|
||||
if (ret != NULL) {
|
||||
ret->name = NULL;
|
||||
try {
|
||||
ret->name = new Name(
|
||||
self->name->concatenate(*suffix->name));
|
||||
} catch(TooLongName) {
|
||||
PyErr_SetString(cName_Exception, "TooLongName");
|
||||
}
|
||||
if (ret->name == NULL) {
|
||||
Py_DECREF(ret);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
return (PyObject *) ret;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
cName_downcase(cName *self) {
|
||||
self->name->downcase();
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
cName_isWildcard(cName *self) {
|
||||
if (self->name->isWildcard())
|
||||
Py_RETURN_TRUE;
|
||||
else
|
||||
Py_RETURN_FALSE;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
cName_getPosition(cName *self) {
|
||||
return Py_BuildValue("I", (unsigned int) self->position);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
cName_clone(cName *self, PyObject *args UNUSED_PARAM) {
|
||||
cName *copy = PyObject_New(cName, &cName_Type);
|
||||
|
||||
if (copy != NULL) {
|
||||
copy->name = new Name(*self->name);
|
||||
if (copy->name == NULL) {
|
||||
Py_DECREF(copy);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
return (PyObject *) copy;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
MessageRenderer *mr;
|
||||
OutputBuffer *buffer;
|
||||
} cMR;
|
||||
|
||||
static void cMR_dealloc(cMR *self);
|
||||
static int cMR_init(cMR *self, PyObject *args);
|
||||
static PyObject *cMR_dump(cMR *self);
|
||||
static PyObject *cMR_writeData(cMR *self, PyObject *args);
|
||||
static PyObject *cMR_writeName(cMR *self, PyObject *args);
|
||||
|
||||
static PyMethodDef cMR_Methods[] = {
|
||||
{ "dump", (PyCFunction)cMR_dump, METH_NOARGS,
|
||||
"Return content of the MessageRenderer" },
|
||||
{ "writeData", (PyCFunction)cMR_writeData, METH_VARARGS,
|
||||
"Write data into the MessageRenderer" },
|
||||
{ "writeName", (PyCFunction)cMR_writeName, METH_VARARGS,
|
||||
"Write a Name into the MessageRenderer" },
|
||||
{ NULL, NULL, 0, NULL }
|
||||
};
|
||||
|
||||
static PyTypeObject cMR_Type = {
|
||||
PyVarObject_HEAD_INIT(NULL, 0)
|
||||
"bind10_dns_noboost.cMessageRenderer", /* tp_name */
|
||||
sizeof(cMR), /* tp_basicsize */
|
||||
0, /* tp_itemsize */
|
||||
(destructor)cMR_dealloc, /* 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|Py_TPFLAGS_BASETYPE, /* tp_flags */
|
||||
"C++ MessageRenderer Object", /* tp_doc */
|
||||
NULL, /* tp_traverse */
|
||||
NULL, /* tp_clear */
|
||||
NULL, /* tp_richcompare */
|
||||
0, /* tp_weaklistoffset */
|
||||
NULL, /* tp_iter */
|
||||
NULL, /* tp_iternext */
|
||||
cMR_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 */
|
||||
(initproc)cMR_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 */
|
||||
// Note: not sure if the following are correct. Added them just to
|
||||
// make the compiler happy.
|
||||
NULL, /* tp_del */
|
||||
0 /* tp_version_tag */
|
||||
};
|
||||
|
||||
static void
|
||||
cMR_dealloc(cMR *self) {
|
||||
if (self->mr != NULL)
|
||||
delete self->mr;
|
||||
self->mr = NULL;
|
||||
if (self->buffer != NULL)
|
||||
delete self->buffer;
|
||||
self->buffer = NULL;
|
||||
Py_TYPE(self)->tp_free(self);
|
||||
}
|
||||
|
||||
static int
|
||||
cMR_init(cMR *self, PyObject *args) {
|
||||
if (!PyArg_ParseTuple(args, ""))
|
||||
return -1;
|
||||
|
||||
self->buffer = new OutputBuffer(1024);
|
||||
if (self->buffer == NULL) {
|
||||
(void) PyErr_NoMemory();
|
||||
return -1;
|
||||
}
|
||||
self->mr = new MessageRenderer(*self->buffer);
|
||||
if (self->mr == NULL) {
|
||||
delete self->buffer;
|
||||
self->buffer = NULL;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
cMR_dump(cMR *self) {
|
||||
return Py_BuildValue("y#", self->buffer->getData(),
|
||||
(Py_ssize_t) self->buffer->getLength());
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
cMR_writeData(cMR *self, PyObject *args) {
|
||||
const char *b;
|
||||
Py_ssize_t len;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "y#", &b, &len))
|
||||
return NULL;
|
||||
|
||||
self->buffer->writeData(b, len);
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
cMR_writeName(cMR *self, PyObject *args) {
|
||||
cName *name;
|
||||
PyObject *compress = Py_True;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "O!|O!",
|
||||
&cName_Type, (PyObject **) &name,
|
||||
&PyBool_Type, &compress))
|
||||
return NULL;
|
||||
|
||||
self->mr->writeName(*name->name, compress == Py_True);
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static PyModuleDef cName_Module = {
|
||||
{ PyObject_HEAD_INIT(NULL) NULL, 0, NULL}, // XXX: ad hoc init values
|
||||
"bind10_dns_noboost", /* m_name */
|
||||
"Python bindings for C++ Name Module", /* m_doc */
|
||||
-1, /* m_size */
|
||||
NULL, /* m_methods */
|
||||
NULL, /* m_reload */
|
||||
NULL, /* m_traverse */
|
||||
NULL, /* m_clear */
|
||||
NULL, /* m_free */
|
||||
};
|
||||
|
||||
PyMODINIT_FUNC
|
||||
PyInit_bind10_dns_noboost(void) {
|
||||
if (PyType_Ready(&cName_Type) < 0)
|
||||
return NULL;
|
||||
if (PyType_Ready(&cNCR_Type) < 0)
|
||||
return NULL;
|
||||
if (PyType_Ready(&cMR_Type) < 0)
|
||||
return NULL;
|
||||
|
||||
PyObject *mod;
|
||||
|
||||
mod = PyModule_Create(&cName_Module);
|
||||
if (mod == NULL)
|
||||
return NULL;
|
||||
|
||||
Py_INCREF(&cName_Type);
|
||||
PyModule_AddObject(mod, "cName", (PyObject *) &cName_Type);
|
||||
Py_INCREF(&cNCR_Type);
|
||||
PyModule_AddObject(mod, "cNameComparisonResult",
|
||||
(PyObject *) &cNCR_Type);
|
||||
Py_INCREF(&cMR_Type);
|
||||
PyModule_AddObject(mod, "cMessageRenderer", (PyObject *) &cMR_Type);
|
||||
|
||||
cName_Exception = PyErr_NewException("bind10_dns_noboost.DNSException", NULL,
|
||||
NULL);
|
||||
Py_INCREF(cName_Exception);
|
||||
PyModule_AddObject(mod, "DNSException", cName_Exception);
|
||||
|
||||
cName_Relation = Py_BuildValue("{i:s,i:s,i:s,i:s}",
|
||||
0, "SUPERDOMAIN",
|
||||
1, "SUBDOMAIN",
|
||||
2, "EQUAL",
|
||||
3, "COMMONANCESTOR");
|
||||
Py_INCREF(cName_Relation);
|
||||
PyModule_AddObject(mod, "NameRelation", cName_Relation);
|
||||
|
||||
cName_MAX_WIRE = Py_BuildValue("I", 255U);
|
||||
Py_INCREF(cName_MAX_WIRE);
|
||||
PyModule_AddObject(mod, "MAX_WIRE", cName_MAX_WIRE);
|
||||
cName_MAX_LABELS = Py_BuildValue("I", 128U);
|
||||
Py_INCREF(cName_MAX_LABELS);
|
||||
PyModule_AddObject(mod, "MAX_LABELS", cName_MAX_LABELS);
|
||||
cName_MAX_LABELLEN = Py_BuildValue("I", 63U);
|
||||
Py_INCREF(cName_MAX_LABELLEN);
|
||||
PyModule_AddObject(mod, "MAX_LABELLEN", cName_MAX_LABELLEN);
|
||||
cName_MAX_COMPRESS_POINTER = Py_BuildValue("I", 0x3fffU);
|
||||
Py_INCREF(cName_MAX_COMPRESS_POINTER);
|
||||
PyModule_AddObject(mod, "MAX_COMPRESS_POINTER",
|
||||
cName_MAX_COMPRESS_POINTER);
|
||||
cName_COMPRESS_POINTER_MARK8 = Py_BuildValue("I", 0xc0U);
|
||||
Py_INCREF(cName_COMPRESS_POINTER_MARK8);
|
||||
PyModule_AddObject(mod, "COMPRESS_POINTER_MARK8",
|
||||
cName_COMPRESS_POINTER_MARK8);
|
||||
cName_COMPRESS_POINTER_MARK16 = Py_BuildValue("I", 0xc000U);
|
||||
Py_INCREF(cName_COMPRESS_POINTER_MARK16);
|
||||
PyModule_AddObject(mod, "COMPRESS_POINTER_MARK16",
|
||||
cName_COMPRESS_POINTER_MARK16);
|
||||
|
||||
return mod;
|
||||
}
|
49
src/lib/dns-python/dns.py
Normal file
49
src/lib/dns-python/dns.py
Normal file
@@ -0,0 +1,49 @@
|
||||
"""Python C bindings"""
|
||||
|
||||
import bind10_dns_noboost
|
||||
|
||||
class Name(bind10_dns_noboost.cName):
|
||||
"""Python shadow class of cName"""
|
||||
|
||||
def __init__(self, *args):
|
||||
"""initializer"""
|
||||
super(Name, self).__init__(*args)
|
||||
|
||||
def __len__(self):
|
||||
"""length"""
|
||||
return self.getLength()
|
||||
|
||||
def __str__(self):
|
||||
"""string"""
|
||||
return self.toText()
|
||||
|
||||
def __repr__(self):
|
||||
"""representation"""
|
||||
return '<Name: ' + str(self) +'>'
|
||||
|
||||
class MessageRenderer(bind10_dns_noboost.cMessageRenderer):
|
||||
"""Python shadow class of cMessageRenderer"""
|
||||
|
||||
def __init__(self):
|
||||
"""initializer"""
|
||||
super(MessageRenderer, self).__init__()
|
||||
|
||||
def fromText(text, downcase=False):
|
||||
"""fromText factory"""
|
||||
return Name(text, downcase)
|
||||
|
||||
def fromWire(wire, position, downcase=False):
|
||||
"""fromWire factory"""
|
||||
n = Name(wire, position, downcase)
|
||||
return (n, n.getPosition() - position)
|
||||
|
||||
def compare(n1, n2):
|
||||
"""compare"""
|
||||
ncr = n1.compare(n2)
|
||||
return (ncr.getOrder(), \
|
||||
ncr.getCommonLabels(), \
|
||||
bind10_dns_noboost.NameRelation[ncr.getRelation()])
|
||||
|
||||
def concatenate(n1, n2):
|
||||
"""concatenate"""
|
||||
return n1.concatenate(n2)
|
590
src/lib/dns-python/test.py
Normal file
590
src/lib/dns-python/test.py
Normal file
@@ -0,0 +1,590 @@
|
||||
"""Python tests"""
|
||||
|
||||
from dns import *
|
||||
|
||||
example = fromText("www.example.com")
|
||||
upper = fromText("WWW.EXAMPLE.COM")
|
||||
small = fromText("aaa.example.com")
|
||||
large = fromText("zzz.example.com")
|
||||
|
||||
def f2b(name):
|
||||
"""file to binary"""
|
||||
f = open(name)
|
||||
rl = f.readlines()
|
||||
f.close()
|
||||
b = bytearray()
|
||||
for l in rl:
|
||||
if l[0] == '#':
|
||||
continue
|
||||
if l[-1] == '\n':
|
||||
l = l[:-1]
|
||||
b += bytearray().fromhex(l)
|
||||
return bytes(b)
|
||||
|
||||
def nflc():
|
||||
"""name Factory Lower Case"""
|
||||
namestr = ''
|
||||
labelcount = 0
|
||||
for ch in range(0, bind10_dns_noboost.MAX_WIRE + 1):
|
||||
if (ch < ord('A')) or (ch > ord('Z')):
|
||||
ss = '%03d' % ch
|
||||
namestr += '\\' + ss
|
||||
labelcount += 1
|
||||
if labelcount == bind10_dns_noboost.MAX_LABELLEN:
|
||||
namestr += '.'
|
||||
labelcount = 0
|
||||
return Name(namestr)
|
||||
|
||||
|
||||
|
||||
def testFT():
|
||||
"""fromText"""
|
||||
nl = []
|
||||
nl.append(fromText("www.example.com"))
|
||||
nl.append(fromText("www.example.com.")) # with a trailing dot
|
||||
nl.append(fromText("wWw.exAmpLe.com")) # mixed cases
|
||||
nl.append(fromText("\\wWw.exAmpLe.com")) # escape with a backslash
|
||||
# decimal representation for "WWW"
|
||||
nl.append(fromText("\\087\\087\\087.example.com"))
|
||||
|
||||
for it in nl:
|
||||
if it != example:
|
||||
print('FAILED: (FT)',it,'!=',example)
|
||||
|
||||
# root names
|
||||
if fromText("@") != fromText("."):
|
||||
print('FAILED: (FT) root name')
|
||||
|
||||
# downcase
|
||||
n = fromText("Www.eXample.coM", True)
|
||||
if n.toWire() != example.toWire():
|
||||
print('FAILED: (FT) downcase')
|
||||
|
||||
#
|
||||
# Tests for bogus names. These should trigger an exception.
|
||||
#
|
||||
# empty label cannot be followed by another label
|
||||
try:
|
||||
n = fromText(".a")
|
||||
print('FAILED: (FT) .a')
|
||||
except bind10_dns_noboost.DNSException as e:
|
||||
if str(e) != 'EmptyLabel':
|
||||
print('FAILED: (FT) .a')
|
||||
# duplicate period
|
||||
try:
|
||||
n = fromText("a..")
|
||||
print('FAILED: (FT) a..')
|
||||
except bind10_dns_noboost.DNSException as e:
|
||||
if str(e) != 'EmptyLabel':
|
||||
print('FAILED: (FT) a..')
|
||||
# label length must be < 64
|
||||
try:
|
||||
n = fromText("012345678901234567890123456789" +
|
||||
"012345678901234567890123456789" +
|
||||
"0123")
|
||||
print('FAILED: (FT) TooLongLabel')
|
||||
except bind10_dns_noboost.DNSException as e:
|
||||
if str(e) != 'TooLongLabel':
|
||||
print('FAILED: (FT) TooLongLabel')
|
||||
# now-unsupported bitstring labels
|
||||
try:
|
||||
n = fromText("\\[b11010000011101]")
|
||||
print('FAILED: (FT) BadLabelType')
|
||||
except bind10_dns_noboost.DNSException as e:
|
||||
if str(e) != 'BadLabelType':
|
||||
print('FAILED: (FT) BadLabelType')
|
||||
# label length must be < 64
|
||||
try:
|
||||
n = fromText("012345678901234567890123456789" +
|
||||
"012345678901234567890123456789" +
|
||||
"012\\x")
|
||||
print('FAILED: (FT) TooLongLabel')
|
||||
except bind10_dns_noboost.DNSException as e:
|
||||
if str(e) != 'TooLongLabel':
|
||||
print('FAILED: (FT) TooLongLabel')
|
||||
# but okay as long as resulting len < 64 even if the original string is
|
||||
# "too long"
|
||||
try:
|
||||
n = fromText("012345678901234567890123456789" +
|
||||
"012345678901234567890123456789" +
|
||||
"01\\x")
|
||||
except bind10_dns_noboost.DNSException:
|
||||
print('FAILED: (FT) too long')
|
||||
# incomplete \DDD pattern (exactly 3 D's must appear)
|
||||
try:
|
||||
n = fromText("\\12abc")
|
||||
print('FAILED: (FT) BadEscape')
|
||||
except bind10_dns_noboost.DNSException as e:
|
||||
if str(e) != 'BadEscape':
|
||||
print('FAILED: (FT) BadEscape')
|
||||
# \DDD must not exceed 255
|
||||
try:
|
||||
n = fromText("\\256")
|
||||
print('FAILED: (FT) BadEscape')
|
||||
except bind10_dns_noboost.DNSException as e:
|
||||
if str(e) != 'BadEscape':
|
||||
print('FAILED: (FT) BadEscape')
|
||||
# Same tests for \111 as for \\x above
|
||||
try:
|
||||
n = fromText("012345678901234567890123456789" +
|
||||
"012345678901234567890123456789" +
|
||||
"012\\111")
|
||||
print('FAILED: (FT) TooLongLabel')
|
||||
except bind10_dns_noboost.DNSException as e:
|
||||
if str(e) != 'TooLongLabel':
|
||||
print('FAILED: (FT) TooLongLabel')
|
||||
try:
|
||||
n = fromText("012345678901234567890123456789" +
|
||||
"012345678901234567890123456789" +
|
||||
"01\\111")
|
||||
except bind10_dns_noboost.DNSException:
|
||||
print('FAILED: (FT) too long')
|
||||
# A domain name must be 255 octets or less
|
||||
try:
|
||||
n = fromText("123456789.123456789.123456789.123456789.123456789." +
|
||||
"123456789.123456789.123456789.123456789.123456789." +
|
||||
"123456789.123456789.123456789.123456789.123456789." +
|
||||
"123456789.123456789.123456789.123456789.123456789." +
|
||||
"123456789.123456789.123456789.123456789.123456789." +
|
||||
"1234")
|
||||
print('FAILED: (FT) TooLongName')
|
||||
except bind10_dns_noboost.DNSException as e:
|
||||
if str(e) != 'TooLongName':
|
||||
print('FAILED: (FT) TooLongName')
|
||||
# This is a possible longest name and should be accepted
|
||||
try:
|
||||
n = fromText("123456789.123456789.123456789.123456789.123456789." +
|
||||
"123456789.123456789.123456789.123456789.123456789." +
|
||||
"123456789.123456789.123456789.123456789.123456789." +
|
||||
"123456789.123456789.123456789.123456789.123456789." +
|
||||
"123456789.123456789.123456789.123456789.123456789." +
|
||||
"123")
|
||||
except bind10_dns_noboost.DNSException:
|
||||
print('FAILED: (FT) longest')
|
||||
# \DDD must consist of 3 digits
|
||||
try:
|
||||
n = fromText("\\12")
|
||||
print('FAILED: (FT) IncompleteName')
|
||||
except bind10_dns_noboost.DNSException as e:
|
||||
if str(e) != 'IncompleteName':
|
||||
print('FAILED: (FT) IncompleteName')
|
||||
|
||||
# a name with the max number of labels. should be constructed without
|
||||
# an error, and its length should be the max value.
|
||||
try:
|
||||
n = fromText("0.1.2.3.4.5.6.7.8.9.0.1.2.3.4.5.6.7.8.9." + # 40
|
||||
"0.1.2.3.4.5.6.7.8.9.0.1.2.3.4.5.6.7.8.9." + # 80
|
||||
"0.1.2.3.4.5.6.7.8.9.0.1.2.3.4.5.6.7.8.9." + # 120
|
||||
"0.1.2.3.4.5.6.7.8.9.0.1.2.3.4.5.6.7.8.9." + # 160
|
||||
"0.1.2.3.4.5.6.7.8.9.0.1.2.3.4.5.6.7.8.9." + # 200
|
||||
"0.1.2.3.4.5.6.7.8.9.0.1.2.3.4.5.6.7.8.9." + # 240
|
||||
"0.1.2.3.4.5.6.")
|
||||
if bind10_dns_noboost.MAX_LABELS != n.getLabelCount():
|
||||
print('FAILED: (FT)',bind10_dns_noboost.MAX_LABELS,'!=',
|
||||
n.getLabelCount())
|
||||
except bind10_dns_noboost.DNSException:
|
||||
print('FAILED: (FT) maxlabels')
|
||||
|
||||
def testFW():
|
||||
"""fromWire"""
|
||||
#
|
||||
# test cases derived from BIND9 tests.
|
||||
#
|
||||
# normal case with a compression pointer
|
||||
(n, _) = fromWire(f2b("testdata/name_fromWire1"), 25)
|
||||
if n != fromText("vix.com"):
|
||||
print('FAILED: (FW) n',n.toText(),'!=',"vix.com")
|
||||
# bogus label character (looks like a local compression pointer)
|
||||
try:
|
||||
(n, _) = fromWire(f2b("testdata/name_fromWire2"), 25)
|
||||
print('FAILED: (FW) BadLabelType')
|
||||
except bind10_dns_noboost.DNSException as e:
|
||||
if str(e) != 'BadLabelType':
|
||||
print('FAILED: (FW) BadLabelType')
|
||||
# a bad compression pointer (too big)
|
||||
try:
|
||||
(n, _) = fromWire(f2b("testdata/name_fromWire3_1"), 25)
|
||||
print('FAILED: (FW) BadPointer')
|
||||
except bind10_dns_noboost.DNSException as e:
|
||||
if str(e) != 'BadPointer':
|
||||
print('FAILED: (FW) BadPointer')
|
||||
# forward reference
|
||||
try:
|
||||
(n, _) = fromWire(f2b("testdata/name_fromWire3_2"), 25)
|
||||
print('FAILED: (FW) BadPointer')
|
||||
except bind10_dns_noboost.DNSException as e:
|
||||
if str(e) != 'BadPointer':
|
||||
print('FAILED: (FW) BadPointer')
|
||||
# invalid name length
|
||||
try:
|
||||
(n, _) = fromWire(f2b("testdata/name_fromWire4"), 550)
|
||||
print('FAILED: (FW) TooLongName')
|
||||
except bind10_dns_noboost.DNSException as e:
|
||||
if str(e) != 'TooLongName':
|
||||
print('FAILED: (FW) TooLongName')
|
||||
|
||||
# skip test for from Wire5. It's for disabling decompression, but our
|
||||
# implementation always allows it.
|
||||
|
||||
# bad pointer (too big)
|
||||
try:
|
||||
(n, _) = fromWire(f2b("testdata/name_fromWire6"), 25)
|
||||
print('FAILED: (FW) BadPointer')
|
||||
except bind10_dns_noboost.DNSException as e:
|
||||
if str(e) != 'BadPointer':
|
||||
print('FAILED: (FW) BadPointer')
|
||||
# input ends unexpectedly
|
||||
try:
|
||||
(n, _) = fromWire(f2b("testdata/name_fromWire7"), 25)
|
||||
print('FAILED: (FW) IncompleteName')
|
||||
except bind10_dns_noboost.DNSException as e:
|
||||
if str(e) != 'IncompleteName':
|
||||
print('FAILED: (FW) IncompleteName')
|
||||
# many hops of compression but valid. should succeed
|
||||
try:
|
||||
(n, _) = fromWire(f2b("testdata/name_fromWire8"), 383)
|
||||
if n != fromText("vix.com"):
|
||||
print('FAILED: (FW) vix.com')
|
||||
except bind10_dns_noboost.DNSException:
|
||||
print('FAILED: (FW) vix.com')
|
||||
|
||||
#
|
||||
# Additional test cases
|
||||
#
|
||||
|
||||
# large names, a long but valid one, and invalid (too long) one.
|
||||
try:
|
||||
(n, _) = fromWire(f2b("testdata/name_fromWire9"), 0)
|
||||
if n.getLength() != bind10_dns_noboost.MAX_WIRE:
|
||||
print('FAILED: (FW) ong but valid')
|
||||
except bind10_dns_noboost.DNSException:
|
||||
print('FAILED: (FW) ong but valid')
|
||||
try:
|
||||
(n, _) = fromWire(f2b("testdata/name_fromWire10"), 0)
|
||||
print('FAILED: (FW) TooLongName')
|
||||
except bind10_dns_noboost.DNSException as e:
|
||||
if str(e) != 'TooLongName':
|
||||
print('FAILED: (FW) TooLongName')
|
||||
|
||||
# A name with possible maximum number of labels; awkward but valid
|
||||
try:
|
||||
(n, _) = fromWire(f2b("testdata/name_fromWire11"), 0)
|
||||
if n.getLabelCount() != bind10_dns_noboost.MAX_LABELS:
|
||||
print('FAILED: (FW) maxlabels')
|
||||
except bind10_dns_noboost.DNSException:
|
||||
print('FAILED: (FW) maxlabels')
|
||||
|
||||
# Wire format including an invalid label length
|
||||
try:
|
||||
(n, _) = fromWire(f2b("testdata/name_fromWire12"), 0)
|
||||
print('FAILED: (FW) BadLabelType')
|
||||
except bind10_dns_noboost.DNSException as e:
|
||||
if str(e) != 'BadLabelType':
|
||||
print('FAILED: (FW) BadLabelType')
|
||||
|
||||
# converting upper-case letters to down-case
|
||||
(n, _) = fromWire(f2b("testdata/name_fromWire1"), 25, True)
|
||||
if n.toText() != 'vix.com.':
|
||||
print('FAILED: (FW) ',n.toText(),'!=','vix.com.')
|
||||
if n.getLabelCount() != 3:
|
||||
print('FAILED: (FW) ',n.getLabelCount(),'!= 3')
|
||||
|
||||
def testTT():
|
||||
"""toText"""
|
||||
# tests derived from BIND9
|
||||
n = fromText("a.b.c.d")
|
||||
if n.toText(True) != "a.b.c.d":
|
||||
print('FAILED: (TT)',n.toText(True),'!= a.b.c.d')
|
||||
n = fromText("a.\\\\[\\[.c.d")
|
||||
if n.toText(True) != "a.\\\\[[.c.d":
|
||||
print('FAILED: (TT)',n.toText(),'!= a.\\\\[[.c.d')
|
||||
n = fromText("a.b.C.d")
|
||||
if n.toText(False) != "a.b.C.d.":
|
||||
print('FAILED: (TT)',n.toText(False),'!= a.b.C.d.')
|
||||
|
||||
# test omit_final_dot. It's false by default.
|
||||
n = fromText("a.b.c.d.")
|
||||
if n.toText(True) != "a.b.c.d":
|
||||
print('FAILED: (TT)',n.toText(True),'!= a.b.c.d')
|
||||
n1 = fromText("a.b.")
|
||||
n2 = fromText("a.b.")
|
||||
if n1.toText(False) != n2.toText():
|
||||
print('FAILED: (TT)',n1.toText(False))
|
||||
|
||||
# the root name is a special case: omit_final_dot will be ignored.
|
||||
n = fromText(".")
|
||||
if n.toText(True) != '.':
|
||||
print('FAILED: (TT)',n.toText(True),' != ,')
|
||||
|
||||
def testTW():
|
||||
"""toWire"""
|
||||
data = "\x01\x61\x03\x76\x69\x78\x03\x63\x6f\x6d\x00"
|
||||
n = fromText("a.vix.com.")
|
||||
w = n.toWire()
|
||||
if len(w) != len(data):
|
||||
print('FAILED: (TW)',len(w),'!=',len(data))
|
||||
|
||||
def testF():
|
||||
"""compare"""
|
||||
n1 = fromText("c.d")
|
||||
n2 = fromText("a.b.c.d")
|
||||
t = compare(n1, n2)
|
||||
if t[0] < 0:
|
||||
tt = (-1, t[1], t[2])
|
||||
elif t[0] > 0:
|
||||
tt = (1, t[1],t[2])
|
||||
else:
|
||||
tt = (0, t[1],t[2])
|
||||
if tt != (-1,3,'SUPERDOMAIN'):
|
||||
print('FAILED: (F) ', tt)
|
||||
|
||||
n1 = fromText("a.b.c.d")
|
||||
n2 = fromText("c.d")
|
||||
t = compare(n1, n2)
|
||||
if t[0] < 0:
|
||||
tt = (-1, t[1], t[2])
|
||||
elif t[0] > 0:
|
||||
tt = (1, t[1],t[2])
|
||||
else:
|
||||
tt = (0, t[1],t[2])
|
||||
if tt != (1, 3, 'SUBDOMAIN'):
|
||||
print('FAILED: (F) ', tt)
|
||||
|
||||
n1 = fromText("a.b.c.d")
|
||||
n2 = fromText("c.d.e.f")
|
||||
t = compare(n1, n2)
|
||||
if t[0] < 0:
|
||||
tt = (-1, t[1], t[2])
|
||||
elif t[0] > 0:
|
||||
tt = (1, t[1],t[2])
|
||||
else:
|
||||
tt = (0, t[1],t[2])
|
||||
if tt != (-1, 1, 'COMMONANCESTOR'):
|
||||
print('FAILED: (F) ', tt)
|
||||
|
||||
n1 = fromText("a.b.c.d")
|
||||
n2 = fromText("f.g.c.d")
|
||||
t = compare(n1, n2)
|
||||
if t[0] < 0:
|
||||
tt = (-1, t[1], t[2])
|
||||
elif t[0] > 0:
|
||||
tt = (1, t[1],t[2])
|
||||
else:
|
||||
tt = (0, t[1],t[2])
|
||||
if tt != (-1, 3, 'COMMONANCESTOR'):
|
||||
print('FAILED: (F) ', tt)
|
||||
|
||||
n1 = fromText("a.b.c.d")
|
||||
n2 = fromText("A.b.C.d.")
|
||||
t = compare(n1, n2)
|
||||
if t[0] < 0:
|
||||
tt = (-1, t[1], t[2])
|
||||
elif t[0] > 0:
|
||||
tt = (1, t[1],t[2])
|
||||
else:
|
||||
tt = (0, t[1],t[2])
|
||||
if tt != (0, 5, 'EQUAL'):
|
||||
print('FAILED: (F) ', tt)
|
||||
|
||||
def testE():
|
||||
"""equal"""
|
||||
n = fromText("WWW.EXAMPLE.COM.")
|
||||
if not (example == n):
|
||||
print('FAILED: (E) 1')
|
||||
if not example.equals(n):
|
||||
print('FAILED: (E) 2')
|
||||
n = fromText("www.example.org.")
|
||||
if not (example != n):
|
||||
print('FAILED: (E) 3')
|
||||
if not example.nequals(n):
|
||||
print('FAILED: (E) 4')
|
||||
|
||||
def testIW():
|
||||
"""isWildcard"""
|
||||
if not example.isWildcard() is False:
|
||||
print('FAILED: (IW)',example.toText())
|
||||
n = fromText("*.a.example.com")
|
||||
if not n.isWildcard() is True:
|
||||
print('FAILED: (IW)',n.toText())
|
||||
n = fromText("a.*.example.com")
|
||||
if not n.isWildcard() is False:
|
||||
print('FAILED: (IW)',n.toText())
|
||||
|
||||
def testC():
|
||||
"""concatenate"""
|
||||
nc = fromText("aaa.www.example.com.")
|
||||
n = fromText("aaa")
|
||||
c = compare(nc, concatenate(n, example))
|
||||
if c[2] != 'EQUAL':
|
||||
print('FAILED: (C)',nc,'!=',n,'+',example)
|
||||
|
||||
n = fromText(".")
|
||||
c = compare(example, concatenate(n, example))
|
||||
if c[2] != 'EQUAL':
|
||||
print('FAILED: (C)',example,'!=',n,'+',example)
|
||||
|
||||
c = compare(example, concatenate(example, n))
|
||||
if c[2] != 'EQUAL':
|
||||
print('FAILED: (C)',example,'!=',example,'+',n)
|
||||
|
||||
# concatenating two valid names would result in too long a name.
|
||||
n1 = fromText("123456789.123456789.123456789.123456789.123456789." +
|
||||
"123456789.123456789.123456789.123456789.123456789." +
|
||||
"123456789.123456789.123456789.123456789.123456789.")
|
||||
n2 = fromText("123456789.123456789.123456789.123456789.123456789." +
|
||||
"123456789.123456789.123456789.123456789.123456789." +
|
||||
"1234.");
|
||||
try:
|
||||
n = concatenate(n1, n2)
|
||||
print('FAILED: (C) toolong')
|
||||
except bind10_dns_noboost.DNSException as e:
|
||||
if str(e) != 'TooLongName':
|
||||
print('FAILED: (C) TooLongName')
|
||||
|
||||
def testS():
|
||||
"""split"""
|
||||
# normal cases with or without explicitly specifying the trailing dot.
|
||||
n = fromText("example.com.")
|
||||
ns = example.split(1, 2)
|
||||
if n != ns:
|
||||
print('FAILED: (S)',n,'!=',ns)
|
||||
ns = example.split(1, 3)
|
||||
if n != ns:
|
||||
print('FAILED: (S)',n,'!=',ns)
|
||||
# edge cases: only the first or last label.
|
||||
n = fromText("www.")
|
||||
ns = example.split(0, 1)
|
||||
if n != ns:
|
||||
print('FAILED: (S)',n,'!=',ns)
|
||||
n = fromText(".")
|
||||
ns = example.split(3, 1)
|
||||
if n != ns:
|
||||
print('FAILED: (S)',n,'!=',ns)
|
||||
# invalid range: an exception should be thrown.
|
||||
try:
|
||||
n = example.split(1, 0)
|
||||
print('FAILED: (S) OutOfRange')
|
||||
except bind10_dns_noboost.DNSException as e:
|
||||
if str(e) != 'OutOfRange':
|
||||
print('FAILED: (S) OutOfRange')
|
||||
try:
|
||||
n = example.split(2, 3)
|
||||
print('FAILED: (S) OutOfRange')
|
||||
except bind10_dns_noboost.DNSException as e:
|
||||
if str(e) != 'OutOfRange':
|
||||
print('FAILED: (S) OutOfRange')
|
||||
|
||||
def testD():
|
||||
"""downcase"""
|
||||
# usual case: all-upper case name to all-lower case
|
||||
upper.downcase()
|
||||
if upper.toWire() != example.toWire():
|
||||
print('FAILED: (D) upper')
|
||||
# confirm that non upper-case characters are intact
|
||||
n1 = nflc()
|
||||
n2 = nflc()
|
||||
n1.downcase()
|
||||
if n1.toWire() != n2.toWire():
|
||||
print('FAILED: (D) nameFactoryLowerCase')
|
||||
|
||||
def testLE():
|
||||
"""leq"""
|
||||
if not (small <= large) or \
|
||||
not (small <= small) or \
|
||||
large <= small:
|
||||
print('FAILED: (LE)')
|
||||
|
||||
def testGE():
|
||||
"""geq"""
|
||||
if not (large >= small) or \
|
||||
not (large >= large) or \
|
||||
small >= large:
|
||||
print('FAILED: (GE)')
|
||||
|
||||
def testLT():
|
||||
"""lthan"""
|
||||
if not (small < large) or \
|
||||
small < small or \
|
||||
large < small:
|
||||
print('FAILED: (LT)')
|
||||
|
||||
def testGT():
|
||||
"""gthan"""
|
||||
if not (large > small) or \
|
||||
large > large or \
|
||||
small > large:
|
||||
print('FAILED: (GT)')
|
||||
|
||||
def testWN():
|
||||
"""writeName"""
|
||||
data = f2b("testdata/name_toWire1")
|
||||
mr = MessageRenderer()
|
||||
n = fromText("a.example.com.")
|
||||
mr.writeName(n)
|
||||
n = fromText("b.example.com.")
|
||||
mr.writeName(n)
|
||||
n = fromText("a.example.org.")
|
||||
mr.writeName(n)
|
||||
if mr.dump() != data:
|
||||
print('FAILED: (WN)',mr.dump(),'!=',data)
|
||||
|
||||
# toWireInLargeBuffer
|
||||
pad = b'\x00' * 0x3fff
|
||||
data = f2b("testdata/name_toWire2")
|
||||
mr = MessageRenderer()
|
||||
mr.writeData(pad)
|
||||
n = fromText("a.example.com.")
|
||||
mr.writeName(n)
|
||||
n = fromText("a.example.com.")
|
||||
mr.writeName(n)
|
||||
n = fromText("b.example.com.")
|
||||
mr.writeName(n)
|
||||
d = mr.dump()[0x3fff :]
|
||||
if d != data:
|
||||
print('FAILED: (WN) LB',d,'!=',data)
|
||||
|
||||
# toWireWithUncompressed
|
||||
data = f2b("testdata/name_toWire3")
|
||||
mr = MessageRenderer()
|
||||
n = fromText("a.example.com.")
|
||||
mr.writeName(n)
|
||||
n = fromText("b.example.com.")
|
||||
mr.writeName(n, False)
|
||||
n = fromText("b.example.com.")
|
||||
mr.writeName(n)
|
||||
if mr.dump() != data:
|
||||
print('FAILED: (WN) UC',mr.dump(),'!=',data)
|
||||
|
||||
# toWireCaseCompress
|
||||
data = f2b("testdata/name_toWire1")
|
||||
mr = MessageRenderer()
|
||||
n = fromText("a.example.com.")
|
||||
mr.writeName(n)
|
||||
# this should match the first name in terms of compression:
|
||||
n = fromText("b.exAmple.CoM.")
|
||||
mr.writeName(n)
|
||||
n = fromText("a.example.org.")
|
||||
mr.writeName(n)
|
||||
if mr.dump() != data:
|
||||
print('FAILED: (WN) CC',mr.dump(),'!=',data)
|
||||
|
||||
def testAll():
|
||||
"""All"""
|
||||
testFT()
|
||||
testFW()
|
||||
testTT()
|
||||
testTW()
|
||||
testF()
|
||||
testE()
|
||||
testIW()
|
||||
testC()
|
||||
testS()
|
||||
testD()
|
||||
testLE()
|
||||
testGE()
|
||||
testLT()
|
||||
testGT()
|
||||
testWN()
|
||||
|
||||
testAll()
|
||||
print("PASSED")
|
Reference in New Issue
Block a user