import argparse
import datetime
import daemon
+import ipaddress
import logging
import logging.handlers
import re
@property
def domain(self):
- return "local" # XXX
+ # Load ethernet settings
+ ethernet_settings = self.read_settings("/var/ipfire/ethernet/settings")
+
+ # Load DHCP settings
+ dhcp_settings = self.read_settings("/var/ipfire/dhcp/settings")
+
+ subnets = {}
+ for zone in ("GREEN", "BLUE"):
+ if not dhcp_settings.get("ENABLE_%s" % zone) == "on":
+ continue
+
+ netaddr = ethernet_settings.get("%s_NETADDRESS" % zone)
+ submask = ethernet_settings.get("%s_NETMASK" % zone)
+
+ subnet = ipaddress.ip_network("%s/%s" % (netaddr, submask))
+ domain = dhcp_settings.get("DOMAIN_NAME_%s" % zone)
+
+ subnets[subnet] = domain
+
+ address = ipaddress.ip_address(self.ipaddr)
+
+ for subnet, domain in subnets.items():
+ if address in subnet:
+ return domain
+
+ # Fall back to localdomain if no match could be found
+ return "localdomain"
+
+ @staticmethod
+ def read_settings(filename):
+ settings = {}
+
+ with open(filename) as f:
+ for line in f.readlines():
+ # Remove line-breaks
+ line = line.rstrip()
+
+ k, v = line.split("=", 1)
+ settings[k] = v
+
+ return settings
@property
def fqdn(self):
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),
]
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):
+ # 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]
- # 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]
-
# 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)
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:
--- /dev/null
+###############################################################################
+# #
+# IPFire.org - A linux based firewall #
+# Copyright (C) 2007-2011 IPFire Team <info@ipfire.org> #
+# #
+# This program is free software: you can redistribute it and/or modify #
+# it under the terms of the GNU General Public License as published by #
+# the Free Software Foundation, either version 3 of the License, or #
+# (at your option) any later version. #
+# #
+# This program is distributed in the hope that it will be useful, #
+# but WITHOUT ANY WARRANTY; without even the implied warranty of #
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
+# GNU General Public License for more details. #
+# #
+# You should have received a copy of the GNU General Public License #
+# along with this program. If not, see <http://www.gnu.org/licenses/>. #
+# #
+###############################################################################
+
+###############################################################################
+# Definitions
+###############################################################################
+
+include Config
+
+VER = 3.4.1
+
+THISAPP = py2-ipaddress-$(VER)
+DL_FILE = $(THISAPP).tar.gz
+DL_FROM = $(URL_IPFIRE)
+DIR_APP = $(DIR_SRC)/$(THISAPP)
+TARGET = $(DIR_INFO)/$(THISAPP)
+
+###############################################################################
+# Top-level Rules
+###############################################################################
+
+objects = $(DL_FILE)
+
+$(DL_FILE) = $(DL_FROM)/$(DL_FILE)
+
+$(DL_FILE)_MD5 = 47734313c841068e3d5386d048d01c3d
+
+install : $(TARGET)
+
+check : $(patsubst %,$(DIR_CHK)/%,$(objects))
+
+download :$(patsubst %,$(DIR_DL)/%,$(objects))
+
+md5 : $(subst %,%_MD5,$(objects))
+
+###############################################################################
+# Downloading, checking, md5sum
+###############################################################################
+
+$(patsubst %,$(DIR_CHK)/%,$(objects)) :
+ @$(CHECK)
+
+$(patsubst %,$(DIR_DL)/%,$(objects)) :
+ @$(LOAD)
+
+$(subst %,%_MD5,$(objects)) :
+ @$(MD5)
+
+###############################################################################
+# Installation Details
+###############################################################################
+
+$(TARGET) : $(patsubst %,$(DIR_DL)/%,$(objects))
+ @$(PREBUILD)
+ @rm -rf $(DIR_APP) && cd $(DIR_SRC) && tar zxf $(DIR_DL)/$(DL_FILE)
+ cd $(DIR_APP) && python setup.py install --root=/
+ @rm -rf $(DIR_APP)
+ @$(POSTBUILD)