From 9f9d4e3c74ba61783dad3ddcedbc9b920b67a327 Mon Sep 17 00:00:00 2001 From: Arne Fitzenreiter Date: Thu, 13 Oct 2016 17:21:28 +0200 Subject: [PATCH 1/9] unbound/dhcp: stop lease bridge if dhcp was needed to killed Signed-off-by: Arne Fitzenreiter Signed-off-by: Michael Tremer --- src/initscripts/init.d/dhcp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/initscripts/init.d/dhcp b/src/initscripts/init.d/dhcp index 2182bc4b3..2ae86db31 100644 --- a/src/initscripts/init.d/dhcp +++ b/src/initscripts/init.d/dhcp @@ -58,7 +58,6 @@ case "$1" in killall -w -s KILL /usr/sbin/dhcpd > /dev/null 2>&1 rm -f /var/run/dhcpd.pid > /dev/null 2>&1 echo_ok; - exit 0 fi boot_mesg "Stopping Unbound DHCP Leases Bridge..." From 901e172c91a4a74de635d931839effd03851418d Mon Sep 17 00:00:00 2001 From: Michael Tremer Date: Sat, 15 Oct 2016 17:03:31 +0200 Subject: [PATCH 2/9] unbound-dhcp-bridge: Reading in static hosts Signed-off-by: Michael Tremer --- config/unbound/unbound-dhcp-leases-bridge | 59 +++++++++++++++++++++-- 1 file changed, 55 insertions(+), 4 deletions(-) diff --git a/config/unbound/unbound-dhcp-leases-bridge b/config/unbound/unbound-dhcp-leases-bridge index 91bdb4f36..78504f3fe 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 @@ -111,6 +121,44 @@ class UnboundDHCPLeasesBridge(object): 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 @@ -501,6 +549,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 +565,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 = { From cd4437eaa76be37161820c37725dd788f57c0ac2 Mon Sep 17 00:00:00 2001 From: Michael Tremer Date: Sat, 15 Oct 2016 19:06:27 +0200 Subject: [PATCH 3/9] unbound-dhcp-bridge: Skip processing leases with empty hostname Signed-off-by: Michael Tremer --- config/unbound/unbound-dhcp-leases-bridge | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/config/unbound/unbound-dhcp-leases-bridge b/config/unbound/unbound-dhcp-leases-bridge index 78504f3fe..70da1e031 100644 --- a/config/unbound/unbound-dhcp-leases-bridge +++ b/config/unbound/unbound-dhcp-leases-bridge @@ -114,6 +114,10 @@ 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): From a3f77ded659c607ea1c00e9500aece0418ec5c4a Mon Sep 17 00:00:00 2001 From: Michael Tremer Date: Sat, 15 Oct 2016 19:08:22 +0200 Subject: [PATCH 4/9] 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 --- config/unbound/unbound-dhcp-leases-bridge | 69 +++++++++-------------- 1 file changed, 27 insertions(+), 42 deletions(-) diff --git a/config/unbound/unbound-dhcp-leases-bridge b/config/unbound/unbound-dhcp-leases-bridge index 70da1e031..a41354349 100644 --- a/config/unbound/unbound-dhcp-leases-bridge +++ b/config/unbound/unbound-dhcp-leases-bridge @@ -123,6 +123,23 @@ class UnboundDHCPLeasesBridge(object): 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): @@ -455,63 +472,31 @@ 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: return + # Update cache + self._cached_leases = leases + # Write out all 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: + for name, ttl, type, content in l.rrset: + log.debug("Removing records for %s" % name) + self._control("local_data_remove", name) for l in new_leases: for rr in l.rrset: From 9324732071de3b33db6a30452b3ab1134c4bd5e2 Mon Sep 17 00:00:00 2001 From: Michael Tremer Date: Sat, 15 Oct 2016 19:17:44 +0200 Subject: [PATCH 5/9] unbound-dhcp-bridge: Only update cache when lease was added/removed Signed-off-by: Michael Tremer --- config/unbound/unbound-dhcp-leases-bridge | 36 ++++++++++++++++------- 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/config/unbound/unbound-dhcp-leases-bridge b/config/unbound/unbound-dhcp-leases-bridge index a41354349..4804dba2a 100644 --- a/config/unbound/unbound-dhcp-leases-bridge +++ b/config/unbound/unbound-dhcp-leases-bridge @@ -486,23 +486,37 @@ class UnboundConfigWriter(object): if not new_leases and not removed_leases: return - # Update cache - self._cached_leases = leases - # Write out all leases self.write_dhcp_leases(leases) # Update unbound about changes for l in removed_leases: - for name, ttl, type, content in l.rrset: - log.debug("Removing records for %s" % name) - self._control("local_data_remove", name) + 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: @@ -515,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") From 13e6019b926169ddadeb3fe6f3fc77f69f6a66d3 Mon Sep 17 00:00:00 2001 From: Michael Tremer Date: Sat, 15 Oct 2016 22:32:05 +0100 Subject: [PATCH 6/9] unbound-dhcp-bridge: Make leases unique by IP address Signed-off-by: Michael Tremer --- config/unbound/unbound-dhcp-leases-bridge | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/unbound/unbound-dhcp-leases-bridge b/config/unbound/unbound-dhcp-leases-bridge index 4804dba2a..54cd8135b 100644 --- a/config/unbound/unbound-dhcp-leases-bridge +++ b/config/unbound/unbound-dhcp-leases-bridge @@ -222,7 +222,7 @@ class DHCPLeases(object): # 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 From 6920fbe86df2cacefc1a91b9590d84a495734e65 Mon Sep 17 00:00:00 2001 From: Michael Tremer Date: Sat, 15 Oct 2016 22:32:21 +0100 Subject: [PATCH 7/9] unbound: Omit reverse PTRs if address equals GREEN Signed-off-by: Michael Tremer --- src/initscripts/init.d/unbound | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/initscripts/init.d/unbound b/src/initscripts/init.d/unbound index 4c6b45222..4e424775e 100644 --- a/src/initscripts/init.d/unbound +++ b/src/initscripts/init.d/unbound @@ -138,6 +138,9 @@ update_hosts() { unbound-control -q local_data "${fqdn} ${LOCAL_TTL} IN A ${address}" + # Skip reverse resolution if the address equals the GREEN address + [ "${address}" = "${GREEN_ADDRESS}" ] && continue + # Add RDNS address=$(ip_address_revptr ${address}) unbound-control -q local_data "${address} ${LOCAL_TTL} IN PTR ${fqdn}" From 96473f525dcec4115b9bab0b305ff5b92194b134 Mon Sep 17 00:00:00 2001 From: Michael Tremer Date: Sat, 15 Oct 2016 22:38:01 +0100 Subject: [PATCH 8/9] Revert "setup: Store passwords in SHA format" This reverts commit eef9b2529c3cab522dac4f4bcfa1a0075376514e. It appears that htpasswd is not salting any passwords that are stored with the SHA (-s) algorithm. MD5 passwords however are salted. That leads us to the conclusion that the "MD5 algorithm" in htpasswd is more secure than the "SHA algorithm" although the hash function itself should be stronger. With a rainbow table, cracking "SHA" is easily done. A rainbow table for "MD5" + salt would be way too large to be efficiently stored. Hence this commit is reverted to old behaviour to avoid the clear failure of design in SHA. Signed-off-by: Michael Tremer Signed-off-by: Arne Fitzenreiter --- config/rootfiles/core/106/filelists/files | 1 - src/setup/passwords.c | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/config/rootfiles/core/106/filelists/files b/config/rootfiles/core/106/filelists/files index fd363f321..a67d30a48 100644 --- a/config/rootfiles/core/106/filelists/files +++ b/config/rootfiles/core/106/filelists/files @@ -22,5 +22,4 @@ srv/web/ipfire/cgi-bin/logs.cgi/log.dat srv/web/ipfire/cgi-bin/pakfire.cgi srv/web/ipfire/cgi-bin/pppsetup.cgi srv/web/ipfire/cgi-bin/services.cgi -usr/sbin/setup var/ipfire/backup/include diff --git a/src/setup/passwords.c b/src/setup/passwords.c index 50ee38ed7..e7b4b5231 100644 --- a/src/setup/passwords.c +++ b/src/setup/passwords.c @@ -56,7 +56,7 @@ int handleadminpassword(void) return 0; snprintf(commandstring, STRING_SIZE, - "/usr/sbin/htpasswd -c -s -b " CONFIG_ROOT "/auth/users admin '%s'", password); + "/usr/sbin/htpasswd -c -m -b " CONFIG_ROOT "/auth/users admin '%s'", password); sprintf(message, _("Setting %s 'admin' user password..."), NAME); if (runhiddencommandwithstatus(commandstring, _("Setting password"), message, NULL)) { sprintf(message, _("Problem setting %s 'admin' user password."), NAME); From 86667d0c7a32054bea49dcbf1f90803b6170a581 Mon Sep 17 00:00:00 2001 From: Arne Fitzenreiter Date: Sat, 15 Oct 2016 23:52:07 +0200 Subject: [PATCH 9/9] core106: set version to 106 Signed-off-by: Arne Fitzenreiter --- make.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/make.sh b/make.sh index 9289d810f..d4d164ea0 100755 --- a/make.sh +++ b/make.sh @@ -26,7 +26,7 @@ NAME="IPFire" # Software name SNAME="ipfire" # Short name VERSION="2.19" # Version number CORE="106" # Core Level (Filename) -PAKFIRE_CORE="105" # Core Level (PAKFIRE) +PAKFIRE_CORE="106" # Core Level (PAKFIRE) GIT_BRANCH=`git rev-parse --abbrev-ref HEAD` # Git Branch SLOGAN="www.ipfire.org" # Software slogan CONFIG_ROOT=/var/ipfire # Configuration rootdir