diff --git a/Jupiter b/Jupiter index 5620679..2d834a6 160000 --- a/Jupiter +++ b/Jupiter @@ -1 +1 @@ -Subproject commit 5620679e80b2489358d0bdcb90e03ca5f530dbde +Subproject commit 2d834a64a6123f968531f81d797f4a97be1f0cac diff --git a/Release/Bot.lib b/Release/Bot.lib index bebfc5f..0cbc005 100644 Binary files a/Release/Bot.lib and b/Release/Bot.lib differ diff --git a/Release/Plugins/RenX.Core.lib b/Release/Plugins/RenX.Core.lib index acae2df..ca155b3 100644 Binary files a/Release/Plugins/RenX.Core.lib and b/Release/Plugins/RenX.Core.lib differ diff --git a/RenX.Core/RenX_BanDatabase.cpp b/RenX.Core/RenX_BanDatabase.cpp index 382f5bf..5bb3050 100644 --- a/RenX.Core/RenX_BanDatabase.cpp +++ b/RenX.Core/RenX_BanDatabase.cpp @@ -165,6 +165,8 @@ void RenX::BanDatabase::add(RenX::Server *server, const RenX::PlayerInfo *player entry->steamid = player->steamid; entry->ip = player->ip32; entry->prefix_length = 32U; + if (player->rdns_thread.joinable()) + player->rdns_thread.join(); entry->rdns = player->rdns; entry->name = player->name; entry->banner = banner; diff --git a/RenX.Core/RenX_PlayerInfo.h b/RenX.Core/RenX_PlayerInfo.h index a159f04..006a0dd 100644 --- a/RenX.Core/RenX_PlayerInfo.h +++ b/RenX.Core/RenX_PlayerInfo.h @@ -25,6 +25,9 @@ */ #include +#include +#include +#include "Jupiter/Reference_String.h" #include "Jupiter/String.h" #include "Jupiter/INIFile.h" #include "RenX.h" @@ -48,11 +51,12 @@ namespace RenX // TODO: Add backpack Jupiter::StringS name; Jupiter::StringS ip; - Jupiter::StringS rdns; Jupiter::StringS adminType; Jupiter::StringS uuid; Jupiter::StringS character; Jupiter::StringS vehicle; + Jupiter::StringS rdns; + std::mutex rdns_mutex; uint64_t steamid = 0; uint32_t ip32 = 0; uint16_t ban_flags = 0; @@ -61,6 +65,7 @@ namespace RenX int id = 0; bool isBot = false; bool is_dev = false; + bool rdns_resolved = false; unsigned short ping = 0; double score = 0.0f; double credits = 0.0f; @@ -85,10 +90,12 @@ namespace RenX mutable Jupiter::StringS gamePrefix; mutable Jupiter::StringS formatNamePrefix; + mutable std::thread rdns_thread; mutable int access = 0; mutable Jupiter::INIFile varData; // This will be replaced later with a more dedicated type. }; + static Jupiter::ReferenceString rdns_pending = STRING_LITERAL_AS_REFERENCE("RDNS_PENDING"); } /** Re-enable warnings */ diff --git a/RenX.Core/RenX_Plugin.cpp b/RenX.Core/RenX_Plugin.cpp index 5d51432..fea2447 100644 --- a/RenX.Core/RenX_Plugin.cpp +++ b/RenX.Core/RenX_Plugin.cpp @@ -61,6 +61,11 @@ void RenX::Plugin::RenX_OnPlayerUUIDChange(Server *, const RenX::PlayerInfo *, c return; } +void RenX::Plugin::RenX_OnPlayerRDNS(Server *, const RenX::PlayerInfo *) +{ + return; +} + void RenX::Plugin::RenX_OnServerCreate(Server *) { return; diff --git a/RenX.Core/RenX_Plugin.h b/RenX.Core/RenX_Plugin.h index 595b3b7..3ee54d8 100644 --- a/RenX.Core/RenX_Plugin.h +++ b/RenX.Core/RenX_Plugin.h @@ -48,6 +48,7 @@ namespace RenX virtual void RenX_OnPlayerCreate(Server *server, const PlayerInfo *player); virtual void RenX_OnPlayerDelete(Server *server, const PlayerInfo *player); virtual void RenX_OnPlayerUUIDChange(Server *server, const PlayerInfo *player, const Jupiter::ReadableString &newUUID); + virtual void RenX_OnPlayerRDNS(Server *server, const PlayerInfo *player); virtual void RenX_OnServerCreate(Server *server); virtual void RenX_OnServerDisconnect(Server *server, RenX::DisconnectReason reason); virtual bool RenX_OnBan(Server *server, const PlayerInfo *player, Jupiter::StringType &data); diff --git a/RenX.Core/RenX_Server.cpp b/RenX.Core/RenX_Server.cpp index d69a0d3..911874c 100644 --- a/RenX.Core/RenX_Server.cpp +++ b/RenX.Core/RenX_Server.cpp @@ -59,9 +59,40 @@ int RenX::Server::think() } else { + auto cycle_player_rdns = [this]() // Cycles through any pending RDNS resolutions, and fires events as necessary. + { + if (this->player_rdns_resolutions_pending != 0) + { + RenX::PlayerInfo *player; + Jupiter::ArrayList &xPlugins = *RenX::getCore()->getPlugins(); + for (Jupiter::DLList::Node *node = this->players.getNode(0); node != nullptr; node = node->next) + { + player = node->data; + if (player->rdns_thread.joinable() && player->rdns_mutex.try_lock()) // RDNS event hasn't fired AND RDNS value has been resolved + { + player->rdns_mutex.unlock(); + player->rdns_thread.join(); + --this->player_rdns_resolutions_pending; + + // Check for bans + this->banCheck(player); + + // Fire RDNS resolved event + for (size_t index = 0; index < xPlugins.size(); ++index) + xPlugins.get(++index)->RenX_OnPlayerRDNS(this, player); + + if (this->player_rdns_resolutions_pending == 0) // No more resolutions pending + return; + } + } + } + }; + // Connected and fine - if (RenX::Server::sock.recv() > 0) + if (RenX::Server::sock.recv() > 0) // Data received { + cycle_player_rdns(); + Jupiter::ReadableString::TokenizeResult result = Jupiter::ReferenceString::tokenize(RenX::Server::sock.getBuffer(), '\n'); if (result.token_count != 0) { @@ -77,8 +108,10 @@ int RenX::Server::think() } } } - else if (Jupiter::Socket::getLastError() == 10035) + else if (Jupiter::Socket::getLastError() == 10035) // Operation would block (no new data) { + cycle_player_rdns(); + if (RenX::Server::awaitingPong == false && std::chrono::steady_clock::now() - RenX::Server::lastActivity >= RenX::Server::pingRate) { RenX::Server::lastActivity = std::chrono::steady_clock::now(); @@ -464,7 +497,7 @@ void RenX::Server::banCheck(RenX::PlayerInfo *player) if ((this->localSteamBan && entry->steamid != 0 && entry->steamid == player->steamid) || (this->localIPBan && entry->ip != 0 && (entry->ip & netmask) == (player->ip32 & netmask)) - || (this->localRDNSBan && entry->rdns.isNotEmpty() && entry->is_rdns_ban() && player->rdns.match(entry->rdns)) + || (this->localRDNSBan && entry->rdns.isNotEmpty() && entry->is_rdns_ban() && player->rdns_thread.joinable() == false && player->rdns.match(entry->rdns)) || (this->localNameBan && entry->name.isNotEmpty() && entry->name.equalsi(player->name))) { player->ban_flags |= entry->flags; @@ -625,6 +658,13 @@ bool RenX::Server::removePlayer(int id) xPlugins.get(i)->RenX_OnPlayerDelete(this, p); if (p->isBot) --this->bot_count; + + if (p->rdns_thread.joinable()) // Close the RDNS thread, if one exists + { + --this->player_rdns_resolutions_pending; + p->rdns_thread.join(); + } + delete p; return true; } @@ -1151,6 +1191,14 @@ void RenX::Server::sendLogChan(const Jupiter::ReadableString &msg) const } } +void resolve_rdns(RenX::PlayerInfo *player) +{ + player->rdns_mutex.lock(); + char *resolved = Jupiter::Socket::resolveHostname_alloc(Jupiter::CStringS(player->ip).c_str(), 0); + player->rdns.capture(resolved, strlen(resolved)); + player->rdns_mutex.unlock(); +} + #define PARSE_PLAYER_DATA_P(DATA) \ Jupiter::ReferenceString name; \ TeamType team; \ @@ -1277,7 +1325,10 @@ void RenX::Server::processLine(const Jupiter::ReadableString &line) r->ip = ip; r->ip32 = Jupiter::Socket::pton4(Jupiter::CStringS(r->ip).c_str()); if (this->resolvesRDNS() && r->ip32 != 0) - r->rdns = Jupiter::Socket::resolveHostname(Jupiter::CStringS(r->ip).c_str(), 0); + { + r->rdns_thread = std::thread(resolve_rdns, r); + ++this->player_rdns_resolutions_pending; + } r->steamid = steamid; if (r->isBot = isBot) r->formatNamePrefix = IRCCOLOR "05[B]"; @@ -1306,7 +1357,11 @@ void RenX::Server::processLine(const Jupiter::ReadableString &line) { r->ip = ip; r->ip32 = Jupiter::Socket::pton4(Jupiter::CStringS(r->ip).c_str()); - r->rdns = Jupiter::Socket::resolveHostname(Jupiter::CStringS(r->ip).c_str(), 0); + if (this->resolvesRDNS()) + { + r->rdns_thread = std::thread(resolve_rdns, r); + ++this->player_rdns_resolutions_pending; + } recalcUUID = true; } if (r->steamid == 0U && steamid != 0U) @@ -3056,9 +3111,17 @@ void RenX::Server::wipeData() player = RenX::Server::players.remove(0U); for (size_t index = 0; index < xPlugins.size(); ++index) xPlugins.get(index)->RenX_OnPlayerDelete(this, player); + + if (player->rdns_thread.joinable()) // Close the RDNS thread, if one exists + { + --this->player_rdns_resolutions_pending; + player->rdns_thread.join(); + } + delete player; } RenX::Server::bot_count = 0; + RenX::Server::player_rdns_resolutions_pending = 0; RenX::Server::buildings.emptyAndDelete(); RenX::Server::mutators.emptyAndDelete(); RenX::Server::maps.emptyAndDelete(); diff --git a/RenX.Core/RenX_Server.h b/RenX.Core/RenX_Server.h index 41e1339..ad90fd7 100644 --- a/RenX.Core/RenX_Server.h +++ b/RenX.Core/RenX_Server.h @@ -975,6 +975,7 @@ namespace RenX int mineLimit = 0; int timeLimit = 0; size_t bot_count = 0; + size_t player_rdns_resolutions_pending = 0; unsigned int rconVersion = 0; double crateRespawnAfterPickup = 0.0; uuid_func calc_uuid; diff --git a/RenX.Core/RenX_Tags.cpp b/RenX.Core/RenX_Tags.cpp index a09d7ab..0669a29 100644 --- a/RenX.Core/RenX_Tags.cpp +++ b/RenX.Core/RenX_Tags.cpp @@ -499,7 +499,14 @@ void TagsImp::processTags(Jupiter::StringType &msg, const RenX::Server *server, PROCESS_TAG(this->INTERNAL_NAME_TAG, RenX::getFormattedPlayerName(player)); PROCESS_TAG(this->INTERNAL_RAW_NAME_TAG, player->name); PROCESS_TAG(this->INTERNAL_IP_TAG, player->ip); - PROCESS_TAG(this->INTERNAL_RDNS_TAG, player->rdns); + if (player->rdns_thread.joinable()) + { + PROCESS_TAG(this->INTERNAL_RDNS_TAG, RenX::rdns_pending); + } + else + { + PROCESS_TAG(this->INTERNAL_RDNS_TAG, player->rdns); + } PROCESS_TAG(this->INTERNAL_UUID_TAG, player->uuid); PROCESS_TAG(this->INTERNAL_ID_TAG, Jupiter::StringS::Format("%d", player->id)); PROCESS_TAG(this->INTERNAL_CHARACTER_TAG, RenX::translateName(player->character)); @@ -537,7 +544,14 @@ void TagsImp::processTags(Jupiter::StringType &msg, const RenX::Server *server, PROCESS_TAG(this->INTERNAL_VICTIM_NAME_TAG, RenX::getFormattedPlayerName(victim)); PROCESS_TAG(this->INTERNAL_VICTIM_RAW_NAME_TAG, victim->name); PROCESS_TAG(this->INTERNAL_VICTIM_IP_TAG, victim->ip); - PROCESS_TAG(this->INTERNAL_VICTIM_RDNS_TAG, victim->rdns); + if (victim->rdns_thread.joinable()) + { + PROCESS_TAG(this->INTERNAL_VICTIM_RDNS_TAG, RenX::rdns_pending); + } + else + { + PROCESS_TAG(this->INTERNAL_VICTIM_RDNS_TAG, victim->rdns); + } PROCESS_TAG(this->INTERNAL_VICTIM_UUID_TAG, victim->uuid); PROCESS_TAG(this->INTERNAL_VICTIM_ID_TAG, Jupiter::StringS::Format("%d", victim->id)); PROCESS_TAG(this->INTERNAL_VICTIM_CHARACTER_TAG, RenX::translateName(victim->character)); diff --git a/RenX.Logging/RenX_Logging.cpp b/RenX.Logging/RenX_Logging.cpp index 95edaef..bfa730e 100644 --- a/RenX.Logging/RenX_Logging.cpp +++ b/RenX.Logging/RenX_Logging.cpp @@ -30,6 +30,7 @@ using namespace Jupiter::literals; void RenX_LoggingPlugin::init() { RenX_LoggingPlugin::muteOwnExecute = Jupiter::IRC::Client::Config->getBool(RenX_LoggingPlugin::getName(), "MuteOwnExecute"_jrs, true); + RenX_LoggingPlugin::playerRDNSPublic = Jupiter::IRC::Client::Config->getBool(RenX_LoggingPlugin::getName(), "PlayerRDNSPublic"_jrs, false); RenX_LoggingPlugin::joinPublic = Jupiter::IRC::Client::Config->getBool(RenX_LoggingPlugin::getName(), "JoinPublic"_jrs, true); RenX_LoggingPlugin::partPublic = Jupiter::IRC::Client::Config->getBool(RenX_LoggingPlugin::getName(), "PartPublic"_jrs, true); RenX_LoggingPlugin::kickPublic = Jupiter::IRC::Client::Config->getBool(RenX_LoggingPlugin::getName(), "KickPublic"_jrs, true); @@ -107,14 +108,17 @@ void RenX_LoggingPlugin::init() RenX_LoggingPlugin::otherPublic = Jupiter::IRC::Client::Config->getBool(RenX_LoggingPlugin::getName(), "OtherPublic"_jrs, false); /** Event formats */ + RenX_LoggingPlugin::playerRDNSFmt = Jupiter::IRC::Client::Config->get(this->getName(), "PlayerRDNSFormat"_jrs, + Jupiter::StringS::Format(IRCCOLOR "05[RDNS] " IRCBOLD "%.*s" IRCNORMAL "'s hostname is " IRCBOLD "%.*s", RenX::tags->nameTag.size(), RenX::tags->nameTag.ptr(), RenX::tags->rdnsTag.size(), RenX::tags->rdnsTag.ptr())); + RenX_LoggingPlugin::joinPublicFmt = Jupiter::IRC::Client::Config->get(this->getName(), "JoinPublicFormat"_jrs, Jupiter::StringS::Format(IRCCOLOR "12[Join] " IRCBOLD "%.*s" IRCBOLD " joined the game fighting for the %.*s!", RenX::tags->nameTag.size(), RenX::tags->nameTag.ptr(), RenX::tags->teamLongTag.size(), RenX::tags->teamLongTag.ptr())); RenX_LoggingPlugin::joinAdminFmt = Jupiter::IRC::Client::Config->get(this->getName(), "JoinAdminFormat"_jrs, - Jupiter::StringS::Format(IRCCOLOR "12[Join] " IRCBOLD "%.*s" IRCBOLD " joined the game fighting for the %.*s from " IRCBOLD "%.*s" IRCBOLD " using Steam ID " IRCBOLD "%.*s" IRCBOLD ". Their hostname is: " IRCBOLD "%.*s", RenX::tags->nameTag.size(), RenX::tags->nameTag.ptr(), RenX::tags->teamLongTag.size(), RenX::tags->teamLongTag.ptr(), RenX::tags->ipTag.size(), RenX::tags->ipTag.ptr(), RenX::tags->steamTag.size(), RenX::tags->steamTag.ptr(), RenX::tags->rdnsTag.size(), RenX::tags->rdnsTag.ptr())); + Jupiter::StringS::Format(IRCCOLOR "12[Join] " IRCBOLD "%.*s" IRCBOLD " joined the game fighting for the %.*s from " IRCBOLD "%.*s" IRCBOLD " using Steam ID " IRCBOLD "%.*s" IRCBOLD ".", RenX::tags->nameTag.size(), RenX::tags->nameTag.ptr(), RenX::tags->teamLongTag.size(), RenX::tags->teamLongTag.ptr(), RenX::tags->ipTag.size(), RenX::tags->ipTag.ptr(), RenX::tags->steamTag.size(), RenX::tags->steamTag.ptr())); RenX_LoggingPlugin::joinNoSteamAdminFmt = Jupiter::IRC::Client::Config->get(this->getName(), "JoinNoSteamAdminFormat"_jrs, - Jupiter::StringS::Format(IRCCOLOR "12[Join] " IRCBOLD "%.*s" IRCBOLD " joined the game fighting for the %.*s from " IRCBOLD "%.*s" IRCBOLD ", but is " IRCBOLD "not" IRCBOLD " using Steam. Their hostname is: " IRCBOLD "%.*s", RenX::tags->nameTag.size(), RenX::tags->nameTag.ptr(), RenX::tags->teamLongTag.size(), RenX::tags->teamLongTag.ptr(), RenX::tags->ipTag.size(), RenX::tags->ipTag.ptr(), RenX::tags->rdnsTag.size(), RenX::tags->rdnsTag.ptr())); + Jupiter::StringS::Format(IRCCOLOR "12[Join] " IRCBOLD "%.*s" IRCBOLD " joined the game fighting for the %.*s from " IRCBOLD "%.*s" IRCBOLD ", but is " IRCBOLD "not" IRCBOLD " using Steam.", RenX::tags->nameTag.size(), RenX::tags->nameTag.ptr(), RenX::tags->teamLongTag.size(), RenX::tags->teamLongTag.ptr(), RenX::tags->ipTag.size(), RenX::tags->ipTag.ptr())); RenX_LoggingPlugin::partFmt = Jupiter::IRC::Client::Config->get(this->getName(), "PartFormat"_jrs, Jupiter::StringS::Format(IRCCOLOR "12[Part] " IRCBOLD "%.*s" IRCBOLD " left the %.*s.", RenX::tags->nameTag.size(), RenX::tags->nameTag.ptr(), RenX::tags->teamLongTag.size(), RenX::tags->teamLongTag.ptr())); @@ -416,6 +420,7 @@ void RenX_LoggingPlugin::init() Jupiter::StringS::Format(IRCCOLOR "06[Other]" IRCCOLOR " %.*s", RenX::tags->messageTag.size(), RenX::tags->messageTag.ptr())); /** Sanitize tags */ + RenX::sanitizeTags(playerRDNSFmt); RenX::sanitizeTags(joinPublicFmt); RenX::sanitizeTags(joinAdminFmt); RenX::sanitizeTags(joinNoSteamAdminFmt); @@ -523,6 +528,22 @@ void RenX_LoggingPlugin::init() typedef void(RenX::Server::*logFuncType)(const Jupiter::ReadableString &msg) const; +void RenX_LoggingPlugin::RenX_OnPlayerRDNS(RenX::Server *server, const RenX::PlayerInfo *player) +{ + logFuncType func; + if (RenX_LoggingPlugin::playerRDNSPublic) + func = &RenX::Server::sendLogChan; + else + func = &RenX::Server::sendAdmChan; + + Jupiter::String msg = this->playerRDNSFmt; + if (msg.isNotEmpty()) + { + RenX::processTags(msg, server, player); + (server->*func)(msg); + } +} + void RenX_LoggingPlugin::RenX_OnJoin(RenX::Server *server, const RenX::PlayerInfo *player) { Jupiter::String msg; diff --git a/RenX.Logging/RenX_Logging.h b/RenX.Logging/RenX_Logging.h index 3d124f5..0e2088e 100644 --- a/RenX.Logging/RenX_Logging.h +++ b/RenX.Logging/RenX_Logging.h @@ -25,6 +25,8 @@ class RenX_LoggingPlugin : public RenX::Plugin { public: // RenX::Plugin + void RenX_OnPlayerRDNS(RenX::Server *server, const RenX::PlayerInfo *player) override; + void RenX_OnJoin(RenX::Server *server, const RenX::PlayerInfo *player) override; void RenX_OnPart(RenX::Server *server, const RenX::PlayerInfo *player) override; void RenX_OnKick(RenX::Server *server, const RenX::PlayerInfo *player, const Jupiter::ReadableString &reason) override; @@ -135,6 +137,7 @@ private: STRING_LITERAL_AS_NAMED_REFERENCE(name, "RenX.Logging"); unsigned int muteOwnExecute : 1; + unsigned int playerRDNSPublic : 1; unsigned int joinPublic : 1; unsigned int partPublic : 1; unsigned int kickPublic : 1; @@ -212,6 +215,7 @@ private: unsigned int otherPublic : 1; /** Event formats */ + Jupiter::String playerRDNSFmt; Jupiter::StringS joinPublicFmt, joinAdminFmt, joinNoSteamAdminFmt; Jupiter::StringS partFmt; Jupiter::StringS kickFmt;