diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/server/bnetserver/Packets/WoWRealmPackets.cpp | 7 | ||||
| -rw-r--r-- | src/server/game/Server/Protocol/ServerPktHeader.h | 40 | ||||
| -rw-r--r-- | src/server/game/Server/WorldSocket.cpp | 82 | ||||
| -rw-r--r-- | src/server/game/Server/WorldSocket.h | 25 | ||||
| -rw-r--r-- | src/server/shared/Cryptography/Authentication/WorldPacketCrypt.cpp | 4 |
5 files changed, 94 insertions, 64 deletions
diff --git a/src/server/bnetserver/Packets/WoWRealmPackets.cpp b/src/server/bnetserver/Packets/WoWRealmPackets.cpp index 714c43b8eb4..4ea34a7e173 100644 --- a/src/server/bnetserver/Packets/WoWRealmPackets.cpp +++ b/src/server/bnetserver/Packets/WoWRealmPackets.cpp @@ -42,10 +42,12 @@ void Battlenet::WoWRealm::ListUnsubscribe::CallHandler(Session* session) void Battlenet::WoWRealm::JoinRequestV2::Read() { + ClientSeed = _stream.Read<uint32>(32); + _stream.Read<uint32>(20); + Realm.Region = _stream.Read<uint8>(8); + _stream.Read<uint16>(12); Realm.Battlegroup = _stream.Read<uint8>(8); Realm.Index = _stream.Read<uint32>(32); - Realm.Region = _stream.Read<uint8>(8); - ClientSeed = _stream.Read<uint32>(32); } std::string Battlenet::WoWRealm::JoinRequestV2::ToString() const @@ -194,7 +196,6 @@ std::string Battlenet::WoWRealm::ToonReady::ToString() const void Battlenet::WoWRealm::JoinResponseV2::Write() { - _stream.Write(0, 27); _stream.Write(Response, 1); if (Response == SUCCESS) { diff --git a/src/server/game/Server/Protocol/ServerPktHeader.h b/src/server/game/Server/Protocol/ServerPktHeader.h index fcb24cfa80d..edd0057d8d1 100644 --- a/src/server/game/Server/Protocol/ServerPktHeader.h +++ b/src/server/game/Server/Protocol/ServerPktHeader.h @@ -19,43 +19,23 @@ #ifndef __SERVERPKTHDR_H__ #define __SERVERPKTHDR_H__ -#include "Log.h" - #pragma pack(push, 1) -struct ServerPktHeader +union ServerPktHeader { - /** - * size is the length of the payload _plus_ the length of the opcode - */ - ServerPktHeader(uint32 size, uint16 cmd) : size(size) - { - uint8 headerIndex=0; - if (isLargePacket()) - { - TC_LOG_DEBUG("network", "initializing large server to client packet. Size: %u, cmd: %u", size, cmd); - header[headerIndex++] = 0x80 | (0xFF & (size >> 16)); - } - header[headerIndex++] = 0xFF &(size >> 8); - header[headerIndex++] = 0xFF & size; + static uint32 const SizeOf[2]; - header[headerIndex++] = 0xFF & cmd; - header[headerIndex++] = 0xFF & (cmd >> 8); - } - - uint8 getHeaderLength() + struct { - // cmd = 2 bytes, size= 2||3bytes - return 2 + (isLargePacket() ? 3 : 2); - } + uint16 Size; + uint32 Command; + } Setup; - bool isLargePacket() const + struct { - return size > 0x7FFF; - } - - const uint32 size; - uint8 header[5]; + uint32 Command : 13; + uint32 Size : 19; + } Normal; }; #pragma pack(pop) diff --git a/src/server/game/Server/WorldSocket.cpp b/src/server/game/Server/WorldSocket.cpp index 639f2234973..c26da27fc80 100644 --- a/src/server/game/Server/WorldSocket.cpp +++ b/src/server/game/Server/WorldSocket.cpp @@ -32,11 +32,18 @@ std::string const WorldSocket::ServerConnectionInitialize("WORLD OF WARCRAFT CON std::string const WorldSocket::ClientConnectionInitialize("WORLD OF WARCRAFT CONNECTION - CLIENT TO SERVER"); +uint32 const ClientPktHeader::SizeOf[2][2] = +{ + { 2, 0 }, + { 6, 4 } +}; + +uint32 const ServerPktHeader::SizeOf[2] = { sizeof(uint16) + sizeof(uint32), sizeof(uint32) }; WorldSocket::WorldSocket(tcp::socket&& socket) : Socket(std::move(socket)), _authSeed(rand32()), _OverSpeedPings(0), _worldSession(nullptr), _initialized(false) { - _headerBuffer.Resize(2); + _headerBuffer.Resize(ClientPktHeader::SizeOf[0][0]); } void WorldSocket::Start() @@ -44,8 +51,9 @@ void WorldSocket::Start() AsyncRead(); MessageBuffer initializer; - ServerPktHeader header(ServerConnectionInitialize.size(), 0); - initializer.Write(header.header, header.getHeaderLength() - 2); + ServerPktHeader header; + header.Setup.Size = ServerConnectionInitialize.size(); + initializer.Write(&header, sizeof(header.Setup.Size)); initializer.Write(ServerConnectionInitialize.c_str(), ServerConnectionInitialize.length()); std::unique_lock<std::mutex> dummy(_writeLock, std::defer_lock); @@ -122,38 +130,51 @@ void WorldSocket::ReadHandler() AsyncRead(); } +void WorldSocket::ExtractOpcodeAndSize(ClientPktHeader const* header, uint32& opcode, uint32& size) const +{ + if (_authCrypt.IsInitialized()) + { + opcode = header->Normal.Command; + size = header->Normal.Size; + } + else + { + opcode = header->Setup.Command; + size = header->Setup.Size; + if (_initialized) + size -= 4; + } +} + bool WorldSocket::ReadHeaderHandler() { - ASSERT(_headerBuffer.GetActiveSize() == (_initialized ? sizeof(ClientPktHeader) : 2)); + ASSERT(_headerBuffer.GetActiveSize() == ClientPktHeader::SizeOf[_initialized][_authCrypt.IsInitialized()], "Header size %u different than expected %u", _headerBuffer.GetActiveSize(), ClientPktHeader::SizeOf[_initialized][_authCrypt.IsInitialized()]); _authCrypt.DecryptRecv(_headerBuffer.GetReadPointer(), _headerBuffer.GetActiveSize()); ClientPktHeader* header = reinterpret_cast<ClientPktHeader*>(_headerBuffer.GetReadPointer()); - EndianConvertReverse(header->size); + uint32 opcode; + uint32 size; - if (_initialized) - EndianConvert(header->cmd); + ExtractOpcodeAndSize(header, opcode, size); - if (!header->IsValidSize() || (_initialized && !header->IsValidOpcode())) + if (!ClientPktHeader::IsValidSize(size) || (_initialized && !ClientPktHeader::IsValidOpcode(opcode))) { if (_worldSession) { Player* player = _worldSession->GetPlayer(); TC_LOG_ERROR("network", "WorldSocket::ReadHeaderHandler(): client (account: %u, char [GUID: %u, name: %s]) sent malformed packet (size: %hu, cmd: %u)", - _worldSession->GetAccountId(), player ? player->GetGUIDLow() : 0, player ? player->GetName().c_str() : "<none>", header->size, header->cmd); + _worldSession->GetAccountId(), player ? player->GetGUIDLow() : 0, player ? player->GetName().c_str() : "<none>", size, opcode); } else TC_LOG_ERROR("network", "WorldSocket::ReadHeaderHandler(): client %s sent malformed packet (size: %hu, cmd: %u)", - GetRemoteIpAddress().to_string().c_str(), header->size, header->cmd); + GetRemoteIpAddress().to_string().c_str(), size, opcode); CloseSocket(); return false; } - if (_initialized) - header->size -= sizeof(header->cmd); - - _packetBuffer.Resize(header->size); + _packetBuffer.Resize(size); return true; } @@ -162,8 +183,12 @@ bool WorldSocket::ReadDataHandler() if (_initialized) { ClientPktHeader* header = reinterpret_cast<ClientPktHeader*>(_headerBuffer.GetReadPointer()); + uint32 cmd; + uint32 size; - Opcodes opcode = Opcodes(header->cmd); + ExtractOpcodeAndSize(header, cmd, size); + + Opcodes opcode = Opcodes(cmd); std::string opcodeName = GetOpcodeNameForLogging(opcode); @@ -250,7 +275,7 @@ bool WorldSocket::ReadDataHandler() } _initialized = true; - _headerBuffer.Resize(sizeof(ClientPktHeader)); + _headerBuffer.Resize(ClientPktHeader::SizeOf[1][0]); _packetBuffer.Reset(); HandleSendAuthSession(); } @@ -271,24 +296,34 @@ void WorldSocket::SendPacket(WorldPacket& packet) TC_LOG_TRACE("network.opcode", "S->C: %s %s", (_worldSession ? _worldSession->GetPlayerInfo() : GetRemoteIpAddress().to_string()).c_str(), GetOpcodeNameForLogging(packet.GetOpcode()).c_str()); - ServerPktHeader header(packet.size() + 2, packet.GetOpcode()); - std::unique_lock<std::mutex> guard(_writeLock); - _authCrypt.EncryptSend(header.header, header.getHeaderLength()); + ServerPktHeader header; + uint32 sizeOfHeader = ServerPktHeader::SizeOf[_authCrypt.IsInitialized()]; + if (_authCrypt.IsInitialized()) + { + header.Normal.Size = packet.size(); + header.Normal.Command = packet.GetOpcode(); + _authCrypt.EncryptSend((uint8*)&header, sizeOfHeader); + } + else + { + header.Setup.Size = packet.size() + 4; + header.Setup.Command = packet.GetOpcode(); + } #ifndef TC_SOCKET_USE_IOCP - if (_writeQueue.empty() && _writeBuffer.GetRemainingSpace() >= header.getHeaderLength() + packet.size()) + if (_writeQueue.empty() && _writeBuffer.GetRemainingSpace() >= sizeOfHeader + packet.size()) { - _writeBuffer.Write(header.header, header.getHeaderLength()); + _writeBuffer.Write((uint8*)&header, sizeOfHeader); if (!packet.empty()) _writeBuffer.Write(packet.contents(), packet.size()); } else #endif { - MessageBuffer buffer(header.getHeaderLength() + packet.size()); - buffer.Write(header.header, header.getHeaderLength()); + MessageBuffer buffer(sizeOfHeader + packet.size()); + buffer.Write((uint8*)&header, sizeOfHeader); if (!packet.empty()) buffer.Write(packet.contents(), packet.size()); @@ -381,6 +416,7 @@ void WorldSocket::HandleAuthSession(WorldPacket& recvPacket) // even if auth credentials are bad, try using the session key we have - client cannot read auth response error without it _authCrypt.Init(&k); + _headerBuffer.Resize(ClientPktHeader::SizeOf[1][1]); // First reject the connection if packet contains invalid data or realm state doesn't allow logging in if (sWorld->IsClosed()) diff --git a/src/server/game/Server/WorldSocket.h b/src/server/game/Server/WorldSocket.h index 46614afd3bd..9928e0d5afa 100644 --- a/src/server/game/Server/WorldSocket.h +++ b/src/server/game/Server/WorldSocket.h @@ -34,13 +34,24 @@ using boost::asio::ip::tcp; #pragma pack(push, 1) -struct ClientPktHeader +union ClientPktHeader { - uint16 size; - uint32 cmd; - - bool IsValidSize() const { return size >= 4 && size < 10240; } - bool IsValidOpcode() const { return cmd < NUM_OPCODE_HANDLERS; } + static uint32 const SizeOf[2][2]; + + struct + { + uint16 Size; + uint32 Command; + } Setup; + + struct + { + uint32 Command : 13; + uint32 Size : 19; + } Normal; + + static bool IsValidSize(uint32 size) { return size < 10240; } + static bool IsValidOpcode(uint32 opcode) { return opcode < NUM_OPCODE_HANDLERS; } }; #pragma pack(pop) @@ -73,6 +84,8 @@ private: void HandlePing(WorldPacket& recvPacket); + void ExtractOpcodeAndSize(ClientPktHeader const* header, uint32& opcode, uint32& size) const; + uint32 _authSeed; WorldPacketCrypt _authCrypt; diff --git a/src/server/shared/Cryptography/Authentication/WorldPacketCrypt.cpp b/src/server/shared/Cryptography/Authentication/WorldPacketCrypt.cpp index b9d9b86005c..69198c18df0 100644 --- a/src/server/shared/Cryptography/Authentication/WorldPacketCrypt.cpp +++ b/src/server/shared/Cryptography/Authentication/WorldPacketCrypt.cpp @@ -28,11 +28,11 @@ WorldPacketCrypt::WorldPacketCrypt() : PacketCrypt(SHA_DIGEST_LENGTH) void WorldPacketCrypt::Init(BigNumber* K) { - uint8 ServerEncryptionKey[SEED_KEY_SIZE] = { 0xCC, 0x98, 0xAE, 0x04, 0xE8, 0x97, 0xEA, 0xCA, 0x12, 0xDD, 0xC0, 0x93, 0x42, 0x91, 0x53, 0x57 }; + uint8 ServerEncryptionKey[SEED_KEY_SIZE] = { 0x08, 0xF1, 0x95, 0x9F, 0x47, 0xE5, 0xD2, 0xDB, 0xA1, 0x3D, 0x77, 0x8F, 0x3F, 0x3E, 0xE7, 0x00 }; HmacSha1 serverEncryptHmac(SEED_KEY_SIZE, (uint8*)ServerEncryptionKey); uint8 *encryptHash = serverEncryptHmac.ComputeHash(K); - uint8 ServerDecryptionKey[SEED_KEY_SIZE] = { 0xC2, 0xB3, 0x72, 0x3C, 0xC6, 0xAE, 0xD9, 0xB5, 0x34, 0x3C, 0x53, 0xEE, 0x2F, 0x43, 0x67, 0xCE }; + uint8 ServerDecryptionKey[SEED_KEY_SIZE] = { 0x40, 0xAA, 0xD3, 0x92, 0x26, 0x71, 0x43, 0x47, 0x3A, 0x31, 0x08, 0xA6, 0xE7, 0xDC, 0x98, 0x2A }; HmacSha1 clientDecryptHmac(SEED_KEY_SIZE, (uint8*)ServerDecryptionKey); uint8 *decryptHash = clientDecryptHmac.ComputeHash(K); |
