From ada2d7234e5546dc020bba27ce10a67ecc2456fe Mon Sep 17 00:00:00 2001 From: Cyril Jaquier Date: Tue, 10 Jul 2007 19:54:01 +0000 Subject: [PATCH] - Added "ignoreregex" support to fail2ban-regex git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/branches/FAIL2BAN-0_8@596 a942ae1a-1317-0410-a47c-b1dcaea8d605 --- CHANGELOG | 1 + fail2ban-regex | 103 +++++++++++++++++++++++++++++++++++++++++++---- server/filter.py | 23 ++++++++--- 3 files changed, 113 insertions(+), 14 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index fe76ac7c..d4c19632 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -14,6 +14,7 @@ ver. 0.8.1 (2007/??/??) - stable - Improved regular expressions. Thanks to Yaroslav Halchenko - Added sendmail actions. The action started with "mail" are now deprecated. Thanks to Raphaƫl Marichez +- Added "ignoreregex" support to fail2ban-regex ver. 0.8.0 (2007/05/03) - stable ---------- diff --git a/fail2ban-regex b/fail2ban-regex index 28ea4b43..2f987e0c 100755 --- a/fail2ban-regex +++ b/fail2ban-regex @@ -68,6 +68,7 @@ class Fail2banRegex: def __init__(self): self.__filter = Filter(None) + self.__ignoreregex = list() self.__failregex = list() # Setup logging logging.getLogger("fail2ban").handlers = [] @@ -92,7 +93,7 @@ class Fail2banRegex: @staticmethod def dispUsage(): - print "Usage: "+sys.argv[0]+" [OPTIONS] " + print "Usage: "+sys.argv[0]+" [OPTIONS] [IGNOREREGEX]" print print "Fail2Ban v" + version + " reads log file that contains password failure report" print "and bans the corresponding IP addresses using firewall rules." @@ -111,6 +112,10 @@ class Fail2banRegex: print " string a string representing a 'failregex'" print " filename path to a filter file (filter.d/sshd.conf)" print + print "IgnoreRegex:" + print " string a string representing an 'ignoreregex'" + print " filename path to a filter file (filter.d/sshd.conf)" + print print "Report bugs to " def getCmdLineOptions(self, optList): @@ -128,6 +133,35 @@ class Fail2banRegex: def logIsFile(value): return os.path.isfile(value) + def readIgnoreRegex(self, value): + if os.path.isfile(value): + reader = SafeConfigParser() + try: + reader.read(value) + print "Use ignoreregex file : " + value + self.__ignoreregex = [RegexStat(m) + for m in reader.get("Definition", "ignoreregex").split('\n')] + except NoSectionError: + print "No [Definition] section in " + value + print + return False + except NoOptionError: + print "No failregex option in " + value + print + return False + except MissingSectionHeaderError: + print "No section headers in " + value + print + return False + else: + if len(value) > 53: + stripReg = value[0:50] + "..." + else: + stripReg = value + print "Use ignoreregex line : " + stripReg + self.__ignoreregex = [RegexStat(value)] + return True + def readRegex(self, value): if os.path.isfile(value): reader = SafeConfigParser() @@ -157,8 +191,27 @@ class Fail2banRegex: self.__failregex = [RegexStat(value)] return True + def testIgnoreRegex(self, line): + found = False + for regex in self.__ignoreregex: + logging.getLogger("fail2ban").setLevel(logging.DEBUG) + try: + self.__filter.addIgnoreRegex(regex.getFailRegex()) + try: + ret = self.__filter.ignoreLine(line) + if ret: + regex.inc() + except RegexException, e: + print e + return False + finally: + self.__filter.delIgnoreRegex(0) + logging.getLogger("fail2ban").setLevel(logging.CRITICAL) + def testRegex(self, line): found = False + for regex in self.__ignoreregex: + self.__filter.addIgnoreRegex(regex.getFailRegex()) for regex in self.__failregex: logging.getLogger("fail2ban").setLevel(logging.DEBUG) try: @@ -182,6 +235,8 @@ class Fail2banRegex: finally: self.__filter.delFailRegex(0) logging.getLogger("fail2ban").setLevel(logging.CRITICAL) + for regex in self.__ignoreregex: + self.__filter.delIgnoreRegex(0) def printStats(self): print @@ -191,25 +246,51 @@ class Fail2banRegex: # Print title cnt = 1 - print "Failregex:" + print "Failregex" + print "|- Regular expressions:" for failregex in self.__failregex: - print "[" + str(cnt) + "] " + failregex.getFailRegex() + print "| [" + str(cnt) + "] " + failregex.getFailRegex() cnt += 1 + cnt = 1 - print + print "|" # Print stats cnt = 1 total = 0 - print "Number of matches:" + print "`- Number of matches:" for failregex in self.__failregex: match = failregex.getStats() total += match - print "[" + str(cnt) + "] " + str(match) + " match(es)" + print " [" + str(cnt) + "] " + str(match) + " match(es)" cnt += 1 print + # Print title + cnt = 1 + print "Ignoreregex" + print "|- Regular expressions:" + for failregex in self.__ignoreregex: + print "| [" + str(cnt) + "] " + failregex.getFailRegex() + cnt += 1 + cnt = 1 + + print "|" + + # Print stats + cnt = 1 + print "`- Number of matches:" + for failregex in self.__ignoreregex: + match = failregex.getStats() + print " [" + str(cnt) + "] " + str(match) + " match(es)" + cnt += 1 + + print + print "Summary" + print "=======" + print + if total == 0: print "Sorry, no match" print @@ -236,7 +317,7 @@ class Fail2banRegex: print "Date template hits:" for template in self.__filter.dateDetector.getTemplates(): - print `template.getHits()` + " hit: " + template.getName() + print `template.getHits()` + " hit(s): " + template.getName() print @@ -260,7 +341,7 @@ if __name__ == "__main__": # Process command line fail2banRegex.getCmdLineOptions(optList) # We need exactly 3 parameters - if not len(sys.argv) == 3: + if not len(sys.argv) in (3, 4): fail2banRegex.dispUsage() sys.exit(-1) else: @@ -269,6 +350,10 @@ if __name__ == "__main__": print "=============" print + if len(sys.argv) == 4: + if fail2banRegex.readIgnoreRegex(sys.argv[3]) == False: + sys.exit(-1) + if fail2banRegex.readRegex(sys.argv[2]) == False: sys.exit(-1) @@ -278,6 +363,7 @@ if __name__ == "__main__": print "Use log file : " + sys.argv[1] print for line in hdlr: + fail2banRegex.testIgnoreRegex(line) fail2banRegex.testRegex(line) except IOError, e: print e @@ -290,6 +376,7 @@ if __name__ == "__main__": stripLog = sys.argv[1] print "Use single line: " + stripLog print + fail2banRegex.testIgnoreRegex(sys.argv[1]) fail2banRegex.testRegex(sys.argv[1]) if fail2banRegex.printStats(): diff --git a/server/filter.py b/server/filter.py index 131c6d02..b567445a 100644 --- a/server/filter.py +++ b/server/filter.py @@ -413,6 +413,20 @@ 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. # @@ -423,12 +437,9 @@ class Filter(JailThread): def findFailure(self, line): failList = list() # Checks if we must ignore this line. - for ignoreRegex in self.__ignoreRegex: - ignoreRegex.search(line) - if ignoreRegex.hasMatched(): - # The ignoreregex matched. Return. - logSys.debug("Ignoring this line") - return failList + if self.ignoreLine(line): + # The ignoreregex matched. Return. + return failList # Iterates over all the regular expressions. for failRegex in self.__failRegex: failRegex.search(line)