Compare commits

...
51 Commits
Author SHA1 Message Date
Cyril Jaquier 0175d01419 - Added license in COPYING. Thanks to Axel Thimm
git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/branches/FAIL2BAN-0_6@508 a942ae1a-1317-0410-a47c-b1dcaea8d605
2007-01-03 18:18:31 +00:00
Cyril Jaquier 2a1a4b467b - Added contributor
git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/branches/FAIL2BAN-0_6@507 a942ae1a-1317-0410-a47c-b1dcaea8d605
2007-01-03 18:18:01 +00:00
Cyril Jaquier 3252b15890 - Fixed removal of host in hosts.deny. Thanks to René Berber
git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/branches/FAIL2BAN-0_6@497 a942ae1a-1317-0410-a47c-b1dcaea8d605
2006-12-19 21:51:28 +00:00
Cyril Jaquier ef0bf70ba3 - Send SIGTERM instead of SIGINT when using "-k"
git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/branches/FAIL2BAN-0_6@492 a942ae1a-1317-0410-a47c-b1dcaea8d605
2006-12-18 21:49:10 +00:00
Cyril Jaquier 3ba3346dec - Update for release (0.6.2)
git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/branches/FAIL2BAN-0_6@486 a942ae1a-1317-0410-a47c-b1dcaea8d605
2006-12-11 21:43:57 +00:00
Cyril Jaquier ed0f57dbad - Added pydev project file
git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/branches/FAIL2BAN-0_6@485 a942ae1a-1317-0410-a47c-b1dcaea8d605
2006-12-11 21:14:58 +00:00
Cyril Jaquier 0a8f24c5f4 - Added named group "host" for "failregex"
- Fixed vulnerability CVE-2006-6302

git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/branches/FAIL2BAN-0_6@484 a942ae1a-1317-0410-a47c-b1dcaea8d605
2006-12-10 21:16:26 +00:00
Cyril Jaquier 8a253db9b5 - Propagated patches from Yaroslav Halchenko
git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/branches/FAIL2BAN-0_6@449 a942ae1a-1317-0410-a47c-b1dcaea8d605
2006-11-06 22:43:42 +00:00
Cyril Jaquier adf7827efd - Added Eclipse project
git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/branches/FAIL2BAN-0_6@448 a942ae1a-1317-0410-a47c-b1dcaea8d605
2006-11-06 22:35:06 +00:00
Cyril Jaquier bfbf8a70d2 - Updated
git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/branches/FAIL2BAN-0_6@248 a942ae1a-1317-0410-a47c-b1dcaea8d605
2006-03-19 18:35:21 +00:00
Cyril Jaquier 089770d1c0 - Fixed UTF-8 log file reading
git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/branches/FAIL2BAN-0_6@247 a942ae1a-1317-0410-a47c-b1dcaea8d605
2006-03-19 18:30:33 +00:00
Cyril Jaquier 2304f07a38 - Fixed logfile path
git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/branches/FAIL2BAN-0_6@245 a942ae1a-1317-0410-a47c-b1dcaea8d605
2006-03-17 16:28:46 +00:00
Cyril Jaquier 22995edd97 This commit was manufactured by cvs2svn to create branch 'FAIL2BAN-0_6'.
git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/branches/FAIL2BAN-0_6@244 a942ae1a-1317-0410-a47c-b1dcaea8d605
2006-03-15 23:07:12 +00:00
Cyril Jaquier 97aa913e24 - Updated for 0.6.1
git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/trunk@243 a942ae1a-1317-0410-a47c-b1dcaea8d605
2006-03-15 23:07:12 +00:00
Cyril Jaquier cbc18112bf - Updated
git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/trunk@242 a942ae1a-1317-0410-a47c-b1dcaea8d605
2006-02-21 12:46:58 +00:00
Cyril Jaquier b659cb2c2a - Updated
git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/trunk@241 a942ae1a-1317-0410-a47c-b1dcaea8d605
2006-02-13 21:37:44 +00:00
Cyril Jaquier 293f077d7b - Updated
git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/trunk@240 a942ae1a-1317-0410-a47c-b1dcaea8d605
2006-02-12 18:15:44 +00:00
Cyril Jaquier 83ea17fd24 - Updated
git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/trunk@239 a942ae1a-1317-0410-a47c-b1dcaea8d605
2006-02-12 12:30:39 +00:00
Cyril Jaquier dfb6f63753 - Updated
git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/trunk@238 a942ae1a-1317-0410-a47c-b1dcaea8d605
2006-02-11 15:30:04 +00:00
Cyril Jaquier 7e24b948bf - Added vsftpd support. Thanks to zugeschmiert
git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/trunk@237 a942ae1a-1317-0410-a47c-b1dcaea8d605
2006-02-11 15:29:32 +00:00
Cyril Jaquier 054d18dd28 - Updated with ideas for 0.7
git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/trunk@236 a942ae1a-1317-0410-a47c-b1dcaea8d605
2006-02-10 10:26:16 +00:00
Cyril Jaquier d29648d4de - Added a more robust firewall initialization loop. Thanks to Yaroslav Halchenko
git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/trunk@235 a942ae1a-1317-0410-a47c-b1dcaea8d605
2006-01-22 11:10:29 +00:00
Cyril Jaquier ad4280d506 - Updated
git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/trunk@234 a942ae1a-1317-0410-a47c-b1dcaea8d605
2006-01-22 11:08:42 +00:00
Cyril Jaquier de7acd4d6c - Added support for shorewall and hosts.deny
- Renamed fail2ban.conf.default to fail2ban.conf.iptables


git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/trunk@233 a942ae1a-1317-0410-a47c-b1dcaea8d605
2006-01-22 11:07:22 +00:00
Cyril Jaquier 3e86a8204b - Removed 192.168.0.0/16 from ignoreip
git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/trunk@232 a942ae1a-1317-0410-a47c-b1dcaea8d605
2006-01-12 16:20:00 +00:00
Cyril Jaquier 1044b82e12 - Removed debug option
- Added SMTP authentification support
- Changed syslog output to a more standard format


git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/trunk@231 a942ae1a-1317-0410-a47c-b1dcaea8d605
2006-01-03 15:16:22 +00:00
Cyril Jaquier 79318b3549 - Updated
git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/trunk@230 a942ae1a-1317-0410-a47c-b1dcaea8d605
2006-01-03 15:14:27 +00:00
Cyril Jaquier 6386c9e580 - Added SMTP authentification support
git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/trunk@229 a942ae1a-1317-0410-a47c-b1dcaea8d605
2006-01-03 15:13:41 +00:00
Cyril Jaquier 85f1d74d85 - Removed debug option
git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/trunk@228 a942ae1a-1317-0410-a47c-b1dcaea8d605
2006-01-03 15:13:24 +00:00
Cyril Jaquier fb07353aeb - Added TAI64N support
git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/trunk@227 a942ae1a-1317-0410-a47c-b1dcaea8d605
2006-01-03 15:13:04 +00:00
Cyril Jaquier be26cd5b75 - Removed debug option
- Added SMTP authentification support
- Added TAI64N support


git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/trunk@226 a942ae1a-1317-0410-a47c-b1dcaea8d605
2006-01-03 15:11:57 +00:00
Yaroslav Halchenko 3eb0ca0ee5 propagated fix for the path bug. Thanks to Nick Craig-Wood
git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/trunk@225 a942ae1a-1317-0410-a47c-b1dcaea8d605
2005-12-27 15:09:50 +00:00
Cyril Jaquier 7494fe283b - Updated
git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/trunk@224 a942ae1a-1317-0410-a47c-b1dcaea8d605
2005-12-16 23:51:59 +00:00
Cyril Jaquier 9cd787c50e - Fixed crash when time format does not match data
git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/trunk@223 a942ae1a-1317-0410-a47c-b1dcaea8d605
2005-12-16 23:50:59 +00:00
Cyril Jaquier 15806fc3da - Added permanent banning feature
git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/trunk@222 a942ae1a-1317-0410-a47c-b1dcaea8d605
2005-12-16 23:48:52 +00:00
Cyril Jaquier 716e0840fc - Removed unneeded semicolon
git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/trunk@221 a942ae1a-1317-0410-a47c-b1dcaea8d605
2005-12-16 23:47:03 +00:00
Cyril Jaquier cd38dddd00 - Fixed locale bug. Thanks to Fernando Jos�
git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/trunk@220 a942ae1a-1317-0410-a47c-b1dcaea8d605
2005-12-16 23:44:34 +00:00
Cyril Jaquier 52e7a26756 - Updated to CVS version
git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/trunk@219 a942ae1a-1317-0410-a47c-b1dcaea8d605
2005-12-16 23:44:06 +00:00
Cyril Jaquier af827330b2 - Updated
git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/trunk@218 a942ae1a-1317-0410-a47c-b1dcaea8d605
2005-12-16 23:43:46 +00:00
Cyril Jaquier 840f6cd052 - Merged FAIL2BAN-0_5 with HEAD
git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/trunk@216 a942ae1a-1317-0410-a47c-b1dcaea8d605
2005-11-20 17:07:47 +00:00
Cyril Jaquier 07d127bebd - Added an initd script for RedHat/Fedora. Thanks to Andrey G. Grozin
git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/trunk@113 a942ae1a-1317-0410-a47c-b1dcaea8d605
2005-07-01 09:30:52 +00:00
Cyril Jaquier 73ff1540e8 - Prepared for 0.4.1
git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/trunk@111 a942ae1a-1317-0410-a47c-b1dcaea8d605
2005-06-30 09:30:59 +00:00
Cyril Jaquier be43f2eaeb - Changed PID lock file location from /tmp to /var/run
git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/trunk@110 a942ae1a-1317-0410-a47c-b1dcaea8d605
2005-06-30 09:26:38 +00:00
Cyril Jaquier 7b118f42d3 - Initd script for Gentoo
git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/trunk@109 a942ae1a-1317-0410-a47c-b1dcaea8d605
2005-06-30 09:25:28 +00:00
Cyril Jaquier 9317581b18 - Modified for readability. Thanks to Iain Lea
git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/trunk@108 a942ae1a-1317-0410-a47c-b1dcaea8d605
2005-06-29 06:17:28 +00:00
Cyril Jaquier 51f1dcee55 - Fixed textToDNS method which generated wrong matches for "rhost=12-xyz...". Thanks to Tom Pike
git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/trunk@107 a942ae1a-1317-0410-a47c-b1dcaea8d605
2005-05-28 19:46:18 +00:00
Cyril Jaquier a051e05cb4 - Prepared for 0.4.0 release
git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/trunk@105 a942ae1a-1317-0410-a47c-b1dcaea8d605
2005-04-24 11:04:29 +00:00
Cyril Jaquier b0cae2c43f - Changed all sections to disabled by default
- Add "Invalid user" to SSH failregex


git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/trunk@104 a942ae1a-1317-0410-a47c-b1dcaea8d605
2005-04-24 11:03:44 +00:00
Cyril Jaquier 468f70dc15 - Changed to CVS version
git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/trunk@103 a942ae1a-1317-0410-a47c-b1dcaea8d605
2005-04-03 12:13:11 +00:00
Cyril Jaquier 0c9c50397a - Fixed bug in utils/dns.py
git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/trunk@102 a942ae1a-1317-0410-a47c-b1dcaea8d605
2005-04-03 12:12:52 +00:00
Cyril Jaquier a4ff90cd0a - Fixed textToDNS method which did not recognize "12-344-54-33.adsl.xyz.ab". Thanks to K�vin Drapel
git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/trunk@101 a942ae1a-1317-0410-a47c-b1dcaea8d605
2005-04-03 12:08:57 +00:00
33 changed files with 3191 additions and 803 deletions
+17
View File
@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>fail2ban-stable</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.python.pydev.PyDevBuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.python.pydev.pythonNature</nature>
</natures>
</projectDescription>
+12
View File
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?eclipse-pydev version="1.0"?>
<pydev_project>
<pydev_property name="org.python.pydev.PYTHON_PROJECT_VERSION">python 2.4</pydev_property>
<pydev_pathproperty name="org.python.pydev.PROJECT_SOURCE_PATH">
<path>/fail2ban-stable/confreader</path>
<path>/fail2ban-stable/firewall</path>
<path>/fail2ban-stable/logreader</path>
<path>/fail2ban-stable/utils</path>
</pydev_pathproperty>
</pydev_project>
+161 -6
View File
@@ -4,17 +4,172 @@
|_| \__,_|_|_/___|_.__/\__,_|_||_|
=============================================================
Fail2Ban (version 0.3.1) 31/03/2005
Fail2Ban (version 0.6.3) 200?/??/??
=============================================================
ver. 0.3.1 (03/31/2005) - beta
ver. 0.6.3 (200?/??/??) - stable
----------
- Send SIGTERM instead of SIGINT when using "-k"
- Fixed removal of host in hosts.deny. Thanks to René Berber
- Added license in COPYING. Thanks to Axel Thimm
ver. 0.6.2 (2006/12/11) - stable
----------
- Fixed UTF-8 log file parsing
- Propagated patches introduced by Debian maintainer
(Yaroslav Halchenko):
* Made locale configurable
* Fixed warning if ignoreip is empty
- Added named group "host" for "failregex". Fixed security
vulnerability CVE-2006-6302
ver. 0.6.1 (2006/03/16) - stable
----------
- Added permanent banning. Set banTime to a negative value to
enable this feature (-1 is perfect). Thanks to Mannone
- Fixed locale bug. Thanks to Fernando José
- Fixed crash when time format does not match data
- Propagated patch from Debian to fix fail2ban search path
addition to the path search list: now it is added first.
Thanks to Nick Craig-Wood
- Added SMTP authentification for mail notification. Thanks
to Markus Hoffmann
- Removed debug mode as it is confusing for people
- Added parsing of timestamp in TAI64N format (#1275325).
Thanks to Mark Edgington
- Added patch #1382936 (Default formatted syslog logging).
Thanks to Patrick B�rjesson
- Removed 192.168.0.0/16 from ignoreip. Attacks could also
come from the local network.
- Robust startup: if iptables module does not get fully
initialized after startup of fail2ban, fail2ban will do
"maxreinit" attempts to initialize its own firewall. It
will sleep between attempts for "polltime" number of
seconds (closes Debian: #334272). Thanks to Yaroslav
Halchenko
- Added "interpolations" in fail2ban.conf. This is provided
by the ConfigParser module. Old configuration files still
work. Thanks to Yaroslav Halchenko
- Added initial support for hosts.deny and shorewall. Need
more testing. Please test. Thanks to kojiro from Gentoo
forum for hosts.deny support
- Added support for vsftpd. Thanks to zugeschmiert
ver. 0.6.0 (2005/11/20) - stable
----------
- Propagated patches introduced by Debian maintainer
(Yaroslav Halchenko):
* Added an option to report local time (including timezone)
or GMT in mail notification.
ver. 0.5.5 (2005/10/26) - beta
----------
- Propagated patches introduced by Debian maintainer
(Yaroslav Halchenko):
* Introduced fwcheck option to verify consistency of the
chains. Implemented automatic restart of fail2ban main
function in case check of fwban or fwunban command failed
(closes: #329163, #331695). (Introduced patch was further
adjusted by upstream author).
* Added -f command line parameter for [findtime].
* Added a cleanup of firewall rules on emergency shutdown
when unknown exception is catched.
* Fail2ban should not crash now if a wrong file name is
specified in config.
* reordered code a bit so that log targets are setup right
after background and then only loglevel (verbose, debug)
is processed, so the warning could be seen in the logs
* Added a keyword <section> in parsing of the subject and
the body of an email sent out by fail2ban (closes:
#330311)
ver. 0.5.4 (2005/09/13) - beta
----------
- Fixed bug #1286222.
- Propagated patches introduced by Debian maintainer
(Yaroslav Halchenko):
* Fixed handling of SYSLOG logging target. Now it can log
to any SYSLOG target and facility as directed by the
config
* Format of SYSLOG entries fixed to look closer to standard
* Fixed errata in config/gentoo-confd
* Introduced findtime configuration variable to control the
lifetime of caught "failed" log entries
ver. 0.5.3 (2005/09/08) - beta
----------
- Fixed a bug when overriding "maxfailures" or "bantime".
Thanks to Yaroslav Halchenko
- Added more debug output if an error occurs when sending
mail. Thanks to Stephen Gildea
- Renamed "maxretry" to "maxfailures" and changed default
value to 5. Thanks to Stephen Gildea
- Hopefully fixed bug #1256075
- Fixed bug #1262345
- Fixed exception handling in PIDLock
- Removed warning when using "-V" or "-h" with no config
file. Thanks to Yaroslav Halchenko
- Removed "-i eth0" from config file. Thanks to Yaroslav
Halchenko
ver. 0.5.2 (2005/08/06) - beta
----------
- Better PID lock file handling. Should close #1239562
- Added man pages
- Removed log4py dependency. Use logging module instead
- "maxretry" and "bantime" can be overridden in each section
- Fixed bug #1246278 (excessive memory usage)
- Fixed crash on wrong option value in configuration file
- Changed custom chains to lowercase
ver. 0.5.1 (2005/07/23) - beta
----------
- Fixed bugs #1241756, #1239557
- Added log targets in configuration file. Removed -l option
- Changed iptables rules in order to create a separated chain
for each section
- Fixed static banList in firewall.py
- Added an initd script for Debian. Thanks to Yaroslav
Halchenko
- Check for obsolete files after install
ver. 0.5.0 (2005/07/12) - beta
----------
- Added support for CIDR mask in ignoreip
- Added mail notification support
- Fixed bug #1234699
- Added tags replacement in rules definition. Should allow a
clean solution for Feature Request #1229479
- Removed "interface" and "firewall" options
- Added start and end commands in the configuration file.
Thanks to Yaroslav Halchenko
- Added firewall rules definition in the configuration file
- Cleaned fail2ban.py
- Added an initd script for RedHat/Fedora. Thanks to Andrey
G. Grozin
ver. 0.4.1 (2005/06/30) - stable
----------
- Fixed textToDNS method which generated wrong matches for
"rhost=12-xyz...". Thanks to Tom Pike
- fail2ban.conf modified for readability. Thanks to Iain Lea
- Added an initd script for Gentoo
- Changed default PID lock file location from /tmp to
/var/run
ver. 0.4.0 (2005/04/24) - stable
----------
- Fixed textToDNS which did not recognize strings like
"12-345-67-890.abcd.mnopqr.xyz"
ver. 0.3.1 (2005/03/31) - beta
----------
- Corrected level of messages
- Added DNS lookup support
- Improved parsing speed. Only parse the new log messages
- Added a second verbose level (-vv)
ver. 0.3.0 (02/24/2005) - beta
ver. 0.3.0 (2005/02/24) - beta
----------
- Re-writting of parts of the code in order to handle several
log files with different rules
@@ -25,7 +180,7 @@ ver. 0.3.0 (02/24/2005) - beta
- Added ipfw-start-rule option (thanks to Robert Edeker)
- Added -k option which kills a currently running Fail2Ban
ver. 0.1.2 (11/21/2004) - beta
ver. 0.1.2 (2004/11/21) - beta
----------
- Add ipfw and ipfwadm support. The rules are taken from
BlockIt. Thanks to Robert Edeker
@@ -33,7 +188,7 @@ ver. 0.1.2 (11/21/2004) - beta
Robert Edeker who reminded me this
- Small code cleaning
ver. 0.1.1 (10/23/2004) - beta
ver. 0.1.1 (2004/10/23) - beta
----------
- Add SIGTERM handler in order to exit nicely when in daemon
mode
@@ -47,6 +202,6 @@ ver. 0.1.1 (10/23/2004) - beta
- Code documentation
ver. 0.1.0 (10/12/2004) - alpha
ver. 0.1.0 (2004/10/12) - alpha
----------
- Initial release
+339
View File
@@ -0,0 +1,339 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.
+15 -4
View File
@@ -1,19 +1,30 @@
README
CHANGELOG
TODO
COPYING
setup.cfg
setup.py
version.py
fail2ban
fail2ban.py
firewall/__init__.py
firewall/firewall.py
firewall/iptables.py
firewall/ipfw.py
firewall/ipfwadm.py
logreader/__init__.py
logreader/logreader.py
confreader/__init__.py
confreader/configreader.py
utils/__init__.py
utils/dns.py
config/fail2ban.conf.default
utils/process.py
utils/mail.py
utils/strings.py
utils/pidlock.py
config/fail2ban.conf.iptables
config/fail2ban.conf.shorewall
config/fail2ban.conf.hostsdeny
config/gentoo-initd
config/gentoo-confd
config/redhat-initd
config/debian-initd
man/fail2ban.8
man/fail2ban.conf.5
+62 -35
View File
@@ -4,18 +4,17 @@
|_| \__,_|_|_/___|_.__/\__,_|_||_|
=============================================================
Fail2Ban (version 0.3.1) 03/31/2005
Fail2Ban (version 0.6.2) 2006/12/11
=============================================================
Fail2Ban scans log files like /var/log/pwdfail and bans IP
that makes too many password failures. It updates firewall
rules to reject the IP address. Currently iptables, ipfw and
ipfwadm are supported. Fail2Ban can read multiple log files
such as sshd or Apache web server ones. It needs log4py.
rules to reject the IP address. These rules can be defined by
the user. Fail2Ban can read multiple log files such as sshd
or Apache web server ones.
This is my first Python program. I began learning Python for
less than one week so please be understanding ;-) English is
not either my mother tongue...
This is my first Python program. Moreover, English is not my
mother tongue...
More details:
@@ -28,8 +27,8 @@ brute force or scripts. They try 10, 20 and sometimes more
user/password (without success anyway). In order to
discourage these script kiddies, I wanted that sshd refuse
login from a specific ip after 3 password failures. After
some google searches, I found that sshd was not able of that.
So I search for a script or program that do it. Found
some Google searches, I found that sshd was not able of that.
So I search for a script or program that do it. I found
nothing :-( So I decide to write mine and to learn Python :-)
For each sections defined in the configuration file, Fail2Ban
@@ -37,43 +36,65 @@ tries to find lines which match the failregex. Then it
retrieves the message time using timeregex and timepattern.
It finally gets the ip and if it has already done 3 or more
password failures in the last banTime, the ip is banned for
banTime using a iptable rule. After banTime, the rule is
deleted. Notice that if no "plain" ip is available, Fail2Ban
try to do DNS lookup in order to found one or several ip's to
ban.
banTime using a firewall rule. This rule is set by the user
in the configuration file. Thus, Fail2Ban can be adapted for
lots of firewall. After banTime, the rule is deleted. Notice
that if no "plain" ip is available, Fail2Ban try to do DNS
lookup in order to found one or several ip's to ban.
Sections can be freely added so it is possible to monitor
several daemons at the same time.
Runs on my server and does its job rather well :-) The idea
is to make fail2ban usable with daemons and services that
require a login (sshd, telnetd, ...). It should also support
others firewalls than iptables.
require a login (sshd, telnetd, ...) and with different
firewalls.
Installation:
-------------
Require: python-2.3 (http://www.python.org)
log4py-1.1 (http://sourceforge.net/projects/log4py)
Require: python-2.4 (http://www.python.org)
To install, just do:
> tar xvfj fail2ban-0.3.1.tar.bz2
> cd fail2ban-0.3.1
> tar xvfj fail2ban-0.6.2.tar.bz2
> cd fail2ban-0.6.2
> python setup.py install
This will install Fail2Ban into /usr/lib/fail2ban. The
fail2ban.py executable is placed into /usr/bin.
fail2ban executable is placed into /usr/bin.
Gentoo: ebuilds are available on the website.
Debian: Fail2Ban is in Debian unstable.
RedHat: packages are available on the website.
Fail2Ban should now be correctly installed. Just type:
> fail2ban.py -h
> fail2ban -h
to see if everything is alright. You can configure fail2ban
with a config file. Copy config/fail2ban.conf.default to
/etc/fail2ban.conf.
with a config file. Different kind of configuration files are
available:
iptables: copy config/fail2ban.conf.iptables to
/etc/fail2ban.conf
hosts.deny: copy config/fail2ban.conf.hostsdeny to
/etc/fail2ban.conf
shorewall: copy config/fail2ban.conf.shorewall to
/etc/fail2ban.conf
Do not forget to edit fail2ban.conf to meet your needs.
You can use the initd script available in config/. Copy
<dist>-initd to /etc/init.d/fail2ban. Gentoo users must copy
gentoo-confd to /etc/conf.d/fail2ban. You can start fail2ban:
> /etc/init.d/fail2ban start
Gentoo users can add it to the default runlevel:
> rc-update add fail2ban default
Configuration:
--------------
@@ -83,20 +104,23 @@ or using command line options. Command line options override
the value stored in fail2ban.conf. Here are the command line
options:
-b start fail2ban in background
-d start fail2ban in debug mode
-e <INTF> ban IP on the INTF interface
-b start in background
-c <FILE> read configuration file FILE
-p <FILE> create PID lock in FILE
-h display this help message
-i <IP(s)> IP(s) to ignore
-k kill a currently running Fail2Ban instance
-l <FILE> log message in FILE
-r <VALUE> allow a max of VALUE password failure
-t <TIME> ban IP for TIME seconds
-k kill a currently running instance
-r <VALUE> allow a max of VALUE password failure [maxfailures]
-t <TIME> ban IP for TIME seconds [bantime]
-f <TIME> lifetime in seconds of failed entry [findtime]
-v verbose. Use twice for greater effect
-w <FIWA> select the firewall to use. Can be iptables,
ipfwadm or ipfw
-V print software version
Please note that a vulnerability (CVE-2006-6302) affects
version < 0.6.2. Since 0.6.2, a named group "host" was added
to "failregex". This group must match the host address. Old
configuration files will still work but will generate a
warning. In this case, please update your configuration file.
Contact:
--------
@@ -104,7 +128,7 @@ Contact:
You need some new features, you found bugs or you just
appreciate this program, you can contact me at :
Website: http://www.sourceforge.net/projects/fail2ban
Website: http://fail2ban.sourceforge.net
Cyril Jaquier: <lostcontrol@users.sourceforge.net>
@@ -112,8 +136,11 @@ Cyril Jaquier: <lostcontrol@users.sourceforge.net>
Thanks:
-------
Kévin Drapel, Marvin Rouge, Sireyessire, Robert Edeker
Kévin Drapel, Marvin Rouge, Sireyessire, Robert Edeker,
Tom Pike, Iain Lea, Andrey G. Grozin, Yaroslav Halchenko,
Jonathan Kamens, Stephen Gildea, Markus Hoffmann, Mark
Edgington, Patrick Börjesson, kojiro, zugeschmiert, René
Berber, Nils Breunese
License:
--------
+87 -7
View File
@@ -4,12 +4,92 @@
|_| \__,_|_|_/___|_.__/\__,_|_||_|
=============================================================
ToDo
ToDo $Revision$
=============================================================
- cleanup fail2ban.py
- improve configuration file and command line options
handling
- improve installation process
- add init script
- use FAM (inotify, gamin, ...)
See Feature Request Tracking System at SourceForge.net
- improve installation process (better prefix support)
- improve documentation and website for user
- use Doxygen
- use PyLint to check the code
- better configuration files
- add a check to see if the time of the log messages is
correctly detected (valid regexp)
- use Gentoo Portage style for scripts.
- banning engines script in /etc/fail2ban/scripts.d
Example: /etc/fail2ban/scripts.d/iptables
Will be mostly bash scripting which is more "user
friendly".
- split configuration files in /etc/fail2ban/services.d
for log files
Example: /etc/fail2ban/services.d/apache
Mainly regular expressions.
- template for common regex in /etc/fail2ban/templates.d
Example: /etc/fail2ban/templates.d/date
Mainly regular expressions.
- remove debug mode (root check)
- better return values in function
- use more email.Utils in mail.py
- add gettext support. Is this really needed for a server
utility?
- send an email when fail2ban is running
- add multithreading. Python threading is not really
efficient. However, fail2ban could benefit of it. We could
use threads like this:
- one thread which check for host to unban.
- one thread per file to watch. This will allow things like
different polling time for each file.
<srv> is read-only (we only read log files) thus no locks
are required. However, <meth> is read-write and must take
care of concurrency in case of multithreading.
- add FAM/Gamin support. Should be quite efficient with
threading. Take care that handle_one_event() release the
Python lock.
- add a test framework. We could use unittest which is in
Python since 2.1. It should be possible to run all tests
automatically.
- add client/server using socket. Something similar to
gdesklets. DBUS seems to be designed for desktop use.
- fail2ban start -> start the daemon.
- fail2ban stop -> stop the daemon.
- fail2ban add <srv> <meth> -> add <srv> monitoring with
<meth> ban method (iptables, hosts.deny, etc).
- fail2ban del <srv> -> remove <srv> monitoring.
- fail2ban status <srv> -> query current fail2ban status.
Should return infos like a ban counter. Could be graph
with rrdtool.
- fail2ban pause <srv> -> suspend monitoring.
- fail2ban resume <srv> -> resume monitoring.
- fail2ban list -> list available services.
- fail2ban flush <srv> -> flush the <srv> ban list.
- remove PID file.
- remove most of the command lines options if possible.
- add the possibility to specify wildcard in log files.
Example: logfile = /var/log/apache2/access-*.log
Should we start one thread per file or just one thread per
serivce?
- autodetect date format in log file. Match the most popular
format and sort them using the hit ratio. Should avoid
user problem with regex and not have a big impact on perfs.
- restart automatically the daemon if an exception occurs.
+73
View File
@@ -0,0 +1,73 @@
#! /bin/sh
#
# Fail2Ban init.d file - to be launched on boot
#
# Written by Miquel van Smoorenburg <miquels@cistron.nl>.
# Modified for Debian
# by Ian Murdock <imurdock@gnu.ai.mit.edu>.
# Adjusted for Fail2Ban
# by Yaroslav Halchenko <debian@onerussian.com>.
#
# Version: $Id$
#
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
DAEMON=/usr/bin/fail2ban
NAME=fail2ban
DESC=fail2ban
PIDFILE=/var/run/$NAME.pid
test -x $DAEMON || exit 0
# Include fail2ban defaults if available
if [ -f /etc/default/fail2ban ] ; then
. /etc/default/fail2ban
fi
DAEMON_OPTS=$FAIL2BAN_OPTS
set -e
case "$1" in
start)
echo -n "Starting $DESC: "
[ -f $PIDFILE ] && [ ! -d /proc/`cat $PIDFILE` ] && rm -f $PIDFILE
start-stop-daemon --start --quiet --pidfile $PIDFILE \
-b --exec $DAEMON -- $DAEMON_OPTS
echo "$NAME."
;;
stop)
echo -n "Stopping $DESC: "
start-stop-daemon --stop --quiet --pidfile $PIDFILE
echo "$NAME."
;;
restart|force-reload)
echo -n "Restarting $DESC: "
( $0 stop )
sleep 1
$0 start
;;
status)
echo -n "Status of $DESC: "
if [ ! -e "$PIDFILE" ]; then
echo "$NAME is not running."
exit 3
fi
if [ ! -r "$PIDFILE" ]; then
echo "$PIDFILE not readable, status of $NAME unknown."
exit 4
fi
if [ -d /proc/`cat "$PIDFILE"` ]; then
echo "$NAME is running."
exit 0
else
echo "$NAME is not running but $PIDFILE exists."
exit 1
fi
;;
*)
N=/etc/init.d/$NAME
echo "Usage: $N {start|stop|restart|force-reload|status}" >&2
exit 1
;;
esac
exit 0
-96
View File
@@ -1,96 +0,0 @@
# Fail2Ban configuration file
#
# $Revision$
[DEFAULT]
# firewall: select the firewall system to use. Actually,
# the available options are: iptables, ipfwadm, ipfw
firewall = iptables
# ipfw-start-rule: set the first rule number used by Fail2Ban.
# This option is only used if firewall = ipfw.
ipfw-start-rule = 100
# background: true to start fail2ban as a daemon. Output
# is redirect to logfile.
background = false
# debug: true to enable debug mode. More verbose output
# and bypass root user test.
debug = false
# pidlock: the path of the PID lock file. Fail2Ban must be
# able to write into that file.
#pidlock = /var/run/fail2ban.pid
# logfile: the path of the file for logging messages of
# fail2ban.
logfile = /var/log/fail2ban.log
# maxretry: the number of retry before IP gets ban.
maxretry = 3
# bantime: the number of seconds an IP will be ban.
bantime = 600
# ignoreip: a space separated list that contains IP which
# will be ignore by fail2ban. Example:
# ignoreip = 192.168.0.1 123.45.235.65
ignoreip =
# interface: the interface name on which the IP will be
# banned.
interface = eth0
# polltime: the number of seconds that fail2ban sleeps
# between two iteration (check for IP to unban - parse
# log file). 1 is a good value.
polltime = 1
# You can define a new section for each log file to check for
# password failure. Each section has to define the following
# options: logfile, timeregex, timepattern, failregex.
[Apache]
# enabled: is this section active ?
enabled = true
# logfile: file to monitor.
logfile = log-test/apache
# timeregex: regular expression which have to match the
# timestamp of an Apache log event.
# [Wed Jan 05 15:08:01 2005]
timeregex = \S{3} \S{3} \d{2} \d{2}:\d{2}:\d{2} \d{4}
# timepattern: indicates the "timeregex" fields signification.
# Notice that '%' must be espaced with '%'.
# See syntax here: http://rgruet.free.fr/PQR2.3.html#timeModule
timepattern = %%a %%b %%d %%H:%%M:%%S %%Y
# failregex: regular expression which have to match the
# message written in the log file in case of password failure.
failregex = authentication failure|user .* not found
[SSH]
# enabled: is this section active ?
enabled = true
# logfile: file to monitor.
logfile = log-test/current
# timeregex: regular expression which have to match the
# timestamp of an Apache log event.
# Mar 7 17:53:28
timeregex = \S{3}\s{1,2}\d{1,2} \d{2}:\d{2}:\d{2}
# timepattern: indicates the "timeregex" fields signification.
# Notice that '%' must be espaced with '%'.
# See syntax here: http://rgruet.free.fr/PQR2.3.html#timeModule
timepattern = %%b %%d %%H:%%M:%%S
# failregex: regular expression which have to match the
# message written in the log file in case of password failure.
failregex = Authentication failure|Failed password
+336
View File
@@ -0,0 +1,336 @@
# Fail2Ban configuration file
#
# $Revision$
#
# 2005.06.21 modified for readability Iain Lea iain@bricbrac.de
[DEFAULT]
# Option: background
# Notes.: start fail2ban as a daemon. Output is redirect to logfile.
# Values: [true | false] Default: false
#
background = false
# Option: locale
# Notes.: global (cannot be redefined per section) locale to use for
# timestamp pattern matching by changing LC_TIME for
# fail2ban process. Empty entry sets locale to default one
# (usually specified by LC_ALL environment variable).
# Values: LOCALE Default:
#
locale =
# Option: logtargets
# Notes.: log targets. Space separated list of logging targets.
# Values: STDERR SYSLOG file Default: /var/log/fail2ban.log
#
logtargets = /var/log/fail2ban.log
# Option: syslog-target
# Notes.: where to find syslog facility if logtarget SYSLOG.
# Values: SOCKET HOST HOST:PORT Default: /dev/log
#
syslog-target = /dev/log
# Option: syslog-facility
# Notes.: which syslog facility to use if logtarget SYSLOG.
# Values: NUM Default: 1
#
syslog-facility = 1
# Option: pidlock
# Notes.: path of the PID lock file (must be able to write to file).
# Values: FILE Default: /var/run/fail2ban.pid
#
pidlock = /var/run/fail2ban.pid
# Option: maxfailures
# Notes.: number of failures before IP gets banned.
# Values: NUM Default: 5
#
maxfailures = 5
# Option: bantime
# Notes.: number of seconds an IP will be banned. If set to a negative
# value, IP will never be unbanned (permanent banning).
# Values: NUM Default: 600
#
bantime = 600
# Option: findtime
# Notes.: lifetime in seconds of a "failed" log entry.
# Values: NUM Default: 600
#
findtime = 600
# Option: ignoreip
# Notes.: space separated list of IP's to be ignored by fail2ban.
# You can use CIDR mask in order to specify a range.
# Example: ignoreip = 192.168.0.1/24 123.45.235.65
# Values: IP Default:
#
ignoreip =
# Option: cmdstart
# Notes.: command executed once at the start of Fail2Ban
# Values: CMD Default:
#
cmdstart =
# Option: cmdend
# Notes.: command executed once at the end of Fail2Ban.
# Values: CMD Default:
#
cmdend =
# Option: polltime
# Notes.: number of seconds fail2ban sleeps between iterations.
# Values: NUM Default: 1
#
polltime = 1
# Option: reinittime
# Notes.: minimal number of seconds between the re-initialization of
# firewalls due to external changes in their rules (see fwcheck)
# Values: NUM Default: 100
#
reinittime = 10
# Option: maxreinits
# Notes.: maximal number of re-initialization of firewalls due to external
# changes. -1 stays for infinite, so only reinittime is of importance
# Values: NUM Default: -1
#
maxreinits = -1
# NOTE: Interpolations
#
# fwstart, as well as fwend, fwcheck, fwban, fwunban, use interpolations
# so %(__name__)s will be substituted by a name of each section
# (unless the option is overriden in a section).
# If you are going to use interpolations in your setup, please make
# sure that you specified options port and protocol (which also has
# an option in DEFAULT).
#
# Option: hostsdeny
# Notes.: hosts.deny file path.
# Values: STR Default: /etc/hosts.deny
#
hostsdeny = /etc/hosts.deny
# Option: fwban
# Notes.: command executed when banning an IP. Take care that the
# command is executed with Fail2Ban user rights.
# Tags: <ip> IP address
# <failures> number of failures
# <failtime> unix timestamp of the last failure
# <bantime> unix timestamp of the ban time
# Values: CMD
# Default: iptables -I INPUT 1 -s <ip> -j DROP
#
fwban = IP=<ip> && echo "ALL: $IP" >> %(hostsdeny)s
# Option: fwunban
# Notes.: command executed when unbanning an IP. Take care that the
# command is executed with Fail2Ban user rights.
# Tags: <ip> IP address
# <bantime> unix timestamp of the ban time
# <unbantime> unix timestamp of the unban time
# Values: CMD
# Default: iptables -D INPUT -s <ip> -j DROP
#
fwunban = IP=<ip> && sed -i.old /ALL:\ $IP/d %(hostsdeny)s
[MAIL]
# Option: enabled
# Notes.: enable mail notification when banning an IP address.
# Values: [true | false] Default: false
#
enabled = false
# Option: host
# Notes.: host running the mail server.
# Values: STR Default: localhost
#
host = localhost
# Option: port
# Notes.: port of the mail server.
# Values: INT Default: 25
#
port = 25
# Option: user
# Notes.: the username for smtp-server if authentification is required.
# if user is empty, no authentification is done.
# Values: STR Default:
#
user =
# Option: password
# Notes.: the smtp-user's password if authentification is required.
# Values: STR Default:
#
password =
# Option: from
# Notes.: e-mail address of the sender.
# Values: MAIL Default: fail2ban
#
from = fail2ban
# Option: to
# Notes.: e-mail addresses of the receiver. Addresses are space
# separated.
# Values: MAIL Default: root
#
to = root
# Option: localtime
# Notes.: report local time (including timezone) or GMT
# Values: [true | false] Default: false
#
localtime = true
# Option: subject
# Notes.: subject of the e-mail.
# Tags: <section> active section (eg ssh, apache, etc)
# <ip> IP address
# <failures> number of failures
# <failtime> unix timestamp of the last failure
# Values: TEXT Default: [Fail2Ban] <section>: Banned <ip>
#
subject = [Fail2Ban] <section>: Banned <ip>
# Option: message
# Notes.: message of the e-mail.
# Tags: <section> active section (eg ssh, apache, etc)
# <ip> IP address
# <failures> number of failures
# <failtime> unix timestamp of the last failure
# <br> new line
# Values: TEXT Default:
#
message = Hi,<br>
The IP <ip> has just been banned by Fail2Ban after
<failures> attempts against <section>.<br>
Regards,<br>
Fail2Ban
# You can define a new section for each log file to check for
# password failure. Each section has to define the following
# options: logfile, fwban, fwunban, timeregex, timepattern,
# failregex.
[Apache]
# Option: enabled
# Notes.: enable monitoring for this section.
# Values: [true | false] Default: false
#
enabled = false
# Option: logfile
# Notes.: logfile to monitor.
# Values: FILE Default: /var/log/httpd/access_log
#
logfile = /var/log/httpd/access_log
# Option: timeregex
# Notes.: regex to match timestamp in Apache logfile. For TAI64N format,
# use timeregex = @[0-9a-f]{24}
# Values: [Wed Jan 05 15:08:01 2005]
# Default: \S{3} \S{3} \d{2} \d{2}:\d{2}:\d{2} \d{4}
#
timeregex = \S{3} \S{3} \d{2} \d{2}:\d{2}:\d{2} \d{4}
# Option: timepattern
# Notes.: format used in "timeregex" fields definition. Note that '%' must be
# escaped with '%' (see http://rgruet.free.fr/PQR2.3.html#timeModule).
# For TAI64N format, use timepattern = tai64n
# Values: TEXT Default: %%a %%b %%d %%H:%%M:%%S %%Y
#
timepattern = %%a %%b %%d %%H:%%M:%%S %%Y
# Option: failregex
# Notes.: regex to match the password failure messages in the logfile.
# Values: TEXT Default: authentication failure|user .* not found
#
failregex = [[]client (?P<host>\S*)[]] user .*(?:: authentication failure|not found)
[VSFTPD]
# Option: enabled
# Notes.: enable monitoring for this section.
# Values: [true | false] Default: false
#
enabled = false
# Option: logfile
# Notes.: logfile to monitor.
# Values: FILE Default: /var/log/secure
#
logfile = /var/log/vsftpd.log
# Option: port
# Notes.: specifies port to monitor
# Values: [ NUM | STRING ] Default:
#
port = ftp
# Option: timeregex
# Notes.: regex to match timestamp in VSFTPD logfile.
# Values: [Mar 7 17:53:28]
# Default: \S{3}\s{1,2}\d{1,2} \d{2}:\d{2}:\d{2}
#
timeregex = \S{3}\s{1,2}\d{1,2} \d{2}:\d{2}:\d{2}
# Option: timepattern
# Notes.: format used in "timeregex" fields definition. Note that '%' must be
# escaped with '%' (see http://rgruet.free.fr/PQR2.3.html#timeModule)
# Values: TEXT Default: %%b %%d %%H:%%M:%%S
#
timepattern = %%b %%d %%H:%%M:%%S
# Option: failregex
# Notes.: regex to match the password failures messages in the logfile.
# Values: TEXT Default: Authentication failure|Failed password|Invalid user
#
failregex = vsftpd: \(pam_unix\) authentication failure; .* rhost=(?P<host>\S+)
[SSH]
# Option: enabled
# Notes.: enable monitoring for this section.
# Values: [true | false] Default: true
#
enabled = true
# Option: logfile
# Notes.: logfile to monitor.
# Values: FILE Default: /var/log/secure
#
logfile = /var/log/secure
# Option: timeregex
# Notes.: regex to match timestamp in SSH logfile. For TAI64N format,
# use timeregex = @[0-9a-f]{24}
# Values: [Mar 7 17:53:28]
# Default: \S{3}\s{1,2}\d{1,2} \d{2}:\d{2}:\d{2}
#
timeregex = \S{3}\s{1,2}\d{1,2} \d{2}:\d{2}:\d{2}
# Option: timepattern
# Notes.: format used in "timeregex" fields definition. Note that '%' must be
# escaped with '%' (see http://rgruet.free.fr/PQR2.3.html#timeModule).
# For TAI64N format, use timepattern = tai64n
# Values: TEXT Default: %%b %%d %%H:%%M:%%S
#
timepattern = %%b %%d %%H:%%M:%%S
# Option: failregex
# Notes.: regex to match the password failures messages in the logfile.
# Values: TEXT Default: Authentication failure|Failed password|Invalid user
#
failregex = : (?:(?:Authentication failure|Failed [-/\w+]+) for(?: [iI](?:llegal|nvalid) user)?|[Ii](?:llegal|nvalid) user|ROOT LOGIN REFUSED) .*(?: from|FROM) (?:::f{4,6}:)?(?P<host>\S*)
+370
View File
@@ -0,0 +1,370 @@
# Fail2Ban configuration file
#
# $Revision$
#
# 2005.06.21 modified for readability Iain Lea iain@bricbrac.de
[DEFAULT]
# Option: background
# Notes.: start fail2ban as a daemon. Output is redirect to logfile.
# Values: [true | false] Default: false
#
background = false
# Option: locale
# Notes.: global (cannot be redefined per section) locale to use for
# timestamp pattern matching by changing LC_TIME for
# fail2ban process. Empty entry sets locale to default one
# (usually specified by LC_ALL environment variable).
# Values: LOCALE Default:
#
locale =
# Option: logtargets
# Notes.: log targets. Space separated list of logging targets.
# Values: STDERR SYSLOG file Default: /var/log/fail2ban.log
#
logtargets = /var/log/fail2ban.log
# Option: syslog-target
# Notes.: where to find syslog facility if logtarget SYSLOG.
# Values: SOCKET HOST HOST:PORT Default: /dev/log
#
syslog-target = /dev/log
# Option: syslog-facility
# Notes.: which syslog facility to use if logtarget SYSLOG.
# Values: NUM Default: 1
#
syslog-facility = 1
# Option: pidlock
# Notes.: path of the PID lock file (must be able to write to file).
# Values: FILE Default: /var/run/fail2ban.pid
#
pidlock = /var/run/fail2ban.pid
# Option: maxfailures
# Notes.: number of failures before IP gets banned.
# Values: NUM Default: 5
#
maxfailures = 5
# Option: bantime
# Notes.: number of seconds an IP will be banned. If set to a negative
# value, IP will never be unbanned (permanent banning).
# Values: NUM Default: 600
#
bantime = 600
# Option: findtime
# Notes.: lifetime in seconds of a "failed" log entry.
# Values: NUM Default: 600
#
findtime = 600
# Option: ignoreip
# Notes.: space separated list of IP's to be ignored by fail2ban.
# You can use CIDR mask in order to specify a range.
# Example: ignoreip = 192.168.0.1/24 123.45.235.65
# Values: IP Default:
#
ignoreip =
# Option: cmdstart
# Notes.: command executed once at the start of Fail2Ban
# Values: CMD Default:
#
cmdstart =
# Option: cmdend
# Notes.: command executed once at the end of Fail2Ban.
# Values: CMD Default:
#
cmdend =
# Option: polltime
# Notes.: number of seconds fail2ban sleeps between iterations.
# Values: NUM Default: 1
#
polltime = 1
# Option: reinittime
# Notes.: minimal number of seconds between the re-initialization of
# firewalls due to external changes in their rules (see fwcheck)
# Values: NUM Default: 100
#
reinittime = 10
# Option: maxreinits
# Notes.: maximal number of re-initialization of firewalls due to external
# changes. -1 stays for infinite, so only reinittime is of importance
# Values: NUM Default: -1
#
maxreinits = -1
# NOTE: Interpolations
#
# fwstart, as well as fwend, fwcheck, fwban, fwunban, use interpolations
# so %(__name__)s will be substituted by a name of each section
# (unless the option is overriden in a section).
# If you are going to use interpolations in your setup, please make
# sure that you specified options port and protocol (which also has
# an option in DEFAULT).
#
# Option: protocol
# Notes.: internally used by config reader for interpolations.
# Values: [ tcp | udp | icmp | all ] Default: tcp
#
protocol = tcp
# Option: fwstart
# Notes.: command executed once at the start of Fail2Ban.
# Values: CMD Default:
#
fwstart = iptables -N fail2ban-%(__name__)s
iptables -A fail2ban-%(__name__)s -j RETURN
iptables -I INPUT -p %(protocol)s --dport %(port)s -j fail2ban-%(__name__)s
# Option: fwend
# Notes.: command executed once at the end of Fail2Ban
# Values: CMD Default:
#
fwend = iptables -D INPUT -p %(protocol)s --dport %(port)s -j fail2ban-%(__name__)s
iptables -F fail2ban-%(__name__)s
iptables -X fail2ban-%(__name__)s
# Option: fwcheck
# Notes.: command executed once before each fwban command
# Values: CMD Default:
#
fwcheck = iptables -L INPUT | grep -q fail2ban-%(__name__)s
# Option: fwban
# Notes.: command executed when banning an IP. Take care that the
# command is executed with Fail2Ban user rights.
# Tags: <ip> IP address
# <failures> number of failures
# <failtime> unix timestamp of the last failure
# <bantime> unix timestamp of the ban time
# Values: CMD
# Default: iptables -I INPUT 1 -s <ip> -j DROP
#
fwban = iptables -I fail2ban-%(__name__)s 1 -s <ip> -j DROP
# Option: fwunban
# Notes.: command executed when unbanning an IP. Take care that the
# command is executed with Fail2Ban user rights.
# Tags: <ip> IP address
# <bantime> unix timestamp of the ban time
# <unbantime> unix timestamp of the unban time
# Values: CMD
# Default: iptables -D INPUT -s <ip> -j DROP
#
fwunban = iptables -D fail2ban-%(__name__)s -s <ip> -j DROP
[MAIL]
# Option: enabled
# Notes.: enable mail notification when banning an IP address.
# Values: [true | false] Default: false
#
enabled = false
# Option: host
# Notes.: host running the mail server.
# Values: STR Default: localhost
#
host = localhost
# Option: port
# Notes.: port of the mail server.
# Values: INT Default: 25
#
port = 25
# Option: user
# Notes.: the username for smtp-server if authentification is required.
# if user is empty, no authentification is done.
# Values: STR Default:
#
user =
# Option: password
# Notes.: the smtp-user's password if authentification is required.
# Values: STR Default:
#
password =
# Option: from
# Notes.: e-mail address of the sender.
# Values: MAIL Default: fail2ban
#
from = fail2ban
# Option: to
# Notes.: e-mail addresses of the receiver. Addresses are space
# separated.
# Values: MAIL Default: root
#
to = root
# Option: localtime
# Notes.: report local time (including timezone) or GMT
# Values: [true | false] Default: false
#
localtime = true
# Option: subject
# Notes.: subject of the e-mail.
# Tags: <section> active section (eg ssh, apache, etc)
# <ip> IP address
# <failures> number of failures
# <failtime> unix timestamp of the last failure
# Values: TEXT Default: [Fail2Ban] <section>: Banned <ip>
#
subject = [Fail2Ban] <section>: Banned <ip>
# Option: message
# Notes.: message of the e-mail.
# Tags: <section> active section (eg ssh, apache, etc)
# <ip> IP address
# <failures> number of failures
# <failtime> unix timestamp of the last failure
# <br> new line
# Values: TEXT Default:
#
message = Hi,<br>
The IP <ip> has just been banned by Fail2Ban after
<failures> attempts against <section>.<br>
Regards,<br>
Fail2Ban
# You can define a new section for each log file to check for
# password failure. Each section has to define the following
# options: logfile, fwban, fwunban, timeregex, timepattern,
# failregex.
[Apache]
# Option: enabled
# Notes.: enable monitoring for this section.
# Values: [true | false] Default: false
#
enabled = false
# Option: logfile
# Notes.: logfile to monitor.
# Values: FILE Default: /var/log/httpd/access_log
#
logfile = /var/log/httpd/access_log
# Option: port
# Notes.: specifies port to monitor
# Values: [ NUM | STRING ] Default:
#
port = http
# Option: timeregex
# Notes.: regex to match timestamp in Apache logfile. For TAI64N format,
# use timeregex = @[0-9a-f]{24}
# Values: [Wed Jan 05 15:08:01 2005]
# Default: \S{3} \S{3} \d{2} \d{2}:\d{2}:\d{2} \d{4}
#
timeregex = \S{3} \S{3} \d{2} \d{2}:\d{2}:\d{2} \d{4}
# Option: timepattern
# Notes.: format used in "timeregex" fields definition. Note that '%' must be
# escaped with '%' (see http://rgruet.free.fr/PQR2.3.html#timeModule).
# For TAI64N format, use timepattern = tai64n
# Values: TEXT Default: %%a %%b %%d %%H:%%M:%%S %%Y
#
timepattern = %%a %%b %%d %%H:%%M:%%S %%Y
# Option: failregex
# Notes.: regex to match the password failure messages in the logfile.
# Values: TEXT Default: authentication failure|user .* not found
#
failregex = [[]client (?P<host>\S*)[]] user .*(?:: authentication failure|not found)
[VSFTPD]
# Option: enabled
# Notes.: enable monitoring for this section.
# Values: [true | false] Default: false
#
enabled = false
# Option: logfile
# Notes.: logfile to monitor.
# Values: FILE Default: /var/log/secure
#
logfile = /var/log/vsftpd.log
# Option: port
# Notes.: specifies port to monitor
# Values: [ NUM | STRING ] Default:
#
port = ftp
# Option: timeregex
# Notes.: regex to match timestamp in VSFTPD logfile.
# Values: [Mar 7 17:53:28]
# Default: \S{3}\s{1,2}\d{1,2} \d{2}:\d{2}:\d{2}
#
timeregex = \S{3}\s{1,2}\d{1,2} \d{2}:\d{2}:\d{2}
# Option: timepattern
# Notes.: format used in "timeregex" fields definition. Note that '%' must be
# escaped with '%' (see http://rgruet.free.fr/PQR2.3.html#timeModule)
# Values: TEXT Default: %%b %%d %%H:%%M:%%S
#
timepattern = %%b %%d %%H:%%M:%%S
# Option: failregex
# Notes.: regex to match the password failures messages in the logfile.
# Values: TEXT Default: Authentication failure|Failed password|Invalid user
#
failregex = vsftpd: \(pam_unix\) authentication failure; .* rhost=(?P<host>\S+)
[SSH]
# Option: enabled
# Notes.: enable monitoring for this section.
# Values: [true | false] Default: true
#
enabled = true
# Option: logfile
# Notes.: logfile to monitor.
# Values: FILE Default: /var/log/secure
#
logfile = /var/log/secure
# Option: port
# Notes.: specifies port to monitor
# Values: [ NUM | STRING ] Default:
#
port = ssh
# Option: timeregex
# Notes.: regex to match timestamp in SSH logfile. For TAI64N format,
# use timeregex = @[0-9a-f]{24}
# Values: [Mar 7 17:53:28]
# Default: \S{3}\s{1,2}\d{1,2} \d{2}:\d{2}:\d{2}
#
timeregex = \S{3}\s{1,2}\d{1,2} \d{2}:\d{2}:\d{2}
# Option: timepattern
# Notes.: format used in "timeregex" fields definition. Note that '%' must be
# escaped with '%' (see http://rgruet.free.fr/PQR2.3.html#timeModule).
# For TAI64N format, use timepattern = tai64n
# Values: TEXT Default: %%b %%d %%H:%%M:%%S
#
timepattern = %%b %%d %%H:%%M:%%S
# Option: failregex
# Notes.: regex to match the password failures messages in the logfile.
# Values: TEXT Default: Authentication failure|Failed password|Invalid user
#
failregex = : (?:(?:Authentication failure|Failed [-/\w+]+) for(?: [iI](?:llegal|nvalid) user)?|[Ii](?:llegal|nvalid) user|ROOT LOGIN REFUSED) .*(?: from|FROM) (?:::f{4,6}:)?(?P<host>\S*)
+324
View File
@@ -0,0 +1,324 @@
# Fail2Ban configuration file
#
# $Revision$
#
# 2005.06.21 modified for readability Iain Lea iain@bricbrac.de
[DEFAULT]
# Option: background
# Notes.: start fail2ban as a daemon. Output is redirect to logfile.
# Values: [true | false] Default: false
#
background = false
# Option: locale
# Notes.: global (cannot be redefined per section) locale to use for
# timestamp pattern matching by changing LC_TIME for
# fail2ban process. Empty entry sets locale to default one
# (usually specified by LC_ALL environment variable).
# Values: LOCALE Default:
#
locale =
# Option: logtargets
# Notes.: log targets. Space separated list of logging targets.
# Values: STDERR SYSLOG file Default: /var/log/fail2ban.log
#
logtargets = /var/log/fail2ban.log
# Option: syslog-target
# Notes.: where to find syslog facility if logtarget SYSLOG.
# Values: SOCKET HOST HOST:PORT Default: /dev/log
#
syslog-target = /dev/log
# Option: syslog-facility
# Notes.: which syslog facility to use if logtarget SYSLOG.
# Values: NUM Default: 1
#
syslog-facility = 1
# Option: pidlock
# Notes.: path of the PID lock file (must be able to write to file).
# Values: FILE Default: /var/run/fail2ban.pid
#
pidlock = /var/run/fail2ban.pid
# Option: maxfailures
# Notes.: number of failures before IP gets banned.
# Values: NUM Default: 5
#
maxfailures = 5
# Option: bantime
# Notes.: number of seconds an IP will be banned. If set to a negative
# value, IP will never be unbanned (permanent banning).
# Values: NUM Default: 600
#
bantime = 600
# Option: findtime
# Notes.: lifetime in seconds of a "failed" log entry.
# Values: NUM Default: 600
#
findtime = 600
# Option: ignoreip
# Notes.: space separated list of IP's to be ignored by fail2ban.
# You can use CIDR mask in order to specify a range.
# Example: ignoreip = 192.168.0.1/24 123.45.235.65
# Values: IP Default:
#
ignoreip =
# Option: cmdstart
# Notes.: command executed once at the start of Fail2Ban
# Values: CMD Default:
#
cmdstart =
# Option: cmdend
# Notes.: command executed once at the end of Fail2Ban.
# Values: CMD Default:
#
cmdend =
# Option: polltime
# Notes.: number of seconds fail2ban sleeps between iterations.
# Values: NUM Default: 1
#
polltime = 1
# Option: reinittime
# Notes.: minimal number of seconds between the re-initialization of
# firewalls due to external changes in their rules (see fwcheck)
# Values: NUM Default: 100
#
reinittime = 10
# Option: maxreinits
# Notes.: maximal number of re-initialization of firewalls due to external
# changes. -1 stays for infinite, so only reinittime is of importance
# Values: NUM Default: -1
#
maxreinits = -1
# NOTE: Interpolations
#
# fwstart, as well as fwend, fwcheck, fwban, fwunban, use interpolations
# so %(__name__)s will be substituted by a name of each section
# (unless the option is overriden in a section).
# If you are going to use interpolations in your setup, please make
# sure that you specified options port and protocol (which also has
# an option in DEFAULT).
#
# Option: fwban
# Notes.: command executed when banning an IP. Take care that the
# command is executed with Fail2Ban user rights.
# Tags: <ip> IP address
# <failures> number of failures
# <failtime> unix timestamp of the last failure
# <bantime> unix timestamp of the ban time
# Values: CMD
# Default: iptables -I INPUT 1 -s <ip> -j DROP
#
fwban = shorewall drop <ip>
# Option: fwunban
# Notes.: command executed when unbanning an IP. Take care that the
# command is executed with Fail2Ban user rights.
# Tags: <ip> IP address
# <bantime> unix timestamp of the ban time
# <unbantime> unix timestamp of the unban time
# Values: CMD
# Default: iptables -D INPUT -s <ip> -j DROP
#
fwunban = shorewall allow <ip>
[MAIL]
# Option: enabled
# Notes.: enable mail notification when banning an IP address.
# Values: [true | false] Default: false
#
enabled = false
# Option: host
# Notes.: host running the mail server.
# Values: STR Default: localhost
#
host = localhost
# Option: port
# Notes.: port of the mail server.
# Values: INT Default: 25
#
port = 25
# Option: user
# Notes.: the username for smtp-server if authentification is required.
# if user is empty, no authentification is done.
# Values: STR Default:
#
user =
# Option: password
# Notes.: the smtp-user's password if authentification is required.
# Values: STR Default:
#
password =
# Option: from
# Notes.: e-mail address of the sender.
# Values: MAIL Default: fail2ban
#
from = fail2ban
# Option: to
# Notes.: e-mail addresses of the receiver. Addresses are space
# separated.
# Values: MAIL Default: root
#
to = root
# Option: localtime
# Notes.: report local time (including timezone) or GMT
# Values: [true | false] Default: false
#
localtime = true
# Option: subject
# Notes.: subject of the e-mail.
# Tags: <section> active section (eg ssh, apache, etc)
# <ip> IP address
# <failures> number of failures
# <failtime> unix timestamp of the last failure
# Values: TEXT Default: [Fail2Ban] <section>: Banned <ip>
#
subject = [Fail2Ban] <section>: Banned <ip>
# Option: message
# Notes.: message of the e-mail.
# Tags: <section> active section (eg ssh, apache, etc)
# <ip> IP address
# <failures> number of failures
# <failtime> unix timestamp of the last failure
# <br> new line
# Values: TEXT Default:
#
message = Hi,<br>
The IP <ip> has just been banned by Fail2Ban after
<failures> attempts against <section>.<br>
Regards,<br>
Fail2Ban
# You can define a new section for each log file to check for
# password failure. Each section has to define the following
# options: logfile, fwban, fwunban, timeregex, timepattern,
# failregex.
[Apache]
# Option: enabled
# Notes.: enable monitoring for this section.
# Values: [true | false] Default: false
#
enabled = false
# Option: logfile
# Notes.: logfile to monitor.
# Values: FILE Default: /var/log/httpd/access_log
#
logfile = /var/log/httpd/access_log
# Option: timeregex
# Notes.: regex to match timestamp in Apache logfile. For TAI64N format,
# use timeregex = @[0-9a-f]{24}
# Values: [Wed Jan 05 15:08:01 2005]
# Default: \S{3} \S{3} \d{2} \d{2}:\d{2}:\d{2} \d{4}
#
timeregex = \S{3} \S{3} \d{2} \d{2}:\d{2}:\d{2} \d{4}
# Option: timepattern
# Notes.: format used in "timeregex" fields definition. Note that '%' must be
# escaped with '%' (see http://rgruet.free.fr/PQR2.3.html#timeModule).
# For TAI64N format, use timepattern = tai64n
# Values: TEXT Default: %%a %%b %%d %%H:%%M:%%S %%Y
#
timepattern = %%a %%b %%d %%H:%%M:%%S %%Y
# Option: failregex
# Notes.: regex to match the password failure messages in the logfile.
# Values: TEXT Default: authentication failure|user .* not found
#
failregex = [[]client (?P<host>\S*)[]] user .*(?:: authentication failure|not found)
[VSFTPD]
# Option: enabled
# Notes.: enable monitoring for this section.
# Values: [true | false] Default: false
#
enabled = false
# Option: logfile
# Notes.: logfile to monitor.
# Values: FILE Default: /var/log/secure
#
logfile = /var/log/vsftpd.log
# Option: timeregex
# Notes.: regex to match timestamp in VSFTPD logfile.
# Values: [Mar 7 17:53:28]
# Default: \S{3}\s{1,2}\d{1,2} \d{2}:\d{2}:\d{2}
#
timeregex = \S{3}\s{1,2}\d{1,2} \d{2}:\d{2}:\d{2}
# Option: timepattern
# Notes.: format used in "timeregex" fields definition. Note that '%' must be
# escaped with '%' (see http://rgruet.free.fr/PQR2.3.html#timeModule)
# Values: TEXT Default: %%b %%d %%H:%%M:%%S
#
timepattern = %%b %%d %%H:%%M:%%S
# Option: failregex
# Notes.: regex to match the password failures messages in the logfile.
# Values: TEXT Default: Authentication failure|Failed password|Invalid user
#
failregex = vsftpd: \(pam_unix\) authentication failure; .* rhost=(?P<host>\S+)
[SSH]
# Option: enabled
# Notes.: enable monitoring for this section.
# Values: [true | false] Default: true
#
enabled = true
# Option: logfile
# Notes.: logfile to monitor.
# Values: FILE Default: /var/log/secure
#
logfile = /var/log/secure
# Option: timeregex
# Notes.: regex to match timestamp in SSH logfile. For TAI64N format,
# use timeregex = @[0-9a-f]{24}
# Values: [Mar 7 17:53:28]
# Default: \S{3}\s{1,2}\d{1,2} \d{2}:\d{2}:\d{2}
#
timeregex = \S{3}\s{1,2}\d{1,2} \d{2}:\d{2}:\d{2}
# Option: timepattern
# Notes.: format used in "timeregex" fields definition. Note that '%' must be
# escaped with '%' (see http://rgruet.free.fr/PQR2.3.html#timeModule).
# For TAI64N format, use timepattern = tai64n
# Values: TEXT Default: %%b %%d %%H:%%M:%%S
#
timepattern = %%b %%d %%H:%%M:%%S
# Option: failregex
# Notes.: regex to match the password failures messages in the logfile.
# Values: TEXT Default: Authentication failure|Failed password|Invalid user
#
failregex = : (?:(?:Authentication failure|Failed [-/\w+]+) for(?: [iI](?:llegal|nvalid) user)?|[Ii](?:llegal|nvalid) user|ROOT LOGIN REFUSED) .*(?: from|FROM) (?:::f{4,6}:)?(?P<host>\S*)
+23
View File
@@ -0,0 +1,23 @@
# This file is part of Fail2Ban.
#
# Fail2Ban is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# Fail2Ban is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Fail2Ban; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# Author: Cyril Jaquier
#
# $Revision$
# Command line options for Fail2Ban. Refer to "fail2ban -h" for
# valid options.
FAIL2BAN_OPTS="-v"
+50
View File
@@ -0,0 +1,50 @@
#!/sbin/runscript
# This file is part of Fail2Ban.
#
# Fail2Ban is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# Fail2Ban is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Fail2Ban; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# Author: Sireyessire, Cyril Jaquier
#
# $Revision$
opts="start stop restart showlog"
FAIL2BAN="/usr/bin/fail2ban"
depend() {
need net
need logger
after iptables
}
start() {
ebegin "Starting fail2ban"
${FAIL2BAN} -b ${FAIL2BAN_OPTS} > /dev/null
eend $? "Failed to start fail2ban"
}
stop() {
ebegin "Stopping fail2ban"
${FAIL2BAN} -k > /dev/null
eend $? "Failed to stop fail2ban"
}
zap() {
rm /var/run/fail2ban.pid
}
showlog(){
less /var/log/fail2ban.log
}
+78
View File
@@ -0,0 +1,78 @@
#!/bin/bash
#
# fail2ban
#
# chkconfig: 345 91 9
# description: if many unsuccessfull login attempts from some ip address \
# during a short period happen, this address is banned \
# by the firewall
#
# Author: Andrey G. Grozin
#
# $Revision$
# Source function library.
. /etc/init.d/functions
# Get config.
. /etc/sysconfig/network
# Check that networking is up.
[ "${NETWORKING}" = "no" ] && exit 0
[ -f /etc/fail2ban.conf ] || exit 0
FAIL2BAN="/usr/bin/fail2ban"
PIDFILE="/var/run/fail2ban.pid"
RETVAL=0
start() {
echo -n $"Starting fail2ban: "
"${FAIL2BAN}" -b > /dev/null
RETVAL=$?
echo
}
stop() {
if [ -f "${PIDFILE}" ]; then
echo -n $"Stopping fail2ban: "
"${FAIL2BAN}" -k > /dev/null
echo
fi
}
restart() {
stop
start
}
# See how we were called.
case "$1" in
start)
start
;;
stop)
stop
;;
status)
status fail2ban
RETVAL=$?
;;
reload)
restart
;;
restart)
restart
;;
condrestart)
if [ -f "${PIDFILE}" ]; then
restart
fi
;;
*)
echo $"Usage: $0 {start|stop|status|restart|condrestart}"
exit 1
;;
esac
exit $RETVAL
+24 -19
View File
@@ -24,28 +24,22 @@ __date__ = "$Date$"
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
__license__ = "GPL"
import logging
from ConfigParser import *
# Gets the instance of the logger.
logSys = logging.getLogger("fail2ban")
class ConfigReader:
""" This class allow the handling of the configuration options.
The DEFAULT section contains the global information about
Fail2Ban. Each other section is for a different log file.
"""
# Each optionValues entry is composed of an array with:
# 0 -> the type of the option
# 1 -> the name of the option
# 2 -> the default value for the option
optionValues = (["bool", "enabled", True],
["str", "logfile", "/dev/null"],
["str", "timeregex", ""],
["str", "timepattern", ""],
["str", "failregex", ""])
def __init__(self, logSys, confPath):
def __init__(self, confPath):
self.confPath = confPath
self.configParser = SafeConfigParser()
self.logSys = logSys
def openConf(self):
""" Opens the configuration file.
@@ -54,16 +48,23 @@ class ConfigReader:
def getSections(self):
""" Returns all the sections present in the configuration
file except the DEFAULT section.
file except the DEFAULT and MAIL sections.
"""
return self.configParser.sections()
def getLogOptions(self, sec):
sections = self.configParser.sections()
sections.remove("MAIL")
logSys.debug("Found sections: " + `sections`)
return sections
# Each optionValues entry is composed of an array with:
# 0 -> the type of the option
# 1 -> the name of the option
# 2 -> the default value for the option
def getLogOptions(self, sec, options):
""" Gets all the options of a given section. The options
are defined in the optionValues list.
"""
values = dict()
for option in self.optionValues:
for option in options:
try:
if option[0] == "bool":
v = self.configParser.getboolean(sec, option[1])
@@ -74,7 +75,11 @@ class ConfigReader:
values[option[1]] = v
except NoOptionError:
self.logSys.warn("No '"+option[1]+"' defined in '"+sec+"'")
logSys.warn("No '" + option[1] + "' defined in '" + sec + "'")
values[option[1]] = option[2]
except ValueError:
logSys.warn("Wrong value for '" + option[1] + "' in '" + sec +
"'. Using default one: '" + `option[2]` + "'")
values[option[1]] = option[2]
return values
Executable
+68
View File
@@ -0,0 +1,68 @@
#!/usr/bin/env python
# This file is part of Fail2Ban.
#
# Fail2Ban is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# Fail2Ban is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Fail2Ban; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
# Author: Cyril Jaquier
#
# $Revision$
__author__ = "Cyril Jaquier"
__version__ = "$Revision$"
__date__ = "$Date$"
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
__license__ = "GPL"
import sys, traceback, logging
# Inserts our own modules path first in the list
# fix for bug #343821
sys.path.insert(1, "/usr/lib/fail2ban")
# Now we can import our modules.
import fail2ban
from utils.pidlock import PIDLock
# Get the instance of the logger.
logSys = logging.getLogger("fail2ban")
# Get PID lock file instance
pidLock = PIDLock()
# Handle all the unhandled exceptions
try:
# Start the application
fail2ban.main()
except SystemExit:
# We called sys.exit(). Nothing wrong so just pass
pass
except Exception, e:
# Print the exception data
(type, value, tb) = sys.exc_info()
tbStack = traceback.extract_tb(tb)
logSys.error("Fail2Ban got an unhandled exception and died.")
logSys.error("Type: " + `type.__name__` + "\n" +
"Value: " + `e.args` + "\n" +
"TB: " + `tbStack`)
# Try to clean up after ourselves
# just for extreme caution - wrapping with try
try:
fail2ban.restoreFwRules()
except Exception:
pass
# Remove the PID lock file. Should close #1239562
pidLock.remove()
logging.shutdown()
+413 -410
View File
@@ -1,5 +1,3 @@
#!/usr/bin/env python
# This file is part of Fail2Ban.
#
# Fail2Ban is free software; you can redistribute it and/or modify
@@ -17,6 +15,7 @@
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
# Author: Cyril Jaquier
# Modified by: Yaroslav Halchenko (SYSLOG, findtime)
#
# $Revision$
@@ -26,50 +25,58 @@ __date__ = "$Date$"
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
__license__ = "GPL"
import time, sys, getopt, os, signal, string
import time, sys, getopt, os, string, signal, logging, logging.handlers, \
copy, locale
from ConfigParser import *
# Checks if log4py is present.
try:
import log4py
except:
print "log4py is needed (see README)"
sys.exit(-1)
# Appends our own modules path
sys.path.append('/usr/lib/fail2ban')
from firewall.iptables import Iptables
from firewall.ipfw import Ipfw
from firewall.ipfwadm import Ipfwadm
from version import version
from firewall.firewall import Firewall
from logreader.logreader import LogReader
from confreader.configreader import ConfigReader
from version import version
from utils.mail import Mail
from utils.pidlock import PIDLock
from utils.dns import *
from utils.process import *
def usage():
print "Usage: fail2ban.py [OPTIONS]"
# Get the instance of the logger.
logSys = logging.getLogger("fail2ban")
# Get PID lock file instance
pidLock = PIDLock()
# Global variables
logFwList = list()
conf = dict()
def dispUsage():
""" Prints Fail2Ban command line options and exits
"""
print "Usage: "+sys.argv[0]+" [OPTIONS]"
print
print "Fail2Ban v"+version+" reads log file that contains password failure report"
print "and bans the corresponding IP address using iptables."
print "and bans the corresponding IP addresses using firewall rules."
print
print " -b start fail2ban in background"
print " -d start fail2ban in debug mode"
print " -e <INTF> ban IP on the INTF interface"
print " -b start in background"
print " -c <FILE> read configuration file FILE"
print " -p <FILE> create PID lock in FILE"
print " -h display this help message"
print " -i <IP(s)> IP(s) to ignore"
print " -k kill a currently running Fail2Ban instance"
print " -l <FILE> log message in FILE"
print " -r <VALUE> allow a max of VALUE password failure"
print " -t <TIME> ban IP for TIME seconds"
print " -k kill a currently running instance"
print " -r <VALUE> allow a max of VALUE password failure [maxfailures]"
print " -t <TIME> ban IP for TIME seconds [bantime]"
print " -f <TIME> lifetime in seconds of failed entry [findtime]"
print " -v verbose. Use twice for greater effect"
print " -w <FIWA> select the firewall to use. Can be iptables,"
print " ipfwadm or ipfw"
print " -V print software version"
print
print "Report bugs to <lostcontrol@users.sourceforge.net>"
sys.exit(0)
def dispVersion():
""" Prints Fail2Ban version and exits
"""
print sys.argv[0]+" "+version
sys.exit(0)
def checkForRoot():
""" Check for root user.
"""
@@ -79,359 +86,260 @@ def checkForRoot():
else:
return False
def createDaemon():
"""Detach a process from the controlling terminal and run it in the
background as a daemon.
http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/278731
"""
try:
# Fork a child process so the parent can exit. This will return control
# to the command line or shell. This is required so that the new process
# is guaranteed not to be a process group leader. We have this guarantee
# because the process GID of the parent is inherited by the child, but
# the child gets a new PID, making it impossible for its PID to equal its
# PGID.
pid = os.fork()
except OSError, e:
return((e.errno, e.strerror)) # ERROR (return a tuple)
if (pid == 0): # The first child.
# Next we call os.setsid() to become the session leader of this new
# session. The process also becomes the process group leader of the
# new process group. Since a controlling terminal is associated with a
# session, and this new session has not yet acquired a controlling
# terminal our process now has no controlling terminal. This shouldn't
# fail, since we're guaranteed that the child is not a process group
# leader.
os.setsid()
# When the first child terminates, all processes in the second child
# are sent a SIGHUP, so it's ignored.
signal.signal(signal.SIGHUP, signal.SIG_IGN)
try:
# Fork a second child to prevent zombies. Since the first child is
# a session leader without a controlling terminal, it's possible for
# it to acquire one by opening a terminal in the future. This second
# fork guarantees that the child is no longer a session leader, thus
# preventing the daemon from ever acquiring a controlling terminal.
pid = os.fork() # Fork a second child.
except OSError, e:
return((e.errno, e.strerror)) # ERROR (return a tuple)
if (pid == 0): # The second child.
# Ensure that the daemon doesn't keep any directory in use. Failure
# to do this could make a filesystem unmountable.
os.chdir("/")
# Give the child complete control over permissions.
os.umask(0)
else:
os._exit(0) # Exit parent (the first child) of the second child.
else:
os._exit(0) # Exit parent of the first child.
# Close all open files. Try the system configuration variable, SC_OPEN_MAX,
# for the maximum number of open files to close. If it doesn't exist, use
# the default value (configurable).
try:
maxfd = os.sysconf("SC_OPEN_MAX")
except (AttributeError, ValueError):
maxfd = 256 # default maximum
for fd in range(0, maxfd):
try:
os.close(fd)
except OSError: # ERROR (ignore)
pass
# Redirect the standard file descriptors to /dev/null.
os.open("/dev/null", os.O_RDONLY) # standard input (0)
os.open("/dev/null", os.O_RDWR) # standard output (1)
os.open("/dev/null", os.O_RDWR) # standard error (2)
return True
def sigTERMhandler(signum, frame):
""" Handles the TERM signal when in daemon mode in order to
exit properly.
"""
logSys.debug("Signal handler called with sig "+`signum`)
killApp()
killApp()
def setFwMustCheck(value):
""" Set the mustCheck value of the firewalls (True/False)
"""
for element in logFwList:
element[2].setMustCheck(value)
def initializeFwRules():
""" Initializes firewalls by running cmdstart and then
fwstart for each section
"""
# Execute global start command
executeCmd(conf["cmdstart"], conf["debug"])
# Execute start command of each section
for element in logFwList:
element[2].initialize(conf["debug"])
def reBan():
""" For each section asks the Firewall to reban known IPs
"""
for element in logFwList:
element[2].reBan(conf["debug"])
def restoreFwRules():
""" Flush the ban list
"""
logSys.warn("Restoring firewall rules...")
try:
for element in logFwList:
# Execute end command of each section
element[2].restore(conf["debug"])
# Execute global end command
executeCmd(conf["cmdend"], conf["debug"])
except ExternalError:
# nothing bad really - we can survive :-)
pass
def killApp():
""" Flush the ban list, remove the PID lock file and exit
nicely.
"""
logSys.warn("Restoring firewall rules...")
fireWall.flushBanList(conf["debug"])
removePID(conf["pidlock"])
# Restore Fw rules
restoreFwRules()
# Remove the PID lock
pidLock.remove()
logSys.info("Exiting...")
logging.shutdown()
sys.exit(0)
def checkForPID(lockfile):
""" Checks for running Fail2Ban.
Returns the current PID if Fail2Ban is running or False
if no instance found.
"""
try:
fileHandler = open(lockfile)
pid = fileHandler.readline()
return pid
except IOError:
return False
def createPID(lockfile):
""" Creates a PID lock file with the current PID.
"""
fileHandler = open(lockfile, mode='w')
pid = os.getpid()
fileHandler.write(`pid`+'\n')
fileHandler.close()
logSys.debug("Created PID lock ("+`pid`+") in "+lockfile)
def removePID(lockfile):
""" Remove PID lock.
"""
os.remove(lockfile)
logSys.debug("Removed PID lock "+lockfile)
def killPID(pid):
""" Kills the process with the given PID using the
INT signal (same effect as <ctrl>+<c>).
def getCmdLineOptions(optList):
""" Gets the command line options
"""
try:
return os.kill(pid, 2)
except OSError:
logSys.error("Can not kill process " + `pid` + ". Please check that " +
"Fail2Ban is not running and remove the file " +
"'/tmp/fail2ban.pid'")
if __name__ == "__main__":
# Gets an instance of log4py.
logSys = log4py.Logger().get_instance()
logSys.set_formatstring("%T %L %M")
conf = dict()
conf["verbose"] = 0
conf["background"] = False
conf["debug"] = False
conf["conffile"] = "/etc/fail2ban.conf"
conf["pidlock"] = "/tmp/fail2ban.pid"
conf["logging"] = False
conf["logfile"] = "/var/log/fail2ban.log"
conf["maxretry"] = 3
conf["bantime"] = 600
conf["ignoreip"] = ''
conf["interface"] = "eth0"
conf["firewall"] = "iptables"
conf["ipfw-start-rule"] = 0
conf["polltime"] = 1
# Reads the command line options.
try:
optList, args = getopt.getopt(sys.argv[1:], 'hvbdkc:l:t:i:r:e:w:p:')
except getopt.GetoptError:
usage()
# Pre-parsing of command line options for the -c option
for opt in optList:
if opt[0] == "-c":
conf["conffile"] = opt[1]
# Config file
configParser = SafeConfigParser()
configParser.read(conf["conffile"])
# background
try:
conf["background"] = configParser.getboolean("DEFAULT", "background")
except ValueError:
logSys.warn("background option should be a boolean")
logSys.warn("Using default value")
except NoOptionError:
logSys.warn("background option not in config file")
logSys.warn("Using default value")
# debug
try:
conf["debug"] = configParser.getboolean("DEFAULT", "debug")
except ValueError:
logSys.warn("debug option should be a boolean")
logSys.warn("Using default value")
except NoOptionError:
logSys.warn("debug option not in config file")
logSys.warn("Using default value")
# logfile
try:
conf["logfile"] = configParser.get("DEFAULT", "logfile")
except ValueError:
logSys.warn("logfile option should be a string")
logSys.warn("Using default value")
except NoOptionError:
logSys.warn("logfile option not in config file")
logSys.warn("Using default value")
# pidlock
try:
conf["pidlock"] = configParser.get("DEFAULT", "pidlock")
except ValueError:
logSys.warn("pidlock option should be a string")
logSys.warn("Using default value")
except NoOptionError:
logSys.warn("pidlock option not in config file")
logSys.warn("Using default value")
# maxretry
try:
conf["maxretry"] = configParser.getint("DEFAULT", "maxretry")
except ValueError:
logSys.warn("maxretry option should be an integer")
logSys.warn("Using default value")
except NoOptionError:
logSys.warn("maxretry option not in config file")
logSys.warn("Using default value")
# bantime
try:
conf["bantime"] = configParser.getint("DEFAULT", "bantime")
except ValueError:
logSys.warn("bantime option should be an integer")
logSys.warn("Using default value")
except NoOptionError:
logSys.warn("bantime option not in config file")
logSys.warn("Using default value")
# ignoreip
try:
conf["ignoreip"] = configParser.get("DEFAULT", "ignoreip")
except ValueError:
logSys.warn("ignoreip option should be a string")
logSys.warn("Using default value")
except NoOptionError:
logSys.warn("ignoreip option not in config file")
logSys.warn("Using default value")
# interface
try:
conf["interface"] = configParser.get("DEFAULT", "interface")
except ValueError:
logSys.warn("interface option should be a string")
logSys.warn("Using default value")
except NoOptionError:
logSys.warn("interface option not in config file")
logSys.warn("Using default value")
# firewall
try:
conf["firewall"] = configParser.get("DEFAULT", "firewall")
except ValueError:
logSys.warn("firewall option should be a string")
logSys.warn("Using default value")
except NoOptionError:
logSys.warn("firewall option not in config file")
logSys.warn("Using default value")
# ipfw-start-rule
try:
conf["ipfw-start-rule"] = configParser.getint("DEFAULT",
"ipfw-start-rule")
except ValueError:
logSys.warn("ipfw-start-rule option should be an integer")
logSys.warn("Using default value")
except NoOptionError:
logSys.warn("ipfw-start-rule option not in config file")
logSys.warn("Using default value")
# polltime
try:
conf["polltime"] = configParser.getint("DEFAULT", "polltime")
except ValueError:
logSys.warn("polltime option should be an integer")
logSys.warn("Using default value")
except NoOptionError:
logSys.warn("polltime option not in config file")
logSys.warn("Using default value")
for opt in optList:
if opt[0] == "-h":
usage()
if opt[0] == "-v":
conf["verbose"] = conf["verbose"] + 1
if opt[0] == "-b":
conf["background"] = True
if opt[0] == "-d":
conf["debug"] = True
if opt[0] == "-e":
conf["interface"] = opt[1]
if opt[0] == "-l":
conf["logging"] = True
conf["logfile"] = opt[1]
if opt[0] == "-t":
try:
conf["bantime"] = int(opt[1])
except ValueError:
logSys.warn("banTime must be an integer")
logSys.warn("Using default value")
if opt[0] == "-f":
try:
conf["findtime"] = int(opt[1])
except ValueError:
logSys.warn("findTime must be an integer")
logSys.warn("Using default value")
if opt[0] == "-i":
conf["ignoreip"] = opt[1]
if opt[0] == "-r":
conf["retrymax"] = int(opt[1])
if opt[0] == "-w":
conf["firewall"] = opt[1]
conf["maxfailures"] = int(opt[1])
if opt[0] == "-p":
conf["pidlock"] = opt[1]
if opt[0] == "-k":
pid = checkForPID(conf["pidlock"])
if pid:
killPID(int(pid))
logSys.warn("Killed Fail2Ban with PID "+pid)
sys.exit(0)
else:
logSys.error("No running Fail2Ban found")
sys.exit(-1)
conf["kill"] = True
def main():
""" Fail2Ban main function
"""
# Add the default logging handler
stdout = logging.StreamHandler(sys.stdout)
logSys.addHandler(stdout)
# Default formatter
formatterstring='%(levelname)s: %(message)s'
formatter = logging.Formatter('%(asctime)s ' + formatterstring)
stdout.setFormatter(formatter)
conf["kill"] = False
conf["debug"] = False
conf["verbose"] = 0
conf["conffile"] = "/etc/fail2ban.conf"
# Reads the command line options.
try:
cmdOpts = 'hvVbdkc:t:i:r:p:'
cmdLongOpts = ['help', 'version']
optList, args = getopt.getopt(sys.argv[1:], cmdOpts, cmdLongOpts)
except getopt.GetoptError:
dispUsage()
# Pre-parsing of command line options for the -c option
for opt in optList:
if opt[0] == "-c":
conf["conffile"] = opt[1]
if opt[0] in ["-h", "--help"]:
dispUsage()
if opt[0] in ["-V", "--version"]:
dispVersion()
# Reads the config file and create a LogReader instance for
# each log file to check.
confReader = ConfigReader(conf["conffile"])
confReader.openConf()
# Options
optionValues = (["bool", "background", False],
["str", "logtargets", "/var/log/fail2ban.log"],
["str", "syslog-target", "/dev/log"],
["int", "syslog-facility", 1],
["str", "pidlock", "/var/run/fail2ban.pid"],
["str", "locale", ""],
["int", "maxfailures", 5],
["int", "bantime", 600],
["int", "findtime", 600],
["str", "ignoreip", ""],
["int", "polltime", 1],
["str", "cmdstart", ""],
["str", "cmdend", ""],
["int", "reinittime", 100],
["int", "maxreinits", 100])
# Gets global configuration options
conf.update(confReader.getLogOptions("DEFAULT", optionValues))
# Gets command line options
getCmdLineOptions(optList)
# PID lock
pidLock.setPath(conf["pidlock"])
# Set the LC_TIME with the user's default setting
try:
logSys.info("Setting LC_TIME locale option to '%s'"%conf["locale"])
locale.setlocale(locale.LC_TIME, conf["locale"])
except Exception:
logSys.error("Unable to set locale to '%s'"%conf["locale"])
sys.exit(-1)
# Now we can kill properly a running instance if needed
if conf["kill"]:
pid = pidLock.exists()
if pid:
killPID(int(pid))
logSys.warn("Killed Fail2Ban with PID "+pid)
sys.exit(0)
else:
logSys.error("No running Fail2Ban found")
sys.exit(-1)
# Start Fail2Ban in daemon mode
if conf["background"]:
retCode = createDaemon()
signal.signal(signal.SIGTERM, sigTERMhandler)
if not retCode:
logSys.error("Unable to start daemon")
sys.exit(-1)
# Process some options
for c in conf:
if c == "verbose":
logSys.warn("Verbose level is "+`conf[c]`)
if conf[c] == 1:
logSys.set_loglevel(log4py.LOGLEVEL_VERBOSE)
elif conf[c] > 1:
logSys.set_loglevel(log4py.LOGLEVEL_DEBUG)
elif c == "debug" and conf[c]:
logSys.set_loglevel(log4py.LOGLEVEL_DEBUG)
logSys.set_formatstring(log4py.FMT_DEBUG)
elif c == "background" and conf[c]:
retCode = createDaemon()
signal.signal(signal.SIGTERM, sigTERMhandler)
logSys.set_target(conf["logfile"])
if not retCode:
logSys.error("Unable to start daemon")
sys.exit(-1)
elif c == "logging" and conf[c]:
try:
open(conf["logfile"], "a")
logSys.set_target(conf["logfile"])
except IOError:
logSys.warn("Unable to log to "+conf["logfile"])
logSys.warn("Using default output for logging")
elif c == "ignoreip":
ignoreIPList = conf[c].split(' ')
elif c == "firewall":
conf[c] = string.lower(conf[c])
if conf[c] == "ipfw":
fireWallName = "Ipfw"
elif conf[c] == "ipfwadm":
fireWallName = "Ipfwadm"
# First setup Log targets
# Bug fix for #1234699
os.umask(0077)
for target in conf["logtargets"].split():
# target formatter
# By default global formatter is taken. Is different for SYSLOG
tformatter = formatter
if target == "STDERR":
hdlr = logging.StreamHandler(sys.stderr)
elif target == "SYSLOG":
# SYSLOG target can be either
# a socket (file, so it starts with /)
# or hostname
# or hostname:port
syslogtargets = re.findall("(/[\w/]*)|([^/ ][^: ]*)(:(\d+)){,1}",
conf["syslog-target"])
# we are waiting for a single match
syslogtargets = syslogtargets[0]
# assign facility if it was defined
if conf["syslog-facility"] < 0:
facility = handlers.SysLogHandler.LOG_USER
else:
fireWallName = "Iptables"
facility = conf["syslog-facility"]
if len(syslogtargets) == 0: # everything default
hdlr = logging.handlers.SysLogHandler()
else:
if not (syslogtargets[0] == ""): # got socket
syslogtarget = syslogtargets[0]
else: # got hostname and maybe a port
if syslogtargets[3] == "": # no port specified
port = 514
else:
port = int(syslogtargets[3])
syslogtarget = (syslogtargets[1], port)
hdlr = logging.handlers.SysLogHandler(syslogtarget, facility)
tformatter = logging.Formatter("%(asctime)s %(name)s " +
formatterstring, "%b %e %T");
else:
# Target should be a file
try:
open(target, "a")
hdlr = logging.FileHandler(target)
except IOError:
logSys.error("Unable to log to " + target)
continue
# Set formatter and add handler to logger
hdlr.setFormatter(tformatter)
logSys.addHandler(hdlr)
# Verbose level
if conf["verbose"]:
logSys.warn("Verbose level is "+`conf["verbose"]`)
if conf["verbose"] == 1:
logSys.setLevel(logging.INFO)
elif conf["verbose"] > 1:
logSys.setLevel(logging.DEBUG)
if conf["verbose"] > 2:
formatterstring = ('%(levelname)s: [%(filename)s (%(lineno)d)] ' +
'%(message)s')
formatter = logging.Formatter("%(asctime)s " + formatterstring)
stdout.setFormatter(formatter)
# Debug mode. Should only be used by developers
if conf["debug"]:
logSys.warn("DEBUG MODE: FIREWALL COMMANDS ARE _NOT_ EXECUTED BUT " +
"ONLY DISPLAYED IN THE LOG MESSAGES")
# Ignores IP list
# and filter out empty entries. Otherwise
# WARNING: is not a valid IP address
ignoreIPList = filter(None, conf["ignoreip"].split(' '))
# Checks for root user. This is necessary because log files
# are owned by root and firewall needs root access.
if not checkForRoot():
@@ -440,51 +348,115 @@ if __name__ == "__main__":
sys.exit(-1)
# Checks that no instance of Fail2Ban is currently running.
pid = checkForPID(conf["pidlock"])
pid = pidLock.exists()
if pid:
logSys.error("Fail2Ban already running with PID "+pid)
sys.exit(-1)
else:
createPID(conf["pidlock"])
ret = pidLock.create()
if not ret:
# Unable to create PID lock. Exit
sys.exit(-1)
logSys.debug("ConfFile is "+conf["conffile"])
logSys.debug("BanTime is "+`conf["bantime"]`)
logSys.debug("retryAllowed is "+`conf["maxretry"]`)
logSys.debug("ConfFile is " + conf["conffile"])
logSys.debug("BanTime is " + `conf["bantime"]`)
logSys.debug("FindTime is " + `conf["findtime"]`)
logSys.debug("MaxFailure is " + `conf["maxfailures"]`)
# Reads the config file and create a LogReader instance for
# each log file to check.
confReader = ConfigReader(logSys, conf["conffile"]);
confReader.openConf()
logList = list()
# Options
optionValues = (["bool", "enabled", False],
["str", "host", "localhost"],
["int", "port", "25"],
["str", "from", "root"],
["str", "to", "root"],
["str", "user", ''],
["str", "password", ''],
["bool", "localtime", False],
["str", "subject", "[Fail2Ban] Banned <ip>"],
["str", "message", "Fail2Ban notification"])
# Gets global configuration options
mailConf = confReader.getLogOptions("MAIL", optionValues)
# Create mailer if enabled
if mailConf["enabled"]:
logSys.debug("Mail enabled")
mail = Mail(mailConf["host"], mailConf["port"])
mail.setFromAddr(mailConf["from"])
mail.setUser(mailConf["user"])
mail.setPassword(mailConf["password"])
mail.setToAddr(mailConf["to"])
mail.setLocalTimeFlag(mailConf["localtime"])
logSys.debug("to: " + mailConf["to"] + " from: " + mailConf["from"])
# Options
optionValues = (["bool", "enabled", False],
["str", "logfile", "/dev/null"],
["int", "maxfailures", conf["maxfailures"]],
["int", "bantime", conf["bantime"]],
["int", "findtime", conf["findtime"]],
["str", "timeregex", ""],
["str", "timepattern", ""],
["str", "failregex", ""],
["str", "fwstart", ""],
["str", "fwend", ""],
["str", "fwban", ""],
["str", "fwunban", ""],
["str", "fwcheck", ""])
logSys.info("Fail2Ban v" + version + " is running")
# Gets the options of each sections
for t in confReader.getSections():
l = confReader.getLogOptions(t)
l = confReader.getLogOptions(t, optionValues)
if l["enabled"]:
lObj = LogReader(logSys, l["logfile"], l["timeregex"],
l["timepattern"], l["failregex"], conf["bantime"])
lObj.setName(t)
logList.append(lObj)
# Creates one instance of Iptables (thanks to Pyhton dynamic
# features).
fireWallObj = eval(fireWallName)
fireWall = fireWallObj(conf["bantime"], logSys, conf["interface"])
# IPFW needs rules number. The configuration option "ipfw-start-rule"
# defines the first rule number used by Fail2Ban.
if fireWallName == "Ipfw":
fireWall.setCrtRuleNbr(conf["ipfw-start-rule"])
# Creates a logreader object
lObj = LogReader(l["logfile"], l["timeregex"], l["timepattern"],
l["failregex"], l["maxfailures"], l["findtime"])
# Creates a firewall object
fObj = Firewall(l["fwstart"], l["fwend"], l["fwban"], l["fwunban"],
l["fwcheck"], l["bantime"])
# "Name" the firewall
fObj.setSection(t)
# Links them into a list. I'm not really happy
# with this :/
logFwList.append([t, lObj, fObj, dict(), l])
# We add 127.0.0.1 to the ignore list has we do not want
# to be ban ourself.
for element in logList:
element.addIgnoreIP("127.0.0.1")
for element in logFwList:
element[1].addIgnoreIP("127.0.0.1")
while len(ignoreIPList) > 0:
ip = ignoreIPList.pop()
for element in logList:
element.addIgnoreIP(ip)
# Bug fix for #1239557
if isValidIP(ip):
for element in logFwList:
element[1].addIgnoreIP(ip)
else:
logSys.warn(ip + " is not a valid IP address")
logSys.info("Fail2Ban v"+version+" is running")
failListFull = dict()
# Startup loop -- necessary to avoid crash if it takes time for iptables
# to startup. To avoid introduction of new config options, reusing
# maxreinits and polltime.
reinits = 0
while True:
try:
initializeFwRules()
break
except ExternalError, e:
reinits += 1
logSys.warn(e)
if conf["maxreinits"] < 0 or (reinits < conf["maxreinits"]):
logSys.warn("#%d attempt to initialize the firewalls" % reinits)
else:
logSys.error("Exiting: Too many attempts to initialize the " +
"firewall")
killApp()
time.sleep(conf["polltime"])
# try to reinit once if it fails immediately
lastReinitTime = time.time() - conf["reinittime"] - 1
reinits = 0
# Main loop
while True:
try:
@@ -493,14 +465,15 @@ if __name__ == "__main__":
# Checks if some IP have to be remove from ban
# list.
fireWall.checkForUnBan(conf["debug"])
for element in logFwList:
element[2].checkForUnBan(conf["debug"])
# If the log file has not been modified since the
# last time, we sleep for 1 second. This is active
# polling so not very effective.
modList = list()
for element in logList:
if element.isModified():
for element in logFwList:
if element[1].isModified():
modList.append(element)
if len(modList) == 0:
@@ -509,43 +482,73 @@ if __name__ == "__main__":
# Gets the failure list from the log file. For a given IP,
# takes only the service which has the most password failures.
failList = dict()
for element in modList:
e = element.getFailures()
e = element[1].getFailures()
for key in e.iterkeys():
if failList.has_key(key):
if failList[key][0] < e[key][0]:
failList[key] = (e[key][0], e[key][1], element)
if element[3].has_key(key):
element[3][key] = (element[3][key][0] + e[key][0],
e[key][1])
else:
failList[key] = (e[key][0], e[key][1], element)
# Add the last log failures to the global failure list.
for key in failList.iterkeys():
if failListFull.has_key(key):
failListFull[key] = (failListFull[key][0] + 1,
failList[key][1], failList[key][2])
else:
failListFull[key] = failList[key]
element[3][key] = (e[key][0], e[key][1])
# Remove the oldest failure attempts from the global list.
unixTime = time.time()
failListFullTemp = failListFull.copy()
for key in failListFullTemp.iterkeys():
failTime = failListFullTemp[key][2].getFindTime()
if failListFullTemp[key][1] < unixTime - failTime:
del failListFull[key]
# We iterate the failure list and ban IP that make
# *retryAllowed* login failures.
failListFullTemp = failListFull.copy()
for key in failListFullTemp.iterkeys():
element = failListFullTemp[key]
if element[0] >= conf["maxretry"]:
logSys.info(element[2].getName()+": "+key+" has "+
`element[0]`+" login failure(s). Banned.")
fireWall.addBanIP(key, conf["debug"])
del failListFull[key]
unixTime = time.time()
for element in logFwList:
fails = element[3].copy()
findTime = element[1].getFindTime()
for attempt in fails:
failTime = fails[attempt][1]
if failTime < unixTime - findTime:
del element[3][attempt]
elif fails[attempt][0] >= element[1].getMaxRetry():
aInfo = {"section": element[0],
"ip": attempt,
"failures": element[3][attempt][0],
"failtime": failTime}
logSys.info(element[0] + ": " + aInfo["ip"] +
" has " + `aInfo["failures"]` +
" login failure(s). Banned.")
element[2].addBanIP(aInfo, conf["debug"])
# Send a mail notification
if 'mail' in locals():
mail.sendmail(mailConf["subject"],
mailConf["message"], aInfo)
del element[3][attempt]
except ExternalError, e:
# Something wrong while dealing with Iptables.
# May be chain got removed?
reinits += 1
logSys.error(e)
if ((unixTime - lastReinitTime > conf["reinittime"]) and
((conf["maxreinits"] < 0) or (reinits < conf["maxreinits"]))):
logSys.warn("#%d reinitialization of firewalls"%reinits)
lastReinitTime = unixTime
else:
logSys.error("Exiting: reinits follow too often, or too many " +
"reinit attempts")
killApp()
# We already failed runCheck so disable it until
# restoring a safe state
setFwMustCheck(False)
# save firewalls to keep a list of IPs for rebanning
logFwListCopy = copy.deepcopy(logFwList)
try:
# restore as much as possible
restoreFwRules()
# reinitialize all the chains
initializeFwRules()
# restore the lists of baned IPs
logFwList.__init__(logFwListCopy)
# reBan known IPs
reBan()
# Now we can enable the runCheck test again
setFwMustCheck(True)
except ExternalError:
raise ExternalError("Big Oops happened: situation is out of " +
"control. Something is wrong with your " +
"setup. Please check your settings")
except KeyboardInterrupt:
# When the user press <ctrl>+<c> we exit nicely.
killApp()
+125 -31
View File
@@ -24,54 +24,138 @@ __date__ = "$Date$"
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
__license__ = "GPL"
import time, os
import time, os, logging, re
from utils.process import executeCmd
from utils.strings import replaceTag
# unfortunately but I have to bring ExternalError in especially for
# flushBanList: if one of IPs got flushed manually outside or something, we
# might endup with not "full" flush unless we handle exception within the loop
from utils.process import ExternalError
# Gets the instance of the logger.
logSys = logging.getLogger("fail2ban")
class Firewall:
""" Manages the ban list and executes the command that ban
the IP.
"""
banList = dict()
def __init__(self, banTime, logSys, interface):
def __init__(self, startRule, endRule, banRule, unBanRule, checkRule,
banTime):
self.banRule = banRule
self.unBanRule = unBanRule
self.checkRule = checkRule
self.startRule = startRule
self.endRule = endRule
self.banTime = banTime
self.logSys = logSys
self.interface = interface
self.banList = dict()
self.section = ""
self.mustCheck = True
def setSection(self, section):
""" Set optional section name for clarify of logging
"""
self.section = section
def getMustCheck(self):
""" Return true if the runCheck test is executed
"""
return self.mustCheck
def addBanIP(self, ip, debug):
def setMustCheck(self, value):
""" Enable or disable the execution of runCheck test
"""
self.mustCheck = value
def initialize(self, debug):
logSys.debug("%s: Initialize firewall rules"%self.section)
executeCmd(self.startRule, debug)
def restore(self, debug):
logSys.debug("%s: Restore firewall rules"%self.section)
try:
self.flushBanList(debug)
executeCmd(self.endRule, debug)
except ExternalError:
pass
def addBanIP(self, aInfo, debug):
""" Bans an IP.
"""
ip = aInfo["ip"]
if not self.inBanList(ip):
self.logSys.warn("Ban "+ip)
self.banList[ip] = time.time()
self.__executeCmd(self.banIP(ip), debug)
crtTime = time.time()
if self.banTime < 0:
banMsg = "Ban (permanent)"
else:
banMsg = "Ban (%d s)"%self.banTime
logSys.warn("%s: %s "%(self.section, banMsg) + ip)
self.banList[ip] = crtTime
aInfo["bantime"] = crtTime
self.runCheck(debug)
cmd = self.banIP(aInfo)
if executeCmd(cmd, debug):
raise ExternalError("Firewall: execution of fwban command " +
"'%s' failed"%cmd)
else:
self.logSys.error(ip+" already in ban list")
self.runCheck(debug)
logSys.error("%s: "%self.section+ip+" already in ban list")
def delBanIP(self, ip, debug):
def delBanIP(self, aInfo, debug):
""" Unban an IP.
"""
ip = aInfo["ip"]
if self.inBanList(ip):
self.logSys.warn("Unban "+ip)
logSys.warn("%s: Unban "%self.section + ip)
del self.banList[ip]
self.__executeCmd(self.unBanIP(ip), debug)
self.runCheck(debug)
executeCmd(self.unBanIP(aInfo), debug)
else:
self.logSys.error(ip+" not in ban list")
logSys.error("%s: "%self.section+ip+" not in ban list")
def reBan(self, debug):
""" Re-Bans known IPs.
TODO: implement "failures" and "failtime"
"""
for ip in self.banList:
aInfo = {"ip": ip,
"bantime":self.banList[ip]}
logSys.warn("%s: ReBan "%self.section + ip)
# next piece is similar to the on in addBanIp
# so might be one more function will not hurt
self.runCheck(debug)
executeCmd(self.banIP(aInfo), debug)
def inBanList(self, ip):
""" Checks if IP is in ban list.
"""
return self.banList.has_key(ip)
def checkForUnBan(self, debug):
""" Check for IP to remove from ban list.
def runCheck(self, debug):
""" Runs fwcheck command and throws an exception if it returns non-0
result
"""
if self.mustCheck:
executeCmd(self.checkRule, debug)
else:
return None
def checkForUnBan(self, debug):
""" Check for IP to remove from ban list. If banTime is smaller than
zero, IP will be never removed.
"""
if self.banTime < 0:
# Permanent banning
return
banListTemp = self.banList.copy()
for element in banListTemp.iteritems():
ip = element[0]
btime = element[1]
if btime < time.time()-self.banTime:
self.delBanIP(ip, debug)
aInfo = {"ip": element[0],
"bantime": btime,
"unbantime": time.time()}
self.delBanIP(aInfo, debug)
def flushBanList(self, debug):
""" Flushes the ban list and of course the firewall rules.
@@ -79,18 +163,28 @@ class Firewall:
"""
banListTemp = self.banList.copy()
for element in banListTemp.iteritems():
ip = element[0]
self.delBanIP(ip, debug)
def __executeCmd(self, cmd, debug):
""" Executes an OS command.
aInfo = {"ip": element[0],
"bantime": element[1],
"unbantime": time.time()}
try:
self.delBanIP(aInfo, debug)
except ExternalError:
# we must let it fail here in the loop, or we don't
# flush properly
pass
def banIP(self, aInfo):
""" Returns query to ban IP.
"""
self.logSys.debug(cmd)
if not debug:
return os.system(cmd)
else:
return None
query = replaceTag(self.banRule, aInfo)
return query
def unBanIP(self, aInfo):
""" Returns query to unban IP.
"""
query = replaceTag(self.unBanRule, aInfo)
return query
def viewBanList(self):
""" Prints the ban list on screen. Usefull for debugging.
"""
-72
View File
@@ -1,72 +0,0 @@
# This file is part of Fail2Ban.
#
# Fail2Ban is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# Fail2Ban is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Fail2Ban; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
# Author: Cyril Jaquier
#
# $Revision$
__author__ = "Cyril Jaquier"
__version__ = "$Revision$"
__date__ = "$Date$"
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
__license__ = "GPL"
import os
from firewall import Firewall
class Ipfw(Firewall):
""" This class contains specific methods and variables for the
iptables firewall. Must implements the 'abstracts' methods
banIP(ip) and unBanIP(ip).
Must adds abstract methods definition:
http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/266468
"""
crtRuleNbr = 0
def getCrtRuleNbr(self):
""" Gets the current rule number.
"""
return self.crtRuleNbr
def setCrtRuleNbr(self, value):
""" Sets the current rule number.
"""
self.crtRuleNbr = value
def banIP(self, ip):
""" Returns query to ban IP.
"""
query = "ipfw -q add "+`self.crtRuleNbr`+" deny ip from "+ip+" to any"
self.crtRuleNbr = self.crtRuleNbr + 1
return query
def unBanIP(self, ip):
""" Returns query to unban IP.
"""
ruleNbr = str(self.__findRuleNumber(ip))
query = "ipfw -q delete "+ruleNbr
return query
def __findRuleNumber(self, ip):
""" Uses shell commands in order to find the rule
number we want to delete.
"""
output = os.popen("ipfw list|grep \"from "+ip+" to\"|awk '{print $1}'",
"r");
return output.read()
-48
View File
@@ -1,48 +0,0 @@
# This file is part of Fail2Ban.
#
# Fail2Ban is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# Fail2Ban is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Fail2Ban; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
# Author: Cyril Jaquier
#
# $Revision$
__author__ = "Cyril Jaquier"
__version__ = "$Revision$"
__date__ = "$Date$"
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
__license__ = "GPL"
from firewall import Firewall
class Iptables(Firewall):
""" This class contains specific methods and variables for the
iptables firewall. Must implements the 'abstracts' methods
banIP(ip) and unBanIP(ip).
Must adds abstract methods definition:
http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/266468
"""
def banIP(self, ip):
""" Returns query to ban IP.
"""
query = "iptables -I INPUT 1 -i "+self.interface+" -s "+ip+" -j DROP"
return query
def unBanIP(self, ip):
""" Returns query to unban IP.
"""
query = "iptables -D INPUT -i "+self.interface+" -s "+ip+" -j DROP"
return query
+8 -2
View File
@@ -1,3 +1,4 @@
[Wed Mar 31 15:11:28 2005] [error] [client www.google.ch] user cyril: authentication failure for "/phpinfo": Password Mismatch
[Mon Jan 03 05:02:15 2005] [error] [client 81.83.248.17] File does not exist: /var/www/jaquier.dyndns.org/htdocs/msadc
[Mon Jan 03 05:02:20 2005] [error] [client 81.83.248.17] File does not exist: /var/www/jaquier.dyndns.org/htdocs/msadc
[Mon Jan 03 05:02:20 2005] [error] [client 81.83.248.17] File does not exist: /var/www/jaquier.dyndns.org/htdocs/msadc
@@ -98,5 +99,10 @@
[Wed Jan 05 15:14:24 2005] [error] [client 192.168.0.129] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico
[Wed Jan 05 15:14:29 2005] [error] [client 192.168.0.129] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico
[Wed Jan 05 15:14:34 2005] [error] [client 192.168.0.129] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico
[Wed Mar 05 15:08:28 2005] [error] [client 192.168.0.128] user cyril: authentication failure for "/phpinfo": Password Mismatch
[Wed Mar 05 15:09:28 2005] [error] [client 192.168.0.128] user cyril: authentication failure for "/phpinfo": Password Mismatch
[Wed Mar 10 15:08:28 2005] [error] [client www.google.ch] user cyril: authentication failure for "/phpinfo": Password Mismatch
[Wed Mar 10 15:09:28 2005] [error] [client www.google.ch] user cyril: authentication failure for "/phpinfo": Password Mismatch
[Wed Mar 10 15:11:28 2005] [error] [client www.google.ch] user cyril: authentication failure for "/phpinfo": Password Mismatch
[Wed Mar 30 15:11:28 2005] [error] [client www.google.ch] user cyril: authentication failure for "/phpinfo": Password Mismatch
[Wed Mar 30 15:11:28 2005] [error] [client www.google.ch] user cyril: authentication failure for "/phpinfo": Password Mismatch
[Wed Mar 30 15:11:28 2005] [error] [client www.google.ch] user cyril: authentication failure for "/phpinfo": Password Mismatch
[Wed Mar 30 15:11:28 2005] [error] [client www.google.ch] user cyril: authentication failure for "/phpinfo": Password Mismatch
+6
View File
@@ -3,3 +3,9 @@ Jan 7 17:53:26 [sshd] (pam_unix) authentication failure; logname= uid=0 euid=0
Mar 7 17:53:28 [sshd] error: PAM: Authentication failure for kevin from 62.220.137.36
Mar 7 17:55:28 [sshd] error: PAM: Authentication failure for kevin from 62.220.137.36
Mar 7 17:57:28 [sshd] error: PAM: Authentication failure for kevin from 62.220.137.36
Mar 7 17:57:28 [sshd] error: PAM: Authentication failure for kevin from 192.168.0.128
Mar 7 17:57:28 [sshd] error: PAM: Authentication failure for kevin from 192.168.0.128
Mar 7 17:57:28 [sshd] error: PAM: Authentication failure for kevin from 192.168.0.128
Mar 7 17:57:28 [sshd] error: PAM: Authentication failure for kevin from 192.168.0.128
Mar 7 17:57:28 [sshd] error: PAM: Authentication failure for kevin from www.google.ch
Mar 7 17:57:28 [sshd] error: PAM: Authentication failure for kevin from www.google.ch
+90 -40
View File
@@ -24,39 +24,37 @@ __date__ = "$Date$"
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
__license__ = "GPL"
import os, sys, time, re
import os, sys, time, re, logging
from utils.dns import *
# Gets the instance of the logger.
logSys = logging.getLogger("fail2ban")
class LogReader:
""" Reads a log file and reports information about IP that make password
failure, bad user or anything else that is considered as doubtful login
attempt.
"""
def __init__(self, logSys, logPath, timeregex, timepattern, failregex,
findTime = 3600):
def __init__(self, logPath, timeregex, timepattern, failregex,
maxRetry, findTime):
self.logPath = logPath
self.maxRetry = maxRetry
self.timeregex = timeregex
self.timepattern = timepattern
self.failregex = failregex
self.findTime = findTime
self.ignoreIpList = []
self.lastModTime = 0
self.logSys = logSys
self.lastPos = 0
self.lastDate = 0
self.logStats = None
def setName(self, name):
""" Sets the name of the log reader.
def getMaxRetry(self):
""" Gets the maximum number of failures
"""
self.name = name
def getName(self):
""" Gets the name of the log reader.
"""
return self.name
return self.maxRetry
def getFindTime(self):
""" Gets the find time.
@@ -66,13 +64,23 @@ class LogReader:
def addIgnoreIP(self, ip):
""" Adds an IP to the ignore list.
"""
self.logSys.debug("Add "+ip+" to ignore list")
logSys.debug("Add "+ip+" to ignore list")
self.ignoreIpList.append(ip)
def inIgnoreIPList(self, ip):
""" Checks if IP is in the ignore list.
"""
return ip in self.ignoreIpList
for i in self.ignoreIpList:
s = i.split('/', 1)
# IP address without CIDR mask
if len(s) == 1:
s.insert(1, '32')
s[1] = long(s[1])
a = cidr(s[0], s[1])
b = cidr(ip, s[1])
if a == b:
return True
return False
def openLogFile(self):
""" Opens the log file specified on init.
@@ -80,8 +88,8 @@ class LogReader:
try:
fileHandler = open(self.logPath)
except OSError:
self.logSys.error("Unable to open "+self.logPath)
sys.exit(-1)
logSys.error("Unable to open "+self.logPath)
return fileHandler
def isModified(self):
@@ -89,16 +97,15 @@ class LogReader:
"""
try:
self.logStats = os.stat(self.logPath)
if self.lastModTime == self.logStats.st_mtime:
return False
else:
logSys.debug(self.logPath+" has been modified")
self.lastModTime = self.logStats.st_mtime
return True
except OSError:
self.logSys.error("Unable to get stat on "+self.logPath)
sys.exit(-1)
if self.lastModTime == self.logStats.st_mtime:
logSys.error("Unable to get stat on "+self.logPath)
return False
else:
self.logSys.debug(self.logPath+" has been modified")
self.lastModTime = self.logStats.st_mtime
return True
def setFilePos(self, file):
""" Sets the file position. We must take care of log file rotation
@@ -107,13 +114,13 @@ class LogReader:
"""
line = file.readline()
if self.lastDate < self.getTime(line):
self.logSys.debug("Date " + `self.lastDate` + " is " +
"smaller than " + `self.getTime(line)`)
self.logSys.debug("Log rotation detected for " + self.logPath)
logSys.debug("Date " + `self.lastDate` + " is " + "smaller than " +
`self.getTime(line)`)
logSys.debug("Log rotation detected for " + self.logPath)
self.lastPos = 0
self.logSys.debug("Setting file position to " + `self.lastPos` + " for "
+ self.logPath)
logSys.debug("Setting file position to " + `self.lastPos` + " for " +
self.logPath)
file.seek(self.lastPos)
def getFailures(self):
@@ -124,28 +131,36 @@ class LogReader:
and the latest failure time.
"""
ipList = dict()
self.logSys.debug(self.logPath)
logSys.debug(self.logPath)
logFile = self.openLogFile()
self.setFilePos(logFile)
lastLine = ''
for line in logFile.readlines():
lastLine = None
for line in logFile:
try:
# Try to convert UTF-8 string to Latin-1
line = line.decode('utf-8').encode('latin-1')
except UnicodeDecodeError:
pass
if not self.hasTime(line):
# There is no valid time in this line
continue
lastLine = line
failList = self.findFailure(line)
for element in failList:
for element in self.findFailure(line):
ip = element[0]
unixTime = element[1]
if unixTime < time.time()-self.findTime:
break
if self.inIgnoreIPList(ip):
self.logSys.debug("Ignore "+ip)
logSys.debug("Ignore "+ip)
continue
self.logSys.debug("Found "+ip)
logSys.debug("Found "+ip)
if ipList.has_key(ip):
ipList[ip] = (ipList[ip][0]+1, unixTime)
else:
ipList[ip] = (1, unixTime)
self.lastPos = logFile.tell()
self.lastDate = self.getTime(lastLine)
if lastLine:
self.lastDate = self.getTime(lastLine)
logFile.close()
return ipList
@@ -162,12 +177,30 @@ class LogReader:
timeMatch = re.search(self.timeregex, match.string)
if timeMatch:
date = self.getUnixTime(timeMatch.group())
ipMatch = textToIp(match.string)
try:
# Fix for CVE-2006-6302
matchString = match.group("host")
except IndexError:
# However does not break the current configuration
logSys.warn("No 'host' group defined. This is a security " +
"issue. Please fix your configuration file " +
"and look at CVE-2006-6302")
matchString = match.string
ipMatch = textToIp(matchString)
if ipMatch:
for ip in ipMatch:
failList.append([ip, date])
return failList
def hasTime(self, line):
""" Return true if the line contains a date
"""
timeMatch = re.search(self.timeregex, line)
if timeMatch:
return True
else:
return False
def getTime(self, line):
""" Gets the time of a log message.
"""
@@ -182,8 +215,25 @@ class LogReader:
Pattern should describe the date construction of
value.
"""
date = list(time.strptime(value, self.timepattern))
try:
# Check if the parsed value is in TAI64N format
if not self.timepattern.lower() == "tai64n":
date = list(time.strptime(value, self.timepattern))
else:
# extract part of format which represents seconds since epoch
seconds_since_epoch = value[2:17]
date = list(time.gmtime(int(seconds_since_epoch, 16)))
except ValueError, e:
logSys.error(e)
logSys.error("Please check the format and your locale settings.")
return None
if date[0] < 2000:
# There is probably no year field in the logs
date[0] = time.gmtime()[0]
# Bug fix for #1241756
# If the date is greater than the current time, we suppose
# that the log is not from this year but from the year before
if time.mktime(date) > time.time():
date[0] -= 1
unixTime = time.mktime(date)
return unixTime
+58
View File
@@ -0,0 +1,58 @@
.\"
.TH "FAIL2BAN" "8" "July 2005" "Cyril Jaquier" "System administration tools"
.SH "NAME"
fail2ban \- bans IP that makes too many password failures
.SH "SYNOPSIS"
.B fail2ban
[\fIOPTIONS\fR]
.SH "DESCRIPTION"
\fBFail2Ban\fR reads log file that contains password failure report
and bans the corresponding IP addresses using firewall rules. It updates
firewall rules to reject the IP address.
.SH "OPTIONS"
.TP
\fB\-b\fR
start in background
.TP
\fB\-c\fR \fIFILE\fR
read configuration file \fIFILE\fR
.TP
\fB\-p\fR \fIFILE\fR
create PID lock in \fIFILE\fR
.TP
\fB\-h, \-\-help\fR
display this help message
.TP
\fB\-i\fR \fIIP\fR
\fIIP\fR(s) to ignore
.TP
\fB\-k\fR
kill a currently running Fail2Ban instance
.TP
\fB\-r\fR \fIVALUE\fR
allow a max of \fIVALUE\fR password failure [maxfailures]
.TP
\fB\-t\fR \fITIME\fR
ban IP for \fITIME\fR seconds [bantime]
.TP
\fB\-f\fR \fITIME\fR
lifetime in seconds of failed entry [findtime]
.TP
\fB\-v\fR
verbose. Use twice for greater effect
.TP
\fB\-V, \-\-version\fR
print software version
.SH "FILES"
.I /etc/fail2ban.conf
.RS
The configuration file. See \fBfail2ban.conf\fR(5) for further details.
.SH "REPORTING BUGS"
Please report bugs at http://sourceforge.net/projects/fail2ban/
via bug tracker
.SH "AUTHOR"
Cyril Jaquier <lostcontrol@users.sourceforge.net>
.SH "SEE ALSO"
.TP
See
.BR "http://fail2ban.sourceforge.net/".
+20
View File
@@ -0,0 +1,20 @@
.\"
.TH "FAIL2BAN.CONF" "5" "July 2005" "Cyril Jaquier" "System administration tools"
.SH "NAME"
fail2ban.conf \- configuration data for fail2ban
.SH "DESCRIPTION"
\fB/etc/fail2ban.conf\fR contains data about the general configuration of fail2ban, the mail notification and services to monitor.
.SH "VARIABLES"
Please look at the file itself
.SH "FILES"
.I /etc/fail2ban.conf
.SH "REPORTING BUGS"
Please report bugs at http://sourceforge.net/projects/fail2ban/
via bug tracker
.SH "AUTHOR"
Cyril Jaquier <lostcontrol@users.sourceforge.net>
.SH "SEE ALSO"
.BR fail2ban (8)
.TP
See
.BR "http://fail2ban.sourceforge.net/".
+49 -9
View File
@@ -28,15 +28,55 @@ __license__ = "GPL"
from distutils.core import setup
from version import version
from os.path import isfile, join
from sys import exit, argv
longdesc = '''
Fail2Ban scans log files like /var/log/pwdfail or
/var/log/apache/error_log and bans IP that makes
too many password failures. It updates firewall rules
to reject the IP address or executes user defined
commands.'''
setup(
name = "fail2ban",
version = version,
description = "Ban IPs that make too many password failure",
author = "Cyril Jaquier",
author_email = "lostcontrol@users.sourceforge.net",
url = "http://www.sourceforge.net/projects/fail2ban",
scripts = ['fail2ban.py'],
py_modules = ['version'],
packages = ['firewall', 'logreader', 'confreader', 'utils']
name = "fail2ban",
version = version,
description = "Ban IPs that make too many password failure",
long_description = longdesc,
author = "Cyril Jaquier",
author_email = "lostcontrol@users.sourceforge.net",
url = "http://fail2ban.sourceforge.net",
license = "GPL",
platforms = "Posix",
scripts = ['fail2ban'],
py_modules = ['fail2ban', 'version'],
packages = ['firewall', 'logreader', 'confreader', 'utils']
)
# Do some checks after installation
# Search for obsolete files.
obsoleteFiles = []
elements = {"/usr/bin/": ["fail2ban.py"],
"/usr/lib/fail2ban/firewall/": ["iptables.py", "ipfwadm.py",
"ipfw.py"]}
for dir in elements:
for f in elements[dir]:
path = join(dir, f)
if isfile(path):
obsoleteFiles.append(path)
if obsoleteFiles:
print
print "Obsolete files from previous Fail2Ban versions were found on " \
"your system."
print "Please delete them:"
print
for f in obsoleteFiles:
print "\t" + f
print
# Update config file
if argv[1] == "install":
print
print "Please do not forget to update your configuration file."
print "Use config/fail2ban.conf.* as example."
print
+33 -3
View File
@@ -24,7 +24,7 @@ __date__ = "$Date$"
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
__license__ = "GPL"
import os, re, socket
import os, re, socket, struct
def dnsToIp(dns):
""" Convert a DNS into an IP address using the Python socket module.
@@ -37,8 +37,9 @@ def dnsToIp(dns):
def textToDns(text):
""" Search for possible DNS in an arbitrary text.
Thanks to Tom Pike.
"""
match = re.findall("\w*\.\w*\.\w*", text)
match = re.findall("(?:(?:\w|-)+\.){2,}\w+", text)
if match:
return match
else:
@@ -54,6 +55,16 @@ def searchIP(text):
else:
return []
def isValidIP(str):
""" Return true if str is a valid IP
"""
s = str.split('/', 1)
try:
socket.inet_aton(s[0])
return True
except socket.error:
return False
def textToIp(text):
""" Return the IP of DNS found in a given text.
"""
@@ -61,7 +72,8 @@ def textToIp(text):
# Search for plain IP
plainIP = searchIP(text)
for element in plainIP:
ipList.append(element)
if isValidIP(element):
ipList.append(element)
if not ipList:
# Try to get IP from possible DNS
dnsList = textToDns(text)
@@ -70,3 +82,21 @@ def textToIp(text):
for e in dns:
ipList.append(e)
return ipList
def cidr(i, n):
""" Convert an IP address string with a CIDR mask into a 32-bit
integer.
"""
# 32-bit IPv4 address mask
MASK = 0xFFFFFFFFL
return ~(MASK >> n) & MASK & addr2bin(i)
def addr2bin(str):
""" Convert a string IPv4 address into an unsigned integer.
"""
return struct.unpack("!L", socket.inet_aton(str))[0]
def bin2addr(addr):
""" Convert a numeric IPv4 address into string n.n.n.n form.
"""
return socket.inet_ntoa(struct.pack("!L", addr))
+91
View File
@@ -0,0 +1,91 @@
# This file is part of Fail2Ban.
#
# Fail2Ban is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# Fail2Ban is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Fail2Ban; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
# Author: Cyril Jaquier
#
# $Revision$
__author__ = "Cyril Jaquier"
__version__ = "$Revision$"
__date__ = "$Date$"
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
__license__ = "GPL"
import logging, smtplib, email.Utils
from utils.strings import replaceTag
# Gets the instance of the logger.
logSys = logging.getLogger("fail2ban")
class Mail:
""" Mailer class
"""
def __init__(self, host, port = 25):
self.host = host
self.port = port
self.localTimeFlag = False
def setFromAddr(self, fromAddr):
""" Set from: address
"""
self.fromAddr = fromAddr
def setUser(self, user):
""" Set smtpuser
"""
self.user = user
def setPassword(self, password):
""" Set smtppassword
"""
self.password = password
def setToAddr(self, toAddr):
""" Set to: address
"""
self.toAddr = toAddr.split()
def setLocalTimeFlag(self, localTimeFlag):
""" Set to: address
"""
self.localTimeFlag = localTimeFlag
def sendmail(self, subject, message, aInfo):
""" Send an email using smtplib
"""
subj = replaceTag(subject, aInfo)
msg = replaceTag(message, aInfo)
mail = ("From: %s\r\nTo: %s\r\nDate: %s\r\nSubject: %s\r\n\r\n" %
(self.fromAddr, ", ".join(self.toAddr),
email.Utils.formatdate(localtime = self.localTimeFlag),
subj)) + msg
try:
server = smtplib.SMTP(self.host, self.port)
#server.set_debuglevel(1)
if not self.user == '':
server.login(self.user, self.password)
server.sendmail(self.fromAddr, self.toAddr, mail)
logSys.debug("Email sent to " + `self.toAddr`)
server.quit()
except Exception, e:
logSys.error("Unable to send mail to " + self.host + ":" +
`self.port` + " from " + self.fromAddr + " to " +
`self.toAddr` + ": " + `e` + ": " + `e.args`)
+109
View File
@@ -0,0 +1,109 @@
# This file is part of Fail2Ban.
#
# Fail2Ban is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# Fail2Ban is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Fail2Ban; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
# Author: Cyril Jaquier
#
# $Revision$
__author__ = "Cyril Jaquier"
__version__ = "$Revision$"
__date__ = "$Date$"
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
__license__ = "GPL"
import os, logging
# Gets the instance of the logger.
logSys = logging.getLogger("fail2ban")
class PIDLock:
""" Manages the PID lock file.
The following class shows how to implement the singleton pattern[1] in
Python. A singleton is a class that makes sure only one instance of it
is ever created. Typically such classes are used to manage resources
that by their very nature can only exist once.
http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/52558
"""
class __impl:
""" Implementation of the singleton interface """
def setPath(self, path):
""" Set PID lock file path.
"""
self.path = path
def create(self):
""" Create PID lock.
"""
try:
fileHandler = open(self.path, mode='w')
pid = os.getpid()
fileHandler.write(`pid` + '\n')
fileHandler.close()
logSys.debug("Created PID lock (" + `pid` + ") in " + self.path)
return True
except:
logSys.error("Unable to create PID lock " + self.path)
return False
def remove(self):
""" Remove PID lock.
"""
try:
os.remove(self.path)
logSys.debug("Removed PID lock " + self.path)
except OSError:
logSys.error("Unable to remove PID lock " + self.path)
except AttributeError:
# AttributeError if self.path wasn't specified yet
logSys.debug("PID lock not removed because not defined yet")
def exists(self):
""" Returns the current PID if Fail2Ban is running or False
if no instance found.
"""
try:
fileHandler = open(self.path)
pid = fileHandler.readline()
fileHandler.close()
return pid
except IOError:
return False
# storage for the instance reference
__instance = None
def __init__(self):
""" Create singleton instance """
# Check whether we already have an instance
if PIDLock.__instance is None:
# Create and remember instance
PIDLock.__instance = PIDLock.__impl()
# Store instance reference as the only member in the handle
self.__dict__['_PIDLock__instance'] = PIDLock.__instance
def __getattr__(self, attr):
""" Delegate access to implementation """
return getattr(self.__instance, attr)
def __setattr__(self, attr, value):
""" Delegate access to implementation """
return setattr(self.__instance, attr, value)
+137
View File
@@ -0,0 +1,137 @@
# This file is part of Fail2Ban.
#
# Fail2Ban is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# Fail2Ban is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Fail2Ban; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
# Author: Cyril Jaquier
#
# $Revision$
__author__ = "Cyril Jaquier"
__version__ = "$Revision$"
__date__ = "$Date$"
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
__license__ = "GPL"
import os, logging, signal
# Gets the instance of the logger.
logSys = logging.getLogger("fail2ban")
class ExternalError(UserWarning):
""" Exception to warn about failed fwcheck or fwban command
"""
pass
def createDaemon():
""" Detach a process from the controlling terminal and run it in the
background as a daemon.
http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/278731
"""
try:
# Fork a child process so the parent can exit. This will return control
# to the command line or shell. This is required so that the new process
# is guaranteed not to be a process group leader. We have this guarantee
# because the process GID of the parent is inherited by the child, but
# the child gets a new PID, making it impossible for its PID to equal its
# PGID.
pid = os.fork()
except OSError, e:
return((e.errno, e.strerror)) # ERROR (return a tuple)
if (pid == 0): # The first child.
# Next we call os.setsid() to become the session leader of this new
# session. The process also becomes the process group leader of the
# new process group. Since a controlling terminal is associated with a
# session, and this new session has not yet acquired a controlling
# terminal our process now has no controlling terminal. This shouldn't
# fail, since we're guaranteed that the child is not a process group
# leader.
os.setsid()
# When the first child terminates, all processes in the second child
# are sent a SIGHUP, so it's ignored.
signal.signal(signal.SIGHUP, signal.SIG_IGN)
try:
# Fork a second child to prevent zombies. Since the first child is
# a session leader without a controlling terminal, it's possible for
# it to acquire one by opening a terminal in the future. This second
# fork guarantees that the child is no longer a session leader, thus
# preventing the daemon from ever acquiring a controlling terminal.
pid = os.fork() # Fork a second child.
except OSError, e:
return((e.errno, e.strerror)) # ERROR (return a tuple)
if (pid == 0): # The second child.
# Ensure that the daemon doesn't keep any directory in use. Failure
# to do this could make a filesystem unmountable.
os.chdir("/")
else:
os._exit(0) # Exit parent (the first child) of the second child.
else:
os._exit(0) # Exit parent of the first child.
# Close all open files. Try the system configuration variable, SC_OPEN_MAX,
# for the maximum number of open files to close. If it doesn't exist, use
# the default value (configurable).
try:
maxfd = os.sysconf("SC_OPEN_MAX")
except (AttributeError, ValueError):
maxfd = 256 # default maximum
for fd in range(0, maxfd):
try:
os.close(fd)
except OSError: # ERROR (ignore)
pass
# Redirect the standard file descriptors to /dev/null.
os.open("/dev/null", os.O_RDONLY) # standard input (0)
os.open("/dev/null", os.O_RDWR) # standard output (1)
os.open("/dev/null", os.O_RDWR) # standard error (2)
return True
def killPID(pid):
""" Kills the process with the given PID using the
INT signal (same effect as <ctrl>+<c>).
"""
try:
return os.kill(pid, signal.SIGTERM)
except OSError:
logSys.error("Can not kill process " + `pid` + ". Please check that " +
"Fail2Ban is not running and remove the file " +
"'/tmp/fail2ban.pid'")
return False
def executeCmd(cmd, debug):
""" Executes an OS command.
"""
if cmd == "":
logSys.debug("Nothing to do")
return None
logSys.debug(cmd)
if not debug:
retval = os.system(cmd)
if not retval == 0:
logSys.error("'" + cmd + "' returned " + `retval`)
raise ExternalError("Execution of command '%s' failed" % cmd)
return retval
else:
return None
+12 -20
View File
@@ -24,25 +24,17 @@ __date__ = "$Date$"
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
__license__ = "GPL"
from firewall import Firewall
import logging
class Ipfwadm(Firewall):
""" This class contains specific methods and variables for the
iptables firewall. Must implements the 'abstracts' methods
banIP(ip) and unBanIP(ip).
Must adds abstract methods definition:
http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/266468
# Gets the instance of the logger.
logSys = logging.getLogger("fail2ban")
def replaceTag(query, aInfo):
""" Replace tags in query
"""
def banIP(self, ip):
""" Returns query to ban IP.
"""
query = "ipfwadm -I -a deny -W "+self.interface+" -S "+ip
return query
def unBanIP(self, ip):
""" Returns query to unban IP.
"""
query = "ipfwadm -I -d deny -W "+self.interface+" -S "+ip
return query
string = query
for tag in aInfo:
string = string.replace('<'+tag+'>', `aInfo[tag]`)
# New line
string = string.replace('<br>', '\n')
return string
+1 -1
View File
@@ -24,4 +24,4 @@ __date__ = "$Date$"
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
__license__ = "GPL"
version = "0.3.1"
version = "0.6.2-SVN"