]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/xline.cpp
Use XLineFactory in ADDLINE, so that it can deal with anything the rest of the ircd...
[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, User* user)
130 {
131         /*IdentHostPair ih = IdentSplit(hostmask);*/
132
133         if (DelLine(line->Displayable(), line->type, user, 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(line);
139         sort(active_lines.begin(), active_lines.end(), XLineManager::XSortComparison);
140         pending_lines.push_back(line);
141         lookup_lines[line->type][line->Displayable()] = line;
142         line->OnAdd();
143
144         FOREACH_MOD(I_OnAddLine,OnAddLine(user, line)); 
145
146         return true;
147 }
148
149 /*bool XLineManager::AddZLine(long duration, const char* source, const char* reason, const char* ipaddr)
150 {
151         if (strchr(ipaddr,'@'))
152         {
153                 while (*ipaddr != '@')
154                         ipaddr++;
155                 ipaddr++;
156         }*/
157
158 // deletes a g:line, returns true if the line existed and was removed
159
160 bool XLineManager::DelLine(const char* hostmask, char type, User* user, bool simulate)
161 {
162         IdentHostPair ih = IdentSplit(hostmask);
163         for (std::vector<XLine*>::iterator i = active_lines.begin(); i != active_lines.end(); i++)
164         {
165                 if ((*i)->type == type)
166                 {
167                         if ((*i)->MatchesLiteral(hostmask))
168                         {
169                                 if (!simulate)
170                                 {
171                                         (*i)->Unset();
172                                         delete *i;
173                                         active_lines.erase(i);
174                                         if (lookup_lines.find(type) != lookup_lines.end())
175                                                 lookup_lines[type].erase(hostmask);
176
177                                         FOREACH_MOD(I_OnDelLine,OnDelLine(user, *i));
178
179                                         std::vector<XLine*>::iterator pptr = std::find(pending_lines.begin(), pending_lines.end(), *i);                                 
180                                         if (pptr != pending_lines.end())
181                                                 pending_lines.erase(pptr);
182                                 }
183                                 return true;
184                         }
185                 }
186         }
187
188         return false;
189 }
190
191
192 void ELine::Unset()
193 {
194         /* remove exempt from everyone and force recheck after deleting eline */
195         for (std::vector<User*>::const_iterator u2 = ServerInstance->local_users.begin(); u2 != ServerInstance->local_users.end(); u2++)
196         {
197                 User* u = (User*)(*u2);
198                 u->exempt = false;
199         }
200
201         if (ServerInstance->XLines->lookup_lines.find('E') != ServerInstance->XLines->lookup_lines.end())
202                 ServerInstance->XLines->CheckELines(ServerInstance->XLines->lookup_lines['E']);
203 }
204
205 // returns a pointer to the reason if a nickname matches a qline, NULL if it didnt match
206
207 QLine* XLineManager::matches_qline(const char* nick)
208 {
209         if (lookup_lines.find('Q') == lookup_lines.end())
210                 return NULL;
211
212         if (lookup_lines.find('Q') != lookup_lines.end() && lookup_lines['Q'].empty())
213                 return NULL;
214
215         for (std::vector<XLine*>::iterator i = active_lines.begin(); i != active_lines.end(); i++)
216                 if ((*i)->type == 'Q' && (*i)->Matches(nick))
217                         return (QLine*)(*i);
218         return NULL;
219 }
220
221 // returns a pointer to the reason if a host matches a gline, NULL if it didnt match
222
223 GLine* XLineManager::matches_gline(User* user)
224 {
225         if (lookup_lines.find('G') == lookup_lines.end())
226                 return NULL;
227
228         if (lookup_lines.find('G') != lookup_lines.end() && lookup_lines['G'].empty())
229                 return NULL;
230
231         for (std::vector<XLine*>::iterator i = active_lines.begin(); i != active_lines.end(); i++)
232                 if ((*i)->type == 'G' && (*i)->Matches(user))
233                         return (GLine*)(*i);
234
235         return NULL;
236 }
237
238 ELine* XLineManager::matches_exception(User* user)
239 {
240         if (lookup_lines.find('E') == lookup_lines.end())
241                 return NULL;
242
243         if (lookup_lines.find('E') != lookup_lines.end() && lookup_lines['E'].empty())
244                 return NULL;
245
246         for (std::vector<XLine*>::iterator i = active_lines.begin(); i != active_lines.end(); i++)
247         {
248                 if ((*i)->type == 'E' && (*i)->Matches(user))
249                         return (ELine*)(*i);
250         }
251         return NULL;
252 }
253
254
255 void XLineManager::gline_set_creation_time(const char* host, time_t create_time)
256 {
257         /*for (std::vector<XLine*>::iterator i = glines.begin(); i != glines.end(); i++)
258         {
259                 if (!strcasecmp(host,(*i)->hostmask))
260                 {
261                         (*i)->set_time = create_time;
262                         (*i)->expiry = create_time + (*i)->duration;
263                         return;
264                 }
265         }*/
266
267         return ;
268 }
269
270 void XLineManager::eline_set_creation_time(const char* host, time_t create_time)
271 {
272         /*for (std::vector<ELine*>::iterator i = elines.begin(); i != elines.end(); i++)
273         {
274                 if (!strcasecmp(host,(*i)->hostmask))
275                 {
276                         (*i)->set_time = create_time;
277                         (*i)->expiry = create_time + (*i)->duration;
278                         return;
279                 }
280         }*/
281
282         return;
283 }
284
285 void XLineManager::qline_set_creation_time(const char* nick, time_t create_time)
286 {
287         /*for (std::vector<QLine*>::iterator i = qlines.begin(); i != qlines.end(); i++)
288         {
289                 if (!strcasecmp(nick,(*i)->nick))
290                 {
291                         (*i)->set_time = create_time;
292                         (*i)->expiry = create_time + (*i)->duration;
293                         return;
294                 }
295         }*/
296
297         return;
298 }
299
300 void XLineManager::zline_set_creation_time(const char* ip, time_t create_time)
301 {
302         /*for (std::vector<ZLine*>::iterator i = zlines.begin(); i != zlines.end(); i++)
303         {
304                 if (!strcasecmp(ip,(*i)->ipaddr))
305                 {
306                         (*i)->set_time = create_time;
307                         (*i)->expiry = create_time + (*i)->duration;
308                         return;
309                 }
310         }*/
311
312         return;
313 }
314
315 // returns a pointer to the reason if an ip address matches a zline, NULL if it didnt match
316
317 ZLine* XLineManager::matches_zline(User *u)
318 {
319         if (lookup_lines.find('Z') == lookup_lines.end())
320                 return NULL;
321
322         if (lookup_lines.find('Z') != lookup_lines.end() && lookup_lines['Z'].empty())
323                 return NULL;
324
325         for (std::vector<XLine*>::iterator i = active_lines.begin(); i != active_lines.end(); i++)
326                 if ((*i)->type == 'Z' && (*i)->Matches(u))
327                         return (ZLine*)(*i);
328         return NULL;
329 }
330
331 // returns a pointer to the reason if a host matches a kline, NULL if it didnt match
332
333 KLine* XLineManager::matches_kline(User* user)
334 {
335         if (lookup_lines.find('K') == lookup_lines.end())
336                 return NULL;
337
338         if (lookup_lines.find('K') != lookup_lines.end() && lookup_lines['K'].empty())
339                 return NULL;
340
341         for (std::vector<XLine*>::iterator i = active_lines.begin(); i != active_lines.end(); i++)
342                 if ((*i)->Matches(user))
343                         return (KLine*)(*i);
344
345         return NULL;
346 }
347
348 bool XLineManager::XSortComparison(const XLine *one, const XLine *two)
349 {
350         // account for permanent lines
351         if (one->expiry == 0)
352         {
353                 return false;
354         }
355         return (one->expiry) < (two->expiry);
356 }
357
358 // removes lines that have expired
359 void XLineManager::expire_lines()
360 {
361         time_t current = ServerInstance->Time();
362
363         /* Because we now store all our XLines in sorted order using ((*i)->duration + (*i)->set_time) as a key, this
364          * means that to expire the XLines we just need to do a while, picking off the top few until there are
365          * none left at the head of the queue that are after the current time.
366          */
367
368         while ((active_lines.size()) && (current > (*active_lines.begin())->expiry) && ((*active_lines.begin())->duration != 0))
369         {
370                 std::vector<XLine*>::iterator i = active_lines.begin();
371                 (*i)->DisplayExpiry();
372                 (*i)->Unset();
373                 active_lines.erase(i);
374                 delete *i;
375         }
376 }
377
378 // applies lines, removing clients and changing nicks etc as applicable
379 void XLineManager::ApplyLines()
380 {
381         for (std::vector<User*>::const_iterator u2 = ServerInstance->local_users.begin(); u2 != ServerInstance->local_users.end(); u2++)
382         {
383                 User* u = (User*)(*u2);
384
385                 for (std::vector<XLine *>::iterator i = pending_lines.begin(); i != pending_lines.end(); i++)
386                 {
387                         XLine *x = *i;
388                         if (x->Matches(u))
389                                 x->Apply(u);
390                 }
391         }
392
393         pending_lines.clear();
394 }
395
396 void XLineManager::stats_k(User* user, string_list &results)
397 {
398         /*std::string sn = ServerInstance->Config->ServerName;
399         for (std::vector<KLine*>::iterator i = klines.begin(); i != klines.end(); i++)
400                 results.push_back(sn+" 216 "+user->nick+" :"+(*i)->identmask+"@"+(*i)->hostmask+" "+ConvToStr((*i)->set_time)+" "+ConvToStr((*i)->duration)+" "+(*i)->source+" :"+(*i)->reason);*/
401 }
402
403 void XLineManager::stats_g(User* user, string_list &results)
404 {
405         /*std::string sn = ServerInstance->Config->ServerName;
406         for (std::vector<GLine*>::iterator i = glines.begin(); i != glines.end(); i++)
407                 results.push_back(sn+" 223 "+user->nick+" :"+(*i)->identmask+"@"+(*i)->hostmask+" "+ConvToStr((*i)->set_time)+" "+ConvToStr((*i)->duration)+" "+(*i)->source+" :"+(*i)->reason);*/
408 }
409
410 void XLineManager::stats_q(User* user, string_list &results)
411 {
412         /*std::string sn = ServerInstance->Config->ServerName;
413         for (std::vector<QLine*>::iterator i = qlines.begin(); i != qlines.end(); i++)
414                 results.push_back(sn+" 217 "+user->nick+" :"+(*i)->nick+" "+ConvToStr((*i)->set_time)+" "+ConvToStr((*i)->duration)+" "+(*i)->source+" :"+(*i)->reason);*/
415 }
416
417 void XLineManager::stats_z(User* user, string_list &results)
418 {
419         /*std::string sn = ServerInstance->Config->ServerName;
420         for (std::vector<ZLine*>::iterator i = zlines.begin(); i != zlines.end(); i++)
421                 results.push_back(sn+" 223 "+user->nick+" :"+(*i)->ipaddr+" "+ConvToStr((*i)->set_time)+" "+ConvToStr((*i)->duration)+" "+(*i)->source+" :"+(*i)->reason);*/
422 }
423
424 void XLineManager::stats_e(User* user, string_list &results)
425 {
426         /*std::string sn = ServerInstance->Config->ServerName;
427         for (std::vector<ELine*>::iterator i = elines.begin(); i != elines.end(); i++)
428                 results.push_back(sn+" 223 "+user->nick+" :"+(*i)->identmask+"@"+(*i)->hostmask+" "+ConvToStr((*i)->set_time)+" "+ConvToStr((*i)->duration)+" "+(*i)->source+" :"+(*i)->reason);*/
429 }
430
431 XLineManager::XLineManager(InspIRCd* Instance) : ServerInstance(Instance)
432 {
433         GFact = new GLineFactory(Instance);
434         EFact = new ELineFactory(Instance);
435         KFact = new KLineFactory(Instance);
436         QFact = new QLineFactory(Instance);
437         ZFact = new ZLineFactory(Instance);
438
439         RegisterFactory(GFact);
440         RegisterFactory(EFact);
441         RegisterFactory(KFact);
442         RegisterFactory(QFact);
443         RegisterFactory(ZFact);
444 }
445
446 XLineManager::~XLineManager()
447 {
448         UnregisterFactory(GFact);
449         UnregisterFactory(EFact);
450         UnregisterFactory(KFact);
451         UnregisterFactory(QFact);
452         UnregisterFactory(ZFact);
453
454         delete GFact;
455         delete EFact;
456         delete KFact;
457         delete QFact;
458         delete ZFact;
459 }
460
461 void XLine::Apply(User* u)
462 {
463 }
464
465 void XLine::DefaultApply(User* u, char line)
466 {
467         char reason[MAXBUF];
468         snprintf(reason, MAXBUF, "%c-Lined: %s", line, this->reason);
469         if (*ServerInstance->Config->MoronBanner)
470                 u->WriteServ("NOTICE %s :*** %s", u->nick, ServerInstance->Config->MoronBanner);
471         if (ServerInstance->Config->HideBans)
472                 User::QuitUser(ServerInstance, u, line + std::string("-Lined"), reason);
473         else
474                 User::QuitUser(ServerInstance, u, reason);
475 }
476
477 bool KLine::Matches(User *u)
478 {
479         if (u->exempt)
480                 return false;
481
482         if ((match(u->ident, this->identmask)))
483         {
484                 if ((match(u->host, this->hostmask, true)) || (match(u->GetIPString(), this->hostmask, true)))
485                 {
486                         return true;
487                 }
488         }
489
490         return false;
491 }
492
493 void KLine::Apply(User* u)
494 {
495         DefaultApply(u, 'K');
496 }
497
498 bool GLine::Matches(User *u)
499 {
500         if (u->exempt)
501                 return false;
502
503         if ((match(u->ident, this->identmask)))
504         {
505                 if ((match(u->host, this->hostmask, true)) || (match(u->GetIPString(), this->hostmask, true)))
506                 {
507                         return true;
508                 }
509         }
510
511         return false;
512 }
513
514 void GLine::Apply(User* u)
515 {       
516         DefaultApply(u, 'G');
517 }
518
519 bool ELine::Matches(User *u)
520 {
521         if (u->exempt)
522                 return false;
523
524         if ((match(u->ident, this->identmask)))
525         {
526                 if ((match(u->host, this->hostmask, true)) || (match(u->GetIPString(), this->hostmask, true)))
527                 {
528                         return true;
529                 }
530         }
531
532         return false;
533 }
534
535 bool ZLine::Matches(User *u)
536 {
537         if (u->exempt)
538                 return false;
539
540         if (match(u->GetIPString(), this->ipaddr, true))
541                 return true;
542         else
543                 return false;
544 }
545
546 void ZLine::Apply(User* u)
547 {       
548         DefaultApply(u, 'Z');
549 }
550
551
552 bool QLine::Matches(User *u)
553 {
554         if (u->exempt)
555                 return false;
556
557         if (match(u->nick, this->nick))
558                 return true;
559
560         return false;
561 }
562
563 void QLine::Apply(User* u)
564 {       
565         /* Can we force the user to their uid here instead? */
566         DefaultApply(u, 'Q');
567 }
568
569
570 bool ZLine::Matches(const std::string &str)
571 {
572         if (match(str.c_str(), this->ipaddr, true))
573                 return true;
574         else
575                 return false;
576 }
577
578 bool QLine::Matches(const std::string &str)
579 {
580         if (match(str.c_str(), this->nick))
581                 return true;
582
583         return false;
584 }
585
586 bool ELine::Matches(const std::string &str)
587 {
588         return ((match(str.c_str(), matchtext.c_str(), true)));
589 }
590
591 bool KLine::Matches(const std::string &str)
592 {
593         return ((match(str.c_str(), matchtext.c_str(), true)));
594 }
595
596 bool GLine::Matches(const std::string &str)
597 {
598         return ((match(str.c_str(), matchtext.c_str(), true)));
599 }
600
601 bool ELine::MatchesLiteral(const std::string &str)
602 {
603         return (assign(str) == matchtext);
604 }
605
606 bool ZLine::MatchesLiteral(const std::string &str)
607 {       
608         return (assign(str) == this->ipaddr);
609 }
610
611 bool GLine::MatchesLiteral(const std::string &str)
612 {       
613         return (assign(str) == matchtext);
614 }
615
616 bool KLine::MatchesLiteral(const std::string &str)
617 {       
618         return (assign(str) == matchtext);
619 }
620
621 bool QLine::MatchesLiteral(const std::string &str)
622 {       
623         return (assign(str) == this->nick);
624 }
625
626 void ELine::OnAdd()
627 {
628         /* When adding one eline, only check the one eline */
629         for (std::vector<User*>::const_iterator u2 = ServerInstance->local_users.begin(); u2 != ServerInstance->local_users.end(); u2++)
630         {
631                 User* u = (User*)(*u2);
632                 if (this->Matches(u))
633                         u->exempt = true;
634         }
635 }
636
637 void ELine::DisplayExpiry()
638 {
639         ServerInstance->SNO->WriteToSnoMask('x',"Expiring timed E-Line %s@%s (set by %s %d seconds ago)",this->identmask,this->hostmask,this->source,this->duration);
640 }
641
642 void QLine::DisplayExpiry()
643 {
644         ServerInstance->SNO->WriteToSnoMask('x',"Expiring timed Q-Line %s (set by %s %d seconds ago)",this->nick,this->source,this->duration);
645 }
646
647 void ZLine::DisplayExpiry()
648 {
649         ServerInstance->SNO->WriteToSnoMask('x',"Expiring timed Z-Line %s (set by %s %d seconds ago)",this->ipaddr,this->source,this->duration);
650 }
651
652 void KLine::DisplayExpiry()
653 {
654         ServerInstance->SNO->WriteToSnoMask('x',"Expiring timed K-Line %s@%s (set by %s %d seconds ago)",this->identmask,this->hostmask,this->source,this->duration);
655 }
656
657 void GLine::DisplayExpiry()
658 {
659         ServerInstance->SNO->WriteToSnoMask('x',"Expiring timed G-Line %s@%s (set by %s %d seconds ago)",this->identmask,this->hostmask,this->source,this->duration);
660 }
661
662 const char* ELine::Displayable()
663 {
664         return matchtext.c_str();
665 }
666
667 const char* KLine::Displayable()
668 {
669         return matchtext.c_str();
670 }
671
672 const char* GLine::Displayable()
673 {
674         return matchtext.c_str();
675 }
676
677 const char* ZLine::Displayable()
678 {
679         return ipaddr;
680 }
681
682 const char* QLine::Displayable()
683 {
684         return nick;
685 }
686
687 bool XLineManager::RegisterFactory(XLineFactory* xlf)
688 {
689         std::map<char, XLineFactory*>::iterator n = line_factory.find(xlf->GetType());
690
691         if (n != line_factory.end())
692                 return false;
693
694         line_factory[xlf->GetType()] = xlf;
695
696         return true;
697 }
698
699 bool XLineManager::UnregisterFactory(XLineFactory* xlf)
700 {
701         std::map<char, XLineFactory*>::iterator n = line_factory.find(xlf->GetType());
702
703         if (n == line_factory.end())
704                 return false;
705
706         line_factory.erase(n);
707
708         return true;
709 }
710
711 XLineFactory* XLineManager::GetFactory(const char type)
712 {
713         std::map<char, XLineFactory*>::iterator n = line_factory.find(type);
714
715         if (n != line_factory.end())
716                 return NULL;
717
718         return n->second;
719 }
720