mirror of
https://github.com/NLnetLabs/unbound.git
synced 2026-08-28 10:50:05 +02: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:
+1
-1
@@ -34,7 +34,7 @@
|
||||
|
||||
SUEXEC = sudo
|
||||
UNBOUND = ../unbound
|
||||
SCRIPT = ./test-dict.conf
|
||||
SCRIPT = ./test-resip.conf
|
||||
|
||||
UNBOUND_OPTS = -dv -c $(SCRIPT)
|
||||
|
||||
|
||||
@@ -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
|
||||
* ************************************************************************************ */
|
||||
|
||||
+38
-22
@@ -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 */
|
||||
|
||||
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user