[dnssec-trigger/f20] Use new Python dispatcher script and ship /etc/dnssec.conf

Tomas Hozza thozza at fedoraproject.org
Wed Jan 29 15:55:53 UTC 2014


commit aadb7cd0950b38d0de77d1c1db755e4da9625944
Author: Tomas Hozza <thozza at redhat.com>
Date:   Wed Jan 29 16:53:39 2014 +0100

    Use new Python dispatcher script and ship /etc/dnssec.conf
    
    Signed-off-by: Tomas Hozza <thozza at redhat.com>

 01-dnssec-trigger-hook |  653 ++++++++++++++++++++++++++++++++++++++++--------
 dnssec-trigger.spec    |   19 +-
 dnssec.conf.sample     |   54 ++++
 3 files changed, 614 insertions(+), 112 deletions(-)
---
diff --git a/01-dnssec-trigger-hook b/01-dnssec-trigger-hook
index 6bc6a19..1d4953e 100755
--- a/01-dnssec-trigger-hook
+++ b/01-dnssec-trigger-hook
@@ -1,107 +1,546 @@
-#!/bin/sh
-#
-# NetworkManager trigger for in dispatcher.d
-# config items
-alias unbound-control="/usr/sbin/unbound-control"
-alias dnssec-trigger-control="/usr/sbin/dnssec-trigger-control"
-alias pidof="/usr/sbin/pidof"
-alias nmcli="/usr/bin/nmcli"
-
-state_dir="/var/run/dnssec-trigger"
-validate_forward_zones="no"
-
-# implementation
-ifname="$1"
-action="$2"
-domains=""
-nameservers=""
-global_nameservers=""
-conn_zones_file="$state_dir/$CONNECTION_UUID"
-
-################################################################
-# get domains and nameservers if provided by connection going up
-case "$action" in
-    "vpn-up" )
-        domains="`echo $VPN_IP4_DOMAINS $VPN_IP6_DOMAINS | tr " " "\n" | sort -u | tr "\n" " " | sed '$s/.$//'`"
-        nameservers="`echo $VPN_IP4_NAMESERVERS $VPN_IP6_NAMESERVERS`"
-        ;;
-    "up" )
-        domains="`echo $IP4_DOMAINS $IP6_DOMAINS | tr " " "\n" | sort -u | tr "\n" " " | sed '$s/.$//'`"
-        nameservers="`echo $IP4_NAMESERVERS $IP6_NAMESERVERS`"
-        ;;
-esac
-
-#########################
-# get global nameservers
-# try to get nmcli version
-NMCLI_VER="`nmcli -v 2> /dev/null | sed 's/.*version \([0-9]\)\.\([0-9]\)\.\([0-9]\)\.\([0-9]\).*/\1\2\3\4/'`"
-# if nmcli exists
-if [ -n $NMCLI_VER ]; then
-    # if the version is greater or equal 0.9.9.0
-    if [ $NMCLI_VER -ge 0990 ]; then
-        global_nameservers="`nmcli -f IP4,IP6 dev show | fgrep 'DNS' | awk '{print $2;}'`"
-    else
-        global_nameservers="`nmcli -f IP4,IP6 dev list | fgrep 'DNS' | awk '{print $2;}'`"
-    fi
-# nmcli does not exist
-else
-    global_nameservers="`nm-tool | grep 'DNS:' | awk '{print $2;}'`"
-fi
-# fix whitespaces
-global_nameservers="`echo $global_nameservers`"
-
-
-############################################################
-# configure global nameservers using dnssec-trigger-control
-if [ -n "`pidof dnssec-triggerd`" ] ; then
-    dnssec-trigger-control submit "$global_nameservers" &> /dev/null
-    logger "dnssec-trigger-hook(networkmanager) $ifname $action added global DNS $global_nameservers"
-else
-    logger "dnssec-trigger-hook(networkmanager) $ifname $action NOT added global DNS - dnssec-triggerd is not running"
-fi
-
-######################################################
-# add forward zones into unbound using unbound-control
-if [ -n "`pidof unbound`" ]; then
-    if [ -r "$conn_zones_file" ]; then
-        for domain in `cat $conn_zones_file`; do
-            # Remove forward zone from unbound
-            if [ "$validate_forward_zones" == "no" ]; then
-            	unbound-control forward_remove +i $domain &> /dev/null
-	    else
-            	unbound-control forward_remove $domain &> /dev/null
-	    fi
-            unbound-control flush_zone $domain &> /dev/null
-            unbound-control flush_requestlist &> /dev/null
-
-            logger "dnssec-trigger-hook(networkmanager) $ifname $action removed forward DNS zone $domain"
-        done
-
-        # Remove file with zones for this connection
-        rm -f $conn_zones_file &> /dev/null
-    fi
-
-    if [ "$action" == "vpn-up" ] || [ "$action" == "up" ]; then
-        if [ -n "$domains" ]; then
-            for domain in $domains; do
-                # Add forward zone into unbound
-                if [ "$validate_forward_zones" == "no" ]; then
-                    unbound-control forward_add +i $domain $nameservers &> /dev/null
-                else
-                    unbound-control forward_add $domain $nameservers &> /dev/null
-                fi
-                unbound-control flush_zone $domain &> /dev/null
-                unbound-control flush_requestlist &> /dev/null
-
-                # Create zone info file
-                echo $domain >> $conn_zones_file
-
-                logger "dnssec-trigger-hook(networkmanager) $ifname $action added forward DNS zone $domain $nameservers"
-            done
-        fi
-    fi
-else
-    logger "dnssec-trigger-hook(networkmanager) $ifname $action NOT added forward DNS zone(s) - unbound is not running"
-fi
- 
-exit 0
+#!/usr/bin/python2
+# -*- coding: utf-8 -*-
+"""
+ at author: Tomas Hozza <thozza at redhat.com>
+"""
+
+from gi.repository import NMClient
+import socket
+import struct
+import subprocess
+import os
+import os.path
+import syslog
+import sys
+
+
+# DO NOT CHANGE THE VALUE HERE, CHANGE IT IN **DNSSEC_CONF** file
+DEFAULT_VALIDATE_FORWARD_ZONES = True
+DEFAULT_ADD_WIFI_PROVIDED_ZONES = False
+
+STATE_DIR = "/var/run/dnssec-trigger"
+DNSSEC_CONF = "/etc/dnssec.conf"
+
+UNBOUND = "/usr/sbin/unbound"
+UNBOUND_CONTROL = "/usr/sbin/unbound-control"
+DNSSEC_TRIGGER = "/usr/sbin/dnssec-triggerd"
+DNSSEC_TRIGGER_CONTROL = "/usr/sbin/dnssec-trigger-control"
+PIDOF = "/usr/sbin/pidof"
+
+
+class FZonesConfig:
+
+    """
+    Class representing dnssec-trigger script forward zones behaviour
+    configuration.
+    """
+
+    def __init__(self):
+        self.validate_fzones = DEFAULT_VALIDATE_FORWARD_ZONES
+        self.add_wifi_zones = DEFAULT_ADD_WIFI_PROVIDED_ZONES
+
+
+class ActiveConnection:
+
+    """
+    Simple class representing NM Active Connection with information relevant
+    for this script.
+    """
+
+    TYPE_WIFI = "WIFI"
+    TYPE_VPN = "VPN"
+    TYPE_OTHER = "OTHER"
+
+    def __init__(self):
+        self.type = self.TYPE_OTHER
+        self.is_default = False
+        self.nameservers = []
+        self.domains = []
+        self.uuid = ""
+        pass
+
+    def __str__(self):
+        string = "UUID: " + self.get_uuid() + "\n"
+        string += "TYPE: " + str(self.get_type()) + "\n"
+        string += "DEFAULT: " + str(self.get_is_default()) + "\n"
+        string += "NS: " + str(self.get_nameservers()) + "\n"
+        string += "DOMAINS: " + str(self.get_domains())
+        return string
+
+    def get_uuid(self):
+        return self.uuid
+
+    def get_type(self):
+        return self.type
+
+    def get_is_default(self):
+        return self.is_default
+
+    def get_nameservers(self):
+        return self.nameservers
+
+    def get_domains(self):
+        return self.domains
+
+    def set_uuid(self, uuid=""):
+        self.uuid = uuid
+
+    def set_type(self, conn_type=TYPE_OTHER):
+        if conn_type == self.TYPE_VPN:
+            self.type = self.TYPE_VPN
+        elif conn_type == self.TYPE_WIFI:
+            self.type = self.TYPE_WIFI
+        else:
+            self.type = self.TYPE_OTHER
+
+    def set_is_default(self, is_default=True):
+        self.is_default = is_default
+
+    def set_nameservers(self, servers=[]):
+        self.nameservers = servers
+
+    def set_domains(self, domains=[]):
+        self.domains = domains
+
+
+def ip4_to_str(ip4):
+    """
+    Converts IPv4 address from integer to string.
+    """
+    return socket.inet_ntop(socket.AF_INET, struct.pack("=I", ip4))
+
+
+def ip6_to_str(ip6):
+    """
+    Converts IPv6 address from integer to string.
+    """
+    addr_struct = ip6
+    return socket.inet_ntop(socket.AF_INET6, addr_struct)
+
+
+def get_fzones_settings_from_conf(conf_file=""):
+    """
+    Reads the forward zones behaviour config from file.
+    """
+    config = FZonesConfig()
+
+    try:
+        with open(conf_file, "r") as f:
+            lines = [l.strip()
+                     for l in f.readlines() if l.strip() and not l.strip().startswith("#")]
+            for line in lines:
+                option_line = line.split("=")
+                if option_line:
+                    if option_line[0].strip() == "validate_connection_provided_zones":
+                        if option_line[1].strip() == "yes":
+                            config.validate_fzones = True
+                        else:
+                            config.validate_fzones = False
+                    elif option_line[0].strip() == "add_wifi_provided_zones":
+                        if option_line[1].strip() == "yes":
+                            config.add_wifi_zones = True
+                        else:
+                            config.add_wifi_zones = False
+    except IOError:
+        # we don't mind if the config file does not exist
+        pass
+
+    return config
+
+
+def get_nm_active_connections():
+    """
+    Process Active Connections from NM and return list of ActiveConnection
+    objects. Active Connections from NM without nameservers are ignored.
+    """
+    result = []
+    client = NMClient.Client()
+    ac = client.get_active_connections()
+
+    for connection in ac:
+        new_connection = ActiveConnection()
+
+        # get the UUID
+        new_connection.set_uuid(connection.get_uuid())
+
+        # Find out if the ActiveConnection is VPN, WIFI or OTHER
+        try:
+            connection.get_vpn_state()
+        except AttributeError:
+            # We don't need to change anything
+            pass
+        else:
+            new_connection.set_type(ActiveConnection.TYPE_VPN)
+
+        # if the connection is NOT VPN, then check if it's WIFI
+        if new_connection.get_type() != ActiveConnection.TYPE_VPN:
+            try:
+                device_type = connection.get_devices()[
+                    0].get_device_type().value_name
+            except AttributeError:
+                # We don't need to change anything
+                pass
+            else:
+                if device_type == "NM_DEVICE_TYPE_WIFI":
+                    new_connection.set_type(ActiveConnection.TYPE_WIFI)
+
+        # Finc out if default connection for IP4 or IP6
+        if connection.get_default() or connection.get_default6():
+            new_connection.set_is_default(True)
+        else:
+            new_connection.set_is_default(False)
+
+        # Get nameservers (IP4 + IP6)
+        ips = []
+        try:
+            ips4_int = connection.get_ip4_config().get_nameservers()
+        except AttributeError:
+            # we don't mind if there are no IP4 nameservers
+            pass
+        else:
+            for ip4 in ips4_int:
+                ips.append(ip4_to_str(ip4))
+        try:
+            num = connection.get_ip6_config().get_num_nameservers()
+            for i in range(0,num):
+                ips.append(ip6_to_str(connection.get_ip6_config().get_nameserver(i)))
+        except AttributeError:
+            # we don't mind if there are no IP6 nameservers
+            pass
+        new_connection.set_nameservers(ips)
+
+        # Get domains (IP4 + IP6)
+        domains = []
+        try:
+            domains.extend(connection.get_ip4_config().get_domains())
+        except AttributeError:
+            # we don't mind if there are no IP6 domains
+            pass
+        try:
+            domains.extend(connection.get_ip6_config().get_domains())
+        except AttributeError:
+            # we don't mind if there are no IP6 domains
+            pass
+        new_connection.set_domains(domains)
+
+        # If there are no nameservers in the connection, it is useless
+        if new_connection.get_nameservers():
+            result.append(new_connection)
+
+    return result
+
+
+def is_running(binary=""):
+    """
+    Checks if the given binary is running.
+    """
+    if binary:
+        sp = subprocess.Popen(PIDOF + " " + binary,
+                              stdout=subprocess.PIPE,
+                              stderr=open(os.devnull, "wb"),
+                              shell=True)
+        sp.wait()
+        if sp.returncode == 0:
+            # pidof returns "0" if at least one program with the name runs
+            return True
+    return False
+
+
+def dnssec_trigger_set_global_ns(servers=[]):
+    """
+    Configures global nameservers into dnssec-trigger.
+    """
+    if servers:
+        servers_list = " ".join(servers)
+        ret = subprocess.call(
+            DNSSEC_TRIGGER_CONTROL + " submit " + servers_list,
+            stdout=open(os.devnull, "wb"),
+            stderr=subprocess.STDOUT,
+            shell=True)
+        if ret == 0:
+            syslog.syslog(
+                syslog.LOG_INFO, "Global forwarders added: " + servers_list)
+        else:
+            syslog.syslog(
+                syslog.LOG_ERR, "Global forwarders NOT added: " + servers_list)
+
+
+def unbound_add_forward_zone(domain="", servers=[], secure=DEFAULT_VALIDATE_FORWARD_ZONES):
+    """
+    Adds a forward zone into the unbound.
+    """
+    if domain and servers:
+        servers_list = " ".join(servers)
+        # build the command
+        cmd = UNBOUND_CONTROL + " forward_add"
+        if not secure:
+            cmd += " +i"
+        cmd += " " + domain + " " + servers_list
+        # Add the forward zone
+        ret = subprocess.call(cmd,
+                              stdout=open(os.devnull, "wb"),
+                              stderr=subprocess.STDOUT,
+                              shell=True)
+        # Flush cache
+        subprocess.call(UNBOUND_CONTROL + " flush_zone " + domain,
+                        stdout=open(os.devnull, "wb"),
+                        stderr=subprocess.STDOUT,
+                        shell=True)
+        subprocess.call(UNBOUND_CONTROL + " flush_requestlist",
+                        stdout=open(os.devnull, "wb"),
+                        stderr=subprocess.STDOUT,
+                        shell=True)
+
+        if secure:
+            validated = "(DNSSEC validated)"
+        else:
+            validated = "(*NOT* DNSSEC validated)"
+
+        if ret == 0:
+            syslog.syslog(
+                syslog.LOG_INFO, "Added " + validated + " connection provided forward zone '" + domain + "' with NS: " + servers_list)
+        else:
+            syslog.syslog(
+                syslog.LOG_ERR, "NOT added connection provided forward zone '" + domain + "' with NS: " + servers_list)
+
+
+def unbound_del_forward_zone(domain="", secure=DEFAULT_VALIDATE_FORWARD_ZONES):
+    """
+    Deletes a forward zone from the unbound.
+    """
+    if domain:
+        cmd = UNBOUND_CONTROL + " forward_remove"
+        if not secure:
+            cmd += " +i"
+        cmd += " " + domain
+        # Remove the forward zone
+        ret = subprocess.call(cmd,
+                              stdout=open(os.devnull, "wb"),
+                              stderr=subprocess.STDOUT,
+                              shell=True)
+        # Flush cache
+        subprocess.call(UNBOUND_CONTROL + " flush_zone " + domain,
+                        stdout=open(os.devnull, "wb"),
+                        stderr=subprocess.STDOUT,
+                        shell=True)
+        subprocess.call(UNBOUND_CONTROL + " flush_requestlist",
+                        stdout=open(os.devnull, "wb"),
+                        stderr=subprocess.STDOUT,
+                        shell=True)
+        if ret == 0:
+            syslog.syslog(
+                syslog.LOG_INFO, "Removed connection provided forward zone '" + domain + "'")
+        else:
+            syslog.syslog(
+                syslog.LOG_ERR, "NOT removed connection provided forward zone '" + domain + "'")
+
+
+def unbound_get_forward_zones():
+    """
+    Returns list of currently configured forward zones from the unbound.
+    """
+    zones = []
+    # get all configured forward zones
+    sp = subprocess.Popen(UNBOUND_CONTROL + " list_forwards",
+                          stdout=subprocess.PIPE,
+                          stderr=open(os.devnull, "wb"),
+                          shell=True)
+
+    sp.wait()
+
+    if sp.returncode == 0:
+        for line in sp.stdout.readlines():
+            zones.append(line.strip().split(" ")[0][:-1])
+
+    return zones
+
+##############################################################################
+
+
+def append_fzone_to_file(uuid="", zone=""):
+    """
+    Append forward zones from connection with UUID to the disk file.
+    """
+    if uuid and zone:
+        with open(os.path.join(STATE_DIR, uuid), "a") as f:
+            f.write(zone + "\n")
+
+
+def write_fzones_to_file(uuid="", zones=[]):
+    """
+    Write forward zones from connection with UUID to the disk file.
+    """
+    if uuid and zones:
+        with open(os.path.join(STATE_DIR, uuid), "w") as f:
+            for zone in zones:
+                f.write(zone + "\n")
+
+
+def get_fzones_from_file(uuid=""):
+    """
+    Gets all zones from a file with specified UUID name din STATE_DIR
+    """
+    zones = []
+    if uuid:
+        with open(os.path.join(STATE_DIR, uuid), "r") as f:
+            zones = [line.strip() for line in f.readlines()]
+    return zones
+
+
+def get_fzones_from_disk():
+    """
+    Gets all forward zones from the disk STATE_DIR.
+    Return a dict of "zone" : "connection UUID"
+    """
+    zones = {}
+    conn_files = os.listdir(STATE_DIR)
+    for uuid in conn_files:
+        for zone in get_fzones_from_file(uuid):
+            zones[zone] = uuid
+    return zones
+
+
+def del_all_fzones_from_file(uuid="", secure=DEFAULT_VALIDATE_FORWARD_ZONES):
+    """
+    Removes all forward zones contained in file with UUID name in STATE_DIR.
+    """
+    if uuid:
+        with open(os.path.join(STATE_DIR, uuid), "r") as f:
+            for line in f.readlines():
+                unbound_del_forward_zone(line.strip(), secure)
+
+
+def del_fzones_for_nonexisting_conn(ac=[], secure=DEFAULT_VALIDATE_FORWARD_ZONES):
+    """
+    Removes all forward zones contained in file (in STATE_DIR) for non-existing
+    active connections.
+    """
+    ac_uuid_list = [conn.get_uuid() for conn in ac]
+    conn_files = os.listdir(STATE_DIR)
+    # Remove all non-existing connections zones
+    for uuid in conn_files:
+        if uuid not in ac_uuid_list:
+            # remove all zones from the file
+            del_all_fzones_from_file(uuid, secure)
+            # remove the file
+            os.unlink(os.path.join(STATE_DIR, uuid))
+
+
+def del_fzone_from_file(uuid="", zone=""):
+    """
+    Deletes a zone from file and writes changes into it. If there are no zones
+    left, the file is deleted.
+    """
+    if uuid and zone:
+        zones = get_fzones_from_file(uuid)
+        zones.remove(zone)
+        if zones:
+            write_fzones_to_file(uuid, zones)
+        else:
+            os.unlink(os.path.join(STATE_DIR, uuid))
+
+
+##############################################################################
+
+
+def configure_global_forwarders(active_connections=[]):
+    """
+    Configure global forwarders using dnssec-trigger-control
+    """
+    # get only default connections
+    default_conns = filter(lambda x: x.get_is_default(), active_connections)
+    # get forwarders from default connections
+    default_forwarders = []
+    for conn in default_conns:
+        default_forwarders.extend(conn.get_nameservers())
+
+    if default_forwarders:
+        dnssec_trigger_set_global_ns(default_forwarders)
+
+##############################################################################
+
+
+def configure_forward_zones(active_connections=[], fzones_config=None):
+    """
+    Configures forward zones in the unbound using unbound-control.
+    """
+    # Filter out WIFI connections if desirable
+    if not fzones_config.add_wifi_zones:
+        connections = filter(
+            lambda x: x.get_type() != ActiveConnection.TYPE_WIFI, active_connections)
+    else:
+        connections = active_connections
+    # If validate forward zones
+    secure = fzones_config.validate_fzones
+
+    # Filter active connections with domain(s)
+    conns_with_domains = filter(lambda x: x.get_domains(), connections)
+    fzones_from_ac = {}
+    # Construct dict of domain -> active connection
+    for conn in conns_with_domains:
+        # iterate through all domains in the active connection
+        for domain in conn.get_domains():
+            # if there is already such a domain
+            if domain in fzones_from_ac:
+                # if the "conn" is VPN and the conn for existing domain is not
+                if fzones_from_ac[domain].get_type() != ActiveConnection.TYPE_VPN and conn.get_type() == ActiveConnection.TYPE_VPN:
+                    fzones_from_ac[domain] = conn
+                # if none of there connections are VPNs or both are VPNs,
+                # prefer the default one
+                elif not fzones_from_ac[domain].get_is_default() and conn.get_is_default():
+                    fzones_from_ac[domain] = conn
+            else:
+                fzones_from_ac[domain] = conn
+
+    # Remove all zones which connection UUID does not match any existing AC
+    del_fzones_for_nonexisting_conn(conns_with_domains, secure)
+
+    # Remove all zones which connection UUID is different than the current AC
+    # UUID for the zone
+    fzones_from_disk = get_fzones_from_disk()
+    for zone, uuid in fzones_from_disk.iteritems():
+        connection = fzones_from_ac[zone]
+        # if the AC UUID is NOT the same as from the disk, remove the zone
+        if connection.get_uuid() != uuid:
+            unbound_del_forward_zone(zone, secure)
+            del_fzone_from_file(uuid, zone)
+
+    # get zones from unbound and delete them from fzones_from_ac
+    # there may be zones manually configured in unbound.conf and we
+    # don't want to replace them
+    unbound_zones = unbound_get_forward_zones()
+    for zone in unbound_zones:
+        try:
+            del fzones_from_ac[zone]
+        except KeyError:
+            # we don't mind if there is no such zone
+            pass
+
+    # Add forward zones that are not already configured
+    fzones_from_disk = get_fzones_from_disk()
+    for zone, connection in fzones_from_ac.iteritems():
+        if zone not in fzones_from_disk:
+            unbound_add_forward_zone(
+                zone, connection.get_nameservers(), secure)
+            append_fzone_to_file(connection.get_uuid(), zone)
+
+
+##############################################################################
+
+
+if __name__ == "__main__":
+    if not is_running(DNSSEC_TRIGGER):
+        syslog.syslog(syslog.LOG_ERR, "dnssec-triggerd daemon is not running!")
+        sys.exit(1)
+    if not is_running(UNBOUND):
+        syslog.syslog(syslog.LOG_ERR, "unbound server daemon is not running!")
+        sys.exit(1)
+
+    fzones_config = get_fzones_settings_from_conf(DNSSEC_CONF)
+
+    # Get all actove connections from NM
+    ac = get_nm_active_connections()
+    # Configure global forwarders
+    configure_global_forwarders(ac)
+    # Configure forward zones
+    configure_forward_zones(ac, fzones_config)
diff --git a/dnssec-trigger.spec b/dnssec-trigger.spec
index 07e5e5b..595bfaa 100644
--- a/dnssec-trigger.spec
+++ b/dnssec-trigger.spec
@@ -1,7 +1,7 @@
 Summary: NetworkManager plugin to update/reconfigure DNSSEC resolving
 Name: dnssec-trigger
 Version: 0.11
-Release: 18%{?dist}
+Release: 19%{?dist}
 License: BSD
 Url: http://www.nlnetlabs.nl/downloads/dnssec-trigger/
 Source: http://www.nlnetlabs.nl/downloads/dnssec-trigger/%{name}-%{version}.tar.gz
@@ -9,11 +9,14 @@ Source1:dnssec-triggerd.service
 Source2: dnssec-triggerd-keygen.service
 Source3: dnssec-trigger.conf
 # Latest NM dispatcher hook from upstream SVN
-# http://www.nlnetlabs.nl/svn/dnssec-trigger/trunk/01-dnssec-trigger-hook.sh.in
+# http://www.nlnetlabs.nl/svn/dnssec-trigger/trunk/contrib/01-dnssec-trigger-hook-new_nm
 Source4: 01-dnssec-trigger-hook
 Source5: dnssec-trigger.tmpfiles.d
 Source6: dnssec-triggerd-resolvconf-handle.sh
 Source7: dnssec-triggerd-resolvconf-handle.service
+# http://www.nlnetlabs.nl/svn/dnssec-trigger/trunk/contrib/dnssec.conf.sample
+# we turned the validation of forward zones off, to not break existing installations.
+Source8: dnssec.conf.sample
 Patch1: dnssec-trigger-0.11-improve_dialog_texts.patch
 Patch2: dnssec-trigger-842455.patch
 # https://www.nlnetlabs.nl/bugs-script/show_bug.cgi?id=489
@@ -21,7 +24,7 @@ Patch3: dnssec-trigger-0.11-nl489.patch
 Patch4: dnssec-trigger-0.11-coverity_scan.patch
 
 Requires(postun): initscripts
-Requires: ldns >= 1.6.10, NetworkManager, unbound, xdg-utils
+Requires: ldns >= 1.6.10, NetworkManager, NetworkManager-glib, unbound, xdg-utils
 Requires(pre): shadow-utils
 BuildRequires: desktop-file-utils systemd-units, openssl-devel, ldns-devel
 BuildRequires: gtk2-devel, NetworkManager-devel
@@ -71,8 +74,10 @@ install -m 0644 %{SOURCE7} %{buildroot}%{_unitdir}/%{name}d-resolvconf-handle.se
 
 desktop-file-install --dir=%{buildroot}%{_datadir}/applications dnssec-trigger-panel.desktop
 
-# overwrite the stock NM hook since there is new one in upstream SVN that has not been released yet
-cp -p %{SOURCE4} %{buildroot}/%{_sysconfdir}/NetworkManager/dispatcher.d/01-dnssec-trigger-hook
+# overwrite the stock NM hook since there is new and improved one in upstream SVN contrib/
+install -p -m 0755 %{SOURCE4} %{buildroot}/%{_sysconfdir}/NetworkManager/dispatcher.d/01-dnssec-trigger-hook
+# install the /etc/dnssec.conf
+install -p -m 0644 %{SOURCE8} %{buildroot}/%{_sysconfdir}/dnssec.conf
 
 # install the configuration for /var/run/dnssec-trigger into tmpfiles.d dir
 mkdir -p %{buildroot}%{_tmpfilesdir}
@@ -103,6 +108,7 @@ rm -rf ${RPM_BUILD_ROOT}
 
 %attr(0755,root,root) %dir %{_sysconfdir}/%{name}
 %attr(0755,root,root) %{_sysconfdir}/NetworkManager/dispatcher.d/01-dnssec-trigger-hook
+%attr(0644,root,root) %config(noreplace) %{_sysconfdir}/dnssec.conf
 %attr(0644,root,root) %config(noreplace) %{_sysconfdir}/%{name}/dnssec-trigger.conf
 %attr(0644,root,root) %config(noreplace) %{_sysconfdir}/xdg/autostart/dnssec-trigger-panel.desktop
 %dir %{_localstatedir}/run/%{name}
@@ -132,6 +138,9 @@ fi
 %systemd_postun_with_restart %{name}d.service
 
 %changelog
+* Wed Jan 29 2014 Tomas Hozza <thozza at redhat.com> - 0.11-19
+- Use new Python dispatcher script and ship /etc/dnssec.conf
+
 * Tue Jan 28 2014 Tomas Hozza <thozza at redhat.com> - 0.11-18
 - Use systemd macros instead of directly calling systemctl
 - simplify the systemd unit file for generating keys
diff --git a/dnssec.conf.sample b/dnssec.conf.sample
new file mode 100644
index 0000000..ef29603
--- /dev/null
+++ b/dnssec.conf.sample
@@ -0,0 +1,54 @@
+# validate_connection_provided_zones:
+# -----------------------------------
+# Setts if forward zones added into unbound by dnssec-trigger script
+# will be DNSSEC validated or NOT. Note that this setting is global
+# for all added forward zones..
+# Possible options are:
+#
+# validate_connection_provided_zones=yes - All connection provided zones
+#                                          configured as forward zones into
+#                                          unbound WILL BE DNSSEC validated
+#                                          (NOTE: If connection provided DNS
+#                                          servers are NOT DNSSEC capable, the
+#                                          resolving of provided zones will
+#                                          NOT work!)
+#
+# validate_connection_provided_zones=no - All connection provided zones
+#                                         configured as forward zones into
+#                                         unbound will NOT be DNSSEC validated
+#
+#
+# NOTICE: if you turn the validation OFF then all forward zones added by
+# dnssec-trigger script will NOT be DNSSEC validated. If you turn the
+# validation ON, only newly added forward zones will be DNSSEC validated.
+# Forward zones added before the change will still NOT be DNSSEC validated.
+# To force validation of previously added forward zone you need to restart
+# it. For VPNs this can be done by restart NetworkManager.
+validate_connection_provided_zones=no
+
+# add_wifi_provided_zones:
+# ------------------------
+# Setts if domains provided by WiFi connection are configured as forward zones
+# into unbound.
+# Possible options are:
+#
+# add_wifi_provided_zones=yes - Domains provided by ANY WiFi connection will
+#                               be configured as forward zones into unbound.
+#                               (NOTE: See the possible security implications
+#                               stated below!)
+#
+# add_wifi_provided_zones=no - Domains provided by ANY WiFi connection will
+#                              NOT be configured as forward zones into unbound.
+#                              (NOTE: Forward zones will be still configured
+#                              for any other type of connection!)
+#
+# NOTICE: Turning ON the addition of WiFi provided domains as forward zones
+# into unbound may have SECURITY implications such as:
+# - A WiFi access point can intentionally provide you a domain via DHCP for
+#   which it does not have authority and route all your DNS queries to its
+#   DNS servers.
+# - In addition to the previous point, if you have the DNSSEC validation
+#   of forward zones turned OFF, the WiFi provided DNS servers can spoof
+#   the IP address for domain names from the provided domain WITHOUT YOU
+#   KNOWING IT! 
+add_wifi_provided_zones=no


More information about the scm-commits mailing list