X-Git-Url: https://git.netwichtig.de/gitweb/?a=blobdiff_plain;f=src%2Fmodules%2Fm_spanningtree.cpp;h=22c9e92461acb262156cff05da6f2b3806363209;hb=c4458ecc70025aeac7ca87115ed0a698e7bbcdad;hp=7a59960f4a428d0d58979cc62d511323488b3e3e;hpb=4b40b54d80ced77d092aa7890b2bd07b364c9a9f;p=user%2Fhenk%2Fcode%2Finspircd.git diff --git a/src/modules/m_spanningtree.cpp b/src/modules/m_spanningtree.cpp index 7a59960f4..22c9e9246 100644 --- a/src/modules/m_spanningtree.cpp +++ b/src/modules/m_spanningtree.cpp @@ -41,11 +41,7 @@ using namespace std; #include "cull_list.h" #include "aes.h" -#ifdef GCC3 #define nspace __gnu_cxx -#else -#define nspace std -#endif /* * The server list in InspIRCd is maintained as two structures @@ -154,7 +150,7 @@ extern std::vector pelines; * are created and destroyed. */ -class TreeServer +class TreeServer : public classbase { TreeServer* Parent; /* Parent entry */ TreeServer* Route; /* Route entry */ @@ -167,8 +163,6 @@ class TreeServer TreeSocket* Socket; /* For directly connected servers this points at the socket object */ time_t NextPing; /* After this time, the server should be PINGed*/ bool LastPingWasGood; /* True if the server responded to the last PING with a PONG */ - std::map Users; /* Users on this server */ - bool DontModifyHash; /* When the server is splitting, this is set to true so we dont bash our own iterator to death */ public: @@ -183,7 +177,6 @@ class TreeServer VersionString = ""; UserCount = OperCount = 0; VersionString = Srv->GetVersion(); - DontModifyHash = false; } /* We use this constructor only to create the 'root' item, TreeRoot, which @@ -266,50 +259,26 @@ class TreeServer this->AddHashEntry(); } - void AddUser(userrec* user) - { - if (this->DontModifyHash) - return; - - log(DEBUG,"Add user %s to server %s",user->nick,this->ServerName.c_str()); - std::map::iterator iter; - iter = Users.find(user); - if (iter == Users.end()) - Users[user] = user; - } - - void DelUser(userrec* user) - { - /* FIX BY BRAIN: - * Quitting the user in QuitUsers changes the hash by removing the user here, - * corrupting the iterator! - * When netsplitting, this->DontModifyHash is set to prevent it now! - */ - if (this->DontModifyHash) - return; - - log(DEBUG,"Remove user %s from server %s",user->nick,this->ServerName.c_str()); - std::map::iterator iter; - iter = Users.find(user); - if (iter != Users.end()) - Users.erase(iter); - } - int QuitUsers(const std::string &reason) { - int x = Users.size(); log(DEBUG,"Removing all users from server %s",this->ServerName.c_str()); const char* reason_s = reason.c_str(); - this->DontModifyHash = true; - for (std::map::iterator n = Users.begin(); n != Users.end(); n++) + std::vector time_to_die; + for (user_hash::iterator n = clientlist.begin(); n != clientlist.end(); n++) { - log(DEBUG,"Kill %s fd=%d",n->second->nick,n->second->fd); - if (!IS_LOCAL(n->second)) - kill_link(n->second,reason_s); + if (!strcmp(n->second->server, this->ServerName.c_str())) + { + time_to_die.push_back(n->second); + } } - Users.clear(); - this->DontModifyHash = false; - return x; + for (std::vector::iterator n = time_to_die.begin(); n != time_to_die.end(); n++) + { + userrec* a = (userrec*)*n; + log(DEBUG,"Kill %s fd=%d",a->nick,a->fd); + if (!IS_LOCAL(a)) + kill_link(a,reason_s); + } + return time_to_die.size(); } /* This method is used to add the structure to the @@ -493,7 +462,7 @@ class TreeServer * of them, and populate the list on rehash/load. */ -class Link +class Link : public classbase { public: irc::string Name; @@ -586,9 +555,9 @@ class cmd_rconnect : public command_t cmd_rconnect (Module* Callback) : command_t("RCONNECT", 'o', 2), Creator(Callback) { this->source = "m_spanningtree.so"; - } + } - void Handle (char **parameters, int pcnt, userrec *user) + void Handle (const char** parameters, int pcnt, userrec *user) { WriteServ(user->fd,"NOTICE %s :*** RCONNECT: Sending remote connect to \002%s\002 to connect server \002%s\002.",user->nick,parameters[0],parameters[1]); /* Is this aimed at our server? */ @@ -596,7 +565,7 @@ class cmd_rconnect : public command_t { /* Yes, initiate the given connect */ WriteOpers("*** Remote CONNECT from %s matching \002%s\002, connecting server \002%s\002",user->nick,parameters[0],parameters[1]); - char* para[1]; + const char* para[1]; para[0] = parameters[1]; Creator->OnPreCommand("CONNECT", para, 1, user, true); } @@ -919,7 +888,7 @@ class TreeSocket : public InspSocket return true; userrec* who = new userrec(); who->fd = FD_MAGIC_NUMBER; - char* modelist[64]; + const char* modelist[64]; memset(&modelist,0,sizeof(modelist)); for (unsigned int q = 0; q < params.size(); q++) { @@ -957,7 +926,7 @@ class TreeSocket : public InspSocket userrec* user = Srv->FindNick(source); if (!user) { - WriteChannelWithServ((char*)source.c_str(), c, "TOPIC %s :%s", c->name, c->topic); + WriteChannelWithServ(source.c_str(), c, "TOPIC %s :%s", c->name, c->topic); } else { @@ -987,7 +956,7 @@ class TreeSocket : public InspSocket memset(&mode_users,0,sizeof(mode_users)); mode_users[0] = first; mode_users[1] = modestring; - strcpy(mode_users[1],"+"); + strcpy(first,"+"); unsigned int modectr = 2; userrec* who = NULL; @@ -1059,7 +1028,7 @@ class TreeSocket : public InspSocket { /* We also always let u-lined clients win, no matter what the TS value */ log(DEBUG,"Our our channel newer than theirs, accepting their modes"); - Srv->SendMode(mode_users,modectr,who); + Srv->SendMode((const char**)mode_users,modectr,who); } else { @@ -1089,7 +1058,7 @@ class TreeSocket : public InspSocket if (ourTS >= TS) { log(DEBUG,"Our our channel newer than theirs, accepting their modes"); - Srv->SendMode(mode_users,modectr,who); + Srv->SendMode((const char**)mode_users,modectr,who); } else { @@ -1139,18 +1108,17 @@ class TreeSocket : public InspSocket // NICK age nick host dhost ident +modes ip :gecos // 0 123 4 56 7 time_t age = atoi(params[0].c_str()); - std::string modes = params[5]; - while (*(modes.c_str()) == '+') - { - char* m = (char*)modes.c_str(); - m++; - modes = m; - } - char* tempnick = (char*)params[1].c_str(); + + /* This used to have a pretty craq'y loop doing the same thing, + * now we just let the STL do the hard work (more efficiently) + */ + params[5] = params[5].substr(params[5].find_first_not_of('+')); + + const char* tempnick = params[1].c_str(); log(DEBUG,"Introduce client %s!%s@%s",tempnick,params[4].c_str(),params[2].c_str()); - user_hash::iterator iter; - iter = clientlist.find(tempnick); + user_hash::iterator iter = clientlist.find(tempnick); + if (iter != clientlist.end()) { // nick collision @@ -1164,32 +1132,19 @@ class TreeSocket : public InspSocket strlcpy(clientlist[tempnick]->nick, tempnick,NICKMAX-1); strlcpy(clientlist[tempnick]->host, params[2].c_str(),63); strlcpy(clientlist[tempnick]->dhost, params[3].c_str(),63); - clientlist[tempnick]->server = (char*)FindServerNamePtr(source.c_str()); + clientlist[tempnick]->server = FindServerNamePtr(source.c_str()); strlcpy(clientlist[tempnick]->ident, params[4].c_str(),IDENTMAX); strlcpy(clientlist[tempnick]->fullname, params[7].c_str(),MAXGECOS); clientlist[tempnick]->registered = 7; clientlist[tempnick]->signon = age; - strlcpy(clientlist[tempnick]->modes, modes.c_str(),53); - for (char *v = clientlist[tempnick]->modes; *v; v++) + + for (std::string::iterator v = params[5].begin(); v != params[5].end(); v++) { - switch (*v) - { - case 'i': - clientlist[tempnick]->modebits |= UM_INVISIBLE; - break; - case 'w': - clientlist[tempnick]->modebits |= UM_WALLOPS; - break; - case 's': - clientlist[tempnick]->modebits |= UM_SERVERNOTICE; - break; - default: - break; - } + clientlist[tempnick]->modes[(*v)-65] = 1; } inet_aton(params[6].c_str(),&clientlist[tempnick]->ip4); - WriteOpers("*** Client connecting at %s: %s!%s@%s [%s]",clientlist[tempnick]->server,clientlist[tempnick]->nick,clientlist[tempnick]->ident,clientlist[tempnick]->host,(char*)inet_ntoa(clientlist[tempnick]->ip4)); + WriteOpers("*** Client connecting at %s: %s!%s@%s [%s]",clientlist[tempnick]->server,clientlist[tempnick]->nick,clientlist[tempnick]->ident,clientlist[tempnick]->host, inet_ntoa(clientlist[tempnick]->ip4)); params[7] = ":" + params[7]; DoOneToAllButSender(source,"NICK",params,source); @@ -1198,7 +1153,7 @@ class TreeSocket : public InspSocket TreeServer* SourceServer = FindServer(source); if (SourceServer) { - SourceServer->AddUser(clientlist[tempnick]); + log(DEBUG,"Found source server of %s",clientlist[tempnick]->nick); SourceServer->AddUserCount(); } @@ -1382,7 +1337,7 @@ class TreeSocket : public InspSocket { if (u->second->registered == 7) { - snprintf(data,MAXBUF,":%s NICK %lu %s %s %s %s +%s %s :%s",u->second->server,(unsigned long)u->second->age,u->second->nick,u->second->host,u->second->dhost,u->second->ident,u->second->modes,(char*)inet_ntoa(u->second->ip4),u->second->fullname); + snprintf(data,MAXBUF,":%s NICK %lu %s %s %s %s +%s %s :%s",u->second->server,(unsigned long)u->second->age,u->second->nick,u->second->host,u->second->dhost,u->second->ident,u->second->FormatModes(),inet_ntoa(u->second->ip4),u->second->fullname); this->WriteLine(data); if (*u->second->oper) { @@ -1546,11 +1501,8 @@ class TreeSocket : public InspSocket userrec* u = Srv->FindNick(prefix); if (u) { + u->modes[UM_OPERATOR] = 1; strlcpy(u->oper,opertype.c_str(),NICKMAX-1); - if (!strchr(u->modes,'o')) - { - strcat(u->modes,"o"); - } DoOneToAllButSender(u->nick,"OPERTYPE",params,u->server); } return true; @@ -1573,7 +1525,9 @@ class TreeSocket : public InspSocket { std::deque par; par.push_back(params[1]); - DoOneToMany(u->nick,"NICK",par); + /* This is not required as one is sent in OnUserPostNick below + */ + //DoOneToMany(u->nick,"NICK",par); Srv->ChangeUserNick(u,params[1]); u->age = atoi(params[2].c_str()); } @@ -1637,6 +1591,7 @@ class TreeSocket : public InspSocket std::string reason = params[1]; params[1] = ":" + params[1]; DoOneToAllButSender(prefix,"KILL",params,sourceserv); + ::Write(who->fd, ":%s KILL %s :%s (%s)", sourceserv.c_str(), who->nick, sourceserv.c_str(), reason.c_str()); Srv->QuitUser(who,reason); } return true; @@ -1761,19 +1716,19 @@ class TreeSocket : public InspSocket { case 'Z': propogate = add_zline(atoi(params[4].c_str()), params[2].c_str(), params[5].c_str(), params[1].c_str()); - zline_set_creation_time((char*)params[1].c_str(), atoi(params[3].c_str())); + zline_set_creation_time(params[1].c_str(), atoi(params[3].c_str())); break; case 'Q': propogate = add_qline(atoi(params[4].c_str()), params[2].c_str(), params[5].c_str(), params[1].c_str()); - qline_set_creation_time((char*)params[1].c_str(), atoi(params[3].c_str())); + qline_set_creation_time(params[1].c_str(), atoi(params[3].c_str())); break; case 'E': propogate = add_eline(atoi(params[4].c_str()), params[2].c_str(), params[5].c_str(), params[1].c_str()); - eline_set_creation_time((char*)params[1].c_str(), atoi(params[3].c_str())); + eline_set_creation_time(params[1].c_str(), atoi(params[3].c_str())); break; case 'G': propogate = add_gline(atoi(params[4].c_str()), params[2].c_str(), params[5].c_str(), params[1].c_str()); - gline_set_creation_time((char*)params[1].c_str(), atoi(params[3].c_str())); + gline_set_creation_time(params[1].c_str(), atoi(params[3].c_str())); break; case 'K': propogate = add_kline(atoi(params[4].c_str()), params[2].c_str(), params[5].c_str(), params[1].c_str()); @@ -1872,7 +1827,7 @@ class TreeSocket : public InspSocket unsigned long signon = atoi(params[1].c_str()); unsigned long idle = atoi(params[2].c_str()); if ((who_to_send_to) && (who_to_send_to->fd > -1)) - do_whois(who_to_send_to,u,signon,idle,(char*)nick_whoised.c_str()); + do_whois(who_to_send_to,u,signon,idle,nick_whoised.c_str()); } else { @@ -2014,8 +1969,8 @@ class TreeSocket : public InspSocket TreeServer* CheckDupe = FindServer(servername); if (CheckDupe) { - this->WriteLine("ERROR :Server "+servername+" already exists on server "+CheckDupe->GetParent()->GetName()+"!"); - Srv->SendOpers("*** Server connection from \2"+servername+"\2 denied, already exists on server "+CheckDupe->GetParent()->GetName()); + this->WriteLine("ERROR :Server "+servername+" already exists!"); + Srv->SendOpers("*** Server connection from \2"+servername+"\2 denied, already exists"); return false; } TreeServer* Node = new TreeServer(servername,description,ParentOfThis,NULL); @@ -2201,37 +2156,28 @@ class TreeSocket : public InspSocket bool ProcessLine(std::string line) { - char* l = (char*)line.c_str(); - for (char* x = l; *x; x++) - { - if ((*x == '\r') || (*x == '\n')) - *x = 0; - } - if (!*l) - return true; - - log(DEBUG,"IN: %s",l); - std::deque params; - this->Split(l,true,params); - irc::string command = ""; - std::string prefix = ""; - if (((params[0].c_str())[0] == ':') && (params.size() > 1)) - { - prefix = params[0]; - command = params[1].c_str(); - char* pref = (char*)prefix.c_str(); - prefix = ++pref; - params.pop_front(); - params.pop_front(); - } - else + irc::string command; + std::string prefix; + + if (line.empty()) + return true; + + line = line.substr(0, line.find_first_of("\r\n")); + + log(DEBUG,"IN: %s", line.c_str()); + + this->Split(line.c_str(),true,params); + + if ((params[0][0] == ':') && (params.size() > 1)) { - prefix = ""; - command = params[0].c_str(); + prefix = params[0].substr(1); params.pop_front(); } + command = params[0].c_str(); + params.pop_front(); + if ((!this->ctx_in) && (command == "AES")) { std::string sserv = params[0]; @@ -2581,22 +2527,14 @@ class TreeSocket : public InspSocket } if (who) { - if (command == "QUIT") - { - TreeServer* s = FindServer(who->server); - if (s) - { - s->DelUser(who); - } - } - else if ((command == "NICK") && (params.size() > 0)) + if ((command == "NICK") && (params.size() > 0)) { /* On nick messages, check that the nick doesnt * already exist here. If it does, kill their copy, * and our copy. */ userrec* x = Srv->FindNick(params[0]); - if (x) + if ((x) && (x != who)) { std::deque p; p.push_back(params[0]); @@ -2617,10 +2555,10 @@ class TreeSocket : public InspSocket } // its a user target = who->server; - char* strparams[127]; + const char* strparams[127]; for (unsigned int q = 0; q < params.size(); q++) { - strparams[q] = (char*)params[q].c_str(); + strparams[q] = params[q].c_str(); } if (!Srv->CallCommandHandler(command.c_str(), strparams, params.size(), who)) { @@ -2688,6 +2626,38 @@ class TreeSocket : public InspSocket virtual int OnIncomingConnection(int newsock, char* ip) { + /* To prevent anyone from attempting to flood opers/DDoS by connecting to the server port, + * or discovering if this port is the server port, we don't allow connections from any + * IPs for which we don't have a link block. + */ + bool found = false; + char resolved_host[MAXBUF]; + vector::iterator i; + for (i = LinkBlocks.begin(); i != LinkBlocks.end(); i++) + { + if (i->IPAddr == ip) + { + found = true; + break; + } + /* XXX: Fixme: blocks for a very short amount of time, + * we should cache these on rehash/startup + */ + if (CleanAndResolve(resolved_host,i->IPAddr.c_str(),true)) + { + if (std::string(resolved_host) == ip) + { + found = true; + break; + } + } + } + if (!found) + { + WriteOpers("Server connection from %s denied (no link blocks with that IP address)", ip); + close(newsock); + return false; + } TreeSocket* s = new TreeSocket(newsock, ip); Srv->AddSocket(s); return true; @@ -3000,14 +2970,14 @@ class ModuleSpanningTree : public Module return serverlist.size(); } - void HandleLinks(char** parameters, int pcnt, userrec* user) + void HandleLinks(const char** parameters, int pcnt, userrec* user) { ShowLinks(TreeRoot,user,0); WriteServ(user->fd,"365 %s * :End of /LINKS list.",user->nick); return; } - void HandleLusers(char** parameters, int pcnt, userrec* user) + void HandleLusers(const char** parameters, int pcnt, userrec* user) { unsigned int n_users = usercnt(); @@ -3092,7 +3062,7 @@ class ModuleSpanningTree : public Module // (a character matrix), then draw the branches as a series of "L" shapes // from the nodes. This is not only friendlier on CPU it uses less stack. - void HandleMap(char** parameters, int pcnt, userrec* user) + void HandleMap(const char** parameters, int pcnt, userrec* user) { // This array represents a virtual screen which we will // "scratch" draw to, as the console device of an irc @@ -3148,7 +3118,7 @@ class ModuleSpanningTree : public Module return; } - int HandleSquit(char** parameters, int pcnt, userrec* user) + int HandleSquit(const char** parameters, int pcnt, userrec* user) { TreeServer* s = FindServerMask(parameters[0]); if (s) @@ -3178,7 +3148,7 @@ class ModuleSpanningTree : public Module return 1; } - int HandleTime(char** parameters, int pcnt, userrec* user) + int HandleTime(const char** parameters, int pcnt, userrec* user) { if ((user->fd > -1) && (pcnt)) { @@ -3202,7 +3172,7 @@ class ModuleSpanningTree : public Module return 1; } - int HandleRemoteWhois(char** parameters, int pcnt, userrec* user) + int HandleRemoteWhois(const char** parameters, int pcnt, userrec* user) { if ((user->fd > -1) && (pcnt > 1)) { @@ -3280,7 +3250,7 @@ class ModuleSpanningTree : public Module } } - int HandleVersion(char** parameters, int pcnt, userrec* user) + int HandleVersion(const char** parameters, int pcnt, userrec* user) { // we've already checked if pcnt > 0, so this is safe TreeServer* found = FindServerMask(parameters[0]); @@ -3317,7 +3287,7 @@ class ModuleSpanningTree : public Module return 1; } - int HandleConnect(char** parameters, int pcnt, userrec* user) + int HandleConnect(const char** parameters, int pcnt, userrec* user) { for (std::vector::iterator x = LinkBlocks.begin(); x < LinkBlocks.end(); x++) { @@ -3366,7 +3336,7 @@ class ModuleSpanningTree : public Module return 0; } - virtual int OnPreCommand(const std::string &command, char **parameters, int pcnt, userrec *user, bool validated) + virtual int OnPreCommand(const std::string &command, const char** parameters, int pcnt, userrec *user, bool validated) { /* If the command doesnt appear to be valid, we dont want to mess with it. */ if (!validated) @@ -3627,7 +3597,7 @@ class ModuleSpanningTree : public Module params.push_back(user->host); params.push_back(user->dhost); params.push_back(user->ident); - params.push_back("+"+std::string(user->modes)); + params.push_back("+"+std::string(user->FormatModes())); params.push_back((char*)inet_ntoa(user->ip4)); params.push_back(":"+std::string(user->fullname)); DoOneToMany(Srv->GetServerName(),"NICK",params); @@ -3886,6 +3856,13 @@ class ModuleSpanningTree : public Module (*params)[2] = ":" + (*params)[2]; DoOneToMany(Srv->GetServerName(),"METADATA",*params); } + else if (event->GetEventID() == "send_mode") + { + std::deque* params = (std::deque*)event->GetData(); + if (params->size() < 2) + return; + DoOneToMany(Srv->GetServerName(),"FMODE",*params); + } } virtual ~ModuleSpanningTree()