From b8dd42b9a6b42d69bcabbedb962bc13ecc44d22a Mon Sep 17 00:00:00 2001 From: Michael Tremer Date: Wed, 14 Sep 2016 15:54:36 +0100 Subject: [PATCH] unbound+DHCP: Read existing leases from unbound This allows us to restart unbound and all DHCP leases will be re-imported even if the unbound-dhcp-leases-bridge is not restarted. Signed-off-by: Michael Tremer --- config/unbound/unbound-dhcp-leases-bridge | 52 ++++++++++++++++++----- 1 file changed, 41 insertions(+), 11 deletions(-) diff --git a/config/unbound/unbound-dhcp-leases-bridge b/config/unbound/unbound-dhcp-leases-bridge index 06bff2eda2..a3e16616ef 100644 --- a/config/unbound/unbound-dhcp-leases-bridge +++ b/config/unbound/unbound-dhcp-leases-bridge @@ -257,10 +257,10 @@ class Lease(object): def rrset(self): return [ # Forward record - (self.fqdn, LOCAL_TTL, "IN A", self.ipaddr), + (self.fqdn, "%s" % LOCAL_TTL, "IN A", self.ipaddr), # Reverse record - (self.ipaddr, LOCAL_TTL, "IN PTR", self.fqdn), + (self.ipaddr, "%s" % LOCAL_TTL, "IN PTR", self.fqdn), ] @@ -268,33 +268,63 @@ class UnboundConfigWriter(object): def __init__(self, path): self.path = path - self._cached_leases = [] + @property + def existing_leases(self): + local_data = self._control("list_local_data") + ret = {} + + for line in local_data.splitlines(): + try: + hostname, ttl, x, record_type, content = line.split("\t") + except ValueError: + continue + + # Ignore everything that is not A or PTR + if not record_type in ("A", "PTR"): + continue + + if hostname.endswith("."): + hostname = hostname[:-1] + + if content.endswith("."): + content = content[:-1] + + if record_type == "A": + ret[hostname] = content + elif record_type == "PTR": + ret[content] = hostname + + return ret def update_dhcp_leases(self, leases): # Strip all non-active or expired leases leases = [l for l in leases if l.active and not l.expired] # Find any leases that have expired or do not exist any more - removed_leases = [l for l in self._cached_leases if l.expired or l not in leases] + removed_leases = [] + for fqdn, address in self.existing_leases.items(): + if not fqdn in (l.fqdn for l in leases): + removed_leases += [fqdn, address] # Find any leases that have been added - new_leases = [l for l in leases if l not in self._cached_leases] + new_leases = [l for l in leases + if l.fqdn not in self.existing_leases] # End here if nothing has changed if not new_leases and not removed_leases: return - self._cached_leases = leases - # Write out all leases self.write_dhcp_leases(leases) # Update unbound about changes - for l in removed_leases: - self._control("local_data_remove", l.fqdn) + for hostname in removed_leases: + log.debug("Removing all records for %s" % hostname) + self._control("local_data_remove", hostname) for l in new_leases: for rr in l.rrset: + log.debug("Adding new record %s" % " ".join(rr)) self._control("local_data", *rr) @@ -305,11 +335,11 @@ class UnboundConfigWriter(object): f.write("local-data: \"%s\"\n" % " ".join(rr)) def _control(self, *args): - command = ["unbound-control", "-q"] + command = ["unbound-control"] command.extend(args) try: - subprocess.check_call(command) + return subprocess.check_output(command) # Log any errors except subprocess.CalledProcessError as e: -- 2.39.2