diff options
Diffstat (limited to 'pythonmod/interface.i')
| -rw-r--r-- | pythonmod/interface.i | 427 |
1 files changed, 395 insertions, 32 deletions
diff --git a/pythonmod/interface.i b/pythonmod/interface.i index 4b20c6ec135c..89d138486606 100644 --- a/pythonmod/interface.i +++ b/pythonmod/interface.i @@ -1,7 +1,6 @@ /* * interface.i: unbound python module */ - %module unboundmodule %{ /** @@ -34,10 +33,10 @@ #include "sldns/pkthdr.h" %} -%include "stdint.i" // uint_16_t can be known type now +%include "stdint.i" /* uint_16_t can be known type now */ %inline %{ - //converts [len][data][len][data][0] string to a List of labels (PyBytes) + /* converts [len][data][len][data][0] string to a List of labels (PyBytes) */ PyObject* GetNameAsLabelList(const char* name, int len) { PyObject* list; int cnt=0, i; @@ -202,13 +201,16 @@ struct packed_rrset_key { char* dname; size_t dname_len; uint32_t flags; - uint16_t type; //rrset type in network format - uint16_t rrset_class; //rrset class in network format + uint16_t type; /* rrset type in network format */ + uint16_t rrset_class; /* rrset class in network format */ %mutable; }; -//This subroutine converts values between the host and network byte order. -//Specifically, ntohs() converts 16-bit quantities from network byte order to host byte order. +/** + * This subroutine converts values between the host and network byte order. + * Specifically, ntohs() converts 16-bit quantities from network byte order to + * host byte order. + */ uint16_t ntohs(uint16_t netshort); %inline %{ @@ -269,17 +271,24 @@ struct lruhash_entry { %ignore packed_rrset_data::rr_data; struct packed_rrset_data { - uint32_t ttl; //TTL (in seconds like time()) + /* TTL (in seconds like time()) */ + uint32_t ttl; - size_t count; //number of rrs - size_t rrsig_count; //number of rrsigs + /* number of rrs */ + size_t count; + /* number of rrsigs */ + size_t rrsig_count; enum rrset_trust trust; enum sec_status security; - size_t* rr_len; //length of every rr's rdata - uint32_t *rr_ttl; //ttl of every rr - uint8_t** rr_data; //array of pointers to every rr's rdata; The rr_data[i] rdata is stored in uncompressed wireformat. + /* length of every rr's rdata */ + size_t* rr_len; + /* ttl of every rr */ + uint32_t *rr_ttl; + /* array of pointers to every rr's rdata. The rr_data[i] rdata is stored in + * uncompressed wireformat. */ + uint8_t** rr_data; }; %pythoncode %{ @@ -359,10 +368,10 @@ struct reply_info { size_t an_numrrsets; size_t ns_numrrsets; size_t ar_numrrsets; - size_t rrset_count; // an_numrrsets + ns_numrrsets + ar_numrrsets + size_t rrset_count; /* an_numrrsets + ns_numrrsets + ar_numrrsets */ struct ub_packed_rrset_key** rrsets; - struct rrset_ref ref[1]; //? + struct rrset_ref ref[1]; /* ? */ }; struct rrset_ref { @@ -396,11 +405,11 @@ struct dns_msg { struct rrset_ref* _rrset_ref_get(struct reply_info* r, int idx) { if ((r != NULL) && (idx >= 0) && ((size_t)idx < r->rrset_count)) { -//printf("_rrset_ref_get: %lX key:%lX\n", r->ref + idx, r->ref[idx].key); +/* printf("_rrset_ref_get: %lX key:%lX\n", r->ref + idx, r->ref[idx].key); */ return &(r->ref[idx]); -// return &(r->ref[idx]); +/* return &(r->ref[idx]); */ } -//printf("_rrset_ref_get: NULL\n"); +/* printf("_rrset_ref_get: NULL\n"); */ return NULL; } %} @@ -479,30 +488,166 @@ struct comm_reply { if _newclass:family = _swig_property(_family_get) %} } + +/* ************************************************************************************ * + Structure edns_option + * ************************************************************************************ */ +/* Rename the members to follow the python convention of marking them as + * private. Access to the opt_code and opt_data members is given by the later + * python defined code and data members respectively. */ +%rename(_next) edns_option::next; +%rename(_opt_code) edns_option::opt_code; +%rename(_opt_len) edns_option::opt_len; +%rename(_opt_data) edns_option::opt_data; +struct edns_option { + struct edns_option* next; + uint16_t opt_code; + size_t opt_len; + uint8_t* opt_data; +}; + +%inline %{ + PyObject* _edns_option_opt_code_get(struct edns_option* option) { + uint16_t opt_code = option->opt_code; + return PyInt_FromLong(opt_code); + } + + PyObject* _edns_option_opt_data_get(struct edns_option* option) { + return PyByteArray_FromStringAndSize((uint8_t*)option->opt_data, + option->opt_len); + } +%} +%extend edns_option { + %pythoncode %{ + def _opt_code_get(self): return _edns_option_opt_code_get(self) + __swig_getmethods__["code"] = _opt_code_get + if _newclass: opt_code = _swig_property(_opt_code_get) + + def _opt_data_get(self): return _edns_option_opt_data_get(self) + __swig_getmethods__["data"] = _opt_data_get + if _newclass: opt_data = _swig_property(_opt_data_get) + %} +} + /* ************************************************************************************ * + Structure edns_data + * ************************************************************************************ */ +/* This is ignored because we will pass a double pointer of this to Python + * with custom getmethods. This is done to bypass Swig's behavior to pass NULL + * pointers as None. */ +%ignore edns_data::opt_list; +struct edns_data { + int edns_present; + uint8_t ext_rcode; + uint8_t edns_version; + uint16_t bits; + uint16_t udp_size; + struct edns_option* opt_list; +}; +%inline %{ + struct edns_option** _edns_data_opt_list_get(struct edns_data* edns) { + return &edns->opt_list; + } +%} +%extend edns_data { + %pythoncode %{ + def _opt_list_iter(self): return EdnsOptsListIter(self.opt_list) + __swig_getmethods__["opt_list_iter"] = _opt_list_iter + if _newclass:opt_list_iter = _swig_property(_opt_list_iter) + def _opt_list(self): return _edns_data_opt_list_get(self) + __swig_getmethods__["opt_list"] = _opt_list + if _newclass:opt_list = _swig_property(_opt_list) + %} +} + +/* ************************************************************************************ * + Structure module_env + * ************************************************************************************ */ +struct module_env { + struct config_file* cfg; + struct slabhash* msg_cache; + struct rrset_cache* rrset_cache; + struct infra_cache* infra_cache; + struct key_cache* key_cache; + + /* --- services --- */ + struct outbound_entry* (*send_query)(struct query_info* qinfo, + uint16_t flags, int dnssec, int want_dnssec, int nocaps, + struct sockaddr_storage* addr, socklen_t addrlen, + uint8_t* zone, size_t zonelen, int ssl_upstream, + struct module_qstate* q); + void (*detach_subs)(struct module_qstate* qstate); + int (*attach_sub)(struct module_qstate* qstate, + struct query_info* qinfo, uint16_t qflags, int prime, + int valrec, struct module_qstate** newq); + void (*kill_sub)(struct module_qstate* newq); + int (*detect_cycle)(struct module_qstate* qstate, + struct query_info* qinfo, uint16_t flags, int prime, + int valrec); + + struct regional* scratch; + struct sldns_buffer* scratch_buffer; + struct worker* worker; + struct mesh_area* mesh; + struct alloc_cache* alloc; + struct ub_randstate* rnd; + time_t* now; + struct timeval* now_tv; + int need_to_validate; + struct val_anchors* anchors; + struct val_neg_cache* neg_cache; + struct comm_timer* probe_timer; + struct iter_forwards* fwds; + struct iter_hints* hints; + void* modinfo[MAX_MODULE]; + + void* inplace_cb_lists[inplace_cb_types_total]; + struct edns_known_option* edns_known_options; + size_t edns_known_options_num; +}; + + +/* ************************************************************************************ * Structure module_qstate * ************************************************************************************ */ %ignore module_qstate::ext_state; %ignore module_qstate::minfo; +/* These are ignored because we will pass a double pointer of them to Python + * with custom getmethods. This is done to bypass Swig's behavior to pass NULL + * pointers as None. */ +%ignore module_qstate::edns_opts_front_in; +%ignore module_qstate::edns_opts_back_out; +%ignore module_qstate::edns_opts_back_in; +%ignore module_qstate::edns_opts_front_out; + /* Query state */ struct module_qstate { struct query_info qinfo; - uint16_t query_flags; //See QF_BIT_xx constants - int is_priming; + uint16_t query_flags; /* See QF_BIT_xx constants */ + int is_priming; + int is_valrec; struct comm_reply* reply; struct dns_msg* return_msg; - int return_rcode; + int return_rcode; struct regional* region; /* unwrapped */ - int curmod; + int curmod; - enum module_ext_state ext_state[MAX_MODULE]; - void* minfo[MAX_MODULE]; + enum module_ext_state ext_state[MAX_MODULE]; + void* minfo[MAX_MODULE]; + time_t prefetch_leeway; struct module_env* env; /* unwrapped */ struct mesh_state* mesh_info; + + struct edns_option* edns_opts_front_in; + struct edns_option* edns_opts_back_out; + struct edns_option* edns_opts_back_in; + struct edns_option* edns_opts_front_out; + int no_cache_lookup; + int no_cache_store; }; %constant int MODULE_COUNT = MAX_MODULE; @@ -540,6 +685,25 @@ struct module_qstate { def __getitem__(self, index): return _unboundmodule._ext_state_get(self.obj, index) def __setitem__(self, index, value): _unboundmodule._ext_state_set(self.obj, index, value) def __len__(self): return _unboundmodule.MODULE_COUNT + + class EdnsOptsListIter: + def __init__(self, obj): + self._current = obj + self._temp = None + def __iter__(self): return self + def __next__(self): + """Python 3 compatibility""" + return self._get_next() + def next(self): + """Python 2 compatibility""" + return self._get_next() + def _get_next(self): + if not edns_opt_list_is_empty(self._current): + self._temp = self._current + self._current = _p_p_edns_option_get_next(self._current) + return _dereference_edns_option(self._temp) + else: + raise StopIteration %} %inline %{ @@ -549,12 +713,42 @@ struct module_qstate { } return 0; } - + void _ext_state_set(struct module_qstate* q, int idx, enum module_ext_state state) { if ((q != NULL) && (idx >= 0) && (idx < MAX_MODULE)) { q->ext_state[idx] = state; } } + + int edns_opt_list_is_empty(struct edns_option** opt) { + if (!opt || !(*opt)) return 1; + return 0; + } + + struct edns_option* _dereference_edns_option(struct edns_option** opt) { + if (!opt) return NULL; + return *opt; + } + + struct edns_option** _p_p_edns_option_get_next(struct edns_option** opt) { + return &(*opt)->next; + } + + struct edns_option** _edns_opts_front_in_get(struct module_qstate* q) { + return &q->edns_opts_front_in; + } + + struct edns_option** _edns_opts_back_out_get(struct module_qstate* q) { + return &q->edns_opts_back_out; + } + + struct edns_option** _edns_opts_back_in_get(struct module_qstate* q) { + return &q->edns_opts_back_in; + } + + struct edns_option** _edns_opts_front_out_get(struct module_qstate* q) { + return &q->edns_opts_front_out; + } %} %extend module_qstate { @@ -566,6 +760,32 @@ struct module_qstate { def __ext_state_get(self): return ExtState(self) __swig_getmethods__["ext_state"] = __ext_state_get if _newclass:ext_state = _swig_property(__ext_state_get)#, __ext_state_set) + + def _edns_opts_front_in_iter(self): return EdnsOptsListIter(self.edns_opts_front_in) + __swig_getmethods__["edns_opts_front_in_iter"] = _edns_opts_front_in_iter + if _newclass:edns_opts_front_in_iter = _swig_property(_edns_opts_front_in_iter) + def _edns_opts_back_out_iter(self): return EdnsOptsListIter(self.edns_opts_back_out) + __swig_getmethods__["edns_opts_back_out_iter"] = _edns_opts_back_out_iter + if _newclass:edns_opts_back_out_iter = _swig_property(_edns_opts_back_out_iter) + def _edns_opts_back_in_iter(self): return EdnsOptsListIter(self.edns_opts_back_in) + __swig_getmethods__["edns_opts_back_in_iter"] = _edns_opts_back_in_iter + if _newclass:edns_opts_back_in_iter = _swig_property(_edns_opts_back_in_iter) + def _edns_opts_front_out_iter(self): return EdnsOptsListIter(self.edns_opts_front_out) + __swig_getmethods__["edns_opts_front_out_iter"] = _edns_opts_front_out_iter + if _newclass:edns_opts_front_out_iter = _swig_property(_edns_opts_front_out_iter) + + def _edns_opts_front_in(self): return _edns_opts_front_in_get(self) + __swig_getmethods__["edns_opts_front_in"] = _edns_opts_front_in + if _newclass:edns_opts_front_in = _swig_property(_edns_opts_front_in) + def _edns_opts_back_out(self): return _edns_opts_back_out_get(self) + __swig_getmethods__["edns_opts_back_out"] = _edns_opts_back_out + if _newclass:edns_opts_back_out = _swig_property(_edns_opts_back_out) + def _edns_opts_back_in(self): return _edns_opts_back_in_get(self) + __swig_getmethods__["edns_opts_back_in"] = _edns_opts_back_in + if _newclass:edns_opts_back_in = _swig_property(_edns_opts_back_in) + def _edns_opts_front_out(self): return _edns_opts_front_out_get(self) + __swig_getmethods__["edns_opts_front_out"] = _edns_opts_front_out + if _newclass:edns_opts_front_out = _swig_property(_edns_opts_front_out) %} } @@ -1037,8 +1257,9 @@ struct delegpt* find_delegation(struct module_qstate* qstate, char *nm, size_t n /* ************************************************************************************ * Functions * ************************************************************************************ */ - -// Various debuging functions +/****************************** + * Various debuging functions * + ******************************/ void verbose(enum verbosity_value level, const char* format, ...); void log_info(const char* format, ...); void log_err(const char* format, ...); @@ -1048,24 +1269,166 @@ void log_dns_msg(const char* str, struct query_info* qinfo, struct reply_info* r void log_query_info(enum verbosity_value v, const char* str, struct query_info* qinf); void regional_log_stats(struct regional *r); -// Free allocated memory from marked sources returning corresponding types +/*************************************************************************** + * Free allocated memory from marked sources returning corresponding types * + ***************************************************************************/ %typemap(newfree, noblock = 1) char * { free($1); } -// Mark as source returning newly allocated memory +/*************************************************** + * Mark as source returning newly allocated memory * + ***************************************************/ %newobject sldns_wire2str_type; %newobject sldns_wire2str_class; -// LDNS functions +/****************** + * LDNS functions * + ******************/ char *sldns_wire2str_type(const uint16_t atype); char *sldns_wire2str_class(const uint16_t aclass); -// Functions from pythonmod_utils +/********************************** + * Functions from pythonmod_utils * + **********************************/ int storeQueryInCache(struct module_qstate* qstate, struct query_info* qinfo, struct reply_info* msgrep, int is_referral); void invalidateQueryInCache(struct module_qstate* qstate, struct query_info* qinfo); -// Module conversion functions +/******************************* + * Module conversion functions * + *******************************/ const char* strextstate(enum module_ext_state s); const char* strmodulevent(enum module_ev e); +/************************** + * Edns related functions * + **************************/ +struct edns_option* edns_opt_list_find(struct edns_option* list, uint16_t code); +int edns_register_option(uint16_t opt_code, int bypass_cache_stage, + int no_aggregation, struct module_env* env); + +%pythoncode %{ + def register_edns_option(env, code, bypass_cache_stage=False, + no_aggregation=False): + """Wrapper function to provide keyword attributes.""" + return edns_register_option(code, bypass_cache_stage, + no_aggregation, env) +%} + +/****************************** + * Callback related functions * + ******************************/ +/* typemap to check if argument is callable */ +%typemap(in) PyObject *py_cb { + if (!PyCallable_Check($input)) { + SWIG_exception_fail(SWIG_TypeError, "Need a callable object!"); + return NULL; + } + $1 = $input; +} +/* typemap to get content/size from a bytearray */ +%typemap(in) (size_t len, uint8_t* py_bytearray_data) { + if (!PyByteArray_CheckExact($input)) { + SWIG_exception_fail(SWIG_TypeError, "Expected bytearray!"); + return NULL; + } + $2 = PyByteArray_AsString($input); + $1 = PyByteArray_Size($input); +} + +int edns_opt_list_remove(struct edns_option** list, uint16_t code); +int edns_opt_list_append(struct edns_option** list, uint16_t code, size_t len, + uint8_t* py_bytearray_data, struct regional* region); + +%{ + /* This function is called by unbound in order to call the python + * callback function. */ + int python_inplace_cb_reply_generic(struct query_info* qinfo, + struct module_qstate* qstate, struct reply_info* rep, int rcode, + struct edns_data* edns, struct edns_option** opt_list_out, + struct regional* region, void* python_callback) + { + PyObject *func, *py_edns, *py_qstate, *py_opt_list_out, *py_qinfo; + PyObject *py_rep, *py_region; + PyObject *result; + int res = 0; + + func = (PyObject *) python_callback; + PyGILState_STATE gstate = PyGILState_Ensure(); + py_edns = SWIG_NewPointerObj((void*) edns, SWIGTYPE_p_edns_data, 0); + py_qstate = SWIG_NewPointerObj((void*) qstate, + SWIGTYPE_p_module_qstate, 0); + py_opt_list_out = SWIG_NewPointerObj((void*) opt_list_out, + SWIGTYPE_p_p_edns_option, 0); + py_qinfo = SWIG_NewPointerObj((void*) qinfo, SWIGTYPE_p_query_info, 0); + py_rep = SWIG_NewPointerObj((void*) rep, SWIGTYPE_p_reply_info, 0); + py_region = SWIG_NewPointerObj((void*) region, SWIGTYPE_p_regional, 0); + result = PyObject_CallFunction(func, "OOOiOOO", py_qinfo, py_qstate, + py_rep, rcode, py_edns, py_opt_list_out, py_region); + Py_XDECREF(py_edns); + Py_XDECREF(py_qstate); + Py_XDECREF(py_opt_list_out); + Py_XDECREF(py_qinfo); + Py_XDECREF(py_rep); + Py_XDECREF(py_region); + if (result) { + res = PyInt_AsLong(result); + } + Py_XDECREF(result); + PyGILState_Release(gstate); + return res; + } + + /* Swig implementations for Python */ + static int register_inplace_cb_reply(PyObject* py_cb, + struct module_env* env) + { + int ret = inplace_cb_reply_register( + python_inplace_cb_reply_generic, (void*) py_cb, env); + if (ret) Py_INCREF(py_cb); + return ret; + } + static int register_inplace_cb_reply_cache(PyObject* py_cb, + struct module_env* env) + { + int ret = inplace_cb_reply_cache_register( + python_inplace_cb_reply_generic, (void*) py_cb, env); + if (ret) Py_INCREF(py_cb); + return ret; + } + static int register_inplace_cb_reply_local(PyObject* py_cb, + struct module_env* env) + { + int ret = inplace_cb_reply_local_register( + python_inplace_cb_reply_generic, (void*) py_cb, env); + if (ret) Py_INCREF(py_cb); + return ret; + } + static int register_inplace_cb_reply_servfail(PyObject* py_cb, + struct module_env* env) + { + int ret = inplace_cb_reply_servfail_register( + python_inplace_cb_reply_generic, (void*) py_cb, env); + if (ret) Py_INCREF(py_cb); + return ret; + } +%} +/* C declarations */ +int inplace_cb_reply_register( + inplace_cb_reply_func_t* cb, void* cb_arg, struct module_env* env); +int inplace_cb_reply_cache_register( + inplace_cb_reply_func_t* cb, void* cb_arg, struct module_env* env); +int inplace_cb_reply_local_register( + inplace_cb_reply_func_t* cb, void* cb_arg, struct module_env* env); +int inplace_cb_reply_servfail_register( + inplace_cb_reply_func_t* cb, void* cb_arg, struct module_env* env); + +/* Swig declarations */ +static int register_inplace_cb_reply(PyObject* py_cb, + struct module_env* env); +static int register_inplace_cb_reply_cache(PyObject* py_cb, + struct module_env* env); +static int register_inplace_cb_reply_local(PyObject* py_cb, + struct module_env* env); +static int register_inplace_cb_reply_servfail(PyObject* py_cb, + struct module_env* env); |
