Skip to content

Commit 16c72ca

Browse files
committed
New: m_extbanredirect by @revrsefr
1 parent 6e12ccc commit 16c72ca

1 file changed

Lines changed: 231 additions & 0 deletions

File tree

src/modules/m_extbanredirect.cpp

Lines changed: 231 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,231 @@
1+
/*
2+
* InspIRCd -- Internet Relay Chat Daemon
3+
*
4+
* Copyright (C) 2014 Attila Molnar <attilamolnar@hush.com>
5+
*
6+
* This file is part of InspIRCd. InspIRCd is free software: you can
7+
* redistribute it and/or modify it under the terms of the GNU General Public
8+
* License as published by the Free Software Foundation, version 2.
9+
*
10+
* This program is distributed in the hope that it will be useful, but WITHOUT
11+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12+
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
13+
* details.
14+
*
15+
* You should have received a copy of the GNU General Public License
16+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
17+
*/
18+
19+
/// $ModAuthor: Attila Molnar updated by reverse for v4
20+
/// $ModAuthorMail: attilamolnar@hush.com
21+
/// $ModConfig: <extbanredirect char="d">
22+
/// $ModDepends: core 4
23+
/// $ModDesc: Provide extended ban <extbanchar>:<chan>:<mask> to redirect users to another channel
24+
25+
26+
#include "inspircd.h"
27+
#include "listmode.h"
28+
#include "modules/extban.h"
29+
30+
enum
31+
{
32+
// From UnrealIRCd
33+
ERR_LINKCHANNEL = 470,
34+
// From m_banredirect
35+
ERR_REDIRECT = 690
36+
};
37+
38+
class BanWatcher : public ModeWatcher
39+
{
40+
public:
41+
ExtBan::Base& extban;
42+
43+
BanWatcher(Module* parent, ExtBan::Base& xb)
44+
: ModeWatcher(parent, "ban", MODETYPE_CHANNEL)
45+
, extban(xb)
46+
{
47+
}
48+
49+
bool IsExtBanRedirect(const std::string& mask, std::string& value, bool& inverted)
50+
{
51+
std::string name;
52+
if (!ExtBan::Parse(mask, name, value, inverted))
53+
return false;
54+
55+
if (inverted)
56+
return false;
57+
58+
if (name.size() == 1)
59+
return name[0] == extban.GetLetter();
60+
return irc::equals(name, extban.GetName());
61+
}
62+
63+
bool BeforeMode(User* source, User*, Channel* channel, Modes::Change& change) override
64+
{
65+
if (!IS_LOCAL(source) || !channel || !change.adding)
66+
return true;
67+
68+
std::string value;
69+
bool inverted;
70+
if (!IsExtBanRedirect(change.param, value, inverted))
71+
return true;
72+
73+
const std::string::size_type p = value.find(':');
74+
if (p == std::string::npos)
75+
{
76+
source->WriteNumeric(ERR_REDIRECT, INSP_FORMAT("Extban redirect \"{}\" is invalid. Format: <extban>:<chan>:<mask>", change.param));
77+
return false;
78+
}
79+
80+
const std::string targetname(value, 0, p);
81+
if (!ServerInstance->Channels.IsChannel(targetname))
82+
{
83+
source->WriteNumeric(ERR_NOSUCHCHANNEL, channel->name, INSP_FORMAT("Invalid channel name in redirection ({})", targetname));
84+
return false;
85+
}
86+
87+
Channel* const targetchan = ServerInstance->Channels.Find(targetname);
88+
if (!targetchan)
89+
{
90+
source->WriteNumeric(ERR_NOSUCHCHANNEL, channel->name, INSP_FORMAT("Target channel {} must exist to be set as a redirect.", targetname));
91+
return false;
92+
}
93+
94+
if (targetchan == channel)
95+
{
96+
source->WriteNumeric(ERR_NOSUCHCHANNEL, channel->name, "You cannot set a ban redirection to the channel the ban is on");
97+
return false;
98+
}
99+
100+
if (targetchan->GetPrefixValue(source) < OP_VALUE)
101+
{
102+
source->WriteNumeric(ERR_CHANOPRIVSNEEDED, channel->name, INSP_FORMAT("You must be opped on {} to set it as a redirect.", targetname));
103+
return false;
104+
}
105+
106+
return true;
107+
}
108+
};
109+
110+
class ExtBanRedirect final
111+
: public ExtBan::MatchingBase
112+
{
113+
static bool CheckSimpleBan(User* user, const std::string& mask)
114+
{
115+
const auto at = mask.find('@');
116+
if (at == std::string::npos)
117+
return false;
118+
119+
const std::string prefix(mask, 0, at);
120+
if (!InspIRCd::Match(user->nick + "!" + user->GetDisplayedUser(), prefix) &&
121+
!InspIRCd::Match(user->nick + "!" + user->GetRealUser(), prefix))
122+
{
123+
return false;
124+
}
125+
126+
const std::string suffix(mask, at + 1);
127+
return InspIRCd::Match(user->GetRealHost(), suffix) ||
128+
InspIRCd::Match(user->GetDisplayedHost(), suffix) ||
129+
InspIRCd::MatchCIDR(user->GetAddress(), suffix);
130+
}
131+
132+
public:
133+
ExtBanRedirect(Module* Creator)
134+
: MatchingBase(Creator, "redirect", 'd')
135+
{
136+
}
137+
138+
void Canonicalize(std::string& text) override
139+
{
140+
const auto p = text.find(':');
141+
if (p == std::string::npos)
142+
return;
143+
144+
std::string chan(text, 0, p);
145+
std::string mask(text, p + 1);
146+
ModeParser::CleanMask(mask);
147+
text.assign(chan).append(":").append(mask);
148+
}
149+
150+
bool IsMatch(User* user, Channel* channel, const std::string& text) override
151+
{
152+
const auto p = text.find(':');
153+
if (p == std::string::npos)
154+
return false;
155+
156+
const std::string mask(text, p + 1);
157+
return CheckSimpleBan(user, mask);
158+
}
159+
};
160+
161+
class ModuleExtBanRedirect : public Module
162+
{
163+
ChanModeReference limitmode;
164+
ChanModeReference limitredirect;
165+
ExtBanRedirect extban;
166+
BanWatcher banwatcher;
167+
bool active;
168+
169+
public:
170+
ModuleExtBanRedirect()
171+
: Module(VF_VENDOR, "Provide extended ban <extbanchar>:<chan>:<mask> to redirect users to another channel")
172+
, limitmode(this, "limit")
173+
, limitredirect(this, "redirect")
174+
, extban(this)
175+
, banwatcher(this, extban)
176+
, active(false)
177+
{
178+
}
179+
180+
void ReadConfig(ConfigStatus&) override
181+
{
182+
// The extban letter is configured via <extbans redirect="...">.
183+
// This tag is kept for compatibility with older configs.
184+
const auto& tag = ServerInstance->Config->ConfValue("extbanredirect");
185+
const auto confletter = tag->getString("char", "", 1, 1);
186+
if (!confletter.empty() && confletter[0] != extban.GetLetter())
187+
ServerInstance->Logs.Debug(MODNAME, "Ignoring <extbanredirect:char>; use <extbans redirect=\"{}\"> instead.", confletter[0]);
188+
}
189+
190+
ModResult OnCheckBan(User* user, Channel* chan, const std::string& mask) override
191+
{
192+
LocalUser* localuser = IS_LOCAL(user);
193+
194+
if (active || !localuser)
195+
return MOD_RES_PASSTHRU;
196+
197+
std::string value;
198+
bool inverted;
199+
if (!banwatcher.IsExtBanRedirect(mask, value, inverted))
200+
return MOD_RES_PASSTHRU;
201+
202+
if (!extban.IsMatch(localuser, chan, value))
203+
return MOD_RES_PASSTHRU;
204+
205+
std::string::size_type p = value.find(':');
206+
if (p == std::string::npos)
207+
return MOD_RES_PASSTHRU;
208+
209+
const std::string targetname = value.substr(0, p);
210+
Channel* const target = ServerInstance->Channels.Find(targetname);
211+
if (target && target->IsModeSet(limitmode))
212+
{
213+
if (target->IsModeSet(limitredirect) && target->GetUsers().size() >= ConvToNum<size_t>(target->GetModeParameter(limitmode)))
214+
{
215+
// The core will send "You're banned"
216+
return MOD_RES_DENY;
217+
}
218+
}
219+
220+
// Ok to redirect
221+
// The core will send "You're banned"
222+
localuser->WriteNumeric(ERR_LINKCHANNEL, chan->name, targetname, "You are banned from this channel, so you are automatically being transferred to the redirected channel.");
223+
active = true;
224+
Channel::JoinUser(localuser, targetname);
225+
active = false;
226+
227+
return MOD_RES_DENY;
228+
}
229+
};
230+
231+
MODULE_INIT(ModuleExtBanRedirect)

0 commit comments

Comments
 (0)