From ba385fa43ce4a38a8e70f578bd87ddd37c26ad27 Mon Sep 17 00:00:00 2001 From: Thilo Schulz Date: Fri, 29 Jul 2011 13:46:50 +0000 Subject: [PATCH] - Switch master server protocol to dpmaster for better game separation. Based partly on patch by Zack Middleton - Get rid of ugly cvars sv_heartbeat and cl_gamename and replace with single com_gamename - Remove sv_flatline. Flatlines are ignored by dpmaster and are considered to be insecure because flatlines can be udp-spoofed. --- README | 28 ++++++++++------------------ code/client/cl_main.c | 25 ++++++++++++++++--------- code/qcommon/common.c | 2 ++ code/qcommon/q_shared.h | 11 +++++------ code/qcommon/qcommon.h | 1 + code/server/server.h | 2 -- code/server/sv_client.c | 4 ++-- code/server/sv_init.c | 2 -- code/server/sv_main.c | 11 +++++------ 9 files changed, 41 insertions(+), 45 deletions(-) diff --git a/README b/README index 63d467df..4ef1ff78 100644 --- a/README +++ b/README @@ -120,8 +120,6 @@ New cvars cl_mouseAccelStyle - Set to 1 for QuakeLive mouse acceleration behaviour, 0 for standard q3 cl_mouseAccelOffset - Tuning the acceleration curve, see below - cl_gamename - Gamename sent to master server in - getserversExt query in_joystickUseAnalog - Do not translate joystick axis events to keyboard commands @@ -197,6 +195,10 @@ New cvars through which other processes can control the server while it is running. Nonfunctional on Windows. + com_gamename - Gamename sent to master server in + getservers[Ext] query and infoResponse + "gamename" infostring value. Also used + for filtering local network games. com_protocol - Specify protocol version number for current ioquake3 protocol, see "Network protocols" section below @@ -210,9 +212,6 @@ New cvars holds custom pk3 files for your server sv_banFile - Name of the file that is used for storing the server bans - sv_heartbeat - Heartbeat string sent to master server - sv_flatline - Heartbeat string sent to master server - when server is killed net_ip6 - IPv6 address to bind to net_port6 - port to bind to using the ipv6 address @@ -527,25 +526,18 @@ Creating standalone games +set com_homepath - to the command line. You can also control which kind of messages to send to - the master server: + to the command line. You can also control which game name to use when talking + to the master server: - +set sv_heartbeat +set sv_flatline - +set cl_gamename + +set com_gamename - The and message can be specific to your game. The - flatline message is sent to signal the master server that the game server is - quitting. Vanilla quake3 uses "QuakeArena-1" both for the heartbeat and - flatline messages. - The cl_gamename message is for dpmaster to specify which game the client - wants a server list for. It is only used in the new ipv6 based getServersExt - query. + So clients requesting a server list will only receive servers that have a + matching game name. Example line: +set com_basegame basefoo +set com_homepath .foo - +set sv_heartbeat fooalive +set sv_flatline foodead - +set cl_gamename foo + +set com_gamename foo If you really changed parts that would make vanilla ioquake3 incompatible with diff --git a/code/client/cl_main.c b/code/client/cl_main.c index 7c986953..ac2239ed 100644 --- a/code/client/cl_main.c +++ b/code/client/cl_main.c @@ -109,8 +109,6 @@ cvar_t *cl_guidServerUniq; cvar_t *cl_consoleKeys; -cvar_t *cl_gamename; - clientActive_t cl; clientConnection_t clc; clientStatic_t cls; @@ -2306,9 +2304,9 @@ void CL_CheckForResend( void ) { #endif // The challenge request shall be followed by a client challenge so no malicious server can hijack this connection. - // Add the heartbeat gamename so the server knows we're running the correct game and can reject the client + // Add the gamename so the server knows we're running the correct game or can reject the client // with a meaningful message - Com_sprintf(data, sizeof(data), "getchallenge %d %s", clc.challenge, Cvar_VariableString("sv_heartbeat")); + Com_sprintf(data, sizeof(data), "getchallenge %d %s", clc.challenge, com_gamename->string); NET_OutOfBandPrint(NS_CLIENT, clc.serverAddress, "%s", data); break; @@ -3472,8 +3470,6 @@ void CL_Init( void ) { // ~ and `, as keys and characters cl_consoleKeys = Cvar_Get( "cl_consoleKeys", "~ ` 0x7e 0x60", CVAR_ARCHIVE); - cl_gamename = Cvar_Get("cl_gamename", GAMENAME_FOR_MASTER, CVAR_TEMP); - // userinfo Cvar_Get ("name", "UnnamedPlayer", CVAR_USERINFO | CVAR_ARCHIVE ); Cvar_Get ("rate", "25000", CVAR_USERINFO | CVAR_ARCHIVE ); @@ -3696,9 +3692,19 @@ void CL_ServerInfoPacket( netadr_t from, msg_t *msg ) { char info[MAX_INFO_STRING]; char *infoString; int prot; + char *gamename; infoString = MSG_ReadString( msg ); + // if this isn't the correct gamename, ignore it + gamename = Info_ValueForKey( infoString, "gamename" ); + + if (gamename && *gamename && strcmp(gamename, com_gamename->string)) + { + Com_DPrintf( "Game mismatch in info packet: %s\n", infoString ); + return; + } + // if this isn't the correct protocol version, ignore it prot = atoi( Info_ValueForKey( infoString, "protocol" ) ); @@ -4078,16 +4084,17 @@ void CL_GlobalServers_f( void ) { if(v4enabled) { Com_sprintf(command, sizeof(command), "getserversExt %s %s", - cl_gamename->string, Cmd_Argv(2)); + com_gamename->string, Cmd_Argv(2)); } else { Com_sprintf(command, sizeof(command), "getserversExt %s %s ipv6", - cl_gamename->string, Cmd_Argv(2)); + com_gamename->string, Cmd_Argv(2)); } } else - Com_sprintf(command, sizeof(command), "getservers %s", Cmd_Argv(2)); + Com_sprintf(command, sizeof(command), "getservers %s %s", + com_gamename->string, Cmd_Argv(2)); for (i=3; i < count; i++) { diff --git a/code/qcommon/common.c b/code/qcommon/common.c index 42896e0a..411c1ffe 100644 --- a/code/qcommon/common.c +++ b/code/qcommon/common.c @@ -85,6 +85,7 @@ cvar_t *com_minimized; cvar_t *com_maxfpsMinimized; cvar_t *com_abnormalExit; cvar_t *com_standalone; +cvar_t *com_gamename; cvar_t *com_protocol; #ifdef LEGACY_PROTOCOL cvar_t *com_legacyprotocol; @@ -2793,6 +2794,7 @@ 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_gamename = Cvar_Get("com_gamename", GAMENAME_FOR_MASTER, 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); diff --git a/code/qcommon/q_shared.h b/code/qcommon/q_shared.h index a8968643..07b92455 100644 --- a/code/qcommon/q_shared.h +++ b/code/qcommon/q_shared.h @@ -31,27 +31,26 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #define BASEGAME "foobar" #define CLIENT_WINDOW_TITLE "changeme" #define CLIENT_WINDOW_MIN_TITLE "changeme2" - #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 HOMEPATH_NAME_UNIX ".foo" #define HOMEPATH_NAME_WIN "FooBar" #define HOMEPATH_NAME_MACOSX HOMEPATH_NAME_WIN + #define GAMENAME_FOR_MASTER "foobar" // must NOT contain whitespace // #define LEGACY_PROTOCOL // You probably don't need this for your standalone game #else #define PRODUCT_NAME "ioq3" #define BASEGAME "baseq3" #define CLIENT_WINDOW_TITLE "ioquake3" #define CLIENT_WINDOW_MIN_TITLE "ioq3" - #define GAMENAME_FOR_MASTER "Quake3Arena" - #define HEARTBEAT_FOR_MASTER "QuakeArena-1" - #define FLATLINE_FOR_MASTER HEARTBEAT_FOR_MASTER #define HOMEPATH_NAME_UNIX ".q3a" #define HOMEPATH_NAME_WIN "Quake3" #define HOMEPATH_NAME_MACOSX HOMEPATH_NAME_WIN + #define GAMENAME_FOR_MASTER "Quake3Arena" #define LEGACY_PROTOCOL #endif +// Heartbeat for dpmaster protocol. You shouldn't change this unless you know what you're doing +#define HEARTBEAT_FOR_MASTER "DarkPlaces" + #define BASETA "missionpack" #ifndef PRODUCT_VERSION diff --git a/code/qcommon/qcommon.h b/code/qcommon/qcommon.h index 841418a8..e08a0c81 100644 --- a/code/qcommon/qcommon.h +++ b/code/qcommon/qcommon.h @@ -870,6 +870,7 @@ extern cvar_t *sv_paused; extern cvar_t *cl_packetdelay; extern cvar_t *sv_packetdelay; +extern cvar_t *com_gamename; extern cvar_t *com_protocol; #ifdef LEGACY_PROTOCOL extern cvar_t *com_legacyprotocol; diff --git a/code/server/server.h b/code/server/server.h index 4d08aef9..be749167 100644 --- a/code/server/server.h +++ b/code/server/server.h @@ -294,8 +294,6 @@ extern cvar_t *sv_lanForceRate; extern cvar_t *sv_strictAuth; #endif extern cvar_t *sv_banFile; -extern cvar_t *sv_heartbeat; -extern cvar_t *sv_flatline; extern serverBan_t serverBans[SERVER_MAXBANS]; extern int serverBansCount; diff --git a/code/server/sv_client.c b/code/server/sv_client.c index 06be68e4..a7ba1101 100644 --- a/code/server/sv_client.c +++ b/code/server/sv_client.c @@ -70,10 +70,10 @@ void SV_GetChallenge(netadr_t from) if(gameName && *gameName) { // reject client if the heartbeat string sent by the client doesn't match ours - if(strcmp(gameName, sv_heartbeat->string)) + if(strcmp(gameName, com_gamename->string)) { NET_OutOfBandPrint(NS_SERVER, from, "print\nGame mismatch: This is a %s server\n", - sv_heartbeat->string); + com_gamename->string); return; } } diff --git a/code/server/sv_init.c b/code/server/sv_init.c index 1ad51009..4f287938 100644 --- a/code/server/sv_init.c +++ b/code/server/sv_init.c @@ -686,8 +686,6 @@ void SV_Init (void) sv_strictAuth = Cvar_Get ("sv_strictAuth", "1", CVAR_ARCHIVE ); #endif sv_banFile = Cvar_Get("sv_banFile", "serverbans.dat", CVAR_ARCHIVE); - sv_heartbeat = Cvar_Get("sv_heartbeat", HEARTBEAT_FOR_MASTER, CVAR_INIT); - sv_flatline = Cvar_Get("sv_flatline", FLATLINE_FOR_MASTER, CVAR_INIT); // initialize bot cvars so they are listed and can be set before loading the botlib SV_BotInitCvars(); diff --git a/code/server/sv_main.c b/code/server/sv_main.c index 614270c7..d7b88ed4 100644 --- a/code/server/sv_main.c +++ b/code/server/sv_main.c @@ -61,9 +61,6 @@ cvar_t *sv_lanForceRate; // dedicated 1 (LAN) server forces local client rates t cvar_t *sv_strictAuth; #endif cvar_t *sv_banFile; -cvar_t *sv_heartbeat; // Heartbeat string that is sent to the master -cvar_t *sv_flatline; // If the master server supports it we can send a flatline - // when server is killed serverBan_t serverBans[SERVER_MAXBANS]; int serverBansCount = 0; @@ -338,11 +335,11 @@ Informs all masters that this server is going down void SV_MasterShutdown( void ) { // send a hearbeat right now svs.nextHeartbeatTime = -9999; - SV_MasterHeartbeat(sv_flatline->string); + SV_MasterHeartbeat(HEARTBEAT_FOR_MASTER); // send it again to minimize chance of drops svs.nextHeartbeatTime = -9999; - SV_MasterHeartbeat(sv_flatline->string); + SV_MasterHeartbeat(HEARTBEAT_FOR_MASTER); // when the master tries to poll the server, it won't respond, so // it will be removed from the list @@ -644,6 +641,8 @@ 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, "gamename", com_gamename->string ); + #ifdef LEGACY_PROTOCOL if(com_legacyprotocol->integer > 0) Info_SetValueForKey(infostring, "protocol", va("%i", com_legacyprotocol->integer)); @@ -1154,7 +1153,7 @@ void SV_Frame( int msec ) { SV_SendClientMessages(); // send a heartbeat to the master if needed - SV_MasterHeartbeat(sv_heartbeat->string); + SV_MasterHeartbeat(HEARTBEAT_FOR_MASTER); } /*