README.md 10.7 KB
Newer Older
Stéphane Bortzmeyer's avatar
Stéphane Bortzmeyer committed
1
2
# Homer

3
4
Homer is a DoH (DNS-over-HTTPS) and DoT (DNS-over-TLS) client. Its
main purpose is to test DoH and DoT resolvers.
Stephane Bortzmeyer's avatar
Stephane Bortzmeyer committed
5
6
7
8
9

It is currently quite experimental.

## Usage

10
11
12
13
14
Two mandatory arguments, the URL of the DoH server (or name/address of
the DoT resolver), and a domain name to query. By default, Homer uses
DoH. Also by defaut, the type of data is AAAA (IP address). You can
add a third argument to use another type, as in the second example
below.
Stephane Bortzmeyer's avatar
Stephane Bortzmeyer committed
15
16

```
17
% homer https://doh.powerdns.org/ framagit.org
Stephane Bortzmeyer's avatar
Stephane Bortzmeyer committed
18
19
20
21
22
23
24
25
26
27
28
id 0
opcode QUERY
rcode NOERROR
flags QR RD RA
;QUESTION
framagit.org. IN AAAA
;ANSWER
framagit.org. 10800 IN AAAA 2a01:4f8:200:1302::42
;AUTHORITY
;ADDITIONAL
Total elapsed time: 0.40 seconds (402.28 ms/request)
29
30
31
32
33
34
35
36
37
38
39
40
41
42

% homer --dot 9.9.9.9 cocca.fr A
id 42545
opcode QUERY
rcode NOERROR
flags QR RD RA
;QUESTION
cocca.fr. IN A
;ANSWER
cocca.fr. 43200 IN A 185.17.236.69
;AUTHORITY
;ADDITIONAL

Total elapsed time: 0.07 seconds (66.72 ms/request )
Stephane Bortzmeyer's avatar
Stephane Bortzmeyer committed
43
44
```

45
46
47
Possible options, besides `--dot`:

* --verbose or -v: Makes the program more talkative
Alexandre's avatar
Alexandre committed
48
* --debug: Makes the program very talkative (sets verbose to true)
49
50
51
52
* --head or -e: (DoH) Uses only the HEAD HTTP method. Since the RFC
  does not mention it, result is probably indefinite.
* --POST or -P: (DoH) Uses the POST HTTP method (default is GET)
* --insecure or -k: Does not check the certificate
53
54
* -4: Uses only IPv4
* -6: Uses only IPv6
55
56
* --dnssec: requests DNSSEC data (signatures)
* --noedns: no EDNS (default is to indicate EDNS support)
57
58
59
60
* --ecs: send ECS, my subnet to auth. servers (default is to refuse
  it)
* --key KEYINBASE64: authentifies a DoT resolver with its public
  key. Example: `homer.py --key "62lKu9HsDVbyiPenApnc4sfmSYTHOVfFgL3pyB+cBL4=" --dot 145.100.185.15 IN NS`
Alexandre's avatar
Alexandre committed
61
* --check: Run a set of tests (see below)
62
63
64
* --pipelining: on DoT, send several requests even before getting the
  reply to the first one (may increase performance when you have
  several requests)
Alexandre's avatar
Alexandre committed
65
66
67
68
* --multistreams: (DoH) Uses HTTP/2 streams (requires the --file option)
* --file INPUT_FILE: provide an input file with a list of domain name to query
  (read the first line only, use --repeat N to read up to N lines of the file)
* --repeat N: repeat a test N times or read up to N lines of a file
69
* --no-display-results: do not output DNS response
Alexandre's avatar
Alexandre committed
70
71
72
73
74
75
76
77
78
79
80
81
82

### Check

The `--check` option allows to run several defined tests on a connection.

Homer displays `OK` on success and `KO` on failure.
The program stops after the first failed test.

```
% homer --check https://doh.bortzmeyer.fr framagit.org
OK
```

83
84
85
86
87
88
89
90
Each test is marked with a level of compliance. There are three
levels, "legal" (compliant with the strict requirments of the RFCs),
"necessary" (in a typical setup) and "nicetohave". The default level
is "necessary" but you can change it with option
`--mandatory-check`. For instance, sending a reply when the request
uses the HEAD method is "nicetohave" for a DoH server (the RFC does
not mandate it). The tests are always performed but are not fatal if
the choosen level is lower than the level of the test.
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

### Repetition of tests

You can repeat the tests several times, for instance for performance
measurements. This is done with option `--repeat N` where N is the
number of repetitions.

```
% homer --repeat 3 https://doh.bortzmeyer.fr ça.fr SOA
Test 0
...
Test 1
...
Test 2

Total elapsed time: 0.10 seconds (33.56 ms/request , 7.88 ms/request if we ignore the first one)
```

Homer reuses the same connection for all requests, both for DoH and
DoT, which explains why the first request is often longer.

Repetition is often combined with the use of an external file, where
Homer reads the domain names (and types) to query. Here is a sample
file:

```
truc.fr
chose.fr
machin.fr
trucmachin.fr NS
```

Assuming the file is named `list.txt`, this command will run four
tests, with the above names (and the query type `NS` for the last
one):

```
% homer --repeat 4 --file list.txt https://doh.42l.fr/dns-query
```

When repeating tests, you can add a delay between tests, with `--delay
Alexandre's avatar
Alexandre committed
132
133
N` or `-d N`, where N is the (possibly fractional) number of seconds
to wait.
134

Alexandre's avatar
Alexandre committed
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
### Mulitstreams

When using Homer with DoH, the option `--multistreams` can be used
to specify that you want to take advantage of the HTTP/2 streams
when sending several requests.

This option requires an input file provided with the `--file` option.
By default only the first line of the file is read. You need to
specify a number of line with `--repeat` to read more lines from
the file.

For example :
```
% ./homer.py --multistreams --file input_file --repeat 5 https://doh.powerdns.org
```

In order to focus on the time per request, you can suppress the
152
output by using the option `--no-display-results`.
Alexandre's avatar
Alexandre committed
153

154
Two modes are available. By default each response is read,
Alexandre's avatar
Alexandre committed
155
156
157
158
159
checked and displayed as soon as it is received.
You can use `--sync` to delay this processing after the last transfer.
In that case the DNS responses are displayed in the same order as they
were sent.

160
161
162
163
164
165
An option `--time` allows to display the time taken by each transfer.
This is based on [libcurl time values](https://curl.haxx.se/libcurl/c/curl_easy_getinfo.html#TIMES)
[CURLINFO_TOTAL_TIME](https://curl.haxx.se/libcurl/c/curl_easy_getinfo.html#CURLINFOTOTALTIME)
and [CURLINFO_PRETRANSFER_TIME](https://curl.haxx.se/libcurl/c/curl_easy_getinfo.html#CURLINFOPRETRANSFERTIME)

```
166
% ./homer.py  --multistreams --file input_file --repeat 5 --no-display-results --time https://doh.powerdns.org
Alexandre's avatar
Alexandre committed
167
168
169
170
171
  0   (200)     41.995 ms    51.409 ms     9.414 ms
  1   (200)      0.156 ms     8.648 ms     8.492 ms
  2   (200)      0.121 ms     8.494 ms     8.373 ms
  3   (200)      0.120 ms    11.185 ms    11.065 ms
  4   (200)      0.103 ms    11.922 ms    11.819 ms
172

Alexandre's avatar
Alexandre committed
173
Total elapsed time: 0.07 seconds (9.83 ms/request)
174
175
```

176
177
178

### Monitoring with Nagios, Icinga, or similar software

Winfried Angele's avatar
Winfried Angele committed
179
If the program is named `check_doh` or ` check_dot` (either from
180
181
182
183
184
185
186
187
188
189
copying or symbolic linking), it will behave as a [monitoring
plugin](https://www.monitoring-plugins.org/), suitable to be used from monitoring program like Nagios
or [Icinga](https://icinga.com/). The options are different in that case, and follow the
monitoring plugins conventions:

* -H: host name or address to monitor
* -V: virtual hostname (the certificate check will be based on that)
* -n: domain name to lookup
* -t: DNS type to query
* -p: (DoH) path in the URLx
190
* -e: a string to expect in the result
191
192
193
* -P: uses the HTTP method POST
* -h: uses the HTTP method HEAD
* -i: insecure (do not check the certificate)
194
* -k:  authenticated the DoT server with this public key
195
196
197
198
199
200
201
202
203
204
205

For Icinga, the following definition enables the plugin:

```
object CheckCommand "doh_monitor" {
  command = [ PluginContribDir + "/check_doh" ]

  arguments = {
      "-H" = "$address6$",
	  "-n" = "$doh_lookup$",
	  "-p" = "$doh_path$",
206
	  "-e" = "$doh_expect$",
207
208
	  "-V" = "$doh_vhost$",
	  "-t" = "$doh_type$",
Winfried Angele's avatar
Winfried Angele committed
209
	  "-P" = "$doh_post$",
210
211
212
213
214
215
216
217
218
219
220
221
	  "-i" = "$doh_insecure$",
	  "-h" = "$doh_head$"	
	  }
}

object CheckCommand "dot_monitor" {
  command = [ PluginContribDir + "/check_dot" ]

  arguments = {
      "-H" = "$address6$",
	  "-n" = "$dot_lookup$",
	  "-p" = "$dot_path$",
222
	  "-e" = "$dot_expect$",
223
224
	  "-V" = "$dot_vhost$",
	  "-t" = "$dot_type$",
Winfried Angele's avatar
Winfried Angele committed
225
	  "-P" = "$dot_post$",
226
	  "-i" = "$dot_insecure$",
227
228
	  "-h" = "$dot_head$",
	  "-k" = "$dot_key$"
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
	}
}

```

And a possible use is:

```
apply Service "doh" {
  import "generic-service"
  check_command = "doh_monitor"
    assign where (host.address || host.address6) && host.vars.doh
      vars.doh_lookup = "fr.wikipedia.org"

}

apply Service "dot" {
  import "generic-service"
  check_command = "dot_monitor"
    assign where (host.address || host.address6) && host.vars.dot
      vars.dot_lookup = "fr.wikipedia.org"

}

```

```
object Host "myserver" {
...
  vars.dot = true
  vars.dot_vhost = "dot.me.example"

  vars.doh = true
  vars.doh_vhost = "doh.me.example"
  vars.doh_post = true

```
266

Stephane Bortzmeyer's avatar
Stephane Bortzmeyer committed
267
268
## Installation

269
270
271
You need Python 3, [DNSpython](http://www.dnspython.org/),
[PyOpenSSL](https://www.pyopenssl.org/),
[netaddr](https://github.com/drkjam/netaddr/) and
272
[pycurl](http://pycurl.io/docs/latest). You can install them with pip
273
274
`pip3 install dnspython pyOpenSSL netaddr pycurl`. Then, just run the
script `homer` (or `homer.py`).
275
276

On Debian, if you prefer regular operating system packages to pip,
277
278
`apt install python3 python3-dnspython python3-openssl python3-netaddr
python3-pycurl` will install everything you need.
Stephane Bortzmeyer's avatar
Stephane Bortzmeyer committed
279

Stephane Bortzmeyer's avatar
Stephane Bortzmeyer committed
280
281
### Testing

282
283
284
The tests configured in `tests.yaml` require
https://framagit.org/feth/test_exe_matrix. Then, just `test_exe_matrix
tests.yaml`.
Stephane Bortzmeyer's avatar
Stephane Bortzmeyer committed
285

286
## Public servers
Stephane Bortzmeyer's avatar
Stephane Bortzmeyer committed
287

Stephane Bortzmeyer's avatar
Stephane Bortzmeyer committed
288
289
(Managed by non-profit organisations. I may trim this list in the
future, to remove servers that do not validate with DNSSEC.)
Stephane Bortzmeyer's avatar
Stephane Bortzmeyer committed
290

291
292
### DoH

Stephane Bortzmeyer's avatar
Stephane Bortzmeyer committed
293
* `https://doh.powerdns.org/`
294
* `https://doh.bortzmeyer.fr/` ([Documentation](https://doh.bortzmeyer.fr/about)) 
Stephane Bortzmeyer's avatar
Stephane Bortzmeyer committed
295
* `https://doh.42l.fr/dns-query` ([Documentation](https://42l.fr/DoH-service))
296
* `https://odvr.nic.cz/doh` ([Documentation](https://www.nic.cz/odvr/))
297
* `https://dns.hostux.net/dns-query`
298
  ([Documentation](https://dns.hostux.net/))
299
* `https://ldn-fai.net/dns-query` ([Documentation in french](https://ldn-fai.net/serveur-dns-recursif-ouvert/))
300
* `https://dns.digitale-gesellschaft.ch/dns-query` ([Documentation in german](https://www.digitale-gesellschaft.ch/dns/))
Stephane Bortzmeyer's avatar
Stephane Bortzmeyer committed
301
302
303
304
305
* `https://doh.ffmuc.net`
  ([Documentation](https://ffmuc.net/wiki/doku.php?id=knb:dohdot_en))
* `https://doh.libredns.gr/dns-query`
  ([Documentation](https://libredns.gr/); Also,
  `https://doh.libredns.gr/ads` is a lying resolver, blocking ads and trackers)
306
* `https://dns.switch.ch/dns-query` ([Documentation](https://www.switch.ch/security/info/public-dns/))
Stephane Bortzmeyer's avatar
Stephane Bortzmeyer committed
307
308
309
* `https://nat64.tuxis.nl`
  ([Documentation](https://www.tuxis.nl/blog/public-doh-dot-dns64-nat64-service-20191021/);
  NAT64, and no IPv4 address)
310
311
312
313
314
315
316

### DoT

* `dot.bortzmeyer.fr` ([Documentation](https://doh.bortzmeyer.fr/about)) 
* `dns.digitale-gesellschaft.ch` ([Documentation in german](https://www.digitale-gesellschaft.ch/dns/))
* `dot.ffmuc.net` ([Documentation](https://ffmuc.net/wiki/doku.php?id=knb:dohdot_en)) 
* `ns0.ldn-fai.net` ([Documentation in french](https://ldn-fai.net/serveur-dns-recursif-ouvert/))
Stephane Bortzmeyer's avatar
Stephane Bortzmeyer committed
317
* `dot.libredns.gr` ([Documentation](https://libredns.gr/))
Stephane Bortzmeyer's avatar
Stephane Bortzmeyer committed
318
319
320
321
322
323
* `dns.switch.ch` ([Documentation](https://www.switch.ch/security/info/public-dns/))
* `nat64.tuxis.net`
  ([Documentation](https://www.tuxis.nl/blog/public-doh-dot-dns64-nat64-service-20191021/);
  NAT64, and no IPv4 address)
* `anycast.censurfridns.dk` ([Documentation](https://blog.uncensoreddns.org/))
  
Stephane Bortzmeyer's avatar
Stephane Bortzmeyer committed
324
325
## License 

326
GPL. See LICENSE.
Stephane Bortzmeyer's avatar
Stephane Bortzmeyer committed
327
328
329

## Author

330
Stéphane Bortzmeyer <stephane+framagit@bortzmeyer.org> and Alexandre Pion
Stephane Bortzmeyer's avatar
Stephane Bortzmeyer committed
331

332
## Reference site
Stephane Bortzmeyer's avatar
Stephane Bortzmeyer committed
333

334
335
https://framagit.org/bortzmeyer/homer/ Use the Gitlab issue tracker to
report bugs or wishes.
Stephane Bortzmeyer's avatar
Stephane Bortzmeyer committed
336
337
338
339
340
341
342

## See also

* A [simple DoH client](https://github.com/curl/doh), from the author
  of curl.