The Battle for Wesnoth  1.19.10+dev
ban.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2008 - 2025
3  by Pauli Nieminen <paniemin@cc.hut.fi>
4  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
5 
6  This program is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation; either version 2 of the License, or
9  (at your option) any later version.
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY.
12 
13  See the COPYING file for more details.
14 */
15 
16 #include "config.hpp"
17 #include "filesystem.hpp"
18 #include "lexical_cast.hpp"
19 #include "log.hpp"
21 #include "serialization/chrono.hpp"
22 #include "serialization/parser.hpp"
25 #include "utils/general.hpp"
26 
27 #include "server/wesnothd/ban.hpp"
28 
29 #include <functional>
30 
31 namespace wesnothd
32 {
33 static lg::log_domain log_server("server");
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)
37 
38 std::ostream& operator<<(std::ostream& o, const banned& n)
39 {
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();
46 }
47 
48 bool banned_compare::operator()(const banned_ptr& a, const banned_ptr& b) const
49 {
50  return (*a) > (*b);
51 }
52 
54 
56 {
57  return (this->*(active_))(a,b);
58 }
59 
60 bool banned_compare_subnet::less(const banned_ptr& a, const banned_ptr& b) const
61 {
62  return a->get_int_ip() < b->get_int_ip();
63 }
64 
65 const std::string banned::who_banned_default_ = "system";
66 
67 banned::banned(const std::string& ip)
68  : ip_(0)
69  , mask_(0)
70  , ip_text_()
71  , end_time_()
72  , start_time_()
73  , reason_()
74  , who_banned_(who_banned_default_)
75  , group_()
76  , nick_()
77 {
78  ip_mask pair = parse_ip(ip);
79  ip_ = pair.first;
80  mask_ = 0xFFFFFFFF;
81 }
82 
83 banned::banned(const std::string& ip,
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)
89  : ip_(0)
90  , mask_(0)
91  , ip_text_(ip)
92  , end_time_(end_time)
93  , start_time_(std::chrono::system_clock::now())
94  , reason_(reason)
95  , who_banned_(who_banned)
96  , group_(group)
97  , nick_(nick)
98 {
99  ip_mask pair = parse_ip(ip_text_);
100  ip_ = pair.first;
101  mask_ = pair.second;
102 }
103 
105  : ip_(0)
106  , mask_(0)
107  , ip_text_()
108  , end_time_()
109  , start_time_()
110  , reason_()
111  , who_banned_(who_banned_default_)
112  , group_()
113  , nick_()
114 {
115  read(cfg);
116 }
117 
118 ip_mask parse_ip(const std::string& ip)
119 {
120  // We use bit operations to construct the integer
121  // ip_mask is a pair: first is ip and second is mask
122  ip_mask ret;
123  ret.first = 0;
124  ret.second = 0;
125  std::vector<std::string> split_ip = utils::split(ip, '.');
126  if (split_ip.size() > 4) throw banned::error("Malformed ip address: " + ip);
127 
128  unsigned int shift = 4*8; // start shifting from the highest byte
129  //unsigned int mask = 0xFF000000;
130  const unsigned int complete_part_mask = 0xFF;
131  auto part = split_ip.begin();
132  bool wildcard = false;
133  do {
134  shift -= 8;
135  //mask >>= 8;
136  if(part == split_ip.end()) {
137  if(!wildcard)
138  throw banned::error("Malformed ip address: '" + ip + "'");
139  // Adding 0 to ip and mask is nop
140  // we can then break out of loop
141  break;
142  } else {
143  if(*part == "*") {
144  wildcard = true;
145  // Adding 0 to ip and mask is nop
146  } else {
147  // wildcard = false;
148  unsigned int part_ip = lexical_cast_default<unsigned int>(*part, complete_part_mask + 1);
149  if(part_ip > complete_part_mask) {
150  throw banned::error("Malformed ip address: '" + ip + "'");
151  }
152 
153  ret.first |= (part_ip << shift);
154  ret.second |= (complete_part_mask << shift);
155  }
156  }
157  ++part;
158  } while(shift);
159 
160  return ret;
161 }
162 
163 void banned::read(const config& cfg)
164 {
165  {
166  // parse ip and mask
167  ip_text_ = cfg["ip"].str();
168  ip_mask pair = parse_ip(ip_text_);
169  ip_ = pair.first;
170  mask_ = pair.second;
171  }
172 
173  nick_ = cfg["nick"].str();
174 
175  if(cfg.has_attribute("end_time")) {
176  end_time_ = chrono::parse_timestamp(cfg["end_time"]);
177  }
178 
179  if(cfg.has_attribute("start_time")) {
180  start_time_ = chrono::parse_timestamp(cfg["start_time"]);
181  }
182 
183  reason_ = cfg["reason"].str();
184 
185  // only overwrite defaults if exists
186  if(cfg.has_attribute("who_banned")) {
187  who_banned_ = cfg["who_banned"].str();
188  }
189 
190  if(cfg.has_attribute("group")) {
191  group_ = cfg["group"].str();
192  }
193 }
194 
195 void banned::write(config& cfg) const
196 {
197  cfg["ip"] = get_ip();
198  cfg["nick"] = get_nick();
199 
200  if(end_time_) {
201  cfg["end_time"] = chrono::serialize_timestamp(*end_time_);
202  }
203 
204  if(start_time_) {
205  cfg["start_time"] = chrono::serialize_timestamp(*start_time_);
206  }
207 
208  cfg["reason"] = reason_;
209 
211  cfg["who_banned"] = who_banned_;
212  }
213 
214  if(!group_.empty()) {
215  cfg["group"] = group_;
216  }
217 }
218 
219 utils::optional<std::chrono::seconds> banned::get_remaining_ban_time() const
220 {
221  if(end_time_) {
222  const auto time_left = *end_time_ - std::chrono::system_clock::now();
223  return std::chrono::duration_cast<std::chrono::seconds>(time_left);
224  } else {
225  return {};
226  }
227 }
228 
229 std::string banned::get_human_start_time() const
230 {
231  if(start_time_) {
233  } else {
234  return "unknown";
235  }
236 }
237 
238 std::string banned::get_human_end_time() const
239 {
240  if(end_time_) {
242  } else {
243  return "permanent";
244  }
245 }
246 
247 bool banned::operator>(const banned& b) const
248 {
249  static constexpr std::chrono::system_clock::time_point epoch;
250  return end_time_.value_or(epoch) > b.get_end_time().value_or(epoch);
251 }
252 
253 unsigned int banned::get_mask_ip(unsigned int mask) const
254 {
255  return ip_ & mask & mask_;
256 }
257 
258 bool banned::match_ip(const ip_mask& pair) const
259 {
260  return (ip_ & mask_) == (pair.first & mask_);
261 }
262 
263 // Unlike match_ip this function takes both masks into account.
264 bool banned::match_ipmask(const ip_mask& pair) const
265 {
266  return (ip_ & mask_ & pair.second) == (pair.first & pair.second & mask_);
267 }
268 
270 {
271  if(filename_.empty() || !filesystem::file_exists(filename_)) {
272  return;
273  }
274 
275  LOG_SERVER << "Reading bans from " << filename_;
276  dirty_ = false;
278  config cfg = io::read_gz(*ban_file);
279 
280  for(const config& b : cfg.child_range("ban")) {
281  try {
282  auto new_ban = std::make_shared<banned>(b);
283  assert(bans_.insert(new_ban).second);
284 
285  if (new_ban->get_end_time())
286  time_queue_.push(new_ban);
287  } catch(const banned::error& e) {
288  ERR_SERVER << e.message << " while reading bans";
289  }
290  }
291 
292  // load deleted too
293  if(auto cfg_del = cfg.optional_child("deleted")) {
294  for(const config& b : cfg_del->child_range("ban")) {
295  try {
296  auto new_ban = std::make_shared<banned>(b);
297  deleted_bans_.push_back(new_ban);
298  } catch(const banned::error& e) {
299  ERR_SERVER << e.message << " while reading deleted bans";
300  }
301  }
302  }
303 }
304 
306 {
307  if(filename_.empty() || !dirty_) {
308  return;
309  }
310 
311  LOG_SERVER << "Writing bans to " << filename_;
312  dirty_ = false;
313 
314  config cfg;
315  for(const auto& b : bans_) {
316  config& child = cfg.add_child("ban");
317  b->write(child);
318  }
319 
320  config& deleted = cfg.add_child("deleted");
321  for(const auto& db : deleted_bans_) {
322  config& child = deleted.add_child("ban");
323  db->write(child);
324  }
325 
327  config_writer writer(*ban_file, true);
328  writer.write(cfg);
329 }
330 
331 std::pair<bool, utils::optional<std::chrono::system_clock::time_point>> ban_manager::parse_time(
332  const std::string& duration, std::chrono::system_clock::time_point start_time) const
333 {
334  if(duration.substr(0, 4) == "TIME") {
335  std::size_t number = 0;
336  for(auto i = duration.begin() + 4; i != duration.end(); ++i) {
337  if(is_digit(*i)) {
338  number = number * 10 + to_digit(*i);
339  } else {
340  switch(*i) {
341  case 'Y':
342  start_time += chrono::years{number};
343  break;
344  case 'M':
345  start_time += chrono::months{number};
346  break;
347  case 'D':
348  start_time += chrono::days{number};
349  break;
350  case 'h':
351  start_time += std::chrono::hours{number};
352  break;
353  case 'm':
354  start_time += std::chrono::minutes{number};
355  break;
356  case 's':
357  start_time += std::chrono::seconds{number};
358  break;
359  default:
360  LOG_SERVER << "Invalid time modifier given: '" << *i << "'.";
361  break;
362  }
363  number = 0;
364  }
365  }
366  return { true, start_time };
367  }
368 
369  std::string dur_lower;
370  try {
371  dur_lower = utf8::lowercase(duration);
372  } catch(const utf8::invalid_utf8_exception& e) {
373  ERR_SERVER << "While parsing ban command duration string, caught an invalid utf8 exception: " << e.what();
374  return { false, utils::nullopt };
375  }
376 
377  if(dur_lower == "permanent" || duration == "0") {
378  return { true, utils::nullopt };
379  } else if(const auto time_itor = ban_times_.find(duration); time_itor != ban_times_.end()) {
380  return { true, start_time + time_itor->second };
381  } else {
382  std::string::const_iterator i = duration.begin();
383  int number = -1;
384  for (std::string::const_iterator d_end = duration.end(); i != d_end; ++i) {
385  if (is_digit(*i))
386  {
387  if (number == -1) number = 0;
388  number = number * 10 + to_digit(*i);
389  } else {
390  if (number == -1) number = 1;
391  switch(*i)
392  {
393  case 'Y':
394  case 'y':
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') {
399  } else --i;
400  start_time += chrono::years{number};
401  break;
402  case 'M':
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') {
409  } else --i;
410  start_time += std::chrono::minutes{number};
411  break;
412  }
413  --i;
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') {
419  } else --i;
420  start_time += chrono::months{number};
421  break;
422  case 'D':
423  case 'd':
424  if (++i != d_end && tolower(*i) == 'a'
425  && ++i != d_end && tolower(*i) == 'y'
426  && ++i != d_end && tolower(*i) == 's') {
427  } else --i;
428  start_time += chrono::days{number};
429  break;
430  case 'H':
431  case 'h':
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') {
436  } else --i;
437  start_time += std::chrono::hours{number};
438  break;
439  case 'm':
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') {
445  } else --i;
446  start_time += chrono::months{number};
447  break;
448  }
449  --i;
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') {
456  } else --i;
457  start_time += std::chrono::minutes{number};
458  break;
459  case 'S':
460  case 's':
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') {
467  } else --i;
468  start_time += std::chrono::seconds{number};
469  break;
470  default:
471  return { false, utils::nullopt };
472  break;
473  }
474  number = -1;
475  }
476  }
477 
478  if(is_digit(*--i)) {
479  start_time += std::chrono::minutes{number}; // default to minutes
480  }
481 
482  return { true, start_time };
483  }
484 }
485 
486 std::string ban_manager::ban(const std::string& ip,
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)
492 {
493  std::ostringstream ret;
494  try {
496  if((ban = bans_.find(std::make_shared<banned>(ip))) != bans_.end()) {
497  // Already exsiting ban for ip. We have to first remove it
498  ret << "Overwriting ban: " << (**ban) << "\n";
499  bans_.erase(ban);
500  }
501  } catch(const banned::error& e) {
502  ERR_SERVER << e.message << " while creating dummy ban for finding existing ban";
503  return e.message;
504  }
505 
506  try {
507  auto new_ban = std::make_shared<banned>(ip, end_time, reason, who_banned, group, nick);
508  bans_.insert(new_ban);
509  if(end_time) {
510  time_queue_.push(new_ban);
511  }
512  ret << *new_ban;
513  } catch(const banned::error& e) {
514  ERR_SERVER << e.message << " while banning";
515  return e.message;
516  }
517 
518  dirty_ = true;
519  write();
520  return ret.str();
521 }
522 
523 void ban_manager::unban(std::ostringstream& os, const std::string& ip, bool immediate_write)
524 {
526  try {
527  ban = bans_.find(std::make_shared<banned>(ip));
528  } catch (const banned::error& e) {
529  ERR_SERVER << e.message;
530  os << e.message;
531  return;
532  }
533 
534  if(ban == bans_.end()) {
535  os << "There is no ban on '" << ip << "'.";
536  return;
537  }
538 
539  // keep ban entry still in memory
540  os << "Ban on '" << **ban << "' removed.";
541  // group bans don't get saved
542  if ((*ban)->get_group().empty()) deleted_bans_.push_back(*ban);
543  bans_.erase(ban);
544  dirty_ = true;
545  if(immediate_write) {
546  write();
547  }
548 }
549 
550 void ban_manager::unban_group(std::ostringstream& os, const std::string& group)
551 {
552  ban_set temp;
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); });
555 
556  os << "Removed " << (bans_.size() - temp.size()) << " bans";
557  bans_.swap(temp);
558  dirty_ = true;
559  write();
560 }
561 
562 void ban_manager::check_ban_times(const std::chrono::system_clock::time_point& time_now)
563 {
564  while(!time_queue_.empty()) {
565  banned_ptr ban = time_queue_.top();
566  const auto& end_time = ban->get_end_time();
567 
568  if(!end_time || *end_time > time_now) {
569  // No bans going to expire
570  DBG_SERVER
571  << "Ban on " << ban->get_ip() << " not removed."
572  << " time: " << chrono::format_local_timestamp(time_now)
573  << " end_time: " << (end_time ? chrono::format_local_timestamp(*end_time) : "none");
574  break;
575  }
576 
577  // This ban is going to expire so delete it.
578  LOG_SERVER
579  << "Removing ban on " << ban->get_ip() << "."
580  << " time: " << chrono::format_local_timestamp(time_now)
581  << " end_time: " << chrono::format_local_timestamp(*end_time);
582  std::ostringstream os;
583  unban(os, ban->get_ip(), false);
584  time_queue_.pop();
585  }
586 
587  // Save bans if there is any new ones
588  write();
589 }
590 
591 void ban_manager::list_deleted_bans(std::ostringstream& out, const std::string& mask) const
592 {
593  if(deleted_bans_.empty()) {
594  out << "No removed bans found.";
595  return;
596  }
597 
598  ip_mask pair;
599  try {
600  pair = parse_ip(mask);
601  } catch(const banned::error& e) {
602  out << "parse error: " << e.message;
603  return;
604  }
605 
606  out << "DELETED BANS LIST";
607  for(deleted_ban_list::const_iterator i = deleted_bans_.begin(); i != deleted_bans_.end(); ++i) {
608  if((*i)->match_ipmask(pair)) {
609  out << "\n" << (**i);
610  }
611  }
612 }
613 
614 void ban_manager::list_bans(std::ostringstream& out, const std::string& mask)
615 {
616  expire_bans();
617  if(bans_.empty()) {
618  out << "No bans set.";
619  return;
620  }
621 
622  ip_mask pair;
623  try {
624  pair = parse_ip(mask);
625  } catch(const banned::error& e) {
626  out << "parse error: " << e.message;
627  return;
628  }
629 
630  out << "BAN LIST";
631  std::set<std::string> groups;
632 
633  for(const auto& b : bans_) {
634  if(b->get_group().empty()) {
635  if(b->match_ipmask(pair)) {
636  out << "\n" << *b;
637  }
638  } else {
639  groups.insert(b->get_group());
640  }
641  }
642 
643  // Don't list ban groups when looking for specific bans.
644  if(!groups.empty() && mask == "*") {
645  out << "\nban groups: ";
646 
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));
651  }
652 }
653 
654 banned_ptr ban_manager::get_ban_info(const std::string& ip)
655 {
656  expire_bans();
657  ip_mask mask;
658  try {
659  mask = parse_ip(ip);
660  } catch (const banned::error&) {
661  return nullptr;
662  }
663 
664  auto ban = std::find_if(bans_.begin(), bans_.end(), [&mask](const banned_ptr& p) { return p->match_ip(mask); });
665  return ban != bans_.end() ? *ban : nullptr;
666 }
667 
669 {
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"
675  " argument.\n";
676  auto itor = ban_times_.begin();
677  if(itor != ban_times_.end()) {
678  ban_help_ += "You can also use " + itor->first;
679  ++itor;
680  }
681  for(; itor != ban_times_.end(); ++itor) {
682  ban_help_ += std::string(", ") + itor->first;
683  }
684  if(!ban_times_.empty()) {
685  ban_help_ += " for standard ban times. (not combinable)\n";
686  }
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";
690 }
691 
693 {
694  ban_times_.clear();
695  for(const config& bt : cfg.child_range("ban_time")) {
696  // Use the zero time point so we can easily convert the end time point to a duration
697  auto [success, end_time] = parse_time(bt["time"], {});
698 
699  if(success) {
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));
702  }
703  }
704 
705  init_ban_help();
706  if(filename_ != cfg["ban_save_file"]) {
707  dirty_ = true;
708  filename_ = cfg["ban_save_file"].str();
709  }
710 }
711 
713 {
714  try {
715  write();
716  } catch(...) {
717  DBG_SERVER << "Caught exception in ban_manager destructor: " << utils::get_unknown_exception_type();
718  }
719 }
720 
722  : bans_()
723  , deleted_bans_()
724  , time_queue_()
725  , ban_times_()
726  , ban_help_()
727  , filename_()
728  , dirty_(false)
729 {
730  init_ban_help();
731 }
732 
733 } // namespace wesnothd
std::string filename_
Definition: action_wml.cpp:534
#define DBG_SERVER
Definition: ban.cpp:36
#define LOG_SERVER
Definition: ban.cpp:35
#define ERR_SERVER
Definition: ban.cpp:34
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.
Definition: config.hpp:158
bool has_attribute(config_key_type key) const
Definition: config.cpp:157
child_itors child_range(config_key_type key)
Definition: config.cpp:268
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.
Definition: config.cpp:380
config & add_child(config_key_type key)
Definition: config.cpp:436
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="")
Definition: ban.cpp:486
void expire_bans()
Definition: ban.hpp:152
void list_bans(std::ostringstream &out, const std::string &mask="*")
Definition: ban.cpp:614
void unban(std::ostringstream &os, const std::string &ip, bool immediate_write=true)
Definition: ban.cpp:523
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 ...
Definition: ban.cpp:331
void check_ban_times(const std::chrono::system_clock::time_point &time_now)
Definition: ban.cpp:562
default_ban_times ban_times_
Definition: ban.hpp:135
banned_ptr get_ban_info(const std::string &ip)
Definition: ban.cpp:654
std::string filename_
Definition: ban.hpp:137
void unban_group(std::ostringstream &os, const std::string &group)
Definition: ban.cpp:550
bool is_digit(const char &c) const
Definition: ban.hpp:140
std::size_t to_digit(const char &c) const
Definition: ban.hpp:145
ban_time_queue time_queue_
Definition: ban.hpp:134
std::string ban_help_
Definition: ban.hpp:136
deleted_ban_list deleted_bans_
Definition: ban.hpp:133
void list_deleted_bans(std::ostringstream &out, const std::string &mask="*") const
Definition: ban.cpp:591
void load_config(const config &)
Definition: ban.cpp:692
void init_ban_help()
Definition: ban.cpp:668
utils::optional< std::chrono::system_clock::time_point > start_time_
Definition: ban.hpp:65
std::string group_
Definition: ban.hpp:68
bool match_ipmask(const ip_mask &ip) const
Definition: ban.cpp:264
std::string reason_
Definition: ban.hpp:66
utils::optional< std::chrono::seconds > get_remaining_ban_time() const
Returns the seconds remaining until than ban expires, or nullopt if permanent.
Definition: ban.cpp:219
std::string get_human_start_time() const
Definition: ban.cpp:229
unsigned int get_mask_ip(unsigned int) const
Definition: ban.cpp:253
unsigned int mask() const
Definition: ban.hpp:120
void read(const config &)
Definition: ban.cpp:163
static const std::string who_banned_default_
Definition: ban.hpp:70
unsigned int ip_
Definition: ban.hpp:61
std::string get_nick() const
Definition: ban.hpp:107
unsigned int mask_
Definition: ban.hpp:62
std::string nick_
Definition: ban.hpp:69
bool operator>(const banned &b) const
Definition: ban.cpp:247
void write(config &) const
Definition: ban.cpp:195
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="")
Definition: ban.cpp:83
bool match_ip(const ip_mask &ip) const
Definition: ban.cpp:258
std::string get_human_end_time() const
Definition: ban.cpp:238
std::string get_ip() const
Definition: ban.hpp:99
std::string who_banned_
Definition: ban.hpp:67
utils::optional< std::chrono::system_clock::time_point > end_time_
Definition: ban.hpp:64
std::string ip_text_
Definition: ban.hpp:63
Definitions for the interface to Wesnoth Markup Language (WML).
Declarations for File-IO.
std::size_t i
Definition: function.cpp:1030
New lexcical_cast header.
Standard logging facilities (interface).
std::chrono::duration< int, std::ratio< 2629746 > > months
Definition: chrono.hpp:42
auto serialize_timestamp(const std::chrono::system_clock::time_point &time)
Definition: chrono.hpp:57
auto parse_timestamp(long long val)
Definition: chrono.hpp:47
auto format_local_timestamp(const std::chrono::system_clock::time_point &time, std::string_view format="%F %T")
Definition: chrono.hpp:62
std::chrono::duration< int, std::ratio< 31556952 > > years
Definition: chrono.hpp:43
std::chrono::duration< int, std::ratio< 86400 > > days
Definition: chrono.hpp:40
filesystem::scoped_istream istream_file(const std::string &fname, bool treat_failure_as_error)
static bool file_exists(const bfs::path &fpath)
Definition: filesystem.cpp:328
filesystem::scoped_ostream ostream_file(const std::string &fname, std::ios_base::openmode mode, bool create_directory)
std::unique_ptr< std::istream > scoped_istream
Definition: filesystem.hpp:53
std::unique_ptr< std::ostream > scoped_ostream
Definition: filesystem.hpp:54
config read_gz(std::istream &file, abstract_validator *validator)
Might throw a std::ios_base::failure especially a gzip_error.
Definition: parser.cpp:683
std::string lowercase(std::string_view s)
Returns a lowercased version of the string.
Definition: unicode.cpp:50
std::string get_unknown_exception_type()
Utility function for finding the type of thing caught with catch(...).
Definition: general.cpp:23
std::vector< std::string > split(const config_attribute_value &val)
std::ostream & operator<<(std::ostream &o, const banned &n)
Definition: ban.cpp:38
std::set< banned_ptr, banned_compare_subnet > ban_set
Definition: ban.hpp:52
static lg::log_domain log_server("server")
std::shared_ptr< banned > banned_ptr
Definition: ban.hpp:34
ip_mask parse_ip(const std::string &ip)
Definition: ban.cpp:118
std::pair< unsigned int, unsigned int > ip_mask
Definition: ban.hpp:56
std::string::const_iterator iterator
Definition: tokenizer.hpp:25
bool operator()(const banned_ptr &a, const banned_ptr &b) const
Definition: ban.cpp:55
static compare_fn active_
Definition: ban.hpp:49
bool(banned_compare_subnet::* compare_fn)(const banned_ptr &a, const banned_ptr &b) const
Definition: ban.hpp:48
bool less(const banned_ptr &a, const banned_ptr &b) const
Definition: ban.cpp:60
bool operator()(const banned_ptr &a, const banned_ptr &b) const
Definition: ban.cpp:48
mock_party p
static map_location::direction n
#define e
#define b