Merge pull request #401 from bes-internal/ignorecommand

ENH: New ignorecommand with path to external command for dynamic ignoreip list
pull/522/head
Daniel Black 2013-12-24 23:43:41 -08:00
commit dfb6c45297
12 changed files with 73 additions and 3 deletions

View File

@ -54,7 +54,9 @@ class FilterReader(ConfigReader):
def getOptions(self, pOpts): def getOptions(self, pOpts):
opts = [["string", "ignoreregex", ""], opts = [["string", "ignoreregex", ""],
["string", "failregex", ""]] ["string", "failregex", ""],
["string", "ignorecommand", ""]
]
self.__opts = ConfigReader.getOptions(self, "Definition", opts, pOpts) self.__opts = ConfigReader.getOptions(self, "Definition", opts, pOpts)
def convert(self): def convert(self):

View File

@ -80,6 +80,7 @@ class JailReader(ConfigReader):
["string", "usedns", "warn"], ["string", "usedns", "warn"],
["string", "failregex", None], ["string", "failregex", None],
["string", "ignoreregex", None], ["string", "ignoreregex", None],
["string", "ignorecommand", None],
["string", "ignoreip", None], ["string", "ignoreip", None],
["string", "filter", ""], ["string", "filter", ""],
["string", "action", ""]] ["string", "action", ""]]
@ -164,6 +165,8 @@ class JailReader(ConfigReader):
stream.append(["set", self.__name, "usedns", self.__opts[opt]]) stream.append(["set", self.__name, "usedns", self.__opts[opt]])
elif opt == "failregex": elif opt == "failregex":
stream.append(["set", self.__name, "addfailregex", self.__opts[opt]]) stream.append(["set", self.__name, "addfailregex", self.__opts[opt]])
elif opt == "ignorecommand":
stream.append(["set", self.__name, "ignorecommand", self.__opts[opt]])
elif opt == "ignoreregex": elif opt == "ignoreregex":
for regex in self.__opts[opt].split('\n'): for regex in self.__opts[opt].split('\n'):
# Do not send a command if the rule is empty. # Do not send a command if the rule is empty.

View File

@ -57,6 +57,7 @@ protocol = [
["set <JAIL> dellogpath <FILE>", "removes <FILE> from the monitoring list of <JAIL>"], ["set <JAIL> dellogpath <FILE>", "removes <FILE> from the monitoring list of <JAIL>"],
["set <JAIL> addfailregex <REGEX>", "adds the regular expression <REGEX> which must match failures 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> delfailregex <INDEX>", "removes the regular expression at <INDEX> for failregex"],
["set <JAIL> ignorecommand <VALUE>", "sets ignorecommand of <JAIL>"],
["set <JAIL> addignoreregex <REGEX>", "adds the regular expression <REGEX> which should match pattern to exclude for <JAIL>"], ["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> 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> findtime <TIME>", "sets the number of seconds <TIME> for which the filter will look back for <JAIL>"],
@ -77,6 +78,7 @@ protocol = [
['', "JAIL INFORMATION", ""], ['', "JAIL INFORMATION", ""],
["get <JAIL> logpath", "gets the list of the monitored files for <JAIL>"], ["get <JAIL> logpath", "gets the list of the monitored files for <JAIL>"],
["get <JAIL> ignoreip", "gets the list of ignored IP addresses for <JAIL>"], ["get <JAIL> ignoreip", "gets the list of ignored IP addresses for <JAIL>"],
["get <JAIL> ignorecommand", "gets ignorecommand of <JAIL>"],
["get <JAIL> failregex", "gets the list of regular expressions which matches the failures 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> 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> findtime", "gets the time for which the filter will look back for failures for <JAIL>"],

View File

@ -31,6 +31,11 @@
# defined using space separator. # defined using space separator.
ignoreip = 127.0.0.1/8 ignoreip = 127.0.0.1/8
# External command that will take an tagged arguments to ignore, e.g. <ip>,
# and return true if the IP is to be ignored. False otherwise.
#
# ignorecommand = /path/to/command <ip>
# "bantime" is the number of seconds that a host is banned. # "bantime" is the number of seconds that a host is banned.
bantime = 600 bantime = 600

View File

@ -128,6 +128,9 @@ for <JAIL>
removes the regular expression at removes the regular expression at
<INDEX> for failregex <INDEX> for failregex
.TP .TP
\fBset <JAIL> ignorecommand <VALUE>\fR
sets ignorecommand of <JAIL>
.TP
\fBset <JAIL> addignoreregex <REGEX>\fR \fBset <JAIL> addignoreregex <REGEX>\fR
adds the regular expression adds the regular expression
<REGEX> which should match pattern <REGEX> which should match pattern
@ -206,6 +209,9 @@ files for <JAIL>
gets the list of ignored IP gets the list of ignored IP
addresses for <JAIL> addresses for <JAIL>
.TP .TP
\fBget <JAIL> ignorecommand\fR
gets ignorecommand of <JAIL>
.TP
\fBget <JAIL> failregex\fR \fBget <JAIL> failregex\fR
gets the list of regular gets the list of regular
expressions which matches the expressions which matches the

View File

@ -70,6 +70,11 @@ The following options are applicable to all jails. Their meaning is described in
\fBaction\fR \fBaction\fR
.TP .TP
\fBignoreip\fR \fBignoreip\fR
A space separated list of IPs not to ban.
.TP
\fBignorecommand\fR
A command that is executed to determine if the current ban's actionban is to be executed. This command will return true if the current ban should be ignored. A false return value will result in the ban's actionban executed.
Like ACTION FILES, tags like <ip> are can be included in the ignore command value and will be substitued before execution. Currently only <ip> is supported however more will be added later.
.TP .TP
\fBbantime\fR \fBbantime\fR
.TP .TP

View File

@ -30,8 +30,9 @@ from jailthread import JailThread
from datedetector import DateDetector from datedetector import DateDetector
from mytime import MyTime from mytime import MyTime
from failregex import FailRegex, Regex, RegexException from failregex import FailRegex, Regex, RegexException
from action import Action
import logging, re, os, fcntl, time import logging, re, os, fcntl, time, shlex, subprocess
# Gets the instance of the logger. # Gets the instance of the logger.
logSys = logging.getLogger("fail2ban.filter") logSys = logging.getLogger("fail2ban.filter")
@ -67,6 +68,8 @@ class Filter(JailThread):
self.__findTime = 6000 self.__findTime = 6000
## The ignore IP list. ## The ignore IP list.
self.__ignoreIpList = [] self.__ignoreIpList = []
## External command
self.__ignoreCommand = False
self.dateDetector = DateDetector() self.dateDetector = DateDetector()
self.dateDetector.addDefaultTemplate() self.dateDetector.addDefaultTemplate()
@ -212,6 +215,20 @@ class Filter(JailThread):
def run(self): # pragma: no cover def run(self): # pragma: no cover
raise Exception("run() is abstract") raise Exception("run() is abstract")
##
# Set external command, for ignoredips
#
def setIgnoreCommand(self, command):
self.__ignoreCommand = command
##
# Get external command, for ignoredips
#
def getIgnoreCommand(self):
return self.__ignoreCommand
## ##
# Ban an IP - http://blogs.buanzo.com.ar/2009/04/fail2ban-patch-ban-ip-address-manually.html # Ban an IP - http://blogs.buanzo.com.ar/2009/04/fail2ban-patch-ban-ip-address-manually.html
# Arturo 'Buanzo' Busleiman <buanzo@buanzo.com.ar> # Arturo 'Buanzo' Busleiman <buanzo@buanzo.com.ar>
@ -284,6 +301,12 @@ class Filter(JailThread):
continue continue
if a == b: if a == b:
return True return True
if self.__ignoreCommand:
command = Action.replaceTag(self.__ignoreCommand, { 'ip': ip } )
logSys.debug('ignore command: ' + command)
return Action.executeCmd(command)
return False return False

View File

@ -184,6 +184,12 @@ class Server:
def getFindTime(self, name): def getFindTime(self, name):
return self.__jails.getFilter(name).getFindTime() return self.__jails.getFilter(name).getFindTime()
def setIgnoreCommand(self, name, value):
self.__jails.getFilter(name).setIgnoreCommand(value)
def getIgnoreCommand(self, name):
return self.__jails.getFilter(name).getIgnoreCommand()
def addFailRegex(self, name, value): def addFailRegex(self, name, value):
self.__jails.getFilter(name).addFailRegex(value) self.__jails.getFilter(name).addFailRegex(value)

View File

@ -142,6 +142,10 @@ class Transmitter:
value = command[2] value = command[2]
self.__server.delLogPath(name, value) self.__server.delLogPath(name, value)
return self.__server.getLogPath(name) return self.__server.getLogPath(name)
elif command[1] == "ignorecommand":
value = command[2]
self.__server.setIgnoreCommand(name, value)
return self.__server.getIgnoreCommand(name)
elif command[1] == "addfailregex": elif command[1] == "addfailregex":
value = command[2] value = command[2]
self.__server.addFailRegex(name, value) self.__server.addFailRegex(name, value)
@ -239,6 +243,8 @@ class Transmitter:
return self.__server.getLogPath(name) return self.__server.getLogPath(name)
elif command[1] == "ignoreip": elif command[1] == "ignoreip":
return self.__server.getIgnoreIP(name) return self.__server.getIgnoreIP(name)
elif command[1] == "ignorecommand":
return self.__server.getIgnoreCommand(name)
elif command[1] == "failregex": elif command[1] == "failregex":
return self.__server.getFailRegex(name) return self.__server.getFailRegex(name)
elif command[1] == "ignoreregex": elif command[1] == "ignoreregex":

View File

@ -0,0 +1,5 @@
#!/usr/bin/python
import sys
if sys.argv[1] == "10.0.0.1":
exit(0)
exit(1)

View File

@ -171,7 +171,6 @@ class IgnoreIP(LogCaptureTestCase):
ipList = "127.0.0.1", "192.168.0.1", "255.255.255.255", "99.99.99.99" ipList = "127.0.0.1", "192.168.0.1", "255.255.255.255", "99.99.99.99"
for ip in ipList: for ip in ipList:
self.filter.addIgnoreIP(ip) self.filter.addIgnoreIP(ip)
self.assertTrue(self.filter.inIgnoreIPList(ip)) self.assertTrue(self.filter.inIgnoreIPList(ip))
def testIgnoreIPNOK(self): def testIgnoreIPNOK(self):
@ -201,6 +200,11 @@ class IgnoreIP(LogCaptureTestCase):
self.assertFalse(self._is_logged('Ignore 192.168.1.32')) self.assertFalse(self._is_logged('Ignore 192.168.1.32'))
self.assertTrue(self._is_logged('Requested to manually ban an ignored IP 192.168.1.32. User knows best. Proceeding to ban it.')) self.assertTrue(self._is_logged('Requested to manually ban an ignored IP 192.168.1.32. User knows best. Proceeding to ban it.'))
def testIgnoreCommand(self):
self.filter.setIgnoreCommand("testcases/files/ignorecommand.py <ip>")
self.assertTrue(self.filter.inIgnoreIPList("10.0.0.1"))
self.assertFalse(self.filter.inIgnoreIPList("10.0.0.0"))
class IgnoreIPDNS(IgnoreIP): class IgnoreIPDNS(IgnoreIP):

View File

@ -337,6 +337,9 @@ class Transmitter(TransmitterBase):
self.transm.proceed(["set", self.jailName, "delignoreip", value]), self.transm.proceed(["set", self.jailName, "delignoreip", value]),
(0, [value])) (0, [value]))
def testJailIgnoreCommand(self):
self.setGetTest("ignorecommand", "bin ", jail=self.jailName)
def testJailRegex(self): def testJailRegex(self):
self.jailAddDelRegexTest("failregex", self.jailAddDelRegexTest("failregex",
[ [