aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRob Austein <sra@hactrn.net>2012-09-17 00:36:46 +0000
committerRob Austein <sra@hactrn.net>2012-09-17 00:36:46 +0000
commit493b827b2b425fcbf79a7aa7b0db1ef7a9d253a5 (patch)
treecb649efe4d5b31737ec64d68347f315d11d85374
parentb51426395b2c9542989d74678906901b4db0a4ad (diff)
Add IPAddress class. This is intended to replace the rpki.ipaddrs
classes eventually, but may still need to be split into separate IPv4 and IPv6 classes or reimplemented as a subclass of PyLong. Won't know until we try to move away from the rpki.POW.pkix ASN.1 code, and there's more groundwork to do before we can make that jump. svn path=/branches/tk274/; revision=4715
-rw-r--r--rpkid/ext/POW.c408
1 files changed, 397 insertions, 11 deletions
diff --git a/rpkid/ext/POW.c b/rpkid/ext/POW.c
index 9e40aeb6..1d7cb73c 100644
--- a/rpkid/ext/POW.c
+++ b/rpkid/ext/POW.c
@@ -108,6 +108,8 @@
#include <time.h>
#include <string.h>
+#include <arpa/inet.h>
+#include <sys/socket.h>
/*
* Maximum size of a raw IP (v4 or v6) address, in bytes.
@@ -153,12 +155,13 @@
#define DER_FORMAT 2
/* Object check functions */
-#define X_X509_Check(op) ((op)->ob_type == &x509type)
-#define X_X509_store_Check(op) ((op)->ob_type == &x509_storetype)
-#define X_X509_crl_Check(op) ((op)->ob_type == &x509_crltype)
-#define X_asymmetric_Check(op) ((op)->ob_type == &asymmetrictype)
-#define X_digest_Check(op) ((op)->ob_type == &digesttype)
-#define X_cms_Check(op) ((op)->ob_type == &cmstype)
+#define POW_X509_Check(op) PyObject_TypeCheck(op, &x509type)
+#define POW_X509_Store_Check(op) PyObject_TypeCheck(op, &x509_storetype)
+#define POW_X509_CRL_Check(op) PyObject_TypeCheck(op, &x509_crltype)
+#define POW_Asymmetric_Check(op) PyObject_TypeCheck(op, &asymmetrictype)
+#define POW_Digest_Check(op) PyObject_TypeCheck(op, &digesttype)
+#define POW_CMS_Check(op) PyObject_TypeCheck(op, &cmstype)
+#define POW_IPAddress_Check(op) PyObject_TypeCheck(op, &ipaddresstype)
static char pow_module__doc__ [] =
"Python interface to RFC-3779-enabled OpenSSL. This code is intended\n"
@@ -189,10 +192,21 @@ static PyTypeObject
x509_crltype,
asymmetrictype,
digesttype,
- cmstype;
+ cmstype,
+ ipaddresstype;
+
/*========== Pre-definitions ==========*/
/*========== C structs ==========*/
+
+typedef struct {
+ PyObject_HEAD
+ unsigned char address[16];
+ unsigned char version;
+ unsigned char length;
+ unsigned short af;
+} ipaddress_object;
+
typedef struct {
PyObject_HEAD
X509 *x509;
@@ -550,7 +564,7 @@ x509_helper_sequence_to_stack(PyObject *x509_sequence)
if ((x509obj = (x509_object*) PySequence_GetItem(x509_sequence, i)) == NULL)
goto error;
- if (!X_X509_Check(x509obj))
+ if (!POW_X509_Check(x509obj))
lose_type_error("Inapropriate type");
if (!sk_X509_push(x509_stack, x509obj->x509))
@@ -688,7 +702,7 @@ Python_Long_to_ASN1_INTEGER(PyObject *py_long)
memset(buf, 0, sizeof(buf));
if (_PyLong_AsByteArray((PyLongObject *) py_long, buf, sizeof(buf), 0, 0) < 0)
- lose_type_error("Couldn't extract ASID value");
+ goto error;
while (b < buf + sizeof(buf) - 1 && *b == 0)
b++;
@@ -712,9 +726,380 @@ Python_Long_to_ASN1_INTEGER(PyObject *py_long)
return NULL;
}
+/*========== helper functions ==========*/
+/*========== IPAddress code ==========*/
-/*========== helper functions ==========*/
+static PyObject *
+ipaddress_object_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+ static char *kwlist[] = {"initializer", "version", NULL};
+ ipaddress_object *self = NULL;
+ PyObject *init = NULL;
+ PyObject *pylong = NULL;
+ int version = 0;
+ const char *s = NULL;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|i", kwlist, &init, &version) ||
+ (self = (ipaddress_object *) type->tp_alloc(type, 0)) == NULL)
+ goto error;
+
+ if (POW_IPAddress_Check(init)) {
+ ipaddress_object *src = (ipaddress_object *) init;
+
+ memcpy(self->address, src->address, sizeof(self->address));
+ self->version = src->version;
+ self->length = src->length;
+ self->af = src->af;
+
+ return (PyObject *) self;
+ }
+
+ if ((s = PyString_AsString(init)) == NULL)
+ PyErr_Clear();
+ else if (version == 0)
+ version = strchr(s, ':') ? 6 : 4;
+
+ switch (version) {
+ case 4: self->length = 4; self->af = AF_INET; break;
+ case 6: self->length = 16; self->af = AF_INET6; break;
+ default: lose("Unknown IP version number");
+ }
+ self->version = version;
+
+ if (s != NULL) {
+ if (inet_pton(self->af, s, self->address) <= 0)
+ lose("Couldn't parse IP address");
+ return (PyObject *) self;
+ }
+
+ if ((pylong = PyNumber_Long(init)) != NULL) {
+ if (_PyLong_AsByteArray((PyLongObject *) pylong, self->address, self->length, 0, 0) < 0)
+ goto error;
+ Py_XDECREF(pylong);
+ return (PyObject *) self;
+ }
+
+ lose_type_error("Couldn't convert initializer to IPAddress");
+
+ error:
+ Py_XDECREF(self);
+ Py_XDECREF(pylong);
+ return NULL;
+}
+
+static PyObject *
+ipaddress_object_str(ipaddress_object *self)
+{
+ char addrstr[sizeof("aaaa:bbbb:cccc:dddd:eeee:ffff:255.255.255.255") + 1];
+
+ if (!inet_ntop(self->af, self->address, addrstr, sizeof(addrstr)))
+ lose("Couldn't convert IP address");
+
+ return PyString_FromString(addrstr);
+
+ error:
+ return NULL;
+}
+
+static PyObject *
+ipaddress_object_repr(ipaddress_object *self)
+{
+ char addrstr[sizeof("aaaa:bbbb:cccc:dddd:eeee:ffff:255.255.255.255") + 1];
+
+ if (!inet_ntop(self->af, self->address, addrstr, sizeof(addrstr)))
+ lose("Couldn't convert IP address");
+
+ return PyString_FromFormat("<%s object %s at %p>",
+ self->ob_type->tp_name, addrstr, self);
+
+ error:
+ return NULL;
+}
+
+static int
+ipaddress_object_compare(PyObject *arg1, PyObject *arg2)
+{
+ PyObject *obj1 = PyNumber_Long(arg1);
+ PyObject *obj2 = PyNumber_Long(arg2);
+ int cmp = -1;
+
+ if (obj1 != NULL && obj2 != NULL)
+ cmp = PyObject_Compare(obj1, obj2);
+
+ Py_XDECREF(obj1);
+ Py_XDECREF(obj2);
+ return cmp;
+}
+
+static PyObject *
+ipaddress_object_richcompare(PyObject *arg1, PyObject *arg2, int op)
+{
+ PyObject *obj1 = PyNumber_Long(arg1);
+ PyObject *obj2 = PyNumber_Long(arg2);
+ PyObject *result = NULL;
+
+ if (obj1 != NULL && obj2 != NULL)
+ result = PyObject_RichCompare(obj1, obj2, op);
+
+ Py_XDECREF(obj1);
+ Py_XDECREF(obj2);
+ return result;
+}
+
+static long
+ipaddress_object_hash(ipaddress_object *self)
+{
+ unsigned long h = 0;
+ int i;
+
+ for (i = 0; i < self->length; i++)
+ h ^= self->address[i] << ((i & 3) << 3);
+
+ return (long) h == -1 ? 0 : (long) h;
+}
+
+static PyObject *
+ipaddress_object_get_bits(ipaddress_object *self, void *closure)
+{
+ return PyInt_FromLong(self->length * 8);
+}
+
+static PyObject *
+ipaddress_object_number_binary_helper(binaryfunc function, PyObject *arg1, PyObject *arg2)
+{
+ ipaddress_object *addr = NULL;
+ ipaddress_object *addr1 = NULL;
+ ipaddress_object *addr2 = NULL;
+ ipaddress_object *result = NULL;
+ PyObject *obj1 = NULL;
+ PyObject *obj2 = NULL;
+ PyObject *obj3 = NULL;
+ PyObject *obj4 = NULL;
+
+ if (POW_IPAddress_Check(arg1))
+ addr1 = (ipaddress_object *) arg1;
+
+ if (POW_IPAddress_Check(arg2))
+ addr2 = (ipaddress_object *) arg2;
+
+ if ((addr1 == NULL && addr2 == NULL) ||
+ (addr1 != NULL && addr2 != NULL && addr1->version != addr2->version) ||
+ (obj1 = PyNumber_Long(arg1)) == NULL ||
+ (obj2 = PyNumber_Long(arg2)) == NULL) {
+ result = (ipaddress_object *) Py_NotImplemented;
+ goto error;
+ }
+
+ if ((obj3 = function(obj1, obj2)) == NULL)
+ goto error;
+
+ if ((obj4 = PyNumber_Long(obj3)) == NULL)
+ lose("Couldn't convert result");
+
+ addr = addr1 != NULL ? addr1 : addr2;
+
+ if ((result = (ipaddress_object *) addr->ob_type->tp_alloc(addr->ob_type, 0)) == NULL)
+ goto error;
+
+ result->version = addr->version;
+ result->length = addr->length;
+ result->af = addr->af;
+
+ if (_PyLong_AsByteArray((PyLongObject *) obj4, result->address, result->length, 0, 0) < 0) {
+ Py_XDECREF(result);
+ result = NULL;
+ }
+
+ error: /* Fall through */
+ Py_XDECREF(obj1);
+ Py_XDECREF(obj2);
+ Py_XDECREF(obj3);
+ Py_XDECREF(obj4);
+
+ return (PyObject *) result;
+}
+
+static PyObject *
+ipaddress_object_number_long(PyObject *arg)
+{
+ ipaddress_object *addr = (ipaddress_object *) arg;
+
+ if (!POW_IPAddress_Check(arg))
+ return Py_NotImplemented;
+
+ return _PyLong_FromByteArray(addr->address, addr->length, 0, 0);
+}
+
+static PyObject *
+ipaddress_object_number_int(PyObject *arg)
+{
+ return ipaddress_object_number_long(arg);
+}
+
+static PyObject *
+ipaddress_object_number_add(PyObject *arg1, PyObject *arg2)
+{
+ return ipaddress_object_number_binary_helper(PyNumber_Add, arg1, arg2);
+}
+
+static PyObject *
+ipaddress_object_number_subtract(PyObject *arg1, PyObject *arg2)
+{
+ return ipaddress_object_number_binary_helper(PyNumber_Subtract, arg1, arg2);
+}
+
+static PyObject *
+ipaddress_object_number_lshift(PyObject *arg1, PyObject *arg2)
+{
+ return ipaddress_object_number_binary_helper(PyNumber_Lshift, arg1, arg2);
+}
+
+static PyObject *
+ipaddress_object_number_rshift(PyObject *arg1, PyObject *arg2)
+{
+ return ipaddress_object_number_binary_helper(PyNumber_Rshift, arg1, arg2);
+}
+
+static PyObject *
+ipaddress_object_number_and(PyObject *arg1, PyObject *arg2)
+{
+ return ipaddress_object_number_binary_helper(PyNumber_And, arg1, arg2);
+}
+
+static PyObject *
+ipaddress_object_number_xor(PyObject *arg1, PyObject *arg2)
+{
+ return ipaddress_object_number_binary_helper(PyNumber_Xor, arg1, arg2);
+}
+
+static PyObject *
+ipaddress_object_number_or(PyObject *arg1, PyObject *arg2)
+{
+ return ipaddress_object_number_binary_helper(PyNumber_Or, arg1, arg2);
+}
+
+static int
+ipaddress_object_number_nonzero(ipaddress_object *self)
+{
+ int i;
+
+ for (i = 0; i < self->length; i++)
+ if (self->address[i] != 0)
+ return 1;
+ return 0;
+}
+
+static PyObject *
+ipaddress_object_number_invert(ipaddress_object *self)
+{
+ ipaddress_object *result = NULL;
+ int i;
+
+ if ((result = (ipaddress_object *) self->ob_type->tp_alloc(self->ob_type, 0)) == NULL)
+ goto error;
+
+ result->version = self->version;
+ result->length = self->length;
+ result->af = self->af;
+
+ for (i = 0; i < self->length; i++)
+ result->address[i] = ~self->address[i];
+
+ error: /* Fall through */
+ return (PyObject *) result;
+}
+
+static PyGetSetDef ipaddress_getsetters[] = {
+ {"bits", (getter) ipaddress_object_get_bits},
+ {NULL}
+};
+
+static PyNumberMethods ipaddress_NumberMethods = {
+ ipaddress_object_number_add, /* nb_add */
+ ipaddress_object_number_subtract, /* nb_subtract */
+ 0, /* nb_multiply */
+ 0, /* nb_divide */
+ 0, /* nb_remainder */
+ 0, /* nb_divmod */
+ 0, /* nb_power */
+ 0, /* nb_negative */
+ 0, /* nb_positive */
+ 0, /* nb_absolute */
+ (inquiry) ipaddress_object_number_nonzero, /* nb_nonzero */
+ (unaryfunc) ipaddress_object_number_invert, /* nb_invert */
+ ipaddress_object_number_lshift, /* nb_lshift */
+ ipaddress_object_number_rshift, /* nb_rshift */
+ ipaddress_object_number_and, /* nb_and */
+ ipaddress_object_number_xor, /* nb_xor */
+ ipaddress_object_number_or, /* nb_or */
+ 0, /* nb_coerce */
+ ipaddress_object_number_int, /* nb_int */
+ ipaddress_object_number_long, /* nb_long */
+ 0, /* nb_float */
+ 0, /* nb_oct */
+ 0, /* nb_hex */
+ 0, /* nb_inplace_add */
+ 0, /* nb_inplace_subtract */
+ 0, /* nb_inplace_multiply */
+ 0, /* nb_inplace_divide */
+ 0, /* nb_inplace_remainder */
+ 0, /* nb_inplace_power */
+ 0, /* nb_inplace_lshift */
+ 0, /* nb_inplace_rshift */
+ 0, /* nb_inplace_and */
+ 0, /* nb_inplace_xor */
+ 0, /* nb_inplace_or */
+ 0, /* nb_floor_divide */
+ 0, /* nb_true_divide */
+ 0, /* nb_inplace_floor_divide */
+ 0, /* nb_inplace_true_divide */
+ 0, /* nb_index */
+};
+
+static PyTypeObject ipaddresstype = {
+ PyObject_HEAD_INIT(NULL)
+ 0, /* ob_size */
+ "_POW.IPAddress", /* tp_name */
+ sizeof(ipaddress_object), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ ipaddress_object_compare, /* tp_compare */
+ (reprfunc) ipaddress_object_repr, /* tp_repr */
+ &ipaddress_NumberMethods, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ (hashfunc) ipaddress_object_hash, /* tp_hash */
+ 0, /* tp_call */
+ (reprfunc) ipaddress_object_str, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_CHECKTYPES, /* tp_flags */
+ 0, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ ipaddress_object_richcompare, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ ipaddress_getsetters, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0, /* tp_alloc */
+ ipaddress_object_new, /* tp_new */
+};
+
+/*========== IPAddress code ==========*/
/*========== X509 code ==========*/
@@ -3672,7 +4057,7 @@ cms_object_sign(cms_object *self, PyObject *args)
if ((crlobj = (x509_crl_object *) PySequence_GetItem(crl_sequence, i)) == NULL)
goto error;
- if (!X_X509_crl_Check(crlobj))
+ if (!POW_X509_CRL_Check(crlobj))
lose_type_error("Inappropriate type");
if (!crlobj->crl)
@@ -4384,6 +4769,7 @@ init_POW(void)
Define_Class(asymmetrictype);
Define_Class(digesttype);
Define_Class(cmstype);
+ Define_Class(ipaddresstype);
#undef Define_Class