From 1a460a79dd65a7571a1ffe59df9d38c9294d0cfd Mon Sep 17 00:00:00 2001
From: Zsombor Welker <fedora@zdeqb.com>
Date: Sun, 25 Apr 2021 18:55:53 +0200
Subject: [PATCH] Move systemd-resolved dbus handling into separate class

---
 src/systemd_resolved_docker/cli.py            | 17 ++++---
 .../dockerdnsconnector.py                     | 41 ---------------
 .../resolvedconnector.py                      | 51 +++++++++++++++++++
 3 files changed, 62 insertions(+), 47 deletions(-)
 create mode 100644 src/systemd_resolved_docker/resolvedconnector.py

diff --git a/src/systemd_resolved_docker/cli.py b/src/systemd_resolved_docker/cli.py
index 278259c..b216dfd 100644
--- a/src/systemd_resolved_docker/cli.py
+++ b/src/systemd_resolved_docker/cli.py
@@ -5,6 +5,7 @@ import docker
 import signal
 from systemd import daemon, journal
 
+from systemd_resolved_docker.resolvedconnector import SystemdResolvedConnector
 from .dockerdnsconnector import DockerDNSConnector
 from .utils import find_default_docker_bridge_gateway, find_docker_dns_servers
 
@@ -15,10 +16,9 @@ class Handler:
         self.log("Started daemon")
 
     def on_update(self, hosts):
-        os.system('resolvectl flush-caches')
-
         message = "Refreshed - %d items (%s)" % (
             len(hosts), ' '.join(["%s/%s" % (host.ip, ','.join(host.host_names)) for host in hosts]))
+
         self.log(message)
 
     def on_stop(self):
@@ -56,13 +56,18 @@ def main():
     handler = Handler()
     handler.log("Default domain: %s, allowed domains: %s" % (default_domain, ", ".join(domains)))
 
-    connector = DockerDNSConnector(listen_addresses, listen_port, dns_server, domains, default_domain, interface,
-                                   handler, cli)
-    connector.start()
+    resolved = SystemdResolvedConnector(interface, listen_addresses, domains)
+
+    dns_connector = DockerDNSConnector(listen_addresses, listen_port, dns_server, domains, default_domain, interface,
+                                       handler, cli)
+    dns_connector.start()
+
+    resolved.register()
 
     def sig_handler(signum, frame):
         handler.log("Stopping - %s" % signal.Signals(signum))
-        connector.stop()
+        resolved.unregister()
+        dns_connector.stop()
 
     signal.signal(signal.SIGTERM, sig_handler)
     signal.signal(signal.SIGINT, sig_handler)
diff --git a/src/systemd_resolved_docker/dockerdnsconnector.py b/src/systemd_resolved_docker/dockerdnsconnector.py
index 5cfb002..705e014 100644
--- a/src/systemd_resolved_docker/dockerdnsconnector.py
+++ b/src/systemd_resolved_docker/dockerdnsconnector.py
@@ -1,12 +1,8 @@
-import ipaddress
 import threading
-from socket import AF_INET, AF_INET6
 
-import dbus
 from dnslib import A, CLASS, DNSLabel, QTYPE, RR
 from dnslib.proxy import ProxyResolver
 from dnslib.server import DNSServer
-from pyroute2 import IPRoute
 
 from .dockerwatcher import DockerWatcher, DockerHost
 from .interceptresolver import InterceptResolver
@@ -24,7 +20,6 @@ class DockerDNSConnector:
         self.dns_domains = dns_domains
         self.docker_interface = docker_interface
         self.handler = handler
-        self.resolved_registered = False
 
         self.dns_domains_globs = ['*%s' % domain if domain.startswith('.') else domain for domain in dns_domains]
 
@@ -53,8 +48,6 @@ class DockerDNSConnector:
         self.handler.on_start()
 
     def stop(self):
-        self.update_resolved(enabled=False)
-
         for server in self.servers:
             server.stop()
 
@@ -63,39 +56,6 @@ class DockerDNSConnector:
 
         self.handler.on_stop()
 
-    def update_resolved(self, enabled=True):
-        if self.resolved_registered == enabled:
-            return
-
-        with IPRoute() as ipr:
-            ifi = ipr.link_lookup(ifname=self.docker_interface)
-            if not ifi:
-                raise ValueError("Unknown interface '%s'" % self.docker_interface)
-
-            ifindex = ifi[0]
-
-            system_bus = dbus.SystemBus()
-            proxy = system_bus.get_object('org.freedesktop.resolve1', '/org/freedesktop/resolve1')
-            manager = dbus.Interface(proxy, 'org.freedesktop.resolve1.Manager')
-
-            if enabled:
-                domains = [[domain.strip("."), True] for domain in self.dns_domains]
-                ips = [
-                    [
-                        AF_INET if isinstance(ip, ipaddress.IPv4Address) else AF_INET6,
-                        ip.packed
-                    ]
-                    for ip in [ipaddress.ip_address(ip) for ip in self.listen_addresses]
-                ]
-
-                manager.SetLinkDomains(ifindex, domains)
-                manager.SetLinkDNS(ifindex, ips)
-                manager.SetLinkDNSSEC(ifindex, "no")
-            else:
-                manager.RevertLink(ifindex)
-
-            self.resolved_registered = enabled
-
     def handle_hosts(self, hosts):
         zone = []
         host_names = []
@@ -114,7 +74,6 @@ class DockerDNSConnector:
                 host_names.append(hn)
 
         self.resolver.update(zone)
-        self.update_resolved(enabled=len(host_names) > 0)
 
         self.handler.on_update(mapped_hosts)
 
diff --git a/src/systemd_resolved_docker/resolvedconnector.py b/src/systemd_resolved_docker/resolvedconnector.py
new file mode 100644
index 0000000..cc9560a
--- /dev/null
+++ b/src/systemd_resolved_docker/resolvedconnector.py
@@ -0,0 +1,51 @@
+import ipaddress
+from socket import AF_INET, AF_INET6
+
+import dbus
+
+from pyroute2 import IPRoute
+
+
+class SystemdResolvedConnector:
+    def __init__(self, docker_interface, listen_addresses, dns_domains):
+        super().__init__()
+
+        self.docker_interface = docker_interface
+        self.listen_addresses = listen_addresses
+        self.dns_domains = dns_domains
+
+        self.ifindex = self.resolve_ifindex(docker_interface)
+
+    @staticmethod
+    def resolve_ifindex(docker_interface):
+        with IPRoute() as ipr:
+            ifi = ipr.link_lookup(ifname=docker_interface)
+            if not ifi:
+                raise ValueError("Unknown interface '%s'" % docker_interface)
+
+            return ifi[0]
+
+    @staticmethod
+    def if_manager():
+        system_bus = dbus.SystemBus()
+        proxy = system_bus.get_object('org.freedesktop.resolve1', '/org/freedesktop/resolve1')
+        return dbus.Interface(proxy, 'org.freedesktop.resolve1.Manager')
+
+    def register(self):
+        domains = [[domain.strip("."), True] for domain in self.dns_domains]
+        ips = [
+            [
+                AF_INET if isinstance(ip, ipaddress.IPv4Address) else AF_INET6,
+                ip.packed
+            ]
+            for ip in [ipaddress.ip_address(ip) for ip in self.listen_addresses]
+        ]
+
+        manager = self.if_manager()
+        manager.SetLinkDomains(self.ifindex, domains)
+        manager.SetLinkDNS(self.ifindex, ips)
+        manager.SetLinkDNSSEC(self.ifindex, "no")
+
+    def unregister(self):
+        manager = self.if_manager()
+        manager.RevertLink(self.ifindex)
-- 
GitLab