ENH: Database now optional, by setting dbfile to "None"

pull/480/head
Steven Hiscocks 2013-12-10 21:16:36 +00:00
parent 174f9a243a
commit e18af48e34
11 changed files with 85 additions and 43 deletions

View File

@ -49,9 +49,10 @@ pidfile = /var/run/fail2ban/fail2ban.pid
# Options: dbfile
# Notes.: Set the file for the fail2ban persistent data to be stored.
# A value of :memory: means database is only stored in memory, and
# data is lost once fail2ban is stops.
# Values: [ FILE ] :memory: Default: /var/lib/fail2ban/fail2ban.sqlite3
# A value of ":memory:" means database is only stored in memory
# and data is lost once fail2ban is stops.
# A value of "None" disables the database.
# Values: [ None :memory: FILE ] Default: /var/lib/fail2ban/fail2ban.sqlite3
dbfile = /var/lib/fail2ban/fail2ban.sqlite3
# Options: dbpurgeage

View File

@ -103,11 +103,17 @@ class Beautifier:
else:
msg = msg + `response`
elif inC[1] == "dbfile":
msg = "Current database file is:\n"
msg = msg + "`- " + response
if response is None:
msg = "Database currently disabled"
else:
msg = "Current database file is:\n"
msg = msg + "`- " + response
elif inC[1] == "dbpurgeage":
msg = "Current database purge age is:\n"
msg = msg + "`- %iseconds" % response
if response is None:
msg = "Database currently disabled"
else:
msg = "Current database purge age is:\n"
msg = msg + "`- %iseconds" % response
elif inC[2] in ("logpath", "addlogpath", "dellogpath"):
if len(response) == 0:
msg = "No file is currently monitored"

View File

@ -44,7 +44,7 @@ protocol = [
["set logtarget <TARGET>", "sets logging target to <TARGET>. Can be STDOUT, STDERR, SYSLOG or a file"],
["get logtarget", "gets logging target"],
['', "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"],
["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"],

View File

@ -527,9 +527,11 @@ class FileFilter(Filter):
logSys.error(path + " already exists")
else:
container = FileContainer(path, self.getLogEncoding(), tail)
lastpos = self.jail.getDatabase().addLog(self.jail, container)
if lastpos and not tail:
container.setPos(lastpos)
db = self.jail.getDatabase()
if db is not None:
lastpos = db.addLog(self.jail, container)
if lastpos and not tail:
container.setPos(lastpos)
self.__logPath.append(container)
logSys.info("Added logfile = %s" % path)
self._addLogPath(path) # backend specific
@ -549,7 +551,9 @@ class FileFilter(Filter):
for log in self.__logPath:
if log.getFileName() == path:
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)
self._delLogPath(path)
return
@ -648,7 +652,9 @@ class FileFilter(Filter):
break
self.processLineAndAdd(line)
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
def status(self):

View File

@ -37,7 +37,7 @@ class Jail:
# list had .index until 2.6
_BACKENDS = ['pyinotify', 'gamin', 'polling', 'systemd']
def __init__(self, db, name, backend = "auto"):
def __init__(self, name, backend = "auto", db=None):
self.__db = db
self.setName(name)
self.__queue = Queue.Queue()
@ -130,7 +130,8 @@ class Jail:
def putFailTicket(self, ticket):
self.__queue.put(ticket)
self.__db.addBan(self, ticket)
if self.__db is not None:
self.__db.addBan(self, ticket)
def getFailTicket(self):
try:
@ -142,8 +143,9 @@ class Jail:
self.__filter.start()
self.__action.start()
# Restore any previous valid bans from the database
for ticket in self.__db.getBans(self, self.__action.getBanTime()):
self.__queue.put(ticket)
if self.__db is not None:
for ticket in self.__db.getBans(self, self.__action.getBanTime()):
self.__queue.put(ticket)
logSys.info("Jail '%s' started" % self.__name)
def stop(self):

View File

@ -50,13 +50,13 @@ class Jails:
# @param name The name of the jail
# @param backend The backend to use
def add(self, db, name, backend):
def add(self, name, backend, db=None):
try:
self.__lock.acquire()
if self.__jails.has_key(name):
raise DuplicateJailException(name)
else:
self.__jails[name] = Jail(db, name, backend)
self.__jails[name] = Jail(name, backend, db=None)
finally:
self.__lock.release()

View File

@ -43,6 +43,7 @@ class Server:
self.__loggingLock = Lock()
self.__lock = RLock()
self.__jails = Jails()
self.__db = None
self.__daemon = daemon
self.__transm = Transmitter(self)
self.__asyncServer = AsyncServer(self.__transm)
@ -51,9 +52,6 @@ class Server:
# Set logging level
self.setLogLevel(3)
self.setLogTarget("STDOUT")
# Create database, initially in memory
self.setDatabase(":memory:")
def __sigTERMhandler(self, signum, frame):
logSys.debug("Caught signal %d. Exiting" % signum)
@ -121,12 +119,14 @@ class Server:
def addJail(self, name, backend):
self.__jails.add(self.__db, name, backend)
self.__db.addJail(self.__jails.get(name))
self.__jails.add(name, backend, self.__db)
if self.__db is not None:
self.__db.addJail(self.__jails.get(name))
def delJail(self, name):
self.__jails.remove(name)
self.__db.delJailName(name)
if self.__db is not None:
self.__db.delJailName(name)
def startJail(self, name):
try:
@ -468,8 +468,11 @@ class Server:
def setDatabase(self, filename):
if self.__jails.size() == 0:
self.__db = Fail2BanDb(filename)
self.__db.delAllJails()
if filename.lower() == "none":
self.__db = None
else:
self.__db = Fail2BanDb(filename)
self.__db.delAllJails()
else:
raise RuntimeError(
"Cannot change database when there are jails present")

View File

@ -116,10 +116,18 @@ class Transmitter:
#Database
elif name == "dbfile":
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":
self.__server.getDatabase().setPurgeAge(command[1])
return self.__server.getDatabase().getPurgeAge()
db = self.__server.getDatabase()
if db is None:
return None
else:
db.setPurgeAge(command[1])
return db.getPurgeAge()
# Jail
elif command[1] == "idle":
if command[2] == "on":
@ -266,9 +274,17 @@ class Transmitter:
return self.__server.getLogTarget()
#Database
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":
return self.__server.getDatabase().getPurgeAge()
db = self.__server.getDatabase()
if db is None:
return None
else:
return db.getPurgeAge()
# Filter
elif command[1] == "logpath":
return self.__server.getLogPath(name)

View File

@ -24,16 +24,12 @@ __license__ = "GPL"
from threading import Lock
from fail2ban.server.database import Fail2BanDb
class DummyJail(object):
"""A simple 'jail' to suck in all the tickets generated by Filter's
"""
def __init__(self):
self.lock = Lock()
self.queue = []
self.__db = Fail2BanDb(":memory:")
self.__db.addJail(self)
def __len__(self):
try:
@ -69,5 +65,5 @@ class DummyJail(object):
return "DummyJail #%s with %d tickets" % (id(self), len(self))
def getDatabase(self):
return self.__db
return None

View File

@ -40,7 +40,6 @@ from fail2ban.server.filter import FileFilter, DNSUtils
from fail2ban.server.failmanager import FailManager
from fail2ban.server.failmanager import FailManagerEmpty
from fail2ban.server.mytime import MyTime
from fail2ban.server.database import Fail2BanDb
from fail2ban.tests.utils import setUpMyTime, tearDownMyTime
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
#_copy_lines_between_files(GetFailures.FILENAME_01, self.name, n=100)
# 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
_copy_lines_between_files(GetFailures.FILENAME_01, self.file, n=100)
@ -920,5 +919,5 @@ class JailTests(unittest.TestCase):
def testSetBackend_gh83(self):
# smoke test
# Must not fail to initiate
jail = Jail(Fail2BanDb(":memory:"), 'test', backend='polling')
jail = Jail('test', backend='polling')

View File

@ -28,7 +28,6 @@ import unittest, socket, time, tempfile, os, locale, sys
from fail2ban.server.server import Server
from fail2ban.server.jail import Jail
from fail2ban.server.database import Fail2BanDb
from fail2ban.exceptions import UnknownJailException
try:
from fail2ban.server import filtersystemd
@ -175,9 +174,23 @@ class Transmitter(TransmitterBase):
self.setGetTestNOK("dbfile", tmpFilename)
self.server.delJail(self.jailName)
self.setGetTest("dbfile", tmpFilename)
self.setGetTest("dbpurgeage", 600)
self.setGetTest("dbpurgeage", "600", 600)
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):
jail2 = "TestJail2"
jail3 = "TestJail3"
@ -651,5 +664,5 @@ class JailTests(unittest.TestCase):
def testLongName(self):
# Just a smoke test for now
longname = "veryveryverylongname"
jail = Jail(Fail2BanDb(":memory:"), longname)
jail = Jail(longname)
self.assertEqual(jail.getName(), longname)