diff --git a/CHANGELOG b/CHANGELOG index de0736a0..829d346f 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -4,9 +4,22 @@ |_| \__,_|_|_/___|_.__/\__,_|_||_| ============================================================= -Fail2Ban (version 0.5.3) 2005/09/08 +Fail2Ban (version 0.5.4) 2005/09/13 ============================================================= +ver. 0.5.4 (2005/09/13) - beta +---------- +- Fixed bug #1286222. +- Propagated patches introduced by Debian maintainer + (Yaroslav Halchenko): + * Fixed handling of SYSLOG logging target. Now it can log + to any SYSLOG target and facility as directed by the + config + * Format of SYSLOG entries fixed to look closer to standard + * Fixed errata in config/gentoo-confd + * Introduced findtime configuration variable to control the + lifetime of caught "failed" log entries + ver. 0.5.3 (2005/09/08) - beta ---------- - Fixed a bug when overriding "maxfailures" or "bantime". diff --git a/PKG-INFO b/PKG-INFO index d08ff836..bc30c0d1 100644 --- a/PKG-INFO +++ b/PKG-INFO @@ -1,6 +1,6 @@ Metadata-Version: 1.0 Name: fail2ban -Version: 0.5.3 +Version: 0.5.4 Summary: Ban IPs that make too many password failure Home-page: http://fail2ban.sourceforge.net Author: Cyril Jaquier diff --git a/README b/README index ba03b945..243c194f 100644 --- a/README +++ b/README @@ -4,7 +4,7 @@ |_| \__,_|_|_/___|_.__/\__,_|_||_| ============================================================= -Fail2Ban (version 0.5.3) 2005/09/08 +Fail2Ban (version 0.5.4) 2005/09/13 ============================================================= Fail2Ban scans log files like /var/log/pwdfail and bans IP @@ -58,8 +58,8 @@ Require: python-2.3 (http://www.python.org) To install, just do: -> tar xvfj fail2ban-0.5.3.tar.bz2 -> cd fail2ban-0.5.3 +> tar xvfj fail2ban-0.5.4.tar.bz2 +> cd fail2ban-0.5.4 > python setup.py install This will install Fail2Ban into /usr/lib/fail2ban. The fail2ban diff --git a/config/debian-initd b/config/debian-initd index b3892991..c10691d5 100644 --- a/config/debian-initd +++ b/config/debian-initd @@ -1,13 +1,14 @@ #! /bin/sh # -# skeleton example file to build /etc/init.d/ scripts. -# This file should be used to construct scripts for /etc/init.d. +# Fail2Ban init.d file - to be launched on boot # # Written by Miquel van Smoorenburg . -# Modified for Debian -# by Ian Murdock . +# Modified for Debian +# by Ian Murdock . +# Adjusted for Fail2Ban +# by Yaroslav Halchenko . # -# Version: @(#)skeleton 1.9 26-Feb-2001 miquels@cistron.nl +# Version: $Id: debian-initd,v 1.1.2.2 2005/09/11 15:42:32 yarikoptic Exp $ # PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin @@ -26,36 +27,47 @@ 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 + start) + echo -n "Starting $DESC: " + [ -f $PIDFILE ] && [ ! -d /proc/`cat $PIDFILE` ] && rm -f $PIDFILE + start-stop-daemon --start --quiet --pidfile $PIDFILE \ + -b --exec $DAEMON -- $DAEMON_OPTS + echo "$NAME." + ;; + stop) + echo -n "Stopping $DESC: " + start-stop-daemon --stop --quiet --pidfile $PIDFILE + echo "$NAME." + ;; + restart|force-reload) + echo -n "Restarting $DESC: " + ( $0 stop ) + sleep 1 + $0 start + ;; + status) + echo -n "Status of $DESC: " + if [ ! -e "$PIDFILE" ]; then + echo "$NAME is not running." + exit 3 + fi + if [ ! -r "$PIDFILE" ]; then + echo "$PIDFILE not readable, status of $NAME unknown." + exit 4 + fi + if [ -d /proc/`cat "$PIDFILE"` ]; then + echo "$NAME is running." + exit 0 + else + echo "$NAME is not running but $PIDFILE exists." + exit 1 + fi ;; + *) + N=/etc/init.d/$NAME + echo "Usage: $N {start|stop|restart|force-reload|status}" >&2 + exit 1 + ;; esac -exit 0 \ No newline at end of file +exit 0 diff --git a/config/fail2ban.conf.default b/config/fail2ban.conf.default index d1dd0732..6ee91f81 100644 --- a/config/fail2ban.conf.default +++ b/config/fail2ban.conf.default @@ -1,6 +1,6 @@ # Fail2Ban configuration file # -# $Revision: 1.8.2.11 $ +# $Revision: 1.8.2.13 $ # # 2005.06.21 modified for readability Iain Lea iain@bricbrac.de @@ -23,6 +23,18 @@ debug = false # logtargets = /var/log/fail2ban.log +# Option: syslog-target +# Notes.: where to find syslog facility if logtarget SYSLOG. +# Values: SOCKET HOST HOST:PORT Default: /dev/log +# +syslog-target = /dev/log + +# Option: syslog-facility +# Notes.: which syslog facility to use if logtarget SYSLOG. +# Values: NUM Default: 1 +# +syslog-facility = 1 + # Option: pidlock # Notes.: path of the PID lock file (must be able to write to file). # Values: FILE Default: /var/run/fail2ban.pid @@ -41,6 +53,12 @@ maxfailures = 5 # bantime = 600 +# Option: findtime +# Notes.: lifetime in seconds of a "failed" log entry. +# Values: NUM Default: 600 +# +findtime = 600 + # Option: ignoreip # Notes.: space separated list of IP's to be ignored by fail2ban. # You can use CIDR mask in order to specify a range. @@ -56,7 +74,7 @@ ignoreip = 192.168.0.0/16 cmdstart = # Option: cmdend -# Notes.: command executed once at the end of Fail2Ban +# Notes.: command executed once at the end of Fail2Ban. # Values: CMD Default: # cmdend = @@ -114,7 +132,7 @@ subject = [Fail2Ban] Banned # number of failures # unix timestamp of the last failure #
new line -# Values: TEXT Default: +# Values: TEXT Default: # message = Hi,
The IP has just been banned by Fail2Ban after @@ -181,7 +199,7 @@ fwunban = iptables -D fail2ban-http -s -j DROP # Option: timeregex # Notes.: regex to match timestamp in Apache logfile. -# Values: [Wed Jan 05 15:08:01 2005] +# 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} @@ -253,7 +271,7 @@ fwunban = iptables -D fail2ban-ssh -s -j DROP # Option: timeregex # Notes.: regex to match timestamp in SSH logfile. -# Values: [Mar 7 17:53:28] +# 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} diff --git a/config/gentoo-confd b/config/gentoo-confd index 94f91d8e..8c4489db 100644 --- a/config/gentoo-confd +++ b/config/gentoo-confd @@ -16,8 +16,8 @@ # # Author: Cyril Jaquier # -# $Revision: 1.1 $ +# $Revision: 1.1.2.1 $ -# Command line options for Fail2Ban. Refer to "fail2ban.py -h" for +# Command line options for Fail2Ban. Refer to "fail2ban -h" for # valid options. FAIL2BAN_OPTS="-v" diff --git a/fail2ban.py b/fail2ban.py index 7e17c032..0520c6d1 100755 --- a/fail2ban.py +++ b/fail2ban.py @@ -15,12 +15,13 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # Author: Cyril Jaquier +# Modified by: Yaroslav Halchenko (SYSLOG, findtime) # -# $Revision: 1.20.2.16 $ +# $Revision: 1.20.2.18 $ __author__ = "Cyril Jaquier" -__version__ = "$Revision: 1.20.2.16 $" -__date__ = "$Date: 2005/09/05 21:12:08 $" +__version__ = "$Revision: 1.20.2.18 $" +__date__ = "$Date: 2005/09/13 20:42:33 $" __copyright__ = "Copyright (c) 2004 Cyril Jaquier" __license__ = "GPL" @@ -144,7 +145,8 @@ def main(): logSys.addHandler(stdout) # Default formatter - formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s') + formatterstring='%(levelname)s: %(message)s' + formatter = logging.Formatter('%(asctime)s ' + formatterstring) stdout.setFormatter(formatter) conf["verbose"] = 0 @@ -175,10 +177,13 @@ def main(): # Options optionValues = (["bool", "background", False], ["str", "logtargets", "/var/log/fail2ban.log"], + ["str", "syslog-target", "/dev/log"], + ["int", "syslog-facility", 1], ["bool", "debug", False], ["str", "pidlock", "/var/run/fail2ban.pid"], ["int", "maxfailures", 5], ["int", "bantime", 600], + ["int", "findtime", 600], ["str", "ignoreip", ""], ["int", "polltime", 1], ["str", "cmdstart", ""], @@ -226,9 +231,9 @@ def main(): # Set debug log level if conf["debug"]: logSys.setLevel(logging.DEBUG) - formatter = logging.Formatter("%(asctime)s %(levelname)s " + - "[%(filename)s (%(lineno)d)] " + - "%(message)s") + formatterstring = ('%(levelname)s: [%(filename)s (%(lineno)d)] ' + + '%(message)s') + formatter = logging.Formatter("%(asctime)s " + formatterstring) stdout.setFormatter(formatter) logSys.warn("DEBUG MODE: FIREWALL COMMANDS ARE _NOT_ EXECUTED BUT " + "ONLY DISPLAYED IN THE LOG MESSAGES") @@ -238,10 +243,41 @@ def main(): # Bug fix for #1234699 os.umask(0077) for target in conf["logtargets"].split(): + # target formatter + # By default global formatter is taken. Is different for SYSLOG + tformatter = formatter if target == "STDERR": hdlr = logging.StreamHandler(sys.stderr) elif target == "SYSLOG": - hdlr = logging.handlers.SysLogHandler() + # SYSLOG target can be either + # a socket (file, so it starts with /) + # or hostname + # or hostname:port + syslogtargets = re.findall("(/[\w/]*)|([^/ ][^: ]*)(:(\d+)){,1}", + conf["syslog-target"]) + # we are waiting for a single match + syslogtargets = syslogtargets[0] + + # assign facility if it was defined + if conf["syslog-facility"] < 0: + facility = handlers.SysLogHandler.LOG_USER + else: + facility = conf["syslog-facility"] + + if len(syslogtargets) == 0: # everything default + hdlr = logging.handlers.SysLogHandler() + else: + if not ( syslogtargets[0] == "" ): # got socket + syslogtarget = syslogtargets[0] + else: # got hostname and maybe a port + if syslogtargets[3] == "": # no port specified + port = 514 + else: + port = int(syslogtargets[3]) + syslogtarget = (syslogtargets[1], port) + hdlr = logging.handlers.SysLogHandler(syslogtarget, facility) + tformatter = logging.Formatter("fail2ban[%(process)d]: " + + formatterstring); else: # Target should be a file try: @@ -251,12 +287,12 @@ def main(): logSys.error("Unable to log to " + target) continue # Set formatter and add handler to logger - hdlr.setFormatter(formatter) + hdlr.setFormatter(tformatter) logSys.addHandler(hdlr) # Ignores IP list ignoreIPList = conf["ignoreip"].split(' ') - + # Checks for root user. This is necessary because log files # are owned by root and firewall needs root access. if not checkForRoot(): @@ -277,6 +313,7 @@ def main(): logSys.debug("ConfFile is " + conf["conffile"]) logSys.debug("BanTime is " + `conf["bantime"]`) + logSys.debug("FindTime is " + `conf["findtime"]`) logSys.debug("MaxFailure is " + `conf["maxfailures"]`) # Options @@ -302,8 +339,9 @@ def main(): # Options optionValues = (["bool", "enabled", False], ["str", "logfile", "/dev/null"], - ["int", "maxfailures", None], - ["int", "bantime", None], + ["int", "maxfailures", conf["maxfailures"]], + ["int", "bantime", conf["bantime"]], + ["int", "findtime", conf["findtime"]], ["str", "timeregex", ""], ["str", "timepattern", ""], ["str", "failregex", ""], @@ -316,23 +354,11 @@ def main(): for t in confReader.getSections(): l = confReader.getLogOptions(t, optionValues) if l["enabled"]: - # Override maxfailures option - if not l["maxfailures"] == None: - maxFailures = l["maxfailures"] - else: - maxFailures = conf["maxfailures"] - - # Override bantime option - if not l["bantime"] == None: - banTime = l["bantime"] - else: - banTime = conf["bantime"] - # Creates a logreader object lObj = LogReader(l["logfile"], l["timeregex"], l["timepattern"], - l["failregex"], maxFailures, banTime) + l["failregex"], l["maxfailures"], l["findtime"]) # Creates a firewall object - fObj = Firewall(l["fwban"], l["fwunban"], banTime) + fObj = Firewall(l["fwban"], l["fwunban"], l["bantime"]) # Links them into a list. I'm not really happy # with this :/ logFwList.append([t, lObj, fObj, dict(), l]) diff --git a/utils/mail.py b/utils/mail.py index 5ae2fc43..73b8bd92 100644 --- a/utils/mail.py +++ b/utils/mail.py @@ -16,17 +16,18 @@ # Author: Cyril Jaquier # -# $Revision: 1.1.2.3 $ +# $Revision: 1.1.2.4 $ __author__ = "Cyril Jaquier" -__version__ = "$Revision: 1.1.2.3 $" -__date__ = "$Date: 2005/09/08 18:05:59 $" +__version__ = "$Revision: 1.1.2.4 $" +__date__ = "$Date: 2005/09/12 14:42:08 $" __copyright__ = "Copyright (c) 2004 Cyril Jaquier" __license__ = "GPL" import logging, smtplib from utils.strings import replaceTag +from time import strftime, gmtime # Gets the instance of the logger. logSys = logging.getLogger("fail2ban") @@ -55,8 +56,10 @@ class Mail: 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 + mail = ("From: %s\r\nTo: %s\r\nDate: %s\r\nSubject: %s\r\n\r\n" % + (self.fromAddr, ", ".join(self.toAddr), + strftime("%a, %d %b %Y %H:%M:%S +0000", gmtime()), + subj)) + msg try: server = smtplib.SMTP(self.host, self.port) diff --git a/version.py b/version.py index 30da7d75..347c3964 100644 --- a/version.py +++ b/version.py @@ -16,12 +16,12 @@ # Author: Cyril Jaquier # -# $Revision: 1.12.2.8 $ +# $Revision: 1.12.2.10 $ __author__ = "Cyril Jaquier" -__version__ = "$Revision: 1.12.2.8 $" -__date__ = "$Date: 2005/09/08 18:20:51 $" +__version__ = "$Revision: 1.12.2.10 $" +__date__ = "$Date: 2005/09/13 20:43:00 $" __copyright__ = "Copyright (c) 2004 Cyril Jaquier" __license__ = "GPL" -version = "0.5.3" +version = "0.5.4"