#!/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)