%PDF- %PDF-
Direktori : /backups/router/usr/local/opnsense/mvc/app/controllers/OPNsense/Routing/Api/ |
Current File : //backups/router/usr/local/opnsense/mvc/app/controllers/OPNsense/Routing/Api/SettingsController.php |
<?php /* * Copyright (C) 2023 Deciso B.V. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ namespace OPNsense\Routing\Api; use OPNsense\Base\ApiMutableModelControllerBase; use OPNsense\Base\UserException; use OPNsense\Core\Backend; use OPNsense\Core\Config; use OPNsense\Firewall\Util; class SettingsController extends ApiMutableModelControllerBase { protected static $internalModelClass = '\OPNsense\Routing\Gateways'; protected static $internalModelName = 'gateways'; public function reconfigureAction() { $result = ["status" => "failed"]; if ($this->request->isPost()) { (new Backend())->configdRun('interface routes configure'); $result = ["status" => "ok"]; } return $result; } public function searchGatewayAction() { $cfg = Config::getInstance()->object(); $ifconfig = json_decode((new Backend())->configdRun('interface list ifconfig'), true); $gateways_status = json_decode((new Backend())->configdRun('interface gateways status'), true); $gateways = array_values($this->getModel()->gatewaysIndexedByName(true, false, true)); $down_gateways = !empty((string)$cfg->system->gw_switch_default) ? array_map(function ($gw) { if (str_contains($gw['status'], 'down')) { return $gw['name']; } }, $gateways_status) : []; $default_gwv4 = $this->getModel()->getDefaultGW($down_gateways, 'inet'); $default_gwv6 = $this->getModel()->getDefaultGW($down_gateways, 'inet6'); foreach ($gateways as $idx => $gateway) { if (empty($gateway['uuid'])) { $gateways[$idx]['uuid'] = $gateway['name']; } /* flags used by view to filter or format elements */ $gateways[$idx]['virtual'] = !empty($gateway['virtual']); $gateways[$idx]['disabled'] = !empty($gateway['disabled']); $gateways[$idx]['upstream'] = !empty($gateway['defaultgw']); $gateways[$idx]['defaultgw'] = false; foreach (['default_gwv4', 'default_gwv6'] as $default_gw) { /* gateway might be configured as defaultgw, whether it is active is determined here */ if (!empty($$default_gw)) { if ($gateway['name'] == $$default_gw['name']) { $gateways[$idx]['defaultgw'] = true; } } } /* format interface name */ $gateways[$idx]['interface_descr'] = (string)$cfg->interfaces->{$gateway['interface']}->descr ?: strtoupper($gateway['interface']); /* parse gateway and monitoring status */ $i = array_search($gateway['name'], array_column($gateways_status, 'name')); $gateways[$idx]['status'] = $i !== false ? $gateways_status[$i]['status_translated'] : 'Pending'; foreach (['delay', 'stddev', 'loss'] as $status_kw) { $gateways[$idx][$status_kw] = $i !== false ? $gateways_status[$i][$status_kw] : '~'; } $gateways[$idx]['label_class'] = 'fa fa-plug text-default'; if ($i !== false) { if (str_contains($gateways_status[$i]['status'], 'down')) { $gateways[$idx]['label_class'] = 'fa fa-plug text-danger'; } elseif (str_contains($gateways_status[$i]['status'], 'loss') || str_contains($gateways_status[$i]['status'], 'delay')) { $gateways[$idx]['label_class'] = 'fa fa-plug text-warning'; } elseif (str_contains($gateways_status[$i]['status'], 'none')) { $gateways[$idx]['label_class'] = 'fa fa-plug text-success'; } } elseif (empty($gateway['disabled']) && !empty($gateway['monitor_disable'])) { $gateways[$idx]['label_class'] = 'fa fa-plug text-success'; } /* warn about misconfigured gateways */ if (empty($gateway['fargw']) && array_key_exists('gateway', $gateway)) { if (Util::isIpAddress($gateway['gateway'])) { /* exclude non-static entries in the config */ $proto = $gateway['ipprotocol'] === 'inet' ? 'ipaddr' : 'ipaddrv6'; $ip = (string)$cfg->interfaces->{$gateway['interface']}->{$proto}; $include = (!empty($ip) && Util::isIpAddress($ip)); if ($include && array_key_exists($gateway['if'], $ifconfig)) { $ipproto = $gateway['ipprotocol'] === 'inet' ? 'ipv4' : 'ipv6'; $subnets = []; foreach ($ifconfig[$gateway['if']][$ipproto] as $ip) { if (!empty($ip['ipaddr']) && !empty($ip['subnetbits'])) { $subnets[] = $ip['ipaddr'] . '/' . $ip['subnetbits']; } } $match = false; foreach ($subnets as $subnet) { if (Util::isIPInCIDR($gateway['gateway'], $subnet)) { $match = true; break; } } if (empty($subnets) || !$match) { $gateways[$idx]['status'] = gettext('Misconfigured Gateway IP'); $gateways[$idx]['label_class'] = 'fa fa-plug text-warning'; } } } } if (empty($gateway['is_loopback']) && empty($gateway['if'])) { $gateways[$idx]['status'] = gettext('No interface attached'); $gateways[$idx]['label_class'] = 'fa fa-plug text-warning'; } } return $this->searchRecordsetBase($gateways); } public function getGatewayAction($uuid = null) { if (!$this->isValidUUID($uuid)) { /* uuid is likely a gateway name (legacy config) */ $gateway = $this->getModel()->gatewaysIndexedByName(true, false, true)[$uuid] ?? []; if (!empty($gateway)) { if (!empty($gateway['dynamic'])) { $gateway['gateway'] = null; } $node = $this->getModel()->gateway_item->Add(); $node->setNodes($gateway); return ['gateway_item' => $node->getNodes()]; } else { /* make sure getBase() returns a node */ $uuid = null; } } return $this->getBase('gateway_item', 'gateway_item', $uuid); } public function setGatewayAction($uuid) { if (!$this->isValidUUID($uuid)) { $mdl = $this->getModel(); $uuid = $mdl->gateway_item->generateUUID(); } $result = $this->setBase('gateway_item', 'gateway_item', $uuid); return $result; } public function addGatewayAction() { return $this->addBase("gateway_item", "gateway_item"); } public function delGatewayAction($uuid) { $result = ["result" => "failed"]; if ($this->request->isPost()) { if ($uuid != null) { $gateway = $this->getModel()->getNodeByReference('gateway_item.' . $uuid); $cfg = Config::getInstance()->object(); foreach ($cfg->interfaces->children() as $tag => $interface) { if ((string)$interface->gateway == (string)$gateway->name) { throw new UserException(sprintf( gettext("Gateway %s cannot be deleted because it is in use on Interface '%s'"), $gateway->name, $interface->descr ?? $tag )); } } $groups = []; foreach ($cfg->gateways->children() as $tag => $gw_group) { if ($tag == 'gateway_group' && !empty($gw_group)) { foreach ($gw_group->item as $item) { $name = explode("|", (string)$item); if ($name[0] == $gateway->name) { $groups[] = (string)$gw_group->name; } } } } if (!empty($groups)) { throw new UserException(sprintf( gettext("Gateway %s cannot be deleted because it is in use on Gateway Group(s) '%s'"), $gateway->name, implode(', ', $groups) )); } $routes = []; foreach ($cfg->staticroutes->children() as $route) { if (!empty($route)) { if ((string)$route->gateway == $gateway->name) { $routes[] = (string)$route->network; } } } if (!empty($routes)) { throw new UserException(sprintf( gettext("Gateway %s cannot be deleted because it is in use on Static Route(s) '%s'"), $gateway->name, implode(', ', $routes) )); } $result = $this->delBase('gateway_item', $uuid); } } return $result; } public function toggleGatewayAction($uuid, $enabled = null) { /* mimick default API "enable" behaviour by inverting. * it's not enough to invert the $enabled parameter, since * the toggle might be implicit. */ $result = array("result" => "failed"); if ($this->request->isPost()) { $mdl = $this->getModel(); if ($uuid != null) { $node = $mdl->getNodeByReference('gateway_item' . '.' . $uuid); if ($node != null) { $result['changed'] = true; if ($enabled == "0" || $enabled == "1") { /* invert "enabled" */ $disabled = $enabled == "0" ? "1" : "0"; $result['result'] = empty($disabled) ? "Enabled" : "Disabled"; $result['changed'] = (string)$node->disabled !== $disabled; $node->disabled = $disabled; } elseif ($enabled !== null) { // failed $result['changed'] = false; } elseif ((string)$node->disabled == "0") { $result['result'] = "Disabled"; $node->disabled = "1"; } else { $result['result'] = "Enabled"; $node->disabled = "0"; } // if item has toggled, serialize to config and save if ($result['changed']) { $this->save(); } } } } return $result; } }