From cdf328078bd3e16e1f4beb9b0d6956595fb59c67 Mon Sep 17 00:00:00 2001 From: Ad Schellevis Date: Wed, 21 Apr 2021 17:04:44 +0200 Subject: [PATCH] add policy based routing support for "dynamic gateway policy" type interfaces. closes https://github.com/opnsense/core/issues/4905 o expose gateway_interface property on gateway so consumers can act upon it o exclude gateway_interface gateways on automatic "let out anything from firewall host itself (force gw)" rules to avoid side affects o construct proper route-to statement when address is omitted o construct proper reply-to statement when address is omitted and a reply-to property is set in the (dynamic) rule --- src/etc/inc/filter.lib.inc | 9 +++++++-- .../mvc/app/library/OPNsense/Firewall/FilterRule.php | 8 ++++++-- .../mvc/app/library/OPNsense/Firewall/Plugin.php | 11 ++++++++--- .../mvc/app/library/OPNsense/Routing/Gateways.php | 2 ++ 4 files changed, 23 insertions(+), 7 deletions(-) diff --git a/src/etc/inc/filter.lib.inc b/src/etc/inc/filter.lib.inc index 9dada6872..d1a1998cb 100644 --- a/src/etc/inc/filter.lib.inc +++ b/src/etc/inc/filter.lib.inc @@ -601,10 +601,15 @@ function filter_core_rules_system($fw, $defaults) $intf_has_v6 = $intf_has_v6 || is_subnetv6($addr); } foreach ($fw->getInterfaceGateways($ifcfg['if']) as $gwname) { - $gwproto = $fw->getGateway($gwname)['proto']; + $gwcfg = $fw->getGateway($gwname); + if (empty($gwcfg['gateway'])) { + // XXX: only force traffic on explict gateway [address] selection, + // exclude gateway_interface types. + continue; + } // only try to add gateway rules for traffic leaving this interface // when the correct protocol is assigned to the interface - if (($gwproto == 'inet' && $intf_has_v4) || ($gwproto == 'inet6' && $intf_has_v6)) { + if (($gwcfg['proto'] == 'inet' && $intf_has_v4) || ($gwcfg['proto'] == 'inet6' && $intf_has_v6)) { $fw->registerFilterRule( 100000, array('from' => "({$ifcfg['if']})", 'direction' => 'out', 'gateway' => $gwname, diff --git a/src/opnsense/mvc/app/library/OPNsense/Firewall/FilterRule.php b/src/opnsense/mvc/app/library/OPNsense/Firewall/FilterRule.php index dea2b0810..3c42c38b9 100644 --- a/src/opnsense/mvc/app/library/OPNsense/Firewall/FilterRule.php +++ b/src/opnsense/mvc/app/library/OPNsense/Firewall/FilterRule.php @@ -123,8 +123,12 @@ class FilterRule extends Rule // reply-to gateway set, when found map to reply attribute, otherwise skip keyword if (!empty($this->gatewayMapping[$rule['reply-to']])) { $if = $this->gatewayMapping[$rule['reply-to']]['interface']; - $gw = $this->gatewayMapping[$rule['reply-to']]['gateway']; - $rule['reply'] = "reply-to ( {$if} {$gw} ) "; + if (!empty($this->gatewayMapping[$rule['reply-to']]['gateway'])){ + $gw = $this->gatewayMapping[$rule['reply-to']]['gateway']; + $rule['reply'] = "reply-to ( {$if} {$gw} ) "; + } else { + $rule['reply'] = "reply-to {$if} "; + } } } elseif (!isset($rule['disablereplyto']) && $rule['direction'] != 'any') { $proto = $rule['ipprotocol']; diff --git a/src/opnsense/mvc/app/library/OPNsense/Firewall/Plugin.php b/src/opnsense/mvc/app/library/OPNsense/Firewall/Plugin.php index 4d4f90fdb..51ecec4d5 100644 --- a/src/opnsense/mvc/app/library/OPNsense/Firewall/Plugin.php +++ b/src/opnsense/mvc/app/library/OPNsense/Firewall/Plugin.php @@ -102,11 +102,16 @@ class Plugin { $this->gateways = $gateways; foreach ($gateways->gatewaysIndexedByName(false, true) as $key => $gw) { - if (Util::isIpAddress($gw['gateway']) && !empty($gw['if'])) { - $this->gatewayMapping[$key] = array("logic" => "route-to ( {$gw['if']} {$gw['gateway']} )", + if (!empty($gw['gateway_interface']) || Util::isIpAddress($gw['gateway'])) { + if (Util::isIpAddress($gw['gateway'])) { + $logic = "route-to ( {$gw['if']} {$gw['gateway']} )"; + } else { + $logic = "route-to {$gw['if']}"; + } + $this->gatewayMapping[$key] = array("logic" => $logic, "interface" => $gw['if'], "gateway" => $gw['gateway'], - "proto" => strstr($gw['gateway'], ':') ? "inet6" : "inet", + "proto" => $gw['ipprotocol'], "type" => "gateway"); } } diff --git a/src/opnsense/mvc/app/library/OPNsense/Routing/Gateways.php b/src/opnsense/mvc/app/library/OPNsense/Routing/Gateways.php index 62510f861..fe678e525 100644 --- a/src/opnsense/mvc/app/library/OPNsense/Routing/Gateways.php +++ b/src/opnsense/mvc/app/library/OPNsense/Routing/Gateways.php @@ -212,6 +212,7 @@ class Gateways "name" => strtoupper("{$descr}_{$ctype}"), "descr" => "Interface " . strtoupper("{$descr}_{$ctype}") . " Gateway", "monitor_disable" => true, // disable monitoring by default + "gateway_interface" => false, // Dynamic gateway policy "if" => $realif, "dynamic" => true, "virtual" => true @@ -253,6 +254,7 @@ class Gateways $gwkey = $this->newKey($thisconf['priority'], !empty($thisconf['defaultgw'])); // gateway should only contain a valid address, make sure its empty unset($thisconf['gateway']); + $thisconf['gateway_interface'] = true; $this->cached_gateways[$gwkey] = $thisconf; } elseif ( $ipproto == 'inet6'