#!/usr/bin/perl # # This is the Solaris log parser version 1.0 # 7/15/01 Stan Sander # 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 # '' Multiple recipients can be included # in a comma seperated list like # ',' my $fromaddress = ''; # put your e-mail here my $recipient = ''; ############################################################################## # # # 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 = ; # 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;