Oddity With OS X Content Filter Not Calling handleNewFlow

I'm working with content filters on OS X and encountered an issue where the handleNewFlow function is not called unless I explicitly invoke completionHandler(nil) in the startFilter method. This is perplexing because I expected handleNewFlow to be called automatically when new traffic flows are detected.

Here's an example of my startFilter function without the completionHandler:

override func startFilter(completionHandler: @escaping (Error?) -> Void) {
    os_log("Start filter called")
    
    // Create a network rule that matches all traffic
    let allTrafficNetworkRule = NENetworkRule(remoteNetwork: nil,
                                              remotePrefix: 0,
                                              localNetwork: nil,
                                              localPrefix: 0,
                                              protocol: .any,
                                              direction: .outbound)

    // Create a filter rule that allows all traffic
    let allowAllFilterRule = NEFilterRule(networkRule: allTrafficNetworkRule, action: .allow)
    
    // Set filter settings with the default action to allow all traffic
    let filterSettings = NEFilterSettings(rules: [allowAllFilterRule], defaultAction: .allow)

    // If I include this it will work fine, but TCP sessions will be reset:
   //completionHandler(nil)
}

Question:

Why, when I include completionHandler(nil) in the startFilter method, do all TCP sessions on my computer get reset? Is there a way to around this? My ideal state would be to get handleNewFlow to execute, but not without resetting sessions on my machine.

Answered by DTS Engineer in 791551022
I'm working with content filters on OS X and encountered an issue where the handleNewFlow function is not called unless I explicitly invoke completionHandler(nil) in the startFilter method.

Right. That’s because, until you call the completion handler, your filter isn’t considered ‘up’ by the system. The act of calling the completion handler is what tells the system that you’re reading to handle flows.

do all TCP sessions on my computer get reset?

Yes, that is indeed the expected behaviour. When a filter comes up the system closes existing connections. Apps are expected to re-establish those connections, which allows your filter to… well… filter them.

My ideal state would be to get handleNewFlow to execute, but not without resetting sessions on my machine.

This isn’t the first time I’ve seen folks bump into this design point (r. 99402484). If you’d like to see it change, I encourage you to file an enhancement request with your rationale.

Please post your bug number, just for the record.

Share and Enjoy

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

I'm working with content filters on OS X and encountered an issue where the handleNewFlow function is not called unless I explicitly invoke completionHandler(nil) in the startFilter method.

Right. That’s because, until you call the completion handler, your filter isn’t considered ‘up’ by the system. The act of calling the completion handler is what tells the system that you’re reading to handle flows.

do all TCP sessions on my computer get reset?

Yes, that is indeed the expected behaviour. When a filter comes up the system closes existing connections. Apps are expected to re-establish those connections, which allows your filter to… well… filter them.

My ideal state would be to get handleNewFlow to execute, but not without resetting sessions on my machine.

This isn’t the first time I’ve seen folks bump into this design point (r. 99402484). If you’d like to see it change, I encourage you to file an enhancement request with your rationale.

Please post your bug number, just for the record.

Share and Enjoy

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

Oddity With OS X Content Filter Not Calling handleNewFlow
 
 
Q