#!/usr/bin/perl
#
# $Id: avStats.pl,v 1.2 2010/05/12 14:39:44 rdilley Exp $
#
# author: ron dilley
#
# desc: this perl script parses Symantec A/V logs and generates stats
#
# Copyright (C) 2010  Ron A. Dilley
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; version 2
# of the License.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
#
# ron.dilley@uberadmin.com
#
############################################################################

#
# modules
#
use Getopt::Std;
use FileHandle;

#
# pragmas
#
use strict;

#
# set environment
#
$ENV{PATH} = "/usr/bin:/bin:/usr/sbin:/sbin:/usr/ucb";

#
# turn on autoflush
#
select STDERR; $| = 1;
select STDOUT; $| = 1;

#
# defines
#
$::TRUE = 1;
$::FALSE = 0;
$::FAILED = -1;

$::VERSION = '$Id: avStats.pl,v 1.2 2010/05/12 14:39:44 rdilley Exp $';
$::PROGNAME = "avStats.pl";

%::Config = ();
$::Config{'debug'} = $::FALSE;

#
# main routine
#
if ( &main() != $::TRUE ) {
  exit( 1 );
}

exit( 0 );

############################################################################
#
# sub-routines
#

#
# main routine
#
sub main {
  my $arg;

  #
  # display script banner
  #
  &show_banner();

  #
  # parse command-line
  #
  &parse_command_line();

  # process args that are left
  while( $arg = shift( @::ARGV ) ) {
    &processFile( $arg );
  }

  &showStats();

  # done
  return $::TRUE;
}

#
# display banner info
#
sub show_banner {
  print stderr "$::PROGNAME v$::VERSION\n";
  print stderr "By: Ron Dilley\n";
  print stderr "\n";
  print stderr "$::PROGNAME comes with ABSOLUTELY NO WARRANTY.\n";
  print stderr "This is free software, and you are welcome\n";
  print stderr "to redistribute it under certain conditions;\n";
  print stderr "See the GNU General Public License for details.\n";
  print stderr "\n";

  return $::TRUE;
}

#
# display help info
#
sub show_help {
  print "Syntax:\n";
  print "\n";
  print "$::PROGNAME [options] {dir} [{dir} ...]\n";
  print "\n";
  print "-d {0-9}   Display debug information during program run\n";
  print "\n";

  return $::TRUE;
}

#
# parse command-line arguments
#
sub parse_command_line {
  no strict 'vars';

  if ( getopts( 'd:' ) == $::FALSE ) {
    &show_help();
    return $::FAILED;
  }
  if ( defined $opt_d ) {
    if ( $opt_d > 0 ) {
      # set debug mode
      $::Config{'debug'} = $opt_d;
    }
  }

  return $::TRUE;
}

#
# process av log file
#
sub processFile {
  my ( $fname ) = @_;
  my $fHandle = new FileHandle;
  my $line;
  my $computer;
  my $source;
  my $risk;
  my $occurences;
  my $filename;
  my $actAction;
  my $reqAction;
  my $secAction;
  my $eTime;
  my $user;
  my $eDate;

  if ( $fname eq "-" ) {
    # read from stdin
    if ( ! defined open( $fHandle, "<&STDIN" ) ) {
      print "ERROR - Unable to dup stdin\n";
      return $::FAILED;
    }
  } else {
    if ( ! defined open( $fHandle, "< $fname" ) ) {
      print "ERROR - Unable to open [$fname]\n";
      return $::FAILED;
    }
  }

  while( $line = <$fHandle> ) {
    chomp( $line );
    if ( $line =~ m/.*\s+SymantecServer\s+.*\s+Virus found,Computer name: (.*),Source: (.*),Risk name: (.*),Occurrences: (\d+),(.*),\".*\",Actual action: (.*),Requested action: (.*),Secondary action: (.*),Event time: (.*),Inserted:.*,User: (.*),Source computer.*/ ) {
      $computer = $1;
      $source = $2;
      $risk = $3;
      $occurences = $4;
      $filename = $5;
      $actAction = $6;
      $reqAction = $7;
      $secAction = $8;
      $eTime = $9;
      $user = $10;
    } elsif ( $line =~ m/.*\s+SymantecServer\s+.*\s+Virus found,Computer name: (.*),Source: (.*),Risk name: (.*),Occurrences: (\d+),(.*),,Actual action: (.*),Requested action: (.*),Secondary action: (.*),Event time: (.*),Inserted:.*,User: (.*),Source computer.*/ ) {
      $computer = $1;
      $source = $2;
      $risk = $3;
      $occurences = $4;
      $filename = $5;
      $actAction = $6;
      $reqAction = $7;
      $secAction = $8;
      $eTime = $9;
      $user = $10;
    } elsif ( $line =~ m/.*\s+SymantecServer\s+.*\s+Security risk found,Computer name: (.*),Source: (.*),Risk name: (.*),Occurrences: (\d+),(.*),\".*\",Actual action: (.*),Requested action: (.*),Secondary action: (.*),Event time: (.*),Inserted:.*,User: (.*),Source computer.*/ ) {
      $computer = $1;
      $source = $2;
      $risk = $3;
      $occurences = $4;
      $filename = $5;
      $actAction = $6;
      $reqAction = $7;
      $secAction = $8;
      $eTime = $9;
      $user = $10;
    } elsif ( $line =~ m/.*\s+SymantecServer\s+.*\s+Security risk found,Computer name: (.*),Source: (.*),Risk name: (.*),Occurrences: (\d+),(.*),,Actual action: (.*),Requested action: (.*),Secondary action: (.*),Event time: (.*),Inserted:.*,User: (.*),Source computer.*/ ) {
      $computer = $1;
      $source = $2;
      $risk = $3;
      $occurences = $4;
      $filename = $5;
      $actAction = $6;
      $reqAction = $7;
      $secAction = $8;
      $eTime = $9;
      $user = $10;
    } elsif ( $line =~ m/.*\s+SymantecServer\s+.*:\s+(.*),Traffic from IP address (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}) is blocked from (.*) to (.*),Local:\s+(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}),.*Remote:\s+(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}),.*Begin: (.*),End.*Occurrences: (\d+),.*Application: (.*),Location.*User: (.*),Domain: (.*).*/ ) {
      $computer = $1;
      $source = "Network Protect";
      $risk = "Untrusted Traffic";
      $occurences = $8;
      $filename = $2;
      $actAction = "Traffic Blocked";
      $reqAction = "Traffic Blocked";
      $secAction = "None";
      $eTime = $7;
      $user = $10;
    } elsif ( $line =~ m/.*\s+SymantecServer\s+.*\s+(.*),\[SID: \d+\]\s+(.*)\.\s+Traffic has been blocked from this application: (.*),Local:\s+(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}),.*Remote:\s+(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}),.*Begin: (.*),End.*Occurrences: (\d+),.*Application: (.*),Location.*User: (.*),Domain: (.*).*/ ) {
      $computer = $1;
      $source = "Network Protect";
      $risk = $2;
      $occurences = $7;
      $filename = $8;
      $actAction = "Traffic Blocked";
      $reqAction = "Traffic Blocked";
      $secAction = "None";
      $eTime = $6;
      $user = $9;
    } elsif ( $line =~ m/.*\s+SymantecServer\s+.*\s+Site: (.*),Server: (.*),Domain: (.*),(.*),(.*),(.*),(.*)/ ) {
      # ignore them
      $eTime = "";
    } elsif ( $line =~ m/.*\s+SymantecServer\s+.*\s+(.*)\s+.*/ ) {
      # ignore them
      $eTime = "";
    }

    if ( $eTime =~ m/^(\d+)\-(\d+)\-(\d+) \d+:\d+:\d+/ ) {
      $eDate = "$1$2$3";

      if ( defined $::daysByHost{$computer}{$eDate} ) {
	$::daysByHost{$computer}{$eDate}{$risk}++;
      } else {
	$::daysByHost{$computer}{$eDate}{$risk} = 1;
      }

      if ( defined $::hostsByDay{$eDate}{$computer} ) {
	$::hostsByDay{$eDate}{$computer}++;
      } else {
	$::hostsByDay{$eDate}{$computer} = 1;
      }
    }
  }

  close( $fname );
}

#
# display stats
#
sub showStats {
  my $key;
  my $day;
  my $host;
  my $risk;

  print "Infections per host by day\n";
  print "====\n\n";
  foreach $key ( sort {$a <=> $b} keys( %::hostsByDay ) ) {
    print "$key\n";
    foreach $host ( sort {$::hostsByDay{$key}{$b} <=> $::hostsByDay{$key}{$a}} keys( % { $::hostsByDay{$key} }  ) ) {
      printf( "  %-20s %10d\n", $host, $::hostsByDay{$key}{$host} );
    }
  }

  print "\n";

  print "Infections per day by host\n";
  print "====\n\n";

  foreach $host ( sort {scalar(keys(%{$::daysByHost{$b}})) <=> scalar(keys(%{$::daysByHost{$a}}))} keys( %::daysByHost ) ) {
    print "$host\n";
    foreach $day ( sort {$a <=> $b} keys( % { $::daysByHost{$host} }  ) ) {
      print "  $day\n";
      foreach $risk ( sort {$::daysByHost{$host}{$day}{$b} <=> $::daysByHost{$host}{$day}{$a}} keys( % { $::daysByHost{$host}{$day} } ) ) {
	printf( "    %-10d %-30s\n", $::daysByHost{$host}{$day}{$risk}, $risk );
      }
    }
    print "\n";
  }
}
