from celery import Celery, task from os import getenv import re import json import logging from utils import (ns_exec, sudo, ADDRESSES, get_network_type, dhcp_no_free_re, dhcp_ack_re, is_there_systemd) DHCP_LOGFILE = getenv('DHCP_LOGFILE', '/var/log/syslog') VLAN_CONF = getenv('VLAN_CONF', 'vlan.conf') FIREWALL_CONF = getenv('FIREWALL_CONF', 'firewall.conf') CACHE_URI = getenv('CACHE_URI') AMQP_URI = getenv('AMQP_URI') celery = Celery('tasks',) celery.conf.update(CELERY_TASK_RESULT_EXPIRES=300, BROKER_URL=AMQP_URI, CELERY_CREATE_MISSING_QUEUES=True) celery.conf.update(CELERY_CACHE_BACKEND=CACHE_URI, CELERY_RESULT_BACKEND='cache') logger = logging.getLogger(__name__) @task(name="firewall.reload_firewall") def reload_firewall(data4, data6, save_config=True): try: ns_exec(('ip6tables-restore', '-c'), data6) ns_exec(('iptables-restore', '-c'), data4) except: logging.exception('Unhandled exception: ') raise if save_config: with open(FIREWALL_CONF, 'w') as f: json.dump([data4, data6], f) logger.info("Firewall configuration is reloaded.") @task(name="firewall.reload_firewall_vlan") def reload_firewall_vlan(data, save_config=True): network_type = get_network_type() if network_type is None: logger.info("Ignored reload_firewall_vlan() network type=%s", network_type) return # Add additional addresses from config for k, v in ADDRESSES.items(): data[k]['addresses'] += v uplink = getenv('UPLINK', None) if uplink: data[uplink] = {'interfaces': uplink} print network_type br = network_type('firewall') br.migrate(data) if save_config: with open(VLAN_CONF, 'w') as f: json.dump(data, f) try: ns_exec(('ip', 'ro', 'add', 'default', 'via', getenv('GATEWAY', '152.66.243.254'))) except: pass logger.info("Interface (vlan) configuration is reloaded.") @task(name="firewall.reload_dhcp") def reload_dhcp(data): with open('/etc/dhcp/dhcpd.conf.generated', 'w') as f: f.write("\n".join(data) + "\n") if is_there_systemd(): sudo(('/bin/systemctl', 'restart', 'dhcpd')) else: sudo(('/etc/init.d/isc-dhcp-server', 'restart')) logger.info("DHCP configuration is reloaded.") def ipset_save(data): r = re.compile(r'^add blacklist ([0-9.]+)$') data_new = [x['ipv4'] for x in data] data_old = [] lines = ns_exec(('ipset', 'save', 'blacklist')) for line in lines.splitlines(): x = r.match(line.rstrip()) if x: data_old.append(x.group(1)) l_add = list(set(data_new).difference(set(data_old))) l_del = list(set(data_old).difference(set(data_new))) return (l_add, l_del) def ipset_restore(l_add, l_del): ipset = [] ipset.append('create blacklist hash:ip family inet hashsize ' '4096 maxelem 65536') ipset += ['add blacklist %s' % x for x in l_add] ipset += ['del blacklist %s' % x for x in l_del] ns_exec(('ipset', 'restore', '-exist'), '\n'.join(ipset) + '\n') @task(name="firewall.reload_blacklist") def reload_blacklist(data): l_add, l_del = ipset_save(data) ipset_restore(l_add, l_del) logger.info("Blacklist configuration is reloaded.") @task(name="firewall.get_dhcp_clients") def get_dhcp_clients(): clients = {} with open(DHCP_LOGFILE, 'r') as f: for line in f: m = dhcp_ack_re.search(line) if m is None: m = dhcp_no_free_re.search(line) if m is None: continue m = m.groupdict() mac = m['mac'] ip = m.get('ip', None) hostname = m.get('hostname', None) interface = m.get('interface', None) clients[mac] = {'ip': ip, 'hostname': hostname, 'interface': interface} return clients def start_firewall(): try: ns_exec(('ipset', 'create', 'blacklist', 'hash:ip', 'family', 'inet', 'hashsize', '4096', 'maxelem', '65536')) except: pass try: with open(FIREWALL_CONF, 'r') as f: data4, data6 = json.load(f) reload_firewall(data4, data6, True) except Exception: logger.exception('Unhandled exception: ') def start_networking(): try: with open(VLAN_CONF, 'r') as f: data = json.load(f) reload_firewall_vlan(data, True) except Exception: logger.exception('Unhandled exception: ') def main(): start_networking() start_firewall() main()