Merge remote-tracking branch 'remotes/upstream/master', fix test cases (see bellow)

Conflicts resolved:
	ChangeLog
	fail2ban/server/filter.py
	fail2ban/server/jail.py
	fail2ban/tests/actionstestcase.py
Test cases fixed:
	testBanActionsAInfo - fail ticket with current time (otherwise ticket will be ignored - ban time too old)
	testFail2BanExceptHook - use local sys.__excepthook__ to check was really executed and prevent write error in stderr.
pull/716/head
sebres 2014-06-24 14:02:24 +02:00
commit 00b7205a3c
58 changed files with 301 additions and 323 deletions

View File

@ -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
@ -27,18 +32,23 @@ ver. 0.9.1 (2014/xx/xx) - better, faster, stronger
* Database now returns persistent bans on restart (bantime < 0)
* Recursive action tags now fully processed. Fixes issue with bsd-ipfw
action
* Correct times for non-timezone date times formats during DST.
* Fixed TypeError with "ipfailures" and "ipjailfailures" action tags.
Thanks Serg G. Brester (sebres)
* Correct times for non-timezone date times formats during DST
Thanks Serg G. Brester (sebres)
* Pass a copy of, not original, aInfo into actions to avoid side-effects
- 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 <chain> tag to iptables-ipsets
* 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
----------

View File

@ -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

1
THANKS
View File

@ -87,6 +87,7 @@ Robert Edeker
Rolf Fokkens
Roman Gelfand
Russell Odom
SATO Kentaro
Sebastian Arcus
Serg G. Brester (sebres)
Sireyessire

View File

@ -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.client")
logSys = getLogger("fail2ban")
##
#

View File

@ -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('<HOST>', '(?&.ipv4)'),

View File

@ -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

View File

@ -24,8 +24,8 @@ __author__ = "Cyril Jaquier"
__copyright__ = "Copyright (c) 2004 Cyril Jaquier, 2012- Yaroslav Halchenko"
__license__ = "GPL"
import unittest, logging, sys, time, os
import logging
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,

View File

@ -14,7 +14,7 @@
[INCLUDES]
before = iptables-blocktype.conf
before = iptables-common.conf
[Definition]
@ -31,22 +31,6 @@ actionunban = ipset del fail2ban-<name> <ip> -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

View File

@ -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-<name> 0 -s <i
[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

View File

@ -8,7 +8,7 @@
[INCLUDES]
before = iptables-blocktype.conf
before = iptables-common.conf
[Definition]
@ -53,18 +53,3 @@ actionunban = iptables -D f2b-<name> -s <ip> -j <blocktype>
[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

View File

@ -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

View File

@ -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

View File

@ -19,7 +19,7 @@
[INCLUDES]
before = iptables-blocktype.conf
before = iptables-common.conf
[Definition]
@ -28,13 +28,13 @@ before = iptables-blocktype.conf
# Values: CMD
#
actionstart = ipset --create f2b-<name> iphash
iptables -I INPUT -p <protocol> -m multiport --dports <port> -m set --match-set f2b-<name> src -j <blocktype>
iptables -I <chain> -p <protocol> -m multiport --dports <port> -m set --match-set f2b-<name> src -j <blocktype>
# Option: actionstop
# Notes.: command executed once at the end of Fail2Ban
# Values: CMD
#
actionstop = iptables -D INPUT -p <protocol> -m multiport --dports <port> -m set --match-set f2b-<name> src -j <blocktype>
actionstop = iptables -D <chain> -p <protocol> -m multiport --dports <port> -m set --match-set f2b-<name> src -j <blocktype>
ipset --flush f2b-<name>
ipset --destroy f2b-<name>
@ -56,18 +56,3 @@ actionunban = ipset --test f2b-<name> <ip> && ipset --del f2b-<name> <ip>
[Init]
# Default name of the ipset
#
name = default
# 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

View File

@ -15,8 +15,7 @@
[INCLUDES]
before = iptables-blocktype.conf
before = iptables-common.conf
[Definition]
@ -25,13 +24,13 @@ before = iptables-blocktype.conf
# Values: CMD
#
actionstart = ipset create f2b-<name> hash:ip timeout <bantime>
iptables -I INPUT -m set --match-set f2b-<name> src -j <blocktype>
iptables -I <chain> -m set --match-set f2b-<name> src -j <blocktype>
# Option: actionstop
# Notes.: command executed once at the end of Fail2Ban
# Values: CMD
#
actionstop = iptables -D INPUT -m set --match-set f2b-<name> src -j <blocktype>
actionstop = iptables -D <chain> -m set --match-set f2b-<name> src -j <blocktype>
ipset flush f2b-<name>
ipset destroy f2b-<name>
@ -53,12 +52,8 @@ actionunban = ipset del f2b-<name> <ip> -exist
[Init]
# Default name of the ipset
#
name = default
# Option: bantime
# Notes: specifies the bantime in seconds (handled internally rather than by fail2ban)
# Values: [ NUM ] Default: 600
#
bantime = 600

View File

@ -15,8 +15,7 @@
[INCLUDES]
before = iptables-blocktype.conf
before = iptables-common.conf
[Definition]
@ -25,13 +24,13 @@ before = iptables-blocktype.conf
# Values: CMD
#
actionstart = ipset create f2b-<name> hash:ip timeout <bantime>
iptables -I INPUT -p <protocol> -m multiport --dports <port> -m set --match-set f2b-<name> src -j <blocktype>
iptables -I <chain> -p <protocol> -m multiport --dports <port> -m set --match-set f2b-<name> src -j <blocktype>
# Option: actionstop
# Notes.: command executed once at the end of Fail2Ban
# Values: CMD
#
actionstop = iptables -D INPUT -p <protocol> -m multiport --dports <port> -m set --match-set f2b-<name> src -j <blocktype>
actionstop = iptables -D <chain> -p <protocol> -m multiport --dports <port> -m set --match-set f2b-<name> src -j <blocktype>
ipset flush f2b-<name>
ipset destroy f2b-<name>
@ -53,24 +52,8 @@ actionunban = ipset del f2b-<name> <ip> -exist
[Init]
# Default name of the ipset
#
name = default
# 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

View File

@ -11,7 +11,7 @@
[INCLUDES]
before = iptables-blocktype.conf
before = iptables-common.conf
[Definition]
@ -60,24 +60,3 @@ actionunban = iptables -D f2b-<name> -s <ip> -j f2b-<name>-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

View File

@ -6,7 +6,7 @@
[INCLUDES]
before = iptables-blocktype.conf
before = iptables-common.conf
[Definition]
@ -50,24 +50,3 @@ actionunban = iptables -D f2b-<name> -s <ip> -j <blocktype>
[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

View File

@ -8,8 +8,7 @@
[INCLUDES]
before = iptables-blocktype.conf
before = iptables-common.conf
[Definition]
@ -53,24 +52,3 @@ actionunban = iptables -D f2b-<name> -s <ip> -j <blocktype>
[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

View File

@ -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-<name> -j <blocktype>;fi
actionstart = if [ `id -u` -eq 0 ];then iptables -I <chain> -m recent --update --seconds 3600 --name f2b-<name> -j <blocktype>;fi
# Option: actionstop
# Notes.: command executed once at the end of Fail2Ban
# Values: CMD
#
actionstop = echo / > /proc/net/xt_recent/f2b-<name>
if [ `id -u` -eq 0 ];then iptables -D INPUT -m recent --update --seconds 3600 --name f2b-<name> -j <blocktype>;fi
if [ `id -u` -eq 0 ];then iptables -D <chain> -m recent --update --seconds 3600 --name f2b-<name> -j <blocktype>;fi
# Option: actioncheck
# Notes.: command executed once before each actionban command
@ -66,12 +65,3 @@ actionunban = echo -<ip> > /proc/net/xt_recent/f2b-<name>
[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

View File

@ -6,7 +6,7 @@
[INCLUDES]
before = iptables-blocktype.conf
before = iptables-common.conf
[Definition]
@ -50,24 +50,3 @@ actionunban = iptables -D f2b-<name> -s <ip> -j <blocktype>
[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

View File

@ -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'] = \

View File

@ -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!

View File

@ -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 getLogger
# Gets the instance of the logger.
logSys = logging.getLogger(__name__)
logSys = getLogger(__name__)
class ActionReader(DefinitionInitConfigReader):

View File

@ -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 getLogger
# Gets the instance of the logger.
logSys = logging.getLogger(__name__)
logSys = getLogger(__name__)
##
# Beautify the output of the client.

View File

@ -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 getLogger
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 = getLogger(__name__)
__all__ = ['SafeConfigParserWithIncludes']

View File

@ -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 getLogger
# Gets the instance of the logger.
logSys = logging.getLogger(__name__)
logSys = getLogger(__name__)
class ConfigReader(SafeConfigParserWithIncludes):

View File

@ -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 getLogger
# Gets the instance of the logger.
logSys = logging.getLogger(__name__)
logSys = getLogger(__name__)
class Configurator:

View File

@ -24,12 +24,11 @@ __author__ = "Cyril Jaquier"
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
__license__ = "GPL"
import logging
from .configreader import ConfigReader
from ..helpers import getLogger
# Gets the instance of the logger.
logSys = logging.getLogger(__name__)
logSys = getLogger(__name__)
class Fail2banReader(ConfigReader):

View File

@ -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 getLogger
# Gets the instance of the logger.
logSys = logging.getLogger(__name__)
logSys = getLogger(__name__)
class FilterReader(DefinitionInitConfigReader):

View File

@ -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 getLogger
# Gets the instance of the logger.
logSys = logging.getLogger(__name__)
logSys = getLogger(__name__)
class JailReader(ConfigReader):

View File

@ -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 getLogger
# Gets the instance of the logger.
logSys = logging.getLogger(__name__)
logSys = getLogger(__name__)
class JailsReader(ConfigReader):

View File

@ -107,3 +107,17 @@ class FormatterWithTraceBack(logging.Formatter):
def format(self, record):
record.tbc = record.tb = self._tb()
return logging.Formatter.format(self, record)
def getLogger(name):
"""Get logging.Logger instance with Fail2Ban logger name convention
"""
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
"""
getLogger("fail2ban").critical(
"Unhandled exception in Fail2Ban:", exc_info=True)
return sys.__excepthook__(exctype, value, traceback)

View File

@ -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 getLogger
# Gets the instance of the logger.
logSys = logging.getLogger(__name__)
logSys = getLogger(__name__)
# Create a lock for running system commands
_cmd_lock = threading.Lock()
@ -68,6 +69,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 +91,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.
@ -135,8 +142,7 @@ class ActionBase(object):
def __init__(self, jail, name):
self._jail = jail
self._name = name
self._logSys = logging.getLogger(
'%s.%s' % (__name__, self.__class__.__name__))
self._logSys = getLogger("fail2ban.%s" % self.__class__.__name__)
def start(self):
"""Executed when the jail/action is started.

View File

@ -42,9 +42,10 @@ from .observer import Observers
from .jailthread import JailThread
from .action import ActionBase, CommandAction, CallingMap
from .mytime import MyTime
from ..helpers import getLogger
# Gets the instance of the logger.
logSys = logging.getLogger(__name__)
logSys = getLogger(__name__)
class Actions(JailThread, Mapping):
"""Handles jail actions.
@ -299,11 +300,12 @@ class Actions(JailThread, Mapping):
# do actions :
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:
@ -347,11 +349,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

View File

@ -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 getLogger,formatExceptionInfo
# Gets the instance of the logger.
logSys = logging.getLogger(__name__)
logSys = getLogger(__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()

View File

@ -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 getLogger
# Gets the instance of the logger.
logSys = logging.getLogger(__name__)
logSys = getLogger(__name__)
##
# Banning Manager.

View File

@ -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 getLogger
# Gets the instance of the logger.
logSys = logging.getLogger(__name__)
logSys = getLogger(__name__)
if sys.version_info >= (3,):
sqlite3.register_adapter(

View File

@ -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 getLogger
# Gets the instance of the logger.
logSys = logging.getLogger(__name__)
logSys = getLogger(__name__)
class DateDetector(object):
"""Manages one or more date templates to find a date within a log line.

View File

@ -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 getLogger
logSys = logging.getLogger(__name__)
logSys = getLogger(__name__)
class DateTemplate(object):

View File

@ -24,10 +24,10 @@ __author__ = "Cyril Jaquier"
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
__license__ = "GPL"
import logging
from ..helpers import getLogger
# Gets the instance of the logger.
logSys = logging.getLogger(__name__)
logSys = getLogger(__name__)
class FailData:

View File

@ -29,9 +29,10 @@ import logging
from .faildata import FailData
from .ticket import FailTicket
from ..helpers import getLogger
# Gets the instance of the logger.
logSys = logging.getLogger(__name__)
logSys = getLogger(__name__)
class FailManager:

View File

@ -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, datetime
import re, os, fcntl, sys, locale, codecs, datetime
from .failmanager import FailManagerEmpty, FailManager
from .observer import Observers
@ -32,9 +32,10 @@ from .datetemplate import DatePatternRegex, DateEpoch, DateTai64n
from .mytime import MyTime
from .failregex import FailRegex, Regex, RegexException
from .action import CommandAction
from ..helpers import getLogger
# Gets the instance of the logger.
logSys = logging.getLogger(__name__)
logSys = getLogger(__name__)
##
# Log reader class.

View File

@ -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 getLogger
# Gets the instance of the logger.
logSys = logging.getLogger(__name__)
logSys = getLogger(__name__)
##
# Log reader class.

View File

@ -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 getLogger
# Gets the instance of the logger.
logSys = logging.getLogger(__name__)
logSys = getLogger(__name__)
##
# Log reader class.

View File

@ -32,6 +32,7 @@ import pyinotify
from .failmanager import FailManagerEmpty
from .filter import FileFilter
from .mytime import MyTime
from ..helpers import getLogger
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 = getLogger(__name__)
##
# Log reader class.

View File

@ -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 getLogger
# Gets the instance of the logger.
logSys = logging.getLogger("fail2ban.filter")
logSys = getLogger(__name__)
##
# Journal reader class.

View File

@ -26,10 +26,11 @@ __license__ = "GPL"
import Queue, logging, math, random
from .actions import Actions
from ..helpers import getLogger
from .mytime import MyTime
# Gets the instance of the logger.
logSys = logging.getLogger(__name__)
logSys = getLogger(__name__)
class Jail:
"""Fail2Ban jail, which manages a filter and associated actions.

View File

@ -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 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:
excepthook(*sys.exc_info())
self.run = run_with_except_hook
@abstractproperty
def status(self): # pragma: no cover - abstract
"""Abstract - Should provide status information.

View File

@ -25,14 +25,14 @@ __author__ = "Serg G. Brester (sebres)"
__copyright__ = "Copyright (c) 2014 Serg G. Brester"
__license__ = "GPL"
import time, logging
import threading
import os, datetime, math, json, random
import os, time, datetime, math, json, random
import sys
from ..helpers import getLogger
from .mytime import MyTime
# Gets the instance of the logger.
logSys = logging.getLogger(__name__)
logSys = getLogger(__name__)
class ObserverThread(threading.Thread):
"""Handles observing a database, managing bad ips and ban increment.

View File

@ -33,9 +33,10 @@ from .filter import FileFilter, JournalFilter
from .transmitter import Transmitter
from .asyncserver import AsyncServer, AsyncServerException
from .. import version
from ..helpers import getLogger, excepthook
# Gets the instance of the logger.
logSys = logging.getLogger(__name__)
logSys = getLogger(__name__)
try:
from .database import Fail2BanDb
@ -70,6 +71,9 @@ class Server:
signal.signal(signal.SIGTERM, self.__sigTERMhandler)
signal.signal(signal.SIGINT, self.__sigTERMhandler)
# Ensure unhandled exceptions are logged
sys.excepthook = excepthook
# First set the mask to only allow access to owner
os.umask(0077)
if self.__daemon: # pragma: no cover
@ -352,7 +356,7 @@ class Server:
def setLogLevel(self, value):
try:
self.__loggingLock.acquire()
logging.getLogger(__name__).parent.parent.setLevel(
getLogger("fail2ban").setLevel(
getattr(logging, value.upper()))
except AttributeError:
raise ValueError("Invalid log level")
@ -384,7 +388,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")
@ -405,7 +409,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 = getLogger("fail2ban")
for handler in logger.handlers[::-1]:
# Remove the handler.
logger.removeHandler(handler)
@ -442,7 +446,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 getLogger("fail2ban").handlers:
try:
handler.doRollover()
logSys.info("rollover performed on %s" % self.__logTarget)
@ -451,7 +455,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 getLogger("fail2ban").handlers:
handler.flush()
logSys.info("flush performed on %s" % self.__logTarget)
return "flushed"

View File

@ -24,14 +24,15 @@ __author__ = "Cyril Jaquier"
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
__license__ = "GPL"
import logging
from ..helpers import getLogger
from .mytime import MyTime
# Gets the instance of the logger.
logSys = logging.getLogger(__name__)
logSys = getLogger(__name__)
class Ticket:
def __init__(self, ip, time, matches=None):
def __init__(self, ip, time=None, matches=None):
"""Ticket constructor
@param ip the IP address
@ -43,7 +44,7 @@ class Ticket:
self.__restored = False;
self.__banCount = 0;
self.__banTime = None;
self.__time = time
self.__time = time if time is not None else MyTime.time()
self.__attempt = 0
self.__file = None
self.__matches = matches or []

View File

@ -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 getLogger
# Gets the instance of the logger.
logSys = logging.getLogger(__name__)
logSys = getLogger(__name__)
class Transmitter:

View File

@ -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
@ -141,3 +142,27 @@ class ExecuteActions(LogCaptureTestCase):
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"))
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.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"))

View File

@ -0,0 +1,14 @@
from fail2ban.server.action import ActionBase
class TestAction(ActionBase):
def ban(self, aInfo):
del aInfo['ip']
self._logSys.info("%s ban deleted aInfo IP", self._name)
def unban(self, aInfo):
del aInfo['ip']
self._logSys.info("%s unban deleted aInfo IP", self._name)
Action = TestAction

View File

@ -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

View File

@ -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)

View File

@ -30,11 +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 getLogger
try:
from ..server import filtersystemd
@ -722,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.server.server').parent.parent
l = getLogger('fail2ban')
l.warning("Before file moved")
try:
f2, fn2 = tempfile.mkstemp("fail2ban.log")
@ -804,5 +806,33 @@ class RegexTests(unittest.TestCase):
self.assertTrue(fr.hasMatched())
self.assertRaises(RegexException, fr.getHost)
class _BadThread(JailThread):
def run(self):
raise RuntimeError('run bad thread exception')
class LoggingTests(LogCaptureTestCase):
def setUp(self):
"""Call before every test case."""
LogCaptureTestCase.setUp(self)
def tearDown(self):
"""Call after every test case."""
LogCaptureTestCase.tearDown(self)
def testGetF2BLogger(self):
testLogSys = getLogger("fail2ban.some.string.with.name")
self.assertEqual(testLogSys.parent.name, "fail2ban")
self.assertEqual(testLogSys.name, "fail2ban.name")
def testFail2BanExceptHook(self):
prev_exchook = sys.__excepthook__
x = []
sys.__excepthook__ = lambda *args: x.append(args)
badThread = _BadThread()
badThread.start()
badThread.join()
self.assertTrue(self._is_logged("Unhandled exception"))
sys.__excepthook__ = prev_exchook
self.assertEqual(len(x), 1)
self.assertEqual(x[0][0], RuntimeError)

View File

@ -30,8 +30,9 @@ import unittest
from StringIO import StringIO
from ..server.mytime import MyTime
from ..helpers import getLogger
logSys = logging.getLogger(__name__)
logSys = getLogger(__name__)
def mtimesleep():
# no sleep now should be necessary since polling tracks now not only
@ -90,6 +91,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
@ -190,7 +192,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
@ -203,7 +205,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