Per App VPN detection on iOS

Hello!

Is it possible to read Per App VPN config from a managed app and manually send request to the proxy app on iOS?

I'm working on a cross-platform app which uses socket to do the networking. It handles proxy itself by reading

CFNetworkCopySystemSettings()

However, since Per-App VPN is not applied system wide, the available keys for iOS in 'Global Proxy Settings Constants' aren't present in the return value. As a result the app ignores the Per App VPN and sent requests directly.

By printing out the return value, I saw a hidden __SCOPED__ key, it seems when a proxy is running, other than eth0, there will be another interface like utun2 listed there. Can I use that to read Per App VPN config?

If you’re using a low-level networking API and want to honour the system proxy settings then it’s best to use CFNetworkCopyProxiesForURL.

Keep in mind that the result of this may be a requirement to run a PAC script. You can do this using CFNetworkExecuteProxyAutoConfigurationURL.


This is one of the reasons why we encourage folks to adopt Network framework (-: Once you start adding all the goo necessary to get your ‘cross-platform’ BSD Sockets working well in the challenging network environments encountered by iOS, you’ll find that you’ve written more code than you’ve saved. It is better, IMO, to refactor your cross-platform code to use a higher-level of abstraction. You can then fulfil that abstraction with your existing BSD Sockets code on other platforms and Network framework code on Apple ones.


Having said that, I don’t think any of this is necessary to handle the per-app VPN case. In per-app VPN the system snags your network connections at a higher-level; it doesn’t rely on the app supporting proxies properly. What has caused you to start down this path?

Share and Enjoy

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

We are downstream developers and the upstream uses socket, so naturally we are using it. The project is relatively huge so if not necessary we hope that we can avoid refactoring the network code.

OK. But be aware that this means:

  • Your BSD Sockets code must be very well written to handle all the various networking scenarios encountered by iOS devices.

  • There are some things that it just won’t be compatible with.

This post has more details.

Is there anyway that we can detect and send requests to the per-app VPN app, I assume the per-app VPN app still listens on certain port?

You’ve misunderstood how per-app VPN works. The per-app VPN system does not listen on ports. Rather, when you enable per-app VPN, the system intercepts all network requests in the networking stack [1] and redirects them to the VPN. There’s no need to explicitly support this in your app, regardless of what networking API it uses.

There’s a good high-level discussion of this in WWDC 2015 Session 717 What’s New in Network Extension and VPN.

Share and Enjoy

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

[1] For app proxy, it does this above the TCP level. For a packet tunnel in per-app VPN mode, it does this at the IP level.

My current understanding is that

No. In both cases the app’s network traffic is routed to the per-app VPN Network Extension provider. The difference between app proxy and packet tunnel (in per-app VPN mode) is where the traffic is intercepted, not whether the traffic is intercepted. From an app developer’s point of view’ that’s irrelevant [1].

Share and Enjoy

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

[1] It’s really important for the NE provider because it determines whether they receive TCP flows or IP packets. Which is better for them depends on the on-the-wire protocol supported by their VPN.

But because of the layer difference, if my app uses BSD socket, and the traffic happens between the app proxy layer and packet tunnel layer, effectively the traffic is not intercepted by app proxy provider, but is intercepted by packet tunnel provider right?

No. The traffic interception mechanism exists within the kernel [1] and applies regardless of how the traffic was generated.

Share and Enjoy

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

[1] In reality there’s some subtlety here. Back when per-app VPN was introduced, all networking was done within the kernel and that’s how WWDC 2015 Session 717 describes things. Since then we’ve introduced a user-space networking stack. BSD Sockets always talks to the kernel networking stack. Network framework, and things layered on top of it, can talk to either the kernel or the user-space networking stack depending on the configuration. However, when we added the user-space networking stack we also added the appropriate interception points for per-app VPN so, in practice, it doesn’t matter which API you use.

back soon

can I take this as both NEAppProxyProvider and NEPacketTunnelProvider can intercept all network traffic from my app even if my app is using BSD socket to do all the networking … ?

Yes.

including DNS resolution

A word of caution here:

  • If you’re doing DNS resolution via system APIs — and if you’re working at the BSD Socket level then I generally recommend getaddrinfo — then you’re all set.

  • If you’re implementing your own resolver — that is, you have code that sends UDP packets to port 53 — then I strongly recommend that you not do this on Apple platforms. It guarantees that you’ll be incompatible with various iOS networking scenarios.

    If you think you need to use your own resolver, please post an explanation of your rationale here and I can point you in the right direction. For example, many folks implement their own resolver because they need async support, but you can do that on Apple platforms using DNSServiceGetAddrInfo.

Share and Enjoy

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

Per App VPN detection on iOS
 
 
Q