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