summaryrefslogblamecommitdiffstats
path: root/skripti/zone/update.py
blob: 34a4e39b7d7bd93780606a68aade4670bc96164a (plain) (tree)













































































































































































                                                                                                                                                                                                                  
#!/usr/bin/python3
import dns.zone
import dns.resolver
import dns.update
import dns.tsigkeyring
import json
import sys
import math
with open(sys.argv[1], "r") as db:
	lines = db.readlines()
newconfig = json.loads(lines.pop(0)[:-1])
domena = newconfig["d"]
strežniki = [dns.resolver.resolve(domena, "SOA")[0].mname]
naslovi = []
for strežnik in strežniki:
	for i in dns.resolver.resolve(strežnik, "AAAA"):
		naslovi.append(i.address)
	for i in dns.resolver.resolve(strežnik, "A"):
		naslovi.append(i.address)
for naslov in naslovi: # opcijsko dodaj tule kakšen try catch
	zone = None
	zone = dns.zone.from_xfr(dns.query.xfr(naslov, domena))
	if zone != None:
		break
config = None
try:
	config = json.loads(b''.join(dns.resolver.resolve("_urejevalnik." + domena, "TXT")[0].strings).decode())
except dns.resolver.NXDOMAIN:
	pass
except json.decoder.JSONDecodeError:
	pass
if config == None:
	config = {"v": 0, "d": domena, "c": {}, "t": 1, "+": 100, "i": {}}
rrs = []
for r in zone.iterate_rdatas():
	if r[0].to_unicode() == "_urejevalnik" or r[2].rdtype in [dns.rdatatype.RRSIG, dns.rdatatype.NSEC, dns.rdatatype.NSEC3, dns.rdatatype.DNSKEY]:
		continue
	commentkey = r[0].to_unicode() + " " + r[2].rdtype.name
	komentar = ""
	if commentkey in config["c"].keys():
		komentar = config["c"][commentkey]
		del config["c"][commentkey]
	konec = "\t"
	if r[0].to_unicode() in config["i"].keys():
		konec = config["i"][r[0].to_unicode()]
	vrednost = ""
	if r[2].rdtype == dns.rdatatype.TXT:
		for string in r[2].strings:
			bajti = b''
			for char in string:
				if char < ord(b' '):
					bajti += b'\\' + ("%03d" % ord(char)).encode()
				else:
					bajti += bytes([char])
			niz = ""
			for znak in bajti.replace(b'\\', b'\\\\').replace(b'"', b'\\"').decode('utf-8', errors='surrogateescape'):
				if '\udc80' <= znak <= '\udcff':
					niz += '\\'+("%03d" % (ord(znak)-0xdc00))
				else:
					niz += znak
			vrednost = '"' + niz + '"'
	else:
		vrednost = r[2].to_text()
	rrs.append((r[1], r[0].to_unicode(), komentar, konec, r[2].rdclass, r[2].rdtype, vrednost))
komentar = ""
lineno = 1
novikomentarji = {}
novikonci = {}
keyring = None
plus = 0
minus = 0
if len(sys.argv) == 3:
	with open(sys.argv[2]) as file:
		ključ = file.read()
	keyring = dns.tsigkeyring.from_text({ključ.split()[ključ.split().index("key")+1].replace('"', "").replace(";", ""): ključ.split()[ključ.split().index("secret")+1].replace('"', "").replace(";", "")})
update = dns.update.Update(domena, keyring=keyring)
while True:
	try:
		lineno += 1
		line = lines.pop(0)[:-1] # odstranimo zadnji \n, ki ga zraven da .readlines
		if len(line.split()) == 0 or line[0] == ';' or line[0] == '#' or line[0] == '/':
			komentar += line + "\n"
			continue
		ime = line.split()[0]
		konec = ""
		index = len(ime)
		while line[index] in ["\t", " "]:
			konec += line[index]
			index += 1
		nizi = line.split()[1:]
		tip = None
		razred = None
		ttl = None
		while tip == None:
			try:
				ttl = int(nizi[0])
				nizi.pop(0)
			except ValueError:
				pass
			try:
				razred = dns.rdataclass.from_text(nizi[0])
				nizi.pop(0)
			except dns.rdataclass.UnknownRdataclass:
				pass
			try:
				tip = dns.rdatatype.from_text(nizi[0])
				for i in [" ", "\t"]:
					for j in [" ", "\t"]:
						try:
							datastart = line.index(i+nizi[0]+j)+len(i+nizi[0]+i)
						except ValueError:
							continue
						break
					else:
						continue
					break
				nizi.pop(0)
			except dns.rdatatype.UnknownRdatatype:
				pass
		if tip == None:
			print(f"NAPAKA: na vrstici {lineno} ne najdem tipa zapisa. Vrstica je lahko bodisi komentar, ki se začne z ';', bodisi je v obliki IME [TTL={newconfig["t"]}] [CLASS=IN] TIP PODATKI.")
			print(f"Vsebina neveljavne vrstice: " + line)
			sys.exit(1)
		while line[datastart] in [" ", "\t"]:
			datastart += 1
		data = line[datastart:]
		if razred == None:
			razred = dns.rdataclass.IN
		if ttl == None:
			ttl = newconfig["t"]
		ime = dns.name.from_unicode(ime, dns.name.from_unicode(domena)).choose_relativity(dns.name.from_unicode(domena), True).to_unicode()
		if tip == dns.rdatatype.SOA:
			data = data.split()
			data[2] = str(int(data[2])+newconfig["+"])
			data = " ".join(data)
		tapl = (ttl, ime, komentar, konec, razred, tip, data)
		if komentar != "":
			novikomentarji[ime + " " + tip.to_text(tip)] = komentar
		if konec != "\t":
			novikonci[ime] = konec
		if not tapl in rrs:
			print("+ " + komentar.replace("\n", "\n+ ") + ime + konec + str(ttl) + "\t" + razred.to_text(razred) + "\t" + tip.to_text(tip) + "\t" + data)
			plus += 1
			update.add(ime, ttl, tip, data)
		else:
			rrs.remove(tapl)
		komentar = ""
	except IndexError:
		break
obstoječ = "" # zadnji komentar
for komentar in config["c"].values():
	obstoječ += komentar
for rr in rrs:
	print("- " + komentar.replace("\n", "\n- ") + rr[1] + konec + str(rr[0]) + "\t" + rr[4].to_text(rr[4]) + "\t" + rr[5].to_text(rr[5]) + "\t" + rr[6])
	minus += 1
	update.delete(rr[1], rr[5].to_text(rr[5]), rr[6])
if obstoječ != komentar:
	print("- " + "\n+ ".join(obstoječ.split("\n")))
	print("+ " + "\n+ ".join(komentar.split("\n")))
	plus += 1
	minus += 1
novikomentarji["z"] = komentar
newconfig["c"] = novikomentarji
newconfig["i"] = novikonci
odziv = input(f"(-{minus}/+{plus}) Ali želite te spremembe poslati na strežnik? [Y/D/J/n] ")
if len(odziv) != 0 and odziv[0] in ["n", "N", "0", "f", "F"]:
	print("Prekinjam. Nasvidenje!")
	sys.exit(0)
jason = json.dumps(newconfig)
jasonsplit = " ".join(['"' + jason[i*255:i*255+255].replace("\\", "\\\\").replace('"', '\\"') + '"' for i in range(math.ceil(len(jason)/255))])
update.replace("_urejevalnik", 1, dns.rdatatype.TXT, jasonsplit)
response = dns.query.tcp(update, naslov)
print("Poslal zahtevo. Odziv strežnika:")
print(response)