The Battle for Wesnoth  1.15.9+dev
ban.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2008 - 2018 by Pauli Nieminen <paniemin@cc.hut.fi>
3  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY.
11 
12  See the COPYING file for more details.
13 */
14 
15 #include "config.hpp"
16 #include "filesystem.hpp"
17 #include "lexical_cast.hpp"
18 #include "log.hpp"
20 #include "serialization/parser.hpp"
23 
24 #include "server/wesnothd/ban.hpp"
25 
26 #include <functional>
27 
28 namespace wesnothd
29 {
30 static lg::log_domain log_server("server");
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)
34 
35 std::ostream& operator<<(std::ostream& o, const banned& n)
36 {
37  return o << "IP: " << n.get_ip() <<
38  (n.get_nick().empty() ? "" : " nick: " + n.get_nick()) <<
39  " reason: '" << n.get_reason() << "'"
40  " start_time: " << n.get_human_start_time() <<
41  " end_time: " << n.get_human_end_time() <<
42  " issuer: " << n.get_who_banned();
43 }
44 
46 {
47  return (*a) > (*b);
48 }
49 
51 
53 {
54  return (this->*(active_))(a,b);
55 }
56 
58 {
59  return a->get_int_ip() < b->get_int_ip();
60 }
61 
62 const std::string banned::who_banned_default_ = "system";
63 
64 banned::banned(const std::string& ip)
65  : ip_(0)
66  , mask_(0)
67  , ip_text_()
68  , end_time_(0)
69  , start_time_(0)
70  , reason_()
71  , who_banned_(who_banned_default_)
72  , group_()
73  , nick_()
74 {
75  ip_mask pair = parse_ip(ip);
76  ip_ = pair.first;
77  mask_ = 0xFFFFFFFF;
78 }
79 
80 banned::banned(const std::string& ip,
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)
86  : ip_(0)
87  , mask_(0)
88  , ip_text_(ip)
89  , end_time_(end_time)
90  , start_time_(std::time(0))
91  , reason_(reason)
92  , who_banned_(who_banned)
93  , group_(group)
94  , nick_(nick)
95 {
96  ip_mask pair = parse_ip(ip_text_);
97  ip_ = pair.first;
98  mask_ = pair.second;
99 }
100 
102  : ip_(0)
103  , mask_(0)
104  , ip_text_()
105  , end_time_(0)
106  , start_time_(0)
107  , reason_()
109  , group_()
110  , nick_()
111 {
112  read(cfg);
113 }
114 
115 ip_mask parse_ip(const std::string& ip)
116 {
117  // We use bit operations to construct the integer
118  // ip_mask is a pair: first is ip and second is mask
119  ip_mask ret;
120  ret.first = 0;
121  ret.second = 0;
122  std::vector<std::string> split_ip = utils::split(ip, '.');
123  if (split_ip.size() > 4) throw banned::error("Malformed ip address: " + ip);
124 
125  unsigned int shift = 4*8; // start shifting from the highest byte
126  unsigned int mask = 0xFF000000;
127  const unsigned int complete_part_mask = 0xFF;
128  auto part = split_ip.begin();
129  bool wildcard = false;
130  do {
131  shift -= 8;
132  mask >>= 8;
133  if(part == split_ip.end()) {
134  if(!wildcard)
135  throw banned::error("Malformed ip address: '" + ip + "'");
136  // Adding 0 to ip and mask is nop
137  // we can then break out of loop
138  break;
139  } else {
140  if(*part == "*") {
141  wildcard = true;
142  // Adding 0 to ip and mask is nop
143  } else {
144  // wildcard = false;
145  unsigned int part_ip = lexical_cast_default<unsigned int>(*part, complete_part_mask + 1);
146  if(part_ip > complete_part_mask) {
147  throw banned::error("Malformed ip address: '" + ip + "'");
148  }
149 
150  ret.first |= (part_ip << shift);
151  ret.second |= (complete_part_mask << shift);
152  }
153  }
154  ++part;
155  } while(shift);
156 
157  return ret;
158 }
159 
160 void banned::read(const config& cfg)
161 {
162  {
163  // parse ip and mask
164  ip_text_ = cfg["ip"].str();
165  ip_mask pair = parse_ip(ip_text_);
166  ip_ = pair.first;
167  mask_ = pair.second;
168  }
169 
170  nick_ = cfg["nick"].str();
171 
172  if(cfg.has_attribute("end_time")) {
173  end_time_ = cfg["end_time"].to_time_t(0);
174  }
175 
176  if(cfg.has_attribute("start_time")) {
177  start_time_ = cfg["start_time"].to_time_t(0);
178  }
179 
180  reason_ = cfg["reason"].str();
181 
182  // only overwrite defaults if exists
183  if(cfg.has_attribute("who_banned")) {
184  who_banned_ = cfg["who_banned"].str();
185  }
186 
187  if(cfg.has_attribute("group")) {
188  group_ = cfg["group"].str();
189  }
190 }
191 
192 void banned::write(config& cfg) const
193 {
194  cfg["ip"] = get_ip();
195  cfg["nick"] = get_nick();
196 
197  if(end_time_ > 0) {
198  std::stringstream ss;
199  ss << end_time_;
200  cfg["end_time"] = ss.str();
201  }
202 
203  if(start_time_ > 0) {
204  std::stringstream ss;
205  ss << start_time_;
206  cfg["start_time"] = ss.str();
207  }
208 
209  cfg["reason"] = reason_;
210 
212  cfg["who_banned"] = who_banned_;
213  }
214 
215  if(!group_.empty()) {
216  cfg["group"] = group_;
217  }
218 }
219 
220 std::string banned::get_human_start_time() const
221 {
222  if(start_time_ == 0) {
223  return "unknown";
224  }
225 
227 }
228 
229 std::string banned::get_human_end_time() const
230 {
231  if(end_time_ == 0) {
232  return "permanent";
233  }
234 
236 }
237 
238 std::string banned::get_human_time_span() const
239 {
240  if(end_time_ == 0) {
241  return "permanent";
242  }
243 
244  return lg::get_timespan(end_time_ - std::time(nullptr));
245 }
246 
247 bool banned::operator>(const banned& b) const
248 {
249  return end_time_ > b.get_end_time();
250 }
251 
252 unsigned int banned::get_mask_ip(unsigned int mask) const
253 {
254  return ip_ & mask & mask_;
255 }
256 
257 bool banned::match_ip(const ip_mask& pair) const
258 {
259  return (ip_ & mask_) == (pair.first & mask_);
260 }
261 
262 // Unlike match_ip this function takes both masks into account.
263 bool banned::match_ipmask(const ip_mask& pair) const
264 {
265  return (ip_ & mask_ & pair.second) == (pair.first & pair.second & mask_);
266 }
267 
269 {
270  if(filename_.empty() || !filesystem::file_exists(filename_)) {
271  return;
272  }
273 
274  LOG_SERVER << "Reading bans from " << filename_ << "\n";
275  config cfg;
276  dirty_ = false;
278  read_gz(cfg, *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() != 0)
286  time_queue_.push(new_ban);
287  } catch(const banned::error& e) {
288  ERR_SERVER << e.message << " while reading bans" << std::endl;
289  }
290  }
291 
292  // load deleted too
293  if(const config& cfg_del = cfg.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" << std::endl;
300  }
301  }
302  }
303 }
304 
306 {
307  if(filename_.empty() || !dirty_) {
308  return;
309  }
310 
311  LOG_SERVER << "Writing bans to " << filename_ << "\n";
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 bool ban_manager::parse_time(const std::string& duration, std::time_t* time) const
332 {
333  if (!time) return false;
334 
335  if(duration.substr(0, 4) == "TIME") {
336  std::tm* loc;
337  loc = std::localtime(time);
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 << "'.\n";
365  break;
366  }
367  number = 0;
368  }
369  }
370  *time = mktime(loc);
371  return true;
372  }
373 
374  const auto time_itor = ban_times_.find(duration);
375 
376  std::string dur_lower;
377  try {
378  dur_lower = utf8::lowercase(duration);
379  } catch(const utf8::invalid_utf8_exception& e) {
380  ERR_SERVER << "While parsing ban command duration string, caught an invalid utf8 exception: " << e.what() << std::endl;
381  return false;
382  }
383 
384  if(dur_lower == "permanent" || duration == "0") {
385  *time = 0;
386  } else if(ban_times_.find(duration) != ban_times_.end()) {
387  *time += time_itor->second;
388  } else {
389  std::string::const_iterator i = duration.begin();
390  int number = -1;
391  for (std::string::const_iterator d_end = duration.end(); i != d_end; ++i) {
392  if (is_digit(*i))
393  {
394  if (number == -1) number = 0;
395  number = number * 10 + to_digit(*i);
396  } else {
397  if (number == -1) number = 1;
398  switch(*i)
399  {
400  case 'Y':
401  case 'y':
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') {
406  } else --i;
407  *time += number * 365*24*60*60; // a year;
408  break;
409  case 'M':
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') {
416  } else --i;
417  *time += number * 60;
418  break;
419  }
420  --i;
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') {
426  } else --i;
427  *time += number * 30*24*60*60; // 30 days
428  break;
429  case 'D':
430  case 'd':
431  if (++i != d_end && tolower(*i) == 'a'
432  && ++i != d_end && tolower(*i) == 'y'
433  && ++i != d_end && tolower(*i) == 's') {
434  } else --i;
435  *time += number * 24*60*60;
436  break;
437  case 'H':
438  case 'h':
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') {
443  } else --i;
444  *time += number * 60*60;
445  break;
446  case 'm':
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') {
452  } else --i;
453  *time += number * 30*24*60*60; // 30 days
454  break;
455  }
456  --i;
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') {
463  } else --i;
464  *time += number * 60;
465  break;
466  case 'S':
467  case 's':
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') {
474  } else --i;
475  *time += number;
476  break;
477  default:
478  return false;
479  break;
480  }
481  number = -1;
482  }
483  }
484 
485  if(is_digit(*--i)) {
486  *time += number * 60; // default to minutes
487  }
488  }
489 
490  return true;
491 }
492 
493 std::string ban_manager::ban(const std::string& ip,
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)
499 {
500  std::ostringstream ret;
501  try {
502  ban_set::iterator ban;
503  if((ban = bans_.find(std::make_shared<banned>(ip))) != bans_.end()) {
504  // Already exsiting ban for ip. We have to first remove it
505  ret << "Overwriting ban: " << (**ban) << "\n";
506  bans_.erase(ban);
507  }
508  } catch(const banned::error& e) {
509  ERR_SERVER << e.message << " while creating dummy ban for finding existing ban" << std::endl;
510  return e.message;
511  }
512 
513  try {
514  auto new_ban = std::make_shared<banned>(ip, end_time, reason, who_banned, group, nick);
515  bans_.insert(new_ban);
516  if(end_time != 0) {
517  time_queue_.push(new_ban);
518  }
519  ret << *new_ban;
520  } catch(const banned::error& e) {
521  ERR_SERVER << e.message << " while banning" << std::endl;
522  return e.message;
523  }
524 
525  dirty_ = true;
526  write();
527  return ret.str();
528 }
529 
530 void ban_manager::unban(std::ostringstream& os, const std::string& ip, bool immediate_write)
531 {
532  ban_set::iterator ban;
533  try {
534  ban = bans_.find(std::make_shared<banned>(ip));
535  } catch (const banned::error& e) {
536  ERR_SERVER << e.message << std::endl;
537  os << e.message;
538  return;
539  }
540 
541  if(ban == bans_.end()) {
542  os << "There is no ban on '" << ip << "'.";
543  return;
544  }
545 
546  // keep ban entry still in memory
547  os << "Ban on '" << **ban << "' removed.";
548  // group bans don't get saved
549  if ((*ban)->get_group().empty()) deleted_bans_.push_back(*ban);
550  bans_.erase(ban);
551  dirty_ = true;
552  if(immediate_write) {
553  write();
554  }
555 }
556 
557 void ban_manager::unban_group(std::ostringstream& os, const std::string& group)
558 {
559  ban_set temp;
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); });
562 
563  os << "Removed " << (bans_.size() - temp.size()) << " bans";
564  bans_.swap(temp);
565  dirty_ = true;
566  write();
567 }
568 
569 void ban_manager::check_ban_times(std::time_t time_now)
570 {
571  while(!time_queue_.empty()) {
572  banned_ptr ban = time_queue_.top();
573 
574  if(ban->get_end_time() > time_now) {
575  // No bans going to expire
576  DBG_SERVER << "ban " << ban->get_ip() << " not removed. time: " << time_now << " end_time "
577  << ban->get_end_time() << "\n";
578  break;
579  }
580 
581  // This ban is going to expire so delete it.
582  LOG_SERVER << "Remove a ban " << ban->get_ip() << ". time: " << time_now << " end_time " << ban->get_end_time()
583  << "\n";
584  std::ostringstream os;
585  unban(os, ban->get_ip(), false);
586  time_queue_.pop();
587  }
588 
589  // Save bans if there is any new ones
590  write();
591 }
592 
593 void ban_manager::list_deleted_bans(std::ostringstream& out, const std::string& mask) const
594 {
595  if(deleted_bans_.empty()) {
596  out << "No removed bans found.";
597  return;
598  }
599 
600  ip_mask pair;
601  try {
602  pair = parse_ip(mask);
603  } catch(const banned::error& e) {
604  out << "parse error: " << e.message;
605  return;
606  }
607 
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);
612  }
613  }
614 }
615 
616 void ban_manager::list_bans(std::ostringstream& out, const std::string& mask)
617 {
618  expire_bans();
619  if(bans_.empty()) {
620  out << "No bans set.";
621  return;
622  }
623 
624  ip_mask pair;
625  try {
626  pair = parse_ip(mask);
627  } catch(const banned::error& e) {
628  out << "parse error: " << e.message;
629  return;
630  }
631 
632  out << "BAN LIST";
633  std::set<std::string> groups;
634 
635  for(const auto& b : bans_) {
636  if(b->get_group().empty()) {
637  if(b->match_ipmask(pair)) {
638  out << "\n" << *b;
639  }
640  } else {
641  groups.insert(b->get_group());
642  }
643  }
644 
645  // Don't list ban groups when looking for specific bans.
646  if(!groups.empty() && mask == "*") {
647  out << "\nban groups: ";
648 
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));
653  }
654 }
655 
656 std::string ban_manager::is_ip_banned(const std::string& ip)
657 {
658  expire_bans();
659  ip_mask pair;
660  try {
661  pair = parse_ip(ip);
662  } catch (const banned::error&) {
663  return "";
664  }
665 
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() + ")";
670 }
671 
673 {
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"
679  " argument.\n";
680  auto itor = ban_times_.begin();
681  if(itor != ban_times_.end()) {
682  ban_help_ += "You can also use " + itor->first;
683  ++itor;
684  }
685  for(; itor != ban_times_.end(); ++itor) {
686  ban_help_ += std::string(", ") + itor->first;
687  }
688  if(!ban_times_.empty()) {
689  ban_help_ += " for standard ban times. (not combinable)\n";
690  }
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";
694 }
695 
697 {
698  ban_times_.clear();
699  for(const config& bt : cfg.child_range("ban_time")) {
700  std::time_t duration = 0;
701  if(parse_time(bt["time"], &duration)) {
702  ban_times_.emplace(bt["name"], duration);
703  }
704  }
705 
706  init_ban_help();
707  if(filename_ != cfg["ban_save_file"]) {
708  dirty_ = true;
709  filename_ = cfg["ban_save_file"].str();
710  }
711 }
712 
714 {
715  try {
716  write();
717  } catch(...) {
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
bool(banned_compare_subnet::* compare_fn)(const banned_ptr &a, const banned_ptr &b) const
Definition: ban.hpp:47
#define LOG_SERVER
Definition: ban.cpp:32
bool match_ipmask(const ip_mask &ip) const
Definition: ban.cpp:263
#define DBG_SERVER
Definition: ban.cpp:33
std::string reason_
Definition: ban.hpp:65
std::string get_reason() const
Definition: ban.hpp:88
std::string get_timestamp(const std::time_t &t, const std::string &format)
Definition: log.cpp:176
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:415
void write(const config &cfg)
std::string get_timespan(const std::time_t &t)
Definition: log.cpp:183
void load_config(const config &)
Definition: ban.cpp:696
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:80
bool less(const banned_ptr &a, const banned_ptr &b) const
Definition: ban.cpp:57
std::time_t start_time_
Definition: ban.hpp:64
static l_noret error(LoadState *S, const char *why)
Definition: lundump.cpp:39
New lexcical_cast header.
bool has_attribute(config_key_type key) const
Definition: config.cpp:208
#define a
void check_ban_times(std::time_t time_now)
Definition: ban.cpp:569
std::string is_ip_banned(const std::string &ip)
Definition: ban.cpp:656
static bool file_exists(const bfs::path &fpath)
Definition: filesystem.cpp:263
std::time_t get_end_time() const
Definition: ban.hpp:80
child_itors child_range(config_key_type key)
Definition: config.cpp:357
std::string get_human_end_time() const
Definition: ban.cpp:229
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:682
Definitions for the interface to Wesnoth Markup Language (WML).
std::string group_
Definition: ban.hpp:67
static compare_fn active_
Definition: ban.hpp:48
std::string filename_
Definition: action_wml.cpp:562
#define b
std::pair< unsigned int, unsigned int > ip_mask
Definition: ban.hpp:55
std::shared_ptr< banned > banned_ptr
Definition: ban.hpp:33
std::string get_who_banned() const
Definition: ban.hpp:96
void read(const config &)
Definition: ban.cpp:160
std::string nick_
Definition: ban.hpp:68
static lg::log_domain log_server("server")
void unban_group(std::ostringstream &os, const std::string &group)
Definition: ban.cpp:557
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:593
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:493
bool operator()(const banned_ptr &a, const banned_ptr &b) const
Definition: ban.cpp:45
std::time_t end_time_
Definition: ban.hpp:63
std::string get_human_start_time() const
Definition: ban.cpp:220
std::unique_ptr< std::istream > scoped_istream
Definition: filesystem.hpp:36
ip_mask parse_ip(const std::string &ip)
Definition: ban.cpp:115
unsigned int mask() const
Definition: ban.hpp:112
std::unique_ptr< std::ostream > scoped_ostream
Definition: filesystem.hpp:37
std::size_t i
Definition: function.cpp:933
Thrown by operations encountering invalid UTF-8 data.
std::string who_banned_
Definition: ban.hpp:66
mock_party p
std::ostream & operator<<(std::ostream &o, const banned &n)
Definition: ban.cpp:35
void write(config &) const
Definition: ban.cpp:192
std::string get_nick() const
Definition: ban.hpp:99
std::set< banned_ptr, banned_compare_subnet > ban_set
Definition: ban.hpp:51
static const std::string who_banned_default_
Definition: ban.hpp:69
Declarations for File-IO.
static int writer(lua_State *L, const void *b, size_t size, void *B)
Definition: lstrlib.cpp:182
std::string lowercase(const std::string &s)
Returns a lowercased version of the string.
Definition: unicode.cpp:51
unsigned int ip_
Definition: ban.hpp:60
config & add_child(config_key_type key)
Definition: config.cpp:471
#define ERR_SERVER
Definition: ban.cpp:31
void list_bans(std::ostringstream &out, const std::string &mask="*")
Definition: ban.cpp:616
void init_ban_help()
Definition: ban.cpp:672
bool match_ip(const ip_mask &ip) const
Definition: ban.cpp:257
std::vector< std::string > split(const config_attribute_value &val)
std::string get_ip() const
Definition: ban.hpp:91
void unban(std::ostringstream &os, const std::string &ip, bool immediate_write=true)
Definition: ban.cpp:530
Definition: ban.cpp:28
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:331
Standard logging facilities (interface).
std::string message
Definition: exceptions.hpp:31
unsigned int get_mask_ip(unsigned int) const
Definition: ban.cpp:252
#define e
bool operator>(const banned &b) const
Definition: ban.cpp:247
std::string get_human_time_span() const
Definition: ban.cpp:238
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:59
static map_location::DIRECTION n
std::string::const_iterator iterator
Definition: tokenizer.hpp:24
bool operator()(const banned_ptr &a, const banned_ptr &b) const
Definition: ban.cpp:52
std::string ip_text_
Definition: ban.hpp:62
unsigned int mask_
Definition: ban.hpp:61
filesystem::scoped_ostream ostream_file(const std::string &fname, bool create_directory)