From e8131475cd34b95a34b84c2b949b808f48d90a5f Mon Sep 17 00:00:00 2001 From: Steven Hiscocks Date: Mon, 9 Jun 2014 22:17:00 +0100 Subject: [PATCH 01/13] ENH: Realign and harmonise log messages with getF2BLogger helper --- ChangeLog | 2 ++ bin/fail2ban-client | 2 +- config/filter.d/recidive.conf | 2 +- fail2ban/client/actionreader.py | 5 +++-- fail2ban/client/beautifier.py | 5 ++--- fail2ban/client/configparserinc.py | 5 +++-- fail2ban/client/configreader.py | 5 +++-- fail2ban/client/configurator.py | 5 ++--- fail2ban/client/fail2banreader.py | 5 ++--- fail2ban/client/filterreader.py | 5 +++-- fail2ban/client/jailreader.py | 5 +++-- fail2ban/client/jailsreader.py | 5 ++--- fail2ban/helpers.py | 5 +++++ fail2ban/server/action.py | 7 ++++--- fail2ban/server/actions.py | 3 ++- fail2ban/server/asyncserver.py | 8 ++++---- fail2ban/server/banmanager.py | 4 ++-- fail2ban/server/database.py | 4 ++-- fail2ban/server/datedetector.py | 4 ++-- fail2ban/server/datetemplate.py | 4 ++-- fail2ban/server/faildata.py | 4 ++-- fail2ban/server/failmanager.py | 3 ++- fail2ban/server/filter.py | 5 +++-- fail2ban/server/filtergamin.py | 5 +++-- fail2ban/server/filterpoll.py | 5 +++-- fail2ban/server/filterpyinotify.py | 3 ++- fail2ban/server/filtersystemd.py | 6 +++--- fail2ban/server/jail.py | 3 ++- fail2ban/server/server.py | 13 +++++++------ fail2ban/server/ticket.py | 4 ++-- fail2ban/server/transmitter.py | 6 ++++-- fail2ban/tests/files/logs/recidive | 12 ++++++------ fail2ban/tests/servertestcase.py | 8 +++++++- fail2ban/tests/utils.py | 4 +++- 34 files changed, 99 insertions(+), 72 deletions(-) diff --git a/ChangeLog b/ChangeLog index d4ea774a..ff70f07c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -38,6 +38,8 @@ ver. 0.9.1 (2014/xx/xx) - better, faster, stronger * Fail2ban-regex - add print-all-matched option. Closes gh-652 * Suppress fail2ban-client warnings for non-critical config options * Match non "Bye Bye" disconnect messages for sshd locked account regex + * Realign fail2ban log output with white space to improve readability. Does + not affect SYSLOG output. ver. 0.9.0 (2014/03/14) - beta ---------- diff --git a/bin/fail2ban-client b/bin/fail2ban-client index 289d7b39..b9713153 100755 --- a/bin/fail2ban-client +++ b/bin/fail2ban-client @@ -32,7 +32,7 @@ from fail2ban.client.configurator import Configurator from fail2ban.client.beautifier import Beautifier # Gets the instance of the logger. -logSys = logging.getLogger("fail2ban.client") +logSys = logging.getLogger("fail2ban") ## # diff --git a/config/filter.d/recidive.conf b/config/filter.d/recidive.conf index aa1b0013..b38735ad 100644 --- a/config/filter.d/recidive.conf +++ b/config/filter.d/recidive.conf @@ -21,7 +21,7 @@ before = common.conf [Definition] -_daemon = fail2ban\.server\.actions +_daemon = fail2ban\.actions\s* # The name of the jail that this filter is used for. In jail.conf, name the # jail using this filter 'recidive', or change this line! diff --git a/fail2ban/client/actionreader.py b/fail2ban/client/actionreader.py index 6b0334ac..07572930 100644 --- a/fail2ban/client/actionreader.py +++ b/fail2ban/client/actionreader.py @@ -24,12 +24,13 @@ __author__ = "Cyril Jaquier" __copyright__ = "Copyright (c) 2004 Cyril Jaquier" __license__ = "GPL" -import logging, os +import os from .configreader import ConfigReader, DefinitionInitConfigReader +from ..helpers import getF2BLogger # Gets the instance of the logger. -logSys = logging.getLogger(__name__) +logSys = getF2BLogger(__name__) class ActionReader(DefinitionInitConfigReader): diff --git a/fail2ban/client/beautifier.py b/fail2ban/client/beautifier.py index 25d73cb2..070c80c5 100644 --- a/fail2ban/client/beautifier.py +++ b/fail2ban/client/beautifier.py @@ -21,12 +21,11 @@ __author__ = "Cyril Jaquier, Yaroslav Halchenko" __copyright__ = "Copyright (c) 2004 Cyril Jaquier, 2013- Yaroslav Halchenko" __license__ = "GPL" -import logging - from ..exceptions import UnknownJailException, DuplicateJailException +from ..helpers import getF2BLogger # Gets the instance of the logger. -logSys = logging.getLogger(__name__) +logSys = getF2BLogger(__name__) ## # Beautify the output of the client. diff --git a/fail2ban/client/configparserinc.py b/fail2ban/client/configparserinc.py index 7519e599..1be786c7 100644 --- a/fail2ban/client/configparserinc.py +++ b/fail2ban/client/configparserinc.py @@ -24,7 +24,8 @@ __author__ = 'Yaroslav Halhenko' __copyright__ = 'Copyright (c) 2007 Yaroslav Halchenko' __license__ = 'GPL' -import logging, os, sys +import os, sys +from ..helpers import getF2BLogger if sys.version_info >= (3,2): # pragma: no cover @@ -60,7 +61,7 @@ else: # pragma: no cover from ConfigParser import SafeConfigParser # Gets the instance of the logger. -logSys = logging.getLogger(__name__) +logSys = getF2BLogger(__name__) __all__ = ['SafeConfigParserWithIncludes'] diff --git a/fail2ban/client/configreader.py b/fail2ban/client/configreader.py index 51ca6948..e905b278 100644 --- a/fail2ban/client/configreader.py +++ b/fail2ban/client/configreader.py @@ -24,13 +24,14 @@ __author__ = "Cyril Jaquier" __copyright__ = "Copyright (c) 2004 Cyril Jaquier" __license__ = "GPL" -import glob, logging, os +import glob, os from ConfigParser import NoOptionError, NoSectionError from .configparserinc import SafeConfigParserWithIncludes +from ..helpers import getF2BLogger # Gets the instance of the logger. -logSys = logging.getLogger(__name__) +logSys = getF2BLogger(__name__) class ConfigReader(SafeConfigParserWithIncludes): diff --git a/fail2ban/client/configurator.py b/fail2ban/client/configurator.py index df523280..23c21c4b 100644 --- a/fail2ban/client/configurator.py +++ b/fail2ban/client/configurator.py @@ -24,13 +24,12 @@ __author__ = "Cyril Jaquier" __copyright__ = "Copyright (c) 2004 Cyril Jaquier" __license__ = "GPL" -import logging - from .fail2banreader import Fail2banReader from .jailsreader import JailsReader +from ..helpers import getF2BLogger # Gets the instance of the logger. -logSys = logging.getLogger(__name__) +logSys = getF2BLogger(__name__) class Configurator: diff --git a/fail2ban/client/fail2banreader.py b/fail2ban/client/fail2banreader.py index 251c6985..4d106f3a 100644 --- a/fail2ban/client/fail2banreader.py +++ b/fail2ban/client/fail2banreader.py @@ -24,12 +24,11 @@ __author__ = "Cyril Jaquier" __copyright__ = "Copyright (c) 2004 Cyril Jaquier" __license__ = "GPL" -import logging - from .configreader import ConfigReader +from ..helpers import getF2BLogger # Gets the instance of the logger. -logSys = logging.getLogger(__name__) +logSys = getF2BLogger(__name__) class Fail2banReader(ConfigReader): diff --git a/fail2ban/client/filterreader.py b/fail2ban/client/filterreader.py index 5a11dc41..2f5b3b05 100644 --- a/fail2ban/client/filterreader.py +++ b/fail2ban/client/filterreader.py @@ -24,13 +24,14 @@ __author__ = "Cyril Jaquier" __copyright__ = "Copyright (c) 2004 Cyril Jaquier" __license__ = "GPL" -import logging, os, shlex +import os, shlex from .configreader import ConfigReader, DefinitionInitConfigReader from ..server.action import CommandAction +from ..helpers import getF2BLogger # Gets the instance of the logger. -logSys = logging.getLogger(__name__) +logSys = getF2BLogger(__name__) class FilterReader(DefinitionInitConfigReader): diff --git a/fail2ban/client/jailreader.py b/fail2ban/client/jailreader.py index 5735b021..6207d8f4 100644 --- a/fail2ban/client/jailreader.py +++ b/fail2ban/client/jailreader.py @@ -24,15 +24,16 @@ __author__ = "Cyril Jaquier" __copyright__ = "Copyright (c) 2004 Cyril Jaquier" __license__ = "GPL" -import logging, re, glob, os.path +import re, glob, os.path import json from .configreader import ConfigReader from .filterreader import FilterReader from .actionreader import ActionReader +from ..helpers import getF2BLogger # Gets the instance of the logger. -logSys = logging.getLogger(__name__) +logSys = getF2BLogger(__name__) class JailReader(ConfigReader): diff --git a/fail2ban/client/jailsreader.py b/fail2ban/client/jailsreader.py index 047749b3..86fd501f 100644 --- a/fail2ban/client/jailsreader.py +++ b/fail2ban/client/jailsreader.py @@ -24,13 +24,12 @@ __author__ = "Cyril Jaquier" __copyright__ = "Copyright (c) 2004 Cyril Jaquier" __license__ = "GPL" -import logging - from .configreader import ConfigReader from .jailreader import JailReader +from ..helpers import getF2BLogger # Gets the instance of the logger. -logSys = logging.getLogger(__name__) +logSys = getF2BLogger(__name__) class JailsReader(ConfigReader): diff --git a/fail2ban/helpers.py b/fail2ban/helpers.py index 2579381d..c3e50336 100644 --- a/fail2ban/helpers.py +++ b/fail2ban/helpers.py @@ -107,3 +107,8 @@ class FormatterWithTraceBack(logging.Formatter): def format(self, record): record.tbc = record.tb = self._tb() return logging.Formatter.format(self, record) + +def getF2BLogger(name): + """Get logging.Logger instance with Fail2Ban logger name convention + """ + return logging.getLogger("fail2ban.%s" % name.rpartition(".")[-1]) diff --git a/fail2ban/server/action.py b/fail2ban/server/action.py index fefe2c2c..ea7bc91c 100644 --- a/fail2ban/server/action.py +++ b/fail2ban/server/action.py @@ -25,10 +25,11 @@ import logging, os, subprocess, time, signal, tempfile import threading, re from abc import ABCMeta from collections import MutableMapping -#from subprocess import call + +from ..helpers import getF2BLogger # Gets the instance of the logger. -logSys = logging.getLogger(__name__) +logSys = getF2BLogger(__name__) # Create a lock for running system commands _cmd_lock = threading.Lock() @@ -136,7 +137,7 @@ class ActionBase(object): self._jail = jail self._name = name self._logSys = logging.getLogger( - '%s.%s' % (__name__, self.__class__.__name__)) + "fail2ban.%s" % self.__class__.__name__) def start(self): """Executed when the jail/action is started. diff --git a/fail2ban/server/actions.py b/fail2ban/server/actions.py index dd68ac13..467df510 100644 --- a/fail2ban/server/actions.py +++ b/fail2ban/server/actions.py @@ -41,9 +41,10 @@ from .banmanager import BanManager from .jailthread import JailThread from .action import ActionBase, CommandAction, CallingMap from .mytime import MyTime +from ..helpers import getF2BLogger # Gets the instance of the logger. -logSys = logging.getLogger(__name__) +logSys = getF2BLogger(__name__) class Actions(JailThread, Mapping): """Handles jail actions. diff --git a/fail2ban/server/asyncserver.py b/fail2ban/server/asyncserver.py index 56704510..326e35cb 100644 --- a/fail2ban/server/asyncserver.py +++ b/fail2ban/server/asyncserver.py @@ -25,12 +25,12 @@ __copyright__ = "Copyright (c) 2004 Cyril Jaquier" __license__ = "GPL" from pickle import dumps, loads, HIGHEST_PROTOCOL -import asyncore, asynchat, socket, os, logging, sys, traceback, fcntl +import asyncore, asynchat, socket, os, sys, traceback, fcntl -from .. import helpers +from ..helpers import getF2BLogger,formatExceptionInfo # Gets the instance of the logger. -logSys = logging.getLogger(__name__) +logSys = getF2BLogger(__name__) if sys.version_info >= (3,): # b"" causes SyntaxError in python <= 2.5, so below implements equivalent @@ -81,7 +81,7 @@ class RequestHandler(asynchat.async_chat): self.close_when_done() def handle_error(self): - e1, e2 = helpers.formatExceptionInfo() + e1, e2 = formatExceptionInfo() logSys.error("Unexpected communication error: %s" % str(e2)) logSys.error(traceback.format_exc().splitlines()) self.close() diff --git a/fail2ban/server/banmanager.py b/fail2ban/server/banmanager.py index fc9eb948..68954b9c 100644 --- a/fail2ban/server/banmanager.py +++ b/fail2ban/server/banmanager.py @@ -24,14 +24,14 @@ __author__ = "Cyril Jaquier" __copyright__ = "Copyright (c) 2004 Cyril Jaquier" __license__ = "GPL" -import logging from threading import Lock from .ticket import BanTicket from .mytime import MyTime +from ..helpers import getF2BLogger # Gets the instance of the logger. -logSys = logging.getLogger(__name__) +logSys = getF2BLogger(__name__) ## # Banning Manager. diff --git a/fail2ban/server/database.py b/fail2ban/server/database.py index 54cca4d3..24a3a327 100644 --- a/fail2ban/server/database.py +++ b/fail2ban/server/database.py @@ -21,7 +21,6 @@ __author__ = "Steven Hiscocks" __copyright__ = "Copyright (c) 2013 Steven Hiscocks" __license__ = "GPL" -import logging import sys import shutil, time import sqlite3 @@ -32,9 +31,10 @@ from threading import Lock from .mytime import MyTime from .ticket import FailTicket +from ..helpers import getF2BLogger # Gets the instance of the logger. -logSys = logging.getLogger(__name__) +logSys = getF2BLogger(__name__) if sys.version_info >= (3,): sqlite3.register_adapter( diff --git a/fail2ban/server/datedetector.py b/fail2ban/server/datedetector.py index c5effea0..8d3ccaf2 100644 --- a/fail2ban/server/datedetector.py +++ b/fail2ban/server/datedetector.py @@ -21,13 +21,13 @@ __author__ = "Cyril Jaquier and Fail2Ban Contributors" __copyright__ = "Copyright (c) 2004 Cyril Jaquier" __license__ = "GPL" -import logging from threading import Lock from .datetemplate import DatePatternRegex, DateTai64n, DateEpoch +from ..helpers import getF2BLogger # Gets the instance of the logger. -logSys = logging.getLogger(__name__) +logSys = getF2BLogger(__name__) class DateDetector(object): """Manages one or more date templates to find a date within a log line. diff --git a/fail2ban/server/datetemplate.py b/fail2ban/server/datetemplate.py index 19bdd0ef..0e6141e5 100644 --- a/fail2ban/server/datetemplate.py +++ b/fail2ban/server/datetemplate.py @@ -25,12 +25,12 @@ __copyright__ = "Copyright (c) 2004 Cyril Jaquier" __license__ = "GPL" import re -import logging from abc import abstractmethod from .strptime import reGroupDictStrptime, timeRE +from ..helpers import getF2BLogger -logSys = logging.getLogger(__name__) +logSys = getF2BLogger(__name__) class DateTemplate(object): diff --git a/fail2ban/server/faildata.py b/fail2ban/server/faildata.py index 232a492d..328bdb07 100644 --- a/fail2ban/server/faildata.py +++ b/fail2ban/server/faildata.py @@ -24,10 +24,10 @@ __author__ = "Cyril Jaquier" __copyright__ = "Copyright (c) 2004 Cyril Jaquier" __license__ = "GPL" -import logging +from ..helpers import getF2BLogger # Gets the instance of the logger. -logSys = logging.getLogger(__name__) +logSys = getF2BLogger(__name__) class FailData: diff --git a/fail2ban/server/failmanager.py b/fail2ban/server/failmanager.py index 548e6adb..75b505c9 100644 --- a/fail2ban/server/failmanager.py +++ b/fail2ban/server/failmanager.py @@ -29,9 +29,10 @@ import logging from .faildata import FailData from .ticket import FailTicket +from ..helpers import getF2BLogger # Gets the instance of the logger. -logSys = logging.getLogger(__name__) +logSys = getF2BLogger(__name__) class FailManager: diff --git a/fail2ban/server/filter.py b/fail2ban/server/filter.py index 73233905..ec60ed15 100644 --- a/fail2ban/server/filter.py +++ b/fail2ban/server/filter.py @@ -21,7 +21,7 @@ __author__ = "Cyril Jaquier and Fail2Ban Contributors" __copyright__ = "Copyright (c) 2004 Cyril Jaquier, 2011-2013 Yaroslav Halchenko" __license__ = "GPL" -import logging, re, os, fcntl, sys, locale, codecs +import re, os, fcntl, sys, locale, codecs from .failmanager import FailManagerEmpty, FailManager from .ticket import FailTicket @@ -31,9 +31,10 @@ from .datetemplate import DatePatternRegex, DateEpoch, DateTai64n from .mytime import MyTime from .failregex import FailRegex, Regex, RegexException from .action import CommandAction +from ..helpers import getF2BLogger # Gets the instance of the logger. -logSys = logging.getLogger(__name__) +logSys = getF2BLogger(__name__) ## # Log reader class. diff --git a/fail2ban/server/filtergamin.py b/fail2ban/server/filtergamin.py index 898c8dfc..f6d13d5d 100644 --- a/fail2ban/server/filtergamin.py +++ b/fail2ban/server/filtergamin.py @@ -23,16 +23,17 @@ __author__ = "Cyril Jaquier, Yaroslav Halchenko" __copyright__ = "Copyright (c) 2004 Cyril Jaquier, 2012 Yaroslav Halchenko" __license__ = "GPL" -import time, logging, fcntl +import time, fcntl import gamin from .failmanager import FailManagerEmpty from .filter import FileFilter from .mytime import MyTime +from ..helpers import getF2BLogger # Gets the instance of the logger. -logSys = logging.getLogger(__name__) +logSys = getF2BLogger(__name__) ## # Log reader class. diff --git a/fail2ban/server/filterpoll.py b/fail2ban/server/filterpoll.py index 27af97b4..a94b7cb8 100644 --- a/fail2ban/server/filterpoll.py +++ b/fail2ban/server/filterpoll.py @@ -24,14 +24,15 @@ __author__ = "Cyril Jaquier, Yaroslav Halchenko" __copyright__ = "Copyright (c) 2004 Cyril Jaquier; 2012 Yaroslav Halchenko" __license__ = "GPL" -import time, logging, os +import time, os from .failmanager import FailManagerEmpty from .filter import FileFilter from .mytime import MyTime +from ..helpers import getF2BLogger # Gets the instance of the logger. -logSys = logging.getLogger(__name__) +logSys = getF2BLogger(__name__) ## # Log reader class. diff --git a/fail2ban/server/filterpyinotify.py b/fail2ban/server/filterpyinotify.py index b340ef13..68cb9b0f 100644 --- a/fail2ban/server/filterpyinotify.py +++ b/fail2ban/server/filterpyinotify.py @@ -32,6 +32,7 @@ import pyinotify from .failmanager import FailManagerEmpty from .filter import FileFilter from .mytime import MyTime +from ..helpers import getF2BLogger if not hasattr(pyinotify, '__version__') \ @@ -48,7 +49,7 @@ except Exception, e: % str(e)) # Gets the instance of the logger. -logSys = logging.getLogger(__name__) +logSys = getF2BLogger(__name__) ## # Log reader class. diff --git a/fail2ban/server/filtersystemd.py b/fail2ban/server/filtersystemd.py index f2dee8cb..71dde126 100644 --- a/fail2ban/server/filtersystemd.py +++ b/fail2ban/server/filtersystemd.py @@ -22,7 +22,7 @@ __author__ = "Steven Hiscocks" __copyright__ = "Copyright (c) 2013 Steven Hiscocks" __license__ = "GPL" -import logging, datetime, time +import datetime, time from distutils.version import LooseVersion from systemd import journal @@ -32,10 +32,10 @@ if LooseVersion(getattr(journal, '__version__', "0")) < '204': from .failmanager import FailManagerEmpty from .filter import JournalFilter from .mytime import MyTime - +from ..helpers import getF2BLogger # Gets the instance of the logger. -logSys = logging.getLogger("fail2ban.filter") +logSys = getF2BLogger(__name__) ## # Journal reader class. diff --git a/fail2ban/server/jail.py b/fail2ban/server/jail.py index a7c174ae..5c1c4e70 100644 --- a/fail2ban/server/jail.py +++ b/fail2ban/server/jail.py @@ -26,9 +26,10 @@ __license__ = "GPL" import Queue, logging from .actions import Actions +from ..helpers import getF2BLogger # Gets the instance of the logger. -logSys = logging.getLogger(__name__) +logSys = getF2BLogger(__name__) class Jail: """Fail2Ban jail, which manages a filter and associated actions. diff --git a/fail2ban/server/server.py b/fail2ban/server/server.py index 735ce0a9..2f227517 100644 --- a/fail2ban/server/server.py +++ b/fail2ban/server/server.py @@ -32,9 +32,10 @@ from .filter import FileFilter, JournalFilter from .transmitter import Transmitter from .asyncserver import AsyncServer, AsyncServerException from .. import version +from ..helpers import getF2BLogger # Gets the instance of the logger. -logSys = logging.getLogger(__name__) +logSys = getF2BLogger(__name__) try: from .database import Fail2BanDb @@ -335,7 +336,7 @@ class Server: def setLogLevel(self, value): try: self.__loggingLock.acquire() - logging.getLogger(__name__).parent.parent.setLevel( + logging.getLogger("fail2ban").setLevel( getattr(logging, value.upper())) except AttributeError: raise ValueError("Invalid log level") @@ -367,7 +368,7 @@ class Server: try: self.__loggingLock.acquire() # set a format which is simpler for console use - formatter = logging.Formatter("%(asctime)s %(name)-16s[%(process)d]: %(levelname)-7s %(message)s") + formatter = logging.Formatter("%(asctime)s %(name)-24s[%(process)d]: %(levelname)-7s %(message)s") if target == "SYSLOG": # Syslog daemons already add date to the message. formatter = logging.Formatter("%(name)s[%(process)d]: %(levelname)s %(message)s") @@ -388,7 +389,7 @@ class Server: return False # Removes previous handlers -- in reverse order since removeHandler # alter the list in-place and that can confuses the iterable - logger = logging.getLogger(__name__).parent.parent + logger = logging.getLogger("fail2ban") for handler in logger.handlers[::-1]: # Remove the handler. logger.removeHandler(handler) @@ -425,7 +426,7 @@ class Server: def flushLogs(self): if self.__logTarget not in ['STDERR', 'STDOUT', 'SYSLOG']: - for handler in logging.getLogger(__name__).parent.parent.handlers: + for handler in logging.getLogger("fail2ban").handlers: try: handler.doRollover() logSys.info("rollover performed on %s" % self.__logTarget) @@ -434,7 +435,7 @@ class Server: logSys.info("flush performed on %s" % self.__logTarget) return "rolled over" else: - for handler in logging.getLogger(__name__).parent.parent.handlers: + for handler in logging.getLogger("fail2ban").handlers: handler.flush() logSys.info("flush performed on %s" % self.__logTarget) return "flushed" diff --git a/fail2ban/server/ticket.py b/fail2ban/server/ticket.py index 8d036b2d..a216e9ed 100644 --- a/fail2ban/server/ticket.py +++ b/fail2ban/server/ticket.py @@ -24,10 +24,10 @@ __author__ = "Cyril Jaquier" __copyright__ = "Copyright (c) 2004 Cyril Jaquier" __license__ = "GPL" -import logging +from ..helpers import getF2BLogger # Gets the instance of the logger. -logSys = logging.getLogger(__name__) +logSys = getF2BLogger(__name__) class Ticket: diff --git a/fail2ban/server/transmitter.py b/fail2ban/server/transmitter.py index 2baf00a7..b5edf367 100644 --- a/fail2ban/server/transmitter.py +++ b/fail2ban/server/transmitter.py @@ -24,11 +24,13 @@ __author__ = "Cyril Jaquier" __copyright__ = "Copyright (c) 2004 Cyril Jaquier" __license__ = "GPL" -import logging, time +import time import json +from ..helpers import getF2BLogger + # Gets the instance of the logger. -logSys = logging.getLogger(__name__) +logSys = getF2BLogger(__name__) class Transmitter: diff --git a/fail2ban/tests/files/logs/recidive b/fail2ban/tests/files/logs/recidive index 4b23b1a5..edb3a155 100644 --- a/fail2ban/tests/files/logs/recidive +++ b/fail2ban/tests/files/logs/recidive @@ -1,14 +1,14 @@ # failJSON: { "time": "2006-02-13T15:52:30", "match": true , "host": "1.2.3.4" } -2006-02-13 15:52:30,388 fail2ban.server.actions: NOTICE [sendmail] Ban 1.2.3.4 +2006-02-13 15:52:30,388 fail2ban.actions: NOTICE [sendmail] Ban 1.2.3.4 # failJSON: { "time": "2006-02-13T15:52:30", "match": true , "host": "1.2.3.4", "desc": "Extended with [PID]" } -2006-02-13 15:52:30,388 fail2ban.server.actions[123]: NOTICE [sendmail] Ban 1.2.3.4 +2006-02-13 15:52:30,388 fail2ban.actions[123]: NOTICE [sendmail] Ban 1.2.3.4 # failJSON: { "match": false } -2006-02-13 16:07:31,183 fail2ban.server.actions: NOTICE [sendmail] Unban 1.2.3.4 +2006-02-13 16:07:31,183 fail2ban.actions: NOTICE [sendmail] Unban 1.2.3.4 # failJSON: { "match": false } -2006-02-13 15:52:30,388 fail2ban.server.actions: NOTICE [recidive] Ban 1.2.3.4 +2006-02-13 15:52:30,388 fail2ban.actions: NOTICE [recidive] Ban 1.2.3.4 # syslog example # failJSON: { "time": "2004-09-16T00:44:55", "match": true , "host": "10.0.0.7" } -Sep 16 00:44:55 spaceman fail2ban.server.actions: NOTICE [jail] Ban 10.0.0.7 +Sep 16 00:44:55 spaceman fail2ban.actions: NOTICE [jail] Ban 10.0.0.7 # failJSON: { "time": "2006-02-13T15:52:30", "match": true , "host": "1.2.3.4", "desc": "Extended with [PID] and padding" } -2006-02-13 15:52:30,388 fail2ban.server.actions[123]: NOTICE [sendmail] Ban 1.2.3.4 +2006-02-13 15:52:30,388 fail2ban.actions [123]: NOTICE [sendmail] Ban 1.2.3.4 diff --git a/fail2ban/tests/servertestcase.py b/fail2ban/tests/servertestcase.py index 7b05a9b6..1dfe13ca 100644 --- a/fail2ban/tests/servertestcase.py +++ b/fail2ban/tests/servertestcase.py @@ -35,6 +35,7 @@ import logging from ..server.failregex import Regex, FailRegex, RegexException from ..server.server import Server from ..server.jail import Jail +from ..helpers import getF2BLogger try: from ..server import filtersystemd @@ -722,7 +723,7 @@ class TransmitterLogging(TransmitterBase): os.close(f) self.server.setLogLevel("WARNING") self.assertEqual(self.transm.proceed(["set", "logtarget", fn]), (0, fn)) - l = logging.getLogger('fail2ban.server.server').parent.parent + l = logging.getLogger('fail2ban') l.warning("Before file moved") try: f2, fn2 = tempfile.mkstemp("fail2ban.log") @@ -796,5 +797,10 @@ class RegexTests(unittest.TestCase): self.assertTrue(fr.hasMatched()) self.assertRaises(RegexException, fr.getHost) +class LoggingTests(unittest.TestCase): + def testGetF2BLogger(self): + testLogSys = getF2BLogger("fail2ban.some.string.with.name") + self.assertEqual(testLogSys.parent.name, "fail2ban") + self.assertEqual(testLogSys.name, "fail2ban.name") diff --git a/fail2ban/tests/utils.py b/fail2ban/tests/utils.py index 7727632e..f35685a4 100644 --- a/fail2ban/tests/utils.py +++ b/fail2ban/tests/utils.py @@ -30,8 +30,9 @@ import unittest from StringIO import StringIO from ..server.mytime import MyTime +from ..helpers import getF2BLogger -logSys = logging.getLogger(__name__) +logSys = getF2BLogger(__name__) def mtimesleep(): # no sleep now should be necessary since polling tracks now not only @@ -89,6 +90,7 @@ def gatherTests(regexps=None, no_network=False): tests.addTest(unittest.makeSuite(servertestcase.Transmitter)) tests.addTest(unittest.makeSuite(servertestcase.JailTests)) tests.addTest(unittest.makeSuite(servertestcase.RegexTests)) + tests.addTest(unittest.makeSuite(servertestcase.LoggingTests)) tests.addTest(unittest.makeSuite(actiontestcase.CommandActionTest)) tests.addTest(unittest.makeSuite(actionstestcase.ExecuteActions)) # FailManager From f7da091437b991fd860d1dac90af9fe111633c20 Mon Sep 17 00:00:00 2001 From: Steven Hiscocks Date: Mon, 9 Jun 2014 22:27:51 +0100 Subject: [PATCH 02/13] ENH: Log unhandled exceptions to Fail2Ban log --- ChangeLog | 1 + fail2ban/helpers.py | 7 +++++++ fail2ban/server/jailthread.py | 13 +++++++++++++ fail2ban/server/server.py | 5 ++++- fail2ban/tests/servertestcase.py | 13 ++++++++++++- 5 files changed, 37 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index ff70f07c..a7743801 100644 --- a/ChangeLog +++ b/ChangeLog @@ -40,6 +40,7 @@ ver. 0.9.1 (2014/xx/xx) - better, faster, stronger * Match non "Bye Bye" disconnect messages for sshd locked account regex * Realign fail2ban log output with white space to improve readability. Does not affect SYSLOG output. + * Log unhandled exceptions ver. 0.9.0 (2014/03/14) - beta ---------- diff --git a/fail2ban/helpers.py b/fail2ban/helpers.py index c3e50336..35c7ebc3 100644 --- a/fail2ban/helpers.py +++ b/fail2ban/helpers.py @@ -112,3 +112,10 @@ def getF2BLogger(name): """Get logging.Logger instance with Fail2Ban logger name convention """ return logging.getLogger("fail2ban.%s" % name.rpartition(".")[-1]) + +def fail2ban_excepthook(exctype, value, traceback): + """Except hook used to log unhandled exceptions to Fail2Ban log + """ + logging.getLogger("fail2ban").critical( + "Unhandled exception in Fail2Ban:", exc_info=True) + return sys.__excepthook__(exctype, value, traceback) diff --git a/fail2ban/server/jailthread.py b/fail2ban/server/jailthread.py index 7dcdb2d7..4f640f8b 100644 --- a/fail2ban/server/jailthread.py +++ b/fail2ban/server/jailthread.py @@ -24,9 +24,12 @@ __author__ = "Cyril Jaquier" __copyright__ = "Copyright (c) 2004 Cyril Jaquier" __license__ = "GPL" +import sys from threading import Thread from abc import abstractproperty, abstractmethod +from ..helpers import fail2ban_excepthook + class JailThread(Thread): """Abstract class for threading elements in Fail2Ban. @@ -53,6 +56,16 @@ class JailThread(Thread): ## The time the thread sleeps in the loop. self.sleeptime = 1 + # excepthook workaround for threads, derived from: + # http://bugs.python.org/issue1230540#msg91244 + run = self.run + def run_with_except_hook(*args, **kwargs): + try: + run(*args, **kwargs) + except: + fail2ban_excepthook(*sys.exc_info()) + self.run = run_with_except_hook + @abstractproperty def status(self): # pragma: no cover - abstract """Abstract - Should provide status information. diff --git a/fail2ban/server/server.py b/fail2ban/server/server.py index 2f227517..a6be18ac 100644 --- a/fail2ban/server/server.py +++ b/fail2ban/server/server.py @@ -32,7 +32,7 @@ from .filter import FileFilter, JournalFilter from .transmitter import Transmitter from .asyncserver import AsyncServer, AsyncServerException from .. import version -from ..helpers import getF2BLogger +from ..helpers import getF2BLogger, fail2ban_excepthook # Gets the instance of the logger. logSys = getF2BLogger(__name__) @@ -70,6 +70,9 @@ class Server: signal.signal(signal.SIGTERM, self.__sigTERMhandler) signal.signal(signal.SIGINT, self.__sigTERMhandler) + # Ensure unhandled exceptions are logged + sys.excepthook = fail2ban_excepthook + # First set the mask to only allow access to owner os.umask(0077) if self.__daemon: # pragma: no cover diff --git a/fail2ban/tests/servertestcase.py b/fail2ban/tests/servertestcase.py index 1dfe13ca..6ce6e54f 100644 --- a/fail2ban/tests/servertestcase.py +++ b/fail2ban/tests/servertestcase.py @@ -35,6 +35,8 @@ import logging from ..server.failregex import Regex, FailRegex, RegexException from ..server.server import Server from ..server.jail import Jail +from ..server.jailthread import JailThread +from .utils import LogCaptureTestCase from ..helpers import getF2BLogger try: @@ -797,10 +799,19 @@ class RegexTests(unittest.TestCase): self.assertTrue(fr.hasMatched()) self.assertRaises(RegexException, fr.getHost) -class LoggingTests(unittest.TestCase): +class _BadThread(JailThread): + def run(self): + int("cat") + +class LoggingTests(LogCaptureTestCase): def testGetF2BLogger(self): testLogSys = getF2BLogger("fail2ban.some.string.with.name") self.assertEqual(testLogSys.parent.name, "fail2ban") self.assertEqual(testLogSys.name, "fail2ban.name") + def testFail2BanExceptHook(self): + badThread = _BadThread() + badThread.start() + badThread.join() + self.assertTrue(self._is_logged("Unhandled exception")) From 4fc7f1a831062e2caa2ef81d3677bff8b3a2d34a Mon Sep 17 00:00:00 2001 From: Steven Hiscocks Date: Tue, 10 Jun 2014 20:36:19 +0100 Subject: [PATCH 03/13] ENH: Tweak naming of getF2BLogger, and ensure consistent use --- bin/fail2ban-client | 3 ++- bin/fail2ban-regex | 4 ++-- bin/fail2ban-server | 5 +++-- bin/fail2ban-testcases | 6 +++--- fail2ban/client/actionreader.py | 4 ++-- fail2ban/client/beautifier.py | 4 ++-- fail2ban/client/configparserinc.py | 4 ++-- fail2ban/client/configreader.py | 4 ++-- fail2ban/client/configurator.py | 4 ++-- fail2ban/client/fail2banreader.py | 4 ++-- fail2ban/client/filterreader.py | 4 ++-- fail2ban/client/jailreader.py | 4 ++-- fail2ban/client/jailsreader.py | 4 ++-- fail2ban/helpers.py | 4 ++-- fail2ban/server/action.py | 7 +++---- fail2ban/server/actions.py | 4 ++-- fail2ban/server/asyncserver.py | 4 ++-- fail2ban/server/banmanager.py | 4 ++-- fail2ban/server/database.py | 4 ++-- fail2ban/server/datedetector.py | 4 ++-- fail2ban/server/datetemplate.py | 4 ++-- fail2ban/server/faildata.py | 4 ++-- fail2ban/server/failmanager.py | 4 ++-- fail2ban/server/filter.py | 4 ++-- fail2ban/server/filtergamin.py | 4 ++-- fail2ban/server/filterpoll.py | 4 ++-- fail2ban/server/filterpyinotify.py | 4 ++-- fail2ban/server/filtersystemd.py | 4 ++-- fail2ban/server/jail.py | 4 ++-- fail2ban/server/server.py | 12 ++++++------ fail2ban/server/ticket.py | 4 ++-- fail2ban/server/transmitter.py | 4 ++-- fail2ban/tests/misctestcase.py | 4 ++-- fail2ban/tests/servertestcase.py | 7 +++---- fail2ban/tests/utils.py | 8 ++++---- 35 files changed, 80 insertions(+), 80 deletions(-) diff --git a/bin/fail2ban-client b/bin/fail2ban-client index b9713153..89e0a903 100755 --- a/bin/fail2ban-client +++ b/bin/fail2ban-client @@ -30,9 +30,10 @@ from fail2ban.protocol import printFormatted from fail2ban.client.csocket import CSocket from fail2ban.client.configurator import Configurator from fail2ban.client.beautifier import Beautifier +from fail2ban.helpers import getLogger # Gets the instance of the logger. -logSys = logging.getLogger("fail2ban") +logSys = getLogger("fail2ban") ## # diff --git a/bin/fail2ban-regex b/bin/fail2ban-regex index 3a887867..ff7e2fb7 100755 --- a/bin/fail2ban-regex +++ b/bin/fail2ban-regex @@ -45,9 +45,9 @@ from fail2ban.client.filterreader import FilterReader from fail2ban.server.filter import Filter from fail2ban.server.failregex import RegexException -from fail2ban.helpers import FormatterWithTraceBack +from fail2ban.helpers import FormatterWithTraceBack, getLogger # Gets the instance of the logger. -logSys = logging.getLogger("fail2ban") +logSys = getLogger("fail2ban") def debuggexURL(sample, regex): q = urllib.urlencode({ 're': regex.replace('', '(?&.ipv4)'), diff --git a/bin/fail2ban-server b/bin/fail2ban-server index aba19ab5..ec0c0dbe 100755 --- a/bin/fail2ban-server +++ b/bin/fail2ban-server @@ -22,13 +22,14 @@ __author__ = "Cyril Jaquier" __copyright__ = "Copyright (c) 2004 Cyril Jaquier" __license__ = "GPL" -import getopt, sys, logging, os +import getopt, sys, os from fail2ban.version import version from fail2ban.server.server import Server +from fail2ban.helpers import getLogger # Gets the instance of the logger. -logSys = logging.getLogger("fail2ban") +logSys = getLogger("fail2ban") ## # \mainpage Fail2Ban diff --git a/bin/fail2ban-testcases b/bin/fail2ban-testcases index 0e2fdb4b..8b1343a3 100755 --- a/bin/fail2ban-testcases +++ b/bin/fail2ban-testcases @@ -25,7 +25,7 @@ __copyright__ = "Copyright (c) 2004 Cyril Jaquier, 2012- Yaroslav Halchenko" __license__ = "GPL" -import unittest, logging, sys, time, os +import unittest, sys, time, os # Check if local fail2ban module exists, and use if it exists by # modifying the path. This is such that tests can be used in dev @@ -35,7 +35,7 @@ if os.path.exists("fail2ban/__init__.py"): from fail2ban.version import version from fail2ban.tests.utils import gatherTests -from fail2ban.helpers import FormatterWithTraceBack +from fail2ban.helpers import FormatterWithTraceBack, getLogger from fail2ban.server.mytime import MyTime from optparse import OptionParser, Option @@ -70,7 +70,7 @@ parser = get_opt_parser() # # Logging # -logSys = logging.getLogger("fail2ban") +logSys = getLogger("fail2ban") # Numerical level of verbosity corresponding to a log "level" verbosity = {'heavydebug': 4, diff --git a/fail2ban/client/actionreader.py b/fail2ban/client/actionreader.py index 07572930..91f3322b 100644 --- a/fail2ban/client/actionreader.py +++ b/fail2ban/client/actionreader.py @@ -27,10 +27,10 @@ __license__ = "GPL" import os from .configreader import ConfigReader, DefinitionInitConfigReader -from ..helpers import getF2BLogger +from ..helpers import getLogger # Gets the instance of the logger. -logSys = getF2BLogger(__name__) +logSys = getLogger(__name__) class ActionReader(DefinitionInitConfigReader): diff --git a/fail2ban/client/beautifier.py b/fail2ban/client/beautifier.py index 070c80c5..cf17e54f 100644 --- a/fail2ban/client/beautifier.py +++ b/fail2ban/client/beautifier.py @@ -22,10 +22,10 @@ __copyright__ = "Copyright (c) 2004 Cyril Jaquier, 2013- Yaroslav Halchenko" __license__ = "GPL" from ..exceptions import UnknownJailException, DuplicateJailException -from ..helpers import getF2BLogger +from ..helpers import getLogger # Gets the instance of the logger. -logSys = getF2BLogger(__name__) +logSys = getLogger(__name__) ## # Beautify the output of the client. diff --git a/fail2ban/client/configparserinc.py b/fail2ban/client/configparserinc.py index 1be786c7..80b99517 100644 --- a/fail2ban/client/configparserinc.py +++ b/fail2ban/client/configparserinc.py @@ -25,7 +25,7 @@ __copyright__ = 'Copyright (c) 2007 Yaroslav Halchenko' __license__ = 'GPL' import os, sys -from ..helpers import getF2BLogger +from ..helpers import getLogger if sys.version_info >= (3,2): # pragma: no cover @@ -61,7 +61,7 @@ else: # pragma: no cover from ConfigParser import SafeConfigParser # Gets the instance of the logger. -logSys = getF2BLogger(__name__) +logSys = getLogger(__name__) __all__ = ['SafeConfigParserWithIncludes'] diff --git a/fail2ban/client/configreader.py b/fail2ban/client/configreader.py index e905b278..22115d3a 100644 --- a/fail2ban/client/configreader.py +++ b/fail2ban/client/configreader.py @@ -28,10 +28,10 @@ import glob, os from ConfigParser import NoOptionError, NoSectionError from .configparserinc import SafeConfigParserWithIncludes -from ..helpers import getF2BLogger +from ..helpers import getLogger # Gets the instance of the logger. -logSys = getF2BLogger(__name__) +logSys = getLogger(__name__) class ConfigReader(SafeConfigParserWithIncludes): diff --git a/fail2ban/client/configurator.py b/fail2ban/client/configurator.py index 23c21c4b..0dd9f955 100644 --- a/fail2ban/client/configurator.py +++ b/fail2ban/client/configurator.py @@ -26,10 +26,10 @@ __license__ = "GPL" from .fail2banreader import Fail2banReader from .jailsreader import JailsReader -from ..helpers import getF2BLogger +from ..helpers import getLogger # Gets the instance of the logger. -logSys = getF2BLogger(__name__) +logSys = getLogger(__name__) class Configurator: diff --git a/fail2ban/client/fail2banreader.py b/fail2ban/client/fail2banreader.py index 4d106f3a..361a5e54 100644 --- a/fail2ban/client/fail2banreader.py +++ b/fail2ban/client/fail2banreader.py @@ -25,10 +25,10 @@ __copyright__ = "Copyright (c) 2004 Cyril Jaquier" __license__ = "GPL" from .configreader import ConfigReader -from ..helpers import getF2BLogger +from ..helpers import getLogger # Gets the instance of the logger. -logSys = getF2BLogger(__name__) +logSys = getLogger(__name__) class Fail2banReader(ConfigReader): diff --git a/fail2ban/client/filterreader.py b/fail2ban/client/filterreader.py index 2f5b3b05..40d74c45 100644 --- a/fail2ban/client/filterreader.py +++ b/fail2ban/client/filterreader.py @@ -28,10 +28,10 @@ import os, shlex from .configreader import ConfigReader, DefinitionInitConfigReader from ..server.action import CommandAction -from ..helpers import getF2BLogger +from ..helpers import getLogger # Gets the instance of the logger. -logSys = getF2BLogger(__name__) +logSys = getLogger(__name__) class FilterReader(DefinitionInitConfigReader): diff --git a/fail2ban/client/jailreader.py b/fail2ban/client/jailreader.py index 6207d8f4..a4bf5174 100644 --- a/fail2ban/client/jailreader.py +++ b/fail2ban/client/jailreader.py @@ -30,10 +30,10 @@ import json from .configreader import ConfigReader from .filterreader import FilterReader from .actionreader import ActionReader -from ..helpers import getF2BLogger +from ..helpers import getLogger # Gets the instance of the logger. -logSys = getF2BLogger(__name__) +logSys = getLogger(__name__) class JailReader(ConfigReader): diff --git a/fail2ban/client/jailsreader.py b/fail2ban/client/jailsreader.py index 86fd501f..84c614b9 100644 --- a/fail2ban/client/jailsreader.py +++ b/fail2ban/client/jailsreader.py @@ -26,10 +26,10 @@ __license__ = "GPL" from .configreader import ConfigReader from .jailreader import JailReader -from ..helpers import getF2BLogger +from ..helpers import getLogger # Gets the instance of the logger. -logSys = getF2BLogger(__name__) +logSys = getLogger(__name__) class JailsReader(ConfigReader): diff --git a/fail2ban/helpers.py b/fail2ban/helpers.py index 35c7ebc3..2c810878 100644 --- a/fail2ban/helpers.py +++ b/fail2ban/helpers.py @@ -108,7 +108,7 @@ class FormatterWithTraceBack(logging.Formatter): record.tbc = record.tb = self._tb() return logging.Formatter.format(self, record) -def getF2BLogger(name): +def getLogger(name): """Get logging.Logger instance with Fail2Ban logger name convention """ return logging.getLogger("fail2ban.%s" % name.rpartition(".")[-1]) @@ -116,6 +116,6 @@ def getF2BLogger(name): def fail2ban_excepthook(exctype, value, traceback): """Except hook used to log unhandled exceptions to Fail2Ban log """ - logging.getLogger("fail2ban").critical( + getLogger("fail2ban").critical( "Unhandled exception in Fail2Ban:", exc_info=True) return sys.__excepthook__(exctype, value, traceback) diff --git a/fail2ban/server/action.py b/fail2ban/server/action.py index ea7bc91c..e1bd719a 100644 --- a/fail2ban/server/action.py +++ b/fail2ban/server/action.py @@ -26,10 +26,10 @@ import threading, re from abc import ABCMeta from collections import MutableMapping -from ..helpers import getF2BLogger +from ..helpers import getLogger # Gets the instance of the logger. -logSys = getF2BLogger(__name__) +logSys = getLogger(__name__) # Create a lock for running system commands _cmd_lock = threading.Lock() @@ -136,8 +136,7 @@ class ActionBase(object): def __init__(self, jail, name): self._jail = jail self._name = name - self._logSys = logging.getLogger( - "fail2ban.%s" % self.__class__.__name__) + self._logSys = getLogger("fail2ban.%s" % self.__class__.__name__) def start(self): """Executed when the jail/action is started. diff --git a/fail2ban/server/actions.py b/fail2ban/server/actions.py index 467df510..86a47743 100644 --- a/fail2ban/server/actions.py +++ b/fail2ban/server/actions.py @@ -41,10 +41,10 @@ from .banmanager import BanManager from .jailthread import JailThread from .action import ActionBase, CommandAction, CallingMap from .mytime import MyTime -from ..helpers import getF2BLogger +from ..helpers import getLogger # Gets the instance of the logger. -logSys = getF2BLogger(__name__) +logSys = getLogger(__name__) class Actions(JailThread, Mapping): """Handles jail actions. diff --git a/fail2ban/server/asyncserver.py b/fail2ban/server/asyncserver.py index 326e35cb..14673a99 100644 --- a/fail2ban/server/asyncserver.py +++ b/fail2ban/server/asyncserver.py @@ -27,10 +27,10 @@ __license__ = "GPL" from pickle import dumps, loads, HIGHEST_PROTOCOL import asyncore, asynchat, socket, os, sys, traceback, fcntl -from ..helpers import getF2BLogger,formatExceptionInfo +from ..helpers import getLogger,formatExceptionInfo # Gets the instance of the logger. -logSys = getF2BLogger(__name__) +logSys = getLogger(__name__) if sys.version_info >= (3,): # b"" causes SyntaxError in python <= 2.5, so below implements equivalent diff --git a/fail2ban/server/banmanager.py b/fail2ban/server/banmanager.py index 68954b9c..b24fa9e5 100644 --- a/fail2ban/server/banmanager.py +++ b/fail2ban/server/banmanager.py @@ -28,10 +28,10 @@ from threading import Lock from .ticket import BanTicket from .mytime import MyTime -from ..helpers import getF2BLogger +from ..helpers import getLogger # Gets the instance of the logger. -logSys = getF2BLogger(__name__) +logSys = getLogger(__name__) ## # Banning Manager. diff --git a/fail2ban/server/database.py b/fail2ban/server/database.py index 24a3a327..51161911 100644 --- a/fail2ban/server/database.py +++ b/fail2ban/server/database.py @@ -31,10 +31,10 @@ from threading import Lock from .mytime import MyTime from .ticket import FailTicket -from ..helpers import getF2BLogger +from ..helpers import getLogger # Gets the instance of the logger. -logSys = getF2BLogger(__name__) +logSys = getLogger(__name__) if sys.version_info >= (3,): sqlite3.register_adapter( diff --git a/fail2ban/server/datedetector.py b/fail2ban/server/datedetector.py index 8d3ccaf2..fe5282fd 100644 --- a/fail2ban/server/datedetector.py +++ b/fail2ban/server/datedetector.py @@ -24,10 +24,10 @@ __license__ = "GPL" from threading import Lock from .datetemplate import DatePatternRegex, DateTai64n, DateEpoch -from ..helpers import getF2BLogger +from ..helpers import getLogger # Gets the instance of the logger. -logSys = getF2BLogger(__name__) +logSys = getLogger(__name__) class DateDetector(object): """Manages one or more date templates to find a date within a log line. diff --git a/fail2ban/server/datetemplate.py b/fail2ban/server/datetemplate.py index 0e6141e5..a5179ed1 100644 --- a/fail2ban/server/datetemplate.py +++ b/fail2ban/server/datetemplate.py @@ -28,9 +28,9 @@ import re from abc import abstractmethod from .strptime import reGroupDictStrptime, timeRE -from ..helpers import getF2BLogger +from ..helpers import getLogger -logSys = getF2BLogger(__name__) +logSys = getLogger(__name__) class DateTemplate(object): diff --git a/fail2ban/server/faildata.py b/fail2ban/server/faildata.py index 328bdb07..91aaa1ee 100644 --- a/fail2ban/server/faildata.py +++ b/fail2ban/server/faildata.py @@ -24,10 +24,10 @@ __author__ = "Cyril Jaquier" __copyright__ = "Copyright (c) 2004 Cyril Jaquier" __license__ = "GPL" -from ..helpers import getF2BLogger +from ..helpers import getLogger # Gets the instance of the logger. -logSys = getF2BLogger(__name__) +logSys = getLogger(__name__) class FailData: diff --git a/fail2ban/server/failmanager.py b/fail2ban/server/failmanager.py index 75b505c9..353f7135 100644 --- a/fail2ban/server/failmanager.py +++ b/fail2ban/server/failmanager.py @@ -29,10 +29,10 @@ import logging from .faildata import FailData from .ticket import FailTicket -from ..helpers import getF2BLogger +from ..helpers import getLogger # Gets the instance of the logger. -logSys = getF2BLogger(__name__) +logSys = getLogger(__name__) class FailManager: diff --git a/fail2ban/server/filter.py b/fail2ban/server/filter.py index ec60ed15..d1c9d2ad 100644 --- a/fail2ban/server/filter.py +++ b/fail2ban/server/filter.py @@ -31,10 +31,10 @@ from .datetemplate import DatePatternRegex, DateEpoch, DateTai64n from .mytime import MyTime from .failregex import FailRegex, Regex, RegexException from .action import CommandAction -from ..helpers import getF2BLogger +from ..helpers import getLogger # Gets the instance of the logger. -logSys = getF2BLogger(__name__) +logSys = getLogger(__name__) ## # Log reader class. diff --git a/fail2ban/server/filtergamin.py b/fail2ban/server/filtergamin.py index f6d13d5d..c9e8e31c 100644 --- a/fail2ban/server/filtergamin.py +++ b/fail2ban/server/filtergamin.py @@ -30,10 +30,10 @@ import gamin from .failmanager import FailManagerEmpty from .filter import FileFilter from .mytime import MyTime -from ..helpers import getF2BLogger +from ..helpers import getLogger # Gets the instance of the logger. -logSys = getF2BLogger(__name__) +logSys = getLogger(__name__) ## # Log reader class. diff --git a/fail2ban/server/filterpoll.py b/fail2ban/server/filterpoll.py index a94b7cb8..f37be431 100644 --- a/fail2ban/server/filterpoll.py +++ b/fail2ban/server/filterpoll.py @@ -29,10 +29,10 @@ import time, os from .failmanager import FailManagerEmpty from .filter import FileFilter from .mytime import MyTime -from ..helpers import getF2BLogger +from ..helpers import getLogger # Gets the instance of the logger. -logSys = getF2BLogger(__name__) +logSys = getLogger(__name__) ## # Log reader class. diff --git a/fail2ban/server/filterpyinotify.py b/fail2ban/server/filterpyinotify.py index 68cb9b0f..784a7e53 100644 --- a/fail2ban/server/filterpyinotify.py +++ b/fail2ban/server/filterpyinotify.py @@ -32,7 +32,7 @@ import pyinotify from .failmanager import FailManagerEmpty from .filter import FileFilter from .mytime import MyTime -from ..helpers import getF2BLogger +from ..helpers import getLogger if not hasattr(pyinotify, '__version__') \ @@ -49,7 +49,7 @@ except Exception, e: % str(e)) # Gets the instance of the logger. -logSys = getF2BLogger(__name__) +logSys = getLogger(__name__) ## # Log reader class. diff --git a/fail2ban/server/filtersystemd.py b/fail2ban/server/filtersystemd.py index 71dde126..ce89d65a 100644 --- a/fail2ban/server/filtersystemd.py +++ b/fail2ban/server/filtersystemd.py @@ -32,10 +32,10 @@ if LooseVersion(getattr(journal, '__version__', "0")) < '204': from .failmanager import FailManagerEmpty from .filter import JournalFilter from .mytime import MyTime -from ..helpers import getF2BLogger +from ..helpers import getLogger # Gets the instance of the logger. -logSys = getF2BLogger(__name__) +logSys = getLogger(__name__) ## # Journal reader class. diff --git a/fail2ban/server/jail.py b/fail2ban/server/jail.py index 5c1c4e70..e48e5d7b 100644 --- a/fail2ban/server/jail.py +++ b/fail2ban/server/jail.py @@ -26,10 +26,10 @@ __license__ = "GPL" import Queue, logging from .actions import Actions -from ..helpers import getF2BLogger +from ..helpers import getLogger # Gets the instance of the logger. -logSys = getF2BLogger(__name__) +logSys = getLogger(__name__) class Jail: """Fail2Ban jail, which manages a filter and associated actions. diff --git a/fail2ban/server/server.py b/fail2ban/server/server.py index a6be18ac..8efb2c59 100644 --- a/fail2ban/server/server.py +++ b/fail2ban/server/server.py @@ -32,10 +32,10 @@ from .filter import FileFilter, JournalFilter from .transmitter import Transmitter from .asyncserver import AsyncServer, AsyncServerException from .. import version -from ..helpers import getF2BLogger, fail2ban_excepthook +from ..helpers import getLogger, fail2ban_excepthook # Gets the instance of the logger. -logSys = getF2BLogger(__name__) +logSys = getLogger(__name__) try: from .database import Fail2BanDb @@ -339,7 +339,7 @@ class Server: def setLogLevel(self, value): try: self.__loggingLock.acquire() - logging.getLogger("fail2ban").setLevel( + getLogger("fail2ban").setLevel( getattr(logging, value.upper())) except AttributeError: raise ValueError("Invalid log level") @@ -392,7 +392,7 @@ class Server: return False # Removes previous handlers -- in reverse order since removeHandler # alter the list in-place and that can confuses the iterable - logger = logging.getLogger("fail2ban") + logger = getLogger("fail2ban") for handler in logger.handlers[::-1]: # Remove the handler. logger.removeHandler(handler) @@ -429,7 +429,7 @@ class Server: def flushLogs(self): if self.__logTarget not in ['STDERR', 'STDOUT', 'SYSLOG']: - for handler in logging.getLogger("fail2ban").handlers: + for handler in getLogger("fail2ban").handlers: try: handler.doRollover() logSys.info("rollover performed on %s" % self.__logTarget) @@ -438,7 +438,7 @@ class Server: logSys.info("flush performed on %s" % self.__logTarget) return "rolled over" else: - for handler in logging.getLogger("fail2ban").handlers: + for handler in getLogger("fail2ban").handlers: handler.flush() logSys.info("flush performed on %s" % self.__logTarget) return "flushed" diff --git a/fail2ban/server/ticket.py b/fail2ban/server/ticket.py index a216e9ed..329b3831 100644 --- a/fail2ban/server/ticket.py +++ b/fail2ban/server/ticket.py @@ -24,10 +24,10 @@ __author__ = "Cyril Jaquier" __copyright__ = "Copyright (c) 2004 Cyril Jaquier" __license__ = "GPL" -from ..helpers import getF2BLogger +from ..helpers import getLogger # Gets the instance of the logger. -logSys = getF2BLogger(__name__) +logSys = getLogger(__name__) class Ticket: diff --git a/fail2ban/server/transmitter.py b/fail2ban/server/transmitter.py index b5edf367..0cd30515 100644 --- a/fail2ban/server/transmitter.py +++ b/fail2ban/server/transmitter.py @@ -27,10 +27,10 @@ __license__ = "GPL" import time import json -from ..helpers import getF2BLogger +from ..helpers import getLogger # Gets the instance of the logger. -logSys = getF2BLogger(__name__) +logSys = getLogger(__name__) class Transmitter: diff --git a/fail2ban/tests/misctestcase.py b/fail2ban/tests/misctestcase.py index ca84eba7..64b6b65e 100644 --- a/fail2ban/tests/misctestcase.py +++ b/fail2ban/tests/misctestcase.py @@ -32,7 +32,7 @@ import datetime from glob import glob from StringIO import StringIO -from ..helpers import formatExceptionInfo, mbasename, TraceBack, FormatterWithTraceBack +from ..helpers import formatExceptionInfo, mbasename, TraceBack, FormatterWithTraceBack, getLogger from ..server.datetemplate import DatePatternRegex @@ -159,7 +159,7 @@ class TestsUtilsTest(unittest.TestCase): # and both types of traceback at once fmt = ' %(tb)s | %(tbc)s : %(message)s' - logSys = logging.getLogger("fail2ban_tests") + logSys = getLogger("fail2ban_tests") out = logging.StreamHandler(strout) out.setFormatter(Formatter(fmt)) logSys.addHandler(out) diff --git a/fail2ban/tests/servertestcase.py b/fail2ban/tests/servertestcase.py index 6ce6e54f..9b78fda8 100644 --- a/fail2ban/tests/servertestcase.py +++ b/fail2ban/tests/servertestcase.py @@ -30,14 +30,13 @@ import tempfile import os import locale import sys -import logging from ..server.failregex import Regex, FailRegex, RegexException from ..server.server import Server from ..server.jail import Jail from ..server.jailthread import JailThread from .utils import LogCaptureTestCase -from ..helpers import getF2BLogger +from ..helpers import getLogger try: from ..server import filtersystemd @@ -725,7 +724,7 @@ class TransmitterLogging(TransmitterBase): os.close(f) self.server.setLogLevel("WARNING") self.assertEqual(self.transm.proceed(["set", "logtarget", fn]), (0, fn)) - l = logging.getLogger('fail2ban') + l = getLogger('fail2ban') l.warning("Before file moved") try: f2, fn2 = tempfile.mkstemp("fail2ban.log") @@ -806,7 +805,7 @@ class _BadThread(JailThread): class LoggingTests(LogCaptureTestCase): def testGetF2BLogger(self): - testLogSys = getF2BLogger("fail2ban.some.string.with.name") + testLogSys = getLogger("fail2ban.some.string.with.name") self.assertEqual(testLogSys.parent.name, "fail2ban") self.assertEqual(testLogSys.name, "fail2ban.name") diff --git a/fail2ban/tests/utils.py b/fail2ban/tests/utils.py index f35685a4..0cb8d5b8 100644 --- a/fail2ban/tests/utils.py +++ b/fail2ban/tests/utils.py @@ -30,9 +30,9 @@ import unittest from StringIO import StringIO from ..server.mytime import MyTime -from ..helpers import getF2BLogger +from ..helpers import getLogger -logSys = getF2BLogger(__name__) +logSys = getLogger(__name__) def mtimesleep(): # no sleep now should be necessary since polling tracks now not only @@ -187,7 +187,7 @@ class LogCaptureTestCase(unittest.TestCase): # For extended testing of what gets output into logging # system, we will redirect it to a string - logSys = logging.getLogger("fail2ban") + logSys = getLogger("fail2ban") # Keep old settings self._old_level = logSys.level @@ -200,7 +200,7 @@ class LogCaptureTestCase(unittest.TestCase): def tearDown(self): """Call after every test case.""" # print "O: >>%s<<" % self._log.getvalue() - logSys = logging.getLogger("fail2ban") + logSys = getLogger("fail2ban") logSys.handlers = self._old_handlers logSys.level = self._old_level From 9764c78415e7776c0cffdd306e29180336ef9f35 Mon Sep 17 00:00:00 2001 From: Steven Hiscocks Date: Tue, 10 Jun 2014 20:38:18 +0100 Subject: [PATCH 04/13] ENH: Rename fail2ban_excepthook to excepthook --- fail2ban/helpers.py | 2 +- fail2ban/server/jailthread.py | 4 ++-- fail2ban/server/server.py | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/fail2ban/helpers.py b/fail2ban/helpers.py index 2c810878..7ba8a72a 100644 --- a/fail2ban/helpers.py +++ b/fail2ban/helpers.py @@ -113,7 +113,7 @@ def getLogger(name): """ return logging.getLogger("fail2ban.%s" % name.rpartition(".")[-1]) -def fail2ban_excepthook(exctype, value, traceback): +def excepthook(exctype, value, traceback): """Except hook used to log unhandled exceptions to Fail2Ban log """ getLogger("fail2ban").critical( diff --git a/fail2ban/server/jailthread.py b/fail2ban/server/jailthread.py index 4f640f8b..2627cebf 100644 --- a/fail2ban/server/jailthread.py +++ b/fail2ban/server/jailthread.py @@ -28,7 +28,7 @@ import sys from threading import Thread from abc import abstractproperty, abstractmethod -from ..helpers import fail2ban_excepthook +from ..helpers import excepthook class JailThread(Thread): """Abstract class for threading elements in Fail2Ban. @@ -63,7 +63,7 @@ class JailThread(Thread): try: run(*args, **kwargs) except: - fail2ban_excepthook(*sys.exc_info()) + excepthook(*sys.exc_info()) self.run = run_with_except_hook @abstractproperty diff --git a/fail2ban/server/server.py b/fail2ban/server/server.py index 8efb2c59..02f3423b 100644 --- a/fail2ban/server/server.py +++ b/fail2ban/server/server.py @@ -32,7 +32,7 @@ from .filter import FileFilter, JournalFilter from .transmitter import Transmitter from .asyncserver import AsyncServer, AsyncServerException from .. import version -from ..helpers import getLogger, fail2ban_excepthook +from ..helpers import getLogger, excepthook # Gets the instance of the logger. logSys = getLogger(__name__) @@ -71,7 +71,7 @@ class Server: signal.signal(signal.SIGINT, self.__sigTERMhandler) # Ensure unhandled exceptions are logged - sys.excepthook = fail2ban_excepthook + sys.excepthook = excepthook # First set the mask to only allow access to owner os.umask(0077) From 664f1db0ba77a6be6e020f5fb2d4e7f5a4af0b14 Mon Sep 17 00:00:00 2001 From: Steven Hiscocks Date: Tue, 10 Jun 2014 20:58:57 +0100 Subject: [PATCH 05/13] BF: Fix getLogger for single level log level names --- fail2ban/helpers.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/fail2ban/helpers.py b/fail2ban/helpers.py index 7ba8a72a..cecd3f31 100644 --- a/fail2ban/helpers.py +++ b/fail2ban/helpers.py @@ -111,7 +111,9 @@ class FormatterWithTraceBack(logging.Formatter): def getLogger(name): """Get logging.Logger instance with Fail2Ban logger name convention """ - return logging.getLogger("fail2ban.%s" % name.rpartition(".")[-1]) + if "." in name: + name = "fail2ban.%s" % name.rpartition(".")[-1] + return logging.getLogger(name) def excepthook(exctype, value, traceback): """Except hook used to log unhandled exceptions to Fail2Ban log From 1e1c4ac62a2bb4cc693c963c2ba794c6666cd730 Mon Sep 17 00:00:00 2001 From: SATO Kentaro Date: Mon, 16 Jun 2014 21:15:03 +0900 Subject: [PATCH 06/13] ENH: Add to iptables-ipsets. --- ChangeLog | 1 + THANKS | 1 + config/action.d/iptables-ipset-proto4.conf | 10 ++++++++-- config/action.d/iptables-ipset-proto6-allports.conf | 10 ++++++++-- config/action.d/iptables-ipset-proto6.conf | 10 ++++++++-- 5 files changed, 26 insertions(+), 6 deletions(-) diff --git a/ChangeLog b/ChangeLog index d4ea774a..2aeb2fb0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -38,6 +38,7 @@ ver. 0.9.1 (2014/xx/xx) - better, faster, stronger * Fail2ban-regex - add print-all-matched option. Closes gh-652 * Suppress fail2ban-client warnings for non-critical config options * Match non "Bye Bye" disconnect messages for sshd locked account regex + * Add tag to iptables-ipsets. ver. 0.9.0 (2014/03/14) - beta ---------- diff --git a/THANKS b/THANKS index 27165492..08079490 100644 --- a/THANKS +++ b/THANKS @@ -85,6 +85,7 @@ Robert Edeker Rolf Fokkens Roman Gelfand Russell Odom +SATO Kentaro Sebastian Arcus Sireyessire silviogarbes diff --git a/config/action.d/iptables-ipset-proto4.conf b/config/action.d/iptables-ipset-proto4.conf index fc03c68c..4714f0df 100644 --- a/config/action.d/iptables-ipset-proto4.conf +++ b/config/action.d/iptables-ipset-proto4.conf @@ -28,13 +28,13 @@ before = iptables-blocktype.conf # Values: CMD # actionstart = ipset --create f2b- iphash - iptables -I INPUT -p -m multiport --dports -m set --match-set f2b- src -j + iptables -I -p -m multiport --dports -m set --match-set f2b- src -j # Option: actionstop # Notes.: command executed once at the end of Fail2Ban # Values: CMD # -actionstop = iptables -D INPUT -p -m multiport --dports -m set --match-set f2b- src -j +actionstop = iptables -D -p -m multiport --dports -m set --match-set f2b- src -j ipset --flush f2b- ipset --destroy f2b- @@ -60,6 +60,12 @@ actionunban = ipset --test f2b- && ipset --del f2b- # name = default +# Option: chain +# Notes specifies the iptables chain to which the Fail2Ban rules should be +# added +# Values: STRING Default: INPUT +chain = INPUT + # Option: port # Notes.: specifies port to monitor # Values: [ NUM | STRING ] Default: ssh diff --git a/config/action.d/iptables-ipset-proto6-allports.conf b/config/action.d/iptables-ipset-proto6-allports.conf index 72fba9cd..a3726873 100644 --- a/config/action.d/iptables-ipset-proto6-allports.conf +++ b/config/action.d/iptables-ipset-proto6-allports.conf @@ -25,13 +25,13 @@ before = iptables-blocktype.conf # Values: CMD # actionstart = ipset create f2b- hash:ip timeout - iptables -I INPUT -m set --match-set f2b- src -j + iptables -I -m set --match-set f2b- src -j # Option: actionstop # Notes.: command executed once at the end of Fail2Ban # Values: CMD # -actionstop = iptables -D INPUT -m set --match-set f2b- src -j +actionstop = iptables -D -m set --match-set f2b- src -j ipset flush f2b- ipset destroy f2b- @@ -57,6 +57,12 @@ actionunban = ipset del f2b- -exist # name = default +# Option: chain +# Notes specifies the iptables chain to which the Fail2Ban rules should be +# added +# Values: STRING Default: INPUT +chain = INPUT + # Option: bantime # Notes: specifies the bantime in seconds (handled internally rather than by fail2ban) # Values: [ NUM ] Default: 600 diff --git a/config/action.d/iptables-ipset-proto6.conf b/config/action.d/iptables-ipset-proto6.conf index 5d848110..a3081ea0 100644 --- a/config/action.d/iptables-ipset-proto6.conf +++ b/config/action.d/iptables-ipset-proto6.conf @@ -25,13 +25,13 @@ before = iptables-blocktype.conf # Values: CMD # actionstart = ipset create f2b- hash:ip timeout - iptables -I INPUT -p -m multiport --dports -m set --match-set f2b- src -j + iptables -I -p -m multiport --dports -m set --match-set f2b- src -j # Option: actionstop # Notes.: command executed once at the end of Fail2Ban # Values: CMD # -actionstop = iptables -D INPUT -p -m multiport --dports -m set --match-set f2b- src -j +actionstop = iptables -D -p -m multiport --dports -m set --match-set f2b- src -j ipset flush f2b- ipset destroy f2b- @@ -57,6 +57,12 @@ actionunban = ipset del f2b- -exist # name = default +# Option: chain +# Notes specifies the iptables chain to which the Fail2Ban rules should be +# added +# Values: STRING Default: INPUT +chain = INPUT + # Option: port # Notes.: specifies port to monitor # Values: [ NUM | STRING ] Default: ssh From 8268c1641f968d553141236803f2b2467a477071 Mon Sep 17 00:00:00 2001 From: Steven Hiscocks Date: Tue, 17 Jun 2014 23:24:23 +0100 Subject: [PATCH 07/13] BF: aInfo could be modified by actions, causing unexpected behaviour A separate copy of aInfo is passed to each action --- config/action.d/smtp.py | 2 +- fail2ban/server/action.py | 6 ++++++ fail2ban/server/actions.py | 14 ++++++++------ 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/config/action.d/smtp.py b/config/action.d/smtp.py index 2d0add8e..86857616 100644 --- a/config/action.d/smtp.py +++ b/config/action.d/smtp.py @@ -45,7 +45,7 @@ messages['ban'] = {} messages['ban']['head'] = \ """Hi, -The IP %(ip)s has just been banned for %(bantime)s seconds +The IP %(ip)s has just been banned for %(bantime)i seconds by Fail2Ban after %(failures)i attempts against %(jailname)s. """ messages['ban']['tail'] = \ diff --git a/fail2ban/server/action.py b/fail2ban/server/action.py index fefe2c2c..7464e008 100644 --- a/fail2ban/server/action.py +++ b/fail2ban/server/action.py @@ -68,6 +68,9 @@ class CallingMap(MutableMapping): def __init__(self, *args, **kwargs): self.data = dict(*args, **kwargs) + def __repr__(self): + return "%s(%r)" % (self.__class__.__name__, self.data) + def __getitem__(self, key): value = self.data[key] if callable(value): @@ -87,6 +90,9 @@ class CallingMap(MutableMapping): def __len__(self): return len(self.data) + def copy(self): + return self.__class__(self.data.copy()) + class ActionBase(object): """An abstract base class for actions in Fail2Ban. diff --git a/fail2ban/server/actions.py b/fail2ban/server/actions.py index dd68ac13..77cc208d 100644 --- a/fail2ban/server/actions.py +++ b/fail2ban/server/actions.py @@ -273,11 +273,12 @@ class Actions(JailThread, Mapping): logSys.notice("[%s] Ban %s" % (self._jail.name, aInfo["ip"])) for name, action in self._actions.iteritems(): try: - action.ban(aInfo) + action.ban(aInfo.copy()) except Exception as e: logSys.error( - "Failed to execute ban jail '%s' action '%s': %s", - self._jail.name, name, e, + "Failed to execute ban jail '%s' action '%s' " + "info '%r': %s", + self._jail.name, name, aInfo, e, exc_info=logSys.getEffectiveLevel()<=logging.DEBUG) return True else: @@ -321,11 +322,12 @@ class Actions(JailThread, Mapping): logSys.notice("[%s] Unban %s" % (self._jail.name, aInfo["ip"])) for name, action in self._actions.iteritems(): try: - action.unban(aInfo) + action.unban(aInfo.copy()) except Exception as e: logSys.error( - "Failed to execute unban jail '%s' action '%s': %s", - self._jail.name, name, e, + "Failed to execute unban jail '%s' action '%s' " + "info '%r': %s", + self._jail.name, name, aInfo, e, exc_info=logSys.getEffectiveLevel()<=logging.DEBUG) @property From 65ff3e960498fc78282787ca5a4bbe1c2604f8f2 Mon Sep 17 00:00:00 2001 From: SATO Kentaro Date: Wed, 18 Jun 2014 19:04:57 +0900 Subject: [PATCH 08/13] ENH: Introduce iptables-common.conf. --- MANIFEST | 2 +- config/action.d/firewallcmd-ipset.conf | 18 +------- config/action.d/firewallcmd-new.conf | 18 +------- config/action.d/iptables-allports.conf | 17 +------ config/action.d/iptables-blocktype.conf | 22 --------- config/action.d/iptables-common.conf | 45 +++++++++++++++++++ config/action.d/iptables-ipset-proto4.conf | 23 +--------- .../iptables-ipset-proto6-allports.conf | 15 +------ config/action.d/iptables-ipset-proto6.conf | 27 +---------- config/action.d/iptables-multiport-log.conf | 23 +--------- config/action.d/iptables-multiport.conf | 23 +--------- config/action.d/iptables-new.conf | 24 +--------- config/action.d/iptables-xt_recent-echo.conf | 16 ++----- config/action.d/iptables.conf | 23 +--------- 14 files changed, 61 insertions(+), 235 deletions(-) delete mode 100644 config/action.d/iptables-blocktype.conf create mode 100644 config/action.d/iptables-common.conf diff --git a/MANIFEST b/MANIFEST index 7df49199..92edcca8 100644 --- a/MANIFEST +++ b/MANIFEST @@ -258,7 +258,7 @@ config/action.d/dummy.conf config/action.d/firewallcmd-new.conf config/action.d/firewallcmd-ipset.conf config/action.d/iptables-ipset-proto6-allports.conf -config/action.d/iptables-blocktype.conf +config/action.d/iptables-common.conf config/action.d/iptables-ipset-proto4.conf config/action.d/iptables-ipset-proto6.conf config/action.d/iptables-xt_recent-echo.conf diff --git a/config/action.d/firewallcmd-ipset.conf b/config/action.d/firewallcmd-ipset.conf index 03e30c3c..38b0f3d3 100644 --- a/config/action.d/firewallcmd-ipset.conf +++ b/config/action.d/firewallcmd-ipset.conf @@ -14,7 +14,7 @@ [INCLUDES] -before = iptables-blocktype.conf +before = iptables-common.conf [Definition] @@ -31,22 +31,6 @@ actionunban = ipset del fail2ban- -exist [Init] -# Default name of the chain -# -name = default - -# Option: port -# Notes.: specifies port to monitor -# Values: [ NUM | STRING ] -# -port = ssh - -# Option: protocol -# Notes.: internally used by config reader for interpolations. -# Values: [ tcp | udp | icmp | all ] -# -protocol = tcp - # Option: chain # Notes specifies the iptables chain to which the fail2ban rules should be # added diff --git a/config/action.d/firewallcmd-new.conf b/config/action.d/firewallcmd-new.conf index 62887967..9754e3f3 100644 --- a/config/action.d/firewallcmd-new.conf +++ b/config/action.d/firewallcmd-new.conf @@ -4,7 +4,7 @@ [INCLUDES] -before = iptables-blocktype.conf +before = iptables-common.conf [Definition] @@ -24,22 +24,6 @@ actionunban = firewall-cmd --direct --remove-rule ipv4 filter f2b- 0 -s -s -j [Init] -# Default name of the chain -# -name = default - -# Option: protocol -# Notes.: internally used by config reader for interpolations. -# Values: [ tcp | udp | icmp | all ] Default: tcp -# -protocol = tcp - -# Option: chain -# Notes specifies the iptables chain to which the fail2ban rules should be -# added -# Values: STRING Default: INPUT -chain = INPUT diff --git a/config/action.d/iptables-blocktype.conf b/config/action.d/iptables-blocktype.conf deleted file mode 100644 index c505e49c..00000000 --- a/config/action.d/iptables-blocktype.conf +++ /dev/null @@ -1,22 +0,0 @@ -# Fail2Ban configuration file -# -# Author: Daniel Black -# -# This is a included configuration file and includes the defination for the blocktype -# used in all iptables based actions by default. -# -# The user can override the default in iptables-blocktype.local - -[INCLUDES] - -after = iptables-blocktype.local - -[Init] - -# Option: blocktype -# Note: This is what the action does with rules. This can be any jump target -# as per the iptables man page (section 8). Common values are DROP -# REJECT, REJECT --reject-with icmp-port-unreachable -# Values: STRING -blocktype = REJECT --reject-with icmp-port-unreachable - diff --git a/config/action.d/iptables-common.conf b/config/action.d/iptables-common.conf new file mode 100644 index 00000000..c191c5a1 --- /dev/null +++ b/config/action.d/iptables-common.conf @@ -0,0 +1,45 @@ +# Fail2Ban configuration file +# +# Author: Daniel Black +# +# This is a included configuration file and includes the definitions for the iptables +# used in all iptables based actions by default. +# +# The user can override the defaults in iptables-common.local + +[INCLUDES] + +after = iptables-blocktype.local + iptables-common.local +# iptables-blocktype.local is obsolete + +[Init] + +# Option: chain +# Notes specifies the iptables chain to which the Fail2Ban rules should be +# added +# Values: STRING Default: INPUT +chain = INPUT + +# Default name of the chain +# +name = default + +# Option: port +# Notes.: specifies port to monitor +# Values: [ NUM | STRING ] Default: +# +port = ssh + +# Option: protocol +# Notes.: internally used by config reader for interpolations. +# Values: [ tcp | udp | icmp | all ] Default: tcp +# +protocol = tcp + +# Option: blocktype +# Note: This is what the action does with rules. This can be any jump target +# as per the iptables man page (section 8). Common values are DROP +# REJECT, REJECT --reject-with icmp-port-unreachable +# Values: STRING +blocktype = REJECT --reject-with icmp-port-unreachable diff --git a/config/action.d/iptables-ipset-proto4.conf b/config/action.d/iptables-ipset-proto4.conf index 4714f0df..c72b1a85 100644 --- a/config/action.d/iptables-ipset-proto4.conf +++ b/config/action.d/iptables-ipset-proto4.conf @@ -19,7 +19,7 @@ [INCLUDES] -before = iptables-blocktype.conf +before = iptables-common.conf [Definition] @@ -56,24 +56,3 @@ actionunban = ipset --test f2b- && ipset --del f2b- [Init] -# Default name of the ipset -# -name = default - -# Option: chain -# Notes specifies the iptables chain to which the Fail2Ban rules should be -# added -# Values: STRING Default: INPUT -chain = INPUT - -# Option: port -# Notes.: specifies port to monitor -# Values: [ NUM | STRING ] Default: ssh -# -port = ssh - -# Option: protocol -# Notes.: internally used by config reader for interpolations. -# Values: [ tcp | udp | icmp | all ] Default: tcp -# -protocol = tcp diff --git a/config/action.d/iptables-ipset-proto6-allports.conf b/config/action.d/iptables-ipset-proto6-allports.conf index a3726873..aaeee461 100644 --- a/config/action.d/iptables-ipset-proto6-allports.conf +++ b/config/action.d/iptables-ipset-proto6-allports.conf @@ -15,8 +15,7 @@ [INCLUDES] -before = iptables-blocktype.conf - +before = iptables-common.conf [Definition] @@ -53,18 +52,8 @@ actionunban = ipset del f2b- -exist [Init] -# Default name of the ipset -# -name = default - -# Option: chain -# Notes specifies the iptables chain to which the Fail2Ban rules should be -# added -# Values: STRING Default: INPUT -chain = INPUT - # Option: bantime # Notes: specifies the bantime in seconds (handled internally rather than by fail2ban) # Values: [ NUM ] Default: 600 - +# bantime = 600 diff --git a/config/action.d/iptables-ipset-proto6.conf b/config/action.d/iptables-ipset-proto6.conf index a3081ea0..bd36c49e 100644 --- a/config/action.d/iptables-ipset-proto6.conf +++ b/config/action.d/iptables-ipset-proto6.conf @@ -15,8 +15,7 @@ [INCLUDES] -before = iptables-blocktype.conf - +before = iptables-common.conf [Definition] @@ -53,30 +52,8 @@ actionunban = ipset del f2b- -exist [Init] -# Default name of the ipset -# -name = default - -# Option: chain -# Notes specifies the iptables chain to which the Fail2Ban rules should be -# added -# Values: STRING Default: INPUT -chain = INPUT - -# Option: port -# Notes.: specifies port to monitor -# Values: [ NUM | STRING ] Default: ssh -# -port = ssh - -# Option: protocol -# Notes.: internally used by config reader for interpolations. -# Values: [ tcp | udp | icmp | all ] Default: tcp -# -protocol = tcp - # Option: bantime # Notes: specifies the bantime in seconds (handled internally rather than by fail2ban) # Values: [ NUM ] Default: 600 - +# bantime = 600 diff --git a/config/action.d/iptables-multiport-log.conf b/config/action.d/iptables-multiport-log.conf index 5a611033..f4d80d6c 100644 --- a/config/action.d/iptables-multiport-log.conf +++ b/config/action.d/iptables-multiport-log.conf @@ -11,7 +11,7 @@ [INCLUDES] -before = iptables-blocktype.conf +before = iptables-common.conf [Definition] @@ -60,24 +60,3 @@ actionunban = iptables -D f2b- -s -j f2b--log [Init] -# Default name of the chain -# -name = default - -# Option: port -# Notes.: specifies port to monitor -# Values: [ NUM | STRING ] Default: -# -port = ssh - -# Option: protocol -# Notes.: internally used by config reader for interpolations. -# Values: [ tcp | udp | icmp | all ] Default: tcp -# -protocol = tcp - -# Option: chain -# Notes specifies the iptables chain to which the fail2ban rules should be -# added -# Values: STRING Default: INPUT -chain = INPUT diff --git a/config/action.d/iptables-multiport.conf b/config/action.d/iptables-multiport.conf index ab3225bc..b70baf92 100644 --- a/config/action.d/iptables-multiport.conf +++ b/config/action.d/iptables-multiport.conf @@ -6,7 +6,7 @@ [INCLUDES] -before = iptables-blocktype.conf +before = iptables-common.conf [Definition] @@ -50,24 +50,3 @@ actionunban = iptables -D f2b- -s -j [Init] -# Default name of the chain -# -name = default - -# Option: port -# Notes.: specifies port to monitor -# Values: [ NUM | STRING ] Default: -# -port = ssh - -# Option: protocol -# Notes.: internally used by config reader for interpolations. -# Values: [ tcp | udp | icmp | all ] Default: tcp -# -protocol = tcp - -# Option: chain -# Notes specifies the iptables chain to which the fail2ban rules should be -# added -# Values: STRING Default: INPUT -chain = INPUT diff --git a/config/action.d/iptables-new.conf b/config/action.d/iptables-new.conf index 9a4587b1..3c6657d9 100644 --- a/config/action.d/iptables-new.conf +++ b/config/action.d/iptables-new.conf @@ -8,8 +8,7 @@ [INCLUDES] -before = iptables-blocktype.conf - +before = iptables-common.conf [Definition] @@ -53,24 +52,3 @@ actionunban = iptables -D f2b- -s -j [Init] -# Default name of the chain -# -name = default - -# Option: port -# Notes.: specifies port to monitor -# Values: [ NUM | STRING ] Default: -# -port = ssh - -# Option: protocol -# Notes.: internally used by config reader for interpolations. -# Values: [ tcp | udp | icmp | all ] Default: tcp -# -protocol = tcp - -# Option: chain -# Notes specifies the iptables chain to which the fail2ban rules should be -# added -# Values: STRING Default: INPUT -chain = INPUT diff --git a/config/action.d/iptables-xt_recent-echo.conf b/config/action.d/iptables-xt_recent-echo.conf index 5d309b56..1a72968f 100644 --- a/config/action.d/iptables-xt_recent-echo.conf +++ b/config/action.d/iptables-xt_recent-echo.conf @@ -6,8 +6,7 @@ [INCLUDES] -before = iptables-blocktype.conf - +before = iptables-common.conf [Definition] @@ -33,14 +32,14 @@ before = iptables-blocktype.conf # own rules. The 3600 second timeout is independent and acts as a # safeguard in case the fail2ban process dies unexpectedly. The # shorter of the two timeouts actually matters. -actionstart = if [ `id -u` -eq 0 ];then iptables -I INPUT -m recent --update --seconds 3600 --name f2b- -j ;fi +actionstart = if [ `id -u` -eq 0 ];then iptables -I -m recent --update --seconds 3600 --name f2b- -j ;fi # Option: actionstop # Notes.: command executed once at the end of Fail2Ban # Values: CMD # actionstop = echo / > /proc/net/xt_recent/f2b- - if [ `id -u` -eq 0 ];then iptables -D INPUT -m recent --update --seconds 3600 --name f2b- -j ;fi + if [ `id -u` -eq 0 ];then iptables -D -m recent --update --seconds 3600 --name f2b- -j ;fi # Option: actioncheck # Notes.: command executed once before each actionban command @@ -66,12 +65,3 @@ actionunban = echo - > /proc/net/xt_recent/f2b- [Init] -# Default name of the chain -# -name = default - -# Option: protocol -# Notes.: internally used by config reader for interpolations. -# Values: [ tcp | udp | icmp | all ] Default: tcp -# -protocol = tcp diff --git a/config/action.d/iptables.conf b/config/action.d/iptables.conf index 5afe4bf1..a956fc55 100644 --- a/config/action.d/iptables.conf +++ b/config/action.d/iptables.conf @@ -6,7 +6,7 @@ [INCLUDES] -before = iptables-blocktype.conf +before = iptables-common.conf [Definition] @@ -50,24 +50,3 @@ actionunban = iptables -D f2b- -s -j [Init] -# Default name of the chain -# -name = default - -# Option: port -# Notes.: specifies port to monitor -# Values: [ NUM | STRING ] Default: -# -port = ssh - -# Option: protocol -# Notes.: internally used by config reader for interpolations. -# Values: [ tcp | udp | icmp | all ] Default: tcp -# -protocol = tcp - -# Option: chain -# Notes specifies the iptables chain to which the fail2ban rules should be -# added -# Values: STRING Default: INPUT -chain = INPUT From 7640aa091825baf715fe7dfe5fd0210fa2d40537 Mon Sep 17 00:00:00 2001 From: Steven Hiscocks Date: Sun, 22 Jun 2014 13:46:25 +0100 Subject: [PATCH 09/13] TST: Test for actions modifying (un)ban aInfo --- fail2ban/tests/actionstestcase.py | 22 +++++++++++++++++++ .../files/action.d/action_modifyainfo.py | 11 ++++++++++ 2 files changed, 33 insertions(+) create mode 100644 fail2ban/tests/files/action.d/action_modifyainfo.py diff --git a/fail2ban/tests/actionstestcase.py b/fail2ban/tests/actionstestcase.py index ed0fb619..3f968e46 100644 --- a/fail2ban/tests/actionstestcase.py +++ b/fail2ban/tests/actionstestcase.py @@ -29,6 +29,7 @@ import os import tempfile from ..server.actions import Actions +from ..server.ticket import FailTicket from .dummyjail import DummyJail from .utils import LogCaptureTestCase @@ -140,3 +141,24 @@ class ExecuteActions(LogCaptureTestCase): self.__actions.stop() self.__actions.join() self.assertTrue(self._is_logged("Failed to stop")) + + def testBanActionsAInfo(self): + # Action which deletes IP address from aInfo + self.__actions.add( + "action1", + os.path.join(TEST_FILES_DIR, "action.d/action_modifyainfo.py"), + {}) + self.__actions.add( + "action2", + os.path.join(TEST_FILES_DIR, "action.d/action_modifyainfo.py"), + {}) + self.__jail.putFailTicket(FailTicket("1.2.3.4", 0)) + self.__actions._Actions__checkBan() + # Will fail if modification of aInfo from first action propagates + # to second action, as both delete same key + self.assertFalse(self._is_logged("Failed to execute ban")) + + self.__actions._Actions__flushBan() + # Will fail if modification of aInfo from first action propagates + # to second action, as both delete same key + self.assertFalse(self._is_logged("Failed to execute unban")) diff --git a/fail2ban/tests/files/action.d/action_modifyainfo.py b/fail2ban/tests/files/action.d/action_modifyainfo.py new file mode 100644 index 00000000..0a1d944a --- /dev/null +++ b/fail2ban/tests/files/action.d/action_modifyainfo.py @@ -0,0 +1,11 @@ + +from fail2ban.server.action import ActionBase + +class TestAction(ActionBase): + + def ban(self, aInfo): + del aInfo['ip'] + + unban = ban + +Action = TestAction From dd3ab858dd30d4ebcab09f6d88e03726a9fdad60 Mon Sep 17 00:00:00 2001 From: Steven Hiscocks Date: Sun, 22 Jun 2014 13:56:32 +0100 Subject: [PATCH 10/13] TST: actions modifying aInfo test more robust --- fail2ban/tests/actionstestcase.py | 4 ++++ fail2ban/tests/files/action.d/action_modifyainfo.py | 5 ++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/fail2ban/tests/actionstestcase.py b/fail2ban/tests/actionstestcase.py index 3f968e46..d66930ef 100644 --- a/fail2ban/tests/actionstestcase.py +++ b/fail2ban/tests/actionstestcase.py @@ -157,8 +157,12 @@ class ExecuteActions(LogCaptureTestCase): # Will fail if modification of aInfo from first action propagates # to second action, as both delete same key self.assertFalse(self._is_logged("Failed to execute ban")) + self.assertTrue(self._is_logged("action1 ban deleted aInfo IP")) + self.assertTrue(self._is_logged("action2 ban deleted aInfo IP")) self.__actions._Actions__flushBan() # Will fail if modification of aInfo from first action propagates # to second action, as both delete same key self.assertFalse(self._is_logged("Failed to execute unban")) + self.assertTrue(self._is_logged("action1 unban deleted aInfo IP")) + self.assertTrue(self._is_logged("action2 unban deleted aInfo IP")) diff --git a/fail2ban/tests/files/action.d/action_modifyainfo.py b/fail2ban/tests/files/action.d/action_modifyainfo.py index 0a1d944a..9fbe1e0b 100644 --- a/fail2ban/tests/files/action.d/action_modifyainfo.py +++ b/fail2ban/tests/files/action.d/action_modifyainfo.py @@ -5,7 +5,10 @@ class TestAction(ActionBase): def ban(self, aInfo): del aInfo['ip'] + self._logSys.info("%s ban deleted aInfo IP", self._name) - unban = ban + def unban(self, aInfo): + del aInfo['ip'] + self._logSys.info("%s unban deleted aInfo IP", self._name) Action = TestAction From 305b31ae1c201a80ffef5fe5b5bdb96e1236256f Mon Sep 17 00:00:00 2001 From: Yaroslav Halchenko Date: Sat, 21 Jun 2014 22:20:34 -0400 Subject: [PATCH 11/13] DOC: ChangeLog -- Added an entry about iptables-common.conf --- ChangeLog | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/ChangeLog b/ChangeLog index 7cc1a5a6..b901723d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -10,6 +10,11 @@ Fail2Ban (version 0.9.0.dev) 2014/xx/xx ver. 0.9.1 (2014/xx/xx) - better, faster, stronger ---------- +- Refactoring (IMPORTANT -- Please review your setup and configuration): + * iptables-common.conf replaced iptables-blocktype.conf + (iptables-blocktype.local should still be read) and now also + provides defaults for the chain, port, protocol and name tags + - Fixes: * systemd backend error on bad utf-8 in python3 * badips.py action error when logging HTTP error raised with badips request @@ -34,14 +39,13 @@ ver. 0.9.1 (2014/xx/xx) - better, faster, stronger - New features: - Added monit filter thanks Jason H Martin. - - Enhancements * Fail2ban-regex - add print-all-matched option. Closes gh-652 * Suppress fail2ban-client warnings for non-critical config options * Match non "Bye Bye" disconnect messages for sshd locked account regex - * Add tag to iptables-ipsets. + * Add tag to iptables-ipsets * Realign fail2ban log output with white space to improve readability. Does - not affect SYSLOG output. + not affect SYSLOG output * Log unhandled exceptions ver. 0.9.0 (2014/03/14) - beta From 602239051bcd26c44dfa706d7d591d6a2669cff1 Mon Sep 17 00:00:00 2001 From: Yaroslav Halchenko Date: Sun, 22 Jun 2014 10:56:50 -0400 Subject: [PATCH 12/13] BF: reincarnated import of logging (used to obtain level constants) --- bin/fail2ban-testcases | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/fail2ban-testcases b/bin/fail2ban-testcases index 8b1343a3..475aa40b 100755 --- a/bin/fail2ban-testcases +++ b/bin/fail2ban-testcases @@ -24,7 +24,7 @@ __author__ = "Cyril Jaquier" __copyright__ = "Copyright (c) 2004 Cyril Jaquier, 2012- Yaroslav Halchenko" __license__ = "GPL" - +import logging import unittest, sys, time, os # Check if local fail2ban module exists, and use if it exists by From c7de888cd394bbfba4e440049a86fdfe1c1e7020 Mon Sep 17 00:00:00 2001 From: Yaroslav Halchenko Date: Sun, 22 Jun 2014 10:59:43 -0400 Subject: [PATCH 13/13] DOC: Changelog for previous merge (pass a copy of aInfo) --- ChangeLog | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index b901723d..bdae885c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -34,7 +34,8 @@ ver. 0.9.1 (2014/xx/xx) - better, faster, stronger action * Fixed TypeError with "ipfailures" and "ipjailfailures" action tags. Thanks Serg G. Brester - * Correct times for non-timezone date times formats during DST. + * Correct times for non-timezone date times formats during DST + * Pass a copy of, not original, aInfo into actions to avoid side-effects - New features: - Added monit filter thanks Jason H Martin.