mirror of https://github.com/fail2ban/fail2ban
amend to a54b401ee2
(0.11-fix-get-current-bans):
- differentiate between unknown ban-time after upgrade (-2) and persistent ban-time (-1); - better handling to correct current ban-time, uses `bantime.maxtime` (if increment allowed) or `bantime` of jail; - extended test-cases in order to cover the change of `bantime.maxtime`.pull/2030/merge
parent
9440956575
commit
7526f50706
|
@ -378,9 +378,9 @@ class Fail2BanDb(object):
|
||||||
"COMMIT;" % Fail2BanDb._CREATE_TABS['logs'])
|
"COMMIT;" % Fail2BanDb._CREATE_TABS['logs'])
|
||||||
|
|
||||||
if version < 3 and self._tableExists(cur, "bans"):
|
if version < 3 and self._tableExists(cur, "bans"):
|
||||||
# set ban-time to -1 (note it means rather unknown, as persistent, will be fixed by restore):
|
# set ban-time to -2 (note it means rather unknown, as persistent, will be fixed by restore):
|
||||||
cur.executescript("BEGIN TRANSACTION;"
|
cur.executescript("BEGIN TRANSACTION;"
|
||||||
"CREATE TEMPORARY TABLE bans_temp AS SELECT jail, ip, timeofban, -1 as bantime, 1 as bancount, data FROM bans;"
|
"CREATE TEMPORARY TABLE bans_temp AS SELECT jail, ip, timeofban, -2 as bantime, 1 as bancount, data FROM bans;"
|
||||||
"DROP TABLE bans;"
|
"DROP TABLE bans;"
|
||||||
"%s;\n"
|
"%s;\n"
|
||||||
"INSERT INTO bans SELECT * from bans_temp;"
|
"INSERT INTO bans SELECT * from bans_temp;"
|
||||||
|
@ -747,7 +747,7 @@ class Fail2BanDb(object):
|
||||||
if ip is not None:
|
if ip is not None:
|
||||||
query += " AND ip=?"
|
query += " AND ip=?"
|
||||||
queryArgs.append(ip)
|
queryArgs.append(ip)
|
||||||
query += " AND (timeofban + bantime > ? OR bantime = -1)"
|
query += " AND (timeofban + bantime > ? OR bantime <= -1)"
|
||||||
queryArgs.append(fromtime)
|
queryArgs.append(fromtime)
|
||||||
if forbantime not in (None, -1): # not specified or persistent (all)
|
if forbantime not in (None, -1): # not specified or persistent (all)
|
||||||
query += " AND timeofban > ?"
|
query += " AND timeofban > ?"
|
||||||
|
@ -773,7 +773,9 @@ class Fail2BanDb(object):
|
||||||
tickets = []
|
tickets = []
|
||||||
ticket = None
|
ticket = None
|
||||||
if correctBanTime is True:
|
if correctBanTime is True:
|
||||||
correctBanTime = jail.actions.getBanTime() if jail is not None else None
|
correctBanTime = jail.getMaxBanTime() if jail is not None else None
|
||||||
|
# don't change if persistent allowed:
|
||||||
|
if correctBanTime == -1: correctBanTime = None
|
||||||
|
|
||||||
for ticket in self._getCurrentBans(cur, jail=jail, ip=ip,
|
for ticket in self._getCurrentBans(cur, jail=jail, ip=ip,
|
||||||
forbantime=forbantime, fromtime=fromtime
|
forbantime=forbantime, fromtime=fromtime
|
||||||
|
@ -781,12 +783,17 @@ class Fail2BanDb(object):
|
||||||
# can produce unpack error (database may return sporadical wrong-empty row):
|
# can produce unpack error (database may return sporadical wrong-empty row):
|
||||||
try:
|
try:
|
||||||
banip, timeofban, bantime, bancount, data = ticket
|
banip, timeofban, bantime, bancount, data = ticket
|
||||||
# if persistent ban (or still unknown after upgrade), use current bantime of the jail:
|
|
||||||
if correctBanTime and (bantime == -1 or bantime > correctBanTime):
|
|
||||||
bantime = correctBanTime
|
|
||||||
# additionally check for empty values:
|
# additionally check for empty values:
|
||||||
if banip is None or banip == "": # pragma: no cover
|
if banip is None or banip == "": # pragma: no cover
|
||||||
raise ValueError('unexpected value %r' % (banip,))
|
raise ValueError('unexpected value %r' % (banip,))
|
||||||
|
# if bantime unknown (after upgrade-db from earlier version), just use min known ban-time:
|
||||||
|
if bantime == -2: # todo: remove it in future version
|
||||||
|
bantime = jail.actions.getBanTime() if jail is not None else (
|
||||||
|
correctBanTime if correctBanTime else 600)
|
||||||
|
elif correctBanTime:
|
||||||
|
# if persistent ban (or greater as max), use current max-bantime of the jail:
|
||||||
|
if bantime == -1 or bantime > correctBanTime:
|
||||||
|
bantime = correctBanTime
|
||||||
except ValueError as e: # pragma: no cover
|
except ValueError as e: # pragma: no cover
|
||||||
logSys.debug("get current bans: ignore row %r - %s", ticket, e)
|
logSys.debug("get current bans: ignore row %r - %s", ticket, e)
|
||||||
continue
|
continue
|
||||||
|
|
|
@ -263,14 +263,23 @@ class Jail(object):
|
||||||
return self._banExtra.get(opt, None)
|
return self._banExtra.get(opt, None)
|
||||||
return self._banExtra
|
return self._banExtra
|
||||||
|
|
||||||
|
def getMaxBanTime(self):
|
||||||
|
"""Returns max possible ban-time of jail.
|
||||||
|
"""
|
||||||
|
return self._banExtra.get("maxtime", -1) \
|
||||||
|
if self._banExtra.get('increment') else self.actions.getBanTime()
|
||||||
|
|
||||||
def restoreCurrentBans(self, correctBanTime=True):
|
def restoreCurrentBans(self, correctBanTime=True):
|
||||||
"""Restore any previous valid bans from the database.
|
"""Restore any previous valid bans from the database.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
if self.database is not None:
|
if self.database is not None:
|
||||||
forbantime = None;
|
if self._banExtra.get('increment'):
|
||||||
# use ban time as search time if we have not enabled a increasing:
|
forbantime = None;
|
||||||
if not self.getBanTimeExtra('increment'):
|
if correctBanTime:
|
||||||
|
correctBanTime = self.getMaxBanTime()
|
||||||
|
else:
|
||||||
|
# use ban time as search time if we have not enabled a increasing:
|
||||||
forbantime = self.actions.getBanTime()
|
forbantime = self.actions.getBanTime()
|
||||||
for ticket in self.database.getCurrentBans(jail=self, forbantime=forbantime,
|
for ticket in self.database.getCurrentBans(jail=self, forbantime=forbantime,
|
||||||
correctBanTime=correctBanTime
|
correctBanTime=correctBanTime
|
||||||
|
|
|
@ -170,9 +170,9 @@ class DatabaseTest(LogCaptureTestCase):
|
||||||
self.assertEqual(self.db.updateDb(Fail2BanDb.__version__), Fail2BanDb.__version__)
|
self.assertEqual(self.db.updateDb(Fail2BanDb.__version__), Fail2BanDb.__version__)
|
||||||
self.assertRaises(NotImplementedError, self.db.updateDb, Fail2BanDb.__version__ + 1)
|
self.assertRaises(NotImplementedError, self.db.updateDb, Fail2BanDb.__version__ + 1)
|
||||||
# check current bans (should find exactly 1 ticket after upgrade):
|
# check current bans (should find exactly 1 ticket after upgrade):
|
||||||
tickets = self.db.getCurrentBans(fromtime=1388009242, correctBanTime=False)
|
tickets = self.db.getCurrentBans(fromtime=1388009242, correctBanTime=123456)
|
||||||
self.assertEqual(len(tickets), 1)
|
self.assertEqual(len(tickets), 1)
|
||||||
self.assertEqual(tickets[0].getBanTime(), -1); # ban-time still unknown (normally updated from jail)
|
self.assertEqual(tickets[0].getBanTime(), 123456); # ban-time was unknown (normally updated from jail)
|
||||||
finally:
|
finally:
|
||||||
if self.db and self.db._dbFilename != ":memory:":
|
if self.db and self.db._dbFilename != ":memory:":
|
||||||
os.remove(self.db._dbBackupFilename)
|
os.remove(self.db._dbBackupFilename)
|
||||||
|
|
|
@ -386,6 +386,7 @@ class BanTimeIncrDB(unittest.TestCase):
|
||||||
|
|
||||||
# two separate jails :
|
# two separate jails :
|
||||||
jail1 = DummyJail(backend='polling')
|
jail1 = DummyJail(backend='polling')
|
||||||
|
jail1.setBanTimeExtra('increment', 'true')
|
||||||
jail1.database = self.db
|
jail1.database = self.db
|
||||||
self.db.addJail(jail1)
|
self.db.addJail(jail1)
|
||||||
jail2 = DummyJail(name='DummyJail-2', backend='polling')
|
jail2 = DummyJail(name='DummyJail-2', backend='polling')
|
||||||
|
@ -433,7 +434,8 @@ class BanTimeIncrDB(unittest.TestCase):
|
||||||
# jail2 does not restore any bans (because all ban tickets should be already expired: stime-6000):
|
# jail2 does not restore any bans (because all ban tickets should be already expired: stime-6000):
|
||||||
jail2.restoreCurrentBans(correctBanTime=False)
|
jail2.restoreCurrentBans(correctBanTime=False)
|
||||||
self.assertEqual(jail2.getFailTicket(), False)
|
self.assertEqual(jail2.getFailTicket(), False)
|
||||||
# test again, but now normally (with maximum ban-time of restored ticket allowed):
|
# test again, but now normally (with maximum ban-time of restored ticket = allowed 10m = 600):
|
||||||
|
jail1.setBanTimeExtra('maxtime', '10m')
|
||||||
jail1.restoreCurrentBans()
|
jail1.restoreCurrentBans()
|
||||||
ticket = jail1.getFailTicket()
|
ticket = jail1.getFailTicket()
|
||||||
self.assertTrue(ticket.restored)
|
self.assertTrue(ticket.restored)
|
||||||
|
|
Loading…
Reference in New Issue