//***************************************************************************** // void IPList::copy( IPList &destination ) { destination.clear( ); for ( ULONG ulIdx = 0; ulIdx < _ipVector.size( ); ulIdx++ ) destination.push_back( _ipVector[ulIdx] ); destination.sort( ); }
//***************************************************************************** // 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 ProtocolLogin::getCharacterList(uint32_t accountName, const std::string& password) { uint32_t serverIp = serverIPs[0].first; for (uint32_t i = 0; i < serverIPs.size(); i++) { if ((serverIPs[i].first & serverIPs[i].second) == (getConnection()->getIP() & serverIPs[i].second)) { serverIp = serverIPs[i].first; break; } } Account account; if (!IOLoginData::loginserverAuthentication(accountName, password, account)) { disconnectClient("Account name or password is not correct."); return; } auto output = OutputMessagePool::getOutputMessage(); //Update premium days Game::updatePremium(account); const std::string& motd = g_config.getString(ConfigManager::MOTD); if (!motd.empty()) { //Add MOTD output->addByte(0x14); std::ostringstream ss; ss << g_game.getMotdNum() << "\n" << motd; output->addString(ss.str()); } //Add char list output->addByte(0x64); uint8_t size = std::min<size_t>(std::numeric_limits<uint8_t>::max(), account.characters.size()); output->addByte(size); for (uint8_t i = 0; i < size; i++) { output->addString(account.characters[i]); output->addString(g_config.getString(ConfigManager::SERVER_NAME)); output->add<uint32_t>(serverIp); output->add<uint16_t>(g_config.getNumber(ConfigManager::GAME_PORT)); } //Add premium days if (g_config.getBoolean(ConfigManager::FREE_PREMIUM)) { output->add<uint16_t>(0xFFFF); //client displays free premium } else { output->add<uint16_t>(account.premiumDays); } send(output); disconnect(); }
//***************************************************************************** // bool MASTERSERVER_RefreshIPList( IPList &List, const char *FileName ) { std::stringstream oldIPs; for ( ULONG ulIdx = 0; ulIdx < List.size(); ulIdx++ ) oldIPs << List.getEntryAsString ( ulIdx, false ).c_str() << "-"; if ( !(List.clearAndLoadFromFile( FileName )) ) std::cerr << List.getErrorMessage(); std::stringstream newIPs; for ( ULONG ulIdx = 0; ulIdx < List.size(); ulIdx++ ) newIPs << List.getEntryAsString ( ulIdx, false ).c_str() << "-"; return ( strcmp ( newIPs.str().c_str(), oldIPs.str().c_str() ) != 0 ); }
//***************************************************************************** // void MASTERSERVER_InitializeBans( void ) { const bool BannedIPsChanged = MASTERSERVER_RefreshIPList ( g_BannedIPs, "banlist.txt" ); const bool BannedIPExemptionsChanged = MASTERSERVER_RefreshIPList ( g_BannedIPExemptions, "whitelist.txt" ); if ( !(g_MultiServerExceptions.clearAndLoadFromFile( "multiserver_whitelist.txt" )) ) std::cerr << g_MultiServerExceptions.getErrorMessage(); if ( !(g_BlockedIPs.clearAndLoadFromFile( "blocklist.txt" )) ) std::cerr << g_BlockedIPs.getErrorMessage(); std::cerr << "\nBan list: " << g_BannedIPs.size() << " banned IPs, " << g_BlockedIPs.size( ) << " blocked IPs, " << g_BannedIPExemptions.size() << " exemptions." << std::endl; std::cerr << "Multi-server exceptions: " << g_MultiServerExceptions.size() << "." << std::endl; if ( BannedIPsChanged || BannedIPExemptionsChanged ) { // [BB] The ban list was changed, so no server has the latest list anymore. for( std::set<SERVER_s, SERVERCompFunc>::iterator it = g_Servers.begin(); it != g_Servers.end(); ++it ) { it->bHasLatestBanList = false; it->bVerifiedLatestBanList = false; } std::cerr << "Ban lists were changed since last refresh\n"; } /* // [BB] Print all banned IPs, to make sure the IP list has been parsed successfully. std::cerr << "Entries in blacklist:\n"; for ( ULONG ulIdx = 0; ulIdx < g_BannedIPs.size(); ulIdx++ ) std::cerr << g_BannedIPs.getEntryAsString(ulIdx).c_str(); // [BB] Print all exemption-IPs, to make sure the IP list has been parsed successfully. std::cerr << "Entries in whitelist:\n"; for ( ULONG ulIdx = 0; ulIdx < g_BannedIPExemptions.size(); ulIdx++ ) std::cerr << g_BannedIPExemptions.getEntryAsString(ulIdx).c_str(); */ }
void IAllocation::addPermissions(const IPList& ips) { for (auto it = ips.begin(); it != ips.end(); ++it) { addPermission(*it); } }
//***************************************************************************** // 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 ); }
bool ProtocolLogin::parseFirstPacket(NetworkMessage& msg) { if( #ifndef _CONSOLE !GUI::getInstance()->m_connections || #endif g_game.getGameState() == GAME_STATE_SHUTDOWN) { getConnection()->closeConnection(); return false; } uint32_t clientip = getConnection()->getIP(); /*uint16_t clientos = */msg.GetU16(); uint16_t version = msg.GetU16(); msg.SkipBytes(12); if(version <= 760) { disconnectClient(0x0A, "Only clients with protocol " CLIENT_VERSION_STR " allowed!"); return false; } if(!RSA_decrypt(msg)) { getConnection()->closeConnection(); return false; } uint32_t key[4]; key[0] = msg.GetU32(); key[1] = msg.GetU32(); key[2] = msg.GetU32(); key[3] = msg.GetU32(); enableXTEAEncryption(); setXTEAKey(key); std::string accountName = msg.GetString(); std::string password = msg.GetString(); if(accountName.empty()) { if(g_config.getBoolean(ConfigManager::ACCOUNT_MANAGER)) { accountName = "1"; password = "******"; } else { disconnectClient(0x0A, "Invalid Account Name."); return false; } } if(version < CLIENT_VERSION_MIN || version > CLIENT_VERSION_MAX) { disconnectClient(0x0A, "Only clients with protocol " CLIENT_VERSION_STR " allowed!"); return false; } if(g_game.getGameState() == GAME_STATE_STARTUP) { disconnectClient(0x0A, "Gameworld is starting up. Please wait."); return false; } if(g_game.getGameState() == GAME_STATE_MAINTAIN) { disconnectClient(0x0A, "Gameworld is under maintenance. Please re-connect in a while."); return false; } if(g_bans.isIpDisabled(clientip)) { disconnectClient(0x0A, "Too many connections attempts from this IP. Try again later."); return false; } if(IOBan::getInstance()->isIpBanished(clientip)) { disconnectClient(0x0A, "Your IP is banished!"); return false; } uint32_t serverip = serverIPs[0].first; for(uint32_t i = 0; i < serverIPs.size(); i++) { if((serverIPs[i].first & serverIPs[i].second) == (clientip & serverIPs[i].second)) { serverip = serverIPs[i].first; break; } } Account account = IOLoginData::getInstance()->loadAccount(accountName); if(account.id == 0 || !passwordTest(password, account.password)) { g_bans.addLoginAttempt(clientip, false); disconnectClient(0x0A, "Account name or password is not correct."); return false; } g_bans.addLoginAttempt(clientip, true); OutputMessage_ptr output = OutputMessagePool::getInstance()->getOutputMessage(this, false); if(output) { TRACK_MESSAGE(output); //Update premium days g_game.updatePremium(account); //Add MOTD output->AddByte(0x14); std::ostringstream ss; ss << g_game.getMotdNum() << "\n" << g_config.getString(ConfigManager::MOTD); output->AddString(ss.str()); //Add char list output->AddByte(0x64); if(g_config.getBoolean(ConfigManager::ACCOUNT_MANAGER) && account.id != 1) { output->AddByte((uint8_t)account.charList.size() + 1); output->AddString("Account Manager"); output->AddString(g_config.getString(ConfigManager::SERVER_NAME)); output->AddU32(serverip); output->AddU16(g_config.getNumber(ConfigManager::GAME_PORT)); } else output->AddByte((uint8_t)account.charList.size()); std::list<std::string>::iterator it, end; for(it = account.charList.begin(), end = account.charList.end(); it != end; ++it) { output->AddString(*it); if(g_config.getBoolean(ConfigManager::ON_OR_OFF_CHARLIST)) { if(g_game.getPlayerByName((*it))) output->AddString("Online"); else output->AddString("Offline"); } else output->AddString(g_config.getString(ConfigManager::SERVER_NAME)); output->AddU32(serverip); output->AddU16(g_config.getNumber(ConfigManager::GAME_PORT)); } //Add premium days if(g_config.getBoolean(ConfigManager::FREE_PREMIUM)) output->AddU16(0xFFFF); //client displays free premium else output->AddU16(account.premiumDays); OutputMessagePool::getInstance()->send(output); } getConnection()->closeConnection(); return true; }
void mainLoader(int argc, char* argv[], ServiceManager* services) { //dispatcher thread g_game.setGameState(GAME_STATE_STARTUP); srand((unsigned int)OTSYS_TIME()); #ifdef _WIN32 SetConsoleTitle(STATUS_SERVER_NAME); #endif std::cout << STATUS_SERVER_NAME << " - Version " << STATUS_SERVER_VERSION << std::endl; std::cout << "Compilied on " << __DATE__ << ' ' << __TIME__ << " for arch "; #if defined(__amd64__) || defined(_M_X64) std::cout << "x64" << std::endl; #elif defined(__i386__) || defined(_M_IX86) || defined(_X86_) std::cout << "x86" << std::endl; #elif defined(__arm__) std::cout << "ARM" << std::endl; #elif defined(__mips__) std::cout << "MIPS" << std::endl; #else std::cout << "unk" << std::endl; #endif std::cout << std::endl; std::cout << "A server developed by " << STATUS_SERVER_DEVELOPERS << std::endl; std::cout << "Visit our forum for updates, support, and resources: http://otland.net/." << std::endl; std::cout << std::endl; // read global config std::cout << ">> Loading config" << std::endl; if (!g_config.load()) { startupErrorMessage("Unable to load config.lua!"); return; } #ifdef _WIN32 std::string defaultPriority = asLowerCaseString(g_config.getString(ConfigManager::DEFAULT_PRIORITY)); if (defaultPriority == "realtime") { SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS); } else if (defaultPriority == "high") { SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS); } else if (defaultPriority == "higher") { SetPriorityClass(GetCurrentProcess(), ABOVE_NORMAL_PRIORITY_CLASS); } std::ostringstream mutexName; mutexName << "forgottenserver_" << g_config.getNumber(ConfigManager::LOGIN_PORT); CreateMutex(nullptr, FALSE, mutexName.str().c_str()); if (GetLastError() == ERROR_ALREADY_EXISTS) { startupErrorMessage("Another instance of The Forgotten Server is already running with the same login port, please shut it down first or change ports for this one."); return; } #endif #ifdef __PROTOCOL_77__ //set RSA key const char* p("14299623962416399520070177382898895550795403345466153217470516082934737582776038882967213386204600674145392845853859217990626450972452084065728686565928113"); const char* q("7630979195970404721891201847792002125535401292779123937207447574596692788513647179235335529307251350570728407373705564708871762033017096809910315212884101"); g_RSA.setKey(p, q); #endif std::cout << ">> Establishing database connection..." << std::flush; Database* db = Database::getInstance(); if (!db->connect()) { startupErrorMessage("Failed to connect to database."); return; } std::cout << " MySQL " << db->getClientVersion() << std::endl; // run database manager std::cout << ">> Running database manager" << std::endl; DatabaseManager* dbManager = DatabaseManager::getInstance(); if (!dbManager->isDatabaseSetup()) { startupErrorMessage("The database you have specified in config.lua is empty, please import the schema to the database."); return; } dbManager->updateDatabase(); dbManager->checkTriggers(); dbManager->checkEncryption(); if (g_config.getBoolean(ConfigManager::OPTIMIZE_DATABASE) && !dbManager->optimizeTables()) { std::cout << "> No tables were optimized." << std::endl; } //load vocations std::cout << ">> Loading vocations" << std::endl; if (!g_vocations.loadFromXml()) { startupErrorMessage("Unable to load vocations!"); return; } //load commands std::cout << ">> Loading commands" << std::endl; if (!g_commands.loadFromXml()) { startupErrorMessage("Unable to load commands!"); return; } // load item data std::cout << ">> Loading items" << std::endl; if (Item::items.loadFromOtb("data/items/" + ITEMS_PATH + "/items.otb")) { startupErrorMessage("Unable to load items (OTB)!"); return; } if (!Item::items.loadFromXml()) { startupErrorMessage("Unable to load items (XML)!"); return; } std::cout << ">> Loading script systems" << std::endl; if (!ScriptingManager::getInstance()->loadScriptSystems()) { startupErrorMessage("Failed to load script systems"); return; } std::cout << ">> Loading monsters" << std::endl; if (!g_monsters.loadFromXml()) { startupErrorMessage("Unable to load monsters!"); return; } std::cout << ">> Loading experience stages" << std::endl; if (!g_game.loadExperienceStages()) { startupErrorMessage("Unable to load experience stages!"); return; } std::string passwordType = asLowerCaseString(g_config.getString(ConfigManager::PASSWORDTYPE)); if (passwordType == "sha1") { g_config.setNumber(ConfigManager::PASSWORD_TYPE, PASSWORD_TYPE_SHA1); std::cout << ">> Using SHA1 passwords" << std::endl; } else { g_config.setNumber(ConfigManager::PASSWORD_TYPE, PASSWORD_TYPE_PLAIN); std::cout << ">> Using plaintext passwords" << std::endl; } std::cout << ">> Checking world type... " << std::flush; std::string worldType = asLowerCaseString(g_config.getString(ConfigManager::WORLD_TYPE)); if (worldType == "pvp") { g_game.setWorldType(WORLD_TYPE_PVP); } else if (worldType == "no-pvp") { g_game.setWorldType(WORLD_TYPE_NO_PVP); } else if (worldType == "pvp-enforced") { g_game.setWorldType(WORLD_TYPE_PVP_ENFORCED); } else { std::cout << std::endl; std::ostringstream ss; ss << "> ERROR: Unknown world type: " << g_config.getString(ConfigManager::WORLD_TYPE) << ", valid world types are: pvp, no-pvp and pvp-enforced."; startupErrorMessage(ss.str()); return; } std::cout << asUpperCaseString(worldType) << std::endl; std::cout << ">> Loading map" << std::endl; if (!g_game.loadMap(g_config.getString(ConfigManager::MAP_NAME))) { startupErrorMessage("Failed to load map"); return; } std::cout << ">> Initializing gamestate" << std::endl; g_game.setGameState(GAME_STATE_INIT); // Tibia protocols services->add<ProtocolGame>(g_config.getNumber(ConfigManager::GAME_PORT)); services->add<ProtocolLogin>(g_config.getNumber(ConfigManager::LOGIN_PORT)); // OT protocols services->add<ProtocolStatus>(g_config.getNumber(ConfigManager::STATUS_PORT)); int32_t autoSaveEachMinutes = g_config.getNumber(ConfigManager::AUTO_SAVE_EACH_MINUTES); if (autoSaveEachMinutes > 0) { g_scheduler.addEvent(createSchedulerTask(autoSaveEachMinutes * 1000 * 60, boost::bind(&Game::autoSave, &g_game))); } if (g_config.getBoolean(ConfigManager::SERVERSAVE_ENABLED)) { int32_t serverSaveHour = g_config.getNumber(ConfigManager::SERVERSAVE_H); if (serverSaveHour >= 0 && serverSaveHour <= 24) { time_t timeNow = time(nullptr); tm* timeinfo = localtime(&timeNow); if (serverSaveHour == 0) { serverSaveHour = 23; } else { serverSaveHour--; } timeinfo->tm_hour = serverSaveHour; timeinfo->tm_min = 55; timeinfo->tm_sec = 0; double difference = difftime(mktime(timeinfo), timeNow); if (difference < 0) { difference += 86400; } g_scheduler.addEvent(createSchedulerTask(difference * 1000, boost::bind(&Game::prepareServerSave, &g_game))); } } Houses::getInstance().payHouses(); IOLoginData::getInstance()->updateHouseOwners(); g_npcs.reload(); std::cout << ">> Loaded all modules, server starting up..." << std::endl; std::pair<uint32_t, uint32_t> IpNetMask; IpNetMask.first = inet_addr("127.0.0.1"); IpNetMask.second = 0xFFFFFFFF; serverIPs.push_back(IpNetMask); char szHostName[128]; if (gethostname(szHostName, 128) == 0) { hostent* he = gethostbyname(szHostName); if (he) { unsigned char** addr = (unsigned char**)he->h_addr_list; while (addr[0] != nullptr) { IpNetMask.first = *(uint32_t*)(*addr); IpNetMask.second = 0xFFFFFFFF; serverIPs.push_back(IpNetMask); addr++; } } } std::string ip = g_config.getString(ConfigManager::IP); uint32_t resolvedIp = inet_addr(ip.c_str()); if (resolvedIp == INADDR_NONE) { struct hostent* he = gethostbyname(ip.c_str()); if (!he) { std::ostringstream ss; ss << "ERROR: Cannot resolve " << ip << "!" << std::endl; startupErrorMessage(ss.str()); return; } resolvedIp = *(uint32_t*)he->h_addr; } IpNetMask.first = resolvedIp; IpNetMask.second = 0; serverIPs.push_back(IpNetMask); #if !defined(WIN32) && !defined(__ROOT_PERMISSION__) if (getuid() == 0 || geteuid() == 0) { std::cout << "> WARNING: " << STATUS_SERVER_NAME << " has been executed as root user, it is recommended to execute is as a normal user." << std::endl; } #endif g_game.start(services); g_game.setGameState(GAME_STATE_NORMAL); g_loaderSignal.notify_all(); }
bool ProtocolLogin::parseFirstPacket(NetworkMessage& msg) { if(g_game.getGameState() == GAME_STATE_SHUTDOWN){ getConnection()->closeConnection(); return false; } uint32_t clientip = getConnection()->getIP(); /*uint16_t clientos =*/ msg.GetU16(); uint16_t version = msg.GetU16(); msg.SkipBytes(12); if(version <= 760){ disconnectClient(0x0A, STRING_CLIENT_VERSION); } if(!RSA_decrypt(g_otservRSA, msg)){ getConnection()->closeConnection(); return false; } uint32_t key[4]; key[0] = msg.GetU32(); key[1] = msg.GetU32(); key[2] = msg.GetU32(); key[3] = msg.GetU32(); enableXTEAEncryption(); setXTEAKey(key); uint32_t accnumber = msg.GetU32(); std::string password = msg.GetString(); if(!accnumber){ disconnectClient(0x0A, "You must enter your account number."); return false; } if(version < CLIENT_VERSION_MIN || version > CLIENT_VERSION_MAX){ disconnectClient(0x0A, STRING_CLIENT_VERSION); return false; } if(g_game.getGameState() == GAME_STATE_STARTUP){ disconnectClient(0x0A, "Gameworld is starting up. Please wait."); return false; } if(g_bans.isIpDisabled(clientip)){ disconnectClient(0x0A, "Too many connections attempts from this IP. Try again later."); return false; } if(g_bans.isIpBanished(clientip)){ disconnectClient(0x0A, "Your IP is banished!"); return false; } uint32_t serverip = serverIPs[0].first; for(uint32_t i = 0; i < serverIPs.size(); i++){ if((serverIPs[i].first & serverIPs[i].second) == (clientip & serverIPs[i].second)){ serverip = serverIPs[i].first; break; } } Account account = IOAccount::instance()->loadAccount(accnumber); if(!(accnumber != 0 && account.accnumber == accnumber && passwordTest(password, account.password))){ g_bans.addLoginAttempt(clientip, false); disconnectClient(0x0A, "Please enter a valid account number and password."); return false; } g_bans.addLoginAttempt(clientip, true); OutputMessage* output = OutputMessagePool::getInstance()->getOutputMessage(this, false); //Add MOTD std::stringstream motd; output->AddByte(0x14); motd << g_config.getNumber(ConfigManager::MOTD_NUM) << "\n"; motd << g_config.getString(ConfigManager::MOTD); output->AddString(motd.str()); //Add char list output->AddByte(0x64); output->AddByte((uint8_t)account.charList.size()); std::list<std::string>::iterator it; for(it = account.charList.begin(); it != account.charList.end(); it++){ output->AddString((*it)); output->AddString(g_config.getString(ConfigManager::WORLD_NAME)); output->AddU32(serverip); output->AddU16(g_config.getNumber(ConfigManager::PORT)); } //Add premium days output->AddU16(account.premiumDays);//output->AddU16(0); OutputMessagePool::getInstance()->send(output); getConnection()->closeConnection(); return true; }
bool ProtocolLogin::parseFirstPacket(NetworkMessage& msg) { if (g_game.getGameState() == GAME_STATE_SHUTDOWN) { getConnection()->closeConnection(); return false; } uint32_t clientip = getConnection()->getIP(); /*uint16_t clientos = */ msg.GetU16(); uint16_t version = msg.GetU16(); msg.SkipBytes(12); /* * Skipped bytes: * 12 bytes: dat, spr, pic signatures (4 bytes each) */ #ifdef __PROTOCOL_77__ if (!RSA_decrypt(msg)) { getConnection()->closeConnection(); return false; } uint32_t key[4]; key[0] = msg.GetU32(); key[1] = msg.GetU32(); key[2] = msg.GetU32(); key[3] = msg.GetU32(); enableXTEAEncryption(); setXTEAKey(key); #endif uint32_t accountName = msg.GetU32(); std::string password = msg.GetString(); if (version < CLIENT_VERSION_MIN || version > CLIENT_VERSION_MAX) { disconnectClient(0x0A, "Only clients with protocol " CLIENT_VERSION_STR " allowed!"); return false; } if (g_game.getGameState() == GAME_STATE_STARTUP) { disconnectClient(0x0A, "Gameworld is starting up. Please wait."); return false; } if (g_game.getGameState() == GAME_STATE_MAINTAIN) { disconnectClient(0x0A, "Gameworld is under maintenance. Please re-connect in a while."); return false; } BanInfo banInfo; if (IOBan::getInstance()->isIpBanned(clientip, banInfo)) { if (banInfo.reason.empty()) { banInfo.reason = "(none)"; } std::ostringstream ss; ss << "Your IP has been banned until " << formatDateShort(banInfo.expiresAt) << " by " << banInfo.bannedBy << ".\n\nReason specified:\n" << banInfo.reason; disconnectClient(0x0A, ss.str().c_str()); return false; } uint32_t serverip = serverIPs[0].first; for (uint32_t i = 0; i < serverIPs.size(); i++) { if ((serverIPs[i].first & serverIPs[i].second) == (clientip & serverIPs[i].second)) { serverip = serverIPs[i].first; break; } } if (!accountName) { disconnectClient(0x0A, "Invalid account id."); return false; } Account account; if (!IOLoginData::getInstance()->loginserverAuthentication(accountName, password, account)) { disconnectClient(0x0A, "Account id or password is not correct."); return false; } OutputMessage_ptr output = OutputMessagePool::getInstance()->getOutputMessage(this, false); if (output) { //Update premium days g_game.updatePremium(account); //Add MOTD output->AddByte(0x14); std::ostringstream ss; ss << g_game.getMotdNum() << "\n" << g_config.getString(ConfigManager::MOTD); output->AddString(ss.str()); //Add char list output->AddByte(0x64); output->AddByte((uint8_t)account.charList.size()); for (const std::string& characterName : account.charList) { output->AddString(characterName); if (g_config.getBoolean(ConfigManager::ON_OR_OFF_CHARLIST)) { if (g_game.getPlayerByName(characterName)) { output->AddString("Online"); } else { output->AddString("Offline"); } } else { output->AddString(g_config.getString(ConfigManager::SERVER_NAME)); } output->AddU32(serverip); output->AddU16(g_config.getNumber(ConfigManager::GAME_PORT)); } //Add premium days if (g_config.getBoolean(ConfigManager::FREE_PREMIUM)) { output->AddU16(0xFFFF); //client displays free premium } else { output->AddU16(account.premiumDays); } OutputMessagePool::getInstance()->send(output); } getConnection()->closeConnection(); return true; }