[quake3-commits] r1950 - in trunk/code: client qcommon server
DONOTREPLY at icculus.org
DONOTREPLY at icculus.org
Wed Apr 27 12:03:36 EDT 2011
Author: thilo
Date: 2011-04-27 12:03:35 -0400 (Wed, 27 Apr 2011)
New Revision: 1950
Modified:
trunk/code/client/cl_main.c
trunk/code/client/cl_net_chan.c
trunk/code/client/client.h
trunk/code/qcommon/common.c
trunk/code/qcommon/files.c
trunk/code/qcommon/net_chan.c
trunk/code/qcommon/q_shared.c
trunk/code/qcommon/q_shared.h
trunk/code/qcommon/qcommon.h
trunk/code/server/server.h
trunk/code/server/sv_client.c
Log:
- Harden the client and server protocol against UDP spoofing attacks. This will defend ioquake3 against http://aluigi.altervista.org/papers/q3noclient.txt (#3041)
- Retains full compatibility to the old but unsecure protocol between clients and servers
- Harden the connection process against DoS attacks, possibly connected to UDP spoofing
Modified: trunk/code/client/cl_main.c
===================================================================
--- trunk/code/client/cl_main.c 2011-04-26 09:48:40 UTC (rev 1949)
+++ trunk/code/client/cl_main.c 2011-04-27 16:03:35 UTC (rev 1950)
@@ -533,7 +533,6 @@
len = clc.serverMessageSequence;
swlen = LittleLong( len );
FS_Write (&swlen, 4, clc.demofile);
-
// skip the packet sequencing information
len = msg->cursize - headerBytes;
swlen = LittleLong(len);
@@ -636,14 +635,24 @@
if ( Cmd_Argc() == 2 ) {
s = Cmd_Argv(1);
Q_strncpyz( demoName, s, sizeof( demoName ) );
- Com_sprintf (name, sizeof(name), "demos/%s.%s%d", demoName, DEMOEXT, com_protocol->integer );
+#ifdef PROTOCOL_SUPPORT_OLD
+ if(clc.compat)
+ Com_sprintf(name, sizeof(name), "demos/%s.%s%d", demoName, DEMOEXT, com_oldprotocol->integer);
+ else
+#endif
+ Com_sprintf(name, sizeof(name), "demos/%s.%s%d", demoName, DEMOEXT, com_protocol->integer);
} else {
int number;
// scan for a free demo name
for ( number = 0 ; number <= 9999 ; number++ ) {
CL_DemoFilename( number, demoName );
- Com_sprintf (name, sizeof(name), "demos/%s.%s%d", demoName, DEMOEXT, com_protocol->integer );
+#ifdef PROTOCOL_SUPPORT_OLD
+ if(clc.compat)
+ Com_sprintf(name, sizeof(name), "demos/%s.%s%d", demoName, DEMOEXT, com_oldprotocol->integer);
+ else
+#endif
+ Com_sprintf(name, sizeof(name), "demos/%s.%s%d", demoName, DEMOEXT, com_protocol->integer);
if (!FS_FileExists(name))
break; // file doesn't exist
@@ -665,7 +674,6 @@
clc.spDemoRecording = qfalse;
}
-
Q_strncpyz( clc.demoName, demoName, sizeof( clc.demoName ) );
// don't start saving messages until a non-delta compressed message is received
@@ -889,36 +897,62 @@
CL_WalkDemoExt
====================
*/
-static void CL_WalkDemoExt(char *arg, char *name, int *demofile)
+static int CL_WalkDemoExt(char *arg, char *name, int *demofile)
{
int i = 0;
*demofile = 0;
- Com_sprintf (name, MAX_OSPATH, "demos/%s.%s%d", arg, DEMOEXT, com_protocol->integer);
-
- FS_FOpenFileRead( name, demofile, qtrue );
-
- if (*demofile)
+#ifdef PROTOCOL_SUPPORT_OLD
+ if(com_oldprotocol->integer > 0)
{
- Com_Printf("Demo file: %s\n", name);
- return;
+ Com_sprintf(name, MAX_OSPATH, "demos/%s.%s%d", arg, DEMOEXT, com_oldprotocol->integer);
+ FS_FOpenFileRead(name, demofile, qtrue);
+
+ if (*demofile)
+ {
+ Com_Printf("Demo file: %s\n", name);
+ return com_oldprotocol->integer;
+ }
}
+
+ if(com_protocol->integer != com_oldprotocol->integer)
+#endif
+ {
+ Com_sprintf(name, MAX_OSPATH, "demos/%s.%s%d", arg, DEMOEXT, com_protocol->integer);
+ FS_FOpenFileRead(name, demofile, qtrue);
+ if (*demofile)
+ {
+ Com_Printf("Demo file: %s\n", name);
+ return com_protocol->integer;
+ }
+ }
+
Com_Printf("Not found: %s\n", name);
while(demo_protocols[i])
{
+#ifdef PROTOCOL_SUPPORT_OLD
+ if(demo_protocols[i] == com_oldprotocol->integer)
+ continue;
+#endif
+ if(demo_protocols[i] == com_protocol->integer)
+ continue;
+
Com_sprintf (name, MAX_OSPATH, "demos/%s.%s%d", arg, DEMOEXT, demo_protocols[i]);
FS_FOpenFileRead( name, demofile, qtrue );
if (*demofile)
{
Com_Printf("Demo file: %s\n", name);
- break;
+
+ return demo_protocols[i];
}
else
Com_Printf("Not found: %s\n", name);
i++;
}
+
+ return -1;
}
/*
@@ -978,7 +1012,11 @@
break;
}
- if(demo_protocols[i] || protocol == com_protocol->integer)
+ if(demo_protocols[i] || protocol == com_protocol->integer
+#ifdef PROTOCOL_SUPPORT_OLD
+ || protocol == com_oldprotocol->integer
+#endif
+ )
{
Com_sprintf(name, sizeof(name), "demos/%s", arg);
FS_FOpenFileRead(name, &clc.demofile, qtrue);
@@ -995,11 +1033,11 @@
Q_strncpyz(retry, arg, len + 1);
retry[len] = '\0';
- CL_WalkDemoExt(retry, name, &clc.demofile);
+ protocol = CL_WalkDemoExt(retry, name, &clc.demofile);
}
}
else
- CL_WalkDemoExt(arg, name, &clc.demofile);
+ protocol = CL_WalkDemoExt(arg, name, &clc.demofile);
if (!clc.demofile) {
Com_Error( ERR_DROP, "couldn't open %s", name);
@@ -1013,6 +1051,13 @@
clc.demoplaying = qtrue;
Q_strncpyz( cls.servername, Cmd_Argv(1), sizeof( cls.servername ) );
+#ifdef PROTOCOL_SUPPORT_OLD
+ if(protocol <= com_oldprotocol->integer)
+ clc.compat = qtrue;
+ else
+ clc.compat = qfalse;
+#endif
+
// read demo messages until connected
while ( cls.state >= CA_CONNECTED && cls.state < CA_PRIMED ) {
CL_ReadDemoMessage();
@@ -2153,7 +2198,16 @@
port = Cvar_VariableValue ("net_qport");
Q_strncpyz( info, Cvar_InfoString( CVAR_USERINFO ), sizeof( info ) );
- Info_SetValueForKey( info, "protocol", va("%i", com_protocol->integer ) );
+
+#ifdef PROTOCOL_SUPPORT_OLD
+ if(com_oldprotocol->integer == com_protocol->integer)
+ clc.compat = qtrue;
+
+ if(clc.compat)
+ Info_SetValueForKey(info, "protocol", va("%i", com_oldprotocol->integer));
+ else
+#endif
+ Info_SetValueForKey(info, "protocol", va("%i", com_protocol->integer));
Info_SetValueForKey( info, "qport", va("%i", port ) );
Info_SetValueForKey( info, "challenge", va("%i", clc.challenge ) );
@@ -2394,6 +2448,7 @@
void CL_ConnectionlessPacket( netadr_t from, msg_t *msg ) {
char *s;
char *c;
+ int challenge;
MSG_BeginReadingOOB( msg );
MSG_ReadLong( msg ); // skip the -1
@@ -2415,20 +2470,35 @@
return;
}
- if(!NET_CompareAdr(from, clc.serverAddress))
+ c = Cmd_Argv(2);
+ if(*c)
+ challenge = atoi(c);
+
+#ifdef PROTOCOL_SUPPORT_OLD
+ if(!clc.compat)
{
- // This challenge response is not coming from the expected address.
- // Check whether we have a matching client challenge to prevent
- // connection hi-jacking.
-
- c = Cmd_Argv(2);
-
- if(!*c || atoi(c) != clc.challenge)
+ if(!*c || challenge != clc.challenge)
{
- Com_DPrintf("Challenge response received from unexpected source. Ignored.\n");
+ Com_Printf("Bad challenge for challengeResponse. Ignored.\n");
return;
}
}
+ else
+#endif
+ {
+ if(!NET_CompareAdr(from, clc.serverAddress))
+ {
+ // This challenge response is not coming from the expected address.
+ // Check whether we have a matching client challenge to prevent
+ // connection hi-jacking.
+
+ if(!*c || challenge != clc.challenge)
+ {
+ Com_DPrintf("Challenge response received from unexpected source. Ignored.\n");
+ return;
+ }
+ }
+ }
// start sending challenge response instead of challenge request packets
clc.challenge = atoi(Cmd_Argv(1));
@@ -2457,7 +2527,34 @@
Com_Printf( "connectResponse from wrong address. Ignored.\n" );
return;
}
- Netchan_Setup (NS_CLIENT, &clc.netchan, from, Cvar_VariableValue( "net_qport" ) );
+
+#ifdef PROTOCOL_SUPPORT_OLD
+ if(!clc.compat)
+ {
+ c = Cmd_Argv(1);
+
+ if(*c)
+ challenge = atoi(c);
+ else
+ {
+ Com_Printf("Bad connectResponse received. Ignored.\n");
+ return;
+ }
+
+ if(challenge != clc.challenge)
+ {
+ Com_Printf("ConnectResponse with bad challenge received. Ignored.\n");
+ return;
+ }
+ }
+
+ Netchan_Setup(NS_CLIENT, &clc.netchan, from, Cvar_VariableValue("net_qport"),
+ clc.challenge, clc.compat);
+#else
+ Netchan_Setup(NS_CLIENT, &clc.netchan, from, Cvar_VariableValue("net_qport"),
+ clc.challenge);
+#endif
+
cls.state = CA_CONNECTED;
clc.lastPacketSentTime = -9999; // send first packet immediately
return;
@@ -2475,13 +2572,6 @@
return;
}
- // a disconnect message from the server, which will happen if the server
- // dropped the connection but it is still getting packets from us
- if (!Q_stricmp(c, "disconnect")) {
- CL_DisconnectPacket( from );
- return;
- }
-
// echo request from server
if ( !Q_stricmp(c, "echo") ) {
NET_OutOfBandPrint( NS_CLIENT, from, "%s", Cmd_Argv(1) );
@@ -2501,10 +2591,33 @@
}
// echo request from server
- if ( !Q_stricmp(c, "print") ) {
+ if(!Q_stricmp(c, "print")){
s = MSG_ReadString( msg );
+
+ #ifdef PROTOCOL_SUPPORT_OLD
+ // Hack to detect legacy server protocol
+ if(cls.state == CA_CHALLENGING && com_oldprotocol->integer > 0)
+ {
+ char buf[128];
+ int len;
+
+ len = Com_sprintf(buf, sizeof(buf), "Server uses protocol version %d",
+ com_oldprotocol->integer);
+
+ if(len < sizeof(buf) && !Q_strncmp(s, buf, len) && !isdigit(s[len]))
+ {
+ // This is an old, but compatible protocol version.
+ // Go back to connecting state.
+ clc.compat = qtrue;
+ cls.state = CA_CONNECTING;
+ return;
+ }
+ }
+ #endif
+
Q_strncpyz( clc.serverMessage, s, sizeof( clc.serverMessage ) );
Com_Printf( "%s", s );
+
return;
}
@@ -3445,7 +3558,13 @@
// if this isn't the correct protocol version, ignore it
prot = atoi( Info_ValueForKey( infoString, "protocol" ) );
- if ( prot != com_protocol->integer ) {
+
+ if(prot != com_protocol->integer
+#ifdef PROTOCOL_SUPPORT_OLD
+ && prot != com_oldprotocol->integer
+#endif
+ )
+ {
Com_DPrintf( "Different protocol info packet: %s\n", infoString );
return;
}
Modified: trunk/code/client/cl_net_chan.c
===================================================================
--- trunk/code/client/cl_net_chan.c 2011-04-26 09:48:40 UTC (rev 1949)
+++ trunk/code/client/cl_net_chan.c 2011-04-27 16:03:35 UTC (rev 1950)
@@ -147,9 +147,6 @@
Netchan_Transmit( chan, msg->cursize, msg->data );
}
-extern int oldsize;
-int newsize = 0;
-
/*
=================
CL_Netchan_Process
@@ -161,7 +158,8 @@
ret = Netchan_Process( chan, msg );
if (!ret)
return qfalse;
+
CL_Netchan_Decode( msg );
- newsize += msg->cursize;
+
return qtrue;
}
Modified: trunk/code/client/client.h
===================================================================
--- trunk/code/client/client.h 2011-04-26 09:48:40 UTC (rev 1949)
+++ trunk/code/client/client.h 2011-04-27 16:03:35 UTC (rev 1950)
@@ -260,6 +260,10 @@
float voipPower;
#endif
+#ifdef PROTOCOL_SUPPORT_OLD
+ qboolean compat;
+#endif
+
// big stuff at end of structure so most offsets are 15 bits or less
netchan_t netchan;
} clientConnection_t;
Modified: trunk/code/qcommon/common.c
===================================================================
--- trunk/code/qcommon/common.c 2011-04-26 09:48:40 UTC (rev 1949)
+++ trunk/code/qcommon/common.c 2011-04-27 16:03:35 UTC (rev 1950)
@@ -32,7 +32,7 @@
#endif
int demo_protocols[] =
-{ 66, 67, 68, 0 };
+{ 67, 66, 0 };
#define MAX_NUM_ARGVS 50
@@ -86,6 +86,9 @@
cvar_t *com_abnormalExit;
cvar_t *com_standalone;
cvar_t *com_protocol;
+#ifdef PROTOCOL_SUPPORT_OLD
+cvar_t *com_oldprotocol;
+#endif
cvar_t *com_basegame;
cvar_t *com_homepath;
cvar_t *com_busyWait;
@@ -2710,6 +2713,9 @@
s = va("%s %s %s", Q3_VERSION, PLATFORM_STRING, __DATE__ );
com_version = Cvar_Get ("version", s, CVAR_ROM | CVAR_SERVERINFO );
com_protocol = Cvar_Get ("protocol", va("%i", PROTOCOL_VERSION), CVAR_SERVERINFO | CVAR_INIT);
+#ifdef PROTOCOL_SUPPORT_OLD
+ com_oldprotocol = Cvar_Get ("oldprotocol", va("%i", PROTOCOL_OLD_VERSION), CVAR_INIT);
+#endif
Sys_Init();
Modified: trunk/code/qcommon/files.c
===================================================================
--- trunk/code/qcommon/files.c 2011-04-26 09:48:40 UTC (rev 1949)
+++ trunk/code/qcommon/files.c 2011-04-27 16:03:35 UTC (rev 1950)
@@ -1030,6 +1030,11 @@
if(protocol == com_protocol->integer)
return qtrue;
+#ifdef PROTOCOL_SUPPORT_OLD
+ if(protocol == PROTOCOL_OLD_VERSION)
+ return qtrue;
+#endif
+
for(index = 0; demo_protocols[index]; index++)
{
if(demo_protocols[index] == protocol)
Modified: trunk/code/qcommon/net_chan.c
===================================================================
--- trunk/code/qcommon/net_chan.c 2011-04-26 09:48:40 UTC (rev 1949)
+++ trunk/code/qcommon/net_chan.c 2011-04-27 16:03:35 UTC (rev 1950)
@@ -83,7 +83,12 @@
called to open a channel to a remote system
==============
*/
-void Netchan_Setup( netsrc_t sock, netchan_t *chan, netadr_t adr, int qport ) {
+void Netchan_Setup(netsrc_t sock, netchan_t *chan, netadr_t adr, int qport, int challenge
+#ifdef PROTOCOL_SUPPORT_OLD
+ , qboolean compat
+#endif
+ )
+{
Com_Memset (chan, 0, sizeof(*chan));
chan->sock = sock;
@@ -91,6 +96,10 @@
chan->qport = qport;
chan->incomingSequence = 0;
chan->outgoingSequence = 1;
+#ifdef PROTOCOL_SUPPORT_OLD
+ chan->compat = compat;
+ chan->challenge = challenge;
+#endif
}
// TTimo: unused, commenting out to make gcc happy
@@ -190,17 +199,24 @@
msg_t send;
byte send_buf[MAX_PACKETLEN];
int fragmentLength;
+ int outgoingSequence;
// write the packet header
MSG_InitOOB (&send, send_buf, sizeof(send_buf)); // <-- only do the oob here
- MSG_WriteLong( &send, chan->outgoingSequence | FRAGMENT_BIT );
+ outgoingSequence = chan->outgoingSequence | FRAGMENT_BIT;
+ MSG_WriteLong(&send, outgoingSequence);
// send the qport if we are a client
if ( chan->sock == NS_CLIENT ) {
MSG_WriteShort( &send, qport->integer );
}
+#ifdef PROTOCOL_SUPPORT_OLD
+ if(!chan->compat)
+#endif
+ MSG_WriteLong(&send, NETCHAN_GENCHECKSUM(chan->challenge, chan->outgoingSequence));
+
// copy the reliable message to the packet first
fragmentLength = FRAGMENT_SIZE;
if ( chan->unsentFragmentStart + fragmentLength > chan->unsentLength ) {
@@ -268,13 +284,18 @@
MSG_InitOOB (&send, send_buf, sizeof(send_buf));
MSG_WriteLong( &send, chan->outgoingSequence );
- chan->outgoingSequence++;
// send the qport if we are a client
- if ( chan->sock == NS_CLIENT ) {
- MSG_WriteShort( &send, qport->integer );
- }
+ if(chan->sock == NS_CLIENT)
+ MSG_WriteShort(&send, qport->integer);
+#ifdef PROTOCOL_SUPPORT_OLD
+ if(!chan->compat)
+#endif
+ MSG_WriteLong(&send, NETCHAN_GENCHECKSUM(chan->challenge, chan->outgoingSequence));
+
+ chan->outgoingSequence++;
+
MSG_WriteData( &send, data, length );
// send the datagram
@@ -327,6 +348,17 @@
qport = MSG_ReadShort( msg );
}
+#ifdef PROTOCOL_SUPPORT_OLD
+ if(!chan->compat)
+#endif
+ {
+ int checksum = MSG_ReadLong(msg);
+
+ // UDP spoofing protection
+ if(NETCHAN_GENCHECKSUM(chan->challenge, sequence) != checksum)
+ return qfalse;
+ }
+
// read the fragment information
if ( fragmented ) {
fragmentStart = MSG_ReadShort( msg );
Modified: trunk/code/qcommon/q_shared.c
===================================================================
--- trunk/code/qcommon/q_shared.c 2011-04-26 09:48:40 UTC (rev 1949)
+++ trunk/code/qcommon/q_shared.c 2011-04-27 16:03:35 UTC (rev 1950)
@@ -962,7 +962,7 @@
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;
@@ -973,6 +973,8 @@
if(len >= size)
Com_Printf("Com_sprintf: Output length %d too short, require %d bytes.\n", size, len);
+
+ return len;
}
/*
Modified: trunk/code/qcommon/q_shared.h
===================================================================
--- trunk/code/qcommon/q_shared.h 2011-04-26 09:48:40 UTC (rev 1949)
+++ trunk/code/qcommon/q_shared.h 2011-04-27 16:03:35 UTC (rev 1950)
@@ -34,6 +34,7 @@
#define GAMENAME_FOR_MASTER "iofoo3" // must NOT contain whitespaces
#define HEARTBEAT_FOR_MASTER GAMENAME_FOR_MASTER
#define FLATLINE_FOR_MASTER GAMENAME_FOR_MASTER "dead"
+// #define PROTOCOL_SUPPORT_OLD // You probably don't need this for your standalone game
#else
#define PRODUCT_NAME "ioq3"
#define BASEGAME "baseq3"
@@ -42,6 +43,7 @@
#define GAMENAME_FOR_MASTER "Quake3Arena"
#define HEARTBEAT_FOR_MASTER "QuakeArena-1"
#define FLATLINE_FOR_MASTER HEARTBEAT_FOR_MASTER
+ #define PROTOCOL_SUPPORT_OLD
#endif
#define BASETA "missionpack"
@@ -682,7 +684,7 @@
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 );
Modified: trunk/code/qcommon/qcommon.h
===================================================================
--- trunk/code/qcommon/qcommon.h 2011-04-26 09:48:40 UTC (rev 1949)
+++ trunk/code/qcommon/qcommon.h 2011-04-27 16:03:35 UTC (rev 1950)
@@ -194,8 +194,9 @@
#define MAX_DOWNLOAD_WINDOW 8 // max of eight download frames
#define MAX_DOWNLOAD_BLKSIZE 2048 // 2048 byte block chunks
-
+#define NETCHAN_GENCHECKSUM(challenge, sequence) ((challenge) ^ ((sequence) * (challenge)))
+
/*
Netchan handles packet fragmentation and out of order / duplicate suppression
*/
@@ -223,10 +224,20 @@
int unsentFragmentStart;
int unsentLength;
byte unsentBuffer[MAX_MSGLEN];
+
+ int challenge;
+
+#ifdef PROTOCOL_SUPPORT_OLD
+ qboolean compat;
+#endif
} netchan_t;
void Netchan_Init( int qport );
-void Netchan_Setup( netsrc_t sock, netchan_t *chan, netadr_t adr, int qport );
+void Netchan_Setup(netsrc_t sock, netchan_t *chan, netadr_t adr, int qport, int challenge
+#ifdef PROTOCOL_SUPPORT_OLD
+ , qboolean compat
+#endif
+);
void Netchan_Transmit( netchan_t *chan, int length, const byte *data );
void Netchan_TransmitNextFragment( netchan_t *chan );
@@ -242,7 +253,8 @@
==============================================================
*/
-#define PROTOCOL_VERSION 68
+#define PROTOCOL_VERSION 69
+#define PROTOCOL_OLD_VERSION 68
// 1.31 - 67
// maintain a list of compatible protocols for demo playing
@@ -857,6 +869,9 @@
extern cvar_t *sv_packetdelay;
extern cvar_t *com_protocol;
+#ifdef PROTOCOL_SUPPORT_OLD
+extern cvar_t *com_oldprotocol;
+#endif
// com_speeds times
extern int time_game;
Modified: trunk/code/server/server.h
===================================================================
--- trunk/code/server/server.h 2011-04-26 09:48:40 UTC (rev 1949)
+++ trunk/code/server/server.h 2011-04-27 16:03:35 UTC (rev 1950)
@@ -188,7 +188,11 @@
#endif
int oldServerTime;
- qboolean csUpdated[MAX_CONFIGSTRINGS+1];
+ qboolean csUpdated[MAX_CONFIGSTRINGS+1];
+
+#ifdef PROTOCOL_SUPPORT_OLD
+ qboolean compat;
+#endif
} client_t;
//=============================================================================
@@ -197,7 +201,11 @@
// 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
Modified: trunk/code/server/sv_client.c
===================================================================
--- trunk/code/server/sv_client.c 2011-04-26 09:48:40 UTC (rev 1949)
+++ trunk/code/server/sv_client.c 2011-04-27 16:03:35 UTC (rev 1950)
@@ -55,8 +55,10 @@
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 @@
}
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,18 +99,17 @@
{
// 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.
// Drop also for addresses coming in on local LAN and for stand-alone games independent from id's assets.
@@ -121,7 +137,7 @@
// 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 @@
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,7 @@
#endif
challenge->pingTime = svs.time;
- NET_OutOfBandPrint( NS_SERVER, challenge->adr, "challengeResponse %i %s", challenge->challenge, clientChallenge);
+ NET_OutOfBandPrint( NS_SERVER, challenge->adr, "challengeResponse %i %d", challenge->challenge, clientChallenge);
}
#ifndef STANDALONE
@@ -289,6 +301,9 @@
intptr_t denied;
int count;
char *ip;
+#ifdef PROTOCOL_SUPPORT_OLD
+ qboolean compat = qfalse;
+#endif
Com_DPrintf ("SVC_DirectConnect ()\n");
@@ -301,11 +316,21 @@
Q_strncpyz( userinfo, Cmd_Argv(1), sizeof(userinfo) );
- version = atoi( Info_ValueForKey( userinfo, "protocol" ) );
- if ( version != com_protocol->integer ) {
- NET_OutOfBandPrint( NS_SERVER, from, "print\nServer uses protocol version %i (yours is %i).\n", com_protocol->integer, version );
- Com_DPrintf (" rejected connect from version %i\n", version);
- return;
+ version = atoi(Info_ValueForKey(userinfo, "protocol"));
+
+#ifdef PROTOCOL_SUPPORT_OLD
+ if(version > 0 && com_oldprotocol->integer == version)
+ compat = qtrue;
+ else
+#endif
+ {
+ if(version != com_protocol->integer)
+ {
+ NET_OutOfBandPrint(NS_SERVER, from, "print\nServer uses protocol version %i "
+ "(yours is %i).\n", com_protocol->integer, version);
+ Com_DPrintf(" rejected connect from version %i\n", version);
+ return;
+ }
}
challenge = atoi( Info_ValueForKey( userinfo, "challenge" ) );
@@ -487,7 +512,12 @@
newcl->challenge = challenge;
// save the address
- Netchan_Setup (NS_SERVER, &newcl->netchan , from, qport);
+#ifdef PROTOCOL_SUPPORT_OLD
+ newcl->compat = compat;
+ Netchan_Setup(NS_SERVER, &newcl->netchan, from, qport, challenge, compat);
+#else
+ Netchan_Setup(NS_SERVER, &newcl->netchan, from, qport, challenge);
+#endif
// init the netchan queue
newcl->netchan_end_queue = &newcl->netchan_start_queue;
@@ -508,7 +538,7 @@
SV_UserinfoChanged( newcl );
// send the connect packet to the client
- NET_OutOfBandPrint( NS_SERVER, from, "connectResponse" );
+ NET_OutOfBandPrint(NS_SERVER, from, "connectResponse %d", challenge);
Com_DPrintf( "Going from CS_FREE to CS_CONNECTED for %s\n", newcl->name );
More information about the quake3-commits
mailing list