File: //usr/local/bandmin/IP/Acct.pm
#
#****************************************
#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/ipchains") {
$self->{"backend"} = "ipchains";
my $nulltable = `/sbin/ipchains -L null 2>&1`;
if ($nulltable =~ /Incompatible with this kernel/i) {
$self->{"backend"} = "iptables";
if (! -e "/sbin/iptables" && -e "/sbin/iptables.old") {
symlink("/sbin/iptables.old","/sbin/iptables");
}
}
} elsif(-e "/sbin/iptables") {
$self->{"backend"} = "iptables";
} elsif(-e "/sbin/ipfwadm") {
$self->{"backend"} = "ipfwadm";
} elsif(-e "/sbin/ipfw") {
$self->{"backend"} = "ipfw";
} elsif(-e "/sbin/ipf") {
$self->{"backend"} = "ipf";
} elsif(-e "/sbin/iptables.old") {
$self->{"backend"} = "iptables";
symlink("/sbin/iptables.old","/sbin/iptables");
} 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","-F","acctboth");
system("/sbin/ipchains","-X","acctboth");
system("/sbin/ipchains","-N","acctboth");
system("/sbin/ipchains","-I","input","-j","acctboth");
system("/sbin/ipchains","-I","output","-j","acctboth");
}
if ($self->{"backend"} eq "iptables") {
my $nulltable = `/sbin/iptables -L acctboth -n 2>&1`;
if ($nulltable !~ /acctboth/) {
#system("/sbin/iptables","-D","INPUT","-j","acctboth");
#system("/sbin/iptables","-D","OUTPUT","-j","acctboth");
#system("/sbin/iptables","-F","acctboth");
#system("/sbin/iptables","-X","acctboth");
system("/sbin/iptables","-N","acctboth");
system("/sbin/iptables","-I","INPUT","-j","acctboth");
system("/sbin/iptables","-I","OUTPUT","-j","acctboth");
}
system("/sbin/iptables","-F","acctboth");
}
if ($self->{"backend"} eq "ipfwadm") {
die "ipfwadm support is broken .. please fix";
system("/sbin/ipfwadm","-A","-f");
}
if ($self->{"backend"} eq "ipf") {
die "ipf support is broken .. please fix";
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") {
die "ipfw support is broken .. please fix";
$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,
@SERVICES
) = @_;
my($service);
if ($self->{"backend"} eq "ipchains") {
foreach $service (@SERVICES) {
system("/sbin/ipchains","-A","acctboth","-s",$ip,"--destination-port","$service","-p","tcp","-i","!","lo");
system("/sbin/ipchains","-A","acctboth","-d",$ip,"--source-port","$service","-p","tcp","-i","!","lo");
}
system("/sbin/ipchains","-A","acctboth","-s",$ip,"-p","icmp","-i","!","lo");
system("/sbin/ipchains","-A","acctboth","-d",$ip,"-p","icmp","-i","!","lo");
system("/sbin/ipchains","-A","acctboth","-s",$ip,"-p","tcp","-i","!","lo");
system("/sbin/ipchains","-A","acctboth","-d",$ip,"-p","tcp","-i","!","lo");
system("/sbin/ipchains","-A","acctboth","-s",$ip,"-p","udp","-i","!","lo");
system("/sbin/ipchains","-A","acctboth","-d",$ip,"-p","udp","-i","!","lo");
system("/sbin/ipchains","-A","acctboth","-s",$ip,"-p","all","-i","!","lo");
system("/sbin/ipchains","-A","acctboth","-d",$ip,"-p","all","-i","!","lo");
}
if ($self->{"backend"} eq "iptables") {
foreach $service (@SERVICES) {
system("/sbin/iptables","-A","acctboth","-s",$ip,"-p","tcp","--destination-port","$service","!","-i","lo");
system("/sbin/iptables","-A","acctboth","-d",$ip,"-p","tcp","--source-port","$service","!","-i","lo");
}
system("/sbin/iptables","-A","acctboth","-s",$ip,"-p","icmp","!","-i","lo");
system("/sbin/iptables","-A","acctboth","-d",$ip,"-p","icmp","!","-i","lo");
system("/sbin/iptables","-A","acctboth","-s",$ip,"-p","tcp","!","-i","lo");
system("/sbin/iptables","-A","acctboth","-d",$ip,"-p","tcp","!","-i","lo");
system("/sbin/iptables","-A","acctboth","-s",$ip,"-p","udp","!","-i","lo");
system("/sbin/iptables","-A","acctboth","-d",$ip,"-p","udp","!","-i","lo");
system("/sbin/iptables","-A","acctboth","-s",$ip,"-p","all","!","-i","lo");
system("/sbin/iptables","-A","acctboth","-d",$ip,"-p","all","!","-i","lo");
}
if ($self->{"backend"} eq "ipfwadm") {
die "ipfwadm support is broken .. please fix";
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") {
die "ipfw support is broken .. please fix";
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") {
die "ipf support is broken .. please fix";
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","-i","!","lo");
}
if ($self->{"backend"} eq "iptables") {
system("/sbin/iptables","-A","acctboth","-s","0.0.0.0/0","-d","0.0.0.0/0","!","-i","lo");
}
if ($self->{"backend"} eq "ipfwadm") {
die "ipfwadm support is broken .. please fix";
system("/sbin/ipfwadm","-A","-a","-P","all","-S","0.0.0.0/0","-D","0.0.0.0/0");
}
if ($self->{"backend"} eq "ipfw") {
die "ipfw support is broken .. please fix";
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") {
die "ipf support is broken .. please fix";
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);
my($protocol,$port,$path);
if ($self->{"backend"} eq "ipchains") {
$ipstuff = `/sbin/ipchains -L acctboth -v -x -n`;
}
if ($self->{"backend"} eq "iptables") {
my $nulltable = `/sbin/iptables -L acctboth -n 2>&1`;
if ($nulltable !~ /acctboth/) {
system("/usr/local/bandmin/bandminstart");
}
$ipstuff = `/sbin/iptables -L acctboth -v -x -n`;
}
if ($self->{"backend"} eq "ipfwadm") {
die "ipfwadm support is broken .. please fix";
$ipstuff = `/sbin/ipfwadm -Alxn`;
}
if ($self->{"backend"} eq "ipfw") {
die "ipfw support is broken .. please fix";
$ipstuff = `/sbin/ipfw -a list $IPFWLINENUM`;
}
if ($self->{"backend"} eq "ipf") {
die "ipf support is broken .. please fix";
$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 = '';
$port = '';
$protocol = '';
$path = '';
if ($self->{"backend"} eq "iptables") {
if ($ipdata =~ /^\d* (\d*)\s+(\S+) .* \d*\.\d*\.\d*\.\d*\/\d* (\d*\.\d*\.\d*\.\d*) \S+ (\S+)/) {
$ip = $3;
$bytes = $1;
$protocol = $2;
$port = $4;
$port =~ s/^.pt://g;
$path = 'in';
} elsif ($ipdata =~ /^\d* (\d*)\s+(\S+) .* (\d*\.\d*\.\d*\.\d*) \d*\.\d*\.\d*\.\d*\/\d* \S+ (\S+)/) {
$ip = $3;
$bytes = $1;
$protocol = $2;
$port = $4;
$port =~ s/^.pt://g;
$path = 'out';
} elsif ($ipdata =~ /^\d* (\d*)\s+(\S+) .* (\d*\.\d*\.\d*\.\d*) \d*\.\d*\.\d*\.\d*\/\d* / ) {
$ip = $3;
$protocol = $2;
$bytes = $1;
$path = 'out';
} elsif ($ipdata =~ /^\d* (\d*)\s+(\S+) .* \d*\.\d*\.\d*\.\d*\/\d* (\d*\.\d*\.\d*\.\d*) /) {
$ip = $3;
$bytes = $1;
$protocol = $2;
$path = 'in';
} elsif ($ipdata =~ /^\d* (\d*)\s+(\S+) .* 0\.0\.0\.0\/0 0\.0\.0\.0\/0/) {
$ip = "all";
$bytes = $1;
$protocol = $2;
}
if($port eq "n/a" || $port eq "*") { $port = ''; }
}
if ($self->{"backend"} eq "ipchains") {
if ($ipdata =~ /^\d* (\d*)\s+(\S+) .* (\d*\.\d*\.\d*\.\d*) \d*\.\d*\.\d*\.\d*\/\d* \S+.*\-\> (\S+)/) {
$ip = $3;
$bytes = $1;
$protocol = $2;
$port = $4;
$path = 'out';
} elsif ($ipdata =~ /^\d* (\d*)\s+(\S+) .* (\d*\.\d*\.\d*\.\d*) \d*\.\d*\.\d*\.\d*\/\d* (\S+)/) {
$ip = $3;
$bytes = $1;
$protocol = $2;
$port = $4;
$path = 'out';
} elsif ($ipdata =~ /^\d* (\d*)\s+(\S+) .* \d*\.\d*\.\d*\.\d*\/\d* (\d*\.\d*\.\d*\.\d*) (\S+)/) {
$ip = $3;
$bytes = $1;
$protocol = $2;
$port = $4;
$path = 'in';
} elsif ($ipdata =~ /^\d* (\d*)\s+(\S+) .* (\d*\.\d*\.\d*\.\d*) \d*\.\d*\.\d*\.\d*\/\d* / ) {
$ip = $3;
$protocol = $2;
$bytes = $1;
$path = 'in';
#outgoing
} elsif ($ipdata =~ /^\d* (\d*)\s+(\S+) .* \d*\.\d*\.\d*\.\d*\/\d* (\d*\.\d*\.\d*\.\d*) /) {
$ip = $3;
$bytes = $1;
$protocol = $2;
$path = 'out';
} elsif ($ipdata =~ /^\d* (\d*)\s+(\S+) .* 0\.0\.0\.0\/0 0\.0\.0\.0\/0/) {
$ip = "all";
$bytes = $1;
$protocol = $2;
}
if($port eq "n/a" || $port eq "*") { $port = ''; }
}
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;
if($port ne "") {
$ipbytemap{"${ip}-${protocol}-${path}-${port}"} += $bytes;
} elsif ($path ne "") {
$ipbytemap{"${ip}-${protocol}-${path}"} += $bytes;
} else {
$ipbytemap{"${ip}-${protocol}"} += $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") {
die "ipfwadm support is broken .. please fix";
system("/sbin/ipfwadm","-Az");
}
if ($self->{"backend"} eq "ipf") {
die "ipf support is broken .. please fix";
$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") {
die "ipfw support is broken .. please fix";
system("/sbin/ipfw","zero",$IPFWLINENUM);
}
}