#!/usr/bin/perl
#
# snort_stat.pl is a perl script trying to generate statistical data from every
# day snort log file.
#
# USAGE: cat <snort_log> | snort_stat.pl -r -f -h -t n -l<num>
#        -d: debug
#        -r: resolve IP address to domain name
#        -f: use fixed rather than variable width columns
#        -h: produce html output
#        -t: threshold
#        -a: scan whole file (no date limit)
#	 -l: limit to <num> entries
#
# or put it in the root's crontab file:
#59      10      *       *       *       root    cat /var/log/authlog | /etc/snort_stat.pl | sendmail root
#
# Changelog:
# 2003-01-07, Christian Hammers <ch@debian.org>
#	* added option "-l"
#	* filtered for yesterdays lines
#	* renamed "attacks to events"
#	* slightly reformatted.
# 2002-03-20, Yen-Ming Chen <chenym@ALUMNI.CMU.EDU>
# 	* initial release
# 

use Getopt::Std;		# use Getopt for options
use Socket;			# use socket for resolving domain name from IP
use vars qw($opt_r $opt_f $opt_d $opt_h $opt_t $opt_a);
%HOSTS = ();			# Hash for IP <-> domain name mapping  

getopts('darfht:l:') || die "Could not getopts"; # get options in command line
$saddr_len = 15;
$daddr_len = 15;
$timeout = 3;			# for name resolver
$th = $opt_t || 0;		# default threshold
$maxlines = $opt_l || 99999;	# no more than opt_l lines per statistic

# used to filter yesterdays lines as auth.log is rotate weekly only
chomp($yesterday_date_string = `/bin/date -d yesterday +'\%m/\%d-'`);
if ($opt_d) { $yesterday_date_string = "."; }

# process whatever comes in
while (<>) {
  my $alert = {};
  chomp;
  # is this line an alert message
  if ( $_ =~ /^\[\*\*\]/ ) {
    $line = <>;
    chomp($line);
    unless ( $line eq "" ) {
      # strip off the [**] from either end.
      s/\s*\[\*\*\]\s*//og;
      s/\s*\[[0-9:]+\]\s*//o;
      if ($_ =~ /^spp_anomsensor\:[\D]+\:\s([\d\.]+)/ox) {
        $alert->{PLUGIN} = "anomsensor"; $alert->{TYPE} = "plugin";
        $alert->{SIG} = $alert->{PLUGIN};
      } elsif ($_ =~ /^spp_portscan\:\sEnd\sof\sportscan\sfrom\s([\d\.]+)/ox) {
        $alert->{PLUGIN} = "portscan"; $alert->{TYPE} = "plugin";
        $alert->{SADDR} = $1; $alert->{SIG} = $alert->{PLUGIN};
        process_data($alert); $lastwassnort = 1; next;
      } elsif ( $_ =~ /^spp_stream4\:\s(.+)/o ) {
        $alert->{SIG} = $1; $alert->{TYPE} = "alert";
	$alert->{PLUGIN} = "stream";
      } elsif ( $_ =~ /[^:]/ox) {
        $alert->{SIG} = $_; $alert->{TYPE} = "alert"; 
      }
      if ( $line =~ m/^\[Classification\:([^\]]*)\]\s
	   \[Priority\:\s(\d+)\]/ox) {
        $alert->{CLASS} = $1; $alert->{PRIORITY} = $2;
	$line=<>;
      }
      if ( $line =~ m/^\[Priority\:\s(\d+)\]/ox) {
        $alert->{CLASS} = "Undefined"; $alert->{PRIORITY} = $1;
	$line=<>;
      }
      if ( $line =~ m/^(\d+)\/(\d+)(?:\/\d+)?\-(\d+)\:(\d+)\:(\d+)\.(\d+)\s
	   ([\d\.]+)[\:]*([\d]*)\s[\-\>]+\s([\d\.]+)[\:]*([\d]*)/ox) {

	   	next if (!$opt_a && $line =~ /^$yesterday_date_string/);
        $alert->{MON} = $1;   $alert->{DAY} = $2;   $alert->{HOUR} = $3; 
        $alert->{MIN} = $4;   $alert->{SEC} = $5;   $alert->{SADDR} = $7; 
        $alert->{SPORT} = $8; $alert->{DADDR} = $9; $alert->{DPORT} = $10; 
        $alert->{HOST} = "localhost"; 
        $alert->{CLASS} = "Undefined" if ! defined ($alert->{CLASS});
        $alert->{PRIORITY} = 0 if ! defined ($alert->{PRIORITY});
        process_data($alert); $lastwassnort = 1; next;
      }
    } else { 
      print STDERR "Warning, file may be incomplete\n";
      next;
    }
  } 
  # This is syslog format
  if ($_ =~ m/^(\w{3}) \s+ (\d+) \s (\d+)\:(\d+)\:(\d+)\s 
                   (\S+?)\ssnort[\[\d+\]]*\:\s+(.+)/ox 
      || m/^(\d+)\/(\d+)\-(\d+)\:(\d+)\:(\d+)\.(\d+)\s(.+)/ox) 
  {
    $alert->{MON} = $1;    $alert->{DAY} = $2;    $alert->{HOUR} = $3; 
    $alert->{MIN} = $4;    $alert->{SEC} = $5;    $alert->{HOST} = $6;  
    $alert->{SIG} = $7;    
    $alert->{SIG} =~ s/\s*\[[\d\:]+\]\s*//;  # Get rid of [343:33:31]
    $alert->{SIG} =~ s/\[\*\*\]//og; # Get rid of [**] if fast alert
    if ($alert->{SIG} =~ m/spp_portscan\:\sEnd\sof\sportscan\sfrom\s
	([\d\.]+)/ox) { # portscan
      $alert->{SADDR} = $1; $alert->{TYPE} = "plugin"; 
      $alert->{PLUGIN} = "portscan";
      process_data($alert); $lastwassnort = 1; next;
    } elsif ( $alert->{SIG} =~ s/\s([\d\.]+)[\:]?([\d]*)\s[\-\>]+\s
                            ([\d\.]+)[\:]?([\d]*)\s*//x) {
      $alert->{SADDR} = $1; $alert->{SPORT} = $2; 
      $alert->{DADDR} = $3; $alert->{DPORT} = $4; 
      if ($alert->{SIG} =~ m/spp_anomsensor\:\sAnomaly\sthreshold\s
	  exceeded\:\s([\d\.]+)/ox) { # spade
	$alert->{THR} = $1; $alert->{TYPE} = "plugin"; 
	$alert->{PLUGIN} = "anomsensor";
	process_data($alert); $lastwassnort = 1; next;
      } elsif ($alert->{SIG} =~ s/spp_bo\:\s//ox) { # bo
	$alert->{TYPE} = "plugin"; $alert->{PLUGIN} = "bo";
	process_data($alert); $lastwassnort = 1; next;
      } elsif ($alert->{SIG} =~ s/spp_stream4\:\s//ox) { # stream4 
        $alert->{TYPE} = "plugin"; $alert->{PLUGIN} = "stream";
        process_data($alert); $lastwassnort = 1; next;
      } else { # normal alert
	if ( $alert->{SIG} =~ s/\[Classification\:([^\[|^\]]*?)\]\s*
	     (?:\[Priority\:\s(\d+)\])//x ) {
	  $alert->{CLASS} = $1;  $alert->{PRIORITY} = $2;
        }
        if ( $alert->{SIG} =~ s/^\[Priority\:\s(\d+)\]//x ) {
            $alert->{CLASS} = "Undefined"; $alert->{PRIORITY} = $1;
        }
        $alert->{TYPE} = "sys"; $alert->{PLUGIN} = "none";
	process_data($alert); $lastwassnort = 1; next;
      }
    } else {
      print STDERR "No source/dest IP address found! Skipped!" if $opt_d; 
      $alert = {}; next;
    }
  }
  # If a snort message has been repeated several times
  elsif ($lastwassnort && $_ =~ m/last message repeated (\d+) times/) {
    # put the data in the matrix again for each repeat
    $repeats = $1;
    while ($repeats) {
      push @result, $result[-1];
      $repeats--;
    }
    next;
  } else {
    $lastwassnort = 0;
    next;
  }				# Message not related to snort
}

# begin statistics
# I should've used $#result + 1 as $total in the first version! :(
$total = $#result + 1;

for $i ( 0 .. $#result ) {
  # for the same pair of eventer and victim with same sig
  # to see the event pattern
  # used in same_event()
  $s0{"$result[$i]->[9],$result[$i]->[7],$result[$i]->[6]"}++;
  # for the same pair of eventer and victim 
  # to see how many ways are being tried
  # used in same_host_dest()
  $s1{"$result[$i]->[7],$result[$i]->[9]"}++;
  # from same host use same method to event 
  # to see how many events launched from one host
  # used in same_host_sig()
  $s2{"$result[$i]->[6],$result[$i]->[7]"}++;
  # to same victim with same method
  # to see how many events received by one host
  # used in same_dest_sig_stat()
  $s3{"$result[$i]->[6],$result[$i]->[9]"}++;
  # same signature
  # to see the popularity of one event method
  # used in event_distribution()
  $s4{"$result[$i]->[6]"}++;
  # source ip
  $s5{"$result[$i]->[7]"}++;
  # destination ip
  $s6{"$result[$i]->[9]"}++;
}

# begin report

exit 0 unless ($total);
print_head();
print_summary();
print_menu();
same_event();
same_host_dest();
same_host_sig();
same_dest_sig_stat();
event_distribution();
if ($opt_p) {
  portscan();
}
if ($opt_n) {
  anomsensor();
}
print_footer();

# print the header (e.g. for mail)
sub print_head {
  my $hostname = `hostname --fqdn`;
  chomp($hostname);
  if ($opt_h) {
    print "<html>\n<head>\n";
    print "<title>Snort Statistics</title>";
    print "</head>\n<body>\n";
    print "<h1>[SNORT] $hostname Statistics</h1>\n";
  } else { 
    print "Subject: [SNORT] $hostname daily report\n\n";
  }
}

# print the time of begin and end of the log
sub print_summary {
  if ($opt_h) {
    print "<table>\n";
    print "<tr><th>The log begins at:</th>\n";
    print "<td>$result[0]->[0] $result[0]->[1] $result[0]->[2]:$result[0]->[3]:$result[0]->[4]</td></tr>\n";
    print "<tr><th>The log ends at:</th>\n";
    print "<td>$result[$#result]->[0] $result[$#result]->[1] $result[$#result]->[2]:$result[$#result]->[3]:$result[$#result]->[4]</td></tr>\n";
    print "<tr><th>Total events:</th><td> $total</td></tr>\n";
    print "<tr><th>Signatures recorded:</th><td> ". keys(%s4) ."</td></tr>\n";
    print "<tr><th>Source IP recorded:</th><td> ". keys(%s5) ."</td></tr>\n";
    print "<tr><th>Destination IP recorded:</th><td> ". keys(%s6) ."</td></tr>\n";
    print "<tr><th>Portscan detected:</th><td> ", eval '$#posres +1',"</td></tr>\n" if $opt_p;
    print "<tr><th>Anomaly detected:</th><td> ", eval '$#anores +1',"</td></tr>\n" if $opt_n;
    print "</table>\n";
    print "<hr>\n";
  } else {
    print "Events between  $result[0]->[0] $result[0]->[1] ".
	  "$result[0]->[2]:$result[0]->[3]:$result[0]->[4]  and  ".
    	  "$result[$#result]->[0] $result[$#result]->[1] ".
	  "$result[$#result]->[2]:$result[$#result]->[3]:$result[$#result]->[4]\n";
    print "Total events: $total\n";
    print "Signatures recorded: ". keys(%s4) ."\n";
    print "Source IP recorded: ". keys(%s5) ."\n";
    print "Destination IP recorded: ". keys(%s6) ."\n";
    print "Portscan recorded: ", eval '$#posres +1',"\n" if $opt_p;
    print "Anomaly recorded: ", eval '$#anores +1',"\n" if $opt_n;
  }
}

# print menu for HTML page
sub print_menu {
  if ($opt_h) {
    print "<ul><a name=\"top\"></a>\n";
    print "<li><a href=\"#same_hdm\">Number of events from same host to same destination with same method</a>\n"; 
    print "<li><a href=\"#same_hd\">Percentage and number of events from a host to a destination</a>\n";
    print "<li><a href=\"#same_hm\">Percentage and number of events from one host to any with same method</a>\n";
    print "<li><a href=\"#same_d\">Percentage and number of events to one certain host</a>\n";
    print "<li><a href=\"#same_m\">Distribution of event methods</a>\n";
    print "<li><a href=\"#portscan\">Portscans performed to/from HOME_NET</a>\n" if $opt_p;
    print "<li><a href=\"#spade\">Anomaly detected by SPADE</a>\n" if $opt_n;
    print "</ul><HR>\n";
  }
}

# to see the frequency of the event from a certain pair of 
# host and destination
sub same_event {
  if ($opt_h) {
    print "<h3><a name=\"same_hdm\">Number of event from same host to same destination using same method</a></h3>\n";
    print "<table>\n";
    print "<tr><th># of events</th><th>from</th><th>to</th><th>with</th></tr>";
    foreach $k (sort { $s0{$b} <=> $s0{$a} } keys %s0) { 
      @_ = split ",",$k;
      print "<tr><td>$s0{$k}</td><td>$_[1]</td><td>$_[0]</td>
             <td>".printHref($_[2])."</td></tr>\n" if $s0{$k} > $th;
    }
    print "</table><a href=\"#top\">Top</a><hr>\n";
  } else {
    section_header("Events from same host to same destination using same method\n", "asdm");
    foreach $k ((sort { $s0{$b} <=> $s0{$a} } keys %s0)[0..$maxlines]) { 
      @_ = split ",",$k;
      printf(" %4d  %-${saddr_len}s  %-${daddr_len}s  %-20s\n",
	     $s0{$k},$_[1],$_[0],$_[2]) if $s0{$k} > $th;
    }
  }
}

# to see the percentage and number of events from a host to a destination
sub same_host_dest {
  if ($opt_h) {
    print "<h3><a name=\"same_hd\">Percentage and number of events from a host to a destination</a></h3>\n";
    print "<table>\n";
    print "<tr><th>%</th><th># of events</th><th>from</th><th>to</th></tr>\n";
    foreach $k (sort { $s1{$b} <=> $s1{$a} } keys %s1) {
      @_ = split ",",$k;
      printf("<tr><td>%-2.2f</td><td>%-2d</td><td>%-20s</td><td>%-20s</td>
              <td>\n",$s1{$k}/$total*100,$s1{$k},$_[0],$_[1]) if $s1{$k} > $th;
    }
    print "</table><a href=\"#top\">Top</a><hr>\n";
  } else {
    section_header("Percentage and number of events from a host to a destination\n", "pasd");  
    foreach $k ((sort { $s1{$b} <=> $s1{$a} } keys %s1)[0..$maxlines]) {
      @_ = split ",",$k;
      printf("%5.2f  %4d  %-${saddr_len}s  %-${daddr_len}s\n",
	     $s1{$k}/$total*100, $s1{$k},$_[0],$_[1]) if $s1{$k} > $th;
    }
  }
}

# to see how many events launched from one host
sub same_host_sig {
  if ($opt_h) {
    print "<h3><a name=\"same_hm\">Percentage and number of events from one host to any with same method</a></h3>\n";
    print "<table>\n";
    print "<tr><th>%</th><th># of events</th><th>from</th><th>type</th></tr>\n";
    foreach $k (sort { $s2{$b} <=> $s2{$a} } keys %s2) {
      @_ = split ",",$k;
      printf("<tr><td>%-2.2f</td><td>%-4d</td><td>%-20s</td><td>%-28s</td>
             </tr>\n",$s2{$k}/$total*100,$s2{$k},$_[1],&printHref($_[0])) if $s2{$k} > $th;
    }
    print "</table><a href=\"#top\">Top</a><hr>\n";
  } else { 
    section_header("Percentage and number of events from one host to any with same method\n", "pasm");  
    foreach $k ((sort { $s2{$b} <=> $s2{$a} } keys %s2)[0..$maxlines]) {
      @_ = split ",",$k;
      printf("%5.2f  %4d  %-${saddr_len}s  %-28s\n",
	     $s2{$k}/$total*100, $s2{$k},$_[1],$_[0]) if $s2{$k} > $th;
    }
  }
}

# to see how many events received by one host (destination correlated)
sub same_dest_sig_stat {
  if ($opt_h) {
    print "<h3><a name=\"same_d\">Percentage and number of events to one certain host</a></h3>\n";
    print "<table>\n";
    print "<tr><th>%</th><th># of events</th><th>to</th><th>type</th></tr>\n";
    foreach $k (sort { $s3{$b} <=> $s3{$a} } keys %s3) {
      @_ = split ",",$k;
      printf("<tr><td>%-2.2f</td><td>%-4d</td><td>%-25s</td><td>%-28s</td><td>\n",$s3{$k}/$total*100,$s3{$k},$_[1],&printHref($_[0])) if $s3{$k} > $th;
    }
    print "</table><a href=\"#top\">Top</a><hr>\n";
  } else {
    section_header("Percentage and number of events to one certain host\n", "padm");
    foreach $k ((sort { $s3{$b} <=> $s3{$a} } keys %s3)[0..$maxlines]) {
      @_ = split ",",$k;
      printf("%5.2f  %4d  %-${daddr_len}s  %-28s\n",
	$s3{$k}/$total*100, $s3{$k}, $_[1], $_[0]) if $s3{$k} > $th;
    }
  }
}

# to see the popularity of one event method
sub event_distribution {
  if ($opt_h) {
    print "<h3><a name=\"same_m\">Distribution of event methods</a></h3>\n";
    print "<table>\n";
    print "<tr><th>%</th><th># of events</th><th>methods</th></tr>\n";
    foreach $k (sort { $s4{$b} <=> $s4{$a} } keys %s4) {
      @p1 = split ":",$k;
      if ($s4{$k} > $th) {
        printf("<tr><td>%-2.2f</td><td><B>%-4d</B></td><td><B>%-32s</B></td>
                </tr>\n", $s4{$k}/$total*100,$s4{$k},&printHref($p1[0])); 
        foreach $k2 (sort { $s0{$b} <=> $s0{$a} } keys %s0) {
          @p2 = split ",",$k2;
          printf("<tr><td></td><td>%-4d</td><td>%-32s</td></tr>\n", $s0{$k2}, join(" -> ", $p2[1],$p2[0])) if $p1[0] eq $p2[2];
        }
      }
    }
    print "</table><a href=\"#top\">Top</a><hr>\n";
  } else {
    section_header("The distribution of event methods\n", "pam");
    foreach $k ((sort { $s4{$b} <=> $s4{$a} } keys %s4)[0..$maxlines]) {
      @p1 = split ":",$k;
      if ($s4{$k} > $th) {
        printf("%5.2f  %4d  %-32s\n", $s4{$k}/$total*100,$s4{$k},$p1[0]); 
        foreach $k2 (sort { $s0{$b} <=> $s0{$a} } keys %s0) {
          @p2 = split ",",$k2;
          printf("\t\t %-4d  %-${saddr_len}s -> %-${daddr_len}s\n", $s0{$k2}, $p2[1],$p2[0]) if $p1[0] eq $p2[2];
        }
      }
    }
  }
}

# portscan (if enable -p switch)
# Please use '-A fast' to generate the log, so portscan() can process it.
# contributed by: Paul Bobby, <paul.bobby@lmco.com>
#                 Jian-Da Li, <jdli@freebsd.csie.nctu.edu.tw>
sub portscan {
  my (%s7, %s8);
  # to see how many times a host performs portscan
  # used in portscan()
  for $i (0 .. $#posres) {
    $s7{"$posres[$i]->[0]"}++;
  }
  if ($opt_h) {
    print "<h3><a name=\"portscan\">Portscans performed to/from HOME_NET</a></h3>\n";
    print "<table>\n";
    print "<tr><th>Scan Attempts</th><th>Source Address</th></tr>\n";
    foreach $k (sort { $s7{$b} <=> $s7{$a} } keys %s7) {
      print "<tr><td>$s7{$k}</td><td>$k</td></tr>\n" if $s7{$k} > $th;
    }
    print "</table><a href=\"#top\">Top</a><HR>\n";
  } else {
    section_header("Portscans performed to/from HOME_NET\n", "as");
    foreach $k ((sort { $s7{$b} <=> $s7{$a} } keys %s7)[0..$maxlines]) {
      printf(" %4d  %-${saddr_len}s\n", $s7{$k},$k) if $s7{$k} > $th;
    }
  }
}

# anomsensor (if enable -n switch)
# This function process data generated by spp_anomsensor plug-in (SPADE)
# By Yen-Ming Chen <chenym@alumni.cmu.edu>
sub anomsensor {
  my (%s7);
  # to see how many times a host performs portscan
  # used in anomsensor()
  for $i (0 .. $#anores) {
    $s7{"$anores[$i]->[1],$anores[$i]->[3],$anores[$i]->[4]"}++;
  }
  if ($opt_h) {
    print "<h3><a name=\"spade\">Anomaly detected by SPADE</a></h3>\n";
    print "<table>\n";
    print "<tr><th>Scan Attempts</th><th>Source Address</th><th>Destination Address</th><th>Destination Ports</th></tr>\n";
    foreach $k (sort { $s7{$b} <=> $s7{$a} } keys %s7) {
      @_ = split(/,/,$k);
      print "<tr><td>$s7{$k}</td><td>$_[0]</td><td>$_[1]</td><td>$_[2]</td></tr>\n" if $s7{$k} > $th;
    }
    print "</table><a href=\"#top\">Top</a><HR>\n";
  } else {
    section_header("Anomaly detected by SPADE\n", "asdo");
    foreach $k ((sort { $s7{$b} <=> $s7{$a} } keys %s7)[0..$maxlines]) {
      @_ = split(/,/,$k);
      printf("   %-4d   %-${saddr_len}s %-${daddr_len}s\t%-6d\n", $s7{$k},$_[0],$_[1],$_[2]) if $s7{$k} > $th;
    }
  }
}

# print the footer (needed for html)
sub print_footer {
  if ($opt_h) { 
    print "Generated by <a href=\"http://xanadu.incident.org/snort/\">snort_stat.pl</a>\n";
    print "</body>\n</html>\n";
  } 
}

#
# resolve host name and cache it
# contributed by: Angelos Karageorgiou, <angelos@stocktrade.gr>
# edited by: $Author: ssmeenk $
#
sub resolve {
  local ($mname, $miaddr, $mhost = shift);
  $miaddr = inet_aton($mhost);
  if (!$HOSTS{$mhost}) {
    $mname ="";
    eval {
      local $SIG{ALRM} = sub {die "alarm\n" }; # NB \n required
      alarm $timeout;
      $mname = gethostbyaddr($miaddr, AF_INET);
      alarm 0;
    };
    die if $@ && $@ ne "alarm\n"; # propagate errors
    if ($mname =~ /^$/) {
      $mname = $mhost;
    }
    $HOSTS{$mhost} = $mname;
  }
  return $HOSTS{$mhost};
}

# Use a title and a short code to write the section headers
# This is used in place of a FORMAT as this allows variable column widths
# contributed by: Ned Patterson, <jpatter@alum.mit.edu>
#
# Usage: section_header($title, $format);
# 
# Format: "pasdom"
#  p	percentage of events
#  a 	number of events
#  s	source host
#  d 	destination host
#  o	home net
#  m	method used
#
sub section_header {
  my $linelength;
  $title = shift; 
  $_ = shift;
  print("\n\n$title");
  # constant for method length for now
  $linelength = (/p/?7:0) +
		(/a/?20:0) +
		(/s/?$saddr_len:0) +
		(/d/?$daddr_len+3:0) +
		(/m/?20:0);
  print( '=' x $linelength, "\n");
  print("  %   ")                      if (s/^p([asdm]*)/$1/);
  print(" # of  ")                     if (s/^a([sdm]*)/$1/);
  printf("%-${saddr_len}s  ", "from")  if (s/^s([dm]*)/$1/);
  printf("%-${daddr_len}s  ", "to"  )  if (s/^d(m*)/$1/);
  printf("%-5s   ", "ports"  )         if (s/^o(m*)/$1/);
  print("method")                      if (/^m/);
  print("\n");
  
  print( '=' x $linelength, "\n");
}

# Put data $alert into matrix for further process
# INPUT: $alert
sub process_data() {
  $self = shift;
  # if the resolve switch is on
  if ($opt_r) {
    $self->{SADDR} = resolve($self->{SADDR});
    unless ($opt_f) {
      if ( length($self->{SADDR}) > $saddr_len ) {
	$saddr_len = length($self->{SADDR});
      }
    }
    $self->{DADDR} = resolve($self->{DADDR});
    unless ($opt_f) {
      if ( length($self->{DADDR}) > $daddr_len ) {
	$daddr_len = length($self->{DADDR});
      }
    }
  }
  # put those data into a big matrix
  if ($self->{PLUGIN} eq "anomsensor") {
    push @anores , [$self->{THR},$self->{SADDR},$self->{SPORT},
                    $self->{DADDR},$self->{DPORT}];
    $opt_n = 1;
  } elsif ($self->{PLUGIN} eq "portscan") {
    push @posres , [$self->{SADDR}];
    $opt_p = 1;
  } elsif ($self->{TYPE} eq "sys" || $self->{TYPE} eq "alert" || 
	   $self->{PLUGIN} eq "stream" || $self->{PLUGIN} eq "bo" ) {
    $self->{SIG} =~ s/\:$//o;
    push @result ,[$self->{MON},$self->{DAY},$self->{HOUR},$self->{MIN},
                   $self->{SEC},$self->{HOST},$self->{SIG},$self->{SADDR},
                   $self->{SPORT},$self->{DADDR},$self->{DPORT}];
    $lastwassnort = 1;
  } else {
    print STDERR "Unknown alert type/plugin! $self->{TYPE}:$self->{PLUGIN} Skipped!\n";
    return;
  }
  1;
}

# Turn IDS into the link to whitehats
sub printHref
{
  my $type = $_[0];

  if ($type =~ /\A\s*(IDS\d+)\//) 
    {
      return "<a href=\"http://www.whitehats.com/info/$1\" 
            target=\"_blank\">$type</a>";
    }
  return $type;
}
