From b8b614309acd67eafa4aa4197426100aaff5af80 Mon Sep 17 00:00:00 2001 From: Yax <kianby@madyanne.fr> Date: Wed, 06 Sep 2017 16:29:16 +0000 Subject: [PATCH] Vilain reporting --- vilain | 188 ++-------------------------------------------- 1 files changed, 10 insertions(+), 178 deletions(-) diff --git a/vilain b/vilain index f0ea83e..9c2841c 100755 --- a/vilain +++ b/vilain @@ -1,179 +1,11 @@ -#!/usr/bin/env python3.4 -# -*- coding:Utf-8 -*- +#!/bin/sh +# script to launch vilain with the latest python3 version available - -""" -Author : thuban <thuban@yeuxdelibad.net> -Licence : MIT - -Description : Mimic fail2ban with pf for OpenBSD. - Inspired from http://www.vincentdelft.be/post/post_20161106 - - In pf.conf, add : - table <vilain_bruteforce> persist - block quick from <vilain_bruteforce> - - You might want to add a cron task to remove old banned IP. As example, to ban for one day max : - pfctl -t vilain_bruteforce -T expire 86400 - - To see banned IP : - pfctl -t vilain_bruteforce -T show - -""" - -import sys -import os -import configparser -import re -import time -import logging -import subprocess -from multiprocessing import Process, Queue, TimeoutError - -configfile = "/etc/vilain.conf" -version = "0.1" -vilain_table = "vilain_bruteforce" -logfile = "/var/log/daemon" - -if os.geteuid() != 0: - print("Only root can use this tool") - sys.exit() - -# Configure logging -logger = logging.getLogger(__name__) -logging.basicConfig(filename=logfile, - format='%(asctime)s %(module)s:%(funcName)s:%(message)s', - datefmt='%H:%M:%S') -logger.setLevel(logging.DEBUG) -ch = logging.StreamHandler(sys.stdout) -logger.addHandler(ch) - -# functions -def readconfig(): - if not os.path.isfile(configfile): - logging.error("Can't read config file, exiting...") - sys.exit(1) - - config = configparser.ConfigParser() - config.read(configfile) - return(config) - -def load_config(): - c = readconfig() - d = c.defaults() - watch_while = int(d['watch_while']) - maxtries = int(d['maxtries']) - vilain_table = d['vilain_table'] - return(watch_while, maxtries, vilain_table) - -def load_sections(): - c = readconfig() - for s in c.sections(): - logfile = c.get(s,'logfile') - regex = c.get(s,'regex') - d = {'name' : s, 'logfile':logfile, 'regex':regex} - yield d - - -def check_logs(logfile, regex, bad_ip_queue): - """ - worker who put in bad_ip_queue bruteforce IP - """ - if not os.path.isfile(logfile) : - logger.warning("{} doesn't exist".format(logfile)) - return - # Watch the file for changes - stat = os.stat(logfile) - size = stat.st_size - mtime = stat.st_mtime - RE = re.compile(regex) - while True: - time.sleep(0.5) - stat = os.stat(logfile) - if mtime < stat.st_mtime: - mtime = stat.st_mtime - with open(logfile, "rb") as f: - f.seek(size) - lines = f.readlines() - ul = [ u.decode() for u in lines ] - line = "".join(ul).strip() - - ret = RE.match(line) - if ret: - bad_ip = ret.groups()[0] - bad_ip_queue.put(bad_ip) - size = stat.st_size - -def ban_ips(bad_ip_queue, watch_while, maxtries, vilain_table): - """ - worker who ban IP on bad_ip_queue - add IP in bad_ips_list - record time when this IP has been seen in ip_seen_at = { ip:time } - - check number of occurence of the same ip in bad_ips_list - if more than 3 : ban and clean of list - - check old ip in ip_seen_at : remove older than watch_while - """ - - bad_ips_list = [] - ip_seen_at = {} - while True: - try: - ip = bad_ip_queue.get(0.5) - logger.info("{} detected".format(ip)) - bad_ips_list.append(ip) - ip_seen_at[ip] = time.time() - - n_ip = bad_ips_list.count(ip) - if n_ip >= maxtries: - logger.info("Blacklisting {}".format(ip)) - subprocess.call(["pfctl", "-t", vilain_table, "-T", "add", ip]) - ip_seen_at.pop(ip) - while ip in bad_ips_list: - bad_ips_list.remove(ip) - - to_remove = [] - for recorded_ip, last_seen in ip_seen_at.items(): - if time.time() - last_seen >= watch_while: - logger.info("{} not seen since a long time, forgetting...".format(recorded_ip)) - to_remove.append(recorded_ip) - for i in to_remove: - ip_seen_at.pop(i) - - except TimeoutError: - pass - except KeyboardInterrupt: - sys.exit(0) - -def main(): - os.chdir(os.path.dirname(os.path.abspath(__file__))) - - watch_while, maxtries, vilain_table = load_config() - bad_ip_queue = Queue() - workers = [] - - for entry in load_sections(): - logger.info("Start vilain for {}".format(entry['name'])) - worker = Process(target=check_logs, - args=(entry['logfile'], entry['regex'], bad_ip_queue)) - workers.append(worker) - worker.daemon = True - worker.start() - - ban_worker = Process(target=ban_ips, args=(bad_ip_queue, watch_while, maxtries)) - workers.append(ban_worker) - ban_worker.daemon = True - ban_worker.start() - - for w in workers: - w.join() - - return 0 - -if __name__ == '__main__': - main() - - -# vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4 - +PYTHONVERSION=$(ls -l /usr/local/bin/python3.* |grep -Eo "3\.[0-9]" |tail -n1) +PYTHON="/usr/local/bin/python$PYTHONVERSION" +if [ -x $PYTHON ]; then + $PYTHON /usr/local/sbin/vilain.py >/dev/null 2>&1 & +else + echo "Error : no python3 executable found" +fi +exit -- Gitblit v1.9.3