From b79ff62b6d56bbfbf076335596a2c37856e72580 Mon Sep 17 00:00:00 2001 From: Ad Schellevis Date: Sat, 23 Dec 2017 17:36:03 +0100 Subject: [PATCH] Firewall/nat. implement new rule generation for the sections done sofar. for https://github.com/opnsense/core/issues/1326 Moves most rule generation features in our filter, filter_generate_address() is only used in vpn_openvpn_export.php now, so to keep clearity we're going to move this out of the way for now too. --- src/etc/inc/filter.inc | 261 +++------------------------------ src/www/vpn_openvpn_export.php | 43 ++++++ 2 files changed, 61 insertions(+), 243 deletions(-) diff --git a/src/etc/inc/filter.inc b/src/etc/inc/filter.inc index c700dd0db..a1e3b9afc 100644 --- a/src/etc/inc/filter.inc +++ b/src/etc/inc/filter.inc @@ -248,10 +248,23 @@ function filter_configure_sync($verbose = false) } } + if (!empty($config['nat']['npt'])) { + // register user npt rules + foreach ($config['nat']['npt'] as $rule) { + $fw->registerNptRule(100, $rule); + } + } + + if (!empty($config['nat']['onetoone'])) { + // register user 1:1 mappings + foreach ($config['nat']['onetoone'] as $rule) { + $fw->registerNatRule(200, $rule); + } + } if (!empty($config['nat']['rule'])) { // register user forward rules foreach ($config['nat']['rule'] as $rule) { - $fw->registerForwardRule(100, $rule); + $fw->registerForwardRule(300, $rule); } } @@ -280,7 +293,9 @@ function filter_configure_sync($verbose = false) } $FilterIflist = filter_generate_optcfg_array(); - $natrules = filter_nat_rules_generate($FilterIflist, $fw); + $natrules = filter_nat_rules_generate($FilterIflist); + $natrules .= "\n# NAT Redirects\n"; + $natrules .= $fw->outputNatRules(); if ($verbose) { echo '.'; @@ -777,103 +792,6 @@ function filter_generate_optcfg_array() } -function filter_get_reflection_interfaces(&$FilterIflist, $natif) -{ - $nat_if_list = array(); - foreach ($FilterIflist as $ifent => $ifname) { - if ($ifname['if'] != $natif && !interface_has_gateway($ifent)) { - $nat_if_list[] = $ifname['if']; - } - } - return $nat_if_list; -} - -function filter_generate_reflection_nat(&$FilterIflist, $rule, &$route_table, $nat_ifs, $protocol, $target, $target_ip, $target_subnet = '') -{ - // Initialize natrules holder string - $natrules = ''; - - /* TODO: Add this option to port forwards page. */ - if (isset($rule['staticnatport'])) { - $static_port = " static-port"; - } else { - $static_port = " port 1024:65535"; - } - - if (!empty($protocol)) { - $protocol_text = " proto {$protocol}"; - } else { - $protocol_text = ""; - } - - if (empty($target_subnet) || !is_numeric($target_subnet)) { - $target_subnet = 32; - } - - if (!is_array($route_table)) { - /* get a simulated IPv4-only route table based on the config */ - $route_table = filter_get_direct_networks_list($FilterIflist); - foreach($route_table as $rt_key => $rt_ent) { - if (!is_subnetv4($rt_ent['subnet'])) { - unset($route_table[$rt_key]); - } - if (isset($route_table[$rt_key]) && isset($FilterIflist[$rt_ent['if']]['if'])) { - $route_table[$rt_key]['if'] = $FilterIflist[$rt_ent['if']]['if']; - } - } - } - - /* Check if the target is accessed through a static route */ - foreach($route_table as $route) { - if (isset($route['gateway']) && is_ipaddr($route['gateway'])) { - $subnet_split = explode("/", $route['subnet']); - if (in_array($route['if'], $nat_ifs) && check_subnets_overlap($target_ip, $target_subnet, $subnet_split[0], $subnet_split[1])) { - $target_ip = $route['gateway']; - $target_subnet = 32; - break; - } - } - } - - /* Search for matching subnets in the routing table */ - foreach($route_table as $route) { - $subnet = $route['subnet']; - $subnet_split = explode("/", $subnet); - $subnet_if = $route['if']; - if (in_array($subnet_if, $nat_ifs) && check_subnets_overlap($target_ip, $target_subnet, $subnet_split[0], $subnet_split[1])) { - $ifsubnet_ip = ""; - /* Find interface IP to use for NAT */ - foreach ($route_table as $ifnetwork) { - if (isset($ifnetwork['ip']) && is_ipaddr($ifnetwork['ip']) && $ifnetwork['if'] == $subnet_if && ip_in_subnet($ifnetwork['ip'], $subnet)) { - $ifsubnet_ip = $ifnetwork['ip']; - break; - } - } - if (!empty($ifsubnet_ip)) { - $subnets = array($subnet); - /* Find static routes that also need to be referenced in the NAT rule */ - foreach($route_table as $rtentry) { - if (isset($rtentry['gateway']) && is_ipaddr($rtentry['gateway']) && $rtentry['if'] == $subnet_if && ip_in_subnet($rtentry['gateway'], $subnet)) { - $subnets[] = $rtentry['subnet']; - } - } - if (count($subnets) > 1) { - $subnet = "{ " . implode(" ", $subnets) . " }"; - } - $natrules .= "no nat on {$subnet_if}{$protocol_text} from {$subnet_if} to {$target}\n"; - $natrules .= "nat on {$subnet_if}{$protocol_text} from {$subnet} to {$target} -> {$ifsubnet_ip}{$static_port}\n"; - } - } - } - - if (!empty($natrules)) { - $natrules .= "\n"; - } - - return $natrules; -} - - function filter_nat_rules_automatic_tonathosts(&$FilterIflist, $with_descr = false) { global $config, $GatewaysList; @@ -1122,105 +1040,13 @@ function filter_nat_rules_generate_if(&$FilterIflist, $if, $src = "any", $srcpor return $natrule; } -function filter_nat_rules_generate(&$FilterIflist, &$fw) +function filter_nat_rules_generate(&$FilterIflist) { global $config, $GatewaysList; $natrules = "no nat proto carp\n"; $natrules .= "no rdr proto carp\n"; - $reflection_txt = ""; - $route_table = ""; - - /* any 1:1 mappings? */ - if (isset($config['nat']['onetoone']) && is_array($config['nat']['onetoone'])) { - foreach ($config['nat']['onetoone'] as $rule) { - if (isset($rule['disabled'])) { - continue; - } - $sn = ""; - $sn1 = ""; - $target = alias_expand($rule['external']); - if (!$target) { - $natrules .= "# Unresolvable alias {$rule['target']}\n"; - continue; /* unresolvable alias */ - } - - if (!$rule['interface']) { - $natif = "wan"; - } else { - $natif = $rule['interface']; - } - if (!isset($FilterIflist[$natif])) { - continue; - } - $srcaddr = filter_generate_address($FilterIflist, $rule, 'source'); - $dstaddr = filter_generate_address($FilterIflist, $rule, 'destination'); - if (!$dstaddr) { - $dstaddr = $FilterIflist[$natif]['ip']; - } - - $srcaddr = trim($srcaddr); - $dstaddr = trim($dstaddr); - - $tmp = explode('/', $srcaddr); - $srcip = $tmp[0]; - if (!empty($tmp[1]) && is_numeric($tmp[1]) && strpos($target, '/') === false) { - $sn = $tmp[1]; - $sn1 = "/{$sn}"; - } - - $natif = $FilterIflist[$natif]['if']; - - /* - * If reflection is enabled, turn on extra redirections - * for this rule by adding other interfaces to an rdr rule. - */ - if ((isset($config['system']['enablebinatreflection']) || $rule['natreflection'] == "enable") - && $rule['natreflection'] != "disable") { - $nat_if_list = filter_get_reflection_interfaces($FilterIflist, $natif); - } else { - $nat_if_list = array(); - } - $nattype = empty($rule['type']) ? "binat" : $rule['type']; - $natrules .= "{$nattype} on {$natif} from {$srcaddr} to {$dstaddr} -> {$target}{$sn1}\n"; - if (!empty($nat_if_list)) { - $binat_if_list = implode(" ", $nat_if_list); - $binat_if_list = "{ {$binat_if_list} }"; - $reflection_txt .= "rdr on {$binat_if_list} from {$dstaddr} to {$target}{$sn1} -> {$srcaddr} bitmask\n"; - } - - $nat_if_list = array_merge(array($natif), $nat_if_list); - if (isset($config['system']['enablenatreflectionhelper'])) { - $reflection_txt .= filter_generate_reflection_nat($FilterIflist, $rule, $route_table, $nat_if_list, '', $srcaddr, $srcip, $sn); - } - } - } - - /* Add binat rules for Network Prefix translation */ - if (isset($config['nat']['npt']) && is_array($config['nat']['npt'])) { - foreach ($config['nat']['npt'] as $rule) { - if (isset($rule['disabled'])) { - continue; - } - if (!$rule['interface']) { - $natif = "wan"; - } else { - $natif = $rule['interface']; - } - if (!isset($FilterIflist[$natif])) { - continue; - } - $srcaddr = filter_generate_address($FilterIflist, $rule, 'source'); - $dstaddr = filter_generate_address($FilterIflist, $rule, 'destination'); - $srcaddr = trim($srcaddr); - $dstaddr = trim($dstaddr); - - $natrules .= "binat on \${$natif} from {$srcaddr} to any -> {$dstaddr}\n"; - $natrules .= "binat on \${$natif} from {$dstaddr} to any -> {$srcaddr}\n"; - } - } - if (isset($config['nat']['outbound']['mode']) && $config['nat']['outbound']['mode'] == "disabled") { $natrules .= "\n# Outbound NAT rules are disabled\n"; } @@ -1333,14 +1159,6 @@ function filter_nat_rules_generate(&$FilterIflist, &$fw) unset($alports); } - - $natrules .= "\n# NAT Inbound Redirects\n"; - $natrules .= $fw->outputNatRules(); - - if (!empty($reflection_txt)) { - $natrules .= "\n# Reflection redirects and NAT for 1:1 mappings\n" . $reflection_txt; - } - return $natrules; } @@ -1362,49 +1180,6 @@ function filter_generate_port(& $rule, $target = "source", $isnat = false) { return $src; } -function filter_generate_address(&$FilterIflist, &$rule, $target = 'source', $isnat = false) -{ - global $config; - - $src = ''; - - if (isset($rule[$target]['any'])) { - $src = "any"; - } elseif (!empty($rule[$target]['network'])) { - $network_name = $rule[$target]['network']; - $matches = ""; - if ($network_name == '(self)') { - $src = "(self)"; - } elseif (preg_match("/^(wan|lan|opt[0-9]+)ip$/", $network_name, $matches)) { - if (empty($FilterIflist[$matches[1]]['if'])) { - // interface non-existent or in-active - return null; - } - $src = "({$FilterIflist["{$matches[1]}"]['if']})"; - } else { - if (empty($FilterIflist[$network_name]['if'])) { - // interface non-existent or in-active - return null; - } - $src = "({$FilterIflist[$network_name]['if']}:network)"; - } - if (isset($rule[$target]['not'])) { - $src = " !{$src}"; - } - } elseif ($rule[$target]['address']) { - $expsrc = alias_expand($rule[$target]['address']); - if (isset($rule[$target]['not'])) { - $not = "!"; - } else { - $not = ""; - } - $src = " {$not} {$expsrc}"; - } - $src .= filter_generate_port($rule, $target, $isnat); - - return $src; -} - function filter_rules_legacy(&$FilterIflist) { global $config; diff --git a/src/www/vpn_openvpn_export.php b/src/www/vpn_openvpn_export.php index 365bf9ee5..bc286ecce 100644 --- a/src/www/vpn_openvpn_export.php +++ b/src/www/vpn_openvpn_export.php @@ -35,6 +35,49 @@ require_once("services.inc"); require_once("filter.inc"); require_once("interfaces.inc"); +function filter_generate_address(&$FilterIflist, &$rule, $target = 'source', $isnat = false) +{ + global $config; + + $src = ''; + + if (isset($rule[$target]['any'])) { + $src = "any"; + } elseif (!empty($rule[$target]['network'])) { + $network_name = $rule[$target]['network']; + $matches = ""; + if ($network_name == '(self)') { + $src = "(self)"; + } elseif (preg_match("/^(wan|lan|opt[0-9]+)ip$/", $network_name, $matches)) { + if (empty($FilterIflist[$matches[1]]['if'])) { + // interface non-existent or in-active + return null; + } + $src = "({$FilterIflist["{$matches[1]}"]['if']})"; + } else { + if (empty($FilterIflist[$network_name]['if'])) { + // interface non-existent or in-active + return null; + } + $src = "({$FilterIflist[$network_name]['if']}:network)"; + } + if (isset($rule[$target]['not'])) { + $src = " !{$src}"; + } + } elseif ($rule[$target]['address']) { + $expsrc = alias_expand($rule[$target]['address']); + if (isset($rule[$target]['not'])) { + $not = "!"; + } else { + $not = ""; + } + $src = " {$not} {$expsrc}"; + } + $src .= filter_generate_port($rule, $target, $isnat); + + return $src; +} + function openvpn_client_export_prefix($srvid, $usrid = null, $crtid = null) { global $config;