1DNS-based language dictionary
2=============================
3
4This example shows how to create a simple language dictionary based on **DNS**
5service within 15 minutes. The translation will be performed using TXT resource
6records.
7
8Key parts
9---------
10
11Initialization
12~~~~~~~~~~~~~~
13
14On **init()** module loads dictionary from a text file containing records in
15``word [tab] translation`` format.
16
17::
18
19   def init(id, cfg):
20      log_info("pythonmod: dict init")
21      f = open("examples/dict_data.txt", "r")
22      ...
23
24The suitable file can be found at http://slovnik.zcu.cz
25
26DNS query and word lookup
27~~~~~~~~~~~~~~~~~~~~~~~~~
28
29Let's define the following format od DNS queries:
30``word1[.]word2[.] ... wordN[.]{en,cs}[._dict_.cz.]``.
31Word lookup is done by simple ``dict`` lookup from broken DNS request.
32Query name is divided into a list of labels. This list is accessible as
33``qname_list`` attribute.
34
35::
36
37   aword = ' '.join(qstate.qinfo.qname_list[0:-4]) #skip last four labels
38   adict = qstate.qinfo.qname_list[-4] #get 4th label from the end
39
40   words = [] #list of words
41   if (adict == "en") and (aword in en_dict):
42      words = en_dict[aword] 
43
44   if (adict == "cs") and (aword in cz_dict):
45      words = cz_dict[aword] # CS -> EN
46
47In the first step, we get a string in the form:
48``word1[space]word2[space]...word[space]``.
49In the second assignment, fourth label from the end is obtained. This label
50should contains *"cs"* or *"en"*. This label determines the direction of
51translation.
52
53Forming of a DNS reply
54~~~~~~~~~~~~~~~~~~~~~~
55
56DNS reply is formed only on valid match and added as TXT answer.
57
58::
59
60    msg = DNSMessage(qstate.qinfo.qname_str, RR_TYPE_TXT, RR_CLASS_IN, PKT_AA)
61
62    for w in words:
63        msg.answer.append("%s 300 IN TXT \"%s\"" % (qstate.qinfo.qname_str, w.replace("\"", "\\\"")))
64
65    if not msg.set_return_msg(qstate):
66        qstate.ext_state[id] = MODULE_ERROR 
67        return True
68
69    qstate.return_rcode = RCODE_NOERROR
70    qstate.ext_state[id] = MODULE_FINISHED 
71    return True
72
73In the first step, a :class:`DNSMessage` instance is created for a given query
74*(type TXT)*.
75The fourth argument specifies the flags *(authoritative answer)*.
76In the second step, we append TXT records containing the translation *(on the
77right side of RR)*.
78Then, the response is finished and ``qstate.return_msg`` contains new response.
79If no error, the module sets :attr:`module_qstate.return_rcode` and
80:attr:`module_qstate.ext_state`.
81
82**Steps:**
83
841. create :class:`DNSMessage` instance
852. append TXT records containing the translation
863. set response to ``qstate.return_msg``
87
88Testing
89-------
90
91Run the Unbound server:
92
93``root@localhost>unbound -dv -c ./test-dict.conf``
94
95In case you use own configuration file, don't forget to enable Python module::
96
97    module-config: "validator python iterator"
98
99and use valid script path::
100
101    python-script: "./examples/dict.py"
102
103The translation from english word *"a bar fly"* to Czech can be done by doing:
104
105``>>>dig TXT @127.0.0.1 a.bar.fly.en._dict_.cz``
106
107::
108
109    ; (1 server found)
110    ;; global options:  printcmd
111    ;; Got answer:
112    ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 48691
113    ;; flags: aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
114
115    ;; QUESTION SECTION:
116    ;a.bar.fly.en._dict_.cz.    IN  TXT
117
118    ;; ANSWER SECTION:
119    a.bar.fly.en._dict_.cz. 300 IN  TXT "barov\253 povale\232"
120
121    ;; Query time: 5 msec
122    ;; SERVER: 127.0.0.1#53(127.0.0.1)
123    ;; WHEN: Mon Jan 01 17:44:18 2009
124    ;; MSG SIZE  rcvd: 67
125
126``>>>dig TXT @127.0.0.1 nic.cs._dict_.cz``
127
128::
129	
130    ; <<>> DiG 9.5.0-P2 <<>> TXT @127.0.0.1 nic.cs._dict_.cz
131    ; (1 server found)
132    ;; global options:  printcmd
133    ;; Got answer:
134    ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 58710
135    ;; flags: aa rd ra; QUERY: 1, ANSWER: 6, AUTHORITY: 0, ADDITIONAL: 0
136
137    ;; QUESTION SECTION:
138    ;nic.cs._dict_.cz.      IN  TXT
139
140    ;; ANSWER SECTION:
141    nic.cs._dict_.cz.   300 IN  TXT "aught"
142    nic.cs._dict_.cz.   300 IN  TXT "naught"
143    nic.cs._dict_.cz.   300 IN  TXT "nihil"
144    nic.cs._dict_.cz.   300 IN  TXT "nix"
145    nic.cs._dict_.cz.   300 IN  TXT "nothing"
146    nic.cs._dict_.cz.   300 IN  TXT "zilch"
147
148    ;; Query time: 0 msec
149    ;; SERVER: 127.0.0.1#53(127.0.0.1)
150    ;; WHEN: Mon Jan 01 17:45:39 2009
151    ;; MSG SIZE  rcvd: 143
152
153    Proof that the unbound still works as resolver.
154
155``>>>dig A @127.0.0.1 www.nic.cz``
156
157::
158
159    ; (1 server found)
160    ;; global options:  printcmd
161    ;; Got answer:
162    ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 19996
163    ;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 3, ADDITIONAL: 5
164
165    ;; QUESTION SECTION:
166    ;www.nic.cz.            IN  A
167
168    ;; ANSWER SECTION:
169    www.nic.cz.     1662    IN  A   217.31.205.50
170
171    ;; AUTHORITY SECTION:
172    ...
173
174Complete source code
175--------------------
176
177.. literalinclude:: ../../examples/dict.py
178   :language: python
179