Skip to content

Commit

Permalink
system: restructure routing to carry out default gateway switching an…
Browse files Browse the repository at this point in the history
…d address family specific reconfig

Also improves the log message generation and avoids default gateway addition
to interfaces without an address set.  In order to make the gateway switch
work we need to switch the underlying monitor action to reload routing info
as well as doing the filter reload.
  • Loading branch information
fichtner committed Apr 27, 2023
1 parent da81983 commit a8e9862
Show file tree
Hide file tree
Showing 6 changed files with 52 additions and 45 deletions.
18 changes: 1 addition & 17 deletions src/etc/inc/filter.inc
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ function ifgroup_setup()
}
}

function filter_configure_sync($verbose = false, $load_aliases = true, $switch_gw = true)
function filter_configure_sync($verbose = false, $load_aliases = true)
{
global $config;

Expand Down Expand Up @@ -252,22 +252,6 @@ function filter_configure_sync($verbose = false, $load_aliases = true, $switch_g
}
}

if ($switch_gw && isset($config['system']['gw_switch_default'])) {
// When gateway switching is enabled, we might consider a different default gateway.
// although this isn't really the right spot for the feature (it's a monitoring/routing decision),
// we keep it here for now (historical reasons).
$down_gateways = return_down_gateways();
foreach (array("inet", "inet6") as $ipprotocol) {
if (!empty($down_gateways)) {
log_msg(sprintf("Ignore down %s gateways : %s", $ipprotocol, implode(",", $down_gateways)), LOG_DEBUG);
}
$default_gw = $fw->getGateways()->getDefaultGW($down_gateways, $ipprotocol);
if ($default_gw !== null && !empty($default_gw['gateway'])) {
system_default_route($default_gw['gateway'], $default_gw['if'], isset($default_gw['fargw']));
}
}
}

openlog("firewall", LOG_DAEMON, LOG_LOCAL4);

$aliases = filter_generate_aliases();
Expand Down
63 changes: 43 additions & 20 deletions src/etc/inc/system.inc
Original file line number Diff line number Diff line change
Expand Up @@ -587,8 +587,10 @@ function system_default_route($gateway, $interface, $far = false)
mwexecf('/sbin/route add -%s default %s', [$family, $gateway]);
}

function system_routing_configure($verbose = false, $interface = null, $monitor = true)
function system_routing_configure($verbose = false, $interface = null, $monitor = true, $family = null)
{
global $config;

service_log(sprintf('Setting up route%s...', empty($interface) ? 's' : " {$interface}"), $verbose);

if (!empty($interface)) {
Expand All @@ -599,19 +601,30 @@ function system_routing_configure($verbose = false, $interface = null, $monitor

$ifdetails = legacy_interfaces_details();
$gateways = new \OPNsense\Routing\Gateways($ifdetails);
$down_gateways = isset($config['system']['gw_switch_default']) ? return_down_gateways() : [];

foreach (['inet', 'inet6'] as $ipproto) {
/* determine default gateway without considering monitor status */
$gateway = $gateways->getDefaultGW([], $ipproto);
$logproto = $ipproto == 'inet' ? 'IPv4' : 'IPv6';
if ($gateway != null) {
log_msg("ROUTING: {$logproto} default gateway set to {$gateway['interface']}", LOG_INFO);
if ((empty($interface) || $interface == $gateway['interface']) && !empty($gateway['gateway'])) {
log_msg("ROUTING: setting {$logproto} default route to {$gateway['gateway']}");
system_default_route($gateway['gateway'], $gateway['interface'], isset($gateway['fargw']));
} else {
log_msg("ROUTING: skipping {$logproto} default route");
if (!empty($down_gateways)) {
log_msg(sprintf('ROUTING: ignoring down gateways: %s', implode(', ', $down_gateways)), LOG_DEBUG);
}

foreach (['inet' => 'ipv4', 'inet6' => 'ipv6'] as $ipproto => $type) {
if ($family !== null && $family !== $ipproto) {
continue;
}

$gateway = $gateways->getDefaultGW($down_gateways, $ipproto);
if ($gateway == null) {
continue;
}

if (isset($config['system']['gw_switch_default']) || empty($interface) || $interface == $gateway['interface']) {
if (empty($ifdetails[$gateway['if']][$type][0])) {
log_msg("ROUTING: refusing to set {$ipproto} gateway on addressless {$gateway['interface']}", LOG_ERR);
continue;
}

log_msg("ROUTING: configuring {$ipproto} default gateway on {$gateway['interface']}", LOG_INFO);
system_default_route($gateway['gateway'], $gateway['interface'], isset($gateway['fargw']));
}
}

Expand All @@ -628,10 +641,19 @@ function system_routing_configure($verbose = false, $interface = null, $monitor
continue;
}

if (!is_subnet($rtent['network'])) {
if (is_subnetv4($rtent['network'])) {
$ipproto = 'inet';
} elseif (is_subnetv6($rtent['network'])) {
$ipproto = 'inet6';
} else {
log_msg(sprintf('Cannot add static route to: %s', $rtent['network']), LOG_ERR);
continue;
}

if ($family !== null && $family !== $ipproto) {
continue;
}

$interfacegw = $gateway['if'];
$gatewayip = $gateway['gateway'];
$fargw = isset($gateway['fargw']) && $gateway['ipprotocol'] != 'inet6';
Expand All @@ -646,19 +668,16 @@ function system_routing_configure($verbose = false, $interface = null, $monitor
break;
}

$ip = $rtent['network'];
$cmd = " -{$ipproto} {$blackhole} " . escapeshellarg($rtent['network']) . " ";

if (!empty($rtent['disabled'])) {
$inet = (is_subnetv6($ip) ? "-inet6" : "-inet");
$cmd = " {$inet} {$blackhole} " . escapeshellarg($ip) . " ";
mwexec("/sbin/route delete {$cmd}", true);
} else {
$inet = (is_subnetv6($ip) ? "-inet6" : "-inet");
$cmd = " {$inet} {$blackhole} " . escapeshellarg($ip) . " ";
if (is_ipaddr($gatewayip)) {
mwexec("/sbin/route delete {$cmd}", true);
if ($fargw) {
mwexecf('/sbin/route delete %s %s -interface %s ', [$inet, $gatewayip, $interfacegw], true);
mwexecf('/sbin/route add %s %s -interface %s', [$inet, $gatewayip, $interfacegw], true);
mwexecf('/sbin/route delete -%s %s -interface %s ', [$ipproto, $gatewayip, $interfacegw], true);
mwexecf('/sbin/route add %s -%s -interface %s', [$ipproto, $gatewayip, $interfacegw], true);
} elseif (is_linklocal($gatewayip) && strpos($gatewayip, '%') === false) {
$gatewayip .= "%{$interfacegw}";
}
Expand All @@ -678,6 +697,10 @@ function system_routing_configure($verbose = false, $interface = null, $monitor
$reloads = [];

foreach ($gateways->gatewaysIndexedByName(true) as $name => $gateway) {
if ($family !== null && $family !== $gateway['ipprotocol']) {
continue;
}

if ($interface == $gateway['interface']) {
$reloads[] = $name;
}
Expand Down
6 changes: 3 additions & 3 deletions src/etc/rc.bootup
Original file line number Diff line number Diff line change
Expand Up @@ -86,11 +86,11 @@ system_hostname_configure(true);
system_resolver_configure(true);
system_syslog_start(true);

filter_configure_sync(true, false, false); /* apply default policy before interface setup */
filter_configure_sync(true, false); /* apply default policy before interface setup */
interfaces_hardware(true);
interfaces_configure(true);
system_resolver_configure(true); /* adapts to runtime interface configuration */
filter_configure_sync(true, true, false);
filter_configure_sync(true);
plugins_configure('early', true);
system_routing_configure(true, null, false);

Expand All @@ -99,7 +99,7 @@ plugins_configure('dhcrelay', true);
plugins_configure('dns', true);

plugins_configure('monitor', true, [null, true]);
filter_configure_sync(true, true, false);
filter_configure_sync(true);
plugins_configure('vpn', true);
plugins_configure('bootup', true);
rrd_configure(true, true);
Expand Down
2 changes: 1 addition & 1 deletion src/etc/rc.newwanip
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ foreach (array_keys($restartifs) as $ifname) {
*/
ifgroup_setup();

system_routing_configure(false, $interface);
system_routing_configure(false, $interface, true, 'inet');
filter_configure_sync();

if (is_ipaddr($cacheip) && $ip != $cacheip) {
Expand Down
2 changes: 1 addition & 1 deletion src/etc/rc.newwanipv6
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ $interfaces = array_keys(link_interface_to_track6($interface, true));
array_unshift($interfaces, $interface);

foreach ($interfaces as $interface) {
system_routing_configure(false, $interface);
system_routing_configure(false, $interface, true, 'inet6');
}

filter_configure_sync();
Expand Down
6 changes: 3 additions & 3 deletions src/etc/rc.syshook.d/monitor/10-dpinger
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#!/bin/sh

# Copyright (c) 2018-2019 Franco Fichtner <franco@opnsense.org>
# Copyright (c) 2018-2023 Franco Fichtner <franco@opnsense.org>
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
Expand Down Expand Up @@ -34,7 +34,7 @@ fi

/usr/bin/logger -t dpinger "GATEWAY ALARM: ${GATEWAY} (Addr: ${2} Alarm: ${3} RTT: ${4}us RTTd: ${5}us Loss: ${6}%)"

echo -n "Reloading filter: "
/usr/local/bin/flock -n -E 0 -o /tmp/filter_reload_gateway.lock configctl filter reload skip_alias
echo -n "Reloading routes/filter: "
/usr/local/bin/flock -n -E 0 -o /tmp/filter_reload_gateway.lock configctl routes configure

exit 0

0 comments on commit a8e9862

Please sign in to comment.