diff --git a/extensions/Servers/Proxmox/Livewire/Firewall.php b/extensions/Servers/Proxmox/Livewire/Firewall.php index 666bc6182..ed703f9f2 100644 --- a/extensions/Servers/Proxmox/Livewire/Firewall.php +++ b/extensions/Servers/Proxmox/Livewire/Firewall.php @@ -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');