Blob Blame History Raw
From 5b0c27136acbbd17ce3167341a9ca22e4397766e Mon Sep 17 00:00:00 2001
From: wouter <wouter@14dc9c71-5cc2-e011-b339-0019d10b89f4>
Date: Wed, 8 Apr 2015 13:00:10 +0000
Subject: [PATCH 2/2] - Patches from Tomas Hozza for dnssec-trigger-script:  
 Add newlines between classes to conform with PEP-8 and    increase
 readability.   Add/remove local zones in Unbound when configuring    reverse
 addr forward zones.

git-svn-id: http://www.nlnetlabs.nl/svn/dnssec-trigger/trunk@695 14dc9c71-5cc2-e011-b339-0019d10b89f4
---
 dnssec-trigger-script.in | 79 ++++++++++++++++++++++++++++++++++++++++++------
 2 files changed, 77 insertions(+), 9 deletions(-)

diff --git a/dnssec-trigger-script.in b/dnssec-trigger-script.in
index 88010e9..4cb2940 100644
--- a/dnssec-trigger-script.in
+++ b/dnssec-trigger-script.in
@@ -24,9 +24,11 @@ log.addHandler(logging.StreamHandler())
 # NetworkManager reportedly doesn't pass the PATH environment variable.
 os.environ['PATH'] = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
 
+
 class UserError(Exception):
     pass
 
+
 class Lock:
     """Lock used to serialize the script"""
 
@@ -45,6 +47,7 @@ class Lock:
     def __exit__(self, t, v, tb):
         fcntl.lockf(self.lock, fcntl.LOCK_UN)
 
+
 class Config:
     """Global configuration options"""
 
@@ -84,10 +87,12 @@ class Config:
     def flush_command(self):
         return "flush_negative" if self.keep_positive_answers else "flush_zone"
 
+
 config = Config()
 if config.debug:
     log.setLevel(logging.DEBUG)
 
+
 class ConnectionList:
     """List of NetworkManager active connections"""
 
@@ -151,6 +156,7 @@ class ConnectionList:
         # Prefer first connection
         return first
 
+
 class Connection:
     """Representation of a NetworkManager active connection"""
 
@@ -217,6 +223,7 @@ class Connection:
     def is_wifi(self):
         return self.type == "wifi"
 
+
 class UnboundZoneConfig:
     """A dictionary-like proxy object for Unbound's forward zone configuration."""
 
@@ -287,6 +294,45 @@ class UnboundZoneConfig:
         log.debug("unbound-control: {}".format(args))
         subprocess.check_call(["unbound-control"] + args, stdout=DEVNULL, stderr=DEVNULL)
 
+
+class UnboundLocalZoneConfig:
+    """A dictionary-like proxy object for Unbound's local zone configuration."""
+
+    def __init__(self):
+        subprocess.check_call(["unbound-control", "status"], stdout=DEVNULL, stderr=DEVNULL)
+        self.cache = {}
+        for line in subprocess.check_output(["unbound-control", "list_local_zones"]).decode().split('\n'):
+            if line:
+                fields = line.split(" ")
+                name = fields.pop(0).rstrip(".")
+                type = fields.pop(0)
+                self.cache[name] = type
+        log.debug(self)
+
+    def __repr__(self):
+        return "<UnboundLocalZoneConfig(data={cache})>".format(**vars(self))
+
+    def __iter__(self):
+        return iter(self.cache)
+
+    def add(self, zone, type):
+        """Install a local zone into Unbound."""
+        self.cache[zone] = type
+        self._control(["local_zone", zone, type])
+        log.debug(self)
+
+    def remove(self, zone):
+        """Remove a local zone from Unbound."""
+        if self.cache.pop(zone, None):
+            self._control(["local_zone_remove", zone])
+            log.debug(self)
+
+    @staticmethod
+    def _control(args):
+        log.debug("unbound-control: {}".format(args))
+        subprocess.check_call(["unbound-control"] + args, stdout=DEVNULL, stderr=DEVNULL)
+
+
 class Store:
     """A proxy object to access stored zones or global servers."""
 
@@ -371,8 +417,7 @@ class Application:
         "d.f.ip6.arpa",
         "168.192.in-addr.arpa",
         ] + ["{}.172.in-addr.arpa".format(octet) for octet in range(16, 32)] + [
-        "10.in-addr.arpa",
-        ] if config.use_private_address_ranges else []
+        "10.in-addr.arpa"]
 
     def __init__(self, argv):
         if len(argv) > 1 and argv[1] == '--debug':
@@ -589,18 +634,31 @@ class Application:
         with Lock():
             connections = ConnectionList(self.client, skip_wifi=not config.add_wifi_provided_zones).get_zone_connection_mapping()
             unbound_zones = UnboundZoneConfig()
+            unbound_local_zones = UnboundLocalZoneConfig()
             stored_zones = Store('zones')
 
             # Remove any zones managed by dnssec-trigger that are no longer
             # valid.
             log.debug("removing zones that are no longer valid")
             for zone in stored_zones:
-                # Remove all zones that are not in connections except those for
-                # reverse name resolution of private addresses.
-                if zone not in connections and zone not in self.rfc1918_reverse_zones:
-                    if zone in unbound_zones:
-                        unbound_zones.remove(zone)
-                    stored_zones.remove(zone)
+                # leave zones that are provided by some connection
+                if zone in connections:
+                    continue
+
+                if zone in self.rfc1918_reverse_zones:
+                    # if zone is private address range reverse zone and we are congifured to use them, leave it
+                    if config.use_private_address_ranges:
+                        continue
+                    # otherwise add Unbound local zone of type 'static' like Unbound does and remove it later
+                    else:
+                        unbound_local_zones.add(zone, "static")
+
+                # Remove all zones that are not in connections except OR
+                # are private address ranges reverse zones and we are NOT
+                # configured to use them
+                if zone in unbound_zones:
+                    unbound_zones.remove(zone)
+                stored_zones.remove(zone)
 
             # Install all zones coming from connections except those installed
             # by other means than dnssec-trigger-script.
@@ -615,7 +673,7 @@ class Application:
             # RFC1918 zones will be installed, except those already provided by connections
             # and those installed by other means than by dnssec-trigger-script.
             # RFC19118 zones will be removed if there are no global forwarders.
-            if self.rfc1918_reverse_zones:
+            if config.use_private_address_ranges:
                 log.debug("configuring RFC 1918 private zones")
                 for zone in self.rfc1918_reverse_zones:
                     # Ignore a connection provided zone as it's been already
@@ -628,6 +686,7 @@ class Application:
                         if zone in stored_zones or zone not in unbound_zones:
                             unbound_zones.add(zone, self.global_forwarders, secure=False)
                             stored_zones.add(zone)
+                            unbound_local_zones.remove(zone)
                     else:
                         # There are no global forwarders, therefore remove the zone
                         log.debug("Removing RFC 1918 private zone '%s' since there are no global forwarders", zone)
@@ -635,9 +694,11 @@ class Application:
                             unbound_zones.remove(zone)
                         if zone in stored_zones:
                             stored_zones.remove(zone)
+                        unbound_local_zones.add(zone, "static")
 
             stored_zones.commit()
 
+
 if __name__ == "__main__":
     try:
         Application(sys.argv).run()
-- 
2.1.0