33 #define ERR_SERVER LOG_STREAM(err, log_server)
34 #define LOG_SERVER LOG_STREAM(info, log_server)
35 #define DBG_SERVER LOG_STREAM(debug, log_server)
39 return o <<
"IP: " <<
n.get_ip() <<
40 (
n.get_nick().empty() ?
"" :
" nick: " +
n.get_nick()) <<
41 " reason: '" <<
n.get_reason() <<
"'"
42 " start_time: " <<
n.get_human_start_time() <<
43 " end_time: " <<
n.get_human_end_time() <<
44 " issuer: " <<
n.get_who_banned();
61 return a->get_int_ip() <
b->get_int_ip();
73 , who_banned_(who_banned_default_)
83 const std::time_t end_time,
84 const std::string& reason,
85 const std::string& who_banned,
86 const std::string& group,
87 const std::string& nick)
92 , start_time_(std::time(0))
94 , who_banned_(who_banned)
110 , who_banned_(who_banned_default_)
124 std::vector<std::string> split_ip =
utils::split(ip,
'.');
125 if (split_ip.size() > 4)
throw banned::error(
"Malformed ip address: " + ip);
127 unsigned int shift = 4*8;
129 const unsigned int complete_part_mask = 0xFF;
130 auto part = split_ip.begin();
131 bool wildcard =
false;
135 if(part == split_ip.end()) {
147 unsigned int part_ip = lexical_cast_default<unsigned int>(*part, complete_part_mask + 1);
148 if(part_ip > complete_part_mask) {
152 ret.first |= (part_ip << shift);
153 ret.second |= (complete_part_mask << shift);
172 nick_ = cfg[
"nick"].str();
175 end_time_ = cfg[
"end_time"].to_time_t(0);
190 group_ = cfg[
"group"].str();
200 std::stringstream ss;
202 cfg[
"end_time"] = ss.str();
206 std::stringstream ss;
208 cfg[
"start_time"] = ss.str();
267 return (
ip_ &
mask_ & pair.second) == (pair.first & pair.second &
mask_);
284 auto new_ban = std::make_shared<banned>(
b);
285 assert(
bans_.insert(new_ban).second);
287 if (new_ban->get_end_time() != 0)
296 for(
const config&
b : cfg_del->child_range(
"ban")) {
298 auto new_ban = std::make_shared<banned>(
b);
301 ERR_SERVER <<
e.message <<
" while reading deleted bans";
317 for(
const auto&
b :
bans_) {
335 if (!time)
return false;
337 if(duration.substr(0, 4) ==
"TIME") {
339 loc = std::localtime(time);
341 std::size_t number = 0;
342 for(
auto i = duration.begin() + 4;
i != duration.end(); ++
i) {
348 loc->tm_year = number;
351 loc->tm_mon = number;
354 loc->tm_mday = number;
357 loc->tm_hour = number;
360 loc->tm_min = number;
363 loc->tm_sec = number;
366 LOG_SERVER <<
"Invalid time modifier given: '" << *
i <<
"'.";
376 const auto time_itor =
ban_times_.find(duration);
378 std::string dur_lower;
382 ERR_SERVER <<
"While parsing ban command duration string, caught an invalid utf8 exception: " <<
e.what();
386 if(dur_lower ==
"permanent" || duration ==
"0") {
389 *time += time_itor->second;
391 std::string::const_iterator
i = duration.begin();
393 for (std::string::const_iterator d_end = duration.end();
i != d_end; ++
i) {
396 if (number == -1) number = 0;
399 if (number == -1) number = 1;
404 if (++
i != d_end && tolower(*
i) ==
'e'
405 && ++
i != d_end && tolower(*
i) ==
'a'
406 && ++
i != d_end && tolower(*
i) ==
'r'
407 && ++
i != d_end && tolower(*
i) ==
's') {
409 *time += number * 365*24*60*60;
412 if (++
i != d_end && tolower(*
i) ==
'i') {
413 if (++
i != d_end && tolower(*
i) ==
'n'
414 && ++
i != d_end && tolower(*
i) ==
'u'
415 && ++
i != d_end && tolower(*
i) ==
't'
416 && ++
i != d_end && tolower(*
i) ==
'e'
417 && ++
i != d_end && tolower(*
i) ==
's') {
419 *time += number * 60;
423 if (++
i != d_end && tolower(*
i) ==
'o'
424 && ++
i != d_end && tolower(*
i) ==
'n'
425 && ++
i != d_end && tolower(*
i) ==
't'
426 && ++
i != d_end && tolower(*
i) ==
'h'
427 && ++
i != d_end && tolower(*
i) ==
's') {
429 *time += number * 30*24*60*60;
433 if (++
i != d_end && tolower(*
i) ==
'a'
434 && ++
i != d_end && tolower(*
i) ==
'y'
435 && ++
i != d_end && tolower(*
i) ==
's') {
437 *time += number * 24*60*60;
441 if (++
i != d_end && tolower(*
i) ==
'o'
442 && ++
i != d_end && tolower(*
i) ==
'u'
443 && ++
i != d_end && tolower(*
i) ==
'r'
444 && ++
i != d_end && tolower(*
i) ==
's') {
446 *time += number * 60*60;
449 if (++
i != d_end && tolower(*
i) ==
'o') {
450 if (++
i != d_end && tolower(*
i) ==
'n'
451 && ++
i != d_end && tolower(*
i) ==
't'
452 && ++
i != d_end && tolower(*
i) ==
'h'
453 && ++
i != d_end && tolower(*
i) ==
's') {
455 *time += number * 30*24*60*60;
459 if (++
i != d_end && tolower(*
i) ==
'i'
460 && ++
i != d_end && tolower(*
i) ==
'n'
461 && ++
i != d_end && tolower(*
i) ==
'u'
462 && ++
i != d_end && tolower(*
i) ==
't'
463 && ++
i != d_end && tolower(*
i) ==
'e'
464 && ++
i != d_end && tolower(*
i) ==
's') {
466 *time += number * 60;
470 if (++
i != d_end && tolower(*
i) ==
'e'
471 && ++
i != d_end && tolower(*
i) ==
'c'
472 && ++
i != d_end && tolower(*
i) ==
'o'
473 && ++
i != d_end && tolower(*
i) ==
'n'
474 && ++
i != d_end && tolower(*
i) ==
'd'
475 && ++
i != d_end && tolower(*
i) ==
's') {
488 *time += number * 60;
496 const std::time_t& end_time,
497 const std::string& reason,
498 const std::string& who_banned,
499 const std::string& group,
500 const std::string& nick)
502 std::ostringstream ret;
505 if((
ban =
bans_.find(std::make_shared<banned>(ip))) !=
bans_.end()) {
507 ret <<
"Overwriting ban: " << (**ban) <<
"\n";
511 ERR_SERVER <<
e.message <<
" while creating dummy ban for finding existing ban";
516 auto new_ban = std::make_shared<banned>(ip, end_time, reason, who_banned, group, nick);
517 bans_.insert(new_ban);
536 ban =
bans_.find(std::make_shared<banned>(ip));
544 os <<
"There is no ban on '" << ip <<
"'.";
549 os <<
"Ban on '" << **
ban <<
"' removed.";
554 if(immediate_write) {
562 std::insert_iterator<ban_set> temp_inserter(temp, temp.begin());
563 std::remove_copy_if(
bans_.begin(),
bans_.end(), temp_inserter, [&group](
const banned_ptr&
p) { return p->match_group(group); });
565 os <<
"Removed " << (
bans_.size() - temp.size()) <<
" bans";
576 if(
ban->get_end_time() > time_now) {
578 DBG_SERVER <<
"ban " <<
ban->get_ip() <<
" not removed. time: " << time_now <<
" end_time "
579 <<
ban->get_end_time();
584 LOG_SERVER <<
"Remove a ban " <<
ban->get_ip() <<
". time: " << time_now <<
" end_time " <<
ban->get_end_time();
585 std::ostringstream os;
597 out <<
"No removed bans found.";
605 out <<
"parse error: " <<
e.message;
609 out <<
"DELETED BANS LIST";
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));
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"
683 ban_help_ +=
"You can also use " + itor->first;
687 ban_help_ += std::string(
", ") + itor->first;
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;
Class for writing a config out to a file in pieces.
void write(const config &cfg)
A config object defines a single node in a WML file, with access to child nodes.
bool has_attribute(config_key_type key) const
child_itors child_range(config_key_type key)
optional_config_impl< config > optional_child(config_key_type key, int n=0)
Equivalent to mandatory_child, but returns an empty optional if the nth child was not found.
config & add_child(config_key_type key)
Thrown by operations encountering invalid UTF-8 data.
std::string ban(const std::string &, const std::time_t &, const std::string &, const std::string &, const std::string &, const std::string &="")
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 ...
void list_bans(std::ostringstream &out, const std::string &mask="*")
void unban(std::ostringstream &os, const std::string &ip, bool immediate_write=true)
default_ban_times ban_times_
void unban_group(std::ostringstream &os, const std::string &group)
bool is_digit(const char &c) const
std::size_t to_digit(const char &c) const
ban_time_queue time_queue_
void check_ban_times(std::time_t time_now)
std::string is_ip_banned(const std::string &ip)
deleted_ban_list deleted_bans_
void list_deleted_bans(std::ostringstream &out, const std::string &mask="*") const
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 match_ipmask(const ip_mask &ip) const
std::string get_human_start_time() const
unsigned int get_mask_ip(unsigned int) const
unsigned int mask() const
void read(const config &)
static const std::string who_banned_default_
std::string get_nick() const
bool operator>(const banned &b) const
void write(config &) const
bool match_ip(const ip_mask &ip) const
std::string get_human_end_time() const
std::string get_human_time_span() const
std::string get_ip() const
Definitions for the interface to Wesnoth Markup Language (WML).
Declarations for File-IO.
New lexcical_cast header.
Standard logging facilities (interface).
filesystem::scoped_istream istream_file(const std::string &fname, bool treat_failure_as_error)
static bool file_exists(const bfs::path &fpath)
filesystem::scoped_ostream ostream_file(const std::string &fname, std::ios_base::openmode mode, bool create_directory)
std::unique_ptr< std::istream > scoped_istream
std::unique_ptr< std::ostream > scoped_ostream
std::string get_timespan(const std::time_t &t)
std::string get_timestamp(const std::time_t &t, const std::string &format)
std::string lowercase(const std::string &s)
Returns a lowercased version of the string.
std::string get_unknown_exception_type()
Utility function for finding the type of thing caught with catch(...).
std::vector< std::string > split(const config_attribute_value &val)
std::ostream & operator<<(std::ostream &o, const banned &n)
std::set< banned_ptr, banned_compare_subnet > ban_set
static lg::log_domain log_server("server")
std::shared_ptr< banned > banned_ptr
ip_mask parse_ip(const std::string &ip)
std::pair< unsigned int, unsigned int > ip_mask
std::string::const_iterator iterator
void read_gz(config &cfg, std::istream &file, abstract_validator *validator)
Might throw a std::ios_base::failure especially a gzip_error.
bool operator()(const banned_ptr &a, const banned_ptr &b) const
static compare_fn active_
bool(banned_compare_subnet::* compare_fn)(const banned_ptr &a, const banned_ptr &b) const
bool less(const banned_ptr &a, const banned_ptr &b) const
bool operator()(const banned_ptr &a, const banned_ptr &b) const
static map_location::DIRECTION n