- 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,6 +233,160 @@ class Filter(JailThread):
return True return True
return False return False
def processLine(self, line):
if not self._isActive():
# The jail has been stopped
return
try:
# Decode line to UTF-8
l = line.decode('utf-8')
except UnicodeDecodeError:
pass
timeMatch = self.dateDetector.matchTime(line)
if not timeMatch:
# There is no valid time in this line
return
# 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 = l[:timeMatch.start()] + l[timeMatch.end():]
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))
##
# Returns true if the line should be ignored.
#
# Uses ignoreregex.
# @param line: the line
# @return: a boolean
def ignoreLine(self, line):
for ignoreRegex in self.__ignoreRegex:
ignoreRegex.search(line)
if ignoreRegex.hasMatched():
return True
return False
##
# Finds the failure in a line given split into time and log parts.
#
# Uses the failregex pattern to find it and timeregex in order
# to find the logging time.
# @return a dict with IP and timestamp.
def findFailure(self, timeLine, logLine):
failList = list()
# Checks if we must ignore this line.
if self.ignoreLine(logLine):
# The ignoreregex matched. Return.
return failList
# Iterates over all the regular expressions.
for failRegex in self.__failRegex:
failRegex.search(logLine)
if failRegex.hasMatched():
# The failregex matched.
date = self.dateDetector.getUnixTime(timeLine)
if date == None:
logSys.debug("Found a match for '" + logLine +"' but no "
+ "valid date/time found for '"
+ timeLine + "'. Please contact the "
+ "author in order to get support for this "
+ "format")
else:
try:
host = failRegex.getHost()
ipMatch = DNSUtils.textToIp(host)
if ipMatch:
for ip in ipMatch:
failList.append([ip, date])
# We matched a regex, it is enough to stop.
break
except RegexException, e:
logSys.error(e)
return failList
##
# Get the status of the filter.
#
# Get some informations about the filter state such as the total
# number of failures.
# @return a list with tuple
def status(self):
ret = [("Currently failed", self.failManager.size()),
("Total failed", self.failManager.getFailTotal())]
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. # Open the log file.
@ -372,7 +475,7 @@ class Filter(JailThread):
for element in self.findFailure(timeLine, logLine): for element in self.findFailure(timeLine, logLine):
ip = element[0] ip = element[0]
unixTime = element[1] unixTime = element[1]
if unixTime < MyTime.time()-self.__findTime: if unixTime < MyTime.time() - self.getFindTime():
break break
if self.inIgnoreIPList(ip): if self.inIgnoreIPList(ip):
logSys.debug("Ignore "+ip) logSys.debug("Ignore "+ip)
@ -385,71 +488,6 @@ class Filter(JailThread):
self.__closeLogFile() self.__closeLogFile()
return True return True
##
# Returns true if the line should be ignored.
#
# Uses ignoreregex.
# @param line: the line
# @return: a boolean
def ignoreLine(self, line):
for ignoreRegex in self.__ignoreRegex:
ignoreRegex.search(line)
if ignoreRegex.hasMatched():
return True
return False
##
# Finds the failure in a line given split into time and log parts.
#
# Uses the failregex pattern to find it and timeregex in order
# to find the logging time.
# @return a dict with IP and timestamp.
def findFailure(self, timeLine, logLine):
failList = list()
# Checks if we must ignore this line.
if self.ignoreLine(logLine):
# The ignoreregex matched. Return.
return failList
# Iterates over all the regular expressions.
for failRegex in self.__failRegex:
failRegex.search(logLine)
if failRegex.hasMatched():
# The failregex matched.
date = self.dateDetector.getUnixTime(timeLine)
if date == None:
logSys.debug("Found a match for '" + logLine +"' but no "
+ "valid date/time found for '"
+ timeLine + "'. Please contact the "
+ "author in order to get support for this "
+ "format")
else:
try:
host = failRegex.getHost()
ipMatch = DNSUtils.textToIp(host)
if ipMatch:
for ip in ipMatch:
failList.append([ip, date])
# We matched a regex, it is enough to stop.
break
except RegexException, e:
logSys.error(e)
return failList
##
# Get the status of the filter.
#
# Get some informations about the filter state such as the total
# number of failures.
# @return a list with tuple
def status(self):
ret = [("Currently failed", self.failManager.size()),
("Total failed", self.failManager.getFailTotal())]
return ret
## ##
# 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}")