Browse Source

dns-sync draft

Sebastian Lohff 3 years ago
parent
commit
9f8695dddc
1 changed files with 182 additions and 0 deletions
  1. 182
    0
      bin/dns-sync

+ 182
- 0
bin/dns-sync View File

@@ -0,0 +1,182 @@
1
+#!/usr/bin/env python3
2
+# -*- coding: utf-8 -*-
3
+import argparse
4
+import os
5
+import sys
6
+import json
7
+import requests
8
+
9
+import django
10
+
11
+os.environ.setdefault("DJANGO_SETTINGS_MODULE", "dnmgmt.settings")
12
+sys.path.append("..")
13
+django.setup()
14
+
15
+from django.db.models import Count
16
+from domains.models import Domain, ReverseZone
17
+
18
+
19
+__VERSION__ = '0.1'
20
+
21
+
22
+def _parser():
23
+	parser = argparse.ArgumentParser(
24
+	             #prog='foo',
25
+	             #description='do some awesome foo',
26
+	)
27
+
28
+	#parser.add_argument("-p", "--port", default=2323, type=int, help="Your port")
29
+	#parser.add_argument("-v", "--verbose", default=False, action="store_true", help="Be more verbose")
30
+
31
+	parser.add_argument("--version", action="version", version="%(prog)s " + __VERSION__)
32
+
33
+	return parser
34
+
35
+def mergeDomains(domains, zoneData):
36
+	rrAdd = []
37
+	rrData = zoneData['rrsets']
38
+
39
+	for domain, rrType, records in domains:
40
+		found = False
41
+		pdnsDom = list(filter(lambda _x: _x['name'] == domain and _x['type'] == rrType, rrData))
42
+		if len(pdnsDom) > 0:
43
+			rrSet = set(_x['content'] for _x in pdnsDom[0]['records'])
44
+			if rrSet == set(records):
45
+				found = True
46
+
47
+		if not found:
48
+			# new domain!
49
+			rrAdd.append({
50
+				"name": domain,
51
+				"type": rrType,
52
+				"ttl": 60*60,
53
+				"changetype": "REPLACE",
54
+				"records": [{"content": record, "disabled": False} for record in records],
55
+			})
56
+
57
+	return rrAdd
58
+
59
+
60
+def removeOldDomains(domains, zoneData):
61
+	rrDel = []
62
+
63
+	for entry in zoneData['rrsets']:
64
+		# search for name/type in domain dict. if non-existtant mark for deletion
65
+		# this could be much more efficient with a dict! name: [rrset...]
66
+		if not any(entry['name'] == _x[0] and entry['type'] == _x[1] for _x in domains):
67
+			rrDel.append({
68
+				"changetype": "DELETE",
69
+				"name": entry["name"],
70
+				"type": entry["type"],
71
+			})
72
+
73
+	return rrDel
74
+
75
+def handleNameserver(ns, servers, usedNameservers, domains):
76
+	servers.append(ns.name)
77
+
78
+	if ns.name not in usedNameservers and (ns.glueIPv4 or ns.glueIPv6):
79
+		usedNameservers.append(ns.name)
80
+		if ns.glueIPv4:
81
+			domains.append((ns.name, "A", [ns.glueIPv4]))
82
+		if ns.glueIPv6:
83
+			domains.append((ns.name, "AAAA", [ns.glueIPv6]))
84
+
85
+
86
+def main():
87
+	parser = _parser()
88
+	args = parser.parse_args()
89
+	print(args)
90
+
91
+	s = requests.Session()
92
+	s.headers = {
93
+		'X-API-Key': 'bei2aequ2OBi',
94
+		'Accept': 'application/json'
95
+	}
96
+
97
+	print(" --> TLD dn.")
98
+	zoneData = s.get("http://potatos.portal.dn:8081/api/v1/servers/localhost/zones/dn.").json()
99
+
100
+	domains = []
101
+	usedNameservers = []
102
+	qs = Domain.objects.annotate(nsCount=Count('nameservers')).filter(nsCount__gt=0).order_by("name")
103
+
104
+	# cycle through all domains
105
+	for domain in qs:
106
+		print("    %s" % (domain.name))
107
+		servers = []
108
+		for ns in domain.nameservers.all():
109
+			servers.append(ns.name)
110
+
111
+			if ns.name not in usedNameservers and (ns.glueIPv4 or ns.glueIPv6):
112
+				# FIXME: find dns glue record duplicates in whois webif
113
+				usedNameservers.append(ns.name)
114
+				if ns.glueIPv4:
115
+					domains.append((ns.name, "A", [ns.glueIPv4]))
116
+				if ns.glueIPv6:
117
+					domains.append((ns.name, "AAAA", [ns.glueIPv6]))
118
+
119
+		domains.append((domain.name, "NS", servers))
120
+
121
+	# cycle through all reverse records
122
+	qs = Domain.objects.annotate(nsCount=Count('nameservers')).filter(nsCount__gt=0).order_by("name")
123
+	for rzone in qs:
124
+		print("    %s" % (rzone.getZone(),))
125
+		servers = []
126
+		for ns in domain.nameservers.all():
127
+			servers.append(ns.name)
128
+
129
+			if ns.name not in usedNameservers and (ns.glueIPv4 or ns.glueIPv6):
130
+				# FIXME: find dns glue record duplicates in whois webif
131
+				usedNameservers.append(ns.name)
132
+				if ns.glueIPv4:
133
+					domains.append((ns.name, "A", [ns.glueIPv4]))
134
+				if ns.glueIPv6:
135
+					domains.append((ns.name, "AAAA", [ns.glueIPv6]))
136
+
137
+		rzones.append((rzone.getZone, "PTR", servers))
138
+	
139
+
140
+
141
+	newDomains = mergeDomains(domains, zoneData)
142
+	print("Add/replace", newDomains)
143
+	r = s.patch("http://potatos.portal.dn:8081/api/v1/servers/localhost/zones/dn.", data=json.dumps({'rrsets': newDomains}))
144
+	if r.status_code != 204:
145
+		raise RuntimeError("Could not update records in powerdns")
146
+
147
+	# delete old domains (except for NS/SOA of head)
148
+	domains.extend([
149
+		("dn.", "NS", []),
150
+		("dn.", "SOA", []),
151
+	])
152
+
153
+	delDomains = removeOldDomains(domains, zoneData)
154
+	print("Del", delDomains)
155
+	r = s.patch("http://potatos.portal.dn:8081/api/v1/servers/localhost/zones/dn.", data=json.dumps({'rrsets': delDomains}))
156
+	if r.status_code != 204:
157
+		raise RuntimeError("Could not update records in powerdns")
158
+
159
+	# and now for the reverse zones...
160
+	zoneData = s.get("http://potatos.portal.dn:8081/api/v1/servers/localhost/zones/dn.").json()
161
+	qs = ReverseZone.objects.annotate(nsCount=Count('nameservers')).filter(nsCount__gt=0).order_by("name")
162
+
163
+	# cycle through all domains
164
+	for domain in qs:
165
+		print("    %s" % (domain.name))
166
+		servers = []
167
+		for ns in domain.nameservers.all():
168
+			servers.append(ns.name)
169
+
170
+			if ns.name not in usedNameservers and (ns.glueIPv4 or ns.glueIPv6):
171
+				# FIXME: find dns glue record duplicates in whois webif
172
+				usedNameservers.append(ns.name)
173
+				if ns.glueIPv4:
174
+					domains.append((ns.name, "A", [ns.glueIPv4]))
175
+				if ns.glueIPv6:
176
+					domains.append((ns.name, "AAAA", [ns.glueIPv6]))
177
+
178
+		domains.append((domain.name, "NS", servers))
179
+
180
+
181
+if __name__ == '__main__':
182
+	main()

Loading…
Cancel
Save