The Battle for Wesnoth  1.19.5+dev
ban.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2008 - 2024
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 std::string banned::get_human_start_time() const
220 {
221  if(start_time_) {
223  } else {
224  return "unknown";
225  }
226 }
227 
228 std::string banned::get_human_end_time() const
229 {
230  if(end_time_) {
232  } else {
233  return "permanent";
234  }
235 }
236 
237 std::string banned::get_human_time_span() const
238 {
239  if(!end_time_) {
240  return "permanent";
241  }
242 
243  auto remaining = *end_time_ - std::chrono::system_clock::now();
244  return lg::format_timespan(std::chrono::duration_cast<std::chrono::seconds>(remaining));
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  config cfg;
277  dirty_ = false;
279  read_gz(cfg, *ban_file);
280 
281  for(const config& b : cfg.child_range("ban")) {
282  try {
283  auto new_ban = std::make_shared<banned>(b);
284  assert(bans_.insert(new_ban).second);
285 
286  if (new_ban->get_end_time())
287  time_queue_.push(new_ban);
288  } catch(const banned::error& e) {
289  ERR_SERVER << e.message << " while reading bans";
290  }
291  }
292 
293  // load deleted too
294  if(auto cfg_del = cfg.optional_child("deleted")) {
295  for(const config& b : cfg_del->child_range("ban")) {
296  try {
297  auto new_ban = std::make_shared<banned>(b);
298  deleted_bans_.push_back(new_ban);
299  } catch(const banned::error& e) {
300  ERR_SERVER << e.message << " while reading deleted bans";
301  }
302  }
303  }
304 }
305 
307 {
308  if(filename_.empty() || !dirty_) {
309  return;
310  }
311 
312  LOG_SERVER << "Writing bans to " << filename_;
313  dirty_ = false;
314 
315  config cfg;
316  for(const auto& b : bans_) {
317  config& child = cfg.add_child("ban");
318  b->write(child);
319  }
320 
321  config& deleted = cfg.add_child("deleted");
322  for(const auto& db : deleted_bans_) {
323  config& child = deleted.add_child("ban");
324  db->write(child);
325  }
326 
328  config_writer writer(*ban_file, true);
329  writer.write(cfg);
330 }
331 
332 std::pair<bool, utils::optional<std::chrono::system_clock::time_point>> ban_manager::parse_time(
333  const std::string& duration, std::chrono::system_clock::time_point start_time) const
334 {
335  if(duration.substr(0, 4) == "TIME") {
336  auto as_time_t = std::chrono::system_clock::to_time_t(start_time);
337  std::tm* loc = std::localtime(&as_time_t);
338 
339  std::size_t number = 0;
340  for(auto i = duration.begin() + 4; i != duration.end(); ++i) {
341  if(is_digit(*i)) {
342  number = number * 10 + to_digit(*i);
343  } else {
344  switch(*i) {
345  case 'Y':
346  loc->tm_year = number;
347  break;
348  case 'M':
349  loc->tm_mon = number;
350  break;
351  case 'D':
352  loc->tm_mday = number;
353  break;
354  case 'h':
355  loc->tm_hour = number;
356  break;
357  case 'm':
358  loc->tm_min = number;
359  break;
360  case 's':
361  loc->tm_sec = number;
362  break;
363  default:
364  LOG_SERVER << "Invalid time modifier given: '" << *i << "'.";
365  break;
366  }
367  number = 0;
368  }
369  }
370  return { true, std::chrono::system_clock::from_time_t(std::mktime(loc)) };
371  }
372 
373  std::string dur_lower;
374  try {
375  dur_lower = utf8::lowercase(duration);
376  } catch(const utf8::invalid_utf8_exception& e) {
377  ERR_SERVER << "While parsing ban command duration string, caught an invalid utf8 exception: " << e.what();
378  return { false, utils::nullopt };
379  }
380 
381  if(dur_lower == "permanent" || duration == "0") {
382  return { true, utils::nullopt };
383  } else if(const auto time_itor = ban_times_.find(duration); time_itor != ban_times_.end()) {
384  return { true, start_time + time_itor->second };
385  } else {
386  std::string::const_iterator i = duration.begin();
387  int number = -1;
388  for (std::string::const_iterator d_end = duration.end(); i != d_end; ++i) {
389  if (is_digit(*i))
390  {
391  if (number == -1) number = 0;
392  number = number * 10 + to_digit(*i);
393  } else {
394  if (number == -1) number = 1;
395  switch(*i)
396  {
397  case 'Y':
398  case 'y':
399  if (++i != d_end && tolower(*i) == 'e'
400  && ++i != d_end && tolower(*i) == 'a'
401  && ++i != d_end && tolower(*i) == 'r'
402  && ++i != d_end && tolower(*i) == 's') {
403  } else --i;
404  start_time += chrono::years{number};
405  break;
406  case 'M':
407  if (++i != d_end && tolower(*i) == 'i') {
408  if (++i != d_end && tolower(*i) == 'n'
409  && ++i != d_end && tolower(*i) == 'u'
410  && ++i != d_end && tolower(*i) == 't'
411  && ++i != d_end && tolower(*i) == 'e'
412  && ++i != d_end && tolower(*i) == 's') {
413  } else --i;
414  start_time += std::chrono::minutes{number};
415  break;
416  }
417  --i;
418  if (++i != d_end && tolower(*i) == 'o'
419  && ++i != d_end && tolower(*i) == 'n'
420  && ++i != d_end && tolower(*i) == 't'
421  && ++i != d_end && tolower(*i) == 'h'
422  && ++i != d_end && tolower(*i) == 's') {
423  } else --i;
424  start_time += chrono::months{number};
425  break;
426  case 'D':
427  case 'd':
428  if (++i != d_end && tolower(*i) == 'a'
429  && ++i != d_end && tolower(*i) == 'y'
430  && ++i != d_end && tolower(*i) == 's') {
431  } else --i;
432  start_time += chrono::days{number};
433  break;
434  case 'H':
435  case 'h':
436  if (++i != d_end && tolower(*i) == 'o'
437  && ++i != d_end && tolower(*i) == 'u'
438  && ++i != d_end && tolower(*i) == 'r'
439  && ++i != d_end && tolower(*i) == 's') {
440  } else --i;
441  start_time += std::chrono::hours{number};
442  break;
443  case 'm':
444  if (++i != d_end && tolower(*i) == 'o') {
445  if (++i != d_end && tolower(*i) == 'n'
446  && ++i != d_end && tolower(*i) == 't'
447  && ++i != d_end && tolower(*i) == 'h'
448  && ++i != d_end && tolower(*i) == 's') {
449  } else --i;
450  start_time += chrono::months{number};
451  break;
452  }
453  --i;
454  if (++i != d_end && tolower(*i) == 'i'
455  && ++i != d_end && tolower(*i) == 'n'
456  && ++i != d_end && tolower(*i) == 'u'
457  && ++i != d_end && tolower(*i) == 't'
458  && ++i != d_end && tolower(*i) == 'e'
459  && ++i != d_end && tolower(*i) == 's') {
460  } else --i;
461  start_time += std::chrono::minutes{number};
462  break;
463  case 'S':
464  case 's':
465  if (++i != d_end && tolower(*i) == 'e'
466  && ++i != d_end && tolower(*i) == 'c'
467  && ++i != d_end && tolower(*i) == 'o'
468  && ++i != d_end && tolower(*i) == 'n'
469  && ++i != d_end && tolower(*i) == 'd'
470  && ++i != d_end && tolower(*i) == 's') {
471  } else --i;
472  start_time += std::chrono::seconds{number};
473  break;
474  default:
475  return { false, utils::nullopt };
476  break;
477  }
478  number = -1;
479  }
480  }
481 
482  if(is_digit(*--i)) {
483  start_time += std::chrono::minutes{number}; // default to minutes
484  }
485 
486  return { true, start_time };
487  }
488 }
489 
490 std::string ban_manager::ban(const std::string& ip,
491  const utils::optional<std::chrono::system_clock::time_point>& end_time,
492  const std::string& reason,
493  const std::string& who_banned,
494  const std::string& group,
495  const std::string& nick)
496 {
497  std::ostringstream ret;
498  try {
500  if((ban = bans_.find(std::make_shared<banned>(ip))) != bans_.end()) {
501  // Already exsiting ban for ip. We have to first remove it
502  ret << "Overwriting ban: " << (**ban) << "\n";
503  bans_.erase(ban);
504  }
505  } catch(const banned::error& e) {
506  ERR_SERVER << e.message << " while creating dummy ban for finding existing ban";
507  return e.message;
508  }
509 
510  try {
511  auto new_ban = std::make_shared<banned>(ip, end_time, reason, who_banned, group, nick);
512  bans_.insert(new_ban);
513  if(end_time) {
514  time_queue_.push(new_ban);
515  }
516  ret << *new_ban;
517  } catch(const banned::error& e) {
518  ERR_SERVER << e.message << " while banning";
519  return e.message;
520  }
521 
522  dirty_ = true;
523  write();
524  return ret.str();
525 }
526 
527 void ban_manager::unban(std::ostringstream& os, const std::string& ip, bool immediate_write)
528 {
530  try {
531  ban = bans_.find(std::make_shared<banned>(ip));
532  } catch (const banned::error& e) {
533  ERR_SERVER << e.message;
534  os << e.message;
535  return;
536  }
537 
538  if(ban == bans_.end()) {
539  os << "There is no ban on '" << ip << "'.";
540  return;
541  }
542 
543  // keep ban entry still in memory
544  os << "Ban on '" << **ban << "' removed.";
545  // group bans don't get saved
546  if ((*ban)->get_group().empty()) deleted_bans_.push_back(*ban);
547  bans_.erase(ban);
548  dirty_ = true;
549  if(immediate_write) {
550  write();
551  }
552 }
553 
554 void ban_manager::unban_group(std::ostringstream& os, const std::string& group)
555 {
556  ban_set temp;
557  std::insert_iterator<ban_set> temp_inserter(temp, temp.begin());
558  std::remove_copy_if(bans_.begin(), bans_.end(), temp_inserter, [&group](const banned_ptr& p) { return p->match_group(group); });
559 
560  os << "Removed " << (bans_.size() - temp.size()) << " bans";
561  bans_.swap(temp);
562  dirty_ = true;
563  write();
564 }
565 
566 void ban_manager::check_ban_times(const std::chrono::system_clock::time_point& time_now)
567 {
568  while(!time_queue_.empty()) {
569  banned_ptr ban = time_queue_.top();
570  const auto& end_time = ban->get_end_time();
571 
572  if(!end_time || *end_time > time_now) {
573  // No bans going to expire
574  DBG_SERVER
575  << "Ban on " << ban->get_ip() << " not removed."
576  << " time: " << chrono::format_local_timestamp(time_now)
577  << " end_time: " << (end_time ? chrono::format_local_timestamp(*end_time) : "none");
578  break;
579  }
580 
581  // This ban is going to expire so delete it.
582  LOG_SERVER
583  << "Removing ban on " << ban->get_ip() << "."
584  << " time: " << chrono::format_local_timestamp(time_now)
585  << " end_time: " << chrono::format_local_timestamp(*end_time);
586  std::ostringstream os;
587  unban(os, ban->get_ip(), false);
588  time_queue_.pop();
589  }
590 
591  // Save bans if there is any new ones
592  write();
593 }
594 
595 void ban_manager::list_deleted_bans(std::ostringstream& out, const std::string& mask) const
596 {
597  if(deleted_bans_.empty()) {
598  out << "No removed bans found.";
599  return;
600  }
601 
602  ip_mask pair;
603  try {
604  pair = parse_ip(mask);
605  } catch(const banned::error& e) {
606  out << "parse error: " << e.message;
607  return;
608  }
609 
610  out << "DELETED BANS LIST";
611  for(deleted_ban_list::const_iterator i = deleted_bans_.begin(); i != deleted_bans_.end(); ++i) {
612  if((*i)->match_ipmask(pair)) {
613  out << "\n" << (**i);
614  }
615  }
616 }
617 
618 void ban_manager::list_bans(std::ostringstream& out, const std::string& mask)
619 {
620  expire_bans();
621  if(bans_.empty()) {
622  out << "No bans set.";
623  return;
624  }
625 
626  ip_mask pair;
627  try {
628  pair = parse_ip(mask);
629  } catch(const banned::error& e) {
630  out << "parse error: " << e.message;
631  return;
632  }
633 
634  out << "BAN LIST";
635  std::set<std::string> groups;
636 
637  for(const auto& b : bans_) {
638  if(b->get_group().empty()) {
639  if(b->match_ipmask(pair)) {
640  out << "\n" << *b;
641  }
642  } else {
643  groups.insert(b->get_group());
644  }
645  }
646 
647  // Don't list ban groups when looking for specific bans.
648  if(!groups.empty() && mask == "*") {
649  out << "\nban groups: ";
650 
651  out << *groups.begin();
652  std::ostream& (*fn)(std::ostream&, const std::string&) = &std::operator<<;
653  std::for_each(++groups.begin(), groups.end(),
654  std::bind(fn, std::bind(fn, std::ref(out), std::string(", ")), std::placeholders::_1));
655  }
656 }
657 
658 std::string ban_manager::is_ip_banned(const std::string& ip)
659 {
660  expire_bans();
661  ip_mask pair;
662  try {
663  pair = parse_ip(ip);
664  } catch (const banned::error&) {
665  return "";
666  }
667 
668  auto ban = std::find_if(bans_.begin(), bans_.end(), [pair](const banned_ptr& p) { return p->match_ip(pair); });
669  if (ban == bans_.end()) return "";
670  const std::string& nick = (*ban)->get_nick();
671  return (*ban)->get_reason() + (nick.empty() ? "" : " (" + nick + ")") + " (Remaining ban duration: " + (*ban)->get_human_time_span() + ")";
672 }
673 
675 {
676  ban_help_ = "ban <mask> <time> <reason>\n"
677  "The time format is: %d[%s[%d[%s[...]]]] where %s is a time"
678  " modifier: s or S (seconds), m (minutes), h or H (hours), d"
679  " or D (days), M (months) or y or Y (years) and %d is a number.\n"
680  "Permanent bans can be set with 'permanent' or '0' as the time"
681  " argument.\n";
682  auto itor = ban_times_.begin();
683  if(itor != ban_times_.end()) {
684  ban_help_ += "You can also use " + itor->first;
685  ++itor;
686  }
687  for(; itor != ban_times_.end(); ++itor) {
688  ban_help_ += std::string(", ") + itor->first;
689  }
690  if(!ban_times_.empty()) {
691  ban_help_ += " for standard ban times. (not combinable)\n";
692  }
693  ban_help_ += "ban 127.0.0.1 2h20m flooded lobby\n"
694  "kban suokko 5D flooded again\n"
695  "kban suokko Y One year ban for constant flooding";
696 }
697 
699 {
700  ban_times_.clear();
701  for(const config& bt : cfg.child_range("ban_time")) {
702  // Use the zero time point so we can easily convert the end time point to a duration
703  auto [success, end_time] = parse_time(bt["time"], {});
704 
705  if(success) {
706  auto duration = end_time.value_or(decltype(end_time)::value_type{}).time_since_epoch();
707  ban_times_.emplace(bt["name"], std::chrono::duration_cast<std::chrono::seconds>(duration));
708  }
709  }
710 
711  init_ban_help();
712  if(filename_ != cfg["ban_save_file"]) {
713  dirty_ = true;
714  filename_ = cfg["ban_save_file"].str();
715  }
716 }
717 
719 {
720  try {
721  write();
722  } catch(...) {
723  DBG_SERVER << "Caught exception in ban_manager destructor: " << utils::get_unknown_exception_type();
724  }
725 }
726 
728  : bans_()
729  , deleted_bans_()
730  , time_queue_()
731  , ban_times_()
732  , ban_help_()
733  , filename_()
734  , dirty_(false)
735 {
736  init_ban_help();
737 }
738 
739 } // 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:172
bool has_attribute(config_key_type key) const
Definition: config.cpp:157
child_itors child_range(config_key_type key)
Definition: config.cpp:272
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:384
config & add_child(config_key_type key)
Definition: config.cpp:440
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:490
void expire_bans()
Definition: ban.hpp:150
void list_bans(std::ostringstream &out, const std::string &mask="*")
Definition: ban.cpp:618
void unban(std::ostringstream &os, const std::string &ip, bool immediate_write=true)
Definition: ban.cpp:527
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:332
void check_ban_times(const std::chrono::system_clock::time_point &time_now)
Definition: ban.cpp:566
default_ban_times ban_times_
Definition: ban.hpp:133
std::string filename_
Definition: ban.hpp:135
void unban_group(std::ostringstream &os, const std::string &group)
Definition: ban.cpp:554
bool is_digit(const char &c) const
Definition: ban.hpp:138
std::size_t to_digit(const char &c) const
Definition: ban.hpp:143
ban_time_queue time_queue_
Definition: ban.hpp:132
std::string ban_help_
Definition: ban.hpp:134
std::string is_ip_banned(const std::string &ip)
Definition: ban.cpp:658
deleted_ban_list deleted_bans_
Definition: ban.hpp:131
void list_deleted_bans(std::ostringstream &out, const std::string &mask="*") const
Definition: ban.cpp:595
void load_config(const config &)
Definition: ban.cpp:698
void init_ban_help()
Definition: ban.cpp:674
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
std::string get_human_start_time() const
Definition: ban.cpp:219
unsigned int get_mask_ip(unsigned int) const
Definition: ban.cpp:253
unsigned int mask() const
Definition: ban.hpp:118
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:105
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:228
std::string get_human_time_span() const
Definition: ban.cpp:237
std::string get_ip() const
Definition: ban.hpp:97
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:1028
New lexcical_cast header.
Standard logging facilities (interface).
std::chrono::duration< int, std::ratio< 2629746 > > months
Definition: chrono.hpp:41
auto serialize_timestamp(const std::chrono::system_clock::time_point &time)
Definition: chrono.hpp:56
auto parse_timestamp(long long val)
Definition: chrono.hpp:46
auto format_local_timestamp(const std::chrono::system_clock::time_point &time, std::string_view format="%F %T")
Definition: chrono.hpp:61
std::chrono::duration< int, std::ratio< 31556952 > > years
Definition: chrono.hpp:42
std::chrono::duration< int, std::ratio< 86400 > > days
Definition: chrono.hpp:39
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:325
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
std::string format_timespan(const std::chrono::seconds &span)
TODO: we also have utils::format_timespan, which does something very similar...
Definition: log.cpp:404
std::string lowercase(const std::string &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
void read_gz(config &cfg, std::istream &file, abstract_validator *validator)
Might throw a std::ios_base::failure especially a gzip_error.
Definition: parser.cpp:678
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