Network: Auto-kick clients after too many failed rcon/settings attempts
This commit is contained in:
@@ -1039,9 +1039,12 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_SETTINGS_PASSWO
|
|||||||
DEBUG(net, 0, "[settings-ctrl] wrong password from client-id %d", this->client_id);
|
DEBUG(net, 0, "[settings-ctrl] wrong password from client-id %d", this->client_id);
|
||||||
NetworkServerSendRcon(this->client_id, CC_ERROR, "Access Denied");
|
NetworkServerSendRcon(this->client_id, CC_ERROR, "Access Denied");
|
||||||
this->settings_authed = false;
|
this->settings_authed = false;
|
||||||
|
NetworkRecvStatus status = this->HandleAuthFailure(this->settings_auth_failures);
|
||||||
|
if (status != NETWORK_RECV_STATUS_OKAY) return status;
|
||||||
} else {
|
} else {
|
||||||
DEBUG(net, 0, "[settings-ctrl] client-id %d", this->client_id);
|
DEBUG(net, 0, "[settings-ctrl] client-id %d", this->client_id);
|
||||||
this->settings_authed = true;
|
this->settings_authed = true;
|
||||||
|
this->settings_auth_failures = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return this->SendSettingsAccessUpdate(this->settings_authed);
|
return this->SendSettingsAccessUpdate(this->settings_authed);
|
||||||
@@ -1592,7 +1595,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_RCON(Packet *p)
|
|||||||
|
|
||||||
if (_settings_client.network.rcon_password.empty()) {
|
if (_settings_client.network.rcon_password.empty()) {
|
||||||
NetworkServerSendRcon(this->client_id, CC_ERROR, "Access Denied");
|
NetworkServerSendRcon(this->client_id, CC_ERROR, "Access Denied");
|
||||||
return NETWORK_RECV_STATUS_OKAY;
|
return this->HandleAuthFailure(this->rcon_auth_failures);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<byte> password = p->Recv_buffer();
|
std::vector<byte> password = p->Recv_buffer();
|
||||||
@@ -1601,7 +1604,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_RCON(Packet *p)
|
|||||||
if (password != this->rcon_password_hash_cache.GetHash(_settings_client.network.rcon_password, this->rcon_hash_bits)) {
|
if (password != this->rcon_password_hash_cache.GetHash(_settings_client.network.rcon_password, this->rcon_hash_bits)) {
|
||||||
DEBUG(net, 0, "[rcon] wrong password from client-id %d", this->client_id);
|
DEBUG(net, 0, "[rcon] wrong password from client-id %d", this->client_id);
|
||||||
NetworkServerSendRcon(this->client_id, CC_ERROR, "Access Denied");
|
NetworkServerSendRcon(this->client_id, CC_ERROR, "Access Denied");
|
||||||
return NETWORK_RECV_STATUS_OKAY;
|
return this->HandleAuthFailure(this->rcon_auth_failures);
|
||||||
}
|
}
|
||||||
|
|
||||||
DEBUG(net, 3, "[rcon] Client-id %d executed: %s", this->client_id, command.c_str());
|
DEBUG(net, 3, "[rcon] Client-id %d executed: %s", this->client_id, command.c_str());
|
||||||
@@ -1609,6 +1612,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_RCON(Packet *p)
|
|||||||
_redirect_console_to_client = this->client_id;
|
_redirect_console_to_client = this->client_id;
|
||||||
IConsoleCmdExec(command.c_str());
|
IConsoleCmdExec(command.c_str());
|
||||||
_redirect_console_to_client = INVALID_CLIENT_ID;
|
_redirect_console_to_client = INVALID_CLIENT_ID;
|
||||||
|
this->rcon_auth_failures = 0;
|
||||||
return NETWORK_RECV_STATUS_OKAY;
|
return NETWORK_RECV_STATUS_OKAY;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1638,6 +1642,17 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_MOVE(Packet *p)
|
|||||||
return NETWORK_RECV_STATUS_OKAY;
|
return NETWORK_RECV_STATUS_OKAY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NetworkRecvStatus ServerNetworkGameSocketHandler::HandleAuthFailure(uint &failure_count)
|
||||||
|
{
|
||||||
|
failure_count++;
|
||||||
|
if (_settings_client.network.max_auth_failures != 0 && failure_count >= _settings_client.network.max_auth_failures) {
|
||||||
|
DEBUG(net, 0, "Kicked client-id #%d due to too many failed authentication attempts", this->client_id);
|
||||||
|
return this->SendError(NETWORK_ERROR_KICKED);
|
||||||
|
} else {
|
||||||
|
return NETWORK_RECV_STATUS_OKAY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const char *ServerNetworkGameSocketHandler::GetClientStatusName(ClientStatus status)
|
const char *ServerNetworkGameSocketHandler::GetClientStatusName(ClientStatus status)
|
||||||
{
|
{
|
||||||
static const char* _client_status_names[] {
|
static const char* _client_status_names[] {
|
||||||
|
@@ -100,6 +100,9 @@ public:
|
|||||||
uint desync_frame_seed = 0;
|
uint desync_frame_seed = 0;
|
||||||
uint desync_frame_state_checksum = 0;
|
uint desync_frame_state_checksum = 0;
|
||||||
|
|
||||||
|
uint rcon_auth_failures = 0;
|
||||||
|
uint settings_auth_failures = 0;
|
||||||
|
|
||||||
ServerNetworkGameSocketHandler(SOCKET s);
|
ServerNetworkGameSocketHandler(SOCKET s);
|
||||||
~ServerNetworkGameSocketHandler();
|
~ServerNetworkGameSocketHandler();
|
||||||
|
|
||||||
@@ -131,6 +134,8 @@ public:
|
|||||||
NetworkRecvStatus SendConfigUpdate();
|
NetworkRecvStatus SendConfigUpdate();
|
||||||
NetworkRecvStatus SendSettingsAccessUpdate(bool ok);
|
NetworkRecvStatus SendSettingsAccessUpdate(bool ok);
|
||||||
|
|
||||||
|
NetworkRecvStatus HandleAuthFailure(uint &failure_count);
|
||||||
|
|
||||||
std::string GetDebugInfo() const override;
|
std::string GetDebugInfo() const override;
|
||||||
|
|
||||||
static void Send();
|
static void Send();
|
||||||
|
@@ -383,6 +383,7 @@ struct NetworkSettings {
|
|||||||
std::string network_id; ///< network ID for servers
|
std::string network_id; ///< network ID for servers
|
||||||
std::string company_password_storage_token; ///< company password storage token
|
std::string company_password_storage_token; ///< company password storage token
|
||||||
std::string company_password_storage_secret; ///< company password storage secret
|
std::string company_password_storage_secret; ///< company password storage secret
|
||||||
|
uint8 max_auth_failures; ///< maximum auth failures before client is kicked
|
||||||
bool autoclean_companies; ///< automatically remove companies that are not in use
|
bool autoclean_companies; ///< automatically remove companies that are not in use
|
||||||
uint8 autoclean_unprotected; ///< remove passwordless companies after this many months
|
uint8 autoclean_unprotected; ///< remove passwordless companies after this many months
|
||||||
uint8 autoclean_protected; ///< remove the password from passworded companies after this many months
|
uint8 autoclean_protected; ///< remove the password from passworded companies after this many months
|
||||||
|
@@ -256,3 +256,11 @@ var = network.reload_cfg
|
|||||||
flags = SF_NOT_IN_SAVE | SF_NO_NETWORK_SYNC | SF_NETWORK_ONLY
|
flags = SF_NOT_IN_SAVE | SF_NO_NETWORK_SYNC | SF_NETWORK_ONLY
|
||||||
def = false
|
def = false
|
||||||
cat = SC_EXPERT
|
cat = SC_EXPERT
|
||||||
|
|
||||||
|
[SDTC_VAR]
|
||||||
|
var = network.max_auth_failures
|
||||||
|
type = SLE_UINT8
|
||||||
|
flags = SF_NOT_IN_SAVE | SF_NO_NETWORK_SYNC | SF_NETWORK_ONLY
|
||||||
|
def = 10
|
||||||
|
min = 0
|
||||||
|
max = 255
|
||||||
|
Reference in New Issue
Block a user