summaryrefslogtreecommitdiffstats
path: root/etc/inc/filter.inc
diff options
context:
space:
mode:
authorErik Fonnesbeck <efonnes@gmail.com>2010-05-08 16:16:11 -0600
committerErik Fonnesbeck <efonnes@gmail.com>2010-05-08 16:16:34 -0600
commite31f58fc03ccaae6b602e183f38e7beb87481235 (patch)
tree7053a35c7476b6ee405720a060b860af9214734c /etc/inc/filter.inc
parent5f2e5c8e30fcf82181341dce26beda27a49ccff7 (diff)
parent129bc05216b55cd0c502f40f47cf7de001eef5ba (diff)
downloadpfsense-e31f58fc03ccaae6b602e183f38e7beb87481235.zip
pfsense-e31f58fc03ccaae6b602e183f38e7beb87481235.tar.gz
Merge http://gitweb.pfsense.org/pfsense/efonne-new_nat_reflection into master
Diffstat (limited to 'etc/inc/filter.inc')
-rw-r--r--etc/inc/filter.inc300
1 files changed, 116 insertions, 184 deletions
diff --git a/etc/inc/filter.inc b/etc/inc/filter.inc
index 55dc424..310d814 100644
--- a/etc/inc/filter.inc
+++ b/etc/inc/filter.inc
@@ -797,145 +797,41 @@ function filter_get_reflection_interfaces($natif = "") {
return $nat_if_list;
}
-function filter_generate_reflection($rule, $nordr, $rdr_ifs, $srcaddr, $dstaddr_port, $dstport, &$starting_localhost_port, &$reflection_txt) {
- global $FilterIflist, $config;
-
+function filter_generate_reflection_nat($rule, $nat_ifs, $protocol, $target, $target_ip, $target_subnet = "") {
// Initialize natrules holder string
$natrules = "";
- $reflection_txt = array();
-
- if(!empty($rdr_ifs)) {
- if($config['system']['reflectiontimeout'])
- $reflectiontimeout = $config['system']['reflectiontimeout'];
- else
- $reflectiontimeout = "2000";
-
- update_filter_reload_status("Creating reflection rule for {$rule['descr']}...");
-
- $rdr_if_list = implode(" ", $rdr_ifs);
- if(count($rdr_ifs) > 1)
- $rdr_if_list = "{ {$rdr_if_list} }";
-
- $natrules .= "\n# Reflection redirects\n";
-
- if($dstport[1])
- $range_end = ($dstport[1]);
- else
- $range_end = ($dstport[0]);
-
- $dstaddr = explode(" ", $dstaddr_port);
- if($dstaddr[2])
- $rflctintrange = $dstaddr[2];
- else
- $rflctintrange = "";
- $dstaddr = $dstaddr[0];
-
- if(isset($rule['destination']['any'])) {
- if(!$rule['interface'])
- $natif = "wan";
- else
- $natif = $rule['interface'];
- if(!isset($FilterIflist[$natif]))
- return "";
- if(is_ipaddr($FilterIflist[$natif]['ip']))
- $dstaddr = $FilterIflist[$natif]['ip'];
- else
- return "";
+ update_filter_reload_status("Creating reflection NAT rule for {$rule['descr']}...");
- if(!empty($FilterIflist[$natif]['sn']))
- $dstaddr = gen_subnet($dstaddr, $FilterIflist[$natif]['sn']) . '/' . $FilterIflist[$natif]['sn'];
- }
-
- switch($rule['protocol']) {
- case "tcp/udp":
- $protocol = "{ tcp udp }";
- $reflect_protos = array('tcp', 'udp');
- break;
- case "tcp":
- case "udp":
- $protocol = $rule['protocol'];
- $reflect_protos = array($rule['protocol']);
- break;
- default:
- return "";
- break;
- }
+ /* TODO: Add this option to port forwards page. */
+ if(isset($rule['staticnatport'])) {
+ $static_port = " static-port";
+ } else {
+ $static_port = " port 1024:65535";
+ }
- if(!empty($nordr)) {
- $natrules .= "no rdr on {$rdr_if_list} proto {$protocol} from {$srcaddr} to {$dstaddr} port {$rflctintrange}\n";
- return $natrules;
- }
+ if(!empty($protocol)) {
+ $protocol_text = " proto {$protocol}";
+ } else {
+ $protocol_text = "";
+ }
- if (is_alias($rule['target']))
- $target = filter_expand_alias($rule['target']);
- else if(is_ipaddr($rule['target']))
- $target = $rule['target'];
- else if (is_ipaddr($FilterIflist[$rule['target']]['ip']))
- $target = $FilterIflist[$rule['target']]['ip'];
- else
- return "";
-
- if($rule['local-port'])
- $lrange_start = $rule['local-port'];
- if(($range_end + 1) - $dstport[0] > 500) {
- log_error("Not installing nat reflection rules for a port range > 500");
- /* only install reflection rules for < 19991 items */
- } else if($starting_localhost_port < 19991) {
- $loc_pt = $lrange_start;
- $rflctnorange = true;
- if(is_alias($loc_pt)) {
- $loc_pt_translated = filter_expand_alias($loc_pt);
- if(!$loc_pt_translated) {
- log_error("Reflection processing: {$loc_pt} is not a vaild port alias.");
- continue;
- }
- $toadd_array = split(" ", $loc_pt_translated);
- $rflctnorange = false;
- }
+ $target_if_list = array();
+ if(empty($target_subnet) || !is_numeric($target_subnet) || $target_subnet == 32) {
+ $target_if_list[] = guess_interface_from_ip($target_ip);
+ } else {
+ $target_if_list[] = guess_interface_from_ip(gen_subnet_max($target_ip, $target_subnet));
+ }
- $inetdport = $starting_localhost_port;
- if($range_end > $dstport[0]) {
- $rflctrange = "{$starting_localhost_port}";
- $delta = $range_end - $dstport[0];
- if(($starting_localhost_port + $delta) > 19990) {
- log_error("Installing partial nat reflection rules. Maximum 1,000 reached.");
- $delta = 19990 - $starting_localhost_port;
- $range_end = $dstport[0] + $delta;
- $rflctintrange = "";
- }
- $starting_localhost_port = $starting_localhost_port + $delta;
- $rflctrange .= ":{$starting_localhost_port}";
- if(empty($rflctintrange))
- $rflctintrange = "{$dstport[0]}:{$range_end}";
- if($rflctnorange)
- $toadd_array = range($loc_pt, $loc_pt + $delta);
- $starting_localhost_port++;
- } else {
- $rflctrange = $starting_localhost_port;
- if(empty($rflctintrange))
- $rflctintrange = $dstport[0];
- if($rflctnorange)
- $toadd_array = array($loc_pt);
- $starting_localhost_port++;
- }
+ foreach ($target_if_list as $target_if) {
+ /* Only install additional NAT rules if the
+ * target is in the list of source networks */
+ if(in_array($target_if, $nat_ifs)) {
+ $target_networks = "{$target_if}:network";
- foreach($toadd_array as $tda){
- foreach($reflect_protos as $reflect_proto) {
- if($reflect_proto == "udp") {
- $socktype = "dgram";
- $dash_u = "-u ";
- } else {
- $socktype = "stream";
- $dash_u = "";
- }
- $reflection_txt[] = "{$inetdport}\t{$socktype}\t{$reflect_proto}\tnowait/0\tnobody\t/usr/bin/nc\tnc {$dash_u}-w {$reflectiontimeout} {$target} {$tda}\n";
- }
- $inetdport++;
- }
- $natrules .= "rdr on {$rdr_if_list} proto {$protocol} from {$srcaddr} to {$dstaddr} port {$rflctintrange} tag PFREFLECT -> 127.0.0.1 port {$rflctrange}\n";
+ $natrules .= "no nat on {$target_if}{$protocol_text} from {$target_if} to {$target}\n";
+ $natrules .= "nat on {$target_if}{$protocol_text} from {$target_networks} to {$target} -> {$target_if}{$static_port}\n";
}
- $reflection_txt = array_unique($reflection_txt);
}
return $natrules;
@@ -1022,8 +918,27 @@ function filter_nat_rules_generate() {
else
$natif = $natent['interface'];
$natif = $FilterIflist[$natif]['if'];
- if($natif)
- $natrules .= "binat on $natif from {$natent['internal']}/{$sn} to any -> {$natent['external']}/{$sn}\n";
+
+ if($natif) {
+ /* If reflection is enabled, turn on extra redirections
+ * for this rule by adding other interfaces to binat rule. */
+ if(isset($config['system']['enablebinatreflection'])) {
+ $nat_if_list = filter_get_reflection_interfaces($natif);
+ } else {
+ $nat_if_list = array();
+ }
+
+ $nat_if_list = array_merge(array($natif), $nat_if_list);
+ //$binat_if_list = implode(" ", $nat_if_list);
+ //if(count($nat_if_list) > 1)
+ // $binat_if_list = "{ {$binat_if_list} }";
+
+ /* binat seems to currently only work with the first interface specified on the line */
+ // $natrules .= "binat on {$binat_if_list} from {$natent['internal']}/{$sn} to any -> {$natent['external']}/{$sn}\n";
+ foreach ($nat_if_list as $natifname)
+ $natrules .= "binat on {$natifname} from {$natent['internal']}/{$sn} to any -> {$natent['external']}/{$sn}\n";
+ $natrules .= filter_generate_reflection_nat($rule, $nat_if_list, "", "{$natent['internal']}/{$sn}", $natent['internal'], $sn);
+ }
}
}
$natrules .= "\n# Outbound NAT rules\n";
@@ -1204,10 +1119,6 @@ function filter_nat_rules_generate() {
fwrite($inetd_fd, "tftp-proxy\tdgram\tudp\twait\t\troot\t/usr/libexec/tftp-proxy\ttftp-proxy -v\n");
if(isset($config['nat']['rule'])) {
- if(!isset($config['system']['disablenatreflection'])) {
- /* start redirects on port 19000 of localhost */
- $starting_localhost_port = 19000;
- }
$natrules .= "# NAT Inbound Redirects\n";
foreach ($config['nat']['rule'] as $rule) {
update_filter_reload_status("Creating NAT rule {$rule['descr']}");
@@ -1237,30 +1148,33 @@ function filter_nat_rules_generate() {
$localport = " port {$localport}";
}
- switch(strtolower($rule['protocol'])) {
- case "tcp/udp":
- $protocol = "{ tcp udp }";
- break;
- case "tcp":
- case "udp":
- $protocol = strtolower($rule['protocol']);
- break;
- default:
- $protocol = strtolower($rule['protocol']);
- $localport = "";
- break;
- }
-
$target = alias_expand($rule['target']);
if(!$target && !isset($rule['nordr'])) {
$natrules .= "# Unresolvable alias {$rule['target']}\n";
continue; /* unresolvable alias */
}
+ if(is_alias($rule['target']))
+ $target_ip = filter_expand_alias($rule['target']);
+ else if(is_ipaddr($rule['target']))
+ $target_ip = $rule['target'];
+ else if(is_ipaddr($FilterIflist[$rule['target']]['ip']))
+ $target_ip = $FilterIflist[$rule['target']]['ip'];
+ else
+ $target_ip = $rule['target'];
+ $target_ip = trim($target_ip);
+
if($rule['associated-rule-id'] == "pass")
$rdrpass = "pass ";
else
$rdrpass = "";
+
+ if (isset($rule['nordr'])) {
+ $nordr = "no ";
+ $rdrpass = "";
+ } else
+ $nordr = "";
+
if(!$rule['interface'])
$natif = "wan";
else
@@ -1271,44 +1185,71 @@ function filter_nat_rules_generate() {
$srcaddr = filter_generate_address($rule, 'source', true);
$dstaddr = filter_generate_address($rule, 'destination', true);
+ $srcaddr = trim($srcaddr);
+ $dstaddr = trim($dstaddr);
if(!$dstaddr)
$dstaddr = $FilterIflist[$natif]['ip'];
- $natif = $FilterIflist[$natif]['if'];
+ $dstaddr_port = explode(" ", $dstaddr);
+ $dstaddr_reflect = $dstaddr;
+ if(isset($rule['destination']['any'])) {
+ /* With reflection enabled, destination of 'any' has side effects
+ * that most people would not expect, so change it on reflection rules. */
+ $dstaddr_reflect = $FilterIflist[$natif]['ip'];
+ if(!empty($FilterIflist[$natif]['sn']))
+ $dstaddr_reflect = gen_subnet($dstaddr_reflect, $FilterIflist[$natif]['sn']) . '/' . $FilterIflist[$natif]['sn'];
+
+ if($dstaddr_port[2])
+ $dstaddr_reflect .= " port " . $dstaddr_port[2];
+ }
- if (isset($rule['nordr'])) {
- $nordr = "no ";
- $rdrpass = "";
- } else
- $nordr = "";
+ $natif = $FilterIflist[$natif]['if'];
- if(!isset($config['system']['disablenatreflection'])) {
- $nat_if_list = filter_get_reflection_interfaces($natif);
- } else {
- $nat_if_list = array();
+ switch(strtolower($rule['protocol'])) {
+ case "tcp/udp":
+ $protocol = "{ tcp udp }";
+ break;
+ case "tcp":
+ case "udp":
+ $protocol = strtolower($rule['protocol']);
+ break;
+ default:
+ $protocol = strtolower($rule['protocol']);
+ $localport = "";
+ break;
}
+ $localport_nat = $localport;
+ if(empty($localport_nat) && $dstaddr_port[2])
+ $localport_nat = " port " . $dstaddr_port[2];
+
if($srcaddr <> "" && $dstaddr <> "" && $natif) {
- $srcaddr = trim($srcaddr);
- $dstaddr = trim($dstaddr);
+ /* If reflection is enabled, turn on extra redirections for
+ * this rule by adding other interfaces to a similar rdr rule. */
+ if(!isset($config['system']['disablenatreflection'])) {
+ $nat_if_list = filter_get_reflection_interfaces($natif);
+ } else {
+ $nat_if_list = array();
+ }
- $natrules .= "{$nordr}rdr {$rdrpass}on {$natif} proto {$protocol} from {$srcaddr} to {$dstaddr}" . ($nordr == "" ? " -> {$target}{$localport}" : "");
+ $natrules .= "{$nordr}rdr {$rdrpass}on {$natif} proto {$protocol} from {$srcaddr} to {$dstaddr}" . ($nordr == "" ? " -> {$target}{$localport}\n" : "\n");
- /* Does this rule redirect back to a internal host? */
- if(isset($rule['destination']['any']) && !interface_has_gateway($rule['interface']) && !isset($rule['nordr'])) {
- $rule_interface_ip = find_interface_ip($natif);
- $rule_interface_subnet = find_interface_subnet($natif);
- $rule_subnet = gen_subnet($rule_interface_ip, $rule_interface_subnet);
- $natrules .= "\n";
- $natrules .= "no nat on {$natif} proto tcp from ({$natif}) to {$rule_subnet}/{$rule_interface_subnet}\n";
- $natrules .= "nat on {$natif} proto tcp from {$rule_subnet}/{$rule_interface_subnet} to {$target} port {$dstport[0]} -> ({$natif})\n";
+ if(!empty($nat_if_list)) {
+ $rdr_if_list = implode(" ", $nat_if_list);
+ if(count($nat_if_list) > 1)
+ $rdr_if_list = "{ {$rdr_if_list} }";
+
+ /* TODO: When using reflection, should all of the redirects be passed
+ * if the port forward is set to pass through the firewall, or should
+ * the port forward's configured interface be the only one to
+ * automatically pass, or should the reflection redirects always pass? */
+ $natrules .= "{$nordr}rdr on {$rdr_if_list} proto {$protocol} from {$srcaddr} to {$dstaddr_reflect}" . ($nordr == "" ? " -> {$target}{$localport}\n" : "\n");
}
- $natrules .= filter_generate_reflection($rule, $nordr, $nat_if_list, $srcaddr, $dstaddr, $dstport, $starting_localhost_port, $reflection_rules);
- $natrules .= "\n";
- foreach ($reflection_rules as $txtline)
- fwrite($inetd_fd, $txtline);
+ $nat_if_list = array_merge(array($natif), $nat_if_list);
+ if(!isset($rule['nordr']))
+ $natrules .= filter_generate_reflection_nat($rule, $nat_if_list, $protocol, "{$target}{$localport_nat}", $target_ip);
}
}
}
@@ -2046,15 +1987,6 @@ EOD;
}
}
- $ipfrules .= "# NAT Reflection rules\n";
- if(isset($config['nat']['rule']) &&
- (!isset($config['system']['disablenatreflection']))) {
- $ipfrules .= <<<EOD
-pass in inet tagged PFREFLECT keep state label "NAT REFLECT: Allow traffic to localhost"
-
-EOD;
- }
-
if(isset($config['filter']['rule'])) {
/* Pre-cache all our rules so we only have to generate them once */
$rule_arr1 = array();
OpenPOWER on IntegriCloud