192 lines
6.3 KiB
ReStructuredText
192 lines
6.3 KiB
ReStructuredText
|
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
|