summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/client/cl_main.c85
-rw-r--r--src/client/cl_net_chan.c6
-rw-r--r--src/qcommon/net_chan.c27
-rw-r--r--src/qcommon/qcommon.h9
-rw-r--r--src/server/sv_client.c22
-rw-r--r--src/server/sv_main.c4
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" );
}