Packet Tunnel Provider with Per App VPN debugging

We have a vpn app which uses PacketTunnelProvider. We also support per-app vpn for iOS, I need help with debugging steps for an issue I am facing recently. In the per app vpn, we have split tunneling: some urls should be tunneled while others should be direct, for tunneled urls/ips everything is working as expected. But for "direct" resources, I am facing an issue where sometimes I don't get an ACK back from the browser. Leading to a series of retransmissions and eventually the direct website not loading.

Some more points of data: we do get true for the writePackets call, which seems to mean that the vpn app did write the packets to the TUN interface, but we don't get an ACK from the browser. I want some way of debugging this further so I can check if the browser actually got the packets. I also suspect that there might be a loop with packets (we are reading the packets we just wrote onto TUN), but can't say for sure since the issue is intermittent, in case of a loop, I would expect it to always help.

Any help would be greatly appreciated.

Answered by DTS Engineer in 838427022
In the per app vpn, we have split tunneling

That’s not something you can implement:

  • In per-app mode (NETunnelProviderRoutingMethod.sourceApplication) traffic is routed to your provider based on the source application.

  • Once traffic is routed to your provider it’s responsible for getting it to its destination.

There’s no mechanism to enable per-app VPN but only handle some of the app’s traffic.

Share and Enjoy

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

In the per app vpn, we have split tunneling

That’s not something you can implement:

  • In per-app mode (NETunnelProviderRoutingMethod.sourceApplication) traffic is routed to your provider based on the source application.

  • Once traffic is routed to your provider it’s responsible for getting it to its destination.

There’s no mechanism to enable per-app VPN but only handle some of the app’s traffic.

Share and Enjoy

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

Hey Quinn, that was explaining the setup, split tunneling is implemented at a logical level. The issue we are facing is around debugging the situation once we actually write packets to the TUN interface.

The issue we are facing is around debugging the situation once we actually write packets to the TUN interface.

I’ve never spent a lot of time debugging this. My experience is that it works well as long as you follow the rules.

To start, it’s important not to think of this as a TUN interface. It’s a packet flow. You write packets to it by calling writePacketObjects(_:) [1]. I see a lot of developers try to extract a TUN file descriptor and manipulate that directly. That’s not supported.

Second, the interface has an IP address that’s assigned by your packet tunnel when you call setTunnelNetworkSettings(_:completionHandler:). Your VPN tunnel should be giving you packet destined for that IP address. When you write packets to the packet flow, they enter the TCP/IP stack from below and are distributed to the relevant app based on the protocol type and local address and port.

I regularly see folks try to use the flow to reinject packets back into the stack. That is, they’re using a packet tunnel provider for something other than VPN. That requires them to reject certain TCP or UDP flows — something this is all TCP and UDP flows — and they think they can do that by calling writePacketObjects(_:) on the packet flow. That’s simply not supported. I’ve seen folks make it work in some cases, but that just muddies the waters because it’ll work, then fail, then work, depending on hard-to-predict circumstances.

Share and Enjoy

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

[1] Or the older writePackets(_:withProtocols:).

Packet Tunnel Provider with Per App VPN debugging
 
 
Q