-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpackets.html
More file actions
296 lines (288 loc) · 8.36 KB
/
packets.html
File metadata and controls
296 lines (288 loc) · 8.36 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
---
layout: default
title: Packets
---
<div class="bubble">
<h1>UDP Packet handling</h1>
Once the session is established after a login, the server will being sending
messages to the Core over UDP. These packets are received using the process
that we started when establishing the
<a href="/login#4">session</a> after a successful login.
<hr />
<div class="center">
<div class="bubble-column" style="max-width: 700px">
<div class="bubble contrast small">
<h1>1.</h1>
<p>
Raw UDP packets enter the Core from
<a
href="https://docs.rs/metaverse_core/latest/metaverse_core/session/struct.Mailbox.html#method.start_udp_read"
>
start_udp_read()</a
>. It continuously receives messages from the server as they come into
the socket.
</p>
</div>
<div class="bubble contrast small">
<h1>2.</h1>
<p>
The raw data is then converted to a
<a
href="https://docs.rs/metaverse_messages/latest/metaverse_messages/packet/packet/struct.Packet.html"
>Packet</a
>
object using the packet's
<a
href="https://docs.rs/metaverse_messages/latest/metaverse_messages/packet/packet/struct.Packet.html#method.from_bytes"
>from_bytes</a
>
function.
</p>
</div>
<div class="bubble contrast small">
<h1>3.</h1>
<p>
The packet's from_bytes functon
<a
href="https://github.com/benthic-mmo/metaverse_client/blob/7586490c87ca4e001d811be20673fc9b00e2a550/crates/messages/src/packet/packet.rs#L36"
>then</a
>
tries to parse the
<a
href="https://docs.rs/metaverse_messages/latest/metaverse_messages/packet/header/index.html"
>Header</a
>, which contains the information about what type of packet the
following data will be.
</p>
</div>
<div class="bubble contrast small">
<h1>4.</h1>
<p>
Handle edgecases like if the packet has no body, or if the packet
header tells you the packet body is
<a
href="https://github.com/benthic-mmo/metaverse_client/blob/7586490c87ca4e001d811be20673fc9b00e2a550/crates/messages/src/packet/packet.rs#L64"
>zerocoded</a
>.
</p>
</div>
</div>
</div>
</div>
<div class="sinister bubble">
<h1>Headers</h1>
Header parsing in the open metaverse protocol can be challenging. Headers can
be a variable number of bytes long, depending on previous values read from the
stream. <br /><br />
The layout is as follows:
<table>
<tr>
<td>Flags</td>
<td>1 byte</td>
<td>
Flag values are set with a bitwise and. The last four bytes are unused.
<table>
<tr>
<td>Zerocoded</td>
<td>0x80</td>
</tr>
<tr>
<td>Reliable</td>
<td>0x40</td>
</tr>
<tr>
<td>Resent</td>
<td>0x20</td>
</tr>
<tr>
<td>Ack</td>
<td>0x10</td>
</tr>
</table>
</td>
</tr>
<tr>
<td>Sequence Number</td>
<td>4 bytes</td>
<td>
The sequence number of this packet. This is used to handle
acknowledgment packets.
</td>
</tr>
<tr>
<td>Extra</td>
<td>1 byte</td>
<td>How many bytes are used to describe the packet ID and frequency.</td>
</tr>
<tr>
<td>Packet ID and frequency</td>
<td>1, 2, or 4 bytes</td>
<td>The combined ID and frequency of the packet</td>
</tr>
</table>
The Packet ID and frequency is handled differently depending on if it is a
high, medium, low, or fixed frequency packet, based on the location of a 0xFF
byte.
<table>
<tr>
<td>High</td>
<td>
The following byte after Extra is not 0xFF. That byte is the packet's
ID.
</td>
<td>
<table>
<tr>
<td>Extra Byte</td>
<td>Packet ID</td>
</tr>
</table>
</td>
</tr>
<tr>
<td>Medium</td>
<td>
If the following byte after Extra is 0xFF, the following byte is the
packet's ID
</td>
<td>
<table>
<tr>
<td>Extra Byte</td>
<td>0xFF</td>
<td>Packet ID</td>
</tr>
</table>
</td>
</tr>
<tr>
<td>Low</td>
<td>
If the following two bytes after Extra is 0xFF, the following byte is
the packet's ID. Low packets are stored in two bytes instead of one.
</td>
<td>
<table>
<tr>
<td>Extra Byte</td>
<td>0xFF</td>
<td>0xFF</td>
<td>Packet ID low byte</td>
<td>Packet ID high byte</td>
</tr>
</table>
</td>
</tr>
<tr>
<td>Fixed</td>
<td>
If the following three bytes after Extra is 0xFF, the following byte is
the packet's ID
</td>
<td>
<table>
<tr>
<td>Extra Byte</td>
<td>0xFF</td>
<td>0xFF</td>
<td>0xFF</td>
<td>Packet ID</td>
</tr>
</table>
</td>
</tr>
</table>
{% capture zerocoded %}
<h2>Zerocoded Headers</h2>
A specific bug can appear only in the headers of certain zerocoded packets of
low frequency, which offsets reading the bytes and creates incorrect packet
IDs.
<br />
<br />
The zerocoding algorithm runs on the entire packet when leaving the server,
sometimes zerocoding the header itself. What you might attempt to decode as
<table>
<tr>
<td>Extra Byte</td>
<td>0xFF</td>
<td>0xFF</td>
<td>Packet ID low byte</td>
<td>Packet ID high byte</td>
</tr>
</table>
is in reality
<table>
<tr>
<td>Extra Byte</td>
<td>0xFF</td>
<td>0xFF</td>
<td>0x00</td>
<td>0x01</td>
<td>Packet ID high byte</td>
</tr>
</table>
That
<table>
<tr>
<td>0x00</td>
<td>0x01</td>
</tr>
</table>
is actually a single zero in the u16's low byte, followed by the u16's high
byte. Failing to account for this will result in the entire body of this
packet to be improperly decoded, and the ID of the packet to parse as 1 for
any zerocoded packet of low frequency with a 0 in the low byte, such as
<a
href="https://docs.rs/metaverse_messages/latest/metaverse_messages/udp/core/region_handshake"
>RegionHandshake</a
>
packets.
<br />
<br />
For these packets, this can be easily avoided by handling parsing like this:
<table>
<tr>
<td>Extra Byte</td>
<td>0xFF</td>
<td>0xFF</td>
<td>Packet ID low byte</td>
<td>0x01 (ignored)</td>
<td>Packet ID high byte</td>
</tr>
</table>
{% endcapture %} {% include evil_benthic.html content=zerocoded %}
</div>
<div class="bubble">
<h1>Reliable Packets</h1>
Some packets have a "reliable" flag. This means that on receive, the client
needs to respond with an
<a
href="https://docs.rs/metaverse_messages/latest/metaverse_messages/udp/core/packet_ack/index.html"
>ack packet</a
>, or else the server will continue sending it.
<br />
When a reliable packet is received, the core will immediately
<a
href="https://github.com/benthic-mmo/metaverse_client/blob/7586490c87ca4e001d811be20673fc9b00e2a550/crates/core/src/transport/udp_handler.rs#L34"
>add the packet's sequence number</a
>
to the ack list. The mailbox is then triggered to
<a
href="https://docs.rs/metaverse_core/latest/metaverse_core/session/struct.Mailbox.html#impl-Handler%3CSendAckList%3E-for-Mailbox"
>send the list</a
>.
</div>
<div class="bubble">
<h1>Packet Body</h1>
The following bytes after the header are the data block containing the packet
body. Some packets contain no body, and are only sent to inform the viewer of
simple events, such as the
<a
href="https://docs.rs/metaverse_messages/latest/metaverse_messages/udp/core/disable_simulator"
>Disable Simulator</a
>
packet. <br /><br />
Packet bodies are parsed based on the combination of the frequency and ID to
determine the packet type. Each packet body has its own parsing rules and
strucs.
</div>