diff options
author | Renato Botelho <renato@netgate.com> | 2016-12-30 09:53:34 -0200 |
---|---|---|
committer | Renato Botelho <renato@netgate.com> | 2016-12-30 09:53:34 -0200 |
commit | ffc4c4a3466cd151a3086128269b9e86d2c49f47 (patch) | |
tree | ddc2bb763dc399b2069f430ecd048850dcb746cf /src/usr | |
parent | 8d379f23a5f33692eb21a36fa7e69b0e15b0f44a (diff) | |
parent | d4b2ebaeb2fa2dcc635d061891aa858f8c16d407 (diff) | |
download | pfsense-ffc4c4a3466cd151a3086128269b9e86d2c49f47.zip pfsense-ffc4c4a3466cd151a3086128269b9e86d2c49f47.tar.gz |
Merge pull request #3139 from stilez/patch-38
Diffstat (limited to 'src/usr')
-rw-r--r-- | src/usr/local/www/firewall_rules.php | 21 | ||||
-rw-r--r-- | src/usr/local/www/firewall_rules_edit.php | 194 |
2 files changed, 144 insertions, 71 deletions
diff --git a/src/usr/local/www/firewall_rules.php b/src/usr/local/www/firewall_rules.php index 41dc6e9..feb2beb 100644 --- a/src/usr/local/www/firewall_rules.php +++ b/src/usr/local/www/firewall_rules.php @@ -688,14 +688,21 @@ foreach ($a_filter as $filteri => $filterent): echo strtoupper($filterent['protocol']); if (strtoupper($filterent['protocol']) == "ICMP" && !empty($filterent['icmptype'])) { - echo ' <span style="cursor: help;" title="' . gettext('ICMP type') . ': ' . - ($filterent['ipprotocol'] == "inet6" ? $icmp6types[$filterent['icmptype']] : $icmptypes[$filterent['icmptype']]) . - '"><u>'; - echo $filterent['icmptype']; - echo '</u></span>'; + // replace each comma-separated icmptype item by its (localised) full description + $t = implode(', ', + array_map( + function($type) { + global $icmptypes; + return $icmptypes[$type]['descrip']; + }, + explode(',', $filterent['icmptype']) + ) + ); + echo sprintf('<br /><div style="cursor:help;padding:1px;line-height:1.1em;max-height:2.5em;max-width:180px;overflow-y:auto;overflow-x:hidden" title="%s:%s%s"><small><u>%s</u></small></div>', gettext('ICMP subtypes'), chr(13), $t, str_replace(',', '</u>, <u>',$filterent['icmptype'])); } - } else echo "*"; - + } else { + echo " *"; + } ?> </td> <td> diff --git a/src/usr/local/www/firewall_rules_edit.php b/src/usr/local/www/firewall_rules_edit.php index 5211255..3a4ba9d 100644 --- a/src/usr/local/www/firewall_rules_edit.php +++ b/src/usr/local/www/firewall_rules_edit.php @@ -35,6 +35,27 @@ require_once("ipsec.inc"); require_once("filter.inc"); require_once("shaper.inc"); +/* build icmptypes valid for IPv4, IPv6 and IPv<any> */ +$icmptypes4 = array('any' => gettext('any')); +$icmptypes6 = array('any' => gettext('any')); +$icmptypes46 = array('any' => gettext('any')); +foreach ($icmptypes as $k => $v) { + if ($v['valid4']) { + $icmptypes4[$k] = $v['descrip']; + if ($v['valid6']) { + $icmptypes6[$k] = $v['descrip']; + $icmptypes46[$k] = $v['descrip']; + } + } else { + $icmptypes6[$k] = $v['descrip']; + } +} +$icmplookup = array( + 'inet' => array('name' => 'IPv4', 'icmptypes' => $icmptypes4, 'helpmsg' => gettext('For ICMP rules on IPv4, one or more of these ICMP subtypes may be specified.')), + 'inet6' => array('name' => 'IPv6', 'icmptypes' => $icmptypes6, 'helpmsg' => gettext('For ICMP rules on IPv6, one or more of these ICMP subtypes may be specified.')), + 'inet46' => array('name' => 'IPv4+6', 'icmptypes' => $icmptypes46, 'helpmsg' => gettext('For ICMP rules on IPv4+IPv6, one or more of these ICMP subtypes may be specified. (Other ICMP subtypes are only valid under IPv4 <i>or</i> IPv6, not both)')) +); + if (isset($_POST['referer'])) { $referer = $_POST['referer']; } else { @@ -292,9 +313,13 @@ $dnqlist =& get_unique_dnqueue_list(); $a_gatewaygroups = return_gateway_groups_array(); if ($_POST) { - + unset($input_errors); - + + if (!array_key_exists($_POST['ipprotocol'], $icmplookup)) { + $input_errors[] = gettext("The IP protocol is not recognized."); + } + if (isset($a_filter[$id]['associated-rule-id'])) { $_POST['proto'] = $pconfig['proto']; if ($pconfig['proto'] == "icmp") { @@ -329,11 +354,6 @@ if ($_POST) { } } } - if (($_POST['proto'] == "icmp") && ($_POST['icmptype'] <> "")) { - if ($_POST['ipprotocol'] == "inet46") { - $input_errors[] = gettext("An ICMP type can not be assigned to a rule that applies to IPv4 and IPv6"); - } - } if (($_POST['proto'] != "tcp") && ($_POST['proto'] != "udp") && ($_POST['proto'] != "tcp/udp")) { $_POST['srcbeginport'] = 0; @@ -558,6 +578,36 @@ if ($_POST) { } } + if ($_POST['proto'] == "icmp") { + $t =& $_POST['icmptype']; + if (isset($t) && !is_array($t)) { + // shouldn't happen but avoids making assumptions for data-sanitising + $input_errors[] = gettext("ICMP types expected to be a list if present, but is not."); + } elseif (!isset($t) || count($t) == 0) { + // not specified or none selected + unset($_POST['icmptype']); + } else { + // check data + $bad_types = array(); + if ((count($t) == 1 && !isset($t['any'])) || count($t) > 1) { + // Only need to check valid if just one selected != "any", or >1 selected + $p = $_POST['ipprotocol']; + foreach ($t as $type) { + if ( ($p == 'inet' && !array_key_exists($type, $icmptypes4)) || + ($p == 'inet6' && !array_key_exists($type, $icmptypes6)) || + ($p == 'inet46' && !array_key_exists($type, $icmptypes46))) { + $bad_types[] = $type; + } + } + } + if (count($bad_types) > 0) { + $input_errors[] = sprintf(gettext("Invalid ICMP subtype: %s can not be used with %s."), implode(';', $bad_types), $t['name']); + } + } + } else { + unset($_POST['icmptype']); // field not applicable, might hold junk from old hidden selections. Unset it. + } + if ($_POST['ackqueue'] != "") { if ($_POST['defaultqueue'] == "") { $input_errors[] = gettext("A queue must be selected when an acknowledge queue is also selected."); @@ -790,14 +840,10 @@ if ($_POST) { unset($filterent['protocol']); } - if ($_POST['proto'] == "icmp") { - if ($filterent['ipprotocol'] == 'inet6' && $_POST['icmp6type']) { - $filterent['icmptype'] = $_POST['icmp6type']; - } else if ($filterent['ipprotocol'] != 'inet6' && $_POST['icmptype']) { - $filterent['icmptype'] = $_POST['icmptype']; - } else { - unset($filterent['icmptype']); - } + // Convert array of selected ICMP types to comma-separated string, for backwards compatibility (previously only allowed one type per rule) + if ($_POST['proto'] == "icmp" && is_array($_POST['icmptype']) && !isset($_POST['icmptype']['any']) && count($_POST['icmptype']) > 0) { + //if any of these conditions not met, rule would apply to all icmptypes, so we would unset + $filterent['icmptype'] = implode(',', $_POST['icmptype']); } else { unset($filterent['icmptype']); } @@ -1234,19 +1280,17 @@ $section->addInput(new Form_Select( ) ))->setHelp('Choose which IP protocol this rule should match.'); -$section->addInput(new Form_Select( +$group = new Form_Group("ICMP Subtypes"); +$group->add(new Form_Select( 'icmptype', - 'ICMP type', - $pconfig['icmptype'], - $icmptypes -))->setHelp('If ICMP is selected for the protocol above, an ICMP type may be specified here.'); + 'ICMP subtypes', + ((isset($pconfig['icmptype']) && strlen($pconfig['icmptype']) > 0) ? explode(',', $pconfig['icmptype']) : 'any'), + isset($icmplookup[$pconfig['ipprotocol']]) ? $icmplookup[$pconfig['ipprotocol']]['icmptypes'] : array('any' => gettext('any')), + true +))->setHelp('<div id="icmptype_help">' . (isset($icmplookup[$pconfig['ipprotocol']]) ? gettext($icmplookup[$pconfig['ipprotocol']]['helpmsg']) : '') . '</div>'); +$group->addClass('icmptype_section'); -$section->addInput(new Form_Select( - 'icmp6type', - 'ICMPv6 type', - $pconfig['icmptype'], - $icmp6types -))->setHelp('If ICMP is selected for the protocol above, an ICMP type may be specified here.'); +$section->add($group); $form->add($section); @@ -1838,48 +1882,36 @@ events.push(function() { } function proto_change() { - if ($('#proto').find(":selected").index() < 3) { - portsenabled = 1; - hideClass('tcpflags', false); - } else { - portsenabled = 0; - hideClass('tcpflags', true); - } + var is_tcpudp = (jQuery.inArray($('#proto :selected').val(), ['tcp','udp', 'tcp/udp']) != -1); + portsenabled = (is_tcpudp ? 1 : 0); + hideClass('tcpflags', !is_tcpudp); // Disable OS if the proto is not TCP. - if ($('#proto').find(":selected").index() < 1) { - disableInput('os', false); - } else { - disableInput('os', true); - } + disableInput('os', ($('#proto :selected').val() != 'tcp')); - if ($('#proto').find(":selected").index() == 3) { - disableInput('icmptype', false); - disableInput('icmp6type', false); - } else { - disableInput('icmptype', true); - disableInput('icmp6type', true); + // Hide ICMP types if not icmp rule + hideClass('icmptype_section', $('#proto').val() != 'icmp'); + // Update ICMP help msg to match current IP protocol + $('#icmptype_help').html(icmphelp[$('#ipprotocol').val()]); + // Update ICMP types available for current IP protocol, copying over any still-valid selections + var listid = "#icmptype\\[\\]"; // for ease of use + var current_sel = ($(listid).val() || ['any']); // Ensures we get correct array when none selected + var new_options = icmptypes[$('#ipprotocol').val()]; + var new_html = ''; + //remove and re-create the select element (otherwise the options can disappear in Safari) + $(listid).remove(); + var select = $("<select></select>").attr("id", "icmptype[]").attr("name", "icmptype[]").addClass("form-control").attr("multiple", "multiple"); + $('div.icmptype_section > div.col-sm-10').prepend(select); + + for (var key in new_options) { + new_html += '<option value="' + key + (jQuery.inArray(key, current_sel) != -1 ? '" selected="selected">' : '">') + new_options[key] + '</option>\n'; } - ext_change(); + $(listid).html(new_html); - if ($('#proto').find(":selected").index() == 3 || $('#proto').find(":selected").index() == 4) { - if ($('#ipprotocol').find(":selected").index() == 0) { // IPv4 - hideInput('icmptype', false); - hideInput('icmp6type', true); - } else if ($('#ipprotocol').find(":selected").index() == 1) { // IPv6 - hideInput('icmptype', true); - hideInput('icmp6type', false); - } else { // IPv4 + IPv6 - hideInput('icmptype', true); - hideInput('icmp6type', true); - } - } else { - hideInput('icmptype', true); - hideInput('icmp6type', true); - } + ext_change(); - if ($('#proto').find(":selected").index() <= 2) { + if (is_tcpudp) { hideClass('dstprtr', false); hideInput('btnsrctoggle', false); if ((($('#srcbeginport').val() == "any") || ($('#srcbeginport').val() == "")) && @@ -1897,6 +1929,19 @@ events.push(function() { show_source_port_range(); } + function icmptype_change() { + var listid = "#icmptype\\[\\]"; // for ease of use + var current_sel = ($(listid).val() || ['any']); // Ensures we get correct array when none selected + if (jQuery.inArray('any', current_sel) != -1) { + // "any" negates all selections + $(listid).find('option').not('[value="any"]').removeAttr('selected'); + } + if ($(listid + ' option:selected').length == 0) { + // no selection = select "any" + $(listid + ' option[value="any"]').prop('selected', true); + } + } + function src_rep_change() { $('#srcendport').prop("selectedIndex", $('#srcbeginport').find(":selected").index()); } @@ -1906,6 +1951,23 @@ events.push(function() { } // On initial page load + +<?php + // Generate icmptype data used in form JS + $out1 = "var icmptypes = [];\n"; + $out2 = "var icmphelp = [];\n"; + foreach ($icmplookup as $k => $v) { + $a = array(); + foreach ($v['icmptypes'] as $icmp_k => $icmp_v) { + $a[] = sprintf("'%s':'%s'", $icmp_k, $icmp_v); + } + $out1 .= "icmptypes['{$k}'] = {\n\t" . implode(",\n\t", $a) . "\n};\n"; + $out2 .= "icmphelp['{$k}'] = '" . str_replace("'", ''', gettext($v['helpmsg'])) . "';\n"; + } + echo $out1; + echo $out2; +?> + proto_change(); ext_change(); @@ -1956,14 +2018,18 @@ events.push(function() { typesel_change(); }); - $('#proto').on('change', function() { + $('#ipprotocol').on('change', function() { proto_change(); }); - $('#ipprotocol').on('change', function() { + $('#proto').on('change', function() { proto_change(); }); + $('#icmptype\\[\\]').on('change', function() { + icmptype_change(); + }); + $('#tcpflags_any').click(function () { if (this.checked) { $('.table-flags').addClass('hidden'); @@ -1998,7 +2064,7 @@ events.push(function() { // fields are disabled function disable_most(disable) { var elementsToDisable = [ - 'interface', 'proto', 'icmptype', 'icmp6type', 'srcnot', 'srctype', 'src', 'srcmask', 'srcbebinport', 'srcbeginport_cust', 'srcendport', + 'interface', 'proto', 'icmptype\\[\\]', 'srcnot', 'srctype', 'src', 'srcmask', 'srcbebinport', 'srcbeginport_cust', 'srcendport', 'srcendport_cust', 'dstnot', 'dsttype', 'dst', 'dstmask', 'dstbeginport', 'dstbeginport_cust', 'dstendport', 'dstendport_cust']; for (var idx=0, len = elementsToDisable.length; idx<len; idx++) { |