-
Notifications
You must be signed in to change notification settings - Fork 107
Description
What happened:
The Unreal Engine plugin's QuilkinPacketHandler appears to be incorrectly serializing the TArray<uint8> routing token. When appending the token as a suffix to outgoing packets, it consistently skips the first byte of the token.
This causes the Quilkin proxy, when configured with a suffix capture filter, to read a misaligned token. This misaligned token then fails to match the correct token in the proxy's routing table (which was set by our matchmaker), causing all client connection attempts to fail with a "no endpoint matched token" error.
What you expected to happen:
We expect the QuilkinPacketHandler to append the full 16-byte token to the outgoing packet. The proxy should then read this exact 16-byte token from the suffix, find a match in its routing table, and successfully forward the packet to the dedicated game server.
How to reproduce it (as minimally and precisely as possible):
- Configure a Matchmaker (like agones-pubsub-allocator) to generate a 16-byte token and register it with the Quilkin proxy's routing table.
- Configure the Quilkin proxy
ConfigMapto capture a 16-byte token from thesuffixof the packet. (SeeCustom filterssection below for YAML). - Configure an Unreal Engine 5.5 client to use the
QuilkinConfigSubsystemandQuilkinPacketHandler. - Have the client request a token from the Matchmaker.
- On the client, receive the 16-byte token, decode it from Base64 into a
TArray<uint8>, and set it usingUQuilkinConfigSubsystem::SetRoutingToken(). - Attempt to
ClientTravelto the Quilkin proxy address. - The connection will fail. The client will log a timeout, and the proxy will log a "no endpoint matched token" error.
Anything else we need to know?:
This is a byte-level serialization bug. The system is fully synchronized on a 16-byte token, but the proxy log proves it is reading a token that is offset by one byte.
Byte-Level Proof
-
Token from Matchmaker (The "Truth"):
- Base64:
bFJUU0tMZTRzS1FZYnFvMA== - Decoded:
lRTSKLe4sKQYbqo0
- Base64:
-
Token the UE Client Initializes With (Correct):
- Log:
LogQuilkin: Display: Initialising PacketHandler: ... Routing Token: bFJUU0tMZTRzS1FZYnFvMA== - Hex:
[0x6C, 0x52, 0x54, 0x53, ... , 0x6F, 0x30]
- Log:
-
Token the Proxy Receives (Incorrect - 1 Byte Offset):
- Log:
...error":"filter no endpoint matched token \UlRTS0xlNHNLUVlicW8wAA==`"` - Decoded:
RTSKLe4sKQYbqo0\x00 - Hex:
[0x52, 0x54, 0x53, 0x4B, ... , 0x30, 0x00]
- Log:
Comparison:
| Array | Byte 1 | Byte 2 | Byte 3 | ... | Byte 15 | Byte 16 |
|---|---|---|---|---|---|---|
| Sent | 0x6C (l) |
0x52 (R) |
0x54 (T) |
... | 0x6F (o) |
0x30 (0) |
| Read | 0x52 (R) |
0x54 (T) |
0x53 (S) |
... | 0x30 (0) |
0x00 (Junk) |
This shows the plugin is failing to write the first byte (0x6C) of the token to the packet. The investigation should focus on the QuilkinPacketHandler's PreSend or LowLevelSend implementation, specifically where the RoutingToken TArray is being copied into the packet buffer.
Environment:
- Quilkin version:
0.9.0(from proxy log{"message":"Starting Quilkin","version":"0.9.0",...) - Execution environment (binary, container, etc): Container (running in Kubernetes)
- Operating system: Linux (container base)
- Custom filters? (Yes/No - if so, what do they do?):
Yes, the standard token capture/router configuration.apiVersion: v1 kind: ConfigMap metadata: name: quilkin-xds-filter-config data: quilkin.yaml: | version: v1alpha1 filters: - name: quilkin.filters.capture.v1alpha1.Capture config: metadataKey: "quilkin.dev/token" suffix: size: 16 remove: true - name: quilkin.filters.token_router.v1alpha1.TokenRouter config: metadataKey: "quilkin.dev/token" Log(s): Matchmaker (Allocator) Log: JSON
{"level":"info", ... "token":"bFJUU0tMZTRzS1FZYnFvMA==", ... "message":"controller: updating GameServer with routing token"}
Unreal Client Log:
LogServer: Display: Starting with token: bFJUU0tMZTRzS1FZYnFvMA==
LogServer: Display: Decoded token to 16 bytes, Token: lRTSKLe4sKQYbqo0
LogQuilkin: Display: Initialising PacketHandler: Packet Handling: Enabled, Routing Token: bFJUU0tMZTRzS1FZYnFvMA==
LogQuilkin: Display: 10.0.10.14:7600 exceeded WaitForRead timeout 6 times
Quilkin Proxy Log:
JSON
{"timestamp":"2025-10-25T18:08:49.789103Z","level":"WARN","fields":{"message":"pipeline report","error":"filter no endpoint matched token UlRTS0xlNHNLUVlicW8wAA==","instances":"6"},"target":"quilkin::components::proxy::packet_router","filename":"src/components/proxy/packet_router.rs","threadId":"ThreadId(2)"}
Others: N/A