mirror of https://github.com/fail2ban/fail2ban
				
				
				
			New upstream release, removed log4py, fresh man file for conf
							parent
							
								
									e965ab1504
								
							
						
					
					
						commit
						e46b5f6665
					
				
							
								
								
									
										12
									
								
								CHANGELOG
								
								
								
								
							
							
						
						
									
										12
									
								
								CHANGELOG
								
								
								
								
							|  | @ -4,9 +4,19 @@ | |||
|              |_| \__,_|_|_/___|_.__/\__,_|_||_| | ||||
| 
 | ||||
| ============================================================= | ||||
| Fail2Ban (version 0.5.1)                           2005/07/23 | ||||
| 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 | ||||
|  |  | |||
							
								
								
									
										13
									
								
								PKG-INFO
								
								
								
								
							
							
						
						
									
										13
									
								
								PKG-INFO
								
								
								
								
							|  | @ -1,10 +1,15 @@ | |||
| Metadata-Version: 1.0 | ||||
| Name: fail2ban | ||||
| Version: 0.5.1 | ||||
| Version: 0.5.2 | ||||
| Summary: Ban IPs that make too many password failure | ||||
| Home-page: http://fail2ban.sourceforge.net | ||||
| Author: Cyril Jaquier | ||||
| Author-email: lostcontrol@users.sourceforge.net | ||||
| License: UNKNOWN | ||||
| Description: UNKNOWN | ||||
| Platform: UNKNOWN | ||||
| License: GPL | ||||
| Description:  | ||||
|         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. | ||||
| Platform: Posix | ||||
|  |  | |||
							
								
								
									
										15
									
								
								README
								
								
								
								
							
							
						
						
									
										15
									
								
								README
								
								
								
								
							|  | @ -4,14 +4,14 @@ | |||
|              |_| \__,_|_|_/___|_.__/\__,_|_||_| | ||||
| 
 | ||||
| ============================================================= | ||||
| Fail2Ban (version 0.5.1)                           2005/07/23 | ||||
| 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. It needs log4py. | ||||
| or Apache web server ones. | ||||
| 
 | ||||
| This is my first Python program. Moreover, English is not my | ||||
| mother tongue... | ||||
|  | @ -55,12 +55,11 @@ Installation: | |||
| ------------- | ||||
| 
 | ||||
| Require: python-2.3 (http://www.python.org) | ||||
|          log4py-1.3 (http://sourceforge.net/projects/log4py) | ||||
| 
 | ||||
| To install, just do: | ||||
| 
 | ||||
| > tar xvfj fail2ban-0.5.1.tar.bz2 | ||||
| > cd fail2ban-0.5.1 | ||||
| > 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 | ||||
|  | @ -95,13 +94,13 @@ or using command line options. Command line options override | |||
| the value stored in fail2ban.conf. Here are the command line | ||||
| options: | ||||
| 
 | ||||
|   -b         start fail2ban in background | ||||
|   -d         start fail2ban in debug mode | ||||
|   -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 Fail2Ban instance | ||||
|   -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 | ||||
|  |  | |||
							
								
								
									
										1
									
								
								TODO
								
								
								
								
							
							
						
						
									
										1
									
								
								TODO
								
								
								
								
							|  | @ -10,4 +10,3 @@ ToDo | |||
| See Feature Request Tracking System at SourceForge.net | ||||
| 
 | ||||
| - improve installation process (better prefix support) | ||||
| - add better documentation (man page) | ||||
|  |  | |||
|  | @ -1,6 +1,6 @@ | |||
| # Fail2Ban configuration file | ||||
| # | ||||
| # $Revision: 1.8.2.7 $ | ||||
| # $Revision: 1.8.2.9 $ | ||||
| # | ||||
| # 2005.06.21  modified for readability  Iain Lea  iain@bricbrac.de | ||||
| 
 | ||||
|  | @ -19,9 +19,9 @@ debug = false | |||
| 
 | ||||
| # Option:  logtargets | ||||
| # Notes.:  log targets. Space separated list of logging targets. | ||||
| # Values:  STDOUT STDERR SYSLOG file  Default:  STDOUT /var/log/fail2ban.log | ||||
| # Values:  STDERR SYSLOG file  Default:  /var/log/fail2ban.log | ||||
| # | ||||
| logtargets = STDOUT /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). | ||||
|  | @ -49,7 +49,7 @@ bantime = 600 | |||
| # Examples | ||||
| #  ignoreip = 192.168.0.0/24 | ||||
| # | ||||
| ignoreip = | ||||
| ignoreip = 192.168.0.0/16 | ||||
| 
 | ||||
| 
 | ||||
| # Option:  cmdstart | ||||
|  | @ -147,17 +147,17 @@ logfile = /var/log/apache/access.log | |||
| # 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 | ||||
| fwstart = iptables -N fail2ban-http | ||||
|           iptables -I INPUT -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 | ||||
| fwend = iptables -D INPUT -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 | ||||
|  | @ -167,9 +167,9 @@ fwend = iptables -D INPUT -i eth0 -p tcp --dport http -j fail2ban-HTTP | |||
| #          <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 | ||||
| # Default: iptables -I INPUT 1 -s <ip> -j DROP | ||||
| # | ||||
| fwban = iptables -I fail2ban-HTTP 1 -i eth0 -s <ip> -j DROP | ||||
| fwban = iptables -I fail2ban-http 1 -s <ip> -j DROP | ||||
| 
 | ||||
| # Option:  fwunban | ||||
| # Notes.:  command executed when unbanning an IP. Take care that the | ||||
|  | @ -178,9 +178,9 @@ fwban = iptables -I fail2ban-HTTP 1 -i eth0 -s <ip> -j DROP | |||
| #          <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 | ||||
| # Default: iptables -D INPUT -s <ip> -j DROP | ||||
| # | ||||
| fwunban = iptables -D fail2ban-HTTP -i eth0 -s <ip> -j DROP | ||||
| fwunban = iptables -D fail2ban-http -s <ip> -j DROP | ||||
| 
 | ||||
| # Option:  timeregex | ||||
| # Notes.:  regex to match timestamp in Apache logfile. | ||||
|  | @ -219,17 +219,17 @@ logfile = /var/log/auth.log | |||
| # 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 | ||||
| fwstart = iptables -N fail2ban-ssh | ||||
|           iptables -I INPUT -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 | ||||
| fwend = iptables -D INPUT -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 | ||||
|  | @ -239,9 +239,9 @@ fwend = iptables -D INPUT -i eth0 -p tcp --dport ssh -j fail2ban-SSH | |||
| #          <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 | ||||
| # Default: iptables -I INPUT 1 -s <ip> -j DROP | ||||
| # | ||||
| fwban = iptables -I fail2ban-SSH 1 -i eth0 -s <ip> -j DROP | ||||
| fwban = iptables -I fail2ban-ssh 1 -s <ip> -j DROP | ||||
| 
 | ||||
| # Option:  fwunbanrule | ||||
| # Notes.:  command executed when unbanning an IP. Take care that the | ||||
|  | @ -250,9 +250,9 @@ fwban = iptables -I fail2ban-SSH 1 -i eth0 -s <ip> -j DROP | |||
| #          <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 | ||||
| # Default: iptables -D INPUT -s <ip> -j DROP | ||||
| # | ||||
| fwunban = iptables -D fail2ban-SSH -i eth0 -s <ip> -j DROP | ||||
| fwunban = iptables -D fail2ban-ssh -s <ip> -j DROP | ||||
| 
 | ||||
| # Option:  timeregex | ||||
| # Notes.:  regex to match timestamp in SSH logfile. | ||||
|  |  | |||
|  | @ -17,7 +17,7 @@ | |||
| # | ||||
| # Author: Sireyessire, Cyril Jaquier | ||||
| #  | ||||
| # $Revision: 1.1.2.1 $ | ||||
| # $Revision: 1.1.2.2 $ | ||||
| 
 | ||||
| opts="start stop restart showlog" | ||||
| 
 | ||||
|  | @ -31,13 +31,13 @@ depend() { | |||
| 
 | ||||
| start() { | ||||
| 	ebegin "Starting fail2ban" | ||||
| 	${FAIL2BAN} -b ${FAIL2BAN_OPTS} | ||||
| 	${FAIL2BAN} -b ${FAIL2BAN_OPTS} > /dev/null | ||||
| 	eend $? "Failed to start fail2ban" | ||||
| } | ||||
| 
 | ||||
| stop() { | ||||
| 	ebegin "Stopping fail2ban" | ||||
| 	${FAIL2BAN} -k | ||||
| 	${FAIL2BAN} -k > /dev/null | ||||
| 	eend $? "Failed to stop fail2ban" | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -9,7 +9,7 @@ | |||
| # | ||||
| # Author: Andrey G. Grozin | ||||
| #  | ||||
| # $Revision: 1.1.2.1 $ | ||||
| # $Revision: 1.1.2.2 $ | ||||
| 
 | ||||
| # Source function library. | ||||
| . /etc/init.d/functions | ||||
|  | @ -28,7 +28,7 @@ RETVAL=0 | |||
| 
 | ||||
| start() { | ||||
|     echo -n $"Starting fail2ban: " | ||||
|     "${FAIL2BAN}" -b | ||||
|     "${FAIL2BAN}" -b > /dev/null | ||||
|     RETVAL=$? | ||||
|     echo | ||||
| } | ||||
|  | @ -36,7 +36,7 @@ start() { | |||
| stop() { | ||||
|     if [ -f "${PIDFILE}" ]; then | ||||
| 	echo -n $"Stopping fail2ban: " | ||||
| 	"${FAIL2BAN}" -k | ||||
| 	"${FAIL2BAN}" -k > /dev/null | ||||
| 	echo | ||||
|     fi | ||||
| } | ||||
|  |  | |||
|  | @ -16,20 +16,20 @@ | |||
| 
 | ||||
| # Author: Cyril Jaquier | ||||
| #  | ||||
| # $Revision: 1.5.2.3 $ | ||||
| # $Revision: 1.5.2.5 $ | ||||
| 
 | ||||
| __author__ = "Cyril Jaquier" | ||||
| __version__ = "$Revision: 1.5.2.3 $" | ||||
| __date__ = "$Date: 2005/07/12 13:07:35 $" | ||||
| __version__ = "$Revision: 1.5.2.5 $" | ||||
| __date__ = "$Date: 2005/08/01 16:31:13 $" | ||||
| __copyright__ = "Copyright (c) 2004 Cyril Jaquier" | ||||
| __license__ = "GPL" | ||||
| 
 | ||||
| import log4py | ||||
| import logging | ||||
| 
 | ||||
| from ConfigParser import * | ||||
| 
 | ||||
| # Gets the instance of log4py. | ||||
| logSys = log4py.Logger().get_instance() | ||||
| # Gets the instance of the logger. | ||||
| logSys = logging.getLogger("fail2ban") | ||||
| 
 | ||||
| class ConfigReader: | ||||
| 	""" This class allow the handling of the configuration options. | ||||
|  | @ -77,5 +77,9 @@ class ConfigReader: | |||
| 			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 | ||||
| 		 | ||||
|  | @ -10,9 +10,6 @@ Currently the main difference with upstream: python libraries are | |||
| placed under /usr/share/fail2ban insteadh of /usr/lib/fail2ban to | ||||
| comply with policy regarding architecture independent resources. | ||||
| 
 | ||||
| Module log4py installed along into fail2ban directory because there is | ||||
| no package for not-developed-in-a-long-time fail2ban | ||||
| 
 | ||||
| See the file TODO.Debian for more details, as well as the Debian Bug | ||||
| Tracking system. | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,3 +1,11 @@ | |||
| fail2ban (0.5.2-1) unstable; urgency=low | ||||
| 
 | ||||
|   * New upstream release | ||||
|   * No log4py any more | ||||
|   * removed -i eth0 from config | ||||
| 
 | ||||
|  -- Yaroslav Halchenko <debian@onerussian.com>  Sat,  6 Aug 2005 09:21:07 -1000 | ||||
| 
 | ||||
| fail2ban (0.5.1-1) unstable; urgency=low | ||||
| 
 | ||||
|   * New upstream release | ||||
|  |  | |||
|  | @ -25,26 +25,3 @@ Boston, MA 02111-1307, USA. | |||
| 
 | ||||
| See /usr/share/common-licenses/GPL for the full license. | ||||
| 
 | ||||
| log4py.py module included in this package is distributed in complience | ||||
| with MIT License: | ||||
| 
 | ||||
| Copyright (c) 2001 Martin Preishuber | ||||
| 
 | ||||
| Permission is hereby granted, free of charge, to any person obtaining | ||||
| a copy of this software and associated documentation files (the | ||||
| "Software"), to deal in the Software without restriction, including | ||||
| without limitation the rights to use, copy, modify, merge, publish, | ||||
| distribute, sublicense, and/or sell copies of the Software, and to | ||||
| permit persons to whom the Software is furnished to do so, subject to | ||||
| the following conditions: | ||||
| 
 | ||||
| The above copyright notice and this permission notice shall be | ||||
| included in all copies or substantial portions of the Software. | ||||
| 
 | ||||
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||||
| EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||||
| MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||||
| NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE | ||||
| LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION | ||||
| OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION | ||||
| WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||||
|  |  | |||
|  | @ -87,7 +87,7 @@ binary-arch: build install copy-inits | |||
| 	dh_installinit | ||||
| #	dh_installcron | ||||
| #	dh_installinfo | ||||
| 	dh_installman fail2ban.1x | ||||
| 	dh_installman fail2ban.1x man/fail2ban.conf.5 | ||||
| 	dh_link | ||||
| 	dh_strip | ||||
| 	dh_compress | ||||
|  |  | |||
							
								
								
									
										50
									
								
								fail2ban
								
								
								
								
							
							
						
						
									
										50
									
								
								fail2ban
								
								
								
								
							|  | @ -18,31 +18,43 @@ | |||
| 
 | ||||
| # Author: Cyril Jaquier | ||||
| #  | ||||
| # $Revision: 1.4.2.3 $ | ||||
| # $Revision: 1.4.2.5 $ | ||||
| 
 | ||||
| __author__ = "Cyril Jaquier" | ||||
| __version__ = "$Revision: 1.4.2.3 $" | ||||
| __date__ = "$Date: 2005/07/15 14:11:21 $" | ||||
| __version__ = "$Revision: 1.4.2.5 $" | ||||
| __date__ = "$Date: 2005/08/04 20:51:14 $" | ||||
| __copyright__ = "Copyright (c) 2004 Cyril Jaquier" | ||||
| __license__ = "GPL" | ||||
| 
 | ||||
| from sys import exit, path | ||||
| import sys, traceback, logging | ||||
| 
 | ||||
| #yoh: We do need to load this path first if we ship log4py with fail2ban | ||||
| # Appends our own modules path. Added before log4py import | ||||
| # because log4py could be distributed with Fail2Ban. | ||||
| path.append('/usr/share/fail2ban') | ||||
| # Appends our own modules path. | ||||
| sys.path.append("/usr/lib/fail2ban") | ||||
| 
 | ||||
| # Checks for required libs | ||||
| # Checks if log4py is present. | ||||
| try: | ||||
| 	import log4py | ||||
| except: | ||||
| 	print "log4py is needed (see README)" | ||||
| 	exit(-1) | ||||
| 
 | ||||
| # Now we can import our module | ||||
| # Now we can import our modules. | ||||
| import fail2ban | ||||
| from utils.pidlock import PIDLock | ||||
| 
 | ||||
| # Start the application | ||||
| fail2ban.main() | ||||
| # Get the instance of the logger. | ||||
| logSys = logging.getLogger("fail2ban") | ||||
| 
 | ||||
| # Get PID lock file instance | ||||
| pidLock = PIDLock() | ||||
| 
 | ||||
| # 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() | ||||
|  |  | |||
							
								
								
									
										178
									
								
								fail2ban.py
								
								
								
								
							
							
						
						
									
										178
									
								
								fail2ban.py
								
								
								
								
							|  | @ -16,15 +16,15 @@ | |||
| 
 | ||||
| # Author: Cyril Jaquier | ||||
| #  | ||||
| # $Revision: 1.20.2.8 $ | ||||
| # $Revision: 1.20.2.13 $ | ||||
| 
 | ||||
| __author__ = "Cyril Jaquier" | ||||
| __version__ = "$Revision: 1.20.2.8 $" | ||||
| __date__ = "$Date: 2005/07/22 21:13:19 $" | ||||
| __version__ = "$Revision: 1.20.2.13 $" | ||||
| __date__ = "$Date: 2005/08/06 18:44:06 $" | ||||
| __copyright__ = "Copyright (c) 2004 Cyril Jaquier" | ||||
| __license__ = "GPL" | ||||
| 
 | ||||
| import time, sys, getopt, os, string, signal, log4py | ||||
| import time, sys, getopt, os, string, signal, logging, logging.handlers | ||||
| from ConfigParser import * | ||||
| 
 | ||||
| from version import version | ||||
|  | @ -32,11 +32,15 @@ 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 * | ||||
| 
 | ||||
| # Gets the instance of log4py. | ||||
| logSys = log4py.Logger().get_instance() | ||||
| # Get the instance of the logger. | ||||
| logSys = logging.getLogger("fail2ban") | ||||
| 
 | ||||
| # Get PID lock file instance | ||||
| pidLock = PIDLock() | ||||
| 
 | ||||
| # Global variables | ||||
| logFwList = list() | ||||
|  | @ -50,13 +54,13 @@ def dispUsage(): | |||
| 	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 fail2ban in background" | ||||
| 	print "  -d         start fail2ban in debug mode" | ||||
| 	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 Fail2Ban instance" | ||||
| 	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" | ||||
|  | @ -101,8 +105,9 @@ def killApp(): | |||
| 	# Execute global start command | ||||
| 	executeCmd(conf["cmdend"], conf["debug"]) | ||||
| 	# Remove the PID lock | ||||
| 	removePID(conf["pidlock"]) | ||||
| 	pidLock.remove() | ||||
| 	logSys.info("Exiting...") | ||||
| 	logging.shutdown() | ||||
| 	sys.exit(0) | ||||
| 
 | ||||
| def getCmdLineOptions(optList): | ||||
|  | @ -128,23 +133,23 @@ def getCmdLineOptions(optList): | |||
| 		if opt[0] == "-i": | ||||
| 			conf["ignoreip"] = opt[1] | ||||
| 		if opt[0] == "-r": | ||||
| 			conf["retrymax"] = int(opt[1]) | ||||
| 			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) | ||||
| 			conf["kill"] = True | ||||
| 
 | ||||
| def main(): | ||||
| 	""" Fail2Ban main function | ||||
| 	""" | ||||
| 	logSys.set_formatstring("%T %L %M") | ||||
| 	 | ||||
| 	# 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" | ||||
|  | @ -169,7 +174,7 @@ def main(): | |||
| 	 | ||||
| 	# Options | ||||
| 	optionValues = (["bool", "background", False], | ||||
| 					["str", "logtargets", "STDOUT /var/log/fail2ban.log"], | ||||
| 					["str", "logtargets", "/var/log/fail2ban.log"], | ||||
| 					["bool", "debug", False], | ||||
| 					["str", "pidlock", "/var/run/fail2ban.pid"], | ||||
| 					["int", "maxretry", 3], | ||||
|  | @ -184,47 +189,23 @@ def main(): | |||
| 	 | ||||
| 	# Gets command line options | ||||
| 	getCmdLineOptions(optList) | ||||
| 
 | ||||
| 	# Process some options | ||||
| 	# Log targets | ||||
| 	# Bug fix for #1234699 | ||||
| 	os.umask(0077) | ||||
| 	# Remove all the targets before setting our own | ||||
| 	logSys.remove_all_targets() | ||||
| 	for target in conf["logtargets"].split(): | ||||
| 		if target == "STDOUT": | ||||
| 			logSys.add_target(log4py.TARGET_SYS_STDOUT) | ||||
| 		elif target == "STDERR": | ||||
| 			logSys.add_target(log4py.TARGET_SYS_STDERR) | ||||
| 		elif target == "SYSLOG": | ||||
| 			logSys.add_target(log4py.TARGET_SYSLOG) | ||||
| 	 | ||||
| 	# PID lock | ||||
| 	pidLock.setPath(conf["pidlock"]) | ||||
| 	 | ||||
| 	# Now we can kill properly a running instance if needed | ||||
| 	try: | ||||
| 		conf["kill"] | ||||
| 		pid = pidLock.exists() | ||||
| 		if pid: | ||||
| 			killPID(int(pid)) | ||||
| 			logSys.warn("Killed Fail2Ban with PID "+pid) | ||||
| 			sys.exit(0) | ||||
| 		else: | ||||
| 			# Target should be a file | ||||
| 			try: | ||||
| 				open(target, "a") | ||||
| 				logSys.add_target(target) | ||||
| 			except IOError: | ||||
| 				logSys.error("Unable to log to " + target) | ||||
| 	 | ||||
| 	# Check if at least one target exists | ||||
| 	if len(logSys.get_targets()) == 0: | ||||
| 		logSys.add_target(log4py.TARGET_SYS_STDOUT) | ||||
| 		logSys.error("No valid logging target found. Logging to STDOUT") | ||||
| 	 | ||||
| 	# Verbose level | ||||
| 	if conf["verbose"]: | ||||
| 		logSys.warn("Verbose level is "+`conf["verbose"]`) | ||||
| 		if conf["verbose"] == 1: | ||||
| 			logSys.set_loglevel(log4py.LOGLEVEL_VERBOSE) | ||||
| 		elif conf["verbose"] > 1: | ||||
| 			logSys.set_loglevel(log4py.LOGLEVEL_DEBUG) | ||||
| 		 | ||||
| 	# Set debug log level | ||||
| 	if conf["debug"]: | ||||
| 		logSys.set_loglevel(log4py.LOGLEVEL_DEBUG) | ||||
| 		logSys.set_formatstring(log4py.FMT_DEBUG) | ||||
| 		logSys.warn("DEBUG MODE: FIREWALL COMMANDS ARE _NOT_ EXECUTED BUT " + | ||||
| 					"ONLY DISPLAYED IN THE LOG MESSAGES") | ||||
| 			logSys.error("No running Fail2Ban found") | ||||
| 			sys.exit(-1) | ||||
| 	except KeyError: | ||||
| 		pass | ||||
| 
 | ||||
| 	# Start Fail2Ban in daemon mode | ||||
| 	if conf["background"]: | ||||
|  | @ -233,10 +214,55 @@ def main(): | |||
| 		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) | ||||
| 	 | ||||
| 	# 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(): | ||||
|  | @ -245,16 +271,16 @@ def main(): | |||
| 			sys.exit(-1) | ||||
| 			 | ||||
| 	# Checks that no instance of Fail2Ban is currently running. | ||||
| 	pid = checkForPID(conf["pidlock"]) | ||||
| 	pid = pidLock.exists() | ||||
| 	if pid: | ||||
| 		logSys.error("Fail2Ban already running with PID "+pid) | ||||
| 		sys.exit(-1) | ||||
| 	else: | ||||
| 		createPID(conf["pidlock"]) | ||||
| 		pidLock.create() | ||||
| 	 | ||||
| 	logSys.debug("ConfFile is "+conf["conffile"]) | ||||
| 	logSys.debug("BanTime is "+`conf["bantime"]`) | ||||
| 	logSys.debug("retryAllowed is "+`conf["maxretry"]`) | ||||
| 	logSys.debug("ConfFile is " + conf["conffile"]) | ||||
| 	logSys.debug("BanTime is " + `conf["bantime"]`) | ||||
| 	logSys.debug("retryAllowed is " + `conf["maxretry"]`) | ||||
| 	 | ||||
| 	# Options | ||||
| 	optionValues = (["bool", "enabled", False], | ||||
|  | @ -277,8 +303,10 @@ def main(): | |||
| 		logSys.debug("to: " + mailConf["to"] + " from: " + mailConf["from"]) | ||||
| 	 | ||||
| 	# Options | ||||
| 	optionValues = (["bool", "enabled", True], | ||||
| 	optionValues = (["bool", "enabled", False], | ||||
| 					["str", "logfile", "/dev/null"], | ||||
| 					["int", "maxretry", None], | ||||
| 					["int", "bantime", None], | ||||
| 					["str", "timeregex", ""], | ||||
| 					["str", "timepattern", ""], | ||||
| 					["str", "failregex", ""], | ||||
|  | @ -291,11 +319,19 @@ def main(): | |||
| 	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"], conf["bantime"]) | ||||
| 							 l["failregex"], maxRetry, banTime) | ||||
| 			# Creates a firewall object | ||||
| 			fObj = Firewall(l["fwban"], l["fwunban"], conf["bantime"]) | ||||
| 			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]) | ||||
|  | @ -311,7 +347,7 @@ def main(): | |||
| 			for element in logFwList: | ||||
| 				element[1].addIgnoreIP(ip) | ||||
| 	 | ||||
| 	logSys.info("Fail2Ban v"+version+" is running") | ||||
| 	logSys.info("Fail2Ban v" + version + " is running") | ||||
| 	# Execute global start command | ||||
| 	executeCmd(conf["cmdstart"], conf["debug"]) | ||||
| 	# Execute start command of each section | ||||
|  | @ -363,7 +399,7 @@ def main(): | |||
| 					failTime = fails[attempt][1] | ||||
| 					if failTime < unixTime - findTime: | ||||
| 						del element[3][attempt] | ||||
| 					elif fails[attempt][0] >= conf["maxretry"]: | ||||
| 					elif fails[attempt][0] >= element[1].getMaxRetry(): | ||||
| 						aInfo = {"ip": attempt, | ||||
| 								 "failures": element[3][attempt][0], | ||||
| 								 "failtime": failTime} | ||||
|  |  | |||
|  | @ -16,21 +16,21 @@ | |||
| 
 | ||||
| # Author: Cyril Jaquier | ||||
| #  | ||||
| # $Revision: 1.8.2.5 $ | ||||
| # $Revision: 1.8.2.6 $ | ||||
| 
 | ||||
| __author__ = "Cyril Jaquier" | ||||
| __version__ = "$Revision: 1.8.2.5 $" | ||||
| __date__ = "$Date: 2005/07/15 14:07:08 $" | ||||
| __version__ = "$Revision: 1.8.2.6 $" | ||||
| __date__ = "$Date: 2005/08/01 16:31:42 $" | ||||
| __copyright__ = "Copyright (c) 2004 Cyril Jaquier" | ||||
| __license__ = "GPL" | ||||
| 
 | ||||
| import time, os, log4py, re | ||||
| import time, os, logging, re | ||||
| 
 | ||||
| from utils.process import executeCmd | ||||
| from utils.strings import replaceTag | ||||
| 
 | ||||
| # Gets the instance of log4py. | ||||
| logSys = log4py.Logger().get_instance() | ||||
| # Gets the instance of the logger. | ||||
| logSys = logging.getLogger("fail2ban") | ||||
| 
 | ||||
| class Firewall: | ||||
| 	""" Manages the ban list and executes the command that ban | ||||
|  |  | |||
							
								
								
									
										593
									
								
								log4py.py
								
								
								
								
							
							
						
						
									
										593
									
								
								log4py.py
								
								
								
								
							|  | @ -1,593 +0,0 @@ | |||
| """ | ||||
| 
 | ||||
| Python logging module - Version 1.3 | ||||
| 
 | ||||
| Loglevels: | ||||
| 
 | ||||
|     LOGLEVEL_NONE, LOGLEVEL_ERROR, LOGLEVEL_NORMAL, LOGLEVEL_VERBOSE, LOGLEVEL_DEBUG | ||||
| 
 | ||||
| Format-Parameters: | ||||
| 
 | ||||
|     %C -- The name of the current class. | ||||
|     %D -- Program duration since program start. | ||||
|     %d -- Program duration for the last step (last output). | ||||
|     %F -- The name of the current function. | ||||
|     %f -- Current filename | ||||
|     %L -- Log type (Error, Warning, Debug or Info) | ||||
|     %M -- The actual message. | ||||
|     %N -- The current line number. | ||||
|     %T -- Current time (human readable). | ||||
|     %t -- Current time (machine readable) | ||||
|     %U -- Current fully qualified module/file. | ||||
|     %u -- Current module/file. | ||||
|     %x -- NDC (nested diagnostic contexts). | ||||
| 
 | ||||
| Pre-defined Formats: | ||||
| 
 | ||||
|     FMT_SHORT -- %M | ||||
|     FMT_MEDIUM -- [ %C.%F ] %D: %M | ||||
|     FMT_LONG -- %T %L %C [%F] %x%M | ||||
|     FMT_DEBUG -- %T [%D (%d)] %L %C [%F (%N)] %x%M | ||||
|      | ||||
| """ | ||||
| 
 | ||||
| # Logging levels | ||||
| LOGLEVEL_NONE = 1 << 0 | ||||
| LOGLEVEL_ERROR = 1 << 1 | ||||
| LOGLEVEL_NORMAL = 1 << 2 | ||||
| LOGLEVEL_VERBOSE = 1 << 3 | ||||
| LOGLEVEL_DEBUG = 1 << 4 | ||||
| 
 | ||||
| # Pre-defined format strings | ||||
| FMT_SHORT = "%M" | ||||
| FMT_MEDIUM = "[ %C.%F ] %D: %M" | ||||
| FMT_LONG = "%T %L %C [%F] %x%M" | ||||
| FMT_DEBUG = "%T [%D (%d)] %L %C [%F (%N)] %x%M" | ||||
| 
 | ||||
| # Special logging targets | ||||
| TARGET_MYSQL = "MySQL" | ||||
| TARGET_POSTGRES = "Postgres" | ||||
| TARGET_SYSLOG = "Syslog" | ||||
| TARGET_SYS_STDOUT = "sys.stdout" | ||||
| TARGET_SYS_STDERR = "sys.stderr" | ||||
| TARGET_SYS_STDOUT_ALIAS = "stdout" | ||||
| TARGET_SYS_STDERR_ALIAS = "stderr" | ||||
| 
 | ||||
| SPECIAL_TARGETS = [ TARGET_MYSQL, TARGET_POSTGRES, TARGET_SYSLOG, TARGET_SYS_STDOUT, TARGET_SYS_STDERR, TARGET_SYS_STDOUT_ALIAS, TARGET_SYS_STDERR_ALIAS ] | ||||
| 
 | ||||
| # Configuration files | ||||
| CONFIGURATION_FILES = {} | ||||
| CONFIGURATION_FILES[1] = "log4py.conf"                    # local directory | ||||
| CONFIGURATION_FILES[2] = "$HOME/.log4py.conf"             # hidden file in the home directory | ||||
| CONFIGURATION_FILES[3] = "/etc/log4py.conf"               # system wide file | ||||
| 
 | ||||
| # Constants for the FileAppender | ||||
| ROTATE_NONE = 0 | ||||
| ROTATE_DAILY = 1 | ||||
| ROTATE_WEEKLY = 2 | ||||
| ROTATE_MONTHLY = 3 | ||||
| 
 | ||||
| # The following constants are of internal interest only | ||||
| 
 | ||||
| # Message constants (used for ansi colors and for logtype %L) | ||||
| MSG_DEBUG = 1 << 0 | ||||
| MSG_WARN = 1 << 1 | ||||
| MSG_ERROR = 1 << 2 | ||||
| MSG_INFO = 1 << 3 | ||||
| 
 | ||||
| # Boolean constants | ||||
| TRUE = "TRUE" | ||||
| FALSE = "FALSE" | ||||
| 
 | ||||
| # Color constants | ||||
| BLACK = 30 | ||||
| RED = 31 | ||||
| GREEN = 32 | ||||
| YELLOW = 33 | ||||
| BLUE = 34 | ||||
| PURPLE = 35 | ||||
| AQUA = 36 | ||||
| WHITE = 37 | ||||
| 
 | ||||
| LOG_MSG = { MSG_DEBUG: "DEBUG", MSG_WARN: "WARNING", MSG_ERROR: "ERROR", MSG_INFO: "INFO"} | ||||
| LOG_COLORS = { MSG_DEBUG: [WHITE, BLACK, FALSE], MSG_WARN: [WHITE, BLACK, FALSE], MSG_ERROR: [WHITE, BLACK, TRUE], MSG_INFO: [WHITE, BLACK, FALSE]} | ||||
| LOG_LEVELS = { "DEBUG": LOGLEVEL_DEBUG, "VERBOSE": LOGLEVEL_VERBOSE, "NORMAL": LOGLEVEL_NORMAL, "NONE": LOGLEVEL_NONE, "ERROR": LOGLEVEL_ERROR } | ||||
| 
 | ||||
| SECTION_DEFAULT = "Default" | ||||
| 
 | ||||
| from time import time, strftime, localtime | ||||
| from types import StringType, ClassType, InstanceType, FileType, TupleType | ||||
| from string import zfill, atoi, lower, upper, join, replace, split, strip | ||||
| from re import sub | ||||
| from ConfigParser import ConfigParser, NoOptionError | ||||
| from os import stat, rename | ||||
| 
 | ||||
| import sys | ||||
| import traceback | ||||
| import os | ||||
| import copy | ||||
| import socket | ||||
| import locale | ||||
| if (os.name == "posix"): | ||||
|     import syslog | ||||
| 
 | ||||
| try: | ||||
|     import MySQLdb | ||||
|     mysql_available = TRUE | ||||
| except: | ||||
|     mysql_available = FALSE | ||||
| 
 | ||||
| def get_homedirectory(): | ||||
|     if (sys.platform == "win32"): | ||||
|         if (os.environ.has_key("USERPROFILE")): | ||||
|             return os.environ["USERPROFILE"] | ||||
|         else: | ||||
|             return "C:\\" | ||||
|     else: | ||||
|         if (os.environ.has_key("HOME")): | ||||
|             return os.environ["HOME"] | ||||
|         else: | ||||
|             # No home directory set | ||||
|             return "" | ||||
| 
 | ||||
| # This is the main class for the logging module | ||||
| 
 | ||||
| class Logger: | ||||
| 
 | ||||
|     cache = {} | ||||
|     instance = None | ||||
|     configfiles = [] | ||||
|     hostname = socket.gethostname() | ||||
| 
 | ||||
|     def __init__(self, useconfigfiles = TRUE, customconfigfiles = None): | ||||
|         """ **(private)** Class initalization & customization. """ | ||||
|         if (customconfigfiles): | ||||
|             if (type(customconfigfiles) == StringType): | ||||
|                 customconfigfiles = [customconfigfiles] | ||||
|             Logger.configfiles = customconfigfiles | ||||
| 
 | ||||
|         if (not Logger.instance): | ||||
|             self.__Logger_setdefaults() | ||||
|             if (useconfigfiles == TRUE): | ||||
|                 self.__Logger_appendconfigfiles(Logger.configfiles) | ||||
|                 # read the default options | ||||
|                 self.__Logger_parse_options() | ||||
| 
 | ||||
|             self.__Logger_timeinit = time() | ||||
|             self.__Logger_timelaststep = self.__Logger_timeinit | ||||
| 
 | ||||
|             Logger.instance = self | ||||
| 
 | ||||
|             if (useconfigfiles == TRUE): | ||||
|                 # read and pre-cache settings for named classids | ||||
|                 self.__Logger_cache_options() | ||||
| 
 | ||||
|     def get_root(self): | ||||
|         """ Provides a way to change the base logger object's properties. """ | ||||
|         return Logger.instance | ||||
| 
 | ||||
|     def get_instance(self, classid = "Main", use_cache = TRUE): | ||||
|         """ Either get the cached logger instance or create a new one | ||||
| 
 | ||||
|         Note that this is safe, even if you have your target set to sys.stdout | ||||
|         or sys.stderr | ||||
|         """ | ||||
| 
 | ||||
|         cache = Logger.cache | ||||
| 
 | ||||
|         if (type(classid) == ClassType): | ||||
|             classid = classid.__name__ | ||||
|         elif (type(classid) == InstanceType): | ||||
|             classid = classid.__class__.__name__ | ||||
| 
 | ||||
|         # classid has to be lowercase, because the ConfigParser returns sections lowercase | ||||
|         classid = lower(classid) | ||||
| 
 | ||||
|         if ((cache.has_key(classid)) and (use_cache == TRUE)): | ||||
|             cat = Logger.cache[classid] | ||||
|         else: | ||||
|             instance = Logger.instance | ||||
| 
 | ||||
|             # test for targets which won't deep copy | ||||
|             targets = instance.__Logger_targets | ||||
|             deepcopyable = TRUE | ||||
|             for i in range(len(targets)): | ||||
|                 if (type(targets[i]) == FileType): | ||||
|                     deepcopyable = FALSE | ||||
|             if (deepcopyable == FALSE): | ||||
|                 # swap the non-copyable target out for a moment | ||||
|                 del instance.__Logger_targets | ||||
|                 cat = copy.deepcopy(instance) | ||||
|                 instance.__Logger_targets = targets | ||||
|                 cat.__Logger_targets = targets | ||||
|             else: | ||||
|                 cat = copy.deepcopy(instance) | ||||
| 
 | ||||
|             cat.__Logger_classname = classid | ||||
|             # new categories have their own private Nested Diagnostic Contexts | ||||
|             self.__Logger_ndc = [] | ||||
|             self.__Logger_classid = classid | ||||
| 
 | ||||
|             cat.debug("Class %s instantiated" % classid) | ||||
|             if (use_cache == TRUE): | ||||
|                 cache[classid] = cat | ||||
| 
 | ||||
|         return cat | ||||
| 
 | ||||
|     # Log-target handling (add, remove, set, remove_all) | ||||
| 
 | ||||
|     def add_target(self, target, *args): | ||||
|         """ Add a target to the logger targets. """ | ||||
|         if (not target in self.__Logger_targets): | ||||
|             if (target == TARGET_MYSQL): | ||||
|                 if (mysql_available == TRUE): | ||||
|                     # Required parameters: dbhost, dbname, dbuser, dbpass, dbtable | ||||
|                     try: | ||||
|                         self.__Logger_mysql_connection = MySQLdb.connect(host=args[0], db=args[1], user=args[2], passwd=args[3]) | ||||
|                         self.__Logger_mysql_cursor = self.__Logger_mysql_connection.cursor() | ||||
|                         self.__Logger_mysql_tablename = args[4] | ||||
|                         self.__Logger_targets.append(target) | ||||
|                     except MySQLdb.OperationalError, detail: | ||||
|                         self.error("MySQL connection failed: %s" % detail) | ||||
|                 else: | ||||
|                     self.error("MySQL target not added - Python-mysql not available") | ||||
|             else: | ||||
|                 if (type(target) == StringType): | ||||
|                     if (target not in SPECIAL_TARGETS): | ||||
|                         # This is a filename | ||||
|                         target = FileAppender(target, self.__Logger_rotation) | ||||
|                 if ((target == TARGET_SYSLOG) and (os.name != "posix")): | ||||
|                     self.warn("TARGET_SYSLOG is not available on non-posix platforms!") | ||||
|                 else: | ||||
|                     self.__Logger_targets.append(target) | ||||
| 
 | ||||
|     def remove_target(self, target): | ||||
|         """ Remove a target from the logger targets. """ | ||||
|         if (target in self.__Logger_targets): | ||||
|             if (target == TARGET_MYSQL): | ||||
|                 self.__Logger_mysql_connection.close() | ||||
|             self.__Logger_targets.remove(target) | ||||
| 
 | ||||
|     def set_target(self, target): | ||||
|         """ Set a single target. """ | ||||
|         if (type(target) == StringType): | ||||
|             if (target not in SPECIAL_TARGETS): | ||||
|                 # File target | ||||
|                 target = FileAppender(target, self.__Logger_rotation) | ||||
|         self.__Logger_targets = [ target ] | ||||
| 
 | ||||
|     def remove_all_targets(self): | ||||
|         """ Remove all targets from the logger targets. """ | ||||
|         self.__Logger_targets=[] | ||||
| 
 | ||||
|     def get_targets(self): | ||||
|         """ Returns all defined targets. """ | ||||
|         return self.__Logger_targets | ||||
| 
 | ||||
|     # Methods to set properties | ||||
| 
 | ||||
|     def set_loglevel(self, loglevel): | ||||
|         """ Set the loglevel for the current instance. """ | ||||
|         self.__Logger_loglevel = loglevel | ||||
| 
 | ||||
|     def set_formatstring(self, formatstring): | ||||
|         """ Set a format string. """ | ||||
|         self.__Logger_formatstring = formatstring | ||||
| 
 | ||||
|     def set_use_ansi_codes(self, useansicodes): | ||||
|         """ Use ansi codes for output to the console (TRUE or FALSE). """ | ||||
|         self.__Logger_useansicodes = useansicodes | ||||
| 
 | ||||
|     def set_time_format(self, timeformat): | ||||
|         """ Set the time format (default: loaded from the system locale). """ | ||||
|         self.__Logger_timeformat = timeformat | ||||
|          | ||||
|     def set_rotation(self, rotation): | ||||
|         """ Set the file rotation mode to one of ROTATE_NONE, ROTATE_DAILY, ROTATE_WEEKLY, ROTATE_MONTHLY """ | ||||
|         self.__Logger_rotation = rotation | ||||
|         for i in range(len(self.__Logger_targets)): | ||||
|             target = self.__Logger_targets[i] | ||||
|             if (isinstance(target, FileAppender)): | ||||
|                 target.set_rotation(rotation) | ||||
| 
 | ||||
|     # Method to get properties | ||||
| 
 | ||||
|     def get_loglevel(self): | ||||
|         """ Returns the current loglevel. """ | ||||
|         return self.__Logger_loglevel | ||||
| 
 | ||||
|     def get_formatstring(self): | ||||
|         """ Returns the current format string. """ | ||||
|         return self.__Logger_formatstring | ||||
| 
 | ||||
|     def get_use_ansi_codes(self): | ||||
|         """ Returns, wether ansi codes are being used or not. """ | ||||
|         return self.__Logger_useansicodes | ||||
| 
 | ||||
|     def get_time_format(self): | ||||
|         """ Returns the current time format. """ | ||||
|         return self.__Logger_timeformat | ||||
| 
 | ||||
|     def get_rotation(self): | ||||
|         """ Returns the current rotation setting. """ | ||||
|         return self.__Logger_rotation | ||||
| 
 | ||||
|     # Methods to push and pop trace messages for nested contexts | ||||
| 
 | ||||
|     def push(self, message): | ||||
|         """ Add a trace message. """ | ||||
|         self.__Logger_ndc.append(message) | ||||
| 
 | ||||
|     def pop(self): | ||||
|         """ Remove the topmost trace message. """ | ||||
|         ct = len(self.__Logger_ndc) | ||||
|         if (ct): | ||||
|             del(self.__Logger_ndc[ct-1]) | ||||
| 
 | ||||
|     def clear_ndc(self): | ||||
|         """ Clears all NDC messages. """ | ||||
|         self.__Logger_ndc = [] | ||||
| 
 | ||||
|     # Methods to actually print messages | ||||
| 
 | ||||
|     def debug(self, *messages): | ||||
|         """ Write a debug message. """ | ||||
|         if (self.__Logger_loglevel >= LOGLEVEL_DEBUG): | ||||
|             message = self.__Logger_collate_messages(messages) | ||||
|             self.__Logger_showmessage(message, MSG_DEBUG) | ||||
| 
 | ||||
|     def warn(self, *messages): | ||||
|         """ Write a warning message. """ | ||||
|         if (self.__Logger_loglevel >= LOGLEVEL_VERBOSE): | ||||
|             message = self.__Logger_collate_messages(messages) | ||||
|             self.__Logger_showmessage(message, MSG_WARN) | ||||
| 
 | ||||
|     def error(self, *messages): | ||||
|         """ Write a error message. """ | ||||
|         if (self.__Logger_loglevel >= LOGLEVEL_ERROR): | ||||
|             message = self.__Logger_collate_messages(messages) | ||||
|             self.__Logger_showmessage(message, MSG_ERROR) | ||||
| 
 | ||||
|     def info(self, *messages): | ||||
|         """ Write a info message. """ | ||||
|         if (self.__Logger_loglevel >= LOGLEVEL_NORMAL): | ||||
|             message = self.__Logger_collate_messages(messages) | ||||
|             self.__Logger_showmessage(message, MSG_INFO) | ||||
| 
 | ||||
|     # Private methods of the Logger class - you never have to use those directly | ||||
| 
 | ||||
|     def __Logger_collate_messages(self, messages): | ||||
|         """ **(private)** Create a single string from a number of messages. """ | ||||
|         return strip(reduce(lambda x, y: "%s%s" % (x, y), messages)) | ||||
| 
 | ||||
|     def __Logger_tracestack(self): | ||||
|         """ **(private)** Analyze traceback stack and set linenumber and functionname. """ | ||||
|         stack = traceback.extract_stack() | ||||
|         self.__Logger_module = stack[-4][0] | ||||
|         self.__Logger_linenumber = stack[-4][1] | ||||
|         self.__Logger_functionname = stack[-4][2] | ||||
|         self.__Logger_filename = stack[-4][0] | ||||
|         if (self.__Logger_functionname == "?"): | ||||
|             self.__Logger_functionname = "Main" | ||||
| 
 | ||||
|     def __Logger_setdefaults(self): | ||||
|         """ **(private)** Set default values for internal variables. """ | ||||
|         locale.setlocale(locale.LC_ALL) | ||||
|         self.__Logger_classid = None | ||||
|         self.__Logger_targets = [ TARGET_SYS_STDOUT ]            # default target = sys.stdout | ||||
|         self.__Logger_formatstring = FMT_LONG | ||||
|         self.__Logger_loglevel = LOGLEVEL_NORMAL | ||||
|         self.__Logger_rotation = ROTATE_NONE | ||||
|         self.__Logger_useansicodes = FALSE | ||||
|         self.__Logger_functionname = "" | ||||
|         self.__Logger_filename = "" | ||||
|         self.__Logger_linenumber = -1 | ||||
|         try: | ||||
|             self.__Logger_timeformat = "%s %s" % (locale.nl_langinfo(locale.D_FMT), locale.nl_langinfo(locale.T_FMT)) | ||||
|         except (AttributeError): | ||||
|             self.__Logger_timeformat = "%d.%m.%Y %H:%M:%S" | ||||
|         self.__Logger_classname = None | ||||
|         self.__Logger_configfilename = "" | ||||
|         self.__Logger_module = "" | ||||
|         self.__Logger_ndc = []                              # ndc = Nested Diagnostic Context | ||||
| 
 | ||||
|     def __Logger_find_config(self): | ||||
|         """ **(private)** Search for configuration files. """ | ||||
|         if (not self.__Logger_configfilename): | ||||
|             priorities = CONFIGURATION_FILES.keys() | ||||
|             priorities.sort() | ||||
|             configfilename = "" | ||||
|             for i in range(len(priorities)): | ||||
|                 filename = CONFIGURATION_FILES[priorities[i]] | ||||
|                 home_directory = get_homedirectory() | ||||
|                 if (os.sep == "\\"): | ||||
|                     home_directory = replace(home_directory, "\\", "\\\\") | ||||
|                 filename = sub("\$HOME", home_directory, filename) | ||||
|                 if (os.path.exists(filename)): | ||||
|                     configfilename = filename | ||||
|                     break | ||||
|             self.__Logger_configfilename = configfilename | ||||
|         return self.__Logger_configfilename | ||||
| 
 | ||||
|     def __Logger_parse_options(self, section = SECTION_DEFAULT): | ||||
|         """ **(private)** Parse main options from config file. """ | ||||
|         configfilename = self.__Logger_find_config() | ||||
| 
 | ||||
|         if (configfilename != ""): | ||||
|             parser = ConfigParser() | ||||
|             parser.read(configfilename) | ||||
|             self.__Logger_set_instance_options(parser, section, self) | ||||
|         return TRUE | ||||
| 
 | ||||
|     def __Logger_set_instance_options(self, parser, section, instance): | ||||
|         """ **(private)** Set the options for a given instance from the parser section """ | ||||
| 
 | ||||
|         for i in range(len(parser.options(section))): | ||||
|             option = lower(parser.options(section)[i]) | ||||
|             value = parser.get(section, option) | ||||
|             if (option == "format"): | ||||
|                 instance.set_formatstring(value) | ||||
|             elif (option == "timeformat"): | ||||
|                 instance.set_time_format(value) | ||||
|             elif (option == "ansi"): | ||||
|                 instance.set_use_ansi_codes(upper(value)) | ||||
|             elif (option == "loglevel"): | ||||
|                 instance.set_loglevel(LOG_LEVELS[upper(value)]) | ||||
|             elif (option == "target"): | ||||
|                 splitted = split(value, ",") | ||||
|                 instance.remove_all_targets() | ||||
|                 for i in range(len(splitted)): | ||||
|                     instance.add_target(strip(splitted[i])) | ||||
| 
 | ||||
|     def __Logger_cache_options(self): | ||||
|         """ **(private)** Read and cache debug levels for categories from config file. """ | ||||
|         configfilename = self.__Logger_find_config() | ||||
| 
 | ||||
|         if (configfilename != ""): | ||||
|             parser = ConfigParser() | ||||
|             parser.read(configfilename) | ||||
| 
 | ||||
|             for i in range(len(parser.sections())): | ||||
|                 section = parser.sections()[i] | ||||
|                 if (section != SECTION_DEFAULT): | ||||
|                     instance = self.get_instance(section) | ||||
|                     self.__Logger_set_instance_options(parser, section, instance) | ||||
|         return TRUE | ||||
| 
 | ||||
|     def __Logger_appendconfigfiles(self, filenames): | ||||
|         """ **(private)** Append a filename to the list of configuration files. """ | ||||
|         filenames.reverse() | ||||
|         for i in range(len(filenames)): | ||||
|             keys = CONFIGURATION_FILES.keys() | ||||
|             CONFIGURATION_FILES[min(keys) - 1] = filenames[i] | ||||
| 
 | ||||
|     def __Logger_get_ndc(self): | ||||
|         """ **(private)** Returns the NDC (nested diagnostic context) joined with single-spaces. """ | ||||
|         if (len(self.__Logger_ndc)): | ||||
|             return join(self.__Logger_ndc) | ||||
|         else: | ||||
|             return "" | ||||
| 
 | ||||
|     def __Logger_showmessage(self, message, messagesource): | ||||
|         """ **(private)** Writes a message to all targets set. """ | ||||
| 
 | ||||
|         if (isinstance(message, Exception)): | ||||
|             (exc_type, exc_value, tb) = sys.exc_info() | ||||
|             exception_summary = traceback.format_exception(exc_type, exc_value, tb) | ||||
|             message = 'Exception caught:\n' | ||||
|             for line in exception_summary: | ||||
|                 message = "%s%s" % (message, line) | ||||
| 
 | ||||
|         currenttime = time() | ||||
|         self.__Logger_tracestack() | ||||
|         timedifference = "%.3f" % (currenttime - self.__Logger_timeinit) | ||||
|         timedifflaststep = "%.3f" % (currenttime - self.__Logger_timelaststep) | ||||
|         self.__Logger_timelaststep = currenttime | ||||
|         milliseconds = int(round((currenttime - long(currenttime)) * 1000)) | ||||
|         timeformat = sub("%S", "%S." + (zfill(milliseconds, 3)), self.__Logger_timeformat) | ||||
|         currentformattedtime = strftime(timeformat, localtime(currenttime)) | ||||
| 
 | ||||
|         line = self.__Logger_formatstring | ||||
|         line = sub("%C", str(self.__Logger_classname), line) | ||||
|         line = sub("%D", timedifference, line) | ||||
|         line = sub("%d", timedifflaststep, line) | ||||
|         line = sub("%F", self.__Logger_functionname, line) | ||||
|         line = sub("%f", self.__Logger_filename, line) | ||||
|         line = sub("%U", self.__Logger_module, line) | ||||
|         line = sub("%u", os.path.split(self.__Logger_module)[-1], line) | ||||
|         ndc = self.__Logger_get_ndc() | ||||
|         if (ndc != ""): | ||||
|             line = sub("%x", "%s - " % ndc, line) | ||||
|         else: | ||||
|             line = sub("%x", "", line) | ||||
|         message = replace(message, "\\", "\\\\") | ||||
|         if (self.__Logger_useansicodes == TRUE): | ||||
|             line = sub("%L", self.__Logger_ansi(LOG_MSG[messagesource], messagesource), line) | ||||
|             line = sub("%M", self.__Logger_ansi(message, messagesource), line) | ||||
|         else: | ||||
|             line = sub("%L", LOG_MSG[messagesource], line) | ||||
|             line = sub("%M", message, line) | ||||
|         line = sub("%N", str(self.__Logger_linenumber), line) | ||||
|         line = sub("%T", currentformattedtime, line) | ||||
|         line = sub("%t", `currenttime`, line) | ||||
| 
 | ||||
|         for i in range(len(self.__Logger_targets)): | ||||
|             target = self.__Logger_targets[i] | ||||
|             if (target == TARGET_MYSQL): | ||||
|                 sqltime = strftime("'%Y-%m-%d', '%H:%M:%S'", localtime(currenttime)) | ||||
|                 sqlStatement = "INSERT INTO %s (host, facility, level, date, time, program, msg) VALUES ('%s', '%s', '%s', %s, '%s', '%s')" % (self.__Logger_mysql_tablename, self.hostname, self.__Logger_functionname, LOG_MSG[messagesource], sqltime, str(self.__Logger_classname), sub("'", "`", message + " " + ndc)) | ||||
|                 self.__Logger_mysql_cursor.execute(sqlStatement) | ||||
|             elif (target == TARGET_SYSLOG): | ||||
|                 # We don't need time and stuff here | ||||
|                 syslog.syslog(message) | ||||
|             elif (isinstance(target, FileAppender)): | ||||
|                 target.writeline(line) | ||||
|             elif (target == sys.stdout) or (lower(target) == TARGET_SYS_STDOUT) or (lower(target) == TARGET_SYS_STDOUT_ALIAS): | ||||
|                 sys.stdout.write("%s\n" % line) | ||||
|             elif (target == sys.stderr) or (lower(target) == TARGET_SYS_STDERR) or (lower(target) == TARGET_SYS_STDERR_ALIAS): | ||||
|                 sys.stderr.write("%s\n" % line) | ||||
|             else: | ||||
|                 target.write("%s\n" % line) | ||||
| 
 | ||||
|     def __Logger_ansi(self, text, messagesource): | ||||
|         """ **(private)** Converts plain text to ansi text. """ | ||||
|         bold = LOG_COLORS[messagesource][2] | ||||
|         fg = str(LOG_COLORS[messagesource][0]) | ||||
|         bg = LOG_COLORS[messagesource][1] | ||||
|         if (bold == TRUE): | ||||
|             fg = "%s;1" % fg | ||||
|         bg = bg + 10 | ||||
|         text = "\033[%d;%sm%s\033[0m" % (bg, fg, text) | ||||
|         return text | ||||
| 
 | ||||
| class FileAppender: | ||||
| 
 | ||||
|     def __init__(self, filename, rotation = ROTATE_NONE): | ||||
|         """ **(private)** Class initalization & customization. """ | ||||
|         self.__FileAppender_filename = sub("\$HOME", get_homedirectory(), filename) | ||||
|         self.__FileAppender_filename = os.path.expanduser(self.__FileAppender_filename) | ||||
|         self.__FileAppender_filename = os.path.expandvars(self.__FileAppender_filename) | ||||
|         self.__FileAppender_rotation = rotation | ||||
| 
 | ||||
|     def __FileAppender_rotate(self, modification_time): | ||||
|         """ **(private)** Check, wether the file has to be rotated yet or not. """ | ||||
|         if (self.__FileAppender_rotation == ROTATE_DAILY): | ||||
|             strftime_mask = "%Y%j" | ||||
|         elif (self.__FileAppender_rotation == ROTATE_WEEKLY): | ||||
|             strftime_mask = "%Y%W" | ||||
|         elif (self.__FileAppender_rotation == ROTATE_MONTHLY): | ||||
|             strftime_mask = "%Y%m" | ||||
|         return (strftime(strftime_mask, localtime(time())) != strftime(strftime_mask, localtime(modification_time))) | ||||
| 
 | ||||
|     def __FileAppender_date_string(self, modification_time): | ||||
|         """ **(private)** Returns a new filename for the rotated file with the appropriate time included. """ | ||||
|         if (self.__FileAppender_rotation == ROTATE_DAILY): | ||||
|             return strftime("%Y-%m-%d", localtime(modification_time)) | ||||
|         elif (self.__FileAppender_rotation == ROTATE_WEEKLY): | ||||
|             return strftime("%Y-Week %W", localtime(modification_time)) | ||||
|         elif (self.__FileAppender_rotation == ROTATE_MONTHLY): | ||||
|             return strftime("%Y-Month %m", localtime(modification_time)) | ||||
| 
 | ||||
|     def get_rotation(self): | ||||
|         """ Returns the current rotation setting. """ | ||||
|         return self.__FileAppender_rotation | ||||
| 
 | ||||
|     def set_rotation(self, rotation): | ||||
|         """ Set the file rotation mode to one of ROTATE_NONE, ROTATE_DAILY, ROTATE_WEEKLY, ROTATE_MONTHLY """ | ||||
|         self.__FileAppender_rotation = rotation | ||||
| 
 | ||||
|     def write(self, text): | ||||
|         """ Write some text to the file appender. """ | ||||
|         if ((os.path.exists(self.__FileAppender_filename)) and (self.__FileAppender_rotation != ROTATE_NONE)): | ||||
|             statinfo = stat(self.__FileAppender_filename) | ||||
|             if (self.__FileAppender_rotate(statinfo[8])): | ||||
|                 splitted = os.path.splitext(self.__FileAppender_filename) | ||||
|                 target_file = "%s-%s%s" % (splitted[0], self.__FileAppender_date_string(statinfo[8]), splitted[1]) | ||||
|                 rename(self.__FileAppender_filename, target_file) | ||||
|         file = open(self.__FileAppender_filename, "a") | ||||
|         file.write(text) | ||||
|         file.close() | ||||
| 
 | ||||
|     def writeline(self, text): | ||||
|         """ Write some text including newline to the file appender. """ | ||||
|         self.write("%s\n" % text) | ||||
|  | @ -16,20 +16,20 @@ | |||
| 
 | ||||
| # Author: Cyril Jaquier | ||||
| #  | ||||
| # $Revision: 1.13.2.4 $ | ||||
| # $Revision: 1.13.2.7 $ | ||||
| 
 | ||||
| __author__ = "Cyril Jaquier" | ||||
| __version__ = "$Revision: 1.13.2.4 $" | ||||
| __date__ = "$Date: 2005/07/23 09:07:53 $" | ||||
| __version__ = "$Revision: 1.13.2.7 $" | ||||
| __date__ = "$Date: 2005/08/06 18:43:11 $" | ||||
| __copyright__ = "Copyright (c) 2004 Cyril Jaquier" | ||||
| __license__ = "GPL" | ||||
| 
 | ||||
| import os, sys, time, re, log4py | ||||
| import os, sys, time, re, logging | ||||
| 
 | ||||
| from utils.dns import * | ||||
| 
 | ||||
| # Gets the instance of log4py. | ||||
| logSys = log4py.Logger().get_instance() | ||||
| # Gets the instance of the logger. | ||||
| logSys = logging.getLogger("fail2ban") | ||||
| 
 | ||||
| class LogReader: | ||||
| 	""" Reads a log file and reports information about IP that make password | ||||
|  | @ -38,8 +38,9 @@ class LogReader: | |||
| 	""" | ||||
| 	 | ||||
| 	def __init__(self, logPath, timeregex, timepattern, failregex, | ||||
| 				  findTime = 3600): | ||||
| 				  maxRetry, findTime): | ||||
| 		self.logPath = logPath | ||||
| 		self.maxRetry = maxRetry | ||||
| 		self.timeregex = timeregex | ||||
| 		self.timepattern = timepattern | ||||
| 		self.failregex = failregex | ||||
|  | @ -50,6 +51,11 @@ class LogReader: | |||
| 		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. | ||||
| 		""" | ||||
|  | @ -83,7 +89,7 @@ class LogReader: | |||
| 			fileHandler = open(self.logPath) | ||||
| 		except OSError: | ||||
| 			logSys.error("Unable to open "+self.logPath) | ||||
| 			sys.exit(-1) | ||||
| 			 | ||||
| 		return fileHandler | ||||
| 		 | ||||
| 	def isModified(self): | ||||
|  | @ -93,7 +99,6 @@ class LogReader: | |||
| 			self.logStats = os.stat(self.logPath) | ||||
| 		except OSError: | ||||
| 			logSys.error("Unable to get stat on "+self.logPath) | ||||
| 			sys.exit(-1) | ||||
| 		 | ||||
| 		if self.lastModTime == self.logStats.st_mtime: | ||||
| 			return False | ||||
|  | @ -130,7 +135,7 @@ class LogReader: | |||
| 		logFile = self.openLogFile() | ||||
| 		self.setFilePos(logFile) | ||||
| 		lastLine = '' | ||||
| 		for line in logFile.readlines(): | ||||
| 		for line in logFile: | ||||
| 			lastLine = line | ||||
| 			failList = self.findFailure(line) | ||||
| 			for element in failList: | ||||
|  |  | |||
|  | @ -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/". | ||||
|  | @ -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/". | ||||
							
								
								
									
										18
									
								
								setup.py
								
								
								
								
							
							
						
						
									
										18
									
								
								setup.py
								
								
								
								
							|  | @ -18,11 +18,11 @@ | |||
| 
 | ||||
| # Author: Cyril Jaquier | ||||
| #  | ||||
| # $Revision: 1.4.2.2 $ | ||||
| # $Revision: 1.4.2.3 $ | ||||
| 
 | ||||
| __author__ = "Cyril Jaquier" | ||||
| __version__ = "$Revision: 1.4.2.2 $" | ||||
| __date__ = "$Date: 2005/07/15 14:14:12 $" | ||||
| __version__ = "$Revision: 1.4.2.3 $" | ||||
| __date__ = "$Date: 2005/07/28 20:30:34 $" | ||||
| __copyright__ = "Copyright (c) 2004 Cyril Jaquier" | ||||
| __license__ = "GPL" | ||||
| 
 | ||||
|  | @ -31,15 +31,25 @@ from version import version | |||
| from os.path import isfile, join | ||||
| from sys import exit, argv | ||||
| 
 | ||||
| longdesc = ''' | ||||
| Fail2Ban scans log files like /var/log/pwdfail or | ||||
| /var/log/apache/error_log and bans IP that makes | ||||
| too many password failures. It updates firewall rules | ||||
| to reject the IP address or executes user defined | ||||
| commands.''' | ||||
| 
 | ||||
| setup( | ||||
| 	name = "fail2ban", | ||||
| 	version = version, | ||||
| 	description = "Ban IPs that make too many password failure", | ||||
| 	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', 'log4py'], | ||||
| 	py_modules = ['fail2ban', 'version'], | ||||
| 	packages = ['firewall', 'logreader', 'confreader', 'utils'] | ||||
| ) | ||||
| 
 | ||||
|  |  | |||
|  | @ -16,20 +16,20 @@ | |||
| 
 | ||||
| # Author: Cyril Jaquier | ||||
| #  | ||||
| # $Revision: 1.1.2.1 $ | ||||
| # $Revision: 1.1.2.2 $ | ||||
| 
 | ||||
| __author__ = "Cyril Jaquier" | ||||
| __version__ = "$Revision: 1.1.2.1 $" | ||||
| __date__ = "$Date: 2005/07/12 13:09:47 $" | ||||
| __version__ = "$Revision: 1.1.2.2 $" | ||||
| __date__ = "$Date: 2005/08/01 16:35:18 $" | ||||
| __copyright__ = "Copyright (c) 2004 Cyril Jaquier" | ||||
| __license__ = "GPL" | ||||
| 
 | ||||
| import log4py, smtplib | ||||
| import logging, smtplib | ||||
| 
 | ||||
| from utils.strings import replaceTag | ||||
| 
 | ||||
| # Gets the instance of log4py. | ||||
| logSys = log4py.Logger().get_instance() | ||||
| # Gets the instance of the logger. | ||||
| logSys = logging.getLogger("fail2ban") | ||||
| 
 | ||||
| class Mail: | ||||
| 	""" Mailer class | ||||
|  |  | |||
|  | @ -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: 1.1.2.1 $ | ||||
| 
 | ||||
| __author__ = "Cyril Jaquier" | ||||
| __version__ = "$Revision: 1.1.2.1 $" | ||||
| __date__ = "$Date: 2005/08/04 20:48:30 $" | ||||
| __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) | ||||
| 	 | ||||
|  | @ -16,24 +16,24 @@ | |||
| 
 | ||||
| # Author: Cyril Jaquier | ||||
| #  | ||||
| # $Revision: 1.1.2.2 $ | ||||
| # $Revision: 1.1.2.4 $ | ||||
| 
 | ||||
| __author__ = "Cyril Jaquier" | ||||
| __version__ = "$Revision: 1.1.2.2 $" | ||||
| __date__ = "$Date: 2005/07/15 14:08:17 $" | ||||
| __version__ = "$Revision: 1.1.2.4 $" | ||||
| __date__ = "$Date: 2005/08/04 20:48:30 $" | ||||
| __copyright__ = "Copyright (c) 2004 Cyril Jaquier" | ||||
| __license__ = "GPL" | ||||
| 
 | ||||
| import os, log4py, signal | ||||
| import os, logging, signal | ||||
| 
 | ||||
| # Gets the instance of log4py. | ||||
| logSys = log4py.Logger().get_instance() | ||||
| # 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. | ||||
| 	""" 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 | ||||
| 		http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/278731 | ||||
| 	""" | ||||
| 
 | ||||
| 	try: | ||||
|  | @ -101,34 +101,6 @@ def createDaemon(): | |||
| 	os.open("/dev/null", os.O_RDWR)		# standard error (2) | ||||
| 
 | ||||
| 	return True | ||||
| 	 | ||||
| def checkForPID(lockfile): | ||||
| 	""" Checks for running Fail2Ban. | ||||
| 	 | ||||
| 		Returns the current PID if Fail2Ban is running or False | ||||
| 		if no instance found. | ||||
| 	""" | ||||
| 	try: | ||||
| 		fileHandler = open(lockfile) | ||||
| 		pid = fileHandler.readline() | ||||
| 		return pid | ||||
| 	except IOError: | ||||
| 		return False | ||||
| 		 | ||||
| def createPID(lockfile): | ||||
| 	""" Creates a PID lock file with the current PID. | ||||
| 	""" | ||||
| 	fileHandler = open(lockfile, mode='w') | ||||
| 	pid = os.getpid() | ||||
| 	fileHandler.write(`pid`+'\n') | ||||
| 	fileHandler.close() | ||||
| 	logSys.debug("Created PID lock ("+`pid`+") in "+lockfile) | ||||
| 		 | ||||
| def removePID(lockfile): | ||||
| 	""" Remove PID lock. | ||||
| 	""" | ||||
| 	os.remove(lockfile) | ||||
| 	logSys.debug("Removed PID lock "+lockfile) | ||||
| 
 | ||||
| def killPID(pid): | ||||
| 	""" Kills the process with the given PID using the | ||||
|  | @ -151,6 +123,9 @@ def executeCmd(cmd, debug): | |||
| 	 | ||||
| 	logSys.debug(cmd) | ||||
| 	if not debug: | ||||
| 		return os.system(cmd) | ||||
| 		retval = os.system(cmd) | ||||
| 		if not retval == 0: | ||||
| 			logSys.error("'" + cmd + "' returned " + `retval`) | ||||
| 		return retval | ||||
| 	else: | ||||
| 		return None | ||||
|  |  | |||
|  | @ -16,18 +16,18 @@ | |||
| 
 | ||||
| # Author: Cyril Jaquier | ||||
| #  | ||||
| # $Revision: 1.1.2.1 $ | ||||
| # $Revision: 1.1.2.2 $ | ||||
| 
 | ||||
| __author__ = "Cyril Jaquier" | ||||
| __version__ = "$Revision: 1.1.2.1 $" | ||||
| __date__ = "$Date: 2005/07/12 13:09:47 $" | ||||
| __version__ = "$Revision: 1.1.2.2 $" | ||||
| __date__ = "$Date: 2005/08/01 16:35:18 $" | ||||
| __copyright__ = "Copyright (c) 2004 Cyril Jaquier" | ||||
| __license__ = "GPL" | ||||
| 
 | ||||
| import log4py | ||||
| import logging | ||||
| 
 | ||||
| # Gets the instance of log4py. | ||||
| logSys = log4py.Logger().get_instance() | ||||
| # Gets the instance of the logger. | ||||
| logSys = logging.getLogger("fail2ban") | ||||
| 
 | ||||
| def replaceTag(query, aInfo): | ||||
| 	""" Replace tags in query | ||||
|  |  | |||
|  | @ -16,12 +16,12 @@ | |||
| 
 | ||||
| # Author: Cyril Jaquier | ||||
| #  | ||||
| # $Revision: 1.12.2.4 $ | ||||
| # $Revision: 1.12.2.6 $ | ||||
| 
 | ||||
| __author__ = "Cyril Jaquier" | ||||
| __version__ = "$Revision: 1.12.2.4 $" | ||||
| __date__ = "$Date: 2005/07/23 09:31:12 $" | ||||
| __version__ = "$Revision: 1.12.2.6 $" | ||||
| __date__ = "$Date: 2005/08/06 15:07:11 $" | ||||
| __copyright__ = "Copyright (c) 2004 Cyril Jaquier" | ||||
| __license__ = "GPL" | ||||
| 
 | ||||
| version = "0.5.1" | ||||
| version = "0.5.2" | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	 Yaroslav Halchenko
						Yaroslav Halchenko