#!/bin/sh
# $Id: ipacset,v 1.7 1998/07/13 11:18:02 moritz Exp $
#
# Set accounting rules as told by config file
# Copyright (C) 1997, 1998 Moritz Both
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# 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., 675 Mass Ave, Cambridge, MA 02139, USA.
#
# The author can be reached via email: moritz@daneben.de, or by
# snail mail: Moritz Both, Im Moore 26, 30167 Hannover,
#             Germany. Phone: +49-511-1610129
#
# config file should be is $1
# =()<RUNFILE="@<RUNFILE>@">()=
RUNFILE="/var/run/ip-accounting-rules"
# =()<IPFWADM="@<IPFWADM>@">()=
IPFWADM="/sbin/ipfwadm"
# =()<CONFIGFILE="@<RULESFILE>@">()=
CONFIGFILE="/etc/ipac.conf"
# =()<FETCHIPAC="@<INSTALLPATH>@/fetchipac">()=
FETCHIPAC="/usr/local/bin/fetchipac"
# =()<LOCKFILE="@<LOCKFILE>@">()=
LOCKFILE="/var/lock/ipac.lck"

IPAC_PROC=/proc/net/ip_acct

TRYAGAIN=""

# -D enbales the debugging mode [FL]
if [ "$1" = "-D" ]; then
	# switch to debugging mode
	IPAC_DEBUG=y
	TESTECHO=echo
	# remove this paramter from list of parameters
	shift
fi

test x$1 != x && CONFIGFILE=$1
test x$2 != x && TRYAGAIN="y"

if [ ! -x $IPFWADM ]; then
	echo "$0: cant execute ipfwadm" >&2
	exit 1
fi

if [ x$CONFIGFILE = x ]; then
	echo "Usage: $0 configfile" >&2
	echo "See ipac documentation for details." >&2
	exit 1
fi

if [ ! -r $CONFIGFILE ]; then
	echo "$0: cant read config file $CONFIGFILE" >&2
	exit 1
fi

if [ ! -r $IPAC_PROC ]; then
	echo "$0: cant read \"$IPAC_PROC\" - exit" >&2
	exit 1
fi

# fetch now before resetting everything
# (if theres something to fetch)
test -r $RUNFILE && $FETCHIPAC

# prevent fetchipac from fetching now and myself from
# running twice
echo $$ >$LOCKFILE.$$ || exit 1
trap "rm -f $LOCKFILE.$$; exit 0" 1 2 3 15
if ln $LOCKFILE.$$ $LOCKFILE 2>/dev/null; then
	trap "rm -f $LOCKFILE.$$ $LOCKFILE; exit" 0 1 2 3 15
else
	if kill -0 `cat $LOCKFILE` 2>/dev/null; then
		rm -f $LOCKFILE.$$
		echo "$0: cant run twice at once, exiting"
		exit 1
	else
		rm -f $LOCKFILE
		if [ x$TRYAGAIN = xy ]; then
			echo "$0: Something weired is going on"
			exit 1
		fi
		echo "$0: removed old lock file, trying again"
		exec $0 $CONFIGFILE y
	fi
fi

sleep 5

$TESTECHO touch $RUNFILE || exit 1
>$RUNFILE

OFS=$IFS
IFS=\|

# delete existing accounting info
$TESTECHO $IPFWADM -Af

# remember the line count in /proc/net/ip_acct when empty
PROC_LINES=`wc -l < $IPAC_PROC`

# read the config file
exec <$CONFIGFILE
while read name direction interface protocol src destination; do
	test `expr "x$name" : "x#"` != 0 && continue
	# ignore empty lines [FL]
	if [ -z "$name" ]; then
		continue
	fi
	# some syntax checking [FL]
	if [ -z "$name" -o -z "$direction" -o -z "$interface" ]; then
		test -n "$IPAC_DEBUG" && echo "incomplete line in config file: "\
		     "\"$name|$direction|$interface|$protocol|$src|$destination\""
		continue
	fi
	
	if [ "x$interface" != "x" ]; then
		if [ `expr "$interface" : [0-9]` != 0 ]; then
			interface="-V $interface"
		else
			interface="-W $interface"
		fi
	fi

	if [ "x$protocol" = "x" ]; then
		protocol="all"
	fi

	if [ "x$src" = "x" ]; then
		src="0.0.0.0/0"
	fi

	if [ "x$destination" = "x" ]; then
		destination="0.0.0.0/0"
	fi

	# support bidirectional rules [FL]
	if [ "$direction" = "io" ]; then
		direction="both"
	fi

	# option for debugging added [FL]
	eval $TESTECHO $IPFWADM -A $direction -a $interface -P $protocol \
		-S $src -D $destination

	# figure out how many actual kernel rules ipfwadm added -
	# this is important when analysing the output of ipfwadm -Al
	# add that many lines to $RUNFILE
	N="$PROC_LINES"
	PROC_LINES=`wc -l < $IPAC_PROC`
	while [ $N -lt $PROC_LINES ]; do
		echo "$name" >>$RUNFILE
		N=`eval expr $N + 1`
	done
done
