]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/xline.cpp
More stuff
[user/henk/code/inspircd.git] / src / xline.cpp
1 /*       +------------------------------------+
2  *       | Inspire Internet Relay Chat Daemon |
3  *       +------------------------------------+
4  *
5  *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
6  * See: http://www.inspircd.org/wiki/index.php/Credits
7  *
8  * This program is free but copyrighted software; see
9  *            the file COPYING for details.
10  *
11  * ---------------------------------------------------
12  */
13
14 /* $Core: libIRCDxline */
15
16 #include "inspircd.h"
17 #include "wildcard.h"
18 #include "xline.h"
19
20 /*
21  * This is now version 3 of the XLine subsystem, let's see if we can get it as nice and 
22  * efficient as we can this time so we can close this file and never ever touch it again ..
23  *
24  * Background:
25  *  Version 1 stored all line types in one list (one for g, one for z, etc). This was fine,
26  *  but both version 1 and 2 suck at applying lines efficiently. That is, every time a new line
27  *  was added, it iterated every existing line for every existing user. Ow. Expiry was also
28  *  expensive, as the lists were NOT sorted.
29  *
30  *  Version 2 moved permanent lines into a seperate list from non-permanent to help optimize
31  *  matching speed, but matched in the same way.
32  *  Expiry was also sped up by sorting the list by expiry (meaning just remove the items at the
33  *  head of the list that are outdated.)
34  *
35  * This was fine and good, but it looked less than ideal in code, and matching was still slower
36  * than it could have been, something which we address here.
37  *
38  * VERSION 3:
39  *  All lines are (as in v1) stored together -- no seperation of perm and non-perm. Expiry will
40  *  still use a sorted list, and we'll just ignore anything permanent.
41  *
42  *  Application will be by a list of lines 'pending' application, meaning only the newly added lines
43  *  will be gone over. Much faster.
44  *
45  * More of course is to come.
46  */
47
48 /* Version two, now with optimized expiry!
49  *
50  * Because the old way was horrendously slow, the new way of expiring xlines is very
51  * very efficient. I have improved the efficiency of the algorithm in two ways:
52  *
53  * (1) There are now two lists of items for each linetype. One list holds temporary
54  *     items, and the other list holds permanent items (ones which will expire).
55  *     Items which are on the permanent list are NEVER checked at all by the
56  *     expire_lines() function.
57  * (2) The temporary xline lists are always kept in strict numerical order, keyed by
58  *     current time + duration. This means that the line which is due to expire the
59  *     soonest is always pointed at by vector::begin(), so a simple while loop can
60  *     very efficiently, very quickly and above all SAFELY pick off the first few
61  *     items in the vector which need zapping.
62  *
63  *     -- Brain
64  */
65
66 bool XLine::Matches(User *u)
67 {
68         return false;
69 }
70
71 /*
72  * Checks what users match a given vector of ELines and sets their ban exempt flag accordingly.
73  */
74 void XLineManager::CheckELines(std::map<std::string, XLine *> &ELines)
75 {
76         if (ELines.empty())
77                 return;
78
79         for (std::vector<User*>::const_iterator u2 = ServerInstance->local_users.begin(); u2 != ServerInstance->local_users.end(); u2++)
80         {
81                 User* u = (User*)(*u2);
82
83                 for (std::map<std::string, XLine *>::iterator i = ELines.begin(); i != ELines.end(); i++)
84                 {
85                         XLine *e = i->second;
86                         u->exempt = e->Matches(u);
87                 }
88         }
89 }
90
91 // this should probably be moved to configreader, but atm it relies on CheckELines above.
92 bool DoneELine(ServerConfig* conf, const char* tag)
93 {
94         for (std::vector<User*>::const_iterator u2 = conf->GetInstance()->local_users.begin(); u2 != conf->GetInstance()->local_users.end(); u2++)
95         {
96                 User* u = (User*)(*u2);
97                 u->exempt = false;
98         }
99
100         conf->GetInstance()->XLines->CheckELines(conf->GetInstance()->XLines->lookup_lines['E']);
101         return true;
102 }
103
104
105 IdentHostPair XLineManager::IdentSplit(const std::string &ident_and_host)
106 {
107         IdentHostPair n = std::make_pair<std::string,std::string>("*","*");
108         std::string::size_type x = ident_and_host.find('@');
109         if (x != std::string::npos)
110         {
111                 n.second = ident_and_host.substr(x + 1,ident_and_host.length());
112                 n.first = ident_and_host.substr(0, x);
113                 if (!n.first.length())
114                         n.first.assign("*");
115                 if (!n.second.length())
116                         n.second.assign("*");
117         }
118         else
119         {
120                 n.second = ident_and_host;
121         }
122
123         return n;
124 }
125
126 // adds a g:line
127
128 /*bool XLineManager::AddELine(long duration, const char* source, const char* reason, const char* hostmask)*/
129 bool XLineManager::AddLine(XLine* line)
130 {
131         /*IdentHostPair ih = IdentSplit(hostmask);*/
132
133         if (DelLine(line->Displayable(), line->type, true))
134                 return false;
135
136         /*ELine* item = new ELine(ServerInstance, ServerInstance->Time(), duration, source, reason, ih.first.c_str(), ih.second.c_str());*/
137
138         active_lines.push_back(item);
139         sort(active_lines.begin(), active_lines.end(), XLineManager::XSortComparison);
140         lookup_lines[line->type][hostmask] = item;
141         line->OnAdd();
142
143         // XXX we really only need to check one line (the new one) - this is a bit wasteful!
144         // we should really create a temporary var here and pass that instead.
145         // hmm, perhaps we can merge this with line "application" somehow.. and just force a recheck on DelELine?
146         /*this->CheckELines(lookup_lines['E']);
147         return true;*/
148 }
149
150 /*bool XLineManager::AddZLine(long duration, const char* source, const char* reason, const char* ipaddr)
151 {
152         if (strchr(ipaddr,'@'))
153         {
154                 while (*ipaddr != '@')
155                         ipaddr++;
156                 ipaddr++;
157         }*/
158
159 // deletes a g:line, returns true if the line existed and was removed
160
161 bool XLineManager::DelLine(const char* hostmask, char type, bool simulate)
162 {
163         IdentHostPair ih = IdentSplit(hostmask);
164         for (std::vector<XLine*>::iterator i = active_lines.begin(); i != active_lines.end(); i++)
165         {
166                 if ((*i)->type == type)
167                 {
168                         if ((*i)->MatchesLiteral(hostmask))
169                         {
170                                 if (!simulate)
171                                 {
172                                         (*i)->Unset();
173                                         delete *i;
174                                         active_lines.erase(i);
175                                         if (lookup_lines.find(type) != lookup_lines.end())
176                                                 lookup_lines[type].erase(hostmask);
177                                         /* XXX: Should erase from pending lines here */
178                                 }
179                                 return true;
180                         }
181                 }
182         }
183
184         return false;
185 }
186
187
188 void ELine::Unset()
189 {
190         /* remove exempt from everyone and force recheck after deleting eline */
191         for (std::vector<User*>::const_iterator u2 = ServerInstance->local_users.begin(); u2 != ServerInstance->local_users.end(); u2++)
192         {
193                 User* u = (User*)(*u2);
194                 u->exempt = false;
195         }
196
197         if (ServerInstance->XLines->lookup_lines.find('E') != ServerInstance->XLines->lookup_lines.end())
198                 ServerInstance->XLines->CheckELines(ServerInstance->XLines->lookup_lines['E']);
199 }
200
201 // returns a pointer to the reason if a nickname matches a qline, NULL if it didnt match
202
203 QLine* XLineManager::matches_qline(const char* nick)
204 {
205         if (lookup_lines.find('Q') == lookup_lines.end())
206                 return NULL;
207
208         if (lookup_lines.find('Q') != lookup_lines.end() && lookup_lines['Q'].empty())
209                 return NULL;
210
211         for (std::vector<XLine*>::iterator i = active_lines.begin(); i != active_lines.end(); i++)
212                 if ((*i)->type == 'Q' && (*i)->Matches(nick))
213                         return (QLine*)(*i);
214         return NULL;
215 }
216
217 // returns a pointer to the reason if a host matches a gline, NULL if it didnt match
218
219 GLine* XLineManager::matches_gline(User* user)
220 {
221         if (lookup_lines.find('G') == lookup_lines.end())
222                 return NULL;
223
224         if (lookup_lines.find('G') != lookup_lines.end() && lookup_lines['G'].empty())
225                 return NULL;
226
227         for (std::vector<XLine*>::iterator i = active_lines.begin(); i != active_lines.end(); i++)
228                 if ((*i)->type == 'G' && (*i)->Matches(user))
229                         return (GLine*)(*i);
230
231         return NULL;
232 }
233
234 ELine* XLineManager::matches_exception(User* user)
235 {
236         if (lookup_lines.find('E') == lookup_lines.end())
237                 return NULL;
238
239         if (lookup_lines.find('E') != lookup_lines.end() && lookup_lines['E'].empty())
240                 return NULL;
241
242         for (std::vector<XLine*>::iterator i = active_lines.begin(); i != active_lines.end(); i++)
243         {
244                 if ((*i)->type == 'E' && (*i)->Matches(user))
245                         return (ELine*)(*i);
246         }
247         return NULL;
248 }
249
250
251 void XLineManager::gline_set_creation_time(const char* host, time_t create_time)
252 {
253         /*for (std::vector<XLine*>::iterator i = glines.begin(); i != glines.end(); i++)
254         {
255                 if (!strcasecmp(host,(*i)->hostmask))
256                 {
257                         (*i)->set_time = create_time;
258                         (*i)->expiry = create_time + (*i)->duration;
259                         return;
260                 }
261         }*/
262
263         return ;
264 }
265
266 void XLineManager::eline_set_creation_time(const char* host, time_t create_time)
267 {
268         /*for (std::vector<ELine*>::iterator i = elines.begin(); i != elines.end(); i++)
269         {
270                 if (!strcasecmp(host,(*i)->hostmask))
271                 {
272                         (*i)->set_time = create_time;
273                         (*i)->expiry = create_time + (*i)->duration;
274                         return;
275                 }
276         }*/
277
278         return;
279 }
280
281 void XLineManager::qline_set_creation_time(const char* nick, time_t create_time)
282 {
283         /*for (std::vector<QLine*>::iterator i = qlines.begin(); i != qlines.end(); i++)
284         {
285                 if (!strcasecmp(nick,(*i)->nick))
286                 {
287                         (*i)->set_time = create_time;
288                         (*i)->expiry = create_time + (*i)->duration;
289                         return;
290                 }
291         }*/
292
293         return;
294 }
295
296 void XLineManager::zline_set_creation_time(const char* ip, time_t create_time)
297 {
298         /*for (std::vector<ZLine*>::iterator i = zlines.begin(); i != zlines.end(); i++)
299         {
300                 if (!strcasecmp(ip,(*i)->ipaddr))
301                 {
302                         (*i)->set_time = create_time;
303                         (*i)->expiry = create_time + (*i)->duration;
304                         return;
305                 }
306         }*/
307
308         return;
309 }
310
311 // returns a pointer to the reason if an ip address matches a zline, NULL if it didnt match
312
313 ZLine* XLineManager::matches_zline(User *u)
314 {
315         if (lookup_lines.find('Z') == lookup_lines.end())
316                 return NULL;
317
318         if (lookup_lines.find('Z') != lookup_lines.end() && lookup_lines['Z'].empty())
319                 return NULL;
320
321         for (std::vector<XLine*>::iterator i = active_lines.begin(); i != active_lines.end(); i++)
322                 if ((*i)->type == 'Z' && (*i)->Matches(u))
323                         return (ZLine*)(*i);
324         return NULL;
325 }
326
327 // returns a pointer to the reason if a host matches a kline, NULL if it didnt match
328
329 KLine* XLineManager::matches_kline(User* user)
330 {
331         if (lookup_lines.find('K') == lookup_lines.end())
332                 return NULL;
333
334         if (lookup_lines.find('K') != lookup_lines.end() && lookup_lines['K'].empty())
335                 return NULL;
336
337         for (std::vector<XLine*>::iterator i = active_lines.begin(); i != active_lines.end(); i++)
338                 if ((*i)->Matches(user))
339                         return (KLine*)(*i);
340
341         return NULL;
342 }
343
344 bool XLineManager::XSortComparison(const XLine *one, const XLine *two)
345 {
346         // account for permanent lines
347         if (one->expiry == 0)
348         {
349                 return false;
350         }
351         return (one->expiry) < (two->expiry);
352 }
353
354 // removes lines that have expired
355 void XLineManager::expire_lines()
356 {
357         time_t current = ServerInstance->Time();
358
359         /* Because we now store all our XLines in sorted order using ((*i)->duration + (*i)->set_time) as a key, this
360          * means that to expire the XLines we just need to do a while, picking off the top few until there are
361          * none left at the head of the queue that are after the current time.
362          */
363
364         while ((active_lines.size()) && (current > (*active_lines.begin())->expiry) && ((*active_lines.begin())->duration != 0))
365         {
366                 std::vector<XLine*>::iterator i = active_lines.begin();
367                 (*i)->DisplayExpiry();
368                 (*i)->Unset();
369                 active_lines.erase(i);
370                 delete *i;
371         }
372 }
373
374 // applies lines, removing clients and changing nicks etc as applicable
375 void XLineManager::ApplyLines()
376 {
377         for (std::vector<User*>::const_iterator u2 = ServerInstance->local_users.begin(); u2 != ServerInstance->local_users.end(); u2++)
378         {
379                 User* u = (User*)(*u2);
380
381                 for (std::vector<XLine *>::iterator i = pending_lines.begin(); i != pending_lines.end(); i++)
382                 {
383                         XLine *x = *i;
384                         if (x->Matches(u))
385                                 x->Apply(u);
386                 }
387         }
388
389         pending_lines.clear();
390 }
391
392 void XLineManager::stats_k(User* user, string_list &results)
393 {
394         /*std::string sn = ServerInstance->Config->ServerName;
395         for (std::vector<KLine*>::iterator i = klines.begin(); i != klines.end(); i++)
396                 results.push_back(sn+" 216 "+user->nick+" :"+(*i)->identmask+"@"+(*i)->hostmask+" "+ConvToStr((*i)->set_time)+" "+ConvToStr((*i)->duration)+" "+(*i)->source+" :"+(*i)->reason);*/
397 }
398
399 void XLineManager::stats_g(User* user, string_list &results)
400 {
401         /*std::string sn = ServerInstance->Config->ServerName;
402         for (std::vector<GLine*>::iterator i = glines.begin(); i != glines.end(); i++)
403                 results.push_back(sn+" 223 "+user->nick+" :"+(*i)->identmask+"@"+(*i)->hostmask+" "+ConvToStr((*i)->set_time)+" "+ConvToStr((*i)->duration)+" "+(*i)->source+" :"+(*i)->reason);*/
404 }
405
406 void XLineManager::stats_q(User* user, string_list &results)
407 {
408         /*std::string sn = ServerInstance->Config->ServerName;
409         for (std::vector<QLine*>::iterator i = qlines.begin(); i != qlines.end(); i++)
410                 results.push_back(sn+" 217 "+user->nick+" :"+(*i)->nick+" "+ConvToStr((*i)->set_time)+" "+ConvToStr((*i)->duration)+" "+(*i)->source+" :"+(*i)->reason);*/
411 }
412
413 void XLineManager::stats_z(User* user, string_list &results)
414 {
415         /*std::string sn = ServerInstance->Config->ServerName;
416         for (std::vector<ZLine*>::iterator i = zlines.begin(); i != zlines.end(); i++)
417                 results.push_back(sn+" 223 "+user->nick+" :"+(*i)->ipaddr+" "+ConvToStr((*i)->set_time)+" "+ConvToStr((*i)->duration)+" "+(*i)->source+" :"+(*i)->reason);*/
418 }
419
420 void XLineManager::stats_e(User* user, string_list &results)
421 {
422         /*std::string sn = ServerInstance->Config->ServerName;
423         for (std::vector<ELine*>::iterator i = elines.begin(); i != elines.end(); i++)
424                 results.push_back(sn+" 223 "+user->nick+" :"+(*i)->identmask+"@"+(*i)->hostmask+" "+ConvToStr((*i)->set_time)+" "+ConvToStr((*i)->duration)+" "+(*i)->source+" :"+(*i)->reason);*/
425 }
426
427 XLineManager::XLineManager(InspIRCd* Instance) : ServerInstance(Instance)
428 {
429 }
430
431 void XLine::Apply(User* u)
432 {
433 }
434
435 void XLine::DefaultApply(User* u, char line)
436 {
437         char reason[MAXBUF];
438         snprintf(reason, MAXBUF, "%c-Lined: %s", line, this->reason);
439         if (*ServerInstance->Config->MoronBanner)
440                 u->WriteServ("NOTICE %s :*** %s", u->nick, ServerInstance->Config->MoronBanner);
441         if (ServerInstance->Config->HideBans)
442                 User::QuitUser(ServerInstance, u, line + std::string("-Lined"), reason);
443         else
444                 User::QuitUser(ServerInstance, u, reason);
445 }
446
447 bool KLine::Matches(User *u)
448 {
449         if (u->exempt)
450                 return false;
451
452         if ((match(u->ident, this->identmask)))
453         {
454                 if ((match(u->host, this->hostmask, true)) || (match(u->GetIPString(), this->hostmask, true)))
455                 {
456                         return true;
457                 }
458         }
459
460         return false;
461 }
462
463 void KLine::Apply(User* u)
464 {
465         DefaultApply(u, 'K');
466 }
467
468 bool GLine::Matches(User *u)
469 {
470         if (u->exempt)
471                 return false;
472
473         if ((match(u->ident, this->identmask)))
474         {
475                 if ((match(u->host, this->hostmask, true)) || (match(u->GetIPString(), this->hostmask, true)))
476                 {
477                         return true;
478                 }
479         }
480
481         return false;
482 }
483
484 void GLine::Apply(User* u)
485 {       
486         DefaultApply(u, 'G');
487 }
488
489 bool ELine::Matches(User *u)
490 {
491         if (u->exempt)
492                 return false;
493
494         if ((match(u->ident, this->identmask)))
495         {
496                 if ((match(u->host, this->hostmask, true)) || (match(u->GetIPString(), this->hostmask, true)))
497                 {
498                         return true;
499                 }
500         }
501
502         return false;
503 }
504
505 bool ZLine::Matches(User *u)
506 {
507         if (u->exempt)
508                 return false;
509
510         if (match(u->GetIPString(), this->ipaddr, true))
511                 return true;
512         else
513                 return false;
514 }
515
516 void ZLine::Apply(User* u)
517 {       
518         DefaultApply(u, 'Z');
519 }
520
521
522 bool QLine::Matches(User *u)
523 {
524         if (u->exempt)
525                 return false;
526
527         if (match(u->nick, this->nick))
528                 return true;
529
530         return false;
531 }
532
533 void QLine::Apply(User* u)
534 {       
535         /* Can we force the user to their uid here instead? */
536         DefaultApply(u, 'Q');
537 }
538
539
540 bool ZLine::Matches(const std::string &str)
541 {
542         if (match(str.c_str(), this->ipaddr, true))
543                 return true;
544         else
545                 return false;
546 }
547
548 bool QLine::Matches(const std::string &str)
549 {
550         if (match(str.c_str(), this->nick))
551                 return true;
552
553         return false;
554 }
555
556 bool ELine::Matches(const std::string &str)
557 {
558         return ((match(str.c_str(), matchtext.c_str(), true)));
559 }
560
561 bool KLine::Matches(const std::string &str)
562 {
563         return ((match(str.c_str(), matchtext.c_str(), true)));
564 }
565
566 bool GLine::Matches(const std::string &str)
567 {
568         return ((match(str.c_str(), matchtext.c_str(), true)));
569 }
570
571 bool ELine::MatchesLiteral(const std::string &str)
572 {
573         return (assign(str) == matchtext);
574 }
575
576 bool ZLine::MatchesLiteral(const std::string &str)
577 {       
578         return (assign(str) == this->ipmask);
579 }
580
581 bool GLine::MatchesLiteral(const std::string &str)
582 {       
583         return (assign(str) == matchtext);
584 }
585
586 bool KLine::MatchesLiteral(const std::string &str)
587 {       
588         return (assign(str) == matchtext);
589 }
590
591 bool QLine::MatchesLiteral(const std::string &str)
592 {       
593         return (assign(str) == this->nickmask);
594 }
595
596 void ELine::OnAdd()
597 {
598         ServerInstance->XLines->CheckELines(ServerInstance->XLines->lookup_lines['E']);
599 }
600
601 void ELine::DisplayExpiry()
602 {
603         ServerInstance->SNO->WriteToSnoMask('x',"Expiring timed E-Line %s@%s (set by %s %d seconds ago)",this->identmask,this->hostmask,this->source,this->duration);
604 }
605
606 void QLine::DisplayExpiry()
607 {
608         ServerInstance->SNO->WriteToSnoMask('x',"Expiring timed Q-Line %s (set by %s %d seconds ago)",this->nick,this->source,this->duration);
609 }
610
611 void ZLine::DisplayExpiry()
612 {
613         ServerInstance->SNO->WriteToSnoMask('x',"Expiring timed Z-Line %s (set by %s %d seconds ago)",this->ipaddr,this->source,this->duration);
614 }
615
616 void KLine::DisplayExpiry()
617 {
618         ServerInstance->SNO->WriteToSnoMask('x',"Expiring timed K-Line %s@%s (set by %s %d seconds ago)",this->identmask,this->hostmask,this->source,this->duration);
619 }
620
621 void GLine::DisplayExpiry()
622 {
623         ServerInstance->SNO->WriteToSnoMask('x',"Expiring timed G-Line %s@%s (set by %s %d seconds ago)",this->identmask,this->hostmask,this->source,this->duration);
624 }
625
626 const char* ELine::Displayable()
627 {
628         return matchtext.c_str();
629 }
630
631 const char* KLine::Displayable()
632 {
633         return matchtext.c_str();
634 }
635
636 const char* GLine::Displayable()
637 {
638         return matchtext.c_str();
639 }
640
641 const char* ZLine::Displayable()
642 {
643         return ipaddr;
644 }
645
646 const char* QLine::Displayable()
647 {
648         return nickmask;
649 }
650