Follow-up to #57. The IP-keyed sticky being implemented there is the right compatible fix, but it is a heuristic, and the NAT corner cases are managed rather than eliminated. The durable answer is to make the reconnect itself carry the routing information, which is possible now that RedirectFix lives in this org.
The gap. After a redirect, the reconnecting client's first frame is LoginTokenQuery, which carries nothing. The proxy must pick the destination backend before any backend sees a byte (the token exchange binds the session to whichever backend answers, see #57), and at that moment it only knows the source address. Everything else is inference.
Option A, a transfer marker from RedirectFix. RedirectFix already patches the redirect path client-side. On ExitAndSwitchServer it can remember the transfer, and on the reconnect send one tiny frame before LoginTokenQuery: an unused packet id carrying the transfer correlation id. The proxy sniffs frame one, consumes the marker (never forwards it), routes deterministically, and proceeds. The natural payload already exists: ClientTransferId from the seamless handshake plumbing (#39), staged proxy-side at redirect time. Old RedirectFix clients simply fall back to the IP sticky, so the fleet can upgrade at its own pace.
Option B, routing by dialled address. Give each backend its own player-facing port (or subdomain) on the proxy, stamp it into the redirect packet via transfers.redirect_address (#38), and route reconnects by which listener they arrive on. No identity needed at all, NAT-proof by construction. Two costs: RedirectFix must start honouring the stamped address (today it ignores it and reconnects to the cached one), and operators must expose a port per backend, which is real friction on panels and firewalls.
Why A is the better first move. It needs no operator-side changes, it reuses an existing correlation id, and it degrades gracefully. B has one unique virtue though: it is exactly the path a future fixed vanilla client will take when it follows the stamped address literally (#18), so whatever we do for A should not paint over B. Concretely: keep redirect_address stamping correct and consider B again the day the vanilla fix ships.
Scope for A, roughly: pick an id for the marker that vanilla will never send (coordinate with the client mod work), stage the expected marker alongside the sticky at redirect time, teach the first-frame path to recognise and strip it, extend RedirectFix to emit it, and version the behaviour so mixed fleets stay coherent. The proxy-side sniffing already has everything it needs; the sensitive part is choosing the marker shape so it can never be confused with a real first frame.
Follow-up to #57. The IP-keyed sticky being implemented there is the right compatible fix, but it is a heuristic, and the NAT corner cases are managed rather than eliminated. The durable answer is to make the reconnect itself carry the routing information, which is possible now that RedirectFix lives in this org.
The gap. After a redirect, the reconnecting client's first frame is
LoginTokenQuery, which carries nothing. The proxy must pick the destination backend before any backend sees a byte (the token exchange binds the session to whichever backend answers, see #57), and at that moment it only knows the source address. Everything else is inference.Option A, a transfer marker from RedirectFix. RedirectFix already patches the redirect path client-side. On
ExitAndSwitchServerit can remember the transfer, and on the reconnect send one tiny frame beforeLoginTokenQuery: an unused packet id carrying the transfer correlation id. The proxy sniffs frame one, consumes the marker (never forwards it), routes deterministically, and proceeds. The natural payload already exists:ClientTransferIdfrom the seamless handshake plumbing (#39), staged proxy-side at redirect time. Old RedirectFix clients simply fall back to the IP sticky, so the fleet can upgrade at its own pace.Option B, routing by dialled address. Give each backend its own player-facing port (or subdomain) on the proxy, stamp it into the redirect packet via
transfers.redirect_address(#38), and route reconnects by which listener they arrive on. No identity needed at all, NAT-proof by construction. Two costs: RedirectFix must start honouring the stamped address (today it ignores it and reconnects to the cached one), and operators must expose a port per backend, which is real friction on panels and firewalls.Why A is the better first move. It needs no operator-side changes, it reuses an existing correlation id, and it degrades gracefully. B has one unique virtue though: it is exactly the path a future fixed vanilla client will take when it follows the stamped address literally (#18), so whatever we do for A should not paint over B. Concretely: keep
redirect_addressstamping correct and consider B again the day the vanilla fix ships.Scope for A, roughly: pick an id for the marker that vanilla will never send (coordinate with the client mod work), stage the expected marker alongside the sticky at redirect time, teach the first-frame path to recognise and strip it, extend RedirectFix to emit it, and version the behaviour so mixed fleets stay coherent. The proxy-side sniffing already has everything it needs; the sensitive part is choosing the marker shape so it can never be confused with a real first frame.