1 /*
2  * Copyright (c) 2018-2020 sel-project
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a copy
5  * of this software and associated documentation files (the "Software"), to deal
6  * in the Software without restriction, including without limitation the rights
7  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8  * copies of the Software, and to permit persons to whom the Software is
9  * furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in all
12  * copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20  * SOFTWARE.
21  *
22  */
23 /**
24  * Copyright: Copyright (c) 2018-2020 sel-project
25  * License: MIT
26  * Authors: Kripth
27  * Source: $(HTTP github.com/sel-project/sel-util/raknet/sel/raknet/packet.d, sel/raknet/packet.d)
28  */
29 module sel.raknet.packet;
30 
31 import std.socket : SocketAddress = Address, InternetAddress, Internet6Address;
32 import std.system : Endian;
33 
34 import xpacket;
35 
36 alias RaknetPacket = PacketImpl!(Endian.bigEndian, ubyte, ushort);
37 
38 // -----
39 // types
40 // -----
41 
42 struct Magic {
43 
44 	enum ubyte[16] constant = [0x00, 0xFF, 0xFF, 0x00, 0xFE, 0xFE, 0xFE, 0xFE, 0xFD, 0xFD, 0xFD, 0xFD, 0x12, 0x34, 0x56, 0x78];
45 
46 	ubyte[16] value = constant;
47 
48 	@property bool valid() pure nothrow @safe @nogc {
49 		return value == constant;
50 	}
51 
52 }
53 
54 struct Triad {
55 
56 	union {
57 
58 		int value;
59 		void[4] array;
60 
61 	}
62 
63 	void serialize(Buffer buffer) {
64 		version(LittleEndian) buffer.writeData(this.array[0..3]);
65 		else buffer.writeData(this.array[3], this.array[2], this.array[1]);
66 	}
67 
68 	void deserialize(Buffer buffer) {
69 		version(LittleEndian) this.array[0..3] = buffer.readData(3);
70 		else {
71 			this.array[3] = buffer.read!ubyte();
72 			this.array[2] = buffer.read!ubyte();
73 			this.array[1] = buffer.read!ubyte();
74 		}
75 	}
76 
77 	alias value this;
78 
79 }
80 
81 struct Address {
82 
83 	ubyte type;
84 	@Condition("type==4") uint ipv4;
85 	@Condition("type==6") ubyte[16] ipv6;
86 	@Condition("type==6") ubyte[10] unknown;
87 	ushort port;
88 
89 	this(SocketAddress address) {
90 		if(cast(InternetAddress)address) {
91 			InternetAddress addr = cast(InternetAddress)address;
92 			this.type = 4;
93 			this.ipv4 = addr.addr;
94 			this.port = addr.port;
95 		} else if(cast(Internet6Address)address) {
96 			Internet6Address addr = cast(Internet6Address)address;
97 			this.type = 6;
98 			this.ipv6 = addr.addr;
99 			this.port = addr.port;
100 		}
101 	}
102 
103 }
104 
105 struct Acknowledge {
106 
107 	bool unique;
108 	Triad first;
109 	@Condition("!unique") Triad last;
110 
111 }
112 
113 struct Encapsulation {
114 
115 	ubyte info;
116 	ushort length;
117 	@Condition("(info&0x7F) >= 64") Triad messageIndex;
118 	@Condition("(info&0x7F) >= 96") Triad orderIndex;
119 	@Condition("(info&0x7F) >= 96") Triad orderChannel;
120 	@Condition("(info&0x7F) != 0") Split split;
121 	@NoLength ubyte[] bytes;
122 
123 }
124 
125 struct Split {
126 
127 	uint count;
128 	ushort id;
129 	uint order;
130 
131 }
132 
133 // -------
134 // control
135 // -------
136 
137 class Ack : RaknetPacket {
138 
139 	enum ubyte ID = 192;
140 
141 	Acknowledge[] packets;
142 
143 	mixin Make;
144 
145 }
146 
147 class Nack : RaknetPacket {
148 
149 	enum ubyte ID = 160;
150 
151 	Acknowledge[] packets;
152 
153 	mixin Make;
154 
155 }
156 
157 class Encapsulated : RaknetPacket {
158 
159 	Triad count;
160 	Encapsulation encapsulation;
161 
162 	mixin Make;
163 
164 }
165 
166 // -----------
167 // unconnected
168 // -----------
169 
170 class UnconnectedPing : RaknetPacket {
171 
172 	enum ubyte ID = 1;
173 
174 	long pingId;
175 	Magic magic;
176 	long guid;
177 
178 	this() pure nothrow @safe @nogc {}
179 
180 	this(long pingId, long guid) pure nothrow @safe @nogc {
181 		this.pingId = pingId;
182 		this.guid = guid;
183 	}
184 
185 	mixin Make;
186 
187 }
188 
189 class UnconnectedPong : RaknetPacket {
190 
191 	enum ubyte ID = 28;
192 
193 	long pingId;
194 	long serverId;
195 	Magic magic;
196 	string status;
197 
198 	this() pure nothrow @safe @nogc {}
199 
200 	this(long pingId, long serverId, string status) pure nothrow @safe @nogc {
201 		this.pingId = pingId;
202 		this.serverId = serverId;
203 		this.status = status;
204 	}
205 
206 	mixin Make;
207 
208 }
209 
210 class OpenConnectionRequest1 : RaknetPacket {
211 
212 	enum ubyte ID = 5;
213 
214 	Magic magic;
215 	ubyte protocol = 9;
216 	@NoLength ubyte[] mtu;
217 
218 	this() pure nothrow @safe @nogc {}
219 
220 	this(ubyte[] mtu) pure nothrow @safe @nogc {
221 		this.mtu = mtu;
222 	}
223 
224 	mixin Make;
225 
226 }
227 
228 class OpenConnectionReply1 : RaknetPacket {
229 
230 	enum ubyte ID = 6;
231 
232 	Magic magic;
233 	long serverId;
234 	bool security;
235 	ushort mtuLength;
236 
237 	this() pure nothrow @safe @nogc {}
238 
239 	this(long serverId, bool security, ushort mtuLength) pure nothrow @safe @nogc {
240 		this.serverId = serverId;
241 		this.security = security;
242 		this.mtuLength = mtuLength;
243 	}
244 	
245 	mixin Make;
246 
247 }
248 
249 class OpenConnectionRequest2 : RaknetPacket {
250 
251 	enum ubyte ID = 7;
252 
253 	Magic magic;
254 	Address serverAddress;
255 	ushort mtuLength;
256 	long clientId;
257 	
258 	this() pure nothrow @safe @nogc {}
259 
260 	this(Address serverAddress, ushort mtuLength, long clientId) pure nothrow @safe @nogc {
261 		this.serverAddress = serverAddress;
262 		this.mtuLength = mtuLength;
263 		this.clientId = clientId;
264 	}
265 	
266 	mixin Make;
267 
268 }
269 
270 class OpenConnectionReply2 : RaknetPacket {
271 
272 	enum ubyte ID = 8;
273 
274 	Magic magic;
275 	long serverId;
276 	Address clientAddress;
277 	ushort mtuLength;
278 	bool security;
279 	
280 	this() pure nothrow @safe @nogc {}
281 
282 	this(long serverId, Address clientAddress, ushort mtuLength, bool security) pure nothrow @safe @nogc {
283 		this.serverId = serverId;
284 		this.clientAddress = clientAddress;
285 		this.mtuLength = mtuLength;
286 		this.security = security;
287 	}
288 	
289 	mixin Make;
290 
291 }
292 
293 // ------------
294 // encapsulated
295 // ------------
296 
297 class ClientConnect : RaknetPacket {
298 
299 	enum ubyte ID = 9;
300 
301 	long clientId;
302 	long pingId;
303 
304 	this() pure nothrow @safe @nogc {}
305 
306 	this(long clientId, long pingId) pure nothrow @safe @nogc {
307 		this.clientId = clientId;
308 		this.pingId = pingId;
309 	}
310 	
311 	mixin Make;
312 
313 }
314 
315 class ServerHandshake : RaknetPacket {
316 
317 	enum ubyte ID = 16;
318 
319 	Address clientAddress;
320 	ushort mtuLength;
321 	Address[10] systemAddresses;
322 	long pingId;
323 	long serverId;
324 
325 	this() pure nothrow @safe @nogc {}
326 
327 	this(Address clientAddress, ushort mtuLength, Address[10] systemAddresses, long pingId, long serverId) pure nothrow @safe @nogc {
328 		this.clientAddress = clientAddress;
329 		this.mtuLength = mtuLength;
330 		this.systemAddresses = systemAddresses;
331 		this.pingId = pingId;
332 		this.serverId = serverId;
333 	}
334 	
335 	mixin Make;
336 
337 }
338 
339 class ClientHandshake : RaknetPacket {
340 
341 	enum ubyte ID = 19;
342 
343 	Address clientAddress;
344 	Address[10] systemAddresses;
345 	long pingId;
346 	long clientId;
347 
348 	this() pure nothrow @safe @nogc {}
349 
350 	this(Address clientAddress, Address[10] systemAddresses, long pingId, long clientId) pure nothrow @safe @nogc {
351 		this.clientAddress = clientAddress;
352 		this.systemAddresses = systemAddresses;
353 		this.pingId = pingId;
354 		this.clientId = clientId;
355 	}
356 	
357 	mixin Make;
358 
359 }
360 
361 class ClientCancelConnection : RaknetPacket {
362 
363 	enum ubyte ID = 21;
364 	
365 	mixin Make;
366 
367 }
368 
369 class Ping : RaknetPacket {
370 
371 	enum ubyte ID = 0;
372 
373 	long time;
374 
375 	this() pure nothrow @safe @nogc {}
376 
377 	this(long time) pure nothrow @safe @nogc {
378 		this.time = time;
379 	}
380 	
381 	mixin Make;
382 
383 }
384 
385 class Pong : RaknetPacket {
386 
387 	enum ubyte ID = 3;
388 
389 	long time;
390 	
391 	this() pure nothrow @safe @nogc {}
392 	
393 	this(long time) pure nothrow @safe @nogc {
394 		this.time = time;
395 	}
396 	
397 	mixin Make;
398 
399 }