Commit 7859e494 authored by Alexandre's avatar Alexandre
Browse files

Merge branch 'master' into pipelining

parents 2f4ade58 63d193fa
......@@ -164,14 +164,13 @@ and [CURLINFO_PRETRANSFER_TIME](https://curl.haxx.se/libcurl/c/curl_easy_getinfo
```
% ./homer.py --multistreams --file input_file --repeat 5 --no-display-results --time https://doh.powerdns.org
0 36.165 ms 44.773 ms 8.608 ms
1 0.142 ms 8.580 ms 8.438 ms
3 0.095 ms 9.223 ms 9.128 ms
2 0.103 ms 10.282 ms 10.179 ms
4 0.104 ms 10.068 ms 9.964 ms
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
Total elapsed time: 0.07 seconds (9.26 ms/request)
OK
Total elapsed time: 0.07 seconds (9.83 ms/request)
```
......
......@@ -106,7 +106,51 @@ def error(msg=None, exit=True):
def usage(msg=None):
if msg:
print(msg,file=sys.stderr)
print("Usage: %s [--dot] url-or-servername domain-name [DNS type]" % sys.argv[0], file=sys.stderr)
print("Usage: %s [options] url-or-servername [domain-name [DNS type]]" % sys.argv[0], file=sys.stderr)
print("""Options
-t --dot Use DoT (by default use DoH)
-P --post --POST Use HTTP POST method for all transfers (DoH only)
-e --head --HEAD Use HTTP HEAD method for all transfers (DoH only)
-r --repeat <N> Perform N times the query. If used with -f, read up to
<N> rows of the <file>.
-d --delay <T> Time to wait in seconds between each synchronous
request (only with --repeat)
-f --file <file> Read domain names from <file>, one per row with an
optional DNS type
--check Perform a set of predefined tests.
--mandatory-level <level>
Define the <level> of test to perform (only with
--check)
Available <level> : legal, necessary, nicetohave
--multistreams Use HTTP/2 streams, needs an input file with -f
(DoH only)
--sync Process received queries synchronously (only with
--multistreams)
--no-display-results
Disable output of DNS response (only with
--multistreams)
--time Display the time elapsed for the query (only with
--multistreams)
--dnssec Request DNSSEC data (signatures)
--noedns Disable EDNS, default is to indicate EDNS support
--ecs Send ECS to authoritative servers, default is to
refuse it
--key <key> Authenticate a DoT resolver with its public <key> in
base64 (DoT only)
--nosni Do not perform SNI (DoT only)
-V --vhost <vhost> Use a specific virtual host
-k --insecure Do not check the certificate
-4 --v4only Force IPv4 resolution of url-or-servername
-6 --v6only Force IPv6 resolution of url-or-servername
-v --verbose Make the program more talkative
--debug Make the program even more talkative than -v
-h --help Print this message
url-or-servername The URL or domain name of the DoT/DoH server
domain-name The domain name to resolve, not required if -f is
provided
DNS type The DNS record type to resolve, default AAAA
""", file=sys.stderr)
print("See the README.md for more details.", file=sys.stderr)
def is_valid_hostname(name):
......@@ -244,6 +288,7 @@ class Request:
use_edns=use_edns, want_dnssec=want_dnssec, options=options)
self.message.flags |= dns.flags.AD # Ask for validation
self.ok = True
self.i = 0 # request's number on the connection (default to the first)
def trunc_data(self):
self.data = self.message.to_wire()
......@@ -677,10 +722,11 @@ class ConnectionDoH(Connection):
self.receive(handle)
handle.request.check_response()
if show_time:
print(f'{handle.request.i:3d}', end=' ')
print(f'{handle.pretime * 1000:8.3f} ms', end=' ')
print(f'{handle.time * 1000:8.3f} ms', end=' ')
print(f'{(handle.time - handle.pretime) * 1000:8.3f} ms')
self.print_time(handle)
try:
self.finished['http'][handle.request.rcode] += 1
except KeyError:
self.finished['http'][handle.request.rcode] = 1
if display_results:
print("Return code %s (%.2f ms):" % (handle.request.rcode,
(handle.time - handle.pretime) * 1000))
......@@ -692,6 +738,13 @@ class ConnectionDoH(Connection):
for handle in self.all_handles:
self.read_result_handle(handle)
def print_time(self, handle):
print(f'{handle.request.i:3d}', end=' ')
print(f'({handle.request.rcode})', end=' ')
print(f'{handle.pretime * 1000:8.3f} ms', end=' ')
print(f'{handle.time * 1000:8.3f} ms', end=' ')
print(f'{(handle.time - handle.pretime) * 1000:8.3f} ms')
def do_test(self, request, synchronous=True):
if synchronous:
handle = self.curl_handle
......@@ -727,6 +780,8 @@ def print_result(connection, request, prefix=None, display_err=True):
size = request.response_size
if (dot and rcode) or (not dot and rcode == 200):
if not monitoring:
if not dot and show_time:
connection.print_time(connection.curl_handle)
if display_results and (not check or verbose):
print(msg)
else:
......@@ -938,9 +993,9 @@ if not monitoring:
try:
optlist, args = getopt.getopt (sys.argv[1:], "hvPkeV:r:f:d:t46",
["help", "verbose", "debug", "dot",
"head", "POST", "insecure", "key=",
"vhost=", "multistreams",
"pipelining", "max-in-flight=",
"head", "HEAD", "post", "POST",
"insecure", "vhost=", "multistreams",
"pipelining", "max-in-flight=", "key=",
"dnssec", "noedns", "ecs", "nosni",
"sync", "no-display-results", "time",
"file=", "repeat=", "delay=",
......@@ -1017,9 +1072,11 @@ if not monitoring:
mandatory_level = value
else:
error("Unknown option %s" % option)
except getopt.error as reason:
except (getopt.error, ValueError) as reason:
usage(reason)
sys.exit(1)
if delay is not None and multistreams:
error("--delay makes no sense with multistreams")
if tests <= 1 and delay is not None:
error("--delay makes no sense if there is no repetition")
if not dot and pipelining:
......@@ -1046,8 +1103,8 @@ if not monitoring:
if sync and not multistreams:
usage("--sync cannot be used without --multistreams")
sys.exit(1)
if show_time and not multistreams:
usage("--time cannot be used without --multistreams")
if show_time and dot:
usage("--time cannot be used with --dot")
sys.exit(1)
if not edns and not no_ecs:
usage("ECS requires EDNS")
......@@ -1124,9 +1181,6 @@ else: # Monitoring plugin
if dot and (post or head):
print("POST or HEAD makes no sense for DoT")
sys.exit(STATE_UNKNOWN)
if dot and multistreams:
print("Multi-streams makes no sense for DoT")
sys.exit(STATE_UNKNOWN)
if dot and path:
print("URL path makes no sense for DoT")
sys.exit(STATE_UNKNOWN)
......@@ -1208,6 +1262,8 @@ for connectTo in ip_set:
if ifile is not None:
input = open(ifile)
if not check:
if multistreams:
conn.finished = { 'http': {} }
for i in range (0, tests):
if tests > 1 and (verbose or display_results):
print("\nTest %i" % i)
......@@ -1281,18 +1337,17 @@ for connectTo in ip_set:
else:
time_per_request = time_tot / tests * 1000
print("\nTotal elapsed time: %.2f seconds (%.2f ms/request%s)" % (time_tot, time_per_request, extra))
if multistreams and verbose:
for rcode, n in conn.finished['http'].items():
print('HTTP', rcode, ':', n, f'({n / tests * 100:0.2f}%)')
if ifile is not None:
input.close()
conn.end()
if ok:
print('OK')
if not monitoring:
sys.exit(0)
else:
sys.exit(STATE_OK)
if check:
print('OK')
sys.exit(0)
else:
print('KO')
if not monitoring:
sys.exit(1)
else:
sys.exit(STATE_CRITICAL)
sys.exit(1)
......@@ -19,14 +19,14 @@ tests:
args:
- '-h'
retcode: 0
partstderr: 'url-or-servername domain-name [DNS type]'
partstderr: 'url-or-servername [domain-name [DNS type]]'
stdout: ''
- exe: './homer.py'
args:
- '--zzz'
retcode: 1
partstderr: 'option --zzz not recognized'
partstderr: 'url-or-servername [domain-name [DNS type]]'
stdout: ''
- exe: './homer.py'
......@@ -132,7 +132,7 @@ tests:
- 'check'
- 'fail'
- 'slow'
timeout: 10
timeout: 12
args:
- '--check'
- 'https://doh.42l.fr/dns-query'
......@@ -991,7 +991,19 @@ tests:
stdout: ''
- exe: './homer.py'
name: '[doh] POST'
name: '[doh] POST --post'
markers:
- 'doh'
args:
- '--post'
- 'https://doh.bortzmeyer.fr'
- 'framagit.org'
retcode: 0
stderr: ''
partstdout: '2a01:4f8:'
- exe: './homer.py'
name: '[doh] POST --POST'
markers:
- 'doh'
args:
......@@ -1003,7 +1015,19 @@ tests:
partstdout: '2a01:4f8:'
- exe: './homer.py'
name: '[doh] HEAD'
name: '[doh] POST -P'
markers:
- 'doh'
args:
- '-P'
- 'https://doh.bortzmeyer.fr'
- 'framagit.org'
retcode: 0
stderr: ''
partstdout: '2a01:4f8:'
- exe: './homer.py'
name: '[doh] HEAD --head'
markers:
- 'doh'
args:
......@@ -1014,6 +1038,30 @@ tests:
stderr: ''
partstdout: 'HEAD'
- exe: './homer.py'
name: '[doh] HEAD --HEAD'
markers:
- 'doh'
args:
- '--HEAD'
- 'https://doh.bortzmeyer.fr'
- 'framagit.org'
retcode: 0
stderr: ''
partstdout: 'HEAD'
- exe: './homer.py'
name: '[doh] HEAD -e'
markers:
- 'doh'
args:
- '-e'
- 'https://doh.bortzmeyer.fr'
- 'framagit.org'
retcode: 0
stderr: ''
partstdout: 'HEAD'
- exe : './homer.py'
name: '[doh] Multistreams with DoT (error)'
markers:
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment