34 #define ERR_SERVER LOG_STREAM(err, log_server)
35 #define LOG_SERVER LOG_STREAM(info, log_server)
36 #define DBG_SERVER LOG_STREAM(debug, log_server)
40 return o <<
"IP: " <<
n.get_ip() <<
41 (
n.get_nick().empty() ?
"" :
" nick: " +
n.get_nick()) <<
42 " reason: '" <<
n.get_reason() <<
"'"
43 " start_time: " <<
n.get_human_start_time() <<
44 " end_time: " <<
n.get_human_end_time() <<
45 " issuer: " <<
n.get_who_banned();
62 return a->get_int_ip() <
b->get_int_ip();
74 , who_banned_(who_banned_default_)
84 const utils::optional<std::chrono::system_clock::time_point>& end_time,
85 const std::string& reason,
86 const std::string& who_banned,
87 const std::string& group,
88 const std::string& nick)
93 , start_time_(std::
chrono::system_clock::now())
95 , who_banned_(who_banned)
111 , who_banned_(who_banned_default_)
125 std::vector<std::string> split_ip =
utils::split(ip,
'.');
126 if (split_ip.size() > 4)
throw banned::error(
"Malformed ip address: " + ip);
128 unsigned int shift = 4*8;
130 const unsigned int complete_part_mask = 0xFF;
131 auto part = split_ip.begin();
132 bool wildcard =
false;
136 if(part == split_ip.end()) {
148 unsigned int part_ip = lexical_cast_default<unsigned int>(*part, complete_part_mask + 1);
149 if(part_ip > complete_part_mask) {
153 ret.first |= (part_ip << shift);
154 ret.second |= (complete_part_mask << shift);
173 nick_ = cfg[
"nick"].str();
191 group_ = cfg[
"group"].str();
222 const auto time_left = *
end_time_ - std::chrono::system_clock::now();
223 return std::chrono::duration_cast<std::chrono::seconds>(time_left);
249 static constexpr std::chrono::system_clock::time_point epoch;
250 return end_time_.value_or(epoch) >
b.get_end_time().value_or(epoch);
266 return (
ip_ &
mask_ & pair.second) == (pair.first & pair.second &
mask_);
282 auto new_ban = std::make_shared<banned>(
b);
283 assert(
bans_.insert(new_ban).second);
285 if (new_ban->get_end_time())
294 for(
const config&
b : cfg_del->child_range(
"ban")) {
296 auto new_ban = std::make_shared<banned>(
b);
299 ERR_SERVER <<
e.message <<
" while reading deleted bans";
315 for(
const auto&
b :
bans_) {
332 const std::string& duration, std::chrono::system_clock::time_point start_time)
const
334 if(duration.substr(0, 4) ==
"TIME") {
335 std::size_t number = 0;
336 for(
auto i = duration.begin() + 4;
i != duration.end(); ++
i) {
351 start_time += std::chrono::hours{number};
354 start_time += std::chrono::minutes{number};
357 start_time += std::chrono::seconds{number};
360 LOG_SERVER <<
"Invalid time modifier given: '" << *
i <<
"'.";
366 return {
true, start_time };
369 std::string dur_lower;
373 ERR_SERVER <<
"While parsing ban command duration string, caught an invalid utf8 exception: " <<
e.what();
374 return {
false, utils::nullopt };
377 if(dur_lower ==
"permanent" || duration ==
"0") {
378 return {
true, utils::nullopt };
380 return {
true, start_time + time_itor->second };
382 std::string::const_iterator
i = duration.begin();
384 for (std::string::const_iterator d_end = duration.end();
i != d_end; ++
i) {
387 if (number == -1) number = 0;
390 if (number == -1) number = 1;
395 if (++
i != d_end && tolower(*
i) ==
'e'
396 && ++
i != d_end && tolower(*
i) ==
'a'
397 && ++
i != d_end && tolower(*
i) ==
'r'
398 && ++
i != d_end && tolower(*
i) ==
's') {
403 if (++
i != d_end && tolower(*
i) ==
'i') {
404 if (++
i != d_end && tolower(*
i) ==
'n'
405 && ++
i != d_end && tolower(*
i) ==
'u'
406 && ++
i != d_end && tolower(*
i) ==
't'
407 && ++
i != d_end && tolower(*
i) ==
'e'
408 && ++
i != d_end && tolower(*
i) ==
's') {
410 start_time += std::chrono::minutes{number};
414 if (++
i != d_end && tolower(*
i) ==
'o'
415 && ++
i != d_end && tolower(*
i) ==
'n'
416 && ++
i != d_end && tolower(*
i) ==
't'
417 && ++
i != d_end && tolower(*
i) ==
'h'
418 && ++
i != d_end && tolower(*
i) ==
's') {
424 if (++
i != d_end && tolower(*
i) ==
'a'
425 && ++
i != d_end && tolower(*
i) ==
'y'
426 && ++
i != d_end && tolower(*
i) ==
's') {
432 if (++
i != d_end && tolower(*
i) ==
'o'
433 && ++
i != d_end && tolower(*
i) ==
'u'
434 && ++
i != d_end && tolower(*
i) ==
'r'
435 && ++
i != d_end && tolower(*
i) ==
's') {
437 start_time += std::chrono::hours{number};
440 if (++
i != d_end && tolower(*
i) ==
'o') {
441 if (++
i != d_end && tolower(*
i) ==
'n'
442 && ++
i != d_end && tolower(*
i) ==
't'
443 && ++
i != d_end && tolower(*
i) ==
'h'
444 && ++
i != d_end && tolower(*
i) ==
's') {
450 if (++
i != d_end && tolower(*
i) ==
'i'
451 && ++
i != d_end && tolower(*
i) ==
'n'
452 && ++
i != d_end && tolower(*
i) ==
'u'
453 && ++
i != d_end && tolower(*
i) ==
't'
454 && ++
i != d_end && tolower(*
i) ==
'e'
455 && ++
i != d_end && tolower(*
i) ==
's') {
457 start_time += std::chrono::minutes{number};
461 if (++
i != d_end && tolower(*
i) ==
'e'
462 && ++
i != d_end && tolower(*
i) ==
'c'
463 && ++
i != d_end && tolower(*
i) ==
'o'
464 && ++
i != d_end && tolower(*
i) ==
'n'
465 && ++
i != d_end && tolower(*
i) ==
'd'
466 && ++
i != d_end && tolower(*
i) ==
's') {
468 start_time += std::chrono::seconds{number};
471 return {
false, utils::nullopt };
479 start_time += std::chrono::minutes{number};
482 return {
true, start_time };
487 const utils::optional<std::chrono::system_clock::time_point>& end_time,
488 const std::string& reason,
489 const std::string& who_banned,
490 const std::string& group,
491 const std::string& nick)
493 std::ostringstream ret;
496 if((
ban =
bans_.find(std::make_shared<banned>(ip))) !=
bans_.end()) {
498 ret <<
"Overwriting ban: " << (**ban) <<
"\n";
502 ERR_SERVER <<
e.message <<
" while creating dummy ban for finding existing ban";
507 auto new_ban = std::make_shared<banned>(ip, end_time, reason, who_banned, group, nick);
508 bans_.insert(new_ban);
527 ban =
bans_.find(std::make_shared<banned>(ip));
535 os <<
"There is no ban on '" << ip <<
"'.";
540 os <<
"Ban on '" << **
ban <<
"' removed.";
545 if(immediate_write) {
553 std::insert_iterator<ban_set> temp_inserter(temp, temp.begin());
554 std::remove_copy_if(
bans_.begin(),
bans_.end(), temp_inserter, [&group](
const banned_ptr&
p) { return p->match_group(group); });
556 os <<
"Removed " << (
bans_.size() - temp.size()) <<
" bans";
566 const auto& end_time =
ban->get_end_time();
568 if(!end_time || *end_time > time_now) {
571 <<
"Ban on " <<
ban->get_ip() <<
" not removed."
579 <<
"Removing ban on " <<
ban->get_ip() <<
"."
582 std::ostringstream os;
594 out <<
"No removed bans found.";
602 out <<
"parse error: " <<
e.message;
606 out <<
"DELETED BANS LIST";
608 if((*i)->match_ipmask(pair)) {
609 out <<
"\n" << (**i);
618 out <<
"No bans set.";
626 out <<
"parse error: " <<
e.message;
631 std::set<std::string> groups;
633 for(
const auto&
b :
bans_) {
634 if(
b->get_group().empty()) {
635 if(
b->match_ipmask(pair)) {
639 groups.insert(
b->get_group());
644 if(!groups.empty() && mask ==
"*") {
645 out <<
"\nban groups: ";
647 out << *groups.begin();
648 std::ostream& (*fn)(std::ostream&,
const std::string&) = &std::operator<<;
649 std::for_each(++groups.begin(), groups.end(),
650 std::bind(fn, std::bind(fn, std::ref(out), std::string(
", ")), std::placeholders::_1));
670 ban_help_ =
"ban <mask> <time> <reason>\n"
671 "The time format is: %d[%s[%d[%s[...]]]] where %s is a time"
672 " modifier: s or S (seconds), m (minutes), h or H (hours), d"
673 " or D (days), M (months) or y or Y (years) and %d is a number.\n"
674 "Permanent bans can be set with 'permanent' or '0' as the time"
678 ban_help_ +=
"You can also use " + itor->first;
682 ban_help_ += std::string(
", ") + itor->first;
685 ban_help_ +=
" for standard ban times. (not combinable)\n";
687 ban_help_ +=
"ban 127.0.0.1 2h20m flooded lobby\n"
688 "kban suokko 5D flooded again\n"
689 "kban suokko Y One year ban for constant flooding";
697 auto [success, end_time] =
parse_time(bt[
"time"], {});
700 auto duration = end_time.value_or(decltype(end_time)::value_type{}).time_since_epoch();
701 ban_times_.emplace(bt[
"name"], std::chrono::duration_cast<std::chrono::seconds>(duration));
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 &ip, const utils::optional< std::chrono::system_clock::time_point > &end_time, const std::string &reason, const std::string &who_banned, const std::string &group, const std::string &nick="")
void list_bans(std::ostringstream &out, const std::string &mask="*")
void unban(std::ostringstream &os, const std::string &ip, bool immediate_write=true)
std::pair< bool, utils::optional< std::chrono::system_clock::time_point > > parse_time(const std::string &duration, std::chrono::system_clock::time_point start_time) const
Parses the given duration and adds it to *time except if the duration is '0' or 'permanent' in which ...
void check_ban_times(const std::chrono::system_clock::time_point &time_now)
default_ban_times ban_times_
banned_ptr get_ban_info(const std::string &ip)
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_
deleted_ban_list deleted_bans_
void list_deleted_bans(std::ostringstream &out, const std::string &mask="*") const
void load_config(const config &)
utils::optional< std::chrono::system_clock::time_point > start_time_
bool match_ipmask(const ip_mask &ip) const
utils::optional< std::chrono::seconds > get_remaining_ban_time() const
Returns the seconds remaining until than ban expires, or nullopt if permanent.
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
banned(const std::string &ip, const utils::optional< std::chrono::system_clock::time_point > &end_time, const std::string &reason, const std::string &who_banned=who_banned_default_, const std::string &group="", const std::string &nick="")
bool match_ip(const ip_mask &ip) const
std::string get_human_end_time() const
std::string get_ip() const
utils::optional< std::chrono::system_clock::time_point > end_time_
Definitions for the interface to Wesnoth Markup Language (WML).
Declarations for File-IO.
New lexcical_cast header.
Standard logging facilities (interface).
std::chrono::duration< int, std::ratio< 2629746 > > months
auto serialize_timestamp(const std::chrono::system_clock::time_point &time)
auto parse_timestamp(long long val)
auto format_local_timestamp(const std::chrono::system_clock::time_point &time, std::string_view format="%F %T")
std::chrono::duration< int, std::ratio< 31556952 > > years
std::chrono::duration< int, std::ratio< 86400 > > days
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
config read_gz(std::istream &file, abstract_validator *validator)
Might throw a std::ios_base::failure especially a gzip_error.
std::string lowercase(std::string_view 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
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