bool InitTypes(ServerConfig* conf, const char* tag)
{
- for (opertype_t::iterator n = conf->opertypes.begin(); n != conf->opertypes.end(); n++)
+ if (conf->opertypes.size())
{
- if (n->second)
- delete[] n->second;
+ conf->GetInstance()->Log(DEBUG,"Currently %d items to clear",conf->opertypes.size());
+ for (opertype_t::iterator n = conf->opertypes.begin(); n != conf->opertypes.end(); n++)
+ {
+ conf->GetInstance()->Log(DEBUG,"Clear item");
+ if (n->second)
+ delete[] n->second;
+ }
}
conf->opertypes.clear();
bool InitClasses(ServerConfig* conf, const char* tag)
{
- for (operclass_t::iterator n = conf->operclass.begin(); n != conf->operclass.end(); n++)
+ if (conf->operclass.size())
{
- if (n->second)
- delete[] n->second;
+ for (operclass_t::iterator n = conf->operclass.begin(); n != conf->operclass.end(); n++)
+ {
+ if (n->second)
+ delete[] n->second;
+ }
}
conf->operclass.clear();
return true;
}
-bool DoType(ServerConfig* conf, const char* tag, char** entries, void** values, int* types)
+bool DoType(ServerConfig* conf, const char* tag, char** entries, ValueList &values, int* types)
{
- char* TypeName = (char*)values[0];
- char* Classes = (char*)values[1];
+ const char* TypeName = values[0].GetString();
+ const char* Classes = values[1].GetString();
conf->opertypes[TypeName] = strdup(Classes);
conf->GetInstance()->Log(DEBUG,"Read oper TYPE '%s' with classes '%s'",TypeName,Classes);
return true;
}
-bool DoClass(ServerConfig* conf, const char* tag, char** entries, void** values, int* types)
+bool DoClass(ServerConfig* conf, const char* tag, char** entries, ValueList &values, int* types)
{
- char* ClassName = (char*)values[0];
- char* CommandList = (char*)values[1];
+ const char* ClassName = values[0].GetString();
+ const char* CommandList = values[1].GetString();
conf->operclass[ClassName] = strdup(CommandList);
conf->GetInstance()->Log(DEBUG,"Read oper CLASS '%s' with commands '%s'",ClassName,CommandList);
case '-':
adding = false;
break;
+ case '*':
+ for (unsigned char d = 'A'; d <= 'z'; d++)
+ {
+ if (ServerInstance->SNO->IsEnabled(d))
+ {
+ if ((!IsNoticeMaskSet(d) && adding) || (IsNoticeMaskSet(d) && !adding))
+ {
+ if ((oldadding != adding) || (!output.length()))
+ output += (adding ? '+' : '-');
+
+ this->SetNoticeMask(d, adding);
+
+ output += d;
+ }
+ }
+ oldadding = adding;
+ }
+ break;
default:
if ((*c >= 'A') && (*c <= 'z') && (ServerInstance->SNO->IsEnabled(*c)))
{
try
{
ServerInstance->Log(DEBUG,"Passing instance: %08x",this->ServerInstance);
- res_reverse = new UserResolver(this->ServerInstance, this, this->GetIPString(), false);
+ res_reverse = new UserResolver(this->ServerInstance, this, this->GetIPString(), DNS_QUERY_REVERSE);
this->ServerInstance->AddResolver(res_reverse);
}
catch (ModuleException& e)
}
}
-UserResolver::UserResolver(InspIRCd* Instance, userrec* user, std::string to_resolve, bool forward) :
- Resolver(Instance, to_resolve, forward ? DNS_QUERY_FORWARD : DNS_QUERY_REVERSE), bound_user(user)
+UserResolver::UserResolver(InspIRCd* Instance, userrec* user, std::string to_resolve, QueryType qt) :
+ Resolver(Instance, to_resolve, qt), bound_user(user)
{
- this->fwd = forward;
+ this->fwd = (qt == DNS_QUERY_A || qt == DNS_QUERY_AAAA);
this->bound_fd = user->GetFd();
}
/* Check we didnt time out */
if (this->bound_user->registered != REG_ALL)
{
- bound_user->res_forward = new UserResolver(this->ServerInstance, this->bound_user, result, true);
+#ifdef IPV6
+ const char *ip = this->bound_user->GetIPString();
+ bound_user->res_forward = new UserResolver(this->ServerInstance, this->bound_user, result, (strstr(ip,"0::ffff:") == ip ? DNS_QUERY_A : DNS_QUERY_AAAA));
+#else
+ bound_user->res_forward = new UserResolver(this->ServerInstance, this->bound_user, result, DNS_QUERY_A);
+#endif
this->ServerInstance->AddResolver(bound_user->res_forward);
}
}
else if ((this->fwd) && (ServerInstance->SE->GetRef(this->bound_fd) == this->bound_user))
{
/* Both lookups completed */
- if (this->bound_user->GetIPString() == result)
+ std::string result2 = "0::ffff:";
+ result2.append(result);
+ if (this->bound_user->GetIPString() == result || this->bound_user->GetIPString() == result2)
{
std::string hostname = this->bound_user->stored_host;
if (hostname.length() < 65)
*password = *nick = *ident = *host = *dhost = *fullname = *awaymsg = *oper = 0;
server = (char*)Instance->FindServerNamePtr(Instance->Config->ServerName);
reset_due = ServerInstance->Time();
+ age = ServerInstance->Time(true);
lines_in = lastping = signon = idle_lastmsg = nping = registered = 0;
ChannelCount = timeout = flood = bytes_in = bytes_out = cmds_in = cmds_out = 0;
- haspassed = dns_done = false;
+ exempt = haspassed = dns_done = false;
fd = -1;
recvq = "";
sendq = "";
for (unsigned int n = 0; n < MAXCHANS; n++)
{
- ucrec* x = new ucrec();
- chans[n] = x;
- x->channel = NULL;
- x->uc_modes = 0;
+ chans[n] = new ucrec();
+ chans[n]->channel = NULL;
+ chans[n]->uc_modes = 0;
}
}
if (ip)
{
+ clonemap::iterator x = ServerInstance->local_clones.find(this->GetIPString());
+ if (x != ServerInstance->local_clones.end())
+ {
+ x->second--;
+ if (!x->second)
+ {
+ ServerInstance->local_clones.erase(x);
+ }
+ }
+
+ clonemap::iterator y = ServerInstance->global_clones.find(this->GetIPString());
+ if (y != ServerInstance->global_clones.end())
+ {
+ y->second--;
+ if (!y->second)
+ {
+ ServerInstance->global_clones.erase(y);
+ }
+ }
+
if (this->GetProtocolFamily() == AF_INET)
{
delete (sockaddr_in*)ip;
}
}
-/* XXX - minor point, other *Host functions return a char *, this one creates it. Might be nice to be consistant? */
-void userrec::MakeHost(char* nhost)
+char* userrec::MakeHost()
{
+ static char nhost[MAXBUF];
/* This is much faster than snprintf */
char* t = nhost;
for(char* n = ident; *n; n++)
for(char* n = host; *n; n++)
*t++ = *n;
*t = 0;
+ return nhost;
+}
+
+char* userrec::MakeHostIP()
+{
+ static char ihost[MAXBUF];
+ /* This is much faster than snprintf */
+ char* t = ihost;
+ for(char* n = ident; *n; n++)
+ *t++ = *n;
+ *t++ = '@';
+ for(const char* n = this->GetIPString(); *n; n++)
+ *t++ = *n;
+ *t = 0;
+ return ihost;
}
void userrec::CloseSocket()
{
try
{
- if (this->fd == FD_MAGIC_NUMBER)
+ if ((this->fd == FD_MAGIC_NUMBER) || (*this->GetWriteError()))
{
sendq = "";
}
if ((sendq.length()) && (this->fd != FD_MAGIC_NUMBER))
{
+ int old_sendq_length = sendq.length();
const char* tb = this->sendq.c_str();
int n_sent = write(this->fd,tb,this->sendq.length());
if (n_sent == -1)
{
- if (errno != EAGAIN)
- this->SetWriteError(strerror(errno));
+ if (errno == EAGAIN)
+ {
+ ServerInstance->Log(DEBUG,"EAGAIN, want write");
+ this->ServerInstance->SE->WantWrite(this);
+ }
+ else
+ {
+ this->QuitUser(ServerInstance, this, strerror(errno));
+ return;
+ }
}
else
{
+ /*ServerInstance->Log(DEBUG,"Wrote: %d of %d: %s", n_sent, old_sendq_length, sendq.substr(0, n_sent).c_str());*/
// advance the queue
tb += n_sent;
this->sendq = tb;
// update the user's stats counters
this->bytes_out += n_sent;
this->cmds_out++;
+ if (n_sent != old_sendq_length)
+ {
+ ServerInstance->Log(DEBUG,"Not all written, want write");
+ this->ServerInstance->SE->WantWrite(this);
+ }
}
}
}
user->WriteCommonExcept("QUIT :%s",reason.c_str());
}
- if (IS_LOCAL(user))
- user->FlushWriteBuf();
-
FOREACH_MOD_I(Instance,I_OnUserDisconnect,OnUserDisconnect(user));
if (IS_LOCAL(user))
free(gecos);
}
- /* every hour, run this function which removes all entries over 3 days */
+ /* every hour, run this function which removes all entries older than Config->WhoWasMaxKeep */
void MaintainWhoWas(InspIRCd* ServerInstance, time_t t)
{
for (whowas_users::iterator iter = ServerInstance->whowas.begin(); iter != ServerInstance->whowas.end(); iter++)
whowas_set* n = (whowas_set*)iter->second;
if (n->size())
{
- while ((n->begin() != n->end()) && ((*n->begin())->signon < t - 259200)) // 3 days
+ while ((n->begin() != n->end()) && ((*n->begin())->signon < t - ServerInstance->Config->WhoWasMaxKeep))
{
WhoWasGroup *a = *(n->begin());
DELETE(a);
}
}
}
+ /* on rehash, refactor maps according to new conf values */
+ void PruneWhoWas(InspIRCd* ServerInstance, time_t t)
+ {
+ /* config values */
+ int groupsize = ServerInstance->Config->WhoWasGroupSize;
+ int maxgroups = ServerInstance->Config->WhoWasMaxGroups;
+ int maxkeep = ServerInstance->Config->WhoWasMaxKeep;
+
+ int groupcount = ServerInstance->whowas.size();
+ /* iterate whowas_fifo oldest first */
+ whowas_users_fifo::iterator iter, safeiter;
+ for (iter = ServerInstance->whowas_fifo.begin(); iter != ServerInstance->whowas_fifo.end(); iter++)
+ {
+ /** prune all groups that has expired due to new maxkeep time and
+ * also any group number higher than new maxgroups. The oldest are
+ * removed first due to iteration over whowas_fifo
+ */
+ if (groupcount > maxgroups || iter->first < t - maxkeep)
+ {
+ whowas_set* n = (whowas_set*)ServerInstance->whowas.find(iter->second)->second;
+ if (n->size())
+ {
+ while (n->begin() != n->end())
+ {
+ WhoWasGroup *a = *(n->begin());
+ DELETE(a);
+ n->erase(n->begin());
+ }
+ }
+ ServerInstance->whowas.erase(iter->second);
+ /* use a safe iter copy for erase and set the orig iter old valid ref by decrementing it */
+ safeiter = iter;
+ --iter;
+ ServerInstance->whowas_fifo.erase(safeiter);
+ }
+ else {
+ /* also trim individual groupsizes in case groupsize should have been lowered */
+ whowas_set* n = (whowas_set*)ServerInstance->whowas.find(iter->second)->second;
+ if (n->size())
+ {
+ int nickcount = n->size();
+ while (n->begin() != n->end() && nickcount > groupsize)
+ {
+ WhoWasGroup *a = *(n->begin());
+ DELETE(a);
+ n->erase(n->begin());
+ nickcount--;
+ }
+ }
+ }
+ groupcount--;
+ }
+ }
};
};
/* adds or updates an entry in the whowas list */
void userrec::AddToWhoWas()
{
+ /* if whowas disabled */
+ if (ServerInstance->Config->WhoWasGroupSize == 0 || ServerInstance->Config->WhoWasMaxGroups == 0)
+ {
+ return;
+ }
+
irc::whowas::whowas_users::iterator iter = ServerInstance->whowas.find(this->nick);
ServerInstance->Log(DEBUG,"Add to whowas lists");
irc::whowas::WhoWasGroup *a = new irc::whowas::WhoWasGroup(this);
n->push_back(a);
ServerInstance->whowas[this->nick] = n;
+ ServerInstance->whowas_fifo[ServerInstance->Time()] = this->nick;
+ if ((int)(ServerInstance->whowas.size()) > ServerInstance->Config->WhoWasMaxGroups)
+ {
+ ServerInstance->Log(DEBUG,"Maxgroups of %d reached deleting oldest group '%s'",ServerInstance->Config->WhoWasMaxGroups, ServerInstance->whowas_fifo.begin()->second.c_str());
+ ServerInstance->whowas.erase(ServerInstance->whowas_fifo.begin()->second);
+ ServerInstance->whowas_fifo.erase(ServerInstance->whowas_fifo.begin());
+ }
}
else
{
ServerInstance->Log(DEBUG,"Using existing whowas group for %s",this->nick);
- if (group->size() > 10)
+ if ((int)(group->size()) >= ServerInstance->Config->WhoWasGroupSize)
{
- ServerInstance->Log(DEBUG,"Trimming existing group to ten entries for %s",this->nick);
+ ServerInstance->Log(DEBUG,"Trimming existing group '%s' to %d entries",this->nick, ServerInstance->Config->WhoWasGroupSize);
irc::whowas::WhoWasGroup *a = (irc::whowas::WhoWasGroup*)*(group->begin());
DELETE(a);
group->pop_front();
}
Instance->Log(DEBUG,"AddClient: %d %d %s",socket,port,ipaddr);
-
+
New = new userrec(Instance);
Instance->clientlist[tempnick] = New;
New->fd = socket;
New->signon = Instance->Time() + Instance->Config->dns_timeout;
New->lastping = 1;
- Instance->Log(DEBUG,"Setting socket addresses");
New->SetSockAddr(AF_FAMILY, ipaddr, port);
- Instance->Log(DEBUG,"Socket addresses set.");
/* Smarter than your average bear^H^H^H^Hset of strlcpys. */
for (const char* temp = New->GetIPString(); *temp && j < 64; temp++, j++)
New->dhost[j] = New->host[j] = *temp;
New->dhost[j] = New->host[j] = 0;
-
- Instance->Log(DEBUG,"Hosts set.");
+
+ Instance->AddLocalClone(New);
+ Instance->AddGlobalClone(New);
// set the registration timeout for this user
unsigned long class_regtimeout = 90;
long class_sqmax = 262144; // 256kb
long class_rqmax = 4096; // 4k
- Instance->Log(DEBUG,"Class stuff set.");
-
for (ClassVector::iterator i = Instance->Config->Classes.begin(); i != Instance->Config->Classes.end(); i++)
{
if ((i->type == CC_ALLOW) && (match(ipaddr,i->host.c_str(),true)))
}
}
- Instance->Log(DEBUG,"nping etc set.");
-
New->nping = Instance->Time() + New->pingmax + Instance->Config->dns_timeout;
New->timeout = Instance->Time() + class_regtimeout;
New->flood = class_flood;
if ((Instance->local_users.size() > Instance->Config->SoftLimit) || (Instance->local_users.size() >= MAXCLIENTS))
{
+ Instance->WriteOpers("*** Warning: softlimit value has been reached: %d clients", Instance->Config->SoftLimit);
userrec::QuitUser(Instance, New,"No more connections allowed");
return;
}
return;
}
- ELine* e = Instance->XLines->matches_exception(New);
- if (!e)
+ New->exempt = (Instance->XLines->matches_exception(New) != NULL);
+ if (!New->exempt)
{
- Instance->Log(DEBUG,"Doesnt match eline.");
ZLine* r = Instance->XLines->matches_zline(ipaddr);
if (r)
{
- Instance->Log(DEBUG,"Matches zline.");
char reason[MAXBUF];
snprintf(reason,MAXBUF,"Z-Lined: %s",r->reason);
userrec::QuitUser(Instance, New, reason);
return;
}
- Instance->Log(DEBUG,"Doesnt match zline.");
}
- Instance->Log(DEBUG,"Check before AddFd.");
-
if (socket > -1)
{
- Instance->Log(DEBUG,"Adding fd.");
if (!Instance->SE->AddFd(New))
{
- Instance->Log(DEBUG,"Oops, fd already exists");
userrec::QuitUser(Instance, New, "Internal error handling connection");
return;
}
}
+ /* NOTE: even if dns lookups are *off*, we still need to display this.
+ * BOPM and other stuff requires it.
+ */
New->WriteServ("NOTICE Auth :*** Looking up your hostname...");
}
long userrec::GlobalCloneCount()
{
- char u1[128];
- char u2[128];
- long x = 0;
-
- for (user_hash::const_iterator a = ServerInstance->clientlist.begin(); a != ServerInstance->clientlist.end(); a++)
- {
- /* We have to match ip's as strings - we don't know what protocol
- * a remote user may be using
- */
- if (strcmp(a->second->GetIPString(u1), this->GetIPString(u2)) == 0)
- x++;
- }
-
- return x;
+ clonemap::iterator x = ServerInstance->global_clones.find(this->GetIPString());
+ if (x != ServerInstance->global_clones.end())
+ return x->second;
+ else
+ return 0;
}
long userrec::LocalCloneCount()
{
- long x = 0;
- for (std::vector<userrec*>::const_iterator a = ServerInstance->local_users.begin(); a != ServerInstance->local_users.end(); a++)
- {
- userrec* comp = *a;
-#ifdef IPV6
- /* I dont think theres any faster way of matching two ipv6 addresses than memcmp */
- in6_addr* s1 = &(((sockaddr_in6*)comp->ip)->sin6_addr);
- in6_addr* s2 = &(((sockaddr_in6*)this->ip)->sin6_addr);
- if (!memcmp(s1->s6_addr, s2->s6_addr, sizeof(in6_addr)))
- x++;
-#else
- in_addr* s1 = &((sockaddr_in*)comp->ip)->sin_addr;
- in_addr* s2 = &((sockaddr_in*)this->ip)->sin_addr;
- if (s1->s_addr == s2->s_addr)
- x++;
-#endif
- }
- return x;
+ clonemap::iterator x = ServerInstance->local_clones.find(this->GetIPString());
+ if (x != ServerInstance->local_clones.end())
+ return x->second;
+ else
+ return 0;
}
void userrec::FullConnect(CullList* Goners)
return;
}
- ELine* e = ServerInstance->XLines->matches_exception(this);
-
- if (!e)
+ if (!this->exempt)
{
GLine* r = ServerInstance->XLines->matches_gline(this);
* changes dont go out onto the network and produce 'fake direction'.
*/
FOREACH_MOD(I_OnUserConnect,OnUserConnect(this));
- FOREACH_MOD(I_OnPostConnect,OnPostConnect(this));
+
this->registered = REG_ALL;
+
+ FOREACH_MOD(I_OnPostConnect,OnPostConnect(this));
+
ServerInstance->SNO->WriteToSnoMask('c',"Client connecting on port %d: %s!%s@%s [%s]", this->GetPort(), this->nick, this->ident, this->host, this->GetIPString());
}
/* IP addresses starting with a : on irc are a Bad Thing (tm) */
if (*buf == ':')
{
- strlcpy(&temp[1], buf, sizeof(temp));
+ strlcpy(&temp[1], buf, sizeof(temp) - 1);
*temp = '0';
return temp;
}
/* IP addresses starting with a : on irc are a Bad Thing (tm) */
if (*buf == ':')
{
- strlcpy(&temp[1], buf, sizeof(temp));
+ strlcpy(&temp[1], buf, sizeof(temp) - 1);
*temp = '0';
strlcpy(buf, temp, sizeof(temp));
}
this->AddWriteBuf(text);
}
ServerInstance->stats->statsSent += text.length();
+ this->ServerInstance->SE->WantWrite(this);
}
/** Write()
FOREACH_MOD(I_OnChangeHost,OnChangeHost(this,host));
}
if (this->ServerInstance->Config->CycleHosts)
- this->WriteCommonExcept("%s","QUIT :Changing hosts");
+ this->WriteCommonExcept("QUIT :Changing hosts");
- strlcpy(this->dhost,host,63);
+ /* Fix by Om: userrec::dhost is 65 long, this was truncating some long hosts */
+ strlcpy(this->dhost,host,64);
if (this->ServerInstance->Config->CycleHosts)
{
try
{
- prefix << ":" << ServerInstance->Config->ServerName << " 319 " << this->nick << " " << dest->nick << " :";
+ prefix << this->nick << " " << dest->nick << " :";
line = prefix.str();
+ int namelen = strlen(ServerInstance->Config->ServerName) + 6;
for (start = 0; (pos = cl.find(' ', start)) != std::string::npos; start = pos+1)
{
length = (pos == std::string::npos) ? cl.length() : pos;
- if (line.length() + length - start > 510)
+ if (line.length() + namelen + length - start > 510)
{
- this->Write(line);
+ ServerInstance->SendWhoisLine(this, dest, 319, "%s", line.c_str());
line = prefix.str();
}
if (line.length())
{
- this->Write(line);
+ ServerInstance->SendWhoisLine(this, dest, 319, "%s", line.c_str());
}
}
this->WriteServ("NOTICE %s :End of %s rules.",this->nick,ServerInstance->Config->ServerName);
}
-void userrec::HandleEvent(EventType et)
+void userrec::HandleEvent(EventType et, int errornum)
{
/* WARNING: May delete this user! */
try
{
- ServerInstance->ProcessUser(this);
+ switch (et)
+ {
+ case EVENT_READ:
+ ServerInstance->ProcessUser(this);
+ break;
+ case EVENT_WRITE:
+ this->FlushWriteBuf();
+ break;
+ case EVENT_ERROR:
+ /** This should be safe, but dont DARE do anything after it -- Brain */
+ userrec::QuitUser(ServerInstance, this, errornum ? strerror(errornum) : "EOF from client");
+ break;
+ }
}
catch (...)
{
ServerInstance->Log(DEBUG,"Exception in userrec::HandleEvent intercepted");
}
}
-