Starting PacketTunnelProvider before login

Hi,

We are developing an app using PacketTunnelProvider from Network Extension framework. It is packaged as a system extension.

We are trying to implement an "always-on" functionality, but cannot manage to start the extension before user login, with or without on-demand enabled.

However we see in other posts (1, 2) that a network extension packaged as sysex should automatically start before user login.

Are we missing something? Is it a limitation of PacketTunnelProvider?

Thanks

Answered by DTS Engineer in 821421022

Regarding the on-demand rules, I was curious why your rules weren’t working so I talked with the NE team about this. Apparently VPN On Demand is only intended to work when a user is logged in. I can see how that makes sense — this feature originated on iOS — but it means that your setup won’t work reliably.

Written by fparat in 821412022
It seems that the daemon program must be run as the first user of the Mac.

Yeah, I think that’s an accident of the implementation rather than a deliberate plan.

My advice right now is that you file an enhancement request asking for official support for this setup. Make sure to include details about why you want to do this.

Once you’re done, please post your bug number, just for the record.

As to what you can do right now, does you scutil command work when you invoke it from a global context? That is, a launchd daemon running as root? I suspect it might not but, if it does, that’s probably the best workaround.

Share and Enjoy

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

You need to be careful about your definition of “before login”. Specifically:

  • If you Mac has FileVault enabled, and

  • You restart it

then that initial login UI is presented by FileVault’s pre-boot environment. No third-party code can run at at that time.

Share and Enjoy

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

Hi,

I forgot to mention that I tried with FileVault disabled.

To further explain my testing process: I install the app in a VM, open it to activate the extension and add a VPN configuration. I then try to connect to the VM after reboot with SSH and Remote Management on the VPN IP address.

I can connect before UI login using the Ethernet interface IP, and even force the VPN on with scutil --nc start, which make the VPN IP accessible, but it kind of defeat the point of the "always-on" functionality.

Written by fparat in 820221022
I connect before UI login using the Ethernet interface IP

Can you explain the “Ethernet” in that quote? Is it just that this Mac is using Ethernet as its primary interface? Or is there some Ethernet / Wi-Fi subtlety in play?

Share and Enjoy

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

Yes I mean the primary interface, which happen to be Ethernet in this case

Thanks for clarifying that. However, that just leads to a follow-up question. You wrote:

Written by fparat in 820221022
I connect before UI login using the [primary] interface IP

What does that mean? What are you connecting? And how does the primary interface IP come into play?

Share and Enjoy

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

I just use the primary interface for diagnostic.

My main problem is how to start my tunnel before any user login on the UI (assuming FileVault is disabled). The use case is to be able to remotely, securely, and reliably access the Mac through the tunnel. You could call this feature "always-on", "server mode", or "unattended mode".

To test if this feature works, I try to connect with SSH on the VPN IP. I cannot connect, so for purpose of experimentation, I try to connect with SSH on the primary interface IP, where I find out with scutil --nc list that my tunnel is disconnected, and that I can start it with scutil --nc start and then connect with SSH on the VPN IP. Without logging in on the UI.

So, I, as a developer, used the primary interface to find out that in theory the system might be able to automatically start the tunnel on boot before user login, but for the end use-case this primary interface may not be reachable.

So now I wonder, why can't the tunnel start itself on boot? Am I using it wrong? Is it a missing feature, a technical limitation, or a restriction that exists on purpose? I am especially confused because in the posts I linked in my first message, it is said that "a Network System Extension on macOS is started when the system starts", and that "network extension [will] run before user session".

Written by fparat in 820529022
To test if this feature works, I try to connect with SSH on the VPN IP.

So you’re testing incoming connections?

Share and Enjoy

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

Yes, and with firewall disabled

Ah, thanks for clarifying that. I was barking up the wrong tree entirely.

The standard ways for bringing up VPN [1] are:

  • Manually

  • On demand

On demand only supports local demand; there’s no way to set it up to trigger on incoming demand.

What do your on-demand rules look like?

Share and Enjoy

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

[1] There’s also Always On VPN, but it’s currently limited to the built-in IKEv2 transport (r. 21363342).

The rules connect on any interface match. Relevant code extract:

let ruleInterface = NEOnDemandRuleConnect()
ruleInterface.interfaceTypeMatch = .any
manager.onDemandRules = [
ruleInterface
]
manager.isOnDemandEnabled = true

Your remarks about incoming demands made me try some tests.

I made a system launchd daemon that would periodically send packets to an IP within the VPN network.

ICMP pings didn't work, but TCP connections (using netcat) would in fact make the tunnel connect without any GUI login!

There are some caveats though. It seems that the daemon program must be run as the first user of the Mac. The tunnel wouldn't try to start if the program is run as root or as a second user (admin or not).

Do you have some insights about this or other ideas?

Thanks

Accepted Answer

Regarding the on-demand rules, I was curious why your rules weren’t working so I talked with the NE team about this. Apparently VPN On Demand is only intended to work when a user is logged in. I can see how that makes sense — this feature originated on iOS — but it means that your setup won’t work reliably.

Written by fparat in 821412022
It seems that the daemon program must be run as the first user of the Mac.

Yeah, I think that’s an accident of the implementation rather than a deliberate plan.

My advice right now is that you file an enhancement request asking for official support for this setup. Make sure to include details about why you want to do this.

Once you’re done, please post your bug number, just for the record.

As to what you can do right now, does you scutil command work when you invoke it from a global context? That is, a launchd daemon running as root? I suspect it might not but, if it does, that’s probably the best workaround.

Share and Enjoy

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

does you scutil command work when you invoke it from a global context? That is, a launchd daemon running as root?

It actually does! Directly using scutil would indeed be less messy than hacking with netcat.

It seems that this would be the best workaround currently. Meanwhile I created the feedback for an official support: FB16332789

Thanks for your time!

Starting PacketTunnelProvider before login
 
 
Q