How do I monitor tunnel traffic with a Packet Filter Provider ?

My application contains a Content Filter Network System extension.

My VPN creates a null/loopback encapsulated tunnel in order to route the traffic to the vpn.

I've noticed that I get FilterSocketFlows through the FilterDataProvider but I never see any tunnel traffic appearing in the FilterPacketProvider.

How can the Packet provider be configured to filter tunnel traffic ?

Note : I have tried only registering a PacketProvider and still dont see any traffic. Is there any documentation of proper configuration ?

Accepted Reply

For anyone stumbling upon this question, I've found what I believe to be the answer.

In the NEFilterDataProvider class, there is a method :

@available(macOS 10.15.4, *)
  open func update(_ flow: NEFilterSocketFlow, using verdict: NEFilterDataVerdict, for direction: NETrafficDirection)

In an initial test demo, this appeared to be what I'm looking for. NEFilterFlow objects from handleNewFlow can be cached and this update method can be used to change a verdict at a later date. No idea when this method was added to the system extension framework SDK as it definitely didn't exist when this problem initially arose.

Few other comments:

  • it appears that trying to update a flow thats finished doesn't seem to cause harm
  • I believe all flow operations take place on the extensions main dispatchqueue.
  • If the new flow object doesn't contain the full 5 tuple information, peeking 1 byte will allow the information to become available in the cached NEFilterSocketFlow object.

Replies

Alternatively if its not possible to monitor tunnel traffic via PacketProvider, how to do stop tunnel connections in the middle of a flow ?

How can the Packet provider be configured to filter tunnel traffic ?

I believe that this is your question so I will attempt to answer this. It sounds like based on your description you have a NEPacketTunnelProvider, a NEFilterDataProvider, and a NEFilterPacketProvider in your environment. If content filtering is your goal, then you do not need a NEPacketTunnelProvider as tunneling to null/loop is good for demonstration purposes but should not be done to actually tunnel traffic over the network or send it to another provider like NEFilterPacketProvider. When I debug content filter scenario's like this I often start with one provider, in this case it is usually NEFilterDataProvider and I run observations on the traffic in one terminal. Next, if all goes well, I bring in NEFilterPacketProvider in another terminal and you should be able to see both running side by side.


Matt Eaton
DTS Engineering, CoreOS
meaton3@apple.com
Hi Matt, thank you for replying however I believe there is a misunderstanding here.

I don't have NEPacketTunnelProvider, I only have a NEFilterDataProvider and NEFilterPacketProvider. The tunnel interface that I speak of is created by third party software which is a VPN client. I create a security product which must be able to filter the traffic on this interface.

I would like to monitor, and filter the traffic coming through this, already existing, tunnel interface. I only see flows at the beginning of a connection. I never see packets through NEFilterPacketProvider. I would like the ability to stop connection at any point in this tunnel, which is currently not possible because we can only provide a verdict at the beginning of the flow.

Best Regards,
Rob


Rob,

I don't have NEPacketTunnelProvider, I only have a NEFilterDataProvider and NEFilterPacketProvider. The tunnel interface that I speak of is created by third party software which is a VPN client.

My VPN creates a null/loopback encapsulated tunnel in order to route the traffic to the vpn.

If the "my VPN" in this context is is not your VPN and a 3rd party then I suspect that you do not have much control over this and like you mentioned, are only able to see flows at the beginning of the connection. (That being before they are claimed by the VPN) One test that you could try to run here to see what is possible is setup a Packet Tunnel on a VM to send traffic to a remote VPN server. Then experiment with your product being started before or after the VPN is started and see what these tests yield. For example, if you start your content filter before your test VPN, what do you see? Also, if you start your VPN first and then your content filter after, what do you see?



Matt Eaton
DTS Engineering, CoreOS
meaton3@apple.com
I've tested this with my product started both before and after the tunnel is created by the thirdparty VPN and the results are the same in both cases. You only see the start of a connection and so you can't filter existing connections.

Is there any other way to filter traffic through tunnels ? If not, this is a major security flaw and should be addressed in a future update.
Existing connections, yes, but you should still be able to see new connections, correct?

Is there any other way to filter traffic through tunnels ? If not, this is a major security flaw and should be addressed in a future update.

When you mentioned the start of the connection, this does at least give you the outbound flow information needed to make a preliminary decision correct? Is the concern this part, or is more on the existing connections side?


Matt Eaton
DTS Engineering, CoreOS
meaton3@apple.com
The concern here is stopping a potentially malicious connection after its already started, one may have to analyze part of the connection before determining whether or not to stop it. This can be done in part by deferring the verdict by a certain number of bytes. But this isn't ideal for potentially long connections that stay open for a time before starting to act suspiciously.

Additionally:
Please look at https://developer.apple.com/forums/thread/132992
  • I've found that completely uninstalling and reinstalling the system extension allows us to provide a flow verdict for existing connections.

    This is most likely because when installing a new system extension is temporarily causes network outage and requires all existing connections to attempt to reconnect. So in this case "existing" is a misnomer.

    Uninstalling and re-installing is a no-go since it causes UI popups.

    In my testing, it seems to only way to provide a verdict for existing connections is to force all existing connections to re-connect by forcing a network outage, thereby allowing us to place a verdict on these "new" connections.

    Please can you confirm there is no better approach for allowing an NEFilter to provide a verdict on existing connections, when these connects are going down a VPN tunnel ?

Add a Comment

I've found that completely uninstalling and reinstalling the system extension allows us to provide a flow verdict for existing connections.

This is most likely because when installing a new system extension is temporarily causes network outage and requires all existing connections to attempt to reconnect. So in this case "existing" is a misnomer.

Uninstalling and re-installing is a no-go since it causes UI popups.

In my testing, it seems to only way to provide a verdict for existing connections is to force all existing connections to re-connect by forcing a network outage, thereby allowing us to place a verdict on these "new" connections.

Please can you confirm there is no better approach for allowing an NEFilter to provide a verdict on existing connections, when these connects are going down a VPN tunnel ?

For anyone stumbling upon this question, I've found what I believe to be the answer.

In the NEFilterDataProvider class, there is a method :

@available(macOS 10.15.4, *)
  open func update(_ flow: NEFilterSocketFlow, using verdict: NEFilterDataVerdict, for direction: NETrafficDirection)

In an initial test demo, this appeared to be what I'm looking for. NEFilterFlow objects from handleNewFlow can be cached and this update method can be used to change a verdict at a later date. No idea when this method was added to the system extension framework SDK as it definitely didn't exist when this problem initially arose.

Few other comments:

  • it appears that trying to update a flow thats finished doesn't seem to cause harm
  • I believe all flow operations take place on the extensions main dispatchqueue.
  • If the new flow object doesn't contain the full 5 tuple information, peeking 1 byte will allow the information to become available in the cached NEFilterSocketFlow object.