mirror of https://github.com/fail2ban/fail2ban
ENH: Database now optional, by setting dbfile to "None"
parent
174f9a243a
commit
e18af48e34
|
@ -49,9 +49,10 @@ pidfile = /var/run/fail2ban/fail2ban.pid
|
||||||
|
|
||||||
# Options: dbfile
|
# Options: dbfile
|
||||||
# Notes.: Set the file for the fail2ban persistent data to be stored.
|
# Notes.: Set the file for the fail2ban persistent data to be stored.
|
||||||
# A value of :memory: means database is only stored in memory, and
|
# A value of ":memory:" means database is only stored in memory
|
||||||
# data is lost once fail2ban is stops.
|
# and data is lost once fail2ban is stops.
|
||||||
# Values: [ FILE ] :memory: Default: /var/lib/fail2ban/fail2ban.sqlite3
|
# A value of "None" disables the database.
|
||||||
|
# Values: [ None :memory: FILE ] Default: /var/lib/fail2ban/fail2ban.sqlite3
|
||||||
dbfile = /var/lib/fail2ban/fail2ban.sqlite3
|
dbfile = /var/lib/fail2ban/fail2ban.sqlite3
|
||||||
|
|
||||||
# Options: dbpurgeage
|
# Options: dbpurgeage
|
||||||
|
|
|
@ -103,11 +103,17 @@ class Beautifier:
|
||||||
else:
|
else:
|
||||||
msg = msg + `response`
|
msg = msg + `response`
|
||||||
elif inC[1] == "dbfile":
|
elif inC[1] == "dbfile":
|
||||||
msg = "Current database file is:\n"
|
if response is None:
|
||||||
msg = msg + "`- " + response
|
msg = "Database currently disabled"
|
||||||
|
else:
|
||||||
|
msg = "Current database file is:\n"
|
||||||
|
msg = msg + "`- " + response
|
||||||
elif inC[1] == "dbpurgeage":
|
elif inC[1] == "dbpurgeage":
|
||||||
msg = "Current database purge age is:\n"
|
if response is None:
|
||||||
msg = msg + "`- %iseconds" % response
|
msg = "Database currently disabled"
|
||||||
|
else:
|
||||||
|
msg = "Current database purge age is:\n"
|
||||||
|
msg = msg + "`- %iseconds" % response
|
||||||
elif inC[2] in ("logpath", "addlogpath", "dellogpath"):
|
elif inC[2] in ("logpath", "addlogpath", "dellogpath"):
|
||||||
if len(response) == 0:
|
if len(response) == 0:
|
||||||
msg = "No file is currently monitored"
|
msg = "No file is currently monitored"
|
||||||
|
|
|
@ -44,7 +44,7 @@ protocol = [
|
||||||
["set logtarget <TARGET>", "sets logging target to <TARGET>. Can be STDOUT, STDERR, SYSLOG or a file"],
|
["set logtarget <TARGET>", "sets logging target to <TARGET>. Can be STDOUT, STDERR, SYSLOG or a file"],
|
||||||
["get logtarget", "gets logging target"],
|
["get logtarget", "gets logging target"],
|
||||||
['', "DATABASE", ""],
|
['', "DATABASE", ""],
|
||||||
["set dbfile <FILE>", "set the location of fail2ban persistent datastore"],
|
["set dbfile <FILE>", "set the location of fail2ban persistent datastore. Set to \"None\" to disable"],
|
||||||
["get dbfile", "get the location of fail2ban persistent datastore"],
|
["get dbfile", "get the location of fail2ban persistent datastore"],
|
||||||
["set dbpurgeage <SECONDS>", "sets the max age in <SECONDS> that history of bans will be kept"],
|
["set dbpurgeage <SECONDS>", "sets the max age in <SECONDS> that history of bans will be kept"],
|
||||||
["get dbpurgeage", "gets the max age in seconds that history of bans will be kept"],
|
["get dbpurgeage", "gets the max age in seconds that history of bans will be kept"],
|
||||||
|
|
|
@ -527,9 +527,11 @@ 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)
|
||||||
lastpos = self.jail.getDatabase().addLog(self.jail, container)
|
db = self.jail.getDatabase()
|
||||||
if lastpos and not tail:
|
if db is not None:
|
||||||
container.setPos(lastpos)
|
lastpos = db.addLog(self.jail, container)
|
||||||
|
if lastpos and not tail:
|
||||||
|
container.setPos(lastpos)
|
||||||
self.__logPath.append(container)
|
self.__logPath.append(container)
|
||||||
logSys.info("Added logfile = %s" % path)
|
logSys.info("Added logfile = %s" % path)
|
||||||
self._addLogPath(path) # backend specific
|
self._addLogPath(path) # backend specific
|
||||||
|
@ -549,7 +551,9 @@ 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)
|
||||||
self.jail.getDatabase().updateLog(self.jail, log)
|
db = self.jail.getDatabase()
|
||||||
|
if db is not None:
|
||||||
|
db.updateLog(self.jail, log)
|
||||||
logSys.info("Removed logfile = %s" % path)
|
logSys.info("Removed logfile = %s" % path)
|
||||||
self._delLogPath(path)
|
self._delLogPath(path)
|
||||||
return
|
return
|
||||||
|
@ -648,7 +652,9 @@ class FileFilter(Filter):
|
||||||
break
|
break
|
||||||
self.processLineAndAdd(line)
|
self.processLineAndAdd(line)
|
||||||
container.close()
|
container.close()
|
||||||
self.jail.getDatabase().updateLog(self.jail, container)
|
db = self.jail.getDatabase()
|
||||||
|
if db is not None:
|
||||||
|
db.updateLog(self.jail, container)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def status(self):
|
def status(self):
|
||||||
|
|
|
@ -37,7 +37,7 @@ class Jail:
|
||||||
# list had .index until 2.6
|
# list had .index until 2.6
|
||||||
_BACKENDS = ['pyinotify', 'gamin', 'polling', 'systemd']
|
_BACKENDS = ['pyinotify', 'gamin', 'polling', 'systemd']
|
||||||
|
|
||||||
def __init__(self, db, name, backend = "auto"):
|
def __init__(self, name, backend = "auto", db=None):
|
||||||
self.__db = db
|
self.__db = db
|
||||||
self.setName(name)
|
self.setName(name)
|
||||||
self.__queue = Queue.Queue()
|
self.__queue = Queue.Queue()
|
||||||
|
@ -130,7 +130,8 @@ class Jail:
|
||||||
|
|
||||||
def putFailTicket(self, ticket):
|
def putFailTicket(self, ticket):
|
||||||
self.__queue.put(ticket)
|
self.__queue.put(ticket)
|
||||||
self.__db.addBan(self, ticket)
|
if self.__db is not None:
|
||||||
|
self.__db.addBan(self, ticket)
|
||||||
|
|
||||||
def getFailTicket(self):
|
def getFailTicket(self):
|
||||||
try:
|
try:
|
||||||
|
@ -142,8 +143,9 @@ class Jail:
|
||||||
self.__filter.start()
|
self.__filter.start()
|
||||||
self.__action.start()
|
self.__action.start()
|
||||||
# Restore any previous valid bans from the database
|
# Restore any previous valid bans from the database
|
||||||
for ticket in self.__db.getBans(self, self.__action.getBanTime()):
|
if self.__db is not None:
|
||||||
self.__queue.put(ticket)
|
for ticket in self.__db.getBans(self, self.__action.getBanTime()):
|
||||||
|
self.__queue.put(ticket)
|
||||||
logSys.info("Jail '%s' started" % self.__name)
|
logSys.info("Jail '%s' started" % self.__name)
|
||||||
|
|
||||||
def stop(self):
|
def stop(self):
|
||||||
|
|
|
@ -50,13 +50,13 @@ class Jails:
|
||||||
# @param name The name of the jail
|
# @param name The name of the jail
|
||||||
# @param backend The backend to use
|
# @param backend The backend to use
|
||||||
|
|
||||||
def add(self, db, name, backend):
|
def add(self, name, backend, db=None):
|
||||||
try:
|
try:
|
||||||
self.__lock.acquire()
|
self.__lock.acquire()
|
||||||
if self.__jails.has_key(name):
|
if self.__jails.has_key(name):
|
||||||
raise DuplicateJailException(name)
|
raise DuplicateJailException(name)
|
||||||
else:
|
else:
|
||||||
self.__jails[name] = Jail(db, name, backend)
|
self.__jails[name] = Jail(name, backend, db=None)
|
||||||
finally:
|
finally:
|
||||||
self.__lock.release()
|
self.__lock.release()
|
||||||
|
|
||||||
|
|
|
@ -43,6 +43,7 @@ class Server:
|
||||||
self.__loggingLock = Lock()
|
self.__loggingLock = Lock()
|
||||||
self.__lock = RLock()
|
self.__lock = RLock()
|
||||||
self.__jails = Jails()
|
self.__jails = Jails()
|
||||||
|
self.__db = None
|
||||||
self.__daemon = daemon
|
self.__daemon = daemon
|
||||||
self.__transm = Transmitter(self)
|
self.__transm = Transmitter(self)
|
||||||
self.__asyncServer = AsyncServer(self.__transm)
|
self.__asyncServer = AsyncServer(self.__transm)
|
||||||
|
@ -51,9 +52,6 @@ class Server:
|
||||||
# Set logging level
|
# Set logging level
|
||||||
self.setLogLevel(3)
|
self.setLogLevel(3)
|
||||||
self.setLogTarget("STDOUT")
|
self.setLogTarget("STDOUT")
|
||||||
|
|
||||||
# Create database, initially in memory
|
|
||||||
self.setDatabase(":memory:")
|
|
||||||
|
|
||||||
def __sigTERMhandler(self, signum, frame):
|
def __sigTERMhandler(self, signum, frame):
|
||||||
logSys.debug("Caught signal %d. Exiting" % signum)
|
logSys.debug("Caught signal %d. Exiting" % signum)
|
||||||
|
@ -121,12 +119,14 @@ class Server:
|
||||||
|
|
||||||
|
|
||||||
def addJail(self, name, backend):
|
def addJail(self, name, backend):
|
||||||
self.__jails.add(self.__db, name, backend)
|
self.__jails.add(name, backend, self.__db)
|
||||||
self.__db.addJail(self.__jails.get(name))
|
if self.__db is not None:
|
||||||
|
self.__db.addJail(self.__jails.get(name))
|
||||||
|
|
||||||
def delJail(self, name):
|
def delJail(self, name):
|
||||||
self.__jails.remove(name)
|
self.__jails.remove(name)
|
||||||
self.__db.delJailName(name)
|
if self.__db is not None:
|
||||||
|
self.__db.delJailName(name)
|
||||||
|
|
||||||
def startJail(self, name):
|
def startJail(self, name):
|
||||||
try:
|
try:
|
||||||
|
@ -468,8 +468,11 @@ class Server:
|
||||||
|
|
||||||
def setDatabase(self, filename):
|
def setDatabase(self, filename):
|
||||||
if self.__jails.size() == 0:
|
if self.__jails.size() == 0:
|
||||||
self.__db = Fail2BanDb(filename)
|
if filename.lower() == "none":
|
||||||
self.__db.delAllJails()
|
self.__db = None
|
||||||
|
else:
|
||||||
|
self.__db = Fail2BanDb(filename)
|
||||||
|
self.__db.delAllJails()
|
||||||
else:
|
else:
|
||||||
raise RuntimeError(
|
raise RuntimeError(
|
||||||
"Cannot change database when there are jails present")
|
"Cannot change database when there are jails present")
|
||||||
|
|
|
@ -116,10 +116,18 @@ class Transmitter:
|
||||||
#Database
|
#Database
|
||||||
elif name == "dbfile":
|
elif name == "dbfile":
|
||||||
self.__server.setDatabase(command[1])
|
self.__server.setDatabase(command[1])
|
||||||
return self.__server.getDatabase().getFilename()
|
db = self.__server.getDatabase()
|
||||||
|
if db is None:
|
||||||
|
return None
|
||||||
|
else:
|
||||||
|
return db.getFilename()
|
||||||
elif name == "dbpurgeage":
|
elif name == "dbpurgeage":
|
||||||
self.__server.getDatabase().setPurgeAge(command[1])
|
db = self.__server.getDatabase()
|
||||||
return self.__server.getDatabase().getPurgeAge()
|
if db is None:
|
||||||
|
return None
|
||||||
|
else:
|
||||||
|
db.setPurgeAge(command[1])
|
||||||
|
return db.getPurgeAge()
|
||||||
# Jail
|
# Jail
|
||||||
elif command[1] == "idle":
|
elif command[1] == "idle":
|
||||||
if command[2] == "on":
|
if command[2] == "on":
|
||||||
|
@ -266,9 +274,17 @@ class Transmitter:
|
||||||
return self.__server.getLogTarget()
|
return self.__server.getLogTarget()
|
||||||
#Database
|
#Database
|
||||||
elif name == "dbfile":
|
elif name == "dbfile":
|
||||||
return self.__server.getDatabase().getFilename()
|
db = self.__server.getDatabase()
|
||||||
|
if db is None:
|
||||||
|
return None
|
||||||
|
else:
|
||||||
|
return db.getFilename()
|
||||||
elif name == "dbpurgeage":
|
elif name == "dbpurgeage":
|
||||||
return self.__server.getDatabase().getPurgeAge()
|
db = self.__server.getDatabase()
|
||||||
|
if db is None:
|
||||||
|
return None
|
||||||
|
else:
|
||||||
|
return db.getPurgeAge()
|
||||||
# Filter
|
# Filter
|
||||||
elif command[1] == "logpath":
|
elif command[1] == "logpath":
|
||||||
return self.__server.getLogPath(name)
|
return self.__server.getLogPath(name)
|
||||||
|
|
|
@ -24,16 +24,12 @@ __license__ = "GPL"
|
||||||
|
|
||||||
from threading import Lock
|
from threading import Lock
|
||||||
|
|
||||||
from fail2ban.server.database import Fail2BanDb
|
|
||||||
|
|
||||||
class DummyJail(object):
|
class DummyJail(object):
|
||||||
"""A simple 'jail' to suck in all the tickets generated by Filter's
|
"""A simple 'jail' to suck in all the tickets generated by Filter's
|
||||||
"""
|
"""
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.lock = Lock()
|
self.lock = Lock()
|
||||||
self.queue = []
|
self.queue = []
|
||||||
self.__db = Fail2BanDb(":memory:")
|
|
||||||
self.__db.addJail(self)
|
|
||||||
|
|
||||||
def __len__(self):
|
def __len__(self):
|
||||||
try:
|
try:
|
||||||
|
@ -69,5 +65,5 @@ class DummyJail(object):
|
||||||
return "DummyJail #%s with %d tickets" % (id(self), len(self))
|
return "DummyJail #%s with %d tickets" % (id(self), len(self))
|
||||||
|
|
||||||
def getDatabase(self):
|
def getDatabase(self):
|
||||||
return self.__db
|
return None
|
||||||
|
|
||||||
|
|
|
@ -40,7 +40,6 @@ from fail2ban.server.filter import FileFilter, DNSUtils
|
||||||
from fail2ban.server.failmanager import FailManager
|
from fail2ban.server.failmanager import FailManager
|
||||||
from fail2ban.server.failmanager import FailManagerEmpty
|
from fail2ban.server.failmanager import FailManagerEmpty
|
||||||
from fail2ban.server.mytime import MyTime
|
from fail2ban.server.mytime import MyTime
|
||||||
from fail2ban.server.database import Fail2BanDb
|
|
||||||
from fail2ban.tests.utils import setUpMyTime, tearDownMyTime
|
from fail2ban.tests.utils import setUpMyTime, tearDownMyTime
|
||||||
|
|
||||||
TEST_FILES_DIR = os.path.join(os.path.dirname(__file__), "files")
|
TEST_FILES_DIR = os.path.join(os.path.dirname(__file__), "files")
|
||||||
|
@ -565,7 +564,7 @@ def get_monitor_failures_testcase(Filter_):
|
||||||
# tail written before, so let's not copy anything yet
|
# tail written before, so let's not copy anything yet
|
||||||
#_copy_lines_between_files(GetFailures.FILENAME_01, self.name, n=100)
|
#_copy_lines_between_files(GetFailures.FILENAME_01, self.name, n=100)
|
||||||
# we should detect the failures
|
# we should detect the failures
|
||||||
self.assert_correct_last_attempt(GetFailures.FAILURES_01, count=3) # was needed if we write twice above
|
self.assert_correct_last_attempt(GetFailures.FAILURES_01, count=6) # was needed if we write twice above
|
||||||
|
|
||||||
# now copy and get even more
|
# now copy and get even more
|
||||||
_copy_lines_between_files(GetFailures.FILENAME_01, self.file, n=100)
|
_copy_lines_between_files(GetFailures.FILENAME_01, self.file, n=100)
|
||||||
|
@ -920,5 +919,5 @@ class JailTests(unittest.TestCase):
|
||||||
def testSetBackend_gh83(self):
|
def testSetBackend_gh83(self):
|
||||||
# smoke test
|
# smoke test
|
||||||
# Must not fail to initiate
|
# Must not fail to initiate
|
||||||
jail = Jail(Fail2BanDb(":memory:"), 'test', backend='polling')
|
jail = Jail('test', backend='polling')
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,6 @@ import unittest, socket, time, tempfile, os, locale, sys
|
||||||
|
|
||||||
from fail2ban.server.server import Server
|
from fail2ban.server.server import Server
|
||||||
from fail2ban.server.jail import Jail
|
from fail2ban.server.jail import Jail
|
||||||
from fail2ban.server.database import Fail2BanDb
|
|
||||||
from fail2ban.exceptions import UnknownJailException
|
from fail2ban.exceptions import UnknownJailException
|
||||||
try:
|
try:
|
||||||
from fail2ban.server import filtersystemd
|
from fail2ban.server import filtersystemd
|
||||||
|
@ -175,9 +174,23 @@ class Transmitter(TransmitterBase):
|
||||||
self.setGetTestNOK("dbfile", tmpFilename)
|
self.setGetTestNOK("dbfile", tmpFilename)
|
||||||
self.server.delJail(self.jailName)
|
self.server.delJail(self.jailName)
|
||||||
self.setGetTest("dbfile", tmpFilename)
|
self.setGetTest("dbfile", tmpFilename)
|
||||||
self.setGetTest("dbpurgeage", 600)
|
self.setGetTest("dbpurgeage", "600", 600)
|
||||||
self.setGetTestNOK("dbpurgeage", "LIZARD")
|
self.setGetTestNOK("dbpurgeage", "LIZARD")
|
||||||
|
|
||||||
|
# Disable database
|
||||||
|
self.assertEqual(self.transm.proceed(
|
||||||
|
["set", "dbfile", "None"]),
|
||||||
|
(0, None))
|
||||||
|
self.assertEqual(self.transm.proceed(
|
||||||
|
["get", "dbfile"]),
|
||||||
|
(0, None))
|
||||||
|
self.assertEqual(self.transm.proceed(
|
||||||
|
["set", "dbpurgeage", "500"]),
|
||||||
|
(0, None))
|
||||||
|
self.assertEqual(self.transm.proceed(
|
||||||
|
["get", "dbpurgeage"]),
|
||||||
|
(0, None))
|
||||||
|
|
||||||
def testAddJail(self):
|
def testAddJail(self):
|
||||||
jail2 = "TestJail2"
|
jail2 = "TestJail2"
|
||||||
jail3 = "TestJail3"
|
jail3 = "TestJail3"
|
||||||
|
@ -651,5 +664,5 @@ class JailTests(unittest.TestCase):
|
||||||
def testLongName(self):
|
def testLongName(self):
|
||||||
# Just a smoke test for now
|
# Just a smoke test for now
|
||||||
longname = "veryveryverylongname"
|
longname = "veryveryverylongname"
|
||||||
jail = Jail(Fail2BanDb(":memory:"), longname)
|
jail = Jail(longname)
|
||||||
self.assertEqual(jail.getName(), longname)
|
self.assertEqual(jail.getName(), longname)
|
||||||
|
|
Loading…
Reference in New Issue