diff --git a/src/etc/inc/gwlb.inc b/src/etc/inc/gwlb.inc index 7ce4b8f27..d4d67035f 100644 --- a/src/etc/inc/gwlb.inc +++ b/src/etc/inc/gwlb.inc @@ -1,6 +1,7 @@ Copyright (C) 2008 Bill Marquette Copyright (C) 2008 Seth Mos Copyright (C) 2010 Ermal Luçi @@ -769,25 +770,8 @@ function fixup_default_gateway($gateways_status, $gateways_arr) continue; } - $defaultif = get_real_interface($gateways_arr[$dfltgwname]['friendlyiface']); - $gwipmatch = $dfltgwip; - if (is_linklocal($dfltgwip)) { - /* correct match in IPv6 case */ - $gwipmatch .= "%{$defaultif}"; - } - - $tmpcmd = "/sbin/route -n get -{$ipprotocol} default 2>/dev/null | /usr/bin/awk '/gateway:/ {print $2}'"; - $defaultgw = trim(exec($tmpcmd), " \n"); - if ($defaultgw != $gwipmatch) { - foreach (glob('/tmp/*_defaultgw' . ($ipprotocol == 'inet' ? '' : 'v6')) as $to_delete) { - log_error("GATEWAYS: removing {$to_delete}"); - @unlink($to_delete); - } - log_error("Switching default gateway to $dfltgwname ($dfltgwip on $defaultif)"); - @file_put_contents("/tmp/{$defaultif}_defaultgw" . ($ipprotocol == 'inet' ? '' : 'v6'), $dfltgwip); - /* XXX fargw and IPv6 should be cleaned up to make it easier to read */ - system_default_route($dfltgwip, !isset($gateways_arr[$dfltgwname]['fargw']) && $ipprotocol == 'inet' ? null : $defaultif); - } + /* switch only if another gateway is set aa the default */ + system_default_route($dfltgwip, $ipprotocol, $gateways_arr[$dfltgwname]['friendlyiface'], isset($gateways_arr[$dfltgwname]['fargw']), true); } } diff --git a/src/etc/inc/interfaces.inc b/src/etc/inc/interfaces.inc index 7e042ef74..41adfb996 100644 --- a/src/etc/inc/interfaces.inc +++ b/src/etc/inc/interfaces.inc @@ -995,7 +995,7 @@ function interface_gif_configure(&$gif, $gifkey = "") foreach ($iflist as $ifname) { if ($config['interfaces'][$ifname]['if'] == $gifif) { if (get_interface_gateway($ifname) || get_interface_gateway_v6($ifname)) { - system_routing_configure($ifname); + system_routing_configure(false, $ifname); break; } } @@ -1076,7 +1076,7 @@ function interfaces_configure($verbose = false) interfaces_group_setup(); if ($reload) { - system_routing_configure('', $verbose); + system_routing_configure($verbose); ipsec_configure_do($verbose); plugins_configure('dns', $verbose); services_dhcpd_configure('all', array(), $verbose); @@ -2713,7 +2713,7 @@ function interface_configure($interface = 'wan', $reloadall = false, $linkupeven } if ($reloadall == true) { - system_routing_configure($interface); + system_routing_configure(false, $interface); ipsec_configure_do(); plugins_configure('dns'); services_dhcpd_configure(); diff --git a/src/etc/inc/system.inc b/src/etc/inc/system.inc index dcac9923e..216b900a6 100644 --- a/src/etc/inc/system.inc +++ b/src/etc/inc/system.inc @@ -417,30 +417,67 @@ function system_host_route($host, $gateway, $delete = true, $add = true) } } -function system_default_route($gateway, $interface = null) +function system_default_route($gateway, $family, $interface, $far = false, $keep = false) { - if (is_ipaddrv4($gateway)) { - $family = 'inet'; - } elseif (is_ipaddrv6($gateway)) { - $family = 'inet6'; - if (is_linklocal($gateway)) { - $gateway .= "%{$interface}"; + $realif = get_real_interface($interface); + + switch ($family) { + case 'inet': + break; + case 'inet6': + if (is_linklocal($gateway)) { + $gateway .= "%{$realif}"; + } + break; + default: + log_error("ROUTING: unknown address family '{$family}'"); + return; + } + + if ($keep) { + $tmpcmd = "/sbin/route -n get -{$family} default 2>/dev/null | /usr/bin/awk '/gateway:/ {print $2}'"; + $current = trim(exec($tmpcmd), " \n"); + if ($current == $gateway) { + log_error("ROUTING: keeping current default gateway '{$gateway}'"); + return; + } + } + + if ($family == 'inet') { + foreach (glob('/tmp/*_defaultgw', GLOB_BRACE) as $to_delete) { + log_error("ROUTING: removing {$to_delete}"); + @unlink($to_delete); + } + + log_error("ROUTING: creating /tmp/{$realif}_defaultgw using '{$gateway}'"); + @file_put_contents("/tmp/{$realif}_defaultgw", $gateway); + + if (!$far) { + $realif = null; } - /* IPv6 does not support far gateway notion */ - $interface = null; } else { - return; + foreach (glob('/tmp/*_defaultgwv6', GLOB_BRACE) as $to_delete) { + log_error("ROUTING: removing {$to_delete}"); + @unlink($to_delete); + } + + log_error("ROUTING: creating /tmp/{$realif}_defaultgwv6 using '{$gateway}'"); + @file_put_contents("/tmp/{$realif}_defaultgwv6", $gateway); + + /* IPv6 does not support far gateway notion */ + $realif = null; + $far = false; } mwexecf('/sbin/route delete -%s default', array($family), true); - if (!empty($interface)) { - mwexecf('/sbin/route delete -%s %s -interface %s', array($family, $gateway, $interface), true); - mwexecf('/sbin/route add -%s %s -interface %s', array($family, $gateway, $interface)); + if (!empty($realif)) { + mwexecf('/sbin/route delete -%s %s -interface %s', array($family, $gateway, $realif), true); + mwexecf('/sbin/route add -%s %s -interface %s', array($family, $gateway, $realif)); } mwexecf('/sbin/route add -%s default %s', array($family, $gateway)); } -function system_routing_configure($interface = '', $verbose = false) +function system_routing_configure($verbose = false, $interface = '') { global $config; @@ -449,58 +486,45 @@ function system_routing_configure($interface = '', $verbose = false) flush(); } - $gatewayip = ""; - $interfacegw = ""; + $interfacegw = ''; $foundgw = false; - $gatewayipv6 = ""; - $interfacegwv6 = ""; - $foundgwv6 = false; + $gatewayip = ''; $fargw = false; + $interfacegwv6 = ''; + $foundgwv6 = false; + $gatewayipv6 = ''; + if (!empty($interface)) { log_error("ROUTING: entering configure using '${interface}'"); } else { log_error("ROUTING: entering configure using defaults"); } - /* tack on all the hard defined gateways as well */ if (isset($config['gateways']['gateway_item'])) { - foreach (glob('/tmp/*_defaultgw{,v6}', GLOB_BRACE) as $to_delete) { - log_error("ROUTING: removing {$to_delete}"); - @unlink($to_delete); - } - foreach ($config['gateways']['gateway_item'] as $gateway) { if (isset($gateway['defaultgw'])) { - if ($foundgw == false && $gateway['ipprotocol'] != "inet6" && (is_ipaddrv4($gateway['gateway']) || $gateway['gateway'] == "dynamic")) { - if ($gateway['gateway'] == "dynamic") { + if ($foundgw == false && $gateway['ipprotocol'] != 'inet6') { + if ($gateway['gateway'] == 'dynamic') { $gateway['gateway'] = get_interface_gateway($gateway['interface']); } + + $interfacegw = $gateway['interface']; $fargw = isset($gateway['fargw']); $gatewayip = $gateway['gateway']; - $interfacegw = $gateway['interface']; - if (!empty($gateway['interface'])) { - $defaultif = get_real_interface($gateway['interface']); - if ($defaultif && is_ipaddrv4($gatewayip)) { - log_error("ROUTING: creating /tmp/{$defaultif}_defaultgw"); - @file_put_contents("/tmp/{$defaultif}_defaultgw", $gatewayip); - } - } $foundgw = true; - } elseif ($foundgwv6 == false && $gateway['ipprotocol'] == "inet6" && (is_ipaddrv6($gateway['gateway']) || $gateway['gateway'] == "dynamic")) { - if ($gateway['gateway'] == "dynamic") { + + log_error("ROUTING: IPv4 default gateway set to {$interfacegw}"); + } elseif ($foundgwv6 == false && $gateway['ipprotocol'] == 'inet6') { + if ($gateway['gateway'] == 'dynamic') { $gateway['gateway'] = get_interface_gateway_v6($gateway['interface']); } - $gatewayipv6 = $gateway['gateway']; + $interfacegwv6 = $gateway['interface']; - if (!empty($gateway['interface'])) { - $defaultifv6 = get_real_interface($gateway['interface']); - if ($defaultifv6 && is_ipaddrv6($gatewayipv6)) { - log_error("ROUTING: creating /tmp/{$defaultifv6}_defaultgwv6"); - @file_put_contents("/tmp/{$defaultifv6}_defaultgwv6", $gatewayipv6); - } - } + $gatewayipv6 = $gateway['gateway']; $foundgwv6 = true; + + log_error("ROUTING: IPv6 default gateway set to {$interfacegwv6}"); } } } @@ -516,43 +540,34 @@ function system_routing_configure($interface = '', $verbose = false) * In fact the following code is a mini gateway switcher * facility which can only switch one hardcoded gateway and * may obscure a problem with the setup for a long time... :( + * + * XXX Find a way to infer an upstream-capable interface or + * maybe make gateway switching the hardcoded behaviour, or + * at least the new default. */ if (!$foundgw) { $interfacegw = 'wan'; - $defaultif = get_real_interface($interfacegw); + log_error("ROUTING: no IPv4 default gateway set, assuming {$interfacegw}"); $gatewayip = get_interface_gateway($interfacegw); - if (is_ipaddrv4($gatewayip)) { - log_error("ROUTING: no IPv4 default gateway set, assuming {$interfacegw} on '{$defaultif}' ({$gatewayip})"); - @file_put_contents("/tmp/{$defaultif}_defaultgw", $gatewayip); - } else { - log_error("ROUTING: no IPv4 default gateway set, skipping {$interfacegw} on '{$defaultif}'"); - } } if (!$foundgwv6) { $interfacegwv6 = 'wan'; - $defaultifv6 = get_real_interface($interfacegwv6); + log_error("ROUTING: no IPv6 default gateway set, assuming {$interfacegwv6}"); $gatewayipv6 = get_interface_gateway_v6($interfacegwv6); - if (is_ipaddrv6($gatewayipv6)) { - log_error("ROUTING: no IPv6 default gateway set, trying {$interfacegwv6} on '{$defaultifv6}' ({$gatewayipv6})"); - @file_put_contents("/tmp/{$defaultifv6}_defaultgwv6", $gatewayipv6); - } else { - log_error("ROUTING: no IPv6 default gateway set, skipping {$interfacegwv6} on '{$defaultifv6}'"); - $interfacegwv6 = ''; - } } if ((empty($interface) || $interface == $interfacegw) && is_ipaddrv4($gatewayip)) { log_error("ROUTING: setting IPv4 default route to {$gatewayip}"); - system_default_route($gatewayip, $fargw ? $defaultif : null); + system_default_route($gatewayip, 'inet', $interfacegw, $fargw); } else { log_error("ROUTING: skipping IPv4 default route"); } if ((empty($interface) || $interface == $interfacegwv6) && is_ipaddrv6($gatewayipv6)) { log_error("ROUTING: setting IPv6 default route to {$gatewayipv6}"); - system_default_route($gatewayipv6, $defaultifv6); + system_default_route($gatewayipv6, 'inet6', $interfacegwv6, false); } else { log_error("ROUTING: skipping IPv6 default route"); } diff --git a/src/etc/rc.bootup b/src/etc/rc.bootup index 7a7ad21b8..afb26e0ad 100755 --- a/src/etc/rc.bootup +++ b/src/etc/rc.bootup @@ -104,7 +104,7 @@ filter_pflog_start(true); setup_gateways_monitor(true); plugins_configure('earlybootup', true); system_cron_configure(true, true); -system_routing_configure('', true); +system_routing_configure(true); plugins_configure('dns', true); services_dhcpd_configure('all', array(), true); diff --git a/src/etc/rc.newwanip b/src/etc/rc.newwanip index 1a92ddad0..dcf3c78e3 100755 --- a/src/etc/rc.newwanip +++ b/src/etc/rc.newwanip @@ -144,7 +144,7 @@ if (isset($config['gifs']['gif']) && is_array($config['gifs']['gif'])){ if (!empty($confif)) { interface_configure($confif); } - system_routing_configure($ifname); + system_routing_configure(false, $ifname); } } } @@ -161,7 +161,7 @@ $cacheip = @file_get_contents($cacheip_file); if (!is_ipaddr($cacheip) || $ip != $cacheip || !is_ipaddr($configip)) { @unlink($cacheip_file); - system_routing_configure($interface); + system_routing_configure(false, $interface); setup_gateways_monitor(); plugins_configure('vpn', false, array($interface)); filter_configure_sync(); diff --git a/src/etc/rc.newwanipv6 b/src/etc/rc.newwanipv6 index 2c357ce20..1b05ac821 100755 --- a/src/etc/rc.newwanipv6 +++ b/src/etc/rc.newwanipv6 @@ -142,7 +142,7 @@ if (!is_ipaddr($cacheip) || $ip != $cacheip || !is_ipaddr($configip)) { @unlink($cacheip_file); - system_routing_configure($interface); + system_routing_configure(false, $interface); setup_gateways_monitor(); plugins_configure('vpn', false, array($interface)); filter_configure_sync(); diff --git a/src/etc/rc.routing_configure b/src/etc/rc.routing_configure index 20d2681ff..3d9a7a964 100755 --- a/src/etc/rc.routing_configure +++ b/src/etc/rc.routing_configure @@ -42,6 +42,6 @@ foreach (glob("/tmp/delete_route_*.todo") as $filename) { unlink($filename); } -system_routing_configure('', true); +system_routing_configure(true); setup_gateways_monitor(true); filter_configure_sync(true);