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):
# exists in the list of known leases. If so replace
# if with the most recent lease
for i, l in enumerate(leases):
- if l.hwaddr == lease.hwaddr:
+ if l.ipaddr == lease.ipaddr:
leases[i] = max(lease, l)
break
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:
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:
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")