mirror of https://github.com/fail2ban/fail2ban
introduced new option `ignorecache` to improve performance of ignore failure check (using caching of `ignoreip`, `ignoreself` and `ignorecommand`)
parent
9b6d17d07e
commit
f8f01d5ab7
|
@ -50,6 +50,8 @@ ver. 0.10.4-dev-1 (20??/??/??) - development edition
|
||||||
* systemd: fixed type error on option `journalflags`: an integer is required (gh-2125);
|
* systemd: fixed type error on option `journalflags`: an integer is required (gh-2125);
|
||||||
|
|
||||||
### New Features
|
### New Features
|
||||||
|
* new option `ignorecache` to improve performance of ignore failure check (using caching of `ignoreip`,
|
||||||
|
`ignoreself` and `ignorecommand`), see `man jail.conf` for syntax-example;
|
||||||
* `ignorecommand` extended to use actions-similar replacement (capable to interpolate
|
* `ignorecommand` extended to use actions-similar replacement (capable to interpolate
|
||||||
all possible tags like `<ip-host>`, `<family>`, `<fid>`, `F-USER` etc.)
|
all possible tags like `<ip-host>`, `<family>`, `<fid>`, `F-USER` etc.)
|
||||||
|
|
||||||
|
|
|
@ -100,6 +100,7 @@ class JailReader(ConfigReader):
|
||||||
["string", "ignorecommand", None],
|
["string", "ignorecommand", None],
|
||||||
["bool", "ignoreself", None],
|
["bool", "ignoreself", None],
|
||||||
["string", "ignoreip", None],
|
["string", "ignoreip", None],
|
||||||
|
["string", "ignorecache", None],
|
||||||
["string", "filter", ""],
|
["string", "filter", ""],
|
||||||
["string", "datepattern", None],
|
["string", "datepattern", None],
|
||||||
["string", "logtimezone", None],
|
["string", "logtimezone", None],
|
||||||
|
|
|
@ -84,6 +84,8 @@ protocol = [
|
||||||
["set <JAIL> ignoreself true|false", "allows the ignoring of own IP addresses"],
|
["set <JAIL> ignoreself true|false", "allows the ignoring of own IP addresses"],
|
||||||
["set <JAIL> addignoreip <IP>", "adds <IP> to the ignore list of <JAIL>"],
|
["set <JAIL> addignoreip <IP>", "adds <IP> to the ignore list of <JAIL>"],
|
||||||
["set <JAIL> delignoreip <IP>", "removes <IP> from the ignore list of <JAIL>"],
|
["set <JAIL> delignoreip <IP>", "removes <IP> from the ignore list of <JAIL>"],
|
||||||
|
["set <JAIL> ignorecommand <VALUE>", "sets ignorecommand of <JAIL>"],
|
||||||
|
["set <JAIL> ignorecache <VALUE>", "sets ignorecache of <JAIL>"],
|
||||||
["set <JAIL> addlogpath <FILE> ['tail']", "adds <FILE> to the monitoring list of <JAIL>, optionally starting at the 'tail' of the file (default 'head')."],
|
["set <JAIL> addlogpath <FILE> ['tail']", "adds <FILE> to the monitoring list of <JAIL>, optionally starting at the 'tail' of the file (default 'head')."],
|
||||||
["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> logencoding <ENCODING>", "sets the <ENCODING> of the log files for <JAIL>"],
|
["set <JAIL> logencoding <ENCODING>", "sets the <ENCODING> of the log files for <JAIL>"],
|
||||||
|
@ -91,7 +93,6 @@ protocol = [
|
||||||
["set <JAIL> deljournalmatch <MATCH>", "removes <MATCH> from the journal filter of <JAIL>"],
|
["set <JAIL> deljournalmatch <MATCH>", "removes <MATCH> from the journal filter 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>"],
|
||||||
|
|
|
@ -81,6 +81,10 @@ class Filter(JailThread):
|
||||||
self.__ignoreSelf = True
|
self.__ignoreSelf = True
|
||||||
## The ignore IP list.
|
## The ignore IP list.
|
||||||
self.__ignoreIpList = []
|
self.__ignoreIpList = []
|
||||||
|
## External command
|
||||||
|
self.__ignoreCommand = False
|
||||||
|
## Cache for ignoreip:
|
||||||
|
self.__ignoreCache = None
|
||||||
## Size of line buffer
|
## Size of line buffer
|
||||||
self.__lineBufferSize = 1
|
self.__lineBufferSize = 1
|
||||||
## Line buffer
|
## Line buffer
|
||||||
|
@ -90,8 +94,6 @@ class Filter(JailThread):
|
||||||
self.__lastDate = None
|
self.__lastDate = None
|
||||||
## if set, treat log lines without explicit time zone to be in this time zone
|
## if set, treat log lines without explicit time zone to be in this time zone
|
||||||
self.__logtimezone = None
|
self.__logtimezone = None
|
||||||
## External command
|
|
||||||
self.__ignoreCommand = False
|
|
||||||
## Default or preferred encoding (to decode bytes from file or journal):
|
## Default or preferred encoding (to decode bytes from file or journal):
|
||||||
self.__encoding = PREFER_ENC
|
self.__encoding = PREFER_ENC
|
||||||
## Cache temporary holds failures info (used by multi-line for wrapping e. g. conn-id to host):
|
## Cache temporary holds failures info (used by multi-line for wrapping e. g. conn-id to host):
|
||||||
|
@ -397,19 +399,34 @@ class Filter(JailThread):
|
||||||
raise Exception("run() is abstract")
|
raise Exception("run() is abstract")
|
||||||
|
|
||||||
##
|
##
|
||||||
# Set external command, for ignoredips
|
# External command, for ignoredips
|
||||||
#
|
#
|
||||||
|
|
||||||
def setIgnoreCommand(self, command):
|
@property
|
||||||
|
def ignoreCommand(self):
|
||||||
|
return self.__ignoreCommand
|
||||||
|
|
||||||
|
@ignoreCommand.setter
|
||||||
|
def ignoreCommand(self, command):
|
||||||
self.__ignoreCommand = command
|
self.__ignoreCommand = command
|
||||||
|
|
||||||
##
|
##
|
||||||
# Get external command, for ignoredips
|
# Cache parameters for ignoredips
|
||||||
#
|
#
|
||||||
|
|
||||||
def getIgnoreCommand(self):
|
@property
|
||||||
return self.__ignoreCommand
|
def ignoreCache(self):
|
||||||
|
return [self.__ignoreCache[0], self.__ignoreCache[1].maxCount, self.__ignoreCache[1].maxTime] \
|
||||||
|
if self.__ignoreCache else None
|
||||||
|
|
||||||
|
@ignoreCache.setter
|
||||||
|
def ignoreCache(self, command):
|
||||||
|
if command:
|
||||||
|
self.__ignoreCache = command['key'], Utils.Cache(
|
||||||
|
maxCount=int(command.get('max-count', 100)), maxTime=MyTime.str2seconds(command.get('max-time', 5*60))
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
self.__ignoreCache = None
|
||||||
##
|
##
|
||||||
# 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>
|
||||||
|
@ -502,29 +519,48 @@ class Filter(JailThread):
|
||||||
return self._inIgnoreIPList(ip, ticket, log_ignore)
|
return self._inIgnoreIPList(ip, ticket, log_ignore)
|
||||||
|
|
||||||
def _inIgnoreIPList(self, ip, ticket, log_ignore=True):
|
def _inIgnoreIPList(self, ip, ticket, log_ignore=True):
|
||||||
|
aInfo = None
|
||||||
|
# cached ?
|
||||||
|
if self.__ignoreCache:
|
||||||
|
key, c = self.__ignoreCache
|
||||||
|
if ticket:
|
||||||
|
aInfo = Actions.ActionInfo(ticket, self.jail)
|
||||||
|
key = CommandAction.replaceDynamicTags(key, aInfo)
|
||||||
|
else:
|
||||||
|
aInfo = { 'ip': ip }
|
||||||
|
key = CommandAction.replaceTag(key, aInfo)
|
||||||
|
v = c.get(key)
|
||||||
|
if v is not None:
|
||||||
|
return v
|
||||||
|
|
||||||
# check own IPs should be ignored and 'ip' is self IP:
|
# check own IPs should be ignored and 'ip' is self IP:
|
||||||
if self.__ignoreSelf and ip in DNSUtils.getSelfIPs():
|
if self.__ignoreSelf and ip in DNSUtils.getSelfIPs():
|
||||||
self.logIgnoreIp(ip, log_ignore, ignore_source="ignoreself rule")
|
self.logIgnoreIp(ip, log_ignore, ignore_source="ignoreself rule")
|
||||||
|
if self.__ignoreCache: c.set(key, True)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
for net in self.__ignoreIpList:
|
for net in self.__ignoreIpList:
|
||||||
# check if the IP is covered by ignore IP
|
# check if the IP is covered by ignore IP
|
||||||
if ip.isInNet(net):
|
if ip.isInNet(net):
|
||||||
self.logIgnoreIp(ip, log_ignore, ignore_source=("ip" if net.isValid else "dns"))
|
self.logIgnoreIp(ip, log_ignore, ignore_source=("ip" if net.isValid else "dns"))
|
||||||
|
if self.__ignoreCache: c.set(key, True)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
if self.__ignoreCommand:
|
if self.__ignoreCommand:
|
||||||
if ticket:
|
if ticket:
|
||||||
aInfo = Actions.ActionInfo(ticket, self.jail)
|
if not aInfo: aInfo = Actions.ActionInfo(ticket, self.jail)
|
||||||
command = CommandAction.replaceDynamicTags(self.__ignoreCommand, aInfo)
|
command = CommandAction.replaceDynamicTags(self.__ignoreCommand, aInfo)
|
||||||
else:
|
else:
|
||||||
command = CommandAction.replaceTag(self.__ignoreCommand, { 'ip': ip })
|
if not aInfo: aInfo = { 'ip': ip }
|
||||||
|
command = CommandAction.replaceTag(self.__ignoreCommand, aInfo)
|
||||||
logSys.debug('ignore command: %s', command)
|
logSys.debug('ignore command: %s', command)
|
||||||
ret, ret_ignore = CommandAction.executeCmd(command, success_codes=(0, 1))
|
ret, ret_ignore = CommandAction.executeCmd(command, success_codes=(0, 1))
|
||||||
ret_ignore = ret and ret_ignore == 0
|
ret_ignore = ret and ret_ignore == 0
|
||||||
self.logIgnoreIp(ip, log_ignore and ret_ignore, ignore_source="command")
|
self.logIgnoreIp(ip, log_ignore and ret_ignore, ignore_source="command")
|
||||||
|
if self.__ignoreCache: c.set(key, ret_ignore)
|
||||||
return ret_ignore
|
return ret_ignore
|
||||||
|
|
||||||
|
if self.__ignoreCache: c.set(key, False)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def processLine(self, line, date=None):
|
def processLine(self, line, date=None):
|
||||||
|
|
|
@ -391,10 +391,17 @@ class Server:
|
||||||
return self.__jails[name].filter.getLogTimeZone()
|
return self.__jails[name].filter.getLogTimeZone()
|
||||||
|
|
||||||
def setIgnoreCommand(self, name, value):
|
def setIgnoreCommand(self, name, value):
|
||||||
self.__jails[name].filter.setIgnoreCommand(value)
|
self.__jails[name].filter.ignoreCommand = value
|
||||||
|
|
||||||
def getIgnoreCommand(self, name):
|
def getIgnoreCommand(self, name):
|
||||||
return self.__jails[name].filter.getIgnoreCommand()
|
return self.__jails[name].filter.ignoreCommand
|
||||||
|
|
||||||
|
def setIgnoreCache(self, name, value):
|
||||||
|
value, options = extractOptions("cache["+value+"]")
|
||||||
|
self.__jails[name].filter.ignoreCache = options
|
||||||
|
|
||||||
|
def getIgnoreCache(self, name):
|
||||||
|
return self.__jails[name].filter.ignoreCache
|
||||||
|
|
||||||
def setPrefRegex(self, name, value):
|
def setPrefRegex(self, name, value):
|
||||||
flt = self.__jails[name].filter
|
flt = self.__jails[name].filter
|
||||||
|
|
|
@ -200,6 +200,10 @@ class Transmitter:
|
||||||
value = command[2]
|
value = command[2]
|
||||||
self.__server.setIgnoreCommand(name, value)
|
self.__server.setIgnoreCommand(name, value)
|
||||||
return self.__server.getIgnoreCommand(name)
|
return self.__server.getIgnoreCommand(name)
|
||||||
|
elif command[1] == "ignorecache":
|
||||||
|
value = command[2]
|
||||||
|
self.__server.setIgnoreCache(name, value)
|
||||||
|
return self.__server.getIgnoreCache(name)
|
||||||
elif command[1] == "addlogpath":
|
elif command[1] == "addlogpath":
|
||||||
value = command[2]
|
value = command[2]
|
||||||
tail = False
|
tail = False
|
||||||
|
@ -358,6 +362,8 @@ class Transmitter:
|
||||||
return self.__server.getIgnoreIP(name)
|
return self.__server.getIgnoreIP(name)
|
||||||
elif command[1] == "ignorecommand":
|
elif command[1] == "ignorecommand":
|
||||||
return self.__server.getIgnoreCommand(name)
|
return self.__server.getIgnoreCommand(name)
|
||||||
|
elif command[1] == "ignorecache":
|
||||||
|
return self.__server.getIgnoreCache(name)
|
||||||
elif command[1] == "prefregex":
|
elif command[1] == "prefregex":
|
||||||
return self.__server.getPrefRegex(name)
|
return self.__server.getPrefRegex(name)
|
||||||
elif command[1] == "failregex":
|
elif command[1] == "failregex":
|
||||||
|
|
|
@ -401,7 +401,7 @@ class IgnoreIP(LogCaptureTestCase):
|
||||||
self.assertLogged('Requested to manually ban an ignored IP 192.168.1.32. User knows best. Proceeding to ban it.')
|
self.assertLogged('Requested to manually ban an ignored IP 192.168.1.32. User knows best. Proceeding to ban it.')
|
||||||
|
|
||||||
def testIgnoreCommand(self):
|
def testIgnoreCommand(self):
|
||||||
self.filter.setIgnoreCommand(sys.executable + ' ' + os.path.join(TEST_FILES_DIR, "ignorecommand.py <ip>"))
|
self.filter.ignoreCommand = sys.executable + ' ' + os.path.join(TEST_FILES_DIR, "ignorecommand.py <ip>")
|
||||||
self.assertTrue(self.filter.inIgnoreIPList("10.0.0.1"))
|
self.assertTrue(self.filter.inIgnoreIPList("10.0.0.1"))
|
||||||
self.assertFalse(self.filter.inIgnoreIPList("10.0.0.0"))
|
self.assertFalse(self.filter.inIgnoreIPList("10.0.0.0"))
|
||||||
self.assertLogged("returned successfully 0", "returned successfully 1", all=True)
|
self.assertLogged("returned successfully 0", "returned successfully 1", all=True)
|
||||||
|
@ -411,7 +411,7 @@ class IgnoreIP(LogCaptureTestCase):
|
||||||
|
|
||||||
def testIgnoreCommandForTicket(self):
|
def testIgnoreCommandForTicket(self):
|
||||||
# by host of IP (2001:db8::1 and 2001:db8::ffff map to "test-host" and "test-other" in the test-suite):
|
# by host of IP (2001:db8::1 and 2001:db8::ffff map to "test-host" and "test-other" in the test-suite):
|
||||||
self.filter.setIgnoreCommand('if [ "<ip-host>" = "test-host" ]; then exit 0; fi; exit 1')
|
self.filter.ignoreCommand = 'if [ "<ip-host>" = "test-host" ]; then exit 0; fi; exit 1'
|
||||||
self.pruneLog()
|
self.pruneLog()
|
||||||
self.assertTrue(self.filter.inIgnoreIPList(FailTicket("2001:db8::1")))
|
self.assertTrue(self.filter.inIgnoreIPList(FailTicket("2001:db8::1")))
|
||||||
self.assertLogged("returned successfully 0")
|
self.assertLogged("returned successfully 0")
|
||||||
|
@ -419,7 +419,7 @@ class IgnoreIP(LogCaptureTestCase):
|
||||||
self.assertFalse(self.filter.inIgnoreIPList(FailTicket("2001:db8::ffff")))
|
self.assertFalse(self.filter.inIgnoreIPList(FailTicket("2001:db8::ffff")))
|
||||||
self.assertLogged("returned successfully 1")
|
self.assertLogged("returned successfully 1")
|
||||||
# by user-name (ignore tester):
|
# by user-name (ignore tester):
|
||||||
self.filter.setIgnoreCommand('if [ "<F-USER>" = "tester" ]; then exit 0; fi; exit 1')
|
self.filter.ignoreCommand = 'if [ "<F-USER>" = "tester" ]; then exit 0; fi; exit 1'
|
||||||
self.pruneLog()
|
self.pruneLog()
|
||||||
self.assertTrue(self.filter.inIgnoreIPList(FailTicket("tester", data={'user': 'tester'})))
|
self.assertTrue(self.filter.inIgnoreIPList(FailTicket("tester", data={'user': 'tester'})))
|
||||||
self.assertLogged("returned successfully 0")
|
self.assertLogged("returned successfully 0")
|
||||||
|
@ -427,6 +427,42 @@ class IgnoreIP(LogCaptureTestCase):
|
||||||
self.assertFalse(self.filter.inIgnoreIPList(FailTicket("root", data={'user': 'root'})))
|
self.assertFalse(self.filter.inIgnoreIPList(FailTicket("root", data={'user': 'root'})))
|
||||||
self.assertLogged("returned successfully 1", all=True)
|
self.assertLogged("returned successfully 1", all=True)
|
||||||
|
|
||||||
|
def testIgnoreCache(self):
|
||||||
|
# like both test-cases above, just cached (so once per key)...
|
||||||
|
self.filter.ignoreCache = {"key":"<ip>"}
|
||||||
|
self.filter.ignoreCommand = 'if [ "<ip>" = "10.0.0.1" ]; then exit 0; fi; exit 1'
|
||||||
|
for i in xrange(5):
|
||||||
|
self.pruneLog()
|
||||||
|
self.assertTrue(self.filter.inIgnoreIPList("10.0.0.1"))
|
||||||
|
self.assertFalse(self.filter.inIgnoreIPList("10.0.0.0"))
|
||||||
|
if not i:
|
||||||
|
self.assertLogged("returned successfully 0", "returned successfully 1", all=True)
|
||||||
|
else:
|
||||||
|
self.assertNotLogged("returned successfully 0", "returned successfully 1", all=True)
|
||||||
|
# by host of IP:
|
||||||
|
self.filter.ignoreCache = {"key":"<ip-host>"}
|
||||||
|
self.filter.ignoreCommand = 'if [ "<ip-host>" = "test-host" ]; then exit 0; fi; exit 1'
|
||||||
|
for i in xrange(5):
|
||||||
|
self.pruneLog()
|
||||||
|
self.assertTrue(self.filter.inIgnoreIPList(FailTicket("2001:db8::1")))
|
||||||
|
self.assertFalse(self.filter.inIgnoreIPList(FailTicket("2001:db8::ffff")))
|
||||||
|
if not i:
|
||||||
|
self.assertLogged("returned successfully")
|
||||||
|
else:
|
||||||
|
self.assertNotLogged("returned successfully")
|
||||||
|
# by user-name:
|
||||||
|
self.filter.ignoreCache = {"key":"<F-USER>", "max-count":"10", "max-time":"1h"}
|
||||||
|
self.assertEqual(self.filter.ignoreCache, ["<F-USER>", 10, 60*60])
|
||||||
|
self.filter.ignoreCommand = 'if [ "<F-USER>" = "tester" ]; then exit 0; fi; exit 1'
|
||||||
|
for i in xrange(5):
|
||||||
|
self.pruneLog()
|
||||||
|
self.assertTrue(self.filter.inIgnoreIPList(FailTicket("tester", data={'user': 'tester'})))
|
||||||
|
self.assertFalse(self.filter.inIgnoreIPList(FailTicket("root", data={'user': 'root'})))
|
||||||
|
if not i:
|
||||||
|
self.assertLogged("returned successfully")
|
||||||
|
else:
|
||||||
|
self.assertNotLogged("returned successfully")
|
||||||
|
|
||||||
def testIgnoreCauseOK(self):
|
def testIgnoreCauseOK(self):
|
||||||
ip = "93.184.216.34"
|
ip = "93.184.216.34"
|
||||||
for ignore_source in ["dns", "ip", "command"]:
|
for ignore_source in ["dns", "ip", "command"]:
|
||||||
|
@ -490,7 +526,7 @@ class IgnoreIPDNS(LogCaptureTestCase):
|
||||||
self.assertRaises(ValueError, lambda: mod.is_googlebot(mod.process_args([cmd])))
|
self.assertRaises(ValueError, lambda: mod.is_googlebot(mod.process_args([cmd])))
|
||||||
self.assertRaises(ValueError, lambda: mod.is_googlebot(mod.process_args([cmd, "192.0"])))
|
self.assertRaises(ValueError, lambda: mod.is_googlebot(mod.process_args([cmd, "192.0"])))
|
||||||
## via command:
|
## via command:
|
||||||
self.filter.setIgnoreCommand(cmd + " <ip>")
|
self.filter.ignoreCommand = cmd + " <ip>"
|
||||||
for ip in bot_ips:
|
for ip in bot_ips:
|
||||||
self.assertTrue(self.filter.inIgnoreIPList(str(ip)), "test of googlebot ip %s failed" % ip)
|
self.assertTrue(self.filter.inIgnoreIPList(str(ip)), "test of googlebot ip %s failed" % ip)
|
||||||
self.assertLogged('-- returned successfully')
|
self.assertLogged('-- returned successfully')
|
||||||
|
@ -498,7 +534,7 @@ class IgnoreIPDNS(LogCaptureTestCase):
|
||||||
self.assertFalse(self.filter.inIgnoreIPList("192.0"))
|
self.assertFalse(self.filter.inIgnoreIPList("192.0"))
|
||||||
self.assertLogged('Argument must be a single valid IP.')
|
self.assertLogged('Argument must be a single valid IP.')
|
||||||
self.pruneLog()
|
self.pruneLog()
|
||||||
self.filter.setIgnoreCommand(cmd + " bad arguments <ip>")
|
self.filter.ignoreCommand = cmd + " bad arguments <ip>"
|
||||||
self.assertFalse(self.filter.inIgnoreIPList("192.0"))
|
self.assertFalse(self.filter.inIgnoreIPList("192.0"))
|
||||||
self.assertLogged('Please provide a single IP as an argument.')
|
self.assertLogged('Please provide a single IP as an argument.')
|
||||||
|
|
||||||
|
|
|
@ -463,7 +463,14 @@ class Transmitter(TransmitterBase):
|
||||||
(0, False))
|
(0, False))
|
||||||
|
|
||||||
def testJailIgnoreCommand(self):
|
def testJailIgnoreCommand(self):
|
||||||
self.setGetTest("ignorecommand", "bin ", jail=self.jailName)
|
self.setGetTest("ignorecommand", "bin/ignore-command <ip>", jail=self.jailName)
|
||||||
|
|
||||||
|
def testJailIgnoreCache(self):
|
||||||
|
self.setGetTest("ignorecache",
|
||||||
|
'key="<ip>",max-time=1d,max-count=9999',
|
||||||
|
["<ip>", 9999, 24*60*60],
|
||||||
|
jail=self.jailName)
|
||||||
|
self.setGetTest("ignorecache", '', None, jail=self.jailName)
|
||||||
|
|
||||||
def testJailRegex(self):
|
def testJailRegex(self):
|
||||||
self.jailAddDelRegexTest("failregex",
|
self.jailAddDelRegexTest("failregex",
|
||||||
|
|
|
@ -233,7 +233,19 @@ list of IPs not to ban. They can include a DNS resp. CIDR mask too. The option a
|
||||||
command that is executed to determine if the current candidate IP for banning (or failure-ID for raw IDs) should not be banned. The option affects additionally to \fBignoreself\fR and \fBignoreip\fR and will be first executed if both don't hit.
|
command that is executed to determine if the current candidate IP for banning (or failure-ID for raw IDs) should not be banned. The option affects additionally to \fBignoreself\fR and \fBignoreip\fR and will be first executed if both don't hit.
|
||||||
.br
|
.br
|
||||||
IP will not be banned if command returns successfully (exit code 0).
|
IP will not be banned if command returns successfully (exit code 0).
|
||||||
Like ACTION FILES, tags like <ip> are can be included in the ignorecommand value and will be substituted before execution. Currently only <ip> is supported however more will be added later.
|
Like ACTION FILES, tags like <ip> are can be included in the ignorecommand value and will be substituted before execution.
|
||||||
|
.TP
|
||||||
|
.B ignorecache
|
||||||
|
provide cache parameters (default disabled) for ignore failure check (caching of the result from `ignoreip`, `ignoreself` and `ignorecommand`), syntax:
|
||||||
|
|
||||||
|
.RS
|
||||||
|
.nf
|
||||||
|
ignorecache = key="<F-USER>@<ip-host>", max-count=100, max-time=5m
|
||||||
|
ignorecommand = if [ "<F-USER>" = "technical" ] && [ "<ip-host>" = "my-host.example.com" ]; then exit 0; fi;
|
||||||
|
exit 1
|
||||||
|
.fi
|
||||||
|
This will cache the result of \fBignorecommand\fR (does not call it repeatedly) for 5 minutes (cache time) for maximal 100 entries (cache size), using values substituted like "user@host" as cache-keys. Set option \fBignorecache\fR to empty value disables the cache.
|
||||||
|
.RE
|
||||||
.TP
|
.TP
|
||||||
.B bantime
|
.B bantime
|
||||||
effective ban duration (in seconds or time abbreviation format).
|
effective ban duration (in seconds or time abbreviation format).
|
||||||
|
|
Loading…
Reference in New Issue