1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191
|
EDNS options
============
This example shows how to interact with EDNS options.
When querying 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 occurrences 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"
Querying 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
|