ascension

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

commit e6cdf76f0f93a9aca8bedc5216e098ca844ff583
parent e5161d1423034ab2319fa9147e24f28ceaa068a9
Author: rexxnor <rexxnor+gnunet@brief.li>
Date:   Sat, 20 Oct 2018 19:41:56 +0200

added definitive support for IXFR

Diffstat:
Mgnsmigrator/gnsmigrator.py | 145++++++++++++++++++++++++++++++++++++++++++++++++-------------------------------
1 file changed, 88 insertions(+), 57 deletions(-)

diff --git a/gnsmigrator/gnsmigrator.py b/gnsmigrator/gnsmigrator.py @@ -288,26 +288,25 @@ class BaseMigrator(): """ Adds a SOA record to GNS """ - if not BaseMigrator.check_if_record_exists_in_zone(record, zonename): - # the dnsname is not needed - _, ttl, rdata = record - zonetuple = str(rdata).split(' ') - domain = str(".".join(domain.split('.')[:-1])) - authns, owner, serial, refresh, retry, expiry, irefresh = zonetuple - if authns[-1] == '.': - authns = authns[:-1] - if owner[-1] == '.': - owner = owner[:-1] - sp.call([GNUNET_NAMESTORE_COMMAND, - '-z', zonename, - '-a', '-n', '@', - '-t', 'SOA', - '-V', "rname=%s.%s mname=%s.%s %d,%d,%d,%d,%d" - % (authns, domain, owner, domain, - int(serial), int(refresh), int(retry), - int(expiry), int(irefresh) - ), - '-e', '%ds' % ttl]) + # needs to be added in any case + _, ttl, rdata = record + zonetuple = str(rdata).split(' ') + domain = str(".".join(domain.split('.')[:-1])) + authns, owner, serial, refresh, retry, expiry, irefresh = zonetuple + if authns[-1] == '.': + authns = authns[:-1] + if owner[-1] == '.': + owner = owner[:-1] + sp.call([GNUNET_NAMESTORE_COMMAND, + '-z', zonename, + '-a', '-n', '@', + '-t', 'SOA', + '-V', "rname=%s.%s mname=%s.%s %d,%d,%d,%d,%d" + % (authns, domain, owner, domain, + int(serial), int(refresh), int(retry), + int(expiry), int(irefresh) + ), + '-e', '%ds' % ttl]) @staticmethod def add_ns_record_to_gns(record, zonename, domain): @@ -392,12 +391,29 @@ class BaseMigrator(): return domain.split('.')[0] @staticmethod - def get_current_serial(domain): + def get_current_serial(domain, resolver=None): """ Gets the current serial for a given zone """ - soa_answer = dns.resolver.query(domain, 'SOA') - return soa_answer[0].serial + # this seems to be different from the data via AXFR + try: + soa_answer = dns.resolver.query(domain, 'SOA') + except dns.resolver.NoAnswer: + print("the domain '%s' does not exist" % domain) + master_answer = dns.resolver.query(soa_answer[0].mname, 'A') + try: + if resolver: + zone = dns.zone.from_xfr(dns.query.xfr( + resolver, domain)) + else: + zone = dns.zone.from_xfr(dns.query.xfr( + master_answer[0].address, domain)) + except dns.resolver.NoAnswer: + print("nameserver for '%s' did not answer" % domain) + except dns.exception.FormError: + print("domain '%s' does not allow xfr requests" % domain) + for soa_record in zone.iterate_rdatas(rdtype=dns.rdatatype.SOA): + return soa_record[2].serial @staticmethod def get_zone_serial(zonename): @@ -437,6 +453,7 @@ class TLDMigrator(BaseMigrator): @classmethod def __init__(cls, tld, transferns): BaseMigrator.__init__(tld) + cls.soa = None cls.tld = tld cls.transferns = transferns cls.zone = None @@ -469,48 +486,60 @@ class TLDMigrator(BaseMigrator): except sp.CalledProcessError: print("Zone %s already exists!" % domainpart) + @staticmethod + def get_zone_soa(zone): + """ + Fetches soa record from zone + """ + ret = None + for soarecord in zone.iterate_rdatas(rdtype=dns.rdatatype.SOA): + if str(soarecord[0]) == '@': + ret = soarecord + break + return ret @classmethod def mirror_zone(cls): """ Extract necessary information from Generator """ - zone = None - # And to unzip and unpickle: - - currentserial = cls.get_current_serial(cls.tld) - zoneserial = 0 - if zone: - for record in zone.iterate_rdatas(rdtype=dns.rdatatype.SOA): - zoneserial = str(record[2]).split(' ')[2].split(',')[0] - break + currentserial = int(cls.get_current_serial(cls.tld, cls.transferns)) + zoneserial = int(cls.get_zone_serial(cls.tld[:-1])) + print(zoneserial) + print(currentserial) + if zoneserial == 0: + cls.initial_zone_transfer() + cls.transfer_zone() + cls.soa = cls.get_zone_soa(cls.zone) + elif zoneserial < currentserial: + cls.initial_zone_transfer(serial=zoneserial) + cls.transfer_zone() + cls.soa = cls.get_zone_soa(cls.zone) + elif zoneserial == currentserial: + print("Nothing to do!") + sys.exit(0) + # this case should be unnecessary but AXFR SOA is not equal to direct SOA else: - if zoneserial == 0: - cls.initial_zone_transfer() - cls.transfer_zone() - elif zoneserial < currentserial and zoneserial != 0: - cls.merge_zones() - - @classmethod - def merge_zones(cls): - """ - Fetch diff and merge zones - """ - currentzone = cls.zone - partialzone = dns.zone.from_xfr(cls.zonegenerator) - for rdata in partialzone.iterate_rdatasets(dns.rdatatype.NS): - name, rdataset = rdata - current_set = currentzone.get_rdataset(name, dns.rdatatype.NS, - create=True) - current_set.union_update(rdataset) - for soarecord in partialzone.iterate_rdatas(dns.rdatatype.SOA): - name, _, rdata = soarecord - if str(name) == '@': - super().add_soa_record_to_gns(soarecord, cls.tld[:-1], cls.tld) + print("SOA serial is bigger than zone serial?") + print(zoneserial, currentserial) + sys.exit(0) + + #@classmethod + #def merge_zones(cls): + # """ + # Fetch diff and merge zones + # """ + # currentzone = cls.zone + # partialzone = dns.zone.from_xfr(cls.zonegenerator) + # for rdata in partialzone.iterate_rdatasets(dns.rdatatype.NS): + # name, rdataset = rdata + # current_set = currentzone.get_rdataset(name, dns.rdatatype.NS, + # create=True) + # current_set.union_update(rdataset) @classmethod def transfer_zone(cls, zone_factory=dns.zone.Zone, - relativize=True, check_origin=True): + relativize=True): """ Do the actual zone transfer """ @@ -537,8 +566,6 @@ class TLDMigrator(BaseMigrator): for record in rrset: record.choose_relativity(zone.origin, relativize) zrds.add(record) - if check_origin: - zone.check_origin() cls.zone = zone except Exception as transferexception: print("Error occured during Zone transfer: %s" % transferexception) @@ -593,6 +620,10 @@ class TLDMigrator(BaseMigrator): for thread in threads: thread.join() + # Add soa record to GNS once completed + soa = cls.get_zone_soa(cls.zone) + super().add_soa_record_to_gns(soa, cls.tld[:-1], cls.tld) + @staticmethod def add_record_to_gns(record, zonename, domain): """