/* * interface.i: unbound python module */ %module unboundmodule %{ /** * \file * This is the interface between the unbound server and a python module * called to perform operations on queries. */ #include #include #include #include #include #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 += 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; cnt++; } 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(const char* dname) { char buf[LDNS_MAX_DOMAINLEN+1]; buf[0] = '\0'; dname_str((uint8_t*)dname, buf); return PyBytes_FromString(buf); } %} %extend query_info { %pythoncode %{ def _get_qtype_str(self): return sldns_wire2str_type(self.qtype) __swig_getmethods__["qtype_str"] = _get_qtype_str if _newclass:qtype_str = _swig_property(_get_qtype_str) def _get_qclass_str(self): return sldns_wire2str_class(self.qclass) __swig_getmethods__["qclass_str"] = _get_qclass_str if _newclass:qclass_str = _swig_property(_get_qclass_str) __swig_getmethods__["qname"] = _unboundmodule._get_qname if _newclass:qname = _swig_property(_unboundmodule._get_qname) __swig_getmethods__["qname_list"] = _unboundmodule._get_qname_components if _newclass:qname_list = _swig_property(_unboundmodule._get_qname_components) def _get_qname_str(self): return dnameAsStr(self.qname) __swig_getmethods__["qname_str"] = _get_qname_str if _newclass:qname_str = _swig_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)) __swig_getmethods__["type_str"] = _get_type_str if _newclass:type_str = _swig_property(_get_type_str) def _get_class_str(self): return sldns_wire2str_class(_unboundmodule.ntohs(self.rrset_class)) __swig_getmethods__["rrset_class_str"] = _get_class_str if _newclass:rrset_class_str = _swig_property(_get_class_str) __swig_getmethods__["dname"] = _unboundmodule._get_dname if _newclass:dname = _swig_property(_unboundmodule._get_dname) __swig_getmethods__["dname_list"] = _unboundmodule._get_dname_components if _newclass:dname_list = _swig_property(_unboundmodule._get_dname_components) def _get_dname_str(self): return dnameAsStr(self.dname) __swig_getmethods__["dname_str"] = _get_dname_str if _newclass:dname_str = _swig_property(_get_dname_str) %} } #if defined(SWIGWORDSIZE64) typedef long int rrset_id_t; #else typedef long long int rrset_id_t; #endif struct ub_packed_rrset_key { struct lruhash_entry entry; rrset_id_t id; struct packed_rrset_key rk; }; struct lruhash_entry { lock_rw_t lock; struct lruhash_entry* overflow_next; struct lruhash_entry* lru_next; struct lruhash_entry* lru_prev; hashvalue_t 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 { uint32_t ttl; //TTL (in seconds like time()) size_t count; //number of rrs size_t rrsig_count; //number of rrsigs 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. }; %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 obj.count + 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 obj.count + 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 obj.count + 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) __swig_getmethods__["rr_len"] = _get_data_rr_len if _newclass:rr_len = _swig_property(_get_data_rr_len) def _get_data_rr_ttl(self): return RRSetData_RRTTL(self) __swig_getmethods__["rr_ttl"] =_get_data_rr_ttl if _newclass:rr_len = _swig_property(_get_data_rr_ttl) def _get_data_rr_data(self): return RRSetData_RRData(self) __swig_getmethods__["rr_data"] = _get_data_rr_data if _newclass:rr_len = _swig_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_t 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 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 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) __swig_getmethods__["ref"] = _rrset_ref_get if _newclass:ref = _swig_property(_rrset_ref_get) def _rrset_rrsets_get(self): return ReplyInfo_RRSet(self) __swig_getmethods__["rrsets"] = _rrset_rrsets_get if _newclass:rrsets = _swig_property(_rrset_rrsets_get) %} } /* ************************************************************************************ * Structure mesh_state * ************************************************************************************ */ struct mesh_state { struct mesh_reply* reply_list; }; struct mesh_reply { struct mesh_reply* next; struct comm_reply query_reply; }; struct comm_reply { }; %inline %{ 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) { int af = (int)((struct sockaddr_in*) &(reply->addr))->sin_family; switch(af) { case AF_INET: return PyBytes_FromString("ip4"); case AF_INET6: return PyBytes_FromString("ip6"); case AF_UNIX: return PyBytes_FromString("unix"); } 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); } %} %extend comm_reply { %pythoncode %{ def _addr_get(self): return _comm_reply_addr_get(self) __swig_getmethods__["addr"] = _addr_get if _newclass:addr = _swig_property(_addr_get) def _port_get(self): return _comm_reply_port_get(self) __swig_getmethods__["port"] = _port_get if _newclass:port = _swig_property(_port_get) def _family_get(self): return _comm_reply_family_get(self) __swig_getmethods__["family"] = _family_get if _newclass:family = _swig_property(_family_get) %} } /* ************************************************************************************ * Structure module_qstate * ************************************************************************************ */ %ignore module_qstate::ext_state; %ignore module_qstate::minfo; /* Query state */ struct module_qstate { struct query_info qinfo; uint16_t query_flags; //See QF_BIT_xx constants int is_priming; 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]; struct module_env* env; /* unwrapped */ struct mesh_state* mesh_info; }; %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 %} %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; } } %} %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) __swig_getmethods__["ext_state"] = __ext_state_get if _newclass:ext_state = _swig_property(__ext_state_get)#, __ext_state_set) %} } /* ************************************************************************************ * 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 * ************************************************************************************ */ 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_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; char* dlv_anchor_file; struct config_strlist* dlv_anchor_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* control_ifs; int control_port; char* server_key_file; char* server_cert_file; char* control_key_file; char* control_cert_file; int do_daemonize; char* 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 %{ __swig_getmethods__["dname"] = _unboundmodule._get_dp_dname if _newclass:dname = _swig_property(_unboundmodule._get_dp_dname) __swig_getmethods__["dname_list"] = _unboundmodule._get_dp_dname_components if _newclass:dname_list = _swig_property(_unboundmodule._get_dp_dname_components) def _get_dname_str(self): return dnameAsStr(self.dname) __swig_getmethods__["dname_str"] = _get_dname_str if _newclass:dname_str = _swig_property(_get_dname_str) %} } %extend delegpt_ns { %pythoncode %{ __swig_getmethods__["dname"] = _unboundmodule._get_dpns_dname if _newclass:dname = _swig_property(_unboundmodule._get_dpns_dname) __swig_getmethods__["dname_list"] = _unboundmodule._get_dpns_dname_components if _newclass:dname_list = _swig_property(_unboundmodule._get_dpns_dname_components) def _get_dname_str(self): return dnameAsStr(self.dname) __swig_getmethods__["dname_str"] = _get_dname_str if _newclass:dname_str = _swig_property(_get_dname_str) %} } %extend delegpt_addr { %pythoncode %{ def _addr_get(self): return _delegpt_addr_addr_get(self) __swig_getmethods__["addr"] = _addr_get if _newclass:addr = _swig_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_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_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 }; %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)) 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; for (i=0; i < PyList_Size(l); i++) { item = PyList_GetItem(l, i); len = sldns_buffer_remaining(qb); if(qsec) { if(sldns_str2wire_rr_question_buf(PyBytes_AsString(item), sldns_buffer_current(qb), &len, NULL, NULL, 0, NULL, 0) != 0) return 0; } else { if(sldns_str2wire_rr_buf(PyBytes_AsString(item), sldns_buffer_current(qb), &len, NULL, default_ttl, NULL, 0, NULL, 0) != 0) return 0; } 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 contants""" 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 iter_dp_is_useless(struct query_info* qinfo, uint16_t qflags, struct delegpt* dp); struct iter_hints_stub* hints_lookup_stub(struct iter_hints* hints, uint8_t* qname, uint16_t qclass, struct delegpt* dp); /* 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; 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); if(!dp) return NULL; if(iter_dp_is_useless(&qinfo, BIT_RD, dp)) { 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); if (stub) { return stub->dp; } else { return dp; } } return NULL; } %} /* ************************************************************************************ * 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, ...); 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); // 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);