Hi, I have a VPN product for macOS. When activated, it creates a virtual interface that capture all outgoing traffic for the VPN. the VPN encrypt it, and send it to the tunnel gateway. The gateway then decapsulates the packet and forwards it to the original destination.
To achieve this, The vpn modifies the routing table with the following commands:
# after packets were encoded with the vpn protocol, re-send them through
# the physical interface
/sbin/route add -host <tunnel_gateway_address_in_physical_subnet> <default_gateway> -ifp en0 > /dev/null 2>&1
# remove the default rule for en0 and replace it with scoped rule
/sbin/route delete default <default_gateway> -ifp en0 > /dev/null 2>&1
/sbin/route add default <default_gateway> -ifscope en0 > /dev/null 2>&1
# create new rule for the virtual interface that will catch all packets
# for the vpn
/sbin/route add default <tunnel_gateway_address_in_tunnel_subnet> -ifp utunX > /dev/null 2>&1
This works in most cases. However, there are scenarios where the VPN process may crash, stop responding, or another VPN product may alter the routing table. When that happens, packets may no longer go out through the correct interface.
Question: Is there a way to reliably reconstruct the routing table from scratch in such scenarios? Ideally, I would like to rebuild the baseline rules for the physical interface (e.g., en0) and then reapply the VPN-specific rules on top. Are there APIs, system utilities, or best practices in macOS for restoring the original routing configuration before reapplying custom VPN routes?
Thanks
I have a VPN product for macOS.
It sounds like your VPN product isn’t based on the Network Extension (NE) provider architecture. Is that right?
If so, there’s not much I can do to help you out here. On macOS the routing table is ‘owned’ by system infrastructure. You can’t safely modify it behind the system’s back. If you do, you’ll run into all sorts of weird problems.
This has been true since the dawn of Mac OS X but, historically, you had to bend the rules to create a VPN product. That’s not been the case since we introduced support for NE providers back in macOS 10.11. At that point DTS stopped supported such shenanigans; we now only support VPN products based on the NE provider architecture.
This year at WWDC the NE team went out of their way to clarify their position on this. See WWDC 2025 Session 234 Filter and tunnel network traffic with NetworkExtension, starting at 7:26.
Oh, and if you are using an NE provider and NE is failing to restore the routine table properly, please do let me know. That should just happen automatically.
Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"