Compare commits

...
Author SHA1 Message Date
Cyril Jaquier 7e0e005e24 - Prepared for 0.5.2
git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/branches/FAIL2BAN-0_5@174 a942ae1a-1317-0410-a47c-b1dcaea8d605
2005-08-06 15:07:11 +00:00
Cyril Jaquier 800115a422 - Fixed a bug in logging level
git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/branches/FAIL2BAN-0_5@173 a942ae1a-1317-0410-a47c-b1dcaea8d605
2005-08-04 21:03:49 +00:00
Cyril Jaquier a8f98be252 - Updated
git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/branches/FAIL2BAN-0_5@172 a942ae1a-1317-0410-a47c-b1dcaea8d605
2005-08-04 21:01:12 +00:00
Cyril Jaquier e93c0db20b - Added new PID lock file management
- Fixed a bug with daemon mode and logging


git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/branches/FAIL2BAN-0_5@171 a942ae1a-1317-0410-a47c-b1dcaea8d605
2005-08-04 20:52:13 +00:00
Cyril Jaquier 1fcf7612fd - Added new PID lock file management
git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/branches/FAIL2BAN-0_5@170 a942ae1a-1317-0410-a47c-b1dcaea8d605
2005-08-04 20:51:14 +00:00
Cyril Jaquier 9761d31f4b - Updated
git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/branches/FAIL2BAN-0_5@169 a942ae1a-1317-0410-a47c-b1dcaea8d605
2005-08-04 20:49:00 +00:00
Cyril Jaquier 4d0c5f6341 - Added a PID lock file class
git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/branches/FAIL2BAN-0_5@168 a942ae1a-1317-0410-a47c-b1dcaea8d605
2005-08-04 20:48:30 +00:00
Cyril Jaquier d0a0088894 - Redirect stdout to /dev/null
git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/branches/FAIL2BAN-0_5@167 a942ae1a-1317-0410-a47c-b1dcaea8d605
2005-08-01 16:58:14 +00:00
Cyril Jaquier e8b4d66c54 - Removed log4py dependency
git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/branches/FAIL2BAN-0_5@166 a942ae1a-1317-0410-a47c-b1dcaea8d605
2005-08-01 16:41:33 +00:00
Cyril Jaquier 5a38a2563c - Removed log4py dependency
- Catch the unhandled exceptions


git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/branches/FAIL2BAN-0_5@165 a942ae1a-1317-0410-a47c-b1dcaea8d605
2005-08-01 16:40:46 +00:00
Cyril Jaquier c2d30a29de - Updated
git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/branches/FAIL2BAN-0_5@164 a942ae1a-1317-0410-a47c-b1dcaea8d605
2005-08-01 16:39:11 +00:00
Cyril Jaquier 8688acab65 - Removed log4py dependency
- Better handling of the return value of os.system()


git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/branches/FAIL2BAN-0_5@163 a942ae1a-1317-0410-a47c-b1dcaea8d605
2005-08-01 16:38:07 +00:00
Cyril Jaquier 4d9c24adbf - Removed log4py dependency
git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/branches/FAIL2BAN-0_5@162 a942ae1a-1317-0410-a47c-b1dcaea8d605
2005-08-01 16:35:18 +00:00
Cyril Jaquier bed25265d7 - Added man pages
git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/branches/FAIL2BAN-0_5@161 a942ae1a-1317-0410-a47c-b1dcaea8d605
2005-08-01 16:33:56 +00:00
Cyril Jaquier a081e8b3f5 - Updated
git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/branches/FAIL2BAN-0_5@160 a942ae1a-1317-0410-a47c-b1dcaea8d605
2005-07-28 20:59:28 +00:00
Cyril Jaquier bebba84f0e - Updated
git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/branches/FAIL2BAN-0_5@159 a942ae1a-1317-0410-a47c-b1dcaea8d605
2005-07-28 20:31:00 +00:00
Cyril Jaquier e40dd99727 - Added description
git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/branches/FAIL2BAN-0_5@158 a942ae1a-1317-0410-a47c-b1dcaea8d605
2005-07-28 20:30:34 +00:00
Cyril Jaquier 84042dbd31 - "maxretry" and "bantime" can be overridden in each section
git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/branches/FAIL2BAN-0_5@157 a942ae1a-1317-0410-a47c-b1dcaea8d605
2005-07-28 20:29:45 +00:00
Cyril Jaquier 45426598dd - "maxretry" and "bantime" can be overridden in each section
- Fixed bug #1246278 (excessive memory usage)


git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/branches/FAIL2BAN-0_5@156 a942ae1a-1317-0410-a47c-b1dcaea8d605
2005-07-28 20:27:26 +00:00
Cyril Jaquier 8686151421 - Fixed crash on wrong option value in configuration file
git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/branches/FAIL2BAN-0_5@155 a942ae1a-1317-0410-a47c-b1dcaea8d605
2005-07-28 20:20:13 +00:00
Cyril Jaquier 46a4f1fcf3 - Changed custom chains to lowercase
git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/branches/FAIL2BAN-0_5@154 a942ae1a-1317-0410-a47c-b1dcaea8d605
2005-07-28 20:18:59 +00:00
Cyril Jaquier d6e7bc7b03 - Prepared for 0.5.1
git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/branches/FAIL2BAN-0_5@152 a942ae1a-1317-0410-a47c-b1dcaea8d605
2005-07-23 09:31:12 +00:00
Cyril Jaquier 891b8d9e8a - Fixed a bug in the previous... bug fix
git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/branches/FAIL2BAN-0_5@151 a942ae1a-1317-0410-a47c-b1dcaea8d605
2005-07-23 09:07:53 +00:00
Cyril Jaquier 02386131e9 - Fixed bug #1239557
git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/branches/FAIL2BAN-0_5@150 a942ae1a-1317-0410-a47c-b1dcaea8d605
2005-07-22 21:13:19 +00:00
Cyril Jaquier a3f30d8555 - Updated
git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/branches/FAIL2BAN-0_5@149 a942ae1a-1317-0410-a47c-b1dcaea8d605
2005-07-22 21:12:14 +00:00
Cyril Jaquier ec299bd60f - Better check of IPv4 validity
git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/branches/FAIL2BAN-0_5@148 a942ae1a-1317-0410-a47c-b1dcaea8d605
2005-07-22 21:11:42 +00:00
Cyril Jaquier bbfc65f569 - Fixed bug #1241756
git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/branches/FAIL2BAN-0_5@147 a942ae1a-1317-0410-a47c-b1dcaea8d605
2005-07-22 21:10:29 +00:00
Cyril Jaquier 5dbed848bc - Updated
git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/branches/FAIL2BAN-0_5@146 a942ae1a-1317-0410-a47c-b1dcaea8d605
2005-07-15 19:28:15 +00:00
Cyril Jaquier bb430ec25c - Removed logfile option and added logtargets
git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/branches/FAIL2BAN-0_5@145 a942ae1a-1317-0410-a47c-b1dcaea8d605
2005-07-15 19:27:38 +00:00
Cyril Jaquier 74dfb8440e - Added obsolete files detection and update config reminder after install
git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/branches/FAIL2BAN-0_5@144 a942ae1a-1317-0410-a47c-b1dcaea8d605
2005-07-15 14:14:12 +00:00
Cyril Jaquier 2b8df84fa9 - Changed Fail2Ban description
git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/branches/FAIL2BAN-0_5@143 a942ae1a-1317-0410-a47c-b1dcaea8d605
2005-07-15 14:12:51 +00:00
Cyril Jaquier cd1ede8d5b - Updated
git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/branches/FAIL2BAN-0_5@142 a942ae1a-1317-0410-a47c-b1dcaea8d605
2005-07-15 14:11:49 +00:00
Cyril Jaquier 8e43d98ca4 - Moved path.append() before importing log4py
git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/branches/FAIL2BAN-0_5@141 a942ae1a-1317-0410-a47c-b1dcaea8d605
2005-07-15 14:11:21 +00:00
Cyril Jaquier 3b154baae5 - Removed os.umask(0) as it is a potential security issue. Thanks to Yaroslav Halchenko
git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/branches/FAIL2BAN-0_5@140 a942ae1a-1317-0410-a47c-b1dcaea8d605
2005-07-15 14:08:17 +00:00
Cyril Jaquier d2f7dc0521 - Fixed banList which must not be static
git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/branches/FAIL2BAN-0_5@139 a942ae1a-1317-0410-a47c-b1dcaea8d605
2005-07-15 14:07:08 +00:00
Cyril Jaquier 6be14566e1 - Corrected logfile path
- Changed firewall rules in order to create a specific chain for each section


git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/branches/FAIL2BAN-0_5@138 a942ae1a-1317-0410-a47c-b1dcaea8d605
2005-07-15 14:06:11 +00:00
Cyril Jaquier e919d8372b - Initial commit. Thanks to Yaroslav Halchenko
git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/branches/FAIL2BAN-0_5@137 a942ae1a-1317-0410-a47c-b1dcaea8d605
2005-07-15 14:04:39 +00:00
Cyril Jaquier df28acf495 - Prepared for 0.5.0
git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/branches/FAIL2BAN-0_5@136 a942ae1a-1317-0410-a47c-b1dcaea8d605
2005-07-12 13:12:40 +00:00
Cyril Jaquier 158110aa46 - Updated
git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/branches/FAIL2BAN-0_5@135 a942ae1a-1317-0410-a47c-b1dcaea8d605
2005-07-12 13:12:22 +00:00
Cyril Jaquier 0a8905e3a6 - Fixed bug #1234699
- Added mail notification support


git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/branches/FAIL2BAN-0_5@134 a942ae1a-1317-0410-a47c-b1dcaea8d605
2005-07-12 13:11:58 +00:00
Cyril Jaquier 3acb0b8548 - Added CIDR mask support
git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/branches/FAIL2BAN-0_5@133 a942ae1a-1317-0410-a47c-b1dcaea8d605
2005-07-12 13:10:14 +00:00
Cyril Jaquier a50d0ace81 - Initial commit
git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/branches/FAIL2BAN-0_5@132 a942ae1a-1317-0410-a47c-b1dcaea8d605
2005-07-12 13:09:47 +00:00
Cyril Jaquier dba169ae9c - Moved replaceTag() to utils/strings.py
git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/branches/FAIL2BAN-0_5@131 a942ae1a-1317-0410-a47c-b1dcaea8d605
2005-07-12 13:08:24 +00:00
Cyril Jaquier 8a94f873de - Removed MAIL for getSections()
git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/branches/FAIL2BAN-0_5@130 a942ae1a-1317-0410-a47c-b1dcaea8d605
2005-07-12 13:07:35 +00:00
Cyril Jaquier 6ae8556d15 - Added mail notification support
- Added CIDR mask support in ignoreip


git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/branches/FAIL2BAN-0_5@129 a942ae1a-1317-0410-a47c-b1dcaea8d605
2005-07-12 13:06:25 +00:00
Cyril Jaquier 7cdb6c94bb - Added more tags in firewall rules definition. Should help for Feature Request #1229479
git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/branches/FAIL2BAN-0_5@128 a942ae1a-1317-0410-a47c-b1dcaea8d605
2005-07-09 15:11:48 +00:00
Cyril Jaquier 18486d66bd - Updated
git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/branches/FAIL2BAN-0_5@127 a942ae1a-1317-0410-a47c-b1dcaea8d605
2005-07-09 15:09:03 +00:00
Cyril Jaquier 6ae86bd7d6 - Removed unused options
- Cleanup


git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/branches/FAIL2BAN-0_5@126 a942ae1a-1317-0410-a47c-b1dcaea8d605
2005-07-09 13:18:59 +00:00
Cyril Jaquier cb97a9e091 - Oups... I forgot to add this one. Now, this is the main executable
git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/branches/FAIL2BAN-0_5@125 a942ae1a-1317-0410-a47c-b1dcaea8d605
2005-07-08 10:21:52 +00:00
Cyril Jaquier 8e16185ef1 - Applied changes (command line options) from Yaroslav Halchenko
git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/branches/FAIL2BAN-0_5@124 a942ae1a-1317-0410-a47c-b1dcaea8d605
2005-07-08 10:01:04 +00:00
Cyril Jaquier ebccfea6cb - Added new fail2ban binary
git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/branches/FAIL2BAN-0_5@123 a942ae1a-1317-0410-a47c-b1dcaea8d605
2005-07-07 16:57:05 +00:00
Cyril Jaquier 5595ffcac7 - Lot of changes. Most of them are cleanup
git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/branches/FAIL2BAN-0_5@122 a942ae1a-1317-0410-a47c-b1dcaea8d605
2005-07-07 16:56:30 +00:00
Cyril Jaquier e98f8c8182 - Updated
git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/branches/FAIL2BAN-0_5@121 a942ae1a-1317-0410-a47c-b1dcaea8d605
2005-07-07 16:55:50 +00:00
Cyril Jaquier 3d79d9d1cb - Initial import
git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/branches/FAIL2BAN-0_5@120 a942ae1a-1317-0410-a47c-b1dcaea8d605
2005-07-07 16:53:47 +00:00
Cyril Jaquier 3df3c510f4 - Moved __executeCmd to utils/process.py
- Removed interface


git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/branches/FAIL2BAN-0_5@119 a942ae1a-1317-0410-a47c-b1dcaea8d605
2005-07-07 16:52:54 +00:00
Cyril Jaquier 65fef83e56 - Made configreader more generic. Also used for global options now
git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/branches/FAIL2BAN-0_5@118 a942ae1a-1317-0410-a47c-b1dcaea8d605
2005-07-07 16:51:52 +00:00
Cyril Jaquier 1014183f3f - Changed fail2ban binary name
git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/branches/FAIL2BAN-0_5@117 a942ae1a-1317-0410-a47c-b1dcaea8d605
2005-07-07 16:50:56 +00:00
Cyril Jaquier 992a3f7d31 - Added start and end command options
git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/branches/FAIL2BAN-0_5@116 a942ae1a-1317-0410-a47c-b1dcaea8d605
2005-07-07 16:50:20 +00:00
Cyril Jaquier 685f4aad99 - Initial 0.5 commit
git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/branches/FAIL2BAN-0_5@115 a942ae1a-1317-0410-a47c-b1dcaea8d605
2005-07-05 12:57:20 +00:00
Cyril Jaquier ea9a671e88 This commit was manufactured by cvs2svn to create branch 'FAIL2BAN-0_5'.
git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/branches/FAIL2BAN-0_5@114 a942ae1a-1317-0410-a47c-b1dcaea8d605
2005-07-01 09:30:52 +00:00
Cyril Jaquier 5c9c6e82cf This commit was manufactured by cvs2svn to create branch 'FAIL2BAN-0_5'.
git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/branches/FAIL2BAN-0_5@12 a942ae1a-1317-0410-a47c-b1dcaea8d605
2004-10-10 23:41:08 +00:00
30 changed files with 2299 additions and 254 deletions
+102
View File
@@ -0,0 +1,102 @@
__ _ _ ___ _
/ _|__ _(_) |_ ) |__ __ _ _ _
| _/ _` | | |/ /| '_ \/ _` | ' \
|_| \__,_|_|_/___|_.__/\__,_|_||_|
=============================================================
Fail2Ban (version 0.5.2) 2005/08/06
=============================================================
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 (2005/02/24) - beta
----------
- Re-writting of parts of the code in order to handle several
log files with different rules
- Removed sshd.py because it is no more needed
- Fixed a bug when exiting with IP in the ban list
- Added PID lock file
- Improved some parts of the code
- Added ipfw-start-rule option (thanks to Robert Edeker)
- Added -k option which kills a currently running Fail2Ban
ver. 0.1.2 (2004/11/21) - beta
----------
- Add ipfw and ipfwadm support. The rules are taken from
BlockIt. Thanks to Robert Edeker
- Add -e option which allows to set the interface. Thanks to
Robert Edeker who reminded me this
- Small code cleaning
ver. 0.1.1 (2004/10/23) - beta
----------
- Add SIGTERM handler in order to exit nicely when in daemon
mode
- Add -r option which allows to set the maximum number of
login failures
- Remove the Metalog class as the log file are not so syslog
daemon specific
- Rewrite log reader to be service centered. Sshd support
added. Match "Failed password" and "Illegal user"
- Add /etc/fail2ban.conf configuration support
- Code documentation
ver. 0.1.0 (2004/10/12) - alpha
----------
- Initial release
+27
View File
@@ -0,0 +1,27 @@
README
CHANGELOG
TODO
setup.cfg
setup.py
version.py
fail2ban
fail2ban.py
firewall/__init__.py
firewall/firewall.py
logreader/__init__.py
logreader/logreader.py
confreader/__init__.py
confreader/configreader.py
utils/__init__.py
utils/dns.py
utils/process.py
utils/mail.py
utils/strings.py
utils/pidlock.py
config/fail2ban.conf.default
config/gentoo-initd
config/gentoo-confd
config/redhat-initd
config/debian-initd
man/fail2ban.8
man/fail2ban.conf.5
+144
View File
@@ -0,0 +1,144 @@
__ _ _ ___ _
/ _|__ _(_) |_ ) |__ __ _ _ _
| _/ _` | | |/ /| '_ \/ _` | ' \
|_| \__,_|_|_/___|_.__/\__,_|_||_|
=============================================================
Fail2Ban (version 0.5.2) 2005/08/06
=============================================================
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. 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. Moreover, English is not my
mother tongue...
More details:
-------------
Fail2Ban is rather simple. I have a home server connected to
the Internet which runs apache, samba, sshd, ... I see in my
logs that people are trying to log into my box using "manual"
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. I found
nothing :-( So I decide to write mine and to learn Python :-)
For each sections defined in the configuration file, Fail2Ban
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 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, ...) and with different
firewalls.
Installation:
-------------
Require: python-2.3 (http://www.python.org)
To install, just do:
> tar xvfj fail2ban-0.5.2.tar.bz2
> cd fail2ban-0.5.2
> python setup.py install
This will install Fail2Ban into /usr/lib/fail2ban. The fail2ban
executable is placed into /usr/bin.
Gentoo: an ebuild is available on the website.
Debian: a package is available on the website.
Fail2Ban should now be correctly installed. Just type:
> 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.
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:
--------------
You can configure fail2ban using the file /etc/fail2ban.conf
or using command line options. Command line options override
the value stored in fail2ban.conf. Here are the command line
options:
-b start in background
-d start in debug mode
-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 instance
-r <VALUE> allow a max of VALUE password failure
-t <TIME> ban IP for TIME seconds
-v verbose. Use twice for greater effect
-V print software version
Contact:
--------
You need some new features, you found bugs or you just
appreciate this program, you can contact me at :
Website: http://fail2ban.sourceforge.net
Cyril Jaquier: <lostcontrol@users.sourceforge.net>
Thanks:
-------
Kévin Drapel, Marvin Rouge, Sireyessire, Robert Edeker,
Tom Pike, Iain Lea, Andrey G. Grozin, Yaroslav Halchenko
License:
--------
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
+12
View File
@@ -0,0 +1,12 @@
__ _ _ ___ _
/ _|__ _(_) |_ ) |__ __ _ _ _
| _/ _` | | |/ /| '_ \/ _` | ' \
|_| \__,_|_|_/___|_.__/\__,_|_||_|
=============================================================
ToDo
=============================================================
See Feature Request Tracking System at SourceForge.net
- improve installation process (better prefix support)
+61
View File
@@ -0,0 +1,61 @@
#! /bin/sh
#
# skeleton example file to build /etc/init.d/ scripts.
# This file should be used to construct scripts for /etc/init.d.
#
# Written by Miquel van Smoorenburg <miquels@cistron.nl>.
# Modified for Debian
# by Ian Murdock <imurdock@gnu.ai.mit.edu>.
#
# Version: @(#)skeleton 1.9 26-Feb-2001 miquels@cistron.nl
#
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 /var/run/$NAME.pid \
-b --exec $DAEMON -- $DAEMON_OPTS
echo "$NAME."
;;
stop)
echo -n "Stopping $DESC: "
start-stop-daemon --stop --quiet --pidfile /var/run/$NAME.pid
rm -f $PIDFILE
echo "$NAME."
;;
restart|force-reload)
#
# If the "reload" option is implemented, move the "force-reload"
# option to the "reload" entry above. If not, "force-reload" is
# just the same as "restart".
#
echo -n "Restarting $DESC: "
( $0 stop )
sleep 1
$0 start
;;
*)
N=/etc/init.d/$NAME
# echo "Usage: $N {start|stop|restart|reload|force-reload}" >&2
echo "Usage: $N {start|stop|restart|force-reload}" >&2
exit 1
;;
esac
exit 0
+272
View File
@@ -0,0 +1,272 @@
# 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: debug
# Notes.: enable debug mode. More verbose output and bypass root user test.
# Values: [true | false] Default: false
#
debug = false
# 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: 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: maxretry
# Notes.: number of retrys before IP gets banned.
# Values: NUM Default: 3
#
maxretry = 3
# Option: bantime
# Notes.: number of seconds an IP will be banned.
# Values: NUM Default: 600
#
bantime = 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: 192.168.0.0/24
#
ignoreip = 192.168.0.0/24
# 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
[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: 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: subject
# Notes.: subject of the e-mail.
# Tags: <ip> IP address
# <failures> number of failures
# <failtime> unix timestamp of the last failure
# Values: TEXT Default: [Fail2Ban] Banned <ip>
#
subject = [Fail2Ban] Banned <ip>
# Option: message
# Notes.: message of the e-mail.
# Tags: <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.<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: fwstart
# Notes.: command executed once at the start of Fail2Ban
# Values: CMD Default:
#
fwstart = iptables -N fail2ban-http
iptables -I INPUT -i eth0 -p tcp --dport http -j fail2ban-http
iptables -A fail2ban-http -j RETURN
# Option: fwend
# Notes.: command executed once at the end of Fail2Ban
# Values: CMD Default:
#
fwend = iptables -D INPUT -i eth0 -p tcp --dport http -j fail2ban-http
iptables -D fail2ban-http -j RETURN
iptables -X fail2ban-http
# 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 -i eth0 -s <ip> -j DROP
#
fwban = iptables -I fail2ban-http 1 -i eth0 -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 -i eth0 -s <ip> -j DROP
#
fwunban = iptables -D fail2ban-http -i eth0 -s <ip> -j DROP
# Option: timeregex
# Notes.: regex to match timestamp in Apache logfile.
# 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)
# 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 = authentication failure|user .* not found
[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: fwstart
# Notes.: command executed once at the start of Fail2Ban
# Values: CMD Default:
#
fwstart = iptables -N fail2ban-ssh
iptables -I INPUT -i eth0 -p tcp --dport ssh -j fail2ban-ssh
iptables -A fail2ban-ssh -j RETURN
# Option: fwend
# Notes.: command executed once at the end of Fail2Ban
# Values: CMD Default:
#
fwend = iptables -D INPUT -i eth0 -p tcp --dport ssh -j fail2ban-ssh
iptables -D fail2ban-ssh -j RETURN
iptables -X fail2ban-ssh
# Option: fwbanrule
# 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 -i eth0 -s <ip> -j DROP
#
fwban = iptables -I fail2ban-ssh 1 -i eth0 -s <ip> -j DROP
# Option: fwunbanrule
# 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 -i eth0 -s <ip> -j DROP
#
fwunban = iptables -D fail2ban-ssh -i eth0 -s <ip> -j DROP
# Option: timeregex
# Notes.: regex to match timestamp in SSH 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 = Authentication failure|Failed password|Invalid user
+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.py -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
+25
View File
@@ -0,0 +1,25 @@
# 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"
+85
View File
@@ -0,0 +1,85 @@
# 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
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.
"""
def __init__(self, confPath):
self.confPath = confPath
self.configParser = SafeConfigParser()
def openConf(self):
""" Opens the configuration file.
"""
self.configParser.read(self.confPath)
def getSections(self):
""" Returns all the sections present in the configuration
file except the DEFAULT and MAIL sections.
"""
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 options:
try:
if option[0] == "bool":
v = self.configParser.getboolean(sec, option[1])
elif option[0] == "int":
v = self.configParser.getint(sec, option[1])
else:
v = self.configParser.get(sec, option[1])
values[option[1]] = v
except NoOptionError:
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
+27 -138
View File
@@ -26,146 +26,35 @@ __date__ = "$Date$"
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
__license__ = "GPL"
import posix,sys,os
import string,re,time
import sys, traceback, logging
from firewall.iptables import Iptables
# Appends our own modules path.
sys.path.append("/usr/lib/fail2ban")
def checkForRoot():
""" Check for root user.
"""
uid = `posix.getuid()`
if uid == '0':
return True
else:
return False
# Now we can import our modules.
import fail2ban
from utils.pidlock import PIDLock
# start: To be removed
def executeCmd(cmd):
return #os.system(cmd)
# Get the instance of the logger.
logSys = logging.getLogger("fail2ban")
def unBanIP(ip):
iptables = 'iptables -D INPUT -i eth0 -s '+ip+' -j DROP'
executeCmd(iptables)
print iptables
# Get PID lock file instance
pidLock = PIDLock()
def banIP(ip):
iptables = 'iptables -I INPUT 1 -i eth0 -s '+ip+' -j DROP'
executeCmd(iptables)
print iptables
# end:
def checkForUnBan(banList, currentTime, banTime):
""" Check for user to remove from ban list.
"""
iterBanList = banList.iteritems()
for i in range(len(banList)):
element = iterBanList.next()
ip = element[0]
btime = element[1]
if btime < currentTime-banTime:
del banList[ip]
unBanIP(ip)
print '`->', currentTime
return banList
def checkForBan(retryList, banList, currentTime):
iterRetry = retryList.iteritems()
for i in range(len(retryList)):
element = iterRetry.next()
retry = element[1][0]
ip = element[0]
if element[1][0] > 2 and not banList.has_key(ip):
banList[ip] = currentTime
banIP(ip)
print '`->', currentTime
return banList
def flushBanList(banList):
iterBanList = banList.iteritems()
for i in range(len(banList)):
element = iterBanList.next()
ip = element[0]
unBanIP(ip)
def parseLogLine(line):
""" Match sshd failed password log
"""
if re.search("Failed password", line):
matchIP = re.search("(?:\d{1,3}\.){3}\d{1,3}", line)
return matchIP
if __name__ == "__main__":
# start: For object oriented testing
f = Iptables()
f.banIP('11', 1231)
f.banIP('13', 1232)
f.banIP('13', 1233)
f.unBanIP('11')
f.viewBanList()
f.flushBanList()
# end:
if not checkForRoot():
print "You must be root."
#sys.exit(-1)
logPath = './log-test/test'
banTime = 60
ignoreIPs = '127.0.0.1'
lastModTime = 0
banList = dict()
while True:
try:
currentTime = time.time()
banList = checkForUnBan(banList, currentTime, banTime)
try:
pwdFailStats = os.stat(logPath)
except OSError:
print "Unable to get stat on", logPath
sys.exit(-1)
if lastModTime == pwdFailStats.st_mtime:
time.sleep(1)
continue
print logPath, 'has been modified'
lastModTime = pwdFailStats.st_mtime
try:
pwdfail = open(logPath)
except OSError:
print "Unable to open", logPath
sys.exit(-1)
retryList = dict()
for line in pwdfail.readlines():
match = parseLogLine(line)
if match:
ip = match.group()
date = list(time.strptime(line[0:15], "%b %d %H:%M:%S"))
date[0] = time.gmtime()[0]
unixTime = time.mktime(date)
if unixTime < currentTime-banTime:
continue
if re.search(ip, ignoreIPs):
print 'Ignore ', ip
continue
print 'Found', ip, 'at', unixTime
if retryList.has_key(`ip`):
retryList[`ip`] = (retryList[`ip`][0]+1,unixTime)
else:
retryList[`ip`] = (1,unixTime)
pwdfail.close()
banList = checkForBan(retryList, banList, currentTime)
except KeyboardInterrupt:
print 'Restoring iptables...'
flushBanList(banList)
print 'Exiting...'
sys.exit(0)
# Start the application. Handle all the unhandled exceptions
try:
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`)
# Remove the PID lock file. Should close #1239562
pidLock.remove()
logging.shutdown()
Executable
+411
View File
@@ -0,0 +1,411 @@
# 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 time, sys, getopt, os, string, signal, logging, logging.handlers
from ConfigParser import *
from version import version
from firewall.firewall import Firewall
from logreader.logreader import LogReader
from confreader.configreader import ConfigReader
from utils.mail import Mail
from utils.pidlock import PIDLock
from utils.dns import *
from utils.process import *
# 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 addresses using firewall rules."
print
print " -b start in background"
print " -d start in debug mode"
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 instance"
print " -r <VALUE> allow a max of VALUE password failure"
print " -t <TIME> ban IP for TIME seconds"
print " -v verbose. Use twice for greater effect"
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.
"""
uid = `os.getuid()`
if uid == '0':
return True
else:
return False
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()
def killApp():
""" Flush the ban list, remove the PID lock file and exit
nicely.
"""
logSys.warn("Restoring firewall rules...")
for element in logFwList:
element[2].flushBanList(conf["debug"])
# Execute end command of each section
for element in logFwList:
l = element[4]
executeCmd(l["fwend"], conf["debug"])
# Execute global start command
executeCmd(conf["cmdend"], conf["debug"])
# Remove the PID lock
pidLock.remove()
logSys.info("Exiting...")
logging.shutdown()
sys.exit(0)
def getCmdLineOptions(optList):
""" Gets the command line options
"""
for opt in optList:
if opt[0] in ["-h", "--help"]:
dispUsage()
if opt[0] in ["-V", "--version"]:
dispVersion()
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] == "-t":
try:
conf["bantime"] = int(opt[1])
except ValueError:
logSys.warn("banTime must be an integer")
logSys.warn("Using default value")
if opt[0] == "-i":
conf["ignoreip"] = opt[1]
if opt[0] == "-r":
conf["maxretry"] = 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)
def main():
""" Fail2Ban main function
"""
# Add the default logging handler
stdout = logging.StreamHandler(sys.stdout)
logSys.addHandler(stdout)
# Default formatter
formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s')
stdout.setFormatter(formatter)
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]
# 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"],
["bool", "debug", False],
["str", "pidlock", "/var/run/fail2ban.pid"],
["int", "maxretry", 3],
["int", "bantime", 600],
["str", "ignoreip", ""],
["int", "polltime", 1],
["str", "cmdstart", ""],
["str", "cmdend", ""])
# Gets global configuration options
conf.update(confReader.getLogOptions("DEFAULT", optionValues))
# Gets command line options
getCmdLineOptions(optList)
# 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)
# 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)
# Set debug log level
if conf["debug"]:
logSys.setLevel(logging.DEBUG)
formatter = logging.Formatter("%(asctime)s %(levelname)s " +
"[%(filename)s (%(lineno)d)] " +
"%(message)s")
stdout.setFormatter(formatter)
logSys.warn("DEBUG MODE: FIREWALL COMMANDS ARE _NOT_ EXECUTED BUT " +
"ONLY DISPLAYED IN THE LOG MESSAGES")
# Process some options
# Log targets
# Bug fix for #1234699
os.umask(0077)
for target in conf["logtargets"].split():
if target == "STDERR":
hdlr = logging.StreamHandler(sys.stderr)
elif target == "SYSLOG":
hdlr = logging.handlers.SysLogHandler()
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(formatter)
logSys.addHandler(hdlr)
# PID lock
pidLock.setPath(conf["pidlock"])
# Ignores IP list
ignoreIPList = conf["ignoreip"].split(' ')
# maxretry option
maxRetry = conf["maxretry"]
# bantime option
banTime = conf["bantime"]
# Checks for root user. This is necessary because log files
# are owned by root and firewall needs root access.
if not checkForRoot():
logSys.error("You must be root")
if not conf["debug"]:
sys.exit(-1)
# Checks that no instance of Fail2Ban is currently running.
pid = pidLock.exists()
if pid:
logSys.error("Fail2Ban already running with PID "+pid)
sys.exit(-1)
else:
pidLock.create()
logSys.debug("ConfFile is " + conf["conffile"])
logSys.debug("BanTime is " + `conf["bantime"]`)
logSys.debug("retryAllowed is " + `conf["maxretry"]`)
# Options
optionValues = (["bool", "enabled", False],
["str", "host", "localhost"],
["int", "port", "25"],
["str", "from", "root"],
["str", "to", "root"],
["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.setToAddr(mailConf["to"])
logSys.debug("to: " + mailConf["to"] + " from: " + mailConf["from"])
# Options
optionValues = (["bool", "enabled", False],
["str", "logfile", "/dev/null"],
["int", "maxretry", None],
["int", "bantime", None],
["str", "timeregex", ""],
["str", "timepattern", ""],
["str", "failregex", ""],
["str", "fwstart", ""],
["str", "fwend", ""],
["str", "fwban", ""],
["str", "fwunban", ""])
# Gets the options of each sections
for t in confReader.getSections():
l = confReader.getLogOptions(t, optionValues)
if l["enabled"]:
# Override maxretry option
if not l["maxretry"] == None:
maxRetry = l["maxretry"]
# Override bantime option
if not l["bantime"] == None:
banTime = l["bantime"]
# Creates a logreader object
lObj = LogReader(l["logfile"], l["timeregex"], l["timepattern"],
l["failregex"], maxRetry, banTime)
# Creates a firewall object
fObj = Firewall(l["fwban"], l["fwunban"], banTime)
# 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 logFwList:
element[1].addIgnoreIP("127.0.0.1")
while len(ignoreIPList) > 0:
ip = ignoreIPList.pop()
# Bug fix for #1239557
if isValidIP(ip):
for element in logFwList:
element[1].addIgnoreIP(ip)
logSys.info("Fail2Ban v" + version + " is running")
# Execute global start command
executeCmd(conf["cmdstart"], conf["debug"])
# Execute start command of each section
for element in logFwList:
l = element[4]
executeCmd(l["fwstart"], conf["debug"])
# Main loop
while True:
try:
sys.stdout.flush()
sys.stderr.flush()
# Checks if some IP have to be remove from ban
# list.
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 logFwList:
if element[1].isModified():
modList.append(element)
if len(modList) == 0:
time.sleep(conf["polltime"])
continue
# Gets the failure list from the log file. For a given IP,
# takes only the service which has the most password failures.
for element in modList:
e = element[1].getFailures()
for key in e.iterkeys():
if element[3].has_key(key):
element[3][key] = (element[3][key][0] + e[key][0],
e[key][1])
else:
element[3][key] = (e[key][0], e[key][1])
# Remove the oldest failure attempts from the global list.
# We iterate the failure list and ban IP that make
# *retryAllowed* login failures.
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 = {"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 KeyboardInterrupt:
# When the user press <ctrl>+<c> we exit nicely.
killApp()
+80 -18
View File
@@ -24,29 +24,91 @@ __date__ = "$Date$"
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
__license__ = "GPL"
import time, os, logging, re
from utils.process import executeCmd
from utils.strings import replaceTag
# 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, banRule, unBanRule, banTime):
self.banRule = banRule
self.unBanRule = unBanRule
self.banTime = banTime
self.banList = dict()
def addBanIP(self, ip, time):
self.banList[ip] = time
def addBanIP(self, aInfo, debug):
""" Bans an IP.
"""
ip = aInfo["ip"]
if not self.inBanList(ip):
crtTime = time.time()
logSys.warn("Ban " + ip)
self.banList[ip] = crtTime
aInfo["bantime"] = crtTime
executeCmd(self.banIP(aInfo), debug)
else:
logSys.error(ip+" already in ban list")
def delBanIP(self, ip):
del self.banList[ip]
def delBanIP(self, aInfo, debug):
""" Unban an IP.
"""
ip = aInfo["ip"]
if self.inBanList(ip):
logSys.warn("Unban "+ip)
del self.banList[ip]
executeCmd(self.unBanIP(aInfo), debug)
else:
logSys.error(ip+" not in ban list")
def flushBanList(self):
iterBanList = self.banList.iteritems()
for i in range(len(self.banList)):
element = iterBanList.next()
ip = element[0]
self.unBanIP(ip)
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.
"""
banListTemp = self.banList.copy()
for element in banListTemp.iteritems():
btime = element[1]
if btime < time.time()-self.banTime:
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.
Called when fail2ban exits.
"""
banListTemp = self.banList.copy()
for element in banListTemp.iteritems():
aInfo = {"ip": element[0],
"bantime": element[1],
"unbantime": time.time()}
self.delBanIP(aInfo, debug)
def banIP(self, aInfo):
""" Returns query to ban IP.
"""
query = replaceTag(self.banRule, aInfo)
return query
def unBanIP(self, aInfo):
""" Returns query to unban IP.
"""
query = replaceTag(self.unBanRule, aInfo)
return query
def executeCmd(self, cmd):
return #os.system(cmd)
def viewBanList(self):
iterBanList = self.banList.iteritems()
for i in range(len(self.banList)):
element = iterBanList.next()
""" Prints the ban list on screen. Usefull for debugging.
"""
for element in self.banList.iteritems():
print element
+108
View File
@@ -0,0 +1,108 @@
[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
[Mon Jan 03 05:02:21 2005] [error] [client 81.83.248.17] File does not exist: /var/www/jaquier.dyndns.org/htdocs/msadc
[Mon Jan 03 05:02:22 2005] [error] [client 81.83.248.17] File does not exist: /var/www/jaquier.dyndns.org/htdocs/msadc
[Mon Jan 03 05:02:22 2005] [error] [client 81.83.248.17] File does not exist: /var/www/jaquier.dyndns.org/htdocs/msadc
[Mon Jan 03 05:02:22 2005] [error] [client 81.83.248.17] File does not exist: /var/www/jaquier.dyndns.org/htdocs/msadc
[Mon Jan 03 05:02:22 2005] [error] [client 81.83.248.17] File does not exist: /var/www/jaquier.dyndns.org/htdocs/\xe0
[Mon Jan 03 05:02:23 2005] [error] [client 81.83.248.17] File does not exist: /var/www/jaquier.dyndns.org/htdocs/msdac
[Mon Jan 03 05:02:23 2005] [error] [client 81.83.248.17] File does not exist: /var/www/jaquier.dyndns.org/htdocs/msdac
[Mon Jan 03 05:02:24 2005] [error] [client 81.83.248.17] File does not exist: /var/www/jaquier.dyndns.org/htdocs/PBServer
[Mon Jan 03 05:02:24 2005] [error] [client 81.83.248.17] File does not exist: /var/www/jaquier.dyndns.org/htdocs/PBServer
[Mon Jan 03 05:02:27 2005] [error] [client 81.83.248.17] File does not exist: /var/www/jaquier.dyndns.org/htdocs/Rpc
[Mon Jan 03 05:02:27 2005] [error] [client 81.83.248.17] File does not exist: /var/www/jaquier.dyndns.org/htdocs/Rpc
[Mon Jan 03 05:02:27 2005] [error] [client 81.83.248.17] File does not exist: /var/www/jaquier.dyndns.org/htdocs/samples
[Mon Jan 03 05:02:27 2005] [error] [client 81.83.248.17] File does not exist: /var/www/jaquier.dyndns.org/htdocs/samples
[Mon Jan 03 05:02:28 2005] [error] [client 81.83.248.17] File does not exist: /var/www/jaquier.dyndns.org/htdocs/scripts..\xc1\x9c..
[Mon Jan 03 05:02:28 2005] [error] [client 81.83.248.17] File does not exist: /var/www/jaquier.dyndns.org/htdocs/scripts
[Mon Jan 03 05:02:28 2005] [error] [client 81.83.248.17] File does not exist: /var/www/jaquier.dyndns.org/htdocs/scripts
[Mon Jan 03 05:02:28 2005] [error] [client 81.83.248.17] File does not exist: /var/www/jaquier.dyndns.org/htdocs/scripts
[Mon Jan 03 05:02:32 2005] [error] [client 81.83.248.17] File does not exist: /var/www/jaquier.dyndns.org/htdocs/scripts
[Mon Jan 03 05:02:32 2005] [error] [client 81.83.248.17] File does not exist: /var/www/jaquier.dyndns.org/htdocs/scripts
[Mon Jan 03 05:02:33 2005] [error] [client 81.83.248.17] File does not exist: /var/www/jaquier.dyndns.org/htdocs/scripts
[Mon Jan 03 05:02:33 2005] [error] [client 81.83.248.17] File does not exist: /var/www/jaquier.dyndns.org/htdocs/scripts
[Mon Jan 03 05:02:33 2005] [error] [client 81.83.248.17] File does not exist: /var/www/jaquier.dyndns.org/htdocs/scripts
[Mon Jan 03 05:02:34 2005] [error] [client 81.83.248.17] File does not exist: /var/www/jaquier.dyndns.org/htdocs/scripts
[Mon Jan 03 05:02:34 2005] [error] [client 81.83.248.17] File does not exist: /var/www/jaquier.dyndns.org/htdocs/scripts
[Mon Jan 03 05:02:38 2005] [error] [client 81.83.248.17] File does not exist: /var/www/jaquier.dyndns.org/htdocs/scripts
[Mon Jan 03 05:02:38 2005] [error] [client 81.83.248.17] File does not exist: /var/www/jaquier.dyndns.org/htdocs/scripts
[Mon Jan 03 05:02:38 2005] [error] [client 81.83.248.17] File does not exist: /var/www/jaquier.dyndns.org/htdocs/scripts
[Mon Jan 03 05:02:38 2005] [error] [client 81.83.248.17] File does not exist: /var/www/jaquier.dyndns.org/htdocs/scripts
[Mon Jan 03 05:02:39 2005] [error] [client 81.83.248.17] File does not exist: /var/www/jaquier.dyndns.org/htdocs/scripts
[Mon Jan 03 05:02:39 2005] [error] [client 81.83.248.17] File does not exist: /var/www/jaquier.dyndns.org/htdocs/scripts
[Mon Jan 03 11:08:29 2005] [error] [client 128.178.150.127] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico
[Mon Jan 03 20:08:52 2005] [error] [client 83.76.202.195] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico
[Tue Jan 04 15:19:50 2005] [error] [client 213.221.138.70] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico
[Tue Jan 04 15:19:55 2005] [error] [client 213.221.138.70] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico
[Tue Jan 04 15:20:01 2005] [error] [client 213.221.138.70] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico
[Tue Jan 04 15:20:05 2005] [error] [client 213.221.138.70] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico
[Tue Jan 04 15:20:08 2005] [error] [client 213.221.138.70] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico
[Tue Jan 04 15:20:12 2005] [error] [client 213.221.138.70] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico
[Tue Jan 04 15:20:16 2005] [error] [client 213.221.138.70] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico
[Tue Jan 04 15:20:22 2005] [error] [client 213.221.138.70] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico
[Tue Jan 04 15:20:26 2005] [error] [client 213.221.138.70] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico
[Tue Jan 04 15:20:28 2005] [error] [client 213.221.138.70] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico
[Tue Jan 04 15:20:38 2005] [error] [client 213.221.138.70] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico
[Tue Jan 04 20:54:59 2005] [error] [client 192.168.0.129] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico
[Tue Jan 04 20:55:04 2005] [error] [client 192.168.0.129] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico
[Tue Jan 04 20:55:29 2005] [error] [client 192.168.0.129] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico
[Tue Jan 04 21:34:29 2005] [error] [client 81.63.51.202] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico
[Tue Jan 04 21:34:32 2005] [error] [client 81.63.51.202] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico
[Wed Jan 05 00:17:41 2005] [error] [client 217.251.126.37] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico
[Wed Jan 05 00:18:03 2005] [error] [client 217.251.126.37] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico
[Wed Jan 05 00:18:12 2005] [error] [client 217.251.126.37] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico
[Wed Jan 05 01:24:38 2005] [error] [client 81.63.51.202] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico
[Wed Jan 05 01:24:40 2005] [error] [client 81.63.51.202] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico
[Wed Jan 05 01:24:46 2005] [error] [client 81.63.51.202] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico
[Wed Jan 05 01:24:48 2005] [error] [client 81.63.51.202] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico
[Wed Jan 05 01:25:58 2005] [error] [client 81.63.51.202] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico
[Wed Jan 05 01:26:34 2005] [error] [client 81.63.51.202] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico
[Wed Jan 05 01:26:37 2005] [error] [client 81.63.51.202] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico
[Wed Jan 05 10:13:02 2005] [error] [client 192.168.0.129] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico
[Wed Jan 05 10:13:07 2005] [error] [client 192.168.0.129] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico
[Wed Jan 05 10:13:10 2005] [error] [client 192.168.0.129] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico
[Wed Jan 05 10:17:07 2005] [error] [client 192.168.0.129] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico
[Wed Jan 05 14:41:40 2005] [error] [client 192.168.0.129] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico
[Wed Jan 05 14:41:45 2005] [error] [client 192.168.0.129] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico
[Wed Jan 05 14:41:47 2005] [error] [client 192.168.0.129] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico
[Wed Jan 05 14:41:51 2005] [error] [client 192.168.0.129] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico
[Wed Jan 05 14:55:30 2005] [error] [client 212.101.4.200] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico
[Wed Jan 05 15:03:44 2005] [error] [client 192.168.0.129] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico
[Wed Jan 05 15:03:48 2005] [error] [client 192.168.0.129] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico
[Wed Jan 05 15:03:52 2005] [error] [client 192.168.0.129] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico
[Wed Jan 05 15:03:57 2005] [error] [client 192.168.0.129] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico
[Wed Jan 05 15:06:45 2005] [error] [client 212.101.4.200] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico
[Wed Mar 05 15:07:28 2005] [error] [client 192.168.0.128] user cyril: authentication failure for "/phpinfo": Password Mismatch
[Wed Jan 05 15:08:01 2005] [error] [client 192.168.0.128] user not found: /phpinfo
[Wed Jan 05 15:10:45 2005] [crit] [client 192.168.0.128] (13)Permission denied: /var/www/jaquier.dyndns.org/htdocs/css/.htaccess pcfg_openfile: unable to check htaccess file, ensure it is readable, referer: http://earth/phpinfo
[Wed Jan 05 15:10:45 2005] [crit] [client 192.168.0.128] (13)Permission denied: /var/www/jaquier.dyndns.org/htdocs/images/.htaccess pcfg_openfile: unable to check htaccess file, ensure it is readable, referer: http://earth/phpinfo
[Wed Jan 05 15:10:45 2005] [error] [client 192.168.0.128] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico
[Wed Jan 05 15:11:09 2005] [error] [client 192.168.0.128] user test not found: /phpinfo
[Wed Jan 05 15:11:10 2005] [error] [client 192.168.0.128] user test not found: /phpinfo
[Wed Jan 06 15:11:11 2005] [error] [client 192.168.0.128] user test not found: /phpinfo
[Wed Jan 06 15:11:13 2005] [error] [client 192.168.0.128] user test not found: /phpinfo
[Wed Jan 06 15:11:14 2005] [error] [client 192.168.0.128] user test not found: /phpinfo
[Wed Jan 05 15:11:15 2005] [crit] [client 192.168.0.128] (13)Permission denied: /var/www/jaquier.dyndns.org/htdocs/css/.htaccess pcfg_openfile: unable to check htaccess file, ensure it is readable, referer: http://earth/phpinfo
[Wed Jan 05 15:11:15 2005] [crit] [client 192.168.0.128] (13)Permission denied: /var/www/jaquier.dyndns.org/htdocs/images/.htaccess pcfg_openfile: unable to check htaccess file, ensure it is readable, referer: http://earth/phpinfo
[Wed Jan 05 15:11:15 2005] [error] [client 192.168.0.128] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico
[Wed Jan 05 15:12:32 2005] [error] [client 212.101.4.200] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico
[Wed Jan 05 15:13:48 2005] [error] [client 192.168.0.129] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico
[Wed Jan 05 15:13:51 2005] [error] [client 192.168.0.129] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico
[Wed Jan 05 15:13:52 2005] [error] [client 192.168.0.129] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico
[Wed Jan 05 15:13:52 2005] [error] [client 192.168.0.129] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico
[Wed Jan 05 15:13:54 2005] [error] [client 192.168.0.129] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico
[Wed Jan 05 15:13:56 2005] [error] [client 192.168.0.129] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico
[Wed Jan 05 15:13:59 2005] [error] [client 192.168.0.129] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico
[Wed Jan 05 15:14:20 2005] [error] [client 192.168.0.129] File does not exist: /var/www/jaquier.dyndns.org/htdocs/favicon.ico
[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 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
+11 -4
View File
@@ -1,4 +1,11 @@
- Last output repeated 2 times -
Oct 7 11:47:08 [sshd] Failed password for illegal user test from 69.182.27.122 port 34015 ssh2
Oct 7 11:47:09 [sshd] Failed password for illegal user guest from 69.182.27.122 port 34068 ssh2
Oct 7 11:47:11 [sshd] Failed password for illegal user admin from 69.182.27.122 port 34127 ssh2
Jan 7 17:53:15 [sshd] (pam_unix) 2 more authentication failures; logname= uid=0 euid=0 tty=ssh ruser= rhost=62.220.137.36 user=kevin
Jan 7 17:53:26 [sshd] (pam_unix) authentication failure; logname= uid=0 euid=0 tty=ssh ruser= rhost=62.220.137.36 user=kevin
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
+5 -4
View File
@@ -425,7 +425,8 @@ Oct 7 01:03:12 [sshd] Failed password for illegal user tata from 128.178.164.52
- Last output repeated 2 times -
Oct 7 01:03:20 [sshd] Failed password for illegal user tata from 128.178.164.52 port 37187 ssh2
- Last output repeated 2 times -
Oct 8 11:47:08 [sshd] Failed password for illegal user test from 69.182.27.122 port 34015 ssh2
Oct 8 11:47:09 [sshd] Failed password for illegal user guest from 69.182.27.122 port 34068 ssh2
Oct 8 11:47:11 [sshd] Failed password for illegal user admin from 69.182.27.122 port 34127 ssh2
Oct 9 21:54:11 yellow sshd[16069]: Failed password for cyril from 212.41.79.210 port 29404 ssh2
Nov 14 11:47:08 [sshd] Failed password for illegal user test from 69.182.27.122 port 34015 ssh2
Nov 14 11:47:09 [sshd] Failed password for illegal user guest from 69.182.27.122 port 34068 ssh2
Nov 14 11:47:11 [sshd] Failed password for illegal user admin from 69.182.27.122 port 34127 ssh2
Nov 15 11:12:11 yellow sshd[16069]: Failed password for cyril from 212.41.79.210 port 29404 ssh2
Nov 15 21:54:11 yellow sshd[16069]: Illegal user for cyril from 212.41.79.210 port 29404 ssh2
+147 -11
View File
@@ -24,44 +24,180 @@ __date__ = "$Date$"
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
__license__ = "GPL"
import os, sys
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, logPath, 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.lastPos = 0
self.lastDate = 0
self.logStats = None
def getMaxRetry(self):
""" Gets the maximum number of failures
"""
return self.maxRetry
def getFindTime(self):
""" Gets the find time.
"""
return self.findTime
def addIgnoreIP(self, ip):
""" Adds an IP to the ignore list.
"""
logSys.debug("Add "+ip+" to ignore list")
self.ignoreIpList.append(ip)
def inIgnoreIPList(self, ip):
return ip in self.ignoreIpList
""" Checks if IP is in the ignore list.
"""
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.
"""
try:
fileHandler = open(self.logPath)
except OSError:
print "Unable to open", self.logPath
logSys.error("Unable to open "+self.logPath)
sys.exit(-1)
return fileHandler
def isModified(self):
""" Checks if the log file has been modified using os.stat().
"""
try:
logStats = os.stat(self.logPath)
self.logStats = os.stat(self.logPath)
except OSError:
print "Unable to get stat on", logPath
logSys.error("Unable to get stat on "+self.logPath)
sys.exit(-1)
if self.lastModTime == logStats.st_mtime:
if self.lastModTime == self.logStats.st_mtime:
return False
else:
print self.logPath, 'has been modified'
self.lastModTime = logStats.st_mtime
logSys.debug(self.logPath+" has been modified")
self.lastModTime = self.logStats.st_mtime
return True
def getPwdFailure(self):
failList = self.getFailInfo(self.findTime)
def setFilePos(self, file):
""" Sets the file position. We must take care of log file rotation
and reset the position to 0 in that case. Use the log message
timestamp in order to detect this.
"""
line = file.readline()
if self.lastDate < self.getTime(line):
logSys.debug("Date " + `self.lastDate` + " is " + "smaller than " +
`self.getTime(line)`)
logSys.debug("Log rotation detected for " + self.logPath)
self.lastPos = 0
logSys.debug("Setting file position to " + `self.lastPos` + " for " +
self.logPath)
file.seek(self.lastPos)
def getFailures(self):
""" Gets all the failure in the log file which are
newer than time.time()-self.findTime.
Returns a dict with the IP, the number of failure
and the latest failure time.
"""
ipList = dict()
logSys.debug(self.logPath)
logFile = self.openLogFile()
self.setFilePos(logFile)
lastLine = ''
for line in logFile:
lastLine = line
failList = self.findFailure(line)
for element in failList:
ip = element[0]
unixTime = element[1]
if unixTime < time.time()-self.findTime:
break
if self.inIgnoreIPList(ip):
logSys.debug("Ignore "+ip)
continue
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)
logFile.close()
return ipList
def findFailure(self, line):
""" Finds the failure in line. Uses the failregex pattern
to find it and timeregex in order to find the logging
time.
Returns a dict with IP and timestamp.
"""
failList = list()
match = re.search(self.failregex, line)
if match:
timeMatch = re.search(self.timeregex, match.string)
if timeMatch:
date = self.getUnixTime(timeMatch.group())
ipMatch = textToIp(match.string)
if ipMatch:
for ip in ipMatch:
failList.append([ip, date])
return failList
def getTime(self, line):
""" Gets the time of a log message.
"""
date = 0
timeMatch = re.search(self.timeregex, line)
if timeMatch:
date = self.getUnixTime(timeMatch.group())
return date
def getUnixTime(self, value):
""" Returns the Unix timestamp of the given value.
Pattern should describe the date construction of
value.
"""
date = list(time.strptime(value, self.timepattern))
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
-65
View File
@@ -1,65 +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 re, time
from logreader import LogReader
class Metalog(LogReader):
def getFailInfo(self, findTime):
ipList = dict()
logFile = self.openLogFile()
for line in logFile.readlines():
match = self.parseLogLine(line)
if match:
ip = match[0]
unixTime = match[1]
if unixTime < time.time()-self.findTime:
continue
if self.inIgnoreIPList(ip):
print 'Ignore', ip
continue
print 'Found', ip, 'at', unixTime
if ipList.has_key(ip):
ipList[ip] = (ipList[ip][0]+1, unixTime)
else:
ipList[ip] = (1, unixTime)
logFile.close()
return ipList
def parseLogLine(self, line):
""" Match sshd failed password log
"""
if re.search("Failed password", line):
matchIP = re.search("(?:\d{1,3}\.){3}\d{1,3}", line)
if matchIP:
date = list(time.strptime(line[0:15], "%b %d %H:%M:%S"))
date[0] = time.gmtime()[0]
unixTime = time.mktime(date)
return [matchIP.group(), unixTime]
else:
return False
+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\-d\fR
start in debug mode. Commands are NOT executed but only displayed
.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
.TP
\fB\-t\fR \fITIME\fR
ban IP for \fITIME\fR seconds
.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/".
+5
View File
@@ -0,0 +1,5 @@
[install]
install-purelib=/usr/lib/fail2ban
[sdist]
formats=bztar
Executable
+82
View File
@@ -0,0 +1,82 @@
#!/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"
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. It needs log4py.'''
setup(
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.default as example."
print
+25
View File
@@ -0,0 +1,25 @@
# 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"
+101
View File
@@ -0,0 +1,101 @@
# 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, re, socket, struct
def dnsToIp(dns):
""" Convert a DNS into an IP address using the Python socket module.
Thanks to Kevin Drapel.
"""
try:
return socket.gethostbyname_ex(dns)[2]
except socket.gaierror:
return list()
def textToDns(text):
""" Search for possible DNS in an arbitrary text.
Thanks to Tom Pike.
"""
match = re.findall("(?:(?:\w|-)+\.){2,}\w+", text)
if match:
return match
else:
return []
def searchIP(text):
""" Search if an IP address if directly available and return
it.
"""
match = re.findall("(?:\d{1,3}\.){3}\d{1,3}", text)
if match:
return match
else:
return []
def isValidIP(str):
""" Return true if str is a valid IP
"""
try:
socket.inet_aton(str)
return True
except socket.error:
return False
def textToIp(text):
""" Return the IP of DNS found in a given text.
"""
ipList = list()
# Search for plain IP
plainIP = searchIP(text)
for element in plainIP:
if isValidIP(element):
ipList.append(element)
if not ipList:
# Try to get IP from possible DNS
dnsList = textToDns(text)
for element in dnsList:
dns = dnsToIp(element)
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))
+71
View File
@@ -0,0 +1,71 @@
# 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
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
def setFromAddr(self, fromAddr):
""" Set from: address
"""
self.fromAddr = fromAddr
def setToAddr(self, toAddr):
""" Set to: address
"""
self.toAddr = toAddr.split()
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\nSubject: %s\r\n\r\n" %
(self.fromAddr, ", ".join(self.toAddr), subj)) + msg
try:
server = smtplib.SMTP(self.host, self.port)
#server.set_debuglevel(1)
server.sendmail(self.fromAddr, self.toAddr, mail)
logSys.debug("Email sent to " + `self.toAddr`)
server.quit()
except Exception:
logSys.error("Unable to send mail to " + self.host + ":" +
`self.port` + " from " + self.fromAddr + " to " +
`self.toAddr`)
+98
View File
@@ -0,0 +1,98 @@
# 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.
"""
fileHandler = open(self.path, mode='w')
pid = os.getpid()
fileHandler.write(`pid` + '\n')
fileHandler.close()
logSys.debug("Created PID lock (" + `pid` + ") in " + self.path)
def remove(self):
""" Remove PID lock.
"""
os.remove(self.path)
logSys.debug("Removed PID lock " + self.path)
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)
+131
View File
@@ -0,0 +1,131 @@
# 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")
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, 2)
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`)
return retval
else:
return None
+13 -14
View File
@@ -24,18 +24,17 @@ __date__ = "$Date$"
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
__license__ = "GPL"
from firewall import Firewall
import logging
class Iptables(Firewall):
def banIP(self, ip, time):
query = 'iptables -I INPUT 1 -i eth0 -s '+str(ip)+' -j DROP'
self.addBanIP(ip, time)
self.executeCmd(query)
print query
def unBanIP(self, ip):
query = 'iptables -D INPUT -i eth0 -s '+str(ip)+' -j DROP'
self.delBanIP(ip)
self.executeCmd(query)
print query
# Gets the instance of the logger.
logSys = logging.getLogger("fail2ban")
def replaceTag(query, aInfo):
""" Replace tags in query
"""
string = query
for tag in aInfo:
string = string.replace('<'+tag+'>', `aInfo[tag]`)
# New line
string = string.replace('<br>', '\n')
return string
+27
View File
@@ -0,0 +1,27 @@
# 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"
version = "0.5.2"