diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/server/game/Handlers/CharacterHandler.cpp | 2 | ||||
-rw-r--r-- | src/server/game/Server/WorldSession.cpp | 14 | ||||
-rw-r--r-- | src/server/game/Server/WorldSession.h | 77 | ||||
-rw-r--r-- | src/server/game/World/World.cpp | 14 | ||||
-rw-r--r-- | src/server/game/World/World.h | 4 | ||||
-rw-r--r-- | src/server/worldserver/worldserver.conf.dist | 36 |
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 |