#!/usr/bin/perl
#
# This is the Solaris log parser version 1.0
# 7/15/01  Stan Sander <stsander@earthlink.net>
# The script will take a line in a file generated via syslog (shown in the
# sample below), convert it to DSHIELD format, and mail it to dshield.
# If you use this on a Solaris 7 or older system, you 
# will likely have to adjust the path to perl above.
# If anyone finds this script to be useful, I'm happy to provide it under
# the GNU GPL.  If you would like to send suggestions for improvement, I'm 
# ready to listen.  My e-mail address is above.  
# Version 1.1 8/17/02 added support for log lines that report packet counts 
# greater than 1.  This is also shown in the sample below.  Also I prettied
# up the code a bit. :-)
#
#################################################################################   Solaris ipmon via syslog sample,
#
# May 26 18:58:11 server ipmon[7552]: [ID 702911 local0.warning] 18:58:11.269602 2x ppp0 @0:23 b 211.226.239.2,1580 -> 206.133.143.189,53 PR tcp len 20 15360 -S IN
################################################################################
use strict;
require 5.005;
use Date::Manip qw(ParseDate UnixDate);
use Mail::Mailer;
#############################################################################
#                                                                           #
#  USER CONFIGURATIONS BELOW                                                #
#                                                                           #
#############################################################################
# Change the file variable to the file that needs parsed. 

my $file = "/var/adm/messages.0"; 

# Set this to your DSHIELD user ID or leave at the default of 0 for anonymous.

my $dshield_id = 0;

# set up mailing information.  Addresses are in the form of 
# '<address@domain.com>' Multiple recipients can be included
# in a comma seperated list like
# '<reports@dshield.org>,<dshield@your.domain>'

my $fromaddress = '<address@domain.com>';  # put your e-mail here
my $recipient = '<reports@dshield.org>';
##############################################################################
#                                                                            #
# There shouldn't be anything below here that you should have to tweak unless#
# you are outside the US or parsing a really old file.                       #
#                                                                            #
#    END OF USER CONFIGURATIONS                                              #
#                                                                            #
##############################################################################
# Declare the rest of the variables and arrays.
my $count = 1;
my $input = "";
my @line = ();
my $month = "";
my $day = "";
my $time = "";
my $year = ((localtime)[5] + 1900);
my $lastyear = "";
my $date = "";
my $datestr = "";
my $processid =  "";
my @process = ();
my $action = "";
my $rawsource = "";
my @source = ();
my $sourceip = "";
my $sourceport = 0;
my $rawtarget = "";
my @target = ();
my $targetip = "";
my $targetport = 0;
my $protocol = "";
my $flags = "";
my $now = (localtime);  # needed for dshield subject line, this should also
my $tz = UnixDate($now, "%z");  # make us daylight savings aware
my $mailer = Mail::Mailer->new("sendmail");

# Open file and read one line at a time, and open up mailer

open(SYSLOG, "<$file") or die "Can't open $file for reading:  $!\n";
$mailer->open({ Sender => $fromaddress,
		From  => $fromaddress,
		To    => $recipient,
		Subject => "FORMAT DSHIELD USERID $dshield_id TZ $tz",
	}) or die "Problem opening mail handler:  $!\n";
until(eof(SYSLOG)){
	$input = <SYSLOG>;

# Read each field in the input line into an array, 
# and assign variable names to the values we want to use

	@line = split /\s+/, $input;
	$month = $line[0];
	$day = $line[1];
	$time = $line[2];
#
# Do date conversion and get time zone from system.  Hopefully this 
# will handle Dec 31 -> Jan 1 transitions correctly.  I do make an 
# assumption here that you are using data that otherwise is in the 
# current year.  If you aren't, then you'll have to change this section.
# The lines in the test for the if statement will need adjustment if
# your system is outside the US.  The other functions should be 
# aware of your locale.
#
	if ($month eq 'Dec' && (localtime)[4] eq '0'){
		$lastyear = $year - 1;
		$date = ParseDate("$month $day $time $lastyear");
		$datestr = UnixDate($date, "%Y-%m-%d %H:%M:%S %z");
	} else {
		$date = ParseDate("$month $day $time $year");
		$datestr = UnixDate($date, "%Y-%m-%d %H:%M:%S %z");
	};
	
	$processid = $line[4];
# move on if there is a short line in the log
	if (!defined $processid){ next; };
	@process = split /\[/, $processid;
# discard line if not generated by ipmon
	if ($process[0] ne 'ipmon'){ next; };
        if($line[9] =~ /x/){  # multiple packets reported on this line
                $line[9] =~ s/x//, $line[9];
                $count = $line[9];
                $action = $line[12];
# discard line if the packet was passed
                if ($action ne 'b'){ next; };
                $rawsource = $line[13];
                $rawtarget = $line[15];
                $protocol = $line[17];
                if ($protocol eq 'icmp') {
                        $flags = $line[22];
                } else {
                        $flags = $line[21];
                };
        } else { # only 1 packet reported on this line
                $count = 1;
                $action = $line[11];
                if ($action ne 'b'){ next; };
                $rawsource = $line[12];
                $rawtarget = $line[14];
                $protocol = $line[16];
                if ($protocol eq 'icmp'){
                        $flags = $line[21];
                } else {
                        $flags = $line[20];
                };
        };
# Take the leading - off of the flags variable since we won't need it.
        $flags =~ s/-//, $flags;
	if ($protocol eq 'icmp'){
		next;  # discard icmp packets that were logged
	};	       # at least for now.  
#
# Discard lines that are from packets that were blocked because of the slow
# link or some other delay while enroute.  Also UDP packets don't have flags
# so we need to set the flags variable to an empty string for that.
# I have these defined because ipf can be rather "chatty" with these on a 
# slow link and I'm on a 56K dialup.
#
	if ($protocol eq 'udp'){ $flags = ""; };
	if ($flags eq 'AP'){ next; };
	if ($flags eq 'AF'){ next; };
	if ($flags eq 'A'){ next; };
	if ($flags eq 'AFP'){ next; };
	if ($flags eq 'R'){ next; };
	if ($flags eq 'AR'){ next; };
	if ($flags eq 'AS'){ next; };
# Now we have to split the IP and port into separate variables
	@source = split /,/, $rawsource;
	$sourceip = $source[0];
	$sourceport = $source[1];
	@target = split /,/, $rawtarget;
	$targetip = $target[0];
	$targetport = $target[1];
	print $mailer "$datestr\t$dshield_id\t$count\t$sourceip\t$sourceport\t$targetip\t$targetport\t\U$protocol\t$flags\n";
};
close SYSLOG or warn "Problem closing $file :  $!\n";
$mailer->close();
exit;

