diff options
author | Dag-Erling Smørgrav <des@FreeBSD.org> | 2019-02-06 12:31:02 +0000 |
---|---|---|
committer | Dag-Erling Smørgrav <des@FreeBSD.org> | 2019-02-06 12:31:02 +0000 |
commit | 9c9d011eed674ddd7e4a0a148691887afb9e75cd (patch) | |
tree | cd45bceeed24e66e5b2838e8589d2c111cf691c6 /pythonmod | |
parent | 089d83fbd0b24f957b753d440f188ddadaabf4ff (diff) | |
download | src-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.rst | 33 | ||||
-rw-r--r-- | pythonmod/doc/modules/struct.rst | 30 | ||||
-rw-r--r-- | pythonmod/examples/inplace_callbacks.py | 24 | ||||
-rw-r--r-- | pythonmod/interface.i | 289 | ||||
-rw-r--r-- | pythonmod/pythonmod.c | 157 | ||||
-rw-r--r-- | pythonmod/pythonmod.h | 8 |
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 */ |