This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "IPFire 2.x development tree".
The branch, next has been updated via 3ec5ba501ebe5a9579cbf4c78a6f4ee157f839ed (commit) via c7b83f9bedd69f74586627d7e5705cd6e4548239 (commit) via 5d4f3a42cea5e4224aa4ba469dd7bc182ece4b67 (commit) via 7354d2947a9a57c34502ee8d689fe52f434e525d (commit) from b8a5c2fc7b844784abb17c030615d58e9f448a56 (commit)
Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below.
- Log ----------------------------------------------------------------- commit 3ec5ba501ebe5a9579cbf4c78a6f4ee157f839ed Author: Michael Tremer michael.tremer@ipfire.org Date: Sat Oct 15 19:17:44 2016 +0200
unbound-dhcp-bridge: Only update cache when lease was added/removed
Signed-off-by: Michael Tremer michael.tremer@ipfire.org
commit c7b83f9bedd69f74586627d7e5705cd6e4548239 Author: Michael Tremer michael.tremer@ipfire.org Date: Sat Oct 15 19:08:22 2016 +0200
unbound-dhcp-bridge: Rewrite update algorithm
Before the bridge tries reading any existing leases from unbound but this makes it difficult to destinguish between what is a DHCP lease, static host entry or anything else.
This patch will change the bridge back to just remember what has been added to the cache already which makes it easier to keep track.
Signed-off-by: Michael Tremer michael.tremer@ipfire.org
commit 5d4f3a42cea5e4224aa4ba469dd7bc182ece4b67 Author: Michael Tremer michael.tremer@ipfire.org Date: Sat Oct 15 19:06:27 2016 +0200
unbound-dhcp-bridge: Skip processing leases with empty hostname
Signed-off-by: Michael Tremer michael.tremer@ipfire.org
commit 7354d2947a9a57c34502ee8d689fe52f434e525d Author: Michael Tremer michael.tremer@ipfire.org Date: Sat Oct 15 17:03:31 2016 +0200
unbound-dhcp-bridge: Reading in static hosts
Signed-off-by: Michael Tremer michael.tremer@ipfire.org
-----------------------------------------------------------------------
Summary of changes: config/unbound/unbound-dhcp-leases-bridge | 156 ++++++++++++++++++++---------- 1 file changed, 106 insertions(+), 50 deletions(-)
Difference in files: diff --git a/config/unbound/unbound-dhcp-leases-bridge b/config/unbound/unbound-dhcp-leases-bridge index 91bdb4f..4804dba 100644 --- a/config/unbound/unbound-dhcp-leases-bridge +++ b/config/unbound/unbound-dhcp-leases-bridge @@ -64,9 +64,10 @@ def reverse_pointer_to_ip_address(rr): return ".".join(parts)
class UnboundDHCPLeasesBridge(object): - def __init__(self, dhcp_leases_file, fix_leases_file, unbound_leases_file): + def __init__(self, dhcp_leases_file, fix_leases_file, unbound_leases_file, hosts_file): self.leases_file = dhcp_leases_file self.fix_leases_file = fix_leases_file + self.hosts_file = hosts_file
self.unbound = UnboundConfigWriter(unbound_leases_file) self.running = False @@ -75,10 +76,15 @@ class UnboundDHCPLeasesBridge(object): log.info("Unbound DHCP Leases Bridge started on %s" % self.leases_file) self.running = True
- # Initially read leases file + # Initial setup + self.hosts = self.read_static_hosts() self.update_dhcp_leases()
- i = inotify.adapters.Inotify([self.leases_file, self.fix_leases_file]) + i = inotify.adapters.Inotify([ + self.leases_file, + self.fix_leases_file, + self.hosts_file, + ])
for event in i.event_gen(): # End if we are requested to terminate @@ -92,6 +98,10 @@ class UnboundDHCPLeasesBridge(object):
# Update leases after leases file has been modified if "IN_MODIFY" in type_names: + # Reload hosts + if watch_path == self.hosts_file: + self.hosts = self.read_static_hosts() + self.update_dhcp_leases()
# If the file is deleted, we re-add the watcher @@ -104,13 +114,72 @@ class UnboundDHCPLeasesBridge(object): leases = []
for lease in DHCPLeases(self.leases_file): + # Don't bother with any leases that don't have a hostname + if not lease.fqdn: + continue + leases.append(lease)
for lease in FixLeases(self.fix_leases_file): leases.append(lease)
+ # Skip any leases that also are a static host + leases = [l for l in leases if not l.fqdn in self.hosts] + + # Remove any inactive or expired leases + leases = [l for l in leases if l.active and not l.expired] + + # Dump leases + if leases: + log.debug("DHCP Leases:") + for lease in leases: + log.debug(" %s:" % lease.fqdn) + log.debug(" State: %s" % lease.binding_state) + log.debug(" Start: %s" % lease.time_starts) + log.debug(" End : %s" % lease.time_ends) + if lease.expired: + log.debug(" Expired") + self.unbound.update_dhcp_leases(leases)
+ def read_static_hosts(self): + log.info("Reading static hosts from %s" % self.hosts_file) + + hosts = {} + with open(self.hosts_file) as f: + for line in f.readlines(): + line = line.rstrip() + + try: + enabled, ipaddr, hostname, domainname = line.split(",") + except: + log.warning("Could not parse line: %s" % line) + continue + + # Skip any disabled entries + if not enabled == "on": + continue + + if hostname and domainname: + fqdn = "%s.%s" % (hostname, domainname) + elif hostname: + fqdn = hostname + elif domainname: + fqdn = domainname + + try: + hosts[fqdn].append(ipaddr) + hosts[fqdn].sort() + except KeyError: + hosts[fqdn] = [ipaddr,] + + # Dump everything in the logs + log.debug("Static hosts:") + for hostname, addresses in hosts.items(): + log.debug(" %-20s : %s" % (hostname, ", ".join(addresses))) + + return hosts + def terminate(self): self.running = False
@@ -403,51 +472,15 @@ class UnboundConfigWriter(object): def __init__(self, path): self.path = path
- @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] = reverse_pointer_to_ip_address(hostname) - - return ret + self._cached_leases = []
def update_dhcp_leases(self, leases): - # Cache all expired or inactive leases - expired_leases = [l for l in leases if l.expired or not l.active] - # Find any leases that have expired or do not exist any more # but are still in the unbound local data - removed_leases = [] - for fqdn, address in self.existing_leases.items(): - if fqdn in (l.fqdn for l in expired_leases): - removed_leases += [fqdn, address] - - # Strip all non-active or expired leases - leases = [l for l in leases if l.active and not l.expired] + 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.fqdn not in self.existing_leases] + 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: @@ -457,15 +490,33 @@ class UnboundConfigWriter(object): self.write_dhcp_leases(leases)
# Update unbound about changes - for hostname in removed_leases: - log.debug("Removing all records for %s" % hostname) - self._control("local_data_remove", hostname) + 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 + + # If the removal was successful, we will remove it from the cache + else: + self._cached_leases.remove(l)
for l in new_leases: - for rr in l.rrset: - log.debug("Adding new record %s" % " ".join(rr)) - self._control("local_data", *rr) + try: + for rr in l.rrset: + log.debug("Adding new record %s" % " ".join(rr)) + self._control("local_data", *rr)
+ # If the lease cannot be added we will try the next one + except: + continue + + # Add lease to cache when successfully added + else: + self._cached_leases.append(l)
def write_dhcp_leases(self, leases): with open(self.path, "w") as f: @@ -478,13 +529,15 @@ class UnboundConfigWriter(object): command.extend(args)
try: - return subprocess.check_output(command) + subprocess.check_output(command)
# Log any errors except subprocess.CalledProcessError as e: log.critical("Could not run %s, error code: %s: %s" % ( " ".join(command), e.returncode, e.output))
+ raise +
if __name__ == "__main__": parser = argparse.ArgumentParser(description="Bridge for DHCP Leases and Unbound DNS") @@ -501,6 +554,8 @@ if __name__ == "__main__": metavar="PATH", help="Path to the unbound configuration file") parser.add_argument("--fix-leases", default="/var/ipfire/dhcp/fixleases", metavar="PATH", help="Path to the fix leases file") + parser.add_argument("--hosts", default="/var/ipfire/main/hosts", + metavar="PATH", help="Path to static hosts file")
# Parse command line arguments args = parser.parse_args() @@ -515,7 +570,8 @@ if __name__ == "__main__":
setup_logging(loglevel)
- bridge = UnboundDHCPLeasesBridge(args.dhcp_leases, args.fix_leases, args.unbound_leases) + bridge = UnboundDHCPLeasesBridge(args.dhcp_leases, args.fix_leases, + args.unbound_leases, args.hosts)
ctx = daemon.DaemonContext(detach_process=args.daemon) ctx.signal_map = {
hooks/post-receive -- IPFire 2.x development tree