ACC SHELL

Path : /sbin/
File Upload :
Current File : //sbin/SuSEfirewall2

#!/bin/bash
#
# SuSEfirewall2 - stateful packetfilter rules generator
# Copyright (C) 2000-2002 Marc Heuse <marc@suse.de>
# Copyright (C) 2003,2004 SUSE Linux AG
# Copyright (C) 2005-2008 SUSE LINUX Products GmbH
#
# Author:     Marc Heuse
# Maintainer: Ludwig Nussel
# 
# Please send feedback via http://www.suse.de/feedback
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# version 2 as published by the Free Software Foundation.
# 
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

#
# 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() {
cat <<EOF
SuSEfirewall2 3.6, Copyright (C) 2005  SUSE LINUX Products GmbH

stateful packet filter rules generator for iptables.

$0 start|test|debug [file FILENAME]
$0 basic|stop|close|status|help
$0 open ZONE TYPE services...
$0 on|off

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)
  basic   set basic filter rules that drop 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 -nvL"
  debug   print the iptables command to stdout instead of executing them
  log     show SuSEfirewall2 related syslog messages in a better readable format
  help    this output
  open    open the specified services in the specified zone. You need to
          restart SuSEfirewall2 for changes to take effect.
  on      add SuSEfirwall2 initscripts to boot process and start
  off     remove SuSEfirwall2 initscripts from boot process and stop

  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 may be used with the start, test and debug options.
EOF
    exit 0
}

removefiles=()
declare -a  removefiles
removeonexit()
{
    removefiles[${#removefiles[@]}]="$1"
}

cleanup()
{
    local file
    for file in "${removefiles[@]}"; do
	    rm -f "$file"
    done
}
trap cleanup EXIT

quiet=''
syslog()
{
    local pri="-p auth.err"
    local dashs='-s'
    if [ "$1" = '0' ]; then
	pri="-p auth.info"
	if [ -n "$quiet" ]; then
	    dashs=''
	fi
    elif [ "$1" = '-1' ]; then
	pri="-p auth.warn"
    fi
    shift
    /bin/logger $dashs $pri -t SuSEfirewall2 "$*"
}

message()
{
    syslog 0 "$*"
}

warning()
{
    syslog -1 "Warning:" "$*"
}

deprecated()
{
    warning "$@ is deprecated and will likely be removed in the future."
    warning "If you think it should be kept please report your use case at"
    warning "http://forge.novell.com/modules/xfmod/project/?susefirewall2"
}

error()
{
    syslog -2 "Error:" "$*"
}

die()
{
    local ret=1
    trap EXIT
    cleanup
    case "$1" in
	[0-9]) ret="$1"; shift ;;
    esac
    [ -n "$*" ] && syslog "$ret" "$*"
    exit $ret
}

need()
{
    . "$SCRIPTSDIR/SuSEfirewall2-$1"
}

CONFIGURATIONSDIR_0="/etc/sysconfig/SuSEfirewall2.d/services"
CONFIGURATIONSDIR_1="/usr/share/SuSEfirewall2/services"
SCRIPTSDIR="/etc/sysconfig/scripts"
FWCONFIG="/etc/sysconfig/SuSEfirewall2"
LOCKFILE="/var/lock/SuSEfirewall2.pid"
BOOTLOCKFILE="/var/lock/SuSEfirewall2.booting"
STATUSDIR="/var/run/SuSEfirewall2"
FW_CUSTOMRULES=""

FW_ZONE_DEFAULT=""
USE_IPTABLES_BATCH=''

# whether ip6tables supports state matching
IP6TABLES_HAVE_STATE=1

# whether ip6tables support REJECT
IP6TABLES_HAVE_REJECT=1

ACTION="start"
MODE="standard"
INITSCRIPTS="" # on|off
needconfig=
needlock=1
create_bootlock=0
remove_bootlock=0

# prevent double log entries when called from ip-up
if test -x /usr/bin/tty && ! /usr/bin/tty -s; then
    quiet=1
fi

getopttmp=`/usr/bin/getopt -o hq --long help,scriptsdir:,batch,nobatch,file:,debug,test,bootlock,bootunlock,quiet \
     -n 'SuSEfirewall2' -- "$@"`

[ $? != 0 ] && die 1 "getopt error"

eval set -- "$getopttmp"

while true ; do
        case "$1" in
		--file) FWCONFIG="$2"; shift 2 ;;
		--batch) USE_IPTABLES_BATCH='yes'; shift ;;
		--nobatch) USE_IPTABLES_BATCH='no'; shift ;;
                --scriptsdir) SCRIPTSDIR="$2" ; shift 2 ;;
                --test) MODE="test" ; shift ;;
                --debug) MODE="debug"; needlock=0 ; shift ;;
                --bootlock) create_bootlock=1 ; shift ;;
                --bootunlock) remove_bootlock=1 ; shift ;;
                -h|--help) help ; shift ;;
                -q|--quiet) quiet=1 ; shift ;;
                --) shift ; break ;;
                *) die 1 "getopt error"; ;;
        esac
done

case "$1" in
    start|"") needconfig=1 ;;
    test) MODE="test" ;;
    debug) MODE="debug"; needlock=0 ;;
    easy|novice|basic) ACTION="basic" ;;
    stop|halt|down|shutdown) ACTION="stop"; needconfig=1 ;;
    close) ACTION="close" ;;
    status) ACTION="status"; USE_IPTABLES_BATCH='no'; needlock=0 ;;
    open) ACTION="open"; USE_IPTABLES_BATCH='no'; needlock=0 ;;
    log) ACTION="showlog"; USE_IPTABLES_BATCH='no' ;;
    bootlock) ACTION="bootlock"; create_bootlock=1; needlock=0 ;;
    bootunlock) ACTION="bootunlock"; remove_bootlock=1; needlock=0 ;;
    help) help ;;
    off) ACTION="stop"; needconfig=1; INITSCRIPTS="off" ;;
    on) ACTION="start"; needconfig=1; INITSCRIPTS="on" ;;
    *) help ;;
esac
shift

case "$ACTION" in
    start|stop)
	while [ $# -gt 0 ]; do
	    case "$1" in
		file) FWCONFIG="$2"; shift 2 ;;
		force|batch) shift ;;  # unused, for compatability
		*) echo "invalid option: $1"; exit 1 ;;
	    esac
	done
	;;
esac

test -e /etc/sysconfig/network/config && . /etc/sysconfig/network/config

if [ -r "$FWCONFIG" ]; then
    . "$FWCONFIG"
elif [ -n "$needconfig" ]; then
    die 6 " Can not read $FWCONFIG"
fi

if [ -z "$USE_IPTABLES_BATCH" ]; then
    case "$FW_USE_IPTABLES_BATCH" in
	no) USE_IPTABLES_BATCH='' ;;
	yes) USE_IPTABLES_BATCH='yes' ;;
	''|auto) USE_IPTABLES_BATCH='auto' ;;
    esac
fi

if [ "$FW_ZONE_DEFAULT" = 'yes' -o "$FW_ZONE_DEFAULT" = 'auto' ]; then
    FW_ZONE_DEFAULT=''
fi

if [ -n "$USE_IPTABLES_BATCH" -a "$USE_IPTABLES_BATCH" != 'no' ]; then
    need batch
    check_iptables_batch
fi

[ "$USE_IPTABLES_BATCH" = 'no' ] && USE_IPTABLES_BATCH=''

### Definitions - fixed
unset ${!LC_*} ${!RC_LC_*} LANGUAGE RC_LANG
export LANG=en_US

export PATH="/sbin:/bin:/usr/sbin:/usr/bin"

hwdesc2iface=/etc/sysconfig/network/scripts/hwdesc2iface
modinfo="/sbin/modinfo"
TC="/usr/sbin/tc"
IPTABLES_BIN="/usr/sbin/iptables"
IP6TABLES_BIN="/usr/sbin/ip6tables"
if [ "$MODE" = debug ]; then
    IPTABLES="iptables"
    iptables()
    {
	echo iptables "$@"
    }
    IP6TABLES="ip6tables"
    ip6tables()
    {
	echo ip6tables "$@"
    }
    TC="tc"
    tc()
    {
	echo tc "$@"
    }
    modprobe()
    {
	echo modprobe "$@"
    }
else
    IPTABLES="$IPTABLES_BIN"
    IP6TABLES="$IP6TABLES_BIN"

    ### ipv6 checks
    case "$FW_IPv6" in
	    drop|reject) IP6TABLES_HAVE_STATE=0 ;;
	    no) IP6TABLES=":" ;;
	    *) FW_IPv6="" ;;
    esac


    ####

    if [ -n "$USE_IPTABLES_BATCH" ]; then
	IPTABLES=iptables
	[ "$IP6TABLES" != ":" ] && IP6TABLES=ip6tables
    fi
fi

### jump targets
ACCEPT="ACCEPT"
DROP="DROP"
REJECT="reject_func"
[ "$FW_REJECT" = yes ] && DROP="reject_func"

# fwmarks

mark_redir=1

# ipsec

ipsec_chain=""
IPSEC_INPUT_MATCH="-m policy --dir in --pol ipsec --proto esp"
IPSEC_OUTPUT_MATCH="-m policy --dir out --pol ipsec --proto esp"

### zones

all_zones="int ext dmz"
forward_zones=
input_zones=

#### constants

safe_icmp_replies="echo-reply destination-unreachable time-exceeded parameter-problem timestamp-reply address-mask-reply protocol-unreachable redirect"
safe_icmpv6_replies="echo-reply destination-unreachable packet-too-big time-exceeded parameter-problem"
stateless_icmpv6_types="router-solicitation router-advertisement neighbour-solicitation neighbour-advertisement redirect"

###############

check_ip6tables_support()
{
    [ "$IP6TABLES" != ':' ] || return

    # Do we have a kernel with IPv6 enabled?
    $IP6TABLES_BIN -nvL >/dev/null 2>&1 || IP6TABLES=:
    if ! $IP6TABLES_BIN -m state --help >/dev/null 2>&1 || \
    ( ! $modinfo ip6t_state >/dev/null 2>&1 && ! $modinfo xt_state >/dev/null 2>&1); then
	warning "ip6tables does not support state matching. Extended IPv6 support disabled."
	IP6TABLES_HAVE_STATE=0
	# reject incoming packets if not specified otherwise
	[ "$FW_IPv6" != 'no' -a "$FW_IPv6" != 'drop' ] && FW_IPv6='reject'
    fi

    $modinfo ip6t_REJECT >/dev/null 2>&1 || IP6TABLES_HAVE_REJECT=0

    if [ \( "$FW_REJECT" = "yes" -o "$FW_IPv6" = "reject" \) \
	    -a "$IP6TABLES_HAVE_REJECT" != 1 ]; then
	    warning "Kernel lacks support for IPv6 REJECT target! Using DROP for IPv6 instead."
    fi
}

is_running()
{
	test -e /proc/net/ip_tables_names && $IPTABLES_BIN -nL reject_func >/dev/null 2>&1
}

parse_logging()
{
    if [ -z "$FW_LOG_LIMIT" ]; then
	FW_LOG_LIMIT="-m limit --limit 3/minute"
    elif [ "$FW_LOG_LIMIT" = 'no' ]; then
	FW_LOG_LIMIT=''
    else
	FW_LOG_LIMIT="-m limit --limit $FW_LOG_LIMIT"
    fi

    ### logging setup
    if [ -z "$FW_LOG" ]; then
	LOG='--log-level warning --log-tcp-options --log-ip-options --log-prefix SFW2'
    else
	LOG="$FW_LOG"
    fi

    case "$LOG" in
	-j\ *) ;;
	*) LOG="-j LOG $LOG" ;;
    esac

    LDC=''  # log drop critical
    LDA=''  # log drop all
    LDAC='' # log drop all or critical
    LAC=''  # log accept critical
    LAA=''  # log accept all
    LAAC='' # log accept all or critical

    # 'critical' will be unset if 'all' is set since 'critical' might be a special case of 'all'.
    if [ "$FW_LOG_DROP_ALL" != yes ]; then
	LDA=":"
	if [ "$FW_LOG_DROP_CRIT" = no ]; then
	    LDC=":"
	    LDAC=":"
	fi
    else
	LDC=':'
    fi

    if [ "$FW_LOG_ACCEPT_ALL" != yes ]; then
	LAA=":"
	if [ "$FW_LOG_ACCEPT_CRIT" = no ]; then
	    LAC=":"
	    LAAC=":"
	fi
    else 
	LAC=':'
    fi

    [ "$LAA" = ':' ] && LOG="$FW_LOG_LIMIT $LOG"
}

### Functions
function setproc()
{
    [ -z "$2" -o ! -w "$2" ] && return
    if [ "$MODE" != "debug" ]; then
	echo "$1" > "$2"
    else
	echo "echo \"$1\" > \"$2\""
    fi
}

# parameters: protocol port variable
# check whether $1 and $2/$3 are a valid protocol/port combination and sets global
# variables $proto, $port ($rport) and $sport ($rsport) in iptables syntax
# $4 is used for logging
# returns 1 on error, the content of $proto and $port is undefined then
check_proto_port()
{
    proto="$1"
    port="$2"
    sport="$3"
    local var="$4"
    case "$proto" in
	'')
	    if [ -z "$proto" -a -z "$port" -a -z "$sport" ]; then
		proto=''
		port=''
		rport=''
		sport=''
		rsport=''
	    else
		error "proto must not be empty in ${var}"
		return 1
	    fi
	    ;;
	_rpc_) # cannot check ports here
	    ;;
	tcp|udp)
	    if [ -n "$port" ]; then
		rport="--sport $port"
		port="--dport $port"
	    else
		port=''
		rport=''
	    fi
	    if [ -n "$sport" ]; then
		rsport="--dport $sport"
		sport="--sport $sport"
	    else
		sport=''
		rsport=''
	    fi

	    ;;
	icmp)
	    if [ -n "$port" ]; then
		port="--icmp-type $port"
		rport="$port"
	    else
		port=''
		rport=''
	    fi
	    if [ -n "$sport" ]; then
		sport="--icmp-type $sport"
		rsport="$sport"
	    else
		sport=''
		rsport=''
	    fi
	;;
	*)
	    if [ -n "$port" ]; then
		error "port is only valid with tcp, udp or icmp in ${var}"
		return 1
	    fi
	;;
    esac
    [ -z "$proto" ] || proto="-p $proto"
    return 0
}

reset_rules() {
    local policy_input policy_output policy_forward

    policy_input=${1:-ACCEPT}
    policy_output=${2:-ACCEPT}
    policy_forward=${3:-ACCEPT}

    $IPTABLES -P INPUT $policy_input
    $IPTABLES -P OUTPUT $policy_output
    $IPTABLES -P FORWARD $policy_forward
    # yes we need cat for /proc
    for i in `sort < /proc/net/ip_tables_names`; do
	$IPTABLES -t $i -F
	$IPTABLES -t $i -X
    done
    if [ "$IP6TABLES" != ":" ]; then
	$IP6TABLES -P INPUT $policy_input
	$IP6TABLES -P OUTPUT $policy_output
	$IP6TABLES -P FORWARD $policy_forward
	for i in `sort /proc/net/ip6_tables_names`; do
	    $IP6TABLES -t $i -F
	    $IP6TABLES -t $i -X
	done
    fi
}

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

function load_modules()
{
    local i
    for i in "$@"; do
	modprobe "$i"
    done
}

function rulelog()
{
    rule=$1
    case $rule in
	input_*)
		echo IN${rule#input_}
		;;
	forward_*)
		echo FWD${rule#forward_}
		;;
    esac	
}


function allow_basic_established()
{
    # needed for dhcp and dns replies
    local iptables
    for iptables in "$IPTABLES" "$IP6TABLES"; do
	    $LAA $iptables -A INPUT ${LOG}"-IN-ACC-EST " -m state --state ESTABLISHED
	    $iptables -A INPUT -j "$ACCEPT" -m state --state ESTABLISHED

	    # if two hosts have a tcp connection on fixed ports and
	    # one of the hosts crashes it will send a SYN to the
	    # peer if it comes back up. The peer sends back ACK as
	    # it thinks there is already a connection established.
	    # This ACK is INVALID and must be answered with RST
	    # otherwise long timeouts may occur (#46818).
#	    $LDA $iptables -A INPUT ${LOG}"-IN-REJECT-ACK " -m state --state INVALID -p tcp --tcp-flags SYN,RST,ACK ACK
#	    $iptables -A INPUT -j "$REJECT" -m state --state INVALID -p tcp --tcp-flags SYN,RST,ACK ACK
    done

    # need to accept icmp RELATED packets (bnc#382004)
    $LAA $IPTABLES -A INPUT ${LOG}"-IN-ACC-REL " -p icmp -m state --state RELATED
    $IPTABLES -A INPUT -j "$ACCEPT" -p icmp -m state --state RELATED
    $LAA $IP6TABLES -A INPUT ${LOG}"-IN-ACC-REL " -p icmpv6 -m state --state RELATED
    $IP6TABLES -A INPUT -j "$ACCEPT" -p icmpv6 -m state --state RELATED
}

have_bridgeinterfaces()
{
    local i
    for i in /sys/class/net/*/bridge; do
	[ -e "$i" ] && return 0
    done
    return 1
}

allow_bridgetraffic()
{
    local iptables
    case "$FW_FORWARD_ALLOW_BRIDGING" in
	yes) ;;
	no)
	    return
	    ;;
	auto|'')
	    have_bridgeinterfaces || return
	;;
    esac
    for iptables in "$IPTABLES" "$IP6TABLES"; do
	$iptables -A FORWARD -m physdev --physdev-is-bridged -j ACCEPT
    done
}

xen_forward_hack()
{
    local dev iptables

    if [ -n "$FW_FORWARD_ALWAYS_INOUT_DEV" ]; then
	warning "FW_FORWARD_ALWAYS_INOUT_DEV is deprecated and most likely not needed at all anymore"
    fi
    for iptables in "$IPTABLES" "$IP6TABLES"; do
	for dev in $FW_FORWARD_ALWAYS_INOUT_DEV; do
	    $iptables -A FORWARD -i $dev -o $dev -j ACCEPT
	done
    done
}

function set_basic_rules()
{
    local itype

    check_ip6tables_support

    load_modules ip_tables ip_conntrack $FW_LOAD_MODULES

    if [ "$IP6TABLES" != ':' ]; then
	load_modules ip6table_filter ip6table_mangle
    fi
    
    # determine policy
    local DROP_JUMP
    if [ "$DROP" = "ACCEPT" ]; then
	DROP_JUMP="ACCEPT"
    else
	DROP_JUMP="DROP"
    fi

    reset_rules "$DROP_JUMP" ACCEPT "$DROP_JUMP"

    # loopback is always allowed
    for iptables in "$IPTABLES" "$IP6TABLES"; do
	$iptables -A INPUT  -j "$ACCEPT" -i lo
	$iptables -A OUTPUT -j "$ACCEPT" -o lo
	if [ "$FW_LO_NOTRACK" != 'no' ]; then
	    $iptables -t raw -A PREROUTING -j NOTRACK -i lo
	    $iptables -t raw -A OUTPUT -j NOTRACK -o lo
	fi
    done

    # Special REJECT function #
    
    $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 -N reject_func
    if [ "$IP6TABLES_HAVE_REJECT" = 1 ]; then
	$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?
    fi
    # sometimes the above lines do not work despite prior checks, so add drop
    # always to be on the safe side
    $IP6TABLES -A reject_func -j DROP

    allow_bridgetraffic
    xen_forward_hack

    # workaround for ip6tables without state matching
    if [ "$IP6TABLES_HAVE_STATE" != 1 ]; then
	for itype in $stateless_icmpv6_types $safe_icmpv6_replies; do
	    $LAA $IP6TABLES -A INPUT ${LOG}"-IN-ACC-ICMP " -p icmpv6 --icmpv6-type $itype
	    $IP6TABLES -A INPUT -j "$ACCEPT" -p icmpv6 --icmpv6-type $itype
	done
	if [ "$FW_ALLOW_PING_FW" = yes ]; then
	    $LAA $IP6TABLES -A INPUT ${LOG}"-`rulelog $chain`-ACC-PING "  -p icmpv6 --icmpv6-type echo-request
	    $IP6TABLES -A INPUT -j "$ACCEPT" -p icmpv6 --icmpv6-type echo-request
	fi
	$LAA $IP6TABLES -A INPUT -p tcp --tcp-flags ACK ACK ${LOG}"-IN-ACC-TCP "
	$IP6TABLES -A INPUT -p tcp --tcp-flags ACK ACK -j "$ACCEPT"
	# Drop all until IPv6 is really supported
	$LDA $IP6TABLES -A INPUT ${LOG}"-IN-IPv6_PROHIB "
	if [ "$FW_IPv6" = "drop" -o "$IP6TABLES_HAVE_REJECT" != 1 ]; then
	    $IP6TABLES -A INPUT -j "$DROP"
	else
	    $IP6TABLES -A INPUT -j "$REJECT"
	fi
	$IP6TABLES -A OUTPUT -p icmpv6 -j "$ACCEPT"
	$IP6TABLES -A OUTPUT -p tcp -j "$ACCEPT"
	if [ "$IP6TABLES_HAVE_REJECT" != 1 -o "$FW_IPv6_REJECT_OUTGOING" = "no" ]; then
	    $IP6TABLES -A OUTPUT -j "$DROP"
	else
	    $IP6TABLES -A OUTPUT -j "$REJECT"
	fi
	IP6TABLES=":" # disable further rules
    fi

    allow_basic_established

    # make sure basic rules get committed even if there are errors later
    [ -n "$USE_IPTABLES_BATCH" ] && iptables_batch_commitpoint
}

handle_initscripts()
{
    local i
    case "$INITSCRIPTS" in
	on)
	    for i in SuSEfirewall2_init SuSEfirewall2_setup; do
		/sbin/insserv -f $i
	    done
	    ;;
	off)
	    for i in SuSEfirewall2_setup SuSEfirewall2_init; do
		/sbin/insserv -r -f $i
	    done
	    ;;
    esac
}

# set $dev to actual name of device $1
getdevinfo()
{
    local dev=
    local d="$1"
    local var="$2"
    if [ -d /sys/class/net/"$d" ]; then
	dev="$d"
    else
	local deprecatediface=
	if [ -x /sbin/getcfg-interface ]; then
	    dev=`/sbin/getcfg-interface "$d"`
	elif [ -x "$hwdesc2iface" ]; then
	    case "$d" in
		*-id-*) dev=`$hwdesc2iface id ${d#*-id-}`; deprecatediface=1 ;;
		*-bus-*) dev=`$hwdesc2iface bus ${d#*-bus-}`; deprecatediface=1 ;;
	    esac
	fi

	if [ -z "$dev" -o ! -d /sys/class/net/"$dev" ]; then
	    return 1
	fi
	
	if [ -n "$deprecatediface" ]; then
	    warning "$var: the notation '$d' is deprecated. Please use '$dev' instead" 
	fi
    fi

    echo "$dev"
    return 0
}

setlock()
{
    if [ "$remove_bootlock" -ne 0 ]; then
	rm -f "$BOOTLOCKFILE"
    fi
    ### Locking mechanism
    if [ "$needlock" -ne 0 ]; then
	if [ -e "$BOOTLOCKFILE" ]; then
	    die 0 "$BOOTLOCKFILE exists which means system boot in progress, exit." 
	fi
	if [ -e "$LOCKFILE" ]; then
	    read PID < $LOCKFILE
	    message "Another SuSEfirewall2 with PID $PID found, waiting ..."
	    i=0
	    while [ -e "$LOCKFILE" -a "$i" -lt 15 ]; do
		sleep 2
		i=$(( i + 1 ))
	    done
	    if [ -e "$LOCKFILE" ]; then
		message "Lockfile is still there, ignoring it ..."
		kill -TERM $PID
		sleep 2
		kill -KILL $PID
		rm -f "$LOCKFILE"
	    fi
	fi
	removeonexit "$LOCKFILE"
	set -o noclobber
	echo "$$" > $LOCKFILE || exit 1
	set +o noclobber
    fi
    if [ "$create_bootlock" -eq 1 ]; then
	touch "$BOOTLOCKFILE"
    fi
}

##
## function definitions for full featured mode
##

# Provide empty functions for transparent hook support for customised rules
fw_custom_after_chain_creation() { true; }
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; }

evaluateinterfaces()
{
    local devs=""
    local var dev
    local zone="$1"
    var="FW_DEV_`cibiz $zone`"
    eval set -- \$$var
    for dev in "$@" ; do
	if [ "$dev" = 'any' ]; then
	    if [ -n "$FW_ZONE_DEFAULT" ]; then
		error "zone '$FW_ZONE_DEFAULT' is already default, ignoring 'any' in '$var'"
	    else
		FW_ZONE_DEFAULT="$zone"
	    fi
	    continue
	elif [ "$dev" = 'auto' ]; then
	    warning "ignoring deprecated interface 'auto' in $var"
	    continue
	fi
	dev=`getdevinfo "$dev" "$var"` || continue
	case "$dev" in *:*) continue; ;; esac

	devs="$devs $dev"
    done
    set -- $devs
    eval FW_DEV_$zone="\$*"
}

#sets iface_$name=$zone
check_interfaces_unique()
{
    local zone devs d z
    for zone in $all_zones; do
	eval devs="\$FW_DEV_$zone"
	for d in $devs; do
	    [ -z "$d" ] && continue
	    d=${d//[^A-Za-z0-9]/_}
	    eval z=\${iface_$d}
	    if [ -z "$z" ]; then
		eval iface_$d=$zone
	    else
		error "$d already in zone '$z' but also configured for '$zone'"
	    fi
	done
    done
}

source_config_for_iface()
{
    local iface="$1"
    local dir=/etc/sysconfig/network
    if [ -x /sbin/getcfg ] ; then
	eval `/sbin/getcfg -d $dir -f ifcfg- -- $iface 2>/dev/null`
	cfg="$HWD_CONFIG_0"
    fi
    if [ -z "$cfg" ]; then
	cfg=$iface
    fi
    . $dir/ifcfg-$cfg 2>/dev/null
}

check_iface_override()
{
    local iface="$1"
    local f="$STATUSDIR/override/interfaces/$iface/zone"
    local z dummy
    test -e "$f" || return 0
    read z dummy < "$f" || return 0
    echo "$z"
}

autodetect_interfaces()
{
    local d z
    local have_override=''
    set -- /sys/class/net/*
    for d in "$@"; do
	test -d "$d" || continue
	d="${d#/sys/class/net/}"
	[ -z "$d" -o "$d" = 'lo' -o "$d" = 'sit0' ] && continue
	d=${d//[^A-Za-z0-9]/_}
	unset z
	if [ "$FW_RUNTIME_OVERRIDE" != 'no' ]; then
	    z=`check_iface_override $d`
	    if [ -n "$z" ]; then
		eval iface_$d=$z
		if eval [ -n "\"\$zone_$z\"" ]; then
		    message "runtime zone override '$z' for interface '$d'"
		    have_override=1
		    continue
		else
		    error "invalid zone '$z' as override for interface '$d'"
		fi
	    fi
	fi
	eval z=\${iface_$d}
	[ -n "$z" ] && continue
	eval [ -n "\"\$seen_$d\"" ] && continue
	eval local seen_$d=1
	z=`source_config_for_iface $d && echo $FW_ZONE`
	if [ -n "$z" ]; then
	    if eval [ -n "\"\$zone_$z\"" ]; then
		eval FW_DEV_$z="\"\$FW_DEV_$z \$d\""
		#" fix vim syntax
		eval iface_$d=$z
	    else
		error "invalid zone '$z' specified for interface '$d'"
	    fi
	elif [ -n "$FW_ZONE_DEFAULT" -a "$FW_ZONE_DEFAULT" != 'no' ]; then
	    message "using default zone '$FW_ZONE_DEFAULT' for interface $d"
	    z="$FW_ZONE_DEFAULT"
	    eval FW_DEV_$z="\"\$FW_DEV_$z \$d\""
	    #" fix vim syntax
	    eval iface_$d=$z
	else
	    warning "no firewall zone defined for interface $d"
	fi
    done

    # runtime override, we have to reconstruct FW_DEV_*
    if [ -n "$have_override" ]; then
	for z in $all_zones; do
	    eval "FW_DEV_$z=''"
	done
	for d in ${!iface_*}; do
	    eval z="\$$d"
	    eval "FW_DEV_$z=\"\$FW_DEV_$z ${d#iface_}\""
	done
    fi
}

write_interface_status()
{
    local d z
    mkdir -p "$STATUSDIR"/status/interfaces
    for d in "$STATUSDIR/status/interfaces/"*; do
	d=${d##*/}
	[ "$d" != '*' ] || break
	d=${d//[^A-Za-z0-9]/_}
	eval z="\$iface_$d"
	if [ -z "$z" ]; then
	    rm -rf "$STATUSDIR/status/interfaces/$d"
	else
	    eval local seen_$d=1
	    echo $z > "$STATUSDIR/status/interfaces/$d/zone"
	fi
    done
    for d in ${!iface_*}; do
	eval z="\$$d"
	d=${d#iface_}
	eval [ -n "\"\$seen_$d\"" ] && continue
	mkdir "$STATUSDIR/status/interfaces/$d"
	echo $z > "$STATUSDIR/status/interfaces/$d/zone"
    done
}

write_zone_status()
{
    local v z
    mkdir -p "$STATUSDIR/status/zones"
    for z in "$STATUSDIR/status/zones/"*; do
	z=${z##*/}
	[ "$z" != '*' ] || break
	z=${z//[^A-Za-z0-9]/_}
	eval v="\$zone_$d"
	if [ -z "$v" ]; then
	    rm -rf "$STATUSDIR/status/zones/$z"
	else
	    eval local seen_$z=1
	fi
    done
    for z in $all_zones; do
	eval [ -n "\"\$seen_$z\"" ] && continue
	mkdir "$STATUSDIR/status/zones/$z"
    done
}

write_status()
{
    [ "$MODE" != "debug" ] || return
    [ "$FW_WRITE_STATUS" != "no" ] || return

    write_interface_status
    write_zone_status
}

parse_interfaces()
{
    local zone devs var

    for zone in $all_zones; do
	evaluateinterfaces $zone
    done
    if [ -z "$FW_ZONE_DEFAULT" ]; then
	FW_ZONE_DEFAULT='ext'
	warning "no default firewall zone defined, assuming 'ext'"
    fi
}

process_masq_dev()
{
    local devs=""
    local dev
    set -- $FW_MASQ_DEV
    for dev in "$@" ; do
	if [ "$dev" = 'auto' ]; then
	    warning "ignoring deprecated interface 'auto' in FW_MASQ_DEV"
	    continue
	fi
	# zone specified?
	if [ "$dev" != "${dev#zone:}" ]; then
	    dev=${dev#zone:}
	    if eval [ -n "\"\$zone_$dev\"" ]; then
		eval devs="\"\$devs \$FW_DEV_$dev\""
		continue
	    fi
	fi
	dev=`getdevinfo "$dev" FW_MASQ_DEV` || continue
	case "$dev" in *:*) continue; ;; esac

	devs="$devs $dev"
    done
    FW_MASQ_DEV="$devs"
}

load_customrules()
{
    ### Load custom rules
    if [ -n "$FW_CUSTOMRULES" ]; then
	if [ ! -r "$FW_CUSTOMRULES" ]; then
	    die 1 "Firewall customary rules file can not be read from $FW_CUSTOMRULES"
	fi
	. "$FW_CUSTOMRULES"
	message "Firewall customary rules loaded from $FW_CUSTOMRULES"
    fi
}

check_interfaces()
{
    local v
    for zone in $all_zones; do
	eval v="\$FW_DEV_$zone"
	[ -n "$v" ] && return
    done
    warning 'no interface active'
}

verify_parameters()
{
    if [ "$FW_ROUTE" = no ]; then
	if [ "$FW_MASQUERADE" = yes ]; then
	    warning 'FW_ROUTE needs to be set to yes for masquerading to work!'
	fi
	if [ "$FW_ALLOW_CLASS_ROUTING" = yes ]; then
	    warning 'FW_ROUTE needs to be set to yes for FW_ALLOW_CLASS_ROUTING to work!'
	fi
	if [ "$FW_ALLOW_PING_DMZ" = yes -o "$FW_ALLOW_PING_EXT" = yes ]; then
	    warning 'FW_ROUTE needs to be set to yes for FW_ALLOW_PING_EXT and/or FW_ALLOW_PING_DMZ to work!'
	fi
    fi

    if [ "$FW_MASQUERADE" = no ]; then
	[ -n "$FW_MASQ_NETS" -a "$FW_MASQ_NETS" != "0/0" ] && warning 'FW_MASQ_NETS needs FW_MASQUERADE set to yes to work!'
	[ -n "$FW_FORWARD_MASQ" ] && warning 'FW_FORWARD_MASQ needs FW_MASQUERADE set to yes to work!'
    fi
}

# Turn ip forwarding on if configured
switch_on_ip_forwarding()
{
    if [ "$FW_ROUTE" = yes ]; then
	setproc 1 /proc/sys/net/ipv4/ip_forward
    else
	setproc 0 /proc/sys/net/ipv4/ip_forward
    fi
}

# warn user if device to masquerade is  from a non private network
# 0/0 has to be skipped here, otherwise the spoof rules would block
# anything
verify_masq_nets()
{
    local nets net1
    for nets in $FW_MASQ_NETS ; do
	IFS=, eval set -- \$nets
	net1="$1"

	# skip 0/0
	test "$net1" = "0/0" && continue

	IFS=/ eval set -- \$net1

	[ -z "$2" ] && continue

	case "$1" in
	    10.*|172.1[6789].*|172.2[0-9].*|172.3[01].*|192.168.*) ;;
	    *) warning "The network $net1 you want to masquerade is not from a private network " \
		    'like 10.0.0.0/8, 172.16.0.0/12 or 192.168.0.0/16'
	esac
    done
}

#################################
# Configuring more kernel stuff #
#################################
set_proc_stuff()
{
    if [ "$FW_KERNEL_SECURITY" != no ]; then
	setproc 1 /proc/sys/net/ipv4/icmp_echo_ignore_broadcasts 
# test "$FW_ALLOW_PING_FW" = yes || setproc 1 /proc/sys/net/ipv4/icmp_echo_ignore_all  # XXX
	setproc 1 /proc/sys/net/ipv4/ip_always_defrag  # XXX not there?
	setproc 1 /proc/sys/net/ipv4/icmp_ignore_bogus_error_responses 
	setproc 5 /proc/sys/net/ipv4/icmp_echoreply_rate 
	setproc 5 /proc/sys/net/ipv4/icmp_destunreach_rate 
	setproc 5 /proc/sys/net/ipv4/icmp_paramprob_rate 
	setproc 6 /proc/sys/net/ipv4/icmp_timeexceed_rate 
	setproc 20 /proc/sys/net/ipv4/ipfrag_time 
	for i in /proc/sys/net/ipv4/conf/*; do
	    setproc 1 $i/log_martians 
	    setproc 0 $i/bootp_relay 
	    [ "$FW_ROUTE" != yes ] && setproc 0 $i/forwarding
	    setproc 0 $i/proxy_arp 
	    setproc 1 $i/secure_redirects 
	    #setproc 0 $i/accept_redirects # let kernel decide this
	    setproc 0 $i/accept_source_route 
	    setproc 1 $i/rp_filter 
	done
	setproc 1 /proc/sys/net/ipv4/route/flush
    fi
}

# Make input/forward chains
create_chains()
{
    local iptables
    for iptables in "$IPTABLES" "$IP6TABLES"; do
	for TARGET in input forward; do
	    for CHAIN in $all_zones; do
		$iptables -N ${TARGET}_${CHAIN}
	    done
	done
    done
}

### configurations ###

parse_configurations()
{
    local var zone configurations config

    for zone in $input_zones; do
	var="FW_CONFIGURATIONS_`cibiz $zone`"
	eval configurations="\"\$$var\""

	for config in $configurations; do
	    local TCP=''
	    local UDP=''
	    local RPC=''
	    local IP=''
	    local BROADCAST=''
	    local RELATED=''
	    local MODULES=''

	    # XXX: could use a sub shell in order to enforce use of known variables only
	    if [ ! -r $CONFIGURATIONSDIR_0/$config ] || ! . $CONFIGURATIONSDIR_0/$config; then
		if [ ! -r $CONFIGURATIONSDIR_1/$config ] || ! . $CONFIGURATIONSDIR_1/$config; then
		    warning "config '$config' not available"
		    continue
		fi
	    fi

	    for var in TCP UDP RPC IP; do
		eval [ -n \"\$$var\" ] \&\& FW_SERVICES_`cibiz $zone`_$var="\"\$FW_SERVICES_`cibiz $zone`_$var \$$var\""
	    done

	    if [ -n "$BROADCAST" ]; then
		var=FW_ALLOW_FW_BROADCAST_`cibiz $zone`
		eval allow="\"\$$var\""
		if [ "$allow" != 'yes' ]; then
		    # 'no' is ignored later anyways
		    eval $var="\"\$$var \$BROADCAST\""
		fi
	    fi
	    
	    if [ -n "$RELATED" ]; then
		eval FW_SERVICES_ACCEPT_RELATED_`cibiz $zone`="\"\$FW_SERVICES_ACCEPT_RELATED_`cibiz $zone` \$RELATED\""
	    fi

	    if [ -n "$MODULES" ]; then
		eval FW_LOAD_MODULES="\"\$FW_LOAD_MODULES \$MODULES\""
	    fi

	done
    done
}

### handling of broadcasts ###

check_convert_old_broadcast()
{
    if [ -n "$FW_ALLOW_FW_BROADCAST" -o -n "$FW_IGNORE_FW_BROADCAST" ]; then
	need oldbroadcast
	convert_old_broadcast
    fi
}

drop_broadcast()
{
    local allow ignore port zone

    for zone in $input_zones; do
	eval allow="\$FW_ALLOW_FW_BROADCAST_`cibiz $zone`"
	eval ignore="\$FW_IGNORE_FW_BROADCAST_`cibiz $zone`"

	local match="-A input_$zone -m pkttype --pkt-type broadcast"

	for port in $allow; do
	    [ $port = no -o $port = yes ] && continue
	    $LAA $IPTABLES $match -p udp --dport $port ${LOG}"-ACC-BCAST${zone:0:1} "
	    $IPTABLES $match -p udp --dport $port -j "$ACCEPT"
	done

	if [ "$ignore" != yes ]; then
	    for port in $ignore; do
		[ $port = no ] && continue
		$IPTABLES $match -p udp --dport $port -j DROP
	    done

	    if [ "$allow" != 'yes' ]; then
		$LDA $IPTABLES $match ${LOG}"-DROP-BCAST${zone:0:1} "
	    fi
	fi

	if [ "$allow" != 'yes' ]; then
	    $IPTABLES $match -j DROP # no need to send icmp for broadcasts
	fi
    done
}

### zones ###

parse_zones()
{
    local zone
    for zone in $FW_ZONES; do
	case $zone in
	    [Ii][Nn][Tt]|[Ee][Xx][Tt]|[Dd][Mm][Zz])
		error "FW_ZONES=$zone ignored" ;;
	    *)
		if [ "$zone" != "${zone//[^A-Za-z0-9]/_}" ]; then
		    error "ignoring invalid zone name $zone in FW_ZONES"
		else
		    all_zones="$all_zones $zone"
		fi
		;;
	esac
    done
    for zone in $all_zones; do
	eval "zone_$zone=0"
    done
}

remove_unused_zones()
{
    local zone zones devs
    for zone in $all_zones; do
	eval devs="\$FW_DEV_$zone"
	if [ -n "$devs" -o "$ipsec_chain" = $zone -o "$FW_ZONE_DEFAULT" = "$zone" ]; then
	    if [ -z "$zones" ]; then
		zones=$zone
	    else
		zones="$zones $zone"
	    fi
	fi
    done

    [ "$all_zones" != "$zones" ] && all_zones="$zones"
}

# convert if built in zone, eg ext -> EXT
cibiz()
{
    case $1 in
	int) echo INT ;;
	ext) echo EXT ;;
	dmz) echo DMZ ;;
	*)   echo "$1" ;;
    esac
}

### IPsec ###

parse_ipsec()
{
    if [ "$FW_IPSEC_TRUST" = yes ]; then
	ipsec_chain="int"
    elif [ "$FW_IPSEC_TRUST" = no ]; then
	:
    elif [ -n "$FW_IPSEC_TRUST" ]; then
	for zone in $all_zones; do
	    if [ "$FW_IPSEC_TRUST" = "$zone" ]; then
		ipsec_chain="$zone"
		break;
	    fi
	done
	if [ -z "$ipsec_chain" ]; then
	    warning "FW_IPSEC_TRUST: $FW_IPSEC_TRUST is no valid zone"
	fi
    fi
}

allow_ipsec()
{
    if [ -n "$ipsec_chain" ]; then
	$IPTABLES -A INPUT -j "input_$ipsec_chain" $IPSEC_INPUT_MATCH
	$IPTABLES -A FORWARD -j "forward_$ipsec_chain" $IPSEC_INPUT_MATCH
	$IPTABLES -A FORWARD -j "forward_$ipsec_chain" $IPSEC_OUTPUT_MATCH
    fi
}

#####################################
# Rule split up - forking to chains #
#####################################
# ipv4 and ipv6
fork_to_chains()
{
    local iptables
    local zone
    local dev
    local devs
    local var val

    for iptables in "$IPTABLES" "$IP6TABLES"; do
	for zone in $saved_input_zones; do
	    var="FW_PROTECT_FROM_`cibiz $zone`"
	    eval val="\"\$$var\""
	    if [ "$val" = 'notrack' ]; then
		# already have rules for that
		continue
	    fi
	    eval devs="\$FW_DEV_$zone"
	    for dev in $devs; do
		$iptables -A INPUT -j input_$zone -i $dev
	    done
	done
	if [ -n "$FW_ZONE_DEFAULT" -a "$FW_ZONE_DEFAULT" != 'no' ]; then
	    $iptables -A INPUT -j "input_$FW_ZONE_DEFAULT"
	fi
	if [ "$FW_ROUTE" = yes ]; then
	    for zone in $forward_zones; do
		eval devs="\$FW_DEV_$zone"
		for dev in $devs; do
		    $iptables -A FORWARD -j forward_$zone -i $dev
		done
	    done
	fi
    done
}

# ipv4 and ipv6
finish_chains()
{
    local iptables
    for iptables in "$IPTABLES" "$IP6TABLES"; do
	# anything which is now not in the input_* chains is evil
	$LDAC $iptables -A INPUT ${LOG}"-IN-ILL-TARGET " 
	$iptables -A INPUT -j "$DROP"

	$LDAC $iptables -A FORWARD ${LOG}"-FWD-ILL-ROUTING "
	if [ "$FW_ROUTE" = yes ]; then
	    $iptables -A FORWARD -j "$DROP" # this is an unneeded rule, but looks nice :)
	fi

	$iptables -A OUTPUT -j ACCEPT -m state --state NEW,ESTABLISHED,RELATED
	$LDAC $iptables -A OUTPUT ${LOG}"-OUT-ERROR " 
	# we want to let locally generated packets out since our task is not
	# to protect the world from us, but protect us from the world ;)
	# policy is ACCEPT $iptables -A OUTPUT -j ACCEPT
    done

    # MSS stuff needs this?
    if [ "$FW_ROUTE" = yes ]; then
	$IPTABLES -I FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu
    fi
}

# Protect the firewall from the internal network? #
protect_from_internal()
{
    local iptables zone devs dev chain
    local newzones=
    for zone in $input_zones; do

	if [ "$zone" = "int" -a "$FW_PROTECT_FROM_INTERNAL" = "no" ]; then
	    val="no"
	    warning "FW_PROTECT_FROM_INTERNAL is deprecated, use FW_PROTECT_FROM_INT instead"
	else
	    var="FW_PROTECT_FROM_`cibiz $zone`"
	    eval val="\"\$$var\""
	fi

	if [ "$val" = notrack ]; then
	    eval devs="\$FW_DEV_$zone"
	    for dev in $devs; do
		for iptables in "$IPTABLES" "$IP6TABLES"; do
		    $iptables -t raw -i $dev -I PREROUTING -j NOTRACK
		    $iptables -t raw -o $dev -I OUTPUT -j NOTRACK
		    $iptables -i $dev -I INPUT -j ACCEPT
		    $iptables -o $dev -I OUTPUT -j ACCEPT
		done
	    done
	elif [ "$val" = no ]; then
	    chain=input_$zone
	    for iptables in "$IPTABLES" "$IP6TABLES"; do
		$LAA $iptables -A $chain ${LOG}"-`rulelog $chain`-ACC-ALL " 
		$iptables -A $chain -j "$ACCEPT"
	    done
	else
	    if [ -z "$newzones" ]; then
		newzones="$zone"
	    else
		newzones="$newzones $zone"
	    fi
	fi
    done

    if [ "$input_zones" != "$newzones" ]; then 
	saved_input_zones="$input_zones" # need that for fork_to_chains
	input_zones="$newzones"
    fi
}

allow_related()
{
    local var
    local services target service proto net
    local iptables zone chain

    for zone in $input_zones; do
	chain=input_$zone
	var="FW_SERVICES_ACCEPT_RELATED_`cibiz $zone`"
	eval services="\"\$$var\""

	for service in $services; do
	    IFS=, eval set -- \$service
	    
	    net="${1:-0/0}"
	    proto="$2"
	    port="$3"
	    sport="$4"

	    iptables="$IPTABLES $IP6TABLES"
	    case "$net" in
		*:*) iptables="$IP6TABLES" ;;
		[0-9]*.*.*.*) iptables="$IPTABLES" ;;
	    esac

	    if check_proto_port "$proto" "$port" "$sport" "$var"; then
		for iptables in $iptables; do
		    $LAA $iptables -A $chain -s $net $proto $rport $rsport -m state --state RELATED ${LOG}"-`rulelog $chain`-REL "
		    $iptables -A $chain -s $net $proto $rport $rsport -j ACCEPT -m state --state RELATED
		done
	    fi
	done
    done
}

# ICMP stuff
allow_icmp()
{
    local chain dev itype zone devs
    # INPUT ICMP rules
    if [ "$FW_ALLOW_FW_SOURCEQUENCH" != "no" ]; then
	for chain in $input_zones; do
	    chain=input_$chain
	    $LAA $IPTABLES -A $chain ${LOG}"-`rulelog $chain`-ACC-SOURCEQUENCH "  -p icmp --icmp-type source-quench
	    $IPTABLES -A $chain -j "$ACCEPT" -p icmp --icmp-type source-quench
	done
    fi

    if [ "$FW_ALLOW_PING_FW" = yes ]; then
	for chain in $input_zones; do
	    chain=input_$chain
	    $LAA $IPTABLES -A $chain ${LOG}"-`rulelog $chain`-ACC-PING "  -p icmp --icmp-type echo-request
	    $IPTABLES -A $chain -j "$ACCEPT" -p icmp --icmp-type echo-request

	    $LAA $IP6TABLES -A $chain ${LOG}"-`rulelog $chain`-ACC-PING "  -p icmpv6 --icmpv6-type echo-request
	    $IP6TABLES -A $chain -j "$ACCEPT" -p icmpv6 --icmpv6-type echo-request
	done
    fi

# not needed as there is a generic accept rule for ICMP RELATED packets
#    local icmp_types="$safe_icmp_replies"
#    for itype in $icmp_types; do
#	for chain in $input_zones; do
#	    chain=input_$chain
#	    $IPTABLES -A $chain ${LOG}"-`rulelog $chain`-ACC-ICMP "  -m state --state ESTABLISHED,RELATED -p icmp --icmp-type $itype
#	    $IPTABLES -A $chain -j "$ACCEPT" -m state --state ESTABLISHED,RELATED -p icmp --icmp-type $itype
#	done
#    done
#    icmp_types="$safe_icmpv6_replies"
#    for itype in $icmp_types; do
#	for chain in $input_zones; do
#	    chain=input_$chain
#	    $IP6TABLES -A $chain ${LOG}"-`rulelog $chain`-ACC-ICMP " -m state --state ESTABLISHED,RELATED  -p icmpv6 --icmpv6-type $itype
#	    $IP6TABLES -A $chain -j "$ACCEPT" -m state --state ESTABLISHED,RELATED -p icmpv6 --icmpv6-type $itype
#	done
#    done
    # DROP rules for input ICMP are after trusted handling (see below)
    
    # state matching for these does not work
    icmp_types="$stateless_icmpv6_types"
    for itype in $icmp_types; do
	for chain in $input_zones; do
	    chain=input_$chain
	    $LAA $IP6TABLES -A $chain ${LOG}"-`rulelog $chain`-ACC-ICMP " -p icmpv6 --icmpv6-type $itype
	    $IP6TABLES -A $chain -j "$ACCEPT" -p icmpv6 --icmpv6-type $itype
	done
    done
    $IP6TABLES -A OUTPUT -j "$ACCEPT" -p icmpv6 # XXX: some are not catched by conntrack, should be fixed in kernel
}

allow_forward_icmp_echo()
{
    [ "$FW_ROUTE" != "yes" ] && return

    local zone chain var val

    # FORWARD ICMP rules
    for zone in $forward_zones; do
	var="FW_ALLOW_PING_`cibiz $zone`"
	eval val="\"\$$var\""

	[ "$val" != yes ] && continue

	eval devs="\$FW_DEV_$zone"

	for dev in $devs; do
	    for chain in $forward_zones; do
		[ "$chain" = "$zone" ] && continue

		chain=forward_$chain
		$LAA $IPTABLES -A $chain ${LOG}"-`rulelog $chain`-ACC-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
		$LAA $IP6TABLES -A $chain ${LOG}"-`rulelog $chain`-ACC-PING "  -p icmpv6 --icmpv6-type echo-request -o $dev
		$IP6TABLES -A $chain -j "$ACCEPT" -m state --state NEW -p icmpv6 --icmpv6-type echo-request -o $dev
	    done
	done
	chain=forward_$zone
	$LAA $IPTABLES -A $chain ${LOG}"-`rulelog $chain`-ACC-PING "  -p icmp --icmp-type echo-reply
	$IPTABLES -A $chain -j "$ACCEPT"  -m state --state ESTABLISHED -p icmp --icmp-type echo-reply
	$LAA $IP6TABLES -A $chain ${LOG}"-`rulelog $chain`-ACC-PING "  -p icmpv6 --icmpv6-type echo-reply
	$IP6TABLES -A $chain -j "$ACCEPT"  -m state --state ESTABLISHED -p icmpv6 --icmpv6-type echo-reply
    done
    # drop rule for forwarding chains are at the end of the forwarding rules
}

#############################
# Trusted Networks Handling #
#############################
process_trusted_nets()
{
    local nets net chain
    for nets in $FW_TRUSTED_NETS; do
	IFS=, eval set -- \$nets
	net="$1"
	proto="$2"
	port="$3"
	if [ -n "$4" ]; then
	    error "Too many arguments in FW_TRUSTED_NETS -> $nets"
	elif [ -z "$net" ]; then
	    error "network parameter of FW_TRUSTED_NETS is empty -> $nets"
	elif [ -z "$proto" -a -n "$port" ]; then
	    error "need to specify protocol for port $port in FW_TRUSTED_NETS"
	elif check_proto_port "$proto" "$port" "" 'FW_TRUSTED_NETS'; then
	    for chain in $input_zones; do # trusted networks can be on any interface ...
		chain=input_$chain
		$LAC $IPTABLES -A $chain ${LOG}"-`rulelog $chain`-ACC-TRUST " -m state --state NEW -s $net $proto $port
		$LAA $IPTABLES -A $chain ${LOG}"-`rulelog $chain`-ACC-TRUST " -s $net $proto $port
		$IPTABLES -A $chain -j "$ACCEPT"  -m state --state NEW,ESTABLISHED,RELATED -s $net $proto $port
	    done
	fi
    done
}

# determine port numbers of rpc services and generate a suitable iptables
# parameter fragment
#
# parameters: names of rpc services, e.g. ypbind mountd
rpcservicerules()
{
    perl "$SCRIPTSDIR/SuSEfirewall2-rpcinfo" "$@" 2>/dev/null
}

# parameters: REJECT|DROP
reject_or_drop_services()
{
    local action="$1"
    local var
    local services target service proto net port
    local iptables zone chain

    eval target=\$$action

    for zone in $input_zones; do
	chain=input_$zone
	var="FW_SERVICES_${action}_`cibiz $zone`"
	eval services="\"\$$var\""

	for service in $services; do
	    IFS=, eval set -- \$service

	    net="${1:-0/0}"
	    proto="$2"
	    port="$3"
	    sport="$4"

	    iptables="$IPTABLES $IP6TABLES"
	    case "$net" in
		*:*) iptables="$IP6TABLES" ;;
		[0-9]*.*.*.*) iptables="$IPTABLES" ;;
	    esac

	    if [ "$proto" = "_rpc_" ]; then
		rpcservicerules $service | while read ARG; do
		    $LDC $IPTABLES -A $chain ${LOG}"-`rulelog $chain`-$action " -m state --state NEW $ARG
		    $IPTABLES -A $chain -j "$target" $ARG
		done
	    elif check_proto_port "$proto" "$port" "$sport" "$var"; then
		for iptables in $iptables; do
		    $LDA $iptables -A $chain -s $net $proto $port $sport -m state --state NEW ${LOG}"-`rulelog $chain`-$action "
		    $iptables -A $chain -s $net $proto $port $sport -m state --state NEW -j "$target"
		done
	    fi
	done
    done
}

accept_services()
{
    local var
    local services target service proto net
    local iptables zone chain
    local ipt_recent_update ipt_recent_set ipt_recent_rcheck

    for zone in $input_zones; do
	chain=input_$zone
	var="FW_SERVICES_ACCEPT_`cibiz $zone`"
	eval services="\"\$$var\""

	for service in $services; do
	    ipt_recent_update=''
	    ipt_recent_set=''
	    ipt_recent_rcheck=''
	    IFS=, eval set -- \$service
	    if [ "$#" -lt 1 ]; then
		error "too few parameters in $var -> $service"
		continue
	    fi
	    
	    net="${1:-0/0}"
	    proto="$2"
	    port="$3"
	    sport="$4"

	    while [ "$#" -gt 4 ]; do
		case "$5" in
		    hitcount=*) ipt_recent_update="$ipt_recent_update --hitcount ${5#*=}"; shift ;;
		    blockseconds=*) ipt_recent_update="$ipt_recent_update --seconds ${5#*=}"; shift ;;
		    recentname=*)
			ipt_recent_update="$ipt_recent_update --name ${5#*=}"
			ipt_recent_set="$ipt_recent_set --name ${5#*=}"
			shift
			;;
		    *) error "unknown parameter $5 in $var -> $service"; continue 2 ;;
		esac
	    done

	    if [ -n "$ipt_recent_update" ]; then
		ipt_recent_rcheck="-m recent --rcheck$ipt_recent_update"
		ipt_recent_update="-m recent --update$ipt_recent_update --rttl"
		ipt_recent_set="-m recent --set$ipt_recent_set"
	    fi

	    iptables="$IPTABLES $IP6TABLES"
	    case "$net" in
		*:*) iptables="$IP6TABLES" ;;
		[0-9]*.*.*.*) iptables="$IPTABLES" ;;
	    esac

	    if [ "$proto" = "_rpc_" ]; then
		rpcservicerules $service | while read ARG; do
		    if [ -n "$ipt_recent_set" ]; then
			$LDC $IPTABLES -A $chain ${LOG}"-`rulelog $chain`-DROPr " $ARG -m state --state NEW $ipt_recent_rcheck
			$IPTABLES -A $chain -j "$DROP" $ARG -m state --state NEW $ipt_recent_update
		    fi
		    $LAC $IPTABLES -A $chain ${LOG}"-`rulelog $chain`-ACC " -m state --state NEW $ARG
		    $LAA $IPTABLES -A $chain ${LOG}"-`rulelog $chain`-ACC " $ARG
		    [ -n "$ipt_recent_set" ] && $IPTABLES -A $chain -j ACCEPT $ARG -m state --state NEW $ipt_recent_set
		    $IPTABLES -A $chain -j ACCEPT $ARG
		done
	    elif check_proto_port "$proto" "$port" "$sport" "$var"; then
		for iptables in $iptables; do
		    if [ -n "$ipt_recent_set" ]; then
			$LDC $iptables -A $chain ${LOG}"-`rulelog $chain`-DROPr " -s $net $proto $port $sport -m state --state NEW $ipt_recent_rcheck
			$iptables -A $chain -j "$DROP" -s $net $proto $port $sport -m state --state NEW $ipt_recent_update
		    fi
		    $LAC $iptables -A $chain -s $net $proto $port $sport -m state --state NEW ${LOG}"-`rulelog $chain`-ACC "
		    $LAA $iptables -A $chain -s $net $proto $port $sport ${LOG}"-`rulelog $chain`-ACC "
		    [ -n "$ipt_recent_set" ] && $iptables -A $chain -s $net $proto $port $sport -j ACCEPT -m state --state NEW $ipt_recent_set
		    $iptables -A $chain -s $net $proto $port $sport -j ACCEPT
		done
	    fi
	done
    done
}

allow_tcp_highports()
{
    local j chain
    for j in $FW_ALLOW_INCOMING_HIGHPORTS_TCP; do
	case "$j" in
	[Dd][Nn][Ss]) warning "FW_ALLOW_INCOMING_HIGHPORTS_TCP=DNS is no longer supported" ;;
	no) ;;
	yes)
	    deprecated 'FW_ALLOW_INCOMING_HIGHPORTS_TCP'
	    for chain in $input_zones; do
		chain=input_$chain
		$LAC $IPTABLES -A $chain ${LOG}"-`rulelog $chain`-ACC-HiTCP " -p tcp --dport 1024: --syn
		$LAA $IPTABLES -A $chain ${LOG}"-`rulelog $chain`-ACC-HiTCP " -p tcp --dport 1024:
		$IPTABLES -A $chain -j "$ACCEPT" -p tcp --dport 1024:
	    done
	    break;
	    ;;
	*)
	    deprecated 'FW_ALLOW_INCOMING_HIGHPORTS_TCP'
	    for chain in $input_zones; do
		chain=input_$chain
		$LAC $IPTABLES -A $chain ${LOG}"-`rulelog $chain`-ACC-HIGH " -p tcp --sport $j --dport 1024: --syn
		$LAA $IPTABLES -A $chain ${LOG}"-`rulelog $chain`-ACC-HIGH " -p tcp --sport $j --dport 1024:
		$IPTABLES -A $chain -j "$ACCEPT" -p tcp --sport $j --dport 1024:
	    done
	    ;;
	esac
    done
}

allow_rpc_services()
{
    local zone chain ports
    for zone in $input_zones; do
	chain=input_$zone
	eval ports="\$FW_SERVICES_`cibiz $zone`_RPC"
	rpcservicerules $ports | while read ARG; do
	    $LAC $IPTABLES -A $chain ${LOG}"-`rulelog $chain`-ACC-RPC " -m state --state NEW $ARG
	    $LAA $IPTABLES -A $chain ${LOG}"-`rulelog $chain`-ACC-RPC " $ARG
	    $IPTABLES -A $chain -j "$ACCEPT" $ARG
	done
    done
}

allow_ip_services()
{
    local proto zone iptables protos

    for zone in $input_zones; do
	chain=input_$zone
	eval protos="\$FW_SERVICES_`cibiz $zone`_IP"
	for iptables in "$IPTABLES" "$IP6TABLES"; do
	    for proto in $protos; do
		$LAA $iptables -A $chain ${LOG}"-`rulelog $chain`-ACC-IP " -p $proto
		$iptables -A $chain -j "$ACCEPT" -p $proto
	    done
	done
    done
}

allow_tcp_services()
{
    local port zone iptables ports

    for zone in $input_zones; do
	chain=input_$zone
	eval ports="\$FW_SERVICES_`cibiz $zone`_TCP"
	for iptables in "$IPTABLES" "$IP6TABLES"; do
	    for port in $ports; do
		$LAC $iptables -A $chain ${LOG}"-`rulelog $chain`-ACC-TCP " -p tcp --dport $port --syn
		$LAA $iptables -A $chain ${LOG}"-`rulelog $chain`-ACC-TCP " -p tcp --dport $port
		$iptables -A $chain -j "$ACCEPT" -p tcp --dport $port
	    done
	done
    done
}

# UDP Stuff
allow_udp_services()
{
    local port zone iptables ports

    for zone in $input_zones; do
	chain=input_$zone
	eval ports="\$FW_SERVICES_`cibiz $zone`_UDP"
	for iptables in "$IPTABLES" "$IP6TABLES"; do
	    for port in $ports; do
		$LAA $iptables -A $chain ${LOG}"-`rulelog $chain`-ACC-UDP " -p udp --dport $port
		$iptables -A $chain -j "$ACCEPT" -p udp --dport $port
	    done
	done
    done
}

allow_highports_udp()
{
    local j chain
    # checking "yes" in the loop allows you to log individual services plus
    # allowing all
    for j in $FW_ALLOW_INCOMING_HIGHPORTS_UDP; do
	case "$j" in
	    [Dd][Nn][Ss])
		    warning "FW_ALLOW_INCOMING_HIGHPORTS_UDP=DNS is no longer supported"
		    ;;
	    no) ;;
	    yes)
		deprecated 'FW_ALLOW_INCOMING_HIGHPORTS_UDP'
		for chain in $input_zones; do
		    chain=input_$chain
		    $LAC $IPTABLES -A $chain ${LOG}"-`rulelog $chain`-ACC-HiUDP " -m state --state NEW -p udp --dport 1024:
		    $LAA $IPTABLES -A $chain ${LOG}"-`rulelog $chain`-ACC-HiUDP " -p udp --dport 1024:
		    $IPTABLES -A $chain -j "$ACCEPT" -m state --state NEW -p udp --dport 1024:
		done
		break;
		;;
	    *)
		deprecated 'FW_ALLOW_INCOMING_HIGHPORTS_UDP'
		for chain in $input_zones; do
		    chain=input_$chain
		    $LAC $IPTABLES -A $chain ${LOG}"-`rulelog $chain`-ACC-HiUDP " -m state --state NEW -p udp --sport $j --dport 1024:
		    $LAA $IPTABLES -A $chain ${LOG}"-`rulelog $chain`-ACC-HiUDP " -p udp --sport $j --dport 1024:
		    $IPTABLES -A $chain -j "$ACCEPT" -m state --state NEW -p udp --sport $j --dport 1024:
		done
		;;
	esac
    done
}

# redirect packets from one port to another, opens ports in input_*
redirect_rules()
{
    local chain nets net1 net2 proto port1 port2
    local redirectinstalled
    for nets in $FW_REDIRECT; do
	IFS=, eval set -- \$nets

	net1="$1"
	net2="$2"
	proto="$3"
	port1="$4"
	port2="$5"
	
	if [ -n "$6" ]; then
	    error "Too many arguments in FW_REDIRECT -> $nets"
	elif [ -z "$net1" -o -z "$net2" -o -z "$proto" -o -z "$port1" -o -z "$port2" ]; then
	    error "Missing parameter in FW_REDIRECT -> $nets"
	elif [ "$proto" != tcp -a "$proto" != udp ]; then
	    error "FW_REDIRECT supports only tcp and udp -> $nets"
	else
	    net1=${net1/\!/\! }
	    net2=${net2/\!/\! }
	    $IPTABLES -A PREROUTING -t mangle -j MARK  -p $proto -s $net1 -d $net2 --dport $port1 --set-mark $mark_redir
	    $IPTABLES -A PREROUTING -t nat -j REDIRECT -p $proto -s $net1 -d $net2 --dport $port1 --to-ports $port2
	    redirectinstalled=1
	fi
    done

    if [ -n "$redirectinstalled" ]; then
	for chain in $input_zones; do
	    chain=input_$chain
	    $LAC $IPTABLES -A $chain ${LOG}"-`rulelog $chain`-ACC-REDIR " -m mark --mark $mark_redir -m state --state NEW
	    $LAA $IPTABLES -A $chain ${LOG}"-`rulelog $chain`-ACC-REDIR " -m mark --mark $mark_redir -m state --state NEW,ESTABLISHED,RELATED
	    $IPTABLES -A $chain -j "$ACCEPT" -m state --state NEW,ESTABLISHED,RELATED -m mark --mark $mark_redir
	done
    fi

}

allow_class_routing()
{
    local chain iface devs zone iptables

    if [ "$FW_ALLOW_CLASS_ROUTING" = 'yes' ]; then
	FW_ALLOW_CLASS_ROUTING="$forward_zones"
    elif [ "$FW_ALLOW_CLASS_ROUTING" = 'no' ]; then
	return
    fi
    
    # assuming that only traffic from $zone interface enter the
    # forward_$zone chain anyways, we don't need the -i parameter
    for zone in $FW_ALLOW_CLASS_ROUTING; do
	eval devs="\$FW_DEV_$zone"
	chain=forward_$zone
	for iface in $devs; do
	    for iptables in "$IPTABLES" "$IP6TABLES"; do
		$LAA $iptables -A $chain $LOG"-`rulelog $chain`-ACC-CLASS "  -o $iface
		$iptables -A $chain -j "$ACCEPT" -o $iface
	    done
	done
    done
}

allow_related_forward_icmp()
{
    local chain itype

    for chain in $forward_zones; do
	chain=forward_$chain
	for itype in $safe_icmp_replies; do
	    $LAA $IPTABLES -A $chain ${LOG}"-`rulelog $chain`-FWD-RELA"  -m state --state ESTABLISHED,RELATED -p icmp --icmp-type $itype
	    $IPTABLES -A $chain -j "$ACCEPT" -m state --state ESTABLISHED,RELATED -p icmp --icmp-type $itype
	done
	for itype in $safe_icmpv6_replies; do
	    $LAA $IP6TABLES -A $chain ${LOG}"-`rulelog $chain`-FWD-RELA " -m state --state ESTABLISHED,RELATED  -p icmpv6 --icmpv6-type $itype
	    $IP6TABLES -A $chain -j "$ACCEPT" -m state --state ESTABLISHED,RELATED -p icmpv6 --icmpv6-type $itype
	done
    done
}

# <source network>,<destination network>[,protocol[,port[,flags]]]
forwarding_rules()
{
    local nets net1 net2 flags more_args_in more_args_out chain iptables var services
    local target="$1"
    if [ "$target" = ACCEPT ]; then
	var="FW_FORWARD"
    else
	var="FW_FORWARD_${target}"
    fi
    eval services="\"\$$var\""
    for nets in $services; do
	IFS=, eval set -- \$nets

	net1="$1"
	net2="$2"
	proto="$3"
	port="$4"
	flags="$5"
	rport=""
	more_args_in=
	more_args_out=

	case "$flags" in
	    "") ;;
	    ipsec)
		more_args_in="$IPSEC_INPUT_MATCH"
		more_args_out="$IPSEC_OUTPUT_MATCH"
		;;
	    *)
		echo "Error: unsupported flag in FW_FORWARD: $flags"
		net1=""
		;;
	esac

	if ! check_proto_port "$proto" "$port" '' "FW_FORWARD"; then
	    continue
	fi

	if [ -n "$net1" -a -n "$net2" ]; then
	    if [ "${net1//:/_}" != "$net1" -o "${net2//:/_}" != "$net2" ]; then
		iptables=$IP6TABLES
	    else
		iptables=$IPTABLES
	    fi
	    for chain in $forward_zones; do
		chain=forward_$chain
		$LAC $iptables -A $chain ${LOG}"-`rulelog $chain`-${target:0:3}-FORW "  -s $net1 -d $net2 $proto $port -m state --state NEW $more_args_in
		$LAA $iptables -A $chain ${LOG}"-`rulelog $chain`-${target:0:3}-FORW "  -s $net1 -d $net2 $proto $port $more_args_in
		$iptables -A $chain -j "$target" -m state --state NEW,ESTABLISHED,RELATED -s $net1 -d $net2 $proto $port $more_args_in
		$iptables -A $chain -j "$target" -m state --state ESTABLISHED,RELATED -s $net2 -d $net1 $proto $rport $more_args_in
		if [ -n "$more_args_out" ]; then
		    $LAC $iptables -A $chain ${LOG}"-`rulelog $chain`-${target:0:3}-FORW "  -s $net1 -d $net2 $proto $port -m state --state NEW $more_args_out
		    $LAA $iptables -A $chain ${LOG}"-`rulelog $chain`-${target:0:3}-FORW "  -s $net1 -d $net2 $proto $port $more_args_out
		    $iptables -A $chain -j "$target" -m state --state NEW,ESTABLISHED,RELATED -s $net1 -d $net2 $proto $port $more_args_out
		    $iptables -A $chain -j "$target" -m state --state ESTABLISHED,RELATED -s $net2 -d $net1 $proto $rport $more_args_out
		fi
	    done
	else
	    error "too few parameters in $var -> $nets"
	fi
     done
}

masquerading_rules()
{
    local nets net1 net2 proto port dev snet2 sport
    local szone dzone sdev sdevs
    local z d
    local var='FW_NOMASQ_NETS'
    for nets in $FW_NOMASQ_NETS -- $FW_MASQ_NETS; do
	if [ "$nets" = '--' ]; then # cheap hack
	    var='FW_MASQ_NETS'
	    continue
	fi
	IFS=, eval set -- \$nets

	net1="$1"
	net2="$2"
	proto="$3"
	port="$4"
	rport=""

	if [ -n "$5" ]; then
   	    error "Too many arguments in $var -> $nets"
	elif [ -z "$net1" ]; then
	    error "source network must not be empty in $var -> $nets"
	elif check_proto_port "$proto" "$port" '' "$var"; then
	    net1=${net1/\!/\! }
	    net2=${net2/\!/\! }
	    snet2=""
	    if [ -n "$net2" ]; then
		snet2="-s $net2"
		net2="-d $net2"
	    fi

	    for dev in $FW_MASQ_DEV; do
		d=${dev//[^A-Za-z0-9]/_}
		eval z=\${iface_$d}

		if [ "$var" = "FW_NOMASQ_NETS" ]; then # cheap hack
		    $IPTABLES -A POSTROUTING -j ACCEPT -t nat -s $net1 $net2 $proto $port -o $dev
		    continue
		fi

		for dzone in $forward_zones; do
		    dzone=forward_$dzone
		    for szone in $forward_zones; do
			[ "$z" = "$szone" ] && continue
			eval sdevs="\$FW_DEV_$szone"
			for sdev in $sdevs; do
			    [ "$sdev" = "$dev" ] && continue
			    if [ "forward_$z" != "$dzone" ]; then
				#echo "$dzone: $sdev ($szone) -> $dev ($z)"
				$LAA $IPTABLES -A $dzone ${LOG}"-`rulelog $dzone`-ACC-MASQ "  -s $net1 $net2 $proto $port -i $sdev -o $dev
				$IPTABLES -A $dzone -j "$ACCEPT" -m state --state NEW,ESTABLISHED,RELATED -s $net1 $net2 $proto $port -i $sdev -o $dev
			    else
				#echo "$dzone: $sdev ($szone) <- $dev ($z)"
				# we need to allow the replies as well
				$LAA $IPTABLES -A $dzone -d $net1 $snet2 $proto $rport -i $dev -o $sdev ${LOG}"-`rulelog $dzone`-ACC-MASQ " -m state --state ESTABLISHED,RELATED
				$IPTABLES -A $dzone -d $net1 $snet2 $proto $rport -i $dev -o $sdev -j "$ACCEPT" -m state --state ESTABLISHED,RELATED
			    fi
			done
		    done
	        done

		$IPTABLES -A POSTROUTING -j MASQUERADE -t nat -s $net1 $net2 $proto $port -o $dev
	    done
	fi
    done
}

# <source network>,<ip to forward to>,<protocol>,<port>[,redirect port,[destination ip]]
forward_masquerading_rules()
{
    local nets net1 net2 proto port1 port2 lip
    for nets in $FW_FORWARD_MASQ; do
	IFS=, eval set -- \$nets

	net1="$1"
	net2="$2"
	proto="$3"
	port1="$4"
	port2="$5"
	lip="$6"

	case "$net2" in
	    */*|'')
		error "target must be a single host in FW_FORWARD_MASQ -> $nets"
		continue
		;;
	esac

	if [ -n "$7" ]; then
   	    error "too many arguments in FW_FORWARD_MASQ -> $nets"
	elif [ -z "$net1" ]; then
	    error "source network must not be empty in FW_FORWARD_MASQ -> $nets"
        elif [ "$proto" != tcp -a "$proto" != udp ]; then
	    error "The protocol with FW_FORWARD_MASQ must be tcp or udp -> $nets"
        elif [ -z "$port1" ]; then
	    error "Port missing in FW_FORWARD_MASQ -> $nets"
	else
	    net1=${net1/\!/\! }
	    net2=${net2/\!/\! }
	    proto="-p $proto"
	    test -z "$port2" && port2="$port1"
	    port1="--dport $port1"
	    dport2="--dport $port2"
	    port2=":${port2/:/-}"
	    test -n "$lip" && lip="-d $lip"
	    for dev in $FW_MASQ_DEV; do
		$IPTABLES -A PREROUTING -j DNAT -t nat $proto -s $net1 $lip $port1 --to-destination ${net2}${port2} -i $dev
		# to install minimal rule set we'd need to check if
		# $net1 is covered by $FW_MASQ_NETS. Not feasible in
		# bash code so just check for 0/0
		if [ "$FW_MASQ_NETS" != "0/0" ]; then
		    $IPTABLES -A POSTROUTING -j MASQUERADE -t nat -s $net1 -d $net2 $proto $dport2 -o $dev
		fi
	    done
	    for chain in $forward_zones; do
		chain=forward_$chain
		$LAC $IPTABLES -A $chain ${LOG}"-`rulelog $chain`-ACC-REVMASQ " $proto -s $net1 -d $net2 $dport2 -m state --state NEW
		$LAA $IPTABLES -A $chain ${LOG}"-`rulelog $chain`-ACC-REVMASQ " $proto -s $net1 -d $net2 $dport2
		$IPTABLES -A $chain -j "$ACCEPT" $proto -s $net1 -d $net2 $dport2
		$IPTABLES -A $chain -j "$ACCEPT" $proto -d $net1 -s $net2 -m state --state ESTABLISHED,RELATED
	    done
	fi
    done
}

# Special Logging + Deny #
drop_all()
{
    local chain
    local zone
    local drop
    local chainprefix='input_'

    for zone in $input_zones '--' $forward_zones; do

	if [ "$zone" = '--' ]; then
	    [ "$FW_ROUTE" != 'yes' ] && break
	    chainprefix='forward_'
	    continue
	fi

	chain="$chainprefix$zone"

	eval drop="\$FW_REJECT_`cibiz $zone`"
	if [ "$drop" = "yes" ]; then
	    drop="$REJECT"
	else
	    drop="$DROP"
	fi

	# log and drop multicast packets separately to not flood
	# other log targets (#155326, #538053)
	$LDA $IPTABLES -A $chain ${LOG}"-`rulelog $chain`-DROP-DEFLT " -m pkttype --pkt-type multicast
	$IPTABLES -A $chain -j "$DROP" -m pkttype --pkt-type multicast

	eval local ignore="\$FW_IGNORE_FW_BROADCAST_`cibiz $zone`"
	if [ "$ignore" != 'yes' ]; then
	    $LDA $IPTABLES -A $chain ${LOG}"-`rulelog $chain`-DROP-DEFLT " -m pkttype --pkt-type broadcast
	fi
	$IPTABLES -A $chain -j "$DROP" -m pkttype --pkt-type broadcast
	# some packet types are considered critical
	if [ -z "$LDC" ]; then
	    local log=${LOG}"-`rulelog $chain`-DROP-DEFLT"
	    $IPTABLES  -A $chain $log" " -p tcp --syn
	    $IP6TABLES -A $chain $log" " -p tcp --syn
	    $IPTABLES  -A $chain $log" " -p icmp
	    $IP6TABLES -A $chain $log" " -p icmpv6
	    $IPTABLES  -A $chain $log" " -p udp -m state --state NEW
	    $IP6TABLES -A $chain $log" " -p udp -m state --state NEW
	fi
	# log anything else
	$LDA $IPTABLES -A $chain ${LOG}"-`rulelog $chain`-DROP-DEFLT "
	$IPTABLES -A $chain -j "$drop"
	$LDA $IP6TABLES -A $chain ${LOG}"-`rulelog $chain`-DROP-DEFLT "
	$IP6TABLES -A $chain -j "$drop"
    done
}

############################################
#                                          #
# Now we begin to set the filter rules ... #
#                                          #
############################################

if [ "$ACTION" = "showlog" ]; then
    exec perl "$SCRIPTSDIR/SuSEfirewall2-showlog" "$@"
    die 1 "failed to execute $SCRIPTSDIR/SuSEfirewall2-showlog"
fi

###############

parse_logging

setlock

if [ "$ACTION" = "bootlock" -o "$ACTION" = "bootunlock" ]; then
    # lock file already set in setlock
    die 0
fi

if [ "$ACTION" = "basic" ]; then
    # Reset the filter rules
    set_basic_rules

    $IPTABLES -A INPUT -j "$ACCEPT" -p icmp --icmp-type echo-request

    # log incoming tcp connection requests. also logging udp etc would just flood the log
    $IPTABLES -A INPUT -p tcp -m state --state NEW $LOG"-IN-DROP-NEW-CONNECT "

    # reject anything else
    $IPTABLES -A INPUT -j "$DROP"

    [ -n "$USE_IPTABLES_BATCH" ] && commit_iptables_batch

    die 0 "Firewall rules successfully set in simple mode"
fi

if [ "$MODE" = "test" ]; then
    DROP="ACCEPT"
    REJECT="ACCEPT"
    FW_LOG_DROP_ALL=yes
    FW_LOG_DROP_CRIT=yes
    FW_LOG_ACCEPT_ALL=no
    FW_LOG_ACCEPT_CRIT=no
    warning "SuSEfirewall2 is running in TEST MODE, no packet filtering is done!"
fi
	
if [ "$ACTION" = "stop" ]; then
    if [ "$FW_STOP_KEEP_ROUTING_STATE" != "yes" ]; then
	setproc 0 /proc/sys/net/ipv4/ip_forward
    fi
    # Do we have a kernel with IPv6 enabled?
    $IP6TABLES_BIN -nvL >/dev/null 2>&1 || IP6TABLES=:
    reset_rules
    clear_qdisc_settings
    handle_initscripts
    [ -n "$USE_IPTABLES_BATCH" ] && commit_iptables_batch
    die 0 "Firewall rules unloaded."
fi

if [ "$ACTION" = "close" ]; then
    set_basic_rules
    setproc 0 /proc/sys/net/ipv4/ip_forward
    [ -n "$USE_IPTABLES_BATCH" ] && commit_iptables_batch
    die 0 "Firewall rules set to CLOSE."
fi

if [ "$ACTION" = "status" ]; then
    if [ "$UID" != 0 ]; then
	die 2 "You need to be root to check the status"
    fi
    if ! is_running; then
	die 1 "SuSEfirewall2 not active"
    fi

    [ -z "$quiet" ] || die 0

    # yes we need cat here, while read ... does no work :-(
    for i in `sort < /proc/net/ip_tables_names`; do
	echo "### iptables $i ###"
	$IPTABLES -t $i -vnL
	echo ""
    done
    if [ "$IP6TABLES" != ":" ]; then
	for i in `sort /proc/net/ip6_tables_names`; do
	    echo "### ip6tables $i ###"
	    $IP6TABLES -t $i -vnL
	    echo ""
	done
    fi
    die 0
fi

if [ "$ACTION" = "open" ]; then
    OPENHELPER="$SCRIPTSDIR/SuSEfirewall2-open"
    exec perl -w $OPENHELPER "$@"
    die 1 "failed to execute $OPENHELPER"
fi

### main mode ###

message "Setting up rules from $FWCONFIG ..."

parse_zones
parse_interfaces
check_interfaces_unique
autodetect_interfaces
write_status
process_masq_dev

load_customrules

check_interfaces

verify_parameters
#verify_masq_nets

parse_ipsec

remove_unused_zones
[ "$FW_ROUTE" = 'yes' ] && forward_zones="$all_zones"
input_zones="$all_zones"
saved_input_zones="$input_zones" # need that for fork_to_chains

parse_configurations

# Set default rules + flush
set_basic_rules

switch_on_ip_forwarding

set_proc_stuff

create_chains

# HOOK
fw_custom_after_chain_creation

# HOOK, deprecated
fw_custom_before_antispoofing

# HOOK, deprecated
fw_custom_after_antispoofing

protect_from_internal

check_convert_old_broadcast

drop_broadcast

allow_ipsec

allow_icmp

allow_forward_icmp_echo

# HOOK
fw_custom_before_port_handling

process_trusted_nets

allow_related

allow_ip_services

allow_tcp_services

allow_udp_services

allow_rpc_services

accept_services

reject_or_drop_services DROP

reject_or_drop_services REJECT

allow_tcp_highports

allow_highports_udp

# HOOK
fw_custom_before_masq

redirect_rules

if [ "$FW_ROUTE" = yes ]; then

    allow_related_forward_icmp

    allow_class_routing

    forwarding_rules DROP
    forwarding_rules REJECT
    forwarding_rules ACCEPT

    if [ "$FW_MASQUERADE" = yes ]; then
	masquerading_rules
	forward_masquerading_rules
    fi
fi

# HOOK
fw_custom_before_denyall

drop_all

fork_to_chains

finish_chains

# HTB settings
if [ -n "$FW_HTB_TUNE_DEV" ]; then
    need qdisc
    do_qdisc_settings
fi

[ -n "$USE_IPTABLES_BATCH" ] && commit_iptables_batch

handle_initscripts

# END #
die 0 "Firewall rules successfully set"

# vim: sw=4

ACC SHELL 2018