Fail2ban + IPTables

Xcantion

New Member
Hallo Liebe leutz,

ich habe da einmal eine frage .. ich habe mir eine Iptables Firewall zusammengebastelt die funktioniert auch wunderbar .. zumindest soweit wie ich das beurteilen kann..

Jetzt wollte ich Fail2ban mit den IPTables verknüpfen... doch ab hier wirds heikel..

Es sieht so aus als wenn Fail2Ban seine eigenen IPTables von haus aus mitbringt..
Das heißt jedesmal wenn ich die Iptables am laufen habe und Fail2ban starte / restarte werden die Rules umgeschrieben..

Ich werde mal meine momentane Konfiguration Posten evtl. wirds dann einfacher zu verstehen sein.

Also meine Selbsgeschriebene IPTables Scripts:

Pfad: /etc/default/iptables
Code:
*filter
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [0:0]

# MY_REJECT-Chain
    -N MY_REJECT

# MY_REJECT fuellen
    -A MY_REJECT -p tcp -m limit --limit 7200/h -j LOG --log-prefix "REJECT TCP "
    -A MY_REJECT -p tcp -j REJECT --reject-with tcp-reset
    -A MY_REJECT -p udp -m limit --limit 7200/h -j LOG --log-prefix "REJECT UDP "
    -A MY_REJECT -p udp -j REJECT --reject-with icmp-port-unreachable
    -A MY_REJECT -p icmp -m limit --limit 7200/h -j LOG --log-prefix "DROP ICMP "
    -A MY_REJECT -p icmp -j DROP
    -A MY_REJECT -m limit --limit 7200/h -j LOG --log-prefix "REJECT OTHER "
    -A MY_REJECT -j REJECT --reject-with icmp-proto-unreachable

# MY_DROP-Chain
    -N MY_DROP
    -A MY_DROP -m limit --limit 7200/h -j LOG --log-prefix "PORTSCAN DROP "
    -A MY_DROP -j DROP

# Alle verworfenen Pakete protokollieren
    -A INPUT -m state --state INVALID -m limit --limit 7200/h -j LOG --log-prefix "INPUT INVALID "
    -A OUTPUT -m state --state INVALID -m limit --limit 7200/h -j LOG --log-prefix "OUTPUT INVALID "

# Korrupte Pakete zurueckweisen
    -A INPUT -m state --state INVALID -j DROP
    -A OUTPUT -m state --state INVALID -j DROP

# Stealth Scans etc. DROPpen
# Keine Flags gesetzt
    -A INPUT -p tcp --tcp-flags ALL NONE -j MY_DROP

# SYN und FIN gesetzt
    -A INPUT -p tcp --tcp-flags SYN,FIN SYN,FIN -j MY_DROP

# SYN und RST gleichzeitig gesetzt
    -A INPUT -p tcp --tcp-flags SYN,RST SYN,RST -j MY_DROP

# FIN und RST gleichzeitig gesetzt
    -A INPUT -p tcp --tcp-flags FIN,RST FIN,RST -j MY_DROP

# FIN ohne ACK
    -A INPUT -p tcp --tcp-flags ACK,FIN FIN -j MY_DROP

# PSH ohne ACK
    -A INPUT -p tcp --tcp-flags ACK,PSH PSH -j MY_DROP

# URG ohne ACK
    -A INPUT -p tcp --tcp-flags ACK,URG URG -j MY_DROP

# Loopback-Netzwerk-Kommunikation zulassen
    -A INPUT -i lo -j ACCEPT
    -A OUTPUT -o lo -j ACCEPT

# Fail2Ban Kette
	-N fail2ban-ssh
       -A fail2ban-ssh -j RETURN
       -I INPUT -p tcp --dport ssh -j fail2ban-ssh

# Connection-Tracking aktivieren
    -A OUTPUT -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT
    -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

# HTTP
    -A INPUT -i eth0 -m state --state NEW -p tcp --dport 80 -j ACCEPT

# HTTPS
    -A INPUT -i eth0 -m state --state NEW -p tcp --dport 443 -j ACCEPT

# SSH
    -A INPUT -i eth0 -m state --state NEW -p tcp --dport 22 -j ACCEPT

# MYSQL
    -A INPUT -i eth0 -m state --state NEW -p tcp --dport 3306 -j ACCEPT

# fail2ban-ssh
	-I fail2ban-ssh 1 -s xxx.xxx.xxx.xxx -j DROP

# Default-Policies mit REJECT
    -A INPUT -j MY_REJECT
    -A OUTPUT -j MY_REJECT

# Keep state.
#-A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

# http/https, smtp/smtps, pop3/pop3s, imap/imaps, ssh
#-A INPUT -p tcp -m multiport --dport 80,443,25,465,110,995,143,993,587,465,22 -j ACCEPT

# Loop device.
#-A INPUT -i lo -j ACCEPT

# http/https
#-A INPUT -p tcp -m multiport --dport 80,443 -j ACCEPT

# smtp/smtps
#-A INPUT -p tcp -m multiport --dport 25,465 -j ACCEPT

# pop3/pop3s
#-A INPUT -p tcp -m multiport --dport 110,995 -j ACCEPT

# imap/imaps
#-A INPUT -p tcp -m multiport --dport 143,993 -j ACCEPT

# ldap/ldaps
#-A INPUT -p tcp -m multiport --dport 389,636 -j ACCEPT

# ftp.
#-A INPUT -p tcp -m multiport --dport 21,20 -j ACCEPT

# ssh
#-A INPUT -p tcp --dport 22 -j ACCEPT

COMMIT
In dieser Datei kann ich sämtliche Rules einstellen...

Aufruf des oben genannten IPTables Scriptes erfolgt via:

Pfad: /etc/init.d/iptables
Code:
 /lib/lsb/init-functions

IPTABLES='iptables'
IPTABLES_DATA="/etc/default/$IPTABLES"
IPTABLES_CONFIG="/etc/default/${IPTABLES}-config"
IPV="${IPTABLES%tables}" # ip for ipv4 | ip6 for ipv6
PROC_IPTABLES_NAMES="/proc/net/${IPV}_tables_names"
VAR_SUBSYS_IPTABLES="/var/lock/subsys/$IPTABLES"
[ -d $(dirname ${VAR_SUBSYS_IPTABLES}) ] || mkdir -p $(dirname ${VAR_SUBSYS_IPTABLES})

if [ ! -x /sbin/$IPTABLES ]; then
    log_daemon_msg "/sbin/$IPTABLES does not exist." "iptables"
    exit 0
fi

if lsmod 2>/dev/null | grep -q ipchains ; then
    log_daemon_msg  "ipchains and $IPTABLES can not be used together." "iptables"
    exit 0
fi

# Old or new modutils
/sbin/modprobe --version 2>&1 | grep -q module-init-tools \
    && NEW_MODUTILS=1 \
    || NEW_MODUTILS=0

# Default firewall configuration:
IPTABLES_MODULES=""
IPTABLES_MODULES_UNLOAD="yes"
IPTABLES_SAVE_ON_STOP="no"
IPTABLES_SAVE_ON_RESTART="no"
IPTABLES_SAVE_COUNTER="no"
IPTABLES_STATUS_NUMERIC="yes"

# Load firewall configuration.
[ -f "$IPTABLES_CONFIG" ] && . "$IPTABLES_CONFIG"

rmmod_r() {
    # Unload module with all referring modules.
    # At first all referring modules will be unloaded, then the module itself.
    local mod=$1
    local ret=0
    local ref=

    # Get referring modules.
    # New modutils have another output format.
    [ $NEW_MODUTILS = 1 ] \
	&& ref=`lsmod | awk "/^${mod}/ { print \\\$4; }" | tr ',' ' '` \
	|| ref=`lsmod | grep ^${mod} | cut -d "[" -s -f 2 | cut -d "]" -s -f 1`

    # recursive call for all referring modules
    for i in $ref; do
	rmmod_r $i
	let ret+=$?;
    done

    # Unload module.
    # The extra test is for 2.6: The module might have autocleaned,
    # after all referring modules are unloaded.
    if grep -q "^${mod}" /proc/modules ; then
	modprobe -r $mod > /dev/null 2>&1
	let ret+=$?;
    fi

    return $ret
}

flush_n_delete() {
    # Flush firewall rules and delete chains.
    [ -e "$PROC_IPTABLES_NAMES" ] || return 1

    # Check if firewall is configured (has tables)
    tables=`cat $PROC_IPTABLES_NAMES 2>/dev/null`
    [ -z "$tables" ] && return 1

    log_daemon_msg "Flushing firewall rules" "iptables"
    ret=0
    # For all tables
    for i in $tables; do
        # Flush firewall rules.
	$IPTABLES -t $i -F;
	let ret+=$?;

        # Delete firewall chains.
	$IPTABLES -t $i -X;
	let ret+=$?;

	# Set counter to zero.
	$IPTABLES -t $i -Z;
	let ret+=$?;
    done

    [ $ret -eq 0 ] && log_end_msg 0 || log_end_msg 1
    return $ret
}

set_policy() {
    # Set policy for configured tables.
    policy=$1

    # Check if iptable module is loaded
    [ ! -e "$PROC_IPTABLES_NAMES" ] && return 1

    # Check if firewall is configured (has tables)
    tables=`cat $PROC_IPTABLES_NAMES 2>/dev/null`
    [ -z "$tables" ] && return 1

    log_daemon_msg "Setting chains to policy $policy"
    ret=0
    for i in $tables; do
        echo -n " $i"
        case "$i" in
            raw)
                $IPTABLES -t raw -P PREROUTING $policy \
                && $IPTABLES -t raw -P OUTPUT $policy \
                || let ret+=1
            ;;
            filter)
                $IPTABLES -t filter -P INPUT $policy \
                && $IPTABLES -t filter -P OUTPUT $policy \
                && $IPTABLES -t filter -P FORWARD $policy \
                || let ret+=1
            ;;
            nat)
            $IPTABLES -t nat -P PREROUTING $policy \
                && $IPTABLES -t nat -P POSTROUTING $policy \
                && $IPTABLES -t nat -P OUTPUT $policy \
                || let ret+=1
            ;;
            mangle)
                $IPTABLES -t mangle -P PREROUTING $policy \
                && $IPTABLES -t mangle -P POSTROUTING $policy \
                && $IPTABLES -t mangle -P INPUT $policy \
                && $IPTABLES -t mangle -P OUTPUT $policy \
                && $IPTABLES -t mangle -P FORWARD $policy \
                || let ret+=1
            ;;
            *)
                let ret+=1
            ;;
        esac
    done

    [ $ret -eq 0 ] && log_end_msg 0 || log_end_msg 1
    return $ret
}

start() {
    # Do not start if there is no config file.
    [ -f "$IPTABLES_DATA" ] || return 1

    log_daemon_msg "Applying $IPTABLES firewall rules"

    OPT=
    [ "x$IPTABLES_SAVE_COUNTER" = "xyes" ] && OPT="-c"

    $IPTABLES-restore $OPT $IPTABLES_DATA
    if [ $? -eq 0 ]; then
        log_end_msg 0
    else
        log_end_msg 1; return 1
    fi
    
    # Load additional modules (helpers)
    if [ -n "$IPTABLES_MODULES" ]; then
	echo -n "Loading additional $IPTABLES modules"
	ret=0
	for mod in $IPTABLES_MODULES; do
	    echo -n "$mod "
	    modprobe $mod > /dev/null 2>&1
	    let ret+=$?;
	done
	[ $ret -eq 0 ] && log_end_msg 0 || log_end_msg 1
    fi
    
    touch $VAR_SUBSYS_IPTABLES
    return $ret
}

stop() {
    # Do not stop if iptables module is not loaded.
    [ -e "$PROC_IPTABLES_NAMES" ] || return 1

    flush_n_delete
    set_policy ACCEPT
    
    if [ "x$IPTABLES_MODULES_UNLOAD" = "xyes" ]; then
	echo -n "Unloading $IPTABLES modules"
	ret=0
	rmmod_r ${IPV}_tables
	let ret+=$?;
	rmmod_r ${IPV}_conntrack
	let ret+=$?;
	[ $ret -eq 0 ] && log_end_msg 0 || log_end_msg 1
    fi
    
    rm -f $VAR_SUBSYS_IPTABLES
    return $ret
}

save() {
    # Check if iptable module is loaded
    [ ! -e "$PROC_IPTABLES_NAMES" ] && return 1

    # Check if firewall is configured (has tables)
    tables=`cat $PROC_IPTABLES_NAMES 2>/dev/null`
    [ -z "$tables" ] && return 1

    echo -n "Saving firewall rules to $IPTABLES_DATA"

    OPT=
    [ "x$IPTABLES_SAVE_COUNTER" = "xyes" ] && OPT="-c"

    ret=0
    TMP_FILE=`/bin/mktemp -q /tmp/$IPTABLES.XXXXXX` \
	&& chmod 600 "$TMP_FILE" \
	&& $IPTABLES-save $OPT > $TMP_FILE 2>/dev/null \
	&& size=`stat -c '%s' $TMP_FILE` && [ $size -gt 0 ] \
	|| ret=1
    if [ $ret -eq 0 ]; then
	if [ -e $IPTABLES_DATA ]; then
	    cp -f $IPTABLES_DATA $IPTABLES_DATA.save \
		&& chmod 600 $IPTABLES_DATA.save \
		|| ret=1
	fi
	if [ $ret -eq 0 ]; then
	    cp -f $TMP_FILE $IPTABLES_DATA \
		&& chmod 600 $IPTABLES_DATA \
	        || ret=1
	fi
    fi
    [ $ret -eq 0 ] && log_end_msg 0 || log_end_msg 1
    echo
    rm -f $TMP_FILE
    return $ret
}

status() {
    tables=`cat $PROC_IPTABLES_NAMES 2>/dev/null`

    # Do not print status if lockfile is missing and iptables modules are not 
    # loaded.
    # Check if iptable module is loaded
    if [ ! -f "$VAR_SUBSYS_IPTABLES" -a -z "$tables" ]; then
	echo "Firewall is stopped."
	return 1
    fi

    # Check if firewall is configured (has tables)
    if [ ! -e "$PROC_IPTABLES_NAMES" ]; then
	echo "Firewall is not configured. "
	return 1
    fi
    if [ -z "$tables" ]; then
	echo "Firewall is not configured. "
	return 1
    fi

    NUM=
    [ "x$IPTABLES_STATUS_NUMERIC" = "xyes" ] && NUM="-n"
    VERBOSE= 
    [ "x$IPTABLES_STATUS_VERBOSE" = "xyes" ] && VERBOSE="--verbose"
    COUNT=
    [ "x$IPTABLES_STATUS_LINENUMBERS" = "xyes" ] && COUNT="--line-numbers"

    for table in $tables; do
	echo "Table: $table"
	$IPTABLES -t $table --list $NUM $VERBOSE $COUNT && echo
    done

    return 0
}

restart() {
    [ "x$IPTABLES_SAVE_ON_RESTART" = "xyes" ] && save
    stop
    start
}

case "$1" in
    start)
	stop
	start
	RETVAL=$?
	;;
    stop)
	[ "x$IPTABLES_SAVE_ON_STOP" = "xyes" ] && save
	stop
	RETVAL=$?
	;;
    restart)
	restart
	RETVAL=$?
	;;
    condrestart)
	[ -e "$VAR_SUBSYS_IPTABLES" ] && restart
	;;
    status)
	status
	RETVAL=$?
	;;
    panic)
	flush_n_delete
	set_policy DROP
	RETVAL=$?
        ;;
    save)
	save
	RETVAL=$?
	;;
    *)
	echo "Usage: $0 {start|stop|restart|condrestart|status|panic|save}"
	exit 1
	;;
esac

exit $RETVAL

Sowit so gut:
Das ganze sieht in der Console folgendermasßen aus:
IPTables -L

Code:
Chain INPUT (policy DROP)
target     prot opt source               destination
fail2ban-ssh  tcp  --  anywhere             anywhere            tcp dpt:ssh
LOG        all  --  anywhere             anywhere            state INVALID limit: avg 2/sec burst 5 LOG level warning prefix `INPUT INVALID '
DROP       all  --  anywhere             anywhere            state INVALID
MY_DROP    tcp  --  anywhere             anywhere            tcp flags:FIN,SYN,RST,PSH,ACK,URG/NONE
MY_DROP    tcp  --  anywhere             anywhere            tcp flags:FIN,SYN/FIN,SYN
MY_DROP    tcp  --  anywhere             anywhere            tcp flags:SYN,RST/SYN,RST
MY_DROP    tcp  --  anywhere             anywhere            tcp flags:FIN,RST/FIN,RST
MY_DROP    tcp  --  anywhere             anywhere            tcp flags:FIN,ACK/FIN
MY_DROP    tcp  --  anywhere             anywhere            tcp flags:PSH,ACK/PSH
MY_DROP    tcp  --  anywhere             anywhere            tcp flags:ACK,URG/URG
ACCEPT     all  --  anywhere             anywhere
ACCEPT     all  --  anywhere             anywhere            state RELATED,ESTABLISHED
ACCEPT     tcp  --  anywhere             anywhere            state NEW tcp dpt:www
ACCEPT     tcp  --  anywhere             anywhere            state NEW tcp dpt:https
ACCEPT     tcp  --  anywhere             anywhere            state NEW tcp dpt:ssh
ACCEPT     tcp  --  anywhere             anywhere            state NEW tcp dpt:mysql
MY_REJECT  all  --  anywhere             anywhere

Chain FORWARD (policy DROP)
target     prot opt source               destination

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination
LOG        all  --  anywhere             anywhere            state INVALID limit: avg 2/sec burst 5 LOG level warning prefix `OUTPUT INVALID '
DROP       all  --  anywhere             anywhere            state INVALID
ACCEPT     all  --  anywhere             anywhere
ACCEPT     all  --  anywhere             anywhere            state NEW,RELATED,ESTABLISHED
MY_REJECT  all  --  anywhere             anywhere

Chain MY_DROP (7 references)
target     prot opt source               destination
LOG        all  --  anywhere             anywhere            limit: avg 2/sec burst 5 LOG level warning prefix `PORTSCAN DROP '
DROP       all  --  anywhere             anywhere

Chain MY_REJECT (2 references)
target     prot opt source               destination
LOG        tcp  --  anywhere             anywhere            limit: avg 2/sec burst 5 LOG level warning prefix `REJECT TCP '
REJECT     tcp  --  anywhere             anywhere            reject-with tcp-reset
LOG        udp  --  anywhere             anywhere            limit: avg 2/sec burst 5 LOG level warning prefix `REJECT UDP '
REJECT     udp  --  anywhere             anywhere            reject-with icmp-port-unreachable
LOG        icmp --  anywhere             anywhere            limit: avg 2/sec burst 5 LOG level warning prefix `DROP ICMP '
DROP       icmp --  anywhere             anywhere
LOG        all  --  anywhere             anywhere            limit: avg 2/sec burst 5 LOG level warning prefix `REJECT OTHER '
REJECT     all  --  anywhere             anywhere            reject-with icmp-proto-unreachable
Chain fail2ban-ssh (1 references)
target     prot opt source               destination
DROP       all  --  server.domain.de  anywhere
RETURN     all  --  anywhere             anywhere

Wie man hier im unteren Teil sieht habe ich bereits die Fail2ban Chan mit eingebaut...

Wenn ich jetzt Fail2ban starte / restarte...

Dann wird aus:
Code:
Chain fail2ban-ssh (1 references)
target     prot opt source               destination
DROP       all  --  server.domain.de  anywhere
RETURN     all  --  anywhere             anywhere

das hier:
Code:
Chain fail2ban-SSH (1 references)
target     prot opt source               destination
RETURN     all  --  anywhere             anywhere

Chain fail2ban-apache (1 references)
target     prot opt source               destination
RETURN     all  --  anywhere             anywhere

Chain fail2ban-ssh (2 references)
target     prot opt source               destination
RETURN     all  --  anywhere             anywhere

Wie man hier deutlich erkennen kann werden die Rules überschrieben und Fail2ban setzt die eigenen rules..

ich denke das liegt daran weil im ordner:
/etc/fail2ban/action.d
ebenfalls iptables confs herumliegen und Fail2ban auf diese zugreift ...

Meine frage an dieser Stelle lautet.. wie bekomme ich Fail2ban dazu das er die richtige Fail2ban IPtables nutzt? Also sprich diese eine locale datei in /etc/default? Und wie stelle ich Fail2ban ein das er auch diese Iptables für die Rules verwendet...

Ich weiss das es ungefähr so aussehen müsste:
[fail2ban-ssh]
enabled = true
filter = sshd
action = iptables[name=SSH, port=ssh, protocol=tcp]
sendmail-whois[name=SSH, dest=webmaster@domain.de, sender=fail2ban@domain.de]
logpath = /var/log/sshd.log
maxretry = 3

Kann mir hier wer weiterhelfen wie das richtig sein müsste.. oder gar helfen das ganze zu optimieren / tunen ... wei gesagt das ist selbstgeschrieben und mein 1. Versuch :P nach unzähligen HOWTO´s
 
Back
Top