diff options
| author | 2026-03-09 18:02:38 +0000 | |
|---|---|---|
| committer | 2026-03-09 18:04:21 +0000 | |
| commit | 53a254823e01a2a111dc11bf5ec7c2bf0e592f87 (patch) | |
| tree | 91940cf6fefe09b1d5c9da275072a4ae250a999b /src/modules | |
| parent | Redocument extended bans to be easier to read. (diff) | |
| download | inspircd++-53a254823e01a2a111dc11bf5ec7c2bf0e592f87.tar.gz inspircd++-53a254823e01a2a111dc11bf5ec7c2bf0e592f87.tar.bz2 inspircd++-53a254823e01a2a111dc11bf5ec7c2bf0e592f87.zip | |
Add a redirect extended ban to the redirect module.
Also, deprecate the banredirect module now its behaviour has been
entirely replaced.
Closes #730
Closes #2043
Diffstat (limited to 'src/modules')
| -rw-r--r-- | src/modules/m_banredirect.cpp | 2 | ||||
| -rw-r--r-- | src/modules/m_redirect.cpp | 133 |
2 files changed, 109 insertions, 26 deletions
diff --git a/src/modules/m_banredirect.cpp b/src/modules/m_banredirect.cpp index 2a75dc148..13a76ae60 100644 --- a/src/modules/m_banredirect.cpp +++ b/src/modules/m_banredirect.cpp @@ -272,7 +272,7 @@ private: public: ModuleBanRedirect() - : Module(VF_VENDOR | VF_COMMON, "Allows specifying a channel to redirect a banned user to in the ban mask.") + : Module(VF_VENDOR | VF_COMMON | VF_DEPRECATED, "Allows specifying a channel to redirect a banned user to in the ban mask.") , banwatcher(this) , limitmode(this, "limit") , redirectmode(this, "redirect") diff --git a/src/modules/m_redirect.cpp b/src/modules/m_redirect.cpp index 1a7962ddd..4c811f0af 100644 --- a/src/modules/m_redirect.cpp +++ b/src/modules/m_redirect.cpp @@ -26,6 +26,7 @@ #include "inspircd.h" #include "extension.h" +#include "modules/extban.h" #include "numerichelper.h" enum @@ -37,6 +38,88 @@ enum ERR_REDIRECT = 690, }; +namespace +{ + Channel* CheckRedirect(User* source, Channel* channel, const std::string& parameter) + { + if (!ServerInstance->Channels.IsChannel(parameter)) + { + source->WriteNumeric(Numerics::NoSuchChannel(parameter)); + return nullptr; + } + + auto* c = ServerInstance->Channels.Find(parameter); + if (!source->IsOper()) + { + if (!c) + { + source->WriteNumeric(ERR_REDIRECT, parameter, INSP_FORMAT("Target channel {} must exist to be set as a redirect.", parameter)); + return nullptr; + } + else if (c->GetPrefixValue(source) < OP_VALUE) + { + source->WriteNumeric(ERR_REDIRECT, c->name, INSP_FORMAT("You must be opped on {} to set it as a redirect.", c->name)); + return nullptr; + } + } + return c; + } +} + +class RedirectExtBan final + : public ExtBan::Acting +{ +private: + bool SplitBan(const std::string& text, std::string& chan, std::string& mask) + { + auto sep = text.find(':'); + if (sep == std::string::npos || sep == 0 || sep+1 >= text.length()) + return false; // Malformed. + + chan.assign(text, 0, sep); + mask.assign(text, sep + 1); + return true; + } + +public: + std::string matchchan; + + RedirectExtBan(Module* mod) + : ExtBan::Acting(mod, "redirect", 'd') + { + if (!ServerInstance->Config->ConfValue("redirect")->getBool("extban")) + DisableAutoRegister(); + } + + bool IsMatch(User* user, Channel* channel, const std::string& text) override + { + std::string target, mask; + if (!SplitBan(text, target, mask)) + return false; // Malformed. + + matchchan = target; + return ExtBan::Acting::IsMatch(user, channel, mask); + } + + bool Validate(ListModeBase* lm, LocalUser* user, Channel* channel, std::string& text) override + { + std::string target, mask; + if (!SplitBan(text, target, mask)) + { + user->WriteNumeric(ERR_REDIRECT, text, "Redirect extban must be in the format <chan>:<mask>."); + return false; // Malformed. + } + + auto* targetchan = CheckRedirect(user, channel, target); + if (!targetchan) + return false; // Bad target. + + Canonicalize(mask); + text = INSP_FORMAT("{}:{}", targetchan->name, mask); + return true; + } +}; + class RedirectMode final : public ParamMode<RedirectMode, StringExtItem> { @@ -51,25 +134,11 @@ public: { if (IS_LOCAL(source)) { - if (!ServerInstance->Channels.IsChannel(parameter)) - { - source->WriteNumeric(Numerics::NoSuchChannel(parameter)); + auto* targetchan = CheckRedirect(source, channel, parameter); + if (!targetchan) return false; - } - if (!source->IsOper()) - { - auto* c = ServerInstance->Channels.Find(parameter); - if (!c) - { - source->WriteNumeric(ERR_REDIRECT, parameter, INSP_FORMAT("Target channel {} must exist to be set as a redirect.", parameter)); - return false; - } - else if (c->GetPrefixValue(source) < OP_VALUE) - { - source->WriteNumeric(ERR_REDIRECT, c->name, INSP_FORMAT("You must be opped on {} to set it as a redirect.", c->name)); - return false; - } - } + + parameter = targetchan->name; } ext.Set(channel, parameter); @@ -87,6 +156,7 @@ class ModuleRedirect final { private: bool action_ban; + bool action_extban; bool action_inviteonly; bool action_key; bool action_limit; @@ -95,14 +165,22 @@ private: ChanModeReference inviteonlymode; ChanModeReference keymode; ChanModeReference limitmode; + RedirectExtBan redirectextban; RedirectMode redirectmode; - ModResult HandleRedirect(LocalUser* user, Channel* chan, const std::string& reason) + ModResult HandleRedirect(LocalUser* user, Channel* chan, const std::string& reason, bool param = true) { - const auto* channel = redirectmode.ext.Get(chan); + const auto* channel = param ? redirectmode.ext.Get(chan) : &redirectextban.matchchan; if (!channel) return MOD_RES_PASSTHRU; // Should never happen. + // Sometimes broken services can make circular or chained +L, avoid this. + if (!activechan.empty()) + { + user->WriteNumeric(ERR_LINKCHANNEL, activechan, channel, "You may not join this channel. A redirect is set, but you cannot be redirected as it is a circular loop."); + return MOD_RES_PASSTHRU; + } + if (user->IsModeSet(antiredirectmode)) { user->WriteNumeric(ERR_LINKCHANNEL, chan->name, *channel, @@ -129,6 +207,7 @@ public: , inviteonlymode(this, "inviteonly") , keymode(this, "key") , limitmode(this, "limit") + , redirectextban(this) , redirectmode(this) { } @@ -137,6 +216,7 @@ public: { const auto& tag = ServerInstance->Config->ConfValue("redirect"); action_ban = tag->getBool("ban", false); + action_extban = tag->getBool("extban", false); action_inviteonly = tag->getBool("inviteonly", true); action_key = tag->getBool("key", true); action_limit = tag->getBool("limit", true); @@ -144,16 +224,19 @@ public: ModResult OnUserPreJoin(LocalUser* user, Channel* chan, const std::string& cname, std::string& privs, const std::string& keygiven, bool override) override { - if (override || !chan || !chan->IsModeSet(redirectmode)) + if (override || !chan) return MOD_RES_PASSTHRU; // No redirect possible. - // Sometimes broken services can make circular or chained +L, avoid this. - if (!activechan.empty()) + if (action_extban) { - user->WriteNumeric(ERR_LINKCHANNEL, activechan, cname, "You may not join this channel. A redirect is set, but you cannot be redirected as it is a circular loop."); - return MOD_RES_PASSTHRU; + const auto modres = redirectextban.GetStatus(user, chan); + if (modres == MOD_RES_DENY) + return HandleRedirect(user, chan, "you're extbanned", false); } + if (!chan->IsModeSet(redirectmode)) + return MOD_RES_PASSTHRU; // All others require the mode. + if (action_ban && chan->IsBanned(user)) return HandleRedirect(user, chan, "you're banned"); |
