mirror of
https://github.com/pfsense/pfsense.git
synced 2025-10-26 11:38:35 +00:00
Filter log parsing update
* Share filter log parsing code instead of using copy/paste/code duplication. * Reworked the JavaScript a little so it could also be shared * Fix a large number of bugs, especially in the AJAX-based dynamic log viewer. * Picks up some more detail from the logs, and more accurately determines the protocol of a given log entry. * Adds a CLI log parser (filterparser.php) * Removed some redundant/unused code * Code cleanup/style fixes * Added support for finding logged rdr rules from miniupnpd NOTE: Due to the dynamic nature of upnp rules, the rule may not be present when checked.
This commit is contained in:
parent
5155bb3302
commit
af8ae7cec9
@ -38,13 +38,15 @@
|
||||
##|-PRIV
|
||||
|
||||
require("guiconfig.inc");
|
||||
require_once("filter_log.inc");
|
||||
|
||||
if($_GET['getrulenum'] or $_POST['getrulenum']) {
|
||||
if($_GET['getrulenum'])
|
||||
$rulenum = escapeshellarg($_GET['getrulenum']);
|
||||
$rulenum = $_GET['getrulenum'];
|
||||
if($_POST['getrulenum'])
|
||||
$rulenum = escapeshellarg($_POST['getrulenum']);
|
||||
$rule = `pfctl -vvsr | grep '@{$rulenum} '`;
|
||||
$rulenum = $_POST['getrulenum'];
|
||||
list($rulenum, $type) = explode(',', $rulenum);
|
||||
$rule = find_rule_by_number($rulenum, $type);
|
||||
echo "The rule that triggered this action is:\n\n{$rule}";
|
||||
exit;
|
||||
}
|
||||
@ -58,126 +60,12 @@ if (!$nentries)
|
||||
if ($_POST['clear'])
|
||||
clear_log_file($filter_logfile);
|
||||
|
||||
/* format filter logs */
|
||||
function conv_clog($logfile, $tail = 50) {
|
||||
global $config, $nentries, $g;
|
||||
$logarr = "";
|
||||
/* make interface/port table */
|
||||
$iftable = array();
|
||||
$iflist = get_configured_interface_with_descr();
|
||||
foreach ($iflist as $if => $ifdesc)
|
||||
$iftable[get_real_interface($if)] = $ifdesc;
|
||||
|
||||
$sor = isset($config['syslog']['reverse']) ? "-r" : "";
|
||||
|
||||
if(isset($config['system']['usefifolog']))
|
||||
exec("/usr/sbin/fifolog_reader {$logfile} | /usr/bin/tail {$sor} -n 500", $logarr);
|
||||
else
|
||||
exec("/usr/sbin/clog {$logfile} | grep -v \"CLOG\" | grep -v \"\033\" | /usr/bin/tail {$sor} -n 500", $logarr);
|
||||
|
||||
$filterlog = array();
|
||||
|
||||
$counter = 1;
|
||||
|
||||
foreach ($logarr as $logent) {
|
||||
|
||||
if($counter > $nentries)
|
||||
break;
|
||||
|
||||
$log_split = "";
|
||||
|
||||
|
||||
preg_match("/(\b(?:\d{1,3}\.){3}\d{1,3}(\.\w+)?)\s.*\s(\b(?:\d{1,3}\.){3}\d{1,3}(\.\w+)?)/", $logent, $log_split);
|
||||
|
||||
$flent['src'] = convert_port_period_to_colon($log_split[1]);
|
||||
$flent['dst'] = convert_port_period_to_colon($log_split[3]);
|
||||
|
||||
preg_match("/(.*)\s.*\spf:\s.*\srule\s(.*)\(match\)\:\s(.*)\s\w+\son\s(\w+)\:\s(.*)\s>\s(.*)\:\s.*/", $logent, $log_split);
|
||||
|
||||
$beforeupper = $logent;
|
||||
$logent = strtoupper($logent);
|
||||
|
||||
if(stristr(strtoupper($logent), "UDP") == true)
|
||||
$flent['proto'] = "UDP";
|
||||
else if(stristr(strtoupper($logent), "TCP") == true)
|
||||
$flent['proto'] = "TCP";
|
||||
else if(stristr(strtoupper($logent), "ICMP") == true)
|
||||
$flent['proto'] = "ICMP";
|
||||
else if(stristr(strtoupper($logent), "HSRP") == true)
|
||||
$flent['proto'] = "HSRP";
|
||||
else if(stristr(strtoupper($logent), "ESP") == true)
|
||||
$flent['proto'] = "ESP";
|
||||
else if(stristr(strtoupper($logent), "AH") == true)
|
||||
$flent['proto'] = "AH";
|
||||
else if(stristr(strtoupper($logent), "GRE") == true)
|
||||
$flent['proto'] = "GRE";
|
||||
else if(stristr(strtoupper($logent), "IGMP") == true)
|
||||
$flent['proto'] = "IGMP";
|
||||
else if(stristr(strtoupper($logent), "CARP") == true)
|
||||
$flent['proto'] = "CARP";
|
||||
else if(stristr(strtoupper($logent), "VRRP") == true)
|
||||
$flent['proto'] = "VRRP";
|
||||
else if(stristr(strtoupper($logent), "PFSYNC") == true)
|
||||
$flent['proto'] = "PFSYNC";
|
||||
else if(stristr($logent, "sack") == true)
|
||||
$flent['proto'] = "TCP";
|
||||
else
|
||||
$flent['proto'] = "TCP";
|
||||
|
||||
$flent['time'] = $log_split[1];
|
||||
$flent['act'] = $log_split[3];
|
||||
$flent['interface'] = empty($iftable[$log_split[4]]) ? $log_split[4] : $iftable[$log_split[4]];
|
||||
|
||||
$tmp = split("/", $log_split[2]);
|
||||
$flent['rulenum'] = $tmp[0];
|
||||
|
||||
$shouldadd = true;
|
||||
|
||||
if(trim($flent['src']) == "")
|
||||
$shouldadd = false;
|
||||
if(trim($flent['dst']) == "")
|
||||
$shouldadd = false;
|
||||
if(trim($flent['time']) == "")
|
||||
$shouldadd = false;
|
||||
|
||||
if($shouldadd == true) {
|
||||
$counter++;
|
||||
$filterlog[] = $flent;
|
||||
} else {
|
||||
if($g['debug']) {
|
||||
log_error("There was a error parsing rule: $beforeupper . Please report to mailing list or forum.");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return $filterlog;
|
||||
}
|
||||
|
||||
function convert_port_period_to_colon($addr) {
|
||||
$addr_split = split("\.", $addr);
|
||||
if($addr_split[4] == "")
|
||||
$newvar = $addr_split[0] . "." . $addr_split[1] . "." . $addr_split[2] . "." . $addr_split[3];
|
||||
else
|
||||
$newvar = $addr_split[0] . "." . $addr_split[1] . "." . $addr_split[2] . "." . $addr_split[3] . ":" . $addr_split[4];
|
||||
if($newvar == "...")
|
||||
return $addr;
|
||||
return $newvar;
|
||||
}
|
||||
|
||||
function format_ipf_ip($ipfip) {
|
||||
list($ip,$port) = explode(",", $ipfip);
|
||||
if (!$port)
|
||||
return $ip;
|
||||
|
||||
return $ip . ", port " . $port;
|
||||
}
|
||||
|
||||
$pgtitle = array("Status","System logs","Firewall");
|
||||
include("head.inc");
|
||||
|
||||
?>
|
||||
<body link="#0000CC" vlink="#0000CC" alink="#0000CC">
|
||||
<script src="/javascript/filter_log.js" type="text/javascript"></script>
|
||||
<?php include("fbegin.inc"); ?>
|
||||
<table width="100%" border="0" cellpadding="0" cellspacing="0">
|
||||
<tr><td>
|
||||
@ -201,11 +89,11 @@ include("head.inc");
|
||||
<div id="mainarea">
|
||||
<table class="tabcont" width="100%" border="0" cellpadding="0" cellspacing="0">
|
||||
<?php if (!isset($config['syslog']['rawfilter'])):
|
||||
$filterlog = conv_clog($filter_logfile, $nentries);
|
||||
$filterlog = conv_log_filter($filter_logfile, $nentries, $nentries + 100);
|
||||
?>
|
||||
<tr>
|
||||
<td colspan="6" class="listtopic">
|
||||
Last <?=$nentries;?> firewall log entries (<a href='/diag_logs_filter_dynamic.php'>switch</a> to dynamic view)</td>
|
||||
Last <?php echo $nentries;?> firewall log entries (<a href='/diag_logs_filter_dynamic.php'>switch</a> to dynamic view)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="10%" class="listhdrr">Act</td>
|
||||
@ -218,79 +106,37 @@ include("head.inc");
|
||||
<tr>
|
||||
<td class="listlr" nowrap align="middle">
|
||||
<center>
|
||||
<a href="#" onClick="javascript:getURL('diag_logs_filter.php?getrulenum=<?php echo $filterent['rulenum']; ?>', outputrule);">
|
||||
<?php if (strstr(strtolower($filterent['act']), "p"))
|
||||
$img = "/themes/{$g['theme']}/images/icons/icon_pass.gif";
|
||||
else if(strstr(strtolower($filterent['act']), "r"))
|
||||
$img = "/themes/{$g['theme']}/images/icons/icon_reject.gif";
|
||||
else
|
||||
$img = "/themes/{$g['theme']}/images/icons/icon_block.gif";
|
||||
?>
|
||||
<img border="0" src="<?=$img;?>" width="11" height="11" align="absmiddle">
|
||||
<a href="#" onClick="javascript:getURL('diag_logs_filter.php?getrulenum=<?php echo "{$filterent['rulenum']},{$filterent['act']}"; ?>', outputrule);">
|
||||
<img border="0" src="<?php echo find_action_image($filterent['act']);?>" width="11" height="11" align="absmiddle" alt="<?php echo $filterent['act'];?>" title="<?php echo $filterent['act'];?>" />
|
||||
<?php if ($filterent['count']) echo $filterent['count'];?></td>
|
||||
<td class="listr" nowrap><?=htmlspecialchars($filterent['time']);?></td>
|
||||
<td class="listr" nowrap><?=htmlspecialchars($filterent['interface']);?></td>
|
||||
<td class="listr" nowrap><?=htmlspecialchars($filterent['src']);?></td>
|
||||
<td class="listr" nowrap><?=htmlspecialchars($filterent['dst']);?></td>
|
||||
<td class="listr" nowrap><?=htmlspecialchars($filterent['proto']);?></td>
|
||||
<td class="listr" nowrap><?php echo htmlspecialchars($filterent['time']);?></td>
|
||||
<td class="listr" nowrap><?php echo htmlspecialchars($filterent['interface']);?></td>
|
||||
<td class="listr" nowrap><?php echo htmlspecialchars($filterent['src']);?></td>
|
||||
<td class="listr" nowrap><?php echo htmlspecialchars($filterent['dst']);?></td>
|
||||
<?php
|
||||
if ($filterent['proto'] == "TCP")
|
||||
$filterent['proto'] .= ":{$filterent['tcpflags']}";
|
||||
?>
|
||||
<td class="listr" nowrap><?php echo htmlspecialchars($filterent['proto']);?></td>
|
||||
</tr><?php endforeach; ?>
|
||||
<?php else: ?>
|
||||
<tr>
|
||||
<td colspan="2" class="listtopic">
|
||||
Last <?=$nentries;?> firewall log entries</td>
|
||||
Last <?php echo $nentries;?> firewall log entries</td>
|
||||
</tr>
|
||||
<?php dump_clog($filter_logfile, $nentries); ?>
|
||||
<?php endif; ?>
|
||||
<tr><td><br><form action="diag_logs_filter.php" method="post">
|
||||
<input name="clear" type="submit" class="formbtn" value="Clear log"></td></tr>
|
||||
<tr><td><br /><form action="diag_logs_filter.php" method="post">
|
||||
<input name="clear" type="submit" class="formbtn" value="Clear log" /></td></tr>
|
||||
</form>
|
||||
</table>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<script language="javascript">
|
||||
if (typeof getURL == 'undefined') {
|
||||
getURL = function(url, callback) {
|
||||
if (!url)
|
||||
throw 'No URL for getURL';
|
||||
try {
|
||||
if (typeof callback.operationComplete == 'function')
|
||||
callback = callback.operationComplete;
|
||||
} catch (e) {}
|
||||
if (typeof callback != 'function')
|
||||
throw 'No callback function for getURL';
|
||||
var http_request = null;
|
||||
if (typeof XMLHttpRequest != 'undefined') {
|
||||
http_request = new XMLHttpRequest();
|
||||
}
|
||||
else if (typeof ActiveXObject != 'undefined') {
|
||||
try {
|
||||
http_request = new ActiveXObject('Msxml2.XMLHTTP');
|
||||
} catch (e) {
|
||||
try {
|
||||
http_request = new ActiveXObject('Microsoft.XMLHTTP');
|
||||
} catch (e) {}
|
||||
}
|
||||
}
|
||||
if (!http_request)
|
||||
throw 'Both getURL and XMLHttpRequest are undefined';
|
||||
http_request.onreadystatechange = function() {
|
||||
if (http_request.readyState == 4) {
|
||||
callback( { success : true,
|
||||
content : http_request.responseText,
|
||||
contentType : http_request.getResponseHeader("Content-Type") } );
|
||||
}
|
||||
}
|
||||
http_request.open('GET', url, true);
|
||||
http_request.send(null);
|
||||
}
|
||||
}
|
||||
|
||||
function outputrule(req) {
|
||||
alert(req.content);
|
||||
}
|
||||
</script>
|
||||
<p><span class="vexpl"><a href="http://doc.pfsense.org/index.php/What_are_TCP_Flags%3F">TCP Flags</a>: F - FIN, S - SYN, A or . - ACK, R - RST, P - PSH, U - URG, E - ECE, C - CWR</span></p>
|
||||
|
||||
<?php include("fend.inc"); ?>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@ -38,134 +38,20 @@
|
||||
##|-PRIV
|
||||
|
||||
require("guiconfig.inc");
|
||||
require_once("filter_log.inc");
|
||||
|
||||
$filter_logfile = "{$g['varlog_path']}/filter.log";
|
||||
$nentries = $config['syslog']['nentries'];
|
||||
if (!$nentries)
|
||||
$nentries = 50;
|
||||
|
||||
/* Hardcode this. AJAX doesn't do so well with large numbers */
|
||||
$nentries = 50;
|
||||
|
||||
/* AJAX related routines */
|
||||
handle_ajax();
|
||||
handle_ajax($nentries, $nentries + 20);
|
||||
|
||||
if ($_POST['clear'])
|
||||
clear_log_file($filter_logfile);
|
||||
|
||||
/* format filter logs */
|
||||
function conv_clog_filter($logfile, $tail = 50) {
|
||||
global $config, $nentries;
|
||||
|
||||
/* make interface/port table */
|
||||
$iftable = array();
|
||||
$iflist = get_configured_interface_with_descr(false, true);
|
||||
foreach ($iflist as $if => $ifdesc)
|
||||
$iftable[get_real_interface($if)] = $ifdesc;
|
||||
|
||||
$sor = isset($config['syslog']['reverse']) ? "-r" : "";
|
||||
|
||||
$logarr = "";
|
||||
if(isset($config['system']['usefifolog']))
|
||||
exec("/usr/sbin/fifolog_reader {$logfile} | /usr/bin/tail {$sor} -n {$tail}", $logarr);
|
||||
else
|
||||
exec("/usr/sbin/clog {$logfile} | grep -v \"CLOG\" | grep -v \"\033\" | /usr/bin/tail {$sor} -n {$tail}", $logarr);
|
||||
|
||||
$filterlog = array();
|
||||
|
||||
$counter = 0;
|
||||
|
||||
foreach ($logarr as $logent) {
|
||||
|
||||
if($counter > $nentries)
|
||||
break;
|
||||
|
||||
$log_split = "";
|
||||
|
||||
preg_match("/(\b(?:\d{1,3}\.){3}\d{1,3}(\.\w+)?)\s.*\s(\b(?:\d{1,3}\.){3}\d{1,3}(\.\w+)?)/", $logent, $log_split);
|
||||
|
||||
$flent['src'] = convert_port_period_to_colon($log_split[1]);
|
||||
$flent['dst'] = convert_port_period_to_colon($log_split[3]);
|
||||
|
||||
preg_match("/(.*)\s.*\spf:\s.*\srule\s(.*)\(match\)\:\s(.*)\s\w+\son\s(\w+)\:\s(.*)\s>\s(.*)\:\s.*/", $logent, $log_split);
|
||||
|
||||
$beforeupper = $logent;
|
||||
$logent = strtoupper($logent);
|
||||
|
||||
if(stristr(strtoupper($logent), "UDP") == true)
|
||||
$flent['proto'] = "UDP";
|
||||
else if(stristr(strtoupper($logent), "TCP") == true)
|
||||
$flent['proto'] = "TCP";
|
||||
else if(stristr(strtoupper($logent), "ICMP") == true)
|
||||
$flent['proto'] = "ICMP";
|
||||
else if(stristr(strtoupper($logent), "HSRP") == true)
|
||||
$flent['proto'] = "HSRP";
|
||||
else if(stristr(strtoupper($logent), "ESP") == true)
|
||||
$flent['proto'] = "ESP";
|
||||
else if(stristr(strtoupper($logent), "AH") == true)
|
||||
$flent['proto'] = "AH";
|
||||
else if(stristr(strtoupper($logent), "GRE") == true)
|
||||
$flent['proto'] = "GRE";
|
||||
else if(stristr(strtoupper($logent), "IGMP") == true)
|
||||
$flent['proto'] = "IGMP";
|
||||
else if(stristr(strtoupper($logent), "CARP") == true)
|
||||
$flent['proto'] = "CARP";
|
||||
else if(stristr(strtoupper($logent), "VRRP") == true)
|
||||
$flent['proto'] = "VRRP";
|
||||
else if(stristr(strtoupper($logent), "PFSYNC") == true)
|
||||
$flent['proto'] = "PFSYNC";
|
||||
else if(stristr($logent, "sack") == true)
|
||||
$flent['proto'] = "TCP";
|
||||
else
|
||||
$flent['proto'] = "TCP";
|
||||
|
||||
$flent['time'] = $log_split[1];
|
||||
$flent['act'] = $log_split[3];
|
||||
$flent['interface'] = empty($iftable[$log_split[4]]) ? $log_split[4] : $iftable[$log_split[4]];
|
||||
|
||||
$tmp = split("/", $log_split[2]);
|
||||
$flent['rulenum'] = $tmp[0];
|
||||
|
||||
$shouldadd = true;
|
||||
|
||||
if(trim($flent['src']) == "")
|
||||
$shouldadd = false;
|
||||
if(trim($flent['dst']) == "")
|
||||
$shouldadd = false;
|
||||
if(trim($flent['time']) == "")
|
||||
$shouldadd = false;
|
||||
|
||||
if($shouldadd == true) {
|
||||
$counter++;
|
||||
$filterlog[] = $flent;
|
||||
} else {
|
||||
if($g['debug']) {
|
||||
log_error("There was a error parsing rule: $beforeupper . Please report to mailing list or forum.");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return $filterlog;
|
||||
}
|
||||
|
||||
function convert_port_period_to_colon($addr) {
|
||||
$addr_split = split("\.", $addr);
|
||||
if($addr_split[4] == "")
|
||||
$newvar = $addr_split[0] . "." . $addr_split[1] . "." . $addr_split[2] . "." . $addr_split[3];
|
||||
else
|
||||
$newvar = $addr_split[0] . "." . $addr_split[1] . "." . $addr_split[2] . "." . $addr_split[3] . ":" . $addr_split[4];
|
||||
if($newvar == "...")
|
||||
return "";
|
||||
return $newvar;
|
||||
}
|
||||
|
||||
function format_ipf_ip($ipfip) {
|
||||
list($ip,$port) = explode(",", $ipfip);
|
||||
if (!$port)
|
||||
return $ip;
|
||||
|
||||
return $ip . ", port " . $port;
|
||||
}
|
||||
|
||||
$filterlog = conv_clog_filter($filter_logfile, $nentries);
|
||||
$filterlog = conv_log_filter($filter_logfile, $nentries, $nentries + 100);
|
||||
|
||||
$pgtitle = array("Diagnostics","System logs","Firewall");
|
||||
include("head.inc");
|
||||
@ -173,6 +59,8 @@ include("head.inc");
|
||||
?>
|
||||
<body link="#0000CC" vlink="#0000CC" alink="#0000CC">
|
||||
<?php include("fbegin.inc"); ?>
|
||||
<script src="/javascript/scriptaculous/prototype.js" type="text/javascript"></script>
|
||||
<script src="/javascript/scriptaculous/scriptaculous.js" type="text/javascript"></script>
|
||||
<script language="javascript">
|
||||
lastsawtime = '<?php echo time(); ?>;';
|
||||
var lines = Array();
|
||||
@ -180,13 +68,26 @@ include("head.inc");
|
||||
var updateDelay = 25500;
|
||||
var isBusy = false;
|
||||
var isPaused = false;
|
||||
var nentries = <?php echo $nentries; ?>;
|
||||
<?php
|
||||
if(isset($config['syslog']['reverse']))
|
||||
echo " var isReverse = true;\n";
|
||||
echo "var isReverse = true;\n";
|
||||
else
|
||||
echo " var isReverse = false;\n";
|
||||
echo "var isReverse = false;\n";
|
||||
?>
|
||||
/* Called by the AJAX updater */
|
||||
function format_log_line(row) {
|
||||
var line = '';
|
||||
line = ' <span class="log-action" nowrap>' + row[0] + '</span>';
|
||||
line += ' <span class="log-time" nowrap>' + row[1] + '</span>';
|
||||
line += ' <span class="log-interface" nowrap>' + row[2] + '</span>';
|
||||
line += ' <span class="log-source" nowrap>' + row[3] + '</span>';
|
||||
line += ' <span class="log-destination" nowrap>' + row[4] + '</span>';
|
||||
line += ' <span class="log-protocol" nowrap>' + row[5] + '</span>';
|
||||
return line;
|
||||
}
|
||||
</script>
|
||||
<script src="/javascript/filter_log.js" type="text/javascript"></script>
|
||||
<table width="100%" border="0" cellpadding="0" cellspacing="0">
|
||||
<tr><td>
|
||||
<?php
|
||||
@ -208,7 +109,7 @@ include("head.inc");
|
||||
<td>
|
||||
<div id="mainarea">
|
||||
<div class="listtopic">
|
||||
Last <?php echo $nentries; ?> records; Pause:<input valign="middle" type="checkbox" onClick="javascript:toggle_pause();">
|
||||
Last <?php echo $nentries; ?> records; (Switch to <a href="diag_logs_filter.php">regular</a> view) Pause:<input valign="middle" type="checkbox" onClick="javascript:toggle_pause();">
|
||||
</div>
|
||||
<div id="log">
|
||||
<div class="log-header">
|
||||
@ -220,234 +121,27 @@ include("head.inc");
|
||||
<span class="log-protocol">Proto</span>
|
||||
</div>
|
||||
<?php $counter=0; foreach ($filterlog as $filterent): ?>
|
||||
<?php
|
||||
if(isset($config['syslog']['reverse'])) {
|
||||
/* honour reverse logging setting */
|
||||
if($counter == 0)
|
||||
$activerow = " id=\"firstrow\"";
|
||||
else
|
||||
$activerow = "";
|
||||
|
||||
} else {
|
||||
/* non-reverse logging */
|
||||
if($counter == count($filterlog))
|
||||
$activerow = " id=\"firstrow\"";
|
||||
else
|
||||
$activerow = "";
|
||||
}
|
||||
?>
|
||||
<div class="log-entry" <?php echo $activerow; ?>>
|
||||
<span class="log-action" nowrap><a href="#" onClick="javascript:getURL('diag_logs_filter.php?getrulenum=<?php echo $filterent['rulenum']; ?>', outputrule);">
|
||||
<div class="log-entry"<?php echo is_first_row($counter, count($filterlog)); ?>>
|
||||
<span class="log-action" nowrap><a href="#" onClick="javascript:getURL('diag_logs_filter.php?getrulenum=<?php echo "{$filterent['rulenum']},{$filterent['act']}"; ?>', outputrule);">
|
||||
<img border="0" src="<?php echo find_action_image($filterent['act']);?>" width="11" height="11" align="absmiddle" alt="<?php echo $filterent['act'];?>" title="<?php echo $filterent['act'];?>" /></a></span>
|
||||
<span class="log-time" ><?php echo htmlspecialchars($filterent['time']);?></span>
|
||||
<span class="log-interface" ><?php echo htmlspecialchars($filterent['interface']);?></span>
|
||||
<span class="log-source" ><?php echo htmlspecialchars($filterent['src']);?></span>
|
||||
<span class="log-destination" ><?php echo htmlspecialchars($filterent['dst']);?></span>
|
||||
<?php
|
||||
if (strstr(strtolower($filterent['act']), "p"))
|
||||
$img = "/themes/metallic/images/icons/icon_pass.gif";
|
||||
else if(strstr(strtolower($filterent['act']), "r"))
|
||||
$img = "/themes/metallic/images/icons/icon_reject.gif";
|
||||
else
|
||||
$img = "/themes/metallic/images/icons/icon_block.gif";
|
||||
if ($filterent['proto'] == "TCP")
|
||||
$filterent['proto'] .= ":{$filterent['tcpflags']}";
|
||||
?>
|
||||
<img border="0" src="<?=$img;?>" width="11" height="11" align="absmiddle"></a></span>
|
||||
<span class="log-time" ><?=htmlspecialchars($filterent['time']);?></span>
|
||||
<span class="log-interface" ><?=htmlspecialchars($filterent['interface']);?></span>
|
||||
<span class="log-source" ><?=htmlspecialchars($filterent['src']);?></span>
|
||||
<span class="log-destination" ><?=htmlspecialchars($filterent['dst']);?></span>
|
||||
<span class="log-protocol" ><?=htmlspecialchars($filterent['proto']);?></span>
|
||||
<span class="log-protocol" ><?php echo htmlspecialchars($filterent['proto']);?></span>
|
||||
</div>
|
||||
<?php $counter++; endforeach; ?>
|
||||
<?php $counter++; endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<script language="javascript">
|
||||
if (typeof getURL == 'undefined') {
|
||||
getURL = function(url, callback) {
|
||||
if (!url)
|
||||
throw 'No URL for getURL';
|
||||
try {
|
||||
if (typeof callback.operationComplete == 'function')
|
||||
callback = callback.operationComplete;
|
||||
} catch (e) {}
|
||||
if (typeof callback != 'function')
|
||||
throw 'No callback function for getURL';
|
||||
var http_request = null;
|
||||
if (typeof XMLHttpRequest != 'undefined') {
|
||||
http_request = new XMLHttpRequest();
|
||||
}
|
||||
else if (typeof ActiveXObject != 'undefined') {
|
||||
try {
|
||||
http_request = new ActiveXObject('Msxml2.XMLHTTP');
|
||||
} catch (e) {
|
||||
try {
|
||||
http_request = new ActiveXObject('Microsoft.XMLHTTP');
|
||||
} catch (e) {}
|
||||
}
|
||||
}
|
||||
if (!http_request)
|
||||
throw 'Both getURL and XMLHttpRequest are undefined';
|
||||
http_request.onreadystatechange = function() {
|
||||
if (http_request.readyState == 4) {
|
||||
callback( { success : true,
|
||||
content : http_request.responseText,
|
||||
contentType : http_request.getResponseHeader("Content-Type") } );
|
||||
}
|
||||
}
|
||||
http_request.open('GET', url, true);
|
||||
http_request.send(null);
|
||||
}
|
||||
}
|
||||
<p><span class="vexpl"><a href="http://doc.pfsense.org/index.php/What_are_TCP_Flags%3F">TCP Flags</a>: F - FIN, S - SYN, A or . - ACK, R - RST, P - PSH, U - URG, E - ECE, C - CWR</span></p>
|
||||
|
||||
function outputrule(req) {
|
||||
alert(req.content);
|
||||
}
|
||||
function fetch_new_rules() {
|
||||
if(isPaused)
|
||||
return;
|
||||
if(isBusy)
|
||||
return;
|
||||
isBusy = true;
|
||||
getURL('diag_logs_filter_dynamic.php?lastsawtime=' + lastsawtime, fetch_new_rules_callback);
|
||||
}
|
||||
function fetch_new_rules_callback(callback_data) {
|
||||
if(isPaused)
|
||||
return;
|
||||
|
||||
var data_split;
|
||||
var new_data_to_add = Array();
|
||||
var data = callback_data.content;
|
||||
|
||||
data_split = data.split("\n");
|
||||
|
||||
for(var x=0; x<data_split.length-1; x++) {
|
||||
/* loop through rows */
|
||||
row_split = data_split[x].split("||");
|
||||
var line = '';
|
||||
line = '<div class="log-entry">';
|
||||
line += ' <span class="log-action" nowrap>' + row_split[0] + '</span>';
|
||||
line += ' <span class="log-time" nowrap>' + row_split[1] + '</span>';
|
||||
line += ' <span class="log-interface" nowrap>' + row_split[2] + '</span>';
|
||||
line += ' <span class="log-source" nowrap>' + row_split[3] + '</span>';
|
||||
line += ' <span class="log-destination" nowrap>' + row_split[4] + '</span>';
|
||||
line += ' <span class="log-protocol" nowrap>' + row_split[5] + '</span>';
|
||||
line += '</div>';
|
||||
lastsawtime = row_split[6];
|
||||
new_data_to_add[new_data_to_add.length] = line;
|
||||
}
|
||||
update_div_rows(new_data_to_add);
|
||||
isBusy = false;
|
||||
}
|
||||
function update_div_rows(data) {
|
||||
if(isPaused)
|
||||
return;
|
||||
|
||||
var isIE = navigator.appName.indexOf('Microsoft') != -1;
|
||||
var isSafari = navigator.userAgent.indexOf('Safari') != -1;
|
||||
var isOpera = navigator.userAgent.indexOf('Opera') != -1;
|
||||
var rulestable = document.getElementById('log');
|
||||
var rows = rulestable.getElementsByTagName('div');
|
||||
var showanim = 1;
|
||||
if (isIE) {
|
||||
showanim = 0;
|
||||
}
|
||||
//alert(data.length);
|
||||
for(var x=0; x<data.length; x++) {
|
||||
var numrows = rows.length;
|
||||
var appearatrow;
|
||||
/* if reverse logging is enabled we need to show the
|
||||
* records in a reverse order with new items appearing
|
||||
* on the top
|
||||
*/
|
||||
//if(isReverse == false) {
|
||||
// for (var i = 2; i < numrows; i++) {
|
||||
// nextrecord = i + 1;
|
||||
// if(nextrecord < numrows)
|
||||
// rows[i].innerHTML = rows[nextrecord].innerHTML;
|
||||
// }
|
||||
// appearatrow = numrows - 1;
|
||||
//} else {
|
||||
for (var i = numrows; i > 0; i--) {
|
||||
nextrecord = i + 1;
|
||||
if(nextrecord < numrows)
|
||||
rows[nextrecord].innerHTML = rows[i].innerHTML;
|
||||
}
|
||||
appearatrow = 1;
|
||||
//}
|
||||
var item = document.getElementById('firstrow');
|
||||
if(x == data.length-1) {
|
||||
/* nothing */
|
||||
showanim = false;
|
||||
} else {
|
||||
showanim = false;
|
||||
}
|
||||
if (showanim) {
|
||||
rows[appearatrow].style.display = 'none';
|
||||
rows[appearatrow].innerHTML = data[x];
|
||||
new Effect.Appear(rows[appearatrow]);
|
||||
} else {
|
||||
rows[appearatrow].innerHTML = data[x];
|
||||
}
|
||||
}
|
||||
/* rechedule AJAX interval */
|
||||
timer = setInterval('fetch_new_rules()', updateDelay);
|
||||
}
|
||||
function toggle_pause() {
|
||||
if(isPaused) {
|
||||
isPaused = false;
|
||||
fetch_new_rules();
|
||||
} else {
|
||||
isPaused = true;
|
||||
}
|
||||
}
|
||||
/* start local AJAX engine */
|
||||
lastsawtime = '<?php echo time(); ?>;';
|
||||
timer = setInterval('fetch_new_rules()', updateDelay);
|
||||
</script>
|
||||
<?php include("fend.inc"); ?>
|
||||
</body>
|
||||
</html>
|
||||
<?php
|
||||
|
||||
/* AJAX specific handlers */
|
||||
function handle_ajax() {
|
||||
if($_GET['getrulenum'] or $_POST['getrulenum']) {
|
||||
if($_GET['getrulenum'])
|
||||
$rulenum = $_GET['getrulenum'];
|
||||
if($_POST['getrulenum'])
|
||||
$rulenum = $_POST['getrulenum'];
|
||||
$rule = `pfctl -vvsr | grep '@{$rulenum} '`;
|
||||
echo "The rule that triggered this action is:\n\n{$rule}";
|
||||
exit;
|
||||
}
|
||||
|
||||
if($_GET['lastsawtime'] or $_POST['lastsawtime']) {
|
||||
global $filter_logfile,$filterent;
|
||||
if($_GET['lastsawtime'])
|
||||
$lastsawtime = $_GET['lastsawtime'];
|
||||
if($_POST['lastsawtime'])
|
||||
$lastsawtime = $_POST['lastsawtime'];
|
||||
/* compare lastsawrule's time stamp to filter logs.
|
||||
* afterwards return the newer records so that client
|
||||
* can update AJAX interface screen.
|
||||
*/
|
||||
$new_rules = "";
|
||||
$filterlog = conv_clog_filter($filter_logfile, 50);
|
||||
foreach($filterlog as $log_row) {
|
||||
$time_regex = "";
|
||||
preg_match("/.*([0-9][0-9]:[0-9][0-9]:[0-9][0-9])/", $log_row['time'], $time_regex);
|
||||
$row_time = strtotime($time_regex[1]);
|
||||
if (strstr(strtolower($log_row['act']), "p"))
|
||||
$img = "<img border='0' src='/themes/metallic/images/icons/icon_pass.gif'>";
|
||||
else if(strstr(strtolower($filterent['act']), "r"))
|
||||
$img = "<img border='0' src='/themes/metallic/images/icons/icon_reject.gif'>";
|
||||
else
|
||||
$img = "<img border='0' src='/themes/metallic/images/icons/icon_block.gif'>";
|
||||
//echo "{$time_regex[1]} - $row_time > $lastsawtime<p>";
|
||||
if($row_time > $lastsawtime)
|
||||
$new_rules .= "{$img}||{$log_row['time']}||{$log_row['interface']}||{$log_row['src']}||{$log_row['dst']}||{$log_row['proto']}||" . time() . "||\n";
|
||||
}
|
||||
echo $new_rules;
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
226
usr/local/www/filter_log.inc
Normal file
226
usr/local/www/filter_log.inc
Normal file
@ -0,0 +1,226 @@
|
||||
<?php
|
||||
/* $Id$ */
|
||||
/*
|
||||
log.inc.php
|
||||
part of pfSesne by Scott Ullrich
|
||||
originally based on m0n0wall (http://m0n0.ch/wall)
|
||||
|
||||
Copyright (C) 2009 Jim Pingle <myfirstname>@<mylastname>.org
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
||||
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* format filter logs */
|
||||
function conv_log_filter($logfile, $nentries, $tail = 50) {
|
||||
global $config, $g;
|
||||
|
||||
/* Make sure this is a number before using it in a system call */
|
||||
if (!(is_numeric($tail)))
|
||||
return;
|
||||
|
||||
/* Always do a reverse tail, to be sure we're grabbing the 'end' of the log. */
|
||||
$logarr = "";
|
||||
|
||||
if(isset($config['system']['usefifolog']))
|
||||
exec("/usr/sbin/fifolog_reader {$logfile} | /usr/bin/tail -r -n 500", $logarr);
|
||||
else
|
||||
exec("/usr/sbin/clog {$logfile} | grep -v \"CLOG\" | grep -v \"\033\" | /usr/bin/tail -r -n 500", $logarr);
|
||||
|
||||
$filterlog = array();
|
||||
$counter = 0;
|
||||
|
||||
foreach ($logarr as $logent) {
|
||||
if($counter >= $nentries)
|
||||
break;
|
||||
|
||||
$flent = parse_filter_line($logent);
|
||||
if ($flent != "") {
|
||||
$counter++;
|
||||
$filterlog[] = $flent;
|
||||
}
|
||||
}
|
||||
/* Since the lines are in reverse order, flip them around if needed based on the user's preference */
|
||||
return isset($config['syslog']['reverse']) ? $filterlog : array_reverse($filterlog);
|
||||
}
|
||||
|
||||
function parse_filter_line($line) {
|
||||
global $config, $g;
|
||||
$log_split = "";
|
||||
preg_match("/(.*)\s(.*)\spf:\s.*\srule\s(.*)\(match\)\:\s(.*)\s\w+\son\s(\w+)\:\s\((.*)\)\s(.*)\s>\s(.*)\:\s(.*)/", $line, $log_split);
|
||||
|
||||
list($all, $flent['time'], $host, $rule, $flent['act'], $flent['realint'], $details, $src, $dst, $leftovers) = $log_split;
|
||||
|
||||
$flent['src'] = convert_port_period_to_colon($src);
|
||||
$flent['dst'] = convert_port_period_to_colon($dst);
|
||||
$flent['interface'] = convert_log_interface_to_friendly_interface_name($flent['realint']);
|
||||
|
||||
$tmp = split("/", $rule);
|
||||
$flent['rulenum'] = $tmp[0];
|
||||
|
||||
$proto = array(" ", "(?)");
|
||||
/* Attempt to determine the protocol, based on several possible patterns.
|
||||
* The value returned by strpos() must be strictly checkeded against the
|
||||
* boolean FALSE because it could return a valid answer of 0 upon success. */
|
||||
if (!(strpos($details, 'proto ') === FALSE)) {
|
||||
preg_match("/.*\sproto\s(.*)\s\(/", $details, $proto);
|
||||
} elseif (!(strpos($details, 'proto: ') === FALSE)) {
|
||||
preg_match("/.*\sproto\:(.*)\s\(/", $details, $proto);
|
||||
} elseif (!(strpos($leftovers, 'sum ok] ') === FALSE)) {
|
||||
preg_match("/.*\ssum ok]\s(.*)\,\s.*/", $leftovers, $proto);
|
||||
} elseif (!(strpos($line, 'sum ok] ') === FALSE)) {
|
||||
preg_match("/.*\ssum ok]\s(.*)\,\s.*/", $line, $proto);
|
||||
}
|
||||
$proto = split(" ", trim($proto[1]));
|
||||
$flent['proto'] = rtrim($proto[0], ",");
|
||||
|
||||
/* If we're dealing with TCP, try to determine the flags/control bits */
|
||||
$flent['tcpflags'] = "";
|
||||
if ($flent['proto'] == "TCP") {
|
||||
$flags = split('[\, ]', $leftovers);
|
||||
$flent['tcpflags'] = $flags[0];
|
||||
if ($flent['tcpflags'] == ".")
|
||||
$flent['tcpflags'] = "A";
|
||||
}
|
||||
|
||||
/* If there is a src, a dst, and a time, then the line should be usable/good */
|
||||
if (!((trim($flent['src']) == "") || (trim($flent['dst']) == "") || (trim($flent['time']) == ""))) {
|
||||
return $flent;
|
||||
} else {
|
||||
if($g['debug']) {
|
||||
log_error("There was a error parsing rule: $errline. Please report to mailing list or forum.");
|
||||
}
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
function convert_log_interface_to_friendly_interface_name($int) {
|
||||
global $config;
|
||||
|
||||
$iflist = get_configured_interface_with_descr();
|
||||
foreach ($iflist as $if => $ifdesc)
|
||||
$iftable[get_real_interface($if)] = $ifdesc;
|
||||
|
||||
/* Check for WAN first, pppoe (ng0) doesn't return properly otherwise */
|
||||
if ($int == get_real_wan_interface($int))
|
||||
$int = 'wan';
|
||||
else
|
||||
$int = empty($iftable[$int]) ? $int : $iftable[$int];
|
||||
|
||||
return $int;
|
||||
}
|
||||
|
||||
function convert_port_period_to_colon($addr) {
|
||||
if (substr_count($addr, '.') > 1) {
|
||||
/* IPv4 - Change the port delimiter to : */
|
||||
$addr_split = split("\.", $addr);
|
||||
if($addr_split[4] == "") {
|
||||
$newvar = "{$addr_split[0]}.{$addr_split[1]}.{$addr_split[2]}.{$addr_split[3]}";
|
||||
$newvar = rtrim($newvar, ":");
|
||||
} else {
|
||||
$port_split = split("\:", $addr_split[4]);
|
||||
$newvar = "{$addr_split[0]}.{$addr_split[1]}.{$addr_split[2]}.{$addr_split[3]}:{$port_split[0]}";
|
||||
$newvar = rtrim($newvar, ":");
|
||||
}
|
||||
if($newvar == "...")
|
||||
return $addr;
|
||||
return $newvar;
|
||||
} else {
|
||||
/* IPv6 - Leave it alone */
|
||||
$addr = split(" ", $addr);
|
||||
return rtrim($addr[0], ":");
|
||||
}
|
||||
}
|
||||
|
||||
function find_rule_by_number($rulenum, $type="rules") {
|
||||
/* Passing arbitrary input to grep could be a Very Bad Thing(tm) */
|
||||
if (!(is_numeric($rulenum)))
|
||||
return;
|
||||
/* At the moment, miniupnpd is the only thing I know of that
|
||||
generates logging rdr rules */
|
||||
if ($type == "rdr")
|
||||
return `pfctl -vvsn -a "miniupnpd" | grep '^@{$rulenum} '`;
|
||||
else
|
||||
return `pfctl -vvsr | grep '^@{$rulenum} '`;
|
||||
}
|
||||
|
||||
function find_action_image($action) {
|
||||
global $g;
|
||||
if ((strstr(strtolower($action), "p")) || (strtolower($action) == "rdr"))
|
||||
return "/themes/{$g['theme']}/images/icons/icon_pass.gif";
|
||||
else if(strstr(strtolower($action), "r"))
|
||||
return "/themes/{$g['theme']}/images/icons/icon_reject.gif";
|
||||
else
|
||||
return "/themes/{$g['theme']}/images/icons/icon_block.gif";
|
||||
}
|
||||
|
||||
function is_first_row($rownum, $totalrows) {
|
||||
global $config;
|
||||
if(isset($config['syslog']['reverse'])) {
|
||||
/* Honor reverse logging setting */
|
||||
if($rownum == 0)
|
||||
return " id=\"firstrow\"";
|
||||
} else {
|
||||
/* non-reverse logging */
|
||||
if($rownum == $totalrows - 1)
|
||||
return " id=\"firstrow\"";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
/* AJAX specific handlers */
|
||||
function handle_ajax($nentries, $tail = 50) {
|
||||
global $config;
|
||||
if($_GET['lastsawtime'] or $_POST['lastsawtime']) {
|
||||
global $filter_logfile,$filterent;
|
||||
if($_GET['lastsawtime'])
|
||||
$lastsawtime = $_GET['lastsawtime'];
|
||||
if($_POST['lastsawtime'])
|
||||
$lastsawtime = $_POST['lastsawtime'];
|
||||
/* compare lastsawrule's time stamp to filter logs.
|
||||
* afterwards return the newer records so that client
|
||||
* can update AJAX interface screen.
|
||||
*/
|
||||
$new_rules = "";
|
||||
$filterlog = conv_log_filter($filter_logfile, $nentries, $tail);
|
||||
/* We need this to always be in forward order for the AJAX update to work properly */
|
||||
$filterlog = isset($config['syslog']['reverse']) ? array_reverse($filterlog) : $filterlog;
|
||||
foreach($filterlog as $log_row) {
|
||||
$time_regex = "";
|
||||
preg_match("/.*([0-9][0-9]:[0-9][0-9]:[0-9][0-9])/", $log_row['time'], $time_regex);
|
||||
$row_time = strtotime($time_regex[1]);
|
||||
$img = "<img border='0' src='" . find_action_image($log_row['act']) . "' alt={$log_row['act']} title={$log_row['act']} />";
|
||||
//echo "{$time_regex[1]} - $row_time > $lastsawtime<p>";
|
||||
if($row_time > $lastsawtime) {
|
||||
if ($log_row['proto'] == "TCP")
|
||||
$log_row['proto'] .= ":{$log_row['tcpflags']}";
|
||||
|
||||
$img = "<a href=\"#\" onClick=\"javascript:getURL('diag_logs_filter.php?getrulenum={$log_row['rulenum']},{$log_row['rulenum']}', outputrule);\">{$img}</a>";
|
||||
$new_rules .= "{$img}||{$log_row['time']}||{$log_row['interface']}||{$log_row['src']}||{$log_row['dst']}||{$log_row['proto']}||" . time() . "||\n";
|
||||
}
|
||||
}
|
||||
echo $new_rules;
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
59
usr/local/www/filterparser.php
Normal file
59
usr/local/www/filterparser.php
Normal file
@ -0,0 +1,59 @@
|
||||
#!/usr/local/bin/php -q
|
||||
<?php
|
||||
/* $Id$ */
|
||||
/*
|
||||
filterparser.php
|
||||
part of pfSesne by Scott Ullrich
|
||||
originally based on m0n0wall (http://m0n0.ch/wall)
|
||||
|
||||
Copyright (C) 2009 Jim Pingle <myfirstname>@<mylastname>.org
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
||||
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
A quick CLI log parser.
|
||||
Examples:
|
||||
clog /var/log/filter.log | tail -50 | /usr/local/www/filterparser.php
|
||||
clog -f /var/log/filter.log | /usr/local/www/filterparser.php
|
||||
*/
|
||||
include_once("filter_log.inc");
|
||||
include_once("interfaces.inc");
|
||||
|
||||
$log = fopen("php://stdin", "r");
|
||||
while(!feof($log)) {
|
||||
$line = fgets($log);
|
||||
$flent = parse_filter_line(trim($line));
|
||||
/* Available fields:
|
||||
time - Time the packet was seen
|
||||
rulenum - Rule number matched
|
||||
act - Action (pass/block)
|
||||
interface - Friendly interface name (WAN, LAN, etc)
|
||||
realint - Real interface name (fxp0, em0, vr0, etc)
|
||||
proto - Protocol (e.g. TCP, UDP, ICMP, etc)
|
||||
tcpflags - TCP flags/control bits
|
||||
src - Source address with port
|
||||
dst - Destination address with port
|
||||
*/
|
||||
if ($flent != "")
|
||||
echo "{$flent['time']} {$flent['act']} {$flent['realint']} {$flent['proto']} {$flent['src']} {$flent['dst']}\n";
|
||||
}
|
||||
fclose($log); ?>
|
||||
@ -1,18 +1,4 @@
|
||||
|
||||
lastsawtime = '<?php echo time(); ?>;';
|
||||
var lines = Array();
|
||||
var timer;
|
||||
var updateDelay = 30000;
|
||||
var isBusy = false;
|
||||
var isPaused = true;
|
||||
|
||||
<?php
|
||||
if(isset($config['syslog']['reverse']))
|
||||
echo " var isReverse = true;\n";
|
||||
else
|
||||
echo " var isReverse = false;\n";
|
||||
?>
|
||||
|
||||
if (typeof getURL == 'undefined') {
|
||||
getURL = function(url, callback) {
|
||||
if (!url)
|
||||
@ -74,20 +60,13 @@ function fetch_new_rules_callback(callback_data) {
|
||||
for(var x=0; x<data_split.length-1; x++) {
|
||||
/* loop through rows */
|
||||
row_split = data_split[x].split("||");
|
||||
var line = '';
|
||||
line = '<div class="log-entry">';
|
||||
line += ' <span class="log-action-mini" nowrap> ' + row_split[0] + ' </span>';
|
||||
line += ' <span class="log-interface-mini" nowrap>' + row_split[2] + '</span>';
|
||||
line += ' <span class="log-source-mini" nowrap>' + row_split[3] + '</span>';
|
||||
line += ' <span class="log-destination-mini" nowrap>' + row_split[4] + '</span>';
|
||||
line += ' <span class="log-protocol-mini" nowrap>' + row_split[5] + '</span>';
|
||||
line += '</tr></div>';
|
||||
lastsawtime = row_split[6];
|
||||
new_data_to_add[new_data_to_add.length] = line;
|
||||
new_data_to_add[new_data_to_add.length] = format_log_line(row_split);
|
||||
}
|
||||
update_div_rows(new_data_to_add);
|
||||
isBusy = false;
|
||||
}
|
||||
|
||||
function update_div_rows(data) {
|
||||
if(isPaused)
|
||||
return;
|
||||
@ -101,29 +80,32 @@ function update_div_rows(data) {
|
||||
if (isIE) {
|
||||
showanim = 0;
|
||||
}
|
||||
//alert(data.length);
|
||||
|
||||
var startat = data.length - nentries;
|
||||
if (startat < 0) {
|
||||
startat = 0;
|
||||
}
|
||||
data = data.slice(startat, data.length);
|
||||
|
||||
for(var x=0; x<data.length; x++) {
|
||||
var numrows = rows.length;
|
||||
var appearatrow;
|
||||
/* if reverse logging is enabled we need to show the
|
||||
* records in a reverse order with new items appearing
|
||||
* on the top
|
||||
*/
|
||||
//if(isReverse == false) {
|
||||
// for (var i = 2; i < numrows; i++) {
|
||||
// nextrecord = i + 1;
|
||||
// if(nextrecord < numrows)
|
||||
// rows[i].innerHTML = rows[nextrecord].innerHTML;
|
||||
// }
|
||||
// appearatrow = numrows - 1;
|
||||
//} else {
|
||||
* on the top
|
||||
*/
|
||||
if(isReverse == false) {
|
||||
for (var i = 2; i < numrows; i++) {
|
||||
nextrecord = i + 1;
|
||||
if(nextrecord < numrows)
|
||||
rows[i].innerHTML = rows[nextrecord].innerHTML;
|
||||
}
|
||||
} else {
|
||||
for (var i = numrows; i > 0; i--) {
|
||||
nextrecord = i + 1;
|
||||
if(nextrecord < numrows)
|
||||
rows[nextrecord].innerHTML = rows[i].innerHTML;
|
||||
}
|
||||
appearatrow = 1;
|
||||
//}
|
||||
}
|
||||
var item = document.getElementById('firstrow');
|
||||
if(x == data.length-1) {
|
||||
/* nothing */
|
||||
@ -132,15 +114,13 @@ function update_div_rows(data) {
|
||||
showanim = false;
|
||||
}
|
||||
if (showanim) {
|
||||
rows[appearatrow].style.display = 'none';
|
||||
rows[appearatrow].innerHTML = data[x];
|
||||
new Effect.Appear(rows[appearatrow]);
|
||||
item.style.display = 'none';
|
||||
item.innerHTML = data[x];
|
||||
new Effect.Appear(item);
|
||||
} else {
|
||||
rows[appearatrow].innerHTML = data[x];
|
||||
item.innerHTML = data[x];
|
||||
}
|
||||
}
|
||||
/* rechedule AJAX interval */
|
||||
timer = setInterval('fetch_new_rules()', updateDelay);
|
||||
}
|
||||
function toggle_pause() {
|
||||
if(isPaused) {
|
||||
@ -151,5 +131,4 @@ function toggle_pause() {
|
||||
}
|
||||
}
|
||||
/* start local AJAX engine */
|
||||
lastsawtime = '<?php echo time(); ?>;';
|
||||
timer = setInterval('fetch_new_rules()', updateDelay);
|
||||
@ -1,170 +0,0 @@
|
||||
<?php
|
||||
|
||||
//set variable for custom title
|
||||
$log_title = "Firewall Logs";
|
||||
$log_title_link = "diag_logs_filter.php";
|
||||
|
||||
//set variables for log
|
||||
$filter_logfile = "{$g['varlog_path']}/filter.log";
|
||||
$nentries = 5;
|
||||
$filterlog = conv_clog_filter($filter_logfile, $nentries);
|
||||
|
||||
/* AJAX related routines */
|
||||
handle_ajax();
|
||||
|
||||
|
||||
/* format filter logs */
|
||||
function conv_clog_filter($logfile, $tail = 8) {
|
||||
global $config, $nentries, $g;
|
||||
$logarr = "";
|
||||
/* make interface/port table */
|
||||
$iftable = array();
|
||||
$iflist = get_configured_interface_with_descr();
|
||||
foreach ($iflist as $ifl => $ifdesc)
|
||||
$iftable[get_real_interface($ifl)] = $ifdesc;
|
||||
|
||||
$sor = isset($config['syslog']['reverse']) ? "-r" : "";
|
||||
|
||||
exec("/usr/sbin/fifolog_reader {$logfile} | /usr/bin/tail {$sor} -n 500", $logarr);
|
||||
|
||||
$filterlog = array();
|
||||
|
||||
$counter = 1;
|
||||
|
||||
foreach ($logarr as $logent) {
|
||||
|
||||
if($counter > $nentries)
|
||||
break;
|
||||
|
||||
$log_split = "";
|
||||
|
||||
|
||||
preg_match("/(\b(?:\d{1,3}\.){3}\d{1,3}(\.\w+)?)\s.*\s(\b(?:\d{1,3}\.){3}\d{1,3}(\.\w+)?)/", $logent, $log_split);
|
||||
|
||||
$flent['src'] = convert_port_period_to_colon($log_split[1]);
|
||||
$flent['dst'] = convert_port_period_to_colon($log_split[3]);
|
||||
|
||||
preg_match("/(.*)\s.*\spf:\s.*\srule\s(.*)\(match\)\:\s(.*)\s\w+\son\s(\w+)\:\s(.*)\s>\s(.*)\:\s.*/", $logent, $log_split);
|
||||
|
||||
$beforeupper = $logent;
|
||||
$logent = strtoupper($logent);
|
||||
|
||||
if(stristr(strtoupper($logent), "UDP") == true)
|
||||
$flent['proto'] = "UDP";
|
||||
else if(stristr(strtoupper($logent), "TCP") == true)
|
||||
$flent['proto'] = "TCP";
|
||||
else if(stristr(strtoupper($logent), "ICMP") == true)
|
||||
$flent['proto'] = "ICMP";
|
||||
else if(stristr(strtoupper($logent), "HSRP") == true)
|
||||
$flent['proto'] = "HSRP";
|
||||
else if(stristr(strtoupper($logent), "ESP") == true)
|
||||
$flent['proto'] = "ESP";
|
||||
else if(stristr(strtoupper($logent), "AH") == true)
|
||||
$flent['proto'] = "AH";
|
||||
else if(stristr(strtoupper($logent), "GRE") == true)
|
||||
$flent['proto'] = "GRE";
|
||||
else if(stristr(strtoupper($logent), "IGMP") == true)
|
||||
$flent['proto'] = "IGMP";
|
||||
else if(stristr(strtoupper($logent), "CARP") == true)
|
||||
$flent['proto'] = "CARP";
|
||||
else if(stristr(strtoupper($logent), "VRRP") == true)
|
||||
$flent['proto'] = "VRRP";
|
||||
else if(stristr(strtoupper($logent), "PFSYNC") == true)
|
||||
$flent['proto'] = "PFSYNC";
|
||||
else if(stristr($logent, "sack") == true)
|
||||
$flent['proto'] = "TCP";
|
||||
else
|
||||
$flent['proto'] = "TCP";
|
||||
|
||||
$flent['time'] = $log_split[1];
|
||||
$flent['act'] = $log_split[3];
|
||||
$flent['interface'] = empty($iftable[$log_split[4]]) ? $log_split[4] : $iftable[$log_split[4]];
|
||||
|
||||
$tmp = split("/", $log_split[2]);
|
||||
$flent['rulenum'] = $tmp[0];
|
||||
|
||||
$shouldadd = true;
|
||||
|
||||
if(trim($flent['src']) == "")
|
||||
$shouldadd = false;
|
||||
if(trim($flent['dst']) == "")
|
||||
$shouldadd = false;
|
||||
if(trim($flent['time']) == "")
|
||||
$shouldadd = false;
|
||||
|
||||
if($shouldadd == true) {
|
||||
$counter++;
|
||||
$filterlog[] = $flent;
|
||||
} else {
|
||||
if($g['debug']) {
|
||||
log_error("There was a error parsing rule: $beforeupper . Please report to mailing list or forum.");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return $filterlog;
|
||||
}
|
||||
|
||||
function convert_port_period_to_colon($addr) {
|
||||
$addr_split = split("\.", $addr);
|
||||
if($addr_split[4] == "")
|
||||
$newvar = $addr_split[0] . "." . $addr_split[1] . "." . $addr_split[2] . "." . $addr_split[3];
|
||||
else
|
||||
$newvar = $addr_split[0] . "." . $addr_split[1] . "." . $addr_split[2] . "." . $addr_split[3] . ":" . $addr_split[4];
|
||||
if($newvar == "...")
|
||||
return $addr;
|
||||
return $newvar;
|
||||
}
|
||||
|
||||
function format_ipf_ip($ipfip) {
|
||||
list($ip,$port) = explode(",", $ipfip);
|
||||
if (!$port)
|
||||
return $ip;
|
||||
|
||||
return $ip . ", port " . $port;
|
||||
}
|
||||
|
||||
/* AJAX specific handlers */
|
||||
function handle_ajax() {
|
||||
if($_GET['getrulenum'] or $_POST['getrulenum']) {
|
||||
if($_GET['getrulenum'])
|
||||
$rulenum = $_GET['getrulenum'];
|
||||
if($_POST['getrulenum'])
|
||||
$rulenum = $_POST['getrulenum'];
|
||||
$rule = `pfctl -vvsr | grep @{$rulenum}`;
|
||||
echo "The rule that triggered this action is:\n\n{$rule}";
|
||||
exit;
|
||||
}
|
||||
|
||||
if($_GET['lastsawtime'] or $_POST['lastsawtime']) {
|
||||
global $filter_logfile,$filterent;
|
||||
if($_GET['lastsawtime'])
|
||||
$lastsawtime = $_GET['lastsawtime'];
|
||||
if($_POST['lastsawtime'])
|
||||
$lastsawtime = $_POST['lastsawtime'];
|
||||
/* compare lastsawrule's time stamp to filter logs.
|
||||
* afterwards return the newer records so that client
|
||||
* can update AJAX interface screen.
|
||||
*/
|
||||
$new_rules = "";
|
||||
$filterlog = conv_clog_filter($filter_logfile, 8);
|
||||
foreach($filterlog as $log_row) {
|
||||
$time_regex = "";
|
||||
preg_match("/.*([0-9][0-9]:[0-9][0-9]:[0-9][0-9])/", $log_row['time'], $time_regex);
|
||||
$row_time = strtotime($time_regex[1]);
|
||||
if (strstr(strtolower($log_row['act']), "p"))
|
||||
$img = "<img border='0' src='/themes/metallic/images/icons/icon_pass.gif'>";
|
||||
else if(strstr(strtolower($filterent['act']), "r"))
|
||||
$img = "<img border='0' src='/themes/metallic/images/icons/icon_reject.gif'>";
|
||||
else
|
||||
$img = "<img border='0' src='/themes/metallic/images/icons/icon_block.gif'>";
|
||||
//echo "{$time_regex[1]} - $row_time > $lastsawtime<p>";
|
||||
if($row_time > $lastsawtime)
|
||||
$new_rules .= "{$img}||{$log_row['time']}||{$log_row['interface']}||{$log_row['src']}||{$log_row['dst']}||{$log_row['proto']}||" . time() . "||\n";
|
||||
}
|
||||
echo $new_rules;
|
||||
exit;
|
||||
}
|
||||
}
|
||||
?>
|
||||
@ -34,9 +34,73 @@
|
||||
require_once("guiconfig.inc");
|
||||
require_once("pfsense-utils.inc");
|
||||
require_once("functions.inc");
|
||||
require_once("/usr/local/www/widgets/include/log.inc");
|
||||
|
||||
/* In an effort to reduce duplicate code, many shared functions have been moved here. */
|
||||
require_once("filter_log.inc");
|
||||
|
||||
//set variable for custom title
|
||||
$log_title = "Firewall Logs";
|
||||
$log_title_link = "diag_logs_filter.php";
|
||||
|
||||
if($_POST['filterlogentries']) {
|
||||
$config['widgets']['filterlogentries'] = $_POST['filterlogentries'];
|
||||
write_config("Saved Filter Log Entries via Dashboard");
|
||||
Header("Location: /");
|
||||
}
|
||||
|
||||
$nentries = isset($config['widgets']['filterlogentries']) ? $config['widgets']['filterlogentries'] : 5;
|
||||
|
||||
//set variables for log
|
||||
$filter_logfile = "{$g['varlog_path']}/filter.log";
|
||||
$filterlog = conv_log_filter($filter_logfile, $nentries);
|
||||
|
||||
/* AJAX related routines */
|
||||
handle_ajax($nentries, $nentries + 20);
|
||||
|
||||
?>
|
||||
|
||||
<script language="javascript">
|
||||
lastsawtime = '<?php echo time(); ?>';
|
||||
var lines = Array();
|
||||
var timer;
|
||||
var updateDelay = 30000;
|
||||
var isBusy = false;
|
||||
var isPaused = false;
|
||||
var nentries = <?php echo $nentries; ?>;
|
||||
|
||||
<?php
|
||||
if(isset($config['syslog']['reverse']))
|
||||
echo "var isReverse = true;\n";
|
||||
else
|
||||
echo "var isReverse = false;\n";
|
||||
?>
|
||||
|
||||
/* Called by the AJAX updater */
|
||||
function format_log_line(row) {
|
||||
var line = '';
|
||||
line = ' <span class="log-action-mini" nowrap> ' + row[0] + ' </span>';
|
||||
line += ' <span class="log-interface-mini" nowrap>' + row[2] + '</span>';
|
||||
line += ' <span class="log-source-mini" nowrap>' + row[3] + '</span>';
|
||||
line += ' <span class="log-destination-mini" nowrap>' + row[4] + '</span>';
|
||||
line += ' <span class="log-protocol-mini" nowrap>' + row[5] + '</span>';
|
||||
return line;
|
||||
}
|
||||
</script>
|
||||
<script src="/javascript/filter_log.js" type="text/javascript"></script>
|
||||
<input type="hidden" id="log-config" name="log-config" value="">
|
||||
|
||||
<div id="log-settings" name="log-settings" class="widgetconfigdiv" style="display:none;">
|
||||
<form action="/widgets/widgets/log.widget.php" method="post" name="iforma">
|
||||
Number of lines to display:
|
||||
<select name="filterlogentries" class="formfld unknown" id="filterlogentries">
|
||||
<?php for ($i = 1; $i <= 20; $i++) { ?>
|
||||
<option value="<?php echo $i;?>" <?php if ($nentries == $i) echo "SELECTED";?>><?php echo $i;?></option>
|
||||
<?php } ?>
|
||||
</select><br/>
|
||||
<input id="submita" name="submita" type="submit" class="formbtn" value="Save" />
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="log-header">
|
||||
<span class="log-action-mini-header">Act</span>
|
||||
<span class="log-interface-mini-header">IF</span>
|
||||
@ -45,36 +109,23 @@ require_once("/usr/local/www/widgets/include/log.inc");
|
||||
<span class="log-protocol-mini-header">Prot</span>
|
||||
</div>
|
||||
<?php $counter=0; foreach ($filterlog as $filterent): ?>
|
||||
<?php
|
||||
if(isset($config['syslog']['reverse'])) {
|
||||
/* honour reverse logging setting */
|
||||
if($counter == 0)
|
||||
$activerow = " id=\"firstrow\"";
|
||||
else
|
||||
$activerow = "";
|
||||
|
||||
} else {
|
||||
/* non-reverse logging */
|
||||
if($counter == count($filterlog))
|
||||
$activerow = " id=\"firstrow\"";
|
||||
else
|
||||
$activerow = "";
|
||||
}
|
||||
?>
|
||||
<div class="log-entry-mini" <?php echo $activerow; ?> style="clear:both;">
|
||||
<div class="log-entry-mini" <?php echo is_first_row($counter, count($filterlog)); ?> style="clear:both;">
|
||||
<span class="log-action-mini" nowrap>
|
||||
<a href="#" onClick="javascript:getURL('diag_logs_filter.php?getrulenum=<?php echo "{$filterent['rulenum']},{$filterent['act']}"; ?>', outputrule);"><img border="0" src="<?php echo find_action_image($filterent['act']);?>" alt="<?php echo $filterent['act'];?>" title="<?php echo $filterent['act'];?>" /></a> </span>
|
||||
<span class="log-interface-mini"><?php echo htmlspecialchars($filterent['interface']);?> </span>
|
||||
<span class="log-source-mini"><?php echo htmlspecialchars($filterent['src']);?> </span>
|
||||
<span class="log-destination-mini"><?php echo htmlspecialchars($filterent['dst']);?> </span>
|
||||
<?php
|
||||
if (strstr(strtolower($filterent['act']), "p"))
|
||||
$img = "/themes/metallic/images/icons/icon_pass.gif";
|
||||
else if(strstr(strtolower($filterent['act']), "r"))
|
||||
$img = "/themes/metallic/images/icons/icon_reject.gif";
|
||||
else
|
||||
$img = "/themes/metallic/images/icons/icon_block.gif";
|
||||
if ($filterent['proto'] == "TCP")
|
||||
$filterent['proto'] .= ":{$filterent['tcpflags']}";
|
||||
?>
|
||||
<img border="0" src="<?=$img;?>"> </span>
|
||||
<span class="log-interface-mini" ><?=htmlspecialchars(convert_real_interface_to_friendly_interface_name($filterent['interface']));?> </span>
|
||||
<span class="log-source-mini" ><?=htmlspecialchars($filterent['src']);?> </span>
|
||||
<span class="log-destination-mini" ><?=htmlspecialchars($filterent['dst']);?> </span>
|
||||
<span class="log-protocol-mini" ><?=htmlspecialchars($filterent['proto']);?> </span>
|
||||
<span class="log-protocol-mini"><?php echo htmlspecialchars($filterent['proto']);?> </span>
|
||||
</div>
|
||||
<?php $counter++; endforeach; ?>
|
||||
<?php $counter++; endforeach; ?>
|
||||
|
||||
<!-- needed to display the widget settings menu -->
|
||||
<script language="javascript" type="text/javascript">
|
||||
selectIntLink = "log-configure";
|
||||
textlink = document.getElementById(selectIntLink);
|
||||
textlink.style.display = "inline";
|
||||
</script>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user