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("pfsense-utils.inc"); require_once("interfaces.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')); /** * build array with interface options for this form */ function formInterfaces() { global $config; $interfaces = array(); foreach ( get_configured_interface_with_descr(false, true) as $if => $ifdesc) { $interfaces[$if] = $ifdesc; } if (!empty($config['ifgroups']['ifgroupentry']) && is_array($config['ifgroups']['ifgroupentry'])) { foreach ($config['ifgroups']['ifgroupentry'] as $ifgrp) { $interfaces[$ifgrp['ifname']] = $ifgrp['descr']; } } if (isset($config['l2tp']['mode']) && $config['l2tp']['mode'] == "server") { $interfaces['l2tp'] = "L2TP VPN"; } if (isset($config['pptpd']['mode']) && $config['pptpd']['mode'] == "server") { $interfaces['pptp'] = "PPTP VPN"; } if (is_pppoe_server_enabled()) { $interfaces['pppoe'] = "PPPoE VPN"; } /* add ipsec interfaces */ if (isset($config['ipsec']['enable']) || isset($config['ipsec']['client']['enable'])) { $interfaces["enc0"] = "IPsec"; } /* add openvpn/tun interfaces */ if (isset($config['openvpn']['openvpn-server']) || isset($config['openvpn']['openvpn-client'])) { $interfaces['openvpn'] = 'OpenVPN'; } return $interfaces; } /** * fetch list of selectable networks to use in form */ function formNetworks() { $networks = array(); $networks["any"] = gettext("any"); $networks["pptp"] = gettext("PPTP clients"); $networks["pppoe"] = gettext("PPPoE clients"); $networks["l2tp"] = gettext("L2TP clients"); foreach (get_configured_interface_with_descr() as $ifent => $ifdesc) { $networks[$ifent] = htmlspecialchars($ifdesc) . " " . gettext("net"); $networks[$ifent."ip"] = htmlspecialchars($ifdesc). " ". gettext("address"); } return $networks; } /** * 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; } } 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); } /** * obscured by clouds, is_specialnet uses this.. so let's hide it in here. * let's kill this another day. */ $specialsrcdst = explode(" ", "any (self) pptp pppoe l2tp openvpn"); $ifdisp = get_configured_interface_with_descr(); foreach ($ifdisp as $kif => $kdescr) { $specialsrcdst[] = "{$kif}"; $specialsrcdst[] = "{$kif}ip"; } if (!isset($config['filter']['rule'])) { $config['filter']['rule'] = array(); } $a_filter = &$config['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('interface','type','direction','ipprotocol','protocol','icmptype','os','disabled','log' ,'descr','tcpflags_any','tcpflags1','tcpflags2','tag','tagged','quick','allowopts' ,'disablereplyto','max','max-src-nodes','max-src-conn','max-src-states','statetype' ,'statetimeout','nopfsync','nosync','max-src-conn-rate','max-src-conn-rates','gateway','sched' ,'associated-rule-id','floating', 'category' ); $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 = $a_gatewaygroups[$pconfig['gateway']]['ipprotocol']; if(($pconfig['ipprotocol'] == "inet6") && ($pconfig['ipprotocol'] != $family)) { $input_errors[] = gettext("You can not assign a IPv4 gateway group on IPv6 Address Family rule"); } if(($pconfig['ipprotocol'] == "inet") && ($pconfig['ipprotocol'] != $family)) { $input_errors[] = gettext("You can not assign a IPv6 gateway group on IPv4 Address Family 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 a 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 a IPv4 Filter rule"); } } if ($pconfig['protocol'] == "icmp" && !empty($pconfig['icmptype']) && $pconfig['ipprotocol'] == "inet46") { $input_errors[] = gettext("You can not assign a ICMP type to a rule that applies to IPv4 and IPv6"); } if($pconfig['statetype'] == "synproxy 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']))) { if(!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']); if((is_ipaddrv6($pconfig['src']) || is_ipaddrv6($pconfig['dst'])) && ($pconfig['ipprotocol'] == "inet")) $input_errors[] = gettext("You can not use IPv6 addresses in IPv4 rules."); if((is_ipaddrv4($pconfig['src']) || is_ipaddrv4($pconfig['dst'])) && ($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 a 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 (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 ($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 if (write_config()) { mark_subsystem_dirty('filter'); } if (!empty($pconfig['floating'])) { header("Location: firewall_rules.php?if=FloatingRules"); } else { header("Location: firewall_rules.php?if=" . htmlspecialchars($pconfig['interface'])); } exit; } } legacy_html_escape_form_data($pconfig); $page_filename = "firewall_rules_edit.php"; 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'] ) : ?>
> $ifacename): ?>

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">
/>
/>
" />
   
  " /> " onclick="window.location.href=''" />