aboutsummaryrefslogtreecommitdiff
path: root/pythonmod
diff options
context:
space:
mode:
authorDag-Erling Smørgrav <des@FreeBSD.org>2019-02-06 12:31:02 +0000
committerDag-Erling Smørgrav <des@FreeBSD.org>2019-02-06 12:31:02 +0000
commit9c9d011eed674ddd7e4a0a148691887afb9e75cd (patch)
treecd45bceeed24e66e5b2838e8589d2c111cf691c6 /pythonmod
parent089d83fbd0b24f957b753d440f188ddadaabf4ff (diff)
downloadsrc-9c9d011eed674ddd7e4a0a148691887afb9e75cd.tar.gz
src-9c9d011eed674ddd7e4a0a148691887afb9e75cd.zip
Vendor import of Unbound 1.9.0.vendor/unbound/1.9.0
Notes
Notes: svn path=/vendor/unbound/dist/; revision=343835 svn path=/vendor/unbound/1.9.0/; revision=343836; tag=vendor/unbound/1.9.0
Diffstat (limited to 'pythonmod')
-rw-r--r--pythonmod/doc/modules/functions.rst33
-rw-r--r--pythonmod/doc/modules/struct.rst30
-rw-r--r--pythonmod/examples/inplace_callbacks.py24
-rw-r--r--pythonmod/interface.i289
-rw-r--r--pythonmod/pythonmod.c157
-rw-r--r--pythonmod/pythonmod.h8
6 files changed, 487 insertions, 54 deletions
diff --git a/pythonmod/doc/modules/functions.rst b/pythonmod/doc/modules/functions.rst
index 49ea7bfa45f0..43c66eb380dd 100644
--- a/pythonmod/doc/modules/functions.rst
+++ b/pythonmod/doc/modules/functions.rst
@@ -103,42 +103,67 @@ Inplace callbacks
:param opt_list_out: :class:`edns_option`. EDNS option list to append options to.
:param region: :class:`regional`
-.. function:: register_inplace_cb_reply(py_cb, env)
+.. function:: inplace_cb_query(qinfo, flags, qstate, addr, zone, region)
+
+ Function prototype for callback functions used in
+ `register_inplace_cb_query`_.
+
+ :param qinfo: :class:`query_info`
+ :param flags: query flags (integer)
+ :param qstate: :class:`module_qstate`
+ :param addr: :class:`sockaddr_storage`
+ :param zone: zone name in wire format (bytes)
+ :param region: :class:`regional`
+
+.. function:: register_inplace_cb_reply(py_cb, env, id)
Register py_cb as an inplace reply callback function.
:param py_cb: Python function that follows `inplace_cb_reply`_'s prototype. **Must** be callable.
:param env: :class:`module_env`
+ :param id: Module ID.
:return: True on success, False otherwise
:rtype: boolean
-.. function:: register_inplace_cb_reply_cache(py_cb, env)
+.. function:: register_inplace_cb_reply_cache(py_cb, env, id)
Register py_cb as an inplace reply_cache callback function.
:param py_cb: Python function that follows `inplace_cb_reply`_'s prototype. **Must** be callable.
:param env: :class:`module_env`
+ :param id: Module ID.
:return: True on success, False otherwise
:rtype: boolean
-.. function:: register_inplace_cb_reply_local(py_cb, env)
+.. function:: register_inplace_cb_reply_local(py_cb, env, id)
Register py_cb as an inplace reply_local callback function.
:param py_cb: Python function that follows `inplace_cb_reply`_'s prototype. **Must** be callable.
:param env: :class:`module_env`
+ :param id: Module ID.
:return: True on success, False otherwise
:rtype: boolean
-.. function:: register_inplace_cb_reply_servfail(py_cb, env)
+.. function:: register_inplace_cb_reply_servfail(py_cb, env, id)
Register py_cb as an inplace reply_servfail callback function.
:param py_cb: Python function that follows `inplace_cb_reply`_'s prototype. **Must** be callable.
:param env: :class:`module_env`
+ :param id: Module ID.
:return: True on success, False otherwise
:rtype: boolean
+.. function:: register_inplace_cb_query(py_cb, env, id)
+
+ Register py_cb as an inplace query callback function.
+
+ :param py_cb: Python function that follows `inplace_cb_query`_'s prototype. **Must** be callable.
+ :param env: :class:`module_env`
+ :param id: Module ID.
+ :return: True on success, False otherwise
+ :rtype: boolean
Logging
-------
diff --git a/pythonmod/doc/modules/struct.rst b/pythonmod/doc/modules/struct.rst
index c74298b8b75d..de7c084e9008 100644
--- a/pythonmod/doc/modules/struct.rst
+++ b/pythonmod/doc/modules/struct.rst
@@ -514,3 +514,33 @@ pythonmod_qstate
Here you can keep your own private data (each thread has own data object).
+sockaddr_storage
+-------------------------
+
+.. class:: sockaddr_storage
+
+ The :class:`sockaddr_storage` provides these data attributes:
+
+ .. attribute:: family
+
+ Address family name as a string. Possible values are `ip4`, `ip6`, and `unix`.
+
+ .. attribute:: addr
+
+ Address in presentation format.
+
+ .. attribute:: raw_addr
+
+ Address in network wire format.
+
+ .. attribute:: port
+
+ Port number. Invalid for Unix address.
+
+ .. attribute:: flowinfo
+
+ Flow info value. Valid only for IPv6 address.
+
+ .. attribute:: scope_id
+
+ Scope ID value. Valid only for IPv6 address.
diff --git a/pythonmod/examples/inplace_callbacks.py b/pythonmod/examples/inplace_callbacks.py
index e47fc8292be2..776add8c29ad 100644
--- a/pythonmod/examples/inplace_callbacks.py
+++ b/pythonmod/examples/inplace_callbacks.py
@@ -247,6 +247,25 @@ def inplace_servfail_callback(qinfo, qstate, rep, rcode, edns, opt_list_out,
return True
+def inplace_query_callback(qinfo, flags, qstate, addr, zone, region, **kwargs):
+ """
+ Function that will be registered as an inplace callback function.
+ It will be called before sending a query to a backend server.
+
+ :param qinfo: query_info struct;
+ :param flags: flags of the query;
+ :param qstate: module qstate. opt_lists are available here;
+ :param addr: struct sockaddr_storage. Address of the backend server;
+ :param zone: zone name in binary;
+ :param region: region to allocate temporary data. Needs to be used when we
+ want to append a new option to opt_lists.
+ :param **kwargs: Dictionary that may contain parameters added in a future
+ release.
+ """
+ log_info("python: outgoing query to {}@{}".format(addr.addr, addr.port))
+ return True
+
+
def init_standard(id, env):
"""
New version of the init function.
@@ -281,6 +300,11 @@ def init_standard(id, env):
if not register_inplace_cb_reply_servfail(inplace_servfail_callback, env, id):
return False
+ # Register the inplace_query_callback function as an inplace callback
+ # before sending a query to a backend server.
+ if not register_inplace_cb_query(inplace_query_callback, env, id):
+ return False
+
return True
diff --git a/pythonmod/interface.i b/pythonmod/interface.i
index 96accb69cca6..5f2559bacffa 100644
--- a/pythonmod/interface.i
+++ b/pythonmod/interface.i
@@ -12,6 +12,8 @@
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
+ #include <netdb.h>
+ #include <sys/un.h>
#include <stdarg.h>
#include "config.h"
#include "util/log.h"
@@ -43,15 +45,21 @@
i = 0;
while (i < len) {
- i += name[i] + 1;
+ i += ((unsigned int)name[i]) + 1;
cnt++;
}
list = PyList_New(cnt);
i = 0; cnt = 0;
while (i < len) {
- PyList_SetItem(list, cnt, PyBytes_FromStringAndSize(name + i + 1, name[i]));
- i += name[i] + 1;
+ char buf[LDNS_MAX_LABELLEN+1];
+ if(((unsigned int)name[i])+1 <= (unsigned int)sizeof(buf) &&
+ i+(int)((unsigned int)name[i]) < len) {
+ memmove(buf, name + i + 1, (unsigned int)name[i]);
+ buf[(unsigned int)name[i]] = 0;
+ PyList_SetItem(list, cnt, PyString_FromString(buf));
+ }
+ i += ((unsigned int)name[i]) + 1;
cnt++;
}
return list;
@@ -159,11 +167,11 @@ struct query_info {
%}
%inline %{
- PyObject* dnameAsStr(const char* dname) {
+ PyObject* dnameAsStr(PyObject* dname) {
char buf[LDNS_MAX_DOMAINLEN+1];
buf[0] = '\0';
- dname_str((uint8_t*)dname, buf);
- return PyBytes_FromString(buf);
+ dname_str((uint8_t*)PyBytes_AsString(dname), buf);
+ return PyString_FromString(buf);
}
%}
@@ -427,63 +435,191 @@ struct dns_msg {
}
/* ************************************************************************************ *
- Structure mesh_state
+ Structure sockaddr_storage
* ************************************************************************************ */
-struct mesh_state {
- struct mesh_reply* reply_list;
-};
-struct mesh_reply {
- struct mesh_reply* next;
- struct comm_reply query_reply;
-};
+struct sockaddr_storage {};
-struct comm_reply {
+%inline %{
+ static size_t _sockaddr_storage_len(const struct sockaddr_storage *ss) {
+ if (ss == NULL) {
+ return 0;
+ }
-};
+ switch (ss->ss_family) {
+ case AF_INET: return sizeof(struct sockaddr_in);
+ case AF_INET6: return sizeof(struct sockaddr_in6);
+ case AF_UNIX: return sizeof(struct sockaddr_un);
+ default:
+ return 0;
+ }
+ }
-%inline %{
+ PyObject *_sockaddr_storage_family(const struct sockaddr_storage *ss) {
+ if (ss == NULL) {
+ return Py_None;
+ }
+
+ switch (ss->ss_family) {
+ case AF_INET: return PyUnicode_FromString("ip4");
+ case AF_INET6: return PyUnicode_FromString("ip6");
+ case AF_UNIX: return PyUnicode_FromString("unix");
+ default:
+ return Py_None;
+ }
+ }
+
+ PyObject *_sockaddr_storage_addr(const struct sockaddr_storage *ss) {
+ const struct sockaddr *sa;
+ size_t sa_len;
+ char name[NI_MAXHOST] = {0};
+
+ if (ss == NULL) {
+ return Py_None;
+ }
+
+ sa = (struct sockaddr *)ss;
+ sa_len = _sockaddr_storage_len(ss);
+ if (sa_len == 0) {
+ return Py_None;
+ }
+
+ if (getnameinfo(sa, sa_len, name, sizeof(name), NULL, 0, NI_NUMERICHOST) != 0) {
+ return Py_None;
+ }
+
+ return PyUnicode_FromString(name);
+ }
+
+ PyObject *_sockaddr_storage_raw_addr(const struct sockaddr_storage *ss) {
+ size_t sa_len;
+
+ if (ss == NULL) {
+ return Py_None;
+ }
+
+ sa_len = _sockaddr_storage_len(ss);
+ if (sa_len == 0) {
+ return Py_None;
+ }
+
+ if (ss->ss_family == AF_INET) {
+ const struct sockaddr_in *sa = (struct sockaddr_in *)ss;
+ const struct in_addr *raw = (struct in_addr *)&sa->sin_addr;
+ return PyBytes_FromStringAndSize((const char *)raw, sizeof(*raw));
+ }
+
+ if (ss->ss_family == AF_INET6) {
+ const struct sockaddr_in6 *sa = (struct sockaddr_in6 *)ss;
+ const struct in6_addr *raw = (struct in6_addr *)&sa->sin6_addr;
+ return PyBytes_FromStringAndSize((const char *)raw, sizeof(*raw));
+ }
+
+ if (ss->ss_family == AF_UNIX) {
+ const struct sockaddr_un *sa = (struct sockaddr_un *)ss;
+ return PyBytes_FromString(sa->sun_path);
+ }
- PyObject* _comm_reply_addr_get(struct comm_reply* reply) {
- char dest[64];
- reply_addr2str(reply, dest, 64);
- if (dest[0] == 0)
return Py_None;
- return PyBytes_FromString(dest);
- }
+ }
- PyObject* _comm_reply_family_get(struct comm_reply* reply) {
+ PyObject *_sockaddr_storage_port(const struct sockaddr_storage *ss) {
+ if (ss == NULL) {
+ return Py_None;
+ }
- int af = (int)((struct sockaddr_in*) &(reply->addr))->sin_family;
+ if (ss->ss_family == AF_INET) {
+ const struct sockaddr_in *sa4 = (struct sockaddr_in *)ss;
+ return PyInt_FromLong(ntohs(sa4->sin_port));
+ }
- switch(af) {
- case AF_INET: return PyBytes_FromString("ip4");
- case AF_INET6: return PyBytes_FromString("ip6");
- case AF_UNIX: return PyBytes_FromString("unix");
+ if (ss->ss_family == AF_INET6) {
+ const struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)ss;
+ return PyInt_FromLong(ntohs(sa6->sin6_port));
}
return Py_None;
- }
+ }
- PyObject* _comm_reply_port_get(struct comm_reply* reply) {
- uint16_t port;
- port = ntohs(((struct sockaddr_in*)&(reply->addr))->sin_port);
- return PyInt_FromLong(port);
- }
+ PyObject *_sockaddr_storage_flowinfo(const struct sockaddr_storage *ss) {
+ const struct sockaddr_in6 *sa6;
+
+ if (ss == NULL || ss->ss_family != AF_INET6) {
+ return Py_None;
+ }
+ sa6 = (struct sockaddr_in6 *)ss;
+ return PyInt_FromLong(ntohl(sa6->sin6_flowinfo));
+ }
+
+ PyObject *_sockaddr_storage_scope_id(const struct sockaddr_storage *ss) {
+ const struct sockaddr_in6 *sa6;
+
+ if (ss == NULL || ss->ss_family != AF_INET6) {
+ return Py_None;
+ }
+
+ sa6 = (struct sockaddr_in6 *)ss;
+ return PyInt_FromLong(ntohl(sa6->sin6_scope_id));
+ }
%}
+%extend sockaddr_storage {
+ %pythoncode %{
+ def _family_get(self): return _sockaddr_storage_family(self)
+ __swig_getmethods__["family"] = _family_get
+ if _newclass: family = _swig_property(_family_get)
+
+ def _addr_get(self): return _sockaddr_storage_addr(self)
+ __swig_getmethods__["addr"] = _addr_get
+ if _newclass: addr = _swig_property(_addr_get)
+
+ def _raw_addr_get(self): return _sockaddr_storage_raw_addr(self)
+ __swig_getmethods__["raw_addr"] = _raw_addr_get
+ if _newclass: raw_addr = _swig_property(_raw_addr_get)
+
+ def _port_get(self): return _sockaddr_storage_port(self)
+ __swig_getmethods__["port"] = _port_get
+ if _newclass: port = _swig_property(_port_get)
+
+ def _flowinfo_get(self): return _sockaddr_storage_flowinfo(self)
+ __swig_getmethods__["flowinfo"] = _flowinfo_get
+ if _newclass: flowinfo = _swig_property(_flowinfo_get)
+
+ def _scope_id_get(self): return _sockaddr_storage_scope_id(self)
+ __swig_getmethods__["scope_id"] = _scope_id_get
+ if _newclass: scope_id = _swig_property(_scope_id_get)
+ %}
+}
+
+/* ************************************************************************************ *
+ Structure mesh_state
+ * ************************************************************************************ */
+struct mesh_state {
+ struct mesh_reply* reply_list;
+};
+
+struct mesh_reply {
+ struct mesh_reply* next;
+ struct comm_reply query_reply;
+};
+
+%rename(_addr) comm_reply::addr;
+struct comm_reply {
+ struct sockaddr_storage addr;
+};
+
%extend comm_reply {
%pythoncode %{
- def _addr_get(self): return _comm_reply_addr_get(self)
+ def _addr_get(self): return _sockaddr_storage_addr(self._addr)
__swig_getmethods__["addr"] = _addr_get
if _newclass:addr = _swig_property(_addr_get)
- def _port_get(self): return _comm_reply_port_get(self)
+ def _port_get(self): return _sockaddr_storage_port(self._addr)
__swig_getmethods__["port"] = _port_get
if _newclass:port = _swig_property(_port_get)
- def _family_get(self): return _comm_reply_family_get(self)
+ def _family_get(self): return _sockaddr_storage_family(self._addr)
__swig_getmethods__["family"] = _family_get
if _newclass:family = _swig_property(_family_get)
%}
@@ -1081,7 +1217,7 @@ int checkList(PyObject *l)
for (i=0; i < PyList_Size(l); i++)
{
item = PyList_GetItem(l, i);
- if (!PyBytes_Check(item))
+ if (!PyBytes_Check(item) && !PyUnicode_Check(item))
return 0;
}
return 1;
@@ -1096,23 +1232,40 @@ int pushRRList(sldns_buffer* qb, PyObject *l, uint32_t default_ttl, int qsec,
PyObject* item;
int i;
size_t len;
+ char* s;
+ PyObject* ascstr;
for (i=0; i < PyList_Size(l); i++)
{
+ ascstr = NULL;
item = PyList_GetItem(l, i);
+ if(PyObject_TypeCheck(item, &PyBytes_Type)) {
+ s = PyBytes_AsString(item);
+ } else {
+ ascstr = PyUnicode_AsASCIIString(item);
+ s = PyBytes_AsString(ascstr);
+ }
len = sldns_buffer_remaining(qb);
if(qsec) {
- if(sldns_str2wire_rr_question_buf(PyBytes_AsString(item),
+ if(sldns_str2wire_rr_question_buf(s,
sldns_buffer_current(qb), &len, NULL, NULL, 0, NULL, 0)
- != 0)
+ != 0) {
+ if(ascstr)
+ Py_DECREF(ascstr);
return 0;
+ }
} else {
- if(sldns_str2wire_rr_buf(PyBytes_AsString(item),
+ if(sldns_str2wire_rr_buf(s,
sldns_buffer_current(qb), &len, NULL, default_ttl,
- NULL, 0, NULL, 0) != 0)
+ NULL, 0, NULL, 0) != 0) {
+ if(ascstr)
+ Py_DECREF(ascstr);
return 0;
+ }
}
+ if(ascstr)
+ Py_DECREF(ascstr);
sldns_buffer_skip(qb, len);
sldns_buffer_write_u16_at(qb, count_offset,
@@ -1437,6 +1590,54 @@ int edns_opt_list_append(struct edns_option** list, uint16_t code, size_t len,
return python_inplace_cb_register(inplace_cb_reply_servfail,
py_cb, env, id);
}
+
+ int python_inplace_cb_query_generic(
+ struct query_info* qinfo, uint16_t flags, struct module_qstate* qstate,
+ struct sockaddr_storage* addr, socklen_t addrlen,
+ uint8_t* zone, size_t zonelen, struct regional* region, int id,
+ void* python_callback)
+ {
+ int res = 0;
+ PyObject *func = python_callback;
+
+ PyGILState_STATE gstate = PyGILState_Ensure();
+
+ PyObject *py_qinfo = SWIG_NewPointerObj((void*) qinfo, SWIGTYPE_p_query_info, 0);
+ PyObject *py_qstate = SWIG_NewPointerObj((void*) qstate, SWIGTYPE_p_module_qstate, 0);
+ PyObject *py_addr = SWIG_NewPointerObj((void *) addr, SWIGTYPE_p_sockaddr_storage, 0);
+ PyObject *py_zone = PyBytes_FromStringAndSize((const char *)zone, zonelen);
+ PyObject *py_region = SWIG_NewPointerObj((void*) region, SWIGTYPE_p_regional, 0);
+
+ PyObject *py_args = Py_BuildValue("(OiOOOO)", py_qinfo, flags, py_qstate, py_addr, py_zone, py_region);
+ PyObject *py_kwargs = Py_BuildValue("{}");
+ PyObject *result = PyObject_Call(func, py_args, py_kwargs);
+ if (result) {
+ res = PyInt_AsLong(result);
+ }
+
+ Py_XDECREF(py_qinfo);
+ Py_XDECREF(py_qstate);
+ Py_XDECREF(py_addr);
+ Py_XDECREF(py_zone);
+ Py_XDECREF(py_region);
+
+ Py_XDECREF(py_args);
+ Py_XDECREF(py_kwargs);
+ Py_XDECREF(result);
+
+ PyGILState_Release(gstate);
+
+ return res;
+ }
+
+ static int register_inplace_cb_query(PyObject* py_cb,
+ struct module_env* env, int id)
+ {
+ int ret = inplace_cb_register(python_inplace_cb_query_generic,
+ inplace_cb_query, (void*) py_cb, env, id);
+ if (ret) Py_INCREF(py_cb);
+ return ret;
+ }
%}
/* C declarations */
int inplace_cb_register(void* cb, enum inplace_cb_list_type type, void* cbarg,
@@ -1451,3 +1652,5 @@ static int register_inplace_cb_reply_local(PyObject* py_cb,
struct module_env* env, int id);
static int register_inplace_cb_reply_servfail(PyObject* py_cb,
struct module_env* env, int id);
+static int register_inplace_cb_query(PyObject *py_cb,
+ struct module_env* env, int id);
diff --git a/pythonmod/pythonmod.c b/pythonmod/pythonmod.c
index 35a20434b935..a668ecc23cc7 100644
--- a/pythonmod/pythonmod.c
+++ b/pythonmod/pythonmod.c
@@ -110,6 +110,136 @@ struct pythonmod_qstate {
#include "pythonmod/interface.h"
#endif
+/** log python error */
+static void
+log_py_err(void)
+{
+ char *result = NULL;
+ const char* iomod = "cStringIO";
+ PyObject *modStringIO = NULL;
+ PyObject *modTB = NULL;
+ PyObject *obFuncStringIO = NULL;
+ PyObject *obStringIO = NULL;
+ PyObject *obFuncTB = NULL;
+ PyObject *argsTB = NULL;
+ PyObject *obResult = NULL;
+ PyObject *ascstr = NULL;
+ PyObject *exc_typ, *exc_val, *exc_tb;
+
+ /* Fetch the error state now before we cruch it */
+ /* exc val contains the error message
+ * exc tb contains stack traceback and other info. */
+ PyErr_Fetch(&exc_typ, &exc_val, &exc_tb);
+ PyErr_NormalizeException(&exc_typ, &exc_val, &exc_tb);
+
+ /* Import the modules we need - cStringIO and traceback */
+ modStringIO = PyImport_ImportModule("cStringIO");
+ if (modStringIO==NULL) {
+ /* python 1.4 and before */
+ modStringIO = PyImport_ImportModule("StringIO");
+ iomod = "StringIO";
+ }
+ if (modStringIO==NULL) {
+ /* python 3 */
+ modStringIO = PyImport_ImportModule("io");
+ iomod = "io";
+ }
+ if (modStringIO==NULL) {
+ log_err("pythonmod: cannot print exception, "
+ "cannot ImportModule cStringIO or StringIO or io");
+ goto cleanup;
+ }
+ modTB = PyImport_ImportModule("traceback");
+ if (modTB==NULL) {
+ log_err("pythonmod: cannot print exception, "
+ "cannot ImportModule traceback");
+ goto cleanup;
+ }
+
+ /* Construct a cStringIO object */
+ obFuncStringIO = PyObject_GetAttrString(modStringIO, "StringIO");
+ if (obFuncStringIO==NULL) {
+ log_err("pythonmod: cannot print exception, "
+ "cannot GetAttrString %s.StringIO", iomod);
+ goto cleanup;
+ }
+ obStringIO = PyObject_CallObject(obFuncStringIO, NULL);
+ if (obStringIO==NULL) {
+ log_err("pythonmod: cannot print exception, "
+ "cannot call %s.StringIO()", iomod);
+ goto cleanup;
+ }
+
+ /* Get the traceback.print_exception function, and call it. */
+ obFuncTB = PyObject_GetAttrString(modTB, "print_exception");
+ if (obFuncTB==NULL) {
+ log_err("pythonmod: cannot print exception, "
+ "cannot GetAttrString traceback.print_exception");
+ goto cleanup;
+ }
+ argsTB = Py_BuildValue("OOOOO", (exc_typ ? exc_typ : Py_None),
+ (exc_val ? exc_val : Py_None), (exc_tb ? exc_tb : Py_None),
+ Py_None, obStringIO);
+ if (argsTB==NULL) {
+ log_err("pythonmod: cannot print exception, "
+ "cannot BuildValue for print_exception");
+ goto cleanup;
+ }
+
+ obResult = PyObject_CallObject(obFuncTB, argsTB);
+ if (obResult==NULL) {
+ PyErr_Print();
+ log_err("pythonmod: cannot print exception, "
+ "call traceback.print_exception() failed");
+ goto cleanup;
+ }
+
+ /* Now call the getvalue() method in the StringIO instance */
+ Py_DECREF(obFuncStringIO);
+ obFuncStringIO = PyObject_GetAttrString(obStringIO, "getvalue");
+ if (obFuncStringIO==NULL) {
+ log_err("pythonmod: cannot print exception, "
+ "cannot GetAttrString StringIO.getvalue");
+ goto cleanup;
+ }
+ Py_DECREF(obResult);
+ obResult = PyObject_CallObject(obFuncStringIO, NULL);
+ if (obResult==NULL) {
+ log_err("pythonmod: cannot print exception, "
+ "call StringIO.getvalue() failed");
+ goto cleanup;
+ }
+
+ /* And it should be a string all ready to go - duplicate it. */
+ if (!PyString_Check(obResult) && !PyUnicode_Check(obResult)) {
+ log_err("pythonmod: cannot print exception, "
+ "StringIO.getvalue() result did not String_Check"
+ " or Unicode_Check");
+ goto cleanup;
+ }
+ if(PyString_Check(obResult)) {
+ result = PyString_AsString(obResult);
+ } else {
+ ascstr = PyUnicode_AsASCIIString(obResult);
+ result = PyBytes_AsString(ascstr);
+ }
+ log_err("pythonmod: python error: %s", result);
+
+cleanup:
+ Py_XDECREF(modStringIO);
+ Py_XDECREF(modTB);
+ Py_XDECREF(obFuncStringIO);
+ Py_XDECREF(obStringIO);
+ Py_XDECREF(obFuncTB);
+ Py_XDECREF(argsTB);
+ Py_XDECREF(obResult);
+ Py_XDECREF(ascstr);
+
+ /* clear the exception, by not restoring it */
+ /* Restore the exception state */
+ /* PyErr_Restore(exc_typ, exc_val, exc_tb); */
+}
+
int pythonmod_init(struct module_env* env, int id)
{
/* Initialize module */
@@ -193,13 +323,26 @@ int pythonmod_init(struct module_env* env, int id)
/* TODO: deallocation of pe->... if an error occurs */
- if (PyRun_SimpleFile(script_py, pe->fname) < 0)
- {
+ if (PyRun_SimpleFile(script_py, pe->fname) < 0) {
log_err("pythonmod: can't parse Python script %s", pe->fname);
+ /* print the error to logs too, run it again */
+ fseek(script_py, 0, SEEK_SET);
+ /* we don't run the file, like this, because then side-effects
+ * s = PyRun_File(script_py, pe->fname, Py_file_input,
+ * PyModule_GetDict(PyImport_AddModule("__main__")), pe->dict);
+ * could happen (again). Instead we parse the file again to get
+ * the error string in the logs, for when the daemon has stderr
+ * removed. SimpleFile run already printed to stderr, for then
+ * this is called from unbound-checkconf or unbound -dd the user
+ * has a nice formatted error.
+ */
+ /* ignore the NULL return of _node, it is NULL due to the parse failure
+ * that we are expecting */
+ (void)PyParser_SimpleParseFile(script_py, pe->fname, Py_file_input);
+ log_py_err();
PyGILState_Release(gil);
return 0;
}
-
fclose(script_py);
if ((pe->func_init = PyDict_GetItemString(pe->dict, "init_standard")) == NULL)
@@ -244,7 +387,7 @@ int pythonmod_init(struct module_env* env, int id)
if (PyErr_Occurred())
{
log_err("pythonmod: Exception occurred in function init");
- PyErr_Print();
+ log_py_err();
Py_XDECREF(res);
Py_XDECREF(py_init_arg);
PyGILState_Release(gil);
@@ -274,7 +417,7 @@ void pythonmod_deinit(struct module_env* env, int id)
res = PyObject_CallFunction(pe->func_deinit, "i", id);
if (PyErr_Occurred()) {
log_err("pythonmod: Exception occurred in function deinit");
- PyErr_Print();
+ log_py_err();
}
/* Free result if any */
Py_XDECREF(res);
@@ -312,7 +455,7 @@ void pythonmod_inform_super(struct module_qstate* qstate, int id, struct module_
if (PyErr_Occurred())
{
log_err("pythonmod: Exception occurred in function inform_super");
- PyErr_Print();
+ log_py_err();
qstate->ext_state[id] = module_error;
}
else if ((res == NULL) || (!PyObject_IsTrue(res)))
@@ -353,7 +496,7 @@ void pythonmod_operate(struct module_qstate* qstate, enum module_ev event,
if (PyErr_Occurred())
{
log_err("pythonmod: Exception occurred in function operate, event: %s", strmodulevent(event));
- PyErr_Print();
+ log_py_err();
qstate->ext_state[id] = module_error;
}
else if ((res == NULL) || (!PyObject_IsTrue(res)))
diff --git a/pythonmod/pythonmod.h b/pythonmod/pythonmod.h
index 991ae51a20a7..ae8af27eb22b 100644
--- a/pythonmod/pythonmod.h
+++ b/pythonmod/pythonmod.h
@@ -74,4 +74,12 @@ int python_inplace_cb_reply_generic(struct query_info* qinfo,
struct edns_data* edns, struct edns_option** opt_list_out,
struct comm_reply* repinfo, struct regional* region, int id,
void* python_callback);
+
+/** Declared here for fptr_wlist access. The definition is in interface.i. */
+int python_inplace_cb_query_generic(
+ struct query_info* qinfo, uint16_t flags, struct module_qstate* qstate,
+ struct sockaddr_storage* addr, socklen_t addrlen,
+ uint8_t* zone, size_t zonelen, struct regional* region, int id,
+ void* python_callback);
+
#endif /* PYTHONMOD_H */