diff --git a/CHANGELOG b/CHANGELOG index de0736a0..89b01f3b 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -7,6 +7,18 @@ Fail2Ban (version 0.5.3) 2005/09/08 ============================================================= +ver. ?.?.? (????/??/??) - ? +---------- +- 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/config/debian-initd b/config/debian-initd index b3892991..2c5c48d1 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$ # 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 13b4539f..3c86ea53 100644 --- a/config/fail2ban.conf.default +++ b/config/fail2ban.conf.default @@ -23,6 +23,16 @@ debug = false # logtargets = /var/log/fail2ban.log +# Option: syslog-target +# Notes.: where to find syslog facility if logtarget SYSLOG. +# Values: file(socket) hostname hostname: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 +51,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 +72,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 +130,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 +197,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 +269,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 e156c368..bea9017e 100644 --- a/config/gentoo-confd +++ b/config/gentoo-confd @@ -18,6 +18,6 @@ # # $Revision$ -# 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 debd2b6b..dafc1ad0 100755 --- a/fail2ban.py +++ b/fail2ban.py @@ -15,6 +15,7 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # Author: Cyril Jaquier +# Modified by: Yaroslav Halchenko (SYSLOG, findtime) # # $Revision$ @@ -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,42 @@ 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 may be 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 +288,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 +314,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 +340,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 +355,12 @@ 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])