mirror of https://github.com/fail2ban/fail2ban
RF: Refactor Jail and JailThread
Includes: - documentation to new format and use of properties - change isActive->is_active as former no longer documented for python3, and later introduction and documented in python2.6 - status formatter in beautifier somewhat more automatically formatted; no changes are required for additional status elements - JailThread now set to active within `start` method, complimenting `stop` methodpull/628/head
parent
212d05dc0b
commit
df8d700d17
|
@ -121,7 +121,7 @@ class SMTPAction(ActionBase):
|
||||||
self.matches = matches
|
self.matches = matches
|
||||||
|
|
||||||
self.message_values = CallingMap(
|
self.message_values = CallingMap(
|
||||||
jailname = self._jail.getName(), # Doesn't change
|
jailname = self._jail.name,
|
||||||
hostname = socket.gethostname,
|
hostname = socket.gethostname,
|
||||||
bantime = self._jail.actions.getBanTime,
|
bantime = self._jail.actions.getBanTime,
|
||||||
)
|
)
|
||||||
|
|
|
@ -67,28 +67,23 @@ class Beautifier:
|
||||||
msg = "logs: " + response
|
msg = "logs: " + response
|
||||||
elif inC[0:1] == ['status']:
|
elif inC[0:1] == ['status']:
|
||||||
if len(inC) > 1:
|
if len(inC) > 1:
|
||||||
# Create IP list
|
|
||||||
ipList = ""
|
|
||||||
for ip in response[1][1][2][1]:
|
|
||||||
ipList += ip + " "
|
|
||||||
# Creates file list.
|
|
||||||
fileList = ""
|
|
||||||
for f in response[0][1][2][1]:
|
|
||||||
fileList += f + " "
|
|
||||||
# Display information
|
# Display information
|
||||||
msg = "Status for the jail: " + inC[1] + "\n"
|
msg = ["Status for the jail: %s" % inC[1]]
|
||||||
msg = msg + "|- " + response[0][0] + "\n"
|
for n, res1 in enumerate(response):
|
||||||
msg = msg + "| |- " + response[0][1][2][0] + ":\t" + fileList + "\n"
|
prefix1 = "`-" if n == len(response) - 1 else "|-"
|
||||||
msg = msg + "| |- " + response[0][1][0][0] + ":\t" + `response[0][1][0][1]` + "\n"
|
msg.append("%s %s" % (prefix1, res1[0]))
|
||||||
msg = msg + "| `- " + response[0][1][1][0] + ":\t" + `response[0][1][1][1]` + "\n"
|
prefix1 = " " if n == len(response) - 1 else "| "
|
||||||
msg = msg + "`- " + response[1][0] + "\n"
|
for m, res2 in enumerate(res1[1]):
|
||||||
msg = msg + " |- " + response[1][1][0][0] + ":\t" + `response[1][1][0][1]` + "\n"
|
prefix2 = prefix1 + ("`-" if m == len(res1[1]) - 1 else "|-")
|
||||||
msg = msg + " | `- " + response[1][1][2][0] + ":\t" + ipList + "\n"
|
val = " ".join(res2[1]) if isinstance(res2[1], list) else res2[1]
|
||||||
msg = msg + " `- " + response[1][1][1][0] + ":\t" + `response[1][1][1][1]`
|
msg.append("%s %s:\t%s" % (prefix2, res2[0], val))
|
||||||
else:
|
else:
|
||||||
msg = "Status\n"
|
msg = ["Status"]
|
||||||
msg = msg + "|- " + response[0][0] + ":\t" + `response[0][1]` + "\n"
|
for n, res1 in enumerate(response):
|
||||||
msg = msg + "`- " + response[1][0] + ":\t\t" + response[1][1]
|
prefix1 = "`-" if n == len(response) - 1 else "|-"
|
||||||
|
val = " ".join(res1[1]) if isinstance(res1[1], list) else res1[1]
|
||||||
|
msg.append("%s %s:\t%s" % (prefix1, res1[0], val))
|
||||||
|
msg = "\n".join(msg)
|
||||||
elif inC[1] == "logtarget":
|
elif inC[1] == "logtarget":
|
||||||
msg = "Current logging target is:\n"
|
msg = "Current logging target is:\n"
|
||||||
msg = msg + "`- " + response
|
msg = msg + "`- " + response
|
||||||
|
|
|
@ -192,30 +192,29 @@ class Actions(JailThread, Mapping):
|
||||||
bool
|
bool
|
||||||
True when the thread exits nicely.
|
True when the thread exits nicely.
|
||||||
"""
|
"""
|
||||||
self.setActive(True)
|
|
||||||
for name, action in self._actions.iteritems():
|
for name, action in self._actions.iteritems():
|
||||||
try:
|
try:
|
||||||
action.start()
|
action.start()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logSys.error("Failed to start jail '%s' action '%s': %s",
|
logSys.error("Failed to start jail '%s' action '%s': %s",
|
||||||
self._jail.getName(), name, e)
|
self._jail.name, name, e)
|
||||||
while self._isActive():
|
while self.active:
|
||||||
if not self.getIdle():
|
if not self.idle:
|
||||||
#logSys.debug(self._jail.getName() + ": action")
|
#logSys.debug(self._jail.name + ": action")
|
||||||
ret = self.__checkBan()
|
ret = self.__checkBan()
|
||||||
if not ret:
|
if not ret:
|
||||||
self.__checkUnBan()
|
self.__checkUnBan()
|
||||||
time.sleep(self.getSleepTime())
|
time.sleep(self.sleeptime)
|
||||||
else:
|
else:
|
||||||
time.sleep(self.getSleepTime())
|
time.sleep(self.sleeptime)
|
||||||
self.__flushBan()
|
self.__flushBan()
|
||||||
for name, action in self._actions.iteritems():
|
for name, action in self._actions.iteritems():
|
||||||
try:
|
try:
|
||||||
action.stop()
|
action.stop()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logSys.error("Failed to stop jail '%s' action '%s': %s",
|
logSys.error("Failed to stop jail '%s' action '%s': %s",
|
||||||
self._jail.getName(), name, e)
|
self._jail.name, name, e)
|
||||||
logSys.debug(self._jail.getName() + ": action terminated")
|
logSys.debug(self._jail.name + ": action terminated")
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def __checkBan(self):
|
def __checkBan(self):
|
||||||
|
@ -237,31 +236,31 @@ class Actions(JailThread, Mapping):
|
||||||
aInfo["failures"] = bTicket.getAttempt()
|
aInfo["failures"] = bTicket.getAttempt()
|
||||||
aInfo["time"] = bTicket.getTime()
|
aInfo["time"] = bTicket.getTime()
|
||||||
aInfo["matches"] = "\n".join(bTicket.getMatches())
|
aInfo["matches"] = "\n".join(bTicket.getMatches())
|
||||||
if self._jail.getDatabase() is not None:
|
if self._jail.database is not None:
|
||||||
aInfo["ipmatches"] = lambda: "\n".join(
|
aInfo["ipmatches"] = lambda: "\n".join(
|
||||||
self._jail.getDatabase().getBansMerged(
|
self._jail.database.getBansMerged(
|
||||||
ip=bTicket.getIP()).getMatches())
|
ip=bTicket.getIP()).getMatches())
|
||||||
aInfo["ipjailmatches"] = lambda: "\n".join(
|
aInfo["ipjailmatches"] = lambda: "\n".join(
|
||||||
self._jail.getDatabase().getBansMerged(
|
self._jail.database.getBansMerged(
|
||||||
ip=bTicket.getIP(), jail=self._jail).getMatches())
|
ip=bTicket.getIP(), jail=self._jail).getMatches())
|
||||||
aInfo["ipfailures"] = lambda: "\n".join(
|
aInfo["ipfailures"] = lambda: "\n".join(
|
||||||
self._jail.getDatabase().getBansMerged(
|
self._jail.database.getBansMerged(
|
||||||
ip=bTicket.getIP()).getAttempt())
|
ip=bTicket.getIP()).getAttempt())
|
||||||
aInfo["ipjailfailures"] = lambda: "\n".join(
|
aInfo["ipjailfailures"] = lambda: "\n".join(
|
||||||
self._jail.getDatabase().getBansMerged(
|
self._jail.database.getBansMerged(
|
||||||
ip=bTicket.getIP(), jail=self._jail).getAttempt())
|
ip=bTicket.getIP(), jail=self._jail).getAttempt())
|
||||||
if self.__banManager.addBanTicket(bTicket):
|
if self.__banManager.addBanTicket(bTicket):
|
||||||
logSys.warning("[%s] Ban %s" % (self._jail.getName(), aInfo["ip"]))
|
logSys.warning("[%s] Ban %s" % (self._jail.name, aInfo["ip"]))
|
||||||
for name, action in self._actions.iteritems():
|
for name, action in self._actions.iteritems():
|
||||||
try:
|
try:
|
||||||
action.ban(aInfo)
|
action.ban(aInfo)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logSys.error(
|
logSys.error(
|
||||||
"Failed to execute ban jail '%s' action '%s': %s",
|
"Failed to execute ban jail '%s' action '%s': %s",
|
||||||
self._jail.getName(), name, e)
|
self._jail.name, name, e)
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
logSys.info("[%s] %s already banned" % (self._jail.getName(),
|
logSys.info("[%s] %s already banned" % (self._jail.name,
|
||||||
aInfo["ip"]))
|
aInfo["ip"]))
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
@ -298,28 +297,20 @@ class Actions(JailThread, Mapping):
|
||||||
aInfo["failures"] = ticket.getAttempt()
|
aInfo["failures"] = ticket.getAttempt()
|
||||||
aInfo["time"] = ticket.getTime()
|
aInfo["time"] = ticket.getTime()
|
||||||
aInfo["matches"] = "".join(ticket.getMatches())
|
aInfo["matches"] = "".join(ticket.getMatches())
|
||||||
logSys.warning("[%s] Unban %s" % (self._jail.getName(), aInfo["ip"]))
|
logSys.warning("[%s] Unban %s" % (self._jail.name, aInfo["ip"]))
|
||||||
for name, action in self._actions.iteritems():
|
for name, action in self._actions.iteritems():
|
||||||
try:
|
try:
|
||||||
action.unban(aInfo)
|
action.unban(aInfo)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logSys.error(
|
logSys.error(
|
||||||
"Failed to execute unban jail '%s' action '%s': %s",
|
"Failed to execute unban jail '%s' action '%s': %s",
|
||||||
self._jail.getName(), name, e)
|
self._jail.name, name, e)
|
||||||
|
|
||||||
|
@property
|
||||||
def status(self):
|
def status(self):
|
||||||
"""Get the status of the filter.
|
"""Status of active bans, and total ban counts.
|
||||||
|
|
||||||
Get some informations about the filter state such as the total
|
|
||||||
number of failures.
|
|
||||||
|
|
||||||
Returns
|
|
||||||
-------
|
|
||||||
list
|
|
||||||
List of tuple pairs, each containing a description and value
|
|
||||||
for general status information.
|
|
||||||
"""
|
"""
|
||||||
ret = [("Currently banned", self.__banManager.size()),
|
ret = [("Currently banned", self.__banManager.size()),
|
||||||
("Total banned", self.__banManager.getBanTotal()),
|
("Total banned", self.__banManager.getBanTotal()),
|
||||||
("IP list", self.__banManager.getBanList())]
|
("Banned IP list", self.__banManager.getBanList())]
|
||||||
return ret
|
return ret
|
||||||
|
|
|
@ -184,10 +184,10 @@ class Fail2BanDb(object):
|
||||||
def addJail(self, cur, jail):
|
def addJail(self, cur, jail):
|
||||||
cur.execute(
|
cur.execute(
|
||||||
"INSERT OR REPLACE INTO jails(name, enabled) VALUES(?, 1)",
|
"INSERT OR REPLACE INTO jails(name, enabled) VALUES(?, 1)",
|
||||||
(jail.getName(),))
|
(jail.name,))
|
||||||
|
|
||||||
def delJail(self, jail):
|
def delJail(self, jail):
|
||||||
return self.delJailName(jail.getName())
|
return self.delJailName(jail.name)
|
||||||
|
|
||||||
@commitandrollback
|
@commitandrollback
|
||||||
def delJailName(self, cur, name):
|
def delJailName(self, cur, name):
|
||||||
|
@ -211,7 +211,7 @@ class Fail2BanDb(object):
|
||||||
cur.execute(
|
cur.execute(
|
||||||
"SELECT firstlinemd5, lastfilepos FROM logs "
|
"SELECT firstlinemd5, lastfilepos FROM logs "
|
||||||
"WHERE jail=? AND path=?",
|
"WHERE jail=? AND path=?",
|
||||||
(jail.getName(), container.getFileName()))
|
(jail.name, container.getFileName()))
|
||||||
try:
|
try:
|
||||||
firstLineMD5, lastLinePos = cur.fetchone()
|
firstLineMD5, lastLinePos = cur.fetchone()
|
||||||
except TypeError:
|
except TypeError:
|
||||||
|
@ -220,7 +220,7 @@ class Fail2BanDb(object):
|
||||||
cur.execute(
|
cur.execute(
|
||||||
"INSERT OR REPLACE INTO logs(jail, path, firstlinemd5, lastfilepos) "
|
"INSERT OR REPLACE INTO logs(jail, path, firstlinemd5, lastfilepos) "
|
||||||
"VALUES(?, ?, ?, ?)",
|
"VALUES(?, ?, ?, ?)",
|
||||||
(jail.getName(), container.getFileName(),
|
(jail.name, container.getFileName(),
|
||||||
container.getHash(), container.getPos()))
|
container.getHash(), container.getPos()))
|
||||||
if container.getHash() != firstLineMD5:
|
if container.getHash() != firstLineMD5:
|
||||||
lastLinePos = None
|
lastLinePos = None
|
||||||
|
@ -232,7 +232,7 @@ class Fail2BanDb(object):
|
||||||
queryArgs = []
|
queryArgs = []
|
||||||
if jail is not None:
|
if jail is not None:
|
||||||
query += " WHERE jail=?"
|
query += " WHERE jail=?"
|
||||||
queryArgs.append(jail.getName())
|
queryArgs.append(jail.name)
|
||||||
cur.execute(query, queryArgs)
|
cur.execute(query, queryArgs)
|
||||||
return set(row[0] for row in cur.fetchmany())
|
return set(row[0] for row in cur.fetchmany())
|
||||||
|
|
||||||
|
@ -245,7 +245,7 @@ class Fail2BanDb(object):
|
||||||
"UPDATE logs SET firstlinemd5=?, lastfilepos=? "
|
"UPDATE logs SET firstlinemd5=?, lastfilepos=? "
|
||||||
"WHERE jail=? AND path=?",
|
"WHERE jail=? AND path=?",
|
||||||
(container.getHash(), container.getPos(),
|
(container.getHash(), container.getPos(),
|
||||||
jail.getName(), container.getFileName()))
|
jail.name, container.getFileName()))
|
||||||
|
|
||||||
@commitandrollback
|
@commitandrollback
|
||||||
def addBan(self, cur, jail, ticket):
|
def addBan(self, cur, jail, ticket):
|
||||||
|
@ -253,7 +253,7 @@ class Fail2BanDb(object):
|
||||||
#TODO: Implement data parts once arbitrary match keys completed
|
#TODO: Implement data parts once arbitrary match keys completed
|
||||||
cur.execute(
|
cur.execute(
|
||||||
"INSERT INTO bans(jail, ip, timeofban, data) VALUES(?, ?, ?, ?)",
|
"INSERT INTO bans(jail, ip, timeofban, data) VALUES(?, ?, ?, ?)",
|
||||||
(jail.getName(), ticket.getIP(), ticket.getTime(),
|
(jail.name, ticket.getIP(), ticket.getTime(),
|
||||||
{"matches": ticket.getMatches(),
|
{"matches": ticket.getMatches(),
|
||||||
"failures": ticket.getAttempt()}))
|
"failures": ticket.getAttempt()}))
|
||||||
|
|
||||||
|
@ -264,7 +264,7 @@ class Fail2BanDb(object):
|
||||||
|
|
||||||
if jail is not None:
|
if jail is not None:
|
||||||
query += " AND jail=?"
|
query += " AND jail=?"
|
||||||
queryArgs.append(jail.getName())
|
queryArgs.append(jail.name)
|
||||||
if bantime is not None:
|
if bantime is not None:
|
||||||
query += " AND timeofban > ?"
|
query += " AND timeofban > ?"
|
||||||
queryArgs.append(MyTime.time() - bantime)
|
queryArgs.append(MyTime.time() - bantime)
|
||||||
|
@ -284,7 +284,7 @@ class Fail2BanDb(object):
|
||||||
return tickets
|
return tickets
|
||||||
|
|
||||||
def getBansMerged(self, ip, jail=None, **kwargs):
|
def getBansMerged(self, ip, jail=None, **kwargs):
|
||||||
cacheKey = ip if jail is None else "%s|%s" % (ip, jail.getName())
|
cacheKey = ip if jail is None else "%s|%s" % (ip, jail.name)
|
||||||
if cacheKey in self._bansMergedCache:
|
if cacheKey in self._bansMergedCache:
|
||||||
return self._bansMergedCache[cacheKey]
|
return self._bansMergedCache[cacheKey]
|
||||||
matches = []
|
matches = []
|
||||||
|
|
|
@ -530,15 +530,10 @@ class Filter(JailThread):
|
||||||
logSys.error(e)
|
logSys.error(e)
|
||||||
return failList
|
return failList
|
||||||
|
|
||||||
|
@property
|
||||||
##
|
|
||||||
# Get the status of the filter.
|
|
||||||
#
|
|
||||||
# Get some informations about the filter state such as the total
|
|
||||||
# number of failures.
|
|
||||||
# @return a list with tuple
|
|
||||||
|
|
||||||
def status(self):
|
def status(self):
|
||||||
|
"""Status of failures detected by filter.
|
||||||
|
"""
|
||||||
ret = [("Currently failed", self.failManager.size()),
|
ret = [("Currently failed", self.failManager.size()),
|
||||||
("Total failed", self.failManager.getFailTotal())]
|
("Total failed", self.failManager.getFailTotal())]
|
||||||
return ret
|
return ret
|
||||||
|
@ -562,7 +557,7 @@ class FileFilter(Filter):
|
||||||
logSys.error(path + " already exists")
|
logSys.error(path + " already exists")
|
||||||
else:
|
else:
|
||||||
container = FileContainer(path, self.getLogEncoding(), tail)
|
container = FileContainer(path, self.getLogEncoding(), tail)
|
||||||
db = self.jail.getDatabase()
|
db = self.jail.database
|
||||||
if db is not None:
|
if db is not None:
|
||||||
lastpos = db.addLog(self.jail, container)
|
lastpos = db.addLog(self.jail, container)
|
||||||
if lastpos and not tail:
|
if lastpos and not tail:
|
||||||
|
@ -586,7 +581,7 @@ class FileFilter(Filter):
|
||||||
for log in self.__logPath:
|
for log in self.__logPath:
|
||||||
if log.getFileName() == path:
|
if log.getFileName() == path:
|
||||||
self.__logPath.remove(log)
|
self.__logPath.remove(log)
|
||||||
db = self.jail.getDatabase()
|
db = self.jail.database
|
||||||
if db is not None:
|
if db is not None:
|
||||||
db.updateLog(self.jail, log)
|
db.updateLog(self.jail, log)
|
||||||
logSys.info("Removed logfile = %s" % path)
|
logSys.info("Removed logfile = %s" % path)
|
||||||
|
@ -682,18 +677,21 @@ class FileFilter(Filter):
|
||||||
# might occur leading at least to tests failures.
|
# might occur leading at least to tests failures.
|
||||||
while has_content:
|
while has_content:
|
||||||
line = container.readline()
|
line = container.readline()
|
||||||
if not line or not self._isActive():
|
if not line or not self.active:
|
||||||
# The jail reached the bottom or has been stopped
|
# The jail reached the bottom or has been stopped
|
||||||
break
|
break
|
||||||
self.processLineAndAdd(line)
|
self.processLineAndAdd(line)
|
||||||
container.close()
|
container.close()
|
||||||
db = self.jail.getDatabase()
|
db = self.jail.database
|
||||||
if db is not None:
|
if db is not None:
|
||||||
db.updateLog(self.jail, container)
|
db.updateLog(self.jail, container)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
@property
|
||||||
def status(self):
|
def status(self):
|
||||||
ret = Filter.status(self)
|
"""Status of Filter plus files being monitored.
|
||||||
|
"""
|
||||||
|
ret = super(FileFilter, self).status
|
||||||
path = [m.getFileName() for m in self.getLogPath()]
|
path = [m.getFileName() for m in self.getLogPath()]
|
||||||
ret.append(("File list", path))
|
ret.append(("File list", path))
|
||||||
return ret
|
return ret
|
||||||
|
|
|
@ -109,16 +109,15 @@ class FilterGamin(FileFilter):
|
||||||
# @return True when the thread exits nicely
|
# @return True when the thread exits nicely
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
self.setActive(True)
|
|
||||||
# Gamin needs a loop to collect and dispatch events
|
# Gamin needs a loop to collect and dispatch events
|
||||||
while self._isActive():
|
while self.active:
|
||||||
if not self.getIdle():
|
if not self.idle:
|
||||||
# We cannot block here because we want to be able to
|
# We cannot block here because we want to be able to
|
||||||
# exit.
|
# exit.
|
||||||
if self.monitor.event_pending():
|
if self.monitor.event_pending():
|
||||||
self.monitor.handle_events()
|
self.monitor.handle_events()
|
||||||
time.sleep(self.getSleepTime())
|
time.sleep(self.sleeptime)
|
||||||
logSys.debug(self.jail.getName() + ": filter terminated")
|
logSys.debug(self.jail.name + ": filter terminated")
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -82,12 +82,11 @@ class FilterPoll(FileFilter):
|
||||||
# @return True when the thread exits nicely
|
# @return True when the thread exits nicely
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
self.setActive(True)
|
while self.active:
|
||||||
while self._isActive():
|
|
||||||
if logSys.getEffectiveLevel() <= 6:
|
if logSys.getEffectiveLevel() <= 6:
|
||||||
logSys.log(6, "Woke up idle=%s with %d files monitored",
|
logSys.log(6, "Woke up idle=%s with %d files monitored",
|
||||||
self.getIdle(), len(self.getLogPath()))
|
self.idle, len(self.getLogPath()))
|
||||||
if not self.getIdle():
|
if not self.idle:
|
||||||
# Get file modification
|
# Get file modification
|
||||||
for container in self.getLogPath():
|
for container in self.getLogPath():
|
||||||
filename = container.getFileName()
|
filename = container.getFileName()
|
||||||
|
@ -104,11 +103,11 @@ class FilterPoll(FileFilter):
|
||||||
self.failManager.cleanup(MyTime.time())
|
self.failManager.cleanup(MyTime.time())
|
||||||
self.dateDetector.sortTemplate()
|
self.dateDetector.sortTemplate()
|
||||||
self.__modified = False
|
self.__modified = False
|
||||||
time.sleep(self.getSleepTime())
|
time.sleep(self.sleeptime)
|
||||||
else:
|
else:
|
||||||
time.sleep(self.getSleepTime())
|
time.sleep(self.sleeptime)
|
||||||
logSys.debug(
|
logSys.debug(
|
||||||
(self.jail is not None and self.jail.getName() or "jailless") +
|
(self.jail is not None and self.jail.name or "jailless") +
|
||||||
" filter terminated")
|
" filter terminated")
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
@ -143,7 +142,7 @@ class FilterPoll(FileFilter):
|
||||||
if self.__file404Cnt[filename] > 2:
|
if self.__file404Cnt[filename] > 2:
|
||||||
logSys.warning("Too many errors. Setting the jail idle")
|
logSys.warning("Too many errors. Setting the jail idle")
|
||||||
if self.jail is not None:
|
if self.jail is not None:
|
||||||
self.jail.setIdle(True)
|
self.jail.idle = True
|
||||||
else:
|
else:
|
||||||
logSys.warning("No jail is assigned to %s" % self)
|
logSys.warning("No jail is assigned to %s" % self)
|
||||||
self.__file404Cnt[filename] = 0
|
self.__file404Cnt[filename] = 0
|
||||||
|
|
|
@ -168,11 +168,10 @@ class FilterPyinotify(FileFilter):
|
||||||
# loop is necessary
|
# loop is necessary
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
self.setActive(True)
|
|
||||||
self.__notifier = pyinotify.ThreadedNotifier(self.__monitor,
|
self.__notifier = pyinotify.ThreadedNotifier(self.__monitor,
|
||||||
ProcessPyinotify(self))
|
ProcessPyinotify(self))
|
||||||
self.__notifier.start()
|
self.__notifier.start()
|
||||||
logSys.debug("pyinotifier started for %s.", self.jail.getName())
|
logSys.debug("pyinotifier started for %s.", self.jail.name)
|
||||||
# TODO: verify that there is nothing really to be done for
|
# TODO: verify that there is nothing really to be done for
|
||||||
# idle jails
|
# idle jails
|
||||||
return True
|
return True
|
||||||
|
|
|
@ -211,7 +211,6 @@ class FilterSystemd(JournalFilter): # pragma: systemd no cover
|
||||||
# handover to FailManager
|
# handover to FailManager
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
self.setActive(True)
|
|
||||||
|
|
||||||
# Seek to now - findtime in journal
|
# Seek to now - findtime in journal
|
||||||
start_time = datetime.datetime.now() - \
|
start_time = datetime.datetime.now() - \
|
||||||
|
@ -224,9 +223,9 @@ class FilterSystemd(JournalFilter): # pragma: systemd no cover
|
||||||
except OSError:
|
except OSError:
|
||||||
pass # Reading failure, so safe to ignore
|
pass # Reading failure, so safe to ignore
|
||||||
|
|
||||||
while self._isActive():
|
while self.active:
|
||||||
if not self.getIdle():
|
if not self.idle:
|
||||||
while self._isActive():
|
while self.active:
|
||||||
try:
|
try:
|
||||||
logentry = self.__journal.get_next()
|
logentry = self.__journal.get_next()
|
||||||
except OSError:
|
except OSError:
|
||||||
|
@ -247,20 +246,14 @@ class FilterSystemd(JournalFilter): # pragma: systemd no cover
|
||||||
except FailManagerEmpty:
|
except FailManagerEmpty:
|
||||||
self.failManager.cleanup(MyTime.time())
|
self.failManager.cleanup(MyTime.time())
|
||||||
self.__modified = False
|
self.__modified = False
|
||||||
self.__journal.wait(self.getSleepTime())
|
self.__journal.wait(self.sleeptime)
|
||||||
logSys.debug((self.jail is not None and self.jail.getName()
|
logSys.debug((self.jail is not None and self.jail.name
|
||||||
or "jailless") +" filter terminated")
|
or "jailless") +" filter terminated")
|
||||||
return True
|
return True
|
||||||
|
|
||||||
##
|
@property
|
||||||
# Get the status of the filter.
|
|
||||||
#
|
|
||||||
# Get some informations about the filter state such as the total
|
|
||||||
# number of failures.
|
|
||||||
# @return a list with tuple
|
|
||||||
|
|
||||||
def status(self):
|
def status(self):
|
||||||
ret = JournalFilter.status(self)
|
ret = super(FilterSystemd, self).status
|
||||||
ret.append(("Journal matches",
|
ret.append(("Journal matches",
|
||||||
[" + ".join(" ".join(match) for match in self.__matches)]))
|
[" + ".join(" ".join(match) for match in self.__matches)]))
|
||||||
return ret
|
return ret
|
||||||
|
|
|
@ -31,6 +31,12 @@ from .actions import Actions
|
||||||
logSys = logging.getLogger(__name__)
|
logSys = logging.getLogger(__name__)
|
||||||
|
|
||||||
class Jail:
|
class Jail:
|
||||||
|
"""Fail2Ban jail, which manages a filter and associated actions.
|
||||||
|
|
||||||
|
The class handles the initialisation of a filter, and actions. It's
|
||||||
|
role is then to act as an interface between the filter and actions,
|
||||||
|
passing bans detected by the filter, for the actions to then act upon.
|
||||||
|
"""
|
||||||
|
|
||||||
#Known backends. Each backend should have corresponding __initBackend method
|
#Known backends. Each backend should have corresponding __initBackend method
|
||||||
# yoh: stored in a list instead of a tuple since only
|
# yoh: stored in a list instead of a tuple since only
|
||||||
|
@ -38,15 +44,32 @@ class Jail:
|
||||||
_BACKENDS = ['pyinotify', 'gamin', 'polling', 'systemd']
|
_BACKENDS = ['pyinotify', 'gamin', 'polling', 'systemd']
|
||||||
|
|
||||||
def __init__(self, name, backend = "auto", db=None):
|
def __init__(self, name, backend = "auto", db=None):
|
||||||
|
"""Initialise a jail, by initalises filter and actions.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
name : str
|
||||||
|
Name assigned to the jail.
|
||||||
|
backend : str
|
||||||
|
Backend to be used for filter. "auto" will attempt to pick
|
||||||
|
the most preferred backend method. Default: "auto"
|
||||||
|
db : Fail2BanDb
|
||||||
|
Fail2Ban persistent database instance. Default: `None`
|
||||||
|
"""
|
||||||
self.__db = db
|
self.__db = db
|
||||||
self.setName(name)
|
# 26 based on iptable chain name limit of 30 less len('f2b-')
|
||||||
|
if len(name) >= 26:
|
||||||
|
logSys.warning("Jail name %r might be too long and some commands "
|
||||||
|
"might not function correctly. Please shorten"
|
||||||
|
% name)
|
||||||
|
self.__name = name
|
||||||
self.__queue = Queue.Queue()
|
self.__queue = Queue.Queue()
|
||||||
self.__filter = None
|
self.__filter = None
|
||||||
logSys.info("Creating new jail '%s'" % self.__name)
|
logSys.info("Creating new jail '%s'" % self.name)
|
||||||
self._setBackend(backend)
|
self._setBackend(backend)
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "%s(%r)" % (self.__class__.__name__, self.__name)
|
return "%s(%r)" % (self.__class__.__name__, self.name)
|
||||||
|
|
||||||
def _setBackend(self, backend):
|
def _setBackend(self, backend):
|
||||||
backend = backend.lower() # to assure consistent matching
|
backend = backend.lower() # to assure consistent matching
|
||||||
|
@ -78,51 +101,49 @@ class Jail:
|
||||||
"Backend %r failed to initialize due to %s" % (b, e))
|
"Backend %r failed to initialize due to %s" % (b, e))
|
||||||
# log error since runtime error message isn't printed, INVALID COMMAND
|
# log error since runtime error message isn't printed, INVALID COMMAND
|
||||||
logSys.error(
|
logSys.error(
|
||||||
"Failed to initialize any backend for Jail %r" % self.__name)
|
"Failed to initialize any backend for Jail %r" % self.name)
|
||||||
raise RuntimeError(
|
raise RuntimeError(
|
||||||
"Failed to initialize any backend for Jail %r" % self.__name)
|
"Failed to initialize any backend for Jail %r" % self.name)
|
||||||
|
|
||||||
|
|
||||||
def _initPolling(self):
|
def _initPolling(self):
|
||||||
logSys.info("Jail '%s' uses poller" % self.__name)
|
logSys.info("Jail '%s' uses poller" % self.name)
|
||||||
from filterpoll import FilterPoll
|
from filterpoll import FilterPoll
|
||||||
self.__filter = FilterPoll(self)
|
self.__filter = FilterPoll(self)
|
||||||
|
|
||||||
def _initGamin(self):
|
def _initGamin(self):
|
||||||
# Try to import gamin
|
# Try to import gamin
|
||||||
import gamin
|
import gamin
|
||||||
logSys.info("Jail '%s' uses Gamin" % self.__name)
|
logSys.info("Jail '%s' uses Gamin" % self.name)
|
||||||
from filtergamin import FilterGamin
|
from filtergamin import FilterGamin
|
||||||
self.__filter = FilterGamin(self)
|
self.__filter = FilterGamin(self)
|
||||||
|
|
||||||
def _initPyinotify(self):
|
def _initPyinotify(self):
|
||||||
# Try to import pyinotify
|
# Try to import pyinotify
|
||||||
import pyinotify
|
import pyinotify
|
||||||
logSys.info("Jail '%s' uses pyinotify" % self.__name)
|
logSys.info("Jail '%s' uses pyinotify" % self.name)
|
||||||
from filterpyinotify import FilterPyinotify
|
from filterpyinotify import FilterPyinotify
|
||||||
self.__filter = FilterPyinotify(self)
|
self.__filter = FilterPyinotify(self)
|
||||||
|
|
||||||
def _initSystemd(self): # pragma: systemd no cover
|
def _initSystemd(self): # pragma: systemd no cover
|
||||||
# Try to import systemd
|
# Try to import systemd
|
||||||
import systemd
|
import systemd
|
||||||
logSys.info("Jail '%s' uses systemd" % self.__name)
|
logSys.info("Jail '%s' uses systemd" % self.name)
|
||||||
from filtersystemd import FilterSystemd
|
from filtersystemd import FilterSystemd
|
||||||
self.__filter = FilterSystemd(self)
|
self.__filter = FilterSystemd(self)
|
||||||
|
|
||||||
def setName(self, name):
|
@property
|
||||||
# 26 based on iptable chain name limit of 30 less len('f2b-')
|
def name(self):
|
||||||
if len(name) >= 26:
|
"""Name of jail.
|
||||||
logSys.warning("Jail name %r might be too long and some commands "
|
"""
|
||||||
"might not function correctly. Please shorten"
|
|
||||||
% name)
|
|
||||||
self.__name = name
|
|
||||||
|
|
||||||
def getName(self):
|
|
||||||
return self.__name
|
return self.__name
|
||||||
|
|
||||||
def getDatabase(self):
|
@property
|
||||||
|
def database(self):
|
||||||
|
"""The database used to store persistent data for the jail.
|
||||||
|
"""
|
||||||
return self.__db
|
return self.__db
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def filter(self):
|
def filter(self):
|
||||||
"""The filter which the jail is using to monitor log files.
|
"""The filter which the jail is using to monitor log files.
|
||||||
|
@ -134,50 +155,71 @@ class Jail:
|
||||||
"""Actions object used to manage actions for jail.
|
"""Actions object used to manage actions for jail.
|
||||||
"""
|
"""
|
||||||
return self.__actions
|
return self.__actions
|
||||||
|
|
||||||
|
@property
|
||||||
|
def idle(self):
|
||||||
|
"""A boolean indicating whether jail is idle.
|
||||||
|
"""
|
||||||
|
return self.filter.idle or self.actions.idle
|
||||||
|
|
||||||
|
@idle.setter
|
||||||
|
def idle(self, value):
|
||||||
|
self.filter.idle = value
|
||||||
|
self.actions.idle = value
|
||||||
|
|
||||||
|
@property
|
||||||
|
def status(self):
|
||||||
|
"""The status of the jail.
|
||||||
|
"""
|
||||||
|
return [
|
||||||
|
("Filter", self.filter.status),
|
||||||
|
("Actions", self.actions.status),
|
||||||
|
]
|
||||||
|
|
||||||
def putFailTicket(self, ticket):
|
def putFailTicket(self, ticket):
|
||||||
|
"""Add a fail ticket to the jail.
|
||||||
|
|
||||||
|
Used by filter to add a failure for banning.
|
||||||
|
"""
|
||||||
self.__queue.put(ticket)
|
self.__queue.put(ticket)
|
||||||
if self.__db is not None:
|
if self.database is not None:
|
||||||
self.__db.addBan(self, ticket)
|
self.database.addBan(self, ticket)
|
||||||
|
|
||||||
def getFailTicket(self):
|
def getFailTicket(self):
|
||||||
|
"""Get a fail ticket from the jail.
|
||||||
|
|
||||||
|
Used by actions to get a failure for banning.
|
||||||
|
"""
|
||||||
try:
|
try:
|
||||||
return self.__queue.get(False)
|
return self.__queue.get(False)
|
||||||
except Queue.Empty:
|
except Queue.Empty:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def start(self):
|
def start(self):
|
||||||
self.__filter.start()
|
"""Start the jail, by starting filter and actions threads.
|
||||||
self.__actions.start()
|
|
||||||
|
Once stated, also queries the persistent database to reinstate
|
||||||
|
any valid bans.
|
||||||
|
"""
|
||||||
|
self.filter.start()
|
||||||
|
self.actions.start()
|
||||||
# Restore any previous valid bans from the database
|
# Restore any previous valid bans from the database
|
||||||
if self.__db is not None:
|
if self.database is not None:
|
||||||
for ticket in self.__db.getBans(
|
for ticket in self.database.getBans(
|
||||||
jail=self, bantime=self.__actions.getBanTime()):
|
jail=self, bantime=self.actions.getBanTime()):
|
||||||
self.__queue.put(ticket)
|
self.__queue.put(ticket)
|
||||||
logSys.info("Jail '%s' started" % self.__name)
|
logSys.info("Jail '%s' started" % self.name)
|
||||||
|
|
||||||
def stop(self):
|
def stop(self):
|
||||||
self.__filter.stop()
|
"""Stop the jail, by stopping filter and actions threads.
|
||||||
self.__actions.stop()
|
"""
|
||||||
self.__filter.join()
|
self.filter.stop()
|
||||||
self.__actions.join()
|
self.actions.stop()
|
||||||
logSys.info("Jail '%s' stopped" % self.__name)
|
self.filter.join()
|
||||||
|
self.actions.join()
|
||||||
def isAlive(self):
|
logSys.info("Jail '%s' stopped" % self.name)
|
||||||
isAlive0 = self.__filter.isAlive()
|
|
||||||
isAlive1 = self.__actions.isAlive()
|
def is_alive(self):
|
||||||
return isAlive0 or isAlive1
|
"""Check jail "is_alive" by checking filter and actions threads.
|
||||||
|
"""
|
||||||
def setIdle(self, value):
|
return self.filter.is_alive() or self.actions.is_alive()
|
||||||
self.__filter.setIdle(value)
|
|
||||||
self.__actions.setIdle(value)
|
|
||||||
|
|
||||||
def getIdle(self):
|
|
||||||
return self.__filter.getIdle() or self.__actions.getIdle()
|
|
||||||
|
|
||||||
def getStatus(self):
|
|
||||||
fStatus = self.__filter.status()
|
|
||||||
aStatus = self.__actions.status()
|
|
||||||
ret = [("filter", fStatus),
|
|
||||||
("action", aStatus)]
|
|
||||||
return ret
|
|
||||||
|
|
|
@ -25,94 +25,42 @@ __copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
||||||
__license__ = "GPL"
|
__license__ = "GPL"
|
||||||
|
|
||||||
from threading import Thread
|
from threading import Thread
|
||||||
import logging
|
from abc import abstractproperty, abstractmethod
|
||||||
|
|
||||||
# Gets the instance of the logger.
|
|
||||||
logSys = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
class JailThread(Thread):
|
class JailThread(Thread):
|
||||||
|
"""Abstract class for threading elements in Fail2Ban.
|
||||||
##
|
"""
|
||||||
# Constructor.
|
|
||||||
#
|
|
||||||
# Initialize the filter object with default values.
|
|
||||||
# @param jail the jail object
|
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
Thread.__init__(self)
|
"""Initialise a JailThread instance.
|
||||||
|
"""
|
||||||
|
super(JailThread, self).__init__()
|
||||||
## Control the state of the thread.
|
## Control the state of the thread.
|
||||||
self.__isRunning = False
|
self.active = False
|
||||||
## Control the idle state of the thread.
|
## Control the idle state of the thread.
|
||||||
self.__isIdle = False
|
self.idle = False
|
||||||
## The time the thread sleeps in the loop.
|
## The time the thread sleeps in the loop.
|
||||||
self.__sleepTime = 1
|
self.sleeptime = 1
|
||||||
|
|
||||||
##
|
@abstractproperty
|
||||||
# Set the time that the thread sleeps.
|
def status(self): # pragma: no cover - abstract
|
||||||
#
|
"""Abstract - Should provide status information.
|
||||||
# This value could also be called "polling time". A value of 1 is a
|
"""
|
||||||
# good one. This unit is "second"
|
pass
|
||||||
# @param value the polling time (second)
|
|
||||||
|
def start(self):
|
||||||
def setSleepTime(self, value):
|
"""Sets active flag and starts thread.
|
||||||
self.__sleepTime = value
|
"""
|
||||||
logSys.info("Set sleeptime %s" % value)
|
self.active = True
|
||||||
|
super(JailThread, self).start()
|
||||||
##
|
|
||||||
# Get the time that the thread sleeps.
|
def stop(self):
|
||||||
#
|
"""Sets `active` property to False, to flag run method to return.
|
||||||
# @return the polling time
|
"""
|
||||||
|
self.active = False
|
||||||
def getSleepTime(self):
|
|
||||||
return self.__sleepTime
|
@abstractmethod
|
||||||
|
def run(self): # pragma: no cover - absract
|
||||||
##
|
"""Abstract - Called when thread starts, thread stops when returns.
|
||||||
# Set the idle flag.
|
"""
|
||||||
#
|
|
||||||
# This flag stops the check of the log file.
|
|
||||||
# @param value boolean value
|
|
||||||
|
|
||||||
def setIdle(self, value):
|
|
||||||
self.__isIdle = value
|
|
||||||
|
|
||||||
##
|
|
||||||
# Get the idle state.
|
|
||||||
#
|
|
||||||
# @return the idle state
|
|
||||||
|
|
||||||
def getIdle(self):
|
|
||||||
return self.__isIdle
|
|
||||||
|
|
||||||
##
|
|
||||||
# Stop the thread.
|
|
||||||
#
|
|
||||||
# Stop the exection of the thread and quit.
|
|
||||||
|
|
||||||
def stop(self):
|
|
||||||
self.__isRunning = False
|
|
||||||
|
|
||||||
##
|
|
||||||
# Set the isRunning flag.
|
|
||||||
#
|
|
||||||
# @param value True if the thread is running
|
|
||||||
|
|
||||||
def setActive(self, value):
|
|
||||||
self.__isRunning = value
|
|
||||||
|
|
||||||
##
|
|
||||||
# Check if the thread is active.
|
|
||||||
#
|
|
||||||
# Check if the filter thread is running.
|
|
||||||
# @return True if the thread is running
|
|
||||||
|
|
||||||
def _isActive(self):
|
|
||||||
return self.__isRunning
|
|
||||||
|
|
||||||
##
|
|
||||||
# Get the status of the thread
|
|
||||||
#
|
|
||||||
# Get some informations about the thread. This is an abstract method.
|
|
||||||
# @return a list with tuple
|
|
||||||
|
|
||||||
def status(self):
|
|
||||||
pass
|
pass
|
||||||
|
|
|
@ -132,7 +132,7 @@ class Server:
|
||||||
def startJail(self, name):
|
def startJail(self, name):
|
||||||
try:
|
try:
|
||||||
self.__lock.acquire()
|
self.__lock.acquire()
|
||||||
if not self.isAlive(name):
|
if not self.__jails[name].is_alive():
|
||||||
self.__jails[name].start()
|
self.__jails[name].start()
|
||||||
finally:
|
finally:
|
||||||
self.__lock.release()
|
self.__lock.release()
|
||||||
|
@ -141,7 +141,7 @@ class Server:
|
||||||
logSys.debug("Stopping jail %s" % name)
|
logSys.debug("Stopping jail %s" % name)
|
||||||
try:
|
try:
|
||||||
self.__lock.acquire()
|
self.__lock.acquire()
|
||||||
if self.isAlive(name):
|
if self.__jails[name].is_alive():
|
||||||
self.__jails[name].stop()
|
self.__jails[name].stop()
|
||||||
self.delJail(name)
|
self.delJail(name)
|
||||||
finally:
|
finally:
|
||||||
|
@ -155,16 +155,13 @@ class Server:
|
||||||
self.stopJail(jail)
|
self.stopJail(jail)
|
||||||
finally:
|
finally:
|
||||||
self.__lock.release()
|
self.__lock.release()
|
||||||
|
|
||||||
def isAlive(self, name):
|
|
||||||
return self.__jails[name].isAlive()
|
|
||||||
|
|
||||||
def setIdleJail(self, name, value):
|
def setIdleJail(self, name, value):
|
||||||
self.__jails[name].setIdle(value)
|
self.__jails[name].idle = value
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def getIdleJail(self, name):
|
def getIdleJail(self, name):
|
||||||
return self.__jails[name].getIdle()
|
return self.__jails[name].idle
|
||||||
|
|
||||||
# Filter
|
# Filter
|
||||||
def addIgnoreIP(self, name, ip):
|
def addIgnoreIP(self, name, ip):
|
||||||
|
@ -316,7 +313,7 @@ class Server:
|
||||||
self.__lock.release()
|
self.__lock.release()
|
||||||
|
|
||||||
def statusJail(self, name):
|
def statusJail(self, name):
|
||||||
return self.__jails[name].getStatus()
|
return self.__jails[name].status
|
||||||
|
|
||||||
# Logging
|
# Logging
|
||||||
|
|
||||||
|
|
|
@ -77,7 +77,7 @@ class SMTPActionTest(unittest.TestCase):
|
||||||
self.assertEqual(self.smtpd.mailfrom, "fail2ban")
|
self.assertEqual(self.smtpd.mailfrom, "fail2ban")
|
||||||
self.assertEqual(self.smtpd.rcpttos, ["root"])
|
self.assertEqual(self.smtpd.rcpttos, ["root"])
|
||||||
self.assertTrue(
|
self.assertTrue(
|
||||||
"Subject: [Fail2Ban] %s: started" % self.jail.getName()
|
"Subject: [Fail2Ban] %s: started" % self.jail.name
|
||||||
in self.smtpd.data)
|
in self.smtpd.data)
|
||||||
|
|
||||||
def testStop(self):
|
def testStop(self):
|
||||||
|
@ -86,7 +86,7 @@ class SMTPActionTest(unittest.TestCase):
|
||||||
self.assertEqual(self.smtpd.rcpttos, ["root"])
|
self.assertEqual(self.smtpd.rcpttos, ["root"])
|
||||||
self.assertTrue(
|
self.assertTrue(
|
||||||
"Subject: [Fail2Ban] %s: stopped" %
|
"Subject: [Fail2Ban] %s: stopped" %
|
||||||
self.jail.getName() in self.smtpd.data)
|
self.jail.name in self.smtpd.data)
|
||||||
|
|
||||||
def testBan(self):
|
def testBan(self):
|
||||||
aInfo = {
|
aInfo = {
|
||||||
|
@ -102,7 +102,7 @@ class SMTPActionTest(unittest.TestCase):
|
||||||
self.assertEqual(self.smtpd.rcpttos, ["root"])
|
self.assertEqual(self.smtpd.rcpttos, ["root"])
|
||||||
self.assertTrue(
|
self.assertTrue(
|
||||||
"Subject: [Fail2Ban] %s: banned %s" %
|
"Subject: [Fail2Ban] %s: banned %s" %
|
||||||
(self.jail.getName(), aInfo['ip']) in self.smtpd.data)
|
(self.jail.name, aInfo['ip']) in self.smtpd.data)
|
||||||
self.assertTrue(
|
self.assertTrue(
|
||||||
"%i attempts" % aInfo['failures'] in self.smtpd.data)
|
"%i attempts" % aInfo['failures'] in self.smtpd.data)
|
||||||
|
|
||||||
|
|
|
@ -84,8 +84,8 @@ class ExecuteActions(LogCaptureTestCase):
|
||||||
|
|
||||||
self.__actions.stop()
|
self.__actions.stop()
|
||||||
self.__actions.join()
|
self.__actions.join()
|
||||||
self.assertEqual(self.__actions.status(),[("Currently banned", 0 ),
|
self.assertEqual(self.__actions.status,[("Currently banned", 0 ),
|
||||||
("Total banned", 0 ), ("IP list", [] )])
|
("Total banned", 0 ), ("Banned IP list", [] )])
|
||||||
|
|
||||||
|
|
||||||
def testAddActionPython(self):
|
def testAddActionPython(self):
|
||||||
|
|
|
@ -61,7 +61,7 @@ class DatabaseTest(unittest.TestCase):
|
||||||
self.db = Fail2BanDb(self.dbFilename)
|
self.db = Fail2BanDb(self.dbFilename)
|
||||||
# and check jail of same name still present
|
# and check jail of same name still present
|
||||||
self.assertTrue(
|
self.assertTrue(
|
||||||
self.jail.getName() in self.db.getJailNames(),
|
self.jail.name in self.db.getJailNames(),
|
||||||
"Jail not retained in Db after disconnect reconnect.")
|
"Jail not retained in Db after disconnect reconnect.")
|
||||||
|
|
||||||
def testUpdateDb(self):
|
def testUpdateDb(self):
|
||||||
|
@ -80,7 +80,7 @@ class DatabaseTest(unittest.TestCase):
|
||||||
self.jail = DummyJail()
|
self.jail = DummyJail()
|
||||||
self.db.addJail(self.jail)
|
self.db.addJail(self.jail)
|
||||||
self.assertTrue(
|
self.assertTrue(
|
||||||
self.jail.getName() in self.db.getJailNames(),
|
self.jail.name in self.db.getJailNames(),
|
||||||
"Jail not added to database")
|
"Jail not added to database")
|
||||||
|
|
||||||
def testAddLog(self):
|
def testAddLog(self):
|
||||||
|
|
|
@ -32,6 +32,8 @@ class DummyJail(object):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.lock = Lock()
|
self.lock = Lock()
|
||||||
self.queue = []
|
self.queue = []
|
||||||
|
self.idle = False
|
||||||
|
self.database = None
|
||||||
self.actions = Actions(self)
|
self.actions = Actions(self)
|
||||||
|
|
||||||
def __len__(self):
|
def __len__(self):
|
||||||
|
@ -58,15 +60,6 @@ class DummyJail(object):
|
||||||
finally:
|
finally:
|
||||||
self.lock.release()
|
self.lock.release()
|
||||||
|
|
||||||
def setIdle(self, value):
|
@property
|
||||||
pass
|
def name(self):
|
||||||
|
|
||||||
def getIdle(self):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def getName(self):
|
|
||||||
return "DummyJail #%s with %d tickets" % (id(self), len(self))
|
return "DummyJail #%s with %d tickets" % (id(self), len(self))
|
||||||
|
|
||||||
def getDatabase(self):
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
|
@ -325,7 +325,7 @@ class LogFileMonitor(LogCaptureTestCase):
|
||||||
self.file = open(self.name, 'a')
|
self.file = open(self.name, 'a')
|
||||||
self.filter = FilterPoll(DummyJail())
|
self.filter = FilterPoll(DummyJail())
|
||||||
self.filter.addLogPath(self.name)
|
self.filter.addLogPath(self.name)
|
||||||
self.filter.setActive(True)
|
self.filter.active = True
|
||||||
self.filter.addFailRegex("(?:(?:Authentication failure|Failed [-/\w+]+) for(?: [iI](?:llegal|nvalid) user)?|[Ii](?:llegal|nvalid) user|ROOT LOGIN REFUSED) .*(?: from|FROM) <HOST>")
|
self.filter.addFailRegex("(?:(?:Authentication failure|Failed [-/\w+]+) for(?: [iI](?:llegal|nvalid) user)?|[Ii](?:llegal|nvalid) user|ROOT LOGIN REFUSED) .*(?: from|FROM) <HOST>")
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
|
@ -466,7 +466,7 @@ def get_monitor_failures_testcase(Filter_):
|
||||||
self.jail = DummyJail()
|
self.jail = DummyJail()
|
||||||
self.filter = Filter_(self.jail)
|
self.filter = Filter_(self.jail)
|
||||||
self.filter.addLogPath(self.name)
|
self.filter.addLogPath(self.name)
|
||||||
self.filter.setActive(True)
|
self.filter.active = True
|
||||||
self.filter.addFailRegex("(?:(?:Authentication failure|Failed [-/\w+]+) for(?: [iI](?:llegal|nvalid) user)?|[Ii](?:llegal|nvalid) user|ROOT LOGIN REFUSED) .*(?: from|FROM) <HOST>")
|
self.filter.addFailRegex("(?:(?:Authentication failure|Failed [-/\w+]+) for(?: [iI](?:llegal|nvalid) user)?|[Ii](?:llegal|nvalid) user|ROOT LOGIN REFUSED) .*(?: from|FROM) <HOST>")
|
||||||
self.filter.start()
|
self.filter.start()
|
||||||
# If filter is polling it would sleep a bit to guarantee that
|
# If filter is polling it would sleep a bit to guarantee that
|
||||||
|
@ -687,7 +687,7 @@ def get_monitor_failures_journal_testcase(Filter_): # pragma: systemd no cover
|
||||||
"TEST_UUID=%s" % self.test_uuid])
|
"TEST_UUID=%s" % self.test_uuid])
|
||||||
self.journal_fields = {
|
self.journal_fields = {
|
||||||
'TEST_FIELD': "1", 'TEST_UUID': self.test_uuid}
|
'TEST_FIELD': "1", 'TEST_UUID': self.test_uuid}
|
||||||
self.filter.setActive(True)
|
self.filter.active = True
|
||||||
self.filter.addFailRegex("(?:(?:Authentication failure|Failed [-/\w+]+) for(?: [iI](?:llegal|nvalid) user)?|[Ii](?:llegal|nvalid) user|ROOT LOGIN REFUSED) .*(?: from|FROM) <HOST>")
|
self.filter.addFailRegex("(?:(?:Authentication failure|Failed [-/\w+]+) for(?: [iI](?:llegal|nvalid) user)?|[Ii](?:llegal|nvalid) user|ROOT LOGIN REFUSED) .*(?: from|FROM) <HOST>")
|
||||||
self.filter.start()
|
self.filter.start()
|
||||||
|
|
||||||
|
@ -804,7 +804,7 @@ class GetFailures(unittest.TestCase):
|
||||||
setUpMyTime()
|
setUpMyTime()
|
||||||
self.jail = DummyJail()
|
self.jail = DummyJail()
|
||||||
self.filter = FileFilter(self.jail)
|
self.filter = FileFilter(self.jail)
|
||||||
self.filter.setActive(True)
|
self.filter.active = True
|
||||||
# TODO Test this
|
# TODO Test this
|
||||||
#self.filter.setTimeRegex("\S{3}\s{1,2}\d{1,2} \d{2}:\d{2}:\d{2}")
|
#self.filter.setTimeRegex("\S{3}\s{1,2}\d{1,2} \d{2}:\d{2}:\d{2}")
|
||||||
#self.filter.setTimePattern("%b %d %H:%M:%S")
|
#self.filter.setTimePattern("%b %d %H:%M:%S")
|
||||||
|
@ -895,7 +895,7 @@ class GetFailures(unittest.TestCase):
|
||||||
('warn', output_yes)):
|
('warn', output_yes)):
|
||||||
jail = DummyJail()
|
jail = DummyJail()
|
||||||
filter_ = FileFilter(jail, useDns=useDns)
|
filter_ = FileFilter(jail, useDns=useDns)
|
||||||
filter_.setActive(True)
|
filter_.active = True
|
||||||
filter_.failManager.setMaxRetry(1) # we might have just few failures
|
filter_.failManager.setMaxRetry(1) # we might have just few failures
|
||||||
|
|
||||||
filter_.addLogPath(GetFailures.FILENAME_USEDNS)
|
filter_.addLogPath(GetFailures.FILENAME_USEDNS)
|
||||||
|
|
|
@ -45,7 +45,7 @@ class FilterSamplesRegex(unittest.TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
"""Call before every test case."""
|
"""Call before every test case."""
|
||||||
self.filter = Filter(None)
|
self.filter = Filter(None)
|
||||||
self.filter.setActive(True)
|
self.filter.active = True
|
||||||
|
|
||||||
setUpMyTime()
|
setUpMyTime()
|
||||||
|
|
||||||
|
|
|
@ -227,8 +227,7 @@ class Transmitter(TransmitterBase):
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.transm.proceed(["stop", self.jailName]), (0, None))
|
self.transm.proceed(["stop", self.jailName]), (0, None))
|
||||||
self.assertRaises(
|
self.assertTrue(self.jailName not in self.server._Server__jails)
|
||||||
UnknownJailException, self.server.isAlive, self.jailName)
|
|
||||||
|
|
||||||
def testStartStopAllJail(self):
|
def testStartStopAllJail(self):
|
||||||
self.server.addJail("TestJail2", "auto")
|
self.server.addJail("TestJail2", "auto")
|
||||||
|
@ -242,10 +241,8 @@ class Transmitter(TransmitterBase):
|
||||||
time.sleep(0.1)
|
time.sleep(0.1)
|
||||||
self.assertEqual(self.transm.proceed(["stop", "all"]), (0, None))
|
self.assertEqual(self.transm.proceed(["stop", "all"]), (0, None))
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
self.assertRaises(
|
self.assertTrue(self.jailName not in self.server._Server__jails)
|
||||||
UnknownJailException, self.server.isAlive, self.jailName)
|
self.assertTrue("TestJail2" not in self.server._Server__jails)
|
||||||
self.assertRaises(
|
|
||||||
UnknownJailException, self.server.isAlive, "TestJail2")
|
|
||||||
|
|
||||||
def testJailIdle(self):
|
def testJailIdle(self):
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
|
@ -482,15 +479,15 @@ class Transmitter(TransmitterBase):
|
||||||
self.assertEqual(self.transm.proceed(["status", self.jailName]),
|
self.assertEqual(self.transm.proceed(["status", self.jailName]),
|
||||||
(0,
|
(0,
|
||||||
[
|
[
|
||||||
('filter', [
|
('Filter', [
|
||||||
('Currently failed', 0),
|
('Currently failed', 0),
|
||||||
('Total failed', 0),
|
('Total failed', 0),
|
||||||
('File list', [])]
|
('File list', [])]
|
||||||
),
|
),
|
||||||
('action', [
|
('Actions', [
|
||||||
('Currently banned', 0),
|
('Currently banned', 0),
|
||||||
('Total banned', 0),
|
('Total banned', 0),
|
||||||
('IP list', [])]
|
('Banned IP list', [])]
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
@ -774,7 +771,7 @@ class JailTests(unittest.TestCase):
|
||||||
# Just a smoke test for now
|
# Just a smoke test for now
|
||||||
longname = "veryveryverylongname"
|
longname = "veryveryverylongname"
|
||||||
jail = Jail(longname)
|
jail = Jail(longname)
|
||||||
self.assertEqual(jail.getName(), longname)
|
self.assertEqual(jail.name, longname)
|
||||||
|
|
||||||
class RegexTests(unittest.TestCase):
|
class RegexTests(unittest.TestCase):
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue