31 #define ERR_SERVER LOG_STREAM(err, log_server) 32 #define LOG_SERVER LOG_STREAM(info, log_server) 33 #define DBG_SERVER LOG_STREAM(debug, log_server) 37 return o <<
"IP: " << n.
get_ip() <<
54 return (this->*(active_))(
a,
b);
59 return a->get_int_ip() < b->get_int_ip();
71 , who_banned_(who_banned_default_)
81 const std::time_t end_time,
82 const std::string& reason,
83 const std::string& who_banned,
84 const std::string& group,
85 const std::string& nick)
122 std::vector<std::string> split_ip =
utils::split(ip,
'.');
123 if (split_ip.size() > 4)
throw banned::error(
"Malformed ip address: " + ip);
125 unsigned int shift = 4*8;
126 unsigned int mask = 0xFF000000;
127 const unsigned int complete_part_mask = 0xFF;
128 auto part = split_ip.begin();
129 bool wildcard =
false;
133 if(part == split_ip.end()) {
145 unsigned int part_ip = lexical_cast_default<unsigned int>(*part, complete_part_mask + 1);
146 if(part_ip > complete_part_mask) {
150 ret.first |= (part_ip << shift);
151 ret.second |= (complete_part_mask << shift);
170 nick_ = cfg[
"nick"].str();
173 end_time_ = cfg[
"end_time"].to_time_t(0);
188 group_ = cfg[
"group"].str();
198 std::stringstream ss;
200 cfg[
"end_time"] = ss.str();
204 std::stringstream ss;
206 cfg[
"start_time"] = ss.str();
265 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() != 0)
286 time_queue_.push(new_ban);
294 for(
const config&
b : cfg_del.child_range(
"ban")) {
296 auto new_ban = std::make_shared<banned>(
b);
297 deleted_bans_.push_back(new_ban);
315 for(
const auto&
b : bans_) {
321 for(
const auto& db : deleted_bans_) {
333 if (!time)
return false;
335 if(duration.substr(0, 4) ==
"TIME") {
337 loc = std::localtime(time);
339 std::size_t number = 0;
340 for(
auto i = duration.begin() + 4;
i != duration.end(); ++
i) {
342 number = number * 10 + to_digit(*
i);
346 loc->tm_year = number;
349 loc->tm_mon = number;
352 loc->tm_mday = number;
355 loc->tm_hour = number;
358 loc->tm_min = number;
361 loc->tm_sec = number;
364 LOG_SERVER <<
"Invalid time modifier given: '" << *
i <<
"'.\n";
374 const auto time_itor = ban_times_.find(duration);
376 std::string dur_lower;
380 ERR_SERVER <<
"While parsing ban command duration string, caught an invalid utf8 exception: " << e.what() << std::endl;
384 if(dur_lower ==
"permanent" || duration ==
"0") {
386 }
else if(ban_times_.find(duration) != ban_times_.end()) {
387 *time += time_itor->second;
389 std::string::const_iterator
i = duration.begin();
391 for (std::string::const_iterator d_end = duration.end(); i != d_end; ++
i) {
394 if (number == -1) number = 0;
395 number = number * 10 + to_digit(*i);
397 if (number == -1) number = 1;
402 if (++i != d_end && tolower(*i) ==
'e' 403 && ++i != d_end && tolower(*i) ==
'a' 404 && ++i != d_end && tolower(*i) ==
'r' 405 && ++i != d_end && tolower(*i) ==
's') {
407 *time += number * 365*24*60*60;
410 if (++i != d_end && tolower(*i) ==
'i') {
411 if (++i != d_end && tolower(*i) ==
'n' 412 && ++i != d_end && tolower(*i) ==
'u' 413 && ++i != d_end && tolower(*i) ==
't' 414 && ++i != d_end && tolower(*i) ==
'e' 415 && ++i != d_end && tolower(*i) ==
's') {
417 *time += number * 60;
421 if (++i != d_end && tolower(*i) ==
'o' 422 && ++i != d_end && tolower(*i) ==
'n' 423 && ++i != d_end && tolower(*i) ==
't' 424 && ++i != d_end && tolower(*i) ==
'h' 425 && ++i != d_end && tolower(*i) ==
's') {
427 *time += number * 30*24*60*60;
431 if (++i != d_end && tolower(*i) ==
'a' 432 && ++i != d_end && tolower(*i) ==
'y' 433 && ++i != d_end && tolower(*i) ==
's') {
435 *time += number * 24*60*60;
439 if (++i != d_end && tolower(*i) ==
'o' 440 && ++i != d_end && tolower(*i) ==
'u' 441 && ++i != d_end && tolower(*i) ==
'r' 442 && ++i != d_end && tolower(*i) ==
's') {
444 *time += number * 60*60;
447 if (++i != d_end && tolower(*i) ==
'o') {
448 if (++i != d_end && tolower(*i) ==
'n' 449 && ++i != d_end && tolower(*i) ==
't' 450 && ++i != d_end && tolower(*i) ==
'h' 451 && ++i != d_end && tolower(*i) ==
's') {
453 *time += number * 30*24*60*60;
457 if (++i != d_end && tolower(*i) ==
'i' 458 && ++i != d_end && tolower(*i) ==
'n' 459 && ++i != d_end && tolower(*i) ==
'u' 460 && ++i != d_end && tolower(*i) ==
't' 461 && ++i != d_end && tolower(*i) ==
'e' 462 && ++i != d_end && tolower(*i) ==
's') {
464 *time += number * 60;
468 if (++i != d_end && tolower(*i) ==
'e' 469 && ++i != d_end && tolower(*i) ==
'c' 470 && ++i != d_end && tolower(*i) ==
'o' 471 && ++i != d_end && tolower(*i) ==
'n' 472 && ++i != d_end && tolower(*i) ==
'd' 473 && ++i != d_end && tolower(*i) ==
's') {
486 *time += number * 60;
494 const std::time_t& end_time,
495 const std::string& reason,
496 const std::string& who_banned,
497 const std::string& group,
498 const std::string& nick)
500 std::ostringstream ret;
503 if((ban = bans_.find(std::make_shared<banned>(ip))) != bans_.end()) {
505 ret <<
"Overwriting ban: " << (**ban) <<
"\n";
509 ERR_SERVER << e.
message <<
" while creating dummy ban for finding existing ban" << std::endl;
514 auto new_ban = std::make_shared<banned>(ip, end_time, reason, who_banned, group, nick);
515 bans_.insert(new_ban);
517 time_queue_.push(new_ban);
534 ban = bans_.find(std::make_shared<banned>(ip));
541 if(ban == bans_.end()) {
542 os <<
"There is no ban on '" << ip <<
"'.";
547 os <<
"Ban on '" << **ban <<
"' removed.";
549 if ((*ban)->get_group().empty()) deleted_bans_.push_back(*ban);
552 if(immediate_write) {
560 std::insert_iterator<ban_set> temp_inserter(temp, temp.begin());
561 std::remove_copy_if(bans_.begin(), bans_.end(), temp_inserter, [&group](
const banned_ptr&
p) {
return p->match_group(group); });
563 os <<
"Removed " << (bans_.size() - temp.size()) <<
" bans";
571 while(!time_queue_.empty()) {
574 if(ban->get_end_time() > time_now) {
576 DBG_SERVER <<
"ban " << ban->get_ip() <<
" not removed. time: " << time_now <<
" end_time " 577 << ban->get_end_time() <<
"\n";
582 LOG_SERVER <<
"Remove a ban " << ban->get_ip() <<
". time: " << time_now <<
" end_time " << ban->get_end_time()
584 std::ostringstream os;
585 unban(os, ban->get_ip(),
false);
595 if(deleted_bans_.empty()) {
596 out <<
"No removed bans found.";
604 out <<
"parse error: " << e.
message;
608 out <<
"DELETED BANS LIST";
609 for(deleted_ban_list::const_iterator
i = deleted_bans_.begin();
i != deleted_bans_.end(); ++
i) {
610 if((*i)->match_ipmask(pair)) {
611 out <<
"\n" << (**i);
620 out <<
"No bans set.";
628 out <<
"parse error: " << e.
message;
633 std::set<std::string> groups;
635 for(
const auto&
b : bans_) {
636 if(
b->get_group().empty()) {
637 if(
b->match_ipmask(pair)) {
641 groups.insert(
b->get_group());
646 if(!groups.empty() && mask ==
"*") {
647 out <<
"\nban groups: ";
649 out << *groups.begin();
650 std::ostream& (*fn)(std::ostream&,
const std::string&) = &std::operator<<;
651 std::for_each(++groups.begin(), groups.end(),
652 std::bind(fn, std::bind(fn, std::ref(out), std::string(
", ")), std::placeholders::_1));
666 auto ban = std::find_if(bans_.begin(), bans_.end(), [pair](
const banned_ptr&
p) {
return p->match_ip(pair); });
667 if (ban == bans_.end())
return "";
668 const std::string& nick = (*ban)->get_nick();
669 return (*ban)->get_reason() + (nick.empty() ?
"" :
" (" + nick +
")") +
" (Remaining ban duration: " + (*ban)->get_human_time_span() +
")";
674 ban_help_ =
"ban <mask> <time> <reason>\n" 675 "The time format is: %d[%s[%d[%s[...]]]] where %s is a time" 676 " modifier: s or S (seconds), m (minutes), h or H (hours), d" 677 " or D (days), M (months) or y or Y (years) and %d is a number.\n" 678 "Permanent bans can be set with 'permanent' or '0' as the time" 680 auto itor = ban_times_.begin();
681 if(itor != ban_times_.end()) {
682 ban_help_ +=
"You can also use " + itor->first;
685 for(; itor != ban_times_.end(); ++itor) {
686 ban_help_ += std::string(
", ") + itor->first;
688 if(!ban_times_.empty()) {
689 ban_help_ +=
" for standard ban times. (not combinable)\n";
691 ban_help_ +=
"ban 127.0.0.1 2h20m flooded lobby\n" 692 "kban suokko 5D flooded again\n" 693 "kban suokko Y One year ban for constant flooding";
700 std::time_t duration = 0;
701 if(parse_time(bt[
"time"], &duration)) {
702 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
static l_noret error(LoadState *S, const char *why)
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).
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.
static int writer(lua_State *L, const void *b, size_t size, void *B)
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
filesystem::scoped_ostream ostream_file(const std::string &fname, bool create_directory)