#include <sys/errno.h>
#include <sys/ioctl.h>
#include <sys/utsname.h>
-
-#ifdef USE_KQUEUE
-#include <sys/types.h>
-#include <sys/event.h>
-#include <sys/time.h>
-#endif
-
-#ifdef USE_EPOLL
-#include <sys/epoll.h>
-#endif
-
#include <cstdio>
#include <time.h>
#include <string>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/resource.h>
+#ifdef THREADED_DNS
+#include <pthread.h>
+#endif
#ifndef RUSAGE_SELF
#define RUSAGE_SELF 0
#define RUSAGE_CHILDREN -1
#include "dynamic.h"
#include "wildcard.h"
#include "message.h"
+#include "commands.h"
#include "mode.h"
#include "xline.h"
#include "inspstring.h"
#include "dnsqueue.h"
#include "helperfuncs.h"
#include "hashcomp.h"
+#include "socketengine.h"
+#include "typedefs.h"
-#ifdef USE_KQUEUE
-extern int kq;
-#endif
-
-#ifdef USE_EPOLL
-int ep;
-#endif
+extern SocketEngine* SE;
+extern ServerConfig* Config;
extern int MODCOUNT;
extern std::vector<Module*> modules;
extern std::vector<ircd_module*> factory;
-
-extern int LogLevel;
-extern char ServerName[MAXBUF];
-extern char Network[MAXBUF];
-extern char ServerDesc[MAXBUF];
-extern char AdminName[MAXBUF];
-extern char AdminEmail[MAXBUF];
-extern char AdminNick[MAXBUF];
-extern char diepass[MAXBUF];
-extern char restartpass[MAXBUF];
-extern char motd[MAXBUF];
-extern char rules[MAXBUF];
-extern char list[MAXBUF];
-extern char PrefixQuit[MAXBUF];
-extern char DieValue[MAXBUF];
-
-extern int debugging;
extern int WHOWAS_STALE;
extern int WHOWAS_MAX;
-extern int DieDelay;
extern time_t startup_time;
-extern int NetBufferSize;
-extern int MaxWhoResults;
-extern time_t nb_start;
-
-extern bool nofork;
-
extern time_t TIME;
-extern std::vector<std::string> module_names;
-
-extern char MyExecutable[1024];
-extern int boundPortCount;
-extern int portCount;
-
-extern int ports[MAXSOCKS];
-
-extern std::stringstream config_f;
-
-
-
-extern FILE *log_file;
-
-extern ClassVector Classes;
-
const long duration_m = 60;
const long duration_h = duration_m * 60;
const long duration_d = duration_h * 24;
const long duration_w = duration_d * 7;
const long duration_y = duration_w * 52;
-typedef nspace::hash_map<std::string, userrec*, nspace::hash<string>, irc::StrHashComp> user_hash;
-typedef nspace::hash_map<std::string, chanrec*, nspace::hash<string>, irc::StrHashComp> chan_hash;
-typedef nspace::hash_map<in_addr,string*, nspace::hash<in_addr>, irc::InAddr_HashComp> address_cache;
-typedef nspace::hash_map<std::string, WhoWasUser*, nspace::hash<string>, irc::StrHashComp> whowas_hash;
-typedef std::deque<command_t> command_table;
-
-
extern user_hash clientlist;
extern chan_hash chanlist;
extern whowas_hash whowas;
extern command_table cmdlist;
-extern file_cache MOTD;
-extern file_cache RULES;
extern address_cache IP;
extern std::vector<userrec*> all_opers;
// by an integer, meaning there is no need for a scan/search operation.
extern userrec* fd_ref_table[65536];
-extern int statsAccept,statsRefused,statsUnknown,statsCollisions,statsDns,statsDnsGood,statsDnsBad,statsConnects,statsSent,statsRecv;
+extern serverstats* stats;
void handle_join(char **parameters, int pcnt, userrec *user)
{
return;
}
- if (!has_channel(user,Ptr))
+ if ((!has_channel(user,Ptr)) && (!is_uline(user->server)))
{
WriteServ(user->fd,"442 %s %s :You're not on that channel!",user->nick, parameters[0]);
return;
void handle_die(char **parameters, int pcnt, userrec *user)
{
log(DEBUG,"die: %s",user->nick);
- if (!strcmp(parameters[0],diepass))
+ if (!strcmp(parameters[0],Config->diepass))
{
WriteOpers("*** DIE command from %s!%s@%s, terminating...",user->nick,user->ident,user->host);
- sleep(DieDelay);
+ sleep(Config->DieDelay);
Exit(ERROR);
}
else
{
char *argv[32];
log(DEFAULT,"Restart: %s",user->nick);
- if (!strcmp(parameters[0],restartpass))
+ if (!strcmp(parameters[0],Config->restartpass))
{
WriteOpers("*** RESTART command from %s!%s@%s, restarting server.",user->nick,user->ident,user->host);
- argv[0] = MyExecutable;
+ argv[0] = Config->MyExecutable;
argv[1] = "-wait";
- if (nofork)
+ if (Config->nofork)
{
argv[2] = "-nofork";
}
}
sleep(2);
- execv(MyExecutable,argv);
+ execv(Config->MyExecutable,argv);
exit(0);
}
return;
}
- if (strcmp(ServerName,u->server))
+ if (u->fd < 0)
{
// remote kill
WriteOpers("*** Remote kill by %s: %s!%s@%s (%s)",user->nick,u->nick,u->ident,u->host,parameters[1]);
- snprintf(killreason,MAXBUF,"[%s] Killed (%s (%s))",ServerName,user->nick,parameters[1]);
+ snprintf(killreason,MAXBUF,"[%s] Killed (%s (%s))",Config->ServerName,user->nick,parameters[1]);
WriteCommonExcept(u,"QUIT :%s",killreason);
FOREACH_MOD OnRemoteKill(user,u,killreason);
else
{
// local kill
- log(DEFAULT,"LOCAL KILL: %s :%s!%s!%s (%s)", u->nick, ServerName,user->dhost,user->nick,parameters[1]);
- WriteTo(user, u, "KILL %s :%s!%s!%s (%s)", u->nick, ServerName,user->dhost,user->nick,parameters[1]);
+ log(DEFAULT,"LOCAL KILL: %s :%s!%s!%s (%s)", u->nick, Config->ServerName,user->dhost,user->nick,parameters[1]);
+ WriteTo(user, u, "KILL %s :%s!%s!%s (%s)", u->nick, Config->ServerName,user->dhost,user->nick,parameters[1]);
WriteOpers("*** Local Kill by %s: %s!%s@%s (%s)",user->nick,u->nick,u->ident,u->host,parameters[1]);
snprintf(killreason,MAXBUF,"Killed (%s (%s))",user->nick,parameters[1]);
kill_link(u,killreason);
{
if (((Ptr) && (!has_channel(user,Ptr))) && (Ptr->binarymodes & CM_SECRET))
{
- WriteServ(user->fd,"442 %s %s :You're not on that channel!",user->nick, Ptr->name);
+ WriteServ(user->fd,"401 %s %s :No such nick/channel",user->nick, Ptr->name);
return;
}
if (Ptr->topicset)
topic[MAXTOPIC] = '\0';
}
- if (!strcasecmp(user->server,ServerName))
+ if (user->fd > -1)
{
int MOD_RESULT = 0;
FOREACH_RESULT(OnLocalTopicChange(user,Ptr,topic));
strlcpy(Ptr->setby,user->nick,NICKMAX);
Ptr->topicset = TIME;
WriteChannel(Ptr,user,"TOPIC %s :%s",Ptr->name, Ptr->topic);
- if (!strcasecmp(user->server,ServerName))
+ if (user->fd > -1)
{
FOREACH_MOD OnPostLocalTopicChange(user,Ptr,topic);
}
{
if (((c) && (!has_channel(user,c))) && (c->binarymodes & CM_SECRET))
{
- WriteServ(user->fd,"442 %s %s :You're not on that channel!",user->nick, c->name);
+ WriteServ(user->fd,"401 %s %s :No such nick/channel",user->nick, c->name);
return;
}
userlist(user,c);
if (loop_call(handle_privmsg,parameters,pcnt,user,0,pcnt-2,0))
return;
- if (parameters[0][0] == '#')
+ if (parameters[0][0] == '$')
+ {
+ // notice to server mask
+ char* servermask = parameters[0];
+ servermask++;
+ if (match(Config->ServerName,servermask))
+ {
+ ServerPrivmsgAll("%s",parameters[1]);
+ }
+ return;
+ }
+ else if (parameters[0][0] == '#')
{
chan = FindChan(parameters[0]);
if (chan)
}
return;
}
-
- log(DEBUG,"*** PRIVMSG HANDLER");
+
dest = Find(parameters[0]);
if (dest)
{
- log(DEBUG,"*** FOUND NICK %s",dest->nick);
if (strcmp(dest->awaymsg,""))
{
/* auto respond with aweh msg */
}
parameters[1] = (char*)temp.c_str();
- if (!strcmp(dest->server,ServerName))
+ if (dest->fd > -1)
{
// direct write, same server
- log(DEBUG,"*** CALL WRITETO");
WriteTo(user, dest, "PRIVMSG %s :%s", dest->nick, parameters[1]);
}
if (loop_call(handle_notice,parameters,pcnt,user,0,pcnt-2,0))
return;
- if (parameters[0][0] == '#')
+ if (parameters[0][0] == '$')
+ {
+ // notice to server mask
+ char* servermask = parameters[0];
+ servermask++;
+ if (match(Config->ServerName,servermask))
+ {
+ NoticeAll(user, true, "%s",parameters[1]);
+ }
+ return;
+ }
+ else if (parameters[0][0] == '#')
{
chan = FindChan(parameters[0]);
if (chan)
}
parameters[1] = (char*)temp.c_str();
- if (!strcmp(dest->server,ServerName))
+ if (dest->fd > -1)
{
// direct write, same server
WriteTo(user, dest, "NOTICE %s :%s", dest->nick, parameters[1]);
WriteServ(user->fd,"371 %s : Jazza",user->nick);
WriteServ(user->fd,"371 %s : ",user->nick);
WriteServ(user->fd,"371 %s :Testers: CC",user->nick);
+ WriteServ(user->fd,"371 %s : Om",user->nick);
WriteServ(user->fd,"371 %s : Piggles",user->nick);
WriteServ(user->fd,"371 %s : Foamy",user->nick);
WriteServ(user->fd,"371 %s : Hart",user->nick);
WriteServ(user->fd,"371 %s : Rob",user->nick);
WriteServ(user->fd,"371 %s : angelic",user->nick);
WriteServ(user->fd,"371 %s : Jason",user->nick);
+ WriteServ(user->fd,"371 %s : ThaPrince",user->nick);
WriteServ(user->fd,"371 %s : ",user->nick);
WriteServ(user->fd,"371 %s :Thanks to irc-junkie and searchirc",user->nick);
WriteServ(user->fd,"371 %s :for the nice comments and the help",user->nick);
time_t rawtime;
struct tm * timeinfo;
- time ( &rawtime );
- timeinfo = localtime ( &rawtime );
- WriteServ(user->fd,"391 %s %s :%s",user->nick,ServerName, asctime (timeinfo) );
+ time(&rawtime);
+ timeinfo = localtime(&rawtime);
+ WriteServ(user->fd,"391 %s %s :%s",user->nick,Config->ServerName,asctime(timeinfo));
}
void handle_whois(char **parameters, int pcnt, userrec *user)
{
userrec *dest;
-
- if (loop_call(handle_whois,parameters,pcnt,user,0,pcnt-1,0))
- return;
+ if (loop_call(handle_whois,parameters,pcnt,user,0,pcnt-1,0))
+ return;
dest = Find(parameters[0]);
if (dest)
{
- // bug found by phidjit - were able to whois an incomplete connection if it had sent a NICK or USER
- if (dest->registered == 7)
+ do_whois(user,dest,0,0,parameters[0]);
+ }
+ else
+ {
+ /* no such nick/channel */
+ WriteServ(user->fd,"401 %s %s :No such nick/channel",user->nick, parameters[0]);
+ WriteServ(user->fd,"318 %s %s :End of /WHOIS list.",user->nick, parameters[0]);
+ }
+}
+
+void split_chlist(userrec* user, userrec* dest, std::string &cl)
+{
+ std::stringstream channels(cl);
+ std::string line = "";
+ std::string cname = "";
+ while (!channels.eof())
+ {
+ channels >> cname;
+ line = line + cname + " ";
+ if (line.length() > 400)
{
- WriteServ(user->fd,"311 %s %s %s %s * :%s",user->nick, dest->nick, dest->ident, dest->dhost, dest->fullname);
- if ((user == dest) || (strchr(user->modes,'o')))
+ WriteServ(user->fd,"319 %s %s :%s",user->nick, dest->nick, line.c_str());
+ line = "";
+ }
+ }
+ if (line.length())
+ {
+ WriteServ(user->fd,"319 %s %s :%s",user->nick, dest->nick, line.c_str());
+ }
+}
+
+void do_whois(userrec* user, userrec* dest,unsigned long signon, unsigned long idle, char* nick)
+{
+ // bug found by phidjit - were able to whois an incomplete connection if it had sent a NICK or USER
+ if (dest->registered == 7)
+ {
+ WriteServ(user->fd,"311 %s %s %s %s * :%s",user->nick, dest->nick, dest->ident, dest->dhost, dest->fullname);
+ if ((user == dest) || (strchr(user->modes,'o')))
+ {
+ WriteServ(user->fd,"378 %s %s :is connecting from *@%s %s",user->nick, dest->nick, dest->host, dest->ip);
+ }
+ std::string cl = chlist(dest,user);
+ if (cl.length())
+ {
+ if (cl.length() > 400)
{
- WriteServ(user->fd,"378 %s %s :is connecting from *@%s %s",user->nick, dest->nick, dest->host, dest->ip);
+ split_chlist(user,dest,cl);
}
- char* cl = chlist(dest,user);
- if (strcmp(cl,""))
+ else
{
- WriteServ(user->fd,"319 %s %s :%s",user->nick, dest->nick, cl);
+ WriteServ(user->fd,"319 %s %s :%s",user->nick, dest->nick, cl.c_str());
}
- WriteServ(user->fd,"312 %s %s %s :%s",user->nick, dest->nick, dest->server, GetServerDescription(dest->server).c_str());
- if (strcmp(dest->awaymsg,""))
+ }
+ WriteServ(user->fd,"312 %s %s %s :%s",user->nick, dest->nick, dest->server, GetServerDescription(dest->server).c_str());
+ if (*dest->awaymsg)
+ {
+ WriteServ(user->fd,"301 %s %s :%s",user->nick, dest->nick, dest->awaymsg);
+ }
+ if (strchr(dest->modes,'o'))
+ {
+ if (*dest->oper)
{
- WriteServ(user->fd,"301 %s %s :%s",user->nick, dest->nick, dest->awaymsg);
+ WriteServ(user->fd,"313 %s %s :is %s %s on %s",user->nick, dest->nick, (strchr("aeiou",dest->oper[0]) ? "an" : "a"),dest->oper, Config->Network);
}
- if ((strchr(dest->modes,'o')) && (strcmp(dest->oper,"")))
+ else
{
- WriteServ(user->fd,"313 %s %s :is %s %s on %s",user->nick, dest->nick,
- (strchr("aeiou",dest->oper[0]) ? "an" : "a"),dest->oper, Network);
+ WriteServ(user->fd,"313 %s %s :is opered but has an unknown type",user->nick, dest->nick);
}
+ }
+ if ((!signon) && (!idle))
+ {
FOREACH_MOD OnWhois(user,dest);
- if (!strcasecmp(user->server,dest->server))
- {
- // idle time and signon line can only be sent if youre on the same server (according to RFC)
- WriteServ(user->fd,"317 %s %s %d %d :seconds idle, signon time",user->nick, dest->nick, abs((dest->idle_lastmsg)-TIME), dest->signon);
- }
-
- WriteServ(user->fd,"318 %s %s :End of /WHOIS list.",user->nick, dest->nick);
+ }
+ if (!strcasecmp(user->server,dest->server))
+ {
+ // idle time and signon line can only be sent if youre on the same server (according to RFC)
+ WriteServ(user->fd,"317 %s %s %d %d :seconds idle, signon time",user->nick, dest->nick, abs((dest->idle_lastmsg)-TIME), dest->signon);
}
else
{
- WriteServ(user->fd,"401 %s %s :No such nick/channel",user->nick, parameters[0]);
- WriteServ(user->fd,"318 %s %s :End of /WHOIS list.",user->nick, parameters[0]);
+ if ((idle) || (signon))
+ WriteServ(user->fd,"317 %s %s %d %d :seconds idle, signon time",user->nick, dest->nick, idle, signon);
}
+ WriteServ(user->fd,"318 %s %s :End of /WHOIS list.",user->nick, dest->nick);
}
else
{
- /* no such nick/channel */
- WriteServ(user->fd,"401 %s %s :No such nick/channel",user->nick, parameters[0]);
- WriteServ(user->fd,"318 %s %s :End of /WHOIS list.",user->nick, parameters[0]);
+ WriteServ(user->fd,"401 %s %s :No such nick/channel",user->nick, nick);
+ WriteServ(user->fd,"318 %s %s :End of /WHOIS list.",user->nick, nick);
}
}
reason[MAXQUIT-1] = '\0';
}
- Write(user->fd,"ERROR :Closing link (%s@%s) [%s%s]",user->ident,user->host,PrefixQuit,parameters[0]);
- WriteOpers("*** Client exiting: %s!%s@%s [%s%s]",user->nick,user->ident,user->host,PrefixQuit,parameters[0]);
- WriteCommonExcept(user,"QUIT :%s%s",PrefixQuit,parameters[0]);
- FOREACH_MOD OnUserQuit(user,std::string(PrefixQuit)+std::string(parameters[0]));
+ /* We should only prefix the quit for a local user. Remote users have
+ * already been prefixed, where neccessary, by the upstream server.
+ */
+ if (user->fd > -1)
+ {
+ Write(user->fd,"ERROR :Closing link (%s@%s) [%s%s]",user->ident,user->host,Config->PrefixQuit,parameters[0]);
+ WriteOpers("*** Client exiting: %s!%s@%s [%s%s]",user->nick,user->ident,user->host,Config->PrefixQuit,parameters[0]);
+ WriteCommonExcept(user,"QUIT :%s%s",Config->PrefixQuit,parameters[0]);
+ }
+ else
+ {
+ WriteOpers("*** Client exiting at %s: %s!%s@%s [%s]",user->server,user->nick,user->ident,user->host,parameters[0]);
+ WriteCommonExcept(user,"QUIT :%s",parameters[0]);
+ }
+ FOREACH_MOD OnUserQuit(user,std::string(Config->PrefixQuit)+std::string(parameters[0]));
}
else
/* push the socket on a stack of sockets due to be closed at the next opportunity */
if (user->fd > -1)
{
-#ifdef USE_KQUEUE
- struct kevent ke;
- EV_SET(&ke, user->fd, EVFILT_READ, EV_DELETE, 0, 0, NULL);
- int i = kevent(kq, &ke, 1, 0, 0, NULL);
- if (i == -1)
- {
- log(DEBUG,"kqueue: Failed to remove user from queue!");
- }
-#endif
-#ifdef USE_EPOLL
- struct epoll_event ev;
- ev.events = EPOLLIN | EPOLLET;
- ev.data.fd = user->fd;
- int i = epoll_ctl(ep, EPOLL_CTL_DEL, user->fd, &ev);
- if (i < 0)
- {
- log(DEBUG,"epoll: List deletion failure!");
- }
-#endif
+ SE->DelFd(user->fd);
user->CloseSocket();
}
{
if ((!strcmp(parameters[0],"0")) || (!strcmp(parameters[0],"*")))
{
- if (user->chans[0].channel)
+ if ((user->chans.size()) && (user->chans[0].channel))
{
int n_list = 0;
for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
if (strchr(i->second->modes,'o')) { strlcat(tmp, "*", 9); }
WriteServ(user->fd,"352 %s %s %s %s %s %s %s :0 %s",user->nick, Ptr ? Ptr->name : "*", i->second->ident, i->second->dhost, i->second->server, i->second->nick, tmp, i->second->fullname);
n_list++;
- if (n_list > MaxWhoResults)
+ if (n_list > Config->MaxWhoResults)
{
WriteServ(user->fd,"523 %s WHO :Command aborted: More results than configured limit",user->nick);
break;
strlcat(tmp, cmode(i->second, Ptr),5);
WriteServ(user->fd,"352 %s %s %s %s %s %s %s :0 %s",user->nick, Ptr->name, i->second->ident, i->second->dhost, i->second->server, i->second->nick, tmp, i->second->fullname);
n_list++;
- if (n_list > MaxWhoResults)
+ if (n_list > Config->MaxWhoResults)
{
WriteServ(user->fd,"523 %s WHO :Command aborted: More results than configured limit",user->nick);
break;
strlcat(tmp, "H" ,9);
}
if (strchr(u->modes,'o')) { strlcat(tmp, "*" ,9); }
- WriteServ(user->fd,"352 %s %s %s %s %s %s %s :0 %s",user->nick, u->chans[0].channel ? u->chans[0].channel->name
+ WriteServ(user->fd,"352 %s %s %s %s %s %s %s :0 %s",user->nick, u->chans.size() ? u->chans[0].channel->name
: "*", u->ident, u->dhost, u->server, u->nick, tmp, u->fullname);
}
WriteServ(user->fd,"315 %s %s :End of /WHO list.",user->nick, parameters[0]);
} else {
strlcat(tmp, "H" ,9);
}
- WriteServ(user->fd,"352 %s %s %s %s %s %s %s* :0 %s", user->nick, oper->chans[0].channel ? oper->chans[0].channel->name
+ WriteServ(user->fd,"352 %s %s %s %s %s %s %s* :0 %s", user->nick, oper->chans.size() ? oper->chans[0].channel->name
: "*", oper->ident, oper->dhost, oper->server, oper->nick, tmp, oper->fullname);
}
WriteServ(user->fd,"315 %s %s :End of /WHO list.",user->nick, parameters[0]);
void handle_wallops(char **parameters, int pcnt, userrec *user)
{
WriteWallOps(user,false,"%s",parameters[0]);
+ FOREACH_MOD OnWallops(user,parameters[0]);
}
void handle_list(char **parameters, int pcnt, userrec *user)
void handle_rehash(char **parameters, int pcnt, userrec *user)
{
WriteServ(user->fd,"382 %s %s :Rehashing",user->nick,CleanFilename(CONFIG_FILE));
- ReadConfig(false,user);
std::string parameter = "";
if (pcnt)
+ {
parameter = parameters[0];
+ }
+ else
+ {
+ WriteOpers("%s is rehashing config file %s",user->nick,CleanFilename(CONFIG_FILE));
+ Config->Read(false,user);
+ }
FOREACH_MOD OnRehash(parameter);
- WriteOpers("%s is rehashing config file %s",user->nick,CleanFilename(CONFIG_FILE));
}
void handle_lusers(char **parameters, int pcnt, userrec *user)
{
- WriteServ(user->fd,"251 %s :There are %d users and %d invisible on %d servers",user->nick,usercnt()-usercount_invisible(),usercount_invisible(),servercount());
+ // this lusers command shows one server at all times because
+ // a protocol module must override it to show those stats.
+ WriteServ(user->fd,"251 %s :There are %d users and %d invisible on 1 server",user->nick,usercnt()-usercount_invisible(),usercount_invisible());
WriteServ(user->fd,"252 %s %d :operator(s) online",user->nick,usercount_opers());
WriteServ(user->fd,"253 %s %d :unknown connections",user->nick,usercount_unknown());
WriteServ(user->fd,"254 %s %d :channels formed",user->nick,chancount());
- WriteServ(user->fd,"254 %s :I have %d clients and %d servers",user->nick,local_count(),count_servs());
+ WriteServ(user->fd,"254 %s :I have %d clients and 0 servers",user->nick,local_count());
}
void handle_admin(char **parameters, int pcnt, userrec *user)
{
- WriteServ(user->fd,"256 %s :Administrative info for %s",user->nick,ServerName);
- WriteServ(user->fd,"257 %s :Name - %s",user->nick,AdminName);
- WriteServ(user->fd,"258 %s :Nickname - %s",user->nick,AdminNick);
- WriteServ(user->fd,"258 %s :E-Mail - %s",user->nick,AdminEmail);
+ WriteServ(user->fd,"256 %s :Administrative info for %s",user->nick,Config->ServerName);
+ WriteServ(user->fd,"257 %s :Name - %s",user->nick,Config->AdminName);
+ WriteServ(user->fd,"258 %s :Nickname - %s",user->nick,Config->AdminNick);
+ WriteServ(user->fd,"258 %s :E-Mail - %s",user->nick,Config->AdminEmail);
}
void handle_ping(char **parameters, int pcnt, userrec *user)
{
- WriteServ(user->fd,"PONG %s :%s",ServerName,parameters[0]);
+ WriteServ(user->fd,"PONG %s :%s",Config->ServerName,parameters[0]);
}
void handle_pong(char **parameters, int pcnt, userrec *user)
void handle_modules(char **parameters, int pcnt, userrec *user)
{
- for (unsigned int i = 0; i < module_names.size(); i++)
+ for (unsigned int i = 0; i < Config->module_names.size(); i++)
{
Version V = modules[i]->GetVersion();
char modulename[MAXBUF];
strlcat(flagstate,", service provider",MAXBUF);
if (!flagstate[0])
strcpy(flagstate," <no flags>");
- strlcpy(modulename,module_names[i].c_str(),256);
+ strlcpy(modulename,Config->module_names[i].c_str(),256);
if (strchr(user->modes,'o'))
{
WriteServ(user->fd,"900 %s :0x%08lx %d.%d.%d.%d %s (%s)",user->nick,modules[i],V.Major,V.Minor,V.Revision,V.Build,CleanFilename(modulename),flagstate+2);
void handle_stats(char **parameters, int pcnt, userrec *user)
{
- char Link_ServerName[MAXBUF],Link_IPAddr[MAXBUF],Link_Port[MAXBUF];
if (pcnt != 1)
{
return;
if (*parameters[0] == 'c')
{
- for (int i = 0; i < ConfValueEnum("link",&config_f); i++)
- {
- ConfValue("link","name",i,Link_ServerName,&config_f);
- ConfValue("link","ipaddr",i,Link_IPAddr,&config_f);
- ConfValue("link","port",i,Link_Port,&config_f);
- WriteServ(user->fd,"213 %s C *@%s * %s %s 0 M",user->nick,Link_IPAddr,Link_ServerName,Link_Port);
- WriteServ(user->fd,"244 %s H * * %s",user->nick,Link_ServerName);
- }
+ /* This stats symbol must be handled by a linking module */
}
if (*parameters[0] == 'i')
{
int idx = 0;
- for (ClassVector::iterator i = Classes.begin(); i != Classes.end(); i++)
+ for (ClassVector::iterator i = Config->Classes.begin(); i != Config->Classes.end(); i++)
{
- WriteServ(user->fd,"215 %s I * * * %d %d %s *",user->nick,MAXCLIENTS,idx,ServerName);
+ WriteServ(user->fd,"215 %s I * * * %d %d %s *",user->nick,MAXCLIENTS,idx,Config->ServerName);
idx++;
}
}
if (*parameters[0] == 'y')
{
int idx = 0;
- for (ClassVector::iterator i = Classes.begin(); i != Classes.end(); i++)
+ for (ClassVector::iterator i = Config->Classes.begin(); i != Config->Classes.end(); i++)
{
WriteServ(user->fd,"218 %s Y %d %d 0 %d %d",user->nick,idx,120,i->flood,i->registration_timeout);
idx++;
if (*parameters[0] == 'U')
{
- for (int i = 0; i < ConfValueEnum("uline",&config_f); i++)
+ char ulined[MAXBUF];
+ for (int i = 0; i < Config->ConfValueEnum("uline",&Config->config_f); i++)
{
- ConfValue("uline","server",i,Link_ServerName,&config_f);
- WriteServ(user->fd,"248 %s U %s",user->nick,Link_ServerName);
+ Config->ConfValue("uline","server",i,ulined,&Config->config_f);
+ WriteServ(user->fd,"248 %s U %s",user->nick,ulined);
}
}
WriteServ(user->fd,"249 %s :Users(HASH_MAP) %d (%d bytes, %d buckets)",user->nick,clientlist.size(),clientlist.size()*sizeof(userrec),clientlist.bucket_count());
WriteServ(user->fd,"249 %s :Channels(HASH_MAP) %d (%d bytes, %d buckets)",user->nick,chanlist.size(),chanlist.size()*sizeof(chanrec),chanlist.bucket_count());
WriteServ(user->fd,"249 %s :Commands(VECTOR) %d (%d bytes)",user->nick,cmdlist.size(),cmdlist.size()*sizeof(command_t));
- WriteServ(user->fd,"249 %s :MOTD(VECTOR) %d, RULES(VECTOR) %d",user->nick,MOTD.size(),RULES.size());
+ WriteServ(user->fd,"249 %s :MOTD(VECTOR) %d, RULES(VECTOR) %d",user->nick,Config->MOTD.size(),Config->RULES.size());
WriteServ(user->fd,"249 %s :address_cache(HASH_MAP) %d (%d buckets)",user->nick,IP.size(),IP.bucket_count());
WriteServ(user->fd,"249 %s :Modules(VECTOR) %d (%d)",user->nick,modules.size(),modules.size()*sizeof(Module));
WriteServ(user->fd,"249 %s :ClassFactories(VECTOR) %d (%d)",user->nick,factory.size(),factory.size()*sizeof(ircd_module));
if (*parameters[0] == 'T')
{
- WriteServ(user->fd,"249 Brain :accepts %d refused %d",statsAccept,statsRefused);
- WriteServ(user->fd,"249 Brain :unknown commands %d",statsUnknown);
- WriteServ(user->fd,"249 Brain :nick collisions %d",statsCollisions);
- WriteServ(user->fd,"249 Brain :dns requests %d succeeded %d failed %d",statsDns,statsDnsGood,statsDnsBad);
- WriteServ(user->fd,"249 Brain :connections %d",statsConnects);
- WriteServ(user->fd,"249 Brain :bytes sent %dK recv %dK",(statsSent / 1024),(statsRecv / 1024));
+ WriteServ(user->fd,"249 Brain :accepts %d refused %d",stats->statsAccept,stats->statsRefused);
+ WriteServ(user->fd,"249 Brain :unknown commands %d",stats->statsUnknown);
+ WriteServ(user->fd,"249 Brain :nick collisions %d",stats->statsCollisions);
+ WriteServ(user->fd,"249 Brain :dns requests %d succeeded %d failed %d",stats->statsDns,stats->statsDnsGood,stats->statsDnsBad);
+ WriteServ(user->fd,"249 Brain :connections %d",stats->statsConnects);
+ WriteServ(user->fd,"249 Brain :bytes sent %dK recv %dK",(stats->statsSent / 1024),(stats->statsRecv / 1024));
}
/* stats o */
if (*parameters[0] == 'o')
{
- for (int i = 0; i < ConfValueEnum("oper",&config_f); i++)
+ for (int i = 0; i < Config->ConfValueEnum("oper",&Config->config_f); i++)
{
char LoginName[MAXBUF];
char HostName[MAXBUF];
char OperType[MAXBUF];
- ConfValue("oper","name",i,LoginName,&config_f);
- ConfValue("oper","host",i,HostName,&config_f);
- ConfValue("oper","type",i,OperType,&config_f);
+ Config->ConfValue("oper","name",i,LoginName,&Config->config_f);
+ Config->ConfValue("oper","host",i,HostName,&Config->config_f);
+ Config->ConfValue("oper","type",i,OperType,&Config->config_f);
WriteServ(user->fd,"243 %s O %s * %s %s 0",user->nick,HostName,LoginName,OperType);
}
}
void handle_links(char **parameters, int pcnt, userrec *user)
{
- WriteServ(user->fd,"364 %s %s %s :0 %s",user->nick,ServerName,ServerName,ServerDesc);
+ WriteServ(user->fd,"364 %s %s %s :0 %s",user->nick,Config->ServerName,Config->ServerName,Config->ServerDesc);
WriteServ(user->fd,"365 %s * :End of /LINKS list.",user->nick);
}
void handle_map(char **parameters, int pcnt, userrec *user)
{
- char line[MAXBUF];
- snprintf(line,MAXBUF,"006 %s :%s",user->nick,ServerName);
+ // as with /LUSERS this does nothing without a linking
+ // module to override its behaviour and display something
+ // better.
+ WriteServ(user->fd,"006 %s :%s",user->nick,Config->ServerName);
WriteServ(user->fd,"007 %s :End of /MAP",user->nick);
}
{
char ServName[MAXBUF];
- /* fix, by w00t - per nenolod. I don't see how we can want '""' as a uline. */
- if (!server || !(*server))
+ if (!server)
+ return false;
+ if (!(*server))
return true;
- for (int i = 0; i < ConfValueEnum("uline",&config_f); i++)
+ for (int i = 0; i < Config->ConfValueEnum("uline",&Config->config_f); i++)
{
- ConfValue("uline","server",i,ServName,&config_f);
+ Config->ConfValue("uline","server",i,ServName,&Config->config_f);
if (!strcasecmp(server,ServName))
{
return true;
snprintf(TheHost,MAXBUF,"%s@%s",user->ident,user->host);
- for (int i = 0; i < ConfValueEnum("oper",&config_f); i++)
+ for (int i = 0; i < Config->ConfValueEnum("oper",&Config->config_f); i++)
{
- ConfValue("oper","name",i,LoginName,&config_f);
- ConfValue("oper","password",i,Password,&config_f);
- ConfValue("oper","type",i,OperType,&config_f);
- ConfValue("oper","host",i,HostName,&config_f);
+ Config->ConfValue("oper","name",i,LoginName,&Config->config_f);
+ Config->ConfValue("oper","password",i,Password,&Config->config_f);
+ Config->ConfValue("oper","type",i,OperType,&Config->config_f);
+ Config->ConfValue("oper","host",i,HostName,&Config->config_f);
if ((!strcmp(LoginName,parameters[0])) && (!operstrcmp(Password,parameters[1])) && (match(TheHost,HostName)))
{
fail2 = true;
- for (j =0; j < ConfValueEnum("type",&config_f); j++)
+ for (j =0; j < Config->ConfValueEnum("type",&Config->config_f); j++)
{
- ConfValue("type","name",j,TypeName,&config_f);
+ Config->ConfValue("type","name",j,TypeName,&Config->config_f);
if (!strcmp(TypeName,OperType))
{
/* found this oper's opertype */
- ConfValue("type","host",j,HostName,&config_f);
+ Config->ConfValue("type","host",j,HostName,&Config->config_f);
if (*HostName)
ChangeDisplayedHost(user,HostName);
strlcpy(user->oper,TypeName,NICKMAX);
user->registered = (user->registered | 2);
// dont attempt to look up the dns until they pick a nick... because otherwise their pointer WILL change
// and unless we're lucky we'll get a duff one later on.
+ //user->dns_done = (!lookup_dns(user->nick));
+ //if (user->dns_done)
+ // log(DEBUG,"Aborting dns lookup of %s because dns server experienced a failure.",user->nick);
+
+#ifdef THREADED_DNS
+ // initialize their dns lookup thread
+ if (pthread_create(&user->dnsthread, NULL, dns_task, (void *)user) != 0)
+ {
+ log(DEBUG,"Failed to create DNS lookup thread for user %s",user->nick);
+ }
+#else
user->dns_done = (!lookup_dns(user->nick));
if (user->dns_done)
log(DEBUG,"Aborting dns lookup of %s because dns server experienced a failure.",user->nick);
+#endif
+
}
if (user->registered == 3)
{
long total = 0;
const char* str_end = str + strlen(str);
n_field[0] = 0;
+
+ if ((!strchr(str,'s')) && (!strchr(str,'m')) && (!strchr(str,'h')) && (!strchr(str,'d')) && (!strchr(str,'w')) && (!strchr(str,'y')))
+ {
+ std::string n = str;
+ n = n + "s";
+ return duration(n.c_str());
+ }
for (char* i = (char*)str; i < str_end; i++)
{
return total;
}
+/* All other ircds when doing this check usually just look for a string of *@* or *. We're smarter than that, though. */
+
+bool host_matches_everyone(std::string mask, userrec* user)
+{
+ char insanemasks[MAXBUF];
+ char buffer[MAXBUF];
+ char itrigger[MAXBUF];
+ Config->ConfValue("insane","hostmasks",0,insanemasks,&Config->config_f);
+ Config->ConfValue("insane","trigger",0,itrigger,&Config->config_f);
+ if (*itrigger == 0)
+ strlcpy(itrigger,"95.5",MAXBUF);
+ if ((*insanemasks == 'y') || (*insanemasks == 't') || (*insanemasks == '1'))
+ return false;
+ long matches = 0;
+ for (user_hash::iterator u = clientlist.begin(); u != clientlist.end(); u++)
+ {
+ strlcpy(buffer,u->second->ident,MAXBUF);
+ strlcat(buffer,"@",MAXBUF);
+ strlcat(buffer,u->second->host,MAXBUF);
+ if (match(buffer,mask.c_str()))
+ matches++;
+ }
+ float percent = ((float)matches / (float)clientlist.size()) * 100;
+ if (percent > (float)atof(itrigger))
+ {
+ WriteOpers("*** \2WARNING\2: %s tried to set a G/K/E line mask of %s, which covers %.2f%% of the network!",user->nick,mask.c_str(),percent);
+ return true;
+ }
+ return false;
+}
+
+bool ip_matches_everyone(std::string ip, userrec* user)
+{
+ char insanemasks[MAXBUF];
+ char itrigger[MAXBUF];
+ Config->ConfValue("insane","ipmasks",0,insanemasks,&Config->config_f);
+ Config->ConfValue("insane","trigger",0,itrigger,&Config->config_f);
+ if (*itrigger == 0)
+ strlcpy(itrigger,"95.5",MAXBUF);
+ if ((*insanemasks == 'y') || (*insanemasks == 't') || (*insanemasks == '1'))
+ return false;
+ long matches = 0;
+ for (user_hash::iterator u = clientlist.begin(); u != clientlist.end(); u++)
+ {
+ if (match(u->second->ip,ip.c_str()))
+ matches++;
+ }
+ float percent = ((float)matches / (float)clientlist.size()) * 100;
+ if (percent > (float)atof(itrigger))
+ {
+ WriteOpers("*** \2WARNING\2: %s tried to set a Z line mask of %s, which covers %.2f%% of the network!",user->nick,ip.c_str(),percent);
+ return true;
+ }
+ return false;
+}
+
+bool nick_matches_everyone(std::string nick, userrec* user)
+{
+ char insanemasks[MAXBUF];
+ char itrigger[MAXBUF];
+ Config->ConfValue("insane","nickmasks",0,insanemasks,&Config->config_f);
+ Config->ConfValue("insane","trigger",0,itrigger,&Config->config_f);
+ if (*itrigger == 0)
+ strlcpy(itrigger,"95.5",MAXBUF);
+ if ((*insanemasks == 'y') || (*insanemasks == 't') || (*insanemasks == '1'))
+ return false;
+ long matches = 0;
+ for (user_hash::iterator u = clientlist.begin(); u != clientlist.end(); u++)
+ {
+ if (match(u->second->nick,nick.c_str()))
+ matches++;
+ }
+ float percent = ((float)matches / (float)clientlist.size()) * 100;
+ if (percent > (float)atof(itrigger))
+ {
+ WriteOpers("*** \2WARNING\2: %s tried to set a Q line mask of %s, which covers %.2f%% of the network!",user->nick,nick.c_str(),percent);
+ return true;
+ }
+ return false;
+}
void handle_kline(char **parameters, int pcnt, userrec *user)
{
if (pcnt >= 3)
{
+ if (host_matches_everyone(parameters[0],user))
+ return;
add_kline(duration(parameters[1]),user->nick,parameters[2],parameters[0]);
+ FOREACH_MOD OnAddKLine(duration(parameters[1]), user, parameters[2], parameters[0]);
if (!duration(parameters[1]))
{
WriteOpers("*** %s added permenant K-line for %s.",user->nick,parameters[0]);
{
WriteOpers("*** %s added timed K-line for %s, expires in %d seconds.",user->nick,parameters[0],duration(parameters[1]));
}
+ apply_lines(APPLY_KLINES);
}
else
{
if (del_kline(parameters[0]))
{
+ FOREACH_MOD OnDelKLine(user, parameters[0]);
WriteOpers("*** %s Removed K-line on %s.",user->nick,parameters[0]);
}
else
WriteServ(user->fd,"NOTICE %s :*** K-Line %s not found in list, try /stats k.",user->nick,parameters[0]);
}
}
- apply_lines();
}
void handle_eline(char **parameters, int pcnt, userrec *user)
{
if (pcnt >= 3)
{
+ if (host_matches_everyone(parameters[0],user))
+ return;
add_eline(duration(parameters[1]),user->nick,parameters[2],parameters[0]);
+ FOREACH_MOD OnAddELine(duration(parameters[1]), user, parameters[2], parameters[0]);
if (!duration(parameters[1]))
{
WriteOpers("*** %s added permenant E-line for %s.",user->nick,parameters[0]);
{
if (del_eline(parameters[0]))
{
+ FOREACH_MOD OnDelELine(user, parameters[0]);
WriteOpers("*** %s Removed E-line on %s.",user->nick,parameters[0]);
}
else
void handle_gline(char **parameters, int pcnt, userrec *user)
{
- char netdata[MAXBUF];
if (pcnt >= 3)
{
+ if (host_matches_everyone(parameters[0],user))
+ return;
add_gline(duration(parameters[1]),user->nick,parameters[2],parameters[0]);
+ FOREACH_MOD OnAddGLine(duration(parameters[1]), user, parameters[2], parameters[0]);
if (!duration(parameters[1]))
{
WriteOpers("*** %s added permenant G-line for %s.",user->nick,parameters[0]);
{
WriteOpers("*** %s added timed G-line for %s, expires in %d seconds.",user->nick,parameters[0],duration(parameters[1]));
}
+ apply_lines(APPLY_GLINES);
}
else
{
if (del_gline(parameters[0]))
{
- // . <mask> <who-removed-it>
- snprintf(netdata,MAXBUF,". %s %s",parameters[0],user->nick);
+ FOREACH_MOD OnDelGLine(user, parameters[0]);
WriteOpers("*** %s Removed G-line on %s.",user->nick,parameters[0]);
}
else
WriteServ(user->fd,"NOTICE %s :*** G-Line %s not found in list, try /stats g.",user->nick,parameters[0]);
}
}
- apply_lines();
}
void handle_zline(char **parameters, int pcnt, userrec *user)
{
if (pcnt >= 3)
{
+ if (strchr(parameters[0],'@'))
+ {
+ WriteServ(user->fd,"NOTICE %s :*** You cannot include a username in a zline, a zline must ban only an IP mask",user->nick);
+ return;
+ }
+ if (ip_matches_everyone(parameters[0],user))
+ return;
add_zline(duration(parameters[1]),user->nick,parameters[2],parameters[0]);
+ FOREACH_MOD OnAddZLine(duration(parameters[1]), user, parameters[2], parameters[0]);
if (!duration(parameters[1]))
{
WriteOpers("*** %s added permenant Z-line for %s.",user->nick,parameters[0]);
{
WriteOpers("*** %s added timed Z-line for %s, expires in %d seconds.",user->nick,parameters[0],duration(parameters[1]));
}
+ apply_lines(APPLY_ZLINES);
}
else
{
if (del_zline(parameters[0]))
{
+ FOREACH_MOD OnDelZLine(user, parameters[0]);
WriteOpers("*** %s Removed Z-line on %s.",user->nick,parameters[0]);
}
else
WriteServ(user->fd,"NOTICE %s :*** Z-Line %s not found in list, try /stats Z.",user->nick,parameters[0]);
}
}
- apply_lines();
}
void handle_qline(char **parameters, int pcnt, userrec *user)
{
if (pcnt >= 3)
{
+ if (nick_matches_everyone(parameters[0],user))
+ return;
add_qline(duration(parameters[1]),user->nick,parameters[2],parameters[0]);
+ FOREACH_MOD OnAddQLine(duration(parameters[1]), user, parameters[2], parameters[0]);
if (!duration(parameters[1]))
{
WriteOpers("*** %s added permenant Q-line for %s.",user->nick,parameters[0]);
{
WriteOpers("*** %s added timed Q-line for %s, expires in %d seconds.",user->nick,parameters[0],duration(parameters[1]));
}
+ apply_lines(APPLY_QLINES);
}
else
{
if (del_qline(parameters[0]))
{
+ FOREACH_MOD OnDelQLine(user, parameters[0]);
WriteOpers("*** %s Removed Q-line on %s.",user->nick,parameters[0]);
}
else
{
- WriteServ(user->fd,"NOTICE %s :*** Q-Line %s not found in list, try /stats k.",user->nick,parameters[0]);
+ WriteServ(user->fd,"NOTICE %s :*** Q-Line %s not found in list, try /stats q.",user->nick,parameters[0]);
}
}
- apply_lines();
}