mirror of https://github.com/fail2ban/fail2ban
- Added file support to fail2ban-regex. Benchmark feature has been removed
git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/trunk@523 a942ae1a-1317-0410-a47c-b1dcaea8d6050.x
parent
a257fdc87d
commit
7bcfd2ace9
232
fail2ban-regex
232
fail2ban-regex
|
@ -1,4 +1,4 @@
|
|||
#!/usr/bin/env python
|
||||
#!/usr/bin/python -O
|
||||
# This file is part of Fail2Ban.
|
||||
#
|
||||
# Fail2Ban is free software; you can redistribute it and/or modify
|
||||
|
@ -25,12 +25,14 @@ __date__ = "$Date$"
|
|||
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
||||
__license__ = "GPL"
|
||||
|
||||
import locale, getopt, sys, time, logging, gc
|
||||
import getopt, sys, time, logging, os
|
||||
|
||||
# Inserts our own modules path first in the list
|
||||
# fix for bug #343821
|
||||
sys.path.insert(1, "/usr/share/fail2ban")
|
||||
|
||||
from ConfigParser import SafeConfigParser
|
||||
from ConfigParser import NoOptionError, NoSectionError, MissingSectionHeaderError
|
||||
from common.version import version
|
||||
from server.filter import Filter
|
||||
from server.regex import RegexException
|
||||
|
@ -38,13 +40,38 @@ from server.regex import RegexException
|
|||
# Gets the instance of the logger.
|
||||
logSys = logging.getLogger("fail2ban.regex")
|
||||
|
||||
class RegexStat:
|
||||
|
||||
def __init__(self, failregex):
|
||||
self.__stats = 0
|
||||
self.__failregex = failregex
|
||||
self.__ipList = list()
|
||||
|
||||
def inc(self):
|
||||
self.__stats += 1
|
||||
|
||||
def getStats(self):
|
||||
return self.__stats
|
||||
|
||||
def getFailRegex(self):
|
||||
return self.__failregex
|
||||
|
||||
def appendIP(self, value):
|
||||
self.__ipList.extend(value)
|
||||
|
||||
def getIPList(self):
|
||||
return self.__ipList
|
||||
|
||||
class Fail2banRegex:
|
||||
|
||||
test = None
|
||||
|
||||
def __init__(self):
|
||||
self.__filter = Filter(None)
|
||||
self.__failregex = list()
|
||||
# Setup logging
|
||||
logging.getLogger("fail2ban").handlers = []
|
||||
self.__hdlr = logging.StreamHandler(sys.stdout)
|
||||
self.__hdlr = logging.StreamHandler(Fail2banRegex.test)
|
||||
# set a format which is simpler for console use
|
||||
formatter = logging.Formatter("%(message)s")
|
||||
# tell the handler to use this format
|
||||
|
@ -52,7 +79,8 @@ class Fail2banRegex:
|
|||
logging.getLogger("fail2ban").addHandler(self.__hdlr)
|
||||
logging.getLogger("fail2ban").setLevel(logging.ERROR)
|
||||
|
||||
def dispVersion(self):
|
||||
@staticmethod
|
||||
def dispVersion():
|
||||
print "Fail2Ban v" + version
|
||||
print
|
||||
print "Copyright (c) 2004-2006 Cyril Jaquier"
|
||||
|
@ -62,14 +90,26 @@ class Fail2banRegex:
|
|||
print "Written by Cyril Jaquier <lostcontrol@users.sourceforge.net>."
|
||||
print "Many contributions by Yaroslav O. Halchenko <debian@onerussian.com>."
|
||||
|
||||
def dispUsage(self):
|
||||
print "Usage: "+sys.argv[0]+" <logline> <failregex>"
|
||||
@staticmethod
|
||||
def dispUsage():
|
||||
print "Usage: "+sys.argv[0]+" [OPTIONS] <LOG> <REGEX>"
|
||||
print
|
||||
print "Fail2Ban v" + version + " reads log file that contains password failure report"
|
||||
print "and bans the corresponding IP addresses using firewall rules."
|
||||
print
|
||||
print "This tools can test and benchmark your regular expressions for the \"failregex\""
|
||||
print "option."
|
||||
print "This tools can test regular expressions for \"fail2ban\"."
|
||||
print
|
||||
print "Options:"
|
||||
print " -h, --help display this help message"
|
||||
print " -V, --version print the version"
|
||||
print
|
||||
print "Log:"
|
||||
print " string a string representing a log line"
|
||||
print " filename path to a log file (/var/log/auth.log)"
|
||||
print
|
||||
print "Regex:"
|
||||
print " string a string representing a 'failregex'"
|
||||
print " filename path to a filter file (filter.d/sshd.conf)"
|
||||
print
|
||||
print "Report bugs to <lostcontrol@users.sourceforge.net>"
|
||||
|
||||
|
@ -78,87 +118,149 @@ class Fail2banRegex:
|
|||
"""
|
||||
for opt in optList:
|
||||
if opt[0] in ["-h", "--help"]:
|
||||
self.dispUsage()
|
||||
sys.exit(0)
|
||||
elif opt[0] in ["-V", "--version"]:
|
||||
self.dispVersion()
|
||||
sys.exit(0)
|
||||
self.dispUsage()
|
||||
sys.exit(0)
|
||||
elif opt[0] in ["-V", "--version"]:
|
||||
self.dispVersion()
|
||||
sys.exit(0)
|
||||
|
||||
@staticmethod
|
||||
def logIsFile(value):
|
||||
return os.path.isfile(value)
|
||||
|
||||
def readRegex(self, value):
|
||||
if os.path.isfile(value):
|
||||
reader = SafeConfigParser()
|
||||
try:
|
||||
reader.read(value)
|
||||
self.__failregex = [RegexStat(m)
|
||||
for m in reader.get("Definition", "failregex").split('\n')]
|
||||
except NoSectionError:
|
||||
print "No [Definition] section in " + value
|
||||
return False
|
||||
except NoOptionError:
|
||||
print "No failregex option in " + value
|
||||
return False
|
||||
except MissingSectionHeaderError:
|
||||
print "No section headers in " + value
|
||||
return False
|
||||
else:
|
||||
self.__failregex = [RegexStat(value)]
|
||||
return True
|
||||
|
||||
def testRegex(self, line, regex):
|
||||
print
|
||||
try:
|
||||
def testRegex(self, line):
|
||||
for regex in self.__failregex:
|
||||
logging.getLogger("fail2ban").setLevel(logging.DEBUG)
|
||||
self.__filter.addFailRegex(regex)
|
||||
ret = self.__filter.findFailure(line)
|
||||
print
|
||||
logging.getLogger("fail2ban").setLevel(logging.CRITICAL)
|
||||
except RegexException, e:
|
||||
print e
|
||||
return False
|
||||
except IndexError:
|
||||
print "Sorry, but no <host> found in regex"
|
||||
return False
|
||||
if len(ret) == 0:
|
||||
try:
|
||||
self.__filter.addFailRegex(regex.getFailRegex())
|
||||
try:
|
||||
ret = self.__filter.findFailure(line)
|
||||
if not len(ret) == 0:
|
||||
regex.inc()
|
||||
regex.appendIP(ret)
|
||||
except RegexException, e:
|
||||
print e
|
||||
return False
|
||||
except IndexError:
|
||||
print "Sorry, but no <host> found in regex"
|
||||
return False
|
||||
finally:
|
||||
self.__filter.delFailRegex(0)
|
||||
logging.getLogger("fail2ban").setLevel(logging.CRITICAL)
|
||||
|
||||
def printStats(self):
|
||||
print
|
||||
print "Results"
|
||||
print "======="
|
||||
print
|
||||
|
||||
# Print title
|
||||
cnt = 1
|
||||
print "Failregex:"
|
||||
for failregex in self.__failregex:
|
||||
print "[" + str(cnt) + "] " + failregex.getFailRegex()
|
||||
cnt += 1
|
||||
|
||||
print
|
||||
|
||||
# Print stats
|
||||
cnt = 1
|
||||
total = 0
|
||||
print "Number of matches:"
|
||||
for failregex in self.__failregex:
|
||||
match = failregex.getStats()
|
||||
total += match
|
||||
print "[" + str(cnt) + "] " + str(match) + " match(es)"
|
||||
cnt += 1
|
||||
|
||||
print
|
||||
|
||||
if total == 0:
|
||||
print "Sorry, no match"
|
||||
print
|
||||
print "Look at the above section 'Running tests' which could contain important"
|
||||
print "information."
|
||||
return False
|
||||
else:
|
||||
print "Success, the following data were found:"
|
||||
timeTuple = time.localtime(ret[0][1])
|
||||
print "Date: " + time.strftime("%a %b %d %H:%M:%S %Y", timeTuple)
|
||||
ipList = ""
|
||||
for i in ret:
|
||||
ipList = ipList + " " + i[0]
|
||||
print "IP :" + ipList
|
||||
# Print stats
|
||||
cnt = 1
|
||||
print "Addresses found:"
|
||||
for failregex in self.__failregex:
|
||||
print "[" + str(cnt) + "]"
|
||||
for ip in failregex.getIPList():
|
||||
timeTuple = time.localtime(ip[1])
|
||||
timeString = time.strftime("%a %b %d %H:%M:%S %Y", timeTuple)
|
||||
print " " + ip[0] + " (" + timeString + ")"
|
||||
cnt += 1
|
||||
|
||||
print
|
||||
|
||||
print "Date template hits:"
|
||||
for template in self.__filter.dateDetector.getTemplates():
|
||||
print `template.getHits()` + " hit: " + template.getName()
|
||||
|
||||
print
|
||||
print "Benchmark. Executing 1000..."
|
||||
gc.disable()
|
||||
total = 0
|
||||
maxValue = 0
|
||||
maxPos = 0
|
||||
minValue = 99999999
|
||||
minPos = 0
|
||||
for i in range(1000):
|
||||
start = time.time()
|
||||
ret = self.__filter.findFailure(line)
|
||||
end = time.time()
|
||||
diff = (end - start) * 1000
|
||||
total = total + diff
|
||||
minValue = min(minValue, diff)
|
||||
if minValue == diff:
|
||||
minPos = i
|
||||
maxValue = max(maxValue, diff)
|
||||
if maxValue == diff:
|
||||
maxPos = i
|
||||
gc.enable()
|
||||
print "Performance"
|
||||
print "Avg: " + `total / 1000` + " ms"
|
||||
print "Max: " + `maxValue` + " ms (Run " + `maxPos` + ")"
|
||||
print "Min: " + `minValue` + " ms (Run " + `minPos` + ")"
|
||||
|
||||
print "Success, the total number of match is " + str(total)
|
||||
print
|
||||
print "However, look at the above section 'Running tests' which could contain important"
|
||||
print "information."
|
||||
return True
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
regex = Fail2banRegex()
|
||||
fail2banRegex = Fail2banRegex()
|
||||
# Reads the command line options.
|
||||
try:
|
||||
cmdOpts = 'hV'
|
||||
cmdLongOpts = ['help', 'version']
|
||||
optList, args = getopt.getopt(sys.argv[1:], cmdOpts, cmdLongOpts)
|
||||
except getopt.GetoptError:
|
||||
regex.dispUsage()
|
||||
fail2banRegex.dispUsage()
|
||||
sys.exit(-1)
|
||||
# Process command line
|
||||
regex.getCmdLineOptions(optList)
|
||||
fail2banRegex.getCmdLineOptions(optList)
|
||||
# We need exactly 3 parameters
|
||||
if len(sys.argv) <> 3:
|
||||
regex.dispUsage()
|
||||
if not len(sys.argv) == 3:
|
||||
fail2banRegex.dispUsage()
|
||||
sys.exit(-1)
|
||||
else:
|
||||
ret = regex.testRegex(sys.argv[1], sys.argv[2])
|
||||
if ret:
|
||||
if fail2banRegex.readRegex(sys.argv[2]) == False:
|
||||
sys.exit(-1)
|
||||
|
||||
print
|
||||
print "Running tests"
|
||||
print "============="
|
||||
print
|
||||
|
||||
if fail2banRegex.logIsFile(sys.argv[1]):
|
||||
hdlr = open(sys.argv[1])
|
||||
for line in hdlr:
|
||||
fail2banRegex.testRegex(line)
|
||||
else:
|
||||
fail2banRegex.testRegex(sys.argv[1])
|
||||
|
||||
if fail2banRegex.printStats():
|
||||
sys.exit(0)
|
||||
else:
|
||||
sys.exit(-1)
|
||||
|
|
|
@ -1,12 +1,11 @@
|
|||
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.36.
|
||||
.TH FAIL2BAN-CLIENT "1" "January 2007" "fail2ban-client v0.7.6" "User Commands"
|
||||
.TH FAIL2BAN-CLIENT "1" "January 2007" "fail2ban-client v0.7.6-SVN" "User Commands"
|
||||
.SH NAME
|
||||
fail2ban-client \- configure and control the server
|
||||
.SH SYNOPSIS
|
||||
.B fail2ban-client
|
||||
[\fIOPTIONS\fR]... \fI<COMMAND>\fR
|
||||
.SH DESCRIPTION
|
||||
Fail2Ban v0.7.6 reads log file that contains password failure report
|
||||
[?1034hUsage: ../fail2ban\-client [OPTIONS]... <COMMAND>
|
||||
.PP
|
||||
Fail2Ban v0.7.6\-SVN reads log file that contains password failure report
|
||||
and bans the corresponding IP addresses using firewall rules.
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
|
|
|
@ -1,16 +1,36 @@
|
|||
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.36.
|
||||
.TH FAIL2BAN-REGEX "1" "January 2007" "fail2ban-regex v0.7.6" "User Commands"
|
||||
.TH FAIL2BAN-REGEX "1" "January 2007" "fail2ban-regex v0.7.6-SVN" "User Commands"
|
||||
.SH NAME
|
||||
fail2ban-regex \- test Fail2ban "failregex" option
|
||||
.SH SYNOPSIS
|
||||
.B fail2ban-regex
|
||||
\fI<logline> <failregex>\fR
|
||||
[\fIOPTIONS\fR] \fI<LOG> <REGEX>\fR
|
||||
.SH DESCRIPTION
|
||||
Fail2Ban v0.7.6 reads log file that contains password failure report
|
||||
Fail2Ban v0.7.6\-SVN reads log file that contains password failure report
|
||||
and bans the corresponding IP addresses using firewall rules.
|
||||
.PP
|
||||
This tools can test and benchmark your regular expressions for the "failregex"
|
||||
option.
|
||||
This tools can test regular expressions for "fail2ban".
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
\fB\-h\fR, \fB\-\-help\fR
|
||||
display this help message
|
||||
.TP
|
||||
\fB\-V\fR, \fB\-\-version\fR
|
||||
print the version
|
||||
.SH LOG
|
||||
.TP
|
||||
\fBstring\fR
|
||||
a string representing a log line
|
||||
.TP
|
||||
\fBfilename\fR
|
||||
path to a log file (/var/log/auth.log)
|
||||
.SH REGEX
|
||||
.TP
|
||||
\fBstring\fR
|
||||
a string representing a 'failregex'
|
||||
.TP
|
||||
\fBfilename\fR
|
||||
path to a filter file (filter.d/sshd.conf)
|
||||
.SH AUTHOR
|
||||
Written by Cyril Jaquier <lostcontrol@users.sourceforge.net>.
|
||||
Many contributions by Yaroslav O. Halchenko <debian@onerussian.com>.
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.36.
|
||||
.TH FAIL2BAN-SERVER "1" "January 2007" "fail2ban-server v0.7.6" "User Commands"
|
||||
.TH FAIL2BAN-SERVER "1" "January 2007" "fail2ban-server v0.7.6-SVN" "User Commands"
|
||||
.SH NAME
|
||||
fail2ban-server \- start the server
|
||||
.SH SYNOPSIS
|
||||
.B fail2ban-server
|
||||
[\fIOPTIONS\fR]
|
||||
.SH DESCRIPTION
|
||||
Fail2Ban v0.7.6 reads log file that contains password failure report
|
||||
Fail2Ban v0.7.6\-SVN reads log file that contains password failure report
|
||||
and bans the corresponding IP addresses using firewall rules.
|
||||
.PP
|
||||
Only use this command for debugging purpose. Start the server with
|
||||
|
|
|
@ -40,4 +40,30 @@ echo "[done]"
|
|||
echo -n "Generating fail2ban-regex "
|
||||
help2man --section=1 --no-info --include=fail2ban-regex.h2m --output fail2ban-regex.1 ../fail2ban-regex
|
||||
echo "[done]"
|
||||
|
||||
echo -n "Patching fail2ban-regex "
|
||||
# Changes the title.
|
||||
sed -i -e 's/.SS "Log:"/.SH LOG/' fail2ban-regex.1
|
||||
sed -i -e 's/.SS "Regex:"/.SH REGEX/' fail2ban-regex.1
|
||||
# Sets bold font for commands.
|
||||
IFS="
|
||||
"
|
||||
NEXT=0
|
||||
FOUND=0
|
||||
LINES=$( cat fail2ban-regex.1 )
|
||||
echo -n "" > fail2ban-regex.1
|
||||
for LINE in $LINES; do
|
||||
if [ "$LINE" = ".SH LOG" ]; then
|
||||
FOUND=1
|
||||
fi
|
||||
if [ $NEXT -eq 1 ] && [ $FOUND -eq 1 ]; then
|
||||
echo "\fB$LINE\fR" >> fail2ban-regex.1
|
||||
else
|
||||
echo "$LINE" >> fail2ban-regex.1
|
||||
fi
|
||||
if [ "$LINE" = ".TP" ]; then
|
||||
NEXT=1
|
||||
else
|
||||
NEXT=0
|
||||
fi
|
||||
done
|
||||
echo "[done]"
|
||||
|
|
Loading…
Reference in New Issue