#!/usr/bin/perl -w # # $Revision: 2.4 $ $Date: 2010-12-17 19:30:15-05 $ # $Source: /usr/local/src/c/checksyslog/src/RCS/checksyslog,v $ # $UUID: 4e28398a-8082-3651-a618-7fe488d8ba1b $ # # checksyslog - a program to extract abnormal entries from a system log # # author: James W. Abendschan # license: GPL - http://www.gnu.org/copyleft/gpl.html # url: http://www.jammed.com/~jwa/hacks/security/checksyslog/ # # Original-Id: checksyslog,v 1.3 2001/05/04 10:07:42 jwa Exp use strict; use POSIX qw(strftime); select(STDOUT); $| = 1; # parse arguments my $constant = 0; my $verbose = 0; my $filter = ""; my ($log, $rules); while (my $arg = shift @ARGV) { $log = shift @ARGV if ($arg =~ /^-l$|^--log$/); if ($arg =~ /^-t$|^--today$/) { $filter = strftime("%b %e", localtime(time())); } $filter = shift @ARGV if ($arg =~ /^-f$|^--filter$/); $rules = shift @ARGV if ($arg =~ /^-r$|^--rules$/); $constant = 1 if ($arg =~ /^-c$|^--constant$/); $verbose = 1 if ($arg =~ /^-v$|^--verbose$/); } usage() if ($rules eq ""); # suck in the rulefile my $rfh; open($rfh, "< $rules") || die "rule file $rules: $!\n"; my @lines = <$rfh>; close($rfh); # preprocess to remove comments & expand % definitions my $defS = 1; my ($k, $v, @v); # for lines holding "$VAR=something" my %defH = (); # hash holding definitions my $line; my @rules = (); while ($line = shift @lines) { $line =~ s/\r|\n//g; next if (($line =~ /^$/) || ($line =~ /^#/)); $defS = 0 if ($line !~ /^\%/); # end definition state $rules .= $line . "\n"; if ($defS) { ($k, @v) = split(/=/, $line); $v = join("=", @v); $defH{$k} = $v; print "$k = $defH{$k}\n" if ($verbose); } else { my @k = keys %defH; while ($k = shift @k) { if ($line =~ /${k}/) { $line =~ s/$k/$defH{$k}/g; } } push(@rules, $line); } } # now build the moby regexp my $rulecount = 0; my $rulez = ""; while ($line = shift @rules) { if (($line !~ /^$/) && ($line !~ /^#/) && ($line ne " ")) { # validate RE. perl will barf here if it's bad. eval { qr/$line/; }; if ($@) { die "[$line]: invalid RE: $!\n"; } $rulecount++; $line = $defH{"%PREPEND"} . $line; $rulez = "$rulez|$line" if ($rulez ne ""); $rulez = "$line" if ($rulez eq ""); print "Added rule: [$line]\n" if ($verbose); } } print "Read $rulecount rules\n" if ($verbose); # Do it. my $lfh; if ($constant) { # tail -f open($lfh, "< $log") || die "can't open $log: $!"; my $curpos; while (1) { for ($curpos = tell($lfh) ; $line = <$lfh> ; $curpos = tell($lfh)) { print $line if ( (($filter eq "") || ($line =~ /$filter/)) && ($line !~ /$rulez/)); } sleep 3; seek($lfh, $curpos, 0); } } # Read a logfile or STDIN. if (defined($log)) { open($lfh, "< $log") || die "can't open $log: $!"; } else { open($lfh, "-") || die "can't open STDIN: $!"; warn "Reading from stdin\n"; } while ($line = <$lfh>) { print $line if ( (($filter eq "") || ($line =~ /$filter/o)) && ($line !~ /$rulez/o)); } close($lfh); exit(0); # ------------------------------------------------------------------------- sub usage { print <<_EOF_; usage: $0 --rules rulefile [--log path to syslog] [--today] [--filter filter] IE: $0 --rules /usr/local/lib/checksyslog.rules \\ --log /var/log/syslog --today A rulefile must be specified. With no --log option, input is taken from stdin. _EOF_ exit(1); }