TrinityCore
Loading...
Searching...
No Matches
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 "Common.h"
19#include "WorldPacket.h"
20#include "WorldSession.h"
21#include "Log.h"
22#include "Opcodes.h"
23#include "ByteBuffer.h"
24#include "CryptoHash.h"
25#include "GameTime.h"
26#include "World.h"
27#include "Util.h"
28#include "Warden.h"
29#include "AccountMgr.h"
30#include <charconv>
31
32Warden::Warden() : _session(nullptr), _checkTimer(10 * IN_MILLISECONDS), _clientResponseTimer(0),
33 _dataSent(false), _initialized(false)
34{
35}
36
38{
39 _initialized = false;
40}
41
43{
44 TC_LOG_DEBUG("warden", "Make module for client");
46
47 _module->Id = Trinity::Crypto::MD5::GetDigestOf(_module->CompressedData, _module->CompressedSize);
48}
49
51{
52 TC_LOG_DEBUG("warden", "Send module to client");
53
54 // Create packet structure
56
57 uint32 sizeLeft = _module->CompressedSize;
58 uint32 pos = 0;
59 uint16 burstSize;
60 while (sizeLeft > 0)
61 {
62 burstSize = sizeLeft < 500 ? sizeLeft : 500;
64 packet.DataSize = burstSize;
65 memcpy(packet.Data, _module->CompressedData + pos, burstSize);
66 sizeLeft -= burstSize;
67 pos += burstSize;
68
69 EndianConvert(packet.DataSize);
70
71 EncryptData(reinterpret_cast<uint8*>(&packet), burstSize + 3);
72 WorldPacket pkt1(SMSG_WARDEN_DATA, burstSize + 3);
73 pkt1.append(reinterpret_cast<uint8*>(&packet), burstSize + 3);
74 _session->SendPacket(&pkt1);
75 }
76}
77
79{
80 TC_LOG_DEBUG("warden", "Request module");
81
82 // Create packet structure
83 WardenModuleUse request;
85
86 request.ModuleId = _module->Id;
87 request.ModuleKey = _module->Key;
88 request.Size = _module->CompressedSize;
89
90 EndianConvert(request.Size);
91
92 // Encrypt with warden RC4 key.
93 EncryptData(reinterpret_cast<uint8*>(&request), sizeof(WardenModuleUse));
94
96 pkt.append(reinterpret_cast<uint8*>(&request), sizeof(WardenModuleUse));
97 _session->SendPacket(&pkt);
98}
99
101{
102 if (!_initialized)
103 return;
104
105 if (_dataSent)
106 {
107 uint32 maxClientResponseDelay = sWorld->getIntConfig(CONFIG_WARDEN_CLIENT_RESPONSE_DELAY);
108
109 if (maxClientResponseDelay > 0)
110 {
111 // Kick player if client response delays more than set in config
112 if (_clientResponseTimer > maxClientResponseDelay * IN_MILLISECONDS)
113 {
114 TC_LOG_WARN("warden", "{} (latency: {}, IP: {}) exceeded Warden module response delay ({}) - disconnecting client",
116 _session->KickPlayer("Warden::Update Warden module response delay exceeded");
117 }
118 else
119 _clientResponseTimer += diff;
120 }
121 }
122 else
123 {
124 if (diff >= _checkTimer)
126 else
127 _checkTimer -= diff;
128 }
129}
130
131void Warden::DecryptData(uint8* buffer, uint32 length)
132{
133 _inputCrypto.UpdateData(buffer, length);
134}
135
136void Warden::EncryptData(uint8* buffer, uint32 length)
137{
138 _outputCrypto.UpdateData(buffer, length);
139}
140
141bool Warden::IsValidCheckSum(uint32 checksum, uint8 const* data, const uint16 length)
142{
143 uint32 newChecksum = BuildChecksum(data, length);
144
145 if (checksum != newChecksum)
146 {
147 TC_LOG_DEBUG("warden", "CHECKSUM IS NOT VALID");
148 return false;
149 }
150 else
151 {
152 TC_LOG_DEBUG("warden", "CHECKSUM IS VALID");
153 return true;
154 }
155}
156
158{
159 std::array<uint8, 20> bytes;
160 std::array<uint32, 5> ints;
161};
162
164{
165 keyData hash;
166 hash.bytes = Trinity::Crypto::SHA1::GetDigestOf(data, size_t(length));
167 uint32 checkSum = 0;
168 for (uint8 i = 0; i < 5; ++i)
169 checkSum = checkSum ^ hash.ints[i];
170
171 return checkSum;
172}
173
174char const* Warden::ApplyPenalty(WardenCheck const* check)
175{
176 WardenActions action;
177
178 if (check)
179 action = check->Action;
180 else
182
183 switch (action)
184 {
186 _session->KickPlayer("Warden::Penalty");
187 break;
189 {
190 std::string accountName;
192 std::stringstream banReason;
193 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 << ": " << check->Comment << " (CheckId: " << check->CheckId << ")";
197
198 sWorld->BanAccount(BAN_ACCOUNT, accountName, sWorld->getIntConfig(CONFIG_WARDEN_CLIENT_BAN_DURATION), banReason.str(),"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 || recvData.empty())
271 return;
272
273 _warden->HandleData(recvData);
274}
void EndianConvert(T &val)
@ IN_MILLISECONDS
Definition Common.h:35
uint8_t uint8
Definition Define.h:135
uint16_t uint16
Definition Define.h:134
uint32_t uint32
Definition Define.h:133
#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:363
#define sWardenCheckMgr
@ LUA_EVAL_CHECK
WardenActions
@ WARDEN_ACTION_KICK
@ WARDEN_ACTION_BAN
@ WARDEN_ACTION_LOG
@ WARDEN_CMSG_MODULE_MISSING
Definition Warden.h:31
@ WARDEN_CMSG_HASH_RESULT
Definition Warden.h:35
@ WARDEN_CMSG_MODULE_FAILED
Definition Warden.h:36
@ WARDEN_CMSG_CHEAT_CHECKS_RESULT
Definition Warden.h:33
@ WARDEN_CMSG_MODULE_OK
Definition Warden.h:32
@ WARDEN_SMSG_MODULE_CACHE
Definition Warden.h:40
@ WARDEN_SMSG_MODULE_USE
Definition Warden.h:39
@ WARDEN_CMSG_MEM_CHECKS_RESULT
Definition Warden.h:34
static bool GetName(uint32 accountId, std::string &name)
void hexlike() const
void append(T value)
Definition ByteBuffer.h:129
size_t size() const
Definition ByteBuffer.h:409
bool empty() const
Definition ByteBuffer.h:410
uint8 * contents()
Definition ByteBuffer.h:395
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:32
char const * ApplyPenalty(WardenCheck const *check)
Definition Warden.cpp:174
virtual void InitializeModuleForClient(ClientWardenModule &module)=0
Optional< ClientWardenModule > _module
Definition Warden.h:128
void EncryptData(uint8 *buffer, uint32 length)
Definition Warden.cpp:136
uint32 _checkTimer
Definition Warden.h:125
void DecryptData(uint8 *buffer, uint32 length)
Definition Warden.cpp:131
uint32 _clientResponseTimer
Definition Warden.h:126
void MakeModuleForClient()
Definition Warden.cpp:42
bool ProcessLuaCheckResponse(std::string const &msg)
Definition Warden.cpp:244
virtual void RequestHash()=0
void RequestModule()
Definition Warden.cpp:78
Trinity::Crypto::ARC4 _outputCrypto
Definition Warden.h:124
Trinity::Crypto::ARC4 _inputCrypto
Definition Warden.h:123
void HandleData(ByteBuffer &buff)
Definition Warden.cpp:209
static bool IsValidCheckSum(uint32 checksum, const uint8 *data, const uint16 length)
Definition Warden.cpp:141
void SendModuleToClient()
Definition Warden.cpp:50
bool _dataSent
Definition Warden.h:127
void Update(uint32 diff)
Definition Warden.cpp:100
virtual void InitializeModule()=0
bool _initialized
Definition Warden.h:129
virtual void HandleCheckResult(ByteBuffer &buff)=0
static uint32 BuildChecksum(const uint8 *data, uint32 length)
Definition Warden.cpp:163
virtual void RequestChecks()=0
WorldSession * _session
Definition Warden.h:119
virtual void HandleHashResult(ByteBuffer &buff)=0
virtual ~Warden()
Definition Warden.cpp:37
void SendPacket(WorldPacket const *packet)
Send a packet to the client.
void HandleWardenDataOpcode(WorldPacket &recvData)
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
uint32 GetAccountId() const
uint32 GetLatency() const
std::unique_ptr< Warden > _warden
@ SMSG_WARDEN_DATA
Definition Opcodes.h:771
#define sWorld
Definition World.h:900
@ CONFIG_WARDEN_CLIENT_BAN_DURATION
Definition World.h:361
@ CONFIG_WARDEN_CLIENT_RESPONSE_DELAY
Definition World.h:358
@ CONFIG_WARDEN_CLIENT_FAIL_ACTION
Definition World.h:360
WardenActions Action
std::string Comment
WardenCheckType Type
uint8 Data[500]
Definition Warden.h:62
std::array< uint8, 16 > ModuleKey
Definition Warden.h:53
uint8 Command
Definition Warden.h:51
uint32 Size
Definition Warden.h:54
std::array< uint8, 16 > ModuleId
Definition Warden.h:52
std::array< uint32, 5 > ints
Definition Warden.cpp:160
std::array< uint8, 20 > bytes
Definition Warden.cpp:159