mirror of https://github.com/fail2ban/fail2ban
Merge commit '0.9.0a2-792-g1864f75' into debian-releases/experimental
* commit '0.9.0a2-792-g1864f75': (113 commits) Credits and notes from #806 fixed encoding fixed encoding ENH: Ignore errors while unbaning in symbiosis firewall ENH: just a bit more descriptive exception ;-) ENH/BF(TST): making permissions restrictive is not sufficient -- really remove file to test changelog entry for postfix-sasl fix added systemd configuration for postfix-sasl.conf 1.5 version of Fail2ban logwatch file minor typo Fxi jail.conf to use more syslog macros ENH: symbiosis-blacklist-allports action Fix typos. changelog and thanks for the preceding fix Added entry for Cloudflare action ChangeLog Added and entry about Cloudflare action Changed to Cloudflare JSON API Fix sieve filter to use correct option changelog entries for already merged and upcoming merge Update courier-smtp.conf ...debian-releases/experimental
commit
8b2f0678a7
|
@ -8,3 +8,4 @@ htmlcov
|
|||
*.rej
|
||||
*.bak
|
||||
__pycache__
|
||||
.vagrant/
|
||||
|
|
|
@ -6,6 +6,7 @@ python:
|
|||
- "2.7"
|
||||
- "3.2"
|
||||
- "3.3"
|
||||
- "3.4"
|
||||
- "pypy"
|
||||
before_install:
|
||||
- if [[ $TRAVIS_PYTHON_VERSION == 2.7 ]]; then sudo apt-get update -qq; fi
|
||||
|
|
|
@ -0,0 +1,181 @@
|
|||
#!/usr/bin/perl
|
||||
##########################################################################
|
||||
# $Id: fail2ban 150 2013-06-18 22:19:38Z mtremaine $
|
||||
##########################################################################
|
||||
# $Log: fail2ban,v $
|
||||
# Revision 1.5 2008/08/18 16:07:46 mike
|
||||
# Patches from Paul Gear <paul at libertysys.com> -mgt
|
||||
#
|
||||
# Revision 1.4 2008/06/30 23:07:51 kirk
|
||||
# fixed copyright holders for files where I know who they should be
|
||||
#
|
||||
# Revision 1.3 2008/03/24 23:31:26 kirk
|
||||
# added copyright/license notice to each script
|
||||
#
|
||||
# Revision 1.2 2006/12/15 04:53:59 bjorn
|
||||
# Additional filtering, by Willi Mann.
|
||||
#
|
||||
# Revision 1.1 2006/05/30 19:04:26 bjorn
|
||||
# Added fail2ban service, written by Yaroslav Halchenko.
|
||||
#
|
||||
# Written by Yaroslav Halchenko <debian@onerussian.com> for fail2ban
|
||||
#
|
||||
##########################################################################
|
||||
|
||||
########################################################
|
||||
## Copyright (c) 2008 Yaroslav Halchenko
|
||||
## Covered under the included MIT/X-Consortium License:
|
||||
## http://www.opensource.org/licenses/mit-license.php
|
||||
## All modifications and contributions by other persons to
|
||||
## this script are assumed to have been donated to the
|
||||
## Logwatch project and thus assume the above copyright
|
||||
## and licensing terms. If you want to make contributions
|
||||
## under your own copyright or a different license this
|
||||
## must be explicitly stated in the contribution an the
|
||||
## Logwatch project reserves the right to not accept such
|
||||
## contributions. If you have made significant
|
||||
## contributions to this script and want to claim
|
||||
## copyright please contact logwatch-devel@lists.sourceforge.net.
|
||||
#########################################################
|
||||
|
||||
use strict;
|
||||
use Logwatch ':all';
|
||||
|
||||
my $Debug = $ENV{'LOGWATCH_DEBUG'} || 0;
|
||||
my $Detail = $ENV{'LOGWATCH_DETAIL_LEVEL'} || 0;
|
||||
my $IgnoreHost = $ENV{'sshd_ignore_host'} || "";
|
||||
my $DebugCounter = 0;
|
||||
my $ReInitializations = 0;
|
||||
my @IptablesErrors = ();
|
||||
my @ActionErrors = ();
|
||||
my $NotValidIP = 0; # reported invalid IPs number
|
||||
my @OtherList = ();
|
||||
|
||||
my %ServicesBans = ();
|
||||
|
||||
if ( $Debug >= 5 ) {
|
||||
print STDERR "\n\nDEBUG: Inside Fail2Ban Filter \n\n";
|
||||
$DebugCounter = 1;
|
||||
}
|
||||
|
||||
while (defined(my $ThisLine = <STDIN>)) {
|
||||
if ( $Debug >= 5 ) {
|
||||
print STDERR "DEBUG($DebugCounter): $ThisLine";
|
||||
$DebugCounter++;
|
||||
}
|
||||
chomp($ThisLine);
|
||||
if ( ($ThisLine =~ /..,... DEBUG: /) or
|
||||
($ThisLine =~ /..,... \S*\s*: DEBUG /) or # syntax of 0.7.? fail2ban
|
||||
($ThisLine =~ /..,... INFO: (Fail2Ban v.* is running|Exiting|Enabled sections:)/) or
|
||||
($ThisLine =~ /INFO\s+Log rotation detected for/) or
|
||||
($ThisLine =~ /INFO\s+Jail.+(?:stopped|started|uses poller)/) or
|
||||
($ThisLine =~ /INFO\s+Changed logging target to/) or
|
||||
($ThisLine =~ /INFO\s+Creating new jail/) or
|
||||
($ThisLine =~ /..,... \S+\s*: INFO\s+(Set |Socket|Exiting|Gamin|Created|Added|Using)/) or # syntax of 0.7.? fail2ban
|
||||
($ThisLine =~ /..,... WARNING: Verbose level is /) or
|
||||
($ThisLine =~ /..,... WARNING: Restoring firewall rules/)
|
||||
)
|
||||
{
|
||||
if ( $Debug >= 6 ) {
|
||||
print STDERR "DEBUG($DebugCounter): line ignored\n";
|
||||
}
|
||||
} elsif ( my ($Service,$Action,$Host) = ($ThisLine =~ m/WARNING:?\s\[?(.*?)[]:]?\s(Ban|Unban)[^\.]* (\S+)/)) {
|
||||
if ( $Debug >= 6 ) {
|
||||
print STDERR "DEBUG($DebugCounter): Found $Action for $Service from $Host\n";
|
||||
}
|
||||
$ServicesBans{$Service}{$Host}{$Action}++;
|
||||
$ServicesBans{$Service}{"(all)"}{$Action}++;
|
||||
} elsif ( my ($Service,$Host,$NumFailures) = ($ThisLine =~ m/INFO: (\S+): (.+) has (\d+) login failure\(s\). Banned./)) {
|
||||
if ($Debug >= 4) {
|
||||
print STDERR "DEBUG: Found host $Host trying to access $Service - failed $NumFailures times\n";
|
||||
}
|
||||
push @{$ServicesBans{$Service}{$Host}{'Failures'}}, $NumFailures;
|
||||
} elsif ( my ($Service,$Host) = ($ThisLine =~ m/ ERROR:\s(.*):\s(\S+)\salready in ban list/)) {
|
||||
$ServicesBans{$Service}{$Host}{'AlreadyInTheList'}++;
|
||||
} elsif ( my ($Service,$Host) = ($ThisLine =~ m/WARNING\s*\[(.*)\]\s*(\S+)\s*already banned/)) {
|
||||
$ServicesBans{$Service}{$Host}{'AlreadyInTheList'}++;
|
||||
} elsif ( my ($Service,$Host) = ($ThisLine =~ m/ WARNING:\s(.*):\sReBan (\S+)/)) {
|
||||
$ServicesBans{$Service}{$Host}{'ReBan'}++;
|
||||
} elsif ($ThisLine =~ / ERROR:?\s*(Execution of command )?\'?iptables/) {
|
||||
push @IptablesErrors, "$ThisLine\n";
|
||||
} elsif ($ThisLine =~ /ERROR.*returned \d+$/) {
|
||||
push @ActionErrors, "$ThisLine\n";
|
||||
} elsif (($ThisLine =~ /..,... WARNING: \#\S+ reinitialization of firewalls/) or
|
||||
($ThisLine =~ / ERROR\s*Invariant check failed. Trying to restore a sane environment/)) {
|
||||
$ReInitializations++;
|
||||
} elsif ($ThisLine =~ /..,... WARNING: is not a valid IP address/) {
|
||||
# just ignore - this will be fixed within fail2ban and is harmless warning
|
||||
}
|
||||
else
|
||||
{
|
||||
# Report any unmatched entries...
|
||||
push @OtherList, "$ThisLine\n";
|
||||
}
|
||||
}
|
||||
|
||||
###########################################################
|
||||
|
||||
|
||||
if (keys %ServicesBans) {
|
||||
printf("\nBanned services with Fail2Ban: Bans:Unbans\n");
|
||||
foreach my $service (sort {$a cmp $b} keys %ServicesBans) {
|
||||
printf(" %-55s [%3d:%-3d]\n", "$service:",
|
||||
$ServicesBans{$service}{'(all)'}{'Ban'},
|
||||
$ServicesBans{$service}{'(all)'}{'Unban'});
|
||||
delete $ServicesBans{$service}{'(all)'};
|
||||
my $totalSort = TotalCountOrder(%{$ServicesBans{$service}}, \&SortIP);
|
||||
if ($Detail >= 5) {
|
||||
foreach my $ip (sort $totalSort keys %{$ServicesBans{$service}}) {
|
||||
my $name = LookupIP($ip);
|
||||
printf(" %-53s %3d:%-3d\n",
|
||||
$name,
|
||||
$ServicesBans{$service}{$ip}{'Ban'},
|
||||
$ServicesBans{$service}{$ip}{'Unban'});
|
||||
if (($Detail >= 10) and ($ServicesBans{$service}{$ip}{'Failures'}>0)) {
|
||||
print " Failed ";
|
||||
foreach my $fails (@{$ServicesBans{$service}{$ip}{'Failures'}}) {
|
||||
print " $fails";
|
||||
}
|
||||
print " times";
|
||||
printf("\n %d Duplicate Ban attempts", $ServicesBans{$service}{$ip}{'AlreadyInTheList'}) ;
|
||||
printf("\n %d ReBans due to rules reinitilizations", $ServicesBans{$service}{$ip}{'ReBan'}) ;
|
||||
print "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if ($Detail>0) {
|
||||
if ($#IptablesErrors > 0) {
|
||||
printf("\n%d faulty iptables invocation(s)", $#IptablesErrors);
|
||||
if ($Detail > 5) {
|
||||
print ":\n";
|
||||
print @IptablesErrors ;
|
||||
}
|
||||
}
|
||||
if ($#ActionErrors > 0) {
|
||||
printf("\n%d error(s) returned from actions", $#ActionErrors);
|
||||
if ($Detail > 5) {
|
||||
print ":\n";
|
||||
print @ActionErrors ;
|
||||
}
|
||||
}
|
||||
if ($ReInitializations > 0) {
|
||||
printf("\n%d fail2ban rules reinitialization(s)", $ReInitializations);
|
||||
}
|
||||
if ($#OtherList >= 0) {
|
||||
print "\n**Unmatched Entries**\n";
|
||||
print @OtherList;
|
||||
}
|
||||
}
|
||||
|
||||
exit(0);
|
||||
|
||||
# vi: shiftwidth=3 tabstop=3 syntax=perl et
|
||||
# Local Variables:
|
||||
# mode: perl
|
||||
# perl-indent-level: 3
|
||||
# indent-tabs-mode: nil
|
||||
# End:
|
|
@ -0,0 +1,17 @@
|
|||
Guidelines on Fail2Ban contributions
|
||||
====================================
|
||||
|
||||
### You found a severe security vulnerability in Fail2Ban?
|
||||
email details to fail2ban-vulnerabilities at lists dot sourceforge dot net .
|
||||
|
||||
### You need some new features, you found bugs?
|
||||
visit [Issues](https://github.com/fail2ban/fail2ban/issues)
|
||||
and if your issue is not yet known -- file a bug report. See
|
||||
[Fail2Ban wiki](http://www.fail2ban.org/wiki/index.php/HOWTO_Seek_Help)
|
||||
on further instructions.
|
||||
|
||||
### You would like to troubleshoot or discuss?
|
||||
join the [mailing list](https://lists.sourceforge.net/lists/listinfo/fail2ban-users)
|
||||
|
||||
### You would like to contribute (new filters/actions/code/documentation)?
|
||||
send a [pull request](https://github.com/fail2ban/fail2ban/pulls)
|
49
ChangeLog
49
ChangeLog
|
@ -10,24 +10,69 @@ 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:
|
||||
* UTF-8 fixes in pure-ftp thanks to Johannes Weberhofer. Closes gh-806.
|
||||
* systemd backend error on bad utf-8 in python3
|
||||
* badips.py action error when logging HTTP error raised with badips request
|
||||
* fail2ban-regex failed to work in python3 due to space/tab mix
|
||||
* recidive regex samples incorrect log level
|
||||
* journalmatch for recidive incorrect PRIORITY
|
||||
* loglevel couldn't be changed in fail2ban.conf
|
||||
* Handle case when no sqlite library is available for persistent database
|
||||
* Only reban once per IP from database on fail2ban restart
|
||||
* Nginx filter to support missing server_name. Closes gh-676
|
||||
* fail2ban-regex assertion error caused by miscount missed lines with
|
||||
multiline regex
|
||||
* Fix actions failing to execute for Python 3.4.0. Workaround for
|
||||
http://bugs.python.org/issue21207
|
||||
* Database now returns persistent bans on restart (bantime < 0)
|
||||
* Recursive action tags now fully processed. Fixes issue with bsd-ipfw
|
||||
action
|
||||
* Fixed TypeError with "ipfailures" and "ipjailfailures" action tags.
|
||||
Thanks Serg G. Brester
|
||||
* Correct times for non-timezone date times formats during DST
|
||||
* Pass a copy of, not original, aInfo into actions to avoid side-effects
|
||||
* Per-distribution paths to the exim's main log
|
||||
* Ignored IPs are no longer banned when being restored from persistent
|
||||
database
|
||||
* Manually unbanned IPs are now removed from persistent database, such they
|
||||
wont be banned again when Fail2Ban is restarted
|
||||
* Pass "bantime" parameter to the actions in default jail's action
|
||||
definition(s)
|
||||
* filters.d/sieve.conf - fixed typo in _daemon. Thanks Jisoo Park
|
||||
* cyrus-imap -- also catch also failed logins via secured (imaps/pop3s).
|
||||
Regression was introduced while strengthening failregex in 0.8.11 (bd175f)
|
||||
Debian bug #755173
|
||||
* postfix-sasl -- added journalmatch. Thanks Luc Maisonobe
|
||||
|
||||
- New features:
|
||||
|
||||
- New filters:
|
||||
- monit Thanks Jason H Martin
|
||||
- directadmin Thanks niorg
|
||||
- New actions:
|
||||
- symbiosis-blacklist-allports for Bytemark symbiosis firewall
|
||||
- fail2ban-client can fetch the running server version
|
||||
- Added Cloudflare API action
|
||||
|
||||
- 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
|
||||
* courier-smtp filter:
|
||||
- match lines with user names
|
||||
- match lines containing "535 Authentication failed" attempts
|
||||
* Add <chain> tag to iptables-ipsets
|
||||
* Realign fail2ban log output with white space to improve readability. Does
|
||||
not affect SYSLOG output
|
||||
* Log unhandled exceptions
|
||||
* cyrus-imap: catch "user not found" attempts
|
||||
|
||||
ver. 0.9.0 (2014/03/14 - beta
|
||||
ver. 0.9.0 (2014/03/14) - beta
|
||||
----------
|
||||
|
||||
Carries all fixes, features and enhancements from 0.8.13 (unreleased) with
|
||||
|
|
2
MANIFEST
2
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
|
||||
|
|
|
@ -6,20 +6,20 @@ By Roy Sigurd Karlsbakk <roy@karlsbakk.net>
|
|||
|
||||
ABOUT
|
||||
|
||||
This readme is meant for those wanting to install fail2ban on Solaris 10,
|
||||
This README is meant for those wanting to install fail2ban on Solaris 10,
|
||||
OpenSolaris, OpenIndiana etc. To some degree it may as well be useful for
|
||||
users of older Solaris versions and Nexenta, but don't rely on it.
|
||||
|
||||
READ ME FIRST
|
||||
|
||||
If I use the term Solaris, I am talking about any Solaris dialect, that is, the
|
||||
official Sun/Oracle ones or derivates. If I describe an OS as
|
||||
official Sun/Oracle ones or derivatives. If I describe an OS as
|
||||
"OpenSolaris-based", it means it's either OpenSolaris, OpenIndiana or one of the
|
||||
other, but /not/ the Nexenta family, since this only uses the OpenSolaris/
|
||||
IllumOS kernel and not the userland. If I say Solaris 10, I mean Solaris 10 and
|
||||
perhaps, if you're lucky and have some good gods on your side, it may also apply
|
||||
to Solaris 9 or even 8 and hopefully in the new Solaris 11 whenever that may be
|
||||
released. Quoted lines of code, settings et cetera are indented with two spaces.
|
||||
released. Quoted lines of code, settings etc. are indented with two spaces.
|
||||
This does _not_ mean you should use that indentation, especially in config files
|
||||
where they can be harmful. Optional settings are prefixed with OPT: while
|
||||
required settings are prefixed with REQ:. If no prefix is found, regard it as a
|
||||
|
@ -111,7 +111,7 @@ GOTCHAS AND FIXMES
|
|||
svcadm enable fail2ban
|
||||
|
||||
* If svcs -xv says that fail2ban failed to start or svcs says it's in maintenance mode
|
||||
check /var/svc/log/network-fail2ban:default.log for clues.
|
||||
check /var/svc/log/network-fail2ban:default.log for clues.
|
||||
Check permissions on /var/adm, /var/adm/auth.log /var/adm/fail2ban.log and /var/run/fail2ban
|
||||
You may need to:
|
||||
|
||||
|
|
20
README.md
20
README.md
|
@ -68,24 +68,12 @@ Code status:
|
|||
Contact:
|
||||
--------
|
||||
|
||||
### You found a severe security vulnerability in Fail2Ban?
|
||||
email details to fail2ban-vulnerabilities at lists dot sourceforge dot net .
|
||||
|
||||
### You need some new features, you found bugs?
|
||||
visit [Issues](https://github.com/fail2ban/fail2ban/issues)
|
||||
and if your issue is not yet known -- file a bug report. See
|
||||
[Fail2Ban wiki](http://www.fail2ban.org/wiki/index.php/HOWTO_Seek_Help)
|
||||
on further instructions.
|
||||
|
||||
### You would like to troubleshoot or discuss?
|
||||
join the [mailing list](https://lists.sourceforge.net/lists/listinfo/fail2ban-users)
|
||||
|
||||
### You would like to contribute (new filters/actions/code/documentation)?
|
||||
send a pull request
|
||||
### Bugs, feature requests, discussions?
|
||||
See [CONTRIBUTING.md](https://github.com/fail2ban/fail2ban/blob/master/CONTRIBUTING.md)
|
||||
|
||||
### You just appreciate this program:
|
||||
send kudos to the original author ([Cyril Jaquier](mailto: Cyril Jaquier <cyril.jaquier@fail2ban.org>)
|
||||
or better to the [mailing list](https://lists.sourceforge.net/lists/listinfo/fail2ban-users)
|
||||
send kudos to the original author ([Cyril Jaquier](mailto: Cyril Jaquier <cyril.jaquier@fail2ban.org>))
|
||||
or *better* to the [mailing list](https://lists.sourceforge.net/lists/listinfo/fail2ban-users)
|
||||
since Fail2Ban is "community-driven" for years now.
|
||||
|
||||
Thanks:
|
||||
|
|
12
THANKS
12
THANKS
|
@ -44,10 +44,14 @@ Hank Leininger
|
|||
Hanno 'Rince' Wagner
|
||||
Helmut Grohne
|
||||
Iain Lea
|
||||
Ioan Indreias
|
||||
Ivo Truxa
|
||||
John Thoe
|
||||
Jacques Lav!gnotte
|
||||
Ioan Indreias
|
||||
Johannes Weberhofer
|
||||
Jason H Martin
|
||||
Jisoo Park
|
||||
Joel M Snyder
|
||||
Jonathan Kamens
|
||||
Jonathan Lanning
|
||||
Jonathan Underwood
|
||||
|
@ -60,6 +64,7 @@ kjohnsonecl
|
|||
kojiro
|
||||
Lars Kneschke
|
||||
Lee Clemens
|
||||
leftyfb (Mike Rushton)
|
||||
Manuel Arostegui Ramirez
|
||||
Marcel Dopita
|
||||
Mark Edgington
|
||||
|
@ -75,8 +80,10 @@ Michael Hanselmann
|
|||
Mika (mkl)
|
||||
Nick Munger
|
||||
onorua
|
||||
Paul Marrapese
|
||||
Noel Butler
|
||||
Patrick Börjesson
|
||||
Pressy
|
||||
Raphaël Marichez
|
||||
RealRancor
|
||||
René Berber
|
||||
|
@ -84,7 +91,10 @@ Robert Edeker
|
|||
Rolf Fokkens
|
||||
Roman Gelfand
|
||||
Russell Odom
|
||||
SATO Kentaro
|
||||
Sean DuBois
|
||||
Sebastian Arcus
|
||||
Serg G. Brester
|
||||
Sireyessire
|
||||
silviogarbes
|
||||
Stefan Tatschner
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
Vagrant.configure("2") do |config|
|
||||
|
||||
config.vm.define "secure" do |secure|
|
||||
secure.vm.box = "ubuntu/trusty64"
|
||||
secure.vm.hostname = "secure.dev.fail2ban.org"
|
||||
secure.vm.network "private_network", ip: "192.168.200.100"
|
||||
|
||||
# secure.vm.synced_folder 'salt/roots', '/srv/salt'
|
||||
|
||||
# secure.vm.provision :salt do |salt|
|
||||
# salt.minion_config = 'salt/minion'
|
||||
# salt.run_highstate = true
|
||||
# salt.verbose = true
|
||||
# end
|
||||
end
|
||||
|
||||
config.vm.define "attacker" do |attacker|
|
||||
attacker.vm.box = "ubuntu/trusty64"
|
||||
attacker.vm.hostname = "attacker.dev.fail2ban.org"
|
||||
attacker.vm.network "private_network", ip: "192.168.200.150"
|
||||
|
||||
# attacker.vm.synced_folder 'salt/roots', '/srv/salt'
|
||||
|
||||
# attacker.vm.provision :salt do |salt|
|
||||
# salt.minion_config = 'salt/minion'
|
||||
# salt.run_highstate = true
|
||||
# salt.verbose = true
|
||||
# end
|
||||
end
|
||||
end
|
|
@ -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")
|
||||
|
||||
##
|
||||
#
|
||||
|
@ -51,6 +52,7 @@ class Fail2banClient:
|
|||
self.__conf["conf"] = "/etc/fail2ban"
|
||||
self.__conf["dump"] = False
|
||||
self.__conf["force"] = False
|
||||
self.__conf["background"] = True
|
||||
self.__conf["verbose"] = 1
|
||||
self.__conf["interactive"] = False
|
||||
self.__conf["socket"] = None
|
||||
|
@ -83,6 +85,8 @@ class Fail2banClient:
|
|||
print " -v increase verbosity"
|
||||
print " -q decrease verbosity"
|
||||
print " -x force execution of the server (remove socket file)"
|
||||
print " -b start server in background (default)"
|
||||
print " -f start server in foreground (note that the client forks once itself)"
|
||||
print " -h, --help display this help message"
|
||||
print " -V, --version print the version"
|
||||
print
|
||||
|
@ -125,6 +129,10 @@ class Fail2banClient:
|
|||
self.__conf["force"] = True
|
||||
elif opt[0] == "-i":
|
||||
self.__conf["interactive"] = True
|
||||
elif opt[0] == "-b":
|
||||
self.__conf["background"] = True
|
||||
elif opt[0] == "-f":
|
||||
self.__conf["background"] = False
|
||||
elif opt[0] in ["-h", "--help"]:
|
||||
self.dispUsage()
|
||||
sys.exit(0)
|
||||
|
@ -194,7 +202,8 @@ class Fail2banClient:
|
|||
# Start the server
|
||||
self.__startServerAsync(self.__conf["socket"],
|
||||
self.__conf["pidfile"],
|
||||
self.__conf["force"])
|
||||
self.__conf["force"],
|
||||
self.__conf["background"])
|
||||
try:
|
||||
# Wait for the server to start
|
||||
self.__waitOnServer()
|
||||
|
@ -242,14 +251,12 @@ class Fail2banClient:
|
|||
#
|
||||
# Start the Fail2ban server in daemon mode.
|
||||
|
||||
def __startServerAsync(self, socket, pidfile, force = False):
|
||||
def __startServerAsync(self, socket, pidfile, force = False, background = True):
|
||||
# Forks the current process.
|
||||
pid = os.fork()
|
||||
if pid == 0:
|
||||
args = list()
|
||||
args.append(self.SERVER)
|
||||
# Start in background mode.
|
||||
args.append("-b")
|
||||
# Set the socket path.
|
||||
args.append("-s")
|
||||
args.append(socket)
|
||||
|
@ -259,6 +266,12 @@ class Fail2banClient:
|
|||
# Force the execution if needed.
|
||||
if force:
|
||||
args.append("-x")
|
||||
# Start in foreground mode if requested.
|
||||
if background:
|
||||
args.append("-b")
|
||||
else:
|
||||
args.append("-f")
|
||||
|
||||
try:
|
||||
# Use the current directory.
|
||||
exe = os.path.abspath(os.path.join(sys.path[0], self.SERVER))
|
||||
|
@ -312,7 +325,7 @@ class Fail2banClient:
|
|||
|
||||
# Reads the command line options.
|
||||
try:
|
||||
cmdOpts = 'hc:s:p:xdviqV'
|
||||
cmdOpts = 'hc:s:p:xfbdviqV'
|
||||
cmdLongOpts = ['help', 'version']
|
||||
optList, args = getopt.getopt(self.__argv[1:], cmdOpts, cmdLongOpts)
|
||||
except getopt.GetoptError:
|
||||
|
|
|
@ -25,11 +25,11 @@ This tools can test regular expressions for "fail2ban".
|
|||
|
||||
"""
|
||||
|
||||
__author__ = "Cyril Jaquier, Yaroslav Halchenko"
|
||||
__copyright__ = "Copyright (c) 2004-2008 Cyril Jaquier, 2012-2013 Yaroslav Halchenko"
|
||||
__author__ = "Fail2Ban Developers"
|
||||
__copyright__ = "Copyright (c) 2004-2008 Cyril Jaquier, 2012-2014 Yaroslav Halchenko"
|
||||
__license__ = "GPL"
|
||||
|
||||
import getopt, sys, time, logging, os, locale, shlex, urllib
|
||||
import getopt, sys, time, logging, os, locale, shlex, time, urllib
|
||||
from optparse import OptionParser, Option
|
||||
|
||||
from ConfigParser import NoOptionError, NoSectionError, MissingSectionHeaderError
|
||||
|
@ -45,9 +45,9 @@ from fail2ban.client.filterreader import FilterReader
|
|||
from fail2ban.server.filter import Filter
|
||||
from fail2ban.server.failregex import RegexException
|
||||
|
||||
from fail2ban.tests.utils 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)'),
|
||||
|
@ -223,6 +223,7 @@ class Fail2banRegex(object):
|
|||
self._filter = Filter(None)
|
||||
self._ignoreregex = list()
|
||||
self._failregex = list()
|
||||
self._time_elapsed = None
|
||||
self._line_stats = LineStats()
|
||||
|
||||
if opts.maxlines:
|
||||
|
@ -344,10 +345,11 @@ class Fail2banRegex(object):
|
|||
pass
|
||||
else:
|
||||
self._line_stats.matched += 1
|
||||
self._line_stats.missed -= 1
|
||||
return line, ret
|
||||
|
||||
def process(self, test_lines):
|
||||
|
||||
t0 = time.time()
|
||||
for line_no, line in enumerate(test_lines):
|
||||
if isinstance(line, tuple):
|
||||
line_datetimestripped, ret = fail2banRegex.testRegex(
|
||||
|
@ -382,6 +384,7 @@ class Fail2banRegex(object):
|
|||
|
||||
if line_no % 10 == 0 and self._filter.dateDetector is not None:
|
||||
self._filter.dateDetector.sortTemplate()
|
||||
self._time_elapsed = time.time() - t0
|
||||
|
||||
|
||||
|
||||
|
@ -455,7 +458,10 @@ class Fail2banRegex(object):
|
|||
template.hits, template.name))
|
||||
pprint_list(out, "[# of hits] date format")
|
||||
|
||||
print "\nLines: %s" % self._line_stats
|
||||
print "\nLines: %s" % self._line_stats,
|
||||
if self._time_elapsed is not None:
|
||||
print "[processed in %.2f sec]" % self._time_elapsed,
|
||||
print
|
||||
|
||||
if self._print_all_matched:
|
||||
self.printLines('matched')
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
@ -34,7 +34,8 @@ if os.path.exists("fail2ban/__init__.py"):
|
|||
sys.path.insert(0, ".")
|
||||
from fail2ban.version import version
|
||||
|
||||
from fail2ban.tests.utils import FormatterWithTraceBack, gatherTests
|
||||
from fail2ban.tests.utils import gatherTests
|
||||
from fail2ban.helpers import FormatterWithTraceBack, getLogger
|
||||
from fail2ban.server.mytime import MyTime
|
||||
|
||||
from optparse import OptionParser, Option
|
||||
|
@ -69,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,
|
||||
|
|
|
@ -36,7 +36,7 @@ from fail2ban.server.actions import ActionBase
|
|||
from fail2ban.version import version as f2bVersion
|
||||
|
||||
class BadIPsAction(ActionBase):
|
||||
"""Fail2Ban action which resports bans to badips.com, and also
|
||||
"""Fail2Ban action which reports bans to badips.com, and also
|
||||
blacklist bad IPs listed on badips.com by using another action's
|
||||
ban method.
|
||||
|
||||
|
@ -53,7 +53,7 @@ class BadIPsAction(ActionBase):
|
|||
age : str, optional
|
||||
Age of last report for bad IPs, per badips.com syntax.
|
||||
Default "24h" (24 hours)
|
||||
key : str, optional
|
||||
key : str, optional
|
||||
Key issued by badips.com to report bans, for later retrieval
|
||||
of personalised content.
|
||||
banaction : str, optional
|
||||
|
@ -65,7 +65,7 @@ class BadIPsAction(ActionBase):
|
|||
from category used for reporting. e.g. may want to report
|
||||
"postfix", but want to use whole "mail" category for blacklist.
|
||||
Default `category`.
|
||||
bankey : str, optional
|
||||
bankey : str, optional
|
||||
Key issued by badips.com to blacklist IPs reported with the
|
||||
associated key.
|
||||
updateperiod : int, optional
|
||||
|
@ -161,7 +161,7 @@ class BadIPsAction(ActionBase):
|
|||
"/".join([self._badips, "get", "list", category, str(score)]),
|
||||
urlencode({'age': age})])
|
||||
if key:
|
||||
url = "&".join([url, urlencode({"key", key})])
|
||||
url = "&".join([url, urlencode({'key': key})])
|
||||
response = urlopen(self._Request(url))
|
||||
except HTTPError as response:
|
||||
messages = json.loads(response.read().decode('utf-8'))
|
||||
|
@ -258,7 +258,7 @@ class BadIPsAction(ActionBase):
|
|||
self._logSys.error(
|
||||
"Error banning IP %s for jail '%s' with action '%s': %s",
|
||||
ip, self._jail.name, self.banaction, e,
|
||||
exc_info=self._logSys.getEffectiveLevel<=logging.DEBUG)
|
||||
exc_info=self._logSys.getEffectiveLevel()<=logging.DEBUG)
|
||||
else:
|
||||
self._bannedips.add(ip)
|
||||
self._logSys.info(
|
||||
|
@ -279,7 +279,7 @@ class BadIPsAction(ActionBase):
|
|||
self._logSys.info(
|
||||
"Error unbanning IP %s for jail '%s' with action '%s': %s",
|
||||
ip, self._jail.name, self.banaction, e,
|
||||
exc_info=self._logSys.getEffectiveLevel<=logging.DEBUG)
|
||||
exc_info=self._logSys.getEffectiveLevel()<=logging.DEBUG)
|
||||
else:
|
||||
self._logSys.info(
|
||||
"Unbanned IP %s for jail '%s' with action '%s'",
|
||||
|
@ -346,7 +346,7 @@ class BadIPsAction(ActionBase):
|
|||
try:
|
||||
url = "/".join([self._badips, "add", self.category, aInfo['ip']])
|
||||
if self.key:
|
||||
url = "?".join([url, urlencode({"key", self.key})])
|
||||
url = "?".join([url, urlencode({'key': self.key})])
|
||||
response = urlopen(self._Request(url))
|
||||
except HTTPError as response:
|
||||
messages = json.loads(response.read().decode('utf-8'))
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
#
|
||||
# Author: Mike Rushton
|
||||
#
|
||||
# Referenced from from http://www.normyee.net/blog/2012/02/02/adding-cloudflare-support-to-fail2ban by NORM YEE
|
||||
#
|
||||
# To get your Cloudflare API key: https://www.cloudflare.com/my-account
|
||||
#
|
||||
|
||||
[Definition]
|
||||
|
||||
# Option: actionstart
|
||||
# Notes.: command executed once at the start of Fail2Ban.
|
||||
# Values: CMD
|
||||
#
|
||||
actionstart =
|
||||
|
||||
# Option: actionstop
|
||||
# Notes.: command executed once at the end of Fail2Ban
|
||||
# Values: CMD
|
||||
#
|
||||
actionstop =
|
||||
|
||||
# Option: actioncheck
|
||||
# Notes.: command executed once before each actionban command
|
||||
# Values: CMD
|
||||
#
|
||||
actioncheck =
|
||||
|
||||
# Option: actionban
|
||||
# Notes.: command executed when banning an IP. Take care that the
|
||||
# command is executed with Fail2Ban user rights.
|
||||
# Tags: <ip> IP address
|
||||
# <failures> number of failures
|
||||
# <time> unix timestamp of the ban time
|
||||
# Values: CMD
|
||||
#
|
||||
actionban = curl https://www.cloudflare.com/api_json.html -d 'a=ban' -d 'tkn=<cftoken>' -d 'email=<cfuser>' -d 'key=<ip>'
|
||||
# Option: actionunban
|
||||
# Notes.: command executed when unbanning an IP. Take care that the
|
||||
# command is executed with Fail2Ban user rights.
|
||||
# Tags: <ip> IP address
|
||||
# <failures> number of failures
|
||||
# <time> unix timestamp of the ban time
|
||||
# Values: CMD
|
||||
#
|
||||
actionunban = curl https://www.cloudflare.com/api_json.html -d 'a=nul' -d 'tkn=<cftoken>' -d 'email=<cfuser>' -d 'key=<ip>'
|
||||
|
||||
|
||||
[Init]
|
||||
|
||||
# Default Cloudflare API token
|
||||
cftoken =
|
||||
|
||||
# Default Cloudflare username
|
||||
cfuser =
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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'] = \
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
# Fail2Ban configuration file for Bytemark Symbiosis firewall
|
||||
#
|
||||
# Author: Yaroslav Halchenko
|
||||
#
|
||||
|
||||
|
||||
[Definition]
|
||||
|
||||
# Option: actionstart
|
||||
# Notes.: command executed once at the start of Fail2Ban.
|
||||
# Values: CMD
|
||||
#
|
||||
actionstart =
|
||||
|
||||
# Option: actionstop
|
||||
# Notes.: command executed once at the end of Fail2Ban
|
||||
# Values: CMD
|
||||
#
|
||||
actionstop =
|
||||
|
||||
# Option: actioncheck
|
||||
# Notes.: command executed once before each actionban command
|
||||
# Values: CMD
|
||||
#
|
||||
actioncheck = iptables -n -L <chain>
|
||||
|
||||
# Option: actionban
|
||||
# Notes.: command executed when banning an IP.
|
||||
# Values: CMD
|
||||
#
|
||||
actionban = echo 'all' >| /etc/symbiosis/firewall/blacklist.d/<ip>.auto
|
||||
iptables -I <chain> 1 -s <ip> -j <blocktype>
|
||||
|
||||
# Option: actionunban
|
||||
# Notes.: command executed when unbanning an IP.
|
||||
# Values: CMD
|
||||
#
|
||||
actionunban = rm -f /etc/symbiosis/firewall/blacklist.d/<ip>.auto
|
||||
iptables -D <chain> -s <ip> -j <blocktype> || :
|
||||
|
||||
[Init]
|
||||
|
||||
# Option: chain
|
||||
# Notes specifies the iptables chain to which the fail2ban rules should be
|
||||
# added to. blacklist is a chain initiated by symbiosis firewall.
|
||||
# Values: STRING Default: blacklist
|
||||
chain = blacklist
|
||||
|
||||
# Option: blocktype
|
||||
# Note: This is to match default symbiosis firewall type for blacklisted IPs
|
||||
# Values: STRING
|
||||
blocktype = DROP
|
|
@ -1,9 +1,9 @@
|
|||
# Fail2Ban action configuration file for ufw
|
||||
#
|
||||
# You are required to run "ufw enable" before this will have an effect.
|
||||
# You are required to run "ufw enable" before this will have any effect.
|
||||
#
|
||||
# The insert position should be approprate to block the required traffic.
|
||||
# A number after an allow rule to the application won't be much use.
|
||||
# The insert position should be appropriate to block the required traffic.
|
||||
# A number after an allow rule to the application won't be of much use.
|
||||
|
||||
[Definition]
|
||||
|
||||
|
@ -19,7 +19,7 @@ actionunban = [ -n "<application>" ] && app="app <application>" ; ufw delete <bl
|
|||
|
||||
[Init]
|
||||
# Option: insertpos
|
||||
# Notes.: The postition number in the firewall list to insert the block rule
|
||||
# Notes.: The position number in the firewall list to insert the block rule
|
||||
insertpos = 1
|
||||
|
||||
# Option: blocktype
|
||||
|
|
|
@ -12,7 +12,8 @@ before = common.conf
|
|||
|
||||
_daemon = courieresmtpd
|
||||
|
||||
failregex = ^%(__prefix_line)serror,relay=<HOST>,.*: 550 User unknown\.$
|
||||
failregex = ^%(__prefix_line)serror,relay=<HOST>,.*: 550 User (<.*> )?unknown\.?$
|
||||
^%(__prefix_line)serror,relay=<HOST>,msg="535 Authentication failed\.",cmd:( AUTH \S+)?( [0-9a-zA-Z\+/=]+)?$
|
||||
|
||||
ignoreregex =
|
||||
|
||||
|
|
|
@ -11,9 +11,9 @@ before = common.conf
|
|||
|
||||
[Definition]
|
||||
|
||||
_daemon = (?:cyrus/)?(?:imapd?|pop3d?)
|
||||
_daemon = (?:cyrus/)?(?:imap(d|s)?|pop3(d|s)?)
|
||||
|
||||
failregex = ^%(__prefix_line)sbadlogin: \S+ ?\[<HOST>\] \S+ .*?\[?SASL\(-13\): authentication failure: .*\]?$
|
||||
failregex = ^%(__prefix_line)sbadlogin: \S+ ?\[<HOST>\] \S+ .*?\[?SASL\(-13\): (authentication failure|user not found): .*\]?$
|
||||
|
||||
ignoreregex =
|
||||
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
# Fail2Ban configuration file for Directadmin
|
||||
#
|
||||
#
|
||||
#
|
||||
|
||||
[INCLUDES]
|
||||
|
||||
before = common.conf
|
||||
|
||||
[Definition]
|
||||
|
||||
failregex = ^: \'<HOST>\' \d{1,3} failed login attempt(s)?. \s*
|
||||
|
||||
ignoreregex =
|
||||
|
||||
[Init]
|
||||
datepattern = ^%%Y:%%m:%%d-%%H:%%M:%%S
|
||||
|
||||
#
|
||||
# Requires Directadmin v1.45.3 or higher. http://www.directadmin.com/features.php?id=1590
|
||||
#
|
||||
# Author: Cyril Roos
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
# Fail2Ban filter for monit.conf, looks for failed access attempts
|
||||
#
|
||||
#
|
||||
|
||||
[Definition]
|
||||
|
||||
failregex = ^\[[A-Z]+\s+\]\s*error\s*:\s*Warning:\s+Client '<HOST>' supplied unknown user '\w+' accessing monit httpd$
|
||||
^\[[A-Z]+\s+\]\s*error\s*:\s*Warning:\s+Client '<HOST>' supplied wrong password for user '\w+' accessing monit httpd$
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
# Fail2Ban configuration file
|
||||
# for Oracle IMS with XML logging
|
||||
#
|
||||
# Author: Joel Snyder/jms@opus1.com/2014-June-01
|
||||
#
|
||||
#
|
||||
|
||||
|
||||
[INCLUDES]
|
||||
|
||||
# Read common prefixes.
|
||||
# If any customizations available -- read them from
|
||||
# common.local
|
||||
before = common.conf
|
||||
|
||||
|
||||
[Definition]
|
||||
|
||||
# Option: failregex
|
||||
# Notes.: regex to match the password failures messages
|
||||
# in the logfile. The host must be matched by a
|
||||
# group named "host". The tag "<HOST>" can
|
||||
# be used for standard IP/hostname matching and is
|
||||
# only an alias for
|
||||
# (?:::f{4,6}:)?(?P<host>[\w\-.^_]+)
|
||||
# Values: TEXT
|
||||
#
|
||||
#
|
||||
# CONFIGURATION REQUIREMENTS FOR ORACLE IMS v6 and ABOVE:
|
||||
#
|
||||
# In OPTION.DAT you must have LOG_FORMAT=4 and
|
||||
# bit 5 of LOG_CONNECTION must be set.
|
||||
#
|
||||
# Many of these sub-fields are optional and can be turned on and off
|
||||
# by the system manager. We need the "tr" field
|
||||
# (transport information (present if bit 5 of LOG_CONNECTION is
|
||||
# set and transport information is available)).
|
||||
# "di" should be there by default if you have LOG_FORMAT=4.
|
||||
# Do not use "mi" as this is not included by default.
|
||||
#
|
||||
# Typical line IF YOU ARE USING TAGGING ! ! ! is:
|
||||
# <co ts="2014-06-02T09:45:50.29" pi="123f.3f8.4397"
|
||||
# sc="tcp_local" dr="+" ac="U"
|
||||
# tr="TCP|192.245.12.223|25|151.1.71.144|59762" ap="SMTP"
|
||||
# mi="Bad password"
|
||||
# us="01ko8hqnoif09qx0np@imap.opus1.com"
|
||||
# di="535 5.7.8 Bad username or password (Authentication failed)."/>
|
||||
# Format is generally documented in the PORT_ACCESS mapping
|
||||
# at http://docs.oracle.com/cd/E19563-01/819-4428/bgaur/index.html
|
||||
#
|
||||
# All that would be on one line.
|
||||
# Note that you MUST have LOG_FORMAT=4 for this to work!
|
||||
#
|
||||
|
||||
failregex = ^.*tr="[A-Z]+\|[0-9.]+\|\d+\|<HOST>\|\d+" ap="[^"]*" mi="Bad password" us="[^"]*" di="535 5.7.8 Bad username or password( \(Authentication failed\))?\."/>$
|
||||
|
||||
# Option: ignoreregex
|
||||
# Notes.: regex to ignore. If this regex matches, the line is ignored.
|
||||
# Values: TEXT
|
||||
#
|
||||
ignoreregex =
|
|
@ -11,4 +11,9 @@ _daemon = postfix/smtpd
|
|||
|
||||
failregex = ^%(__prefix_line)swarning: [-._\w]+\[<HOST>\]: SASL (?:LOGIN|PLAIN|(?:CRAM|DIGEST)-MD5) authentication failed(: [ A-Za-z0-9+/]*={0,2})?\s*$
|
||||
|
||||
[Init]
|
||||
|
||||
journalmatch = _SYSTEMD_UNIT=postfix.service
|
||||
|
||||
|
||||
# Author: Yaroslav Halchenko
|
||||
|
|
|
@ -15,7 +15,7 @@ before = common.conf
|
|||
_daemon = pure-ftpd
|
||||
|
||||
# Error message specified in multiple languages
|
||||
__errmsg = (?:<EFBFBD>ϥΪ<EFBFBD>\[.*\]<5D><><EFBFBD>ҥ<EFBFBD><D2A5><EFBFBD>|ʹ<><CAB9><EFBFBD><EFBFBD>\[.*\]<5D><>֤ʧ<D6A4><CAA7>|\[.*\] kullan<61>c<EFBFBD>s<EFBFBD> i<>in giri<72> hatal<61>|<7C><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> \[.*\]|Godkjennelse mislyktes for \[.*\]|Beh<65>righetskontroll misslyckas f<>r anv<6E>ndare \[.*\]|Autentifikacia uzivatela zlyhala \[.*\]|Autentificare esuata pentru utilizatorul \[.*\]|Autentica<63><61>o falhou para usu<73>rio \[.*\]|Autentyfikacja nie powiod<6F>a si<73> dla u<>ytkownika \[.*\]|Autorisatie faalde voor gebruiker \[.*\]|\[.*\] <20><><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>|Autenticazione falita per l'utente \[.*\]|Azonos<6F>t<EFBFBD>s sikertelen \[.*\] felhaszn<7A>l<EFBFBD>nak|\[.*\] c'est un batard, il connait pas son code|Erreur d'authentification pour l'utilisateur \[.*\]|Autentificaci<63>n fallida para el usuario \[.*\]|Authentication failed for user \[.*\]|Authentifizierung fehlgeschlagen f<>r Benutzer \[.*\].|Godkendelse mislykkedes for \[.*\]|Autentifikace u<>ivatele selhala \[.*\])
|
||||
__errmsg = (?:Godkendelse mislykkedes for \[.*\]|Authentifizierung fehlgeschlagen für Benutzer \[.*\].|Authentication failed for user \[.*\]|Autentificación fallida para el usuario \[.*\]|\[.*\] c'est un batard, il connait pas son code|Erreur d'authentification pour l'utilisateur \[.*\]|Azonosítás sikertelen \[.*\] felhasználónak|Autenticazione falita per l'utente \[.*\]|Autorisatie faalde voor gebruiker \[.*\]|Godkjennelse mislyktes for \[.*\]|\[.*\] kullanýcýsý için giriþ hatalý|Autenticação falhou para usuário \[.*\]|Autentificare esuata pentru utilizatorul \[.*\]|Autentifikace uživatele selhala \[.*\]|Autentyfikacja nie powiodła się dla użytkownika \[.*\]|Autentifikacia uzivatela zlyhala \[.*\]|Behörighetskontroll misslyckas för användare \[.*\]|Авторизация не удалась пользователю \[.*\]|\[.*\] 嶸盪 檣隸 褒ぬ|妏蚚氪\[.*\]桄痐囮啖|使用者\[.*\]驗證失敗)
|
||||
|
||||
failregex = ^%(__prefix_line)s\(.+?@<HOST>\) \[WARNING\] %(__errmsg)s\s*$
|
||||
|
||||
|
@ -24,7 +24,13 @@ ignoreregex =
|
|||
# Author: Cyril Jaquier
|
||||
# Modified: Yaroslav Halchenko for pure-ftpd
|
||||
# Documentation thanks to Blake on http://www.fail2ban.org/wiki/index.php?title=Fail2ban:Community_Portal
|
||||
# UTF-8 editing and mechanism thanks to Johannes Weberhofer
|
||||
#
|
||||
# Only logs to syslog though facility can be changed configuration file/command line
|
||||
#
|
||||
# fgrep -r MSG_AUTH_FAILED_LOG pure-ftpd-1.0.36/src
|
||||
# To get messages in the right encoding:
|
||||
# grep MSG_AUTH_FAILED_LOG pure-ftpd-1.0.36/src/messages_[defhint]* | grep -Po '".?"' | recode latin1..utf-8 | tr -d '"' > messages
|
||||
# grep MSG_AUTH_FAILED_LOG pure-ftpd-1.0.36/src/messages_[pr][to] | grep -Po '".?"' | recode latin1..utf-8 | tr -d '"' >> messages
|
||||
# grep MSG_AUTH_FAILED_LOG pure-ftpd-1.0.36/src/messages_[cps][slkv] | grep -Po '".?"' | recode latin2..utf-8 | tr -d '"' >> messages
|
||||
# grep MSG_AUTH_FAILED_LOG pure-ftpd-1.0.36/src/messages_ru | grep -Po '".?"' | recode KOI8-R..utf-8 | tr -d '"' >> messages
|
||||
# grep MSG_AUTH_FAILED_LOG pure-ftpd-1.0.36/src/messages_[kz] | grep -Po '".*?"' | tr -d '"' | recode big5..utf-8 >> messages
|
||||
|
|
|
@ -21,13 +21,13 @@ 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!
|
||||
_jailname = recidive
|
||||
|
||||
failregex = ^(%(__prefix_line)s| %(_daemon)s%(__pid_re)s?:\s+)WARNING\s+\[(?!%(_jailname)s\])(?:.*)\]\s+Ban\s+<HOST>\s*$
|
||||
failregex = ^(%(__prefix_line)s| %(_daemon)s%(__pid_re)s?:\s+)NOTICE\s+\[(?!%(_jailname)s\])(?:.*)\]\s+Ban\s+<HOST>\s*$
|
||||
|
||||
[Init]
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ before = common.conf
|
|||
|
||||
[Definition]
|
||||
|
||||
_deamon = (?:cyrus/)?(?:tim)?sieved?
|
||||
_daemon = (?:cyrus/)?(?:tim)?sieved?
|
||||
|
||||
failregex = ^%(__prefix_line)sbadlogin: \S+ ?\[<HOST>\] \S+ authentication failure$
|
||||
|
||||
|
|
|
@ -30,9 +30,9 @@ failregex = ^%(__prefix_line)s(?:error: PAM: )?[aA]uthentication (?:failure|erro
|
|||
^%(__prefix_line)sReceived disconnect from <HOST>: 3: \S+: Auth fail$
|
||||
^%(__prefix_line)sUser .+ from <HOST> not allowed because a group is listed in DenyGroups\s*$
|
||||
^%(__prefix_line)sUser .+ from <HOST> not allowed because none of user's groups are listed in AllowGroups\s*$
|
||||
^(?P<__prefix>%(__prefix_line)s)User .+ not allowed because account is locked<SKIPLINES>(?P=__prefix)(?:error: )?Received disconnect from <HOST>: 11: Bye Bye \[preauth\]$
|
||||
^(?P<__prefix>%(__prefix_line)s)User .+ not allowed because account is locked<SKIPLINES>(?P=__prefix)(?:error: )?Received disconnect from <HOST>: 11: .+ \[preauth\]$
|
||||
^(?P<__prefix>%(__prefix_line)s)Disconnecting: Too many authentication failures for .+? \[preauth\]<SKIPLINES>(?P=__prefix)(?:error: )?Connection closed by <HOST> \[preauth\]$
|
||||
^(?P<__prefix>%(__prefix_line)s)Connection from <HOST> port \d+<SKIPLINES>(?P=__prefix)Disconnecting: Too many authentication failures for .+? \[preauth\]$
|
||||
^(?P<__prefix>%(__prefix_line)s)Connection from <HOST> port \d+(?: on \S+ port \d+)?<SKIPLINES>(?P=__prefix)Disconnecting: Too many authentication failures for .+? \[preauth\]$
|
||||
|
||||
ignoreregex =
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
#
|
||||
# YOU SHOULD NOT MODIFY THIS FILE.
|
||||
#
|
||||
# It will probably be overwitten or improved in a distribution update.
|
||||
# It will probably be overwritten or improved in a distribution update.
|
||||
#
|
||||
# Provide customizations in a jail.local file or a jail.d/customisation.local.
|
||||
# For example to change the default bantime for all jails and to enable the
|
||||
|
@ -151,22 +151,22 @@ port = 0:65535
|
|||
banaction = iptables-multiport
|
||||
|
||||
# The simplest action to take: ban only
|
||||
action_ = %(banaction)s[name=%(__name__)s, port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"]
|
||||
action_ = %(banaction)s[name=%(__name__)s, bantime="%(bantime)s", port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"]
|
||||
|
||||
# ban & send an e-mail with whois report to the destemail.
|
||||
action_mw = %(banaction)s[name=%(__name__)s, port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"]
|
||||
action_mw = %(banaction)s[name=%(__name__)s, bantime="%(bantime)s", port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"]
|
||||
%(mta)s-whois[name=%(__name__)s, dest="%(destemail)s", protocol="%(protocol)s", chain="%(chain)s"]
|
||||
|
||||
# ban & send an e-mail with whois report and relevant log lines
|
||||
# to the destemail.
|
||||
action_mwl = %(banaction)s[name=%(__name__)s, port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"]
|
||||
action_mwl = %(banaction)s[name=%(__name__)s, bantime="%(bantime)s", port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"]
|
||||
%(mta)s-whois-lines[name=%(__name__)s, dest="%(destemail)s", logpath=%(logpath)s, chain="%(chain)s"]
|
||||
|
||||
# See the IMPORTANT note in action.d/xarf-login-attack for when to use this action
|
||||
#
|
||||
# ban & send a xarf e-mail to abuse contact of IP address and include relevant log lines
|
||||
# to the destemail.
|
||||
action_xarf = %(banaction)s[name=%(__name__)s, port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"]
|
||||
action_xarf = %(banaction)s[name=%(__name__)s, bantime="%(bantime)s", port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"]
|
||||
xarf-login-attack[service=%(__name__)s, sender="%(sender)s", logpath=%(logpath)s, port="%(port)s"]
|
||||
|
||||
|
||||
|
@ -366,11 +366,17 @@ maxretry = 5
|
|||
port = http,https
|
||||
logpath = /var/log/tomcat*/catalina.out
|
||||
|
||||
[monit]
|
||||
#Ban clients brute-forcing the monit gui login
|
||||
filter = monit
|
||||
port = 2812
|
||||
logpath = /var/log/monit
|
||||
|
||||
|
||||
[webmin-auth]
|
||||
|
||||
port = 10000
|
||||
logpath = /var/log/auth.log
|
||||
logpath = %(syslog_authpriv)s
|
||||
|
||||
|
||||
#
|
||||
|
@ -423,7 +429,7 @@ maxretry = 6
|
|||
|
||||
[vsftpd]
|
||||
# or overwrite it in jails.local to be
|
||||
# logpath = /var/log/auth.log
|
||||
# logpath = %(syslog_authpriv)s
|
||||
# if you want to rely on PAM failed login attempts
|
||||
# vsftpd's failregex should match both of those formats
|
||||
port = ftp,ftp-data,ftps,ftps-data
|
||||
|
@ -495,13 +501,13 @@ logpath = %(solidpop3d_log)s
|
|||
[exim]
|
||||
|
||||
port = smtp,465,submission
|
||||
logpath = /var/log/exim/mainlog
|
||||
logpath = %(exim_main_log)s
|
||||
|
||||
|
||||
[exim-spam]
|
||||
|
||||
port = smtp,465,submission
|
||||
logpath = /var/log/exim/mainlog
|
||||
logpath = %(exim_main_log)s
|
||||
|
||||
|
||||
[kerio]
|
||||
|
@ -533,7 +539,7 @@ logpath = %(postfix_log)s
|
|||
[perdition]
|
||||
|
||||
port = imap3,imaps,pop3,pop3s
|
||||
logpath = /var/log/maillog
|
||||
logpath = %(syslog_mail)s
|
||||
|
||||
|
||||
[squirrelmail]
|
||||
|
@ -657,13 +663,13 @@ maxretry = 5
|
|||
[pam-generic]
|
||||
# pam-generic filter can be customized to monitor specific subset of 'tty's
|
||||
banaction = iptables-allports
|
||||
logpath = /var/log/auth.log
|
||||
logpath = %(syslog_authpriv)s
|
||||
|
||||
|
||||
[xinetd-fail]
|
||||
|
||||
banaction = iptables-multiport-log
|
||||
logpath = /var/log/daemon.log
|
||||
logpath = %(syslog_daemon)s
|
||||
maxretry = 2
|
||||
|
||||
|
||||
|
@ -693,5 +699,18 @@ action = %(banaction)s[name=%(__name__)s-tcp, port="%(tcpport)s", protocol="tcp
|
|||
[nagios]
|
||||
|
||||
enabled = false
|
||||
logpath = /var/log/messages ; nrpe.cfg may define a different log_facility
|
||||
logpath = %(syslog_daemon)s ; nrpe.cfg may define a different log_facility
|
||||
maxretry = 1
|
||||
|
||||
|
||||
[oracleims]
|
||||
# see "oracleims" filter file for configuration requirement for Oracle IMS v6 and above
|
||||
enabled = false
|
||||
logpath = /opt/sun/comms/messaging64/log/mail.log_current
|
||||
maxretry = 6
|
||||
banaction = iptables-allports
|
||||
|
||||
[directadmin]
|
||||
enabled = false
|
||||
logpath = /var/log/directadmin/login.log
|
||||
port = 2222
|
||||
|
|
|
@ -7,16 +7,22 @@ after = paths-overrides.local
|
|||
|
||||
[DEFAULT]
|
||||
|
||||
|
||||
|
||||
sshd_log = %(syslog_authpriv)s
|
||||
|
||||
dropbear_log = %(syslog_authpriv)s
|
||||
|
||||
# There is no sensible generic defaults for syslog log targets, thus
|
||||
# leaving them empty here so that no errors while parsing/interpolating configs
|
||||
syslog_daemon =
|
||||
syslog_ftp =
|
||||
syslog_local0 =
|
||||
syslog_mail_warn =
|
||||
syslog_user =
|
||||
|
||||
# from /etc/audit/auditd.conf
|
||||
auditd_log = /var/log/audit/audit.log
|
||||
|
||||
exim_main_log = /var/log/exim/mainlog
|
||||
|
||||
nginx_error_log = /var/log/nginx/error.log
|
||||
|
||||
|
@ -31,7 +37,7 @@ lighttpd_error_log = /var/log/lighttpd/error.log
|
|||
suhosin_log = %(syslog_user)s %(lighttpd_error_log)s
|
||||
|
||||
# defaults to ftp or local2 if ftp doesn't exist
|
||||
proftpd_log = %(syslog_ftp)s
|
||||
proftpd_log = %(syslog_ftp)s
|
||||
|
||||
# http://svnweb.freebsd.org/ports/head/ftp/proftpd/files/patch-src_proftpd.8.in?view=markup
|
||||
# defaults to ftp but can be overwritten.
|
||||
|
|
|
@ -30,6 +30,7 @@ apache_error_log = /var/log/apache2/*error.log
|
|||
|
||||
apache_access_log = /var/log/apache2/*access.log
|
||||
|
||||
exim_main_log = /var/log/exim4/mainlog
|
||||
|
||||
# was in debian squeezy but not in wheezy
|
||||
# /etc/proftpd/proftpd.conf (SystemLog)
|
||||
|
|
|
@ -32,4 +32,6 @@ apache_access_log = /var/log/httpd/*access_log
|
|||
# proftpd_log = /var/log/proftpd/auth.log
|
||||
# Tested and it worked out in /var/log/messages so assuming syslog_ftp for now.
|
||||
|
||||
exim_main_log = /var/log/exim/main.log
|
||||
|
||||
mysql_log = /var/lib/mysql/mysqld.log
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[INCLUDES]
|
||||
|
||||
before = common-paths.conf
|
||||
before = paths-common.conf
|
||||
|
||||
after = paths-overrides.local
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
[INCLUDES]
|
||||
|
||||
before = common-paths.conf
|
||||
before = paths-common.conf
|
||||
|
||||
after = paths-overrides.local
|
||||
|
||||
|
|
|
@ -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):
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
@ -52,6 +51,8 @@ class Beautifier:
|
|||
try:
|
||||
if inC[0] == "ping":
|
||||
msg = "Server replied: " + response
|
||||
elif inC[0] == "version":
|
||||
msg = response
|
||||
elif inC[0] == "start":
|
||||
msg = "Jail started"
|
||||
elif inC[0] == "stop":
|
||||
|
|
|
@ -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']
|
||||
|
||||
|
|
|
@ -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):
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
||||
|
|
|
@ -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):
|
||||
|
||||
|
|
|
@ -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):
|
||||
|
||||
|
|
|
@ -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):
|
||||
|
||||
|
|
|
@ -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):
|
||||
|
||||
|
|
|
@ -20,9 +20,104 @@
|
|||
__author__ = "Cyril Jaquier, Arturo 'Buanzo' Busleiman, Yaroslav Halchenko"
|
||||
__license__ = "GPL"
|
||||
|
||||
import sys
|
||||
import os
|
||||
import traceback
|
||||
import re
|
||||
import logging
|
||||
|
||||
def formatExceptionInfo():
|
||||
""" Consistently format exception information """
|
||||
import sys
|
||||
cla, exc = sys.exc_info()[:2]
|
||||
return (cla.__name__, str(exc))
|
||||
|
||||
#
|
||||
# Following "traceback" functions are adopted from PyMVPA distributed
|
||||
# under MIT/Expat and copyright by PyMVPA developers (i.e. me and
|
||||
# Michael). Hereby I re-license derivative work on these pieces under GPL
|
||||
# to stay in line with the main Fail2Ban license
|
||||
#
|
||||
def mbasename(s):
|
||||
"""Custom function to include directory name if filename is too common
|
||||
|
||||
Also strip .py at the end
|
||||
"""
|
||||
base = os.path.basename(s)
|
||||
if base.endswith('.py'):
|
||||
base = base[:-3]
|
||||
if base in set(['base', '__init__']):
|
||||
base = os.path.basename(os.path.dirname(s)) + '.' + base
|
||||
return base
|
||||
|
||||
class TraceBack(object):
|
||||
"""Customized traceback to be included in debug messages
|
||||
"""
|
||||
|
||||
def __init__(self, compress=False):
|
||||
"""Initialize TrackBack metric
|
||||
|
||||
Parameters
|
||||
----------
|
||||
compress : bool
|
||||
if True then prefix common with previous invocation gets
|
||||
replaced with ...
|
||||
"""
|
||||
self.__prev = ""
|
||||
self.__compress = compress
|
||||
|
||||
def __call__(self):
|
||||
ftb = traceback.extract_stack(limit=100)[:-2]
|
||||
entries = [
|
||||
[mbasename(x[0]), os.path.dirname(x[0]), str(x[1])] for x in ftb]
|
||||
entries = [ [e[0], e[2]] for e in entries
|
||||
if not (e[0] in ['unittest', 'logging.__init__']
|
||||
or e[1].endswith('/unittest'))]
|
||||
|
||||
# lets make it more concise
|
||||
entries_out = [entries[0]]
|
||||
for entry in entries[1:]:
|
||||
if entry[0] == entries_out[-1][0]:
|
||||
entries_out[-1][1] += ',%s' % entry[1]
|
||||
else:
|
||||
entries_out.append(entry)
|
||||
sftb = '>'.join(['%s:%s' % (mbasename(x[0]),
|
||||
x[1]) for x in entries_out])
|
||||
if self.__compress:
|
||||
# lets remove part which is common with previous invocation
|
||||
prev_next = sftb
|
||||
common_prefix = os.path.commonprefix((self.__prev, sftb))
|
||||
common_prefix2 = re.sub('>[^>]*$', '', common_prefix)
|
||||
|
||||
if common_prefix2 != "":
|
||||
sftb = '...' + sftb[len(common_prefix2):]
|
||||
self.__prev = prev_next
|
||||
|
||||
return sftb
|
||||
|
||||
class FormatterWithTraceBack(logging.Formatter):
|
||||
"""Custom formatter which expands %(tb) and %(tbc) with tracebacks
|
||||
|
||||
TODO: might need locking in case of compressed tracebacks
|
||||
"""
|
||||
def __init__(self, fmt, *args, **kwargs):
|
||||
logging.Formatter.__init__(self, fmt=fmt, *args, **kwargs)
|
||||
compress = '%(tbc)s' in fmt
|
||||
self._tb = TraceBack(compress=compress)
|
||||
|
||||
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)
|
||||
|
|
|
@ -38,6 +38,7 @@ protocol = [
|
|||
["status", "gets the current status of the server"],
|
||||
["ping", "tests if the server is alive"],
|
||||
["help", "return this output"],
|
||||
["version", "return the server version"],
|
||||
['', "LOGGING", ""],
|
||||
["set loglevel <LEVEL>", "sets logging level to <LEVEL>. Levels: CRITICAL, ERROR, WARNING, NOTICE, INFO, DEBUG"],
|
||||
["get loglevel", "gets the logging level"],
|
||||
|
|
|
@ -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.
|
||||
|
@ -194,6 +200,8 @@ class CommandAction(ActionBase):
|
|||
timeout
|
||||
"""
|
||||
|
||||
_escapedTags = set(('matches', 'ipmatches', 'ipjailmatches'))
|
||||
|
||||
def __init__(self, jail, name):
|
||||
super(CommandAction, self).__init__(jail, name)
|
||||
self.timeout = 60
|
||||
|
@ -351,8 +359,8 @@ class CommandAction(ActionBase):
|
|||
if not self.executeCmd(stopCmd, self.timeout):
|
||||
raise RuntimeError("Error stopping action")
|
||||
|
||||
@staticmethod
|
||||
def substituteRecursiveTags(tags):
|
||||
@classmethod
|
||||
def substituteRecursiveTags(cls, tags):
|
||||
"""Sort out tag definitions within other tags.
|
||||
|
||||
so: becomes:
|
||||
|
@ -371,8 +379,11 @@ class CommandAction(ActionBase):
|
|||
within the values recursively replaced.
|
||||
"""
|
||||
t = re.compile(r'<([^ >]+)>')
|
||||
for tag, value in tags.iteritems():
|
||||
value = str(value)
|
||||
for tag in tags.iterkeys():
|
||||
if tag in cls._escapedTags:
|
||||
# Escaped so won't match
|
||||
continue
|
||||
value = str(tags[tag])
|
||||
m = t.search(value)
|
||||
done = []
|
||||
#logSys.log(5, 'TAG: %s, value: %s' % (tag, value))
|
||||
|
@ -383,6 +394,9 @@ class CommandAction(ActionBase):
|
|||
# recursive definitions are bad
|
||||
#logSys.log(5, 'recursion fail tag: %s value: %s' % (tag, value) )
|
||||
return False
|
||||
elif found_tag in cls._escapedTags:
|
||||
# Escaped so won't match
|
||||
continue
|
||||
else:
|
||||
if tags.has_key(found_tag):
|
||||
value = value.replace('<%s>' % found_tag , tags[found_tag])
|
||||
|
@ -441,10 +455,11 @@ class CommandAction(ActionBase):
|
|||
`query` string with tags replaced.
|
||||
"""
|
||||
string = query
|
||||
aInfo = cls.substituteRecursiveTags(aInfo)
|
||||
for tag in aInfo:
|
||||
if "<%s>" % tag in query:
|
||||
value = str(aInfo[tag]) # assure string
|
||||
if tag.endswith('matches'):
|
||||
if tag in cls._escapedTags:
|
||||
# That one needs to be escaped since its content is
|
||||
# out of our control
|
||||
value = cls.escapeTag(value)
|
||||
|
|
|
@ -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 getLogger
|
||||
|
||||
# Gets the instance of the logger.
|
||||
logSys = logging.getLogger(__name__)
|
||||
logSys = getLogger(__name__)
|
||||
|
||||
class Actions(JailThread, Mapping):
|
||||
"""Handles jail actions.
|
||||
|
@ -196,6 +197,8 @@ class Actions(JailThread, Mapping):
|
|||
if ticket is not None:
|
||||
# Unban the IP.
|
||||
self.__unBan(ticket)
|
||||
if self._jail.database is not None:
|
||||
self._jail.database.delBan(self._jail, ticket)
|
||||
else:
|
||||
raise ValueError("IP %s is not banned" % ip)
|
||||
|
||||
|
@ -215,7 +218,8 @@ class Actions(JailThread, Mapping):
|
|||
action.start()
|
||||
except Exception as e:
|
||||
logSys.error("Failed to start jail '%s' action '%s': %s",
|
||||
self._jail.name, name, e)
|
||||
self._jail.name, name, e,
|
||||
exc_info=logSys.getEffectiveLevel()<=logging.DEBUG)
|
||||
while self.active:
|
||||
if not self.idle:
|
||||
#logSys.debug(self._jail.name + ": action")
|
||||
|
@ -234,7 +238,8 @@ class Actions(JailThread, Mapping):
|
|||
action.stop()
|
||||
except Exception as e:
|
||||
logSys.error("Failed to stop jail '%s' action '%s': %s",
|
||||
self._jail.name, name, e)
|
||||
self._jail.name, name, e,
|
||||
exc_info=logSys.getEffectiveLevel()<=logging.DEBUG)
|
||||
logSys.debug(self._jail.name + ": action terminated")
|
||||
return True
|
||||
|
||||
|
@ -253,32 +258,31 @@ class Actions(JailThread, Mapping):
|
|||
if ticket != False:
|
||||
aInfo = CallingMap()
|
||||
bTicket = BanManager.createBanTicket(ticket)
|
||||
aInfo["ip"] = bTicket.getIP()
|
||||
ip = bTicket.getIP()
|
||||
aInfo["ip"] = ip
|
||||
aInfo["failures"] = bTicket.getAttempt()
|
||||
aInfo["time"] = bTicket.getTime()
|
||||
aInfo["matches"] = "\n".join(bTicket.getMatches())
|
||||
if self._jail.database is not None:
|
||||
aInfo["ipmatches"] = lambda: "\n".join(
|
||||
self._jail.database.getBansMerged(
|
||||
ip=bTicket.getIP()).getMatches())
|
||||
aInfo["ipjailmatches"] = lambda: "\n".join(
|
||||
self._jail.database.getBansMerged(
|
||||
ip=bTicket.getIP(), jail=self._jail).getMatches())
|
||||
aInfo["ipfailures"] = lambda: "\n".join(
|
||||
self._jail.database.getBansMerged(
|
||||
ip=bTicket.getIP()).getAttempt())
|
||||
aInfo["ipjailfailures"] = lambda: "\n".join(
|
||||
self._jail.database.getBansMerged(
|
||||
ip=bTicket.getIP(), jail=self._jail).getAttempt())
|
||||
aInfo["ipmatches"] = lambda jail=self._jail: "\n".join(
|
||||
jail.database.getBansMerged(ip=ip).getMatches())
|
||||
aInfo["ipjailmatches"] = lambda jail=self._jail: "\n".join(
|
||||
jail.database.getBansMerged(ip=ip, jail=jail).getMatches())
|
||||
aInfo["ipfailures"] = lambda jail=self._jail: \
|
||||
jail.database.getBansMerged(ip=ip).getAttempt()
|
||||
aInfo["ipjailfailures"] = lambda jail=self._jail: \
|
||||
jail.database.getBansMerged(ip=ip, jail=jail).getAttempt()
|
||||
if self.__banManager.addBanTicket(bTicket):
|
||||
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:
|
||||
logSys.notice("[%s] %s already banned" % (self._jail.name,
|
||||
|
@ -321,11 +325,13 @@ 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
|
||||
def status(self):
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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(
|
||||
|
@ -368,10 +368,25 @@ class Fail2BanDb(object):
|
|||
#TODO: Implement data parts once arbitrary match keys completed
|
||||
cur.execute(
|
||||
"INSERT INTO bans(jail, ip, timeofban, data) VALUES(?, ?, ?, ?)",
|
||||
(jail.name, ticket.getIP(), ticket.getTime(),
|
||||
(jail.name, ticket.getIP(), int(round(ticket.getTime())),
|
||||
{"matches": ticket.getMatches(),
|
||||
"failures": ticket.getAttempt()}))
|
||||
|
||||
@commitandrollback
|
||||
def delBan(self, cur, jail, ticket):
|
||||
"""Delete a ban from the database.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
jail : Jail
|
||||
Jail in which the ban has occurred.
|
||||
ticket : BanTicket
|
||||
Ticket of the ban to be removed.
|
||||
"""
|
||||
cur.execute(
|
||||
"DELETE FROM bans WHERE jail = ? AND ip = ? AND timeofban = ?",
|
||||
(jail.name, ticket.getIP(), int(round(ticket.getTime()))))
|
||||
|
||||
@commitandrollback
|
||||
def _getBans(self, cur, jail=None, bantime=None, ip=None):
|
||||
query = "SELECT ip, timeofban, data FROM bans WHERE 1"
|
||||
|
@ -380,7 +395,7 @@ class Fail2BanDb(object):
|
|||
if jail is not None:
|
||||
query += " AND jail=?"
|
||||
queryArgs.append(jail.name)
|
||||
if bantime is not None:
|
||||
if bantime is not None and bantime >= 0:
|
||||
query += " AND timeofban > ?"
|
||||
queryArgs.append(MyTime.time() - bantime)
|
||||
if ip is not None:
|
||||
|
@ -399,7 +414,8 @@ class Fail2BanDb(object):
|
|||
Jail that the ban belongs to. Default `None`; all jails.
|
||||
bantime : int
|
||||
Ban time in seconds, such that bans returned would still be
|
||||
valid now. Default `None`; no limit.
|
||||
valid now. Negative values are equivalent to `None`.
|
||||
Default `None`; no limit.
|
||||
ip : str
|
||||
IP Address to filter bans by. Default `None`; all IPs.
|
||||
|
||||
|
@ -427,7 +443,8 @@ class Fail2BanDb(object):
|
|||
Jail that the ban belongs to. Default `None`; all jails.
|
||||
bantime : int
|
||||
Ban time in seconds, such that bans returned would still be
|
||||
valid now. Default `None`; no limit.
|
||||
valid now. Negative values are equivalent to `None`.
|
||||
Default `None`; no limit.
|
||||
ip : str
|
||||
IP Address to filter bans by. Default `None`; all IPs.
|
||||
|
||||
|
@ -438,7 +455,8 @@ class Fail2BanDb(object):
|
|||
in a list. When `ip` argument passed, a single `Ticket` is
|
||||
returned.
|
||||
"""
|
||||
if bantime is None:
|
||||
cacheKey = None
|
||||
if bantime is None or bantime < 0:
|
||||
cacheKey = (ip, jail)
|
||||
if cacheKey in self._bansMergedCache:
|
||||
return self._bansMergedCache[cacheKey]
|
||||
|
@ -468,7 +486,7 @@ class Fail2BanDb(object):
|
|||
ticket.setAttempt(failures)
|
||||
tickets.append(ticket)
|
||||
|
||||
if bantime is None:
|
||||
if cacheKey:
|
||||
self._bansMergedCache[cacheKey] = tickets if ip is None else ticket
|
||||
return tickets if ip is None else ticket
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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:
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
||||
|
|
|
@ -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 getLogger
|
||||
|
||||
# Gets the instance of the logger.
|
||||
logSys = logging.getLogger(__name__)
|
||||
logSys = getLogger(__name__)
|
||||
|
||||
##
|
||||
# Log reader class.
|
||||
|
@ -790,8 +791,10 @@ class FileContainer:
|
|||
try:
|
||||
line = line.decode(self.getEncoding(), 'strict')
|
||||
except UnicodeDecodeError:
|
||||
logSys.warning("Error decoding line from '%s' with '%s': %s" %
|
||||
(self.getFileName(), self.getEncoding(), `line`))
|
||||
logSys.warning(
|
||||
"Error decoding line from '%s' with '%s'. Continuing "
|
||||
" to process line ignoring invalid characters: %r" %
|
||||
(self.getFileName(), self.getEncoding(), line))
|
||||
if sys.version_info >= (3,): # In python3, must be decoded
|
||||
line = line.decode(self.getEncoding(), 'ignore')
|
||||
return line
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
|
@ -167,8 +167,9 @@ class FilterSystemd(JournalFilter): # pragma: systemd no cover
|
|||
logelements.append(logentry['_HOSTNAME'])
|
||||
if logentry.get('SYSLOG_IDENTIFIER'):
|
||||
logelements.append(logentry['SYSLOG_IDENTIFIER'])
|
||||
if logentry.get('_PID'):
|
||||
logelements[-1] += ("[%i]" % logentry['_PID'])
|
||||
if logentry.get('SYSLOG_PID') or logentry.get('_PID'):
|
||||
logelements[-1] += ("[%i]" % logentry.get(
|
||||
'SYSLOG_PID', logentry['_PID']))
|
||||
logelements[-1] += ":"
|
||||
elif logentry.get('_COMM'):
|
||||
logelements.append(logentry['_COMM'])
|
||||
|
@ -212,6 +213,12 @@ class FilterSystemd(JournalFilter): # pragma: systemd no cover
|
|||
|
||||
def run(self):
|
||||
|
||||
if not self.getJournalMatch():
|
||||
logSys.notice(
|
||||
"Jail started without 'journalmatch' set. "
|
||||
"Jail regexs will be checked against all journal entries, "
|
||||
"which is not advised for performance reasons.")
|
||||
|
||||
# Seek to now - findtime in journal
|
||||
start_time = datetime.datetime.now() - \
|
||||
datetime.timedelta(seconds=int(self.getFindTime()))
|
||||
|
|
|
@ -26,9 +26,10 @@ __license__ = "GPL"
|
|||
import Queue, logging
|
||||
|
||||
from .actions import Actions
|
||||
from ..helpers import getLogger
|
||||
|
||||
# Gets the instance of the logger.
|
||||
logSys = logging.getLogger(__name__)
|
||||
logSys = getLogger(__name__)
|
||||
|
||||
class Jail:
|
||||
"""Fail2Ban jail, which manages a filter and associated actions.
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -32,9 +32,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
|
||||
|
@ -69,6 +70,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
|
||||
|
@ -335,7 +339,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")
|
||||
|
@ -367,7 +371,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 +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(__name__).parent.parent
|
||||
logger = getLogger("fail2ban")
|
||||
for handler in logger.handlers[::-1]:
|
||||
# Remove the handler.
|
||||
logger.removeHandler(handler)
|
||||
|
@ -425,7 +429,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)
|
||||
|
@ -434,7 +438,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"
|
||||
|
@ -523,11 +527,19 @@ class Server:
|
|||
except (AttributeError, ValueError):
|
||||
maxfd = 256 # default maximum
|
||||
|
||||
for fd in range(0, maxfd):
|
||||
try:
|
||||
os.close(fd)
|
||||
except OSError: # ERROR (ignore)
|
||||
pass
|
||||
# urandom should not be closed in Python 3.4.0. Fixed in 3.4.1
|
||||
# http://bugs.python.org/issue21207
|
||||
if sys.version_info[0:3] == (3, 4, 0): # pragma: no cover
|
||||
urandom_fd = os.open("/dev/urandom", os.O_RDONLY)
|
||||
for fd in range(0, maxfd):
|
||||
try:
|
||||
if not os.path.sameopenfile(urandom_fd, fd):
|
||||
os.close(fd)
|
||||
except OSError: # ERROR (ignore)
|
||||
pass
|
||||
os.close(urandom_fd)
|
||||
else:
|
||||
os.closerange(0, maxfd)
|
||||
|
||||
# Redirect the standard file descriptors to /dev/null.
|
||||
os.open("/dev/null", os.O_RDONLY) # standard input (0)
|
||||
|
|
|
@ -190,5 +190,5 @@ def reGroupDictStrptime(found_dict):
|
|||
if gmtoff is not None:
|
||||
return calendar.timegm(date_result.utctimetuple())
|
||||
else:
|
||||
return time.mktime(date_result.utctimetuple())
|
||||
return time.mktime(date_result.timetuple())
|
||||
|
||||
|
|
|
@ -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 Ticket:
|
||||
|
||||
|
|
|
@ -24,11 +24,14 @@ __author__ = "Cyril Jaquier"
|
|||
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
||||
__license__ = "GPL"
|
||||
|
||||
import logging, time
|
||||
import time
|
||||
import json
|
||||
|
||||
from ..helpers import getLogger
|
||||
from .. import version
|
||||
|
||||
# Gets the instance of the logger.
|
||||
logSys = logging.getLogger(__name__)
|
||||
logSys = getLogger(__name__)
|
||||
|
||||
class Transmitter:
|
||||
|
||||
|
@ -100,7 +103,9 @@ class Transmitter:
|
|||
elif command[0] == "get":
|
||||
return self.__commandGet(command[1:])
|
||||
elif command[0] == "status":
|
||||
return self.status(command[1:])
|
||||
return self.status(command[1:])
|
||||
elif command[0] == "version":
|
||||
return version.version
|
||||
raise Exception("Invalid command")
|
||||
|
||||
def __commandSet(self, command):
|
||||
|
|
|
@ -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,28 @@ 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.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"))
|
||||
|
|
|
@ -100,17 +100,24 @@ class CommandActionTest(LogCaptureTestCase):
|
|||
{'ipjailmatches': "some >char< should \< be[ escap}ed&\n"}),
|
||||
"some \\>char\\< should \\\\\\< be\\[ escap\\}ed\\&\n")
|
||||
|
||||
|
||||
# Recursive
|
||||
aInfo["ABC"] = "<xyz>"
|
||||
self.assertEqual(
|
||||
self.__action.replaceTag("Text <xyz> text <ABC> ABC", aInfo),
|
||||
"Text 890 text 890 ABC")
|
||||
|
||||
# Callable
|
||||
self.assertEqual(
|
||||
self.__action.replaceTag("09 <callme> 11",
|
||||
CallingMap(callme=lambda: str(10))),
|
||||
self.__action.replaceTag("09 <matches> 11",
|
||||
CallingMap(matches=lambda: str(10))),
|
||||
"09 10 11")
|
||||
|
||||
# As tag not present, therefore callable should not be called
|
||||
# Will raise ValueError if it is
|
||||
self.assertEqual(
|
||||
self.__action.replaceTag("abc",
|
||||
CallingMap(callme=lambda: int("a"))), "abc")
|
||||
CallingMap(matches=lambda: int("a"))), "abc")
|
||||
|
||||
def testExecuteActionBan(self):
|
||||
self.__action.actionstart = "touch /tmp/fail2ban.test"
|
||||
|
|
|
@ -173,14 +173,25 @@ class DatabaseTest(unittest.TestCase):
|
|||
self.assertTrue(
|
||||
isinstance(self.db.getBans(jail=self.jail)[0], FailTicket))
|
||||
|
||||
def testDelBan(self):
|
||||
self.testAddBan()
|
||||
ticket = self.db.getBans(jail=self.jail)[0]
|
||||
self.db.delBan(self.jail, ticket)
|
||||
self.assertEqual(len(self.db.getBans(jail=self.jail)), 0)
|
||||
|
||||
def testGetBansWithTime(self):
|
||||
if Fail2BanDb is None: # pragma: no cover
|
||||
return
|
||||
self.testAddJail()
|
||||
ticket = FailTicket("127.0.0.1", MyTime.time() - 40, ["abc\n"])
|
||||
self.db.addBan(self.jail, ticket)
|
||||
self.db.addBan(
|
||||
self.jail, FailTicket("127.0.0.1", MyTime.time() - 60, ["abc\n"]))
|
||||
self.db.addBan(
|
||||
self.jail, FailTicket("127.0.0.1", MyTime.time() - 40, ["abc\n"]))
|
||||
self.assertEqual(len(self.db.getBans(jail=self.jail,bantime=50)), 1)
|
||||
self.assertEqual(len(self.db.getBans(jail=self.jail,bantime=20)), 0)
|
||||
# Negative values are for persistent bans, and such all bans should
|
||||
# be returned
|
||||
self.assertEqual(len(self.db.getBans(jail=self.jail,bantime=-1)), 2)
|
||||
|
||||
def testGetBansMerged(self):
|
||||
if Fail2BanDb is None: # pragma: no cover
|
||||
|
@ -251,6 +262,10 @@ class DatabaseTest(unittest.TestCase):
|
|||
self.assertEqual(len(tickets), 1)
|
||||
tickets = self.db.getBansMerged(bantime=5)
|
||||
self.assertEqual(len(tickets), 0)
|
||||
# Negative values are for persistent bans, and such all bans should
|
||||
# be returned
|
||||
tickets = self.db.getBansMerged(bantime=-1)
|
||||
self.assertEqual(len(tickets), 2)
|
||||
|
||||
def testPurge(self):
|
||||
if Fail2BanDb is None: # pragma: no cover
|
||||
|
|
|
@ -131,7 +131,7 @@ class DateDetectorTest(unittest.TestCase):
|
|||
# see https://github.com/fail2ban/fail2ban/pull/130
|
||||
# yoh: unfortunately this test is not really effective to reproduce the
|
||||
# situation but left in place to assure consistent behavior
|
||||
mu = time.mktime(datetime.datetime(2012, 10, 11, 2, 37, 17).utctimetuple())
|
||||
mu = time.mktime(datetime.datetime(2012, 10, 11, 2, 37, 17).timetuple())
|
||||
logdate = self.__datedetector.getTime('2012/10/11 02:37:17 [error] 18434#0')
|
||||
self.assertNotEqual(logdate, None)
|
||||
( logTime, logMatch ) = logdate
|
||||
|
|
|
@ -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
|
|
@ -1,5 +1,9 @@
|
|||
# failJSON: { "time": "2005-04-10T03:47:57", "match": true , "host": "1.2.3.4" }
|
||||
Apr 10 03:47:57 web courieresmtpd: error,relay=::ffff:1.2.3.4,ident=tmf,from=<tmf@example.com>,to=<mailman-subscribe@example.com>: 550 User unknown.
|
||||
# failJSON: { "time": "2005-07-03T23:07:20", "match": true , "host": "1.2.3.4" }
|
||||
Jul 3 23:07:20 szerver courieresmtpd: error,relay=::ffff:1.2.3.4,msg="535 Authentication failed.",cmd: YWRvYmVhZG9iZQ==
|
||||
# failJSON: { "time": "2005-07-04T18:39:39", "match": true , "host": "1.2.3.4" }
|
||||
Jul 4 18:39:39 mail courieresmtpd: error,relay=::ffff:1.2.3.4,from=<picaro@astroboymail.com>,to=<user@update.net>: 550 User <benny> unknown
|
||||
# failJSON: { "time": "2005-07-06T03:42:28", "match": true , "host": "1.2.3.4" }
|
||||
Jul 6 03:42:28 whistler courieresmtpd: error,relay=::ffff:1.2.3.4,from=<>,to=<admin at memcpy>: 550 User unknown.
|
||||
# failJSON: { "time": "2004-11-21T23:16:17", "match": true , "host": "1.2.3.4" }
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
# failJSON: { "time": "2005-01-04T21:51:05", "match": true , "host": "127.0.0.1" }
|
||||
Jan 4 21:51:05 hostname cyrus/imap[5355]: badlogin: localhost.localdomain [127.0.0.1] plaintext cyrus@localdomain SASL(-13): authentication failure: checkpass failed
|
||||
# failJSON: { "time": "2005-01-04T21:51:05", "match": true , "host": "127.0.0.1", "desc": "For secure imaps" }
|
||||
Jan 4 21:51:05 hostname cyrus/imaps[5355]: badlogin: localhost.localdomain [127.0.0.1] plaintext cyrus@localdomain SASL(-13): authentication failure: checkpass failed
|
||||
# failJSON: { "time": "2005-02-20T17:23:32", "match": true , "host": "198.51.100.23" }
|
||||
Feb 20 17:23:32 domain cyrus/pop3[18635]: badlogin: localhost [198.51.100.23] plaintext administrator SASL(-13): authentication failure: checkpass failed
|
||||
# failJSON: { "time": "2005-02-20T17:23:32", "match": true , "host": "1.2.3.4" }
|
||||
|
@ -10,4 +12,7 @@ Jun 8 18:11:13 lampserver imap[4480]: badlogin: example.com [198.51.100.45] DIGE
|
|||
Dec 21 10:01:57 hostname imapd[18454]: badlogin: example.com [198.51.100.57] CRAM-MD5 [SASL(-13): authentication failure: incorrect digest response]
|
||||
# failJSON: { "time": "2004-12-30T16:03:27", "match": true , "host": "1.2.3.4" }
|
||||
Dec 30 16:03:27 somehost imapd[2517]: badlogin: local-somehost[1.2.3.4] OTP [SASL(-13): authentication failure: External SSF not good enough]
|
||||
|
||||
# failJSON: { "time": "2005-07-17T22:55:56", "match": true , "host": "1.2.3.4" }
|
||||
Jul 17 22:55:56 derry cyrus/imaps[7568]: badlogin: serafinat.xxxxxx [1.2.3.4] plain [SASL(-13): user not found: user: pressy@derry property: cmusaslsecretPLAIN not found in sasldb]
|
||||
# failJSON: { "time": "2005-07-18T16:46:42", "match": true , "host": "1.2.3.4" }
|
||||
Jul 18 16:46:42 derry cyrus/imaps[27449]: badlogin: serafinat.xxxxxx [1.2.3.4] PLAIN [SASL(-13): user not found: Password verification failed]
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
# failJSON: { "time": "2014-07-02T00:17:45", "match": true , "host": "3.2.1.4" }
|
||||
2014:07:02-00:17:45: '3.2.1.4' 2 failed login attempts. Account 'test'
|
||||
|
||||
# failJSON: { "time": "2014-07-02T13:07:40", "match": true , "host": "40.40.123.231" }
|
||||
2014:07:02-13:07:40: '40.40.123.231' 13 failed login attempts. Account 'admin'
|
||||
|
||||
# failJSON: { "time": "2014-07-02T13:07:50", "match": true , "host": "40.40.123.231" }
|
||||
2014:07:02-13:07:50: '40.40.123.231' 5 failed login attempt. Invalid account 'user%2Ename'
|
||||
|
||||
# failJSON: { "time": "2014-07-02T13:28:39", "match": false , "host": "12.12.123.231" }
|
||||
2014:07:02-13:28:39: '12.12.123.231' successful login to 'nobody' after 1 attempts
|
||||
|
||||
# failJSON: { "time": "2014-07-02T13:29:38", "match": true , "host": "1.2.3.4" }
|
||||
2014:07:02-13:29:38: '1.2.3.4' 2 failed login attempts. Account 'user' via 'admin'
|
|
@ -1,12 +1,12 @@
|
|||
# failJSON: { "time": "2010-09-16T06:51:00", "match": true , "host": "80.187.101.33" }
|
||||
# failJSON: { "time": "2010-09-16T07:51:00", "match": true , "host": "80.187.101.33" }
|
||||
@400000004c91b044077a9e94 imap-login: Info: Aborted login (auth failed, 1 attempts): user=<martin@waschbuesch.de>, method=CRAM-MD5, rip=80.187.101.33, lip=80.254.129.240, TLS
|
||||
|
||||
# failJSON: { "time": "2010-09-16T06:51:00", "match": true , "host": "176.61.140.224" }
|
||||
# failJSON: { "time": "2010-09-16T07:51:00", "match": true , "host": "176.61.140.224" }
|
||||
@400000004c91b044077a9e94 dovecot-auth: pam_unix(dovecot:auth): authentication failure; logname= uid=0 euid=0 tty=dovecot ruser=web rhost=176.61.140.224
|
||||
# Above example with injected rhost into ruser -- should not match for 1.2.3.4
|
||||
# failJSON: { "time": "2010-09-16T06:51:00", "match": true , "host": "192.0.43.10" }
|
||||
# failJSON: { "time": "2010-09-16T07:51:00", "match": true , "host": "192.0.43.10" }
|
||||
@400000004c91b044077a9e94 dovecot-auth: pam_unix(dovecot:auth): authentication failure; logname= uid=0 euid=0 tty=dovecot ruser=rhost=1.2.3.4 rhost=192.0.43.10
|
||||
# failJSON: { "time": "2010-09-16T06:51:00", "match": true , "host": "176.61.140.225" }
|
||||
# failJSON: { "time": "2010-09-16T07:51:00", "match": true , "host": "176.61.140.225" }
|
||||
@400000004c91b044077a9e94 dovecot-auth: pam_unix(dovecot:auth): authentication failure; logname= uid=0 euid=0 tty=dovecot ruser=root rhost=176.61.140.225 user=root
|
||||
|
||||
# failJSON: { "time": "2004-12-12T11:19:11", "match": true , "host": "190.210.136.21" }
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
# failJSON: { "time": "2005-04-16T21:05:29", "match": true , "host": "69.93.127.111" }
|
||||
[PDT Apr 16 21:05:29] error : Warning: Client '69.93.127.111' supplied unknown user 'foo' accessing monit httpd
|
||||
|
||||
# failJSON: { "time": "2005-04-16T20:59:33", "match": true , "host": "97.113.189.111" }
|
||||
[PDT Apr 16 20:59:33] error : Warning: Client '97.113.189.111' supplied wrong password for user 'admin' accessing monit httpd
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
# CONFIGURATION REQUIREMENTS FOR ORACLE IMS v6.3 and ABOVE:
|
||||
#
|
||||
# In OPTION.DAT you must have LOG_FORMAT=4 and
|
||||
# bit 5 of LOG_CONNECTION must be set.
|
||||
#
|
||||
# Many of these sub-fields are optional and can be turned on and off
|
||||
# by the system manager. We need the "tr" field
|
||||
# (transport information (present if bit 5 of LOG_CONNECTION is
|
||||
# set and transport information is available)).
|
||||
# "di" should be there by default if you have LOG_FORMAT=4.
|
||||
#
|
||||
# failJSON: { "time": "2014-06-02T22:02:13", "match": false , "host": "23.122.129.179" }
|
||||
<co ts="2014-06-02T22:02:13.94" pi="72a9.3b4.3774" sc="tcp_submit" dr="+" ac="U" tr="TCP|192.245.12.223|465|23.122.129.179|60766" ap="SMTP/TLS-128-RC4" mi="Authentication successful - switched to channel tcp_submit" us="jaugustine@example.org" di="235 2.7.0 LOGIN authentication successful."/>
|
||||
# failJSON: { "time": "2014-06-02T16:06:33", "match": true , "host": "89.96.245.78" }
|
||||
<co ts="2014-06-02T16:06:33.99" pi="72aa.17f0.25622" sc="tcp_local" dr="+" ac="U" tr="TCP|192.245.12.223|25|89.96.245.78|4299" ap="SMTP" mi="Bad password" us="nic@transcend.com" di="535 5.7.8 Bad username or password (Authentication failed)."/>
|
||||
# failJSON: { "time": "2014-06-02T10:08:07", "match": true , "host": "71.95.206.106" }
|
||||
<co ts="2014-06-02T10:08:07.56" pi="123f.8e2.9022" sc="tcp_local" dr="+" ac="U" tr="TCP|192.245.12.223|25|71.95.206.106|56591" ap="SMTP" mi="Bad password" us="romeo.julieta@opus1.com" di="535 5.7.8 Bad username or password (Authentication failed)."/>
|
||||
# failJSON: { "time": "2014-06-02T09:54:58", "match": true , "host": "151.1.71.144" }
|
||||
<co ts="2014-06-02T09:54:58.82" pi="123f.715.7116" sc="tcp_local" dr="+" ac="U" tr="TCP|192.245.12.223|25|151.1.71.144|58406" ap="SMTP" mi="Bad password" us="01ko8hqnoif09qx0np@imap.opus1.com" di="535 5.7.8 Bad username or password (Authentication failed)."/>
|
|
@ -1,12 +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: WARNING [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]: WARNING [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: WARNING [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: WARNING [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: WARNING [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.actions [123]: NOTICE [sendmail] Ban 1.2.3.4
|
||||
|
|
|
@ -1,25 +1,25 @@
|
|||
# failJSON: { "time": "2013-07-09T01:45:16", "match": false , "host": "173.242.116.187" }
|
||||
# failJSON: { "time": "2013-07-09T02:45:16", "match": false , "host": "173.242.116.187" }
|
||||
type=USER_LOGIN msg=audit(1373330716.415:4063): user pid=11998 uid=0 auid=4294967295 ses=4294967295 subj=system_u:system_r:sshd_t:s0-s0:c0.c1023 msg='op=login acct="root" exe="/usr/sbin/sshd" hostname=? addr=173.242.116.187 terminal=ssh res=failed'
|
||||
|
||||
# failJSON: { "time": "2013-07-09T01:45:17", "match": false , "host": "173.242.116.187" }
|
||||
# failJSON: { "time": "2013-07-09T02:45:17", "match": false , "host": "173.242.116.187" }
|
||||
type=USER_LOGIN msg=audit(1373330717.000:4068): user pid=12000 uid=0 auid=4294967295 ses=4294967295 subj=system_u:system_r:sshd_t:s0-s0:c0.c1023 msg='op=login acct=28756E6B6E6F776E207573657229 exe="/usr/sbin/sshd" hostname=? addr=173.242.116.187 terminal=ssh res=failed'
|
||||
|
||||
# failJSON: { "time": "2013-07-09T01:45:17", "match": true , "host": "173.242.116.187" }
|
||||
# failJSON: { "time": "2013-07-09T02:45:17", "match": true , "host": "173.242.116.187" }
|
||||
type=USER_ERR msg=audit(1373330717.000:4070): user pid=12000 uid=0 auid=4294967295 ses=4294967295 subj=system_u:system_r:sshd_t:s0-s0:c0.c1023 msg='op=PAM:bad_ident acct="?" exe="/usr/sbin/sshd" hostname=173.242.116.187 addr=173.242.116.187 terminal=ssh res=failed'
|
||||
|
||||
# failJSON: { "time": "2013-07-09T01:45:17", "match": false , "host": "173.242.116.187" }
|
||||
# failJSON: { "time": "2013-07-09T02:45:17", "match": false , "host": "173.242.116.187" }
|
||||
type=USER_LOGIN msg=audit(1373330717.000:4073): user pid=12000 uid=0 auid=4294967295 ses=4294967295 subj=system_u:system_r:sshd_t:s0-s0:c0.c1023 msg='op=login acct=28696E76616C6964207573657229 exe="/usr/sbin/sshd" hostname=? addr=173.242.116.187 terminal=ssh res=failed'
|
||||
|
||||
# failJSON: { "time": "2013-06-30T01:02:08", "match": false , "host": "113.240.248.18" }
|
||||
# failJSON: { "time": "2013-06-30T02:02:08", "match": false , "host": "113.240.248.18" }
|
||||
type=USER_LOGIN msg=audit(1372546928.000:52008): user pid=21569 uid=0 auid=0 ses=76 subj=unconfined_u:system_r:sshd_t:s0-s0:c0.c1023 msg='op=login acct="sshd" exe="/usr/sbin/sshd" hostname=? addr=113.240.248.18 terminal=ssh res=failed'
|
||||
|
||||
# failJSON: { "time": "2013-06-30T02:58:20", "match": true , "host": "113.240.248.18" }
|
||||
# failJSON: { "time": "2013-06-30T03:58:20", "match": true , "host": "113.240.248.18" }
|
||||
type=USER_ERR msg=audit(1372557500.000:61747): user pid=23684 uid=0 auid=0 ses=76 subj=unconfined_u:system_r:sshd_t:s0-s0:c0.c1023 msg='op=PAM:bad_ident acct="?" exe="/usr/sbin/sshd" hostname=113.240.248.18 addr=113.240.248.18 terminal=ssh res=failed'
|
||||
|
||||
# failJSON: { "time": "2013-06-30T03:58:20", "match": false , "host": "113.240.248.18" }
|
||||
# failJSON: { "time": "2013-06-30T04:58:20", "match": false , "host": "113.240.248.18" }
|
||||
type=USER_LOGIN msg=audit(1372557500.000:61750): user pid=23684 uid=0 auid=0 ses=76 subj=unconfined_u:system_r:sshd_t:s0-s0:c0.c1023 msg='op=login acct=28696E76616C6964207573657229 exe="/usr/sbin/sshd" hostname=? addr=113.240.248.18 terminal=ssh res=failed'
|
||||
|
||||
# failJSON: { "time": "2013-07-06T17:48:00", "match": true , "host": "194.228.20.113" }
|
||||
# failJSON: { "time": "2013-07-06T18:48:00", "match": true , "host": "194.228.20.113" }
|
||||
type=USER_AUTH msg=audit(1373129280.000:9): user pid=1277 uid=0 auid=4294967295 ses=4294967295 subj=system_u:system_r:sshd_t:s0-s0:c0.c1023 msg='op=pubkey acct="root" exe="/usr/sbin/sshd" hostname=? addr=194.228.20.113 terminal=ssh res=failed'
|
||||
|
||||
# failJSON: { "time": "2013-10-30T07:57:43", "match": true , "host": "192.168.3.100" }
|
||||
|
|
|
@ -136,3 +136,15 @@ Jul 13 18:44:28 mdop sshd[4931]: Received disconnect from 89.24.13.192: 3: com.j
|
|||
Feb 12 04:09:18 localhost sshd[26713]: Connection from 115.249.163.77 port 51353
|
||||
# failJSON: { "time": "2005-02-12T04:09:21", "match": true , "host": "115.249.163.77", "desc": "from gh-457" }
|
||||
Feb 12 04:09:21 localhost sshd[26713]: Disconnecting: Too many authentication failures for root [preauth]
|
||||
|
||||
# failJSON: { "match": false }
|
||||
Feb 12 04:09:18 localhost sshd[26713]: Connection from 115.249.163.77 port 51353 on 127.0.0.1 port 22
|
||||
# failJSON: { "time": "2005-02-12T04:09:21", "match": true , "host": "115.249.163.77", "desc": "Multiline match with interface address" }
|
||||
Feb 12 04:09:21 localhost sshd[26713]: Disconnecting: Too many authentication failures for root [preauth]
|
||||
|
||||
# failJSON: { "match": false }
|
||||
Apr 27 13:02:04 host sshd[29116]: User root not allowed because account is locked
|
||||
# failJSON: { "match": false }
|
||||
Apr 27 13:02:04 host sshd[29116]: input_userauth_request: invalid user root [preauth]
|
||||
# failJSON: { "time": "2005-04-27T13:02:04", "match": true , "host": "1.2.3.4", "desc": "No Bye-Bye" }
|
||||
Apr 27 13:02:04 host sshd[29116]: Received disconnect from 1.2.3.4: 11: Normal Shutdown, Thank you for playing [preauth]
|
||||
|
|
|
@ -24,6 +24,7 @@ __license__ = "GPL"
|
|||
|
||||
from __builtin__ import open as fopen
|
||||
import unittest
|
||||
import getpass
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
|
@ -349,10 +350,20 @@ class LogFileMonitor(LogCaptureTestCase):
|
|||
# shorter wait time for not modified status
|
||||
return not self.isModified(0.4)
|
||||
|
||||
def testNoLogFile(self):
|
||||
def testUnaccessibleLogFile(self):
|
||||
os.chmod(self.name, 0)
|
||||
self.filter.getFailures(self.name)
|
||||
self.assertTrue(self._is_logged('Unable to open %s' % self.name))
|
||||
failure_was_logged = self._is_logged('Unable to open %s' % self.name)
|
||||
is_root = getpass.getuser() == 'root'
|
||||
# If ran as root, those restrictive permissions would not
|
||||
# forbid log to be read.
|
||||
self.assertTrue(failure_was_logged != is_root)
|
||||
|
||||
def testNoLogFile(self):
|
||||
_killfile(self.file, self.name)
|
||||
self.filter.getFailures(self.name)
|
||||
failure_was_logged = self._is_logged('Unable to open %s' % self.name)
|
||||
self.assertTrue(failure_was_logged)
|
||||
|
||||
def testRemovingFailRegex(self):
|
||||
self.filter.delFailRegex(0)
|
||||
|
@ -794,7 +805,7 @@ class GetFailures(unittest.TestCase):
|
|||
FILENAME_MULTILINE = os.path.join(TEST_FILES_DIR, "testcase-multiline.log")
|
||||
|
||||
# so that they could be reused by other tests
|
||||
FAILURES_01 = ('193.168.0.128', 3, 1124017199.0,
|
||||
FAILURES_01 = ('193.168.0.128', 3, 1124013599.0,
|
||||
[u'Aug 14 11:59:59 [sshd] error: PAM: Authentication failure for kevin from 193.168.0.128']*3)
|
||||
|
||||
def setUp(self):
|
||||
|
@ -844,7 +855,7 @@ class GetFailures(unittest.TestCase):
|
|||
|
||||
|
||||
def testGetFailures02(self):
|
||||
output = ('141.3.81.106', 4, 1124017139.0,
|
||||
output = ('141.3.81.106', 4, 1124013539.0,
|
||||
[u'Aug 14 11:%d:59 i60p295 sshd[12365]: Failed publickey for roehl from ::ffff:141.3.81.106 port 51332 ssh2'
|
||||
% m for m in 53, 54, 57, 58])
|
||||
|
||||
|
@ -854,7 +865,7 @@ class GetFailures(unittest.TestCase):
|
|||
_assert_correct_last_attempt(self, self.filter, output)
|
||||
|
||||
def testGetFailures03(self):
|
||||
output = ('203.162.223.135', 7, 1124017144.0)
|
||||
output = ('203.162.223.135', 7, 1124013544.0)
|
||||
|
||||
self.filter.addLogPath(GetFailures.FILENAME_03)
|
||||
self.filter.addFailRegex("error,relay=<HOST>,.*550 User unknown")
|
||||
|
@ -862,7 +873,7 @@ class GetFailures(unittest.TestCase):
|
|||
_assert_correct_last_attempt(self, self.filter, output)
|
||||
|
||||
def testGetFailures04(self):
|
||||
output = [('212.41.96.186', 4, 1124017200.0),
|
||||
output = [('212.41.96.186', 4, 1124013600.0),
|
||||
('212.41.96.185', 4, 1124017198.0)]
|
||||
|
||||
self.filter.addLogPath(GetFailures.FILENAME_04)
|
||||
|
@ -877,11 +888,11 @@ class GetFailures(unittest.TestCase):
|
|||
|
||||
def testGetFailuresUseDNS(self):
|
||||
# We should still catch failures with usedns = no ;-)
|
||||
output_yes = ('93.184.216.119', 2, 1124017139.0,
|
||||
output_yes = ('93.184.216.119', 2, 1124013539.0,
|
||||
[u'Aug 14 11:54:59 i60p295 sshd[12365]: Failed publickey for roehl from example.com port 51332 ssh2',
|
||||
u'Aug 14 11:58:59 i60p295 sshd[12365]: Failed publickey for roehl from ::ffff:93.184.216.119 port 51332 ssh2'])
|
||||
|
||||
output_no = ('93.184.216.119', 1, 1124017139.0,
|
||||
output_no = ('93.184.216.119', 1, 1124013539.0,
|
||||
[u'Aug 14 11:58:59 i60p295 sshd[12365]: Failed publickey for roehl from ::ffff:93.184.216.119 port 51332 ssh2'])
|
||||
|
||||
# Actually no exception would be raised -- it will be just set to 'no'
|
||||
|
@ -904,7 +915,7 @@ class GetFailures(unittest.TestCase):
|
|||
|
||||
|
||||
def testGetFailuresMultiRegex(self):
|
||||
output = ('141.3.81.106', 8, 1124017141.0)
|
||||
output = ('141.3.81.106', 8, 1124013541.0)
|
||||
|
||||
self.filter.addLogPath(GetFailures.FILENAME_02)
|
||||
self.filter.addFailRegex("Failed .* from <HOST>")
|
||||
|
@ -923,8 +934,8 @@ class GetFailures(unittest.TestCase):
|
|||
self.assertRaises(FailManagerEmpty, self.filter.failManager.toBan)
|
||||
|
||||
def testGetFailuresMultiLine(self):
|
||||
output = [("192.0.43.10", 2, 1124017199.0),
|
||||
("192.0.43.11", 1, 1124017198.0)]
|
||||
output = [("192.0.43.10", 2, 1124013599.0),
|
||||
("192.0.43.11", 1, 1124013598.0)]
|
||||
self.filter.addLogPath(GetFailures.FILENAME_MULTILINE)
|
||||
self.filter.addFailRegex("^.*rsyncd\[(?P<pid>\d+)\]: connect from .+ \(<HOST>\)$<SKIPLINES>^.+ rsyncd\[(?P=pid)\]: rsync error: .*$")
|
||||
self.filter.setMaxLines(100)
|
||||
|
@ -942,7 +953,7 @@ class GetFailures(unittest.TestCase):
|
|||
self.assertEqual(sorted(foundList), sorted(output))
|
||||
|
||||
def testGetFailuresMultiLineIgnoreRegex(self):
|
||||
output = [("192.0.43.10", 2, 1124017199.0)]
|
||||
output = [("192.0.43.10", 2, 1124013599.0)]
|
||||
self.filter.addLogPath(GetFailures.FILENAME_MULTILINE)
|
||||
self.filter.addFailRegex("^.*rsyncd\[(?P<pid>\d+)\]: connect from .+ \(<HOST>\)$<SKIPLINES>^.+ rsyncd\[(?P=pid)\]: rsync error: .*$")
|
||||
self.filter.addIgnoreRegex("rsync error: Received SIGINT")
|
||||
|
@ -956,9 +967,9 @@ class GetFailures(unittest.TestCase):
|
|||
self.assertRaises(FailManagerEmpty, self.filter.failManager.toBan)
|
||||
|
||||
def testGetFailuresMultiLineMultiRegex(self):
|
||||
output = [("192.0.43.10", 2, 1124017199.0),
|
||||
("192.0.43.11", 1, 1124017198.0),
|
||||
("192.0.43.15", 1, 1124017198.0)]
|
||||
output = [("192.0.43.10", 2, 1124013599.0),
|
||||
("192.0.43.11", 1, 1124013598.0),
|
||||
("192.0.43.15", 1, 1124013598.0)]
|
||||
self.filter.addLogPath(GetFailures.FILENAME_MULTILINE)
|
||||
self.filter.addFailRegex("^.*rsyncd\[(?P<pid>\d+)\]: connect from .+ \(<HOST>\)$<SKIPLINES>^.+ rsyncd\[(?P=pid)\]: rsync error: .*$")
|
||||
self.filter.addFailRegex("^.* sendmail\[.*, msgid=<(?P<msgid>[^>]+).*relay=\[<HOST>\].*$<SKIPLINES>^.+ spamd: result: Y \d+ .*,mid=<(?P=msgid)>(,bayes=[.\d]+)?(,autolearn=\S+)?\s*$")
|
||||
|
|
|
@ -32,8 +32,7 @@ import datetime
|
|||
from glob import glob
|
||||
from StringIO import StringIO
|
||||
|
||||
from .utils import mbasename, TraceBack, FormatterWithTraceBack
|
||||
from ..helpers import formatExceptionInfo
|
||||
from ..helpers import formatExceptionInfo, mbasename, TraceBack, FormatterWithTraceBack, getLogger
|
||||
from ..server.datetemplate import DatePatternRegex
|
||||
|
||||
|
||||
|
@ -160,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)
|
||||
|
|
|
@ -129,7 +129,7 @@ def testSampleRegexsFactory(name):
|
|||
jsonTimeLocal = datetime.datetime.strptime(t, "%Y-%m-%dT%H:%M:%S.%f")
|
||||
|
||||
|
||||
jsonTime = time.mktime(jsonTimeLocal.utctimetuple())
|
||||
jsonTime = time.mktime(jsonTimeLocal.timetuple())
|
||||
|
||||
jsonTime += jsonTimeLocal.microsecond / 1000000
|
||||
|
||||
|
|
|
@ -30,11 +30,14 @@ 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
|
||||
from .. import version
|
||||
|
||||
try:
|
||||
from ..server import filtersystemd
|
||||
|
@ -146,15 +149,18 @@ class Transmitter(TransmitterBase):
|
|||
def testPing(self):
|
||||
self.assertEqual(self.transm.proceed(["ping"]), (0, "pong"))
|
||||
|
||||
def testVersion(self):
|
||||
self.assertEqual(self.transm.proceed(["version"]), (0, version.version))
|
||||
|
||||
def testSleep(self):
|
||||
t0 = time.time()
|
||||
self.assertEqual(self.transm.proceed(["sleep", "1"]), (0, None))
|
||||
t1 = time.time()
|
||||
# Approx 1 second delay
|
||||
self.assertAlmostEqual(t1 - t0, 1, places=2)
|
||||
self.assertAlmostEqual(t1 - t0, 1, places=1)
|
||||
|
||||
def testDatabase(self):
|
||||
_, tmpFilename = tempfile.mkstemp(".db", "Fail2Ban_")
|
||||
tmp, tmpFilename = tempfile.mkstemp(".db", "fail2ban_")
|
||||
# Jails present, can't change database
|
||||
self.setGetTestNOK("dbfile", tmpFilename)
|
||||
self.server.delJail(self.jailName)
|
||||
|
@ -175,6 +181,8 @@ class Transmitter(TransmitterBase):
|
|||
self.assertEqual(self.transm.proceed(
|
||||
["get", "dbpurgeage"]),
|
||||
(0, None))
|
||||
os.close(tmp)
|
||||
os.unlink(tmpFilename)
|
||||
|
||||
def testAddJail(self):
|
||||
jail2 = "TestJail2"
|
||||
|
@ -528,11 +536,27 @@ class Transmitter(TransmitterBase):
|
|||
|
||||
def testPythonActionMethodsAndProperties(self):
|
||||
action = "TestCaseAction"
|
||||
self.assertEqual(
|
||||
self.transm.proceed(["set", self.jailName, "addaction", action,
|
||||
os.path.join(TEST_FILES_DIR, "action.d", "action.py"),
|
||||
'{"opt1": "value"}']),
|
||||
(0, action))
|
||||
try:
|
||||
out = self.transm.proceed(
|
||||
["set", self.jailName, "addaction", action,
|
||||
os.path.join(TEST_FILES_DIR, "action.d", "action.py"),
|
||||
'{"opt1": "value"}'])
|
||||
self.assertEqual(out, (0, action))
|
||||
except AssertionError:
|
||||
if ((2, 6) <= sys.version_info < (2, 6, 5)) \
|
||||
and '__init__() keywords must be strings' in out[1]:
|
||||
# known issue http://bugs.python.org/issue2646 in 2.6 series
|
||||
# since general Fail2Ban warnings are suppressed in normal
|
||||
# operation -- let's issue Python's native warning here
|
||||
import warnings
|
||||
warnings.warn(
|
||||
"Your version of Python %s seems to experience a known "
|
||||
"issue forbidding correct operation of Fail2Ban: "
|
||||
"http://bugs.python.org/issue2646 Upgrade your Python and "
|
||||
"meanwhile other intestPythonActionMethodsAndProperties will "
|
||||
"be skipped" % (sys.version))
|
||||
return
|
||||
raise
|
||||
self.assertEqual(
|
||||
sorted(self.transm.proceed(["get", self.jailName,
|
||||
"actionproperties", action])[1]),
|
||||
|
@ -704,7 +728,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")
|
||||
|
@ -778,5 +802,19 @@ class RegexTests(unittest.TestCase):
|
|||
self.assertTrue(fr.hasMatched())
|
||||
self.assertRaises(RegexException, fr.getHost)
|
||||
|
||||
class _BadThread(JailThread):
|
||||
def run(self):
|
||||
int("ignore this exception -- raised for testing")
|
||||
|
||||
class LoggingTests(LogCaptureTestCase):
|
||||
|
||||
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):
|
||||
badThread = _BadThread()
|
||||
badThread.start()
|
||||
badThread.join()
|
||||
self.assertTrue(self._is_logged("Unhandled exception"))
|
||||
|
|
|
@ -22,89 +22,17 @@ __author__ = "Yaroslav Halchenko"
|
|||
__copyright__ = "Copyright (c) 2013 Yaroslav Halchenko"
|
||||
__license__ = "GPL"
|
||||
|
||||
import logging, os, re, traceback, time, unittest
|
||||
from os.path import basename, dirname
|
||||
import logging
|
||||
import os
|
||||
import re
|
||||
import time
|
||||
import unittest
|
||||
from StringIO import StringIO
|
||||
|
||||
from ..server.mytime import MyTime
|
||||
from ..helpers import getLogger
|
||||
|
||||
logSys = logging.getLogger(__name__)
|
||||
|
||||
#
|
||||
# Following "traceback" functions are adopted from PyMVPA distributed
|
||||
# under MIT/Expat and copyright by PyMVPA developers (i.e. me and
|
||||
# Michael). Hereby I re-license derivative work on these pieces under GPL
|
||||
# to stay in line with the main Fail2Ban license
|
||||
#
|
||||
def mbasename(s):
|
||||
"""Custom function to include directory name if filename is too common
|
||||
|
||||
Also strip .py at the end
|
||||
"""
|
||||
base = basename(s)
|
||||
if base.endswith('.py'):
|
||||
base = base[:-3]
|
||||
if base in set(['base', '__init__']):
|
||||
base = basename(dirname(s)) + '.' + base
|
||||
return base
|
||||
|
||||
class TraceBack(object):
|
||||
"""Customized traceback to be included in debug messages
|
||||
"""
|
||||
|
||||
def __init__(self, compress=False):
|
||||
"""Initialize TrackBack metric
|
||||
|
||||
Parameters
|
||||
----------
|
||||
compress : bool
|
||||
if True then prefix common with previous invocation gets
|
||||
replaced with ...
|
||||
"""
|
||||
self.__prev = ""
|
||||
self.__compress = compress
|
||||
|
||||
def __call__(self):
|
||||
ftb = traceback.extract_stack(limit=100)[:-2]
|
||||
entries = [[mbasename(x[0]), dirname(x[0]), str(x[1])] for x in ftb]
|
||||
entries = [ [e[0], e[2]] for e in entries
|
||||
if not (e[0] in ['unittest', 'logging.__init__']
|
||||
or e[1].endswith('/unittest'))]
|
||||
|
||||
# lets make it more concise
|
||||
entries_out = [entries[0]]
|
||||
for entry in entries[1:]:
|
||||
if entry[0] == entries_out[-1][0]:
|
||||
entries_out[-1][1] += ',%s' % entry[1]
|
||||
else:
|
||||
entries_out.append(entry)
|
||||
sftb = '>'.join(['%s:%s' % (mbasename(x[0]),
|
||||
x[1]) for x in entries_out])
|
||||
if self.__compress:
|
||||
# lets remove part which is common with previous invocation
|
||||
prev_next = sftb
|
||||
common_prefix = os.path.commonprefix((self.__prev, sftb))
|
||||
common_prefix2 = re.sub('>[^>]*$', '', common_prefix)
|
||||
|
||||
if common_prefix2 != "":
|
||||
sftb = '...' + sftb[len(common_prefix2):]
|
||||
self.__prev = prev_next
|
||||
|
||||
return sftb
|
||||
|
||||
class FormatterWithTraceBack(logging.Formatter):
|
||||
"""Custom formatter which expands %(tb) and %(tbc) with tracebacks
|
||||
|
||||
TODO: might need locking in case of compressed tracebacks
|
||||
"""
|
||||
def __init__(self, fmt, *args, **kwargs):
|
||||
logging.Formatter.__init__(self, fmt=fmt, *args, **kwargs)
|
||||
compress = '%(tbc)s' in fmt
|
||||
self._tb = TraceBack(compress=compress)
|
||||
|
||||
def format(self, record):
|
||||
record.tbc = record.tb = self._tb()
|
||||
return logging.Formatter.format(self, record)
|
||||
logSys = getLogger(__name__)
|
||||
|
||||
def mtimesleep():
|
||||
# no sleep now should be necessary since polling tracks now not only
|
||||
|
@ -146,7 +74,6 @@ def gatherTests(regexps=None, no_network=False):
|
|||
if not regexps: # pragma: no cover
|
||||
tests = unittest.TestSuite()
|
||||
else: # pragma: no cover
|
||||
import re
|
||||
class FilteredTestSuite(unittest.TestSuite):
|
||||
_regexps = [re.compile(r) for r in regexps]
|
||||
def addTest(self, suite):
|
||||
|
@ -163,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
|
||||
|
@ -259,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
|
||||
|
@ -272,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
|
||||
|
||||
|
|
|
@ -24,4 +24,4 @@ __author__ = "Cyril Jaquier, Yaroslav Halchenko, Steven Hiscocks, Daniel Black"
|
|||
__copyright__ = "Copyright (c) 2004 Cyril Jaquier, 2011-2014 Yaroslav Halchenko, 2013-2013 Steven Hiscocks, Daniel Black"
|
||||
__license__ = "GPL-v2+"
|
||||
|
||||
version = "0.9.0"
|
||||
version = "0.9.0.dev"
|
||||
|
|
|
@ -154,7 +154,7 @@ _fail2ban () {
|
|||
fi
|
||||
return 0
|
||||
;;
|
||||
delfailregex|delignoregex)
|
||||
delfailregex|delignoreregex)
|
||||
COMPREPLY=( $( compgen -W \
|
||||
"$( "$1" get "$jail" "${prev/del/}" 2>/dev/null | awk -F"[][]" '{print $2}')" \
|
||||
-- "$cur" ) )
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue