- Split Filter into Filter and FileFilter.

git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/branches/FAIL2BAN-0_8@641 a942ae1a-1317-0410-a47c-b1dcaea8d605
_tent/ipv6_via_aInfo
Cyril Jaquier 2007-12-26 11:46:22 +00:00
parent 9199e02853
commit 65dcbed591
5 changed files with 210 additions and 172 deletions

View File

@ -57,11 +57,6 @@ class Filter(JailThread):
self.jail = jail self.jail = jail
## The failures manager. ## The failures manager.
self.failManager = FailManager() self.failManager = FailManager()
## The log file handler.
self.__crtHandler = None
self.__crtFilename = None
## The log file path.
self.__logPath = []
## The regular expression list matching the failures. ## The regular expression list matching the failures.
self.__failRegex = list() self.__failRegex = list()
## The regular expression list with expressions to ignore. ## The regular expression list with expressions to ignore.
@ -70,58 +65,12 @@ class Filter(JailThread):
self.__findTime = 6000 self.__findTime = 6000
## The ignore IP list. ## The ignore IP list.
self.__ignoreIpList = [] self.__ignoreIpList = []
## The last position of the file.
self.__lastPos = dict()
## The last date in tht log file.
self.__lastDate = dict()
self.dateDetector = DateDetector() self.dateDetector = DateDetector()
self.dateDetector.addDefaultTemplate() self.dateDetector.addDefaultTemplate()
logSys.info("Created Filter") logSys.info("Created Filter")
##
# Add a log file path
#
# @param path log file path
def addLogPath(self, path):
self.getLogPath().append(path)
# Initialize default values
self.__lastDate[path] = 0
self.__lastPos[path] = 0
##
# Delete a log path
#
# @param path the log file to delete
def delLogPath(self, path):
self.getLogPath().remove(path)
del self.__lastDate[path]
del self.__lastPos[path]
##
# Get the log file path
#
# @return log file path
def getLogPath(self):
return self.__logPath
##
# Check whether path is already monitored.
#
# @param path The path
# @return True if the path is already monitored else False
def containsLogPath(self, path):
try:
self.getLogPath().index(path)
return True
except ValueError:
return False
## ##
# Add a regular expression which matches the failure. # Add a regular expression which matches the failure.
# #
@ -284,106 +233,37 @@ class Filter(JailThread):
return True return True
return False return False
##
# Open the log file. def processLine(self, line):
if not self._isActive():
def __openLogFile(self, filename): # The jail has been stopped
""" Opens the log file specified on init. return
"""
try: try:
self.__crtFilename = filename # Decode line to UTF-8
self.__crtHandler = open(filename) l = line.decode('utf-8')
logSys.debug("Opened " + filename) except UnicodeDecodeError:
return True pass
except OSError: timeMatch = self.dateDetector.matchTime(line)
logSys.error("Unable to open " + filename) if not timeMatch:
except IOError: # There is no valid time in this line
logSys.error("Unable to read " + filename + return
". Please check permissions") # Lets split into time part and log part of the line
return False timeLine = timeMatch.group()
# Lets leave the beginning in as well, so if there is no
## # anchore at the beginning of the time regexp, we don't
# Close the log file. # at least allow injection. Should be harmless otherwise
logLine = l[:timeMatch.start()] + l[timeMatch.end():]
def __closeLogFile(self): for element in self.findFailure(timeLine, logLine):
self.__crtFilename = None ip = element[0]
self.__crtHandler.close() unixTime = element[1]
if unixTime < MyTime.time() - self.__findTime:
##
# Set the file position.
#
# Sets the file position. We must take care of log file rotation
# and reset the position to 0 in that case. Use the log message
# timestamp in order to detect this.
def __setFilePos(self):
line = self.__crtHandler.readline()
lastDate = self.__lastDate[self.__crtFilename]
lineDate = self.dateDetector.getUnixTime(line)
if lastDate < lineDate:
logSys.debug("Date " + `lastDate` + " is smaller than " + `lineDate`)
logSys.debug("Log rotation detected for " + self.__crtFilename)
self.__lastPos[self.__crtFilename] = 0
lastPos = self.__lastPos[self.__crtFilename]
logSys.debug("Setting file position to " + `lastPos` + " for " +
self.__crtFilename)
self.__crtHandler.seek(lastPos)
##
# Get the file position.
def __getFilePos(self):
return self.__crtHandler.tell()
##
# Gets all the failure in the log file.
#
# Gets all the failure in the log file which are newer than
# MyTime.time()-self.findTime. When a failure is detected, a FailTicket
# is created and is added to the FailManager.
def getFailures(self, filename):
# Try to open log file.
if not self.__openLogFile(filename):
logSys.error("Unable to get failures in " + filename)
return False
self.__setFilePos()
lastTimeLine = None
for line in self.__crtHandler:
if not self._isActive():
# The jail has been stopped
break break
try: if self.inIgnoreIPList(ip):
# Decode line to UTF-8 logSys.debug("Ignore "+ip)
line = line.decode('utf-8')
except UnicodeDecodeError:
pass
timeMatch = self.dateDetector.matchTime(line)
if not timeMatch:
# There is no valid time in this line
continue continue
# Lets split into time part and log part of the line logSys.debug("Found "+ip)
timeLine = timeMatch.group() self.failManager.addFailure(FailTicket(ip, unixTime))
# Lets leave the beginning in as well, so if there is no
# anchore at the beginning of the time regexp, we don't
# at least allow injection. Should be harmless otherwise
logLine = line[:timeMatch.start()] + line[timeMatch.end():]
lastTimeLine = timeLine
for element in self.findFailure(timeLine, logLine):
ip = element[0]
unixTime = element[1]
if unixTime < MyTime.time()-self.__findTime:
break
if self.inIgnoreIPList(ip):
logSys.debug("Ignore "+ip)
continue
logSys.debug("Found "+ip)
self.failManager.addFailure(FailTicket(ip, unixTime))
self.__lastPos[filename] = self.__getFilePos()
if lastTimeLine:
self.__lastDate[filename] = self.dateDetector.getUnixTime(lastTimeLine)
self.__closeLogFile()
return True
## ##
# Returns true if the line should be ignored. # Returns true if the line should be ignored.
@ -451,6 +331,164 @@ class Filter(JailThread):
return ret return ret
class FileFilter(Filter):
def __init__(self, jail):
Filter.__init__(self, jail)
## The log file handler.
self.__crtHandler = None
self.__crtFilename = None
## The log file path.
self.__logPath = []
## The last position of the file.
self.__lastPos = dict()
## The last date in tht log file.
self.__lastDate = dict()
##
# Add a log file path
#
# @param path log file path
def addLogPath(self, path):
self.getLogPath().append(path)
# Initialize default values
self.__lastDate[path] = 0
self.__lastPos[path] = 0
##
# Delete a log path
#
# @param path the log file to delete
def delLogPath(self, path):
self.getLogPath().remove(path)
del self.__lastDate[path]
del self.__lastPos[path]
##
# Get the log file path
#
# @return log file path
def getLogPath(self):
return self.__logPath
##
# Check whether path is already monitored.
#
# @param path The path
# @return True if the path is already monitored else False
def containsLogPath(self, path):
try:
self.getLogPath().index(path)
return True
except ValueError:
return False
##
# Open the log file.
def __openLogFile(self, filename):
""" Opens the log file specified on init.
"""
try:
self.__crtFilename = filename
self.__crtHandler = open(filename)
logSys.debug("Opened " + filename)
return True
except OSError:
logSys.error("Unable to open " + filename)
except IOError:
logSys.error("Unable to read " + filename +
". Please check permissions")
return False
##
# Close the log file.
def __closeLogFile(self):
self.__crtFilename = None
self.__crtHandler.close()
##
# Set the file position.
#
# Sets the file position. We must take care of log file rotation
# and reset the position to 0 in that case. Use the log message
# timestamp in order to detect this.
def __setFilePos(self):
line = self.__crtHandler.readline()
lastDate = self.__lastDate[self.__crtFilename]
lineDate = self.dateDetector.getUnixTime(line)
if lastDate < lineDate:
logSys.debug("Date " + `lastDate` + " is smaller than " + `lineDate`)
logSys.debug("Log rotation detected for " + self.__crtFilename)
self.__lastPos[self.__crtFilename] = 0
lastPos = self.__lastPos[self.__crtFilename]
logSys.debug("Setting file position to " + `lastPos` + " for " +
self.__crtFilename)
self.__crtHandler.seek(lastPos)
##
# Get the file position.
def __getFilePos(self):
return self.__crtHandler.tell()
##
# Gets all the failure in the log file.
#
# Gets all the failure in the log file which are newer than
# MyTime.time()-self.findTime. When a failure is detected, a FailTicket
# is created and is added to the FailManager.
def getFailures(self, filename):
# Try to open log file.
if not self.__openLogFile(filename):
logSys.error("Unable to get failures in " + filename)
return False
self.__setFilePos()
lastTimeLine = None
for line in self.__crtHandler:
if not self._isActive():
# The jail has been stopped
break
try:
# Decode line to UTF-8
line = line.decode('utf-8')
except UnicodeDecodeError:
pass
timeMatch = self.dateDetector.matchTime(line)
if not timeMatch:
# There is no valid time in this line
continue
# Lets split into time part and log part of the line
timeLine = timeMatch.group()
# Lets leave the beginning in as well, so if there is no
# anchore at the beginning of the time regexp, we don't
# at least allow injection. Should be harmless otherwise
logLine = line[:timeMatch.start()] + line[timeMatch.end():]
lastTimeLine = timeLine
for element in self.findFailure(timeLine, logLine):
ip = element[0]
unixTime = element[1]
if unixTime < MyTime.time() - self.getFindTime():
break
if self.inIgnoreIPList(ip):
logSys.debug("Ignore "+ip)
continue
logSys.debug("Found "+ip)
self.failManager.addFailure(FailTicket(ip, unixTime))
self.__lastPos[filename] = self.__getFilePos()
if lastTimeLine:
self.__lastDate[filename] = self.dateDetector.getUnixTime(lastTimeLine)
self.__closeLogFile()
return True
## ##
# Utils class for DNS and IP handling. # Utils class for DNS and IP handling.
# #

View File

@ -25,7 +25,7 @@ __copyright__ = "Copyright (c) 2004 Cyril Jaquier"
__license__ = "GPL" __license__ = "GPL"
from failmanager import FailManagerEmpty from failmanager import FailManagerEmpty
from filter import Filter from filter import FileFilter
from mytime import MyTime from mytime import MyTime
import time, logging, gamin import time, logging, gamin
@ -40,7 +40,7 @@ logSys = logging.getLogger("fail2ban.filter")
# that matches a given regular expression. This class is instanciated by # that matches a given regular expression. This class is instanciated by
# a Jail object. # a Jail object.
class FilterGamin(Filter): class FilterGamin(FileFilter):
## ##
# Constructor. # Constructor.
@ -49,7 +49,7 @@ class FilterGamin(Filter):
# @param jail the jail object # @param jail the jail object
def __init__(self, jail): def __init__(self, jail):
Filter.__init__(self, jail) FileFilter.__init__(self, jail)
self.__modified = False self.__modified = False
# Gamin monitor # Gamin monitor
self.monitor = gamin.WatchMonitor() self.monitor = gamin.WatchMonitor()
@ -74,7 +74,7 @@ class FilterGamin(Filter):
logSys.error(path + " already exists") logSys.error(path + " already exists")
else: else:
self.monitor.watch_file(path, self.callback) self.monitor.watch_file(path, self.callback)
Filter.addLogPath(self, path) FileFilter.addLogPath(self, path)
logSys.info("Added logfile = %s" % path) logSys.info("Added logfile = %s" % path)
## ##
@ -87,7 +87,7 @@ class FilterGamin(Filter):
logSys.error(path + " is not monitored") logSys.error(path + " is not monitored")
else: else:
self.monitor.stop_watch(path) self.monitor.stop_watch(path)
Filter.delLogPath(self, path) FileFilter.delLogPath(self, path)
logSys.info("Removed logfile = %s" % path) logSys.info("Removed logfile = %s" % path)
## ##
@ -126,6 +126,6 @@ class FilterGamin(Filter):
# Desallocates the resources used by Gamin. # Desallocates the resources used by Gamin.
def __cleanup(self): def __cleanup(self):
for path in Filter.getLogPath(self): for path in self.getLogPath(self):
self.monitor.stop_watch(path) self.monitor.stop_watch(path)
del self.monitor del self.monitor

View File

@ -25,7 +25,7 @@ __copyright__ = "Copyright (c) 2004 Cyril Jaquier"
__license__ = "GPL" __license__ = "GPL"
from failmanager import FailManagerEmpty from failmanager import FailManagerEmpty
from filter import Filter from filter import FileFilter
from mytime import MyTime from mytime import MyTime
import time, logging, os import time, logging, os
@ -40,7 +40,7 @@ logSys = logging.getLogger("fail2ban.filter")
# that matches a given regular expression. This class is instanciated by # that matches a given regular expression. This class is instanciated by
# a Jail object. # a Jail object.
class FilterPoll(Filter): class FilterPoll(FileFilter):
## ##
# Constructor. # Constructor.
@ -49,7 +49,7 @@ class FilterPoll(Filter):
# @param jail the jail object # @param jail the jail object
def __init__(self, jail): def __init__(self, jail):
Filter.__init__(self, jail) FileFilter.__init__(self, jail)
self.__modified = False self.__modified = False
## The time of the last modification of the file. ## The time of the last modification of the file.
self.__lastModTime = dict() self.__lastModTime = dict()
@ -67,7 +67,7 @@ class FilterPoll(Filter):
else: else:
self.__lastModTime[path] = 0 self.__lastModTime[path] = 0
self.__file404Cnt[path] = 0 self.__file404Cnt[path] = 0
Filter.addLogPath(self, path) FileFilter.addLogPath(self, path)
logSys.info("Added logfile = %s" % path) logSys.info("Added logfile = %s" % path)
## ##
@ -81,7 +81,7 @@ class FilterPoll(Filter):
else: else:
del self.__lastModTime[path] del self.__lastModTime[path]
del self.__file404Cnt[path] del self.__file404Cnt[path]
Filter.delLogPath(self, path) FileFilter.delLogPath(self, path)
logSys.info("Removed logfile = %s" % path) logSys.info("Removed logfile = %s" % path)
## ##

View File

@ -54,14 +54,14 @@ class DateDetectorTest(unittest.TestCase):
self.assertEqual(self.__datedetector.getTime(log), date) self.assertEqual(self.__datedetector.getTime(log), date)
self.assertEqual(self.__datedetector.getUnixTime(log), dateUnix) self.assertEqual(self.__datedetector.getUnixTime(log), dateUnix)
def testDefaultTempate(self): # def testDefaultTempate(self):
self.__datedetector.setDefaultRegex("^\S{3}\s{1,2}\d{1,2} \d{2}:\d{2}:\d{2}") # self.__datedetector.setDefaultRegex("^\S{3}\s{1,2}\d{1,2} \d{2}:\d{2}:\d{2}")
self.__datedetector.setDefaultPattern("%b %d %H:%M:%S") # self.__datedetector.setDefaultPattern("%b %d %H:%M:%S")
#
log = "Jan 23 21:59:59 [sshd] error: PAM: Authentication failure" # log = "Jan 23 21:59:59 [sshd] error: PAM: Authentication failure"
date = [2005, 1, 23, 21, 59, 59, 1, 23, -1] # date = [2005, 1, 23, 21, 59, 59, 1, 23, -1]
dateUnix = 1106513999.0 # dateUnix = 1106513999.0
#
self.assertEqual(self.__datedetector.getTime(log), date) # self.assertEqual(self.__datedetector.getTime(log), date)
self.assertEqual(self.__datedetector.getUnixTime(log), dateUnix) # self.assertEqual(self.__datedetector.getUnixTime(log), dateUnix)

View File

@ -26,7 +26,7 @@ __license__ = "GPL"
import unittest import unittest
from server.filterpoll import FilterPoll from server.filterpoll import FilterPoll
from server.filter import Filter from server.filter import FileFilter
from server.failmanager import FailManager from server.failmanager import FailManager
from server.failmanager import FailManagerEmpty from server.failmanager import FailManagerEmpty
@ -34,7 +34,7 @@ class IgnoreIP(unittest.TestCase):
def setUp(self): def setUp(self):
"""Call before every test case.""" """Call before every test case."""
self.__filter = Filter(None) self.__filter = FileFilter(None)
def tearDown(self): def tearDown(self):
"""Call after every test case.""" """Call after every test case."""
@ -86,7 +86,7 @@ class GetFailures(unittest.TestCase):
def setUp(self): def setUp(self):
"""Call before every test case.""" """Call before every test case."""
self.__filter = Filter(None) self.__filter = FileFilter(None)
self.__filter.setActive(True) self.__filter.setActive(True)
# TODO Test this # TODO Test this
#self.__filter.setTimeRegex("\S{3}\s{1,2}\d{1,2} \d{2}:\d{2}:\d{2}") #self.__filter.setTimeRegex("\S{3}\s{1,2}\d{1,2} \d{2}:\d{2}:\d{2}")