Private
Public Access
1
0

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'] ?? ''); $stateProtocol = strtoupper($state['protocol'] ?? '');
// More flexible matching - try multiple approaches // Normalize all values for comparison
$normalizedSourceIP = strtolower(trim($sourceIP)); $normalizedSourceIP = strtolower(trim($sourceIP));
$normalizedDestIP = strtolower(trim($destIP)); $normalizedDestIP = strtolower(trim($destIP));
$normalizedStateSourceIP = strtolower(trim($stateSourceIP)); $normalizedStateSourceIP = strtolower(trim($stateSourceIP));
$normalizedStateDestIP = strtolower(trim($stateDestIP)); $normalizedStateDestIP = strtolower(trim($stateDestIP));
$normalizedProtocol = strtoupper(trim($protocol));
// Check if this state matches the log entry (more lenient matching) // Very flexible matching logic
$sourceMatch = false; $ipMatch = false;
$reverseMatch = false;
// Try exact match // Check if IPs match in either direction
if ($normalizedStateSourceIP === $normalizedSourceIP && $normalizedStateDestIP === $normalizedDestIP) { if (($normalizedStateSourceIP === $normalizedSourceIP && $normalizedStateDestIP === $normalizedDestIP) ||
$sourceMatch = true; ($normalizedStateSourceIP === $normalizedDestIP && $normalizedStateDestIP === $normalizedSourceIP)) {
} elseif ($normalizedStateSourceIP === $normalizedDestIP && $normalizedStateDestIP === $normalizedSourceIP) { $ipMatch = true;
$reverseMatch = true;
} }
// Try partial match (contains) for cases where IP format differs // Also try if one of the IPs matches (useful for single-sided matching)
if (!$sourceMatch && !$reverseMatch) { if (!$ipMatch && (
if ((str_contains($normalizedStateSourceIP, $normalizedSourceIP) || str_contains($normalizedSourceIP, $normalizedStateSourceIP)) && $normalizedStateSourceIP === $normalizedSourceIP ||
(str_contains($normalizedStateDestIP, $normalizedDestIP) || str_contains($normalizedDestIP, $normalizedStateDestIP))) { $normalizedStateSourceIP === $normalizedDestIP ||
$sourceMatch = true; $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) // Protocol match
$protocolMatch = true; $protocolMatch = (empty($protocol) || $protocol === '-' || $normalizedProtocol === $stateProtocol);
if (!empty($protocol) && $protocol !== '-') {
$protocolMatch = (strtoupper(trim($protocol)) === $stateProtocol);
}
// Check port match - focus on destination port which is the service port // Port match - check if destination port from log matches any port in state
// Source port is usually ephemeral and not relevant for matching $portMatch = false;
$portMatch = true; if (empty($destPort) || $destPort === '-') {
if (!empty($destPort) && $destPort !== '-') { $portMatch = true; // No port specified, match all
} else {
$destPortNum = (int)$destPort; $destPortNum = (int)$destPort;
// Match if either state's source or destination port equals the log's destination port if ($stateDestPort === $destPortNum || $stateSourcePort === $destPortNum) {
// This handles bidirectional connections $portMatch = true;
$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 (($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); $bytes = (int)($state['bytes_total'] ?? $state['bytes'] ?? 0);
$packets = (int)($state['packets_total'] ?? $state['packets'] ?? 0); $packets = (int)($state['packets_total'] ?? $state['packets'] ?? 0);
$stateName = strtoupper($state['state'] ?? 'UNKNOWN'); $stateName = strtoupper($state['state'] ?? 'UNKNOWN');