- Implement dual protocol support (#4962)

- Fix several UDP spoofing security issues
This commit is contained in:
Thilo Schulz 2011-07-12 11:59:48 +00:00
parent 309c322b80
commit e06c117e9e
13 changed files with 550 additions and 247 deletions

View file

@ -533,7 +533,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);
@ -636,14 +635,24 @@ void CL_Record_f( void ) {
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 LEGACY_PROTOCOL
if(clc.compat)
Com_sprintf(name, sizeof(name), "demos/%s.%s%d", demoName, DEMOEXT, com_legacyprotocol->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 LEGACY_PROTOCOL
if(clc.compat)
Com_sprintf(name, sizeof(name), "demos/%s.%s%d", demoName, DEMOEXT, com_legacyprotocol->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 @@ 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
@ -889,36 +897,62 @@ 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, com_protocol->integer);
FS_FOpenFileRead( name, demofile, qtrue );
if (*demofile)
#ifdef LEGACY_PROTOCOL
if(com_legacyprotocol->integer > 0)
{
Com_Printf("Demo file: %s\n", name);
return;
Com_sprintf(name, MAX_OSPATH, "demos/%s.%s%d", arg, DEMOEXT, com_legacyprotocol->integer);
FS_FOpenFileRead(name, demofile, qtrue);
if (*demofile)
{
Com_Printf("Demo file: %s\n", name);
return com_legacyprotocol->integer;
}
}
if(com_protocol->integer != com_legacyprotocol->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 LEGACY_PROTOCOL
if(demo_protocols[i] == com_legacyprotocol->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 @@ void CL_PlayDemo_f( void ) {
break;
}
if(demo_protocols[i] || protocol == com_protocol->integer)
if(demo_protocols[i] || protocol == com_protocol->integer
#ifdef LEGACY_PROTOCOL
|| protocol == com_legacyprotocol->integer
#endif
)
{
Com_sprintf(name, sizeof(name), "demos/%s", arg);
FS_FOpenFileRead(name, &clc.demofile, qtrue);
@ -995,11 +1033,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);
@ -1013,6 +1051,13 @@ void CL_PlayDemo_f( void ) {
clc.demoplaying = qtrue;
Q_strncpyz( clc.servername, Cmd_Argv(1), sizeof( clc.servername ) );
#ifdef LEGACY_PROTOCOL
if(protocol <= com_legacyprotocol->integer)
clc.compat = qtrue;
else
clc.compat = qfalse;
#endif
// read demo messages until connected
while ( clc.state >= CA_CONNECTED && clc.state < CA_PRIMED ) {
CL_ReadDemoMessage();
@ -2180,7 +2225,9 @@ void CL_CheckForResend( void ) {
#endif
// 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;
@ -2190,7 +2237,16 @@ void CL_CheckForResend( void ) {
port = Cvar_VariableValue ("net_qport");
Q_strncpyz( info, Cvar_InfoString( CVAR_USERINFO ), sizeof( info ) );
Info_SetValueForKey( info, "protocol", va("%i", com_protocol->integer ) );
#ifdef LEGACY_PROTOCOL
if(com_legacyprotocol->integer == com_protocol->integer)
clc.compat = qtrue;
if(clc.compat)
Info_SetValueForKey(info, "protocol", va("%i", com_legacyprotocol->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 ) );
@ -2431,6 +2487,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
@ -2446,23 +2503,70 @@ 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 != com_protocol->integer)
{
Com_DPrintf("Challenge response received from unexpected source. Ignored.\n");
#ifdef LEGACY_PROTOCOL
if(com_legacyprotocol->integer > 0)
{
// Server is ioq3 but has a different protocol than we do.
// Fall back to idq3 protocol.
clc.compat = qtrue;
Com_Printf(S_COLOR_YELLOW "Warning: Server reports protocol version %d, "
"we have %d. Trying legacy protocol %d.\n",
ver, com_protocol->integer, com_legacyprotocol->integer);
}
else
#endif
{
Com_Printf(S_COLOR_YELLOW "Warning: Server reports protocol version %d, we have %d. "
"Trying anyways.\n", ver, com_protocol->integer);
}
}
}
#ifdef LEGACY_PROTOCOL
else
clc.compat = qtrue;
if(clc.compat)
{
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;
}
}
}
else
#endif
{
if(!*c || challenge != clc.challenge)
{
Com_Printf("Bad challenge for challengeResponse. Ignored.\n");
return;
}
}
@ -2494,7 +2598,36 @@ 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" ) );
#ifdef LEGACY_PROTOCOL
if(!clc.compat)
#endif
{
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;
}
}
#ifdef LEGACY_PROTOCOL
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, qfalse);
#endif
clc.state = CA_CONNECTED;
clc.lastPacketSentTime = -9999; // send first packet immediately
return;
@ -2512,13 +2645,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) );
@ -2538,10 +2664,12 @@ 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 ) );
Com_Printf( "%s", s );
return;
}
@ -3492,7 +3620,13 @@ void CL_ServerInfoPacket( netadr_t from, msg_t *msg ) {
// 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 LEGACY_PROTOCOL
&& prot != com_legacyprotocol->integer
#endif
)
{
Com_DPrintf( "Different protocol info packet: %s\n", infoString );
return;
}

View file

@ -147,9 +147,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
@ -161,7 +158,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;
}

View file

@ -263,6 +263,10 @@ typedef struct {
float voipPower;
#endif
#ifdef LEGACY_PROTOCOL
qboolean compat;
#endif
// big stuff at end of structure so most offsets are 15 bits or less
netchan_t netchan;
} clientConnection_t;

View file

@ -42,8 +42,8 @@ DEMOS MENU
#define ART_ARROWLEFT "menu/art/arrows_horz_left"
#define ART_ARROWRIGHT "menu/art/arrows_horz_right"
#define MAX_DEMOS 128
#define NAMEBUFSIZE ( MAX_DEMOS * 16 )
#define MAX_DEMOS 1024
#define NAMEBUFSIZE (MAX_DEMOS * 32)
#define ID_BACK 10
#define ID_GO 11
@ -72,6 +72,9 @@ typedef struct {
int numDemos;
char names[NAMEBUFSIZE];
int numLegacyDemos;
char namesLegacy[NAMEBUFSIZE];
char *demolist[MAX_DEMOS];
} demos_t;
@ -133,6 +136,7 @@ static void Demos_MenuInit( void ) {
int i;
int len;
char *demoname, extension[32];
int protocol, protocolLegacy;
memset( &s_demos, 0 ,sizeof(demos_t) );
s_demos.menu.key = UI_DemosMenu_Key;
@ -223,11 +227,34 @@ static void Demos_MenuInit( void ) {
s_demos.list.generic.y = 130;
s_demos.list.width = 16;
s_demos.list.height = 14;
Com_sprintf(extension, sizeof(extension), ".%s%d", DEMOEXT, (int) trap_Cvar_VariableValue("protocol"));
s_demos.list.numitems = trap_FS_GetFileList( "demos", extension, s_demos.names, NAMEBUFSIZE );
s_demos.list.itemnames = (const char **)s_demos.demolist;
s_demos.list.columns = 3;
protocolLegacy = trap_Cvar_VariableValue("com_legacyprotocol");
protocol = trap_Cvar_VariableValue("com_protocol");
if(!protocol)
protocol = trap_Cvar_VariableValue("protocol");
if(protocolLegacy == protocol)
protocolLegacy = 0;
Com_sprintf(extension, sizeof(extension), ".%s%d", DEMOEXT, protocol);
s_demos.numDemos = trap_FS_GetFileList("demos", extension, s_demos.names, NAMEBUFSIZE);
if(s_demos.numDemos > MAX_DEMOS)
s_demos.numDemos = MAX_DEMOS;
if(protocolLegacy > 0)
{
Com_sprintf(extension, sizeof(extension), ".%s%d", DEMOEXT, protocolLegacy);
s_demos.numLegacyDemos = trap_FS_GetFileList("demos", extension, s_demos.namesLegacy, NAMEBUFSIZE);
}
else
s_demos.numLegacyDemos = 0;
s_demos.list.numitems = s_demos.numDemos + s_demos.numLegacyDemos;
if (!s_demos.list.numitems) {
strcpy( s_demos.names, "No Demos Found." );
s_demos.list.numitems = 1;
@ -239,15 +266,21 @@ static void Demos_MenuInit( void ) {
s_demos.list.numitems = MAX_DEMOS;
demoname = s_demos.names;
for ( i = 0; i < s_demos.list.numitems; i++ ) {
for(i = 0; i < s_demos.numDemos; i++)
{
s_demos.list.itemnames[i] = demoname;
// strip extension
len = strlen( demoname );
if (!Q_stricmp(demoname + len - 4,".dm3"))
demoname[len-4] = '\0';
len = strlen(demoname);
// Q_strupr(demoname);
demoname += len + 1;
}
demoname = s_demos.namesLegacy;
for(; i < s_demos.list.numitems; i++)
{
s_demos.list.itemnames[i] = demoname;
len = strlen(demoname);
demoname += len + 1;
}

View file

@ -32,7 +32,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#endif
int demo_protocols[] =
{ 66, 67, 68, 0 };
{ 67, 66, 0 };
#define MAX_NUM_ARGVS 50
@ -87,6 +87,9 @@ cvar_t *com_maxfpsMinimized;
cvar_t *com_abnormalExit;
cvar_t *com_standalone;
cvar_t *com_protocol;
#ifdef LEGACY_PROTOCOL
cvar_t *com_legacyprotocol;
#endif
cvar_t *com_basegame;
cvar_t *com_homepath;
cvar_t *com_busyWait;
@ -2796,7 +2799,16 @@ void Com_Init( char *commandLine ) {
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);
com_protocol = Cvar_Get("com_protocol", va("%i", PROTOCOL_VERSION), CVAR_SERVERINFO | CVAR_INIT);
#ifdef LEGACY_PROTOCOL
com_legacyprotocol = Cvar_Get("com_legacyprotocol", va("%i", PROTOCOL_LEGACY_VERSION), CVAR_INIT);
// Keep for compatibility with old mods / mods that haven't updated yet.
if(com_legacyprotocol->integer > 0)
Cvar_Get("protocol", com_legacyprotocol->string, CVAR_ROM);
else
#endif
Cvar_Get("protocol", com_protocol->string, CVAR_ROM);
Sys_Init();

View file

@ -1056,6 +1056,11 @@ qboolean FS_IsDemoExt(const char *filename, int namelen)
if(protocol == com_protocol->integer)
return qtrue;
#ifdef LEGACY_PROTOCOL
if(protocol == com_legacyprotocol->integer)
return qtrue;
#endif
for(index = 0; demo_protocols[index]; index++)
{
if(demo_protocols[index] == protocol)

View file

@ -83,7 +83,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, qboolean compat)
{
Com_Memset (chan, 0, sizeof(*chan));
chan->sock = sock;
@ -91,6 +92,11 @@ 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;
#ifdef LEGACY_PROTOCOL
chan->compat = compat;
#endif
}
// TTimo: unused, commenting out to make gcc happy
@ -190,17 +196,24 @@ 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 );
}
#ifdef LEGACY_PROTOCOL
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,12 +281,17 @@ 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);
#ifdef LEGACY_PROTOCOL
if(!chan->compat)
#endif
MSG_WriteLong(&send, NETCHAN_GENCHECKSUM(chan->challenge, chan->outgoingSequence));
chan->outgoingSequence++;
MSG_WriteData( &send, data, length );
@ -327,6 +345,17 @@ qboolean Netchan_Process( netchan_t *chan, msg_t *msg ) {
qport = MSG_ReadShort( msg );
}
#ifdef LEGACY_PROTOCOL
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 );

View file

@ -37,6 +37,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#define HOMEPATH_NAME_UNIX ".foo"
#define HOMEPATH_NAME_WIN "FooBar"
#define HOMEPATH_NAME_MACOSX HOMEPATH_NAME_WIN
// #define LEGACY_PROTOCOL // You probably don't need this for your standalone game
#else
#define PRODUCT_NAME "ioq3"
#define BASEGAME "baseq3"
@ -48,6 +49,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#define HOMEPATH_NAME_UNIX ".q3a"
#define HOMEPATH_NAME_WIN "Quake3"
#define HOMEPATH_NAME_MACOSX HOMEPATH_NAME_WIN
#define LEGACY_PROTOCOL
#endif
#define BASETA "missionpack"

View file

@ -195,7 +195,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
@ -224,10 +225,16 @@ typedef struct {
int unsentFragmentStart;
int unsentLength;
byte unsentBuffer[MAX_MSGLEN];
int challenge;
#ifdef LEGACY_PROTOCOL
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, qboolean compat);
void Netchan_Transmit( netchan_t *chan, int length, const byte *data );
void Netchan_TransmitNextFragment( netchan_t *chan );
@ -243,7 +250,8 @@ PROTOCOL
==============================================================
*/
#define PROTOCOL_VERSION 68
#define PROTOCOL_VERSION 69
#define PROTOCOL_LEGACY_VERSION 68
// 1.31 - 67
// maintain a list of compatible protocols for demo playing
@ -863,6 +871,9 @@ extern cvar_t *cl_packetdelay;
extern cvar_t *sv_packetdelay;
extern cvar_t *com_protocol;
#ifdef LEGACY_PROTOCOL
extern cvar_t *com_legacyprotocol;
#endif
// com_speeds times
extern int time_game;

View file

@ -188,7 +188,11 @@ typedef struct client_s {
#endif
int oldServerTime;
qboolean csUpdated[MAX_CONFIGSTRINGS+1];
qboolean csUpdated[MAX_CONFIGSTRINGS+1];
#ifdef LEGACY_PROTOCOL
qboolean compat;
#endif
} client_t;
//=============================================================================

View file

@ -59,12 +59,25 @@ void SV_GetChallenge(netadr_t from)
int clientChallenge;
challenge_t *challenge;
qboolean wasfound = qfalse;
char *gameName;
// ignore if we are in single player
if ( Cvar_VariableValue( "g_gametype" ) == GT_SINGLE_PLAYER || Cvar_VariableValue("ui_singlePlayerActive")) {
return;
}
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;
@ -302,6 +315,9 @@ void SV_DirectConnect( netadr_t from ) {
intptr_t denied;
int count;
char *ip;
#ifdef LEGACY_PROTOCOL
qboolean compat = qfalse;
#endif
Com_DPrintf ("SVC_DirectConnect ()\n");
@ -314,11 +330,21 @@ void SV_DirectConnect( netadr_t from ) {
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 LEGACY_PROTOCOL
if(version > 0 && com_legacyprotocol->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" ) );
@ -500,7 +526,12 @@ gotnewcl:
newcl->challenge = challenge;
// save the address
Netchan_Setup (NS_SERVER, &newcl->netchan , from, qport);
#ifdef LEGACY_PROTOCOL
newcl->compat = compat;
Netchan_Setup(NS_SERVER, &newcl->netchan, from, qport, challenge, compat);
#else
Netchan_Setup(NS_SERVER, &newcl->netchan, from, qport, challenge, qfalse);
#endif
// init the netchan queue
newcl->netchan_end_queue = &newcl->netchan_start_queue;
@ -521,7 +552,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 );

View file

@ -643,7 +643,13 @@ void SVC_Info( netadr_t from ) {
// to prevent timed spoofed reply packets that add ghost servers
Info_SetValueForKey( infostring, "challenge", Cmd_Argv(1) );
Info_SetValueForKey( infostring, "protocol", va("%i", com_protocol->integer) );
#ifdef LEGACY_PROTOCOL
if(com_legacyprotocol->integer > 0)
Info_SetValueForKey(infostring, "protocol", va("%i", com_legacyprotocol->integer));
else
#endif
Info_SetValueForKey(infostring, "protocol", va("%i", com_protocol->integer));
Info_SetValueForKey( infostring, "hostname", sv_hostname->string );
Info_SetValueForKey( infostring, "mapname", sv_mapname->string );
Info_SetValueForKey( infostring, "clients", va("%i", count) );
@ -868,10 +874,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" );
}