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