libknot 3.3.10__tar.gz → 3.3.12.dev0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- libknot-3.3.12.dev0/PKG-INFO +320 -0
- libknot-3.3.12.dev0/README.md +298 -0
- {libknot-3.3.10 → libknot-3.3.12.dev0}/libknot/__init__.py +1 -1
- {libknot-3.3.10 → libknot-3.3.12.dev0}/libknot/control.py +2 -2
- {libknot-3.3.10 → libknot-3.3.12.dev0}/libknot/probe.py +6 -4
- libknot-3.3.12.dev0/libknot.egg-info/PKG-INFO +320 -0
- {libknot-3.3.10 → libknot-3.3.12.dev0}/pyproject.toml +1 -1
- {libknot-3.3.10 → libknot-3.3.12.dev0}/setup.py +1 -1
- libknot-3.3.10/PKG-INFO +0 -188
- libknot-3.3.10/README.md +0 -166
- libknot-3.3.10/libknot.egg-info/PKG-INFO +0 -188
- {libknot-3.3.10 → libknot-3.3.12.dev0}/libknot/dname.py +0 -0
- {libknot-3.3.10 → libknot-3.3.12.dev0}/libknot.egg-info/SOURCES.txt +0 -0
- {libknot-3.3.10 → libknot-3.3.12.dev0}/libknot.egg-info/dependency_links.txt +0 -0
- {libknot-3.3.10 → libknot-3.3.12.dev0}/libknot.egg-info/top_level.txt +0 -0
- {libknot-3.3.10 → libknot-3.3.12.dev0}/setup.cfg +0 -0
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: libknot
|
|
3
|
+
Version: 3.3.12.dev0
|
|
4
|
+
Summary: Python bindings for libknot
|
|
5
|
+
Home-page: https://gitlab.nic.cz/knot/knot-dns/-/tree/master/python/libknot
|
|
6
|
+
Author: CZ.NIC, z.s.p.o.
|
|
7
|
+
Author-email: "CZ.NIC, z.s.p.o." <knot-dns@labs.nic.cz>
|
|
8
|
+
License: GPL-3.0
|
|
9
|
+
Project-URL: Documentation, https://www.knot-dns.cz/documentation
|
|
10
|
+
Project-URL: Issues, https://gitlab.nic.cz/knot/knot-dns/-/issues
|
|
11
|
+
Project-URL: Source, https://gitlab.nic.cz/knot/knot-dns/-/tree/master/python/libknot
|
|
12
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Intended Audience :: System Administrators
|
|
15
|
+
Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Topic :: Internet :: Name Service (DNS)
|
|
18
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
19
|
+
Classifier: Topic :: System :: Systems Administration
|
|
20
|
+
Requires-Python: >=3.5
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
|
|
23
|
+
# Libknot API in Python
|
|
24
|
+
|
|
25
|
+
A Python interface for managing the Knot DNS daemon.
|
|
26
|
+
|
|
27
|
+
# Table of contents
|
|
28
|
+
|
|
29
|
+
* [Introduction](#introduction)
|
|
30
|
+
* [Control module](#control-module)
|
|
31
|
+
+ [Control usage](#control-usage)
|
|
32
|
+
+ [CTL protocol reference](#kctl-proto)
|
|
33
|
+
+ [CTL commands reference](#kctl-cmds)
|
|
34
|
+
+ [Control examples](#control-examples)
|
|
35
|
+
* [Probe module](#probe-module)
|
|
36
|
+
+ [Probe usage](#probe-usage)
|
|
37
|
+
+ [Probe examples](#probe-examples)
|
|
38
|
+
* [Dname module](#dname-module)
|
|
39
|
+
+ [Dname usage](#dname-usage)
|
|
40
|
+
+ [Dname examples](#dname-examples)
|
|
41
|
+
|
|
42
|
+
## Introduction<a id="introduction"></a>
|
|
43
|
+
|
|
44
|
+
If the shared `libknot.so` library isn't available in the library search path, it's
|
|
45
|
+
necessary to load the library first, e.g.:
|
|
46
|
+
|
|
47
|
+
```python3
|
|
48
|
+
import libknot
|
|
49
|
+
libknot.Knot("/usr/lib/libknot.so")
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Control module<a id="control-module"></a>
|
|
53
|
+
|
|
54
|
+
Using this module it's possible to create scripts for efficient tasks that
|
|
55
|
+
would require complex shell scripts with multiple calls of `knotc`. For
|
|
56
|
+
communication with the daemon it uses the same mechanism as the `knotc` utility,
|
|
57
|
+
i.e. communication via a Unix socket.
|
|
58
|
+
|
|
59
|
+
The module API is stored in `libknot.control`.
|
|
60
|
+
|
|
61
|
+
### Control usage<a id="control-usage"></a>
|
|
62
|
+
|
|
63
|
+
The module usage consists of several steps:
|
|
64
|
+
|
|
65
|
+
* Initialization and connection to the daemon control socket.
|
|
66
|
+
* One or more control operations. An operation is called by sending a command
|
|
67
|
+
with optional data to the daemon. The operation result has to be received
|
|
68
|
+
afterwards.
|
|
69
|
+
* Closing the connection and deinitialization.
|
|
70
|
+
|
|
71
|
+
### KnotCTL protocol overview<a id="kctl-proto"></a>
|
|
72
|
+
|
|
73
|
+
Connections are supposed to be short-lived, because maintaining a passive
|
|
74
|
+
connection is costly for the server. Therefore the expected usage of the ctl
|
|
75
|
+
interface is to always open a new connection on demand, then close it once it's
|
|
76
|
+
not immediately needed.
|
|
77
|
+
|
|
78
|
+
Messages are composed of units. These are of four types whose identifiers are
|
|
79
|
+
defined in `libknot.control.KnotCtlType`:
|
|
80
|
+
|
|
81
|
+
| Type | Description | IO action |
|
|
82
|
+
| ------- | ---------------------------------------------------------- | --------- |
|
|
83
|
+
| `END` | Signals intent to terminate connection. | flush |
|
|
84
|
+
| `DATA` | Holds various information - see about data sections below. | cache |
|
|
85
|
+
| `EXTRA` | Additional data. | cache |
|
|
86
|
+
| `BLOCK` | End of data block. | flush |
|
|
87
|
+
|
|
88
|
+
A unit can optionaly hold data, though this is only meaningful for the `DATA`
|
|
89
|
+
and `EXTRA` types. The data consists of several sections of which usually only
|
|
90
|
+
a few at a time will be present. For example when a unit issuing a `stats`
|
|
91
|
+
command is sent, there is no reason for it to contain an `ERROR` section.
|
|
92
|
+
|
|
93
|
+
The data section identifiers are defined in `libknot.control.KnotCtlDataIdx`:
|
|
94
|
+
|
|
95
|
+
| Section name | Description |
|
|
96
|
+
| ------------ | ------------------------------------------------------ |
|
|
97
|
+
| `COMMAND` | Command name. |
|
|
98
|
+
| `FLAGS` | Command flags. |
|
|
99
|
+
| `ERROR` | Error message. |
|
|
100
|
+
| `SECTION` | Configuration section name. |
|
|
101
|
+
| `ITEM` | Configuration item name. |
|
|
102
|
+
| `ID` | Configuration item identifier. |
|
|
103
|
+
| `ZONE` | Zone name. |
|
|
104
|
+
| `OWNER` | Zone record owner |
|
|
105
|
+
| `TTL` | Zone record TTL. |
|
|
106
|
+
| `TYPE` | Zone record type name. |
|
|
107
|
+
| `DATA` | Configuration item/zone record data. |
|
|
108
|
+
| `FILTERS` | Command options or filters for output data processing. |
|
|
109
|
+
|
|
110
|
+
### CTL commands reference<a id="kctl-cmds"></a>
|
|
111
|
+
|
|
112
|
+
The following is a reference for the low-level CTL API. In case you're unsure
|
|
113
|
+
of the commands' semantics, please consult the
|
|
114
|
+
<a href="https://knot.pages.nic.cz/knot-dns/master/html/man_knotc.html#actions">knotc documentation</a>.
|
|
115
|
+
|
|
116
|
+
A concise notation is used for command synopsis:
|
|
117
|
+
|
|
118
|
+
<pre>
|
|
119
|
+
cmd-name(SECTION_NAME:<i>section's purpouse</i>,
|
|
120
|
+
[OPTIONAL_SECTION=<b>"literal value"</b><i>:literal's purpouse</i>],
|
|
121
|
+
[OPT_SECTION1, OPT_SECTION2], <i># Sections must be present together or not at all</i>
|
|
122
|
+
[OPT_MASTER, [OPT_SLAVE]], <i># OPT_SLAVE may only appear if OPT_MASTER is present</i>
|
|
123
|
+
SECTION_NAME2=<b>"option1"</b>|<b>"option2"</b>, <i># Either one or the other literal may be used</i>
|
|
124
|
+
SECTION_NAME3={<b>"asdf"</b>}, <i># any subset of characters</i>
|
|
125
|
+
SECTION_NAME4=<b>"a"</b><i>:flag's purpouse</i>,<b>"s"</b>,<b>"d"</b>,<b>"f"</b> <i># any subset of characters</i>
|
|
126
|
+
)
|
|
127
|
+
</pre>
|
|
128
|
+
|
|
129
|
+
The **`"B"`** flag always represents an option to execute in blocking mode.
|
|
130
|
+
|
|
131
|
+
#### Server
|
|
132
|
+
|
|
133
|
+
* <pre>status([TYPE=<b>"cert-key"</b>|<b>"configure"</b>|<b>"version"</b>|<b>"workers"</b>])</pre>
|
|
134
|
+
* <pre>stop()</pre>
|
|
135
|
+
* <pre>reload()</pre>
|
|
136
|
+
* <pre>stats([SECTION:<i>module</i>], [ITEM:<i>counter</i>], [FLAGS=<b>"F"</b>:<i>include 0 counters</i>])</pre>
|
|
137
|
+
|
|
138
|
+
#### Zone events
|
|
139
|
+
|
|
140
|
+
`ZONE`: if none applies to all zones
|
|
141
|
+
|
|
142
|
+
* <pre>zone-status([ZONE], [FILTERS={<b>"rstefc"</b>}])</pre>
|
|
143
|
+
+ `FILTERS`: role `(r)`, serial `(s)`, transaction `(t)`, events `(e)`, freeze `(f)`, catalog `(c)`
|
|
144
|
+
* <pre>zone-reload([ZONE], [FLAGS={<b>"B"</b>,<b>"F"</b><i>:reload modules</i>}])</pre>
|
|
145
|
+
* <pre>zone-refresh([ZONE], [FLAGS=<b>"B"</b>])</pre>
|
|
146
|
+
* <pre>zone-retransfer([ZONE], [FLAGS=<b>"B"</b>])</pre>
|
|
147
|
+
* <pre>zone-notify([ZONE], [FLAGS=<b>"B"</b>])</pre>
|
|
148
|
+
* <pre>zone-flush([ZONE], [FILTERS=<b>"d"</b>, DATA:<i>output directory</i>], [FLAGS=<b>"B"</b>])</pre>
|
|
149
|
+
* <pre>zone-backup([ZONE], [FILTERS={<b>"dzjtkocq"</b>}, [DATA:<i>output dir if "d" filter present</i>]], [FLAGS=<b>"B"</b>])</pre>
|
|
150
|
+
+ `FILTERS`
|
|
151
|
+
- zonefile `(z)`, journal `(j)`, timers `(t)`, kaspdb `(k)`, keysonly `(o)`, catalog `(c)`, quic `(q)`
|
|
152
|
+
- negative counterparts (eg. `nozonefile`) are symmetrical and capitalized
|
|
153
|
+
* <pre>zone-restore <i>analogous to zone-backup</i></pre>
|
|
154
|
+
* <pre>zone-sign([ZONE], [FLAGS=<b>"B"</b>])</pre>
|
|
155
|
+
* <pre>zone-validate([ZONE], [FLAGS=<b>"B"</b>])</pre>
|
|
156
|
+
* <pre>zone-keys-load([ZONE], [FLAGS=<b>"B"</b>])</pre>
|
|
157
|
+
* <pre>zone-key-rollover([ZONE], TYPE=<b>"ksk"</b>|<b>"zsk"</b>, [FLAGS=<b>"B"</b>])</pre>
|
|
158
|
+
* <pre>zone-ksk-submitted([ZONE], [FLAGS=<b>"B"</b>])</pre>
|
|
159
|
+
* <pre>zone-freeze([ZONE], [FLAGS=<b>"B"</b>])</pre>
|
|
160
|
+
* <pre>zone-thaw([ZONE], [FLAGS=<b>"B"</b>])</pre>
|
|
161
|
+
* <pre>zone-xfr-freeze([ZONE], [FLAGS=<b>"B"</b>])</pre>
|
|
162
|
+
* <pre>zone-xfr-thaw([ZONE], [FLAGS=<b>"B"</b>])</pre>
|
|
163
|
+
|
|
164
|
+
#### Zone editing
|
|
165
|
+
|
|
166
|
+
Use `"@"` as `OWNER` if you want to denote `ZONE` itself as the owner.
|
|
167
|
+
|
|
168
|
+
* <pre>zone-read([ZONE<i>:if none read all</i>], [OWNER], [TYPE])</pre>
|
|
169
|
+
* <pre>zone-begin(ZONE)</pre>
|
|
170
|
+
* <pre>zone-commit(ZONE)</pre>
|
|
171
|
+
* <pre>zone-abort(ZONE)</pre>
|
|
172
|
+
* <pre>zone-diff(ZONE)</pre>
|
|
173
|
+
* <pre>zone-get(ZONE, [OWNER], [TYPE])</pre> <!-- TODO: test if OWNER and TYPE may be specified independently -->
|
|
174
|
+
* <pre>zone-set(ZONE, OWNER, [TTL], TYPE, DATA)</pre>
|
|
175
|
+
* <pre>zone-unset(ZONE, OWNER, [TYPE, [DATA]])</pre>
|
|
176
|
+
* <pre>zone-purge(ZONE, [FILTERS={<b>ocejktf</b>}], [FLAGS=<b>"B"</b>])</pre>
|
|
177
|
+
+ `FILTERS`: orphan `(o)`, catalog `(c)`, expire `(e)`, journal `(j)`, kaspdb `(k)`, timers `(t)`, zonefile `(f)`
|
|
178
|
+
* <pre>zone-stats(ZONE, [SECTION<i>:module</i>], [ITEM<i>:counter</i>], [FLAGS=<b>"F"</b>:<i>include 0 counters</i>])</pre>
|
|
179
|
+
|
|
180
|
+
#### Configuration
|
|
181
|
+
|
|
182
|
+
optional list schema option ('s') in FILTERS <!-- TODO: k cemu to je? -->
|
|
183
|
+
|
|
184
|
+
For the following commands:<br/>
|
|
185
|
+
· `SECTION` holds the configuration section name (eg. `template`)<br/>
|
|
186
|
+
· `ID` holds the configuration id (eg. `default`)<br/>
|
|
187
|
+
· `ITEM` holds the configuration item name (eg. `storage`)<br/>
|
|
188
|
+
|
|
189
|
+
* <pre>conf-list([SECTION, [ID], [ITEM]], [FILTERS=<b>"s"</b>])</pre>
|
|
190
|
+
* <pre>conf-read([SECTION, [ID], [ITEM]])</pre>
|
|
191
|
+
* <pre>conf-begin()</pre>
|
|
192
|
+
* <pre>conf-commit()</pre>
|
|
193
|
+
* <pre>conf-abort()</pre>
|
|
194
|
+
* <pre>conf-diff([SECTION, [ID], [ITEM]])</pre>
|
|
195
|
+
* <pre>conf-get([SECTION, [ID], [ITEM]])</pre>
|
|
196
|
+
* <pre>conf-set(SECTION, ID, ITEM, [DATA], [FILTERS=<b>"s"</b>])</pre>
|
|
197
|
+
* <pre>conf-unset([SECTION, [ID], [ITEM]], [DATA])</pre>
|
|
198
|
+
|
|
199
|
+
### Control examples<a id="control-examples"></a>
|
|
200
|
+
|
|
201
|
+
```python3
|
|
202
|
+
import json
|
|
203
|
+
import libknot.control
|
|
204
|
+
|
|
205
|
+
# Initialization
|
|
206
|
+
ctl = libknot.control.KnotCtl()
|
|
207
|
+
ctl.connect("/var/run/knot/knot.sock")
|
|
208
|
+
ctl.set_timeout(60)
|
|
209
|
+
|
|
210
|
+
try:
|
|
211
|
+
# Operation without parameters
|
|
212
|
+
ctl.send_block(cmd="conf-begin")
|
|
213
|
+
resp = ctl.receive_block()
|
|
214
|
+
|
|
215
|
+
# Operation with parameters
|
|
216
|
+
ctl.send_block(cmd="conf-set", section="zone", item="domain", data="test")
|
|
217
|
+
resp = ctl.receive_block()
|
|
218
|
+
|
|
219
|
+
ctl.send_block(cmd="conf-commit")
|
|
220
|
+
resp = ctl.receive_block()
|
|
221
|
+
|
|
222
|
+
# Operation with a result displayed in JSON format
|
|
223
|
+
ctl.send_block(cmd="conf-read", section="zone", item="domain")
|
|
224
|
+
resp = ctl.receive_block()
|
|
225
|
+
print(json.dumps(resp, indent=4))
|
|
226
|
+
except libknot.control.KnotCtlError as exc:
|
|
227
|
+
# Print libknot error
|
|
228
|
+
print(exc)
|
|
229
|
+
finally:
|
|
230
|
+
# Deinitialization
|
|
231
|
+
ctl.send(libknot.control.KnotCtlType.END)
|
|
232
|
+
ctl.close()
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
```python3
|
|
236
|
+
# List configured zones (including catalog member ones)
|
|
237
|
+
ctl.send_block(cmd="conf-list", filters="z")
|
|
238
|
+
resp = ctl.receive_block()
|
|
239
|
+
for zone in resp['zone']:
|
|
240
|
+
print(zone)
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
```python3
|
|
244
|
+
# Print expirations as unixtime for all secondary zones
|
|
245
|
+
ctl.send_block(cmd="zone-status", filters="u")
|
|
246
|
+
resp = ctl.receive_block()
|
|
247
|
+
for zone in resp:
|
|
248
|
+
if resp[zone]["role"] == "master":
|
|
249
|
+
continue
|
|
250
|
+
|
|
251
|
+
expiration = resp[zone]["expiration"]
|
|
252
|
+
if expiration == "-":
|
|
253
|
+
print("Zone %s not loaded" % zone)
|
|
254
|
+
else:
|
|
255
|
+
print("Zone %s expires at %s" % (zone, resp[zone]["expiration"]))
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
## Probe module<a id="probe module"></a>
|
|
259
|
+
|
|
260
|
+
Using this module it's possible to receive traffic data from a running daemon with
|
|
261
|
+
active probe module.
|
|
262
|
+
|
|
263
|
+
The module API is stored in `libknot.probe`.
|
|
264
|
+
|
|
265
|
+
### Probe usage<a id="probe-usage"></a>
|
|
266
|
+
|
|
267
|
+
The module usage consists of several steps:
|
|
268
|
+
|
|
269
|
+
* Initialization of one or more probe channels
|
|
270
|
+
* Periodical receiving of data units from the channels and data processing
|
|
271
|
+
|
|
272
|
+
### Probe examples<a id="probe-examples"></a>
|
|
273
|
+
|
|
274
|
+
```python3
|
|
275
|
+
import libknot.probe
|
|
276
|
+
|
|
277
|
+
# Initialization of the first probe channel stored in `/run/knot`
|
|
278
|
+
probe = libknot.probe.KnotProbe("/run/knot", 1)
|
|
279
|
+
|
|
280
|
+
# Array for storing up to 8 data units
|
|
281
|
+
data = libknot.probe.KnotProbeDataArray(8)
|
|
282
|
+
while (True):
|
|
283
|
+
# Receiving data units with timeout of 1000 ms
|
|
284
|
+
if probe.consume(data, 1000) > 0:
|
|
285
|
+
# Printing received data units in the default format
|
|
286
|
+
for item in data:
|
|
287
|
+
print(item)
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
## Dname module<a id="dname-module"></a>
|
|
291
|
+
|
|
292
|
+
This module provides a few dname-related operations.
|
|
293
|
+
|
|
294
|
+
The module API is stored in `libknot.dname`.
|
|
295
|
+
|
|
296
|
+
### Dname usage<a id="dname-usage"></a>
|
|
297
|
+
|
|
298
|
+
The dname object is initialized from a string with textual dname.
|
|
299
|
+
Then the dname can be reformatted to wire format or back to textual format.
|
|
300
|
+
|
|
301
|
+
### Dname examples<a id="dname-examples"></a>
|
|
302
|
+
|
|
303
|
+
```python3
|
|
304
|
+
import libknot.dname
|
|
305
|
+
|
|
306
|
+
dname1 = libknot.dname.KnotDname("knot-dns.cz")
|
|
307
|
+
print("%s: wire: %s size: %u" % (dname1.str(), dname1.wire(), dname1.size()))
|
|
308
|
+
|
|
309
|
+
dname2 = libknot.dname.KnotDname("e\\120ample.c\om.")
|
|
310
|
+
print("%s: wire: %s size: %u" % (dname2.str(), dname2.wire(), dname2.size()))
|
|
311
|
+
|
|
312
|
+
dname3 = libknot.dname.KnotDname(dname_wire=b'\x02cz\x00')
|
|
313
|
+
print("%s: wire: %s size: %u" % (dname3.str(), dname3.wire(), dname3.size()))
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
```bash
|
|
317
|
+
knot-dns.cz.: wire: b'\x08knot-dns\x02cz\x00' size: 13
|
|
318
|
+
example.com.: wire: b'\x07example\x03com\x00' size: 13
|
|
319
|
+
cz.: wire: b'\x02cz\x00' size: 4
|
|
320
|
+
```
|
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
# Libknot API in Python
|
|
2
|
+
|
|
3
|
+
A Python interface for managing the Knot DNS daemon.
|
|
4
|
+
|
|
5
|
+
# Table of contents
|
|
6
|
+
|
|
7
|
+
* [Introduction](#introduction)
|
|
8
|
+
* [Control module](#control-module)
|
|
9
|
+
+ [Control usage](#control-usage)
|
|
10
|
+
+ [CTL protocol reference](#kctl-proto)
|
|
11
|
+
+ [CTL commands reference](#kctl-cmds)
|
|
12
|
+
+ [Control examples](#control-examples)
|
|
13
|
+
* [Probe module](#probe-module)
|
|
14
|
+
+ [Probe usage](#probe-usage)
|
|
15
|
+
+ [Probe examples](#probe-examples)
|
|
16
|
+
* [Dname module](#dname-module)
|
|
17
|
+
+ [Dname usage](#dname-usage)
|
|
18
|
+
+ [Dname examples](#dname-examples)
|
|
19
|
+
|
|
20
|
+
## Introduction<a id="introduction"></a>
|
|
21
|
+
|
|
22
|
+
If the shared `libknot.so` library isn't available in the library search path, it's
|
|
23
|
+
necessary to load the library first, e.g.:
|
|
24
|
+
|
|
25
|
+
```python3
|
|
26
|
+
import libknot
|
|
27
|
+
libknot.Knot("/usr/lib/libknot.so")
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Control module<a id="control-module"></a>
|
|
31
|
+
|
|
32
|
+
Using this module it's possible to create scripts for efficient tasks that
|
|
33
|
+
would require complex shell scripts with multiple calls of `knotc`. For
|
|
34
|
+
communication with the daemon it uses the same mechanism as the `knotc` utility,
|
|
35
|
+
i.e. communication via a Unix socket.
|
|
36
|
+
|
|
37
|
+
The module API is stored in `libknot.control`.
|
|
38
|
+
|
|
39
|
+
### Control usage<a id="control-usage"></a>
|
|
40
|
+
|
|
41
|
+
The module usage consists of several steps:
|
|
42
|
+
|
|
43
|
+
* Initialization and connection to the daemon control socket.
|
|
44
|
+
* One or more control operations. An operation is called by sending a command
|
|
45
|
+
with optional data to the daemon. The operation result has to be received
|
|
46
|
+
afterwards.
|
|
47
|
+
* Closing the connection and deinitialization.
|
|
48
|
+
|
|
49
|
+
### KnotCTL protocol overview<a id="kctl-proto"></a>
|
|
50
|
+
|
|
51
|
+
Connections are supposed to be short-lived, because maintaining a passive
|
|
52
|
+
connection is costly for the server. Therefore the expected usage of the ctl
|
|
53
|
+
interface is to always open a new connection on demand, then close it once it's
|
|
54
|
+
not immediately needed.
|
|
55
|
+
|
|
56
|
+
Messages are composed of units. These are of four types whose identifiers are
|
|
57
|
+
defined in `libknot.control.KnotCtlType`:
|
|
58
|
+
|
|
59
|
+
| Type | Description | IO action |
|
|
60
|
+
| ------- | ---------------------------------------------------------- | --------- |
|
|
61
|
+
| `END` | Signals intent to terminate connection. | flush |
|
|
62
|
+
| `DATA` | Holds various information - see about data sections below. | cache |
|
|
63
|
+
| `EXTRA` | Additional data. | cache |
|
|
64
|
+
| `BLOCK` | End of data block. | flush |
|
|
65
|
+
|
|
66
|
+
A unit can optionaly hold data, though this is only meaningful for the `DATA`
|
|
67
|
+
and `EXTRA` types. The data consists of several sections of which usually only
|
|
68
|
+
a few at a time will be present. For example when a unit issuing a `stats`
|
|
69
|
+
command is sent, there is no reason for it to contain an `ERROR` section.
|
|
70
|
+
|
|
71
|
+
The data section identifiers are defined in `libknot.control.KnotCtlDataIdx`:
|
|
72
|
+
|
|
73
|
+
| Section name | Description |
|
|
74
|
+
| ------------ | ------------------------------------------------------ |
|
|
75
|
+
| `COMMAND` | Command name. |
|
|
76
|
+
| `FLAGS` | Command flags. |
|
|
77
|
+
| `ERROR` | Error message. |
|
|
78
|
+
| `SECTION` | Configuration section name. |
|
|
79
|
+
| `ITEM` | Configuration item name. |
|
|
80
|
+
| `ID` | Configuration item identifier. |
|
|
81
|
+
| `ZONE` | Zone name. |
|
|
82
|
+
| `OWNER` | Zone record owner |
|
|
83
|
+
| `TTL` | Zone record TTL. |
|
|
84
|
+
| `TYPE` | Zone record type name. |
|
|
85
|
+
| `DATA` | Configuration item/zone record data. |
|
|
86
|
+
| `FILTERS` | Command options or filters for output data processing. |
|
|
87
|
+
|
|
88
|
+
### CTL commands reference<a id="kctl-cmds"></a>
|
|
89
|
+
|
|
90
|
+
The following is a reference for the low-level CTL API. In case you're unsure
|
|
91
|
+
of the commands' semantics, please consult the
|
|
92
|
+
<a href="https://knot.pages.nic.cz/knot-dns/master/html/man_knotc.html#actions">knotc documentation</a>.
|
|
93
|
+
|
|
94
|
+
A concise notation is used for command synopsis:
|
|
95
|
+
|
|
96
|
+
<pre>
|
|
97
|
+
cmd-name(SECTION_NAME:<i>section's purpouse</i>,
|
|
98
|
+
[OPTIONAL_SECTION=<b>"literal value"</b><i>:literal's purpouse</i>],
|
|
99
|
+
[OPT_SECTION1, OPT_SECTION2], <i># Sections must be present together or not at all</i>
|
|
100
|
+
[OPT_MASTER, [OPT_SLAVE]], <i># OPT_SLAVE may only appear if OPT_MASTER is present</i>
|
|
101
|
+
SECTION_NAME2=<b>"option1"</b>|<b>"option2"</b>, <i># Either one or the other literal may be used</i>
|
|
102
|
+
SECTION_NAME3={<b>"asdf"</b>}, <i># any subset of characters</i>
|
|
103
|
+
SECTION_NAME4=<b>"a"</b><i>:flag's purpouse</i>,<b>"s"</b>,<b>"d"</b>,<b>"f"</b> <i># any subset of characters</i>
|
|
104
|
+
)
|
|
105
|
+
</pre>
|
|
106
|
+
|
|
107
|
+
The **`"B"`** flag always represents an option to execute in blocking mode.
|
|
108
|
+
|
|
109
|
+
#### Server
|
|
110
|
+
|
|
111
|
+
* <pre>status([TYPE=<b>"cert-key"</b>|<b>"configure"</b>|<b>"version"</b>|<b>"workers"</b>])</pre>
|
|
112
|
+
* <pre>stop()</pre>
|
|
113
|
+
* <pre>reload()</pre>
|
|
114
|
+
* <pre>stats([SECTION:<i>module</i>], [ITEM:<i>counter</i>], [FLAGS=<b>"F"</b>:<i>include 0 counters</i>])</pre>
|
|
115
|
+
|
|
116
|
+
#### Zone events
|
|
117
|
+
|
|
118
|
+
`ZONE`: if none applies to all zones
|
|
119
|
+
|
|
120
|
+
* <pre>zone-status([ZONE], [FILTERS={<b>"rstefc"</b>}])</pre>
|
|
121
|
+
+ `FILTERS`: role `(r)`, serial `(s)`, transaction `(t)`, events `(e)`, freeze `(f)`, catalog `(c)`
|
|
122
|
+
* <pre>zone-reload([ZONE], [FLAGS={<b>"B"</b>,<b>"F"</b><i>:reload modules</i>}])</pre>
|
|
123
|
+
* <pre>zone-refresh([ZONE], [FLAGS=<b>"B"</b>])</pre>
|
|
124
|
+
* <pre>zone-retransfer([ZONE], [FLAGS=<b>"B"</b>])</pre>
|
|
125
|
+
* <pre>zone-notify([ZONE], [FLAGS=<b>"B"</b>])</pre>
|
|
126
|
+
* <pre>zone-flush([ZONE], [FILTERS=<b>"d"</b>, DATA:<i>output directory</i>], [FLAGS=<b>"B"</b>])</pre>
|
|
127
|
+
* <pre>zone-backup([ZONE], [FILTERS={<b>"dzjtkocq"</b>}, [DATA:<i>output dir if "d" filter present</i>]], [FLAGS=<b>"B"</b>])</pre>
|
|
128
|
+
+ `FILTERS`
|
|
129
|
+
- zonefile `(z)`, journal `(j)`, timers `(t)`, kaspdb `(k)`, keysonly `(o)`, catalog `(c)`, quic `(q)`
|
|
130
|
+
- negative counterparts (eg. `nozonefile`) are symmetrical and capitalized
|
|
131
|
+
* <pre>zone-restore <i>analogous to zone-backup</i></pre>
|
|
132
|
+
* <pre>zone-sign([ZONE], [FLAGS=<b>"B"</b>])</pre>
|
|
133
|
+
* <pre>zone-validate([ZONE], [FLAGS=<b>"B"</b>])</pre>
|
|
134
|
+
* <pre>zone-keys-load([ZONE], [FLAGS=<b>"B"</b>])</pre>
|
|
135
|
+
* <pre>zone-key-rollover([ZONE], TYPE=<b>"ksk"</b>|<b>"zsk"</b>, [FLAGS=<b>"B"</b>])</pre>
|
|
136
|
+
* <pre>zone-ksk-submitted([ZONE], [FLAGS=<b>"B"</b>])</pre>
|
|
137
|
+
* <pre>zone-freeze([ZONE], [FLAGS=<b>"B"</b>])</pre>
|
|
138
|
+
* <pre>zone-thaw([ZONE], [FLAGS=<b>"B"</b>])</pre>
|
|
139
|
+
* <pre>zone-xfr-freeze([ZONE], [FLAGS=<b>"B"</b>])</pre>
|
|
140
|
+
* <pre>zone-xfr-thaw([ZONE], [FLAGS=<b>"B"</b>])</pre>
|
|
141
|
+
|
|
142
|
+
#### Zone editing
|
|
143
|
+
|
|
144
|
+
Use `"@"` as `OWNER` if you want to denote `ZONE` itself as the owner.
|
|
145
|
+
|
|
146
|
+
* <pre>zone-read([ZONE<i>:if none read all</i>], [OWNER], [TYPE])</pre>
|
|
147
|
+
* <pre>zone-begin(ZONE)</pre>
|
|
148
|
+
* <pre>zone-commit(ZONE)</pre>
|
|
149
|
+
* <pre>zone-abort(ZONE)</pre>
|
|
150
|
+
* <pre>zone-diff(ZONE)</pre>
|
|
151
|
+
* <pre>zone-get(ZONE, [OWNER], [TYPE])</pre> <!-- TODO: test if OWNER and TYPE may be specified independently -->
|
|
152
|
+
* <pre>zone-set(ZONE, OWNER, [TTL], TYPE, DATA)</pre>
|
|
153
|
+
* <pre>zone-unset(ZONE, OWNER, [TYPE, [DATA]])</pre>
|
|
154
|
+
* <pre>zone-purge(ZONE, [FILTERS={<b>ocejktf</b>}], [FLAGS=<b>"B"</b>])</pre>
|
|
155
|
+
+ `FILTERS`: orphan `(o)`, catalog `(c)`, expire `(e)`, journal `(j)`, kaspdb `(k)`, timers `(t)`, zonefile `(f)`
|
|
156
|
+
* <pre>zone-stats(ZONE, [SECTION<i>:module</i>], [ITEM<i>:counter</i>], [FLAGS=<b>"F"</b>:<i>include 0 counters</i>])</pre>
|
|
157
|
+
|
|
158
|
+
#### Configuration
|
|
159
|
+
|
|
160
|
+
optional list schema option ('s') in FILTERS <!-- TODO: k cemu to je? -->
|
|
161
|
+
|
|
162
|
+
For the following commands:<br/>
|
|
163
|
+
· `SECTION` holds the configuration section name (eg. `template`)<br/>
|
|
164
|
+
· `ID` holds the configuration id (eg. `default`)<br/>
|
|
165
|
+
· `ITEM` holds the configuration item name (eg. `storage`)<br/>
|
|
166
|
+
|
|
167
|
+
* <pre>conf-list([SECTION, [ID], [ITEM]], [FILTERS=<b>"s"</b>])</pre>
|
|
168
|
+
* <pre>conf-read([SECTION, [ID], [ITEM]])</pre>
|
|
169
|
+
* <pre>conf-begin()</pre>
|
|
170
|
+
* <pre>conf-commit()</pre>
|
|
171
|
+
* <pre>conf-abort()</pre>
|
|
172
|
+
* <pre>conf-diff([SECTION, [ID], [ITEM]])</pre>
|
|
173
|
+
* <pre>conf-get([SECTION, [ID], [ITEM]])</pre>
|
|
174
|
+
* <pre>conf-set(SECTION, ID, ITEM, [DATA], [FILTERS=<b>"s"</b>])</pre>
|
|
175
|
+
* <pre>conf-unset([SECTION, [ID], [ITEM]], [DATA])</pre>
|
|
176
|
+
|
|
177
|
+
### Control examples<a id="control-examples"></a>
|
|
178
|
+
|
|
179
|
+
```python3
|
|
180
|
+
import json
|
|
181
|
+
import libknot.control
|
|
182
|
+
|
|
183
|
+
# Initialization
|
|
184
|
+
ctl = libknot.control.KnotCtl()
|
|
185
|
+
ctl.connect("/var/run/knot/knot.sock")
|
|
186
|
+
ctl.set_timeout(60)
|
|
187
|
+
|
|
188
|
+
try:
|
|
189
|
+
# Operation without parameters
|
|
190
|
+
ctl.send_block(cmd="conf-begin")
|
|
191
|
+
resp = ctl.receive_block()
|
|
192
|
+
|
|
193
|
+
# Operation with parameters
|
|
194
|
+
ctl.send_block(cmd="conf-set", section="zone", item="domain", data="test")
|
|
195
|
+
resp = ctl.receive_block()
|
|
196
|
+
|
|
197
|
+
ctl.send_block(cmd="conf-commit")
|
|
198
|
+
resp = ctl.receive_block()
|
|
199
|
+
|
|
200
|
+
# Operation with a result displayed in JSON format
|
|
201
|
+
ctl.send_block(cmd="conf-read", section="zone", item="domain")
|
|
202
|
+
resp = ctl.receive_block()
|
|
203
|
+
print(json.dumps(resp, indent=4))
|
|
204
|
+
except libknot.control.KnotCtlError as exc:
|
|
205
|
+
# Print libknot error
|
|
206
|
+
print(exc)
|
|
207
|
+
finally:
|
|
208
|
+
# Deinitialization
|
|
209
|
+
ctl.send(libknot.control.KnotCtlType.END)
|
|
210
|
+
ctl.close()
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
```python3
|
|
214
|
+
# List configured zones (including catalog member ones)
|
|
215
|
+
ctl.send_block(cmd="conf-list", filters="z")
|
|
216
|
+
resp = ctl.receive_block()
|
|
217
|
+
for zone in resp['zone']:
|
|
218
|
+
print(zone)
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
```python3
|
|
222
|
+
# Print expirations as unixtime for all secondary zones
|
|
223
|
+
ctl.send_block(cmd="zone-status", filters="u")
|
|
224
|
+
resp = ctl.receive_block()
|
|
225
|
+
for zone in resp:
|
|
226
|
+
if resp[zone]["role"] == "master":
|
|
227
|
+
continue
|
|
228
|
+
|
|
229
|
+
expiration = resp[zone]["expiration"]
|
|
230
|
+
if expiration == "-":
|
|
231
|
+
print("Zone %s not loaded" % zone)
|
|
232
|
+
else:
|
|
233
|
+
print("Zone %s expires at %s" % (zone, resp[zone]["expiration"]))
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
## Probe module<a id="probe module"></a>
|
|
237
|
+
|
|
238
|
+
Using this module it's possible to receive traffic data from a running daemon with
|
|
239
|
+
active probe module.
|
|
240
|
+
|
|
241
|
+
The module API is stored in `libknot.probe`.
|
|
242
|
+
|
|
243
|
+
### Probe usage<a id="probe-usage"></a>
|
|
244
|
+
|
|
245
|
+
The module usage consists of several steps:
|
|
246
|
+
|
|
247
|
+
* Initialization of one or more probe channels
|
|
248
|
+
* Periodical receiving of data units from the channels and data processing
|
|
249
|
+
|
|
250
|
+
### Probe examples<a id="probe-examples"></a>
|
|
251
|
+
|
|
252
|
+
```python3
|
|
253
|
+
import libknot.probe
|
|
254
|
+
|
|
255
|
+
# Initialization of the first probe channel stored in `/run/knot`
|
|
256
|
+
probe = libknot.probe.KnotProbe("/run/knot", 1)
|
|
257
|
+
|
|
258
|
+
# Array for storing up to 8 data units
|
|
259
|
+
data = libknot.probe.KnotProbeDataArray(8)
|
|
260
|
+
while (True):
|
|
261
|
+
# Receiving data units with timeout of 1000 ms
|
|
262
|
+
if probe.consume(data, 1000) > 0:
|
|
263
|
+
# Printing received data units in the default format
|
|
264
|
+
for item in data:
|
|
265
|
+
print(item)
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
## Dname module<a id="dname-module"></a>
|
|
269
|
+
|
|
270
|
+
This module provides a few dname-related operations.
|
|
271
|
+
|
|
272
|
+
The module API is stored in `libknot.dname`.
|
|
273
|
+
|
|
274
|
+
### Dname usage<a id="dname-usage"></a>
|
|
275
|
+
|
|
276
|
+
The dname object is initialized from a string with textual dname.
|
|
277
|
+
Then the dname can be reformatted to wire format or back to textual format.
|
|
278
|
+
|
|
279
|
+
### Dname examples<a id="dname-examples"></a>
|
|
280
|
+
|
|
281
|
+
```python3
|
|
282
|
+
import libknot.dname
|
|
283
|
+
|
|
284
|
+
dname1 = libknot.dname.KnotDname("knot-dns.cz")
|
|
285
|
+
print("%s: wire: %s size: %u" % (dname1.str(), dname1.wire(), dname1.size()))
|
|
286
|
+
|
|
287
|
+
dname2 = libknot.dname.KnotDname("e\\120ample.c\om.")
|
|
288
|
+
print("%s: wire: %s size: %u" % (dname2.str(), dname2.wire(), dname2.size()))
|
|
289
|
+
|
|
290
|
+
dname3 = libknot.dname.KnotDname(dname_wire=b'\x02cz\x00')
|
|
291
|
+
print("%s: wire: %s size: %u" % (dname3.str(), dname3.wire(), dname3.size()))
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
```bash
|
|
295
|
+
knot-dns.cz.: wire: b'\x08knot-dns\x02cz\x00' size: 13
|
|
296
|
+
example.com.: wire: b'\x07example\x03com\x00' size: 13
|
|
297
|
+
cz.: wire: b'\x02cz\x00' size: 4
|
|
298
|
+
```
|
|
@@ -37,7 +37,7 @@ class KnotCtlDataIdx(enum.IntEnum):
|
|
|
37
37
|
TTL = 8
|
|
38
38
|
TYPE = 9
|
|
39
39
|
DATA = 10
|
|
40
|
-
|
|
40
|
+
FILTERS = 11
|
|
41
41
|
|
|
42
42
|
|
|
43
43
|
class KnotCtlData(object):
|
|
@@ -207,7 +207,7 @@ class KnotCtl(object):
|
|
|
207
207
|
query[KnotCtlDataIdx.TYPE] = rtype
|
|
208
208
|
query[KnotCtlDataIdx.DATA] = data
|
|
209
209
|
query[KnotCtlDataIdx.FLAGS] = flags
|
|
210
|
-
query[KnotCtlDataIdx.
|
|
210
|
+
query[KnotCtlDataIdx.FILTERS] = filters
|
|
211
211
|
|
|
212
212
|
self.send(KnotCtlType.DATA, query)
|
|
213
213
|
self.send(KnotCtlType.BLOCK)
|
|
@@ -12,9 +12,9 @@ class KnotProbeDataProto(enum.IntEnum):
|
|
|
12
12
|
|
|
13
13
|
UDP = 0
|
|
14
14
|
TCP = 1
|
|
15
|
-
QUIC =
|
|
16
|
-
TLS =
|
|
17
|
-
HTTPS =
|
|
15
|
+
QUIC = 2
|
|
16
|
+
TLS = 3
|
|
17
|
+
HTTPS = 4
|
|
18
18
|
|
|
19
19
|
|
|
20
20
|
class KnotProbeDataDNSHdr(ctypes.BigEndianStructure):
|
|
@@ -132,8 +132,10 @@ class KnotProbeData(ctypes.Structure):
|
|
|
132
132
|
string += COL("UDP", GRN)
|
|
133
133
|
elif self.proto == KnotProbeDataProto.TCP:
|
|
134
134
|
string += COL("TCP", RED)
|
|
135
|
-
|
|
135
|
+
elif self.proto == KnotProbeDataProto.QUIC:
|
|
136
136
|
string += COL("QUIC", ORG)
|
|
137
|
+
else:
|
|
138
|
+
string += COL("TLS", YELW)
|
|
137
139
|
if self.tcp_rtt > 0:
|
|
138
140
|
string += ", RTT %.2f ms" % (self.tcp_rtt / 1000)
|
|
139
141
|
string += "\n ID %u, " % self.query_hdr.id
|