X-Git-Url: https://git.netwichtig.de/gitweb/?a=blobdiff_plain;f=src%2Fusers.cpp;h=ed979e337a29db2f5fa2183f6c26572604451b5d;hb=ed105d7fef72b5bb5f23e72fae40d6b4ffdcb5b8;hp=c98a690250630fb01772545f9642e3f13571895d;hpb=3bd571b8bb0cdc2900407a342dd3a77aff2c2d2a;p=user%2Fhenk%2Fcode%2Finspircd.git diff --git a/src/users.cpp b/src/users.cpp index c98a69025..ed979e337 100644 --- a/src/users.cpp +++ b/src/users.cpp @@ -31,10 +31,15 @@ unsigned long uniq_id = 0; 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(); @@ -43,30 +48,33 @@ bool InitTypes(ServerConfig* conf, const char* tag) 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); @@ -98,6 +106,24 @@ std::string userrec::ProcessNoticeMasks(const char *sm) 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))) { @@ -127,7 +153,7 @@ void userrec::StartDNSLookup() 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) @@ -136,10 +162,10 @@ void userrec::StartDNSLookup() } } -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(); } @@ -154,7 +180,12 @@ void UserResolver::OnLookupComplete(const std::string &result) /* 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); } } @@ -166,7 +197,9 @@ void UserResolver::OnLookupComplete(const std::string &result) 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) @@ -264,9 +297,10 @@ userrec::userrec(InspIRCd* Instance) : ServerInstance(Instance) *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 = ""; @@ -297,6 +331,26 @@ userrec::~userrec() 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; @@ -310,9 +364,9 @@ userrec::~userrec() } } -/* 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++) @@ -321,6 +375,21 @@ void userrec::MakeHost(char* nhost) 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() @@ -607,27 +676,42 @@ void userrec::FlushWriteBuf() { 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); + } } } } @@ -725,9 +809,6 @@ void userrec::QuitUser(InspIRCd* Instance, userrec *user, const std::string &qui 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)) @@ -800,7 +881,7 @@ namespace irc 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++) @@ -808,7 +889,7 @@ namespace irc 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); @@ -817,12 +898,71 @@ namespace irc } } } + /* 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"); @@ -834,6 +974,13 @@ void userrec::AddToWhoWas() 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 { @@ -841,9 +988,9 @@ void userrec::AddToWhoWas() 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(); @@ -880,7 +1027,7 @@ void userrec::AddClient(InspIRCd* Instance, int socket, int port, bool iscached, } Instance->Log(DEBUG,"AddClient: %d %d %s",socket,port,ipaddr); - + New = new userrec(Instance); Instance->clientlist[tempnick] = New; New->fd = socket; @@ -894,16 +1041,15 @@ void userrec::AddClient(InspIRCd* Instance, int socket, int port, bool iscached, 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; @@ -912,8 +1058,6 @@ void userrec::AddClient(InspIRCd* Instance, int socket, int port, bool iscached, 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))) @@ -928,8 +1072,6 @@ void userrec::AddClient(InspIRCd* Instance, int socket, int port, bool iscached, } } - 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; @@ -937,20 +1079,15 @@ void userrec::AddClient(InspIRCd* Instance, int socket, int port, bool iscached, New->sendqmax = class_sqmax; New->recvqmax = class_rqmax; - Instance->Log(DEBUG,"Push back to local users."); Instance->local_users.push_back(New); - Instance->Log(DEBUG,"Check softlimit: %d %d %d",Instance->local_users.size(), Instance->Config->SoftLimit, MAXCLIENTS); if ((Instance->local_users.size() > Instance->Config->SoftLimit) || (Instance->local_users.size() >= MAXCLIENTS)) { - Instance->Log(DEBUG,"Check softlimit failed"); Instance->WriteOpers("*** Warning: softlimit value has been reached: %d clients", Instance->Config->SoftLimit); userrec::QuitUser(Instance, New,"No more connections allowed"); return; } - Instance->Log(DEBUG,"Softlimit passed."); - /* * XXX - * this is done as a safety check to keep the file descriptors within range of fd_ref_table. @@ -967,79 +1104,50 @@ void userrec::AddClient(InspIRCd* Instance, int socket, int port, bool iscached, return; } - Instance->Log(DEBUG,"socket < MAX_DESCRIPTORS passed."); - - 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 u2[128]; - long x = 0; - strlcpy(u2, this->GetIPString(), 64); - - 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 - */ - ServerInstance->Log(DEBUG,"Match %s against %s", a->second->GetIPString(), u2); - if (strcasecmp(a->second->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::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) @@ -1074,9 +1182,7 @@ 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); @@ -1297,7 +1403,7 @@ const char* userrec::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; } @@ -1339,7 +1445,7 @@ const char* userrec::GetIPString(char* buf) /* 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)); } @@ -1399,6 +1505,7 @@ void userrec::Write(std::string text) this->AddWriteBuf(text); } ServerInstance->stats->statsSent += text.length(); + this->ServerInstance->SE->WantWrite(this); } /** Write() @@ -1753,9 +1860,10 @@ bool userrec::ChangeDisplayedHost(const char* host) 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) { @@ -1862,16 +1970,17 @@ void userrec::SplitChanList(userrec* dest, const std::string &cl) 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(); } @@ -1888,7 +1997,7 @@ void userrec::SplitChanList(userrec* dest, const std::string &cl) if (line.length()) { - this->Write(line); + ServerInstance->SendWhoisLine(this, dest, 319, "%s", line.c_str()); } } @@ -1987,16 +2096,27 @@ void userrec::ShowRULES() 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"); } } -