Request from Network Extension bypassing the tunnel

Hey everyone! I have a Packet Tunnel Provider Network Extension and what I'm trying to do is to send a request from the Network Extension that will go via that tunnel. When I'm trying to do such a request in the main app, I can see in the PCAP that it's using the VPN's DNS server. When doing such a request from the Network Extension, the tunnel is bypassed. I've tried multiple requests:

  1. a regular data task via the URLSession.shared (with default configuration) with a hostname in the URL
  2. a regular data task via the URLSession.shared (with default configuration) with a bare IP address in the URL
  3. a DNS lookup via DNSServiceQueryRecord
  4. using a DNS resolve library that uses some sockets magic to resolve the DNS query - link to the library

setup:

Network Extension: Packet Tunnel; macOS: 12.6; Xcode 14.1

implementation:

I'm using the NEPacketTunnelFlow API to read and write the packets.

disclaimer:

I haven't tested this on iOS yet. But I would assume the network stack logic will be the same?

questions:

Is this an expected behavior? I think it kinda does make sense to me as a prevention that it won't end up in an infinite cycle. however, is there any way how to force the request to use the tunnel?

thank you in advance for any help!

Answered by Systems Engineer in 744632022

Is this an expected behavior? I think it kinda does make sense to me as a prevention that it won't end up in an infinite cycle. however, is there any way how to force the request to use the tunnel?

When making lower level connections in the Network Extension, use an API like NWTCPConnection or NWUDPSession, this will ensure that the traffic will traverse the tunnel instead of possibly the default route. See In-Provider Networking for more info. The downside of course here is that the APIs I mentioned above are not really suitable for HTTP, so just be aware of that as you proceed.

Accepted Answer

Is this an expected behavior? I think it kinda does make sense to me as a prevention that it won't end up in an infinite cycle. however, is there any way how to force the request to use the tunnel?

When making lower level connections in the Network Extension, use an API like NWTCPConnection or NWUDPSession, this will ensure that the traffic will traverse the tunnel instead of possibly the default route. See In-Provider Networking for more info. The downside of course here is that the APIs I mentioned above are not really suitable for HTTP, so just be aware of that as you proceed.

Matt already explained the way forward here but I want to answer this explicitly:

Is this an expected behavior?

Yes, and for the reasons you theorised: To prevent VPN loops, standard network connections will go directly, not via your tunnel. You can opt in to sending them via your tunnel in the way that Matt described.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Request from Network Extension bypassing the tunnel
 
 
Q