#!/bin/bash

#
# LRP/Debian network configuration system
#
# Ring a ding ding, my dang a lang dong	   Dave 'Kill a Cop' Cinege   GPL2
# Ding Dong Dell, Pussy's in the well      Matthew 'Network Cowboy' Grant GPL2

# 
# start)
# Depending on the auto config portions in /etc/network.conf, it auto-
# generates hosts, resolv.conf, sets the hostname, starts up interfaces,
# configures the IP filter/firewall and sets up routes (not necessarily
# in that order). 
# 
# stop)
# brings down all interfaces listed in /proc/net/dev, and their associated
# routes. Flushes all rules for iptables.
#

# bail out if we are not root
if [ "`id -un`" != "root" ] ; then
	echo 1>&2
	echo "  `basename $0`: you must be root to run this command." 1>&2
	echo 1>&2
	exit 1
fi

TARGET_KERNEL1="2.4"
TARGET_KERNEL2="2.6"
TARGET_KERNEL3="3"

#DEBUG=1

SP='   '

qt () { "$@" >/dev/null 2>&1 ; }
vb () { "$@" ; }
source () { . $1 ; }
include () { local F; for F in "$@"; do . "$F"; done; } 
basename () { echo "${1##*/}"; }

BANNER="# This file was generated by $0. It may be overwritten!"


#Default safe settings
VERBOSE=YES
IPV6_MODULE=NO
IPV4_FWDING_KERNEL=NO
IPV6_FWDING_KERNEL=NO
IP_FILTER_KERNEL=PACKET
IF_AUTO=""
BRG_SWITCH=NO
IPV4_DISABLE=NO
IPV6_DISABLE=NO
IPV6_DAD_WAIT_TIME=10
BASE_MODPATH="/lib/modules/`uname -r`/kernel"
MODPATH="${BASE_MODPATH}/net"
KERN_VERSION=`uname -r | cut -d . -f 1,2`
if echo "$KERN_VERSION" | grep '^[3-9]\..*' -q; then
	KERN_VERSION='3'
fi
[ "$KERN_VERSION" = "$TARGET_KERNEL1" ] && MODEXT="o"
[ "$KERN_VERSION" = "$TARGET_KERNEL2" ] && MODEXT="ko"
[ "$KERN_VERSION" = "$TARGET_KERNEL3" ] && MODEXT="ko"
LIB_MODPATH="${BASE_MODPATH}/lib"
SCHED_MODPATH="${MODPATH}/sched"
NETFILTER_XMODPATH="${MODPATH}/netfilter"
NETFILTER_V4MODPATH="${MODPATH}/ipv4/netfilter"
NETFILTER_V6MODPATH="${MODPATH}/ipv6/netfilter"
NETFILTER_IPSETMODPATH="${NETFILTER_XMODPATH}/ipset"
NETFILTER_IPVSMODPATH="${NETFILTER_XMODPATH}/ipvs"
QOS_MODULES="sch_cbq sch_sfq sch_red sch_gred cls_fw"
NETFILTER_CONF="/etc/netscript"
IPTBL_FILE="$NETFILTER_CONF/iptables"
IPTBL_FILE_BACKUP="$IPTBL_FILE.backup"
IP6TBL_FILE="$NETFILTER_CONF/ip6tables"
IP6TBL_FILE_BACKUP="$IP6TBL_FILE.backup"
IPTBL="/sbin/iptables"
IPTBL_RESTORE="/sbin/iptables-restore"
IPTBL_SAVE="/sbin/iptables-save"
IP6TBL="/sbin/ip6tables"
IP6TBL_RESTORE="/sbin/ip6tables-restore"
IP6TBL_SAVE="/sbin/ip6tables-save"
MODULE_PROC="/proc/modules"
IPTBL_V4PROC="/proc/net/ip_tables_names"
IPTBL_V6PROC="/proc/net/ip6_tables_names"
IPV4_PROC="/proc/sys/net/ipv4"
IPV6_PROC="/proc/sys/net/ipv6"
IPFWD_V4PROC="${IPV4_PROC}/ip_forward"
IPFWD_V6PROC="${IPV6_PROC}/conf/all/forwarding"
IPV6_MODPATH=${MODPATH}/ipv6/ipv6.${MODEXT}
IPV6_DEFAULT_PREFIX=default
DEFAULT_METRIC=999999999
IPSPEC_MODULE=NO
IPSEC_MODPATH="${MODPATH}/ipsec/ipsec.${MODEXT}"
IPSEC_EXTMODPATH="${MODPATH}/ipsec/ext"
BACKUP_LEVELS=2
BRG_NETFILTER_REMOVE="YES"
BRG_LIST="brg0"
IF_DEFAULT_IPV6_DISABLE="NO"
INITCTL="/sbin/initctl"

#==============================================================================#

# Read in configuration files 
# 	- these ones can be changed by users
[ -f $NETFILTER_CONF/network.conf ] \
	&& source $NETFILTER_CONF/network.conf
IPFILTER=0
[ -f $NETFILTER_CONF/ipfilter.conf ] \
	&& source $NETFILTER_CONF/ipfilter.conf && IPFILTER=1
[ -f $NETFILTER_CONF/srvfilter.conf ] \
	&& source $NETFILTER_CONF/srvfilter.conf
[ -f $NETFILTER_CONF/if.conf ] \
	&& source $NETFILTER_CONF/if.conf
[ -f $NETFILTER_CONF/qos.conf ] \
	&& source $NETFILTER_CONF/qos.conf

[ "$DEBUG" ] && qt () { "$@" ; }
[ "$VERBOSE" = "NO" ] && vb () { qt "$@" ; }


[ -f /proc/net/ip_fwchains ] && IPCHAINS=1
[ -f /proc/net/ip_masq/autofw ] && IPAUTOFW=1
[ -f /proc/net/ip_masq/portfw ] && IPPORTFW=1
[ -f /proc/net/ip_masq/mfw ] && IPMFW=1

GDC_PATH=/usr/bin/gdc
IF_LIST="$IF_AUTO"
IFDEVLIST=`cat /proc/net/dev | grep '^[ _a-zA-Z0-9\-]\+:' | sed -e 's/^ *\([a-zA-Z0-9_\-]\+\):.*$/\1/'`
IFDEVLIST="$IFDEVLIST $IF_DYNAMIC"
for DEV in $IFDEVLIST; do
	if [ "$DEV" = "lo" ]; then
		continue
	fi
	ANS=`echo "$IF_LIST" | grep "\<${DEV}\>"`
	if [ -z "$ANS" ]; then
		IF_LIST="$IF_LIST $DEV"
	fi
done
unset DEV IFDEVLIST ANS
IFLIST="`echo $IF_LIST | sed 's/ /|/g'`|all"
for IF in $IF_LIST; do
    REV_IF_LIST="$IF $REV_IF_LIST"
done
unset IF

# determine if running under systemd
UNDER_SYSTEMD=0
[ -x /bin/systemctl ] && systemctl status default.target > /dev/null 2>&1 \
	&& UNDER_SYSTEMD=1

# determine runlevel for disabling functionality in parallel boot environment
[ -x /sbin/runlevel ] && RUNLVL=`/sbin/runlevel | sed -e 's/^. \(.\)$/\1/'`
# Handle systemd parallel boot environment
if [ $UNDER_SYSTEMD -gt 0 ]; then
	(! systemctl is-active --quiet netscript \
		|| ps -C netscript ho args | grep -q '^start\|stop\|restart$') \
		&& RUNLVL=0
fi

# Setup stuff for IPv6
IPV6_KRNL=0
[ -d $IPV6_PROC ] && IPV6_KRNL=1

#############################################################################
# Code to set up function lists for filtering
#############################################################################

get_fns () {
	local STR="s/^.* ${1}\([^ ]\+\)$/\1/"
	if [ -n "$BASH_VERSION" ]; then
		declare -F | grep $1 | sed -e "$STR"
	else
		hash | grep "^function $1" | sed -e "$STR"
	fi
}

for FN in `get_fns ipf4_`; do
	if [ -z "$IPF4_FNS" ]; then
		IPF4_FNS="$FN"
	else
		IPF4_FNS="${IPF4_FNS}|$FN"
	fi
done; unset FN

for FN in `get_fns ipf6_`; do
	if [ -z "$IPF6_FNS" ]; then
		IPF6_FNS="$FN"
	else
		IPF6_FNS="${IPF6_FNS}|$FN"
	fi
done; unset FN

###############################################################################
#IP kernel option loading for global kernel switches
###############################################################################
read_sysctl () {
        local PROCFILE PROCVAL COMMENT ANS

	while read PROCFILE PROCVAL COMMENT; do
		if [ -z "$PROCFILE" -o -z "$PROCVAL" ]; then
			continue
		fi
	
		if [ "$PROCFILE"  = "#" -o "$PROCVAL" = "#" ]; then
			continue
		fi
		
		case "$PROCVAL" in
		YES|Yes|yes)
			PROCVAL=1
			;;
		NO|No|no)
			PROCVAL=0
			;;
		esac

		[ ! -f $1/$PROCFILE ] && continue

		echo $PROCVAL > $1/$PROCFILE
	done

}

read_gbl_sysctl () {

	echo "$NET_GLOBAL_SYSCTL" | read_sysctl /proc/sys/net
	
	return 0
}


###############################################################################
#IP Forwarding configuration
###############################################################################
start_auto_ipkrnlswch () {
    	local DIR
    
	# read in the global sysctl settings
	read_gbl_sysctl

	# Turn on global RP filter switch - this is ANDed with 
	# the per interface ones
	echo 1 > ${IPV4_PROC}/conf/all/rp_filter
	# Fix the Shared Media Mess
	echo 0 > ${IPV4_PROC}/conf/all/shared_media
	echo 0 > ${IPV4_PROC}/conf/default/shared_media


	if [ "$IPV4_FWDING_KERNEL" = "YES" ]; then
		vb echo -n "Enabling IPv4 packet forwarding..."
		echo "1" >$IPFWD_V4PROC && vb echo "done."
	elif [ "$IPV4_FWDING_KERNEL" != "FILTER_ON" ]; then
		vb echo -n "Disabling IPv4 packet forwarding..."
		echo "0" >$IPFWD_V4PROC && vb echo "done."
	fi 

	# IPv6  
	if [ $IPV6_KRNL -lt 1 ]; then
		return 0
	fi
	
	# Most hardened servers and routers need defaults like these
	# for interface host mode
	for DIR in ${IPV6_PROC}/conf/*; do
		# Don't allow ICMP redirect by default
		echo 0 > $DIR/accept_redirects
	done

	# This is here just to do the printing when IPv6 IS disabled.
	case "$IPV6_DISABLE" in
	YES|Yes|yes)
		vb echo -n "Disabling IPv6 protocol..." 
		ifv6_setproc all disable_ipv6 "$IPV6_DISABLE" && echo "done."
		;;
	*)
		ifv6_setproc all disable_ipv6 "$IPV6_DISABLE"
		;;
	esac

	# Set this flag as required for creation of dynamic bridged
	# interfaces
	ifv6_setproc default disable_ipv6 "$IF_DEFAULT_IPV6_DISABLE"

	if [ "$IPV6_FWDING_KERNEL" = "YES" ]; then
		vb echo -n "Enabling IPv6 packet forwarding..." 
		echo "1" >$IPFWD_V6PROC && vb echo "done."
	elif [ "$IPV6_FWDING_KERNEL" != "FILTER_ON" ]; then
		vb echo -n "Disabling IPv6 packet forwarding..." 
		echo "0" >$IPFWD_V6PROC && vb echo "done."
	fi 

}

###############################################################################
#Interface configuration
###############################################################################
start_auto_if () {

	if [ $UNDER_SYSTEMD -le 0 ]; then
		###
		#localhost interface
		####################
		vb echo -n "Configuring loopback interface lo..."
		if_lo_up && vb echo "done."
	fi
	# Do the rest of the interfaces
	iface_up all
}

##############################################################################
# Interface stuff iface_up, iface_down, iface_reset, iface_upstart_emit
##############################################################################
iface_up () {
    local IF
    vb echo -n "Configuring interface:"
    if [ "$1" = "all" ] ; then
	for IF in $IF_AUTO; do
	    if_up $IF && vb echo -n " $IF"
	done
	unset IF
	# Wait for IPv6 DAD to happen
	case "$IPV6_DISABLE" in
	YES|Yes|yes)
		;;
	*)
		if [ $IPV6_DAD_WAIT_TIME -gt 0 ]; then
			sleep "$IPV6_DAD_WAIT_TIME"
		fi
		;;
	esac
    else
	# Don't do anything during boot or shutdown
	case "$RUNLVL" in
	unknown|0|1|6)
    		vb echo "."
		return 0
		;;
	esac
	local IF_NODASH=`echo "$1" | sed -e 's/\-/_/g'`
	eval local IF_CHAIN_AUTO=\"\${"${IF_NODASH}"_IF_CHAIN_AUTO:-""}\"
	if_up $1 && vb echo -n " $1"
	for IF in $IF_CHAIN_AUTO; do
	    if_up $IF && vb echo -n " $IF"
	done
	unset IF
    fi
    vb echo "."
    # Don't do anything more during boot or shutdown
    case "$RUNLVL" in
    unknown|0|1|6)
            return 0
            ;;
    esac
    # If DHCP/radvd is around, tell it all about this!
    if [ -n "$DHCP_RA_STROKE_CMD" ]; then
	vb echo -n "Stroking DHCP/RA..."
    	sleep 5 && $DHCP_RA_STROKE_CMD
        vb echo "done."
    fi
}


iface_down () {
    local IF
    vb echo -n "Stopping interface:"
    if [ "$1" = "all" ] ; then
	for IF in $REV_IF_LIST; do
	    if_down $IF && vb echo -n " $IF"
	done
	unset IF
    else
	# Don't do anything during boot or shutdown
	case "$RUNLVL" in
	unknown|0|1|6)
    		vb echo "."
		return 0
		;;
	esac
	local REV_IF_CHAIN
	local IF_NODASH=`echo "$1" | sed -e 's/\-/_/g'`
	eval local IF_CHAIN=\"\${"${IF_NODASH}"_IF_CHAIN:-""}\"
	eval local IF_CHAIN_AUTO=\"\${"${IF_NODASH}"_IF_CHAIN_AUTO:-""}\"
	IF_CHAIN="$IF_CHAIN_AUTO $IF_CHAIN" 
	for IF in $IF_CHAIN; do
		REV_IF_CHAIN="$REV_IF_CHAIN $IF"
	done
	unset IF
	for IF in $REV_IF_CHAIN; do
		if_down $IF && vb echo -n " $IF"
	done
	unset IF
	if_down $1 && vb echo -n " $1"
    fi
    vb echo "."
}


iface_reset () {
    iface_down $1
    sleep 2
    iface_up $1
}


iface_qos () {
    
    vb echo -n "Reloading QoS for interface: "
    if [ "$1" = "all" ] ; then
	for IF in $IF_AUTO; do
		ip_QoSppp $IF
		ip_QoSclear $IF && ip_QoS $IF && vb echo -n " $IF"
	done
	unset IF
    else
	ip_QoSppp $1
	ip_QoSclear $1 && ip_QoS $1 && vb echo -n " $1"
    fi
    vb echo "."
    return 0
}

iface_upstart_emit () {
	if ! [ -x "$INITCTL" ]; then
		return 0
	fi

	$INITCTL emit --no-wait "$@"
}


##############################################################################
# Functions to set 2.4 kernel interface parameters
# ifv4_setproc (<interface> <file> YES|NO
# ifv6_setproc (<interface> <file> YES|NO
##############################################################################
ifv4_setproc () {
	if [ -z "$3" ]; then
		return 0;
	fi

	[ ! -f ${IPV4_PROC}/conf/$1/$2 ] && return 1

	case "$3" in 
	YES|Yes|yes)
		echo 1 > ${IPV4_PROC}/conf/$1/$2
		return 0;
		;;
	NO|No|no)
		echo 0 > ${IPV4_PROC}/conf/$1/$2
		return 0;
		;;
	*)
		if echo $3 | grep -q '^[0-9]\+$'; then
			echo $3 > ${IPV4_PROC}/conf/$1/$2
			return 0
		fi

		return 1;
		;;
	esac
	
	return 0;
	
}

ifv6_setproc () {
	if [ -z "$3" ]; then
		return 0;
	fi

	[ $IPV6_KRNL -lt 1 ] && return 1 
	[ ! -f ${IPV6_PROC}/conf/$1/$2 ] && return 1

	case "$3" in 
	YES|Yes|yes)
		echo 1 > ${IPV6_PROC}/conf/$1/$2
		return 0;
		;;
	NO|No|no)
		echo 0 > ${IPV6_PROC}/conf/$1/$2
		return 0;
		;;
	*)
		if echo $3 | grep -q '^[0-9]\+$'; then
			echo $3 > ${IPV6_PROC}/conf/$1/$2
			return 0
		fi
		
		return 1;
		;;
	esac
	
	return 0;
	
}


##############################################################################
# Functions to configure the bridge
# brg_global()
##############################################################################
brg_unbind_netfilter () {
	local STUFF

	# Unbind bridges from Netfilter
	if [ "$BRG_NETFILTER_REMOVE" != "NO" \
		-a "$BRG_NETFILTER_REMOVE" != "No" \
		-a "$BRG_NETFILTER_REMOVE" != "no" ]; then
		STUFF=" 
# Disable netfilter in bridge(s) - useful when not
# doing bridge filtering.
bridge/bridge-nf-call-ip6tables NO
bridge/bridge-nf-call-iptables NO
bridge/bridge-nf-call-arptables NO
bridge/bridge-nf-filter-pppoe-tagged NO
bridge/bridge-nf-filter-vlan-tagged NO
"
		echo "$STUFF" | read_sysctl /proc/sys/net

	else
		STUFF=" 
# Disable netfilter in bridge(s) - useful when not
# doing bridge filtering.
bridge/bridge-nf-call-ip6tables YES
bridge/bridge-nf-call-iptables YES
bridge/bridge-nf-call-arptables YES
bridge/bridge-nf-filter-pppoe-tagged YES
bridge/bridge-nf-filter-vlan-tagged YES
"
		echo "$STUFF" | read_sysctl /proc/sys/net
	fi

	return 0
}

brg_global() {
	local INT BRG ANS
	local BRG_DEVLIST
	
	case "$BRG_SWITCH" in
	YES|Yes|yes)
		BRG_LIST="$BRG_LIST"
		;;
	NO|No|no)
		unset BRG_LIST
		;;
	0|1|2|3|4|5|6|7|8|9|10)
		INT=0
		while [ $INT -lt $BRG_SWITCH ]; do

			BRG_LIST="$BRG_LIST brg${INT}"
			INT=$(( $INT + 1 ))
		done
		;;
	esac

	BRG_DEVLIST=`brctl show | sed -e '1d' | grep '^[-a-zA-Z0-9_]' | sed -e 's/^\([a-zA-Z0-9_\-]\+\)[ 	].*$/\1/'`
	for BRG in $BRG_DEVLIST; do
		ANS=`echo "$BRG_LIST" | grep "$BRG"`
		if [ -z "$ANS" ]; then
			qt ip link set dev "$BRG" down
			brctl delbr "$BRG"
		fi
	done
	for BRG in $BRG_LIST; do
		brctl addbr "$BRG" > /dev/null 2>&1
	done

	brg_unbind_netfilter

	return 0
}

brg_iface () {
	local BRG ANS

	case $2 in
	up)
		if [ "$3" = "NO" -o "$3" = "No" -o "$3" = "no" ]; then
			return 0
		fi
		if [ "$3" = "YES" -o "$3" = "Yes" -o "$3" = "yes" ]; then
			BRG=brg0
		else
			BRG=$3
		fi
		[ -z "$BRG" ] && return 0
		ANS=`echo "$BRG_LIST" | grep "$BRG"`
		if [ -n "$ANS" ]; then
			brctl addif "$BRG" $1 > /dev/null 2>&1
			[ -z "$4" ] && ifv6_setproc $1 disable_ipv6 YES
		fi
		;;
	down)	
		BRG=`brctl show | sed -e '1d' | grep "${1}\$" | sed -e 's/^\([a-zA-Z]\+[0-9]\+\)[ 	]\+.*$/\1/'`
		[ -z "$BRG" ] && BRG=brg0
		brctl delif $BRG $1 > /dev/null 2>&1
		[ -z "$3" ] && ifv6_setproc $1 disable_ipv6 NO
		;;
	esac

	return 0
}

##############################################################################
# Functions to set the default route
##############################################################################

ipv4_default_route () {
	
	if [ "$1" != "$IPV4_DEFAULT_GWDEV" ]; then
		return 0
	fi
	
	# Default route support
        case "$IPV4_DEFAULT_GW" in
	OTHER|Other|other|OFF|Off|off|NO|No|no)
		;;
	"")
		ip route del default metric $DEFAULT_METRIC > /dev/null 2>&1
		;;
	*)
		ip route replace default via $IPV4_DEFAULT_GW \
			metric $DEFAULT_METRIC
		;;
	esac
	
	return 0
}

ipv6_default_route () {
	
	if [ "$1" != "$IPV6_DEFAULT_GWDEV" ]; then
		return 0
	fi
	
	# IPv6 default route - this could be better 
	case "$IPV6_DEFAULT_GW" in
	OTHER|Other|other|OFF|Off|off|NO|No|no)
		;;
	"")
		ip -6 route del $IPV6_DEFAULT_PREFIX metric $DEFAULT_METRIC \
			> /dev/null 2>&1
		;;
	*)
		local IPV6_ZERO_GW=`echo $IPV6_DEFAULT_GW \
			| eval $SED_IPV6ADDR`
		if ! ip -6 route list $IPV6_DEFAULT_PREFIX \
			| grep  -q "$IPV6_ZERO_GW.*metric $DEFAULT_METRIC"; 
		then
			ip -6 route del $IPV6_DEFAULT_PREFIX \
				metric $DEFAULT_METRIC > /dev/null 2>&1
			ip -6 route add $IPV6_DEFAULT_PREFIX \
				metric $DEFAULT_METRIC via $IPV6_DEFAULT_GW \
				dev $IPV6_DEFAULT_GWDEV
		fi
		;;
	esac
}



##############################################################################
# checkarg() a function to check interface arguments
##############################################################################
checkarg() {
    eval "case \"$*\" in
        $IFLIST)
            ;;
        *)
            echo \"Usage: `basename $0` ifup|ifdown|ifqos|ifreload\" 
	    echo \"       ${SP} {$IFLIST}\"
            exit 1
            ;;
         esac"
}


##############################################################################
# functions to handle filter stuff
##############################################################################

#
# backup_rotate <filename> <maxlevel>
#
backup_rotate () {
        local MAX="$2"
        [ $MAX -lt 2 ] && MAX=2
        local COUNT=$(($MAX - 1))
        local PREV="$MAX"
        while [ $COUNT -gt 0 ]; do
                [ -f "${1}.${COUNT}" ] && mv "${1}.${COUNT}" "${1}.${PREV}"
                PREV=$COUNT
                COUNT=$(( $COUNT - 1 ))
        done
        [ -f "$1" ] && mv "$1" "${1}.1"
	return 0
}

ipv4filter_kernfwd () {
	local OVERRIDE="$2"

	if [ "$OVERRIDE" != "YES" -a "$OVERRIDE" != "Yes" \
		-a "$OVERRIDE" != "yes" \
		-a  "$IPV4_FWDING_KERNEL" != "FILTER_ON" ]; then
		return 0;
    	fi
    
	case $1 in 
	on)
		vb echo -n "Enabling IPv4 packet forwarding..."
		echo "1" >$IPFWD_V4PROC \
			&& vb echo "done."
		;;
	off)
		vb echo -n "Disabling IPv4 packet forwarding..."
		echo "0" >$IPFWD_V4PROC \
			&& vb echo "done."
	    	;;
	*)
		echo "AAARGGHH - wrong argument given to ipv4filter_kernfwd: $1"
		exit 1
		;;
	esac
}

# Check and see if filtering and mangling are available
ipv4filter_check () {
	local TBL MANGLE FILTER
	MANGLE=0
	FILTER=0

	[ ! -f "$IPTBL_V4PROC" ] && return 1

	for TBL in `cat $IPTBL_V4PROC`; do
		case $TBL in
		mangle)
			MANGLE=1
			;;
		filter)
			FILTER=1
			;;
		esac
	done

	if [ $MANGLE -ne 1 -a $FILTER -ne 1 ]; then
		return 1
	fi

	return 0
}

# A function to flush the filters (for internal use)
ipv4filter_flush  () {
	local TBL

	# Flush the IPV4 filters out, and user defined chains
	[ ! -f $IPTBL_V4PROC ] && return 0
	for TBL in `cat $IPTBL_V4PROC`; do
		if [ "$TBL" = "$1" ]; then
			continue
		fi
		$IPTBL -t $TBL -F
		$IPTBL -t $TBL -X
	done

	return 0
}

ipv4filter_policy () {
	local TBL

	[ ! -f $IPTBL_V4PROC ] && return 0
	for TBL in `cat $IPTBL_V4PROC`; do
		if [ "$TBL" = "$2" ]; then
			continue
		fi

		case $TBL in
		mangle)
			$IPTBL -t $TBL -P PREROUTING $1
			$IPTBL -t $TBL -P OUTPUT $1
			;;
		filter)
			$IPTBL -t $TBL -P INPUT $1
			$IPTBL -t $TBL -P FORWARD $1
			$IPTBL -t $TBL -P OUTPUT $1
			;;
		nat)
			$IPTBL -t $TBL -P PREROUTING $1
			$IPTBL -t $TBL -P POSTROUTING $1
			$IPTBL -t $TBL -P OUTPUT $1
			;;
		esac
	done

	return 0
}
				
# function to set the filter default policies
ipv4filter_clear () { 

	ipv4filter_flush $1

	ipv4filter_policy ACCEPT $1

	return 0	    

}

# Selects basic filter type configuration function
ipv4filter_iptbl_cfg () {
	
	if [ ! -f $1 ] ; then
		echo
		echo "IPv4 filters: no $1 file."
		echo
		return 1
	fi
	echo -n "Loading IPv4 filters..." 
	if $IPTBL_RESTORE < $1; then
		ipv4filter_fairq
		ipf4_laptopfw
		vb echo "done."
		ipv4filter_kernfwd on
	else
		return 1
	fi

	return 0

}

ipv4filter_iptbl_save () {
	local OLD_UMASK
	
	echo -n "Saving IPv4 filters..."
	backup_rotate "$IPTBL_FILE" "$BACKUP_LEVELS"
	OLD_UMASK=`umask`
	umask 0277
	if $IPTBL_SAVE > $IPTBL_FILE; then
		umask $OLD_UMASK
		chmod 0400 $IPTBL_FILE
		vb echo "done."
	else
		umask $OLD_UMASK
		vb echo
		return 1
	fi 

	vb echo
	return 0
}

# Some functions to handle Protocol IP Port tuples

ipfilter_echoParam () {
	local format="$1"
	local IFS='_'
	set -- $2
	eval "echo \"$format\""
}
	
ipfilter_echoIpPort () {
	local format1="$1"
	local format2="$2"
	local testpar="$3"
	local IFS='_'
	set -- $4
	eval "echo -n \"$format1\""
	eval "if [ -n \"$testpar\" ]; then
		echo \" $format2\"
	fi"
}

ipv4filter_delTie () {
	local CHAIN="$1"
	shift
	qt $IPTBL -t mangle -D "$CHAIN" $*
	qt $IPTBL -t mangle -D "$CHAIN" -s 0/0 $*
	qt $IPTBL -t mangle -D "$CHAIN" -d 0/0 $*
	qt $IPTBL -t mangle -D "$CHAIN" -d 0/0 -s 0/0 $*
	return 0
}

# A function to mark packets for classification 
ipv4filter_fairq () {
	local CLS
	local TNL

	[ -z "$MANGLE_OUTPUT_BYPASS" ] && [ -z "$CLS_FAIRQ" ] && return 0
	
	qt $IPTBL -t mangle -F nomangle
	qt $IPTBL -t mangle -N nomangle

	# Accept IPv4 tunnel traffic - any changes on
	# OUTPUT chain will cause rerouting, and Free S/WAN problems
	for TNL in $MANGLE_OUTPUT_BYPASS; do
		$IPTBL -t mangle -A nomangle -j ACCEPT \
			-p `ipfilter_echoParam '$1' $TNL` \
			-d `ipfilter_echoIpPort '$2' ' --dport $3' '$3' $TNL`
	done

	# Add the nomangle chain to the OUTPUT chain
	# NOTE position this is inserted.
	ipv4filter_delTie OUTPUT -j nomangle
	$IPTBL -t mangle -I OUTPUT 1 -j nomangle

	[ -z "$CLS_FAIRQ" ] && return 0
	
	# Clear chain if it already exists
	qt $IPTBL -t mangle -F fairq

	# Create new chain
	qt $IPTBL -t mangle -N fairq

	# Populate chains
	for CLS in $CLS_FAIRQ; do
		$IPTBL -t mangle -A fairq -j MARK \
			--set-mark `ipfilter_echoParam '$1' $CLS` \
			-p `ipfilter_echoParam '$2' $CLS` \
			`ipfilter_echoIpPort '-d $3' ' --dport $4' '$4' $CLS`
		$IPTBL -t mangle -A fairq -j MARK \
			--set-mark `ipfilter_echoParam '$1' $CLS` \
			-p `ipfilter_echoParam '$2' $CLS` \
			`ipfilter_echoIpPort '-s $3' ' --sport $4' '$4' $CLS`
	done;

	# Add fairq chain to OUTPUT and PREROUTING chains
	ipv4filter_delTie OUTPUT -j fairq
	$IPTBL -t mangle -I OUTPUT 2 -j fairq # NOTE postion this is inserted.
	ipv4filter_delTie PREROUTING -j fairq
	$IPTBL -t mangle -I PREROUTING 1 -j fairq

	return 0
}

ipv4filter_exec () {
	local RES
	
	local FN="$1"
	shift
	eval "case \"$FN\" in
		$IPF4_FNS)
			case \$1 in 
			-r|remove)
				vb echo -n \"Removing IPv4 filter $FN...\"
				;;
			*)
				vb echo -n \"Loading IPv4 filter $FN...\"
				;;
			esac
			if ipf4_${FN} $*; then 	
				echo \"done.\"
				exit 0
			fi
			exit 1
			;;
		*)
    			echo \"       `basename $0` ipfilter exec $IPF4_FNS\"
			echo \"                              [chain p1 p2 ...]\"
    			exit 1
			;;
		esac"

	return 0
}


ipv4filter_cmd () {
	
	if [ "$KERN_VERSION" != "$TARGET_KERNEL1" \
		-a "$KERN_VERSION" != "$TARGET_KERNEL2" \
		-a "$KERN_VERSION" != "$TARGET_KERNEL3" ] ; then
		echo
		echo "IPv4 filters: kernel not version ${TARGET_KERNEL1}.x, ${TARGET_KERNEL2}.x, or ${TARGET_KERNEL3}.x."
		if [ "$IPV4_FWDING_KERNEL" = "FILTER_ON" ]; then
			# Keep the output pretty..
			echo
		fi
		ipv4filter_kernfwd off
		echo
		return 1
	fi
	if ! [ -x $IPTBL ] ; then
		echo
		echo "IPv4 filters: $IPTBL not found."
		echo
		return 1
	fi
	case $1 in
	load|reload|restart|reset)
		ipv4filter_iptbl_cfg $IPTBL_FILE
    		;;
	usebackup)
		local BKUP_NUM=1
    		[ -n "$2" ] && BKUP_NUM="$2"
		ipv4filter_iptbl_cfg "${IPTBL_FILE}.${BKUP_NUM}"
		;;
	save)
		ipv4filter_iptbl_save
    		;;
	fairq)
		echo -n "Reloading IPv4 fairq filters..."
		if ipv4filter_fairq; then 
			echo "done."
    		else
			echo "netfilter kernel modules not loaded."
    		fi
    		;;
	clear|flush)
		ipv4filter_kernfwd off
 		vb echo -n "Flushing IPv4 filters..."
 		ipv4filter_clear
		ipv4filter_fairq
    		vb echo "done."
    		;;
	exec)
		shift
		ipv4filter_exec $*
		;;
	forward|fwd)
		ipv4filter_kernfwd on yes
		;;
	noforward|nofwd)
		ipv4filter_kernfwd off yes
		;;
	
	*)
		echo "Usage: `basename $0` ipfilter load|clear|fairq|flush|fwd|nofwd|reload|save"
		echo "                              usebackup [backup-number]"
		echo "       `basename $0` ipfilter exec $IPF4_FNS"
		echo "                              [chain p1 p2 ...]"
		exit 1
		;;
	esac
}

# IPv6 filters

ipv6filter_kernfwd () {
	local OVERRIDE="$2"

	if [ "$OVERRIDE" != "YES" -a "$OVERRIDE" != "Yes" \
		-a "$OVERRIDE" != "yes" \
		-a  "$IPV6_FWDING_KERNEL" != "FILTER_ON" ]; then
		return 0;
    	fi
    
	case $1 in 
	on)
		vb echo -n "Enabling IPv6 packet forwarding..." 
		echo "1" >$IPFWD_V6PROC \
			&& vb echo "done."
		;;
	off)
		vb echo -n "Disabling IPv6 packet forwarding..."
		echo "0" >$IPFWD_V6PROC \
			&& vb echo "done."
	    	;;
	*)
		echo "AAARGGHH - wrong argument given to ipv6filter_kernfwd: $1"
		exit 1
		;;
	esac
}

# Check and see if filtering and mangling are available
ipv6filter_check () {
	local TBL MANGLE FILTER
	MANGLE=0
	FILTER=0

	[ ! -f "$IPTBL_V6PROC" ] && return 1

	for TBL in `cat $IPTBL_V6PROC`; do
		case $TBL in
		mangle)
			MANGLE=1
			;;
		filter)
			FILTER=1
			;;
		esac
	done

	if [ $MANGLE -ne 1 -a $FILTER -ne 1 ]; then
		return 1
	fi

	return 0
}


# A function to flush the filters (for internal use)
ipv6filter_flush  () {
	local TBL

	# Flush the IPV6 filters out, and user defined chains
	[ ! -f $IPTBL_V6PROC ] && return 0
	for TBL in `cat $IPTBL_V6PROC`; do
		if [ "$TBL" = "$1" ]; then
			continue
		fi
		$IP6TBL -t $TBL -F
		$IP6TBL -t $TBL -X
	done

	return 0
}

ipv6filter_policy () {
	local TBL

	[ ! -f $IPTBL_V6PROC ] && return 0
	for TBL in `cat $IPTBL_V6PROC`; do
		if [ "$TBL" = "$2" ]; then
			continue
		fi

		case $TBL in
		mangle)
			$IP6TBL -t $TBL -P PREROUTING $1
			$IP6TBL -t $TBL -P OUTPUT $1
			;;
		filter)
			$IP6TBL -t $TBL -P INPUT $1
			$IP6TBL -t $TBL -P FORWARD $1
			$IP6TBL -t $TBL -P OUTPUT $1
			;;
		nat)
			$IP6TBL -t $TBL -P PREROUTING $1
			$IP6TBL -t $TBL -P POSTROUTING $1
			$IP6TBL -t $TBL -P OUTPUT $1
			;;
		esac
	done

	return 0
}
				
# function to set the filter default policies
ipv6filter_clear () { 

	ipv6filter_flush $1

	ipv6filter_policy ACCEPT $1

	return 0	    

}

# Selects basic filter type configuration function
ipv6filter_iptbl_cfg () {
	
	if [ ! -f $1 ] ; then
		echo
		echo "IPv6 filters: no $1 file."
		echo
		return 1
	fi
	echo -n "Loading IPv6 filters..." 
	if $IP6TBL_RESTORE < $1; then
		ipv6filter_fairq
		ipf6_laptopfw
		vb echo "done."
		ipv6filter_kernfwd on
	else
		return 1
	fi

	return 0

}

ipv6filter_iptbl_save () {
	local OLD_UMASK

	echo -n "Saving IPv6 filters..."
	backup_rotate "$IP6TBL_FILE" "$BACKUP_LEVELS"
	OLD_UMASK=`umask`
	umask 0277
	if $IP6TBL_SAVE > $IP6TBL_FILE; then
		umask $OLD_UMASK
		chmod 0400 $IP6TBL_FILE
		vb echo "done."
	else
		umask $OLD_UMASK
		vb echo
		return 1
	fi 

	vb echo
	return 0
}

ipv6filter_delTie () {
	local CHAIN="$1"
	shift
	qt $IP6TBL -t mangle -D "$CHAIN" $*
	qt $IP6TBL -t mangle -D "$CHAIN" -s ::/0 $*
	qt $IP6TBL -t mangle -D "$CHAIN" -d ::/0 $*
	qt $IP6TBL -t mangle -D "$CHAIN" -s ::/0 -d ::/0 $*
	return 0
}

# A function to mark packets for classification 
ipv6filter_fairq () {
	local CLS
	local TNL

	[ -z "$IPV6_MANGLE_OUTPUT_BYPASS" ] && [ -z "$IPV6_CLS_FAIRQ" ] \
		&& return 0
	
	qt $IP6TBL -t mangle -F nomangle
	qt $IP6TBL -t mangle -N nomangle

	# Accept IPv6 tunnel traffic - any changes on
	# OUTPUT chain will cause rerouting, and Free S/WAN problems
	for TNL in $IPV6_MANGLE_OUTPUT_BYPASS; do
		$IP6TBL -t mangle -A nomangle -j ACCEPT \
			-p `ipfilter_echoParam '$1' $TNL` \
			-d `ipfilter_echoIpPort '$2' ' --dport $3' '$3' $TNL`
	done

	# Add the nomangle chain to the OUTPUT chain
	# NOTE position this is inserted.
	ipv6filter_delTie OUTPUT -j nomangle
	$IP6TBL -t mangle -I OUTPUT 1 -j nomangle

	[ -z "$IPV6_CLS_FAIRQ" ] && return 0
	
	# Clear chain if it already exists
	qt $IP6TBL -t mangle -F fairq

	# Create new chain
	qt $IP6TBL -t mangle -N fairq

	# Populate chains
	for CLS in $IPV6_CLS_FAIRQ; do
		$IP6TBL -t mangle -A fairq -j MARK \
			--set-mark `ipfilter_echoParam '$1' $CLS` \
			-p `ipfilter_echoParam '$2' $CLS` \
			`ipfilter_echoIpPort '-d $3' ' --dport $4' '$4' $CLS`
		$IP6TBL -t mangle -A fairq -j MARK \
			--set-mark `ipfilter_echoParam '$1' $CLS` \
			-p `ipfilter_echoParam '$2' $CLS` \
			`ipfilter_echoIpPort '-s $3' ' --sport $4' '$4' $CLS`
	done;

	# Add fairq chain to OUTPUT and PREROUTING chains
	ipv6filter_delTie OUTPUT -j fairq
	$IP6TBL -t mangle -I OUTPUT 2 -j fairq # NOTE postion this is inserted.
	ipv6filter_delTie PREROUTING -j fairq
	$IP6TBL -t mangle -I PREROUTING 1 -j fairq

	return 0
}

ipv6filter_exec () {
	local RES
	
	local FN="$1"
	shift
	eval "case \"$FN\" in
		$IPF6_FNS)
			case \$1 in 
			-r|remove)
				vb echo -n \"Removing IPv6 filter $FN...\"
				;;
			*)
				vb echo -n \"Loading IPv6 filter $FN...\"
				;;
			esac
			if ipf6_${FN} $*; then 	
				echo \"done.\"
				exit 0
			fi
			exit 1
			;;
		*)
    			echo \"       `basename $0` ip6filter exec $IPF6_FNS\"
			echo \"                              [chain p1 p2 ...]\"
    			exit 1
			;;
		esac"


	return 0
}

ipv6filter_cmd () {
	if [ $IPV6_KRNL -lt 1 ]; then
		return 0
	fi

	if [ "$KERN_VERSION" != "$TARGET_KERNEL1"  \
		-a "$KERN_VERSION" != "$TARGET_KERNEL2" \
		-a "$KERN_VERSION" != "$TARGET_KERNEL3" ] ; then
		echo
		echo "IPv6 filters: kernel not version ${TARGET_KERNEL1}.x, ${TARGET_KERNEL2}.x, or ${TARGET_KERNEL3}.x."
		if [ "$IPV6_FWDING_KERNEL" = "FILTER_ON" ]; then
			# Keep the output pretty..
			echo
		fi
		ipv6filter_kernfwd off
		echo
		return 1
	fi
	if ! [ -x $IP6TBL ] ; then
		echo
		echo "IPv6 filters: $IP6TBL not found."
		echo
		return 1
	fi
	case $1 in
	load|reload|restart|reset)
		ipv6filter_iptbl_cfg $IP6TBL_FILE
    		;;
	usebackup)
		local BKUP_NUM=1
    		[ -n "$2" ] && BKUP_NUM="$2"
		ipv6filter_iptbl_cfg "${IP6TBL_FILE}.${BKUP_NUM}"
		;;
	save)
		ipv6filter_iptbl_save
    		;;
	fairq)
		echo -n "Reloading IPv6 fairq filters..."
		if ipv6filter_fairq; then 
			echo "done."
    		else
			echo "netfilter IPv6 kernel modules not loaded."
    		fi
    		;;
	clear|flush)
		ipv6filter_kernfwd off
 		vb echo -n "Flushing IPv6 filters..."
 		ipv6filter_clear
		ipv6filter_fairq
    		vb echo "done."
    		;;
	exec)
		shift
		ipv6filter_exec $*
		;;
	forward|fwd)
		ipv6filter_kernfwd on yes
		;;
	noforward|nofwd)
		ipv6filter_kernfwd off yes
		;;
	
	*)
		echo "Usage: `basename $0` ip6filter load|clear|fairq|flush|fwd|nofwd|reload|save"
		echo "                               usebackup [backup-number]"
		echo "       `basename $0` ip6filter exec $IPF6_FNS"
		echo "                              [chain p1 p2 ...]"
		exit 1
		;;
	esac
}


##############################################################################
# Start and stop
##############################################################################

start () {

	start_auto_ipkrnlswch
	ipv4filter_cmd load
	
	if [ $IPV6_KRNL -ge 1 ]; then
		ipv6filter_cmd load
	fi
	
	start_auto_if
		
}	#END start ()

stop () {

	iface_down all

	vb echo -n "Disabling IPv4 packet forwarding..."
	echo "0" >$IPFWD_V4PROC \
	    && vb echo "done."
	vb echo -n "Flushing IPv4 filters..."
	ipv4filter_clear && vb echo "done."
	
	if [ $IPV6_KRNL -ge 1 ]; then
		vb echo -n "Disabling IPv6 packet forwarding..."
		echo "0" >$IPFWD_V6PROC \
	    		&& vb echo "done."
		vb echo -n "Flushing IPv6 filters..."
		ipv6filter_clear && vb echo "done."
	fi

}	#END stop ()

#############################################################################
# Debian compatibility hooks 
#############################################################################

ifupdown_usage () {
	echo "Usage: `basename $0` -a|$IFLIST" 1>&2
	echo "       Use the netscript command instead as it a lot better." 1>&2
	exit 1
}

ifupdown () {
	local OPTA
	local OPTIND

	OPTA=0
	OPTIND=1
        while getopts :ah F; do
                case $F in
		a) 	OPTA=1
			;;
                h)
                        ifupdown_usage
                        exit 1
                        ;;
                \?)
                        ;;
                esac
        done
        shift $(( $OPTIND - 1 ))

	case "$RUNLVL" in
	unknown|0|1|6)
		# Do nothing
		exit 0
		;;
	*)
		if [ "`basename $0`" = "ifup" -a $OPTA -gt 0 ]; then
			iface_up all > /dev/null
			exit 0
		elif [ "`basename $0`" = "ifdown" -a $OPTA -gt 0 ]; then
			iface_down all > /dev/null
			exit 0
		fi
		;;
	esac

	if [ $# -eq 1 ]; then
		eval "case \"$*\" in
            			$IFLIST)
	                		;;
			        *)
					ifupdown_usage
					exit 1
					;;
			esac"

		case "`basename $0`" in
			ifup)

				iface_up $1 > /dev/null
				exit 0
				;;
			ifdown)
				iface_down $1 > /dev/null
				exit 0
				;;
		esac
	fi
	

	ifupdown_usage
	exit 1

}

#############################################################################
# Main - Down to business
#############################################################################


# Handle symlinked ifup and ifdown commands

if [ "`basename $0`" = "ifup" -o "`basename $0`" = "ifdown" ]; then 
	ifupdown $*
fi

case "$1" in
	start)	start	;;
	stop)	stop	;; 
	reload) start reload ;;
	restart|force-reload)
		$0 stop
		sleep 1
		$0 start
		;;

	ifup|ifreload)
		shift
		checkarg $*
		iface_up $1
		;;

	ifdown)
		shift
		checkarg $*
		iface_down $1
		;;
	
	ifqos)
		shift
		checkarg $*
		iface_qos $1
		;;

	ifreset|ifrestart)
		shift
		checkarg $*
		iface_reset $1
		;;

	ipfilter)
		shift
		if ! ipv4filter_cmd $*; then
		    exit 1
		fi
		;;

	*)
		if [ $IPV6_KRNL -ge 1 -a "$1" = "ip6filter" ]; then
			shift
			if ! ipv6filter_cmd $*; then
		    	exit 1
			fi
			exit 0
		fi
		echo "Usage: `basename $0` start|stop|reload|restart" 
		echo "       `basename $0` ifup|ifdown|ifqos|ifreload"
		echo "       ${SP} {$IFLIST}"
		echo "Usage: `basename $0` ipfilter load|clear|fairq|flush|fwd|nofwd|reload|save"
		echo "                              usebackup [backup-number]"
		echo "       `basename $0` ipfilter exec $IPF4_FNS"
		echo "                              [chain p1 p2 ...]"
		if [ $IPV6_KRNL -ge 1 ]; then 
			echo "Usage: `basename $0` ip6filter load|clear|fairq|flush|fwd|nofwd|reload|save"
			echo "                              usebackup [backup-number]"
			echo "       `basename $0` ip6filter exec $IPF6_FNS"
			echo "                              [chain p1 p2 ...]"
		fi
		exit 1 
        ;;
esac

exit 0


