Configure Syslog Socket Path

pull/949/head
Lee Clemens 2015-02-05 23:44:57 -05:00
parent 40068f5f31
commit 445fd7367f
8 changed files with 75 additions and 8 deletions

View File

@ -34,6 +34,11 @@ loglevel = INFO
# #
logtarget = /var/log/fail2ban.log logtarget = /var/log/fail2ban.log
# Option: syslogsocket
# Notes: Set the syslog socket file. Only used when logtarget is SYSLOG
# Values: [ FILE ] Default: /dev/log
syslogsocket = /dev/log
# Option: socket # Option: socket
# Notes.: Set the socket file. This is used to communicate with the daemon. Do # Notes.: Set the socket file. This is used to communicate with the daemon. Do
# not remove this file when Fail2ban runs. It will not be possible to # not remove this file when Fail2ban runs. It will not be possible to

View File

@ -85,6 +85,9 @@ class Beautifier:
val = " ".join(res1[1]) if isinstance(res1[1], list) else res1[1] val = " ".join(res1[1]) if isinstance(res1[1], list) else res1[1]
msg.append("%s %s:\t%s" % (prefix1, res1[0], val)) msg.append("%s %s:\t%s" % (prefix1, res1[0], val))
msg = "\n".join(msg) msg = "\n".join(msg)
elif inC[1] == "syslogsocket":
msg = "Current syslog socket is:\n"
msg = msg + "`- " + response
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

View File

@ -46,6 +46,7 @@ class Fail2banReader(ConfigReader):
def getOptions(self): def getOptions(self):
opts = [["string", "loglevel", "INFO" ], opts = [["string", "loglevel", "INFO" ],
["string", "logtarget", "STDERR"], ["string", "logtarget", "STDERR"],
["string", "syslogsocket", "/dev/log"],
["string", "dbfile", "/var/lib/fail2ban/fail2ban.sqlite3"], ["string", "dbfile", "/var/lib/fail2ban/fail2ban.sqlite3"],
["int", "dbpurgeage", 86400]] ["int", "dbpurgeage", 86400]]
self.__opts = ConfigReader.getOptions(self, "Definition", opts) self.__opts = ConfigReader.getOptions(self, "Definition", opts)
@ -57,6 +58,8 @@ class Fail2banReader(ConfigReader):
stream.append(["set", "loglevel", self.__opts[opt]]) stream.append(["set", "loglevel", self.__opts[opt]])
elif opt == "logtarget": elif opt == "logtarget":
stream.append(["set", "logtarget", self.__opts[opt]]) stream.append(["set", "logtarget", self.__opts[opt]])
elif opt == "syslogsocket":
stream.append(["set", "syslogsocket", self.__opts[opt]])
elif opt == "dbfile": elif opt == "dbfile":
stream.append(["set", "dbfile", self.__opts[opt]]) stream.append(["set", "dbfile", self.__opts[opt]])
elif opt == "dbpurgeage": elif opt == "dbpurgeage":

View File

@ -44,6 +44,8 @@ protocol = [
["get loglevel", "gets the logging level"], ["get loglevel", "gets the logging level"],
["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"],
["set syslogsocket <SOCKET>", "sets the syslog socket path to <SOCKET>. Only used if logtarget is SYSLOG"],
["get syslogsocket", "gets syslog socket path"],
["flushlogs", "flushes the logtarget if a file and reopens it. For log rotation."], ["flushlogs", "flushes the logtarget if a file and reopens it. For log rotation."],
['', "DATABASE", ""], ['', "DATABASE", ""],
["set dbfile <FILE>", "set the location of fail2ban persistent datastore. Set to \"None\" to disable"], ["set dbfile <FILE>", "set the location of fail2ban persistent datastore. Set to \"None\" to disable"],

View File

@ -25,7 +25,7 @@ __copyright__ = "Copyright (c) 2004 Cyril Jaquier"
__license__ = "GPL" __license__ = "GPL"
from threading import Lock, RLock from threading import Lock, RLock
import logging, logging.handlers, sys, os, signal import logging, logging.handlers, sys, os, signal, stat
from .jails import Jails from .jails import Jails
from .filter import FileFilter, JournalFilter from .filter import FileFilter, JournalFilter
@ -55,10 +55,12 @@ class Server:
self.__asyncServer = AsyncServer(self.__transm) self.__asyncServer = AsyncServer(self.__transm)
self.__logLevel = None self.__logLevel = None
self.__logTarget = None self.__logTarget = None
self.__syslogSocket = None
# Set logging level # Set logging level
self.setLogLevel("INFO") self.setLogLevel("INFO")
self.setLogTarget("STDOUT") self.setLogTarget("STDOUT")
self.setSyslogSocket("/dev/log")
def __sigTERMhandler(self, signum, frame): def __sigTERMhandler(self, signum, frame):
logSys.debug("Caught signal %d. Exiting" % signum) logSys.debug("Caught signal %d. Exiting" % signum)
self.quit() self.quit()
@ -376,7 +378,16 @@ class Server:
# Syslog daemons already add date to the message. # Syslog daemons already add date to the message.
formatter = logging.Formatter("%(name)s[%(process)d]: %(levelname)s %(message)s") formatter = logging.Formatter("%(name)s[%(process)d]: %(levelname)s %(message)s")
facility = logging.handlers.SysLogHandler.LOG_DAEMON facility = logging.handlers.SysLogHandler.LOG_DAEMON
hdlr = logging.handlers.SysLogHandler("/dev/log", facility=facility) if os.path.exists(self.__syslogSocket)\
and stat.S_ISSOCK(os.stat(
self.__syslogSocket).st_mode):
hdlr = logging.handlers.SysLogHandler(
self.__syslogSocket, facility=facility)
else:
logSys.error(
"Syslog socket file: %s does not exists"
" or is not a socket" % self.__syslogSocket)
return False
elif target == "STDOUT": elif target == "STDOUT":
hdlr = logging.StreamHandler(sys.stdout) hdlr = logging.StreamHandler(sys.stdout)
elif target == "STDERR": elif target == "STDERR":
@ -412,21 +423,44 @@ class Server:
logger.addHandler(hdlr) logger.addHandler(hdlr)
# Does not display this message at startup. # Does not display this message at startup.
if not self.__logTarget is None: if not self.__logTarget is None:
logSys.info("Changed logging target to %s for Fail2ban v%s" % logSys.info(
(target, version.version)) "Changed logging target to %s for Fail2ban v%s"
% ((target
if target != "SYSLOG"
else "%s (%s)"
% (target, self.__syslogSocket)),
version.version))
# Sets the logging target. # Sets the logging target.
self.__logTarget = target self.__logTarget = target
return True return True
finally: finally:
self.__loggingLock.release() self.__loggingLock.release()
##
# Sets the syslog socket.
#
# syslogsocket is the full path to the syslog socket
# @param syslogsocket the syslog socket path
def setSyslogSocket(self, syslogsocket):
self.__syslogSocket = syslogsocket
# Conditionally reload, logtarget depends on socket path when SYSLOG
return self.__logTarget != "SYSLOG"\
or self.setLogTarget(self.__logTarget)
def getLogTarget(self): def getLogTarget(self):
try: try:
self.__loggingLock.acquire() self.__loggingLock.acquire()
return self.__logTarget return self.__logTarget
finally: finally:
self.__loggingLock.release() self.__loggingLock.release()
def getSyslogSocket(self):
try:
self.__loggingLock.acquire()
return self.__syslogSocket
finally:
self.__loggingLock.release()
def flushLogs(self): def flushLogs(self):
if self.__logTarget not in ['STDERR', 'STDOUT', 'SYSLOG']: if self.__logTarget not in ['STDERR', 'STDOUT', 'SYSLOG']:
for handler in getLogger("fail2ban").handlers: for handler in getLogger("fail2ban").handlers:

View File

@ -121,6 +121,12 @@ class Transmitter:
return self.__server.getLogTarget() return self.__server.getLogTarget()
else: else:
raise Exception("Failed to change log target") raise Exception("Failed to change log target")
elif name == "syslogsocket":
value = command[1]
if self.__server.setSyslogSocket(value):
return self.__server.getSyslogSocket()
else:
raise Exception("Failed to change syslog socket")
#Database #Database
elif name == "dbfile": elif name == "dbfile":
self.__server.setDatabase(command[1]) self.__server.setDatabase(command[1])
@ -264,6 +270,8 @@ class Transmitter:
return self.__server.getLogLevel() return self.__server.getLogLevel()
elif name == "logtarget": elif name == "logtarget":
return self.__server.getLogTarget() return self.__server.getLogTarget()
elif name == "syslogsocket":
return self.__server.getSyslogSocket()
#Database #Database
elif name == "dbfile": elif name == "dbfile":
db = self.__server.getDatabase() db = self.__server.getDatabase()

View File

@ -623,7 +623,8 @@ class JailsReaderTest(LogCaptureTestCase):
'/var/lib/fail2ban/fail2ban.sqlite3'], '/var/lib/fail2ban/fail2ban.sqlite3'],
['set', 'dbpurgeage', 86400], ['set', 'dbpurgeage', 86400],
['set', 'loglevel', "INFO"], ['set', 'loglevel', "INFO"],
['set', 'logtarget', '/var/log/fail2ban.log']]) ['set', 'logtarget', '/var/log/fail2ban.log'],
['set', 'syslogsocket', '/dev/log']])
# and if we force change configurator's fail2ban's baseDir # and if we force change configurator's fail2ban's baseDir
# there should be an error message (test visually ;) -- # there should be an error message (test visually ;) --

View File

@ -739,6 +739,7 @@ class TransmitterLogging(TransmitterBase):
self.server = Server() self.server = Server()
self.server.setLogTarget("/dev/null") self.server.setLogTarget("/dev/null")
self.server.setLogLevel("CRITICAL") self.server.setLogLevel("CRITICAL")
self.server.setSyslogSocket("/dev/log")
super(TransmitterLogging, self).setUp() super(TransmitterLogging, self).setUp()
def testLogTarget(self): def testLogTarget(self):
@ -768,6 +769,16 @@ class TransmitterLogging(TransmitterBase):
return return
self.setGetTest("logtarget", "SYSLOG") self.setGetTest("logtarget", "SYSLOG")
def testSyslogSocket(self):
self.setGetTest("syslogsocket", "/dev/log/NEW/PATH")
def testSyslogSocketNOK(self):
self.setGetTest("syslogsocket", "/this/path/should/not/exist")
self.setGetTestNOK("logtarget", "SYSLOG")
# set back for other tests
self.setGetTest("syslogsocket", "/dev/log")
self.setGetTest("logtarget", "SYSLOG")
def testLogLevel(self): def testLogLevel(self):
self.setGetTest("loglevel", "HEAVYDEBUG") self.setGetTest("loglevel", "HEAVYDEBUG")
self.setGetTest("loglevel", "DEBUG") self.setGetTest("loglevel", "DEBUG")