- New log rotation detection algorithm.

- Print monitored files in status.

git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/branches/FAIL2BAN-0_8@644 a942ae1a-1317-0410-a47c-b1dcaea8d605
_tent/ipv6_via_aInfo
Cyril Jaquier 2008-01-14 23:12:21 +00:00
parent 2703c8ebb9
commit 695b6b1fe5
4 changed files with 110 additions and 85 deletions

View File

@ -4,10 +4,10 @@
|_| \__,_|_|_/___|_.__/\__,_|_||_|
=============================================================
Fail2Ban (version 0.8.2) 2007/??/??
Fail2Ban (version 0.8.2) 2008/??/??
=============================================================
ver. 0.8.2 (2007/??/??) - stable
ver. 0.8.2 (2008/??/??) - stable
----------
- Fixed named filter. Thanks to Yaroslav Halchenko
- Fixed wrong path for apache-auth in jail.conf. Thanks to
@ -27,6 +27,8 @@ ver. 0.8.2 (2007/??/??) - stable
- Refactoring. Reduced number of files.
- Removed Python 2.4. Minimum required version is now Python
2.3.
- New log rotation detection algorithm.
- Print monitored files in status.
ver. 0.8.1 (2007/08/14) - stable
----------

View File

@ -72,9 +72,14 @@ class Beautifier:
ipList = ""
for ip in response[1][1][2][1]:
ipList += ip + " "
# Creates file list.
fileList = ""
for f in response[0][1][2][1]:
fileList += f + " "
# Display information
msg = "Status for the jail: " + inC[1] + "\n"
msg = msg + "|- " + response[0][0] + "\n"
msg = msg + "| |- " + response[0][1][2][0] + ":\t" + fileList + "\n"
msg = msg + "| |- " + response[0][1][0][0] + ":\t" + `response[0][1][0][1]` + "\n"
msg = msg + "| `- " + response[0][1][1][0] + ":\t" + `response[0][1][1][1]` + "\n"
msg = msg + "`- " + response[1][0] + "\n"

View File

@ -242,8 +242,8 @@ class Filter(JailThread):
# Decode line to UTF-8
l = line.decode('utf-8')
except UnicodeDecodeError:
pass
timeMatch = self.dateDetector.matchTime(line)
l = line
timeMatch = self.dateDetector.matchTime(l)
if not timeMatch:
# There is no valid time in this line
return
@ -335,26 +335,17 @@ 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
def addLogPath(self, path, tail = False):
container = FileContainer(path, tail)
self.__logPath.append(container)
##
# Delete a log path
@ -362,9 +353,10 @@ class FileFilter(Filter):
# @param path the log file to delete
def delLogPath(self, path):
self.getLogPath().remove(path)
del self.__lastDate[path]
del self.__lastPos[path]
for log in self.__logPath:
if log.getFileName() == path:
self.__logPath.remove(log)
return
##
# Get the log file path
@ -381,62 +373,16 @@ class FileFilter(Filter):
# @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")
for log in self.__logPath:
if log.getFileName() == path:
return True
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()
def getFileContainer(self, path):
for log in self.__logPath:
if log.getFileName() == path:
return log
return None
##
# Gets all the failure in the log file.
@ -446,13 +392,20 @@ class FileFilter(Filter):
# is created and is added to the FailManager.
def getFailures(self, filename):
# Try to open log file.
if not self.__openLogFile(filename):
container = self.getFileContainer(filename)
if container == None:
logSys.error("Unable to get failures in " + filename)
return False
self.__setFilePos()
lastTimeLine = None
for line in self.__crtHandler:
# Try to open log file.
try:
container.open()
except Exception, e:
logSys.error("Unable to open %s" % filename)
logSys.exception(e)
return False
line = container.readline()
while not line == "":
if not self._isActive():
# The jail has been stopped
break
@ -464,6 +417,7 @@ class FileFilter(Filter):
timeMatch = self.dateDetector.matchTime(line)
if not timeMatch:
# There is no valid time in this line
line = container.readline()
continue
# Lets split into time part and log part of the line
timeLine = timeMatch.group()
@ -471,7 +425,6 @@ class FileFilter(Filter):
# 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]
@ -482,12 +435,77 @@ class FileFilter(Filter):
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()
# Read a new line.
line = container.readline()
container.close()
return True
def status(self):
ret = Filter.status(self)
path = [m.getFileName() for m in self.getLogPath()]
ret.append(("File list", path))
return ret
##
# FileContainer class.
#
# This class manages a file handler and takes care of log rotation detection.
# In order to detect log rotation, the hash (MD5) of the first line of the file
# is computed and compared to the previous hash of this line.
import md5
class FileContainer:
def __init__(self, filename, tail = False):
self.__filename = filename
self.__tail = tail
self.__handler = None
# Try to open the file. Raises an exception if an error occured.
handler = open(filename)
try:
firstLine = handler.readline()
# Computes the MD5 of the first line.
self.__hash = md5.new(firstLine).digest()
# Start at the beginning of file if tail mode is off.
if tail:
handler.seek(0, 2)
self.__pos = handler.tell()
else:
self.__pos = 0
finally:
handler.close()
def getFileName(self):
return self.__filename
def open(self):
self.__handler = open(self.__filename)
firstLine = self.__handler.readline()
# Computes the MD5 of the first line.
myHash = md5.new(firstLine).digest()
# Compare hash.
if not self.__hash == myHash:
logSys.info("Log rotation detected for %s" % self.__filename)
self.__hash = myHash
self.__pos = 0
# Sets the file pointer to the last position.
self.__handler.seek(self.__pos)
def readline(self):
if self.__handler == None:
return ""
return self.__handler.readline()
def close(self):
if not self.__handler == None:
# Saves the last position.
self.__pos = self.__handler.tell()
# Closes the file.
self.__handler.close()
self.__handler = None
##
# Utils class for DNS and IP handling.

View File

@ -126,6 +126,6 @@ class FilterGamin(FileFilter):
# Desallocates the resources used by Gamin.
def __cleanup(self):
for path in self.getLogPath(self):
self.monitor.stop_watch(path)
for path in self.getLogPath():
self.monitor.stop_watch(path.getFileName())
del self.monitor