diff --git a/Jupiter b/Jupiter index 94bda33..2132691 160000 --- a/Jupiter +++ b/Jupiter @@ -1 +1 @@ -Subproject commit 94bda33c248ef6fd9c0e09ecda6b27184865df6c +Subproject commit 21326918e9caf39c37d487183801715724908f85 diff --git a/Release/Bot.lib b/Release/Bot.lib index 0c94a68..c40ec42 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 41da5c7..9a3bc6f 100644 Binary files a/Release/Plugins/RenX.Core.lib and b/Release/Plugins/RenX.Core.lib differ diff --git a/RenX.Core/RenX.Core.vcxproj b/RenX.Core/RenX.Core.vcxproj index 87d9cf7..21d663f 100644 --- a/RenX.Core/RenX.Core.vcxproj +++ b/RenX.Core/RenX.Core.vcxproj @@ -70,6 +70,7 @@ + @@ -80,6 +81,7 @@ + diff --git a/RenX.Core/RenX.Core.vcxproj.filters b/RenX.Core/RenX.Core.vcxproj.filters index e375b38..24b4e41 100644 --- a/RenX.Core/RenX.Core.vcxproj.filters +++ b/RenX.Core/RenX.Core.vcxproj.filters @@ -47,6 +47,9 @@ Header Files + + Header Files + @@ -67,5 +70,8 @@ Source Files + + Source Files + \ No newline at end of file diff --git a/RenX.Core/RenX_BanDatabase.cpp b/RenX.Core/RenX_BanDatabase.cpp new file mode 100644 index 0000000..8f372cb --- /dev/null +++ b/RenX.Core/RenX_BanDatabase.cpp @@ -0,0 +1,147 @@ +/** + * Copyright (C) 2014 Justin James. + * + * This license must be preserved. + * Any applications, libraries, or code which make any use of any + * component of this program must not be commercial, unless explicit + * permission is granted from the original author. The use of this + * program for non-profit purposes is permitted. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * In the event that this license restricts you from making desired use of this program, contact the original author. + * Written by Justin James + */ + +#include +#include "Jupiter/IRC_Client.h" +#include "Jupiter/INIFile.h" +#include "RenX_PlayerInfo.h" +#include "RenX_BanDatabase.h" +#include "RenX_Core.h" +#include "RenX_Plugin.h" + +RenX::BanDatabase _banDatabase; +RenX::BanDatabase *RenX::banDatabase = &_banDatabase; +RenX::BanDatabase &RenX::defaultBanDatabase = _banDatabase; + +bool RenX::BanDatabase::load(const Jupiter::ReadableString &fname) +{ + RenX::BanDatabase::filename = fname; + FILE *file = fopen(RenX::BanDatabase::filename.c_str(), "rb"); + if (file != nullptr) + { + RenX::BanDatabase::version = fgetc(file); + while (!feof(file)) + if (fgetc(file) == '\n') + break; + Entry *entry; + char c; + while (!feof(file)) + { + entry = new Entry(); + fread(&entry->active, 1, 1, file); + fread(&entry->timestamp, sizeof(time_t), 1, file); + fread(&entry->length, sizeof(time_t), 1, file); + fread(&entry->steamid, sizeof(uint64_t), 1, file); + fread(&entry->ip, sizeof(uint32_t), 1, file); + if (feof(file)) + { + delete entry; + break; + } + c = fgetc(file); + while (c != '\n' && c != EOF) + { + if (c == '\0') + { + // add plugin data. + break; + } + entry->name += c; + c = fgetc(file); + } + entries.add(entry); + } + fclose(file); + return true; + } + else + { + RenX::BanDatabase::version = 0; + file = fopen(RenX::BanDatabase::filename.c_str(), "ab"); + if (file != nullptr) + { + fputc(RenX::BanDatabase::version, file); + fputc('\n', file); + fclose(file); + return true; + } + return false; + } +} + +void RenX::BanDatabase::add(RenX::Server *server, const RenX::PlayerInfo *player, time_t length) +{ + Entry *entry = new Entry(); + entry->active = 1; + entry->timestamp = time(0); + entry->length = length; + entry->steamid = player->steamid; + entry->ip = player->ip32; + entry->name = player->name; + entries.add(entry); + + FILE *file = fopen(RenX::BanDatabase::filename.c_str(), "ab"); + if (file != nullptr) + { + fwrite(&entry->active, 1, 1, file); + fwrite(&entry->timestamp, sizeof(time_t), 1, file); + fwrite(&entry->length, sizeof(time_t), 1, file); + fwrite(&entry->steamid, sizeof(uint64_t), 1, file); + fwrite(&entry->ip, sizeof(uint32_t), 1, file); + fwrite(entry->name.ptr(), sizeof(char), entry->name.size(), file); + // add plugin data + Jupiter::String pluginData; + Jupiter::ArrayList &xPlugins = *RenX::getCore()->getPlugins(); + for (size_t i = 0; i < xPlugins.size(); i++) + if (xPlugins.get(i)->RenX_OnBan(server, player, pluginData)) + { + fputc('\0', file); + fwrite(xPlugins.get(i)->getName().ptr(), sizeof(char), xPlugins.get(i)->getName().size(), file); + fputc('\0', file); + fwrite(pluginData.ptr(), sizeof(char), pluginData.size(), file); + } + + + fputc('\n', file); + fclose(file); + } +} + +uint8_t RenX::BanDatabase::getVersion() const +{ + return RenX::BanDatabase::version; +} + +const Jupiter::ReadableString &RenX::BanDatabase::getFileName() const +{ + return RenX::BanDatabase::filename; +} + +const Jupiter::ArrayList &RenX::BanDatabase::getEntries() const +{ + return RenX::BanDatabase::entries; +} + +RenX::BanDatabase::BanDatabase() +{ + RenX::BanDatabase::load(Jupiter::IRC::Client::Config->get(STRING_LITERAL_AS_REFERENCE("RenX"), STRING_LITERAL_AS_REFERENCE("BanDB"), STRING_LITERAL_AS_REFERENCE("Bans.db"))); +} + +RenX::BanDatabase::~BanDatabase() +{ + RenX::BanDatabase::entries.emptyAndDelete(); +} \ No newline at end of file diff --git a/RenX.Core/RenX_BanDatabase.h b/RenX.Core/RenX_BanDatabase.h new file mode 100644 index 0000000..491c6eb --- /dev/null +++ b/RenX.Core/RenX_BanDatabase.h @@ -0,0 +1,114 @@ +/** + * Copyright (C) 2014 Justin James. + * + * This license must be preserved. + * Any applications, libraries, or code which make any use of any + * component of this program must not be commercial, unless explicit + * permission is granted from the original author. The use of this + * program for non-profit purposes is permitted. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * In the event that this license restricts you from making desired use of this program, contact the original author. + * Written by Justin James + */ + +#if !defined _RENX_BANDATABASE_H_HEADER +#define _RENX_BANDATABASE_H_HEADER + +#include +#include +#include "Jupiter/String.h" +#include "Jupiter/CString.h" +#include "Jupiter/ArrayList.h" + +/** DLL Linkage Nagging */ +#if defined _MSC_VER +#pragma warning(push) +#pragma warning(disable: 4251) +#endif + +namespace RenX +{ + struct PlayerInfo; + class Server; + + /** + * @brief Represents the local ban database. + */ + class RENX_API BanDatabase + { + public: + /** + * @brief Represents a Ban entry in the database. + */ + struct RENX_API Entry + { + unsigned char active; /** 1 if the ban is active, 0 otherwise */ + 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 */; + uint32_t ip /** IPv4 address of the banned player */; + Jupiter::StringS name /** Name of the banned player */; + }; + + /** + * @brief Loads a file into the ban system. + * Note: This will generate a database file if none is found. + * + * @param fname String containing the name of the file to load + * @return True on success, false otherwise. + */ + bool load(const Jupiter::ReadableString &fname); + + /** + * @param Adds a ban entry for a player and immediately writes it to the database. + * + * @param server Server the player is playing in + * @param player Data of the player to be banned + * @param length Duration of the ban + */ + void add(RenX::Server *server, const RenX::PlayerInfo *player, time_t length); + + /** + * @brief Fetches the version of the database file. + * + * @return Database version + */ + uint8_t getVersion() const; + + /** + * @brief Fetches the name of the database file. + * + * @return Database file name + */ + const Jupiter::ReadableString &getFileName() const; + + /** + * @brief Fetches the list of ban entries. + * + * @return List of entries + */ + const Jupiter::ArrayList &getEntries() const; + + BanDatabase(); + ~BanDatabase(); + + private: + uint8_t version; + Jupiter::CStringS filename; + Jupiter::ArrayList entries; + }; + + RENX_API extern RenX::BanDatabase *banDatabase; + RENX_API extern RenX::BanDatabase &defaultBanDatabase; +} + +/** Re-enable warnings */ +#if defined _MSC_VER +#pragma warning(pop) +#endif + +#endif // _RENX_BANDATABASE_H_HEADER \ No newline at end of file diff --git a/RenX.Core/RenX_Core.cpp b/RenX.Core/RenX_Core.cpp index 76be9f7..c1508b7 100644 --- a/RenX.Core/RenX_Core.cpp +++ b/RenX.Core/RenX_Core.cpp @@ -40,7 +40,7 @@ RenX::Core::Core() RenX::Core::translationsFile.readFile(Jupiter::IRC::Client::Config->get(STRING_LITERAL_AS_REFERENCE("RenX"), STRING_LITERAL_AS_REFERENCE("TranslationsFile"), STRING_LITERAL_AS_REFERENCE("Translations.ini"))); RenX::initTranslations(RenX::Core::translationsFile); RenX::Core::commandsFile.readFile(Jupiter::IRC::Client::Config->get(STRING_LITERAL_AS_REFERENCE("RenX"), STRING_LITERAL_AS_REFERENCE("CommandsFile"), STRING_LITERAL_AS_REFERENCE("RenXGameCommands.ini"))); - + unsigned int wc = serverList.wordCount(WHITESPACE); RenX::Server *server; diff --git a/RenX.Core/RenX_PlayerInfo.h b/RenX.Core/RenX_PlayerInfo.h index cf4fc75..49423be 100644 --- a/RenX.Core/RenX_PlayerInfo.h +++ b/RenX.Core/RenX_PlayerInfo.h @@ -46,6 +46,7 @@ namespace RenX Jupiter::StringS adminType; Jupiter::StringS uuid; uint64_t steamid = 0; + uint32_t ip32 = 0; TeamType team = Other; int id = 0; bool isBot = false; diff --git a/RenX.Core/RenX_Plugin.cpp b/RenX.Core/RenX_Plugin.cpp index 9d3ec14..797a89e 100644 --- a/RenX.Core/RenX_Plugin.cpp +++ b/RenX.Core/RenX_Plugin.cpp @@ -45,6 +45,11 @@ void RenX::Plugin::RenX_OnPlayerDelete(Server *, const RenX::PlayerInfo *) return; } +bool RenX::Plugin::RenX_OnBan(Server *, const RenX::PlayerInfo *, Jupiter::StringType &) +{ + return false; +} + void RenX::Plugin::RenX_OnJoin(Server *, const RenX::PlayerInfo *) { return; diff --git a/RenX.Core/RenX_Plugin.h b/RenX.Core/RenX_Plugin.h index cdae664..ded8d74 100644 --- a/RenX.Core/RenX_Plugin.h +++ b/RenX.Core/RenX_Plugin.h @@ -24,6 +24,7 @@ */ #include "Jupiter/Plugin.h" +#include "Jupiter/String_Type.h" #include "RenX.h" namespace RenX @@ -40,6 +41,7 @@ namespace RenX /** Non-RCON RenX logs */ virtual void RenX_OnPlayerCreate(Server *server, const PlayerInfo *player); virtual void RenX_OnPlayerDelete(Server *server, const PlayerInfo *player); + virtual bool RenX_OnBan(Server *server, const PlayerInfo *player, Jupiter::StringType &data); /** Player type logs */ virtual void RenX_OnJoin(Server *server, const PlayerInfo *player); diff --git a/RenX.Core/RenX_Server.cpp b/RenX.Core/RenX_Server.cpp index 11a2990..f2ed0b6 100644 --- a/RenX.Core/RenX_Server.cpp +++ b/RenX.Core/RenX_Server.cpp @@ -25,6 +25,7 @@ #include "RenX_GameCommand.h" #include "RenX_Functions.h" #include "RenX_Plugin.h" +#include "RenX_BanDatabase.h" int RenX::Server::think() { @@ -300,24 +301,38 @@ void RenX::Server::kickPlayer(const RenX::PlayerInfo *player) void RenX::Server::banPlayer(int id) { - RenX::Server::sock.send(Jupiter::StringS::Format("cadminkickban pid%d\n", id)); + if (RenX::Server::rconBan) + RenX::Server::sock.send(Jupiter::StringS::Format("cadminkickban pid%d\n", id)); + else + { + RenX::PlayerInfo *player = RenX::Server::getPlayer(id); + if (player != nullptr) + RenX::Server::banPlayer(player); + } } -void RenX::Server::banPlayer(const RenX::PlayerInfo *player) +void RenX::Server::banPlayer(const RenX::PlayerInfo *player, time_t length) { - if (this->profile->pidbug) + if (RenX::Server::rconBan && length == 0) { - if (player->isBot) - RenX::Server::sock.send(Jupiter::StringS::Format("cadminkickban %.*s\n", player->name.size(), player->name.ptr())); - else if (player->id < 1000) - RenX::Server::banPlayer(player->id); - else if (player->name.contains('|') == false) - RenX::Server::sock.send(Jupiter::StringS::Format("cadminkickban %.*s\n", player->name.size(), player->name.ptr())); + if (this->profile->pidbug) + { + if (player->isBot) + RenX::Server::sock.send(Jupiter::StringS::Format("cadminkickban %.*s\n", player->name.size(), player->name.ptr())); + else if (player->id < 1000) + RenX::Server::banPlayer(player->id); + else if (player->name.contains('|') == false) + RenX::Server::sock.send(Jupiter::StringS::Format("cadminkickban %.*s\n", player->name.size(), player->name.ptr())); + else + RenX::Server::banPlayer(player->id); + } else - RenX::Server::banPlayer(player->id); + RenX::Server::sock.send(Jupiter::StringS::Format("cadminkickban pid%d\n", player->id)); } else - RenX::Server::banPlayer(player->id); + RenX::Server::kickPlayer(player); + if (RenX::Server::localBan) + RenX::banDatabase->add(this, player, length); } bool RenX::Server::removePlayer(int id) @@ -665,6 +680,7 @@ void RenX::Server::processLine(const Jupiter::ReadableString &line) r->joinTime = time(nullptr); r->steamid = steamid; r->ip = ip; + r->ip32 = Jupiter::Socket::pton4(Jupiter::CStringS(r->ip).c_str()); if (id != 0) server->players.add(r); switch (this->uuidMode) @@ -680,6 +696,24 @@ void RenX::Server::processLine(const Jupiter::ReadableString &line) } for (size_t i = 0; i < xPlugins.size(); i++) xPlugins.get(i)->RenX_OnPlayerCreate(server, r); + + const Jupiter::ArrayList &entries = RenX::banDatabase->getEntries(); + RenX::BanDatabase::Entry *entry; + for (size_t i = 0; i != entries.size(); i++) + { + entry = entries.get(i); + if (entry->active) + { + if (entry->timestamp + entry->length > time(0)) + entry->active = false; + else if (server->localSteamBan && entry->steamid == r->steamid) + server->kickPlayer(r); + else if (server->localIPBan && entry->ip == r->ip32) + server->kickPlayer(r); + else if (server->localNameBan && entry->name.equalsi(r->name)) + server->kickPlayer(r); + } + } } else if (r->name.size() == 0) r->name = name; r->team = team; @@ -990,7 +1024,6 @@ void RenX::Server::processLine(const Jupiter::ReadableString &line) name = playerData.gotoToken(4, CListDelim); } - printf("Name: %.*s - ID: %d - isBot: %u - steamid: %llu - ip: %.*s" ENDL, name.size(), name.ptr(), id, isBot, steamid.asUnsignedLongLong(), ip.size(), ip.ptr()); RenX::PlayerInfo *player = getPlayerOrAdd(this, name, id, team, isBot, steamid.asUnsignedLongLong(), ip); } else @@ -1134,6 +1167,11 @@ void RenX::Server::init() RenX::Server::rules = Jupiter::IRC::Client::Config->get(RenX::Server::configSection, STRING_LITERAL_AS_REFERENCE("Rules"), STRING_LITERAL_AS_REFERENCE("Anarchy!")); RenX::Server::delay = Jupiter::IRC::Client::Config->getInt(RenX::Server::configSection, STRING_LITERAL_AS_REFERENCE("ReconnectDelay"), 60); RenX::Server::uuidMode = Jupiter::IRC::Client::Config->getInt(RenX::Server::configSection, STRING_LITERAL_AS_REFERENCE("UUIDMode"), 0); + RenX::Server::rconBan = Jupiter::IRC::Client::Config->getBool(RenX::Server::configSection, STRING_LITERAL_AS_REFERENCE("RCONBan"), false); + RenX::Server::localSteamBan = Jupiter::IRC::Client::Config->getBool(RenX::Server::configSection, STRING_LITERAL_AS_REFERENCE("LocalSteamBan"), true); + RenX::Server::localIPBan = Jupiter::IRC::Client::Config->getBool(RenX::Server::configSection, STRING_LITERAL_AS_REFERENCE("LocalIPBan"), true); + RenX::Server::localNameBan = Jupiter::IRC::Client::Config->getBool(RenX::Server::configSection, STRING_LITERAL_AS_REFERENCE("LocalNameBan"), false); + RenX::Server::localBan = RenX::Server::localIPBan || RenX::Server::localSteamBan || RenX::Server::localNameBan; RenX::Server::steamFormat = Jupiter::IRC::Client::Config->getInt(RenX::Server::configSection, STRING_LITERAL_AS_REFERENCE("SteamFormat"), 16); RenX::Server::neverSay = Jupiter::IRC::Client::Config->getBool(RenX::Server::configSection, STRING_LITERAL_AS_REFERENCE("NeverSay"), false); diff --git a/RenX.Core/RenX_Server.h b/RenX.Core/RenX_Server.h index 9705adb..9d76fcb 100644 --- a/RenX.Core/RenX_Server.h +++ b/RenX.Core/RenX_Server.h @@ -23,6 +23,7 @@ * @brief Defines the Server class. */ +#include #include "Jupiter/TCPSocket.h" #include "Jupiter/DLList.h" #include "Jupiter/ArrayList.h" @@ -257,8 +258,9 @@ namespace RenX * @brief Bans a player from the server. * * @param player Data of the player to ban. + * @param length Duration of the ban (0 for permanent). */ - void banPlayer(const RenX::PlayerInfo *player); + void banPlayer(const RenX::PlayerInfo *player, time_t length = 0); /** * @brief Removes a player's data based on their ID number. @@ -523,6 +525,11 @@ namespace RenX time_t delay; int steamFormat; /** 16 = hex, 10 = base 10, 8 = octal, -2 = SteamID 2, -3 = SteamID 3 */ unsigned int uuidMode; /** 0 = steam, 1 = nickname */ + bool rconBan; + bool localBan; + bool localSteamBan; + bool localIPBan; + bool localNameBan; bool neverSay; Jupiter::TCPSocket sock; Jupiter::CStringS clientHostname;