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
This commit is contained in:
Ad Schellevis 2021-04-21 17:04:44 +02:00
parent d3bc697309
commit cdf328078b
4 changed files with 23 additions and 7 deletions

View File

@ -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,

View File

@ -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'];

View File

@ -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");
}
}

View File

@ -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'