Files
bpfire/html/cgi-bin/logs.cgi/firewalllog.dat
Michael Tremer 00793c27c9 GeoIP: Add lookup function for convenience
Instead of opening the database again for each lookup,
we will read it into memory on first use and every lookup
after that will be coming from cache.

Reviewed-by: Peter Müller <peter.mueller@link38.eu>
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
2017-11-13 22:37:19 +00:00

447 lines
13 KiB
Perl

#!/usr/bin/perl
#
# SmoothWall CGIs
#
# This code is distributed under the terms of the GPL
#
# (c) The SmoothWall Team
#
# $Id: firewalllog.dat,v 1.4.2.18 2005/08/23 12:01:50 eoberlander Exp $
#
# July 28, 2003 - Darren Critchley - darren@kdi.ca
# - added source mac adapter to layout
#
use strict;
use Getopt::Std;
# enable only the following on debugging purpose
#use warnings;
#use CGI::Carp 'fatalsToBrowser';
require '/var/ipfire/general-functions.pl';
require "${General::swroot}/geoip-functions.pl";
require "${General::swroot}/lang.pl";
require "${General::swroot}/header.pl";
my %color = ();
my %mainsettings = ();
&General::readhash("${General::swroot}/main/settings", \%mainsettings);
&General::readhash("/srv/web/ipfire/html/themes/".$mainsettings{'THEME'}."/include/colors.txt", \%color);
use POSIX();
#workaround to suppress a warning when a variable is used only once
my @dummy = ( ${Header::table2colour} );
undef (@dummy);
my %cgiparams=();
my %logsettings=();
my $errormessage = '';
my @shortmonths = ( 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug',
'Sep', 'Oct', 'Nov', 'Dec' );
my @longmonths = ( $Lang::tr{'january'}, $Lang::tr{'february'}, $Lang::tr{'march'},
$Lang::tr{'april'}, $Lang::tr{'may'}, $Lang::tr{'june'}, $Lang::tr{'july'}, $Lang::tr{'august'},
$Lang::tr{'september'}, $Lang::tr{'october'}, $Lang::tr{'november'},
$Lang::tr{'december'} );
my @now = localtime();
my $dow = $now[6];
my $doy = $now[7];
my $tdoy = $now[7];
my $year = $now[5]+1900;
$cgiparams{'DAY'} = $now[3];
$cgiparams{'MONTH'} = $now[4];
$cgiparams{'ACTION'} = '';
&Header::getcgihash(\%cgiparams);
$logsettings{'LOGVIEW_REVERSE'} = 'off';
&General::readhash("${General::swroot}/logging/settings", \%logsettings);
${Header::viewsize} = defined ($logsettings{'LOGVIEW_VIEWSIZE'}) ? $logsettings{'LOGVIEW_VIEWSIZE'} : 150;
my $start = ($logsettings{'LOGVIEW_REVERSE'} eq 'on') ? 0x7FFFF000 : 0; #index of firts line number to display
if ($ENV{'QUERY_STRING'} && $cgiparams{'ACTION'} ne $Lang::tr{'update'})
{
my @temp = split(',',$ENV{'QUERY_STRING'});
$start = $temp[0];
$cgiparams{'MONTH'} = $temp[1];
$cgiparams{'DAY'} = $temp[2];
}
if (!($cgiparams{'MONTH'} =~ /^(0|1|2|3|4|5|6|7|8|9|10|11)$/) ||
!($cgiparams{'DAY'} =~ /^(0|1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16|17|18|19|20|21|22|23|24|25|26|27|28|29|30|31)$/))
{
$cgiparams{'DAY'} = $now[3];
$cgiparams{'MONTH'} = $now[4];
}
elsif($cgiparams{'ACTION'} eq '>>')
{
my @temp_then=();
my @temp_now = localtime(time);
$temp_now[4] = $cgiparams{'MONTH'};
$temp_now[3] = $cgiparams{'DAY'};
if ($cgiparams{'DAY'}) {
@temp_then = localtime(POSIX::mktime(@temp_now) + 86400);
## Retrieve the same time on the next day +
## 86400 seconds in a day
} else {
$temp_now[3] = 1;
$temp_now[4] = ($temp_now[4]+1) %12;
@temp_then = localtime(POSIX::mktime(@temp_now) );
$temp_then[3] = 0;
}
$cgiparams{'MONTH'} = $temp_then[4];
$cgiparams{'DAY'} = $temp_then[3];
}
elsif($cgiparams{'ACTION'} eq '<<')
{
my @temp_then=();
my @temp_now = localtime(time);
$temp_now[4] = $cgiparams{'MONTH'};
$temp_now[3] = $cgiparams{'DAY'};
if ($cgiparams{'DAY'}) {
@temp_then = localtime(POSIX::mktime(@temp_now) - 86400);
## Retrieve the same time on the next day -
## 86400 seconds in a day
} else {
$temp_now[3] = 1;
$temp_now[4] = ($temp_now[4]-1) %12;
@temp_then = localtime(POSIX::mktime(@temp_now) );
$temp_then[3] = 0;
}
$cgiparams{'MONTH'} = $temp_then[4];
$cgiparams{'DAY'} = $temp_then[3];
}
# Find in which file.gz is the log. Can be calculated because WEEKLY ROTATING of access.log
my $gzindex;
my $date = $cgiparams{'DAY'} == 0 ? '' : $cgiparams{'DAY'} <= 9 ? "0$cgiparams{'DAY'}" : "$cgiparams{'DAY'}";
{
my $xday;
# Calculate time. If future date, calculate for past year !!!
if (( $cgiparams{'MONTH'} eq $now[4]) && ($cgiparams{'DAY'} > $now[3]) ||
( $cgiparams{'MONTH'} > $now[4] ) ) {
$xday = POSIX::mktime( 0, 0, 0, $cgiparams{'DAY'}, $cgiparams{'MONTH'}, $year - 1901 );
$date = "$longmonths[$cgiparams{'MONTH'}] $date, ". int($year-1);
} else {
$xday = POSIX::mktime( 0, 0, 0, $cgiparams{'DAY'}, $cgiparams{'MONTH'}, $year - 1900 );
$date = "$longmonths[$cgiparams{'MONTH'}] $date, $year";
}
# calculate end of active week (saturday 23H59)
my @then = ();
@then = localtime(time());
my $sunday = POSIX::mktime( 0, 0, 0, @then[3], @then[4], @then[5]);
$sunday += (6-$then[6]) * 86400;
# Convert delta in second to full weeks
$gzindex = int (($sunday-$xday)/604800 );
}
my $monthstr = $shortmonths[$cgiparams{'MONTH'}];
my $daystr = $cgiparams{'DAY'} == 0 ? '..' : $cgiparams{'DAY'} <= 9 ? " $cgiparams{'DAY'}" : "$cgiparams{'DAY'}";
my $lines = 0;
my @log=();
my $loop = 1;
my $filestr = 0;
my $lastdatetime; # for debug
my $search_for_end = 0;
while ($gzindex >=0 && $loop) {
# calculate file name
if ($gzindex == 0) {
$filestr = "/var/log/messages";
} else {
$filestr = "/var/log/messages.$gzindex";
$filestr = "$filestr.gz" if -f "$filestr.gz";
}
# now read file if existing
if (open (FILE,($filestr =~ /.gz$/ ? "gzip -dc $filestr |" : $filestr))) {
#&General::log("reading $filestr");
READ:while (<FILE>) {
my $line = $_;
if ($line =~ /^${monthstr} ${daystr} ..:..:.. [\w\-]+ kernel:.*IN=.*$/) {
# when standart viewing, just keep in memory the correct slice
# it starts a '$start' and size is $viewport
# If export, then keep all lines...
if ($cgiparams{'ACTION'} eq $Lang::tr{'export'}){
$log[$lines++] = "$line";
} else {
if ($lines++ < ($start + $Header::viewsize)) {
push(@log,"$line");
if (@log > $Header::viewsize) {
shift (@log);
}
#} else { dont do this optimisation, need to count lines !
# $datetime = $maxtime; # we have read viewsize lines, stop main loop
# last READ; # exit read file
}
}
$search_for_end = 1; # we find the start of slice, can look for end now
} else {
if ($search_for_end == 1) {
#finish read files when date is over (test month equality only)
$line =~ /^(...) (..) ..:..:..*$/;
$loop = 0 if ( ($1 ne $monthstr) || ( ($daystr ne '..') && ($daystr ne $2) ) );
}
}
}
close (FILE);
}
$gzindex--; # will try next gz file eg 40,39,38,.... because it may have holes when ipcop stopped
# for a long time
}# while
# $errormessage = "$Lang::tr{'date not in logs'}: $filestr $Lang::tr{'could not be opened'}";
if ($cgiparams{'ACTION'} eq $Lang::tr{'export'})
{
print "Content-type: text/plain\n\n";
print "IPFire firewall log\r\n";
print "$Lang::{'date'}: $date\r\n\r\n";
if ($logsettings{'LOGVIEW_REVERSE'} eq 'on') { @log = reverse @log; }
foreach $_ (@log)
{
/^... (..) (..:..:..) [\w\-]+ kernel:.*(IN=.*)$/;
my $day = $1;
$day =~ tr / /0/;
my $time = $cgiparams{'DAY'} ? "$2" : "$day/$2" ;
print "$time $3\r\n";
}
exit 0;
}
&Header::showhttpheaders();
&Header::openpage($Lang::tr{'firewall log'}, 1, '');
&Header::openbigbox('100%', 'left', '', $errormessage);
if ($errormessage) {
&Header::openbox('100%', 'left', $Lang::tr{'error messages'});
print "<font class='base'>$errormessage&nbsp;</font>\n";
&Header::closebox();
}
&Header::openbox('100%', 'left', "$Lang::tr{'settings'}");
print <<END
<form method='post' action='$ENV{'SCRIPT_NAME'}'>
<table width='100%'>
<tr>
<td width='10%' class='base'>$Lang::tr{'month'}:&nbsp;</td>
<td width='10%'>
<select name='MONTH'>
END
;
for (my $month = 0; $month < 12; $month++)
{
print "\t<option ";
if ($month == $cgiparams{'MONTH'}) {
print "selected='selected' ";
}
print "value='$month'>$longmonths[$month]</option>\n";
}
print <<END
</select>
</td>
<td width='10%' class='base' align='right'>&nbsp;$Lang::tr{'day'}:&nbsp;</td>
<td width='40%'>
<select name='DAY'>
END
;
print "<option value='0'>$Lang::tr{'all'}</option>\n";
for (my $day = 1; $day <= 31; $day++)
{
print "\t<option ";
if ($day == $cgiparams{'DAY'}) {
print "selected='selected' ";
}
print "value='$day'>$day</option>\n";
}
print <<END
</select>
</td>
<td width='5%' align='center'><input type='submit' name='ACTION' title='$Lang::tr{'day before'}' value='&lt;&lt;' /></td>
<td width='5%' align='center'><input type='submit' name='ACTION' title='$Lang::tr{'day after'}' value='&gt;&gt;' /></td>
<td width='10%' align='center'><input type='submit' name='ACTION' value='$Lang::tr{'update'}' /></td>
<td width='10%' align='center'><input type='submit' name='ACTION' value='$Lang::tr{'export'}' /></td>
</tr>
</table>
</form>
END
;
&Header::closebox();
&Header::openbox('100%', 'left', $Lang::tr{'log'});
print "<p><b>$Lang::tr{'firewall hits'} $date: $lines</b></p>";
my $lastPageIndex = $lines - ${Header::viewsize};
$start = $lastPageIndex if ($start >= $lastPageIndex);
$start = 0 if ($start < 0);
my $prev;
if ($start == 0) {
$prev = -1;
} else {
$prev = $start - ${Header::viewsize};
$prev = 0 if ( $prev < 0);
}
my $next;
if ($start == $lastPageIndex) {
$next = -1;
} else {
$next = $start + ${Header::viewsize};
$next = $lines - ${Header::viewsize} if ($next >= $lines - ${Header::viewsize});
}
if ($logsettings{'LOGVIEW_REVERSE'} eq 'on') { @log = reverse @log; }
if ($lines != 0) { &oldernewer(); }
print <<END
<table width='100%' class='tbl'>
<tr>
<th align='center' class='boldbase'><b>$Lang::tr{'time'}</b></th>
<th align='center' class='boldbase'><b>$Lang::tr{'chain'}</b></th>
<th align='center' class='boldbase'><b>$Lang::tr{'iface'}</b></th>
<th align='center' class='boldbase'><b>$Lang::tr{'proto'}</b></th>
<th align='center' class='boldbase'><b>$Lang::tr{'source'}<br/>$Lang::tr{'destination'}</b></th>
<th align='center' class='boldbase'><b>$Lang::tr{'src port'}<br />$Lang::tr{'dst port'}</b></th>
<th align='center' class='boldbase'><b>$Lang::tr{'country'}</b></th>
<th align='center' class='boldbase'><b>$Lang::tr{'mac address'}</b></th>
</tr>
END
;
$lines = 0;
foreach $_ (@log)
{
# If ipv6 uses a bridge, PHYSIN= contains the relevant iface information
# otherwise use IN=
my $packet = '';
if ($_ =~ /^... (..) (..:..:..) [\w\-]+ kernel:(.*)(IN=.*)(PHYSIN=.*)$/) { $packet = $5; }
elsif ($_ =~ /^... (..) (..:..:..) [\w\-]+ kernel:(.*)(IN=.*)$/) { $packet = $4; }
my $day = $1;
$day =~ tr / /0/;
my $time = $cgiparams{'DAY'} ? "$2" : "$day/$2" ;
my $chain = $3;
my ($iface, $srcaddr, $dstaddr, $macaddr, $proto, $srcport, $dstport);
if ($packet =~ /PHYSIN=(\w+)/) { $iface=$1; } elsif ($packet =~ /IN=(\w+)/) { $iface = $1; }
# Identify whether ipv4 or ipv6. Both are mutally exclusive.
if ($packet =~ /SRC\=(([\d]{1,3})(\.([\d]{1,3})){3})/) { $srcaddr=$1; }
if ($packet =~ /SRC\=(([0-9a-fA-F]{0,4})(\:([0-9a-fA-F]{0,4})){2,7})/) { $srcaddr=$1; }
if ($packet =~ /DST\=(([\d]{1,3})(\.([\d]{1,3})){3})/) { $dstaddr=$1; }
if ($packet =~ /DST\=(([0-9a-fA-F]{0,4})(\:([0-9a-fA-F]{0,4})){2,7})/) { $dstaddr=$1; }
$macaddr=$1 if $packet =~ /MAC=([\w+\:]+)/;
$proto=$1 if $packet =~ /PROTO=(\w+)/;
$srcport=$1 if $packet =~ /SPT=(\d+)/;
$dstport=$1 if $packet =~ /DPT=(\d+)/;
my $ccode = &GeoIP::lookup($srcaddr);
my $servi = uc(getservbyport($srcport, lc($proto)));
if ($servi ne '' && $srcport < 1024) {
$srcport = "$srcport($servi)";
}
$servi = uc(getservbyport($dstport, lc($proto)));
if ($servi ne '' && $dstport < 1024) {
$dstport = "$dstport($servi)";
}
my @mactemp = split(/:/,$macaddr);
$macaddr = "$mactemp[6]:$mactemp[7]:$mactemp[8]:$mactemp[9]:$mactemp[10]:$mactemp[11]";
my $col="";
if ($lines % 2) {
print "<tr>";
$col="bgcolor='$color{'color20'}'";
}
else {
print "<tr>";
$col="bgcolor='$color{'color22'}'";
}
print <<END
<td align='center' $col>$time</td>
<td align='center' $col>$chain</td>
<td align='center' $col>$iface</td>
<td align='center' $col>$proto</td>
<td align='center' $col><a href='/cgi-bin/ipinfo.cgi?ip=$srcaddr'>$srcaddr</a><br /><a href='/cgi-bin/ipinfo.cgi?ip=$dstaddr'>$dstaddr</a></td>
<td align='center' $col>$srcport<br/>$dstport</td>
END
;
# Get flag icon for of the country.
my $flag_icon = &GeoIP::get_flag_icon($ccode);
if ( $flag_icon) {
print "<td align='center' $col><a href='../country.cgi#$ccode'><img src='$flag_icon' border='0' align='absmiddle' alt='$ccode'></a></td>";
} else {
print "<td align='center' $col></td>";
}
print <<END
<td align='center' $col>$macaddr</td>
</tr>
END
;
$lines++;
}
print "</table>";
&oldernewer();
&Header::closebox();
&Header::closebigbox();
&Header::closepage();
sub oldernewer
{
print <<END
<table width='100%'>
<tr>
END
;
print "<td align='center' width='50%'>";
if ($prev != -1) {
print "<a href='/cgi-bin/logs.cgi/firewalllog.dat?0,$cgiparams{'MONTH'},$cgiparams{'DAY'}'>$Lang::tr{'first'}</a> ";
print "<a href='/cgi-bin/logs.cgi/firewalllog.dat?$prev,$cgiparams{'MONTH'},$cgiparams{'DAY'}'>$Lang::tr{'older'}</a>";
}
else {
print "$Lang::tr{'first'} $Lang::tr{'older'}";
}
print "</td>\n";
print "<td align='center' width='50%'>";
if ($next >= 0) {
print "<a href='/cgi-bin/logs.cgi/firewalllog.dat?$next,$cgiparams{'MONTH'},$cgiparams{'DAY'}'>$Lang::tr{'newer'}</a> ";
print "<a href='/cgi-bin/logs.cgi/firewalllog.dat?$lastPageIndex,$cgiparams{'MONTH'},$cgiparams{'DAY'}'>$Lang::tr{'last'}</a>";
}
else {
print "$Lang::tr{'newer'} $Lang::tr{'last'} ";
}
print "</td>\n";
print <<END
</tr>
</table>
END
;
}