Saving and loading custom settings for Network Extensions

Let's say we have a content filter app that lets the user block traffic to certain hosts.

When the app is running, it's simple to communicate the user's list of blocked hosts to the network extension through XPC.

But from the documentation, it's unclear to me how the extension should handle things after e.g. a reboot. If I understand correctly, the extension is loaded by macOS automatically, even with no user logged in yet. However, it's not clear what state is persisted. Probably none.

What would be the preferred method to reload the user's custom rules after a reboot, before the user logs in? Simply a file somewhere (where?) on disk that the extension opens and reads? Something more elegant? Or is XPC through the main app (and waiting for an user to log in) the preferred method?

Replies

When you mention:

app is running, it's simple to communicate the user's list of blocked hosts to the network extension through XPC.

It sounds like you mean through the container app that initially starts the Content Filter? If that is true, you will want to research another solution to provide the required information to the Network Extension. The reason for this being that the Network Extension and container app have very different process lifetimes, and this could cause an issue if you are relying on external information for your Network Extension to run.


Matt Eaton
DTS Engineering, CoreOS
meaton3@apple.com
Yes, finding another solution for providing the info was the idea. I don't want to rely on the container app for these kinds of things (even though it knows how to communicate with the extension for other reasons), if it can be avoided. But I wasn't sure how an extension is expected/allowed to handle things.

(And I am still not quite sure about the lifecycle details, as "The operating system will run your system extension as needed" from WWDC 2019 session 714 isn't super exact.)

But I'm probably overthinking this due to my brain still being in old school kernel extension land.

Maybe I should start thinking of network extensions like normal app code and simply put a config file under /Library/Application Support.

the operating system will run your system extension as needed

I believe what is meant here is that the operating system will handler the lifecycle of your System Extension. For example, starting and stopping the extension and ensuring that the extension is always running, even when a user is not logged in.

But I'm probably overthinking this due to my brain still being in old school kernel extension land. Maybe I should start thinking of network extensions like normal app code and simply put a config file under /Library/Application Support.

I think it's good when designing your application to consider the differences between the lifecycle of where and when your Network Extension runs compared to a container app. This will keep you from pitfalls like trying to share an app group with between the two etc...

The key thing to keep in mind is that if you need a helper application that works with your Network Extension, you will need to do it at the system level, like with a Daemon, and not in user space.

Matt Eaton
DTS Engineering, CoreOS
meaton3@apple.com

This will keep you from pitfalls like trying to share an app group with between the two etc...

Wait, what, sharing an app group is a pitfall?

Here's my current plan.

I have a firewall app that contains a network extension. The container app is used (by the user) for two things:
  1. Making changes to the firewall rules. The rules are written to disk, and the app sends a "hey, the rules were changed" XPC message to the extension when the user makes modifications. The extension also loads the rules when it starts up. This way, it should always be in sync.

  2. Inspecting some analytics about network traffic. When the container app is open (and the XPC connection is active), the extension "streams" some data back to the app. When the app is not open (and the user isn't actively interested), the analytics data doesn't need to be collected or streamed.

So, in normal day-to-day use, the container app isn't open, and the extension just does its content filtering job independently.

But while the app is open, the app and the extension can communicate through XPC. For this, I thought having them both in the same app group would be a good thing. Is this a pitfall and a mistake?




The rules are written to disk, and the app sends a "hey, the rules were changed" XPC message to the extension when the user makes modifications. The extension also loads the rules when it starts up. This way, it should always be in sync.

Why would the Network Extension have read access to the disk?


Wait, what, sharing an app group is a pitfall?

Your Network Extension and Container app will write to two different app groups. The major difference being that your Network Extension writes to an app group that is accessed at the system level.


Matt Eaton
DTS Engineering, CoreOS
meaton3@apple.com
Thanks for your answers and patience!

Your Network Extension and Container app will write to two different app groups.

Ah, I'm not expecting to use the app group containers for sharing files. I just have them in the same app group for easy XPC. So far, I haven't had any problems with that. I hope simply sharing an app group is not a mistake in itself, as long as I don't expect too much from it.


Why would the Network Extension have read access to the disk?

I tried it out and was surprised that the extension did have read access to the disk. But that brings me to the original question: what would be the preferred (and simplest) way to access persistent storage for a network extension? Is file access fine?

I wouldn't want to e.g. create an extra daemon unless it's actually necessary. In my experience, any moving part will fail when the product reaches actual customers and their devices. Disk access from an extension might feel a little dirty and weird, but does seem to work, and it's the simplest thing I can think of.

But working with system extensions is completely new to me. I have only worked with kernel extensions before. That's why I'm admittedly very unfamiliar with all this, and have silly questions. For example, regarding the disk access: should we do that, even though we can?