From 7b1541504216ce09ef2c7987eb5a7117a2125a5a Mon Sep 17 00:00:00 2001 From: Tim Angus Date: Mon, 10 Jun 2013 20:30:48 +0100 Subject: [PATCH] Rate limit getchallenge --- code/server/server.h | 22 ++++++++++++++++++++++ code/server/sv_client.c | 14 ++++++++++++++ code/server/sv_main.c | 23 +++-------------------- 3 files changed, 39 insertions(+), 20 deletions(-) diff --git a/code/server/server.h b/code/server/server.h index be7e5baa..c3f3ae01 100644 --- a/code/server/server.h +++ b/code/server/server.h @@ -308,6 +308,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/code/server/sv_client.c b/code/server/sv_client.c index 4012ee6e..2dcff87e 100644 --- a/code/server/sv_client.c +++ b/code/server/sv_client.c @@ -67,6 +67,20 @@ void SV_GetChallenge(netadr_t from) return; } + // 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); #ifdef LEGACY_PROTOCOL diff --git a/code/server/sv_main.c b/code/server/sv_main.c index 8d5f1a2a..e48e0b97 100644 --- a/code/server/sv_main.c +++ b/code/server/sv_main.c @@ -354,30 +354,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; /* ================ @@ -494,7 +477,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; @@ -526,7 +509,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 );