Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Basic Whitelist #4

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
183 changes: 169 additions & 14 deletions GhostServer/main_cli.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ static enum {
CMD_BAN,
CMD_BAN_ID,
CMD_SERVER_MSG,
CMD_WHITELIST_ENABLE,
CMD_WHITELIST_ADD_NAME,
CMD_WHITELIST_ADD_IP,
CMD_WHITELIST_REMOVE_NAME,
CMD_WHITELIST_REMOVE_IP,
} g_current_cmd = CMD_NONE;

static char *g_entered_pre;
Expand Down Expand Up @@ -45,20 +50,27 @@ static void handle_cmd(char *line) {

if (!strcmp(line, "help")) {
puts("Available commands:");
puts(" help show this list");
puts(" quit terminate the server");
puts(" list list all the currently connected clients");
puts(" countdown_set set the pre/post cmds and countdown duration");
puts(" countdown start a countdown");
puts(" disconnect disconnect a client by name");
puts(" disconnect_id disconnect a client by ID");
puts(" ban ban connections from a certain IP by ghost name");
puts(" ban_id ban connections from a certain IP by ghost ID");
puts(" accept_players start accepting connections from players");
puts(" refuse_players stop accepting connections from players");
puts(" accept_spectators start accepting connections from spectators");
puts(" refuse_spectators stop accepting connections from spectators");
puts(" server_msg send all clients a message from the server");
puts(" help show this list");
puts(" quit terminate the server");
puts(" list list all the currently connected clients");
puts(" countdown_set set the pre/post cmds and countdown duration");
puts(" countdown start a countdown");
puts(" disconnect disconnect a client by name");
puts(" disconnect_id disconnect a client by ID");
puts(" ban ban connections from a certain IP by ghost name");
puts(" ban_id ban connections from a certain IP by ghost ID");
puts(" accept_players start accepting connections from players");
puts(" refuse_players stop accepting connections from players");
puts(" accept_spectators start accepting connections from spectators");
puts(" refuse_spectators stop accepting connections from spectators");
puts(" server_msg send all clients a message from the server");
puts(" whitelist_enable enable whitelist");
puts(" whitelist_disable disable whitelist");
puts(" whitelist_add_name add player to whitelist");
puts(" whitelist_add_ip add player to whitelist");
puts(" whitelist_remove_name remove player from whitelist");
puts(" whitelist_remove_ip remove player from whitelist");
puts(" whitelist print out all entries on whitelist");
return;
}

Expand Down Expand Up @@ -169,6 +181,66 @@ static void handle_cmd(char *line) {
return;
}

if (!strcmp(line, "whitelist_enable")) {
g_current_cmd = CMD_WHITELIST_ENABLE;
fputs("Disconnect players not on whitelist? (y/N) ", stdout);
fflush(stdout);
return;
}

if (!strcmp(line, "whitelist_disable")) {
g_network->ScheduleServerThread([] {
g_network->whitelistEnabled = false;
});
puts("Whitelist now disabled");
return;
}

if (!strcmp(line, "whitelist_add_name")) {
g_current_cmd = CMD_WHITELIST_ADD_NAME;
fputs("Player to add: ", stdout);
fflush(stdout);
return;
}

if (!strcmp(line, "whitelist_add_ip")) {
g_current_cmd = CMD_WHITELIST_ADD_IP;
fputs("Player IP to add: ", stdout);
fflush(stdout);
return;
}

if (!strcmp(line, "whitelist_remove_name")) {
g_current_cmd = CMD_WHITELIST_REMOVE_NAME;
fputs("Player to remove: ", stdout);
fflush(stdout);
return;
}

if (!strcmp(line, "whitelist_remove_ip")) {
g_current_cmd = CMD_WHITELIST_REMOVE_IP;
fputs("Player IP to remove: ", stdout);
fflush(stdout);
return;
}

if (!strcmp(line, "whitelist")) {
if (g_network->whitelist.size() == 0) {
puts("No players on whitelist");
} else {
puts("Players on whitelist:");
for (auto& entry : g_network->whitelist) {
printf(" %s\n", entry.value.c_str());
}
}

if (g_network->whitelistEnabled)
puts("(Whitelist enabled)");
else
puts("(Whitelist disabled)");
return;
}

printf("Unknown command: '%s'\n", line);
return;

Expand Down Expand Up @@ -255,6 +327,89 @@ static void handle_cmd(char *line) {
g_current_cmd = CMD_NONE;
g_network->ServerMessage(line);
return;

case CMD_WHITELIST_ENABLE:
g_current_cmd = CMD_NONE;
g_network->ScheduleServerThread([=] {
g_network->whitelistEnabled = true;

if (!strcmp(line, "y")) {
for (auto& client : g_network->clients) {
if (!g_network->IsOnWhitelist(client.name, client.IP)) {
g_network->DisconnectPlayer(client, "Not on whitelist");
}
}
}
});

puts("Whitelist now enabled!");
return;

case CMD_WHITELIST_ADD_NAME:
g_current_cmd = CMD_NONE;
g_network->ScheduleServerThread([=] {
g_network->whitelist.insert({ WhitelistEntryType::NAME, line });
});
printf("Added player %s to whitelist\n", line);
return;

case CMD_WHITELIST_ADD_IP:
g_current_cmd = CMD_NONE;
g_network->ScheduleServerThread([=] {
g_network->whitelist.insert({ WhitelistEntryType::IP, line });
});
printf("Added player IP %s to whitelist\n", line);
return;

case CMD_WHITELIST_REMOVE_NAME: {
g_current_cmd = CMD_NONE;

std::string _line(line);

auto index = std::find_if(g_network->whitelist.begin(), g_network->whitelist.end(), [&](const WhitelistEntry& entry) {
return entry.type == WhitelistEntryType::NAME && entry.value == _line;
});

if (index != g_network->whitelist.end()) {
auto clients = g_network->GetPlayerByName(_line);

g_network->ScheduleServerThread([=]() {
g_network->whitelist.erase(index);

for (auto client : clients) {
g_network->DisconnectPlayer(*client, "Not on whitelist!");
}
});
}

printf("Removed player %s from whitelist\n", line);
return;
}

case CMD_WHITELIST_REMOVE_IP: {
g_current_cmd = CMD_NONE;

std::string _line(line);

auto index = std::find_if(g_network->whitelist.begin(), g_network->whitelist.end(), [&](const WhitelistEntry& entry) {
return entry.type == WhitelistEntryType::IP && entry.value == _line;
});

if (index != g_network->whitelist.end()) {
g_network->ScheduleServerThread([=]() {
g_network->whitelist.erase(index);

auto* client = g_network->GetClientByIP(_line);
if (client == nullptr)
return;

g_network->DisconnectPlayer(*client, "Not on whitelist!");
});
}

printf("Removed player IP %s from whitelist\n", line);
return;
}
}
}

Expand Down
38 changes: 38 additions & 0 deletions GhostServer/networkmanager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,18 @@ Client* NetworkManager::GetClientByID(sf::Uint32 ID)
return nullptr;
}

Client* NetworkManager::GetClientByIP(std::string IP) {
sf::IpAddress clientIP(IP);

for (auto& client : this->clients) {
if (client.IP == clientIP) {
return &client;
}
}

return nullptr;
}

bool NetworkManager::StartServer(const int port)
{
if (this->udpSocket.bind(port) != sf::Socket::Done) {
Expand Down Expand Up @@ -255,6 +267,14 @@ void NetworkManager::CheckConnection()
return;
}

if (whitelistEnabled) {
auto clientIp = client.tcpSocket->getRemoteAddress();
if (!IsOnWhitelist(name, clientIp)) {
// Refuse connection, since the player was not found in the whitelist
return;
}
}

client.ID = this->lastID++;
client.IP = client.tcpSocket->getRemoteAddress();
client.port = port;
Expand Down Expand Up @@ -546,3 +566,21 @@ void NetworkManager::DoHeartbeats()
}
}
}

bool NetworkManager::IsOnWhitelist(std::string name, sf::IpAddress IP) {
if (whitelist.empty())
return false;

auto index = std::find_if(whitelist.begin(), whitelist.end(), [&name, &IP](const WhitelistEntry& entry) {
switch (entry.type) {
case WhitelistEntryType::NAME:
return entry.value == name;
case WhitelistEntryType::IP:
return entry.value == IP.toString();
default:
return false;
}
});

return index != whitelist.end();
}
21 changes: 21 additions & 0 deletions GhostServer/networkmanager.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include <SFML/Network.hpp>

#include <vector>
#include <set>
#include <mutex>
#include <atomic>
#include <thread>
Expand Down Expand Up @@ -64,6 +65,20 @@ struct Client {
bool spectator;
};

enum class WhitelistEntryType {
NAME,
IP,
};

struct WhitelistEntry {
WhitelistEntryType type;
std::string value;

bool operator<(const WhitelistEntry& rhs) const {
return value < rhs.value;
}
};

#ifdef GHOST_GUI
class NetworkManager : public QObject
{
Expand Down Expand Up @@ -100,9 +115,13 @@ class NetworkManager
bool acceptingPlayers = true;
bool acceptingSpectators = true;

bool whitelistEnabled = false;
std::set<WhitelistEntry> whitelist;

void ScheduleServerThread(std::function<void()> func);

Client* GetClientByID(sf::Uint32 ID);
Client* GetClientByIP(std::string IP);

bool StartServer(const int port);
void StopServer();
Expand All @@ -120,6 +139,8 @@ class NetworkManager
void BanClientIP(Client &cl);
void ServerMessage(const char *msg);

bool IsOnWhitelist(std::string name, sf::IpAddress IP);

#ifdef GHOST_GUI
signals:
void OnNewEvent(QString event);
Expand Down