dnmgmt/bin/dns-sync

166 lines
4.5 KiB
Plaintext
Raw Normal View History

2017-04-06 11:57:22 +02:00
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import argparse
import os
import sys
import json
import requests
import django
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "dnmgmt.settings")
2017-04-07 15:06:05 +02:00
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.append(BASE_DIR)
2017-04-06 11:57:22 +02:00
django.setup()
from django.db.models import Count
from domains.models import Domain, ReverseZone
__VERSION__ = '0.1'
def _parser():
parser = argparse.ArgumentParser(
#prog='foo',
#description='do some awesome foo',
)
#parser.add_argument("-p", "--port", default=2323, type=int, help="Your port")
#parser.add_argument("-v", "--verbose", default=False, action="store_true", help="Be more verbose")
parser.add_argument("--version", action="version", version="%(prog)s " + __VERSION__)
return parser
2017-04-07 15:06:05 +02:00
def mergeDomains(zoneData, pdnsData):
2017-04-06 11:57:22 +02:00
rrAdd = []
2017-04-07 15:06:05 +02:00
rrData = pdnsData['rrsets']
2017-04-06 11:57:22 +02:00
2017-04-07 15:06:05 +02:00
for domain, rrType, records in zoneData:
2017-04-06 11:57:22 +02:00
found = False
pdnsDom = list(filter(lambda _x: _x['name'] == domain and _x['type'] == rrType, rrData))
if len(pdnsDom) > 0:
rrSet = set(_x['content'] for _x in pdnsDom[0]['records'])
if rrSet == set(records):
found = True
if not found:
# new domain!
rrAdd.append({
"name": domain,
"type": rrType,
"ttl": 60*60,
"changetype": "REPLACE",
"records": [{"content": record, "disabled": False} for record in records],
})
return rrAdd
2017-04-07 15:06:05 +02:00
def removeOldDomains(zoneData, pdnsData):
2017-04-06 11:57:22 +02:00
rrDel = []
2017-04-07 15:06:05 +02:00
for entry in pdnsData['rrsets']:
2017-04-06 11:57:22 +02:00
# search for name/type in domain dict. if non-existtant mark for deletion
# this could be much more efficient with a dict! name: [rrset...]
2017-04-07 15:06:05 +02:00
if not any(entry['name'] == _x[0] and entry['type'] == _x[1] for _x in zoneData):
2017-04-06 11:57:22 +02:00
rrDel.append({
"changetype": "DELETE",
"name": entry["name"],
"type": entry["type"],
})
return rrDel
def handleNameserver(ns, servers, usedNameservers, domains):
servers.append(ns.name)
if ns.name not in usedNameservers and (ns.glueIPv4 or ns.glueIPv6):
usedNameservers.append(ns.name)
if ns.glueIPv4:
domains.append((ns.name, "A", [ns.glueIPv4]))
if ns.glueIPv6:
domains.append((ns.name, "AAAA", [ns.glueIPv6]))
2017-04-07 15:06:05 +02:00
def getDomainsFromQueryset(qs, zone, glueRecords, usedNameservers):
2017-04-06 11:57:22 +02:00
for domain in qs:
servers = []
for ns in domain.nameservers.all():
servers.append(ns.name)
if ns.name not in usedNameservers and (ns.glueIPv4 or ns.glueIPv6):
usedNameservers.append(ns.name)
if ns.glueIPv4:
2017-04-07 15:06:05 +02:00
glueRecords.append((ns.name, "A", [ns.glueIPv4]))
2017-04-06 11:57:22 +02:00
if ns.glueIPv6:
2017-04-07 15:06:05 +02:00
glueRecords.append((ns.name, "AAAA", [ns.glueIPv6]))
2017-04-06 11:57:22 +02:00
2017-04-07 15:06:05 +02:00
zone.append((domain.getZone(), "NS", servers))
2017-04-06 11:57:22 +02:00
2017-04-07 15:06:05 +02:00
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()
2017-04-06 11:57:22 +02:00
2017-04-07 15:06:05 +02:00
# add dn. (NS + glue Nameservers)
newDomains = mergeDomains(zoneData, pdnsData)
2017-04-06 11:57:22 +02:00
print("Add/replace", newDomains)
2017-04-07 15:06:05 +02:00
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")
2017-04-06 11:57:22 +02:00
2017-04-07 15:06:05 +02:00
delDomains = removeOldDomains(zoneData, zoneData + protectedRecords)
2017-04-06 11:57:22 +02:00
print("Del", delDomains)
2017-04-07 15:06:05 +02:00
r = s.patch(url, data=json.dumps({'rrsets': delDomains}))
2017-04-06 11:57:22 +02:00
if r.status_code != 204:
raise RuntimeError("Could not update records in powerdns")
2017-04-07 15:06:05 +02:00
def main():
parser = _parser()
args = parser.parse_args()
2017-04-06 11:57:22 +02:00
2017-04-07 15:06:05 +02:00
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.")
2017-04-06 11:57:22 +02:00
if __name__ == '__main__':
main()