Why is localEndpoint not available for NEAppProxyTCPFlow?

NEAppProxyUDPFlow contains below property:

open var localEndpoint: NWEndpoint? { get }

Why is localEndpoint not available for NEAppProxyTCPFlow?

Is there a way to determine the source port of a flow of type NEAppProxyTCPFlow within the following method of NETransparentProxyProvider?

override func handleNewFlow(_ flow: NEAppProxyFlow) -> Bool {

Answered by DTS Engineer in 855494022

If someone starts a TCP connection using a connect-by-name API, the system does its Happy Eyeballs thing. This means that the local interface, and hence the local IP address, aren’t known until the connection goes through.

Note For more background to this, read Understanding Also-Ran Connections.

Conceptually an app proxy sits above the TCP layer. Given that, your handle-new-flow method is called before the system has local endpoint info available.

I presume you’re building a transparent proxy here. If so, one option is to accept the flow and then wait for the first data transfer. By the time that happens, all the endpoint info will be set up.

There are a couple of downsides to this:

  • As a transparent proxy, you can’t ‘unaccept’ a flow. If the local endpoint info reveals that the flow needs no special handling, you’ll still have to proxy it.
  • The act of making a connection can ‘leak’ information. Unfortunately that a hard concept problem to resolve. I’ve seen in come up before, although that was in the context of a content filter.

Anyway, if you can share some info about what you plan to do with the local endpoint info, we can discuss your next steps.

Share and Enjoy

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

If someone starts a TCP connection using a connect-by-name API, the system does its Happy Eyeballs thing. This means that the local interface, and hence the local IP address, aren’t known until the connection goes through.

Note For more background to this, read Understanding Also-Ran Connections.

Conceptually an app proxy sits above the TCP layer. Given that, your handle-new-flow method is called before the system has local endpoint info available.

I presume you’re building a transparent proxy here. If so, one option is to accept the flow and then wait for the first data transfer. By the time that happens, all the endpoint info will be set up.

There are a couple of downsides to this:

  • As a transparent proxy, you can’t ‘unaccept’ a flow. If the local endpoint info reveals that the flow needs no special handling, you’ll still have to proxy it.
  • The act of making a connection can ‘leak’ information. Unfortunately that a hard concept problem to resolve. I’ve seen in come up before, although that was in the context of a content filter.

Anyway, if you can share some info about what you plan to do with the local endpoint info, we can discuss your next steps.

Share and Enjoy

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

@DTS Engineer

We have a separate module responsible for making decisions—whether to block, send directly, or route through a proxy. This module runs in a different process, and the extension communicates with it via IPC.

When the extension receives a flow:

  • The extension accepts the flow and queries the decision module for a verdict (block, direct, or proxy). It sends all metadata except the source port(This is not available).

  • The decision module responds with the verdict and, in the case of a proxy decision, the listener details (loopback IP and port). It also stores the metadata for later use when forwarding the flow to the proxy.

  • If the verdict is "send direct," the extension copies the flow to its actual destination.

  • If the verdict is "send to proxy," the extension copies the flow to the decision module’s listener.

  • Just before sending the flow to the proxy listener, the extension also provides the source port so that the decision module can update the corresponding metadata using the flow ID.

  • When the proxy listener receives the copied flow, it looks up the metadata using the source port, which serves as the only unique identifier at that point.

If we could obtain the source port right away and only talk to the decision module once, the whole process would be much simpler.

If we could obtain the source port right away … the whole process would be much simpler.

Hmmm, interesting. In situations like this the source IP address is tricky, but passing you the source port might be more feasible. I recommend that you file an enhancement request for that specifically, making sure to include information about why the source port, and not the source address, is important to you.

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"

Why is localEndpoint not available for NEAppProxyTCPFlow?
 
 
Q