quic-go / masque-go

MASQUE: Proxying UDP in HTTP/3, RFC 9298
MIT License
81 stars 9 forks source link

connected and unconnected sockets #3

Open marten-seemann opened 6 months ago

marten-seemann commented 6 months ago

Currently the proxy uses connected sockets. This is a good idea performance-wise, but comes with the obvious limitation on the number of proxied connections.

We should have an API that allows an application more fine-grained control. One option would be a callback on the Server:

type Server struct {
    // ... existing stuff

    // PacketConnForRemote is called when establishing a new proxied connection.
    // It is possible to return the same net.PacketConn (an unconnected UDP socket) for multiple distinct remote address.
    // However, the same net.PacketConn cannot be used for the same remote address.
    PacketConnForRemote(*net.UDPAddr) net.PacketConn
}

The problem here is that the same net.PacketConn can't be used for the same remote address: We need to know which QUIC connection to put a packet on. It's also not clear how timeouts should work: If one proxied connection is closed, it should be possible to reuse the same net.PacketConn at some point, but probably not immediately, since UDP packets might still be in flight between the remote and the proxy.

marten-seemann commented 6 months ago

There are multiple ways to slice and dice it. One option that comes to mind is using one (unconnected) socket per client. This might make in a setting where the client is using the proxy to proxy all its traffic over the proxy.

However, it also breaks as soon as the client requests to connect to the same IP (not domain!) multiple times. This will be pretty common, given the current centralization of the edge infrastructure in the hands of a few giant CDN providers.

marten-seemann commented 4 months ago

43 opens up a path to using unconnected UDP sockets: When the application wishes to proceed with a masque.Request, it can either:

For ProxyUnconnectedSocket, we can then perform the necessary checks (are we already proxying another connection to the same net.UDPAddr as target?), and reject the proxying attempt with a masque.ErrAlreadyProxyingToThisTarget (better naming tbd). The application can then decide to either switch to a connected socket, attempt again using another unconnected socket, or even create a new unconnected socket.