From 6145d6d52474362975d2b5a7ea608b64f0ca26ac Mon Sep 17 00:00:00 2001 From: Max-Wilhelm Bruker Date: Wed, 2 Mar 2011 19:39:38 +0100 Subject: [PATCH] chat flood protection (yet untested) --- common/protocol.cpp | 1 + common/protocol_datastructures.h | 2 +- common/server.h | 3 +++ common/server_protocolhandler.cpp | 30 ++++++++++++++++++++++++++++++ common/server_protocolhandler.h | 1 + servatrice/servatrice.ini.example | 5 +++++ servatrice/src/servatrice.cpp | 4 ++++ servatrice/src/servatrice.h | 4 ++++ 8 files changed, 49 insertions(+), 1 deletion(-) diff --git a/common/protocol.cpp b/common/protocol.cpp index 726803e1..fe3997ad 100644 --- a/common/protocol.cpp +++ b/common/protocol.cpp @@ -268,6 +268,7 @@ void ProtocolResponse::initializeHash() responseHash.insert("user_level_too_low", RespUserLevelTooLow); responseHash.insert("in_ignore_list", RespInIgnoreList); responseHash.insert("would_overwrite_old_session", RespWouldOverwriteOldSession); + responseHash.insert("chat_flood", RespChatFlood); } Response_JoinRoom::Response_JoinRoom(int _cmdId, ResponseCode _responseCode, ServerInfo_Room *_roomInfo) diff --git a/common/protocol_datastructures.h b/common/protocol_datastructures.h index dea6988c..8e3d9826 100644 --- a/common/protocol_datastructures.h +++ b/common/protocol_datastructures.h @@ -8,7 +8,7 @@ class DeckList; -enum ResponseCode { RespNothing, RespOk, RespInternalError, RespInvalidCommand, RespInvalidData, RespNameNotFound, RespLoginNeeded, RespFunctionNotAllowed, RespGameNotStarted, RespGameFull, RespContextError, RespWrongPassword, RespSpectatorsNotAllowed, RespOnlyBuddies, RespUserLevelTooLow, RespInIgnoreList, RespWouldOverwriteOldSession }; +enum ResponseCode { RespNothing, RespOk, RespInternalError, RespInvalidCommand, RespInvalidData, RespNameNotFound, RespLoginNeeded, RespFunctionNotAllowed, RespGameNotStarted, RespGameFull, RespContextError, RespWrongPassword, RespSpectatorsNotAllowed, RespOnlyBuddies, RespUserLevelTooLow, RespInIgnoreList, RespWouldOverwriteOldSession, RespChatFlood }; // PrivateZone: Contents of the zone are always visible to the owner, // but not to anyone else. diff --git a/common/server.h b/common/server.h index 3816cef4..f9ff7fad 100644 --- a/common/server.h +++ b/common/server.h @@ -38,6 +38,9 @@ public: virtual bool getGameShouldPing() const = 0; virtual int getMaxGameInactivityTime() const = 0; virtual int getMaxPlayerInactivityTime() const = 0; + virtual int getMessageCountingInterval() const { return 0; } + virtual int getMaxMessageCountPerInterval() const { return 0; } + virtual int getMaxMessageSizePerInterval() const { return 0; } virtual QMap getBuddyList(const QString &name) = 0; virtual QMap getIgnoreList(const QString &name) = 0; diff --git a/common/server_protocolhandler.cpp b/common/server_protocolhandler.cpp index 7f0ebe4a..9a9cc90e 100644 --- a/common/server_protocolhandler.cpp +++ b/common/server_protocolhandler.cpp @@ -208,6 +208,16 @@ void Server_ProtocolHandler::processCommandContainer(CommandContainer *cont) void Server_ProtocolHandler::pingClockTimeout() { + int interval = server->getMessageCountingInterval(); + if (interval > 0) { + messageSizeOverTime.prepend(0); + if (messageSizeOverTime.size() > server->getMessageCountingInterval()) + messageSizeOverTime.removeLast(); + messageCountOverTime.prepend(0); + if (messageCountOverTime.size() > server->getMessageCountingInterval()) + messageCountOverTime.removeLast(); + } + if (lastCommandTime.secsTo(QDateTime::currentDateTime()) > server->getMaxPlayerInactivityTime()) deleteLater(); } @@ -355,6 +365,26 @@ ResponseCode Server_ProtocolHandler::cmdLeaveRoom(Command_LeaveRoom * /*cmd*/, C ResponseCode Server_ProtocolHandler::cmdRoomSay(Command_RoomSay *cmd, CommandContainer * /*cont*/, Server_Room *room) { + QString msg = cmd->getMessage(); + + if (server->getMessageCountingInterval() > 0) { + int totalSize = 0, totalCount = 0; + if (messageSizeOverTime.isEmpty()) + messageSizeOverTime.prepend(0); + messageSizeOverTime[0] += msg.size(); + for (int i = 0; i < messageSizeOverTime.size(); ++i) + totalSize += messageSizeOverTime[i]; + + if (messageCountOverTime.isEmpty()) + messageCountOverTime.prepend(0); + ++messageCountOverTime[0]; + for (int i = 0; i < messageCountOverTime.size(); ++i) + totalCount += messageCountOverTime[i]; + + if ((totalSize > server->getMaxMessageSizePerInterval()) || (totalCount > server->getMaxMessageCountPerInterval())) + return RespChatFlood; + } + room->say(this, cmd->getMessage()); return RespOk; } diff --git a/common/server_protocolhandler.h b/common/server_protocolhandler.h index d4da0ea7..e47b6d2e 100644 --- a/common/server_protocolhandler.h +++ b/common/server_protocolhandler.h @@ -30,6 +30,7 @@ protected: QMap buddyList, ignoreList; private: QList itemQueue; + QList messageSizeOverTime, messageCountOverTime; QDateTime lastCommandTime; QTimer *pingClock; diff --git a/servatrice/servatrice.ini.example b/servatrice/servatrice.ini.example index 46a2359d..82625b84 100644 --- a/servatrice/servatrice.ini.example +++ b/servatrice/servatrice.ini.example @@ -27,3 +27,8 @@ size=1 [game] max_game_inactivity_time=120 max_player_inactivity_time=15 + +[security] +message_counting_interval=10 +max_message_size_per_interval=1000 +max_message_count_per_interval=10 diff --git a/servatrice/src/servatrice.cpp b/servatrice/src/servatrice.cpp index 15ade424..3660432f 100644 --- a/servatrice/src/servatrice.cpp +++ b/servatrice/src/servatrice.cpp @@ -84,6 +84,10 @@ Servatrice::Servatrice(QObject *parent) maxGameInactivityTime = settings->value("game/max_game_inactivity_time").toInt(); maxPlayerInactivityTime = settings->value("game/max_player_inactivity_time").toInt(); + + messageCountingInterval = settings->value("security/message_counting_interval").toInt(); + maxMessageCountPerInterval = settings->value("security/max_message_count_per_interval").toInt(); + maxMessageSizePerInterval = settings->value("security/max_message_size_per_interval").toInt(); } Servatrice::~Servatrice() diff --git a/servatrice/src/servatrice.h b/servatrice/src/servatrice.h index 66348cdf..fb4476d2 100644 --- a/servatrice/src/servatrice.h +++ b/servatrice/src/servatrice.h @@ -45,6 +45,9 @@ public: bool getGameShouldPing() const { return true; } int getMaxGameInactivityTime() const { return maxGameInactivityTime; } int getMaxPlayerInactivityTime() const { return maxPlayerInactivityTime; } + int getMessageCountingInterval() const { return messageCountingInterval; } + int getMaxMessageCountPerInterval() const { return maxMessageCountPerInterval; } + int getMaxMessageSizePerInterval() const { return maxMessageSizePerInterval; } QString getDbPrefix() const { return dbPrefix; } void updateLoginMessage(); ServerInfo_User *getUserData(const QString &name); @@ -62,6 +65,7 @@ private: int uptime; int maxGameInactivityTime; int maxPlayerInactivityTime; + int messageCountingInterval, maxMessageCountPerInterval, maxMessageSizePerInterval; ServerInfo_User *evalUserQueryResult(const QSqlQuery &query, bool complete); };