mirror of https://github.com/fail2ban/fail2ban
ban time incr: 2st test case added (code optimized for test cases), to test both stand-alone:
python ./bin/fail2ban-testcases -l debug 'BanTimeIncr'pull/716/head
parent
237706e39f
commit
14167ed778
|
@ -300,7 +300,7 @@ class Actions(JailThread, Mapping):
|
|||
def calcBanTime(self, banTime, banCount):
|
||||
return self._banExtra['evformula'](self.BanTimeIncr(banTime, banCount))
|
||||
|
||||
def incrBanTime(self, bTicket, ip):
|
||||
def incrBanTime(self, bTicket):
|
||||
"""Check for IP address to increment ban time (if was already banned).
|
||||
|
||||
Returns
|
||||
|
@ -308,6 +308,7 @@ class Actions(JailThread, Mapping):
|
|||
float
|
||||
new ban time.
|
||||
"""
|
||||
ip = bTicket.getIP()
|
||||
orgBanTime = self.__banManager.getBanTime()
|
||||
banTime = orgBanTime
|
||||
# check ip was already banned (increment time of ban):
|
||||
|
@ -374,7 +375,7 @@ class Actions(JailThread, Mapping):
|
|||
try:
|
||||
# if ban time was not set:
|
||||
if not ticket.getRestored() and bTicket.getBanTime() is None:
|
||||
btime = self.incrBanTime(bTicket, ip)
|
||||
btime = self.incrBanTime(bTicket)
|
||||
bTicket.setBanTime(btime);
|
||||
except Exception as e:
|
||||
logSys.error('%s', e, exc_info=logSys.getEffectiveLevel()<=logging.DEBUG)
|
||||
|
|
|
@ -505,7 +505,9 @@ class Fail2BanDb(object):
|
|||
cur = self._db.cursor()
|
||||
return cur.execute(query, queryArgs)
|
||||
|
||||
def _getCurrentBans(self, jail = None, ip = None, forbantime=None):
|
||||
def _getCurrentBans(self, jail = None, ip = None, forbantime=None, fromtime=None):
|
||||
if fromtime is None:
|
||||
fromtime = MyTime.time()
|
||||
#query = "SELECT count(ip), max(timeofban) FROM bans WHERE ip = ?"
|
||||
query = "SELECT ip, max(timeofban), bantime, bancount, data FROM bans WHERE 1"
|
||||
queryArgs = []
|
||||
|
@ -516,17 +518,17 @@ class Fail2BanDb(object):
|
|||
query += " AND ip=?"
|
||||
queryArgs.append(ip)
|
||||
query += " AND timeofban + bantime > ?"
|
||||
queryArgs.append(MyTime.time())
|
||||
queryArgs.append(fromtime)
|
||||
if forbantime is not None:
|
||||
query += " AND timeofban > ?"
|
||||
queryArgs.append(MyTime.time() - forbantime)
|
||||
queryArgs.append(fromtime - forbantime)
|
||||
query += " GROUP BY ip ORDER BY ip, timeofban DESC"
|
||||
cur = self._db.cursor()
|
||||
#logSys.debug((query, queryArgs));
|
||||
return cur.execute(query, queryArgs)
|
||||
|
||||
def getCurrentBans(self, jail = None, ip = None, forbantime=None):
|
||||
if forbantime is None:
|
||||
def getCurrentBans(self, jail = None, ip = None, forbantime=None, fromtime=None):
|
||||
if forbantime is None and jail is not None:
|
||||
cacheKey = (ip, jail)
|
||||
if cacheKey in self._bansMergedCache:
|
||||
return self._bansMergedCache[cacheKey]
|
||||
|
@ -534,7 +536,7 @@ class Fail2BanDb(object):
|
|||
tickets = []
|
||||
ticket = None
|
||||
|
||||
results = list(self._getCurrentBans(jail=jail, ip=ip, forbantime=forbantime))
|
||||
results = list(self._getCurrentBans(jail=jail, ip=ip, forbantime=forbantime, fromtime=fromtime))
|
||||
|
||||
if results:
|
||||
matches = []
|
||||
|
@ -552,7 +554,7 @@ class Fail2BanDb(object):
|
|||
ticket.setAttempt(failures)
|
||||
tickets.append(ticket)
|
||||
|
||||
if forbantime is None:
|
||||
if forbantime is None and jail is not None:
|
||||
self._bansMergedCache[cacheKey] = tickets if ip is None else ticket
|
||||
return tickets if ip is None else ticket
|
||||
|
||||
|
|
|
@ -278,3 +278,131 @@ class DatabaseTest(unittest.TestCase):
|
|||
self.db.purge() # Should leave jail as ban present
|
||||
self.assertEqual(len(self.db.getJailNames()), 1)
|
||||
self.assertEqual(len(self.db.getBans(jail=self.jail)), 1)
|
||||
|
||||
|
||||
# Author: Serg G. Brester (sebres)
|
||||
#
|
||||
|
||||
__author__ = "Serg Brester"
|
||||
__copyright__ = "Copyright (c) 2014 Serg G. Brester"
|
||||
|
||||
class BanTimeIncr(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
"""Call before every test case."""
|
||||
if Fail2BanDb is None and sys.version_info >= (2,7): # pragma: no cover
|
||||
raise unittest.SkipTest(
|
||||
"Unable to import fail2ban database module as sqlite is not "
|
||||
"available.")
|
||||
elif Fail2BanDb is None:
|
||||
return
|
||||
_, self.dbFilename = tempfile.mkstemp(".db", "fail2ban_")
|
||||
self.db = Fail2BanDb(self.dbFilename)
|
||||
|
||||
def tearDown(self):
|
||||
"""Call after every test case."""
|
||||
if Fail2BanDb is None: # pragma: no cover
|
||||
return
|
||||
# Cleanup
|
||||
os.remove(self.dbFilename)
|
||||
|
||||
def testBanTimeIncr(self):
|
||||
if Fail2BanDb is None: # pragma: no cover
|
||||
return
|
||||
jail = DummyJail()
|
||||
jail.database = self.db
|
||||
self.db.addJail(jail)
|
||||
a = jail.actions
|
||||
# we tests with initial ban time = 10 seconds:
|
||||
a.setBanTime(10)
|
||||
a.setBanTimeExtra('enabled', 'true')
|
||||
a.setBanTimeExtra('multipliers', '1 2 4 8 16 32 64 128 256 512 1024 2048')
|
||||
ip = "127.0.0.2"
|
||||
# used as start and fromtime (like now but time independence, cause test case can run slow):
|
||||
stime = int(MyTime.time())
|
||||
ticket = FailTicket(ip, stime, [])
|
||||
# test ticket not yet found
|
||||
self.assertEqual(
|
||||
[a.incrBanTime(ticket) for i in xrange(3)],
|
||||
[10, 10, 10]
|
||||
)
|
||||
# add a ticket banned
|
||||
self.db.addBan(jail, ticket)
|
||||
# get a ticket already banned in this jail:
|
||||
self.assertEqual(
|
||||
[(banCount, timeOfBan, lastBanTime) for banCount, timeOfBan, lastBanTime in self.db.getBan(ip, jail, None, False)],
|
||||
[(1, stime, 10)]
|
||||
)
|
||||
# incr time and ban a ticket again :
|
||||
ticket.setTime(stime + 15)
|
||||
self.assertEqual(a.incrBanTime(ticket), 20)
|
||||
self.db.addBan(jail, ticket)
|
||||
# get a ticket already banned in this jail:
|
||||
self.assertEqual(
|
||||
[(banCount, timeOfBan, lastBanTime) for banCount, timeOfBan, lastBanTime in self.db.getBan(ip, jail, None, False)],
|
||||
[(2, stime + 15, 20)]
|
||||
)
|
||||
# get a ticket already banned in all jails:
|
||||
self.assertEqual(
|
||||
[(banCount, timeOfBan, lastBanTime) for banCount, timeOfBan, lastBanTime in self.db.getBan(ip, '', None, True)],
|
||||
[(2, stime + 15, 20)]
|
||||
)
|
||||
# search currently banned and 1 day later (nothing should be found):
|
||||
self.assertEqual(
|
||||
self.db.getCurrentBans(forbantime=-24*60*60, fromtime=stime),
|
||||
[]
|
||||
)
|
||||
# search currently banned anywhere:
|
||||
restored_tickets = self.db.getCurrentBans(fromtime=stime)
|
||||
self.assertEqual(
|
||||
str(restored_tickets),
|
||||
('[FailTicket: ip=%s time=%s bantime=20 bancount=2 #attempts=0 matches=[]]' % (ip, stime + 15))
|
||||
)
|
||||
# search currently banned:
|
||||
restored_tickets = self.db.getCurrentBans(jail=jail, fromtime=stime)
|
||||
self.assertEqual(
|
||||
str(restored_tickets),
|
||||
('[FailTicket: ip=%s time=%s bantime=20 bancount=2 #attempts=0 matches=[]]' % (ip, stime + 15))
|
||||
)
|
||||
restored_tickets[0].setRestored(True)
|
||||
self.assertTrue(restored_tickets[0].getRestored())
|
||||
# increase ban multiple times:
|
||||
for i in xrange(10):
|
||||
ticket.setTime(stime + lastBanTime + 5)
|
||||
banTime = a.incrBanTime(ticket)
|
||||
self.assertEqual(banTime, lastBanTime * 2)
|
||||
self.db.addBan(jail, ticket)
|
||||
lastBanTime = banTime
|
||||
# increase again, but the last multiplier reached (time not increased):
|
||||
ticket.setTime(stime + lastBanTime + 5)
|
||||
banTime = a.incrBanTime(ticket)
|
||||
self.assertNotEqual(banTime, lastBanTime * 2)
|
||||
self.assertEqual(banTime, lastBanTime)
|
||||
self.db.addBan(jail, ticket)
|
||||
lastBanTime = banTime
|
||||
# add two tickets from yesterday: one unbanned (bantime already out-dated):
|
||||
ticket2 = FailTicket(ip+'2', stime-24*60*60, [])
|
||||
ticket2.setBanTime(12*60*60)
|
||||
self.db.addBan(jail, ticket2)
|
||||
# and one from yesterday also, but still currently banned :
|
||||
ticket2 = FailTicket(ip+'1', stime-24*60*60, [])
|
||||
ticket2.setBanTime(36*60*60)
|
||||
self.db.addBan(jail, ticket2)
|
||||
# search currently banned:
|
||||
restored_tickets = self.db.getCurrentBans(fromtime=stime)
|
||||
self.assertEqual(len(restored_tickets), 2)
|
||||
self.assertEqual(
|
||||
str(restored_tickets[0]),
|
||||
'FailTicket: ip=%s time=%s bantime=%s bancount=13 #attempts=0 matches=[]' % (ip, stime + lastBanTime + 5, lastBanTime)
|
||||
)
|
||||
self.assertEqual(
|
||||
str(restored_tickets[1]),
|
||||
'FailTicket: ip=%s time=%s bantime=%s bancount=1 #attempts=0 matches=[]' % (ip+'1', stime-24*60*60, 36*60*60)
|
||||
)
|
||||
# search out-dated (give another fromtime now is -18 hours):
|
||||
restored_tickets = self.db.getCurrentBans(fromtime=stime-18*60*60)
|
||||
self.assertEqual(len(restored_tickets), 3)
|
||||
self.assertEqual(
|
||||
str(restored_tickets[2]),
|
||||
'FailTicket: ip=%s time=%s bantime=%s bancount=1 #attempts=0 matches=[]' % (ip+'2', stime-24*60*60, 12*60*60)
|
||||
)
|
||||
|
|
|
@ -184,6 +184,7 @@ def gatherTests(regexps=None, no_network=False):
|
|||
tests.addTest(unittest.makeSuite(misctestcase.CustomDateFormatsTest))
|
||||
# Database
|
||||
tests.addTest(unittest.makeSuite(databasetestcase.DatabaseTest))
|
||||
tests.addTest(unittest.makeSuite(databasetestcase.BanTimeIncr))
|
||||
|
||||
# Filter
|
||||
tests.addTest(unittest.makeSuite(filtertestcase.IgnoreIP))
|
||||
|
|
Loading…
Reference in New Issue