From f10c9433c00faf68092eaf8b2324b4217e59f1a6 Mon Sep 17 00:00:00 2001 From: Sebastian Lohff Date: Fri, 7 Apr 2017 15:06:05 +0200 Subject: [PATCH] dns-sync script near to completion --- bin/dns-sync | 139 ++++++++++++++++++++++----------------------------- 1 file changed, 61 insertions(+), 78 deletions(-) diff --git a/bin/dns-sync b/bin/dns-sync index c82a451..7f1b717 100755 --- a/bin/dns-sync +++ b/bin/dns-sync @@ -9,7 +9,8 @@ import requests import django os.environ.setdefault("DJANGO_SETTINGS_MODULE", "dnmgmt.settings") -sys.path.append("..") +BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +sys.path.append(BASE_DIR) django.setup() from django.db.models import Count @@ -32,11 +33,11 @@ def _parser(): return parser -def mergeDomains(domains, zoneData): +def mergeDomains(zoneData, pdnsData): rrAdd = [] - rrData = zoneData['rrsets'] + rrData = pdnsData['rrsets'] - for domain, rrType, records in domains: + for domain, rrType, records in zoneData: found = False pdnsDom = list(filter(lambda _x: _x['name'] == domain and _x['type'] == rrType, rrData)) if len(pdnsDom) > 0: @@ -57,13 +58,13 @@ def mergeDomains(domains, zoneData): return rrAdd -def removeOldDomains(domains, zoneData): +def removeOldDomains(zoneData, pdnsData): rrDel = [] - for entry in zoneData['rrsets']: + for entry in pdnsData['rrsets']: # search for name/type in domain dict. if non-existtant mark for deletion # this could be much more efficient with a dict! name: [rrset...] - if not any(entry['name'] == _x[0] and entry['type'] == _x[1] for _x in domains): + if not any(entry['name'] == _x[0] and entry['type'] == _x[1] for _x in zoneData): rrDel.append({ "changetype": "DELETE", "name": entry["name"], @@ -83,99 +84,81 @@ def handleNameserver(ns, servers, usedNameservers, domains): domains.append((ns.name, "AAAA", [ns.glueIPv6])) -def main(): - parser = _parser() - args = parser.parse_args() - print(args) - - s = requests.Session() - s.headers = { - 'X-API-Key': 'bei2aequ2OBi', - 'Accept': 'application/json' - } - - print(" --> TLD dn.") - zoneData = s.get("http://potatos.portal.dn:8081/api/v1/servers/localhost/zones/dn.").json() - - domains = [] - usedNameservers = [] - qs = Domain.objects.annotate(nsCount=Count('nameservers')).filter(nsCount__gt=0).order_by("name") - - # cycle through all domains +def getDomainsFromQueryset(qs, zone, glueRecords, usedNameservers): for domain in qs: - print(" %s" % (domain.name)) servers = [] for ns in domain.nameservers.all(): servers.append(ns.name) if ns.name not in usedNameservers and (ns.glueIPv4 or ns.glueIPv6): - # FIXME: find dns glue record duplicates in whois webif usedNameservers.append(ns.name) if ns.glueIPv4: - domains.append((ns.name, "A", [ns.glueIPv4])) + glueRecords.append((ns.name, "A", [ns.glueIPv4])) if ns.glueIPv6: - domains.append((ns.name, "AAAA", [ns.glueIPv6])) + glueRecords.append((ns.name, "AAAA", [ns.glueIPv6])) - domains.append((domain.name, "NS", servers)) - - # cycle through all reverse records - qs = Domain.objects.annotate(nsCount=Count('nameservers')).filter(nsCount__gt=0).order_by("name") - for rzone in qs: - print(" %s" % (rzone.getZone(),)) - servers = [] - for ns in domain.nameservers.all(): - servers.append(ns.name) - - if ns.name not in usedNameservers and (ns.glueIPv4 or ns.glueIPv6): - # FIXME: find dns glue record duplicates in whois webif - usedNameservers.append(ns.name) - if ns.glueIPv4: - domains.append((ns.name, "A", [ns.glueIPv4])) - if ns.glueIPv6: - domains.append((ns.name, "AAAA", [ns.glueIPv6])) - - rzones.append((rzone.getZone, "PTR", servers)) - + zone.append((domain.getZone(), "NS", servers)) +def mergeDomainsWithPdns(s, args, zone, zoneData, protectedRecords=[]): + url = "http://potatos.portal.dn:8081/api/v1/servers/localhost/zones/%s" % (zone,) + pdnsData = s.get(url).json() - newDomains = mergeDomains(domains, zoneData) + # add dn. (NS + glue Nameservers) + newDomains = mergeDomains(zoneData, pdnsData) print("Add/replace", newDomains) - r = s.patch("http://potatos.portal.dn:8081/api/v1/servers/localhost/zones/dn.", data=json.dumps({'rrsets': newDomains})) - if r.status_code != 204: - raise RuntimeError("Could not update records in powerdns") - # delete old domains (except for NS/SOA of head) - domains.extend([ - ("dn.", "NS", []), - ("dn.", "SOA", []), - ]) + if len(newDomains) > 0: + r = s.patch(url, data=json.dumps({'rrsets': newDomains})) + if r.status_code != 204: + raise RuntimeError("Could not update records in powerdns") - delDomains = removeOldDomains(domains, zoneData) + delDomains = removeOldDomains(zoneData, zoneData + protectedRecords) print("Del", delDomains) - r = s.patch("http://potatos.portal.dn:8081/api/v1/servers/localhost/zones/dn.", data=json.dumps({'rrsets': delDomains})) + r = s.patch(url, data=json.dumps({'rrsets': delDomains})) if r.status_code != 204: raise RuntimeError("Could not update records in powerdns") - # and now for the reverse zones... - zoneData = s.get("http://potatos.portal.dn:8081/api/v1/servers/localhost/zones/dn.").json() - qs = ReverseZone.objects.annotate(nsCount=Count('nameservers')).filter(nsCount__gt=0).order_by("name") - # cycle through all domains - for domain in qs: - print(" %s" % (domain.name)) - servers = [] - for ns in domain.nameservers.all(): - servers.append(ns.name) +def main(): + parser = _parser() + args = parser.parse_args() - if ns.name not in usedNameservers and (ns.glueIPv4 or ns.glueIPv6): - # FIXME: find dns glue record duplicates in whois webif - usedNameservers.append(ns.name) - if ns.glueIPv4: - domains.append((ns.name, "A", [ns.glueIPv4])) - if ns.glueIPv6: - domains.append((ns.name, "AAAA", [ns.glueIPv6])) + s = requests.Session() + s.headers = { + 'X-API-Key': 'bei2aequ2OBi', + 'Accept': 'application/json' + } + + domains = [] + rzone4 = [] + rzone6 = [] + usedNameservers = [] + + # assenble domain data + # dn. + qs = Domain.objects.annotate(nsCount=Count('nameservers')).filter(nsCount__gt=0).order_by("name") + getDomainsFromQueryset(qs, domains, domains, usedNameservers) + + # reverse zones + qs = ReverseZone.objects.annotate(nsCount=Count('nameservers')).filter(nsCount__gt=0).order_by("parentNet__address") + qs4 = filter(lambda _revz: _revz.getNetwork().version == 4, qs) + qs6 = filter(lambda _revz: _revz.getNetwork().version == 6, qs) + getDomainsFromQueryset(qs4, rzone4, domains, usedNameservers) + getDomainsFromQueryset(qs6, rzone6, domains, usedNameservers) + + print("dn.", domains) + print("v4", rzone4) + print("v6", rzone6) + + protectedRecords = [ + ("dn.", "NS", []), + ("dn.", "SOA", []), + ] + + mergeDomainsWithPdns(s, args, "dn.", domains, protectedRecords) + mergeDomainsWithPdns(s, args, "10.in-addr.arpa.", rzone4) + mergeDomainsWithPdns(s, args, "3.2.7.c.3.a.d.f.ip6.arpa.") - domains.append((domain.name, "NS", servers)) if __name__ == '__main__':