mirror of
https://github.com/mod-playerbots/azerothcore-wotlk.git
synced 2026-01-15 18:10:26 +00:00
feat(Core/Packet): Implement AntiDOS protection from Trinity (#2789)
* Implement AntiDOS protection from Trinity Co-authored-by: jackpoz <giacomopoz@gmail.com> Co-authored-by: Shauren <shauren.trinity@gmail.com> Co-authored-by: Vincent-Michael <trinity.michael_vincent@gmx.eu>
This commit is contained in:
@@ -41,7 +41,7 @@
|
||||
|
||||
namespace {
|
||||
|
||||
std::string const DefaultPlayerName = "<none>";
|
||||
std::string const DefaultPlayerName = "<none>";
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -86,17 +86,18 @@ bool WorldSessionFilter::Process(WorldPacket* packet)
|
||||
}
|
||||
|
||||
/// WorldSession constructor
|
||||
WorldSession::WorldSession(uint32 id, WorldSocket* sock, AccountTypes sec, uint8 expansion, time_t mute_time, LocaleConstant locale, uint32 recruiter, bool isARecruiter, bool skipQueue, uint32 TotalTime):
|
||||
WorldSession::WorldSession(uint32 id, WorldSocket* sock, AccountTypes sec, uint8 expansion, time_t mute_time, LocaleConstant locale, uint32 recruiter, bool isARecruiter, bool skipQueue, uint32 TotalTime) :
|
||||
m_muteTime(mute_time),
|
||||
m_timeOutTime(0),
|
||||
_lastAuctionListItemsMSTime(0),
|
||||
_lastAuctionListOwnerItemsMSTime(0),
|
||||
AntiDOS(this),
|
||||
m_GUIDLow(0),
|
||||
_player(NULL),
|
||||
m_Socket(sock),
|
||||
_security(sec),
|
||||
_skipQueue(skipQueue),
|
||||
_accountId(id),
|
||||
_accountId(id),
|
||||
m_expansion(expansion),
|
||||
m_total_time(TotalTime),
|
||||
_logoutTime(0),
|
||||
@@ -109,7 +110,7 @@ WorldSession::WorldSession(uint32 id, WorldSocket* sock, AccountTypes sec, uint8
|
||||
m_latency(0),
|
||||
m_clientTimeDelay(0),
|
||||
m_TutorialsChanged(false),
|
||||
recruiterId(recruiter),
|
||||
recruiterId(recruiter),
|
||||
isRecruiter(isARecruiter),
|
||||
m_currentBankerGUID(0),
|
||||
timeWhoCommandAllowed(0)
|
||||
@@ -139,7 +140,7 @@ WorldSession::~WorldSession()
|
||||
|
||||
///- unload player if not unloaded
|
||||
if (_player)
|
||||
LogoutPlayer (true);
|
||||
LogoutPlayer(true);
|
||||
|
||||
/// - If have unclosed socket, close it
|
||||
if (m_Socket)
|
||||
@@ -174,8 +175,8 @@ std::string WorldSession::GetPlayerInfo() const
|
||||
std::ostringstream ss;
|
||||
|
||||
ss << "[Player: " << GetPlayerName()
|
||||
<< " (Guid: " << (_player != NULL ? _player->GetGUID() : 0)
|
||||
<< ", Account: " << GetAccountId() << ")]";
|
||||
<< " (Guid: " << (_player != NULL ? _player->GetGUID() : 0)
|
||||
<< ", Account: " << GetAccountId() << ")]";
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
@@ -207,20 +208,20 @@ void WorldSession::SendPacket(WorldPacket const* packet)
|
||||
|
||||
if ((cur_time - lastTime) < 60)
|
||||
{
|
||||
sendPacketCount+=1;
|
||||
sendPacketBytes+=packet->size();
|
||||
sendPacketCount += 1;
|
||||
sendPacketBytes += packet->size();
|
||||
|
||||
sendLastPacketCount+=1;
|
||||
sendLastPacketBytes+=packet->size();
|
||||
sendLastPacketCount += 1;
|
||||
sendLastPacketBytes += packet->size();
|
||||
}
|
||||
else
|
||||
{
|
||||
uint64 minTime = uint64(cur_time - lastTime);
|
||||
uint64 fullTime = uint64(lastTime - firstTime);
|
||||
|
||||
sLog->outDetail("Send all time packets count: " UI64FMTD " bytes: " UI64FMTD " avr.count/sec: %f avr.bytes/sec: %f time: %u", sendPacketCount, sendPacketBytes, float(sendPacketCount)/fullTime, float(sendPacketBytes)/fullTime, uint32(fullTime));
|
||||
sLog->outDetail("Send all time packets count: " UI64FMTD " bytes: " UI64FMTD " avr.count/sec: %f avr.bytes/sec: %f time: %u", sendPacketCount, sendPacketBytes, float(sendPacketCount) / fullTime, float(sendPacketBytes) / fullTime, uint32(fullTime));
|
||||
|
||||
sLog->outDetail("Send last min packets count: " UI64FMTD " bytes: " UI64FMTD " avr.count/sec: %f avr.bytes/sec: %f", sendLastPacketCount, sendLastPacketBytes, float(sendLastPacketCount)/minTime, float(sendLastPacketBytes)/minTime);
|
||||
sLog->outDetail("Send last min packets count: " UI64FMTD " bytes: " UI64FMTD " avr.count/sec: %f avr.bytes/sec: %f", sendLastPacketCount, sendLastPacketBytes, float(sendLastPacketCount) / minTime, float(sendLastPacketBytes) / minTime);
|
||||
|
||||
lastTime = cur_time;
|
||||
sendLastPacketCount = 1;
|
||||
@@ -251,7 +252,7 @@ bool WorldSession::Update(uint32 diff, PacketFilter& updater)
|
||||
if (updater.ProcessLogout())
|
||||
{
|
||||
UpdateTimeOutTime(diff);
|
||||
|
||||
|
||||
/// If necessary, kick the player because the client didn't send anything for too long
|
||||
/// (or they've been idling in character select)
|
||||
if (sWorld->getBoolConfig(CONFIG_CLOSE_IDLE_CONNECTIONS) && IsConnectionIdle() && m_Socket)
|
||||
@@ -266,12 +267,13 @@ bool WorldSession::Update(uint32 diff, PacketFilter& updater)
|
||||
bool deletePacket = true;
|
||||
WorldPacket* firstDelayedPacket = NULL;
|
||||
uint32 processedPackets = 0;
|
||||
time_t currentTime = time(nullptr);
|
||||
|
||||
while (m_Socket && !m_Socket->IsClosed() && !_recvQueue.empty() && _recvQueue.peek(true) != firstDelayedPacket && _recvQueue.next(packet, updater))
|
||||
{
|
||||
if (packet->GetOpcode() >= NUM_MSG_TYPES)
|
||||
{
|
||||
sLog->outError("WorldSession Packet filter: received non-existent opcode %s (0x%.4X)",LookupOpcodeName(packet->GetOpcode()), packet->GetOpcode());
|
||||
sLog->outError("WorldSession Packet filter: received non-existent opcode %s (0x%.4X)", LookupOpcodeName(packet->GetOpcode()), packet->GetOpcode());
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -299,24 +301,24 @@ bool WorldSession::Update(uint32 diff, PacketFilter& updater)
|
||||
QueuePacket(packet);
|
||||
}*/
|
||||
}
|
||||
else
|
||||
else if (_player->IsInWorld() && AntiDOS.EvaluateOpcode(*packet, currentTime))
|
||||
{
|
||||
if (movementPacket)
|
||||
{
|
||||
HandleMovementOpcodes(*movementPacket);
|
||||
delete movementPacket;
|
||||
movementPacket = NULL;
|
||||
}
|
||||
sScriptMgr->OnPacketReceive(this, *packet);
|
||||
#ifdef ELUNA
|
||||
if (!sEluna->OnPacketReceive(this, *packet))
|
||||
break;
|
||||
#endif
|
||||
(this->*opHandle.handler)(*packet);
|
||||
if (movementPacket)
|
||||
{
|
||||
HandleMovementOpcodes(*movementPacket);
|
||||
delete movementPacket;
|
||||
movementPacket = NULL;
|
||||
}
|
||||
sScriptMgr->OnPacketReceive(this, *packet);
|
||||
#ifdef ELUNA
|
||||
if (!sEluna->OnPacketReceive(this, *packet))
|
||||
break;
|
||||
#endif
|
||||
(this->*opHandle.handler)(*packet);
|
||||
}
|
||||
break;
|
||||
case STATUS_TRANSFER:
|
||||
if (_player && !_player->IsInWorld())
|
||||
if (_player && !_player->IsInWorld() && AntiDOS.EvaluateOpcode(*packet, currentTime))
|
||||
{
|
||||
if (movementPacket)
|
||||
{
|
||||
@@ -324,10 +326,10 @@ bool WorldSession::Update(uint32 diff, PacketFilter& updater)
|
||||
movementPacket = NULL;
|
||||
}
|
||||
sScriptMgr->OnPacketReceive(this, *packet);
|
||||
#ifdef ELUNA
|
||||
#ifdef ELUNA
|
||||
if (!sEluna->OnPacketReceive(this, *packet))
|
||||
break;
|
||||
#endif
|
||||
#endif
|
||||
(this->*opHandle.handler)(*packet);
|
||||
}
|
||||
break;
|
||||
@@ -335,12 +337,15 @@ bool WorldSession::Update(uint32 diff, PacketFilter& updater)
|
||||
if (m_inQueue) // prevent cheating
|
||||
break;
|
||||
|
||||
sScriptMgr->OnPacketReceive(this, *packet);
|
||||
#ifdef ELUNA
|
||||
if (!sEluna->OnPacketReceive(this, *packet))
|
||||
break;
|
||||
#endif
|
||||
(this->*opHandle.handler)(*packet);
|
||||
if (AntiDOS.EvaluateOpcode(*packet, currentTime))
|
||||
{
|
||||
sScriptMgr->OnPacketReceive(this, *packet);
|
||||
#ifdef ELUNA
|
||||
if (!sEluna->OnPacketReceive(this, *packet))
|
||||
break;
|
||||
#endif
|
||||
(this->*opHandle.handler)(*packet);
|
||||
}
|
||||
break;
|
||||
case STATUS_NEVER:
|
||||
break;
|
||||
@@ -348,7 +353,7 @@ bool WorldSession::Update(uint32 diff, PacketFilter& updater)
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch(ByteBufferException const&)
|
||||
catch (ByteBufferException const&)
|
||||
{
|
||||
sLog->outError("WorldSession::Update ByteBufferException occured while parsing a packet (opcode: %u) from client %s, accountid=%i. Skipped packet.", packet->GetOpcode(), GetRemoteAddress().c_str(), GetAccountId());
|
||||
if (sLog->IsOutDebug())
|
||||
@@ -361,8 +366,8 @@ bool WorldSession::Update(uint32 diff, PacketFilter& updater)
|
||||
|
||||
if (deletePacket)
|
||||
delete packet;
|
||||
else
|
||||
deletePacket = true;
|
||||
|
||||
deletePacket = true;
|
||||
|
||||
if (++processedPackets >= 150) // limit (by count) packets processed in one update, prevent DDoS
|
||||
break;
|
||||
@@ -423,13 +428,13 @@ void WorldSession::HandleTeleportTimeout(bool updateInSessions)
|
||||
time_t currTime = time(NULL);
|
||||
if (updateInSessions) // session update from World::UpdateSessions
|
||||
{
|
||||
if (GetPlayer()->IsBeingTeleportedFar() && GetPlayer()->GetSemaphoreTeleportFar()+sWorld->getIntConfig(CONFIG_TELEPORT_TIMEOUT_FAR) < currTime)
|
||||
if (GetPlayer()->IsBeingTeleportedFar() && GetPlayer()->GetSemaphoreTeleportFar() + sWorld->getIntConfig(CONFIG_TELEPORT_TIMEOUT_FAR) < currTime)
|
||||
while (GetPlayer() && GetPlayer()->IsBeingTeleportedFar())
|
||||
HandleMoveWorldportAckOpcode();
|
||||
}
|
||||
else // session update from Map::Update
|
||||
{
|
||||
if (GetPlayer()->IsBeingTeleportedNear() && GetPlayer()->GetSemaphoreTeleportNear()+sWorld->getIntConfig(CONFIG_TELEPORT_TIMEOUT_NEAR) < currTime)
|
||||
if (GetPlayer()->IsBeingTeleportedNear() && GetPlayer()->GetSemaphoreTeleportNear() + sWorld->getIntConfig(CONFIG_TELEPORT_TIMEOUT_NEAR) < currTime)
|
||||
while (GetPlayer() && GetPlayer()->IsInWorld() && GetPlayer()->IsBeingTeleportedNear())
|
||||
{
|
||||
Player* plMover = GetPlayer()->m_mover->ToPlayer();
|
||||
@@ -493,13 +498,13 @@ void WorldSession::LogoutPlayer(bool save)
|
||||
sOutdoorPvPMgr->HandlePlayerLeaveZone(_player, _player->GetZoneId());
|
||||
|
||||
// pussywizard: remove from battleground queues on logout
|
||||
for (int i=0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; ++i)
|
||||
for (int i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; ++i)
|
||||
if (BattlegroundQueueTypeId bgQueueTypeId = _player->GetBattlegroundQueueTypeId(i))
|
||||
{
|
||||
_player->RemoveBattlegroundQueueId(bgQueueTypeId);
|
||||
sBattlegroundMgr->GetBattlegroundQueue(bgQueueTypeId).RemovePlayer(_player->GetGUID(), false, i);
|
||||
// track if player logs out after invited to join BG
|
||||
if(_player->IsInvitedForBattlegroundInstance() && sWorld->getBoolConfig(CONFIG_BATTLEGROUND_TRACK_DESERTERS))
|
||||
if (_player->IsInvitedForBattlegroundInstance() && sWorld->getBoolConfig(CONFIG_BATTLEGROUND_TRACK_DESERTERS))
|
||||
{
|
||||
PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_DESERTER_TRACK);
|
||||
stmt->setUInt32(0, _player->GetGUIDLow());
|
||||
@@ -560,7 +565,7 @@ void WorldSession::LogoutPlayer(bool save)
|
||||
{
|
||||
_player->GetGroup()->SendUpdate();
|
||||
_player->GetGroup()->ResetMaxEnchantingLevel();
|
||||
|
||||
|
||||
Map::PlayerList const &playerList = _player->GetMap()->GetPlayers();
|
||||
|
||||
if (_player->GetMap()->IsDungeon() || _player->GetMap()->IsRaidOrHeroicDungeon())
|
||||
@@ -732,8 +737,7 @@ void WorldSession::LoadAccountData(PreparedQueryResult result, uint32 mask)
|
||||
|
||||
m_accountData[type].Time = time_t(fields[1].GetUInt32());
|
||||
m_accountData[type].Data = fields[2].GetString();
|
||||
}
|
||||
while (result->NextRow());
|
||||
} while (result->NextRow());
|
||||
}
|
||||
|
||||
void WorldSession::SetAccountData(AccountDataType type, time_t tm, std::string const& data)
|
||||
@@ -757,7 +761,7 @@ void WorldSession::SetAccountData(AccountDataType type, time_t tm, std::string c
|
||||
|
||||
PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(index);
|
||||
stmt->setUInt32(0, id);
|
||||
stmt->setUInt8 (1, type);
|
||||
stmt->setUInt8(1, type);
|
||||
stmt->setUInt32(2, uint32(tm));
|
||||
stmt->setString(3, data);
|
||||
CharacterDatabase.Execute(stmt);
|
||||
@@ -855,8 +859,8 @@ void WorldSession::ReadMovementInfo(WorldPacket &data, MovementInfo* mi)
|
||||
|
||||
//! Anti-cheat checks. Please keep them in seperate if() blocks to maintain a clear overview.
|
||||
//! Might be subject to latency, so just remove improper flags.
|
||||
#ifdef ACORE_DEBUG
|
||||
#define REMOVE_VIOLATING_FLAGS(check, maskToRemove) \
|
||||
#ifdef ACORE_DEBUG
|
||||
#define REMOVE_VIOLATING_FLAGS(check, maskToRemove) \
|
||||
{ \
|
||||
if (check) \
|
||||
{ \
|
||||
@@ -866,17 +870,17 @@ void WorldSession::ReadMovementInfo(WorldPacket &data, MovementInfo* mi)
|
||||
mi->RemoveMovementFlag((maskToRemove)); \
|
||||
} \
|
||||
}
|
||||
#else
|
||||
#define REMOVE_VIOLATING_FLAGS(check, maskToRemove) \
|
||||
#else
|
||||
#define REMOVE_VIOLATING_FLAGS(check, maskToRemove) \
|
||||
if (check) \
|
||||
mi->RemoveMovementFlag((maskToRemove));
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
/*! This must be a packet spoofing attempt. MOVEMENTFLAG_ROOT sent from the client is not valid
|
||||
in conjunction with any of the moving movement flags such as MOVEMENTFLAG_FORWARD.
|
||||
It will freeze clients that receive this player's movement info.
|
||||
*/
|
||||
/*! This must be a packet spoofing attempt. MOVEMENTFLAG_ROOT sent from the client is not valid
|
||||
in conjunction with any of the moving movement flags such as MOVEMENTFLAG_FORWARD.
|
||||
It will freeze clients that receive this player's movement info.
|
||||
*/
|
||||
REMOVE_VIOLATING_FLAGS(mi->HasMovementFlag(MOVEMENTFLAG_ROOT),
|
||||
MOVEMENTFLAG_ROOT);
|
||||
|
||||
@@ -920,7 +924,7 @@ void WorldSession::ReadMovementInfo(WorldPacket &data, MovementInfo* mi)
|
||||
e.g. aerial combat.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
REMOVE_VIOLATING_FLAGS(mi->HasMovementFlag(MOVEMENTFLAG_FLYING | MOVEMENTFLAG_CAN_FLY) && GetSecurity() == SEC_PLAYER && !GetPlayer()->m_mover->HasAuraType(SPELL_AURA_FLY) && !GetPlayer()->m_mover->HasAuraType(SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED),
|
||||
MOVEMENTFLAG_FLYING | MOVEMENTFLAG_CAN_FLY);
|
||||
|
||||
@@ -932,7 +936,7 @@ void WorldSession::ReadMovementInfo(WorldPacket &data, MovementInfo* mi)
|
||||
REMOVE_VIOLATING_FLAGS(mi->HasMovementFlag(MOVEMENTFLAG_SPLINE_ENABLED) &&
|
||||
(!GetPlayer()->movespline->Initialized() || GetPlayer()->movespline->Finalized()), MOVEMENTFLAG_SPLINE_ENABLED);
|
||||
|
||||
#undef REMOVE_VIOLATING_FLAGS
|
||||
#undef REMOVE_VIOLATING_FLAGS
|
||||
}
|
||||
|
||||
void WorldSession::WriteMovementInfo(WorldPacket* data, MovementInfo* mi)
|
||||
@@ -946,14 +950,14 @@ void WorldSession::WriteMovementInfo(WorldPacket* data, MovementInfo* mi)
|
||||
|
||||
if (mi->HasMovementFlag(MOVEMENTFLAG_ONTRANSPORT))
|
||||
{
|
||||
data->appendPackGUID(mi->transport.guid);
|
||||
data->appendPackGUID(mi->transport.guid);
|
||||
|
||||
*data << mi->transport.pos.PositionXYZOStream();
|
||||
*data << mi->transport.time;
|
||||
*data << mi->transport.seat;
|
||||
*data << mi->transport.pos.PositionXYZOStream();
|
||||
*data << mi->transport.time;
|
||||
*data << mi->transport.seat;
|
||||
|
||||
if (mi->HasExtraMovementFlag(MOVEMENTFLAG2_INTERPOLATED_MOVEMENT))
|
||||
*data << mi->transport.time2;
|
||||
if (mi->HasExtraMovementFlag(MOVEMENTFLAG2_INTERPOLATED_MOVEMENT))
|
||||
*data << mi->transport.time2;
|
||||
}
|
||||
|
||||
if (mi->HasMovementFlag(MovementFlags(MOVEMENTFLAG_SWIMMING | MOVEMENTFLAG_FLYING)) || mi->HasExtraMovementFlag(MOVEMENTFLAG2_ALWAYS_ALLOW_PITCHING))
|
||||
@@ -1126,7 +1130,7 @@ void WorldSession::SendAddonsInfo()
|
||||
data << uint32(bannedAddons->size());
|
||||
for (AddonMgr::BannedAddonList::const_iterator itr = bannedAddons->begin(); itr != bannedAddons->end(); ++itr)
|
||||
{
|
||||
data << uint32(itr->Id);
|
||||
data << uint32(itr->Id);
|
||||
data.append(itr->NameMD5, sizeof(itr->NameMD5));
|
||||
data.append(itr->VersionMD5, sizeof(itr->VersionMD5));
|
||||
data << uint32(itr->Timestamp);
|
||||
@@ -1282,7 +1286,7 @@ void WorldSession::ProcessQueryCallbackPet()
|
||||
_loadPetFromDBSecondCallback.get(param);
|
||||
HandleLoadPetFromDBSecondCallback((LoadPetFromDBQueryHolder*)param);
|
||||
delete param;
|
||||
_loadPetFromDBSecondCallback.cancel();
|
||||
_loadPetFromDBSecondCallback.cancel();
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -1331,3 +1335,299 @@ void WorldSession::InitWarden(BigNumber* k, std::string const& os)
|
||||
// _warden->Init(this, k);
|
||||
}
|
||||
}
|
||||
|
||||
bool WorldSession::DosProtection::EvaluateOpcode(WorldPacket& p, time_t time) const
|
||||
{
|
||||
uint32 maxPacketCounterAllowed = GetMaxPacketCounterAllowed(p.GetOpcode());
|
||||
|
||||
// Return true if there no limit for the opcode
|
||||
if (!maxPacketCounterAllowed)
|
||||
return true;
|
||||
|
||||
PacketCounter& packetCounter = _PacketThrottlingMap[p.GetOpcode()];
|
||||
if (packetCounter.lastReceiveTime != time)
|
||||
{
|
||||
packetCounter.lastReceiveTime = time;
|
||||
packetCounter.amountCounter = 0;
|
||||
}
|
||||
|
||||
// Check if player is flooding some packets
|
||||
if (++packetCounter.amountCounter <= maxPacketCounterAllowed)
|
||||
return true;
|
||||
|
||||
sLog->outString("AntiDOS: Account %u, IP: %s, Ping: %u, Character %s, flooding packet (opc: %s (0x%X), count: %u)",
|
||||
Session->GetAccountId(), Session->GetRemoteAddress().c_str(), Session->GetLatency(),
|
||||
Session->GetPlayerName().c_str(), opcodeTable[p.GetOpcode()].name, p.GetOpcode(), packetCounter.amountCounter);
|
||||
|
||||
switch (_policy)
|
||||
{
|
||||
case POLICY_LOG:
|
||||
return true;
|
||||
case POLICY_KICK:
|
||||
{
|
||||
sLog->outString("AntiDOS: Player %s kicked!", Session->GetPlayerName().c_str());
|
||||
Session->KickPlayer();
|
||||
return false;
|
||||
}
|
||||
case POLICY_BAN:
|
||||
{
|
||||
uint32 bm = sWorld->getIntConfig(CONFIG_PACKET_SPOOF_BANMODE);
|
||||
uint32 duration = sWorld->getIntConfig(CONFIG_PACKET_SPOOF_BANDURATION); // in seconds
|
||||
std::string nameOrIp = "";
|
||||
switch (bm)
|
||||
{
|
||||
case 0: // Ban account
|
||||
(void)AccountMgr::GetName(Session->GetAccountId(), nameOrIp);
|
||||
sBan->BanAccount(nameOrIp, std::to_string(duration), "DOS (Packet Flooding/Spoofing", "Server: AutoDOS");
|
||||
break;
|
||||
case 1: // Ban ip
|
||||
nameOrIp = Session->GetRemoteAddress();
|
||||
sBan->BanIP(nameOrIp, std::to_string(duration), "DOS (Packet Flooding/Spoofing", "Server: AutoDOS");
|
||||
break;
|
||||
}
|
||||
|
||||
sLog->outString("AntiDOS: Player automatically banned for %u seconds.", duration);
|
||||
return false;
|
||||
}
|
||||
default: // invalid policy
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
uint32 WorldSession::DosProtection::GetMaxPacketCounterAllowed(uint16 opcode) const
|
||||
{
|
||||
uint32 maxPacketCounterAllowed;
|
||||
switch (opcode)
|
||||
{
|
||||
// CPU usage sending 2000 packets/second on a 3.70 GHz 4 cores on Win x64
|
||||
// [% CPU mysqld] [%CPU worldserver RelWithDebInfo]
|
||||
case CMSG_PLAYER_LOGIN: // 0 0.5
|
||||
case CMSG_NAME_QUERY: // 0 1
|
||||
case CMSG_PET_NAME_QUERY: // 0 1
|
||||
case CMSG_NPC_TEXT_QUERY: // 0 1
|
||||
case CMSG_ATTACKSTOP: // 0 1
|
||||
case CMSG_QUERY_QUESTS_COMPLETED: // 0 1
|
||||
case CMSG_QUERY_TIME: // 0 1
|
||||
case CMSG_CORPSE_MAP_POSITION_QUERY: // 0 1
|
||||
case CMSG_MOVE_TIME_SKIPPED: // 0 1
|
||||
case MSG_QUERY_NEXT_MAIL_TIME: // 0 1
|
||||
case CMSG_SETSHEATHED: // 0 1
|
||||
case MSG_RAID_TARGET_UPDATE: // 0 1
|
||||
case CMSG_PLAYER_LOGOUT: // 0 1
|
||||
case CMSG_LOGOUT_REQUEST: // 0 1
|
||||
case CMSG_PET_RENAME: // 0 1
|
||||
case CMSG_QUESTGIVER_CANCEL: // 0 1
|
||||
case CMSG_QUESTGIVER_REQUEST_REWARD: // 0 1
|
||||
case CMSG_COMPLETE_CINEMATIC: // 0 1
|
||||
case CMSG_BANKER_ACTIVATE: // 0 1
|
||||
case CMSG_BUY_BANK_SLOT: // 0 1
|
||||
case CMSG_OPT_OUT_OF_LOOT: // 0 1
|
||||
case CMSG_DUEL_ACCEPTED: // 0 1
|
||||
case CMSG_DUEL_CANCELLED: // 0 1
|
||||
case CMSG_CALENDAR_COMPLAIN: // 0 1
|
||||
case CMSG_QUEST_QUERY: // 0 1.5
|
||||
case CMSG_ITEM_QUERY_SINGLE: // 0 1.5
|
||||
case CMSG_ITEM_NAME_QUERY: // 0 1.5
|
||||
case CMSG_GAMEOBJECT_QUERY: // 0 1.5
|
||||
case CMSG_CREATURE_QUERY: // 0 1.5
|
||||
case CMSG_QUESTGIVER_STATUS_QUERY: // 0 1.5
|
||||
case CMSG_GUILD_QUERY: // 0 1.5
|
||||
case CMSG_ARENA_TEAM_QUERY: // 0 1.5
|
||||
case CMSG_TAXINODE_STATUS_QUERY: // 0 1.5
|
||||
case CMSG_TAXIQUERYAVAILABLENODES: // 0 1.5
|
||||
case CMSG_QUESTGIVER_QUERY_QUEST: // 0 1.5
|
||||
case CMSG_PAGE_TEXT_QUERY: // 0 1.5
|
||||
case MSG_QUERY_GUILD_BANK_TEXT: // 0 1.5
|
||||
case MSG_CORPSE_QUERY: // 0 1.5
|
||||
case MSG_MOVE_SET_FACING: // 0 1.5
|
||||
case CMSG_REQUEST_PARTY_MEMBER_STATS: // 0 1.5
|
||||
case CMSG_QUESTGIVER_COMPLETE_QUEST: // 0 1.5
|
||||
case CMSG_SET_ACTION_BUTTON: // 0 1.5
|
||||
case CMSG_RESET_INSTANCES: // 0 1.5
|
||||
case CMSG_HEARTH_AND_RESURRECT: // 0 1.5
|
||||
case CMSG_TOGGLE_PVP: // 0 1.5
|
||||
case CMSG_PET_ABANDON: // 0 1.5
|
||||
case CMSG_ACTIVATETAXIEXPRESS: // 0 1.5
|
||||
case CMSG_ACTIVATETAXI: // 0 1.5
|
||||
case CMSG_SELF_RES: // 0 1.5
|
||||
case CMSG_UNLEARN_SKILL: // 0 1.5
|
||||
case CMSG_EQUIPMENT_SET_SAVE: // 0 1.5
|
||||
case CMSG_DELETEEQUIPMENT_SET: // 0 1.5
|
||||
case CMSG_DISMISS_CRITTER: // 0 1.5
|
||||
case CMSG_REPOP_REQUEST: // 0 1.5
|
||||
case CMSG_GROUP_INVITE: // 0 1.5
|
||||
case CMSG_GROUP_DECLINE: // 0 1.5
|
||||
case CMSG_GROUP_ACCEPT: // 0 1.5
|
||||
case CMSG_GROUP_UNINVITE_GUID: // 0 1.5
|
||||
case CMSG_GROUP_UNINVITE: // 0 1.5
|
||||
case CMSG_GROUP_DISBAND: // 0 1.5
|
||||
case CMSG_BATTLEMASTER_JOIN_ARENA: // 0 1.5
|
||||
case CMSG_LEAVE_BATTLEFIELD: // 0 1.5
|
||||
case MSG_GUILD_BANK_LOG_QUERY: // 0 2
|
||||
case CMSG_LOGOUT_CANCEL: // 0 2
|
||||
case CMSG_REALM_SPLIT: // 0 2
|
||||
case CMSG_ALTER_APPEARANCE: // 0 2
|
||||
case CMSG_QUEST_CONFIRM_ACCEPT: // 0 2
|
||||
case MSG_GUILD_EVENT_LOG_QUERY: // 0 2.5
|
||||
case CMSG_READY_FOR_ACCOUNT_DATA_TIMES: // 0 2.5
|
||||
case CMSG_QUESTGIVER_STATUS_MULTIPLE_QUERY: // 0 2.5
|
||||
case CMSG_BEGIN_TRADE: // 0 2.5
|
||||
case CMSG_INITIATE_TRADE: // 0 3
|
||||
case CMSG_MESSAGECHAT: // 0 3.5
|
||||
case CMSG_INSPECT: // 0 3.5
|
||||
case CMSG_AREA_SPIRIT_HEALER_QUERY: // not profiled
|
||||
case CMSG_STANDSTATECHANGE: // not profiled
|
||||
case MSG_RANDOM_ROLL: // not profiled
|
||||
case CMSG_TIME_SYNC_RESP: // not profiled
|
||||
case CMSG_TRAINER_BUY_SPELL: // not profiled
|
||||
case CMSG_FORCE_RUN_SPEED_CHANGE_ACK: // not profiled
|
||||
{
|
||||
// "0" is a magic number meaning there's no limit for the opcode.
|
||||
// All the opcodes above must cause little CPU usage and no sync/async database queries at all
|
||||
maxPacketCounterAllowed = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
case CMSG_QUESTGIVER_ACCEPT_QUEST: // 0 4
|
||||
case CMSG_QUESTLOG_REMOVE_QUEST: // 0 4
|
||||
case CMSG_QUESTGIVER_CHOOSE_REWARD: // 0 4
|
||||
case CMSG_CONTACT_LIST: // 0 5
|
||||
case CMSG_LEARN_PREVIEW_TALENTS: // 0 6
|
||||
case CMSG_AUTOBANK_ITEM: // 0 6
|
||||
case CMSG_AUTOSTORE_BANK_ITEM: // 0 6
|
||||
case CMSG_WHO: // 0 7
|
||||
case CMSG_PLAYER_VEHICLE_ENTER: // 0 8
|
||||
case CMSG_LEARN_PREVIEW_TALENTS_PET: // not profiled
|
||||
case MSG_MOVE_HEARTBEAT:
|
||||
{
|
||||
maxPacketCounterAllowed = 200;
|
||||
break;
|
||||
}
|
||||
|
||||
case CMSG_GUILD_SET_PUBLIC_NOTE: // 1 2 1 async db query
|
||||
case CMSG_GUILD_SET_OFFICER_NOTE: // 1 2 1 async db query
|
||||
case CMSG_SET_CONTACT_NOTES: // 1 2.5 1 async db query
|
||||
case CMSG_CALENDAR_GET_CALENDAR: // 0 1.5 medium upload bandwidth usage
|
||||
case CMSG_GUILD_BANK_QUERY_TAB: // 0 3.5 medium upload bandwidth usage
|
||||
case CMSG_QUERY_INSPECT_ACHIEVEMENTS: // 0 13 high upload bandwidth usage
|
||||
case CMSG_GAMEOBJ_REPORT_USE: // not profiled
|
||||
case CMSG_GAMEOBJ_USE: // not profiled
|
||||
case MSG_PETITION_DECLINE: // not profiled
|
||||
{
|
||||
maxPacketCounterAllowed = 50;
|
||||
break;
|
||||
}
|
||||
|
||||
case CMSG_QUEST_POI_QUERY: // 0 25 very high upload bandwidth usage
|
||||
{
|
||||
maxPacketCounterAllowed = MAX_QUEST_LOG_SIZE;
|
||||
break;
|
||||
}
|
||||
|
||||
case CMSG_GM_REPORT_LAG: // 1 3 1 async db query
|
||||
case CMSG_SPELLCLICK: // not profiled
|
||||
case CMSG_REMOVE_GLYPH: // not profiled
|
||||
case CMSG_DISMISS_CONTROLLED_VEHICLE: // not profiled
|
||||
{
|
||||
maxPacketCounterAllowed = 20;
|
||||
break;
|
||||
}
|
||||
|
||||
case CMSG_PETITION_SIGN: // 9 4 2 sync 1 async db queries
|
||||
case CMSG_TURN_IN_PETITION: // 8 5.5 2 sync db query
|
||||
case CMSG_GROUP_CHANGE_SUB_GROUP: // 6 5 1 sync 1 async db queries
|
||||
case CMSG_PETITION_QUERY: // 4 3.5 1 sync db query
|
||||
case CMSG_CHAR_RACE_CHANGE: // 5 4 1 sync db query
|
||||
case CMSG_CHAR_CUSTOMIZE: // 5 5 1 sync db query
|
||||
case CMSG_CHAR_FACTION_CHANGE: // 5 5 1 sync db query
|
||||
case CMSG_CHAR_DELETE: // 4 4 1 sync db query
|
||||
case CMSG_DEL_FRIEND: // 7 5 1 async db query
|
||||
case CMSG_ADD_FRIEND: // 6 4 1 async db query
|
||||
case CMSG_CHAR_RENAME: // 5 3 1 async db query
|
||||
case CMSG_GMSURVEY_SUBMIT: // 2 3 1 async db query
|
||||
case CMSG_BUG: // 1 1 1 async db query
|
||||
case CMSG_GROUP_SET_LEADER: // 1 2 1 async db query
|
||||
case CMSG_GROUP_RAID_CONVERT: // 1 5 1 async db query
|
||||
case CMSG_GROUP_ASSISTANT_LEADER: // 1 2 1 async db query
|
||||
case CMSG_PETITION_BUY: // not profiled 1 sync 1 async db queries
|
||||
case CMSG_CHANGE_SEATS_ON_CONTROLLED_VEHICLE: // not profiled
|
||||
case CMSG_REQUEST_VEHICLE_PREV_SEAT: // not profiled
|
||||
case CMSG_REQUEST_VEHICLE_NEXT_SEAT: // not profiled
|
||||
case CMSG_REQUEST_VEHICLE_SWITCH_SEAT: // not profiled
|
||||
case CMSG_REQUEST_VEHICLE_EXIT: // not profiled
|
||||
case CMSG_CONTROLLER_EJECT_PASSENGER: // not profiled
|
||||
case CMSG_ITEM_REFUND: // not profiled
|
||||
case CMSG_SOCKET_GEMS: // not profiled
|
||||
case CMSG_WRAP_ITEM: // not profiled
|
||||
case CMSG_REPORT_PVP_AFK: // not profiled
|
||||
{
|
||||
maxPacketCounterAllowed = 10;
|
||||
break;
|
||||
}
|
||||
|
||||
case CMSG_CHAR_CREATE: // 7 5 3 async db queries
|
||||
case CMSG_CHAR_ENUM: // 22 3 2 async db queries
|
||||
case CMSG_GMTICKET_CREATE: // 1 25 1 async db query
|
||||
case CMSG_GMTICKET_UPDATETEXT: // 0 15 1 async db query
|
||||
case CMSG_GMTICKET_DELETETICKET: // 1 25 1 async db query
|
||||
case CMSG_GMRESPONSE_RESOLVE: // 1 25 1 async db query
|
||||
case CMSG_CALENDAR_ADD_EVENT: // 21 10 2 async db query
|
||||
case CMSG_CALENDAR_UPDATE_EVENT: // not profiled
|
||||
case CMSG_CALENDAR_REMOVE_EVENT: // not profiled
|
||||
case CMSG_CALENDAR_COPY_EVENT: // not profiled
|
||||
case CMSG_CALENDAR_EVENT_INVITE: // not profiled
|
||||
case CMSG_CALENDAR_EVENT_SIGNUP: // not profiled
|
||||
case CMSG_CALENDAR_EVENT_RSVP: // not profiled
|
||||
case CMSG_CALENDAR_EVENT_REMOVE_INVITE: // not profiled
|
||||
case CMSG_CALENDAR_EVENT_MODERATOR_STATUS: // not profiled
|
||||
case CMSG_ARENA_TEAM_INVITE: // not profiled
|
||||
case CMSG_ARENA_TEAM_ACCEPT: // not profiled
|
||||
case CMSG_ARENA_TEAM_DECLINE: // not profiled
|
||||
case CMSG_ARENA_TEAM_LEAVE: // not profiled
|
||||
case CMSG_ARENA_TEAM_DISBAND: // not profiled
|
||||
case CMSG_ARENA_TEAM_REMOVE: // not profiled
|
||||
case CMSG_ARENA_TEAM_LEADER: // not profiled
|
||||
case CMSG_LOOT_METHOD: // not profiled
|
||||
case CMSG_GUILD_INVITE: // not profiled
|
||||
case CMSG_GUILD_ACCEPT: // not profiled
|
||||
case CMSG_GUILD_DECLINE: // not profiled
|
||||
case CMSG_GUILD_LEAVE: // not profiled
|
||||
case CMSG_GUILD_DISBAND: // not profiled
|
||||
case CMSG_GUILD_LEADER: // not profiled
|
||||
case CMSG_GUILD_MOTD: // not profiled
|
||||
case CMSG_GUILD_RANK: // not profiled
|
||||
case CMSG_GUILD_ADD_RANK: // not profiled
|
||||
case CMSG_GUILD_DEL_RANK: // not profiled
|
||||
case CMSG_GUILD_INFO_TEXT: // not profiled
|
||||
case CMSG_GUILD_BANK_DEPOSIT_MONEY: // not profiled
|
||||
case CMSG_GUILD_BANK_WITHDRAW_MONEY: // not profiled
|
||||
case CMSG_GUILD_BANK_BUY_TAB: // not profiled
|
||||
case CMSG_GUILD_BANK_UPDATE_TAB: // not profiled
|
||||
case CMSG_SET_GUILD_BANK_TEXT: // not profiled
|
||||
case MSG_SAVE_GUILD_EMBLEM: // not profiled
|
||||
case MSG_PETITION_RENAME: // not profiled
|
||||
case MSG_TALENT_WIPE_CONFIRM: // not profiled
|
||||
case MSG_SET_DUNGEON_DIFFICULTY: // not profiled
|
||||
case MSG_SET_RAID_DIFFICULTY: // not profiled
|
||||
case MSG_PARTY_ASSIGNMENT: // not profiled
|
||||
case MSG_RAID_READY_CHECK: // not profiled
|
||||
{
|
||||
maxPacketCounterAllowed = 3;
|
||||
break;
|
||||
}
|
||||
|
||||
case CMSG_ITEM_REFUND_INFO: // not profiled
|
||||
{
|
||||
maxPacketCounterAllowed = PLAYER_SLOTS_COUNT;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
maxPacketCounterAllowed = 100;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return maxPacketCounterAllowed;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user