From 09133c8f595bea3714620b0504b95c7281862583 Mon Sep 17 00:00:00 2001 From: Brian Bustin Date: Wed, 1 Jul 2015 15:02:40 -0400 Subject: [PATCH] Initial backend changes to make it possible to have one or more secondary name servers --- management/daemon.py | 2 +- management/dns_update.py | 78 ++++++++++++++++------------ management/status_checks.py | 7 +-- management/templates/custom-dns.html | 2 +- 4 files changed, 50 insertions(+), 39 deletions(-) diff --git a/management/daemon.py b/management/daemon.py index 88dd9a42..2d14b4e6 100755 --- a/management/daemon.py +++ b/management/daemon.py @@ -229,7 +229,7 @@ def dns_get_secondary_nameserver(): def dns_set_secondary_nameserver(): from dns_update import set_secondary_dns try: - return set_secondary_dns(request.form.get('hostname'), env) + return set_secondary_dns(request.form.get('hostname').split(","), env) except ValueError as e: return (str(e), 400) diff --git a/management/dns_update.py b/management/dns_update.py index 5a3ca1dc..5321b4f7 100755 --- a/management/dns_update.py +++ b/management/dns_update.py @@ -144,8 +144,13 @@ def build_zone(domain, all_domains, additional_records, www_redirect_domains, en records.append((None, "NS", "ns1.%s." % env["PRIMARY_HOSTNAME"], False)) # Define ns2.PRIMARY_HOSTNAME or whatever the user overrides. - secondary_ns = get_secondary_dns(additional_records) or ("ns2." + env["PRIMARY_HOSTNAME"]) - records.append((None, "NS", secondary_ns+'.', False)) + # User may provide one or more additional nameservers + secondary_dns_records = get_secondary_dns(additional_records) + if len(secondary_dns_records) > 0: + for secondary_ns in secondary_dns_records: + records.append((None, "NS", secondary_ns+'.', False)) + else: + records.append((None, "NS", "ns2." + env["PRIMARY_HOSTNAME"] + '.', False)) # In PRIMARY_HOSTNAME... @@ -462,17 +467,23 @@ zone: zonefile: %s """ % (domain, zonefile) - # If a custom secondary nameserver has been set, allow zone transfers - # and notifies to that nameserver. - if get_secondary_dns(additional_records): - # Get the IP address of the nameserver by resolving it. - hostname = get_secondary_dns(additional_records) - resolver = dns.resolver.get_default_resolver() - response = dns.resolver.query(hostname+'.', "A") - ipaddr = str(response[0]) - nsdconf += """\tnotify: %s NOKEY - provide-xfr: %s NOKEY -""" % (ipaddr, ipaddr) + # If custom secondary nameservers have been set, allow zone transfers + # and notifies to them. + if get_secondary_dns(additional_records, ['_secondary_nameserver']): + for hostname in get_secondary_dns(additional_records): + # Get the IP address of the nameserver by resolving it. + resolver = dns.resolver.get_default_resolver() + response = dns.resolver.query(hostname+'.', "A") + ipaddr = str(response[0]) + nsdconf += "\n\tnotify: %s NOKEY\n\tprovide-xfr: %s NOKEY" % (ipaddr, ipaddr) + # Some providers use different servers for zone transfers and notifies + # such as DNS Made Easy. This allows us to set these IP addresses as well manually + # in custom.yaml + if get_secondary_dns(additional_records, ["_secondary_notify_xfr"]): + for ipaddr in get_secondary_dns(additional_records, ["_secondary_notify_xfr"]): + nsdconf += "\n\tnotify: %s NOKEY\n\tprovide-xfr: %s NOKEY" % (ipaddr, ipaddr) + + # Check if the file is changing. If it isn't changing, # return False to flag that no change was made. @@ -785,33 +796,36 @@ def set_custom_dns_record(qname, rtype, value, action, env): if made_change: # serialize & save write_custom_dns_config(newconfig, env) - return made_change ######################################################################## -def get_secondary_dns(custom_dns): +def get_secondary_dns(custom_dns, dns_type=['_secondary_nameserver']): + valid_types = set(['_secondary_nameserver', '_secondary_notify_xfr']) + if not valid_types.issuperset(set(dns_type)): + raise ValueError("Valid types are one or more of the following: %s" % ", ".join(valid_types)) + + values = [] for qname, rtype, value in custom_dns: - if qname == "_secondary_nameserver": - return value - return None + if qname in dns_type: + if isinstance(value, str): + values.append(value) + return values def set_secondary_dns(hostname, env): - - if hostname in (None, ""): - # Clear. - set_custom_dns_record("_secondary_nameserver", "A", None, "set", env) - else: - # Validate. - hostname = hostname.strip().lower() + hostnames = [item.strip().lower() for item in hostname] + if len(hostnames) > 0: resolver = dns.resolver.get_default_resolver() - try: - response = dns.resolver.query(hostname, "A") - except (dns.resolver.NoNameservers, dns.resolver.NXDOMAIN, dns.resolver.NoAnswer): - raise ValueError("Could not resolve the IP address of %s." % hostname) - - # Set. - set_custom_dns_record("_secondary_nameserver", "A", hostname, "set", env) + for item in hostnames: + try: + response = dns.resolver.query(item, "A") + except (dns.resolver.NoNameservers, dns.resolver.NXDOMAIN, dns.resolver.NoAnswer): + raise ValueError("Could not resolve the IP address of %s." % item) + # Set. + set_custom_dns_record("_secondary_nameserver", "A", {"A":hostnames}, "set", env) + else: + # Clear. + set_custom_dns_record("_secondary_nameserver", "A", None, "set", env) # Apply. return do_dns_update(env) diff --git a/management/status_checks.py b/management/status_checks.py index f7020c6f..b804378a 100755 --- a/management/status_checks.py +++ b/management/status_checks.py @@ -370,12 +370,9 @@ def check_dns_zone(domain, env, output, dns_zonefiles): # the TLD, and so we're not actually checking the TLD. For that we'd need # to do a DNS trace. ip = query_dns(domain, "A") - secondary_ns = get_secondary_dns(get_custom_dns_config(env)) or "ns2." + env['PRIMARY_HOSTNAME'] + secondary_ns = get_secondary_dns(get_custom_dns_config(env)) or ["ns2." + env['PRIMARY_HOSTNAME']] 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(): output.print_ok("Nameservers are set correctly at registrar. [%s]" % correct_ns) elif ip == env['PUBLIC_IP']: diff --git a/management/templates/custom-dns.html b/management/templates/custom-dns.html index 711bc384..ddc1153f 100644 --- a/management/templates/custom-dns.html +++ b/management/templates/custom-dns.html @@ -67,7 +67,7 @@

Using a Secondary Nameserver

-

If your TLD requires you to have two separate nameservers, you can either set up a secondary (aka “slave”) nameserver or, alternatively, set up external DNS and ignore the DNS server on this box. If you choose to use a seconday/slave nameserver, you must find a seconday/slave nameserver service provider. Your domain name registrar or virtual cloud provider may provide this service for you. Once you set up the seconday/slave nameserver service, enter the hostname of their secondary nameserver:

+

If your TLD requires you to have two separate nameservers, you can either set up a secondary (aka “slave”) nameserver or, alternatively, set up external DNS and ignore the DNS server on this box. If you choose to use a seconday/slave nameserver, you must find a seconday/slave nameserver service provider. Your domain name registrar or virtual cloud provider may provide this service for you. Once you set up the seconday/slave nameserver service, enter the hostname of their secondary nameserver (multiple secondaries can be added separated with commas i.e. ns2.hostingcompany.com,ns3.hostingcompany.com):