From 6d2ffb4c637a49983bc6ce22b68ccec0ed09e0f4 Mon Sep 17 00:00:00 2001 From: Tim Angus Date: Sat, 3 Oct 2009 15:17:16 +0000 Subject: * Merge ioq3-r1637 --- src/server/server.h | 3 +- src/server/sv_client.c | 33 ++++++++++----- src/server/sv_game.c | 3 -- src/server/sv_init.c | 15 +++---- src/server/sv_main.c | 107 ++++++++++++++++++++++++++++++++--------------- src/server/sv_net_chan.c | 60 +++++++++++++------------- src/server/sv_snapshot.c | 3 -- src/server/sv_world.c | 6 +-- 8 files changed, 137 insertions(+), 93 deletions(-) (limited to 'src/server') diff --git a/src/server/server.h b/src/server/server.h index eb3766e8..fe78026c 100644 --- a/src/server/server.h +++ b/src/server/server.h @@ -205,6 +205,7 @@ typedef struct client_s { typedef struct { netadr_t adr; int challenge; + int clientChallenge; // challenge number coming from the client int time; // time the last packet was sent to the autherize server int pingTime; // time the challenge response was sent to client int firstTime; // time the adr was first used, for authorize timeout checks @@ -313,7 +314,7 @@ void SV_SpawnServer( char *server, qboolean killBots ); // // sv_client.c // -void SV_GetChallenge( netadr_t from ); +void SV_GetChallenge(netadr_t from); void SV_DirectConnect( netadr_t from ); diff --git a/src/server/sv_client.c b/src/server/sv_client.c index 4b7b3bb6..4449f1c8 100644 --- a/src/server/sv_client.c +++ b/src/server/sv_client.c @@ -42,12 +42,21 @@ to be sent to the authorize server. When an authorizeip is returned, a challenge response will be sent to that ip. + +ioquake3: we added a possibility for clients to add a challenge +to their packets, to make it more difficult for malicious servers +to hi-jack client connections. +Also, the auth stuff is completely disabled for com_standalone games +as well as IPv6 connections, since there is no way to use the +v4-only auth server for these new types of connections. ================= */ -void SV_GetChallenge( netadr_t from ) { +void SV_GetChallenge(netadr_t from) +{ int i; int oldest; int oldestTime; + const char *clientChallenge = Cmd_Argv(1); challenge_t *challenge; oldest = 0; @@ -65,21 +74,24 @@ void SV_GetChallenge( netadr_t from ) { } } - if (i == MAX_CHALLENGES) { + if (i == MAX_CHALLENGES) + { // this is the first time this client has asked for a challenge challenge = &svs.challenges[oldest]; - challenge->challenge = ( (rand() << 16) ^ rand() ) ^ svs.time; + challenge->clientChallenge = 0; challenge->adr = from; challenge->firstTime = svs.time; challenge->time = svs.time; challenge->connected = qfalse; - i = oldest; } // send the challengeResponse challenge->pingTime = svs.time; NET_OutOfBandPrint( NS_SERVER, from, "challengeResponse %i", challenge->challenge ); + + challenge->pingTime = svs.time; + NET_OutOfBandPrint( NS_SERVER, challenge->adr, "challengeResponse %i %s", challenge->challenge, clientChallenge); } /* @@ -339,7 +351,7 @@ void SV_DropClient( client_t *drop, const char *reason ) { for (i = 0 ; i < MAX_CHALLENGES ; i++, challenge++) { if ( NET_CompareAdr( drop->netchan.remoteAddress, challenge->adr ) ) { - challenge->connected = qfalse; + Com_Memset(challenge, 0, sizeof(*challenge)); break; } } @@ -350,7 +362,6 @@ void SV_DropClient( client_t *drop, const char *reason ) { // tell everyone why they got dropped SV_SendServerCommand( NULL, "print \"%s" S_COLOR_WHITE " %s\n\"", drop->name, reason ); - if (drop->download) { FS_FCloseFile( drop->download ); drop->download = 0; @@ -394,7 +405,7 @@ It will be resent if the client acknowledges a later message but has the wrong gamestate. ================ */ -void SV_SendClientGameState( client_t *client ) { +static void SV_SendClientGameState( client_t *client ) { int start; entityState_t *base, nullstate; msg_t msg; @@ -531,7 +542,7 @@ SV_StopDownload_f Abort a download if in progress ================== */ -void SV_StopDownload_f( client_t *cl ) { +static void SV_StopDownload_f( client_t *cl ) { if (*cl->downloadName) Com_DPrintf( "clientDownload: %d : file \"%s\" aborted\n", (int) (cl - svs.clients), cl->downloadName ); @@ -545,7 +556,7 @@ SV_DoneDownload_f Downloads are finished ================== */ -void SV_DoneDownload_f( client_t *cl ) { +static void SV_DoneDownload_f( client_t *cl ) { Com_DPrintf( "clientDownload: %s Done\n", cl->name); // resend the game state to update any clients that entered during the download SV_SendClientGameState(cl); @@ -559,7 +570,7 @@ The argument will be the last acknowledged block from the client, it should be the same as cl->downloadClientBlock ================== */ -void SV_NextDownload_f( client_t *cl ) +static void SV_NextDownload_f( client_t *cl ) { int block = atoi( Cmd_Argv(1) ); @@ -588,7 +599,7 @@ void SV_NextDownload_f( client_t *cl ) SV_BeginDownload_f ================== */ -void SV_BeginDownload_f( client_t *cl ) { +static void SV_BeginDownload_f( client_t *cl ) { // Kill any existing download SV_CloseDownload( cl ); diff --git a/src/server/sv_game.c b/src/server/sv_game.c index d375c095..1efa6d5f 100644 --- a/src/server/sv_game.c +++ b/src/server/sv_game.c @@ -182,17 +182,14 @@ qboolean SV_inPVSIgnorePortals( const vec3_t p1, const vec3_t p2) { int leafnum; int cluster; - int area1, area2; byte *mask; leafnum = CM_PointLeafnum (p1); cluster = CM_LeafCluster (leafnum); - area1 = CM_LeafArea (leafnum); mask = CM_ClusterPVS (cluster); leafnum = CM_PointLeafnum (p2); cluster = CM_LeafCluster (leafnum); - area2 = CM_LeafArea (leafnum); if ( mask && (!(mask[cluster>>3] & (1<<(cluster&7)) ) ) ) return qfalse; diff --git a/src/server/sv_init.c b/src/server/sv_init.c index 43eb2c09..34ced5c5 100644 --- a/src/server/sv_init.c +++ b/src/server/sv_init.c @@ -105,7 +105,7 @@ SV_SetConfigstring =============== */ void SV_SetConfigstring (int index, const char *val) { - int len, i; + int i; client_t *client; if ( index < 0 || index >= MAX_CONFIGSTRINGS ) { @@ -141,8 +141,6 @@ void SV_SetConfigstring (int index, const char *val) { continue; } - - len = strlen( val ); SV_SendConfigstring(client, index); } } @@ -217,7 +215,7 @@ to the clients -- only the fields that differ from the baseline will be transmitted ================ */ -void SV_CreateBaseline( void ) { +static void SV_CreateBaseline( void ) { sharedEntity_t *svent; int entnum; @@ -242,7 +240,7 @@ SV_BoundMaxClients =============== */ -void SV_BoundMaxClients( int minimum ) { +static void SV_BoundMaxClients( int minimum ) { // get the current maxclients value Cvar_Get( "sv_maxclients", "8", 0 ); @@ -266,7 +264,7 @@ NOT cause this to be called, unless the game is exited to the menu system first. =============== */ -void SV_Startup( void ) { +static void SV_Startup( void ) { if ( svs.initialized ) { Com_Error( ERR_FATAL, "SV_Startup: svs.initialized" ); } @@ -364,7 +362,7 @@ void SV_ChangeMaxClients( void ) { SV_ClearServer ================ */ -void SV_ClearServer(void) { +static void SV_ClearServer(void) { int i; for ( i = 0 ; i < MAX_CONFIGSTRINGS ; i++ ) { @@ -382,7 +380,7 @@ SV_TouchCGame touch the cgame.vm so that a pure client can load it if it's in a seperate pk3 ================ */ -void SV_TouchCGame(void) { +static void SV_TouchCGame(void) { fileHandle_t f; char filename[MAX_QPATH]; @@ -470,7 +468,6 @@ void SV_SpawnServer( char *server, qboolean killBots ) { Cvar_Set("cl_paused", "0"); // get a new checksum feed and restart the file system - srand(Com_Milliseconds()); sv.checksumFeed = ( ((int) rand() << 16) ^ rand() ) ^ Com_Milliseconds(); FS_Restart( sv.checksumFeed ); diff --git a/src/server/sv_main.c b/src/server/sv_main.c index 305cf299..41bfec4a 100644 --- a/src/server/sv_main.c +++ b/src/server/sv_main.c @@ -74,7 +74,7 @@ SV_ExpandNewlines Converts newlines to "\n" so a line prints nicer =============== */ -char *SV_ExpandNewlines( char *in ) { +static char *SV_ExpandNewlines( char *in ) { static char string[1024]; int l; @@ -97,10 +97,11 @@ char *SV_ExpandNewlines( char *in ) { ====================== SV_ReplacePendingServerCommands - This is ugly +FIXME: This is ugly ====================== */ -int SV_ReplacePendingServerCommands( client_t *client, const char *cmd ) { +#if 0 // unused +static int SV_ReplacePendingServerCommands( client_t *client, const char *cmd ) { int i, index, csnum1, csnum2; for ( i = client->reliableSent+1; i <= client->reliableSequence; i++ ) { @@ -117,6 +118,7 @@ int SV_ReplacePendingServerCommands( client_t *client, const char *cmd ) { } return qfalse; } +#endif /* ====================== @@ -223,52 +225,89 @@ but not on every player enter or exit. #define HEARTBEAT_MSEC 300*1000 #define HEARTBEAT_GAME "Tremulous" void SV_MasterHeartbeat( void ) { - static netadr_t adr[MAX_MASTER_SERVERS]; + static netadr_t adr[MAX_MASTER_SERVERS][2]; // [2] for v4 and v6 address for the same address string. int i; int res; + int netenabled; + + netenabled = Cvar_VariableIntegerValue("net_enabled"); // "dedicated 1" is for lan play, "dedicated 2" is for inet public play - if ( !com_dedicated || com_dedicated->integer != 2 ) { + if (!com_dedicated || com_dedicated->integer != 2 || !(netenabled & (NET_ENABLEV4 | NET_ENABLEV6))) return; // only dedicated servers send heartbeats - } // if not time yet, don't send anything - if ( svs.time < svs.nextHeartbeatTime ) { + if ( svs.time < svs.nextHeartbeatTime ) return; - } - svs.nextHeartbeatTime = svs.time + HEARTBEAT_MSEC; + svs.nextHeartbeatTime = svs.time + HEARTBEAT_MSEC; // send to group masters - for ( i = 0 ; i < MAX_MASTER_SERVERS ; i++ ) { - if ( !sv_master[i]->string[0] ) { + for (i = 0; i < MAX_MASTER_SERVERS; i++) + { + if(!sv_master[i]->string[0]) continue; - } // see if we haven't already resolved the name // resolving usually causes hitches on win95, so only // do it when needed - if ( sv_master[i]->modified ) { + if(sv_master[i]->modified || (adr[i][0].type == NA_BAD && adr[i][1].type == NA_BAD)) + { sv_master[i]->modified = qfalse; - - Com_Printf( "Resolving %s\n", sv_master[i]->string ); - res = NET_StringToAdr( sv_master[i]->string, &adr[i], NA_UNSPEC ); - if ( !res ) { - Com_Printf( "Couldn't resolve address: %s\n", sv_master[i]->string ); - continue; + + if(netenabled & NET_ENABLEV4) + { + Com_Printf("Resolving %s (IPv4)\n", sv_master[i]->string); + res = NET_StringToAdr(sv_master[i]->string, &adr[i][0], NA_IP); + + if(res == 2) + { + // if no port was specified, use the default master port + adr[i][0].port = BigShort(PORT_MASTER); + } + + if(res) + Com_Printf( "%s resolved to %s\n", sv_master[i]->string, NET_AdrToStringwPort(adr[i][0])); + else + Com_Printf( "%s has no IPv4 address.\n", sv_master[i]->string); } - if ( res == 2 ) { - // if no port was specified, use the default master port - adr[i].port = BigShort( PORT_MASTER ); + + if(netenabled & NET_ENABLEV6) + { + Com_Printf("Resolving %s (IPv6)\n", sv_master[i]->string); + res = NET_StringToAdr(sv_master[i]->string, &adr[i][1], NA_IP6); + + if(res == 2) + { + // if no port was specified, use the default master port + adr[i][1].port = BigShort(PORT_MASTER); + } + + if(res) + Com_Printf( "%s resolved to %s\n", sv_master[i]->string, NET_AdrToStringwPort(adr[i][1])); + else + Com_Printf( "%s has no IPv6 address.\n", sv_master[i]->string); + } + + if(adr[i][0].type == NA_BAD && adr[i][1].type == NA_BAD) + { + Com_Printf("Couldn't resolve address: %s\n", sv_master[i]->string); + Cvar_Set(sv_master[i]->name, ""); + sv_master[i]->modified = qfalse; + continue; } - Com_Printf( "%s resolved to %s\n", sv_master[i]->string, NET_AdrToStringwPort(adr[i])); } Com_Printf ("Sending heartbeat to %s\n", sv_master[i]->string ); + // this command should be changed if the server info / status format // ever incompatably changes - NET_OutOfBandPrint( NS_SERVER, adr[i], "heartbeat %s\n", HEARTBEAT_GAME ); + + if(adr[i][0].type != NA_BAD) + NET_OutOfBandPrint( NS_SERVER, adr[i][0], "heartbeat %s\n", HEARTBEAT_GAME ); + if(adr[i][1].type != NA_BAD) + NET_OutOfBandPrint( NS_SERVER, adr[i][1], "heartbeat %s\n", HEARTBEAT_GAME ); } } @@ -342,7 +381,7 @@ and all connected players. Used for getting detailed information after the simple info query. ================ */ -void SVC_Status( netadr_t from ) { +static void SVC_Status( netadr_t from ) { char player[1024]; char status[MAX_MSGLEN]; int i; @@ -449,7 +488,7 @@ SVC_FlushRedirect ================ */ -void SV_FlushRedirect( char *outputbuf ) { +static void SV_FlushRedirect( char *outputbuf ) { NET_OutOfBandPrint( NS_SERVER, svs.redirectAddress, "print\n%s", outputbuf ); } @@ -462,7 +501,7 @@ Shift down the remaining args Redirect all printfs =============== */ -void SVC_RemoteCommand( netadr_t from, msg_t *msg ) { +static void SVC_RemoteCommand( netadr_t from, msg_t *msg ) { qboolean valid; unsigned int time; char remaining[1024]; @@ -483,10 +522,10 @@ void SVC_RemoteCommand( netadr_t from, msg_t *msg ) { if ( !strlen( sv_rconPassword->string ) || strcmp (Cmd_Argv(1), sv_rconPassword->string) ) { valid = qfalse; - Com_Printf ("Bad rcon from %s:\n%s\n", NET_AdrToString (from), Cmd_Argv(2) ); + Com_Printf ("Bad rcon from %s: %s\n", NET_AdrToString (from), Cmd_ArgsFrom(2) ); } else { valid = qtrue; - Com_Printf ("Rcon from %s:\n%s\n", NET_AdrToString (from), Cmd_Argv(2) ); + Com_Printf ("Rcon from %s: %s\n", NET_AdrToString (from), Cmd_ArgsFrom(2) ); } // start redirecting all print outputs to the packet @@ -532,7 +571,7 @@ Clients that are in the game can still send connectionless packets. ================= */ -void SV_ConnectionlessPacket( netadr_t from, msg_t *msg ) { +static void SV_ConnectionlessPacket( netadr_t from, msg_t *msg ) { char *s; char *c; @@ -554,7 +593,7 @@ void SV_ConnectionlessPacket( netadr_t from, msg_t *msg ) { } else if (!Q_stricmp(c, "getinfo")) { SVC_Info( from ); } else if (!Q_stricmp(c, "getchallenge")) { - SV_GetChallenge( from ); + SV_GetChallenge(from); } else if (!Q_stricmp(c, "connect")) { SV_DirectConnect( from ); } else if (!Q_stricmp(c, "rcon")) { @@ -641,7 +680,7 @@ SV_CalcPings Updates the cl->ping variables =================== */ -void SV_CalcPings( void ) { +static void SV_CalcPings( void ) { int i, j; client_t *cl; int total, count; @@ -697,7 +736,7 @@ for a few seconds to make sure any final reliable message gets resent if necessary ================== */ -void SV_CheckTimeouts( void ) { +static void SV_CheckTimeouts( void ) { int i; client_t *cl; int droppoint; @@ -738,7 +777,7 @@ void SV_CheckTimeouts( void ) { SV_CheckPaused ================== */ -qboolean SV_CheckPaused( void ) { +static qboolean SV_CheckPaused( void ) { int count; client_t *cl; int i; diff --git a/src/server/sv_net_chan.c b/src/server/sv_net_chan.c index 0de49d4f..dd2bb204 100644 --- a/src/server/sv_net_chan.c +++ b/src/server/sv_net_chan.c @@ -35,28 +35,29 @@ SV_Netchan_Encode ============== */ static void SV_Netchan_Encode( client_t *client, msg_t *msg ) { - long reliableAcknowledge, i, index; + long i, index; byte key, *string; - int srdc, sbit, soob; - + int srdc, sbit; + qboolean soob; + if ( msg->cursize < SV_ENCODE_START ) { return; } - srdc = msg->readcount; - sbit = msg->bit; - soob = msg->oob; - - msg->bit = 0; - msg->readcount = 0; - msg->oob = 0; - - reliableAcknowledge = MSG_ReadLong(msg); + srdc = msg->readcount; + sbit = msg->bit; + soob = msg->oob; + + msg->bit = 0; + msg->readcount = 0; + msg->oob = qfalse; + + /* reliableAcknowledge = */ MSG_ReadLong(msg); + + msg->oob = soob; + msg->bit = sbit; + msg->readcount = srdc; - msg->oob = soob; - msg->bit = sbit; - msg->readcount = srdc; - string = (byte *)client->lastClientCommandString; index = 0; // xor the client challenge with the netchan sequence number @@ -90,23 +91,24 @@ SV_Netchan_Decode */ static void SV_Netchan_Decode( client_t *client, msg_t *msg ) { int serverId, messageAcknowledge, reliableAcknowledge; - int i, index, srdc, sbit, soob; + int i, index, srdc, sbit; + qboolean soob; byte key, *string; - srdc = msg->readcount; - sbit = msg->bit; - soob = msg->oob; - - msg->oob = 0; - - serverId = MSG_ReadLong(msg); + srdc = msg->readcount; + sbit = msg->bit; + soob = msg->oob; + + msg->oob = qfalse; + + serverId = MSG_ReadLong(msg); messageAcknowledge = MSG_ReadLong(msg); reliableAcknowledge = MSG_ReadLong(msg); - msg->oob = soob; - msg->bit = sbit; - msg->readcount = srdc; - + msg->oob = soob; + msg->bit = sbit; + msg->readcount = srdc; + string = (byte *)client->reliableCommands[ reliableAcknowledge & (MAX_RELIABLE_COMMANDS-1) ]; index = 0; // @@ -137,7 +139,7 @@ void SV_Netchan_TransmitNextFragment( client_t *client ) { if (!client->netchan.unsentFragments) { // make sure the netchan queue has been properly initialized (you never know) - if (!client->netchan_end_queue) { + if ((!client->netchan_end_queue) && (client->state >= CS_CONNECTED)) { Com_Error(ERR_DROP, "netchan queue is not properly initialized in SV_Netchan_TransmitNextFragment\n"); } // the last fragment was transmitted, check wether we have queued messages diff --git a/src/server/sv_snapshot.c b/src/server/sv_snapshot.c index 037b772d..d813aad4 100644 --- a/src/server/sv_snapshot.c +++ b/src/server/sv_snapshot.c @@ -299,7 +299,6 @@ static void SV_AddEntitiesVisibleFromPoint( vec3_t origin, clientSnapshot_t *fra int l; int clientarea, clientcluster; int leafnum; - int c_fullsend; byte *clientpvs; byte *bitvector; @@ -319,8 +318,6 @@ static void SV_AddEntitiesVisibleFromPoint( vec3_t origin, clientSnapshot_t *fra clientpvs = CM_ClusterPVS (clientcluster); - c_fullsend = 0; - for ( e = 0 ; e < sv.num_entities ; e++ ) { ent = SV_GentityNum(e); diff --git a/src/server/sv_world.c b/src/server/sv_world.c index d40cc217..508ff0cc 100644 --- a/src/server/sv_world.c +++ b/src/server/sv_world.c @@ -104,7 +104,7 @@ SV_CreateworldSector Builds a uniformly subdivided tree for the given world size =============== */ -worldSector_t *SV_CreateworldSector( int depth, vec3_t mins, vec3_t maxs ) { +static worldSector_t *SV_CreateworldSector( int depth, vec3_t mins, vec3_t maxs ) { worldSector_t *anode; vec3_t size; vec3_t mins1, maxs1, mins2, maxs2; @@ -380,7 +380,7 @@ SV_AreaEntities_r ==================== */ -void SV_AreaEntities_r( worldSector_t *node, areaParms_t *ap ) { +static void SV_AreaEntities_r( worldSector_t *node, areaParms_t *ap ) { svEntity_t *check, *next; sharedEntity_t *gcheck; int count; @@ -508,7 +508,7 @@ SV_ClipMoveToEntities ==================== */ -void SV_ClipMoveToEntities( moveclip_t *clip ) { +static void SV_ClipMoveToEntities( moveclip_t *clip ) { int i, num; int touchlist[MAX_GENTITIES]; sharedEntity_t *touch; -- cgit