For this, I'm following sample code of SimpleFirewall app provided as part of WWDC 2019 session Network Extensions for Modern Mac.
Following is my subclass of NEFilterDataProvider:
Code Block swift import NetworkExtension import os.log class FilterDataProvider: NEFilterDataProvider { override func startFilter(completionHandler: @escaping (Error?) -> Void) { let filterSettings = NEFilterSettings(rules: [NEFilterRule(networkRule: NENetworkRule( remoteNetwork: nil, remotePrefix: 0, localNetwork: nil, localPrefix: 0, protocol: .TCP, direction: .outbound ), action: .filterData)], defaultAction: .allow) apply(filterSettings) { error in if let applyError = error { os_log("Failed to apply filter settings: %@", applyError.localizedDescription) } completionHandler(error) } } override func handleNewFlow(_ flow: NEFilterFlow) -> NEFilterNewFlowVerdict { guard let socketFlow = flow as? NEFilterSocketFlow, let url = socketFlow.url else { return .allow() } /* .drop() if url found in local DB */ return .allow() } }
Although, I'm able to capture url in handleNewFlow but this does not seem like an elegant or optimal solution possible.
I'm really concerned about the performance as this captures all the TCP outbound traffic generated by any app on the system not limited to just HTTP outbound traffic from web browser apps.
I can think of possible solutions but I'm unable to find the APIs available for implementing that on macOS:
How do you get flow as Browser Flow, something like NEFilterBrowserFlow but not just for WebKit-based browsers but for all browsers?
If #1 not possible, then how do you get something like sourceAppIdentifier to match against bundle identifiers of browser apps?
If possible, how do you filter only HTTP traffic?