Commit 3b91bc2c authored by Joshua Tauberer's avatar Joshua Tauberer

if secondary nameservers are given, status checks now check they are serving the right info

parent 4c4babd9
...@@ -28,6 +28,7 @@ Control panel: ...@@ -28,6 +28,7 @@ Control panel:
* Fixed the jumpiness when a modal is displayed. * Fixed the jumpiness when a modal is displayed.
* Focus is put into the login form fields when the login form is displayed. * Focus is put into the login form fields when the login form is displayed.
* Status checks now include a warning if a custom DNS record has been set on a domain that would normally serve web and as a result that domain no longer is serving web. * Status checks now include a warning if a custom DNS record has been set on a domain that would normally serve web and as a result that domain no longer is serving web.
* Status checks now check that secondary nameservers, if specified, are actually serving the domains.
* Some errors in the control panel when there is invalid data in the database or an improperly named archived user account have been suppressed. * Some errors in the control panel when there is invalid data in the database or an improperly named archived user account have been suppressed.
* Added subresource integrity attributes to all remotely-sourced resources (i.e. via CDNs) to guard against CDNs being used as an attack vector. * Added subresource integrity attributes to all remotely-sourced resources (i.e. via CDNs) to guard against CDNs being used as an attack vector.
......
...@@ -380,12 +380,14 @@ def check_dns_zone(domain, env, output, dns_zonefiles): ...@@ -380,12 +380,14 @@ def check_dns_zone(domain, env, output, dns_zonefiles):
# We provide a DNS zone for the domain. It should have NS records set up # We provide a DNS zone for the domain. It should have NS records set up
# at the domain name's registrar pointing to this box. The secondary DNS # at the domain name's registrar pointing to this box. The secondary DNS
# server may be customized. Unfortunately this may not check the domain's # server may be customized.
# whois information -- we may be getting the NS records from us rather than # (I'm not sure whether this necessarily tests the TLD's configuration,
# the TLD, and so we're not actually checking the TLD. For that we'd need # as it should, or if one successful NS line at the TLD will result in
# to do a DNS trace. # this query being answered by the box, which would mean the test is only
# half working.)
ip = query_dns(domain, "A") ip = query_dns(domain, "A")
secondary_ns = get_secondary_dns(get_custom_dns_config(env), mode="NS") or ["ns2." + env['PRIMARY_HOSTNAME']] custom_secondary_ns = get_secondary_dns(get_custom_dns_config(env), mode="NS")
secondary_ns = custom_secondary_ns or ["ns2." + env['PRIMARY_HOSTNAME']]
existing_ns = query_dns(domain, "NS") existing_ns = query_dns(domain, "NS")
correct_ns = "; ".join(sorted(["ns1." + env['PRIMARY_HOSTNAME']] + secondary_ns)) correct_ns = "; ".join(sorted(["ns1." + env['PRIMARY_HOSTNAME']] + secondary_ns))
if existing_ns.lower() == correct_ns.lower(): if existing_ns.lower() == correct_ns.lower():
...@@ -400,6 +402,25 @@ def check_dns_zone(domain, env, output, dns_zonefiles): ...@@ -400,6 +402,25 @@ def check_dns_zone(domain, env, output, dns_zonefiles):
control panel to set the nameservers to %s.""" control panel to set the nameservers to %s."""
% (existing_ns, correct_ns) ) % (existing_ns, correct_ns) )
# If the user is probably not using external DNS...
if ip == env['PUBLIC_IP'] and custom_secondary_ns:
# Check that each custom secondary nameserver resolves the IP address.
for ns in custom_secondary_ns:
# We must first resolve the nameserver to an IP address so we can query it.
ns_ip = query_dns(ns, "A")
if not ns_ip:
output.print_error("Secondary nameserver %s is not valid (it doesn't resolve to an IP address)." % ns)
continue
# Now query it to see what it says about this domain.
ip = query_dns(domain, "A", at=ns_ip, nxdomain=None)
if ip == env['PUBLIC_IP']:
output.print_ok("Secondary nameserver %s resolved the domain correctly." % ns)
elif ip is None:
output.print_error("Secondary nameserver %s is not configured to resolve this domain." % ns)
else:
output.print_error("Secondary nameserver %s is not configured correctly. (It resolved this domain as %s. It should be %s.)" % (ns, ip, env['PUBLIC_IP']))
def check_dns_zone_suggestions(domain, env, output, dns_zonefiles, domains_with_a_records): def check_dns_zone_suggestions(domain, env, output, dns_zonefiles, domains_with_a_records):
# Warn if a custom DNS record is preventing this or the automatic www redirect from # Warn if a custom DNS record is preventing this or the automatic www redirect from
# being served. # being served.
...@@ -548,7 +569,7 @@ def check_web_domain(domain, rounded_time, ssl_certificates, env, output): ...@@ -548,7 +569,7 @@ def check_web_domain(domain, rounded_time, ssl_certificates, env, output):
# website for also needs a signed certificate. # website for also needs a signed certificate.
check_ssl_cert(domain, rounded_time, ssl_certificates, env, output) check_ssl_cert(domain, rounded_time, ssl_certificates, env, output)
def query_dns(qname, rtype, nxdomain='[Not Set]'): def query_dns(qname, rtype, nxdomain='[Not Set]', at=None):
# Make the qname absolute by appending a period. Without this, dns.resolver.query # Make the qname absolute by appending a period. Without this, dns.resolver.query
# will fall back a failed lookup to a second query with this machine's hostname # will fall back a failed lookup to a second query with this machine's hostname
# appended. This has been causing some false-positive Spamhaus reports. The # appended. This has been causing some false-positive Spamhaus reports. The
...@@ -557,9 +578,17 @@ def query_dns(qname, rtype, nxdomain='[Not Set]'): ...@@ -557,9 +578,17 @@ def query_dns(qname, rtype, nxdomain='[Not Set]'):
if isinstance(qname, str): if isinstance(qname, str):
qname += "." qname += "."
# Use the default nameservers (as defined by the system, which is our locally
# running bind server), or if the 'at' argument is specified, use that host
# as the nameserver.
resolver = dns.resolver.get_default_resolver()
if at:
resolver = dns.resolver.Resolver()
resolver.nameservers = [at]
# Do the query. # Do the query.
try: try:
response = dns.resolver.query(qname, rtype) response = resolver.query(qname, rtype)
except (dns.resolver.NoNameservers, dns.resolver.NXDOMAIN, dns.resolver.NoAnswer): except (dns.resolver.NoNameservers, dns.resolver.NXDOMAIN, dns.resolver.NoAnswer):
# Host did not have an answer for this query; not sure what the # Host did not have an answer for this query; not sure what the
# difference is between the two exceptions. # difference is between the two exceptions.
......
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