- 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
## The failures manager.
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.
self.__failRegex = list()
## The regular expression list with expressions to ignore.
@ -70,58 +65,12 @@ class Filter(JailThread):
self.__findTime = 6000
## The ignore IP list.
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.addDefaultTemplate()
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.
#
@ -284,6 +233,160 @@ class Filter(JailThread):
return True
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.
@ -372,7 +475,7 @@ class Filter(JailThread):
for element in self.findFailure(timeLine, logLine):
ip = element[0]
unixTime = element[1]
if unixTime < MyTime.time()-self.__findTime:
if unixTime < MyTime.time() - self.getFindTime():
break
if self.inIgnoreIPList(ip):
logSys.debug("Ignore "+ip)
@ -385,71 +488,6 @@ class Filter(JailThread):
self.__closeLogFile()
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.

View File

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

View File

@ -25,7 +25,7 @@ __copyright__ = "Copyright (c) 2004 Cyril Jaquier"
__license__ = "GPL"
from failmanager import FailManagerEmpty
from filter import Filter
from filter import FileFilter
from mytime import MyTime
import time, logging, os
@ -40,7 +40,7 @@ logSys = logging.getLogger("fail2ban.filter")
# that matches a given regular expression. This class is instanciated by
# a Jail object.
class FilterPoll(Filter):
class FilterPoll(FileFilter):
##
# Constructor.
@ -49,7 +49,7 @@ class FilterPoll(Filter):
# @param jail the jail object
def __init__(self, jail):
Filter.__init__(self, jail)
FileFilter.__init__(self, jail)
self.__modified = False
## The time of the last modification of the file.
self.__lastModTime = dict()
@ -67,7 +67,7 @@ class FilterPoll(Filter):
else:
self.__lastModTime[path] = 0
self.__file404Cnt[path] = 0
Filter.addLogPath(self, path)
FileFilter.addLogPath(self, path)
logSys.info("Added logfile = %s" % path)
##
@ -81,7 +81,7 @@ class FilterPoll(Filter):
else:
del self.__lastModTime[path]
del self.__file404Cnt[path]
Filter.delLogPath(self, path)
FileFilter.delLogPath(self, 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.getUnixTime(log), dateUnix)
def testDefaultTempate(self):
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")
log = "Jan 23 21:59:59 [sshd] error: PAM: Authentication failure"
date = [2005, 1, 23, 21, 59, 59, 1, 23, -1]
dateUnix = 1106513999.0
self.assertEqual(self.__datedetector.getTime(log), date)
self.assertEqual(self.__datedetector.getUnixTime(log), dateUnix)
# def testDefaultTempate(self):
# 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")
#
# log = "Jan 23 21:59:59 [sshd] error: PAM: Authentication failure"
# date = [2005, 1, 23, 21, 59, 59, 1, 23, -1]
# dateUnix = 1106513999.0
#
# self.assertEqual(self.__datedetector.getTime(log), date)
# self.assertEqual(self.__datedetector.getUnixTime(log), dateUnix)

View File

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