X-Git-Url: https://git.netwichtig.de/gitweb/?a=blobdiff_plain;f=src%2Fmodules%2Fm_spanningtree%2Fmain.cpp;h=fbc6ad40c8059d88493b747b60e7377867c6ec63;hb=687778b72e31322a73b2e2e17af6bd0f2a2561bc;hp=81543b0da1693bbaf52bb004bae9e50132f3d075;hpb=7770cd985405c7630e9149fc08c314ec824a9c75;p=user%2Fhenk%2Fcode%2Finspircd.git diff --git a/src/modules/m_spanningtree/main.cpp b/src/modules/m_spanningtree/main.cpp index 81543b0da..fbc6ad40c 100644 --- a/src/modules/m_spanningtree/main.cpp +++ b/src/modules/m_spanningtree/main.cpp @@ -25,7 +25,6 @@ #include "socket.h" #include "xline.h" #include "iohook.h" -#include "modules/spanningtree.h" #include "resolvers.h" #include "main.h" @@ -37,11 +36,21 @@ #include "translate.h" ModuleSpanningTree::ModuleSpanningTree() - : rconnect(this), rsquit(this), map(this) + : Away::EventListener(this) + , Stats::EventListener(this) + , CTCTags::EventListener(this) + , rconnect(this) + , rsquit(this) + , map(this) , commands(this) , currmembid(0) - , eventprov(this, "event/spanningtree") + , broadcasteventprov(this, "event/server-broadcast") + , linkeventprov(this, "event/server-link") + , messageeventprov(this, "event/server-message") + , synceventprov(this, "event/server-sync") + , sslapi(this) , DNS(this, "DNS") + , tagevprov(this, "event/messagetag") , loopCall(false) { } @@ -133,26 +142,12 @@ void ModuleSpanningTree::ShowLinks(TreeServer* Current, User* user, int hops) InspIRCd::Format("%d %s", (((Utils->FlatLinks) && (!user->IsOper())) ? 0 : hops), Current->GetDesc().c_str())); } -void ModuleSpanningTree::HandleLinks(const std::vector& parameters, User* user) +void ModuleSpanningTree::HandleLinks(const CommandBase::Params& parameters, User* user) { ShowLinks(Utils->TreeRoot,user,0); user->WriteNumeric(RPL_ENDOFLINKS, '*', "End of /LINKS list."); } -std::string ModuleSpanningTree::TimeToStr(time_t secs) -{ - time_t mins_up = secs / 60; - time_t hours_up = mins_up / 60; - time_t days_up = hours_up / 24; - secs = secs % 60; - mins_up = mins_up % 60; - hours_up = hours_up % 24; - return ((days_up ? (ConvToStr(days_up) + "d") : "") - + (hours_up ? (ConvToStr(hours_up) + "h") : "") - + (mins_up ? (ConvToStr(mins_up) + "m") : "") - + ConvToStr(secs) + "s"); -} - void ModuleSpanningTree::ConnectServer(Autoconnect* a, bool on_timer) { if (!a) @@ -192,33 +187,35 @@ void ModuleSpanningTree::ConnectServer(Autoconnect* a, bool on_timer) void ModuleSpanningTree::ConnectServer(Link* x, Autoconnect* y) { - bool ipvalid = true; - - if (InspIRCd::Match(ServerInstance->Config->ServerName, assign(x->Name), rfc_case_insensitive_map)) + if (InspIRCd::Match(ServerInstance->Config->ServerName, x->Name, ascii_case_insensitive_map)) { ServerInstance->SNO->WriteToSnoMask('l', "CONNECT: Not connecting to myself."); return; } - DNS::QueryType start_type = DNS::QUERY_AAAA; - if (strchr(x->IPAddr.c_str(),':')) + irc::sockets::sockaddrs sa; + if (x->IPAddr.find('/') != std::string::npos) { - in6_addr n; - if (inet_pton(AF_INET6, x->IPAddr.c_str(), &n) < 1) - ipvalid = false; + if (!irc::sockets::isunix(x->IPAddr) || !irc::sockets::untosa(x->IPAddr, sa)) + { + // We don't use the family() != AF_UNSPEC check below for UNIX sockets as + // that results in a DNS lookup. + ServerInstance->SNO->WriteToSnoMask('l', "CONNECT: Error connecting \002%s\002: %s is not a UNIX socket!", + x->Name.c_str(), x->IPAddr.c_str()); + return; + } } else { - in_addr n; - if (inet_aton(x->IPAddr.c_str(),&n) < 1) - ipvalid = false; + // If this fails then the IP sa will be AF_UNSPEC. + irc::sockets::aptosa(x->IPAddr, x->Port, sa); } - + /* Do we already have an IP? If so, no need to resolve it. */ - if (ipvalid) + if (sa.family() != AF_UNSPEC) { // Create a TreeServer object that will start connecting immediately in the background - TreeSocket* newsocket = new TreeSocket(x, y, x->IPAddr); + TreeSocket* newsocket = new TreeSocket(x, y, sa); if (newsocket->GetFd() > -1) { /* Handled automatically on success */ @@ -232,10 +229,19 @@ void ModuleSpanningTree::ConnectServer(Link* x, Autoconnect* y) } else if (!DNS) { - ServerInstance->SNO->WriteToSnoMask('l', "CONNECT: Error connecting \002%s\002: Hostname given and m_dns.so is not loaded, unable to resolve.", x->Name.c_str()); + ServerInstance->SNO->WriteToSnoMask('l', "CONNECT: Error connecting \002%s\002: Hostname given and core_dns is not loaded, unable to resolve.", x->Name.c_str()); } else { + // Guess start_type from bindip aftype + DNS::QueryType start_type = DNS::QUERY_AAAA; + irc::sockets::sockaddrs bind; + if ((!x->Bind.empty()) && (irc::sockets::aptosa(x->Bind, 0, bind))) + { + if (bind.family() == AF_INET) + start_type = DNS::QUERY_A; + } + ServernameResolver* snr = new ServernameResolver(*DNS, x->IPAddr, x, start_type, y); try { @@ -265,12 +271,12 @@ void ModuleSpanningTree::AutoConnectServers(time_t curtime) void ModuleSpanningTree::DoConnectTimeout(time_t curtime) { - std::map >::iterator i = Utils->timeoutlist.begin(); + SpanningTreeUtilities::TimeoutList::iterator i = Utils->timeoutlist.begin(); while (i != Utils->timeoutlist.end()) { TreeSocket* s = i->first; - std::pair p = i->second; - std::map >::iterator me = i; + std::pair p = i->second; + SpanningTreeUtilities::TimeoutList::iterator me = i; i++; if (s->GetLinkState() == DYING) { @@ -279,14 +285,14 @@ void ModuleSpanningTree::DoConnectTimeout(time_t curtime) } else if (curtime > s->age + p.second) { - ServerInstance->SNO->WriteToSnoMask('l',"CONNECT: Error connecting \002%s\002 (timeout of %d seconds)",p.first.c_str(),p.second); + ServerInstance->SNO->WriteToSnoMask('l',"CONNECT: Error connecting \002%s\002 (timeout of %u seconds)",p.first.c_str(),p.second); Utils->timeoutlist.erase(me); s->Close(); } } } -ModResult ModuleSpanningTree::HandleVersion(const std::vector& parameters, User* user) +ModResult ModuleSpanningTree::HandleVersion(const CommandBase::Params& parameters, User* user) { // We've already confirmed that !parameters.empty(), so this is safe TreeServer* found = Utils->FindServerMask(parameters[0]); @@ -303,8 +309,12 @@ ModResult ModuleSpanningTree::HandleVersion(const std::vector& para // If it's empty it might be that the server is still syncing (full version hasn't arrived yet) // or the server is a 2.0 server and does not send a full version. bool showfull = ((user->IsOper()) && (!found->GetFullVersion().empty())); - const std::string& Version = (showfull ? found->GetFullVersion() : found->GetVersion()); - user->WriteNumeric(RPL_VERSION, Version); + + Numeric::Numeric numeric(RPL_VERSION); + irc::tokenstream tokens(showfull ? found->GetFullVersion() : found->GetVersion()); + for (std::string token; tokens.GetTrailing(token); ) + numeric.push(token); + user->WriteNumeric(numeric); } else { @@ -313,20 +323,20 @@ ModResult ModuleSpanningTree::HandleVersion(const std::vector& para return MOD_RES_DENY; } -ModResult ModuleSpanningTree::HandleConnect(const std::vector& parameters, User* user) +ModResult ModuleSpanningTree::HandleConnect(const CommandBase::Params& parameters, User* user) { for (std::vector >::iterator i = Utils->LinkBlocks.begin(); i < Utils->LinkBlocks.end(); i++) { Link* x = *i; - if (InspIRCd::Match(x->Name.c_str(),parameters[0], rfc_case_insensitive_map)) + if (InspIRCd::Match(x->Name, parameters[0], ascii_case_insensitive_map)) { - if (InspIRCd::Match(ServerInstance->Config->ServerName, assign(x->Name), rfc_case_insensitive_map)) + if (InspIRCd::Match(ServerInstance->Config->ServerName, x->Name, ascii_case_insensitive_map)) { user->WriteRemoteNotice(InspIRCd::Format("*** CONNECT: Server \002%s\002 is ME, not connecting.", x->Name.c_str())); return MOD_RES_DENY; } - TreeServer* CheckDupe = Utils->FindServer(x->Name.c_str()); + TreeServer* CheckDupe = Utils->FindServer(x->Name); if (!CheckDupe) { user->WriteRemoteNotice(InspIRCd::Format("*** CONNECT: Connecting to server: \002%s\002 (%s:%d)", x->Name.c_str(), (x->HiddenFromStats ? "" : x->IPAddr.c_str()), x->Port)); @@ -349,14 +359,26 @@ void ModuleSpanningTree::OnUserInvite(User* source, User* dest, Channel* channel if (IS_LOCAL(source)) { CmdBuilder params(source, "INVITE"); - params.push_back(dest->uuid); - params.push_back(channel->name); + params.push(dest->uuid); + params.push(channel->name); params.push_int(channel->age); - params.push_back(ConvToStr(expiry)); + params.push(ConvToStr(expiry)); params.Broadcast(); } } +ModResult ModuleSpanningTree::OnPreTopicChange(User* user, Channel* chan, const std::string& topic) +{ + // XXX: Deny topic changes if the current topic set time is the current time or is in the future because + // other servers will drop our FTOPIC. This restriction will be removed when the protocol is updated. + if ((chan->topicset >= ServerInstance->Time()) && (Utils->serverlist.size() > 1)) + { + user->WriteNumeric(ERR_CHANOPRIVSNEEDED, chan->name, "Retry topic change later"); + return MOD_RES_DENY; + } + return MOD_RES_PASSTHRU; +} + void ModuleSpanningTree::OnPostTopicChange(User* user, Channel* chan, const std::string &topic) { // Drop remote events on the floor. @@ -366,34 +388,78 @@ void ModuleSpanningTree::OnPostTopicChange(User* user, Channel* chan, const std: CommandFTopic::Builder(user, chan).Broadcast(); } -void ModuleSpanningTree::OnUserMessage(User* user, void* dest, int target_type, const std::string& text, char status, const CUList& exempt_list, MessageType msgtype) +void ModuleSpanningTree::OnUserPostMessage(User* user, const MessageTarget& target, const MessageDetails& details) { if (!IS_LOCAL(user)) return; - const char* message_type = (msgtype == MSG_PRIVMSG ? "PRIVMSG" : "NOTICE"); - if (target_type == TYPE_USER) + const char* message_type = (details.type == MSG_PRIVMSG ? "PRIVMSG" : "NOTICE"); + switch (target.type) { - User* d = (User*) dest; - if (!IS_LOCAL(d)) + case MessageTarget::TYPE_USER: + { + User* d = target.Get(); + if (!IS_LOCAL(d)) + { + CmdBuilder params(user, message_type); + params.push_tags(details.tags_out); + params.push(d->uuid); + params.push_last(details.text); + params.Unicast(d); + } + break; + } + case MessageTarget::TYPE_CHANNEL: { - CmdBuilder params(user, message_type); - params.push_back(d->uuid); - params.push_last(text); - params.Unicast(d); + Utils->SendChannelMessage(user, target.Get(), details.text, target.status, details.tags_out, details.exemptions, message_type); + break; + } + case MessageTarget::TYPE_SERVER: + { + const std::string* serverglob = target.Get(); + CmdBuilder par(user, message_type); + par.push_tags(details.tags_out); + par.push(*serverglob); + par.push_last(details.text); + par.Broadcast(); + break; } } - else if (target_type == TYPE_CHANNEL) - { - Utils->SendChannelMessage(user->uuid, (Channel*)dest, text, status, exempt_list, message_type); - } - else if (target_type == TYPE_SERVER) +} + +void ModuleSpanningTree::OnUserPostTagMessage(User* user, const MessageTarget& target, const CTCTags::TagMessageDetails& details) +{ + if (!IS_LOCAL(user)) + return; + + switch (target.type) { - char* target = (char*) dest; - CmdBuilder par(user, message_type); - par.push_back(target); - par.push_last(text); - par.Broadcast(); + case MessageTarget::TYPE_USER: + { + User* d = target.Get(); + if (!IS_LOCAL(d)) + { + CmdBuilder params(user, "TAGMSG"); + params.push_tags(details.tags_out); + params.push(d->uuid); + params.Unicast(d); + } + break; + } + case MessageTarget::TYPE_CHANNEL: + { + Utils->SendChannelMessage(user, target.Get(), "", target.status, details.tags_out, details.exemptions, "TAGMSG"); + break; + } + case MessageTarget::TYPE_SERVER: + { + const std::string* serverglob = target.Get(); + CmdBuilder par(user, "TAGMSG"); + par.push_tags(details.tags_out); + par.push(*serverglob); + par.Broadcast(); + break; + } } } @@ -408,6 +474,10 @@ void ModuleSpanningTree::OnUserConnect(LocalUser* user) if (user->quitting) return; + // Create the lazy ssl_cert metadata for this user if not already created. + if (sslapi) + sslapi->GetCertificate(user); + CommandUID::Builder(user).Broadcast(); if (user->IsOper()) @@ -416,7 +486,7 @@ void ModuleSpanningTree::OnUserConnect(LocalUser* user) for(Extensible::ExtensibleStore::const_iterator i = user->GetExtList().begin(); i != user->GetExtList().end(); i++) { ExtensionItem* item = i->first; - std::string value = item->serialize(FORMAT_NETWORK, user, i->second); + std::string value = item->ToNetwork(user, i->second); if (!value.empty()) ServerInstance->PI->SendMetaData(user, item->name, value); } @@ -443,12 +513,12 @@ void ModuleSpanningTree::OnUserJoin(Membership* memb, bool sync, bool created_by else { CmdBuilder params(memb->user, "IJOIN"); - params.push_back(memb->chan->name); + params.push(memb->chan->name); params.push_int(memb->id); if (!memb->modes.empty()) { - params.push_back(ConvToStr(memb->chan->age)); - params.push_back(memb->modes); + params.push(ConvToStr(memb->chan->age)); + params.push(memb->modes); } params.Broadcast(); } @@ -462,12 +532,12 @@ void ModuleSpanningTree::OnChangeHost(User* user, const std::string &newhost) CmdBuilder(user, "FHOST").push(newhost).Broadcast(); } -void ModuleSpanningTree::OnChangeName(User* user, const std::string &gecos) +void ModuleSpanningTree::OnChangeRealName(User* user, const std::string& real) { if (user->registered != REG_ALL || !IS_LOCAL(user)) return; - CmdBuilder(user, "FNAME").push_last(gecos).Broadcast(); + CmdBuilder(user, "FNAME").push_last(real).Broadcast(); } void ModuleSpanningTree::OnChangeIdent(User* user, const std::string &ident) @@ -483,7 +553,7 @@ void ModuleSpanningTree::OnUserPart(Membership* memb, std::string &partmessage, if (IS_LOCAL(memb->user)) { CmdBuilder params(memb->user, "PART"); - params.push_back(memb->chan->name); + params.push(memb->chan->name); if (!partmessage.empty()) params.push_last(partmessage); params.Broadcast(); @@ -523,8 +593,8 @@ void ModuleSpanningTree::OnUserPostNick(User* user, const std::string &oldnick) { // The nick TS is updated by the core, we don't do it CmdBuilder params(user, "NICK"); - params.push_back(user->nick); - params.push_back(ConvToStr(user->age)); + params.push(user->nick); + params.push(ConvToStr(user->age)); params.Broadcast(); } else if (!loopCall) @@ -539,8 +609,8 @@ void ModuleSpanningTree::OnUserKick(User* source, Membership* memb, const std::s return; CmdBuilder params(source, "KICK"); - params.push_back(memb->chan->name); - params.push_back(memb->user->uuid); + params.push(memb->chan->name); + params.push(memb->user->uuid); // If a remote user is being kicked by us then send the membership id in the kick too if (!IS_LOCAL(memb->user)) params.push_int(memb->id); @@ -550,16 +620,13 @@ void ModuleSpanningTree::OnUserKick(User* source, Membership* memb, const std::s void ModuleSpanningTree::OnPreRehash(User* user, const std::string ¶meter) { - if (loopCall) - return; // Don't generate a REHASH here if we're in the middle of processing a message that generated this one - ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "OnPreRehash called with param %s", parameter.c_str()); // Send out to other servers if (!parameter.empty() && parameter[0] != '-') { - CmdBuilder params((user ? user->uuid : ServerInstance->Config->GetSID()), "REHASH"); - params.push_back(parameter); + CmdBuilder params(user ? user : ServerInstance->FakeClient, "REHASH"); + params.push(parameter); params.Forward(user ? TreeServer::Get(user)->GetRoute() : NULL); } } @@ -622,7 +689,7 @@ void ModuleSpanningTree::OnUnloadModule(Module* mod) { TreeServer* server = i->second; if (!server->IsRoot()) - FOREACH_MOD_CUSTOM(GetEventProvider(), SpanningTreeEventListener, OnServerSplit, (server)); + FOREACH_MOD_CUSTOM(GetLinkEventProvider(), ServerProtocol::LinkEventListener, OnServerSplit, (server, false)); } return; } @@ -682,20 +749,24 @@ void ModuleSpanningTree::OnDelLine(User* user, XLine *x) user = ServerInstance->FakeClient; CmdBuilder params(user, "DELLINE"); - params.push_back(x->type); - params.push_back(x->Displayable()); + params.push(x->type); + params.push(x->Displayable()); params.Broadcast(); } -ModResult ModuleSpanningTree::OnSetAway(User* user, const std::string &awaymsg) +void ModuleSpanningTree::OnUserAway(User* user) { if (IS_LOCAL(user)) - CommandAway::Builder(user, awaymsg).Broadcast(); + CommandAway::Builder(user).Broadcast(); +} - return MOD_RES_PASSTHRU; +void ModuleSpanningTree::OnUserBack(User* user) +{ + if (IS_LOCAL(user)) + CommandAway::Builder(user).Broadcast(); } -void ModuleSpanningTree::OnMode(User* source, User* u, Channel* c, const Modes::ChangeList& modes, ModeParser::ModeProcessFlag processflags, const std::string& output_mode) +void ModuleSpanningTree::OnMode(User* source, User* u, Channel* c, const Modes::ChangeList& modes, ModeParser::ModeProcessFlag processflags) { if (processflags & ModeParser::MODE_LOCALONLY) return; @@ -707,7 +778,7 @@ void ModuleSpanningTree::OnMode(User* source, User* u, Channel* c, const Modes:: CmdBuilder params(source, "MODE"); params.push(u->uuid); - params.push(output_mode); + params.push(ClientProtocol::Messages::Mode::ToModeLetters(modes)); params.push_raw(Translate::ModeChangeListToParams(modes.getlist())); params.Broadcast(); } @@ -716,12 +787,19 @@ void ModuleSpanningTree::OnMode(User* source, User* u, Channel* c, const Modes:: CmdBuilder params(source, "FMODE"); params.push(c->name); params.push_int(c->age); - params.push(output_mode); + params.push(ClientProtocol::Messages::Mode::ToModeLetters(modes)); params.push_raw(Translate::ModeChangeListToParams(modes.getlist())); params.Broadcast(); } } +void ModuleSpanningTree::OnShutdown(const std::string& reason) +{ + const TreeServer::ChildServers& children = Utils->TreeRoot->GetChildren(); + while (!children.empty()) + children.front()->SQuit(reason, true); +} + CullResult ModuleSpanningTree::cull() { if (Utils) @@ -733,7 +811,7 @@ ModuleSpanningTree::~ModuleSpanningTree() { ServerInstance->PI = &ServerInstance->DefaultProtocolInterface; - Server* newsrv = new Server(ServerInstance->Config->ServerName, ServerInstance->Config->ServerDesc); + Server* newsrv = new Server(ServerInstance->Config->GetSID(), ServerInstance->Config->ServerName, ServerInstance->Config->ServerDesc); SetLocalUsersServer(newsrv); delete Utils; @@ -754,6 +832,7 @@ Version ModuleSpanningTree::GetVersion() void ModuleSpanningTree::Prioritize() { ServerInstance->Modules->SetPriority(this, PRIORITY_LAST); + ServerInstance->Modules.SetPriority(this, I_OnPreTopicChange, PRIORITY_FIRST); } MODULE_INIT(ModuleSpanningTree)