introduced new options: `dbmaxmatches` (fail2ban.conf) and `maxmatches` (jail.conf);

setting `maxmatches` and `dbmaxmatches` to 0 saves memory usage and database size (closes gh-2118).
pull/2402/head
sebres 2019-04-18 20:31:39 +02:00
parent 1083788e70
commit 0386df0042
9 changed files with 57 additions and 9 deletions

View File

@ -68,6 +68,12 @@ dbfile = /var/lib/fail2ban/fail2ban.sqlite3
# Values: [ SECONDS ] Default: 86400 (24hours)
dbpurgeage = 1d
# Options: dbmaxmatches
# Notes.: Number of matches stored in database per ticket (resolvable via
# tags <ipmatches>/<ipjailmatches> in actions)
# Values: [ INT ] Default: 10
dbmaxmatches = 10
[Thread]
# Options: stacksize

View File

@ -69,6 +69,9 @@ findtime = 10m
# "maxretry" is the number of failures before a host get banned.
maxretry = 5
# "maxmatches" is the number of matches stored in ticket (resolvable via tag <matches> in actions).
maxmatches = %(maxretry)s
# "backend" specifies the backend used to get files modification.
# Available options are "pyinotify", "gamin", "polling", "systemd" and "auto".
# This option can be overridden in each jail as well.

View File

@ -54,6 +54,7 @@ class Fail2banReader(ConfigReader):
["string", "logtarget", "STDERR"],
["string", "syslogsocket", "auto"],
["string", "dbfile", "/var/lib/fail2ban/fail2ban.sqlite3"],
["int", "dbmaxmatches", None],
["string", "dbpurgeage", "1d"]]
self.__opts = ConfigReader.getOptions(self, "Definition", opts)
if updateMainOpt:
@ -73,7 +74,7 @@ class Fail2banReader(ConfigReader):
# Also dbfile should be set before all other database options.
# So adding order indices into items, to be stripped after sorting, upon return
order = {"thread":0, "syslogsocket":11, "loglevel":12, "logtarget":13,
"dbfile":50, "dbpurgeage":51}
"dbfile":50, "dbmaxmatches":51, "dbpurgeage":51}
stream = list()
for opt in self.__opts:
if opt in order:

View File

@ -93,6 +93,7 @@ class JailReader(ConfigReader):
opts = [["bool", "enabled", False],
["string", "backend", "auto"],
["int", "maxretry", None],
["int", "maxmatches", None],
["string", "findtime", None],
["string", "bantime", None],
["string", "usedns", None], # be sure usedns is before all regex(s) in stream

View File

@ -443,6 +443,12 @@ class Server:
def getUseDns(self, name):
return self.__jails[name].filter.getUseDns()
def setMaxMatches(self, name, value):
self.__jails[name].filter.failManager.maxMatches = value
def getMaxMatches(self, name):
return self.__jails[name].filter.failManager.maxMatches
def setMaxRetry(self, name, value):
self.__jails[name].filter.setMaxRetry(value)

View File

@ -183,6 +183,15 @@ class Transmitter:
else:
if self.__quiet: return
return db.filename
elif name == "dbmaxmatches":
db = self.__server.getDatabase()
if db is None:
logSys.msg("dbmaxmatches setting was not in effect since no db yet")
return None
else:
db.maxMatches = int(command[1])
if self.__quiet: return
return db.maxMatches
elif name == "dbpurgeage":
db = self.__server.getDatabase()
if db is None:
@ -310,6 +319,11 @@ class Transmitter:
self.__server.setLogTimeZone(name, value)
if self.__quiet: return
return self.__server.getLogTimeZone(name)
elif command[1] == "maxmatches":
value = command[2]
self.__server.setMaxMatches(name, int(value))
if self.__quiet: return
return self.__server.getMaxMatches(name)
elif command[1] == "maxretry":
value = command[2]
self.__server.setMaxRetry(name, int(value))
@ -398,6 +412,12 @@ class Transmitter:
return None
else:
return db.filename
elif name == "dbmaxmatches":
db = self.__server.getDatabase()
if db is None:
return None
else:
return db.maxMatches
elif name == "dbpurgeage":
db = self.__server.getDatabase()
if db is None:
@ -433,6 +453,8 @@ class Transmitter:
return self.__server.getDatePattern(name)
elif command[1] == "logtimezone":
return self.__server.getLogTimeZone(name)
elif command[1] == "maxmatches":
return self.__server.getMaxMatches(name)
elif command[1] == "maxretry":
return self.__server.getMaxRetry(name)
elif command[1] == "maxlines":

View File

@ -881,18 +881,20 @@ class JailsReaderTest(LogCaptureTestCase):
self.assertTrue(
find_set('syslogsocket') < find_set('loglevel') < find_set('logtarget')
)
# then dbfile should be before dbpurgeage
# then dbfile should be before dbmaxmatches and dbpurgeage
self.assertTrue(find_set('dbpurgeage') > find_set('dbfile'))
self.assertTrue(find_set('dbmaxmatches') > find_set('dbfile'))
# and there is logging information left to be passed into the
# server
self.assertSortedEqual(commands,
[['set', 'dbfile',
'/var/lib/fail2ban/fail2ban.sqlite3'],
['set', 'dbpurgeage', '1d'],
['set', 'loglevel', "INFO"],
['set', 'logtarget', '/var/log/fail2ban.log'],
['set', 'syslogsocket', 'auto']])
self.assertSortedEqual(commands,[
['set', 'syslogsocket', 'auto'],
['set', 'loglevel', "INFO"],
['set', 'logtarget', '/var/log/fail2ban.log'],
['set', 'dbfile', '/var/lib/fail2ban/fail2ban.sqlite3'],
['set', 'dbmaxmatches', 10],
['set', 'dbpurgeage', '1d'],
])
# and if we force change configurator's fail2ban's baseDir
# there should be an error message (test visually ;) --

View File

@ -179,6 +179,7 @@ def _start_params(tmp, use_stock=False, use_stock_cfg=None,
"pidfile = " + pjoin(tmp, "f2b.pid"),
"backend = polling",
"dbfile = " + db,
"dbmaxmatches = 100",
"dbpurgeage = 1d",
"",
)

View File

@ -374,6 +374,12 @@ class Transmitter(TransmitterBase):
self.assertLogged("Ban 192.0.2.2", wait=True)
self.assertNotLogged("Ban 192.0.2.1")
def testJailMaxMatches(self):
self.setGetTest("maxmatches", "5", 5, jail=self.jailName)
self.setGetTest("maxmatches", "2", 2, jail=self.jailName)
self.setGetTest("maxmatches", "-2", -2, jail=self.jailName)
self.setGetTestNOK("maxmatches", "Duck", jail=self.jailName)
def testJailMaxRetry(self):
self.setGetTest("maxretry", "5", 5, jail=self.jailName)
self.setGetTest("maxretry", "2", 2, jail=self.jailName)