#/usr/bin/perl -wT use 5.006; use strict; use warnings; use HTTPD::ADS; use IO::Socket::UNIX; use HTTPD::Log::Filter; use Compress::Zlib; #do not run this as root, I specifically split root-privileged code into another module. #you MUST run this as your Postgresql database username BEGIN { use CGI::Carp qw(cluck carpout); my $logfile="/tmp/LogReader.log"; die "cannot open log file $logfile for write" if (-e $logfile && ! (-w $logfile)); open(LOG, ">>$logfile") or die "carp could not open log"; carpout(\*LOG); } our $VERSION = '0.02'; #daemon process waits for events to come in, then puts them in database and analyzes and takes action my $IDSDatabase="wwwads"; my $IDSDataUser=""; my $IDSDataPassword=""; my $line; my $gz; my $loopcount; my $bytesread; my $rv; my %args; my $apacheids = HTTPD::ADS->new ( IDSDataUser => $IDSDataUser, IDSDataPassword => $IDSDataPassword, IDSDatabase => $IDSDatabase, IDSTimeWindowSize => 7801920 ); my $logfilter= HTTPD::Log::Filter->new( format => 'ELF', capture => [ qw( host ident authexclude date request status bytes referer agent )]); my $linenumber=0; my $filename; #foreach $loopcount ('33'..'86') { # $filename = "/var/log/httpd/inside.slavelucy.com-access_log.$loopcount.gz"; foreach $loopcount ('1'..'15') { $filename = "/var/log/httpd/www.maturebelles.com-access_log.$loopcount".($loopcount > 1?".gz":""); $gz = gzopen($filename, "rb") || die "could not open log file"; print "$linenumber lines\n"; print "process $filename\n "; for ($bytesread=$gz->gzreadline($line),$linenumber=0; $bytesread > 0; $bytesread=$gz->gzreadline($line),$linenumber++) { $rv=$logfilter->filter($line); if (!defined $rv) { my $time = scalar localtime; carp "$time: Invalid log format in $filename at line $linenumber $! \n"; next ; } #1st is to put the event in the database. # then can decide what to do about it. # One may think access to protected page w/o specifying username is innocent. Maybe. but it could # be that someone trys and then failing to get in launches a brute force attack. So while blank # username on its own might be innocent it could be counted with failed login attempts # as grounds for "termination with extreme prejuidice" of some hacker # or blackholing his ip anyway. But you need data on which to make a decision. next unless ($logfilter->status >= 400 && $logfilter->status < 500); $apacheids->event_recorder( # ip => gethostbyname($logfilter->host), ip => $logfilter->host, request => $logfilter->request, status =>$logfilter->status, referer =>$logfilter->referer, user =>$logfilter->authexclude, time =>$logfilter->date ); print "$linenumber completed\r"; } ; } 1; __END__ =head1 AUTHOR Dana Hudes, Edhudes@networkengineer.bizE =head1 SEE ALSO L. =cut