Filtering Network Traffic sample not working with Safari for protocol TCP

My app has some features that required to use System Extension and Network Extension. So for this, I was trying to check Apple Sample here, where it is filtering TCP and UDP data.

When I checked with different browsers, I found an issue where I was getting call backs for protocol TCP with browsers Chrome and Firefox but same was not working with Safari.

Am I missing anything here? Or Safari requires something specific configurations which are not mentioned in Apple documentation?
I am not aware of anything specific that is required to capture TCP flows in Safari. Have you tried a configuration like:

Code Block swift
let anyHostAndPortRule = NENetworkRule(
remoteNetwork: NWHostEndpoint(hostname: "0.0.0.0", port: "0"),
remotePrefix: 0,
localNetwork: nil,
localPrefix: 0,
protocol: .TCP,
direction: .any
)
let filterRule = NEFilterRule(networkRule: anyHostAndPortRule, action: .filterData)
let filterSettings = NEFilterSettings(rules: [filterRule], defaultAction: .allow)


And then logging the flow in handleNewFlow:

Code Block swift
override func handleNewFlow(_ flow: NEFilterFlow) -> NEFilterNewFlowVerdict {
os_log(.debug, log: self.log, "Received a new flow: %{public}@", flow.description)
}

Does this improve your situation on Safari?


Matt Eaton
DTS Engineering, CoreOS
meaton3@apple.com
I am already using the same configuration you mentioned. The handleNewFlow method is not getting called for Safari. It is working only for Firefox and Chrome.
In that case, is it a bug in the API or something?
I suspect that there is not a bug in the TCP filtering process on macOS for Safari. As an example, I ran these rules through a Simple Firewall testbed project this morning and received many flows for Safari. One of them being:

Code Block text
2020-08-27 07:19:45.732666-0700 0x139d81 Debug 0x0 42267 0 com.example.apple-samplecode.SimpleFirewallTestBed.SimpleFirewallExtension: [com.example.apple-samplecode.SimpleFirewallTestBed.SimpleFirewallExtension:provider] Received a new flow:
identifier = ...
hostname = example.com
sourceAppIdentifier = .com.apple.Safari
sourceAppVersion = 13.1.1
sourceAppUniqueIdentifier = 20:{length = 20, bytes = ...}
procPID = pid
eprocPID = pid
direction = outbound
inBytes = 0
outBytes = 0
signature = 32:{length = 32, bytes = ... }
remoteEndpoint = x.x.x.x:x
protocol = 6
family = 2
type = 1
procUUID = ...
eprocUUID = ...


If you still continue to experience issues on Safari feel free to open a DTS incident to have this investigated further.

Matt Eaton
DTS Engineering, CoreOS
meaton3@apple.com
Can you please check Apple sample, it has some issues I guess for Safari?
It has some problem with object passing to remoteNetwork (NWHostEndpoint). The sample code you have shared here, it's working.

Not working from Apple sample:
Code Block
let filterRules = ["0.0.0.0", "::"].map { address -> NEFilterRule in
      let localNetwork = NWHostEndpoint(hostname: address, port: FilterDataProvider.localPort)
      let inboundNetworkRule = NENetworkRule(remoteNetwork: nil,
                          remotePrefix: 0,
                          localNetwork: localNetwork,
                          localPrefix: 0,
                          protocol: .TCP,
                          direction: .inbound)
      return NEFilterRule(networkRule: inboundNetworkRule, action: .filterData)
}

Working code shared by you:
Code Block
let anyHostAndPortRule = NENetworkRule(
      remoteNetwork: NWHostEndpoint(hostname: "0.0.0.0", port: "0"),
      remotePrefix: 0,
      localNetwork: nil,
      localPrefix: 0,
      protocol: .TCP,
      direction: .any
)
let filterRule = NEFilterRule(networkRule: anyHostAndPortRule, action: .filterData)

May be we should fix this in Apple sample too...

Also in call back handleNewFlow, remoteEndpoint or localEndpoint getting nil for Safari due to which it is returning from guard let condition.

It is all working fine for other browsers like Google Chrome and Firefox with Apple Sample...

I do not think there is any issue in the sample for Simple Firewall. The key things to pay attention to in the sample configuration are:
  • FilterDataProvider.localPort (Which was defined as 8888)

  • direction: .inbound

Typically, to get this working you would start the Simple Firewall example on your machine, and from another machine make a TCP or HTTP connection on port 8888 to your machine. From there it would catch and prompt you to allow/deny the flow.

Notice in my example I am using port 0 and direction .any. That means any TCP/UDP connection inbound or outbound on any port. That's why when you load Safari and request example.com or apple.com it catches and prompts you to allow / deny the flow.

Matt Eaton
DTS Engineering, CoreOS
meaton3@apple.com
Filtering Network Traffic sample not working with Safari for protocol TCP
 
 
Q