Running SimpleTunnel as MacOS app

I am attempting to learn more about the Network Extensions provided using the SimpleTunnel example since I am trying to develop a macOS per app vpn. The SimpleTunnel readme states "The SimpleTunnel OS X targets require the OS X 11.0 SDK or newer." I am new to XCode/swift and was wondering is that means that the SimpleTunnel example can be run as a MacOS app. If so, what exactly do I have to do in XCode to make it run. If not, is there an example of Network Extensions usage for a MacOS app?

Accepted Reply

SimpleTunnel does not include code for a macOS VPN client. However, the Network Extension provider architecture is available on macOS, and it is relatively straightforward to create a per-app VPN client (either an app proxy provider or a packet tunnel provider in per-app VPN mode) that shares the vast majority of its code between the two platforms.

IMPORTANT Not all Network Extension providers are supported on macOS. App proxy and packet tunnel providers are supported on both macOS and iOS. Content filter and DNS proxy providers are iOS only right now.

The SimpleTunnel readme states "The SimpleTunnel OS X targets require the OS X 11.0 SDK or newer."

This is referring to the

tunnel_server
target within the project, which builds a macOS command-line tool that acts as a VPN server that you can connect to using the SimpleTunnel iOS app.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Replies

SimpleTunnel does not include code for a macOS VPN client. However, the Network Extension provider architecture is available on macOS, and it is relatively straightforward to create a per-app VPN client (either an app proxy provider or a packet tunnel provider in per-app VPN mode) that shares the vast majority of its code between the two platforms.

IMPORTANT Not all Network Extension providers are supported on macOS. App proxy and packet tunnel providers are supported on both macOS and iOS. Content filter and DNS proxy providers are iOS only right now.

The SimpleTunnel readme states "The SimpleTunnel OS X targets require the OS X 11.0 SDK or newer."

This is referring to the

tunnel_server
target within the project, which builds a macOS command-line tool that acts as a VPN server that you can connect to using the SimpleTunnel iOS app.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Thanks, thats very helpful. I have one more question, can I use a configuration profile instead of NEPacketTunnelProviders to enable per app vpn mode? I seem to understand that using packet tunnel providers do the same thing as what a configuration profile does to enable per app vpn mode. Or am I supposed to use both of them together?

can I use a configuration profile instead of NEPacketTunnelProviders to enable per app vpn mode?

Neither )-: Well, it’s complex. To start, there are two aspects to this:

  • Configuring the per-app VPN itself (A)

  • Configuring apps to use the per-app VPN (B)

With regards A, in all cases you can configure the VPN via a configuration profile with the VPN payload (

com.apple.vpn.managed
). Additionally, for development builds (those with the
get-task-allow
entitlement) you can configure some VPN things using
NETunnelProviderManager
and its subclasses, although I’ve never actually tried to configure per-app VPN in this way.

With regards B, it depends on your platform and your deployment mechanism:

  • On iOS for development builds, you can configure an app to use the VPN using the

    NETestAppMapping
    property in your
    Info.plist
    .
  • On iOS for other builds, you must configure this mapping via MDM.

  • On macOS, regardless of how you deploy, you must configure these mappings using the App-to-Per-App VPN Mapping payload (

    com.apple.vpn.managed.appmapping
    ) in a configuration profile.

To summarise my recommendations:

  • On iOS, do your initial testing using a configuration profile and

    NETestAppMapping
    , and then do more in-depth testing using MDM.
  • On macOS, you can do all testing your testing using a configuration profile with the VPN and App-to-Per-App VPN Mapping payloads.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Oh okay, I see. So I have to do both A and B right? "A" configures the VPN and "B" configures apps to use the per app vpn client.


In terms of configuring "A" and "B" to the configuration profile, how do I add them to one configuration profile since both use two different values (com.apple.vpn.managed.applayer and com.apple.vpn.managed.appmapping) for the "PayloadType" key? Whats the correct structure? (Do I add another Dict to the PayloadContent key?)


Or do I install them as two seperate configuration profiles?

Or do I install them as two seperate configuration profiles?

That might work but it’s not what I recommend. If you have two closely related payloads, you should put them in the same profile. In some cases that’s actually required [1] but, even if it’s not, it’s best practice IMO.

how do I add them to one configuration profile

Profiles support multiple payloads. A good way to get a handle on how to structure this is to use Apple Configurator to create a test profile profile. It’s GUI makes it easy to create a profile with multiple payloads.

Unfortunately Apple Configurator does not support the App-to-Per-App VPN Mapping payload (

com.apple.vpn.managed.appmapping
), so you can only use this for guidance, not for the final task.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

[1] For example, when you have a profile that configures a third-party VPN client and includes a digital identity to be used by that client.

Awesome, thanks. In terms of the App-to-Per-App VPN Mapping payload array of dictionaries, I was unable to figure out how to obtain the DesignatedRequirement and SigningIdentifier values. So I am wondering how can I obtain these for the app that will use the per-app vpn?


Key

Type

Value

Identifier
StringThe app’s bundle ID.
VPNUUID
StringThe VPNUUID of the Per-App VPN defined in a Per-App VPN payload.
DesignatedRequirement
StringThe code signature designated requirement of the app that will use the per-app VPN.
SigningIdentifier
StringThe code signature signing identifier of the app that will use the per-app VPN.

In terms of the App-to-Per-App VPN Mapping payload array of dictionaries, I was unable to figure out how to obtain the

DesignatedRequirement
and
SigningIdentifier
values.

You can get these with the

codesign
tool. For example:
$ # DesignatedRequirement
$
$ codesign -d --requirements - /Applications/TextEdit.app
…
designated => identifier "com.apple.TextEdit" and anchor apple
$ 
$ # SigningIdentifier
$
$ codesign -d -v /Applications/TextEdit.app
…
Identifier=com.apple.TextEdit
…

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

How should I do if I want to get bundle identifier of an app on my iPhone?

The App-to-Per-App VPN Mapping payload isn’t supported on iOS. On iOS you have to set up these mappings via your MDM solution.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"