Merge pull request #2329 from GregoryLundberg/GL_I2327
Implement MP Moderation
This commit is contained in:
commit
ed6ad71f48
10 changed files with 78 additions and 34 deletions
|
@ -158,6 +158,13 @@ std::pair<wesnothd_connection_ptr, config> open_connection(std::string host)
|
|||
std::swap(initial_lobby_config, data);
|
||||
}
|
||||
|
||||
if(data.has_child("error")) {
|
||||
std::string error_message;
|
||||
config* error = &data.child("error");
|
||||
error_message = (*error)["message"].str();
|
||||
throw wesnothd_rejected_client_error(error_message);
|
||||
}
|
||||
|
||||
// Continue if we did not get a direction to login
|
||||
if(!data.has_child("mustlogin")) {
|
||||
continue;
|
||||
|
|
|
@ -853,6 +853,8 @@ bool game_launcher::play_multiplayer(mp_selection res)
|
|||
multiplayer_server_.clear();
|
||||
}
|
||||
|
||||
} catch(wesnothd_rejected_client_error& e) {
|
||||
gui2::show_error_message(e.message);
|
||||
} catch(game::mp_server_error& e) {
|
||||
gui2::show_error_message(_("Error while starting server: ") + e.message);
|
||||
} catch(game::load_game_failed& e) {
|
||||
|
|
|
@ -207,7 +207,7 @@ void lobby_player_info::kick_ban_button_callback(window& w)
|
|||
void lobby_player_info::do_kick_ban(bool ban)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << (ban ? "kban" : "kick ") << info_.name;
|
||||
ss << (ban ? "kban " : "kick ") << info_.name;
|
||||
if(ban && !time_->get_value().empty()) {
|
||||
ss << " " << time_->get_value();
|
||||
}
|
||||
|
|
|
@ -264,6 +264,7 @@ static lg::log_domain log_server("server");
|
|||
return;
|
||||
LOG_SERVER << "Reading bans from " << filename_ << "\n";
|
||||
config cfg;
|
||||
dirty_ = false;
|
||||
filesystem::scoped_istream ban_file = filesystem::istream_file(filename_);
|
||||
read_gz(cfg, *ban_file);
|
||||
|
||||
|
@ -518,10 +519,11 @@ static lg::log_domain log_server("server");
|
|||
return e.message;
|
||||
}
|
||||
dirty_ = true;
|
||||
write();
|
||||
return ret.str();
|
||||
}
|
||||
|
||||
void ban_manager::unban(std::ostringstream& os, const std::string& ip)
|
||||
void ban_manager::unban(std::ostringstream& os, const std::string& ip, bool immediate_write)
|
||||
{
|
||||
ban_set::iterator ban;
|
||||
try {
|
||||
|
@ -543,7 +545,9 @@ static lg::log_domain log_server("server");
|
|||
if ((*ban)->get_group().empty()) deleted_bans_.push_back(*ban);
|
||||
bans_.erase(ban);
|
||||
dirty_ = true;
|
||||
|
||||
if (immediate_write) {
|
||||
write();
|
||||
}
|
||||
}
|
||||
|
||||
void ban_manager::unban_group(std::ostringstream& os, const std::string& group)
|
||||
|
@ -555,6 +559,7 @@ static lg::log_domain log_server("server");
|
|||
os << "Removed " << (bans_.size() - temp.size()) << " bans";
|
||||
bans_.swap(temp);
|
||||
dirty_ = true;
|
||||
write();
|
||||
}
|
||||
|
||||
void ban_manager::check_ban_times(time_t time_now)
|
||||
|
@ -573,7 +578,7 @@ static lg::log_domain log_server("server");
|
|||
// This ban is going to expire so delete it.
|
||||
LOG_SERVER << "Remove a ban " << ban->get_ip() << ". time: " << time_now << " end_time " << ban->get_end_time() << "\n";
|
||||
std::ostringstream os;
|
||||
unban(os, ban->get_ip());
|
||||
unban(os, ban->get_ip(), false);
|
||||
time_queue_.pop();
|
||||
|
||||
}
|
||||
|
@ -609,8 +614,9 @@ static lg::log_domain log_server("server");
|
|||
|
||||
|
||||
|
||||
void ban_manager::list_bans(std::ostringstream& out, const std::string& mask) const
|
||||
void ban_manager::list_bans(std::ostringstream& out, const std::string& mask)
|
||||
{
|
||||
expire_bans();
|
||||
if (bans_.empty())
|
||||
{
|
||||
out << "No bans set.";
|
||||
|
@ -652,8 +658,9 @@ static lg::log_domain log_server("server");
|
|||
}
|
||||
|
||||
|
||||
std::string ban_manager::is_ip_banned(const std::string& ip) const
|
||||
std::string ban_manager::is_ip_banned(const std::string& ip)
|
||||
{
|
||||
expire_bans();
|
||||
ip_mask pair;
|
||||
try {
|
||||
pair = parse_ip(ip);
|
||||
|
|
|
@ -135,6 +135,10 @@ namespace wesnothd {
|
|||
{ return c - '0'; }
|
||||
|
||||
void init_ban_help();
|
||||
void check_ban_times(time_t time_now);
|
||||
inline void expire_bans() {
|
||||
check_ban_times(time(nullptr));
|
||||
}
|
||||
public:
|
||||
ban_manager();
|
||||
~ban_manager();
|
||||
|
@ -151,16 +155,14 @@ namespace wesnothd {
|
|||
bool parse_time(const std::string& duration, time_t* time) const;
|
||||
|
||||
std::string ban(const std::string&, const time_t&, const std::string&, const std::string&, const std::string&, const std::string& = "");
|
||||
void unban(std::ostringstream& os, const std::string& ip);
|
||||
void unban(std::ostringstream& os, const std::string& ip, bool immediate_write=true);
|
||||
void unban_group(std::ostringstream& os, const std::string& group);
|
||||
|
||||
|
||||
void check_ban_times(time_t time_now);
|
||||
|
||||
void list_deleted_bans(std::ostringstream& out, const std::string& mask = "*") const;
|
||||
void list_bans(std::ostringstream& out, const std::string& mask = "*") const;
|
||||
void list_bans(std::ostringstream& out, const std::string& mask = "*");
|
||||
|
||||
std::string is_ip_banned(const std::string& ip) const;
|
||||
std::string is_ip_banned(const std::string& ip);
|
||||
|
||||
const std::string& get_ban_help() const
|
||||
{ return ban_help_; }
|
||||
|
|
|
@ -485,7 +485,19 @@ void server::load_config() {
|
|||
}
|
||||
}
|
||||
|
||||
std::string server::is_ip_banned(const std::string& ip) const {
|
||||
bool server::ip_exceeds_connection_limit(const std::string& ip) const
|
||||
{
|
||||
if (concurrent_connections_ == 0) return false;
|
||||
size_t connections = 0;
|
||||
for(const auto& player: player_connections_) {
|
||||
if (client_address(player.socket()) == ip) {
|
||||
++connections;
|
||||
}
|
||||
}
|
||||
return connections >= concurrent_connections_;
|
||||
}
|
||||
|
||||
std::string server::is_ip_banned(const std::string& ip) {
|
||||
if (!tor_ip_list_.empty()) {
|
||||
if (find(tor_ip_list_.begin(), tor_ip_list_.end(), ip) != tor_ip_list_.end()) return "TOR IP";
|
||||
}
|
||||
|
@ -2439,6 +2451,7 @@ void server::kickban_handler(const std::string& issuer_name, const std::string&
|
|||
if (banned) *out << "\n";
|
||||
else banned = true;
|
||||
const std::string ip = client_address(player.socket());
|
||||
*out << ban_manager_.ban(ip, parsed_time, reason, issuer_name, dummy_group, target);
|
||||
users_to_kick.push_back(player.socket());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -156,7 +156,7 @@ private:
|
|||
void load_config();
|
||||
|
||||
bool ip_exceeds_connection_limit(const std::string& ip) const;
|
||||
std::string is_ip_banned(const std::string& ip) const;
|
||||
std::string is_ip_banned(const std::string& ip);
|
||||
|
||||
simple_wml::document version_query_response_;
|
||||
simple_wml::document login_response_;
|
||||
|
|
|
@ -53,7 +53,7 @@ void server_base::start_server()
|
|||
acceptor_.listen();
|
||||
serve();
|
||||
|
||||
handshake_response_.connection_num = 42;
|
||||
handshake_response_.connection_num = htonl(42);
|
||||
|
||||
#ifndef _WIN32
|
||||
sighup_.async_wait(
|
||||
|
@ -78,23 +78,8 @@ void server_base::accept_connection(const boost::system::error_code& error, sock
|
|||
return;
|
||||
}
|
||||
|
||||
const std::string ip = client_address(socket);
|
||||
|
||||
const std::string reason = is_ip_banned(ip);
|
||||
if (!reason.empty()) {
|
||||
LOG_SERVER << ip << "\trejected banned user. Reason: " << reason << "\n";
|
||||
async_send_error(socket, "You are banned. Reason: " + reason);
|
||||
return;
|
||||
/*} else if (ip_exceeds_connection_limit(ip)) {
|
||||
LOG_SERVER << ip << "\trejected ip due to excessive connections\n";
|
||||
async_send_error(socket, "Too many connections from your IP.");
|
||||
return;*/
|
||||
} else {
|
||||
|
||||
DBG_SERVER << ip << "\tnew connection accepted\n";
|
||||
serverside_handshake(socket);
|
||||
}
|
||||
|
||||
DBG_SERVER << client_address(socket) << "\tnew connection tentatively accepted\n";
|
||||
serverside_handshake(socket);
|
||||
}
|
||||
|
||||
void server_base::serverside_handshake(socket_ptr socket)
|
||||
|
@ -118,7 +103,25 @@ void server_base::handle_handshake(const boost::system::error_code& error, socke
|
|||
async_write(
|
||||
*socket, boost::asio::buffer(handshake_response_.buf, 4),
|
||||
[=](const boost::system::error_code& error, size_t)
|
||||
{ if(!check_error(error, socket)) this->handle_new_client(socket); }
|
||||
{
|
||||
if(!check_error(error, socket)) {
|
||||
const std::string ip = client_address(socket);
|
||||
|
||||
const std::string reason = is_ip_banned(ip);
|
||||
if (!reason.empty()) {
|
||||
LOG_SERVER << ip << "\trejected banned user. Reason: " << reason << "\n";
|
||||
async_send_error(socket, "You are banned. Reason: " + reason);
|
||||
return;
|
||||
} else if (ip_exceeds_connection_limit(ip)) {
|
||||
LOG_SERVER << ip << "\trejected ip due to excessive connections\n";
|
||||
async_send_error(socket, "Too many connections from your IP.");
|
||||
return;
|
||||
} else {
|
||||
DBG_SERVER << ip << "\tnew connection fully accepted\n";
|
||||
this->handle_new_client(socket);
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -153,7 +156,7 @@ void server_base::run() {
|
|||
}
|
||||
}
|
||||
|
||||
std::string client_address(socket_ptr socket)
|
||||
std::string client_address(const socket_ptr socket)
|
||||
{
|
||||
boost::system::error_code error;
|
||||
std::string result = socket->remote_endpoint(error).address().to_string();
|
||||
|
|
|
@ -58,7 +58,8 @@ protected:
|
|||
virtual void handle_new_client(socket_ptr socket) = 0;
|
||||
|
||||
virtual bool accepting_connections() const { return true; }
|
||||
virtual std::string is_ip_banned(const std::string&) const { return std::string(); }
|
||||
virtual std::string is_ip_banned(const std::string&) { return std::string(); }
|
||||
virtual bool ip_exceeds_connection_limit(const std::string&) const { return false; }
|
||||
|
||||
#ifndef _WIN32
|
||||
boost::asio::posix::stream_descriptor input_;
|
||||
|
|
|
@ -23,6 +23,15 @@ struct wesnothd_error : public game::error
|
|||
wesnothd_error(const std::string& error) : game::error(error) {}
|
||||
};
|
||||
|
||||
/**
|
||||
* Error used when the client is rejected by the MP server.
|
||||
* Technically, this is not an error but the only way to handle the condition is as if it were an error.
|
||||
*/
|
||||
struct wesnothd_rejected_client_error : public game::error
|
||||
{
|
||||
wesnothd_rejected_client_error (const std::string& msg) : game::error (msg) {}
|
||||
};
|
||||
|
||||
///We received invalid data from wesnothd during a game
|
||||
///This means we cannot continue with the game but we can stay connected to wesnothd and start a new game
|
||||
///TODO: find a short name
|
||||
|
|
Loading…
Add table
Reference in a new issue