#!/bin/sh
# $Id: fetchipac,v 1.20 1999/08/06 10:53:22 moritz Exp $
#
# Fetch IP accounting stats
# Copyright (C) 1997 - 1999 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
#

# =()<ACCTDIR="@<ACCTDIR>@">()=
ACCTDIR="/var/log/ip-acct"
# =()<RUNFILE="@<RUNFILE>@">()=
RUNFILE="/var/run/ip-accounting-rules"
# =()<IPFWADM="@<IPFWADM>@">()=
IPFWADM="/sbin/ipfwadm"
# =()<IPCHAINS="@<IPCHAINS>@">()=
IPCHAINS=""
# =()<IPACSET="@<INSTALLPATH>@/ipacset">()=
IPACSET="/usr/local/bin/ipacset"
# =()<DATDELIM="@<DATDELIM>@">()=
DATDELIM="#-#-#-#-#"
# =()<LOCKFILE="@<LOCKFILE>@">()=
LOCKFILE="/var/lock/ipac.lck"
# =()<AWK="@<AWK>@">()=
AWK="/usr/bin/awk"
# =()<CH_INNAME="@<CH_INNAME>@">()=
CH_INNAME="ipac_in"
# =()<CH_OUTNAME="@<CH_OUTNAME>@">()=
CH_OUTNAME="ipac_out"
# =()<CH_IONAME="@<CH_IONAME>@">()=
CH_IONAME="ipac_bth"
# =()<IPFWADM_PROC="@<IPFWADM_PROC>@">()=
IPFWADM_PROC="/proc/net/ip_acct"
# =()<IPCHAINS_PROC_C="@<IPCHAINS_PROC_C>@">()=
IPCHAINS_PROC_C="/proc/net/ip_fwchains"


# Options to ipfwadm: l=list, A=Accounting, n=numeric output,
#          x=eXpand numbers (display exact values), v=verbose, 
#          e=extended output mode, z=reset counters
OPTS="-lAnxvez"

# Options to ipchains:
CH_OPTS="--list --numeric --exact --verbose --zero"


if [ -f $IPFWADM_PROC ]; then
        HAVE_IPCHAINS=no
        if [ -z "$IPFWADM" ]; then
                echo "$0: ipfwadm tool missing" >&2
                exit 1
        fi
        if [ ! -x $IPFWADM ]; then
                echo "$0: cant execute $IPFWADM" >&2
                exit 1
        fi
elif [ -f $IPCHAINS_PROC_C ]; then
        HAVE_IPCHAINS=yes
        if [ -z "$IPCHAINS" ]; then
                echo "$0: ipchains tool missing" >&2
                exit 1
        fi
        if [ ! -x $IPCHAINS ]; then
                echo "$0: cant execute $IPCHAINS" >&2
                exit 1
        fi
	# Check if all chains and jumps are there or if some
	# firewall script deleted them. (This check is only an estimate.)
	if [ `egrep -c "(input|output) .* ($CH_INNAME|$CH_OUTNAME|$CH_IONAME)"\
			$IPCHAINS_PROC_C` != 4 ]; then
		# we have indeed corrupted chains. Try to fix them.
		echo "$0: Warning: ipac chains and/or jumps are corrupted. Trying to fix them" >&2
		$IPACSET --fix-chains
	fi
else
        echo "$0: no ip firewall / accounting code in the kernel" >&2
        exit 1
fi

if [ -f $LOCKFILE ]; then
	# lock file exists, so ipacset might be running
	# remove lock file if process died.
	if kill -0 `cat $LOCKFILE` 2>/dev/null; then
		:
	else
		rm -f $LOCKFILE
		test -f $LOCKFILE || exec $0
	fi
	exit 1
fi

if [ ! -r $RUNFILE ]; then
	# no run file?
	echo "$0: Cant read \"$RUNFILE\" - ipacset not run?" >&2
	exit 1
fi

test -d $ACCTDIR || mkdir $ACCTDIR
if [ ! -d $ACCTDIR ]; then
	echo "$0: cant create \"$ACCTDIR\" - exit" >&2
	exit 1
fi

FILE=$ACCTDIR/`date +"%Y%m%d-%H%M%S"`

if [ $HAVE_IPCHAINS = yes ]; then
	# we need to re-sort the output of ipchains according to the
	# order in $RUNFILE.
	ORDER=`while read CHAIN REST; do 
		echo -n "$CHAIN "
		echo $REST >> $FILE
	done <$RUNFILE`
	echo "$DATDELIM" >>$FILE
	$IPCHAINS $CH_OPTS | \
		$AWK -v CH_INNAME=$CH_INNAME -v CH_OUTNAME=$CH_OUTNAME \
				-v CH_IONAME=$CH_IONAME -v ORDER="$ORDER" '
			BEGIN	{ iin=0; iout=0; iio=0; }
			/^Chain / { 
				if ($2==CH_INNAME) p=1
				else if ($2 == CH_OUTNAME) p=2
				else if ($2 == CH_IONAME) p=3
				else p=0

				next
			}
			/^ *[0-9]+ +[0-9]+ / {
				if (p==1)	{ _in[iin++] = $1 " " $2 }
				else if (p==2)	{ out[iout++] = $1 " " $2 }
				else if (p==3)	{ io[iio++] = $1 " " $2 }
			}
			END {
				iin=0; iout=0; iio=0;
				n = split(ORDER, o, / /)
				for (i=1; i<n; i++) {
					if (o[i] == CH_INNAME) 
						print _in[iin++]
					else if (o[i] == CH_OUTNAME)
						print out[iout++]
					else
						print io[iio++]
				}
			}
		' \
		>>$FILE
else
	cat $RUNFILE >$FILE || exit 1
	echo "$DATDELIM" >>$FILE
	$IPFWADM $OPTS >>$FILE
fi

# EOF
