diff options
-rw-r--r-- | src/client/cl_main.c | 85 | ||||
-rw-r--r-- | src/client/cl_net_chan.c | 6 | ||||
-rw-r--r-- | src/qcommon/net_chan.c | 27 | ||||
-rw-r--r-- | src/qcommon/qcommon.h | 9 | ||||
-rw-r--r-- | src/server/sv_client.c | 22 | ||||
-rw-r--r-- | src/server/sv_main.c | 4 |
6 files changed, 104 insertions, 49 deletions
diff --git a/src/client/cl_main.c b/src/client/cl_main.c index 3907c685..621d3cd6 100644 --- a/src/client/cl_main.c +++ b/src/client/cl_main.c @@ -585,7 +585,6 @@ void CL_WriteDemoMessage ( msg_t *msg, int headerBytes ) { len = clc.serverMessageSequence; swlen = LittleLong( len ); FS_Write (&swlen, 4, clc.demofile); - // skip the packet sequencing information len = msg->cursize - headerBytes; swlen = LittleLong(len); @@ -717,7 +716,6 @@ void CL_Record_f( void ) { clc.spDemoRecording = qfalse; } - Q_strncpyz( clc.demoName, demoName, sizeof( clc.demoName ) ); // don't start saving messages until a non-delta compressed message is received @@ -941,36 +939,41 @@ void CL_ReadDemoMessage( void ) { 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, PROTOCOL_VERSION); - - FS_FOpenFileRead( name, demofile, qtrue ); + FS_FOpenFileRead(name, demofile, qtrue); if (*demofile) { Com_Printf("Demo file: %s\n", name); - return; + return PROTOCOL_VERSION; } Com_Printf("Not found: %s\n", name); while(demo_protocols[i]) { + if(demo_protocols[i] == PROTOCOL_VERSION) + 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; } /* @@ -1047,11 +1050,11 @@ void CL_PlayDemo_f( void ) { 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); @@ -2286,7 +2289,9 @@ void CL_CheckForResend( void ) { // requesting a challenge // The challenge request shall be followed by a client challenge so no malicious server can hijack this connection. - Com_sprintf(data, sizeof(data), "getchallenge %d", clc.challenge); + // Add the heartbeat gamename so the server knows we're running the correct game and can reject the client + // with a meaningful message + Com_sprintf(data, sizeof(data), "getchallenge %d %s", clc.challenge, Cvar_VariableString("sv_heartbeat")); NET_OutOfBandPrint(NS_CLIENT, clc.serverAddress, "%s", data); break; @@ -2641,6 +2646,7 @@ Responses to broadcasts, etc void CL_ConnectionlessPacket( netadr_t from, msg_t *msg ) { char *s; char *c; + int challenge; MSG_BeginReadingOOB( msg ); MSG_ReadLong( msg ); // skip the -1 @@ -2656,26 +2662,35 @@ void CL_ConnectionlessPacket( netadr_t from, msg_t *msg ) { // challenge from the server we are connecting to if (!Q_stricmp(c, "challengeResponse")) { + char *strver; + int ver; + if (clc.state != CA_CONNECTING) { Com_DPrintf("Unwanted challenge response received. Ignored.\n"); return; } - if(!NET_CompareAdr(from, clc.serverAddress)) + c = Cmd_Argv(2); + if(*c) + challenge = atoi(c); + + strver = Cmd_Argv(3); + if(*strver) { - // This challenge response is not coming from the expected address. - // Check whether we have a matching client challenge to prevent - // connection hi-jacking. + ver = atoi(strver); - c = Cmd_Argv(2); - - if(!*c || atoi(c) != clc.challenge) + if(ver != PROTOCOL_VERSION) { - Com_DPrintf("Challenge response received from unexpected source. Ignored.\n"); - return; + Com_Printf(S_COLOR_YELLOW "Warning: Server reports protocol version %d, we have %d. " + "Trying anyways.\n", ver, PROTOCOL_VERSION); } } + if(!*c || challenge != clc.challenge) + { + Com_Printf("Bad challenge for challengeResponse. Ignored.\n"); + return; + } // start sending challenge response instead of challenge request packets clc.challenge = atoi(Cmd_Argv(1)); @@ -2704,7 +2719,26 @@ void CL_ConnectionlessPacket( netadr_t from, msg_t *msg ) { Com_Printf( "connectResponse from wrong address. Ignored.\n" ); return; } - Netchan_Setup (NS_CLIENT, &clc.netchan, from, Cvar_VariableValue( "net_qport" ) ); + + 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.state = CA_CONNECTED; clc.lastPacketSentTime = -9999; // send first packet immediately return; @@ -2722,13 +2756,6 @@ void CL_ConnectionlessPacket( netadr_t from, msg_t *msg ) { 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) ); @@ -2742,14 +2769,16 @@ void CL_ConnectionlessPacket( netadr_t from, msg_t *msg ) { } // echo request from server - if ( !Q_stricmp(c, "print") ) { + if(!Q_stricmp(c, "print")){ s = MSG_ReadString( msg ); + Q_strncpyz( clc.serverMessage, s, sizeof( clc.serverMessage ) ); while( clc.serverMessage[ strlen( clc.serverMessage ) - 1 ] == '\n' ) clc.serverMessage[ strlen( clc.serverMessage ) - 1 ] = '\0'; Com_Printf( "%s", s ); + return; } diff --git a/src/client/cl_net_chan.c b/src/client/cl_net_chan.c index 561f322a..fbfc4dc9 100644 --- a/src/client/cl_net_chan.c +++ b/src/client/cl_net_chan.c @@ -148,9 +148,6 @@ void CL_Netchan_Transmit( netchan_t *chan, msg_t* msg ) { Netchan_Transmit( chan, msg->cursize, msg->data ); } -extern int oldsize; -int newsize = 0; - /* ================= CL_Netchan_Process @@ -162,7 +159,8 @@ qboolean CL_Netchan_Process( netchan_t *chan, msg_t *msg ) { ret = Netchan_Process( chan, msg ); if (!ret) return qfalse; + CL_Netchan_Decode( msg ); - newsize += msg->cursize; + return qtrue; } diff --git a/src/qcommon/net_chan.c b/src/qcommon/net_chan.c index 4aacfa7e..d9c6760b 100644 --- a/src/qcommon/net_chan.c +++ b/src/qcommon/net_chan.c @@ -84,7 +84,8 @@ Netchan_Setup 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) +{ Com_Memset (chan, 0, sizeof(*chan)); chan->sock = sock; @@ -92,6 +93,7 @@ void Netchan_Setup( netsrc_t sock, netchan_t *chan, netadr_t adr, int qport ) { chan->qport = qport; chan->incomingSequence = 0; chan->outgoingSequence = 1; + chan->challenge = challenge; } // TTimo: unused, commenting out to make gcc happy @@ -191,17 +193,21 @@ void Netchan_TransmitNextFragment( netchan_t *chan ) { 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 ); } + 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 ) { @@ -269,12 +275,14 @@ void Netchan_Transmit( netchan_t *chan, int length, const byte *data ) { 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); + + MSG_WriteLong(&send, NETCHAN_GENCHECKSUM(chan->challenge, chan->outgoingSequence)); + + chan->outgoingSequence++; MSG_WriteData( &send, data, length ); @@ -306,6 +314,7 @@ qboolean Netchan_Process( netchan_t *chan, msg_t *msg ) { int sequence; int qport; int fragmentStart, fragmentLength; + int checksum; qboolean fragmented; // XOR unscramble all data in the packet after the header @@ -328,6 +337,12 @@ qboolean Netchan_Process( netchan_t *chan, msg_t *msg ) { qport = MSG_ReadShort( msg ); } + 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 ); diff --git a/src/qcommon/qcommon.h b/src/qcommon/qcommon.h index 165dccae..28834168 100644 --- a/src/qcommon/qcommon.h +++ b/src/qcommon/qcommon.h @@ -193,7 +193,8 @@ void NET_Sleep(int msec); #define MAX_DOWNLOAD_WINDOW 48 // ACK window of 48 download chunks. Cannot set this higher, or clients // will overflow the reliable commands buffer #define MAX_DOWNLOAD_BLKSIZE 1024 // 896 byte block chunks - + +#define NETCHAN_GENCHECKSUM(challenge, sequence) ((challenge) ^ ((sequence) * (challenge))) /* Netchan handles packet fragmentation and out of order / duplicate suppression @@ -222,10 +223,12 @@ typedef struct { int unsentFragmentStart; int unsentLength; byte unsentBuffer[MAX_MSGLEN]; + + int challenge; } 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); void Netchan_Transmit( netchan_t *chan, int length, const byte *data ); void Netchan_TransmitNextFragment( netchan_t *chan ); @@ -241,7 +244,7 @@ PROTOCOL ============================================================== */ -#define PROTOCOL_VERSION 70 +#define PROTOCOL_VERSION 71 // maintain a list of compatible protocols for demo playing // NOTE: that stuff only works with two digits protocols diff --git a/src/server/sv_client.c b/src/server/sv_client.c index 8ff3f0a1..99dca704 100644 --- a/src/server/sv_client.c +++ b/src/server/sv_client.c @@ -60,6 +60,19 @@ void SV_GetChallenge(netadr_t from) int clientChallenge; challenge_t *challenge; qboolean wasfound = qfalse; + char *gameName; + + gameName = Cmd_Argv(2); + if(gameName && *gameName) + { + // reject client if the heartbeat string sent by the client doesn't match ours + if(strcmp(gameName, sv_heartbeat->string)) + { + NET_OutOfBandPrint(NS_SERVER, from, "print\nGame mismatch: This is a %s server\n", + sv_heartbeat->string); + return; + } + } oldest = 0; oldestClientTime = oldestTime = 0x7fffffff; @@ -139,8 +152,9 @@ void SV_DirectConnect( netadr_t from ) { version = atoi( Info_ValueForKey( userinfo, "protocol" ) ); if ( version != PROTOCOL_VERSION ) { - NET_OutOfBandPrint( NS_SERVER, from, "print\nServer uses protocol version %i\n", PROTOCOL_VERSION ); - Com_DPrintf (" rejected connect from version %i\n", version); + NET_OutOfBandPrint(NS_SERVER, from, "print\nServer uses protocol version %i " + "(yours is %i).\n", PROTOCOL_VERSION, version); + Com_DPrintf(" rejected connect from version %i\n", version); return; } @@ -308,7 +322,7 @@ gotnewcl: newcl->challenge = challenge; // save the address - Netchan_Setup (NS_SERVER, &newcl->netchan , from, qport); + Netchan_Setup(NS_SERVER, &newcl->netchan, from, qport, challenge); // init the netchan queue newcl->netchan_end_queue = &newcl->netchan_start_queue; @@ -329,7 +343,7 @@ gotnewcl: 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 ); diff --git a/src/server/sv_main.c b/src/server/sv_main.c index 014c3a96..f746c180 100644 --- a/src/server/sv_main.c +++ b/src/server/sv_main.c @@ -865,10 +865,6 @@ void SV_PacketEvent( netadr_t from, msg_t *msg ) { } return; } - - // if we received a sequenced packet from an address we don't recognize, - // send an out of band disconnect packet to it - NET_OutOfBandPrint( NS_SERVER, from, "disconnect" ); } |