mirror of https://github.com/fail2ban/fail2ban
Merge pull request #401 from bes-internal/ignorecommand
ENH: New ignorecommand with path to external command for dynamic ignoreip listpull/522/head
commit
dfb6c45297
|
@ -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):
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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>"],
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
||||||
|
|
|
@ -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":
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
#!/usr/bin/python
|
||||||
|
import sys
|
||||||
|
if sys.argv[1] == "10.0.0.1":
|
||||||
|
exit(0)
|
||||||
|
exit(1)
|
|
@ -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):
|
||||||
|
|
||||||
|
|
|
@ -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",
|
||||||
[
|
[
|
||||||
|
|
Loading…
Reference in New Issue