//***************************************************************************** // void SERVER_AUTH_Negotiate ( const char *Username, const unsigned int ClientSessionID ) { NETWORK_ClearBuffer( &g_AuthServerBuffer ); NETWORK_WriteLong( &g_AuthServerBuffer.ByteStream, SERVER_AUTH_NEGOTIATE ); NETWORK_WriteByte( &g_AuthServerBuffer.ByteStream, AUTH_PROTOCOL_VERSION ); NETWORK_WriteLong( &g_AuthServerBuffer.ByteStream, ClientSessionID); NETWORK_WriteString( &g_AuthServerBuffer.ByteStream, Username ); NETWORK_LaunchPacket( &g_AuthServerBuffer, g_AuthServerAddress ); }
//***************************************************************************** // void SERVER_AUTH_SRPMessage ( const int MagicNumber, const int SessionID, const TArray<unsigned char> &Bytes ) { NETWORK_ClearBuffer( &g_AuthServerBuffer ); NETWORK_WriteLong( &g_AuthServerBuffer.ByteStream, MagicNumber ); NETWORK_WriteLong( &g_AuthServerBuffer.ByteStream, SessionID ); NETWORK_WriteShort( &g_AuthServerBuffer.ByteStream, Bytes.Size() ); for ( unsigned int i = 0; i < Bytes.Size(); ++i ) NETWORK_WriteByte( &g_AuthServerBuffer.ByteStream, Bytes[i] ); NETWORK_LaunchPacket( &g_AuthServerBuffer, g_AuthServerAddress ); }
//***************************************************************************** // void ZANDRONUM_QueryServer( SERVER_s *pServer ) { // Clear out the buffer, and write out launcher challenge. NETWORK_ClearBuffer( &g_MessageBuffer ); NETWORK_WriteLong( &g_MessageBuffer.ByteStream, LAUNCHER_SERVER_CHALLENGE ); NETWORK_WriteLong( &g_MessageBuffer.ByteStream, SQF_NUMPLAYERS|SQF_PLAYERDATA|SQF_GAMETYPE ); NETWORK_WriteLong( &g_MessageBuffer.ByteStream, 0 ); // Send the server our packet. NETWORK_LaunchPacket( &g_MessageBuffer, pServer->Address, true ); }
//***************************************************************************** // void SERVER_MASTER_Tick( void ) { UCVarValue Val; while (( g_lStoredQueryIPHead != g_lStoredQueryIPTail ) && ( gametic >= g_StoredQueryIPs[g_lStoredQueryIPHead].lNextAllowedGametic )) { g_lStoredQueryIPHead++; g_lStoredQueryIPHead = g_lStoredQueryIPHead % MAX_STORED_QUERY_IPS; } // Send an update to the master server every 30 seconds. if ( gametic % ( TICRATE * 30 )) return; // User doesn't wish to update the master server. if ( sv_updatemaster == false ) return; NETWORK_ClearBuffer( &g_MasterServerBuffer ); Val = sv_masterip.GetGenericRep( CVAR_String ); NETWORK_StringToAddress( Val.String, &g_AddressMasterServer ); I_SetPort( g_AddressMasterServer, g_lMasterPort ); // Write to our packet a challenge to the master server. Val = sv_masteroverrideip.GetGenericRep( CVAR_String ); if ( Val.String[0] == '\0' ) NETWORK_WriteLong( &g_MasterServerBuffer, SERVER_MASTER_CHALLENGE ); else { netadr_t OverrideIP; NETWORK_WriteLong( &g_MasterServerBuffer, SERVER_MASTER_CHALLENGE_OVERRIDE ); NETWORK_StringToAddress( Val.String, &OverrideIP ); NETWORK_WriteByte( &g_MasterServerBuffer, OverrideIP.ip[0] ); NETWORK_WriteByte( &g_MasterServerBuffer, OverrideIP.ip[1] ); NETWORK_WriteByte( &g_MasterServerBuffer, OverrideIP.ip[2] ); NETWORK_WriteByte( &g_MasterServerBuffer, OverrideIP.ip[3] ); NETWORK_WriteShort( &g_MasterServerBuffer, NETWORK_GetLocalPort( )); } // Send the master server our packet. // NETWORK_LaunchPacket( &g_MasterServerBuffer, g_AddressMasterServer, true ); NETWORK_LaunchPacket( &g_MasterServerBuffer, g_AddressMasterServer ); }
//***************************************************************************** // void MASTERSERVER_RequestServerVerification( const SERVER_s &Server ) { NETWORK_ClearBuffer( &g_MessageBuffer ); NETWORK_WriteByte( &g_MessageBuffer.ByteStream, MASTER_SERVER_VERIFICATION ); NETWORK_WriteString( &g_MessageBuffer.ByteStream, Server.MasterBanlistVerificationString.c_str() ); NETWORK_WriteLong( &g_MessageBuffer.ByteStream, Server.ServerVerificationInt ); NETWORK_LaunchPacket( &g_MessageBuffer, Server.Address ); }
//***************************************************************************** // void MASTERSERVER_SendBanlistToServer( const SERVER_s &Server ) { // [BB] If the server supports it, potentially split the ban list over multiple packets. if ( Server.iServerRevision >= 2907 ) { BanlistPacketSender sender ( Server ); sender.start(); // Write all the bans. for ( unsigned int i = 0; i < g_BannedIPs.size( ); ++i ) sender.writeBanEntry ( g_BannedIPs.getEntryAsString( i, false, false, false ).c_str( ), MSB_BAN ); // Write all the exceptions. for ( unsigned int i = 0; i < g_BannedIPExemptions.size( ); ++i ) sender.writeBanEntry ( g_BannedIPExemptions.getEntryAsString( i, false, false, false ).c_str( ), MSB_BANEXEMPTION ); sender.end(); } else { NETWORK_ClearBuffer( &g_MessageBuffer ); NETWORK_WriteByte( &g_MessageBuffer.ByteStream, MASTER_SERVER_BANLIST ); // [BB] If the server sent us a verification string, send it along with the ban list. // This allows the server to verify that the list actually was sent from our master // (and is not just a packet with forged source IP). if ( Server.MasterBanlistVerificationString.size() ) NETWORK_WriteString( &g_MessageBuffer.ByteStream, Server.MasterBanlistVerificationString.c_str() ); // Write all the bans. NETWORK_WriteLong( &g_MessageBuffer.ByteStream, g_BannedIPs.size( )); for ( ULONG i = 0; i < g_BannedIPs.size( ); i++ ) NETWORK_WriteString( &g_MessageBuffer.ByteStream, g_BannedIPs.getEntryAsString( i, false, false, false ).c_str( )); // Write all the exceptions. NETWORK_WriteLong( &g_MessageBuffer.ByteStream, g_BannedIPExemptions.size( )); for ( ULONG i = 0; i < g_BannedIPExemptions.size( ); i++ ) NETWORK_WriteString( &g_MessageBuffer.ByteStream, g_BannedIPExemptions.getEntryAsString( i, false, false, false ).c_str( )); NETWORK_LaunchPacket( &g_MessageBuffer, Server.Address ); } Server.bHasLatestBanList = true; Server.bVerifiedLatestBanList = false; printf( "-> Banlist sent to %s.\n", NETWORK_AddressToString( Server.Address )); }
//***************************************************************************** // void ZANDRONUM_QueryMasterServer( void ) { // Clear out the buffer, and write out launcher challenge. NETWORK_ClearBuffer( &g_MessageBuffer ); NETWORK_WriteLong( &g_MessageBuffer.ByteStream, LAUNCHER_MASTER_CHALLENGE ); NETWORK_WriteShort( &g_MessageBuffer.ByteStream, MASTER_SERVER_VERSION ); // Send the master server our packet. NETWORK_LaunchPacket( &g_MessageBuffer, g_AddressMasterServer, true ); }
//***************************************************************************** // void NETWORK_WriteFloat( BYTESTREAM_s *pByteStream, float Float ) { union { float f; int l; } dat; dat.f = Float; NETWORK_WriteLong( pByteStream, dat.l ); }
//***************************************************************************** // void SERVER_MASTER_SendServerInfo( netadr_t Address, ULONG ulFlags, ULONG ulTime ) { UCVarValue Val; char szAddress[4][4]; ULONG ulIdx; ULONG ulBits; ULONG ulNumPWADs; // Let's just use the master server buffer! It gets cleared again when we need it anyway! NETWORK_ClearBuffer( &g_MasterServerBuffer ); // First, check to see if we've been queried by this address recently. if ( g_lStoredQueryIPHead != g_lStoredQueryIPTail ) { ulIdx = g_lStoredQueryIPHead; while ( ulIdx != (ULONG)g_lStoredQueryIPTail ) { // Check to see if this IP exists in our stored query IP list. If it does, then // ignore it, since it queried us less than 10 seconds ago. if ( NETWORK_CompareAddress( Address, g_StoredQueryIPs[ulIdx].Address, true )) { // Write our header. NETWORK_WriteLong( &g_MasterServerBuffer, SERVER_LAUNCHER_IGNORING ); // Send the time the launcher sent to us. NETWORK_WriteLong( &g_MasterServerBuffer, ulTime ); // Send the packet. // NETWORK_LaunchPacket( &g_MasterServerBuffer, Address, true ); NETWORK_LaunchPacket( &g_MasterServerBuffer, Address ); if ( sv_showlauncherqueries ) Printf( "Ignored IP launcher challenge.\n" ); // Nothing more to do here. return; } ulIdx++; ulIdx = ulIdx % MAX_STORED_QUERY_IPS; } } // Now, check to see if this IP has been banend from this server. itoa( Address.ip[0], szAddress[0], 10 ); itoa( Address.ip[1], szAddress[1], 10 ); itoa( Address.ip[2], szAddress[2], 10 ); itoa( Address.ip[3], szAddress[3], 10 ); if (( sv_enforcebans ) && ( SERVERBAN_IsIPBanned( szAddress[0], szAddress[1], szAddress[2], szAddress[3] ))) { // Write our header. NETWORK_WriteLong( &g_MasterServerBuffer, SERVER_LAUNCHER_BANNED ); // Send the time the launcher sent to us. NETWORK_WriteLong( &g_MasterServerBuffer, ulTime ); // Send the packet. NETWORK_LaunchPacket( &g_MasterServerBuffer, Address ); if ( sv_showlauncherqueries ) Printf( "Denied BANNED IP launcher challenge.\n" ); // Nothing more to do here. return; } // This IP didn't exist in the list. and it wasn't banned. // So, add it, and keep it there for 10 seconds. g_StoredQueryIPs[g_lStoredQueryIPTail].Address = Address; g_StoredQueryIPs[g_lStoredQueryIPTail].lNextAllowedGametic = gametic + ( TICRATE * ( sv_queryignoretime )); g_lStoredQueryIPTail++; g_lStoredQueryIPTail = g_lStoredQueryIPTail % MAX_STORED_QUERY_IPS; if ( g_lStoredQueryIPTail == g_lStoredQueryIPHead ) Printf( "SERVER_MASTER_SendServerInfo: WARNING! g_lStoredQueryIPTail == g_lStoredQueryIPHead\n" ); // Write our header. NETWORK_WriteLong( &g_MasterServerBuffer, SERVER_LAUNCHER_CHALLENGE ); // Send the time the launcher sent to us. NETWORK_WriteLong( &g_MasterServerBuffer, ulTime ); // Send our version. NETWORK_WriteString( &g_MasterServerBuffer, DOTVERSIONSTR ); // Send the information about the data that will be sent. ulBits = ulFlags; // If the launcher desires to know the team damage, but we're not in a game mode where // team damage applies, then don't send back team damage information. if (( teamplay || teamgame || teamlms || teampossession || teamcoop || (( deathmatch == false ) && ( teamgame == false ))) == false ) { if ( ulBits & SQF_TEAMDAMAGE ) ulBits &= ~SQF_TEAMDAMAGE; } // If the launcher desires to know the team score, but we're not in a game mode where // teams have scores, then don't send back team score information. if (( teamplay || teamgame || teamlms || teampossession || teamcoop ) == false ) { if ( ulBits & SQF_TEAMSCORES ) ulBits &= ~SQF_TEAMSCORES; } // If the launcher wants to know player data, then we have to tell them how many players // are in the server. if ( ulBits & SQF_PLAYERDATA ) ulBits |= SQF_NUMPLAYERS; NETWORK_WriteLong( &g_MasterServerBuffer, ulBits ); // Send the server name. if ( ulBits & SQF_NAME ) { Val = sv_hostname.GetGenericRep( CVAR_String ); NETWORK_WriteString( &g_MasterServerBuffer, Val.String ); } // Send the website URL. if ( ulBits & SQF_URL ) { Val = sv_website.GetGenericRep( CVAR_String ); NETWORK_WriteString( &g_MasterServerBuffer, Val.String ); } // Send the host's e-mail address. if ( ulBits & SQF_EMAIL ) { Val = sv_hostemail.GetGenericRep( CVAR_String ); NETWORK_WriteString( &g_MasterServerBuffer, Val.String ); } if ( ulBits & SQF_MAPNAME ) NETWORK_WriteString( &g_MasterServerBuffer, level.mapname ); if ( ulBits & SQF_MAXCLIENTS ) NETWORK_WriteByte( &g_MasterServerBuffer, sv_maxclients ); if ( ulBits & SQF_MAXPLAYERS ) NETWORK_WriteByte( &g_MasterServerBuffer, sv_maxplayers ); // Send out the PWAD information. if ( ulBits & SQF_PWADS ) { ulNumPWADs = 0; for ( ulIdx = 0; Wads.GetWadName( ulIdx ) != NULL; ulIdx++ ) { // Skip the IWAD file index, skulltag.wad/pk3, and files that were automatically // loaded from subdirectories (such as skin files). if (( ulIdx == FWadCollection::IWAD_FILENUM ) || ( stricmp( Wads.GetWadName( ulIdx ), "scoredoomst.wad" ) == 0 ) || ( stricmp( Wads.GetWadName( ulIdx ), "scoredoomst.pk3" ) == 0 ) || ( Wads.GetLoadedAutomatically( ulIdx ))) { continue; } ulNumPWADs++; } NETWORK_WriteByte( &g_MasterServerBuffer, ulNumPWADs ); for ( ulIdx = 0; Wads.GetWadName( ulIdx ) != NULL; ulIdx++ ) { // Skip the IWAD file index, skulltag.wad/pk3, and files that were automatically // loaded from subdirectories (such as skin files). if (( ulIdx == FWadCollection::IWAD_FILENUM ) || ( stricmp( Wads.GetWadName( ulIdx ), "scoredoomst.wad" ) == 0 ) || ( stricmp( Wads.GetWadName( ulIdx ), "scoredoomst.pk3" ) == 0 ) || ( Wads.GetLoadedAutomatically( ulIdx ))) { continue; } NETWORK_WriteString( &g_MasterServerBuffer, (char *)Wads.GetWadName( ulIdx )); } } if ( ulBits & SQF_GAMETYPE ) { NETWORK_WriteByte( &g_MasterServerBuffer, GAME_GetGameType( )); NETWORK_WriteByte( &g_MasterServerBuffer, instagib ); NETWORK_WriteByte( &g_MasterServerBuffer, buckshot ); } if ( ulBits & SQF_GAMENAME ) NETWORK_WriteString( &g_MasterServerBuffer, SERVER_MASTER_GetGameName( )); if ( ulBits & SQF_IWAD ) NETWORK_WriteString( &g_MasterServerBuffer, (char *)Wads.GetWadName( FWadCollection::IWAD_FILENUM )); if ( ulBits & SQF_FORCEPASSWORD ) NETWORK_WriteByte( &g_MasterServerBuffer, sv_forcepassword ); if ( ulBits & SQF_FORCEJOINPASSWORD ) NETWORK_WriteByte( &g_MasterServerBuffer, sv_forcejoinpassword ); if ( ulBits & SQF_GAMESKILL ) NETWORK_WriteByte( &g_MasterServerBuffer, gameskill ); if ( ulBits & SQF_BOTSKILL ) NETWORK_WriteByte( &g_MasterServerBuffer, botskill ); if ( ulBits & SQF_DMFLAGS ) { NETWORK_WriteLong( &g_MasterServerBuffer, dmflags ); NETWORK_WriteLong( &g_MasterServerBuffer, dmflags2 ); NETWORK_WriteLong( &g_MasterServerBuffer, compatflags ); } if ( ulBits & SQF_LIMITS ) { NETWORK_WriteShort( &g_MasterServerBuffer, fraglimit ); NETWORK_WriteShort( &g_MasterServerBuffer, (SHORT)timelimit ); if ( timelimit ) { LONG lTimeLeft; lTimeLeft = (LONG)( timelimit - ( level.totaltime / ( TICRATE * 60 ))); //ghk if ( lTimeLeft < 0 ) lTimeLeft = 0; NETWORK_WriteShort( &g_MasterServerBuffer, lTimeLeft ); } NETWORK_WriteShort( &g_MasterServerBuffer, duellimit ); NETWORK_WriteLong( &g_MasterServerBuffer, pointlimit ); //ghk writelong NETWORK_WriteShort( &g_MasterServerBuffer, winlimit ); } // Send the team damage scale. if ( teamplay || teamgame || teamlms || teampossession || teamcoop || (( deathmatch == false ) && ( teamgame == false ))) { if ( ulBits & SQF_TEAMDAMAGE ) NETWORK_WriteFloat( &g_MasterServerBuffer, teamdamage ); } // Send the team scores. if ( teamplay || teamgame || teamlms || teampossession || teamcoop ) { if ( ulBits & SQF_TEAMSCORES ) { for ( ulIdx = 0; ulIdx < NUM_TEAMS; ulIdx++ ) { if ( teamplay ) NETWORK_WriteShort( &g_MasterServerBuffer, TEAM_GetFragCount( ulIdx )); else if ( teamlms ) NETWORK_WriteShort( &g_MasterServerBuffer, TEAM_GetWinCount( ulIdx )); else NETWORK_WriteShort( &g_MasterServerBuffer, TEAM_GetScore( ulIdx )); //ghk writelong? } } } if ( ulBits & SQF_NUMPLAYERS ) NETWORK_WriteByte( &g_MasterServerBuffer, SERVER_CalcNumPlayers( )); if ( ulBits & SQF_PLAYERDATA ) { for ( ulIdx = 0; ulIdx < MAXPLAYERS; ulIdx++ ) { if ( playeringame[ulIdx] == false ) continue; NETWORK_WriteString( &g_MasterServerBuffer, players[ulIdx].userinfo.netname ); if ( teamgame || possession || teampossession || cooperative || teamcoop ) NETWORK_WriteLong( &g_MasterServerBuffer, players[ulIdx].lPointCount );//ghk writelong else if ( deathmatch ) NETWORK_WriteLong( &g_MasterServerBuffer, players[ulIdx].fragcount ); //ghk writelong else NETWORK_WriteLong( &g_MasterServerBuffer, players[ulIdx].killcount ); //ghk writelong NETWORK_WriteShort( &g_MasterServerBuffer, players[ulIdx].ulPing ); NETWORK_WriteByte( &g_MasterServerBuffer, PLAYER_IsTrueSpectator( &players[ulIdx] )); NETWORK_WriteByte( &g_MasterServerBuffer, players[ulIdx].bIsBot ); if ( teamplay || teamgame || teamlms || teampossession || teamcoop ) { if ( players[ulIdx].bOnTeam == false ) NETWORK_WriteByte( &g_MasterServerBuffer, 255 ); else NETWORK_WriteByte( &g_MasterServerBuffer, players[ulIdx].ulTeam ); } NETWORK_WriteByte( &g_MasterServerBuffer, players[ulIdx].ulTime / ( TICRATE * 60 )); } } // NETWORK_LaunchPacket( &g_MasterServerBuffer, Address, true ); NETWORK_LaunchPacket( &g_MasterServerBuffer, Address ); }
//***************************************************************************** // void MASTERSERVER_ParseCommands( BYTESTREAM_s *pByteStream ) { long lCommand; NETADDRESS_s AddressFrom; AddressFrom = NETWORK_GetFromAddress( ); // [RC] If this IP is in our flood queue, ignore it completely. if ( g_floodProtectionIPQueue.addressInQueue( AddressFrom ) || g_ShortFloodQueue.addressInQueue( AddressFrom )) { while ( NETWORK_ReadByte( pByteStream ) != -1 ) // [RC] Is this really necessary? ; return; } // Is this IP banned? Send the user an explanation, and ignore the IP for 30 seconds. if ( !g_BannedIPExemptions.isIPInList( AddressFrom ) && g_BannedIPs.isIPInList( AddressFrom )) { NETWORK_ClearBuffer( &g_MessageBuffer ); NETWORK_WriteLong( &g_MessageBuffer.ByteStream, MSC_IPISBANNED ); NETWORK_LaunchPacket( &g_MessageBuffer, AddressFrom ); printf( "* Received challenge from banned IP (%s). Ignoring for 10 seconds.\n", NETWORK_AddressToString( AddressFrom )); g_queryIPQueue.addAddress( AddressFrom, g_lCurrentTime, &std::cerr ); return; } lCommand = NETWORK_ReadLong( pByteStream ); switch ( lCommand ) { // Server is telling master server of its existence. case SERVER_MASTER_CHALLENGE: { // Certain IPs can be blocked from just hosting. if ( !g_BannedIPExemptions.isIPInList( AddressFrom ) && g_BlockedIPs.isIPInList( AddressFrom )) { NETWORK_ClearBuffer( &g_MessageBuffer ); NETWORK_WriteLong( &g_MessageBuffer.ByteStream, MSC_IPISBANNED ); NETWORK_LaunchPacket( &g_MessageBuffer, AddressFrom ); printf( "* Received server challenge from blocked IP (%s). Ignoring for 10 seconds.\n", NETWORK_AddressToString( AddressFrom )); g_queryIPQueue.addAddress( AddressFrom, g_lCurrentTime, &std::cerr ); return; } SERVER_s newServer; newServer.Address = AddressFrom; // [BB] If no verification string was send, NETWORK_ReadString just returns an empty string. // Thus, this is still compatible with older servers that don't send the string. newServer.MasterBanlistVerificationString = NETWORK_ReadString( pByteStream ); // [BB] If no value was send, NETWORK_ReadByte just returns -1. // Thus, this is still compatible with older servers that don't tell us whether they enforce our bans // and gives them the benefit of the doubt, i.e. it assumes that they enforce our bans. const int temp = NETWORK_ReadByte( pByteStream ); newServer.bEnforcesBanList = ( temp != 0 ); newServer.bNewFormatServer = ( temp != -1 ); newServer.iServerRevision = ( ( pByteStream->pbStreamEnd - pByteStream->pbStream ) >= 4 ) ? NETWORK_ReadLong( pByteStream ) : NETWORK_ReadShort( pByteStream ); std::set<SERVER_s, SERVERCompFunc>::iterator currentServer = g_Servers.find ( newServer ); // This is a new server; add it to the list. if ( currentServer == g_Servers.end() ) { unsigned int iNumOtherServers = 0; // First count the number of servers from this IP. for( std::set<SERVER_s, SERVERCompFunc>::const_iterator it = g_Servers.begin(); it != g_Servers.end(); ++it ) { if ( NETWORK_CompareAddress( it->Address, AddressFrom, true )) iNumOtherServers++; } if ( iNumOtherServers >= 10 && !g_MultiServerExceptions.isIPInList( AddressFrom )) printf( "* More than 10 servers received from %s. Ignoring request...\n", NETWORK_AddressToString( AddressFrom )); else { // [BB] 3021 is 98d, don't put those servers on the list. if ( ( newServer.bNewFormatServer ) && ( newServer.iServerRevision != 3021 ) ) { std::set<SERVER_s, SERVERCompFunc>::iterator currentUnverifiedServer = g_UnverifiedServers.find ( newServer ); // [BB] This is a new server, but we still need to verify it. if ( currentUnverifiedServer == g_UnverifiedServers.end() ) { srand ( time(NULL) ); newServer.ServerVerificationInt = rand() + rand() * rand() + rand() * rand() * rand(); // [BB] We don't send the ban list to unverified servers, so just pretent the server already has the list. newServer.bHasLatestBanList = true; MASTERSERVER_RequestServerVerification ( newServer ); MASTERSERVER_AddServer( newServer, g_UnverifiedServers ); } } else { printf( "* Received server challenge from old server (%s). Ignoring IP for 10 seconds.\n", NETWORK_AddressToString( newServer.Address )); g_queryIPQueue.addAddress( newServer.Address, g_lCurrentTime, &std::cerr ); } } } // Command is from a server already on the list. It's just sending us a heartbeat. else { // [BB] Only if the verification string matches. if ( stricmp ( currentServer->MasterBanlistVerificationString.c_str(), newServer.MasterBanlistVerificationString.c_str() ) == 0 ) { currentServer->lLastReceived = g_lCurrentTime; // [BB] The server possibly changed the ban setting, so update it. currentServer->bEnforcesBanList = newServer.bEnforcesBanList; } } // Ignore IP for 10 seconds. // if ( !g_MultiServerExceptions.isIPInList( Address ) ) // g_floodProtectionIPQueue.addAddress( AddressFrom, g_lCurrentTime, &std::cerr ); return; } case SERVER_MASTER_VERIFICATION: { SERVER_s newServer; newServer.Address = AddressFrom; newServer.MasterBanlistVerificationString = NETWORK_ReadString( pByteStream ); newServer.ServerVerificationInt = NETWORK_ReadLong( pByteStream ); std::set<SERVER_s, SERVERCompFunc>::iterator currentServer = g_UnverifiedServers.find ( newServer ); // [BB] Apparently, we didn't request any verification from this server, so ignore it. if ( currentServer == g_UnverifiedServers.end() ) return; if ( ( stricmp ( newServer.MasterBanlistVerificationString.c_str(), currentServer->MasterBanlistVerificationString.c_str() ) == 0 ) && ( newServer.ServerVerificationInt == currentServer->ServerVerificationInt ) ) { MASTERSERVER_AddServer( *currentServer, g_Servers ); g_UnverifiedServers.erase ( currentServer ); } return; } case SERVER_MASTER_BANLIST_RECEIPT: { SERVER_s server; server.Address = AddressFrom; server.MasterBanlistVerificationString = NETWORK_ReadString( pByteStream ); std::set<SERVER_s, SERVERCompFunc>::iterator currentServer = g_Servers.find ( server ); // [BB] We don't know the server. Just ignore it. if ( currentServer == g_Servers.end() ) return; if ( stricmp ( server.MasterBanlistVerificationString.c_str(), currentServer->MasterBanlistVerificationString.c_str() ) == 0 ) { currentServer->bVerifiedLatestBanList = true; std::cerr << NETWORK_AddressToString ( AddressFrom ) << " acknowledged receipt of the banlist.\n"; } } return; // Launcher is asking master server for server list. case LAUNCHER_SERVER_CHALLENGE: case LAUNCHER_MASTER_CHALLENGE: { NETWORK_ClearBuffer( &g_MessageBuffer ); // Did this IP query us recently? If so, send it an explanation, and ignore it completely for 3 seconds. if ( g_queryIPQueue.addressInQueue( AddressFrom )) { NETWORK_WriteLong( &g_MessageBuffer.ByteStream, MSC_REQUESTIGNORED ); NETWORK_LaunchPacket( &g_MessageBuffer, AddressFrom ); printf( "* Extra launcher challenge from %s. Ignoring for 3 seconds.\n", NETWORK_AddressToString( AddressFrom )); g_ShortFloodQueue.addAddress( AddressFrom, g_lCurrentTime, &std::cerr ); return; } // [BB] The launcher only sends the protocol version with LAUNCHER_MASTER_CHALLENGE. if ( lCommand == LAUNCHER_MASTER_CHALLENGE ) { // [BB] Check if the requested version of the protocol matches ours. const unsigned short usVersion = NETWORK_ReadShort( pByteStream ); if ( usVersion != MASTER_SERVER_VERSION ) { NETWORK_WriteLong( &g_MessageBuffer.ByteStream, MSC_WRONGVERSION ); NETWORK_LaunchPacket( &g_MessageBuffer, AddressFrom ); return; } } printf( "-> Sending server list to %s.\n", NETWORK_AddressToString( AddressFrom )); // Wait 10 seconds before sending this IP the server list again. g_queryIPQueue.addAddress( AddressFrom, g_lCurrentTime, &std::cerr ); switch ( lCommand ) { case LAUNCHER_SERVER_CHALLENGE: // Send the list of servers. NETWORK_WriteLong( &g_MessageBuffer.ByteStream, MSC_BEGINSERVERLIST ); for( std::set<SERVER_s, SERVERCompFunc>::const_iterator it = g_Servers.begin(); it != g_Servers.end(); ++it ) { // [BB] Possibly omit servers that don't enforce our ban list. if ( ( it->bEnforcesBanList == true ) || ( g_bHideBanIgnoringServers == false ) ) MASTERSERVER_SendServerIPToLauncher ( it->Address, &g_MessageBuffer.ByteStream ); } // Tell the launcher that we're done sending servers. NETWORK_WriteByte( &g_MessageBuffer.ByteStream, MSC_ENDSERVERLIST ); // Send the launcher our packet. NETWORK_LaunchPacket( &g_MessageBuffer, AddressFrom ); return; case LAUNCHER_MASTER_CHALLENGE: const unsigned long ulMaxPacketSize = 1024; unsigned long ulPacketNum = 0; std::set<SERVER_s, SERVERCompFunc>::const_iterator it = g_Servers.begin(); NETWORK_WriteLong( &g_MessageBuffer.ByteStream, MSC_BEGINSERVERLISTPART ); NETWORK_WriteByte( &g_MessageBuffer.ByteStream, ulPacketNum ); NETWORK_WriteByte( &g_MessageBuffer.ByteStream, MSC_SERVERBLOCK ); unsigned long ulSizeOfPacket = 6; // 4 (MSC_BEGINSERVERLISTPART) + 1 (0) + 1 (MSC_SERVERBLOCK) while ( it != g_Servers.end() ) { NETADDRESS_s serverAddress = it->Address; std::vector<USHORT> serverPortList; do { // [BB] Possibly omit servers that don't enforce our ban list. if ( ( it->bEnforcesBanList == true ) || ( g_bHideBanIgnoringServers == false ) ) serverPortList.push_back ( it->Address.usPort ); ++it; } while ( ( it != g_Servers.end() ) && NETWORK_CompareAddress( it->Address, serverAddress, true ) ); // [BB] All servers on this IP ignore the list, nothing to send. if ( serverPortList.size() == 0 ) continue; const unsigned long ulServerBlockNetSize = MASTERSERVER_CalcServerIPBlockNetSize( serverAddress, serverPortList ); // [BB] If sending this block would cause the current packet to exceed ulMaxPacketSize ... if ( ulSizeOfPacket + ulServerBlockNetSize > ulMaxPacketSize - 1 ) { // [BB] ... close the current packet and start a new one. NETWORK_WriteByte( &g_MessageBuffer.ByteStream, 0 ); // [BB] Terminate MSC_SERVERBLOCK by sending 0 ports. NETWORK_WriteByte( &g_MessageBuffer.ByteStream, MSC_ENDSERVERLISTPART ); NETWORK_LaunchPacket( &g_MessageBuffer, AddressFrom ); NETWORK_ClearBuffer( &g_MessageBuffer ); ++ulPacketNum; ulSizeOfPacket = 5; NETWORK_WriteLong( &g_MessageBuffer.ByteStream, MSC_BEGINSERVERLISTPART ); NETWORK_WriteByte( &g_MessageBuffer.ByteStream, ulPacketNum ); NETWORK_WriteByte( &g_MessageBuffer.ByteStream, MSC_SERVERBLOCK ); } ulSizeOfPacket += ulServerBlockNetSize; MASTERSERVER_SendServerIPBlockToLauncher ( serverAddress, serverPortList, &g_MessageBuffer.ByteStream ); } NETWORK_WriteByte( &g_MessageBuffer.ByteStream, 0 ); // [BB] Terminate MSC_SERVERBLOCK by sending 0 ports. NETWORK_WriteByte( &g_MessageBuffer.ByteStream, MSC_ENDSERVERLIST ); NETWORK_LaunchPacket( &g_MessageBuffer, AddressFrom ); return; } } } printf( "* Received unknown challenge (%ld) from %s. Ignoring for 10 seconds...\n", lCommand, NETWORK_AddressToString( AddressFrom )); g_floodProtectionIPQueue.addAddress( AddressFrom, g_lCurrentTime, &std::cerr ); }