unbound/pythonmod/doc/examples/example4.rst
george 4812f02dd0 - Added generic EDNS code for registering known EDNS option codes,
bypassing the cache response stage and uniquifying mesh states. Four EDNS
  option lists were added to module_qstate (module_qstate.edns_opts_*) to
  store EDNS options from/to front/back side.
- Added two flags to module_qstate (no_cache_lookup, no_cache_store) that
  control the modules' cache interactions.
- Added code for registering inplace callback functions. The registered
  functions can be called just before replying with local data or Chaos,
  replying from cache, replying with SERVFAIL, replying with a resolved
  query, sending a query to a nameserver. The functions can inspect the
  available data and maybe change response/query related data (i.e. append
  EDNS options).
- Updated Python module for the above.
- Updated Python documentation.



git-svn-id: https://unbound.nlnetlabs.nl/svn/trunk@3947 be551aaa-1e26-0410-a405-d3ace91eadb9
2016-12-06 13:42:51 +00:00

179 lines
4.8 KiB
ReStructuredText

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 accessible 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