Commit 66ea1c09 authored by Alexandre's avatar Alexandre
Browse files

Merge branch 'fix-exit-on-error'

Do not exit on error with --check

See merge request bortzmeyer/homer!28
parents bf5940ad 84267e39
......@@ -60,9 +60,11 @@ def error(msg=None, exit=True):
if msg is None:
msg = "Unknown error"
print(msg, file=sys.stderr)
def error_and_exit(msg=None):
error(msg)
if opts.check:
print('KO')
if exit:
sys.exit(1)
def usage(msg=None):
......@@ -360,7 +362,7 @@ def resolved_ips(host, port, family, dot=False):
try:
addr_list = socket.getaddrinfo(host, port, family)
except socket.gaierror:
error("Could not resolve \"%s\"" % host)
error_and_exit("Could not resolve \"%s\"" % host)
ip_set = { addr[4][0] for addr in addr_list }
return ip_set
......@@ -418,11 +420,11 @@ def parse_opts(opts):
elif option == "--repeat" or option == "-r":
opts.tests = int(value)
if opts.tests <= 1:
error("--repeat needs a value > 1")
error_and_exit("--repeat needs a value > 1")
elif option == "--delay" or option == "-d":
opts.delay = float(value)
if delay <= 0:
error("--delay needs a value > 0")
error_and_exit("--delay needs a value > 0")
elif option == "--file" or option == "-f":
opts.ifile = value
elif option == "--key":
......@@ -436,67 +438,53 @@ def parse_opts(opts):
elif option == "--max-in-flight":
opts.max_in_flight = int(value)
if max_in_flight <= 0:
error("--max_in_flight but be > 0")
error_and_exit("--max_in_flight but be > 0")
if max_in_flight >= 65536:
error("Because of a limit of the DNS protocol (the size of the query ID) --max_in_flight must be < 65 536")
error_and_exit("Because of a limit of the DNS protocol (the size of the query ID) --max_in_flight must be < 65 536")
elif option == "--check":
opts.check = True
opts.display_results = False
elif option == "--mandatory-level":
opts.mandatory_level = value
else:
error("Unknown option %s" % option)
error_and_exit("Unknown option %s" % option)
except (getopt.error, ValueError) as reason:
error(reason)
sys.exit(1)
error_and_exit(reason)
if opts.delay is not None and opts.multistreams:
error("--delay makes no sense with multistreams")
error_and_exit("--delay makes no sense with multistreams")
if opts.tests <= 1 and opts.delay is not None:
error("--delay makes no sense if there is no repetition")
error_and_exit("--delay makes no sense if there is no repetition")
if not opts.dot and opts.pipelining:
error("Pipelining is only accepted for DoT")
sys.exit(1)
error_and_exit("Pipelining is only accepted for DoT")
if opts.dot and (opts.post or opts.head):
error("POST or HEAD makes non sense for DoT")
sys.exit(1)
error_and_exit("POST or HEAD makes non sense for DoT")
if opts.post and opts.head:
error("POST or HEAD but not both")
sys.exit(1)
error_and_exit("POST or HEAD but not both")
if opts.pipelining and opts.ifile is None:
error("Pipelining requires an input file")
sys.exit(1)
error_and_exit("Pipelining requires an input file")
if opts.check and opts.multistreams:
error("--check and --multistreams are not compatible")
sys.exit(1)
error_and_exit("--check and --multistreams are not compatible")
if opts.dot and opts.multistreams:
error("Multi-streams makes no sense for DoT")
sys.exit(1)
error_and_exit("Multi-streams makes no sense for DoT")
if opts.multistreams and opts.ifile is None:
error("Multi-streams requires an input file")
sys.exit(1)
error_and_exit("Multi-streams requires an input file")
if opts.show_time and opts.dot:
error("--time cannot be used with --dot")
sys.exit(1)
error_and_exit("--time cannot be used with --dot")
if not opts.edns and not opts.no_ecs:
error("ECS requires EDNS")
sys.exit(1)
error_and_exit("ECS requires EDNS")
if opts.mandatory_level is not None and \
opts.mandatory_level not in homer.mandatory_levels.keys():
error("Unknown mandatory level \"%s\"" % opts.mandatory_level)
sys.exit(1)
error_and_exit("Unknown mandatory level \"%s\"" % opts.mandatory_level)
if opts.mandatory_level is not None and not opts.check:
error("--mandatory-level only makes sense with --check")
sys.exit(1)
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]
if opts.ifile is None and (len(args) != 2 and len(args) != 3):
error("Wrong number of arguments")
sys.exit(1)
error_and_exit("Wrong number of arguments")
if opts.ifile is not None and len(args) != 1:
error("Wrong number of arguments (if --file is used, do not indicate the domain name)")
sys.exit(1)
error_and_exit("Wrong number of arguments (if --file is used, do not indicate the domain name)")
url = args[0]
if opts.ifile is None:
name = args[1]
......@@ -604,18 +592,18 @@ else:
if opts.dot:
port = homer.PORT_DOT
if not homer.is_valid_hostname(url):
error("DoT requires a host name or IP address, not \"%s\"" % 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):
error("DoH requires a valid HTTPS URL, not \"%s\"" % 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
# errors (for instance whitespaces, IPv6 address litterals without
# brackets...) are ignored.
except ValueError:
error("The provided url \"%s\" could not be parsed" % url)
error_and_exit("The provided url \"%s\" could not be parsed" % url)
netloc = url_parts.netloc
if opts.forceIPv4:
family = socket.AF_INET
......@@ -631,8 +619,9 @@ if opts.verbose and opts.check:
print("%d IP found : %s" % (len(ip_set), ', '.join(ip_set)))
ok = True
i = 1 # ip counter
i = 0 # ip counter
for ip in ip_set:
i += 1
if opts.dot and opts.vhostname is not None:
extracheck = opts.vhostname
else:
......@@ -652,12 +641,20 @@ for ip in ip_set:
multistreams=opts.multistreams)
except TimeoutError:
error("timeout")
ok = False
continue
except ConnectionRefusedError:
error("Connection to server refused")
ok = False
continue
except ValueError:
error("\"%s\" not a name or an IP address" % url)
ok = False
continue
except socket.gaierror:
error("Could not resolve \"%s\"" % url)
ok = False
continue
except homer.ConnectionDOTException as e:
print(e, file=sys.stderr)
err = "Could not connect to \"%s\"" % url
......@@ -666,27 +663,35 @@ for ip in ip_set:
elif ip is not None:
err += " on %s" % ip
error(err)
ok = False
continue
except (homer.ConnectionException, homer.DOHException) as e:
error(e)
ok = False
continue
if conn.dot and not conn.success:
ok = False
continue
if opts.ifile is not None:
input = open(opts.ifile)
if not opts.check:
ok = run_default(name, conn, opts)
else:
ok = run_check(conn) and ok # need to run run_check first
if opts.ifile is not None:
input.close()
conn.end()
i += 1
conn.end()
if ok:
if opts.check or opts.pipelining:
print('OK')
sys.exit(0)
else:
if opts.check:
print('KO')
sys.exit(1)
......@@ -311,6 +311,22 @@ tests:
retcode: 0
partstdout: "checking IP : 2001:4860:4860::8888\nConnecting to 2001:4860:4860::8888 ..."
- name: '[dot][check] Verify that all IPs are tried even when one is failing'
exe: './homer.py'
timeout: 6
markers:
- 'dot'
- 'check'
args:
- '-v'
- '-k'
- '--dot'
- '--check'
- 'brok.sources.org'
- 'tm'
retcode: 1
partstdout: "(3/3) checking IP"
- name: '[doh][check] Test all the IPs, force IPv4'
exe: './homer.py'
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