Beefy Boxes and Bandwidth Generously Provided by pair Networks
Your skill will accomplish
what the force of many cannot
 
PerlMonks  

(code) Netfilter/iptables log parser/reporter for PHB consumption

by ybiC (Prior)
on Nov 10, 2003 at 04:16 UTC ( #305787=sourcecode: print w/ replies, xml ) Need Help??

Category: Networking Code
Author/Contact Info ybiC
Description:

A lightweight parser for Netfilter logs.   Produces a highly-simplified summary report for PHB consumption.   Sample input and report at tail of pod.

From a perlish standpoint, this has been my re-entry after a couple-month absence, and an exercise in using File::Temp properly, as well as an introduction to the following modules:

Update: as always, critique is welcome and requested.

#!/usr/bin/perl -w

## fwreport
## pod at tail


$|++;
use strict;
my $version = '0.09.27';


use File::Temp qw/tempfile/;
use Socket;
use Net::Whois::IANA;
use Locale::Country;
use File::Slurp;
use Text::Autoformat;
# use Module::Versions::Report;


## Config params:
my $infile     = shift || 'fwreport.in';    ## logfile from Netfilters
+ firewall
my $foutfile   = shift || 'fwreport.out';   ## formatted output report
my $routfile   = shift || 'fwreport.raw';   ## unformatted output repo
+rt
my $tempdir    = '/tmp/';
my $template   = 'file_XXXXXXXXXX';
my $fqdn_level = 2;


## Eliminate duplicates from input file:
my $attacks = 1;
my ( $fh, $filename1 ) = tempfile($template, DIR=>$tempdir, UNLINK=>1)
+;
{
  open( IN, $infile )  or die "Error opening $infile: $!";
  while(<IN>){
    my %seen;
    for (<IN>){
      ++$attacks;
      ++$seen{$_};
    }
    print $fh sort keys %seen;
  }
  close IN  or die "Error closing $infile: $!";
}


## Ready intermediate file from write to read:
seek $fh,0,0;


## Parse intermediate file:

my (@countries, @domains, @s_svcs, @d_svcs, );
while(<$fh>){


  ## Populate hash with select elements from entry:
  my @elements = split( /\s+/ );
  my %entry;
  for my $element (@elements) {
    my ($key, $value) = split(/=/, $element, 2);
    next unless ($key =~ m/^(IN|OUT|SRC|DST|PROTO|SPT|DPT)$/);
    $entry{$key} = (defined($value) ? $value : '');
  }


  ## Determine what country attack is from:
  my $iana = new Net::Whois::IANA;
  $iana->whois_query(-ip=>$entry{SRC});
    ## leading 2 chars only, avoid CACA, USUS, EU # whole world msgs:
  my $cc = substr($iana->country(), 0, 2);
    ## decode to name:
  my $cn = code2country($cc);
  push(@countries, $cn) if $cn;


  ## Reverse DNS lookup of attacking host:
  my $domain = gethostbyaddr(inet_aton($entry{SRC}),AF_INET);
    ## truncate FQDN down to n-level:
  push @domains,($domain ? $domain =~ m/((?:[^.]+\.?){1,$fqdn_level})$
+/ : $entry{SRC});


  ## Determine name of attacking service:
  my $s_svc = getservbyport( $entry{SPT}, lc($entry{PROTO}) );
  push @s_svcs,($s_svc ? $s_svc : $entry{SPT});


  ## Determine name of attacked service:
  my $d_svc = getservbyport( $entry{DPT}, lc($entry{PROTO}) );
  push @d_svcs,( $d_svc ? $d_svc : $entry{DPT});

}



## Wrap it up:
{
  undef my %saw; @saw{@countries} = (); my @countries_u = sort keys %s
+aw;
  undef    %saw; @saw{@domains}   = (); my @domains_u   = sort keys %s
+aw;
  undef    %saw; @saw{@s_svcs}    = (); my @s_svcs_u    = sort keys %s
+aw;
  undef    %saw; @saw{@d_svcs}    = (); my @d_svcs_u    = sort keys %s
+aw;

  open( OUT, "+> $routfile" )  or die "Error opening $routfile: $!";

  my ($sec,$min,$hour,$mday,$mon,$year,) = localtime(time);
  my $stamp = sprintf(
    "%02d-%02d-%02d   %02d:%02d", $year+1900, $mon+1, $mday, $hour, $m
+in
  );
  print OUT $stamp . "\n"x2;
  print OUT "\n"x2;

  print OUT 'BLOCKED ATTACKS = ' . $attacks . "\n"x2;
  print OUT "\n"x1;

  print OUT 'ATTACKING COUNTRIES = ';
  print OUT my $countries_u = @countries_u . "\n"x2;
  print OUT $_ . '    ' for (@countries_u);
  print OUT "\n"x3;

  my @domains_us = SortAlphaThenNum( @domains_u );
  print OUT 'ATTACKING DOMAINS = ';
  print OUT my $domains_us = @domains_us . "\n"x2;
  print OUT $_ . ', ' for (@domains_us);
  print OUT "\n"x3;

  my @s_svcs_us = SortAlphaThenNum( @s_svcs_u );
  print OUT 'ATTACKING SERVICES = ';
  print OUT my $s_svcs_us = @s_svcs_us . "\n"x2;
  print OUT $_ . ', ' for (@s_svcs_us);
  print OUT "\n"x3;

  my @d_svcs_us = SortAlphaThenNum( @d_svcs_u );
  print OUT 'ATTACKED SERVICES = ';
  print OUT my $d_svcs_us = @d_svcs_us . "\n"x2;
  print OUT $_ . ', ' for (@d_svcs_us);
  print OUT "\n"x3;

  close OUT  or die "Error closing $routfile: $!";
}


## Spruce it up a bit:
{
  my $rawtext = read_file($routfile);
  my $formatted = autoformat $rawtext,{left=>1,right=>72,all=>1,squeez
+e=>0};
  write_file($foutfile, $formatted);
}



######################################################################
+####


## Elements with any alpha before elements with all numeric
sub SortAlphaThenNum {
  my @unsorted = @_;
  return my @sorted =
    map $_->[0],
    sort {
      $a->[1] <=> $b->[1] || $a->[2] cmp $b->[2] ||
      $a->[3] <=> $b->[3] || $a->[0] cmp $b->[0]
    }
    map [ $_, scalar(/^\d/), split /(\d+)/, $_, 2],
    @unsorted
  ;
}


END {
  sleep 1 &&  print "\a" for( 1..3 ); 
}


######################################################################
+####



=head1 TITLE

fwreport

=head1 SYNOPSIS

fwreport infile outfile

=head1 DESCRIPTION

 A lightweight parser for Netfilter logs.
 Produces highly-simplified summary for PHB consumption.

=head1 TODO

   ?combine redundant 'wrap it up' code into sub?

   Sanity-check IN
   Strip leading whitespace from IN:
     s/^\s+//g
   Datetimestamp for filename
   Datestamp of input file to output report
   Getopt::Long and Pod::Usage
     --infile, --outfile, --versions, --help, --man
   Module::Versions::Report conditionally with END{...}
   Test on Win32
   File::Temp instead of $routfile
     File::Slurp may not allow this

=head1 UPDATE

 2003-11-10   14:45 CST
   Post to PerlMonks
   Reduce number and scope of global vars
   PC speaker beeps on completion
   Datestamp of program run to output report
   Sample input and report to pod


 2003-11-08   22:00 CST
   File::Slurp, Text::Autoformat to prettify output report
   Output sort any-alpha first, all-numeric last
   Revise parsing:
     number of (attacks, attackers, ISPs)
     list of (countries, domains, attack(ing|ed) services)
   Parse country codes to names
   Add Module::Versions::Report
   Eliminate duplicates entries from intermediate file
   Print to OUT instead of STDOUT
   Strip all but rightmost 2 or 3 elements of FQDN
   Strip bogus  country code info:
     CACA => CA, USUS => US, EU  # Country is really world wide => EU
   Only print protocol num if no service name
   Eliminate duplicate entries from IN
   Use File::Temp for intermediate file
   Parse src/dst ports to service names:
     Debug TCP is uc while /etc/services is lc
   Read data from IN
   Rename from "whobe"
   Parse input from syslog contents
   Read from file (one IPaddr/line) instead of @ARGV
   Reverse name lookup of source address
   Variable-ize output delimiter

 2003-10-31   17:10 CST
   Initial working code

=head1 TESTED

 Debian                    3.0r1
 Perl                      5.8.0
 strict                    1.02
 warnings                  1.00
 File::Temp                0.14
 Socket                    1.75
 Net::Whois::IANA          0.03
 Locale::Country           2.06
 File::Slurp               2004.0904
 Text::Autoformat          1.12
 Modules::Versions::Report 1.02

=head1 BUGS

 Unclear on root-cause, but IP addresses registered to LACNIC
   occasionally cause errors and lookup failure:
   Use of uninitialized value in scalar chomp at Net/Whois/IANA.pm lin
+e 117.

=head1 CREDITS

 Props ta menolly for gracious reminder of rudimentary perling,
 atcroft for hash-populating aid,
 tye and jmcnamara for es'plaining seek() re: File::Temp write then re
+ad,
 wufnik and Enlil for FQDN truncating idears,
 bart, Enlil, and Limbic~Region for unnatural list sorting with ST,
 dru145 for  www.ginini.com.au/tools/fwlogsum/,
 Lincoln Stein for NPwP,
 And to some guy named vroom.

=head1 AUTHOR

ybiC

=head1 SAMPLE INPUT

 (extraneous fields stripped, to reduce lateral scrolling at PM)

 IN=eth0 OUT= SRC=172.141.50.1 DST=1.2.3.4 SPT=3155 DPT=17300 PROTO=UD
+P
 IN=eth0 OUT= SRC=200.226.91.1 DST=1.2.3.4 SPT=1369 DPT=17300 PROTO=UD
+P
 ACTION=drop-input IN=eth0 OUT= SRC=202.123.79.1 DST=1.2.3.4 SPT=49634
+ DPT=21 PROTO=TCP
 IN=eth0 OUT= SRC=211.162.110.1 DST=1.2.3.4 SPT=30112 DPT=1026 PROTO=T
+CP
 IN=eth0 OUT= SRC=213.25.170.1 DST=1.2.3.4 SPT=4674 DPT=2282 PROTO=TCP
 IN=eth0 OUT= SRC=221.141.148.1 DST=1.2.3.4 SPT=4124 DPT=25 PROTO=TCP
 IN=eth0 OUT= SRC=24.128.81.1 DST=1.2.3.4 SPT=3789 DPT=17300 PROTO=UDP
 IN=eth0 OUT= SRC=24.150.221.1 DST=1.2.3.4 SPT=1900 DPT=17300 PROTO=TC
+P
 IN=eth0 OUT= SRC=24.187.84.1 DST=1.2.3.4 SPT=4789 DPT=593 PROTO=UDP
 IN=eth0 OUT= SRC=24.194.92.1 DST=1.2.3.4 SPT=3540 DPT=17300 PROTO=TCP
 IN=eth0 OUT= SRC=24.214.27.1 DST=1.2.3.4 SPT=4076 DPT=17300 PROTO=TCP
 IN=eth0 OUT= SRC=24.60.217.1 DST=1.2.3.4 SPT=2268 DPT=17300 PROTO=TCP
 IN=eth0 OUT= SRC=61.143.182.1 DST=1.2.3.4 SPT=30110 DPT=1026 PROTO=TC
+P
 IN=eth0 OUT= SRC=61.172.3.1 DST=1.2.3.4 SPT=32997 DPT=1026 PROTO=TCP
 IN=eth0 OUT= SRC=61.250.91.1 DST=1.2.3.4 SPT=58926 DPT=443 PROTO=TCP
 IN=eth0 OUT= SRC=62.59.148.1 DST=1.2.3.4 SPT=666 DPT=1026 PROTO=TCP
 IN=eth0 OUT= SRC=63.83.69.1 DST=1.2.3.4 SPT=4823 DPT=57 PROTO=TCP
 IN=eth0 OUT= SRC=65.130.116.1 DST=1.2.3.4 SPT=2782 DPT=524 PROTO=TCP
 IN=eth0 OUT= SRC=65.50.156.1 DST=1.2.3.4 SPT=2394 DPT=17300 PROTO=TCP
 IN=eth0 OUT= SRC=68.1.179.1 DST=1.2.3.4 SPT=2878 DPT=515 PROTO=TCP
 IN=eth0 OUT= SRC=68.13.16.1 DST=1.2.3.4 SPT=53 DPT=1026 52 PROTO=TCP
 IN=eth0 OUT= SRC=68.16.97.1 DST=1.2.3.4 SPT=65322 DPT=554 PROTO=TCP
 IN=eth0 OUT= SRC=68.16.97.1 DST=1.2.3.4 SPT=65323 DPT=7070 PROTO=TCP
 IN=eth0 OUT= SRC=68.21.37.1 DST=1.2.3.4 SPT=2991 DPT=20168 PROTO=TCP
 IN=eth0 OUT= SRC=68.22.76.1 DST=1.2.3.4 SPT=1379 DPT=20168 PROTO=UDP
 IN=eth0 OUT= SRC=68.3.106.1 DST=1.2.3.4 SPT=3577 DPT=20168 PROTO=UDP
 IN=eth0 OUT= SRC=68.50.191.1 DST=1.2.3.4 SPT=4565 DPT=20168 PROTO=TCP
 IN=eth0 OUT= SRC=68.51.50.1 DST=1.2.3.4 SPT=3425 DPT=20168 PROTO=TCP
 IN=eth0 OUT= SRC=68.83.144.1 DST=1.2.3.4 SPT=1298 DPT=20168 PROTO=TCP
 IN=eth0 OUT= SRC=68.99.193.1 DST=1.2.3.4 SPT=4070 DPT=1026 PROTO=TCP
 IN=eth0 OUT= SRC=68.99.193.1 DST=1.2.3.4 SPT=4070 DPT=1027 PROTO=UDP
 IN=eth0 OUT= SRC=81.166.217.1 DST=1.2.3.4 SPT=3963 DPT=21 PROTO=TCP
 IN=eth0 OUT= SRC=193.108.95.1 DST=1.2.3.4 SPT=80 DPT=1042 PROTO=TCP
 IN=eth0 OUT= SRC=193.108.95.1 DST=1.2.3.4 SPT=80 DPT=1043 PROTO=TCP
 IN=eth0 OUT= SRC=202.12.29.1 DST=1.2.3.4 SPT=43 DPT=38423 PROTO=TCP
 IN=eth0 OUT= SRC=216.239.59.1 DST=1.2.3.4 SPT=80 DPT=1031 PROTO=TCP

=head1 SAMPLE OUTPUT

 2003-11-09   14:55


 BLOCKED ATTACKS = 36


 ATTACKING COUNTRIES = 10

 Australia    Brazil    Canada    China    France    Hong Kong    Kore
+a,
 Republic of    Netherlands    Poland    United States


 ATTACKING DOMAINS = 25

 ameritech.net, apnic.net, attbi.com, bellsouth.net, cgocable.net,
 com.br, comcast.net, cox.net, knology.net, optonline.net, qwest.net,
 rogers.com, rr.com, tiscali.fr, zonnet.nl, 61.143.182.1, 61.172.3.1,
 61.250.91.1, 63.83.69.1, 193.108.95.1, 202.123.79.1,
 211.162.110.1, 213.25.170.1, 216.239.59.1, 221.141.148.1,


 ATTACKING SERVICES = 32

 domain, whois, www, 666, 1298, 1369, 1379, 1900, 2268, 2394, 2782, 28
+78,
 2991, 3425, 3540, 3577, 3789, 3963, 4070, 4076, 4124, 4565, 4674, 478
+9,
 4823, 30110, 30112, 32997, 49634, 58926, 65322, 65323,


 ATTACKED SERVICES = 18

 ftp, https, mtp, printer, smtp, 524, 554, 593, 1026, 1027, 1031, 1042
+,
 1043, 2282, 7070, 17300, 20168, 38423,

=cut

Comment on (code) Netfilter/iptables log parser/reporter for PHB consumption
Download Code

Back to Code Catacombs

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: sourcecode [id://305787]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others avoiding work at the Monastery: (14)
As of 2015-07-28 18:24 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    The top three priorities of my open tasks are (in descending order of likelihood to be worked on) ...









    Results (258 votes), past polls