From: Wouter Wijngaards Date: Thu, 3 Sep 2009 14:51:38 +0000 (+0000) Subject: source IP from python and doxygen fixes. X-Git-Tag: release-1.4.0rc1~90 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e46441787cff9d2b6af48be5ea8214014c811228;p=thirdparty%2Funbound.git source IP from python and doxygen fixes. git-svn-id: file:///svn/unbound/trunk@1813 be551aaa-1e26-0410-a405-d3ace91eadb9 --- diff --git a/doc/Changelog b/doc/Changelog index 852d17be0..dd7049fe9 100644 --- a/doc/Changelog +++ b/doc/Changelog @@ -3,6 +3,9 @@ pick up the system resolvconf nameservers and hosts there. - included ldns updated (enum warning fixed). - makefile fix for parallel makes. + - Patch from Zdenek Vasicek and Attila Nagy for using the source IP + from python scripts. See pythonmod/examples/resip.py. + - doxygen comment fixes. 2 September 2009: Wouter - TRAFFIC keyword for testbound. Simplifies test generation. diff --git a/doc/unbound.doxygen b/doc/unbound.doxygen index 328d11e66..fb8764982 100644 --- a/doc/unbound.doxygen +++ b/doc/unbound.doxygen @@ -499,6 +499,7 @@ EXCLUDE = ./build \ pythonmod/interface.h \ pythonmod/examples/resgen.py \ pythonmod/examples/resmod.py \ + pythonmod/examples/resip.py \ libunbound/python/unbound.py \ libunbound/python/libunbound_wrap.c \ ./ldns-src diff --git a/pythonmod/Makefile b/pythonmod/Makefile index bf35bec72..2a0015241 100644 --- a/pythonmod/Makefile +++ b/pythonmod/Makefile @@ -34,7 +34,7 @@ SUEXEC = sudo UNBOUND = ../unbound -SCRIPT = ./test-dict.conf +SCRIPT = ./test-resip.conf UNBOUND_OPTS = -dv -c $(SCRIPT) diff --git a/pythonmod/examples/resip.py b/pythonmod/examples/resip.py new file mode 100644 index 000000000..6bcac7252 --- /dev/null +++ b/pythonmod/examples/resip.py @@ -0,0 +1,96 @@ +''' + resip.py: This example shows how to generate authoritative response + and how to find out the IP address of a client + + Copyright (c) 2009, Zdenek Vasicek (vasicek AT fit.vutbr.cz) + Marek Vavrusa (xvavru00 AT stud.fit.vutbr.cz) + + This software is open source. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * Neither the name of the organization nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + + Usage: + + dig @127.0.0.1 -t TXT what.is.my.ip. +''' + +def init(id, cfg): return True + +def deinit(id): return True + +def inform_super(id, qstate, superqstate, qdata): return True + +def operate(id, event, qstate, qdata): + print "Operate", event,"state:",qstate + + # Please note that if this module blocks, by moving to the validator + # to validate or iterator to lookup or spawn a subquery to look up, + # then, other incoming queries are queued up onto this module and + # all of them receive the same reply. + # You can inspect the cache. + + if (event == MODULE_EVENT_NEW) or (event == MODULE_EVENT_PASS): + if (qstate.qinfo.qname_str.endswith("what.is.my.ip.")): #query name ends with localdomain + #create instance of DNS message (packet) with given parameters + msg = DNSMessage(qstate.qinfo.qname_str, RR_TYPE_TXT, RR_CLASS_IN, PKT_QR | PKT_RA | PKT_AA) + #append RR + if (qstate.qinfo.qtype == RR_TYPE_TXT) or (qstate.qinfo.qtype == RR_TYPE_ANY): + rl = qstate.mesh_info.reply_list + while (rl): + if rl.query_reply: + q = rl.query_reply + # The TTL of 0 is mandatory, otherwise it ends up in + # the cache, and is returned to other IP addresses. + msg.answer.append("%s 0 IN TXT \"%s %d (%s)\"" % (qstate.qinfo.qname_str, q.addr,q.port,q.family)) + rl = rl.next + + #set qstate.return_msg + if not msg.set_return_msg(qstate): + qstate.ext_state[id] = MODULE_ERROR + return True + + #we don't need validation, result is valid + qstate.return_msg.rep.security = 2 + + qstate.return_rcode = RCODE_NOERROR + qstate.ext_state[id] = MODULE_FINISHED + return True + else: + #pass the query to validator + qstate.ext_state[id] = MODULE_WAIT_MODULE + return True + + if event == MODULE_EVENT_MODDONE: + log_info("pythonmod: iterator module done") + qstate.ext_state[id] = MODULE_FINISHED + return True + + log_err("pythonmod: bad event") + qstate.ext_state[id] = MODULE_ERROR + return True diff --git a/pythonmod/interface.i b/pythonmod/interface.i index 63ec6be8b..733430d29 100644 --- a/pythonmod/interface.i +++ b/pythonmod/interface.i @@ -17,6 +17,7 @@ #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" @@ -24,6 +25,7 @@ #include "util/data/dname.h" #include "util/storage/lruhash.h" #include "services/cache/dns.h" + #include "services/mesh.h" %} %include "stdint.i" // uint_16_t can be known type now @@ -408,6 +410,68 @@ struct dns_msg { %} } +/* ************************************************************************************ * + 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 PyString_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 PyString_FromString("ip4"); + case AF_INET6: return PyString_FromString("ip6"); + case AF_UNIX: return PyString_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 * ************************************************************************************ */ diff --git a/pythonmod/pythonmod_utils.c b/pythonmod/pythonmod_utils.c index ca383b699..3f4d41447 100644 --- a/pythonmod/pythonmod_utils.c +++ b/pythonmod/pythonmod_utils.c @@ -40,6 +40,7 @@ */ #include "config.h" #include "util/module.h" +#include "util/netevent.h" #include "util/net_help.h" #include "services/cache/dns.h" #include "services/cache/rrset.h" @@ -52,13 +53,13 @@ #undef _XOPEN_SOURCE #include -/** Store the reply_info and query_info pair in message cache (qstate->msg_cache) */ +/* Store the reply_info and query_info pair in message cache (qstate->msg_cache) */ int storeQueryInCache(struct module_qstate* qstate, struct query_info* qinfo, struct reply_info* msgrep, int is_referral) { if (!msgrep) return 0; - if (msgrep->authoritative) //authoritative answer can't be stored in cache + if (msgrep->authoritative) /*authoritative answer can't be stored in cache*/ { PyErr_SetString(PyExc_ValueError, "Authoritative answer can't be stored"); return 0; @@ -67,7 +68,7 @@ int storeQueryInCache(struct module_qstate* qstate, struct query_info* qinfo, st return dns_cache_store(qstate->env, qinfo, msgrep, is_referral); } -/** Invalidate the message associated with query_info stored in message cache */ +/* Invalidate the message associated with query_info stored in message cache */ void invalidateQueryInCache(struct module_qstate* qstate, struct query_info* qinfo) { hashvalue_t h; @@ -78,10 +79,10 @@ void invalidateQueryInCache(struct module_qstate* qstate, struct query_info* qin h = query_info_hash(qinfo); if ((e=slabhash_lookup(qstate->env->msg_cache, h, qinfo, 0))) { - r = (struct reply_info*)(e->data); - if (r) - { - r->ttl = 0; + r = (struct reply_info*)(e->data); + if (r) + { + r->ttl = 0; if(rrset_array_lock(r->ref, r->rrset_count, *qstate->env->now)) { for(i=0; i< r->rrset_count; i++) { @@ -96,14 +97,14 @@ void invalidateQueryInCache(struct module_qstate* qstate, struct query_info* qin } rrset_array_unlock(r->ref, r->rrset_count); } - } - lock_rw_unlock(&e->lock); + } + lock_rw_unlock(&e->lock); } else { - log_info("invalidateQueryInCache: qinfo is not in cache"); + log_info("invalidateQueryInCache: qinfo is not in cache"); } } -/** Create response according to the ldns packet content */ +/* Create response according to the ldns packet content */ int createResponse(struct module_qstate* qstate, ldns_buffer* pkt) { struct msg_parse* prs; @@ -112,8 +113,8 @@ int createResponse(struct module_qstate* qstate, ldns_buffer* pkt) /* parse message */ prs = (struct msg_parse*) regional_alloc(qstate->env->scratch, sizeof(struct msg_parse)); if (!prs) { - log_err("storeResponse: out of memory on incoming message"); - return 0; + log_err("storeResponse: out of memory on incoming message"); + return 0; } memset(prs, 0, sizeof(*prs)); @@ -121,12 +122,12 @@ int createResponse(struct module_qstate* qstate, ldns_buffer* pkt) ldns_buffer_set_position(pkt, 0); if (parse_packet(pkt, prs, qstate->env->scratch) != LDNS_RCODE_NOERROR) { - verbose(VERB_ALGO, "storeResponse: parse error on reply packet"); - return 0; + verbose(VERB_ALGO, "storeResponse: parse error on reply packet"); + return 0; } /* edns is not examined, but removed from message to help cache */ if(parse_extract_edns(prs, &edns) != LDNS_RCODE_NOERROR) - return 0; + return 0; /* remove CD-bit, we asked for in case we handle validation ourself */ prs->flags &= ~BIT_CD; @@ -138,23 +139,38 @@ int createResponse(struct module_qstate* qstate, ldns_buffer* pkt) memset(qstate->return_msg, 0, sizeof(*qstate->return_msg)); if(!parse_create_msg(pkt, prs, NULL, &(qstate->return_msg)->qinfo, &(qstate->return_msg)->rep, qstate->region)) { - log_err("storeResponse: malloc failure: allocating incoming dns_msg"); - return 0; + log_err("storeResponse: malloc failure: allocating incoming dns_msg"); + return 0; } /* Make sure that the RA flag is set (since the presence of * this module means that recursion is available) */ - //qstate->return_msg->rep->flags |= BIT_RA; + /* qstate->return_msg->rep->flags |= BIT_RA; */ /* Clear the AA flag */ /* FIXME: does this action go here or in some other module? */ - //qstate->return_msg->rep->flags &= ~BIT_AA; + /*qstate->return_msg->rep->flags &= ~BIT_AA; */ /* make sure QR flag is on */ - //qstate->return_msg->rep->flags |= BIT_QR; + /*qstate->return_msg->rep->flags |= BIT_QR; */ if(verbosity >= VERB_ALGO) - log_dns_msg("storeResponse: packet:", &qstate->return_msg->qinfo, qstate->return_msg->rep); + log_dns_msg("storeResponse: packet:", &qstate->return_msg->qinfo, qstate->return_msg->rep); return 1; } + + +/* Convert reply->addr to string */ +void reply_addr2str(struct comm_reply* reply, char* dest, int maxlen) +{ + int af = (int)((struct sockaddr_in*) &(reply->addr))->sin_family; + void* sinaddr = &((struct sockaddr_in*) &(reply->addr))->sin_addr; + + if(af == AF_INET6) + sinaddr = &((struct sockaddr_in6*)&(reply->addr))->sin6_addr; + dest[0] = 0; + if (inet_ntop(af, sinaddr, dest, (socklen_t)maxlen) == 0) + return; + dest[maxlen-1] = 0; +} diff --git a/pythonmod/pythonmod_utils.h b/pythonmod/pythonmod_utils.h index bd4d6edae..2aa8f7572 100644 --- a/pythonmod/pythonmod_utils.h +++ b/pythonmod/pythonmod_utils.h @@ -77,4 +77,12 @@ void invalidateQueryInCache(struct module_qstate* qstate, struct query_info* qin */ int createResponse(struct module_qstate* qstate, ldns_buffer* pkt); +/** + * Convert reply->addr to string + * @param reply: comm reply with address in it. + * @param dest: destination string. + * @param maxlen: length of string buffer. + */ +void reply_addr2str(struct comm_reply* reply, char* dest, int maxlen); + #endif /* PYTHONMOD_UTILS_H */ diff --git a/pythonmod/test-resip.conf b/pythonmod/test-resip.conf new file mode 100644 index 000000000..7620f736f --- /dev/null +++ b/pythonmod/test-resip.conf @@ -0,0 +1,18 @@ +# Example configuration file for resip.py +server: + verbosity: 1 + #interface: 0.0.0.0 + do-daemonize: no + #access-control: 0.0.0.0/0 allow + chroot: "" + username: "" + directory: "" + logfile: "" + pidfile: "unbound.pid" + module-config: "validator python iterator" + +# Python config section +python: + # Script file to load + python-script: "./examples/resip.py" + diff --git a/util/config_file.c b/util/config_file.c index cccedbbad..1d8587445 100644 --- a/util/config_file.c +++ b/util/config_file.c @@ -59,8 +59,6 @@ int ub_c_parse(void); int ub_c_lex(void); /** wrap function */ int ub_c_wrap(void); -/** print error with file and line number */ -void ub_c_error(const char *message); /** init ports possible for use */ static void init_outgoing_availports(int* array, int num); diff --git a/util/mini_event.c b/util/mini_event.c index 597276c89..aa5a92e6f 100644 --- a/util/mini_event.c +++ b/util/mini_event.c @@ -252,7 +252,7 @@ int event_base_loopexit(struct event_base* base, return 0; } -/** free event base, free events yourself */ +/* free event base, free events yourself */ void event_base_free(struct event_base* base) { if(!base) @@ -279,7 +279,7 @@ void event_set(struct event* ev, int fd, short bits, ev->added = 0; } -/** add event to a base */ +/* add event to a base */ int event_base_set(struct event_base* base, struct event* ev) { ev->ev_base = base; @@ -287,7 +287,7 @@ int event_base_set(struct event_base* base, struct event* ev) return 0; } -/** add event to make it active, you may not change it with event_set anymore */ +/* add event to make it active, you may not change it with event_set anymore */ int event_add(struct event* ev, struct timeval* tv) { if(ev->added) @@ -323,7 +323,7 @@ int event_add(struct event* ev, struct timeval* tv) return 0; } -/** remove event, you may change it again */ +/* remove event, you may change it again */ int event_del(struct event* ev) { if(ev->ev_fd != -1 && ev->ev_fd >= ev->ev_base->capfd) diff --git a/util/mini_event.h b/util/mini_event.h index 4813402f0..248468ada 100644 --- a/util/mini_event.h +++ b/util/mini_event.h @@ -88,8 +88,16 @@ struct event_base int maxfd; /** capacity - size of the fds array */ int capfd; - /** fdset for read write, for fds ready, and added */ - fd_set reads, writes, ready, content; + /* fdset for read write, for fds ready, and added */ + fd_set + /** fds for reading */ + reads, + /** fds for writing */ + writes, + /** fds determined ready for use */ + ready, + /** ready plus newly added events. */ + content; /** array of 0 - maxsig of ptr to event for it */ struct event** signals; /** if we need to exit */ @@ -146,7 +154,9 @@ int event_add(struct event *, struct timeval *); /** remove event. You may change it again */ int event_del(struct event *); +/** add a timer */ #define evtimer_add(ev, tv) event_add(ev, tv) +/** remove a timer */ #define evtimer_del(ev) event_del(ev) /* uses different implementation. Cannot mix fd/timeouts and signals inside diff --git a/validator/val_anchor.c b/validator/val_anchor.c index cfc2c0dbb..4c6116373 100644 --- a/validator/val_anchor.c +++ b/validator/val_anchor.c @@ -481,7 +481,7 @@ is_bind_special(int c) /** * Read a keyword skipping bind comments; spaces, specials, restkeywords. * The file is split into the following tokens: - * * special characters, on their own, rdlen=1, { } " ; + * * special characters, on their own, rdlen=1, { } doublequote ; * * whitespace becomes a single ' ' or tab. Newlines become spaces. * * other words ('keywords') * * comments are skipped if desired