]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/modules/m_nickflood.cpp
Fix the cloaking module on C++98 compilers.
[user/henk/code/inspircd.git] / src / modules / m_nickflood.cpp
1 /*
2  * InspIRCd -- Internet Relay Chat Daemon
3  *
4  *   Copyright (C) 2013, 2016-2019 Sadie Powell <sadie@witchery.services>
5  *   Copyright (C) 2012, 2019 Robby <robby@chatbelgie.be>
6  *   Copyright (C) 2012, 2014 Attila Molnar <attilamolnar@hush.com>
7  *   Copyright (C) 2010 Craig Edwards <brain@inspircd.org>
8  *   Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org>
9  *   Copyright (C) 2007-2009 Robin Burchell <robin+git@viroteck.net>
10  *
11  * This file is part of InspIRCd.  InspIRCd is free software: you can
12  * redistribute it and/or modify it under the terms of the GNU General Public
13  * License as published by the Free Software Foundation, version 2.
14  *
15  * This program is distributed in the hope that it will be useful, but WITHOUT
16  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
18  * details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
22  */
23
24
25 #include "inspircd.h"
26 #include "modules/exemption.h"
27
28 // The number of seconds nickname changing will be blocked for.
29 static unsigned int duration;
30
31 /** Holds settings and state associated with channel mode +F
32  */
33 class nickfloodsettings
34 {
35  public:
36         unsigned int secs;
37         unsigned int nicks;
38         time_t reset;
39         time_t unlocktime;
40         unsigned int counter;
41
42         nickfloodsettings(unsigned int b, unsigned int c)
43                 : secs(b), nicks(c), unlocktime(0), counter(0)
44         {
45                 reset = ServerInstance->Time() + secs;
46         }
47
48         void addnick()
49         {
50                 if (ServerInstance->Time() > reset)
51                 {
52                         counter = 1;
53                         reset = ServerInstance->Time() + secs;
54                 }
55                 else
56                         counter++;
57         }
58
59         bool shouldlock()
60         {
61                 return ((ServerInstance->Time() <= reset) && (counter == this->nicks));
62         }
63
64         void clear()
65         {
66                 counter = 0;
67         }
68
69         bool islocked()
70         {
71                 if (ServerInstance->Time() > unlocktime)
72                         unlocktime = 0;
73
74                 return (unlocktime != 0);
75         }
76
77         void lock()
78         {
79                 unlocktime = ServerInstance->Time() + duration;
80         }
81 };
82
83 /** Handles channel mode +F
84  */
85 class NickFlood : public ParamMode<NickFlood, SimpleExtItem<nickfloodsettings> >
86 {
87  public:
88         NickFlood(Module* Creator)
89                 : ParamMode<NickFlood, SimpleExtItem<nickfloodsettings> >(Creator, "nickflood", 'F')
90         {
91                 syntax = "<nick-changes>:<seconds>";
92         }
93
94         ModeAction OnSet(User* source, Channel* channel, std::string& parameter) CXX11_OVERRIDE
95         {
96                 std::string::size_type colon = parameter.find(':');
97                 if ((colon == std::string::npos) || (parameter.find('-') != std::string::npos))
98                 {
99                         source->WriteNumeric(Numerics::InvalidModeParameter(channel, this, parameter));
100                         return MODEACTION_DENY;
101                 }
102
103                 /* Set up the flood parameters for this channel */
104                 unsigned int nnicks = ConvToNum<unsigned int>(parameter.substr(0, colon));
105                 unsigned int nsecs = ConvToNum<unsigned int>(parameter.substr(colon+1));
106
107                 if ((nnicks<1) || (nsecs<1))
108                 {
109                         source->WriteNumeric(Numerics::InvalidModeParameter(channel, this, parameter));
110                         return MODEACTION_DENY;
111                 }
112
113                 ext.set(channel, new nickfloodsettings(nsecs, nnicks));
114                 return MODEACTION_ALLOW;
115         }
116
117         void SerializeParam(Channel* chan, const nickfloodsettings* nfs, std::string& out)
118         {
119                 out.append(ConvToStr(nfs->nicks)).push_back(':');
120                 out.append(ConvToStr(nfs->secs));
121         }
122 };
123
124 class ModuleNickFlood : public Module
125 {
126         CheckExemption::EventProvider exemptionprov;
127         NickFlood nf;
128
129  public:
130         ModuleNickFlood()
131                 : exemptionprov(this)
132                 , nf(this)
133         {
134         }
135
136         void ReadConfig(ConfigStatus&) CXX11_OVERRIDE
137         {
138                 ConfigTag* tag = ServerInstance->Config->ConfValue("nickflood");
139                 duration = tag->getDuration("duration", 60, 10, 600);
140         }
141
142         ModResult OnUserPreNick(LocalUser* user, const std::string& newnick) CXX11_OVERRIDE
143         {
144                 for (User::ChanList::iterator i = user->chans.begin(); i != user->chans.end(); i++)
145                 {
146                         Channel* channel = (*i)->chan;
147                         ModResult res;
148
149                         nickfloodsettings *f = nf.ext.get(channel);
150                         if (f)
151                         {
152                                 res = CheckExemption::Call(exemptionprov, user, channel, "nickflood");
153                                 if (res == MOD_RES_ALLOW)
154                                         continue;
155
156                                 if (f->islocked())
157                                 {
158                                         user->WriteNumeric(ERR_CANTCHANGENICK, InspIRCd::Format("%s has been locked for nickchanges for %u seconds because there have been more than %u nick changes in %u seconds", channel->name.c_str(), duration, f->nicks, f->secs));
159                                         return MOD_RES_DENY;
160                                 }
161
162                                 if (f->shouldlock())
163                                 {
164                                         f->clear();
165                                         f->lock();
166                                         channel->WriteNotice(InspIRCd::Format("No nick changes are allowed for %u seconds because there have been more than %u nick changes in %u seconds.", duration, f->nicks, f->secs));
167                                         return MOD_RES_DENY;
168                                 }
169                         }
170                 }
171
172                 return MOD_RES_PASSTHRU;
173         }
174
175         /*
176          * XXX: HACK: We do the increment on the *POST* event here (instead of all together) because we have no way of knowing whether other modules would block a nickchange.
177          */
178         void OnUserPostNick(User* user, const std::string &oldnick) CXX11_OVERRIDE
179         {
180                 if (isdigit(user->nick[0])) /* allow switches to UID */
181                         return;
182
183                 for (User::ChanList::iterator i = user->chans.begin(); i != user->chans.end(); ++i)
184                 {
185                         Channel* channel = (*i)->chan;
186                         ModResult res;
187
188                         nickfloodsettings *f = nf.ext.get(channel);
189                         if (f)
190                         {
191                                 res = CheckExemption::Call(exemptionprov, user, channel, "nickflood");
192                                 if (res == MOD_RES_ALLOW)
193                                         return;
194
195                                 /* moved this here to avoid incrementing the counter for nick
196                                  * changes that are denied for some other reason (bans, +N, etc.)
197                                  * per bug #874.
198                                  */
199                                 f->addnick();
200                         }
201                 }
202         }
203
204         Version GetVersion() CXX11_OVERRIDE
205         {
206                 return Version("Adds channel mode F (nickflood) which helps protect against spammers which mass-change nicknames.", VF_VENDOR);
207         }
208 };
209
210 MODULE_INIT(ModuleNickFlood)