How to suppress Allow/DontAllow popup when we call filterManager.saveToPreferences?

Hi, I have Content Filter Simple Firewall example from Apple site and modified as per my requirement and I able to compile & run with my developer id account.

As part of NE activation request, throwing the Allow/Don't Allow popup after allowing the NE from security preferences. When I went through the code I got to know that this popup is getting from filterManager.saveToPreferences as part of activation request. Attached the screen shot for reference. How to suppress this allow/disallow popup? Please help me.

Is there any way to Allow by default without any Popup after allowing from security preferences?

How to suppress this allow/disallow popup?

With standard APIs, no. This would be an Enhancement Request. If you are using MDM then there is an opportunity to auto-allow this using the com.apple.webcontent-filter payload. This should be possible by setting the FilterType to "Plugin" and setting PluginBundleID to the bundle identifier of the app.

Matt Eaton
DTS Engineering, CoreOS
meaton3@apple.com

One more doubt, If I reboot the machine without providing the response like Allow/Don'tAllow which is shown in the above popup then by default considering as Allow without generating the popup again after machine up. Is there any way to generate the popup again after machine up?

Thanks.

If I reboot the machine without providing the response like Allow/Don'tAllow which is shown in the above popup then by default considering as Allow without generating the popup again after machine up. Is there any way to generate the popup again after machine up?

Are you saying that your Network Configuration has defaulted to being active when the machine is rebooted even though no-one actually activated and allowed it?

If so, do you have any OnDemandRules that are activating your provider?

Matt Eaton
DTS Engineering, CoreOS
meaton3@apple.com

Here two cases are there.

Case 1: NE was activated but chosen DontAllow option from the popup as shown below.
As part of bootstrap, we are trying to save the preferences for the popup if filtermanger object is available & Not Allowed. But the Allow/Don'tAllow popup is not coming and configuring with Allow automatically.

Case2: NE was activated but not chosen any option from the popup as shown below. Whenever machine is rebooting, preferences are saving with Allow automatically at downtime and extension is running after machine is up.

Code snippet to save the preferences:

      NEFilterManager.shared().isEnabled = true
      NEFilterManager.shared().saveToPreferences { serror in
        DispatchQueue.main.async {
          if let error = serror {
            exit(Controller.ReturnCodes.saveConfFailed.rawValue)
          }
          exit(Controller.ReturnCodes.success.rawValue)
        }
      }

I have one doubt. If we activate the NE before user login and if we wont choose any option from the above popup then automatically considering as Allow after user login into the machine. Is this intentional?

Case2: NE was activated but not chosen any option from the popup as shown below. Whenever machine is rebooting, preferences are saving with Allow automatically at downtime and extension is running after machine is up.

The fact that the Network System Extension is alive makes sense in this case, but having the Network Configuration being active does not (Unless there are OnDemandRules activating it). If the provider is receiving flow data in handleNewFlow you may want to open a TSI on this so that it can be looked at further. Please provide a sample project if you open a TSI.

Regarding:

Case 1: NE was activated but chosen DontAllow option from the popup as shown below. As part of bootstrap, we are trying to save the preferences for the popup if filtermanger object is available & Not Allowed. But the Allow/Don'tAllow popup is not coming and configuring with Allow automatically.

I'm don't think I am understanding what your workflow is here. You are not trying to automatically activate the Network Configuration if the user has disallowed the prompt are you?

Matt Eaton
DTS Engineering, CoreOS
meaton3@apple.com

Regarding: Case 1: NE was activated but chosen DontAllow option from the popup as shown below. As part of bootstrap, we are trying to save the preferences for the popup if filtermanger object is available & Not Allowed. But the Allow/Don'tAllow popup is not coming and configuring with Allow automatically.

I'm don't think I am understanding what your workflow is here. You are not trying to automatically activate the Network Configuration if the user has disallowed the prompt are you?

No, I want to keep the NE state as previous like 'Dont'Allow'. But NE is allowing without any user action after rebooting the machine. This is not expected behaviour.

Here, we want to confirm from the user to Allow/DontAllow the NE after machine reboot. So, we were added functionality like NEFilterManager.shared().saveToPreferences for the popup to decide if user did not allow the NE for filtering previously. But this is not giving popup and allowing by default. Here NEFilterManager.shared().saveToPreferences is calling before user login into the machine.

One more point, If we call NEFilterManager.shared().saveToPreferences after user login into the machine then popup is coming to Allow/DontAllow. But, If I call this before user login into the machine then popup is not coming & NE is allowing by default.

Is this expected behaviour?

Below is the sample code to start the NE and startFilter() is API to activate & Allow the NE.

class Controller: NSObject {
    @objc func startFilter() -> NSNumber {
        current_cmd = .start
        if NEFilterManager.shared().isEnabled {
            exit(Controller.ReturnCodes.success.rawValue)
        }
        if NEFilterManager.shared().providerConfiguration != nil {
            NEFilterManager.shared().isEnabled = true
            NEFilterManager.shared().saveToPreferences { serror in
                DispatchQueue.main.async {
                    if let error = serror {
                        os_log("Error is saving NE configuration %@", error.localizedDescription)
                        exit(Controller.ReturnCodes.saveConfFailed.rawValue)
                    }
                    exit(Controller.ReturnCodes.success.rawValue)
                }
            }
        }
        else {
            guard let extensionIdentifier = extensionBundle.bundleIdentifier else {
                os_log("failed to get the bundleidentified before activation request")
                return NSNumber(value:Controller.ReturnCodes.invalidBundleIdentifier.rawValue)
            }
            let activationRequest = OSSystemExtensionRequest.activationRequest(forExtensionWithIdentifier: extensionIdentifier, queue: .main)
            activationRequest.delegate = self
            OSSystemExtensionManager.shared.submitRequest(activationRequest)
        }
        return NSNumber(value: Controller.ReturnCodes.procStillRunning.rawValue)
        
    }
  
    // MARK: Content Filter Configuration Management
    func enableFilterConfiguration() {
        let filterManager = NEFilterManager.shared()

        if filterManager.providerConfiguration == nil {
            let providerConfiguration = NEFilterProviderConfiguration()
            providerConfiguration.filterSockets = true
            providerConfiguration.filterPackets = false
            //providerConfiguration.filterBrowsers = false
            filterManager.providerConfiguration = providerConfiguration
            if let appName = Bundle.main.infoDictionary?["CFBundleName"] as? String {
                filterManager.localizedDescription = appName
            }
        }

        filterManager.isEnabled = true

        filterManager.saveToPreferences { saveError in
            DispatchQueue.main.async {
                if let error = saveError {
                    os_log("Failed to save the filter configuration: %@", error.localizedDescription)
                    exit(Controller.ReturnCodes.saveConfFailed.rawValue)
                }
                exit(Controller.ReturnCodes.success.rawValue)
            }
        }
    }
}

extension Controller: OSSystemExtensionRequestDelegate {

    // MARK: OSSystemExtensionActivationRequestDelegate

    func request(_ request: OSSystemExtensionRequest,didFinishWithResult result: OSSystemExtensionRequest.Result){
        guard result == .completed else {
            os_log("Unexpected result %d for system extension request", result.rawValue)
            //status = .stopped
            exit(Controller.ReturnCodes.RequestFailed.rawValue)
        }
        if self.current_cmd != .uninstall {
            enableFilterConfiguration()
        }
        else {
            exit(Controller.ReturnCodes.success.rawValue)
        }
    }

    func request(_ request: OSSystemExtensionRequest, didFailWithError error: Error) {

        os_log("System extension request failed: %@", error.localizedDescription)
        //status = .stopped
        exit(Controller.ReturnCodes.RequestFailed.rawValue)
        
    }

    func requestNeedsUserApproval(_ request: OSSystemExtensionRequest) {

        os_log("Extension %@ requires user approval", request.identifier)
    }

    func request(_ request: OSSystemExtensionRequest,
                 actionForReplacingExtension existing: OSSystemExtensionProperties,
                 withExtension extension: OSSystemExtensionProperties) -> OSSystemExtensionRequest.ReplacementAction {

        os_log("Replacing extension %@ version %@ with version %@", request.identifier, existing.bundleShortVersion, `extension`.bundleShortVersion)
        return .replace
    }
}

One more point, Automatic login option was enabled in my Mac machine.

Is this expected behaviour?

A Network System Extension will always start during bootup of the system. If the user previously allowed the provider to run, then it will run again regardless of the code in the container app. When the system is booted up, the system extension is run, not the container app.

Matt Eaton
DTS Engineering, CoreOS
meaton3@apple.com

A Network System Extension will always start during bootup of the system. If the user previously allowed the provider to run, then it will run again regardless of the code in the container app. When the system is booted up, the system extension is run, not the container app.

I think, my intention haven't understood properly. When we try to configure & activate NE, we will get two popups. First one is Security Preferences. Once we allow NE to activate from Security & Privacy then again we will get another popup to allow network content to filter.

Below two images are related to first popup. OS will throw below image whenever submit the activation request and If we allow here then NE will be activated. Once we allow here and if we run systemextensionsctl list command then will NE will show as [activated enabled] I think, you mentioned about this in your previous reply and this is fine for us.

Once we activate the NE from Security&Privacy as shown in above image then will get another popup like Allow/Don't Allow as shown below to enable filter configuration. If we choose Allow to filter network content then will show app as running in Network as shown below.

Now issue is facing when we choose Don't Allow from above popup and restart the machine. we have enableFilterConfiguration() functionality as part of machine bootstrap to confirm from the user to Allow/DontAllow the NE whenever machine is up after restart. But this is not throwing any popup like Allow/DontAllow and allowing network content to filter by default. This can notice from Network as shown above image. Here enableFilterConfiguration() is calling as part of bootstrap before user login into the machine and automatic user login option was enabled in my Mac machine.

If we call enableFilterConfiguration after user login into the machine then popup is coming to Allow/DontAllow. But, If I call this before user login into the machine then popup is not coming to Allow/DontAllow & NE is allowing to filter the content.

NE activation & enableFilterConfiguration() code was added in my previous reply for reference.

I have added a video at https://youtu.be/8gnO8n4gADo for reference.

Noticed same issue with https://its.gmu.edu/wp-content/uploads/anyconnect-macos-4.10.05085-core-vpn-webdeploy-k9.dmg also. I think, this is a bug at apple.

But this is not throwing any popup like Allow/DontAllow and allowing network content to filter by default.

Okay, so because your Network System Extension is installed here it will be started again during bootup, but I am surprised that it goes through the container app route as this is not technically loaded into user space yet. You are not creating the container app as a daemon are you? Just to confirm that the container app code you have above is running in a .app and exists in the /Applications folder correct?

Okay, so I just watched the video and I see that you are starting an agent from the command line and this is starting the installation process. This is your problem because you are not running the app from the /Applications folder with Finder. Do not create you container app as an agent or daemon and create it as a standard macOS .app and I suspect this issue will just go away.

Matt Eaton
DTS Engineering, CoreOS
meaton3@apple.com

The code running in .app and available at /Applications directory only. Internally my agent has the .app and few other executable files. When I install my agent, my .app will be placed in /Applications/ folder. One of the process name of my agent is daemon. This daemon process internally will start the .app to activate the NE. Here these is no issue if we choose Allow from below popup. Issue with Don't Allow option only. NE is allowing to filter the network content if we select Don'tAllow and restart the machine. Here my daemon process internally starts the .app as part of bootstrap when machine is up.

I have noticed same issue with one of the cisco product which is available at https://its.gmu.edu/wp-content/uploads/anyconnect-macos-4.10.05085-core-vpn-webdeploy-k9.dmg. I think, this is a bug in apple.

How to suppress Allow/DontAllow popup when we call filterManager.saveToPreferences?
 
 
Q