00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014 #include "module.h"
00015 #include "global.h"
00016 #include "os_session.h"
00017
00018 enum DefconLevel
00019 {
00020 DEFCON_NO_NEW_CHANNELS,
00021 DEFCON_NO_NEW_NICKS,
00022 DEFCON_NO_MLOCK_CHANGE,
00023 DEFCON_FORCE_CHAN_MODES,
00024 DEFCON_REDUCE_SESSION,
00025 DEFCON_NO_NEW_CLIENTS,
00026 DEFCON_OPER_ONLY,
00027 DEFCON_SILENT_OPER_ONLY,
00028 DEFCON_AKILL_NEW_CLIENTS,
00029 DEFCON_NO_NEW_MEMOS
00030 };
00031
00032 bool DefConModesSet = false;
00033
00034 struct DefconConfig
00035 {
00036 std::vector<std::bitset<32> > DefCon;
00037 std::set<Anope::string> DefConModesOn, DefConModesOff;
00038 std::map<Anope::string, Anope::string> DefConModesOnParams;
00039
00040 int defaultlevel, sessionlimit;
00041 Anope::string chanmodes, message, offmessage, akillreason;
00042 std::vector<Anope::string> defcons;
00043 time_t akillexpire, timeout;
00044 bool globalondefcon;
00045
00046 DefconConfig()
00047 {
00048 this->DefCon.resize(6);
00049 this->defcons.resize(5);
00050 }
00051
00052 bool Check(DefconLevel level)
00053 {
00054 return this->Check(this->defaultlevel, level);
00055 }
00056
00057 bool Check(int dlevel, DefconLevel level)
00058 {
00059 return this->DefCon[dlevel].test(level);
00060 }
00061
00062 void Add(int dlevel, DefconLevel level)
00063 {
00064 this->DefCon[dlevel][level] = true;
00065 }
00066
00067 void Del(int dlevel, DefconLevel level)
00068 {
00069 this->DefCon[dlevel][level] = false;
00070 }
00071
00072 bool SetDefConParam(const Anope::string &name, const Anope::string &buf)
00073 {
00074 return DefConModesOnParams.insert(std::make_pair(name, buf)).second;
00075 }
00076
00077 void UnsetDefConParam(const Anope::string &name)
00078 {
00079 DefConModesOnParams.erase(name);
00080 }
00081
00082 bool GetDefConParam(const Anope::string &name, Anope::string &buf)
00083 {
00084 std::map<Anope::string, Anope::string>::iterator it = DefConModesOnParams.find(name);
00085
00086 buf.clear();
00087
00088 if (it != DefConModesOnParams.end())
00089 {
00090 buf = it->second;
00091 return true;
00092 }
00093
00094 return false;
00095 }
00096 };
00097
00098 static DefconConfig DConfig;
00099
00100 static void runDefCon();
00101 static Anope::string defconReverseModes(const Anope::string &modes);
00102
00103 static ServiceReference<GlobalService> GlobalService("GlobalService", "Global");
00104
00105 static Timer *timeout;
00106
00107 class DefConTimeout : public CallBack
00108 {
00109 int level;
00110
00111 public:
00112 DefConTimeout(Module *mod, int newlevel) : CallBack(mod, DConfig.timeout), level(newlevel)
00113 {
00114 timeout = this;
00115 }
00116
00117 ~DefConTimeout()
00118 {
00119 timeout = NULL;
00120 }
00121
00122 void Tick(time_t) anope_override
00123 {
00124 if (DConfig.defaultlevel != level)
00125 {
00126 DConfig.defaultlevel = level;
00127 FOREACH_MOD(I_OnDefconLevel, OnDefconLevel(level));
00128 Log(OperServ, "operserv/defcon") << "Defcon level timeout, returning to level " << level;
00129
00130 if (DConfig.globalondefcon)
00131 {
00132 if (!DConfig.offmessage.empty())
00133 GlobalService->SendGlobal(Global, "", DConfig.offmessage);
00134 else
00135 GlobalService->SendGlobal(Global, "", Anope::printf(Language::Translate(_("The Defcon Level is now at Level: \002%d\002")), DConfig.defaultlevel));
00136
00137 if (!DConfig.message.empty())
00138 GlobalService->SendGlobal(Global, "", DConfig.message);
00139 }
00140
00141 runDefCon();
00142 }
00143 }
00144 };
00145
00146 class CommandOSDefcon : public Command
00147 {
00148 void SendLevels(CommandSource &source)
00149 {
00150 if (DConfig.Check(DEFCON_NO_NEW_CHANNELS))
00151 source.Reply(_("* No new channel registrations"));
00152 if (DConfig.Check(DEFCON_NO_NEW_NICKS))
00153 source.Reply(_("* No new nick registrations"));
00154 if (DConfig.Check(DEFCON_NO_MLOCK_CHANGE))
00155 source.Reply(_("* No mode lock changes"));
00156 if (DConfig.Check(DEFCON_FORCE_CHAN_MODES) && !DConfig.chanmodes.empty())
00157 source.Reply(_("* Force Chan Modes (%s) to be set on all channels"), DConfig.chanmodes.c_str());
00158 if (DConfig.Check(DEFCON_REDUCE_SESSION))
00159 source.Reply(_("* Use the reduced session limit of %d"), DConfig.sessionlimit);
00160 if (DConfig.Check(DEFCON_NO_NEW_CLIENTS))
00161 source.Reply(_("* Kill any NEW clients connecting"));
00162 if (DConfig.Check(DEFCON_OPER_ONLY))
00163 source.Reply(_("* Ignore any non-opers with message"));
00164 if (DConfig.Check(DEFCON_SILENT_OPER_ONLY))
00165 source.Reply(_("* Silently ignore non-opers"));
00166 if (DConfig.Check(DEFCON_AKILL_NEW_CLIENTS))
00167 source.Reply(_("* AKILL any new clients connecting"));
00168 if (DConfig.Check(DEFCON_NO_NEW_MEMOS))
00169 source.Reply(_("* No new memos sent"));
00170 }
00171
00172 public:
00173 CommandOSDefcon(Module *creator) : Command(creator, "operserv/defcon", 1, 1)
00174 {
00175 this->SetDesc(_("Manipulate the DefCon system"));
00176 this->SetSyntax(_("[\0021\002|\0022\002|\0023\002|\0024\002|\0025\002]"));
00177 }
00178
00179 void Execute(CommandSource &source, const std::vector<Anope::string> ¶ms) anope_override
00180 {
00181 const Anope::string &lvl = params[0];
00182
00183 if (lvl.empty())
00184 {
00185 source.Reply(_("Services are now at DEFCON \002%d\002."), DConfig.defaultlevel);
00186 this->SendLevels(source);
00187 return;
00188 }
00189
00190 int newLevel = 0;
00191 try
00192 {
00193 newLevel = convertTo<int>(lvl);
00194 }
00195 catch (const ConvertException &) { }
00196
00197 if (newLevel < 1 || newLevel > 5)
00198 {
00199 this->OnSyntaxError(source, "");
00200 return;
00201 }
00202
00203 DConfig.defaultlevel = newLevel;
00204
00205 FOREACH_MOD(I_OnDefconLevel, OnDefconLevel(newLevel));
00206
00207 delete timeout;
00208
00209 if (DConfig.timeout)
00210 timeout = new DefConTimeout(this->module, 5);
00211
00212 source.Reply(_("Services are now at DEFCON \002%d\002."), DConfig.defaultlevel);
00213 this->SendLevels(source);
00214 Log(LOG_ADMIN, source, this) << "to change defcon level to " << newLevel;
00215
00216
00217
00218 if (DConfig.globalondefcon)
00219 {
00220 if (DConfig.defaultlevel == 5 && !DConfig.offmessage.empty())
00221 GlobalService->SendGlobal(Global, "", DConfig.offmessage);
00222 else if (DConfig.defaultlevel != 5)
00223 {
00224 GlobalService->SendGlobal(Global, "", Anope::printf(_("The Defcon level is now at: \002%d\002"), DConfig.defaultlevel));
00225 if (!DConfig.message.empty())
00226 GlobalService->SendGlobal(Global, "", DConfig.message);
00227 }
00228 }
00229
00230
00231 runDefCon();
00232 return;
00233 }
00234
00235 bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override
00236 {
00237 this->SendSyntax(source);
00238 source.Reply(" ");
00239 source.Reply(_("The defcon system can be used to implement a pre-defined\n"
00240 "set of restrictions to services useful during an attempted\n"
00241 "attack on the network."));
00242 return true;
00243 }
00244 };
00245
00246 class OSDefcon : public Module
00247 {
00248 ServiceReference<SessionService> session_service;
00249 ServiceReference<XLineManager> akills;
00250 CommandOSDefcon commandosdefcon;
00251
00252 void ParseModeString()
00253 {
00254 int add = -1;
00255 unsigned char mode;
00256 ChannelMode *cm;
00257 ChannelModeParam *cmp;
00258 Anope::string modes, param;
00259
00260 spacesepstream ss(DConfig.chanmodes);
00261
00262 DConfig.DefConModesOn.clear();
00263 DConfig.DefConModesOff.clear();
00264 ss.GetToken(modes);
00265
00266
00267 for (unsigned i = 0, end = modes.length(); i < end; ++i)
00268 {
00269 mode = modes[i];
00270
00271 switch (mode)
00272 {
00273 case '+':
00274 add = 1;
00275 continue;
00276 case '-':
00277 add = 0;
00278 continue;
00279 default:
00280 if (add < 0)
00281 continue;
00282 }
00283
00284 if ((cm = ModeManager::FindChannelModeByChar(mode)))
00285 {
00286 if (cm->type == MODE_STATUS || cm->type == MODE_LIST || !cm->CanSet(NULL))
00287 {
00288 Log(this) << "DefConChanModes mode character '" << mode << "' cannot be locked";
00289 continue;
00290 }
00291 else if (add)
00292 {
00293 DConfig.DefConModesOn.insert(cm->name);
00294 DConfig.DefConModesOff.erase(cm->name);
00295
00296 if (cm->type == MODE_PARAM)
00297 {
00298 cmp = anope_dynamic_static_cast<ChannelModeParam *>(cm);
00299
00300 if (!ss.GetToken(param))
00301 {
00302 Log(this) << "DefConChanModes mode character '" << mode << "' has no parameter while one is expected";
00303 continue;
00304 }
00305
00306 if (!cmp->IsValid(param))
00307 continue;
00308
00309 DConfig.SetDefConParam(cmp->name, param);
00310 }
00311 }
00312 else if (DConfig.DefConModesOn.count(cm->name))
00313 {
00314 DConfig.DefConModesOn.erase(cm->name);
00315
00316 if (cm->type == MODE_PARAM)
00317 DConfig.UnsetDefConParam(cm->name);
00318 }
00319 }
00320 }
00321
00322
00323 if ((cm = ModeManager::FindChannelModeByName("REDIRECT")) && DConfig.DefConModesOn.count(cm->name) && !DConfig.DefConModesOn.count("LIMIT"))
00324 {
00325 DConfig.DefConModesOn.erase("REDIRECT");
00326
00327 Log(this) << "DefConChanModes must lock mode +l as well to lock mode +L";
00328 }
00329 }
00330
00331 public:
00332 OSDefcon(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, CORE), session_service("SessionService", "session"), akills("XLineManager", "xlinemanager/sgline"), commandosdefcon(this)
00333 {
00334 this->SetAuthor("Anope");
00335
00336 Implementation i[] = { I_OnReload, I_OnChannelModeSet, I_OnChannelModeUnset, I_OnPreCommand, I_OnUserConnect, I_OnChannelModeAdd, I_OnChannelCreate };
00337 ModuleManager::Attach(i, this, sizeof(i) / sizeof(Implementation));
00338
00339
00340 try
00341 {
00342 this->OnReload();
00343 }
00344 catch (const ConfigException &ex)
00345 {
00346 throw ModuleException(ex.GetReason());
00347 }
00348 }
00349
00350 void OnReload() anope_override
00351 {
00352 ConfigReader config;
00353 DefconConfig dconfig;
00354
00355 dconfig.defaultlevel = config.ReadInteger("defcon", "defaultlevel", 0, 0);
00356 dconfig.defcons[4] = config.ReadValue("defcon", "level4", 0);
00357 dconfig.defcons[3] = config.ReadValue("defcon", "level3", 0);
00358 dconfig.defcons[2] = config.ReadValue("defcon", "level2", 0);
00359 dconfig.defcons[1] = config.ReadValue("defcon", "level1", 0);
00360 dconfig.sessionlimit = config.ReadInteger("defcon", "sessionlimit", 0, 0);
00361 dconfig.akillreason = config.ReadValue("defcon", "akillreason", 0);
00362 dconfig.akillexpire = Anope::DoTime(config.ReadValue("defcon", "akillexpire", 0));
00363 dconfig.chanmodes = config.ReadValue("defcon", "chanmodes", 0);
00364 dconfig.timeout = Anope::DoTime(config.ReadValue("defcon", "timeout", 0));
00365 dconfig.globalondefcon = config.ReadFlag("defcon", "globalondefcon", 0);
00366 dconfig.message = config.ReadValue("defcon", "message", 0);
00367 dconfig.offmessage = config.ReadValue("defcon", "offmessage", 0);
00368
00369 if (dconfig.defaultlevel < 1 || dconfig.defaultlevel > 5)
00370 throw ConfigException("The value for <defcon:defaultlevel> must be between 1 and 5");
00371 else if (dconfig.akillexpire <= 0)
00372 throw ConfigException("The value for <defcon:akillexpire> must be greater than zero!");
00373
00374 for (unsigned level = 1; level < 5; ++level)
00375 {
00376 spacesepstream operations(dconfig.defcons[level]);
00377 Anope::string operation;
00378 while (operations.GetToken(operation))
00379 {
00380 if (operation.equals_ci("nonewchannels"))
00381 dconfig.Add(level, DEFCON_NO_NEW_CHANNELS);
00382 else if (operation.equals_ci("nonewnicks"))
00383 dconfig.Add(level, DEFCON_NO_NEW_NICKS);
00384 else if (operation.equals_ci("nomlockchanges"))
00385 dconfig.Add(level, DEFCON_NO_MLOCK_CHANGE);
00386 else if (operation.equals_ci("forcechanmodes"))
00387 dconfig.Add(level, DEFCON_FORCE_CHAN_MODES);
00388 else if (operation.equals_ci("reducedsessions"))
00389 dconfig.Add(level, DEFCON_REDUCE_SESSION);
00390 else if (operation.equals_ci("nonewclients"))
00391 dconfig.Add(level, DEFCON_NO_NEW_CLIENTS);
00392 else if (operation.equals_ci("operonly"))
00393 dconfig.Add(level, DEFCON_OPER_ONLY);
00394 else if (operation.equals_ci("silentoperonly"))
00395 dconfig.Add(level, DEFCON_SILENT_OPER_ONLY);
00396 else if (operation.equals_ci("akillnewclients"))
00397 dconfig.Add(level, DEFCON_AKILL_NEW_CLIENTS);
00398 else if (operation.equals_ci("nonewmemos"))
00399 dconfig.Add(level, DEFCON_NO_NEW_MEMOS);
00400 }
00401
00402 if (dconfig.Check(level, DEFCON_REDUCE_SESSION) && dconfig.sessionlimit <= 0)
00403 throw ConfigException("The value for <defcon:sessionlimit> must be greater than zero!");
00404 else if (dconfig.Check(level, DEFCON_AKILL_NEW_CLIENTS) && dconfig.akillreason.empty())
00405 throw ConfigException("The value for <defcon:akillreason> must not be empty!");
00406 else if (dconfig.Check(level, DEFCON_FORCE_CHAN_MODES) && dconfig.chanmodes.empty())
00407 throw ConfigException("The value for <defcon:chanmodes> must not be empty!");
00408 }
00409
00410 DConfig = dconfig;
00411 this->ParseModeString();
00412 }
00413
00414 EventReturn OnChannelModeSet(Channel *c, MessageSource &, const Anope::string &mname, const Anope::string ¶m) anope_override
00415 {
00416 ChannelMode *cm = ModeManager::FindChannelModeByName(mname);
00417
00418 if (DConfig.Check(DEFCON_FORCE_CHAN_MODES) && cm && DConfig.DefConModesOff.count(mname))
00419 {
00420 c->RemoveMode(OperServ, cm, param);
00421
00422 return EVENT_STOP;
00423 }
00424
00425 return EVENT_CONTINUE;
00426 }
00427
00428 EventReturn OnChannelModeUnset(Channel *c, MessageSource &, const Anope::string &mname, const Anope::string &) anope_override
00429 {
00430 ChannelMode *cm = ModeManager::FindChannelModeByName(mname);
00431
00432 if (DConfig.Check(DEFCON_FORCE_CHAN_MODES) && cm && DConfig.DefConModesOn.count(mname))
00433 {
00434 Anope::string param;
00435
00436 if (DConfig.GetDefConParam(mname, param))
00437 c->SetMode(OperServ, cm, param);
00438 else
00439 c->SetMode(OperServ, cm);
00440
00441 return EVENT_STOP;
00442
00443 }
00444
00445 return EVENT_CONTINUE;
00446 }
00447
00448 EventReturn OnPreCommand(CommandSource &source, Command *command, std::vector<Anope::string> ¶ms) anope_override
00449 {
00450 if (command->name == "nickserv/register" || command->name == "nickserv/group")
00451 {
00452 if (DConfig.Check(DEFCON_NO_NEW_NICKS))
00453 {
00454 source.Reply(_("Services are in DefCon mode, please try again later."));
00455 return EVENT_STOP;
00456 }
00457 }
00458 else if (command->name == "chanserv/mode" && params.size() > 1 && params[1].equals_ci("LOCK"))
00459 {
00460 if (DConfig.Check(DEFCON_NO_MLOCK_CHANGE))
00461 {
00462 source.Reply(_("Services are in DefCon mode, please try again later."));
00463 return EVENT_STOP;
00464 }
00465 }
00466 else if (command->name == "chanserv/register")
00467 {
00468 if (DConfig.Check(DEFCON_NO_NEW_CHANNELS))
00469 {
00470 source.Reply(_("Services are in DefCon mode, please try again later."));
00471 return EVENT_STOP;
00472 }
00473 }
00474 else if (command->name == "memoserv/send")
00475 {
00476 if (DConfig.Check(DEFCON_NO_NEW_MEMOS))
00477 {
00478 source.Reply(_("Services are in DefCon mode, please try again later."));
00479 return EVENT_STOP;
00480 }
00481 }
00482
00483 return EVENT_CONTINUE;
00484 }
00485
00486 void OnUserConnect(User *u, bool &exempt) anope_override
00487 {
00488 if (exempt || !u->Quitting() || !u->server->IsSynced() || u->server->IsULined())
00489 return;
00490
00491 if (DConfig.Check(DEFCON_AKILL_NEW_CLIENTS) && akills)
00492 {
00493 Log(OperServ, "operserv/defcon") << "DEFCON: adding akill for *@" << u->host;
00494 XLine x("*@" + u->host, Config->OperServ, Anope::CurTime + DConfig.akillexpire, DConfig.akillreason, XLineManager::GenerateUID());
00495 x.by = Config->OperServ;
00496 akills->Send(NULL, &x);
00497 }
00498 if (DConfig.Check(DEFCON_NO_NEW_CLIENTS) || DConfig.Check(DEFCON_AKILL_NEW_CLIENTS))
00499 {
00500 u->Kill(Config->OperServ, DConfig.akillreason);
00501 return;
00502 }
00503
00504 if (DConfig.Check(DEFCON_NO_NEW_CLIENTS) || DConfig.Check(DEFCON_AKILL_NEW_CLIENTS))
00505 {
00506 u->Kill(Config->OperServ, DConfig.akillreason);
00507 return;
00508 }
00509
00510 if (DConfig.sessionlimit <= 0 || !session_service)
00511 return;
00512
00513 Session *session;
00514 try
00515 {
00516 session = session_service->FindSession(u->ip);
00517 }
00518 catch (const SocketException &)
00519 {
00520 return;
00521 }
00522 Exception *exception = session_service->FindException(u);
00523
00524 if (DConfig.Check(DEFCON_REDUCE_SESSION) && !exception)
00525 {
00526 if (session && session->count > static_cast<unsigned>(DConfig.sessionlimit))
00527 {
00528 if (!Config->SessionLimitExceeded.empty())
00529 IRCD->SendMessage(OperServ, u->nick, Config->SessionLimitExceeded.c_str(), u->host.c_str());
00530 if (!Config->SessionLimitDetailsLoc.empty())
00531 IRCD->SendMessage(OperServ, u->nick, "%s", Config->SessionLimitDetailsLoc.c_str());
00532
00533 ++session->hits;
00534 if (akills && Config->MaxSessionKill && session->hits >= Config->MaxSessionKill)
00535 {
00536 XLine x("*@" + u->host, Config->OperServ, Anope::CurTime + Config->SessionAutoKillExpiry, "Defcon session limit exceeded", XLineManager::GenerateUID());
00537 akills->Send(NULL, &x);
00538 Log(OperServ, "akill/defcon") << "[DEFCON] Added a temporary AKILL for \002*@" << u->host << "\002 due to excessive connections";
00539 }
00540 else
00541 {
00542 u->Kill(Config->OperServ, "Defcon session limit exceeded");
00543 u = NULL;
00544 }
00545 }
00546 }
00547 }
00548
00549 void OnChannelModeAdd(ChannelMode *cm) anope_override
00550 {
00551 if (DConfig.chanmodes.find(cm->mchar) != Anope::string::npos)
00552 this->ParseModeString();
00553 }
00554
00555 void OnChannelCreate(Channel *c) anope_override
00556 {
00557 if (DConfig.Check(DEFCON_FORCE_CHAN_MODES))
00558 c->SetModes(OperServ, false, "%s", DConfig.chanmodes.c_str());
00559 }
00560 };
00561
00562 static void runDefCon()
00563 {
00564 if (DConfig.Check(DEFCON_FORCE_CHAN_MODES))
00565 {
00566 if (!DConfig.chanmodes.empty() && !DefConModesSet)
00567 {
00568 if (DConfig.chanmodes[0] == '+' || DConfig.chanmodes[0] == '-')
00569 {
00570 Log(OperServ, "operserv/defcon") << "DEFCON: setting " << DConfig.chanmodes << " on all channels";
00571 DefConModesSet = true;
00572 for (channel_map::const_iterator it = ChannelList.begin(), it_end = ChannelList.end(); it != it_end; ++it)
00573 it->second->SetModes(OperServ, false, "%s", DConfig.chanmodes.c_str());
00574 }
00575 }
00576 }
00577 else
00578 {
00579 if (!DConfig.chanmodes.empty() && DefConModesSet)
00580 {
00581 if (DConfig.chanmodes[0] == '+' || DConfig.chanmodes[0] == '-')
00582 {
00583 DefConModesSet = false;
00584 Anope::string newmodes = defconReverseModes(DConfig.chanmodes);
00585 if (!newmodes.empty())
00586 {
00587 Log(OperServ, "operserv/defcon") << "DEFCON: setting " << newmodes << " on all channels";
00588 for (channel_map::const_iterator it = ChannelList.begin(), it_end = ChannelList.end(); it != it_end; ++it)
00589 it->second->SetModes(OperServ, false, "%s", newmodes.c_str());
00590 }
00591 }
00592 }
00593 }
00594 }
00595
00596 static Anope::string defconReverseModes(const Anope::string &modes)
00597 {
00598 if (modes.empty())
00599 return "";
00600 Anope::string newmodes;
00601 for (unsigned i = 0, end = modes.length(); i < end; ++i)
00602 {
00603 if (modes[i] == '+')
00604 newmodes += '-';
00605 else if (modes[i] == '-')
00606 newmodes += '+';
00607 else
00608 newmodes += modes[i];
00609 }
00610 return newmodes;
00611 }
00612
00613 MODULE_INIT(OSDefcon)