]> git.ipfire.org Git - ipfire-2.x.git/blobdiff - config/unbound/unbound-dhcp-leases-bridge
core186: Ship ovpnmain.cgi
[ipfire-2.x.git] / config / unbound / unbound-dhcp-leases-bridge
index 50a0e516a99e59b2dbc9e1891015e1b698bf3ddf..7f89f620a1400c5542e2d9585ffa4b658d2a115e 100644 (file)
@@ -22,6 +22,7 @@
 import argparse
 import datetime
 import daemon
+import filecmp
 import functools
 import ipaddress
 import logging
@@ -441,8 +442,11 @@ class Lease(object):
                        if address in subnet:
                                return subnets[subnet]
 
-               # Fall back to localdomain if no match could be found
-               return "localdomain"
+               # Load main settings
+               settings = self.read_settings("/var/ipfire/main/settings")
+
+               # Fall back to the host domain if no match could be found
+               return settings.get("DOMAINNAME", "localdomain")
 
        @staticmethod
        @functools.cache
@@ -511,64 +515,46 @@ class UnboundConfigWriter(object):
        def __init__(self, path):
                self.path = path
 
-               self._cached_leases = []
-
        def update_dhcp_leases(self, leases):
-               # Find any leases that have expired or do not exist any more
-               # but are still in the unbound local data
-               removed_leases = [l for l in self._cached_leases if not l in leases]
-
-               # Find any leases that have been added
-               new_leases = [l for l in leases if l not in self._cached_leases]
-
-               # End here if nothing has changed
-               if not new_leases and not removed_leases:
-                       return
-
                # Write out all leases
-               self.write_dhcp_leases(leases)
+               if self.write_dhcp_leases(leases):
+                       log.debug("Reloading Unbound...")
 
-               # Update unbound about changes
-               for l in removed_leases:
-                       try:
-                               for name, ttl, type, content in l.rrset:
-                                       log.debug("Removing records for %s" % name)
-                                       self._control("local_data_remove", name)
-
-                       # If the lease cannot be removed we will try the next one
-                       except:
-                               continue
+                       # Reload the configuration without dropping the cache
+                       self._control("reload_keep_cache")
 
-                       # If the removal was successful, we will remove it from the cache
-                       else:
-                               self._cached_leases.remove(l)
+       def write_dhcp_leases(self, leases):
+               log.debug("Writing DHCP leases...")
 
-               for l in new_leases:
-                       try:
+               with tempfile.NamedTemporaryFile(mode="w") as f:
+                       for l in sorted(leases, key=lambda x: x.ipaddr):
                                for rr in l.rrset:
-                                       log.debug("Adding new record %s" % " ".join(rr))
-                                       self._control("local_data", *rr)
+                                       f.write("local-data: \"%s\"\n" % " ".join(rr))
 
-                       # If the lease cannot be added we will try the next one
-                       except:
-                               continue
+                       # Flush the file
+                       f.flush()
 
-                       # Add lease to cache when successfully added
-                       else:
-                               self._cached_leases.append(l)
+                       # Compare if the new leases file has changed from the previous version
+                       try:
+                               if filecmp.cmp(f.name, self.path, shallow=False):
+                                       log.debug("The generated leases file has not changed")
 
-       def write_dhcp_leases(self, leases):
-               with tempfile.NamedTemporaryFile(mode="w", delete=False) as f:
-                       filename = f.name
+                                       return False
 
-                       for l in leases:
-                               for rr in l.rrset:
-                                       f.write("local-data: \"%s\"\n" % " ".join(rr))
+                               # Remove the old file
+                               os.unlink(self.path)
+
+                       # If the previous file did not exist, just keep falling through
+                       except FileNotFoundError:
+                               pass
 
                        # Make file readable for everyone
                        os.fchmod(f.fileno(), stat.S_IRUSR|stat.S_IWUSR|stat.S_IRGRP|stat.S_IROTH)
 
-               os.rename(filename, self.path)
+                       # Move the file to its destination
+                       os.link(f.name, self.path)
+
+               return True
 
        def _control(self, *args):
                command = ["unbound-control"]
@@ -582,7 +568,7 @@ class UnboundConfigWriter(object):
                        log.critical("Could not run %s, error code: %s: %s" % (
                                " ".join(command), e.returncode, e.output))
 
-                       raise
+                       raise e
 
 
 if __name__ == "__main__":
@@ -618,13 +604,14 @@ if __name__ == "__main__":
        bridge = UnboundDHCPLeasesBridge(args.dhcp_leases, args.fix_leases,
                args.unbound_leases, args.hosts)
 
-       ctx = daemon.DaemonContext(detach_process=args.daemon, stderr=sys.stderr)
-       ctx.signal_map = {
-               signal.SIGHUP  : bridge.update_dhcp_leases,
-               signal.SIGTERM : bridge.terminate,
-       }
-
-       with ctx:
+       with daemon.DaemonContext(
+               detach_process=args.daemon,
+               stderr=None if args.daemon else sys.stderr,
+               signal_map = {
+                       signal.SIGHUP  : bridge.update_dhcp_leases,
+                       signal.SIGTERM : bridge.terminate,
+               },
+       ) as daemon:
                setup_logging(daemon=args.daemon, loglevel=loglevel)
 
                bridge.run()