Created
April 29, 2015 19:16
-
-
Save agramajo/216ac69d507428b6d13d to your computer and use it in GitHub Desktop.
display stats by ip accounting with iptables
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/perl | |
use strict; | |
# Quick display stats by ip accounting with iptables chains | |
# Only for linux kernel and netfilter | |
# | |
# CONFIG | |
# Read the source! | |
# | |
# SUMMARY | |
# - Parse the output of arp command, so harvest ip addresses | |
# - Create chains for accounting (in main forward chain) | |
# - Run iptables -L and parse this (twice): | |
# | |
# Chain stats (1 references) | |
# num pkts bytes target prot opt in out source destination | |
# 1 501 43099 RETURN all -- * * 10.0.0.10 0.0.0.0/0 | |
# 2 0 0 RETURN all -- * * 0.0.0.0/0 10.0.0.10 | |
# 3 2 1524 RETURN all -- * * 0.0.0.0/0 10.0.0.10 | |
# 4 101 82146 RETURN all -- * * 10.0.0.109 0.0.0.0/0 | |
# 5 2 1540 RETURN all -- * * 0.0.0.0/0 10.0.0.109 | |
# 6 239 110995 RETURN all -- * * 10.0.0.108 0.0.0.0/0 | |
# 7 28786 5831340 RETURN all -- * * 10.0.0.110 0.0.0.0/0 | |
# 8 1596 97792 RETURN all -- * * 0.0.0.0/0 10.0.0.110 | |
# | |
# - Calculate rate transfer of each ip address | |
# - Generate output sorted by download rate (ip, rate down, rate up): | |
# | |
# HOST DOWNLOAD UPLOAD | |
# 172.21.0.56 22.55K ( 180.44K) 13.58K ( 108.67K) | |
# 10.0.0.105 9.77K ( 78.12K) 9.80K ( 78.38K) | |
# 10.0.0.128 5.88K ( 47.07K) 112.6 ( 900.8) | |
# 10.0.0.109 76.9 ( 615.2) 81.4 ( 651.2) | |
# 10.0.0.110 76.8 ( 614.4) 81.3 ( 650.4) | |
# 10.0.0.130 89.3 ( 714.4) 50.7 ( 405.6) | |
# 10.0.0.10 6 ( 48) 6 ( 48) | |
# TOTAL 31.16K ( 249.30K) 22.56K ( 180.44K) | |
# | |
# - Flush and clean on exit (ctrl-c to break) | |
# | |
# DISCLAIMER | |
# Use at your own risk! | |
# | |
# AUTHOR | |
# Alejandro Gramajo ( agramajo at gmail dot com ) | |
# 20060504 | |
# | |
# config | |
# | |
my $ipt = "/sbin/iptables"; | |
my $arp = "/usr/sbin/arp"; | |
my $chain = "stats" . $$; | |
my $main_chain = "FORWARD"; | |
my $sleep_time = 5; # in seconds | |
my $ipt_list = "$ipt -L $chain -n -v -x --line-numbers"; | |
my $arp_list = "$arp -n"; | |
my %data1; | |
my %data2; | |
my $cont = 1; | |
check(); | |
# | |
# capture signals for ending, clean all rules | |
# | |
$SIG{'INT'} = \&end; | |
$SIG{'TERM'} = \&end; | |
# | |
# capture arp output, build rules | |
# | |
start(); | |
print "Waiting for $sleep_time seconds...\n\n"; | |
# | |
# main loop | |
# | |
while ($cont) { | |
my @data = `$ipt_list 2>&1`; | |
foreach (@data) { | |
next unless /^\d+/; # skip not numbers | |
# bytes == pos 2 | |
# ip source == pos 8 | |
# ip destination == pos 9 | |
my ($bytes, $ip_src, $ip_dst) = (split /\s+/)[2,8,9]; | |
if ($ip_dst =~ /0\.0\.0\.0/) { $data1{ $ip_src } = $bytes } | |
elsif ($ip_src =~ /0\.0\.0\.0/) { $data2{ $ip_dst } = $bytes } | |
} | |
sleep $sleep_time; | |
my @data = `$ipt_list 2>&1`; | |
foreach (@data) { | |
next unless /^\d+/; # skip not numbers | |
# bytes == pos 2 | |
# ip source == pos 8 | |
# ip destination == pos 9 | |
my ($bytes, $ip_src, $ip_dst) = (split /\s+/)[2,8,9]; | |
# | |
# calculate difference in bytes | |
# | |
if ($ip_dst =~ /0\.0\.0\.0/) { | |
$data1{ $ip_src } = $bytes - $data1{ $ip_src }; | |
} | |
elsif ($ip_src =~ /0\.0\.0\.0/) { | |
$data2{ $ip_dst } = $bytes - $data2{ $ip_dst }; | |
} | |
} | |
my $total1 = 0; | |
my $total2 = 0; | |
printf("\t%-16s %19s %19s\n", "HOST", "DOWNLOAD", "UPLOAD"); | |
# sorted by rate of ip destination (download) | |
foreach (sort { $data2{ $b } <=> $data2{ $a } } keys %data1) { | |
# speed = bytes / time | |
my $rate_src = $data1{ $_ } / $sleep_time; | |
my $rate_dst = $data2{ $_ } / $sleep_time; | |
# show only rate > 0 | |
next if ($rate_src == 0 and $rate_dst == 0); | |
$total1 += $rate_src; | |
$total2 += $rate_dst; | |
printf("\t%-16s %8s (%8s) %8s (%8s)\n", $_, | |
size2human($rate_dst), size2human($rate_dst*8), | |
size2human($rate_src), size2human($rate_src*8), | |
); | |
} | |
printf("\t%-16s %8s (%8s) %8s (%8s)\n", "TOTAL", | |
size2human($total2),size2human($total2*8), | |
size2human($total1),size2human($total1*8), | |
); | |
print "-" x 70, "\n"; | |
} | |
# | |
# functions | |
# | |
sub size2human { | |
# XXX max giga (G) | |
my $data = shift; | |
my $tmp; | |
if ($data > 1024**3) { $tmp = sprintf "%0.2fG", $data / 1024**3; } | |
elsif ($data > 1024**2) { $tmp = sprintf "%0.2fM", $data / 1024**2; } | |
elsif ($data > 1024) { $tmp = sprintf "%0.2fK", $data / 1024; } | |
else { $tmp = $data; } | |
return $tmp; | |
} | |
sub start { | |
system("$ipt -N $chain"); | |
system("$ipt -I $main_chain -j $chain"); | |
open ARP, "$arp_list |"; | |
while (<ARP>) { | |
next unless /^\d+/; # skip not numbers | |
my $ip = (split /\s+/)[0]; | |
system("$ipt -A $chain -s $ip -j RETURN"); | |
system("$ipt -A $chain -d $ip -j RETURN"); | |
} | |
close ARP; | |
} | |
sub end { | |
system("$ipt -F $chain"); | |
system("$ipt -D $main_chain -j $chain"); | |
system("$ipt -X $chain"); | |
$cont = 0; | |
} | |
sub check { | |
die "\nOnly run as root\n\n" if ($> != 0); | |
die "\nWhere is $ipt\n\n" unless (-e $ipt); | |
die "\nWhere is $arp\n\n" unless (-e $arp); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment