* 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(); } /** * 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" ,"max-src-conn-rate","max-src-conn-rates", "tag", "tagged", "allowopts", "disablereplyto","tcpflags1" ,"tcpflags2") as $fieldname) { if (!empty($item[$fieldname])) { 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; } // define form fields $config_fields = array( 'allowopts', 'associated-rule-id', 'category', 'descr', 'direction', 'disabled', 'disablereplyto', 'floating', 'gateway', 'icmptype', 'interface', 'ipprotocol', 'log', 'max', 'max-src-conn', 'max-src-conn-rate', 'max-src-conn-rates', 'max-src-nodes', 'max-src-states', 'nopfsync', 'nosync', 'os', 'prio', 'protocol', 'quick', 'sched', 'set-prio', 'set-prio-low', 'statetimeout', 'statetype', 'tag', 'tagged', 'tcpflags1', 'tcpflags2', 'tcpflags_any', 'type', ); $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]; } } // process fields with some kind of logic address_to_pconfig($a_filter[$configId]['source'], $pconfig['src'], $pconfig['srcmask'], $pconfig['srcnot'], $pconfig['srcbeginport'], $pconfig['srcendport']); address_to_pconfig($a_filter[$configId]['destination'], $pconfig['dst'], $pconfig['dstmask'], $pconfig['dstnot'], $pconfig['dstbeginport'], $pconfig['dstendport']); 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; } } } 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")); if (!is_specialnet($pconfig['src'])) { $reqdfields[] = "srcmask"; $reqdfieldsn[] = gettext("Source bit count"); } if (!is_specialnet($pconfig['dst'])) { $reqdfields[] = "dstmask"; $reqdfieldsn[] = gettext("Destination bit count"); } do_input_validation($_POST, $reqdfields, $reqdfieldsn, $input_errors); 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'])) { foreach($config['gateways']['gateway_group'] as $gw_group) { if($gw_group['name'] == $pconfig['gateway']) { $a_gatewaygroups = return_gateway_groups_array(); $family = 'inet'; if ( count($a_gatewaygroups[$pconfig['gateway']]) > 0 && is_ipaddrv6($a_gatewaygroups[$pconfig['gateway']][0]['gwip'])) { $family = 'inet6'; } if(($pconfig['ipprotocol'] == "inet6") && ($pconfig['ipprotocol'] != $family)) { $input_errors[] = gettext('You can not assign an IPv4 gateway group on an IPv6 rule.'); } if(($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(lookup_gateway_ip_by_name($pconfig['gateway']))) { if ($pconfig['ipprotocol'] == "inet6" && !is_ipaddrv6(lookup_gateway_ip_by_name($pconfig['gateway']))) { $input_errors[] = gettext('You can not assign the IPv4 Gateway to an IPv6 filter rule.'); } if ($pconfig['ipprotocol'] == "inet" && !is_ipaddrv4(lookup_gateway_ip_by_name($pconfig['gateway']))) { $input_errors[] = gettext('You can not assign the IPv6 Gateway 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.'); } 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 ( (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 ( (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 (!is_specialnet($pconfig['src'])) { if (!is_ipaddroralias($pconfig['src'])) { $input_errors[] = sprintf(gettext("%s is not a valid source IP address or alias."),$pconfig['src']); } if (!is_numericint($pconfig['srcmask'])) { $input_errors[] = gettext("A valid source bit count must be specified."); } } if (!is_specialnet($pconfig['dst'])) { if (!is_ipaddroralias($pconfig['dst'])) { $input_errors[] = sprintf(gettext("%s is not a valid destination IP address or alias."),$pconfig['dst']); } if (!is_numericint($pconfig['dstmask'])) { $input_errors[] = gettext("A valid destination bit count must be specified."); } } if (is_ipaddr($pconfig['src']) && is_ipaddr($pconfig['dst']) && !validate_address_family($pconfig['src'], $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]) && $pconfig['ipprotocol'] == "inet") { $input_errors[] = gettext("You can not use IPv6 addresses in IPv4 rules."); } elseif (is_ipaddrv4($pconfig[$fam]) && $pconfig['ipprotocol'] == "inet6") { $input_errors[] = gettext("You can not use IPv4 addresses in IPv6 rules."); } } } if (is_ipaddrv4($pconfig['src']) && $pconfig['srcmask'] > 32) { $input_errors[] = gettext("Invalid subnet mask on IPv4 source"); } if (is_ipaddrv4($pconfig['dst']) && $pconfig['dstmask'] > 32) { $input_errors[] = gettext("Invalid subnet mask on IPv4 destination"); } 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 ($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 (!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['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 (count($input_errors) == 0) { $filterent = array(); // 1-on-1 copy of form values $copy_fields = array('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', 'quick' , 'max-src-conn-rate', 'max-src-conn-rates', 'category') ; 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]); } } } // 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 (!empty($pconfig['disablereplyto'])) { $filterent['disablereplyto'] = true; } 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 ($pconfig['protocol'] != "any") { $filterent['protocol'] = $pconfig['protocol']; } if ($pconfig['protocol'] == "icmp" && !empty($pconfig['icmptype'])) { $filterent['icmptype'] = $pconfig['icmptype']; } // 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'], $pconfig['srcmask'], !empty($pconfig['srcnot']), $pconfig['srcbeginport'], $pconfig['srcendport']); pconfig_to_address($filterent['destination'], $pconfig['dst'], $pconfig['dstmask'], !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']; } $a_filter[$id] = $filterent; } else { $filterent['created'] = make_config_revision_entry(); 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 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); ?>
/>
/>
' />

$nat_rule ): if( isset($nat_rule['associated-rule-id']) && $nat_rule['associated-rule-id']==$pconfig['associated-rule-id'] ) : ?>
> true)) as $iface => $ifdetail): ?>
name="srcnot" type="checkbox" value="yes" />
type="text" id="src_address" for="src" value="" aria-label=""/>
" id="showadvancedboxsrc" />
name="dstnot" type="checkbox" id="srcnot" value="yes" />
type="text" id="dst_address" for="dst" value="" aria-label=""/>
type="text" value="" for="dstbeginport"> type="text" value="" for="dstendport">
/>
/>
" />
()
()