ascension

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

commit fed58bebd10242d719d6615fa3b9e9b92bb6b7bd
parent 1cf160afcf98be8d88ba10f684541ce7cdba7026
Author: rexxnor <rexxnor+gnunet@brief.li>
Date:   Thu, 10 Jan 2019 15:05:26 +0100

added daemonization, bumped version

Diffstat:
Mascension/ascension.py | 123++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------
Msetup.py | 2+-
2 files changed, 95 insertions(+), 30 deletions(-)

diff --git a/ascension/ascension.py b/ascension/ascension.py @@ -23,12 +23,14 @@ import logging import queue import re import sys +import time import subprocess as sp import threading import dns.query import dns.resolver import dns.zone import docopt +from daemonize import Daemonize # GLOBALS GNUNET_ZONE_CREATION_COMMAND = 'gnunet-identity' @@ -77,6 +79,7 @@ class Ascender(): reverse_parsing = cls.domain.split('.')[::-1] reverse_parsing = list(filter(None, reverse_parsing)) counter = 0 + stop = len(reverse_parsing) - 1 for domainpart in reverse_parsing: pkey_lookup = sp.Popen([GNUNET_ZONE_CREATION_COMMAND, '-d'], @@ -90,6 +93,7 @@ class Ascender(): pkey_zone = pkey_zone.decode().strip() pkey_lookup.stdout.close() pkey_line.stdout.close() + # Create identity in GNUnet try: ret = sp.run([GNUNET_ZONE_CREATION_COMMAND, @@ -118,7 +122,6 @@ class Ascender(): '-u', '%s.%s' % (domainpart, reverse_parsing[counter - 1])]) - if "No results." in result.decode(): ret = sp.run([GNUNET_NAMESTORE_COMMAND, '-z', reverse_parsing[counter - 1], @@ -131,9 +134,23 @@ class Ascender(): logging.warning("failed to add record %s", domainpart) logging.warning("failed to add %s record %s", "PKEY", domainpart) + if counter == stop: + break counter += 1 + # Create the entire zone with name + if counter != 0: + zonename = cls.domain[:-1] + try: + ret = sp.run([GNUNET_ZONE_CREATION_COMMAND, + '-C', zonename], + stdout=sp.DEVNULL, + stderr=sp.DEVNULL) + logging.info("executed command: %s", " ".join(ret.args)) + except sp.CalledProcessError: + logging.info("Zone %s already exists!", domainpart) + @classmethod def get_current_serial(cls, domain, resolver=None): """ @@ -199,7 +216,7 @@ class Ascender(): Extracts records from zone and adds them to GNS """ logging.info("Starting to add records into GNS...") - zonename = cls.get_lowest_domain_part(cls.domain) + zonename = cls.domain[:-1] # Defining FIFO Queue taskqueue = queue.Queue(maxsize=5) @@ -288,9 +305,9 @@ class Ascender(): thread.join() # Add soa record to GNS once completed (updates the previous one) - #soa = cls.get_zone_soa(cls.zone) - #cls.add_soa_record_to_gns(soa, zonename, cls.domain) - #logging.info("All records have been added!") + soa = cls.get_zone_soa(cls.zone) + cls.add_soa_record_to_gns(soa, zonename, cls.domain) + logging.info("All records have been added!") @staticmethod def add_recordline_to_gns(recordline, zonename, label): @@ -371,7 +388,7 @@ class Ascender(): try: _, proto = str(label).split('.') except ValueError: - logging.warning("could not parse SRV label %s" % label) + logging.warning("could not parse SRV label %s", label) return (rdtype, None) priority, weight, destport, target = value.split(' ') @@ -404,7 +421,7 @@ class Ascender(): except sp.CalledProcessError: serial = "" soa_serial = 0 - soapattern = re.compile(r'.+\s(\d+),\d+,+\d+,\d+,\d+', re.M) + soapattern = re.compile(r'.+\s(\d+),\d+,\d+,\d+,\d+', re.M) if re.findall(soapattern, serial): soa_serial = re.findall(soapattern, serial)[0] else: @@ -412,12 +429,57 @@ class Ascender(): return soa_serial @staticmethod + def get_zone_refresh_time(zonename): + """ + Extracts the current serial from a given zone + """ + if zonename[-1] == '.': + zonename = zonename[:-1] + try: + serial = sp.check_output([GNUNET_GNS_COMMAND, + '-t', 'SOA', + '-u', '@.%s' % zonename]) + serial = serial.decode() + except sp.CalledProcessError: + serial = "" + refresh = 0 + soapattern = re.compile(r'.+\s\d+,(\d+),\d+,\d+,\d+', re.M) + if re.findall(soapattern, serial): + refresh = re.findall(soapattern, serial)[0] + else: + refresh = 0 + return refresh + + @staticmethod + def get_zone_retry_time(zonename): + """ + Extracts the current serial from a given zone + """ + if zonename[-1] == '.': + zonename = zonename[:-1] + try: + serial = sp.check_output([GNUNET_GNS_COMMAND, + '-t', 'SOA', + '-u', '@.%s' % zonename]) + serial = serial.decode() + except sp.CalledProcessError: + serial = "" + retry = 300 + soapattern = re.compile(r'.+\s\d+,\d+,(\d+),\d+,\d+', re.M) + if re.findall(soapattern, serial): + retry = re.findall(soapattern, serial)[0] + else: + retry = 300 + return retry + + @staticmethod def get_zone_soa(zone): """ Fetches soa record from zone """ ret = None for soarecord in zone.iterate_rdatas(rdtype=dns.rdatatype.SOA): + # TODO this might need improval depending on which SOA is picked if str(soarecord[0]) == '@': ret = soarecord break @@ -439,7 +501,6 @@ class Ascender(): '-t', rtype_str, '-V', str(value), '-e', '%ds' % ttl]) - print(debug) ret = sp.run([GNUNET_NAMESTORE_COMMAND, '-z', zonename, '-a', '-n', dnsname_str, @@ -496,26 +557,12 @@ class Ascender(): return True return False - @staticmethod - def get_lowest_domain_part(domain): - """ - Returns the lowest domain part in hierarchy - """ - return domain.split('.')[0] - def main(): """ Initializes object and handles arguments """ # argument parsing from docstring definition - args = docopt.docopt(__doc__, version='GNS Migrator 0.2.0') - - # Checks if GNUnet services are running - try: - sp.check_output([GNUNET_ARM_COMMAND, '-I'], timeout=1) - except sp.TimeoutExpired: - logging.critical('GNUnet Services are not running!') - sys.exit(1) + args = docopt.docopt(__doc__, version='Ascension 0.3.0') # argument parsing debug = args['--debug'] @@ -527,13 +574,31 @@ def main(): if debug: logging.basicConfig(level=logging.DEBUG) + # Checks if GNUnet services are running + try: + sp.check_output([GNUNET_ARM_COMMAND, '-I'], timeout=1) + except sp.TimeoutExpired: + logging.critical('GNUnet Services are not running!') + sys.exit(1) + # Initialize class instance ascender = Ascender(domain, transferns, port) - serial = ascender.get_zone_serial(domain) - ascender.initial_zone_transfer(serial) - ascender.bootstrap_zone() - ascender.mirror_zone() - ascender.add_records_to_gns() + + # Event loop for actual daemon + while 1: + serial = ascender.get_zone_serial(domain) + ascender.initial_zone_transfer(serial) + ascender.bootstrap_zone() + ascender.mirror_zone() + ascender.add_records_to_gns() + refresh = ascender.get_zone_refresh_time(domain) + retry = ascender.get_zone_retry_time(domain) + if refresh == 0: + time.sleep(retry) + else: + time.sleep(refresh) if __name__ == '__main__': - main() + PIDFILE = '/tmp/%s' % 'ascension' + DAEMON = Daemonize(app="ascension", pid=PIDFILE, action=main) + DAEMON.start() diff --git a/setup.py b/setup.py @@ -10,7 +10,7 @@ with open("README.md", "r") as fh: setuptools.setup( name="ascension", - version="0.1.3", + version="0.3.0", author="rexxnor", author_email="rexxnor+gnunet@brief.li", description="Tool to migrate DNS Zones to the GNU Name System",