Update some of warden.
This commit is contained in:
+191
-77
@@ -27,6 +27,18 @@ namespace Game
|
||||
{
|
||||
public abstract class Warden
|
||||
{
|
||||
internal WorldSession _session;
|
||||
internal byte[] _inputKey = new byte[16];
|
||||
internal byte[] _outputKey = new byte[16];
|
||||
internal byte[] _seed = new byte[16];
|
||||
internal SARC4 _inputCrypto;
|
||||
internal SARC4 _outputCrypto;
|
||||
internal uint _checkTimer; // Timer for sending check requests
|
||||
internal uint _clientResponseTimer; // Timer for client response delay
|
||||
internal bool _dataSent;
|
||||
internal ClientWardenModule _module;
|
||||
internal bool _initialized;
|
||||
|
||||
protected Warden()
|
||||
{
|
||||
_inputCrypto = new SARC4();
|
||||
@@ -34,35 +46,40 @@ namespace Game
|
||||
_checkTimer = 10 * Time.InMilliseconds;
|
||||
}
|
||||
|
||||
public abstract void Init(WorldSession session, BigInteger k);
|
||||
public abstract ClientWardenModule GetModuleForClient();
|
||||
public abstract void InitializeModule();
|
||||
public abstract void RequestHash();
|
||||
public abstract void HandleHashResult(ByteBuffer buff);
|
||||
public abstract void RequestData();
|
||||
public abstract void HandleData(ByteBuffer buff);
|
||||
public void MakeModuleForClient()
|
||||
{
|
||||
Log.outDebug(LogFilter.Warden, "Make module for client");
|
||||
InitializeModuleForClient(out _module);
|
||||
|
||||
// md5 hash
|
||||
MD5 ctx = MD5.Create();
|
||||
ctx.Initialize();
|
||||
ctx.TransformBlock(_module.CompressedData, 0, _module.CompressedData.Length, _module.CompressedData, 0);
|
||||
ctx.TransformBlock(_module.Id, 0, _module.Id.Length, _module.Id, 0);
|
||||
}
|
||||
|
||||
public void SendModuleToClient()
|
||||
{
|
||||
Log.outDebug(LogFilter.Warden, "Send module to client");
|
||||
|
||||
// Create packet structure
|
||||
WardenModuleTransfer packet = new();
|
||||
|
||||
uint sizeLeft = _module.CompressedSize;
|
||||
int pos = 0;
|
||||
uint burstSize;
|
||||
while (sizeLeft > 0)
|
||||
{
|
||||
WardenModuleTransfer transfer = new();
|
||||
|
||||
burstSize = sizeLeft < 500 ? sizeLeft : 500u;
|
||||
transfer.Command = WardenOpcodes.Smsg_ModuleCache;
|
||||
transfer.DataSize = (ushort)burstSize;
|
||||
Buffer.BlockCopy(_module.CompressedData, pos, transfer.Data, 0, (int)burstSize);
|
||||
packet.Command = WardenOpcodes.SmsgModuleCache;
|
||||
packet.DataSize = (ushort)burstSize;
|
||||
Buffer.BlockCopy(_module.CompressedData, pos, packet.Data, 0, (int)burstSize);
|
||||
sizeLeft -= burstSize;
|
||||
pos += (int)burstSize;
|
||||
|
||||
Warden3DataServer packet = new();
|
||||
packet.Data = EncryptData(transfer.Write());
|
||||
_session.SendPacket(packet);
|
||||
Warden3DataServer pkt1 = new();
|
||||
pkt1.Data = EncryptData(packet);
|
||||
_session.SendPacket(pkt1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,51 +89,45 @@ namespace Game
|
||||
|
||||
// Create packet structure
|
||||
WardenModuleUse request = new();
|
||||
request.Command = WardenOpcodes.Smsg_ModuleUse;
|
||||
request.Command = WardenOpcodes.SmsgModuleUse;
|
||||
|
||||
request.ModuleId = _module.Id;
|
||||
request.ModuleKey = _module.Key;
|
||||
request.Size = _module.CompressedSize;
|
||||
|
||||
Warden3DataServer packet = new();
|
||||
packet.Data = EncryptData(request.Write());
|
||||
packet.Data = EncryptData(request);
|
||||
_session.SendPacket(packet);
|
||||
}
|
||||
|
||||
public void Update()
|
||||
public void Update(uint diff)
|
||||
{
|
||||
if (_initialized)
|
||||
{
|
||||
uint currentTimestamp = GameTime.GetGameTimeMS();
|
||||
uint diff = currentTimestamp - _previousTimestamp;
|
||||
_previousTimestamp = currentTimestamp;
|
||||
if (!_initialized)
|
||||
return;
|
||||
|
||||
if (_dataSent)
|
||||
if (_dataSent)
|
||||
{
|
||||
uint maxClientResponseDelay = WorldConfig.GetUIntValue(WorldCfg.WardenClientResponseDelay);
|
||||
if (maxClientResponseDelay > 0)
|
||||
{
|
||||
uint maxClientResponseDelay = WorldConfig.GetUIntValue(WorldCfg.WardenClientResponseDelay);
|
||||
if (maxClientResponseDelay > 0)
|
||||
// Kick player if client response delays more than set in config
|
||||
if (_clientResponseTimer > maxClientResponseDelay * Time.InMilliseconds)
|
||||
{
|
||||
// Kick player if client response delays more than set in config
|
||||
if (_clientResponseTimer > maxClientResponseDelay * Time.InMilliseconds)
|
||||
{
|
||||
Log.outWarn(LogFilter.Warden, "{0} (latency: {1}, IP: {2}) exceeded Warden module response delay for more than {3} - disconnecting client",
|
||||
_session.GetPlayerInfo(), _session.GetLatency(), _session.GetRemoteAddress(), Time.secsToTimeString(maxClientResponseDelay, TimeFormat.ShortText));
|
||||
_session.KickPlayer("Warden::Update Warden module response delay exceeded");
|
||||
}
|
||||
else
|
||||
_clientResponseTimer += diff;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (diff >= _checkTimer)
|
||||
{
|
||||
RequestData();
|
||||
Log.outWarn(LogFilter.Warden, "{0} (latency: {1}, IP: {2}) exceeded Warden module response delay for more than {3} - disconnecting client",
|
||||
_session.GetPlayerInfo(), _session.GetLatency(), _session.GetRemoteAddress(), Time.secsToTimeString(maxClientResponseDelay, TimeFormat.ShortText));
|
||||
_session.KickPlayer("Warden::Update Warden module response delay exceeded");
|
||||
}
|
||||
else
|
||||
_checkTimer -= diff;
|
||||
_clientResponseTimer += diff;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (diff >= _checkTimer)
|
||||
RequestChecks();
|
||||
else
|
||||
_checkTimer -= diff;
|
||||
}
|
||||
}
|
||||
|
||||
public void DecryptData(byte[] buffer)
|
||||
@@ -158,7 +169,7 @@ namespace Game
|
||||
return checkSum;
|
||||
}
|
||||
|
||||
public string Penalty(WardenCheck check = null)
|
||||
public string ApplyPenalty(WardenCheck check = null)
|
||||
{
|
||||
WardenActions action;
|
||||
|
||||
@@ -169,51 +180,154 @@ namespace Game
|
||||
|
||||
switch (action)
|
||||
{
|
||||
case WardenActions.Log:
|
||||
return "None";
|
||||
case WardenActions.Kick:
|
||||
_session.KickPlayer("Warden::Penalty");
|
||||
return "Kick";
|
||||
case WardenActions.Ban:
|
||||
{
|
||||
string duration = WorldConfig.GetIntValue(WorldCfg.WardenClientBanDuration) + "s";
|
||||
string accountName;
|
||||
Global.AccountMgr.GetName(_session.GetAccountId(), out accountName);
|
||||
string banReason = "Warden Anticheat Violation";
|
||||
// Check can be NULL, for example if the client sent a wrong signature in the warden packet (CHECKSUM FAIL)
|
||||
if (check != null)
|
||||
banReason += ": " + check.Comment + " (CheckId: " + check.CheckId + ")";
|
||||
|
||||
Global.WorldMgr.BanAccount(BanMode.Account, accountName, duration, banReason, "Server");
|
||||
return "Ban";
|
||||
}
|
||||
default:
|
||||
break;
|
||||
case WardenActions.Ban:
|
||||
{
|
||||
Global.AccountMgr.GetName(_session.GetAccountId(), out string accountName);
|
||||
string banReason = "Warden Anticheat Violation";
|
||||
// Check can be NULL, for example if the client sent a wrong signature in the warden packet (CHECKSUM FAIL)
|
||||
if (check != null)
|
||||
banReason += ": " + check.Comment + " (CheckId: " + check.CheckId + ")";
|
||||
|
||||
Global.WorldMgr.BanAccount(BanMode.Account, accountName, WorldConfig.GetUIntValue(WorldCfg.WardenClientBanDuration), banReason, "Server");
|
||||
break;
|
||||
}
|
||||
case WardenActions.Log:
|
||||
default:
|
||||
return "None";
|
||||
}
|
||||
return "Undefined";
|
||||
|
||||
return action.ToString();
|
||||
}
|
||||
|
||||
internal WorldSession _session;
|
||||
internal byte[] _inputKey = new byte[16];
|
||||
internal byte[] _outputKey = new byte[16];
|
||||
internal byte[] _seed = new byte[16];
|
||||
internal SARC4 _inputCrypto;
|
||||
internal SARC4 _outputCrypto;
|
||||
internal uint _checkTimer; // Timer for sending check requests
|
||||
internal uint _clientResponseTimer; // Timer for client response delay
|
||||
internal bool _dataSent;
|
||||
internal uint _previousTimestamp;
|
||||
internal ClientWardenModule _module;
|
||||
internal bool _initialized;
|
||||
public void HandleData(ByteBuffer buff)
|
||||
{
|
||||
byte[] data = buff.GetData();
|
||||
DecryptData(data);
|
||||
var opcode = data[0];
|
||||
Log.outDebug(LogFilter.Warden, $"Got packet, opcode 0x{opcode:X}, size {data.Length - 1}");
|
||||
|
||||
switch ((WardenOpcodes)opcode)
|
||||
{
|
||||
case WardenOpcodes.CmsgModuleMissing:
|
||||
SendModuleToClient();
|
||||
break;
|
||||
case WardenOpcodes.CmsgModuleOk:
|
||||
RequestHash();
|
||||
break;
|
||||
case WardenOpcodes.CmsgCheatChecksResult:
|
||||
HandleCheckResult(buff);
|
||||
break;
|
||||
case WardenOpcodes.CmsgMemChecksResult:
|
||||
Log.outDebug(LogFilter.Warden, "NYI WARDEN_CMSG_MEM_CHECKS_RESULT received!");
|
||||
break;
|
||||
case WardenOpcodes.CmsgHashResult:
|
||||
HandleHashResult(buff);
|
||||
InitializeModule();
|
||||
break;
|
||||
case WardenOpcodes.CmsgModuleFailed:
|
||||
Log.outDebug(LogFilter.Warden, "NYI WARDEN_CMSG_MODULE_FAILED received!");
|
||||
break;
|
||||
default:
|
||||
Log.outWarn(LogFilter.Warden, $"Got unknown warden opcode 0x{opcode:X} of size {data.Length - 1}.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool ProcessLuaCheckResponse(string msg)
|
||||
{
|
||||
string WARDEN_TOKEN = "_TW\t";
|
||||
if (!msg.StartsWith(WARDEN_TOKEN))
|
||||
return false;
|
||||
|
||||
ushort id = 0;
|
||||
ushort.Parse(msg.Substring(WARDEN_TOKEN.Length - 1, 10));
|
||||
if (id < Global.WardenCheckMgr.GetMaxValidCheckId())
|
||||
{
|
||||
WardenCheck check = Global.WardenCheckMgr.GetCheckData(id);
|
||||
if (check.Type == WardenCheckType.LuaEval)
|
||||
{
|
||||
string penalty1 = ApplyPenalty(check);
|
||||
Log.outWarn(LogFilter.Warden, $"{_session.GetPlayerInfo()} failed Warden check {id} ({check.Type}). Action: {penalty1}");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
string penalty = ApplyPenalty(null);
|
||||
Log.outWarn(LogFilter.Warden, $"{_session.GetPlayerInfo()} sent bogus Lua check response for Warden. Action: {penalty}");
|
||||
return true;
|
||||
}
|
||||
|
||||
public abstract void Init(WorldSession session, BigInteger k);
|
||||
|
||||
public abstract void InitializeModule();
|
||||
|
||||
public abstract void RequestHash();
|
||||
|
||||
public abstract void HandleHashResult(ByteBuffer buff);
|
||||
|
||||
public abstract void HandleCheckResult(ByteBuffer buff);
|
||||
|
||||
public abstract void InitializeModuleForClient(out ClientWardenModule module);
|
||||
|
||||
public abstract void RequestChecks();
|
||||
}
|
||||
|
||||
class WardenModuleUse
|
||||
{
|
||||
public WardenOpcodes Command;
|
||||
public byte[] ModuleId = new byte[16];
|
||||
public byte[] ModuleKey = new byte[16];
|
||||
public uint Size;
|
||||
|
||||
public static implicit operator byte[](WardenModuleUse use)
|
||||
{
|
||||
ByteBuffer buffer = new ByteBuffer();
|
||||
buffer.WriteUInt8((byte)use.Command);
|
||||
buffer.WriteBytes(use.ModuleId, 16);
|
||||
buffer.WriteBytes(use.ModuleKey, 16);
|
||||
buffer.WriteUInt32(use.Size);
|
||||
return buffer.GetData();
|
||||
}
|
||||
}
|
||||
|
||||
class WardenModuleTransfer
|
||||
{
|
||||
public WardenOpcodes Command;
|
||||
public ushort DataSize;
|
||||
public byte[] Data = new byte[500];
|
||||
|
||||
public static implicit operator byte[](WardenModuleTransfer transfer)
|
||||
{
|
||||
ByteBuffer buffer = new ByteBuffer();
|
||||
buffer.WriteUInt8((byte)transfer.Command);
|
||||
buffer.WriteUInt16(transfer.DataSize);
|
||||
buffer.WriteBytes(transfer.Data, 500);
|
||||
return buffer.GetData();
|
||||
}
|
||||
}
|
||||
|
||||
class WardenHashRequest
|
||||
{
|
||||
public WardenOpcodes Command;
|
||||
public byte[] Seed = new byte[16];
|
||||
|
||||
public static implicit operator byte[](WardenHashRequest request)
|
||||
{
|
||||
ByteBuffer buffer = new ByteBuffer();
|
||||
buffer.WriteUInt8((byte)request.Command);
|
||||
buffer.WriteBytes(request.Seed);
|
||||
return buffer.GetData();
|
||||
}
|
||||
}
|
||||
|
||||
public class ClientWardenModule
|
||||
{
|
||||
public byte[] Id = new byte[16];
|
||||
public byte[] Key = new byte[16];
|
||||
public uint CompressedSize;
|
||||
public byte[] CompressedData;
|
||||
public uint CompressedSize;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user