The Battle for Wesnoth  1.17.0-dev
ban.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2008 - 2021
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/parser.hpp"
24 
25 #include "server/wesnothd/ban.hpp"
26 
27 #include <functional>
28 
29 namespace wesnothd
30 {
31 static lg::log_domain log_server("server");
32 #define ERR_SERVER LOG_STREAM(err, log_server)
33 #define LOG_SERVER LOG_STREAM(info, log_server)
34 #define DBG_SERVER LOG_STREAM(debug, log_server)
35 
36 std::ostream& operator<<(std::ostream& o, const banned& n)
37 {
38  return o << "IP: " << n.get_ip() <<
39  (n.get_nick().empty() ? "" : " nick: " + n.get_nick()) <<
40  " reason: '" << n.get_reason() << "'"
41  " start_time: " << n.get_human_start_time() <<
42  " end_time: " << n.get_human_end_time() <<
43  " issuer: " << n.get_who_banned();
44 }
45 
47 {
48  return (*a) > (*b);
49 }
50 
52 
54 {
55  return (this->*(active_))(a,b);
56 }
57 
59 {
60  return a->get_int_ip() < b->get_int_ip();
61 }
62 
63 const std::string banned::who_banned_default_ = "system";
64 
65 banned::banned(const std::string& ip)
66  : ip_(0)
67  , mask_(0)
68  , ip_text_()
69  , end_time_(0)
70  , start_time_(0)
71  , reason_()
72  , who_banned_(who_banned_default_)
73  , group_()
74  , nick_()
75 {
76  ip_mask pair = parse_ip(ip);
77  ip_ = pair.first;
78  mask_ = 0xFFFFFFFF;
79 }
80 
81 banned::banned(const std::string& ip,
82  const std::time_t end_time,
83  const std::string& reason,
84  const std::string& who_banned,
85  const std::string& group,
86  const std::string& nick)
87  : ip_(0)
88  , mask_(0)
89  , ip_text_(ip)
90  , end_time_(end_time)
91  , start_time_(std::time(0))
92  , reason_(reason)
93  , who_banned_(who_banned)
94  , group_(group)
95  , nick_(nick)
96 {
97  ip_mask pair = parse_ip(ip_text_);
98  ip_ = pair.first;
99  mask_ = pair.second;
100 }
101 
103  : ip_(0)
104  , mask_(0)
105  , ip_text_()
106  , end_time_(0)
107  , start_time_(0)
108  , reason_()
110  , group_()
111  , nick_()
112 {
113  read(cfg);
114 }
115 
116 ip_mask parse_ip(const std::string& ip)
117 {
118  // We use bit operations to construct the integer
119  // ip_mask is a pair: first is ip and second is mask
120  ip_mask ret;
121  ret.first = 0;
122  ret.second = 0;
123  std::vector<std::string> split_ip = utils::split(ip, '.');
124  if (split_ip.size() > 4) throw banned::error("Malformed ip address: " + ip);
125 
126  unsigned int shift = 4*8; // start shifting from the highest byte
127  unsigned int mask = 0xFF000000;
128  const unsigned int complete_part_mask = 0xFF;
129  auto part = split_ip.begin();
130  bool wildcard = false;
131  do {
132  shift -= 8;
133  mask >>= 8;
134  if(part == split_ip.end()) {
135  if(!wildcard)
136  throw banned::error("Malformed ip address: '" + ip + "'");
137  // Adding 0 to ip and mask is nop
138  // we can then break out of loop
139  break;
140  } else {
141  if(*part == "*") {
142  wildcard = true;
143  // Adding 0 to ip and mask is nop
144  } else {
145  // wildcard = false;
146  unsigned int part_ip = lexical_cast_default<unsigned int>(*part, complete_part_mask + 1);
147  if(part_ip > complete_part_mask) {
148  throw banned::error("Malformed ip address: '" + ip + "'");
149  }
150 
151  ret.first |= (part_ip << shift);
152  ret.second |= (complete_part_mask << shift);
153  }
154  }
155  ++part;
156  } while(shift);
157 
158  return ret;
159 }
160 
161 void banned::read(const config& cfg)
162 {
163  {
164  // parse ip and mask
165  ip_text_ = cfg["ip"].str();
166  ip_mask pair = parse_ip(ip_text_);
167  ip_ = pair.first;
168  mask_ = pair.second;
169  }
170 
171  nick_ = cfg["nick"].str();
172 
173  if(cfg.has_attribute("end_time")) {
174  end_time_ = cfg["end_time"].to_time_t(0);
175  }
176 
177  if(cfg.has_attribute("start_time")) {
178  start_time_ = cfg["start_time"].to_time_t(0);
179  }
180 
181  reason_ = cfg["reason"].str();
182 
183  // only overwrite defaults if exists
184  if(cfg.has_attribute("who_banned")) {
185  who_banned_ = cfg["who_banned"].str();
186  }
187 
188  if(cfg.has_attribute("group")) {
189  group_ = cfg["group"].str();
190  }
191 }
192 
193 void banned::write(config& cfg) const
194 {
195  cfg["ip"] = get_ip();
196  cfg["nick"] = get_nick();
197 
198  if(end_time_ > 0) {
199  std::stringstream ss;
200  ss << end_time_;
201  cfg["end_time"] = ss.str();
202  }
203 
204  if(start_time_ > 0) {
205  std::stringstream ss;
206  ss << start_time_;
207  cfg["start_time"] = ss.str();
208  }
209 
210  cfg["reason"] = reason_;
211 
213  cfg["who_banned"] = who_banned_;
214  }
215 
216  if(!group_.empty()) {
217  cfg["group"] = group_;
218  }
219 }
220 
221 std::string banned::get_human_start_time() const
222 {
223  if(start_time_ == 0) {
224  return "unknown";
225  }
226 
228 }
229 
230 std::string banned::get_human_end_time() const
231 {
232  if(end_time_ == 0) {
233  return "permanent";
234  }
235 
237 }
238 
239 std::string banned::get_human_time_span() const
240 {
241  if(end_time_ == 0) {
242  return "permanent";
243  }
244 
245  return lg::get_timespan(end_time_ - std::time(nullptr));
246 }
247 
248 bool banned::operator>(const banned& b) const
249 {
250  return end_time_ > b.get_end_time();
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_ << "\n";
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() != 0)
287  time_queue_.push(new_ban);
288  } catch(const banned::error& e) {
289  ERR_SERVER << e.message << " while reading bans" << std::endl;
290  }
291  }
292 
293  // load deleted too
294  if(const config& cfg_del = cfg.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" << std::endl;
301  }
302  }
303  }
304 }
305 
307 {
308  if(filename_.empty() || !dirty_) {
309  return;
310  }
311 
312  LOG_SERVER << "Writing bans to " << filename_ << "\n";
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 bool ban_manager::parse_time(const std::string& duration, std::time_t* time) const
333 {
334  if (!time) return false;
335 
336  if(duration.substr(0, 4) == "TIME") {
337  std::tm* loc;
338  loc = std::localtime(time);
339 
340  std::size_t number = 0;
341  for(auto i = duration.begin() + 4; i != duration.end(); ++i) {
342  if(is_digit(*i)) {
343  number = number * 10 + to_digit(*i);
344  } else {
345  switch(*i) {
346  case 'Y':
347  loc->tm_year = number;
348  break;
349  case 'M':
350  loc->tm_mon = number;
351  break;
352  case 'D':
353  loc->tm_mday = number;
354  break;
355  case 'h':
356  loc->tm_hour = number;
357  break;
358  case 'm':
359  loc->tm_min = number;
360  break;
361  case 's':
362  loc->tm_sec = number;
363  break;
364  default:
365  LOG_SERVER << "Invalid time modifier given: '" << *i << "'.\n";
366  break;
367  }
368  number = 0;
369  }
370  }
371  *time = mktime(loc);
372  return true;
373  }
374 
375  const auto time_itor = ban_times_.find(duration);
376 
377  std::string dur_lower;
378  try {
379  dur_lower = utf8::lowercase(duration);
380  } catch(const utf8::invalid_utf8_exception& e) {
381  ERR_SERVER << "While parsing ban command duration string, caught an invalid utf8 exception: " << e.what() << std::endl;
382  return false;
383  }
384 
385  if(dur_lower == "permanent" || duration == "0") {
386  *time = 0;
387  } else if(ban_times_.find(duration) != ban_times_.end()) {
388  *time += time_itor->second;
389  } else {
390  std::string::const_iterator i = duration.begin();
391  int number = -1;
392  for (std::string::const_iterator d_end = duration.end(); i != d_end; ++i) {
393  if (is_digit(*i))
394  {
395  if (number == -1) number = 0;
396  number = number * 10 + to_digit(*i);
397  } else {
398  if (number == -1) number = 1;
399  switch(*i)
400  {
401  case 'Y':
402  case 'y':
403  if (++i != d_end && tolower(*i) == 'e'
404  && ++i != d_end && tolower(*i) == 'a'
405  && ++i != d_end && tolower(*i) == 'r'
406  && ++i != d_end && tolower(*i) == 's') {
407  } else --i;
408  *time += number * 365*24*60*60; // a year;
409  break;
410  case 'M':
411  if (++i != d_end && tolower(*i) == 'i') {
412  if (++i != d_end && tolower(*i) == 'n'
413  && ++i != d_end && tolower(*i) == 'u'
414  && ++i != d_end && tolower(*i) == 't'
415  && ++i != d_end && tolower(*i) == 'e'
416  && ++i != d_end && tolower(*i) == 's') {
417  } else --i;
418  *time += number * 60;
419  break;
420  }
421  --i;
422  if (++i != d_end && tolower(*i) == 'o'
423  && ++i != d_end && tolower(*i) == 'n'
424  && ++i != d_end && tolower(*i) == 't'
425  && ++i != d_end && tolower(*i) == 'h'
426  && ++i != d_end && tolower(*i) == 's') {
427  } else --i;
428  *time += number * 30*24*60*60; // 30 days
429  break;
430  case 'D':
431  case 'd':
432  if (++i != d_end && tolower(*i) == 'a'
433  && ++i != d_end && tolower(*i) == 'y'
434  && ++i != d_end && tolower(*i) == 's') {
435  } else --i;
436  *time += number * 24*60*60;
437  break;
438  case 'H':
439  case 'h':
440  if (++i != d_end && tolower(*i) == 'o'
441  && ++i != d_end && tolower(*i) == 'u'
442  && ++i != d_end && tolower(*i) == 'r'
443  && ++i != d_end && tolower(*i) == 's') {
444  } else --i;
445  *time += number * 60*60;
446  break;
447  case 'm':
448  if (++i != d_end && tolower(*i) == 'o') {
449  if (++i != d_end && tolower(*i) == 'n'
450  && ++i != d_end && tolower(*i) == 't'
451  && ++i != d_end && tolower(*i) == 'h'
452  && ++i != d_end && tolower(*i) == 's') {
453  } else --i;
454  *time += number * 30*24*60*60; // 30 days
455  break;
456  }
457  --i;
458  if (++i != d_end && tolower(*i) == 'i'
459  && ++i != d_end && tolower(*i) == 'n'
460  && ++i != d_end && tolower(*i) == 'u'
461  && ++i != d_end && tolower(*i) == 't'
462  && ++i != d_end && tolower(*i) == 'e'
463  && ++i != d_end && tolower(*i) == 's') {
464  } else --i;
465  *time += number * 60;
466  break;
467  case 'S':
468  case 's':
469  if (++i != d_end && tolower(*i) == 'e'
470  && ++i != d_end && tolower(*i) == 'c'
471  && ++i != d_end && tolower(*i) == 'o'
472  && ++i != d_end && tolower(*i) == 'n'
473  && ++i != d_end && tolower(*i) == 'd'
474  && ++i != d_end && tolower(*i) == 's') {
475  } else --i;
476  *time += number;
477  break;
478  default:
479  return false;
480  break;
481  }
482  number = -1;
483  }
484  }
485 
486  if(is_digit(*--i)) {
487  *time += number * 60; // default to minutes
488  }
489  }
490 
491  return true;
492 }
493 
494 std::string ban_manager::ban(const std::string& ip,
495  const std::time_t& end_time,
496  const std::string& reason,
497  const std::string& who_banned,
498  const std::string& group,
499  const std::string& nick)
500 {
501  std::ostringstream ret;
502  try {
503  ban_set::iterator ban;
504  if((ban = bans_.find(std::make_shared<banned>(ip))) != bans_.end()) {
505  // Already exsiting ban for ip. We have to first remove it
506  ret << "Overwriting ban: " << (**ban) << "\n";
507  bans_.erase(ban);
508  }
509  } catch(const banned::error& e) {
510  ERR_SERVER << e.message << " while creating dummy ban for finding existing ban" << std::endl;
511  return e.message;
512  }
513 
514  try {
515  auto new_ban = std::make_shared<banned>(ip, end_time, reason, who_banned, group, nick);
516  bans_.insert(new_ban);
517  if(end_time != 0) {
518  time_queue_.push(new_ban);
519  }
520  ret << *new_ban;
521  } catch(const banned::error& e) {
522  ERR_SERVER << e.message << " while banning" << std::endl;
523  return e.message;
524  }
525 
526  dirty_ = true;
527  write();
528  return ret.str();
529 }
530 
531 void ban_manager::unban(std::ostringstream& os, const std::string& ip, bool immediate_write)
532 {
533  ban_set::iterator ban;
534  try {
535  ban = bans_.find(std::make_shared<banned>(ip));
536  } catch (const banned::error& e) {
537  ERR_SERVER << e.message << std::endl;
538  os << e.message;
539  return;
540  }
541 
542  if(ban == bans_.end()) {
543  os << "There is no ban on '" << ip << "'.";
544  return;
545  }
546 
547  // keep ban entry still in memory
548  os << "Ban on '" << **ban << "' removed.";
549  // group bans don't get saved
550  if ((*ban)->get_group().empty()) deleted_bans_.push_back(*ban);
551  bans_.erase(ban);
552  dirty_ = true;
553  if(immediate_write) {
554  write();
555  }
556 }
557 
558 void ban_manager::unban_group(std::ostringstream& os, const std::string& group)
559 {
560  ban_set temp;
561  std::insert_iterator<ban_set> temp_inserter(temp, temp.begin());
562  std::remove_copy_if(bans_.begin(), bans_.end(), temp_inserter, [&group](const banned_ptr& p) { return p->match_group(group); });
563 
564  os << "Removed " << (bans_.size() - temp.size()) << " bans";
565  bans_.swap(temp);
566  dirty_ = true;
567  write();
568 }
569 
570 void ban_manager::check_ban_times(std::time_t time_now)
571 {
572  while(!time_queue_.empty()) {
573  banned_ptr ban = time_queue_.top();
574 
575  if(ban->get_end_time() > time_now) {
576  // No bans going to expire
577  DBG_SERVER << "ban " << ban->get_ip() << " not removed. time: " << time_now << " end_time "
578  << ban->get_end_time() << "\n";
579  break;
580  }
581 
582  // This ban is going to expire so delete it.
583  LOG_SERVER << "Remove a ban " << ban->get_ip() << ". time: " << time_now << " end_time " << ban->get_end_time()
584  << "\n";
585  std::ostringstream os;
586  unban(os, ban->get_ip(), false);
587  time_queue_.pop();
588  }
589 
590  // Save bans if there is any new ones
591  write();
592 }
593 
594 void ban_manager::list_deleted_bans(std::ostringstream& out, const std::string& mask) const
595 {
596  if(deleted_bans_.empty()) {
597  out << "No removed bans found.";
598  return;
599  }
600 
601  ip_mask pair;
602  try {
603  pair = parse_ip(mask);
604  } catch(const banned::error& e) {
605  out << "parse error: " << e.message;
606  return;
607  }
608 
609  out << "DELETED BANS LIST";
610  for(deleted_ban_list::const_iterator i = deleted_bans_.begin(); i != deleted_bans_.end(); ++i) {
611  if((*i)->match_ipmask(pair)) {
612  out << "\n" << (**i);
613  }
614  }
615 }
616 
617 void ban_manager::list_bans(std::ostringstream& out, const std::string& mask)
618 {
619  expire_bans();
620  if(bans_.empty()) {
621  out << "No bans set.";
622  return;
623  }
624 
625  ip_mask pair;
626  try {
627  pair = parse_ip(mask);
628  } catch(const banned::error& e) {
629  out << "parse error: " << e.message;
630  return;
631  }
632 
633  out << "BAN LIST";
634  std::set<std::string> groups;
635 
636  for(const auto& b : bans_) {
637  if(b->get_group().empty()) {
638  if(b->match_ipmask(pair)) {
639  out << "\n" << *b;
640  }
641  } else {
642  groups.insert(b->get_group());
643  }
644  }
645 
646  // Don't list ban groups when looking for specific bans.
647  if(!groups.empty() && mask == "*") {
648  out << "\nban groups: ";
649 
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));
654  }
655 }
656 
657 std::string ban_manager::is_ip_banned(const std::string& ip)
658 {
659  expire_bans();
660  ip_mask pair;
661  try {
662  pair = parse_ip(ip);
663  } catch (const banned::error&) {
664  return "";
665  }
666 
667  auto ban = std::find_if(bans_.begin(), bans_.end(), [pair](const banned_ptr& p) { return p->match_ip(pair); });
668  if (ban == bans_.end()) return "";
669  const std::string& nick = (*ban)->get_nick();
670  return (*ban)->get_reason() + (nick.empty() ? "" : " (" + nick + ")") + " (Remaining ban duration: " + (*ban)->get_human_time_span() + ")";
671 }
672 
674 {
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"
680  " argument.\n";
681  auto itor = ban_times_.begin();
682  if(itor != ban_times_.end()) {
683  ban_help_ += "You can also use " + itor->first;
684  ++itor;
685  }
686  for(; itor != ban_times_.end(); ++itor) {
687  ban_help_ += std::string(", ") + itor->first;
688  }
689  if(!ban_times_.empty()) {
690  ban_help_ += " for standard ban times. (not combinable)\n";
691  }
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";
695 }
696 
698 {
699  ban_times_.clear();
700  for(const config& bt : cfg.child_range("ban_time")) {
701  std::time_t duration = 0;
702  if(parse_time(bt["time"], &duration)) {
703  ban_times_.emplace(bt["name"], duration);
704  }
705  }
706 
707  init_ban_help();
708  if(filename_ != cfg["ban_save_file"]) {
709  dirty_ = true;
710  filename_ = cfg["ban_save_file"].str();
711  }
712 }
713 
715 {
716  try {
717  write();
718  } catch(...) {
719  }
720 }
721 
723  : bans_()
724  , deleted_bans_()
725  , time_queue_()
726  , ban_times_()
727  , ban_help_()
728  , filename_()
729  , dirty_(false)
730 {
731  init_ban_help();
732 }
733 
734 } // namespace wesnothd
bool(banned_compare_subnet::* compare_fn)(const banned_ptr &a, const banned_ptr &b) const
Definition: ban.hpp:48
#define LOG_SERVER
Definition: ban.cpp:33
bool match_ipmask(const ip_mask &ip) const
Definition: ban.cpp:264
#define DBG_SERVER
Definition: ban.cpp:34
std::string reason_
Definition: ban.hpp:66
std::string get_reason() const
Definition: ban.hpp:89
std::string get_timestamp(const std::time_t &t, const std::string &format)
Definition: log.cpp:174
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...
Definition: config.cpp:402
void write(const config &cfg)
std::string get_timespan(const std::time_t &t)
Definition: log.cpp:181
void load_config(const config &)
Definition: ban.cpp:697
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="")
Definition: ban.cpp:81
bool less(const banned_ptr &a, const banned_ptr &b) const
Definition: ban.cpp:58
std::time_t start_time_
Definition: ban.hpp:65
static l_noret error(LoadState *S, const char *why)
Definition: lundump.cpp:40
New lexcical_cast header.
bool has_attribute(config_key_type key) const
Definition: config.cpp:211
#define a
void check_ban_times(std::time_t time_now)
Definition: ban.cpp:570
std::string is_ip_banned(const std::string &ip)
Definition: ban.cpp:657
static bool file_exists(const bfs::path &fpath)
Definition: filesystem.cpp:263
std::time_t get_end_time() const
Definition: ban.hpp:81
child_itors child_range(config_key_type key)
Definition: config.cpp:344
std::string get_human_end_time() const
Definition: ban.cpp:230
filesystem::scoped_istream istream_file(const std::string &fname, bool treat_failure_as_error)
STL namespace.
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:683
Definitions for the interface to Wesnoth Markup Language (WML).
std::string group_
Definition: ban.hpp:68
filesystem::scoped_ostream ostream_file(const std::string &fname, std::ios_base::openmode mode, bool create_directory)
static compare_fn active_
Definition: ban.hpp:49
std::string filename_
Definition: action_wml.cpp:564
#define b
std::pair< unsigned int, unsigned int > ip_mask
Definition: ban.hpp:56
std::shared_ptr< banned > banned_ptr
Definition: ban.hpp:34
std::string get_who_banned() const
Definition: ban.hpp:97
void read(const config &)
Definition: ban.cpp:161
std::string nick_
Definition: ban.hpp:69
static lg::log_domain log_server("server")
void unban_group(std::ostringstream &os, const std::string &group)
Definition: ban.cpp:558
Class for writing a config out to a file in pieces.
void list_deleted_bans(std::ostringstream &out, const std::string &mask="*") const
Definition: ban.cpp:594
std::string ban(const std::string &, const std::time_t &, const std::string &, const std::string &, const std::string &, const std::string &="")
Definition: ban.cpp:494
bool operator()(const banned_ptr &a, const banned_ptr &b) const
Definition: ban.cpp:46
std::time_t end_time_
Definition: ban.hpp:64
std::string get_human_start_time() const
Definition: ban.cpp:221
std::unique_ptr< std::istream > scoped_istream
Definition: filesystem.hpp:39
ip_mask parse_ip(const std::string &ip)
Definition: ban.cpp:116
static int writer(lua_State *L, const void *b, size_t size, void *ud)
Definition: lstrlib.cpp:221
unsigned int mask() const
Definition: ban.hpp:113
std::unique_ptr< std::ostream > scoped_ostream
Definition: filesystem.hpp:40
std::size_t i
Definition: function.cpp:967
Thrown by operations encountering invalid UTF-8 data.
std::string who_banned_
Definition: ban.hpp:67
mock_party p
std::ostream & operator<<(std::ostream &o, const banned &n)
Definition: ban.cpp:36
void write(config &) const
Definition: ban.cpp:193
std::string get_nick() const
Definition: ban.hpp:100
std::set< banned_ptr, banned_compare_subnet > ban_set
Definition: ban.hpp:52
static const std::string who_banned_default_
Definition: ban.hpp:70
Declarations for File-IO.
std::string lowercase(const std::string &s)
Returns a lowercased version of the string.
Definition: unicode.cpp:52
unsigned int ip_
Definition: ban.hpp:61
config & add_child(config_key_type key)
Definition: config.cpp:514
#define ERR_SERVER
Definition: ban.cpp:32
void list_bans(std::ostringstream &out, const std::string &mask="*")
Definition: ban.cpp:617
void init_ban_help()
Definition: ban.cpp:673
bool match_ip(const ip_mask &ip) const
Definition: ban.cpp:258
std::vector< std::string > split(const config_attribute_value &val)
std::string get_ip() const
Definition: ban.hpp:92
void unban(std::ostringstream &os, const std::string &ip, bool immediate_write=true)
Definition: ban.cpp:531
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 &#39;0&#39; or &#39;permanent&#39; in which ...
Definition: ban.cpp:332
Standard logging facilities (interface).
std::string message
Definition: exceptions.hpp:30
unsigned int get_mask_ip(unsigned int) const
Definition: ban.cpp:253
#define e
bool operator>(const banned &b) const
Definition: ban.cpp:248
std::string get_human_time_span() const
Definition: ban.cpp:239
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:61
static map_location::DIRECTION n
std::string::const_iterator iterator
Definition: tokenizer.hpp:25
bool operator()(const banned_ptr &a, const banned_ptr &b) const
Definition: ban.cpp:53
std::string ip_text_
Definition: ban.hpp:63
unsigned int mask_
Definition: ban.hpp:62