From 59ecde4930ac6580db3634664341546fd5328374 Mon Sep 17 00:00:00 2001 From: Renato Botelho Date: Thu, 29 Apr 2010 08:21:17 -0300 Subject: Improve NAT Port Forwarding New features available are: * Now you can disable a rule * You can define "no rdr" rules * Source type, address and port, with an option "not" for exceptions * Destination type, address and port, with an option "not" for exceptions Implemented by: Carlos Eduardo Ramos Renato Botelho Vinicius Coque Reviewed by: cmb and efonne Sponsored by: BluePex Security Solutions --- usr/local/www/firewall_nat_edit.php | 571 +++++++++++++++++++++++++++--------- 1 file changed, 427 insertions(+), 144 deletions(-) (limited to 'usr/local/www/firewall_nat_edit.php') diff --git a/usr/local/www/firewall_nat_edit.php b/usr/local/www/firewall_nat_edit.php index 8b36fb8..bff59ed 100755 --- a/usr/local/www/firewall_nat_edit.php +++ b/usr/local/www/firewall_nat_edit.php @@ -44,6 +44,13 @@ require_once("itemid.inc"); require("filter.inc"); require("shaper.inc"); +$specialsrcdst = explode(" ", "any pptp pppoe l2tp openvpn"); +$ifdisp = get_configured_interface_with_descr(); +foreach ($ifdisp as $kif => $kdescr) { + $specialsrcdst[] = "{$kif}"; + $specialsrcdst[] = "{$kif}ip"; +} + if (!is_array($config['nat']['rule'])) { $config['nat']['rule'] = array(); } @@ -59,96 +66,200 @@ if (isset($_GET['dup'])) { } if (isset($id) && $a_nat[$id]) { - $pconfig['extaddr'] = $a_nat[$id]['external-address']; + $pconfig['disabled'] = isset($a_nat[$id]['disabled']); + $pconfig['nordr'] = isset($a_nat[$id]['nordr']); + + address_to_pconfig($a_nat[$id]['source'], $pconfig['src'], + $pconfig['srcmask'], $pconfig['srcnot'], + $pconfig['srcbeginport'], $pconfig['srcendport']); + + address_to_pconfig($a_nat[$id]['destination'], $pconfig['dst'], + $pconfig['dstmask'], $pconfig['dstnot'], + $pconfig['dstbeginport'], $pconfig['dstendport']); + $pconfig['proto'] = $a_nat[$id]['protocol']; - list($pconfig['beginport'],$pconfig['endport']) = explode("-", $a_nat[$id]['external-port']); - if(!$pconfig['endport']) - $pconfig['endport'] = $pconfig['beginport']; $pconfig['localip'] = $a_nat[$id]['target']; $pconfig['localbeginport'] = $a_nat[$id]['local-port']; $pconfig['descr'] = $a_nat[$id]['descr']; $pconfig['interface'] = $a_nat[$id]['interface']; $pconfig['associated-rule-id'] = $a_nat[$id]['associated-rule-id']; $pconfig['nosync'] = isset($a_nat[$id]['nosync']); + if (!$pconfig['interface']) $pconfig['interface'] = "wan"; } else { $pconfig['interface'] = "wan"; + $pconfig['src'] = "any"; + $pconfig['srcbeginport'] = "any"; + $pconfig['srcendport'] = "any"; } if (isset($_GET['dup'])) unset($id); /* run through $_POST items encoding HTML entties so that the user - * cannot think he is slick and perform a XSS attack on the unwilling + * cannot think he is slick and perform a XSS attack on the unwilling */ foreach ($_POST as $key => $value) { $temp = $value; $newpost = htmlentities($temp); - if($newpost <> $temp) - $input_errors[] = "Invalid characters detected ($temp). Please remove invalid characters and save again."; + if($newpost <> $temp) + $input_errors[] = "Invalid characters detected ($temp). Please remove invalid characters and save again."; } if ($_POST) { - if ($_POST['beginport_cust'] && !$_POST['beginport']) - $_POST['beginport'] = $_POST['beginport_cust']; - if ($_POST['endport_cust'] && !$_POST['endport']) - $_POST['endport'] = $_POST['endport_cust']; - if ($_POST['localbeginport_cust'] && !$_POST['localbeginport']) - $_POST['localbeginport'] = $_POST['localbeginport_cust']; + if(strtoupper($_POST['proto']) == "TCP" || strtoupper($_POST['proto']) == "UDP" || strtoupper($_POST['proto']) == "TCP/UDP") { + if ($_POST['srcbeginport_cust'] && !$_POST['srcbeginport']) + $_POST['srcbeginport'] = $_POST['srcbeginport_cust']; + if ($_POST['srcendport_cust'] && !$_POST['srcendport']) + $_POST['srcendport'] = $_POST['srcendport_cust']; + + if ($_POST['srcbeginport'] == "any") { + $_POST['srcbeginport'] = 0; + $_POST['srcendport'] = 0; + } else { + if (!$_POST['srcendport']) + $_POST['srcendport'] = $_POST['srcbeginport']; + } + if ($_POST['srcendport'] == "any") + $_POST['srcendport'] = $_POST['srcbeginport']; + + if ($_POST['dstbeginport_cust'] && !$_POST['dstbeginport']) + $_POST['dstbeginport'] = $_POST['dstbeginport_cust']; + if ($_POST['dstendport_cust'] && !$_POST['dstendport']) + $_POST['dstendport'] = $_POST['dstendport_cust']; + + if ($_POST['dstbeginport'] == "any") { + $_POST['dstbeginport'] = 0; + $_POST['dstendport'] = 0; + } else { + if (!$_POST['dstendport']) + $_POST['dstendport'] = $_POST['dstbeginport']; + } + if ($_POST['dstendport'] == "any") + $_POST['dstendport'] = $_POST['dstbeginport']; + + if ($_POST['localbeginport_cust'] && !$_POST['localbeginport']) + $_POST['localbeginport'] = $_POST['localbeginport_cust']; - if (!$_POST['endport']) - $_POST['endport'] = $_POST['beginport']; - /* Make beginning port end port if not defined and endport is */ - if (!$_POST['beginport'] && $_POST['endport']) - $_POST['beginport'] = $_POST['endport']; + /* Make beginning port end port if not defined and endport is */ + if (!$_POST['srcbeginport'] && $_POST['srcendport']) + $_POST['srcbeginport'] = $_POST['srcendport']; + if (!$_POST['dstbeginport'] && $_POST['dstendport']) + $_POST['dstbeginport'] = $_POST['dstendport']; + } else { + $_POST['srcbeginport'] = 0; + $_POST['srcendport'] = 0; + $_POST['dstbeginport'] = 0; + $_POST['dstendport'] = 0; + } + + if (is_specialnet($_POST['srctype'])) { + $_POST['src'] = $_POST['srctype']; + $_POST['srcmask'] = 0; + } else if ($_POST['srctype'] == "single") { + $_POST['srcmask'] = 32; + } + if (is_specialnet($_POST['dsttype'])) { + $_POST['dst'] = $_POST['dsttype']; + $_POST['dstmask'] = 0; + } else if ($_POST['dsttype'] == "single") { + $_POST['dstmask'] = 32; + } else if (is_ipaddr($_POST['dsttype'])) { + $_POST['dst'] = $_POST['dsttype']; + $_POST['dstmask'] = 32; + $_POST['dsttype'] = "single"; + } unset($input_errors); $pconfig = $_POST; /* input validation */ if(strtoupper($_POST['proto']) == "TCP" or strtoupper($_POST['proto']) == "UDP" or strtoupper($_POST['proto']) == "TCP/UDP") { - $reqdfields = explode(" ", "interface proto beginport endport localip localbeginport"); - $reqdfieldsn = explode(",", "Interface,Protocol,External port from,External port to,NAT IP,Local port"); + $reqdfields = explode(" ", "interface proto dstbeginport dstendport localip"); + $reqdfieldsn = explode(",", "Interface,Protocol,Destination port from,Destination port to,NAT IP"); } else { $reqdfields = explode(" ", "interface proto localip"); $reqdfieldsn = explode(",", "Interface,Protocol,NAT IP"); } + if ($_POST['srctype'] == "single" || $_POST['srctype'] == "network") { + $reqdfields[] = "src"; + $reqdfieldsn[] = "Source address"; + } + if ($_POST['dsttype'] == "single" || $_POST['dsttype'] == "network") { + $reqdfields[] = "dst"; + $reqdfieldsn[] = "Destination address"; + } + do_input_validation($_POST, $reqdfields, $reqdfieldsn, &$input_errors); + if (!$_POST['srcbeginport']) { + $_POST['srcbeginport'] = 0; + $_POST['srcendport'] = 0; + } + if (!$_POST['dstbeginport']) { + $_POST['dstbeginport'] = 0; + $_POST['dstendport'] = 0; + } + if (($_POST['localip'] && !is_ipaddroralias($_POST['localip']))) { $input_errors[] = "\"{$_POST['localip']}\" is not valid NAT IP address or host alias."; } - /* only validate the ports if the protocol is TCP, UDP or TCP/UDP */ - if(strtoupper($_POST['proto']) == "TCP" or strtoupper($_POST['proto']) == "UDP" or strtoupper($_POST['proto']) == "TCP/UDP") { + if ($_POST['srcbeginport'] && !is_portoralias($_POST['srcbeginport'])) + $input_errors[] = "{$_POST['srcbeginport']} is not a valid start source port. It must be a port alias or integer between 1 and 65535."; + if ($_POST['srcendport'] && !is_portoralias($_POST['srcendport'])) + $input_errors[] = "{$_POST['srcendport']} is not a valid end source port. It must be a port alias or integer between 1 and 65535."; + if ($_POST['dstbeginport'] && !is_portoralias($_POST['dstbeginport'])) + $input_errors[] = "{$_POST['dstbeginport']} is not a valid start destination port. It must be a port alias or integer between 1 and 65535."; + if ($_POST['dstendport'] && !is_portoralias($_POST['dstendport'])) + $input_errors[] = "{$_POST['dstendport']} is not a valid end destination port. It must be a port alias or integer between 1 and 65535."; + + if ($_POST['localbeginport'] && !is_portoralias($_POST['localbeginport'])) { + $input_errors[] = "{$_POST['localbeginport']} is not a valid local port. It must be a port alias or integer between 1 and 65535."; + } - if ($_POST['beginport'] && !is_portoralias($_POST['beginport'])) { - $input_errors[] = "The start port must be an integer between 1 and 65535."; - } + /* if user enters an alias and selects "network" then disallow. */ + if( ($_POST['srctype'] == "network" && is_alias($_POST['src']) ) + || ($_POST['dsttype'] == "network" && is_alias($_POST['dst']) ) ) { + $input_errors[] = "You must specify single host or alias for alias entries."; + } - if ($_POST['endport'] && !is_portoralias($_POST['endport'])) { - $input_errors[] = "The end port must be an integer between 1 and 65535."; + if (!is_specialnet($_POST['srctype'])) { + if (($_POST['src'] && !is_ipaddroralias($_POST['src']))) { + $input_errors[] = "{$_POST['src']} is not a valid source IP address or alias."; } - - if ($_POST['localbeginport'] && !is_portoralias($_POST['localbeginport'])) { - $input_errors[] = "The local port must be an integer between 1 and 65535."; + if (($_POST['srcmask'] && !is_numericint($_POST['srcmask']))) { + $input_errors[] = "A valid source bit count must be specified."; } - - if ($_POST['beginport'] > $_POST['endport']) { - /* swap */ - $tmp = $_POST['endport']; - $_POST['endport'] = $_POST['beginport']; - $_POST['beginport'] = $tmp; + } + if (!is_specialnet($_POST['dsttype'])) { + if (($_POST['dst'] && !is_ipaddroralias($_POST['dst']))) { + $input_errors[] = "{$_POST['dst']} is not a valid destination IP address or alias."; } - - if (!$input_errors) { - if (($_POST['endport'] - $_POST['beginport'] + $_POST['localbeginport']) > 65535) - $input_errors[] = "The target port range must be an integer between 1 and 65535."; + if (($_POST['dstmask'] && !is_numericint($_POST['dstmask']))) { + $input_errors[] = "A valid destination bit count must be specified."; } + } + + if ($_POST['srcbeginport'] > $_POST['srcendport']) { + /* swap */ + $tmp = $_POST['srcendport']; + $_POST['srcendport'] = $_POST['srcbeginport']; + $_POST['srcbeginport'] = $tmp; + } + if ($_POST['dstbeginport'] > $_POST['dstendport']) { + /* swap */ + $tmp = $_POST['dstendport']; + $_POST['dstendport'] = $_POST['dstbeginport']; + $_POST['dstbeginport'] = $tmp; + } + if (!$input_errors) { + if (($_POST['dstendport'] - $_POST['dstbeginport'] + $_POST['localbeginport']) > 65535) + $input_errors[] = "The target port range must be an integer between 1 and 65535."; } /* check for overlaps */ @@ -157,40 +268,45 @@ if ($_POST) { continue; if ($natent['interface'] != $_POST['interface']) continue; - if ($natent['external-address'] != $_POST['extaddr']) + if ($natent['destination']['address'] != $_POST['dst']) continue; if (($natent['proto'] != $_POST['proto']) && ($natent['proto'] != "tcp/udp") && ($_POST['proto'] != "tcp/udp")) continue; - list($begp,$endp) = explode("-", $natent['external-port']); + list($begp,$endp) = explode("-", $natent['destination']['port']); if (!$endp) $endp = $begp; if (!( (($_POST['beginport'] < $begp) && ($_POST['endport'] < $begp)) || (($_POST['beginport'] > $endp) && ($_POST['endport'] > $endp)))) { - $input_errors[] = "The external port range overlaps with an existing entry."; + $input_errors[] = "The destination port range overlaps with an existing entry."; break; } } if (!$input_errors) { $natent = array(); - if ($_POST['extaddr']) - $natent['external-address'] = $_POST['extaddr']; - $natent['protocol'] = $_POST['proto']; - if ($_POST['beginport'] == $_POST['endport']) - $natent['external-port'] = $_POST['beginport']; - else - $natent['external-port'] = $_POST['beginport'] . "-" . $_POST['endport']; + $natent['disabled'] = isset($_POST['disabled']) ? true:false; + $natent['nordr'] = isset($_POST['nordr']) ? true:false; + + pconfig_to_address($natent['source'], $_POST['src'], + $_POST['srcmask'], $_POST['srcnot'], + $_POST['srcbeginport'], $_POST['srcendport']); + + pconfig_to_address($natent['destination'], $_POST['dst'], + $_POST['dstmask'], $_POST['dstnot'], + $_POST['dstbeginport'], $_POST['dstendport']); + + $natent['protocol'] = $_POST['proto']; $natent['target'] = $_POST['localip']; $natent['local-port'] = $_POST['localbeginport']; $natent['interface'] = $_POST['interface']; $natent['descr'] = $_POST['descr']; $natent['associated-rule-id'] = $_POST['associated-rule-id']; - + if($_POST['filter-rule-association'] == "pass") $natent['associated-rule-id'] = "pass"; @@ -200,7 +316,7 @@ if ($_POST) { unset($natent['nosync']); // If we used to have an associated filter rule, but no-longer should have one - if ($a_nat[$id]>0 && empty($natent['associated-rule-id'])) { + if ($a_nat[$id]>0 && ( empty($natent['associated-rule-id']) || $natent['associated-rule-id'] != $a_nat[$id]['associated-rule-id'] ) ) { // Delete the previous rule delete_id($a_nat[$id]['associated-rule-id'], $config['filter']['rule']); mark_subsystem_dirty('filter'); @@ -241,13 +357,16 @@ if ($_POST) { if (!empty($natent['associated-rule-id'])) { $filterentid = get_id($natent['associated-rule-id'], $config['filter']['rule']); if ($filterentid == false) { - $filterent['source']['any'] = ""; + pconfig_to_address($filterent['source'], $_POST['src'], + $_POST['srcmask'], $_POST['srcnot'], + $_POST['srcbeginport'], $_POST['srcendport']); $filterent['associated-rule-id'] = $natent['associated-rule-id']; } else $filterent =& $config['filter']['rule'][$filterentid]; } else - // Create the default source entry for new filter entries - $filterent['source']['any'] = ""; + pconfig_to_address($filterent['source'], $_POST['src'], + $_POST['srcmask'], $_POST['srcnot'], + $_POST['srcbeginport'], $_POST['srcendport']); // Update interface, protocol and destination $filterent['interface'] = $_POST['interface']; @@ -255,7 +374,7 @@ if ($_POST) { $filterent['destination']['address'] = $_POST['localip']; $dstpfrom = $_POST['localbeginport']; - $dstpto = $dstpfrom + $_POST['endport'] - $_POST['beginport']; + $dstpto = $dstpfrom + $_POST['dstendport'] - $_POST['dstbeginport']; if ($dstpfrom == $dstpto) $filterent['destination']['port'] = $dstpfrom; @@ -308,31 +427,47 @@ include("fbegin.inc"); ?>
- - - + + + + + + + + + + + - - - - + + + + + + + + + + + + + + + + + + + + - - - - - + - - + +
Edit NAT entry
Edit Redirect entry
Disabled + > + Disable this rule
+ Set this option to disable this rule without removing it from the list. +
No RDR (NOT) + > + Enabling this option will disable redirection for traffic matching this rule. +
Hint: this option is rarely needed, don't use this unless you know what you're doing.
+
Interface - $ifdesc) - if(have_ruleint_access($if)) + foreach ($iflist as $if => $ifdesc) + if(have_ruleint_access($if)) $interfaces[$if] = $ifdesc; - + if ($config['pptpd']['mode'] == "server") - if(have_ruleint_access("pptp")) + if(have_ruleint_access("pptp")) $interfaces['pptp'] = "PPTP VPN"; - + if ($config['pppoe']['mode'] == "server") - if(have_ruleint_access("pppoe")) + if(have_ruleint_access("pppoe")) $interfaces['pppoe'] = "PPPoE VPN"; - + /* add ipsec interfaces */ if (isset($config['ipsec']['enable']) || isset($config['ipsec']['mobileclients']['enable'])) - if(have_ruleint_access("enc0")) - $interfaces["enc0"] = "IPsec"; + if(have_ruleint_access("enc0")) + $interfaces["enc0"] = "IPsec"; foreach ($interfaces as $iface => $ifacename): ?>
External address - -
- - If you want this rule to apply to another IP address than the IP address of the interface chosen above, - select it here (you need to define Virtual IP addresses on the first). Also note that if you are trying to redirect connections on the LAN select the "any" option.
Protocol @@ -381,55 +489,223 @@ include("fbegin.inc"); ?> this rule should match.
Hint: in most cases, you should specify TCP  here.
Source + - Show source address and port range +
Destination + > + not +
+ Use this option to invert the sense of the match. +
+
+ + + + + + + + + +
Type:   + +
Address:   + + / + +
+
Destination port range + + + + + + + + + +
from:   + + +
to: + + +
+
+ + Specify the port or port range for the destination of the packet for this mapping. +
+ Hint: you can leave the 'to' field empty if you only want to map a single port +
+
External port - range - - - - - - - - - -
from:  
to:
-
Specify the port or port range on - the firewall's external address for this mapping.
- Hint: you can leave the 'to' field empty if you only - want to map a single port
NAT IPRedirect target IP
Enter the internal IP address of the server on which you want to map the ports.
e.g. 192.168.1.12
Local port
Redirect target port - $linkedrule = "
View the filter rule
"; } echo ">". htmlspecialchars('Rule ' . $filter_rule['descr']) . "\n"; - + } if ($filter_rule['interface'] == $pconfig['interface']) $filter_id++; @@ -526,6 +802,9 @@ include("fbegin.inc"); ?> "") var customarray=new Array(); var oTextbox1 = new AutoSuggestControl(document.getElementById("localip"), new StateSuggestions(addressarray)); - var oTextbox2 = new AutoSuggestControl(document.getElementById("beginport_cust"), new StateSuggestions(customarray)); - var oTextbox3 = new AutoSuggestControl(document.getElementById("endport_cust"), new StateSuggestions(customarray)); - var oTextbox4 = new AutoSuggestControl(document.getElementById("localbeginport_cust"), new StateSuggestions(customarray)); + var oTextbox2 = new AutoSuggestControl(document.getElementById("src"), new StateSuggestions(addressarray)); + var oTextbox3 = new AutoSuggestControl(document.getElementById("dst"), new StateSuggestions(addressarray)); + var oTextbox4 = new AutoSuggestControl(document.getElementById("dstbeginport_cust"), new StateSuggestions(customarray)); + var oTextbox5 = new AutoSuggestControl(document.getElementById("dstendport_cust"), new StateSuggestions(customarray)); + var oTextbox6 = new AutoSuggestControl(document.getElementById("srcbeginport_cust"), new StateSuggestions(customarray)); + var oTextbox7 = new AutoSuggestControl(document.getElementById("srcendport_cust"), new StateSuggestions(customarray)); + var oTextbox8 = new AutoSuggestControl(document.getElementById("localbeginport_cust"), new StateSuggestions(customarray)); //--> -- cgit v1.1