From f340e5c0f5a74a6bb0b515d9e25dec57f28467c6 Mon Sep 17 00:00:00 2001 From: Yaroslav Halchenko Date: Tue, 2 Jul 2013 20:43:51 -0400 Subject: [PATCH] ENH(+possibly BF): for FilterPoll rely not only on mtime but also ino and size to assess if file was modified mtime alone is a poor measure here as many of our tests shown -- on older Pythons and some file systems mtime might be reported only with precision up to a second. If file gets rotated fast, or there are new modifications within the same second, fail2ban might miss them with Polling backend if judging only by mtime. With this modification we will track also inode and size which are all indicative of a file change. --- server/filterpoll.py | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/server/filterpoll.py b/server/filterpoll.py index 4acecd42..4cd7cb48 100644 --- a/server/filterpoll.py +++ b/server/filterpoll.py @@ -57,7 +57,7 @@ class FilterPoll(FileFilter): FileFilter.__init__(self, jail) self.__modified = False ## The time of the last modification of the file. - self.__lastModTime = dict() + self.__prevStats = dict() self.__file404Cnt = dict() logSys.debug("Created FilterPoll") @@ -67,7 +67,7 @@ class FilterPoll(FileFilter): # @param path log file path def _addLogPath(self, path): - self.__lastModTime[path] = 0 + self.__prevStats[path] = (0, None, None) # mtime, ino, size self.__file404Cnt[path] = 0 ## @@ -76,7 +76,7 @@ class FilterPoll(FileFilter): # @param path the log file to delete def _delLogPath(self, path): - del self.__lastModTime[path] + del self.__prevStats[path] del self.__file404Cnt[path] ## @@ -126,18 +126,20 @@ class FilterPoll(FileFilter): def isModified(self, filename): try: logStats = os.stat(filename) + stats = logStats.st_mtime, logStats.st_ino, logStats.st_size + pstats = self.__prevStats[filename] self.__file404Cnt[filename] = 0 if logSys.getEffectiveLevel() <= 7: # we do not want to waste time on strftime etc if not necessary - dt = logStats.st_mtime - self.__lastModTime[filename] - logSys.log(7, "Checking %s for being modified. Previous/current mtimes: %s / %s. dt: %s", - filename, _ctime(self.__lastModTime[filename]), _ctime(logStats.st_mtime), dt) + dt = logStats.st_mtime - pstats[0] + logSys.log(7, "Checking %s for being modified. Previous/current stats: %s / %s. dt: %s", + filename, pstats, stats, dt) # os.system("stat %s | grep Modify" % filename) - if self.__lastModTime[filename] == logStats.st_mtime: + if pstats == stats: return False else: - logSys.debug(filename + " has been modified") - self.__lastModTime[filename] = logStats.st_mtime + logSys.debug("%s has been modified", filename) + self.__prevStats[filename] = stats return True except OSError, e: logSys.error("Unable to get stat on %s because of: %s"