iw4x-client/src/Components/Modules/Bans.cpp

321 lines
5.8 KiB
C++
Raw Normal View History

2022-02-27 07:53:44 -05:00
#include <STDInclude.hpp>
#include "Bans.hpp"
2017-01-19 16:23:59 -05:00
namespace Components
{
2023-01-25 13:20:44 -05:00
const char* Bans::BanListFile = "userraw/bans.json";
2022-06-28 03:26:43 -04:00
// Have only one instance of IW4x read/write the file
std::unique_lock<Utils::NamedMutex> Bans::Lock()
2017-01-19 16:23:59 -05:00
{
2022-06-28 03:26:43 -04:00
static Utils::NamedMutex mutex{"iw4x-ban-list-lock"};
std::unique_lock lock{mutex};
return lock;
}
2021-12-17 13:49:25 -05:00
2022-06-28 03:26:43 -04:00
bool Bans::IsBanned(const banEntry& entry)
{
BanList list;
LoadBans(&list);
2017-01-19 16:23:59 -05:00
if (entry.first.bits)
2017-01-19 16:23:59 -05:00
{
2022-06-04 08:59:14 -04:00
for (const auto& idEntry : list.idList)
2017-01-19 16:23:59 -05:00
{
if (idEntry.bits == entry.first.bits)
2017-01-19 16:23:59 -05:00
{
return true;
}
}
}
if (entry.second.full)
{
2022-06-28 03:26:43 -04:00
for (const auto& ipEntry : list.ipList)
2017-01-19 16:23:59 -05:00
{
if (ipEntry.full == entry.second.full)
{
return true;
}
}
}
return false;
}
2022-06-28 03:26:43 -04:00
void Bans::InsertBan(const banEntry& entry)
2017-01-19 16:23:59 -05:00
{
2022-06-28 03:26:43 -04:00
BanList list;
LoadBans(&list);
2017-01-19 16:23:59 -05:00
if (entry.first.bits)
2017-01-19 16:23:59 -05:00
{
bool found = false;
2022-06-28 03:26:43 -04:00
for (const auto& idEntry : list.idList)
2017-01-19 16:23:59 -05:00
{
if (idEntry.bits == entry.first.bits)
2017-01-19 16:23:59 -05:00
{
found = true;
break;
}
}
if (!found)
{
list.idList.push_back(entry.first);
}
}
if (entry.second.full)
{
bool found = false;
2022-06-28 03:26:43 -04:00
for (const auto& ipEntry : list.ipList)
2017-01-19 16:23:59 -05:00
{
if (ipEntry.full == entry.second.full)
{
found = true;
break;
}
}
if (!found)
{
list.ipList.push_back(entry.second);
}
}
2022-06-28 03:26:43 -04:00
SaveBans(&list);
2018-10-13 11:37:37 -04:00
}
2022-06-28 03:26:43 -04:00
void Bans::SaveBans(const BanList* list)
2018-10-13 11:37:37 -04:00
{
2023-01-25 13:20:44 -05:00
assert(list);
2022-06-28 03:26:43 -04:00
const auto _ = Lock();
2018-10-13 11:37:37 -04:00
2017-01-19 16:23:59 -05:00
std::vector<std::string> idVector;
std::vector<std::string> ipVector;
for (const auto& idEntry : list->idList)
2017-01-19 16:23:59 -05:00
{
idVector.emplace_back(Utils::String::VA("%llX", idEntry.bits));
2017-01-19 16:23:59 -05:00
}
for (const auto& ipEntry : list->ipList)
2017-01-19 16:23:59 -05:00
{
ipVector.emplace_back(Utils::String::VA("%u.%u.%u.%u",
2017-01-19 16:23:59 -05:00
ipEntry.bytes[0] & 0xFF,
ipEntry.bytes[1] & 0xFF,
ipEntry.bytes[2] & 0xFF,
2023-01-25 13:20:44 -05:00
ipEntry.bytes[3] & 0xFF)
);
2017-01-19 16:23:59 -05:00
}
const nlohmann::json bans = nlohmann::json
2017-01-19 16:23:59 -05:00
{
{ "ip", ipVector },
{ "id", idVector },
};
2023-01-25 13:20:44 -05:00
Utils::IO::WriteFile(BanListFile, bans.dump());
2017-01-19 16:23:59 -05:00
}
2022-06-28 03:26:43 -04:00
void Bans::LoadBans(BanList* list)
2017-01-19 16:23:59 -05:00
{
2023-01-25 13:20:44 -05:00
assert(list);
2022-06-28 03:26:43 -04:00
const auto _ = Lock();
2017-01-19 16:23:59 -05:00
2023-01-25 13:20:44 -05:00
const auto bans = Utils::IO::ReadFile(BanListFile);
if (bans.empty())
2017-01-19 16:23:59 -05:00
{
2022-06-28 03:26:43 -04:00
Logger::Debug("bans.json does not exist");
return;
}
2017-01-19 16:23:59 -05:00
nlohmann::json banData;
try
{
2023-01-25 13:20:44 -05:00
banData = nlohmann::json::parse(bans);
}
2023-01-25 13:20:44 -05:00
catch (const std::exception& ex)
2022-06-28 03:26:43 -04:00
{
Logger::PrintError(Game::CON_CHANNEL_ERROR, "Json Parse Error: {}\n", ex.what());
2022-06-28 03:26:43 -04:00
return;
}
2017-01-19 16:23:59 -05:00
2023-01-25 13:20:44 -05:00
if (!banData.contains("id") || !banData.contains("ip"))
{
Logger::PrintError(Game::CON_CHANNEL_ERROR, "bans.json contains invalid data\n");
return;
}
2022-06-28 03:26:43 -04:00
const auto& idList = banData["id"];
const auto& ipList = banData["ip"];
2017-01-19 16:23:59 -05:00
2022-06-28 03:26:43 -04:00
if (idList.is_array())
{
const nlohmann::json::array_t arr = idList;
for (auto &idEntry : arr)
2022-06-28 03:26:43 -04:00
{
if (idEntry.is_string())
2017-01-19 16:23:59 -05:00
{
2022-06-28 03:26:43 -04:00
SteamID id;
auto guid = idEntry.get<std::string>();
id.bits = std::strtoull(guid.data(), nullptr, 16);
2022-06-28 03:26:43 -04:00
list->idList.push_back(id);
2017-01-19 16:23:59 -05:00
}
}
}
2022-06-28 03:26:43 -04:00
if (ipList.is_array())
2017-01-19 16:23:59 -05:00
{
const nlohmann::json::array_t arr = ipList;
for (auto &ipEntry : arr)
2022-06-28 03:26:43 -04:00
{
if (ipEntry.is_string())
{
Network::Address addr(ipEntry.get<std::string>());
2017-01-19 16:23:59 -05:00
2022-06-28 03:26:43 -04:00
list->ipList.push_back(addr.getIP());
}
}
2017-01-19 16:23:59 -05:00
}
2022-06-28 03:26:43 -04:00
}
2017-01-19 16:23:59 -05:00
2022-06-28 03:26:43 -04:00
void Bans::BanClient(Game::client_t* cl, const std::string& reason)
{
2017-01-19 16:23:59 -05:00
SteamID guid;
2022-06-28 03:26:43 -04:00
guid.bits = cl->steamID;
2017-01-19 16:23:59 -05:00
2022-08-20 06:09:41 -04:00
InsertBan({guid, cl->header.netchan.remoteAddress.ip});
2017-01-19 16:23:59 -05:00
2022-06-28 03:26:43 -04:00
Game::SV_DropClient(cl, reason.data(), true);
2017-01-19 16:23:59 -05:00
}
2018-10-13 11:37:37 -04:00
void Bans::UnbanClient(SteamID id)
{
2022-06-28 03:26:43 -04:00
BanList list;
LoadBans(&list);
2018-10-13 11:37:37 -04:00
2022-06-28 03:26:43 -04:00
const auto entry = std::find_if(list.idList.begin(), list.idList.end(), [&id](const SteamID& entry)
2018-10-13 11:37:37 -04:00
{
return id.bits == entry.bits;
});
if (entry != list.idList.end())
{
list.idList.erase(entry);
}
2022-06-28 03:26:43 -04:00
SaveBans(&list);
2018-10-13 11:37:37 -04:00
}
void Bans::UnbanClient(Game::netIP_t ip)
{
2022-06-28 03:26:43 -04:00
BanList list;
LoadBans(&list);
2018-10-13 11:37:37 -04:00
2022-06-28 03:26:43 -04:00
const auto entry = std::find_if(list.ipList.begin(), list.ipList.end(), [&ip](const Game::netIP_t& entry)
2018-10-13 11:37:37 -04:00
{
return ip.full == entry.full;
});
if (entry != list.ipList.end())
{
list.ipList.erase(entry);
}
2022-06-28 03:26:43 -04:00
SaveBans(&list);
2018-10-13 11:37:37 -04:00
}
2017-01-19 16:23:59 -05:00
Bans::Bans()
{
2022-06-28 03:26:43 -04:00
Command::Add("banClient", [](Command::Params* params)
2017-01-19 16:23:59 -05:00
{
if (!Dedicated::IsRunning())
2022-06-28 03:26:43 -04:00
{
Logger::Print("Server is not running.\n");
return;
}
if (params->size() < 2)
{
Logger::Print("{} <client number> : permanently ban a client\n", params->get(0));
return;
}
2017-01-19 16:23:59 -05:00
2022-06-28 03:26:43 -04:00
const auto* input = params->get(1);
2017-01-19 16:23:59 -05:00
2022-06-28 03:26:43 -04:00
for (auto i = 0; input[i] != '\0'; ++i)
{
if (input[i] < '0' || input[i] > '9')
{
Logger::Print("Bad slot number: {}\n", input);
return;
}
}
const auto clientNum = std::strtoul(input, nullptr, 10);
if (clientNum >= Game::MAX_CLIENTS)
2022-06-28 03:26:43 -04:00
{
Logger::Print("Bad client slot: {}\n", clientNum);
2022-06-28 03:26:43 -04:00
return;
}
2023-04-16 09:07:09 -04:00
auto* cl = &Game::svs_clients[clientNum];
if (cl->header.state < Game::CS_ACTIVE)
2022-06-28 03:26:43 -04:00
{
Logger::Print("Client {} is not active\n", clientNum);
2022-06-28 03:26:43 -04:00
return;
}
if (cl->bIsTestClient)
{
return;
}
2022-06-28 03:26:43 -04:00
const std::string reason = params->size() < 3 ? "EXE_ERR_BANNED_PERM" : params->join(2);
2023-04-16 09:07:09 -04:00
BanClient(cl, reason);
2017-01-19 16:23:59 -05:00
});
2022-06-28 03:26:43 -04:00
Command::Add("unbanClient", [](Command::Params* params)
2018-10-13 11:37:37 -04:00
{
if (!Dedicated::IsRunning())
2022-06-28 03:26:43 -04:00
{
Logger::Print("Server is not running.\n");
return;
}
2018-10-13 11:37:37 -04:00
2022-06-28 03:26:43 -04:00
if (params->size() < 3)
{
Logger::Print("{} <type> <ip or guid>\n", params->get(0));
return;
}
const auto* type = params->get(1);
2018-10-13 11:37:37 -04:00
if (type == "ip"s)
{
Network::Address address(params->get(2));
2022-06-28 03:26:43 -04:00
UnbanClient(address.getIP());
2018-10-13 11:37:37 -04:00
2022-06-12 17:07:53 -04:00
Logger::Print("Unbanned IP {}\n", params->get(2));
2018-10-13 11:37:37 -04:00
}
else if (type == "guid"s)
{
SteamID id;
id.bits = std::strtoull(params->get(2), nullptr, 16);
2018-10-13 11:37:37 -04:00
2022-06-28 03:26:43 -04:00
UnbanClient(id);
2018-10-13 11:37:37 -04:00
2022-06-12 17:07:53 -04:00
Logger::Print("Unbanned GUID {}\n", params->get(2));
2018-10-13 11:37:37 -04:00
}
});
2017-01-19 16:23:59 -05:00
}
}