googleforgames / quilkin

Quilkin is a non-transparent UDP proxy specifically designed for use with large scale multiplayer dedicated game server deployments, to ensure security, access control, telemetry data, metrics and more.
Apache License 2.0
1.3k stars 94 forks source link

Bind Quilkin's sender socket to a given address:port #345

Open davidkornel opened 3 years ago

davidkornel commented 3 years ago

This is a feature proposal issue It would be nice to be able to bind Quilkin's sender socket to a given address and port pair. When Quilkin proxies the packets to an upstream host server, it chooses a random socket to use. This feature would remove the randomness and allow us to control which address and port pair to use.

Why do we need this?

We are using a separate control and media plane, and dynamically (via an XDS server) create a media plane pipeline for every single RTP/RTCP stream. After the mentioned SDP messages we would know where to bind the sender socket.

Not sure if this should be a filter or not. Or in general how the configuration would look like? What do you think about this?

XAMPPRocky commented 3 years ago

Thank you for your issue! This should be relatively straightforward to add to Quilkin, we need to add a upstream_addr: or equivalvent to the proxy configuration, and then in our implementation, we change the upstream socket to be Arc<UdpSocket>, which is either a new dynamically allocated socket or the socket defined from upstream_addr: if set.

hellof20 commented 2 years ago

hello, any update about this feature?

XAMPPRocky commented 2 years ago

@hellof20 Hello, no there's been no work on it yet, we're currently focused on xDS support in Quilkin, a PR is always welcome!

markmandel commented 2 years ago

Was just digging into the PR (thanks so much btw!) and it made me realise some concerns that make me wonder if this is viable (or maybe need to take a different approach).

Quilkin is built to be non-transparent, so that may be the issue here that could be blocking for this specific use case.

In the PR as I noted in a comment if we have only a singular address/port combo as the sending port, then each Session's key is no longer unique combo of receiver and ephemeral address and port - which may have some unintended consequences.

In the current model as well, each Session can watch it's own Socket, since it's unique: https://github.com/googleforgames/quilkin/blob/786d0d3561ad758aee7aa90966f9c106e4847f30/src/proxy/sessions/session.rs#L184

But if the socket is shared in this scenario - which part of Quilkin listens for incoming packets from usptream endpoints, and how do we determine which downstream client that a packet is supposed to go to if they are sharing the port?

I'm concerned this current config solution of a singular upstream_address only works if you have one client to one one endpoint, but not if you have multiple clients and/or multiple endpoints (anything that forces multiple sessions).

If we had a address per-endpoint, that solves part of the problem (multiple endpoints), but still leaves us with the problem of how to handle multiple downstream clients creating multiple sessions all bound to the same port.

So... I'm not quite sure how we can facilitate the currently proposed design 🤔 or come up with a new design that will work to solve the outlined problems.

Do we need a mode that assumes a singular UDP client->server connection maybe? (feels a bit weird), or some kind of other control over which port a Session creates? (or maybe a way to somehow tell Quilkin to reuse some ports on disconnect or something?)

Thoughts?

markmandel commented 2 years ago

I had two other potential thoughts over the weekend, but I'm not familiar with this protocol, but thought I would run them by you, see if they would work out:

  1. Configurable Session timeout

I think those might help in your circumstances, since you could set a timeout that aligns with your system, and potentially avoid/reduce the issue where the port the RTPengine is expecting is still up and working.

I also figured we'll have to do this at some point anyway 😄

  1. Sequential sender port assignment

Basically have an option to turn off ephemeral port assignment, and instead use a sequential system starting from a configured value.

This would take some logic on the Quilkin side, since if you assigned 8000, 8001 and 8002, and the Session tied to 8001 drops, then rather than assign 8003 on the next Session creation, you would go back to 8001 - but this is not impossible.

This would require some port management in the end user side, but would mean you would know the range of sending ports, based on how many client connections and endpoints you have. If you only have a single connection to a single endpoint, then you also know what your sending port is (the configured lowest value in the sequence).

Does that work?