anope- supernets anope source code & configuration |
git clone git://git.acid.vegas/anope.git |
Log | Files | Refs | Archive | README |
os_defcon.cpp (18009B)
1 /* OperServ core functions 2 * 3 * (C) 2003-2022 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 enum DefconLevel 16 { 17 DEFCON_NO_NEW_CHANNELS, 18 DEFCON_NO_NEW_NICKS, 19 DEFCON_NO_MLOCK_CHANGE, 20 DEFCON_FORCE_CHAN_MODES, 21 DEFCON_REDUCE_SESSION, 22 DEFCON_NO_NEW_CLIENTS, 23 DEFCON_OPER_ONLY, 24 DEFCON_SILENT_OPER_ONLY, 25 DEFCON_AKILL_NEW_CLIENTS, 26 DEFCON_NO_NEW_MEMOS 27 }; 28 29 bool DefConModesSet = false; 30 31 struct DefconConfig 32 { 33 std::vector<std::bitset<32> > DefCon; 34 std::set<Anope::string> DefConModesOn, DefConModesOff; 35 std::map<Anope::string, Anope::string> DefConModesOnParams; 36 37 int defaultlevel, sessionlimit; 38 Anope::string chanmodes, message, offmessage, akillreason; 39 std::vector<Anope::string> defcons; 40 time_t akillexpire, timeout; 41 bool globalondefcon; 42 43 unsigned max_session_kill; 44 time_t session_autokill_expiry; 45 Anope::string sle_reason, sle_detailsloc; 46 47 DefconConfig() 48 { 49 this->DefCon.resize(6); 50 this->defcons.resize(5); 51 } 52 53 bool Check(DefconLevel level) 54 { 55 return this->Check(this->defaultlevel, level); 56 } 57 58 bool Check(int dlevel, DefconLevel level) 59 { 60 return this->DefCon[dlevel].test(level); 61 } 62 63 void Add(int dlevel, DefconLevel level) 64 { 65 this->DefCon[dlevel][level] = true; 66 } 67 68 void Del(int dlevel, DefconLevel level) 69 { 70 this->DefCon[dlevel][level] = false; 71 } 72 73 bool SetDefConParam(const Anope::string &name, const Anope::string &buf) 74 { 75 return DefConModesOnParams.insert(std::make_pair(name, buf)).second; 76 } 77 78 void UnsetDefConParam(const Anope::string &name) 79 { 80 DefConModesOnParams.erase(name); 81 } 82 83 bool GetDefConParam(const Anope::string &name, Anope::string &buf) 84 { 85 std::map<Anope::string, Anope::string>::iterator it = DefConModesOnParams.find(name); 86 87 buf.clear(); 88 89 if (it != DefConModesOnParams.end()) 90 { 91 buf = it->second; 92 return true; 93 } 94 95 return false; 96 } 97 }; 98 99 static DefconConfig DConfig; 100 101 static void runDefCon(); 102 static Anope::string defconReverseModes(const Anope::string &modes); 103 104 static ServiceReference<GlobalService> GlobalService("GlobalService", "Global"); 105 106 static Timer *timeout; 107 108 class DefConTimeout : public Timer 109 { 110 int level; 111 112 public: 113 DefConTimeout(Module *mod, int newlevel) : Timer(mod, DConfig.timeout), level(newlevel) 114 { 115 timeout = this; 116 } 117 118 ~DefConTimeout() 119 { 120 timeout = NULL; 121 } 122 123 void Tick(time_t) anope_override 124 { 125 if (DConfig.defaultlevel != level) 126 { 127 DConfig.defaultlevel = level; 128 FOREACH_MOD(OnDefconLevel, (level)); 129 Log(Config->GetClient("OperServ"), "operserv/defcon") << "Defcon level timeout, returning to level " << level; 130 131 if (DConfig.globalondefcon) 132 { 133 if (!DConfig.offmessage.empty()) 134 GlobalService->SendGlobal(NULL, "", DConfig.offmessage); 135 else 136 GlobalService->SendGlobal(NULL, "", Anope::printf(Language::Translate(_("The Defcon level is now at: \002%d\002")), DConfig.defaultlevel)); 137 138 if (!DConfig.message.empty()) 139 GlobalService->SendGlobal(NULL, "", DConfig.message); 140 } 141 142 runDefCon(); 143 } 144 } 145 }; 146 147 class CommandOSDefcon : public Command 148 { 149 void SendLevels(CommandSource &source) 150 { 151 if (DConfig.Check(DEFCON_NO_NEW_CHANNELS)) 152 source.Reply(_("* No new channel registrations")); 153 if (DConfig.Check(DEFCON_NO_NEW_NICKS)) 154 source.Reply(_("* No new nick registrations")); 155 if (DConfig.Check(DEFCON_NO_MLOCK_CHANGE)) 156 source.Reply(_("* No mode lock changes")); 157 if (DConfig.Check(DEFCON_FORCE_CHAN_MODES) && !DConfig.chanmodes.empty()) 158 source.Reply(_("* Force channel modes (%s) to be set on all channels"), DConfig.chanmodes.c_str()); 159 if (DConfig.Check(DEFCON_REDUCE_SESSION)) 160 source.Reply(_("* Use the reduced session limit of %d"), DConfig.sessionlimit); 161 if (DConfig.Check(DEFCON_NO_NEW_CLIENTS)) 162 source.Reply(_("* Kill any new clients connecting")); 163 if (DConfig.Check(DEFCON_OPER_ONLY)) 164 source.Reply(_("* Ignore non-opers with a message")); 165 if (DConfig.Check(DEFCON_SILENT_OPER_ONLY)) 166 source.Reply(_("* Silently ignore non-opers")); 167 if (DConfig.Check(DEFCON_AKILL_NEW_CLIENTS)) 168 source.Reply(_("* AKILL any new clients connecting")); 169 if (DConfig.Check(DEFCON_NO_NEW_MEMOS)) 170 source.Reply(_("* No new memos sent")); 171 } 172 173 public: 174 CommandOSDefcon(Module *creator) : Command(creator, "operserv/defcon", 1, 1) 175 { 176 this->SetDesc(_("Manipulate the DefCon system")); 177 this->SetSyntax(_("[\0021\002|\0022\002|\0023\002|\0024\002|\0025\002]")); 178 } 179 180 void Execute(CommandSource &source, const std::vector<Anope::string> ¶ms) anope_override 181 { 182 const Anope::string &lvl = params[0]; 183 184 if (lvl.empty()) 185 { 186 source.Reply(_("Services are now at DEFCON \002%d\002."), DConfig.defaultlevel); 187 this->SendLevels(source); 188 return; 189 } 190 191 int newLevel = 0; 192 try 193 { 194 newLevel = convertTo<int>(lvl); 195 } 196 catch (const ConvertException &) { } 197 198 if (newLevel < 1 || newLevel > 5) 199 { 200 this->OnSyntaxError(source, ""); 201 return; 202 } 203 204 DConfig.defaultlevel = newLevel; 205 206 FOREACH_MOD(OnDefconLevel, (newLevel)); 207 208 delete timeout; 209 210 if (DConfig.timeout) 211 timeout = new DefConTimeout(this->module, 5); 212 213 source.Reply(_("Services are now at DEFCON \002%d\002."), DConfig.defaultlevel); 214 this->SendLevels(source); 215 Log(LOG_ADMIN, source, this) << "to change defcon level to " << newLevel; 216 217 /* Global notice the user what is happening. Also any Message that 218 the Admin would like to add. Set in config file. */ 219 if (DConfig.globalondefcon) 220 { 221 if (DConfig.defaultlevel == 5 && !DConfig.offmessage.empty()) 222 GlobalService->SendGlobal(NULL, "", DConfig.offmessage); 223 else if (DConfig.defaultlevel != 5) 224 { 225 GlobalService->SendGlobal(NULL, "", Anope::printf(_("The Defcon level is now at: \002%d\002"), DConfig.defaultlevel)); 226 if (!DConfig.message.empty()) 227 GlobalService->SendGlobal(NULL, "", DConfig.message); 228 } 229 } 230 231 /* Run any defcon functions, e.g. FORCE CHAN MODE */ 232 runDefCon(); 233 return; 234 } 235 236 bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override 237 { 238 this->SendSyntax(source); 239 source.Reply(" "); 240 source.Reply(_("The defcon system can be used to implement a pre-defined\n" 241 "set of restrictions to services useful during an attempted\n" 242 "attack on the network.")); 243 return true; 244 } 245 }; 246 247 class OSDefcon : public Module 248 { 249 ServiceReference<SessionService> session_service; 250 ServiceReference<XLineManager> akills; 251 CommandOSDefcon commandosdefcon; 252 253 void ParseModeString() 254 { 255 int add = -1; /* 1 if adding, 0 if deleting, -1 if neither */ 256 unsigned char mode; 257 ChannelMode *cm; 258 ChannelModeParam *cmp; 259 Anope::string modes, param; 260 261 spacesepstream ss(DConfig.chanmodes); 262 263 DConfig.DefConModesOn.clear(); 264 DConfig.DefConModesOff.clear(); 265 ss.GetToken(modes); 266 267 /* Loop while there are modes to set */ 268 for (unsigned i = 0, end = modes.length(); i < end; ++i) 269 { 270 mode = modes[i]; 271 272 switch (mode) 273 { 274 case '+': 275 add = 1; 276 continue; 277 case '-': 278 add = 0; 279 continue; 280 default: 281 if (add < 0) 282 continue; 283 } 284 285 if ((cm = ModeManager::FindChannelModeByChar(mode))) 286 { 287 if (cm->type == MODE_STATUS || cm->type == MODE_LIST) 288 { 289 Log(this) << "DefConChanModes mode character '" << mode << "' cannot be locked"; 290 continue; 291 } 292 else if (add) 293 { 294 DConfig.DefConModesOn.insert(cm->name); 295 DConfig.DefConModesOff.erase(cm->name); 296 297 if (cm->type == MODE_PARAM) 298 { 299 cmp = anope_dynamic_static_cast<ChannelModeParam *>(cm); 300 301 if (!ss.GetToken(param)) 302 { 303 Log(this) << "DefConChanModes mode character '" << mode << "' has no parameter while one is expected"; 304 continue; 305 } 306 307 if (!cmp->IsValid(param)) 308 continue; 309 310 DConfig.SetDefConParam(cmp->name, param); 311 } 312 } 313 else if (DConfig.DefConModesOn.count(cm->name)) 314 { 315 DConfig.DefConModesOn.erase(cm->name); 316 317 if (cm->type == MODE_PARAM) 318 DConfig.UnsetDefConParam(cm->name); 319 } 320 } 321 } 322 323 /* We can't mlock +L if +l is not mlocked as well. */ 324 if ((cm = ModeManager::FindChannelModeByName("REDIRECT")) && DConfig.DefConModesOn.count(cm->name) && !DConfig.DefConModesOn.count("LIMIT")) 325 { 326 DConfig.DefConModesOn.erase("REDIRECT"); 327 328 Log(this) << "DefConChanModes must lock mode +l as well to lock mode +L"; 329 } 330 } 331 332 public: 333 OSDefcon(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR), session_service("SessionService", "session"), akills("XLineManager", "xlinemanager/sgline"), commandosdefcon(this) 334 { 335 336 } 337 338 void OnReload(Configuration::Conf *conf) anope_override 339 { 340 Configuration::Block *block = conf->GetModule(this); 341 DefconConfig dconfig; 342 343 dconfig.defaultlevel = block->Get<int>("defaultlevel"); 344 dconfig.defcons[4] = block->Get<const Anope::string>("level4"); 345 dconfig.defcons[3] = block->Get<const Anope::string>("level3"); 346 dconfig.defcons[2] = block->Get<const Anope::string>("level2"); 347 dconfig.defcons[1] = block->Get<const Anope::string>("level1"); 348 dconfig.sessionlimit = block->Get<int>("sessionlimit"); 349 dconfig.akillreason = block->Get<const Anope::string>("akillreason"); 350 dconfig.akillexpire = block->Get<time_t>("akillexpire"); 351 dconfig.chanmodes = block->Get<const Anope::string>("chanmodes"); 352 dconfig.timeout = block->Get<time_t>("timeout"); 353 dconfig.globalondefcon = block->Get<bool>("globalondefcon"); 354 dconfig.message = block->Get<const Anope::string>("message"); 355 dconfig.offmessage = block->Get<const Anope::string>("offmessage"); 356 357 block = conf->GetModule("os_session"); 358 359 dconfig.max_session_kill = block->Get<int>("maxsessionkill"); 360 dconfig.session_autokill_expiry = block->Get<time_t>("sessionautokillexpiry"); 361 dconfig.sle_reason = block->Get<const Anope::string>("sessionlimitexceeded"); 362 dconfig.sle_detailsloc = block->Get<const Anope::string>("sessionlimitdetailsloc"); 363 364 if (dconfig.defaultlevel < 1 || dconfig.defaultlevel > 5) 365 throw ConfigException("The value for <defcon:defaultlevel> must be between 1 and 5"); 366 else if (dconfig.akillexpire <= 0) 367 throw ConfigException("The value for <defcon:akillexpire> must be greater than zero!"); 368 369 for (unsigned level = 1; level < 5; ++level) 370 { 371 spacesepstream operations(dconfig.defcons[level]); 372 Anope::string operation; 373 while (operations.GetToken(operation)) 374 { 375 if (operation.equals_ci("nonewchannels")) 376 dconfig.Add(level, DEFCON_NO_NEW_CHANNELS); 377 else if (operation.equals_ci("nonewnicks")) 378 dconfig.Add(level, DEFCON_NO_NEW_NICKS); 379 else if (operation.equals_ci("nomlockchanges")) 380 dconfig.Add(level, DEFCON_NO_MLOCK_CHANGE); 381 else if (operation.equals_ci("forcechanmodes")) 382 dconfig.Add(level, DEFCON_FORCE_CHAN_MODES); 383 else if (operation.equals_ci("reducedsessions")) 384 dconfig.Add(level, DEFCON_REDUCE_SESSION); 385 else if (operation.equals_ci("nonewclients")) 386 dconfig.Add(level, DEFCON_NO_NEW_CLIENTS); 387 else if (operation.equals_ci("operonly")) 388 dconfig.Add(level, DEFCON_OPER_ONLY); 389 else if (operation.equals_ci("silentoperonly")) 390 dconfig.Add(level, DEFCON_SILENT_OPER_ONLY); 391 else if (operation.equals_ci("akillnewclients")) 392 dconfig.Add(level, DEFCON_AKILL_NEW_CLIENTS); 393 else if (operation.equals_ci("nonewmemos")) 394 dconfig.Add(level, DEFCON_NO_NEW_MEMOS); 395 } 396 397 if (dconfig.Check(level, DEFCON_REDUCE_SESSION) && dconfig.sessionlimit <= 0) 398 throw ConfigException("The value for <defcon:sessionlimit> must be greater than zero!"); 399 else if (dconfig.Check(level, DEFCON_AKILL_NEW_CLIENTS) && dconfig.akillreason.empty()) 400 throw ConfigException("The value for <defcon:akillreason> must not be empty!"); 401 else if (dconfig.Check(level, DEFCON_FORCE_CHAN_MODES) && dconfig.chanmodes.empty()) 402 throw ConfigException("The value for <defcon:chanmodes> must not be empty!"); 403 } 404 405 DConfig = dconfig; 406 this->ParseModeString(); 407 } 408 409 EventReturn OnChannelModeSet(Channel *c, MessageSource &source, ChannelMode *mode, const Anope::string ¶m) anope_override 410 { 411 if (DConfig.Check(DEFCON_FORCE_CHAN_MODES) && DConfig.DefConModesOff.count(mode->name) && source.GetUser() && !source.GetBot()) 412 { 413 c->RemoveMode(Config->GetClient("OperServ"), mode, param); 414 415 return EVENT_STOP; 416 } 417 418 return EVENT_CONTINUE; 419 } 420 421 EventReturn OnChannelModeUnset(Channel *c, MessageSource &source, ChannelMode *mode, const Anope::string &) anope_override 422 { 423 if (DConfig.Check(DEFCON_FORCE_CHAN_MODES) && DConfig.DefConModesOn.count(mode->name) && source.GetUser() && !source.GetBot()) 424 { 425 Anope::string param; 426 427 if (DConfig.GetDefConParam(mode->name, param)) 428 c->SetMode(Config->GetClient("OperServ"), mode, param); 429 else 430 c->SetMode(Config->GetClient("OperServ"), mode); 431 432 return EVENT_STOP; 433 434 } 435 436 return EVENT_CONTINUE; 437 } 438 439 EventReturn OnPreCommand(CommandSource &source, Command *command, std::vector<Anope::string> ¶ms) anope_override 440 { 441 if (DConfig.Check(DEFCON_OPER_ONLY) && !source.IsOper()) 442 { 443 source.Reply(_("Services are in DefCon mode, please try again later.")); 444 return EVENT_STOP; 445 } 446 else if (DConfig.Check(DEFCON_SILENT_OPER_ONLY) && !source.IsOper()) 447 { 448 return EVENT_STOP; 449 } 450 else if (command->name == "nickserv/register" || command->name == "nickserv/group") 451 { 452 if (DConfig.Check(DEFCON_NO_NEW_NICKS)) 453 { 454 source.Reply(_("Services are in DefCon mode, please try again later.")); 455 return EVENT_STOP; 456 } 457 } 458 else if (command->name == "chanserv/mode" && params.size() > 1 && params[1].equals_ci("LOCK")) 459 { 460 if (DConfig.Check(DEFCON_NO_MLOCK_CHANGE)) 461 { 462 source.Reply(_("Services are in DefCon mode, please try again later.")); 463 return EVENT_STOP; 464 } 465 } 466 else if (command->name == "chanserv/register") 467 { 468 if (DConfig.Check(DEFCON_NO_NEW_CHANNELS)) 469 { 470 source.Reply(_("Services are in DefCon mode, please try again later.")); 471 return EVENT_STOP; 472 } 473 } 474 else if (command->name == "memoserv/send") 475 { 476 if (DConfig.Check(DEFCON_NO_NEW_MEMOS)) 477 { 478 source.Reply(_("Services are in DefCon mode, please try again later.")); 479 return EVENT_STOP; 480 } 481 } 482 483 return EVENT_CONTINUE; 484 } 485 486 void OnUserConnect(User *u, bool &exempt) anope_override 487 { 488 if (exempt || u->Quitting() || !u->server->IsSynced() || u->server->IsULined()) 489 return; 490 491 BotInfo *OperServ = Config->GetClient("OperServ"); 492 if (DConfig.Check(DEFCON_AKILL_NEW_CLIENTS) && akills) 493 { 494 Log(OperServ, "operserv/defcon") << "DEFCON: adding akill for *@" << u->host; 495 XLine x("*@" + u->host, OperServ ? OperServ->nick : "defcon", Anope::CurTime + DConfig.akillexpire, DConfig.akillreason, XLineManager::GenerateUID()); 496 akills->Send(NULL, &x); 497 } 498 499 if (DConfig.Check(DEFCON_NO_NEW_CLIENTS) || DConfig.Check(DEFCON_AKILL_NEW_CLIENTS)) 500 { 501 u->Kill(OperServ, DConfig.akillreason); 502 return; 503 } 504 505 if (DConfig.sessionlimit <= 0 || !session_service) 506 return; 507 508 Session *session = session_service->FindSession(u->ip.addr()); 509 Exception *exception = session_service->FindException(u); 510 511 if (DConfig.Check(DEFCON_REDUCE_SESSION) && !exception) 512 { 513 if (session && session->count > static_cast<unsigned>(DConfig.sessionlimit)) 514 { 515 if (!DConfig.sle_reason.empty()) 516 { 517 Anope::string message = DConfig.sle_reason.replace_all_cs("%IP%", u->ip.addr()); 518 u->SendMessage(OperServ, message); 519 } 520 if (!DConfig.sle_detailsloc.empty()) 521 u->SendMessage(OperServ, DConfig.sle_detailsloc); 522 523 ++session->hits; 524 if (akills && DConfig.max_session_kill && session->hits >= DConfig.max_session_kill) 525 { 526 XLine x("*@" + session->addr.mask(), OperServ ? OperServ->nick : "", Anope::CurTime + DConfig.session_autokill_expiry, "Defcon session limit exceeded", XLineManager::GenerateUID()); 527 akills->Send(NULL, &x); 528 Log(OperServ, "akill/defcon") << "[DEFCON] Added a temporary AKILL for \002*@" << session->addr.mask() << "\002 due to excessive connections"; 529 } 530 else 531 { 532 u->Kill(OperServ, "Defcon session limit exceeded"); 533 } 534 } 535 } 536 } 537 538 void OnChannelModeAdd(ChannelMode *cm) anope_override 539 { 540 if (DConfig.chanmodes.find(cm->mchar) != Anope::string::npos) 541 this->ParseModeString(); 542 } 543 544 void OnChannelSync(Channel *c) anope_override 545 { 546 if (DConfig.Check(DEFCON_FORCE_CHAN_MODES)) 547 c->SetModes(Config->GetClient("OperServ"), false, "%s", DConfig.chanmodes.c_str()); 548 } 549 }; 550 551 static void runDefCon() 552 { 553 BotInfo *OperServ = Config->GetClient("OperServ"); 554 if (DConfig.Check(DEFCON_FORCE_CHAN_MODES)) 555 { 556 if (!DConfig.chanmodes.empty() && !DefConModesSet) 557 { 558 if (DConfig.chanmodes[0] == '+' || DConfig.chanmodes[0] == '-') 559 { 560 Log(OperServ, "operserv/defcon") << "DEFCON: setting " << DConfig.chanmodes << " on all channels"; 561 DefConModesSet = true; 562 for (channel_map::const_iterator it = ChannelList.begin(), it_end = ChannelList.end(); it != it_end; ++it) 563 it->second->SetModes(OperServ, false, "%s", DConfig.chanmodes.c_str()); 564 } 565 } 566 } 567 else 568 { 569 if (!DConfig.chanmodes.empty() && DefConModesSet) 570 { 571 if (DConfig.chanmodes[0] == '+' || DConfig.chanmodes[0] == '-') 572 { 573 DefConModesSet = false; 574 Anope::string newmodes = defconReverseModes(DConfig.chanmodes); 575 if (!newmodes.empty()) 576 { 577 Log(OperServ, "operserv/defcon") << "DEFCON: setting " << newmodes << " on all channels"; 578 for (channel_map::const_iterator it = ChannelList.begin(), it_end = ChannelList.end(); it != it_end; ++it) 579 it->second->SetModes(OperServ, true, "%s", newmodes.c_str()); 580 } 581 } 582 } 583 } 584 } 585 586 static Anope::string defconReverseModes(const Anope::string &modes) 587 { 588 if (modes.empty()) 589 return ""; 590 Anope::string newmodes; 591 for (unsigned i = 0, end = modes.length(); i < end; ++i) 592 { 593 if (modes[i] == '+') 594 newmodes += '-'; 595 else if (modes[i] == '-') 596 newmodes += '+'; 597 else 598 newmodes += modes[i]; 599 } 600 return newmodes; 601 } 602 603 MODULE_INIT(OSDefcon)