I am developing a VPN app that uses Network Extension and Wireguard protocol on Ventura (13.4). I am testing the following scenario:
- Connect my Mac to WiFi (en0 = index 16) and to an iPad (via USB-C) which works as hotspot (en11 = index 26).
- Make sure in System Settings that WiFi is before iPad hotspot in Service order
- Connect to the VPN client (utun3 = index 28 is created)
- Disable WiFi
When I disable WiFi I lose access to the internet. To regain the internet access on a new interface I need to restart the tunnel completely. From a user perspective, on a Mac it seems fine, but on an iOS device it feels like suboptimal solution - the user might frequently move between WiFi/cellular connectivity and we need to reestablish VPN connection every time the default interface changes (I tested that scenario as well and it behaves exactly the same as on macOS).
So far I have implemented a workaround to avoid such reconnection, and in our tunnel implementation I use good, old bind
to rebind our tunnel socket (UDP) to the primary interface (en0/en11).
I checked the NECP logs for more details, and in a scenario, when I don't use the custom bind
, I see that some rules are created which seem to be skipped:
2023-06-27 08:53:25.277090+0200 0x43e4a5 Error 0x0 0 0 kernel: necp_socket_find_policy_match_with_info_locked: DATA-TRACE <SOCKET <private>>: MATCHED POLICY - proto 17 port <local 64002/64002 remote 0/0> <drop-all order 9001> <pid=73678 Application 66744 Real Application 66744 BoundInterface 26> (policy id=29157 session_order=2002 policy_order=10802 result=IP_TUNNEL)
2023-06-27 08:53:25.277097+0200 0x43e4a5 Default 0x0 0 0 kernel: necp_socket_find_policy_match: Socket Policy: <private> (BoundInterface 26 Proto 17) Policy 29157 Skip 10494 Result 6 Parameter 26
My application PID is 73678 and iPad hotspot network interface (en11) is 26. To me it looks like the packets which are supposed go to the en11 interface are skipped.
Is this expected/desired behavior, that while changing network interfaces, the tunnel should be completely restarted?