We have a PacketTunnelProvider
in a SystemExtension
with split tunneling. We are configuring a private IP address range of 240.0.0.1/10
as included routes and specifying a few matching domains using NEPacketTunnelNetworkSettings.
Once TunnelNetworkSettings has been applied successfully, a new utunx
interface is created, and it includes routes for the 240.0.0.1/10
IP range. In our case, the interface name is utun3
, where 'x' represents an integer value.
According to our business logic, we need to establish connections with some IPs from this range. To achieve this, we are utilizing the NWConnection
class API to create connections with IP addresses
Like this
func establishConnection() {
// Specify the destination host and port
let host = "240.0.0.19"
let port = 80
// Create an NWHostEndpoint
let endpoint = NWHostEndpoint(hostname: host, port: "\(port)")
// Create an NWConnection
let connection = NWConnection(to: endpoint, using: .tcp)
connection.start(queue: .global())
}
For the above code, we have observed different behaviour for IP packets when creating connections from different targets.
In the first case, when we create a connection to the IP address 240.0.0.19 from the Main app target
using the provided code, the IP packets correctly go through the utun3
interface because this address falls within the 240.0.0/10 range, which is part of the included routes.
However, in the second case, when we use the same code to create a connection to 240.0.0.19
from the Extension target
, the IP packets go through the primary interface en0
rather than the utun3
interface.
**Question : **
- Why do we have different behaviour for the same code?
- How can we achieve the same behaviour as the
Main app target
in theSystem Extension target
?
-- Thanks
Why do we have different behaviour for the same code?
Because Apple platforms have a subsystem called NECP that, amongst other things, works to prevent VPN loops. See A Peek Behind the NECP Curtain.
How can we achieve the same behaviour as the Main app target in the System Extension target?
The canonical way to achieve this goal is to use the legacy in-provider networking API and create a TCP connection using the createTCPConnectionThroughTunnel(to:enableTLS:tlsParameters:delegate:)
method.
This is annoying, because the in-provider networking API is not one of our preferred networking APIs. See TN3151 Choosing the right networking API for more on that. We already have a bug on file to provide a nice way to do this with NWConnection
(r. 100151093).
In the meantime, I think you’ll be able to set this up by explicitly binding your NWConnection
to your VPN interface with the requiredInterface
property.
I must admit to having never tried this myself )-:
Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"