32 #define ERR_SERVER LOG_STREAM(err, log_server) 33 #define LOG_SERVER LOG_STREAM(info, log_server) 34 #define DBG_SERVER LOG_STREAM(debug, log_server) 38 return o <<
"IP: " << n.
get_ip() <<
55 return (this->*(active_))(
a,
b);
60 return a->get_int_ip() < b->get_int_ip();
72 , who_banned_(who_banned_default_)
82 const std::time_t end_time,
83 const std::string& reason,
84 const std::string& who_banned,
85 const std::string& group,
86 const std::string& nick)
123 std::vector<std::string> split_ip =
utils::split(ip,
'.');
124 if (split_ip.size() > 4)
throw banned::error(
"Malformed ip address: " + ip);
126 unsigned int shift = 4*8;
128 const unsigned int complete_part_mask = 0xFF;
129 auto part = split_ip.begin();
130 bool wildcard =
false;
134 if(part == split_ip.end()) {
146 unsigned int part_ip = lexical_cast_default<unsigned int>(*part, complete_part_mask + 1);
147 if(part_ip > complete_part_mask) {
151 ret.first |= (part_ip << shift);
152 ret.second |= (complete_part_mask << shift);
171 nick_ = cfg[
"nick"].str();
174 end_time_ = cfg[
"end_time"].to_time_t(0);
189 group_ = cfg[
"group"].str();
199 std::stringstream ss;
201 cfg[
"end_time"] = ss.str();
205 std::stringstream ss;
207 cfg[
"start_time"] = ss.str();
266 return (
ip_ &
mask_ & pair.second) == (pair.first & pair.second &
mask_);
283 auto new_ban = std::make_shared<banned>(
b);
284 assert(bans_.insert(new_ban).second);
286 if (new_ban->get_end_time() != 0)
287 time_queue_.push(new_ban);
295 for(
const config&
b : cfg_del.child_range(
"ban")) {
297 auto new_ban = std::make_shared<banned>(
b);
298 deleted_bans_.push_back(new_ban);
316 for(
const auto&
b : bans_) {
322 for(
const auto& db : deleted_bans_) {
334 if (!time)
return false;
336 if(duration.substr(0, 4) ==
"TIME") {
338 loc = std::localtime(time);
340 std::size_t number = 0;
341 for(
auto i = duration.begin() + 4;
i != duration.end(); ++
i) {
343 number = number * 10 + to_digit(*
i);
347 loc->tm_year = number;
350 loc->tm_mon = number;
353 loc->tm_mday = number;
356 loc->tm_hour = number;
359 loc->tm_min = number;
362 loc->tm_sec = number;
365 LOG_SERVER <<
"Invalid time modifier given: '" << *
i <<
"'.\n";
375 const auto time_itor = ban_times_.find(duration);
377 std::string dur_lower;
381 ERR_SERVER <<
"While parsing ban command duration string, caught an invalid utf8 exception: " << e.what() << std::endl;
385 if(dur_lower ==
"permanent" || duration ==
"0") {
387 }
else if(ban_times_.find(duration) != ban_times_.end()) {
388 *time += time_itor->second;
390 std::string::const_iterator
i = duration.begin();
392 for (std::string::const_iterator d_end = duration.end(); i != d_end; ++
i) {
395 if (number == -1) number = 0;
396 number = number * 10 + to_digit(*i);
398 if (number == -1) number = 1;
403 if (++i != d_end && tolower(*i) ==
'e' 404 && ++i != d_end && tolower(*i) ==
'a' 405 && ++i != d_end && tolower(*i) ==
'r' 406 && ++i != d_end && tolower(*i) ==
's') {
408 *time += number * 365*24*60*60;
411 if (++i != d_end && tolower(*i) ==
'i') {
412 if (++i != d_end && tolower(*i) ==
'n' 413 && ++i != d_end && tolower(*i) ==
'u' 414 && ++i != d_end && tolower(*i) ==
't' 415 && ++i != d_end && tolower(*i) ==
'e' 416 && ++i != d_end && tolower(*i) ==
's') {
418 *time += number * 60;
422 if (++i != d_end && tolower(*i) ==
'o' 423 && ++i != d_end && tolower(*i) ==
'n' 424 && ++i != d_end && tolower(*i) ==
't' 425 && ++i != d_end && tolower(*i) ==
'h' 426 && ++i != d_end && tolower(*i) ==
's') {
428 *time += number * 30*24*60*60;
432 if (++i != d_end && tolower(*i) ==
'a' 433 && ++i != d_end && tolower(*i) ==
'y' 434 && ++i != d_end && tolower(*i) ==
's') {
436 *time += number * 24*60*60;
440 if (++i != d_end && tolower(*i) ==
'o' 441 && ++i != d_end && tolower(*i) ==
'u' 442 && ++i != d_end && tolower(*i) ==
'r' 443 && ++i != d_end && tolower(*i) ==
's') {
445 *time += number * 60*60;
448 if (++i != d_end && tolower(*i) ==
'o') {
449 if (++i != d_end && tolower(*i) ==
'n' 450 && ++i != d_end && tolower(*i) ==
't' 451 && ++i != d_end && tolower(*i) ==
'h' 452 && ++i != d_end && tolower(*i) ==
's') {
454 *time += number * 30*24*60*60;
458 if (++i != d_end && tolower(*i) ==
'i' 459 && ++i != d_end && tolower(*i) ==
'n' 460 && ++i != d_end && tolower(*i) ==
'u' 461 && ++i != d_end && tolower(*i) ==
't' 462 && ++i != d_end && tolower(*i) ==
'e' 463 && ++i != d_end && tolower(*i) ==
's') {
465 *time += number * 60;
469 if (++i != d_end && tolower(*i) ==
'e' 470 && ++i != d_end && tolower(*i) ==
'c' 471 && ++i != d_end && tolower(*i) ==
'o' 472 && ++i != d_end && tolower(*i) ==
'n' 473 && ++i != d_end && tolower(*i) ==
'd' 474 && ++i != d_end && tolower(*i) ==
's') {
487 *time += number * 60;
495 const std::time_t& end_time,
496 const std::string& reason,
497 const std::string& who_banned,
498 const std::string& group,
499 const std::string& nick)
501 std::ostringstream ret;
504 if((ban = bans_.find(std::make_shared<banned>(ip))) != bans_.end()) {
506 ret <<
"Overwriting ban: " << (**ban) <<
"\n";
510 ERR_SERVER << e.
message <<
" while creating dummy ban for finding existing ban" << std::endl;
515 auto new_ban = std::make_shared<banned>(ip, end_time, reason, who_banned, group, nick);
516 bans_.insert(new_ban);
518 time_queue_.push(new_ban);
535 ban = bans_.find(std::make_shared<banned>(ip));
542 if(ban == bans_.end()) {
543 os <<
"There is no ban on '" << ip <<
"'.";
548 os <<
"Ban on '" << **ban <<
"' removed.";
550 if ((*ban)->get_group().empty()) deleted_bans_.push_back(*ban);
553 if(immediate_write) {
561 std::insert_iterator<ban_set> temp_inserter(temp, temp.begin());
562 std::remove_copy_if(bans_.begin(), bans_.end(), temp_inserter, [&group](
const banned_ptr&
p) {
return p->match_group(group); });
564 os <<
"Removed " << (bans_.size() - temp.size()) <<
" bans";
572 while(!time_queue_.empty()) {
575 if(ban->get_end_time() > time_now) {
577 DBG_SERVER <<
"ban " << ban->get_ip() <<
" not removed. time: " << time_now <<
" end_time " 578 << ban->get_end_time() <<
"\n";
583 LOG_SERVER <<
"Remove a ban " << ban->get_ip() <<
". time: " << time_now <<
" end_time " << ban->get_end_time()
585 std::ostringstream os;
586 unban(os, ban->get_ip(),
false);
596 if(deleted_bans_.empty()) {
597 out <<
"No removed bans found.";
605 out <<
"parse error: " << e.
message;
609 out <<
"DELETED BANS LIST";
610 for(deleted_ban_list::const_iterator
i = deleted_bans_.begin();
i != deleted_bans_.end(); ++
i) {
611 if((*i)->match_ipmask(pair)) {
612 out <<
"\n" << (**i);
621 out <<
"No bans set.";
629 out <<
"parse error: " << e.
message;
634 std::set<std::string> groups;
636 for(
const auto&
b : bans_) {
637 if(
b->get_group().empty()) {
638 if(
b->match_ipmask(pair)) {
642 groups.insert(
b->get_group());
647 if(!groups.empty() && mask ==
"*") {
648 out <<
"\nban groups: ";
650 out << *groups.begin();
651 std::ostream& (*fn)(std::ostream&,
const std::string&) = &std::operator<<;
652 std::for_each(++groups.begin(), groups.end(),
653 std::bind(fn, std::bind(fn, std::ref(out), std::string(
", ")), std::placeholders::_1));
667 auto ban = std::find_if(bans_.begin(), bans_.end(), [pair](
const banned_ptr&
p) {
return p->match_ip(pair); });
668 if (ban == bans_.end())
return "";
669 const std::string& nick = (*ban)->get_nick();
670 return (*ban)->get_reason() + (nick.empty() ?
"" :
" (" + nick +
")") +
" (Remaining ban duration: " + (*ban)->get_human_time_span() +
")";
675 ban_help_ =
"ban <mask> <time> <reason>\n" 676 "The time format is: %d[%s[%d[%s[...]]]] where %s is a time" 677 " modifier: s or S (seconds), m (minutes), h or H (hours), d" 678 " or D (days), M (months) or y or Y (years) and %d is a number.\n" 679 "Permanent bans can be set with 'permanent' or '0' as the time" 681 auto itor = ban_times_.begin();
682 if(itor != ban_times_.end()) {
683 ban_help_ +=
"You can also use " + itor->first;
686 for(; itor != ban_times_.end(); ++itor) {
687 ban_help_ += std::string(
", ") + itor->first;
689 if(!ban_times_.empty()) {
690 ban_help_ +=
" for standard ban times. (not combinable)\n";
692 ban_help_ +=
"ban 127.0.0.1 2h20m flooded lobby\n" 693 "kban suokko 5D flooded again\n" 694 "kban suokko Y One year ban for constant flooding";
701 std::time_t duration = 0;
702 if(parse_time(bt[
"time"], &duration)) {
703 ban_times_.emplace(bt[
"name"], duration);
bool(banned_compare_subnet::* compare_fn)(const banned_ptr &a, const banned_ptr &b) const
bool match_ipmask(const ip_mask &ip) const
std::string get_reason() const
std::string get_timestamp(const std::time_t &t, const std::string &format)
config & child(config_key_type key, int n=0)
Returns the nth child with the given key, or a reference to an invalid config if there is none...
void write(const config &cfg)
std::string get_timespan(const std::time_t &t)
void load_config(const config &)
banned(const std::string &ip, const std::time_t end_time, const std::string &reason, const std::string &who_banned=who_banned_default_, const std::string &group="", const std::string &nick="")
bool less(const banned_ptr &a, const banned_ptr &b) const
New lexcical_cast header.
bool has_attribute(config_key_type key) const
void check_ban_times(std::time_t time_now)
std::string is_ip_banned(const std::string &ip)
static bool file_exists(const bfs::path &fpath)
std::time_t get_end_time() const
child_itors child_range(config_key_type key)
std::string get_human_end_time() const
filesystem::scoped_istream istream_file(const std::string &fname, bool treat_failure_as_error)
void read_gz(config &cfg, std::istream &file, abstract_validator *validator)
Might throw a std::ios_base::failure especially a gzip_error.
Definitions for the interface to Wesnoth Markup Language (WML).
filesystem::scoped_ostream ostream_file(const std::string &fname, std::ios_base::openmode mode, bool create_directory)
static compare_fn active_
std::pair< unsigned int, unsigned int > ip_mask
std::shared_ptr< banned > banned_ptr
std::string get_who_banned() const
void read(const config &)
static lg::log_domain log_server("server")
void unban_group(std::ostringstream &os, const std::string &group)
Class for writing a config out to a file in pieces.
void list_deleted_bans(std::ostringstream &out, const std::string &mask="*") const
std::string ban(const std::string &, const std::time_t &, const std::string &, const std::string &, const std::string &, const std::string &="")
bool operator()(const banned_ptr &a, const banned_ptr &b) const
std::string get_human_start_time() const
std::unique_ptr< std::istream > scoped_istream
ip_mask parse_ip(const std::string &ip)
unsigned int mask() const
std::unique_ptr< std::ostream > scoped_ostream
Thrown by operations encountering invalid UTF-8 data.
std::ostream & operator<<(std::ostream &o, const banned &n)
void write(config &) const
std::string get_nick() const
std::set< banned_ptr, banned_compare_subnet > ban_set
static const std::string who_banned_default_
Declarations for File-IO.
std::string lowercase(const std::string &s)
Returns a lowercased version of the string.
config & add_child(config_key_type key)
void list_bans(std::ostringstream &out, const std::string &mask="*")
bool match_ip(const ip_mask &ip) const
std::vector< std::string > split(const config_attribute_value &val)
std::string get_ip() const
void unban(std::ostringstream &os, const std::string &ip, bool immediate_write=true)
bool parse_time(const std::string &duration, std::time_t *time) const
Parses the given duration and adds it to *time except if the duration is '0' or 'permanent' in which ...
Standard logging facilities (interface).
unsigned int get_mask_ip(unsigned int) const
bool operator>(const banned &b) const
std::string get_human_time_span() const
A config object defines a single node in a WML file, with access to child nodes.
static map_location::DIRECTION n
std::string::const_iterator iterator
bool operator()(const banned_ptr &a, const banned_ptr &b) const