engine: client: add random key to the query, so we can validate master server response

This commit is contained in:
Alibek Omarov 2023-10-22 18:16:42 +03:00
parent 201258dc9e
commit 7d61b5317c
2 changed files with 50 additions and 11 deletions

View File

@ -92,7 +92,7 @@ client_t cl;
client_static_t cls; client_static_t cls;
clgame_static_t clgame; clgame_static_t clgame;
void CL_InternetServers_f( void ); static void CL_SendMasterServerScanRequest( void );
//====================================================================== //======================================================================
int GAME_EXPORT CL_Active( void ) int GAME_EXPORT CL_Active( void )
@ -1081,7 +1081,7 @@ void CL_CheckForResend( void )
qboolean bandwidthTest; qboolean bandwidthTest;
if( cls.internetservers_wait ) if( cls.internetservers_wait )
CL_InternetServers_f(); CL_SendMasterServerScanRequest();
// if the local server is running and we aren't then connect // if the local server is running and we aren't then connect
if( cls.state == ca_disconnected && SV_Active( )) if( cls.state == ca_disconnected && SV_Active( ))
@ -1574,10 +1574,10 @@ void CL_LocalServers_f( void )
CL_BuildMasterServerScanRequest CL_BuildMasterServerScanRequest
================= =================
*/ */
static size_t NONNULL CL_BuildMasterServerScanRequest( char *buf, size_t size, qboolean nat, const char *filter ) static size_t NONNULL CL_BuildMasterServerScanRequest( char *buf, size_t size, uint32_t *key, qboolean nat, const char *filter )
{ {
size_t remaining; size_t remaining;
char *info; char *info, temp[32];
if( unlikely( size < sizeof( MS_SCAN_REQUEST ))) if( unlikely( size < sizeof( MS_SCAN_REQUEST )))
return 0; return 0;
@ -1589,15 +1589,32 @@ static size_t NONNULL CL_BuildMasterServerScanRequest( char *buf, size_t size, q
Q_strncpy( info, filter, remaining ); Q_strncpy( info, filter, remaining );
*key = COM_RandomLong( 0, 0x7FFFFFFF );
#ifndef XASH_ALL_SERVERS #ifndef XASH_ALL_SERVERS
Info_SetValueForKey( info, "gamedir", GI->gamefolder, remaining ); Info_SetValueForKey( info, "gamedir", GI->gamefolder, remaining );
#endif #endif
Info_SetValueForKey( info, "clver", XASH_VERSION, remaining ); // let master know about client version Info_SetValueForKey( info, "clver", XASH_VERSION, remaining ); // let master know about client version
Info_SetValueForKey( info, "nat", nat ? "1" : "0", remaining ); Info_SetValueForKey( info, "nat", nat ? "1" : "0", remaining );
Q_snprintf( temp, sizeof( temp ), "%x", *key );
Info_SetValueForKey( info, "key", temp, remaining );
return sizeof( MS_SCAN_REQUEST ) + Q_strlen( info ); return sizeof( MS_SCAN_REQUEST ) + Q_strlen( info );
} }
/*
=================
CL_SendMasterServerScanRequest
=================
*/
static void CL_SendMasterServerScanRequest( void )
{
cls.internetservers_wait = NET_SendToMasters( NS_CLIENT,
cls.internetservers_query_len, cls.internetservers_query );
cls.internetservers_pending = true;
}
/* /*
================= =================
CL_InternetServers_f CL_InternetServers_f
@ -1605,24 +1622,24 @@ CL_InternetServers_f
*/ */
void CL_InternetServers_f( void ) void CL_InternetServers_f( void )
{ {
char fullquery[512];
size_t len;
qboolean nat = cl_nat.value != 0.0f; qboolean nat = cl_nat.value != 0.0f;
uint32_t key;
if( Cmd_Argc( ) > 2 ) if( Cmd_Argc( ) > 2 || ( Cmd_Argc( ) == 2 && !Info_IsValid( Cmd_Argv( 1 ))))
{ {
Con_Printf( S_USAGE "internetservers [filter]\n" ); Con_Printf( S_USAGE "internetservers [filter]\n" );
return; return;
} }
len = CL_BuildMasterServerScanRequest( fullquery, sizeof( fullquery ), nat, Cmd_Argv( 1 )); cls.internetservers_query_len = CL_BuildMasterServerScanRequest(
cls.internetservers_query, sizeof( cls.internetservers_query ),
&cls.internetservers_key, nat, Cmd_Argv( 1 ));
Con_Printf( "Scanning for servers on the internet area...\n" ); Con_Printf( "Scanning for servers on the internet area...\n" );
NET_Config( true, true ); // allow remote NET_Config( true, true ); // allow remote
cls.internetservers_wait = NET_SendToMasters( NS_CLIENT, len, fullquery ); CL_SendMasterServerScanRequest();
cls.internetservers_pending = true;
} }
/* /*
@ -2150,6 +2167,25 @@ void CL_ConnectionlessPacket( netadr_t from, sizebuf_t *msg )
return; return;
} }
// check the extra header
if( MSG_ReadByte( msg ) == 0x7f )
{
uint32_t key = MSG_ReadDword( msg );
if( cls.internetservers_key != key )
{
Con_Printf( S_WARN "unexpected server list packet from %s (invalid key)\n", NET_AdrToString( from ));
return;
}
MSG_ReadByte( msg ); // reserved byte
}
else
{
Con_Printf( S_WARN "invalid server list packet from %s (missing extra header)\n", NET_AdrToString( from ));
return;
}
// serverlist got from masterserver // serverlist got from masterserver
while( MSG_GetNumBitsLeft( msg ) > 8 ) while( MSG_GetNumBitsLeft( msg ) > 8 )
{ {

View File

@ -618,7 +618,10 @@ typedef struct
file_t *demofile; file_t *demofile;
file_t *demoheader; // contain demo startup info in case we record a demo on this level 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_wait; // internetservers is waiting for dns request
qboolean internetservers_pending; // internetservers is waiting for dns request qboolean internetservers_pending; // if true, clean master server pings
uint32_t internetservers_key; // compare key to validate master server reply
char internetservers_query[512]; // cached query
uint32_t internetservers_query_len;
// legacy mode support // legacy mode support
qboolean legacymode; // one-way 48 protocol compatibility qboolean legacymode; // one-way 48 protocol compatibility