]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
source IP from python and doxygen fixes.
authorWouter Wijngaards <wouter@nlnetlabs.nl>
Thu, 3 Sep 2009 14:51:38 +0000 (14:51 +0000)
committerWouter Wijngaards <wouter@nlnetlabs.nl>
Thu, 3 Sep 2009 14:51:38 +0000 (14:51 +0000)
git-svn-id: file:///svn/unbound/trunk@1813 be551aaa-1e26-0410-a405-d3ace91eadb9

12 files changed:
doc/Changelog
doc/unbound.doxygen
pythonmod/Makefile
pythonmod/examples/resip.py [new file with mode: 0644]
pythonmod/interface.i
pythonmod/pythonmod_utils.c
pythonmod/pythonmod_utils.h
pythonmod/test-resip.conf [new file with mode: 0644]
util/config_file.c
util/mini_event.c
util/mini_event.h
validator/val_anchor.c

index 852d17be0d31add696acbb6b6c96a199654767d8..dd7049fe9e6077aa37000c1db99392f971e14a6d 100644 (file)
@@ -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.
index 328d11e6658e3e8cc1fa525293d32f7f42f7e0ee..fb8764982d1102debcf7cfebfa2a05a41916c0ab 100644 (file)
@@ -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
index bf35bec72da8c59c50f4abdd75c9cfb272960774..2a00152418ab6b946d3699d251a8f30d3c21357a 100644 (file)
@@ -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 (file)
index 0000000..6bcac72
--- /dev/null
@@ -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
index 63ec6be8b1bec3f1a127c5e2104a948ac6bd8327..733430d29739a0102440a6b930e849e82aefbddd 100644 (file)
@@ -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
  * ************************************************************************************ */
index ca383b6995df539ac583f1d04fc374a2729d117f..3f4d41447c82f67807b9b59e43a9d9156a2390a2 100644 (file)
@@ -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"
 #undef _XOPEN_SOURCE
 #include <Python.h>
 
-/** 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;
+}
index bd4d6edae9c6e3995b0ab282064562781ae262c2..2aa8f7572cc2ab5332a63a04a9406855ec6f3bf2 100644 (file)
@@ -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 (file)
index 0000000..7620f73
--- /dev/null
@@ -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"
+
index cccedbbad0a88adf829ad4ff02677bc03d4082ce..1d8587445fa8b46b316683729529d6e5c6380045 100644 (file)
@@ -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);
index 597276c8993db7d604e1a7fdb697591e1df3159d..aa5a92e6f9ab244bf110a4ed801d2ed1b831e426 100644 (file)
@@ -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)
index 4813402f079e36558e48fa0f18f1591a69962db0..248468ada84ab3eb39f8527ae53c495bc559b574 100644 (file)
@@ -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
index cfc2c0dbbe213f2171361c2ebf29f2912395b8d6..4c6116373136016fae740c2aa2e18b914c50e060 100644 (file)
@@ -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