TrinityCore
Warden.cpp
Go to the documentation of this file.
1/*
2 * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include "Warden.h"
19#include "AccountMgr.h"
20#include "ByteBuffer.h"
21#include "Common.h"
22#include "CryptoHash.h"
23#include "GameTime.h"
24#include "Log.h"
25#include "SmartEnum.h"
26#include "Util.h"
27#include "WardenPackets.h"
28#include "World.h"
29#include "WorldPacket.h"
30#include "WorldSession.h"
31#include <charconv>
32
33Warden::Warden() : _session(nullptr), _checkTimer(10 * IN_MILLISECONDS), _clientResponseTimer(0),
34 _dataSent(false), _initialized(false)
35{
36}
37
39{
40 _initialized = false;
41}
42
44{
45 TC_LOG_DEBUG("warden", "Make module for client");
47
48 _module->Id = Trinity::Crypto::MD5::GetDigestOf(_module->CompressedData, _module->CompressedSize);
49}
50
52{
53 TC_LOG_DEBUG("warden", "Send module to client");
54
55 // Create packet structure
57
58 uint32 sizeLeft = _module->CompressedSize;
59 uint32 pos = 0;
60 uint16 burstSize;
61 while (sizeLeft > 0)
62 {
63 burstSize = sizeLeft < 500 ? sizeLeft : 500;
65 packet.DataSize = burstSize;
66 memcpy(packet.Data, _module->CompressedData + pos, burstSize);
67 sizeLeft -= burstSize;
68 pos += burstSize;
69
70 EndianConvert(packet.DataSize);
71
72 EncryptData(reinterpret_cast<uint8*>(&packet), burstSize + 3);
73 WorldPacket pkt1(SMSG_WARDEN3_DATA, burstSize + 3);
74 pkt1.append(reinterpret_cast<uint8*>(&packet), burstSize + 3);
75 _session->SendPacket(&pkt1);
76 }
77}
78
80{
81 TC_LOG_DEBUG("warden", "Request module");
82
83 // Create packet structure
84 WardenModuleUse request;
86
87 request.ModuleId = _module->Id;
88 request.ModuleKey = _module->Key;
89 request.Size = _module->CompressedSize;
90
91 EndianConvert(request.Size);
92
93 // Encrypt with warden RC4 key.
94 EncryptData(reinterpret_cast<uint8*>(&request), sizeof(WardenModuleUse));
95
97 pkt.append(reinterpret_cast<uint8*>(&request), sizeof(WardenModuleUse));
98 _session->SendPacket(&pkt);
99}
100
102{
103 if (!_initialized)
104 return;
105
106 if (_dataSent)
107 {
108 uint32 maxClientResponseDelay = sWorld->getIntConfig(CONFIG_WARDEN_CLIENT_RESPONSE_DELAY);
109
110 if (maxClientResponseDelay > 0)
111 {
112 // Kick player if client response delays more than set in config
113 if (_clientResponseTimer > maxClientResponseDelay * IN_MILLISECONDS)
114 {
115 TC_LOG_WARN("warden", "{} (latency: {}, IP: {}) exceeded Warden module response delay ({}) - disconnecting client",
117 _session->KickPlayer("Warden::Update Warden module response delay exceeded");
118 }
119 else
120 _clientResponseTimer += diff;
121 }
122 }
123 else
124 {
125 if (diff >= _checkTimer)
127 else
128 _checkTimer -= diff;
129 }
130}
131
132void Warden::DecryptData(uint8* buffer, uint32 length)
133{
134 _inputCrypto.UpdateData(buffer, length);
135}
136
137void Warden::EncryptData(uint8* buffer, uint32 length)
138{
139 _outputCrypto.UpdateData(buffer, length);
140}
141
142bool Warden::IsValidCheckSum(uint32 checksum, uint8 const* data, const uint16 length)
143{
144 uint32 newChecksum = BuildChecksum(data, length);
145
146 if (checksum != newChecksum)
147 {
148 TC_LOG_DEBUG("warden", "CHECKSUM IS NOT VALID");
149 return false;
150 }
151 else
152 {
153 TC_LOG_DEBUG("warden", "CHECKSUM IS VALID");
154 return true;
155 }
156}
157
159{
160 std::array<uint8, 20> bytes;
161 std::array<uint32, 5> ints;
162};
163
165{
166 keyData hash;
167 hash.bytes = Trinity::Crypto::SHA1::GetDigestOf(data, size_t(length));
168 uint32 checkSum = 0;
169 for (uint8 i = 0; i < 5; ++i)
170 checkSum = checkSum ^ hash.ints[i];
171
172 return checkSum;
173}
174
175char const* Warden::ApplyPenalty(WardenCheck const* check)
176{
177 WardenActions action;
178
179 if (check)
180 action = check->Action;
181 else
183
184 switch (action)
185 {
187 _session->KickPlayer("Warden::Penalty");
188 break;
190 {
191 std::string accountName;
193 std::string banReason = "Warden Anticheat Violation";
194 // Check can be NULL, for example if the client sent a wrong signature in the warden packet (CHECKSUM FAIL)
195 if (check)
196 banReason += Trinity::StringFormat(": {} (CheckId: {}", check->Comment, check->CheckId);
197
198 sWorld->BanAccount(BAN_ACCOUNT, accountName, sWorld->getIntConfig(CONFIG_WARDEN_CLIENT_BAN_DURATION), banReason, "Server");
199
200 break;
201 }
203 default:
204 return "None";
205 }
206 return EnumUtils::ToTitle(action);
207}
208
210{
211 DecryptData(buff.contents(), buff.size());
212 uint8 opcode;
213 buff >> opcode;
214 TC_LOG_DEBUG("warden", "Got packet, opcode {:02X}, size {}", opcode, uint32(buff.size() - 1));
215 buff.hexlike();
216
217 switch (opcode)
218 {
221 break;
223 RequestHash();
224 break;
226 HandleCheckResult(buff);
227 break;
229 TC_LOG_DEBUG("warden", "NYI WARDEN_CMSG_MEM_CHECKS_RESULT received!");
230 break;
232 HandleHashResult(buff);
234 break;
236 TC_LOG_DEBUG("warden", "NYI WARDEN_CMSG_MODULE_FAILED received!");
237 break;
238 default:
239 TC_LOG_WARN("warden", "Got unknown warden opcode {:02X} of size {}.", opcode, uint32(buff.size() - 1));
240 break;
241 }
242}
243
244bool Warden::ProcessLuaCheckResponse(std::string const& msg)
245{
246 static constexpr char WARDEN_TOKEN[] = "_TW\t";
247 if (!StringStartsWith(msg, WARDEN_TOKEN))
248 return false;
249
250 uint16 id = 0;
251 std::from_chars(msg.data() + sizeof(WARDEN_TOKEN) - 1, msg.data() + msg.size(), id, 10);
252 if (id < sWardenCheckMgr->GetMaxValidCheckId())
253 {
254 WardenCheck const& check = sWardenCheckMgr->GetCheckData(id);
255 if (check.Type == LUA_EVAL_CHECK)
256 {
257 char const* penalty = ApplyPenalty(&check);
258 TC_LOG_WARN("warden", "{} failed Warden check {} ({}). Action: {}", _session->GetPlayerInfo(), id, EnumUtils::ToConstant(check.Type), penalty);
259 return true;
260 }
261 }
262
263 char const* penalty = ApplyPenalty(nullptr);
264 TC_LOG_WARN("warden", "{} sent bogus Lua check response for Warden. Action: {}", _session->GetPlayerInfo(), penalty);
265 return true;
266}
267
269{
270 if (!_warden || packet.Data.empty())
271 return;
272
273 _warden->HandleData(packet.Data);
274}
void EndianConvert(T &val)
Definition: ByteConverter.h:48
@ IN_MILLISECONDS
Definition: Common.h:35
uint8_t uint8
Definition: Define.h:144
uint16_t uint16
Definition: Define.h:143
uint32_t uint32
Definition: Define.h:142
#define TC_LOG_WARN(filterType__,...)
Definition: Log.h:162
#define TC_LOG_DEBUG(filterType__,...)
Definition: Log.h:156
@ BAN_ACCOUNT
std::string secsToTimeString(uint64 timeInSecs, TimeFormat timeFormat, bool hoursOnly)
Definition: Util.cpp:115
bool StringStartsWith(std::string_view haystack, std::string_view needle)
Definition: Util.h:398
#define sWardenCheckMgr
@ LUA_EVAL_CHECK
WardenActions
@ WARDEN_ACTION_KICK
@ WARDEN_ACTION_BAN
@ WARDEN_ACTION_LOG
@ WARDEN_CMSG_MODULE_MISSING
Definition: Warden.h:30
@ WARDEN_CMSG_HASH_RESULT
Definition: Warden.h:34
@ WARDEN_CMSG_MODULE_FAILED
Definition: Warden.h:35
@ WARDEN_CMSG_CHEAT_CHECKS_RESULT
Definition: Warden.h:32
@ WARDEN_CMSG_MODULE_OK
Definition: Warden.h:31
@ WARDEN_SMSG_MODULE_CACHE
Definition: Warden.h:39
@ WARDEN_SMSG_MODULE_USE
Definition: Warden.h:38
@ WARDEN_CMSG_MEM_CHECKS_RESULT
Definition: Warden.h:33
static bool GetName(uint32 accountId, std::string &name)
Definition: AccountMgr.cpp:319
void hexlike() const
Definition: ByteBuffer.cpp:177
void append(T value)
Definition: ByteBuffer.h:143
size_t size() const
Definition: ByteBuffer.h:536
bool empty() const
Definition: ByteBuffer.h:537
uint8 * contents()
Definition: ByteBuffer.h:522
static char const * ToConstant(Enum value)
Definition: SmartEnum.h:120
static char const * ToTitle(Enum value)
Definition: SmartEnum.h:123
void UpdateData(uint8 *data, size_t len)
Definition: ARC4.cpp:51
static Digest GetDigestOf(uint8 const *data, size_t len)
Definition: CryptoHash.h:49
Warden()
Definition: Warden.cpp:33
char const * ApplyPenalty(WardenCheck const *check)
Definition: Warden.cpp:175
virtual void InitializeModuleForClient(ClientWardenModule &module)=0
Optional< ClientWardenModule > _module
Definition: Warden.h:127
void EncryptData(uint8 *buffer, uint32 length)
Definition: Warden.cpp:137
uint32 _checkTimer
Definition: Warden.h:124
void DecryptData(uint8 *buffer, uint32 length)
Definition: Warden.cpp:132
uint32 _clientResponseTimer
Definition: Warden.h:125
void MakeModuleForClient()
Definition: Warden.cpp:43
bool ProcessLuaCheckResponse(std::string const &msg)
Definition: Warden.cpp:244
virtual void RequestHash()=0
void RequestModule()
Definition: Warden.cpp:79
Trinity::Crypto::ARC4 _outputCrypto
Definition: Warden.h:123
Trinity::Crypto::ARC4 _inputCrypto
Definition: Warden.h:122
void HandleData(ByteBuffer &buff)
Definition: Warden.cpp:209
static bool IsValidCheckSum(uint32 checksum, const uint8 *data, const uint16 length)
Definition: Warden.cpp:142
void SendModuleToClient()
Definition: Warden.cpp:51
bool _dataSent
Definition: Warden.h:126
void Update(uint32 diff)
Definition: Warden.cpp:101
virtual void InitializeModule()=0
bool _initialized
Definition: Warden.h:128
virtual void HandleCheckResult(ByteBuffer &buff)=0
static uint32 BuildChecksum(const uint8 *data, uint32 length)
Definition: Warden.cpp:164
virtual void RequestChecks()=0
WorldSession * _session
Definition: Warden.h:118
virtual void HandleHashResult(ByteBuffer &buff)=0
virtual ~Warden()
Definition: Warden.cpp:38
void HandleWardenData(WorldPackets::Warden::WardenData &packet)
Definition: Warden.cpp:268
std::string GetPlayerInfo() const
void KickPlayer(std::string const &reason)
Kick a player out of the World.
std::string const & GetRemoteAddress() const
void SendPacket(WorldPacket const *packet, bool forced=false)
Send a packet to the client.
uint32 GetAccountId() const
uint32 GetLatency() const
std::unique_ptr< Warden > _warden
@ SMSG_WARDEN3_DATA
Definition: Opcodes.h:2063
#define sWorld
Definition: World.h:931
@ CONFIG_WARDEN_CLIENT_BAN_DURATION
Definition: World.h:387
@ CONFIG_WARDEN_CLIENT_RESPONSE_DELAY
Definition: World.h:384
@ CONFIG_WARDEN_CLIENT_FAIL_ACTION
Definition: World.h:386
std::string StringFormat(FormatString< Args... > fmt, Args &&... args)
Default TC string format function.
Definition: StringFormat.h:38
WardenActions Action
std::string Comment
WardenCheckType Type
uint8 Data[500]
Definition: Warden.h:61
std::array< uint8, 16 > ModuleKey
Definition: Warden.h:52
uint8 Command
Definition: Warden.h:50
uint32 Size
Definition: Warden.h:53
std::array< uint8, 16 > ModuleId
Definition: Warden.h:51
std::array< uint32, 5 > ints
Definition: Warden.cpp:161
std::array< uint8, 20 > bytes
Definition: Warden.cpp:160