feat: enhance firewall log matching logic with improved IP, protocol, and port checks for increased flexibility

This commit is contained in:
2025-12-04 22:37:17 -05:00
parent ab1668213d
commit 8c991c615a

View File

@@ -1671,60 +1671,66 @@ class Firewall extends Component
$stateProtocol = strtoupper($state['protocol'] ?? '');
// More flexible matching - try multiple approaches
// Normalize all values for comparison
$normalizedSourceIP = strtolower(trim($sourceIP));
$normalizedDestIP = strtolower(trim($destIP));
$normalizedStateSourceIP = strtolower(trim($stateSourceIP));
$normalizedStateDestIP = strtolower(trim($stateDestIP));
$normalizedProtocol = strtoupper(trim($protocol));
// Check if this state matches the log entry (more lenient matching)
$sourceMatch = false;
$reverseMatch = false;
// Very flexible matching logic
$ipMatch = false;
// Try exact match
if ($normalizedStateSourceIP === $normalizedSourceIP && $normalizedStateDestIP === $normalizedDestIP) {
$sourceMatch = true;
} elseif ($normalizedStateSourceIP === $normalizedDestIP && $normalizedStateDestIP === $normalizedSourceIP) {
$reverseMatch = true;
// Check if IPs match in either direction
if (($normalizedStateSourceIP === $normalizedSourceIP && $normalizedStateDestIP === $normalizedDestIP) ||
($normalizedStateSourceIP === $normalizedDestIP && $normalizedStateDestIP === $normalizedSourceIP)) {
$ipMatch = true;
}
// Try partial match (contains) for cases where IP format differs
if (!$sourceMatch && !$reverseMatch) {
if ((str_contains($normalizedStateSourceIP, $normalizedSourceIP) || str_contains($normalizedSourceIP, $normalizedStateSourceIP)) &&
(str_contains($normalizedStateDestIP, $normalizedDestIP) || str_contains($normalizedDestIP, $normalizedStateDestIP))) {
$sourceMatch = true;
// Also try if one of the IPs matches (useful for single-sided matching)
if (!$ipMatch && (
$normalizedStateSourceIP === $normalizedSourceIP ||
$normalizedStateSourceIP === $normalizedDestIP ||
$normalizedStateDestIP === $normalizedSourceIP ||
$normalizedStateDestIP === $normalizedDestIP)) {
// At least one IP matches, check if the other makes sense
if ($normalizedStateSourceIP === $normalizedSourceIP || $normalizedStateDestIP === $normalizedSourceIP) {
if ($normalizedStateSourceIP === $normalizedDestIP || $normalizedStateDestIP === $normalizedDestIP) {
$ipMatch = true;
}
}
}
// Check protocol match (more lenient)
$protocolMatch = true;
if (!empty($protocol) && $protocol !== '-') {
$protocolMatch = (strtoupper(trim($protocol)) === $stateProtocol);
}
// Protocol match
$protocolMatch = (empty($protocol) || $protocol === '-' || $normalizedProtocol === $stateProtocol);
// Check port match - focus on destination port which is the service port
// Source port is usually ephemeral and not relevant for matching
$portMatch = true;
if (!empty($destPort) && $destPort !== '-') {
// Port match - check if destination port from log matches any port in state
$portMatch = false;
if (empty($destPort) || $destPort === '-') {
$portMatch = true; // No port specified, match all
} else {
$destPortNum = (int)$destPort;
// Match if either state's source or destination port equals the log's destination port
// This handles bidirectional connections
$portMatch = ($stateDestPort === $destPortNum || $stateSourcePort === $destPortNum);
}
// Also consider matching without port if IPs and protocol match
// This is useful for firewall logs that don't include source port
$relaxedMatch = false;
if (!$sourceMatch && !$reverseMatch && empty($sourcePort)) {
// If no source port in log, be more lenient with matching
if (($normalizedStateSourceIP === $normalizedSourceIP || $normalizedStateDestIP === $normalizedSourceIP) &&
($normalizedStateSourceIP === $normalizedDestIP || $normalizedStateDestIP === $normalizedDestIP) &&
$protocolMatch && $portMatch) {
$relaxedMatch = true;
if ($stateDestPort === $destPortNum || $stateSourcePort === $destPortNum) {
$portMatch = true;
}
}
if (($sourceMatch || $reverseMatch || $relaxedMatch) && $protocolMatch && $portMatch) {
// Log first potential match for debugging
if ($ipMatch && $protocolMatch && $portMatch && count($matchingConnections) === 0) {
Log::info('First match found', [
'state_source' => $stateSourceIP,
'state_dest' => $stateDestIP,
'state_protocol' => $stateProtocol,
'state_src_port' => $stateSourcePort,
'state_dst_port' => $stateDestPort,
'log_source' => $sourceIP,
'log_dest' => $destIP,
'log_protocol' => $protocol,
'log_dest_port' => $destPort,
]);
}
if ($ipMatch && $protocolMatch && $portMatch) {
$bytes = (int)($state['bytes_total'] ?? $state['bytes'] ?? 0);
$packets = (int)($state['packets_total'] ?? $state['packets'] ?? 0);
$stateName = strtoupper($state['state'] ?? 'UNKNOWN');