#!/usr/bin/perl -w # $Id: ipfwplot,v 1.3 2003/04/30 07:16:45 candy Exp $ use strict; use POSIX; use Time::Local; use Getopt::Std; use Pg; # ports/database/p5-Pg my $out_type = 0; # 0=counter, 1=add, 2=percent; my $g_title = "top %d scans"; my $g_format_x = "%m/%d"; sub comp { $a <=> $b; }; sub nz($;$) { return defined($_[0]) ? $_[0] : (defined($_[1]) ? $_[1] : ""); } sub autoflush($$) { my($so, $flag) = @_; select((select($so), $| = $flag)[0]); } sub parse_scans($) { my($lbuf) = @_; my $i; my %dp; my @v = split(/ +/, $lbuf); for ($i = 0; $i <= $#v; $i += 2) { my $k = $v[$i]; my $vv = $v[$i + 1]; $dp{$k} = $vv; } return %dp; } # sub read_all($$) { my($date, $dp) = @_; my($lbuf, $i); $i = 0; while ($lbuf = <>) { chomp($lbuf); $lbuf =~ /^([^ ]+)/; my $dt = $1; $date->[$i] = $dt; if ($lbuf =~ /^[^ ]+ +(.+)/) { my $scans = $1; $dp->[$i] = {parse_scans($scans)}; } $i++; } } sub all_dport($) { my($dp) = @_; my($i, $k); my %alldp; for ($i = 0; $i <= $#$dp; $i++) { foreach $k (keys %{$dp->[$i]}) { $alldp{$k} = 1; } } return (sort comp keys %alldp); } sub max_dport($$) { my($dp, $n) = @_; my($i, $k, $j); $i = $#$dp; my %v2k; my @dport; foreach $k (keys %{$dp->[$i]}) { my $v = $dp->[$i]{$k}; if (defined($v2k{$v})) { $v2k{$v} = $v2k{$v} . " " . $k; } else { $v2k{$v} = $k; } } my @val = (sort {$b <=> $a} values %{$dp->[$i]}); for ($j = 0; $j <= $#val; $j++) { if ($v2k{$val[$j]} =~ " ") { $v2k{$val[$j]} =~ s/([^ ]*) //; $k = $1; } else { $k = $v2k{$val[$j]}; } $dport[$j] = $k; } splice(@dport, $n); return @dport; } sub print_table($$$$) { my($fd, $date, $dp, $dport) = @_; my($i, $j, $k); for ($i = 0; $i <= $#$date; $i++) { my $sum = 0; printf($fd "%s", $date->[$i]); for ($j = 0; $j <= $#$dport; $j++) { my $x = nz($dp->[$i]{$dport->[$j]}, 0); $sum += $x; if ($out_type == 0) { printf($fd " %d", $x); } elsif ($out_type == 1) { printf($fd " %d", $sum); } } if ($out_type == 2) { my $sum2 = 0; for ($j = 0; $j <= $#$dport; $j++) { my $x = nz($dp->[$i]{$dport->[$j]}, 0); $sum2 += $x; printf($fd " %d", $sum2 * 100 / $sum); } } printf($fd "\n"); } } sub print_data($$$) { my($date, $dp, $dport) = @_; my($i, $j, $k); printf("#port"); for ($j = 0; $j <= $#$dport; $j++) { printf(" %d", $dport->[$j]); } printf("\n"); print_table(\*STDOUT, $date, $dp, $dport) } sub plot_data($$$) { my($date, $dp, $dport) = @_; my $name = "tmp-d.$$"; my $gname = "tmp-p.$$"; if (open(F, ">$name")) { print_table(\*F, $date, $dp, $dport); close(F); if (open(F, ">$gname")) { print(F << "__END__"); set terminal png color set grid set timefmt "%Y-%m-%d-%H:%M:%S" set xdata time set format x "$g_format_x" set title "$g_title" set data style lines __END__ my $j; for ($j = 0; $j <= $#$dport; $j++) { printf(F "%s ", ($j == 0) ? "plot \"$name\"" : ",\"\""); printf(F "u 1:%d t \"port %s\"\\\n", $j + 2, $dport->[$j]); } close(F); system("gnuplot $gname"); } else { printf(STDERR "%s: %s\n", $name, $!); } } else { printf(STDERR "%s: %s\n", $name, $!); } remove($gname); remove($name); } sub nain($$$) { my($top_n, $npoints, $opt_c) = @_; my $lbuf; my $lno = 1; autoflush(\*STDOUT, 1); my @date; my @dp; my @alldp; read_all(\@date, \@dp); if ($npoints < $#date + 1) { @date = splice(@date, -$npoints); @dp = splice(@dp, -$npoints); } if ($top_n == 0) { @alldp = all_dport(\@dp); } else { @alldp = max_dport(\@dp, $top_n); } if ($opt_c) { print_data(\@date, \@dp, \@alldp); } else { plot_data(\@date, \@dp, \@alldp); } return 0; } my $usage = "usage: %s [-c][-n npoints][-t top_n][-x fmt_x] ipfwcount_output\n" ; use vars qw($opt_c); use vars qw($opt_n); use vars qw($opt_t); use vars qw($opt_o); use vars qw($opt_x); use vars qw($opt_V); sub main() { my($ex); $ex = 1; my $top_n = 7; my $npoints = 36; getopts('cn:t:o:x:V'); if (defined($opt_V)) { printf(STDERR $usage, $0); } else { defined($opt_n) && ($npoints = $opt_n); defined($opt_t) && ($top_n = $opt_t); defined($opt_x) && ($g_format_x = $opt_x); if (nz($opt_o) eq "0" || nz($opt_o) eq "1" || nz($opt_o) eq "2") { $out_type = $opt_o + 0; } $g_title = sprintf($g_title, $top_n); nain($top_n, $npoints, nz($opt_c, 0)); $ex = 0; } return $ex; } exit main();