Python module example documentation bug and crasher

I looked at:

http://www.unbound.net/documentation/pythonmod/examples/example0.html#complete-source-code

When loading that module, unbound always SERVFAIL's. Thinking that this
section was wrongly returning MODULE_ERROR:

  if event == MODULE_EVENT_PASS:
       log_info("pythonmod: event_pass")
       qstate.ext_state[id] = MODULE_ERROR
       return True

I changed it to MODULE_FINISHED. However, that lead to a crash in
unbound:

(gdb) l
2738 return;
2739 }
2740 /* Fetch and validate the keyEntry that corresponds to
the 2741 * current trust anchor. */
2742 if(rcode == LDNS_RCODE_NOERROR) {
2743 dnskey_rrset =
reply_find_rrset_section_an(msg->rep,
2744 ta->name, ta->namelen,
LDNS_RR_TYPE_DNSKEY,
2745 ta->dclass);
2746 }
2747 if(ta->autr) {
(gdb) p *ta
$1 = {node = {parent = 0x7ffff8263140, left = 0x7ffff82010c0, right =
0x7ffff82010c0, key = 0x7ffff8263730, color = 1 '\001'}, lock = {
     __data = {__lock = 1, __count = 0, __owner = 31031, __nusers = 1,
__kind = 0, __spins = 0, __list = {__prev = 0x0, __next = 0x0}},
     __size = "\001\000\000\000\000\000\000\000\067y\000\000\001", '\000'
<repeats 26 times>, __align = 1}, name = 0x7ffff8254470 "",
   namelen = 1, namelabs = 1, parent = 0x0, keylist = 0x0, autr =
0x7ffff82637e0, numDS = 0, numDNSKEY = 1, ds_rrset = 0x0,
   dnskey_rrset = 0x7ffff8263310, dclass = 1}
(gdb) p msg
$2 = (struct dns_msg *) 0x0
(gdb)

When changed to MODULE_WAIT_MODULE it seemed to work.

Paul

Hi Paul.

We fixed this in the current code. Our code now works, and actually
triggers an IPsec tunnel that established.

Attached for others to look at as example, although we still have more
work to do to make it work fully.

We are still wondering why there is some slowness between when the
ipsec tunnel comes up and the application sees the A recorc answer.
This seems to be about 9 seconds and we have no idea what unbound
is doing.

We would also still like to have something better than running
dns.resolver() that more natively goes back into the unbound code.

Paul

(attachments)

ubmodule-tst.py (5.6 KB)

Use module_env, send_query() or attach_sub(). Send query sends a udp
packet (with fallback to TCP and EDNS detection). attach_sub creates
a recursive lookup that is facilitated by unbound (fully validated
result at the end, can recurse further to lookup the nameservers and
dnssec chain of trust for it). In both cases an event is triggered
when the result arrives. The result for the recursion case should not
perform heavy processing - it should especially refrain from making
other recursion calls and not write to UDP buffers - it should instead
stash the data in an internal structure and set it up so that an
upcoming event (module_run) to continue processing outside of the
'interrupt-style' result event can be used for the actual processing.

Best regards,
   Wouter

I'm not sure I fully understand if this can be used.

unbound receives a lookup for an A record. We let unbound continue
until it calls operate() with MODULE_EVENT_MODDONE. Then we want to
launch a lookup for IPSECKEY. You say we should send_query(). This
requires us to create a new qstate to pass with send_query. Then this
operate() should return with MODULE_WAIT_MODULE?

Then we have two lookups in flight. If the send_query has something for
us, I assume we would catch it again in operate(). But that is a
different qstate, the one we created. I don't think we have access to
the previous qstate? How does this information transfer back to the
other qstate handling? How do we ever get back into the first query
to return the A record? Do we just return MODULE_FINISHED in the
IPSECKEY lookup and will that trigger a new operate() for the first
query? And if so, how do we grab the IPSECKEY data from that query?
Is it somewhere reachable in the cache?

Paul