tldtest.net/tldtester/sorter.py

218 lines
6.9 KiB
Python

"""
This file is dumping the IANA root zone and sorting it in the database
Link to IANA website : https://www.internic.net/domain/root.zone
"""
import json
import urllib.request
from tldtester.models import TLD, RootZone
from django.core.exceptions import MultipleObjectsReturned
def zonedownloader():
"""
Downloads the root zone (as to not put constraint on the DNSses and resolve locally). Returns the zonefile in lines.
returns None if not working.
"""
url = urllib.request.urlopen("https://www.internic.net/domain/root.zone")
if url.getcode() == 200:
raw = url.read()
raw = raw.decode("utf-8")
else:
raw = None
return raw
def tlddownloader():
"""
Downloads the TLD data. Returns None if not working, returns a list of TLD's if working. Returns None if not working
"""
url = urllib.request.urlopen("https://data.iana.org/TLD/tlds-alpha-by-domain.txt")
if url.getcode() == 200:
raw = url.read()
raw = raw.decode("utf-8").splitlines()
# File has a timestamp as first line. This will take it out so we only keep the TLD's
raw.pop(0)
for i in range(len(raw)):
raw[i] = raw[i].lower()
else:
raw = None
return raw
def zonesorter(zonefile):
"""
Takes the zonefile as an input and writes the records to the database
"""
for line in zonefile:
value = ""
record = line.split()
if len(record) >= 5:
name = record[0]
recordtype = record[3]
if len(record) == 5:
value = record[4]
else:
for i in range(len(record) - 4):
value = value + record[i + 4] + " "
towrite = {"name": name, "type": recordtype, "value": value}
zonedbwriter(towrite)
def zonedbwriter(recs):
"""
Writes the Zone File to database
"""
db = RootZone()
db.name = recs["name"]
db.rectype = recs["type"]
db.value = recs["value"]
db.save()
def tlddbwriter(recs):
"""
Writes the dictionnary values in the database
"""
if TLD.objects.filter(tld=recs["tld"]).exists():
db = TLD.objects.get(tld=recs["tld"])
else:
db = TLD()
db.tld = recs["tld"]
db.unicodetld = recs["unicodeTld"]
db.nsamount = recs["nsserveramount"]
db.v4nsamount = recs["v4resolvers"]
db.v6nsamount = recs["v6resolvers"]
db.dnssec = recs["algo"]
db.amountofkeys = recs["amountofkeys"]
db.organisation = recs["organisation"]
db.link = recs["link"]
db.rdap = recs["rdap"]
db.save()
def grabber(data, rdaptlds):
"""
This function takes the TLD's and makes querrys to the DNS. It looks up how many authoritative DNS's there are and
analyses the v4, v6 and DNSSEC. Returns a list of dictionaries with all the vallues to write in the database
"""
for tld in data:
nsservers = []
dnsseckeys = []
Arecords = 0
AAAArecords = 0
amountofkeys = 0
link = "https://tldtest.net"
nses = RootZone.objects.all().filter(name=tld + ".", rectype="NS")
for ns in nses:
nsservers.append(ns.value)
for Arecord in nsservers:
try:
RootZone.objects.all().get(name=Arecord, rectype="A")
Arecords += 1
except MultipleObjectsReturned:
Arecords += 1
print("Multiple IPv4 for " + Arecord)
except:
print(Arecord + " Has no IPv4 record")
for AAAArecord in nsservers:
try:
RootZone.objects.all().get(name=AAAArecord, rectype="AAAA")
AAAArecords += 1
except MultipleObjectsReturned:
AAAArecords += 1
print("Multiple IPv6 for" + AAAArecord)
except:
print(AAAArecord + " Has no IPv6 record")
dsrec = RootZone.objects.all().filter(name=tld + ".", rectype="DS")
if len(dsrec) == 0:
# Means No DNSSEC
algo = 400
else:
try:
for ds in dsrec:
dnsseckeys.append(int(ds.value.split()[1]))
amountofkeys += 1
algo = max(dnsseckeys)
except Exception as e:
print(tld + " DNSSEC " + e)
algo = 300
# Who registers the thing and get unicode
rdap = urllib.request.urlopen("https://rdap.iana.org/domain/" + tld)
if rdap.getcode() == 200:
raw = rdap.read().decode("utf-8")
data = json.loads(raw)
try:
if "xn--" in tld:
unicodetld = data["unicodeName"]
else:
unicodetld = tld
except Exception as e:
unicodetld = tld
print(tld)
print(e)
for entity in data["entities"]:
try:
organisation = entity["vcardArray"][1][2][3]
except:
organisation = ""
try:
link = data["links"][0]["href"]
if "rdap" in link:
link = "https://icannwiki.org/." + tld
if organisation.strip() == "":
organisation = link
except Exception as e:
print("link not found for " + tld)
print(e)
link = "https://icannwiki.org/." + tld
if organisation.strip() == "":
organisation = link
if tld in rdaptlds:
rdap = "Yes"
else:
rdap = "No"
results = {"tld": tld, "unicodeTld": unicodetld, "nsserveramount": int(len((nsservers))),
"organisation": organisation, "v4resolvers": Arecords, "v6resolvers": AAAArecords, "algo": algo,
"amountofkeys": amountofkeys, "link": link, "rdap": rdap}
tlddbwriter(results)
def rdaper():
"""
Downloads the RDAP link database from IANA and creates a list of all the tlds that currently support it.
returns either a full or an empty list.
"""
rdaptlds = []
url = urllib.request.urlopen("https://data.iana.org/rdap/dns.json")
if url.getcode() == 200:
raw = url.read()
raw = raw.decode("utf-8")
else:
raw = None
data = json.loads(raw)
for i in data["services"]:
for j in i[0]:
rdaptlds.append(j)
return rdaptlds
def main():
try:
zonefile = zonedownloader().splitlines(True)
rdaptlds = rdaper()
if zonefile is not None:
# First delete the entire zone database if file polling is successful and re write
RootZone.objects.all().delete()
zonesorter(zonefile)
tlds = tlddownloader()
if tlds is not None:
grabber(tlds, rdaptlds)
except Exception as e:
print(e)
if __name__ == '__main__':
main()