source IP from python and doxygen fixes.

git-svn-id: file:///svn/unbound/trunk@1813 be551aaa-1e26-0410-a405-d3ace91eadb9
This commit is contained in:
Wouter Wijngaards 2009-09-03 14:51:38 +00:00
parent cd3a1ff351
commit e46441787c
12 changed files with 246 additions and 32 deletions

View 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.

View 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

View File

@ -34,7 +34,7 @@
SUEXEC = sudo
UNBOUND = ../unbound
SCRIPT = ./test-dict.conf
SCRIPT = ./test-resip.conf
UNBOUND_OPTS = -dv -c $(SCRIPT)

View File

@ -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

View 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
* ************************************************************************************ */

View 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"
@ -52,13 +53,13 @@
#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;
}

View 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 */

18
pythonmod/test-resip.conf Normal file
View File

@ -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"

View 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);

View 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)

View 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

View 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