From 98980bd0cd93725f1b8e076b90cbeda132fd20a1 Mon Sep 17 00:00:00 2001 From: thilo Date: Mon, 1 Jun 2009 05:28:47 +0000 Subject: Make servers echo challenge codes from client getchallenge commands git-svn-id: svn://svn.icculus.org/quake3/trunk@1566 edf5b092-35ff-0310-97b2-ce42778d08ea --- code/server/server.h | 3 +- code/server/sv_client.c | 121 +++++++++++++++++++++++++----------------------- code/server/sv_main.c | 2 +- 3 files changed, 67 insertions(+), 59 deletions(-) (limited to 'code/server') diff --git a/code/server/server.h b/code/server/server.h index a194e45..eab244b 100644 --- a/code/server/server.h +++ b/code/server/server.h @@ -204,6 +204,7 @@ typedef struct client_s { typedef struct { netadr_t adr; int challenge; + int clientChallenge; // challenge number coming from the client int time; // time the last packet was sent to the autherize server int pingTime; // time the challenge response was sent to client int firstTime; // time the adr was first used, for authorize timeout checks @@ -326,7 +327,7 @@ void SV_SpawnServer( char *server, qboolean killBots ); // // sv_client.c // -void SV_GetChallenge( netadr_t from ); +void SV_GetChallenge(netadr_t from); void SV_DirectConnect( netadr_t from ); diff --git a/code/server/sv_client.c b/code/server/sv_client.c index f3d547c..16a67ab 100644 --- a/code/server/sv_client.c +++ b/code/server/sv_client.c @@ -41,12 +41,21 @@ to be sent to the authorize server. When an authorizeip is returned, a challenge response will be sent to that ip. + +ioquake3: we added a possibility for clients to add a challenge +to their packets, to make it more difficult for malicious servers +to hi-jack client connections. +Also, the auth stuff is completely disabled for com_standalone games +as well as IPv6 connections, since there is no way to use the +v4-only auth server for these new types of connections. ================= */ -void SV_GetChallenge( netadr_t from ) { +void SV_GetChallenge(netadr_t from) +{ int i; int oldest; int oldestTime; + const char *clientChallenge = Cmd_Argv(1); challenge_t *challenge; // ignore if we are in single player @@ -69,62 +78,57 @@ void SV_GetChallenge( netadr_t from ) { } } - if (i == MAX_CHALLENGES) { + if (i == MAX_CHALLENGES) + { // this is the first time this client has asked for a challenge challenge = &svs.challenges[oldest]; challenge->challenge = ( (rand() << 16) ^ rand() ) ^ svs.time; + challenge->clientChallenge = 0; challenge->adr = from; challenge->firstTime = svs.time; challenge->time = svs.time; challenge->connected = qfalse; - i = oldest; - } - -#ifdef STANDALONE - challenge->pingTime = svs.time; - NET_OutOfBandPrint( NS_SERVER, from, "challengeResponse %i", challenge->challenge ); -#else - // if they are on a lan address, send the challengeResponse immediately - if ( Sys_IsLANAddress( from ) ) { - challenge->pingTime = svs.time; - NET_OutOfBandPrint( NS_SERVER, from, "challengeResponse %i", challenge->challenge ); - return; } +#ifndef STANDALONE // Drop the authorize stuff if this client is coming in via v6 as the auth server does not support ipv6. - if(challenge->adr.type == NA_IP) + // Drop also for addresses coming in on local LAN and for stand-alone games independent from id's assets. + if(challenge->adr.type == NA_IP && !Cvar_VariableIntegerValue("com_standalone") && !Sys_IsLANAddress(from)) { // look up the authorize server's IP - if ( !svs.authorizeAddress.ip[0] && svs.authorizeAddress.type != NA_BAD ) { + if (svs.authorizeAddress.type == NA_BAD) + { Com_Printf( "Resolving %s\n", AUTHORIZE_SERVER_NAME ); - if ( !NET_StringToAdr( AUTHORIZE_SERVER_NAME, &svs.authorizeAddress, NA_IP ) ) { - Com_Printf( "Couldn't resolve address\n" ); - return; + + if (NET_StringToAdr(AUTHORIZE_SERVER_NAME, &svs.authorizeAddress, NA_IP)) + { + svs.authorizeAddress.port = BigShort( PORT_AUTHORIZE ); + Com_Printf( "%s resolved to %i.%i.%i.%i:%i\n", AUTHORIZE_SERVER_NAME, + svs.authorizeAddress.ip[0], svs.authorizeAddress.ip[1], + svs.authorizeAddress.ip[2], svs.authorizeAddress.ip[3], + BigShort( svs.authorizeAddress.port ) ); } - svs.authorizeAddress.port = BigShort( PORT_AUTHORIZE ); - Com_Printf( "%s resolved to %i.%i.%i.%i:%i\n", AUTHORIZE_SERVER_NAME, - svs.authorizeAddress.ip[0], svs.authorizeAddress.ip[1], - svs.authorizeAddress.ip[2], svs.authorizeAddress.ip[3], - BigShort( svs.authorizeAddress.port ) ); } + // we couldn't contact the auth server, let them in. + if(svs.authorizeAddress.type == NA_BAD) + Com_Printf("Couldn't resolve auth server address\n"); + // 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 - if ( svs.time - challenge->firstTime > AUTHORIZE_TIMEOUT ) { + else if(svs.time - challenge->firstTime > AUTHORIZE_TIMEOUT) Com_DPrintf( "authorize server timed out\n" ); - - challenge->pingTime = svs.time; - NET_OutOfBandPrint( NS_SERVER, challenge->adr, - "challengeResponse %i", challenge->challenge ); - return; - } - - // otherwise send their ip to the authorize server - if ( svs.authorizeAddress.type != NA_BAD ) { + else + { + // otherwise send their ip to the authorize server 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); @@ -132,22 +136,20 @@ void SV_GetChallenge( netadr_t from ) { if (fs && fs->string[0] != 0) { strcpy(game, fs->string); } - + // the 0 is for backwards compatibility with obsolete sv_allowanonymous flags // getIpAuthorize 0 NET_OutOfBandPrint( NS_SERVER, svs.authorizeAddress, - "getIpAuthorize %i %i.%i.%i.%i %s 0 %s", svs.challenges[i].challenge, + "getIpAuthorize %i %i.%i.%i.%i %s 0 %s", challenge->challenge, from.ip[0], from.ip[1], from.ip[2], from.ip[3], game, sv_strictAuth->string ); + + return; } } - else - { - challenge->pingTime = svs.time; - - NET_OutOfBandPrint( NS_SERVER, challenge->adr, - "challengeResponse %i", challenge->challenge ); - } #endif + + challenge->pingTime = svs.time; + NET_OutOfBandPrint( NS_SERVER, challenge->adr, "challengeResponse %i %s", challenge->challenge, clientChallenge); } #ifndef STANDALONE @@ -165,6 +167,7 @@ void SV_AuthorizeIpPacket( netadr_t from ) { int i; char *s; char *r; + challenge_t *challengeptr; if ( !NET_CompareBaseAdr( from, svs.authorizeAddress ) ) { Com_Printf( "SV_AuthorizeIpPacket: not from authorize server\n" ); @@ -182,44 +185,46 @@ void SV_AuthorizeIpPacket( netadr_t from ) { Com_Printf( "SV_AuthorizeIpPacket: challenge not found\n" ); return; } + + challengeptr = &svs.challenges[i]; // send a packet back to the original client - svs.challenges[i].pingTime = svs.time; + challengeptr->pingTime = svs.time; s = Cmd_Argv( 2 ); r = Cmd_Argv( 3 ); // reason if ( !Q_stricmp( s, "demo" ) ) { // they are a demo client trying to connect to a real server - NET_OutOfBandPrint( NS_SERVER, svs.challenges[i].adr, "print\nServer is not a demo server\n" ); + NET_OutOfBandPrint( NS_SERVER, challengeptr->adr, "print\nServer is not a demo server\n" ); // clear the challenge record so it won't timeout and let them through - Com_Memset( &svs.challenges[i], 0, sizeof( svs.challenges[i] ) ); + Com_Memset( challengeptr, 0, sizeof( *challengeptr ) ); return; } if ( !Q_stricmp( s, "accept" ) ) { - NET_OutOfBandPrint( NS_SERVER, svs.challenges[i].adr, - "challengeResponse %i", svs.challenges[i].challenge ); + NET_OutOfBandPrint(NS_SERVER, challengeptr->adr, + "challengeResponse %d %d", challengeptr->challenge, challengeptr->clientChallenge); return; } if ( !Q_stricmp( s, "unknown" ) ) { if (!r) { - NET_OutOfBandPrint( NS_SERVER, svs.challenges[i].adr, "print\nAwaiting CD key authorization\n" ); + NET_OutOfBandPrint( NS_SERVER, challengeptr->adr, "print\nAwaiting CD key authorization\n" ); } else { - NET_OutOfBandPrint( NS_SERVER, svs.challenges[i].adr, "print\n%s\n", r); + NET_OutOfBandPrint( NS_SERVER, challengeptr->adr, "print\n%s\n", r); } // clear the challenge record so it won't timeout and let them through - Com_Memset( &svs.challenges[i], 0, sizeof( svs.challenges[i] ) ); + Com_Memset( challengeptr, 0, sizeof( *challengeptr ) ); return; } // authorization failed if (!r) { - NET_OutOfBandPrint( NS_SERVER, svs.challenges[i].adr, "print\nSomeone is using this CD Key\n" ); + NET_OutOfBandPrint( NS_SERVER, challengeptr->adr, "print\nSomeone is using this CD Key\n" ); } else { - NET_OutOfBandPrint( NS_SERVER, svs.challenges[i].adr, "print\n%s\n", r ); + NET_OutOfBandPrint( NS_SERVER, challengeptr->adr, "print\n%s\n", r ); } // clear the challenge record so it won't timeout and let them through - Com_Memset( &svs.challenges[i], 0, sizeof( svs.challenges[i] ) ); + Com_Memset( challengeptr, 0, sizeof(*challengeptr) ); } #endif @@ -535,9 +540,11 @@ void SV_DropClient( client_t *drop, const char *reason ) { // see if we already have a challenge for this ip challenge = &svs.challenges[0]; - for (i = 0 ; i < MAX_CHALLENGES ; i++, challenge++) { - if ( NET_CompareAdr( drop->netchan.remoteAddress, challenge->adr ) ) { - challenge->connected = qfalse; + for (i = 0 ; i < MAX_CHALLENGES ; i++, challenge++) + { + if(NET_CompareAdr(drop->netchan.remoteAddress, challenge->adr)) + { + Com_Memset(challenge, 0, sizeof(*challenge)); break; } } diff --git a/code/server/sv_main.c b/code/server/sv_main.c index bce9c3d..23dc50f 100644 --- a/code/server/sv_main.c +++ b/code/server/sv_main.c @@ -548,7 +548,7 @@ static void SV_ConnectionlessPacket( netadr_t from, msg_t *msg ) { } else if (!Q_stricmp(c, "getinfo")) { SVC_Info( from ); } else if (!Q_stricmp(c, "getchallenge")) { - SV_GetChallenge( from ); + SV_GetChallenge(from); } else if (!Q_stricmp(c, "connect")) { SV_DirectConnect( from ); #ifndef STANDALONE -- cgit v1.2.3