From 9662ab106f45431ddb375e32f76330c1b72bc03a Mon Sep 17 00:00:00 2001 From: Alibek Omarov Date: Sat, 13 Jul 2019 20:54:16 +0300 Subject: [PATCH] engine: client: implement errormsg, secure client by checking server IP address we're connected to --- engine/client/cl_demo.c | 1 + engine/client/cl_gameui.c | 62 ++++++++++++++++++++- engine/client/cl_main.c | 112 +++++++++++++++++++++++++++----------- engine/client/client.h | 7 ++- engine/common/common.h | 2 +- engine/common/dedicated.c | 2 +- engine/common/net_chan.c | 2 +- 7 files changed, 150 insertions(+), 38 deletions(-) diff --git a/engine/client/cl_demo.c b/engine/client/cl_demo.c index 5075b3cd..86329283 100644 --- a/engine/client/cl_demo.c +++ b/engine/client/cl_demo.c @@ -1154,6 +1154,7 @@ void CL_StopPlayback( void ) // let game known about demo state Cvar_FullSet( "cl_background", "0", FCVAR_READ_ONLY ); cls.state = ca_disconnected; + memset( &cls.serveradr, 0, sizeof( cls.serveradr ) ); cls.set_lastdemo = false; S_StopBackgroundTrack(); cls.connect_time = 0; diff --git a/engine/client/cl_gameui.c b/engine/client/cl_gameui.c index d4553c47..7f43e6b3 100644 --- a/engine/client/cl_gameui.c +++ b/engine/client/cl_gameui.c @@ -503,6 +503,13 @@ void UI_AddTouchButtonToList( const char *name, const char *texture, const char } } +/* +================= +UI_ResetPing + +notify gameui dll about latency reset +================= +*/ void UI_ResetPing( void ) { if( gameui.dllFuncs2.pfnResetPing ) @@ -511,11 +518,62 @@ void UI_ResetPing( void ) } } +/* +================= +UI_ShowConnectionWarning + +show connection warning dialog implemented by gameui dll +================= +*/ void UI_ShowConnectionWarning( void ) { - if( gameui.dllFuncs2.pfnShowConnectionWarning ) + if( cls.state != ca_connected ) + return; + + if( Host_IsLocalClient() ) + return; + + if( ++cl.lostpackets == 8 ) + { + CL_Disconnect(); + if( gameui.dllFuncs2.pfnShowConnectionWarning ) + { + gameui.dllFuncs2.pfnShowConnectionWarning(); + } + Con_DPrintf( S_WARN "Too many lost packets! Showing Network options menu\n" ); + } +} + + +/* +================= +UI_ShowConnectionWarning + +show update dialog +================= +*/ +void UI_ShowUpdateDialog( qboolean preferStore ) +{ + if( gameui.dllFuncs2.pfnShowUpdateDialog ) + { + gameui.dllFuncs2.pfnShowUpdateDialog( preferStore ); + } + + Con_Printf( S_WARN "This version is not supported anymore. To continue, install latest engine version\n" ); +} + +/* +================= +UI_ShowConnectionWarning + +show message box +================= +*/ +void UI_ShowMessageBox( const char *text ) +{ + if( gameui.dllFuncs2.pfnShowMessageBox ) { - gameui.dllFuncs2.pfnShowConnectionWarning(); + gameui.dllFuncs2.pfnShowMessageBox( text ); } } diff --git a/engine/client/cl_main.c b/engine/client/cl_main.c index cba25a0f..ded4c732 100644 --- a/engine/client/cl_main.c +++ b/engine/client/cl_main.c @@ -1098,6 +1098,8 @@ void CL_CheckForResend( void ) cls.signon = 0; cls.state = ca_connecting; Q_strncpy( cls.servername, "localhost", sizeof( cls.servername )); + cls.serveradr.type = NA_LOOPBACK; + // we don't need a challenge on the localhost CL_SendConnectPacket(); return; @@ -1150,6 +1152,7 @@ void CL_CheckForResend( void ) return; } + cls.serveradr = adr; cls.max_fragment_size = Q_max( FRAGMENT_MAX_SIZE, cls.max_fragment_size >> Q_min( 1, cls.connect_retry )); cls.connect_time = host.realtime; // for retransmit requests cls.connect_retry++; @@ -1501,6 +1504,7 @@ void CL_Disconnect( void ) IN_LockInputDevices( false ); // unlock input devices cls.state = ca_disconnected; + memset( &cls.serveradr, 0, sizeof( cls.serveradr ) ); cls.set_lastdemo = false; cls.connect_retry = 0; cls.signon = 0; @@ -1858,6 +1862,19 @@ void CL_SetupOverviewParams( void ) } } +/* +================= +CL_IsFromConnectingServer + +Used for connectionless packets, when netchan may not be ready. +================= +*/ +static qboolean CL_IsFromConnectingServer( netadr_t from ) +{ + return NET_IsLocalAddress( from ) || + NET_CompareAdr( cls.serveradr, from ); +} + /* ================= CL_ConnectionlessPacket @@ -1887,6 +1904,9 @@ void CL_ConnectionlessPacket( netadr_t from, sizebuf_t *msg ) // server connection if( !Q_strcmp( c, "client_connect" )) { + if( !CL_IsFromConnectingServer( from )) + return; + if( cls.state == ca_connected ) { Con_DPrintf( S_ERROR "dup connect received. ignored\n"); @@ -1927,21 +1947,19 @@ void CL_ConnectionlessPacket( netadr_t from, sizebuf_t *msg ) // print command from somewhere Con_Printf( "%s", MSG_ReadString( msg )); } - else if( !Q_strcmp( c, "errormsg" )) - { - args = MSG_ReadString( msg ); - if( !Q_strcmp( args, "Server uses protocol version 48.\n" )) - { - cls.legacyserver = from; - } - } else if( !Q_strcmp( c, "testpacket" )) { byte recv_buf[NET_MAX_FRAGMENT]; - dword crcValue = MSG_ReadLong( msg ); - int realsize = MSG_GetMaxBytes( msg ) - MSG_GetNumBytesRead( msg ); + dword crcValue; + int realsize; dword crcValue2 = 0; + if( !CL_IsFromConnectingServer( from )) + return; + + crcValue = MSG_ReadLong( msg ); + realsize = MSG_GetMaxBytes( msg ) - MSG_GetNumBytesRead( msg ); + if( cls.max_fragment_size != MSG_GetMaxBytes( msg )) { if( cls.connect_retry >= CL_TEST_RETRIES ) @@ -1999,6 +2017,9 @@ void CL_ConnectionlessPacket( netadr_t from, sizebuf_t *msg ) } else if( !Q_strcmp( c, "challenge" )) { + if( !CL_IsFromConnectingServer( from )) + return; + // challenge from the server we are connecting to cls.challenge = Q_atoi( Cmd_Argv( 1 )); CL_SendConnectPacket(); @@ -2006,11 +2027,17 @@ void CL_ConnectionlessPacket( netadr_t from, sizebuf_t *msg ) } else if( !Q_strcmp( c, "echo" )) { + if( !CL_IsFromConnectingServer( from )) + return; + // echo request from server Netchan_OutOfBandPrint( NS_CLIENT, from, "%s", Cmd_Argv( 1 )); } else if( !Q_strcmp( c, "disconnect" )) { + if( !CL_IsFromConnectingServer( from )) + return; + // a disconnect message from the server, which will happen if the server // dropped the connection but it is still getting packets from us CL_Disconnect_f(); @@ -2021,6 +2048,48 @@ void CL_ConnectionlessPacket( netadr_t from, sizebuf_t *msg ) memset( &cls.legacyserver, 0, sizeof( cls.legacyserver )); } } + else if( !Q_strcmp( c, "errormsg" )) + { + if( !CL_IsFromConnectingServer( from )) + return; + + args = MSG_ReadString( msg ); + + if( !Q_strcmp( args, "Server uses protocol version 48.\n" )) + { + cls.legacyserver = from; + } + else + { + if( UI_IsVisible() ) + UI_ShowMessageBox( va("^3Server message^7\n%s", args ) ); + Msg( "%s", args ); + } + } + else if( !Q_strcmp( c, "updatemsg" )) + { + // got an update message from master server + // show update dialog from menu + netadr_t adr; + qboolean preferStore = true; + + if( !Q_strcmp( Cmd_Argv( 1 ), "nostore" ) ) + preferStore = false; + + // trust only hardcoded master server + if( NET_StringToAdr( MASTERSERVER_ADR, &adr ) ) + { + if( NET_CompareAdr( from, adr )) + { + UI_ShowUpdateDialog( preferStore ); + } + } + else + { + // in case we don't have master anymore + UI_ShowUpdateDialog( preferStore ); + } + } else if( !Q_strcmp( c, "f" )) { // serverlist got from masterserver @@ -2713,28 +2782,6 @@ void CL_Escape_f( void ) else UI_SetActiveMenu( true ); } -/* -================= -CL_WarnLostSplitPacket - -================= -*/ -void CL_WarnLostSplitPacket( void ) -{ - if( cls.state != ca_connected ) - return; - - if( Host_IsLocalClient() ) - return; - - if( ++cl.lostpackets == 8 ) - { - CL_Disconnect(); - UI_ShowConnectionWarning(); - Con_DPrintf( S_WARN "Too many lost packets! Showing Network options menu\n" ); - } -} - /* ================= CL_InitLocal @@ -2744,6 +2791,7 @@ void CL_InitLocal( void ) { cls.state = ca_disconnected; cls.signon = 0; + memset( &cls.serveradr, 0, sizeof( cls.serveradr ) ); cl.resourcesneeded.pNext = cl.resourcesneeded.pPrev = &cl.resourcesneeded; cl.resourcesonhand.pNext = cl.resourcesonhand.pPrev = &cl.resourcesonhand; diff --git a/engine/client/client.h b/engine/client/client.h index 4c6930f7..228adc06 100644 --- a/engine/client/client.h +++ b/engine/client/client.h @@ -618,11 +618,15 @@ typedef struct file_t *demoheader; // contain demo startup info in case we record a demo on this level qboolean internetservers_wait; // internetservers is waiting for dns request qboolean internetservers_pending; // internetservers is waiting for dns request + + // legacy mode support qboolean legacymode; // one-way 48 protocol compatibility netadr_t legacyserver; netadr_t legacyservers[MAX_LEGACY_SERVERS]; int legacyservercount; int extensions; + + netadr_t serveradr; } client_static_t; #ifdef __cplusplus @@ -1075,7 +1079,8 @@ void UI_CharEvent( int key ); qboolean UI_MouseInRect( void ); qboolean UI_IsVisible( void ); void UI_ResetPing( void ); -void UI_ShowConnectionWarning( void ); +void UI_ShowUpdateDialog( qboolean preferStore ); +void UI_ShowMessageBox( const char *text ); void UI_AddTouchButtonToList( const char *name, const char *texture, const char *command, unsigned char *color, int flags ); void pfnPIC_Set( HIMAGE hPic, int r, int g, int b, int a ); void pfnPIC_Draw( int x, int y, int width, int height, const wrect_t *prc ); diff --git a/engine/common/common.h b/engine/common/common.h index 5d8b1af8..1c802c60 100644 --- a/engine/common/common.h +++ b/engine/common/common.h @@ -851,7 +851,6 @@ qboolean CL_IsInConsole( void ); qboolean CL_IsThirdPerson( void ); qboolean CL_IsIntermission( void ); qboolean CL_Initialized( void ); -void CL_WarnLostSplitPacket( void ); char *CL_Userinfo( void ); void CL_LegacyUpdateInfo( void ); void CL_CharEvent( int key ); @@ -952,6 +951,7 @@ void GL_FreeImage( const char *name ); void VID_InitDefaultResolution( void ); void VID_Init( void ); void UI_SetActiveMenu( qboolean fActive ); +void UI_ShowConnectionWarning( void ); void Cmd_Null_f( void ); // soundlib shared exports diff --git a/engine/common/dedicated.c b/engine/common/dedicated.c index 49922cd1..e89f96ef 100644 --- a/engine/common/dedicated.c +++ b/engine/common/dedicated.c @@ -327,7 +327,7 @@ void CL_ClearStaticEntities( void ) } -void CL_WarnLostSplitPacket( void ) +void UI_ShowConnectionWarning( void ) { } diff --git a/engine/common/net_chan.c b/engine/common/net_chan.c index 31558823..c766d197 100644 --- a/engine/common/net_chan.c +++ b/engine/common/net_chan.c @@ -140,7 +140,7 @@ qboolean NetSplit_GetLong( netsplit_t *ns, netadr_t *from, byte *data, size_t *l // warn if previous packet not received if( p->received < p->count ) { - CL_WarnLostSplitPacket(); + UI_ShowConnectionWarning(); Con_Reportf( S_WARN "NetSplit_GetLong: lost packet %d\n", p->id ); }