mirror of https://github.com/fail2ban/fail2ban
- 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
parent
9199e02853
commit
65dcbed591
272
server/filter.py
272
server/filter.py
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
||||
##
|
||||
|
|
|
@ -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)
|
||||
|
|
@ -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}")
|
||||
|
|
Loading…
Reference in New Issue