I've spent a long time figuring out some of the intricacies of filtering NEFilterFlow objects, and working out the (fairly difficult) IPC communication between the system extension and the containing app. I have the app in a state now where it is not ready for distribution in the app store, but is ready for validation on a select number of internal test machines.
And here I must confess my almost total ignorance of many of the complexities in this realm. I've never built a macOS app before, and I only have one iOS app in the app store, and that was a much simpler use case (built with React Native, no tricky system extension stuff, and I leveraged TestFlight for testing with that app). So, I fully believe I might be making some total noob mistake here. I can say I've poured over these forums for hours trying lots of things, and I'm really stumped, and would greatly appreciate some detailed help here. 🙏
The problem
Anyway, the problem I'm having is that when I try to get the app to run on another Mac, I can't successfully get the system extension to install. I'll describe the error (as best I can understand it) directly below, and then further down give more information as to how I'm preparing the test application, since the problem might lie there.
When I try to activate the system extension from the containing app on a test machine, the activation requests succeeds far enough to prompt me to grant permission to install the extension, and when granted, it pops up the purple "(Redacted) would like to filter internet content". When I click "allow", however, the system extension shows up orange in the Network pref pane, labeled "not running." Pouring over the console logs, these two seem to be the most likely to shed light:
Code Block (neagent) Failed to find a com.apple.networkextension.filter-data extension inside of app com.acmecorp.product
and:
Code Block (nesessionmanager) com.acmecorp.product[3656]: Tearing down XPC connection due to setup error: Error Domain=NEAgentErrorDomain Code=2 "(null)"
I've inspected the contents of the app, and the system extension is properly packaged with the app. I built the SimpleFirewall app and compared the packaged app directory, and the file structure seems basically identical -- the system extension executable definitely is there. I put in a bunch of os_logs during the filter activation lifecycle process, logging out the bundle main url of the system extension, and it all seems correct, and seems to be pointing to files on the filesystem that exist. Also, I do get this encouraging log during the failing activation process:
Code Block (sysext) Realizing target path: file:///Applications/MyApp.app/Contents/Library/SystemExtensions/com.acmecorp.product.systemextension/
Which has the correct file url, and seems to be indicating that the path to the extension was indeed found. But the extension just stays stuck orange, dead, no IPC communication succeeds, and I have to manually remove it from the Network prefs pane.
I've never had the problem building and running locally on the development machine from the derived data dir from Xcode.
How I'm testing
Since the problem might lie here, I'll describe how I'm getting the app over to the target test machine (which is a physical device, not a VM). Nothing super fancy -- I basically am just going to "Product" > "Archive" from within Xcode and creating an .xcarchive file. I then "show package contents", zip up the app file, and send it to the target machine, where I install it in the /Applications dir.
I did spend a long time figuring out how to add the UUID of the target machine to the provisioning profile before I could even get the container app to load. But I got that figured out and (as described above) the container app loads perfectly, it's only the system extension activation request that fails.
So... Can anyone lend me a hand? Am I going about trying to test correctly? Should I be creating the test app package some other way? Or is my (admittedly crude) method OK, and is it likely the problem lies in how I'm archiving or how the build is setup? Can anyone shed any light on the error?
Am I wrong in thinking that if it builds and runs correctly from Xcode on the dev machine, and I drag the app bundle over to another machine, it should run there too, assuming the test machine is in the provisioning profile, which it is? (Both machines are running Catalina, btw).
Thanks in advance!
I did a quick test of your workflow locally; archiving and exporting a development copy of a local content filter I maintain with a Network System Extension. From there I copied this development signed app to another local development machine. In this case I built on 10.15 and copied to a 11.0 machine for testing. On my 11.0 machine I moved the development app into /Application directory, logged the subsystems running in the container app and in the Network System Extension and was able to see everything running as usual. Now, this only works because like you mentioned, both machines are contained in the provisioning profile that was used to sign the development copy of the app and the Network System Extension. This is roughly equivalent to two members of your development team working together to develop and test locally.
Typically you would test this workflow with a distribution signed copy of your app. For this, you will need to create a Developer ID certificate and signing identity. From there you will need to change your content-filter-provider key to content-filter-provider-systemextension (see more here) and then Developer ID sign and Notarize your app to be distributed for testing.
Having said that above, the logs that you have provided do indicate that there is something wrong in your configuration and possibly the loading of the Network System Extension:
I would concentrate on this side of communication between apps. If you need to, try removing the IPC connection between apps and see if your are able to at least initiate your Network System Extension, and that way you know where to focus your debugging.(neagent) Failed to find a com.apple.networkextension.filter-data extension inside of
app com.acmecorp.product
Code Block
(nesessionmanager) com.acmecorp.product[3656]: Tearing down XPC connection due to setup
error: Error Domain=NEAgentErrorDomain Code=2 "(null)"
If you find that you are unable to come to a resolution here, open a TSI and either myself or Quinn will take a closer look.
Matt Eaton
DTS Engineering, CoreOS
meaton3@apple.com