mirror of https://github.com/fail2ban/fail2ban
- Added support for several "failregex" and "ignoreregex". This should simplify the configuration files.
- Configuration files are backward-compatible but need to be updated in order to take advantage of this feature. git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/trunk@503 a942ae1a-1317-0410-a47c-b1dcaea8d6050.x
parent
34a48157dc
commit
0f31cc0feb
|
@ -15,7 +15,8 @@ ver. 0.7.6 (200?/??/??) - ???
|
|||
- Fixed removal of host in hosts.deny. Thanks to René Berber
|
||||
- Added new date format (2006-12-21 06:43:20) and Exim4
|
||||
filter. Thanks to mEDI
|
||||
- Improved regular expression checking a bit
|
||||
- Several "failregex" and "ignoreregex" are now accepted.
|
||||
Creation of rules should be easier now.
|
||||
|
||||
ver. 0.7.5 (2006/12/07) - beta
|
||||
----------
|
||||
|
|
2
MANIFEST
2
MANIFEST
|
@ -39,6 +39,8 @@ server/dateepoch.py
|
|||
server/banmanager.py
|
||||
server/datetemplate.py
|
||||
server/mytime.py
|
||||
server/regex.py
|
||||
server/failregex.py
|
||||
testcases/banmanagertestcase.py
|
||||
testcases/failmanagertestcase.py
|
||||
testcases/clientreadertestcase.py
|
||||
|
|
|
@ -109,7 +109,18 @@ class Beautifier:
|
|||
msg = "These IP addresses/networks are ignored:\n"
|
||||
for ip in response[:-1]:
|
||||
msg = msg + "|- " + ip + "\n"
|
||||
msg = msg + "`- " + response[len(response)-1]
|
||||
msg = msg + "`- " + response[len(response)-1]
|
||||
elif inC[2] in ("failregex", "addfailregex", "delfailregex",
|
||||
"ignoreregex", "addignoreregex", "delignoreregex"):
|
||||
if len(response) == 0:
|
||||
msg = "No regular expression is defined"
|
||||
else:
|
||||
msg = "The following regular expression are defined:\n"
|
||||
c = 0
|
||||
for ip in response[:-1]:
|
||||
msg = msg + "|- [" + str(c) + "]: " + ip + "\n"
|
||||
c += 1
|
||||
msg = msg + "`- [" + str(c) + "]: " + response[len(response)-1]
|
||||
except Exception:
|
||||
logSys.warn("Beautifier error. Please report the error")
|
||||
logSys.error("Beautify " + `response` + " with " + `self.__inputCmd` +
|
||||
|
|
|
@ -67,8 +67,10 @@ class FilterReader(ConfigReader):
|
|||
elif opt == "timepattern":
|
||||
stream.append(["set", self.__name, "timepattern", self.__opts[opt]])
|
||||
elif opt == "failregex":
|
||||
stream.append(["set", self.__name, "failregex", self.__opts[opt]])
|
||||
for regex in self.__opts[opt].split('\n'):
|
||||
stream.append(["set", self.__name, "addfailregex", regex])
|
||||
elif opt == "ignoreregex":
|
||||
stream.append(["set", self.__name, "ignoreregex", self.__opts[opt]])
|
||||
for regex in self.__opts[opt].split('\n'):
|
||||
stream.append(["set", self.__name, "addignoreregex", regex])
|
||||
return stream
|
||||
|
|
@ -54,8 +54,10 @@ protocol = [
|
|||
["set <JAIL> dellogpath <FILE>", "removes <FILE> to the monitoring list of <JAIL>"],
|
||||
["set <JAIL> timeregex <REGEX>", "sets the regular expression <REGEX> to match the date format for <JAIL>. This will disable the autodetection feature."],
|
||||
["set <JAIL> timepattern <PATTERN>", "sets the pattern <PATTERN> to match the date format for <JAIL>. This will disable the autodetection feature."],
|
||||
["set <JAIL> failregex <REGEX>", "sets the regular expression <REGEX> which must match failures for <JAIL>"],
|
||||
["set <JAIL> ignoreregex <REGEX>", "sets the regular expression <REGEX> which should match pattern to exclude for <JAIL>"],
|
||||
["set <JAIL> addfailregex <REGEX>", "adds the regular expression <REGEX> which must match failures for <JAIL>"],
|
||||
["set <JAIL> delfailregex <INDEX>", "removes the regular expression at <INDEX> for failregex"],
|
||||
["set <JAIL> addignoreregex <REGEX>", "adds the regular expression <REGEX> which should match pattern to exclude for <JAIL>"],
|
||||
["set <JAIL> delignoreregex <INDEX>", "removes the regular expression at <INDEX> for ignoreregex"],
|
||||
["set <JAIL> findtime <TIME>", "sets the number of seconds <TIME> for which the filter will look back for <JAIL>"],
|
||||
["set <JAIL> bantime <TIME>", "sets the number of seconds <TIME> a host will be banned for <JAIL>"],
|
||||
["set <JAIL> maxretry <RETRY>", "sets the number of failures <RETRY> before banning the host for <JAIL>"],
|
||||
|
@ -73,8 +75,8 @@ protocol = [
|
|||
["get <JAIL> ignoreip", "gets the list of ignored IP addresses for <JAIL>"],
|
||||
["get <JAIL> timeregex", "gets the regular expression used for the time detection for <JAIL>"],
|
||||
["get <JAIL> timepattern", "gets the pattern used for the time detection for <JAIL>"],
|
||||
["get <JAIL> failregex", "gets the regular expression which matches the failures for <JAIL>"],
|
||||
["get <JAIL> ignoreregex", "gets the regular expression which matches patterns to ignore for <JAIL>"],
|
||||
["get <JAIL> failregex", "gets the list of regular expressions which matches the failures for <JAIL>"],
|
||||
["get <JAIL> ignoreregex", "gets the list of regular expressions which matches patterns to ignore for <JAIL>"],
|
||||
["get <JAIL> findtime", "gets the time for which the filter will look back for failures for <JAIL>"],
|
||||
["get <JAIL> bantime", "gets the time a host is banned for <JAIL>"],
|
||||
["get <JAIL> maxretry", "gets the number of failures allowed for <JAIL>"],
|
||||
|
|
|
@ -33,6 +33,7 @@ sys.path.insert(1, "/usr/lib/fail2ban")
|
|||
|
||||
from common.version import version
|
||||
from server.filter import Filter
|
||||
from server.regex import RegexException
|
||||
|
||||
# Gets the instance of the logger.
|
||||
logSys = logging.getLogger("fail2ban.regex")
|
||||
|
@ -83,17 +84,17 @@ class Fail2banRegex:
|
|||
self.dispVersion()
|
||||
sys.exit(0)
|
||||
|
||||
def setRegex(self, value):
|
||||
print
|
||||
self.__filter.setFailRegex(value)
|
||||
|
||||
def testRegex(self, line):
|
||||
def testRegex(self, line, regex):
|
||||
print
|
||||
try:
|
||||
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
|
||||
|
@ -156,8 +157,7 @@ if __name__ == "__main__":
|
|||
regex.dispUsage()
|
||||
sys.exit(-1)
|
||||
else:
|
||||
regex.setRegex(sys.argv[2])
|
||||
ret = regex.testRegex(sys.argv[1])
|
||||
ret = regex.testRegex(sys.argv[1], sys.argv[2])
|
||||
if ret:
|
||||
sys.exit(0)
|
||||
else:
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.36.
|
||||
.TH FAIL2BAN-CLIENT "1" "December 2006" "fail2ban-client v0.7.4-SVN" "User Commands"
|
||||
.TH FAIL2BAN-CLIENT "1" "December 2006" "fail2ban-client v0.7.5-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.4\-SVN reads log file that contains password failure report
|
||||
Fail2Ban v0.7.5\-SVN reads log file that contains password failure report
|
||||
and bans the corresponding IP addresses using firewall rules.
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
|
@ -37,6 +37,8 @@ display this help message
|
|||
\fB\-V\fR, \fB\-\-version\fR
|
||||
print the version
|
||||
.SH COMMAND
|
||||
.IP
|
||||
Basic
|
||||
.TP
|
||||
\fBstart\fR
|
||||
starts the server and the jails
|
||||
|
@ -54,6 +56,8 @@ server
|
|||
.TP
|
||||
\fBping\fR
|
||||
tests if the server is alive
|
||||
.IP
|
||||
Logging
|
||||
.TP
|
||||
\fBset loglevel <LEVEL>\fR
|
||||
sets logging level to <LEVEL>. 0
|
||||
|
@ -69,10 +73,24 @@ file
|
|||
.TP
|
||||
\fBget logtarget\fR
|
||||
gets logging target
|
||||
.IP
|
||||
Jail control
|
||||
.TP
|
||||
\fBadd <JAIL> <BACKEND>\fR
|
||||
creates <JAIL> using <BACKEND>
|
||||
.TP
|
||||
\fBstart <JAIL>\fR
|
||||
starts the jail <JAIL>
|
||||
.TP
|
||||
\fBstop <JAIL>\fR
|
||||
stops the jail <JAIL>. The jail is
|
||||
removed
|
||||
.TP
|
||||
\fBstatus <JAIL>\fR
|
||||
gets the current status of <JAIL>
|
||||
.IP
|
||||
Jail configuration
|
||||
.TP
|
||||
\fBset <JAIL> idle on|off\fR
|
||||
sets the idle state of <JAIL>
|
||||
.TP
|
||||
|
@ -104,16 +122,24 @@ match the date format for <JAIL>.
|
|||
This will disable the
|
||||
autodetection feature.
|
||||
.TP
|
||||
\fBset <JAIL> failregex <REGEX>\fR
|
||||
sets the regular expression
|
||||
\fBset <JAIL> addfailregex <REGEX>\fR
|
||||
adds the regular expression
|
||||
<REGEX> which must match failures
|
||||
for <JAIL>
|
||||
.TP
|
||||
\fBset <JAIL> ignoreregex <REGEX>\fR
|
||||
sets the regular expression
|
||||
\fBset <JAIL> delfailregex <INDEX>\fR
|
||||
removes the regular expression at
|
||||
<INDEX> for failregex
|
||||
.TP
|
||||
\fBset <JAIL> addignoreregex <REGEX>\fR
|
||||
adds the regular expression
|
||||
<REGEX> which should match pattern
|
||||
to exclude for <JAIL>
|
||||
.TP
|
||||
\fBset <JAIL> delignoreregex <INDEX>\fR
|
||||
removes the regular expression at
|
||||
<INDEX> for ignoreregex
|
||||
.TP
|
||||
\fBset <JAIL> findtime <TIME>\fR
|
||||
sets the number of seconds <TIME>
|
||||
for which the filter will look
|
||||
|
@ -163,6 +189,8 @@ action <ACT> for <JAIL>
|
|||
\fBset <JAIL> actionunban <ACT> <CMD>\fR
|
||||
sets the unban command <CMD> of
|
||||
the action <ACT> for <JAIL>
|
||||
.IP
|
||||
Jail information
|
||||
.TP
|
||||
\fBget <JAIL> logpath\fR
|
||||
gets the list of the monitored
|
||||
|
@ -181,13 +209,14 @@ gets the pattern used for the time
|
|||
detection for <JAIL>
|
||||
.TP
|
||||
\fBget <JAIL> failregex\fR
|
||||
gets the regular expression which
|
||||
matches the failures for <JAIL>
|
||||
gets the list of regular
|
||||
expressions which matches the
|
||||
failures for <JAIL>
|
||||
.TP
|
||||
\fBget <JAIL> ignoreregex\fR
|
||||
gets the regular expression which
|
||||
matches patterns to ignore for
|
||||
<JAIL>
|
||||
gets the list of regular
|
||||
expressions which matches patterns
|
||||
to ignore for <JAIL>
|
||||
.TP
|
||||
\fBget <JAIL> findtime\fR
|
||||
gets the time for which the filter
|
||||
|
@ -225,16 +254,6 @@ action <ACT> for <JAIL>
|
|||
\fBget <JAIL> actionunban <ACT>\fR
|
||||
gets the unban command for the
|
||||
action <ACT> for <JAIL>
|
||||
.TP
|
||||
\fBstart <JAIL>\fR
|
||||
starts the jail <JAIL>
|
||||
.TP
|
||||
\fBstop <JAIL>\fR
|
||||
stops the jail <JAIL>. The jail is
|
||||
removed
|
||||
.TP
|
||||
\fBstatus <JAIL>\fR
|
||||
gets the current status of <JAIL>
|
||||
.SH FILES
|
||||
\fI/etc/fail2ban/*\fR
|
||||
.SH AUTHOR
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.36.
|
||||
.TH FAIL2BAN-REGEX "1" "December 2006" "fail2ban-regex v0.7.4-SVN" "User Commands"
|
||||
.TH FAIL2BAN-REGEX "1" "December 2006" "fail2ban-regex v0.7.5-SVN" "User Commands"
|
||||
.SH NAME
|
||||
fail2ban-regex \- test Fail2ban "failregex" option
|
||||
.SH SYNOPSIS
|
||||
.B fail2ban-regex
|
||||
\fI<logline> <failregex>\fR
|
||||
.SH DESCRIPTION
|
||||
Fail2Ban v0.7.4\-SVN reads log file that contains password failure report
|
||||
Fail2Ban v0.7.5\-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"
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.36.
|
||||
.TH FAIL2BAN-SERVER "1" "December 2006" "fail2ban-server v0.7.4-SVN" "User Commands"
|
||||
.TH FAIL2BAN-SERVER "1" "December 2006" "fail2ban-server v0.7.5-SVN" "User Commands"
|
||||
.SH NAME
|
||||
fail2ban-server \- start the server
|
||||
.SH SYNOPSIS
|
||||
.B fail2ban-server
|
||||
[\fIOPTIONS\fR]
|
||||
.SH DESCRIPTION
|
||||
Fail2Ban v0.7.4\-SVN reads log file that contains password failure report
|
||||
Fail2Ban v0.7.5\-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
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
# This file is part of Fail2Ban.
|
||||
#
|
||||
# Fail2Ban is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Fail2Ban is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Fail2Ban; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
# Author: Cyril Jaquier
|
||||
#
|
||||
# $Revision$
|
||||
|
||||
__author__ = "Cyril Jaquier"
|
||||
__version__ = "$Revision$"
|
||||
__date__ = "$Date$"
|
||||
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
||||
__license__ = "GPL"
|
||||
|
||||
from regex import Regex, RegexException
|
||||
|
||||
##
|
||||
# Regular expression class.
|
||||
#
|
||||
# This class represents a regular expression with its compiled version.
|
||||
|
||||
class FailRegex(Regex):
|
||||
|
||||
##
|
||||
# Constructor.
|
||||
#
|
||||
# Creates a new object. This method can throw RegexException in order to
|
||||
# avoid construction of invalid object.
|
||||
# @param value the regular expression
|
||||
|
||||
def __init__(self, value):
|
||||
# Replace "<HOST>" with default regular expression for host.
|
||||
regex = value.replace("<HOST>", "(?:::f{4,6}:)?(?P<host>\S+)")
|
||||
# Initializes the parent.
|
||||
Regex.__init__(self, regex)
|
||||
# Check for group "host"
|
||||
if "host" not in self._regexObj.groupindex:
|
||||
raise RegexException("No 'host' group in '%s'" % self._regex)
|
||||
|
||||
##
|
||||
# Returns the matched host.
|
||||
#
|
||||
# This corresponds to the pattern matched by the named group "host".
|
||||
# @return the matched host
|
||||
|
||||
def getHost(self):
|
||||
host = self._matchCache.group("host")
|
||||
if host == None:
|
||||
raise RegexException("Unexpected error. Please check your regex")
|
||||
return host
|
129
server/filter.py
129
server/filter.py
|
@ -29,8 +29,10 @@ from failticket import FailTicket
|
|||
from jailthread import JailThread
|
||||
from datedetector import DateDetector
|
||||
from mytime import MyTime
|
||||
from regex import Regex, RegexException
|
||||
from failregex import FailRegex
|
||||
|
||||
import logging, re, sre_constants
|
||||
import logging, re
|
||||
|
||||
# Gets the instance of the logger.
|
||||
logSys = logging.getLogger("fail2ban.filter")
|
||||
|
@ -61,12 +63,10 @@ class Filter(JailThread):
|
|||
self.__crtFilename = None
|
||||
## The log file path.
|
||||
self.__logPath = []
|
||||
## The regular expression matching the failure.
|
||||
self.__failRegex = ''
|
||||
self.__failRegexObj = None
|
||||
## The regular expression with expression to ignore.
|
||||
self.__ignoreRegex = ''
|
||||
self.__ignoreRegexObj = None
|
||||
## The regular expression list matching the failures.
|
||||
self.__failRegex = list()
|
||||
## The regular expression list with expressions to ignore.
|
||||
self.__ignoreRegex = list()
|
||||
## The amount of time to look back.
|
||||
self.__findTime = 6000
|
||||
## The ignore IP list.
|
||||
|
@ -158,26 +158,26 @@ class Filter(JailThread):
|
|||
return self.dateDetector.getDefaultPattern()
|
||||
|
||||
##
|
||||
# Set the regular expression which matches the failure.
|
||||
# Add a regular expression which matches the failure.
|
||||
#
|
||||
# The regular expression can also match any other pattern than failures
|
||||
# and thus can be used for many purporse.
|
||||
# @param value the regular expression
|
||||
|
||||
def setFailRegex(self, value):
|
||||
def addFailRegex(self, value):
|
||||
try:
|
||||
if value.lstrip() == '':
|
||||
self.__failRegex = value
|
||||
self.__failRegexObj = None
|
||||
else:
|
||||
# Replace "<HOST>" with default regular expression for host.
|
||||
regex = value.replace("<HOST>", "(?:::f{4,6}:)?(?P<host>\S+)")
|
||||
self.__failRegex = regex
|
||||
self.__failRegexObj = re.compile(regex)
|
||||
logSys.info("Set failregex = %s" % self.__failRegex)
|
||||
except sre_constants.error:
|
||||
logSys.error("Unable to compile regular expression " +
|
||||
self.__failRegex)
|
||||
regex = FailRegex(value)
|
||||
self.__failRegex.append(regex)
|
||||
except RegexException, e:
|
||||
logSys.error(e)
|
||||
|
||||
|
||||
def delFailRegex(self, index):
|
||||
try:
|
||||
del self.__failRegex[index]
|
||||
except IndexError:
|
||||
logSys.error("Cannot remove regular expression. Index %d is not "
|
||||
"valid" % index)
|
||||
|
||||
##
|
||||
# Get the regular expression which matches the failure.
|
||||
|
@ -185,25 +185,31 @@ class Filter(JailThread):
|
|||
# @return the regular expression
|
||||
|
||||
def getFailRegex(self):
|
||||
return self.__failRegex
|
||||
failRegex = list()
|
||||
for regex in self.__failRegex:
|
||||
failRegex.append(regex.getRegex())
|
||||
return failRegex
|
||||
|
||||
##
|
||||
# Set the regular expression which matches the failure.
|
||||
# Add the regular expression which matches the failure.
|
||||
#
|
||||
# The regular expression can also match any other pattern than failures
|
||||
# and thus can be used for many purporse.
|
||||
# @param value the regular expression
|
||||
|
||||
def setIgnoreRegex(self, value):
|
||||
def addIgnoreRegex(self, value):
|
||||
try:
|
||||
if value.lstrip() == '':
|
||||
self.__ignoreRegexObj = None
|
||||
else:
|
||||
self.__ignoreRegexObj = re.compile(value)
|
||||
self.__ignoreRegex = value
|
||||
logSys.info("Set ignoreregex = %s" % value)
|
||||
except sre_constants.error:
|
||||
logSys.error("Unable to compile regular expression " + value)
|
||||
regex = Regex(value)
|
||||
self.__ignoreRegex.append(regex)
|
||||
except RegexException, e:
|
||||
logSys.error(e)
|
||||
|
||||
def delIgnoreRegex(self, index):
|
||||
try:
|
||||
del self.__ignoreRegex[index]
|
||||
except IndexError:
|
||||
logSys.error("Cannot remove regular expression. Index %d is not "
|
||||
"valid" % index)
|
||||
|
||||
##
|
||||
# Get the regular expression which matches the failure.
|
||||
|
@ -211,7 +217,10 @@ class Filter(JailThread):
|
|||
# @return the regular expression
|
||||
|
||||
def getIgnoreRegex(self):
|
||||
return self.__ignoreRegex
|
||||
ignoreRegex = list()
|
||||
for regex in self.__ignoreRegex:
|
||||
ignoreRegex.append(regex.getRegex())
|
||||
return ignoreRegex
|
||||
|
||||
##
|
||||
# Set the time needed to find a failure.
|
||||
|
@ -413,43 +422,35 @@ class Filter(JailThread):
|
|||
|
||||
def findFailure(self, line):
|
||||
failList = list()
|
||||
# Checks if failregex is defined.
|
||||
if self.__failRegexObj == None:
|
||||
logSys.error("No failregex is set")
|
||||
return failList
|
||||
# Checks if ignoreregex is defined.
|
||||
if not self.__ignoreRegexObj == None:
|
||||
match = self.__ignoreRegexObj.search(line)
|
||||
if match:
|
||||
# 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
|
||||
match = self.__failRegexObj.search(line)
|
||||
if match:
|
||||
# The failregex matched.
|
||||
date = self.dateDetector.getUnixTime(match.string)
|
||||
if date == None:
|
||||
logSys.debug("Found a match but no valid date/time found "
|
||||
+ "for " + match.string + ". Please contact "
|
||||
+ "the author in order to get support for "
|
||||
+ "this format")
|
||||
else:
|
||||
try:
|
||||
matchGroup = match.group("host")
|
||||
# For strange reasons, match.group can return None with some
|
||||
# regular expressions. However, these expressions can be
|
||||
# compiled successfully.
|
||||
if matchGroup == None:
|
||||
logSys.error("Unexpected error. Please correct your "
|
||||
+ "configuration.")
|
||||
else:
|
||||
ipMatch = DNSUtils.textToIp(match.group("host"))
|
||||
# Iterates over all the regular expressions.
|
||||
for failRegex in self.__failRegex:
|
||||
failRegex.search(line)
|
||||
if failRegex.hasMatched():
|
||||
# The failregex matched.
|
||||
date = self.dateDetector.getUnixTime(line)
|
||||
if date == None:
|
||||
logSys.debug("Found a match but no valid date/time found "
|
||||
+ "for " + line + ". Please contact the "
|
||||
+ "author in order to get support for this "
|
||||
+ "format")
|
||||
else:
|
||||
try:
|
||||
host = failRegex.getHost()
|
||||
ipMatch = DNSUtils.textToIp(host)
|
||||
if ipMatch:
|
||||
for ip in ipMatch:
|
||||
failList.append([ip, date])
|
||||
except IndexError:
|
||||
logSys.error("There is no 'host' group in the rule. " +
|
||||
"Please correct your configuration.")
|
||||
# We matched a regex, it is enough to stop.
|
||||
break
|
||||
except RegexException, e:
|
||||
logSys.error(e)
|
||||
return failList
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,88 @@
|
|||
# This file is part of Fail2Ban.
|
||||
#
|
||||
# Fail2Ban is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Fail2Ban is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Fail2Ban; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
# Author: Cyril Jaquier
|
||||
#
|
||||
# $Revision$
|
||||
|
||||
__author__ = "Cyril Jaquier"
|
||||
__version__ = "$Revision$"
|
||||
__date__ = "$Date$"
|
||||
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
||||
__license__ = "GPL"
|
||||
|
||||
import re, sre_constants
|
||||
|
||||
##
|
||||
# Regular expression class.
|
||||
#
|
||||
# This class represents a regular expression with its compiled version.
|
||||
|
||||
class Regex:
|
||||
|
||||
##
|
||||
# Constructor.
|
||||
#
|
||||
# Creates a new object. This method can throw RegexException in order to
|
||||
# avoid construction of invalid object.
|
||||
# @param value the regular expression
|
||||
|
||||
def __init__(self, regex):
|
||||
self._matchCache = None
|
||||
try:
|
||||
self._regexObj = re.compile(regex)
|
||||
self._regex = regex
|
||||
except sre_constants.error:
|
||||
raise RegexException("Unable to compile regular expression '%s'" %
|
||||
regex)
|
||||
|
||||
##
|
||||
# Gets the regular expression.
|
||||
#
|
||||
# The effective regular expression used is returned.
|
||||
# @return the regular expression
|
||||
|
||||
def getRegex(self):
|
||||
return self._regex
|
||||
|
||||
##
|
||||
# Searches the regular expression.
|
||||
#
|
||||
# Sets an internal cache (match object) in order to avoid searching for
|
||||
# the pattern again. This method must be called before calling any other
|
||||
# method of this object.
|
||||
# @param value the line
|
||||
|
||||
def search(self, value):
|
||||
self._matchCache = self._regexObj.search(value)
|
||||
|
||||
##
|
||||
# Checks if the previous call to search() matched.
|
||||
#
|
||||
# @return True if a match was found, False otherwise
|
||||
|
||||
def hasMatched(self):
|
||||
if self._matchCache:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
##
|
||||
# Exception dedicated to the class Regex.
|
||||
|
||||
class RegexException(Exception):
|
||||
pass
|
|
@ -165,14 +165,20 @@ class Server:
|
|||
def getFindTime(self, name):
|
||||
return self.__jails.getFilter(name).getFindTime()
|
||||
|
||||
def setFailRegex(self, name, value):
|
||||
self.__jails.getFilter(name).setFailRegex(value)
|
||||
def addFailRegex(self, name, value):
|
||||
self.__jails.getFilter(name).addFailRegex(value)
|
||||
|
||||
def delFailRegex(self, name, index):
|
||||
self.__jails.getFilter(name).delFailRegex(index)
|
||||
|
||||
def getFailRegex(self, name):
|
||||
return self.__jails.getFilter(name).getFailRegex()
|
||||
|
||||
def setIgnoreRegex(self, name, value):
|
||||
self.__jails.getFilter(name).setIgnoreRegex(value)
|
||||
def addIgnoreRegex(self, name, value):
|
||||
self.__jails.getFilter(name).addIgnoreRegex(value)
|
||||
|
||||
def delIgnoreRegex(self, name, index):
|
||||
self.__jails.getFilter(name).delIgnoreRegex(index)
|
||||
|
||||
def getIgnoreRegex(self, name):
|
||||
return self.__jails.getFilter(name).getIgnoreRegex()
|
||||
|
|
|
@ -143,13 +143,21 @@ class Transmitter:
|
|||
value = command[2]
|
||||
self.__server.setTimePattern(name, value)
|
||||
return self.__server.getTimePattern(name)
|
||||
elif command[1] == "failregex":
|
||||
elif command[1] == "addfailregex":
|
||||
value = command[2]
|
||||
self.__server.setFailRegex(name, value)
|
||||
self.__server.addFailRegex(name, value)
|
||||
return self.__server.getFailRegex(name)
|
||||
elif command[1] == "ignoreregex":
|
||||
elif command[1] == "delfailregex":
|
||||
value = int(command[2])
|
||||
self.__server.delFailRegex(name, value)
|
||||
return self.__server.getFailRegex(name)
|
||||
elif command[1] == "addignoreregex":
|
||||
value = command[2]
|
||||
self.__server.setIgnoreRegex(name, value)
|
||||
self.__server.addIgnoreRegex(name, value)
|
||||
return self.__server.getIgnoreRegex(name)
|
||||
elif command[1] == "delignoreregex":
|
||||
value = int(command[2])
|
||||
self.__server.delIgnoreRegex(name, value)
|
||||
return self.__server.getIgnoreRegex(name)
|
||||
elif command[1] == "findtime":
|
||||
value = command[2]
|
||||
|
|
|
@ -99,7 +99,7 @@ class GetFailures(unittest.TestCase):
|
|||
output = ('193.168.0.128', 3, 1124013599.0)
|
||||
|
||||
self.__filter.addLogPath(GetFailures.FILENAME_01)
|
||||
self.__filter.setFailRegex("(?:(?:Authentication failure|Failed [-/\w+]+) for(?: [iI](?:llegal|nvalid) user)?|[Ii](?:llegal|nvalid) user|ROOT LOGIN REFUSED) .*(?: from|FROM) (?:::f{4,6}:)?(?P<host>\S*)")
|
||||
self.__filter.addFailRegex("(?:(?:Authentication failure|Failed [-/\w+]+) for(?: [iI](?:llegal|nvalid) user)?|[Ii](?:llegal|nvalid) user|ROOT LOGIN REFUSED) .*(?: from|FROM) (?:::f{4,6}:)?(?P<host>\S*)")
|
||||
|
||||
self.__filter.getFailures(GetFailures.FILENAME_01)
|
||||
|
||||
|
@ -116,7 +116,7 @@ class GetFailures(unittest.TestCase):
|
|||
output = ('141.3.81.106', 4, 1124013539.0)
|
||||
|
||||
self.__filter.addLogPath(GetFailures.FILENAME_02)
|
||||
self.__filter.setFailRegex("Failed .* (?:::f{4,6}:)(?P<host>\S*)")
|
||||
self.__filter.addFailRegex("Failed .* (?:::f{4,6}:)(?P<host>\S*)")
|
||||
|
||||
self.__filter.getFailures(GetFailures.FILENAME_02)
|
||||
|
||||
|
@ -127,13 +127,13 @@ class GetFailures(unittest.TestCase):
|
|||
ip = ticket.getIP()
|
||||
found = (ip, attempts, date)
|
||||
|
||||
self.assertEqual(found, output)
|
||||
self.assertEqual(found, output)
|
||||
|
||||
def testGetFailures03(self):
|
||||
output = ('203.162.223.135', 6, 1124013544.0)
|
||||
|
||||
self.__filter.addLogPath(GetFailures.FILENAME_03)
|
||||
self.__filter.setFailRegex("error,relay=(?:::f{4,6}:)?(?P<host>\S*),.*550 User unknown")
|
||||
self.__filter.addFailRegex("error,relay=(?:::f{4,6}:)?(?P<host>\S*),.*550 User unknown")
|
||||
|
||||
self.__filter.getFailures(GetFailures.FILENAME_03)
|
||||
|
||||
|
@ -151,7 +151,7 @@ class GetFailures(unittest.TestCase):
|
|||
('212.41.96.185', 4, 1124013598.0)]
|
||||
|
||||
self.__filter.addLogPath(GetFailures.FILENAME_04)
|
||||
self.__filter.setFailRegex("Invalid user .* (?P<host>\S*)")
|
||||
self.__filter.addFailRegex("Invalid user .* (?P<host>\S*)")
|
||||
|
||||
self.__filter.getFailures(GetFailures.FILENAME_04)
|
||||
|
||||
|
@ -165,4 +165,33 @@ class GetFailures(unittest.TestCase):
|
|||
self.assertEqual(found, output[i])
|
||||
except FailManagerEmpty:
|
||||
pass
|
||||
|
||||
|
||||
def testGetFailuresMultiRegex(self):
|
||||
output = ('141.3.81.106', 8, 1124013541.0)
|
||||
|
||||
self.__filter.addLogPath(GetFailures.FILENAME_02)
|
||||
self.__filter.addFailRegex("Failed .* from <HOST>")
|
||||
self.__filter.addFailRegex("Accepted .* from <HOST>")
|
||||
|
||||
self.__filter.getFailures(GetFailures.FILENAME_02)
|
||||
|
||||
ticket = self.__filter.failManager.toBan()
|
||||
|
||||
attempts = ticket.getAttempt()
|
||||
date = ticket.getTime()
|
||||
ip = ticket.getIP()
|
||||
found = (ip, attempts, date)
|
||||
|
||||
self.assertEqual(found, output)
|
||||
|
||||
def testGetFailuresIgnoreRegex(self):
|
||||
output = ('141.3.81.106', 8, 1124013541.0)
|
||||
|
||||
self.__filter.addLogPath(GetFailures.FILENAME_02)
|
||||
self.__filter.addFailRegex("Failed .* from <HOST>")
|
||||
self.__filter.addFailRegex("Accepted .* from <HOST>")
|
||||
self.__filter.addIgnoreRegex("for roehl")
|
||||
|
||||
self.__filter.getFailures(GetFailures.FILENAME_02)
|
||||
|
||||
self.assertRaises(FailManagerEmpty, self.__filter.failManager.toBan)
|
||||
|
|
Loading…
Reference in New Issue