Optimized server ban manager using integer ip for wildcard matching
Added who_banned and group fields to ban Made reason required for banning
This commit is contained in:
parent
189a1821d7
commit
2beec3a977
3 changed files with 364 additions and 95 deletions
|
@ -17,70 +17,228 @@
|
|||
#include "filesystem.hpp"
|
||||
#include "serialization/parser.hpp"
|
||||
#include "serialization/binary_or_text.hpp"
|
||||
#include "serialization/string_utils.hpp"
|
||||
|
||||
#include "ban.hpp"
|
||||
|
||||
#include <sstream>
|
||||
#include <algorithm>
|
||||
|
||||
#include <boost/bind.hpp>
|
||||
|
||||
namespace wesnothd {
|
||||
|
||||
#define ERR_SERVER LOG_STREAM(err, mp_server)
|
||||
#define LOG_SERVER LOG_STREAM(info, mp_server)
|
||||
#define DBG_SERVER LOG_STREAM(debug, mp_server)
|
||||
|
||||
bool banned_compare::operator()(const banned_ptr a, const banned_ptr b) const
|
||||
bool banned_compare::operator()(const banned_ptr& a, const banned_ptr& b) const
|
||||
{
|
||||
//! We want to move the lowest value to the top
|
||||
return (*a) > (*b);
|
||||
}
|
||||
|
||||
banned::banned(const std::string& ip, const time_t end_time, const std::string& reason) : ip_(ip), end_time_(end_time), reason_(reason), deleted_(false)
|
||||
banned_compare_subnet::compare_fn banned_compare_subnet::active_ = &banned_compare_subnet::less;
|
||||
|
||||
void banned_compare_subnet::set_use_subnet_mask(bool use)
|
||||
{
|
||||
if (use)
|
||||
{
|
||||
assert(active_ == &banned_compare_subnet::less);
|
||||
active_ = &banned_compare_subnet::less_with_subnet;
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(active_ != &banned_compare_subnet::less);
|
||||
active_ = &banned_compare_subnet::less;
|
||||
}
|
||||
}
|
||||
|
||||
bool banned_compare_subnet::operator()(const banned_ptr& a, const banned_ptr& b) const
|
||||
{
|
||||
return (this->*(active_))(a,b);
|
||||
}
|
||||
|
||||
bool banned_compare_subnet::less(const banned_ptr& a, const banned_ptr& b) const
|
||||
{
|
||||
return a->get_int_ip() < b->get_int_ip();
|
||||
}
|
||||
|
||||
bool banned_compare_subnet::less_with_subnet(const banned_ptr& a, const banned_ptr& b) const
|
||||
{
|
||||
return a->get_mask_ip(b->mask()) < b->get_mask_ip(a->mask());
|
||||
}
|
||||
|
||||
subnet_compare_setter::subnet_compare_setter()
|
||||
{
|
||||
banned_compare_subnet::set_use_subnet_mask(true);
|
||||
}
|
||||
|
||||
subnet_compare_setter::~subnet_compare_setter()
|
||||
{
|
||||
banned_compare_subnet::set_use_subnet_mask(false);
|
||||
}
|
||||
const std::string banned::who_banned_default_ = "system";
|
||||
|
||||
banned_ptr banned::create_dummy(const std::string& ip)
|
||||
{
|
||||
banned_ptr dummy(new banned(ip));
|
||||
return dummy;
|
||||
}
|
||||
|
||||
banned::banned(const std::string& ip) :
|
||||
ip_(0),
|
||||
mask_(0),
|
||||
ip_text_(),
|
||||
end_time_(0),
|
||||
reason_(),
|
||||
who_banned_(who_banned_default_)
|
||||
|
||||
{
|
||||
ip_mask pair = parse_ip(ip);
|
||||
ip_ = pair.first;
|
||||
mask_ = 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
banned::banned(const std::string& ip,
|
||||
const time_t end_time,
|
||||
const std::string& reason,
|
||||
const std::string& who_banned,
|
||||
const std::string& group) :
|
||||
ip_text_(ip),
|
||||
end_time_(end_time),
|
||||
reason_(reason),
|
||||
who_banned_(who_banned),
|
||||
group_(group)
|
||||
{
|
||||
ip_mask pair = parse_ip(ip_text_);
|
||||
ip_ = pair.first;
|
||||
mask_ = pair.second;
|
||||
}
|
||||
|
||||
banned::banned(const config& cfg) :
|
||||
ip_(),
|
||||
ip_(0),
|
||||
mask_(0),
|
||||
ip_text_(),
|
||||
end_time_(0),
|
||||
reason_(),
|
||||
deleted_(false)
|
||||
who_banned_(who_banned_default_)
|
||||
{
|
||||
read(cfg);
|
||||
}
|
||||
|
||||
banned::ip_mask banned::parse_ip(const std::string& ip) const
|
||||
{
|
||||
// We use bit operations to construct the integer
|
||||
// ip_mask is a pair: first is ip and second is mask
|
||||
ip_mask ret;
|
||||
ret.first = 0;
|
||||
ret.second = 0;
|
||||
std::vector<std::string> split_ip = utils::split(ip, '.');
|
||||
unsigned int shift = 4*8; // start shifting from the highest byte
|
||||
unsigned int mask = 0xFF000000;
|
||||
const unsigned int complite_part_mask = 0xFF;
|
||||
std::vector<std::string>::const_iterator part = split_ip.begin();
|
||||
bool wildcard = false;
|
||||
do {
|
||||
shift -= 8;
|
||||
mask >>= 8;
|
||||
if (part == split_ip.end())
|
||||
{
|
||||
if (!wildcard)
|
||||
throw banned::error("Malformed ip address given for ban: " + ip);
|
||||
// Adding 0 to ip and mask is nop
|
||||
// we can then break out of loop
|
||||
break;
|
||||
} else {
|
||||
if (*part == "*")
|
||||
{
|
||||
wildcard = true;
|
||||
// Adding 0 to ip and mask is nop
|
||||
} else {
|
||||
wildcard = false;
|
||||
unsigned int part_ip = lexical_cast_default<unsigned int>(*part, complite_part_mask + 1);
|
||||
if (part_ip > complite_part_mask)
|
||||
throw banned::error("Malformed ip address given for ban: " + ip);
|
||||
ret.first |= (part_ip << shift);
|
||||
ret.second |= (complite_part_mask << shift);
|
||||
}
|
||||
}
|
||||
++part;
|
||||
} while (shift);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void banned::read(const config& cfg)
|
||||
{
|
||||
ip_ = cfg["ip"];
|
||||
end_time_ = lexical_cast<time_t>(cfg["end_time"]);
|
||||
reason_ = cfg["reason"];
|
||||
deleted_ = utils::string_bool(cfg["deleted"]);
|
||||
{
|
||||
// parse ip and mask
|
||||
ip_text_ = cfg["ip"];
|
||||
ip_mask pair = parse_ip(ip_text_);
|
||||
ip_ = pair.first;
|
||||
mask_ = pair.second;
|
||||
}
|
||||
|
||||
if (cfg.has_attribute("end_time"))
|
||||
end_time_ = lexical_cast_default<time_t>(cfg["end_time"], 0);
|
||||
reason_ = cfg["reason"];
|
||||
|
||||
// only overwrite defaults if exists
|
||||
if (cfg.has_attribute("who_banned"))
|
||||
who_banned_ = cfg["who_banned"];
|
||||
if (cfg.has_attribute("group"))
|
||||
group_ = cfg["group"];
|
||||
}
|
||||
|
||||
void banned::write(config& cfg) const
|
||||
{
|
||||
std::stringstream ss;
|
||||
cfg["ip"] = ip_;
|
||||
ss << end_time_;
|
||||
cfg["end_time"] = ss.str();
|
||||
cfg["ip"] = get_ip();
|
||||
if (end_time_ > 0)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << end_time_;
|
||||
cfg["end_time"] = ss.str();
|
||||
}
|
||||
cfg["reason"] = reason_;
|
||||
cfg["deleted"] = deleted_ ? "yes":"no";
|
||||
if (who_banned_ != who_banned_default_)
|
||||
{
|
||||
cfg["who_banned"] = who_banned_;
|
||||
}
|
||||
if (!group_.empty())
|
||||
{
|
||||
cfg["group"] = group_;
|
||||
}
|
||||
}
|
||||
|
||||
std::string banned::get_human_end_time() const
|
||||
std::string banned::get_human_end_time(const time_t& time)
|
||||
{
|
||||
if (end_time_ == 0)
|
||||
if (time == 0)
|
||||
{
|
||||
return "permanent";
|
||||
}
|
||||
char buf[30];
|
||||
struct tm* local;
|
||||
local = localtime(&end_time_);
|
||||
local = localtime(&time);
|
||||
strftime(buf,30,"%H:%M:%S %d.%m.%Y", local );
|
||||
return std::string(buf);
|
||||
|
||||
}
|
||||
|
||||
std::string banned::get_human_end_time() const
|
||||
{
|
||||
return banned::get_human_end_time(end_time_);
|
||||
}
|
||||
|
||||
bool banned::operator>(const banned& b) const
|
||||
{
|
||||
return end_time_ > b.get_end_time();
|
||||
}
|
||||
|
||||
|
||||
unsigned int banned::get_mask_ip(unsigned int mask) const
|
||||
{
|
||||
return ip_ & mask & mask_;
|
||||
}
|
||||
|
||||
void ban_manager::read()
|
||||
{
|
||||
if (filename_.empty() || !file_exists(filename_))
|
||||
|
@ -93,13 +251,15 @@ namespace wesnothd {
|
|||
for (config::child_list::const_iterator itor = bans.begin();
|
||||
itor != bans.end(); ++itor)
|
||||
{
|
||||
banned_ptr new_ban(new banned(**itor));
|
||||
if (!new_ban->is_deleted())
|
||||
{
|
||||
bans_[new_ban->get_ip()] = new_ban;
|
||||
try {
|
||||
banned_ptr new_ban(new banned(**itor));
|
||||
assert(bans_.insert(new_ban).second);
|
||||
|
||||
if (new_ban->get_end_time() != 0)
|
||||
time_queue_.push(new_ban);
|
||||
} catch (banned::error& e) {
|
||||
ERR_SERVER << e.message << " while reading bans\n";
|
||||
}
|
||||
if (new_ban->get_end_time() != 0)
|
||||
time_queue_.push(new_ban);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -110,11 +270,11 @@ namespace wesnothd {
|
|||
LOG_SERVER << "Writing bans to " << filename_ << "\n";
|
||||
dirty_ = false;
|
||||
config cfg;
|
||||
for (ban_map::const_iterator itor = bans_.begin();
|
||||
for (ban_set::const_iterator itor = bans_.begin();
|
||||
itor != bans_.end(); ++itor)
|
||||
{
|
||||
config& child = cfg.add_child("ban");
|
||||
itor->second->write(child);
|
||||
(*itor)->write(child);
|
||||
}
|
||||
scoped_ostream ban_file = ostream_file(filename_);
|
||||
config_writer writer(*ban_file, true, "");
|
||||
|
@ -222,37 +382,70 @@ namespace wesnothd {
|
|||
return ret;
|
||||
}
|
||||
|
||||
void ban_manager::ban(const std::string& ip, const time_t& end_time, const std::string& reason)
|
||||
std::string ban_manager::ban(const std::string& ip,
|
||||
const time_t& end_time,
|
||||
const std::string& reason,
|
||||
const std::string& who_banned,
|
||||
const std::string& group)
|
||||
{
|
||||
dirty_ = true;
|
||||
ban_map::iterator ban;
|
||||
if ((ban = bans_.find(ip)) != bans_.end())
|
||||
{
|
||||
// Already exsiting ban for ip. We have to first remove it
|
||||
ban->second->remove_ban();
|
||||
bans_.erase(ban);
|
||||
ban_set::iterator ban;
|
||||
try {
|
||||
if ((ban = bans_.find(banned::create_dummy(ip))) != bans_.end())
|
||||
{
|
||||
// Already exsiting ban for ip. We have to first remove it
|
||||
bans_.erase(ban);
|
||||
LOG_SERVER << "Overwriting ban: " << (*ban)->get_ip() << " reason was: " << (*ban)->get_reason() << "\n";
|
||||
}
|
||||
} catch (banned::error& e) {
|
||||
ERR_SERVER << e.message << " while creating dummy ban for finding existing ban\n";
|
||||
return e.message;
|
||||
}
|
||||
banned_ptr new_ban(new banned(ip, end_time, reason));
|
||||
bans_.insert(ban_map::value_type(ip,new_ban));
|
||||
if (end_time != 0)
|
||||
time_queue_.push(new_ban);
|
||||
try {
|
||||
banned_ptr new_ban(new banned(ip, end_time, reason,who_banned, group));
|
||||
bans_.insert(new_ban);
|
||||
if (end_time != 0)
|
||||
time_queue_.push(new_ban);
|
||||
} catch (banned::error& e) {
|
||||
ERR_SERVER << e.message << " while banning\n";
|
||||
return e.message;
|
||||
}
|
||||
dirty_ = true;
|
||||
return std::string();
|
||||
}
|
||||
|
||||
void ban_manager::unban(std::ostringstream& os, const std::string& ip)
|
||||
{
|
||||
dirty_ = true;
|
||||
ban_map::iterator ban = bans_.find(ip);
|
||||
ban_set::iterator ban;
|
||||
try {
|
||||
ban = bans_.find(banned::create_dummy(ip));
|
||||
} catch (banned::error& e) {
|
||||
ERR_SERVER << e.message << "\n";
|
||||
os << e.message << "\n";
|
||||
return;
|
||||
}
|
||||
|
||||
if (ban == bans_.end())
|
||||
{
|
||||
os << "There is no ban on '" << ip << "'.";
|
||||
return;
|
||||
}
|
||||
ban->second->remove_ban();
|
||||
bans_.erase(ban);
|
||||
dirty_ = true;
|
||||
|
||||
os << "Ban on '" << ip << "' removed.";
|
||||
}
|
||||
|
||||
void ban_manager::unban_group(std::ostringstream& os, const std::string& group)
|
||||
{
|
||||
ban_set temp;
|
||||
std::insert_iterator<ban_set> temp_inserter(temp, temp.begin());
|
||||
std::remove_copy_if(bans_.begin(), bans_.end(), temp_inserter, boost::bind(&banned::match_group,boost::bind(&banned_ptr::get,_1),group));
|
||||
|
||||
os << "Removed " << (bans_.size() - temp.size()) << " bans";
|
||||
bans_.swap(temp);
|
||||
dirty_ = true;
|
||||
}
|
||||
|
||||
void ban_manager::check_ban_times(time_t time_now)
|
||||
{
|
||||
while (!time_queue_.empty())
|
||||
|
@ -266,20 +459,10 @@ namespace wesnothd {
|
|||
break;
|
||||
}
|
||||
|
||||
if (ban->is_deleted())
|
||||
{
|
||||
// This was allready deleted have to free memory;
|
||||
time_queue_.pop();
|
||||
continue;
|
||||
}
|
||||
|
||||
// No need to make dirty because
|
||||
// these bans will be handled correctly in next load.
|
||||
|
||||
// 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";
|
||||
|
||||
bans_.erase(bans_.find(ban->get_ip()));
|
||||
std::ostringstream os;
|
||||
unban(os, ban->get_ip());
|
||||
time_queue_.pop();
|
||||
|
||||
}
|
||||
|
@ -295,13 +478,30 @@ namespace wesnothd {
|
|||
return;
|
||||
}
|
||||
|
||||
std::set<std::string> groups;
|
||||
|
||||
out << "BAN LIST\n";
|
||||
for (ban_map::const_iterator i = bans_.begin();
|
||||
for (ban_set::const_iterator i = bans_.begin();
|
||||
i != bans_.end(); ++i)
|
||||
{
|
||||
out << "IP: '" << i->second->get_ip() <<
|
||||
"' end_time: '" << i->second->get_human_end_time() <<
|
||||
"' reason: '" << i->second->get_reason() << "'\n";
|
||||
if ((*i)->get_group().empty())
|
||||
{
|
||||
out << "IP: '" << (*i)->get_ip() <<
|
||||
"' end_time: '" << (*i)->get_human_end_time() <<
|
||||
"' reason: '" << (*i)->get_reason() <<
|
||||
"' issuer: "<< (*i)->get_who_banned() << "\n";
|
||||
} else {
|
||||
groups.insert((*i)->get_group());
|
||||
}
|
||||
}
|
||||
|
||||
if (!groups.empty())
|
||||
{
|
||||
out << "ban groups:\n";
|
||||
|
||||
out << *groups.begin();
|
||||
std::ostream& (*fn)(std::ostream&,const std::string&) = &std::operator<<;
|
||||
std::for_each( ++groups.begin(), groups.end(), boost::bind(fn,boost::bind(fn,boost::ref(out),std::string(", ")),_1));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -309,19 +509,20 @@ namespace wesnothd {
|
|||
|
||||
bool ban_manager::is_ip_banned(std::string ip) const
|
||||
{
|
||||
for (ban_map::const_iterator i = bans_.begin(); i != bans_.end(); ++i) {
|
||||
if (utils::wildcard_string_match(ip, i->first)) {
|
||||
DBG_SERVER << "Comparing ban '" << i->first << "' vs '..." << ip << "'\t" << "banned.\n";
|
||||
return true;
|
||||
}
|
||||
DBG_SERVER << "Comparing ban '" << i->first << "' vs '..." << ip << "'\t" << "not banned.\n";
|
||||
subnet_compare_setter setter;
|
||||
ban_set::const_iterator ban;
|
||||
try {
|
||||
ban = bans_.find(banned::create_dummy(ip));
|
||||
} catch (banned::error& e) {
|
||||
ERR_SERVER << e.message << " in is_ip_banned\n";
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
return ban != bans_.end();
|
||||
}
|
||||
|
||||
void ban_manager::init_ban_help()
|
||||
{
|
||||
ban_help_ = "ban <ip|nickname> [<time>] [<reason>]\nTime is give in format ‰d[‰s[‰d‰s[...]]] (where ‰s is s, m, h, D, M or Y).\nIf no time modifier is given minutes are used.\n";
|
||||
ban_help_ = "ban <ip|nickname> [<time>] <reason>\nTime is give in format ‰d[‰s[‰d‰s[...]]] (where ‰s is s, m, h, D, M or Y).\nIf no time modifier is given minutes are used.\n";
|
||||
default_ban_times::iterator itor = ban_times_.begin();
|
||||
if (itor != ban_times_.end())
|
||||
{
|
||||
|
|
|
@ -14,6 +14,9 @@
|
|||
|
||||
#ifndef SERVER_GAME_HPP_INCLUDED
|
||||
#define SERVER_GAME_HPP_INCLUDED
|
||||
#include "game_errors.hpp"
|
||||
|
||||
#include <set>
|
||||
#include <map>
|
||||
#include <queue>
|
||||
#include <ctime>
|
||||
|
@ -30,22 +33,45 @@ namespace wesnothd {
|
|||
|
||||
//! We want to move the lowest value to the top
|
||||
struct banned_compare {
|
||||
bool operator()(const banned_ptr a, const banned_ptr b) const;
|
||||
bool operator()(const banned_ptr& a, const banned_ptr& b) const;
|
||||
};
|
||||
|
||||
typedef std::map<std::string, banned_ptr> ban_map;
|
||||
class subnet_compare_setter;
|
||||
struct banned_compare_subnet {
|
||||
bool operator()(const banned_ptr& a, const banned_ptr& b) const;
|
||||
private:
|
||||
static void set_use_subnet_mask(bool);
|
||||
bool less(const banned_ptr& a, const banned_ptr& b) const;
|
||||
bool less_with_subnet(const banned_ptr& a, const banned_ptr& b) const;
|
||||
typedef bool (banned_compare_subnet::*compare_fn)(const banned_ptr& a, const banned_ptr& b) const;
|
||||
static compare_fn active_;
|
||||
friend class subnet_compare_setter;
|
||||
};
|
||||
|
||||
struct subnet_compare_setter {
|
||||
subnet_compare_setter();
|
||||
~subnet_compare_setter();
|
||||
};
|
||||
|
||||
typedef std::set<banned_ptr,banned_compare_subnet > ban_set;
|
||||
typedef std::priority_queue<banned_ptr,std::vector<banned_ptr>, banned_compare> ban_time_queue;
|
||||
typedef std::map<std::string, size_t> default_ban_times;
|
||||
|
||||
|
||||
class banned {
|
||||
std::string ip_;
|
||||
unsigned int ip_;
|
||||
unsigned int mask_;
|
||||
std::string ip_text_;
|
||||
time_t end_time_;
|
||||
std::string reason_;
|
||||
bool deleted_;
|
||||
|
||||
std::string who_banned_;
|
||||
std::string group_;
|
||||
static const std::string who_banned_default_;
|
||||
typedef std::pair<unsigned int, unsigned int> ip_mask;
|
||||
ip_mask parse_ip(const std::string&) const;
|
||||
banned(const std::string& ip);
|
||||
public:
|
||||
banned(const std::string& ip, const time_t end_time, const std::string& reason);
|
||||
banned(const std::string& ip, const time_t end_time, const std::string& reason, const std::string& who_banned=who_banned_default_, const std::string& group="");
|
||||
banned(const config&);
|
||||
|
||||
void read(const config&);
|
||||
|
@ -55,27 +81,42 @@ namespace wesnothd {
|
|||
{ return end_time_; }
|
||||
|
||||
std::string get_human_end_time() const;
|
||||
static std::string get_human_end_time(const time_t&);
|
||||
|
||||
std::string get_reason() const
|
||||
{ return reason_; }
|
||||
|
||||
std::string get_ip() const
|
||||
std::string get_ip() const
|
||||
{ return ip_text_; }
|
||||
std::string get_group() const
|
||||
{ return group_; }
|
||||
|
||||
std::string get_who_banned() const
|
||||
{ return who_banned_; }
|
||||
|
||||
bool match_group(const std::string& group) const
|
||||
{ return group_ == group; }
|
||||
|
||||
unsigned int get_mask_ip(unsigned int) const;
|
||||
unsigned int get_int_ip() const
|
||||
{ return ip_; }
|
||||
|
||||
void remove_ban()
|
||||
{ deleted_ = true; }
|
||||
unsigned int mask() const
|
||||
{ return mask_; }
|
||||
|
||||
bool is_deleted() const
|
||||
{ return deleted_; }
|
||||
static banned_ptr create_dummy(const std::string& ip);
|
||||
|
||||
//! Notice that comparision is done wrong way to make the smallest value in top of heap
|
||||
bool operator>(const banned& b) const;
|
||||
|
||||
struct error : public ::game::error {
|
||||
error(const std::string& message) : ::game::error(message) {}
|
||||
};
|
||||
};
|
||||
|
||||
class ban_manager
|
||||
{
|
||||
|
||||
ban_map bans_;
|
||||
ban_set bans_;
|
||||
ban_time_queue time_queue_;
|
||||
default_ban_times ban_times_;
|
||||
std::string ban_help_;
|
||||
|
@ -97,8 +138,10 @@ namespace wesnothd {
|
|||
|
||||
time_t parse_time(std::string time_in) const;
|
||||
|
||||
void ban(const std::string&, const time_t&, const std::string&);
|
||||
std::string ban(const std::string&, const time_t&, const std::string&, const std::string&, const std::string&);
|
||||
void unban(std::ostringstream& os, const std::string& ip);
|
||||
void unban_group(std::ostringstream& os, const std::string& group);
|
||||
|
||||
|
||||
void check_ban_times(time_t time_now);
|
||||
|
||||
|
|
|
@ -283,7 +283,7 @@ private:
|
|||
void process_query(const network::connection sock,
|
||||
simple_wml::node& query);
|
||||
//! Process commands from admins and users.
|
||||
std::string process_command(const std::string& cmd);
|
||||
std::string process_command(const std::string& cmd, const std::string& issuer_name);
|
||||
//! Handle private messages between players.
|
||||
void process_whisper(const network::connection sock,
|
||||
simple_wml::node& whisper) const;
|
||||
|
@ -461,7 +461,7 @@ void server::run() {
|
|||
// Then client would reconnect to new server automaticaly.
|
||||
// This would also allow server to move to new port or address if there is need
|
||||
|
||||
process_command("msg All games ended. Shutting down now. Reconnect to the new server.");
|
||||
process_command("msg All games ended. Shutting down now. Reconnect to the new server.", "system");
|
||||
throw network::error("shut down");
|
||||
}
|
||||
if (config_reload == 1) {
|
||||
|
@ -472,7 +472,7 @@ void server::run() {
|
|||
// Process commands from the server socket/fifo
|
||||
std::string admin_cmd;
|
||||
if (input_.read_line(admin_cmd)) {
|
||||
process_command(admin_cmd);
|
||||
process_command(admin_cmd, "socket");
|
||||
}
|
||||
|
||||
time_t now = time(NULL);
|
||||
|
@ -852,15 +852,15 @@ void server::process_query(const network::connection sock,
|
|||
LOG_SERVER << "Admin Command:" << "\ttype: " << command
|
||||
<< "\tIP: "<< network::ip_address(sock)
|
||||
<< "\tnick: "<< pl->second.name() << std::endl;
|
||||
response << process_command(command.to_string());
|
||||
response << process_command(command.to_string(), pl->second.name());
|
||||
// Commands a player may issue.
|
||||
} else if (command == "help") {
|
||||
response << help_msg;
|
||||
} else if (command == "status") {
|
||||
response << process_command(command.to_string() + " " + pl->second.name());
|
||||
response << process_command(command.to_string() + " " + pl->second.name(), pl->second.name());
|
||||
} else if (command == "status " + pl->second.name() || command == "metrics"
|
||||
|| command == "motd" || command == "wml" || command == "netstats") {
|
||||
response << process_command(command.to_string());
|
||||
|| command == "motd" || command == "wml" || command == "netstats" || command == "netstats all") {
|
||||
response << process_command(command.to_string(), pl->second.name());
|
||||
} else if (command == admin_passwd_) {
|
||||
LOG_SERVER << "New Admin recognized:" << "\tIP: "
|
||||
<< network::ip_address(sock) << "\tnick: "
|
||||
|
@ -890,7 +890,7 @@ void server::start_new_server() {
|
|||
LOG_SERVER << "New server started with command: " << restart_command << "\n";
|
||||
}
|
||||
|
||||
std::string server::process_command(const std::string& query) {
|
||||
std::string server::process_command(const std::string& query, const std::string& issuer_name) {
|
||||
std::ostringstream out;
|
||||
const std::string::const_iterator i = std::find(query.begin(),query.end(),' ');
|
||||
const std::string command(query.begin(),i);
|
||||
|
@ -908,7 +908,7 @@ std::string server::process_command(const std::string& query) {
|
|||
server_.stop();
|
||||
input_.stop();
|
||||
graceful_restart = true;
|
||||
process_command("msg The server is shutting down. You may finish your games but can't start new ones. Once all games have ended the server will exit.");
|
||||
process_command("msg The server is shutting down. You may finish your games but can't start new ones. Once all games have ended the server will exit.", issuer_name);
|
||||
out << "Server is doing graceful shut down.";
|
||||
}
|
||||
|
||||
|
@ -925,7 +925,7 @@ std::string server::process_command(const std::string& query) {
|
|||
input_.stop();
|
||||
// start new server
|
||||
start_new_server();
|
||||
process_command("msg The server has been restarted. You may finish your games but can't start new ones and new players can't join this server.");
|
||||
process_command("msg The server has been restarted. You may finish your games but can't start new ones and new players can't join this server.", issuer_name);
|
||||
out << "New server started.";
|
||||
}
|
||||
#endif
|
||||
|
@ -977,19 +977,27 @@ std::string server::process_command(const std::string& query) {
|
|||
<< stats.bytes_received << " bytes\n";
|
||||
}
|
||||
}
|
||||
} else if (command == "ban" || command == "bans" || command == "kban" || command == "kickban") {
|
||||
} else if (command == "ban" || command == "bans" || command == "kban" || command == "kickban" || command == "gban") {
|
||||
if (parameters == "") {
|
||||
ban_manager_.list_bans(out);
|
||||
} else {
|
||||
bool banned_ = false;
|
||||
const bool kick = (command == "kban" || command == "kickban");
|
||||
const std::string::iterator first_space = std::find(parameters.begin(), parameters.end(), ' ');
|
||||
const bool group_ban = command == "gban";
|
||||
std::string::iterator first_space = std::find(parameters.begin(), parameters.end(), ' ');
|
||||
if (first_space == parameters.end())
|
||||
{
|
||||
return ban_manager_.get_ban_help();
|
||||
}
|
||||
std::string::iterator second_space = std::find(first_space+1, parameters.end(), ' ');
|
||||
const std::string target(parameters.begin(), first_space);
|
||||
std::string group;
|
||||
if (group_ban)
|
||||
{
|
||||
group = std::string(first_space+1, second_space);
|
||||
first_space = second_space;
|
||||
second_space = std::find(first_space+1, parameters.end(), ' ');
|
||||
}
|
||||
const std::string time(first_space+1,second_space);
|
||||
time_t parsed_time = ban_manager_.parse_time(time);
|
||||
if (parsed_time == 0)
|
||||
|
@ -1003,13 +1011,19 @@ std::string server::process_command(const std::string& query) {
|
|||
}
|
||||
std::string reason(second_space + 1, parameters.end());
|
||||
utils::strip(reason);
|
||||
if (reason.empty())
|
||||
return ban_manager_.get_ban_help();
|
||||
|
||||
// if we find a '.' consider it an ip mask
|
||||
//! @todo FIXME: should also check for only numbers
|
||||
if (std::count(target.begin(), target.end(), '.') >= 1) {
|
||||
banned_ = true;
|
||||
out << "Set ban on '" << target << "' with end time '" << parsed_time << "' with reason: '" << reason << "'.\n";
|
||||
|
||||
ban_manager_.ban(target, parsed_time, reason);
|
||||
std::string err = ban_manager_.ban(target, parsed_time, reason, issuer_name, group);
|
||||
if (err.empty())
|
||||
out << "Set ban on '" << target << "' with end time '" << wesnothd::banned::get_human_end_time(parsed_time) << "' with reason: '" << reason << "'.\n";
|
||||
else
|
||||
out << err << "\n";
|
||||
|
||||
if (kick) {
|
||||
for (player_map::const_iterator pl = players_.begin();
|
||||
|
@ -1029,9 +1043,12 @@ std::string server::process_command(const std::string& query) {
|
|||
banned_ = true;
|
||||
const std::string& ip = network::ip_address(pl->first);
|
||||
if (!is_ip_banned(ip)) {
|
||||
ban_manager_.ban(ip,parsed_time, reason);
|
||||
out << "Set ban on '" << ip << "' with end time '" << parsed_time << "' with reason: '"
|
||||
<< reason << "'.\n";
|
||||
std::string err = ban_manager_.ban(ip,parsed_time, reason, issuer_name, group);
|
||||
if (err.empty())
|
||||
out << "Set ban on '" << ip << "' with end time '" << wesnothd::banned::get_human_end_time(parsed_time) << "' with reason: '"
|
||||
<< reason << "'.\n";
|
||||
else
|
||||
out << err << "\n";
|
||||
}
|
||||
if (kick) {
|
||||
out << "Kicked " << pl->second.name() << ".\n";
|
||||
|
@ -1049,6 +1066,11 @@ std::string server::process_command(const std::string& query) {
|
|||
return "You must enter an ipmask to unban.";
|
||||
}
|
||||
ban_manager_.unban(out, parameters);
|
||||
} else if (command == "ungban") {
|
||||
if (parameters == "") {
|
||||
return "You must enter an ipmask to unban.";
|
||||
}
|
||||
ban_manager_.unban_group(out, parameters);
|
||||
} else if (command == "kick") {
|
||||
if (parameters == "") {
|
||||
return "You must enter a mask to kick.";
|
||||
|
@ -1715,6 +1737,9 @@ int main(int argc, char** argv) {
|
|||
#endif
|
||||
std::string fifo_path = std::string(FIFODIR) + "/socket";
|
||||
|
||||
// setting path to currentworking directory
|
||||
game_config::path = get_cwd();
|
||||
|
||||
// show 'info' by default
|
||||
lg::set_log_domain_severity("server", 2);
|
||||
lg::timestamps(true);
|
||||
|
|
Loading…
Add table
Reference in a new issue