[Warden] Refactor to match other cores

This commit is contained in:
Antz 2020-01-09 22:33:56 +00:00 committed by Antz
parent 5e1e9ae18a
commit 377686f881
9 changed files with 262 additions and 245 deletions

View file

@ -4001,7 +4001,7 @@ void ObjectMgr::LoadQuests()
// 80 81 82 83 // 80 81 82 83
"`ReqCurrencyCount1`, `ReqCurrencyCount1`, `ReqCurrencyCount1`, `ReqCurrencyCount1`," "`ReqCurrencyCount1`, `ReqCurrencyCount1`, `ReqCurrencyCount1`, `ReqCurrencyCount1`,"
// 84 85 86 87 88 // 84 85 86 87 88
"`ReqSpellCast1`, `ReqSpellCast2`, `ReqSpellCast3`, `ReqSpellCast4`, `ReqSpellLearnedv`," "`ReqSpellCast1`, `ReqSpellCast2`, `ReqSpellCast3`, `ReqSpellCast4`, `ReqSpellLearned`,"
// 89 90 91 92 93 94 // 89 90 91 92 93 94
"`RewChoiceItemId1`, `RewChoiceItemId2`, `RewChoiceItemId3`, `RewChoiceItemId4`, `RewChoiceItemId5`, `RewChoiceItemId6`," "`RewChoiceItemId1`, `RewChoiceItemId2`, `RewChoiceItemId3`, `RewChoiceItemId4`, `RewChoiceItemId5`, `RewChoiceItemId6`,"
// 95 96 97 98 99 100 // 95 96 97 98 99 100

View file

@ -841,21 +841,30 @@ int WorldSocket::HandleAuthSession(WorldPacket& recvPacket)
{ {
// NOTE: ATM the socket is singlethread, have this in mind ... // NOTE: ATM the socket is singlethread, have this in mind ...
uint8 digest[20]; uint8 digest[20];
uint16 clientBuild, security; uint32 clientSeed, id, security;
uint32 id, m_addonSize, clientSeed, expansion; uint32 m_addonSize;
std::string accountName; uint16 BuiltNumberClient;
uint8 expansion = 0;
LocaleConstant locale; LocaleConstant locale;
std::string account;
Sha1Hash sha1; Sha1Hash sha1;
BigNumber v, s, g, N, K; BigNumber v, s, g, N, K;
std::string os;
WorldPacket packet; WorldPacket packet;
bool wardenActive = (sWorld.getConfig(CONFIG_BOOL_WARDEN_WIN_ENABLED) || sWorld.getConfig(CONFIG_BOOL_WARDEN_OSX_ENABLED));
// Read the content of the packet
recvPacket.read_skip<uint32>(); recvPacket.read_skip<uint32>();
recvPacket.read_skip<uint32>(); recvPacket.read_skip<uint32>();
recvPacket >> digest[18]; recvPacket >> digest[18];
recvPacket >> digest[14]; recvPacket >> digest[14];
recvPacket >> digest[3]; recvPacket >> digest[3];
recvPacket >> digest[4]; recvPacket >> BuiltNumberClient;
recvPacket >> digest[8];
recvPacket.read_skip<uint32>();
recvPacket.read_skip<uint8>();
recvPacket >> digest[17];
recvPacket >> digest[6];
recvPacket >> digest[0]; recvPacket >> digest[0];
recvPacket.read_skip<uint32>(); recvPacket.read_skip<uint32>();
recvPacket >> digest[11]; recvPacket >> digest[11];
@ -886,15 +895,21 @@ int WorldSocket::HandleAuthSession(WorldPacket& recvPacket)
addonsData.resize(m_addonSize); addonsData.resize(m_addonSize);
recvPacket.read((uint8*)addonsData.contents(), m_addonSize); recvPacket.read((uint8*)addonsData.contents(), m_addonSize);
accountName = recvPacket.ReadString(recvPacket.ReadBits(11)); uint8 nameLenLow, nameLenHigh;
recvPacket >> nameLenHigh;
recvPacket >> nameLenLow;
uint8 accNameLen = (nameLenHigh << 5) | (nameLenLow >> 3);
account = recvPacket.ReadString(accNameLen);
DEBUG_LOG("WorldSocket::HandleAuthSession: client build %u, account %s, clientseed %X", DEBUG_LOG("WorldSocket::HandleAuthSession: client build %u, account %s, clientseed %X",
clientBuild, BuiltNumberClient,
accountName.c_str(), account.c_str(),
clientSeed); clientSeed);
// Check the version of client trying to connect // Check the version of client trying to connect
if(!IsAcceptableClientBuild(clientBuild)) if (!IsAcceptableClientBuild(BuiltNumberClient))
{ {
SendAuthResponseError(AUTH_VERSION_MISMATCH); SendAuthResponseError(AUTH_VERSION_MISMATCH);
sLog.outError ("WorldSocket::HandleAuthSession: Sent Auth Response (version mismatch)."); sLog.outError ("WorldSocket::HandleAuthSession: Sent Auth Response (version mismatch).");
@ -902,7 +917,7 @@ int WorldSocket::HandleAuthSession(WorldPacket& recvPacket)
} }
// Get the account information from the realmd database // Get the account information from the realmd database
std::string safe_account = accountName; // Duplicate, else will screw the SHA hash verification below std::string safe_account = account; // Duplicate, else will screw the SHA hash verification below
LoginDatabase.escape_string (safe_account); LoginDatabase.escape_string (safe_account);
// No SQL injection, username escaped. // No SQL injection, username escaped.
@ -917,7 +932,8 @@ int WorldSocket::HandleAuthSession(WorldPacket& recvPacket)
"`s`, " // 6 "`s`, " // 6
"`expansion`, " // 7 "`expansion`, " // 7
"`mutetime`, " // 8 "`mutetime`, " // 8
"`locale` " // 9 "`locale`, " // 9
"`os` " // 10
"FROM `account` " "FROM `account` "
"WHERE `username` = '%s'", "WHERE `username` = '%s'",
safe_account.c_str()); safe_account.c_str());
@ -1017,7 +1033,7 @@ int WorldSocket::HandleAuthSession(WorldPacket& recvPacket)
uint32 t = 0; uint32 t = 0;
uint32 seed = m_Seed; uint32 seed = m_Seed;
sha.UpdateData (accountName); sha.UpdateData (account);
sha.UpdateData((uint8*) & t, 4); sha.UpdateData((uint8*) & t, 4);
sha.UpdateData((uint8*) & clientSeed, 4); sha.UpdateData((uint8*) & clientSeed, 4);
sha.UpdateData((uint8*) & seed, 4); sha.UpdateData((uint8*) & seed, 4);
@ -1042,7 +1058,7 @@ int WorldSocket::HandleAuthSession(WorldPacket& recvPacket)
static SqlStatementID updAccount; static SqlStatementID updAccount;
SqlStatement stmt = LoginDatabase.CreateStatement(updAccount, "UPDATE `account` SET `last_ip` = ? WHERE `username` = ?"); SqlStatement stmt = LoginDatabase.CreateStatement(updAccount, "UPDATE `account` SET `last_ip` = ? WHERE `username` = ?");
stmt.PExecute(address.c_str(), accountName.c_str()); stmt.PExecute(address.c_str(), account.c_str());
// NOTE ATM the socket is single-threaded, have this in mind ... // NOTE ATM the socket is single-threaded, have this in mind ...
ACE_NEW_RETURN(m_Session, WorldSession(id, this, AccountTypes(security), expansion, mutetime, locale), -1); ACE_NEW_RETURN(m_Session, WorldSession(id, this, AccountTypes(security), expansion, mutetime, locale), -1);
@ -1054,7 +1070,11 @@ int WorldSocket::HandleAuthSession(WorldPacket& recvPacket)
m_Session->ReadAddonsInfo(addonsData); m_Session->ReadAddonsInfo(addonsData);
// In case needed sometime the second arg is in microseconds 1 000 000 = 1 sec // In case needed sometime the second arg is in microseconds 1 000 000 = 1 sec
ACE_OS::sleep (ACE_Time_Value (0, 10000)); ACE_OS::sleep(ACE_Time_Value(0, 10000));
// Warden: Initialize Warden system only if it is enabled by config
if (wardenActive)
m_Session->InitWarden(uint16(BuiltNumberClient), &K, os);
sWorld.AddSession(m_Session); sWorld.AddSession(m_Session);

View file

@ -36,11 +36,12 @@
#include "AccountMgr.h" #include "AccountMgr.h"
Warden::Warden() : _session(NULL), _inputCrypto(16), _outputCrypto(16), _checkTimer(10000/*10 sec*/), _clientResponseTimer(0), Warden::Warden() : _session(NULL), _inputCrypto(16), _outputCrypto(16), _checkTimer(10000/*10 sec*/), _clientResponseTimer(0),
_dataSent(false), _previousTimestamp(0), _module(NULL), _initialized(false) _module(NULL), _state(WardenState::STATE_INITIAL)
{ {
memset(_inputKey, 0, sizeof(_inputKey)); memset(_inputKey, 0, sizeof(_inputKey));
memset(_outputKey, 0, sizeof(_outputKey)); memset(_outputKey, 0, sizeof(_outputKey));
memset(_seed, 0, sizeof(_seed)); memset(_seed, 0, sizeof(_seed));
_previousTimestamp = WorldTimer::getMSTime();
} }
Warden::~Warden() Warden::~Warden()
@ -48,7 +49,11 @@ Warden::~Warden()
delete[] _module->CompressedData; delete[] _module->CompressedData;
delete _module; delete _module;
_module = NULL; _module = NULL;
_initialized = false; }
void Warden::InitializeModule()
{
SetNewState(WardenState::STATE_INITIALIZE_MODULE);
} }
void Warden::RequestHash() void Warden::RequestHash()
@ -66,6 +71,8 @@ void Warden::RequestHash()
WorldPacket pkt(SMSG_WARDEN_DATA, sizeof(WardenHashRequest)); WorldPacket pkt(SMSG_WARDEN_DATA, sizeof(WardenHashRequest));
pkt.append((uint8*)&Request, sizeof(WardenHashRequest)); pkt.append((uint8*)&Request, sizeof(WardenHashRequest));
_session->SendPacket(&pkt); _session->SendPacket(&pkt);
SetNewState(WardenState::STATE_REQUESTED_HASH);
} }
void Warden::SendModuleToClient() void Warden::SendModuleToClient()
@ -92,6 +99,8 @@ void Warden::SendModuleToClient()
pkt1.append((uint8*)&packet, burstSize + 3); pkt1.append((uint8*)&packet, burstSize + 3);
_session->SendPacket(&pkt1); _session->SendPacket(&pkt1);
} }
SetNewState(WardenState::STATE_SENT_MODULE);
} }
void Warden::RequestModule() void Warden::RequestModule()
@ -112,17 +121,24 @@ void Warden::RequestModule()
WorldPacket pkt(SMSG_WARDEN_DATA, sizeof(WardenModuleUse)); WorldPacket pkt(SMSG_WARDEN_DATA, sizeof(WardenModuleUse));
pkt.append((uint8*)&request, sizeof(WardenModuleUse)); pkt.append((uint8*)&request, sizeof(WardenModuleUse));
_session->SendPacket(&pkt); _session->SendPacket(&pkt);
SetNewState(WardenState::STATE_REQUESTED_MODULE);
} }
void Warden::Update() void Warden::Update()
{ {
if (_initialized) uint32 currentTimestamp = WorldTimer::getMSTime();
{ uint32 diff = currentTimestamp - _previousTimestamp;
uint32 currentTimestamp = WorldTimer::getMSTime(); _previousTimestamp = currentTimestamp;
uint32 diff = currentTimestamp - _previousTimestamp;
_previousTimestamp = currentTimestamp;
if (_dataSent) switch (_state)
{
case WardenState::STATE_INITIAL:
break;
case WardenState::STATE_REQUESTED_MODULE:
case WardenState::STATE_SENT_MODULE:
case WardenState::STATE_REQUESTED_HASH:
case WardenState::STATE_REQUESTED_DATA:
{ {
uint32 maxClientResponseDelay = sWorld.getConfig(CONFIG_UINT32_WARDEN_CLIENT_RESPONSE_DELAY); uint32 maxClientResponseDelay = sWorld.getConfig(CONFIG_UINT32_WARDEN_CLIENT_RESPONSE_DELAY);
@ -131,23 +147,34 @@ void Warden::Update()
// Kick player if client response delays more than set in config // Kick player if client response delays more than set in config
if (_clientResponseTimer > maxClientResponseDelay * IN_MILLISECONDS) if (_clientResponseTimer > maxClientResponseDelay * IN_MILLISECONDS)
{ {
sLog.outWarden("%s (latency: %u, IP: %s) exceeded Warden module response delay for more than %s - disconnecting client", sLog.outWarden("%s (latency: %u, IP: %s) exceeded Warden module response delay on state %s for more than %s - disconnecting client",
_session->GetPlayerName(), _session->GetLatency(), _session->GetRemoteAddress().c_str(), secsToTimeString(maxClientResponseDelay, true).c_str()); _session->GetPlayerName(), _session->GetLatency(), _session->GetRemoteAddress().c_str(), WardenState::to_string(_state), secsToTimeString(maxClientResponseDelay, true).c_str());
_session->KickPlayer(); _session->KickPlayer();
} }
else else
{
_clientResponseTimer += diff; _clientResponseTimer += diff;
}
} }
} }
else break;
case WardenState::STATE_INITIALIZE_MODULE:
case WardenState::STATE_RESTING:
{ {
if (diff >= _checkTimer) if (diff >= _checkTimer)
{ {
RequestData(); RequestData();
} }
else else
{
_checkTimer -= diff; _checkTimer -= diff;
}
} }
break;
default:
sLog.outWarden("Unimplemented warden state!");
break;
} }
} }
@ -161,6 +188,28 @@ void Warden::EncryptData(uint8* buffer, uint32 length)
_outputCrypto.UpdateData(length, buffer); _outputCrypto.UpdateData(length, buffer);
} }
void Warden::SetNewState(WardenState::Value state)
{
//if we pass all initial checks, allow change
if (state < WardenState::STATE_REQUESTED_DATA)
{
if (state < _state)
{
sLog.outWarden("Warden Error: jump from %s to %s which is lower by initialization routine", WardenState::to_string(_state), WardenState::to_string(state));
return;
}
}
_state = state;
//Reset timers
// Set hold off timer, minimum timer should at least be 1 second
uint32 holdOff = sWorld.getConfig(CONFIG_UINT32_WARDEN_CLIENT_CHECK_HOLDOFF);
_checkTimer = (holdOff < 1 ? 1 : holdOff) * IN_MILLISECONDS;
_clientResponseTimer = 0;
}
bool Warden::IsValidCheckSum(uint32 checksum, const uint8* data, const uint16 length) bool Warden::IsValidCheckSum(uint32 checksum, const uint8* data, const uint16 length)
{ {
uint32 newChecksum = BuildChecksum(data, length); uint32 newChecksum = BuildChecksum(data, length);
@ -284,11 +333,14 @@ void WorldSession::HandleWardenDataOpcode(WorldPacket& recvData)
} }
} }
void Warden::RequestData()
{
SetNewState(WardenState::STATE_REQUESTED_DATA);
}
void Warden::HandleData(ByteBuffer& /*buff*/) void Warden::HandleData(ByteBuffer& /*buff*/)
{ {
// Set hold off timer, minimum timer should at least be 1 second SetNewState(WardenState::STATE_RESTING);
uint32 holdOff = sWorld.getConfig(CONFIG_UINT32_WARDEN_CLIENT_CHECK_HOLDOFF);
_checkTimer = (holdOff < 1 ? 1 : holdOff) * IN_MILLISECONDS;
} }
void Warden::LogPositiveToDB(WardenCheck* check) void Warden::LogPositiveToDB(WardenCheck* check)

View file

@ -34,7 +34,7 @@
#include "Database/DatabaseEnv.h" #include "Database/DatabaseEnv.h"
// the default client version with info in warden_checks; for other version checks, see warden_build_specific // the default client version with info in warden_checks; for other version checks, see warden_build_specific
#define DEFAULT_CLIENT_BUILD 5875 #define DEFAULT_CLIENT_BUILD 12340
enum WardenOpcodes enum WardenOpcodes
{ {
@ -95,6 +95,42 @@ struct WardenHashRequest
uint8 Seed[16]; uint8 Seed[16];
}; };
namespace WardenState
{
enum Value
{
STATE_INITIAL,
STATE_REQUESTED_MODULE,
STATE_SENT_MODULE,
STATE_REQUESTED_HASH,
STATE_INITIALIZE_MODULE,
STATE_REQUESTED_DATA,
STATE_RESTING
};
inline const char* to_string(WardenState::Value value)
{
switch (value)
{
case WardenState::STATE_INITIAL:
return "STATE_INITIAL";
case WardenState::STATE_REQUESTED_MODULE:
return "STATE_REQUESTED_MODULE";
case WardenState::STATE_SENT_MODULE:
return "STATE_SENT_MODULE";
case WardenState::STATE_REQUESTED_HASH:
return "STATE_REQUESTED_HASH";
case WardenState::STATE_INITIALIZE_MODULE:
return "STATE_INITIALIZE_MODULE";
case WardenState::STATE_REQUESTED_DATA:
return "STATE_REQUESTED_DATA";
case WardenState::STATE_RESTING:
return "STATE_RESTING";
}
return "UNDEFINED STATE";
}
};
#if defined(__GNUC__) #if defined(__GNUC__)
#pragma pack() #pragma pack()
#else #else
@ -119,10 +155,10 @@ class Warden
virtual void Init(WorldSession* session, BigNumber* k) = 0; virtual void Init(WorldSession* session, BigNumber* k) = 0;
virtual ClientWardenModule* GetModuleForClient() = 0; virtual ClientWardenModule* GetModuleForClient() = 0;
virtual void InitializeModule() = 0; virtual void InitializeModule();
virtual void RequestHash(); virtual void RequestHash();
virtual void HandleHashResult(ByteBuffer &buff) = 0; virtual void HandleHashResult(ByteBuffer &buff) = 0;
virtual void RequestData() = 0; virtual void RequestData();
virtual void HandleData(ByteBuffer &buff); virtual void HandleData(ByteBuffer &buff);
void SendModuleToClient(); void SendModuleToClient();
@ -131,6 +167,8 @@ class Warden
void DecryptData(uint8* buffer, uint32 length); void DecryptData(uint8* buffer, uint32 length);
void EncryptData(uint8* buffer, uint32 length); void EncryptData(uint8* buffer, uint32 length);
void SetNewState(WardenState::Value state);
static bool IsValidCheckSum(uint32 checksum, const uint8 *data, const uint16 length); static bool IsValidCheckSum(uint32 checksum, const uint8 *data, const uint16 length);
static uint32 BuildChecksum(const uint8 *data, uint32 length); static uint32 BuildChecksum(const uint8 *data, uint32 length);
@ -148,10 +186,9 @@ class Warden
ARC4 _outputCrypto; ARC4 _outputCrypto;
uint32 _checkTimer; // Timer for sending check requests uint32 _checkTimer; // Timer for sending check requests
uint32 _clientResponseTimer; // Timer for client response delay uint32 _clientResponseTimer; // Timer for client response delay
bool _dataSent;
uint32 _previousTimestamp; uint32 _previousTimestamp;
ClientWardenModule* _module; ClientWardenModule* _module;
bool _initialized; WardenState::Value _state;
}; };
#endif #endif

View file

@ -32,19 +32,18 @@
#include "WardenCheckMgr.h" #include "WardenCheckMgr.h"
#include "Warden.h" #include "Warden.h"
WardenCheckMgr::WardenCheckMgr() { } WardenCheckMgr::WardenCheckMgr() : m_lock(0), CheckStore(), CheckResultStore() { }
WardenCheckMgr::~WardenCheckMgr() WardenCheckMgr::~WardenCheckMgr()
{ {
for (uint16 i = 0; i < CheckStore.size(); ++i) for (CheckMap::iterator it = CheckStore.begin(); it != CheckStore.end(); ++it)
{ delete it->second;
delete CheckStore[i];
}
for (CheckResultContainer::iterator itr = CheckResultStore.begin(); itr != CheckResultStore.end(); ++itr) for (CheckResultMap::iterator it = CheckResultStore.begin(); it != CheckResultStore.end(); ++it)
{ delete it->second;
delete itr->second;
} CheckStore.clear();
CheckResultStore.clear();
} }
void WardenCheckMgr::LoadWardenChecks() void WardenCheckMgr::LoadWardenChecks()
@ -52,48 +51,34 @@ void WardenCheckMgr::LoadWardenChecks()
// Check if Warden is enabled by config before loading anything // Check if Warden is enabled by config before loading anything
if (!sWorld.getConfig(CONFIG_BOOL_WARDEN_WIN_ENABLED) && !sWorld.getConfig(CONFIG_BOOL_WARDEN_OSX_ENABLED)) if (!sWorld.getConfig(CONFIG_BOOL_WARDEN_WIN_ENABLED) && !sWorld.getConfig(CONFIG_BOOL_WARDEN_OSX_ENABLED))
{ {
sLog.outWarden(">> Warden disabled, loading checks skipped."); sLog.outString(">> Warden disabled, loading checks skipped.");
return; return;
} }
// 0 1 2 3 4 5 6 7 8
QueryResult *result = WorldDatabase.Query("SELECT MAX(`id`) FROM `warden_checks`"); QueryResult *result = WorldDatabase.Query("SELECT id, build, type, data, result, address, length, str, comment FROM warden ORDER BY build ASC, id ASC");
if (!result) if (!result)
{ {
sLog.outWarden(">> Loaded 0 Warden checks. DB table `warden_checks` is empty!"); sLog.outString("[Warden]: >> Loaded 0 warden data and results");
return; return;
} }
Field* fields = result->Fetch();
uint16 maxCheckId = fields[0].GetUInt16();
CheckStore.resize(maxCheckId + 1);
delete result;
// 0 1 2 3 4 5 6 7
result = WorldDatabase.Query("SELECT id, type, data, result, address, length, str, comment FROM warden_checks ORDER BY id ASC");
uint32 count = 0; uint32 count = 0;
Field* fields;
if (!result)
{
sLog.outString("[Warden]: >> Loaded %u warden data and results", count);
return;
}
do do
{ {
fields = result->Fetch(); fields = result->Fetch();
uint16 id = fields[0].GetUInt16(); uint16 id = fields[0].GetUInt16();
uint8 checkType = fields[1].GetUInt8(); uint16 build = fields[1].GetUInt16();
std::string data = fields[2].GetString(); uint8 checkType = fields[2].GetUInt8();
std::string checkResult = fields[3].GetString(); std::string data = fields[3].GetString();
uint32 address = fields[4].GetUInt32(); std::string checkResult = fields[4].GetString();
uint8 length = fields[5].GetUInt8(); uint32 address = fields[5].GetUInt32();
std::string str = fields[6].GetString(); uint8 length = fields[6].GetUInt8();
std::string comment = fields[7].GetString(); std::string str = fields[7].GetString();
std::string comment = fields[8].GetString();
WardenCheck* wardenCheck = new WardenCheck(); WardenCheck* wardenCheck = new WardenCheck();
wardenCheck->Type = checkType; wardenCheck->Type = checkType;
@ -117,11 +102,6 @@ void WardenCheckMgr::LoadWardenChecks()
} }
} }
if (checkType == MEM_CHECK || checkType == MODULE_CHECK)
MemChecksIdPool.push_back(id);
else
OtherChecksIdPool.push_back(id);
if (checkType == MEM_CHECK || checkType == PAGE_CHECK_A || checkType == PAGE_CHECK_B || checkType == PROC_CHECK) if (checkType == MEM_CHECK || checkType == PAGE_CHECK_A || checkType == PAGE_CHECK_B || checkType == PROC_CHECK)
{ {
wardenCheck->Address = address; wardenCheck->Address = address;
@ -132,11 +112,12 @@ void WardenCheckMgr::LoadWardenChecks()
if (checkType == MEM_CHECK || checkType == MPQ_CHECK || checkType == LUA_STR_CHECK || checkType == DRIVER_CHECK || checkType == MODULE_CHECK) if (checkType == MEM_CHECK || checkType == MPQ_CHECK || checkType == LUA_STR_CHECK || checkType == DRIVER_CHECK || checkType == MODULE_CHECK)
wardenCheck->Str = str; wardenCheck->Str = str;
CheckStore[id] = wardenCheck; CheckStore.insert(std::pair<uint16, WardenCheck*>(build, wardenCheck));
if (checkType == MPQ_CHECK || checkType == MEM_CHECK) if (checkType == MPQ_CHECK || checkType == MEM_CHECK)
{ {
WardenCheckResult* wr = new WardenCheckResult(); WardenCheckResult* wr = new WardenCheckResult();
wr->Id = id;
wr->Result.SetHexStr(checkResult.c_str()); wr->Result.SetHexStr(checkResult.c_str());
int len = checkResult.size() / 2; int len = checkResult.size() / 2;
if (wr->Result.GetNumBytes() < len) if (wr->Result.GetNumBytes() < len)
@ -148,7 +129,7 @@ void WardenCheckMgr::LoadWardenChecks()
wr->Result.SetBinary((uint8*)temp, len); wr->Result.SetBinary((uint8*)temp, len);
delete[] temp; delete[] temp;
} }
CheckResultStore[id] = wr; CheckResultStore.insert(std::pair<uint16, WardenCheckResult*>(build, wr));
} }
if (comment.empty()) if (comment.empty())
@ -159,82 +140,9 @@ void WardenCheckMgr::LoadWardenChecks()
++count; ++count;
} while (result->NextRow()); } while (result->NextRow());
sLog.outWarden(">> Loaded %u warden checks.", count); sLog.outString(">> Loaded %u warden checks.", count);
delete result; delete result;
// 0 1 2 3 4 5 6
result = WorldDatabase.Query("SELECT id, build, data, result, address, length, str FROM warden_build_specific ORDER BY id ASC");
if (!result)
{
sLog.outString("[Warden]: >> Loaded 0 warden client build-specific data.");
return;
}
count = 0;
do
{
fields = result->Fetch();
uint16 id = fields[0].GetUInt16();
if (id >= CheckStore.size())
{
sLog.outWarden("ERROR: Build-specific, check is missing in warden_checks, skipping id %u.", id);
continue;
}
uint16 build = fields[1].GetUInt16();
if (build == DEFAULT_CLIENT_BUILD)
{
sLog.outWarden("ERROR: Build-specific table may not contain checks for default %u build, skipping id %u.", DEFAULT_CLIENT_BUILD, id);
continue;
}
//std::string data = fields[2].GetString(); //unused for now
std::string checkResult = fields[3].GetString();
uint32 address = fields[4].GetUInt32();
uint8 length = fields[5].GetUInt8();
std::string str = fields[6].GetString();
WardenCheck* wardenCheck = new WardenCheck();
wardenCheck->CheckId = id;
wardenCheck->Type = CheckStore[id]->Type;
WardenCheckResult* wr = new WardenCheckResult();
switch (wardenCheck->Type)
{
case MEM_CHECK:
wardenCheck->Address = address;
wardenCheck->Length = length;
wardenCheck->Str = str;
wr->Result.SetHexStr(checkResult.c_str());
{
int len = checkResult.size() / 2;
if (wr->Result.GetNumBytes() < len)
{
uint8 *temp = new uint8[len];
memset(temp, 0, len);
memcpy(temp, wr->Result.AsByteArray(), wr->Result.GetNumBytes());
std::reverse(temp, temp + len);
wr->Result.SetBinary((uint8*)temp, len);
delete[] temp;
}
}
break;
default:
sLog.outWarden("The check type %u is considered as build-independent, skipping id %u.", wardenCheck->Type, id);
delete wr;
delete wardenCheck;
continue;
}
MCheckStore[ComposeMultiCheckKey(build, id)] = wardenCheck;
MCheckResultStore[ComposeMultiCheckKey(build, id)] = wr;
++count;
} while (result->NextRow());
sLog.outString(">> Loaded %u warden client build-specific check overrides.", count);
} }
void WardenCheckMgr::LoadWardenOverrides() void WardenCheckMgr::LoadWardenOverrides()
@ -242,22 +150,22 @@ void WardenCheckMgr::LoadWardenOverrides()
// Check if Warden is enabled by config before loading anything // Check if Warden is enabled by config before loading anything
if (!sWorld.getConfig(CONFIG_BOOL_WARDEN_WIN_ENABLED) && !sWorld.getConfig(CONFIG_BOOL_WARDEN_OSX_ENABLED)) if (!sWorld.getConfig(CONFIG_BOOL_WARDEN_WIN_ENABLED) && !sWorld.getConfig(CONFIG_BOOL_WARDEN_OSX_ENABLED))
{ {
sLog.outWarden(">> Warden disabled, loading check overrides skipped."); sLog.outString(">> Warden disabled, loading check overrides skipped.");
return; return;
} }
// 0 1 // 0 1
QueryResult* result = CharacterDatabase.Query("SELECT `wardenId`, `action` FROM `warden_action`"); QueryResult* result = CharacterDatabase.Query("SELECT wardenId, action FROM warden_action");
if (!result) if (!result)
{ {
sLog.outWarden(">> Loaded 0 Warden action overrides. DB table `warden_action` is empty!"); sLog.outString(">> Loaded 0 Warden action overrides. DB table `warden_action` is empty!");
return; return;
} }
uint32 count = 0; uint32 count = 0;
ACE_WRITE_GUARD(ACE_RW_Mutex, g, _checkStoreLock); ACE_WRITE_GUARD(LOCK, g, m_lock)
do do
{ {
@ -269,54 +177,68 @@ void WardenCheckMgr::LoadWardenOverrides()
// Check if action value is in range (0-2, see WardenActions enum) // Check if action value is in range (0-2, see WardenActions enum)
if (action > WARDEN_ACTION_BAN) if (action > WARDEN_ACTION_BAN)
sLog.outWarden("Warden check override action out of range (ID: %u, action: %u)", checkId, action); sLog.outWarden("Warden check override action out of range (ID: %u, action: %u)", checkId, action);
// Check if check actually exists before accessing the CheckStore vector
else if (checkId > CheckStore.size())
sLog.outWarden("Warden check action override for non-existing check (ID: %u, action: %u), skipped", checkId, action);
else else
{ {
CheckStore[checkId]->Action = WardenActions(action); bool found = false;
++count; for (CheckMap::iterator it = CheckStore.begin(); it != CheckStore.end(); ++it)
{
if (it->second->CheckId == checkId)
{
it->second->Action = WardenActions(action);
++count;
found = true;
}
}
if (!found)
sLog.outWarden("Warden check action override for non-existing check (ID: %u, action: %u), skipped", checkId, action);
} }
} }
while (result->NextRow()); while (result->NextRow());
sLog.outWarden(">> Loaded %u warden action overrides.", count); sLog.outString(">> Loaded %u warden action overrides.", count);
} }
WardenCheck* WardenCheckMgr::GetWardenDataById(uint16 build, uint16 Id) WardenCheck* WardenCheckMgr::GetWardenDataById(uint16 build, uint16 id)
{ {
if (Id < CheckStore.size()) WardenCheck* result = NULL;
ACE_READ_GUARD_RETURN(LOCK, g, m_lock, result)
for (CheckMap::iterator it = CheckStore.lower_bound(build); it != CheckStore.upper_bound(build); ++it)
{ {
if (build != DEFAULT_CLIENT_BUILD) if (it->second->CheckId == id)
{ result = it->second;
MultiCheckContainer::const_iterator it = MCheckStore.find(ComposeMultiCheckKey(build, Id));
if (it != MCheckStore.end())
{
return it->second;
}
}
return CheckStore[Id];
} }
return NULL; return result;
} }
WardenCheckResult* WardenCheckMgr::GetWardenResultById(uint16 build, uint16 Id) WardenCheckResult* WardenCheckMgr::GetWardenResultById(uint16 build, uint16 id)
{ {
if (build != DEFAULT_CLIENT_BUILD) WardenCheckResult* result = NULL;
ACE_READ_GUARD_RETURN(LOCK, g, m_lock, result)
for (CheckResultMap::iterator it = CheckResultStore.lower_bound(build); it != CheckResultStore.upper_bound(build); ++it)
{ {
MultiResultContainer::const_iterator it = MCheckResultStore.find(ComposeMultiCheckKey(build, Id)); if (it->second->Id == id)
if (it != MCheckResultStore.end()) result = it->second;
{
return it->second;
}
} }
CheckResultContainer::const_iterator itr = CheckResultStore.find(Id); return result;
if (itr != CheckResultStore.end()) }
{
return itr->second; void WardenCheckMgr::GetWardenCheckIds(bool isMemCheck, uint16 build, std::list<uint16>& idl)
} {
idl.clear(); //just to be sure
return NULL;
ACE_READ_GUARD(LOCK, g, m_lock)
for (CheckMap::iterator it = CheckStore.lower_bound(build); it != CheckStore.upper_bound(build); ++it)
{
if (isMemCheck)
{
if ((it->second->Type == MEM_CHECK) || (it->second->Type == MODULE_CHECK))
idl.push_back(it->second->CheckId);
}
else
idl.push_back(it->second->CheckId);
}
} }

View file

@ -50,6 +50,7 @@ struct WardenCheck
struct WardenCheckResult struct WardenCheckResult
{ {
uint16 Id;
BigNumber Result; // MEM_CHECK BigNumber Result; // MEM_CHECK
}; };
@ -66,33 +67,22 @@ class WardenCheckMgr
return &instance; return &instance;
} }
WardenCheck* GetWardenDataById(uint16 build, uint16 Id); WardenCheck* GetWardenDataById(uint16 /*build*/, uint16 /*id*/);
WardenCheckResult* GetWardenResultById(uint16 build, uint16 Id); WardenCheckResult* GetWardenResultById(uint16 /*build*/, uint16 /*id*/);
void GetWardenCheckIds(bool isMemCheck /* true = MEM */, uint16 build, std::list<uint16>& list);
std::vector<uint16> MemChecksIdPool;
std::vector<uint16> OtherChecksIdPool;
void LoadWardenChecks(); void LoadWardenChecks();
void LoadWardenOverrides(); void LoadWardenOverrides();
ACE_RW_Mutex _checkStoreLock;
private: private:
uint32 inline ComposeMultiCheckKey(uint16 clientBuild, uint16 checkID) { return (uint32(checkID) << 16) | clientBuild; } typedef ACE_RW_Thread_Mutex LOCK;
typedef std::multimap< uint16, WardenCheck* > CheckMap;
typedef std::multimap< uint16, WardenCheckResult* > CheckResultMap;
// We have a linear key without any gaps, so we use vector for fast access LOCK m_lock;
typedef std::vector<WardenCheck*> CheckContainer; CheckMap CheckStore;
typedef std::map<uint32, WardenCheckResult*> CheckResultContainer; CheckResultMap CheckResultStore;
CheckContainer CheckStore;
CheckResultContainer CheckResultStore;
// here we have just few checks, vector is not appropriate; key is from ComposeMultiCheckKey
typedef std::map<uint32 /*MultiCheckKey*/, WardenCheck*> MultiCheckContainer;
typedef std::map<uint32 /*MultiCheckKey*/, WardenCheckResult*> MultiResultContainer;
MultiCheckContainer MCheckStore;
MultiResultContainer MCheckResultStore;
}; };
#define sWardenCheckMgr WardenCheckMgr::instance() #define sWardenCheckMgr WardenCheckMgr::instance()

View file

@ -98,6 +98,7 @@ ClientWardenModule* WardenMac::GetModuleForClient()
void WardenMac::InitializeModule() void WardenMac::InitializeModule()
{ {
sLog.outWarden("Initialize module"); sLog.outWarden("Initialize module");
Warden::InitializeModule();
} }
struct keyData { struct keyData {
@ -174,8 +175,6 @@ void WardenMac::HandleHashResult(ByteBuffer &buff)
_inputCrypto.Init(_inputKey); _inputCrypto.Init(_inputKey);
_outputCrypto.Init(_outputKey); _outputCrypto.Init(_outputKey);
_initialized = true;
_previousTimestamp = WorldTimer::getMSTime(); _previousTimestamp = WorldTimer::getMSTime();
} }
@ -200,16 +199,13 @@ void WardenMac::RequestData()
pkt.append(buff); pkt.append(buff);
_session->SendPacket(&pkt); _session->SendPacket(&pkt);
_dataSent = true; Warden::RequestData();
} }
void WardenMac::HandleData(ByteBuffer &buff) void WardenMac::HandleData(ByteBuffer &buff)
{ {
sLog.outWarden("Handle data"); sLog.outWarden("Handle data");
_dataSent = false;
_clientResponseTimer = 0;
//uint16 Length; //uint16 Length;
//buff >> Length; //buff >> Length;
//uint32 Checksum; //uint32 Checksum;

View file

@ -132,6 +132,8 @@ void WardenWin::InitializeModule()
WorldPacket pkt(SMSG_WARDEN_DATA, sizeof(WardenInitModuleRequest)); WorldPacket pkt(SMSG_WARDEN_DATA, sizeof(WardenInitModuleRequest));
pkt.append((uint8*)&Request, sizeof(WardenInitModuleRequest)); pkt.append((uint8*)&Request, sizeof(WardenInitModuleRequest));
_session->SendPacket(&pkt); _session->SendPacket(&pkt);
Warden::InitializeModule();
} }
void WardenWin::HandleHashResult(ByteBuffer &buff) void WardenWin::HandleHashResult(ByteBuffer &buff)
@ -154,8 +156,6 @@ void WardenWin::HandleHashResult(ByteBuffer &buff)
_inputCrypto.Init(_inputKey); _inputCrypto.Init(_inputKey);
_outputCrypto.Init(_outputKey); _outputCrypto.Init(_outputKey);
_initialized = true;
_previousTimestamp = WorldTimer::getMSTime(); _previousTimestamp = WorldTimer::getMSTime();
} }
@ -163,18 +163,20 @@ void WardenWin::RequestData()
{ {
sLog.outWarden("Request data"); sLog.outWarden("Request data");
uint16 build = _session->GetClientBuild();
uint16 id = 0;
uint8 type = 0;
WardenCheck* wd = NULL;
// If all checks were done, fill the todo list again // If all checks were done, fill the todo list again
if (_memChecksTodo.empty()) if (_memChecksTodo.empty())
_memChecksTodo.assign(sWardenCheckMgr->MemChecksIdPool.begin(), sWardenCheckMgr->MemChecksIdPool.end()); sWardenCheckMgr->GetWardenCheckIds(true, build, _memChecksTodo);
if (_otherChecksTodo.empty()) if (_otherChecksTodo.empty())
_otherChecksTodo.assign(sWardenCheckMgr->OtherChecksIdPool.begin(), sWardenCheckMgr->OtherChecksIdPool.end()); sWardenCheckMgr->GetWardenCheckIds(false, build, _otherChecksTodo);
_serverTicks = WorldTimer::getMSTime(); _serverTicks = WorldTimer::getMSTime();
uint16 id;
uint8 type;
WardenCheck* wd;
_currentChecks.clear(); _currentChecks.clear();
// Build check request // Build check request
@ -195,8 +197,6 @@ void WardenWin::RequestData()
ByteBuffer buff; ByteBuffer buff;
buff << uint8(WARDEN_SMSG_CHEAT_CHECKS_REQUEST); buff << uint8(WARDEN_SMSG_CHEAT_CHECKS_REQUEST);
ACE_READ_GUARD(ACE_RW_Mutex, g, sWardenCheckMgr->_checkStoreLock);
for (uint16 i = 0; i < sWorld.getConfig(CONFIG_UINT32_WARDEN_NUM_OTHER_CHECKS); ++i) for (uint16 i = 0; i < sWorld.getConfig(CONFIG_UINT32_WARDEN_NUM_OTHER_CHECKS); ++i)
{ {
// If todo list is done break loop (will be filled on next Update() run) // If todo list is done break loop (will be filled on next Update() run)
@ -210,18 +210,22 @@ void WardenWin::RequestData()
// Add the id to the list sent in this cycle // Add the id to the list sent in this cycle
_currentChecks.push_back(id); _currentChecks.push_back(id);
wd = sWardenCheckMgr->GetWardenDataById(_session->GetClientBuild(), id); // if we are here, the function is guaranteed to not return NULL
// but ... who knows
switch (wd->Type) wd = sWardenCheckMgr->GetWardenDataById(build, id);
if (wd)
{ {
case MPQ_CHECK: switch (wd->Type)
case LUA_STR_CHECK: {
case DRIVER_CHECK: case MPQ_CHECK:
buff << uint8(wd->Str.size()); case LUA_STR_CHECK:
buff.append(wd->Str.c_str(), wd->Str.size()); case DRIVER_CHECK:
break; buff << uint8(wd->Str.size());
default: buff.append(wd->Str.c_str(), wd->Str.size());
break; break;
default:
break;
}
} }
} }
@ -235,7 +239,7 @@ void WardenWin::RequestData()
for (std::list<uint16>::iterator itr = _currentChecks.begin(); itr != _currentChecks.end(); ++itr) for (std::list<uint16>::iterator itr = _currentChecks.begin(); itr != _currentChecks.end(); ++itr)
{ {
wd = sWardenCheckMgr->GetWardenDataById(_session->GetClientBuild(), *itr); wd = sWardenCheckMgr->GetWardenDataById(build, *itr);
type = wd->Type; type = wd->Type;
buff << uint8(type ^ xorByte); buff << uint8(type ^ xorByte);
@ -301,8 +305,6 @@ void WardenWin::RequestData()
pkt.append(buff); pkt.append(buff);
_session->SendPacket(&pkt); _session->SendPacket(&pkt);
_dataSent = true;
std::stringstream stream; std::stringstream stream;
stream << "Sent check id's: "; stream << "Sent check id's: ";
for (std::list<uint16>::iterator itr = _currentChecks.begin(); itr != _currentChecks.end(); ++itr) for (std::list<uint16>::iterator itr = _currentChecks.begin(); itr != _currentChecks.end(); ++itr)
@ -311,15 +313,14 @@ void WardenWin::RequestData()
} }
sLog.outWarden("%s", stream.str().c_str()); sLog.outWarden("%s", stream.str().c_str());
Warden::RequestData();
} }
void WardenWin::HandleData(ByteBuffer &buff) void WardenWin::HandleData(ByteBuffer &buff)
{ {
sLog.outWarden("Handle data"); sLog.outWarden("Handle data");
_dataSent = false;
_clientResponseTimer = 0;
uint16 Length; uint16 Length;
buff >> Length; buff >> Length;
uint32 Checksum; uint32 Checksum;
@ -349,8 +350,9 @@ void WardenWin::HandleData(ByteBuffer &buff)
uint32 ticksNow = WorldTimer::getMSTime(); uint32 ticksNow = WorldTimer::getMSTime();
uint32 ourTicks = newClientTicks + (ticksNow - _serverTicks); uint32 ourTicks = newClientTicks + (ticksNow - _serverTicks);
sLog.outWarden("ServerTicks %u, RequestTicks %u, CLientTicks %u", ticksNow, _serverTicks, newClientTicks); // Now, At request, At response sLog.outWarden("ServerTicks %u, RequestTicks %u, ClientTicks %u", ticksNow, _serverTicks, newClientTicks); // Now, At request, At response
sLog.outWarden("Waittime %u", ourTicks - newClientTicks); sLog.outWarden("Waittime %u", ourTicks - newClientTicks);
} }
WardenCheckResult* rs; WardenCheckResult* rs;
@ -358,8 +360,6 @@ void WardenWin::HandleData(ByteBuffer &buff)
uint8 type; uint8 type;
uint16 checkFailed = 0; uint16 checkFailed = 0;
ACE_READ_GUARD(ACE_RW_Mutex, g, sWardenCheckMgr->_checkStoreLock);
for (std::list<uint16>::iterator itr = _currentChecks.begin(); itr != _currentChecks.end(); ++itr) for (std::list<uint16>::iterator itr = _currentChecks.begin(); itr != _currentChecks.end(); ++itr)
{ {
rd = sWardenCheckMgr->GetWardenDataById(_session->GetClientBuild(), *itr); rd = sWardenCheckMgr->GetWardenDataById(_session->GetClientBuild(), *itr);

View file

@ -39,5 +39,5 @@
#define WORLD_DB_VERSION_NR 21 #define WORLD_DB_VERSION_NR 21
#define WORLD_DB_STRUCTURE_NR 12 #define WORLD_DB_STRUCTURE_NR 12
#define WORLD_DB_CONTENT_NR 001 #define WORLD_DB_CONTENT_NR 001
#define WORLD_DB_UPDATE_DESCRIPTION "GM_Commands_localization" #define WORLD_DB_UPDATE_DESCRIPTION "warden_refactor"
#endif // __REVISION_H__ #endif // __REVISION_H__