Compare commits

...
Author SHA1 Message Date
Yaroslav Halchenko acc4c2d104 Hope for release tomorrow 2015-04-28 23:52:48 -04:00
Yaroslav Halchenko 840fea9f71 Merge commit '0f75ed5e2ab1159e45a7771a7a4e90c877ec848e'
* commit '0f75ed5e2ab1159e45a7771a7a4e90c877ec848e':
  Just use a system wide python in the tests digest.py
  DOC: Slight tune up to RELEASE doc -- no need for PYTHONPATH to run tests
  MANIFEST: updated for some new files, sorted all entries, removed some duplicates
  Initial changes for the release -- simplified ChangeLog header etc
2015-04-28 23:51:32 -04:00
Yaroslav Halchenko c0e1333fe6 BF: if no /dev/log on Linux -- don't expect setting syslog to work 2015-04-28 23:51:00 -04:00
Yaroslav Halchenko ced4852383 Merge pull request #1037 from ambrice/ufw
Fix actions in ufw.conf
2015-04-28 20:11:58 -04:00
Aaron Brice 7ae0ef2408 Fix actions in ufw.conf
On Ubuntu 15.04 the ufw action was not working.
- With empty <application>, receiving errors:

2015-04-24 16:28:35,204 fail2ban.filter         [8527]: INFO    [sshd] Found 43.255.190.157
2015-04-24 16:28:35,695 fail2ban.actions        [8527]: NOTICE  [sshd] Ban 43.255.190.157
2015-04-24 16:28:35,802 fail2ban.action         [8527]: ERROR   [ -n "" ] && app="app " -- stdout: b''
2015-04-24 16:28:35,803 fail2ban.action         [8527]: ERROR   [ -n "" ] && app="app " -- stderr: b''
2015-04-24 16:28:35,803 fail2ban.action         [8527]: ERROR   [ -n "" ] && app="app " -- returned 1

- With action = ufw[application=OpenSSH], it was silently not doing
  anything (no errors after "Ban x.x.x.x", but no IP addresses in ufw
  status).

Re-arranged the bash commands on two lines, and it works with or without
<application>.
2015-04-28 11:39:00 -07:00
Yaroslav Halchenko 4aafb2d4ac Merge pull request #1035 from leeclemens/add-drupal-filter
Add drupal-auth filter and jail
2015-04-27 14:39:21 -04:00
Lee Clemens 8f792f52fb Add drupal-auth filter and jail 2015-04-27 13:10:27 -04:00
Yaroslav Halchenko 0f75ed5e2a Just use a system wide python in the tests digest.py
to stay inline with the other scripts
2015-04-26 21:57:13 -04:00
Yaroslav Halchenko 1784205ff8 DOC: Slight tune up to RELEASE doc -- no need for PYTHONPATH to run tests 2015-04-26 21:49:58 -04:00
Yaroslav Halchenko 1fb867b839 MANIFEST: updated for some new files, sorted all entries, removed some duplicates 2015-04-26 21:47:28 -04:00
Yaroslav Halchenko ca849b93dc Initial changes for the release -- simplified ChangeLog header etc 2015-04-26 21:39:54 -04:00
Yaroslav Halchenko 23d9e22477 Merge pull request #1001 from leeclemens/bf/1000-asteriskBlocksSelf
Match hacking attempt IP instead of asterisk server IP (closes #1000)
2015-04-26 21:02:04 -04:00
Lee Clemens b530d88eca Merge remote-tracking branch 'upstream/master' into bf/1000-asteriskBlocksSelf
Conflicts:
	ChangeLog
2015-04-26 15:13:59 -04:00
Yaroslav Halchenko 878cbd008e Merge pull request #1024 from themanwhosold/master
updated filter.d/sshd.conf
2015-04-17 08:06:25 -04:00
Markus Oesterle f8c7247f42 added \s after host 2015-04-17 10:22:01 +02:00
Markus Oesterle 5f2807b41f replaced .* before rhost with regex matching all the previous fields 2015-04-17 10:04:35 +02:00
Markus Oesterle 6ba389c70c Fixed typo in filter description authentification instead of authentication 2015-04-16 23:43:57 +02:00
Markus Oesterle 7a1f1c6b0c Fixed the UTC -> CEST difference... 2015-04-16 21:54:57 +02:00
Markus Oesterle b9a09af914 Added changes to ChangeLog & updated sample test cases 2015-04-16 21:33:57 +02:00
Markus Oesterle 8825a5f31b updated filter.d/sshd.conf
Added line to match sshd auth errors on OpenSuSE systems
2015-04-16 19:48:28 +02:00
Yaroslav Halchenko 13d56af981 Merge pull request #1018 from opoplawski/no_network
Do not run smtp tests if no_network set
2015-04-07 21:33:09 -04:00
Orion Poplawski aa8113c128 Do not run smtp tests if no_network set 2015-04-07 15:52:29 -06:00
Yaroslav Halchenko c926af1fce Merge pull request #1002 from sebres/_bf/fix-invalid-ip
fix test for invalid IP (use TEST-NET-1 according to RFC 5737)
2015-03-25 14:02:00 -04:00
Yaroslav Halchenko b2c1673d28 BF: if install pypy -- come back to original directory 2015-03-25 12:56:25 -04:00
Yaroslav Halchenko eb05cd7bd5 BF(OSX): apparently exceptions could not be compared for identity, use repr 2015-03-25 11:27:22 -04:00
sebres 6da0c4ad48 very long time resolving IP for address "abcdef" on some PDC, under NAT etc. - replaced via "abcdef.abcdef" to prevent searching in local domains; 2015-03-25 01:50:51 +01:00
sebres c5ba76aab8 fix test for invalid IP (use TEST-NET-1 according to RFC 5737):
since fef031b3cd failed, because on some platforms like vm:debian 10.0.0.0 returns 'localhost' (intern network).
2015-03-25 01:24:33 +01:00
Lee Clemens 72f4bcfbff Match hacking attempt IP instead of asterisk server IP (closes #1000) 2015-03-24 19:03:26 -04:00
Yaroslav Halchenko d28880fdca Merge pull request #997 from yarikoptic/bf/long-purge-for-recidive
DOC: make a warning for recidive jail to increase dbpurgeage (Closes #964)
2015-03-23 21:30:04 -04:00
Yaroslav Halchenko 54f111429d BF: fixing up version comparison for pypy. Issue appeared in 2.5.0
00:11  yoh: upgraded to 2.5.0 from debianexperimental and now reproduced locally
00:12  yoh: why pypy --version  directs output to stderr?  thereis no error
00:12  mattip: ok, can you try with a nightly from http://buildbot.pypy.org/nightly/trunk ?
00:15 * yoh running with 2.6.0-alpha0...
00:16  yoh: clean -- no crash
2015-03-23 21:28:16 -04:00
Yaroslav Halchenko 9339293413 ENH: minor formatting, no functional changes 2015-03-23 21:26:17 -04:00
Yaroslav Halchenko 4a83741397 BF: do not expect setting logtarget to SYSLOG to work on non-Linuxes
I have no BSD buildbots available for *BSDs etc, so can't speak for all, but
http://nipy.bic.berkeley.edu/builders/fail2ban-py2.6-osx-10.6_master/builds/151/steps/shell_1/logs/stdio
suggests that logically fails on OSX
2015-03-21 22:30:58 -04:00
Yaroslav Halchenko 56aacf872c Merge pull request #952 from ache/master
Update bsd-ipfw.conf
2015-03-21 21:46:54 -04:00
Yaroslav Halchenko 02836b599c Added a comment about systemd backend for jails with logs outside of journal (Closes #959) 2015-03-21 21:25:50 -04:00
Yaroslav Halchenko 320a28a4a4 DOC: make a warning for recidive jail to increase dbpurgeage (Closes #964) 2015-03-21 20:50:03 -04:00
Yaroslav Halchenko 938e6343ea Merge pull request #996 from yarikoptic/bf/no-dns-module
BF/TST: expect ['error'] as a value if no dns module available
2015-03-21 20:27:15 -04:00
Yaroslav Halchenko d5d8bc8134 Merge pull request #986 from yarikoptic/bf/pypy-2.4.0
BF: use daily build of pypy until next one gets released
2015-03-21 20:26:45 -04:00
Yaroslav Halchenko 382e7f02ca BF: expect ['error'] as a value if no dns module available
As many buildbots show:
e.g. http://nipy.bic.berkeley.edu/builders/fail2ban-py2.7-osx-10.8_master/builds/163/steps/shell_1/logs/stdio
2015-03-21 16:04:34 -04:00
Yaroslav Halchenko 782629c256 Merge pull request #985 from yarikoptic/bf/bad_file_descr_3.4
BF: asyncore.loop poll=True for recent (>=3.4) pythons too
2015-03-21 13:31:10 -04:00
Yaroslav Halchenko 3f3ddaceae print travis python version to figure out why not in effect 2015-03-06 08:53:12 -05:00
Yaroslav Halchenko dd9b5f75af BF: use daily build of pypy until next one gets released 2015-03-06 00:20:17 -05:00
Yaroslav Halchenko 31d107d181 BF: asyncore.loop poll=True for recent (>=3.4) pythons too
should avoid
  File /usr/lib/python3.4/asyncore.py, line 208, in loop
    poll_fun(timeout, map)
  File /usr/lib/python3.4/asyncore.py, line 145, in poll
    r, w, e = select.select(r, w, e, timeout)
OSError: [Errno 9] Bad file descriptor
2015-03-05 22:52:40 -05:00
Yaroslav Halchenko daa2a9e5d8 Merge pull request #975 from sebres/gh-973-fix
BF: binding parameter error (unsupported type) (closes gh-973) ...
2015-03-05 22:47:45 -05:00
Yaroslav Halchenko 954075449d BF: fixed casing in __sigUSR1handler 2015-02-26 20:59:52 -05:00
Yaroslav Halchenko e52790073d Merge pull request #979 from tgyurci/master
Flush logs at USR1 signal
2015-02-26 21:00:07 -05:00
Teubel György 0254cbf7fb Flush logs at USR1 signal 2015-02-26 23:23:10 +01:00
sebres 5ab30c88c2 more stable handling of json dump/load different encoded strings for older python versions;
extended test cases (more precise, python version insensitive, etc.)
2015-02-25 22:14:49 +01:00
sebres 2bfe22aa66 makes test case more precise; 2015-02-25 15:05:32 +01:00
sebres 6c788a32ee BF: binding parameter error (unsupported type) by writing json with invalid encoded lines into sqlite database (gh-973);
especially python < 3.0; try to prevent occurring such errors in the future;
2015-02-25 11:56:11 +01:00
Lee Clemens 50cbd4e9eb Merge pull request #961 from yarikoptic/enh/logencoding_msg
ENH: explicitly hint on logencoding setting in jail (Close #909)
2015-02-18 21:19:18 -05:00
Yaroslav Halchenko 82d5e6b840 ENH: explicitly hint on logencoding setting in jail (Close #909) 2015-02-18 21:00:35 -05:00
Yaroslav Halchenko 83805ee5dc Changelog for preceding merge 2015-02-14 16:07:28 -05:00
Yaroslav Halchenko e788e3823e Merge pull request #965 from TorontoMedia/master
Split output of firewallcmd list into separate lines for grepping (Close #908)
2015-02-14 16:06:10 -05:00
TorontoMedia b4f1f613bb Update firewallcmd-allports.conf 2015-02-14 12:32:36 -05:00
TorontoMedia 0fac7e40b6 Update firewallcmd-multiport.conf 2015-02-14 12:31:33 -05:00
Yaroslav Halchenko 54e182e017 Merge pull request #955 from sebres/fail2ban-regex-gh-954
BF: fail2ban-regex does not read '.local' file of given filter (Close #954)
2015-02-14 09:44:54 -05:00
Yaroslav Halchenko ae2af0d51b Minor tune up to changelog (we should eventually just make it into .md format) 2015-02-14 09:37:13 -05:00
Yaroslav Halchenko 07b0ab07ad Merge branch 'master' of https://github.com/rumple010/fail2ban
* 'master' of https://github.com/rumple010/fail2ban:
  Changed default TTL value to 60 seconds.
  Added a reminder to create an nsupdate.local file to set required options.
  Modified the ChangeLog and THANKS files to reflect the addition of action.d/nsupdate.conf.
  add nsupdate action

Conflicts:
	ChangeLog
2015-02-14 09:32:05 -05:00
Yaroslav Halchenko be75519402 Merge pull request #956 from yarikoptic/enh/badips_categories
ENH: check badips.com response on presence of "categories" in it
2015-02-14 09:30:26 -05:00
sebres 74c6f6ac4b BF: fail2ban-regex does not read '.local' file of given filter (gh-954) 2015-02-13 15:36:00 +01:00
Yaroslav Halchenko d5e68abf95 ENH: check badips.com response on presence of "categories" in it
As https://travis-ci.org/fail2ban/fail2ban/jobs/50609529 query might fail in
that response would not contain "categories".  With this change we will handle
it explicitly and will spit out ValueError, providing information about
the response so it could be troubleshooted
2015-02-13 08:55:35 -05:00
Ache ae1451b29f Update bsd-ipfw.conf
Deleting not existent is not error.
Adding already present is not error.
Otherwise all those entries becomes stale forever, not removed and its number increases over time.
2015-02-08 15:55:32 +03:00
Yaroslav Halchenko 3fb2becddb Merge pull request #949 from leeclemens/enh/configSyslogSocket
Configure Syslog Socket Path (closes #814)
2015-02-06 20:08:15 -05:00
Lee Clemens 6268eb32be Use syslogsocket value "auto" to determine syslog socket's path 2015-02-06 19:14:09 -05:00
Yaroslav Halchenko b46ac0b58e Merge pull request #950 from lwh/master
Fixed grammatical error in emails sent
2015-02-06 11:51:19 -05:00
Luke Hollins 549ab24e70 Fixed grammatical error in emails sent 2015-02-06 11:47:03 -05:00
Yaroslav Halchenko 119a7bbb16 Merge pull request #939 from szepeviktor/geoip
Added sendmail-geoip-lines.conf
2015-02-06 11:32:41 -05:00
Viktor Szépe 4c88a00c28 Line notes implemented 2015-02-06 17:22:30 +01:00
Lee Clemens d676a9fd4f update ChangeLog with syslogsocket config enhancement 2015-02-05 23:48:18 -05:00
Lee Clemens 445fd7367f Configure Syslog Socket Path 2015-02-05 23:44:57 -05:00
Yaroslav Halchenko 40068f5f31 Merge pull request #933 from mrc0mmand/nginx-botsearch
Add jail nginx-botsearch and refactor common with apache-botsearch regexes into botsearch-common
2015-02-04 09:27:43 -05:00
Yaroslav Halchenko eaca33e227 Merge branch 'enh/clarifyDnsUtilsMethods' of https://github.com/leeclemens/fail2ban
* 'enh/clarifyDnsUtilsMethods' of https://github.com/leeclemens/fail2ban:
  Update ChangeLog
  Clarify filter.DNSUtils functions' terminology and add unittests

Conflicts:
	ChangeLog -- rephrased a bit as well
2015-02-03 20:29:03 -05:00
Lee Clemens ed71a7cd22 Update ChangeLog 2015-02-03 20:23:25 -05:00
Lee Clemens b28fea4d41 Clarify filter.DNSUtils functions' terminology and add unittests 2015-02-03 20:19:39 -05:00
František Šumšal 9bd25f51c1 Added ChangeLog and THANKS entry 2015-02-04 02:19:15 +01:00
František Šumšal 642e425f75 Merge branch 'master' into nginx-botsearch 2015-02-04 02:18:14 +01:00
Yaroslav Halchenko 5b3aa42c42 Merge pull request #945 from leeclemens/ENH/ChangeLogForLogIgnoreCause
Update ChangeLog from PR 930
2015-02-03 20:16:30 -05:00
Yaroslav Halchenko 43a30f0ad6 Added to CONTRIBUTING.md minimal guidelines for PRs 2015-02-03 20:14:53 -05:00
František Šumšal eb0d086ed0 Merge branch 'master' into nginx-botsearch 2015-02-04 02:13:33 +01:00
Lee Clemens 4091fdde27 Update ChangeLog from PR 930 2015-02-03 19:54:23 -05:00
František Šumšal 1c6d2074fb Changed default settings for nginx-botseach filter 2015-02-04 01:48:59 +01:00
Yaroslav Halchenko 991096e599 Merge pull request #930 from leeclemens/ENH/916-logCauseOfIgnore
Conditionally log Ignore IP, and pass in reason (Closes #916)
2015-02-03 19:24:59 -05:00
Yaroslav Halchenko 51333bb0a6 just a bit of description for a test case 2015-02-03 18:38:19 -05:00
Lee Clemens 50d18f68df fix typo (false positive test) 2015-02-03 18:18:09 -05:00
Lee Clemens c755138672 create OK and NOK methods 2015-02-03 18:11:49 -05:00
Lee Clemens 8233f21fc2 Remove duplicate unittests 2015-02-03 18:06:30 -05:00
Lee Clemens aa848a5f9e Combine ignore cause unitests 2015-02-03 18:02:42 -05:00
Orion Poplawski e7ff7e90b7 [postfix-sasl] update regexes
- Add : to match "SASL LOGIN authentication failed: Password:"
- Add ignoreregex to ignore system authentication issues:
  "warning: unknown[1.1.1.1]: SASL LOGIN authentication failed: Connection lost to authentication server"
- Add test log messages for both
2015-02-03 11:30:16 -07:00
František Šumšal fb0f463eac Include consistency 2015-02-03 15:54:05 +01:00
František Šumšal 705718be52 Filter apache-botsearch.conf now loads variables from botsearch-common.conf 2015-02-03 04:44:33 +01:00
František Šumšal 18778d9174 Created botsearch-common.conf
File contains variables used in -botsearch filters
2015-02-03 04:25:47 +01:00
Lee Clemens 3186df55e3 add Ignore DNS and IP test cases 2015-02-02 21:55:44 -05:00
Yaroslav Halchenko 646c799231 Changelog for above merge 2015-02-02 21:46:38 -05:00
Yaroslav Halchenko 1fbafa46c9 Merge pull request #918 from sebres/issue/161
Issue/161
2015-02-02 21:44:57 -05:00
Yaroslav Halchenko 73af02ffc6 Merge pull request #940 from leeclemens/ENH/ApacheFakeGoogleBot
New jail: apache-fakegooglebot
2015-02-02 21:44:04 -05:00
Yaroslav Halchenko df581fe6e2 Merge pull request #929 from opoplawski/pam_auth
Add filter variable __pam_auth to allow customize for setups with multiple authorization schemes (Close #928)
2015-02-02 21:42:10 -05:00
Yaroslav Halchenko 7f2d1a7269 minor changelog entry reformatting 2015-02-02 21:37:24 -05:00
Yaroslav Halchenko 7ada96b4e9 Merge pull request #932 from opoplawski/dovecot
Dovecot - dovecot auth failure from EL7
2015-02-02 21:37:28 -05:00
František Šumšal f8fe165cd2 Switched from tabs to spaces for indents 2015-02-03 03:35:22 +01:00
Yaroslav Halchenko 767ac4ecac Merge branch 'master' of git://github.com/fail2ban/fail2ban
* 'master' of git://github.com/fail2ban/fail2ban:
  Remove trailing semicolons
2015-02-02 21:21:54 -05:00
Yaroslav Halchenko 8f6d9c6a5a Merge branch 'enh/local_time_zone' of https://github.com/yarikoptic/fail2ban
* 'enh/local_time_zone' of https://github.com/yarikoptic/fail2ban:
  fixed typos, thanks szepeviktor for review
  ENH: use non-UTC date invocation (without -u) and report offset for localzone (%z)

Conflicts:
	ChangeLog
2015-02-02 21:21:44 -05:00
Yaroslav Halchenko 96ae041132 fixed typos, thanks szepeviktor for review 2015-02-02 21:21:37 -05:00
Yaroslav Halchenko fc0ac45f55 Merge pull request #942 from leeclemens/ENH/RemoveTrailingSemicolons
Remove trailing semicolons
2015-02-02 20:56:21 -05:00
Lee Clemens 2d266d96d5 Remove trailing semicolons 2015-02-02 19:03:43 -05:00
Lee Clemens b725db04d8 Add ignorecommands to MANIFEST*'s 2015-02-02 15:03:44 -05:00
Lee Clemens eb17b68641 fix test for invalid IP 2015-02-02 14:03:35 -05:00
Lee Clemens fef031b3cd test ipToName Exception 2015-02-02 14:01:48 -05:00
Lee Clemens 4cfbb840ad move test to more sensible function name 2015-02-02 13:40:56 -05:00
Lee Clemens 0463518d28 Add testcase for DNSUtils.ipToName 2015-02-02 13:14:53 -05:00
Lee Clemens d0986148f0 Merge branch 'yarikoptic-enh/fakegooglebot' into ENH/ApacheFakeGoogleBot 2015-02-02 13:02:19 -05:00
Lee Clemens 841c476045 Merge branch 'enh/fakegooglebot' of https://github.com/yarikoptic/fail2ban into yarikoptic-enh/fakegooglebot
Conflicts:
	config/filter.d/ignorecommands/apache-fakegooglebot
2015-02-02 13:01:23 -05:00
Yaroslav Halchenko 15b65c7ad2 NF: apache-fakegooglebot ignorecommand + DNSUtils.ipToName 2015-02-02 12:19:20 -05:00
Lee Clemens 7e94ba6f0c Remove implementation specific suffix 2015-02-02 11:43:05 -05:00
Lee Clemens 854915920f Remove implementation specific suffix 2015-02-02 11:38:23 -05:00
Lee Clemens 00961d5281 Remove ignorecommand addition from ChangeLog 2015-02-02 11:36:21 -05:00
Lee Clemens 38415d2cf1 Add trailing comma back to list 2015-02-02 11:29:27 -05:00
Lee Clemens af078532ac New jail: apache-fakegooglebot
Detects fake googlebot user agents in apache access log
2015-02-02 00:42:01 -05:00
Viktor Szépe 0430e0dacc Changelog entry for sendmail-geoip-lines 2015-02-01 00:24:40 +01:00
Viktor Szépe 1619ab3145 Added sendmail-geoip-lines.conf 2015-02-01 00:06:56 +01:00
Yaroslav Halchenko cac0848d2c Merge pull request #936 from yarikoptic/enh/ignoreregex
ENH: define ignoreregex for all filters explicitly, to avoid warnings (Closes #934)
2015-01-31 11:53:27 -05:00
Yaroslav Halchenko ec6a30efcf ENH: define ignoreregex for all filters explicitly, to avoid warnings (Closes #934) 2015-01-30 10:38:28 -05:00
František Šumšal c8e82f18b6 Add jail nginx-botsearch
Jail blocks requests for predefined non-existent folders. Based on
apache-botsearch jail.
2015-01-29 17:57:52 +01:00
Orion Poplawski b4776a1ba0 Match dovecot unknown user line 2015-01-29 09:37:37 -07:00
Orion Poplawski ee5c5b34d6 Add ChangeLog and THANKS entry 2015-01-29 09:14:41 -07:00
Orion Poplawski 3bc92610f7 Add dovecot auth failure from EL7 2015-01-29 09:11:59 -07:00
Yaroslav Halchenko c96415da27 added $named and ufw to debian-initd (Debian bug #776572) 2015-01-29 08:32:20 -05:00
Andrew St. Jean 6bdfe756cf Changed default TTL value to 60 seconds. 2015-01-28 22:46:43 -05:00
Lee Clemens f4341999cd simplify/unify log message 2015-01-28 19:43:22 -05:00
Lee Clemens 076b103f97 Conditionally log Ignore IP, and pass in reason (ignoreip, ignorecommand) 2015-01-27 21:06:06 -05:00
Orion Poplawski 79b5a2617f Add filter variable __pam_auth to allow easier changing of pam auth backend 2015-01-27 14:34:27 -07:00
Yaroslav Halchenko 64feb0fd16 Merge pull request #924 from leeclemens/ENH/StatusExtendedInfo
Add extended info to status output using Cymru
2015-01-26 22:55:12 -05:00
Andrew St. Jean 43732acae1 Added a reminder to create an nsupdate.local file to set required options. 2015-01-26 21:48:16 -05:00
Lee Clemens 887fa2a3a0 Update protocol with [FLAVOR] argument to status <JAIL> 2015-01-26 20:11:53 -05:00
Lee Clemens 297a32e6bb Update test since JailThread.action was changed from property to method 2015-01-26 20:02:49 -05:00
Lee Clemens 767fc0d4d4 Merge branch 'ENH/StatusExtendedInfo' of github.com:leeclemens/fail2ban into ENH/StatusExtendedInfo
Conflicts:
	ChangeLog
	fail2ban/server/actions.py
	fail2ban/server/server.py
	fail2ban/server/transmitter.py
	fail2ban/tests/servertestcase.py
2015-01-26 19:50:46 -05:00
Lee Clemens 486214585e Update extended status to accept additional argument, flavor
Default to as-in behavior, or flavor=="basic"
2015-01-26 19:38:06 -05:00
Andrew St. Jean e0f11ae722 Modified the ChangeLog and THANKS files to reflect the addition of action.d/nsupdate.conf. 2015-01-26 11:30:41 -05:00
Yaroslav Halchenko 085d0f72ed ENH: use non-UTC date invocation (without -u) and report offset for localzone (%z) 2015-01-26 09:19:44 -05:00
Yaroslav Halchenko 65980a70fc Merge branch 'enh/recidive-allports' of https://github.com/yarikoptic/fail2ban
* 'enh/recidive-allports' of https://github.com/yarikoptic/fail2ban:
  use iptables-allports for recidive

Conflicts:
	ChangeLog
2015-01-26 09:04:42 -05:00
Yaroslav Halchenko 4f28bc4fb0 Merge pull request #922 from leeclemens/ENH/pypy3TravisSupport
Add pypy3 Travis Support
2015-01-26 09:01:06 -05:00
rumple010 eb76dcd5a0 add nsupdate action
Adds a new action file that uses nsupdate to dynamically update a BIND
zone file with a TXT resource record representing a banned IP address.
Resource record is deleted from the zone when the ban expires.
2015-01-25 23:15:07 -05:00
Lee Clemens dfe4d02f65 Remove version specific package 2015-01-24 12:45:42 -05:00
Lee Clemens 735c51adae fix test of new banManager's instance 2015-01-24 12:45:42 -05:00
Lee Clemens a0debea56a test dnspython nxdomain returned 2015-01-24 12:45:42 -05:00
Lee Clemens 07a47179a7 conditionally import dnspython 2015-01-24 12:45:42 -05:00
Lee Clemens ef3c942808 add dnspython[3] optional dependencies 2015-01-24 12:45:42 -05:00
Lee Clemens 405f363fe8 Conditionally test fail2ban-client status <JAIL> extended when dnspython is installed 2015-01-24 12:45:42 -05:00
Lee Clemens ba69969057 Add pass to empty methods 2015-01-24 12:45:42 -05:00
Lee Clemens 60ac0a1a17 Add extended info to status output using Cyrmu 2015-01-24 12:45:42 -05:00
Lee Clemens 13b2aea48a Remove version specific package 2015-01-24 12:22:34 -05:00
Lee Clemens 03db257c43 fix test of new banManager's instance 2015-01-23 16:18:09 -05:00
Lee Clemens ce0fe8b907 test dnspython nxdomain returned 2015-01-23 16:00:49 -05:00
Lee Clemens 256c871121 conditionally import dnspython 2015-01-23 16:00:33 -05:00
Lee Clemens 8fd9d6a770 add dnspython[3] optional dependencies 2015-01-23 15:43:58 -05:00
Lee Clemens a80ff26e15 Conditionally test fail2ban-client status <JAIL> extended when dnspython is installed 2015-01-23 15:40:00 -05:00
Lee Clemens a8f057eab7 Add pass to empty methods 2015-01-23 15:27:33 -05:00
Lee Clemens 7d0700b6f8 merge ENH/UseTravisRetry 2015-01-23 15:20:56 -05:00
Yaroslav Halchenko cfaa76a355 Merge pull request #923 from leeclemens/ENH/UseTravisRetry
Use travis_retry for commands which use the internet
2015-01-23 15:14:04 -05:00
Lee Clemens 625bcef8a1 Add extended info to status output using Cyrmu 2015-01-23 15:12:04 -05:00
Lee Clemens d01099f347 Use travis_retry for commands which use the internet 2015-01-23 14:43:00 -05:00
Lee Clemens 40eb7a40f7 Add pypy3 Travis Support 2015-01-23 13:54:00 -05:00
Yaroslav Halchenko 17b3df004e Merge pull request #919 from sebres/issue/907-embedded
Issue/907 + embedded
2015-01-21 11:53:25 -05:00
sebres d0b932aaca code review + more test cases (embedded replace in a string) 2015-01-21 09:44:55 +01:00
sebres 6b42878b8c better recognition of embedded-recursive substitution to repeat interpolation 2015-01-20 17:31:17 +01:00
sebres 33e9e2174a recursive/embedded version of issue/907;
test cases merged from remote-tracking branch 'yarikoptic:enh/embedded_tags' into issue/907
infinite busy loop on _escapedTags match in substituteRecursiveTags gh-907
2015-01-20 17:18:25 +01:00
sebres 607af36ad3 workaround for the "Bad file descriptor" issue on Python 2.7, gh-161 : asyncore.loop() using poll
by the way, prevents to write "'build/bdist.linux-x86_64' does not exist -- can't clean it" into stderr;
2015-01-20 14:08:30 +01:00
sebres b04a51246f infinite busy loop on _escapedTags match in substituteRecursiveTags gh-907 2015-01-20 11:32:15 +01:00
Yaroslav Halchenko 9720e0971e Merge pull request #915 from sebres/issue/913
port[s] typo fixed in jail.conf/nginx-http-auth, issue gh-913
2015-01-19 09:10:31 -05:00
sebres 12e3cca3f2 port[s] typo fixed in jail.conf/nginx-http-auth, issue gh-913 2015-01-19 10:28:53 +01:00
Yaroslav Halchenko fdd93d1475 ENH: unittest to catch actions without Init or Definition section and all must have actionban at least 2015-01-08 21:51:52 -05:00
Yaroslav Halchenko 083031524d BF: adding missing Definition section header to firewallcmd-allports 2015-01-08 21:14:50 -05:00
TorontoMedia d7b7f4bc91 Update firewallcmd-allports.conf 2015-01-08 21:06:43 -05:00
Yaroslav Halchenko c7edd9e67f Merge pull request #901 from leeclemens/ENH/PostfixRBL
Create Jail for Postfix based on RBL
2015-01-07 21:45:36 -05:00
Yaroslav Halchenko 995b1d18df Merge pull request #906 from leeclemens/BF/755-strptime
Fix strptime thread safety issue
2015-01-07 20:40:14 -05:00
Lee Clemens 77677e43df Merge branch 'master' of github.com:fail2ban/fail2ban into ENH/PostfixRBL 2015-01-07 20:39:04 -05:00
Yaroslav Halchenko a8f26cd2b2 Merge pull request #905 from TorontoMedia/master
Firewallcmd-multiport.conf and Firewallcmd-allports.conf
2015-01-04 11:23:21 -05:00
Lee Clemens 4714028c69 Change case and tense for consistency 2015-01-03 16:16:23 -05:00
Lee Clemens bda8dc1926 Merge branch 'master' of github.com:fail2ban/fail2ban into ENH/PostfixRBL 2015-01-03 15:29:42 -05:00
Lee Clemens 2f360ce447 Update Changelog with strptime fix 2015-01-03 15:26:34 -05:00
Lee Clemens 38641e741a Merge branch 'master' of github.com:fail2ban/fail2ban into BF/755-strptime
Conflicts:
	ChangeLog
2015-01-03 15:25:54 -05:00
Lee Clemens 541a747d79 Update Changelog with strptime fix 2015-01-03 15:19:58 -05:00
Lee Clemens b26725f654 Move strptime workaround to fail2ban/__init__.py 2015-01-03 13:45:06 -05:00
Lee Clemens d0bcacd97b Fix strptime thread safety issue
strptime thread safety hack-around - http://bugs.python.org/issue7980
2015-01-02 02:55:40 -05:00
TorontoMedia 74c3d5d96c Updated ChangeLog 2015-01-01 13:26:11 -05:00
TorontoMedia 948eec6425 Upd 2015-01-01 12:56:17 -05:00
TorontoMedia 7eed55266b Created firewallcmd-multiport 2015-01-01 12:46:48 -05:00
TorontoMedia 9f91cb2fd8 Created firewallcmd-allports 2015-01-01 12:44:34 -05:00
TorontoMedia a47001ea0e Updated ChangeLog 2015-01-01 12:41:31 -05:00
TorontoMedia 1dfd9941df Update THANKS 2015-01-01 05:33:20 -05:00
TorontoMedia 50e5fd9ed7 Create firewallcmd-multiport.conf 2015-01-01 05:32:41 -05:00
TorontoMedia 591e444753 Create firewallcmd-allports.conf 2015-01-01 05:32:06 -05:00
TorontoMedia c2bb3253ad Update ChangeLog 2015-01-01 05:27:18 -05:00
Yaroslav Halchenko 8fc32bb33f Merge pull request #899 from leeclemens/ENH/gitignore
Add .idea dir to .gitignore
2014-12-31 18:48:57 -05:00
Yaroslav Halchenko acfa83229b Merge branch 'master' of git://github.com/fail2ban/fail2ban
* 'master' of git://github.com/fail2ban/fail2ban:
  Update year in postfix logs test file
  Add 'Client host rejected error message' regex Not sure if it was reworded (using Postfix 2.6) or a slightly different error, but I only have "Client host rejected: cannot find your hostname"
2014-12-31 01:12:56 -05:00
Lee Clemens 0f48cf4284 loosen up regex for spamhaus (spamcop says "Blocked" as part of url) 2014-12-30 19:14:39 -05:00
Lee Clemens fe72a5585c Create Jail for Postfix based on RBL
Use RBL blocks to ban addresses, unique Jail so maxretry can be set to 1 (vs postfix.conf)
2014-12-30 19:06:17 -05:00
Yaroslav Halchenko 37edb075e9 Merge pull request #900 from leeclemens/ENH/PostfixFilterNoQueue
Add 'Client host rejected error message' regex
2014-12-30 18:44:14 -05:00
Lee Clemens e6ffa2e4a1 Update year in postfix logs test file 2014-12-30 18:10:19 -05:00
Lee Clemens 2d7429c47c Add 'Client host rejected error message' regex
Not sure if it was reworded (using Postfix 2.6) or a slightly different error, but I only have "Client host rejected: cannot find your hostname"
2014-12-30 18:05:19 -05:00
Lee Clemens 6c34cf2e1e Add .idea dir to .gitignore 2014-12-30 17:52:45 -05:00
Yaroslav Halchenko d65c4f8f5d moved debian's initd file to files/debian-initd from debian branch 2014-12-30 16:45:35 -05:00
Yaroslav Halchenko bcfcefa203 Merge branch 'patch-2' of https://github.com/szepeviktor/fail2ban
* 'patch-2' of https://github.com/szepeviktor/fail2ban:
  downcase example
  Added an item to "Fixes"
  postfix-sasl failregex case insensitive
2014-12-30 16:35:09 -05:00
Yaroslav Halchenko 35766e720d Merge pull request #896 from szepeviktor/patch-3
Monit config
2014-12-30 15:57:14 -05:00
Viktor Szépe 10f68f4946 Update ChangeLog 2014-12-24 15:00:25 +01:00
Viktor Szépe 971c3d93fe Monit config
Copy it to `/etc/monit/monitrc.d/fail2ban`
More info: https://github.com/szepeviktor/debian-server-tools/blob/master/monitoring/monit/monit-debian-setup.sh#L113
2014-12-24 14:45:48 +01:00
Yaroslav Halchenko cc89649d04 BF: adjusted for new IP of example.com
Conflicts:
	fail2ban/tests/filtertestcase.py
2014-12-21 21:45:30 -05:00
Viktor Szépe a9b6a3754b downcase example 2014-12-11 21:01:52 +01:00
Viktor Szépe 190f55b06e Added an item to "Fixes" 2014-12-11 01:34:20 +01:00
Viktor Szépe 81b3dbde1d postfix-sasl failregex case insensitive 2014-12-11 00:10:37 +01:00
Yaroslav Halchenko fb2b52af14 Merge pull request #879 from sebres/broken-test-setup_install_root
testSetupInstallRoot will be always skipped, ...
2014-12-05 11:20:31 -05:00
sebres a71a64733a clean all after test setup (removes a build directory in current root of fail2ban) 2014-12-05 16:39:17 +01:00
Yaroslav Halchenko 20d212dcd8 Merge pull request #873 from bes-internal/patch-1
exim filter: added  matching  of possible port after host
2014-12-04 10:21:13 -05:00
bes-internal ccc986b7d8 exim filter: correct failregex for exim with extended log options
incoming_interface, incoming_port, outgoing_port
2014-12-04 13:34:44 +03:00
sebres 7d4f071d4b small fix: no cover for failed case 2014-12-03 15:25:27 +01:00
sebres d62b046704 testSetupInstallRoot will be always skipped, because of "wrong" location of 'setup.py'; 2014-12-03 14:45:46 +01:00
Yaroslav Halchenko c5b5695eb9 Merge pull request #868 from sebres/addfailregex-gh-867
"known/" prefix to allow reuse specs from prev files for addfailregex/addignoreregex (Close #867)
2014-12-01 09:02:50 -05:00
sebres 80fb48c5b0 Merge remote-tracking branch 'remotes/upstream/master' into sebres:addfailregex-gh-867 2014-12-01 13:14:42 +01:00
Yaroslav Halchenko a170afcb76 Merge pull request #839 from sebres/fix-none-getattempt-lambda
Fix none getattempt lambda (close #838,  close #848)
2014-11-29 21:33:09 -05:00
sebres effdb450fc better and scalable solution for gh-867 (and gh-868), using only name convention like %(known/failregex)s to add custom expressions, so no interface changes in jail.conf are necessary (for example see test-known-interp in test cases); 2014-11-29 20:33:32 +01:00
Yaroslav Halchenko 9bab6d0009 Changelog entry for preceding fix 2014-11-29 09:52:25 -05:00
Yaroslav Halchenko 4a620aa2ba Merge pull request #869 from opoplawski/logpath
Separate php-url-fopen logpath by newline
2014-11-29 09:50:42 -05:00
Orion Poplawski d8867807f5 Separate php-url-fopen logpath by newline 2014-11-28 22:04:09 -07:00
sebres 00c2ac4b03 python 2.6 compatibility: preventing RuntimeError: dictionary changed size during iteration. 2014-11-28 19:50:52 +01:00
sebres d63b125877 interpolation of config readers extended with %(known/parameter)s.
(means last known option with name `parameter`).
2014-11-28 19:06:17 +01:00
sebres 1439152121 test cases extended (now correct) 2014-11-28 14:52:12 +01:00
sebres cad09d2df3 BF: failregex declared direct in jail was joined to single line, (specifying of multiple expressions was not possible);
feature request (gh-867): new options for jail introduced addfailregex/addignoreregex: extends regex specified in filter (opposite to failregex/ignoreregex that overwrites it);
2014-11-28 03:17:47 +01:00
Yaroslav Halchenko 72370d2574 Merge pull request #858 from g1franc/master
Add ignoreregex to avoid warning on start
2014-11-15 10:22:12 -05:00
Guillaume FRANCOIS a6a2dc868b Add ignoreregex to avoid warning on start 2014-11-12 11:05:56 +01:00
Guillaume FRANCOIS 9269664350 Add ignoreregex to avoid warning on start 2014-11-12 10:30:28 +01:00
Yaroslav Halchenko b379f5d51b Merge pull request #852 from sebres/patch-1
Bug fix in formatJournalEntry, gh-851
2014-11-07 07:45:27 -05:00
Serg G. Brester 6dfddbcdf6 Bug fix in formatJournalEntry, gh-851
Unhandled exception in fail2ban 0.9.1 #851
2014-11-07 01:21:38 +01:00
Yaroslav Halchenko 2a3790f8e8 use iptables-allports for recidive 2014-11-04 13:24:54 -05:00
Yaroslav Halchenko a44cfba9ae Merge pull request #841 from opoplawski/firewallcmd-multiport
ChangeLog for firewallcmd-new multiport support
2014-10-30 18:32:26 -04:00
Orion Poplawski 21be983620 ChangeLog for firewallcmd-new multiport support 2014-10-30 16:11:34 -06:00
Yaroslav Halchenko 967485c2d0 improving grepping 2014-10-29 23:14:47 -04:00
Yaroslav Halchenko efbf5064a1 Merge pull request #807 from xslidian/patch-1
grep IP at the start of lines
2014-10-29 23:07:10 -04:00
Yaroslav Halchenko 6d345a13f0 Merge pull request #840 from opoplawski/firewallcmd-multiport
Use multiport for firewallcmd-new
2014-10-29 23:03:56 -04:00
Orion Poplawski 01b2673e34 Use multiport for firewallcmd-new 2014-10-29 16:27:37 -06:00
sebres 92ba5ae09c few confusing merge info helper 2014-10-29 22:08:44 +01:00
sebres 46a8899f20 code review 2014-10-29 19:27:45 +01:00
Yaroslav Halchenko 36abb5ed96 BF: fix $ for % in jail.conf. Debian bug #767255 2014-10-29 13:08:51 -04:00
sebres 8dbc04aa06 Test cases fixed:
testFail2BanExceptHook - use local sys.__excepthook__ to check was really executed and prevent write error in stderr.
2014-10-29 13:30:24 +01:00
sebres 518cc92ccc actions: bug fix in lambdas in checkBan, because getBansMerged could return None (purge resp. asynchronous addBan), make the logic all around more stable;
test cases: extended with test to check action together with database functionality (ex.: to verify lambdas in checkBan);
database: getBansMerged should work within lock, using reentrant lock (cause call of getBans inside of getBansMerged);
2014-10-29 12:36:21 +01:00
Yaroslav Halchenko 7acddcbe4a Post-release boost to .dev 2014-10-27 23:45:51 -04:00
Yaroslav Halchenko a0115ee458 ENH: additional versioning changes 2014-10-27 21:49:40 -04:00
Yaroslav Halchenko d0a5fe620f Refreshed manpages 2014-10-27 21:47:48 -04:00
Yaroslav Halchenko 564eb3389b ENH: fail early in generate-man + provide PYTHONPATH upstairs 2014-10-27 21:47:07 -04:00
Yaroslav Halchenko 987356d6c0 Changes for the 0.9.1 release versioning 2014-10-27 21:43:17 -04:00
Yaroslav Halchenko 9e8e4dde69 Populated MANIFEST with more entries which were preiously missed or duplicated. Sorted within each "section" 2014-10-27 21:43:11 -04:00
Yaroslav Halchenko fc145eb795 Merge pull request #748 from pacop/master
ENH: Add dateTime format for PortSentry
2014-10-25 12:34:00 -04:00
Yaroslav Halchenko 8a453018a9 Merge pull request #830 from sebres/_tent/cache-config-read-fix1
fix: fail2ban-regex with filter file failed
2014-10-25 12:30:55 -04:00
pacop b60e2bf42f Add portsentry to changelog 2014-10-25 18:17:57 +02:00
pacop e3a037ee3f merge master 2014-10-25 18:15:34 +02:00
sebres 3dac765598 ConfigReader.touch renamed into protected _create_unshared 2014-10-25 17:20:01 +02:00
Yaroslav Halchenko 0b5413ec0b Merge branch 'master' of git://github.com/fail2ban/fail2ban
* 'master' of git://github.com/fail2ban/fail2ban:
2014-10-25 10:38:28 -04:00
Florian Pelgrim 3dabd5fc83 DOC: documentation about available vagrantfile setup
manually picked up from a commit within
https://github.com/fail2ban/fail2ban/pull/786
2014-10-25 10:38:18 -04:00
Florian Pelgrim 6293e44889 Added myself into THANKS 2014-10-25 10:37:28 -04:00
Yaroslav Halchenko b2b5d0b41c Merge pull request #829 from yarikoptic/minimal_python2.6
ENH:  remove obsolete code for python < 2.6 (we support >= 2.6)
2014-10-25 10:32:10 -04:00
Yaroslav Halchenko e1a5decc00 DOC: adjust docs in mytime to place docs into docstrings 2014-10-25 09:34:37 -04:00
Yaroslav Halchenko caa6006a31 ENH: do use @staticmethod (we are well beyond support of 2.4 now) 2014-10-25 09:25:18 -04:00
sebres 07d4badfd0 testExecuteTimeout fixed: give a test still 1 second, because system could be too busy 2014-10-24 05:42:58 +02:00
sebres bef0502e6b coverage: no cover (for failed except) 2014-10-24 05:28:35 +02:00
sebres 0b0ea41f87 fix: fail2ban-regex with filter file failed (after merging #824, because test case missing);
test case for 'readexplicit' added;
2014-10-24 04:59:44 +02:00
Yaroslav Halchenko d4015d6566 ENH: remove obsolete code for python < 2.6 (we support >= 2.6) 2014-10-23 14:51:51 -04:00
Yaroslav Halchenko e2f49b7334 DOC: very minor (tabs/spaces) 2014-10-23 14:44:10 -04:00
Yaroslav Halchenko 78e1a13fad Merge branch '_tent/cache-config-read' of https://github.com/sebres/fail2ban
* '_tent/cache-config-read' of https://github.com/sebres/fail2ban:
  code review, change log entries added;
  reset share/cache storage (if we use 'reload' in client with interactive mode)
  normalize tabs/spaces in docstrings;
  cache-config-read-v2 merged; logging normalized, set log level for loading (read or use shared) file(s) to INFO; prevent to read some files twice by read inside "_getIncludes" and by "read" self (occurred by only one file);
  code review; more stable config sharing, configurator always shares it config readers now;
  code review: use the same code (corresponding test cases - with sharing on and without it);
  rewritten caching resp. sharing of ConfigReader and SafeConfigParserWithIncludes (v.2, first and second level cache, without fingerprinting etc.);
  code review
  ConfigReader/ConfigWrapper renamed as suggested from @yarikoptic; + code clarifying (suggested also);
  Partially merge remote-tracking from 'sebres:cache-config-read-820': test cases extended, configurator.py adapted for test case.
  ENH: keep spitting out logging to the screen in LogCaptureTestCases if HEAVYDEBUG
  test case for check the read of config files will be cached;
  more precise by test
  ConfigWrapper class introduced: sharing of the same ConfigReader object between JailsReader and JailReader (don't read jail config each jail); sharing of the same DefinitionInitConfigReader (ActionReader, FilterReader) between all jails using that; cache of read a config files was optimized; test case extended for all types of config readers;
  config cache optimized - prevent to read the same config file inside different resources multiple times; test case: read jail file only once;
  test case for check the read of config files will be cached;
  caching of read config files, to make start of fail2ban faster, see issue #820
2014-10-23 14:28:33 -04:00
Yaroslav Halchenko 5ac496d030 We better check that installation doesn't cause any errors as well 2014-10-12 17:28:35 -04:00
Yaroslav Halchenko 47441d1383 Merge remote-tracking branch 'origin/master'
* origin/master:
  RF: moving logwatch setup/sample logs under files/logwatch
  ENH: print rebans stats even if no "Failures" are logged, and reduce indentation in output
  ENH: untabified and reindented entire script for sane formatting (no functional changes)
  BF: logwatch -- fixing up regex for 'already banned'
  Sample logfiles to test logwatch services script
  Adjusting fail2ban logwatch script to match lines from 0.9 as well
2014-10-12 16:44:24 -04:00
Yaroslav Halchenko 86a5f42f73 BF: made tests util digest.py friendly to python3 2014-10-12 16:40:29 -04:00
Yaroslav Halchenko 98dc0844ce Merge pull request #782 from yarikoptic/bf/logwatch
logwatch file (original 1.5 version + fixes for change of logs in 0.9)
2014-10-10 22:15:57 -04:00
sebres 7d3e6e9935 code review, change log entries added; 2014-10-10 20:06:58 +02:00
sebres 73a06d55a8 reset share/cache storage (if we use 'reload' in client with interactive mode) 2014-10-10 18:50:24 +02:00
sebres 7f5d4aa7a6 normalize tabs/spaces in docstrings; 2014-10-10 16:59:40 +02:00
sebres 95bdcdecaa cache-config-read-v2 merged;
logging normalized, set log level for loading (read or use shared) file(s) to INFO;
prevent to read some files twice by read inside "_getIncludes" and by "read" self (occurred by only one file);
2014-10-10 16:49:08 +02:00
sebres 02a46d0901 code review;
more stable config sharing, configurator always shares it config readers now;
2014-10-10 12:05:49 +02:00
sebres e0eb4f2358 code review: use the same code (corresponding test cases - with sharing on and without it); 2014-10-10 02:47:42 +02:00
sebres c35b4b24d2 rewritten caching resp. sharing of ConfigReader and SafeConfigParserWithIncludes (v.2, first and second level cache, without fingerprinting etc.); 2014-10-10 02:10:13 +02:00
sebres 37952ab75f code review 2014-10-09 19:51:53 +02:00
sebres f67053c2ec ConfigReader/ConfigWrapper renamed as suggested from @yarikoptic;
+ code clarifying (suggested also);
2014-10-09 19:01:49 +02:00
sebres f6723a12ff Merge branch 'cache-config-read-820' into _tent/cache-config-read 2014-10-09 18:01:31 +02:00
sebres b62ce14ccd Partially merge remote-tracking from 'sebres:cache-config-read-820':
test cases extended, configurator.py adapted for test case.
2014-10-09 18:00:45 +02:00
Yaroslav Halchenko 0c5f11079c ENH: keep spitting out logging to the screen in LogCaptureTestCases if HEAVYDEBUG 2014-10-09 10:47:00 -04:00
sebres f31607ded1 test case for check the read of config files will be cached;
Conflicts:
	fail2ban/tests/clientreadertestcase.py -- removed not needed
        time in imports
2014-10-09 10:30:17 -04:00
sebres 51cae63bf0 more precise by test 2014-10-09 15:39:58 +02:00
sebres 4244c87802 ConfigWrapper class introduced: sharing of the same ConfigReader object between JailsReader and JailReader (don't read jail config each jail);
sharing of the same DefinitionInitConfigReader (ActionReader, FilterReader) between all jails using that;
cache of read a config files was optimized;
test case extended for all types of config readers;
2014-10-09 14:51:08 +02:00
sebres 2a54e61238 config cache optimized - prevent to read the same config file inside different resources multiple times;
test case: read jail file only once;
2014-10-08 15:44:32 +02:00
sebres af4b48e841 test case for check the read of config files will be cached; 2014-10-07 14:37:40 +02:00
pacop ce4f2d1c88 added filter for PortSentry with jail and samples 2014-10-04 15:08:12 +02:00
pacop 37acc6b832 ENH: Add dateTime format for PortSentry
Added dateTime format for PortSentry with EPOCH format
2014-10-04 14:55:22 +02:00
sebres d00af327c5 caching of read config files, to make start of fail2ban faster, see issue #820 2014-10-03 02:11:55 +02:00
Yaroslav Halchenko 05fcb1f104 Merge pull request #813 from schaal/tests-configdir-env-variable
tests: Add function to utils to calculate CONFIG_DIR
2014-10-01 14:19:26 -04:00
Daniel Schaal 270ea363d3 tests: define CONFIG_DIR in utils. 2014-10-01 19:50:03 +02:00
Yaroslav Halchenko b912d61ccb Merge pull request #818 from slowriot/master
adding filter to detect Shellshock attack attempts with Apache
2014-09-29 09:32:21 -04:00
SlowRiot 5d526bbeb1 forgot to add test case to last commit 2014-09-29 00:49:22 +01:00
SlowRiot 7b5dc9f24f adding test case, changelog and thanks entries for apache shellshock filter 2014-09-26 18:48:56 +01:00
SlowRiot fc5f729f01 adding jail conf for shellshock filter 2014-09-26 16:37:50 +01:00
SlowRiot 4f636eb0e3 adding filter to detect Shellshock attack attempts against bash scripts through apache. See http://seclists.org/oss-sec/2014/q3/650 2014-09-26 16:25:07 +01:00
Yaroslav Halchenko bfaf33b6ba Merge pull request #812 from nickweeds/master
Issue #810: Update apache-auth.conf filter to match AH01630: client denied by server configuration
2014-09-14 21:01:50 -04:00
Nick Weeds 2c158fe168 Add apache filter for AH01630 client denied by server configuration 2014-09-14 21:54:05 +01:00
Yaroslav Halchenko caa851e5c8 RF: moving logwatch setup/sample logs under files/logwatch 2014-09-14 09:48:14 -04:00
Yaroslav Halchenko 8f521b8551 DOC: Changelog and THANKS for previous changes 2014-09-13 10:27:37 -04:00
Yaroslav Halchenko 0e1f8f7f39 RF: remove those two additional failregexes for the postfix
see comment
https://github.com/fail2ban/fail2ban/pull/804\#discussion_r17512426
2014-09-13 10:25:27 -04:00
Yaroslav Halchenko 96c20c8379 Merge pull request #804 from pleasantone/master
Add support for postfix/submission/smtpd matching.
2014-09-13 10:24:06 -04:00
Yaroslav Halchenko c58c4de9bc ENH: add empty ignoreregex to avoid a warning (Close #805) 2014-09-13 10:18:37 -04:00
Dean Lee ba44ff312b grep IP at the start of lines
I'm not sure if this regex works best, so I'm patching this single file as a sample.

Don't forget to update `mail-whois-lines.conf` after this patch got merged.

For the following logs, `grep '[^0-9]199.48.161.87[^0-9]'` will output nothing, while `grep '\([^0-9]\|^\)199.48.161.87[^0-9]'` works:
<pre>199.48.161.87 - - [09/Sep/2014:13:38:54 +0800] "POST /wp-login.php HTTP/1.1" 403 4674 "-" "Mozilla/5.0 (Windows NT 6.1; rv:5.0) Gecko/20100101 Firefox/5.0" - hitsjapan.com
199.48.161.87 - - [09/Sep/2014:13:38:56 +0800] "POST /wp-login.php HTTP/1.1" 403 4674 "-" "Mozilla/5.0 (Windows NT 6.1; rv:5.0) Gecko/20100101 Firefox/5.0" - hitsjapan.com
199.48.161.87 - - [09/Sep/2014:13:38:58 +0800] "POST /wp-login.php HTTP/1.1" 403 4674 "-" "Mozilla/5.0 (Windows NT 6.1; rv:5.0) Gecko/20100101 Firefox/5.0" - hitsjapan.com
199.48.161.87 - - [09/Sep/2014:13:39:00 +0800] "POST /wp-login.php HTTP/1.1" 403 4674 "-" "Mozilla/5.0 (Windows NT 6.1; rv:5.0) Gecko/20100101 Firefox/5.0" - hitsjapan.com
199.48.161.87 - - [09/Sep/2014:13:39:05 +0800] "POST /wp-login.php HTTP/1.1" 403 4674 "-" "Mozilla/5.0 (Windows NT 6.1; rv:5.0) Gecko/20100101 Firefox/5.0" - hitsjapan.com
199.48.161.87 - - [09/Sep/2014:13:39:05 +0800] "POST /wp-login.php HTTP/1.1" 403 4674 "-" "Mozilla/5.0 (Windows NT 6.1; rv:5.0) Gecko/20100101 Firefox/5.0" - hitsjapan.com
199.48.161.87 - - [09/Sep/2014:13:39:13 +0800] "POST /wp-login.php HTTP/1.1" 403 4674 "-" "Mozilla/5.0 (Windows NT 6.1; rv:5.0) Gecko/20100101 Firefox/5.0" - hitsjapan.com
199.48.161.87 - - [09/Sep/2014:13:39:21 +0800] "POST /wp-login.php HTTP/1.1" 403 4674 "-" "Mozilla/5.0 (Windows NT 6.1; rv:5.0) Gecko/20100101 Firefox/5.0" - hitsjapan.com
199.48.161.87 - - [09/Sep/2014:13:39:32 +0800] "POST /wp-login.php HTTP/1.1" 403 4674 "-" "Mozilla/5.0 (Windows NT 6.1; rv:5.0) Gecko/20100101 Firefox/5.0" - hitsjapan.com
199.48.161.87 - - [09/Sep/2014:13:39:34 +0800] "POST /wp-login.php HTTP/1.1" 403 4674 "-" "Mozilla/5.0 (Windows NT 6.1; rv:5.0) Gecko/20100101 Firefox/5.0" - hitsjapan.com
199.48.161.87 - - [09/Sep/2014:13:39:34 +0800] "POST /wp-login.php HTTP/1.1" 403 168 "-" "Mozilla/5.0 (Windows NT 6.1; rv:5.0) Gecko/20100101 Firefox/5.0" - hitsjapan.com
199.48.161.87 - - [09/Sep/2014:13:39:34 +0800] "POST /wp-login.php HTTP/1.1" 403 168 "-" "Mozilla/5.0 (Windows NT 6.1; rv:5.0) Gecko/20100101 Firefox/5.0" - hitsjapan.com
199.48.161.87 - - [09/Sep/2014:13:39:35 +0800] "POST /wp-login.php HTTP/1.1" 403 168 "-" "Mozilla/5.0 (Windows NT 6.1; rv:5.0) Gecko/20100101 Firefox/5.0" - hitsjapan.com
199.48.161.87 - - [09/Sep/2014:13:39:35 +0800] "POST /wp-login.php HTTP/1.1" 403 168 "-" "Mozilla/5.0 (Windows NT 6.1; rv:5.0) Gecko/20100101 Firefox/5.0" - hitsjapan.com
199.48.161.87 - - [09/Sep/2014:13:39:35 +0800] "POST /wp-login.php HTTP/1.1" 403 168 "-" "Mozilla/5.0 (Windows NT 6.1; rv:5.0) Gecko/20100101 Firefox/5.0" - hitsjapan.com</pre>
2014-09-09 14:55:34 +08:00
Paul Traina 249e169d8e Update test cases and also suport smtps per request. 2014-09-08 11:53:51 -07:00
Paul Traina 544cfaff2c Add support for postfix/submission/smtpd matching. 2014-09-06 10:23:38 -07:00
Yaroslav Halchenko b1c04f5fa2 ENH: print rebans stats even if no "Failures" are logged, and reduce indentation in output 2014-08-13 23:37:17 -04:00
Yaroslav Halchenko decea64cf9 ENH: untabified and reindented entire script for sane formatting (no functional changes) 2014-08-13 23:28:03 -04:00
Yaroslav Halchenko 8b62353ab0 BF: logwatch -- fixing up regex for 'already banned' 2014-08-13 23:24:38 -04:00
Yaroslav Halchenko 3bd36ba40a Sample logfiles to test logwatch services script 2014-08-13 23:15:31 -04:00
Yaroslav Halchenko b0f26fa391 Adjusting fail2ban logwatch script to match lines from 0.9 as well
File itself includes additional log information about changes
2014-08-11 12:45:50 -04:00
131 changed files with 3068 additions and 972 deletions
+1
View File
@@ -9,3 +9,4 @@ htmlcov
*.bak
__pycache__
.vagrant/
.idea/
+11 -4
View File
@@ -8,14 +8,21 @@ python:
- "3.3"
- "3.4"
- "pypy"
- "pypy3"
before_install:
- if [[ $TRAVIS_PYTHON_VERSION == 2.7 ]]; then sudo apt-get update -qq; fi
- if [[ $TRAVIS_PYTHON_VERSION == 2.7 ]]; then travis_retry sudo apt-get update -qq; fi
install:
- pip install pyinotify
- if [[ $TRAVIS_PYTHON_VERSION == 2.7 ]]; then sudo apt-get install -qq python-gamin; cp /usr/share/pyshared/gamin.py /usr/lib/pyshared/python2.7/_gamin.so $VIRTUAL_ENV/lib/python2.7/site-packages/; fi
- if [[ $TRAVIS_PYTHON_VERSION == 2.7 ]]; then cd ..; pip install -q coveralls; cd -; fi
- travis_retry pip install pyinotify
- if [[ $TRAVIS_PYTHON_VERSION == 2* || $TRAVIS_PYTHON_VERSION == 'pypy' ]]; then travis_retry pip install dnspython; fi
- if [[ $TRAVIS_PYTHON_VERSION == 3* || $TRAVIS_PYTHON_VERSION == 'pypy3' ]]; then travis_retry pip install dnspython3; fi
- if [[ $TRAVIS_PYTHON_VERSION == 2.7 ]]; then travis_retry sudo apt-get install -qq python-gamin; cp /usr/share/pyshared/gamin.py /usr/lib/pyshared/python2.7/_gamin.so $VIRTUAL_ENV/lib/python2.7/site-packages/; fi
- if [[ $TRAVIS_PYTHON_VERSION == 2.7 ]]; then cd ..; travis_retry pip install -q coveralls; cd -; fi
# overcome buggy pypy
- if [[ $TRAVIS_PYTHON_VERSION == pypy ]] ; then dpkg --compare-versions $(pypy --version 2>&1 | awk '/PyPy/{print $2;}') ge 2.5.1 || { d=$PWD; cd /tmp; wget http://buildbot.pypy.org/nightly/trunk/pypy-c-jit-latest-linux64.tar.bz2; tar -xjvf pypy*bz2; cd pypy-*/bin/; export PATH=$PWD:$PATH; cd $d; } ; fi
script:
- if [[ $TRAVIS_PYTHON_VERSION == 2.7 ]]; then coverage run --rcfile=.travis_coveragerc setup.py test; else python setup.py test; fi
# test installation
- sudo python setup.py install
after_success:
# Coverage config file must be .coveragerc for coveralls
- if [[ $TRAVIS_PYTHON_VERSION == 2.7 ]]; then cp -v .travis_coveragerc .coveragerc; fi
-181
View File
@@ -1,181 +0,0 @@
#!/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:
+10
View File
@@ -15,3 +15,13 @@ join the [mailing list](https://lists.sourceforge.net/lists/listinfo/fail2ban-us
### You would like to contribute (new filters/actions/code/documentation)?
send a [pull request](https://github.com/fail2ban/fail2ban/pulls)
Pull requests guidelines
========================
- If there is an issue on github to be closed by the pull request, include
```Closes #ISSUE``` (where ISSUE is issue's number)
- Add a brief summary of the change to the ChangeLog file into a corresponding
section out of Fixes, New Features or Enhancements (improvements to existing
features)
+98 -5
View File
@@ -3,11 +3,93 @@
| _/ _` | | |/ /| '_ \/ _` | ' \
|_| \__,_|_|_/___|_.__/\__,_|_||_|
================================================================================
Fail2Ban (version 0.9.0.dev) 2014/xx/xx
================================================================================
Fail2Ban: Changelog
===================
ver. 0.9.1 (2014/xx/xx) - better, faster, stronger
ver. 0.9.2 (2015/04/29) - better-quick-now-than-later
----------
- Fixes:
* Fix ufw action commands
* infinite busy loop on _escapedTags match in substituteRecursiveTags gh-907.
Thanks TonyThompson
* port[s] typo in jail.conf/nginx-http-auth gh-913. Thanks Frederik Wagner
(fnerdwq)
* $ typo in jail.conf. Thanks Skibbi. Debian bug #767255
* grep'ing for IP in *mail-whois-lines.conf should now match also
at the beginning and EOL. Thanks Dean Lee
* jail.conf
- php-url-fopen: separate logpath entries by newline
* failregex declared direct in jail was joined to single line (specifying of
multiple expressions was not possible).
* filters.d/exim.conf - cover different settings of exim logs
details. Thanks bes.internal
* filter.d/postfix-sasl.conf - failregex is now case insensitive
* filters.d/postfix.conf - add 'Client host rejected error message' failregex
* fail2ban/__init__.py - add strptime thread safety hack-around
* recidive uses iptables-allports banaction by default now.
Avoids problems with iptables versions not understanding 'all' for
protocols and ports
* filter.d/dovecot.conf
- match pam_authenticate line from EL7
- match unknown user line from EL7
* Use use_poll=True for Python 2.7 and >=3.4 to overcome "Bad file
descriptor" msgs issue (gh-161)
* filter.d/postfix-sasl.conf - tweak failregex and add ignoreregex to ignore
system authentication issues
* fail2ban-regex reads filter file(s) completely, incl. '.local' file etc.
(gh-954)
* firewallcmd-* actions: split output into separate lines for grepping (gh-908)
* Guard unicode encode/decode issues while storing records in the database.
Fixes "binding parameter error (unsupported type)" (gh-973), thanks to kot
for reporting
* filter.d/sshd added regex for matching openSUSE ssh authentication failure
* filter.d/asterisk.conf:
- Dropped "Sending fake auth rejection" failregex since it incorrectly
targets the asterisk server itself
- match "hacking attempt detected" logs
- New Features:
- New filters:
- postfix-rbl Thanks Lee Clemens
- apache-fakegooglebot.conf Thanks Lee Clemens
- nginx-botsearch Thanks Frantisek Sumsal
- drupal-auth Thanks Lee Clemens
- New recursive embedded substitution feature added:
- `<<PREF>HOST>` becomes `<IPV4HOST>` for PREF=`IPV4`;
- `<<PREF>HOST>` becomes `1.2.3.4` for PREF=`IPV4` and IPV4HOST=`1.2.3.4`;
- New interpolation feature for config readers - `%(known/parameter)s`.
(means last known option with name `parameter`). This interpolation makes
possible to extend a stock filter or jail regexp in .local file
(opposite to simply set failregex/ignoreregex that overwrites it),
see gh-867.
- Monit config for fail2ban in files/monit/
- New actions:
- action.d/firewallcmd-multiport and action.d/firewallcmd-allports Thanks Donald Yandt
- action.d/sendmail-geoip-lines.conf
- action.d/nsupdate to update DNSBL. Thanks Andrew St. Jean
- New status argument for fail2ban-client -- flavor:
fail2ban-client status <jail> [flavor]
- empty or "basic" works as-is
- "cymru" additionally prints (ASN, Country RIR) per banned IP
(requires dnspython or dnspython3)
- Flush log at USR1 signal
- Enhancements:
* Enable multiport for firewallcmd-new action. Closes gh-834
* files/debian-initd migrated from the debian branch and should be
suitable for manual installations now (thanks Juan Karlo de Guzman)
* Define empty ignoreregex in filters which didn't have it to avoid
warnings (gh-934)
* action.d/{sendmail-*,xarf-login-attack}.conf - report local
timezone not UTC time/zone. Closes gh-911
* Conditionally log Ignore IP with reason (dns, ip, command). Closes gh-916
* Absorbed DNSUtils.cidr into addr2bin in filter.py, added unittests
* Added syslogsocket configuration to fail2ban.conf
* Note in the jail.conf for the recidive jail to increase dbpurgeage (gh-964)
ver. 0.9.1 (2014/10/29) - better, faster, stronger
----------
- Refactoring (IMPORTANT -- Please review your setup and configuration):
@@ -16,6 +98,8 @@ ver. 0.9.1 (2014/xx/xx) - better, faster, stronger
provides defaults for the chain, port, protocol and name tags
- Fixes:
* start of file2ban aborted (on slow hosts, systemd considers the server has
been timed out and kills him), see gh-824
* 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
@@ -48,18 +132,26 @@ ver. 0.9.1 (2014/xx/xx) - better, faster, stronger
* 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-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
* Start performance of fail2ban-client (and tests) increased, start time
and cpu usage rapidly reduced. Introduced a shared storage logic, to
bypass reading lots of config files (see gh-824).
Thanks to Joost Molenaar for good catch (reported gh-820).
* 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
@@ -71,6 +163,7 @@ ver. 0.9.1 (2014/xx/xx) - better, faster, stronger
not affect SYSLOG output
* Log unhandled exceptions
* cyrus-imap: catch "user not found" attempts
* Add support for Portsentry
ver. 0.9.0 (2014/03/14) - beta
----------
+12
View File
@@ -81,6 +81,18 @@ some quick commands::
status test
Testing with vagrant
--------------------
Testing can now be done inside a vagrant VM. Vagrantfile provided in
source code repository established two VMs:
- VM "secure" which can be used for testing fail2ban code.
- VM "attacker" which hcan be used to perform attack against our "secure" VM.
Both VMs are sharing the 192.168.200/24 network. If you are using this network
take a look into the Vagrantfile and change the IP.
Coding Standards
================
+283 -232
View File
@@ -1,122 +1,272 @@
README.md
README.Solaris
ChangeLog
TODO
THANKS
CONTRIBUTING.md
COPYING
ChangeLog
DEVELOP
FILTERS
README.Solaris
README.md
RELEASE
THANKS
TODO
Vagrantfile
bin/fail2ban-client
bin/fail2ban-regex
bin/fail2ban-server
bin/fail2ban-testcases
config/action.d/apf.conf
config/action.d/badips.conf
config/action.d/badips.py
config/action.d/blocklist_de.conf
config/action.d/bsd-ipfw.conf
config/action.d/cloudflare.conf
config/action.d/complain.conf
config/action.d/dshield.conf
config/action.d/dummy.conf
config/action.d/firewallcmd-allports.conf
config/action.d/firewallcmd-ipset.conf
config/action.d/firewallcmd-multiport.conf
config/action.d/firewallcmd-new.conf
config/action.d/hostsdeny.conf
config/action.d/ipfilter.conf
config/action.d/ipfw.conf
config/action.d/iptables-allports.conf
config/action.d/iptables-common.conf
config/action.d/iptables-ipset-proto4.conf
config/action.d/iptables-ipset-proto6-allports.conf
config/action.d/iptables-ipset-proto6.conf
config/action.d/iptables-multiport-log.conf
config/action.d/iptables-multiport.conf
config/action.d/iptables-new.conf
config/action.d/iptables-xt_recent-echo.conf
config/action.d/iptables.conf
config/action.d/mail-buffered.conf
config/action.d/mail-whois-lines.conf
config/action.d/mail-whois.conf
config/action.d/mail.conf
config/action.d/mynetwatchman.conf
config/action.d/nsupdate.conf
config/action.d/nsupdate.conf
config/action.d/osx-afctl.conf
config/action.d/osx-ipfw.conf
config/action.d/pf.conf
config/action.d/route.conf
config/action.d/sendmail-buffered.conf
config/action.d/sendmail-common.conf
config/action.d/sendmail-geoip-lines.conf
config/action.d/sendmail-whois-ipjailmatches.conf
config/action.d/sendmail-whois-ipmatches.conf
config/action.d/sendmail-whois-lines.conf
config/action.d/sendmail-whois-matches.conf
config/action.d/sendmail-whois.conf
config/action.d/sendmail.conf
config/action.d/shorewall.conf
config/action.d/smtp.py
config/action.d/symbiosis-blacklist-allports.conf
config/action.d/ufw.conf
config/action.d/xarf-login-attack.conf
config/fail2ban.conf
config/filter.d/3proxy.conf
config/filter.d/apache-auth.conf
config/filter.d/apache-badbots.conf
config/filter.d/apache-botsearch.conf
config/filter.d/apache-common.conf
config/filter.d/apache-fakegooglebot.conf
config/filter.d/apache-modsecurity.conf
config/filter.d/apache-nohome.conf
config/filter.d/apache-noscript.conf
config/filter.d/apache-overflows.conf
config/filter.d/apache-shellshock.conf
config/filter.d/assp.conf
config/filter.d/asterisk.conf
config/filter.d/botsearch-common.conf
config/filter.d/common.conf
config/filter.d/counter-strike.conf
config/filter.d/courier-auth.conf
config/filter.d/courier-smtp.conf
config/filter.d/cyrus-imap.conf
config/filter.d/directadmin.conf
config/filter.d/dovecot.conf
config/filter.d/dropbear.conf
config/filter.d/ejabberd-auth.conf
config/filter.d/exim-common.conf
config/filter.d/exim-spam.conf
config/filter.d/exim.conf
config/filter.d/freeswitch.conf
config/filter.d/groupoffice.conf
config/filter.d/gssftpd.conf
config/filter.d/guacamole.conf
config/filter.d/horde.conf
config/filter.d/ignorecommands
config/filter.d/ignorecommands/apache-fakegooglebot
config/filter.d/kerio.conf
config/filter.d/lighttpd-auth.conf
config/filter.d/monit.conf
config/filter.d/mysqld-auth.conf
config/filter.d/nagios.conf
config/filter.d/named-refused.conf
config/filter.d/nginx-botsearch.conf
config/filter.d/nginx-http-auth.conf
config/filter.d/nsd.conf
config/filter.d/openwebmail.conf
config/filter.d/oracleims.conf
config/filter.d/pam-generic.conf
config/filter.d/pam-generic.conf
config/filter.d/pam-generic.conf
config/filter.d/perdition.conf
config/filter.d/php-url-fopen.conf
config/filter.d/php-url-fopen.conf
config/filter.d/php-url-fopen.conf
config/filter.d/portsentry.conf
config/filter.d/postfix-rbl.conf
config/filter.d/postfix-sasl.conf
config/filter.d/postfix-sasl.conf
config/filter.d/postfix-sasl.conf
config/filter.d/postfix.conf
config/filter.d/proftpd.conf
config/filter.d/pure-ftpd.conf
config/filter.d/qmail.conf
config/filter.d/recidive.conf
config/filter.d/roundcube-auth.conf
config/filter.d/selinux-common.conf
config/filter.d/selinux-ssh.conf
config/filter.d/sendmail-auth.conf
config/filter.d/sendmail-reject.conf
config/filter.d/sendmail-spam.conf
config/filter.d/sieve.conf
config/filter.d/sogo-auth.conf
config/filter.d/solid-pop3d.conf
config/filter.d/squid.conf
config/filter.d/squirrelmail.conf
config/filter.d/sshd-ddos.conf
config/filter.d/sshd.conf
config/filter.d/stunnel.conf
config/filter.d/suhosin.conf
config/filter.d/tine20.conf
config/filter.d/uwimap-auth.conf
config/filter.d/vsftpd.conf
config/filter.d/webmin-auth.conf
config/filter.d/wuftpd.conf
config/filter.d/xinetd-fail.conf
config/jail.conf
config/paths-common.conf
config/paths-debian.conf
config/paths-fedora.conf
config/paths-freebsd.conf
config/paths-osx.conf
doc/run-rootless.txt
fail2ban-2to3
fail2ban-testcases-all
fail2ban-testcases-all-python3
bin/fail2ban-client
bin/fail2ban-server
bin/fail2ban-testcases
bin/fail2ban-regex
doc/run-rootless.txt
fail2ban/client/configreader.py
fail2ban/client/configparserinc.py
fail2ban/client/jailreader.py
fail2ban/client/fail2banreader.py
fail2ban/client/jailsreader.py
fail2ban/client/beautifier.py
fail2ban/client/filterreader.py
fail2ban/client/actionreader.py
fail2ban/__init__.py
fail2ban/client/__init__.py
fail2ban/client/actionreader.py
fail2ban/client/beautifier.py
fail2ban/client/configparserinc.py
fail2ban/client/configreader.py
fail2ban/client/configurator.py
fail2ban/client/csocket.py
fail2ban/server/asyncserver.py
fail2ban/server/database.py
fail2ban/server/filter.py
fail2ban/server/filterpyinotify.py
fail2ban/server/filtergamin.py
fail2ban/server/filterpoll.py
fail2ban/server/filtersystemd.py
fail2ban/server/iso8601.py
fail2ban/server/server.py
fail2ban/client/fail2banreader.py
fail2ban/client/filterreader.py
fail2ban/client/jailreader.py
fail2ban/client/jailsreader.py
fail2ban/exceptions.py
fail2ban/helpers.py
fail2ban/protocol.py
fail2ban/server/__init__.py
fail2ban/server/action.py
fail2ban/server/actions.py
fail2ban/server/asyncserver.py
fail2ban/server/banmanager.py
fail2ban/server/database.py
fail2ban/server/datedetector.py
fail2ban/server/datetemplate.py
fail2ban/server/faildata.py
fail2ban/server/failmanager.py
fail2ban/server/datedetector.py
fail2ban/server/jailthread.py
fail2ban/server/transmitter.py
fail2ban/server/action.py
fail2ban/server/ticket.py
fail2ban/server/failregex.py
fail2ban/server/filter.py
fail2ban/server/filtergamin.py
fail2ban/server/filterpoll.py
fail2ban/server/filterpyinotify.py
fail2ban/server/filtersystemd.py
fail2ban/server/iso8601.py
fail2ban/server/jail.py
fail2ban/server/jails.py
fail2ban/server/__init__.py
fail2ban/server/banmanager.py
fail2ban/server/datetemplate.py
fail2ban/server/jailthread.py
fail2ban/server/mytime.py
fail2ban/server/failregex.py
fail2ban/server/database.py
fail2ban/tests/banmanagertestcase.py
fail2ban/tests/failmanagertestcase.py
fail2ban/tests/clientreadertestcase.py
fail2ban/tests/filtertestcase.py
fail2ban/server/server.py
fail2ban/server/strptime.py
fail2ban/server/ticket.py
fail2ban/server/transmitter.py
fail2ban/tests/__init__.py
fail2ban/tests/dummyjail.py
fail2ban/tests/samplestestcase.py
fail2ban/tests/datedetectortestcase.py
fail2ban/tests/action_d/__init__.py
fail2ban/tests/action_d/test_badips.py
fail2ban/tests/action_d/test_smtp.py
fail2ban/tests/actionstestcase.py
fail2ban/tests/actiontestcase.py
fail2ban/tests/servertestcase.py
fail2ban/tests/sockettestcase.py
fail2ban/tests/utils.py
fail2ban/tests/misctestcase.py
fail2ban/tests/databasetestcase.py
fail2ban/tests/config/jail.conf
fail2ban/tests/banmanagertestcase.py
fail2ban/tests/clientreadertestcase.py
fail2ban/tests/config/action.d/brokenaction.conf
fail2ban/tests/config/fail2ban.conf
fail2ban/tests/config/filter.d/simple.conf
fail2ban/tests/config/filter.d/test.conf
fail2ban/tests/config/filter.d/test.local
fail2ban/tests/config/jail.conf
fail2ban/tests/config/paths-common.conf
fail2ban/tests/config/paths-debian.conf
fail2ban/tests/config/paths-freebsd.conf
fail2ban/tests/config/paths-osx.conf
fail2ban/tests/config/paths-debian.conf
fail2ban/tests/config/filter.d/simple.conf
fail2ban/tests/config/action.d/brokenaction.conf
fail2ban/tests/files/config/apache-auth/digest/.htaccess
fail2ban/tests/files/config/apache-auth/digest/.htpasswd
fail2ban/tests/files/config/apache-auth/digest_time/.htaccess
fail2ban/tests/files/config/apache-auth/digest_time/.htpasswd
fail2ban/tests/databasetestcase.py
fail2ban/tests/datedetectortestcase.py
fail2ban/tests/dummyjail.py
fail2ban/tests/failmanagertestcase.py
fail2ban/tests/files/action.d/action.py
fail2ban/tests/files/action.d/action_checkainfo.py
fail2ban/tests/files/action.d/action_errors.py
fail2ban/tests/files/action.d/action_modifyainfo.py
fail2ban/tests/files/action.d/action_noAction.py
fail2ban/tests/files/action.d/action_nomethod.py
fail2ban/tests/files/config/apache-auth/README
fail2ban/tests/files/config/apache-auth/basic/authz_owner/.htaccess
fail2ban/tests/files/config/apache-auth/basic/authz_owner/cant_get_me.html
fail2ban/tests/files/config/apache-auth/basic/authz_owner/.htpasswd
fail2ban/tests/files/config/apache-auth/basic/authz_owner/cant_get_me.html
fail2ban/tests/files/config/apache-auth/basic/file/.htaccess
fail2ban/tests/files/config/apache-auth/basic/file/.htpasswd
fail2ban/tests/files/config/apache-auth/digest.py
fail2ban/tests/files/config/apache-auth/digest_wrongrelm/.htaccess
fail2ban/tests/files/config/apache-auth/digest_wrongrelm/.htpasswd
fail2ban/tests/files/config/apache-auth/digest/.htaccess
fail2ban/tests/files/config/apache-auth/digest/.htpasswd
fail2ban/tests/files/config/apache-auth/digest_anon/.htaccess
fail2ban/tests/files/config/apache-auth/digest_anon/.htpasswd
fail2ban/tests/files/config/apache-auth/README
fail2ban/tests/files/config/apache-auth/digest_time/.htaccess
fail2ban/tests/files/config/apache-auth/digest_time/.htpasswd
fail2ban/tests/files/config/apache-auth/digest_wrongrelm/.htaccess
fail2ban/tests/files/config/apache-auth/digest_wrongrelm/.htpasswd
fail2ban/tests/files/config/apache-auth/noentry/.htaccess
fail2ban/tests/files/database_v1.db
fail2ban/tests/files/ignorecommand.py
fail2ban/tests/files/filter.d/substition.conf
fail2ban/tests/files/filter.d/testcase-common.conf
fail2ban/tests/files/filter.d/testcase01.conf
fail2ban/tests/files/testcase01.log
fail2ban/tests/files/testcase02.log
fail2ban/tests/files/testcase03.log
fail2ban/tests/files/testcase04.log
fail2ban/tests/files/testcase-usedns.log
fail2ban/tests/files/testcase-journal.log
fail2ban/tests/files/testcase-multiline.log
fail2ban/tests/files/logs/bsd/syslog-plain.txt
fail2ban/tests/files/logs/bsd/syslog-v.txt
fail2ban/tests/files/logs/bsd/syslog-vv.txt
fail2ban/tests/files/ignorecommand.py
fail2ban/tests/files/logs/3proxy
fail2ban/tests/files/logs/apache-auth
fail2ban/tests/files/logs/apache-badbots
fail2ban/tests/files/logs/apache-botscripts
fail2ban/tests/files/logs/apache-botsearch
fail2ban/tests/files/logs/apache-fakegooglebot
fail2ban/tests/files/logs/apache-modsecurity
fail2ban/tests/files/logs/apache-nohome
fail2ban/tests/files/logs/apache-noscript
fail2ban/tests/files/logs/apache-overflows
fail2ban/tests/files/logs/apache-shellshock
fail2ban/tests/files/logs/assp
fail2ban/tests/files/logs/asterisk
fail2ban/tests/files/logs/bsd/syslog-plain.txt
fail2ban/tests/files/logs/bsd/syslog-v.txt
fail2ban/tests/files/logs/bsd/syslog-vv.txt
fail2ban/tests/files/logs/counter-strike
fail2ban/tests/files/logs/courier-auth
fail2ban/tests/files/logs/courier-smtp
fail2ban/tests/files/logs/cyrus-imap
fail2ban/tests/files/logs/directadmin
fail2ban/tests/files/logs/dovecot
fail2ban/tests/files/logs/dropbear
fail2ban/tests/files/logs/ejabberd-auth
@@ -126,193 +276,94 @@ fail2ban/tests/files/logs/freeswitch
fail2ban/tests/files/logs/groupoffice
fail2ban/tests/files/logs/gssftpd
fail2ban/tests/files/logs/guacamole
fail2ban/tests/files/logs/horde
fail2ban/tests/files/logs/kerio
fail2ban/tests/files/logs/lighttpd-auth
fail2ban/tests/files/logs/monit
fail2ban/tests/files/logs/mysqld-auth
fail2ban/tests/files/logs/nagios
fail2ban/tests/files/logs/named-refused
fail2ban/tests/files/logs/nginx-botsearch
fail2ban/tests/files/logs/nginx-http-auth
fail2ban/tests/files/logs/nsd
fail2ban/tests/files/logs/openwebmail
fail2ban/tests/files/logs/oracleims
fail2ban/tests/files/logs/pam-generic
fail2ban/tests/files/logs/perdition
fail2ban/tests/files/logs/php-url-fopen
fail2ban/tests/files/logs/postfix-sasl
fail2ban/tests/files/logs/named-refused
fail2ban/tests/files/logs/nginx-http-auth
fail2ban/tests/files/logs/pam-generic
fail2ban/tests/files/logs/portsentry
fail2ban/tests/files/logs/postfix
fail2ban/tests/files/logs/postfix-rbl
fail2ban/tests/files/logs/postfix-sasl
fail2ban/tests/files/logs/proftpd
fail2ban/tests/files/logs/pure-ftpd
fail2ban/tests/files/logs/qmail
fail2ban/tests/files/logs/recidive
fail2ban/tests/files/logs/roundcube-auth
fail2ban/tests/files/logs/selinux-ssh
fail2ban/tests/files/logs/sendmail-auth
fail2ban/tests/files/logs/sendmail-reject
fail2ban/tests/files/logs/sendmail-spam
fail2ban/tests/files/logs/sieve
fail2ban/tests/files/logs/squid
fail2ban/tests/files/logs/stunnel
fail2ban/tests/files/logs/suhosin
fail2ban/tests/files/logs/sogo-auth
fail2ban/tests/files/logs/solid-pop3d
fail2ban/tests/files/logs/squid
fail2ban/tests/files/logs/squirrelmail
fail2ban/tests/files/logs/sshd
fail2ban/tests/files/logs/sshd-ddos
fail2ban/tests/files/logs/stunnel
fail2ban/tests/files/logs/suhosin
fail2ban/tests/files/logs/tine20
fail2ban/tests/files/logs/uwimap-auth
fail2ban/tests/files/logs/vsftpd
fail2ban/tests/files/logs/webmin-auth
fail2ban/tests/files/logs/wuftpd
fail2ban/tests/files/logs/uwimap-auth
fail2ban/tests/files/logs/xinetd-fail
fail2ban/tests/config/jail.conf
fail2ban/tests/config/fail2ban.conf
fail2ban/tests/config/filter.d/simple.conf
fail2ban/tests/config/action.d/brokenaction.conf
setup.py
setup.cfg
fail2ban/__init__.py
fail2ban/exceptions.py
fail2ban/helpers.py
fail2ban/tests/files/testcase-journal.log
fail2ban/tests/files/testcase-multiline.log
fail2ban/tests/files/testcase-usedns.log
fail2ban/tests/files/testcase01.log
fail2ban/tests/files/testcase02.log
fail2ban/tests/files/testcase03.log
fail2ban/tests/files/testcase04.log
fail2ban/tests/filtertestcase.py
fail2ban/tests/misctestcase.py
fail2ban/tests/samplestestcase.py
fail2ban/tests/servertestcase.py
fail2ban/tests/sockettestcase.py
fail2ban/tests/utils.py
fail2ban/version.py
fail2ban/protocol.py
setup.py
setup.cfg
kill-server
config/jail.conf
config/fail2ban.conf
config/filter.d/common.conf
config/filter.d/apache-auth.conf
config/filter.d/apache-badbots.conf
config/filter.d/apache-botsearch.conf
config/filter.d/apache-modsecurity.conf
config/filter.d/apache-nohome.conf
config/filter.d/apache-noscript.conf
config/filter.d/apache-overflows.conf
config/filter.d/nginx-http-auth.conf
config/filter.d/counter-strike.conf
config/filter.d/courier-auth.conf
config/filter.d/courier-smtp.conf
config/filter.d/cyrus-imap.conf
config/filter.d/ejabberd-auth.conf
config/filter.d/exim.conf
config/filter.d/freeswitch.conf
config/filter.d/gssftpd.conf
config/filter.d/kerio.conf
config/filter.d/horde.conf
config/filter.d/suhosin.conf
config/filter.d/nagios.conf
config/filter.d/named-refused.conf
config/filter.d/nsd.conf
config/filter.d/openwebmail.conf
config/filter.d/pam-generic.conf
config/filter.d/php-url-fopen.conf
config/filter.d/postfix-sasl.conf
config/filter.d/pam-generic.conf
config/filter.d/php-url-fopen.conf
config/filter.d/postfix-sasl.conf
config/filter.d/postfix.conf
config/filter.d/proftpd.conf
config/filter.d/pure-ftpd.conf
config/filter.d/qmail.conf
config/filter.d/pam-generic.conf
config/filter.d/php-url-fopen.conf
config/filter.d/postfix-sasl.conf
config/filter.d/sendmail-auth.conf
config/filter.d/sendmail-reject.conf
config/filter.d/sieve.conf
config/filter.d/solid-pop3d.conf
config/filter.d/squid.conf
config/filter.d/sshd.conf
config/filter.d/sshd-ddos.conf
config/filter.d/stunnel.conf
config/filter.d/vsftpd.conf
config/filter.d/webmin-auth.conf
config/filter.d/wuftpd.conf
config/filter.d/xinetd-fail.conf
config/filter.d/asterisk.conf
config/filter.d/dovecot.conf
config/filter.d/dropbear.conf
config/filter.d/lighttpd-auth.conf
config/filter.d/recidive.conf
config/filter.d/roundcube-auth.conf
config/filter.d/assp.conf
config/filter.d/sogo-auth.conf
config/filter.d/mysqld-auth.conf
config/filter.d/selinux-common.conf
config/filter.d/selinux-ssh.conf
config/filter.d/3proxy.conf
config/filter.d/apache-common.conf
config/filter.d/exim-common.conf
config/filter.d/exim-spam.conf
config/filter.d/freeswitch.conf
config/filter.d/groupoffice.conf
config/filter.d/perdition.conf
config/filter.d/uwimap-auth.conf
config/filter.d/courier-auth.conf
config/filter.d/courier-smtp.conf
config/filter.d/ejabberd-auth.conf
config/filter.d/guacamole.conf
config/filter.d/sendmail-spam.conf
config/action.d/apf.conf
config/action.d/blocklist_de.conf
config/action.d/osx-afctl.conf
config/action.d/osx-ipfw.conf
config/action.d/sendmail-common.conf
config/action.d/badips.conf
config/action.d/bsd-ipfw.conf
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-common.conf
config/action.d/iptables-ipset-proto4.conf
config/action.d/iptables-ipset-proto6.conf
config/action.d/iptables-xt_recent-echo.conf
config/action.d/route.conf
config/action.d/complain.conf
config/action.d/dshield.conf
config/action.d/hostsdeny.conf
config/action.d/ipfw.conf
config/action.d/ipfilter.conf
config/action.d/iptables.conf
config/action.d/iptables-allports.conf
config/action.d/iptables-multiport.conf
config/action.d/iptables-multiport-log.conf
config/action.d/iptables-new.conf
config/action.d/mail.conf
config/action.d/mail-buffered.conf
config/action.d/mail-whois.conf
config/action.d/mail-whois-lines.conf
config/action.d/mynetwatchman.conf
config/action.d/pf.conf
config/action.d/sendmail.conf
config/action.d/sendmail-buffered.conf
config/action.d/sendmail-whois-ipmatches.conf
config/action.d/sendmail-whois.conf
config/action.d/sendmail-whois-lines.conf
config/action.d/shorewall.conf
config/action.d/xarf-login-attack.conf
config/action.d/ufw.conf
config/fail2ban.conf
doc/run-rootless.txt
man/fail2ban-client.1
man/fail2ban.1
man/jail.conf.5
man/fail2ban-client.h2m
man/fail2ban-server.1
man/fail2ban-server.h2m
man/fail2ban-regex.1
man/fail2ban-regex.h2m
man/generate-man
files/gentoo-initd
files/bash-completion
files/cacti/README
files/cacti/cacti_host_template_fail2ban.xml
files/cacti/fail2ban_stats.sh
files/debian-initd
files/fail2ban-logrotate
files/fail2ban-tmpfiles.conf
files/fail2ban.service
files/fail2ban.upstart
files/gen_badbots
files/gentoo-confd
files/redhat-initd
files/gentoo-initd
files/ipmasq-ZZZzzz_fail2ban.rul
files/logwatch/fail2ban
files/macosx-initd
files/monit/fail2ban
files/nagios/README
files/nagios/check_fail2ban
files/redhat-initd
files/solaris-fail2ban.xml
files/solaris-svc-fail2ban
files/suse-initd
files/fail2ban-logrotate
files/cacti/fail2ban_stats.sh
files/cacti/cacti_host_template_fail2ban.xml
files/cacti/README
files/nagios/check_fail2ban
files/nagios/README
files/bash-completion
files/fail2ban-tmpfiles.conf
files/fail2ban.service
files/ipmasq-ZZZzzz_fail2ban.rul
files/gen_badbots
kill-server
man/fail2ban-client.1
man/fail2ban-client.h2m
man/fail2ban-regex.1
man/fail2ban-regex.h2m
man/fail2ban-server.1
man/fail2ban-server.h2m
man/fail2ban.1
man/generate-man
man/jail.conf.5
setup.cfg
setup.py
+2 -1
View File
@@ -1,4 +1,5 @@
include ChangeLog COPYING DEVELOP FILTERS README.* THANKS TODO
include ChangeLog COPYING DEVELOP FILTERS README.* THANKS TODO CONTRIBUTING* Vagrantfile
graft doc
graft files
recursive-include config *.conf *.py
recursive-include config/filter.d/ignorecommands *
+4 -3
View File
@@ -2,7 +2,7 @@
/ _|__ _(_) |_ ) |__ __ _ _ _
| _/ _` | | |/ /| '_ \/ _` | ' \
|_| \__,_|_|_/___|_.__/\__,_|_||_|
v0.9.0 2014/03/14
v0.9.2 2015/04/29
## Fail2Ban: ban hosts that cause multiple authentication errors
@@ -33,11 +33,12 @@ Optional:
- Linux >= 2.6.13
- [gamin >= 0.0.21](http://www.gnome.org/~veillard/gamin)
- [systemd >= 204](http://www.freedesktop.org/wiki/Software/systemd)
- [dnspython](http://www.dnspython.org/)
To install, just do:
tar xvfj fail2ban-0.9.0.tar.bz2
cd fail2ban-0.9.0
tar xvfj fail2ban-0.9.2.tar.bz2
cd fail2ban-0.9.2
python setup.py install
This will install Fail2Ban into the python library directory. The executable
+11 -7
View File
@@ -47,6 +47,10 @@ Preparation
* Ensure the MANIFEST is complete
ad-hoc bash script to run in a clean clone:
find -type f | grep -v -e '\.git' -e '/doc/' -e '\.travis' -e MANIFEST | sed -e 's,^\./,,g' | while read f; do grep -ne "^$f\$" MANIFEST >/dev/null || echo "$f" ; done
* Run::
python setup.py sdist
@@ -57,24 +61,24 @@ Preparation
* Which indicates that testcases/files/logs/mysqld.log has been moved or is a directory::
tar -C /tmp -jxf dist/fail2ban-0.9.0.tar.bz2
tar -C /tmp -jxf dist/fail2ban-0.9.2.tar.bz2
* clean up current direcory::
diff -rul --exclude \*.pyc . /tmp/fail2ban-0.9.0/
diff -rul --exclude \*.pyc . /tmp/fail2ban-0.9.2/
* Only differences should be files that you don't want distributed.
* Ensure the tests work from the tarball::
cd /tmp/fail2ban-0.9.0/ && export PYTHONPATH=`pwd` && bin/fail2ban-testcases
cd /tmp/fail2ban-0.9.2/ && 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'
git shortlog -sn 0.9.2.. | 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.
@@ -97,7 +101,7 @@ Preparation
* Tag the release by using a signed (and annotated) tag. Cut/paste
release ChangeLog entry as tag annotation::
git tag -s 0.9.1
git tag -s 0.9.2
Pre Release
===========
@@ -140,7 +144,7 @@ Pre Release
* https://bugs.mageia.org/buglist.cgi?quicksearch=fail2ban
* An potentially to the fail2ban-users email list.
* And potentially to the fail2ban-users email list.
* Wait for feedback from distributors
@@ -181,7 +185,7 @@ Post Release
Add the following to the top of the ChangeLog::
ver. 0.9.1 (2014/XX/XXX) - wanna-be-released
ver. 0.9.3 (2014/XX/XXX) - wanna-be-released
-----------
- Fixes:
+8
View File
@@ -6,6 +6,7 @@ the project. If you have been left off, please let us know
(preferably send a pull request on github with the "fix") and you will
be added
Aaron Brice
Adam Tkac
Adrien Clerc
ache
@@ -13,6 +14,7 @@ ag4ve (Shawn)
Alasdair D. Campbell
Amir Caspi
Amy
Andrew St. Jean
Andrey G. Grozin
Andy Fragen
Arturo 'Buanzo' Busleiman
@@ -26,16 +28,20 @@ Christian Rauch
Christophe Carles
Christoph Haas
Christos Psonis
craneworks
Cyril Jaquier
Daniel B. Cid
Daniel B.
Daniel Black
David Nutter
Derek Atkins
Donald Yandt
Eric Gerbier
Enrico Labedzki
Eugene Hopkinson (SlowRiot)
ftoppi
François Boulogne
Frantisek Sumsal
Frédéric
Georgiy Mernov
Guilhem Lettron
@@ -80,7 +86,9 @@ Michael Hanselmann
Mika (mkl)
Nick Munger
onorua
Orion Poplawski
Paul Marrapese
Paul Traina
Noel Butler
Patrick Börjesson
Pressy
+2 -2
View File
@@ -409,6 +409,7 @@ class Fail2banClient:
# TODO: get away from stew of return codes and exception
# handling -- handle via exceptions
try:
self.__configurator.Reload()
self.__configurator.readAll()
ret = self.__configurator.getOptions(jail)
self.__configurator.convertToProtocol()
@@ -418,12 +419,11 @@ class Fail2banClient:
ret = False
return ret
#@staticmethod
@staticmethod
def dumpConfig(cmd):
for c in cmd:
print c
return True
dumpConfig = staticmethod(dumpConfig)
class ServerExecutionException(Exception):
+41 -31
View File
@@ -220,6 +220,7 @@ class Fail2banRegex(object):
self._datepattern_set = False
self._journalmatch = None
self.share_config=dict()
self._filter = Filter(None)
self._ignoreregex = list()
self._failregex = list()
@@ -260,38 +261,47 @@ class Fail2banRegex(object):
def readRegex(self, value, regextype):
assert(regextype in ('fail', 'ignore'))
regex = regextype + 'regex'
if os.path.isfile(value):
print "Use %11s file : %s" % (regex, value)
reader = FilterReader(value, 'fail2ban-regex-jail', {})
reader.setBaseDir(None)
if reader.readexplicit():
reader.getOptions(None)
readercommands = reader.convert()
regex_values = [
RegexStat(m[3])
for m in filter(
lambda x: x[0] == 'set' and x[2] == "add%sregex" % regextype,
readercommands)]
# Read out and set possible value of maxlines
for command in readercommands:
if command[2] == "maxlines":
maxlines = int(command[3])
try:
self.setMaxLines(maxlines)
except ValueError:
print "ERROR: Invalid value for maxlines (%(maxlines)r) " \
"read from %(value)s" % locals()
return False
elif command[2] == 'addjournalmatch':
journalmatch = command[3]
self.setJournalMatch(shlex.split(journalmatch))
elif command[2] == 'datepattern':
datepattern = command[3]
self.setDatePattern(datepattern)
if os.path.isfile(value) or os.path.isfile(value + '.conf'):
if os.path.basename(os.path.dirname(value)) == 'filter.d':
## within filter.d folder - use standard loading algorithm to load filter completely (with .local etc.):
basedir = os.path.dirname(os.path.dirname(value))
value = os.path.splitext(os.path.basename(value))[0]
print "Use %11s filter file : %s, basedir: %s" % (regex, value, basedir)
reader = FilterReader(value, 'fail2ban-regex-jail', {}, share_config=self.share_config, basedir=basedir)
if not reader.read():
print "ERROR: failed to load filter %s" % value
return False
else:
print "ERROR: failed to read %s" % value
return False
## foreign file - readexplicit this file and includes if possible:
print "Use %11s file : %s" % (regex, value)
reader = FilterReader(value, 'fail2ban-regex-jail', {}, share_config=self.share_config)
reader.setBaseDir(None)
if not reader.readexplicit():
print "ERROR: failed to read %s" % value
return False
reader.getOptions(None)
readercommands = reader.convert()
regex_values = [
RegexStat(m[3])
for m in filter(
lambda x: x[0] == 'set' and x[2] == "add%sregex" % regextype,
readercommands)]
# Read out and set possible value of maxlines
for command in readercommands:
if command[2] == "maxlines":
maxlines = int(command[3])
try:
self.setMaxLines(maxlines)
except ValueError:
print "ERROR: Invalid value for maxlines (%(maxlines)r) " \
"read from %(value)s" % locals()
return False
elif command[2] == 'addjournalmatch':
journalmatch = command[3]
self.setJournalMatch(shlex.split(journalmatch))
elif command[2] == 'datepattern':
datepattern = command[3]
self.setDatePattern(datepattern)
else:
print "Use %11s line : %s" % (regex, shortstr(value))
regex_values = [RegexStat(value)]
+9 -1
View File
@@ -111,6 +111,8 @@ class BadIPsAction(ActionBase):
------
HTTPError
Any issues with badips.com request.
ValueError
If badips.com response didn't contain necessary information
"""
try:
response = urlopen(
@@ -122,7 +124,13 @@ class BadIPsAction(ActionBase):
messages['err'])
raise
else:
categories = json.loads(response.read().decode('utf-8'))['categories']
response_json = json.loads(response.read().decode('utf-8'))
if not 'categories' in response_json:
err = "badips.com response lacked categories specification. Response was: %s" \
% (response_json,)
self._logSys.error(err)
raise ValueError(err)
categories = response_json['categories']
categories_names = set(
value['Name'] for value in categories)
if incParents:
+2 -2
View File
@@ -38,7 +38,7 @@ actioncheck =
# Values: CMD
#
# requires an ipfw rule like "deny ip from table(1) to me"
actionban = ipfw table <table> add <ip>
actionban = e=`ipfw table <table> add <ip> 2>&1`; x=$?; [ $x -eq 0 -o "$e" = 'ipfw: setsockopt(IP_FW_TABLE_XADD): File exists' ] || { echo "$e" 1>&2; exit $x; }
# Option: actionunban
@@ -47,7 +47,7 @@ actionban = ipfw table <table> add <ip>
# Tags: See jail.conf(5) man page
# Values: CMD
#
actionunban = ipfw table <table> delete <ip>
actionunban = e=`ipfw table <table> delete <ip> 2>&1`; x=$?; [ $x -eq 0 -o "$e" = 'ipfw: setsockopt(IP_FW_TABLE_XDEL): No such process' ] || { echo "$e" 1>&2; exit $x; }
[Init]
# Option: table
+53
View File
@@ -0,0 +1,53 @@
# Fail2Ban configuration file
#
# Author: Donald Yandt
# Because of the --remove-rules in stop this action requires firewalld-0.3.8+
[INCLUDES]
before = iptables-blocktype.conf
[Definition]
actionstart = firewall-cmd --direct --add-chain ipv4 filter f2b-<name>
firewall-cmd --direct --add-rule ipv4 filter f2b-<name> 1000 -j RETURN
firewall-cmd --direct --add-rule ipv4 filter <chain> 0 -j f2b-<name>
actionstop = firewall-cmd --direct --remove-rule ipv4 filter <chain> 0 -j f2b-<name>
firewall-cmd --direct --remove-rules ipv4 filter f2b-<name>
firewall-cmd --direct --remove-chain ipv4 filter f2b-<name>
# Example actioncheck: firewall-cmd --direct --get-chains ipv4 filter | sed -e 's, ,\n,g' | grep -q '^f2b-recidive$'
actioncheck = firewall-cmd --direct --get-chains ipv4 filter | sed -e 's, ,\n,g' | grep -q '^f2b-<name>$'
actionban = firewall-cmd --direct --add-rule ipv4 filter f2b-<name> 0 -s <ip> -j <blocktype>
actionunban = firewall-cmd --direct --remove-rule ipv4 filter f2b-<name> 0 -s <ip> -j <blocktype>
[Init]
# Default name of the chain
#
name = default
chain = INPUT_direct
# DEV NOTES:
#
# Author: Donald Yandt
# Uses "FirewallD" instead of the "iptables daemon".
#
#
# Output:
# actionstart:
# $ firewall-cmd --direct --add-chain ipv4 filter f2b-recidive
# success
# $ firewall-cmd --direct --add-rule ipv4 filter f2b-recidive 1000 -j RETURN
# success
# $ sudo firewall-cmd --direct --add-rule ipv4 filter INPUT_direct 0 -j f2b-recidive
# success
@@ -0,0 +1,63 @@
# Fail2Ban configuration file
#
# Author: Donald Yandt
# Because of the --remove-rules in stop this action requires firewalld-0.3.8+
[INCLUDES]
before = iptables-blocktype.conf
[Definition]
actionstart = firewall-cmd --direct --add-chain ipv4 filter f2b-<name>
firewall-cmd --direct --add-rule ipv4 filter f2b-<name> 1000 -j RETURN
firewall-cmd --direct --add-rule ipv4 filter <chain> 0 -m state --state NEW -p <protocol> -m multiport --dports <port> -j f2b-<name>
actionstop = firewall-cmd --direct --remove-rule ipv4 filter <chain> 0 -m state --state NEW -p <protocol> -m multiport --dports <port> -j f2b-<name>
firewall-cmd --direct --remove-rules ipv4 filter f2b-<name>
firewall-cmd --direct --remove-chain ipv4 filter f2b-<name>
# Example actioncheck: firewall-cmd --direct --get-chains ipv4 filter | sed -e 's, ,\n,g' | grep -q '^f2b-apache-modsecurity$'
actioncheck = firewall-cmd --direct --get-chains ipv4 filter | sed -e 's, ,\n,g' | grep -q '^f2b-<name>$'
actionban = firewall-cmd --direct --add-rule ipv4 filter f2b-<name> 0 -s <ip> -j <blocktype>
actionunban = firewall-cmd --direct --remove-rule ipv4 filter f2b-<name> 0 -s <ip> -j <blocktype>
[Init]
# Default name of the chain
name = default
chain = INPUT_direct
# Could also use port numbers separated by a comma.
port = 1:65535
# Option: protocol
# Values: [ tcp | udp | icmp | all ]
protocol = tcp
# DEV NOTES:
#
# Author: Donald Yandt
# Uses "FirewallD" instead of the "iptables daemon".
#
#
# Output:
# actionstart:
# $ firewall-cmd --direct --add-chain ipv4 filter f2b-apache-modsecurity
# success
# $ firewall-cmd --direct --add-rule ipv4 filter f2b-apache-modsecurity 1000 -j RETURN
# success
# $ sudo firewall-cmd --direct --add-rule ipv4 filter INPUT_direct 0 -m state --state NEW -p tcp -m multiport --dports 80,443 -j f2b-apache-modsecurity
# success
# actioncheck:
# $ firewall-cmd --direct --get-chains ipv4 filter f2b-apache-modsecurity | sed -e 's, ,\n,g' | grep -q '^f2b-apache-modsecurity$'
# f2b-apache-modsecurity
+3 -3
View File
@@ -10,9 +10,9 @@ before = iptables-common.conf
actionstart = firewall-cmd --direct --add-chain ipv4 filter f2b-<name>
firewall-cmd --direct --add-rule ipv4 filter f2b-<name> 1000 -j RETURN
firewall-cmd --direct --add-rule ipv4 filter <chain> 0 -m state --state NEW -p <protocol> --dport <port> -j f2b-<name>
firewall-cmd --direct --add-rule ipv4 filter <chain> 0 -m state --state NEW -p <protocol> -m multiport --dports <port> -j f2b-<name>
actionstop = firewall-cmd --direct --remove-rule ipv4 filter <chain> 0 -m state --state NEW -p <protocol> --dport <port> -j f2b-<name>
actionstop = firewall-cmd --direct --remove-rule ipv4 filter <chain> 0 -m state --state NEW -p <protocol> -m multiport --dports <port> -j f2b-<name>
firewall-cmd --direct --remove-rules ipv4 filter f2b-<name>
firewall-cmd --direct --remove-chain ipv4 filter f2b-<name>
@@ -43,7 +43,7 @@ chain = INPUT_direct
# success
# $ firewall-cmd --direct --add-rule ipv4 filter fail2ban-name 1000 -j RETURN
# success
# $ sudo firewall-cmd --direct --add-rule ipv4 filter INPUT_direct 0 -m state --state NEW -p tcp --dport 22 -j fail2ban-name
# $ sudo firewall-cmd --direct --add-rule ipv4 filter INPUT_direct 0 -m state --state NEW -p tcp -m multiport --dports 22 -j fail2ban-name
# success
# $ firewall-cmd --direct --get-chains ipv4 filter
# fail2ban-name
+1 -1
View File
@@ -42,7 +42,7 @@ actionban = printf %%b "Hi,\n
Here is more information about <ip>:\n
`whois <ip> || echo missing whois program`\n\n
Lines containing IP:<ip> in <logpath>\n
`grep '[^0-9]<ip>[^0-9]' <logpath>`\n\n
`grep -E '(^|[^0-9])<ip>([^0-9]|$)' <logpath>`\n\n
Regards,\n
Fail2Ban"|mail -s "[Fail2Ban] <name>: banned <ip> from `uname -n`" <dest>
+114
View File
@@ -0,0 +1,114 @@
# Fail2Ban configuration file
#
# Author: Andrew St. Jean
#
# Use nsupdate to perform dynamic DNS updates on a BIND zone file.
# One may want to do this to update a local RBL with banned IP addresses.
#
# Options
#
# domain DNS domain that will appear in nsupdate add and delete
# commands.
#
# ttl The time to live (TTL) in seconds of the TXT resource
# record.
#
# rdata Data portion of the TXT resource record.
#
# nsupdatecmd Full path to the nsupdate command.
#
# keyfile Full path to TSIG key file used for authentication between
# nsupdate and BIND.
#
# Create an nsupdate.local to set at least the <domain> and <keyfile>
# options as they don't have default values.
#
# The ban and unban commands assume nsupdate will authenticate to the BIND
# server using a TSIG key. The full path to the key file must be specified
# in the <keyfile> parameter. Use this command to generate your TSIG key.
#
# dnssec-keygen -a HMAC-MD5 -b 256 -n HOST <key_name>
#
# Replace <key_name> with some meaningful name.
#
# This command will generate two files. Specify the .private file in the
# <keyfile> option. Note that the .key file must also be present in the same
# directory for nsupdate to use the key.
#
# Don't forget to add the key and appropriate allow-update or update-policy
# option to your named.conf file.
#
[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: See jail.conf(5) man page
# Values: CMD
#
actionban = echo <ip> | awk -F. '{print "prereq nxrrset "$4"."$3"."$2"."$1".<domain> TXT"; print "update add "$4"."$3"."$2"."$1".<domain> <ttl> IN TXT \"<rdata>\""; print "send"}' | <nsupdatecmd> -k <keyfile>
# Option: actionunban
# Notes.: command executed when unbanning an IP. Take care that the
# command is executed with Fail2Ban user rights.
# Tags: See jail.conf(5) man page
# Values: CMD
#
actionunban = echo <ip> | awk -F. '{print "update delete "$4"."$3"."$2"."$1".<domain>"; print "send"}' | <nsupdatecmd> -k <keyfile>
[Init]
# Option: domain
# Notes.: DNS domain that nsupdate will update.
# Values: STRING
#
domain =
# Option: ttl
# Notes.: time to live (TTL) in seconds of TXT resource record
# added by nsupdate.
# Values: NUM
#
ttl = 60
# Option: rdata
# Notes.: data portion of the TXT resource record added by nsupdate.
# Values: STRING
#
rdata = Your IP has been banned
# Option: nsupdatecmd
# Notes.: specifies the full path to the nsupdate program that dynamically
# updates BIND zone files.
# Values: CMD
#
nsupdatecmd = /usr/bin/nsupdate
# Option: keyfile
# Notes.: specifies the full path to the file containing the
# TSIG key for communicating with BIND.
# Values: STRING
#
keyfile =
+2 -2
View File
@@ -15,7 +15,7 @@ after = sendmail-common.local
# Values: CMD
#
actionstart = printf %%b "Subject: [Fail2Ban] <name>: started on `uname -n`
Date: `LC_TIME=C date -u +"%%a, %%d %%h %%Y %%T +0000"`
Date: `LC_TIME=C date +"%%a, %%d %%h %%Y %%T %%z"`
From: <sendername> <<sender>>
To: <dest>\n
Hi,\n
@@ -28,7 +28,7 @@ actionstart = printf %%b "Subject: [Fail2Ban] <name>: started on `uname -n`
# Values: CMD
#
actionstop = printf %%b "Subject: [Fail2Ban] <name>: stopped on `uname -n`
Date: `LC_TIME=C date -u +"%%a, %%d %%h %%Y %%T +0000"`
Date: `LC_TIME=C date +"%%a, %%d %%h %%Y %%T %%z"`
From: <sendername> <<sender>>
To: <dest>\n
Hi,\n
+49
View File
@@ -0,0 +1,49 @@
# Fail2Ban configuration file
#
# Author: Viktor Szépe
#
#
[INCLUDES]
before = sendmail-common.conf
[Definition]
# Option: actionban
# Notes.: Command executed when banning an IP. Take care that the
# command is executed with Fail2Ban user rights.
# You need to install geoiplookup and the GeoLite or GeoIP databases.
# (geoip-bin and geoip-database in Debian)
# The host command comes from bind9-host package.
# Tags: See jail.conf(5) man page
# Values: CMD
#
actionban = printf %%b "Subject: [Fail2Ban] <name>: banned <ip> from `uname -n`
Date: `LC_TIME=C date +"%%a, %%d %%h %%Y %%T %%z"`
From: <sendername> <<sender>>
To: <dest>\n
Hi,\n
The IP <ip> has just been banned by Fail2Ban after
<failures> attempts against <name>.\n\n
Here is more information about <ip>:\n
http://bgp.he.net/ip/<ip>
http://www.projecthoneypot.org/ip_<ip>
http://whois.domaintools.com/<ip>\n\n
Country:`geoiplookup -f /usr/share/GeoIP/GeoIP.dat "<ip>" | cut -d':' -f2-`
AS:`geoiplookup -f /usr/share/GeoIP/GeoIPASNum.dat "<ip>" | cut -d':' -f2-`
hostname: `host -t A <ip> 2>&1`\n\n
Lines containing IP:<ip> in <logpath>\n
`grep -E '(^|[^0-9])<ip>([^0-9]|$)' <logpath>`\n\n
Regards,\n
Fail2Ban" | /usr/sbin/sendmail -f <sender> <dest>
[Init]
# Default name of the chain
#
name = default
# Path to the log files which contain relevant lines for the abuser IP
#
logpath = /dev/null
@@ -17,13 +17,13 @@ before = sendmail-common.conf
# Values: CMD
#
actionban = printf %%b "Subject: [Fail2Ban] <name>: banned <ip> from `uname -n`
Date: `LC_TIME=C date -u +"%%a, %%d %%h %%Y %%T +0000"`
Date: `LC_TIME=C date +"%%a, %%d %%h %%Y %%T %%z"`
From: <sendername> <<sender>>
To: <dest>\n
Hi,\n
The IP <ip> has just been banned by Fail2Ban after
<failures> attempts against <name>.\n\n
Here are more information about <ip>:\n
Here is more information about <ip>:\n
`/usr/bin/whois <ip>`\n\n
Matches for <name> with <ipjailfailures> failures IP:<ip>\n
<ipjailmatches>\n\n
@@ -17,13 +17,13 @@ before = sendmail-common.conf
# Values: CMD
#
actionban = printf %%b "Subject: [Fail2Ban] <name>: banned <ip> from `uname -n`
Date: `LC_TIME=C date -u +"%%a, %%d %%h %%Y %%T +0000"`
Date: `LC_TIME=C date +"%%a, %%d %%h %%Y %%T %%z"`
From: <sendername> <<sender>>
To: <dest>\n
Hi,\n
The IP <ip> has just been banned by Fail2Ban after
<failures> attempts against <name>.\n\n
Here are more information about <ip>:\n
Here is more information about <ip>:\n
`/usr/bin/whois <ip>`\n\n
Matches with <ipfailures> failures IP:<ip>\n
<ipmatches>\n\n
+2 -2
View File
@@ -17,7 +17,7 @@ before = sendmail-common.conf
# Values: CMD
#
actionban = printf %%b "Subject: [Fail2Ban] <name>: banned <ip> from `uname -n`
Date: `LC_TIME=C date -u +"%%a, %%d %%h %%Y %%T +0000"`
Date: `LC_TIME=C date +"%%a, %%d %%h %%Y %%T %%z"`
From: <sendername> <<sender>>
To: <dest>\n
Hi,\n
@@ -26,7 +26,7 @@ actionban = printf %%b "Subject: [Fail2Ban] <name>: banned <ip> from `uname -n`
Here is more information about <ip>:\n
`/usr/bin/whois <ip> || echo missing whois program`\n\n
Lines containing IP:<ip> in <logpath>\n
`grep '[^0-9]<ip>[^0-9]' <logpath>`\n\n
`grep -E '(^|[^0-9])<ip>([^0-9]|$)' <logpath>`\n\n
Regards,\n
Fail2Ban" | /usr/sbin/sendmail -f <sender> <dest>
+2 -2
View File
@@ -17,13 +17,13 @@ before = sendmail-common.conf
# Values: CMD
#
actionban = printf %%b "Subject: [Fail2Ban] <name>: banned <ip> from `uname -n`
Date: `LC_TIME=C date -u +"%%a, %%d %%h %%Y %%T +0000"`
Date: `LC_TIME=C date +"%%a, %%d %%h %%Y %%T %%z"`
From: <sendername> <<sender>>
To: <dest>\n
Hi,\n
The IP <ip> has just been banned by Fail2Ban after
<failures> attempts against <name>.\n\n
Here are more information about <ip>:\n
Here is more information about <ip>:\n
`/usr/bin/whois <ip>`\n\n
Matches:\n
<matches>\n\n
+1 -1
View File
@@ -17,7 +17,7 @@ before = sendmail-common.conf
# Values: CMD
#
actionban = printf %%b "Subject: [Fail2Ban] <name>: banned <ip> from `uname -n`
Date: `LC_TIME=C date -u +"%%a, %%d %%h %%Y %%T +0000"`
Date: `LC_TIME=C date +"%%a, %%d %%h %%Y %%T %%z"`
From: <sendername> <<sender>>
To: <dest>\n
Hi,\n
+1 -1
View File
@@ -17,7 +17,7 @@ before = sendmail-common.conf
# Values: CMD
#
actionban = printf %%b "Subject: [Fail2Ban] <name>: banned <ip> from `uname -n`
Date: `LC_TIME=C date -u +"%%a, %%d %%h %%Y %%T +0000"`
Date: `LC_TIME=C date +"%%a, %%d %%h %%Y %%T %%z"`
From: <sendername> <<sender>>
To: <dest>\n
Hi,\n
+4 -2
View File
@@ -13,9 +13,11 @@ actionstop =
actioncheck =
actionban = [ -n "<application>" ] && app="app <application>" ; ufw insert <insertpos> <blocktype> from <ip> to <destination> $app
actionban = [ -n "<application>" ] && app="app <application>"
ufw insert <insertpos> <blocktype> from <ip> to <destination> $app
actionunban = [ -n "<application>" ] && app="app <application>" ; ufw delete <blocktype> from <ip> to <destination> $app
actionunban = [ -n "<application>" ] && app="app <application>"
ufw delete <blocktype> from <ip> to <destination> $app
[Init]
# Option: insertpos
+1 -1
View File
@@ -46,7 +46,7 @@ actionban = oifs=${IFS}; IFS=.;SEP_IP=( <ip> ); set -- ${SEP_IP}; ADDRESSES=$(di
REPORTID=<time>@`uname -n`
TLP=<tlp>
PORT=<port>
DATE=`LC_TIME=C date -u --date=@<time> +"%%a, %%d %%h %%Y %%T +0000"`
DATE=`LC_TIME=C date --date=@<time> +"%%a, %%d %%h %%Y %%T %%z"`
if [ ! -z "$ADDRESSES" ]; then
(printf -- %%b "<header>\n<message>\n<report>\n";
date '+Note: Local timezone is %%z (%%Z)';
+6
View File
@@ -34,6 +34,12 @@ loglevel = INFO
#
logtarget = /var/log/fail2ban.log
# Option: syslogsocket
# Notes: Set the syslog socket file. Only used when logtarget is SYSLOG
# auto uses platform.system() to determine predefined paths
# Values: [ auto | FILE ] Default: auto
syslogsocket = auto
# Option: socket
# Notes.: Set the socket file. This is used to communicate with the daemon. Do
# not remove this file when Fail2ban runs. It will not be possible to
+1 -1
View File
@@ -10,7 +10,7 @@ before = apache-common.conf
[Definition]
failregex = ^%(_apache_error_client)s (AH01797: )?client denied by server configuration: (uri )?\S*(, referer: \S+)?\s*$
failregex = ^%(_apache_error_client)s (AH(01797|01630): )?client denied by server configuration: (uri )?\S*(, referer: \S+)?\s*$
^%(_apache_error_client)s (AH01617: )?user .*? authentication failure for "\S*": Password Mismatch(, referer: \S+)?$
^%(_apache_error_client)s (AH01618: )?user .*? not found(: )?\S*(, referer: \S+)?\s*$
^%(_apache_error_client)s (AH01614: )?client used wrong authentication scheme: \S*(, referer: \S+)?\s*$
+3 -11
View File
@@ -17,7 +17,9 @@
[INCLUDES]
# overwrite with apache-common.local if _apache_error_client is incorrect.
# Load regexes for filtering from botsearch-common.conf
before = apache-common.conf
botsearch-common.conf
[Definition]
@@ -31,18 +33,8 @@ ignoreregex =
# Webroot represents the webroot on which all other files are based
webroot = /var/www/
# Block is the actual non-found directories to block
block = (<webmail>|<phpmyadmin>|<wordpress>)[^,]*
# These are just convient definitions that assist the blocking of stuff that
# isn't installed
webmail = roundcube|(ext)?mail|horde|(v-?)?webmail
phpmyadmin = (typo3/|xampp/|admin/|)(pma|(php)?[Mm]y[Aa]dmin)
wordpress = wp-(login|signup)\.php
# DEV Notes:
#
# Author: Daniel Black
# Author: Daniel Black
+14
View File
@@ -0,0 +1,14 @@
# Fail2Ban filter for fake Googlebot User Agents
[Definition]
failregex = ^<HOST> .*Googlebot.*$
ignoreregex =
# DEV Notes:
#
# Author: Lee Clemens
# Thanks: Johannes B. Ullrich, Ph.D.
# Reference: https://isc.sans.edu/forums/diary/When+Google+isnt+Google/15968/
+26
View File
@@ -0,0 +1,26 @@
# Fail2Ban filter to block web requests containing custom headers attempting to exploit the shellshock bug
#
#
[INCLUDES]
# overwrite with apache-common.local if _apache_error_client is incorrect.
before = apache-common.conf
[Definition]
failregex = ^%(_apache_error_client)s (AH01215: )?/bin/(ba)?sh: warning: HTTP_.*?: ignoring function definition attempt(, referer: \S+)?\s*$
^%(_apache_error_client)s (AH01215: )?/bin/(ba)?sh: error importing function definition for `HTTP_.*?'(, referer: \S+)?\s*$
ignoreregex =
# DEV Notes:
#
# https://wiki.apache.org/httpd/ListOfErrors for apache error IDs
#
# example log lines:
# [Thu Sep 25 09:27:18.813902 2014] [cgi:error] [pid 16860] [client 89.207.132.76:59635] AH01215: /bin/bash: warning: HTTP_TEST: ignoring function definition attempt
# [Thu Sep 25 09:29:56.141832 2014] [cgi:error] [pid 16864] [client 162.247.73.206:41273] AH01215: /bin/bash: error importing function definition for `HTTP_TEST'
#
# Author: Eugene Hopkinson (riot@riot.so)
+1 -1
View File
@@ -22,7 +22,7 @@ failregex = ^(%(__prefix_line)s|\[\]\s*)%(log_prefix)s Registration from '[^']*'
^(%(__prefix_line)s|\[\]\s*)%(log_prefix)s No registration for peer '[^']*' \(from <HOST>\)$
^(%(__prefix_line)s|\[\]\s*)%(log_prefix)s Host <HOST> failed MD5 authentication for '[^']*' \([^)]+\)$
^(%(__prefix_line)s|\[\]\s*)%(log_prefix)s Failed to authenticate (user|device) [^@]+@<HOST>\S*$
^(%(__prefix_line)s|\[\]\s*)%(log_prefix)s (?:handle_request_subscribe: )?Sending fake auth rejection for (device|user) \d*<sip:[^@]+@<HOST>>;tag=\w+\S*$
^(%(__prefix_line)s|\[\]\s*)%(log_prefix)s hacking attempt detected '<HOST>'$
^(%(__prefix_line)s|\[\]\s*)%(log_prefix)s SecurityEvent="(FailedACL|InvalidAccountID|ChallengeResponseFailed|InvalidPassword)",EventTV="[\d-]+",Severity="[\w]+",Service="[\w]+",EventVersion="\d+",AccountID="\d*",SessionID="0x[\da-f]+",LocalAddress="IPV[46]/(UD|TC)P/[\da-fA-F:.]+/\d+",RemoteAddress="IPV[46]/(UD|TC)P/<HOST>/\d+"(,Challenge="\w+",ReceivedChallenge="\w+")?(,ReceivedHash="[\da-f]+")?(,ACLName="\w+")?$
^(%(__prefix_line)s|\[\]\s*WARNING%(__pid_re)s:?(?:\[C-[\da-f]*\])? )Ext\. s: "Rejecting unknown SIP connection from <HOST>"$
+19
View File
@@ -0,0 +1,19 @@
# Generic configuration file for -botsearch filters
[Init]
# Block is the actual non-found directories to block
block = \/?(<webmail>|<phpmyadmin>|<wordpress>|cgi-bin|mysqladmin)[^,]*
# These are just convient definitions that assist the blocking of stuff that
# isn't installed
webmail = roundcube|(ext)?mail|horde|(v-?)?webmail
phpmyadmin = (typo3/|xampp/|admin/|)(pma|(php)?[Mm]y[Aa]dmin)
wordpress = wp-(login|signup)\.php
# DEV Notes:
# Taken from apache-botsearch filter
#
# Author: Frantisek Sumsal
+4
View File
@@ -53,4 +53,8 @@ __bsd_syslog_verbose = (<[^.]+\.[^.]+>)
# This can be optional (for instance if we match named native log files)
__prefix_line = \s*%(__bsd_syslog_verbose)s?\s*(?:%(__hostname)s )?(?:%(__kernel_prefix)s )?(?:@vserver_\S+ )?%(__daemon_combs_re)s?\s%(__daemon_extra_re)s?\s*
# PAM authentication mechanism check for failures, e.g.: pam_unix, pam_sss,
# pam_ldap
__pam_auth = pam_unix
# Author: Yaroslav Halchenko
+1
View File
@@ -6,6 +6,7 @@
failregex = ^: Bad Rcon: "rcon \d+ "\S+" sv_contact ".*?"" from "<HOST>:\d+"$
ignoreregex =
[Init]
+3 -2
View File
@@ -9,9 +9,10 @@ before = common.conf
_daemon = (auth|dovecot(-auth)?|auth-worker)
failregex = ^%(__prefix_line)s(pam_unix(\(dovecot:auth\))?:)?\s+authentication failure; logname=\S* uid=\S* euid=\S* tty=dovecot ruser=\S* rhost=<HOST>(\s+user=\S*)?\s*$
failregex = ^%(__prefix_line)s(%(__pam_auth)s(\(dovecot:auth\))?:)?\s+authentication failure; logname=\S* uid=\S* euid=\S* tty=dovecot ruser=\S* rhost=<HOST>(\s+user=\S*)?\s*$
^%(__prefix_line)s(pop3|imap)-login: (Info: )?(Aborted login|Disconnected)(: Inactivity)? \(((auth failed, \d+ attempts)( in \d+ secs)?|tried to use (disabled|disallowed) \S+ auth)\):( user=<\S*>,)?( method=\S+,)? rip=<HOST>(, lip=(\d{1,3}\.){3}\d{1,3})?(, TLS( handshaking(: SSL_accept\(\) failed: error:[\dA-F]+:SSL routines:[TLS\d]+_GET_CLIENT_HELLO:unknown protocol)?)?(: Disconnected)?)?(, session=<\S+>)?\s*$
^%(__prefix_line)s(Info|dovecot: auth\(default\)): pam\(\S+,<HOST>\): pam_authenticate\(\) failed: (User not known to the underlying authentication module: \d+ Time\(s\)|Authentication failure \(password mismatch\?\))\s*$
^%(__prefix_line)s(Info|dovecot: auth\(default\)|auth-worker\(\d+\)): pam\(\S+,<HOST>\): pam_authenticate\(\) failed: (User not known to the underlying authentication module: \d+ Time\(s\)|Authentication failure \(password mismatch\?\))\s*$
^%(__prefix_line)sauth-worker\(\d+\): pam\(\S+,<HOST>\): unknown user\s*$
ignoreregex =
+26
View File
@@ -0,0 +1,26 @@
# Fail2Ban filter to block repeated failed login attempts to Drupal site(s)
#
#
# Drupal must be setup to use Syslog, which defaults to the following format:
#
# !base_url|!timestamp|!type|!ip|!request_uri|!referer|!uid|!link|!message
#
#
[INCLUDES]
before = common.conf
[Definition]
failregex = ^%(__prefix_line)s(https?:\/\/)([\da-z\.-]+)\.([a-z\.]{2,6})(\/[\w\.-]+)*\|\d{10}\|user\|<HOST>\|.+\|.+\|\d\|.*\|Login attempt failed for .+\.$
ignoreregex =
# DEV Notes:
#
# https://www.drupal.org/documentation/modules/syslog
#
# Author: Lee Clemens
+2 -2
View File
@@ -14,10 +14,10 @@ before = exim-common.conf
[Definition]
failregex = ^%(pid)s %(host_info)ssender verify fail for <\S+>: (?:Unknown user|Unrouteable address|all relevant MX records point to non-existent hosts)\s*$
^%(pid)s \w+ authenticator failed for (\S+ )?\(\S+\) \[<HOST>\]: 535 Incorrect authentication data( \(set_id=.*\)|: \d+ Time\(s\))?\s*$
^%(pid)s \w+ authenticator failed for (\S+ )?\(\S+\) \[<HOST>\](:\d+)?( I=\[\S+\](:\d+)?)?: 535 Incorrect authentication data( \(set_id=.*\)|: \d+ Time\(s\))?\s*$
^%(pid)s %(host_info)sF=(<>|[^@]+@\S+) rejected RCPT [^@]+@\S+: (relay not permitted|Sender verify failed|Unknown user)\s*$
^%(pid)s SMTP protocol synchronization error \([^)]*\): rejected (connection from|"\S+") %(host_info)s(next )?input=".*"\s*$
^%(pid)s SMTP call from \S+ \[<HOST>\](:\d+)? (I=\[\S+\]:\d+ )?dropped: too many nonmail commands \(last was "\S+"\)\s*$
^%(pid)s SMTP call from \S+ \[<HOST>\](:\d+)? (I=\[\S+\](:\d+)? )?dropped: too many nonmail commands \(last was "\S+"\)\s*$
ignoreregex =
+1 -1
View File
@@ -8,7 +8,7 @@
failregex = ^\[\]LOGIN FAILED for user: "\S+" from IP: <HOST>$
ignoreregex =
# Author: Daniel Black
+32
View File
@@ -0,0 +1,32 @@
#!/usr/bin/python
# Inspired by https://isc.sans.edu/forums/diary/When+Google+isnt+Google/15968/
#
# Written in Python to reuse built-in Python batteries and not depend on
# presence of host and cut commands
#
import sys
def process_args(argv):
if len(argv) != 2:
sys.stderr.write("Please provide a single IP as an argument. Got: %s\n"
% (argv[1:]))
sys.exit(2)
ip = argv[1]
from fail2ban.server.filter import DNSUtils
if not DNSUtils.isValidIP(ip):
sys.stderr.write("Argument must be a single valid IP. Got: %s\n"
% ip)
sys.exit(3)
return ip
def is_googlebot(ip):
import re
from fail2ban.server.filter import DNSUtils
host = DNSUtils.ipToName(ip)
sys.exit(0 if (host and re.match('crawl-.*\.googlebot\.com', host)) else 1)
if __name__ == '__main__':
is_googlebot(process_args(sys.argv))
+3
View File
@@ -6,6 +6,9 @@ failregex = ^ SMTP Spam attack detected from <HOST>,
^ IP address <HOST> found in DNS blacklist \S+, mail from \S+ to \S+$
^ Relay attempt from IP address <HOST>
^ Attempt to deliver to unknown recipient \S+, from \S+, IP address <HOST>$
ignoreregex =
[Init]
datepattern = ^\[%%d/%%b/%%Y %%H:%%M:%%S\]
+1
View File
@@ -7,3 +7,4 @@
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$
ignoreregex =
+2
View File
@@ -38,6 +38,8 @@ failregex = ^%(__line_prefix)s( error:)?\s*client <HOST>#\S+( \([\S.]+\))?: (vie
^%(__line_prefix)s( error:)?\s*client <HOST>#\S+( \([\S.]+\))?: zone transfer '\S+/AXFR/\w+' denied\s*$
^%(__line_prefix)s( error:)?\s*client <HOST>#\S+( \([\S.]+\))?: bad zone transfer request: '\S+/IN': non-authoritative zone \(NOTAUTH\)\s*$
ignoreregex =
# DEV Notes:
# Trying to generalize the
# structure which is general to capture general patterns in log
+20
View File
@@ -0,0 +1,20 @@
# Fail2Ban filter to match web requests for selected URLs that don't exist
#
[INCLUDES]
# Load regexes for filtering
before = botsearch-common.conf
[Definition]
failregex = ^<HOST> \- \S+ \[\] \"(GET|POST) \/<block> \S+\" 404 .+$
^ \[error\] \d+#\d+: \*\d+ (\S+ )?\"\S+\" (failed|is not found) \(2\: No such file or directory\), client\: <HOST>\, server\: \S*\, request: \"(GET|POST) \/<block> \S+\"\, .*?$
ignoreregex =
# DEV Notes:
# Based on apache-botsearch filter
#
# Author: Frantisek Sumsal
+2
View File
@@ -24,3 +24,5 @@ _daemon = nsd
failregex = ^\[\]%(__prefix_line)sinfo: ratelimit block .* query <HOST> TYPE255$
^\[\]%(__prefix_line)sinfo: .* <HOST> refused, no acl matches\.$
ignoreregex =
+1 -1
View File
@@ -13,7 +13,7 @@ before = common.conf
# Default: catch all failed logins
_ttys_re=\S*
__pam_re=\(?pam_unix(?:\(\S+\))?\)?:?
__pam_re=\(?%(__pam_auth)s(?:\(\S+\))?\)?:?
_daemon = \S+
failregex = ^%(__prefix_line)s%(__pam_re)s\s+authentication failure; logname=\S* uid=\S* euid=\S* tty=%(_ttys_re)s ruser=\S* rhost=<HOST>(?:\s+user=.*)?\s*$
+12
View File
@@ -0,0 +1,12 @@
# Fail2Ban filter for failure attempts in Counter Strike-1.6
#
#
[Definition]
failregex = \/<HOST> Port\: [0-9]+ (TCP|UDP) Blocked$
ignoreregex =
# Author: Pacop <pacoparu@gmail.com>
+19
View File
@@ -0,0 +1,19 @@
# Fail2Ban filter for Postfix's RBL based Blocked hosts
#
#
[INCLUDES]
# Read common prefixes. If any customizations available -- read them from
# common.local
before = common.conf
[Definition]
_daemon = postfix/smtpd
failregex = ^%(__prefix_line)sNOQUEUE: reject: RCPT from \S+\[<HOST>\]: 454 4\.7\.1 Service unavailable; Client host \[\S+\] blocked using .* from=<\S*> to=<\S+> proto=ESMTP helo=<\S*>$
ignoreregex =
# Author: Lee Clemens
+4 -2
View File
@@ -7,9 +7,11 @@ before = common.conf
[Definition]
_daemon = postfix/smtpd
_daemon = postfix/(submission/)?smtp(d|s)
failregex = ^%(__prefix_line)swarning: [-._\w]+\[<HOST>\]: SASL (?:LOGIN|PLAIN|(?:CRAM|DIGEST)-MD5) authentication failed(: [ A-Za-z0-9+/]*={0,2})?\s*$
failregex = ^%(__prefix_line)swarning: [-._\w]+\[<HOST>\]: SASL ((?i)LOGIN|PLAIN|(?:CRAM|DIGEST)-MD5) authentication failed(: [ A-Za-z0-9+/:]*={0,2})?\s*$
ignoreregex = authentication failed: Connection lost to authentication server$
[Init]
+2 -1
View File
@@ -10,9 +10,10 @@ before = common.conf
[Definition]
_daemon = postfix/smtpd
_daemon = postfix/(submission/)?smtp(d|s)
failregex = ^%(__prefix_line)sNOQUEUE: reject: RCPT from \S+\[<HOST>\]: 554 5\.7\.1 .*$
^%(__prefix_line)sNOQUEUE: reject: RCPT from \S+\[<HOST>\]: 450 4\.7\.1 Client host rejected: cannot find your hostname, (\[\S*\]); from=<\S*> to=<\S+> proto=ESMTP helo=<\S*>$
^%(__prefix_line)sNOQUEUE: reject: RCPT from \S+\[<HOST>\]: 450 4\.7\.1 : Helo command rejected: Host not found; from=<> to=<> proto=ESMTP helo= *$
^%(__prefix_line)sNOQUEUE: reject: VRFY from \S+\[<HOST>\]: 550 5\.1\.1 .*$
^%(__prefix_line)simproper command pipelining after \S+ from [^[]*\[<HOST>\]:?$
+2
View File
@@ -29,6 +29,8 @@ _jailname = recidive
failregex = ^(%(__prefix_line)s| %(_daemon)s%(__pid_re)s?:\s+)NOTICE\s+\[(?!%(_jailname)s\])(?:.*)\]\s+Ban\s+<HOST>\s*$
ignoreregex =
[Init]
journalmatch = _SYSTEMD_UNIT=fail2ban.service PRIORITY=5
+1 -1
View File
@@ -7,7 +7,7 @@
failregex = ^\s+\d\s<HOST>\s+[A-Z_]+_DENIED/403 .*$
^\s+\d\s<HOST>\s+NONE/405 .*$
ignoreregex =
# Author: Daniel Black
+1
View File
@@ -3,6 +3,7 @@
failregex = ^ \[LOGIN_ERROR\].*from <HOST>: Unknown user or password incorrect\.$
ignoreregex =
[Init]
+1
View File
@@ -33,6 +33,7 @@ failregex = ^%(__prefix_line)s(?:error: PAM: )?[aA]uthentication (?:failure|erro
^(?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+(?: on \S+ port \d+)?<SKIPLINES>(?P=__prefix)Disconnecting: Too many authentication failures for .+? \[preauth\]$
^%(__prefix_line)spam_unix\(sshd:auth\):\s+authentication failure;\s*logname=\S*\s*uid=\d*\s*euid=\d*\s*tty=\S*\s*ruser=\S*\s*rhost=<HOST>\s.*$
ignoreregex =
+2
View File
@@ -4,6 +4,8 @@
failregex = ^ LOG\d\[\d+:\d+\]:\ SSL_accept from <HOST>:\d+ : (?P<CODE>[\dA-F]+): error:(?P=CODE):SSL routines:SSL3_GET_CLIENT_CERTIFICATE:peer did not return a certificate$
ignoreregex =
# DEV NOTES:
#
# Author: Daniel Black
+1 -1
View File
@@ -10,7 +10,7 @@ before = common.conf
[Definition]
__pam_re=\(?pam_unix(?:\(\S+\))?\)?:?
__pam_re=\(?%(__pam_auth)s(?:\(\S+\))?\)?:?
_daemon = vsftpd
failregex = ^%(__prefix_line)s%(__pam_re)s\s+authentication failure; logname=\S* uid=\S* euid=\S* tty=(ftp)? ruser=\S* rhost=<HOST>(?:\s+user=.*)?\s*$
+1 -1
View File
@@ -11,7 +11,7 @@ before = common.conf
[Definition]
_daemon = wu-ftpd
__pam_re=\(?pam_unix(?:\(wu-ftpd:auth\))?\)?:?
__pam_re=\(?%(__pam_auth)s(?:\(wu-ftpd:auth\))?\)?:?
failregex = ^%(__prefix_line)sfailed login from \S+ \[<HOST>\]\s*$
^%(__prefix_line)s%(__pam_re)s\s+authentication failure; logname=\S* uid=\S* euid=\S* tty=(ftp)? ruser=\S* rhost=<HOST>(?:\s+user=.*)?\s*$
+50 -8
View File
@@ -79,6 +79,11 @@ maxretry = 5
# See "journalmatch" in the jails associated filter config
# auto: will try to use the following backends, in order:
# pyinotify, gamin, polling.
#
# Note: if systemd backend is choses as the default but you enable a jail
# for which logs are present only in its own log files, specify some other
# backend for that jail (e.g. polling) and provide empty value for
# journalmatch. See https://github.com/fail2ban/fail2ban/issues/959#issuecomment-74901200
backend = auto
# "usedns" specifies if jails should trust hostnames in logs,
@@ -277,18 +282,36 @@ logpath = %(apache_error_log)s
maxretry = 2
[apache-fakegooglebot]
port = http,https
logpath = %(apache_access_log)s
maxretry = 1
ignorecommand = %(ignorecommands_dir)s/apache-fakegooglebot <ip>
[apache-modsecurity]
port = http,https
logpath = %(apache_error_log)s
maxretry = 2
[apache-shellshock]
port = http,https
logpath = %(apache_error_log)s
maxretry = 1
[nginx-http-auth]
ports = http,https
port = http,https
logpath = %(nginx_error_log)s
[nginx-botsearch]
port = http,https
logpath = %(nginx_error_log)s
maxretry = 2
# Ban attackers that try to use PHP's URL-fopen() functionality
# through GET/POST variables. - Experimental, with more than a year
@@ -297,7 +320,8 @@ logpath = %(nginx_error_log)s
[php-url-fopen]
port = http,https
logpath = %(nginx_access_log)s %(apache_access_log)s
logpath = %(nginx_access_log)s
%(apache_access_log)s
[suhosin]
@@ -361,6 +385,11 @@ maxretry = 5
#
#
[drupal-auth]
port = http,https
logpath = %(syslog_daemon)s
[guacamole]
port = http,https
@@ -459,6 +488,13 @@ port = smtp,465,submission
logpath = %(postfix_log)s
[postfix-rbl]
port = smtp,465,submission
logpath = %(syslog_mail)s
maxretry = 1
[sendmail-auth]
port = submission,465,smtp
@@ -643,15 +679,16 @@ maxretry = 5
# Jail for more extended banning of persistent abusers
# !!! WARNING !!!
# Make sure that your loglevel specified in fail2ban.conf/.local
# is not at DEBUG level -- which might then cause fail2ban to fall into
# an infinite loop constantly feeding itself with non-informative lines
# !!! WARNINGS !!!
# 1. Make sure that your loglevel specified in fail2ban.conf/.local
# is not at DEBUG level -- which might then cause fail2ban to fall into
# an infinite loop constantly feeding itself with non-informative lines
# 2. Increase dbpurgeage defined in fail2ban.conf to e.g. 648000 (7.5 days)
# to maintain entries for failed logins for sufficient amount of time
[recidive]
logpath = /var/log/fail2ban.log
port = all
protocol = all
banaction = iptables-allports
bantime = 604800 ; 1 week
findtime = 86400 ; 1 day
maxretry = 5
@@ -714,3 +751,8 @@ banaction = iptables-allports
enabled = false
logpath = /var/log/directadmin/login.log
port = 2222
[portsentry]
enabled = false
logpath = /var/lib/portsentry/portsentry.history
maxretry = 1
+3
View File
@@ -61,3 +61,6 @@ dovecot_log = %(syslog_mail_warn)s
solidpop3d_log = %(syslog_local0)s
mysql_log = %(syslog_daemon)s
# Directory with ignorecommand scripts
ignorecommands_dir = /etc/fail2ban/filter.d/ignorecommands
+4
View File
@@ -68,3 +68,7 @@ logging.notice = _root_notice
# add NOTICE to the priority map of all the levels
logging.handlers.SysLogHandler.priority_map['NOTICE'] = 'notice'
from time import strptime
# strptime thread safety hack-around - http://bugs.python.org/issue7980
strptime("2012", "%Y")
+8 -4
View File
@@ -26,7 +26,7 @@ __license__ = "GPL"
import os
from .configreader import ConfigReader, DefinitionInitConfigReader
from .configreader import DefinitionInitConfigReader
from ..helpers import getLogger
# Gets the instance of the logger.
@@ -47,15 +47,19 @@ class ActionReader(DefinitionInitConfigReader):
DefinitionInitConfigReader.__init__(
self, file_, jailName, initOpts, **kwargs)
def setFile(self, fileName):
self.__file = fileName
DefinitionInitConfigReader.setFile(self, os.path.join("action.d", fileName))
def getFile(self):
return self.__file
def setName(self, name):
self._name = name
def getName(self):
return self._name
def read(self):
return ConfigReader.read(self, os.path.join("action.d", self._file))
def convert(self):
head = ["set", self._jailName]
stream = list()
+3
View File
@@ -85,6 +85,9 @@ class Beautifier:
val = " ".join(res1[1]) if isinstance(res1[1], list) else res1[1]
msg.append("%s %s:\t%s" % (prefix1, res1[0], val))
msg = "\n".join(msg)
elif inC[1] == "syslogsocket":
msg = "Current syslog socket is:\n"
msg = msg + "`- " + response
elif inC[1] == "logtarget":
msg = "Current logging target is:\n"
msg = msg + "`- " + response
+117 -19
View File
@@ -62,6 +62,7 @@ else: # pragma: no cover
# Gets the instance of the logger.
logSys = getLogger(__name__)
logLevel = 7
__all__ = ['SafeConfigParserWithIncludes']
@@ -98,30 +99,73 @@ after = 1.conf
if sys.version_info >= (3,2):
# overload constructor only for fancy new Python3's
def __init__(self, *args, **kwargs):
def __init__(self, share_config=None, *args, **kwargs):
kwargs = kwargs.copy()
kwargs['interpolation'] = BasicInterpolationWithName()
kwargs['inline_comment_prefixes'] = ";"
super(SafeConfigParserWithIncludes, self).__init__(
*args, **kwargs)
self._cfg_share = share_config
#@staticmethod
def getIncludes(resource, seen = []):
else:
def __init__(self, share_config=None, *args, **kwargs):
SafeConfigParser.__init__(self, *args, **kwargs)
self._cfg_share = share_config
@property
def share_config(self):
return self._cfg_share
def _getSharedSCPWI(self, filename):
SCPWI = SafeConfigParserWithIncludes
# read single one, add to return list, use sharing if possible:
if self._cfg_share:
# cache/share each file as include (ex: filter.d/common could be included in each filter config):
hashv = 'inc:'+(filename if not isinstance(filename, list) else '\x01'.join(filename))
cfg, i = self._cfg_share.get(hashv, (None, None))
if cfg is None:
cfg = SCPWI(share_config=self._cfg_share)
i = cfg.read(filename, get_includes=False)
self._cfg_share[hashv] = (cfg, i)
elif logSys.getEffectiveLevel() <= logLevel:
logSys.log(logLevel, " Shared file: %s", filename)
else:
# don't have sharing:
cfg = SCPWI()
i = cfg.read(filename, get_includes=False)
return (cfg, i)
def _getIncludes(self, filenames, seen=[]):
if not isinstance(filenames, list):
filenames = [ filenames ]
# retrieve or cache include paths:
if self._cfg_share:
# cache/share include list:
hashv = 'inc-path:'+('\x01'.join(filenames))
fileNamesFull = self._cfg_share.get(hashv)
if fileNamesFull is None:
fileNamesFull = []
for filename in filenames:
fileNamesFull += self.__getIncludesUncached(filename, seen)
self._cfg_share[hashv] = fileNamesFull
return fileNamesFull
# don't have sharing:
fileNamesFull = []
for filename in filenames:
fileNamesFull += self.__getIncludesUncached(filename, seen)
return fileNamesFull
def __getIncludesUncached(self, resource, seen=[]):
"""
Given 1 config resource returns list of included files
(recursively) with the original one as well
Simple loops are taken care about
"""
# Use a short class name ;)
SCPWI = SafeConfigParserWithIncludes
parser = SafeConfigParser()
try:
if sys.version_info >= (3,2): # pragma: no cover
parser.read(resource, encoding='utf-8')
else:
parser.read(resource)
parser, i = self._getSharedSCPWI(resource)
if not i:
return []
except UnicodeDecodeError, e:
logSys.error("Error decoding config file '%s': %s" % (resource, e))
return []
@@ -141,22 +185,76 @@ after = 1.conf
if r in seen:
continue
s = seen + [resource]
option_list += SCPWI.getIncludes(r, s)
option_list += self._getIncludes(r, s)
# combine lists
return newFiles[0][1] + [resource] + newFiles[1][1]
#print "Includes list for " + resource + " is " + `resources`
getIncludes = staticmethod(getIncludes)
def get_defaults(self):
return self._defaults
def read(self, filenames):
fileNamesFull = []
def get_sections(self):
return self._sections
def read(self, filenames, get_includes=True):
if not isinstance(filenames, list):
filenames = [ filenames ]
for filename in filenames:
fileNamesFull += SafeConfigParserWithIncludes.getIncludes(filename)
logSys.debug("Reading files: %s" % fileNamesFull)
# retrieve (and cache) includes:
fileNamesFull = []
if get_includes:
fileNamesFull += self._getIncludes(filenames)
else:
fileNamesFull = filenames
if not fileNamesFull:
return []
logSys.info(" Loading files: %s", fileNamesFull)
if get_includes or len(fileNamesFull) > 1:
# read multiple configs:
ret = []
alld = self.get_defaults()
alls = self.get_sections()
for filename in fileNamesFull:
# read single one, add to return list, use sharing if possible:
cfg, i = self._getSharedSCPWI(filename)
if i:
ret += i
# merge defaults and all sections to self:
alld.update(cfg.get_defaults())
for n, s in cfg.get_sections().iteritems():
if isinstance(s, dict):
s2 = alls.get(n)
if isinstance(s2, dict):
# save previous known values, for possible using in local interpolations later:
sk = {}
for k, v in s2.iteritems():
if not k.startswith('known/'):
sk['known/'+k] = v
s2.update(sk)
# merge section
s2.update(s)
else:
alls[n] = s.copy()
else:
alls[n] = s
return ret
# read one config :
if logSys.getEffectiveLevel() <= logLevel:
logSys.log(logLevel, " Reading file: %s", fileNamesFull[0])
# read file(s) :
if sys.version_info >= (3,2): # pragma: no cover
return SafeConfigParser.read(self, fileNamesFull, encoding='utf-8')
else:
return SafeConfigParser.read(self, fileNamesFull)
def merge_section(self, section, options, pref='known/'):
alls = self.get_sections()
sk = {}
for k, v in options.iteritems():
if pref == '' or not k.startswith(pref):
sk[pref+k] = v
alls[section].update(sk)
+128 -21
View File
@@ -27,24 +27,131 @@ __license__ = "GPL"
import glob, os
from ConfigParser import NoOptionError, NoSectionError
from .configparserinc import SafeConfigParserWithIncludes
from .configparserinc import SafeConfigParserWithIncludes, logLevel
from ..helpers import getLogger
# Gets the instance of the logger.
logSys = getLogger(__name__)
class ConfigReader(SafeConfigParserWithIncludes):
class ConfigReader():
"""Generic config reader class.
A caching adapter which automatically reuses already shared configuration.
"""
def __init__(self, use_config=None, share_config=None, **kwargs):
# use given shared config if possible (see read):
self._cfg_share = None
self._cfg = None
if use_config is not None:
self._cfg = use_config
# share config if possible:
if share_config is not None:
self._cfg_share = share_config
self._cfg_share_kwargs = kwargs
self._cfg_share_basedir = None
elif self._cfg is None:
self._cfg = ConfigReaderUnshared(**kwargs)
def setBaseDir(self, basedir):
if self._cfg:
self._cfg.setBaseDir(basedir)
else:
self._cfg_share_basedir = basedir
def getBaseDir(self):
if self._cfg:
return self._cfg.getBaseDir()
else:
return self._cfg_share_basedir
@property
def share_config(self):
return self._cfg_share
def read(self, name, once=True):
""" Overloads a default (not shared) read of config reader.
To prevent mutiple reads of config files with it includes, reads into
the config reader, if it was not yet cached/shared by 'name'.
"""
# already shared ?
if not self._cfg:
self._create_unshared(name)
# performance feature - read once if using shared config reader:
if once and self._cfg.read_cfg_files is not None:
return self._cfg.read_cfg_files
# load:
logSys.info("Loading configs for %s under %s ", name, self._cfg.getBaseDir())
ret = self._cfg.read(name)
# save already read and return:
self._cfg.read_cfg_files = ret
return ret
def _create_unshared(self, name=''):
""" Allocates and share a config file by it name.
Automatically allocates unshared or reuses shared handle by given 'name' and
init arguments inside a given shared storage.
"""
if not self._cfg and self._cfg_share is not None:
self._cfg = self._cfg_share.get(name)
if not self._cfg:
self._cfg = ConfigReaderUnshared(share_config=self._cfg_share, **self._cfg_share_kwargs)
if self._cfg_share_basedir is not None:
self._cfg.setBaseDir(self._cfg_share_basedir)
self._cfg_share[name] = self._cfg
else:
self._cfg = ConfigReaderUnshared(**self._cfg_share_kwargs)
def sections(self):
if self._cfg is not None:
return self._cfg.sections()
return []
def has_section(self, sec):
if self._cfg is not None:
return self._cfg.has_section(sec)
return False
def merge_section(self, *args, **kwargs):
if self._cfg is not None:
return self._cfg.merge_section(*args, **kwargs)
def options(self, *args):
if self._cfg is not None:
return self._cfg.options(*args)
return {}
def get(self, sec, opt):
if self._cfg is not None:
return self._cfg.get(sec, opt)
return None
def getOptions(self, *args, **kwargs):
if self._cfg is not None:
return self._cfg.getOptions(*args, **kwargs)
return {}
class ConfigReaderUnshared(SafeConfigParserWithIncludes):
"""Unshared config reader (previously ConfigReader).
Do not use this class (internal not shared/cached represenation).
Use ConfigReader instead.
"""
DEFAULT_BASEDIR = '/etc/fail2ban'
def __init__(self, basedir=None):
SafeConfigParserWithIncludes.__init__(self)
def __init__(self, basedir=None, *args, **kwargs):
SafeConfigParserWithIncludes.__init__(self, *args, **kwargs)
self.read_cfg_files = None
self.setBaseDir(basedir)
self.__opts = None
def setBaseDir(self, basedir):
if basedir is None:
basedir = ConfigReader.DEFAULT_BASEDIR # stock system location
basedir = ConfigReaderUnshared.DEFAULT_BASEDIR # stock system location
self._basedir = basedir.rstrip('/')
def getBaseDir(self):
@@ -55,7 +162,7 @@ class ConfigReader(SafeConfigParserWithIncludes):
raise ValueError("Base configuration directory %s does not exist "
% self._basedir)
basename = os.path.join(self._basedir, filename)
logSys.info("Reading configs for %s under %s " % (basename, self._basedir))
logSys.debug("Reading configs for %s under %s " , filename, self._basedir)
config_files = [ basename + ".conf" ]
# possible further customizations under a .conf.d directory
@@ -71,14 +178,14 @@ class ConfigReader(SafeConfigParserWithIncludes):
if len(config_files):
# at least one config exists and accessible
logSys.debug("Reading config files: " + ', '.join(config_files))
logSys.debug("Reading config files: %s", ', '.join(config_files))
config_files_read = SafeConfigParserWithIncludes.read(self, config_files)
missed = [ cf for cf in config_files if cf not in config_files_read ]
if missed:
logSys.error("Could not read config files: " + ', '.join(missed))
logSys.error("Could not read config files: %s", ', '.join(missed))
if config_files_read:
return True
logSys.error("Found no accessible config files for %r under %s" %
logSys.error("Found no accessible config files for %r under %s",
( filename, self.getBaseDir() ))
return False
else:
@@ -98,7 +205,7 @@ class ConfigReader(SafeConfigParserWithIncludes):
# 1 -> the name of the option
# 2 -> the default value for the option
def getOptions(self, sec, options, pOptions = None):
def getOptions(self, sec, options, pOptions=None):
values = dict()
for option in options:
try:
@@ -121,10 +228,8 @@ class ConfigReader(SafeConfigParserWithIncludes):
logSys.warning("'%s' not defined in '%s'. Using default one: %r"
% (option[1], sec, option[2]))
values[option[1]] = option[2]
else:
logSys.debug(
"Non essential option '%s' not defined in '%s'.",
option[1], sec)
elif logSys.getEffectiveLevel() <= logLevel:
logSys.log(logLevel, "Non essential option '%s' not defined in '%s'.", option[1], sec)
except ValueError:
logSys.warning("Wrong value for '" + option[1] + "' in '" + sec +
"'. Using default one: '" + `option[2]` + "'")
@@ -133,12 +238,12 @@ class ConfigReader(SafeConfigParserWithIncludes):
class DefinitionInitConfigReader(ConfigReader):
"""Config reader for files with options grouped in [Definition] and
[Init] sections.
[Init] sections.
Is a base class for readers of filters and actions, where definitions
in jails might provide custom values for options defined in [Init]
section.
"""
Is a base class for readers of filters and actions, where definitions
in jails might provide custom values for options defined in [Init]
section.
"""
_configOpts = []
@@ -166,7 +271,9 @@ class DefinitionInitConfigReader(ConfigReader):
# needed for fail2ban-regex that doesn't need fancy directories
def readexplicit(self):
return SafeConfigParserWithIncludes.read(self, self._file)
if not self._cfg:
self._create_unshared(self._file)
return SafeConfigParserWithIncludes.read(self._cfg, self._file)
def getOptions(self, pOpts):
self._opts = ConfigReader.getOptions(
+12 -4
View File
@@ -33,12 +33,20 @@ logSys = getLogger(__name__)
class Configurator:
def __init__(self):
def __init__(self, force_enable=False, share_config=None):
self.__settings = dict()
self.__streams = dict()
self.__fail2ban = Fail2banReader()
self.__jails = JailsReader()
# always share all config readers:
if share_config is None:
share_config = dict()
self.__share_config = share_config
self.__fail2ban = Fail2banReader(share_config=share_config)
self.__jails = JailsReader(force_enable=force_enable, share_config=share_config)
def Reload(self):
# clear all shared handlers:
self.__share_config.clear()
def setBaseDir(self, folderName):
self.__fail2ban.setBaseDir(folderName)
self.__jails.setBaseDir(folderName)
+1 -2
View File
@@ -57,7 +57,7 @@ class CSocket:
self.__csock.close()
return ret
#@staticmethod
@staticmethod
def receive(sock):
msg = EMPTY_BYTES
while msg.rfind(CSocket.END_STRING) == -1:
@@ -66,4 +66,3 @@ class CSocket:
raise RuntimeError, "socket connection broken"
msg = msg + chunk
return loads(msg)
receive = staticmethod(receive)
+3
View File
@@ -46,6 +46,7 @@ class Fail2banReader(ConfigReader):
def getOptions(self):
opts = [["string", "loglevel", "INFO" ],
["string", "logtarget", "STDERR"],
["string", "syslogsocket", "auto"],
["string", "dbfile", "/var/lib/fail2ban/fail2ban.sqlite3"],
["int", "dbpurgeage", 86400]]
self.__opts = ConfigReader.getOptions(self, "Definition", opts)
@@ -57,6 +58,8 @@ class Fail2banReader(ConfigReader):
stream.append(["set", "loglevel", self.__opts[opt]])
elif opt == "logtarget":
stream.append(["set", "logtarget", self.__opts[opt]])
elif opt == "syslogsocket":
stream.append(["set", "syslogsocket", self.__opts[opt]])
elif opt == "dbfile":
stream.append(["set", "dbfile", self.__opts[opt]])
elif opt == "dbpurgeage":
+18 -6
View File
@@ -26,7 +26,7 @@ __license__ = "GPL"
import os, shlex
from .configreader import ConfigReader, DefinitionInitConfigReader
from .configreader import DefinitionInitConfigReader
from ..server.action import CommandAction
from ..helpers import getLogger
@@ -40,15 +40,27 @@ class FilterReader(DefinitionInitConfigReader):
["string", "failregex", ""],
]
def read(self):
return ConfigReader.read(self, os.path.join("filter.d", self._file))
def setFile(self, fileName):
self.__file = fileName
DefinitionInitConfigReader.setFile(self, os.path.join("filter.d", fileName))
def convert(self):
stream = list()
def getFile(self):
return self.__file
def getCombined(self):
combinedopts = dict(list(self._opts.items()) + list(self._initOpts.items()))
if not len(combinedopts):
return {}
opts = CommandAction.substituteRecursiveTags(combinedopts)
if not opts:
raise ValueError('recursive tag definitions unable to be resolved')
return opts
def convert(self):
stream = list()
opts = self.getCombined()
if not len(opts):
return stream
for opt, value in opts.iteritems():
if opt == "failregex":
for regex in value.split('\n'):
@@ -59,7 +71,7 @@ class FilterReader(DefinitionInitConfigReader):
for regex in value.split('\n'):
# Do not send a command if the rule is empty.
if regex != '':
stream.append(["set", self._jailName, "addignoreregex", regex])
stream.append(["set", self._jailName, "addignoreregex", regex])
if self._initOpts:
if 'maxlines' in self._initOpts:
# We warn when multiline regex is used without maxlines > 1
+27 -11
View File
@@ -27,7 +27,7 @@ __license__ = "GPL"
import re, glob, os.path
import json
from .configreader import ConfigReader
from .configreader import ConfigReaderUnshared, ConfigReader
from .filterreader import FilterReader
from .actionreader import ActionReader
from ..helpers import getLogger
@@ -87,6 +87,8 @@ class JailReader(ConfigReader):
return pathList
def getOptions(self):
opts1st = [["bool", "enabled", False],
["string", "filter", ""]]
opts = [["bool", "enabled", False],
["string", "logpath", None],
["string", "logencoding", None],
@@ -101,7 +103,9 @@ class JailReader(ConfigReader):
["string", "ignoreip", None],
["string", "filter", ""],
["string", "action", ""]]
self.__opts = ConfigReader.getOptions(self, self.__name, opts)
# Read first options only needed for merge defaults ('known/...' from filter):
self.__opts = ConfigReader.getOptions(self, self.__name, opts1st)
if not self.__opts:
return False
@@ -111,16 +115,26 @@ class JailReader(ConfigReader):
filterName, filterOpt = JailReader.extractOptions(
self.__opts["filter"])
self.__filter = FilterReader(
filterName, self.__name, filterOpt, basedir=self.getBaseDir())
filterName, self.__name, filterOpt, share_config=self.share_config, basedir=self.getBaseDir())
ret = self.__filter.read()
if ret:
self.__filter.getOptions(self.__opts)
else:
# merge options from filter as 'known/...':
self.__filter.getOptions(self.__opts)
ConfigReader.merge_section(self, self.__name, self.__filter.getCombined(), 'known/')
if not ret:
logSys.error("Unable to read the filter")
return False
else:
self.__filter = None
logSys.warning("No filter set for jail %s" % self.__name)
# Read second all options (so variables like %(known/param) can be interpolated):
self.__opts = ConfigReader.getOptions(self, self.__name, opts)
if not self.__opts:
return False
# cumulate filter options again (ignore given in jail):
if self.__filter:
self.__filter.getOptions(self.__opts)
# Read action
for act in self.__opts["action"].split('\n'):
@@ -141,7 +155,7 @@ class JailReader(ConfigReader):
else:
action = ActionReader(
actName, self.__name, actOpt,
basedir=self.getBaseDir())
share_config=self.share_config, basedir=self.getBaseDir())
ret = action.read()
if ret:
action.getOptions(self.__opts)
@@ -202,7 +216,10 @@ class JailReader(ConfigReader):
elif opt == "usedns":
stream.append(["set", self.__name, "usedns", self.__opts[opt]])
elif opt == "failregex":
stream.append(["set", self.__name, "addfailregex", self.__opts[opt]])
for regex in self.__opts[opt].split('\n'):
# Do not send a command if the rule is empty.
if regex != '':
stream.append(["set", self.__name, "addfailregex", regex])
elif opt == "ignorecommand":
stream.append(["set", self.__name, "ignorecommand", self.__opts[opt]])
elif opt == "ignoreregex":
@@ -213,14 +230,14 @@ class JailReader(ConfigReader):
if self.__filter:
stream.extend(self.__filter.convert())
for action in self.__actions:
if isinstance(action, ConfigReader):
if isinstance(action, (ConfigReaderUnshared, ConfigReader)):
stream.extend(action.convert())
else:
stream.append(action)
stream.insert(0, ["add", self.__name, backend])
return stream
#@staticmethod
@staticmethod
def extractOptions(option):
match = JailReader.optionCRE.match(option)
if not match:
@@ -235,4 +252,3 @@ class JailReader(ConfigReader):
val for val in optmatch.group(2,3,4) if val is not None][0]
option_opts[opt.strip()] = value.strip()
return option_name, option_opts
extractOptions = staticmethod(extractOptions)
+4 -3
View File
@@ -68,9 +68,10 @@ class JailsReader(ConfigReader):
for sec in sections:
if sec == 'INCLUDES':
continue
jail = JailReader(sec, basedir=self.getBaseDir(),
force_enable=self.__force_enable)
jail.read()
# use the cfg_share for filter/action caching and the same config for all
# jails (use_config=...), therefore don't read it here:
jail = JailReader(sec, force_enable=self.__force_enable,
share_config=self.share_config, use_config=self._cfg)
ret = jail.getOptions()
if ret:
if jail.isEnabled():
+3 -1
View File
@@ -44,6 +44,8 @@ protocol = [
["get loglevel", "gets the logging level"],
["set logtarget <TARGET>", "sets logging target to <TARGET>. Can be STDOUT, STDERR, SYSLOG or a file"],
["get logtarget", "gets logging target"],
["set syslogsocket auto|<SOCKET>", "sets the syslog socket path to auto or <SOCKET>. Only used if logtarget is SYSLOG"],
["get syslogsocket", "gets syslog socket path"],
["flushlogs", "flushes the logtarget if a file and reopens it. For log rotation."],
['', "DATABASE", ""],
["set dbfile <FILE>", "set the location of fail2ban persistent datastore. Set to \"None\" to disable"],
@@ -54,7 +56,7 @@ protocol = [
["add <JAIL> <BACKEND>", "creates <JAIL> using <BACKEND>"],
["start <JAIL>", "starts the jail <JAIL>"],
["stop <JAIL>", "stops the jail <JAIL>. The jail is removed"],
["status <JAIL>", "gets the current status of <JAIL>"],
["status <JAIL> [FLAVOR]", "gets the current status of <JAIL>, with optional flavor or extended info"],
['', "JAIL CONFIGURATION", ""],
["set <JAIL> idle on|off", "sets the idle state of <JAIL>"],
["set <JAIL> addignoreip <IP>", "adds <IP> to the ignore list of <JAIL>"],
+38 -29
View File
@@ -362,6 +362,7 @@ class CommandAction(ActionBase):
@classmethod
def substituteRecursiveTags(cls, tags):
"""Sort out tag definitions within other tags.
Since v.0.9.2 supports embedded interpolation (see test cases for examples).
so: becomes:
a = 3 a = 3
@@ -378,38 +379,46 @@ class CommandAction(ActionBase):
Dictionary of tags(keys) and their values, with tags
within the values recursively replaced.
"""
t = re.compile(r'<([^ >]+)>')
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))
while m:
found_tag = m.group(1)
#logSys.log(5, 'found: %s' % found_tag)
if found_tag == tag or found_tag in done:
# recursive definitions are bad
#logSys.log(5, 'recursion fail tag: %s value: %s' % (tag, value) )
return False
elif found_tag in cls._escapedTags:
t = re.compile(r'<([^ <>]+)>')
# repeat substitution while embedded-recursive (repFlag is True)
while True:
repFlag = False
# substitute each value:
for tag in tags.iterkeys():
if 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])
#logSys.log(5, 'value now: %s' % value)
done.append(found_tag)
m = t.search(value, m.start())
else:
# Missing tags are ok so we just continue on searching.
# cInfo can contain aInfo elements like <HOST> and valid shell
value = str(tags[tag])
# search and replace all tags within value, that can be interpolated using other tags:
m = t.search(value)
done = []
#logSys.log(5, 'TAG: %s, value: %s' % (tag, value))
while m:
found_tag = m.group(1)
#logSys.log(5, 'found: %s' % found_tag)
if found_tag == tag or found_tag in done:
# recursive definitions are bad
#logSys.log(5, 'recursion fail tag: %s value: %s' % (tag, value) )
return False
if found_tag in cls._escapedTags or not tags.has_key(found_tag):
# Escaped or missing tags - just continue on searching after end of match
# Missing tags are ok - cInfo can contain aInfo elements like <HOST> and valid shell
# constructs like <STDIN>.
m = t.search(value, m.start() + 1)
#logSys.log(5, 'TAG: %s, newvalue: %s' % (tag, value))
tags[tag] = value
m = t.search(value, m.end())
continue
value = value.replace('<%s>' % found_tag , tags[found_tag])
#logSys.log(5, 'value now: %s' % value)
done.append(found_tag)
m = t.search(value, m.start())
#logSys.log(5, 'TAG: %s, newvalue: %s' % (tag, value))
# was substituted?
if tags[tag] != value:
# check still contains any tag - should be repeated (possible embedded-recursive substitution):
if t.search(value):
repFlag = True
tags[tag] = value
if not repFlag:
break
return tags
@staticmethod
+59 -12
View File
@@ -243,6 +243,45 @@ class Actions(JailThread, Mapping):
logSys.debug(self._jail.name + ": action terminated")
return True
def __getBansMerged(self, mi, overalljails=False):
"""Gets bans merged once, a helper for lambda(s), prevents stop of executing action by any exception inside.
This function never returns None for ainfo lambdas - always a ticket (merged or single one)
and prevents any errors through merging (to guarantee ban actions will be executed).
[TODO] move merging to observer - here we could wait for merge and read already merged info from a database
Parameters
----------
mi : dict
merge info, initial for lambda should contains {ip, ticket}
overalljails : bool
switch to get a merged bans :
False - (default) bans merged for current jail only
True - bans merged for all jails of current ip address
Returns
-------
BanTicket
merged or self ticket only
"""
idx = 'all' if overalljails else 'jail'
if idx in mi:
return mi[idx] if mi[idx] is not None else mi['ticket']
try:
jail=self._jail
ip=mi['ip']
mi[idx] = None
if overalljails:
mi[idx] = jail.database.getBansMerged(ip=ip)
else:
mi[idx] = jail.database.getBansMerged(ip=ip, jail=jail)
except Exception as e:
logSys.error(
"Failed to get %s bans merged, jail '%s': %s",
idx, jail.name, e,
exc_info=logSys.getEffectiveLevel()<=logging.DEBUG)
return mi[idx] if mi[idx] is not None else mi['ticket']
def __checkBan(self):
"""Check for IP address to ban.
@@ -264,14 +303,12 @@ class Actions(JailThread, Mapping):
aInfo["time"] = bTicket.getTime()
aInfo["matches"] = "\n".join(bTicket.getMatches())
if self._jail.database is not None:
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()
mi4ip = lambda overalljails=False, self=self, \
mi={'ip':ip, 'ticket':bTicket}: self.__getBansMerged(mi, overalljails)
aInfo["ipmatches"] = lambda: "\n".join(mi4ip(True).getMatches())
aInfo["ipjailmatches"] = lambda: "\n".join(mi4ip().getMatches())
aInfo["ipfailures"] = lambda: mi4ip(True).getAttempt()
aInfo["ipjailfailures"] = lambda: mi4ip().getAttempt()
if self.__banManager.addBanTicket(bTicket):
logSys.notice("[%s] Ban %s" % (self._jail.name, aInfo["ip"]))
for name, action in self._actions.iteritems():
@@ -333,11 +370,21 @@ class Actions(JailThread, Mapping):
self._jail.name, name, aInfo, e,
exc_info=logSys.getEffectiveLevel()<=logging.DEBUG)
@property
def status(self):
"""Status of active bans, and total ban counts.
def status(self, flavor="basic"):
"""Status of current and total ban counts and current banned IP list.
"""
ret = [("Currently banned", self.__banManager.size()),
# TODO: Allow this list to be printed as 'status' output
supported_flavors = ["basic", "cymru"]
if flavor is None or flavor not in supported_flavors:
logSys.warning("Unsupported extended jail status flavor %r. Supported: %s" % (flavor, supported_flavors))
# Always print this information (basic)
ret = [("Currently banned", self.__banManager.size()),
("Total banned", self.__banManager.getBanTotal()),
("Banned IP list", self.__banManager.getBanList())]
if flavor == "cymru":
cymru_info = self.__banManager.getBanListExtendedCymruInfo()
ret += \
[("Banned ASN list", self.__banManager.geBanListExtendedASN(cymru_info)),
("Banned Country list", self.__banManager.geBanListExtendedCountry(cymru_info)),
("Banned RIR list", self.__banManager.geBanListExtendedRIR(cymru_info))]
return ret
+7 -8
View File
@@ -149,12 +149,12 @@ class AsyncServer(asyncore.dispatcher):
self.__init = True
# TODO Add try..catch
# There's a bug report for Python 2.6/3.0 that use_poll=True yields some 2.5 incompatibilities:
if sys.version_info >= (2, 6): # if python 2.6 or greater...
logSys.debug("Detected Python 2.6 or greater. asyncore.loop() not using poll")
asyncore.loop(use_poll = False) # fixes the "Unexpected communication problem" issue on Python 2.6 and 3.0
else: # pragma: no cover
logSys.debug("NOT Python 2.6/3.* - asyncore.loop() using poll")
asyncore.loop(use_poll = True)
if (sys.version_info >= (2, 7) and sys.version_info < (2, 8)) \
or (sys.version_info >= (3, 4)): # if python 2.7 ...
logSys.debug("Detected Python 2.7. asyncore.loop() using poll")
asyncore.loop(use_poll=True) # workaround for the "Bad file descriptor" issue on Python 2.7, gh-161
else:
asyncore.loop(use_poll=False) # fixes the "Unexpected communication problem" issue on Python 2.6 and 3.0
##
# Stops the communication server.
@@ -175,12 +175,11 @@ class AsyncServer(asyncore.dispatcher):
# @param sock: socket file.
#@staticmethod
@staticmethod
def __markCloseOnExec(sock):
fd = sock.fileno()
flags = fcntl.fcntl(fd, fcntl.F_GETFD)
fcntl.fcntl(fd, fcntl.F_SETFD, flags|fcntl.FD_CLOEXEC)
__markCloseOnExec = staticmethod(__markCloseOnExec)
##
# AsyncServerException is used to wrap communication exceptions.
+119 -2
View File
@@ -118,6 +118,124 @@ class BanManager:
finally:
self.__lock.release()
##
# Returns normalized value
#
# @return value or "unknown" if value is None or empty string
@staticmethod
def handleBlankResult(value):
if value is None or len(value) == 0:
return "unknown"
else:
return value
##
# Returns Cymru DNS query information
#
# @return {"asn": [], "country": [], "rir": []} dict for self.__banList IPs
def getBanListExtendedCymruInfo(self):
return_dict = {"asn": [], "country": [], "rir": []}
try:
import dns.exception
import dns.resolver
except ImportError:
logSys.error("dnspython package is required but could not be imported")
return_dict["asn"].append("error")
return_dict["country"].append("error")
return_dict["rir"].append("error")
return return_dict
self.__lock.acquire()
try:
for banData in self.__banList:
ip = banData.getIP()
# Reference: http://www.team-cymru.org/Services/ip-to-asn.html#dns
# TODO: IPv6 compatibility
reversed_ip = ".".join(reversed(ip.split(".")))
question = "%s.origin.asn.cymru.com" % reversed_ip
try:
answers = dns.resolver.query(question, "TXT")
for rdata in answers:
asn, net, country, rir, changed =\
[answer.strip("'\" ") for answer in rdata.to_text().split("|")]
asn = self.handleBlankResult(asn)
country = self.handleBlankResult(country)
rir = self.handleBlankResult(rir)
return_dict["asn"].append(self.handleBlankResult(asn))
return_dict["country"].append(self.handleBlankResult(country))
return_dict["rir"].append(self.handleBlankResult(rir))
except dns.resolver.NXDOMAIN:
return_dict["asn"].append("nxdomain")
return_dict["country"].append("nxdomain")
return_dict["rir"].append("nxdomain")
except dns.exception.DNSException as dnse:
logSys.error("Unhandled DNSException querying Cymru for %s TXT" % question)
logSys.exception(dnse)
except Exception as e:
logSys.error("Unhandled Exception querying Cymru for %s TXT" % question)
logSys.exception(e)
except Exception as e:
logSys.error("Failure looking up extended Cymru info")
logSys.exception(e)
finally:
self.__lock.release()
return return_dict
##
# Returns list of Banned ASNs from Cymru info
#
# Use getBanListExtendedCymruInfo() to provide cymru_info
#
# @return list of Banned ASNs
def geBanListExtendedASN(self, cymru_info):
self.__lock.acquire()
try:
return [asn for asn in cymru_info["asn"]]
except Exception as e:
logSys.error("Failed to lookup ASN")
logSys.exception(e)
return []
finally:
self.__lock.release()
##
# Returns list of Banned Countries from Cymru info
#
# Use getBanListExtendedCymruInfo() to provide cymru_info
#
# @return list of Banned Countries
def geBanListExtendedCountry(self, cymru_info):
self.__lock.acquire()
try:
return [country for country in cymru_info["country"]]
except Exception as e:
logSys.error("Failed to lookup Country")
logSys.exception(e)
return []
finally:
self.__lock.release()
##
# Returns list of Banned RIRs from Cymru info
#
# Use getBanListExtendedCymruInfo() to provide cymru_info
#
# @return list of Banned RIRs
def geBanListExtendedRIR(self, cymru_info):
self.__lock.acquire()
try:
return [rir for rir in cymru_info["rir"]]
except Exception as e:
logSys.error("Failed to lookup RIR")
logSys.exception(e)
return []
finally:
self.__lock.release()
##
# Create a ban ticket.
#
@@ -126,7 +244,7 @@ class BanManager:
# @param ticket the FailTicket
# @return a BanTicket
#@staticmethod
@staticmethod
def createBanTicket(ticket):
ip = ticket.getIP()
#lastTime = ticket.getTime()
@@ -134,7 +252,6 @@ class BanManager:
banTicket = BanTicket(ip, lastTime, ticket.getMatches())
banTicket.setAttempt(ticket.getAttempt())
return banTicket
createBanTicket = staticmethod(createBanTicket)
##
# Add a ban ticket.
+85 -46
View File
@@ -27,7 +27,7 @@ import sqlite3
import json
import locale
from functools import wraps
from threading import Lock
from threading import RLock
from .mytime import MyTime
from .ticket import FailTicket
@@ -37,17 +37,51 @@ from ..helpers import getLogger
logSys = getLogger(__name__)
if sys.version_info >= (3,):
sqlite3.register_adapter(
dict,
lambda x: json.dumps(x, ensure_ascii=False).encode(
locale.getpreferredencoding(), 'replace'))
sqlite3.register_converter(
"JSON",
lambda x: json.loads(x.decode(
locale.getpreferredencoding(), 'replace')))
def _json_dumps_safe(x):
try:
x = json.dumps(x, ensure_ascii=False).encode(
locale.getpreferredencoding(), 'replace')
except Exception, e: # pragma: no cover
logSys.error('json dumps failed: %s', e)
x = '{}'
return x
def _json_loads_safe(x):
try:
x = json.loads(x.decode(
locale.getpreferredencoding(), 'replace'))
except Exception, e: # pragma: no cover
logSys.error('json loads failed: %s', e)
x = {}
return x
else:
sqlite3.register_adapter(dict, json.dumps)
sqlite3.register_converter("JSON", json.loads)
def _normalize(x):
if isinstance(x, dict):
return dict((_normalize(k), _normalize(v)) for k, v in x.iteritems())
elif isinstance(x, list):
return [_normalize(element) for element in x]
elif isinstance(x, unicode):
return x.encode(locale.getpreferredencoding())
else:
return x
def _json_dumps_safe(x):
try:
x = json.dumps(_normalize(x), ensure_ascii=False).decode(
locale.getpreferredencoding(), 'replace')
except Exception, e: # pragma: no cover
logSys.error('json dumps failed: %s', e)
x = '{}'
return x
def _json_loads_safe(x):
try:
x = _normalize(json.loads(x.decode(
locale.getpreferredencoding(), 'replace')))
except Exception, e: # pragma: no cover
logSys.error('json loads failed: %s', e)
x = {}
return x
sqlite3.register_adapter(dict, _json_dumps_safe)
sqlite3.register_converter("JSON", _json_loads_safe)
def commitandrollback(f):
@wraps(f)
@@ -123,7 +157,7 @@ class Fail2BanDb(object):
def __init__(self, filename, purgeAge=24*60*60):
try:
self._lock = Lock()
self._lock = RLock()
self._db = sqlite3.connect(
filename, check_same_thread=False,
detect_types=sqlite3.PARSE_DECLTYPES)
@@ -365,12 +399,16 @@ class Fail2BanDb(object):
del self._bansMergedCache[(ticket.getIP(), jail)]
except KeyError:
pass
try:
del self._bansMergedCache[(ticket.getIP(), None)]
except KeyError:
pass
#TODO: Implement data parts once arbitrary match keys completed
cur.execute(
"INSERT INTO bans(jail, ip, timeofban, data) VALUES(?, ?, ?, ?)",
(jail.name, ticket.getIP(), int(round(ticket.getTime())),
{"matches": ticket.getMatches(),
"failures": ticket.getAttempt()}))
"failures": ticket.getAttempt()}))
@commitandrollback
def delBan(self, cur, jail, ticket):
@@ -427,8 +465,8 @@ class Fail2BanDb(object):
tickets = []
for ip, timeofban, data in self._getBans(**kwargs):
#TODO: Implement data parts once arbitrary match keys completed
tickets.append(FailTicket(ip, timeofban, data['matches']))
tickets[-1].setAttempt(data['failures'])
tickets.append(FailTicket(ip, timeofban, data.get('matches')))
tickets[-1].setAttempt(data.get('failures', 1))
return tickets
def getBansMerged(self, ip=None, jail=None, bantime=None):
@@ -455,40 +493,41 @@ class Fail2BanDb(object):
in a list. When `ip` argument passed, a single `Ticket` is
returned.
"""
cacheKey = None
if bantime is None or bantime < 0:
cacheKey = (ip, jail)
if cacheKey in self._bansMergedCache:
return self._bansMergedCache[cacheKey]
with self._lock:
cacheKey = None
if bantime is None or bantime < 0:
cacheKey = (ip, jail)
if cacheKey in self._bansMergedCache:
return self._bansMergedCache[cacheKey]
tickets = []
ticket = None
tickets = []
ticket = None
results = list(self._getBans(ip=ip, jail=jail, bantime=bantime))
if results:
prev_banip = results[0][0]
matches = []
failures = 0
for banip, timeofban, data in results:
#TODO: Implement data parts once arbitrary match keys completed
if banip != prev_banip:
ticket = FailTicket(prev_banip, prev_timeofban, matches)
ticket.setAttempt(failures)
tickets.append(ticket)
# Reset variables
prev_banip = banip
matches = []
failures = 0
matches.extend(data['matches'])
failures += data['failures']
prev_timeofban = timeofban
ticket = FailTicket(banip, prev_timeofban, matches)
ticket.setAttempt(failures)
tickets.append(ticket)
results = list(self._getBans(ip=ip, jail=jail, bantime=bantime))
if results:
prev_banip = results[0][0]
matches = []
failures = 0
for banip, timeofban, data in results:
#TODO: Implement data parts once arbitrary match keys completed
if banip != prev_banip:
ticket = FailTicket(prev_banip, prev_timeofban, matches)
ticket.setAttempt(failures)
tickets.append(ticket)
# Reset variables
prev_banip = banip
matches = []
failures = 0
matches.extend(data.get('matches', []))
failures += data.get('failures', 1)
prev_timeofban = timeofban
ticket = FailTicket(banip, prev_timeofban, matches)
ticket.setAttempt(failures)
tickets.append(ticket)
if cacheKey:
self._bansMergedCache[cacheKey] = tickets if ip is None else ticket
return tickets if ip is None else ticket
if cacheKey:
self._bansMergedCache[cacheKey] = tickets if ip is None else ticket
return tickets if ip is None else ticket
@commitandrollback
def purge(self, cur):
+46 -42
View File
@@ -338,6 +338,10 @@ class Filter(JailThread):
logSys.debug("Remove " + ip + " from ignore list")
self.__ignoreIpList.remove(ip)
def logIgnoreIp(self, ip, log_ignore, ignore_source="unknown source"):
if log_ignore:
logSys.info("[%s] Ignore %s by %s" % (self.jail.name, ip, ignore_source))
def getIgnoreIP(self):
return self.__ignoreIpList
@@ -349,7 +353,7 @@ class Filter(JailThread):
# @param ip IP address
# @return True if IP address is in ignore list
def inIgnoreIPList(self, ip):
def inIgnoreIPList(self, ip, log_ignore=False):
for i in self.__ignoreIpList:
# An empty string is always false
if i == "":
@@ -363,22 +367,26 @@ class Filter(JailThread):
"(?<=b)1+", bin(DNSUtils.addr2bin(s[1]))).group())
s[1] = long(s[1])
try:
a = DNSUtils.cidr(s[0], s[1])
b = DNSUtils.cidr(ip, s[1])
a = DNSUtils.addr2bin(s[0], cidr=s[1])
b = DNSUtils.addr2bin(ip, cidr=s[1])
except Exception:
# Check if IP in DNS
ips = DNSUtils.dnsToIp(i)
if ip in ips:
self.logIgnoreIp(ip, log_ignore, ignore_source="dns")
return True
else:
continue
if a == b:
self.logIgnoreIp(ip, log_ignore, ignore_source="ip")
return True
if self.__ignoreCommand:
command = CommandAction.replaceTag(self.__ignoreCommand, { 'ip': ip } )
logSys.debug('ignore command: ' + command)
return CommandAction.executeCmd(command)
ret_ignore = CommandAction.executeCmd(command)
self.logIgnoreIp(ip, log_ignore and ret_ignore, ignore_source="command")
return ret_ignore
return False
@@ -418,8 +426,7 @@ class Filter(JailThread):
logSys.debug("Ignore line since time %s < %s - %s"
% (unixTime, MyTime.time(), self.getFindTime()))
break
if self.inIgnoreIPList(ip):
logSys.info("[%s] Ignore %s" % (self.jail.name, ip))
if self.inIgnoreIPList(ip, log_ignore=True):
continue
logSys.info("[%s] Found %s" % (self.jail.name, ip))
## print "D: Adding a ticket for %s" % ((ip, unixTime, [line]),)
@@ -529,8 +536,7 @@ class Filter(JailThread):
logSys.error(e)
return failList
@property
def status(self):
def status(self, flavor="basic"):
"""Status of failures detected by filter.
"""
ret = [("Currently failed", self.failManager.size()),
@@ -686,11 +692,10 @@ class FileFilter(Filter):
db.updateLog(self.jail, container)
return True
@property
def status(self):
def status(self, flavor="basic"):
"""Status of Filter plus files being monitored.
"""
ret = super(FileFilter, self).status
ret = super(FileFilter, self).status(flavor=flavor)
path = [m.getFileName() for m in self.getLogPath()]
ret.append(("File list", path))
return ret
@@ -792,11 +797,13 @@ class FileContainer:
line = line.decode(self.getEncoding(), 'strict')
except UnicodeDecodeError:
logSys.warning(
"Error decoding line from '%s' with '%s'. Continuing "
"Error decoding line from '%s' with '%s'."
" Consider setting logencoding=utf-8 (or another appropriate"
" encoding) for this jail. 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')
# decode with replacing error chars:
line = line.decode(self.getEncoding(), 'replace')
return line
def close(self):
@@ -838,7 +845,7 @@ class DNSUtils:
IP_CRE = re.compile("^(?:\d{1,3}\.){3}\d{1,3}$")
#@staticmethod
@staticmethod
def dnsToIp(dns):
""" Convert a DNS into an IP address using the Python socket module.
Thanks to Kevin Drapel.
@@ -853,9 +860,16 @@ class DNSUtils:
logSys.warning("Socket error raised trying to resolve hostname %s: %s"
% (dns, e))
return list()
dnsToIp = staticmethod(dnsToIp)
#@staticmethod
@staticmethod
def ipToName(ip):
try:
return socket.gethostbyaddr(ip)[0]
except socket.error, e:
logSys.debug("Unable to find a name for the IP %s: %s" % (ip, e))
return None
@staticmethod
def searchIP(text):
""" Search if an IP address if directly available and return
it.
@@ -865,9 +879,8 @@ class DNSUtils:
return match
else:
return None
searchIP = staticmethod(searchIP)
#@staticmethod
@staticmethod
def isValidIP(string):
""" Return true if str is a valid IP
"""
@@ -877,9 +890,8 @@ class DNSUtils:
return True
except socket.error:
return False
isValidIP = staticmethod(isValidIP)
#@staticmethod
@staticmethod
def textToIp(text, useDns):
""" Return the IP of DNS found in a given text.
"""
@@ -901,28 +913,20 @@ class DNSUtils:
text, ipList)
return ipList
textToIp = staticmethod(textToIp)
#@staticmethod
def cidr(i, n):
""" Convert an IP address string with a CIDR mask into a 32-bit
integer.
@staticmethod
def addr2bin(ipstring, cidr=None):
""" Convert a string IPv4 address into binary form.
If cidr is supplied, return the network address for the given block
"""
# 32-bit IPv4 address mask
MASK = 0xFFFFFFFFL
return ~(MASK >> n) & MASK & DNSUtils.addr2bin(i)
cidr = staticmethod(cidr)
if cidr is None:
return struct.unpack("!L", socket.inet_aton(ipstring))[0]
else:
MASK = 0xFFFFFFFFL
return ~(MASK >> cidr) & MASK & DNSUtils.addr2bin(ipstring)
#@staticmethod
def addr2bin(string):
""" Convert a string IPv4 address into an unsigned integer.
@staticmethod
def bin2addr(ipbin):
""" Convert a binary IPv4 address into string n.n.n.n form.
"""
return struct.unpack("!L", socket.inet_aton(string))[0]
addr2bin = staticmethod(addr2bin)
#@staticmethod
def bin2addr(addr):
""" Convert a numeric IPv4 address into string n.n.n.n form.
"""
return socket.inet_ntoa(struct.pack("!L", addr))
bin2addr = staticmethod(bin2addr)
return socket.inet_ntoa(struct.pack("!L", ipbin))
+6 -6
View File
@@ -167,9 +167,10 @@ class FilterSystemd(JournalFilter): # pragma: systemd no cover
logelements.append(logentry['_HOSTNAME'])
if logentry.get('SYSLOG_IDENTIFIER'):
logelements.append(logentry['SYSLOG_IDENTIFIER'])
if logentry.get('SYSLOG_PID') or logentry.get('_PID'):
logelements[-1] += ("[%i]" % logentry.get(
'SYSLOG_PID', logentry['_PID']))
if logentry.get('SYSLOG_PID'):
logelements[-1] += ("[%i]" % logentry['SYSLOG_PID'])
elif logentry.get('_PID'):
logelements[-1] += ("[%i]" % logentry['_PID'])
logelements[-1] += ":"
elif logentry.get('_COMM'):
logelements.append(logentry['_COMM'])
@@ -258,9 +259,8 @@ class FilterSystemd(JournalFilter): # pragma: systemd no cover
or "jailless") +" filter terminated")
return True
@property
def status(self):
ret = super(FilterSystemd, self).status
def status(self, flavor="basic"):
ret = super(FilterSystemd, self).status(flavor=flavor)
ret.append(("Journal matches",
[" + ".join(" ".join(match) for match in self.__matches)]))
return ret
+4 -5
View File
@@ -174,13 +174,12 @@ class Jail:
self.filter.idle = value
self.actions.idle = value
@property
def status(self):
def status(self, flavor="basic"):
"""The status of the jail.
"""
return [
("Filter", self.filter.status),
("Actions", self.actions.status),
("Filter", self.filter.status(flavor=flavor)),
("Actions", self.actions.status(flavor=flavor)),
]
def putFailTicket(self, ticket):
@@ -214,7 +213,7 @@ class Jail:
if self.database is not None:
for ticket in self.database.getBansMerged(
jail=self, bantime=self.actions.getBanTime()):
if not self.filter.inIgnoreIPList(ticket.getIP()):
if not self.filter.inIgnoreIPList(ticket.getIP(), log_ignore=True):
self.__queue.put(ticket)
logSys.info("Jail '%s' started" % self.name)
+3 -3
View File
@@ -26,7 +26,7 @@ __license__ = "GPL"
import sys
from threading import Thread
from abc import abstractproperty, abstractmethod
from abc import abstractmethod
from ..helpers import excepthook
@@ -66,8 +66,8 @@ class JailThread(Thread):
excepthook(*sys.exc_info())
self.run = run_with_except_hook
@abstractproperty
def status(self): # pragma: no cover - abstract
@abstractmethod
def status(self, flavor="basic"): # pragma: no cover - abstract
"""Abstract - Should provide status information.
"""
pass
+41 -35
View File
@@ -26,65 +26,71 @@ import time, datetime
##
# MyTime class.
#
# This class is a wrapper around time.time() and time.gmtime(). When
# performing unit test, it is very useful to get a fixed value from these
# functions.
# Thus, time.time() and time.gmtime() should never be called directly.
# This wrapper should be called instead. The API are equivalent.
class MyTime:
"""A wrapper around time module primarily for testing purposes
This class is a wrapper around time.time() and time.gmtime(). When
performing unit test, it is very useful to get a fixed value from
these functions. Thus, time.time() and time.gmtime() should never
be called directly. This wrapper should be called instead. The API
are equivalent.
"""
myTime = None
##
# Sets the current time.
#
# Use None in order to always get the real current time.
#
# @param t the time to set or None
#@staticmethod
@staticmethod
def setTime(t):
"""Set current time.
Use None in order to always get the real current time.
@param t the time to set or None
"""
MyTime.myTime = t
setTime = staticmethod(setTime)
##
# Equivalent to time.time()
#
# @return time.time() if setTime was called with None
#@staticmethod
@staticmethod
def time():
"""Decorate time.time() for the purpose of testing mocking
@return time.time() if setTime was called with None
"""
if MyTime.myTime is None:
return time.time()
else:
return MyTime.myTime
time = staticmethod(time)
##
# Equivalent to time.gmtime()
#
# @return time.gmtime() if setTime was called with None
#@staticmethod
@staticmethod
def gmtime():
"""Decorate time.gmtime() for the purpose of testing mocking
@return time.gmtime() if setTime was called with None
"""
if MyTime.myTime is None:
return time.gmtime()
else:
return time.gmtime(MyTime.myTime)
gmtime = staticmethod(gmtime)
#@staticmethod
@staticmethod
def now():
"""Decorate datetime.now() for the purpose of testing mocking
@return datetime.now() if setTime was called with None
"""
if MyTime.myTime is None:
return datetime.datetime.now()
else:
return datetime.datetime.fromtimestamp(MyTime.myTime)
now = staticmethod(now)
@staticmethod
def localtime(x=None):
"""Decorate time.localtime() for the purpose of testing mocking
@return time.localtime() if setTime was called with None
"""
if MyTime.myTime is None or x is not None:
return time.localtime(x)
else:
return time.localtime(MyTime.myTime)
localtime = staticmethod(localtime)
+61 -11
View File
@@ -25,7 +25,7 @@ __copyright__ = "Copyright (c) 2004 Cyril Jaquier"
__license__ = "GPL"
from threading import Lock, RLock
import logging, logging.handlers, sys, os, signal
import logging, logging.handlers, sys, os, signal, stat
from .jails import Jails
from .filter import FileFilter, JournalFilter
@@ -55,20 +55,33 @@ class Server:
self.__asyncServer = AsyncServer(self.__transm)
self.__logLevel = None
self.__logTarget = None
self.__syslogSocket = None
self.__autoSyslogSocketPaths = {
'Darwin': '/var/run/syslog',
'FreeBSD': '/var/run/log',
'Linux': '/dev/log',
}
# Set logging level
self.setLogLevel("INFO")
self.setLogTarget("STDOUT")
self.setSyslogSocket("auto")
def __sigTERMhandler(self, signum, frame):
logSys.debug("Caught signal %d. Exiting" % signum)
self.quit()
def __sigUSR1handler(self, signum, fname):
logSys.debug("Caught signal %d. Flushing logs" % signum)
self.flushLogs()
def start(self, sock, pidfile, force = False):
logSys.info("Starting Fail2ban v" + version.version)
# Install signal handlers
signal.signal(signal.SIGTERM, self.__sigTERMhandler)
signal.signal(signal.SIGINT, self.__sigTERMhandler)
signal.signal(signal.SIGUSR1, self.__sigUSR1handler)
# Ensure unhandled exceptions are logged
sys.excepthook = excepthook
@@ -320,9 +333,9 @@ class Server:
finally:
self.__lock.release()
def statusJail(self, name):
return self.__jails[name].status
def statusJail(self, name, flavor="basic"):
return self.__jails[name].status(flavor=flavor)
# Logging
##
@@ -360,7 +373,7 @@ class Server:
return self.__logLevel
finally:
self.__loggingLock.release()
##
# Sets the logging target.
#
@@ -376,7 +389,21 @@ class Server:
# Syslog daemons already add date to the message.
formatter = logging.Formatter("%(name)s[%(process)d]: %(levelname)s %(message)s")
facility = logging.handlers.SysLogHandler.LOG_DAEMON
hdlr = logging.handlers.SysLogHandler("/dev/log", facility=facility)
if self.__syslogSocket == "auto":
import platform
self.__syslogSocket = self.__autoSyslogSocketPaths.get(
platform.system())
if self.__syslogSocket is not None\
and os.path.exists(self.__syslogSocket)\
and stat.S_ISSOCK(os.stat(
self.__syslogSocket).st_mode):
hdlr = logging.handlers.SysLogHandler(
self.__syslogSocket, facility=facility)
else:
logSys.error(
"Syslog socket file: %s does not exists"
" or is not a socket" % self.__syslogSocket)
return False
elif target == "STDOUT":
hdlr = logging.StreamHandler(sys.stdout)
elif target == "STDERR":
@@ -412,21 +439,44 @@ class Server:
logger.addHandler(hdlr)
# Does not display this message at startup.
if not self.__logTarget is None:
logSys.info("Changed logging target to %s for Fail2ban v%s" %
(target, version.version))
logSys.info(
"Changed logging target to %s for Fail2ban v%s"
% ((target
if target != "SYSLOG"
else "%s (%s)"
% (target, self.__syslogSocket)),
version.version))
# Sets the logging target.
self.__logTarget = target
return True
finally:
self.__loggingLock.release()
##
# Sets the syslog socket.
#
# syslogsocket is the full path to the syslog socket
# @param syslogsocket the syslog socket path
def setSyslogSocket(self, syslogsocket):
self.__syslogSocket = syslogsocket
# Conditionally reload, logtarget depends on socket path when SYSLOG
return self.__logTarget != "SYSLOG"\
or self.setLogTarget(self.__logTarget)
def getLogTarget(self):
try:
self.__loggingLock.acquire()
return self.__logTarget
finally:
self.__loggingLock.release()
def getSyslogSocket(self):
try:
self.__loggingLock.acquire()
return self.__syslogSocket
finally:
self.__loggingLock.release()
def flushLogs(self):
if self.__logTarget not in ['STDERR', 'STDOUT', 'SYSLOG']:
for handler in getLogger("fail2ban").handlers:
+1 -1
View File
@@ -55,7 +55,7 @@ class Ticket:
def __eq__(self, other):
try:
return self.__ip == other.__ip and \
round(self.__time,2) == round(other.__time,2) and \
round(self.__time, 2) == round(other.__time, 2) and \
self.__attempt == other.__attempt and \
self.__matches == other.__matches
except AttributeError:
+12 -1
View File
@@ -121,6 +121,12 @@ class Transmitter:
return self.__server.getLogTarget()
else:
raise Exception("Failed to change log target")
elif name == "syslogsocket":
value = command[1]
if self.__server.setSyslogSocket(value):
return self.__server.getSyslogSocket()
else:
raise Exception("Failed to change syslog socket")
#Database
elif name == "dbfile":
self.__server.setDatabase(command[1])
@@ -264,6 +270,8 @@ class Transmitter:
return self.__server.getLogLevel()
elif name == "logtarget":
return self.__server.getLogTarget()
elif name == "syslogsocket":
return self.__server.getSyslogSocket()
#Database
elif name == "dbfile":
db = self.__server.getDatabase()
@@ -333,5 +341,8 @@ class Transmitter:
elif len(command) == 1:
name = command[0]
return self.__server.statusJail(name)
elif len(command) == 2:
name = command[0]
flavor = command[1]
return self.__server.statusJail(name, flavor=flavor)
raise Exception("Invalid command (no status)")
+1 -5
View File
@@ -22,11 +22,7 @@ import unittest
import sys
from ..dummyjail import DummyJail
if os.path.exists('config/fail2ban.conf'):
CONFIG_DIR = "config"
else:
CONFIG_DIR='/etc/fail2ban'
from ..utils import CONFIG_DIR
if sys.version_info >= (2,7):
class BadIPsActionTest(unittest.TestCase):
+1 -4
View File
@@ -30,10 +30,7 @@ else:
from ..dummyjail import DummyJail
if os.path.exists('config/fail2ban.conf'):
CONFIG_DIR = "config"
else:
CONFIG_DIR='/etc/fail2ban'
from ..utils import CONFIG_DIR
class TestSMTPServer(smtpd.SMTPServer):
+1 -1
View File
@@ -86,7 +86,7 @@ class ExecuteActions(LogCaptureTestCase):
self.__actions.stop()
self.__actions.join()
self.assertEqual(self.__actions.status,[("Currently banned", 0 ),
self.assertEqual(self.__actions.status(),[("Currently banned", 0 ),
("Total banned", 0 ), ("Banned IP list", [] )])
+14 -2
View File
@@ -59,6 +59,8 @@ class CommandActionTest(LogCaptureTestCase):
self.assertEqual(CommandAction.substituteRecursiveTags({'A': '<C>'}), {'A': '<C>'})
self.assertEqual(CommandAction.substituteRecursiveTags({'A': '<C> <D> <X>','X':'fun'}), {'A': '<C> <D> fun', 'X':'fun'})
self.assertEqual(CommandAction.substituteRecursiveTags({'A': '<C> <B>', 'B': 'cool'}), {'A': '<C> cool', 'B': 'cool'})
# Escaped tags should be ignored
self.assertEqual(CommandAction.substituteRecursiveTags({'A': '<matches> <B>', 'B': 'cool'}), {'A': '<matches> cool', 'B': 'cool'})
# Multiple stuff on same line is ok
self.assertEqual(CommandAction.substituteRecursiveTags({'failregex': 'to=<honeypot> fromip=<IP> evilperson=<honeypot>', 'honeypot': 'pokie', 'ignoreregex': ''}),
{ 'failregex': "to=pokie fromip=<IP> evilperson=pokie",
@@ -71,6 +73,14 @@ class CommandActionTest(LogCaptureTestCase):
'ABC': '123 192.0.2.0',
'xyz': '890 123 192.0.2.0',
})
# obscure embedded case
self.assertEqual(CommandAction.substituteRecursiveTags({'A': '<<PREF>HOST>', 'PREF': 'IPV4'}),
{'A': '<IPV4HOST>', 'PREF': 'IPV4'})
self.assertEqual(CommandAction.substituteRecursiveTags({'A': '<<PREF>HOST>', 'PREF': 'IPV4', 'IPV4HOST': '1.2.3.4'}),
{'A': '1.2.3.4', 'PREF': 'IPV4', 'IPV4HOST': '1.2.3.4'})
# more embedded within a string and two interpolations
self.assertEqual(CommandAction.substituteRecursiveTags({'A': 'A <IP<PREF>HOST> B IP<PREF> C', 'PREF': 'V4', 'IPV4HOST': '1.2.3.4'}),
{'A': 'A 1.2.3.4 B IPV4 C', 'PREF': 'V4', 'IPV4HOST': '1.2.3.4'})
def testReplaceTag(self):
aInfo = {
@@ -186,8 +196,10 @@ class CommandActionTest(LogCaptureTestCase):
# Should take a minute
self.assertRaises(
RuntimeError, CommandAction.executeCmd, 'sleep 60', timeout=2)
self.assertAlmostEqual(time.time() - stime, 2, places=0)
self.assertTrue(self._is_logged('sleep 60 -- timed out after 2 seconds'))
# give a test still 1 second, because system could be too busy
self.assertTrue(time.time() >= stime + 2 and time.time() <= stime + 3)
self.assertTrue(self._is_logged('sleep 60 -- timed out after 2 seconds')
or self._is_logged('sleep 60 -- timed out after 3 seconds'))
self.assertTrue(self._is_logged('sleep 60 -- killed with SIGTERM'))
def testCaptureStdOutErr(self):
+63 -6
View File
@@ -30,7 +30,6 @@ from ..server.banmanager import BanManager
from ..server.ticket import BanTicket
class AddFailure(unittest.TestCase):
def setUp(self):
"""Call before every test case."""
self.__ticket = BanTicket('193.168.0.128', 1167605999.0)
@@ -39,19 +38,77 @@ class AddFailure(unittest.TestCase):
def tearDown(self):
"""Call after every test case."""
pass
def testAdd(self):
self.assertEqual(self.__banManager.size(), 1)
def testAddDuplicate(self):
self.assertFalse(self.__banManager.addBanTicket(self.__ticket))
self.assertEqual(self.__banManager.size(), 1)
def testInListOK(self):
ticket = BanTicket('193.168.0.128', 1167605999.0)
self.assertTrue(self.__banManager._inBanList(ticket))
def testInListNOK(self):
ticket = BanTicket('111.111.1.111', 1167605999.0)
self.assertFalse(self.__banManager._inBanList(ticket))
class StatusExtendedCymruInfo(unittest.TestCase):
def setUp(self):
"""Call before every test case."""
self.__ban_ip = "93.184.216.34"
self.__asn = "15133"
self.__country = "EU"
self.__rir = "ripencc"
ticket = BanTicket(self.__ban_ip, 1167605999.0)
self.__banManager = BanManager()
self.assertTrue(self.__banManager.addBanTicket(ticket))
def tearDown(self):
"""Call after every test case."""
pass
def testCymruInfo(self):
cymru_info = self.__banManager.getBanListExtendedCymruInfo()
if "assertDictEqual" in dir(self):
self.assertDictEqual(cymru_info, {"asn": [self.__asn],
"country": [self.__country],
"rir": [self.__rir]})
else:
# Python 2.6 does not support assertDictEqual()
self.assertEqual(cymru_info["asn"], [self.__asn])
self.assertEqual(cymru_info["country"], [self.__country])
self.assertEqual(cymru_info["rir"], [self.__rir])
def testCymruInfoASN(self):
self.assertEqual(
self.__banManager.geBanListExtendedASN(self.__banManager.getBanListExtendedCymruInfo()),
[self.__asn])
def testCymruInfoCountry(self):
self.assertEqual(
self.__banManager.geBanListExtendedCountry(self.__banManager.getBanListExtendedCymruInfo()),
[self.__country])
def testCymruInfoRIR(self):
self.assertEqual(
self.__banManager.geBanListExtendedRIR(self.__banManager.getBanListExtendedCymruInfo()),
[self.__rir])
def testCymruInfoNxdomain(self):
ticket = BanTicket("10.0.0.0", 1167605999.0)
self.__banManager = BanManager()
self.assertTrue(self.__banManager.addBanTicket(ticket))
cymru_info = self.__banManager.getBanListExtendedCymruInfo()
if "assertDictEqual" in dir(self):
self.assertDictEqual(cymru_info, {"asn": ["nxdomain"],
"country": ["nxdomain"],
"rir": ["nxdomain"]})
else:
# Python 2.6 does not support assertDictEqual()
self.assertEqual(cymru_info["asn"], ["nxdomain"])
self.assertEqual(cymru_info["country"], ["nxdomain"])
self.assertEqual(cymru_info["rir"], ["nxdomain"])
+122 -16
View File
@@ -21,9 +21,9 @@ __author__ = "Cyril Jaquier, Yaroslav Halchenko"
__copyright__ = "Copyright (c) 2004 Cyril Jaquier, 2011-2013 Yaroslav Halchenko"
__license__ = "GPL"
import os, glob, shutil, tempfile, unittest
from ..client.configreader import ConfigReader
import os, glob, shutil, tempfile, unittest, re, logging
from ..client.configreader import ConfigReaderUnshared
from ..client import configparserinc
from ..client.jailreader import JailReader
from ..client.filterreader import FilterReader
from ..client.jailsreader import JailsReader
@@ -32,8 +32,10 @@ from ..client.configurator import Configurator
from .utils import LogCaptureTestCase
TEST_FILES_DIR = os.path.join(os.path.dirname(__file__), "files")
from .utils import CONFIG_DIR
STOCK = os.path.exists(os.path.join('config','fail2ban.conf'))
CONFIG_DIR='config' if STOCK else '/etc/fail2ban'
IMPERFECT_CONFIG = os.path.join(os.path.dirname(__file__), 'config')
@@ -42,7 +44,7 @@ class ConfigReaderTest(unittest.TestCase):
def setUp(self):
"""Call before every test case."""
self.d = tempfile.mkdtemp(prefix="f2b-temp")
self.c = ConfigReader(basedir=self.d)
self.c = ConfigReaderUnshared(basedir=self.d)
def tearDown(self):
"""Call after every test case."""
@@ -153,12 +155,16 @@ c = d ;in line comment
class JailReaderTest(LogCaptureTestCase):
def __init__(self, *args, **kwargs):
super(JailReaderTest, self).__init__(*args, **kwargs)
self.__share_cfg = {}
def testIncorrectJail(self):
jail = JailReader('XXXABSENTXXX', basedir=CONFIG_DIR)
jail = JailReader('XXXABSENTXXX', basedir=CONFIG_DIR, share_config = self.__share_cfg)
self.assertRaises(ValueError, jail.read)
def testJailActionEmpty(self):
jail = JailReader('emptyaction', basedir=IMPERFECT_CONFIG)
jail = JailReader('emptyaction', basedir=IMPERFECT_CONFIG, share_config = self.__share_cfg)
self.assertTrue(jail.read())
self.assertTrue(jail.getOptions())
self.assertTrue(jail.isEnabled())
@@ -166,7 +172,7 @@ class JailReaderTest(LogCaptureTestCase):
self.assertTrue(self._is_logged('No actions were defined for emptyaction'))
def testJailActionFilterMissing(self):
jail = JailReader('missingbitsjail', basedir=IMPERFECT_CONFIG)
jail = JailReader('missingbitsjail', basedir=IMPERFECT_CONFIG, share_config = self.__share_cfg)
self.assertTrue(jail.read())
self.assertFalse(jail.getOptions())
self.assertTrue(jail.isEnabled())
@@ -174,7 +180,7 @@ class JailReaderTest(LogCaptureTestCase):
self.assertTrue(self._is_logged('Unable to read the filter'))
def TODOtestJailActionBrokenDef(self):
jail = JailReader('brokenactiondef', basedir=IMPERFECT_CONFIG)
jail = JailReader('brokenactiondef', basedir=IMPERFECT_CONFIG, share_config = self.__share_cfg)
self.assertTrue(jail.read())
self.assertFalse(jail.getOptions())
self.assertTrue(jail.isEnabled())
@@ -185,7 +191,7 @@ class JailReaderTest(LogCaptureTestCase):
if STOCK:
def testStockSSHJail(self):
jail = JailReader('sshd', basedir=CONFIG_DIR) # we are running tests from root project dir atm
jail = JailReader('sshd', basedir=CONFIG_DIR, share_config = self.__share_cfg) # we are running tests from root project dir atm
self.assertTrue(jail.read())
self.assertTrue(jail.getOptions())
self.assertFalse(jail.isEnabled())
@@ -332,16 +338,94 @@ class FilterReaderTest(unittest.TestCase):
filterReader.getOptions(None)
self.assertRaises(ValueError, FilterReader.convert, filterReader)
def testFilterReaderExplicit(self):
# read explicit uses absolute path:
path_ = os.path.abspath(os.path.join(TEST_FILES_DIR, "filter.d"))
filterReader = FilterReader(os.path.join(path_, "testcase01.conf"), "testcase01", {})
self.assertEqual(filterReader.readexplicit(),
[os.path.join(path_, "testcase-common.conf"), os.path.join(path_, "testcase01.conf")]
)
try:
filterReader.getOptions(None)
# from included common
filterReader.get('Definition', '__prefix_line')
# from testcase01
filterReader.get('Definition', 'failregex')
filterReader.get('Definition', 'ignoreregex')
except Exception, e: # pragma: no cover - failed if reachable
self.fail('unexpected options after readexplicit: %s' % (e))
class JailsReaderTestCache(LogCaptureTestCase):
def _readWholeConf(self, basedir, force_enable=False, share_config=None):
# read whole configuration like a file2ban-client ...
configurator = Configurator(force_enable=force_enable, share_config=share_config)
configurator.setBaseDir(basedir)
configurator.readEarly()
configurator.getEarlyOptions()
configurator.readAll()
# from here we test a cache with all includes / before / after :
self.assertTrue(configurator.getOptions(None))
def _getLoggedReadCount(self, filematch):
cnt = 0
for s in self.getLog().rsplit('\n'):
if re.match(r"^\s*Reading files?: .*/"+filematch, s):
cnt += 1
return cnt
def testTestJailConfCache(self):
saved_ll = configparserinc.logLevel
configparserinc.logLevel = logging.DEBUG
basedir = tempfile.mkdtemp("fail2ban_conf")
try:
shutil.rmtree(basedir)
shutil.copytree(CONFIG_DIR, basedir)
shutil.copy(CONFIG_DIR + '/jail.conf', basedir + '/jail.local')
shutil.copy(CONFIG_DIR + '/fail2ban.conf', basedir + '/fail2ban.local')
# common sharing handle for this test:
share_cfg = dict()
# read whole configuration like a file2ban-client ...
self._readWholeConf(basedir, share_config=share_cfg)
# how many times jail.local was read:
cnt = self._getLoggedReadCount('jail.local')
# if cnt > 1:
# self.printLog()
self.assertTrue(cnt == 1, "Unexpected count by reading of jail files, cnt = %s" % cnt)
# read whole configuration like a file2ban-client, again ...
# but this time force enable all jails, to check filter and action cached also:
self._readWholeConf(basedir, force_enable=True, share_config=share_cfg)
cnt = self._getLoggedReadCount(r'jail\.local')
# still one (no more reads):
self.assertTrue(cnt == 1, "Unexpected count by second reading of jail files, cnt = %s" % cnt)
# same with filter:
cnt = self._getLoggedReadCount(r'filter\.d/common\.conf')
self.assertTrue(cnt == 1, "Unexpected count by reading of filter files, cnt = %s" % cnt)
# same with action:
cnt = self._getLoggedReadCount(r'action\.d/iptables-common\.conf')
self.assertTrue(cnt == 1, "Unexpected count by reading of action files, cnt = %s" % cnt)
finally:
shutil.rmtree(basedir)
configparserinc.logLevel = saved_ll
class JailsReaderTest(LogCaptureTestCase):
def __init__(self, *args, **kwargs):
super(JailsReaderTest, self).__init__(*args, **kwargs)
self.__share_cfg = {}
def testProvidingBadBasedir(self):
if not os.path.exists('/XXX'):
reader = JailsReader(basedir='/XXX')
self.assertRaises(ValueError, reader.read)
def testReadTestJailConf(self):
jails = JailsReader(basedir=IMPERFECT_CONFIG)
jails = JailsReader(basedir=IMPERFECT_CONFIG, share_config=self.__share_cfg)
self.assertTrue(jails.read())
self.assertFalse(jails.getOptions())
self.assertRaises(ValueError, jails.convert)
@@ -349,6 +433,11 @@ class JailsReaderTest(LogCaptureTestCase):
self.maxDiff = None
self.assertEqual(sorted(comm_commands),
sorted([['add', 'emptyaction', 'auto'],
['add', 'test-known-interp', 'auto'],
['set', 'test-known-interp', 'addfailregex', 'failure test 1 (filter.d/test.conf) <HOST>'],
['set', 'test-known-interp', 'addfailregex', 'failure test 2 (filter.d/test.local) <HOST>'],
['set', 'test-known-interp', 'addfailregex', 'failure test 3 (jail.local) <HOST>'],
['start', 'test-known-interp'],
['add', 'missinglogfiles', 'auto'],
['set', 'missinglogfiles', 'addfailregex', '<IP>'],
['add', 'brokenaction', 'auto'],
@@ -370,8 +459,24 @@ class JailsReaderTest(LogCaptureTestCase):
self.assertTrue(self._is_logged("No file(s) found for glob /weapons/of/mass/destruction"))
if STOCK:
def testReadStockActionConf(self):
for actionConfig in glob.glob(os.path.join(CONFIG_DIR, 'action.d', '*.conf')):
actionName = os.path.basename(actionConfig).replace('.conf', '')
actionReader = ActionReader(actionName, "TEST", {}, basedir=CONFIG_DIR)
self.assertTrue(actionReader.read())
actionReader.getOptions({}) # populate _opts
if not actionName.endswith('-common'):
self.assertTrue('Definition' in actionReader.sections(),
msg="Action file %r is lacking [Definition] section" % actionConfig)
# all must have some actionban defined
self.assertTrue(actionReader._opts.get('actionban', '').strip(),
msg="Action file %r is lacking actionban" % actionConfig)
self.assertTrue('Init' in actionReader.sections(),
msg="Action file %r is lacking [Init] section" % actionConfig)
def testReadStockJailConf(self):
jails = JailsReader(basedir=CONFIG_DIR) # we are running tests from root project dir atm
jails = JailsReader(basedir=CONFIG_DIR, share_config=self.__share_cfg) # we are running tests from root project dir atm
self.assertTrue(jails.read()) # opens fine
self.assertTrue(jails.getOptions()) # reads fine
comm_commands = jails.convert()
@@ -432,7 +537,7 @@ class JailsReaderTest(LogCaptureTestCase):
# Verify that all filters found under config/ have a jail
def testReadStockJailFilterComplete(self):
jails = JailsReader(basedir=CONFIG_DIR, force_enable=True)
jails = JailsReader(basedir=CONFIG_DIR, force_enable=True, share_config=self.__share_cfg)
self.assertTrue(jails.read()) # opens fine
self.assertTrue(jails.getOptions()) # reads fine
# grab all filter names
@@ -449,7 +554,7 @@ class JailsReaderTest(LogCaptureTestCase):
def testReadStockJailConfForceEnabled(self):
# more of a smoke test to make sure that no obvious surprises
# on users' systems when enabling shipped jails
jails = JailsReader(basedir=CONFIG_DIR, force_enable=True) # we are running tests from root project dir atm
jails = JailsReader(basedir=CONFIG_DIR, force_enable=True, share_config=self.__share_cfg) # we are running tests from root project dir atm
self.assertTrue(jails.read()) # opens fine
self.assertTrue(jails.getOptions()) # reads fine
comm_commands = jails.convert(allow_no_files=True)
@@ -518,7 +623,8 @@ class JailsReaderTest(LogCaptureTestCase):
'/var/lib/fail2ban/fail2ban.sqlite3'],
['set', 'dbpurgeage', 86400],
['set', 'loglevel', "INFO"],
['set', 'logtarget', '/var/log/fail2ban.log']])
['set', 'logtarget', '/var/log/fail2ban.log'],
['set', 'syslogsocket', 'auto']])
# and if we force change configurator's fail2ban's baseDir
# there should be an error message (test visually ;) --
@@ -544,7 +650,7 @@ action = testaction1[actname=test1]
filter = testfilter1
""")
jailfd.close()
jails = JailsReader(basedir=basedir)
jails = JailsReader(basedir=basedir, share_config=self.__share_cfg)
self.assertTrue(jails.read())
self.assertTrue(jails.getOptions())
comm_commands = jails.convert(allow_no_files=True)
+6
View File
@@ -0,0 +1,6 @@
#[INCLUDES]
#before = common.conf
[Definition]
failregex = failure test 1 (filter.d/test.conf) <HOST>
@@ -0,0 +1,7 @@
#[INCLUDES]
#before = common.conf
[Definition]
failregex = %(known/failregex)s
failure test 2 (filter.d/test.local) <HOST>
+6
View File
@@ -13,6 +13,12 @@ failregex = <IP>
ignoreregex =
ignoreip =
[test-known-interp]
enabled = true
filter = test
failregex = %(known/failregex)s
failure test 3 (jail.local) <HOST>
[missinglogfiles]
enabled = true
logpath = /weapons/of/mass/destruction
+52 -1
View File
@@ -32,18 +32,21 @@ import shutil
from ..server.filter import FileContainer
from ..server.mytime import MyTime
from ..server.ticket import FailTicket
from ..server.actions import Actions
from .dummyjail import DummyJail
try:
from ..server.database import Fail2BanDb
except ImportError:
Fail2BanDb = None
from .utils import LogCaptureTestCase
TEST_FILES_DIR = os.path.join(os.path.dirname(__file__), "files")
class DatabaseTest(unittest.TestCase):
class DatabaseTest(LogCaptureTestCase):
def setUp(self):
"""Call before every test case."""
super(DatabaseTest, self).setUp()
if Fail2BanDb is None and sys.version_info >= (2,7): # pragma: no cover
raise unittest.SkipTest(
"Unable to import fail2ban database module as sqlite is not "
@@ -55,6 +58,7 @@ class DatabaseTest(unittest.TestCase):
def tearDown(self):
"""Call after every test case."""
super(DatabaseTest, self).tearDown()
if Fail2BanDb is None: # pragma: no cover
return
# Cleanup
@@ -173,6 +177,37 @@ class DatabaseTest(unittest.TestCase):
self.assertTrue(
isinstance(self.db.getBans(jail=self.jail)[0], FailTicket))
def testAddBanInvalidEncoded(self):
if Fail2BanDb is None: # pragma: no cover
return
self.testAddJail()
# invalid + valid, invalid + valid unicode, invalid + valid dual converted (like in filter:readline by fallback) ...
tickets = [
FailTicket("127.0.0.1", 0, ['user "\xd1\xe2\xe5\xf2\xe0"', 'user "\xc3\xa4\xc3\xb6\xc3\xbc\xc3\x9f"']),
FailTicket("127.0.0.2", 0, ['user "\xd1\xe2\xe5\xf2\xe0"', u'user "\xc3\xa4\xc3\xb6\xc3\xbc\xc3\x9f"']),
FailTicket("127.0.0.3", 0, ['user "\xd1\xe2\xe5\xf2\xe0"', b'user "\xc3\xa4\xc3\xb6\xc3\xbc\xc3\x9f"'.decode('utf-8', 'replace')])
]
self.db.addBan(self.jail, tickets[0])
self.db.addBan(self.jail, tickets[1])
self.db.addBan(self.jail, tickets[2])
readtickets = self.db.getBans(jail=self.jail)
self.assertEqual(len(readtickets), 3)
## python 2 or 3 :
invstr = u'user "\ufffd\ufffd\ufffd\ufffd\ufffd"'.encode('utf-8', 'replace')
self.assertTrue(
readtickets[0] == FailTicket("127.0.0.1", 0, [invstr, 'user "\xc3\xa4\xc3\xb6\xc3\xbc\xc3\x9f"'])
or readtickets[0] == tickets[0]
)
self.assertTrue(
readtickets[1] == FailTicket("127.0.0.2", 0, [invstr, u'user "\xc3\xa4\xc3\xb6\xc3\xbc\xc3\x9f"'.encode('utf-8', 'replace')])
or readtickets[1] == tickets[1]
)
self.assertTrue(
readtickets[2] == FailTicket("127.0.0.3", 0, [invstr, 'user "\xc3\xa4\xc3\xb6\xc3\xbc\xc3\x9f"'])
or readtickets[2] == tickets[2]
)
def testDelBan(self):
self.testAddBan()
ticket = self.db.getBans(jail=self.jail)[0]
@@ -267,6 +302,22 @@ class DatabaseTest(unittest.TestCase):
tickets = self.db.getBansMerged(bantime=-1)
self.assertEqual(len(tickets), 2)
def testActionWithDB(self):
# test action together with database functionality
self.testAddJail() # Jail required
self.jail.database = self.db;
actions = Actions(self.jail)
actions.add(
"action_checkainfo",
os.path.join(TEST_FILES_DIR, "action.d/action_checkainfo.py"),
{})
ticket = FailTicket("1.2.3.4", MyTime.time(), ['test', 'test'])
ticket.setAttempt(5)
self.jail.putFailTicket(ticket)
actions._Actions__checkBan()
self.assertTrue(self._is_logged("ban ainfo %s, %s, %s, %s" % (True, True, True, True)))
def testPurge(self):
if Fail2BanDb is None: # pragma: no cover
return
+1
View File
@@ -86,6 +86,7 @@ class DateDetectorTest(unittest.TestCase):
(False, "23-Jan-2005 21:59:59.02"),
(False, "23-Jan-2005 21:59:59 +0100"),
(False, "23-01-2005 21:59:59"),
(True, "1106513999"), # Portsetry
(False, "01-23-2005 21:59:59.252"), # reported on f2b, causes Feb29 fix to break
(False, "@4000000041f4104f00000000"), # TAI64N
(False, "2005-01-23T20:59:59.252Z"), #ISO 8601 (UTC)
@@ -0,0 +1,14 @@
from fail2ban.server.action import ActionBase
class TestAction(ActionBase):
def ban(self, aInfo):
self._logSys.info("ban ainfo %s, %s, %s, %s",
aInfo["ipmatches"] != '', aInfo["ipjailmatches"] != '', aInfo["ipfailures"] > 0, aInfo["ipjailfailures"] > 0
)
def unban(self, aInfo):
pass
Action = TestAction

Some files were not shown because too many files have changed in this diff Show More