Maintained by: NLnet Labs

[Unbound-users] Sending a query from within processing a query in the python module

Paul Wouters
Mon Jan 20 02:11:41 CET 2014


Hi,

We're using a modified "unbound python example". The idea is that when
an A or AAAA query comes in, we wait to query for an IPSECKEY record
before returning the A/AAAA to the application.

As a proof of concept, we used python-dns to fire off the query for the
IPSECKEY record within the unbound python module we load, which then
hits unbound from the outside. This was just a hack, but clearly not
the right way to use it.

How can we do this within the unbound? Can it be done in the python
module, or do we need to use a C module to get more access to various
parts of the iterator?

Or how can we invoke a sub-query? How can we combine the results of a
subquery with the query we are postponing?

Further issue is that our code needs to have the IPSECKEY query result at
the same time as the A record result. This way, we can pass this IPsec
key and the IP address to a shell command (commands.getstatusoutput())
to build an IPsec tunnel, before the A record is returned to the application.

Attached is our little proof of concept code hack.

Paul
-------------- next part --------------
import sys, commands
sys.path.append("/usr/lib/python2.6/site-packages/")
import dns.resolver
import base64

myname = "rhel6.nohats.ca"
myip = "193.110.157.150"

def init(id, cfg):
   global mykey
   log_info("pythonmod: init called, module id is %d port: %d script: %s" % (id, cfg.port, cfg.python_script))
   return True

def deinit(id):
   log_info("pythonmod: deinit called, module id is %d" % id)
   return True

def inform_super(id, qstate, superqstate, qdata):
   log_info("pythonmod: inform_super called, module id is %s, qstate:%s, superqstate:%s, qdata:%s" % (id, qstate, superqstate, qdata))
   return True

def operate(id, event, qstate, qdata):
   global myname
   global myip
   #log_info("pythonmod: operate called, id: %d, event:%s" % (id, strmodulevent(event)))

   if event == MODULE_EVENT_NEW or event == MODULE_EVENT_PASS:
      qstate.ext_state[id] = MODULE_WAIT_MODULE 
      mykey = "<unknown>"
      if qstate.qinfo.qtype in ( 1, 28 ):
            log_info("qname:%s qtype:%s rcode:%s"%(qstate.qinfo.qname_str,qstate.qinfo.qtype, qstate.return_rcode))
            ipseckey = commands.getoutput("ipsec showhostkey --ipseckey")
            if "IPSECKEY" in ipseckey:
               mykey = ipseckey.rsplit(" ")[-1]
               log_info("We found our IPSECKEY to be: %s"%mykey)
            else:
               log_info("We failed to find our IPSECKEY in: %s"%ipseckey)
            try:
                     ipseckeys = dns.resolver.query(qstate.qinfo.qname_str, 'IPSECKEY')
                     for answer in ipseckeys:
                         b64_answer = base64.b64encode(answer.key)
                         log_info("IPSECKEY record found for '%s': %s"%(qstate.qinfo.qname_str,b64_answer))
                         leftwhack = 'ipsec whack --label "%s leftrsasigkey"  --keyid "@%s" --pubkeyrsa "0s%s"'%(qstate.qinfo.qname_str, myname, mykey)
                         rightwhack = 'ipsec whack --label "%s rightrsasigkey"  --keyid "@%s" --pubkeyrsa "0s%s"'%(qstate.qinfo.qname_str,qstate.qinfo.qname_str,b64_answer)
                         addwhack = 'ipsec whack --name %s --encrypt --tunnel --pfs --rsasig --host "%s" --updown "ipsec _updown" --id @%s --to --host "193.110.157.102" --updown "ipsec _updown" --id "@%s" --keyingtries "1" ' %(qstate.qinfo.qname_str, myip, myname, qstate.qinfo.qname_str)
                         upwhack = 'ipsec whack --initiate --name %s'%qstate.qinfo.qname_str
			 log_info(leftwhack)
			 log_info(rightwhack)
			 log_info(addwhack)
			 log_info(upwhack)
                         for cmd in ( leftwhack, rightwhack, addwhack, upwhack ):
                             status, result = commands.getstatusoutput(cmd)
                             log_info("Status:%s, Output: %s"%(status,result))

            except:
                     log_info("ERROR in IPSECKEY record query for '%s' - ignoring for now"%qstate.qinfo.qname_str)

            qstate.ext_state[id] = MODULE_WAIT_MODULE
            return True

      return True

   if event == MODULE_EVENT_MODDONE:
      #log_info("pythonmod: module we are waiting for is done")
      qstate.ext_state[id] = MODULE_FINISHED 
      return True

   log_err("pythonmod: BAD event")
   qstate.ext_state[id] = MODULE_ERROR
   return True

log_info("pythonmod: script loaded.")