Initial changes and test for multi-line filtering

pull/108/head
Steven Hiscocks 2013-01-22 20:54:14 +00:00
parent 51a3be2d79
commit aec709f4c1
9 changed files with 83 additions and 2 deletions

View File

@ -63,6 +63,7 @@ class JailReader(ConfigReader):
["string", "logpath", "/var/log/messages"], ["string", "logpath", "/var/log/messages"],
["string", "backend", "auto"], ["string", "backend", "auto"],
["int", "maxretry", 3], ["int", "maxretry", 3],
["int", "maxlines", 1],
["int", "findtime", 600], ["int", "findtime", 600],
["int", "bantime", 600], ["int", "bantime", 600],
["string", "usedns", "warn"], ["string", "usedns", "warn"],
@ -114,6 +115,8 @@ class JailReader(ConfigReader):
backend = self.__opts[opt] backend = self.__opts[opt]
elif opt == "maxretry": elif opt == "maxretry":
stream.append(["set", self.__name, "maxretry", self.__opts[opt]]) stream.append(["set", self.__name, "maxretry", self.__opts[opt]])
elif opt == "maxlines":
stream.append(["set", self.__name, "maxlines", self.__opts[opt]])
elif opt == "ignoreip": elif opt == "ignoreip":
for ip in self.__opts[opt].split(): for ip in self.__opts[opt].split():
# Do not send a command if the rule is empty. # Do not send a command if the rule is empty.

View File

@ -66,6 +66,7 @@ protocol = [
["set <JAIL> banip <IP>", "manually Ban <IP> for <JAIL>"], ["set <JAIL> banip <IP>", "manually Ban <IP> for <JAIL>"],
["set <JAIL> unbanip <IP>", "manually Unban <IP> in <JAIL>"], ["set <JAIL> unbanip <IP>", "manually Unban <IP> in <JAIL>"],
["set <JAIL> maxretry <RETRY>", "sets the number of failures <RETRY> before banning the host for <JAIL>"], ["set <JAIL> maxretry <RETRY>", "sets the number of failures <RETRY> before banning the host for <JAIL>"],
["set <JAIL> maxlines <LINES>", "sets the number of <LINES> to buffer for regex search for <JAIL>"],
["set <JAIL> addaction <ACT>", "adds a new action named <NAME> for <JAIL>"], ["set <JAIL> addaction <ACT>", "adds a new action named <NAME> for <JAIL>"],
["set <JAIL> delaction <ACT>", "removes the action <NAME> from <JAIL>"], ["set <JAIL> delaction <ACT>", "removes the action <NAME> from <JAIL>"],
["set <JAIL> setcinfo <ACT> <KEY> <VALUE>", "sets <VALUE> for <KEY> of the action <NAME> for <JAIL>"], ["set <JAIL> setcinfo <ACT> <KEY> <VALUE>", "sets <VALUE> for <KEY> of the action <NAME> for <JAIL>"],
@ -84,6 +85,7 @@ protocol = [
["get <JAIL> bantime", "gets the time a host is banned for <JAIL>"], ["get <JAIL> bantime", "gets the time a host is banned for <JAIL>"],
["get <JAIL> usedns", "gets the usedns setting for <JAIL>"], ["get <JAIL> usedns", "gets the usedns setting for <JAIL>"],
["get <JAIL> maxretry", "gets the number of failures allowed for <JAIL>"], ["get <JAIL> maxretry", "gets the number of failures allowed for <JAIL>"],
["get <JAIL> maxlines", "gets the number of lines to buffer for <JAIL>"],
["get <JAIL> addaction", "gets the last action which has been added for <JAIL>"], ["get <JAIL> addaction", "gets the last action which has been added for <JAIL>"],
["get <JAIL> actionstart <ACT>", "gets the start command for the action <ACT> for <JAIL>"], ["get <JAIL> actionstart <ACT>", "gets the start command for the action <ACT> for <JAIL>"],
["get <JAIL> actionstop <ACT>", "gets the stop command for the action <ACT> for <JAIL>"], ["get <JAIL> actionstop <ACT>", "gets the stop command for the action <ACT> for <JAIL>"],

View File

@ -145,6 +145,11 @@ sets the number of failures
<RETRY> before banning the host <RETRY> before banning the host
for <JAIL> for <JAIL>
.TP .TP
\fBset <JAIL> maxlines <LINES>\fR
sets the number of <LINES> to
buffer for regex search for
<JAIL>
.TP
\fBset <JAIL> addaction <ACT>\fR \fBset <JAIL> addaction <ACT>\fR
adds a new action named <NAME> for adds a new action named <NAME> for
<JAIL> <JAIL>
@ -222,6 +227,10 @@ gets the time a host is banned for
gets the number of failures gets the number of failures
allowed for <JAIL> allowed for <JAIL>
.TP .TP
\fBget <JAIL> maxlines\fR
gets the number lines to
buffer for <JAIL>
.TP
\fBget <JAIL> addaction\fR \fBget <JAIL> addaction\fR
gets the last action which has gets the last action which has
been added for <JAIL> been added for <JAIL>

View File

@ -51,7 +51,7 @@ class Regex:
if regex.lstrip() == '': if regex.lstrip() == '':
raise RegexException("Cannot add empty regex") raise RegexException("Cannot add empty regex")
try: try:
self._regexObj = re.compile(regex) self._regexObj = re.compile(regex, re.MULTILINE)
self._regex = regex self._regex = regex
except sre_constants.error: except sre_constants.error:
raise RegexException("Unable to compile regular expression '%s'" % raise RegexException("Unable to compile regular expression '%s'" %

View File

@ -36,6 +36,7 @@ from mytime import MyTime
from failregex import FailRegex, Regex, RegexException from failregex import FailRegex, Regex, RegexException
import logging, re, os, fcntl, time import logging, re, os, fcntl, time
from collections import deque
# Gets the instance of the logger. # Gets the instance of the logger.
logSys = logging.getLogger("fail2ban.filter") logSys = logging.getLogger("fail2ban.filter")
@ -71,6 +72,10 @@ class Filter(JailThread):
self.__findTime = 6000 self.__findTime = 6000
## The ignore IP list. ## The ignore IP list.
self.__ignoreIpList = [] self.__ignoreIpList = []
## Size of line buffer
self.__line_buffer_size = 1
## Line buffer
self.__line_buffer = deque()
self.dateDetector = DateDetector() self.dateDetector = DateDetector()
self.dateDetector.addDefaultTemplate() self.dateDetector.addDefaultTemplate()
@ -204,6 +209,25 @@ class Filter(JailThread):
def getMaxRetry(self): def getMaxRetry(self):
return self.failManager.getMaxRetry() return self.failManager.getMaxRetry()
##
# Set the maximum line buffer size.
#
# @param value the line buffer size
def setMaxLines(self, value):
if value < 1:
value = 1
self.__line_buffer_size = value
logSys.info("Set maxLines = %s" % value)
##
# Get the maximum line buffer size.
#
# @return the line buffer size
def getMaxLines(self):
return self.__line_buffer_size
## ##
# Main loop. # Main loop.
# #
@ -305,7 +329,10 @@ class Filter(JailThread):
else: else:
timeLine = l timeLine = l
logLine = l logLine = l
return self.findFailure(timeLine, logLine) self.__line_buffer.append(logLine)
while len(self.__line_buffer) > self.__line_buffer_size:
self.__line_buffer.popleft()
return self.findFailure(timeLine, "".join(self.__line_buffer))
def processLineAndAdd(self, line): def processLineAndAdd(self, line):
"""Processes the line for failures and populates failManager """Processes the line for failures and populates failManager
@ -365,6 +392,7 @@ class Filter(JailThread):
"in order to get support for this format." "in order to get support for this format."
% (logLine, timeLine)) % (logLine, timeLine))
else: else:
self.__line_buffer.clear()
try: try:
host = failRegex.getHost() host = failRegex.getHost()
ipMatch = DNSUtils.textToIp(host, self.__useDns) ipMatch = DNSUtils.textToIp(host, self.__useDns)

View File

@ -216,6 +216,12 @@ class Server:
def getMaxRetry(self, name): def getMaxRetry(self, name):
return self.__jails.getFilter(name).getMaxRetry() return self.__jails.getFilter(name).getMaxRetry()
def setMaxLines(self, name, value):
self.__jails.getFilter(name).setMaxLines(value)
def getMaxLines(self, name):
return self.__jails.getFilter(name).getMaxLines()
# Action # Action
def addAction(self, name, value): def addAction(self, name, value):
self.__jails.getAction(name).addAction(value) self.__jails.getAction(name).addAction(value)

View File

@ -167,6 +167,10 @@ class Transmitter:
value = command[2] value = command[2]
self.__server.setMaxRetry(name, int(value)) self.__server.setMaxRetry(name, int(value))
return self.__server.getMaxRetry(name) return self.__server.getMaxRetry(name)
elif command[1] == "maxlines":
value = command[2]
self.__server.setMaxLines(name, int(value))
return self.__server.getMaxLines(name)
# command # command
elif command[1] == "bantime": elif command[1] == "bantime":
value = command[2] value = command[2]
@ -245,6 +249,8 @@ class Transmitter:
return self.__server.getFindTime(name) return self.__server.getFindTime(name)
elif command[1] == "maxretry": elif command[1] == "maxretry":
return self.__server.getMaxRetry(name) return self.__server.getMaxRetry(name)
elif command[1] == "maxlines":
return self.__server.getMaxLines(name)
# Action # Action
elif command[1] == "bantime": elif command[1] == "bantime":
return self.__server.getBanTime(name) return self.__server.getBanTime(name)

View File

@ -0,0 +1,12 @@
Aug 14 11:59:58 [sshd] Invalid user toto...
Aug 14 11:59:58 [sshd] from 212.41.96.185
Aug 14 11:59:58 [sshd] Invalid user toto...
Aug 14 11:59:58 [sshd] from 212.41.96.185
Aug 14 11:59:58 [sshd] Invalid user fuck...
Aug 14 11:59:58 [sshd] from 212.41.96.185
Aug 14 11:59:58 [sshd] Invalid user toto...
Aug 14 11:59:58 [sshd] from 212.41.96.185
Aug 14 11:59:58 [sshd] Invalid user fuck...
Aug 14 11:59:58 [sshd] from 212.41.96.185
Aug 14 11:59:58 [sshd] Invalid user fuck...
Aug 14 11:59:58 [sshd] from 212.41.96.185

View File

@ -499,6 +499,7 @@ class GetFailures(unittest.TestCase):
FILENAME_03 = "testcases/files/testcase03.log" FILENAME_03 = "testcases/files/testcase03.log"
FILENAME_04 = "testcases/files/testcase04.log" FILENAME_04 = "testcases/files/testcase04.log"
FILENAME_USEDNS = "testcases/files/testcase-usedns.log" FILENAME_USEDNS = "testcases/files/testcase-usedns.log"
FILENAME_MULTILINE = "testcases/files/testcase-multiline.log"
# so that they could be reused by other tests # so that they could be reused by other tests
FAILURES_01 = ('193.168.0.128', 3, 1124013599.0, FAILURES_01 = ('193.168.0.128', 3, 1124013599.0,
@ -604,6 +605,20 @@ class GetFailures(unittest.TestCase):
self.assertRaises(FailManagerEmpty, self.filter.failManager.toBan) self.assertRaises(FailManagerEmpty, self.filter.failManager.toBan)
def testGetFailuresMultiLine(self):
output = ("212.41.96.185", 3, 1124013598.0)
self.filter.addLogPath(GetFailures.FILENAME_MULTILINE)
self.filter.addFailRegex("Invalid user .+\n.+ from <HOST>$")
self.filter.addIgnoreRegex("user fuck")
self.filter.setMaxLines(2)
self.filter.getFailures(GetFailures.FILENAME_MULTILINE)
_assert_correct_last_attempt(self, self.filter, output)
self.assertRaises(FailManagerEmpty, self.filter.failManager.toBan)
class DNSUtilsTests(unittest.TestCase): class DNSUtilsTests(unittest.TestCase):
def testUseDns(self): def testUseDns(self):