mirror of https://github.com/fail2ban/fail2ban
Merge pull request #949 from leeclemens/enh/configSyslogSocket
Configure Syslog Socket Path (closes #814)pull/952/head
commit
3fb2becddb
|
@ -70,6 +70,7 @@ ver. 0.9.2 (2014/XX/XXX) - wanna-be-released
|
|||
timezone not UTC time/zone. Closes gh-911
|
||||
* Conditionally log Ignore IP with reason (dns, ip, command). Closes gh-916
|
||||
* Absorbed DNSUtils.cidr into addr2bin in filter.py, added unittests
|
||||
* Added syslogsocket configuration to fail2ban.conf
|
||||
|
||||
|
||||
ver. 0.9.1 (2014/10/29) - better, faster, stronger
|
||||
|
|
|
@ -34,6 +34,12 @@ loglevel = INFO
|
|||
#
|
||||
logtarget = /var/log/fail2ban.log
|
||||
|
||||
# Option: syslogsocket
|
||||
# Notes: Set the syslog socket file. Only used when logtarget is SYSLOG
|
||||
# auto uses platform.system() to determine predefined paths
|
||||
# Values: [ auto | FILE ] Default: auto
|
||||
syslogsocket = auto
|
||||
|
||||
# Option: socket
|
||||
# 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
|
||||
|
|
|
@ -85,6 +85,9 @@ class Beautifier:
|
|||
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] == "syslogsocket":
|
||||
msg = "Current syslog socket is:\n"
|
||||
msg = msg + "`- " + response
|
||||
elif inC[1] == "logtarget":
|
||||
msg = "Current logging target is:\n"
|
||||
msg = msg + "`- " + response
|
||||
|
|
|
@ -46,6 +46,7 @@ class Fail2banReader(ConfigReader):
|
|||
def getOptions(self):
|
||||
opts = [["string", "loglevel", "INFO" ],
|
||||
["string", "logtarget", "STDERR"],
|
||||
["string", "syslogsocket", "auto"],
|
||||
["string", "dbfile", "/var/lib/fail2ban/fail2ban.sqlite3"],
|
||||
["int", "dbpurgeage", 86400]]
|
||||
self.__opts = ConfigReader.getOptions(self, "Definition", opts)
|
||||
|
@ -57,6 +58,8 @@ class Fail2banReader(ConfigReader):
|
|||
stream.append(["set", "loglevel", self.__opts[opt]])
|
||||
elif opt == "logtarget":
|
||||
stream.append(["set", "logtarget", self.__opts[opt]])
|
||||
elif opt == "syslogsocket":
|
||||
stream.append(["set", "syslogsocket", self.__opts[opt]])
|
||||
elif opt == "dbfile":
|
||||
stream.append(["set", "dbfile", self.__opts[opt]])
|
||||
elif opt == "dbpurgeage":
|
||||
|
|
|
@ -44,6 +44,8 @@ protocol = [
|
|||
["get loglevel", "gets the logging level"],
|
||||
["set logtarget <TARGET>", "sets logging target to <TARGET>. Can be STDOUT, STDERR, SYSLOG or a file"],
|
||||
["get logtarget", "gets logging target"],
|
||||
["set syslogsocket auto|<SOCKET>", "sets the syslog socket path to auto or <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."],
|
||||
['', "DATABASE", ""],
|
||||
["set dbfile <FILE>", "set the location of fail2ban persistent datastore. Set to \"None\" to disable"],
|
||||
|
|
|
@ -25,7 +25,7 @@ __copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
|||
__license__ = "GPL"
|
||||
|
||||
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 .filter import FileFilter, JournalFilter
|
||||
|
@ -55,10 +55,18 @@ class Server:
|
|||
self.__asyncServer = AsyncServer(self.__transm)
|
||||
self.__logLevel = None
|
||||
self.__logTarget = None
|
||||
self.__syslogSocket = None
|
||||
self.__autoSyslogSocketPaths = {
|
||||
'Darwin': '/var/run/syslog',
|
||||
'FreeBSD': '/var/run/log',
|
||||
'Linux': '/dev/log',
|
||||
}
|
||||
# Set logging level
|
||||
self.setLogLevel("INFO")
|
||||
self.setLogTarget("STDOUT")
|
||||
|
||||
self.setSyslogSocket("auto")
|
||||
|
||||
|
||||
def __sigTERMhandler(self, signum, frame):
|
||||
logSys.debug("Caught signal %d. Exiting" % signum)
|
||||
self.quit()
|
||||
|
@ -360,7 +368,7 @@ class Server:
|
|||
return self.__logLevel
|
||||
finally:
|
||||
self.__loggingLock.release()
|
||||
|
||||
|
||||
##
|
||||
# Sets the logging target.
|
||||
#
|
||||
|
@ -376,7 +384,21 @@ class Server:
|
|||
# Syslog daemons already add date to the message.
|
||||
formatter = logging.Formatter("%(name)s[%(process)d]: %(levelname)s %(message)s")
|
||||
facility = logging.handlers.SysLogHandler.LOG_DAEMON
|
||||
hdlr = logging.handlers.SysLogHandler("/dev/log", facility=facility)
|
||||
if self.__syslogSocket == "auto":
|
||||
import platform
|
||||
self.__syslogSocket = self.__autoSyslogSocketPaths.get(
|
||||
platform.system())
|
||||
if self.__syslogSocket is not None\
|
||||
and 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":
|
||||
hdlr = logging.StreamHandler(sys.stdout)
|
||||
elif target == "STDERR":
|
||||
|
@ -412,21 +434,44 @@ class Server:
|
|||
logger.addHandler(hdlr)
|
||||
# Does not display this message at startup.
|
||||
if not self.__logTarget is None:
|
||||
logSys.info("Changed logging target to %s for Fail2ban v%s" %
|
||||
(target, version.version))
|
||||
logSys.info(
|
||||
"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.
|
||||
self.__logTarget = target
|
||||
return True
|
||||
finally:
|
||||
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):
|
||||
try:
|
||||
self.__loggingLock.acquire()
|
||||
return self.__logTarget
|
||||
finally:
|
||||
self.__loggingLock.release()
|
||||
|
||||
|
||||
def getSyslogSocket(self):
|
||||
try:
|
||||
self.__loggingLock.acquire()
|
||||
return self.__syslogSocket
|
||||
finally:
|
||||
self.__loggingLock.release()
|
||||
|
||||
def flushLogs(self):
|
||||
if self.__logTarget not in ['STDERR', 'STDOUT', 'SYSLOG']:
|
||||
for handler in getLogger("fail2ban").handlers:
|
||||
|
|
|
@ -121,6 +121,12 @@ class Transmitter:
|
|||
return self.__server.getLogTarget()
|
||||
else:
|
||||
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
|
||||
elif name == "dbfile":
|
||||
self.__server.setDatabase(command[1])
|
||||
|
@ -264,6 +270,8 @@ class Transmitter:
|
|||
return self.__server.getLogLevel()
|
||||
elif name == "logtarget":
|
||||
return self.__server.getLogTarget()
|
||||
elif name == "syslogsocket":
|
||||
return self.__server.getSyslogSocket()
|
||||
#Database
|
||||
elif name == "dbfile":
|
||||
db = self.__server.getDatabase()
|
||||
|
|
|
@ -623,7 +623,8 @@ class JailsReaderTest(LogCaptureTestCase):
|
|||
'/var/lib/fail2ban/fail2ban.sqlite3'],
|
||||
['set', 'dbpurgeage', 86400],
|
||||
['set', 'loglevel', "INFO"],
|
||||
['set', 'logtarget', '/var/log/fail2ban.log']])
|
||||
['set', 'logtarget', '/var/log/fail2ban.log'],
|
||||
['set', 'syslogsocket', 'auto']])
|
||||
|
||||
# and if we force change configurator's fail2ban's baseDir
|
||||
# there should be an error message (test visually ;) --
|
||||
|
|
|
@ -739,6 +739,7 @@ class TransmitterLogging(TransmitterBase):
|
|||
self.server = Server()
|
||||
self.server.setLogTarget("/dev/null")
|
||||
self.server.setLogLevel("CRITICAL")
|
||||
self.server.setSyslogSocket("auto")
|
||||
super(TransmitterLogging, self).setUp()
|
||||
|
||||
def testLogTarget(self):
|
||||
|
@ -766,6 +767,18 @@ class TransmitterLogging(TransmitterBase):
|
|||
raise unittest.SkipTest("'/dev/log' not present")
|
||||
elif not os.path.exists("/dev/log"):
|
||||
return
|
||||
self.assertTrue(self.server.getSyslogSocket(), "auto")
|
||||
self.setGetTest("logtarget", "SYSLOG")
|
||||
self.assertTrue(self.server.getSyslogSocket(), "/dev/log")
|
||||
|
||||
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):
|
||||
|
|
Loading…
Reference in New Issue