diff options
Diffstat (limited to 'pythonmod/examples')
-rw-r--r-- | pythonmod/examples/inplace_callbacks.py | 103 | ||||
-rw-r--r-- | pythonmod/examples/resip.py | 20 |
2 files changed, 98 insertions, 25 deletions
diff --git a/pythonmod/examples/inplace_callbacks.py b/pythonmod/examples/inplace_callbacks.py index 02ee56e36e21..e47fc8292be2 100644 --- a/pythonmod/examples/inplace_callbacks.py +++ b/pythonmod/examples/inplace_callbacks.py @@ -6,18 +6,18 @@ Copyright (c) 2016, NLnet Labs. 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. @@ -43,6 +43,8 @@ # This query returns SERVFAIL as the txt record of bogus.nlnetlabs.nl is # intentionally bogus. The reply will contain an empty EDNS option # with option code 65003. +# Unbound will also log the source address(es) of the client(s) that made +# the request. # (unbound needs to be validating for this example to work) # Useful functions: @@ -70,9 +72,11 @@ def inplace_reply_callback(qinfo, qstate, rep, rcode, edns, opt_list_out, - region): - """Function that will be registered as an inplace callback function. + region, **kwargs): + """ + Function that will be registered as an inplace callback function. It will be called when answering with a resolved query. + :param qinfo: query_info struct; :param qstate: module qstate. It contains the available opt_lists; It SHOULD NOT be altered; @@ -84,16 +88,25 @@ def inplace_reply_callback(qinfo, qstate, rep, rcode, edns, opt_list_out, reply. It can be populated with EDNS options; :param region: region to allocate temporary data. Needs to be used when we want to append a new option to opt_list_out. + :param **kwargs: Dictionary that may contain parameters added in a future + release. Current parameters: + ``repinfo``: Reply information for a communication point (comm_reply). + It is None when the callback happens in the mesh + states(modules). + :return: True on success, False on failure. + """ log_info("python: called back while replying.") return True def inplace_cache_callback(qinfo, qstate, rep, rcode, edns, opt_list_out, - region): - """Function that will be registered as an inplace callback function. + region, **kwargs): + """ + Function that will be registered as an inplace callback function. It will be called when answering from the cache. + :param qinfo: query_info struct; :param qstate: module qstate. None; :param rep: reply_info struct; @@ -105,10 +118,17 @@ def inplace_cache_callback(qinfo, qstate, rep, rcode, edns, opt_list_out, reply. It can be populated with EDNS options; :param region: region to allocate temporary data. Needs to be used when we want to append a new option to opt_list_out. + :param **kwargs: Dictionary that may contain parameters added in a future + release. Current parameters: + ``repinfo``: Reply information for a communication point (comm_reply). + It is None when the callback happens in the mesh + states(modules). + :return: True on success, False on failure. For demonstration purposes we want to see if EDNS option 65002 is present and reply with a new value. + """ log_info("python: called back while answering from cache.") # Inspect the incoming EDNS options. @@ -134,9 +154,11 @@ def inplace_cache_callback(qinfo, qstate, rep, rcode, edns, opt_list_out, def inplace_local_callback(qinfo, qstate, rep, rcode, edns, opt_list_out, - region): - """Function that will be registered as an inplace callback function. + region, **kwargs): + """ + Function that will be registered as an inplace callback function. It will be called when answering from local data. + :param qinfo: query_info struct; :param qstate: module qstate. None; :param rep: reply_info struct; @@ -148,7 +170,14 @@ def inplace_local_callback(qinfo, qstate, rep, rcode, edns, opt_list_out, reply. It can be populated with EDNS options; :param region: region to allocate temporary data. Needs to be used when we want to append a new option to opt_list_out. + :param **kwargs: Dictionary that may contain parameters added in a future + release. Current parameters: + ``repinfo``: Reply information for a communication point (comm_reply). + It is None when the callback happens in the mesh + states(modules). + :return: True on success, False on failure. + """ log_info("python: called back while replying with local data or chaos" " reply.") @@ -156,9 +185,11 @@ def inplace_local_callback(qinfo, qstate, rep, rcode, edns, opt_list_out, def inplace_servfail_callback(qinfo, qstate, rep, rcode, edns, opt_list_out, - region): - """Function that will be registered as an inplace callback function. + region, **kwargs): + """ + Function that will be registered as an inplace callback function. It will be called when answering with SERVFAIL. + :param qinfo: query_info struct; :param qstate: module qstate. If not None the relevant opt_lists are available here; @@ -171,23 +202,62 @@ def inplace_servfail_callback(qinfo, qstate, rep, rcode, edns, opt_list_out, reply. It can be populated with EDNS options; :param region: region to allocate temporary data. Needs to be used when we want to append a new option to opt_list_out. + :param **kwargs: Dictionary that may contain parameters added in a future + release. Current parameters: + ``repinfo``: Reply information for a communication point (comm_reply). + It is None when the callback happens in the mesh + states(modules). + :return: True on success, False on failure. - For demonstration purposes we want to reply with an empty EDNS code '65003'. + For demonstration purposes we want to reply with an empty EDNS code '65003' + and log the IP address(es) of the client(s). + """ log_info("python: called back while servfail.") + # Append the example ENDS option b = bytearray.fromhex("") edns_opt_list_append(opt_list_out, 65003, b, region) + + # Log the client(s) IP address(es) + comm_reply = kwargs['repinfo'] + if comm_reply: + # If it is not None this callback was called before the query reached + # the mesh states(modules). There is only one client associated with + # this query. + addr = comm_reply.addr + port = comm_reply.port + addr_family = comm_reply.family + log_info("python: Client IP: {}({}), port: {}" + "".format(addr, addr_family, port)) + else: + # If it is not None this callback was called while the query is in the + # mesh states(modules). In this case they may be multiple clients + # waiting for this query. + # The following code is the same as with the resip.py example. + rl = qstate.mesh_info.reply_list + while (rl): + if rl.query_reply: + q = rl.query_reply + log_info("python: Client IP: {}({}), port: {}" + "".format(q.addr, q.family, q.port)) + rl = rl.next + + return True def init_standard(id, env): - """New version of the init function. + """ + New version of the init function. + The function's signature is the same as the C counterpart and allows for extra functionality during init. + ..note:: This function is preferred by unbound over the old init function. ..note:: The previously accessible configuration options can now be found in env.cgf. + """ log_info("python: inited script {}".format(env.cfg.python_script)) @@ -215,11 +285,14 @@ def init_standard(id, env): def init(id, cfg): - """Previous version init function. + """ + Previous version of the init function. + ..note:: This function is still supported for backwards compatibility when the init_standard function is missing. When init_standard is present this function SHOULD be omitted to avoid confusion to the reader. + """ return True diff --git a/pythonmod/examples/resip.py b/pythonmod/examples/resip.py index 6bcac7252cd2..4a9f24fc6448 100644 --- a/pythonmod/examples/resip.py +++ b/pythonmod/examples/resip.py @@ -47,7 +47,7 @@ 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 + print("Operate {} state: {}".format(event, 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, @@ -61,14 +61,14 @@ def operate(id, event, qstate, qdata): 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 + 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): @@ -90,7 +90,7 @@ def operate(id, event, qstate, qdata): 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 |