diff options
Diffstat (limited to 'contrib/unbound/pythonmod/interface.i')
| -rw-r--r-- | contrib/unbound/pythonmod/interface.i | 1857 |
1 files changed, 1857 insertions, 0 deletions
diff --git a/contrib/unbound/pythonmod/interface.i b/contrib/unbound/pythonmod/interface.i new file mode 100644 index 000000000000..2040fb9e8adf --- /dev/null +++ b/contrib/unbound/pythonmod/interface.i @@ -0,0 +1,1857 @@ +/* + * interface.i: unbound python module + */ +%begin %{ +/* store state of warning output, restored at later pop */ +#pragma GCC diagnostic push +/* ignore warnings for pragma below, where for older GCC it can produce a + warning if the cast-function-type warning is absent. */ +#pragma GCC diagnostic ignored "-Wpragmas" +/* ignore gcc8 METH_NOARGS function cast warnings for swig function pointers */ +#pragma GCC diagnostic ignored "-Wcast-function-type" +%} +%module unboundmodule +%{ +/* restore state of warning output, remove the functioncast ignore */ +#pragma GCC diagnostic pop +/** + * \file + * This is the interface between the unbound server and a python module + * called to perform operations on queries. + */ + #include <sys/types.h> + #include <time.h> + #ifdef HAVE_SYS_SOCKET_H + #include <sys/socket.h> + #endif + #ifdef HAVE_NETINET_IN_H + #include <netinet/in.h> + #endif + #ifdef HAVE_ARPA_INET_H + #include <arpa/inet.h> + #endif + #ifdef HAVE_NETDB_H + #include <netdb.h> + #endif + #ifdef HAVE_SYS_UN_H + #include <sys/un.h> + #endif + #include <stdarg.h> + #include "config.h" + #include "util/log.h" + #include "util/module.h" + #include "util/netevent.h" + #include "util/regional.h" + #include "util/config_file.h" + #include "util/data/msgreply.h" + #include "util/data/packed_rrset.h" + #include "util/data/dname.h" + #include "util/storage/lruhash.h" + #include "services/cache/dns.h" + #include "services/mesh.h" + #include "iterator/iter_delegpt.h" + #include "iterator/iter_hints.h" + #include "iterator/iter_utils.h" + #include "sldns/wire2str.h" + #include "sldns/str2wire.h" + #include "sldns/pkthdr.h" +%} + +%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) */ + PyObject* GetNameAsLabelList(const char* name, int len) { + PyObject* list; + int cnt=0, i; + + i = 0; + while (i < len) { + i += ((unsigned int)name[i]) + 1; + cnt++; + } + + list = PyList_New(cnt); + i = 0; cnt = 0; + while (i < len) { + 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; + } + + /* converts an array of strings (char**) to a List of strings */ + PyObject* CharArrayAsStringList(char** array, int len) { + PyObject* list; + int i; + + if(!array||len==0) return PyList_New(0); + + list = PyList_New(len); + for (i=0; i < len; i++) { + PyList_SET_ITEM(list, i, PyString_FromString(array[i])); + } + return list; + } +%} + +/* ************************************************************************************ * + Structure query_info + * ************************************************************************************ */ +/* Query info */ +%ignore query_info::qname; +%ignore query_info::qname_len; + + +struct query_info { + %immutable; + char* qname; + size_t qname_len; + uint16_t qtype; + uint16_t qclass; + %mutable; +}; + +%inline %{ + enum enum_rr_class { + RR_CLASS_IN = 1, + RR_CLASS_CH = 3, + RR_CLASS_HS = 4, + RR_CLASS_NONE = 254, + RR_CLASS_ANY = 255, + }; + + enum enum_rr_type { + RR_TYPE_A = 1, + RR_TYPE_NS = 2, + RR_TYPE_MD = 3, + RR_TYPE_MF = 4, + RR_TYPE_CNAME = 5, + RR_TYPE_SOA = 6, + RR_TYPE_MB = 7, + RR_TYPE_MG = 8, + RR_TYPE_MR = 9, + RR_TYPE_NULL = 10, + RR_TYPE_WKS = 11, + RR_TYPE_PTR = 12, + RR_TYPE_HINFO = 13, + RR_TYPE_MINFO = 14, + RR_TYPE_MX = 15, + RR_TYPE_TXT = 16, + RR_TYPE_RP = 17, + RR_TYPE_AFSDB = 18, + RR_TYPE_X25 = 19, + RR_TYPE_ISDN = 20, + RR_TYPE_RT = 21, + RR_TYPE_NSAP = 22, + RR_TYPE_NSAP_PTR = 23, + RR_TYPE_SIG = 24, + RR_TYPE_KEY = 25, + RR_TYPE_PX = 26, + RR_TYPE_GPOS = 27, + RR_TYPE_AAAA = 28, + RR_TYPE_LOC = 29, + RR_TYPE_NXT = 30, + RR_TYPE_EID = 31, + RR_TYPE_NIMLOC = 32, + RR_TYPE_SRV = 33, + RR_TYPE_ATMA = 34, + RR_TYPE_NAPTR = 35, + RR_TYPE_KX = 36, + RR_TYPE_CERT = 37, + RR_TYPE_A6 = 38, + RR_TYPE_DNAME = 39, + RR_TYPE_SINK = 40, + RR_TYPE_OPT = 41, + RR_TYPE_APL = 42, + RR_TYPE_DS = 43, + RR_TYPE_SSHFP = 44, + RR_TYPE_IPSECKEY = 45, + RR_TYPE_RRSIG = 46, + RR_TYPE_NSEC = 47, + RR_TYPE_DNSKEY = 48, + RR_TYPE_DHCID = 49, + RR_TYPE_NSEC3 = 50, + RR_TYPE_NSEC3PARAMS = 51, + RR_TYPE_UINFO = 100, + RR_TYPE_UID = 101, + RR_TYPE_GID = 102, + RR_TYPE_UNSPEC = 103, + RR_TYPE_TSIG = 250, + RR_TYPE_IXFR = 251, + RR_TYPE_AXFR = 252, + RR_TYPE_MAILB = 253, + RR_TYPE_MAILA = 254, + RR_TYPE_ANY = 255, + RR_TYPE_DLV = 32769, + }; + + PyObject* _get_qname(struct query_info* q) { + return PyBytes_FromStringAndSize((char*)q->qname, q->qname_len); + } + + PyObject* _get_qname_components(struct query_info* q) { + return GetNameAsLabelList((const char*)q->qname, q->qname_len); + } +%} + +%inline %{ + PyObject* dnameAsStr(PyObject* dname) { + char buf[LDNS_MAX_DOMAINLEN]; + buf[0] = '\0'; + dname_str((uint8_t*)PyBytes_AsString(dname), buf); + return PyString_FromString(buf); + } +%} + +%extend query_info { + %pythoncode %{ + def _get_qtype_str(self): return sldns_wire2str_type(self.qtype) + qtype_str = property(_get_qtype_str) + + def _get_qclass_str(self): return sldns_wire2str_class(self.qclass) + qclass_str = property(_get_qclass_str) + + qname = property(_unboundmodule._get_qname) + + qname_list = property(_unboundmodule._get_qname_components) + + def _get_qname_str(self): return dnameAsStr(self.qname) + qname_str = property(_get_qname_str) + %} +} + +/* ************************************************************************************ * + Structure packed_rrset_key + * ************************************************************************************ */ +%ignore packed_rrset_key::dname; +%ignore packed_rrset_key::dname_len; + +/* RRsets */ +struct packed_rrset_key { + %immutable; + 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 */ + %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. + */ +uint16_t ntohs(uint16_t netshort); + +%inline %{ + PyObject* _get_dname(struct packed_rrset_key* k) { + return PyBytes_FromStringAndSize((char*)k->dname, k->dname_len); + } + PyObject* _get_dname_components(struct packed_rrset_key* k) { + return GetNameAsLabelList((char*)k->dname, k->dname_len); + } +%} + +%extend packed_rrset_key { + %pythoncode %{ + def _get_type_str(self): return sldns_wire2str_type(_unboundmodule.ntohs(self.type)) + type_str = property(_get_type_str) + + def _get_class_str(self): return sldns_wire2str_class(_unboundmodule.ntohs(self.rrset_class)) + rrset_class_str = property(_get_class_str) + + dname = property(_unboundmodule._get_dname) + + dname_list = property(_unboundmodule._get_dname_components) + + def _get_dname_str(self): return dnameAsStr(self.dname) + dname_str = property(_get_dname_str) + %} +} + +#if defined(SWIGWORDSIZE64) +typedef long int rrset_id_type; +#else +typedef long long int rrset_id_type; +#endif + +struct ub_packed_rrset_key { + struct lruhash_entry entry; + rrset_id_type id; + struct packed_rrset_key rk; +}; + +struct lruhash_entry { + lock_rw_type lock; + struct lruhash_entry* overflow_next; + struct lruhash_entry* lru_next; + struct lruhash_entry* lru_prev; + hashvalue_type hash; + void* key; + struct packed_rrset_data* data; +}; + +%ignore packed_rrset_data::rr_len; +%ignore packed_rrset_data::rr_ttl; +%ignore packed_rrset_data::rr_data; + +struct packed_rrset_data { + /* TTL (in seconds like time()) */ + uint32_t ttl; + + /* number of rrs */ + size_t count; + /* number of rrsigs */ + size_t rrsig_count; + + enum rrset_trust trust; + enum sec_status security; + + /* 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 %{ + class RRSetData_RRLen: + def __init__(self, obj): self.obj = obj + def __getitem__(self, index): return _unboundmodule._get_data_rr_len(self.obj, index) + def __len__(self): return self.obj.count + self.obj.rrsig_count + class RRSetData_RRTTL: + def __init__(self, obj): self.obj = obj + def __getitem__(self, index): return _unboundmodule._get_data_rr_ttl(self.obj, index) + def __setitem__(self, index, value): _unboundmodule._set_data_rr_ttl(self.obj, index, value) + def __len__(self): return self.obj.count + self.obj.rrsig_count + class RRSetData_RRData: + def __init__(self, obj): self.obj = obj + def __getitem__(self, index): return _unboundmodule._get_data_rr_data(self.obj, index) + def __len__(self): return self.obj.count + self.obj.rrsig_count +%} + +%inline %{ + PyObject* _get_data_rr_len(struct packed_rrset_data* d, int idx) { + if ((d != NULL) && (idx >= 0) && + ((size_t)idx < (d->count+d->rrsig_count))) + return PyInt_FromLong(d->rr_len[idx]); + return Py_None; + } + void _set_data_rr_ttl(struct packed_rrset_data* d, int idx, uint32_t ttl) + { + if ((d != NULL) && (idx >= 0) && + ((size_t)idx < (d->count+d->rrsig_count))) + d->rr_ttl[idx] = ttl; + } + PyObject* _get_data_rr_ttl(struct packed_rrset_data* d, int idx) { + if ((d != NULL) && (idx >= 0) && + ((size_t)idx < (d->count+d->rrsig_count))) + return PyInt_FromLong(d->rr_ttl[idx]); + return Py_None; + } + PyObject* _get_data_rr_data(struct packed_rrset_data* d, int idx) { + if ((d != NULL) && (idx >= 0) && + ((size_t)idx < (d->count+d->rrsig_count))) + return PyBytes_FromStringAndSize((char*)d->rr_data[idx], + d->rr_len[idx]); + return Py_None; + } +%} + +%extend packed_rrset_data { + %pythoncode %{ + def _get_data_rr_len(self): return RRSetData_RRLen(self) + rr_len = property(_get_data_rr_len) + def _get_data_rr_ttl(self): return RRSetData_RRTTL(self) + rr_ttl = property(_get_data_rr_ttl) + def _get_data_rr_data(self): return RRSetData_RRData(self) + rr_data = property(_get_data_rr_data) + %} +} + +/* ************************************************************************************ * + Structure reply_info + * ************************************************************************************ */ +/* Messages */ +%ignore reply_info::rrsets; +%ignore reply_info::ref; + +struct reply_info { + uint16_t flags; + uint16_t qdcount; + uint32_t ttl; + uint32_t prefetch_ttl; + + uint16_t authoritative; + enum sec_status security; + + size_t an_numrrsets; + size_t ns_numrrsets; + size_t 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 { + struct ub_packed_rrset_key* key; + rrset_id_type id; +}; + +struct dns_msg { + struct query_info qinfo; + struct reply_info *rep; +}; + +%pythoncode %{ + class ReplyInfo_RRSet: + def __init__(self, obj): self.obj = obj + def __getitem__(self, index): return _unboundmodule._rrset_rrsets_get(self.obj, index) + def __len__(self): return self.obj.rrset_count + + class ReplyInfo_Ref: + def __init__(self, obj): self.obj = obj + def __getitem__(self, index): return _unboundmodule._rrset_ref_get(self.obj, index) + def __len__(self): return self.obj.rrset_count +%} + +%inline %{ + struct ub_packed_rrset_key* _rrset_rrsets_get(struct reply_info* r, int idx) { + if ((r != NULL) && (idx >= 0) && ((size_t)idx < r->rrset_count)) + return r->rrsets[idx]; + return NULL; + } + + 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); */ + return &(r->ref[idx]); +/* return &(r->ref[idx]); */ + } +/* printf("_rrset_ref_get: NULL\n"); */ + return NULL; + } +%} + +%extend reply_info { + %pythoncode %{ + def _rrset_ref_get(self): return ReplyInfo_Ref(self) + ref = property(_rrset_ref_get) + + def _rrset_rrsets_get(self): return ReplyInfo_RRSet(self) + rrsets = property(_rrset_rrsets_get) + %} +} + +/* ************************************************************************************ * + Structure sockaddr_storage + * ************************************************************************************ */ + +struct sockaddr_storage {}; + +%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); +#ifdef HAVE_SYS_UN_H + case AF_UNIX: return sizeof(struct sockaddr_un); +#endif + default: + return 0; + } + } + + 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)); + } + +#ifdef HAVE_SYS_UN_H + if (ss->ss_family == AF_UNIX) { + const struct sockaddr_un *sa = (struct sockaddr_un *)ss; + return PyBytes_FromString(sa->sun_path); + } +#endif + + return Py_None; + } + + PyObject *_sockaddr_storage_port(const struct sockaddr_storage *ss) { + if (ss == NULL) { + return Py_None; + } + + if (ss->ss_family == AF_INET) { + const struct sockaddr_in *sa4 = (struct sockaddr_in *)ss; + return PyInt_FromLong(ntohs(sa4->sin_port)); + } + + 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 *_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) + family = property(_family_get) + + def _addr_get(self): return _sockaddr_storage_addr(self) + addr = property(_addr_get) + + def _raw_addr_get(self): return _sockaddr_storage_raw_addr(self) + raw_addr = property(_raw_addr_get) + + def _port_get(self): return _sockaddr_storage_port(self) + port = property(_port_get) + + def _flowinfo_get(self): return _sockaddr_storage_flowinfo(self) + flowinfo = property(_flowinfo_get) + + def _scope_id_get(self): return _sockaddr_storage_scope_id(self) + scope_id = 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::client_addr; +struct comm_reply { + struct sockaddr_storage client_addr; +}; + +%extend comm_reply { + %pythoncode %{ + def _addr_get(self): return _sockaddr_storage_addr(self._addr) + addr = property(_addr_get) + + def _port_get(self): return _sockaddr_storage_port(self._addr) + port = property(_port_get) + + def _family_get(self): return _sockaddr_storage_family(self._addr) + family = 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((void*)option->opt_data, + option->opt_len); + } +%} +%extend edns_option { + %pythoncode %{ + def _opt_code_get(self): return _edns_option_opt_code_get(self) + code = property(_opt_code_get) + + def _opt_data_get(self): return _edns_option_opt_data_get(self) + data = 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_in; + struct edns_option* opt_list_out; + struct edns_option* opt_list_inplace_cb_out; + uint16_t padding_block_size; +}; +%inline %{ + struct edns_option** _edns_data_opt_list_get(struct edns_data* edns) { + return &edns->opt_list_in; + } +%} +%extend edns_data { + %pythoncode %{ + def _opt_list_iter(self): return EdnsOptsListIter(self.opt_list) + opt_list_iter = property(_opt_list_iter) + def _opt_list(self): return _edns_data_opt_list_get(self) + opt_list = property(_opt_list) + %} +} + +/* ************************************************************************************ * + Structure module_env + * ************************************************************************************ */ +%rename(_now) module_env::now; +%rename(_now_tv) module_env::now_tv; +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, + int check_ratelimit, + struct sockaddr_storage* addr, socklen_t addrlen, + uint8_t* zone, size_t zonelen, int tcp_upstream, int ssl_upstream, + char* tls_auth_name, struct module_qstate* q, int* was_ratelimited); + 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; +}; + +%inline %{ + PyObject* _module_env_now_get(struct module_env* env) { + double ts = env->now_tv->tv_sec + env->now_tv->tv_usec / 1e6; + return PyFloat_FromDouble(ts); + } +%} +%extend module_env { + %pythoncode %{ + def _now_get(self): return _module_env_now_get(self) + now = property(_now_get) + %} +} + +/* ************************************************************************************ * + 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; + int is_valrec; + + struct comm_reply* reply; + struct dns_msg* return_msg; + int return_rcode; + struct regional* region; /* unwrapped */ + + int curmod; + + 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; + +%constant int QF_BIT_CD = 0x0010; +%constant int QF_BIT_AD = 0x0020; +%constant int QF_BIT_Z = 0x0040; +%constant int QF_BIT_RA = 0x0080; +%constant int QF_BIT_RD = 0x0100; +%constant int QF_BIT_TC = 0x0200; +%constant int QF_BIT_AA = 0x0400; +%constant int QF_BIT_QR = 0x8000; + +%inline %{ + enum enum_return_rcode { + RCODE_NOERROR = 0, + RCODE_FORMERR = 1, + RCODE_SERVFAIL = 2, + RCODE_NXDOMAIN = 3, + RCODE_NOTIMPL = 4, + RCODE_REFUSED = 5, + RCODE_YXDOMAIN = 6, + RCODE_YXRRSET = 7, + RCODE_NXRRSET = 8, + RCODE_NOTAUTH = 9, + RCODE_NOTZONE = 10 + }; +%} + +%pythoncode %{ + class ExtState: + def __init__(self, obj): self.obj = obj + def __str__(self): + return ", ".join([_unboundmodule.strextstate(_unboundmodule._ext_state_get(self.obj,a)) for a in range(0, _unboundmodule.MODULE_COUNT)]) + 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 %{ + enum module_ext_state _ext_state_get(struct module_qstate* q, int idx) { + if ((q != NULL) && (idx >= 0) && (idx < MAX_MODULE)) { + return q->ext_state[idx]; + } + 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 { + %pythoncode %{ + def set_ext_state(self, id, state): + """Sets the ext state""" + _unboundmodule._ext_state_set(self, id, state) + + def __ext_state_get(self): return ExtState(self) + ext_state = property(__ext_state_get) #, __ext_state_set + + def _edns_opts_front_in_iter(self): return EdnsOptsListIter(self.edns_opts_front_in) + edns_opts_front_in_iter = property(_edns_opts_front_in_iter) + def _edns_opts_back_out_iter(self): return EdnsOptsListIter(self.edns_opts_back_out) + edns_opts_back_out_iter = property(_edns_opts_back_out_iter) + def _edns_opts_back_in_iter(self): return EdnsOptsListIter(self.edns_opts_back_in) + edns_opts_back_in_iter = property(_edns_opts_back_in_iter) + def _edns_opts_front_out_iter(self): return EdnsOptsListIter(self.edns_opts_front_out) + edns_opts_front_out_iter = property(_edns_opts_front_out_iter) + + def _edns_opts_front_in(self): return _edns_opts_front_in_get(self) + edns_opts_front_in = property(_edns_opts_front_in) + def _edns_opts_back_out(self): return _edns_opts_back_out_get(self) + edns_opts_back_out = property(_edns_opts_back_out) + def _edns_opts_back_in(self): return _edns_opts_back_in_get(self) + edns_opts_back_in = property(_edns_opts_back_in) + def _edns_opts_front_out(self): return _edns_opts_front_out_get(self) + edns_opts_front_out = property(_edns_opts_front_out) + %} +} + +/* ************************************************************************************ * + Structure config_strlist + * ************************************************************************************ */ +struct config_strlist { + struct config_strlist* next; + char* str; +}; + +/* ************************************************************************************ * + Structure config_str2list + * ************************************************************************************ */ +struct config_str2list { + struct config_str2list* next; + char* str; + char* str2; +}; + +/* ************************************************************************************ * + Structure config_file + * ************************************************************************************ */ +%ignore config_file::ifs; +%ignore config_file::out_ifs; +%ignore config_file::python_script; +struct config_file { + int verbosity; + int stat_interval; + int stat_cumulative; + int stat_extended; + int num_threads; + int port; + int do_ip4; + int do_ip6; + int do_udp; + int do_tcp; + int outgoing_num_ports; + size_t outgoing_num_tcp; + size_t incoming_num_tcp; + int* outgoing_avail_ports; + size_t msg_buffer_size; + size_t msg_cache_size; + size_t msg_cache_slabs; + size_t num_queries_per_thread; + size_t jostle_time; + size_t rrset_cache_size; + size_t rrset_cache_slabs; + int host_ttl; + size_t infra_cache_slabs; + size_t infra_cache_numhosts; + char* target_fetch_policy; + int if_automatic; + int num_ifs; + char **ifs; + int num_out_ifs; + char **out_ifs; + struct config_strlist* root_hints; + struct config_stub* stubs; + struct config_stub* forwards; + struct config_strlist* donotqueryaddrs; + struct config_str2list* acls; + int donotquery_localhost; + int harden_short_bufsize; + int harden_large_queries; + int harden_glue; + int harden_unverified_glue; + int harden_dnssec_stripped; + int harden_referral_path; + int use_caps_bits_for_id; + struct config_strlist* private_address; + struct config_strlist* private_domain; + size_t unwanted_threshold; + char* chrootdir; + char* username; + char* directory; + char* logfile; + char* pidfile; + int use_syslog; + int hide_identity; + int hide_version; + char* identity; + char* version; + char* module_conf; + struct config_strlist* trust_anchor_file_list; + struct config_strlist* trust_anchor_list; + struct config_strlist* trusted_keys_file_list; + int max_ttl; + int32_t val_date_override; + int bogus_ttl; + int val_clean_additional; + int val_permissive_mode; + char* val_nsec3_key_iterations; + size_t key_cache_size; + size_t key_cache_slabs; + size_t neg_cache_size; + struct config_str2list* local_zones; + struct config_strlist* local_zones_nodefault; + struct config_strlist* local_data; + int remote_control_enable; + struct config_strlist_head control_ifs; + int control_port; + char* server_key_file; + char* server_cert_file; + char* control_key_file; + char* control_cert_file; + int do_daemonize; + struct config_strlist* python_script; +}; + +%inline %{ + PyObject* _get_ifs_tuple(struct config_file* cfg) { + return CharArrayAsStringList(cfg->ifs, cfg->num_ifs); + } + PyObject* _get_ifs_out_tuple(struct config_file* cfg) { + return CharArrayAsStringList(cfg->out_ifs, cfg->num_out_ifs); + } +%} + +%extend config_file { + %pythoncode %{ + ifs = property(_unboundmodule._get_ifs_tuple) + out_ifs = property(_unboundmodule._get_ifs_out_tuple) + + def _deprecated_python_script(self): return "cfg.python_script is deprecated, you can use `mod_env['script']` instead." + python_script = property(_deprecated_python_script) + %} +} + +/* ************************************************************************************ * + ASN: Adding structures related to forwards_lookup and dns_cache_find_delegation + * ************************************************************************************ */ +struct delegpt_ns { + struct delegpt_ns* next; + int resolved; + uint8_t got4; + uint8_t got6; + uint8_t lame; + uint8_t done_pside4; + uint8_t done_pside6; +}; + +struct delegpt_addr { + struct delegpt_addr* next_result; + struct delegpt_addr* next_usable; + struct delegpt_addr* next_target; + int attempts; + int sel_rtt; + int bogus; + int lame; +}; + +struct delegpt { + int namelabs; + struct delegpt_ns* nslist; + struct delegpt_addr* target_list; + struct delegpt_addr* usable_list; + struct delegpt_addr* result_list; + int bogus; + uint8_t has_parent_side_NS; + uint8_t dp_type_mlc; +}; + + +%inline %{ + PyObject* _get_dp_dname(struct delegpt* dp) { + return PyBytes_FromStringAndSize((char*)dp->name, dp->namelen); + } + PyObject* _get_dp_dname_components(struct delegpt* dp) { + return GetNameAsLabelList((char*)dp->name, dp->namelen); + } + PyObject* _get_dpns_dname(struct delegpt_ns* dpns) { + return PyBytes_FromStringAndSize((char*)dpns->name, dpns->namelen); + } + PyObject* _get_dpns_dname_components(struct delegpt_ns* dpns) { + return GetNameAsLabelList((char*)dpns->name, dpns->namelen); + } + + PyObject* _delegpt_addr_addr_get(struct delegpt_addr* target) { + char dest[64]; + delegpt_addr_addr2str(target, dest, 64); + if (dest[0] == 0) + return Py_None; + return PyBytes_FromString(dest); + } + +%} + +%extend delegpt { + %pythoncode %{ + dname = property(_unboundmodule._get_dp_dname) + + dname_list = property(_unboundmodule._get_dp_dname_components) + + def _get_dname_str(self): return dnameAsStr(self.dname) + dname_str = property(_get_dname_str) + %} +} +%extend delegpt_ns { + %pythoncode %{ + dname = property(_unboundmodule._get_dpns_dname) + + dname_list = property(_unboundmodule._get_dpns_dname_components) + + def _get_dname_str(self): return dnameAsStr(self.dname) + dname_str = property(_get_dname_str) + %} +} +%extend delegpt_addr { + %pythoncode %{ + def _addr_get(self): return _delegpt_addr_addr_get(self) + addr = property(_addr_get) + %} +} + +/* ************************************************************************************ * + Enums + * ************************************************************************************ */ +%rename ("MODULE_STATE_INITIAL") "module_state_initial"; +%rename ("MODULE_WAIT_REPLY") "module_wait_reply"; +%rename ("MODULE_WAIT_MODULE") "module_wait_module"; +%rename ("MODULE_RESTART_NEXT") "module_restart_next"; +%rename ("MODULE_WAIT_SUBQUERY") "module_wait_subquery"; +%rename ("MODULE_ERROR") "module_error"; +%rename ("MODULE_FINISHED") "module_finished"; + +enum module_ext_state { + module_state_initial = 0, + module_wait_reply, + module_wait_module, + module_restart_next, + module_wait_subquery, + module_error, + module_finished +}; + +%rename ("MODULE_EVENT_NEW") "module_event_new"; +%rename ("MODULE_EVENT_PASS") "module_event_pass"; +%rename ("MODULE_EVENT_REPLY") "module_event_reply"; +%rename ("MODULE_EVENT_NOREPLY") "module_event_noreply"; +%rename ("MODULE_EVENT_CAPSFAIL") "module_event_capsfail"; +%rename ("MODULE_EVENT_MODDONE") "module_event_moddone"; +%rename ("MODULE_EVENT_ERROR") "module_event_error"; + +enum module_ev { + module_event_new = 0, + module_event_pass, + module_event_reply, + module_event_noreply, + module_event_capsfail, + module_event_moddone, + module_event_error +}; + +enum sec_status { + sec_status_unchecked = 0, + sec_status_bogus, + sec_status_indeterminate, + sec_status_insecure, + sec_status_secure +}; + +enum verbosity_value { + NO_VERBOSE = 0, + VERB_OPS, + VERB_DETAIL, + VERB_QUERY, + VERB_ALGO +}; + +enum inplace_cb_list_type { + /* Inplace callbacks for when a resolved reply is ready to be sent to the + * front.*/ + inplace_cb_reply = 0, + /* Inplace callbacks for when a reply is given from the cache. */ + inplace_cb_reply_cache, + /* Inplace callbacks for when a reply is given with local data + * (or Chaos reply). */ + inplace_cb_reply_local, + /* Inplace callbacks for when the reply is servfail. */ + inplace_cb_reply_servfail, + /* Inplace callbacks for when a query is ready to be sent to the back.*/ + inplace_cb_query, + /* Inplace callback for when a reply is received from the back. */ + inplace_cb_edns_back_parsed, + /* Total number of types. Used for array initialization. + * Should always be last. */ + inplace_cb_types_total +}; + +%constant uint16_t PKT_QR = 1; /* QueRy - query flag */ +%constant uint16_t PKT_AA = 2; /* Authoritative Answer - server flag */ +%constant uint16_t PKT_TC = 4; /* TrunCated - server flag */ +%constant uint16_t PKT_RD = 8; /* Recursion Desired - query flag */ +%constant uint16_t PKT_CD = 16; /* Checking Disabled - query flag */ +%constant uint16_t PKT_RA = 32; /* Recursion Available - server flag */ +%constant uint16_t PKT_AD = 64; /* Authenticated Data - server flag */ + +%{ +int checkList(PyObject *l) +{ + PyObject* item; + int i; + + if (l == Py_None) + return 1; + + if (PyList_Check(l)) + { + for (i=0; i < PyList_Size(l); i++) + { + item = PyList_GetItem(l, i); + if (!PyBytes_Check(item) && !PyUnicode_Check(item)) + return 0; + } + return 1; + } + + return 0; +} + +int pushRRList(sldns_buffer* qb, PyObject *l, uint32_t default_ttl, int qsec, + size_t count_offset) +{ + 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(s, + sldns_buffer_current(qb), &len, NULL, NULL, 0, NULL, 0) + != 0) { + if(ascstr) + Py_DECREF(ascstr); + return 0; + } + } else { + if(sldns_str2wire_rr_buf(s, + sldns_buffer_current(qb), &len, NULL, default_ttl, + 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, + sldns_buffer_read_u16_at(qb, count_offset)+1); + } + return 1; +} + +int set_return_msg(struct module_qstate* qstate, + const char* rr_name, sldns_rr_type rr_type, sldns_rr_class rr_class , uint16_t flags, uint32_t default_ttl, + PyObject* question, PyObject* answer, PyObject* authority, PyObject* additional) +{ + sldns_buffer *qb = 0; + int res = 1; + size_t l; + uint16_t PKT_QR = 1; + uint16_t PKT_AA = 2; + uint16_t PKT_TC = 4; + uint16_t PKT_RD = 8; + uint16_t PKT_CD = 16; + uint16_t PKT_RA = 32; + uint16_t PKT_AD = 64; + + if ((!checkList(question)) || (!checkList(answer)) || (!checkList(authority)) || (!checkList(additional))) + return 0; + if ((qb = sldns_buffer_new(LDNS_RR_BUF_SIZE)) == 0) return 0; + + /* write header */ + sldns_buffer_write_u16(qb, 0); /* ID */ + sldns_buffer_write_u16(qb, 0); /* flags */ + sldns_buffer_write_u16(qb, 1); /* qdcount */ + sldns_buffer_write_u16(qb, 0); /* ancount */ + sldns_buffer_write_u16(qb, 0); /* nscount */ + sldns_buffer_write_u16(qb, 0); /* arcount */ + if ((flags&PKT_QR)) LDNS_QR_SET(sldns_buffer_begin(qb)); + if ((flags&PKT_AA)) LDNS_AA_SET(sldns_buffer_begin(qb)); + if ((flags&PKT_TC)) LDNS_TC_SET(sldns_buffer_begin(qb)); + if ((flags&PKT_RD)) LDNS_RD_SET(sldns_buffer_begin(qb)); + if ((flags&PKT_CD)) LDNS_CD_SET(sldns_buffer_begin(qb)); + if ((flags&PKT_RA)) LDNS_RA_SET(sldns_buffer_begin(qb)); + if ((flags&PKT_AD)) LDNS_AD_SET(sldns_buffer_begin(qb)); + + /* write the query */ + l = sldns_buffer_remaining(qb); + if(sldns_str2wire_dname_buf(rr_name, sldns_buffer_current(qb), &l) != 0) { + sldns_buffer_free(qb); + return 0; + } + sldns_buffer_skip(qb, l); + if (rr_type == 0) { rr_type = LDNS_RR_TYPE_A; } + if (rr_class == 0) { rr_class = LDNS_RR_CLASS_IN; } + sldns_buffer_write_u16(qb, rr_type); + sldns_buffer_write_u16(qb, rr_class); + + /* write RR sections */ + if(res && !pushRRList(qb, question, default_ttl, 1, LDNS_QDCOUNT_OFF)) + res = 0; + if(res && !pushRRList(qb, answer, default_ttl, 0, LDNS_ANCOUNT_OFF)) + res = 0; + if(res && !pushRRList(qb, authority, default_ttl, 0, LDNS_NSCOUNT_OFF)) + res = 0; + if(res && !pushRRList(qb, additional, default_ttl, 0, LDNS_ARCOUNT_OFF)) + res = 0; + + if (res) res = createResponse(qstate, qb); + + if (qb) sldns_buffer_free(qb); + return res; +} +%} + +int set_return_msg(struct module_qstate* qstate, + const char* rr_name, int rr_type, int rr_class , uint16_t flags, uint32_t default_ttl, + PyObject* question, PyObject* answer, PyObject* authority, PyObject* additional); + +%pythoncode %{ + class DNSMessage: + def __init__(self, rr_name, rr_type, rr_class = RR_CLASS_IN, query_flags = 0, default_ttl = 0): + """Query flags is a combination of PKT_xx constants""" + self.rr_name = rr_name + self.rr_type = rr_type + self.rr_class = rr_class + self.default_ttl = default_ttl + self.query_flags = query_flags + self.question = [] + self.answer = [] + self.authority = [] + self.additional = [] + + def set_return_msg(self, qstate): + """Returns 1 if OK""" + status = _unboundmodule.set_return_msg(qstate, self.rr_name, self.rr_type, self.rr_class, + self.query_flags, self.default_ttl, + self.question, self.answer, self.authority, self.additional) + + if (status) and (PKT_AA & self.query_flags): + qstate.return_msg.rep.authoritative = 1 + + return status + +%} +/* ************************************************************************************ * + ASN: Delegation pointer related functions + * ************************************************************************************ */ + +/* Functions which we will need to lookup delegations */ +struct delegpt* dns_cache_find_delegation(struct module_env* env, + uint8_t* qname, size_t qnamelen, uint16_t qtype, uint16_t qclass, + struct regional* region, struct dns_msg** msg, uint32_t timenow, + int noexpiredabove, uint8_t* expiretop, size_t expiretoplen); +int iter_dp_is_useless(struct query_info* qinfo, uint16_t qflags, + struct delegpt* dp, int supports_ipv4, int supports_ipv6, int use_nat64); +struct iter_hints_stub* hints_lookup_stub(struct iter_hints* hints, + uint8_t* qname, uint16_t qclass, struct delegpt* dp, int nolock); + +/* Custom function to perform logic similar to the one in daemon/cachedump.c */ +struct delegpt* find_delegation(struct module_qstate* qstate, char *nm, size_t nmlen); + +%{ +#define BIT_RD 0x100 + +struct delegpt* find_delegation(struct module_qstate* qstate, char *nm, size_t nmlen) +{ + struct delegpt *dp; + struct dns_msg *msg = NULL; + struct regional* region = qstate->env->scratch; + char b[260]; + struct query_info qinfo; + struct iter_hints_stub* stub; + uint32_t timenow = *qstate->env->now; + int nolock = 0; + + regional_free_all(region); + qinfo.qname = (uint8_t*)nm; + qinfo.qname_len = nmlen; + qinfo.qtype = LDNS_RR_TYPE_A; + qinfo.qclass = LDNS_RR_CLASS_IN; + + while(1) { + dp = dns_cache_find_delegation(qstate->env, (uint8_t*)nm, nmlen, qinfo.qtype, qinfo.qclass, region, &msg, timenow, 0, NULL, 0); + if(!dp) + return NULL; + if(iter_dp_is_useless(&qinfo, BIT_RD, dp, + qstate->env->cfg->do_ip4, qstate->env->cfg->do_ip6, + qstate->env->cfg->do_nat64)) { + if (dname_is_root((uint8_t*)nm)) + return NULL; + nm = (char*)dp->name; + nmlen = dp->namelen; + dname_remove_label((uint8_t**)&nm, &nmlen); + dname_str((uint8_t*)nm, b); + continue; + } + stub = hints_lookup_stub(qstate->env->hints, qinfo.qname, + qinfo.qclass, dp, nolock); + if (stub) { + struct delegpt* stubdp = delegpt_copy(stub->dp, region); + lock_rw_unlock(&qstate->env->hints->lock); + return stubdp; + } else { + return dp; + } + } + return NULL; +} +%} + +/* ************************************************************************************ * + Functions + * ************************************************************************************ */ +/****************************** + * Various debugging functions * + ******************************/ + +/* rename the variadic functions because python does the formatting already*/ +%rename (unbound_log_info) log_info; +%rename (unbound_log_err) log_err; +%rename (unbound_log_warn) log_warn; +%rename (unbound_verbose) verbose; +/* provide functions that take one string as argument, so python can cook +the string */ +%rename (log_info) pymod_log_info; +%rename (log_warn) pymod_log_warn; +%rename (log_err) pymod_log_err; +%rename (verbose) pymod_verbose; + +void verbose(enum verbosity_value level, const char* format, ...); +void log_info(const char* format, ...); +void log_err(const char* format, ...); +void log_warn(const char* format, ...); +void log_hex(const char* msg, void* data, size_t length); +void log_dns_msg(const char* str, struct query_info* qinfo, struct reply_info* rep); +void log_query_info(enum verbosity_value v, const char* str, struct query_info* qinf); +void regional_log_stats(struct regional *r); + +/* the one argument string log functions */ +void pymod_log_info(const char* str); +void pymod_log_err(const char* str); +void pymod_log_warn(const char* str); +void pymod_verbose(enum verbosity_value level, const char* str); +%{ +void pymod_log_info(const char* str) { log_info("%s", str); } +void pymod_log_err(const char* str) { log_err("%s", str); } +void pymod_log_warn(const char* str) { log_warn("%s", str); } +void pymod_verbose(enum verbosity_value level, const char* str) { + verbose(level, "%s", str); } +%} + +/*************************************************************************** + * Free allocated memory from marked sources returning corresponding types * + ***************************************************************************/ +%typemap(newfree, noblock = 1) char * { + free($1); +} + +/*************************************************** + * Mark as source returning newly allocated memory * + ***************************************************/ +%newobject sldns_wire2str_type; +%newobject sldns_wire2str_class; + +/****************** + * LDNS functions * + ******************/ +char *sldns_wire2str_type(const uint16_t atype); +char *sldns_wire2str_class(const uint16_t aclass); + +/********************************** + * 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 * + *******************************/ +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 = (void*)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 comm_reply* repinfo, struct regional* region, + struct timeval* start_time, int id, void* python_callback) + { + PyObject *func = NULL, *py_edns = NULL, *py_qstate = NULL; + PyObject *py_opt_list_out = NULL, *py_qinfo = NULL; + PyObject *py_rep = NULL, *py_repinfo = NULL, *py_region = NULL; + PyObject *py_args = NULL, *py_kwargs = NULL, *result = NULL; + int res = 0; + double py_start_time = ((double)start_time->tv_sec) + ((double)start_time->tv_usec) / 1.0e6; + + PyGILState_STATE gstate = PyGILState_Ensure(); + + func = (PyObject *) python_callback; + 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_repinfo = SWIG_NewPointerObj((void*) repinfo, SWIGTYPE_p_comm_reply, 0); + py_region = SWIG_NewPointerObj((void*) region, SWIGTYPE_p_regional, 0); + if(!(py_qinfo && py_qstate && py_rep && py_edns && py_opt_list_out + && py_region && py_repinfo)) { + log_err("pythonmod: swig pointer failure in python_inplace_cb_reply_generic"); + goto out; + } + py_args = Py_BuildValue("(OOOiOOO)", py_qinfo, py_qstate, py_rep, + rcode, py_edns, py_opt_list_out, py_region); + py_kwargs = Py_BuildValue("{s:O,s:d}", "repinfo", py_repinfo, "start_time", + py_start_time); + if(!(py_args && py_kwargs)) { + log_err("pythonmod: BuildValue failure in python_inplace_cb_reply_generic"); + goto out; + } + result = PyObject_Call(func, py_args, py_kwargs); + if (result) { + res = PyInt_AsLong(result); + } +out: + 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_repinfo); + Py_XDECREF(py_region); + Py_XDECREF(py_args); + Py_XDECREF(py_kwargs); + Py_XDECREF(result); + PyGILState_Release(gstate); + return res; + } + + /* register a callback */ + static int python_inplace_cb_register(enum inplace_cb_list_type type, + PyObject* py_cb, struct module_env* env, int id) + { + int ret = inplace_cb_register(python_inplace_cb_reply_generic, + type, (void*) py_cb, env, id); + if (ret) Py_INCREF(py_cb); + return ret; + } + + /* Swig implementations for Python */ + static int register_inplace_cb_reply(PyObject* py_cb, + struct module_env* env, int id) + { + return python_inplace_cb_register(inplace_cb_reply, py_cb, env, id); + } + static int register_inplace_cb_reply_cache(PyObject* py_cb, + struct module_env* env, int id) + { + return python_inplace_cb_register(inplace_cb_reply_cache, py_cb, env, id); + } + static int register_inplace_cb_reply_local(PyObject* py_cb, + struct module_env* env, int id) + { + return python_inplace_cb_register(inplace_cb_reply_local, py_cb, env, id); + } + static int register_inplace_cb_reply_servfail(PyObject* py_cb, + struct module_env* env, int id) + { + 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; + PyObject *py_args = NULL, *py_kwargs = NULL, *result = NULL; + PyObject *py_qinfo = NULL; + PyObject *py_qstate = NULL; + PyObject *py_addr = NULL; + PyObject *py_zone = NULL; + PyObject *py_region = NULL; + + PyGILState_STATE gstate = PyGILState_Ensure(); + + py_qinfo = SWIG_NewPointerObj((void*) qinfo, SWIGTYPE_p_query_info, 0); + py_qstate = SWIG_NewPointerObj((void*) qstate, SWIGTYPE_p_module_qstate, 0); + py_addr = SWIG_NewPointerObj((void *) addr, SWIGTYPE_p_sockaddr_storage, 0); + py_zone = PyBytes_FromStringAndSize((const char *)zone, zonelen); + py_region = SWIG_NewPointerObj((void*) region, SWIGTYPE_p_regional, 0); + if(!(py_qinfo && py_qstate && py_addr && py_zone && py_region)) { + log_err("pythonmod: swig pointer failure in python_inplace_cb_query_generic"); + goto out; + } + py_args = Py_BuildValue("(OiOOOO)", py_qinfo, flags, py_qstate, py_addr, py_zone, py_region); + py_kwargs = Py_BuildValue("{}"); + if(!(py_args && py_kwargs)) { + log_err("pythonmod: BuildValue failure in python_inplace_cb_query_generic"); + goto out; + } + result = PyObject_Call(func, py_args, py_kwargs); + if (result) { + res = PyInt_AsLong(result); + } +out: + 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; + } + + int python_inplace_cb_query_response(struct module_qstate* qstate, + struct dns_msg* response, int id, void* python_callback) + { + int res = 0; + PyObject *func = python_callback; + PyObject *py_qstate = NULL; + PyObject *py_response = NULL; + PyObject *py_args = NULL; + PyObject *py_kwargs = NULL; + PyObject *result = NULL; + + PyGILState_STATE gstate = PyGILState_Ensure(); + + py_qstate = SWIG_NewPointerObj((void*) qstate, SWIGTYPE_p_module_qstate, 0); + py_response = SWIG_NewPointerObj((void*) response, SWIGTYPE_p_dns_msg, 0); + if(!(py_qstate && py_response)) { + log_err("pythonmod: swig pointer failure in python_inplace_cb_query_response"); + goto out; + } + py_args = Py_BuildValue("(OO)", py_qstate, py_response); + py_kwargs = Py_BuildValue("{}"); + if(!(py_args && py_kwargs)) { + log_err("pythonmod: BuildValue failure in python_inplace_cb_query_response"); + goto out; + } + result = PyObject_Call(func, py_args, py_kwargs); + if (result) { + res = PyInt_AsLong(result); + } +out: + Py_XDECREF(py_qstate); + Py_XDECREF(py_response); + + Py_XDECREF(py_args); + Py_XDECREF(py_kwargs); + Py_XDECREF(result); + + PyGILState_Release(gstate); + + return res; + } + + static int register_inplace_cb_query_response(PyObject* py_cb, + struct module_env* env, int id) + { + int ret = inplace_cb_register(python_inplace_cb_query_response, + inplace_cb_query_response, (void*) py_cb, env, id); + if (ret) Py_INCREF(py_cb); + return ret; + } + + int python_inplace_cb_edns_back_parsed_call(struct module_qstate* qstate, + int id, void* python_callback) + { + int res = 0; + PyObject *func = python_callback; + PyObject *py_qstate = NULL; + PyObject *py_args = NULL; + PyObject *py_kwargs = NULL; + PyObject *result = NULL; + + PyGILState_STATE gstate = PyGILState_Ensure(); + + py_qstate = SWIG_NewPointerObj((void*) qstate, SWIGTYPE_p_module_qstate, 0); + if(!py_qstate) { + log_err("pythonmod: swig pointer failure in python_inplace_cb_edns_back_parsed_call"); + goto out; + } + py_args = Py_BuildValue("(O)", py_qstate); + py_kwargs = Py_BuildValue("{}"); + if(!(py_args && py_kwargs)) { + log_err("pythonmod: BuildValue failure in python_inplace_cb_edns_back_parsed_call"); + goto out; + } + result = PyObject_Call(func, py_args, py_kwargs); + if (result) { + res = PyInt_AsLong(result); + } +out: + Py_XDECREF(py_qstate); + + Py_XDECREF(py_args); + Py_XDECREF(py_kwargs); + Py_XDECREF(result); + + PyGILState_Release(gstate); + + return res; + } + + static int register_inplace_cb_edns_back_parsed_call(PyObject* py_cb, + struct module_env* env, int id) + { + int ret = inplace_cb_register(python_inplace_cb_edns_back_parsed_call, + inplace_cb_edns_back_parsed, (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, + struct module_env* env, int id); + +/* Swig declarations */ +static int register_inplace_cb_reply(PyObject* py_cb, + struct module_env* env, int id); +static int register_inplace_cb_reply_cache(PyObject* py_cb, + struct module_env* env, int id); +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); +static int register_inplace_cb_query_response(PyObject *py_cb, + struct module_env* env, int id); +static int register_inplace_cb_edns_back_parsed_call(PyObject *py_cb, + struct module_env* env, int id); |
