# HG changeset patch # User Matti Hamalainen # Date 1250207932 -10800 # Node ID fc053b0010270d48721886718a83bb200196019a # Parent d6da1a6567f8520e72f208735c6688389d198338 Improved reporting and documentation. diff -r d6da1a6567f8 -r fc053b001027 README --- a/README Fri Aug 14 01:26:29 2009 +0300 +++ b/README Fri Aug 14 02:58:52 2009 +0300 @@ -67,3 +67,9 @@ settings to enable it, for example in Debian/Ubuntu you can use rcconf(8) or chkconfig(8). +Reports +======= +Automatic report generation can be enabled from configuration. +You can also run "full" report generation via the "-f" option, in this +special mode, no automatic weeding is performed, resulting in +more data being shown. diff -r d6da1a6567f8 -r fc053b001027 maltfilter --- a/maltfilter Fri Aug 14 01:26:29 2009 +0300 +++ b/maltfilter Fri Aug 14 02:58:52 2009 +0300 @@ -54,6 +54,7 @@ ############################################################################# ### Script code ############################################################################# +my $report = 0; my @scanfiles = (); my @noblock_ips = (); my %filehandles = (); @@ -215,6 +216,9 @@ sub weed_entries() { + # Don't weed in report mode. + return if ($report); + foreach my $mip (keys %iplist) { if (defined($iplist{$mip})) { if ($iplist{$mip} >= 0) { @@ -297,6 +301,16 @@ return $_[0] ? "" : ""; } +sub pe($$) +{ + return $_[0] ? "<$_[1]>" : ""; +} + +sub getIP($$) +{ + return $_[0] ? "$_[1]" : $_[1]; +} + sub generate_status($$) { my $filename = shift; @@ -304,7 +318,6 @@ return unless ($filename ne ""); - mlog(-1, "dumping status '$filename'\n"); open(STATUS, ">", $filename) or die("Could not open '".$filename."'!\n"); my $f = \*STATUS; my $mtime = scalar localtime(); @@ -325,10 +338,24 @@ printH($m, $f, 1, "Maltfilter v$progversion status report"); - printP($m, $f, "Generated: ".$mtime."\n"); + my $val = $settings{"WEEDPERIOD"}; + my $period; - printH($m, $f, 2, "Blocked"); + if ($val > 30 * 24) { + $period = sprintf("%1.1f months", $val / (30.0 * 24.0)); + } elsif ($val > 24 * 7) { + $period = sprintf("%1.1f weeks", $val / 24); + } elsif ($val > 24) { + $period = sprintf("%d days", $val / 24); + } else { + $period = sprintf("%d hours", $val); + } + printP($m, $f, + "Generated ".bb($m).$mtime.eb($m).". Data computed from ". + ($report ? "complete logfile scan" : "a period of last $period").".\n"); + + printH($m, $f, 2, $report ? "Detailed report" : "Blocked entries"); printElem($m, $f, "\n". ""."\n"); my $nexcluded = 0; my $ntotal = 0; @@ -337,12 +364,20 @@ printElem($m, $f, " "); printTD($m, $f, sprintf("%-10d", $hitcount{$mip})); - printTD($m, $f, sprintf("%-15s", $mip)); + printTD($m, $f, sprintf("%-15s", getIP($m, $mip))); printElem(!$m, $f, " : "); printTD($m, $f, scalar localtime($iplist{$mip})); my @s = (); foreach my $cond (sort keys %{$reason{$mip}}) { - push(@s, bb($m).$cond.eb($m)." [".$reason_n{$mip}{$cond}." hits] (".$reason{$mip}{$cond}.")"); + my $str; + if ($report) { + my @tmp = reverse(@{$reason{$mip}{$cond}}); + $#tmp = 5 if ($#tmp > 5); + $str = join(" | ", @tmp); + } else { + $str = $reason{$mip}{$cond}; + } + push(@s, bb($m).$cond.eb($m)." [".$reason_n{$mip}{$cond}." hits] (".$str.")"); } printTD($m, $f, join(", ".($m ? "
" : ""), @s)); printElem($m, $f, "\n", "\n"); @@ -354,33 +389,34 @@ " excluded (defined in NOBLOCK_IPS).\n"); - printH($m, $f, 2, "All recorded hits in general"); + printH($m, $f, 2, "Overview of hits in general"); printP($m, $f, "List of 'hits' of suspicious activity noticed by Maltfilter, but not necessarily acted upon.\n"); - printElem($m, $f, "
HitsIP-addressDate of last hitReason(s)
\n". "" x 2 ."\n"); + my $tmp = ""; + printElem($m, $f, "
IP-address# of hits
IP-address# of hitsReasons
\n". $tmp."".$tmp ."\n"); my $hits = 0; - my @keys = sort { cmp_ip_hits($a, $b, $hitcount{$a}, $hitcount{$b}) } keys %hitcount; + my @keys = sort { cmp_ips($a, $b) } keys %hitcount; my $nkeys = scalar @keys; my $printEntry = sub { - printTD($m, $f, sprintf("%-15s", $_[0])); + printTD($m, $f, sprintf("%-15s", getIP($m, $_[0]))); + printElem(!$m, $f, " : "); + printTD($m, $f, sprintf("%-8d ", $hitcount{$_[0]})); printElem(!$m, $f, " : "); - printTD($m, $f, sprintf("%-8d ", $_[1])); + my $tmp = join(", ", sort keys %{$reason{$_[0]}}); + printTD($m, $f, sprintf("%-30s", $tmp)); + $hits += $hitcount{$_[0]}; }; my $kmax = $nkeys / 2; for (my $i = 0; $i <= $kmax; $i++) { printElem($m, $f, " "); if ($i < $kmax) { - my $mip = $keys[$i]; - &$printEntry($mip, $hitcount{$mip}); - $hits += $hitcount{$mip}; + &$printEntry($keys[$i]); } - printElem(!$m, $f, " | "); + printElem($m, $f, "", " || "); if ($i + $kmax + 1 < $nkeys) { - my $mip = $keys[$i + $kmax + 1]; - &$printEntry($mip, $hitcount{$mip}); - $hits += $hitcount{$mip}; + &$printEntry($keys[$i + $kmax + 1]); } printElem($m, $f, "\n", "\n"); } @@ -422,7 +458,13 @@ my $mcond = $_[4]; my $cnt = $hitcount{$mip}++; - if ($cnt >= $settings{"TRESHOLD"} && check_time($mdate)) { + $reason_n{$mip}{$mclass}++; + if ($report) { + push(@{$reason{$mip}{$mclass}}, $mreason); + } else { + $reason{$mip}{$mclass} = $mreason; + } + if ($report || ($cnt >= $settings{"TRESHOLD"} && check_time($mdate))) { my $pat; if (!$mcond) { $ignored{$mip}{$mclass} = $mreason; @@ -436,14 +478,8 @@ exec_iptables("-I", "INPUT", "1", "-s", $mip, "-j", $settings{"ACTION"}); } $iplist{$mip} = $mdate; - $reason{$mip}{$mclass} = $mreason; - $reason_n{$mip}{$mclass}++; } else { # Over treshold, but is added, check if we can update the timedate - if ($iplist{$mip} < 0) { - $reason{$mip}{$mclass} = $mreason; - $reason_n{$mip}{$mclass}++; - } $iplist{$mip} = $mdate if ($mdate > $iplist{$mip}); } } @@ -559,7 +595,6 @@ } # Test pid file existence -my $report; $pid_file = shift; if ($pid_file eq "-f") { $report = 1; @@ -615,6 +650,7 @@ # Force dry run mode if we are reporting only if ($report) { $settings{"DRY_RUN"} = 1; + $settings{"VERBOSITY"} = 1; } # Clean up certain arrays duplicate entries