Apply default route a different way - macOS

The original way we applied default route, by forking
0.0.0.0/0 into 0/1 and 128/1 works, but if mac os has any networking
hiccups -if you change SSIDs or sleep/wake- macos erases the system default route.
And then all networking on the computer is broken.

to summarize the new way:
allowDefault=1
```
sudo route delete default 192.168.82.1
sudo route add default 10.2.0.2
sudo route add -ifscope en1 default 192.168.82.1
```

gives us this routing table
```
Destination        Gateway            RT_IFA             Flags        Refs      Use    Mtu          Netif Expire    rtt(ms) rttvar(ms)
default            10.2.0.2           10.2.0.18          UGScg          90        1   2800       feth4823
default            192.168.82.1       192.168.82.217     UGScIg
```

allowDefault=0
```
sudo route delete default
sudo route delete -ifscope en1 default
sudo route add default 192.168.82.1
```

Notice the I flag, for -ifscope, on the physical default route.

route change does not seem to work reliably.
This commit is contained in:
travis laduke 2023-06-06 15:05:54 -07:00 committed by Travis LaDuke
parent 03841dcb81
commit 22ab673480

View File

@ -12,6 +12,7 @@
/****/ /****/
#include "../node/Constants.hpp" #include "../node/Constants.hpp"
#include "../osdep/OSUtils.hpp"
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
@ -94,6 +95,7 @@ struct _RTE
char device[128]; char device[128];
int metric; int metric;
bool ifscope; bool ifscope;
bool isDefault;
}; };
#ifdef __BSD__ // ------------------------------------------------------------ #ifdef __BSD__ // ------------------------------------------------------------
@ -127,6 +129,7 @@ static std::vector<_RTE> _getRTEs(const InetAddress &target,bool contains)
InetAddress sa_t,sa_v; InetAddress sa_t,sa_v;
int deviceIndex = -9999; int deviceIndex = -9999;
bool isDefault = false;
if (((rtm->rtm_flags & RTF_LLINFO) == 0)&&((rtm->rtm_flags & RTF_HOST) == 0)&&((rtm->rtm_flags & RTF_UP) != 0)&&((rtm->rtm_flags & RTF_MULTICAST) == 0)) { if (((rtm->rtm_flags & RTF_LLINFO) == 0)&&((rtm->rtm_flags & RTF_HOST) == 0)&&((rtm->rtm_flags & RTF_UP) != 0)&&((rtm->rtm_flags & RTF_MULTICAST) == 0)) {
int which = 0; int which = 0;
@ -160,6 +163,13 @@ static std::vector<_RTE> _getRTEs(const InetAddress &target,bool contains)
if (!sin6->sin6_scope_id) if (!sin6->sin6_scope_id)
sin6->sin6_scope_id = interfaceIndex; sin6->sin6_scope_id = interfaceIndex;
} }
#ifdef __APPLE__
isDefault = IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) && !(rtm->rtm_flags & RTF_IFSCOPE);
#endif
} else {
struct sockaddr_in *sin4 = (struct sockaddr_in *)sa;
isDefault = sin4->sin_addr.s_addr == 0;
} }
sa_t = *sa; sa_t = *sa;
break; break;
@ -167,8 +177,7 @@ static std::vector<_RTE> _getRTEs(const InetAddress &target,bool contains)
//printf("RTA_GATEWAY\n"); //printf("RTA_GATEWAY\n");
switch(sa->sa_family) { switch(sa->sa_family) {
case AF_LINK: case AF_LINK:
deviceIndex = (int)((const struct sockaddr_dl *)sa)->sdl_index; // deviceIndex = (int)((const struct sockaddr_dl *)sa)->sdl_index;
break;
case AF_INET: case AF_INET:
case AF_INET6: case AF_INET6:
sa_v = *sa; sa_v = *sa;
@ -211,10 +220,15 @@ static std::vector<_RTE> _getRTEs(const InetAddress &target,bool contains)
saptr += salen; saptr += salen;
} }
deviceIndex = rtm->rtm_index;
if (((contains)&&(sa_t.containsAddress(target)))||(sa_t == target)) { if (((contains)&&(sa_t.containsAddress(target)))||(sa_t == target)) {
rtes.push_back(_RTE()); rtes.push_back(_RTE());
rtes.back().target = sa_t; rtes.back().target = sa_t;
rtes.back().via = sa_v; rtes.back().via = sa_v;
rtes.back().isDefault = isDefault;
if (deviceIndex >= 0) { if (deviceIndex >= 0) {
if_indextoname(deviceIndex,rtes.back().device); if_indextoname(deviceIndex,rtes.back().device);
} else { } else {
@ -457,22 +471,35 @@ bool ManagedRoute::sync()
return false; return false;
} }
// Find lowest metric system route that this route should override (if any) std::vector<_RTE> rtes(_getRTEs(_target,false));
bool hasRoute = false;
for(std::vector<_RTE>::iterator r(rtes.begin());r!=rtes.end();++r) {
hasRoute = _target == r->target && _via.ipOnly() == r->via.ipOnly() && (strcmp(r->device,_device) == 0);
if (hasRoute) { break; }
}
if (!hasRoute) {
if (_target && _target.netmaskBits() == 0) {
InetAddress newSystemVia; InetAddress newSystemVia;
char newSystemDevice[128]; char newSystemDevice[128];
newSystemDevice[0] = (char)0; newSystemDevice[0] = (char)0;
int systemMetric = 9999999;
std::vector<_RTE> rtes(_getRTEs(_target,false)); // Find system default route that this route should override
// We need to put it back when default route is turned off
for(std::vector<_RTE>::iterator r(rtes.begin());r!=rtes.end();++r) { for(std::vector<_RTE>::iterator r(rtes.begin());r!=rtes.end();++r) {
if (r->via) { if (r->via) {
if ( ((!newSystemVia)||(r->metric < systemMetric)) && (strcmp(r->device,_device) != 0) ) { if ( !_systemVia && r->isDefault == 1 && (strcmp(r->device,_device) != 0) ) {
newSystemVia = r->via; newSystemVia = r->via;
Utils::scopy(newSystemDevice,sizeof(newSystemDevice),r->device); Utils::scopy(newSystemDevice,sizeof(newSystemDevice),r->device);
systemMetric = r->metric;
} }
} }
} }
if (!newSystemVia) { return false; }
// Get device corresponding to route if we don't have that already // Get device corresponding to route if we don't have that already
if ((newSystemVia)&&(!newSystemDevice[0])) { if ((newSystemVia)&&(!newSystemDevice[0])) {
rtes = _getRTEs(newSystemVia,true); rtes = _getRTEs(newSystemVia,true);
@ -483,44 +510,27 @@ bool ManagedRoute::sync()
} }
} }
} }
if (!newSystemDevice[0]) if (!newSystemDevice[0]) { return false; }
newSystemVia.zero();
// Shadow system route if it exists, also delete any obsolete shadows
// and replace them with the new state. sync() is called periodically to // update the system via in case it changed out from under us
// allow us to do that if underlying connectivity changes. // while we were in default route mode
if ((_systemVia != newSystemVia)||(strcmp(_systemDevice,newSystemDevice) != 0)) {
if (_systemVia) {
_routeCmd("delete",leftt,_systemVia,_systemDevice,(const char *)0);
if (rightt)
_routeCmd("delete",rightt,_systemVia,_systemDevice,(const char *)0);
}
_systemVia = newSystemVia; _systemVia = newSystemVia;
Utils::scopy(_systemDevice,sizeof(_systemDevice),newSystemDevice); Utils::scopy(_systemDevice,sizeof(_systemDevice),newSystemDevice);
if (_systemVia) { // Do the actual default route commands
_routeCmd("add",leftt,_systemVia,_systemDevice,(const char *)0); _routeCmd("delete",_target,_systemVia,(const char *)0,(const char *)0);
//_routeCmd("change",leftt,_systemVia,_systemDevice,(const char *)0); _routeCmd("add",_target,_via,(const char *)0,(const char *)0);
if (rightt) { _routeCmd("add",_target,_systemVia,_systemDevice,(const char *)0);
_routeCmd("add",rightt,_systemVia,_systemDevice,(const char *)0); _applied[_target] = true;
//_routeCmd("change",rightt,_systemVia,_systemDevice,(const char *)0); } else {
} // Do the actual route commands
_applied[_target] = true;
_routeCmd("add",leftt,_via,(const char *)0,(_via) ? (const char *)0 : _device);
} }
} }
if (leftt && !_applied.count(leftt)) {
_applied[leftt] = !_via;
//_routeCmd("delete",leftt,_via,(const char *)0,(_via) ? (const char *)0 : _device);
_routeCmd("add",leftt,_via,(const char *)0,(_via) ? (const char *)0 : _device);
//_routeCmd("change",leftt,_via,(const char *)0,(_via) ? (const char *)0 : _device);
}
if (rightt && !_applied.count(rightt)) {
_applied[rightt] = !_via;
//_routeCmd("delete",rightt,_via,(const char *)0,(_via) ? (const char *)0 : _device);
_routeCmd("add",rightt,_via,(const char *)0,(_via) ? (const char *)0 : _device);
//_routeCmd("change",rightt,_via,(const char *)0,(_via) ? (const char *)0 : _device);
}
#endif // __BSD__ ------------------------------------------------------------ #endif // __BSD__ ------------------------------------------------------------
@ -565,18 +575,22 @@ void ManagedRoute::remove()
#endif #endif
#ifdef __BSD__ #ifdef __BSD__
if (_systemVia) {
InetAddress leftt,rightt;
_forkTarget(_target,leftt,rightt);
_routeCmd("delete",leftt,_systemVia,_systemDevice,(const char *)0);
if (rightt)
_routeCmd("delete",rightt,_systemVia,_systemDevice,(const char *)0);
}
#endif // __BSD__ ------------------------------------------------------------ #endif // __BSD__ ------------------------------------------------------------
for(std::map<InetAddress,bool>::iterator r(_applied.begin());r!=_applied.end();++r) { for(std::map<InetAddress,bool>::iterator r(_applied.begin());r!=_applied.end();++r) {
#ifdef __BSD__ // ------------------------------------------------------------ #ifdef __BSD__ // ------------------------------------------------------------
_routeCmd("delete",r->first,_via,r->second ? _device : (const char *)0,(_via) ? (const char *)0 : _device); if (_target && _target.netmaskBits() == 0) {
if (_systemVia) {
_routeCmd("delete",_target,_via,(const char *)0,(const char *)0);
_routeCmd("delete",_target,_systemVia,_systemDevice,(const char *)0);
_routeCmd("add",_target,_systemVia,(const char *)0,(const char *)0);
}
} else {
_routeCmd("delete",_target,_via, (const char *)0, _via ? (const char *)0 : _device);
}
break;
#endif // __BSD__ ------------------------------------------------------------ #endif // __BSD__ ------------------------------------------------------------
#ifdef __LINUX__ // ---------------------------------------------------------- #ifdef __LINUX__ // ----------------------------------------------------------