-
Notifications
You must be signed in to change notification settings - Fork 1.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
net/interfaces: handle iOS network transitions when exit node in use (ENG-2507) #10680
net/interfaces: handle iOS network transitions when exit node in use (ENG-2507) #10680
Conversation
This may be a very specific use case, but what would happen in the case of a USB to Ethernet adapter? I don't frequently use one, but I have done it before. If there was a way to incorporate support for those without much additional effort, that would be awesome. If not, I understand, this seems to be an Apple problem in the first place. |
Thanks for the suggestion. We lack logic for that. We should look at all |
I feel like this is re-inventing the wheel. Might be better to observe |
Bluetooth PAN is probably somewhere in there too, which isn't a problem on iPhones (as originators of Personal Hotspot), but on iPads where people might use Bluetooth to connect to their iPhone it could be prevalent. |
Precisely. I spent the morning looking into how we can ask iOS for the right interface to use instead of making a decision on our end, because I'm concerned about edge cases like that. I'll likely scrap this entire PR and see if we can observe NWPathMonitor updates from our Swift code instead, which is the Apple-sanctioned way to do this. We couldn't use this before because we had to support older versions of macOS and iOS where that wasn't available. But it is no longer an issue now. |
That would make sense... Thank you again for looking into this! |
I’m seeing this issue. Any eta when this change will go live? |
2d1f1cd
to
7d9565a
Compare
I refactored the logic here. We now have a The logic here that hard-codes |
7d9565a
to
8c064a4
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good, just a couple style nits.
8c064a4
to
92c2683
Compare
Updates #8022 Updates #6075 On iOS, we currently rely on delegated interface information to figure out the default route interface. The NetworkExtension framework in iOS seems to set the delegate interface only once, upon the *creation* of the VPN tunnel. If a network transition (e.g. from Wi-Fi to Cellular) happens while the tunnel is connected, it will be ignored and we will still try to set Wi-Fi as the default route because the delegated interface is not getting updated as connectivity transitions. Here we work around this on the Swift side with a NWPathMonitor instance that observes the interface name of the first currently satisfied network path. Our Swift code will call into `UpdateLastKnownDefaultRouteInterface`, so we can rely on that when it is set. If for any reason the Swift machinery didn't work and we don't get any updates, here we also have some fallback logic: we try finding a hardcoded Wi-Fi interface called en0. If en0 is down, we fall back to cellular (pdp_ip0) as a last resort. This doesn't handle all edge cases like USB-Ethernet adapters or multiple Ethernet interfaces, but it is good enough to ensure connectivity isn't broken. I tested this on iPhones and iPads running iOS 17.1 and it appears to work. Switching between different cellular plans on a dual SIM configuration also works (the interface name remains pdp_ip0). Signed-off-by: Andrea Gottardo <andrea@tailscale.com>
92c2683
to
aeef46e
Compare
Fixes ENG-2507
Updates #8022
Updates #6075
On iOS, we currently rely on delegated interface information to figure out the default route interface. When an exit node is being use, our
utun*
interface is the default route, so we ask the system for the delegated interface for theutun*
interface we use. The NetworkExtension framework in iOS seems to set the delegate interface only once, upon the creation of the VPN tunnel. If a network transition (e.g. from Wi-Fi to Cellular) happens while the tunnel is connected, it will be ignored and we will still try to set Wi-Fi as the default route because the delegated interface is not getting updated as connectivity transitions.Here, we special-case iPhones and iPads with a simpler logic that doesn't look at the routing table: we try finding a hardcoded Wi-Fi interface called
en0
, if it doesn't have an address, we fall back to cellular, which ispdp_ip0
. This logic can safely run every time a link change is detected.I tested this on iPhones and iPads running iOS 17.1 and it appears to work. Switching between different cellular plans on a dual SIM configuration also works (the interface name remains
pdp_ip0
).To-Dos