a85b5759f3
These files were pulled from the 1.6.3 release tarball. This new version builds against OpenSSL version 1.1 which will be the default in the new Debian Stable which is due to be released RealSoonNow (tm).
179 lines
4.8 KiB
ReStructuredText
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
|