diff options
Diffstat (limited to 'pythonmod/doc')
| -rw-r--r-- | pythonmod/doc/conf.py | 5 | ||||
| -rw-r--r-- | pythonmod/doc/examples/example1.rst | 14 | ||||
| -rw-r--r-- | pythonmod/doc/examples/example2.rst | 45 | ||||
| -rw-r--r-- | pythonmod/doc/examples/example4.rst | 180 | ||||
| -rw-r--r-- | pythonmod/doc/examples/example5.rst | 191 | ||||
| -rw-r--r-- | pythonmod/doc/examples/example6.rst | 299 | ||||
| -rw-r--r-- | pythonmod/doc/examples/index.rst | 17 | ||||
| -rw-r--r-- | pythonmod/doc/install.rst | 44 | ||||
| -rw-r--r-- | pythonmod/doc/modules/functions.rst | 139 | ||||
| -rw-r--r-- | pythonmod/doc/modules/struct.rst | 187 | 
10 files changed, 919 insertions, 202 deletions
| diff --git a/pythonmod/doc/conf.py b/pythonmod/doc/conf.py index bc7a5aba68d5..7fcfe2d0508c 100644 --- a/pythonmod/doc/conf.py +++ b/pythonmod/doc/conf.py @@ -80,10 +80,13 @@ pygments_style = 'sphinx'  # Options for HTML output  # ----------------------- +# The theme that the html output should use. +html_theme = "classic" +  # The style sheet to use for HTML and HTML Help pages. A file of that name  # must exist either in Sphinx' static/ path, or in one of the custom paths  # given in html_static_path. -html_style = 'default.css' +#html_style = 'default.css'  # The name for this set of Sphinx documents.  If None, it defaults to  # "<project> v<release> documentation". diff --git a/pythonmod/doc/examples/example1.rst b/pythonmod/doc/examples/example1.rst index b49e64409255..ccd76da5a77e 100644 --- a/pythonmod/doc/examples/example1.rst +++ b/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/pythonmod/doc/examples/example2.rst b/pythonmod/doc/examples/example2.rst index f00fcc239609..4ba9239a003f 100644 --- a/pythonmod/doc/examples/example2.rst +++ b/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/pythonmod/doc/examples/example4.rst b/pythonmod/doc/examples/example4.rst index b665351e84ec..3382109903aa 100644 --- a/pythonmod/doc/examples/example4.rst +++ b/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/pythonmod/doc/examples/example5.rst b/pythonmod/doc/examples/example5.rst new file mode 100644 index 000000000000..058fc331e4ba --- /dev/null +++ b/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/pythonmod/doc/examples/example6.rst b/pythonmod/doc/examples/example6.rst new file mode 100644 index 000000000000..ce89aab99f40 --- /dev/null +++ b/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): +        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): +        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): +        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): +        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/pythonmod/doc/examples/index.rst b/pythonmod/doc/examples/index.rst index 6c50225810ef..93d9b8e1e133 100644 --- a/pythonmod/doc/examples/index.rst +++ b/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* diff --git a/pythonmod/doc/install.rst b/pythonmod/doc/install.rst index 991e2b4becf9..b8d0b9fa60d1 100644 --- a/pythonmod/doc/install.rst +++ b/pythonmod/doc/install.rst @@ -1,39 +1,44 @@  Installation -=================================== +============ -**Prerequisites** +Prerequisites +-------------  Python 2.4 or higher, SWIG 1.3 or higher, GNU make -**Download** +Download +--------  You can download the source codes `here`_.  The latest release is 1.1.1, Jan 15, 2009.  .. _here: unbound-1.1.1-py.tar.gz -**Compiling** +Compiling +---------  After downloading, you can compile the Unbound library by doing:: -	> tar -xzf unbound-1.1.1-py.tar.gz -	> cd unbound-1.1.1 -	> ./configure --with-pythonmodule -	> make +    > tar -xzf unbound-1.1.1-py.tar.gz +    > cd unbound-1.1.1 +    > ./configure --with-pythonmodule +    > make  You need GNU make to compile sources.  SWIG and Python devel libraries to compile extension module.  -**Testing** +Testing +-------  If the compilation is successful, you can test the extension module by:: -	> cd pythonmod -	> make sudo # or "make test" or "make suexec" +    > cd pythonmod +    > make sudo # or "make test" or "make suexec" -This will start unbound server with language dictionary service (see :ref:`Tutorials`). +This will start unbound server with language dictionary service +(see :ref:`Tutorials`).  In order to test this service, type:: -   +     > dig TXT @127.0.0.1 aught.en._dict_.cz  Dig should print this message (czech equivalent of aught):: @@ -44,16 +49,17 @@ Dig should print this message (czech equivalent of aught)::     ;; Got answer:     ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 30085     ;; flags: aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0 -    +     ;; QUESTION SECTION: -   ;aught.en._dict_.cz.		IN	TXT -    +   ;aught.en._dict_.cz.     IN  TXT +     ;; ANSWER SECTION: -   aught.en._dict_.cz.	300	IN	TXT	"nic" -    +   aught.en._dict_.cz.  300 IN  TXT "nic" +     ;; Query time: 11 msec     ;; SERVER: 127.0.0.1#53(127.0.0.1)     ;; WHEN: Thu Jan 10 16:45:58 2009     ;; MSG SIZE  rcvd: 52 -The ``pythonmod/examples`` directory contains simple applications written in Python. +The ``pythonmod/examples`` directory contains simple applications written in +Python. diff --git a/pythonmod/doc/modules/functions.rst b/pythonmod/doc/modules/functions.rst index 45a469fec04e..627d44922477 100644 --- a/pythonmod/doc/modules/functions.rst +++ b/pythonmod/doc/modules/functions.rst @@ -7,25 +7,26 @@ Network  .. function:: ntohs(netshort)     This subroutine converts values between the host and network byte order.  -   Specifically, **ntohs()** converts 16-bit quantities from network byte order to host byte order. -    +   Specifically, **ntohs()** converts 16-bit quantities from network byte order +   to host byte order. +     :param netshort: 16-bit short addr     :rtype: converted addr -    -    + +  Cache  -----  .. function:: storeQueryInCache(qstate, qinfo, msgrep, is_referral)     Store pending query in local cache. -    +     :param qstate: :class:`module_qstate`     :param qinfo: :class:`query_info`     :param msgrep: :class:`reply_info`     :param is_referal: integer     :rtype: boolean -    +  .. function:: invalidateQueryInCache(qstate, qinfo)     Invalidate record in local cache. @@ -34,6 +35,111 @@ Cache     :param qinfo: :class:`query_info` +EDNS options +------------ + +.. function:: register_edns_option(env, code, bypass_cache_stage=False, no_aggregation=False) + +    Register EDNS option code. + +    :param env: :class:`module_env` +    :param code: option code(integer) +    :param bypass_cache_stage: whether to bypass the cache response stage +    :param no_aggregation: whether this query should be unique +    :return: ``1`` if successful, ``0`` otherwise +    :rtype: integer + +.. function:: edns_opt_list_find(list, code) + +    Find the EDNS option code in the EDNS option list. + +    :param list: linked list of :class:`edns_option` +    :param code: option code (integer) +    :return: the edns option if found or None +    :rtype: :class:`edns_option` or None + +.. function:: edns_opt_list_remove(list, code); + +    Remove an ENDS option code from the list. +    .. note:: All :class:`edns_option` with the code will be removed + +    :param list: linked list of :class:`edns_option` +    :param code: option code (integer) +    :return: ``1`` if at least one :class:`edns_option` was removed, ``0`` otherwise +    :rtype: integer + +.. function:: edns_opt_list_append(list, code, data, region) + +    Append given EDNS option code with data to the list. + +    :param list: linked list of :class:`edns_option` +    :param code: option code (integer) +    :param data: EDNS data. **Must** be a :class:`bytearray` +    :param region: :class:`regional` + +.. function:: edns_opt_list_is_empty(list) + +    Check if an EDNS option list is empty. + +    :param list: linked list of :class:`edns_option` +    :return: ``1`` if list is empty, ``0`` otherwise +    :rtype: integer + + +Inplace callbacks +----------------- + +.. function:: inplace_cb_reply(qinfo, qstate, rep, rcode, edns, opt_list_out, region) + +    Function prototype for callback functions used in +    `register_inplace_cb_reply`_, `register_inplace_cb_reply_cache`_, +    `register_inplace_cb_reply_local` and `register_inplace_cb_reply_servfail`. + +    :param qinfo: :class:`query_info` +    :param qstate: :class:`module_qstate` +    :param rep: :class:`reply_info` +    :param rcode: return code (integer), check ``RCODE_`` constants. +    :param edns: :class:`edns_data` +    :param opt_list_out: :class:`edns_option`. EDNS option list to append options to. +    :param region: :class:`regional` + +.. function:: register_inplace_cb_reply(py_cb, env) + +    Register py_cb as an inplace reply callback function. + +    :param py_cb: Python function that follows `inplace_cb_reply`_'s prototype. **Must** be callable. +    :param env: :class:`module_env` +    :return: True on success, False otherwise +    :rtype: boolean + +.. function:: register_inplace_cb_reply_cache(py_cb, env) + +    Register py_cb as an inplace reply_cache callback function. + +    :param py_cb: Python function that follows `inplace_cb_reply`_'s prototype. **Must** be callable. +    :param env: :class:`module_env` +    :return: True on success, False otherwise +    :rtype: boolean + +.. function:: register_inplace_cb_reply_local(py_cb, env) + +    Register py_cb as an inplace reply_local callback function. + +    :param py_cb: Python function that follows `inplace_cb_reply`_'s prototype. **Must** be callable. +    :param env: :class:`module_env` +    :return: True on success, False otherwise +    :rtype: boolean + +.. function:: register_inplace_cb_reply_servfail(py_cb, env) + +    Register py_cb as an inplace reply_servfail callback function. + +    :param py_cb: Python function that follows `inplace_cb_reply`_'s prototype. **Must** be callable. +    :param env: :class:`module_env` +    :return: True on success, False otherwise +    :rtype: boolean + +  Logging  ------- @@ -71,50 +177,51 @@ Logging     :param msg: string desc to accompany the hexdump.     :param data: data to dump in hex format.     :param length: length of data. -    +  .. function:: log_dns_msg(str, qinfo, reply)     Log DNS message. -    +     :param str: string message     :param qinfo: :class:`query_info`     :param reply: :class:`reply_info` -    +  .. function:: log_query_info(verbosity_value, str, qinf)     Log query information. -    +     :param verbosity_value: see constants     :param str: string message     :param qinf: :class:`query_info` -    +  .. function:: regional_log_stats(r)     Log regional statistics. -    +     :param r: :class:`regional` +  Debugging  ---------  .. function:: strextstate(module_ext_state)     Debug utility, module external qstate to string. -    +     :param module_ext_state: the state value.     :rtype: descriptive string.  .. function:: strmodulevent(module_event)     Debug utility, module event to string. -    +     :param module_event: the module event value.     :rtype: descriptive string. -    +  .. function:: ldns_rr_type2str(atype)     Convert RR type to string. -    +  .. function:: ldns_rr_class2str(aclass)     Convert RR class to string. diff --git a/pythonmod/doc/modules/struct.rst b/pythonmod/doc/modules/struct.rst index 669f36d91ea2..3af5d8a48c01 100644 --- a/pythonmod/doc/modules/struct.rst +++ b/pythonmod/doc/modules/struct.rst @@ -6,55 +6,94 @@ module_qstate  .. class:: module_qstate -   Module state, per query. -    -   This class provides these data attributes: -    -   .. attribute:: qinfo -    -      (:class:`query_info`) Informations about query being answered. Name, RR type, RR class. -    -   .. attribute:: query_flags -    -      (uint16) Flags for query. See QF_BIT\_ predefined constants. -       -   .. attribute:: is_priming -    -      If this is a (stub or root) priming query (with hints). -    -   .. attribute:: reply -    -      comm_reply contains server replies. -       -   .. attribute:: return_msg -    -      (:class:`dns_msg`) The reply message, with message for client and calling module (read-only attribute). -		Note that if you want to create of modify return_msg you should use :class:`DNSMessage`. -       -   .. attribute:: return_rcode -    -      The rcode, in case of error, instead of a reply message. Determines whether the return_msg contains reply. -    -   .. attribute:: region -    -      Region for this query. Cleared when query process finishes. -    -   .. attribute:: curmod -    -      Which module is executing. -       -   .. attribute:: ext_state[] -    -      Module states. -       -   .. attribute:: env -    -      Environment for this query. -       -   .. attribute:: mesh_info -    -      Mesh related information for this query. +    Module state, per query. + +    This class provides these data attributes: + +    .. attribute:: qinfo + +        (:class:`query_info`) Informations about query being answered. Name, RR type, RR class. + +    .. attribute:: query_flags + +        (uint16) Flags for query. See QF_BIT\_ predefined constants. + +    .. attribute:: is_priming + +        If this is a (stub or root) priming query (with hints). + +    .. attribute:: reply + +        comm_reply contains server replies. + +    .. attribute:: return_msg + +        (:class:`dns_msg`) The reply message, with message for client and calling module (read-only attribute). +        Note that if you want to create of modify return_msg you should use :class:`DNSMessage`. + +    .. attribute:: return_rcode + +        The rcode, in case of error, instead of a reply message. Determines whether the return_msg contains reply. + +    .. attribute:: region + +        Region for this query. Cleared when query process finishes. + +    .. attribute:: curmod + +        Which module is executing. + +    .. attribute:: ext_state[] + +        Module states. + +    .. attribute:: env + +        Environment for this query. +    .. attribute:: mesh_info + +        Mesh related information for this query. + +    .. attribute:: edns_opts_front_in + +        Incoming EDNS options from the front end. + +    .. attribute:: edns_opts_front_in_iter + +        Iterator for `edns_opts_front_in`. + +    .. attribute:: edns_opts_back_out + +        Outgoing EDNS options to the back end. + +    .. attribute:: edns_opts_back_out_iter + +        Iterator for `edns_opts_back_out`. + +    .. attribute:: edns_opts_back_in + +        Incoming EDNS options from the back end. + +    .. attribute:: edns_opts_back_in_iter + +        Iterator for `ends_opts_back_in`. + +    .. attribute:: edns_opts_front_out + +        Outgoing EDNS options to the front end. + +    .. attribute:: edns_opts_front_out_iter + +        Iterator for `edns_opts_front_out`. + +    .. attribute:: no_cache_lookup + +        Flag to indicate whether modules should answer from the cache. + +    .. attribute:: no_cache_store + +        Flag to indicate whether modules should store answer in the cache.  query_info  ---------------- @@ -94,7 +133,57 @@ query_info     .. attribute:: qclass_str        The ``qclass`` in display presentation format (string). -    + +edns_data +--------- + +.. class:: edns_data + +    This class represents the EDNS information parsed/encoded from/to a packet. It provides these data attributes: + +    .. attribute:: edns_present + +        If EDNS OPT record is present. + +    .. attribute:: ext_rcode + +        Extended RCODE. + +    .. attribute:: edns_version + +        The EDNS version number. + +    .. attribute:: bits + +        The EDNS bits field from ttl (host order): Z. + +    .. attribute:: udp_size + +        UDP reassembly size. + +    .. attribute:: opt_list + +        The EDNS option list. + +    .. attribute:: opt_list_iter + +        Iterator for `opt_list`. + +edns_option +----------- + +.. class:: edns_option + +    This class represents an EDNS option (code, data) found in EDNS option lists. It provides these data attributes: + +    .. attribute:: code + +    The EDNS option code. + +    .. attribute:: data + +    The EDNS option data. +  reply_info  -------------------- | 
