aboutsummaryrefslogtreecommitdiff
path: root/external/unbound/pythonmod/doc/examples
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--external/unbound/pythonmod/doc/examples/example0-1.py34
-rw-r--r--external/unbound/pythonmod/doc/examples/example0.rst129
-rw-r--r--external/unbound/pythonmod/doc/examples/example1.rst42
-rw-r--r--external/unbound/pythonmod/doc/examples/example2.rst46
-rw-r--r--external/unbound/pythonmod/doc/examples/example3.rst63
-rw-r--r--external/unbound/pythonmod/doc/examples/example4.rst164
-rw-r--r--external/unbound/pythonmod/doc/examples/index.rst15
7 files changed, 493 insertions, 0 deletions
diff --git a/external/unbound/pythonmod/doc/examples/example0-1.py b/external/unbound/pythonmod/doc/examples/example0-1.py
new file mode 100644
index 000000000..3b234f1e0
--- /dev/null
+++ b/external/unbound/pythonmod/doc/examples/example0-1.py
@@ -0,0 +1,34 @@
+
+def init(id, cfg):
+ 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):
+ return True
+
+def operate(id, event, qstate, qdata):
+ log_info("pythonmod: operate called, id: %d, event:%s" % (id, strmodulevent(event)))
+
+ if event == MODULE_EVENT_NEW:
+ qstate.ext_state[id] = MODULE_WAIT_MODULE
+ 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
+
+ if event == MODULE_EVENT_PASS:
+ log_info("pythonmod: event_pass")
+ qstate.ext_state[id] = MODULE_ERROR
+ return True
+
+ log_err("pythonmod: BAD event")
+ qstate.ext_state[id] = MODULE_ERROR
+ return True
+
+log_info("pythonmod: script loaded.")
diff --git a/external/unbound/pythonmod/doc/examples/example0.rst b/external/unbound/pythonmod/doc/examples/example0.rst
new file mode 100644
index 000000000..80eca5ea6
--- /dev/null
+++ b/external/unbound/pythonmod/doc/examples/example0.rst
@@ -0,0 +1,129 @@
+.. _example_handler:
+
+Fundamentals
+================
+
+This basic example shows how to create simple python module which will pass on the requests to the iterator.
+
+How to enable python module
+----------------------------
+If you look into unbound configuration file, you can find the option `module-config` which specifies the names and the order of modules to be used.
+Example configuration::
+
+ module-config: "validator python iterator"
+
+As soon as the DNS query arrives, Unbound calls modules starting from leftmost - the validator *(it is the first module on the list)*.
+The validator does not know the answer *(it can only validate)*, thus it will pass on the event to the next module.
+Next module is python which can
+
+ a) generate answer *(response)*
+ When python module generates the response unbound calls validator. Validator grabs the answer and determines the security flag.
+
+ b) pass on the event to the iterator.
+ When iterator resolves the query, Unbound informs python module (event :data:`module_event_moddone`). In the end, when the python module is done, validator is called.
+
+Note that the python module is called with :data:`module_event_pass` event, because new DNS event was already handled by validator.
+
+Another situation occurs when we use the following configuration::
+
+ module-config: "python validator iterator"
+
+Python module is the first module here, so it's invoked with :data:`module_event_new` event *(new query)*.
+
+On Python module initialization, module loads script from `python-script` option::
+
+ python-script: "/unbound/test/ubmodule.py"
+
+Simple python module step by step
+---------------------------------
+
+Script file must contain four compulsory functions:
+
+.. function:: init(id, cfg)
+
+ Initialize module internals, like database etc.
+ Called just once on module load.
+
+ :param id: module identifier (integer)
+ :param cfg: :class:`config_file` configuration structure
+
+::
+
+ def init(id, cfg):
+ log_info("pythonmod: init called, module id is %d port: %d script: %s" % (id, cfg.port, cfg.python_script))
+ return True
+
+
+.. function:: deinit(id)
+
+ Deinitialize module internals.
+ Called just once on module unload.
+
+ :param id: module identifier (integer)
+
+::
+
+ def deinit(id):
+ log_info("pythonmod: deinit called, module id is %d" % id)
+ return True
+
+
+.. function:: inform_super(id, qstate, superqstate, qdata)
+
+ Inform super querystate about the results from this subquerystate.
+ Is called when the querystate is finished.
+
+ :param id: module identifier (integer)
+ :param qstate: :class:`module_qstate` Query state
+ :param superqstate: :class:`pythonmod_qstate` Mesh state
+ :param qdata: :class:`query_info` Query data
+
+::
+
+ def inform_super(id, qstate, superqstate, qdata):
+ return True
+
+
+
+.. function:: operate(id, event, qstate, qdata)
+
+ Perform action on pending query. Accepts a new query, or work on pending query.
+
+ You have to set qstate.ext_state on exit.
+ The state informs unbound about result and controls the following states.
+
+ :param id: module identifier (integer)
+ :param qstate: :class:`module_qstate` query state structure
+ :param qdata: :class:`query_info` per query data, here you can store your own data
+
+::
+
+ def operate(id, event, qstate, qdata):
+ log_info("pythonmod: operate called, id: %d, event:%s" % (id, strmodulevent(event)))
+ if event == MODULE_EVENT_NEW:
+ qstate.ext_state[id] = MODULE_WAIT_MODULE
+ return True
+
+ if event == MODULE_EVENT_MODDONE:
+ qstate.ext_state[id] = MODULE_FINISHED
+ return True
+
+ if event == MODULE_EVENT_PASS:
+ qstate.ext_state[id] = MODULE_ERROR
+ return True
+
+ log_err("pythonmod: BAD event")
+ qstate.ext_state[id] = MODULE_ERROR
+ return True
+
+
+Complete source code
+--------------------
+
+.. literalinclude:: example0-1.py
+ :language: python
+
+As you can see, the source code is much more flexible in contrast to C modules.
+Moreover, compulsory functions called on appropriate module events allows to handle almost
+anything from web control to query analysis.
+
diff --git a/external/unbound/pythonmod/doc/examples/example1.rst b/external/unbound/pythonmod/doc/examples/example1.rst
new file mode 100644
index 000000000..b49e64409
--- /dev/null
+++ b/external/unbound/pythonmod/doc/examples/example1.rst
@@ -0,0 +1,42 @@
+.. _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``.
+This packet will be send to a client that asked for it.
+
+Complete source code
+--------------------
+
+.. literalinclude:: ../../examples/log.py
+ :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"``.
+
+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
+ [1231790168] unbound[7941:0] info: query response was ANSWER
+ [1231790168] unbound[7941:0] info: pythonmod: operate called, id: 1, event:module_event_moddone
+ ----------------------------------------------------------------------------------------------------
+ Query: f.gtld-servers.NET., type: AAAA (28), class: IN (1)
+ ----------------------------------------------------------------------------------------------------
+ Return reply :: flags: 8080, QDcount: 1, Security:0, TTL=86400
+ qinfo :: qname: ['f', 'gtld-servers', 'NET', ''] f.gtld-servers.NET., qtype: AAAA, qclass: IN
+ Reply:
+ 0 : ['gtld-servers', 'NET', ''] gtld-servers.NET. flags: 0000 type: SOA (6) class: IN (1)
+ 0 : TTL= 86400
+ 0x00 | 00 3A 02 41 32 05 4E 53 54 4C 44 03 43 4F 4D 00 05 | . : . A 2 . N S T L D . C O M . .
+ 0x10 | 05 6E 73 74 6C 64 0C 76 65 72 69 73 69 67 6E 2D 67 | . n s t l d . v e r i s i g n - g
+ 0x20 | 67 72 73 03 43 4F 4D 00 77 74 2D 64 00 00 0E 10 00 | g r s . C O M . w t - d . . . . .
+ 0x30 | 00 00 03 84 00 12 75 00 00 01 51 80 | . . . . . . u . . . Q .
+
diff --git a/external/unbound/pythonmod/doc/examples/example2.rst b/external/unbound/pythonmod/doc/examples/example2.rst
new file mode 100644
index 000000000..f00fcc239
--- /dev/null
+++ b/external/unbound/pythonmod/doc/examples/example2.rst
@@ -0,0 +1,46 @@
+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.
+
+Complete source code
+--------------------
+
+.. literalinclude:: ../../examples/resgen.py
+ :language: python
+
+Testing
+-------
+
+Run the unbound server:
+
+``root@localhost>unbound -dv -c ./test-resgen.conf``
+
+Query for a A record ending with .localdomain
+
+``dig A test.xxx.localdomain @127.0.0.1``
+
+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.
diff --git a/external/unbound/pythonmod/doc/examples/example3.rst b/external/unbound/pythonmod/doc/examples/example3.rst
new file mode 100644
index 000000000..6213dc188
--- /dev/null
+++ b/external/unbound/pythonmod/doc/examples/example3.rst
@@ -0,0 +1,63 @@
+Response modification
+=====================
+
+This example shows how to modify the response produced by the ``iterator`` module.
+
+As soon as the iterator module returns the response, we :
+
+1. invalidate the data in cache
+2. modify the response *TTL*
+3. rewrite the data in cache
+4. return modified packet
+
+Note that the steps 1 and 3 are neccessary only in case, the python module is the first module in the processing chain.
+In other cases, the validator module guarantees updating data which are produced by iterator module.
+
+Complete source code
+--------------------
+
+.. literalinclude:: ../../examples/resmod.py
+ :language: python
+
+Testing
+-------
+
+Run Unbound server:
+
+``root@localhost>unbound -dv -c ./test-resmod.conf``
+
+Issue a query for name ending with "nic.cz."
+
+``>>>dig A @127.0.0.1 www.nic.cz``
+
+::
+
+ ;; global options: printcmd
+ ;; Got answer:
+ ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 48831
+ ;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 3, ADDITIONAL: 5
+
+ ;; QUESTION SECTION:
+ ;www.nic.cz. IN A
+
+ ;; ANSWER SECTION:
+ www.nic.cz. 10 IN A 217.31.205.50
+
+ ;; AUTHORITY SECTION:
+ nic.cz. 10 IN NS e.ns.nic.cz.
+ nic.cz. 10 IN NS a.ns.nic.cz.
+ nic.cz. 10 IN NS c.ns.nic.cz.
+
+ ;; ADDITIONAL SECTION:
+ a.ns.nic.cz. 10 IN A 217.31.205.180
+ a.ns.nic.cz. 10 IN AAAA 2001:1488:dada:176::180
+ c.ns.nic.cz. 10 IN A 195.66.241.202
+ c.ns.nic.cz. 10 IN AAAA 2a01:40:1000::2
+ e.ns.nic.cz. 10 IN A 194.146.105.38
+
+ ;; Query time: 166 msec
+ ;; SERVER: 127.0.0.1#53(127.0.0.1)
+ ;; WHEN: Mon Jan 02 13:39:43 2009
+ ;; MSG SIZE rcvd: 199
+
+As you can see, TTL of all the records is set to 10.
diff --git a/external/unbound/pythonmod/doc/examples/example4.rst b/external/unbound/pythonmod/doc/examples/example4.rst
new file mode 100644
index 000000000..6cc484797
--- /dev/null
+++ b/external/unbound/pythonmod/doc/examples/example4.rst
@@ -0,0 +1,164 @@
+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.
+
+Key parts
+-----------
+
+Initialization
+~~~~~~~~~~~~~~~~~~~~~~~
+On **init()** module loads dictionary from a text file containing records in ``word [tab] translation`` format.
+::
+
+ def init(id, cfg):
+ log_info("pythonmod: dict init")
+ f = open("examples/dict_data.txt", "r")
+ ...
+
+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.]``.
+Word lookup is done by simple ``dict`` lookup from broken DNS request.
+Query name is divided into a list of labels. This list is accesible as qname_list attribute.
+::
+
+ aword = ' '.join(qstate.qinfo.qname_list[0:-4]) #skip last four labels
+ adict = qstate.qinfo.qname_list[-4] #get 4th label from the end
+
+ words = [] #list of words
+ if (adict == "en") and (aword in en_dict):
+ words = en_dict[aword]
+
+ 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.
+
+
+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)
+
+ 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
+
+ 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)*.
+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)*.
+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`.
+
+**Steps:**
+
+1. create :class:`DNSMessage` instance
+2. append TXT records containing the translation
+3. set response to ``qstate.return_msg``
+
+Testing
+-------
+
+Run the Unbound server:
+
+``root@localhost>unbound -dv -c ./test-dict.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/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
+
+``>>>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 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:
+ ...
+
+Complete source code
+--------------------
+
+.. literalinclude:: ../../examples/dict.py
+ :language: python
diff --git a/external/unbound/pythonmod/doc/examples/index.rst b/external/unbound/pythonmod/doc/examples/index.rst
new file mode 100644
index 000000000..6c5022581
--- /dev/null
+++ b/external/unbound/pythonmod/doc/examples/index.rst
@@ -0,0 +1,15 @@
+.. _Tutorials:
+
+==============================
+Tutorials
+==============================
+
+Here you can find several tutorials which clarify the usage and capabilities of Unbound scriptable interface.
+
+`Tutorials`
+
+.. toctree::
+ :maxdepth: 2
+ :glob:
+
+ example*