aboutsummaryrefslogtreecommitdiff
path: root/src/server/game/Warden/Warden.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/server/game/Warden/Warden.cpp')
-rw-r--r--src/server/game/Warden/Warden.cpp234
1 files changed, 234 insertions, 0 deletions
diff --git a/src/server/game/Warden/Warden.cpp b/src/server/game/Warden/Warden.cpp
new file mode 100644
index 00000000000..3d625df63d0
--- /dev/null
+++ b/src/server/game/Warden/Warden.cpp
@@ -0,0 +1,234 @@
+/*
+ * Copyright (C) 2008-2012 TrinityCore <http://www.trinitycore.org/>
+ * Copyright (C) 2005-2011 MaNGOS <http://getmangos.com/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "Common.h"
+#include "WorldPacket.h"
+#include "WorldSession.h"
+#include "Log.h"
+#include "Opcodes.h"
+#include "ByteBuffer.h"
+#include <openssl/md5.h>
+#include <openssl/sha.h>
+#include "World.h"
+#include "Player.h"
+#include "Util.h"
+#include "Warden.h"
+#include "AccountMgr.h"
+
+Warden::Warden() : _inputCrypto(16), _outputCrypto(16), _checkTimer(10000/*10 sec*/), _clientResponseTimer(0), _dataSent(false), _initialized(false)
+{
+}
+
+Warden::~Warden()
+{
+ delete[] _module->CompressedData;
+ delete _module;
+ _module = NULL;
+ _initialized = false;
+}
+
+void Warden::SendModuleToClient()
+{
+ sLog->outDebug(LOG_FILTER_WARDEN, "Send module to client");
+
+ // Create packet structure
+ WardenModuleTransfer packet;
+
+ uint32 sizeLeft = _module->CompressedSize;
+ uint32 pos = 0;
+ uint16 burstSize;
+ while (sizeLeft > 0)
+ {
+ burstSize = sizeLeft < 500 ? sizeLeft : 500;
+ packet.Command = WARDEN_SMSG_MODULE_CACHE;
+ packet.DataSize = burstSize;
+ memcpy(packet.Data, &_module->CompressedData[pos], burstSize);
+ sizeLeft -= burstSize;
+ pos += burstSize;
+
+ EncryptData((uint8*)&packet, burstSize + 3);
+ WorldPacket pkt1(SMSG_WARDEN_DATA, burstSize + 3);
+ pkt1.append((uint8*)&packet, burstSize + 3);
+ _session->SendPacket(&pkt1);
+ }
+}
+
+void Warden::RequestModule()
+{
+ sLog->outDebug(LOG_FILTER_WARDEN, "Request module");
+
+ // Create packet structure
+ WardenModuleUse request;
+ request.Command = WARDEN_SMSG_MODULE_USE;
+
+ memcpy(request.ModuleId, _module->Id, 16);
+ memcpy(request.ModuleKey, _module->Key, 16);
+ request.Size = _module->CompressedSize;
+
+ // Encrypt with warden RC4 key.
+ EncryptData((uint8*)&request, sizeof(WardenModuleUse));
+
+ WorldPacket pkt(SMSG_WARDEN_DATA, sizeof(WardenModuleUse));
+ pkt.append((uint8*)&request, sizeof(WardenModuleUse));
+ _session->SendPacket(&pkt);
+}
+
+void Warden::Update()
+{
+ if (_initialized)
+ {
+ uint32 currentTimestamp = getMSTime();
+ uint32 diff = currentTimestamp - _previousTimestamp;
+ _previousTimestamp = currentTimestamp;
+
+ if (_dataSent)
+ {
+ uint32 maxClientResponseDelay = sWorld->getIntConfig(CONFIG_WARDEN_CLIENT_RESPONSE_DELAY);
+
+ if (maxClientResponseDelay > 0)
+ {
+ // Kick player if client response delays more than set in config
+ if (_clientResponseTimer > maxClientResponseDelay * IN_MILLISECONDS)
+ {
+ sLog->outWarden("WARDEN: Player %s (guid: %u, account: %u, latency: %u, IP: %s) exceeded Warden module response delay for more than %s - disconnecting client",
+ _session->GetPlayerName(), _session->GetGuidLow(), _session->GetAccountId(), _session->GetLatency(), _session->GetRemoteAddress().c_str(),
+ secsToTimeString(maxClientResponseDelay, true).c_str());
+ _session->KickPlayer();
+ }
+ else
+ _clientResponseTimer += diff;
+ }
+ }
+ else
+ {
+ if (diff >= _checkTimer)
+ {
+ RequestData();
+ }
+ else
+ _checkTimer -= diff;
+ }
+ }
+}
+
+void Warden::DecryptData(uint8* buffer, uint32 length)
+{
+ _inputCrypto.UpdateData(length, buffer);
+}
+
+void Warden::EncryptData(uint8* buffer, uint32 length)
+{
+ _outputCrypto.UpdateData(length, buffer);
+}
+
+bool Warden::IsValidCheckSum(uint32 checksum, const uint8* data, const uint16 length)
+{
+ uint32 newChecksum = BuildChecksum(data, length);
+
+ if (checksum != newChecksum)
+ {
+ sLog->outDebug(LOG_FILTER_WARDEN, "CHECKSUM IS NOT VALID");
+ return false;
+ }
+ else
+ {
+ sLog->outDebug(LOG_FILTER_WARDEN, "CHECKSUM IS VALID");
+ return true;
+ }
+}
+
+uint32 Warden::BuildChecksum(const uint8* data, uint32 length)
+{
+ uint8 hash[20];
+ SHA1(data, length, hash);
+ uint32 checkSum = 0;
+ for (uint8 i = 0; i < 5; ++i)
+ checkSum = checkSum ^ *(uint32*)(&hash[0] + i * 4);
+
+ return checkSum;
+}
+
+std::string Warden::Penalty(WardenCheck* check /*= NULL*/)
+{
+ WardenActions action;
+
+ if (check)
+ action = check->Action;
+ else
+ action = WardenActions(sWorld->getIntConfig(CONFIG_WARDEN_CLIENT_FAIL_ACTION));
+
+ switch (action)
+ {
+ case WARDEN_ACTION_LOG:
+ return "None";
+ break;
+ case WARDEN_ACTION_KICK:
+ _session->KickPlayer();
+ return "Kick";
+ break;
+ case WARDEN_ACTION_BAN:
+ {
+ std::stringstream duration;
+ duration << sWorld->getIntConfig(CONFIG_WARDEN_CLIENT_BAN_DURATION) << "s";
+ std::string accountName;
+ AccountMgr::GetName(_session->GetAccountId(), accountName);
+ sWorld->BanAccount(BAN_ACCOUNT, accountName, duration.str(), "Warden Anticheat violation","Server");
+
+ return "Ban";
+ break;
+ }
+ default:
+ return "Undefined";
+ break;
+ }
+}
+
+void WorldSession::HandleWardenDataOpcode(WorldPacket& recvData)
+{
+ _warden->DecryptData(const_cast<uint8*>(recvData.contents()), recvData.size());
+ uint8 opcode;
+ recvData >> opcode;
+ sLog->outDebug(LOG_FILTER_WARDEN, "Got packet, opcode %02X, size %u", opcode, recvData.size());
+ recvData.hexlike();
+
+ switch(opcode)
+ {
+ case WARDEN_CMSG_MODULE_MISSING:
+ _warden->SendModuleToClient();
+ break;
+ case WARDEN_CMSG_MODULE_OK:
+ _warden->RequestHash();
+ break;
+ case WARDEN_CMSG_CHEAT_CHECKS_RESULT:
+ _warden->HandleData(recvData);
+ break;
+ case WARDEN_CMSG_MEM_CHECKS_RESULT:
+ sLog->outDebug(LOG_FILTER_WARDEN, "NYI WARDEN_CMSG_MEM_CHECKS_RESULT received!");
+ break;
+ case WARDEN_CMSG_HASH_RESULT:
+ _warden->HandleHashResult(recvData);
+ _warden->InitializeModule();
+ break;
+ case WARDEN_CMSG_MODULE_FAILED:
+ sLog->outDebug(LOG_FILTER_WARDEN, "NYI WARDEN_CMSG_MODULE_FAILED received!");
+ break;
+ default:
+ sLog->outDebug(LOG_FILTER_WARDEN, "Got unknown warden opcode %02X of size %u.", opcode, recvData.size() - 1);
+ break;
+ }
+}