diff --git a/src/etc/inc/filter.inc b/src/etc/inc/filter.inc index 24d210cb4..6abd89314 100644 --- a/src/etc/inc/filter.inc +++ b/src/etc/inc/filter.inc @@ -256,12 +256,6 @@ function filter_configure_sync($verbose = false, $load_aliases = true) } } - if (!empty($config['nat']['onetoone'])) { - // register user 1:1 mappings - foreach ($config['nat']['onetoone'] as $rule) { - $fw->registerDNatRule(500, $rule); - } - } if (!empty($config['nat']['rule'])) { // register user forward rules foreach ($config['nat']['rule'] as $rule) { diff --git a/src/etc/inc/plugins.inc.d/pf.inc b/src/etc/inc/plugins.inc.d/pf.inc index da2f18f3a..64ec8bee5 100644 --- a/src/etc/inc/plugins.inc.d/pf.inc +++ b/src/etc/inc/plugins.inc.d/pf.inc @@ -180,6 +180,9 @@ function pf_firewall($fw) foreach ($mdlFilter->snatrules->rule->sortedBy(["sequence"]) as $key => $rule) { $fw->registerSNatRule(50, $rule->serialize()); } + foreach ($mdlFilter->onetoone->rule->sortedBy(["sequence"]) as $key => $rule) { + $fw->registerDNatRule(500, $rule->serialize()); + } foreach ($mdlFilter->npt->rule->sortedBy(["sequence"]) as $key => $rule) { $fw->registerNptRule(50, $rule->serialize()); } diff --git a/src/opnsense/mvc/app/controllers/OPNsense/Firewall/Api/OneToOneController.php b/src/opnsense/mvc/app/controllers/OPNsense/Firewall/Api/OneToOneController.php new file mode 100644 index 000000000..665d02130 --- /dev/null +++ b/src/opnsense/mvc/app/controllers/OPNsense/Firewall/Api/OneToOneController.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("onetoone.rule", null, "sequence", $filter_funct); + } + + public function setRuleAction($uuid) + { + return $this->setBase("rule", "onetoone.rule", $uuid); + } + + public function addRuleAction() + { + return $this->addBase("rule", "onetoone.rule"); + } + + public function getRuleAction($uuid = null) + { + return $this->getBase("rule", "onetoone.rule", $uuid); + } + + public function delRuleAction($uuid) + { + return $this->delBase("onetoone.rule", $uuid); + } + + public function toggleRuleAction($uuid, $enabled = null) + { + return $this->toggleBase("onetoone.rule", $uuid, $enabled); + } +} diff --git a/src/opnsense/mvc/app/controllers/OPNsense/Firewall/OneToOneController.php b/src/opnsense/mvc/app/controllers/OPNsense/Firewall/OneToOneController.php new file mode 100644 index 000000000..a0087f6c2 --- /dev/null +++ b/src/opnsense/mvc/app/controllers/OPNsense/Firewall/OneToOneController.php @@ -0,0 +1,62 @@ +view->pick('OPNsense/Firewall/filter'); + $this->view->ruleController = "one_to_one"; + $this->view->gridFields = [ + [ + 'id' => 'enabled', 'formatter' => 'rowtoggle' ,'width' => '6em', 'heading' => gettext('Enabled') + ], + [ + 'id' => 'sequence','width' => '9em', 'heading' => gettext('Sequence') + ], + [ + 'id' => 'interface','width' => '9em', 'heading' => gettext('Interface') + ], + [ + 'id' => 'target', 'heading' => gettext('External') + ], + [ + 'id' => 'source_net', 'heading' => gettext('Internal') + ], + [ + 'id' => 'destination_net', 'heading' => gettext('Destination') + ], + [ + 'id' => 'description', 'heading' => gettext('Description') + ] + ]; + + $this->view->formDialogFilterRule = $this->getForm("dialogOneToOneRule"); + } +} diff --git a/src/opnsense/mvc/app/controllers/OPNsense/Firewall/forms/dialogOneToOneRule.xml b/src/opnsense/mvc/app/controllers/OPNsense/Firewall/forms/dialogOneToOneRule.xml new file mode 100644 index 000000000..3ed678b25 --- /dev/null +++ b/src/opnsense/mvc/app/controllers/OPNsense/Firewall/forms/dialogOneToOneRule.xml @@ -0,0 +1,81 @@ +
+ + rule.enabled + + checkbox + Enable this rule + + + rule.sequence + + text + + + rule.log + + checkbox + Log packets that are handled by this rule + + + rule.interface + + dropdown + Choose which interface this rule applies to. Hint: in most cases, you'll want to use WAN here + + + rule.type + + dropdown + + Select BINAT (default) or NAT here, when nets are equally sized binat is usually the best option.Using NAT we can also map unequal sized networks. +A BINAT rule specifies a bidirectional mapping between an external and internal network and can be used from both ends, nat only applies in one direction. + + + + + rule.external + + text + Enter the external subnet's starting address for the 1:1 mapping or network. This is the address or network the traffic will translate to/from. + + + rule.source_not + + checkbox + true + Use this option to invert the sense of the match. + + + rule.source_net + + text + + Enter the internal subnet for the 1:1 mapping. + + + rule.destination_not + + checkbox + true + Use this option to invert the sense of the match. + + + rule.destination_net + + text + + The 1:1 mapping will only be used for connections to or from the specified destination. Hint: this is usually 'any'. + + + rule.categories + + select_multiple + + For grouping purposes you may select multiple groups here to organize items. + + + rule.description + + text + +
diff --git a/src/opnsense/mvc/app/models/OPNsense/Core/ACL/ACL.xml b/src/opnsense/mvc/app/models/OPNsense/Core/ACL/ACL.xml index 0aed6b02c..f4c1c402e 100644 --- a/src/opnsense/mvc/app/models/OPNsense/Core/ACL/ACL.xml +++ b/src/opnsense/mvc/app/models/OPNsense/Core/ACL/ACL.xml @@ -238,18 +238,6 @@ api/firewall/category/* - - Firewall: NAT: 1:1 - - firewall_nat_1to1.php* - - - - Firewall: NAT: 1:1: Edit - - firewall_nat_1to1_edit.php* - - Firewall: NAT: Outbound diff --git a/src/opnsense/mvc/app/models/OPNsense/Core/Menu/Menu.xml b/src/opnsense/mvc/app/models/OPNsense/Core/Menu/Menu.xml index cdd92bab1..9cc933e06 100644 --- a/src/opnsense/mvc/app/models/OPNsense/Core/Menu/Menu.xml +++ b/src/opnsense/mvc/app/models/OPNsense/Core/Menu/Menu.xml @@ -133,9 +133,6 @@ - - - diff --git a/src/opnsense/mvc/app/models/OPNsense/Firewall/ACL/ACL.xml b/src/opnsense/mvc/app/models/OPNsense/Firewall/ACL/ACL.xml index a3360c71e..75ff96451 100644 --- a/src/opnsense/mvc/app/models/OPNsense/Firewall/ACL/ACL.xml +++ b/src/opnsense/mvc/app/models/OPNsense/Firewall/ACL/ACL.xml @@ -20,4 +20,11 @@ api/firewall/npt/* + + Firewall: NAT: 1:1 + + ui/firewall/one_to_one/* + api/firewall/one_to_one/* + + diff --git a/src/opnsense/mvc/app/models/OPNsense/Firewall/Filter.php b/src/opnsense/mvc/app/models/OPNsense/Firewall/Filter.php index 179cbef3b..2b4ca0803 100644 --- a/src/opnsense/mvc/app/models/OPNsense/Firewall/Filter.php +++ b/src/opnsense/mvc/app/models/OPNsense/Firewall/Filter.php @@ -134,6 +134,44 @@ class Filter extends BaseModel } } } + /* 1 to 1 mappings */ + foreach ($this->onetoone->rule->iterateItems() as $rule) { + if ($validateFullModel || $rule->isFieldChanged()) { + $ipprotos = []; + $subnets = []; + foreach (['source_net', 'destination_net', 'external'] as $fieldname) { + $subnets[$fieldname] = null; + if (Util::isSubnet($rule->$fieldname) || Util::isIpAddress($rule->$fieldname)) { + $ipprotos[$fieldname] = strpos($rule->$fieldname, ':') === false ? "inet" : "inet6"; + $subnet_default = $ipprotos[$fieldname] == 'inet' ? '32' : '128'; + $subnets[$fieldname] = explode('/', $rule->$fieldname . '/'.$subnet_default)[1]; + } + } + if (count(array_unique(array_values($ipprotos))) > 1) { + foreach (array_keys($ipprotos) as $fieldname) { + $messages->appendMessage(new Message( + gettext("IP protocol families should match."), + $rule->$fieldname->__reference + )); + } + } + + if ($rule->type == 'binat' && !empty((string)$rule->enabled)) { + /* binat rules are more strict, when not enabled, we may skip the validations to ease migration */ + if (empty($ipprotos['source_net'])) { + $messages->appendMessage(new Message( + gettext("For BINAT rules only addresses or subnets are allowed."), + $rule->source_net->__reference + )); + } elseif ($subnets['external'] != $subnets['source_net']) { + $messages->appendMessage(new Message( + gettext("External subnet should match internal subnet."), + $rule->external->__reference + )); + } + } + } + } return $messages; } diff --git a/src/opnsense/mvc/app/models/OPNsense/Firewall/Filter.xml b/src/opnsense/mvc/app/models/OPNsense/Firewall/Filter.xml index eb45df3ac..fc33921bd 100644 --- a/src/opnsense/mvc/app/models/OPNsense/Firewall/Filter.xml +++ b/src/opnsense/mvc/app/models/OPNsense/Firewall/Filter.xml @@ -1,6 +1,6 @@ //OPNsense/Firewall/Filter - 1.0.3 + 1.0.4 MFP OPNsense firewall filter rules @@ -245,5 +245,75 @@ + + + + 1 + Y + + + 0 + Y + + + 1 + 99999 + provide a valid sequence for sorting + Y + 1 + + + Y + wan + Y + + + binat + Y + + BINAT + NAT + + + + Y + + + 0 + Y + + + Y + any + + + 0 + Y + + + Y + N + + + + default + Enable + Disable + + + + + + OPNsense.Firewall.Category + categories.category + name + + + Y + Related category not found. + + + + diff --git a/src/opnsense/mvc/app/models/OPNsense/Firewall/Menu/Menu.xml b/src/opnsense/mvc/app/models/OPNsense/Firewall/Menu/Menu.xml index c39018399..4c6cb39ad 100644 --- a/src/opnsense/mvc/app/models/OPNsense/Firewall/Menu/Menu.xml +++ b/src/opnsense/mvc/app/models/OPNsense/Firewall/Menu/Menu.xml @@ -9,6 +9,9 @@ + + + diff --git a/src/opnsense/mvc/app/models/OPNsense/Firewall/Migrations/MFP1_0_4.php b/src/opnsense/mvc/app/models/OPNsense/Firewall/Migrations/MFP1_0_4.php new file mode 100644 index 000000000..a457021c2 --- /dev/null +++ b/src/opnsense/mvc/app/models/OPNsense/Firewall/Migrations/MFP1_0_4.php @@ -0,0 +1,107 @@ + + +class MFP1_0_4 extends BaseModelMigration +{ + public function run($model) + { + if ($model instanceof Filter) { + $sequence = 1; + $catmdl = new Category(); + foreach ((Config::getInstance()->object())->nat->children() as $child) { + if ($child->getName() == 'onetoone') { + $addr = [] ; + foreach (['destination', 'source'] as $fieldname) { + if (!empty(((string)$child->$fieldname->any))) { + $addr[$fieldname] = 'any'; + } elseif (Util::isSubnet((string)$child->$fieldname->address)) { + $addr[$fieldname] = (string)$child->$fieldname->address; + } elseif (Util::isIpAddress((string)$child->$fieldname->address)) { + $subn = strpos($child->$fieldname->address, ':') === false ? '32' : '128'; + $addr[$fieldname] = (string)$child->$fieldname->address . '/' . $subn; + } elseif (!empty((string)$child->$fieldname->address)) { + $addr[$fieldname] = (string)$child->$fieldname->address; + } elseif (!empty((string)$child->$fieldname->network)) { + $addr[$fieldname] = (string)$child->$fieldname->network; + } else { + $addr[$fieldname] = null; + } + } + + if (!empty($addr['source']) && !empty($addr['destination']) && !empty((string)$child->external)) { + $node = $model->onetoone->rule->Add(); + $node->enabled = empty((string)$child->disabled) ? "1" : "0"; + $node->log = empty((string)$child->log) ? "0" : "1"; + $node->sequence = (string)($sequence++); + if (!empty((string)$child->category)) { + $cats = []; + foreach (explode(',', (string)$child->category) as $cat) { + $tmp = $catmdl->getByName($cat); + if ($tmp != null) { + $cats[] = $tmp->getAttributes()['uuid']; + } + } + $node->categories = implode(",", $cats); + } + $node->interface = (string)$child->interface; + $node->type = !empty((string)$child->type) ? (string)$child->type : 'binat'; + $node->external = (string)$child->external; + $node->source_net = $addr['source']; + $node->destination_net = $addr['source']; + $node->source_not = !empty((string)$child->source->not) ? '1' : '0'; + $node->destination_not = !empty((string)$child->destination->not) ? '1' : '0'; + + $node->description = (string)$child->descr; + } + } + } + } + } + + public function post($model) + { + if ($model instanceof Filter) { + $cfgObj = Config::getInstance()->object(); + if (isset($cfgObj->nat->onetoone)) { + unset($cfgObj->nat->onetoone); + } + } + } +} diff --git a/src/www/firewall_nat_1to1.php b/src/www/firewall_nat_1to1.php deleted file mode 100644 index c3abd7f1e..000000000 --- a/src/www/firewall_nat_1to1.php +++ /dev/null @@ -1,410 +0,0 @@ - - * 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("guiconfig.inc"); -require_once("interfaces.inc"); -require_once("filter.inc"); - -$a_1to1 = &config_read_array('nat', 'onetoone'); - -if ($_SERVER['REQUEST_METHOD'] === 'POST') { - $pconfig = $_POST; - if (isset($pconfig['id']) && isset($a_1to1[$pconfig['id']])) { - // id found and valid - $id = $pconfig['id']; - } - - if (isset($pconfig['apply'])) { - filter_configure(); - $savemsg = get_std_save_message(); - clear_subsystem_dirty('natconf'); - clear_subsystem_dirty('filter'); - } elseif (isset($pconfig['action']) && $pconfig['action'] == 'del' && isset($id)) { - // delete single entry - unset($a_1to1[$id]); - write_config(); - mark_subsystem_dirty('natconf'); - header(url_safe('Location: /firewall_nat_1to1.php')); - exit; - } elseif (isset($pconfig['action']) && $pconfig['action'] == 'del_x' && isset($pconfig['rule']) && count($pconfig['rule']) > 0) { - // delete selected - foreach ($pconfig['rule'] as $rulei) { - unset($a_1to1[$rulei]); - } - write_config(); - mark_subsystem_dirty('natconf'); - header(url_safe('Location: /firewall_nat_1to1.php')); - exit; - } elseif (isset($pconfig['action']) && in_array($pconfig['action'], array('toggle_enable', 'toggle_disable')) && isset($pconfig['rule']) && count($pconfig['rule']) > 0) { - foreach ($pconfig['rule'] as $rulei) { - $a_1to1[$rulei]['disabled'] = $pconfig['action'] == 'toggle_disable'; - } - write_config(); - mark_subsystem_dirty('natconf'); - header(url_safe('Location: /firewall_nat_1to1.php')); - exit; - } elseif (isset($pconfig['action']) && $pconfig['action'] == 'move') { - // move selected - if (isset($pconfig['rule']) && count($pconfig['rule']) > 0) { - // if rule not set/found, move to end - if (!isset($id)) { - $id = count($a_1to1); - } - $a_1to1 = legacy_move_config_list_items($a_1to1, $id, $pconfig['rule']); - - write_config(); - mark_subsystem_dirty('natconf'); - header(url_safe('Location: /firewall_nat_1to1.php')); - exit; - } - } elseif (isset($pconfig['action']) && $pconfig['action'] == 'toggle' && isset($id)) { - // toggle item - if(isset($a_1to1[$id]['disabled'])) { - unset($a_1to1[$id]['disabled']); - } else { - $a_1to1[$id]['disabled'] = true; - } - write_config('Toggled NAT 1:1 rule'); - mark_subsystem_dirty('natconf'); - header(url_safe('Location: /firewall_nat_1to1.php')); - exit; - } -} - -legacy_html_escape_form_data($a_1to1); - -include("head.inc"); - -?> - - - - - - -
-
-
-" . - gettext("You must apply the changes in order for them to take effect.")); -?> -
-
-
- - - - - - - - - - - - - - - - - - - " data-category="" ondblclick="document.location='firewall_nat_1to1_edit.php?id=';"> - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  - - - - - - - - -
- - - " class="act_toggle"> - - - - - - - - - - - -   - - - - -   - - " data-toggle="tooltip"> - - - - - - - - -   - - " data-toggle="tooltip"> - - - - - - -   - - " class="act_move btn btn-default btn-xs"> - - - - - - - - - - - -
- -
-
-
-
-
-
-
- - diff --git a/src/www/firewall_nat_1to1_edit.php b/src/www/firewall_nat_1to1_edit.php deleted file mode 100644 index a933142fd..000000000 --- a/src/www/firewall_nat_1to1_edit.php +++ /dev/null @@ -1,475 +0,0 @@ - - * 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("guiconfig.inc"); -require_once("interfaces.inc"); - -$a_1to1 = &config_read_array('nat', 'onetoone'); - -if ($_SERVER['REQUEST_METHOD'] === 'GET') { - // input record id, if valid - if (isset($_GET['dup']) && isset($a_1to1[$_GET['dup']])) { - $configId = $_GET['dup']; - } elseif (isset($_GET['id']) && isset($a_1to1[$_GET['id']])) { - $id = $_GET['id']; - $configId = $id; - } - - $pconfig = array(); - // set defaults - $pconfig['interface'] = "wan"; - $pconfig['src'] = 'lan'; - $pconfig['dst'] = 'any'; - $pconfig['type'] = 'binat'; - if (isset($configId)) { - // copy settings from config - foreach (array('disabled','interface','external','descr','natreflection', 'type', 'category') as $fieldname) { - if (isset($a_1to1[$configId][$fieldname])) { - $pconfig[$fieldname] = $a_1to1[$configId][$fieldname]; - } else { - $pconfig[$fieldname] = null; - } - } - // read settings with some kind of logic - address_to_pconfig( - $a_1to1[$configId]['source'], $pconfig['src'], - $pconfig['srcmask'], $pconfig['srcnot'], - $pconfig['__unused__'],$pconfig['__unused__'] - ); - - address_to_pconfig( - $a_1to1[$configId]['destination'], $pconfig['dst'], - $pconfig['dstmask'], $pconfig['dstnot'], - $pconfig['__unused__'],$pconfig['__unused__'] - ); - } else { - // init form data on new - foreach (array('disabled','interface','external','descr','natreflection' - ,'src','srcmask','srcnot','dst','dstmask','dstnot' - ) as $fieldname) { - if (!isset($pconfig[$fieldname])) { - $pconfig[$fieldname] = null; - } - } - } - $pconfig['category'] = !empty($pconfig['category']) ? explode(",", $pconfig['category']) : []; -} elseif ($_SERVER['REQUEST_METHOD'] === 'POST') { - $input_errors = array(); - $pconfig = $_POST; - // input record id, if valid - if (isset($_POST['id']) && isset($a_1to1[$_POST['id']])) { - $id = $_POST['id']; - } - - // trim input - foreach (array('external','src','dst') as $fieldname) { - if (isset($pconfig[$fieldname])) { - $pconfig[$fieldname] = trim($pconfig[$fieldname]); - } - } - - /* input validation */ - $reqdfields = explode(" ", "interface external src dst"); - $reqdfieldsn = array(gettext("Interface"), gettext("External subnet"), gettext("Source address"), gettext("Destination address")); - do_input_validation($pconfig, $reqdfields, $reqdfieldsn, $input_errors); - - - /* For external, user can enter only ip's */ - $tmpext = explode('/', $pconfig['external']); - if (!empty($pconfig['external'])) { - if ($pconfig['type'] == 'binat' && (!is_ipaddr($tmpext[0]) || (count($tmpext) != 1 && $pconfig['srcmask'] != $tmpext[1]))) { - $input_errors[] = gettext("A valid external subnet must be specified."); - } elseif ($pconfig['type'] == 'nat' && !is_subnet($pconfig['external'])) { - $input_errors[] = gettext("A valid external subnet must be specified."); - } - } - /* For src, user can enter only ip's or networks */ - if ($pconfig['type'] == 'binat' && !is_subnet($pconfig['src']) && !is_ipaddr($pconfig['src'])) { - $input_errors[] = sprintf(gettext("%s is not a valid source IP address."), $pconfig['src']); - } elseif (!is_specialnet($pconfig['src']) && !is_ipaddroralias($pconfig['src'])) { - $input_errors[] = sprintf(gettext("%s is not a valid source IP address or alias."), $pconfig['src']); - } - if (!empty($pconfig['srcmask']) && !is_numericint($pconfig['srcmask'])) { - $input_errors[] = gettext("A valid source bit count must be specified."); - } - /* For dst, user can enter ip's, networks or aliases */ - if (!is_specialnet($pconfig['dst']) && !is_ipaddroralias($pconfig['dst'])) { - $input_errors[] = sprintf(gettext("%s is not a valid destination IP address or alias."), $pconfig['dst']); - } - if (!empty($pconfig['dstmask']) && !is_numericint($pconfig['dstmask'])) { - $input_errors[] = gettext("A valid destination bit count must be specified."); - } - - if (count($input_errors) == 0) { - $natent = array(); - // 1-on-1 copy - $natent['external'] = $pconfig['external']; - $natent['category'] = !empty($pconfig['category']) ? implode(",", $pconfig['category']) : null; - $natent['descr'] = $pconfig['descr']; - $natent['interface'] = $pconfig['interface']; - $natent['type'] = $pconfig['type']; - - // copy form data with some kind of logic in it - $natent['disabled'] = isset($_POST['disabled']) ? true:false; - pconfig_to_address($natent['source'], $pconfig['src'], - $pconfig['srcmask'], !empty($pconfig['srcnot'])); - - pconfig_to_address($natent['destination'], $pconfig['dst'], - $pconfig['dstmask'], !empty($pconfig['dstnot'])); - - if (isset($pconfig['natreflection'] ) && ($pconfig['natreflection'] == "enable" || $pconfig['natreflection'] == "disable")) { - $natent['natreflection'] = $pconfig['natreflection']; - } - - // save data - if (isset($id)) { - $a_1to1[$id] = $natent; - } else { - $a_1to1[] = $natent; - } - - OPNsense\Core\Config::getInstance()->fromArray($config); - $catmdl = new OPNsense\Firewall\Category(); - if ($catmdl->sync()) { - $catmdl->serializeToConfig(); - $config = OPNsense\Core\Config::getInstance()->toArray(listtags()); - } - write_config(); - mark_subsystem_dirty('natconf'); - header(url_safe('Location: /firewall_nat_1to1.php')); - exit; - } -} - -legacy_html_escape_form_data($pconfig); - -include("head.inc"); - -?> - - - - - - - - -
-
-
- 0) - print_input_errors($input_errors); -?> -
-
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - -
- /> - -
- - -
- - -
- - -
- /> - -
- - - - -
- -
- - - - - - -
- "/> - - -
- -
- /> - -
- - - - -
- -
- - - - - - -
- " aria-label=""/> - - -
- -
- - -
- - -
- -
  - - - - - -
-
-
-
-
-
-
-
-