Beispiel #1
0
 def testParse(self):
     self.assertEqual(iscpy.Explode(iscpy.ScrubComments(self.named_file)), [
         'include "/home/jcollins/roster-dns-management/test/test_data/rndc.key"',
         ';', 'options', '{', 'pid-file "test_data/named.pid"', ';', '}',
         ';', 'controls', '{', 'inet 127.0.0.1 port 35638 allow', '{',
         'localhost', ';', '}', 'keys', '{', 'rndc-key', ';', '}', ';', '}',
         ';'
     ])
     self.assertEqual(
         iscpy.ParseISCString(self.named_file), {
             'include':
             '"/home/jcollins/roster-dns-management/test/test_data/rndc.key"',
             'options': {
                 'pid-file': '"test_data/named.pid"'
             },
             'controls': [{
                 'inet 127.0.0.1 port 35638 allow': {
                     'localhost': True
                 }
             }, {
                 'keys': {
                     'rndc-key': True
                 }
             }]
         })
     self.assertEqual(
         iscpy.MakeISC(iscpy.ParseISCString(self.named_file)),
         'include "/home/jcollins/roster-dns-management/test/test_data/rndc.key";\n'
         'options { pid-file "test_data/named.pid"; };\n'
         'controls { inet 127.0.0.1 port 35638 allow { localhost; } keys { rndc-key; }; };'
     )
Beispiel #2
0
def get_isc_key():
    try:
        import iscpy
    except ImportError:
        logger.debug("", exc_info=True)
        logger.fatal(
            """The 'iscpy' module is required to read keys from isc-config file.
Alternatively set key_name/key_secret in the configuration file""")
        sys.exit(1)
    key_file = os.environ.get('DDNS_HOOK_KEY_FILE')

    # Open the key file for reading
    try:
        f = open(key_file, 'rU')
    except IOError:
        logger.debug("", exc_info=True)
        logger.fatal("""Unable to read isc-config file!
Did you set the DDNS_HOOK_KEY_FILE env?
Alternatively set key_name/key_secret in the configuration file""")
        sys.exit(1)

    # Parse the key file
    parsed_key_file = iscpy.ParseISCString(f.read())

    # Grab the keyname, cut out the substring "key "
    # and remove the extra quotes
    key_name = parsed_key_file.keys()[0][4:].strip('\"')

    # Grab the secret key
    secret = parsed_key_file.values()[0]['secret'].strip('\"')
    algorithm = parsed_key_file.values()[0]['algorithm'].strip('\"')
    f.close()

    return (key_name, algorithm, secret)
Beispiel #3
0
def get_log_location(server, conf_filename):
    """Get the log location of each server"""
    global LOG_DIR
    with open(conf_filename, "r") as fin:
        conf_dict, abcd = iscpy.ParseISCString(fin.read())

    log_location = ZONE_DIR[server] + conf_dict['logging'][
        'channel default_debug']['file'].strip('"')
    LOG_DIR[server] = log_location
Beispiel #4
0
 def testMakeISC(self):
   self.assertEqual(iscpy.MakeISC(
       {'level1': {'level2': {'level3': {'level4': {
           'test1': True, 'test2': True, 'test3': True}}}},
        'newarg': 'newval', 'new_stanza': {'test': True}}),
       'new_stanza { test; };\n'
       'level1 { level2 { level3 { level4 { test1;\n'
                                           'test3;\n'
                                           'test2; }; }; }; };\n'
       'newarg newval;')
   self.assertEqual(iscpy.MakeISC(iscpy.ParseISCString(self.named_file)),
     'acl control-hosts { 127.0.0.1/32;\n'
     '192.168.1.3/32; };\n'
     'acl admin { 192.168.1.2/32;\n'
     '192.168.1.4/32;\n'
     '192.168.0.0/16; };\n'
     'view "authorized" { zone "smtp.university.edu" { masters { 192.168.11.37; };\n'
     'type master;\n'
     'file "test_data/test_zone.db"; };\n'
     'allow-query-cache { network-authorized; };\n'
     'allow-recursion { network-authorized; };\n'
     'recursion yes;\n'
     'zone "university.edu" { check-names ignore;\n'
     'masters { 192.168.11.37; };\n'
     'type slave;\n'
     'file "test_data/university.db.bak"; };\n'
     'match-clients { network-authorized; };\n'
     'zone "." { type hint;\n'
     'file "named.ca"; };\n'
     'additional-from-cache yes;\n'
     'additional-from-auth yes; };\n'
     'controls { inet * allow { control-hosts; } keys { rndc-key; }; };\n'
     'view "unauthorized" { zone "1.210.128.in-addr.arpa" { allow-query { network-unauthorized; };\n'
     'type master;\n'
     'file "test_data/test_reverse_zone.db"; };\n'
     'recursion no;\n'
     'match-clients { network-unauthorized; };\n'
     'zone "." { type hint;\n'
     'file "named.ca"; };\n'
     'zone "0.0.127.in-addr.arpa" { masters { 192.168.1.3; };\n'
     'type slave;\n'
     'file "test_data/university.rev.bak"; };\n'
     'additional-from-cache no;\n'
     'additional-from-auth no; };\n'
     'logging { category "update-security" { "security"; };\n'
     'category "queries" { "query_logging"; };\n'
     'channel "query_logging" { syslog local5;\n'
     'severity info; };\n'
     'category "client" { "null"; };\n'
     'channel "security" { file "/var/log/named-security.log" versions 10 size 10m;\n'
     'print-time yes; }; };\n'
     'include "/etc/rndc.key";\n'
     'options { directory "/var/domain";\n'
     'recursion yes;\n'
     'allow-query { any; };\n'
     'max-cache-size 512M; };')
    def GetNamedZoneToolArgs(self, dns_server, view, zone_file_name):
        """Generates the arg flags for named-checkzone and named-compilezone
    for a specific zone-view-server combination.
     
     Inputs:
       dns_server: name of a DNS server
       view: name of a view
       zone_file_name: the file name of a zone
     
     Outputs:
       string: string of the command flags and their values for named-checkzone
               and named-compilezone.
    """
        zone_name = zone_file_name.rstrip('.db')
        server_directory = '%s/%s' % (self.root_config_dir, dns_server)
        named_file_name = '%s/named.conf.a' % server_directory
        try:
            named_file_handle = open(named_file_name, 'r')
            named_file_string = named_file_handle.read()
        finally:
            named_file_handle.close()

        named_file_dict = iscpy.ParseISCString(named_file_string)
        global_options_dict = named_file_dict['options']

        if ('view "%s"' % view not in named_file_dict):
            raise ConfigManagerError('Could not find view %s in named.conf' %
                                     view)
        view_dict = named_file_dict['view "%s"' % view]

        zone_dict = None
        for zone in view_dict:
            #Making sure we're checking a dictionary
            if (type(view_dict[zone]) == type({})):
                if ('file' in view_dict[zone].keys()):
                    if (view_dict[zone]['file'].strip('"').endswith(
                            zone_file_name)):
                        zone_dict = view_dict[zone]
                        break
        else:
            raise ConfigManagerError(
                'Could not find zone %s in view %s within named.conf' %
                (zone_name, view))

        options_dict = self.MergeOptionsDicts(global_options_dict, view_dict,
                                              zone_dict)
        additional_args = self.GenerateAdditionalNamedCheckzoneArgs(
            options_dict)

        return ' '.join(additional_args)
    def NamedHeaderChangeDirectory(self, named_conf_header, new_directory):
        """Adds/Changes directory in named.conf header

    Inputs:
      named_conf_header: string of namedconf header
      new_directory: {}

    Outputs:
      string: string of namedconf header
    """
        named_conf_header_contents = iscpy.ParseISCString(named_conf_header)
        if ('options' not in named_conf_header_contents):
            named_conf_header_contents['options'] = {}
        named_conf_header_contents['options'][
            'directory'] = '"%s"' % new_directory
        return iscpy.MakeISC(named_conf_header_contents)
Beispiel #7
0
def get_zone(server, conf_filename, relative_remote_dir='/etc/'):
    """Read DEFAULT_CONF_FILENAME and parse the config file.

    This method will read all zonefile to get every zonefile available and
    also assign ZONE_DICT which server has a certain zonefile.
    """
    global ZONE_DIR, FILE_LOCATION, ZONE_DICT, ZONE_SLAVES
    logger.debug('get_zone on: ' + server + ' ' + conf_filename + ' ' +
                 relative_remote_dir)
    with open(conf_filename, "r") as fin:
        conf_dict, abcd = iscpy.ParseISCString(fin.read())

    try:
        bind_working_dir = conf_dict['options']['directory'].strip('"') + '/'
    except KeyError:
        bind_working_dir = relative_remote_dir
    ZONE_DIR[server] = bind_working_dir

    for key in conf_dict:
        if (("zone" in key) and ("master" in conf_dict[key]['type'])):
            zone_name = re.search(r'"(.*)"', key).group(1)

            if zone_name not in IGNORED_ZONE:
                FILE_LOCATION[zone_name] = get_local_filename(
                    conf_dict[key]['file'], bind_working_dir,
                    LOCAL_MNT_DIR[server])

                ZONE_DICT[server].append(zone_name)
                ZONE_SLAVES[server][zone_name] = {}
                if "allow-transfer" in conf_dict[key]:
                    slaves = conf_dict[key]['allow-transfer'].keys()
                    for slave in slaves:
                        if slave != '':
                            ZONE_SLAVES[server][zone_name][slave] = ""

        elif ("include" in key):
            # logger.log("get include :" + strconf_dict['include'])
            for (_, value) in conf_dict['include'].items():
                local_filename = get_local_filename(value, bind_working_dir,
                                                    LOCAL_MNT_DIR[server])
                logger.debug("reading include on: " + value +
                             "\nworking dir:" + bind_working_dir)
                get_zone(server, local_filename, bind_working_dir)
Beispiel #8
0
def get_dns_config():
    """
        Function to get zone config, handle zone and associate file
    """

    # Config 
    # TODO : to put in a external config file
    zones_config_file = '/etc/named/zones.conf'

    # load bind zone config file
    zones_config = iscpy.ParseISCString(open(zones_config_file, 'r').read())

    # Build zone tab to store zone name / config file
    zone_dict = dict()

    for z in zones_config:
        zone = z.split(' ')
        # check if the dns is master for this zone
        if zones_config[z]['type'] == 'master':
            zone_name = zone[1].replace("\"", "")
            zone_file = zones_config[z]['file'].replace("\"", "")
            zone_dict.update({zone_name : {'name': zone_name, 'file': zone_file}})

    return zone_dict
Beispiel #9
0
    def post(self, request, dns_server):
        """POST Method handler, used to create a new zone record.

        This endpoint recieve the following JSON file:
        {
            "directives": {
                "directive1": "value1",
                ...
            }
            "soa_record": {
                "authoritative_server": "",
                "admin_email": "",
                "serial_no": "",
                "slv_refresh_period": "",
                "slv_retry": "",
                "slv_expire": "",
                "max_time_cache": ""
            }
            "zone": {
                "zone ZONENAME": {
                    "file": "ZONE_FILE_PATH",
                    "type": "TYPE"
                    ...
                }
            }
        }
        Note that rclass and TTL are optional.

        This endpoint will return { "status" : "ok" } if adding a new record is
        successfull and {"status" : "fail"} otherwise
        """
        try:
            # Load input parameters
            body = json.loads(request.body.decode('utf-8'))
            body_zone = body['zone']
            zone = str(body_zone.keys()[0])
            if "master" in body_zone[zone]['type']:
                body_directives = body['directives']
                body_soa = body['soa_record']


            # add_absolute_path(body_zone)
            named_file = str(LOCAL_MNT_DIR[dns_server]) + DEFAULT_CONF_FILENAME
            logger.debug("Write named file to directory " + named_file)
            # Add zone to named config file
            named_dict, named_keys = iscpy.ParseISCString(open(named_file).read())
            new_dict = iscpy.AddZone(body_zone, named_dict)
            iscpy.WriteToFile(new_dict, named_keys, named_file)

            # Make new zone file
            if "master" in body_zone[zone]['type']:
                soa = SOARecordData()
                soa.fromJSON(body_soa)
                soa_record = DNSResourceRecord("@", "", "", "SOA", soa)
                resourcerecord = []
                resourcerecord.append(soa_record)
                ns_record = DNSResourceRecord("@", "", "", "NS",
                                              RecordData(body_soa['authoritative_server']))
                resourcerecord.append(ns_record)
                new_zone = DNSZone(body_directives, resourcerecord)
                zone_file = body_zone[zone]['file'].split('"')[1]
                zone_file = ZONE_DIR[dns_server] + zone_file
                local_zone_file = zone_file.replace(REMOTE_MNT_DIR, LOCAL_MNT_DIR[dns_server], 1)
                logger.debug("Write zone file to directory " + local_zone_file)
                logger.debug("Zone to write: " + new_zone.toJSON())
                new_zone.write_to_file(local_zone_file)

            restart_bind(dns_server)

            init_data()
            return HttpResponse('{ "status" : "ok" }')
        except ValueError as v_err:
            logger.warning(v_err.args)
            logger.warning(traceback.format_exc(2) + "\n\n\n")
            return HttpResponse('{"status" : "Invalid JSON arguments"}', status=500)
        except ZoneError as z_err:
            logger.error(z_err.args)
            logger.error(traceback.format_exc() + "\n\n\n")
            return HttpResponse('{"status" : "'+str(z_err.args[0])+'"}', status=500)
        except BindError as b_err:
            logger.error(b_err.args)
            logger.error(traceback.format_exc() + "\n\n\n")
            if b_err.args[0]['file_type']:
                backup_restore_file('restore', b_err.args[0]['file_type'], b_err.args[0]['origin'], '.bak')
            return HttpResponse('{"status" : "'+str(b_err.args[0]['msg'])+'"}', status=500)
        except Exception as b_err:
            logger.error(b_err.args)
            logger.error(traceback.format_exc() + "\n\n\n")
            return HttpResponse('{"status" : "'+str(b_err)+'"}', status=500)