mirror of https://github.com/fail2ban/fail2ban
- 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
parent
2703c8ebb9
commit
695b6b1fe5
|
@ -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 named filter. Thanks to Yaroslav Halchenko
|
||||||
- Fixed wrong path for apache-auth in jail.conf. Thanks to
|
- 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.
|
- Refactoring. Reduced number of files.
|
||||||
- Removed Python 2.4. Minimum required version is now Python
|
- Removed Python 2.4. Minimum required version is now Python
|
||||||
2.3.
|
2.3.
|
||||||
|
- New log rotation detection algorithm.
|
||||||
|
- Print monitored files in status.
|
||||||
|
|
||||||
ver. 0.8.1 (2007/08/14) - stable
|
ver. 0.8.1 (2007/08/14) - stable
|
||||||
----------
|
----------
|
||||||
|
|
|
@ -72,9 +72,14 @@ class Beautifier:
|
||||||
ipList = ""
|
ipList = ""
|
||||||
for ip in response[1][1][2][1]:
|
for ip in response[1][1][2][1]:
|
||||||
ipList += ip + " "
|
ipList += ip + " "
|
||||||
|
# Creates file list.
|
||||||
|
fileList = ""
|
||||||
|
for f in response[0][1][2][1]:
|
||||||
|
fileList += f + " "
|
||||||
# Display information
|
# Display information
|
||||||
msg = "Status for the jail: " + inC[1] + "\n"
|
msg = "Status for the jail: " + inC[1] + "\n"
|
||||||
msg = msg + "|- " + response[0][0] + "\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][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[0][1][1][0] + ":\t" + `response[0][1][1][1]` + "\n"
|
||||||
msg = msg + "`- " + response[1][0] + "\n"
|
msg = msg + "`- " + response[1][0] + "\n"
|
||||||
|
|
180
server/filter.py
180
server/filter.py
|
@ -242,8 +242,8 @@ class Filter(JailThread):
|
||||||
# Decode line to UTF-8
|
# Decode line to UTF-8
|
||||||
l = line.decode('utf-8')
|
l = line.decode('utf-8')
|
||||||
except UnicodeDecodeError:
|
except UnicodeDecodeError:
|
||||||
pass
|
l = line
|
||||||
timeMatch = self.dateDetector.matchTime(line)
|
timeMatch = self.dateDetector.matchTime(l)
|
||||||
if not timeMatch:
|
if not timeMatch:
|
||||||
# There is no valid time in this line
|
# There is no valid time in this line
|
||||||
return
|
return
|
||||||
|
@ -335,26 +335,17 @@ class FileFilter(Filter):
|
||||||
|
|
||||||
def __init__(self, jail):
|
def __init__(self, jail):
|
||||||
Filter.__init__(self, jail)
|
Filter.__init__(self, jail)
|
||||||
## The log file handler.
|
|
||||||
self.__crtHandler = None
|
|
||||||
self.__crtFilename = None
|
|
||||||
## The log file path.
|
## The log file path.
|
||||||
self.__logPath = []
|
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
|
# Add a log file path
|
||||||
#
|
#
|
||||||
# @param path log file path
|
# @param path log file path
|
||||||
|
|
||||||
def addLogPath(self, path):
|
def addLogPath(self, path, tail = False):
|
||||||
self.getLogPath().append(path)
|
container = FileContainer(path, tail)
|
||||||
# Initialize default values
|
self.__logPath.append(container)
|
||||||
self.__lastDate[path] = 0
|
|
||||||
self.__lastPos[path] = 0
|
|
||||||
|
|
||||||
##
|
##
|
||||||
# Delete a log path
|
# Delete a log path
|
||||||
|
@ -362,9 +353,10 @@ class FileFilter(Filter):
|
||||||
# @param path the log file to delete
|
# @param path the log file to delete
|
||||||
|
|
||||||
def delLogPath(self, path):
|
def delLogPath(self, path):
|
||||||
self.getLogPath().remove(path)
|
for log in self.__logPath:
|
||||||
del self.__lastDate[path]
|
if log.getFileName() == path:
|
||||||
del self.__lastPos[path]
|
self.__logPath.remove(log)
|
||||||
|
return
|
||||||
|
|
||||||
##
|
##
|
||||||
# Get the log file path
|
# Get the log file path
|
||||||
|
@ -381,62 +373,16 @@ class FileFilter(Filter):
|
||||||
# @return True if the path is already monitored else False
|
# @return True if the path is already monitored else False
|
||||||
|
|
||||||
def containsLogPath(self, path):
|
def containsLogPath(self, path):
|
||||||
try:
|
for log in self.__logPath:
|
||||||
self.getLogPath().index(path)
|
if log.getFileName() == path:
|
||||||
return True
|
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
|
return False
|
||||||
|
|
||||||
##
|
def getFileContainer(self, path):
|
||||||
# Close the log file.
|
for log in self.__logPath:
|
||||||
|
if log.getFileName() == path:
|
||||||
def __closeLogFile(self):
|
return log
|
||||||
self.__crtFilename = None
|
return 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.
|
||||||
|
@ -446,13 +392,20 @@ class FileFilter(Filter):
|
||||||
# is created and is added to the FailManager.
|
# is created and is added to the FailManager.
|
||||||
|
|
||||||
def getFailures(self, filename):
|
def getFailures(self, filename):
|
||||||
# Try to open log file.
|
container = self.getFileContainer(filename)
|
||||||
if not self.__openLogFile(filename):
|
if container == None:
|
||||||
logSys.error("Unable to get failures in " + filename)
|
logSys.error("Unable to get failures in " + filename)
|
||||||
return False
|
return False
|
||||||
self.__setFilePos()
|
# Try to open log file.
|
||||||
lastTimeLine = None
|
try:
|
||||||
for line in self.__crtHandler:
|
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():
|
if not self._isActive():
|
||||||
# The jail has been stopped
|
# The jail has been stopped
|
||||||
break
|
break
|
||||||
|
@ -464,6 +417,7 @@ class FileFilter(Filter):
|
||||||
timeMatch = self.dateDetector.matchTime(line)
|
timeMatch = self.dateDetector.matchTime(line)
|
||||||
if not timeMatch:
|
if not timeMatch:
|
||||||
# There is no valid time in this line
|
# There is no valid time in this line
|
||||||
|
line = container.readline()
|
||||||
continue
|
continue
|
||||||
# Lets split into time part and log part of the line
|
# Lets split into time part and log part of the line
|
||||||
timeLine = timeMatch.group()
|
timeLine = timeMatch.group()
|
||||||
|
@ -471,7 +425,6 @@ class FileFilter(Filter):
|
||||||
# anchore at the beginning of the time regexp, we don't
|
# anchore at the beginning of the time regexp, we don't
|
||||||
# at least allow injection. Should be harmless otherwise
|
# at least allow injection. Should be harmless otherwise
|
||||||
logLine = line[:timeMatch.start()] + line[timeMatch.end():]
|
logLine = line[:timeMatch.start()] + line[timeMatch.end():]
|
||||||
lastTimeLine = timeLine
|
|
||||||
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]
|
||||||
|
@ -482,11 +435,76 @@ class FileFilter(Filter):
|
||||||
continue
|
continue
|
||||||
logSys.debug("Found "+ip)
|
logSys.debug("Found "+ip)
|
||||||
self.failManager.addFailure(FailTicket(ip, unixTime))
|
self.failManager.addFailure(FailTicket(ip, unixTime))
|
||||||
self.__lastPos[filename] = self.__getFilePos()
|
# Read a new line.
|
||||||
if lastTimeLine:
|
line = container.readline()
|
||||||
self.__lastDate[filename] = self.dateDetector.getUnixTime(lastTimeLine)
|
container.close()
|
||||||
self.__closeLogFile()
|
|
||||||
return True
|
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
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
##
|
##
|
||||||
|
|
|
@ -126,6 +126,6 @@ class FilterGamin(FileFilter):
|
||||||
# Desallocates the resources used by Gamin.
|
# Desallocates the resources used by Gamin.
|
||||||
|
|
||||||
def __cleanup(self):
|
def __cleanup(self):
|
||||||
for path in self.getLogPath(self):
|
for path in self.getLogPath():
|
||||||
self.monitor.stop_watch(path)
|
self.monitor.stop_watch(path.getFileName())
|
||||||
del self.monitor
|
del self.monitor
|
||||||
|
|
Loading…
Reference in New Issue