]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/modules/m_messageflood.cpp
53c9500db44901f6682298faa0fd058cbb2b95c8
[user/henk/code/inspircd.git] / src / modules / m_messageflood.cpp
1 /*       +------------------------------------+
2  *       | Inspire Internet Relay Chat Daemon |
3  *       +------------------------------------+
4  *
5  *  InspIRCd is copyright (C) 2002-2006 ChatSpike-Dev.
6  *                       E-mail:
7  *                <brain@chatspike.net>
8  *                <Craig@chatspike.net>
9  *     
10  * Written by Craig Edwards, Craig McLure, and others.
11  * This program is free but copyrighted software; see
12  *            the file COPYING for details.
13  *
14  * ---------------------------------------------------
15  */
16
17 using namespace std;
18
19 #include <stdio.h>
20 #include <map>
21 #include "users.h"
22 #include "channels.h"
23 #include "modules.h"
24 #include "helperfuncs.h"
25 #include "inspircd.h"
26
27 /* $ModDesc: Provides channel mode +f (message flood protection) */
28
29 class floodsettings : public classbase
30 {
31  public:
32         bool ban;
33         int secs;
34         int lines;
35         time_t reset;
36         std::map<userrec*,int> counters;
37
38         floodsettings() : ban(0), secs(0), lines(0) {};
39         floodsettings(bool a, int b, int c) : ban(a), secs(b), lines(c)
40         {
41                 reset = time(NULL) + secs;
42                 log(DEBUG,"Create new floodsettings: %lu %lu",time(NULL),reset);
43         };
44
45         void addmessage(userrec* who)
46         {
47                 std::map<userrec*,int>::iterator iter = counters.find(who);
48                 if (iter != counters.end())
49                 {
50                         iter->second++;
51                         log(DEBUG,"Count for %s is now %d",who->nick,iter->second);
52                 }
53                 else
54                 {
55                         counters[who] = 1;
56                         log(DEBUG,"Count for %s is now *1*",who->nick);
57                 }
58                 if (time(NULL) > reset)
59                 {
60                         log(DEBUG,"floodsettings timer Resetting.");
61                         counters.clear();
62                         reset = time(NULL) + secs;
63                 }
64         }
65
66         bool shouldkick(userrec* who)
67         {
68                 std::map<userrec*,int>::iterator iter = counters.find(who);
69                 if (iter != counters.end())
70                 {
71                         log(DEBUG,"should kick? %d, %d",iter->second,this->lines);
72                         return (iter->second >= this->lines);
73                 }
74                 else return false;
75         }
76
77         void clear(userrec* who)
78         {
79                 std::map<userrec*,int>::iterator iter = counters.find(who);
80                 if (iter != counters.end())
81                 {
82                         counters.erase(iter);
83                 }
84         }
85 };
86
87 class MsgFlood : public ModeHandler
88 {
89  public:
90         MsgFlood() : ModeHandler('f', 1, 0, false, MODETYPE_CHANNEL, false) { }
91
92         ModePair ModeSet(userrec* source, userrec* dest, chanrec* channel, const std::string &parameter)
93         {
94                 floodsettings* x;
95                 if (channel->GetExt("flood",x))
96                         return std::make_pair(true, (x->ban ? "*" : "")+ConvToStr(x->lines)+":"+ConvToStr(x->secs));
97                 else
98                         return std::make_pair(false, parameter);
99         }
100
101         bool CheckTimeStamp(time_t theirs, time_t ours, const std::string &their_param, const std::string &our_param, chanrec* channel)
102         {
103                 /* When TS is equal, the alphabetically later one wins */
104                 return (their_param < our_param);
105         }
106
107         ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)
108         {
109                 floodsettings *f;
110
111                 if (adding)
112                 {
113                         char ndata[MAXBUF];
114                         char* data = ndata;
115                         strlcpy(ndata,parameter.c_str(),MAXBUF);
116                         char* lines = data;
117                         char* secs = NULL;
118                         bool ban = false;
119                         if (*data == '*')
120                         {
121                                 ban = true;
122                                 lines++;
123                         }
124                         else
125                         {
126                                 ban = false;
127                         }
128                         while (*data)
129                         {
130                                 if (*data == ':')
131                                 {
132                                         *data = 0;
133                                         data++;
134                                         secs = data;
135                                         break;
136                                 }
137                                 else data++;
138                         }
139                         if (secs)
140                         {
141                                 /* Set up the flood parameters for this channel */
142                                 int nlines = atoi(lines);
143                                 int nsecs = atoi(secs);
144                                 if ((nlines<1) || (nsecs<1))
145                                 {
146                                         source->WriteServ("608 %s %s :Invalid flood parameter",source->nick,channel->name);
147                                         parameter = "";
148                                         return MODEACTION_DENY;
149                                 }
150                                 else
151                                 {
152                                         if (!channel->GetExt("flood", f))
153                                         {
154                                                 parameter = ConvToStr(nlines) + ":" +ConvToStr(nsecs);
155                                                 floodsettings *f = new floodsettings(ban,nsecs,nlines);
156                                                 channel->Extend("flood",f);
157                                                 channel->SetMode('f', true);
158                                                 channel->SetModeParam('f', parameter.c_str(), true);
159                                                 return MODEACTION_ALLOW;
160                                         }
161                                 }
162                         }
163                         else
164                         {
165                                 source->WriteServ("608 %s %s :Invalid flood parameter",source->nick,channel->name);
166                                 parameter = "";
167                                 return MODEACTION_DENY;
168                         }
169                 }
170                 else
171                 {
172                         if (channel->GetExt("flood", f))
173                         {
174                                 DELETE(f);
175                                 channel->Shrink("flood");
176                                 channel->SetMode('f', false);
177                                 return MODEACTION_ALLOW;
178                         }
179                 }
180                 
181                 return MODEACTION_DENY;
182         }
183 };
184
185 class ModuleMsgFlood : public Module
186 {
187         Server *Srv;
188         MsgFlood* mf;
189         
190  public:
191  
192         ModuleMsgFlood(Server* Me)
193                 : Module::Module(Me)
194         {
195                 Srv = Me;
196                 mf = new MsgFlood();
197                 Srv->AddMode(mf, 'f');
198         }
199         
200         void ProcessMessages(userrec* user,chanrec* dest, const std::string &text)
201         {
202                 if (IS_LOCAL(user))
203                 {
204                         floodsettings *f;
205                         if (dest->GetExt("flood", f))
206                         {
207                                 f->addmessage(user);
208                                 if (f->shouldkick(user))
209                                 {
210                                         /* Youre outttta here! */
211                                         f->clear(user);
212                                         if (f->ban)
213                                         {
214                                                 const char* parameters[3];
215                                                 parameters[0] = dest->name;
216                                                 parameters[1] = "+b";
217                                                 parameters[2] = user->MakeWildHost();
218                                                 Srv->SendMode(parameters,3,user);
219                                                 std::deque<std::string> n;
220                                                 /* Propogate the ban to other servers.
221                                                  * We dont know what protocol we may be using,
222                                                  * so this event is picked up by our protocol
223                                                  * module and formed into a ban command that
224                                                  * suits the protocol in use.
225                                                  */
226                                                 n.push_back(dest->name);
227                                                 n.push_back("+b");
228                                                 n.push_back(user->MakeWildHost());
229                                                 Event rmode((char *)&n, NULL, "send_mode");
230                                                 rmode.Send();
231                                         }
232                                         dest->ServerKickUser(user, "Channel flood triggered (mode +f)", true);
233                                 }
234                         }
235                 }
236         }
237
238         virtual void OnUserMessage(userrec* user, void* dest, int target_type, const std::string &text, char status)
239         {
240                 if (target_type == TYPE_CHANNEL)
241                 {
242                         ProcessMessages(user,(chanrec*)dest,text);
243                 }
244         }
245
246         virtual void OnUserNotice(userrec* user, void* dest, int target_type, const std::string &text, char status)
247         {
248                 if (target_type == TYPE_CHANNEL)
249                 {
250                         ProcessMessages(user,(chanrec*)dest,text);
251                 }
252         }
253
254         void OnChannelDelete(chanrec* chan)
255         {
256                 floodsettings* f;
257                 if (chan->GetExt("flood", f))
258                 {
259                         DELETE(f);
260                         chan->Shrink("flood");
261                 }
262         }
263
264         void Implements(char* List)
265         {
266                 List[I_On005Numeric] = List[I_OnChannelDelete] = List[I_OnUserNotice] = List[I_OnUserMessage] = 1;
267         }
268
269         virtual void On005Numeric(std::string &output)
270         {
271                 InsertMode(output, "f", 3);
272         }
273
274         virtual ~ModuleMsgFlood()
275         {
276                 DELETE(mf);
277         }
278         
279         virtual Version GetVersion()
280         {
281                 return Version(1,0,0,0,VF_STATIC|VF_VENDOR);
282         }
283 };
284
285
286 class ModuleMsgFloodFactory : public ModuleFactory
287 {
288  public:
289         ModuleMsgFloodFactory()
290         {
291         }
292         
293         ~ModuleMsgFloodFactory()
294         {
295         }
296         
297         virtual Module * CreateModule(Server* Me)
298         {
299                 return new ModuleMsgFlood(Me);
300         }
301         
302 };
303
304
305 extern "C" void * init_module( void )
306 {
307         return new ModuleMsgFloodFactory;
308 }
309