From c7ace886dede07cab8034337f136479ef32051bc Mon Sep 17 00:00:00 2001
From: Thuban <thuban@yeuxdelibad.net>
Date: Mon, 21 Aug 2017 13:40:38 +0000
Subject: [PATCH] support logrotate

---
 vilain.py |   42 ++++++++++++++++++++++++------------------
 1 files changed, 24 insertions(+), 18 deletions(-)

diff --git a/vilain.py b/vilain.py
index 6cfa7f1..d36c59f 100755
--- a/vilain.py
+++ b/vilain.py
@@ -24,6 +24,7 @@
 import configparser
 import re
 import logging
+import logging.handlers
 import subprocess
 import asyncio
 import time
@@ -31,17 +32,20 @@
 CONFIGFILE = "/etc/vilain.conf"
 VERSION = "0.5"
 vilain_table = "vilain_bruteforce"
-logfile = "/var/log/daemon"
+LOGFILE = "/var/log/daemon"
 
 if os.geteuid() != 0:
     print("Only root can use this tool")
     sys.exit(1)
 
 # Configure logging
+log_handler = logging.handlers.WatchedFileHandler(LOGFILE)
+formatter = logging.Formatter(
+        '%(asctime)s %(module)s:%(funcName)s:%(message)s',
+        '%b %d %H:%M:%S')
+log_handler.setFormatter(formatter)
 logger = logging.getLogger(__name__)
-logging.basicConfig(filename=logfile,
-                    format='%(asctime)s %(module)s:%(funcName)s:%(message)s',
-                    datefmt='%H:%M:%S')
+logger.addHandler(log_handler)
 logger.setLevel(logging.INFO)
 
 # functions
@@ -59,7 +63,7 @@
     c = readconfig()
     d = c.defaults()
     watch_while = int(d['watch_while'])
-    vilain_table = d['vilain_table']
+    VILAIN_TABLE = d['vilain_table']
     default_maxtries = int(d['maxtries'])
     sleeptime = float(d['sleeptime'])
     ignore_ips = []
@@ -72,16 +76,15 @@
     c = readconfig()
     for s in c.sections():
         if c.has_option(s,'logfile'):
-            logfile = c.get(s,'logfile')
+            LOGFILE = c.get(s,'logfile')
             regex = c.get(s,'regex')
             #we take the default value of maxtries
             maxtries = c.defaults()['maxtries']
             if c.has_option(s,'maxtries'):
                 #if we have a maxtries defined in the section, we overwrite the default
                 maxtries = int(c.get(s,'maxtries'))
-            d = {'name' : s, 'logfile':logfile, 'regex':regex, 'maxtries': maxtries}
+            d = {'name' : s, 'logfile':LOGFILE, 'regex':regex, 'maxtries': maxtries}
             yield d
-
 
 class Vilain():
     def __init__(self):
@@ -93,7 +96,7 @@
         self.bad_ip_queue = asyncio.Queue(loop=self.loop)
 
         for entry in load_sections():
-            logger.info("Start vilain for {}".format(entry['name']))
+            logger.info("Start vilain for {}".format(entry))
             asyncio.ensure_future(self.check_logs(entry['logfile'], entry['maxtries'], entry['regex'], entry['name']))
 
         asyncio.ensure_future(self.ban_ips())
@@ -114,12 +117,12 @@
 
     def start(self):
         try:
+            logger.info('Run forever loop')
             self.loop.run_forever()
         except KeyboardInterrupt:
             self.loop.close()
         finally:
             self.loop.close()
-
 
     async def check_logs(self, logfile, maxtries, regex, reason):
         """
@@ -131,16 +134,21 @@
             # Watch the file for changes
             stat = os.stat(logfile)
             size = stat.st_size
+            inode = stat.st_ino
             mtime = stat.st_mtime
             RE = re.compile(regex)
             while True:
                 await asyncio.sleep(self.sleeptime)
                 stat = os.stat(logfile)
-                if mtime < stat.st_mtime:
+                if size > stat.st_size and inode != stat.st_ino:
+                    logger.info("The file {} has rotated. We start from position 0".format(logfile))
+                    size = 0
+                    inode = stat.st_ino
+                if mtime < stat.st_mtime and inode == stat.st_ino:
                     logger.debug("{} has been modified".format(logfile))
                     mtime = stat.st_mtime
                     with open(logfile, "rb") as f:
-                        f.seek(size)
+                        f.seek(size,0)
                         for bline in f.readlines():
                             line = bline.decode().strip()
                             ret = RE.match(line)
@@ -152,8 +160,7 @@
                                     await self.bad_ip_queue.put({'ip' : bad_ip, 'maxtries': maxtries, 'reason' : reason})
                                     logger.debug('queue size: {}'.format(self.bad_ip_queue.qsize()))
                                 else:
-                                    logger.info('line match {}. But IP in ingore list'.format(bad_ip))
-
+                                    logger.info('line match {}. But IP in ignore list'.format(bad_ip))
                     size = stat.st_size
 
     async def ban_ips(self):
@@ -161,9 +168,8 @@
         record time when this IP has been seen in ip_seen_at = { ip:{'time':<time>,'count':<counter} }
         and ban with pf
         """
-        logger.info('ban_ips sarted with sleeptime={}'.format(self.sleeptime))
+        logger.info('ban_ips started')
         while True:
-            # await asyncio.sleep(self.sleeptime)
             ip_item = await self.bad_ip_queue.get()
             logger.debug('ban_ips awake')
             ip = ip_item['ip']
@@ -183,9 +189,9 @@
         """
         check old ip in ip_seen_at : remove older than watch_while
         """
-        logger.info('clean_ips sarted with sleeptime={}'.format(self.sleeptime))
+        logger.info('clean_ips started with sleeptime={}'.format(self.sleeptime))
         while True:
-            await asyncio.sleep(self.sleeptime)
+            await asyncio.sleep(self.watch_while)
             to_remove = []
             for recorded_ip, data in self.ip_seen_at.items():
                 if time.time() - data['time'] >= self.watch_while:

--
Gitblit v1.9.3