]> Frank Brehm's Git Trees - pixelpark/admin-tools.git/commitdiff
Adding generation of config file for ACLs
authorFrank Brehm <frank.brehm@pixelpark.com>
Mon, 7 Aug 2017 16:31:45 +0000 (18:31 +0200)
committerFrank Brehm <frank.brehm@pixelpark.com>
Mon, 7 Aug 2017 16:31:45 +0000 (18:31 +0200)
pp_lib/config_named_app.py

index f5395679e01a57ee45c81d39fc71daeb7e633a56..93404dad0ce1c9144d78652b5f204ff03fe71458 100644 (file)
@@ -24,6 +24,7 @@ import tempfile
 import time
 import datetime
 import textwrap
+import ipaddress
 
 # Third party modules
 import six
@@ -38,7 +39,7 @@ from .cfg_app import PpCfgAppError, PpConfigApplication
 
 from .pidfile import PidFileError, InvalidPidFileError, PidFileInUseError, PidFile
 
-__version__ = '0.5.3'
+__version__ = '0.5.4'
 LOG = logging.getLogger(__name__)
 
 
@@ -164,6 +165,11 @@ class PpConfigNamedApp(PpConfigApplication):
         self.temp_log_cfg_file = None
         self.temp_zones_cfg_file = None
 
+        self.acls = {
+            'allow-notify': ['dnsmaster.pixelpark.com'],
+            'allow-transfer': ['dnsmaster.pixelpark.com'],
+        }
+
         description = textwrap.dedent('''\
             Generation of configuration of named (the BIND 9 name daemon).
             ''').strip()
@@ -417,6 +423,9 @@ class PpConfigNamedApp(PpConfigApplication):
             if section_name.lower() == 'named':
                 self.set_named_options(section, section_name)
 
+            if section_name.lower() == 'acl':
+                self.read_acl_lists(section, section_name)
+
         self._perform_cmdline_opts()
 
     # -------------------------------------------------------------------------
@@ -596,6 +605,19 @@ class PpConfigNamedApp(PpConfigApplication):
         if masters:
             self.zone_masters = masters
 
+    # -------------------------------------------------------------------------
+    def read_acl_lists(self, section, section_name):
+
+        if self.verbose > 2:
+            LOG.debug("Evaluating config section {n!r}:\n{s}".format(
+                n=section_name, s=pp(section)))
+
+        for acl_name in section.keys():
+
+            entries_str = section[acl_name].strip()
+            entries = self.re_split_addresses.split(entries_str)
+            self.acls[acl_name] = entries
+
     # -------------------------------------------------------------------------
     def post_init(self):
 
@@ -678,6 +700,7 @@ class PpConfigNamedApp(PpConfigApplication):
 
         LOG.info("Generating all config files in a temporary directory ...")
 
+        self.generate_acl_file()
         self.generate_named_conf()
 
         time.sleep(2)
@@ -706,6 +729,82 @@ class PpConfigNamedApp(PpConfigApplication):
             LOG.debug("Temporary LOG conf: {!r}".format(self.temp_log_cfg_file))
             LOG.debug("Temporary zones conf: {!r}".format(self.temp_zones_cfg_file))
 
+    # -------------------------------------------------------------------------
+    def generate_acl_file(self):
+
+        LOG.info("Generating {} ...".format(self.default_named_acl_cfg_file))
+
+        cur_date = datetime.datetime.now().isoformat(' ')
+
+        lines = []
+        lines.append('###############################################################')
+        lines.append('')
+        lines.append(' Bind9 configuration file for ACLs')
+        lines.append(' {}'.format(self.named_acl_cfg_file))
+        lines.append('')
+        lines.append(' Generated at: {}'.format(cur_date))
+        lines.append('')
+        lines.append('###############################################################')
+        header = textwrap.indent('\n'.join(lines), '//', lambda line: True) + '\n'
+
+        content = header
+
+        for acl_name in sorted(self.acls.keys()):
+
+            lines = []
+            lines.append('')
+            lines.append('// ---------------------------------------------------------------')
+            lines.append('acl {} {{'.format(acl_name))
+            if acl_name in ('allow-notify', 'allow-transfer'):
+                lines.append('\t// Localhost')
+                lines.append('\t127.0.0.1;')
+                if self.named_listen_on_v6:
+                    lines.append('\t::1;')
+
+            ips_done = []
+
+            for entry in self.acls[acl_name]:
+
+                hostname = entry
+                ip = None
+                ips = []
+                try:
+                    ip = ipaddress.ip_address(entry)
+                    ips.append(entry)
+                    hostname = socket.getfqdn(entry)
+                except ValueError:
+                    for info in socket.getaddrinfo(entry, 53):
+                        if info[0] not in (socket.AF_INET, socket.AF_INET6):
+                            continue
+                        if info[0] == socket.AF_INET:
+                            ips.append(info[4][0])
+                        elif self.named_listen_on_v6:
+                            ips.append(info[4][0])
+
+                if ips and hostname:
+                    lines.append('\t// {}'.format(hostname))
+                    for ip in sorted(ips):
+                        if ip not in ips_done:
+                            lines.append('\t{};'.format(ip))
+                            ips_done.append(ip)
+                else:
+                    msg = "Did not found IP address of {!r} for ACL {!r}.".format(
+                        entry, acl_name)
+                    LOG.error(msg)
+
+            lines.append('};')
+
+            content += '\n'.join(lines) + '\n'
+
+        content += '\n// vim: ts=8 filetype=named noet noai\n'
+
+        with open(self.temp_acl_cfg_file, 'w', **self.open_args) as fh:
+            fh.write(content)
+
+        if self.verbose > 2:
+            LOG.debug("Generated {!r}:\n{}".format(self.temp_acl_cfg_file, content.strip()))
+
+
     # -------------------------------------------------------------------------
     def generate_named_conf(self):