Anope IRC Services  Version 2.0
os_session.cpp
Go to the documentation of this file.
1 /* OperServ core functions
2  *
3  * (C) 2003-2014 Anope Team
4  * Contact us at team@anope.org
5  *
6  * Please read COPYING and README for further details.
7  *
8  * Based on the original code of Epona by Lara.
9  * Based on the original code of Services by Andy Church.
10  */
11 
12 #include "module.h"
13 #include "modules/os_session.h"
14 
15 namespace
16 {
17  /* The default session limit */
18  unsigned session_limit;
19  /* How many times to kill before adding an AKILL */
20  unsigned max_session_kill;
21  /* How long session akills should last */
22  time_t session_autokill_expiry;
23  /* Reason to use for session kills */
24  Anope::string sle_reason;
25  /* Optional second reason */
26  Anope::string sle_detailsloc;
27 
28  /* Max limit that can be used for exceptions */
29  unsigned max_exception_limit;
30  /* How long before exceptions expire by default */
31  time_t exception_expiry;
32 
33  /* Number of bits to use when comparing session IPs */
34  unsigned ipv4_cidr;
35  unsigned ipv6_cidr;
36 }
37 
39 {
42  public:
43  MySessionService(Module *m) : SessionService(m), Exceptions("Exception") { }
44 
46  {
47  return new Exception();
48  }
49 
51  {
52  this->Exceptions->push_back(e);
53  }
54 
56  {
57  ExceptionVector::iterator it = std::find(this->Exceptions->begin(), this->Exceptions->end(), e);
58  if (it != this->Exceptions->end())
59  this->Exceptions->erase(it);
60  }
61 
63  {
64  for (std::vector<Exception *>::const_iterator it = this->Exceptions->begin(), it_end = this->Exceptions->end(); it != it_end; ++it)
65  {
66  Exception *e = *it;
67  if (Anope::Match(u->host, e->mask) || Anope::Match(u->ip.addr(), e->mask))
68  return e;
69 
70  if (cidr(e->mask).match(u->ip))
71  return e;
72  }
73  return NULL;
74  }
75 
77  {
78  for (std::vector<Exception *>::const_iterator it = this->Exceptions->begin(), it_end = this->Exceptions->end(); it != it_end; ++it)
79  {
80  Exception *e = *it;
81  if (Anope::Match(host, e->mask))
82  return e;
83 
84  if (cidr(e->mask).match(sockaddrs(host)))
85  return e;
86  }
87 
88  return NULL;
89  }
90 
92  {
93  return this->Exceptions;
94  }
95 
97  {
98  this->Sessions.erase(s->addr);
99  }
100 
102  {
103  cidr c(ip, ip.find(':') != Anope::string::npos ? ipv6_cidr : ipv4_cidr);
104  if (!c.valid())
105  return NULL;
106  SessionMap::iterator it = this->Sessions.find(c);
107  if (it != this->Sessions.end())
108  return it->second;
109  return NULL;
110  }
111 
112  SessionMap::iterator FindSessionIterator(const sockaddrs &ip)
113  {
114  cidr c(ip, ip.ipv6() ? ipv6_cidr : ipv4_cidr);
115  if (!c.valid())
116  return this->Sessions.end();
117  return this->Sessions.find(c);
118  }
119 
121  {
122  return this->Sessions[ip];
123  }
124 
126  {
127  return this->Sessions;
128  }
129 };
130 
132 {
133  protected:
135  unsigned deleted;
137  public:
138  ExceptionDelCallback(CommandSource &_source, const Anope::string &numlist, Command *c) : NumberList(numlist, true), source(_source), deleted(0), cmd(c)
139  {
140  }
141 
143  {
144  if (!deleted)
145  source.Reply(_("No matching entries on session-limit exception list."));
146  else if (deleted == 1)
147  source.Reply(_("Deleted 1 entry from session-limit exception list."));
148  else
149  source.Reply(_("Deleted %d entries from session-limit exception list."), deleted);
150  }
151 
152  virtual void HandleNumber(unsigned number) anope_override
153  {
154  if (!number || number > session_service->GetExceptions().size())
155  return;
156 
157  Log(LOG_ADMIN, source, cmd) << "to remove the session limit exception for " << session_service->GetExceptions()[number - 1]->mask;
158 
159  ++deleted;
160  DoDel(source, number - 1);
161  }
162 
163  static void DoDel(CommandSource &source, unsigned index)
164  {
165  Exception *e = session_service->GetExceptions()[index];
166  FOREACH_MOD(OnExceptionDel, (source, e));
167 
168  session_service->DelException(e);
169  delete e;
170  }
171 };
172 
173 class CommandOSSession : public Command
174 {
175  private:
176  void DoList(CommandSource &source, const std::vector<Anope::string> &params)
177  {
178  Anope::string param = params[1];
179 
180  unsigned mincount = 0;
181  try
182  {
183  mincount = convertTo<unsigned>(param);
184  }
185  catch (const ConvertException &) { }
186 
187  if (mincount <= 1)
188  source.Reply(_("Invalid threshold value. It must be a valid integer greater than 1."));
189  else
190  {
191  ListFormatter list(source.GetAccount());
192  list.AddColumn(_("Session")).AddColumn(_("Host"));
193 
194  for (SessionService::SessionMap::iterator it = session_service->GetSessions().begin(), it_end = session_service->GetSessions().end(); it != it_end; ++it)
195  {
196  Session *session = it->second;
197 
198  if (session->count >= mincount)
199  {
201  entry["Session"] = stringify(session->count);
202  entry["Host"] = session->addr.mask();
203  list.AddEntry(entry);
204  }
205  }
206 
207  source.Reply(_("Hosts with at least \002%d\002 sessions:"), mincount);
208 
209  std::vector<Anope::string> replies;
210  list.Process(replies);
211 
212 
213  for (unsigned i = 0; i < replies.size(); ++i)
214  source.Reply(replies[i]);
215  }
216 
217  return;
218  }
219 
220  void DoView(CommandSource &source, const std::vector<Anope::string> &params)
221  {
222  Anope::string param = params[1];
223  Session *session = session_service->FindSession(param);
224 
225  Exception *exception = session_service->FindException(param);
226  Anope::string entry = "no entry";
227  unsigned limit = session_limit;
228  if (exception)
229  {
230  if (!exception->limit)
231  limit = 0;
232  else if (exception->limit > limit)
233  limit = exception->limit;
234  entry = exception->mask;
235  }
236 
237  if (!session)
238  source.Reply(_("\002%s\002 not found on session list, but has a limit of \002%d\002 because it matches entry: \002%s\002."), param.c_str(), limit, entry.c_str());
239  else
240  source.Reply(_("The host \002%s\002 currently has \002%d\002 sessions with a limit of \002%d\002 because it matches entry: \002%s\002."), session->addr.mask().c_str(), session->count, limit, entry.c_str());
241  }
242  public:
243  CommandOSSession(Module *creator) : Command(creator, "operserv/session", 2, 2)
244  {
245  this->SetDesc(_("View the list of host sessions"));
246  this->SetSyntax(_("LIST \037threshold\037"));
247  this->SetSyntax(_("VIEW \037host\037"));
248  }
249 
250  void Execute(CommandSource &source, const std::vector<Anope::string> &params) anope_override
251  {
252  const Anope::string &cmd = params[0];
253 
254  Log(LOG_ADMIN, source, this) << cmd << " " << params[1];
255 
256  if (!session_limit)
257  source.Reply(_("Session limiting is disabled."));
258  else if (cmd.equals_ci("LIST"))
259  return this->DoList(source, params);
260  else if (cmd.equals_ci("VIEW"))
261  return this->DoView(source, params);
262  else
263  this->OnSyntaxError(source, "");
264  }
265 
266  bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override
267  {
268  this->SendSyntax(source);
269  source.Reply(" ");
270  source.Reply(_("Allows Services Operators to view the session list.\n"
271  " \n"
272  "\002SESSION LIST\002 lists hosts with at least \037threshold\037 sessions.\n"
273  "The threshold must be a number greater than 1. This is to\n"
274  "prevent accidental listing of the large number of single\n"
275  "session hosts.\n"
276  " \n"
277  "\002SESSION VIEW\002 displays detailed information about a specific\n"
278  "host - including the current session count and session limit.\n"
279  "The \037host\037 value may not include wildcards.\n"
280  " \n"
281  "See the \002EXCEPTION\002 help for more information about session\n"
282  "limiting and how to set session limits specific to certain\n"
283  "hosts and groups thereof."));
284  return true;
285  }
286 };
287 
289 {
290  private:
291  void DoAdd(CommandSource &source, const std::vector<Anope::string> &params)
292  {
293  Anope::string mask, expiry, limitstr;
294  unsigned last_param = 3;
295 
296  mask = params.size() > 1 ? params[1] : "";
297  if (!mask.empty() && mask[0] == '+')
298  {
299  expiry = mask;
300  mask = params.size() > 2 ? params[2] : "";
301  last_param = 4;
302  }
303 
304  limitstr = params.size() > last_param - 1 ? params[last_param - 1] : "";
305 
306  if (params.size() <= last_param)
307  {
308  this->OnSyntaxError(source, "ADD");
309  return;
310  }
311 
312  Anope::string reason = params[last_param];
313  if (last_param == 3 && params.size() > 4)
314  reason += " " + params[4];
315  if (reason.empty())
316  {
317  this->OnSyntaxError(source, "ADD");
318  return;
319  }
320 
321  time_t expires = !expiry.empty() ? Anope::DoTime(expiry) : exception_expiry;
322  if (expires < 0)
323  {
324  source.Reply(BAD_EXPIRY_TIME);
325  return;
326  }
327  else if (expires > 0)
328  expires += Anope::CurTime;
329 
330  unsigned limit = -1;
331  try
332  {
333  limit = convertTo<unsigned>(limitstr);
334  }
335  catch (const ConvertException &) { }
336 
337  if (limit > max_exception_limit)
338  {
339  source.Reply(_("Invalid session limit. It must be a valid integer greater than or equal to zero and less than \002%d\002."), max_exception_limit);
340  return;
341  }
342  else
343  {
344  if (mask.find('!') != Anope::string::npos || mask.find('@') != Anope::string::npos)
345  {
346  source.Reply(_("Invalid hostmask. Only real hostmasks are valid, as exceptions are not matched against nicks or usernames."));
347  return;
348  }
349 
350  for (std::vector<Exception *>::iterator it = session_service->GetExceptions().begin(), it_end = session_service->GetExceptions().end(); it != it_end; ++it)
351  {
352  Exception *e = *it;
353  if (e->mask.equals_ci(mask))
354  {
355  if (e->limit != limit)
356  {
357  e->limit = limit;
358  source.Reply(_("Exception for \002%s\002 has been updated to %d."), mask.c_str(), e->limit);
359  }
360  else
361  source.Reply(_("\002%s\002 already exists on the EXCEPTION list."), mask.c_str());
362  return;
363  }
364  }
365 
366  Exception *exception = new Exception();
367  exception->mask = mask;
368  exception->limit = limit;
369  exception->reason = reason;
370  exception->time = Anope::CurTime;
371  exception->who = source.GetNick();
372  exception->expires = expires;
373 
374  EventReturn MOD_RESULT;
375  FOREACH_RESULT(OnExceptionAdd, MOD_RESULT, (exception));
376  if (MOD_RESULT == EVENT_STOP)
377  delete exception;
378  else
379  {
380  Log(LOG_ADMIN, source, this) << "to set the session limit for " << mask << " to " << limit;
381  session_service->AddException(exception);
382  source.Reply(_("Session limit for \002%s\002 set to \002%d\002."), mask.c_str(), limit);
383  if (Anope::ReadOnly)
384  source.Reply(READ_ONLY_MODE);
385  }
386  }
387 
388  return;
389  }
390 
391  void DoDel(CommandSource &source, const std::vector<Anope::string> &params)
392  {
393  const Anope::string &mask = params.size() > 1 ? params[1] : "";
394 
395  if (mask.empty())
396  {
397  this->OnSyntaxError(source, "DEL");
398  return;
399  }
400 
401  if (isdigit(mask[0]) && mask.find_first_not_of("1234567890,-") == Anope::string::npos)
402  {
403  ExceptionDelCallback list(source, mask, this);
404  list.Process();
405  }
406  else
407  {
408  unsigned i = 0, end = session_service->GetExceptions().size();
409  for (; i < end; ++i)
410  if (mask.equals_ci(session_service->GetExceptions()[i]->mask))
411  {
412  Log(LOG_ADMIN, source, this) << "to remove the session limit exception for " << mask;
413  ExceptionDelCallback::DoDel(source, i);
414  source.Reply(_("\002%s\002 deleted from session-limit exception list."), mask.c_str());
415  break;
416  }
417  if (i == end)
418  source.Reply(_("\002%s\002 not found on session-limit exception list."), mask.c_str());
419  }
420 
421  if (Anope::ReadOnly)
422  source.Reply(READ_ONLY_MODE);
423 
424  return;
425  }
426 
427  void DoMove(CommandSource &source, const std::vector<Anope::string> &params)
428  {
429  const Anope::string &n1str = params.size() > 1 ? params[1] : ""; /* From position */
430  const Anope::string &n2str = params.size() > 2 ? params[2] : ""; /* To position */
431  int n1, n2;
432 
433  if (n2str.empty())
434  {
435  this->OnSyntaxError(source, "MOVE");
436  return;
437  }
438 
439  n1 = n2 = -1;
440  try
441  {
442  n1 = convertTo<int>(n1str);
443  n2 = convertTo<int>(n2str);
444  }
445  catch (const ConvertException &) { }
446 
447  if (n1 >= 0 && static_cast<unsigned>(n1) < session_service->GetExceptions().size() && n2 >= 0 && static_cast<unsigned>(n2) < session_service->GetExceptions().size() && n1 != n2)
448  {
449  Exception *temp = session_service->GetExceptions()[n1];
450  session_service->GetExceptions()[n1] = session_service->GetExceptions()[n2];
451  session_service->GetExceptions()[n2] = temp;
452 
453  Log(LOG_ADMIN, source, this) << "to move exception " << session_service->GetExceptions()[n1]->mask << " from position " << n1 + 1 << " to position " << n2 + 1;
454  source.Reply(_("Exception for \002%s\002 (#%d) moved to position \002%d\002."), session_service->GetExceptions()[n1]->mask.c_str(), n1 + 1, n2 + 1);
455 
456  if (Anope::ReadOnly)
457  source.Reply(READ_ONLY_MODE);
458  }
459  else
460  this->OnSyntaxError(source, "MOVE");
461 
462  return;
463  }
464 
465  void ProcessList(CommandSource &source, const std::vector<Anope::string> &params, ListFormatter &list)
466  {
467  const Anope::string &mask = params.size() > 1 ? params[1] : "";
468 
469  if (session_service->GetExceptions().empty())
470  {
471  source.Reply(_("The session exception list is empty."));
472  return;
473  }
474 
475  if (!mask.empty() && mask.find_first_not_of("1234567890,-") == Anope::string::npos)
476  {
477  class ExceptionListCallback : public NumberList
478  {
479  CommandSource &source;
480  ListFormatter &list;
481  public:
482  ExceptionListCallback(CommandSource &_source, ListFormatter &_list, const Anope::string &numlist) : NumberList(numlist, false), source(_source), list(_list)
483  {
484  }
485 
486  void HandleNumber(unsigned Number) anope_override
487  {
488  if (!Number || Number > session_service->GetExceptions().size())
489  return;
490 
491  Exception *e = session_service->GetExceptions()[Number - 1];
492 
494  entry["Number"] = stringify(Number);
495  entry["Mask"] = e->mask;
496  entry["By"] = e->who;
497  entry["Created"] = Anope::strftime(e->time, NULL, true);
498  entry["Expires"] = Anope::Expires(e->expires, source.GetAccount());
499  entry["Limit"] = stringify(e->limit);
500  entry["Reason"] = e->reason;
501  this->list.AddEntry(entry);
502  }
503  }
504  nl_list(source, list, mask);
505  nl_list.Process();
506  }
507  else
508  {
509  for (unsigned i = 0, end = session_service->GetExceptions().size(); i < end; ++i)
510  {
511  Exception *e = session_service->GetExceptions()[i];
512  if (mask.empty() || Anope::Match(e->mask, mask))
513  {
515  entry["Number"] = stringify(i + 1);
516  entry["Mask"] = e->mask;
517  entry["By"] = e->who;
518  entry["Created"] = Anope::strftime(e->time, NULL, true);
519  entry["Expires"] = Anope::Expires(e->expires, source.GetAccount());
520  entry["Limit"] = stringify(e->limit);
521  entry["Reason"] = e->reason;
522  list.AddEntry(entry);
523  }
524  }
525  }
526 
527  if (list.IsEmpty())
528  source.Reply(_("No matching entries on session-limit exception list."));
529  else
530  {
531  source.Reply(_("Current Session Limit Exception list:"));
532 
533  std::vector<Anope::string> replies;
534  list.Process(replies);
535 
536  for (unsigned i = 0; i < replies.size(); ++i)
537  source.Reply(replies[i]);
538  }
539  }
540 
541  void DoList(CommandSource &source, const std::vector<Anope::string> &params)
542  {
543  ListFormatter list(source.GetAccount());
544  list.AddColumn(_("Number")).AddColumn(_("Limit")).AddColumn(_("Mask"));
545 
546  this->ProcessList(source, params, list);
547  }
548 
549  void DoView(CommandSource &source, const std::vector<Anope::string> &params)
550  {
551  ListFormatter list(source.GetAccount());
552  list.AddColumn(_("Number")).AddColumn(_("Mask")).AddColumn(_("By")).AddColumn(_("Created")).AddColumn(_("Expires")).AddColumn(_("Limit")).AddColumn(_("Reason"));
553 
554  this->ProcessList(source, params, list);
555  }
556 
557  public:
558  CommandOSException(Module *creator) : Command(creator, "operserv/exception", 1, 5)
559  {
560  this->SetDesc(_("Modify the session-limit exception list"));
561  this->SetSyntax(_("ADD [\037+expiry\037] \037mask\037 \037limit\037 \037reason\037"));
562  this->SetSyntax(_("DEL {\037mask\037 | \037entry-num\037 | \037list\037}"));
563  this->SetSyntax(_("MOVE \037num\037 \037position\037"));
564  this->SetSyntax(_("LIST [\037mask\037 | \037list\037]"));
565  this->SetSyntax(_("VIEW [\037mask\037 | \037list\037]"));
566  }
567 
568  void Execute(CommandSource &source, const std::vector<Anope::string> &params) anope_override
569  {
570  const Anope::string &cmd = params[0];
571 
572  if (!session_limit)
573  source.Reply(_("Session limiting is disabled."));
574  else if (cmd.equals_ci("ADD"))
575  return this->DoAdd(source, params);
576  else if (cmd.equals_ci("DEL"))
577  return this->DoDel(source, params);
578  else if (cmd.equals_ci("MOVE"))
579  return this->DoMove(source, params);
580  else if (cmd.equals_ci("LIST"))
581  return this->DoList(source, params);
582  else if (cmd.equals_ci("VIEW"))
583  return this->DoView(source, params);
584  else
585  this->OnSyntaxError(source, "");
586  }
587 
588  bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override
589  {
590  this->SendSyntax(source);
591  source.Reply(" ");
592  source.Reply(_("Allows Services Operators to manipulate the list of hosts that\n"
593  "have specific session limits - allowing certain machines,\n"
594  "such as shell servers, to carry more than the default number\n"
595  "of clients at a time. Once a host reaches its session limit,\n"
596  "all clients attempting to connect from that host will be\n"
597  "killed. Before the user is killed, they are notified, of a\n"
598  "source of help regarding session limiting. The content of\n"
599  "this notice is a config setting."));
600  source.Reply(" ");
601  source.Reply(_("\002EXCEPTION ADD\002 adds the given host mask to the exception list.\n"
602  "Note that \002nick!user@host\002 and \002user@host\002 masks are invalid!\n"
603  "Only real host masks, such as \002box.host.dom\002 and \002*.host.dom\002,\n"
604  "are allowed because sessions limiting does not take nick or\n"
605  "user names into account. \037limit\037 must be a number greater than\n"
606  "or equal to zero. This determines how many sessions this host\n"
607  "may carry at a time. A value of zero means the host has an\n"
608  "unlimited session limit. See the \002AKILL\002 help for details about\n"
609  "the format of the optional \037expiry\037 parameter.\n"
610  " \n"
611  "\002EXCEPTION DEL\002 removes the given mask from the exception list.\n"
612  " \n"
613  "\002EXCEPTION MOVE\002 moves exception \037num\037 to \037position\037. The\n"
614  "sessions inbetween will be shifted up or down to fill the gap.\n"
615  " \n"
616  "\002EXCEPTION LIST\002 and \002EXCEPTION VIEW\002 show all current\n"
617  "sessions if the optional mask is given, the list is limited\n"
618  "to those sessions matching the mask. The difference is that\n"
619  "\002EXCEPTION VIEW\002 is more verbose, displaying the name of the\n"
620  "person who added the exception, its session limit, reason,\n"
621  "host mask and the expiry date and time.\n"
622  " \n"
623  "Note that a connecting client will \"use\" the first exception\n"
624  "their host matches."));
625  return true;
626  }
627 };
628 
629 class OSSession : public Module
630 {
636 
637  public:
638  OSSession(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR),
639  exception_type("Exception", Exception::Unserialize), ss(this), commandossession(this), commandosexception(this), akills("XLineManager", "xlinemanager/sgline")
640  {
641  this->SetPermanent(true);
642 
644  }
645 
647  {
648  Configuration::Block *block = Config->GetModule(this);
649 
650  session_limit = block->Get<int>("defaultsessionlimit");
651  max_session_kill = block->Get<int>("maxsessionkill");
652  session_autokill_expiry = block->Get<time_t>("sessionautokillexpiry");
653  sle_reason = block->Get<const Anope::string>("sessionlimitexceeded");
654  sle_detailsloc = block->Get<const Anope::string>("sessionlimitdetailsloc");
655 
656  max_exception_limit = block->Get<int>("maxsessionlimit");
657  exception_expiry = block->Get<time_t>("exceptionexpiry");
658 
659  ipv4_cidr = block->Get<unsigned>("session_ipv4_cidr", "32");
660  ipv6_cidr = block->Get<unsigned>("session_ipv6_cidr", "128");
661 
662  if (ipv4_cidr > 32 || ipv6_cidr > 128)
663  throw ConfigException(this->name + ": session CIDR value out of range");
664  }
665 
666  void OnUserConnect(User *u, bool &exempt) anope_override
667  {
668  if (u->Quitting() || !session_limit || exempt || !u->server || u->server->IsULined())
669  return;
670 
671  cidr u_ip(u->ip, u->ip.ipv6() ? ipv6_cidr : ipv4_cidr);
672  if (!u_ip.valid())
673  return;
674 
675  Session* &session = this->ss.FindOrCreateSession(u_ip);
676 
677  if (session)
678  {
679  bool kill = false;
680  if (session->count >= session_limit)
681  {
682  kill = true;
683  Exception *exception = this->ss.FindException(u);
684  if (exception)
685  {
686  kill = false;
687  if (exception->limit && session->count >= exception->limit)
688  kill = true;
689  }
690  }
691 
692  /* Previously on IRCds that send a QUIT (InspIRCD) when a user is killed, the session for a host was
693  * decremented in do_quit, which caused problems and fixed here
694  *
695  * Now, we create the user struture before calling this to fix some user tracking issues,
696  * so we must increment this here no matter what because it will either be
697  * decremented when the user is killed or quits - Adam
698  */
699  ++session->count;
700 
701  if (kill && !exempt)
702  {
703  BotInfo *OperServ = Config->GetClient("OperServ");
704  if (OperServ)
705  {
706  if (!sle_reason.empty())
707  {
708  Anope::string message = sle_reason.replace_all_cs("%IP%", u->ip.addr());
709  u->SendMessage(OperServ, message);
710  }
711  if (!sle_detailsloc.empty())
712  u->SendMessage(OperServ, sle_detailsloc);
713  }
714 
715  ++session->hits;
716  if (max_session_kill && session->hits >= max_session_kill && akills)
717  {
718  const Anope::string &akillmask = "*@" + session->addr.mask();
719  XLine *x = new XLine(akillmask, OperServ ? OperServ->nick : "", Anope::CurTime + session_autokill_expiry, "Session limit exceeded", XLineManager::GenerateUID());
720  akills->AddXLine(x);
721  akills->Send(NULL, x);
722  Log(OperServ, "akill/session") << "Added a temporary AKILL for \002" << akillmask << "\002 due to excessive connections";
723  }
724  else
725  {
726  u->Kill(OperServ ? OperServ->nick : "", "Session limit exceeded");
727  }
728  }
729  }
730  else
731  {
732  session = new Session(u->ip, u->ip.ipv6() ? ipv6_cidr : ipv4_cidr);
733  }
734  }
735 
737  {
738  if (!session_limit || !u->server || u->server->IsULined())
739  return;
740 
741  SessionService::SessionMap &sessions = this->ss.GetSessions();
742  SessionService::SessionMap::iterator sit = this->ss.FindSessionIterator(u->ip);
743 
744  if (sit == sessions.end())
745  return;
746 
747  Session *session = sit->second;
748 
749  if (session->count > 1)
750  {
751  --session->count;
752  return;
753  }
754 
755  delete session;
756  sessions.erase(sit);
757  }
758 
760  {
761  if (Anope::NoExpire)
762  return;
763  for (unsigned i = this->ss.GetExceptions().size(); i > 0; --i)
764  {
765  Exception *e = this->ss.GetExceptions()[i - 1];
766 
767  if (!e->expires || e->expires > Anope::CurTime)
768  continue;
769  BotInfo *OperServ = Config->GetClient("OperServ");
770  Log(OperServ, "expire/exception") << "Session exception for " << e->mask << " has expired.";
771  this->ss.DelException(e);
772  delete e;
773  }
774  }
775 };
776 
Definition: bots.h:24
CoreExport bool ReadOnly
Definition: main.cpp:28
Anope::string name
Definition: modules.h:221
void ProcessList(CommandSource &source, const std::vector< Anope::string > &params, ListFormatter &list)
Definition: os_session.cpp:465
void DoMove(CommandSource &source, const std::vector< Anope::string > &params)
Definition: os_session.cpp:427
Serialize::Type exception_type
Definition: os_session.cpp:631
Anope::string mask() const
Definition: sockets.cpp:225
unsigned count
Definition: os_session.h:7
time_t time
Definition: os_session.h:19
bool match(const sockaddrs &other)
Definition: sockets.cpp:233
Session * FindSession(const Anope::string &ip) anope_override
Definition: os_session.cpp:101
unsigned limit
Definition: os_session.h:16
void Execute(CommandSource &source, const std::vector< Anope::string > &params) anope_override
Definition: os_session.cpp:250
static bool SetPriority(Module *mod, Implementation i, Priority s, Module **modules=NULL, size_t sz=1)
void Process(std::vector< Anope::string > &)
Definition: misc.cpp:144
void DoDel(CommandSource &source, const std::vector< Anope::string > &params)
Definition: os_session.cpp:391
Serialize::Checker< ExceptionVector > Exceptions
Definition: os_session.cpp:41
Session *& FindOrCreateSession(const cidr &ip)
Definition: os_session.cpp:120
MySessionService(Module *m)
Definition: os_session.cpp:43
Definition: users.h:34
void AddEntry(const ListEntry &entry)
Definition: misc.cpp:134
void DoAdd(CommandSource &source, const std::vector< Anope::string > &params)
Definition: os_session.cpp:291
SessionMap Sessions
Definition: os_session.cpp:40
#define READ_ONLY_MODE
Definition: language.h:71
void OnReload(Configuration::Conf *conf) anope_override
Definition: os_session.cpp:646
void DoList(CommandSource &source, const std::vector< Anope::string > &params)
Definition: os_session.cpp:541
cidr addr
Definition: os_session.h:6
#define FOREACH_RESULT(ename, ret, args)
Definition: modules.h:95
void SetDesc(const Anope::string &d)
Definition: command.cpp:130
bool equals_ci(const char *_str) const
Definition: anope.h:78
Definition: sockets.h:87
CoreExport time_t CurTime
Definition: main.cpp:41
const Anope::string & GetNick() const
Definition: command.cpp:26
OSSession(const Anope::string &modname, const Anope::string &creator)
Definition: os_session.cpp:638
#define FOREACH_MOD(ename, args)
Definition: modules.h:62
std::vector< Exception * > ExceptionVector
Definition: os_session.h:31
std::map< Anope::string, Anope::string > ListEntry
Definition: lists.h:68
void OnExpireTick() anope_override
Definition: os_session.cpp:759
TR1NS::unordered_map< cidr, Session *, cidr::hash > SessionMap
Definition: os_session.h:30
CommandOSException(Module *creator)
Definition: os_session.cpp:558
Definition: Config.cs:26
ServiceReference< XLineManager > akills
Definition: os_session.cpp:635
CoreExport bool Match(const string &str, const string &mask, bool case_sensitive=false, bool use_regex=false)
Definition: misc.cpp:407
virtual void OnSyntaxError(CommandSource &source, const Anope::string &subcommand)
Definition: command.cpp:191
static const size_type npos
Definition: anope.h:44
bool IsEmpty() const
Definition: misc.cpp:139
ExceptionDelCallback(CommandSource &_source, const Anope::string &numlist, Command *c)
Definition: os_session.cpp:138
CoreExport time_t DoTime(const Anope::string &s)
Definition: misc.cpp:275
void Reply(const char *message,...)
Definition: command.cpp:96
string replace_all_cs(const string &_orig, const string &_repl) const
Definition: anope.h:229
void Execute(CommandSource &source, const std::vector< Anope::string > &params) anope_override
Definition: os_session.cpp:568
void DoView(CommandSource &source, const std::vector< Anope::string > &params)
Definition: os_session.cpp:549
MySessionService ss
Definition: os_session.cpp:632
time_t expires
Definition: os_session.h:20
virtual void HandleNumber(unsigned number) anope_override
Definition: os_session.cpp:152
#define anope_override
Definition: services.h:56
bool empty() const
Definition: anope.h:126
Exception * FindException(const Anope::string &host) anope_override
Definition: os_session.cpp:76
void DoList(CommandSource &source, const std::vector< Anope::string > &params)
Definition: os_session.cpp:176
void OnUserQuit(User *u, const Anope::string &msg) anope_override
Definition: os_session.cpp:736
EventReturn
Definition: modules.h:129
#define MODULE_INIT(x)
Definition: modules.h:45
void SetSyntax(const Anope::string &s)
Definition: command.cpp:140
void Process()
Definition: misc.cpp:98
size_type find_first_not_of(const string &_str, size_type pos=0) const
Definition: anope.h:205
Anope::string stringify(const T &x)
Definition: anope.h:710
ExceptionVector & GetExceptions() anope_override
Definition: os_session.cpp:91
SessionMap & GetSessions() anope_override
Definition: os_session.cpp:125
CommandSource & source
Definition: os_session.cpp:134
CoreExport bool NoExpire
Definition: main.cpp:28
Anope::string nick
Definition: users.h:62
void DelException(Exception *e) anope_override
Definition: os_session.cpp:55
Anope::string who
Definition: os_session.h:17
unsigned hits
Definition: os_session.h:8
static void DoDel(CommandSource &source, unsigned index)
Definition: os_session.cpp:163
Definition: xline.h:18
void DoView(CommandSource &source, const std::vector< Anope::string > &params)
Definition: os_session.cpp:220
SessionMap::iterator FindSessionIterator(const sockaddrs &ip)
Definition: os_session.cpp:112
CommandOSException commandosexception
Definition: os_session.cpp:634
void SendSyntax(CommandSource &)
Definition: command.cpp:145
bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override
Definition: os_session.cpp:266
NickCore * GetAccount()
Definition: command.cpp:36
void AddException(Exception *e) anope_override
Definition: os_session.cpp:50
const char * c_str() const
Definition: anope.h:117
Exception * CreateException() anope_override
Definition: os_session.cpp:45
Definition: logger.h:53
T Get(const Anope::string &tag)
Definition: config.h:44
Anope::string mask
Definition: os_session.h:15
#define BAD_EXPIRY_TIME
Definition: language.h:69
CoreExport Anope::string strftime(time_t t, const NickCore *nc=NULL, bool short_output=false)
Definition: misc.cpp:356
Anope::string reason
Definition: os_session.h:18
static Anope::string GenerateUID()
Definition: xline.cpp:234
void SetPermanent(bool state)
Definition: module.cpp:84
void DelSession(Session *s)
Definition: os_session.cpp:96
void OnUserConnect(User *u, bool &exempt) anope_override
Definition: os_session.cpp:666
bool ipv6() const
Definition: sockets.cpp:94
CommandOSSession(Module *creator)
Definition: os_session.cpp:243
size_type find(const string &_str, size_type pos=0) const
Definition: anope.h:192
bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override
Definition: os_session.cpp:588
#define _(x)
Definition: services.h:50
CoreExport Anope::string Expires(time_t seconds, const NickCore *nc=NULL)
Definition: misc.cpp:371
ListFormatter & AddColumn(const Anope::string &name)
Definition: misc.cpp:128
Type(const Anope::string &n, unserialize_func f, Module *owner=NULL)
CommandOSSession commandossession
Definition: os_session.cpp:633
static ServiceReference< SessionService > session_service("SessionService","session")
Exception * FindException(User *u) anope_override
Definition: os_session.cpp:62