def create_rule_blackhole(flow): dst_ip = flow.get('dst_ip') + '/32' dst_subnet = get_subnet(flow.get('dst_ip')) rule = [] rule.extend(('route', dst_ip)) rule.extend(('next-hop', config.get('BLACKHOLE_NEXTHOP'))) rule.extend(('community', config.get('BLACKHOLE_COMMUNITY'))) blackhole_rule = ' '.join(rule) logger.debug("Generate rule '%s'", blackhole_rule) return blackhole_rule
def create_rule_flow(flow, attack_type): dst_ip = flow.get('dst_ip') + '/32' dst_subnet = get_subnet(flow.get('dst_ip')) rule = [] rule.extend(('flow', 'route', 'destination', dst_subnet)) if (attack_type == GRE_FLOOD): rule.extend(('protocol', '[ gre ]')) elif (attack_type == UDP_FLOOD): rule.extend(('protocol', '[ udp ]')) rule.extend(('source-port', '[ =' + str(flow.get('src_ports').keys()[0]) + ' ]')) elif (attack_type == DNS_FLOOD): rule.extend(('protocol', '[ udp ]')) rule.extend(('source-port', '[ =' + str(flow.get('src_ports').keys()[0]) + ' ]')) rule.extend(('packet-length', '[ >900 ]')) elif (attack_type == TCP_SYN_FLOOD): rule.extend(('protocol', '[ tcp ]')) rule.extend(('destination-port', '[ =' + str(flow.get('dst_ports').keys()[0]) + ' ]')) rule.extend(('tcp-flags', '[ syn ]')) else: return '' rule.extend(('community', config.get('FLOW_COMMUNITY'))) rule.extend(('rate-limit', '0')) flowspec_rule = ' '.join(rule) logger.debug("Generate rule '%s'", flowspec_rule) return flowspec_rule
def process_ban(ip, rules): if not rules: return 1 for (ip, rule, attack_type) in rules: logger.info("Process BAN ip:%s with:'%s'", ip, rule) if (not config.get('EXABGP_DRYMODE')): exabgp.send_command('announce ' + rule) store_attack_host(ip, '', attack_type, rule) return 0
def send_command(rule): try: f = open(config.get('EXABGP_PIPE'), "w") f.write(rule + "\n") f.close() return 0 except (OSError, IOError) as err: logging.error('File error: %s', err) return 1
def process_unban(ip): rules = get_attack_host(ip) remove_attack_host(ip) if not rules: return 1 for (rule, ) in rules: rule_count = get_attack_rules_count(rule) if (rule_count == 0): logger.info("Process UNBAN ip:%s with:'%s'", ip, rule) if (not config.get('EXABGP_DRYMODE')): exabgp.send_command('withdraw ' + rule) else: logger.info("There is another BAN rule '%s' for %s network", rule, ip) return 0
__all__ = [ 'init_db', 'store_attack_host', 'remove_attack_host', 'get_attack_host', 'get_attack_rules_count', 'get_all_bans' ] import sqlite3 import logging import my_fastnetmon.config as config logger = logging.getLogger("log") conn = sqlite3.connect(config.get('SQLITE_DB')) c = conn.cursor() def init_db(): c.execute( " SELECT count(name) FROM sqlite_master WHERE type='table' AND name='host_attacks' " ) if c.fetchone()[0] == 0: c.execute( " CREATE TABLE 'host_attacks' (ip TEXT, network TEXT, attack_type TEXT, rule TEXT, datetime TEXT)" ) c.execute( " SELECT count(name) FROM sqlite_master WHERE type='table' AND name='network_attacks' " ) if c.fetchone()[0] == 0: c.execute( " CREATE TABLE 'network_attacks' (network TEXT, attack_type TEXT, rule TEXT, datetime TEXT)" ) conn.commit()
import sys, getopt import sqlite3 import my_fastnetmon.config as config from my_fastnetmon.flows import * from my_fastnetmon.flowspec import * from my_fastnetmon.flowban import * from my_fastnetmon.exabgp import * from my_fastnetmon.database import * program_name = 'process_attack' program_version = '1.2' logger = logging.getLogger("log") logger.setLevel(config.get('LOG_LEVEL')) formatter = logging.Formatter( "%(asctime)s - [%(process)d]:%(levelname)s:%(filename)s:%(funcName)s:%(lineno)d - %(message)s" ) handler = logging.FileHandler(config.get('LOG_FILE')) handler.setFormatter(formatter) logger.addHandler(handler) logger.debug("Start") if __name__ == '__main__': init_db() if len(sys.argv) < 5: sys.exit(2)
def process_flows(flows): rules = [] for key, flow in flows.items(): seconds = int(flow.get('end_datetime').strftime('%s')) - int( flow.get('start_datetime').strftime('%s')) if seconds <= 0: seconds = 1 pps = flow.get('packets') / seconds bps = flow.get('octets') / seconds * 8 # logger.debug("FLOW packets %d start time %s - end time %s: PPS:%d BPS:%d",flow.get('packets'),flow.get('start_datetime').strftime('%s'),flow.get('end_datetime').strftime('%s'),pps,bps) attack_type = '' if (pps > config.get('FLOW_BAN_PPS')): dst_ip = flow.get('dst_ip') # GRE proto (src and dst port == 0) if (flow.get('src_ports').get(0) == 1 and flow.get('dst_ports').get(0) == 1): attack_type = GRE_FLOOD logger.info('Detect GRE/UDP flood to %s', dst_ip) rules.append( (dst_ip, create_rule_flow(flow, GRE_FLOOD), attack_type)) rules.append( (dst_ip, create_rule_flow(flow, UDP_FLOOD), attack_type)) # UDP flood elif (flow.get('protocol') == 'udp' and len(flow.get('src_ports')) == 1 and pps > config.get('UDP_FLOOD_PPS')): # DNS UDP flood set minimum packet len attack_type = 'UDP_FLOOD_' + str( flow.get('src_ports').keys()[0]) if flow.get('src_ports').get(53) == 1: logger.info('Detect UDP DNS flood to %s', dst_ip) rules.append( (dst_ip, create_rule_flow(flow, DNS_FLOOD), attack_type)) else: logger.info('Detect UDP flood from port %d to %s', flow.get('src_ports').keys()[0], dst_ip) rules.append( (dst_ip, create_rule_flow(flow, UDP_FLOOD), attack_type)) # TCP syn flood elif (flow.get('protocol') == 'tcp' and flow.get('flags').get('syn') == 1 and pps > config.get('TCP_SYN_FLOOD_PPS')): attack_type = 'TCP_SYN_FLOOD_' + str( flow.get('dst_ports').keys()[0]) logger.info('Detect TCP syn flood to %s:%d', dst_ip, flow.get('dst_ports').keys()[0]) rules.append( (dst_ip, create_rule_flow(flow, TCP_SYN_FLOOD), attack_type)) else: logger.info('Unknown attack %s:%d %d', dst_ip, flow.get('dst_ports').keys()[0], flow.get('src_ports').keys()[0]) continue if (bps > config.get('FLOW_BAN_BPS') and attack_type): logger.info('Detect HUGE traffic flood (%d) to %s. BLACKHOLE it', bps, dst_ip) rules.append((dst_ip, create_rule_blackhole(flow), attack_type)) continue return rules