#!/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(zone["_urejevalnik"].get_rdataset(dns.rdataclass.IN, dns.rdatatype.TXT)[0].strings).decode())
except KeyError:
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, None, 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, None, 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)