Commit 5bbe9f9a authored by Joshua Tauberer's avatar Joshua Tauberer

status checks: when ipv6 is enabled, check that services are accessible over ipv6 too

parent 7a93d219
...@@ -10,6 +10,7 @@ Mail: ...@@ -10,6 +10,7 @@ Mail:
Control panel: Control panel:
* When IPv6 is enabled, check that system services are accessible over IPv6 too.
* Explanatory text for setting up secondary nameserver is added/fixed. * Explanatory text for setting up secondary nameserver is added/fixed.
* DNS checks now have a timeout in case a DNS server is not responding, so the checks don't stall indefinitely. * DNS checks now have a timeout in case a DNS server is not responding, so the checks don't stall indefinitely.
* Better messages if external DNS is used and, weirdly, custom secondary nameservers are set. * Better messages if external DNS is used and, weirdly, custom secondary nameservers are set.
......
...@@ -103,45 +103,60 @@ def check_service(i, service, env): ...@@ -103,45 +103,60 @@ def check_service(i, service, env):
# Skip check (no port, e.g. no sshd). # Skip check (no port, e.g. no sshd).
return (i, None, None, None) return (i, None, None, None)
import socket
output = BufferedOutput() output = BufferedOutput()
running = False running = False
fatal = False fatal = False
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(1) # Helper function to make a connection to the service, since we try
try: # up to three ways (localhost, IPv4 address, IPv6 address).
def try_connect(ip):
# Connect to the given IP address on the service's port with a one-second timeout.
import socket
s = socket.socket(socket.AF_INET if ":" not in ip else socket.AF_INET6, socket.SOCK_STREAM)
s.settimeout(1)
try: try:
s.connect(( s.connect((ip, service["port"]))
"127.0.0.1" if not service["public"] else env['PUBLIC_IP'], return True
service["port"])) except OSError as e:
running = True # timed out or some other odd error
except OSError as e1: return False
if service["public"] and service["port"] != 53: finally:
# For public services (except DNS), try the private IP as a fallback. s.close()
s1 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s1.settimeout(1) if service["public"]:
try: # Service should be publicly accessible.
s1.connect(("127.0.0.1", service["port"])) if try_connect(env["PUBLIC_IP"]):
output.print_error("%s is running but is not publicly accessible at %s:%d (%s)." % (service['name'], env['PUBLIC_IP'], service['port'], str(e1))) # IPv4 ok.
except: if not env.get("PUBLIC_IPV6") or service.get("ipv6") is False or try_connect(env["PUBLIC_IPV6"]):
raise e1 # No IPv6, or service isn't meant to run on IPv6, or IPv6 is good.
finally: running = True
s1.close()
# IPv4 ok but IPv6 failed. Try the PRIVATE_IPV6 address to see if the service is bound to the interface.
elif service["port"] != 53 and try_connect(env["PRIVATE_IPV6"]):
output.print_error("%s is running (and available over IPv4 and the local IPv6 address), but it is not publicly accessible at %s:%d." % (service['name'], env['PUBLIC_IP'], service['port']))
else: else:
raise output.print_error("%s is running and available over IPv4 but is not accessible over IPv6 at %s port %d." % (service['name'], env['PUBLIC_IPV6'], service['port']))
except OSError as e: # IPv4 failed. Try the private IP to see if the service is running but not accessible (except DNS because a different service runs on the private IP).
output.print_error("%s is not running (%s; port %d)." % (service['name'], str(e), service['port'])) elif service["port"] != 53 and try_connect("127.0.0.1"):
output.print_error("%s is running but is not publicly accessible at %s:%d." % (service['name'], env['PUBLIC_IP'], service['port']))
else:
output.print_error("%s is not running (port %d)." % (service['name'], service['port']))
# Why is nginx not running? # Why is nginx not running?
if service["port"] in (80, 443): if not running and service["port"] in (80, 443):
output.print_line(shell('check_output', ['nginx', '-t'], capture_stderr=True, trap=True)[1].strip()) output.print_line(shell('check_output', ['nginx', '-t'], capture_stderr=True, trap=True)[1].strip())
# Flag if local DNS is not running. else:
if service["port"] == 53 and service["public"] == False: # Service should be running locally.
fatal = True if try_connect("127.0.0.1"):
finally: running = True
s.close() else:
output.print_error("%s is not running (port %d)." % (service['name'], service['port']))
# Flag if local DNS is not running.
if not running and service["port"] == 53 and service["public"] == False:
fatal = True
return (i, running, fatal, output) return (i, running, fatal, output)
......
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