def run(self): ruleset = set(Iptables.read_simple_rules()) while True: modify, rule, directives = self.cmd_queue.get() try: rule_exists = rule in ruleset log.debug('{} rule_exists: {}'.format(rule, rule_exists)) # check for duplicates, apply rule if modify == 'I': if rule_exists: log.warn("Trying to insert existing rule: {}. Command ignored.".format(rule)) else: Iptables.exe_rule(modify, rule) # schedule expiry timeout if present. Only for Insert rules and only if the rule didn't exist before (so it was added now) self.schedule_expiry(rule, directives) ruleset.add(rule) elif modify == 'D': if rule_exists: #TODO delete rules in the loop to delete actual iptables duplicates. It's to satisfy idempotency and plays well with common sense Iptables.exe_rule(modify, rule) ruleset.discard(rule) else: log.warn("Trying to delete not existing rule: {}. Command ignored.".format(rule)) elif modify == 'L': #TODO rereading the iptables? pass finally: self.cmd_queue.task_done()
def run(self): ruleset = set(Iptables.read_simple_rules()) while True: modify, rule, directives = self.cmd_queue.get() try: rule_exists = rule in ruleset log.debug('{} rule_exists: {}'.format(rule, rule_exists)) # check for duplicates, apply rule if modify == 'I': if rule_exists: log.warn( "Trying to insert existing rule: {}. Command ignored." .format(rule)) else: Iptables.exe_rule(modify, rule) # schedule expiry timeout if present. Only for Insert rules and only if the rule didn't exist before (so it was added now) self.schedule_expiry(rule, directives) ruleset.add(rule) elif modify == 'D': if rule_exists: #TODO delete rules in the loop to delete actual iptables duplicates. It's to satisfy idempotency and plays well with common sense Iptables.exe_rule(modify, rule) ruleset.discard(rule) else: log.warn( "Trying to delete not existing rule: {}. Command ignored." .format(rule)) elif modify == 'L': #TODO rereading the iptables? pass finally: self.cmd_queue.task_done()
def index(request): exist_thread = False for threads in threading.enumerate(): test = Iptables(args=(1,), source={'T': 'Firewall', 'M': 'iptables', 'P': '/var/log/iptables.log', 'C': './secapp/kernel/conf/iptables-conf.conf'}) if type(threads) == type(test): exist_thread = True if not exist_thread: thread_iptables = Iptables(args=(1,), source={'T': 'Firewall', 'M': 'iptables', 'P': '/var/log/iptables.log', 'C': './secapp/kernel/conf/iptables-conf.conf'}) thread_iptables.start() latest_source_list = LogSources.objects.order_by('id')[:3] context = {'latest_source_list': latest_source_list} if request.GET.get('run-btn'): hello = int(request.GET.get('textbox')) context.update({'hello': hello}) return render(request, 'secapp/index.html', context)
def add_rule(rule, service_name, chain="INPUT", protocol="tcp"): """ Add the rules using the specified firewall (Rule, str) -> None """ if service_name == "iptables": # create specific Iptables object rule = Iptables(rule, chain, protocol) # add rule to iptables rule.add_rule() else: raise ValueError("Error: " + service_name + " is not yet supported")
def delete_rule(rule, service_name): """ Delete the specified Rule object from the specified firewall service (Rule, str) -> None """ if service_name == "iptables": # create specific Iptables object rule = Iptables(rule) # add rule to iptables rule.delete_rule() else: raise ValueError("Error: " + service_name + " is not yet supported")
def rfw_init_rules(rfwconf): """Clean and insert the rfw init rules. The rules block all INPUT/OUTPUT traffic on rfw ssl port except for whitelisted IPs. Here are the rules that should be created assuming that that the only whitelisted IP is 127.0.0.1: Rule(chain='INPUT', num='1', pkts='0', bytes='0', target='ACCEPT', prot='tcp', opt='--', inp='*', out='*', source='127.0.0.1', destination='0.0.0.0/0', extra='tcp dpt:7393') Rule(chain='INPUT', num='4', pkts='0', bytes='0', target='DROP', prot='tcp', opt='--', inp='*', out='*', source='0.0.0.0/0', destination='0.0.0.0/0', extra='tcp dpt:7393') Rule(chain='OUTPUT', num='1', pkts='0', bytes='0', target='ACCEPT', prot='tcp', opt='--', inp='*', out='*', source='0.0.0.0/0', destination='127.0.0.1', extra='tcp spt:7393') Rule(chain='OUTPUT', num='4', pkts='0', bytes='0', target='DROP', prot='tcp', opt='--', inp='*', out='*', source='0.0.0.0/0', destination='0.0.0.0/0', extra='tcp spt:7393') """ rfw_port = rfwconf.outward_server_port() ipt = Iptables.load() ### log.info('Delete existing init rules') # find 'drop all packets to and from rfw port' drop_input = ipt.find({'target': ['DROP'], 'chain': ['INPUT'], 'prot': ['tcp'], 'extra': ['tcp dpt:' + rfw_port]}) log.info(drop_input) log.info('Existing drop input to rfw port {} rules:\n{}'.format(rfw_port, '\n'.join(map(str, drop_input)))) # breaking things to make it start #for r in drop_input: # Iptables.exe_rule('D', r) drop_output = ipt.find({'target': ['DROP'], 'chain': ['OUTPUT'], 'prot': ['tcp'], 'extra': ['tcp spt:' + rfw_port]}) log.info('Existing drop output to rfw port {} rules:\n{}'.format(rfw_port, '\n'.join(map(str, drop_output)))) # breaking things to make it start #for r in drop_output: # Iptables.exe_rule('D', r) ### log.info('Insert DROP rfw port init rules') # breaking things to make it start #Iptables.exe(['-I', 'INPUT', '-p', 'tcp', '--dport', rfw_port, '-j', 'DROP']) #Iptables.exe(['-I', 'OUTPUT', '-p', 'tcp', '--sport', rfw_port, '-j', 'DROP']) ### log.info('Insert ACCEPT whitelist IP rfw port init rules')
def process(handler, modify, urlpath): # modify should be 'D' for Delete or 'I' for Insert understood as -D and -I iptables flags assert modify in ['D', 'I', 'L'] try: action, rule, directives = cmdparse.parse_command(urlpath) # log.debug('\nAction: {}\nRule: {}\nDirectives: {}'.format(action, rule, directives)) if modify == 'L': if action == 'help': resp = 'TODO usage' return handler.http_resp(200, resp) elif action == 'list': chain = rule rules = Iptables.read_simple_rules(chain) log.debug('List rfw rules: %s', rules) list_of_dict = map(iptables.Rule._asdict, rules) resp = json.dumps(list_of_dict) return handler.http_resp(200, resp) elif rfwconf.is_non_restful(): mod = directives.get('modify') if not mod: raise Exception('Unrecognized command. Non-restful enabled, you need to provide modify parameter.'.format(action)) if mod == 'insert': modify = 'I' elif mod == 'delete': modify = 'D' else: raise Exception('Unrecognized command. Modify parameter can be "insert" or "delete".') else: raise Exception('Unrecognized command. Non-restful disabled.') if modify in ['D', 'I'] and action.upper() in iptables.RULE_TARGETS: # eliminate ignored/whitelisted IP related commands early to prevent propagating them to expiry queue check_whitelist_conflict(rule.source, rfwconf.whitelist()) check_whitelist_conflict(rule.destination, rfwconf.whitelist()) ctup = (modify, rule, directives) log.debug('PUT to Cmd Queue. Tuple: {}'.format(ctup)) cmd_queue.put_nowait(ctup) # Make these rules persistent on file import os.path if os.path.isfile("/etc/init.d/iptables-persistent"): save_command = "/etc/init.d/iptables-persistent save" else: raise Exception('No iptables-persistent command is installed. Please install it first!') if save_command is not None: subprocess.call(save_command, shell=True) return handler.http_resp(200, ctup) else: raise Exception('Unrecognized command.') except Exception, e: msg = 'ERROR: {}'.format(e.message) # logging as error disabled - bad client request is not an error # log.exception(msg) log.info(msg) return handler.http_resp(400, msg) # Bad Request
def iptables_version(min=None, max=None): """ Return iptables version or test for a minimum and/or maximum version min -- minimal iptables version required max -- maximum iptables version required """ return Iptables.version(min=min, max=max)
def process(handler, modify, urlpath): # modify should be 'D' for Delete or 'I' for Insert understood as -D and -I iptables flags assert modify in ['D', 'I', 'L'] log.debug('process {} urlpath: {}'.format(modify, urlpath)) try: action, rule, directives = cmdparse.parse_command(urlpath) log.debug('\nAction: {}\nRule: {}\nDirectives: {}'.format( action, rule, directives)) if modify == 'L': if action == 'help': resp = 'TODO usage' return handler.http_resp(200, resp) elif action == 'list': chain = rule rules = Iptables.read_simple_rules(chain) log.debug('List rfw rules: %s', rules) list_of_dict = map(iptables.Rule._asdict, rules) resp = json.dumps(list_of_dict) return handler.http_resp(200, resp) elif rfwconf.is_non_restful(): mod = directives.get('modify') if not mod: raise Exception( 'Unrecognized command. Non-restful enabled, you need to provide modify parameter.' .format(action)) if mod == 'insert': modify = 'I' elif mod == 'delete': modify = 'D' else: raise Exception( 'Unrecognized command. Modify parameter can be "insert" or "delete".' ) else: raise Exception( 'Unrecognized command. Non-restful disabled.') if modify in ['D', 'I' ] and action.upper() in iptables.RULE_TARGETS: # eliminate ignored/whitelisted IP related commands early to prevent propagating them to expiry queue check_whitelist_conflict(rule.source, rfwconf.whitelist()) check_whitelist_conflict(rule.destination, rfwconf.whitelist()) ctup = (modify, rule, directives) log.debug('PUT to Cmd Queue. Tuple: {}'.format(ctup)) cmd_queue.put_nowait(ctup) return handler.http_resp(200, ctup) else: raise Exception('Unrecognized command.') except Exception, e: msg = 'ERROR: {}'.format(e.message) # logging as error disabled - bad client request is not an error # log.exception(msg) log.info(msg) return handler.http_resp(400, msg) # Bad Request
def rollback(savedlines): """ Rollback changes to the firewall, and report rollback success to the user savedlines -- saved firewall setting to be restored. """ # restore old iptables rules restored = Iptables.restore(savedlines) if restored: sys.stderr.write("*"*70+"\n") sys.stderr.write(" FIREWALL ROLLBACK FAILED.\n") sys.stderr.write("*"*70+"\n") else: sys.stderr.write("Firewall initialization failed. Rollback complete.\n")
def startup_sanity_check(): """Check for most common errors to give informative message to the user """ try: Iptables.verify_install() Iptables.verify_permission() Iptables.verify_original() except Exception, e: log.critical(e) sys.exit(1)
#!/usr/bin/env python # -*- coding: utf-8 -*- from iptables import Iptables from glances import Glances from datetime import date # Author: Moisés Gautier Gómez # Proyecto fin de carrera - Ing. en Informática # Universidad de Granada # Creamos un objeto del tipo Source y operamos con él test = Iptables('proyecto_bd', args=(1,), source={'T' : 'Firewall', 'M' : 'iptables', 'P' : './iptables.log', 'C' : './conf/iptables_conf.conf'}) test.start() #test_2 = Glances('bd_project', args=(1,), source={'T' : 'Watchdog', 'M' : 'glances', 'P' : './glances.csv'}) #test_2.start()
def rfw_init_rules(rfwconf): """Clean and insert the rfw init rules. The rules block all INPUT/OUTPUT traffic on rfw ssl port except for whitelisted IPs. Here are the rules that should be created assuming that that the only whitelisted IP is 127.0.0.1: Rule(chain='INPUT', num='1', pkts='0', bytes='0', target='ACCEPT', prot='tcp', opt='--', inp='*', out='*', source='127.0.0.1', destination='0.0.0.0/0', extra='tcp dpt:7393') Rule(chain='INPUT', num='4', pkts='0', bytes='0', target='DROP', prot='tcp', opt='--', inp='*', out='*', source='0.0.0.0/0', destination='0.0.0.0/0', extra='tcp dpt:7393') Rule(chain='OUTPUT', num='1', pkts='0', bytes='0', target='ACCEPT', prot='tcp', opt='--', inp='*', out='*', source='0.0.0.0/0', destination='127.0.0.1', extra='tcp spt:7393') Rule(chain='OUTPUT', num='4', pkts='0', bytes='0', target='DROP', prot='tcp', opt='--', inp='*', out='*', source='0.0.0.0/0', destination='0.0.0.0/0', extra='tcp spt:7393') """ rfw_port = rfwconf.outward_server_port() ipt = Iptables.load() ### log.info('Delete existing init rules') # find 'drop all packets to and from rfw port' drop_input = ipt.find({ 'target': ['DROP'], 'chain': ['INPUT'], 'prot': ['tcp'], 'extra': ['tcp dpt:' + rfw_port] }) log.info(drop_input) log.info('Existing drop input to rfw port {} rules:\n{}'.format( rfw_port, '\n'.join(map(str, drop_input)))) for r in drop_input: Iptables.exe_rule('D', r) drop_output = ipt.find({ 'target': ['DROP'], 'chain': ['OUTPUT'], 'prot': ['tcp'], 'extra': ['tcp spt:' + rfw_port] }) log.info('Existing drop output to rfw port {} rules:\n{}'.format( rfw_port, '\n'.join(map(str, drop_output)))) for r in drop_output: Iptables.exe_rule('D', r) ### log.info('Insert DROP rfw port init rules') Iptables.exe( ['-I', 'INPUT', '-p', 'tcp', '--dport', rfw_port, '-j', 'DROP']) Iptables.exe( ['-I', 'OUTPUT', '-p', 'tcp', '--sport', rfw_port, '-j', 'DROP']) ### log.info('Insert ACCEPT whitelist IP rfw port init rules') for ip in rfwconf.whitelist(): try: Iptables.exe([ '-D', 'INPUT', '-p', 'tcp', '--dport', rfw_port, '-s', ip, '-j', 'ACCEPT' ]) Iptables.exe([ '-D', 'OUTPUT', '-p', 'tcp', '--sport', rfw_port, '-d', ip, '-j', 'ACCEPT' ]) except subprocess.CalledProcessError, e: pass # ignore Iptables.exe([ '-I', 'INPUT', '-p', 'tcp', '--dport', rfw_port, '-s', ip, '-j', 'ACCEPT' ]) Iptables.exe([ '-I', 'OUTPUT', '-p', 'tcp', '--sport', rfw_port, '-d', ip, '-j', 'ACCEPT' ])
rfwconf = rfwconfig.RfwConfig(args.configfile) except IOError, e: perr(e.message) create_args_parser().print_usage() sys.exit(1) # Initialize Iptables with configured path to system iptables Iptables.ipt_path = rfwconf.iptables_path() startup_sanity_check() # Install signal handlers signal.signal(signal.SIGTERM, __sigTERMhandler) signal.signal(signal.SIGINT, __sigTERMhandler) # TODO we may also need to ignore signal.SIGHUP in daemon mode rules = Iptables.load().rules # TODO make logging more efficient by deferring arguments evaluation log.debug("===== rules =====\n{}".format("\n".join(map(str, rules)))) log.info("Starting rfw server") log.info("Whitelisted IP addresses that will be ignored:") for a in rfwconf.whitelist(): log.info(' {}'.format(a)) # recreate rfw init rules related to rfw port rfw_init_rules(rfwconf) expiry_queue = PriorityQueue() cmd_queue = Queue() rfwthreads.CommandProcessor(cmd_queue, rfwconf.whitelist(), expiry_queue,
perr(e.message) create_args_parser().print_usage() sys.exit(1) # Initialize Iptables with configured path to system iptables Iptables.ipt_path = rfwconf.iptables_path() startup_sanity_check() # Install signal handlers signal.signal(signal.SIGTERM, __sigTERMhandler) signal.signal(signal.SIGINT, __sigTERMhandler) # TODO we may also need to ignore signal.SIGHUP in daemon mode rules = Iptables.load().rules # TODO make logging more efficient by deferring arguments evaluation log.debug("===== rules =====\n{}".format("\n".join(map(str, rules)))) log.info("Starting rfw server") log.info("Whitelisted IP addresses that will be ignored:") for a in rfwconf.whitelist(): log.info(' {}'.format(a)) # recreate rfw init rules related to rfw port rfw_init_rules(rfwconf) expiry_queue = PriorityQueue() cmd_queue = Queue() rfwthreads.CommandProcessor(cmd_queue,
except IOError, e: perr(e.message) create_args_parser().print_usage() sys.exit(1) # Initialize Iptables with configured path to system iptables Iptables.ipt_path = rfwconf.iptables_path() startup_sanity_check() # Install signal handlers signal.signal(signal.SIGTERM, __sigTERMhandler) signal.signal(signal.SIGINT, __sigTERMhandler) # TODO we may also need to ignore signal.SIGHUP in daemon mode Iptables.loadChains() rules = Iptables.load().rules # TODO make logging more efficient by deferring arguments evaluation log.debug("===== rules =====\n{}".format("\n".join(map(str, rules)))) log.info("Starting rfw server") log.info("Whitelisted IP addresses that will be ignored:") for a in rfwconf.whitelist(): log.info(' {}'.format(a)) # recreate rfw init rules related to rfw port rfw_init_rules(rfwconf) expiry_queue = PriorityQueue() cmd_queue = Queue()
def run(self): Iptables.read_chains() ruleset = set(Iptables.read_simple_rules(matching_num=False)) while True: modify, rule, directives = self.cmd_queue.get() try: # Modify the rule to nullify parameters which need not to be included in the search if rule.target != 'CREATE': rule_exists = rule in ruleset else: if ':' in rule.chain: new_chain = rule.chain.split(':')[1] rule_exists = new_chain in iptables.RULE_CHAINS else: rule_exists = rule.chain in iptables.RULE_CHAINS log.debug('{} rule_exists: {}'.format(rule, rule_exists)) # check for duplicates, apply rule if modify == 'I': if rule_exists: log.warn("Trying to insert existing rule: {}. Command ignored.".format(rule)) else: if rule.target == 'CREATE': modify = 'N' if ':' in rule.chain: # renaming a chain modify = 'E' Iptables.exe_rule(modify, rule) # schedule expiry timeout if present. Only for Insert rules and only if the rule didn't exist before (so it was added now) self.schedule_expiry(rule, directives) if rule.target != 'CREATE': ruleset.add(rule) else: if ':' in rule.chain: old_chain = rule.chain.split(':')[0] new_chain = rule.chain.split(':')[1] iptables.RULE_CHAINS.remove(old_chain) iptables.RULE_CHAINS.add(new_chain) iptables.RULE_TARGETS.add(rule.chain) else: iptables.RULE_CHAINS.add(rule.chain) iptables.RULE_TARGETS.add(rule.chain) elif modify == 'D': if rule_exists: if rule.target == 'CREATE': modify = 'X' #TODO delete rules in the loop to delete actual iptables duplicates. It's to satisfy idempotency and plays well with common sense Iptables.exe_rule(modify, rule) if rule.target != 'CREATE': ruleset.discard(rule) else: iptables.RULE_TARGETS.remove(rule.chain) iptables.RULE_CHAINS.remove(rule.chain) else: print("non existing rule") log.warn("Trying to delete not existing rule: {}. Command ignored.".format(rule)) elif modify == 'L': #TODO rereading the iptables? pass # Hack to prevent this exception to reach the threading code, preventing this thread from running more than this except Exception: pass finally: self.cmd_queue.task_done()
def execute_rules(terse_mode=False): """ Execute the generated rules, rollback on error. If Firewall.timeout is set, give the user some time to accept the new configuration, otherwise roll back automatically. """ def user_confirm_timeout_handler(signum, frame): """ This handler is called when the user does not confirm firewall changes withing the given time limit. The firewall will then be rolled back. """ raise Firewall.Error("Success not confirmed by user") r4, r6 = Firewall.calciptableslines() # Save old firewall. if terse_mode: sys.stderr.write("backing up current... ") else: sys.stderr.write("Backing up current firewall...\n") savedlines = Iptables.save() # parse the firewall setup #try: # parsed = iptables_parse.parse(savedlines) #except: # pass # now try to execute the new rules successful = False try: if terse_mode: sys.stderr.write("activating new... ") successful = Iptables.commit( (r4, r6) ) if terse_mode: sys.stderr.write("success") else: sys.stderr.write("New firewall commited successfully.\n") if Firewall.vercmd: vcmd = subprocess.Popen(Firewall.vercmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) result = vcmd.communicate() if len(result[0]) > 0 or len(result[1]) > 0: if len(result[0]) > 0: sys.stderr.write("Verification command output:\n") sys.stderr.write(result[0]) if len(result[1]) > 0: sys.stderr.write("Verification command error output:\n") sys.stderr.write(result[1]) if vcmd.returncode != 0: raise Firewall.Error("External verification command failed.") if Firewall.timeout > 0: sys.stderr.write("To accept the new configuration, type 'OK' within %d seconds!\n" % Firewall.timeout) # setup timeout signal.signal(signal.SIGALRM, user_confirm_timeout_handler) signal.alarm(Firewall.timeout) # wait for user input input = sys.stdin.readline() # reset alarm handling signal.alarm(0) signal.signal(signal.SIGALRM, signal.SIG_DFL) if not re.search("^(OK|YES)", input, re.I): raise Firewall.Error("Success not confirmed by user") except Iptables.Error, e: if terse_mode: sys.stderr.write("error... restoring backup.\n") else: sys.stderr.write("*"*70+"\n") sys.stderr.write("An Iptables error occurred. Starting firewall restoration.\n") Firewall.rollback(savedlines) # show exception sys.stderr.write("%s\n" % e);