ascension

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

commit 65d94cf4300305b946f8ab5b78d8a082c6deb3a4
parent e6cdf76f0f93a9aca8bedc5216e098ca844ff583
Author: rexxnor <rexxnor+gnunet@brief.li>
Date:   Wed, 24 Oct 2018 21:28:30 +0200

unstable version, port specification possible

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

diff --git a/gnsmigrator/gnsmigrator.py b/gnsmigrator/gnsmigrator.py @@ -3,11 +3,15 @@ Usage: gnsmigrator.py -t <tld> -ns <transferns> + gnsmigrator.py -t <tld> -ns <transferns> -p <port> gnsmigrator.py -f <txtfile> + gnsmigrator.py -f <txtfile> -p <port> + gnsmigrator.py -f <txtfile> -p <port> -ns <transferns> gnsmigrator.py -h | --help gnsmigrator.py -v | --version Options: + <port> Port specification <tld> Top level domain to migrate <txtfile> Text File containing domains to transfer <transferns> DNS Server that does the zone transfer @@ -64,12 +68,13 @@ class BaseMigrator(): Base class for migration """ @classmethod - def __init__(cls, domainlist): + def __init__(cls, domainlist, port=53): cls.domainlist = domainlist + cls.port = port cls.zones = {} @classmethod - def initial_zone_transfer(cls): + def initial_zone_transfer(cls, resolver=None): """ Fetch all the zones via zone transfer """ @@ -83,20 +88,35 @@ class BaseMigrator(): master_answer = dns.resolver.query(soa_answer[0].mname, 'A') try: - zone = dns.zone.from_xfr(dns.query.xfr( - master_answer[0].address, domain)) + if resolver: + zone = dns.zone.from_xfr(dns.query.xfr( + resolver, domain, port=cls.port)) + else: + zone = dns.zone.from_xfr(dns.query.xfr( + master_answer[0].address, domain, + port=cls.port)) except dns.resolver.NoAnswer: print("nameserver for '%s' did not answer" % domain) continue except dns.exception.FormError: print("domain '%s' does not allow xfr requests" % domain) continue - cls.zones[domain] = (zone, - (master_answer[0].address, - domain, - zone.get_rdataset('@', dns.rdatatype.SOA).ttl, - 0) - ) + if resolver: + cls.zones[domain] = (zone, + (resolver, + domain, + zone.get_rdataset('@', + dns.rdatatype.SOA).ttl, + 0) + ) + else: + cls.zones[domain] = (zone, + (master_answer[0].address, + domain, + zone.get_rdataset('@', + dns.rdatatype.SOA).ttl, + 0) + ) @classmethod def refresh_zone(cls, domain, zonetuple): @@ -120,20 +140,16 @@ class BaseMigrator(): .split(' ')[5]) xfrinfo[3] = 1 - # A normal BIND9 returns a normal AXFR response with the entire zone - # if the serial is newer. This is why there is no real incremental - # zone transfer using bind. This makes the merger_zones function - # unnecessary. Furthermore this try except block updates only if - # there is a newer zone availible (according to serial). The IXFR - # returns only a SOA record with a new serial if it has not changed try: newzone = dns.zone.from_xfr(dns.query.xfr(xfrinfo[0], xfrinfo[1], rdtype=dns.rdatatype.IXFR, serial=oldserial)) - cls.zones[domain] = (newzone, (xfrinfo[0], - xfrinfo[1], - zone.get_rdataset('@', dns.rdatatype.SOA).ttl)) + cls.zones[domain] = (newzone, + (xfrinfo[0], + xfrinfo[1], + zone.get_rdataset('@', + dns.rdatatype.SOA).ttl)) except dns.zone.NoNS: print('the zone for domain %s was not updated' % domain) @@ -213,6 +229,7 @@ class BaseMigrator(): BaseMigrator.add_ns_record_to_gns(record, zonename, domain) elif rtype_str == 'MX': BaseMigrator.add_mx_record_to_gns(record, zonename) + # TODO Add support for SRV records #elif rtype_str == 'SRV': # BaseMigrator.add_srv_record_to_gns(record, zonename) elif rtype_str in ['A', 'AAAA']: @@ -390,12 +407,13 @@ class BaseMigrator(): """ return domain.split('.')[0] - @staticmethod - def get_current_serial(domain, resolver=None): + @classmethod + def get_current_serial(cls, domain, resolver=None): """ Gets the current serial for a given zone """ - # this seems to be different from the data via AXFR + # SOA is different if taken directly from SOA record + # compared to AXFR/IXFR - changed to respect this try: soa_answer = dns.resolver.query(domain, 'SOA') except dns.resolver.NoAnswer: @@ -404,10 +422,11 @@ class BaseMigrator(): try: if resolver: zone = dns.zone.from_xfr(dns.query.xfr( - resolver, domain)) + resolver, domain, port=cls.port)) else: zone = dns.zone.from_xfr(dns.query.xfr( - master_answer[0].address, domain)) + master_answer[0].address, domain, + port=cls.port)) except dns.resolver.NoAnswer: print("nameserver for '%s' did not answer" % domain) except dns.exception.FormError: @@ -443,16 +462,16 @@ class ZoneMigrator(BaseMigrator): Class that migrates small zones efficiently """ @classmethod - def __init__(cls, domainlist): - BaseMigrator.__init__(domainlist) + def __init__(cls, domainlist, port=53): + BaseMigrator.__init__(domainlist, port) class TLDMigrator(BaseMigrator): """ Class that migrates big zones (TLDs) efficiently """ @classmethod - def __init__(cls, tld, transferns): - BaseMigrator.__init__(tld) + def __init__(cls, tld, transferns, port=53): + BaseMigrator.__init__(tld, port) cls.soa = None cls.tld = tld cls.transferns = transferns @@ -468,7 +487,8 @@ class TLDMigrator(BaseMigrator): cls.zonegenerator = dns.query.xfr(cls.transferns, cls.tld, rdtype=dns.rdatatype.IXFR, - serial=serial) + serial=serial, + port=cls.port) else: cls.zonegenerator = dns.query.xfr(cls.transferns, cls.tld,) @@ -518,28 +538,14 @@ class TLDMigrator(BaseMigrator): elif zoneserial == currentserial: print("Nothing to do!") sys.exit(0) - # this case should be unnecessary but AXFR SOA is not equal to direct SOA + # should be unnecessary but AXFR SOA is not equal to direct SOA else: 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): + def transfer_zone(cls, zone_factory=dns.zone.Zone, relativize=True): """ Do the actual zone transfer """ @@ -595,7 +601,7 @@ class TLDMigrator(BaseMigrator): authns = "%s.%s" % (authns, zonename) # building gns record struct - #GNUnetGNSRecordData() + # GNUnetGNSRecordData() cls.add_record_to_gns(record, zonename, cls.tld) taskqueue.task_done() @@ -623,6 +629,7 @@ class TLDMigrator(BaseMigrator): # 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) + print("All records have been added!") @staticmethod def add_record_to_gns(record, zonename, domain): @@ -670,9 +677,10 @@ def main(): tld = args.get('<tld>', None) transferns = args.get('<transferns>', None) txtfile = args.get('<txtfile>', None) + port = int(args.get('<port>', None)) if tld and transferns: - migrator = TLDMigrator(tld, transferns) + migrator = TLDMigrator(tld, transferns, port) serial = migrator.get_zone_serial(tld) migrator.initial_zone_transfer(serial) migrator.bootstrap_zone() @@ -684,8 +692,8 @@ def main(): with open(txtfile, 'r') as openedtxt: for line in openedtxt: domainlist.append(line.rstrip()) - zonemigrator = ZoneMigrator(domainlist) - zonemigrator.initial_zone_transfer() + zonemigrator = ZoneMigrator(domainlist, port=port) + zonemigrator.initial_zone_transfer(resolver=transferns) zonemigrator.bootstrap_zones() for domain, zonetuple in zonemigrator.zones.items(): zonemigrator.refresh_zone(domain, zonetuple)