218 lines
6.9 KiB
Python
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()
|