- add capability of separating TX and RX in graph (in addition to "total traffic" graph)

- add -S flag to specify source IP address
- improve graph look
This commit is contained in:
farrokhi 2014-07-24 17:40:03 +04:30
parent d3a678af10
commit ced02e2365

View File

@ -3,99 +3,186 @@
use strict; use strict;
use warnings; use warnings;
use Net::Pcap; use Net::Pcap;
use NetPacket::IP;
use Getopt::Std; use Getopt::Std;
my $pktcount=0; my $duplex = 0;
my $curtime=0; my $src_addr = "";
my $reftime=0; my $pktcount = 0;
my $endtime=0; my $curtime = 0;
my $timelen=0; my $reftime = 0;
my $endtime = 0;
my $timelen = 0;
my $hoffset = -1;
my @pps=(); my @pps_src = ();
my @bps=(); my @pps_dst = ();
my @bps_src = ();
my @bps_dst = ();
sub process_pkt sub process_pkt
{ {
my($user_data, $hdr, $pkt) = @_; my($user_data, $hdr, $pkt) = @_;
my $unpacket = unpack('H*', substr($pkt, 0,1));
if (($hoffset == 32) && ($unpacket == 88)) {
$hoffset = 34; # Add 2 bytes to the header is it is an IEEE 802.11 QOS frame
}
my $paquete = substr($pkt, $hoffset); # Hack to parse not only Ethernet but also IEEE 802.11 frames
my $ip_obj = NetPacket::IP->decode( $paquete );
$reftime = $hdr->{tv_sec} if ($reftime == 0); $reftime = $hdr->{tv_sec} if ($reftime == 0);
$endtime = $hdr->{tv_sec}; $endtime = $hdr->{tv_sec};
$curtime = sprintf("%d\n", $hdr->{tv_sec} - $reftime); $curtime = sprintf("%d\n", $hdr->{tv_sec} - $reftime);
$pktcount++; $pktcount++;
my $arrsize=@pps; my $arrsize=@pps_src;
if ($arrsize < $curtime) { # grow array if necessary if ($arrsize < $curtime) { # grow array if necessary
for (my $i = $arrsize; $i <= $curtime; $i++) { for (my $i = $arrsize; $i <= $curtime; $i++) {
$pps[$i]=0; $pps_src[$i] = 0;
$bps[$i]=0; $pps_dst[$i] = 0;
$bps_src[$i] = 0;
$bps_dst[$i] = 0;
} }
} }
$pps[$curtime]++;
$bps[$curtime]+=($hdr->{len} * 8); if ($duplex) # We need separate TX/RX lines in graph
{
if ( $src_addr eq $ip_obj->{src_ip} ) # TX flow
{
$pps_src[$curtime]++;
$bps_src[$curtime]+=($hdr->{len} * 8);
}
elsif ( $src_addr eq $ip_obj->{dest_ip} ) # RX flow
{
$pps_dst[$curtime]++;
$bps_dst[$curtime]+=($hdr->{len} * 8);
}
else
{
$pps_src[$curtime]+=0;
$pps_dst[$curtime]+=0;
$bps_src[$curtime]+=0;
$bps_dst[$curtime]+=0;
}
}
else # We need one line in graph for TX+RX combined
{
$pps_src[$curtime]++;
$bps_src[$curtime]+=($hdr->{len} * 8);
}
} }
sub help { sub help {
print "pcaputil [-h] -f pcapfile [-e filter expression] [-p] [-b]\n"; print "pcaputil -f pcapfile [-e filter expression] [-S src_ip] [-pbh]\n";
print "\n"; print "\n";
print "\t-h\t\thelp\n"; print "\t-h\t\thelp\n";
print "\t-f pcapfile\tinput file name (required)\n"; print "\t-f pcapfile\tinput file name (required)\n";
print "\t-e expression\tfilter expression (tcpdump compatible)\n"; print "\t-e expression\tfilter expression (tcpdump compatible)\n";
print "\t-b\t\tgenerate bps graph\n"; print "\t-b\t\tgenerate bps graph\n";
print "\t-p\t\tgenerate pps graph\n"; print "\t-p\t\tgenerate pps graph\n";
print "\t-S src_ip\tseparate TX/RX flow graph based on source address\n";
print "\n"; print "\n";
exit(); exit();
} }
sub dump_data { sub dump_data_single {
my @data=@_; my $data = shift;
open(my $fh, ">", "temp.data"); open(my $fh, ">", "temp.data");
for (my $i = 0; $i <= $timelen; $i++) { for (my $i = 0; $i <= $timelen; $i++) {
print $fh "$i $data[$i]\n"; print $fh "$i @$data[$i]\n";
} }
close($fh); close($fh);
} }
sub dump_data_double {
# received two arrays by reference
my $tx = shift;
my $rx = shift;
my $crx = 0;
my $ctx = 0;
open(my $fh, ">", "temp.data");
for (my $i = 0; $i <= $timelen; $i++) {
$ctx = 0;
$crx = 0;
$ctx = @$tx[$i] if (defined @$tx[$i]);
$crx = @$rx[$i] if (defined @$rx[$i]);
print $fh "$i $ctx $crx\n";
}
close($fh);
}
sub create_graph { sub create_graph {
my ($dataset)=@_; my ($dataset) = @_;
my $ylabel=""; my $ylabel = "";
my $filename=""; my $filename = "";
my $linecolor=""; my $lddinecolor = "";
my $plotline = "";
my $title = "";
if ($dataset eq 'pps') if ($dataset eq 'pps')
{ {
$ylabel="Packets"; $ylabel = "Packets";
$filename="pps"; $filename = "pps";
$linecolor="#4d0000"; $title = "Packet Traffic Volume";
if ($duplex) # full duplex graph
{
$plotline="plot 'temp.data' using 1:2 title 'RX Packets/s' with lines ls 1, 'temp.data' using 1:3 title 'TX Packets/s' with lines ls 2";
}
else
{
$plotline="plot 'temp.data' using 1:2 title 'TX+RX Packets/s' with lines ls 1";
}
} }
if ($dataset eq 'bps') if ($dataset eq 'bps')
{ {
$ylabel="Bits"; $ylabel = "Bits";
$filename="bps"; $filename = "bps";
$linecolor="#00004d"; $title = "Traffic Volume";
if ($duplex) # full duplex graph
{
$plotline="plot 'temp.data' using 1:2 title 'RX bits/s' with lines ls 1, 'temp.data' using 1:3 title 'TX bits/s' with lines ls 2";
}
else
{
$plotline="plot 'temp.data' using 1:2 title 'TX+RX bits/s' with lines ls 1";
}
} }
my $gpi = <<"END_MESSAGE"; my $gpi = <<"END_MESSAGE";
set terminal postscript eps enhanced color "Helvetica" 30 set terminal postscript eps enhanced color "Helvetica" 30
set title "Throughput Graph" set title "$title"
set style line 99 linetype 1 linecolor rgb "#999999" lw 2 set style line 99 linetype 1 linecolor rgb "#999999" lw 2
set key right bottom set key outside right bottom horizontal Right noreverse enhanced autotitles box linetype -1 linewidth 2.000
set key box linestyle 99 set key box linestyle 99
set key spacing 1.2 set key spacing 1.2
set nokey
set grid xtics ytics mytics set grid xtics ytics mytics
set decimal locale "en_US.UTF-8" set decimal locale "en_US.UTF-8"
set format y "%'.0f" set format y "%'.0f"
set size 2 set size 2,1.6
set size ratio 0.4 set size ratio 0.4
set ylabel "$ylabel" set ylabel "$ylabel"
set xlabel "Time (Seconds)" set xlabel "Time (Seconds)"
set style line 1 lc rgb '$linecolor' lt 1 lw 3 set style line 1 lc rgb '#4d0000' lt 1 lw 3
plot "temp.data" using 1:2 notitle with lines ls 1 set style line 2 lc rgb '#00004d' lt 1 lw 3
$plotline
END_MESSAGE END_MESSAGE
open(GNUPLOT, "| gnuplot | epstopdf -f | convert -density 300 - $filename.png"); open(GNUPLOT, "| gnuplot | epstopdf -f | convert -density 300 - $filename.png");
@ -108,16 +195,43 @@ END_MESSAGE
my $err =''; my $err ='';
my %opts=(); my %opts=();
getopts('hbpe:f:', \%opts); getopts('hbpe:f:S:', \%opts);
if (defined $opts{h}) { help(); } help() if (defined $opts{h});
if (not defined $opts{f}) { help(); } help() if (not defined $opts{f});
my $inputfile=$opts{f}; my $inputfile = $opts{f};
if (defined $opts{S})
{
$src_addr = $opts{S};
$duplex = 1;
}
# process the pcap again, now do the bps and pps calculation # process the pcap again, now do the bps and pps calculation
my $pcap = Net::Pcap::open_offline($inputfile,\$err) or die "Can't open file...$err\n"; my $pcap = Net::Pcap::open_offline($inputfile,\$err) or die "Can't open file...$err\n";
my $datalink;
$datalink = Net::Pcap::datalink($pcap);
CASE: {
# EN10MB capture files
($datalink == 1) && do {
$hoffset = 14;
last CASE;
};
# Linux cooked socket capture files
($datalink == 113) && do {
$hoffset = 16;
last CASE;
};
# DLT_IEEE802_11 capture files
($datalink == 105) && do {
$hoffset = 32;
last CASE;
}
}
if (defined $opts{e}) { if (defined $opts{e}) {
my $filter = $opts{e}; my $filter = $opts{e};
my $filter_t; my $filter_t;
@ -143,7 +257,14 @@ if ($pktcount < 2) {
if (defined $opts{p}) if (defined $opts{p})
{ {
print("Creating PPS graph..."); print("Creating PPS graph...");
dump_data(@pps); if ($duplex)
{
dump_data_double(\@pps_src,\@pps_dst);
}
else
{
dump_data_single(\@pps_src);
}
create_graph('pps'); create_graph('pps');
print("Done.\n"); print("Done.\n");
} }
@ -151,7 +272,14 @@ if (defined $opts{p})
if (defined $opts{b}) if (defined $opts{b})
{ {
print("Creating BPS graph..."); print("Creating BPS graph...");
dump_data(@bps); if ($duplex)
{
dump_data_double(\@bps_src,\@bps_dst);
}
else
{
dump_data_single(\@bps_src);
}
create_graph('bps'); create_graph('bps');
print("Done.\n"); print("Done.\n");
} }