Transparent app proxy and UDP, redux

When doing UDP communications, the socket can either be connected, or not. If it's not connected, it can use sendto to send it to a different destination, and it can use recvfrom to receive from anywhere. (I honestly don't know how often this is used.)

An NEAppProxyUDPFlow does not, as far as I can tell, have any way to tell if it has been connected. In fact, the API involved involves an array of datagrams tied to an array of endpoints. But if the provider and the app do not have the same connected state, the results could be not at all what the app expects.

Is that correct? Or is it to be expected that it will only expect to get data from the set of destinations, and only that set?

> I honestly don't know how often this is used.

A lot.

> But if the provider and the app do not have the same connected state

I’m not sure what your specific concern is here. Each datagram you read from the flow has an associated remote endpoint, so you don’t need to track the connected state for outbound traffic. Are you concerned about inbound stuff?

Share and Enjoy

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

The responses do not have to come from the destinations. Consider, if you will, a UDP-based bit-torrent service: you send a datagram to one particular node, saying "gimme this file." That node then broadcasts that around. You then start getting datagrams from thousands of different nodes, none of which you'd actually sent a message to in the first place. That is only possible if the application did not use connect().

If, however, the application did use connect()... then it should only get responses from that particular node.

How is the transparent proxy supposed to be able to tell what the application is expecting?

> The responses do not have to come from the destinations.

Sure.

I don’t have a definitive answer here but I do have something for you to investigate. Your proxy has a method -handleNewUDPFlow:initialRemoteEndpoint:. If you use a connected UDP socket, is that endpoint populated?

Share and Enjoy

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

Interestingly, I don't have that method -- both TCP and UDP flows come via handleNewFlow(_:) (since that's the one the documentation says to override; I'll try overriding that one and see what happens). The local endpoint is, as far as I can tell, always filled out with the hostname being the interface's IP address, and port being 0. I wrote a small program to open two UDP sockets and connect one, and that did not provide any difference in behaviour that I could see -- I did that before asking. 😄

I get the same results with both overridden methods -- many things have a local port of 0, but some have been bound. eg

2023-03-20 09:39:59.799074+0000 0x16431f5  Debug       0x0                  71647  0    com.kithrup.NETest.NETestTunnel: [com.kithrup:NETestTuennel] Got UDP Flow UDP io.tailscale.ipn.macos.network-extension[{length = 20, bytes = 0x9aa36e7f0ce1e8c94d16d312b51d6b8820b52ff4}] local port 52711 interface en0(bound) remoteHostName <none> localEndpoint 192.168.1.58:52711

FYI, I had filed FB12006678 a while back, and just updated it to mention this issue as well.

Transparent app proxy and UDP, redux
 
 
Q