aboutsummaryrefslogtreecommitdiffstats
path: root/src/modules
diff options
context:
space:
mode:
authorGravatar Sadie Powell2026-03-09 18:02:38 +0000
committerGravatar Sadie Powell2026-03-09 18:04:21 +0000
commit53a254823e01a2a111dc11bf5ec7c2bf0e592f87 (patch)
tree91940cf6fefe09b1d5c9da275072a4ae250a999b /src/modules
parentRedocument extended bans to be easier to read. (diff)
downloadinspircd++-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.cpp2
-rw-r--r--src/modules/m_redirect.cpp133
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");