mirror of
https://github.com/lucaspalomodevelop/core.git
synced 2026-03-14 00:24:40 +00:00
import net/os-firewall from plugins (https://github.com/opnsense/core/issues/6390)
This commit is contained in:
parent
3daff54655
commit
8e299d3efe
48
src/etc/inc/plugins.inc.d/pfplugin.inc
Normal file
48
src/etc/inc/plugins.inc.d/pfplugin.inc
Normal file
@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (C) 2020 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.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @param $fw
|
||||
*/
|
||||
function pfplugin_firewall($fw)
|
||||
{
|
||||
$mdlFilter = new OPNsense\Firewall\Filter();
|
||||
foreach ($mdlFilter->rules->rule->sortedBy(["sequence"]) as $key => $rule) {
|
||||
$content = $rule->serialize();
|
||||
$content["#ref"] = "ui/firewall/filter#" . (string)$rule->getAttributes()['uuid'];
|
||||
$fw->registerFilterRule($rule->getPriority(), $content);
|
||||
}
|
||||
|
||||
foreach ($mdlFilter->snatrules->rule->sortedBy(["sequence"]) as $key => $rule) {
|
||||
$fw->registerSNatRule(50, $rule->serialize());
|
||||
}
|
||||
foreach ($mdlFilter->npt->rule->sortedBy(["sequence"]) as $key => $rule) {
|
||||
$fw->registerNptRule(50, $rule->serialize());
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,178 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (C) 2020 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\Firewall\Api;
|
||||
|
||||
use OPNsense\Base\ApiMutableModelControllerBase;
|
||||
use OPNsense\Core\Backend;
|
||||
use OPNsense\Core\Config;
|
||||
use OPNsense\Firewall\Alias;
|
||||
use OPNsense\Firewall\Category;
|
||||
|
||||
/**
|
||||
* Class FilterBaseController implements actions for various types
|
||||
* @package OPNsense\Firewall\Api
|
||||
*/
|
||||
abstract class FilterBaseController extends ApiMutableModelControllerBase
|
||||
{
|
||||
protected static $internalModelName = 'filter';
|
||||
protected static $internalModelClass = 'OPNsense\Firewall\Filter';
|
||||
protected static $categorysource = null;
|
||||
|
||||
/**
|
||||
* list categories and usage
|
||||
* @return array
|
||||
*/
|
||||
public function listCategoriesAction()
|
||||
{
|
||||
$response = ['rows' => []];
|
||||
$catcount = [];
|
||||
if (!empty(static::$categorysource)) {
|
||||
$node = $this->getModel();
|
||||
foreach (explode('.', static::$categorysource) as $ref) {
|
||||
$node = $node->$ref;
|
||||
}
|
||||
foreach ($node->iterateItems() as $item) {
|
||||
if (!empty((string)$item->categories)) {
|
||||
foreach (explode(',', (string)$item->categories) as $cat) {
|
||||
if (!isset($catcount[$cat])) {
|
||||
$catcount[$cat] = 0;
|
||||
}
|
||||
$catcount[$cat] += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach ((new Category())->categories->category->iterateItems() as $key => $category) {
|
||||
$response['rows'][] = [
|
||||
"uuid" => $key,
|
||||
"name" => (string)$category->name,
|
||||
"color" => (string)$category->color,
|
||||
"used" => isset($catcount[$key]) ? $catcount[$key] : 0
|
||||
];
|
||||
}
|
||||
array_multisort(array_column($response['rows'], "name"), SORT_ASC, SORT_NATURAL, $response['rows']);
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* list of available network options
|
||||
* @return array
|
||||
*/
|
||||
public function listNetworkSelectOptionsAction()
|
||||
{
|
||||
$result = [
|
||||
'single' => [
|
||||
'label' => gettext("Single host or Network")
|
||||
],
|
||||
'aliases' => [
|
||||
'label' => gettext("Aliases"),
|
||||
'items' => []
|
||||
],
|
||||
'networks' => [
|
||||
'label' => gettext("Networks"),
|
||||
'items' => [
|
||||
'any' => gettext('any'),
|
||||
'(self)' => gettext("This Firewall")
|
||||
]
|
||||
]
|
||||
];
|
||||
foreach ((Config::getInstance()->object())->interfaces->children() as $ifname => $ifdetail) {
|
||||
$descr = htmlspecialchars(!empty($ifdetail->descr) ? $ifdetail->descr : strtoupper($ifname));
|
||||
$result['networks']['items'][$ifname] = $descr . " " . gettext("net");
|
||||
if (!isset($ifdetail->virtual)) {
|
||||
$result['networks']['items'][$ifname . "ip"] = $descr . " " . gettext("address");
|
||||
}
|
||||
}
|
||||
foreach ((new Alias())->aliases->alias->iterateItems() as $alias) {
|
||||
if (strpos((string)$alias->type, "port") === false) {
|
||||
$result['aliases']['items'][(string)$alias->name] = (string)$alias->name;
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
|
||||
public function applyAction($rollback_revision = null)
|
||||
{
|
||||
if ($this->request->isPost()) {
|
||||
if ($rollback_revision != null) {
|
||||
// background rollback timer
|
||||
(new Backend())->configdpRun('pfplugin rollback_timer', [$rollback_revision], true);
|
||||
}
|
||||
return array("status" => (new Backend())->configdRun('filter reload'));
|
||||
} else {
|
||||
return array("status" => "error");
|
||||
}
|
||||
}
|
||||
|
||||
public function cancelRollbackAction($rollback_revision)
|
||||
{
|
||||
if ($this->request->isPost()) {
|
||||
return array(
|
||||
"status" => (new Backend())->configdpRun('pfplugin cancel_rollback', [$rollback_revision])
|
||||
);
|
||||
} else {
|
||||
return array("status" => "error");
|
||||
}
|
||||
}
|
||||
|
||||
public function savepointAction()
|
||||
{
|
||||
if ($this->request->isPost()) {
|
||||
// trigger a save, so we know revision->time matches our running config
|
||||
Config::getInstance()->save();
|
||||
return array(
|
||||
"status" => "ok",
|
||||
"retention" => (string)Config::getInstance()->backupCount(),
|
||||
"revision" => (string)Config::getInstance()->object()->revision->time
|
||||
);
|
||||
} else {
|
||||
return array("status" => "error");
|
||||
}
|
||||
}
|
||||
|
||||
public function revertAction($revision)
|
||||
{
|
||||
if ($this->request->isPost()) {
|
||||
Config::getInstance()->lock();
|
||||
$filename = Config::getInstance()->getBackupFilename($revision);
|
||||
if (!$filename) {
|
||||
Config::getInstance()->unlock();
|
||||
return ["status" => gettext("unknown (or removed) savepoint")];
|
||||
}
|
||||
$this->getModel()->rollback($revision);
|
||||
Config::getInstance()->unlock();
|
||||
(new Backend())->configdRun('filter reload');
|
||||
return ["status" => "ok"];
|
||||
} else {
|
||||
return array("status" => "error");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (C) 2020 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\Firewall\Api;
|
||||
|
||||
class FilterController extends FilterBaseController
|
||||
{
|
||||
protected static $categorysource = "rules.rule";
|
||||
|
||||
public function searchRuleAction()
|
||||
{
|
||||
$category = $this->request->get('category');
|
||||
$filter_funct = function ($record) use ($category) {
|
||||
return empty($category) || array_intersect(explode(',', $record->categories), $category);
|
||||
};
|
||||
return $this->searchBase("rules.rule", ['enabled', 'sequence', 'description'], "sequence", $filter_funct);
|
||||
}
|
||||
|
||||
public function setRuleAction($uuid)
|
||||
{
|
||||
return $this->setBase("rule", "rules.rule", $uuid);
|
||||
}
|
||||
|
||||
public function addRuleAction()
|
||||
{
|
||||
return $this->addBase("rule", "rules.rule");
|
||||
}
|
||||
|
||||
public function getRuleAction($uuid = null)
|
||||
{
|
||||
return $this->getBase("rule", "rules.rule", $uuid);
|
||||
}
|
||||
|
||||
public function delRuleAction($uuid)
|
||||
{
|
||||
return $this->delBase("rules.rule", $uuid);
|
||||
}
|
||||
|
||||
public function toggleRuleAction($uuid, $enabled = null)
|
||||
{
|
||||
return $this->toggleBase("rules.rule", $uuid, $enabled);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,72 @@
|
||||
<?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\Firewall\Api;
|
||||
|
||||
class NptController extends FilterBaseController
|
||||
{
|
||||
protected static $categorysource = "npt.rule";
|
||||
|
||||
public function searchRuleAction()
|
||||
{
|
||||
$category = $this->request->get('category');
|
||||
$filter_funct = function ($record) use ($category) {
|
||||
return empty($category) || array_intersect(explode(',', $record->categories), $category);
|
||||
};
|
||||
return $this->searchBase(
|
||||
"npt.rule",
|
||||
['enabled', 'sequence', 'source_net', 'destination_net', 'trackif', 'description'],
|
||||
"sequence",
|
||||
$filter_funct
|
||||
);
|
||||
}
|
||||
|
||||
public function setRuleAction($uuid)
|
||||
{
|
||||
return $this->setBase("rule", "npt.rule", $uuid);
|
||||
}
|
||||
|
||||
public function addRuleAction()
|
||||
{
|
||||
return $this->addBase("rule", "npt.rule");
|
||||
}
|
||||
|
||||
public function getRuleAction($uuid = null)
|
||||
{
|
||||
return $this->getBase("rule", "npt.rule", $uuid);
|
||||
}
|
||||
|
||||
public function delRuleAction($uuid)
|
||||
{
|
||||
return $this->delBase("npt.rule", $uuid);
|
||||
}
|
||||
|
||||
public function toggleRuleAction($uuid, $enabled = null)
|
||||
{
|
||||
return $this->toggleBase("npt.rule", $uuid, $enabled);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (C) 2020 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\Firewall\Api;
|
||||
|
||||
class SourceNatController extends FilterBaseController
|
||||
{
|
||||
protected static $categorysource = "snatrules.rule";
|
||||
|
||||
public function searchRuleAction()
|
||||
{
|
||||
$category = $this->request->get('category');
|
||||
$filter_funct = function ($record) use ($category) {
|
||||
return empty($category) || array_intersect(explode(',', $record->categories), $category);
|
||||
};
|
||||
return $this->searchBase("snatrules.rule", ['enabled', 'sequence', 'description'], "sequence", $filter_funct);
|
||||
}
|
||||
|
||||
public function setRuleAction($uuid)
|
||||
{
|
||||
return $this->setBase("rule", "snatrules.rule", $uuid);
|
||||
}
|
||||
|
||||
public function addRuleAction()
|
||||
{
|
||||
return $this->addBase("rule", "snatrules.rule");
|
||||
}
|
||||
|
||||
public function getRuleAction($uuid = null)
|
||||
{
|
||||
return $this->getBase("rule", "snatrules.rule", $uuid);
|
||||
}
|
||||
|
||||
public function delRuleAction($uuid)
|
||||
{
|
||||
return $this->delBase("snatrules.rule", $uuid);
|
||||
}
|
||||
|
||||
public function toggleRuleAction($uuid, $enabled = null)
|
||||
{
|
||||
return $this->toggleBase("snatrules.rule", $uuid, $enabled);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (C) 2020 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\Firewall;
|
||||
|
||||
class FilterController extends \OPNsense\Base\IndexController
|
||||
{
|
||||
public function indexAction()
|
||||
{
|
||||
$this->view->pick('OPNsense/Firewall/filter');
|
||||
$this->view->ruleController = "filter";
|
||||
$this->view->gridFields = [
|
||||
[
|
||||
'id' => 'enabled', 'formatter' => 'rowtoggle' ,'width' => '6em', 'heading' => gettext('Enabled')
|
||||
],
|
||||
[
|
||||
'id' => 'sequence','width' => '9em', 'heading' => gettext('Sequence')
|
||||
],
|
||||
[
|
||||
'id' => 'description', 'heading' => gettext('Description')
|
||||
]
|
||||
];
|
||||
$this->view->formDialogFilterRule = $this->getForm("dialogFilterRule");
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,60 @@
|
||||
<?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\Firewall;
|
||||
|
||||
class NptController extends \OPNsense\Base\IndexController
|
||||
{
|
||||
public function indexAction()
|
||||
{
|
||||
$this->view->pick('OPNsense/Firewall/filter');
|
||||
$this->view->ruleController = "npt";
|
||||
$this->view->hideSavePointBtns = true;
|
||||
$this->view->gridFields = [
|
||||
[
|
||||
'id' => 'enabled', 'formatter' => 'rowtoggle' ,'width' => '6em', 'heading' => gettext('Enabled')
|
||||
],
|
||||
[
|
||||
'id' => 'sequence','width' => '9em', 'heading' => gettext('Sequence')
|
||||
],
|
||||
[
|
||||
'id' => 'source_net', 'heading' => gettext('Internal IPv6 Prefix')
|
||||
],
|
||||
[
|
||||
'id' => 'destination_net', 'heading' => gettext('External IPv6 Prefix')
|
||||
],
|
||||
[
|
||||
'id' => 'trackif', 'heading' => gettext('Track if')
|
||||
],
|
||||
[
|
||||
'id' => 'description', 'heading' => gettext('Description')
|
||||
]
|
||||
];
|
||||
|
||||
$this->view->formDialogFilterRule = $this->getForm("dialogNptRule");
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (C) 2020 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\Firewall;
|
||||
|
||||
class SourceNatController extends \OPNsense\Base\IndexController
|
||||
{
|
||||
public function indexAction()
|
||||
{
|
||||
$this->view->pick('OPNsense/Firewall/filter');
|
||||
$this->view->ruleController = "source_nat";
|
||||
$this->view->gridFields = [
|
||||
[
|
||||
'id' => 'enabled', 'formatter' => 'rowtoggle' ,'width' => '6em', 'heading' => gettext('Enabled')
|
||||
],
|
||||
[
|
||||
'id' => 'sequence','width' => '9em', 'heading' => gettext('Sequence')
|
||||
],
|
||||
[
|
||||
'id' => 'description', 'heading' => gettext('Description')
|
||||
]
|
||||
];
|
||||
$this->view->formDialogFilterRule = $this->getForm("dialogSNatRule");
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,114 @@
|
||||
<form>
|
||||
<field>
|
||||
<id>rule.enabled</id>
|
||||
<label>enabled</label>
|
||||
<type>checkbox</type>
|
||||
<help>Enable this rule</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>rule.sequence</id>
|
||||
<label>Sequence</label>
|
||||
<type>text</type>
|
||||
</field>
|
||||
<field>
|
||||
<id>rule.action</id>
|
||||
<label>Action</label>
|
||||
<type>dropdown</type>
|
||||
<help>Choose what to do with packets that match the criteria specified below.
|
||||
Hint: the difference between block and reject is that with reject, a packet (TCP RST or ICMP port unreachable for UDP) is returned to the sender, whereas with block the packet is dropped silently. In either case, the original packet is discarded.
|
||||
</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>rule.quick</id>
|
||||
<label>Quick</label>
|
||||
<type>checkbox</type>
|
||||
<help>
|
||||
If a packet matches a rule specifying quick, then that rule is considered the last matching rule and the specified action is taken.
|
||||
When a rule does not have quick enabled, the last matching rule wins.
|
||||
</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>rule.interface</id>
|
||||
<label>Interface</label>
|
||||
<type>select_multiple</type>
|
||||
</field>
|
||||
<field>
|
||||
<id>rule.direction</id>
|
||||
<label>Direction</label>
|
||||
<type>dropdown</type>
|
||||
<help>
|
||||
Direction of the traffic. The default policy is to filter inbound traffic, which sets the policy to the interface originally receiving the traffic.
|
||||
</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>rule.ipprotocol</id>
|
||||
<label>TCP/IP Version</label>
|
||||
<type>dropdown</type>
|
||||
</field>
|
||||
<field>
|
||||
<id>rule.protocol</id>
|
||||
<label>Protocol</label>
|
||||
<type>dropdown</type>
|
||||
</field>
|
||||
<field>
|
||||
<id>rule.source_net</id>
|
||||
<label>Source</label>
|
||||
<type>text</type>
|
||||
</field>
|
||||
<field>
|
||||
<id>rule.source_port</id>
|
||||
<label>Source port</label>
|
||||
<type>text</type>
|
||||
<advanced>true</advanced>
|
||||
<help>Source port number or well known name (imap, imaps, http, https, ...), for ranges use a dash</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>rule.source_not</id>
|
||||
<label>Source / Invert</label>
|
||||
<type>checkbox</type>
|
||||
<help>Use this option to invert the sense of the match.</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>rule.destination_net</id>
|
||||
<label>Destination</label>
|
||||
<type>text</type>
|
||||
</field>
|
||||
<field>
|
||||
<id>rule.destination_not</id>
|
||||
<label>Destination / Invert</label>
|
||||
<type>checkbox</type>
|
||||
<help>Use this option to invert the sense of the match.</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>rule.destination_port</id>
|
||||
<label>Destination port</label>
|
||||
<type>text</type>
|
||||
<help>Destination port number or well known name (imap, imaps, http, https, ...), for ranges use a dash</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>rule.gateway</id>
|
||||
<label>Gateway</label>
|
||||
<type>dropdown</type>
|
||||
<help>
|
||||
Leave as 'default' to use the system routing table. Or choose a gateway to utilize policy based routing.
|
||||
</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>rule.log</id>
|
||||
<label>Log</label>
|
||||
<type>checkbox</type>
|
||||
<help>Log packets that are handled by this rule</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>rule.categories</id>
|
||||
<label>Categories</label>
|
||||
<type>select_multiple</type>
|
||||
<style>tokenize</style>
|
||||
<help>For grouping purposes you may select multiple groups here to organize items.</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>rule.description</id>
|
||||
<label>Description</label>
|
||||
<type>text</type>
|
||||
</field>
|
||||
</form>
|
||||
@ -0,0 +1,53 @@
|
||||
<form>
|
||||
<field>
|
||||
<id>rule.enabled</id>
|
||||
<label>enabled</label>
|
||||
<type>checkbox</type>
|
||||
<help>Enable this rule</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>rule.sequence</id>
|
||||
<label>Sequence</label>
|
||||
<type>text</type>
|
||||
</field>
|
||||
<field>
|
||||
<id>rule.log</id>
|
||||
<label>Log</label>
|
||||
<type>checkbox</type>
|
||||
<help>Log packets that are handled by this rule</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>rule.interface</id>
|
||||
<label>Interface</label>
|
||||
<type>dropdown</type>
|
||||
</field>
|
||||
<field>
|
||||
<id>rule.source_net</id>
|
||||
<label>Internal IPv6 Prefix (source)</label>
|
||||
<type>text</type>
|
||||
</field>
|
||||
<field>
|
||||
<id>rule.destination_net</id>
|
||||
<label>External IPv6 Prefix (target)</label>
|
||||
<type>text</type>
|
||||
<help>Enter the external IPv6 prefix for this network prefix translation. Leave empty to auto-detect the prefix address using the specified tracking interface instead. The prefix size specified for the internal prefix will also be applied to the external prefix.</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>rule.trackif</id>
|
||||
<label>Track interface</label>
|
||||
<type>dropdown</type>
|
||||
<help>Use prefix defined on the selected interface instead of the interface this rule applies to when target prefix is not provided.</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>rule.categories</id>
|
||||
<label>Categories</label>
|
||||
<type>select_multiple</type>
|
||||
<style>tokenize</style>
|
||||
<help>For grouping purposes you may select multiple groups here to organize items.</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>rule.description</id>
|
||||
<label>Description</label>
|
||||
<type>text</type>
|
||||
</field>
|
||||
</form>
|
||||
@ -0,0 +1,101 @@
|
||||
<form>
|
||||
<field>
|
||||
<id>rule.enabled</id>
|
||||
<label>enabled</label>
|
||||
<type>checkbox</type>
|
||||
<help>Enable this rule</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>rule.nonat</id>
|
||||
<label>Do not NAT</label>
|
||||
<type>checkbox</type>
|
||||
<help>Enabling this option will disable NAT for traffic matching this rule and stop processing Outbound NAT rules.</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>rule.sequence</id>
|
||||
<label>Sequence</label>
|
||||
<type>text</type>
|
||||
</field>
|
||||
<field>
|
||||
<id>rule.interface</id>
|
||||
<label>Interface</label>
|
||||
<type>dropdown</type>
|
||||
</field>
|
||||
<field>
|
||||
<id>rule.ipprotocol</id>
|
||||
<label>TCP/IP Version</label>
|
||||
<type>dropdown</type>
|
||||
</field>
|
||||
<field>
|
||||
<id>rule.protocol</id>
|
||||
<label>Protocol</label>
|
||||
<type>dropdown</type>
|
||||
</field>
|
||||
<field>
|
||||
<id>rule.source_net</id>
|
||||
<label>Source</label>
|
||||
<type>text</type>
|
||||
</field>
|
||||
<field>
|
||||
<id>rule.source_port</id>
|
||||
<label>Source port</label>
|
||||
<type>text</type>
|
||||
<advanced>true</advanced>
|
||||
<help>Source port number or well known name (imap, imaps, http, https, ...), for ranges use a dash</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>rule.source_not</id>
|
||||
<label>Source / Invert</label>
|
||||
<type>checkbox</type>
|
||||
<help>Use this option to invert the sense of the match.</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>rule.destination_net</id>
|
||||
<label>Destination</label>
|
||||
<type>text</type>
|
||||
</field>
|
||||
<field>
|
||||
<id>rule.destination_not</id>
|
||||
<label>Destination / Invert</label>
|
||||
<type>checkbox</type>
|
||||
<help>Use this option to invert the sense of the match.</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>rule.destination_port</id>
|
||||
<label>Destination port</label>
|
||||
<type>text</type>
|
||||
<help>Destination port number or well known name (imap, imaps, http, https, ...), for ranges use a dash</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>rule.target</id>
|
||||
<label>Translation / target</label>
|
||||
<type>text</type>
|
||||
<help>
|
||||
Packets matching this rule will be mapped to the IP address given here.
|
||||
</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>rule.target_port</id>
|
||||
<label>Translation port</label>
|
||||
<type>text</type>
|
||||
<help>Destination port number or well known name (imap, imaps, http, https, ...)</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>rule.log</id>
|
||||
<label>Log</label>
|
||||
<type>checkbox</type>
|
||||
<help>Log packets that are handled by this rule</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>rule.categories</id>
|
||||
<label>Categories</label>
|
||||
<type>select_multiple</type>
|
||||
<style>tokenize</style>
|
||||
<help>For grouping purposes you may select multiple groups here to organize items.</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>rule.description</id>
|
||||
<label>Description</label>
|
||||
<type>text</type>
|
||||
</field>
|
||||
</form>
|
||||
16
src/opnsense/mvc/app/models/OPNsense/Firewall/ACL/ACL.xml
Normal file
16
src/opnsense/mvc/app/models/OPNsense/Firewall/ACL/ACL.xml
Normal file
@ -0,0 +1,16 @@
|
||||
<acl>
|
||||
<page-filter-api>
|
||||
<name>Firewall: Rules: API</name>
|
||||
<patterns>
|
||||
<pattern>ui/firewall/filter/*</pattern>
|
||||
<pattern>api/firewall/filter/*</pattern>
|
||||
</patterns>
|
||||
</page-filter-api>
|
||||
<page-filter-snat-api>
|
||||
<name>Firewall: SourceNat: API</name>
|
||||
<patterns>
|
||||
<pattern>ui/firewall/source_nat/*</pattern>
|
||||
<pattern>api/firewall/source_nat/*</pattern>
|
||||
</patterns>
|
||||
</page-filter-snat-api>
|
||||
</acl>
|
||||
@ -0,0 +1,140 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Copyright (C) 2020 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\Firewall\FieldTypes;
|
||||
|
||||
use OPNsense\Core\Config;
|
||||
use OPNsense\Base\FieldTypes\ArrayField;
|
||||
use OPNsense\Base\FieldTypes\ContainerField;
|
||||
|
||||
/**
|
||||
* Class FilterRuleContainerField
|
||||
* @package OPNsense\Firewall\FieldTypes
|
||||
*/
|
||||
class FilterRuleContainerField extends ContainerField
|
||||
{
|
||||
/**
|
||||
* map rules
|
||||
* @return array
|
||||
*/
|
||||
public function serialize()
|
||||
{
|
||||
$result = array();
|
||||
$map_manual = ['source_net', 'source_not', 'source_port', 'destination_net', 'destination_not',
|
||||
'destination_port', 'enabled', 'description', 'sequence', 'action'];
|
||||
// 1-on-1 map (with type conversion if needed)
|
||||
foreach ($this->iterateItems() as $key => $node) {
|
||||
if (!in_array($key, $map_manual)) {
|
||||
if (is_a($node, "OPNsense\\Base\\FieldTypes\\BooleanField")) {
|
||||
$result[$key] = !empty((string)$node);
|
||||
} elseif (is_a($node, "OPNsense\\Base\\FieldTypes\\ProtocolField")) {
|
||||
if ((string)$node != 'any') {
|
||||
$result[$key] = (string)$node;
|
||||
}
|
||||
} else {
|
||||
$result[$key] = (string)$node;
|
||||
}
|
||||
}
|
||||
}
|
||||
// source / destination mapping
|
||||
$result['source'] = array();
|
||||
if (!empty((string)$this->source_net)) {
|
||||
$result['source']['network'] = (string)$this->source_net;
|
||||
if (!empty((string)$this->source_not)) {
|
||||
$result['source']['not'] = true;
|
||||
}
|
||||
if (!empty((string)$this->source_port)) {
|
||||
$result['source']['port'] = (string)$this->source_port;
|
||||
}
|
||||
}
|
||||
$result['destination'] = array();
|
||||
if (!empty((string)$this->destination_net)) {
|
||||
$result['destination']['network'] = (string)$this->destination_net;
|
||||
if (!empty((string)$this->destination_not)) {
|
||||
$result['destination']['not'] = true;
|
||||
}
|
||||
if (!empty((string)$this->destination_port)) {
|
||||
$result['destination']['port'] = (string)$this->destination_port;
|
||||
}
|
||||
}
|
||||
// field mappings and differences
|
||||
$result['disabled'] = empty((string)$this->enabled);
|
||||
$result['descr'] = (string)$this->description;
|
||||
$result['type'] = (string)$this->action;
|
||||
if (strpos((string)$this->interface, ",") !== false) {
|
||||
$result['floating'] = true;
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* rule priority is threaded equally to the legacy rules, first "floating" then groups and single interface
|
||||
* rules are handled last
|
||||
* @return int priority in the ruleset, sequence should determine sort order.
|
||||
*/
|
||||
public function getPriority()
|
||||
{
|
||||
$configObj = Config::getInstance()->object();
|
||||
$interface = (string)$this->interface;
|
||||
if (strpos($interface, ",") !== false) {
|
||||
// floating (multiple interfaces involved)
|
||||
return 1000;
|
||||
} elseif (
|
||||
!empty($configObj->interfaces) &&
|
||||
!empty($configObj->interfaces->$interface) &&
|
||||
!empty($configObj->interfaces->$interface->type) &&
|
||||
$configObj->interfaces->$interface->type == 'group'
|
||||
) {
|
||||
// group type
|
||||
return 2000;
|
||||
} else {
|
||||
// default
|
||||
return 3000;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Class FilterRuleField
|
||||
* @package OPNsense\Firewall\FieldTypes
|
||||
*/
|
||||
class FilterRuleField extends ArrayField
|
||||
{
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function newContainerField($ref, $tagname)
|
||||
{
|
||||
$container_node = new FilterRuleContainerField($ref, $tagname);
|
||||
$parentmodel = $this->getParentModel();
|
||||
$container_node->setParentModel($parentmodel);
|
||||
return $container_node;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,113 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Copyright (C) 2020 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\Firewall\FieldTypes;
|
||||
|
||||
use OPNsense\Base\FieldTypes\ArrayField;
|
||||
use OPNsense\Base\FieldTypes\ContainerField;
|
||||
|
||||
/**
|
||||
* Class SourceNatRuleContainerField
|
||||
* @package OPNsense\Firewall\FieldTypes
|
||||
*/
|
||||
class SourceNatRuleContainerField extends ContainerField
|
||||
{
|
||||
/**
|
||||
* map source nat rules
|
||||
* @return array
|
||||
*/
|
||||
public function serialize()
|
||||
{
|
||||
$result = [];
|
||||
$source_mapper = [
|
||||
'enabled' => false,
|
||||
'source_net' => false,
|
||||
'source_not' => false,
|
||||
'source_port' => 'sourceport',
|
||||
'destination_net' => false,
|
||||
'destination_not' => false,
|
||||
'destination_port' => 'dstport',
|
||||
'target_port' => 'natport',
|
||||
'description' => 'descr'
|
||||
];
|
||||
// 1-on-1 map (with type conversion if needed)
|
||||
foreach ($this->iterateItems() as $key => $node) {
|
||||
$target_fieldname = isset($source_mapper[$key]) ? $source_mapper[$key] : $key;
|
||||
if ($target_fieldname) {
|
||||
if (is_a($node, "OPNsense\\Base\\FieldTypes\\BooleanField")) {
|
||||
$result[$target_fieldname] = !empty((string)$node);
|
||||
} elseif (is_a($node, "OPNsense\\Base\\FieldTypes\\ProtocolField")) {
|
||||
if ((string)$node != 'any') {
|
||||
$result[$target_fieldname] = (string)$node;
|
||||
}
|
||||
} else {
|
||||
$result[$target_fieldname] = (string)$node;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$result['disabled'] = empty((string)$this->enabled);
|
||||
// source / destination mapping, doesn't use port construct like it would for rules.
|
||||
$result['source'] = array();
|
||||
if (!empty((string)$this->source_net)) {
|
||||
$result['source']['network'] = (string)$this->source_net;
|
||||
if (!empty((string)$this->source_not)) {
|
||||
$result['source']['not'] = true;
|
||||
}
|
||||
}
|
||||
$result['destination'] = array();
|
||||
if (!empty((string)$this->destination_net)) {
|
||||
$result['destination']['network'] = (string)$this->destination_net;
|
||||
if (!empty((string)$this->destination_not)) {
|
||||
$result['destination']['not'] = true;
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Class SourceNatRuleField
|
||||
* @package OPNsense\Firewall\FieldTypes
|
||||
*/
|
||||
class SourceNatRuleField extends ArrayField
|
||||
{
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function newContainerField($ref, $tagname)
|
||||
{
|
||||
$container_node = new SourceNatRuleContainerField($ref, $tagname);
|
||||
$parentmodel = $this->getParentModel();
|
||||
$container_node->setParentModel($parentmodel);
|
||||
return $container_node;
|
||||
}
|
||||
}
|
||||
145
src/opnsense/mvc/app/models/OPNsense/Firewall/Filter.php
Normal file
145
src/opnsense/mvc/app/models/OPNsense/Firewall/Filter.php
Normal file
@ -0,0 +1,145 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (C) 2020 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\Firewall;
|
||||
|
||||
use OPNsense\Core\Config;
|
||||
use Phalcon\Messages\Message;
|
||||
use OPNsense\Base\BaseModel;
|
||||
use OPNsense\Firewall\Util;
|
||||
|
||||
class Filter extends BaseModel
|
||||
{
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function performValidation($validateFullModel = false)
|
||||
{
|
||||
// standard model validations
|
||||
$messages = parent::performValidation($validateFullModel);
|
||||
foreach ([$this->rules->rule, $this->snatrules->rule] as $rules) {
|
||||
foreach ($rules->iterateItems() as $rule) {
|
||||
if ($validateFullModel || $rule->isFieldChanged()) {
|
||||
// port / protocol validation
|
||||
if (!empty((string)$rule->source_port) && !in_array($rule->protocol, ['TCP', 'UDP'])) {
|
||||
$messages->appendMessage(new Message(
|
||||
gettext("Source ports are only valid for tcp or udp type rules."),
|
||||
$rule->source_port->__reference
|
||||
));
|
||||
}
|
||||
if (!empty((string)$rule->destination_port) && !in_array($rule->protocol, ['TCP', 'UDP'])) {
|
||||
$messages->appendMessage(new Message(
|
||||
gettext("Destination ports are only valid for tcp or udp type rules."),
|
||||
$rule->destination_port->__reference
|
||||
));
|
||||
}
|
||||
// validate protocol family
|
||||
$dest_is_addr = Util::isSubnet($rule->destination_net) || Util::isIpAddress($rule->destination_net);
|
||||
$dest_proto = strpos($rule->destination_net, ':') === false ? "inet" : "inet6";
|
||||
if ($dest_is_addr && $dest_proto != $rule->ipprotocol) {
|
||||
$messages->appendMessage(new Message(
|
||||
gettext("Destination address type should match selected TCP/IP protocol version."),
|
||||
$rule->destination_net->__reference
|
||||
));
|
||||
}
|
||||
$src_is_addr = Util::isSubnet($rule->source_net) || Util::isIpAddress($rule->source_net);
|
||||
$src_proto = strpos($rule->source_net, ':') === false ? "inet" : "inet6";
|
||||
if ($src_is_addr && $src_proto != $rule->ipprotocol) {
|
||||
$messages->appendMessage(new Message(
|
||||
gettext("Source address type should match selected TCP/IP protocol version."),
|
||||
$rule->source_net->__reference
|
||||
));
|
||||
}
|
||||
// Additional source nat validations
|
||||
if ($rule->target !== null) {
|
||||
$target_is_addr = Util::isSubnet($rule->target) || Util::isIpAddress($rule->target);
|
||||
$target_proto = strpos($rule->target, ':') === false ? "inet" : "inet6";
|
||||
if ($target_is_addr && $target_proto != $rule->ipprotocol) {
|
||||
$messages->appendMessage(new Message(
|
||||
gettext("Target address type should match selected TCP/IP protocol version."),
|
||||
$rule->target->__reference
|
||||
));
|
||||
}
|
||||
if (!empty((string)$rule->target_port) && !in_array($rule->protocol, ['TCP', 'UDP'])) {
|
||||
$messages->appendMessage(new Message(
|
||||
gettext("Target ports are only valid for tcp or udp type rules."),
|
||||
$rule->target_port->__reference
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach ($this->npt->rule->iterateItems() as $rule) {
|
||||
if ($validateFullModel || $rule->isFieldChanged()) {
|
||||
if (!empty((string)$rule->destination_net) && !empty((string)$rule->trackif)) {
|
||||
$messages->appendMessage(new Message(
|
||||
gettext("A track interface is only allowed without an extrenal prefix."),
|
||||
$rule->trackif->__reference
|
||||
));
|
||||
}
|
||||
if (!empty((string)$rule->destination_net) && !empty((string)$rule->source_net)) {
|
||||
$dparts = explode('/', (string)$rule->destination_net);
|
||||
$sparts = explode('/', (string)$rule->source_net);
|
||||
if (count($dparts) == 2 && count($sparts) == 2 && $dparts[1] != $sparts[1]) {
|
||||
$messages->appendMessage(new Message(
|
||||
gettext("External subnet should match internal subnet."),
|
||||
$rule->destination_net->__reference
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $messages;
|
||||
}
|
||||
|
||||
/**
|
||||
* Rollback this model to a previous version.
|
||||
* Make sure to remove this object afterwards, since its contents won't be updated.
|
||||
* @param $revision float|string revision number
|
||||
* @return bool action performed (backup revision existed)
|
||||
*/
|
||||
public function rollback($revision)
|
||||
{
|
||||
$filename = Config::getInstance()->getBackupFilename($revision);
|
||||
if ($filename) {
|
||||
// fiddle with the dom, copy OPNsense->Firewall->Filter from backup to current config
|
||||
$sourcexml = simplexml_load_file($filename);
|
||||
if ($sourcexml->OPNsense->Firewall->Filter) {
|
||||
$sourcedom = dom_import_simplexml($sourcexml->OPNsense->Firewall->Filter);
|
||||
$targetxml = Config::getInstance()->object();
|
||||
$targetdom = dom_import_simplexml($targetxml->OPNsense->Firewall->Filter);
|
||||
$node = $targetdom->ownerDocument->importNode($sourcedom, true);
|
||||
$targetdom->parentNode->replaceChild($node, $targetdom);
|
||||
Config::getInstance()->save();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
270
src/opnsense/mvc/app/models/OPNsense/Firewall/Filter.xml
Normal file
270
src/opnsense/mvc/app/models/OPNsense/Firewall/Filter.xml
Normal file
@ -0,0 +1,270 @@
|
||||
<model>
|
||||
<mount>//OPNsense/Firewall/Filter</mount>
|
||||
<version>1.0.2</version>
|
||||
<migration_prefix>MFP</migration_prefix>
|
||||
<description>
|
||||
OPNsense firewall filter rules
|
||||
</description>
|
||||
<items>
|
||||
<rules>
|
||||
<rule type=".\FilterRuleField">
|
||||
<enabled type="BooleanField">
|
||||
<Default>1</Default>
|
||||
<Required>Y</Required>
|
||||
</enabled>
|
||||
<sequence type="IntegerField">
|
||||
<MinimumValue>1</MinimumValue>
|
||||
<MaximumValue>99999</MaximumValue>
|
||||
<ValidationMessage>provide a valid sequence for sorting</ValidationMessage>
|
||||
<Required>Y</Required>
|
||||
<Default>1</Default>
|
||||
</sequence>
|
||||
<action type="OptionField">
|
||||
<Required>Y</Required>
|
||||
<Default>pass</Default>
|
||||
<OptionValues>
|
||||
<pass>Pass</pass>
|
||||
<block>Block</block>
|
||||
<reject>Reject</reject>
|
||||
</OptionValues>
|
||||
</action>
|
||||
<quick type="BooleanField">
|
||||
<Default>1</Default>
|
||||
<Required>Y</Required>
|
||||
</quick>
|
||||
<interface type="InterfaceField">
|
||||
<Required>N</Required>
|
||||
<Multiple>Y</Multiple>
|
||||
<AllowDynamic>Y</AllowDynamic>
|
||||
</interface>
|
||||
<direction type="OptionField">
|
||||
<Required>Y</Required>
|
||||
<Default>in</Default>
|
||||
<OptionValues>
|
||||
<in>In</in>
|
||||
<out>Out</out>
|
||||
</OptionValues>
|
||||
</direction>
|
||||
<ipprotocol type="OptionField">
|
||||
<Required>Y</Required>
|
||||
<Default>inet</Default>
|
||||
<OptionValues>
|
||||
<inet>IPv4</inet>
|
||||
<inet6>IPv6</inet6>
|
||||
</OptionValues>
|
||||
</ipprotocol>
|
||||
<protocol type="ProtocolField">
|
||||
<Required>Y</Required>
|
||||
<Default>any</Default>
|
||||
</protocol>
|
||||
<!-- XXX: should map internally to 'source' => array('network' => $source_net, "not" => true|false) -->
|
||||
<source_net type="NetworkAliasField">
|
||||
<Default>any</Default>
|
||||
<Required>Y</Required>
|
||||
</source_net>
|
||||
<source_not type="BooleanField">
|
||||
<Default>0</Default>
|
||||
<Required>Y</Required>
|
||||
</source_not>
|
||||
<source_port type="PortField">
|
||||
<Required>N</Required>
|
||||
<EnableWellKnown>Y</EnableWellKnown>
|
||||
<EnableRanges>Y</EnableRanges>
|
||||
<EnableAlias>Y</EnableAlias>
|
||||
<ValidationMessage>Please specify a valid portnumber, name, alias or range</ValidationMessage>
|
||||
</source_port>
|
||||
<!-- XXX: should map internally to 'source' => array('destination' => destination_net, "not" => true|false) -->
|
||||
<destination_net type="NetworkAliasField">
|
||||
<Default>any</Default>
|
||||
<Required>Y</Required>
|
||||
</destination_net>
|
||||
<destination_not type="BooleanField">
|
||||
<Default>0</Default>
|
||||
<Required>Y</Required>
|
||||
</destination_not>
|
||||
<destination_port type="PortField">
|
||||
<Required>N</Required>
|
||||
<EnableWellKnown>Y</EnableWellKnown>
|
||||
<EnableRanges>Y</EnableRanges>
|
||||
<EnableAlias>Y</EnableAlias>
|
||||
<ValidationMessage>Please specify a valid portnumber, name, alias or range</ValidationMessage>
|
||||
</destination_port>
|
||||
<gateway type="JsonKeyValueStoreField">
|
||||
<Required>N</Required>
|
||||
<ConfigdPopulateAct>interface gateways list</ConfigdPopulateAct>
|
||||
<SourceFile>/tmp/gateway_list.json</SourceFile>
|
||||
<ConfigdPopulateTTL>20</ConfigdPopulateTTL>
|
||||
<ValidationMessage>Specify a valid gateway from the list matching the networks ip protocol.</ValidationMessage>
|
||||
</gateway>
|
||||
<log type="BooleanField">
|
||||
<Default>0</Default>
|
||||
<Required>Y</Required>
|
||||
</log>
|
||||
<categories type="ModelRelationField">
|
||||
<Model>
|
||||
<rulesets>
|
||||
<source>OPNsense.Firewall.Category</source>
|
||||
<items>categories.category</items>
|
||||
<display>name</display>
|
||||
</rulesets>
|
||||
</Model>
|
||||
<Multiple>Y</Multiple>
|
||||
<ValidationMessage>Related category not found.</ValidationMessage>
|
||||
</categories>
|
||||
<description type="TextField">
|
||||
<Required>N</Required>
|
||||
<mask>/^([\t\n\v\f\r 0-9a-zA-Z.\-,_\x{00A0}-\x{FFFF}]){0,255}$/u</mask>
|
||||
<ValidationMessage>Description should be a string between 1 and 255 characters</ValidationMessage>
|
||||
</description>
|
||||
</rule>
|
||||
</rules>
|
||||
<snatrules>
|
||||
<rule type=".\SourceNatRuleField">
|
||||
<enabled type="BooleanField">
|
||||
<Default>1</Default>
|
||||
<Required>Y</Required>
|
||||
</enabled>
|
||||
<nonat type="BooleanField">
|
||||
<Default>0</Default>
|
||||
<Required>Y</Required>
|
||||
</nonat>
|
||||
<sequence type="IntegerField">
|
||||
<MinimumValue>1</MinimumValue>
|
||||
<MaximumValue>99999</MaximumValue>
|
||||
<ValidationMessage>provide a valid sequence for sorting</ValidationMessage>
|
||||
<Required>Y</Required>
|
||||
<Default>1</Default>
|
||||
</sequence>
|
||||
<interface type="InterfaceField">
|
||||
<Required>Y</Required>
|
||||
<Default>lan</Default>
|
||||
<AllowDynamic>Y</AllowDynamic>
|
||||
</interface>
|
||||
<ipprotocol type="OptionField">
|
||||
<Required>Y</Required>
|
||||
<Default>inet</Default>
|
||||
<OptionValues>
|
||||
<inet>IPv4</inet>
|
||||
<inet6>IPv6</inet6>
|
||||
</OptionValues>
|
||||
</ipprotocol>
|
||||
<protocol type="ProtocolField">
|
||||
<Required>Y</Required>
|
||||
<Default>any</Default>
|
||||
</protocol>
|
||||
<source_net type="NetworkAliasField">
|
||||
<Default>any</Default>
|
||||
<Required>Y</Required>
|
||||
</source_net>
|
||||
<source_not type="BooleanField">
|
||||
<Default>0</Default>
|
||||
<Required>Y</Required>
|
||||
</source_not>
|
||||
<source_port type="PortField">
|
||||
<Required>N</Required>
|
||||
<EnableWellKnown>Y</EnableWellKnown>
|
||||
<EnableRanges>Y</EnableRanges>
|
||||
<EnableAlias>Y</EnableAlias>
|
||||
<ValidationMessage>Please specify a valid portnumber, name, alias or range</ValidationMessage>
|
||||
</source_port>
|
||||
<destination_net type="NetworkAliasField">
|
||||
<Default>any</Default>
|
||||
<Required>Y</Required>
|
||||
</destination_net>
|
||||
<destination_not type="BooleanField">
|
||||
<Default>0</Default>
|
||||
<Required>Y</Required>
|
||||
</destination_not>
|
||||
<destination_port type="PortField">
|
||||
<Required>N</Required>
|
||||
<EnableWellKnown>Y</EnableWellKnown>
|
||||
<EnableRanges>Y</EnableRanges>
|
||||
<EnableAlias>Y</EnableAlias>
|
||||
<ValidationMessage>Please specify a valid portnumber, name, alias or range</ValidationMessage>
|
||||
</destination_port>
|
||||
<target type="NetworkAliasField">
|
||||
<Default>wanip</Default>
|
||||
<Required>Y</Required>
|
||||
</target>
|
||||
<target_port type="PortField">
|
||||
<Required>N</Required>
|
||||
<EnableWellKnown>Y</EnableWellKnown>
|
||||
<EnableRanges>Y</EnableRanges>
|
||||
</target_port>
|
||||
<log type="BooleanField">
|
||||
<Default>0</Default>
|
||||
<Required>Y</Required>
|
||||
</log>
|
||||
<categories type="ModelRelationField">
|
||||
<Model>
|
||||
<rulesets>
|
||||
<source>OPNsense.Firewall.Category</source>
|
||||
<items>categories.category</items>
|
||||
<display>name</display>
|
||||
</rulesets>
|
||||
</Model>
|
||||
<Multiple>Y</Multiple>
|
||||
<ValidationMessage>Related category not found.</ValidationMessage>
|
||||
</categories>
|
||||
<description type="TextField">
|
||||
<Required>N</Required>
|
||||
<mask>/^([\t\n\v\f\r 0-9a-zA-Z.\-,_\x{00A0}-\x{FFFF}]){0,255}$/u</mask>
|
||||
<ValidationMessage>Description should be a string between 1 and 255 characters</ValidationMessage>
|
||||
</description>
|
||||
</rule>
|
||||
</snatrules>
|
||||
<npt>
|
||||
<rule type=".\SourceNatRuleField">
|
||||
<enabled type="BooleanField">
|
||||
<Default>1</Default>
|
||||
<Required>Y</Required>
|
||||
</enabled>
|
||||
<log type="BooleanField">
|
||||
<Default>0</Default>
|
||||
<Required>Y</Required>
|
||||
</log>
|
||||
<sequence type="IntegerField">
|
||||
<MinimumValue>1</MinimumValue>
|
||||
<MaximumValue>99999</MaximumValue>
|
||||
<ValidationMessage>provide a valid sequence for sorting</ValidationMessage>
|
||||
<Required>Y</Required>
|
||||
<Default>1</Default>
|
||||
</sequence>
|
||||
<interface type="InterfaceField">
|
||||
<Required>Y</Required>
|
||||
<Default>lan</Default>
|
||||
<AllowDynamic>Y</AllowDynamic>
|
||||
</interface>
|
||||
<source_net type="NetworkField">
|
||||
<Required>Y</Required>
|
||||
<AddressFamily>ipv6</AddressFamily>
|
||||
<NetMaskRequired>Y</NetMaskRequired>
|
||||
<WildcardEnabled>N</WildcardEnabled>
|
||||
</source_net>
|
||||
<destination_net type="NetworkField">
|
||||
<AddressFamily>ipv6</AddressFamily>
|
||||
<NetMaskRequired>Y</NetMaskRequired>
|
||||
<WildcardEnabled>N</WildcardEnabled>
|
||||
</destination_net>
|
||||
<trackif type="InterfaceField">
|
||||
</trackif>
|
||||
<categories type="ModelRelationField">
|
||||
<Model>
|
||||
<rulesets>
|
||||
<source>OPNsense.Firewall.Category</source>
|
||||
<items>categories.category</items>
|
||||
<display>name</display>
|
||||
</rulesets>
|
||||
</Model>
|
||||
<Multiple>Y</Multiple>
|
||||
<ValidationMessage>Related category not found.</ValidationMessage>
|
||||
</categories>
|
||||
<description type="TextField">
|
||||
<Required>N</Required>
|
||||
<mask>/^([\t\n\v\f\r 0-9a-zA-Z.\-,_\x{00A0}-\x{FFFF}]){0,255}$/u</mask>
|
||||
<ValidationMessage>Description should be a string between 1 and 255 characters</ValidationMessage>
|
||||
</description>
|
||||
</rule>
|
||||
</npt>
|
||||
</items>
|
||||
</model>
|
||||
15
src/opnsense/mvc/app/models/OPNsense/Firewall/Menu/Menu.xml
Normal file
15
src/opnsense/mvc/app/models/OPNsense/Firewall/Menu/Menu.xml
Normal file
@ -0,0 +1,15 @@
|
||||
<menu>
|
||||
<Firewall>
|
||||
<Automation order="1000" cssClass="fa fa-gear">
|
||||
<Filter order="50" url="/ui/firewall/filter/">
|
||||
<FilterRef url="/ui/firewall/filter#*" visibility="hidden"/>
|
||||
</Filter>
|
||||
<SourceNat order="100" VisibleName="Source NAT" url="/ui/firewall/source_nat/">
|
||||
<FilterRef url="/ui/firewall/source_nat#*" visibility="hidden"/>
|
||||
</SourceNat>
|
||||
<Npt order="100" VisibleName="NPTv6" url="/ui/firewall/npt/">
|
||||
<FilterRef url="/ui/firewall/npt#*" visibility="hidden"/>
|
||||
</Npt>
|
||||
</Automation>
|
||||
</Firewall>
|
||||
</menu>
|
||||
@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Copyright (C) 2020 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\Firewall\Migrations;
|
||||
|
||||
use OPNsense\Core\Config;
|
||||
use OPNsense\Base\BaseModelMigration;
|
||||
|
||||
class MFP1_0_0 extends BaseModelMigration
|
||||
{
|
||||
public function post($model)
|
||||
{
|
||||
// Move OPNsense->Firewall->FilterRule ---> OPNsense->Firewall->Filter
|
||||
$cfgObj = Config::getInstance()->object();
|
||||
if (
|
||||
!empty($cfgObj->OPNsense) && !empty($cfgObj->OPNsense->Firewall)
|
||||
&& !empty($cfgObj->OPNsense->Firewall->FilterRule)
|
||||
) {
|
||||
// model migration created a new, empty rules section
|
||||
if (empty($cfgObj->OPNsense->Firewall->Filter->rules)) {
|
||||
unset($cfgObj->OPNsense->Firewall->Filter->rules);
|
||||
$targetdom = dom_import_simplexml($cfgObj->OPNsense->Firewall->Filter);
|
||||
foreach ($cfgObj->OPNsense->Firewall->FilterRule->children() as $child) {
|
||||
$sourcedom = dom_import_simplexml($child);
|
||||
$targetdom->appendChild($sourcedom);
|
||||
}
|
||||
unset($cfgObj->OPNsense->Firewall->FilterRule);
|
||||
Config::getInstance()->save();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
250
src/opnsense/mvc/app/views/OPNsense/Firewall/filter.volt
Normal file
250
src/opnsense/mvc/app/views/OPNsense/Firewall/filter.volt
Normal file
@ -0,0 +1,250 @@
|
||||
<script>
|
||||
$( document ).ready(function() {
|
||||
let initial_load = true;
|
||||
let grid = $("#grid-rules").UIBootgrid({
|
||||
search:'/api/firewall/{{ruleController}}/search_rule/',
|
||||
get:'/api/firewall/{{ruleController}}/get_rule/',
|
||||
set:'/api/firewall/{{ruleController}}/set_rule/',
|
||||
add:'/api/firewall/{{ruleController}}/add_rule/',
|
||||
del:'/api/firewall/{{ruleController}}/del_rule/',
|
||||
toggle:'/api/firewall/{{ruleController}}/toggle_rule/',
|
||||
options:{
|
||||
requestHandler: function(request){
|
||||
if ( $('#category_filter').val().length > 0) {
|
||||
request['category'] = $('#category_filter').val();
|
||||
}
|
||||
return request;
|
||||
}
|
||||
}
|
||||
});
|
||||
grid.on("loaded.rs.jquery.bootgrid", function (e){
|
||||
// reload categories before grid load
|
||||
ajaxCall('/api/firewall/{{ruleController}}/list_categories', {}, function(data, status){
|
||||
if (data.rows !== undefined) {
|
||||
let current_selection = $("#category_filter").val();
|
||||
$("#category_filter").empty();
|
||||
for (i=0; i < data.rows.length ; ++i) {
|
||||
let row = data.rows[i];
|
||||
let opt_val = $('<div/>').html(row.name).text();
|
||||
let bgcolor = row.color != "" ? row.color : '31708f;'; // set category color
|
||||
let option = $("<option/>").val(row.uuid).html(row.name);
|
||||
if (row.used > 0) {
|
||||
option.attr(
|
||||
'data-content',
|
||||
"<span>"+opt_val + "</span>"+
|
||||
"<span style='background:#"+bgcolor+";' class='badge pull-right'>" + row.used + "</span>"
|
||||
);
|
||||
option.attr('id', row.uuid);
|
||||
}
|
||||
|
||||
$("#category_filter").append(option);
|
||||
}
|
||||
$("#category_filter").val(current_selection);
|
||||
$("#category_filter").selectpicker('refresh');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// open edit dialog when opened with a uuid reference
|
||||
if (window.location.hash !== "" && window.location.hash.split("-").length >= 4) {
|
||||
grid.on('loaded.rs.jquery.bootgrid', function(){
|
||||
if (initial_load) {
|
||||
$(".command-edit:eq(0)").clone(true).data('row-id', window.location.hash.substr(1)).click();
|
||||
initial_load = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$("#reconfigureAct").SimpleActionButton();
|
||||
$("#savepointAct").SimpleActionButton({
|
||||
onAction: function(data, status){
|
||||
stdDialogInform(
|
||||
"{{ lang._('Savepoint created') }}",
|
||||
data['revision'],
|
||||
"{{ lang._('Close') }}"
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
$("#revertAction").on('click', function(){
|
||||
BootstrapDialog.show({
|
||||
type: BootstrapDialog.TYPE_DEFAULT,
|
||||
title: "{{ lang._('Revert to savepoint') }}",
|
||||
message: "<p>{{ lang._('Enter a savepoint to rollback to.') }}</p>" +
|
||||
'<div class="form-group" style="display: block;">' +
|
||||
'<input id="revertToTime" type="text" class="form-control"/>' +
|
||||
'<span class="error text-danger" id="revertToTimeError"></span>'+
|
||||
'</div>',
|
||||
buttons: [{
|
||||
label: "{{ lang._('Revert') }}",
|
||||
cssClass: 'btn-primary',
|
||||
action: function(dialogRef) {
|
||||
ajaxCall("/api/firewall/{{ruleController}}/revert/" + $("#revertToTime").val(), {}, function (data, status) {
|
||||
if (data.status !== "ok") {
|
||||
$("#revertToTime").parent().addClass("has-error");
|
||||
$("#revertToTimeError").html(data.status);
|
||||
} else {
|
||||
std_bootgrid_reload("grid-rules");
|
||||
dialogRef.close();
|
||||
}
|
||||
});
|
||||
}
|
||||
}],
|
||||
onshown: function(dialogRef) {
|
||||
$("#revertToTime").parent().removeClass("has-error");
|
||||
$("#revertToTimeError").html("");
|
||||
$("#revertToTime").val("");
|
||||
}
|
||||
});
|
||||
});
|
||||
// move filter into action header
|
||||
$("#type_filter_container").detach().prependTo('#grid-rules-header > .row > .actionBar > .actions');
|
||||
$("#category_filter").change(function(){
|
||||
$('#grid-rules').bootgrid('reload');
|
||||
});
|
||||
|
||||
// replace all "net" selectors with details retrieved from "list_network_select_options" endpoint
|
||||
ajaxGet('/api/firewall/{{ruleController}}/list_network_select_options', [], function(data, status){
|
||||
// fetch options
|
||||
let options = [];
|
||||
if (data.single) {
|
||||
Object.keys(data).forEach((key, idx) => {
|
||||
if (data[key].items !== undefined) {
|
||||
let optgrp = $("<optgroup/>").attr('label', data[key].label);
|
||||
Object.keys(data[key].items).forEach((key2, idx2) => {
|
||||
let this_item = data[key].items[key2];
|
||||
optgrp.append($("<option/>").val(key2).text(this_item));
|
||||
});
|
||||
options.push(optgrp);
|
||||
} else {
|
||||
options.push($("<option/>").val('').text(data[key].label));
|
||||
}
|
||||
});
|
||||
}
|
||||
if (options.length == 0) {
|
||||
// unable to fetch options.
|
||||
return;
|
||||
}
|
||||
$(".net_selector").each(function(){
|
||||
let $items = $("#network_select").clone().show();
|
||||
let $this_input = $items.find('input');
|
||||
let $this_select = $items.find('select');
|
||||
for (i=0; i < options.length; ++i) {
|
||||
$this_select.append(options[i].clone());
|
||||
}
|
||||
$this_select.attr('for', $(this).attr('id')).selectpicker();
|
||||
$this_select.change(function(){
|
||||
let $value = $(this).val();
|
||||
if ($value !== '') {
|
||||
$this_input.val($value);
|
||||
$this_input.hide();
|
||||
} else {
|
||||
$this_input.show();
|
||||
}
|
||||
});
|
||||
$this_input.attr('id', $(this).attr('id'));
|
||||
$this_input.change(function(){
|
||||
$this_select.val($(this).val());
|
||||
if ($this_select.val() === null || $this_select.val() == '') {
|
||||
$this_select.val('');
|
||||
$this_input.show();
|
||||
} else {
|
||||
$this_input.hide();
|
||||
}
|
||||
$this_select.selectpicker('refresh');
|
||||
});
|
||||
$this_input.show();
|
||||
$(this).replaceWith($items);
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
<ul class="nav nav-tabs" data-tabs="tabs" id="maintabs">
|
||||
<li class="active"><a data-toggle="tab" href="#rules">{{ lang._('Rules') }}</a></li>
|
||||
</ul>
|
||||
<div class="tab-content content-box">
|
||||
<div id="rules" class="tab-pane fade in active">
|
||||
<div class="hidden">
|
||||
<!-- filter per type container -->
|
||||
<div id="type_filter_container" class="btn-group">
|
||||
<select id="category_filter" data-title="{{ lang._('Categories') }}" class="selectpicker" data-live-search="true" data-size="5" multiple data-width="200px">
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<!-- tab page "rules" -->
|
||||
<table id="grid-rules" class="table table-condensed table-hover table-striped" data-editDialog="DialogFilterRule" data-editAlert="FilterRuleChangeMessage">
|
||||
<thead>
|
||||
<tr>
|
||||
<th data-column-id="uuid" data-type="string" data-identifier="true" data-visible="false">{{ lang._('ID') }}</th>
|
||||
{% for fieldlist in gridFields %}
|
||||
<th
|
||||
data-column-id="{{fieldlist['id']}}"
|
||||
data-width="{{fieldlist['width']|default('')}}"
|
||||
data-type="{{fieldlist['type']|default('string')}}"
|
||||
data-formatter="{{fieldlist['formatter']|default('')}}"
|
||||
>{{fieldlist['heading']|default('')}}</th>
|
||||
{% endfor %}
|
||||
<th data-column-id="commands" data-width="7em" data-formatter="commands" data-sortable="false">{{ lang._('Commands') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>
|
||||
<button data-action="add" type="button" class="btn btn-xs btn-default"><span class="fa fa-plus"></span></button>
|
||||
<button data-action="deleteSelected" type="button" class="btn btn-xs btn-default"><span class="fa fa-trash-o"></span></button>
|
||||
</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
<div class="col-md-12">
|
||||
<div id="FilterRuleChangeMessage" class="alert alert-info" style="display: none" role="alert">
|
||||
{{ lang._('After changing settings, please remember to apply them with the button below') }}
|
||||
</div>
|
||||
<hr/>
|
||||
<button class="btn btn-primary" id="reconfigureAct"
|
||||
data-endpoint='/api/firewall/{{ruleController}}/apply'
|
||||
data-label="{{ lang._('Apply') }}"
|
||||
data-error-title="{{ lang._('Filter load error') }}"
|
||||
type="button"
|
||||
></button>
|
||||
{% if not hideSavePointBtns|default(false) %}
|
||||
<div class="pull-right">
|
||||
<button class="btn" id="savepointAct"
|
||||
data-endpoint='/api/firewall/{{ruleController}}/savepoint'
|
||||
data-label="{{ lang._('Savepoint') }}"
|
||||
data-error-title="{{ lang._('snapshot error') }}"
|
||||
type="button"
|
||||
></button>
|
||||
<button class="btn" id="revertAction">
|
||||
{{ lang._('Revert') }}
|
||||
</button>
|
||||
</div>
|
||||
{% endif %}
|
||||
<br/><br/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="network_select" style="display: none;" >
|
||||
<table style="max-width: 348px">
|
||||
<tr>
|
||||
<td>
|
||||
<select data-live-search="true" data-size="5" data-width="348px">
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<input style="display:none;" type="text"/>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
{{ partial("layout_partials/base_dialog",['fields':formDialogFilterRule,'id':'DialogFilterRule','label':lang._('Edit rule')])}}
|
||||
40
src/opnsense/scripts/pfplugin/rollback_cancel
Executable file
40
src/opnsense/scripts/pfplugin/rollback_cancel
Executable file
@ -0,0 +1,40 @@
|
||||
#!/usr/local/bin/php
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (C) 2020 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.
|
||||
*/
|
||||
|
||||
if (count($argv) >= 2) {
|
||||
$revision = preg_replace("/[^0-9.]/", "", $argv[1]);
|
||||
if (!empty($revision)) {
|
||||
$lckfile = "/tmp/pfplugin_{$revision}.lock";
|
||||
if (file_exists($lckfile)) {
|
||||
unlink($lckfile);
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
exit(1);
|
||||
54
src/opnsense/scripts/pfplugin/rollback_timer
Executable file
54
src/opnsense/scripts/pfplugin/rollback_timer
Executable file
@ -0,0 +1,54 @@
|
||||
#!/usr/local/bin/php
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (C) 2020 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.
|
||||
*/
|
||||
|
||||
require_once('script/load_phalcon.php');
|
||||
|
||||
if (count($argv) >= 2) {
|
||||
$revision = preg_replace("/[^0-9.]/", "", $argv[1]);
|
||||
if (!empty($revision)) {
|
||||
$lckfile = "/tmp/pfplugin_{$revision}.lock";
|
||||
file_put_contents($lckfile, "");
|
||||
// give the api 60 seconds to callback
|
||||
for ($i=0; $i < 60 ; ++$i) {
|
||||
if (!file_exists($lckfile)) {
|
||||
// got feedback
|
||||
exit(0);
|
||||
}
|
||||
sleep(1);
|
||||
}
|
||||
@unlink($lckfile);
|
||||
// no feedback, revert
|
||||
$mdlFilter = new OPNsense\Firewall\Filter();
|
||||
if ($mdlFilter->rollback($revision)) {
|
||||
(new OPNsense\Core\Backend())->configdRun('filter reload');
|
||||
} else {
|
||||
syslog(LOG_WARNING, "unable to revert to unexisting revision : {$revision}");
|
||||
}
|
||||
}
|
||||
}
|
||||
11
src/opnsense/service/conf/actions.d/actions_pfplugin.conf
Normal file
11
src/opnsense/service/conf/actions.d/actions_pfplugin.conf
Normal file
@ -0,0 +1,11 @@
|
||||
[rollback_timer]
|
||||
command:/usr/local/bin/flock -n -E 0 -o /tmp/pfplugin_rollback_timer.lock /usr/local/opnsense/scripts/pfplugin/rollback_timer
|
||||
parameters: %s
|
||||
type:script
|
||||
message:wait for api feedback or revert to previous filter plugin config
|
||||
|
||||
[cancel_rollback]
|
||||
command: /usr/local/opnsense/scripts/pfplugin/rollback_cancel
|
||||
parameters: %s
|
||||
type:script_output
|
||||
message:cancel pfplugin rollback
|
||||
Loading…
x
Reference in New Issue
Block a user