From 74e538ffcfe5fa981a240839b6723eeebd21b032 Mon Sep 17 00:00:00 2001 From: Thilo Schulz Date: Thu, 7 Jul 2011 16:07:58 +0000 Subject: [PATCH] - Add better protection against DoSing connecting users from connecting - Have Com_sprintf return string length - add STR_LEN macro for static strings --- code/qcommon/q_shared.c | 4 +++- code/qcommon/q_shared.h | 4 ++-- code/server/server.h | 6 +++++- code/server/sv_client.c | 41 +++++++++++++++++++++++++++-------------- 4 files changed, 37 insertions(+), 18 deletions(-) diff --git a/code/qcommon/q_shared.c b/code/qcommon/q_shared.c index 2cae73df..2390bc9a 100644 --- a/code/qcommon/q_shared.c +++ b/code/qcommon/q_shared.c @@ -919,7 +919,7 @@ int Q_CountChar(const char *string, char tocount) return count; } -void QDECL Com_sprintf(char *dest, int size, const char *fmt, ...) +int QDECL Com_sprintf(char *dest, int size, const char *fmt, ...) { int len; va_list argptr; @@ -930,6 +930,8 @@ void QDECL Com_sprintf(char *dest, int size, const char *fmt, ...) if(len >= size) Com_Printf("Com_sprintf: Output length %d too short, require %d bytes.\n", size, len + 1); + + return len; } /* diff --git a/code/qcommon/q_shared.h b/code/qcommon/q_shared.h index 542eff5f..1ed2bdc1 100644 --- a/code/qcommon/q_shared.h +++ b/code/qcommon/q_shared.h @@ -206,7 +206,7 @@ typedef int clipHandle_t; #define MIN_QINT (-MAX_QINT-1) #define ARRAY_LEN(x) (sizeof(x) / sizeof(*(x))) - +#define STR_LEN(x) (ARRAY_LEN(x) - 1) // angle indexes #define PITCH 0 // up / down @@ -750,7 +750,7 @@ void Parse2DMatrix (char **buf_p, int y, int x, float *m); void Parse3DMatrix (char **buf_p, int z, int y, int x, float *m); int Com_HexStrToInt( const char *str ); -void QDECL Com_sprintf (char *dest, int size, const char *fmt, ...) __attribute__ ((format (printf, 3, 4))); +int QDECL Com_sprintf (char *dest, int size, const char *fmt, ...) __attribute__ ((format (printf, 3, 4))); char *Com_SkipTokens( char *s, int numTokens, char *sep ); char *Com_SkipCharset( char *s, char *sep ); diff --git a/code/server/server.h b/code/server/server.h index a8ecc6c9..a17174ba 100644 --- a/code/server/server.h +++ b/code/server/server.h @@ -197,7 +197,11 @@ typedef struct client_s { // MAX_CHALLENGES is made large to prevent a denial // of service attack that could cycle all of them // out before legitimate users connected -#define MAX_CHALLENGES 1024 +#define MAX_CHALLENGES 2048 +// Allow a certain amount of challenges to have the same IP address +// to make it a bit harder to DOS one single IP address from connecting +// while not allowing a single ip to grab all challenge resources +#define MAX_CHALLENGES_MULTI (MAX_CHALLENGES / 2) #define AUTHORIZE_TIMEOUT 5000 diff --git a/code/server/sv_client.c b/code/server/sv_client.c index 32cafee1..c92d8253 100644 --- a/code/server/sv_client.c +++ b/code/server/sv_client.c @@ -55,8 +55,10 @@ void SV_GetChallenge(netadr_t from) int i; int oldest; int oldestTime; - const char *clientChallenge = Cmd_Argv(1); + int oldestClientTime; + int clientChallenge; challenge_t *challenge; + qboolean wasfound = qfalse; // ignore if we are in single player if ( Cvar_VariableValue( "g_gametype" ) == GT_SINGLE_PLAYER || Cvar_VariableValue("ui_singlePlayerActive")) { @@ -64,15 +66,30 @@ void SV_GetChallenge(netadr_t from) } oldest = 0; - oldestTime = 0x7fffffff; + oldestClientTime = oldestTime = 0x7fffffff; // see if we already have a challenge for this ip challenge = &svs.challenges[0]; - for (i = 0 ; i < MAX_CHALLENGES ; i++, challenge++) { - if (!challenge->connected && NET_CompareAdr( from, challenge->adr ) ) { + clientChallenge = atoi(Cmd_Argv(1)); + + for(i = 0 ; i < MAX_CHALLENGES ; i++, challenge++) + { + if(!challenge->connected && NET_CompareAdr(from, challenge->adr)) + { + wasfound = qtrue; + + if(challenge->time < oldestClientTime) + oldestClientTime = challenge->time; + } + + if(wasfound && i >= MAX_CHALLENGES_MULTI) + { + i = MAX_CHALLENGES; break; } - if ( challenge->time < oldestTime ) { + + if(challenge->time < oldestTime) + { oldestTime = challenge->time; oldest = i; } @@ -82,17 +99,16 @@ void SV_GetChallenge(netadr_t from) { // this is the first time this client has asked for a challenge challenge = &svs.challenges[oldest]; - challenge->clientChallenge = 0; + challenge->clientChallenge = clientChallenge; challenge->adr = from; challenge->firstTime = svs.time; - challenge->time = svs.time; challenge->connected = qfalse; } // always generate a new challenge number, so the client cannot circumvent sv_maxping challenge->challenge = ( (rand() << 16) ^ rand() ) ^ svs.time; challenge->wasrefused = qfalse; - + challenge->time = svs.time; #ifndef STANDALONE // Drop the authorize stuff if this client is coming in via v6 as the auth server does not support ipv6. @@ -121,7 +137,7 @@ void SV_GetChallenge(netadr_t from) // if they have been challenging for a long time and we // haven't heard anything from the authorize server, go ahead and // let them in, assuming the id server is down - else if(svs.time - challenge->firstTime > AUTHORIZE_TIMEOUT) + else if(svs.time - oldestClientTime > AUTHORIZE_TIMEOUT) Com_DPrintf( "authorize server timed out\n" ); else { @@ -129,10 +145,6 @@ void SV_GetChallenge(netadr_t from) cvar_t *fs; char game[1024]; - // If the client provided us with a client challenge, store it... - if(*clientChallenge) - challenge->clientChallenge = atoi(clientChallenge); - Com_DPrintf( "sending getIpAuthorize for %s\n", NET_AdrToString( from )); strcpy(game, BASEGAME); @@ -153,7 +165,8 @@ void SV_GetChallenge(netadr_t from) #endif challenge->pingTime = svs.time; - NET_OutOfBandPrint( NS_SERVER, challenge->adr, "challengeResponse %i %s", challenge->challenge, clientChallenge); + NET_OutOfBandPrint(NS_SERVER, challenge->adr, "challengeResponse %d %d", + challenge->challenge, clientChallenge); } #ifndef STANDALONE