diff --git a/Release/Plugins/RenX.Core.lib b/Release/Plugins/RenX.Core.lib index fb64588..5bdefac 100644 Binary files a/Release/Plugins/RenX.Core.lib and b/Release/Plugins/RenX.Core.lib differ diff --git a/RenX.Commands/RenX_Commands.cpp b/RenX.Commands/RenX_Commands.cpp index dc7bebb..563c5ea 100644 --- a/RenX.Commands/RenX_Commands.cpp +++ b/RenX.Commands/RenX_Commands.cpp @@ -1167,11 +1167,13 @@ void BanSearchIRCCommand::trigger(IRC_Bot *source, const Jupiter::ReadableString const Jupiter::ReadableString &banner = entry->varData.get(pluginInstance.getName()); strftime(timeStr, sizeof(timeStr), "%b %d %Y; Time: %H:%M:%S", localtime(&(entry->timestamp))); - if ((entry->flags & 0x7F) == 0) + if ((entry->flags & 0x7FFF) == 0) types = " NULL;"_jrs; else { types.erase(); + if (entry->is_rdns_ban()) + types += " rdns"_jrs; if (entry->is_type_game()) types += " game"_jrs; if (entry->is_type_chat()) @@ -1979,6 +1981,167 @@ const Jupiter::ReadableString &KickBanIRCCommand::getHelp(const Jupiter::Readabl IRC_COMMAND_INIT(KickBanIRCCommand) +// AddBan IRC Command + +#define ADDBAN_WHITESPACE " \t=" + +void AddBanIRCCommand::create() +{ + this->addTrigger("addban"_jrs); + this->addTrigger("banadd"_jrs); + this->setAccessLevel(4); +} + +void AddBanIRCCommand::trigger(IRC_Bot *source, const Jupiter::ReadableString &channel, const Jupiter::ReadableString &nick, const Jupiter::ReadableString ¶meters) +{ + if (parameters.isNotEmpty()) + { + Jupiter::IRC::Client::Channel *chan = source->getChannel(channel); + if (chan != nullptr) + { + size_t words = parameters.wordCount(ADDBAN_WHITESPACE); + if (words == 0) + source->sendNotice(nick, STRING_LITERAL_AS_REFERENCE("Error: Too Few Parameters. Syntax: KickBan [Reason]")); + else if (words == 1) + KickBanIRCCommand_instance.trigger(source, channel, nick, parameters); + else + { + size_t index = 0; + Jupiter::ReferenceString name; + Jupiter::CStringS ip_str; + uint32_t ip = 0U; + uint8_t prefix_length = 32U; + uint64_t steamid = 0U; + Jupiter::StringS rdns; + Jupiter::String banner = nick + "@IRC"_jrs; + Jupiter::ReferenceString reason = "No reason"_jrs; + time_t duration = 0; + uint16_t flags = 0; + + Jupiter::ReferenceString word; + while (index != words) + { + word = Jupiter::ReferenceString::getWord(parameters, index++, ADDBAN_WHITESPACE); + + if (word.equalsi("Name"_jrs) || word.equalsi("Nick"_jrs) || word.equalsi("Nickname"_jrs) || word.equalsi("Username"_jrs)) + { + if (index == words) + { + source->sendNotice(nick, "ERROR: No value specified for token: "_jrs + word); + return; + } + + name = Jupiter::ReferenceString::getWord(parameters, index++, ADDBAN_WHITESPACE); + } + else if (word.equalsi("IP"_jrs) || word.equalsi("IPAddress"_jrs) || word.equalsi("Address"_jrs)) + { + if (index == words) + { + source->sendNotice(nick, "ERROR: No value specified for token: "_jrs + word); + return; + } + + ip_str = Jupiter::ReferenceString::getWord(parameters, index++, ADDBAN_WHITESPACE); + } + else if (word.equalsi("Steam"_jrs) || word.equalsi("SteamID"_jrs)) + { + if (index == words) + { + source->sendNotice(nick, "ERROR: No value specified for token: "_jrs + word); + return; + } + + steamid = Jupiter::ReferenceString::getWord(parameters, index++, ADDBAN_WHITESPACE).asUnsignedLongLong(); + } + else if (word.equalsi("RDNS"_jrs) || word.equalsi("DNS"_jrs)) + { + if (index == words) + { + source->sendNotice(nick, "ERROR: No value specified for token: "_jrs + word); + return; + } + + rdns = Jupiter::ReferenceString::getWord(parameters, index++, ADDBAN_WHITESPACE); + } + else if (word.equalsi("Reason"_jrs)) + { + if (index == words) + { + source->sendNotice(nick, "ERROR: No value specified for token: "_jrs + word); + return; + } + + reason = Jupiter::ReferenceString::gotoWord(parameters, index++, ADDBAN_WHITESPACE); + break; + } + else if (word.equalsi("Duration"_jrs) || word.equalsi("Length"_jrs) || word.equalsi("Time"_jrs)) + { + if (index == words) + { + source->sendNotice(nick, "ERROR: No value specified for token: "_jrs + word); + return; + } + + duration = Jupiter::ReferenceString::getWord(parameters, index++, ADDBAN_WHITESPACE).asUnsignedLongLong(); + } + else if (word.equalsi("Game"_jrs)) + flags |= RenX::BanDatabase::Entry::FLAG_TYPE_GAME; + else if (word.equalsi("Chat"_jrs)) + flags |= RenX::BanDatabase::Entry::FLAG_TYPE_CHAT; + else if (word.equalsi("Bot"_jrs) || word.equalsi("Command"_jrs)) + flags |= RenX::BanDatabase::Entry::FLAG_TYPE_BOT; + else if (word.equalsi("Vote"_jrs) || word.equalsi("Poll"_jrs)) + flags |= RenX::BanDatabase::Entry::FLAG_TYPE_VOTE; + else if (word.equalsi("Mine"_jrs)) + flags |= RenX::BanDatabase::Entry::FLAG_TYPE_MINE; + else if (word.equalsi("Ladder"_jrs)) + flags |= RenX::BanDatabase::Entry::FLAG_TYPE_LADDER; + else if (word.equalsi("Alert"_jrs)) + flags |= RenX::BanDatabase::Entry::FLAG_TYPE_ALERT; + else + { + source->sendNotice(nick, "ERROR: Unknown token: "_jrs + word); + return; + } + } + + // Default to Game type + if (flags == 0) + flags = RenX::BanDatabase::Entry::FLAG_TYPE_GAME; + + index = ip_str.find('/'); + if (index != JUPITER_INVALID_INDEX) + { + prefix_length = Jupiter::ReferenceString::substring(ip_str, index + 1).asUnsignedInt(); + if (prefix_length == 0) + prefix_length = 32U; + ip_str.set(ip_str.ptr(), index); + } + ip = Jupiter::Socket::pton4(ip_str.c_str()); + + if (rdns.isEmpty()) + Jupiter::Socket::resolveHostname(ip_str.c_str(), 0); + else + flags |= RenX::BanDatabase::Entry::FLAG_USE_RDNS; + + RenX::banDatabase->add(name, ip, prefix_length, steamid, rdns, banner, reason, duration); + } + } + } + else source->sendNotice(nick, STRING_LITERAL_AS_REFERENCE("Error: Too Few Parameters. Syntax: AddBan [...]")); +} + +const Jupiter::ReadableString &AddBanIRCCommand::getHelp(const Jupiter::ReadableString ¶meters) +{ + static STRING_LITERAL_AS_NAMED_REFERENCE(defaultHelp, "Adds a ban entry to the ban list. Use \"help addban keys\" for a list of input keys. Syntax: AddBan [ ...]"); + static STRING_LITERAL_AS_NAMED_REFERENCE(keyHelp, "Valueless keys (flags): Game, Chat, Bot, Vote, Mine, Ladder, Alert; Value-paired keys: Name, IP, Steam, RDNS, Duration, Reason (MUST BE LAST)"); + if (parameters.isNotEmpty() && parameters.equalsi("keys"_jrs)) + return keyHelp; + return defaultHelp; +} + +IRC_COMMAND_INIT(AddBanIRCCommand) + // UnBan IRC Command void UnBanIRCCommand::create() diff --git a/RenX.Commands/RenX_Commands.h b/RenX.Commands/RenX_Commands.h index a790a1c..b8fb10d 100644 --- a/RenX.Commands/RenX_Commands.h +++ b/RenX.Commands/RenX_Commands.h @@ -85,6 +85,7 @@ GENERIC_IRC_COMMAND(MineBanIRCCommand) GENERIC_IRC_COMMAND(KickIRCCommand) GENERIC_IRC_COMMAND(TempBanIRCCommand) GENERIC_IRC_COMMAND(KickBanIRCCommand) +GENERIC_IRC_COMMAND(AddBanIRCCommand) GENERIC_IRC_COMMAND(UnBanIRCCommand) GENERIC_IRC_COMMAND(AddBotsIRCCommand) GENERIC_IRC_COMMAND(KillBotsIRCCommand) diff --git a/RenX.Core/RenX_BanDatabase.cpp b/RenX.Core/RenX_BanDatabase.cpp index 851a209..3c71f20 100644 --- a/RenX.Core/RenX_BanDatabase.cpp +++ b/RenX.Core/RenX_BanDatabase.cpp @@ -39,7 +39,7 @@ void RenX::BanDatabase::process_data(Jupiter::DataBuffer &buffer, FILE *file, fp entry->pos = pos; // Read data from buffer to entry - entry->flags = buffer.pop(); + entry->flags = buffer.pop(); entry->timestamp = buffer.pop(); entry->length = buffer.pop(); entry->steamid = buffer.pop(); @@ -138,7 +138,7 @@ void RenX::BanDatabase::write(RenX::BanDatabase::Entry *entry, FILE *file) buffer.push_to(file); } -void RenX::BanDatabase::add(RenX::Server *server, const RenX::PlayerInfo *player, const Jupiter::ReadableString &banner, const Jupiter::ReadableString &reason, time_t length, uint8_t flags) +void RenX::BanDatabase::add(RenX::Server *server, const RenX::PlayerInfo *player, const Jupiter::ReadableString &banner, const Jupiter::ReadableString &reason, time_t length, uint16_t flags) { Entry *entry = new Entry(); entry->set_active(); @@ -164,7 +164,7 @@ void RenX::BanDatabase::add(RenX::Server *server, const RenX::PlayerInfo *player RenX::BanDatabase::write(entry); } -void RenX::BanDatabase::add(const Jupiter::ReadableString &name, uint32_t ip, uint8_t prefix_length, uint64_t steamid, const Jupiter::ReadableString &rdns, Jupiter::ReadableString &banner, Jupiter::ReadableString &reason, time_t length, uint8_t flags) +void RenX::BanDatabase::add(const Jupiter::ReadableString &name, uint32_t ip, uint8_t prefix_length, uint64_t steamid, const Jupiter::ReadableString &rdns, Jupiter::ReadableString &banner, Jupiter::ReadableString &reason, time_t length, uint16_t flags) { Entry *entry = new Entry(); entry->set_active(); diff --git a/RenX.Core/RenX_BanDatabase.h b/RenX.Core/RenX_BanDatabase.h index a82b079..744262e 100644 --- a/RenX.Core/RenX_BanDatabase.h +++ b/RenX.Core/RenX_BanDatabase.h @@ -80,7 +80,7 @@ namespace RenX struct RENX_API Entry { fpos_t pos; /** Position of the entry in the database */ - uint8_t flags /** Flags affecting this ban entry (0 = Active, 1 = Game, 2 = Chat, 3 = Command, 4 = Vote, 5 = Mine, 6 = Ladder, 7 = Alert Mods) */ = 0x00; + uint16_t flags /** Flags affecting this ban entry (See below for flags) */ = 0x00; time_t timestamp /** Time the ban was created */; time_t length /** Duration of the ban; 0 if permanent */; uint64_t steamid /** SteamID of the banned player */; @@ -92,16 +92,19 @@ namespace RenX Jupiter::StringS reason /** Reason the player was banned */; Jupiter::INIFile::Section varData; /** Variable entry data */ - static const uint8_t FLAG_ACTIVE = 0x80; - static const uint8_t FLAG_TYPE_GAME = 0x40; - static const uint8_t FLAG_TYPE_CHAT = 0x20; - static const uint8_t FLAG_TYPE_BOT = 0x10; - static const uint8_t FLAG_TYPE_VOTE = 0x08; - static const uint8_t FLAG_TYPE_MINE = 0x04; - static const uint8_t FLAG_TYPE_LADDER = 0x02; - static const uint8_t FLAG_TYPE_ALERT = 0x01; + static const uint16_t FLAG_ACTIVE = 0x8000U; + static const uint16_t FLAG_USE_RDNS = 0x4000U; + static const uint16_t FLAG_TYPE_GAME = 0x0080U; + static const uint16_t FLAG_TYPE_CHAT = 0x0040U; + static const uint16_t FLAG_TYPE_BOT = 0x0020U; + static const uint16_t FLAG_TYPE_VOTE = 0x0010U; + static const uint16_t FLAG_TYPE_MINE = 0x0008U; + static const uint16_t FLAG_TYPE_LADDER = 0x0004U; + static const uint16_t FLAG_TYPE_ALERT = 0x0002U; + inline bool is_active() { return (flags & FLAG_ACTIVE) != 0; }; + inline bool is_rdns_ban() { return (flags & FLAG_USE_RDNS) != 0; }; inline bool is_type_game() { return (flags & FLAG_TYPE_GAME) != 0; }; inline bool is_type_chat() { return (flags & FLAG_TYPE_CHAT) != 0; }; inline bool is_type_bot() { return (flags & FLAG_TYPE_BOT) != 0; }; @@ -109,9 +112,9 @@ namespace RenX inline bool is_type_mine() { return (flags & FLAG_TYPE_MINE) != 0; }; inline bool is_type_ladder() { return (flags & FLAG_TYPE_LADDER) != 0; }; inline bool is_type_alert() { return (flags & FLAG_TYPE_ALERT) != 0; }; - inline bool is_type_global() { return ~(flags | 0x01) == 0; }; inline void set_active() { flags |= FLAG_ACTIVE; }; + inline void set_rdns_ban() { flags |= FLAG_USE_RDNS; } inline void set_type_game() { flags |= FLAG_TYPE_GAME; }; inline void set_type_chat() { flags |= FLAG_TYPE_CHAT; }; inline void set_type_bot() { flags |= FLAG_TYPE_BOT; }; @@ -119,9 +122,10 @@ namespace RenX inline void set_type_mine() { flags |= FLAG_TYPE_MINE; }; inline void set_type_ladder() { flags |= FLAG_TYPE_LADDER; }; inline void set_type_alert() { flags |= FLAG_TYPE_ALERT; }; - inline void set_type_global() { flags = 0xFF; }; + inline void set_type_global() { flags = 0xFFFFU; }; inline void unset_active() { flags &= ~FLAG_ACTIVE; }; + inline void unset_rdns_ban() { flags &= ~FLAG_USE_RDNS; } inline void unset_type_game() { flags &= ~FLAG_TYPE_GAME; }; inline void unset_type_chat() { flags &= ~FLAG_TYPE_CHAT; }; inline void unset_type_bot() { flags &= ~FLAG_TYPE_BOT; }; @@ -129,7 +133,7 @@ namespace RenX inline void unset_type_mine() { flags &= ~FLAG_TYPE_MINE; }; inline void unset_type_ladder() { flags &= ~FLAG_TYPE_LADDER; }; inline void unset_type_alert() { flags &= ~FLAG_TYPE_ALERT; }; - inline void unset_type_global() { flags = 0x00; }; + inline void unset_type_global() { flags = 0x0000U; }; }; /** @@ -139,7 +143,7 @@ namespace RenX * @param player Data of the player to be banned * @param length Duration of the ban */ - void add(RenX::Server *server, const RenX::PlayerInfo *player, const Jupiter::ReadableString &banner, const Jupiter::ReadableString &reason, time_t length, uint8_t flags = RenX::BanDatabase::Entry::FLAG_TYPE_GAME); + void add(RenX::Server *server, const RenX::PlayerInfo *player, const Jupiter::ReadableString &banner, const Jupiter::ReadableString &reason, time_t length, uint16_t flags = RenX::BanDatabase::Entry::FLAG_TYPE_GAME); /** * @brief Adds a ban entry for a set of player information and immediately writes it to the database. @@ -152,7 +156,7 @@ namespace RenX * @param reason Reason the player is getting banned * @param length Duration of the ban */ - void add(const Jupiter::ReadableString &name, uint32_t ip, uint8_t prefix_length, uint64_t steamid, const Jupiter::ReadableString &rdns, Jupiter::ReadableString &banner, Jupiter::ReadableString &reason, time_t length, uint8_t flags = RenX::BanDatabase::Entry::FLAG_TYPE_GAME); + void add(const Jupiter::ReadableString &name, uint32_t ip, uint8_t prefix_length, uint64_t steamid, const Jupiter::ReadableString &rdns, Jupiter::ReadableString &banner, Jupiter::ReadableString &reason, time_t length, uint16_t flags = RenX::BanDatabase::Entry::FLAG_TYPE_GAME); /** * @brief Upgrades the ban database to the current write_version. diff --git a/RenX.Core/RenX_PlayerInfo.h b/RenX.Core/RenX_PlayerInfo.h index d01f511..f70f57f 100644 --- a/RenX.Core/RenX_PlayerInfo.h +++ b/RenX.Core/RenX_PlayerInfo.h @@ -53,7 +53,7 @@ namespace RenX Jupiter::StringS vehicle; uint64_t steamid = 0; uint32_t ip32 = 0; - uint8_t ban_flags = 0; + uint16_t ban_flags = 0; TeamType team = TeamType::Other; int id = 0; bool isBot = false; diff --git a/RenX.Core/RenX_Server.cpp b/RenX.Core/RenX_Server.cpp index c11833d..945dde0 100644 --- a/RenX.Core/RenX_Server.cpp +++ b/RenX.Core/RenX_Server.cpp @@ -1073,7 +1073,7 @@ void RenX::Server::processLine(const Jupiter::ReadableString &line) 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->rdns.equals(player->rdns)) + || (this->localRDNSBan && entry->rdns.isNotEmpty() && entry->is_rdns_ban() && player->rdns.match(entry->rdns)) || (this->localNameBan && entry->name.isNotEmpty() && entry->name.equalsi(player->name))) { player->ban_flags |= entry->flags;