#!/bin/bash
#
#####################################################
# Firewall Script v3.1 by Marc Heuse <marc@suse.de> #
#####################################################
VER="v3.1"
#
# For all those fellow experts out there: yes I know that this is NOT a 
# firewall setup but a simple (no, not simple, it tries actually to be
# clever) packet filter. But if we would call this "SuSEpacketfilter",
# only a few user would install it, hence general security would be bad.
#
###########################################################################
#                                                                         #
# The configuration file for this firewall script is                      #
# /etc/sysconfig/SuSEfirewall2                                            #
#                                                                         #
# Please make only modifications to this script if you know what you      #
# are doing! A small explanation of the setup can be found in             #
# /usr/share/doc/packages/SuSEfirewall2/README                            #
#                                                                         #
# For new-user help concerning configuring this firewall, take a look at  #
# the configuration file /etc/sysconfig/SuSEfirewall2 - it tells          #
# you all                                                                 #
# (if not: sorry, but configuring a packet filter/screening router is NOT #
# trivial - you must know what you are doing and what it actually does!)  #
#                                                                         #
###########################################################################

help() {
    echo -e "
SuSEfirewall2 $VER (c)2002 by Marc Heuse <marc@suse.de> http://www.suse.de/~marc
Smart and tight packet filter rules generator for 2.4 kernels using iptables.

$0 start|test|debug [file FILENAME] [force]
$0 stop|close|status|help

Options:
  start	  generate and load the firewall filter rules from 
          /etc/sysconfig/SuSEfirewall2
  stop    unload all filter rules
  close   no incoming network traffic except bootp+ping (for boot security)
  easy    set easy filter rules which rejects all incoming access
  test    generate and load the filter rules but do not drop any packet but log
          to syslog anything which *would* be denied
  status  print the output of \"iptables -L -nv\"
  debug   print the iptables command to stdout instead of executing them
  help    this output

  file FILENAME  same as \"start\" but load alternate config file FILENAME

Calling $0 without any option is the same as the \"start\" option.
The \"file FILENAME\" option my be used with the start, test and debug options.\n"
#old#  force   force starting (does not check /etc/rc.config for START_FW2=yes)
    exit 0
}

FWCONFIG="/etc/sysconfig/SuSEfirewall2"
PERSFWCONFIG="/etc/sysconfig/personal-firewall"
LOCKFILE="/var/lock/SuSEfirewall2.pid"
FW_CUSTOMRULES=""

test "$1" = "-h" -o "$1" = help && help
test -z "$2" -a "$1" = file && help
test -z "$3" -a "$2" = file && help
test -z "$4" -a "$3" = file && help
test "$1" = file && FWCONFIG="$2"
test "$2" = file && FWCONFIG="$3"
test "$3" = file && FWCONFIG="$4"

test -e /etc/rc.config && . /etc/rc.config

test -z "$1" -o "$1" = easy -o "$1" = novice -o "$1" = force -o "$1" = file -o "$1" = stop -o "$1" = start -o "$1" = test -o "$1" = debug && {
    test -e /etc/sysconfig/network/config && . /etc/sysconfig/network/config

    test -e "$FWCONFIG" -o "$1" = easy || { 
        echo "SuSEfirewall2: Can not find $FWCONFIG, aborting ..."
        exit 6
    }
    test "$1" = easy || . $FWCONFIG

# SuSEpersonal-firewall legacy support. Allow for a single-variable configuration,
# according to /etc/sysconfig/personal-firewall.
test -e $PERSFWCONFIG && . $PERSFWCONFIG
REJECT_ALL_INCOMING_CONNECTIONS=`echo $REJECT_ALL_INCOMING_CONNECTIONS`
if [ -z "$REJECT_ALL_INCOMING_CONNECTIONS" ]; then
    REJECT_ALL_INCOMING_CONNECTIONS="no"
fi
if [ "$REJECT_ALL_INCOMING_CONNECTIONS" = "no" ]; then
    :		# do nothing.
else
    # values for REJECT_ALL_INCOMING_CONNECTIONS override settings
    # for SuSEfirewall2 from $FWCONFIG
    # first check if "modem" is selected, and provide wildcard "ppp+"
    # also check if we should do masquerading.
    RAIC=""
    for iname in $REJECT_ALL_INCOMING_CONNECTIONS; do
	case "$iname" in
	    masq|MASQ)
		PFW_MASQ=yes
		;;
	    modem)
		RAIC="$RAIC ppp+"
		PFW_HAVE_IFACE=yes
		;;
	    all|ALL) # not supported any more. We need a list.
		{
		echo "You have set \$REJECT_ALL_INCOMING_CONNECTIONS to the"
		echo "value \"all\". This is not supported any more."
		echo "Please provide interface names in a space-seperated"
		echo "list in /etc/sysconfig/personal-firewall or go through"
		echo "the configuration of SuSEfirewall2 (the file is"
		echo "/etc/sysconfig/SuSEfirewall2)."
		} | logger -s -t "SuSEfirewall2" -p err 
		exit 1
		;;
	    *)
		RAIC="$RAIC $iname"
		PFW_HAVE_IFACE=yes
		;;
	esac
    done
    REJECT_ALL_INCOMING_CONNECTIONS="$RAIC"

    # we have an interface, unless only "masq" is stated. Use the default route iface.
    if [ "$PFW_HAVE_IFACE" = "" ]; then
	FW_DEV_EXT=`/sbin/ip route show | $AWK '/^default / { print $5 ;} { next; }'`
    else
	FW_DEV_EXT="$REJECT_ALL_INCOMING_CONNECTIONS"
    fi
    if [ "$PFW_MASQ" = yes ]; then
	FW_MASQ_DEV="$FW_DEV_EXT"
    fi

    FW_QUICKMODE=yes
fi


#    test "$START_FW2" = yes -o "$1" = easy -o "$1" = stop -o "$1" = status \
#          -o "$1" = close -o "$1" = force -o "$2" = force -o "$3" = force \
#          -o "$4" = force || {
#        echo -e "
#SuSEfirewall2 is not activated yet. If you want to force loading the rules, add
#the command line option \"force\". To configure SuSEfirewall2, edit
#/etc/rc.config.d/firewall2.rc.config & set START_FW2 in /etc/rc.config to \"yes\".
#"
#        exit 1
#    }

    test -z "$FW_DEV_WORLD" -a -z "$FW_AUTOPROTECT_GLOBAL_SERVICES" -a -z "$FW_LOG_DENY_CRIT" || {
        echo -e "Error: This is SuSEfirewall2, $FWCONFIG is for the old SuSEfirewall/firewals package."
        exit 1
    }
}

test "$1" = force && shift
test "$1" = file && { shift; shift; }
test "$1" = force && shift

#######################
#                     #
# Definitions - fixed #
#                     #
#######################
export LC_CTYPE=en_US
export LANGUAGE=english
export RC_LANG=en_US
export LANG=en_US
export RC_LC_ALL=en_US
export RC_LC_MESSAGES=""
export LC_ALL=en_US
export PATH="/sbin:/bin:/usr/sbin:/usr/bin"
alias which='type -p'
IPTABLES=`which iptables`  || IPTABLES="/usr/sbin/iptables"
#IPTABLES="echo iptables "                                 # For debugging only
DEBUG="echo iptables "
IP6TABLES=`which ip6tables`  || IP6TABLES="/usr/sbin/iptables"
#IPTABLES="echo ip6tables "                                 # For debugging only
DEBUG6="echo ip6tables "
AWK=`which awk`            || AWK="/usr/bin/awk"
SED=`which sed`            || SED="/usr/bin/sed"
IFCONFIG=`which ifconfig`  || IFCONFIG="/sbin/ifconfig"
NETSTAT=`which netstat`    || NETSTAT="/bin/netstat"
SORT=`which sort`	   || SORT="/usr/bin/sort"
LSOF=`which lsof`	   || LSOF="/usr/bin/lsof"
LOGGER=`which logger`	   || LOGGER="/usr/bin/logger"
GREP=`which grep`          || GREP="/usr/bin/grep"
TC=`which tc`              || TC="/usr/sbin/tc"

for i in "$GREP" "$AWK" "$SED" "$IFCONFIG" "$NETSTAT" "$SORT"; do
    test -x $i || { echo "I need $i for running but can not find it, aborting."
                    exit 1 ; }
done

test -z `uname -r | $GREP -E '^2\.[3456]' 2> /dev/null` && {
    echo 'This script is for Linux 2.3--2.6 kernels only!'
    exit 1
}

NEED_LSOF=no
test "$FW_SERVICE_DNS" = "yes" -o "$FW_SERVICE_DNS" = "dmz" -o "$FW_SERVICE_DNS" = "ext" && NEED_LSOF=yes
test "$FW_SERVICE_SQUID" = "yes" -o "$FW_SERVICE_SQUID" = "dmz" -o "$FW_SERVICE_SQUID" = "ext" && NEED_LSOF=yes
test "$NEED_LSOF" = yes -a '!' -x "$LSOF" && { 
    echo "I need $LSOF for running but can not find it, aborting."
    exit 1 ; }
test -x "$IPTABLES" -o "$IPTABLES" = "echo iptables " || \
    echo "Warning: Can not find iptables - debug function? (\"$IPTABLES\")"
test -x "$IP6TABLES" -o "$IP6TABLES" = "echo ip6tables " || \
    echo "Warning: Can not find ip6tables - debug function? (\"$IP6TABLES\")"

ACCEPT="ACCEPT"
DROP="DROP"
REJECT="reject_func"
test "$FW_REJECT" = yes && DROP="reject_func"

#############
#           #
# Functions #
#           #
#############
function reset_rules_silent() {
	test "$FW_STOP_KEEP_ROUTING_STATE" = "yes" || {
	    echo 0 > /proc/sys/net/ipv4/ip_forward
	} > /dev/null 2>&1
	$IPTABLES -F INPUT
	$IPTABLES -F OUTPUT
	$IPTABLES -F FORWARD
	$IPTABLES -P INPUT ACCEPT
	$IPTABLES -P OUTPUT ACCEPT
	$IPTABLES -P FORWARD ACCEPT
	$IPTABLES -F
	$IPTABLES -X
	$IPTABLES -t nat -F
	$IPTABLES -t nat -X
	$IPTABLES -t mangle -F
	$IPTABLES -t mangle -X

	$IP6TABLES -F INPUT
	$IP6TABLES -F OUTPUT
	$IP6TABLES -F FORWARD
	$IP6TABLES -P INPUT ACCEPT
	$IP6TABLES -P OUTPUT ACCEPT
	$IP6TABLES -P FORWARD ACCEPT
	$IP6TABLES -F
	$IP6TABLES -X
	$IP6TABLES -t mangle -F
	$IP6TABLES -t mangle -X

#	{ rmmod ipt_TCPMSS ipt_TOS ipt_MASQUERADE ipt_LOG ipt_state \
#	   ipt_MARK ipt_MIRROR ipt_REDIRECT ipt_limit ipt_mac ipt_mark \
#	   ipt_multiport ipt_owner ipt_tcpmss ipt_tos ipt_unclean ip_queue \
#	   ip_nat_ftp ip_conntrack_ftp ipt_REJECT iptable_mangle iptable_nat \
#	   iptable_filter ip_queue ip_conntrack iptable_filter ip_tables \
#          ip6t_REJECT ip6table_mangle ip6table_filter
#	} > /dev/null 2> /dev/null
}

clear_qdisc_settings() {
    for DEVICE_DATA in $FW_HTB_TUNE_DEV; do
        IFS="," read DEV BANDWIDTH < <(echo "$DEVICE_DATA")
        $TC qdisc del dev $DEV root 2> /dev/null
    done
}

function reset_rules() {
	echo -n "SuSEfirewall2: clearing rules now ..."
	reset_rules_silent
        clear_qdisc_settings
	echo " done"
}

function set_basic_rules() {
    { rmmod ipfwadm; rmmod ipchains
      modprobe ip_tables; modprobe ip_conntrack; modprobe ip_conntrack_ftp
      modprobe ip_nat_ftp
      modprobe ip6table_filter ip6table_mangle
    } > /dev/null 2>&1
    test "$DROP" = ACCEPT && DROP_JUMP="ACCEPT"
    test "$DROP" = ACCEPT || DROP_JUMP="DROP"
    $IPTABLES -F INPUT
    $IPTABLES -F OUTPUT
    $IPTABLES -F FORWARD             2> /dev/null
    $IPTABLES -P INPUT "$DROP_JUMP"
    $IPTABLES -P OUTPUT "$ACCEPT"
    $IPTABLES -P FORWARD "$DROP_JUMP"     2> /dev/null
    $IPTABLES -F
    $IPTABLES -X
    # Special REJECT function #
    $IPTABLES -t nat -F
    $IPTABLES -t nat -X
    $IPTABLES -t mangle -F
    $IPTABLES -t mangle -X
    $IPTABLES -N reject_func
    $IPTABLES -A reject_func -p tcp -j REJECT --reject-with tcp-reset
    $IPTABLES -A reject_func -p udp -j REJECT --reject-with icmp-port-unreachable
    $IPTABLES -A reject_func        -j REJECT --reject-with icmp-proto-unreachable

    $IP6TABLES -F INPUT
    $IP6TABLES -F OUTPUT
    $IP6TABLES -F FORWARD             2> /dev/null
    $IP6TABLES -P INPUT "$DROP_JUMP"
    $IP6TABLES -P OUTPUT "$DROP_JUMP"
    $IP6TABLES -P FORWARD "$DROP_JUMP"     2> /dev/null
    $IP6TABLES -F
    $IP6TABLES -X
    # Special REJECT function #
    $IP6TABLES -t mangle -F
    $IP6TABLES -t mangle -X
    $IP6TABLES -N reject_func
    $IP6TABLES -A reject_func -p tcp -j REJECT --reject-with tcp-reset
    $IP6TABLES -A reject_func -p udp -j REJECT --reject-with port-unreach
    $IP6TABLES -A reject_func        -j REJECT --reject-with addr-unreach # know anything better?

    $IP6TABLES -A INPUT  -j "$ACCEPT" -i lo
    $IP6TABLES -A OUTPUT -j "$ACCEPT" -o lo

    test -z "$LOG" && \
    	LOG="--log-level warning --log-tcp-options --log-ip-options --log-prefix SuSE-FW"
    # No state matching with IPv6 yet
    #$LAA $IP6TABLES -A INPUT -m state --state ESTABLISHED,RELATED -j LOG ${LOG}"-ACC-ALL "
    #$IP6TABLES -A INPUT -j "$ACCEPT" -m state --state ESTABLISHED,RELATED
    #$LAA $IP6TABLES -A OUTPUT -m state --state NEW,ESTABLISHED,RELATED -j LOG ${LOG}"-ACC-ALL "
    #$IP6TABLES -A OUTPUT -j ACCEPT -m state --state NEW,ESTABLISHED,RELATED

    # Drop all until IPv6 is really supported
    test -z "$LDC" -o -z "$LDA" && $IP6TABLES -A INPUT -j LOG ${LOG}"-IN-IPv6_PROHIB "
    $IP6TABLES -A INPUT -j "$DROP"
    test -z "$LDC" -o -z "$LDA" && $IP6TABLES -A OUTPUT -j LOG ${LOG}"-OUT-IPv6_PROHIB "
    $IP6TABLES -A OUTPUT -j "$DROP"

}

tos_settings() {
#mangle TOS with icmp does not seem to work. the 2.4 firewall still sucks
#    $IPTABLES -A OUTPUT -j TOS -m state --state NEW -t mangle -p icmp --icmp-type echo-request --set-tos Minimize-Delay # ping
#    $IPTABLES -A OUTPUT -j TOS -t mangle -p icmp --icmp-type echo-reply   --set-tos Minimize-Delay # pong
#    $IPTABLES -A OUTPUT -j TOS -t mangle -p icmp --set-tos Maximize-Reliability # all other ICMP
#    $IPTABLES -A OUTPUT -j TOS -m state --state NEW,ESTABLISHED,RELATED -t mangle -p tcp --sport 22   --set-tos Minimize-Delay # SSH in
#    $IPTABLES -A OUTPUT -j TOS -m state --state NEW,ESTABLISHED,RELATED -t mangle -p tcp --dport 22   --set-tos Minimize-Delay # SSH out
    $IPTABLES -A OUTPUT -j TOS -m state --state NEW,ESTABLISHED,RELATED -t mangle -p tcp --sport 20   --set-tos Maximize-Throughput # FTP Data
    $IPTABLES -A OUTPUT -j TOS -m state --state NEW,ESTABLISHED,RELATED -t mangle -p tcp --dport 20   --set-tos Maximize-Throughput # FTP Data
    $IPTABLES -A OUTPUT -j TOS -m state --state NEW,ESTABLISHED,RELATED -t mangle -p tcp --sport 80   --set-tos Maximize-Throughput # HTTP
    $IPTABLES -A OUTPUT -j TOS -m state --state NEW,ESTABLISHED,RELATED -t mangle -p tcp --dport 80   --set-tos Maximize-Throughput # HTTP
    $IPTABLES -A OUTPUT -j TOS -m state --state NEW,ESTABLISHED,RELATED -t mangle -p tcp --sport 53   --set-tos Minimize-Delay # DNS
    $IPTABLES -A OUTPUT -j TOS -m state --state NEW,ESTABLISHED,RELATED -t mangle -p udp --dport 53   --set-tos Minimize-Delay # DNS
    $IPTABLES -A OUTPUT -j TOS -m state --state NEW,ESTABLISHED,RELATED -t mangle -p udp --dport 161  --set-tos Maximize-Reliability # SNMP
    $IPTABLES -A OUTPUT -j TOS -m state --state NEW,ESTABLISHED,RELATED -t mangle -p udp --dport 162  --set-tos Maximize-Reliability # SNMP Trap
    $IPTABLES -A OUTPUT -j TOS -t mangle -p udp --dport 514  --set-tos Maximize-Reliability # Syslog
    #$IPTABLES -A OUTPUT -j TOS -m state --state NEW,ESTABLISHED,RELATED -t mangle -p udp --set-tos Maximize-Reliability # all UDP
}

#
# tune the upload stream a little bit
# with DSL for example, you have the problem, that your
# downstream collapses if your upstream is full.
# After this tuning this should not happen anymore.
# interactive SSH and VPN are faster too, because they
# get some extra bandwidth besides the bulk traffic
#
# variabel from sysconfig:
#   FW_HTB_TUNE_DEV="DEV1,BANDWIDTH1 DEV2,BANDWIDTH2 ..."
#
# any questions about this to uwe.gansert@suse.de
#
do_qdisc_settings() {
    if [ -n "$FW_HTB_TUNE_DEV" ]; then
	modprobe sch_htb 2> /dev/null
    fi

    for DEVICE_DATA in $FW_HTB_TUNE_DEV; do
        IFS="," read DEV BANDWIDTH < <(echo "$DEVICE_DATA")

        # sanity check
        if [ -n "$DEV" -a -n "$BANDWIDTH" ]; then
            # reserve 10% for small packets (TCP ACK),
            # interactive SSH from and to us and DNS querys.
            # We don't need too much bandwidth but we need it fast.
            SMALL_PACKET_BW=$(( $BANDWIDTH / 10 ))
            if [ "$SMALL_PACKET_BW" -eq 0 ]; then
                echo "Warning: illegal bandwidth settings for $DEV in FW_HTB_TUNE_DEV"
            fi

            # reserve 25% for VPN traffic. Never mind if we don't have
            # a VPN. No bandwidth will be wasted
            VPN_BW=$(( $BANDWIDTH / 4 ))
            if [ "$VPN_BW" -eq 0 ];then
                echo "Warning: illegal bandwidth settings for $DEV in FW_HTB_TUNE_DEV"
            fi

            # bulk traffic
            REST_BW=$(( ${BANDWIDTH}-${SMALL_PACKET_BW}-${VPN_BW} ))

            $TC qdisc add dev $DEV root handle 1:0 htb default 20       # adding the queing discipline

	    # adding the root class 1:1
            $TC class add dev $DEV parent 1:0 classid 1:1 htb \
                rate ${BANDWIDTH}kbit ceil ${BANDWIDTH}kbit

            # class for small tcp packets 1:10
            $TC class add dev $DEV parent 1:1 classid 1:10 htb \
                rate ${SMALL_PACKET_BW}kbit ceil ${BANDWIDTH}kbit prio 0 # and interactive SSH
	    # class for VPN traffic       1:11
            $TC class add dev $DEV parent 1:1 classid 1:11 htb \
                rate ${VPN_BW}kbit ceil ${BANDWIDTH}kbit prio 1
	    # class for all the rest      1:20
            $TC class add dev $DEV parent 1:1 classid 1:20 htb \
                rate ${REST_BW}kbit ceil ${BANDWIDTH}kbit prio 2
	    # packets, marked with "10" to queue 1:10
            $TC filter add dev $DEV parent 1:0 prio 0 protocol ip \
                handle 10 fw flowid 1:10
	    # packets, marked with "11" to queue 1:11
            $TC filter add dev $DEV parent 1:0 prio 1 protocol ip \
                handle 11 fw flowid 1:11

	    # iptables marks small TCP packets (potentially ACK)
	    # with 10, so "tc" will send them to queue 1:10
            $IPTABLES -A POSTROUTING -t mangle -o $DEV -p tcp \
                      -m length --length :64 -j MARK --set-mark 10

	    # iptables marks SSH interactive ssh traffic
	    # with 10 too. So it gets to queue 1:10 like
            $IPTABLES -A POSTROUTING -t mangle -o $DEV -p tcp \
                      -m tos --tos Minimize-Delay \
                      -m tcp --dport 22 -j MARK --set-mark 10

	    # like the rule above, but this time we are
	    # the sshd and want to respond fast, even when
            $IPTABLES -A POSTROUTING -t mangle -o $DEV -p tcp \
                      -m tos --tos Minimize-Delay \
                      -m tcp --sport 22 -j MARK --set-mark 10 

            # same like above for DNS
            $IPTABLES -A POSTROUTING -t mangle -o $DEV -p udp \
                      -m udp --dport 53 -j MARK --set-mark 10
            $IPTABLES -A POSTROUTING -t mangle -o $DEV -p tcp \
                      -m tcp --dport 53 -j MARK --set-mark 10

	    # iptables marks VPN traffic with 11
	    # if we don't have VPN, never mind, no bandwidth
	    # will be wastet and if we need more, then it'll be
	    # be "borrowed" from the other queues
            $IPTABLES -A POSTROUTING -t mangle -o $DEV -p 50 \
                      -j MARK --set-mark 11
 
        else
            echo "Warning: illegal settings in FW_HTB_TUNE_DEV=\"$FW_HTB_TUNE_DEV\""
            echo "         skipped device \"$DEV\""
        fi
    done
}



faulty_int() {
    test -z "$DEV" || {
	case "$DEV" in
	    *ppp*) ;;
	    *) echo -en "\n Warning: interface $DEV is not (yet?) active."
		 ;;
	esac
    }
}

function check_srv() {
    RLVL=`/sbin/runlevel | sed 's/^. //'`
    test -L /etc/init.d/rc${RLVL}.d/S??$1 && return 0
    return 1
}

#############################################
# Get device info via ifconfig and parse it #
#############################################
function getdevinfo() {
    DEVNM=$1
    DEV_TMP=`$IFCONFIG $DEVNM 2>/dev/null`
    DEV_IP=${DEV_TMP##*inet addr:}
    DEV_IP=${DEV_IP%% *}
    DEV_MASK=${DEV_TMP##*ask:}
    DEV_MASK=${DEV_MASK%% *}
    DEV_BCAST=${DEV_TMP##*cast:}
    DEV_BCAST=${DEV_BCAST%% *}
    test "$DEV_IP" = "$DEVNM" && DEV_IP=""
    test "$DEV_MASK" = "$DEVNM" && DEV_MASK=""
    test "$DEV_BCAST" = "$DEVNM" && DEV_BCAST=""
    #DEV_IP="`$IFCONFIG $DEVNM  2>/dev/null|$AWK '/inet addr:/ {print $2}'|$SED 's/addr://'`"
    #DEV_MASK=`$IFCONFIG $DEVNM 2>/dev/null|$AWK '/ Mask:/ {print $4}'|$SED 's/Mask://'`
    #DEV_BCAST=`$IFCONFIG $DEVNM 2>/dev/null|$AWK '/cast:/ {print $3}'|$SED 's/.*cast://'`
    #test -z "$DEV_MASK" && DEV_MASK=`$IFCONFIG $DEVNM 2>/dev/null|$AWK '/ Mask:/ {print $3}'|$SED 's/Mask://'`
}


# Provide empty functions for transparent hook support for customised rules
fw_custom_before_antispoofing() { true; }
fw_custom_after_antispoofing() { true; }
fw_custom_before_port_handling() { true; }
fw_custom_before_masq() { true; }
fw_custom_before_denyall() { true; }

#####################
#                   #
# Locking mechanism #
#                   #
#####################
test -e "$LOCKFILE" && {
    PID=`cat $LOCKFILE`
    $LOGGER -p kern.info -t SuSEfirewall2 "Another SuSEfirewall2 with PID $PID found, waiting ..."
    I=0
    LOCK=1
    while [ "$LOCK" = 1 ]; do
	sleep 2
	test -e "$LOCKFILE" || LOCK=0
	I=$(( $I + 1 ))
	test "$I" = 15 && LOCK=0
    done
    test -e "$LOCKFILE" && {
	$LOGGER -p kern.info -t SuSEfirewall2 "Lockfile is still there, ignoring it ..."
	kill -TERM $PID
	sleep 2
	kill -KILL $PID
	rm -f "$LOCKFILE"
    }
}
trap "rm -f $LOCKFILE" 0 1 2 3 13 15
set -o noclobber
echo "$$" > $LOCKFILE || exit 1
set +o noclobber

# Set NAMESERVER variable
test -e /etc/resolv.conf && NAMESERVERS=`$AWK '/^nameserver/ {print $2}' /etc/resolv.conf| \
    $GREP -iv yast 2> /dev/null`

# Do we have a kernel with IPv6 enabled?
$IP6TABLES -nvL >/dev/null 2>&1 || IP6TABLES=false

##########################
#                        #
# Parse the Command line #
#                        #
##########################
# KG: FIXME: Shouldn't this be removed and just set FW_QUICKMODE=yes instead ?
test "$1" = easy -o "$1" = novice && {
    # Reset the filter rules
    set_basic_rules

    # Setting filter rules
    # 1. allow anything on localhost interface
    $IPTABLES -A INPUT -j "$ACCEPT" -i lo
    # 2. allow anything which is esablished or related
    $IPTABLES -A INPUT -j "$ACCEPT" -m state --state ESTABLISHED,RELATED
    # 3. allow dhcp replies from servers
    $IPTABLES -A INPUT -j "$ACCEPT" -p udp --sport 67 -d 255.255.255.255/32 --dport 68
    # 4. allow echo requests
    $IPTABLES -A INPUT -j "$ACCEPT" -p icmp --icmp-type echo-request

    # Special DNS hack to prevent timeouts
    test -n "$NAMESERVERS" && for k in $NAMESERVERS; do
        test "$k" = 127.0.0.1 || \
            $IPTABLES -A INPUT -j "$ACCEPT" -m state --state NEW -p udp -s $k --sport 53 --dport 1024:65535
    done

    # log incoming tcp connection requests
    $IPTABLES -A INPUT -j LOG -p tcp --syn --log-level warning --log-tcp-options --log-ip-options --log-prefix "SuSE-FW-DROP-NEW-CONNECT "
    # reject anything else
    $IPTABLES -A INPUT -j "$REJECT"

    # Optimise your TCP/UDP connections by setting IP Options!
    tos_settings
    do_qdisc_settings

    $IPTABLES -A OUTPUT -j ACCEPT -m state --state NEW,ESTABLISHED,RELATED

# Log entry
    test -x "$LOGGER" && \
        $LOGGER -p kern.info -t SuSEfirewall2 "Firewall rules successfully set in EASY mode"
    exit 0
}

test "$1" = test && {
    DROP="ACCEPT"
    REJECT="ACCEPT"
    FW_LOG_DROP_ALL=yes
    FW_LOG_DROP_CRIT=yes
    FW_LOG_ACCEPT_ALL=no
    FW_LOG_ACCEPT_CRIT=no
    echo -e '
Warning: SuSEfirewall2 is running in TEST MODE, no packet filtering is done!
\007'
    test -x "$LOGGER" && \
	$LOGGER -p kern.info -t SuSEfirewall2 "Firewall set in TEST mode."
}
test "$1" = debug && {
    IPTABLES="$DEBUG"
    IP6TABLES="$DEBUG6"
}
test "$1" = stop -o "$1" = halt -o "$1" = down -o "$1" = shutdown && {
    echo -n "Removing filter rules "
    test "$FW_STOP_KEEP_ROUTING_STATE" = "yes" && echo "..."
    test "$FW_STOP_KEEP_ROUTING_STATE" = "yes" || \
	echo "and disabling IP forwarding ..."
#    { rmmod ipfwadm; rmmod ipchains; rmmod ip_tables; } > /dev/null 2>&1
    { rmmod ipfwadm; rmmod ipchains; } > /dev/null 2>&1
    reset_rules
    # Log entry
    test -x "$LOGGER" && \
	$LOGGER -p kern.info -t SuSEfirewall2 "Firewall rules unloaded."
    exit 0
}
test "$1" = close && {
    set_basic_rules
    { echo 0 > /proc/sys/net/ipv4/ip_forward 2> /dev/null ; } > /dev/null 2>&1
    $IPTABLES -A INPUT -j ACCEPT -p udp --sport 67 -d 255.255.255.255/32 --dport 68
    $IPTABLES -A INPUT -j ACCEPT -p icmp --icmp-type echo-request
    $IPTABLES -A INPUT -j ACCEPT -i lo
    $IPTABLES -A INPUT -j "$REJECT"
    test -x "$LOGGER" && \
	$LOGGER -p kern.info -t SuSEfirewall2 "Firewall rules set to CLOSE all network traffic."
    exit 0
}
test "$1" = status && {
    $IPTABLES -L -nv
    $IPTABLES -t nat -L -nv
    $IPTABLES -t mangle -L -nv
    exit 0
}
test "$1" = check && {
#   test -x /usr/sbin/openports -a -x /usr/sbin/ip && {
#    for i in 20 53 2000; do
#	/usr/sbin/openports 1.1.1.1 $i
#    done
#   } | $GREP -Ev "^| denied " | $SORT -u
#    exit 0
    echo "The option \"check\" is no longer supported with SuSEfirewall2 because this functionality does not work with iptables :-("
    exit 1
}
test "$1" = start -o "$1" = test -o -z "$1" -o "$1" = debug || {
    echo -e "Error: unknown option $1. Try \"$0 help\"."
    exit 1
}

###################
# Important check #
###################
test -z "$FW_DEV_EXT" && {
    echo -e "\n The Firewall script needs to know the external (internet) interface."
    echo -en " Set FW_DEV_EXT in $FWCONFIG"
    reset_rules
    exit 6
}

########################################################################
#                                                                      #
# If FW_QUICKMODE is set to yes, we only have to set                   #
# some very basic rules. This is done here and then we exit gracefully #
#                                                                      #
########################################################################
test "$FW_QUICKMODE" = yes && {
    # Reset the filter rules
    set_basic_rules

    # Setting filter rules
    # 1. allow anything on localhost interface
    $IPTABLES -A INPUT -j "$ACCEPT" -i lo
    # 2. allow anything which is esablished or related
    $IPTABLES -A INPUT -j "$ACCEPT" -m state --state ESTABLISHED,RELATED
    # 3. allow dhcp replies from servers
    $IPTABLES -A INPUT -j "$ACCEPT" -p udp --sport 67 -d 255.255.255.255/32 --dport 68
    # 4. allow echo requests
    $IPTABLES -A INPUT -j "$ACCEPT" -p icmp --icmp-type echo-request

    # Special DNS hack to prevent timeouts
    test -n "$NAMESERVERS" && for k in $NAMESERVERS; do
        test "$k" = 127.0.0.1 || \
            $IPTABLES -A INPUT -j "$ACCEPT" -m state --state NEW -p udp -s $k --sport 53 --dport 1024:65535
    done


    # masquerading part 1
    test -z "$FW_MASQ_DEV" || {
	$IPTABLES -A INPUT -j "$ACCEPT" -m state --state ESTABLISHED -p udp --dport 61000:65095
        $IPTABLES -I FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu
	for i in $FW_MASQ_DEV; do
	  $IPTABLES -A FORWARD -j "$ACCEPT" -i $i -m state --state ESTABLISHED,RELATED
	done
    }

    # New chain for external input
    $IPTABLES -N input_ext
    $IPTABLES -A input_ext -j "$REJECT"
    # log incoming tcp connection requests
    $IPTABLES -I input_ext 1 -j LOG -p tcp --syn --log-level warning --log-tcp-options --log-ip-options --log-prefix "SuSE-FW-DROP-NEW-CONNECT "

    # now reject everything which is entering through insecure interfaces
    for i in $FW_DEV_EXT; do
	$IPTABLES -A INPUT -i $i -j input_ext
	$IPTABLES -A FORWARD -i $i -j "$REJECT"
    done
    
    # Apply settings from FW_SERVICE_QUICK_*
    # Note that we push the rules to the head of the chain; therefore the reversed order
    # UDP Stuff #
    for PORT in $FW_SERVICES_QUICK_UDP; do
	$IPTABLES -I input_ext 1 -j "$ACCEPT" -m state --state NEW,ESTABLISHED,RELATED -p udp --dport $PORT
    done
    # If port 113 (auth/identd) will not allowed below, outgoing mail would
    # be delayed most of the time. Hence we put a hardcoded reject line in.
    $IPTABLES -I input_ext 1 -j "$REJECT" -p tcp --dport 113 --syn 2> /dev/null
    # TCP Stuff #
    for PORT in $FW_SERVICES_QUICK_TCP; do
	$IPTABLES -I input_ext 1 -j "$ACCEPT" -m state --state NEW,ESTABLISHED,RELATED -p tcp --dport $PORT
    done
    # IP Stuff #
    for PROTO in $FW_SERVICES_QUICK_IP; do
	$IPTABLES -I input_ext 1 -j "$ACCEPT" -m state --state NEW,ESTABLISHED,RELATED -p $PROTO
    done 

    # masquerading part 2
    test -z "$FW_MASQ_DEV" || {
	for i in $FW_MASQ_DEV; do
            $IPTABLES -A FORWARD -j "$ACCEPT" -o $i
            $IPTABLES -A POSTROUTING -j MASQUERADE -t nat -o $i
	done
	echo 1 > /proc/sys/net/ipv4/ip_forward
	EXTRA=" plus masquerading"
    }

    # sadly we now have to open the rules :-(
    $IPTABLES -A INPUT -j "$ACCEPT"
#not sure if I should allow all routing ... hmmm better leaving this disabled
#$IPTABLES -A FORWARD -j "$ACCEPT"

    # Optimise your TCP/UDP connections by setting IP Options!
    tos_settings
    do_qdisc_settings

    $IPTABLES -A OUTPUT -j "$ACCEPT" -m state --state NEW,ESTABLISHED,RELATED

# Log entry
    test -x "$LOGGER" && \
        $LOGGER -p kern.info -t SuSEfirewall2 "Firewall rules successfully set in QUICKMODE for device(s) \"$FW_DEV_EXT\"$EXTRA"
    exit 0
}

#######################
#                     #
# Dynamic Definitions #
#                     #
#######################
echo " $FW_DEV_EXT $FW_DEV_DMZ $FW_DEV_INT " | $GREP -q ipsec && FW_DEV_IPSEC=yes
test "$FW_MASQUERADE" = yes -a "$FW_ROUTE" = no && \
    echo 'Warning FW_ROUTE needs to be set to yes, so that the masquerading works!'
test "$FW_ALLOW_CLASS_ROUTING" = yes -a "$FW_ROUTE" = no && \
    echo 'Warning FW_ROUTE needs to be set to yes, so that the FW_ALLOW_CLASS_ROUTING works!'
test "$FW_ROUTE" = no -a "$FW_ALLOW_PING_DMZ" = yes -o "FW_ROUTE" = no -a "$FW_ALLOW_PING_EXT" = yes && \
    echo 'Warning FW_ROUTE needs to be set to yes, so that the FW_ALLOW_PING_EXT and/or FW_ALLOW_PING_DMZ works!'
test -z "$FW_MASQ_NETS" || {
    test "$FW_MASQUERADE" = no && \
        echo 'Warning FW_MASQ_NETS needs FW_MASQUERADE set to yes to work!'
}
test -z "$FW_FORWARD_MASQ" || {
    test "$FW_MASQUERADE" = no && \
        echo 'Warning FW_FORWARD_MASQ needs FW_MASQUERADE set to yes to work!'
}
test "$FW_SERVICE_AUTODETECT" = no -a "$FW_ALLOW_INCOMING_HIGHPORTS_UDP" '!=' yes -a "$FW_SERVICE_DNS" = yes && \
    echo 'FW_ALLOW_INCOMING_HIGHPORTS_UDP should be set to yes, if you are running a DNS server!'

test "$FW_SERVICE_AUTODETECT" = yes -o "$FW_SERVICE_AUTODETECT" = dmz -o "$FW_SERVICE_AUTODETECT" = ext && {
    test "$FW_SERVICE_DNS" = no -a '!' "$START_NAMED" = no && check_srv named && {
	echo -e 'Warning: detected activated named, enabling FW_SERVICE_DNS!
You still have to allow tcp/udp port 53 on internal, dmz and/or external.'
	FW_SERVICE_DNS=$FW_SERVICE_AUTODETECT
	FW_ALLOW_INCOMING_HIGHPORTS_UDP=yes
    }
    test "$FW_SERVICE_SQUID" = no -a '!' "$START_SQUID" = no && check_srv squid && {
	echo -e 'Warning: detected activated squid, enabling FW_SERVICE_SQUID!
You still have to allow tcp port 3128 on internal, dmz and/or external.'
	FW_SERVICE_SQUID=$FW_SERVICE_AUTODETECT
    }
    test "$FW_SERVICE_DHCPD" = no -a '!' "$START_DHCPD" = no && check_srv dhcpd && {
	echo    'Warning: detected activated dhcpd, enabling FW_SERVICE_DHCPD!'
	FW_SERVICE_DHCPD=$FW_SERVICE_AUTODETECT
    }
    test "$FW_SERVICE_SAMBA" = no -a '!' "$START_SMB" = no && check_srv smb && {
	echo -e 'Warning: detected activated samba, enabling FW_SERVICE_SMB!
You still have to allow tcp port 139 on internal, dmz and/or external.'
	FW_SERVICE_SAMBA=$FW_SERVICE_AUTODETECT
    }
    test "$FW_SERVICE_DHCLIENT" = no && {
	test "$IFCONFIG_0" = dhcpclient -o "$IFCONFIG_1" = dhcpclient \
	    -o "$IFCONFIG_0" = bootp -o "$IFCONFIG_1" = bootp && {
	echo 'Warning: detected BOOTP/DHCLIENT usage for interfaces in /etc/sysconfig/network/config, enabling FW_SERVICE_DHCLIENT!'
	    FW_SERVICE_DHCLIENT=$FW_SERVICE_AUTODETECT
	}
    }
}

NEW_FW_DEV_INT=""
for DEV in $FW_DEV_INT ; do
    getdevinfo $DEV
    if [ "$DEV_IP" = "" ]; then
	faulty_int
    else
        test -z "$DEV_INT" || DEV_INT="$DEV_INT $DEV_IP"
        test -z "$DEV_INT" && DEV_INT="$DEV_IP"
        test -z "$DEV_INT_NET" || DEV_INT_NET="$DEV_INT_NET $DEV_IP/$DEV_MASK"
        test -z "$DEV_INT_NET" && DEV_INT_NET="$DEV_IP/$DEV_MASK"
        test -z "$DEV_INT_BCAST" || DEV_INT_BCAST="$DEV_INT_BCAST $DEV_BCAST"
        test -z "$DEV_INT_BCAST" && DEV_INT_BCAST="$DEV_BCAST"
        test -z `echo "$DEV"|$GREP -E ':|!|\*'` && NEW_FW_DEV_INT="$NEW_FW_DEV_INT $DEV"
    fi
done
FW_DEV_INT="$NEW_FW_DEV_INT"
NEW_FW_DEV_DMZ=""
for DEV in $FW_DEV_DMZ ; do
    getdevinfo $DEV
    if [ "$DEV_IP" = "" ]; then
         faulty_int
    else
        test -z "$DEV_DMZ" || DEV_DMZ="$DEV_DMZ $DEV_IP"
        test -z "$DEV_DMZ" && DEV_DMZ="$DEV_IP"
        test -z "$DEV_DMZ_NET" || DEV_DMZ_NET="$DEV_DMZ_NET $DEV_IP/$DEV_MASK"
        test -z "$DEV_DMZ_NET" && DEV_DMZ_NET="$DEV_IP/$DEV_MASK"
        test -z "$DEV_DMZ_BCAST" || DEV_DMZ_BCAST="$DEV_DMZ_BCAST $DEV_BCAST"
        test -z "$DEV_DMZ_BCAST" && DEV_DMZ_BCAST="$DEV_BCAST"
        test -z `echo "$DEV"|$GREP -E ':|!|\*'` && NEW_FW_DEV_DMZ="$NEW_FW_DEV_DMZ $DEV"
    fi
done
FW_DEV_DMZ="$NEW_FW_DEV_DMZ"
NEW_FW_DEV_EXT=""
for DEV in $FW_DEV_EXT ; do
    getdevinfo $DEV
    if [ "$DEV_IP" = "" ]; then
         faulty_int
    else
        test -z "$DEV_EXT" || DEV_EXT="$DEV_EXT $DEV_IP"
        test -z "$DEV_EXT" && DEV_EXT="$DEV_IP"
        test -z "$DEV_EXT_NET" || DEV_EXT_NET="$DEV_EXT_NET $DEV_IP/$DEV_MASK"
        test -z "$DEV_EXT_NET" && DEV_EXT_NET="$DEV_IP/$DEV_MASK"
        test -z "$DEV_EXT_BCAST" || DEV_EXT_BCAST="$DEV_EXT_BCAST $DEV_BCAST"
        test -z "$DEV_EXT_BCAST" && DEV_EXT_BCAST="$DEV_BCAST"
        test -z `echo "$DEV"|$GREP -E ':|!|\*'` && NEW_FW_DEV_EXT="$DEV $NEW_FW_DEV_EXT"
    fi
done
FW_DEV_EXT="$NEW_FW_DEV_EXT"
NEW_FW_MASQ_DEV=""
for DEV in $FW_MASQ_DEV; do
    test -z `echo "$DEV"|$GREP -E ':|!|\*'` && NEW_FW_MASQ_DEV="$DEV $NEW_FW_MASQ_DEV"
done
FW_MASQ_DEV="$NEW_FW_MASQ_DEV"

# warn user if device to masquerade is  from a non private network,
# add the net to DEV_MASQ_NET which is used for anti-spoof later.
# 0/0 has to be skipped here, otherwise the spoof rules would block
# anything
for NET in $FW_MASQ_NETS ; do
    DEV_IP=${NET%%,*}
    #`echo $NET | $AWK -F, '{print $1}'`
    # skip 0/0
    test "$DEV_IP" = "0/0" && continue

    PART1=${DEV_IP%%/*}
    #`echo $DEV_IP | $AWK -F/ '{print $1}'`
    PART2=${DEV_IP#*/}
    #`echo $DEV_IP | $AWK -F/ '{print $2}'`
    test '!' -z "$PART2" && test "$PART2" -lt 16 && {
        echo "$PART1" | $GREP -Eq '^10\.|^172\.1' || {
	    echo "Warning: Netmask of $DEV_IP might be wrong, ensure that it is correct."
            echo "         Normal is /16 or /24 or smaller."
        }
    }
    echo "$PART1" | $GREP -Eq '^10\.|^172\.1[6789]\.|^172\.2[0-9]\.|^172\.3[01]\.|^192\.168\.' || {
        echo "Warning: The network $DEV_IP you want to masquerade is not from a private network"
        echo '         e.g. 10.0.0.0/8, 172.16.0.0/12 or 192.168.0.0/16 - change this!'
    }
    test -z "$DEV_MASQ_NET" || DEV_MASQ_NET="$DEV_MASQ_NET $DEV_IP"
    test -z "$DEV_MASQ_NET" && DEV_MASQ_NET="$DEV_IP"
done

test -e /etc/resolv.conf || echo "Warning: /etc/resolv.conf not found"
# Get ports/IP bindings of NAMED/SQUID
test "$FW_SERVICE_DNS" = yes -o "$FW_SERVICE_DNS" = dmz -o "$FW_SERVICE_DNS" = ext -o "$START_NAMED" = yes && DNS_PORT=`$LSOF -i -n -P | \
    $AWK -F: '/^named .* UDP / {print $2}'| $GREP -vw 53 | $SORT -un`
test "$FW_SERVICE_SQUID" = yes -o "$FW_SERVICE_SQUID" = dmz -o "$FW_SERVICE_SQUID" = ext -o "$START_SQUID" = yes && SQUID_PORT=`$LSOF -i -n -P | \
    $AWK -F: '/^squid .* UDP/ {print $2}'| $SORT -un`

# Logging setup
LOG="--log-level warning --log-tcp-options --log-ip-options --log-prefix SuSE-FW"
test -z "$FW_LOG" || LOG="$FW_LOG"
test "$FW_LOG_DROP_CRIT" = no -o "$FW_LOG_DROP_ALL" = yes && LDC=":"
test "$FW_LOG_ACCEPT_CRIT" = no -o "$FW_LOG_ACCEPT_ALL" = yes && LAC=":"
test "$FW_LOG_DROP_ALL" = yes || LDA=":"	# it might look weird - a ":"
test "$FW_LOG_ACCEPT_ALL" = yes || LAA=":"	# disables logging of this type

#####################
#                   #
# Load custom rules #
#                   #
#####################
test -z "$FW_CUSTOMRULES" || {
    test -r "$FW_CUSTOMRULES" || {
        echo "Error: Can not read custom rules file: $FW_CUSTOMRULES"
        test -x "$LOGGER" && \
            $LOGGER -p kern.error -t SuSEfirewall2 "Firewall customary rules file can not be read: $FW_CUSTOMRULES"
        exit 1
    }
    . "$FW_CUSTOMRULES"
    test -x "$LOGGER" && \
        $LOGGER -p kern.info -t SuSEfirewall2 "Firewall customary rules loaded from $FW_CUSTOMRULES"
}

########################
# Should I really run? #
########################
INTERFACE_OK=`echo "$DEV_EXT $DEV_INT $DEV_DMZ" | $SED 's/ //g'`
test -z "$INTERFACE_OK" && { 
    echo -en '\n Warning: No interface active (yet?)'
    #reset_rules ; 
    # Remember that we should be active
    # $IPTABLES -N reject_func
    #exit 6 ;
}
# prevent errors due to missing interfaces
INTERFACE_OK=`echo "$DEV_EXT" | $SED 's/ //g'`
test -z "$INTERFACE_OK" && { DEV_EXT=""; DEV_EXT_NET=""; }
INTERFACE_OK=`echo "$DEV_DMZ" | $SED 's/ //g'`
test -z "$INTERFACE_OK" && { DEV_DMZ=""; DEV_DMZ_NET=""; }
INTERFACE_OK=`echo "$DEV_INT" | $SED 's/ //g'`
test -z "$INTERFACE_OK" && { DEV_INT=""; DEV_INT_NET=""; }
test '!' -f /proc/sys/net/ipv4/ip_forward -a "$FW_ROUTE" = yes && \
    echo 'Warning: kernel seems not to have ip_forwarding support!'

############################################
#                                          #
# Now we begin to set the filter rules ... #
#                                          #
############################################
# Set default rules + flush #
#############################
set_basic_rules

#################################
# Turn on routing if configured #
#################################
test "$FW_ROUTE" = yes || { echo 0 >/proc/sys/net/ipv4/ip_forward 2>/dev/null ; } >/dev/null 2>&1
test "$FW_ROUTE" = yes && echo 1 > /proc/sys/net/ipv4/ip_forward

#################################
# Configuring more kernel stuff #
#################################
{
 echo 1 > /proc/sys/net/ipv4/icmp_echo_ignore_broadcasts 2> /dev/null
# test "$FW_ALLOW_PING_FW" = yes || echo 1 > /proc/sys/net/ipv4/icmp_echo_ignore_all 2> /dev/null # XXX
 echo 1 > /proc/sys/net/ipv4/tcp_syncookies 2> /dev/null
 echo 1 > /proc/sys/net/ipv4/ip_always_defrag 2> /dev/null # XXX not there?
 echo 0 > /proc/sys/net/ipv4/tcp_ecn 2> /dev/null
 echo 16384 > /proc/sys/net/ipv4/ip_conntrack_max
 for i in /proc/sys/net/ipv4/conf/*; do
     echo 0 > $i/accept_redirects 2> /dev/null
     echo 0 > $i/accept_source_route 2> /dev/null
     test -z "$FW_DEV_IPSEC" && echo 1 > $i/rp_filter 2> /dev/null
     echo 0 > $i/mc_forwarding 2> /dev/null
 done
 test "$FW_KERNEL_SECURITY" = no || {
    echo 1 > /proc/sys/net/ipv4/icmp_ignore_bogus_error_responses 2> /dev/null
    echo 5 > /proc/sys/net/ipv4/icmp_echoreply_rate 2> /dev/null
    echo 5 > /proc/sys/net/ipv4/icmp_destunreach_rate 2> /dev/null
    echo 5 > /proc/sys/net/ipv4/icmp_paramprob_rate 2> /dev/null
    echo 6 > /proc/sys/net/ipv4/icmp_timeexceed_rate 2> /dev/null
    echo 20 > /proc/sys/net/ipv4/ipfrag_time 2> /dev/null
    echo 1 > /proc/sys/net/ipv4/igmp_max_memberships 2> /dev/null
    echo "1024 29999" > /proc/sys/net/ipv4/ip_local_port_range 2> /dev/null
    for i in /proc/sys/net/ipv4/conf/*; do
        echo 1 > $i/log_martians 2> /dev/null
	echo 0 > $i/bootp_relay 2> /dev/null
	test "$FW_ROUTE" = yes || { echo 0 > $i/forwarding ; } > /dev/null 2>&1
	echo 0 > $i/proxy_arp 2> /dev/null
	echo 1 > $i/secure_redirects 2> /dev/null
    done
    echo 1 > /proc/sys/net/ipv4/route/flush
 }
} > /dev/null 2>&1

########################################
# Allow looping on localhost interface #
########################################
$IPTABLES -A INPUT  -j "$ACCEPT" -i lo
$IPTABLES -A OUTPUT -j "$ACCEPT" -o lo

# Little helper: convert setting to chains list
function serv_to_chains
{
	if test "$1" = "yes" -o "$1" = "int"; then RC="input_int";
	elif test "$1" = "dmz"; then RC="input_int input_dmz";
	elif test "$1" = "ext"; then RC="input_int input_dmz input_ext";
	else RC=""
	fi
	echo $RC
}
# Little helper: convert setting to interfaces
function serv_to_devs
{
	if test "$1" = "yes" -o "$1" = "int"; then RC="$FW_DEV_INT";
	elif test "$1" = "dmz"; then RC="$FW_DEV_INT $FW_DEV_DMZ";
	elif test "$1" = "ext"; then RC="$FW_DEV_INT $FW_DEV_DMZ $FW_DEV_EXT";
	else RC=""
	fi
	echo $RC
}

# Make input/forward chains
for TARGET in input forward; do
    for CHAIN in ext dmz int; do
        $IPTABLES -N ${TARGET}_${CHAIN}
    done
done
######################
# Allow DHCP replies #
######################

FW_SERV_DHCLIENT_DEVS=`serv_to_devs $FW_SERVICE_DHCLIENT`
test ! -z "$FW_SERV_DHCLIENT_DEVS" && {
    #$LAA $IPTABLES -A INPUT -j LOG ${LOG}"-ACCEPT " -p udp --sport 67 -d 255.255.255.255/32 --dport 68
    #$IPTABLES -A INPUT -j "$ACCEPT"  -m state --state ESTABLISHED -p udp --sport 67 -d 255.255.255.255/32 --dport 68
    for dev in $FW_SERV_DHCLIENT_DEVS; do
	$LAA $IPTABLES -A INPUT -j LOG ${LOG}"-ACCEPT " -i $dev -p udp --sport 67 -d 255.255.255.255/32 --dport 68
	$IPTABLES -A INPUT -j "$ACCEPT" -i $dev -m state --state ESTABLISHED -p udp --sport 67 -d 255.255.255.255
   done
}

FW_SERV_DHCPD_DEVS=`serv_to_devs $FW_SERVICE_DHCPD`
test ! -z "$FW_SERV_DHCPD_DEVS" && {
    for dev in $FW_SERV_DHCPD_DEVS; do
	$LAA $IPTABLES -A INPUT -j LOG ${LOG}"-ACCEPT " -i $dev -p udp --sport 68 -d 255.255.255.255/32 --dport 67
	$IPTABLES -A INPUT -j "$ACCEPT" -i $dev -m state --state NEW,ESTABLISHED -p udp --sport 68 -d 255.255.255.255/32 --dport 67
    done
}

#########################
# Special SAMBA support #
#########################
FW_SERV_SAMBA_DEVS=`serv_to_devs $FW_SERVICE_SAMBA`
test ! -z "$FW_SERV_SAMBA_DEVS" && { # baah, these samba rules look evil!
    for dev in $FW_SERV_SAMBA_DEVS; do
	$LAA $IPTABLES -A INPUT -j LOG ${LOG}"-ACCEPT " -i $dev -p udp --dport 137:138
	$IPTABLES -A INPUT -j "$ACCEPT"  -i $dev -m state --state NEW,ESTABLISHED,RELATED -p udp --dport 137:138
    done
}

###################################################
# Customary hook: fw_custom_before_antispoofing() #
###################################################
fw_custom_before_antispoofing

#################################################
# Anti Spoofing rules - not interface dependent #
#################################################
test -z "$LDC" -o -z "$LDA" && $IPTABLES -A INPUT -j LOG ${LOG}"-DROP-ANTI-SPOOFING "  -s 127.0.0.0/8
test -z "$LDC" -o -z "$LDA" && $IPTABLES -A INPUT -j LOG ${LOG}"-DROP-ANTI-SPOOFING "  -d 127.0.0.0/8
$IPTABLES -A INPUT -j "$DROP" -s 127.0.0.0/8
$IPTABLES -A INPUT -j "$DROP" -d 127.0.0.0/8
for SPOOF in $DEV_INT $DEV_EXT $DEV_DMZ; do
    test -z "$LDC" -o -z "$LDA" && $IPTABLES -A INPUT -j LOG ${LOG}"-DROP-ANTI-SPOOFING "  -s $SPOOF
    $IPTABLES -A INPUT -j "$DROP" -s $SPOOF
done
# some people have wrong routing setups, so ...
test "$FW_ROUTE" = yes && for DEV in $FW_DEV_INT $FW_DEV_EXT $FW_DEV_DMZ; do
    $IPTABLES -A FORWARD -j "$ACCEPT" -i $DEV -o $DEV
done

####################################################
# Customary hook: fw_custom_after_antispoofing()   #
####################################################
fw_custom_after_antispoofing

#####################################
# Rule split up - forking to chains #
#####################################
for DEV in $FW_DEV_EXT; do
    for IP in $DEV_EXT; do
        $IPTABLES -A INPUT -j input_ext -i $DEV -d $IP
    done
    test "$FW_ROUTE" = yes && $IPTABLES -A FORWARD -j forward_ext -i $DEV
done
for DEV in $FW_DEV_DMZ; do
    for IP in $DEV_DMZ; do
        $IPTABLES -A INPUT -j input_dmz -i $DEV -d $IP
    done
    test "$FW_ROUTE" = yes && $IPTABLES -A FORWARD -j forward_dmz -i $DEV
done
for DEV in $FW_DEV_INT; do
    for IP in $DEV_INT; do
        $IPTABLES -A INPUT -j input_int -i $DEV -d $IP
    done
    test "$FW_ROUTE" = yes && $IPTABLES -A FORWARD -j forward_int -i $DEV
done

test "$FW_ALLOW_FW_BROADCAST" = yes && {
    for NET in $DEV_EXT_BCAST; do
	for DEV in $FW_DEV_EXT; do
	    $IPTABLES -A INPUT -j input_ext -i $DEV -d $NET
	    $IPTABLES -A INPUT -j input_ext -i $DEV -d 255.255.255.255
	done
    done
    for NET in $DEV_DMZ_BCAST; do
	for DEV in $FW_DEV_DMZ; do
	    $IPTABLES -A INPUT -j input_dmz -i $DEV -d $NET
	    $IPTABLES -A INPUT -j input_dmz -i $DEV -d 255.255.255.255
	done
    done
    for NET in $DEV_INT_BCAST; do
	for DEV in $FW_DEV_INT; do
	    $IPTABLES -A INPUT -j input_int -i $DEV -d $NET
	    $IPTABLES -A INPUT -j input_int -i $DEV -d 255.255.255.255
	done
    done
}

# broadcast stuff
test "$FW_IGNORE_FW_BROADCAST" = yes && {
    for NET in $DEV_EXT_BCAST; do
	for DEV in $FW_DEV_EXT; do
	    $IPTABLES -A INPUT -j "$DROP" -i $DEV -d $NET
	    $IPTABLES -A INPUT -j "$DROP" -i $DEV -d 255.255.255.255
	done
    done
    for NET in $DEV_DMZ_BCAST; do
	for DEV in $FW_DEV_DMZ; do
	    $IPTABLES -A INPUT -j "$DROP" -i $DEV -d $NET
	    $IPTABLES -A INPUT -j "$DROP" -i $DEV -d 255.255.255.255
	done
    done
    for NET in $DEV_INT_BCAST; do
	for DEV in $FW_DEV_INT; do
	    $IPTABLES -A INPUT -j "$DROP" -i $DEV -d $NET
	    $IPTABLES -A INPUT -j "$DROP" -i $DEV -d 255.255.255.255
	done
    done
}

###############################################################
# Anti Spoofing/Cirumvention protection - interface dependent #
###############################################################
for DEV in $FW_DEV_INT; do
    for IP in $DEV_EXT; do
        $IPTABLES -A INPUT -j LOG ${LOG}"-ACCESS_DENIED_INT "  -i $DEV -d $IP
	$IPTABLES -A INPUT -i $DEV -d $IP -j "$DROP"
    done
done
# anything which is now not in the input_* chains is evil
test -z "$LDC" -o -z "$LDA" && $IPTABLES -A INPUT -j LOG ${LOG}"-ILLEGAL-TARGET " 
$IPTABLES -A INPUT -j "$DROP"
test "$FW_ROUTE" = yes && test -z "$LDC" -o -z "$LDA" && $IPTABLES -A FORWARD -j LOG ${LOG}"-ILLEGAL-ROUTING " 
test "$FW_ROUTE" = yes && $IPTABLES -A FORWARD -j "$DROP" # this is an unneeded rule, but looks nice :)
# anti ip spoofing rules
for SPOOF in $DEV_EXT_NET $DEV_DMZ_NET; do
    # special case for internal ipsec devices that have the same ip as the
    # external device
    for net in $DEV_INT_NET; do
	if [ "$net" = "$SPOOF" ]; then
	    echo "$net is internal and external, no spoof protection possible from internal"
	    continue 2
	fi
    done

    test -z "$LDC" -o -z "$LDA" && $IPTABLES -A input_int -j LOG ${LOG}"-DROP-ANTI-SPOOF-iint " -s $SPOOF
    test "$FW_ROUTE" = yes && test -z "$LDC" -o -z "$LDA" && $IPTABLES -A forward_int -j LOG ${LOG}"-DROP-ANTI-SPOOF " -s $SPOOF
    $IPTABLES -A input_int -j "$DROP" -s $SPOOF
    test "$FW_ROUTE" = yes && $IPTABLES -A forward_int -j "$DROP" -s $SPOOF
done
for SPOOF in $DEV_EXT_NET $DEV_INT_NET; do
    test -z "$LDC" -o -z "$LDA" && $IPTABLES -A input_dmz -j LOG ${LOG}"-DROP-ANTI-SPOOF-idmz " -s $SPOOF
    test "$FW_ROUTE" = yes && test -z "$LDC" -o -z "$LDA" && $IPTABLES -A forward_dmz -j LOG ${LOG}"-DROP-ANTI-SPOOF " -s $SPOOF
    $IPTABLES -A input_dmz -j "$DROP" -s $SPOOF
    test "$FW_ROUTE" = yes && $IPTABLES -A forward_dmz -j "$DROP" -s $SPOOF
done
# those devices must not be 0/0!
for SPOOF in $DEV_INT_NET $DEV_DMZ_NET $DEV_MASQ_NET; do
    # special case for internal ipsec devices that have the same ip as the
    # external device
    for net in $DEV_EXT_NET; do
	if [ "$net" = "$SPOOF" ]; then
	    echo "$net is internal and external, no spoof protection possible from external"
	    continue 2
	fi
    done
    test -z "$LDC" -o -z "$LDA" && $IPTABLES -A input_ext -j LOG ${LOG}"-DROP-ANTI-SPOOF-iext " -s $SPOOF
    test "$FW_ROUTE" = yes && test -z "$LDC" -o -z "$LDA" && $IPTABLES -A forward_ext -j LOG ${LOG}"-DROP-ANTI-SPOOF " -s $SPOOF
    $IPTABLES -A input_ext -j "$DROP" -s $SPOOF
    test "$FW_ROUTE" = yes && $IPTABLES -A forward_ext -j "$DROP" -s $SPOOF
done
# anti circumvention rules
test "$FW_ROUTE" = yes && for IP in $DEV_INT $DEV_DMZ; do
    test -z "$LDC" -o -z "$LDA" && $IPTABLES -A forward_ext -j LOG ${LOG}"-DROP-CIRCUMVENTION " -d $IP
    $IPTABLES -A forward_ext -j "$DROP" -d $IP
done
test "$FW_ROUTE" = yes && for IP in $DEV_INT $DEV_EXT; do
    test -z "$LDC" -o -z "$LDA" && $IPTABLES -A forward_dmz -j LOG ${LOG}"-DROP-CIRCUMVENTION " -d $IP
    $IPTABLES -A forward_dmz -j "$DROP" -d $IP
done
test "$FW_ROUTE" = yes && for IP in $DEV_EXT $DEV_DMZ; do
    test -z "$LDC" -o -z "$LDA" && $IPTABLES -A forward_int -j LOG ${LOG}"-DROP-CIRCUMVENTION " -d $IP
    $IPTABLES -A forward_int -j "$DROP" -d $IP
done

###################################################
# Protect the firewall from the internal network? #
###################################################
test "$FW_PROTECT_FROM_INTERNAL" = no && {
    $LAA $IPTABLES -A input_int -j LOG ${LOG}"-ACCEPT-ALL-INTERNAL " 
    $IPTABLES -A input_int -j "$ACCEPT"
}

########################
# ICMP Stuff (special) #
########################
# INPUT ICMP rules
test "$FW_ALLOW_FW_SOURCEQUENCH" = no || for NET in $DEV_EXT_NET; do
        test -z "$LAC" -o -z "$LAA" && $IPTABLES -A input_ext -j LOG ${LOG}"-ACCEPT-SOURCEQUENCH "  -p icmp -s $NET --icmp-type source-quench
        $IPTABLES -A input_ext -j "$ACCEPT" -p icmp -s $NET --icmp-type source-quench
done
test "$FW_ALLOW_PING_FW" = yes && for CHAIN in input_ext input_dmz input_int; do
    $LAA $IPTABLES -A $CHAIN -j LOG ${LOG}"-ACCEPT-PING "  -p icmp --icmp-type echo-request
    $IPTABLES -A $CHAIN -j "$ACCEPT" -p icmp --icmp-type echo-request
done
for TYPE in echo-reply destination-unreachable time-exceeded \
  parameter-problem timestamp-reply address-mask-reply; do
    for CHAIN in input_ext input_dmz input_int; do
	$LAA $IPTABLES -A $CHAIN -j LOG ${LOG}"-ACCEPT-ICMP "  -p icmp --icmp-type $TYPE
	$IPTABLES -A $CHAIN -j "$ACCEPT"  -m state --state ESTABLISHED,RELATED -p icmp --icmp-type $TYPE
    done
done
# DROP rules for input ICMP are after trusted handling (see below)

# OUTPUT ICMP rules
test -z "$LDC" -o -z "$LDA" -o -z "$LAC" -o -z "$LAA" && $IPTABLES -A OUTPUT -j LOG ${LOG}"-TRACEROUTE-ATTEMPT "  -p icmp --icmp-type time-exceeded
test "$FW_ALLOW_FW_TRACEROUTE" = yes && {
    $IPTABLES -A OUTPUT -j "$ACCEPT" -p icmp --icmp-type time-exceeded
    $IPTABLES -A OUTPUT -j "$ACCEPT" -p icmp --icmp-type port-unreachable
}
test "$FW_ALLOW_FW_TRACEROUTE" = yes || \
    $IPTABLES -A OUTPUT -j "$DROP" -p icmp --icmp-type time-exceeded
for TYPE in fragmentation-needed network-prohibited host-prohibited communication-prohibited; do
    $IPTABLES -A OUTPUT -j "$ACCEPT" -p icmp --icmp-type $TYPE
done
$IPTABLES -A OUTPUT -j "$DROP" -p icmp --icmp-type destination-unreachable # we deny all other icmp type 3 codes

# FORWARD ICMP rules
test "$FW_ALLOW_PING_DMZ" = yes -a "$FW_ROUTE" = yes && {
    for DEV in $FW_DEV_DMZ; do
        for CHAIN in forward_ext forward_int; do
	    $LAA $IPTABLES -A $CHAIN -j LOG ${LOG}"-ACCEPT-PING "  -p icmp --icmp-type echo-request -o $DEV
	    $IPTABLES -A $CHAIN -j "$ACCEPT" -m state --state NEW -p icmp --icmp-type echo-request -o $DEV
        done
    done
    $LAA $IPTABLES -A forward_dmz -j LOG ${LOG}"-ACCEPT-PING "  -p icmp --icmp-type echo-reply
    $IPTABLES -A forward_dmz -j "$ACCEPT"  -m state --state ESTABLISHED -p icmp --icmp-type echo-reply
}
test "$FW_ALLOW_PING_EXT" = yes -a "$FW_ROUTE" = yes && {
    for DEV in $FW_DEV_EXT; do
        for CHAIN in forward_int forward_dmz; do
	    $LAA $IPTABLES -A $CHAIN -j LOG ${LOG}"-ACCEPT-PING "  -p icmp --icmp-type echo-request -o $DEV
	    $IPTABLES -A $CHAIN -j "$ACCEPT" -m state --state NEW -p icmp --icmp-type echo-request -o $DEV
        done
    done
    $LAA $IPTABLES -A forward_ext -j LOG ${LOG}"-ACCEPT-PING "  -p icmp --icmp-type echo-reply
    $IPTABLES -A forward_ext -j "$ACCEPT"  -m state --state ESTABLISHED -p icmp --icmp-type echo-reply
}
# drop rule for forwarding chains are at the end of the forwarding rules

####################################################
# Customary hook: fw_custom_before_port_handling() #
####################################################
fw_custom_before_port_handling

#############################
# Trusted Networks Handling #
#############################
for NETS in $FW_TRUSTED_NETS; do
    IFS="," read NET PROTO PORT ERROR < <(echo "$NETS")
    test -z "$4" || {
	echo "Error: Too many arguments in FW_TRUSTED_NETS -> $NETS"
	NET=""
    }
    test -z "$PORT" -a "$PROTO" = tcp -o -z "$PORT" -a "$PROTO" = udp && {
	echo "Error: Missing port definition for TCP/UDP in FW_TRUSTED_NETS -> $NETS"
	NET=""
    }
    test -z "$PORT" || {
	test "$PROTO" = tcp -o "$PROTO" = udp -o "$PROTO" = icmp || {
	    echo "Error: the third parameter is for use with tcp, udp and icmp only in FW_TRUSTED_NETS -> $NETS"
	    NET=""
    }; }
    test -z "$NET" || {
	test -z "$PROTO" || PROTO="-p $PROTO"
	test -z "$PORT" || {
	    test "$PROTO" = "-p icmp" || PORT="--dport $PORT"
	    test "$PROTO" = "-p icmp" && PORT="--icmp-type $PORT"
	}
	for CHAIN in input_ext input_dmz input_int; do # trusted networks can be on any interface ...
	    test "$LAC" = "" -a "$PROTO" = "-p tcp" && $IPTABLES -A $CHAIN -j LOG ${LOG}"-ACCEPT-TRUST "  -s $NET $PROTO $PORT --syn
	    $LAA $IPTABLES -A $CHAIN -j LOG ${LOG}"-ACCEPT-TRUST "  -s $NET $PROTO $PORT
	    $IPTABLES -A $CHAIN -j "$ACCEPT"  -m state --state NEW,ESTABLISHED,RELATED -s $NET $PROTO $PORT
	done
    }
done

# ICMP drop rules must be here to allow trusted rules for ICMP
for CHAIN in input_ext input_dmz input_int; do
    $LDC $IPTABLES -A $CHAIN -j LOG ${LOG}"-DROP-ICMP-CRIT "  -p icmp --icmp-type redirect
    $LDC $IPTABLES -A $CHAIN -j LOG ${LOG}"-DROP-ICMP-CRIT "  -p icmp --icmp-type source-quench
    $LDC $IPTABLES -A $CHAIN -j LOG ${LOG}"-DROP-ICMP-CRIT "  -p icmp --icmp-type timestamp-request
    $LDC $IPTABLES -A $CHAIN -j LOG ${LOG}"-DROP-ICMP-CRIT "  -p icmp --icmp-type address-mask-request
    $LDC $IPTABLES -A $CHAIN -j LOG ${LOG}"-DROP-ICMP-CRIT "  -p icmp --icmp-type 2
    $LDA $IPTABLES -A $CHAIN -j LOG ${LOG}"-DROP-ICMP " -p icmp
    $IPTABLES -A $CHAIN -j "$DROP" -p icmp
done

############
# IP Stuff #
############
for PROTO in $FW_SERVICES_EXT_IP; do
    $LAA $IPTABLES -A input_ext -j LOG ${LOG}"-ACCEPT " -p $PROTO
    $IPTABLES -A input_ext -j "$ACCEPT" -m state --state NEW,ESTABLISHED,RELATED -p $PROTO
done
for PROTO in $FW_SERVICES_DMZ_IP; do
    $LAA $IPTABLES -A input_dmz -j LOG ${LOG}"-ACCEPT " -p $PROTO
    $IPTABLES -A input_dmz -j "$ACCEPT" -m state --state NEW,ESTABLISHED,RELATED -p $PROTO
done
for PROTO in $FW_SERVICES_INT_IP; do
    $LAA $IPTABLES -A input_int -j LOG ${LOG}"-ACCEPT " -p $PROTO
    $IPTABLES -A input_int -j "$ACCEPT" -m state --state NEW,ESTABLISHED,RELATED -p $PROTO
done

#############
# TCP Stuff #
#############
for PORT in $FW_SERVICES_EXT_TCP; do
    $LAC $IPTABLES -A input_ext -j LOG ${LOG}"-ACCEPT " -p tcp --dport $PORT --syn
    $LAA $IPTABLES -A input_ext -j LOG ${LOG}"-ACCEPT " -p tcp --dport $PORT
    $IPTABLES -A input_ext -j "$ACCEPT" -m state --state NEW,ESTABLISHED,RELATED -p tcp --dport $PORT
done
for PORT in $FW_SERVICES_DMZ_TCP; do
    $LAC $IPTABLES -A input_dmz -j LOG ${LOG}"-ACCEPT " -p tcp --dport $PORT --syn
    $LAA $IPTABLES -A input_dmz -j LOG ${LOG}"-ACCEPT " -p tcp --dport $PORT
    $IPTABLES -A input_dmz -j "$ACCEPT" -m state --state NEW,ESTABLISHED,RELATED -p tcp --dport $PORT
done
for PORT in $FW_SERVICES_INT_TCP; do
    $LAC $IPTABLES -A input_int -j LOG ${LOG}"-ACCEPT " -p tcp --dport $PORT --syn
    $LAA $IPTABLES -A input_int -j LOG ${LOG}"-ACCEPT " -p tcp --dport $PORT
    $IPTABLES -A input_int -j "$ACCEPT" -m state --state NEW,ESTABLISHED,RELATED -p tcp --dport $PORT
done

# If port 113 (auth/identd) was not allowed above, outgoing mail would
# be delayed most of the time. Hence we put a hardcoded reject line in.
for CHAIN in input_ext input_dmz input_int; do
    $LDA $IPTABLES -A $CHAIN -j LOG ${LOG}"-REJECT "  -p tcp --dport 113 --syn
    $IPTABLES -A $CHAIN -j "$REJECT" -p tcp --dport 113 --syn 2> /dev/null
done

# some words about the autoprotecting feature below: these long lines of code
# try to identify which services were allowed via the config file (including
# the DNS port for UDP) and which others are open which have to be protected.
# This could even be more optimised by resolving name->number and just
# protecting ports > 1023. I know it looks ... weird ... but it works! ;-)
test "$FW_AUTOPROTECT_SERVICES" = no || {
    PROTECT_GLOBAL=`$NETSTAT -an | \
      $GREP -E '^tcp .* 0.0.0.0:[1-9].*LISTEN|^tcp .* :::[1-9].*LISTEN' | \
      $AWK '{print $4}' | $SED 's/.*://'`
    for IP in $DEV_EXT; do
        PROTECT_EXT="$PROTECT_EXT `$NETSTAT -an | \
	 $AWK '/^tcp .* '"$IP"':[1-9].*LISTEN/ {print $4}' | $SED 's/.*://'`"
    done
    for IP in $DEV_DMZ; do
        PROTECT_DMZ="$PROTECT_DMZ `$NETSTAT -an | \
	 $AWK '/^tcp .* '"$IP"':[1-9].*LISTEN/ {print $4}' | $SED 's/.*://'`"
    done
   test "$FW_PROTECT_FROM_INTERNAL" = no || {
    for IP in $DEV_INT; do
        PROTECT_INT="$PROTECT_INT `$NETSTAT -an | \
	 $AWK '/^tcp .* '"$IP"':[1-9].*LISTEN/ {print $4}' | $SED 's/.*://'`"
    done
    export PROTECT_INT PROTECT_GLOBAL
### XXX TODO BAK
    PROTECT=`for S in $PROTECT_INT $PROTECT_GLOBAL; do echo $S; done | $SORT -n`
    OPENED_INT=`echo "$FW_SERVICES_INT_TCP" | $SED 's/ /|/g'`
    PROTECT_INT=`for S in $PROTECT; do echo $S; done | $GREP -Evw "$OPENED_INT"`
    for PORT in $PROTECT_INT; do
	test -z "$LDC" -o -z "$LDA" && $IPTABLES -A input_int -j LOG ${LOG}"-DROP " -p tcp --dport $PORT --syn
	$IPTABLES -A input_int -j "$DROP" -p tcp --dport $PORT --syn
    done
   }
    PROTECT=`for S in $PROTECT_DMZ $PROTECT_GLOBAL; do echo $S; done | $SORT -n`
    OPENED_DMZ=`echo "$FW_SERVICES_DMZ_TCP" | $SED 's/ /|/g'`
    PROTECT_DMZ=`for S in $PROTECT; do echo $S; done | $GREP -Evw "$OPENED_DMZ"`
    for PORT in $PROTECT_DMZ; do
	test -z "$LDC" -o -z "$LDA" && $IPTABLES -A input_dmz -j LOG ${LOG}"-DROP " -p tcp --dport $PORT --syn
	$IPTABLES -A input_dmz -j "$DROP" -p tcp --dport $PORT --syn
    done
    PROTECT=`for S in $PROTECT_EXT $PROTECT_GLOBAL; do echo $S; done | $SORT -n`
    OPENED_EXT=`echo "$FW_SERVICES_EXT_TCP" | $SED 's/ /|/g'`
    PROTECT_EXT=`for S in $PROTECT; do echo $S; done | $GREP -Evw "$OPENED_EXT"`
    for PORT in $PROTECT_EXT; do
	test -z "$LDC" -o -z "$LDA" && $IPTABLES -A input_ext -j LOG ${LOG}"-DROP " -p tcp --dport $PORT --syn
	$IPTABLES -A input_ext -j "$DROP" -p tcp --dport $PORT --syn
    done
}

DONE_ALL=no
test "$FW_ALLOW_INCOMING_HIGHPORTS_TCP" = yes || {
    for CHAIN in input_int input_dmz input_ext; do
        $LAC $IPTABLES -A $CHAIN -j LOG ${LOG}"-ACCEPT " -m state --state ESTABLISHED,RELATED -p tcp --dport 1024:65535 --syn
        $LAA $IPTABLES -A $CHAIN -j LOG ${LOG}"-ACCEPT " -m state --state ESTABLISHED,RELATED -p tcp --dport 1024:65535
        $IPTABLES -A $CHAIN -j "$ACCEPT" -m state --state ESTABLISHED,RELATED -p tcp --dport 1024:65535
    done
}
for j in $FW_ALLOW_INCOMING_HIGHPORTS_TCP; do
        case "$j" in
            no) ;;
            yes)
		for CHAIN in input_int input_dmz input_ext; do
                    $LAC $IPTABLES -A $CHAIN -j LOG ${LOG}"-ACCEPT " -p tcp --dport 1024:65535 --syn
                    $LAA $IPTABLES -A $CHAIN -j LOG ${LOG}"-ACCEPT " -p tcp --dport 1024:65535
                    $IPTABLES -A $CHAIN -j "$ACCEPT" -m state --state NEW,ESTABLISHED,RELATED -p tcp --dport 1024:65535
		done
		DONE_ALL=yes
                ;;
            [Dd][Nn][Ss])
                test -z "$NAMESERVERS" && \
                    echo 'Warning: No nameservers in /etc/resolv.conf!'
                test "$DONE_ALL" = yes || for k in $NAMESERVERS; do
  		    test "$k" = 127.0.0.1 || for CHAIN in input_int input_dmz input_ext; do
                        $LAA $IPTABLES -A $CHAIN -j LOG ${LOG}"-ACCEPT " -p tcp -s $k --sport 53 --dport 1024:65535
                        $IPTABLES -A $CHAIN -j "$ACCEPT" -m state --state ESTABLISHED,RELATED -p tcp -s $k --sport 53 --dport 1024:65535
		    done
                done
                ;;
            *)
		test "$DONE_ALL" = yes || for CHAIN in input_int input_dmz input_ext; do
                    $LAC $IPTABLES -A $CHAIN -j LOG ${LOG}"-ACCEPT " -p tcp --sport $j --dport 1024:65535 --syn
                    $LAA $IPTABLES -A $CHAIN -j LOG ${LOG}"-ACCEPT " -p tcp --sport $j --dport 1024:65535
                    $IPTABLES -A $CHAIN -j "$ACCEPT" -m state --state NEW,ESTABLISHED,RELATED -p tcp --sport $j --dport 1024:65535
		done
                ;;
        esac
done

# This sucks, we need this rule so we can receive data ... hello stealth scan
for CHAIN in input_int input_dmz input_ext; do
    $LAA $IPTABLES -A $CHAIN -j LOG ${LOG}"-ACCEPT " -p tcp --dport 600:65535 '!' --syn
    $IPTABLES -A $CHAIN -j "$ACCEPT" -m state --state ESTABLISHED -p tcp --dport 600:65535 '!' --syn
done
for CHAIN in input_int input_dmz input_ext; do
    $LAA $IPTABLES -A $CHAIN -j LOG ${LOG}"-ACCEPT " -p tcp --dport 20 '!' --syn
    $IPTABLES -A $CHAIN -j "$ACCEPT" -m state --state ESTABLISHED -p tcp --dport 20 '!' --syn
done

#############
# UDP Stuff #
#############
for PORT in $FW_SERVICES_EXT_UDP; do
    $LAA $IPTABLES -A input_ext -j LOG ${LOG}"-ACCEPT " -p udp --dport $PORT
    $IPTABLES -A input_ext -j "$ACCEPT" -m state --state NEW,ESTABLISHED,RELATED -p udp --dport $PORT
done
for PORT in $FW_SERVICES_DMZ_UDP; do
    $LAA $IPTABLES -A input_dmz -j LOG ${LOG}"-ACCEPT " -p udp --dport $PORT
    $IPTABLES -A input_dmz -j "$ACCEPT" -m state --state NEW,ESTABLISHED,RELATED -p udp --dport $PORT
done
for PORT in $FW_SERVICES_INT_UDP; do
    $LAA $IPTABLES -A input_int -j LOG ${LOG}"-ACCEPT " -p udp --dport $PORT
    $IPTABLES -A input_int -j "$ACCEPT" -m state --state NEW,ESTABLISHED,RELATED -p udp --dport $PORT
done

# NAMED
FW_SERV_DNS_CHAINS=`serv_to_chains $FW_SERVICE_DNS`
test ! -z "$FW_SERV_DNS_CHAINS" && {
    # Warning not necessary; normally named does just use port 53.
    #test -z "$DNS_PORT" && \
    #    echo 'Warning: FW_SERVICE_DNS defined, but no DNS server found running!'
    test -z "$DNS_PORT" || {
	for PORT in $DNS_PORT; do
	    for CHAIN in $FW_SERV_DNS_CHAINS; do
	        $LAA $IPTABLES -A $CHAIN -j LOG ${LOG}"-ACCEPT " -p udp --dport $PORT
	        $IPTABLES -A $CHAIN -j "$ACCEPT" -m state --state NEW,ESTABLISHED,RELATED -p udp --dport $PORT
	    done
	done
    }
}

# SQUID
FW_SERV_SQUID_CHAINS=`serv_to_chains $FW_SERVICE_SQUID`
test ! -z "$FW_SERV_SQUID_CHAINS" && {
    test -z "$SQUID_PORT" && \
        echo 'Warning: FW_SERVICE_SQUID defined, but no Squid server found running!'
    test -z "$SQUID_PORT" || {
	for PORT in $SQUID_PORT; do
	    for CHAIN in $FW_SERV_SQUID_CHAINS; do
	        $LAA $IPTABLES -A $CHAIN -j LOG ${LOG}"-ACCEPT " -p udp --dport $PORT
	        $IPTABLES -A $CHAIN -j "$ACCEPT" -m state --state NEW,ESTABLISHED,RELATED -p udp --dport $PORT
	    done
	done
    }
}

# special pre-rules before the autoprotecting feature to prevent the blocking
# of DNS resolvers
OPEN_DNS=no
for j in $FW_ALLOW_INCOMING_HIGHPORTS_UDP; do
        case "$j" in
            yes)
		OPEN_DNS=yes
		;;
            [Dd][Nn][Ss])
		OPEN_DNS=yes
                ;;
            *)  ;;
        esac
done
test "$OPEN_DNS" = yes && {
   test -z "$NAMESERVERS" && \
       echo 'Warning: No nameservers in /etc/resolv.conf!'
   for k in $NAMESERVERS; do
       test "$k" = 127.0.0.1 || for CHAIN in input_int input_dmz input_ext; do
           $LAA $IPTABLES -A $CHAIN -j LOG ${LOG}"-ACCEPT " -p udp -s $k --sport 53 --dport 1024:65535
# guess this has to be state NEW because the outgoing packet was not seen when
# doing autodialing... XXX - or?
           $IPTABLES -A $CHAIN -j "$ACCEPT" -m state --state NEW,ESTABLISHED,RELATED -p udp -s $k --sport 53 --dport 1024:65535
	done
   done
}

# description of the code below: see TCP notes for the autoprotect feature
test "$FW_AUTOPROTECT_SERVICES" = no || {
    PROTECT_GLOBAL=`$NETSTAT -an | \
      $GREP -E '^udp .* 0.0.0.0:[1-9]|^udp .* :::[1-9]' | $GREP -v ESTAB | \
      $AWK '{print $4}' | $SED 's/.*://'`
    for IP in $DEV_EXT; do
        PROTECT_EXT="$PROTECT_EXT `$NETSTAT -an | $GREP -v ESTAB | \
	 $AWK '/^udp .* '"$IP"':[1-9]/ {print $4}' | $SED 's/.*://'`"
    done
    for IP in $DEV_DMZ; do
        PROTECT_DMZ="$PROTECT_DMZ `$NETSTAT -an | $GREP -v ESTAB | \
	 $AWK '/^udp .* '"$IP"':[1-9]/ {print $4}' | $SED 's/.*://'`"
    done
   test "$FW_PROTECT_FROM_INTERNAL" = no || {
    for IP in $DEV_INT; do
        PROTECT_INT="$PROTECT_INT `$NETSTAT -an | $GREP -v ESTAB | \
	 $AWK '/^udp .* '"$IP"':[1-9]/ {print $4}' | $SED 's/.*://'`"
    done
    PROTECT=`for S in $PROTECT_INT $PROTECT_GLOBAL; do echo $S; done | $SORT -n`
    OPENED_INT=`echo "$FW_SERVICES_INT_UDP $DNS_PORT $SQUID_PORT" | $SED 's/ /|/g'`
    PROTECT_INT=`for S in $PROTECT; do echo $S; done | $GREP -Evw "$OPENED_INT"`
    for PORT in $PROTECT_INT; do
	$LDA $IPTABLES -A input_int -j LOG ${LOG}"-DROP " -p udp --dport $PORT
	$IPTABLES -A input_int -j "$DROP" -p udp --dport $PORT
    done
   }
    PROTECT=`for S in $PROTECT_DMZ $PROTECT_GLOBAL; do echo $S; done | $SORT -n`
    OPENED_DMZ=`echo "$FW_SERVICES_DMZ_UDP $DNS_PORT $SQUID_PORT" | $SED 's/ /|/g'`
    PROTECT_DMZ=`for S in $PROTECT; do echo $S; done | $GREP -Evw "$OPENED_DMZ"`
    for PORT in $PROTECT_DMZ; do
	$LDA $IPTABLES -A input_dmz -j LOG ${LOG}"-DROP " -p udp --dport $PORT
	$IPTABLES -A input_dmz -j "$DROP" -p udp --dport $PORT
    done
    PROTECT=`for S in $PROTECT_EXT $PROTECT_GLOBAL; do echo $S; done | $SORT -n`
    OPENED_EXT=`echo "$FW_SERVICES_EXT_UDP $DNS_PORT $SQUID_PORT" | $SED 's/ /|/g'`
    PROTECT_EXT=`for S in $PROTECT; do echo $S; done | $GREP -Evw "$OPENED_EXT"`
    for PORT in $PROTECT_EXT; do
	$LDA $IPTABLES -A input_ext -j LOG ${LOG}"-DROP " -p udp --dport $PORT
	$IPTABLES -A input_ext -j "$DROP" -p udp --dport $PORT
    done
}

DONE_ALL=no
test "$FW_ALLOW_INCOMING_HIGHPORTS_UDP" = yes || {
    for CHAIN in input_int input_dmz input_ext; do
        $LAA $IPTABLES -A $CHAIN -j LOG ${LOG}"-ACCEPT " -p udp --dport 1024:65535
        $IPTABLES -A $CHAIN -j "$ACCEPT" -m state --state ESTABLISHED,RELATED -p udp --dport 1024:65535
    done
}
for j in $FW_ALLOW_INCOMING_HIGHPORTS_UDP; do
        case "$j" in
            no) ;;
            yes)
		for CHAIN in input_int input_dmz input_ext; do
                    $LAA $IPTABLES -A $CHAIN -j LOG ${LOG}"-ACCEPT " -p udp --dport 1024:65535
                    $IPTABLES -A $CHAIN -j "$ACCEPT" -m state --state NEW,ESTABLISHED,RELATED -p udp --dport 1024:65535
		done
		DONE_ALL=yes
                ;;
            [Dd][Nn][Ss])
                ;;
            *)
		test "$DONE_ALL" = yes || for CHAIN in input_int input_dmz input_ext; do
                    $LAA $IPTABLES -A $CHAIN -j LOG ${LOG}"-ACCEPT " -p udp --sport $j --dport 1024:65535
                    $IPTABLES -A $CHAIN -j "$ACCEPT" -m state --state NEW,ESTABLISHED,RELATED -p udp --sport $j --dport 1024:65535
		done
                ;;
        esac
done

test "$FW_MASQUERADE" = yes && {
    EXT=""; DMZ=""; INT="";
    for DEV1 in $FW_MASQ_DEV; do
	for DEV2 in $FW_DEV_EXT; do
	    test "$DEV1" = $DEV2 -a -z "$EXT" && {
	        $LAA $IPTABLES -A input_ext -j LOG ${LOG}"-ACCEPT " -p udp --dport 61000:65095
        	$IPTABLES -A input_ext -j "$ACCEPT" -m state --state ESTABLISHED -p udp --dport 61000:65095
		EXT=1
	    }
	done
	for DEV2 in $FW_DEV_DMZ; do
	    test "$DEV1" = $DEV2 -a -z "$DMZ" && {
	        $LAA $IPTABLES -A input_dmz -j LOG ${LOG}"-ACCEPT " -p udp --dport 61000:65095
        	$IPTABLES -A input_dmz -j "$ACCEPT" -m state --state ESTABLISHED -p udp --dport 61000:65095
		DMZ=1
	    }
	done
	for DEV2 in $FW_DEV_INT; do
	    test "$DEV1" = $DEV2 -a -z "$INT" && {
	        $LAA $IPTABLES -A input_int -j LOG ${LOG}"-ACCEPT " -p udp --dport 61000:65095
        	$IPTABLES -A input_int -j "$ACCEPT" -m state --state ESTABLISHED -p udp --dport 61000:65095
		INT=1
	    }
	done
    done
}

##################################################
# Customary hook: fw_custom_before_forwardmasq() #
##################################################
fw_custom_before_masq

###############################
# IP FORWARDING STUFF (evil!) #
###############################
for NETS in $FW_REDIRECT; do
    IFS="," read NET1 NET2 PROTO PORT1 PORT2 ERROR < <(echo "$NETS")
    NET2=${NET2/\!/\! }
    test -z "$ERROR" || {
	echo "Error: Too many arguments in FW_REDIRECT -> $NETS"
	NET1=""
    }
    test -z "$NET1" -o -z "$NET2" -o -z "$PROTO" -o -z "$PORT1" -o -z "$PORT2" && {
	echo "Error: Missing parameter in FW_REDIRECT -> $NETS"
	NET1=""
    }
    test "$PROTO" = tcp -o "$PROTO" = udp || {
	echo "Error: Protocol with FW_REDIRECT must be tcp or udp -> $NETS"
	NET1=""
    }
    test -z "$NET1" || {
	PROTO="-p $PROTO"
	PORT1="--dport $PORT1"
	$IPTABLES -A PREROUTING -t nat -j REDIRECT $PROTO -s $NET1 -d $NET2 $PORT1 --to-ports $PORT2
	for CHAIN in input_ext input_dmz input_int; do
	    test "$LAC" = "" -a "$PROTO" = "-p tcp" && $IPTABLES -A $CHAIN -j LOG ${LOG}"-ACCEPT-REDIRECT "  -s $NET1 $PROTO --dport $PORT2 --syn
	    $LAA $IPTABLES -A $CHAIN -j LOG ${LOG}"-ACCEPT-REDIRECT "  -s $NET1 $PROTO --dport $PORT2
	    $IPTABLES -A $CHAIN -j "$ACCEPT" -m state --state NEW,ESTABLISHED,RELATED $PROTO -s $NET1 --dport $PORT2
	done
    }
done

test "$FW_ROUTE" = yes && {
 for CHAIN in forward_ext forward_dmz forward_int; do
    $LAA $IPTABLES -A $CHAIN -j LOG ${LOG}"-FORWARD-RELATED "  -m state --state RELATED -p icmp --icmp-type destination-unreachable
    $LAA $IPTABLES -A $CHAIN -j LOG ${LOG}"-FORWARD-RELATED "  -m state --state ESTABLISHED,RELATED -p icmp --icmp-type echo-reply
    $IPTABLES -A $CHAIN -j "$ACCEPT" -m state --state RELATED -p icmp --icmp-type destination-unreachable
    $IPTABLES -A $CHAIN -j "$ACCEPT" -m state --state ESTABLISHED,RELATED -p icmp --icmp-type echo-reply
 done

 test "$FW_ALLOW_CLASS_ROUTING" = yes && {
    for DEV1 in $FW_DEV_INT; do
        for DEV2 in $FW_DEV_INT; do
	    test "$DEV1" = "$DEV2" || {
		$LAA $IPTABLES -A forward_int -j LOG ${LOG}"-ACCEPT-CLASS "  -i $DEV1 -o $DEV2
		$IPTABLES -A forward_int -j "$ACCEPT" -i $DEV1 -o $DEV2
	    }
	done
    done
    for DEV1 in $FW_DEV_DMZ; do
        for DEV2 in $FW_DEV_DMZ; do
	    test "$DEV1" = "$DEV2" || {
		$LAA $IPTABLES -A forward_dmz -j LOG ${LOG}"-ACCEPT-CLASS "  -i $DEV1 -o $DEV2
		$IPTABLES -A forward_dmz -j "$ACCEPT" -i $DEV1 -o $DEV2
	    }
	done
    done
    for DEV1 in $FW_DEV_EXT; do
        for DEV2 in $FW_DEV_EXT; do
	    test "$DEV1" = "$DEV2" || {
		$LAA $IPTABLES -A forward_ext -j LOG ${LOG}"-ACCEPT-CLASS "  -i $DEV1 -o $DEV2
		$IPTABLES -A forward_ext -j "$ACCEPT" -i $DEV1 -o $DEV2
	    }
	done
    done
 }

 for NETS in $FW_FORWARD; do
    IFS="," read NET1 NET2 PROTO PORT ERROR < <(echo "$NETS")
    test -z "$ERROR" || {
	echo "Error: Too many arguments in FW_FORWARD -> $NETS"
	NET1=""
    }
    test -z "$PORT" -a "$PROTO" = tcp -o -z "$PORT" -a "$PROTO" = udp && {
	echo "Error: Missing port definition for TCP/UDP in FW_FORWARD -> $NETS"
	NET1=""
    }
    test -z "$PORT" || {
	test "$PROTO" = tcp -o "$PROTO" = udp -o "$PROTO" = icmp || {
	    echo "Error: the fourth parameter is for use with tcp, udp and icmp only in FW_FORWARD -> $NETS"
	    NET1=""
    }; }
    test -z "$NET1" -o -z "$NET2" || {
	test -z "$PROTO" || PROTO="-p $PROTO"
	test -z "$PORT" || {
	    test "$PROTO" = icmp || {
		PORTBACK="--sport $PORT"
		PORT="--dport $PORT"
	    }
	    test "$PROTO" = "-p icmp" && PORT="--icmp-type $PORT"
	}
	for CHAIN in forward_ext forward_dmz forward_int; do
	    test "$LAC" = "" -a "$PROTO" = "-p tcp" && $IPTABLES -A $CHAIN -j LOG ${LOG}"-ACCEPT-TRUST "  -s $NET1 -d $NET2 $PROTO $PORT --syn
	    $LAA $IPTABLES -A $CHAIN -j LOG ${LOG}"-ACCEPT-TRUST "  -s $NET1 -d $NET2 $PROTO $PORT
	    $IPTABLES -A $CHAIN -j "$ACCEPT" -m state --state NEW,ESTABLISHED,RELATED -s $NET1 -d $NET2 $PROTO $PORT
	    test "$LAA" = "" -a "$PROTO" = "-p tcp" -o "$PROTO" = "-p udp" && $IPTABLES -A $CHAIN -j LOG ${LOG}"-ACCEPT " -d $NET1 -s $NET2 $PROTO $PORTBACK
	    test "$PROTO" = "-p tcp" && $IPTABLES -A $CHAIN -j "$ACCEPT" -m state --state ESTABLISHED,RELATED -d $NET1 -s $NET2 $PROTO $PORTBACK '!' --syn
	    test "$PROTO" = "-p udp" && $IPTABLES -A $CHAIN -j "$ACCEPT" -m state --state ESTABLISHED,RELATED -d $NET1 -s $NET2 $PROTO $PORTBACK
	done
    }
 done

 test "$FW_MASQUERADE" = yes && {
    for NETS in $FW_MASQ_NETS; do
	IFS="," read NET1 NET2 PROTO PORT ERROR < <(echo "$NETS")
        test -z "$ERROR" || {
   	    echo "Error: Too many arguments in FW_MASQ_NETS -> $NETS"
	    NET1=""
        }
	case "$NET1" in
		*/0)
			if test "$NET1" != "0/0"; then
			    echo "Error: Source network may not be */0 in FW_MASQ_NETS -> $NETS"
			    NET1=""
			fi
		;;
        esac
        test "$PROTO" = tcp -o "$PROTO" = udp -o -z "$PROTO" || {
	    echo "Error: The protocol with FW_MASQ_NETS must be tcp, udp or empty-> $NETS"
	    NET1=""
        }
        test -z "$NET1" || {
	    NET2X=""
	    test -z "$NET2" || NET2X="-s $NET2"
	    test -z "$NET2" || NET2="-d $NET2"
	    test -z "$PROTO" || PROTO="-p $PROTO"
            PORTX=""
	    test -z "$PORT" || PORTX="--sport $PORT"
	    test -z "$PORT" || PORT="--dport $PORT"
	    for DEV in $FW_MASQ_DEV; do
		for CHAIN in forward_ext forward_dmz forward_int; do
		    $LAA $IPTABLES -A $CHAIN -j LOG ${LOG}"-ACCEPT-MASQ "  -s $NET1 $NET2 $PROTO $PORT -o $DEV
		    $IPTABLES -A $CHAIN -j "$ACCEPT" -m state --state NEW,ESTABLISHED,RELATED -s $NET1 $NET2 $PROTO $PORT -o $DEV
#not so sure about the rule below XXX
		    $LAA $IPTABLES -A $CHAIN -j LOG ${LOG}"-ACCEPT-MASQ "  -d $NET1 $NET2X $PROTO $PORTX -i $DEV
		    $IPTABLES -A $CHAIN -j "$ACCEPT" -m state --state ESTABLISHED,RELATED -d $NET1 $NET2X $PROTO $PORTX -i $DEV
#XXX
	        done
		test -z "$PROTO" && \
		    $IPTABLES -A POSTROUTING -j MASQUERADE -t nat -s $NET1 $NET2 -o $DEV
		test -z "$PROTO" || \
		    $IPTABLES -A POSTROUTING -j MASQUERADE -t nat -s $NET1 $NET2 $PROTO $PORT -o $DEV --to-ports 61000-65095
	    done
	}
    done

    for NETS in $FW_FORWARD_MASQ; do
	IFS="," read NET1 NET2 PROTO PORT1 PORT2 LIP ERROR < <(echo "$NETS")
        test -z "$ERROR" || {
   	    echo "Error: Too many arguments in FW_FORWARD_MASQ -> $NETS"
	    NET2=""
        }
	test -z "$LIP" && LIP="$DEV_EXT"
	echo "$NET2" | $GREP -q "/" && {
	    echo "Error: Target must be a single host in FW_FORWARD_MASQ -> $NETS"
	    NET2=""
        }
        test "$PROTO" = tcp -o "$PROTO" = udp || {
	    echo "Error: The protocol with FW_MASQ_NETS must be tcp or udp -> $NETS"
	    NET2=""
        }
        test -z "$PORT1" && {
	    echo "Error: Port missing in FW_MASQ_NETS -> $NETS"
	    NET2=""
        }
        test -z "$NET2" || {
	    test -z "$NET1" || NET1="-s $NET1"
	    PROTO="-p $PROTO"
	    test -z "$PORT2" && PORT2="$PORT1"
	    test -z "$PORT1" || PORT1="--dport $PORT1"
            PORT2X=""
	    test -z "$PORT2" || {
		PORT2X="--dport $PORT2"
                #PORT2=`echo "$PORT2" | sed 's/:/-/g'`
		PORT2=${PORT2/:/-}
	        PORT2=":$PORT2"
	    }
	    for DEV in $FW_MASQ_DEV; do
                for TLIP in $LIP; do
                    $IPTABLES -A PREROUTING -j DNAT -t nat $PROTO $NET1 -d $TLIP $PORT1 --to-destination ${NET2}${PORT2} -i $DEV
		done
		for CHAIN in forward_ext forward_dmz forward_int; do
		    test "$LAC" = "" -a "$PROTO" = "-p tcp" && $IPTABLES -A $CHAIN -j LOG ${LOG}"-ACCEPT-REVERSE_MASQ "  $PROTO $NET1 -d $NET2 $PORT2X -i $DEV --syn
		    $LAA test "$PROTO" = "-p tcp" || $IPTABLES -A $CHAIN -j LOG ${LOG}"-ACCEPT-REVERSE_MASQ "  $PROTO $NET1 -d $NET2 $PORT2X -i $DEV
		    $IPTABLES -A $CHAIN -j "$ACCEPT" -m state --state NEW,ESTABLISHED,RELATED $PROTO $NET1 -d $NET2 $PORT2X -i $DEV
		done
	    done
	}
    done
 }
}

##############################################
# Customary hook: fw_custom_before_denyall() #
##############################################
fw_custom_before_denyall

##########################
# Special Logging + Deny #
##########################
# DROP rules for IP forwarding
test "$FW_ROUTE" = yes && for CHAIN in forward_ext forward_dmz forward_int; do
    test -z "$LDC" && {
        $IPTABLES -A $CHAIN -j LOG ${LOG}"-DROP-DEFAULT " -p tcp --syn
	for TYPE in source-quench redirect echo-request timestamp-request address-mask-request; do
	    $IPTABLES -A $CHAIN -j LOG ${LOG}"-DROP-DEFAULT " -p icmp --icmp-type $TYPE
	done
        $IPTABLES -A $CHAIN -j LOG ${LOG}"-DROP-DEFAULT " -p udp
	$IPTABLES -A $CHAIN -j LOG ${LOG}"-DROP-DEFAULT-INVALID "  -m state --state INVALID
    }
    $LDA $IPTABLES -A $CHAIN -j LOG ${LOG}"-DROP-DEFAULT "
    $IPTABLES -A $CHAIN -j "$DROP"
done
# DROP rule for left INPUT packets
for CHAIN in input_ext input_dmz input_int; do
    test -z "$LDC" && {
        $IPTABLES -A $CHAIN -j LOG ${LOG}"-DROP-DEFAULT " -p tcp --syn
	for TYPE in source-quench redirect echo-request timestamp-request address-mask-request; do
	    $IPTABLES -A $CHAIN -j LOG ${LOG}"-DROP-DEFAULT " -p icmp --icmp-type $TYPE
	done
        $IPTABLES -A $CHAIN -j LOG ${LOG}"-DROP-DEFAULT " -p udp
	$IPTABLES -A $CHAIN -j LOG ${LOG}"-DROP-DEFAULT-INVALID "  -m state --state INVALID
    }
    $LDA $IPTABLES -A $CHAIN -j LOG ${LOG}"-DROP-DEFAULT "
    $IPTABLES -A $CHAIN -j "$DROP"
done

######################
# Optimisation Rules #
######################
# Optimise your TCP/UDP connections by setting IP Options!
TABLES=OUTPUT
test "$FW_ROUTE" = yes && TABLES="OUTPUT PREROUTING"

for i in $TABLES; do
#mangle TOS with icmp does not seem to work. the 2.4 firewall still sucks
#    $IPTABLES -A $i -j TOS -m state --state NEW -t mangle -p icmp --icmp-type echo-request --set-tos Minimize-Delay # ping
#    $IPTABLES -A $i -j TOS -t mangle -p icmp --icmp-type echo-reply   --set-tos Minimize-Delay # pong
#    $IPTABLES -A $i -j TOS -t mangle -p icmp --set-tos Maximize-Reliability # all other ICMP
#    $IPTABLES -A $i -j TOS -m state --state NEW,ESTABLISHED,RELATED -t mangle -p tcp --sport 22   --set-tos Minimize-Delay # SSH in
#    $IPTABLES -A $i -j TOS -m state --state NEW,ESTABLISHED,RELATED -t mangle -p tcp --dport 22   --set-tos Minimize-Delay # SSH out
    $IPTABLES -A $i -j TOS -m state --state NEW,ESTABLISHED,RELATED -t mangle -p tcp --sport 20   --set-tos Maximize-Throughput # FTP Data
    $IPTABLES -A $i -j TOS -m state --state NEW,ESTABLISHED,RELATED -t mangle -p tcp --dport 20   --set-tos Maximize-Throughput # FTP Data
    $IPTABLES -A $i -j TOS -m state --state NEW,ESTABLISHED,RELATED -t mangle -p tcp --sport 80   --set-tos Maximize-Throughput # HTTP
    $IPTABLES -A $i -j TOS -m state --state NEW,ESTABLISHED,RELATED -t mangle -p tcp --dport 80   --set-tos Maximize-Throughput # HTTP
    $IPTABLES -A $i -j TOS -m state --state NEW,ESTABLISHED,RELATED -t mangle -p tcp --sport 53   --set-tos Minimize-Delay # DNS
    $IPTABLES -A $i -j TOS -m state --state NEW,ESTABLISHED,RELATED -t mangle -p udp --dport 53   --set-tos Minimize-Delay # DNS
    $IPTABLES -A $i -j TOS -m state --state NEW,ESTABLISHED,RELATED -t mangle -p udp --dport 161  --set-tos Maximize-Reliability # SNMP
    $IPTABLES -A $i -j TOS -m state --state NEW,ESTABLISHED,RELATED -t mangle -p udp --dport 162  --set-tos Maximize-Reliability # SNMP Trap
    $IPTABLES -A $i -j TOS -t mangle -p udp --dport 514  --set-tos Maximize-Reliability # Syslog
    #$IPTABLES -A $i -j TOS -m state --state NEW,ESTABLISHED,RELATED -t mangle -p udp --set-tos Maximize-Reliability # all UDP
    test "$i" = PREROUTING && i=FORWARD
    $IPTABLES -A $i -j ACCEPT -m state --state NEW,ESTABLISHED,RELATED
    $IPTABLES -A $i -j LOG ${LOG}"-$i-ERROR " 
done

# MSS stuff needs this?
$IPTABLES -I FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu

# HTB settings
do_qdisc_settings

# Log entry
test -x "$LOGGER" && \
    $LOGGER -p kern.info -t SuSEfirewall2 "Firewall rules successfully set from $FWCONFIG"

########
# END ##
exit 0 #
########
