ascension

Migrate DNS zones to the GNU Name System
Log | Files | Refs | README | LICENSE

commit ff3c9c422b5b65613e66035fe352eb177f791f45
parent 225e677789cf7a2a1e50bc56acba4899d06257c8
Author: Christian Grothoff <christian@grothoff.org>
Date:   Wed, 22 May 2019 15:09:39 +0200

implemented DNSCurve support and sub-sub-zone handling correctly, hopefully

Diffstat:
Mascension/ascension.py | 158++++++++++++++++++++++++++++++++++---------------------------------------------
1 file changed, 67 insertions(+), 91 deletions(-)

diff --git a/ascension/ascension.py b/ascension/ascension.py @@ -270,86 +270,10 @@ class Ascender(): # End of worker - # Check if a delegated zone is available in GNS as per NS record - nsrecords = self.zone.iterate_rdatasets(dns.rdatatype.NS) - - # This is broken if your NS is for ns.foo.YOURZONE as you add - # the PKEY to YOURZONE instead of to the foo.YOURZONE subzone. - # alice NS IN ns.alice - # bob NS IN ns.bob - # carol NS IN ns.alice - # => carol GNS2DNS GNS ns.alice@$IP - # dave.foo NS IN gns--pkey--$KEY.bob - # => dave.foo PKEY GNS $KEY - # foo.bar A IN 1.2.3.4 - # => bar PKEY GNS $NEWKEY + mapping: bar => $NEWKEY - # => foo[.bar] A GNS 1.2.3.4 - #gnspkey = list(filter(lambda record: for rec in record[2]: if str(rec).startswith('gns--pkey--'): return true; return false, nsrecords)) - illegalchars = ["I", "L", "O", "U", "i", "l", "o", "u"] - for nsrecord in nsrecords: - name = str(nsrecord[0]) - values = nsrecord[1] - ttl = values.ttl - - gnspkeys = list(filter(lambda record: - str(record).startswith('gns--pkey--'), - values)) - - num_gnspkeys = len(gnspkeys) - if not num_gnspkeys: - # skip empty values - continue - if num_gnspkeys > 1: - logging.critical("Detected ambiguous PKEY records for label \ - %s (not generating PKEY record)", name) - continue - - gnspkey = str(gnspkeys[0]) - # FIXME: drop all NS records under this name later! - # => new map, if entry present during NS processing, skip! - if not any(illegal in gnspkey for illegal in illegalchars): - self.add_pkey_record_to_zone(gnspkey[11:], - self.domain, - name, - ttl) - - # Unify all records under same label into a record set - customrdataset = dict() - for name, rdset in self.zone.iterate_rdatasets(): - # build lookup table for later GNS2DNS records - name = str(name) # Name could be str or DNS.name.Name - if customrdataset.get(name) is None: - work = list() - work.append(rdset) - customrdataset[name] = work - else: - customrdataset[name].append(rdset) - - for label, value in customrdataset.items(): - if value is None: - continue - - subzones = label.split('.') - label = subzones[0] - subdomain = ".".join(subzones[1:]) - zonename = "%s.%s" % (subdomain, self.domain) - - try: - if value.ttl <= self.minimum: - ttl = self.minimum - else: - ttl = value.ttl - except AttributeError: - ttl = self.minimum - - if len(subzones) > 1: - if self.subzonedict.get(zonename): - continue - else: - self.subzonedict[zonename] = (False, ttl) self.create_zone_hierarchy() + # Create one thread thread = threading.Thread(target=worker) thread.start() @@ -456,6 +380,8 @@ class Ascender(): else: value = "%s.%s" % (value, self.domain) elif rdtype == 'NS': + if self.subzonedict(str(label) + "." + zonename): + return (None, None, None) nameserver = str(record.target) if nameserver[-1] == ".": nameserver = nameserver[:-1] @@ -647,6 +573,8 @@ class Ascender(): '-e', "%ss" % ttl]) logging.info("executed command: %s", debug) if ret.returncode != 0: + # FIXME: extend gnunet-namestore to return *specific* error code for + # "record already exists", and in that case reduce log level to DEBUG here. logging.warning("failed to add PKEY record %s to %s", label, domain) #logging.warning("PKEY record %s already exists in %s", label, domain) @@ -655,27 +583,75 @@ class Ascender(): """ Creates the zone hierarchy in GNS for label """ - domain = self.domain - # Build Dictionary from GNS identities + # Extend Dictionary using GNS identities that already exist, + # checking for conflicts with information in DNS ids = sp.run([GNUNET_ZONE_CREATION_COMMAND, '-d'], stdout=sp.PIPE) domainlist = ''.join(col for col in ids.stdout.decode()).split('\n') - altdomainlist = [e for e in domainlist if domain + " " in e] + # Filter for domains relevant for us, i.e. that end in self.domain + altdomainlist = [e for e in domainlist if self.domain + " " in e] for zone in altdomainlist: zonename, _, pkey = zone.split(" ") - self.subzonedict[zonename] = (pkey, self.minimum) + if not self.subzonedict[zonename]: + self.subzonedict[zonename] = (pkey, self.minimum) + else: + pkey_ttl = self.subzonedict[zonename] + self.subzonedict[zonename] = (pkey, self.minimum) + + # Create missing zones (and add to dict) for GNS zones that are NOT DNS zones + # ("." is not a zone-cut in DNS, but always in GNS). + for name in self.zone.nodes(): + # FIXME: name not right! + subzones = name.split('.') + for i in xrange(1,length(subzones)-1): + subdomain = ".".join(subzones[i:]) + zonename = "%s.%s" % (subdomain, self.domain) + ttl = self.minimum # new record, cannot use existing one, might want to use larger value + if not self.subzonedict[zonename]: + pkey = self.create_zone_and_get_pkey(zonename + "." + self.domain) + self.subzonedict[zonename] = (pkey, ttl) + + # Check if a delegated zone is available in GNS as per NS record + # Adds NS records that contain "gns--pkey--" to dictionary + nsrecords = self.zone.iterate_rdatasets(dns.rdatatype.NS) + for nsrecord in nsrecords: + name = str(nsrecord[0]) + values = nsrecord[1] + ttl = values.ttl + + gnspkeys = list(filter(lambda record: + str(record).startswith('gns--pkey--'), + values)) + num_gnspkeys = len(gnspkeys) + if not num_gnspkeys: + # skip empty values + continue + if num_gnspkeys > 1: + logging.critical("Detected ambiguous PKEY records for label \ + %s (not generating PKEY record)", name) + continue + gnspkey = str(gnspkeys[0]) + + # FIXME: test strlen(gnspkey) "right length", theoretically: Crockford base32 decoder... + zone = name + "." + self.domain + if not self.subzonedict[zone]: + self.subzonedict[zone] = (gnspkey[11:],ttl) + else: + # This should be impossible!!? + pkey_ttl = self.subzonedict[zone] + pkey2, ttl = pkey_ttl + if pkey2 != pkey: + logging.critical("PKEY in DNS does not match PKEY in GNS for name %s", name) + continue - zonelist = self.subzonedict.items() - sortedlist = sorted(zonelist, key=lambda s: len(str(s).split('.'))) - for zone, pkeyttltuple in sortedlist: + # Generate PKEY records for all entries in subzonedict + + for zone, pkeyttltuple in self.subzonedict: pkey, ttl = pkeyttltuple - if not pkey: - domain = ".".join(zone.split('.')[1::]) - label = zone.split('.')[0] - pkey = self.create_zone_and_get_pkey(zone) - logging.info("adding zone %s with %s pkey into %s", zone, pkey, domain) - self.add_pkey_record_to_zone(pkey, domain, label, pkeyttltuple[1]) - self.subzonedict[zone] = (pkey, ttl) + domain = ".".join(zone.split('.')[1::]) + label = zone.split('.')[0] + logging.info("adding zone %s with %s pkey into %s", zone, pkey, domain) + self.add_pkey_record_to_zone(pkey, domain, label, ttl) def main(): """