#!/bin/sh
# Tool for help in building firewalls using iptables/ipchains.
# License: GNU GPL
# (c) 2002 Olgierd Pieczul <wojrus@pld.org.pl>
#
# chkconfig: 345 09 98
# description: firewall is a tool helping in building firewalls

# $Revision: 1.20 $, $Date: 2002/08/30 12:44:08 $

if [ -f  /etc/rc.d/init.d/functions ]; then
	  . /etc/rc.d/init.d/functions 
else
	export MODE=debug
	$0 $*
fi 

if [ -f /etc/sysconfig/firewall ]; then
	. /etc/sysconfig/firewall
fi
# TODO: automagically guess which tool should be used (how?)
if [ ! "$USERSPACE_TOOL" = "ipchains" ] && [ ! "$USERSPACE_TOOL" = "iptables" ]; then
	echo 'You must have USERSPACE_TOOL set to "iptables" or "ipchains"'
	exit 1
fi

. /usr/share/tree-firewall/functions-$USERSPACE_TOOL
# debug mode (default: false)
if [ "$MODE" = "debug" ]; then
	debug="true"
else
	debug="false"
fi

# root directory (default: /etc/firewall) 
if [ "$ROOT" ]; then
	root="$ROOT"	  
else
	root="/etc/firewall"
fi

# clean method (default: clean)
if [ "$CLEAN_METHOD" = "clean" ] || [ "$CLEAN_METHOD" = "flush" ]; then
		clean=$CLEAN_METHOD
else
		clean="clean"
fi

#directory for copies of sets
tmpdir=/tmp/tree-firewall

typeset ret=0

# set rules for each chain in given directory.
chains() {
	action=$1; dir=$2; table=$3; # $3 can be empty (ipchains)
	if [ "$action" = "addfirst" ]; then
		# read from the end (but add with -I)
		cat="tac"
	else 
		cat="cat"
	fi
	for chain in $(ls -1 $dir/* | egrep -v '~$'); do
		if [ -f $chain ]; then
# i know, i'm lame ;P
			tmp="$IFS"; IFS='
'	
			for args in $($cat $chain | egrep -v "^\#"); do
				IFS="$tmp"
				if [ "$args" ]; then
					${action}_rule $(basename $chain) "$args" $table || ret=1 
				fi
			done
		fi
	done	
	return $ret
}

do_set () {
	action=$1; set=$2
	if [ -d $root/sets/$set ]; then
		if [ "$action" = "add" ] || [ "$action" = "addfirst" ] && [ -d $tmpdir/$root/sets/$set ]; then
			echo "error: Set \"$set\" has been already added! You should firstly remove it."
    		elif [ "$action" = "del" ] && [ ! -d $tmpdir/$root/sets/$set ]; then
			echo "error: Set \"$set\" is not added!"
		elif [ "$debug" = "false" ]; then
			# show nice message
			if [ "$action" = "add" ] || [ "$action" = "addfirst" ]; then
				show "Firewall: Adding set: $set"
			elif [ "$action" = "del" ]; then
				show "Firewall: Removing set: $set"
			fi
			busy
			tables $action $set && ok || fail
		else
			# "raw" message
			echo "# $set"
			tables $action $set
		fi
		if [ "$action" = "add" ] || [ "$action" = "addfirst" ]; then
			# make copy of set
			mkdir -p $tmpdir/$root/sets > /dev/null
			cp -R $root/sets/$set $tmpdir/$root/sets > /dev/null
		elif [ "$action" = "del" ]; then
			# remove old copy
			rm -rf $tmpdir/$root/sets/$set > /dev/null
		fi
    	else
		  echo "error: No such set: $set"
	fi
}

do_policy () {
	policy=$1
	if [ "$policy" = "default" ] || [ "$policy" = "clean" ]; then
		if [ -d "$root/policies/$policy" ]; then
			if [ "$debug" = "false" ]; then
				show "Firewall: Setting policy: $policy"
				busy
				tables policy $policy && ok || fail
	    		else
				echo "# policy"
			  	tables policy $policy
			fi
		else
			echo "error: Can't find $root/policies/$policy!"
		fi
	else
		echo "error: Unknown policy! Use \"default\" or \"clean\"."
	fi
}

do_flush() {
	if [ "$debug" = "false" ]; then
		show "Firewall: Flushing"
		busy
		flush && ok || fail
	else
		echo "# flush"
		flush	
	fi
	rm -rf $tmpdir/*
}

case "$1" in
# debug mode
-v)
	export MODE="debug"
	shift
	$0 $*
	;;
# alternative root
-d)
	if [ -d $2 ]; then
		export ROOT="$2"
		shift; shift;
		$0 $*
	else
		echo "error: No such directory: $2!"
    		exit 1
    	fi
	;;
# do something with set 	
add | addfirst | del)
	action=$1; sets=$2
	if [ $sets ]; then
		case "$sets" in
		all)
			if [ -f $root/default ]; then
				for set in $(cat $root/default); do
					$0 $action $set
				done
			else
				for set in $root/sets/*; do
					if [ -d $set ] ; then
						$0 $action $(basename $set)
					fi
				done
			fi
			;;
		*)
			# more then one set to do
			if [ $# -gt 2 ]; then
				shift
				for set in $*; do
					$0 $action $set
				done
			else
				do_set $action $sets
			fi
			;;
		esac
	else
		echo "Usage: $0 $action set-name"
	    	fi
		;;
# set policy (default or clean)
policy)
	if [ $2 ]; then
		do_policy $2
	else
		echo "Usage: $0 policy (default|clean)"
	fi
	;;

clean)
	shift
	$0 $* del all
	if [ $MODULES ]; then
		modprobe -r $MODULES
	fi
	;;

flush)
	do_flush
	;;

stop)
	$0 policy clean
	$0 $clean
	if [ $MODULES ]; then
		modprobe -r $MODULES
	fi
	;;

tree)
	echo "*"
	tree $root -I "*~" | egrep -
	;;

start)
    if [ $MODULES ]; then
		modprobe $MODULES
	fi
	$0 policy default
	$0 add all
	;;

restart | reload)
	$0 stop
	$0 start
	;;	

status)
	echo "Sets from $root: "
	for set in $tmpdir/$root/sets/*; do
		echo "- $(basename $set)"
	done
	;;
*)
	echo "Usage: $0 (start|stop|restart|add|addfirst|del|policy|status)"
esac
