]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/xline.cpp
sorted hashcomp etc
[user/henk/code/inspircd.git] / src / xline.cpp
1 /*       +------------------------------------+
2  *       | Inspire Internet Relay Chat Daemon |
3  *       +------------------------------------+
4  *
5  *  Inspire is copyright (C) 2002-2004 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 #include "inspircd.h"
18 #include "inspircd_io.h"
19 #include "inspircd_util.h"
20 #include "inspircd_config.h"
21 #include <unistd.h>
22 #include <fcntl.h>
23 #include <sys/errno.h>
24 #include <time.h>
25 #include <string>
26 #ifdef GCC3
27 #include <ext/hash_map>
28 #else
29 #include <hash_map>
30 #endif
31 #include <map>
32 #include <sstream>
33 #include <vector>
34 #include <deque>
35 #include "connection.h"
36 #include "users.h"
37 #include "servers.h"
38 #include "ctables.h"
39 #include "globals.h"
40 #include "modules.h"
41 #include "dynamic.h"
42 #include "wildcard.h"
43 #include "message.h"
44 #include "commands.h"
45 #include "xline.h"
46 #include "inspstring.h"
47 #include "helperfuncs.h"
48 #include "hashcomp.h"
49
50 using namespace std;
51
52 extern int MODCOUNT;
53 extern std::vector<Module*> modules;
54 extern std::vector<ircd_module*> factory;
55
56 extern int LogLevel;
57 extern char ServerName[MAXBUF];
58 extern char Network[MAXBUF];
59 extern char ServerDesc[MAXBUF];
60 extern char AdminName[MAXBUF];
61 extern char AdminEmail[MAXBUF];
62 extern char AdminNick[MAXBUF];
63 extern char diepass[MAXBUF];
64 extern char restartpass[MAXBUF];
65 extern char motd[MAXBUF];
66 extern char rules[MAXBUF];
67 extern char list[MAXBUF];
68 extern char PrefixQuit[MAXBUF];
69 extern char DieValue[MAXBUF];
70
71 extern int debugging;
72 extern int WHOWAS_STALE;
73 extern int WHOWAS_MAX;
74 extern int DieDelay;
75 extern time_t startup_time;
76 extern int NetBufferSize;
77 extern time_t nb_start;
78
79 extern std::vector<int> fd_reap;
80 extern std::vector<std::string> module_names;
81
82 extern int boundPortCount;
83 extern int portCount;
84 extern int SERVERportCount;
85 extern int ports[MAXSOCKS];
86 extern int defaultRoute;
87
88 extern std::vector<long> auth_cookies;
89 extern std::stringstream config_f;
90
91 extern serverrec* me[32];
92
93 extern FILE *log_file;
94
95 typedef nspace::hash_map<std::string, userrec*, nspace::hash<string>, StrHashComp> user_hash;
96 typedef nspace::hash_map<std::string, chanrec*, nspace::hash<string>, StrHashComp> chan_hash;
97 typedef nspace::hash_map<in_addr,string*, nspace::hash<in_addr>, InAddr_HashComp> address_cache;
98 typedef nspace::hash_map<std::string, WhoWasUser*, nspace::hash<string>, StrHashComp> whowas_hash;
99 typedef std::deque<command_t> command_table;
100
101
102 extern user_hash clientlist;
103 extern chan_hash chanlist;
104 extern whowas_hash whowas;
105 extern command_table cmdlist;
106 extern file_cache MOTD;
107 extern file_cache RULES;
108 extern address_cache IP;
109
110 extern time_t TIME;
111
112 std::vector<KLine> klines;
113 std::vector<GLine> glines;
114 std::vector<ZLine> zlines;
115 std::vector<QLine> qlines;
116 std::vector<ELine> elines;
117
118 // Reads the default bans from the config file.
119 // only a very small number of bans are defined
120 // this way these days, such as qlines against 
121 // services nicks, etc.
122
123 void read_xline_defaults()
124 {
125         char ipmask[MAXBUF];
126         char nick[MAXBUF];
127         char host[MAXBUF];
128         char reason[MAXBUF];
129
130         for (int i = 0; i < ConfValueEnum("badip",&config_f); i++)
131         {
132                 ConfValue("badip","ipmask",i,ipmask,&config_f);
133                 ConfValue("badip","reason",i,reason,&config_f);
134                 add_zline(0,"<Config>",reason,ipmask);
135                 log(DEBUG,"Read Z line (badip tag): ipmask=%s reason=%s",ipmask,reason);
136         }
137         
138         for (int i = 0; i < ConfValueEnum("badnick",&config_f); i++)
139         {
140                 ConfValue("badnick","nick",i,nick,&config_f);
141                 ConfValue("badnick","reason",i,reason,&config_f);
142                 add_qline(0,"<Config>",reason,nick);
143                 log(DEBUG,"Read Q line (badnick tag): nick=%s reason=%s",nick,reason);
144         }
145         
146         for (int i = 0; i < ConfValueEnum("badhost",&config_f); i++)
147         {
148                 ConfValue("badhost","host",i,host,&config_f);
149                 ConfValue("badhost","reason",i,reason,&config_f);
150                 add_kline(0,"<Config>",reason,host);
151                 log(DEBUG,"Read K line (badhost tag): host=%s reason=%s",host,reason);
152         }
153         for (int i = 0; i < ConfValueEnum("exception",&config_f); i++)
154         {
155                 ConfValue("exception","host",i,host,&config_f);
156                 ConfValue("exception","reason",i,reason,&config_f);
157                 add_eline(0,"<Config>",reason,host);
158                 log(DEBUG,"Read E line (exception tag): host=%s reason=%s",host,reason);
159         }
160 }
161
162 // adds a g:line
163
164 void add_gline(long duration, const char* source,const char* reason,const char* hostmask)
165 {
166         del_gline(hostmask);
167         GLine item;
168         item.duration = duration;
169         strlcpy(item.hostmask,hostmask,199);
170         strlcpy(item.reason,reason,MAXBUF);
171         strlcpy(item.source,source,255);
172         item.n_matches = 0;
173         item.set_time = TIME;
174         glines.push_back(item);
175 }
176
177 // adds an e:line (exception to bans)
178
179 void add_eline(long duration, const char* source, const char* reason, const char* hostmask)
180 {
181         del_eline(hostmask);
182         ELine item;
183         item.duration = duration;
184         strlcpy(item.hostmask,hostmask,199);
185         strlcpy(item.reason,reason,MAXBUF);
186         strlcpy(item.source,source,255);
187         item.n_matches = 0;
188         item.set_time = TIME;
189         elines.push_back(item);
190 }
191
192 // adds a q:line
193
194 void add_qline(long duration, const char* source, const char* reason, const char* nickname)
195 {
196         del_qline(nickname);
197         QLine item;
198         item.duration = duration;
199         strlcpy(item.nick,nickname,63);
200         strlcpy(item.reason,reason,MAXBUF);
201         strlcpy(item.source,source,255);
202         item.n_matches = 0;
203         item.is_global = false;
204         item.set_time = TIME;
205         qlines.push_back(item);
206 }
207
208 // adds a z:line
209
210 void add_zline(long duration, const char* source, const char* reason, const char* ipaddr)
211 {
212         del_zline(ipaddr);
213         ZLine item;
214         item.duration = duration;
215         if (strchr(ipaddr,'@'))
216         {
217                 while (*ipaddr != '@')
218                         ipaddr++;
219                 ipaddr++;
220         }
221         strlcpy(item.ipaddr,ipaddr,39);
222         strlcpy(item.reason,reason,MAXBUF);
223         strlcpy(item.source,source,255);
224         item.n_matches = 0;
225         item.is_global = false;
226         item.set_time = TIME;
227         zlines.push_back(item);
228 }
229
230 // adds a k:line
231
232 void add_kline(long duration, const char* source, const char* reason, const char* hostmask)
233 {
234         del_kline(hostmask);
235         KLine item;
236         item.duration = duration;
237         strlcpy(item.hostmask,hostmask,200);
238         strlcpy(item.reason,reason,MAXBUF);
239         strlcpy(item.source,source,255);
240         item.n_matches = 0;
241         item.set_time = TIME;
242         klines.push_back(item);
243 }
244
245 // deletes a g:line, returns true if the line existed and was removed
246
247 bool del_gline(const char* hostmask)
248 {
249         for (std::vector<GLine>::iterator i = glines.begin(); i != glines.end(); i++)
250         {
251                 if (!strcasecmp(hostmask,i->hostmask))
252                 {
253                         glines.erase(i);
254                         return true;
255                 }
256         }
257         return false;
258 }
259
260 // deletes a e:line, returns true if the line existed and was removed
261
262 bool del_eline(const char* hostmask)
263 {
264         for (std::vector<ELine>::iterator i = elines.begin(); i != elines.end(); i++)
265         {
266                 if (!strcasecmp(hostmask,i->hostmask))
267                 {
268                         elines.erase(i);
269                         return true;
270                 }
271         }
272         return false;
273 }
274
275 // deletes a q:line, returns true if the line existed and was removed
276
277 bool del_qline(const char* nickname)
278 {
279         for (std::vector<QLine>::iterator i = qlines.begin(); i != qlines.end(); i++)
280         {
281                 if (!strcasecmp(nickname,i->nick))
282                 {
283                         qlines.erase(i);
284                         return true;
285                 }
286         }
287         return false;
288 }
289
290 bool qline_make_global(const char* nickname)
291 {
292         for (std::vector<QLine>::iterator i = qlines.begin(); i != qlines.end(); i++)
293         {
294                 if (!strcasecmp(nickname,i->nick))
295                 {
296                         i->is_global = true;
297                         return true;
298                 }
299         }
300         return false;
301 }
302
303 bool zline_make_global(const char* ipaddr)
304 {
305         for (std::vector<ZLine>::iterator i = zlines.begin(); i != zlines.end(); i++)
306         {
307                 if (!strcasecmp(ipaddr,i->ipaddr))
308                 {
309                         i->is_global = true;
310                         return true;
311                 }
312         }
313         return false;
314 }
315
316 void sync_xlines(serverrec* serv, char* tcp_host)
317 {
318         char data[MAXBUF];
319         
320         // for zlines and qlines, we should first check if theyre global...
321         for (std::vector<ZLine>::iterator i = zlines.begin(); i != zlines.end(); i++)
322         {
323                 if (i->is_global)
324                 {
325                         snprintf(data,MAXBUF,"%s } %s %s %lu %lu :%s",CreateSum().c_str(),i->ipaddr,i->source,(unsigned long)i->set_time,(unsigned long)i->duration,i->reason);
326                         serv->SendPacket(data,tcp_host);
327                 }
328         }
329         for (std::vector<QLine>::iterator i = qlines.begin(); i != qlines.end(); i++)
330         {
331                 if (i->is_global)
332                 {
333                         snprintf(data,MAXBUF,"%s { %s %s %lu %lu :%s",CreateSum().c_str(),i->nick,i->source,(unsigned long)i->set_time,(unsigned long)i->duration,i->reason);
334                         serv->SendPacket(data,tcp_host);
335                 }
336         }
337         // glines are always global, so no need to check
338         for (std::vector<GLine>::iterator i = glines.begin(); i != glines.end(); i++)
339         {
340                 snprintf(data,MAXBUF,"%s # %s %s %lu %lu :%s",CreateSum().c_str(),i->hostmask,i->source,(unsigned long)i->set_time,(unsigned long)i->duration,i->reason);
341                 serv->SendPacket(data,tcp_host);
342         }
343 }
344
345
346 // deletes a z:line, returns true if the line existed and was removed
347
348 bool del_zline(const char* ipaddr)
349 {
350         for (std::vector<ZLine>::iterator i = zlines.begin(); i != zlines.end(); i++)
351         {
352                 if (!strcasecmp(ipaddr,i->ipaddr))
353                 {
354                         zlines.erase(i);
355                         return true;
356                 }
357         }
358         return false;
359 }
360
361 // deletes a k:line, returns true if the line existed and was removed
362
363 bool del_kline(const char* hostmask)
364 {
365         for (std::vector<KLine>::iterator i = klines.begin(); i != klines.end(); i++)
366         {
367                 if (!strcasecmp(hostmask,i->hostmask))
368                 {
369                         klines.erase(i);
370                         return true;
371                 }
372         }
373         return false;
374 }
375
376 // returns a pointer to the reason if a nickname matches a qline, NULL if it didnt match
377
378 char* matches_qline(const char* nick)
379 {
380         if (qlines.empty())
381                 return NULL;
382         for (std::vector<QLine>::iterator i = qlines.begin(); i != qlines.end(); i++)
383         {
384                 if (match(nick,i->nick))
385                 {
386                         return i->reason;
387                 }
388         }
389         return NULL;
390 }
391
392 // returns a pointer to the reason if a host matches a gline, NULL if it didnt match
393
394 char* matches_gline(const char* host)
395 {
396         if (glines.empty())
397                 return NULL;
398         for (std::vector<GLine>::iterator i = glines.begin(); i != glines.end(); i++)
399         {
400                 if (match(host,i->hostmask))
401                 {
402                         return i->reason;
403                 }
404         }
405         return NULL;
406 }
407
408 char* matches_exception(const char* host)
409 {
410         if (elines.empty())
411                 return NULL;
412         char host2[MAXBUF];
413         snprintf(host2,MAXBUF,"*@%s",host);
414         for (std::vector<ELine>::iterator i = elines.begin(); i != elines.end(); i++)
415         {
416                 if ((match(host,i->hostmask)) || (match(host2,i->hostmask)))
417                 {
418                         return i->reason;
419                 }
420         }
421         return NULL;
422 }
423
424
425 void gline_set_creation_time(char* host, time_t create_time)
426 {
427         for (std::vector<GLine>::iterator i = glines.begin(); i != glines.end(); i++)
428         {
429                 if (!strcasecmp(host,i->hostmask))
430                 {
431                         i->set_time = create_time;
432                         return;
433                 }
434         }
435         return ;        
436 }
437
438 void qline_set_creation_time(char* nick, time_t create_time)
439 {
440         for (std::vector<QLine>::iterator i = qlines.begin(); i != qlines.end(); i++)
441         {
442                 if (!strcasecmp(nick,i->nick))
443                 {
444                         i->set_time = create_time;
445                         return;
446                 }
447         }
448         return ;        
449 }
450
451 void zline_set_creation_time(char* ip, time_t create_time)
452 {
453         for (std::vector<ZLine>::iterator i = zlines.begin(); i != zlines.end(); i++)
454         {
455                 if (!strcasecmp(ip,i->ipaddr))
456                 {
457                         i->set_time = create_time;
458                         return;
459                 }
460         }
461         return ;        
462 }
463
464 // returns a pointer to the reason if an ip address matches a zline, NULL if it didnt match
465
466 char* matches_zline(const char* ipaddr)
467 {
468         if (zlines.empty())
469                 return NULL;
470         for (std::vector<ZLine>::iterator i = zlines.begin(); i != zlines.end(); i++)
471         {
472                 if (match(ipaddr,i->ipaddr))
473                 {
474                         return i->reason;
475                 }
476         }
477         return NULL;
478 }
479
480 // returns a pointer to the reason if a host matches a kline, NULL if it didnt match
481
482 char* matches_kline(const char* host)
483 {
484         if (klines.empty())
485                 return NULL;
486         for (std::vector<KLine>::iterator i = klines.begin(); i != klines.end(); i++)
487         {
488                 if (match(host,i->hostmask))
489                 {
490                         return i->reason;
491                 }
492         }
493         return NULL;
494 }
495
496 // removes lines that have expired
497
498 void expire_lines()
499 {
500         bool go_again = true;
501         time_t current = TIME;
502         
503         // because we mess up an iterator when we remove from the vector, we must bail from
504         // the loop early if we delete an item, therefore this outer while loop is required.
505         while (go_again)
506         {
507                 go_again = false;
508
509                 for (std::vector<KLine>::iterator i = klines.begin(); i != klines.end(); i++)
510                 {
511                         if ((current > (i->duration + i->set_time)) && (i->duration > 0))
512                         {
513                                 WriteOpers("Expiring timed K-Line %s (set by %s %d seconds ago)",i->hostmask,i->source,i->duration);
514                                 klines.erase(i);
515                                 go_again = true;
516                                 break;
517                         }
518                 }
519
520                 for (std::vector<ELine>::iterator i = elines.begin(); i != elines.end(); i++)
521                 {
522                         if ((current > (i->duration + i->set_time)) && (i->duration > 0))
523                         {
524                                 WriteOpers("Expiring timed E-Line %s (set by %s %d seconds ago)",i->hostmask,i->source,i->duration);
525                                 elines.erase(i);
526                                 go_again = true;
527                                 break;
528                         }
529                 }
530
531                 for (std::vector<GLine>::iterator i = glines.begin(); i != glines.end(); i++)
532                 {
533                         if ((current > (i->duration + i->set_time)) && (i->duration > 0))
534                         {
535                                 WriteOpers("Expiring timed G-Line %s (set by %s %d seconds ago)",i->hostmask,i->source,i->duration);
536                                 glines.erase(i);
537                                 go_again = true;
538                                 break;
539                         }
540                 }
541
542                 for (std::vector<ZLine>::iterator i = zlines.begin(); i != zlines.end(); i++)
543                 {
544                         if ((current > (i->duration + i->set_time)) && (i->duration > 0))
545                         {
546                                 WriteOpers("Expiring timed Z-Line %s (set by %s %d seconds ago)",i->ipaddr,i->source,i->duration);
547                                 zlines.erase(i);
548                                 go_again = true;
549                                 break;
550                         }
551                 }
552
553                 for (std::vector<QLine>::iterator i = qlines.begin(); i != qlines.end(); i++)
554                 {
555                         if ((current > (i->duration + i->set_time)) && (i->duration > 0))
556                         {
557                                 WriteOpers("Expiring timed Q-Line %s (set by %s %d seconds ago)",i->nick,i->source,i->duration);
558                                 qlines.erase(i);
559                                 go_again = true;
560                                 break;
561                         }
562                 }
563         }
564 }
565
566 // applies lines, removing clients and changing nicks etc as applicable
567
568 void apply_lines()
569 {
570         bool go_again = true;
571         char reason[MAXBUF];
572         char host[MAXBUF];
573         
574         if ((!glines.size()) && (!klines.size()) && (!zlines.size()) && (!qlines.size()))
575                 return;
576         
577         while (go_again)
578         {
579                 go_again = false;
580                 for (user_hash::const_iterator u = clientlist.begin(); u != clientlist.end(); u++)
581                 {
582                         if (!strcasecmp(u->second->server,ServerName))
583                         {
584                                 snprintf(host,MAXBUF,"%s@%s",u->second->ident,u->second->host);
585                                 if (elines.size())
586                                 {
587                                         // ignore people matching exempts
588                                         if (matches_exception(host))
589                                                 continue;
590                                 }
591                                 if (glines.size())
592                                 {
593                                         char* check = matches_gline(host);
594                                         if (check)
595                                         {
596                                                 WriteOpers("*** User %s matches G-Line: %s",u->second->registered == 7 ? u->second->nick:"<unknown>",check);
597                                                 snprintf(reason,MAXBUF,"G-Lined: %s",check);
598                                                 kill_link(u->second,reason);
599                                                 go_again = true;
600                                                 break;
601                                         }
602                                 }
603                                 if (klines.size())
604                                 {
605                                         char* check = matches_kline(host);
606                                         if (check)
607                                         {
608                                                 WriteOpers("*** User %s matches K-Line: %s",u->second->registered == 7 ? u->second->nick:"<unknown>",check);
609                                                 snprintf(reason,MAXBUF,"K-Lined: %s",check);
610                                                 kill_link(u->second,reason);
611                                                 go_again = true;
612                                                 break;
613                                         }
614                                 }
615                                 if (qlines.size())
616                                 {
617                                         char* check = matches_qline(u->second->nick);
618                                         if (check)
619                                         {
620                                                 snprintf(reason,MAXBUF,"Matched Q-Lined nick: %s",check);
621                                                 WriteOpers("*** Q-Lined nickname %s from %s: %s",u->second->registered == 7 ? u->second->nick:"<unknown>",u->second->host,check);
622                                                 kill_link(u->second,reason);
623                                                 go_again = true;
624                                                 break;
625                                         }
626                                 }
627                                 if (zlines.size())
628                                 {
629                                         char* check = matches_zline(u->second->ip);
630                                         if (check)
631                                         {
632                                                 snprintf(reason,MAXBUF,"Z-Lined: %s",check);
633                                                 WriteOpers("*** User %s matches Z-Line: %s",u->second->registered == 7 ? u->second->nick:"<unknown>",u->second->host,check);
634                                                 kill_link(u->second,reason);
635                                                 go_again = true;
636                                                 break;
637                                         }
638                                 }
639                         }
640                 }
641         }
642 }
643
644 void stats_k(userrec* user)
645 {
646         for (std::vector<KLine>::iterator i = klines.begin(); i != klines.end(); i++)
647         {
648                 WriteServ(user->fd,"216 %s :%s %d %d %s %s",user->nick,i->hostmask,i->set_time,i->duration,i->source,i->reason);
649         }
650 }
651
652 void stats_g(userrec* user)
653 {
654         for (std::vector<GLine>::iterator i = glines.begin(); i != glines.end(); i++)
655         {
656                 WriteServ(user->fd,"223 %s :%s %d %d %s %s",user->nick,i->hostmask,i->set_time,i->duration,i->source,i->reason);
657         }
658 }
659
660 void stats_q(userrec* user)
661 {
662         for (std::vector<QLine>::iterator i = qlines.begin(); i != qlines.end(); i++)
663         {
664                 WriteServ(user->fd,"217 %s :%s %d %d %s %s",user->nick,i->nick,i->set_time,i->duration,i->source,i->reason);
665         }
666 }
667
668 void stats_z(userrec* user)
669 {
670         for (std::vector<ZLine>::iterator i = zlines.begin(); i != zlines.end(); i++)
671         {
672                 WriteServ(user->fd,"223 %s :%s %d %d %s %s",user->nick,i->ipaddr,i->set_time,i->duration,i->source,i->reason);
673         }
674 }
675
676 void stats_e(userrec* user)
677 {
678         for (std::vector<ELine>::iterator i = elines.begin(); i != elines.end(); i++)
679         {
680                 WriteServ(user->fd,"223 %s :%s %d %d %s %s",user->nick,i->hostmask,i->set_time,i->duration,i->source,i->reason);
681         }
682 }