1 /* +------------------------------------+
2 * | Inspire Internet Relay Chat Daemon |
3 * +------------------------------------+
5 * Inspire is copyright (C) 2002-2004 ChatSpike-Dev.
7 * <brain@chatspike.net>
8 * <Craig@chatspike.net>
10 * Written by Craig Edwards, Craig McLure, and others.
11 * This program is free but copyrighted software; see
12 * the file COPYING for details.
14 * ---------------------------------------------------
19 #include "inspircd_config.h"
21 #include "inspircd_io.h"
22 #include "inspircd_util.h"
25 #include <sys/errno.h>
29 #include <ext/hash_map>
46 #include "inspstring.h"
47 #include "helperfuncs.h"
51 extern std::vector<Module*> modules;
52 extern std::vector<ircd_module*> factory;
53 extern ServerConfig* Config;
54 extern std::stringstream config_f;
55 typedef nspace::hash_map<std::string, userrec*, nspace::hash<string>, irc::StrHashComp> user_hash;
56 extern user_hash clientlist;
58 /* Version two, now with optimized expiry!
60 * Because the old way was horrendously slow, the new way of expiring xlines is very
61 * very efficient. I have improved the efficiency of the algorithm in two ways:
63 * (1) There are now two lists of items for each linetype. One list holds temporary
64 * items, and the other list holds permenant items (ones which will expire).
65 * Items which are on the permenant list are NEVER checked at all by the
66 * expire_lines() function.
67 * (2) The temporary xline lists are always kept in strict numerical order, keyed by
68 * current time + duration. This means that the line which is due to expire the
69 * soonest is always pointed at by vector::begin(), so a simple while loop can
70 * very efficiently, very quickly and above all SAFELY pick off the first few
71 * items in the vector which need zapping.
80 /* Lists for temporary lines with an expiry time */
82 std::vector<KLine> klines;
83 std::vector<GLine> glines;
84 std::vector<ZLine> zlines;
85 std::vector<QLine> qlines;
86 std::vector<ELine> elines;
88 /* Seperate lists for perm XLines that isnt checked by expiry functions */
90 std::vector<KLine> pklines;
91 std::vector<GLine> pglines;
92 std::vector<ZLine> pzlines;
93 std::vector<QLine> pqlines;
94 std::vector<ELine> pelines;
97 bool GSortComparison ( const GLine one, const GLine two );
98 bool ZSortComparison ( const ZLine one, const ZLine two );
99 bool ESortComparison ( const ELine one, const ELine two );
100 bool QSortComparison ( const QLine one, const QLine two );
101 bool KSortComparison ( const KLine one, const KLine two );
103 // Reads the default bans from the config file.
104 // only a very small number of bans are defined
105 // this way these days, such as qlines against
106 // services nicks, etc.
108 void read_xline_defaults()
115 for (int i = 0; i < ConfValueEnum("badip",&config_f); i++)
117 ConfValue("badip","ipmask",i,ipmask,&config_f);
118 ConfValue("badip","reason",i,reason,&config_f);
119 add_zline(0,"<Config>",reason,ipmask);
120 log(DEBUG,"Read Z line (badip tag): ipmask=%s reason=%s",ipmask,reason);
123 for (int i = 0; i < ConfValueEnum("badnick",&config_f); i++)
125 ConfValue("badnick","nick",i,nick,&config_f);
126 ConfValue("badnick","reason",i,reason,&config_f);
127 add_qline(0,"<Config>",reason,nick);
128 log(DEBUG,"Read Q line (badnick tag): nick=%s reason=%s",nick,reason);
131 for (int i = 0; i < ConfValueEnum("badhost",&config_f); i++)
133 ConfValue("badhost","host",i,host,&config_f);
134 ConfValue("badhost","reason",i,reason,&config_f);
135 add_kline(0,"<Config>",reason,host);
136 log(DEBUG,"Read K line (badhost tag): host=%s reason=%s",host,reason);
138 for (int i = 0; i < ConfValueEnum("exception",&config_f); i++)
140 ConfValue("exception","host",i,host,&config_f);
141 ConfValue("exception","reason",i,reason,&config_f);
142 add_eline(0,"<Config>",reason,host);
143 log(DEBUG,"Read E line (exception tag): host=%s reason=%s",host,reason);
149 void add_gline(long duration, const char* source,const char* reason,const char* hostmask)
153 item.duration = duration;
154 strlcpy(item.hostmask,hostmask,199);
155 strlcpy(item.reason,reason,MAXBUF);
156 strlcpy(item.source,source,255);
158 item.set_time = TIME;
161 glines.push_back(item);
162 sort(glines.begin(), glines.end(),GSortComparison);
166 pglines.push_back(item);
170 // adds an e:line (exception to bans)
172 void add_eline(long duration, const char* source, const char* reason, const char* hostmask)
176 item.duration = duration;
177 strlcpy(item.hostmask,hostmask,199);
178 strlcpy(item.reason,reason,MAXBUF);
179 strlcpy(item.source,source,255);
181 item.set_time = TIME;
184 elines.push_back(item);
185 sort(elines.begin(), elines.end(),ESortComparison);
189 pelines.push_back(item);
195 void add_qline(long duration, const char* source, const char* reason, const char* nickname)
199 item.duration = duration;
200 strlcpy(item.nick,nickname,63);
201 strlcpy(item.reason,reason,MAXBUF);
202 strlcpy(item.source,source,255);
204 item.is_global = false;
205 item.set_time = TIME;
208 qlines.push_back(item);
209 sort(qlines.begin(), qlines.end(),QSortComparison);
213 pqlines.push_back(item);
219 void add_zline(long duration, const char* source, const char* reason, const char* ipaddr)
223 item.duration = duration;
224 if (strchr(ipaddr,'@'))
226 while (*ipaddr != '@')
230 strlcpy(item.ipaddr,ipaddr,39);
231 strlcpy(item.reason,reason,MAXBUF);
232 strlcpy(item.source,source,255);
234 item.is_global = false;
235 item.set_time = TIME;
238 zlines.push_back(item);
239 sort(zlines.begin(), zlines.end(),ZSortComparison);
243 pzlines.push_back(item);
249 void add_kline(long duration, const char* source, const char* reason, const char* hostmask)
253 item.duration = duration;
254 strlcpy(item.hostmask,hostmask,200);
255 strlcpy(item.reason,reason,MAXBUF);
256 strlcpy(item.source,source,255);
258 item.set_time = TIME;
261 klines.push_back(item);
262 sort(klines.begin(), klines.end(),KSortComparison);
266 pklines.push_back(item);
270 // deletes a g:line, returns true if the line existed and was removed
272 bool del_gline(const char* hostmask)
274 for (std::vector<GLine>::iterator i = glines.begin(); i != glines.end(); i++)
276 if (!strcasecmp(hostmask,i->hostmask))
282 for (std::vector<GLine>::iterator i = pglines.begin(); i != pglines.end(); i++)
284 if (!strcasecmp(hostmask,i->hostmask))
293 // deletes a e:line, returns true if the line existed and was removed
295 bool del_eline(const char* hostmask)
297 for (std::vector<ELine>::iterator i = elines.begin(); i != elines.end(); i++)
299 if (!strcasecmp(hostmask,i->hostmask))
305 for (std::vector<ELine>::iterator i = pelines.begin(); i != pelines.end(); i++)
307 if (!strcasecmp(hostmask,i->hostmask))
316 // deletes a q:line, returns true if the line existed and was removed
318 bool del_qline(const char* nickname)
320 for (std::vector<QLine>::iterator i = qlines.begin(); i != qlines.end(); i++)
322 if (!strcasecmp(nickname,i->nick))
328 for (std::vector<QLine>::iterator i = pqlines.begin(); i != pqlines.end(); i++)
330 if (!strcasecmp(nickname,i->nick))
339 bool qline_make_global(const char* nickname)
341 for (std::vector<QLine>::iterator i = qlines.begin(); i != qlines.end(); i++)
343 if (!strcasecmp(nickname,i->nick))
352 bool zline_make_global(const char* ipaddr)
354 for (std::vector<ZLine>::iterator i = zlines.begin(); i != zlines.end(); i++)
356 if (!strcasecmp(ipaddr,i->ipaddr))
365 // deletes a z:line, returns true if the line existed and was removed
367 bool del_zline(const char* ipaddr)
369 for (std::vector<ZLine>::iterator i = zlines.begin(); i != zlines.end(); i++)
371 if (!strcasecmp(ipaddr,i->ipaddr))
377 for (std::vector<ZLine>::iterator i = pzlines.begin(); i != pzlines.end(); i++)
379 if (!strcasecmp(ipaddr,i->ipaddr))
388 // deletes a k:line, returns true if the line existed and was removed
390 bool del_kline(const char* hostmask)
392 for (std::vector<KLine>::iterator i = klines.begin(); i != klines.end(); i++)
394 if (!strcasecmp(hostmask,i->hostmask))
400 for (std::vector<KLine>::iterator i = pklines.begin(); i != pklines.end(); i++)
402 if (!strcasecmp(hostmask,i->hostmask))
411 // returns a pointer to the reason if a nickname matches a qline, NULL if it didnt match
413 char* matches_qline(const char* nick)
415 if ((qlines.empty()) && (pqlines.empty()))
417 for (std::vector<QLine>::iterator i = qlines.begin(); i != qlines.end(); i++)
418 if (match(nick,i->nick))
420 for (std::vector<QLine>::iterator i = pqlines.begin(); i != pqlines.end(); i++)
421 if (match(nick,i->nick))
426 // returns a pointer to the reason if a host matches a gline, NULL if it didnt match
428 char* matches_gline(const char* host)
430 if ((glines.empty()) && (pglines.empty()))
432 for (std::vector<GLine>::iterator i = glines.begin(); i != glines.end(); i++)
433 if (match(host,i->hostmask))
435 for (std::vector<GLine>::iterator i = pglines.begin(); i != pglines.end(); i++)
436 if (match(host,i->hostmask))
441 char* matches_exception(const char* host)
443 if ((elines.empty()) && (pelines.empty()))
446 snprintf(host2,MAXBUF,"*@%s",host);
447 for (std::vector<ELine>::iterator i = elines.begin(); i != elines.end(); i++)
448 if ((match(host,i->hostmask)) || (match(host2,i->hostmask)))
450 for (std::vector<ELine>::iterator i = pelines.begin(); i != pelines.end(); i++)
451 if ((match(host,i->hostmask)) || (match(host2,i->hostmask)))
457 void gline_set_creation_time(char* host, time_t create_time)
459 for (std::vector<GLine>::iterator i = glines.begin(); i != glines.end(); i++)
461 if (!strcasecmp(host,i->hostmask))
463 i->set_time = create_time;
467 for (std::vector<GLine>::iterator i = pglines.begin(); i != pglines.end(); i++)
469 if (!strcasecmp(host,i->hostmask))
471 i->set_time = create_time;
478 void eline_set_creation_time(char* host, time_t create_time)
480 for (std::vector<ELine>::iterator i = elines.begin(); i != elines.end(); i++)
482 if (!strcasecmp(host,i->hostmask))
484 i->set_time = create_time;
488 for (std::vector<ELine>::iterator i = pelines.begin(); i != pelines.end(); i++)
490 if (!strcasecmp(host,i->hostmask))
492 i->set_time = create_time;
499 void qline_set_creation_time(char* nick, time_t create_time)
501 for (std::vector<QLine>::iterator i = qlines.begin(); i != qlines.end(); i++)
503 if (!strcasecmp(nick,i->nick))
505 i->set_time = create_time;
509 for (std::vector<QLine>::iterator i = pqlines.begin(); i != pqlines.end(); i++)
511 if (!strcasecmp(nick,i->nick))
513 i->set_time = create_time;
520 void zline_set_creation_time(char* ip, time_t create_time)
522 for (std::vector<ZLine>::iterator i = zlines.begin(); i != zlines.end(); i++)
524 if (!strcasecmp(ip,i->ipaddr))
526 i->set_time = create_time;
530 for (std::vector<ZLine>::iterator i = pzlines.begin(); i != pzlines.end(); i++)
532 if (!strcasecmp(ip,i->ipaddr))
534 i->set_time = create_time;
541 // returns a pointer to the reason if an ip address matches a zline, NULL if it didnt match
543 char* matches_zline(const char* ipaddr)
545 if ((zlines.empty()) && (pzlines.empty()))
547 for (std::vector<ZLine>::iterator i = zlines.begin(); i != zlines.end(); i++)
548 if (match(ipaddr,i->ipaddr))
550 for (std::vector<ZLine>::iterator i = pzlines.begin(); i != pzlines.end(); i++)
551 if (match(ipaddr,i->ipaddr))
556 // returns a pointer to the reason if a host matches a kline, NULL if it didnt match
558 char* matches_kline(const char* host)
560 if ((klines.empty()) && (pklines.empty()))
562 for (std::vector<KLine>::iterator i = klines.begin(); i != klines.end(); i++)
563 if (match(host,i->hostmask))
565 for (std::vector<KLine>::iterator i = pklines.begin(); i != pklines.end(); i++)
566 if (match(host,i->hostmask))
571 bool GSortComparison ( const GLine one, const GLine two )
573 return (one.duration + one.set_time) < (two.duration + two.set_time);
576 bool ESortComparison ( const ELine one, const ELine two )
578 return (one.duration + one.set_time) < (two.duration + two.set_time);
581 bool ZSortComparison ( const ZLine one, const ZLine two )
583 return (one.duration + one.set_time) < (two.duration + two.set_time);
586 bool KSortComparison ( const KLine one, const KLine two )
588 return (one.duration + one.set_time) < (two.duration + two.set_time);
591 bool QSortComparison ( const QLine one, const QLine two )
593 return (one.duration + one.set_time) < (two.duration + two.set_time);
596 // removes lines that have expired
600 time_t current = TIME;
602 /* Because we now store all our XLines in sorted order using (i->duration + i->set_time) as a key, this
603 * means that to expire the XLines we just need to do a while, picking off the top few until there are
604 * none left at the head of the queue that are after the current time.
607 while ((glines.size()) && (current > (glines.begin()->duration + glines.begin()->set_time)))
609 std::vector<GLine>::iterator i = glines.begin();
610 WriteOpers("Expiring timed G-Line %s (set by %s %d seconds ago)",i->hostmask,i->source,i->duration);
614 while ((elines.size()) && (current > (elines.begin()->duration + elines.begin()->set_time)))
616 std::vector<ELine>::iterator i = elines.begin();
617 WriteOpers("Expiring timed E-Line %s (set by %s %d seconds ago)",i->hostmask,i->source,i->duration);
621 while ((zlines.size()) && (current > (zlines.begin()->duration + zlines.begin()->set_time)))
623 std::vector<ZLine>::iterator i = zlines.begin();
624 WriteOpers("Expiring timed Z-Line %s (set by %s %d seconds ago)",i->ipaddr,i->source,i->duration);
628 while ((klines.size()) && (current > (klines.begin()->duration + klines.begin()->set_time)))
630 std::vector<KLine>::iterator i = klines.begin();
631 WriteOpers("Expiring timed K-Line %s (set by %s %d seconds ago)",i->hostmask,i->source,i->duration);
635 while ((qlines.size()) && (current > (qlines.begin()->duration + qlines.begin()->set_time)))
637 std::vector<QLine>::iterator i = qlines.begin();
638 WriteOpers("Expiring timed Q-Line %s (set by %s %d seconds ago)",i->nick,i->source,i->duration);
644 // applies lines, removing clients and changing nicks etc as applicable
646 void apply_lines(const int What)
648 bool go_again = true;
652 if ((!glines.size()) && (!klines.size()) && (!zlines.size()) && (!qlines.size()))
658 for (user_hash::const_iterator u = clientlist.begin(); u != clientlist.end(); u++)
660 if (u->second->fd > -1)
662 snprintf(host,MAXBUF,"%s@%s",u->second->ident,u->second->host);
665 // ignore people matching exempts
666 if (matches_exception(host))
669 if ((What & APPLY_GLINES) && (glines.size() || pglines.size()))
671 char* check = matches_gline(host);
674 WriteOpers("*** User %s matches G-Line: %s",u->second->registered == 7 ? u->second->nick:"<unknown>",check);
675 snprintf(reason,MAXBUF,"G-Lined: %s",check);
676 kill_link(u->second,reason);
681 if ((What & APPLY_KLINES) && (klines.size() || pklines.size()))
683 char* check = matches_kline(host);
686 WriteOpers("*** User %s matches K-Line: %s",u->second->registered == 7 ? u->second->nick:"<unknown>",check);
687 snprintf(reason,MAXBUF,"K-Lined: %s",check);
688 kill_link(u->second,reason);
693 if ((What & APPLY_QLINES) && (qlines.size() || pqlines.size()))
695 char* check = matches_qline(u->second->nick);
698 snprintf(reason,MAXBUF,"Matched Q-Lined nick: %s",check);
699 WriteOpers("*** Q-Lined nickname %s from %s: %s",u->second->registered == 7 ? u->second->nick:"<unknown>",u->second->host,check);
700 kill_link(u->second,reason);
705 if ((What & APPLY_ZLINES) && (zlines.size() || pzlines.size()))
707 char* check = matches_zline(u->second->ip);
710 snprintf(reason,MAXBUF,"Z-Lined: %s",check);
711 WriteOpers("*** User %s matches Z-Line: %s",u->second->registered == 7 ? u->second->nick:"<unknown>",u->second->host,check);
712 kill_link(u->second,reason);
722 void stats_k(userrec* user)
724 for (std::vector<KLine>::iterator i = klines.begin(); i != klines.end(); i++)
725 WriteServ(user->fd,"216 %s :%s %d %d %s %s",user->nick,i->hostmask,i->set_time,i->duration,i->source,i->reason);
726 for (std::vector<KLine>::iterator i = pklines.begin(); i != pklines.end(); i++)
727 WriteServ(user->fd,"216 %s :%s %d %d %s %s",user->nick,i->hostmask,i->set_time,i->duration,i->source,i->reason);
730 void stats_g(userrec* user)
732 for (std::vector<GLine>::iterator i = glines.begin(); i != glines.end(); i++)
733 WriteServ(user->fd,"223 %s :%s %d %d %s %s",user->nick,i->hostmask,i->set_time,i->duration,i->source,i->reason);
734 for (std::vector<GLine>::iterator i = pglines.begin(); i != pglines.end(); i++)
735 WriteServ(user->fd,"223 %s :%s %d %d %s %s",user->nick,i->hostmask,i->set_time,i->duration,i->source,i->reason);
738 void stats_q(userrec* user)
740 for (std::vector<QLine>::iterator i = qlines.begin(); i != qlines.end(); i++)
741 WriteServ(user->fd,"217 %s :%s %d %d %s %s",user->nick,i->nick,i->set_time,i->duration,i->source,i->reason);
742 for (std::vector<QLine>::iterator i = pqlines.begin(); i != pqlines.end(); i++)
743 WriteServ(user->fd,"217 %s :%s %d %d %s %s",user->nick,i->nick,i->set_time,i->duration,i->source,i->reason);
746 void stats_z(userrec* user)
748 for (std::vector<ZLine>::iterator i = zlines.begin(); i != zlines.end(); i++)
749 WriteServ(user->fd,"223 %s :%s %d %d %s %s",user->nick,i->ipaddr,i->set_time,i->duration,i->source,i->reason);
750 for (std::vector<ZLine>::iterator i = pzlines.begin(); i != pzlines.end(); i++)
751 WriteServ(user->fd,"223 %s :%s %d %d %s %s",user->nick,i->ipaddr,i->set_time,i->duration,i->source,i->reason);
754 void stats_e(userrec* user)
756 for (std::vector<ELine>::iterator i = elines.begin(); i != elines.end(); i++)
757 WriteServ(user->fd,"223 %s :%s %d %d %s %s",user->nick,i->hostmask,i->set_time,i->duration,i->source,i->reason);
758 for (std::vector<ELine>::iterator i = pelines.begin(); i != pelines.end(); i++)
759 WriteServ(user->fd,"223 %s :%s %d %d %s %s",user->nick,i->hostmask,i->set_time,i->duration,i->source,i->reason);