Fix firewall API endpoints to use correct {interface} path parameter
- Firewall endpoints now use /firewall/{interface}/ where interface is
"primary" or "secondary" (was missing the interface segment)
- Add applyFirewallRulesets() method for applying predefined rulesets by ID
- Add firewallApplyRulesets client endpoint (comma-separated ruleset IDs)
- Add sanitizeFirewallInterface() helper for input validation
- All firewall methods now accept optional interface parameter (default: primary)
- Document that VirtFusion uses ruleset-based firewall (no individual rule CRUD)
- Update README with correct API paths and ruleset documentation
https://claude.ai/code/session_01TCsJ4WZCGuEX3zqh1tQ2zx
This commit is contained in:
@@ -178,10 +178,14 @@ switch ($action) {
|
||||
|
||||
// =================================================================
|
||||
// Firewall Management
|
||||
//
|
||||
// VirtFusion uses a ruleset-based system. Individual rules cannot
|
||||
// be added/deleted via the API. Rulesets are created in admin panel
|
||||
// and applied to servers by ID.
|
||||
// =================================================================
|
||||
|
||||
/**
|
||||
* Get firewall status and rules.
|
||||
* Get firewall status, rules, and assigned rulesets.
|
||||
*/
|
||||
case 'firewallStatus':
|
||||
|
||||
@@ -191,7 +195,8 @@ switch ($action) {
|
||||
$vf->output(['success' => false, 'errors' => 'service <> owner mismatch'], true, true, 403);
|
||||
}
|
||||
|
||||
$result = $vf->getFirewallStatus($serviceID);
|
||||
$interface = isset($_GET['interface']) ? preg_replace('/[^a-z]/', '', $_GET['interface']) : 'primary';
|
||||
$result = $vf->getFirewallStatus($serviceID, $interface);
|
||||
|
||||
if ($result !== false) {
|
||||
$vf->output(['success' => true, 'data' => $result], true, true, 200);
|
||||
@@ -211,7 +216,8 @@ switch ($action) {
|
||||
$vf->output(['success' => false, 'errors' => 'service <> owner mismatch'], true, true, 403);
|
||||
}
|
||||
|
||||
$result = $vf->enableFirewall($serviceID);
|
||||
$interface = isset($_GET['interface']) ? preg_replace('/[^a-z]/', '', $_GET['interface']) : 'primary';
|
||||
$result = $vf->enableFirewall($serviceID, $interface);
|
||||
|
||||
if ($result) {
|
||||
$vf->output(['success' => true, 'data' => ['message' => 'Firewall enabled successfully']], true, true, 200);
|
||||
@@ -231,7 +237,8 @@ switch ($action) {
|
||||
$vf->output(['success' => false, 'errors' => 'service <> owner mismatch'], true, true, 403);
|
||||
}
|
||||
|
||||
$result = $vf->disableFirewall($serviceID);
|
||||
$interface = isset($_GET['interface']) ? preg_replace('/[^a-z]/', '', $_GET['interface']) : 'primary';
|
||||
$result = $vf->disableFirewall($serviceID, $interface);
|
||||
|
||||
if ($result) {
|
||||
$vf->output(['success' => true, 'data' => ['message' => 'Firewall disabled successfully']], true, true, 200);
|
||||
@@ -241,7 +248,7 @@ switch ($action) {
|
||||
break;
|
||||
|
||||
/**
|
||||
* Apply/sync firewall rules.
|
||||
* Apply/sync firewall rules (re-applies currently assigned rulesets).
|
||||
*/
|
||||
case 'firewallApplyRules':
|
||||
|
||||
@@ -251,7 +258,8 @@ switch ($action) {
|
||||
$vf->output(['success' => false, 'errors' => 'service <> owner mismatch'], true, true, 403);
|
||||
}
|
||||
|
||||
$result = $vf->applyFirewallRules($serviceID);
|
||||
$interface = isset($_GET['interface']) ? preg_replace('/[^a-z]/', '', $_GET['interface']) : 'primary';
|
||||
$result = $vf->applyFirewallRules($serviceID, $interface);
|
||||
|
||||
if ($result) {
|
||||
$vf->output(['success' => true, 'data' => ['message' => 'Firewall rules applied successfully']], true, true, 200);
|
||||
@@ -260,6 +268,41 @@ switch ($action) {
|
||||
$vf->output(['success' => false, 'errors' => 'Failed to apply firewall rules'], true, true, 500);
|
||||
break;
|
||||
|
||||
/**
|
||||
* Apply specific firewall rulesets by ID.
|
||||
* Expects comma-separated ruleset IDs in the 'rulesets' parameter.
|
||||
*/
|
||||
case 'firewallApplyRulesets':
|
||||
|
||||
$serviceID = $vf->validateServiceID(true);
|
||||
|
||||
if (!$vf->validateUserOwnsService($serviceID)) {
|
||||
$vf->output(['success' => false, 'errors' => 'service <> owner mismatch'], true, true, 403);
|
||||
}
|
||||
|
||||
$rulesetsParam = isset($_GET['rulesets']) ? trim($_GET['rulesets']) : '';
|
||||
if (empty($rulesetsParam)) {
|
||||
$vf->output(['success' => false, 'errors' => 'No ruleset IDs provided'], true, true, 400);
|
||||
}
|
||||
|
||||
$rulesetIds = array_values(array_filter(array_map('intval', explode(',', $rulesetsParam)), function ($id) {
|
||||
return $id > 0;
|
||||
}));
|
||||
|
||||
if (empty($rulesetIds)) {
|
||||
$vf->output(['success' => false, 'errors' => 'Invalid ruleset IDs'], true, true, 400);
|
||||
}
|
||||
|
||||
$interface = isset($_GET['interface']) ? preg_replace('/[^a-z]/', '', $_GET['interface']) : 'primary';
|
||||
$result = $vf->applyFirewallRulesets($serviceID, $rulesetIds, $interface);
|
||||
|
||||
if ($result) {
|
||||
$vf->output(['success' => true, 'data' => ['message' => 'Firewall rulesets applied successfully']], true, true, 200);
|
||||
}
|
||||
|
||||
$vf->output(['success' => false, 'errors' => 'Failed to apply firewall rulesets'], true, true, 500);
|
||||
break;
|
||||
|
||||
// =================================================================
|
||||
// IP Address Management
|
||||
// =================================================================
|
||||
|
||||
@@ -299,24 +299,32 @@ class Module
|
||||
|
||||
// =========================================================================
|
||||
// Firewall Management
|
||||
//
|
||||
// VirtFusion uses a ruleset-based firewall system. Individual rules cannot
|
||||
// be created or deleted via the API. Instead, predefined rulesets (created
|
||||
// in the VirtFusion admin panel) are applied to servers by ID.
|
||||
//
|
||||
// The {interface} parameter is "primary" or "secondary".
|
||||
// =========================================================================
|
||||
|
||||
/**
|
||||
* Get firewall status and rules for a server.
|
||||
*
|
||||
* @param int $serviceID
|
||||
* @param string $interface Network interface: "primary" or "secondary"
|
||||
* @return array|false
|
||||
*/
|
||||
public function getFirewallStatus($serviceID)
|
||||
public function getFirewallStatus($serviceID, $interface = 'primary')
|
||||
{
|
||||
$serviceID = (int) $serviceID;
|
||||
$interface = $this->sanitizeFirewallInterface($interface);
|
||||
$service = Database::getSystemService($serviceID);
|
||||
|
||||
if ($service) {
|
||||
$whmcsService = Database::getWhmcsService($serviceID);
|
||||
$cp = $this->getCP($whmcsService->server);
|
||||
$request = $this->initCurl($cp['token']);
|
||||
$data = $request->get($cp['url'] . '/servers/' . (int) $service->server_id . '/firewall');
|
||||
$data = $request->get($cp['url'] . '/servers/' . (int) $service->server_id . '/firewall/' . $interface);
|
||||
|
||||
Log::insert(__FUNCTION__, $request->getRequestInfo(), $data);
|
||||
|
||||
@@ -331,18 +339,20 @@ class Module
|
||||
* Enable firewall on a server.
|
||||
*
|
||||
* @param int $serviceID
|
||||
* @param string $interface Network interface: "primary" or "secondary"
|
||||
* @return object|false
|
||||
*/
|
||||
public function enableFirewall($serviceID)
|
||||
public function enableFirewall($serviceID, $interface = 'primary')
|
||||
{
|
||||
$serviceID = (int) $serviceID;
|
||||
$interface = $this->sanitizeFirewallInterface($interface);
|
||||
$service = Database::getSystemService($serviceID);
|
||||
|
||||
if ($service) {
|
||||
$whmcsService = Database::getWhmcsService($serviceID);
|
||||
$cp = $this->getCP($whmcsService->server);
|
||||
$request = $this->initCurl($cp['token']);
|
||||
$data = $request->post($cp['url'] . '/servers/' . (int) $service->server_id . '/firewall/enable');
|
||||
$data = $request->post($cp['url'] . '/servers/' . (int) $service->server_id . '/firewall/' . $interface . '/enable');
|
||||
|
||||
Log::insert(__FUNCTION__, $request->getRequestInfo(), $data);
|
||||
|
||||
@@ -358,18 +368,20 @@ class Module
|
||||
* Disable firewall on a server.
|
||||
*
|
||||
* @param int $serviceID
|
||||
* @param string $interface Network interface: "primary" or "secondary"
|
||||
* @return object|false
|
||||
*/
|
||||
public function disableFirewall($serviceID)
|
||||
public function disableFirewall($serviceID, $interface = 'primary')
|
||||
{
|
||||
$serviceID = (int) $serviceID;
|
||||
$interface = $this->sanitizeFirewallInterface($interface);
|
||||
$service = Database::getSystemService($serviceID);
|
||||
|
||||
if ($service) {
|
||||
$whmcsService = Database::getWhmcsService($serviceID);
|
||||
$cp = $this->getCP($whmcsService->server);
|
||||
$request = $this->initCurl($cp['token']);
|
||||
$data = $request->post($cp['url'] . '/servers/' . (int) $service->server_id . '/firewall/disable');
|
||||
$data = $request->post($cp['url'] . '/servers/' . (int) $service->server_id . '/firewall/' . $interface . '/disable');
|
||||
|
||||
Log::insert(__FUNCTION__, $request->getRequestInfo(), $data);
|
||||
|
||||
@@ -382,32 +394,101 @@ class Module
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply/synchronize firewall rules on a server.
|
||||
* Apply firewall rulesets to a server.
|
||||
*
|
||||
* VirtFusion uses predefined rulesets (created in admin panel).
|
||||
* Individual rules cannot be added/deleted via the API.
|
||||
*
|
||||
* @param int $serviceID
|
||||
* @param array $rulesetIds Array of ruleset IDs to apply
|
||||
* @param string $interface Network interface: "primary" or "secondary"
|
||||
* @return object|false
|
||||
*/
|
||||
public function applyFirewallRules($serviceID)
|
||||
public function applyFirewallRulesets($serviceID, array $rulesetIds, $interface = 'primary')
|
||||
{
|
||||
$serviceID = (int) $serviceID;
|
||||
$interface = $this->sanitizeFirewallInterface($interface);
|
||||
|
||||
// Validate and sanitize ruleset IDs
|
||||
$rulesetIds = array_values(array_filter(array_map('intval', $rulesetIds), function ($id) {
|
||||
return $id > 0;
|
||||
}));
|
||||
|
||||
if (empty($rulesetIds)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$service = Database::getSystemService($serviceID);
|
||||
|
||||
if ($service) {
|
||||
$whmcsService = Database::getWhmcsService($serviceID);
|
||||
$cp = $this->getCP($whmcsService->server);
|
||||
$request = $this->initCurl($cp['token']);
|
||||
$data = $request->post($cp['url'] . '/servers/' . (int) $service->server_id . '/firewall/rules/apply');
|
||||
$request->addOption(CURLOPT_POSTFIELDS, json_encode(['rulesets' => $rulesetIds]));
|
||||
$data = $request->post($cp['url'] . '/servers/' . (int) $service->server_id . '/firewall/' . $interface . '/rules');
|
||||
|
||||
Log::insert(__FUNCTION__, $request->getRequestInfo(), $data);
|
||||
|
||||
$httpCode = $request->getRequestInfo('http_code');
|
||||
if ($httpCode == 200 || $httpCode == 204) {
|
||||
if ($httpCode == 200 || $httpCode == 201 || $httpCode == 204) {
|
||||
return json_decode($data) ?: (object) ['success' => true];
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Backward-compatible wrapper for applying firewall rules.
|
||||
* Syncs/applies existing ruleset assignments on the server.
|
||||
*
|
||||
* @param int $serviceID
|
||||
* @param string $interface Network interface: "primary" or "secondary"
|
||||
* @return object|false
|
||||
*/
|
||||
public function applyFirewallRules($serviceID, $interface = 'primary')
|
||||
{
|
||||
// Fetch current firewall status to get assigned rulesets
|
||||
$status = $this->getFirewallStatus($serviceID, $interface);
|
||||
if ($status && isset($status['data']['rulesets'])) {
|
||||
$rulesetIds = array_column($status['data']['rulesets'], 'id');
|
||||
if (!empty($rulesetIds)) {
|
||||
return $this->applyFirewallRulesets($serviceID, $rulesetIds, $interface);
|
||||
}
|
||||
}
|
||||
|
||||
// If no rulesets found, try a direct re-apply via the enable cycle
|
||||
$serviceID = (int) $serviceID;
|
||||
$interface = $this->sanitizeFirewallInterface($interface);
|
||||
$service = Database::getSystemService($serviceID);
|
||||
|
||||
if ($service) {
|
||||
$whmcsService = Database::getWhmcsService($serviceID);
|
||||
$cp = $this->getCP($whmcsService->server);
|
||||
$request = $this->initCurl($cp['token']);
|
||||
$request->addOption(CURLOPT_POSTFIELDS, json_encode(['rulesets' => []]));
|
||||
$data = $request->post($cp['url'] . '/servers/' . (int) $service->server_id . '/firewall/' . $interface . '/rules');
|
||||
|
||||
Log::insert(__FUNCTION__, $request->getRequestInfo(), $data);
|
||||
|
||||
$httpCode = $request->getRequestInfo('http_code');
|
||||
if ($httpCode == 200 || $httpCode == 201 || $httpCode == 204) {
|
||||
return json_decode($data) ?: (object) ['success' => true];
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitize firewall interface parameter.
|
||||
*
|
||||
* @param string $interface
|
||||
* @return string "primary" or "secondary"
|
||||
*/
|
||||
private function sanitizeFirewallInterface($interface)
|
||||
{
|
||||
return in_array($interface, ['primary', 'secondary'], true) ? $interface : 'primary';
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// IP Address Management
|
||||
// =========================================================================
|
||||
|
||||
Reference in New Issue
Block a user