#! /usr/bin/perl # # 2002-09-03 - Reported wrong month # 2002-08-22 - try to get name of each host (in case of -r) # 2002-08-20 - initial version # # WG-Dshield by Hans Sandsdalen, Kongsberg Spacetec # hans@spacetec.no # # The script will read all logentries from today and produce output in # Dshield-format. # See http://www.dshield.org/specs.php#dshield_format # # It is intended to be run once a day, just before midnight. I have a # cron-job like # # 59 23 * * * WG-Dshield | mail -s "FORMAT DSHIELD USERID 0 TZ +01:00" report@dshield.org # # (WG-Shield will run 23:59 every day, sending output to report@dshield.org) # # Syntax: WG-Dshield [-d] [-r] # -d - debug # -r - the script will write a list of hosts which are denied to stderr, # sorted on number of log entries. Since it is writen to stderr # there is no problem using it in a cron job (the list will not # be mailed to dshield in the example above). # # # # Dshield.awk written by Peter Feltham, Intelligent Organisations # (Email: peter@intelligentorgs.com) is used as a base # # $logfile is the logfile on the unix host. # Setup in Watchguard: # - Open Policy Manager # - Setup/Logging/syslog # - Enter your host # # ---------------------------------------------------------------------- use Socket; # Values to be changed? # UserID and TimeZone, see http://www.dshield.org/specs.php#dshield_format $logfile = "/var/log/firewall/firewall"; $UserID = 23874654; $TimeZone = "+01:00"; # No need to change below (?) # ---------------------------------------------------------------------- require "getopts.pl"; sub basename { # returns only filename &ENTER("basename(@_)"); local($basename) = @_; $basename =~ s#.*/##; $basename; &LEAVE("basename(), returns $basename\n"); $basename; } sub settime { ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time); $mon = $mon + 1; # $mon is 0..11 $sec = substr("0" . $sec, length("0" . $sec )-2 ,2); $min = substr("0" . $min, length("0" . $min )-2 ,2); $hour = substr("0" . $hour, length("0" . $hour)-2 ,2); $mday = substr("0" . $mday, length("0" . $mday)-2 ,2); $mon = substr("0" . $mon, length("0" . $mon )-2 ,2); $year = substr("0" . $year, length("0" . $year)-2 ,2); } sub debug { if ( $opt_d ) { &settime; print "$hour:$min:$sec " . $Dindent . $myname . " DEBUG: @_\n"; } } sub errmsg { die $myname . " ERROR: @_\n"; } sub msg { print $myname . ": @_\n"; } sub ENTER { &debug("ENTER: @_"); $Dindent = $Dintdent . " "; } sub LEAVE { $Dindent = substr($Dindent,3); &debug("LEAVE: @_"); } sub setdate { &ENTER ("setdate @_"); @month_names = ("Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"); &settime; $Oyear = 2000 + $year; $Omon = $mon; $Omday = $mday; $monName = $month_names[$Omon - 1]; $Odate = "$Oyear-$Omon-$Omday"; &LEAVE ("setdate $Odate $monName"); } sub printline { # print one line. If lTime/lRepeats are given, use values from last line &ENTER("printline @_"); local($lTime, $lRepeats) = @_; &debug("lTime=$lTime, lRepeats=$lRepeats"); $line =~ s/ +/ /g; @words = split (/ /,$line); local($count) = 1; # default count local($Time) = $words[2]; # default time if ( $lTime != "" ) { $Time = $lTime; if ( $lRepeats != "") { $count = $lRepeats; } } &debug("words[16]=$words[16], words[17]=$words[17]"); print "$Odate " . # date "$Time " . # hh:mm:ss "$TimeZone " . # timezone "$UserID\t" . # UserID "$count\t" . # count "$words[12]\t" . # Source IP address "$words[14]\t" . # Source port "$words[13]\t" . # Target IP address "$words[15]\t" . # Target port "$words[9]\t" # protocol ; # if ( $words[16] !~ /^\(.*\)$/ ) { if ( $words[16] !~ /^\(/ ) { # if $words[16] do not start with "(" # this is a TCP flag print "$words[16]"; } # end with a newline print "\n"; &debug("Before: DeniedHost{$words[12]}=$DeniedHost{$words[12]}"); if ( $DeniedHost{$words[12]} ne "") { $DeniedHost{$words[12]} += $count; } else { $DeniedHost{$words[12]} = $count; } &debug("After: DeniedHost{$words[12]}=$DeniedHost{$words[12]}"); &LEAVE("printline"); } sub by_reversed_count { if ( $DeniedHost{$a} < $DeniedHost{$b} ) { 1; } elsif ( $DeniedHost{$a} == $DeniedHost{$b}) { 0; } elsif ( $DeniedHost{$a} > $DeniedHost{$b} ) { -1; } } sub GetHostByAddr { &ENTER("GetHostByAddr(@_)"); local($laddr) = @_; local($liaddr) = inet_aton($laddr); local($lhostname) = gethostbyaddr($liaddr,AF_INET); &LEAVE("GetHostByAddr, return $lhostname"); $lhostname; } ############################################################################ &Getopts("dr"); $myname = &basename(__FILE__); undef %DeniedHost; &setdate; # remove leading 0 from $Omday $O2mday = $Omday + 0; $lineno = 0; open (LOG, $logfile) || die ("Could not open $logfile"); while ($inpline = ) { $lineno += 1; chop ($inpline); # &debug ("Read line #$lineno:" . $inpline); if ( $inpline !~ /^$monName *$O2mday/ ) { &debug("$lineno next1: wrong date (" . substr($inpline,0,22) . "...)"); next; } &debug("ok date"); if ( $inpline !~ /last message repeated/ ) { # this is not a repeated line $line = $inpline; # assume that this line should not be printed $printline = 0; if ( $line !~ /deny in/ ) { &debug ("$lineno next2: no \"deny in\" ($line)"); next; } &debug ("WITH \"deny in\""); # from Dshield.awk: # This first set of patterns look for miscellaneous crud coming # off the Firewall, which should not be reported to Dshield, # so if we find such a line, just ignore it. These little parsers # speed up processing - no need to parse crud after all... # if ( $line =~ /unexpextedly/ || $line =~ /are exiting/ || $line =~ /signal 2/ || $line =~ /Can't receive data from server/ || $line =~ /exited with status 1/ || $line =~ /Connection terminated/ || $line =~ /proxy connect failed/ ) { &debug ("$lineno next3: ignore ($line)"); next; } # from Dshield.awk: # Here are some more throwaways, with lots of data fields # none of which is interesting for dShield # These are belts-and-braces backstops, in fact! # Protocol and Proxy dependent: # if ( $line =~ /process_rfds:/ || $line =~ /Message has too much data/ || $line =~ /arp called for own IP/ || $line =~ /terminating session/ || $line =~ /proxy bind/ || $line =~ /server timed out/ || $line =~ /process_stop_request:/ || $line =~ /Exit./ ) { &debug ("$lineno next4: ignore ($line)"); next; } &debug("$lineno report!"); $printline = 1; &printline; } elsif ( $printline ) { # last line was printed, and is repeated. &debug("Previous line: $line"); &debug("REPEAT! $inpline"); # find number of repeats and time $inpline =~ s/ +/ /g; ($w1, $w2, $inpTime, $w4, $w5, $w6, $w7, $number) = split (/ /,$inpline); &debug("Time: $inpTime, # Repeats: $number"); &printline($inpTime, $number); } } close (LOG); if ( $opt_r ) { # print a sorted list of denied hosts to stderr @sortedkeys = sort by_reversed_count keys(%DeniedHost); foreach $host (@sortedkeys) { print stderr "$host\t$DeniedHost{$host}\t" . &GetHostByAddr($host) ."\n"; } }