aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/server/game/Handlers/CharacterHandler.cpp2
-rw-r--r--src/server/game/Server/WorldSession.cpp14
-rw-r--r--src/server/game/Server/WorldSession.h77
-rw-r--r--src/server/game/World/World.cpp14
-rw-r--r--src/server/game/World/World.h4
-rw-r--r--src/server/worldserver/worldserver.conf.dist36
6 files changed, 144 insertions, 3 deletions
diff --git a/src/server/game/Handlers/CharacterHandler.cpp b/src/server/game/Handlers/CharacterHandler.cpp
index 0554820364d..aa766d5b1ac 100644
--- a/src/server/game/Handlers/CharacterHandler.cpp
+++ b/src/server/game/Handlers/CharacterHandler.cpp
@@ -243,6 +243,8 @@ void WorldSession::HandleCharEnum(PreparedQueryResult result)
void WorldSession::HandleCharEnumOpcode(WorldPacket & /*recvData*/)
{
+ AntiDOS.AllowOpcode(CMSG_CHAR_ENUM, false);
+
// remove expired bans
PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_EXPIRED_BANS);
CharacterDatabase.Execute(stmt);
diff --git a/src/server/game/Server/WorldSession.cpp b/src/server/game/Server/WorldSession.cpp
index 5519f1d4d0e..ce1db7fcac7 100644
--- a/src/server/game/Server/WorldSession.cpp
+++ b/src/server/game/Server/WorldSession.cpp
@@ -118,7 +118,8 @@ WorldSession::WorldSession(uint32 id, WorldSocket* sock, AccountTypes sec, uint8
recruiterId(recruiter),
isRecruiter(isARecruiter),
timeLastWhoCommand(0),
- _RBACData(NULL)
+ _RBACData(NULL),
+ AntiDOS(this)
{
if (sock)
{
@@ -274,13 +275,19 @@ bool WorldSession::Update(uint32 diff, PacketFilter& updater)
!_recvQueue.empty() && _recvQueue.peek(true) != firstDelayedPacket &&
_recvQueue.next(packet, updater))
{
- if (packet->GetOpcode() >= NUM_MSG_TYPES)
+ if (!AntiDOS.EvaluateOpcode(*packet))
+ {
+ delete packet;
+ KickPlayer();
+ }
+
+ if (packet && packet->GetOpcode() >= NUM_MSG_TYPES)
{
TC_LOG_ERROR(LOG_FILTER_OPCODES, "Received non-existed opcode %s from %s", GetOpcodeNameForLogging(packet->GetOpcode()).c_str()
, GetPlayerInfo().c_str());
sScriptMgr->OnUnknownPacketReceive(m_Socket, WorldPacket(*packet));
}
- else
+ else if (packet)
{
OpcodeHandler &opHandle = opcodeTable[packet->GetOpcode()];
try
@@ -547,6 +554,7 @@ void WorldSession::LogoutPlayer(bool save)
m_playerLogout = false;
m_playerSave = false;
m_playerRecentlyLogout = true;
+ AntiDOS.AllowOpcode(CMSG_CHAR_ENUM, true);
LogoutRequest(0);
}
diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h
index bf79b34822d..721bdb06c8a 100644
--- a/src/server/game/Server/WorldSession.h
+++ b/src/server/game/Server/WorldSession.h
@@ -30,6 +30,7 @@
#include "World.h"
#include "WorldPacket.h"
#include "Cryptography/BigNumber.h"
+#include "AccountMgr.h"
class Creature;
class GameObject;
@@ -911,6 +912,82 @@ class WorldSession
QueryCallback<PreparedQueryResult, CharacterCreateInfo*, true> _charCreateCallback;
QueryResultHolderFuture _charLoginCallback;
+ friend class World;
+ protected:
+ class DosProtection
+ {
+ friend class World;
+ public:
+ DosProtection(WorldSession* s) : Session(s), _policy((Policy)sWorld->getIntConfig(CONFIG_PACKET_SPOOF_POLICY)) {}
+
+ bool EvaluateOpcode(WorldPacket& p) const
+ {
+ if (IsOpcodeAllowed(p.GetOpcode()))
+ return true;
+
+ // Opcode not allowed, let the punishment begin
+ sLog->outInfo(LOG_FILTER_NETWORKIO, "AntiDOS: Account %u, IP: %s, sent unacceptable packet (opc: %u, size: %u)",
+ Session->GetAccountId(), Session->GetRemoteAddress().c_str(), p.GetOpcode(), p.size());
+
+ switch (_policy)
+ {
+ case POLICY_LOG:
+ return true;
+ case POLICY_KICK:
+ sLog->outInfo(LOG_FILTER_NETWORKIO, "AntiDOS: Player kicked!");
+ return false;
+ case POLICY_BAN:
+ {
+ BanMode bm = (BanMode)sWorld->getIntConfig(CONFIG_PACKET_SPOOF_BANMODE);
+ int64 duration = (int64)sWorld->getIntConfig(CONFIG_PACKET_SPOOF_BANDURATION); // in seconds
+ std::string nameOrIp = "";
+ switch (bm)
+ {
+ case BAN_ACCOUNT: (void)sAccountMgr->GetName(Session->GetAccountId(), nameOrIp); break;
+ case BAN_IP: nameOrIp = Session->GetRemoteAddress(); break;
+ }
+ sWorld->BanAccount(bm, nameOrIp, duration, "DOS (Packet Flooding/Spoofing", "Server: AutoDOS");
+ sLog->outInfo(LOG_FILTER_NETWORKIO, "AntiDOS: Player automatically banned for "I64FMT" seconds.", duration);
+
+ return false;
+ }
+ default: // invalid policy
+ return true;
+ }
+ }
+
+ void AllowOpcode(uint16 opcode, bool allow)
+ {
+ _isOpcodeAllowed[opcode] = allow;
+ }
+
+ protected:
+ enum Policy
+ {
+ POLICY_LOG,
+ POLICY_KICK,
+ POLICY_BAN,
+ };
+
+ bool IsOpcodeAllowed(uint16 opcode) const
+ {
+ OpcodeStatusMap::const_iterator itr = _isOpcodeAllowed.find(opcode);
+ if (itr == _isOpcodeAllowed.end())
+ return true; // No presence in the map indicates this is the first time the opcode was sent this session, so allow
+
+ return itr->second;
+ }
+
+ WorldSession* Session;
+
+ private:
+ typedef UNORDERED_MAP<uint16, bool> OpcodeStatusMap;
+ OpcodeStatusMap _isOpcodeAllowed; // could be bool array, but wouldn't be practical for game versions with non-linear opcodes
+ Policy _policy;
+
+
+ } AntiDOS;
+
private:
// private trade methods
void moveItems(Item* myItems[], Item* hisItems[]);
diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp
index 52ac2d28a41..681f47976e3 100644
--- a/src/server/game/World/World.cpp
+++ b/src/server/game/World/World.cpp
@@ -1229,6 +1229,14 @@ void World::LoadConfigSettings(bool reload)
m_float_configs[CONFIG_STATS_LIMITS_BLOCK] = sConfigMgr->GetFloatDefault("Stats.Limits.Block", 95.0f);
m_float_configs[CONFIG_STATS_LIMITS_CRIT] = sConfigMgr->GetFloatDefault("Stats.Limits.Crit", 95.0f);
+ //packet spoof punishment
+ m_int_configs[CONFIG_PACKET_SPOOF_POLICY] = sConfigMgr->GetIntDefault("PacketSpoof.Policy", (uint32)WorldSession::DosProtection::Policy::POLICY_KICK);
+ m_int_configs[CONFIG_PACKET_SPOOF_BANMODE] = sConfigMgr->GetIntDefault("PacketSpoof.BanMode", (uint32)BAN_ACCOUNT);
+ if (m_int_configs[CONFIG_PACKET_SPOOF_BANMODE] == BAN_CHARACTER || m_int_configs[CONFIG_PACKET_SPOOF_BANMODE] > BAN_IP)
+ m_int_configs[CONFIG_PACKET_SPOOF_BANMODE] = BAN_ACCOUNT;
+
+ m_int_configs[CONFIG_PACKET_SPOOF_BANDURATION] = sConfigMgr->GetIntDefault("PacketSpoof.BanDuration", 86400);
+
// call ScriptMgr if we're reloading the configuration
if (reload)
sScriptMgr->OnConfigLoad(reload);
@@ -2307,6 +2315,12 @@ void World::KickAllLess(AccountTypes sec)
BanReturn World::BanAccount(BanMode mode, std::string const& nameOrIP, std::string const& duration, std::string const& reason, std::string const& author)
{
uint32 duration_secs = TimeStringToSecs(duration);
+ return BanAccount(mode, nameOrIP, duration_secs, reason, author);
+}
+
+/// Ban an account or ban an IP address, duration is in seconds if positive, otherwise permban
+BanReturn World::BanAccount(BanMode mode, std::string const& nameOrIP, uint32 duration_secs, std::string const& reason, std::string const& author)
+{
PreparedQueryResult resultAccounts = PreparedQueryResult(NULL); //used for kicking
PreparedStatement* stmt = NULL;
diff --git a/src/server/game/World/World.h b/src/server/game/World/World.h
index 12586ed4969..bf90b5ac01a 100644
--- a/src/server/game/World/World.h
+++ b/src/server/game/World/World.h
@@ -326,6 +326,9 @@ enum WorldIntConfigs
CONFIG_WINTERGRASP_BATTLETIME,
CONFIG_WINTERGRASP_NOBATTLETIME,
CONFIG_WINTERGRASP_RESTART_AFTER_CRASH,
+ CONFIG_PACKET_SPOOF_POLICY,
+ CONFIG_PACKET_SPOOF_BANMODE,
+ CONFIG_PACKET_SPOOF_BANDURATION,
INT_CONFIG_VALUE_COUNT
};
@@ -687,6 +690,7 @@ class World
void KickAll();
void KickAllLess(AccountTypes sec);
BanReturn BanAccount(BanMode mode, std::string const& nameOrIP, std::string const& duration, std::string const& reason, std::string const& author);
+ BanReturn BanAccount(BanMode mode, std::string const& nameOrIP, uint32 duration_secs, std::string const& reason, std::string const& author);
bool RemoveBanAccount(BanMode mode, std::string const& nameOrIP);
BanReturn BanCharacter(std::string const& name, std::string const& duration, std::string const& reason, std::string const& author);
bool RemoveBanCharacter(std::string const& name);
diff --git a/src/server/worldserver/worldserver.conf.dist b/src/server/worldserver/worldserver.conf.dist
index c4e19e851b3..a98a4e61448 100644
--- a/src/server/worldserver/worldserver.conf.dist
+++ b/src/server/worldserver/worldserver.conf.dist
@@ -2794,3 +2794,39 @@ Log.Async.Enable = 0
#
###################################################################################################
+
+###################################################################################################
+#
+# Packet Spoof Protection Settings
+#
+# These settings determine which action to take when harmful packet spoofing is detected.
+#
+# PacketSpoof.Policy
+# Description: Determines the course of action when packet spoofing is detected.
+# Values: 0 - Log only (LOG_FILTER_NETWORKIO)
+# 1 - Log + kick
+# 2 - Log + kick + ban
+
+PacketSpoof.Policy = 1
+
+#
+# PacketSpoof.BanMode
+# Description: If PacketSpoof.Policy equals 2, this will determine the ban mode.
+# Values: 0 - Ban Account
+# 2 - Ban IP
+# Note: Banning by character not supported for logical reasons.
+#
+
+PacketSpoof.BanMode = 0
+
+#
+# PacketSpoof.BanDuration
+# Description: Duration of the ban in seconds. Only valid if PacketSpoof.Policy is set to 2.
+# Set to 0 for permanent ban.
+# Default: 86400 seconds (1 day)
+#
+
+PacketSpoof.BanDuration = 86400
+
+#
+################################################################################################### \ No newline at end of file