mirror of
https://github.com/mollyim/unbound.git
synced 2025-05-12 21:30:35 +01:00
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:
parent
cd3a1ff351
commit
e46441787c
12 changed files with 246 additions and 32 deletions
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -34,7 +34,7 @@
|
|||
|
||||
SUEXEC = sudo
|
||||
UNBOUND = ../unbound
|
||||
SCRIPT = ./test-dict.conf
|
||||
SCRIPT = ./test-resip.conf
|
||||
|
||||
UNBOUND_OPTS = -dv -c $(SCRIPT)
|
||||
|
||||
|
|
96
pythonmod/examples/resip.py
Normal file
96
pythonmod/examples/resip.py
Normal 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
|
|
@ -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
|
||||
* ************************************************************************************ */
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
18
pythonmod/test-resip.conf
Normal 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"
|
||||
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue