aboutsummaryrefslogtreecommitdiff
path: root/external/unbound/pythonmod/doc/examples
diff options
context:
space:
mode:
Diffstat (limited to 'external/unbound/pythonmod/doc/examples')
-rw-r--r--external/unbound/pythonmod/doc/examples/example1.rst14
-rw-r--r--external/unbound/pythonmod/doc/examples/example2.rst45
-rw-r--r--external/unbound/pythonmod/doc/examples/example4.rst180
-rw-r--r--external/unbound/pythonmod/doc/examples/example5.rst191
-rw-r--r--external/unbound/pythonmod/doc/examples/example6.rst299
-rw-r--r--external/unbound/pythonmod/doc/examples/index.rst17
6 files changed, 629 insertions, 117 deletions
diff --git a/external/unbound/pythonmod/doc/examples/example1.rst b/external/unbound/pythonmod/doc/examples/example1.rst
index b49e64409..ccd76da5a 100644
--- a/external/unbound/pythonmod/doc/examples/example1.rst
+++ b/external/unbound/pythonmod/doc/examples/example1.rst
@@ -1,10 +1,12 @@
.. _log_handler:
Packet logger
-=========================
+=============
This example shows how to log and print details about query and response.
-As soon as the ``iterator`` has finished (event is :data:`module_event_moddone`), ``qstate.return_msg`` contains response packet or ``None``.
+As soon as the ``iterator`` has finished (event is
+:data:`module_event_moddone`), ``qstate.return_msg`` contains response packet
+or ``None``.
This packet will be send to a client that asked for it.
Complete source code
@@ -14,14 +16,16 @@ Complete source code
:language: python
Testing
-------------------
+-------
Run the unbound server:
``root@localhost>unbound -dv -c ./test-log.conf``
-In case you use own configuration file, don't forget to enable python module: ``module-config: "validator python iterator"`` and use valid script path: ``python-script: "./examples/log.py"``.
+In case you use own configuration file, don't forget to enable python module:
+``module-config: "validator python iterator"`` and use valid script path:
+``python-script: "./examples/log.py"``.
-Example of output::
+Example of output::
[1231790168] unbound[7941:0] info: response for <f.gtld-servers.NET. AAAA IN>
[1231790168] unbound[7941:0] info: reply from <gtld-servers.NET.> 192.5.6.31#53
diff --git a/external/unbound/pythonmod/doc/examples/example2.rst b/external/unbound/pythonmod/doc/examples/example2.rst
index f00fcc239..4ba9239a0 100644
--- a/external/unbound/pythonmod/doc/examples/example2.rst
+++ b/external/unbound/pythonmod/doc/examples/example2.rst
@@ -1,12 +1,14 @@
Response generation
-=====================
+===================
This example shows how to handle queries and generate response packet.
.. note::
- If the python module is the first module and validator module is enabled (``module-config: "python validator iterator"``),
- a return_msg security flag has to be set at least to 2. Leaving security flag untouched causes that the
- response will be refused by unbound worker as unbound will consider it as non-valid response.
+ If the python module is the first module and validator module is enabled
+ (``module-config: "python validator iterator"``), a return_msg security flag
+ has to be set at least to 2. Leaving security flag untouched causes that the
+ response will be refused by unbound worker as unbound will consider it as
+ non-valid response.
Complete source code
--------------------
@@ -27,20 +29,21 @@ Query for a A record ending with .localdomain
Dig produces the following output::
- ;; global options: printcmd
- ;; Got answer:
- ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 48426
- ;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
-
- ;; QUESTION SECTION:
- ;test.xxx.localdomain. IN A
-
- ;; ANSWER SECTION:
- test.xxx.localdomain. 10 IN A 127.0.0.1
-
- ;; Query time: 2 msec
- ;; SERVER: 127.0.0.1#53(127.0.0.1)
- ;; WHEN: Mon Jan 01 12:46:02 2009
- ;; MSG SIZE rcvd: 54
-
-As we handle (override) in python module only queries ending with "localdomain.", the unboud can still resolve host names.
+ ;; global options: printcmd
+ ;; Got answer:
+ ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 48426
+ ;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
+
+ ;; QUESTION SECTION:
+ ;test.xxx.localdomain. IN A
+
+ ;; ANSWER SECTION:
+ test.xxx.localdomain. 10 IN A 127.0.0.1
+
+ ;; Query time: 2 msec
+ ;; SERVER: 127.0.0.1#53(127.0.0.1)
+ ;; WHEN: Mon Jan 01 12:46:02 2009
+ ;; MSG SIZE rcvd: 54
+
+As we handle (override) in the python module only queries ending with
+``localdomain.``, unboud can still resolve host names.
diff --git a/external/unbound/pythonmod/doc/examples/example4.rst b/external/unbound/pythonmod/doc/examples/example4.rst
index b665351e8..338210990 100644
--- a/external/unbound/pythonmod/doc/examples/example4.rst
+++ b/external/unbound/pythonmod/doc/examples/example4.rst
@@ -1,15 +1,19 @@
DNS-based language dictionary
-===============================
+=============================
This example shows how to create a simple language dictionary based on **DNS**
-service within 15 minutes. The translation will be performed using TXT resource records.
+service within 15 minutes. The translation will be performed using TXT resource
+records.
Key parts
------------
+---------
Initialization
-~~~~~~~~~~~~~~~~~~~~~~~
-On **init()** module loads dictionary from a text file containing records in ``word [tab] translation`` format.
+~~~~~~~~~~~~~~
+
+On **init()** module loads dictionary from a text file containing records in
+``word [tab] translation`` format.
+
::
def init(id, cfg):
@@ -20,11 +24,14 @@ On **init()** module loads dictionary from a text file containing records in ``w
The suitable file can be found at http://slovnik.zcu.cz
DNS query and word lookup
-~~~~~~~~~~~~~~~~~~~~~~~~~~~
+~~~~~~~~~~~~~~~~~~~~~~~~~
-Let's define the following format od DNS queries: ``word1[.]word2[.] ... wordN[.]{en,cs}[._dict_.cz.]``.
+Let's define the following format od DNS queries:
+``word1[.]word2[.] ... wordN[.]{en,cs}[._dict_.cz.]``.
Word lookup is done by simple ``dict`` lookup from broken DNS request.
-Query name is divided into a list of labels. This list is accessible as qname_list attribute.
+Query name is divided into a list of labels. This list is accessible as
+``qname_list`` attribute.
+
::
aword = ' '.join(qstate.qinfo.qname_list[0:-4]) #skip last four labels
@@ -37,35 +44,40 @@ Query name is divided into a list of labels. This list is accessible as qname_li
if (adict == "cs") and (aword in cz_dict):
words = cz_dict[aword] # CS -> EN
-In the first step, we get a string in the form: ``word1[space]word2[space]...word[space]``.
-In the second assignment, fourth label from the end is obtained. This label should contains *"cs"* or *"en"*.
-This label determines the direction of translation.
-
+In the first step, we get a string in the form:
+``word1[space]word2[space]...word[space]``.
+In the second assignment, fourth label from the end is obtained. This label
+should contains *"cs"* or *"en"*. This label determines the direction of
+translation.
Forming of a DNS reply
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+~~~~~~~~~~~~~~~~~~~~~~
DNS reply is formed only on valid match and added as TXT answer.
+
::
- msg = DNSMessage(qstate.qinfo.qname_str, RR_TYPE_TXT, RR_CLASS_IN, PKT_AA)
+ msg = DNSMessage(qstate.qinfo.qname_str, RR_TYPE_TXT, RR_CLASS_IN, PKT_AA)
- for w in words:
- msg.answer.append("%s 300 IN TXT \"%s\"" % (qstate.qinfo.qname_str, w.replace("\"", "\\\"")))
+ for w in words:
+ msg.answer.append("%s 300 IN TXT \"%s\"" % (qstate.qinfo.qname_str, w.replace("\"", "\\\"")))
- if not msg.set_return_msg(qstate):
- qstate.ext_state[id] = MODULE_ERROR
- return True
+ if not msg.set_return_msg(qstate):
+ qstate.ext_state[id] = MODULE_ERROR
+ return True
- qstate.return_rcode = RCODE_NOERROR
- qstate.ext_state[id] = MODULE_FINISHED
- return True
+ qstate.return_rcode = RCODE_NOERROR
+ qstate.ext_state[id] = MODULE_FINISHED
+ return True
-In the first step, a :class:`DNSMessage` instance is created for a given query *(type TXT)*.
+In the first step, a :class:`DNSMessage` instance is created for a given query
+*(type TXT)*.
The fourth argument specifies the flags *(authoritative answer)*.
-In the second step, we append TXT records containing the translation *(on the right side of RR)*.
+In the second step, we append TXT records containing the translation *(on the
+right side of RR)*.
Then, the response is finished and ``qstate.return_msg`` contains new response.
-If no error, the module sets :attr:`module_qstate.return_rcode` and :attr:`module_qstate.ext_state`.
+If no error, the module sets :attr:`module_qstate.return_rcode` and
+:attr:`module_qstate.ext_state`.
**Steps:**
@@ -82,80 +94,82 @@ Run the Unbound server:
In case you use own configuration file, don't forget to enable Python module::
- module-config: "validator python iterator"
+ module-config: "validator python iterator"
and use valid script path::
- python-script: "./examples/dict.py"
+ python-script: "./examples/dict.py"
The translation from english word *"a bar fly"* to Czech can be done by doing:
``>>>dig TXT @127.0.0.1 a.bar.fly.en._dict_.cz``
-::
+::
+
+ ; (1 server found)
+ ;; global options: printcmd
+ ;; Got answer:
+ ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 48691
+ ;; flags: aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
+
+ ;; QUESTION SECTION:
+ ;a.bar.fly.en._dict_.cz. IN TXT
+
+ ;; ANSWER SECTION:
+ a.bar.fly.en._dict_.cz. 300 IN TXT "barov\253 povale\232"
+
+ ;; Query time: 5 msec
+ ;; SERVER: 127.0.0.1#53(127.0.0.1)
+ ;; WHEN: Mon Jan 01 17:44:18 2009
+ ;; MSG SIZE rcvd: 67
- ; (1 server found)
- ;; global options: printcmd
- ;; Got answer:
- ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 48691
- ;; flags: aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
-
- ;; QUESTION SECTION:
- ;a.bar.fly.en._dict_.cz. IN TXT
-
- ;; ANSWER SECTION:
- a.bar.fly.en._dict_.cz. 300 IN TXT "barov\253 povale\232"
-
- ;; Query time: 5 msec
- ;; SERVER: 127.0.0.1#53(127.0.0.1)
- ;; WHEN: Mon Jan 01 17:44:18 2009
- ;; MSG SIZE rcvd: 67
-
``>>>dig TXT @127.0.0.1 nic.cs._dict_.cz``
+
::
- ; <<>> DiG 9.5.0-P2 <<>> TXT @127.0.0.1 nic.cs._dict_.cz
- ; (1 server found)
- ;; global options: printcmd
- ;; Got answer:
- ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 58710
- ;; flags: aa rd ra; QUERY: 1, ANSWER: 6, AUTHORITY: 0, ADDITIONAL: 0
-
- ;; QUESTION SECTION:
- ;nic.cs._dict_.cz. IN TXT
-
- ;; ANSWER SECTION:
- nic.cs._dict_.cz. 300 IN TXT "aught"
- nic.cs._dict_.cz. 300 IN TXT "naught"
- nic.cs._dict_.cz. 300 IN TXT "nihil"
- nic.cs._dict_.cz. 300 IN TXT "nix"
- nic.cs._dict_.cz. 300 IN TXT "nothing"
- nic.cs._dict_.cz. 300 IN TXT "zilch"
-
- ;; Query time: 0 msec
- ;; SERVER: 127.0.0.1#53(127.0.0.1)
- ;; WHEN: Mon Jan 01 17:45:39 2009
- ;; MSG SIZE rcvd: 143
-
-Proof that the unbound still works as resolver.
+ ; <<>> DiG 9.5.0-P2 <<>> TXT @127.0.0.1 nic.cs._dict_.cz
+ ; (1 server found)
+ ;; global options: printcmd
+ ;; Got answer:
+ ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 58710
+ ;; flags: aa rd ra; QUERY: 1, ANSWER: 6, AUTHORITY: 0, ADDITIONAL: 0
+
+ ;; QUESTION SECTION:
+ ;nic.cs._dict_.cz. IN TXT
+
+ ;; ANSWER SECTION:
+ nic.cs._dict_.cz. 300 IN TXT "aught"
+ nic.cs._dict_.cz. 300 IN TXT "naught"
+ nic.cs._dict_.cz. 300 IN TXT "nihil"
+ nic.cs._dict_.cz. 300 IN TXT "nix"
+ nic.cs._dict_.cz. 300 IN TXT "nothing"
+ nic.cs._dict_.cz. 300 IN TXT "zilch"
+
+ ;; Query time: 0 msec
+ ;; SERVER: 127.0.0.1#53(127.0.0.1)
+ ;; WHEN: Mon Jan 01 17:45:39 2009
+ ;; MSG SIZE rcvd: 143
+
+ Proof that the unbound still works as resolver.
``>>>dig A @127.0.0.1 www.nic.cz``
+
::
- ; (1 server found)
- ;; global options: printcmd
- ;; Got answer:
- ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 19996
- ;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 3, ADDITIONAL: 5
-
- ;; QUESTION SECTION:
- ;www.nic.cz. IN A
-
- ;; ANSWER SECTION:
- www.nic.cz. 1662 IN A 217.31.205.50
-
- ;; AUTHORITY SECTION:
- ...
+ ; (1 server found)
+ ;; global options: printcmd
+ ;; Got answer:
+ ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 19996
+ ;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 3, ADDITIONAL: 5
+
+ ;; QUESTION SECTION:
+ ;www.nic.cz. IN A
+
+ ;; ANSWER SECTION:
+ www.nic.cz. 1662 IN A 217.31.205.50
+
+ ;; AUTHORITY SECTION:
+ ...
Complete source code
--------------------
diff --git a/external/unbound/pythonmod/doc/examples/example5.rst b/external/unbound/pythonmod/doc/examples/example5.rst
new file mode 100644
index 000000000..058fc331e
--- /dev/null
+++ b/external/unbound/pythonmod/doc/examples/example5.rst
@@ -0,0 +1,191 @@
+EDNS options
+============
+
+This example shows how to interact with EDNS options.
+
+When quering unbound with the EDNS option ``65001`` and data ``0xc001`` we
+expect an answer with the same EDNS option code and data ``0xdeadbeef``.
+
+
+Key parts
+~~~~~~~~~
+
+This example relies on the following functionalities:
+
+
+Registering EDNS options
+------------------------
+
+By registering EDNS options we can tune unbound's behavior when encountering a
+query with a known EDNS option. The two available options are:
+
+- ``bypass_cache_stage``: If set to ``True`` unbound will not try to answer
+ from cache. Instead execution is passed to the modules
+- ``no_aggregation``: If set to ``True`` unbound will consider this query
+ unique and will not aggregate it with similar queries
+
+Both values default to ``False``.
+
+.. code-block:: python
+
+ if not register_edns_option(env, 65001, bypass_cache_stage=True,
+ no_aggregation=True):
+ log_info("python: Could not register EDNS option {}".format(65001))
+
+
+EDNS option lists
+-----------------
+
+EDNS option lists can be found in the :class:`module_qstate` class. There are
+four available lists in total:
+
+- :class:`module_qstate.edns_opts_front_in`: options that came from the client
+ side. **Should not** be changed
+- :class:`module_qstate.edns_opts_back_out`: options that will be sent to the
+ server side. Can be populated by edns literate modules
+- :class:`module_qstate.edns_opts_back_in`: options that came from the server
+ side. **Should not** be changed
+- :class:`module_qstate.edns_opts_front_out`: options that will be sent to the
+ client side. Can be populated by edns literate modules
+
+Each list element has the following members:
+
+- ``code``: the EDNS option code;
+- ``data``: the EDNS option data.
+
+
+Reading an EDNS option list
+...........................
+
+The lists' contents can be accessed in python by their ``_iter`` counterpart as
+an iterator:
+
+.. code-block:: python
+
+ if not edns_opt_list_is_empty(qstate.edns_opts_front_in):
+ for o in qstate.edns_opts_front_in_iter:
+ log_info("python: Code: {}, Data: '{}'".format(o.code,
+ "".join('{:02x}'.format(x) for x in o.data)))
+
+
+Writing to an EDNS option list
+..............................
+
+By appending to an EDNS option list we can add new EDNS options. The new
+element is going to be allocated in :class:`module_qstate.region`. The data
+**must** be represented with a python ``bytearray``:
+
+.. code-block:: python
+
+ b = bytearray.fromhex("deadbeef")
+ if not edns_opt_list_append(qstate.edns_opts_front_out,
+ o.code, b, qstate.region):
+ log_info("python: Could not append EDNS option {}".format(o.code))
+
+We can also remove an EDNS option code from an EDNS option list.
+
+.. code-block:: python
+
+ if not edns_opt_list_remove(edns_opt_list, code):
+ log_info("python: Option code {} was not found in the "
+ "list.".format(code))
+
+.. note:: All occurences of the EDNS option code will be removed from the list:
+
+
+Controlling other modules' cache behavior
+-----------------------------------------
+
+During the modules' operation, some modules may interact with the cache
+(e.g., iterator). This behavior can be controlled by using the following
+:class:`module_qstate` flags:
+
+- :class:`module_qstate.no_cache_lookup`: Modules *operating after* this module
+ will not lookup the cache for an answer
+- :class:`module_qstate.no_cache_store`: Modules *operating after* this module
+ will not store the response in the cache
+
+Both values default to ``0``.
+
+.. code-block:: python
+
+ def operate(id, event, qstate, qdata):
+ if (event == MODULE_EVENT_NEW) or (event == MODULE_EVENT_PASS):
+ # Detect if edns option code 56001 is present from the client side. If
+ # so turn on the flags for cache management.
+ if not edns_opt_list_is_empty(qstate.edns_opts_front_in):
+ log_info("python: searching for edns option code 65001 during NEW "
+ "or PASS event ")
+ for o in qstate.edns_opts_front_in_iter:
+ if o.code == 65001:
+ log_info("python: found edns option code 65001")
+ # Instruct other modules to not lookup for an
+ # answer in the cache.
+ qstate.no_cache_lookup = 1
+ log_info("python: enabled no_cache_lookup")
+
+ # Instruct other modules to not store the answer in
+ # the cache.
+ qstate.no_cache_store = 1
+ log_info("python: enabled no_cache_store")
+
+
+Testing
+~~~~~~~
+
+Run the Unbound server: ::
+
+ root@localhost$ unbound -dv -c ./test-edns.conf
+
+In case you use your own configuration file, don't forget to enable the Python
+module::
+
+ module-config: "validator python iterator"
+
+and use a valid script path::
+
+ python-script: "./examples/edns.py"
+
+Quering with EDNS option ``65001:0xc001``:
+
+::
+
+ root@localhost$ dig @localhost nlnetlabs.nl +ednsopt=65001:c001
+
+ ; <<>> DiG 9.10.3-P4-Ubuntu <<>> @localhost nlnetlabs.nl +ednsopt=65001:c001
+ ; (1 server found)
+ ;; global options: +cmd
+ ;; Got answer:
+ ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 33450
+ ;; flags: qr rd ra ad; QUERY: 1, ANSWER: 1, AUTHORITY: 4, ADDITIONAL: 3
+
+ ;; OPT PSEUDOSECTION:
+ ; EDNS: version: 0, flags:; udp: 4096
+ ; OPT=65001: de ad be ef ("....")
+ ;; QUESTION SECTION:
+ ;nlnetlabs.nl. IN A
+
+ ;; ANSWER SECTION:
+ nlnetlabs.nl. 10200 IN A 185.49.140.10
+
+ ;; AUTHORITY SECTION:
+ nlnetlabs.nl. 10200 IN NS anyns.pch.net.
+ nlnetlabs.nl. 10200 IN NS ns.nlnetlabs.nl.
+ nlnetlabs.nl. 10200 IN NS ns-ext1.sidn.nl.
+ nlnetlabs.nl. 10200 IN NS sec2.authdns.ripe.net.
+
+ ;; ADDITIONAL SECTION:
+ ns.nlnetlabs.nl. 10200 IN AAAA 2a04:b900::8:0:0:60
+ ns.nlnetlabs.nl. 10200 IN A 185.49.140.60
+
+ ;; Query time: 10 msec
+ ;; SERVER: 127.0.0.1#53(127.0.0.1)
+ ;; WHEN: Mon Dec 05 14:50:56 CET 2016
+ ;; MSG SIZE rcvd: 212
+
+
+Complete source code
+~~~~~~~~~~~~~~~~~~~~
+
+.. literalinclude:: ../../examples/edns.py
+ :language: python
diff --git a/external/unbound/pythonmod/doc/examples/example6.rst b/external/unbound/pythonmod/doc/examples/example6.rst
new file mode 100644
index 000000000..07117cd55
--- /dev/null
+++ b/external/unbound/pythonmod/doc/examples/example6.rst
@@ -0,0 +1,299 @@
+Inplace callbacks
+=================
+
+This example shows how to register and use inplace callback functions. These
+functions are going to be called just before unbound replies back to a client.
+They can perform certain actions without interrupting unbound's execution flow
+(e.g. add/remove EDNS options, manipulate the reply).
+
+Two different scenarios will be shown:
+
+- If answering from cache and the client used EDNS option code ``65002`` we
+ will answer with the same code but with data ``0xdeadbeef``;
+- When answering with a SERVFAIL we also add an empty EDNS option code
+ ``65003``.
+
+
+Key parts
+~~~~~~~~~
+
+This example relies on the following functionalities:
+
+
+Registering inplace callback functions
+--------------------------------------
+
+There are four types of inplace callback functions:
+
+- `inplace callback reply functions`_
+- `inplace callback reply_cache functions`_
+- `inplace callback reply_local functions`_
+- `inplace callback reply_servfail functions`_
+
+
+Inplace callback reply functions
+................................
+
+Called when answering with a *resolved* query.
+
+The callback function's prototype is the following:
+
+.. code-block:: python
+
+ def inplace_reply_callback(qinfo, qstate, rep, rcode, edns, opt_list_out, region):
+ """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;
+ :param rep: reply_info struct;
+ :param rcode: return code for the query;
+ :param edns: edns_data to be sent to the client side. It SHOULD NOT be
+ altered;
+ :param opt_list_out: the list with the EDNS options that will be sent as a
+ 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.
+ :return: True on success, False on failure.
+ """
+
+.. note:: The function's name is irrelevant.
+
+We can register such function as:
+
+.. code-block:: python
+
+ if not register_inplace_cb_reply(inplace_reply_callback, env, id):
+ log_info("python: Could not register inplace callback function.")
+
+
+Inplace callback reply_cache functions
+......................................
+
+Called when answering *from cache*.
+
+The callback function's prototype is the following:
+
+.. code-block:: python
+
+ def inplace_cache_callback(qinfo, qstate, rep, rcode, edns, opt_list_out, region):
+ """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;
+ :param rcode: return code for the query;
+ :param edns: edns_data sent from the client side. The list with the EDNS
+ options is accesible through edns.opt_list. It SHOULD NOT be
+ altered;
+ :param opt_list_out: the list with the EDNS options that will be sent as a
+ 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.
+ :return: True on success, False on failure.
+ """
+
+.. note:: The function's name is irrelevant.
+
+We can register such function as:
+
+.. code-block:: python
+
+ if not register_inplace_cb_reply_cache(inplace_cache_callback, env, id):
+ log_info("python: Could not register inplace callback function.")
+
+
+Inplace callback reply_local functions
+......................................
+
+Called when answering with *local data* or a *Chaos(CH) reply*.
+
+The callback function's prototype is the following:
+
+.. code-block:: python
+
+ def inplace_local_callback(qinfo, qstate, rep, rcode, edns, opt_list_out, region):
+ """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;
+ :param rcode: return code for the query;
+ :param edns: edns_data sent from the client side. The list with the
+ EDNS options is accesible through edns.opt_list. It
+ SHOULD NOT be altered;
+ :param opt_list_out: the list with the EDNS options that will be sent as a
+ 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.
+ :return: True on success, False on failure.
+ """
+
+.. note:: The function's name is irrelevant.
+
+We can register such function as:
+
+.. code-block:: python
+
+ if not register_inplace_cb_reply_local(inplace_local_callback, env, id):
+ log_info("python: Could not register inplace callback function.")
+
+
+Inplace callback reply_servfail functions
+.........................................
+
+Called when answering with *SERVFAIL*.
+
+The callback function's prototype is the following:
+
+.. code-block:: python
+
+ def inplace_servfail_callback(qinfo, qstate, rep, rcode, edns, opt_list_out, region):
+ """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;
+ :param rep: reply_info struct. None;
+ :param rcode: return code for the query. LDNS_RCODE_SERVFAIL;
+ :param edns: edns_data to be sent to the client side. If qstate is None
+ edns.opt_list contains the EDNS options sent from the client
+ side. It SHOULD NOT be altered;
+ :param opt_list_out: the list with the EDNS options that will be sent as a
+ 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.
+ :return: True on success, False on failure.
+ """
+
+.. note:: The function's name is irrelevant.
+
+We can register such function as:
+
+.. code-block:: python
+
+ if not register_inplace_cb_reply_servfail(inplace_servfail_callback, env, id):
+ log_info("python: Could not register inplace callback function.")
+
+
+Testing
+~~~~~~~
+
+Run the Unbound server: ::
+
+ root@localhost$ unbound -dv -c ./test-inplace_callbacks.conf
+
+In case you use your own configuration file, don't forget to enable the Python
+module::
+
+ module-config: "validator python iterator"
+
+and use a valid script path ::
+
+ python-script: "./examples/inplace_callbacks.py"
+
+On the first query for the nlnetlabs.nl A record we get no EDNS option back:
+
+::
+
+ root@localhost$ dig @localhost nlnetlabs.nl +ednsopt=65002
+
+ ; <<>> DiG 9.10.3-P4-Ubuntu <<>> @localhost nlnetlabs.nl +ednsopt=65002
+ ; (1 server found)
+ ;; global options: +cmd
+ ;; Got answer:
+ ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 48057
+ ;; flags: qr rd ra ad; QUERY: 1, ANSWER: 1, AUTHORITY: 4, ADDITIONAL: 3
+
+ ;; OPT PSEUDOSECTION:
+ ; EDNS: version: 0, flags:; udp: 4096
+ ;; QUESTION SECTION:
+ ;nlnetlabs.nl. IN A
+
+ ;; ANSWER SECTION:
+ nlnetlabs.nl. 10200 IN A 185.49.140.10
+
+ ;; AUTHORITY SECTION:
+ nlnetlabs.nl. 10200 IN NS ns.nlnetlabs.nl.
+ nlnetlabs.nl. 10200 IN NS sec2.authdns.ripe.net.
+ nlnetlabs.nl. 10200 IN NS anyns.pch.net.
+ nlnetlabs.nl. 10200 IN NS ns-ext1.sidn.nl.
+
+ ;; ADDITIONAL SECTION:
+ ns.nlnetlabs.nl. 10200 IN A 185.49.140.60
+ ns.nlnetlabs.nl. 10200 IN AAAA 2a04:b900::8:0:0:60
+
+ ;; Query time: 813 msec
+ ;; SERVER: 127.0.0.1#53(127.0.0.1)
+ ;; WHEN: Mon Dec 05 16:15:32 CET 2016
+ ;; MSG SIZE rcvd: 204
+
+When we issue the same query again we get a cached response and the expected
+``65002: 0xdeadbeef`` EDNS option:
+
+::
+
+ root@localhost$ dig @localhost nlnetlabs.nl +ednsopt=65002
+
+ ; <<>> DiG 9.10.3-P4-Ubuntu <<>> @localhost nlnetlabs.nl +ednsopt=65002
+ ; (1 server found)
+ ;; global options: +cmd
+ ;; Got answer:
+ ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 26489
+ ;; flags: qr rd ra ad; QUERY: 1, ANSWER: 1, AUTHORITY: 4, ADDITIONAL: 3
+
+ ;; OPT PSEUDOSECTION:
+ ; EDNS: version: 0, flags:; udp: 4096
+ ; OPT=65002: de ad be ef ("....")
+ ;; QUESTION SECTION:
+ ;nlnetlabs.nl. IN A
+
+ ;; ANSWER SECTION:
+ nlnetlabs.nl. 10197 IN A 185.49.140.10
+
+ ;; AUTHORITY SECTION:
+ nlnetlabs.nl. 10197 IN NS ns.nlnetlabs.nl.
+ nlnetlabs.nl. 10197 IN NS sec2.authdns.ripe.net.
+ nlnetlabs.nl. 10197 IN NS anyns.pch.net.
+ nlnetlabs.nl. 10197 IN NS ns-ext1.sidn.nl.
+
+ ;; ADDITIONAL SECTION:
+ ns.nlnetlabs.nl. 10197 IN AAAA 2a04:b900::8:0:0:60
+ ns.nlnetlabs.nl. 10197 IN A 185.49.140.60
+
+ ;; Query time: 0 msec
+ ;; SERVER: 127.0.0.1#53(127.0.0.1)
+ ;; WHEN: Mon Dec 05 16:50:04 CET 2016
+ ;; MSG SIZE rcvd: 212
+
+By issuing a query for a bogus domain unbound replies with SERVFAIL and an
+empty EDNS option code ``65003``. *For this example to work unbound needs to be
+validating*:
+
+::
+
+ root@localhost$ dig @localhost bogus.nlnetlabs.nl txt
+
+ ; <<>> DiG 9.10.3-P4-Ubuntu <<>> @localhost bogus.nlnetlabs.nl txt
+ ; (1 server found)
+ ;; global options: +cmd
+ ;; Got answer:
+ ;; ->>HEADER<<- opcode: QUERY, status: SERVFAIL, id: 19865
+ ;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1
+
+ ;; OPT PSEUDOSECTION:
+ ; EDNS: version: 0, flags:; udp: 4096
+ ; OPT=65003
+ ;; QUESTION SECTION:
+ ;bogus.nlnetlabs.nl. IN TXT
+
+ ;; Query time: 11 msec
+ ;; SERVER: 127.0.0.1#53(127.0.0.1)
+ ;; WHEN: Mon Dec 05 17:06:01 CET 2016
+ ;; MSG SIZE rcvd: 51
+
+
+Complete source code
+~~~~~~~~~~~~~~~~~~~~
+.. literalinclude:: ../../examples/inplace_callbacks.py
+ :language: python
diff --git a/external/unbound/pythonmod/doc/examples/index.rst b/external/unbound/pythonmod/doc/examples/index.rst
index 6c5022581..93d9b8e1e 100644
--- a/external/unbound/pythonmod/doc/examples/index.rst
+++ b/external/unbound/pythonmod/doc/examples/index.rst
@@ -1,15 +1,16 @@
.. _Tutorials:
-==============================
-Tutorials
-==============================
+Examples
+========
-Here you can find several tutorials which clarify the usage and capabilities of Unbound scriptable interface.
+Here you can find several tutorials which clarify the usage and capabilities of
+the Unbound scriptable interface.
-`Tutorials`
+Tutorials
+---------
.. toctree::
- :maxdepth: 2
- :glob:
+ :maxdepth: 2
+ :glob:
- example*
+ example*