diff --git a/.gitignore b/.gitignore index 76a33e60..a8942050 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,4 @@ htmlcov *.rej *.bak __pycache__ +.vagrant/ diff --git a/.travis.yml b/.travis.yml index 41eeca27..9a92a7f6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -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 diff --git a/3rdparty/logwatch/fail2ban b/3rdparty/logwatch/fail2ban new file mode 100755 index 00000000..087eb529 --- /dev/null +++ b/3rdparty/logwatch/fail2ban @@ -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 -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 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 = )) { + 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: diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..a668fa3d --- /dev/null +++ b/CONTRIBUTING.md @@ -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) diff --git a/ChangeLog b/ChangeLog index 22db55d9..d92aec4a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -10,21 +10,73 @@ 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 + * postfix* - match with a new daemon string (postfix/submission/smtpd). + Closes gh-804 . Thanks Paul Traina + * apache - added filter for AH01630 client denied by server configuration. - New features: - + - New filters: + - monit Thanks Jason H Martin + - directadmin Thanks niorg + - apache-shellshock Thanks Eugene Hopkinson (SlowRiot) + - 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 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 diff --git a/DEVELOP b/DEVELOP index 592dfcb4..f1426561 100644 --- a/DEVELOP +++ b/DEVELOP @@ -1,4 +1,4 @@ - __ _ _ ___ _ +.. __ _ _ ___ _ / _|__ _(_) |_ ) |__ __ _ _ _ | _/ _` | | |/ /| '_ \/ _` | ' \ |_| \__,_|_|_/___|_.__/\__,_|_||_| @@ -25,6 +25,7 @@ Pull Requests ============= When submitting pull requests on GitHub we ask you to: + * Clearly describe the problem you're solving; * Don't introduce regressions that will make it hard for systems administrators to update; @@ -52,32 +53,32 @@ for more details. Install the package python-coverage to visualise your test coverage. Run the following (note: on Debian-based systems, the script is called -`python-coverage`): +`python-coverage`):: -coverage run bin/fail2ban-testcases -coverage html + coverage run bin/fail2ban-testcases + coverage html Then look at htmlcov/index.html and see how much coverage your test cases exert over the code base. Full coverage is a good thing however it may not be complete. Try to ensure tests cover as many independent paths through the code. -Manual Execution. To run in a development environment do: +Manual Execution. To run in a development environment do:: -./fail2ban-client -c config/ -s /tmp/f2b.sock -i start + ./fail2ban-client -c config/ -s /tmp/f2b.sock -i start -some quick commands: +some quick commands:: -status -add test pyinotify -status test -set test addaction iptables -set test actionban iptables echo >> /tmp/ban -set test actionunban iptables echo >> /tmp/unban -get test actionban iptables -get test actionunban iptables -set test banip 192.168.2.2 -status test + status + add test pyinotify + status test + set test addaction iptables + set test actionban iptables echo >> /tmp/ban + set test actionunban iptables echo >> /tmp/unban + get test actionban iptables + get test actionunban iptables + set test banip 192.168.2.2 + status test @@ -130,10 +131,10 @@ Git Use the following tags in your commit messages: -'BF:' for bug fixes -'DOC:' for documentation fixes -'ENH:' for enhancements -'TST:' for commits concerning tests only (thus not touching the main code-base) +* 'BF:' for bug fixes +* 'DOC:' for documentation fixes +* 'ENH:' for enhancements +* 'TST:' for commits concerning tests only (thus not touching the main code-base) Multiple tags could be joined with +, e.g. "BF+TST:". diff --git a/FILTERS b/FILTERS index fd441e58..10113dfc 100644 --- a/FILTERS +++ b/FILTERS @@ -1,4 +1,4 @@ - __ _ _ ___ _ +.. __ _ _ ___ _ / _|__ _(_) |_ ) |__ __ _ _ _ | _/ _` | | |/ /| '_ \/ _` | ' \ |_| \__,_|_|_/___|_.__/\__,_|_||_| @@ -7,10 +7,8 @@ Developing Filters ================================================================================ -Filters -======= - Filters are tricky. They need to: + * work with a variety of the versions of the software that generates the logs; * work with the range of logging configuration options available in the software; @@ -31,10 +29,11 @@ what you have done, what is the hurdle, and we'll attempt to help (PR will be automagically updated with future commits you would push to complete it). -Filter test cases ------------------ +Filter Test Cases +================= -Purpose: +Purpose +------- Start by finding the log messages that the application generates related to some form of authentication failure. If you are adding to an existing filter @@ -49,7 +48,8 @@ and exim-spam at log messages related to spam. Even if it is a new filter you may consider separating the log messages into different filters based on purpose. -Cause: +Cause +----- Are some of the log lines a result of the same action? For example, is a PAM failure log message, followed by an application specific failure message the @@ -65,7 +65,8 @@ the log message be occurring due to the first step towards the application asking for authentication? Could the log messages occur often? If some of these are true make a note of this in the jail.conf example that you provide. -Samples: +Samples +------- It is important to include log file samples so any future change in the regular expression will still work with the log lines you have identified. @@ -93,21 +94,22 @@ If the mechanism to create the log message isn't obvious provide a configuration and/or sample scripts testcases/files/config/{filtername} and reference these in the comments above the log line. -FailJSON metadata: +FailJSON metadata +----------------- A failJSON metadata is a comment immediately above the log message. It will -look like: +look like:: -# failJSON: { "time": "2013-06-10T10:10:59", "match": true , "host": "93.184.216.119" } + # failJSON: { "time": "2013-06-10T10:10:59", "match": true , "host": "93.184.216.119" } Time should match the time of the log message. It is in a specific format of Year-Month-Day'T'Hour:minute:Second. If your log message does not include a year, like the example below, the year should be listed as 2005, if before Sun Aug 14 10am UTC, and 2004 if afterwards. Here is an example failJSON -line preceding a sample log line: +line preceding a sample log line:: -# failJSON: { "time": "2005-03-24T15:25:51", "match": true , "host": "198.51.100.87" } -Mar 24 15:25:51 buffalo1 dropbear[4092]: bad password attempt for 'root' from 198.51.100.87:5543 + # failJSON: { "time": "2005-03-24T15:25:51", "match": true , "host": "198.51.100.87" } + Mar 24 15:25:51 buffalo1 dropbear[4092]: bad password attempt for 'root' from 198.51.100.87:5543 The "host" in failJSON should contain the IP or domain that should be blocked. @@ -116,27 +118,28 @@ attacks) and any log lines to be excluded (see "Cause" section above), set "match": false in the failJSON and describe the reason in the comment above. After developing regexes, the following command will test all failJSON metadata -against the log lines in all sample log files +against the log lines in all sample log files:: -./fail2ban-testcases testSampleRegex + ./fail2ban-testcases testSampleRegex Developing Filter Regular Expressions -------------------------------------- +===================================== -Date/Time: +Date/Time +--------- At the moment, Fail2Ban depends on log lines to have time stamps. That is why before starting to develop failregex, check if your log line format known to Fail2Ban. Copy the time component from the log line and append an IP address to -test with following command: +test with following command:: -./fail2ban-regex "2013-09-19 02:46:12 1.2.3.4" "" + ./fail2ban-regex "2013-09-19 02:46:12 1.2.3.4" "" -Output of such command should contain something like: +Output of such command should contain something like:: -Date template hits: -|- [# of hits] date format -| [1] Year-Month-Day Hour:Minute:Second + Date template hits: + |- [# of hits] date format + | [1] Year-Month-Day Hour:Minute:Second Ensure that the template description matches time/date elements in your log line time stamp. If there is no matched format then date template needs to be added @@ -144,29 +147,31 @@ to server/datedetector.py. Ensure that a new template is added in the order that more specific matches occur first and that there is no confusion between a Day and a Month. -Filter file: +Filter file +----------- The filter is specified in a config/filter.d/{filtername}.conf file. Filter file -can have sections INCLUDES (optional) and Definition as follows: +can have sections INCLUDES (optional) and Definition as follows:: -[INCLUDES] - -before = common.conf - -after = filtername.local - -[Definition] - -failregex = .... - -ignoreregex = .... + [INCLUDES] + + before = common.conf + + after = filtername.local + + [Definition] + + failregex = .... + + ignoreregex = .... This is also documented in the man page jail.conf (section 5). Other definitions can be added to make failregex's more readable and maintainable to be used through string Interpolations (see http://docs.python.org/2.7/library/configparser.html) -General rules: +General rules +------------- Use "before" if you need to include a common set of rules, like syslog or if there is a common set of regexes for multiple filters. @@ -178,33 +183,35 @@ Try to avoid using ignoreregex mainly for performance reasons. The case when you would use it is if in trying to avoid using it, you end up with an unreadable failregex. -Syslog: +Syslog +------ If your application logs to syslog you can take advantage of log line prefix -definitions present in common.conf. So as a base use: +definitions present in common.conf. So as a base use:: -[INCLUDES] - -before = common.conf - -[Definition] - -_daemon = app - -failregex = ^%(__prefix_line)s + [INCLUDES] + + before = common.conf + + [Definition] + + _daemon = app + + failregex = ^%(__prefix_line)s In this example common.conf defines __prefix_line which also contains the _daemon name (in syslog terms the service) you have just specified. _daemon can also be a regex. -For example, to capture following line _daemon should be set to "dovecot" +For example, to capture following line _daemon should be set to "dovecot":: -Dec 12 11:19:11 dunnart dovecot: pop3-login: Aborted login (tried to use disabled plaintext auth): rip=190.210.136.21, lip=113.212.99.193 + Dec 12 11:19:11 dunnart dovecot: pop3-login: Aborted login (tried to use disabled plaintext auth): rip=190.210.136.21, lip=113.212.99.193 -and then ^%(__prefix_line)s would match "Dec 12 11:19:11 dunnart dovecot: +and then ``^%(__prefix_line)s`` would match "Dec 12 11:19:11 dunnart dovecot: ". Note it matches the trailing space(s) as well. -Substitutions (AKA string interpolations): +Substitutions (AKA string interpolations) +----------------------------------------- We have used string interpolations in above examples. They are useful for making the regexes more readable, reuse generic patterns in multiple failregex @@ -213,7 +220,8 @@ to the user. General principle is that value of a _name variable replaces occurrences of %(_name)s within the same section or anywhere in the config file if defined in [DEFAULT] section. -Regular Expressions: +Regular Expressions +------------------- Regular expressions (failregex, ignoreregex) assume that the date/time has been removed from the log line (this is just how fail2ban works internally ATM). @@ -236,29 +244,33 @@ If you have only a basic knowledge of regular repressions we advise to read http://docs.python.org/2/library/re.html first. It doesn't take long and would remind you e.g. which characters you need to escape and which you don't. -Developing/testing a regex: +Developing/testing a regex +-------------------------- You can develop a regex in a file or using command line depending on your preference. You can also use samples you have already created in the test cases or test them one at a time. The general tool for testing Fail2Ban regexes is fail2ban-regex. To see how to -use it run: +use it run:: -./fail2ban-regex --help + ./fail2ban-regex --help Take note of -l heavydebug / -l debug and -v as they might be very useful. -TIP: Take a look at the source code of the application you are developing +.. TIP:: + Take a look at the source code of the application you are developing failregex for. You may see optional or extra log messages, or parts there of, that need to form part of your regex. It may also reveal how some parts are constrained and different formats depending on configuration or less common usages. -TIP: For looking through source code - http://sourcecodebrowser.com/ . It has +.. TIP:: + For looking through source code - http://sourcecodebrowser.com/ . It has call graphs and can browse different versions. -TIP: Some applications log spaces at the end. If you are not sure add \s*$ as +.. TIP:: + Some applications log spaces at the end. If you are not sure add \s*$ as the end part of the regex. If your regex is not matching, http://www.debuggex.com/?flavor=python can help @@ -277,13 +289,15 @@ When you have fixed the regex put it back into your filter file. Please spread the good word about Debuggex - Serge Toarca is kindly continuing its free availability to Open Source developers. -Finishing up: +Finishing up +------------ If you've added a new filter, add a new entry in config/jail.conf. The theory here is that a user will create a jail.local with [filtername]\nenable=true to enable your jail. So more specifically in the [filter] section in jail.conf: + * ensure that you have "enabled = false" (users will enable as needed); * use "filter =" set to your filter name; * use a typical action to disable ports associated with the application; @@ -295,7 +309,7 @@ Submit github pull request (See "Pull Requests" above) for github.com/fail2ban/fail2ban containing your great work. Filter Security ---------------- +=============== Poor filter regular expressions are susceptible to DoS attacks. @@ -321,33 +335,33 @@ Examples of poor filters 1. Too restrictive -We find a log message: +We find a log message:: Apr-07-13 07:08:36 Invalid command fial2ban from 1.2.3.4 -We make a failregex +We make a failregex:: ^Invalid command \S+ from Now think evil. The user does the command 'blah from 1.2.3.44' -The program diligently logs: +The program diligently logs:: Apr-07-13 07:08:36 Invalid command blah from 1.2.3.44 from 1.2.3.4 And fail2ban matches 1.2.3.44 as the IP that it ban. A DoS attack was successful. -The fix here is that the command can be anything so .* is appropriate. +The fix here is that the command can be anything so .* is appropriate:: ^Invalid command .* from Here the .* will match until the end of the string. Then realise it has more to match, i.e. "from " and go back until it find this. Then it will ban -1.2.3.4 correctly. Since the is always at the end, end the regex with a $. +1.2.3.4 correctly. Since the is always at the end, end the regex with a $:: ^Invalid command .* from $ -Note if we'd just had the expression: +Note if we'd just had the expression:: ^Invalid command \S+ from $ @@ -359,16 +373,16 @@ banned. From the Apache vulnerability CVE-2013-2178 ( original ref: https://vndh.net/note:fail2ban-089-denial-service ). -An example bad regex for Apache: +An example bad regex for Apache:: failregex = [[]client []] user .* not found -Since the user can do a get request on: +Since the user can do a get request on:: GET /[client%20192.168.0.1]%20user%20root%20not%20found HTTP/1.0 -Host: remote.site + Host: remote.site -Now the log line will be: +Now the log line will be:: [Sat Jun 01 02:17:42 2013] [error] [client 192.168.33.1] File does not exist: /srv/http/site/[client 192.168.0.1] user root not found @@ -379,27 +393,27 @@ regex and blocks 192.168.33.1 as a denial of service from the HTTP requester. From: https://github.com/fail2ban/fail2ban/pull/426 -An example ssh log (simplified) +An example ssh log (simplified):: Sep 29 17:15:02 spaceman sshd[12946]: Failed password for user from 127.0.0.1 port 20000 ssh1: ruser remoteuser As we assume username can include anything including spaces its prudent to put -.* here. The remote user can also exist as anything so lets not make assumptions again. +.* here. The remote user can also exist as anything so lets not make assumptions again:: failregex = ^%(__prefix_line)sFailed \S+ for .* from ( port \d*)?( ssh\d+)?(: ruser .*)?$ So this works. The problem is if the .* after remote user is injected by the -user to be 'from 1.2.3.4'. The resultant log line is. +user to be 'from 1.2.3.4'. The resultant log line is:: Sep 29 17:15:02 spaceman sshd[12946]: Failed password for user from 127.0.0.1 port 20000 ssh1: ruser from 1.2.3.4 -Testing with: +Testing with:: fail2ban-regex -v 'Sep 29 17:15:02 Failed password for user from 127.0.0.1 port 20000 ssh1: ruser from 1.2.3.4' '^ Failed \S+ for .* from ( port \d*)?( ssh\d+)?(: ruser .*)?$' -TIP: I've removed the bit that matches __prefix_line from the regex and log. +.. TIP:: I've removed the bit that matches __prefix_line from the regex and log. -Shows: +Shows:: 1) [1] ^ Failed \S+ for .* from ( port \d*)?( ssh\d+)?(: ruser .*)?$ 1.2.3.4 Sun Sep 29 17:15:02 2013 @@ -412,14 +426,14 @@ The result was that 1.2.3.4 was matched, injected by the user, and the wrong IP was banned. The solution here is to make the first .* non-greedy with .*?. Here it matches -as little as required and the fail2ban-regex tool shows the output: +as little as required and the fail2ban-regex tool shows the output:: fail2ban-regex -v 'Sep 29 17:15:02 Failed password for user from 127.0.0.1 port 20000 ssh1: ruser from 1.2.3.4' '^ Failed \S+ for .*? from ( port \d*)?( ssh\d+)?(: ruser .*)?$' 1) [1] ^ Failed \S+ for .*? from ( port \d*)?( ssh\d+)?(: ruser .*)?$ 127.0.0.1 Sun Sep 29 17:15:02 2013 -So the general case here is a log line that contains: +So the general case here is a log line that contains:: (fixed_data_1)(fixed_data_2)(user_injectable_data) @@ -427,20 +441,21 @@ Where the regex that matches fixed_data_1 is gready and matches the entire string, before moving backwards and user_injectable_data can match the entire string. -Another case: +Another case +------------ ref: https://www.debuggex.com/r/CtAbeKMa2sDBEfA2/0 -A webserver logs the following without URL escaping: +A webserver logs the following without URL escaping:: [error] 2865#0: *66647 user "xyz" was not found in "/file", client: 1.2.3.1, server: www.host.com, request: "GET ", client: 3.2.1.1, server: fake.com, request: "GET exploited HTTP/3.3", host: "injected.host", host: "www.myhost.com" -regex: +regex:: failregex = ^ \[error\] \d+#\d+: \*\d+ user "\S+":? (?:password mismatch|was not found in ".*"), client: , server: \S+, request: "\S+ .+ HTTP/\d+\.\d+", host: "\S+" The .* matches to the end of the string. Finds that it can't continue to match -", client ... so it moves from the back and find that the user injected web URL: +", client ... so it moves from the back and find that the user injected web URL:: ", client: 3.2.1.1, server: fake.com, request: "GET exploited HTTP/3.3", host: "injected.host @@ -453,14 +468,14 @@ beyond . 4. Application generates two identical log messages with different meanings If the application generates the following two messages under different -circumstances: +circumstances:: client : authentication failed client : authentication failed -Then it's obvious that a regex of "^client : authentication -failed$" will still cause problems if the user can trigger the second +Then it's obvious that a regex of ``^client : authentication +failed$`` will still cause problems if the user can trigger the second log message with a of 123.1.1.1. Here there's nothing to do except request/change the application so it logs diff --git a/MANIFEST b/MANIFEST index 7df49199..92edcca8 100644 --- a/MANIFEST +++ b/MANIFEST @@ -258,7 +258,7 @@ config/action.d/dummy.conf config/action.d/firewallcmd-new.conf config/action.d/firewallcmd-ipset.conf config/action.d/iptables-ipset-proto6-allports.conf -config/action.d/iptables-blocktype.conf +config/action.d/iptables-common.conf config/action.d/iptables-ipset-proto4.conf config/action.d/iptables-ipset-proto6.conf config/action.d/iptables-xt_recent-echo.conf diff --git a/README.Solaris b/README.Solaris index e41e3811..c654b7c0 100644 --- a/README.Solaris +++ b/README.Solaris @@ -6,20 +6,20 @@ By Roy Sigurd Karlsbakk 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: diff --git a/README.md b/README.md index 308136a1..2679fe53 100644 --- a/README.md +++ b/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 ) -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 )) +or *better* to the [mailing list](https://lists.sourceforge.net/lists/listinfo/fail2ban-users) since Fail2Ban is "community-driven" for years now. Thanks: diff --git a/RELEASE b/RELEASE index e787b040..9002b75e 100644 --- a/RELEASE +++ b/RELEASE @@ -1,4 +1,4 @@ - __ _ _ ___ _ +.. __ _ _ ___ _ / _|__ _(_) |_ ) |__ __ _ _ _ | _/ _` | | |/ /| '_ \/ _` | ' \ |_| \__,_|_|_/___|_.__/\__,_|_||_| @@ -7,7 +7,10 @@ How to do a release for Fail2Ban ================================================================================ -# Check distribution patches and see if they can be included +Preparation +=========== + +* Check distribution patches and see if they can be included * https://apps.fedoraproject.org/packages/fail2ban/sources * http://sources.gentoo.org/cgi-bin/viewvc.cgi/gentoo-x86/net-analyzer/fail2ban/ @@ -16,7 +19,8 @@ How to do a release for Fail2Ban * http://sophie.zarb.org/sources/fail2ban (Mageia) * https://trac.macports.org/browser/trunk/dports/security/fail2ban -# Check distribution outstanding bugs + +* Check distribution outstanding bugs * https://github.com/fail2ban/fail2ban/issues?sort=updated&state=open * http://bugs.debian.org/cgi-bin/pkgreport.cgi?dist=unstable;package=fail2ban @@ -29,144 +33,165 @@ How to do a release for Fail2Ban * https://bugs.mageia.org/buglist.cgi?quicksearch=fail2ban * https://build.opensuse.org/package/requests/openSUSE:Factory/fail2ban -# Make sure the tests pass + +* Make sure the tests pass:: ./fail2ban-testcases-all -# Ensure the version is correct +* Ensure the version is correct in: - in: * ./fail2ban/version.py * top of ChangeLog * README.md -# Ensure the MANIFEST is complete -Run: +* Ensure the MANIFEST is complete + +* Run:: python setup.py sdist -Look for errors like: - 'testcases/files/logs/mysqld.log' not a regular file -- skipping +* Look for errors like:: -Which indicates that testcases/files/logs/mysqld.log has been moved or is a directory + 'testcases/files/logs/mysqld.log' not a regular file -- skipping - tar -C /tmp -jxf dist/fail2ban-0.9.0.tar.bz2 + * Which indicates that testcases/files/logs/mysqld.log has been moved or is a directory:: -# clean up current direcory + tar -C /tmp -jxf dist/fail2ban-0.9.0.tar.bz2 - diff -rul --exclude \*.pyc . /tmp/fail2ban-0.9.0/ +* clean up current direcory:: - # Only differences should be files that you don't want distributed. + diff -rul --exclude \*.pyc . /tmp/fail2ban-0.9.0/ -# Ensure the tests work from the tarball - - cd /tmp/fail2ban-0.9.0/ && export PYTHONPATH=`pwd` && bin/fail2ban-testcases - -# Add/finalize the corresponding entry in the ChangeLog - - To generate a list of committers use e.g. - - git shortlog -sn 0.8.12.. | sed -e 's,^[ 0-9\t]*,,g' | tr '\n' '\|' | sed -e 's:|:, :g' - - Ensure the top of the ChangeLog has the right version and current date. - - Ensure the top entry of the ChangeLog has the right version and current date. - -# Update man pages - - (cd man ; ./generate-man ) - git commit -m 'DOC/ENH: update man pages for release' man/* - -# Cleanout TODO file with the finished stuff - -# Prepare source and rpm binary distributions - - python setup.py sdist + * Only differences should be files that you don't want distributed. -Broken for now: python setup.py bdist_rpm -Broken for now: python setup.py upload +* Ensure the tests work from the tarball:: -# Tag the release by using a signed (and annotated) tag. Cut/paste - release ChangeLog entry as tag annotation + cd /tmp/fail2ban-0.9.0/ && export PYTHONPATH=`pwd` && bin/fail2ban-testcases - git tag -s 0.9.1 +* Add/finalize the corresponding entry in the ChangeLog -# Prerelease (option) + * To generate a list of committers use e.g.:: -# Provide a release sample to distributors + git shortlog -sn 0.8.12.. | sed -e 's,^[ 0-9\t]*,,g' | tr '\n' '\|' | sed -e 's:|:, :g' + + * Ensure the top of the ChangeLog has the right version and current date. + * Ensure the top entry of the ChangeLog has the right version and current date. + +* Update man pages:: + + (cd man ; ./generate-man ) + git commit -m 'DOC/ENH: update man pages for release' man/* + +* Cleanout TODO file with the finished stuff + +* Prepare source and rpm binary distributions:: + + python setup.py sdist + + * Broken for now: python setup.py bdist_rpm + * Broken for now: python setup.py upload + + +* Tag the release by using a signed (and annotated) tag. Cut/paste + release ChangeLog entry as tag annotation:: + + git tag -s 0.9.1 + +Pre Release +=========== + +* Provide a release sample to distributors * Arch Linux: - https://www.archlinux.org/packages/community/any/fail2ban/ + + * https://www.archlinux.org/packages/community/any/fail2ban/ + * Debian: Yaroslav Halchenko - http://packages.qa.debian.org/f/fail2ban.html + + * http://packages.qa.debian.org/f/fail2ban.html + * FreeBSD: Christoph Theis theis@gmx.at>, Nick Hilliard - http://svnweb.freebsd.org/ports/head/security/py-fail2ban/Makefile?view=markup - http://www.freebsd.org/cgi/query-pr-summary.cgi?text=fail2ban + + * http://svnweb.freebsd.org/ports/head/security/py-fail2ban/Makefile?view=markup + * http://www.freebsd.org/cgi/query-pr-summary.cgi?text=fail2ban + * Fedora: Axel Thimm - https://apps.fedoraproject.org/packages/fail2ban - http://pkgs.fedoraproject.org/cgit/fail2ban.git - https://admin.fedoraproject.org/pkgdb/acls/bugs/fail2ban + + * https://apps.fedoraproject.org/packages/fail2ban + * http://pkgs.fedoraproject.org/cgit/fail2ban.git + * https://admin.fedoraproject.org/pkgdb/acls/bugs/fail2ban + * Gentoo: netmon@gentoo.org - http://sources.gentoo.org/cgi-bin/viewvc.cgi/gentoo-x86/net-analyzer/fail2ban/metadata.xml?view=markup - https://bugs.gentoo.org/buglist.cgi?quicksearch=fail2ban + + * http://sources.gentoo.org/cgi-bin/viewvc.cgi/gentoo-x86/net-analyzer/fail2ban/metadata.xml?view=markup + * https://bugs.gentoo.org/buglist.cgi?quicksearch=fail2ban + * openSUSE: Stephan Kulow - https://build.opensuse.org/package/show/openSUSE:Factory/fail2ban + + * https://build.opensuse.org/package/show/openSUSE:Factory/fail2ban + * Mac Ports: @Malbrouck on github (gh-49) - https://trac.macports.org/browser/trunk/dports/security/fail2ban/Portfile + + * https://trac.macports.org/browser/trunk/dports/security/fail2ban/Portfile + * Mageia: - https://bugs.mageia.org/buglist.cgi?quicksearch=fail2ban - An potentially to the fail2ban-users email list. + * https://bugs.mageia.org/buglist.cgi?quicksearch=fail2ban -# Wait for feedback from distributors + * An potentially to the fail2ban-users email list. -# Prepare a release notice https://github.com/fail2ban/fail2ban/releases/new - Upload the source/binaries from the dist directory and tag the release using the URL +* Wait for feedback from distributors -# Upload source/binaries to sourceforge http://sourceforge.net/projects/fail2ban/ +* Prepare a release notice https://github.com/fail2ban/fail2ban/releases/new -# Run the following and update the wiki with output: - python -c 'import fail2ban.protocol; fail2ban.protocol.printWiki()' +* Upload the source/binaries from the dist directory and tag the release using the URL + +* Upload source/binaries to sourceforge http://sourceforge.net/projects/fail2ban/ + +* Run the following and update the wiki with output:: + + python -c 'import fail2ban.protocol; fail2ban.protocol.printWiki()' + + * page: http://www.fail2ban.org/wiki/index.php/Commands - page: http://www.fail2ban.org/wiki/index.php/Commands * Update: - http://www.fail2ban.org/wiki/index.php?title=Template:Fail2ban_Versions&action=edit - http://www.fail2ban.org/wiki/index.php?title=Template:Fail2ban_News&action=edit - move old bits to: - http://www.fail2ban.org/wiki/index.php?title=Template:Fail2ban_OldNews&action=edit + * http://www.fail2ban.org/wiki/index.php?title=Template:Fail2ban_Versions&action=edit - http://www.fail2ban.org/wiki/index.php/ChangeLog - http://www.fail2ban.org/wiki/index.php/Requirements (Check requirement) - http://www.fail2ban.org/wiki/index.php/Features + * http://www.fail2ban.org/wiki/index.php?title=Template:Fail2ban_News&action=edit + * move old bits to http://www.fail2ban.org/wiki/index.php?title=Template:Fail2ban_OldNews&action=edit + + * http://www.fail2ban.org/wiki/index.php/ChangeLog + * http://www.fail2ban.org/wiki/index.php/Requirements (Check requirement) + * http://www.fail2ban.org/wiki/index.php/Features * See if any filters are upgraded: http://www.fail2ban.org/wiki/index.php/Special:AllPages -# Email users and development list of release +* Email users and development list of release -# notify distributors +* notify distributors Post Release ============ -Add the following to the top of the ChangeLog +Add the following to the top of the ChangeLog:: -ver. 0.9.1 (2014/XX/XXX) - wanna-be-released ------------ - -- Fixes: - -- New Features: - -- Enhancements: + ver. 0.9.1 (2014/XX/XXX) - wanna-be-released + ----------- + + - Fixes: + + - New Features: + + - Enhancements: Alter the git shortlog command in the previous section to refer to the just released version. -and adjust common/version.py to carry .dev suffix to signal +and adjust fail2ban/version.py to carry .dev suffix to signal a version under development. diff --git a/THANKS b/THANKS index 64eb4402..0433f7ed 100644 --- a/THANKS +++ b/THANKS @@ -34,6 +34,7 @@ David Nutter Derek Atkins Eric Gerbier Enrico Labedzki +Eugene Hopkinson (SlowRiot) ftoppi François Boulogne Frédéric @@ -44,10 +45,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 +65,7 @@ kjohnsonecl kojiro Lars Kneschke Lee Clemens +leftyfb (Mike Rushton) Manuel Arostegui Ramirez Marcel Dopita Mark Edgington @@ -75,8 +81,11 @@ Michael Hanselmann Mika (mkl) Nick Munger onorua +Paul Marrapese +Paul Traina Noel Butler Patrick Börjesson +Pressy Raphaël Marichez RealRancor René Berber @@ -84,7 +93,10 @@ Robert Edeker Rolf Fokkens Roman Gelfand Russell Odom +SATO Kentaro +Sean DuBois Sebastian Arcus +Serg G. Brester Sireyessire silviogarbes Stefan Tatschner @@ -100,8 +112,9 @@ Vaclav Misek Vincent Deffontaines Yaroslav Halchenko Winston Smith -ykimon Yehuda Katz +ykimon +Yung-Chin Oei Zbigniew Jędrzejewski-Szmek zugeschmiert Zurd diff --git a/Vagrantfile b/Vagrantfile new file mode 100644 index 00000000..120ffd7f --- /dev/null +++ b/Vagrantfile @@ -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 diff --git a/bin/fail2ban-client b/bin/fail2ban-client index 8737c49d..89e0a903 100755 --- a/bin/fail2ban-client +++ b/bin/fail2ban-client @@ -30,9 +30,10 @@ from fail2ban.protocol import printFormatted from fail2ban.client.csocket import CSocket from fail2ban.client.configurator import Configurator from fail2ban.client.beautifier import Beautifier +from fail2ban.helpers import getLogger # Gets the instance of the logger. -logSys = logging.getLogger("fail2ban.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: diff --git a/bin/fail2ban-regex b/bin/fail2ban-regex index ef198dcb..5644dd37 100755 --- a/bin/fail2ban-regex +++ b/bin/fail2ban-regex @@ -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('', '(?&.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') diff --git a/bin/fail2ban-server b/bin/fail2ban-server index aba19ab5..ec0c0dbe 100755 --- a/bin/fail2ban-server +++ b/bin/fail2ban-server @@ -22,13 +22,14 @@ __author__ = "Cyril Jaquier" __copyright__ = "Copyright (c) 2004 Cyril Jaquier" __license__ = "GPL" -import getopt, sys, logging, os +import getopt, sys, os from fail2ban.version import version from fail2ban.server.server import Server +from fail2ban.helpers import getLogger # Gets the instance of the logger. -logSys = logging.getLogger("fail2ban") +logSys = getLogger("fail2ban") ## # \mainpage Fail2Ban diff --git a/bin/fail2ban-testcases b/bin/fail2ban-testcases index b3bddf1c..475aa40b 100755 --- a/bin/fail2ban-testcases +++ b/bin/fail2ban-testcases @@ -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, diff --git a/config/action.d/badips.py b/config/action.d/badips.py index 6b21e963..250b1dc3 100644 --- a/config/action.d/badips.py +++ b/config/action.d/badips.py @@ -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')) diff --git a/config/action.d/cloudflare.conf b/config/action.d/cloudflare.conf new file mode 100644 index 00000000..4d5e2dc8 --- /dev/null +++ b/config/action.d/cloudflare.conf @@ -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 address +# number of failures +#