* Copyright (C) 2003-2004 Manuel Kasper * 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"); /* TCP flags */ $tcpflags = array("syn", "ack", "fin", "rst", "psh", "urg", "ece", "cwr"); /* OS types, request from backend */ $ostypes = json_decode(configd_run('filter list osfp json')); if ($ostypes == null) { $ostypes = array(); } $gateways = new \OPNsense\Routing\Gateways(); $shaper_targets = (new \OPNsense\TrafficShaper\TrafficShaper())->fetchAllTargets(); /** * check if advanced options are set on selected element */ function FormSetAdvancedOptions(&$item) { foreach (array("max", "max-src-nodes", "max-src-conn", "max-src-states","nopfsync", "statetimeout", "adaptivestart" , "adaptiveend", "max-src-conn-rate","max-src-conn-rates", "tag", "tagged", "allowopts", "reply-to","tcpflags1" ,"tcpflags2", "tos", "state-policy") as $fieldname) { if (strlen($item[$fieldname]) > 0) { return true; } } // check these fields for anything being set except a blank string foreach (array('set-prio', 'set-prio-low', 'prio') as $fieldname) { if (isset($item[$fieldname]) && $item[$fieldname] !== '') { return true; } } if (!empty($item["statetype"]) && $item["statetype"] != 'keep state') { return true; } return false; } function is_posnumericint($arg) { // Note that to be safe we do not allow any leading zero - "01", "007" return (is_numericint($arg) && $arg[0] != '0' && $arg > 0); } $a_filter = &config_read_array('filter', 'rule'); if ($_SERVER['REQUEST_METHOD'] === 'GET') { // input record id, if valid if (isset($_GET['dup']) && isset($a_filter[$_GET['dup']])) { $configId = $_GET['dup']; $after = $configId; } elseif (isset($_GET['id']) && isset($a_filter[$_GET['id']])) { $id = $_GET['id']; $configId = $id; } elseif (isset($_GET['get_address_options'])) { /* XXX: no beauty contest here, we need the same valid options as MVC, just dump them... */ echo json_encode((new OPNsense\Firewall\Api\FilterController())->listNetworkSelectOptionsAction()); exit(0); } // define form fields $config_fields = [ 'allowopts', 'associated-rule-id', 'category', 'descr', 'direction', 'disabled', 'disablereplyto', 'reply-to', 'floating', 'gateway', 'icmptype', 'icmp6-type', 'interfacenot', 'interface', 'ipprotocol', 'log', 'max', 'max-src-conn', 'max-src-conn-rate', 'max-src-conn-rates', 'adaptivestart', 'adaptiveend', 'overload', 'max-src-nodes', 'max-src-states', 'nopfsync', 'nosync', 'os', 'prio', 'protocol', 'quick', 'sched', 'set-prio', 'set-prio-low', 'statetimeout', 'statetype', 'state-policy', 'tag', 'tagged', 'tcpflags1', 'tcpflags2', 'tcpflags_any', 'type', 'tos', 'shaper1', 'shaper2' ]; $pconfig = array(); $pconfig['type'] = "pass"; $pconfig['protocol'] = "any"; if (isset($configId)) { // 1-on-1 copy of config data foreach ($config_fields as $fieldname) { if (isset($a_filter[$configId][$fieldname])) { $pconfig[$fieldname] = $a_filter[$configId][$fieldname]; } } $pconfig['category'] = !empty($pconfig['category']) ? explode(",", $pconfig['category']) : []; // process fields with some kind of logic address_to_pconfig( $a_filter[$configId]['source'], $pconfig['src'], $ignore, /* XXX: ignored */ $pconfig['srcnot'], $pconfig['srcbeginport'], $pconfig['srcendport'], true ); address_to_pconfig( $a_filter[$configId]['destination'], $pconfig['dst'], $ignore, /* XXX: ignored */ $pconfig['dstnot'], $pconfig['dstbeginport'], $pconfig['dstendport'], true ); if (isset($id) && isset($a_filter[$configId]['associated-rule-id'])) { // do not link on rule copy. $pconfig['associated-rule-id'] = $a_filter[$configId]['associated-rule-id']; } } else { /* defaults */ if (isset($_GET['if'])) { if ($_GET['if'] == "FloatingRules" ) { $pconfig['floating'] = true; $pconfig['quick'] = true; } else { $pconfig['interface'] = $_GET['if']; } } $pconfig['src'] = "any"; $pconfig['dst'] = "any"; } // initialize empty fields foreach ($config_fields as $fieldname) { if (!isset($pconfig[$fieldname])) { $pconfig[$fieldname] = null; } } // replyto switch $pconfig['reply-to'] = !empty($pconfig['disablereplyto']) ? "__disable__" : $pconfig['reply-to']; } elseif ($_SERVER['REQUEST_METHOD'] === 'POST') { $input_errors = array(); $pconfig = $_POST; // input record id, if valid if (isset($pconfig['id']) && isset($a_filter[$pconfig['id']])) { $id = $pconfig['id']; } if (isset($pconfig['after']) && isset($a_filter[$pconfig['after']])) { $after = $pconfig['after']; } // preprocessing form fields which differ in presentation / actual storage if (empty($pconfig['tcpflags_any'])) { $settcpflags = array(); $outoftcpflags = array(); foreach ($tcpflags as $tcpflag) { if (isset($pconfig['tcpflags1_' . $tcpflag]) && $pconfig['tcpflags1_' . $tcpflag] == "on") $settcpflags[] = $tcpflag; if (isset($pconfig['tcpflags2_' . $tcpflag]) && $pconfig['tcpflags2_' . $tcpflag] == "on") $outoftcpflags[] = $tcpflag; } // flags should be set within if (!empty($outoftcpflags)) { $pconfig['tcpflags2'] = join(",", $outoftcpflags); } if (!empty($settcpflags)) { $pconfig['tcpflags1'] = join(",", $settcpflags); } } // validate form input $reqdfields = array("ipprotocol","type","protocol","src","dst"); $reqdfieldsn = array(gettext("TCP/IP Version"),gettext("Type") ,gettext("Protocol"),gettext("Source"),gettext("Destination")); do_input_validation($_POST, $reqdfields, $reqdfieldsn, $input_errors); if (!empty($pconfig['interfacenot']) && ( (is_array($pconfig['interface']) && count($pconfig['interface']) != 1 ) || empty($pconfig['interface'])) ) { $input_errors[] = gettext("Inverting interfaces is only allowed for single targets to avoid mis-interpretations"); } if ($pconfig['ipprotocol'] == "inet46" && !empty($pconfig['gateway'])) { $input_errors[] = gettext("You can not assign a gateway to a rule that applies to IPv4 and IPv6"); } if (!empty($pconfig['gateway']) && isset($config['gateways']['gateway_group'])) { $family = $gateways->getGroupIPProto($pconfig['gateway']); if ($family !== null && $pconfig['ipprotocol'] == "inet6" && $pconfig['ipprotocol'] != $family) { $input_errors[] = gettext('You can not assign an IPv4 gateway group on an IPv6 rule.'); } if ($family !== null && $pconfig['ipprotocol'] == "inet" && $pconfig['ipprotocol'] != $family) { $input_errors[] = gettext('You can not assign an IPv6 gateway group on an IPv4 rule.'); } } if (!empty($pconfig['gateway']) && is_ipaddr($gateways->getAddress($pconfig['gateway']))) { if ($pconfig['ipprotocol'] == "inet6" && !is_ipaddrv6($gateways->getAddress($pconfig['gateway']))) { $input_errors[] = gettext('You can not assign the IPv4 Gateway to an IPv6 filter rule.'); } if ($pconfig['ipprotocol'] == "inet" && !is_ipaddrv4($gateways->getAddress($pconfig['gateway']))) { $input_errors[] = gettext('You can not assign the IPv6 Gateway to an IPv4 filter rule.'); } } if ($pconfig['ipprotocol'] == "inet46" && !empty($pconfig['reply-to']) && $pconfig['reply-to'] != '__disable__') { $input_errors[] = gettext("You can not assign a reply-to destination to a rule that applies to IPv4 and IPv6"); } elseif (!empty($pconfig['gateway']) && !empty($pconfig['reply-to']) && $pconfig['reply-to'] != '__disable__') { $input_errors[] = gettext('You can not assign a reply-to destination to a rule that uses a gateway.'); } elseif (!empty($pconfig['reply-to']) && is_ipaddr($gateways->getAddress($pconfig['reply-to']))) { if ($pconfig['ipprotocol'] == "inet6" && !is_ipaddrv6($gateways->getAddress($pconfig['reply-to']))) { $input_errors[] = gettext('You can not assign the IPv4 reply-to destination to an IPv6 filter rule.'); } if ($pconfig['ipprotocol'] == "inet" && !is_ipaddrv4($gateways->getAddress($pconfig['reply-to']))) { $input_errors[] = gettext('You can not assign the IPv6 reply-to destination to an IPv4 filter rule.'); } } if ($pconfig['protocol'] == "icmp" && !empty($pconfig['icmptype']) && $pconfig['ipprotocol'] == "inet46") { $input_errors[] = gettext('You can not assign an ICMP type to a rule that applies to IPv4 and IPv6.'); } elseif ($pconfig['protocol'] == "ipv6-icmp" && !empty($pconfig['icmp6-type']) && $pconfig['ipprotocol'] == "inet46") { $input_errors[] = gettext('You can not assign an ICMP type to a rule that applies to IPv4 and IPv6.'); } elseif ($pconfig['protocol'] == "ipv6-icmp" && $pconfig['ipprotocol'] != "inet6") { $input_errors[] = gettext('You can not assign an ICMP type to a rule that applies to IPv4 and IPv6.'); } if ($pconfig['statetype'] == "synproxy state" || $pconfig['statetype'] == "modulate state") { if ($pconfig['protocol'] != "tcp") { $input_errors[] = sprintf(gettext("%s is only valid with protocol tcp."),$pconfig['statetype']); } if($pconfig['gateway'] != "") { $input_errors[] = sprintf(gettext("%s is only valid if the gateway is set to 'default'."),$pconfig['statetype']); } } if (!empty($pconfig['srcbeginport']) && !is_portoralias($pconfig['srcbeginport']) && $pconfig['srcbeginport'] != 'any') { $input_errors[] = sprintf(gettext("%s is not a valid start source port. It must be a port alias or integer between 1 and 65535."),$pconfig['srcbeginport']); } if (!empty($pconfig['srcendport']) && !is_portoralias($pconfig['srcendport']) && $pconfig['srcendport'] != 'any') { $input_errors[] = sprintf(gettext("%s is not a valid end source port. It must be a port alias or integer between 1 and 65535."),$pconfig['srcendport']); } if (!empty($pconfig['dstbeginport']) && !is_portoralias($pconfig['dstbeginport']) && $pconfig['dstbeginport'] != 'any') { $input_errors[] = sprintf(gettext("%s is not a valid start destination port. It must be a port alias or integer between 1 and 65535."),$pconfig['dstbeginport']); } if (!empty($pconfig['dstendport']) && !is_portoralias($pconfig['dstendport']) && $pconfig['dstendport'] != 'any') { $input_errors[] = sprintf(gettext("%s is not a valid end destination port. It must be a port alias or integer between 1 and 65535."),$pconfig['dstendport']); } if (!empty($pconfig['srcbeginport']) && !empty($pconfig['srcendport'])) { if ((is_alias($pconfig['srcbeginport']) || is_alias($pconfig['srcendport'])) && $pconfig['srcbeginport'] != $pconfig['srcendport']) { $input_errors[] = gettext('When selecting aliases for source ports, both from and to fields must be the same'); } } if (!empty($pconfig['dstbeginport']) && !empty($pconfig['dstendport'])) { if ((is_alias($pconfig['dstbeginport']) || is_alias($pconfig['dstendport'])) && $pconfig['dstbeginport'] != $pconfig['dstendport']) { $input_errors[] = gettext('When selecting aliases for destination ports, both from and to fields must be the same'); } } if (strpos($pconfig['src'], ',') > 0) { foreach (explode(',', $pconfig['src']) as $tmp) { if (!is_specialnet($tmp) && !is_alias($tmp)) { $input_errors[] = sprintf(gettext("%s is not a valid source alias."), $tmp); } } } elseif (!is_specialnet($pconfig['src']) && !is_ipaddroralias($pconfig['src']) && !is_subnet($pconfig['src'])) { $input_errors[] = sprintf(gettext("%s is not a valid source IP address or alias."),$pconfig['src']); } if (strpos($pconfig['dst'], ',') > 0) { foreach (explode(',', $pconfig['dst']) as $tmp) { if (!is_specialnet($tmp) && !is_alias($tmp)) { $input_errors[] = sprintf(gettext("%s is not a valid destination alias."), $tmp); } } } elseif (!is_specialnet($pconfig['dst']) && !is_ipaddroralias($pconfig['dst']) && !is_subnet($pconfig['dst'])) { $input_errors[] = sprintf(gettext("%s is not a valid destination IP address or alias."),$pconfig['dst']); } if (is_ipaddr($pconfig['src']) && is_ipaddr($pconfig['dst'])) { if ((is_ipaddrv4($pconfig['src']) && is_ipaddrv6($pconfig['dst'])) || (is_ipaddrv6($pconfig['src']) && is_ipaddrv4($pconfig['dst']))) { $input_errors[] = sprintf(gettext("The Source IP address %s Address Family differs from the destination %s."), $pconfig['src'], $pconfig['dst']); } } foreach (array('src', 'dst') as $fam) { if (is_ipaddr($pconfig[$fam])) { if ((is_ipaddrv6($pconfig[$fam]) || is_subnetv6($pconfig[$fam])) && $pconfig['ipprotocol'] == "inet") { $input_errors[] = gettext("You can not use IPv6 addresses in IPv4 rules."); } elseif ((is_ipaddrv4($pconfig[$fam]) || is_subnetv4($pconfig[$fam])) && $pconfig['ipprotocol'] == "inet6") { $input_errors[] = gettext("You can not use IPv4 addresses in IPv6 rules."); } } } if ((is_ipaddr($pconfig['src']) || is_ipaddr($pconfig['dst'])) && ($pconfig['ipprotocol'] == "inet46")) { $input_errors[] = gettext('You can not use an IPv4 or IPv6 address in combined IPv4 + IPv6 rules.'); } if (!empty($pconfig['os'])) { if ($pconfig['protocol'] != "tcp") { $input_errors[] = gettext("OS detection is only valid with protocol tcp."); } if (!in_array($pconfig['os'], $ostypes)) { $input_errors[] = gettext("Invalid OS detection selection. Please select a valid OS."); } } if (!empty($pconfig['floating']) && !empty($pconfig['gateway']) && (empty($pconfig['direction']) || $pconfig['direction'] == "any")) { $input_errors[] = gettext("You can not use gateways in Floating rules without choosing a direction."); } if (!in_array($pconfig['protocol'], array("tcp","tcp/udp"))) { if (!empty($pconfig['max-src-conn'])) $input_errors[] = gettext("You can only specify the maximum number of established connections per host (advanced option) for TCP protocol."); if (!empty($pconfig['max-src-conn-rate']) || !empty($pconfig['max-src-conn-rates'])) $input_errors[] = gettext("You can only specify the maximum new connections per host / per second(s) (advanced option) for TCP protocol."); if (!empty($pconfig['statetimeout'])) $input_errors[] = gettext("You can only specify the state timeout (advanced option) for TCP protocol."); } if ($pconfig['type'] != 'pass') { if (!empty($pconfig['max'])) { $input_errors[] = gettext("You can only specify the maximum state entries (advanced option) for Pass type rules."); } if (!empty($pconfig['max-src-nodes'])) { $input_errors[] = gettext("You can only specify the maximum number of unique source hosts (advanced option) for Pass type rules."); } if (!empty($pconfig['max-src-conn'])) { $input_errors[] = gettext("You can only specify the maximum number of established connections per host (advanced option) for Pass type rules."); } if (!empty($pconfig['max-src-states'])) { $input_errors[] = gettext("You can only specify the maximum state entries per host (advanced option) for Pass type rules."); } if (!empty($pconfig['max-src-conn-rate']) || !empty($pconfig['max-src-conn-rates'])) { $input_errors[] = gettext("You can only specify the maximum new connections per host / per second(s) (advanced option) for Pass type rules."); } if (!empty($pconfig['statetimeout'])) { $input_errors[] = gettext("You can only specify the state timeout (advanced option) for Pass type rules."); } if (strlen($pconfig['adaptivestart']) > 0 || strlen($pconfig['adaptiveend']) > 0) { $input_errors[] = gettext("You can only specify the adaptive timeouts (advanced option) for Pass type rules."); } if (!empty($pconfig['allowopts'])) { $input_errors[] = gettext("You can only specify allow options (advanced option) for Pass type rules."); } } if ($pconfig['statetype'] == "none") { if (!empty($pconfig['max'])) $input_errors[] = gettext("You cannot specify the maximum state entries (advanced option) if statetype is none."); if (!empty($pconfig['max-src-nodes'])) $input_errors[] = gettext("You cannot specify the maximum number of unique source hosts (advanced option) if statetype is none."); if (!empty($pconfig['max-src-conn'])) $input_errors[] = gettext("You cannot specify the maximum number of established connections per host (advanced option) if statetype is none."); if (!empty($pconfig['max-src-states'])) $input_errors[] = gettext("You cannot specify the maximum state entries per host (advanced option) if statetype is none."); if (!empty($pconfig['max-src-conn-rate']) || !empty($pconfig['max-src-conn-rates'])) $input_errors[] = gettext("You cannot specify the maximum new connections per host / per second(s) (advanced option) if statetype is none."); if (!empty($pconfig['statetimeout'])) $input_errors[] = gettext("You cannot specify the state timeout (advanced option) if statetype is none."); if (is_numeric($pconfig['adaptivestart']) || is_numeric($pconfig['adaptiveend'])) { $input_errors[] = gettext("You cannot specify the adaptive timeouts (advanced option) if statetype is none."); } } if (!empty($pconfig['max']) && !is_posnumericint($pconfig['max'])) $input_errors[] = gettext("Maximum state entries (advanced option) must be a positive integer"); if (!empty($pconfig['max-src-nodes']) && !is_posnumericint($pconfig['max-src-nodes'])) $input_errors[] = gettext("Maximum number of unique source hosts (advanced option) must be a positive integer"); if (!empty($pconfig['max-src-conn']) && !is_posnumericint($pconfig['max-src-conn'])) $input_errors[] = gettext("Maximum number of established connections per host (advanced option) must be a positive integer"); if (!empty($pconfig['max-src-states']) && !is_posnumericint($pconfig['max-src-states'])) $input_errors[] = gettext("Maximum state entries per host (advanced option) must be a positive integer"); if (!empty($pconfig['max-src-conn-rate']) && !is_posnumericint($pconfig['max-src-conn-rate'])) $input_errors[] = gettext("Maximum new connections per host / per second(s) (advanced option) must be a positive integer"); if (!empty($pconfig['statetimeout']) && !is_posnumericint($pconfig['statetimeout'])) $input_errors[] = gettext("State timeout (advanced option) must be a positive integer"); if ( (empty($pconfig['max-src-conn-rate']) && !empty($pconfig['max-src-conn-rates'])) || (!empty($pconfig['max-src-conn-rate']) && empty($pconfig['max-src-conn-rates'])) ) { $input_errors[] = gettext("Both maximum new connections per host and the interval (per second(s)) must be specified"); } if (!empty($pconfig['state-policy']) && !in_array($pconfig['state-policy'], ['if-bound', 'floating'])) { $input_errors[] = sprintf(gettext("Invalid state policy type %s"), $pconfig['state-policy']); } if (empty($pconfig['max']) && ($pconfig['adaptivestart'] === "0" || $pconfig['adaptiveend'] === "0")) { $input_errors[] = gettext("Disabling adaptive timeouts is only supported in combination with a configured maximum number of states for the same rule."); } elseif ($pconfig['adaptivestart'] === "0" xor $pconfig['adaptiveend'] === "0") { $input_errors[] = gettext("Adaptive timeouts must be disabled together."); } elseif (strlen($pconfig['adaptivestart']) > 0 xor strlen($pconfig['adaptiveend']) > 0) { $input_errors[] = gettext("The adaptive timouts values must be set together."); } elseif ((!empty($pconfig['adaptivestart']) && !is_numericint($pconfig['adaptivestart'])) || (!empty($pconfig['adaptiveend']) && !is_numericint($pconfig['adaptiveend']))) { $input_errors[] = gettext("The adaptive.start and adaptive.end values (advanced option) must be configured as non-negative integer values."); } elseif (is_posnumericint($pconfig['max']) && is_numericint($pconfig['adaptiveend']) && $pconfig['max'] > $pconfig['adaptiveend']) { $input_errors[] = gettext("The value of adaptive.end must be greater than the Max states value."); } elseif (is_numericint($pconfig['adaptivestart']) && is_numericint($pconfig['adaptiveend']) && $pconfig['adaptivestart'] > $pconfig['adaptiveend']) { $input_errors[] = gettext("The value of adaptive.end must be greater than adaptive.start value."); } if (empty($pconfig['tcpflags2']) && !empty($pconfig['tcpflags1'])) $input_errors[] = gettext("If you specify TCP flags that should be set you should specify out of which flags as well."); if (isset($pconfig['set-prio']) && $pconfig['set-prio'] !== '' && (!is_numericint($pconfig['set-prio']) || $pconfig['set-prio'] < 0 || $pconfig['set-prio'] > 7)) { $input_errors[] = gettext('Set priority must be an integer between 0 and 7.'); } if (isset($pconfig['set-prio-low']) && $pconfig['set-prio-low'] !== '' && (!is_numericint($pconfig['set-prio-low']) || $pconfig['set-prio-low'] < 0 || $pconfig['set-prio-low'] > 7)) { $input_errors[] = gettext('Set priority for low latency and acknowledgements must be an integer between 0 and 7.'); } if (isset($pconfig['set-prio-low']) && $pconfig['set-prio-low'] !== '' && (!isset($pconfig['set-prio']) || $pconfig['set-prio'] === '')) { $input_errors[] = gettext('Set priority for low latency and acknowledgements requires a set priority for normal packets.'); } if (!empty($pconfig['prio']) && (!is_numericint($pconfig['prio']) || $pconfig['prio'] < 0 || $pconfig['prio'] > 7)) { $input_errors[] = gettext('Priority match must be an integer between 0 and 7.'); } if (!empty($pconfig['tos']) && !isset(get_tos_values()[$pconfig['tos']])) { $input_errors[] = gettext('Match TOS/DSCP value invalid.'); } if (!empty($pconfig['overload']) && !is_alias($pconfig['overload'])) { $input_errors[] = gettext('Max new connections overload table should be a valid alias.'); } if (!empty($pconfig['shaper1']) || !empty($pconfig['shaper2'])) { if (!empty($pconfig['shaper1']) && !isset($shaper_targets[$pconfig['shaper1']])) { $input_errors[] = gettext('Unknown traffic shaper selected.'); } elseif (!empty($pconfig['shaper2']) && !isset($shaper_targets[$pconfig['shaper2']])) { $input_errors[] = gettext('Unknown traffic shaper selected.'); } elseif (empty($pconfig['shaper1']) && !empty($pconfig['shaper2'])) { $input_errors[] = gettext('A shaper is required when configuring one in the reverse direction.'); } elseif (!empty($pconfig['shaper1']) && !empty($pconfig['shaper2']) && $shaper_targets[$pconfig['shaper1']]['type'] != $shaper_targets[$pconfig['shaper2']]['type']) { $input_errors[] = gettext('Pipes and queues can not be combined.'); } } if (count($input_errors) == 0) { $filterent = array(); // 1-on-1 copy of form values $copy_fields = [ 'type', 'interface', 'ipprotocol', 'tag', 'tagged', 'max', 'max-src-nodes', 'max-src-conn', 'max-src-states', 'statetimeout', 'statetype', 'os', 'descr', 'gateway', 'sched', 'associated-rule-id', 'direction', 'state-policy', 'max-src-conn-rate', 'max-src-conn-rates', 'category', 'shaper1', 'shaper2' ] ; foreach ($copy_fields as $fieldname) { if (!empty($pconfig[$fieldname])) { if (is_array($pconfig[$fieldname])) { $filterent[$fieldname] = implode(",", $pconfig[$fieldname]); } else { $filterent[$fieldname] = trim($pconfig[$fieldname]); } } } $filterent['interfacenot'] = !empty($pconfig['interfacenot']); // allow 0 in adaptive timeouts if (is_numericint($pconfig['adaptivestart']) && is_numericint($pconfig['adaptiveend'])) { $filterent['adaptivestart'] = $pconfig['adaptivestart']; $filterent['adaptiveend'] = $pconfig['adaptiveend']; } // only flush non default max new connection overload table if (!empty($pconfig['overload']) && $pconfig['overload'] != 'virusprot') { $filterent['overload'] = $pconfig['overload']; } // attributes with some kind of logic if (!empty($pconfig['floating'])) { $filterent['floating'] = "yes"; } if (!empty($pconfig['tcpflags_any'])) { $filterent['tcpflags_any'] = true; } else { $settcpflags = array(); $outoftcpflags = array(); foreach ($tcpflags as $tcpflag) { if (isset($pconfig['tcpflags1_' . $tcpflag]) && $pconfig['tcpflags1_' . $tcpflag] == "on") { $settcpflags[] = $tcpflag; } if (isset($pconfig['tcpflags2_' . $tcpflag]) && $pconfig['tcpflags2_' . $tcpflag] == "on") { $outoftcpflags[] = $tcpflag; } } if (!empty($outoftcpflags)) { $filterent['tcpflags2'] = join(",", $outoftcpflags); if (!empty($settcpflags)) { $filterent['tcpflags1'] = join(",", $settcpflags); } } } if (!empty($pconfig['allowopts'])) { $filterent['allowopts'] = true; } if ($pconfig['reply-to'] == "__disable__") { $filterent['disablereplyto'] = true; } elseif (!empty($pconfig['reply-to'])) { $filterent['reply-to'] = $pconfig['reply-to']; } if(!empty($pconfig['nopfsync'])) { $filterent['nopfsync'] = true; } if(!empty($pconfig['nosync'])) { $filterent['nosync'] = true; } if (!empty($pconfig['disabled'])) { $filterent['disabled'] = true; } if (!empty($pconfig['log'])) { $filterent['log'] = true; } if (isset($pconfig['set-prio']) && $pconfig['set-prio'] !== '') { $filterent['set-prio'] = $pconfig['set-prio']; } if (isset($pconfig['set-prio-low']) && $pconfig['set-prio-low'] !== '') { $filterent['set-prio-low'] = $pconfig['set-prio-low']; } if (isset($pconfig['prio']) && $pconfig['prio'] !== '') { $filterent['prio'] = $pconfig['prio']; } if (isset($pconfig['tos']) && $pconfig['tos'] !== '') { $filterent['tos'] = $pconfig['tos']; } // XXX: Always store quick, so none existent can have a different functional meaning than an empty value. // Not existent means previous defaults (empty + floating --> non quick, empty + non floating --> quick) $filterent['quick'] = !empty($pconfig['quick']) ? 1 : 0; if ($pconfig['protocol'] != "any") { $filterent['protocol'] = $pconfig['protocol']; } if ($pconfig['protocol'] == "icmp" && !empty($pconfig['icmptype'])) { $filterent['icmptype'] = $pconfig['icmptype']; } elseif ($pconfig['protocol'] == 'ipv6-icmp' && !empty($pconfig['icmp6-type'])) { $filterent['icmp6-type'] = $pconfig['icmp6-type']; } // reset port values for non tcp/udp traffic if (($pconfig['protocol'] != "tcp") && ($pconfig['protocol'] != "udp") && ($pconfig['protocol'] != "tcp/udp")) { $pconfig['srcbeginport'] = 0; $pconfig['srcendport'] = 0; $pconfig['dstbeginport'] = 0; $pconfig['dstendport'] = 0; } pconfig_to_address($filterent['source'], $pconfig['src'], '', !empty($pconfig['srcnot']), $pconfig['srcbeginport'], $pconfig['srcendport']); pconfig_to_address($filterent['destination'], $pconfig['dst'], '', !empty($pconfig['dstnot']), $pconfig['dstbeginport'], $pconfig['dstendport']); $filterent['updated'] = make_config_revision_entry(); // update or insert item if (isset($id)) { if ( isset($a_filter[$id]['created']) && is_array($a_filter[$id]['created']) ) { $filterent['created'] = $a_filter[$id]['created']; } if (!empty($a_filter[$id]['@attributes']) && !empty($a_filter[$id]['@attributes']['uuid'])) { $filterent['@attributes'] = $a_filter[$id]['@attributes']; } else { $filterent['@attributes'] = ['uuid' => generate_uuid()]; } $a_filter[$id] = $filterent; } else { $filterent['created'] = make_config_revision_entry(); $filterent['@attributes'] = ['uuid' => generate_uuid()]; if (isset($after)) { array_splice($a_filter, $after+1, 0, array($filterent)); } else { $a_filter[] = $filterent; } } // sort filter items per interface, not really necessary but leaves a bit nicer sorted config.xml behind. filter_rules_sort(); // write to config 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('filter'); header(url_safe('Location: /firewall_rules.php?if=%s', array( !empty($pconfig['floating']) ? 'FloatingRules' : $pconfig['interface'] ))); exit; } } legacy_html_escape_form_data($pconfig); legacy_html_escape_form_data($a_filter); $priorities = interfaces_vlan_priorities(); include("head.inc"); ?>
0) print_input_errors($input_errors); ?>
deselected, interface rule and not set --> selected if (empty($pconfig['floating']) && $pconfig['quick'] == null){ $is_quick = true; } elseif (!empty($pconfig['floating']) && $pconfig['quick'] == null) { $is_quick = false; } else { $is_quick = $pconfig['quick']; } ?>