#
#****************************************
#Bandmin (c)1998-1999 J. Nick Koston (BlueDraco)
# - A simple Bandwidth Monitor
#****************************************
#
#To use this package you must have a OS that has either ipfwadm,ipchains,iptables
#or ipfw
#

package IP::Acct;

require 5.004;
require Exporter;
use strict;
use Carp;

use vars qw(@ISA $VERSION $IPFWLINENUM $IPACCEPTALL);

$VERSION = 0.60;
$IPFWLINENUM = 1;
$IPACCEPTALL = 2;
@ISA = qw(Exporter);



sub new 
{
	my ($backend);
	my  $self = {};

	bless($self);

	if(-e "/sbin/iptables") {
		$self->{"backend"} = "iptables";		
	} elsif (-e "/sbin/ipchains") {
		$self->{"backend"} = "ipchains";
	} elsif(-e "/sbin/ipfwadm") {
		$self->{"backend"} = "ipfwadm";		
	} elsif(-e "/sbin/ipfw") {
		$self->{"backend"} = "ipfw";		
	} elsif(-e "/sbin/ipf") {
		$self->{"backend"} = "ipf";		
	} else {
		die "Can't find a backend (ipchains or ipfwadm or ipfw or ipf)";
	}

	return($self);

}

sub flush {
	my ($self) = @_;
	my ($rdt);
	my ($activerules,$rule,@RULES);

	if ($self->{"backend"} eq "ipchains") {
                system("/sbin/ipchains","-D","input","-j","acctboth");
                system("/sbin/ipchains","-D","output","-j","acctboth");
		system("/sbin/ipchains","-N","acctboth");
		system("/sbin/ipchains","-F","acctboth");
                system("/sbin/ipchains","-I","input","-j","acctboth");
                system("/sbin/ipchains","-I","output","-j","acctboth");
	}
	if ($self->{"backend"} eq "iptables") {
                system("/sbin/iptables","-D","INPUT","-j","acctboth");
                system("/sbin/iptables","-D","OUTPUT","-j","acctboth");
		system("/sbin/iptables","-N","acctboth");
		system("/sbin/iptables","-F","acctboth");
                system("/sbin/iptables","-I","INPUT","-j","acctboth");
                system("/sbin/iptables","-I","OUTPUT","-j","acctboth");
	}
	if ($self->{"backend"} eq "ipfwadm") {
		system("/sbin/ipfwadm","-A","-f");
	}
	if ($self->{"backend"} eq "ipf") {
		system("/sbin/ipf","-E");
		$activerules = `/sbin/ipfstat -a -i;/sbin/ipfstat -a -o`;
		@RULES = split(/\n/, $activerules);
		open(IPF,"|/sbin/ipf -r -f -");	
		foreach $rule (@RULES) {
			$rule =~ s/^(\d*)\s//g;
			print IPF "$rule\n";
		}
		close(IPF);
	}
	if ($self->{"backend"} eq "ipfw") {
		$rdt = "";
		while($rdt eq "") {
			$rdt = `/sbin/ipfw delete $IPACCEPTALL 2>&1`;
		}
		system("/sbin/ipfw","add",$IPACCEPTALL,"allow","all","from","any","to","any");
		$rdt = "";
		while($rdt eq "") {
			$rdt = `/sbin/ipfw delete $IPFWLINENUM 2>&1`;
		}
		
	}
}

sub initip {
	my ($self,
	  $ip
	) = @_;


        if ($self->{"backend"} eq "ipchains") {
		system("/sbin/ipchains","-A","acctboth","-s",$ip,"-b","-p","all");
        }
        if ($self->{"backend"} eq "iptables") {
		system("/sbin/iptables","-A","acctboth","-s",$ip,"-p","all");
		system("/sbin/iptables","-A","acctboth","-d",$ip,"-p","all");
        }
        if ($self->{"backend"} eq "ipfwadm") {
		system("/sbin/ipfwadm","-A","out","-a","-P","all","-S",$ip);
		system("/sbin/ipfwadm","-A","in","-a","-P","all","-D",$ip);
	}
        if ($self->{"backend"} eq "ipfw") {
		system("/sbin/ipfw","add",$IPFWLINENUM,"count","all","from","any","to",$ip);
		system("/sbin/ipfw","add",$IPFWLINENUM,"count","all","from",$ip,"to","any");
	}
        if ($self->{"backend"} eq "ipf") {
		open(IPF,"|/sbin/ipf -f -");	
		print IPF "count out from $ip to any\n";
		print IPF "count in from any to $ip\n";
		close(IPF);	
	}
}

sub initall {
	my ($self) = @_;

        if ($self->{"backend"} eq "ipchains") {
		system("/sbin/ipchains","-A","acctboth","-s","0.0.0.0/0","-d","0.0.0.0/0");
        }
        if ($self->{"backend"} eq "iptables") {
		system("/sbin/iptables","-A","acctboth","-s","0.0.0.0/0","-d","0.0.0.0/0");
        }
        if ($self->{"backend"} eq "ipfwadm") {
		system("/sbin/ipfwadm","-A","-a","-P","all","-S","0.0.0.0/0","-D","0.0.0.0/0");
	}
        if ($self->{"backend"} eq "ipfw") {
		system("/sbin/ipfw","add",$IPFWLINENUM,"count","all","from","any","to","any");
		system("/sbin/ipfw","add",$IPFWLINENUM,"count","all","from","any","to","any");
	}
        if ($self->{"backend"} eq "ipf") {
		open(IPF,"|/sbin/ipf -f -");	
		print IPF "count out from any to any\n";
		print IPF "count in from any to any\n";
		close(IPF);	
	}

}


sub getipbytes {
        my ($self) = @_;

	my($ipdata,$ipstuff,@IPMASS,$ip,$bytes,%ipbytemap,$rule);

        if ($self->{"backend"} eq "ipchains") {
        	$ipstuff = `/sbin/ipchains -L acctboth -v -x -n`;
	}
        if ($self->{"backend"} eq "iptables") {
        	$ipstuff = `/sbin/iptables -L acctboth -v -x -n`;
	}
        if ($self->{"backend"} eq "ipfwadm") {
	        $ipstuff = `/sbin/ipfwadm -Alxn`;
	}
        if ($self->{"backend"} eq "ipfw") {
		$ipstuff = `/sbin/ipfw -a list $IPFWLINENUM`;
	}
        if ($self->{"backend"} eq "ipf") {
		$ipstuff = `/sbin/ipfstat -a -i;/sbin/ipfstat -a -o`;
	}


	@IPMASS = split(/\n/, $ipstuff);
	foreach $ipdata (@IPMASS) {
        	$ipdata =~ s/\t/ /g;
        	$ipdata =~ s/\s(\s*|.)\s/ /g;
        	$ipdata =~ s/^ //g;
        	$ipdata =~ s/\n//g;

		if ($ipdata eq "") { next; }

		$bytes = 0;
		$ip = "";
	        if ($self->{"backend"} eq "ipchains" || $self->{"backend"} eq "iptables") {
			if ($ipdata =~ /^\d* (\d*) .* (\d*\.\d*\.\d*\.\d*) \d*\.\d*\.\d*\.\d*\/\d*/ ) {
				$ip = $2;
				$bytes = $1;
			} elsif ($ipdata =~ /^\d* (\d*) .* \d*\.\d*\.\d*\.\d*\/\d* (\d*\.\d*\.\d*\.\d*) /) {
				$ip = $2;
				$bytes = $1;
			} elsif ($ipdata =~ /^\d* (\d*) .* 0\.0\.0\.0\/0 0\.0\.0\.0\/0/) {
				$ip = "all";
				$bytes = $1;
			}
	        }
		if ($self->{"backend"} eq "ipfwadm") {
                        if ($ipdata =~ /(\d*\.\d*\.\d*\.\d*) /) {
                                $ip = $1;
                        } elsif ($ipdata =~ /0\.0\.0\.0\/0 0\.0\.0\.0\/0/) {
                                $ip = "all";
                        }
			$ipdata =~ /^\d* (\d*)/; 
			$bytes = $1;
	        }
		if ($self->{"backend"} eq "ipf") {
			$ipdata =~ /^(\d*)/;
			$bytes = $1;
			if ($ipdata =~ /(\d*\.\d*\.\d*\.\d*)/) {
				$ip = $1;
			} elsif ($ipdata =~ /any to any/) {
				$ip = "all";
			}
	        }
		if ($self->{"backend"} eq "ipfw") {
	                (undef,undef,$bytes,
			$rule) = split(/\s/,$ipdata, 4);
        		if ($rule =~ /(\d*\.\d*\.\d*\.\d*)/) {
                		$ip = $1;
			} elsif ($ipdata =~ /any to any/) {
				$ip = "all";
			}
	        }
        	if ($ip =~ /(.*)\.(.*)\.(.*)/ || $ip eq "all") {
                	$ip =~ s/\n//g;
                	$bytes =~ s/\n//g;
			$ipbytemap{$ip} = ($ipbytemap{$ip} + $bytes);
		}
	}
	
	return(%ipbytemap);

}

sub clearcounter {
        my ($self) = @_;
	my ($activerules,$rule,@RULES);

        if ($self->{"backend"} eq "ipchains") {
        	system("/sbin/ipchains","-Z","acctboth");
	}
        if ($self->{"backend"} eq "iptables") {
        	system("/sbin/iptables","-Z","acctboth");
	}
        if ($self->{"backend"} eq "ipfwadm") {
	        system("/sbin/ipfwadm","-Az");
	}

        if ($self->{"backend"} eq "ipf") {
		$activerules = `/sbin/ipfstat -a -i;/sbin/ipfstat -a -o`;
		@RULES = split(/\n/, $activerules);
		open(IPF,"|/sbin/ipf -z -f - >/dev/null");	
		foreach $rule (@RULES) {
			$rule =~ s/^(\d*)\s//g;
			print IPF "$rule\n";
		}
		close(IPF);
	}

        if ($self->{"backend"} eq "ipfw") {
	        system("/sbin/ipfw","zero",$IPFWLINENUM);
	}


}
