How the script works:
- Copies over the current pflog file to the working directory
- Runs tcpdump on the copied pflog file and creates a tcpdump text file
- Creates an array of the file and then goes through it looking for all blocked in traffic
- Creates a hash table of the unique blocked IPs and then determines how many blocked entries for each IP
- For those blocked IPs with over a certain number of blocked entries it goes back through the log array and finds how many passed in, blocked out, and passed out entries
- Reports that information via an HTML formatted email to an address of your choice
- Deletes the tcpdump output and copied over pflog files
This script is designed to be ran as a cron job, right before the log rotates.
----------pfblockreport.pl------------------------
#!/usr/bin/perl -w
use strict;
use File::Copy;
use Net::SMTP;
use Sys::Hostname;
my @blockTemp = ();
my @log = ();
my %blockedIPs;
my $pktLimit = 100;
my $crdt = localtime;
my $to = "dean\@company.com";
#additional recipient (if needed)
#my $to2 = "deptaccount\@company.com";
my $from = "pfblocked\@company.com";
my $hstname = hostname();
my $subject = "PF Block Report for $hstname";
#start of html report
my $message = "<p>PF Block Report for $hstname on $crdt</p> \n" .
"<table border\=\"2\" width\=\"650\"><tr><td>Blocked IP</td><td align\=\"center\">Blocked In</td>" .
"<td align\=\"center\">Passed In</td><td align\=\"center\">Blocked Out</td><td align\=\"center\">Passed Out</td></tr> \n";
#copy over current pf log file
#run tcpdump on output file
#then load array with data
copy("/var/log/pflog","pflogfile");
system("tcpdump -neltttr pflogfile > tcpdumpfile.txt");
open(TDF,"tcpdumpfile.txt");
@log = <TDF>;
close TDF;
#parse each entry with regex looking for IPv4 blocked in only
#load those source IPs into array
foreach my $line(@log)
{
my ($action, $srcIP);
if ($line =~ /(\w+ \d+ \d+:.\d:.\d+)\.(\d+) rule (\d+)\/\(match\) (\w+ \w+) \w+ (\w+)\: (\d+\.\d+\.\d+\.\d+)(.*)/)
{
($action, $srcIP) = ($4, $6);
if ($action eq "block in")
{
push(@blockTemp,$srcIP);
}
}
}
#load hash to get unique blocked IPs
#IP address is the hash key and 1 is value for all
%blockedIPs = map { $_ => 1 } @blockTemp;
#find how many blocked entries per blocked IP
#add that to the value of the hash
foreach my $key (keys(%blockedIPs))
{
my $pkt = 0;
my $host = $key;
foreach my $tmpip(@blockTemp)
{
if ($host eq $tmpip)
{
$pkt++;
}
}
$blockedIPs{$key} = $pkt;
}
#look for blocked IPs that are over the bad entries limit
#then go back through logfile and check to see how many entries
#have those IPs as source with pass in or destination with pass or out
foreach my $key (sort (keys(%blockedIPs)))
{
my $blkIP = $key;
my $x = length ($blkIP);
my $pktNum = $blockedIPs{$key};
my $inCnt = 0;
my $outCnt = 0;
my $boCnt = 0;
if ($pktNum > $pktLimit)
{
foreach my $line(@log)
{
my ($action, $srcHost, $dstHost);
if ($line =~ /(\w+ \d+ \d+:.\d:.\d+)\.(\d+) rule (\d+)\/\(match\) (\w+ \w+) \w+ (\w+)\: (\d+\.\d+\.\d+\.\d+)\.(\d+) > (\d+\.\d+\.\d+\.\d+)\.(\d+)\:(.*)/)
{
($action, $srcHost, $dstHost) = ($4, $6, $8);
if ($blkIP eq $srcHost and $action eq "pass in")
{
$inCnt++;
}
if ($blkIP eq $dstHost and $action eq "pass out")
{
$outCnt++;
}
if ($blkIP eq $dstHost and $action eq "block out")
{
$boCnt++;
}
}
if ($line =~ /(\w+ \d+ \d+:.\d:.\d+)\.(\d+) rule (\d+)\/\(match\) (\w+ \w+) \w+ (\w+)\: (\d+\.\d+\.\d+\.\d+) > (\d+\.\d+\.\d+\.\d+)\:(.*)/)
{
($action, $srcHost, $dstHost) = ($4, $6, $7);
if ($blkIP eq $srcHost and $action eq "pass in")
{
$inCnt++;
}
if ($blkIP eq $dstHost and $action eq "pass out")
{
$outCnt++;
}
if ($blkIP eq $dstHost and $action eq "block out")
{
$boCnt++;
}
}
}
$message = $message . "<tr><td>$key</td><td align\=\"center\">$blockedIPs{$key}</td>" .
"<td align\=\"center\">$inCnt</td><td align\=\"center\">$boCnt</td>" .
"<td align\=\"center\">$outCnt</td></tr> \n";
}
}
$message = $message . "</table>";
#open SMTP connection and mail information
my $smtp = Net::SMTP->new("smtp.company.com");
$smtp->mail( $from );
#for single recipient
$smtp->to( $to );
#for two or more recipients
#$smtp->to( $to,$to2 );
$smtp->data();
$smtp->datasend("MIME-Version: 1.0\n");
$smtp->datasend("Content-Type: text/html; charset=us-ascii\n");
$smtp->datasend("From: " . $from . "\n");
$smtp->datasend("To: " . $to . "\n");
$smtp->datasend("Subject: " . $subject . "\n");
$smtp->datasend("\n");
$smtp->datasend("\n");
$smtp->datasend( $message );
$smtp->datasend("\n");
$smtp->dataend();
$smtp->quit();
#delete tcpdump output and copied over pflog files
unlink("tcpdumpfile.txt");
unlink("pflogfile");