Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
Menu
Open sidebar
DNS testing tools
Remoh
Commits
b0cec718
Commit
b0cec718
authored
Jan 04, 2021
by
Alexandre
Browse files
Merge branch 'rename-to-remoh'
Rename to Remoh Closes #32
parents
0fe78e14
3d36b50a
Changes
11
Hide whitespace changes
Inline
Side-by-side
LICENSE
View file @
b0cec718
...
...
@@ -290,7 +290,7 @@ to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
Homer
Remoh
Copyright (C) 2019 Stéphane Bortzmeyer and Alexandre Pion (AFNIC)
This program is free software; you can redistribute it and/or modify
...
...
README.md
View file @
b0cec718
#
Homer
#
Remoh
Homer is a DoH (DNS-over-HTTPS) and DoT (DNS-over-TLS) client.
Its
main purpose is to test DoH and DoT resolvers.
Remoh (formerly
Homer
)
is a DoH (DNS-over-HTTPS) and DoT (DNS-over-TLS) client.
Its
main purpose is to test DoH and DoT resolvers.
With the proliferation of public DoH and DoT resolvers, and the implementation
of clients inside OS or applications such as web browsers, we wanted to have an
easy to use command line client to make DoT and DoH queries.
Homer
also aims to
easy to use command line client to make DoT and DoH queries.
Remoh
also aims to
assess if a DoT or DoH resolver is compliant with the RFCs (
[
RFC 7858
](
https://www.rfc-editor.org/rfc/rfc7858
)
for DoT and
[
RFC 8484
](
https://www.rfc-editor.org/rfc/rfc8484
)
for DoH).
Homer
is a Python3 script using the
[
dnspython
](
http://www.dnspython.org/
)
Remoh
is a Python3 script using the
[
dnspython
](
http://www.dnspython.org/
)
library to generate and parse DNS messages,
[
netaddr
](
https://github.com/netaddr/netaddr
)
to manipulate IP addresses,
[
PycURL
](
http://pycurl.io/
)
to perform the HTTPs
transfers in DoH and
[
pyOpenSSL
](
https://www.pyopenssl.org/en/stable/
)
to
...
...
@@ -35,13 +35,13 @@ establish TLS session in DoT.
## Usage
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
the DoT resolver), and a domain name to query. By default,
Remoh
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.
```
%
homer
https://doh.powerdns.org/ framagit.org
%
remoh
https://doh.powerdns.org/ framagit.org
id 0
opcode QUERY
rcode NOERROR
...
...
@@ -54,7 +54,7 @@ framagit.org. 10800 IN AAAA 2a01:4f8:200:1302::42
;ADDITIONAL
Total elapsed time: 0.40 seconds (402.28 ms/request)
%
homer
--dot 9.9.9.9 cocca.fr A
%
remoh
--dot 9.9.9.9 cocca.fr A
id 42545
opcode QUERY
rcode NOERROR
...
...
@@ -69,9 +69,9 @@ cocca.fr. 43200 IN A 185.17.236.69
Total elapsed time: 0.07 seconds (66.72 ms/request )
```
When using DoT,
Homer
first resolves the domain name of the resolver into a
When using DoT,
Remoh
first resolves the domain name of the resolver into a
list of IPv4 and IPv6 addresses (or only one subset when using
`-4`
or
`-6`
)
and will loop on each of them until a response is received. Hence if
Homer
gets
and will loop on each of them until a response is received. Hence if
Remoh
gets
an answer, this mean that at least one DoT resolver is up and running. To check
all the IPs, use
`--check`
.
...
...
@@ -128,7 +128,7 @@ 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
%
remoh
--repeat 3 https://doh.bortzmeyer.fr ça.fr SOA
Test 0
...
Test 1
...
...
@@ -138,11 +138,11 @@ 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
Remoh
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
`-f FILE`
, where
Homer
reads the domain names (and types) to query. Here is a sample
Remoh
reads the domain names (and types) to query. Here is a sample
file:
```
...
...
@@ -157,7 +157,7 @@ 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
%
remoh
--repeat 4 --file list.txt https://doh.42l.fr/dns-query
```
When repeating tests, you can add a delay between tests, with
`--delay
...
...
@@ -171,20 +171,20 @@ connection. This can be used to test the compliance of the servers with the
RFCs. DoT is standardized in
[
RFC 7858
](
https://www.rfc-editor.org/rfc/rfc7858
)
and DoH in
[
RFC 8484
](
https://www.rfc-editor.org/rfc/rfc8484
)
.
If all the tests passed,
Homer
displays
`OK`
. Otherwise if at least
on test failed,
Homer
outputs
`KO`
. When a test fails, an error message
If all the tests passed,
Remoh
displays
`OK`
. Otherwise if at least
on test failed,
Remoh
outputs
`KO`
. When a test fails, an error message
is displayed.
```
%
homer
--check https://doh.bortzmeyer.fr framagit.org
%
remoh
--check https://doh.bortzmeyer.fr framagit.org
OK
%
homer
--dot --check dnsotls.lab.nic.cl wikipedia.org
%
remoh
--dot --check dnsotls.lab.nic.cl wikipedia.org
Could not connect to "dnsotls.lab.nic.cl" on 200.1.123.46
KO
```
When used with an URL for DoH or a domain name for DoT,
Homer
loops
When used with an URL for DoH or a domain name for DoT,
Remoh
loops
on all the resolved IPs. All the tests are then run for each connection.
Each test is marked with a level of compliance. There are three
...
...
@@ -216,7 +216,7 @@ the choosen level is lower than the level of the test.
### Multistreams
When using
Homer
with DoH, the option
`--multistreams`
can be used
When using
Remoh
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.
...
...
@@ -227,12 +227,12 @@ the file.
For example :
```
%
homer
--multistreams --file input_file --repeat 5 https://doh.powerdns.org
%
remoh
--multistreams --file input_file --repeat 5 https://doh.powerdns.org
...
Total elapsed time: 0.11 seconds (22.60 ms/request)
```
When dealing with multistreams,
Homer
relies on the multi interface
When dealing with multistreams,
Remoh
relies on the multi interface
from PycURL (and libcurl). By default all the queries are attached to
the multi object before performing the transfers. For a better use of
the multi interface, see the branch
[
homer-perf
](
-/tree/homer-perf
)
.
...
...
@@ -263,27 +263,27 @@ the root NS.
It is possible to pipeline multiple DoT queries with the option
`--pipelining`
.
The queries are created based on the provided input file. Up to
`N`
lines are
read from the file, with
`N`
defined by the option
`--repeat N`
. By default
Homer
sends up to 20 requests in parallel before listening for responses.
Remoh
sends up to 20 requests in parallel before listening for responses.
This value can be changed with
`--max-in-flight`
.
After sending the first query,
Homer
is configured to stop after 10 seconds
After sending the first query,
Remoh
is configured to stop after 10 seconds
has elapsed. This mean that if more queries need to be sent or received 10
seconds after the beginning of the first transfer, they will all be dropped.
To increase this value, update the variable
`MAX_DURATION`
.
Homer
will display all the DNS response as they arrive. To suppress
Remoh
will display all the DNS response as they arrive. To suppress
this output, use
`--no-display-results`
.
If not all the queries got a response in
`MAX_DURATION`
seconds,
Homer
If not all the queries got a response in
`MAX_DURATION`
seconds,
Remoh
outputs
`KO`
instead of
`OK`
.
```
%
homer
--dot --pipelining -f input_file -r 5 dns.switch.ch
%
remoh
--dot --pipelining -f input_file -r 5 dns.switch.ch
...
Total elapsed time: 0.56 seconds (111.67 ms/request)
OK
%
homer
--dot --pipelining -f huge_file -r 1000 127.0.0.1
%
remoh
--dot --pipelining -f huge_file -r 1000 127.0.0.1
...
Elapsed time too long, 42 requests never got a reply
Total elapsed time: 10.29 seconds (10.29 ms/request)
...
...
@@ -292,7 +292,7 @@ KO
### A note on the SNI
By default,
Homer
sends a SNI when establishing the TLS session with DoT. The
By default,
Remoh
sends a SNI when establishing the TLS session with DoT. The
SNI value is extracted from the name or address of the DoT resolver. If a
literal IP address is used, the SNI will then be set with the IP address.
...
...
@@ -396,7 +396,7 @@ You need Python 3, [DNSpython](http://www.dnspython.org/),
[
netaddr
](
https://github.com/drkjam/netaddr/
)
and
[
PycURL
](
http://pycurl.io/docs/latest
)
. You can install them with pip
`pip3 install dnspython pyOpenSSL netaddr pycurl`
. Then, just run the
script
`
homer
`
(or
`
homer
.py`
).
script
`
remoh
`
(or
`
remoh
.py`
).
On Debian, if you prefer regular operating system packages to pip,
`apt install python3 python3-dnspython python3-openssl python3-netaddr
...
...
check-servers.sh
View file @
b0cec718
...
...
@@ -12,13 +12,13 @@ echo "DoT"
for
server
in
$(
cat
dot-servers.txt
)
;
do
echo
""
echo
$server
./
homer
.py
--check
--dot
$server
$domain
$type
./
remoh
.py
--check
--dot
$server
$domain
$type
done
echo
""
echo
"DoH"
for
url
in
$(
cat
doh-servers.txt
)
;
do
echo
""
echo
$url
./
homer
.py
--check
$url
$domain
$type
./
remoh
.py
--check
$url
$domain
$type
done
monitoring.py
View file @
b0cec718
#!/usr/bin/env python3
#
Homer
is a DoH (DNS-over-HTTPS) and DoT (DNS-over-TLS) client. Its
#
Remoh
is a DoH (DNS-over-HTTPS) and DoT (DNS-over-TLS) client. Its
# main purpose is to test DoH and DoT resolvers. Reference site is
# <https://framagit.org/bortzmeyer/homer/> See author, documentation,
# etc, there, or in the README.md included with the distribution.
...
...
@@ -22,7 +22,7 @@ except ImportError as e:
print
(
e
)
sys
.
exit
(
1
)
import
homer
import
remoh
# Values that can be changed from the command line
# "H:n:p:V:t:e:Pih46k:x"
...
...
@@ -170,10 +170,10 @@ def parse_opts_monitoring(me, opts):
def
run_default
(
name
,
connection
,
opts
):
if
connection
.
dot
:
request
=
homer
.
RequestDOT
(
name
,
qtype
=
opts
.
rtype
,
use_edns
=
opts
.
edns
,
request
=
remoh
.
RequestDOT
(
name
,
qtype
=
opts
.
rtype
,
use_edns
=
opts
.
edns
,
want_dnssec
=
opts
.
dnssec
,
no_ecs
=
opts
.
no_ecs
)
else
:
request
=
homer
.
RequestDOH
(
name
,
qtype
=
opts
.
rtype
,
use_edns
=
opts
.
edns
,
request
=
remoh
.
RequestDOH
(
name
,
qtype
=
opts
.
rtype
,
use_edns
=
opts
.
edns
,
want_dnssec
=
opts
.
dnssec
,
no_ecs
=
opts
.
no_ecs
)
request
.
to_wire
()
...
...
@@ -184,7 +184,7 @@ def run_default(name, connection, opts):
try
:
connection
.
do_test
(
request
)
except
(
OpenSSL
.
SSL
.
Error
,
homer
.
DOHException
)
as
e
:
except
(
OpenSSL
.
SSL
.
Error
,
remoh
.
DOHException
)
as
e
:
error
(
e
)
return
False
...
...
@@ -202,7 +202,7 @@ if __name__ == '__main__':
# The provided host is indeed a valid IP
# TODO catch ValueError exception if the host is an url as in :
# ./check_doh -H https://doh.bortzmeyer.fr -n afnic.fr
if
homer
.
is_valid_ip_address
(
opts
.
host
)[
0
]:
if
remoh
.
is_valid_ip_address
(
opts
.
host
)[
0
]:
opts
.
connectTo
=
opts
.
host
ok
=
True
...
...
@@ -212,12 +212,12 @@ if __name__ == '__main__':
extracheck
=
None
try
:
if
opts
.
dot
:
conn
=
homer
.
ConnectionDOT
(
url
,
servername
=
extracheck
,
connect_to
=
opts
.
connectTo
,
conn
=
remoh
.
ConnectionDOT
(
url
,
servername
=
extracheck
,
connect_to
=
opts
.
connectTo
,
forceIPv4
=
opts
.
forceIPv4
,
forceIPv6
=
opts
.
forceIPv6
,
insecure
=
opts
.
insecure
,
sni
=
opts
.
sni
,
key
=
opts
.
key
)
else
:
conn
=
homer
.
ConnectionDOH
(
url
,
servername
=
extracheck
,
connect_to
=
opts
.
connectTo
,
conn
=
remoh
.
ConnectionDOH
(
url
,
servername
=
extracheck
,
connect_to
=
opts
.
connectTo
,
forceIPv4
=
opts
.
forceIPv4
,
forceIPv6
=
opts
.
forceIPv6
,
insecure
=
opts
.
insecure
)
except
TimeoutError
:
...
...
@@ -228,7 +228,7 @@ if __name__ == '__main__':
error
(
"
\"
%s
\"
not a name or an IP address"
%
url
)
except
socket
.
gaierror
:
error
(
"Could not resolve
\"
%s
\"
"
%
url
)
except
(
homer
.
ConnectionException
,
homer
.
DOHException
)
as
e
:
except
(
remoh
.
ConnectionException
,
remoh
.
DOHException
)
as
e
:
error
(
e
)
if
conn
.
dot
and
not
conn
.
success
:
ok
=
False
...
...
homer
.py
→
remoh
.py
View file @
b0cec718
#!/usr/bin/env python3
#
Homer
is a DoH (DNS-over-HTTPS) and DoT (DNS-over-TLS) client. Its
#
Remoh
is a DoH (DNS-over-HTTPS) and DoT (DNS-over-TLS) client. Its
# main purpose is to test DoH and DoT resolvers. Reference site is
# <https://framagit.org/bortzmeyer/homer/> See author, documentation,
# etc, there, or in the README.md included with the distribution.
...
...
@@ -24,7 +24,7 @@ except ImportError as e:
print
(
e
)
sys
.
exit
(
1
)
import
homer
import
remoh
# Values that can be changed from the command line
class
opts
:
...
...
@@ -171,13 +171,13 @@ def check_dot_two_requests(connection, opts):
if
not
connection
.
dot
:
return
True
r1
=
homer
.
RequestDOT
(
'framagit.org'
,
qtype
=
opts
.
rtype
,
use_edns
=
opts
.
edns
,
want_dnssec
=
opts
.
dnssec
,
no_ecs
=
opts
.
no_ecs
)
r2
=
homer
.
RequestDOT
(
'afnic.fr'
,
qtype
=
opts
.
rtype
,
use_edns
=
opts
.
edns
,
want_dnssec
=
opts
.
dnssec
,
no_ecs
=
opts
.
no_ecs
)
r1
=
remoh
.
RequestDOT
(
'framagit.org'
,
qtype
=
opts
.
rtype
,
use_edns
=
opts
.
edns
,
want_dnssec
=
opts
.
dnssec
,
no_ecs
=
opts
.
no_ecs
)
r2
=
remoh
.
RequestDOT
(
'afnic.fr'
,
qtype
=
opts
.
rtype
,
use_edns
=
opts
.
edns
,
want_dnssec
=
opts
.
dnssec
,
no_ecs
=
opts
.
no_ecs
)
requests
=
[]
requests
.
append
((
'Test 1'
,
r1
,
homer
.
mandatory_levels
[
"legal"
]))
requests
.
append
((
'Test 1'
,
r1
,
remoh
.
mandatory_levels
[
"legal"
]))
# RFC 7858 section 3.3, SHOULD accept several requests on one connection.
requests
.
append
((
'Test 2'
,
r2
,
homer
.
mandatory_levels
[
"necessary"
]))
requests
.
append
((
'Test 2'
,
r2
,
remoh
.
mandatory_levels
[
"necessary"
]))
return
do_check
(
connection
,
requests
,
opts
)
...
...
@@ -186,21 +186,21 @@ def check_doh_methods(connection, opts):
if
connection
.
dot
:
return
True
r1
=
homer
.
RequestDOH
(
'framagit.org'
,
qtype
=
opts
.
rtype
,
use_edns
=
opts
.
edns
,
want_dnssec
=
opts
.
dnssec
,
no_ecs
=
opts
.
no_ecs
)
r2
=
homer
.
RequestDOH
(
'afnic.fr'
,
qtype
=
opts
.
rtype
,
use_edns
=
opts
.
edns
,
want_dnssec
=
opts
.
dnssec
,
no_ecs
=
opts
.
no_ecs
)
r1
=
remoh
.
RequestDOH
(
'framagit.org'
,
qtype
=
opts
.
rtype
,
use_edns
=
opts
.
edns
,
want_dnssec
=
opts
.
dnssec
,
no_ecs
=
opts
.
no_ecs
)
r2
=
remoh
.
RequestDOH
(
'afnic.fr'
,
qtype
=
opts
.
rtype
,
use_edns
=
opts
.
edns
,
want_dnssec
=
opts
.
dnssec
,
no_ecs
=
opts
.
no_ecs
)
r2
.
post
=
True
r3
=
homer
.
RequestDOH
(
'www.rfc-editor.org'
,
qtype
=
opts
.
rtype
,
use_edns
=
opts
.
edns
,
want_dnssec
=
opts
.
dnssec
,
no_ecs
=
opts
.
no_ecs
)
r3
=
remoh
.
RequestDOH
(
'www.rfc-editor.org'
,
qtype
=
opts
.
rtype
,
use_edns
=
opts
.
edns
,
want_dnssec
=
opts
.
dnssec
,
no_ecs
=
opts
.
no_ecs
)
r3
.
head
=
True
requests
=
[]
requests
.
append
((
'Test GET'
,
r1
,
homer
.
mandatory_levels
[
"legal"
]))
# RFC 8484, section 4.1
requests
.
append
((
'Test POST'
,
r2
,
homer
.
mandatory_levels
[
"legal"
]))
# RFC 8484, section 4.1
requests
.
append
((
'Test GET'
,
r1
,
remoh
.
mandatory_levels
[
"legal"
]))
# RFC 8484, section 4.1
requests
.
append
((
'Test POST'
,
r2
,
remoh
.
mandatory_levels
[
"legal"
]))
# RFC 8484, section 4.1
# HEAD method is not mentioned in RFC 8484 (see section 4.1), so just "nice to have".
requests
.
append
((
'Test HEAD'
,
r3
,
homer
.
mandatory_levels
[
"nicetohave"
]))
requests
.
append
((
'Test HEAD'
,
r3
,
remoh
.
mandatory_levels
[
"nicetohave"
]))
return
do_check
(
connection
,
requests
,
opts
)
def
check_doh_header
(
connection
,
opts
,
level
=
homer
.
mandatory_levels
[
"nicetohave"
],
def
check_doh_header
(
connection
,
opts
,
level
=
remoh
.
mandatory_levels
[
"nicetohave"
],
accept
=
"application/dns-message"
,
content_type
=
"application/dns-message"
):
# change the MIME value and see what happens
# based on the RFC only application/dns-message must be supported, any
...
...
@@ -212,7 +212,7 @@ def check_doh_header(connection, opts, level=homer.mandatory_levels["nicetohave"
header
=
[
"Accept: %s"
%
accept
,
"Content-type: %s"
%
content_type
]
test_name
=
"Test Header MIME: %s "
%
", "
.
join
(
h
for
h
in
header
)
r1
=
homer
.
RequestDOH
(
'curl.haxx.se'
,
qtype
=
opts
.
rtype
,
use_edns
=
opts
.
edns
,
want_dnssec
=
opts
.
dnssec
,
no_ecs
=
opts
.
no_ecs
)
r1
=
remoh
.
RequestDOH
(
'curl.haxx.se'
,
qtype
=
opts
.
rtype
,
use_edns
=
opts
.
edns
,
want_dnssec
=
opts
.
dnssec
,
no_ecs
=
opts
.
no_ecs
)
r1
.
post
=
True
requests
=
[]
...
...
@@ -252,7 +252,7 @@ def do_check(connection, requests, opts):
try
:
connection
.
send_and_receive
(
bundle
)
except
(
homer
.
ConnectionException
,
homer
.
DOHException
)
as
e
:
except
(
remoh
.
ConnectionException
,
remoh
.
DOHException
)
as
e
:
ok
=
False
print_check_result
(
test_name
,
ok
,
verbose
=
connection
.
verbose
)
print
(
e
,
file
=
sys
.
stderr
)
...
...
@@ -266,7 +266,7 @@ def do_check(connection, requests, opts):
break
return
ok
def
check_truncated_query
(
connection
,
opts
,
level
=
homer
.
mandatory_levels
[
"nicetohave"
]):
def
check_truncated_query
(
connection
,
opts
,
level
=
remoh
.
mandatory_levels
[
"nicetohave"
]):
# send truncated DNS request to the server and expect a HTTP return code
# either equal to 200 or in the 400 range
# in case the server answers with 200, look for a FORMERR error in the DNS
...
...
@@ -281,9 +281,9 @@ def check_truncated_query(connection, opts, level=homer.mandatory_levels["niceto
test_name
=
'Test truncated data'
if
connection
.
dot
:
request
=
homer
.
RequestDOT
(
'example.com'
,
qtype
=
opts
.
rtype
,
use_edns
=
opts
.
edns
,
want_dnssec
=
opts
.
dnssec
,
no_ecs
=
opts
.
no_ecs
)
request
=
remoh
.
RequestDOT
(
'example.com'
,
qtype
=
opts
.
rtype
,
use_edns
=
opts
.
edns
,
want_dnssec
=
opts
.
dnssec
,
no_ecs
=
opts
.
no_ecs
)
else
:
request
=
homer
.
RequestDOH
(
'example.com'
,
qtype
=
opts
.
rtype
,
use_edns
=
opts
.
edns
,
want_dnssec
=
opts
.
dnssec
,
no_ecs
=
opts
.
no_ecs
)
request
=
remoh
.
RequestDOH
(
'example.com'
,
qtype
=
opts
.
rtype
,
use_edns
=
opts
.
edns
,
want_dnssec
=
opts
.
dnssec
,
no_ecs
=
opts
.
no_ecs
)
request
.
post
=
True
request
.
trunc_data
()
...
...
@@ -307,7 +307,7 @@ def check_truncated_query(connection, opts, level=homer.mandatory_levels["niceto
# the RCODE set to FORMERR
# so response can not be parsed in this case
return
True
except
homer
.
DOHException
as
e
:
except
remoh
.
DOHException
as
e
:
print
(
e
,
file
=
sys
.
stderr
)
return
False
...
...
@@ -337,7 +337,7 @@ def run_check(connection):
ok
=
check_dot_two_requests
(
connection
,
opts
)
else
:
ok
=
check_doh_methods
(
connection
,
opts
)
if
not
ok
and
opts
.
mandatory_level
>=
homer
.
mandatory_levels
[
"nicetohave"
]:
if
not
ok
and
opts
.
mandatory_level
>=
remoh
.
mandatory_levels
[
"nicetohave"
]:
return
False
# TODO we miss the tests of pipelining and out-of-order for DoT and
...
...
@@ -348,11 +348,11 @@ def run_check(connection):
# The DoH server is right to reject these (Example: 'HTTP
# error 415: only Content-Type: application/dns-message is
# supported')
ok
=
check_doh_header
(
connection
,
opts
,
level
=
homer
.
mandatory_levels
[
"nocrash"
],
accept
=
"text/html"
)
and
ok
ok
=
check_doh_header
(
connection
,
opts
,
level
=
homer
.
mandatory_levels
[
"nocrash"
],
content_type
=
"text/html"
)
and
ok
ok
=
check_doh_header
(
connection
,
opts
,
level
=
remoh
.
mandatory_levels
[
"nocrash"
],
accept
=
"text/html"
)
and
ok
ok
=
check_doh_header
(
connection
,
opts
,
level
=
remoh
.
mandatory_levels
[
"nocrash"
],
content_type
=
"text/html"
)
and
ok
# test if a truncated query breaks anything
ok
=
check_truncated_query
(
connection
,
opts
,
level
=
homer
.
mandatory_levels
[
"nocrash"
])
and
ok
ok
=
check_truncated_query
(
connection
,
opts
,
level
=
remoh
.
mandatory_levels
[
"nocrash"
])
and
ok
return
ok
...
...
@@ -472,13 +472,13 @@ def parse_opts(opts):
if
not
opts
.
edns
and
not
opts
.
no_ecs
:
error_and_exit
(
"ECS requires EDNS"
)
if
opts
.
mandatory_level
is
not
None
and
\
opts
.
mandatory_level
not
in
homer
.
mandatory_levels
.
keys
():
opts
.
mandatory_level
not
in
remoh
.
mandatory_levels
.
keys
():
error_and_exit
(
"Unknown mandatory level
\"
%s
\"
"
%
opts
.
mandatory_level
)
if
opts
.
mandatory_level
is
not
None
and
not
opts
.
check
:
error_and_exit
(
"--mandatory-level only makes sense with --check"
)
if
opts
.
mandatory_level
is
None
:
opts
.
mandatory_level
=
"necessary"
opts
.
mandatory_level
=
homer
.
mandatory_levels
[
opts
.
mandatory_level
]
opts
.
mandatory_level
=
remoh
.
mandatory_levels
[
opts
.
mandatory_level
]
if
opts
.
ifile
is
None
and
(
len
(
args
)
!=
2
and
len
(
args
)
!=
3
):
error_and_exit
(
"Wrong number of arguments"
)
if
opts
.
ifile
is
not
None
and
len
(
args
)
!=
1
:
...
...
@@ -508,10 +508,10 @@ def run_default(name, connection, opts):
name
,
opts
.
rtype
=
get_next_domain
(
input
)
if
connection
.
dot
:
request
=
homer
.
RequestDOT
(
name
,
qtype
=
opts
.
rtype
,
use_edns
=
opts
.
edns
,
request
=
remoh
.
RequestDOT
(
name
,
qtype
=
opts
.
rtype
,
use_edns
=
opts
.
edns
,
want_dnssec
=
opts
.
dnssec
,
no_ecs
=
opts
.
no_ecs
)
else
:
request
=
homer
.
RequestDOH
(
name
,
qtype
=
opts
.
rtype
,
use_edns
=
opts
.
edns
,
request
=
remoh
.
RequestDOH
(
name
,
qtype
=
opts
.
rtype
,
use_edns
=
opts
.
edns
,
want_dnssec
=
opts
.
dnssec
,
no_ecs
=
opts
.
no_ecs
)
request
.
to_wire
()
...
...
@@ -528,7 +528,7 @@ def run_default(name, connection, opts):
else
:
try
:
connection
.
do_test
(
request
)
# perform the query
except
(
OpenSSL
.
SSL
.
Error
,
homer
.
ConnectionDOTException
,
homer
.
DOHException
)
as
e
:
except
(
OpenSSL
.
SSL
.
Error
,
remoh
.
ConnectionDOTException
,
remoh
.
DOHException
)
as
e
:
ok
=
False
error
(
e
)
break
...
...
@@ -545,12 +545,12 @@ def run_default(name, connection, opts):
done
=
0
try
:
current
=
connection
.
pipelining_init_pending
(
opts
.
max_in_flight
)
except
homer
.
ConnectionDOTException
as
e
:
except
remoh
.
ConnectionDOTException
as
e
:
ok
=
False
error
(
"%s, %i/%i requests never got a reply"
%
(
e
,
opts
.
tests
-
connection
.
nbr_finished_queries
,
opts
.
tests
))
else
:
while
done
<
opts
.
tests
:
if
time
.
time
()
>
start
+
homer
.
MAX_DURATION
:
# if we send thousands of requests
if
time
.
time
()
>
start
+
remoh
.
MAX_DURATION
:
# if we send thousands of requests
# MAX_DURATION will be reached
# need to increase MAX_DURATION based
# on the number of queries
...
...
@@ -561,7 +561,7 @@ def run_default(name, connection, opts):
break
id
=
connection
.
read_result
(
connection
,
connection
.
pending
,
display_results
=
opts
.
display_results
)
if
id
is
None
:
# Probably a timeout
time
.
sleep
(
homer
.
SLEEP_TIMEOUT
)
time
.
sleep
(
remoh
.
SLEEP_TIMEOUT
)
continue
done
+=
1
over
,
rank
,
request
=
connection
.
pending
[
id
]
...
...
@@ -570,7 +570,7 @@ def run_default(name, connection, opts):
if
current
<
len
(
connection
.
all_requests
):
try
:
connection
.
pipelining_fill_pending
(
current
)
except
homer
.
ConnectionDOTException
as
e
:
except
remoh
.
ConnectionDOTException
as
e
:
ok
=
False
error
(
"%s, %i/%i requests never got a reply"
%
(
e
,
opts
.
tests
-
connection
.
nbr_finished_queries
,
opts
.
tests
))
break
...
...
@@ -607,13 +607,13 @@ if not opts.check or opts.connectTo is not None:
ip_set
=
{
opts
.
connectTo
,
}
else
:
if
opts
.
dot
:
port
=
homer
.
PORT_DOT
if
not
homer
.
is_valid_hostname
(
url
):
port
=
remoh
.
PORT_DOT
if
not
remoh
.
is_valid_hostname
(
url
):
error_and_exit
(
"DoT requires a host name or IP address, not
\"
%s
\"
"
%
url
)
netloc
=
url
else
:
port
=
homer
.
PORT_DOH
if
not
homer
.
is_valid_url
(
url
):
port
=
remoh
.
PORT_DOH
if
not
remoh
.
is_valid_url
(
url
):
error_and_exit
(
"DoH requires a valid HTTPS URL, not
\"
%s
\"
"
%
url
)
try
:
url_parts
=
urllib
.
parse
.
urlparse
(
url
)
# A very poor validation, many
...
...
@@ -647,12 +647,12 @@ for ip in ip_set:
print
(
"(%d/%d) checking IP : %s"
%
(
i
,
len
(
ip_set
),
ip
))
try
:
if
opts
.
dot
:
conn
=
homer
.
ConnectionDOT
(
url
,
servername
=
extracheck
,
connect_to
=
ip
,
conn
=
remoh
.
ConnectionDOT
(
url
,
servername
=
extracheck
,
connect_to
=
ip
,
forceIPv4
=
opts
.
forceIPv4
,
forceIPv6
=
opts
.
forceIPv6
,
insecure
=
opts
.
insecure
,
verbose
=
opts
.
verbose
,
debug
=
opts
.
debug
,
sni
=
opts
.
sni
,
key
=
opts
.
key
,
pipelining
=
opts
.
pipelining
)
else
:
conn
=
homer
.
ConnectionDOH
(
url
,
servername
=
extracheck
,
connect_to
=
ip
,
conn
=
remoh
.
ConnectionDOH
(
url
,
servername
=
extracheck
,
connect_to
=
ip
,
forceIPv4
=
opts
.
forceIPv4
,
forceIPv6
=
opts
.
forceIPv6
,
insecure
=
opts
.
insecure
,
verbose
=
opts
.
verbose
,
debug
=
opts
.
debug
,
multistreams
=
opts
.
multistreams
)
...
...
@@ -672,7 +672,7 @@ for ip in ip_set:
error
(
"Could not resolve
\"
%s
\"
"
%
url
)
ok
=
False
continue
except
homer
.
ConnectionDOTException
as
e
:
except
remoh
.
ConnectionDOTException
as
e
:
print
(
e
,
file
=
sys
.
stderr
)
err
=
"Could not connect to
\"
%s
\"
"
%
url
if
opts
.
connectTo
is
not
None
:
...
...
@@ -682,7 +682,7 @@ for ip in ip_set:
error
(
err
)
ok
=
False
continue
except
(
homer
.
ConnectionException
,
homer
.
DOHException
)
as
e
:
except
(
remoh
.
ConnectionException
,
remoh
.
DOHException
)
as
e
:
error
(
e
)
ok
=
False
continue
...
...
homer
/__init__.py
→
remoh
/__init__.py
View file @
b0cec718
File moved
homer
/connection.py
→
remoh
/connection.py
View file @
b0cec718
...
...
@@ -21,8 +21,8 @@ except ImportError as e:
print
(
e
)
sys
.
exit
(
1
)
import
homer
.utils
import
homer
.exceptions
import
remoh
.utils
import
remoh
.exceptions
class
Connection
:
...
...
@@ -30,14 +30,14 @@ class Connection:
forceIPv4
=
False
,
forceIPv6
=
False
,
insecure
=
False
,
verbose
=
False
,
debug
=
False
,
dot
=
False
):
if
dot
and
not
homer
.
is_valid_hostname
(
server
):
raise
homer
.
ConnectionDOTException
(
"DoT requires a host name or IP address, not
\"
%s
\"
"
%
server
)
if
dot
and
not
remoh
.
is_valid_hostname
(
server
):
raise
remoh
.
ConnectionDOTException
(
"DoT requires a host name or IP address, not
\"
%s
\"
"
%
server
)
if
not
dot
and
not
homer
.
is_valid_url
(
server
):
raise
homer
.
ConnectionDOHException
(
"DoH requires a valid HTTPS URL, not
\"
%s
\"
"
%
server
)
if
not
dot
and
not
remoh
.
is_valid_url
(
server
):
raise
remoh
.
ConnectionDOHException
(
"DoH requires a valid HTTPS URL, not
\"
%s
\"
"
%
server
)
if
forceIPv4
and
forceIPv6
:
raise
homer
.
ConnectionException
(
"Force IPv4 *or* IPv6 but not both"
)
raise
remoh
.
ConnectionException
(
"Force IPv4 *or* IPv6 but not both"
)
self
.
dot
=
dot
self
.
server
=
server
...
...
@@ -107,11 +107,11 @@ class ConnectionDOT(Connection):
else
:
addr
=
self
.
server
# otherwise keep the server name
family
=
homer
.
get_addrfamily
(
addr
,
forceIPv4
=
self
.
forceIPv4
,
forceIPv6
=
self
.
forceIPv6
)
addrinfo_list
=
socket
.
getaddrinfo
(
addr
,
homer
.
PORT_DOT
,
family
)
family
=
remoh
.
get_addrfamily
(
addr
,
forceIPv4
=
self
.
forceIPv4
,
forceIPv6
=
self
.
forceIPv6
)
addrinfo_list
=
socket
.
getaddrinfo
(
addr
,
remoh
.
PORT_DOT
,
family
)
addrinfo_set
=
{
(
addrinfo
[
4
],
addrinfo
[
0
])
for
addrinfo
in
addrinfo_list
}
signal
.
signal
(
signal
.
SIGALRM
,
homer
.
exceptions
.
timeout_connection
)
signal
.
signal
(
signal
.
SIGALRM
,
remoh
.
exceptions
.
timeout_connection
)
# contains a set of tuples ('ip address', 'error message')
errors
=
set
()
...
...
@@ -124,7 +124,7 @@ class ConnectionDOT(Connection):
# a string with all the errors
try
:
self
.
establish_session
(
addrinfo
[
0
],
addrinfo
[
1
])
except
homer
.
ConnectionDOTException
as
e
:
except
remoh
.
ConnectionDOTException
as
e
:
errors
.
add
((
addrinfo
[
0
][
0
],
str
(
e
)))
if
self
.
verbose
and
self
.
connect_to
is
None
:
print
(
e
,
file
=
sys
.
stderr
)
...
...
@@ -134,7 +134,7 @@ class ConnectionDOT(Connection):
print
(
"No other IP address"
)
# join all the errors into a single string
err
=
', '
.
join
(
"%s: %s"
%
(
e
[
0
],
e
[
1
])
for
e
in
errors
)
raise
homer
.
ConnectionDOTException
(
err
)
raise
remoh
.
ConnectionDOTException
(
err
)
if
self
.
verbose
and
self
.
connect_to
is
None
:
print
(
"Could not connect to %s"
%
addrinfo
[
0
][
0
])
print
(
"Trying another IP address"
)
...
...
@@ -149,7 +149,7 @@ class ConnectionDOT(Connection):
self
.
hasher
=
hashlib
.
sha256
()
# start the timer
signal
.
alarm
(
homer
.
TIMEOUT_CONN
)
signal
.
alarm
(
remoh
.
TIMEOUT_CONN
)
self
.
sock
=
socket
.
socket
(
sock_family
,
socket
.
SOCK_STREAM
)
...
...
@@ -170,27 +170,27 @@ class ConnectionDOT(Connection):
lambda
conn
,
cert
,
errno
,
depth
,
preverify_ok
:
preverify_ok
)
self
.
session
=
OpenSSL
.
SSL
.
Connection
(
self
.
context
,
self
.
sock
)
if
self
.
sni
:
self
.
session
.
set_tlsext_host_name
(
homer
.
canonicalize
(
self
.
check_name_cert
).
encode
())
self
.
session
.
set_tlsext_host_name
(
remoh
.
canonicalize
(
self
.
check_name_cert
).
encode
())
try
:
self
.
session
.
connect
((
addr
))
self
.
session
.
do_handshake
()
except
homer
.
exceptions
.
TimeoutConnectionError
:
except
remoh
.
exceptions
.
TimeoutConnectionError
:
self
.
state
=
'CONN_TIMEOUT'
raise
homer
.
ConnectionDOTException
(
"Timeout"
)
raise
remoh
.
ConnectionDOTException
(
"Timeout"
)
except
OSError
:
self
.
state
=
'CONN_FAILED'
raise
homer
.
ConnectionDOTException
(
"Cannot connect"
)
raise
remoh
.
ConnectionDOTException
(
"Cannot connect"
)
except
OpenSSL
.
SSL
.
SysCallError
as
e
: