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 }