Commit bfcfd787 authored by Alexandre's avatar Alexandre
Browse files

[DoT] Raise exception on error + tests coverage

Do not print error, instead raise an exception that need to be caught.
The calling method will then decide if the error should be displayed or
not.
parent 588a1919
......@@ -704,6 +704,15 @@ for ip in ip_set:
error("\"%s\" not a name or an IP address" % url)
except socket.gaierror:
error("Could not resolve \"%s\"" % url)
except homer.ConnectionDOTException as e:
if not monitoring:
print(e, file=sys.stderr)
err = "Could not connect to \"%s\"" % url
if opts.connectTo is not None:
err += " on %s" % opts.connectTo
error(err)
else:
error(e)
except (homer.ConnectionException, homer.DOHException) as e:
error(e)
if conn.dot and not conn.success:
......
import sys
import io
import socket
import signal
......@@ -110,24 +111,35 @@ class ConnectionDOT(Connection):
signal.signal(signal.SIGALRM, homer.exceptions.timeout_connection)
# contains a set of tuples ('ip address', 'error message')
errors = set()
i = 0
for addrinfo in addrinfo_set:
if self.establish_session(addrinfo[0], addrinfo[1]):
# catch the raised exceptions and store them in the error set
# if that the last element of the loop raises an exception
# it will also be catched, but in this case we are sure we can not
# establish a connection therefore we raise an exception containing
# a string with all the errors
try:
self.establish_session(addrinfo[0], addrinfo[1])
except homer.ConnectionDOTException as e:
errors.add((addrinfo[0][0], str(e)))
if self.verbose and self.connect_to is None:
print(e, file=sys.stderr)
# we tried all the resolved IPs
if i == (len(addrinfo_set) - 1):
if self.verbose and self.connect_to is None:
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)
if self.verbose and self.connect_to is None:
print("Could not connect to %s" % addrinfo[0][0])
print("Trying another IP address")
else:
self.success = True
break
if self.verbose and self.connect_to is None:
print("Could not connect to %s" % addrinfo[0][0])
print("Trying another IP address")
# we could not establish a connection
if not self.success:
# we tried all the resolved IPs
if self.verbose and self.connect_to is None:
print("No other IP address")
error = "Could not connect to \"%s\"" % self.server
if self.connect_to is not None:
error += " on %s" % self.connect_to
raise homer.ConnectionDOTException(error)
i += 1
def establish_session(self, addr, sock_family):
"""Return True if a TLS session is established."""
......@@ -162,26 +174,16 @@ class ConnectionDOT(Connection):
self.session.connect((addr))
self.session.do_handshake()
except homer.exceptions.TimeoutConnectionError:
if self.verbose:
print("Timeout")
return False
raise homer.ConnectionDOTException("Timeout")
except OSError:
if self.verbose:
print("Cannot connect")
return False
raise homer.ConnectionDOTException("Cannot connect")
except OpenSSL.SSL.SysCallError as e:
if self.verbose:
print("OpenSSL error: %s" % e.args[1], file=sys.stderr)
return False
raise homer.ConnectionDOTException("OpenSSL error: %s" % e.args[1])
except OpenSSL.SSL.ZeroReturnError:
# see #18
if self.verbose:
print("Error: The SSL connection has been closed (try with --nosni to avoid sending SNI ?)", file=sys.stderr)
return False
raise homer.ConnectionDOTException("Error: The SSL connection has been closed (try with --nosni to avoid sending SNI ?)")
except OpenSSL.SSL.Error as e:
if self.verbose:
print("OpenSSL error: %s" % ', '.join(err[0][2] for err in e.args), file=sys.stderr)
return False
raise homer.ConnectionDOTException("OpenSSL error: %s" % ', '.join(err[0][2] for err in e.args))
# RFC 7858, section 4.2 and appendix A
self.cert = self.session.get_peer_certificate()
......@@ -201,12 +203,10 @@ class ConnectionDOT(Connection):
if self.key is None:
valid = homer.validate_hostname(self.check_name_cert, self.cert)
if not valid:
error("Certificate error: \"%s\" is not in the certificate" % (self.check_name_cert), exit=False)
return False
raise homer.ConnectionDOTException("Certificate error: \"%s\" is not in the certificate" % (self.check_name_cert))
else:
if key_string != self.key:
error("Key error: expected \"%s\", got \"%s\"" % (self.key, key_string), exit=False)
return False
raise homer.ConnectionDOTException("Key error: expected \"%s\", got \"%s\"" % (self.key, key_string))
# restore the timer
signal.alarm(0)
......
......@@ -868,6 +868,20 @@ tests:
stderr: ''
partstdout: 'Cannot find'
- exe: './check_dot'
name: '[check_dot] Certificate error'
markers:
- 'dot'
- 'monitoring'
- 'exception'
args:
- '-H'
- 'doh.bortzmeyer.fr'
- '-n'
- 'dnsforum.bj'
retcode: 2
partstdout: 'certificate'
################################################################################
......@@ -1054,6 +1068,20 @@ tests:
stderr: ''
partstdout: 'Cannot find'
- exe: './check_doh'
name: '[check_doh] Certificate error'
markers:
- 'doh'
- 'monitoring'
- 'exception'
args:
- '-H'
- 'dot.bortzmeyer.fr'
- '-n'
- 'dnsforum.bj'
retcode: 2
partstdout: 'certificate'
################################################################################
- exe: './homer.py'
......
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