Thuban
2017-09-09 9120747a0773123eb41ef55d5e131f1789e1bad5
Merge branch 'master' into 'master'

Master

See merge request !2
2 files added
3 files modified
150 ■■■■■ changed files
Makefile 8 ●●●● patch | view | raw | blame | history
vilain 2 ●●● patch | view | raw | blame | history
vilain.py 6 ●●●● patch | view | raw | blame | history
vilainreport 11 ●●●●● patch | view | raw | blame | history
vilainreport.py 123 ●●●●● patch | view | raw | blame | history
Makefile
@@ -2,7 +2,7 @@
# See LICENSE file for copyright and license details.
#
# vilain version
VERSION = 0.6
VERSION = 0.7
# Customize below to fit your system
# paths
@@ -13,10 +13,14 @@
    @echo installing executable file to ${DESTDIR}${PREFIX}/bin
    @mkdir -p ${DESTDIR}${PREFIX}/bin
    @cp -f vilain ${DESTDIR}${PREFIX}/bin
    @cp -f vilainreport ${DESTDIR}${PREFIX}/bin
    @echo installing script file to ${DESTDIR}${PREFIX}/sbin
    @cp -f vilain.py ${DESTDIR}${PREFIX}/sbin
    @cp -f vilainreport.py ${DESTDIR}${PREFIX}/sbin
    @chmod 755 ${DESTDIR}${PREFIX}/bin/vilain
    @chmod 755 ${DESTDIR}${PREFIX}/bin/vilainreport
    @chmod 644 ${DESTDIR}${PREFIX}/sbin/vilain.py
    @chmod 644 ${DESTDIR}${PREFIX}/sbin/vilainreport.py
    @echo installing init script in /etc/rc.d
    @cp -f vilain.rc /etc/rc.d/vilain
    @chmod 755 /etc/rc.d/vilain
@@ -29,7 +33,9 @@
uninstall:
    @echo removing executable file from ${DESTDIR}${PREFIX}/bin
    @rm -f ${DESTDIR}${PREFIX}/bin/vilain
    @rm -f ${DESTDIR}${PREFIX}/bin/vilainreport
    @rm -f ${DESTDIR}${PREFIX}/sbin/vilain.py
    @rm -f ${DESTDIR}${PREFIX}/sbin/vilainreport.py
    @echo removing manual page to ${DESTDIR}${MANPREFIX}/
    @rm -f ${DESTDIR}${MANPREFIX}/vilain.1
vilain
@@ -1,5 +1,5 @@
#!/bin/sh
# script to launch vilain with the latest python3 version avaiable
# script to launch vilain with the latest python3 version available
PYTHONVERSION=$(ls -l /usr/local/bin/python3.* |grep -Eo "3\.[0-9]" |tail -n1)
PYTHON="/usr/local/bin/python$PYTHONVERSION"
vilain.py
@@ -30,7 +30,7 @@
import time
CONFIGFILE = "/etc/vilain.conf"
VERSION = "0.6"
VERSION = "0.7"
vilain_table = "vilain_bruteforce"
LOGFILE = "/var/log/daemon"
@@ -46,7 +46,7 @@
    log_handler = logging.handlers.WatchedFileHandler(LOGFILE)
    formatter = logging.Formatter(
            '%(asctime)s %(module)s:%(funcName)s:%(message)s',
            '%b %d %H:%M:%S')
            '%Y-%m-%d %H:%M:%S')
    log_handler.setFormatter(formatter)
    logger.addHandler(log_handler)
    logger.setLevel(logging.INFO)
@@ -182,7 +182,7 @@
            logger.info("{} detected, reason {}, count: {}, maxtries: {}".format(ip, reason, n_ip, maxtries))
            if n_ip >= maxtries:
                ret = subprocess.call(["pfctl", "-t", self.vilain_table, "-T", "add", ip])
                logger.info("Blacklisting {}, return code:{}".format(ip, ret))
                logger.info("Blacklisting {}, reason {}, return code:{}".format(ip, reason, ret))
            #for debugging, this line allow us to see if the script run until here
            logger.debug('ban_ips end:{}'.format(self.ip_seen_at))
vilainreport
New file
@@ -0,0 +1,11 @@
#!/bin/sh
# script to launch vilainreport with the latest python3 version available
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/vilainreport.py
else
    echo "Error : no python3 executable found"
fi
exit
vilainreport.py
New file
@@ -0,0 +1,123 @@
#!/usr/bin/env python3
# -*- coding:Utf-8 -*-
import re
import sys
pattern = '(\d+)-(\d+)-(\d+) (\d+):(\d+):(\d+).*Blacklisting (\d+\.\d+\.\d+\.\d+), reason (.*), return'
regex = re.compile(pattern)
class CounterDict:
    def __init__(self):
        self._counters = dict()
    def inc(self, k):
        v = self._counters.get(k, 0) + 1
        self._counters[k] = v
    def get(self, k):
        return self._counters.get(k, 0)
    def keys(self):
        return self._counters.keys()
    def reset(self):
        self._counters = dict()
    def topitems(self):
        return sorted(self._counters.items(), key=lambda x: x[1], reverse=True)
class Value:
    def __init__(self):
        self._value = ""
    def __str__(self):
        return self._value
    def __eq__(self, other):
        return str(self._value) == str(other)
    def set(self, value):
        self._value = value
last_day = Value()
# daily counters: key is reason
dcounters = CounterDict()
# global counters: key is reason
gcounters = CounterDict()
# hourly counters: key is hour
hcounters = CounterDict()
# top counters: key is IP
tcounters = CounterDict()
def plural(noun, count):
    if count > 1:
        return noun + "s"
    else:
        return noun
def process(m):
    current_day = m.group(1) + "-" + m.group(2) + "-" + m.group(3)
    current_hour = m.group(4)
    full_time = m.group(4) + ":" + m.group(5) + ":" + m.group(6)
    ip = m.group(7)
    reason = m.group(8)
    # new day
    #print("({})-({}) => {}".format(last_day, current_day, last_day == current_day))
    if last_day != current_day:
        # display day counters
        sys.stdout.write("\n")
        for reason in dcounters.keys():
            count = dcounters.get(reason)
            sys.stdout.write("Probe '{}': {} {}\n".format(reason, count, plural("attack", count)))
        last_day.set(current_day)
        dcounters.reset()
        sys.stdout.write("\n### Date {}\n".format(current_day))
    # output current line
    sys.stdout.write("{} blacklist IP {} ({})\n".format(full_time, ip, reason))
    # increment counters
    dcounters.inc(reason)
    gcounters.inc(reason)
    hcounters.inc(current_hour)
    tcounters.inc(ip)
# parse stdin
for line in sys.stdin:
    match = regex.match(line)
    if match:
        process(match)
# output counters
sys.stdout.write("\n")
for reason in dcounters.keys():
    sys.stdout.write("Probe '{}' : {} attacks\n".format(reason, dcounters.get(reason)))
sys.stdout.write("\n### Attacks per probe\n")
for k in gcounters.keys():
    count = gcounters.get(k)
    sys.stdout.write("Probe '{}': {} {} \n".format(k, count, plural("attack", count)))
sys.stdout.write("\n### Hourly repartition\n")
for k in sorted(hcounters.keys()):
    sys.stdout.write("Hour {} - {:02d}: {}\n".format(k, int(k) + 1, hcounters.get(k)))
sys.stdout.write("\n### Top attackers\n")
for k, v in tcounters.topitems():
    if v < 2:
        break
    sys.stdout.write("IP {:16}: {}\n".format(k, v))