mumble/mumble-1.2.19-limit-amount-of-messages.patch

196 lines
5.0 KiB
Diff
Raw Normal View History

From 44b9004d2c208b42c6f8ffa99938361e31f5a071
From: MadMaurice <madmaurice@zom.bi>
Date: Thu Aug 30 15:08:01 2018 +0200
Prevent instability and crash due to message flood
This patch adds a rate limiting to selected patches. The underlying rate limiter
used is the Leaky-Bucket algorithm. It allows for a burst of messages, but
limits them after a specified amount of messages within a time frame.
From: Ferdinand Thiessen <rpm@fthiessen.de>
Modified this diff, to make it work with 1.2.19 tarball.
"Backported" by manually change the 1.2.19 version according to the original diff.
diff -Nur mumble-1.2.19/src/murmur/Messages.cpp new/src/murmur/Messages.cpp
--- mumble-1.2.19/src/murmur/Messages.cpp 2017-01-27 07:48:33.000000000 +0100
+++ new/src/murmur/Messages.cpp 2019-07-13 00:45:48.281780195 +0200
@@ -42,6 +42,11 @@
#include "ServerUser.h"
#include "Version.h"
+#define RATELIMIT(user) \
+ if (user->leakyBucket.ratelimit(1)) { \
+ return; \
+ }
+
#define MSG_SETUP(st) \
if (uSource->sState != st) { \
return; \
@@ -491,6 +496,10 @@
msg.set_session(pDstServerUser->uiSession);
msg.set_actor(uSource->uiSession);
+ if (uSource == pDstServerUser) {
+ RATELIMIT(uSource);
+ }
+
if (msg.has_channel_id()) {
Channel *c = qhChannels.value(msg.channel_id());
if (!c || (c == pDstServerUser->cChannel))
@@ -798,6 +807,8 @@
p = qhChannels.value(msg.parent());
if (! p)
return;
+ } else {
+ RATELIMIT(uSource);
}
msg.clear_links();
@@ -1074,6 +1085,8 @@
QSet<ServerUser *> users;
QQueue<Channel *> q;
+ RATELIMIT(uSource);
+
QString text = u8(msg.message());
bool changed = false;
@@ -1176,6 +1189,8 @@
return;
}
+ RATELIMIT(uSource);
+
if (msg.has_query() && msg.query()) {
QStack<Channel *> chans;
Channel *p;
@@ -1417,6 +1432,8 @@
}
void Server::msgVersion(ServerUser *uSource, MumbleProto::Version &msg) {
+ RATELIMIT(uSource);
+
if (msg.has_version())
uSource->uiVersion=msg.version();
if (msg.has_release())
diff -Nur mumble-1.2.19/src/murmur/ServerUser.cpp new/src/murmur/ServerUser.cpp
--- mumble-1.2.19/src/murmur/ServerUser.cpp 2017-01-27 07:48:33.000000000 +0100
+++ new/src/murmur/ServerUser.cpp 2019-07-13 00:47:25.974498227 +0200
@@ -128,3 +128,61 @@
return static_cast<int>((sum * 1000000ULL) / elapsed);
}
+#if __cplusplus > 199711LL
+
+inline static
+time_point now() {
+ return std::chrono::steady_clock::now();
+}
+
+inline static
+unsigned long millisecondsBetween(time_point start, time_point end) {
+ return std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();
+}
+
+#else
+
+inline static
+time_point now() {
+ return clock();
+}
+
+inline static
+unsigned long millisecondsBetween(time_point start, time_point end) {
+ return 1000 * (end - start) / CLOCKS_PER_SEC;
+}
+
+#endif
+
+// Rate limiting: burst up to 30, 4 message per sec limit over longer time
+LeakyBucket::LeakyBucket() : tokensPerSec(4), maxTokens(30), currentTokens(0) {
+ lastUpdate = now();
+}
+
+bool LeakyBucket::ratelimit(int tokens) {
+ // First remove tokens we leaked over time
+ time_point tnow = now();
+ long ms = millisecondsBetween(lastUpdate, tnow);
+
+ long drainTokens = (ms * tokensPerSec) / 1000;
+
+ // Prevent constant starvation due to too many updates
+ if (drainTokens > 0) {
+ this->lastUpdate = tnow;
+
+ this->currentTokens -= drainTokens;
+ if (this->currentTokens < 0) {
+ this->currentTokens = 0;
+ }
+ }
+
+ // Then try to add tokens
+ bool limit = this->currentTokens > ((static_cast<long>(maxTokens)) - tokens);
+
+ // If the bucket is not overflowed, allow message and add tokens
+ if (!limit) {
+ this->currentTokens += tokens;
+ }
+
+ return limit;
+}
diff -Nur mumble-1.2.19/src/murmur/ServerUser.h new/src/murmur/ServerUser.h
--- mumble-1.2.19/src/murmur/ServerUser.h 2017-01-27 07:48:33.000000000 +0100
+++ new/src/murmur/ServerUser.h 2019-07-13 00:49:28.023395272 +0200
@@ -40,6 +40,13 @@
#include <winsock2.h>
#endif
+// <chrono> was introduced in C++11
+#if __cplusplus > 199711LL
+#include <chrono>
+#else
+#include <ctime>
+#endif
+
#include "Connection.h"
#include "Net.h"
#include "Timer.h"
@@ -80,6 +87,26 @@
class Server;
+#if __cplusplus > 199711L
+ typedef std::chrono::time_point<std::chrono::steady_clock> time_point;
+#else
+ typedef clock_t time_point;
+#endif
+
+// Simple algorithm for rate limiting
+class LeakyBucket {
+ private:
+ unsigned int tokensPerSec, maxTokens;
+ long currentTokens;
+ time_point lastUpdate;
+
+ public:
+ // Returns true if packets should be dropped
+ bool ratelimit(int tokens);
+
+ LeakyBucket();
+};
+
class ServerUser : public Connection, public User {
private:
Q_OBJECT
@@ -119,6 +146,8 @@
QMap<int, TargetCache> qmTargetCache;
QMap<QString, QString> qmWhisperRedirect;
+ LeakyBucket leakyBucket;
+
int iLastPermissionCheck;
QMap<int, unsigned int> qmPermissionSent;
#ifdef Q_OS_UNIX