4.0 KiB
Request #3: the forked NGO batch/message framing and ConnectionApproved
The LiteNetLib layer is solved and the client now completes the transport handshake against
our server and sends its NGO ConnectionRequest. We decoded it and confirmed the Tachyon JSON
(AI/AT/VB/CKA/CIA/CPK). But the fork changed NGO's batch and message framing, so we cannot
send a ConnectionApproved the client will accept without the exact serialization.
What we already worked out from the wire (for your cross-check)
Decoded from a real 2041-byte ConnectionRequest batch:
[0:2] magic u16 = 0x1160
[2:4] count u16 = 0 (stock BatchCount, sent as 0)
[4:8] size u32 = 2041 (total datagram length)
[8:16] hash u64 = 0x3faa53cee8c5e338 (= XXHash64 over bytes [24:2041], VERIFIED)
[16:24] u64 = 1 (fork field; equals message count here)
[24] bitpacked = 1 (message type: ConnectionRequest, client-local idx)
[25:27] bitpacked = 2014 (message size)
[27] 0x81 (version-header preamble byte)
[28:63] 7 × { u32 hash ; 1 byte version=0 }
[63:68] 00 00 00 00 01 (5 bytes, not in stock NGO)
[68:76] u64 ConfigHash
[76:80] u32 = 1961 (ConnData length)
[80:2041] Tachyon JSON
So the batch hash covers [24:end] (message stream), NOT stock's [16:alignedLength], and
the batch is NOT padded to 8 bytes. Two message-body bytes are unexplained: the 0x81
preamble, and the 00 00 00 00 01.
Questions (in priority order)
Q1 — forked batch header & hash, in NetworkMessageManager.
Confirm the header layout above. Specifically:
- Is the
u64at[16:24]the message count, a tick, or something else? What writes it? - Confirm
BatchHash = XXHash64(buffer + 24, size - 24)(or give the real range/seed). - Does the RECEIVER validate
BatchHashand reject on mismatch, or log-and-continue? This decides whether our outbound hash must be exact. - Does the receiver iterate messages by the
u64count, byBatchCount, or by position?
Q2 — the version-header preamble.
In the forked ConnectionRequestMessage.Serialize (and the shared version-header code), what
is written before the version table? Stock writes BytePacker.WriteValueBitPacked(N) (N=7 ->
0x39). We see a single 0x81. And what is the 00 00 00 00 01 written AFTER the table,
before ConfigHash? Give the exact field sequence of the forbidden segment as this build
serializes it.
Q3 — ConnectionApprovedMessage serialization (the thing we must send).
Full Serialize (server→client) for this build. We need every field and its encoding, in
order: the version header (same preamble as Q2?), OwnerClientId, NetworkTick, any
ConnectedClientIds, sceneObjectCount, and anything the fork added. Also the message
type index the client expects for ConnectionApproved in the pre-approval (local) space,
and how Deserialize reads it — because the client's Deserialize is what accepts or rejects
our packet.
Q4 — how the approval reaches Tachyon.
Earlier finding: NetworkManager.RecRoom_ConnectionInfo is a fork addition, hypothesised to
carry the approval JSON (PMFAAFNFMAL, the "Carrot" / SessionKeyB blob). Confirm whether
the approval JSON rides inside ConnectionApprovedMessage's ConnectionData, in
RecRoom_ConnectionInfo, or elsewhere — i.e. where in the server→client bytes we must place
{"DR":"Carrot",...}.
Q5 — key-null path for the session.
Does the client require a non-null SessionKeyB to proceed, or will it accept an approval with
"Carrot" and no key and stay plaintext (marker 0x11)? This decides whether we can defer the
RSA keypair patch and run voice unencrypted.
Output
Decompiled Serialize/Deserialize bodies where possible, else exact field order + encodings
- byte offsets. Distinguish read from inferred. If a field genuinely is not present, say so — do not fill it from stock NGO; the fork has already diverged in three places above.