Merge pull request #2329 from GregoryLundberg/GL_I2327

Implement MP Moderation
This commit is contained in:
Sergey Popov 2018-01-12 17:50:19 +03:00 committed by GitHub
commit ed6ad71f48
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 78 additions and 34 deletions

View file

@ -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;

View file

@ -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) {

View file

@ -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();
}

View file

@ -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);

View file

@ -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_; }

View file

@ -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());
}
}

View file

@ -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_;

View file

@ -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();

View file

@ -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_;

View file

@ -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