Files
bpfire/html/cgi-bin/logs.cgi/firewalllog.dat
Michael Eitelwein 9877d28d9e Enable correct display of ipv6 entries in Firewall log pages of web UI.
3 main changes:
 - Fill $iface and $out from PHYSIN and PHYSOUT when looking at bridged packets, othwerwise fill from IN and OUT
 - Recognize ipv4 and ipv6 address style for $srcaddr and $dstaddr
 - Match color coding of tables to pie charts (see seperate patch sent earlier)

I am using the bridged ipv6 setup as proposed in the wiki. I do not think this breaks anything when not using ipv6. So it would be nice to include this even if ipv6 is not officially supported yet. It is quite useful when using the ipv6 setup.

Signed-off-by: Michael Eitelwein <michael@eitelwein.net>
---
2016-01-07 14:00:01 +01:00

440 lines
15 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 Geo::IP::PurePerl;
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=
if ($_ =~ /^... (..) (..:..:..) [\w\-]+ kernel:(.*)(PHYSIN=.*)$/) {}
elsif ($_ =~ /^... (..) (..:..:..) [\w\-]+ kernel:(.*)(IN=.*)$/) {}
my $day = $1;
$day =~ tr / /0/;
my $time = $cgiparams{'DAY'} ? "$2" : "$day/$2" ;
my $comment = $3;
my $packet = $4;
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 $gi = Geo::IP::PurePerl->new();
my $ccode = $gi->country_code_by_name($srcaddr);
my $fcode = lc($ccode);
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>$comment</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($fcode);
if ( $flag_icon) {
print "<td align='center' $col><a href='../country.cgi#$fcode'><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
;
}