From c6e16e54f366dcb207f415818eac0b8cc7063da9 Mon Sep 17 00:00:00 2001 From: Ad Schellevis Date: Mon, 1 Jan 2024 17:14:09 +0100 Subject: [PATCH] net/firewall - add NPTv6 for https://github.com/opnsense/core/issues/6383 --- .../src/etc/inc/plugins.inc.d/pfplugin.inc | 3 + .../Firewall/Api/FilterBaseController.php | 40 +++++++++++ .../Firewall/Api/FilterController.php | 8 ++- .../OPNsense/Firewall/Api/NptController.php | 67 +++++++++++++++++++ .../Firewall/Api/SourceNatController.php | 8 ++- .../OPNsense/Firewall/NptController.php | 38 +++++++++++ .../Firewall/forms/dialogFilterRule.xml | 8 ++- .../OPNsense/Firewall/forms/dialogNptRule.xml | 40 +++++++++++ .../Firewall/forms/dialogSNatRule.xml | 7 ++ .../app/models/OPNsense/Firewall/Filter.xml | 55 +++++++++++++++ .../models/OPNsense/Firewall/Menu/Menu.xml | 3 + .../app/views/OPNsense/Firewall/filter.volt | 59 ++++++++++++++-- 12 files changed, 327 insertions(+), 9 deletions(-) create mode 100644 net/firewall/src/opnsense/mvc/app/controllers/OPNsense/Firewall/Api/NptController.php create mode 100644 net/firewall/src/opnsense/mvc/app/controllers/OPNsense/Firewall/NptController.php create mode 100644 net/firewall/src/opnsense/mvc/app/controllers/OPNsense/Firewall/forms/dialogNptRule.xml diff --git a/net/firewall/src/etc/inc/plugins.inc.d/pfplugin.inc b/net/firewall/src/etc/inc/plugins.inc.d/pfplugin.inc index cdb25a5de..3c9aa2fce 100644 --- a/net/firewall/src/etc/inc/plugins.inc.d/pfplugin.inc +++ b/net/firewall/src/etc/inc/plugins.inc.d/pfplugin.inc @@ -42,4 +42,7 @@ function pfplugin_firewall($fw) 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()); + } } diff --git a/net/firewall/src/opnsense/mvc/app/controllers/OPNsense/Firewall/Api/FilterBaseController.php b/net/firewall/src/opnsense/mvc/app/controllers/OPNsense/Firewall/Api/FilterBaseController.php index 789ae9a89..3162d985f 100644 --- a/net/firewall/src/opnsense/mvc/app/controllers/OPNsense/Firewall/Api/FilterBaseController.php +++ b/net/firewall/src/opnsense/mvc/app/controllers/OPNsense/Firewall/Api/FilterBaseController.php @@ -30,6 +30,7 @@ namespace OPNsense\Firewall\Api; use OPNsense\Base\ApiMutableModelControllerBase; use OPNsense\Core\Backend; use OPNsense\Core\Config; +use OPNsense\Firewall\Category; /** * Class FilterBaseController implements actions for various types @@ -39,6 +40,45 @@ 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; + } + public function applyAction($rollback_revision = null) { diff --git a/net/firewall/src/opnsense/mvc/app/controllers/OPNsense/Firewall/Api/FilterController.php b/net/firewall/src/opnsense/mvc/app/controllers/OPNsense/Firewall/Api/FilterController.php index 225a07b72..7af4676eb 100644 --- a/net/firewall/src/opnsense/mvc/app/controllers/OPNsense/Firewall/Api/FilterController.php +++ b/net/firewall/src/opnsense/mvc/app/controllers/OPNsense/Firewall/Api/FilterController.php @@ -29,9 +29,15 @@ namespace OPNsense\Firewall\Api; class FilterController extends FilterBaseController { + protected static $categorysource = "rules.rule"; + public function searchRuleAction() { - return $this->searchBase("rules.rule", array('enabled', 'sequence', 'description'), "sequence"); + $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) diff --git a/net/firewall/src/opnsense/mvc/app/controllers/OPNsense/Firewall/Api/NptController.php b/net/firewall/src/opnsense/mvc/app/controllers/OPNsense/Firewall/Api/NptController.php new file mode 100644 index 000000000..61b1d5705 --- /dev/null +++ b/net/firewall/src/opnsense/mvc/app/controllers/OPNsense/Firewall/Api/NptController.php @@ -0,0 +1,67 @@ +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', '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); + } +} diff --git a/net/firewall/src/opnsense/mvc/app/controllers/OPNsense/Firewall/Api/SourceNatController.php b/net/firewall/src/opnsense/mvc/app/controllers/OPNsense/Firewall/Api/SourceNatController.php index 151bf14db..5833225d9 100644 --- a/net/firewall/src/opnsense/mvc/app/controllers/OPNsense/Firewall/Api/SourceNatController.php +++ b/net/firewall/src/opnsense/mvc/app/controllers/OPNsense/Firewall/Api/SourceNatController.php @@ -29,9 +29,15 @@ namespace OPNsense\Firewall\Api; class SourceNatController extends FilterBaseController { + protected static $categorysource = "snatrules.rule"; + public function searchRuleAction() { - return $this->searchBase("snatrules.rule", array('enabled', 'sequence', 'description'), "sequence"); + $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) diff --git a/net/firewall/src/opnsense/mvc/app/controllers/OPNsense/Firewall/NptController.php b/net/firewall/src/opnsense/mvc/app/controllers/OPNsense/Firewall/NptController.php new file mode 100644 index 000000000..07b1c7efd --- /dev/null +++ b/net/firewall/src/opnsense/mvc/app/controllers/OPNsense/Firewall/NptController.php @@ -0,0 +1,38 @@ +view->pick('OPNsense/Firewall/filter'); + $this->view->ruleController = "npt"; + $this->view->formDialogFilterRule = $this->getForm("dialogNptRule"); + } +} diff --git a/net/firewall/src/opnsense/mvc/app/controllers/OPNsense/Firewall/forms/dialogFilterRule.xml b/net/firewall/src/opnsense/mvc/app/controllers/OPNsense/Firewall/forms/dialogFilterRule.xml index f299cc1c4..af4cda9bc 100644 --- a/net/firewall/src/opnsense/mvc/app/controllers/OPNsense/Firewall/forms/dialogFilterRule.xml +++ b/net/firewall/src/opnsense/mvc/app/controllers/OPNsense/Firewall/forms/dialogFilterRule.xml @@ -99,7 +99,13 @@ checkbox Log packets that are handled by this rule - + + rule.categories + + select_multiple + + For grouping purposes you may select multiple groups here to organize items. + rule.description diff --git a/net/firewall/src/opnsense/mvc/app/controllers/OPNsense/Firewall/forms/dialogNptRule.xml b/net/firewall/src/opnsense/mvc/app/controllers/OPNsense/Firewall/forms/dialogNptRule.xml new file mode 100644 index 000000000..abfe782df --- /dev/null +++ b/net/firewall/src/opnsense/mvc/app/controllers/OPNsense/Firewall/forms/dialogNptRule.xml @@ -0,0 +1,40 @@ +
+ + rule.enabled + + checkbox + Enable this rule + + + rule.sequence + + text + + + rule.interface + + dropdown + + + rule.source_net + + text + + + rule.destination_net + + text + + + rule.categories + + select_multiple + + For grouping purposes you may select multiple groups here to organize items. + + + rule.description + + text + +
diff --git a/net/firewall/src/opnsense/mvc/app/controllers/OPNsense/Firewall/forms/dialogSNatRule.xml b/net/firewall/src/opnsense/mvc/app/controllers/OPNsense/Firewall/forms/dialogSNatRule.xml index 0c87b0450..90dc7a90b 100644 --- a/net/firewall/src/opnsense/mvc/app/controllers/OPNsense/Firewall/forms/dialogSNatRule.xml +++ b/net/firewall/src/opnsense/mvc/app/controllers/OPNsense/Firewall/forms/dialogSNatRule.xml @@ -86,6 +86,13 @@ checkbox Log packets that are handled by this rule
+ + rule.categories + + select_multiple + + For grouping purposes you may select multiple groups here to organize items. + rule.description diff --git a/net/firewall/src/opnsense/mvc/app/models/OPNsense/Firewall/Filter.xml b/net/firewall/src/opnsense/mvc/app/models/OPNsense/Firewall/Filter.xml index 65262b536..ca30b9f98 100644 --- a/net/firewall/src/opnsense/mvc/app/models/OPNsense/Firewall/Filter.xml +++ b/net/firewall/src/opnsense/mvc/app/models/OPNsense/Firewall/Filter.xml @@ -100,6 +100,17 @@ 0 Y + + + + OPNsense.Firewall.Category + categories.category + name + + + Y + Related category not found. + N /^([\t\n\v\f\r 0-9a-zA-Z.\-,_\x{00A0}-\x{FFFF}]){0,255}$/u @@ -184,6 +195,17 @@ 0 Y + + + + OPNsense.Firewall.Category + categories.category + name + + + Y + Related category not found. + N /^([\t\n\v\f\r 0-9a-zA-Z.\-,_\x{00A0}-\x{FFFF}]){0,255}$/u @@ -191,5 +213,38 @@ + + + + 1 + Y + + + Y + lan + Y + + + Y + + + + + + OPNsense.Firewall.Category + categories.category + name + + + Y + Related category not found. + + + N + /^([\t\n\v\f\r 0-9a-zA-Z.\-,_\x{00A0}-\x{FFFF}]){0,255}$/u + Description should be a string between 1 and 255 characters + + + diff --git a/net/firewall/src/opnsense/mvc/app/models/OPNsense/Firewall/Menu/Menu.xml b/net/firewall/src/opnsense/mvc/app/models/OPNsense/Firewall/Menu/Menu.xml index 2889f9bff..476e1f38b 100644 --- a/net/firewall/src/opnsense/mvc/app/models/OPNsense/Firewall/Menu/Menu.xml +++ b/net/firewall/src/opnsense/mvc/app/models/OPNsense/Firewall/Menu/Menu.xml @@ -7,6 +7,9 @@ + + + diff --git a/net/firewall/src/opnsense/mvc/app/views/OPNsense/Firewall/filter.volt b/net/firewall/src/opnsense/mvc/app/views/OPNsense/Firewall/filter.volt index 567eff336..34622514c 100644 --- a/net/firewall/src/opnsense/mvc/app/views/OPNsense/Firewall/filter.volt +++ b/net/firewall/src/opnsense/mvc/app/views/OPNsense/Firewall/filter.volt @@ -2,12 +2,47 @@ $( document ).ready(function() { let initial_load = true; let grid = $("#grid-rules").UIBootgrid({ - search:'/api/firewall/{{ruleController}}/searchRule/', - get:'/api/firewall/{{ruleController}}/getRule/', - set:'/api/firewall/{{ruleController}}/setRule/', - add:'/api/firewall/{{ruleController}}/addRule/', - del:'/api/firewall/{{ruleController}}/delRule/', - toggle:'/api/firewall/{{ruleController}}/toggleRule/' + 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 = $('
').html(row.name).text(); + let bgcolor = row.color != "" ? row.color : '31708f;'; // set category color + let option = $("