Make servers echo challenge codes from client getchallenge commands

This commit is contained in:
Thilo Schulz 2009-06-01 05:28:47 +00:00
parent eaaaa6f5fc
commit 18cc7c1ed3
4 changed files with 68 additions and 60 deletions

View file

@ -132,8 +132,8 @@ NET
#define MAX_RELIABLE_COMMANDS 64 // max string commands buffered for restransmit
typedef enum {
NA_BAD = 0, // an address lookup failed
NA_BOT,
NA_BAD, // an address lookup failed
NA_LOOPBACK,
NA_BROADCAST,
NA_IP,

View file

@ -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 );

View file

@ -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 <challenge> <IP> <game> 0 <auth-flag>
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;
}
}

View file

@ -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