* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
- * Inspire is copyright (C) 2002-2004 ChatSpike-Dev.
+ * InspIRCd is copyright (C) 2002-2006 ChatSpike-Dev.
* E-mail:
* <brain@chatspike.net>
* <Craig@chatspike.net>
#include "message.h"
#include "wildcard.h"
#include "xline.h"
+#include "cull_list.h"
extern InspIRCd* ServerInstance;
extern int WHOWAS_STALE;
extern std::vector<ircd_module*> factory;
extern std::vector<InspSocket*> module_sockets;
extern int MODCOUNT;
-extern InspSocket* socket_ref[65535];
+extern InspSocket* socket_ref[MAX_DESCRIPTORS];
extern time_t TIME;
-extern SocketEngine* SE;
-extern userrec* fd_ref_table[65536];
-extern serverstats* stats;
+extern userrec* fd_ref_table[MAX_DESCRIPTORS];
extern ServerConfig *Config;
extern user_hash clientlist;
extern whowas_hash whowas;
-std::vector<userrec*> local_users;
+extern std::vector<userrec*> local_users;
std::vector<userrec*> all_opers;
userrec::userrec()
{
// the PROPER way to do it, AVOID bzero at *ALL* costs
- strcpy(nick,"");
- strcpy(ip,"127.0.0.1");
- timeout = 0;
- strcpy(ident,"");
- strcpy(host,"");
- strcpy(dhost,"");
- strcpy(fullname,"");
- strcpy(modes,"");
+ *password = *nick = *ident = *host = *dhost = *fullname = *modes = *awaymsg = *oper = 0;
server = (char*)FindServerNamePtr(Config->ServerName);
- strcpy(awaymsg,"");
- strcpy(oper,"");
reset_due = TIME;
- lines_in = 0;
- fd = lastping = signon = idle_lastmsg = nping = registered = 0;
- flood = port = bytes_in = bytes_out = cmds_in = cmds_out = 0;
- haspassed = false;
- dns_done = false;
+ lines_in = fd = lastping = signon = idle_lastmsg = nping = registered = 0;
+ timeout = flood = port = bytes_in = bytes_out = cmds_in = cmds_out = 0;
+ haspassed = dns_done = false;
recvq = "";
sendq = "";
chans.clear();
{
}
+void userrec::MakeHost(char* nhost)
+{
+ /* This is much faster than snprintf */
+ char* t = nhost;
+ for(char* n = ident; *n; n++)
+ *t++ = *n;
+ *t++ = '@';
+ for(char* n = host; *n; n++)
+ *t++ = *n;
+ *t = 0;
+}
+
void userrec::CloseSocket()
{
shutdown(this->fd,2);
char* userrec::GetFullHost()
{
static char result[MAXBUF];
- snprintf(result,MAXBUF,"%s!%s@%s",nick,ident,dhost);
+ char* t = result;
+ for(char* n = nick; *n; n++)
+ *t++ = *n;
+ *t++ = '!';
+ for(char* n = ident; *n; n++)
+ *t++ = *n;
+ *t++ = '@';
+ for(char* n = dhost; *n; n++)
+ *t++ = *n;
+ *t = 0;
return result;
}
+char* userrec::MakeWildHost()
+{
+ static char nresult[MAXBUF];
+ char* t = nresult;
+ *t++ = '*'; *t++ = '!';
+ *t++ = '*'; *t++ = '@';
+ for(char* n = dhost; *n; n++)
+ *t++ = *n;
+ *t = 0;
+ return nresult;
+}
+
int userrec::ReadData(void* buffer, size_t size)
{
if (this->fd > -1)
char* userrec::GetFullRealHost()
{
static char fresult[MAXBUF];
- snprintf(fresult,MAXBUF,"%s!%s@%s",nick,ident,host);
+ char* t = fresult;
+ for(char* n = nick; *n; n++)
+ *t++ = *n;
+ *t++ = '!';
+ for(char* n = ident; *n; n++)
+ *t++ = *n;
+ *t++ = '@';
+ for(char* n = host; *n; n++)
+ *t++ = *n;
+ *t = 0;
return fresult;
}
return true;
// are they even an oper at all?
- if (strchr(this->modes,'o'))
+ if (*this->oper)
{
for (int j =0; j < Config->ConfValueEnum("type",&Config->config_f); j++)
{
bool userrec::BufferIsReady()
{
- for (unsigned int i = 0; i < recvq.length(); i++)
+ unsigned int t = recvq.length();
+ for (unsigned int i = 0; i < t; i++)
if (recvq[i] == '\n')
return true;
return false;
return "";
char* line = (char*)recvq.c_str();
std::string ret = "";
- while ((*line != '\n') && (strlen(line)))
+ while ((*line != '\n') && (*line))
{
ret = ret + *line;
line++;
// send AS MUCH OF THE USERS SENDQ as we are able to (might not be all of it)
void userrec::FlushWriteBuf()
{
- if (sendq.length())
+ if ((sendq.length()) && (this->fd != FD_MAGIC_NUMBER))
{
char* tb = (char*)this->sendq.c_str();
int n_sent = write(this->fd,tb,this->sendq.length());
char reason[MAXBUF];
- strncpy(reason,r,MAXBUF);
+ strlcpy(reason,r,MAXBUF);
if (strlen(reason)>MAXQUIT)
{
log(DEBUG,"closing fd %lu",(unsigned long)user->fd);
if (user->registered == 7) {
- FOREACH_MOD OnUserQuit(user,reason);
+ FOREACH_MOD(I_OnUserQuit,OnUserQuit(user,reason));
WriteCommonExcept(user,"QUIT :%s",reason);
}
user->FlushWriteBuf();
- FOREACH_MOD OnUserDisconnect(user);
+ FOREACH_MOD(I_OnUserDisconnect,OnUserDisconnect(user));
if (user->fd > -1)
{
- if (IOHookModule)
+ if (Config->GetIOHook(user->port))
{
- IOHookModule->OnRawSocketClose(user->fd);
+ try
+ {
+ Config->GetIOHook(user->port)->OnRawSocketClose(user->fd);
+ }
+ catch (ModuleException& modexcept)
+ {
+ log(DEBUG,"Module exception cought: %s",modexcept.GetReason()); \
+ }
}
- SE->DelFd(user->fd);
+ ServerInstance->SE->DelFd(user->fd);
user->CloseSocket();
}
char reason[MAXBUF];
- strncpy(reason,r,MAXBUF);
+ strlcpy(reason,r,MAXBUF);
if (strlen(reason)>MAXQUIT)
{
user->FlushWriteBuf();
if (user->registered == 7) {
- FOREACH_MOD OnUserQuit(user,reason);
+ FOREACH_MOD(I_OnUserQuit,OnUserQuit(user,reason));
WriteCommonExcept(user,"QUIT :%s",reason);
}
- FOREACH_MOD OnUserDisconnect(user);
+ FOREACH_MOD(I_OnUserDisconnect,OnUserDisconnect(user));
if (user->fd > -1)
{
- if (IOHookModule)
+ if (Config->GetIOHook(user->port))
{
- IOHookModule->OnRawSocketClose(user->fd);
+ try
+ {
+ Config->GetIOHook(user->port)->OnRawSocketClose(user->fd);
+ }
+ catch (ModuleException& modexcept)
+ {
+ log(DEBUG,"Module exception cought: %s",modexcept.GetReason()); \
+ }
}
- SE->DelFd(user->fd);
+ ServerInstance->SE->DelFd(user->fd);
user->CloseSocket();
}
strlcpy(a->dhost,u->dhost,160);
strlcpy(a->host,u->host,160);
strlcpy(a->fullname,u->fullname,MAXGECOS);
- strlcpy(a->server,u->server,256);
+ if (u->server)
+ strlcpy(a->server,u->server,256);
a->signon = u->signon;
/* MAX_WHOWAS: max number of /WHOWAS items
}
/* add a client connection to the sockets list */
-void AddClient(int socket, char* host, int port, bool iscached, char* ip)
+void AddClient(int socket, int port, bool iscached, in_addr ip4)
{
string tempnick;
char tn2[MAXBUF];
user_hash::iterator iter;
tempnick = ConvToStr(socket) + "-unknown";
- sprintf(tn2,"%lu-unknown",(unsigned long)socket);
+ sprintf(tn2,"%d-unknown",socket);
iter = clientlist.find(tempnick);
*/
clientlist[tempnick] = new userrec();
- NonBlocking(socket);
- log(DEBUG,"AddClient: %lu %s %d %s",(unsigned long)socket,host,port,ip);
+ char *ipaddr = (char*)inet_ntoa(ip4);
+
+ log(DEBUG,"AddClient: %d %d %s",socket,port,ipaddr);
clientlist[tempnick]->fd = socket;
strlcpy(clientlist[tempnick]->nick, tn2,NICKMAX);
- strlcpy(clientlist[tempnick]->host, host,160);
- strlcpy(clientlist[tempnick]->dhost, host,160);
+ /* We don't know the host yet, dns lookup could still be going on,
+ * so instead we just put the ip address here, for now.
+ */
+ strlcpy(clientlist[tempnick]->host, ipaddr, 160);
+ strlcpy(clientlist[tempnick]->dhost, ipaddr, 160);
clientlist[tempnick]->server = (char*)FindServerNamePtr(Config->ServerName);
strlcpy(clientlist[tempnick]->ident, "unknown",IDENTMAX);
clientlist[tempnick]->registered = 0;
clientlist[tempnick]->signon = TIME + Config->dns_timeout;
clientlist[tempnick]->lastping = 1;
+ clientlist[tempnick]->ip4 = ip4;
clientlist[tempnick]->port = port;
- strlcpy(clientlist[tempnick]->ip,ip,16);
// set the registration timeout for this user
unsigned long class_regtimeout = 90;
for (ClassVector::iterator i = Config->Classes.begin(); i != Config->Classes.end(); i++)
{
- if (match(clientlist[tempnick]->host,i->host) && (i->type == CC_ALLOW))
+ if (match(ipaddr,i->host.c_str()) && (i->type == CC_ALLOW))
{
class_regtimeout = (unsigned long)i->registration_timeout;
class_flood = i->flood;
for (int i = 0; i < MAXCHANS; i++)
clientlist[tempnick]->chans.push_back(a);
- if (clientlist.size() > Config->SoftLimit)
+ if (local_users.size() > Config->SoftLimit)
{
kill_link(clientlist[tempnick],"No more connections allowed");
return;
}
- if (clientlist.size() >= MAXCLIENTS)
+ if (local_users.size() >= MAXCLIENTS)
{
kill_link(clientlist[tempnick],"No more connections allowed");
return;
// irc server at once (or the irc server otherwise initiating this many connections, files etc)
// which for the time being is a physical impossibility (even the largest networks dont have more
// than about 10,000 users on ONE server!)
- if ((unsigned)socket > 65534)
+ if ((unsigned)socket > MAX_DESCRIPTORS)
{
kill_link(clientlist[tempnick],"Server is full");
return;
}
- char* e = matches_exception(ip);
+ char* e = matches_exception(ipaddr);
if (!e)
{
- char* r = matches_zline(ip);
+ char* r = matches_zline(ipaddr);
if (r)
{
char reason[MAXBUF];
}
fd_ref_table[socket] = clientlist[tempnick];
local_users.push_back(clientlist[tempnick]);
- SE->AddFd(socket,true,X_ESTAB_CLIENT);
+ ServerInstance->SE->AddFd(socket,true,X_ESTAB_CLIENT);
+
+ WriteServ(clientlist[tempnick]->fd,"NOTICE Auth :*** Looking up your hostname...");
}
-void FullConnectUser(userrec* user)
+long FindMatchingGlobal(userrec* user)
{
- stats->statsConnects++;
+ long x = 0;
+ for (user_hash::const_iterator a = clientlist.begin(); a != clientlist.end(); a++)
+ {
+ if (a->second->ip4.s_addr == user->ip4.s_addr)
+ x++;
+ }
+ return x;
+}
+
+long FindMatchingLocal(userrec* user)
+{
+ long x = 0;
+ for (std::vector<userrec*>::const_iterator a = local_users.begin(); a != local_users.end(); a++)
+ {
+ userrec* comp = (userrec*)(*a);
+ if (comp->ip4.s_addr == user->ip4.s_addr)
+ x++;
+ }
+ return x;
+}
+
+void FullConnectUser(userrec* user, CullList* Goners)
+{
+ ServerInstance->stats->statsConnects++;
user->idle_lastmsg = TIME;
log(DEBUG,"ConnectUser: %s",user->nick);
- if ((strcmp(Passwd(user),"")) && (!user->haspassed))
- {
- kill_link(user,"Invalid password");
- return;
- }
- if (IsDenied(user))
+ ConnectClass a = GetClass(user);
+
+ if (a.type == CC_DENY)
+ {
+ Goners->AddItem(user,"Unauthorised connection");
+ return;
+ }
+ if ((*(a.pass.c_str())) && (!user->haspassed))
{
- kill_link(user,"Unauthorised connection");
+ Goners->AddItem(user,"Invalid password");
return;
}
+ if (FindMatchingLocal(user) > a.maxlocal)
+ {
+ Goners->AddItem(user,"No more connections allowed from your host via this connect class (local)");
+ WriteOpers("*** WARNING: maximum LOCAL connections (%ld) exceeded for IP %s",a.maxlocal,(char*)inet_ntoa(user->ip4));
+ return;
+ }
+ else if (FindMatchingGlobal(user) > a.maxglobal)
+ {
+ Goners->AddItem(user,"No more connections allowed from your host via this connect class (global)");
+ WriteOpers("*** WARNING: maximum GLOBAL connections (%ld) exceeded for IP %s",a.maxglobal,(char*)inet_ntoa(user->ip4));
+ return;
+ }
char match_against[MAXBUF];
snprintf(match_against,MAXBUF,"%s@%s",user->ident,user->host);
{
char reason[MAXBUF];
snprintf(reason,MAXBUF,"G-Lined: %s",r);
- kill_link_silent(user,reason);
+ Goners->AddItem(user,reason);
return;
}
r = matches_kline(user->host);
{
char reason[MAXBUF];
snprintf(reason,MAXBUF,"K-Lined: %s",r);
- kill_link_silent(user,reason);
+ Goners->AddItem(user,reason);
return;
}
}
WriteServ(user->fd,"001 %s :Welcome to the %s IRC Network %s!%s@%s",user->nick,Config->Network,user->nick,user->ident,user->host);
WriteServ(user->fd,"002 %s :Your host is %s, running version %s",user->nick,Config->ServerName,VERSION);
WriteServ(user->fd,"003 %s :This server was created %s %s",user->nick,__TIME__,__DATE__);
- WriteServ(user->fd,"004 %s %s %s iowghraAsORVSxNCWqBzvdHtGI lvhopsmntikrRcaqOALQbSeKVfHGCuzN",user->nick,Config->ServerName,VERSION);
- // the neatest way to construct the initial 005 numeric, considering the number of configure constants to go in it...
- std::stringstream v;
- v << "WALLCHOPS MODES=13 CHANTYPES=# PREFIX=(ohv)@%+ MAP SAFELIST MAXCHANNELS=" << MAXCHANS;
- v << " MAXBANS=60 NICKLEN=" << NICKMAX;
- v << " TOPICLEN=" << MAXTOPIC << " KICKLEN=" << MAXKICK << " MAXTARGETS=20 AWAYLEN=" << MAXAWAY << " CHANMODES=ohvb,k,l,psmnti NETWORK=";
- v << Config->Network;
- std::string data005 = v.str();
- FOREACH_MOD On005Numeric(data005);
+ WriteServ(user->fd,"004 %s %s %s iowghrasxRVSCWBG lvhopsmntikrcaqbegIOLQRSKVHGCNT vhobeIaqglk",user->nick,Config->ServerName,VERSION);
// anfl @ #ratbox, efnet reminded me that according to the RFC this cant contain more than 13 tokens per line...
// so i'd better split it :)
- std::stringstream out(data005);
+ std::stringstream out(Config->data005);
std::string token = "";
std::string line5 = "";
int token_counter = 0;
// fix 3 by brain, move registered = 7 below these so that spurious modes and host changes dont go out
// onto the network and produce 'fake direction'
- FOREACH_MOD OnUserConnect(user);
- FOREACH_MOD OnGlobalConnect(user);
+ FOREACH_MOD(I_OnUserConnect,OnUserConnect(user));
+ FOREACH_MOD(I_OnGlobalConnect,OnGlobalConnect(user));
user->registered = 7;
- WriteOpers("*** Client connecting on port %lu: %s!%s@%s [%s]",(unsigned long)user->port,user->nick,user->ident,user->host,user->ip);
-}
-
-
-/* shows the message of the day, and any other on-logon stuff */
-void ConnectUser(userrec *user)
-{
- // dns is already done, things are fast. no need to wait for dns to complete just pass them straight on
- if ((user->dns_done) && (user->registered >= 3) && (AllModulesReportReady(user)))
- {
- FullConnectUser(user);
- }
+ WriteOpers("*** Client connecting on port %lu: %s!%s@%s [%s]",(unsigned long)user->port,user->nick,user->ident,user->host,(char*)inet_ntoa(user->ip4));
}
/* re-allocates a nick in the user_hash after they change nicknames,
char nick[MAXBUF];
int MOD_RESULT = 0;
- strcpy(nick,"");
+ *nick = 0;
- FOREACH_RESULT(OnUserPreNick(user,newnick));
+ FOREACH_RESULT(I_OnUserPreNick,OnUserPreNick(user,newnick));
if (MOD_RESULT) {
- stats->statsCollisions++;
+ ServerInstance->stats->statsCollisions++;
kill_link(user,"Nickname collision");
return;
}
if (matches_qline(newnick))
{
- stats->statsCollisions++;
+ ServerInstance->stats->statsCollisions++;
kill_link(user,"Nickname collision");
return;
}
{
if (newnick)
{
- strncpy(nick,newnick,MAXBUF);
+ strlcpy(nick,newnick,MAXBUF);
}
if (user->registered == 7)
{
char* pars[1];
pars[0] = nick;
- handle_nick(pars,1,user);
+ std::string cmd = "NICK";
+ ServerInstance->Parser->CallHandler(cmd,pars,1,user);
}
}
}