#! /bin/sh

# the following 3 lines are from SuSE.
# Determine the base and follow a runlevel link name.
base=${0##*/}
link=${base#*[SK][0-9][0-9]}

# the rest is by markus@wernig.net

# /etc/rc.d/firewall

# sets up a packet filtering firewall with masquerading and port forwarding
# (for transparent proxying by squid and/or dansguardian)
# see http://www.lugbe.ch/lostfound/contrib/router_biel.html

ARG=$1

. /etc/rc.config

[ $START_FW = 'yes' ] || ARG='stop' 

# 2 more SuSE lines ;-)
# The echo return value for success (defined in /etc/rc.config).
return=$rc_done

IPCHAINS=`which ipchains` || IPCHAINS=/sbin/ipchains
LOCALNET=192.168.1.0/24
EXTNET=147.87.65.0/24
DEFAULT_GW=147.87.65.250

# first we have to get our interfaces/addresses
# we start with a crude assumption: our local net starts with "192.168."
# might fail for some nets. 

# get address 192.168.*

MY_LOCAL_ADDR=`ifconfig |grep "192.168." | sed -e s/"inet addr\:"//g | awk '{print $1}'`

# get interface for address 192.168.*

for if in eth0 eth1
do 
	if ifconfig $if | grep "$MY_LOCAL_ADDR" >/dev/null 2>&1; then 
		MY_LOCAL_IF=$if
	else
		MY_EXT_IF=$if
	fi
done

# get other address

MY_EXT_ADDR=`ifconfig $MY_EXT_IF | grep "inet addr" | sed -e s/"inet addr\:"//g | awk '{print $1}'`

# blabber

echo "local: $MY_LOCAL_ADDR ($MY_LOCAL_IF), external: $MY_EXT_ADDR ($MY_EXT_IF)"

# script can be called by boot.local with "start" or "stop"

case "$ARG" in
    start)
	echo -n "Starting firewall"

	# set some kernel network parameters
	
	echo '1' > /proc/sys/net/ipv4/ip_forward
	echo '1' > /proc/sys/net/ipv4/tcp_syncookies
	for f in /proc/sys/net/ipv4/conf/*/rp_filter; do
        	echo '1' > $f
	done
	echo '0' > /proc/sys/net/ipv4/tcp_timestamps
	echo '30' > /proc/sys/net/ipv4/tcp_fin_timeout
	echo '1' > /proc/sys/net/ipv4/icmp_echo_ignore_all
	echo '1' > /proc/sys/net/ipv4/icmp_echo_ignore_broadcasts
	echo '1' > /proc/sys/net/ipv4/icmp_ignore_bogus_error_responses
	
	# set default policies and flush chains
	
	$IPCHAINS -P forward DENY || return=$rc_failed
	$IPCHAINS -P output ACCEPT || return=$rc_failed
	$IPCHAINS -P input DENY || return=$rc_failed
	$IPCHAINS -F || return=$rc_failed
	
	# drop foreign traffic without logging

	$IPCHAINS -A input ! -d $MY_EXT_ADDR -i $MY_EXT_IF -j DENY	

	# reject all ident traffic for faster responses 

	$IPCHAINS -A input -p tcp -d 0/0 auth -j REJECT
	$IPCHAINS -A input -p udp -d 0/0 auth -j REJECT

	# allow local traffic

	$IPCHAINS -A input -s $MY_LOCAL_ADDR -i lo -j ACCEPT
	$IPCHAINS -A input -s $MY_EXT_ADDR -i lo -j ACCEPT
	$IPCHAINS -A input -s 127.0.0.1 -i lo -j ACCEPT
	$IPCHAINS -A output -s $MY_LOCAL_ADDR -i lo -j ACCEPT
	$IPCHAINS -A output -s $MY_EXT_ADDR -i lo -j ACCEPT
	$IPCHAINS -A output -s 127.0.0.1 -i lo -j ACCEPT

	# allow dhcp queries

	$IPCHAINS -A input -p udp -s 0.0.0.0 68 -d 255.255.255.255 67 -i $MY_LOCAL_IF -j ACCEPT
	$IPCHAINS -A output -p udp -s $MY_LOCAL_ADDR 67 -d 255.255.255.255 68 -i $MY_LOCAL_IF -j ACCEPT

	# anti spoofing - only allow traffic to/from addresses on the corresponding interface

	$IPCHAINS -A input -s ! $LOCALNET -i $MY_LOCAL_IF -l -j DENY
	$IPCHAINS -A output -d ! $LOCALNET -i $MY_LOCAL_IF -l -j DENY
	$IPCHAINS -A input -s $LOCALNET ! -i $MY_LOCAL_IF -l -j DENY
	$IPCHAINS -A input -d $LOCALNET ! -i $MY_LOCAL_IF -l -j DENY
	$IPCHAINS -A output -s $LOCALNET ! -i $MY_LOCAL_IF -l -j DENY
	$IPCHAINS -A output -d $LOCALNET ! -i $MY_LOCAL_IF -l -j DENY
	$IPCHAINS -A output ! -s $MY_EXT_ADDR -i $MY_EXT_IF -l -j DENY

	# accept outgoing packets from localnet, but not to EXTNET (i.e. protect HTA from us;-)

	for net in $EXTNET
	do
		$IPCHAINS -A input -s $LOCALNET -d $net -l -j DENY
	done

	# allow port 80 -> is redirected to 8080 (dansguardian), from there to 3128
	
	$IPCHAINS -A input -p tcp -s $LOCALNET ! -d $LOCALNET 80 -y -l -i $MY_LOCAL_IF -j REDIRECT 8080 || return=$rc_failed
	$IPCHAINS -A input -p tcp -s $LOCALNET ! -d $LOCALNET 80 ! -y -i $MY_LOCAL_IF -j REDIRECT 8080 || return=$rc_failed

	# accept paccets directly at 8080

	$IPCHAINS -A input -p tcp -s $LOCALNET -d $MY_LOCAL_ADDR 8080 -y -l -j ACCEPT	
	$IPCHAINS -A input -p tcp -s $LOCALNET -d $MY_LOCAL_ADDR 8080 ! -y -j ACCEPT	

	# masquerade outgoing packets from localnet

	$IPCHAINS -A forward -s $LOCALNET -d ! $LOCALNET -i $MY_EXT_IF -j MASQ || return=$rc_failed

	$IPCHAINS -A input -p udp -s $LOCALNET ! -d $LOCALNET -i $MY_LOCAL_IF -j ACCEPT

	$IPCHAINS -A input -p tcp -s $LOCALNET ! -d $LOCALNET -y -l -i $MY_LOCAL_IF -j ACCEPT
	$IPCHAINS -A input -p tcp -s $LOCALNET ! -d $LOCALNET ! -y  -i $MY_LOCAL_IF -j ACCEPT

	# accept reply packets

	$IPCHAINS -A input -p udp ! -s $LOCALNET -d $MY_EXT_ADDR -i $MY_EXT_IF -j ACCEPT
	$IPCHAINS -A input -p tcp ! -s $LOCALNET -d $MY_EXT_ADDR ! -y -i $MY_EXT_IF -j ACCEPT


	# we allow some icmp messages
	
	for type in echo-request echo-reply destination-unreachable source-quench time-exceeded parameter-problem fragmentation-needed
	do
		$IPCHAINS -A input -p icmp -s $LOCALNET $type -i $MY_LOCAL_IF  -j ACCEPT || return=$rc_failed 
		$IPCHAINS -A input -p icmp -s 0/0 $type -d $MY_EXT_ADDR -i $MY_EXT_IF  -j ACCEPT || return=$rc_failed 
	done

	# the default gateway may send all icmp messages

	$IPCHAINS -A input -p icmp -s $DEFAULT_GW -d $MY_EXT_ADDR -i $MY_EXT_IF  -j ACCEPT || return=$rc_failed 
	

	# allow service requests to this host

	$IPCHAINS -A input -p udp -s $LOCALNET -d $MY_LOCAL_ADDR domain -j ACCEPT -l -i $MY_LOCAL_IF || return=$rc_failed
	$IPCHAINS -A input -p udp -s $LOCALNET -d $MY_LOCAL_ADDR ntp -j ACCEPT -i $MY_LOCAL_IF || return=$rc_failed
	$IPCHAINS -A input -p tcp -s $LOCALNET -d $MY_LOCAL_ADDR ntp -j ACCEPT -i $MY_LOCAL_IF || return=$rc_failed
	$IPCHAINS -A input -p udp -s $LOCALNET -d $MY_LOCAL_ADDR time -j ACCEPT -i $MY_LOCAL_IF || return=$rc_failed
	$IPCHAINS -A input -p tcp -s $LOCALNET -d $MY_LOCAL_ADDR time -y -j ACCEPT -i $MY_LOCAL_IF || return=$rc_failed
	$IPCHAINS -A input -p tcp -s $LOCALNET -d $MY_LOCAL_ADDR ssh -y -l -j ACCEPT -i $MY_LOCAL_IF || return=$rc_failed
	$IPCHAINS -A input -p tcp -s $LOCALNET -d $MY_LOCAL_ADDR ssh ! -y -j ACCEPT -i $MY_LOCAL_IF || return=$rc_failed

	# allow port 3128 (squid proxy) - this could be closed if we want all HTTP traffic
	# to go through 8080 (dansguardian) and not allow people to manually set their browser

	$IPCHAINS -A input -p tcp -s $LOCALNET -d $MY_LOCAL_ADDR 3128 -y -l -i $MY_LOCAL_IF -j ACCEPT || return=$rc_failed
	$IPCHAINS -A input -p tcp -s $LOCALNET -d $MY_LOCAL_ADDR 3128 ! -y -i $MY_LOCAL_IF -j ACCEPT || return=$rc_failed

	# timeout for masqueraded connections - else the session times out in 5 minutes 
	# and users on tcp sessions would have to reconnect (see ipchains --help)

	$IPCHAINS -M -S 7200 30 160

	# deny (and log) everything else

	$IPCHAINS -A input -l -j DENY || return=$rc_failed
	echo -e "$return"
	;;
    stop|open)
	echo -n "Opening up firewall"
	$IPCHAINS -P input ACCEPT
	$IPCHAINS -F
	echo '1' > /proc/sys/net/ipv4/ip_forward 
	$IPCHAINS -A forward -s $LOCALNET -d ! $LOCALNET -i $MY_EXT_IF -j MASQ || return=$rc_failed
	echo  -e "$return"
	# This now is a mere router with no firewall whatsoever. it just masquerades.
	
	;;
    close)
	echo -n "Shutting down firewall"
	$IPCHAINS -P input ACCEPT
	$IPCHAINS -F
	echo '0' > /proc/sys/net/ipv4/ip_forward 
	echo  -e "$return"
	# No more forwarding. The net is closed off, but this host is still reachable on all ports.
	;;
    reload|restart)
        $0 stop && sleep 3 && $0 start || return=$rc_failed
	;;
    *)
	echo "Usage: $0 {start|stop|status|reload|restart}"
	exit 1
esac

# Right, it's SuSE time again.
# Inform the caller not only verbosely and set an exit status.
test "$return" = "$rc_done" || exit 1
exit 0
