diff options
author | Erik Fonnesbeck <efonnes@gmail.com> | 2010-05-08 16:16:11 -0600 |
---|---|---|
committer | Erik Fonnesbeck <efonnes@gmail.com> | 2010-05-08 16:16:34 -0600 |
commit | e31f58fc03ccaae6b602e183f38e7beb87481235 (patch) | |
tree | 7053a35c7476b6ee405720a060b860af9214734c /etc/inc/filter.inc | |
parent | 5f2e5c8e30fcf82181341dce26beda27a49ccff7 (diff) | |
parent | 129bc05216b55cd0c502f40f47cf7de001eef5ba (diff) | |
download | pfsense-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.inc | 300 |
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(); |