From 8ed255c696fedb2367dbe0cec79c84ba0d8e28eb Mon Sep 17 00:00:00 2001 From: Ad Schellevis Date: Fri, 22 Dec 2017 20:12:41 +0100 Subject: [PATCH] firewall/nat, work in progress port forwards. Class names may change later on, but functionally this part should be able to render the portforward rules, which will be integrated first before moving the other redirect/nat portions. --- .../app/library/OPNsense/Firewall/NatRule.php | 101 ++++++++++++------ .../app/library/OPNsense/Firewall/Plugin.php | 9 ++ 2 files changed, 80 insertions(+), 30 deletions(-) diff --git a/src/opnsense/mvc/app/library/OPNsense/Firewall/NatRule.php b/src/opnsense/mvc/app/library/OPNsense/Firewall/NatRule.php index 167d57b2a..947859e43 100644 --- a/src/opnsense/mvc/app/library/OPNsense/Firewall/NatRule.php +++ b/src/opnsense/mvc/app/library/OPNsense/Firewall/NatRule.php @@ -35,22 +35,35 @@ namespace OPNsense\Firewall; */ class NatRule extends Rule { - private $procorder_rdr = array( - 'disabled' => 'parseIsComment', - 'rdr' => 'parseBool,no rdr,rdr', - 'pass' => 'parseBool,pass ', - 'interface' => 'parseInterface', - 'ipprotocol' => 'parsePlain', - 'protocol' => 'parseReplaceSimple,tcp/udp:{tcp udp},proto ', - 'from' => 'parsePlainCurly,from ', - 'from_port' => 'parsePlainCurly, port ', - 'to' => 'parsePlainCurly,to ', - 'to_port' => 'parsePlainCurly, port ', - 'tag' => 'parsePlain, tag ', - 'tagged' => 'parsePlain, tagged ', - 'target' => 'parsePlain, -> ', - 'localport' => 'parsePlain, port ', - 'poolopts' => 'parsePlain' + private $procorder = array( + 'rdr' => array( + 'disabled' => 'parseIsComment', + 'rdr' => 'parseBool,no rdr,rdr', + 'pass' => 'parseBool,pass ', + 'interface' => 'parseInterface', + 'ipprotocol' => 'parsePlain', + 'protocol' => 'parseReplaceSimple,tcp/udp:{tcp udp},proto ', + 'from' => 'parsePlainCurly,from ', + 'from_port' => 'parsePlainCurly, port ', + 'to' => 'parsePlainCurly,to ', + 'to_port' => 'parsePlainCurly, port ', + 'tag' => 'parsePlain, tag ', + 'tagged' => 'parsePlain, tagged ', + 'target' => 'parsePlain, -> ', + 'localport' => 'parsePlain, port ', + 'poolopts' => 'parsePlain', + 'descr' => 'parseComment' + ), + 'rdr_nat' => array( + 'disabled' => 'parseIsComment', + 'nat' => 'parseBool,no nat,nat', + 'interface' => 'parseInterface', + 'protocol' => 'parseReplaceSimple,tcp/udp:{tcp udp},proto ', + 'interface.from' => 'parseInterface, from ,:network', + 'target.to' => 'parsePlainCurly,to ', + 'interface.to' => 'parseInterface, -> ', + 'staticnatport' => 'parseBool, static-port , port 1024:65535 ' + ) ); /** @@ -63,6 +76,16 @@ class NatRule extends Rule return !empty($value) ? "#" : ""; } + /** + * parse comment + * @param string $value field value + * @return string + */ + private function parseComment($value) + { + return !empty($value) ? "# " . $value : ""; + } + /** * search interfaces without a gateway other then the one provided * @param $interface @@ -73,8 +96,8 @@ class NatRule extends Rule $result = array(); foreach ($this->interfaceMapping as $intfk => $intf) { if (empty($intf['gateway']) && empty($intf['gatewayv6']) && $interface != $intfk - && !in_array($intf['if'], $result)) { - $result[] = $intf['if']; + && !in_array($intf['if'], $result) && $intfk != 'loopback') { + $result[] = $intfk; } } return $result; @@ -87,9 +110,9 @@ class NatRule extends Rule */ private function fetchActualRules() { - $result = array(); $result = array(); $interfaces = empty($this->rule['interface']) ? array(null) : explode(',', $this->rule['interface']); + foreach ($interfaces as $interface) { if (isset($this->rule['ipprotocol']) && $this->rule['ipprotocol'] == 'inet46') { $ipprotos = array('inet', 'inet6'); @@ -101,6 +124,7 @@ class NatRule extends Rule foreach ($ipprotos as $ipproto) { $tmp = $this->rule; + $tmp['rule_types'] = array("rdr"); $tmp['rdr'] = !empty($tmp['nordr']); if (!empty($tmp['associated-rule-id']) && $tmp['associated-rule-id'] == "pass") { $tmp['pass'] = empty($tmp['nordr']); @@ -138,9 +162,22 @@ class NatRule extends Rule if (!empty($interface) && empty($this->interfaceMapping[$interface]['if'])) { $tmp['disabled'] = true; } + // automatically generate nat rule when enablenatreflectionhelper is set + if (!$tmp['disabled'] && empty($tmp['nordr']) && !empty($tmp['enablenatreflectionhelper'])) { + $tmp2 = $tmp; + $tmp2['rule_types'][] = "rdr_nat"; + $tmp2['staticnatport'] = !empty($tmp['staticnatport']); + $result[] = $tmp2; + } + $result[] = $tmp; - // print_r($this->interfaceMapping[$interface]); - // print_r($this->reflectionInterfaces($interface)); + // When reflection is enabled our ruleset should cover all + if (!$tmp['disabled'] && in_array($this->rule['natreflection'], array("purenat", "enable"))) { + foreach ($this->reflectionInterfaces($interface) as $refl_interf) { + $tmp['interface'] = $refl_interf; + $result[] = $tmp; + } + } } } return $result; @@ -154,17 +191,21 @@ class NatRule extends Rule { $ruleTxt = ''; foreach ($this->fetchActualRules() as $rule) { - foreach ($this->procorder_rdr as $tag => $handle) { - $tmp = explode(',', $handle); - $method = $tmp[0]; - $args = array(isset($rule[$tag]) ? $rule[$tag] : null); - if (count($tmp) > 1) { - array_shift($tmp); - $args = array_merge($args, $tmp); + foreach ($rule['rule_types'] as $rule_type) { + foreach ($this->procorder[$rule_type] as $tag => $handle) { + // support reuse of the same fieldname + $tag = explode(".", $tag)[0]; + $tmp = explode(',', $handle); + $method = $tmp[0]; + $args = array(isset($rule[$tag]) ? $rule[$tag] : null); + if (count($tmp) > 1) { + array_shift($tmp); + $args = array_merge($args, $tmp); + } + $ruleTxt .= call_user_func_array(array($this,$method), $args); } - $ruleTxt .= call_user_func_array(array($this,$method), $args); + $ruleTxt .= "\n"; } - $ruleTxt .= "\n"; } return $ruleTxt; } diff --git a/src/opnsense/mvc/app/library/OPNsense/Firewall/Plugin.php b/src/opnsense/mvc/app/library/OPNsense/Firewall/Plugin.php index 0cf276260..f44c0696d 100644 --- a/src/opnsense/mvc/app/library/OPNsense/Firewall/Plugin.php +++ b/src/opnsense/mvc/app/library/OPNsense/Firewall/Plugin.php @@ -56,6 +56,12 @@ class Plugin if (!empty(Config::getInstance()->object()->system->skip_rules_gw_down)) { $this->systemDefaults['skip_rules_gw_down'] = true; } + if (!empty(Config::getInstance()->object()->system->disablenatreflection)) { + $this->systemDefaults['natreflection'] = "enable"; + } + if (!empty(Config::getInstance()->object()->system->enablenatreflectionhelper)) { + $this->systemDefaults['enablenatreflectionhelper'] = true; + } } /** @@ -226,6 +232,9 @@ class Plugin */ public function registerNatRule($prio, $conf) { + if (!empty($this->systemDefaults)) { + $conf = array_merge($this->systemDefaults, $conf); + } $rule = new NatRule($this->interfaceMapping, $conf); if (empty($this->natRules[$prio])) { $this->natRules[$prio] = array();