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 * ---------------------------------------------------
18 #include "inspircd_io.h"
19 #include "inspircd_util.h"
20 #include "inspircd_config.h"
23 #include <sys/errno.h>
24 #include <sys/ioctl.h>
25 #include <sys/utsname.h>
30 #include <ext/hash_map>
42 #include "connection.h"
53 #include "inspstring.h"
54 #include "helperfuncs.h"
60 extern std::vector<Module*> modules;
61 extern std::vector<ircd_module*> factory;
64 extern char ServerName[MAXBUF];
65 extern char Network[MAXBUF];
66 extern char ServerDesc[MAXBUF];
67 extern char AdminName[MAXBUF];
68 extern char AdminEmail[MAXBUF];
69 extern char AdminNick[MAXBUF];
70 extern char diepass[MAXBUF];
71 extern char restartpass[MAXBUF];
72 extern char motd[MAXBUF];
73 extern char rules[MAXBUF];
74 extern char list[MAXBUF];
75 extern char PrefixQuit[MAXBUF];
76 extern char DieValue[MAXBUF];
79 extern int WHOWAS_STALE;
80 extern int WHOWAS_MAX;
82 extern time_t startup_time;
83 extern int NetBufferSize;
84 extern time_t nb_start;
86 extern std::vector<int> fd_reap;
87 extern std::vector<std::string> module_names;
89 extern int boundPortCount;
91 extern int SERVERportCount;
92 extern int ports[MAXSOCKS];
93 extern int defaultRoute;
95 extern std::vector<long> auth_cookies;
96 extern std::stringstream config_f;
98 extern serverrec* me[32];
100 extern FILE *log_file;
102 typedef nspace::hash_map<std::string, userrec*, nspace::hash<string>, StrHashComp> user_hash;
103 typedef nspace::hash_map<std::string, chanrec*, nspace::hash<string>, StrHashComp> chan_hash;
104 typedef nspace::hash_map<in_addr,string*, nspace::hash<in_addr>, InAddr_HashComp> address_cache;
105 typedef nspace::hash_map<std::string, WhoWasUser*, nspace::hash<string>, StrHashComp> whowas_hash;
106 typedef std::deque<command_t> command_table;
109 extern user_hash clientlist;
110 extern chan_hash chanlist;
111 extern whowas_hash whowas;
112 extern command_table cmdlist;
113 extern file_cache MOTD;
114 extern file_cache RULES;
115 extern address_cache IP;
119 std::vector<KLine> klines;
120 std::vector<GLine> glines;
121 std::vector<ZLine> zlines;
122 std::vector<QLine> qlines;
123 std::vector<ELine> elines;
125 // Reads the default bans from the config file.
126 // only a very small number of bans are defined
127 // this way these days, such as qlines against
128 // services nicks, etc.
130 void read_xline_defaults()
137 for (int i = 0; i < ConfValueEnum("badip",&config_f); i++)
139 ConfValue("badip","ipmask",i,ipmask,&config_f);
140 ConfValue("badip","reason",i,reason,&config_f);
141 add_zline(0,"<Config>",reason,ipmask);
142 log(DEBUG,"Read Z line (badip tag): ipmask=%s reason=%s",ipmask,reason);
145 for (int i = 0; i < ConfValueEnum("badnick",&config_f); i++)
147 ConfValue("badnick","nick",i,nick,&config_f);
148 ConfValue("badnick","reason",i,reason,&config_f);
149 add_qline(0,"<Config>",reason,nick);
150 log(DEBUG,"Read Q line (badnick tag): nick=%s reason=%s",nick,reason);
153 for (int i = 0; i < ConfValueEnum("badhost",&config_f); i++)
155 ConfValue("badhost","host",i,host,&config_f);
156 ConfValue("badhost","reason",i,reason,&config_f);
157 add_kline(0,"<Config>",reason,host);
158 log(DEBUG,"Read K line (badhost tag): host=%s reason=%s",host,reason);
160 for (int i = 0; i < ConfValueEnum("exception",&config_f); i++)
162 ConfValue("exception","host",i,host,&config_f);
163 ConfValue("exception","reason",i,reason,&config_f);
164 add_eline(0,"<Config>",reason,host);
165 log(DEBUG,"Read E line (exception tag): host=%s reason=%s",host,reason);
171 void add_gline(long duration, const char* source,const char* reason,const char* hostmask)
175 item.duration = duration;
176 strlcpy(item.hostmask,hostmask,199);
177 strlcpy(item.reason,reason,MAXBUF);
178 strlcpy(item.source,source,255);
180 item.set_time = TIME;
181 glines.push_back(item);
184 // adds an e:line (exception to bans)
186 void add_eline(long duration, const char* source, const char* reason, const char* hostmask)
190 item.duration = duration;
191 strlcpy(item.hostmask,hostmask,199);
192 strlcpy(item.reason,reason,MAXBUF);
193 strlcpy(item.source,source,255);
195 item.set_time = TIME;
196 elines.push_back(item);
201 void add_qline(long duration, const char* source, const char* reason, const char* nickname)
205 item.duration = duration;
206 strlcpy(item.nick,nickname,63);
207 strlcpy(item.reason,reason,MAXBUF);
208 strlcpy(item.source,source,255);
210 item.is_global = false;
211 item.set_time = TIME;
212 qlines.push_back(item);
217 void add_zline(long duration, const char* source, const char* reason, const char* ipaddr)
221 item.duration = duration;
222 if (strchr(ipaddr,'@'))
224 while (*ipaddr != '@')
228 strlcpy(item.ipaddr,ipaddr,39);
229 strlcpy(item.reason,reason,MAXBUF);
230 strlcpy(item.source,source,255);
232 item.is_global = false;
233 item.set_time = TIME;
234 zlines.push_back(item);
239 void add_kline(long duration, const char* source, const char* reason, const char* hostmask)
243 item.duration = duration;
244 strlcpy(item.hostmask,hostmask,200);
245 strlcpy(item.reason,reason,MAXBUF);
246 strlcpy(item.source,source,255);
248 item.set_time = TIME;
249 klines.push_back(item);
252 // deletes a g:line, returns true if the line existed and was removed
254 bool del_gline(const char* hostmask)
256 for (std::vector<GLine>::iterator i = glines.begin(); i != glines.end(); i++)
258 if (!strcasecmp(hostmask,i->hostmask))
267 // deletes a e:line, returns true if the line existed and was removed
269 bool del_eline(const char* hostmask)
271 for (std::vector<ELine>::iterator i = elines.begin(); i != elines.end(); i++)
273 if (!strcasecmp(hostmask,i->hostmask))
282 // deletes a q:line, returns true if the line existed and was removed
284 bool del_qline(const char* nickname)
286 for (std::vector<QLine>::iterator i = qlines.begin(); i != qlines.end(); i++)
288 if (!strcasecmp(nickname,i->nick))
297 bool qline_make_global(const char* nickname)
299 for (std::vector<QLine>::iterator i = qlines.begin(); i != qlines.end(); i++)
301 if (!strcasecmp(nickname,i->nick))
310 bool zline_make_global(const char* ipaddr)
312 for (std::vector<ZLine>::iterator i = zlines.begin(); i != zlines.end(); i++)
314 if (!strcasecmp(ipaddr,i->ipaddr))
323 void sync_xlines(serverrec* serv, char* tcp_host)
327 // for zlines and qlines, we should first check if theyre global...
328 for (std::vector<ZLine>::iterator i = zlines.begin(); i != zlines.end(); i++)
332 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);
333 serv->SendPacket(data,tcp_host);
336 for (std::vector<QLine>::iterator i = qlines.begin(); i != qlines.end(); i++)
340 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);
341 serv->SendPacket(data,tcp_host);
344 // glines are always global, so no need to check
345 for (std::vector<GLine>::iterator i = glines.begin(); i != glines.end(); i++)
347 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);
348 serv->SendPacket(data,tcp_host);
353 // deletes a z:line, returns true if the line existed and was removed
355 bool del_zline(const char* ipaddr)
357 for (std::vector<ZLine>::iterator i = zlines.begin(); i != zlines.end(); i++)
359 if (!strcasecmp(ipaddr,i->ipaddr))
368 // deletes a k:line, returns true if the line existed and was removed
370 bool del_kline(const char* hostmask)
372 for (std::vector<KLine>::iterator i = klines.begin(); i != klines.end(); i++)
374 if (!strcasecmp(hostmask,i->hostmask))
383 // returns a pointer to the reason if a nickname matches a qline, NULL if it didnt match
385 char* matches_qline(const char* nick)
389 for (std::vector<QLine>::iterator i = qlines.begin(); i != qlines.end(); i++)
391 if (match(nick,i->nick))
399 // returns a pointer to the reason if a host matches a gline, NULL if it didnt match
401 char* matches_gline(const char* host)
405 for (std::vector<GLine>::iterator i = glines.begin(); i != glines.end(); i++)
407 if (match(host,i->hostmask))
415 char* matches_exception(const char* host)
420 snprintf(host2,MAXBUF,"*@%s",host);
421 for (std::vector<ELine>::iterator i = elines.begin(); i != elines.end(); i++)
423 if ((match(host,i->hostmask)) || (match(host2,i->hostmask)))
432 void gline_set_creation_time(char* host, time_t create_time)
434 for (std::vector<GLine>::iterator i = glines.begin(); i != glines.end(); i++)
436 if (!strcasecmp(host,i->hostmask))
438 i->set_time = create_time;
445 void qline_set_creation_time(char* nick, time_t create_time)
447 for (std::vector<QLine>::iterator i = qlines.begin(); i != qlines.end(); i++)
449 if (!strcasecmp(nick,i->nick))
451 i->set_time = create_time;
458 void zline_set_creation_time(char* ip, time_t create_time)
460 for (std::vector<ZLine>::iterator i = zlines.begin(); i != zlines.end(); i++)
462 if (!strcasecmp(ip,i->ipaddr))
464 i->set_time = create_time;
471 // returns a pointer to the reason if an ip address matches a zline, NULL if it didnt match
473 char* matches_zline(const char* ipaddr)
477 for (std::vector<ZLine>::iterator i = zlines.begin(); i != zlines.end(); i++)
479 if (match(ipaddr,i->ipaddr))
487 // returns a pointer to the reason if a host matches a kline, NULL if it didnt match
489 char* matches_kline(const char* host)
493 for (std::vector<KLine>::iterator i = klines.begin(); i != klines.end(); i++)
495 if (match(host,i->hostmask))
503 // removes lines that have expired
507 bool go_again = true;
508 time_t current = TIME;
510 // because we mess up an iterator when we remove from the vector, we must bail from
511 // the loop early if we delete an item, therefore this outer while loop is required.
516 for (std::vector<KLine>::iterator i = klines.begin(); i != klines.end(); i++)
518 if ((current > (i->duration + i->set_time)) && (i->duration > 0))
520 WriteOpers("Expiring timed K-Line %s (set by %s %d seconds ago)",i->hostmask,i->source,i->duration);
527 for (std::vector<ELine>::iterator i = elines.begin(); i != elines.end(); i++)
529 if ((current > (i->duration + i->set_time)) && (i->duration > 0))
531 WriteOpers("Expiring timed E-Line %s (set by %s %d seconds ago)",i->hostmask,i->source,i->duration);
538 for (std::vector<GLine>::iterator i = glines.begin(); i != glines.end(); i++)
540 if ((current > (i->duration + i->set_time)) && (i->duration > 0))
542 WriteOpers("Expiring timed G-Line %s (set by %s %d seconds ago)",i->hostmask,i->source,i->duration);
549 for (std::vector<ZLine>::iterator i = zlines.begin(); i != zlines.end(); i++)
551 if ((current > (i->duration + i->set_time)) && (i->duration > 0))
553 WriteOpers("Expiring timed Z-Line %s (set by %s %d seconds ago)",i->ipaddr,i->source,i->duration);
560 for (std::vector<QLine>::iterator i = qlines.begin(); i != qlines.end(); i++)
562 if ((current > (i->duration + i->set_time)) && (i->duration > 0))
564 WriteOpers("Expiring timed Q-Line %s (set by %s %d seconds ago)",i->nick,i->source,i->duration);
573 // applies lines, removing clients and changing nicks etc as applicable
577 bool go_again = true;
581 if ((!glines.size()) && (!klines.size()) && (!zlines.size()) && (!qlines.size()))
587 for (user_hash::const_iterator u = clientlist.begin(); u != clientlist.end(); u++)
589 if (!strcasecmp(u->second->server,ServerName))
591 snprintf(host,MAXBUF,"%s@%s",u->second->ident,u->second->host);
594 // ignore people matching exempts
595 if (matches_exception(host))
600 char* check = matches_gline(host);
603 WriteOpers("*** User %s matches G-Line: %s",u->second->registered == 7 ? u->second->nick:"<unknown>",check);
604 snprintf(reason,MAXBUF,"G-Lined: %s",check);
605 kill_link(u->second,reason);
612 char* check = matches_kline(host);
615 WriteOpers("*** User %s matches K-Line: %s",u->second->registered == 7 ? u->second->nick:"<unknown>",check);
616 snprintf(reason,MAXBUF,"K-Lined: %s",check);
617 kill_link(u->second,reason);
624 char* check = matches_qline(u->second->nick);
627 snprintf(reason,MAXBUF,"Matched Q-Lined nick: %s",check);
628 WriteOpers("*** Q-Lined nickname %s from %s: %s",u->second->registered == 7 ? u->second->nick:"<unknown>",u->second->host,check);
629 kill_link(u->second,reason);
636 char* check = matches_zline(u->second->ip);
639 snprintf(reason,MAXBUF,"Z-Lined: %s",check);
640 WriteOpers("*** User %s matches Z-Line: %s",u->second->registered == 7 ? u->second->nick:"<unknown>",u->second->host,check);
641 kill_link(u->second,reason);
651 void stats_k(userrec* user)
653 for (std::vector<KLine>::iterator i = klines.begin(); i != klines.end(); i++)
655 WriteServ(user->fd,"216 %s :%s %d %d %s %s",user->nick,i->hostmask,i->set_time,i->duration,i->source,i->reason);
659 void stats_g(userrec* user)
661 for (std::vector<GLine>::iterator i = glines.begin(); i != glines.end(); i++)
663 WriteServ(user->fd,"223 %s :%s %d %d %s %s",user->nick,i->hostmask,i->set_time,i->duration,i->source,i->reason);
667 void stats_q(userrec* user)
669 for (std::vector<QLine>::iterator i = qlines.begin(); i != qlines.end(); i++)
671 WriteServ(user->fd,"217 %s :%s %d %d %s %s",user->nick,i->nick,i->set_time,i->duration,i->source,i->reason);
675 void stats_z(userrec* user)
677 for (std::vector<ZLine>::iterator i = zlines.begin(); i != zlines.end(); i++)
679 WriteServ(user->fd,"223 %s :%s %d %d %s %s",user->nick,i->ipaddr,i->set_time,i->duration,i->source,i->reason);
683 void stats_e(userrec* user)
685 for (std::vector<ELine>::iterator i = elines.begin(); i != elines.end(); i++)
687 WriteServ(user->fd,"223 %s :%s %d %d %s %s",user->nick,i->hostmask,i->set_time,i->duration,i->source,i->reason);