I guess I did mediocre job maintaining fail2ban in the recent times
(partially since upstream is dead, only minor community
support/fixing and I have no free time for doing upstream scale
maintenance). for squeeze it is too late -- it is deeply frozen and bug
is not grave (although important).

The reason why I have not applied sleep patch is that it is just a
workaround -- not the solution, thus not reliably prevents the problem.

Proper solution requires queuing all iptables commands in a single pull
and executing them sequentially.

Rain (aka linuxoid.rain) in private communication did some "research"
and implemented it via a feeding iptables command to FIFO socket for execution
by a little listener on the other end.  Something like

# in init script
mkfifo -m 600 /var/run/fail2ban.com.sock
tail -f /var/run/fail2ban.com.sock | sh

# in action scripts
echo "command" > /var/run/fail2ban.com.sock

I am attaching his resultant init.d file and the iptables action configuration
for it.  It would be great if someone could verify its functioning with stock
(without sleeps) fail2ban.


Cheers

On Wed, 19 Jan 2011, Olivier Dousse wrote:

> I forgot to mention that the patch at 
> http://sourceforge.net/tracker/?func=detail&aid=2857096&group_id=121032&atid=689046
>  worked fine in system. 
> My suggestion would be to apply this patch to the package released in Squeeze.

-- 
=------------------------------------------------------------------=
Keep in touch                                     www.onerussian.com
Yaroslav Halchenko                 www.ohloh.net/accounts/yarikoptic
#! /bin/sh
### BEGIN INIT INFO
# Provides:          fail2ban
# Required-Start:    $local_fs $remote_fs
# Required-Stop:     $local_fs $remote_fs
# Should-Start:      $time $network $syslog iptables firehol shorewall ipmasq 
arno-iptables-firewall
# Should-Stop:       $network $syslog iptables firehol shorewall ipmasq 
arno-iptables-firewall
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: Start/stop fail2ban
# Description:       Start/stop fail2ban, a daemon scanning the log files and
#                    banning potential attackers.
### END INIT INFO

# Author: Aaron Isotton <[email protected]>
# Modified: by Yaroslav Halchenko <[email protected]>
#  reindented + minor corrections + to work on sarge without modifications
#
PATH=/usr/sbin:/usr/bin:/sbin:/bin
DESC="authentication failure monitor"
NAME=fail2ban

# fail2ban-client is not a daemon itself but starts a daemon and
# loads its with configuration
DAEMON=/usr/bin/$NAME-client
SCRIPTNAME=/etc/init.d/$NAME

# Ad-hoc way to parse out socket file name
SOCKFILE=`grep -h '^[^#]*socket *=' /etc/$NAME/$NAME.conf 
/etc/$NAME/$NAME.local 2>/dev/null \
          | tail -n 1 | sed -e 's/.*socket *= *//g' -e 's/ *$//g'`
[ -z "$SOCKFILE" ] && SOCKFILE='/tmp/fail2ban.sock'

# Exit if the package is not installed
[ -x "$DAEMON" ] || exit 0

# Read configuration variable file if it is present
[ -r /etc/default/$NAME ] && . /etc/default/$NAME
DAEMON_ARGS="$FAIL2BAN_OPTS"

# Load the VERBOSE setting and other rcS variables
[ -f /etc/default/rcS ] && . /etc/default/rcS

# Predefine what can be missing from lsb source later on -- necessary to run
# on sarge. Just present it in a bit more compact way from what was shipped
log_daemon_msg () {
        [ -z "$1" ] && return 1
        echo -n "$1:"
        [ -z "$2" ] || echo -n " $2"
}

# Define LSB log_* functions.
# Depend on lsb-base (>= 3.0-6) to ensure that this file is present.
# Actually has to (>=2.0-7) present in sarge. log_daemon_msg is predefined
#  so we must be ok
. /lib/lsb/init-functions

#
# Shortcut function for abnormal init script interruption
#
report_bug()
{
        echo $*
        echo "Please submit a bug report to Debian BTS (reportbug fail2ban)"
        exit 1
}

#
# Helper function to check if socket is present, which is often left after
# abnormal exit of fail2ban and needs to be removed
#
check_socket()
{
        # Return
        #       0 if socket is present and readable
        #       1 if socket file is not present
        #       2 if socket file is present but not readable
        #       3 if socket file is present but is not a socket
        [ -e "$SOCKFILE" ] || return 1
        [ -r "$SOCKFILE" ] || return 2
        [ -S "$SOCKFILE" ] || return 3
        return 0
}

#
# Function that checks the status of fail2ban and returns
# corresponding code
#
do_status()
{
        $DAEMON ping > /dev/null
        return $?
}

#
# Function that starts the daemon/service
#
do_start()
{
        # Return
        #       0 if daemon has been started
        #       1 if daemon was already running
        #       2 if daemon could not be started
        do_status && return 1

        if [ -e "$SOCKFILE" ]; then
                log_failure_msg "Socket file $SOCKFILE is present"
                [ "$1" = "force-start" ] \
                        && log_success_msg "Starting anyway as requested" \
                        || return 2
                DAEMON_ARGS="$DAEMON_ARGS -x"
        fi

        # Assure that /var/run/fail2ban exists
        [ -d /var/run/fail2ban ] || mkdir -p /var/run/fail2ban

# Костыль для работы многопоточности - создаем сокет для команд
        rm -f /var/run/fail2ban/fail2ban.com.sock 2>/dev/null
        mkfifo -m 600 /var/run/fail2ban/fail2ban.com.sock

        start-stop-daemon --start --quiet --chuid root --exec $DAEMON -- \
                $DAEMON_ARGS start > /dev/null\
                || return 2

# Если демон стартовал - "слушаем" сокет, выполняя команды, которые в него 
попадают
# tail убивается при снятии процесса демона
if do_status
        then
        (tail -f --pid=$(cat /var/run/fail2ban/fail2ban.pid) 
/var/run/fail2ban/fail2ban.com.sock | sh &)
fi
        return 0
}


#
# Function that stops the daemon/service
#
do_stop()
{
        # Return
        #       0 if daemon has been stopped
        #       1 if daemon was already stopped
        #       2 if daemon could not be stopped
        #       other if a failure occurred
        $DAEMON status > /dev/null || return 1
        $DAEMON stop > /dev/null || return 2

        # now we need actually to wait a bit since it might take time
        # for server to react on client's stop request. Especially
        # important for restart command on slow boxes
        count=1
        while do_status && [ $count -lt 60 ]; do
                sleep 1
                count=$(($count+1))
        done
        [ $count -lt 60 ] || return 3 # failed to stop

if ! do_status
        then
        rm -f /var/run/fail2ban/fail2ban.com.sock 2>/dev/null
fi

        return 0
}

#
# Function to reload configuration
#
do_reload() {
        $DAEMON reload > /dev/null && return 0 || return 1
        return 0
}

# yoh:
# shortcut function to don't duplicate case statements and to don't use
# bashisms (arrays). Fixes #368218
#
log_end_msg_wrapper()
{
        [ $1 -lt $2 ] && value=0 || value=1
        log_end_msg $value
}

command="$1"
case "$command" in
        start|force-start)
                [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME"
                do_start "$command"
                [ "$VERBOSE" != no ] && log_end_msg_wrapper $? 2
                ;;

        stop)
                [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME"
                do_stop
                [ "$VERBOSE" != no ] && log_end_msg_wrapper $? 2
                ;;

        restart|force-reload)
                log_daemon_msg "Restarting $DESC" "$NAME"
                do_stop
                case "$?" in
                        0|1)
                                do_start
                                log_end_msg_wrapper $? 1
                                ;;
                        *)
                                # Failed to stop
                                log_end_msg 1
                                ;;
                esac
                ;;

        reload|force-reload)
        log_daemon_msg "Reloading $DESC" "$NAME"
        do_reload
        log_end_msg $?
        ;;

        status)
                log_daemon_msg "Status of $DESC"
                do_status
                case $? in
                        0)  log_success_msg " $NAME is running" ;;
                        255)
                                check_socket
                                case $? in
                                        1)  log_warning_msg " $NAME is not 
running" ;;
                                        0)  log_failure_msg " $NAME is not 
running but $SOCKFILE exists" ;;
                                        2)  log_failure_msg " $SOCKFILE not 
readable, status of $NAME is unknown";;
                                        3)  log_failure_msg " $SOCKFILE exists 
but not a socket, status of $NAME is unknown";;
                                        *)  report_bug "Unknown return code 
from $NAME:check_socket.";;
                                esac
                                ;;
                        *)  report_bug "Unknown $NAME status code"
                esac
                ;;
        *)
                echo "Usage: $SCRIPTNAME 
{start|force-start|stop|restart|force-reload|status}" >&2
                exit 3
                ;;
esac

:
# Fail2Ban configuration file
#
# Author: Cyril Jaquier
# Modified by Yaroslav Halchenko for multiport banning
# $Revision: 658 $
#


[Definition]

# Option:  actionstart
# Notes.:  command executed once at the start of Fail2Ban.
# Values:  CMD
#
actionstart = echo "iptables -N fail2ban-<name>" > 
/var/run/fail2ban/fail2ban.com.sock
              echo "iptables -A fail2ban-<name> -j RETURN" > 
/var/run/fail2ban/fail2ban.com.sock
              echo "iptables -I INPUT -p <protocol> -m multiport --dports 
<port> -j fail2ban-<name>" > /var/run/fail2ban/fail2ban.com.sock
              echo "iptables -I FORWARD -p <protocol> -m multiport --dports 
<port> -j fail2ban-<name>" > /var/run/fail2ban/fail2ban.com.sock

# Option:  actionstop
# Notes.:  command executed once at the end of Fail2Ban
# Values:  CMD
#
actionstop = echo "iptables -D INPUT -p <protocol> -m multiport --dports <port> 
-j fail2ban-<name>" > /var/run/fail2ban/fail2ban.com.sock
             echo "iptables -D FORWARD -p <protocol> -m multiport --dports 
<port> -j fail2ban-<name>" > /var/run/fail2ban/fail2ban.com.sock
             echo "iptables -F fail2ban-<name>" > 
/var/run/fail2ban/fail2ban.com.sock
             echo "iptables -X fail2ban-<name>" > 
/var/run/fail2ban/fail2ban.com.sock

# Option:  actioncheck
# Notes.:  command executed once before each actionban command
# Values:  CMD
#
actioncheck = iptables -n -L INPUT | grep -q fail2ban-<name>

# Option:  actionban
# Notes.:  command executed when banning an IP. Take care that the
#          command is executed with Fail2Ban user rights.
# Tags:    <ip>  IP address
#          <failures>  number of failures
#          <time>  unix timestamp of the ban time
# Values:  CMD
#
actionban = echo "iptables -I fail2ban-<name> 1 -s <ip> -j DROP" > 
/var/run/fail2ban/fail2ban.com.sock

# Option:  actionunban
# Notes.:  command executed when unbanning an IP. Take care that the
#          command is executed with Fail2Ban user rights.
# Tags:    <ip>  IP address
#          <failures>  number of failures
#          <time>  unix timestamp of the ban time
# Values:  CMD
#
actionunban = echo "iptables -D fail2ban-<name> -s <ip> -j DROP" > 
/var/run/fail2ban/fail2ban.com.sock

[Init]

# Defaut name of the chain
#
name = default

# Option:  port
# Notes.:  specifies port to monitor
# Values:  [ NUM | STRING ]  Default:
#
port = ssh

# Option:  protocol
# Notes.:  internally used by config reader for interpolations.
# Values:  [ tcp | udp | icmp | all ] Default: tcp
#
protocol = tcp

Attachment: signature.asc
Description: Digital signature

Reply via email to