65535) return null; return $p; } /** * Very basic CIDR/subnet validation. * Accepts forms like: * 10.0.0.0/24 * 192.168.1.5 */ function sanitize_subnet($subnet) { $subnet = trim($subnet); if ($subnet === '') return null; // allow plain IP if (filter_var($subnet, FILTER_VALIDATE_IP)) { return $subnet; } // allow IP/CIDR $parts = explode('/', $subnet); if (count($parts) === 2) { [$ip, $mask] = $parts; $ip = trim($ip); $mask = trim($mask); if (!filter_var($ip, FILTER_VALIDATE_IP)) { return null; } if (!ctype_digit($mask)) { return null; } $m = (int)$mask; if ($m < 0 || $m > 32) { return null; } return $ip . '/' . $m; } return null; } /** * Run a UFW command and capture output. */ function run_ufw_command($cmd, $dryRun = false) { $cmdline = UFW_BIN . ' ' . $cmd; if ($dryRun) { return [ 'cmd' => $cmdline, 'output' => ['[DRY RUN] Command not executed'], 'exit_code' => 0, ]; } $output = []; $ret = 0; exec($cmdline . ' 2>&1', $output, $ret); return [ 'cmd' => $cmdline, 'output' => $output, 'exit_code' => $ret, ]; } // Handle POST if ($_SERVER['REQUEST_METHOD'] === 'POST') { $action = $_POST['action'] ?? ''; if ($action === 'apply_firewall') { $globalPorts = $_POST['global_ports'] ?? []; $restrictedPorts = $_POST['restricted_port'] ?? []; $restrictedSubnets = $_POST['restricted_subnet'] ?? []; $dryRunChecked = isset($_POST['dry_run']) && $_POST['dry_run'] === '1'; $didAnything = false; // 1) Open ports for all IP (allow) foreach ($globalPorts as $rawPort) { $rawPort = trim($rawPort); if ($rawPort === '') { continue; } $port = sanitize_port($rawPort); if ($port === null) { $errors[] = "Invalid open port: " . htmlspecialchars($rawPort); continue; } $didAnything = true; $res = run_ufw_command('allow ' . (int)$port, $dryRunChecked || $DRY_RUN); if ($res['exit_code'] !== 0) { $errors[] = "Failed to allow port {$port}: " . implode(" ", $res['output']); } else { $messages[] = "Allowed port {$port} for all IPs."; } } // 2) Restricted ports with subnets // Model: Deny port globally, then allow from specified subnets. $count = max(count($restrictedPorts), count($restrictedSubnets)); for ($i = 0; $i < $count; $i++) { $rawPort = $restrictedPorts[$i] ?? ''; $rawSubnet = $restrictedSubnets[$i] ?? ''; $rawPort = trim($rawPort); $rawSubnet = trim($rawSubnet); if ($rawPort === '' || $rawSubnet === '') { continue; } $port = sanitize_port($rawPort); $subnet = sanitize_subnet($rawSubnet); if ($port === null) { $errors[] = "Invalid restricted port: " . htmlspecialchars($rawPort); continue; } if ($subnet === null) { $errors[] = "Invalid subnet/CIDR for port {$port}: " . htmlspecialchars($rawSubnet); continue; } $didAnything = true; // Deny port from everywhere $denyRes = run_ufw_command('deny ' . (int)$port, $dryRunChecked || $DRY_RUN); if ($denyRes['exit_code'] !== 0) { $errors[] = "Failed to deny port {$port}: " . implode(" ", $denyRes['output']); } else { $messages[] = "Denied port {$port} for all IPs."; } // Allow from subnet $allowCmd = 'allow from ' . escapeshellarg($subnet) . ' to any port ' . (int)$port; // We used escapeshellarg() here, but run_ufw_command expects only the ufw arguments, // so we need to build carefully: // Rebuild without full path: $allowCmdForRun = 'allow from ' . $subnet . ' to any port ' . (int)$port; $allowRes = run_ufw_command($allowCmdForRun, $dryRunChecked || $DRY_RUN); if ($allowRes['exit_code'] !== 0) { $errors[] = "Failed to allow port {$port} from {$subnet}: " . implode(" ", $allowRes['output']); } else { $messages[] = "Allowed port {$port} only from {$subnet}."; } } if (!$didAnything) { $errors[] = "No valid firewall rules submitted."; } // Optional: reload or enable ufw here // $reload = run_ufw_command('reload', $dryRunChecked || $DRY_RUN); } } // Get current UFW status $currentStatus = []; $statusExit = 0; if (file_exists(UFW_BIN)) { exec(UFW_BIN . ' status numbered 2>&1', $currentStatus, $statusExit); } else { $currentStatus[] = "UFW binary not found at " . UFW_BIN; $statusExit = 1; } ?> Firewall Rule Manager

Firewall Rule Manager

Configure simple UFW rules to open ports for all IPs and restrict ports to specific subnets. Ensure this interface is accessible only to trusted administrators.

Open Ports (All IPs)

Ports in this list will be allowed from any IP.

Port Comment (optional)
Example: 80, 443, 1935, 22 etc. Empty rows will be ignored.

Restricted Ports (Only From Subnets)

For each row: port is first globally denied, then allowed only from the subnet. Typical use: restrict 8080/8443 to internal networks.

Port Subnet / CIDR (e.g. 192.168.1.0/24)
Subnet examples: 192.168.1.0/24, 10.0.0.0/8, or a single IP like 203.0.113.5.
Use preview first to verify behaviour. Always test on a non-production system before applying to live servers.

Current UFW Status

Output of ufw status numbered: