From 6bd26c248bd3d2fefaf4fe37dedef5fb32e7fd81 Mon Sep 17 00:00:00 2001 From: Monviech <79600909+Monviech@users.noreply.github.com> Date: Tue, 24 Feb 2026 09:58:16 +0100 Subject: [PATCH] Firewall: NAT: Merge npt_rule, onat_rule, snat_rule, dnat_rule into a single nat_rule template (#9855) Most notable differences that are decided by the controller providing an "entrypoint" and "categoryKey" variable: - controller name (entrypoint) - category key (category vs categories) Other subtle differences: - enabled/disabled key (dnat is disabled) - DNAT local port cannot do port ranges so the list_port_select_options reflect that The functionality should be the same as before with less code as the same view template can be shared by all NAT controllers. --- plist | 5 +- .../OPNsense/Firewall/DNatController.php | 8 +- .../OPNsense/Firewall/NptController.php | 8 +- .../OPNsense/Firewall/OneToOneController.php | 8 +- .../OPNsense/Firewall/SourceNatController.php | 8 +- .../{dnat_rule.volt => nat_rule.volt} | 156 +++-- .../app/views/OPNsense/Firewall/npt_rule.volt | 507 -------------- .../views/OPNsense/Firewall/onat_rule.volt | 597 ----------------- .../views/OPNsense/Firewall/snat_rule.volt | 623 ------------------ 9 files changed, 106 insertions(+), 1814 deletions(-) rename src/opnsense/mvc/app/views/OPNsense/Firewall/{dnat_rule.volt => nat_rule.volt} (80%) delete mode 100644 src/opnsense/mvc/app/views/OPNsense/Firewall/npt_rule.volt delete mode 100644 src/opnsense/mvc/app/views/OPNsense/Firewall/onat_rule.volt delete mode 100644 src/opnsense/mvc/app/views/OPNsense/Firewall/snat_rule.volt diff --git a/plist b/plist index ccf0f9e2f6..b5c836744d 100644 --- a/plist +++ b/plist @@ -968,13 +968,10 @@ /usr/local/opnsense/mvc/app/views/OPNsense/Firewall/alias.volt /usr/local/opnsense/mvc/app/views/OPNsense/Firewall/alias_util.volt /usr/local/opnsense/mvc/app/views/OPNsense/Firewall/category.volt -/usr/local/opnsense/mvc/app/views/OPNsense/Firewall/dnat_rule.volt /usr/local/opnsense/mvc/app/views/OPNsense/Firewall/filter_rule.volt /usr/local/opnsense/mvc/app/views/OPNsense/Firewall/firewall_migration.volt /usr/local/opnsense/mvc/app/views/OPNsense/Firewall/group.volt -/usr/local/opnsense/mvc/app/views/OPNsense/Firewall/npt_rule.volt -/usr/local/opnsense/mvc/app/views/OPNsense/Firewall/onat_rule.volt -/usr/local/opnsense/mvc/app/views/OPNsense/Firewall/snat_rule.volt +/usr/local/opnsense/mvc/app/views/OPNsense/Firewall/nat_rule.volt /usr/local/opnsense/mvc/app/views/OPNsense/Hostdiscovery/settings.volt /usr/local/opnsense/mvc/app/views/OPNsense/IDS/index.volt /usr/local/opnsense/mvc/app/views/OPNsense/IDS/policy.volt diff --git a/src/opnsense/mvc/app/controllers/OPNsense/Firewall/DNatController.php b/src/opnsense/mvc/app/controllers/OPNsense/Firewall/DNatController.php index 86d1209aeb..8bb017655f 100644 --- a/src/opnsense/mvc/app/controllers/OPNsense/Firewall/DNatController.php +++ b/src/opnsense/mvc/app/controllers/OPNsense/Firewall/DNatController.php @@ -31,8 +31,10 @@ class DNatController extends \OPNsense\Base\IndexController { public function indexAction() { - $this->view->pick('OPNsense/Firewall/dnat_rule'); - $this->view->formDialogDNatRule = $this->getForm("dialogDNatRule"); - $this->view->formGridDNatRule = $this->getFormGrid('dialogDNatRule'); + $this->view->entrypoint = 'd_nat'; + $this->view->categoryKey = 'category'; + $this->view->pick('OPNsense/Firewall/nat_rule'); + $this->view->formDialogRule = $this->getForm('dialogDNatRule'); + $this->view->formGridRule = $this->getFormGrid('dialogDNatRule'); } } diff --git a/src/opnsense/mvc/app/controllers/OPNsense/Firewall/NptController.php b/src/opnsense/mvc/app/controllers/OPNsense/Firewall/NptController.php index a2a0d140d6..44a2fd84f6 100644 --- a/src/opnsense/mvc/app/controllers/OPNsense/Firewall/NptController.php +++ b/src/opnsense/mvc/app/controllers/OPNsense/Firewall/NptController.php @@ -31,8 +31,10 @@ class NptController extends \OPNsense\Base\IndexController { public function indexAction() { - $this->view->pick('OPNsense/Firewall/npt_rule'); - $this->view->formDialogNptRule = $this->getForm('dialogNptRule'); - $this->view->formGridNptRule = $this->getFormGrid('dialogNptRule'); + $this->view->entrypoint = 'npt'; + $this->view->categoryKey = 'categories'; + $this->view->pick('OPNsense/Firewall/nat_rule'); + $this->view->formDialogRule = $this->getForm('dialogNptRule'); + $this->view->formGridRule = $this->getFormGrid('dialogNptRule'); } } diff --git a/src/opnsense/mvc/app/controllers/OPNsense/Firewall/OneToOneController.php b/src/opnsense/mvc/app/controllers/OPNsense/Firewall/OneToOneController.php index 722b82e27d..072ad166f5 100644 --- a/src/opnsense/mvc/app/controllers/OPNsense/Firewall/OneToOneController.php +++ b/src/opnsense/mvc/app/controllers/OPNsense/Firewall/OneToOneController.php @@ -31,8 +31,10 @@ class OneToOneController extends \OPNsense\Base\IndexController { public function indexAction() { - $this->view->pick('OPNsense/Firewall/onat_rule'); - $this->view->formDialogOneToOneNatRule = $this->getForm('dialogOneToOneRule'); - $this->view->formGridOneToOneNatRule = $this->getFormGrid('dialogOneToOneRule'); + $this->view->entrypoint = 'one_to_one'; + $this->view->categoryKey = 'categories'; + $this->view->pick('OPNsense/Firewall/nat_rule'); + $this->view->formDialogRule = $this->getForm('dialogOneToOneRule'); + $this->view->formGridRule = $this->getFormGrid('dialogOneToOneRule'); } } diff --git a/src/opnsense/mvc/app/controllers/OPNsense/Firewall/SourceNatController.php b/src/opnsense/mvc/app/controllers/OPNsense/Firewall/SourceNatController.php index 3660f69256..7d10c757ea 100644 --- a/src/opnsense/mvc/app/controllers/OPNsense/Firewall/SourceNatController.php +++ b/src/opnsense/mvc/app/controllers/OPNsense/Firewall/SourceNatController.php @@ -31,8 +31,10 @@ class SourceNatController extends \OPNsense\Base\IndexController { public function indexAction() { - $this->view->pick('OPNsense/Firewall/snat_rule'); - $this->view->formDialogSNatRule = $this->getForm('dialogSNatRule'); - $this->view->formGridSNatRule = $this->getFormGrid('dialogSNatRule'); + $this->view->entrypoint = 'source_nat'; + $this->view->categoryKey = 'categories'; + $this->view->pick('OPNsense/Firewall/nat_rule'); + $this->view->formDialogRule = $this->getForm('dialogSNatRule'); + $this->view->formGridRule = $this->getFormGrid('dialogSNatRule'); } } diff --git a/src/opnsense/mvc/app/views/OPNsense/Firewall/dnat_rule.volt b/src/opnsense/mvc/app/views/OPNsense/Firewall/nat_rule.volt similarity index 80% rename from src/opnsense/mvc/app/views/OPNsense/Firewall/dnat_rule.volt rename to src/opnsense/mvc/app/views/OPNsense/Firewall/nat_rule.volt index e9f364c684..546367da08 100644 --- a/src/opnsense/mvc/app/views/OPNsense/Firewall/dnat_rule.volt +++ b/src/opnsense/mvc/app/views/OPNsense/Firewall/nat_rule.volt @@ -1,5 +1,5 @@ {# - # Copyright (c) 2025 Deciso B.V. + # Copyright (c) 2025-2026 Deciso B.V. # All rights reserved. # # Redistribution and use in source and binary forms, with or without modification, @@ -27,9 +27,10 @@ - - - -
- - - {{ partial('layout_partials/base_bootgrid_table', formGridNptRule + {'command_width':'150'}) }} -
- -{{ partial('layout_partials/base_apply_button', {'data_endpoint': '/api/firewall/npt/apply'}) }} -{{ partial("layout_partials/base_dialog",{'fields':formDialogNptRule,'id':formGridNptRule['edit_dialog_id'],'label':lang._('Edit NPT Rule')}) }} diff --git a/src/opnsense/mvc/app/views/OPNsense/Firewall/onat_rule.volt b/src/opnsense/mvc/app/views/OPNsense/Firewall/onat_rule.volt deleted file mode 100644 index 12764b4f24..0000000000 --- a/src/opnsense/mvc/app/views/OPNsense/Firewall/onat_rule.volt +++ /dev/null @@ -1,597 +0,0 @@ -{# - # Copyright (c) 2025 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. - #} - - - - - -
- - - {{ partial('layout_partials/base_bootgrid_table', formGridOneToOneNatRule + {'command_width':'150'}) }} -
- -{{ partial('layout_partials/base_apply_button', {'data_endpoint': '/api/firewall/one_to_one/apply'}) }} -{{ partial("layout_partials/base_dialog",{'fields':formDialogOneToOneNatRule,'id':formGridOneToOneNatRule['edit_dialog_id'],'label':lang._('Edit One-to-One Nat')}) }} diff --git a/src/opnsense/mvc/app/views/OPNsense/Firewall/snat_rule.volt b/src/opnsense/mvc/app/views/OPNsense/Firewall/snat_rule.volt deleted file mode 100644 index bb44302106..0000000000 --- a/src/opnsense/mvc/app/views/OPNsense/Firewall/snat_rule.volt +++ /dev/null @@ -1,623 +0,0 @@ -{# - # Copyright (c) 2025 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. - #} - - - - - -
- - - {{ partial('layout_partials/base_bootgrid_table', formGridSNatRule + {'command_width':'150'}) }} -
- -{{ partial('layout_partials/base_apply_button', {'data_endpoint': '/api/firewall/source_nat/apply'}) }} -{{ partial("layout_partials/base_dialog",{'fields':formDialogSNatRule,'id':formGridSNatRule['edit_dialog_id'],'label':lang._('Edit Source Nat')}) }}