Начало Вход/Регистрация Помощ Tazi stranica s latinski bukwi
Области
 Новини
 Актуална тема
 Linux портали
 Какво е Линукс?
 Въпроси-отговори
 Форуми
   •Трудова борса
   •Конкурс
 Статии
 Дистрибуции
   •Поръчка на CD
 Made In BG
 Файлове
 Връзки
 Галерия
 Конференции
Настройки
 Външен вид
 Предложения
 Направи си сам
И още ...
 За нас
 Линукс за българи ЕООД
 Линк към нас
 Предложения

Подкрепяно от:
TelePoint - Място за хора със свободни идеи

SiteGround

initLab

Adsys Group

SAP Bulgaria

Въпроси отговори
Въпрос: трафик
[Търси: ]

ВНИМАНИЕ: Използвайте форумите на сайта за дa зададете вашите въпроси.

Към началото |Добави въпрос |Отговори
 
Въпрос
От: plamen Дата: 03/24/2004
ТОВА ДАЛИ СТЕ СВЪРШИ РАБОТА

#!/usr/bin/perl
#quick code by <steffen@dett.de> under Terms of GPL 
#                          what's free it's free...
#$Revision: 1.24 $

#some kind of autodetection for chains/ipfwadm
#  in chains mode, an chain "account" is used.
#ipfwadm mode is beeing dropped in future versions.

 #data is stored persistent in /var/log/accountings
($sum_file)
#  you should call this script often in quite mode ($0 -q)
 #  to keep this file uptodate. Once a day (or week or...)
you
#  could call it by cron without parameters to get a mail
#  (STDOUT) with the formated output

#Examples:
#  build Chain "account"
#ipchains -A account -i eth0
#ipchains -A account -i ipsec0
#ipchains -A account -s 192.168.1.1
#  (...)
#insert into master chain:
#ipchains -I input -j account
#ipchains -I output -j account
  # use script often with "-q" (quite), and to display
invoke
it without
#paramters



#Output looks like (here with german language)
#  (errors are english always)
#
#  Account logger for Steffen's firewall $Revision: 1.24 $
## Stufe 1:  Laden bisheriger Werte
## Stufe 2:  Analysieren der Firewalldaten
## Stufe 3:  Speichern der Werte
## Stufe 4:  Ruecksetzen der Firewallzaehler
## Stufe 5:  Ausgabe der berechten Werte
#
 #------------------------------[ Hosts
]------------------------------
#
#Gerдt   eth0:
#     dev    <-->          107.96 MB               12.65 DM
#Gerдt   eth1:
#     dev    <-->           24.91 MB                2.92 DM
#Gerдt   lo:
#     dev    <-->            4313.00 KB             0.49 DM
#Gerдt   ippp6:
#     dev    <-->            2253.02 KB             0.26 DM
#Host 192.168.1.1 [www.domain.com]:
#     in     <---           11.86 MB                1.39 DM
#     out    --->           77.95 MB                9.14 DM
#Host anywhere []:
#     in     <---           25.83 MB                3.03 DM
#     out    --->           25.83 MB                3.03 DM
#Host 192.168.1.2 [mail.domain.com]:
#     in     <---               7.36 KB             0.00 DM
#     out    --->              41.67 KB             0.00 DM
#Host 192.168.1.3 []:
#     in     <---               0.00 KB             0.00 DM
#     out    --->               0.00 KB             0.00 DM
#
 #------------------------------[ SUMME
]------------------------------
#
#     dev    <-->          141.69 MB               16.60 DM
#     in     <---           37.70 MB                4.42 DM
#     out    --->          103.83 MB               12.17 DM
#  Gesammt   <-->          283.21 MB              120.00 DM
#
 #-----------------------[ Kostende Interfaces
]-----------------------
#
#      eth0  <-->          107.96 MB              120.00 DM
#

use strict;
use Socket;

my $english = "1"; #set to "0" for some german output

#persistente Info in:
my $sum_file="/var/log/accountings";

my @PAY_DEVS=(" eth0"); #devs on what traffic must be payed

#z.B. auch 3 fьr Parser etc.
#engl: i.e. level 3 traces parser and so on.
 #  debug level below usually completly senseless, use 1 or
2...
my $DEBUG=0;

#Ausgaben unterdrьcken (fьr hourly-cron)
#engl. suppresses output if set (i.e. for cron)
my $quite = 0; 
my $mode="";
my $print_mode="2";
my $TEST="no";
my $host_names="yes";

sub parse_ipfw($)
{
    #parses line from ipfwadm
    my $line = shift;
    my @entry;
	if (($line =~ /IP accounting rules/) or
        ($line =~ /pkts bytes dir prot/) ) {
        return undef;
    }
	@entry = split(" ", $line); #space separated
    return @entry;
}

sub parse_chains($)
{
     #the chain "account" is inserted into input and output
chain
    #  (what means that direction is i/o)
    #  for use with firewall.std Rev1.25 or higher 
    #parses line from ipfwadm
    my $line = shift;
    my @entry;
	if (($line =~ /^Chain account/) or
        ($line =~ /^ pkts bytes target     prot opt/) ) {
        print "  Skipped: $line\n" if ($DEBUG>3);
        return undef;
    }
    chomp $line;
    $line =~ s/^\s+//; #no leading spaces
	#my ($pkts, $bytestr, $target, $prot, $opt, $tosa, $tosx,
     #    $ifname, $mark, $outsize, $src, $dest, $port,
$junk) 
     #    = split(/\s{1,14}/, $line); #space separated, max
14
    #                                #char width
	my ($pkts, $bytestr, $target, $prot, $opt, $tosa, $tosx,
        $ifname, @rest) 
         = split(/\s+/, $line); #normal, non-empty space
speparateds
    my ($mark, $outsize, $src, $dest, $port, $junk) ;
    my $rest = join (" ", @rest); #make normal string back
    if (!defined $rest or ($rest eq "")) {
         print "Warning: Parse problem (no rest)!\n" if
($DEBUG);
    } else {
        print "Expr: '$rest'\n" if ($DEBUG>5);
        #parse rest by regEx
        if ($rest =~ m/^((\S+)\s+)?    #possible: mark
                        ((\S+)\s+)?    #possible: outsize
                         (\S+)\s+      #must: source
                         (\S+)\s+      #      dest
                         (\S+)         #      port
                       $/x ) {
            $mark = $1;
            $outsize = $3;
            $src=$5;
            $dest=$6;
            $port=$7;
         } else {
              print "Warning: Parse problem (no match)!\n"
if
($DEBUG);
         }
    }
    my $dir="i/o";
         
    if (!defined $port or ($port eq "")) {
         print "Warning: Parse problem (no port)!\n" if
($DEBUG);
    }
    if (defined $junk and ($junk ne "")) {
         print "Warning: Parse problem (junk:$junk)!\n" if
($DEBUG);
    }
    if ($src eq "0.0.0.0/0") {
        $src="anywhere";
    } 
    if ($dest eq "0.0.0.0/0") {
        $dest="anywhere";
    }
    if ( ($dest eq "anywhere") and ($src eq "anywhere") ) {
	#not more than a hack currently...
	$src = " $ifname";
	$dir = "dev";
    }
    if ($DEBUG > 4) {
         print "  Parser: $pkts Pkts $bytestr Bytes,
Target=$target " 
                 . "P:$prot ($opt,$tosa,$tosx) dev:$ifname,
"
                  . "mark/outs.:$mark/$outsize $src<-->$dest
:
$port\n";
    }
     return ($pkts, $bytestr, $dir, $prot, $src, $dest,
$port);
}
    
sub read_in($%)
{
    my ($program);
	my $traffic = shift;
    
    if ( -x "/sbin/ipchains" ) {
        #CHAINS mode
	if ($TEST ne "yes") {
	        $program = "/sbin/ipchains -nvL account";
	} else {
        	$program = "cat out2";
	}
        $mode = "c";
        print "Chains-Mode.\n" if ($DEBUG>2);
    } elsif ( -x "/sbin/ipfwadm" ) {
        #IPFW mode
        $program = "/sbin/ipfwadm -A -l";
        $mode = "f";
        print "IPFW-Mode.\n" if ($DEBUG>2);
    } else {
        die "No firewall program found!\n";
    }
    
	open(IPFW, "$program|") #output kommt von
        or die ("Error fork/execute '$program' [$!]\n");

	my ($line);
	my @entry;
    #damit $entry[4] lesbarer wird zu $entry[$$dir]
     #  eigentlich sollte $dir reichen, weil eh nicht
konstant
     #  richtig wдre wohl "*dir = \1" oder so, hab's
vergessen
    #  aber so geht's auch :)
     #engl: to make it more readble: $entry[4] now we can
write
    #  as $entry[$$dir] (entry of direction). 
     #  This should be $dir, but we have a ref to $dir -->
$$dir.
    #  to make $$dir const, it should be initialized
    #  with *dir = \1 or so, this is real perl magic :)
	my ($pkts, $bytestr, $dir, $prot, $src, $dest, $port) = 
           (\0,    \1,       \2,   \3,    \4,   \5,    \6);
     print "pkts|bytes|dir|prot|src|dest|port\n" if
($DEBUG>2);
	while($line = <IPFW>) {
        print "\n  Raw: $line\n" if ($DEBUG>4);
        if ($mode eq "f") {
            @entry = parse_ipfw($line);
        } elsif ($mode eq "c") {
            @entry = parse_chains($line);
        } else {
            die "Invalid mode $mode (internal error)\n";
        }
         next unless defined ($entry[0]); #weiter, bis was
definiert
		print join("|", @entry), "\n" if ($DEBUG>2);
        
        #erweiterbar: hier wird nur src bzw. dest anywhere 
         #  ausgewertet, diese Blцcke kцnnten wiederholt
werden mit
        #  z.B. dest mailrelay.domain.TLD oder sowas...
         #currently only src and dest "anywhere" get
evaluated.
         #  you could extend this script here to evaluate
more
         #  complex rules, i.e. from host _and_ per device
or
        #  whatever you desire.
		if ( ($entry[$$dir] eq "i/o") &&
		     ($entry[$$prot] eq "all") &&
		     ($entry[$$src] eq "anywhere") &&
		     ($entry[$$port] eq "n/a" )) {
			#outgoing:
			my $bytes = $entry[$$bytestr]; 
			if ($bytes =~ s/K//) {
				$bytes *= 2**10;
			}
			if ($bytes =~ s/M//) {
				$bytes *= 2**20;
			}
			print "IN  Bytes to add: ", $bytes, "\n" if ($DEBUG>3);
			$traffic->{$entry[$$dest]}->{"in"} += $bytes;
            #next; 
            #weiter im Output (jede Zeile nur ein Eintrag)
            #engl. go on in output, only one entry per line
		}
		if ( ($entry[$$dir] eq "i/o") &&
		     ($entry[$$prot] eq "all") &&
		     ($entry[$$dest] eq "anywhere") &&
		     ($entry[$$port] eq "n/a" )) {
			#outgoing:
			my $bytes = $entry[$$bytestr]; 
			if ($bytes =~ s/K//) {
				$bytes *= 2**10;
			}
			if ($bytes =~ s/M//) {
				$bytes *= 2**20;
			}
			print "OUT Bytes to add: ", $bytes, "\n" if ($DEBUG>3);
			$traffic->{$entry[$$src]}->{"out"} += $bytes;
            #next; 
		}
		if ( ($entry[$$dir] eq "dev") &&
		     ($entry[$$prot] eq "all") &&
		     ($entry[$$dest] eq "anywhere") &&
		     ($entry[$$port] eq "n/a" )) {
			#Device
			my $bytes = $entry[$$bytestr]; 
			if ($bytes =~ s/K//) {
				$bytes *= 2**10;
			}
			if ($bytes =~ s/M//) {
				$bytes *= 2**20;
			}
			print "DEV Bytes to add: ", $bytes, "\n" if ($DEBUG>3);
			$traffic->{$entry[$$src]}->{"dev"} += $bytes;
            #next; 
		}
         #wenn kein next in den if's, dann kann man auch
mehrfach
        #  zдhlen. MuЯ man aber nicht :)
        #engl: if not next in if's, then the traffic may be
        #  counted multiple times depending on the rules.
        #  This is what most people would expect :)
	}
	#return $traffic; 
    #brauch nicht, weil ja referenz, und die ist konstant.
     #engl: not neccesary, since we got a reference passed
:)
}

sub reset_acc()
{
    if ($mode eq "f") {
    	if ( system("/sbin/ipfwadm","-A", "-z") ) {
	    	die "Error executing ipfwadm reset! $?\n";
    	}
    } elsif ($mode eq "c") {
    	if ( system("/sbin/ipchains","-Z") ) {
	    	die "Error executing ipchains reset! $?\n";
    	}
    } else {
        die "No firewall program found!\n";
    }
}


sub load($%)
{

    #handles new tab separated format and old format
    if ( ! -e $sum_file ) {
         print "Waring: $sum_file does not exists!\n" if
($DEBUG>1);
        return;
    }
    #sumfile-->hash_ref
	my ($host, $entry, $line) = ("","",0);
	my $traffic = shift;
	open(ACC, "$sum_file")
          or die ("Error opening accountings file
'$sum_file'
[$!]\n");
	while ($entry = <ACC>) {
		$line++;
		print $entry, "\n" if ($DEBUG>2);
		chomp $entry;
		my ($host,$direction,$bytes,$rest);
 		if ($entry !~ /\t/) { #kein Tab drin, muЯ altes Format
sein
			($host,$direction,$bytes,$rest) 
				= split(/ \| /,$entry);
			print "  Line converted to new format\n" if ($DEBUG);
		} else { #neues Format (Tab sep.)
			($host,$direction,$bytes,$rest) 
				= split(/\t/,$entry);
		}
 		print "$host | $direction | $bytes ($rest)\n" if
($DEBUG>2);
		$traffic->{$host}->{$direction} = $bytes;
		if (($bytes eq "") || ($rest ne "")) {
			print "Warning!! Struc-error $sum_file line $line!\n";
			die "EXITING.\n";
		}
	}
	close (ACC);
}

sub save($%)
{
    #hash_ref-->sumfile
	my $host;
	my $traffic = shift;
	open(ACC, ">$sum_file") 
		or die "cannot open $sum_file for writing: $! \n";
	while ($host = each(%$traffic)) {
		my $direction;
		my $traffic_host = $traffic->{$host};
		while ($direction = each(%$traffic_host)) { 
			my $entry=join("\t",$host, $direction, 
				$traffic_host->{$direction});
			print ACC $entry , "\n";
		}
	}
	close (ACC);
	chmod 0600, $sum_file; 
	chown 0,0, $sum_file;
}

sub calc_part_costs($)
{
	#Kunden
	my $fee  = 120;   #DM/gig
	my $bytes = shift;
	my $Gbytes = $bytes / 2**30;
	my $cost = $Gbytes * $fee;
	my $cost_str = sprintf("%.2f DM", $cost);
      #der Ausdruck formatiert "123456789 KB" -->
"123.456.789
KB"
	while ( $cost_str =~ s/(\d+)(\d{3})(.| |$)/$1.$2$3/ ) {}
	return ($cost_str);
}

sub calc_total_costs($)
{
	#echt
	#my $free = 2**30; #first gig free
	my $free = 0; #first gig free
	my $fee  = 120;   #DM/gig

	my $bytes = shift;
	if (($bytes -= $free)<0) {
		return "0 DM"; 
	}
	my $Gbytes = $bytes / 2**30;
	my $Gbytes_i = int($Gbytes);
	if ($Gbytes_i != $Gbytes) {
		$Gbytes_i++;
	}
	my $cost = $Gbytes_i * $fee;
	my $cost_str = sprintf("%.2f DM", $cost);
	while ( $cost_str =~ s/(\d+)(\d{3})(.| |$)/$1.$2$3/ ) {}
	return ($cost_str);
}
	
	
	
	

sub print_val($)
{
	my $byte_str = shift;
	my $bytes    = $byte_str;
    #PB: Petabyte --> 2**50
	if ($byte_str>=(2**40)) {
        #Terabyte, wer weiЯ, vielleicht kommts mal :)
		$byte_str /= 2**40;
		$byte_str = sprintf("%9.4f TB", $byte_str);
	} elsif ($byte_str>=(2**30)) {
		#max 1 tera 
		$byte_str /= 2**30;
		$byte_str = sprintf("%9.4f GB", $byte_str);
	} elsif ($byte_str>=(2**20)) {
		#max 1 giga
		$byte_str /= 2**20;
		$byte_str = sprintf("%9.4f MB", $byte_str);
	} elsif ($byte_str>=(2**10)) {
		#max 1 mega
		$byte_str /= 2**10;
		$byte_str = sprintf("%9.4f KB", $byte_str);
	} else {
		#max 1 kilo
		$byte_str = sprintf("%9d ", $byte_str);
	}	
	while ( $bytes =~ s/(\d+)(\d{3})(.|$)/$1.$2/ ) {}
	printf("%20s == %-13s", $bytes, $byte_str);
}

sub print_val_new($)
{
	my $byte_str = shift;
	my $bytes    = $byte_str;
    #PB: Petabyte --> 2**50
	if ($byte_str>=(10*2**40)) {
        #Terabyte, wer weiЯ, vielleicht kommts mal :)
		$byte_str /= 2**40;
		$byte_str = sprintf("%9.2f TB", $byte_str);
	} elsif ($byte_str>=(10*2**30)) {
		#max 10 tera 
		$byte_str /= 2**30;
		$byte_str = sprintf("   %9.2f GB", $byte_str);
	} elsif ($byte_str>=(10*2**20)) {
		#max 10 giga
		$byte_str /= 2**20;
		$byte_str = sprintf("      %9.2f MB", $byte_str);
	} else {
		$byte_str /= 2**10;
		$byte_str = sprintf("         %9.2f KB", $byte_str);
	}	
	while ( $bytes =~ s/(\d+)(\d{3})(.|$)/$1.$2/ ) {}
	printf("%-26s", $byte_str);
}

sub print_dir($)
{
	my $direction = shift;
	printf("     %-6s", $direction);
	if ($direction eq "in") {
		printf(" <--- ");
	} elsif ($direction eq "out") {
		printf(" ---> ");
	} elsif ($direction eq "dev") {
		printf(" <--> ");
	} else {
		printf(" ?--? "); #gibts erstmal nicht, kommt vielleicht
        #noch fьr andere Ziele...
	}
}

sub print_traffic($%)
{
	print "\n", ("-" x 30), "[ Hosts ]", ("-" x 30), "\n\n";
	my $traffic = shift;
	my ($host) = ("");
	my $total = {};

    sub by_traffic()
    {
        my ($traf_a,$traf_b)  = (0,0);
        #print keys %{$traffic->{$b}};
        
        #jedes device gewinnt gegen jeden host
        #engl: devices have higher sort priority than hosts
		if (defined($traffic->{$a}->{'dev'}) and 
           !defined($traffic->{$b}->{'dev'})) {
            return -1;
        }
        
        #jeder host verliert gegen jedes device
        #engl: hosts have lower sort priority than devices
		if (defined($traffic->{$b}->{'dev'}) and 
           !defined($traffic->{$a}->{'dev'})) {
            return 1;
        }

         #devices oder hosts untereinander nach traffic
sortieren
        #engl. devices and hosts are sorted by traffic
        foreach my $direction (keys %{$traffic->{$a}}) { 
            $traf_a += $traffic->{$a}->{$direction};
        }
        foreach my $direction (keys %{$traffic->{$b}}) { 
            $traf_b += $traffic->{$b}->{$direction};
        }
        return $traf_b <=> $traf_a;
    }

	foreach $host (sort by_traffic (keys %$traffic)) {
		if (!defined($traffic->{$host}->{'dev'})) {
            if ($host_names eq "yes") {
    			printf("Host %s [%s]:\n", $host,
                gethostbyaddr(inet_aton($host), AF_INET));
            } else {
    			printf("Host %s:\n", $host);
            }
		} else {
            if ($english) {
			    printf("Device %s:\n", $host);
            } else {
			    printf("Gerдt  %s:\n", $host);
            }
		}
		my $direction;
		my $traffic_host = $traffic->{$host};
		foreach $direction (sort (keys %$traffic_host)) { 
			print_dir($direction);
			my $bytes = $traffic_host->{$direction};
			$total->{$direction} += $bytes;
			if ($print_mode eq "c") {
			    print_val($bytes);  #classic
			} else {
			    print_val_new($bytes); #differs a little
			}
			printf("%15s\n", calc_part_costs($bytes));
		}
		#print "\n";
	}
	#
	# SUMME (sumarized data)
	#
    if ($english) {
    	print "\n", ("-" x 31), "[ SUM ]", ("-" x 31), "\n\n";
    } else {
     	print "\n", ("-" x 30), "[ SUMME ]", ("-" x 30),
"\n\n";
    }
	my ($direction, $all) = ("", 0);
	foreach $direction (sort(keys %$total)) {
		print_dir($direction);
		my $bytes = $total->{$direction};
		if ($print_mode eq "c") {
		    print_val($bytes);  #classic
		} else {
		    print_val_new($bytes); #differs a little
		}
		printf("%15s\n", calc_part_costs($bytes));
		$all += $bytes;
	}
    if ($english) {
	    print " *** SUM    <--> "; #engl: "sumarzied"
    } else {
	    print "  Gesammt   <--> "; #engl: "sumarzied"
    }
	if ($print_mode eq "c") {
	    print_val($all);  #classic
	} else {
	    print_val_new($all); #differs a little
	}
	printf("%15s\n", calc_total_costs($all));
    if ($english) {
  	    print "\n", ("-" x 24), "[ Expensive Devices ]", ("-"
x
24), "\n\n";
    } else {
  	    print "\n", ("-" x 23), "[ Kostende Interfaces ]",
("-"
x 23), "\n\n";
    }
	foreach my $PAY_DEV (sort(@PAY_DEVS)) {
		my $traffic_host = $traffic->{"$PAY_DEV"};
		my $bytes=0;
		foreach $direction (sort(keys %$traffic_host)) { 
			$bytes += $traffic_host->{$direction};
		}
	    printf("     %-6s <--> ", $PAY_DEV);
		if ($print_mode eq "c") {
		    print_val($bytes);  #classic
		} else {
		    print_val_new($bytes); #differs a little
		}
		printf("%15s\n", calc_total_costs($bytes));
	}
	print "\n";	
}			

sub get_switches
{
  foreach (@ARGV)
  {
    if (/^-(D+)$/) {
        $DEBUG += length ($1) 
    }
    if (/^-q$/) {
	    $quite = "true";
    }
  }
}#end sub get_schwitches

################
#
#     MAIN
#
################################

my @stage;

if ($english) {
      $stage[1] = "# Stage 1:  Load stored values from
disk\n"
;
     $stage[2] = "# Stage 2:  Analyzing data got from
firewall\n";
    $stage[3] = "# Stage 3:  Storeing the values\n";
     $stage[4] = "# Stage 4:  Reseting firewall traffic
counters\n";
     $stage[5] = "# Stage 5:  Output of the calculated
values\n";
} else {
    $stage[1] = "# Stufe 1:  Laden bisheriger Werte\n" ;
     $stage[2] = "# Stufe 2:  Analysieren der
Firewalldaten\n";
    $stage[3] = "# Stufe 3:  Speichern der Werte\n";
     $stage[4] = "# Stufe 4:  Ruecksetzen der
Firewallzaehler\n";
     $stage[5] = "# Stufe 5:  Ausgabe der berechten
Werte\n";
}

get_switches;
print ("Debug-Level: ",$DEBUG, "\n") if ($DEBUG);

my $traffic = {};
 print '  Account logger for Steffen\'s firewall $Revision:
1.24 $',"\n" unless $quite;

#in english: Stage 1: Load saved values
print $stage[1] unless $quite;
load($traffic);

#in english: Stage 2: analyzing the firewall data
print $stage[2] unless $quite;
read_in($traffic);

#in english: Stage 3: Storeing the values
print $stage[3] unless $quite;
save($traffic) unless $DEBUG;

#in english: Stage 4: Reset of firewall counters
print $stage[4] unless $quite;
reset_acc() unless $DEBUG;

#in english: Stage 5: Output of calculated values
print $stage[5] unless $quite;
#exit if $quite; # besser?!
print_traffic($traffic) unless $quite;
print "\n" unless $quite;





<< rndc.conf - problem (1 ) | 4-то cd na mandrake (3 ) >>

 
© 2011-... Асоциация "Линукс за българи"
© 2007-2010 Линукс за българи ЕООД
© 1999-2006 Slavej Karadjov
Ако искате да препечатате или цитирате информация от този сайт прочетете първо това
Външния вид е направен от MOMCHE
Code Version: 1.0.8 H (Revision: 23-09-2011)
 
Изпълнението отне: 0 wallclock secs ( 0.06 usr + 0.01 sys = 0.07 CPU)