summaryrefslogtreecommitdiff
path: root/src/server
diff options
context:
space:
mode:
authorTim Angus <tim@ngus.net>2013-06-10 20:30:48 +0100
committerTim Angus <tim@ngus.net>2014-06-17 17:43:32 +0100
commitfd7072f74ce183c840dd65d8983dfa159374c7c0 (patch)
tree1c7cbe5bdda98a8d752bac9460ed2ea8e30bb848 /src/server
parent92844d4646be3fa958e5d9e1ce2ff4b282018b20 (diff)
Rate limit getchallenge
Diffstat (limited to 'src/server')
-rw-r--r--src/server/server.h22
-rw-r--r--src/server/sv_client.c14
-rw-r--r--src/server/sv_main.c23
3 files changed, 39 insertions, 20 deletions
diff --git a/src/server/server.h b/src/server/server.h
index f562a245..2989eb4e 100644
--- a/src/server/server.h
+++ b/src/server/server.h
@@ -290,6 +290,28 @@ extern cvar_t *sv_voip;
//
// sv_main.c
//
+typedef struct leakyBucket_s leakyBucket_t;
+struct leakyBucket_s {
+ netadrtype_t type;
+
+ union {
+ byte _4[4];
+ byte _6[16];
+ } ipv;
+
+ int lastTime;
+ signed char burst;
+
+ long hash;
+
+ leakyBucket_t *prev, *next;
+};
+
+extern leakyBucket_t outboundLeakyBucket;
+
+qboolean SVC_RateLimit( leakyBucket_t *bucket, int burst, int period );
+qboolean SVC_RateLimitAddress( netadr_t from, int burst, int period );
+
void SV_FinalMessage (char *message);
void QDECL SV_SendServerCommand( client_t *cl, const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
diff --git a/src/server/sv_client.c b/src/server/sv_client.c
index 6199c01f..a895879f 100644
--- a/src/server/sv_client.c
+++ b/src/server/sv_client.c
@@ -63,6 +63,20 @@ void SV_GetChallenge(netadr_t from)
char *gameName;
qboolean gameMismatch;
+ // Prevent using getchallenge as an amplifier
+ if ( SVC_RateLimitAddress( from, 10, 1000 ) ) {
+ Com_DPrintf( "SV_GetChallenge: rate limit from %s exceeded, dropping request\n",
+ NET_AdrToString( from ) );
+ return;
+ }
+
+ // Allow getchallenge to be DoSed relatively easily, but prevent
+ // excess outbound bandwidth usage when being flooded inbound
+ if ( SVC_RateLimit( &outboundLeakyBucket, 10, 100 ) ) {
+ Com_DPrintf( "SV_GetChallenge: rate limit exceeded, dropping request\n" );
+ return;
+ }
+
gameName = Cmd_Argv(2);
gameMismatch = !*gameName || strcmp(gameName, com_gamename->string) != 0;
diff --git a/src/server/sv_main.c b/src/server/sv_main.c
index d7d8e2f6..aad063e2 100644
--- a/src/server/sv_main.c
+++ b/src/server/sv_main.c
@@ -371,30 +371,13 @@ CONNECTIONLESS COMMANDS
==============================================================================
*/
-typedef struct leakyBucket_s leakyBucket_t;
-struct leakyBucket_s {
- netadrtype_t type;
-
- union {
- byte _4[4];
- byte _6[16];
- } ipv;
-
- int lastTime;
- signed char burst;
-
- long hash;
-
- leakyBucket_t *prev, *next;
-};
-
// This is deliberately quite large to make it more of an effort to DoS
#define MAX_BUCKETS 16384
#define MAX_HASHES 1024
static leakyBucket_t buckets[ MAX_BUCKETS ];
static leakyBucket_t *bucketHashes[ MAX_HASHES ];
-static leakyBucket_t outboundLeakyBucket;
+leakyBucket_t outboundLeakyBucket;
/*
================
@@ -511,7 +494,7 @@ static leakyBucket_t *SVC_BucketForAddress( netadr_t address, int burst, int per
SVC_RateLimit
================
*/
-static qboolean SVC_RateLimit( leakyBucket_t *bucket, int burst, int period ) {
+qboolean SVC_RateLimit( leakyBucket_t *bucket, int burst, int period ) {
if ( bucket != NULL ) {
int now = Sys_Milliseconds();
int interval = now - bucket->lastTime;
@@ -543,7 +526,7 @@ SVC_RateLimitAddress
Rate limit for a particular address
================
*/
-static qboolean SVC_RateLimitAddress( netadr_t from, int burst, int period ) {
+qboolean SVC_RateLimitAddress( netadr_t from, int burst, int period ) {
leakyBucket_t *bucket = SVC_BucketForAddress( from, burst, period );
return SVC_RateLimit( bucket, burst, period );