aboutsummaryrefslogtreecommitdiffstats
path: root/src/modules/m_spanningtree/treesocket2.cpp
diff options
context:
space:
mode:
authorGravatar Sadie Powell2024-07-17 00:06:50 +0100
committerGravatar Sadie Powell2024-07-17 00:06:50 +0100
commit889d521e05f2e922683d48c74eb00290e7a2f548 (patch)
treeb4c56bd4cdf0881601c7e4d6ff571e491af10bf4 /src/modules/m_spanningtree/treesocket2.cpp
parentUse std::endian from C++20 in the sha1 module. (diff)
downloadinspircd++-889d521e05f2e922683d48c74eb00290e7a2f548.tar.gz
inspircd++-889d521e05f2e922683d48c74eb00290e7a2f548.tar.bz2
inspircd++-889d521e05f2e922683d48c74eb00290e7a2f548.zip
Shuffle the modules about a bit.
Diffstat (limited to 'src/modules/m_spanningtree/treesocket2.cpp')
-rw-r--r--src/modules/m_spanningtree/treesocket2.cpp458
1 files changed, 0 insertions, 458 deletions
diff --git a/src/modules/m_spanningtree/treesocket2.cpp b/src/modules/m_spanningtree/treesocket2.cpp
deleted file mode 100644
index eae8cbe21..000000000
--- a/src/modules/m_spanningtree/treesocket2.cpp
+++ /dev/null
@@ -1,458 +0,0 @@
-/*
- * InspIRCd -- Internet Relay Chat Daemon
- *
- * Copyright (C) 2019 linuxdaemon <linuxdaemon.irc@gmail.com>
- * Copyright (C) 2018-2024 Sadie Powell <sadie@witchery.services>
- * Copyright (C) 2012-2016, 2018 Attila Molnar <attilamolnar@hush.com>
- * Copyright (C) 2012 Robby <robby@chatbelgie.be>
- * Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org>
- * Copyright (C) 2008, 2012 Robin Burchell <robin+git@viroteck.net>
- * Copyright (C) 2007-2008 Dennis Friis <peavey@inspircd.org>
- * Copyright (C) 2007-2008 Craig Edwards <brain@inspircd.org>
- *
- * This file is part of InspIRCd. InspIRCd is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General Public
- * License as published by the Free Software Foundation, version 2.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-
-#include "inspircd.h"
-#include "timeutils.h"
-
-#include "main.h"
-#include "utils.h"
-#include "treeserver.h"
-#include "treesocket.h"
-#include "resolvers.h"
-#include "commands.h"
-
-/* Handle ERROR command */
-void TreeSocket::Error(CommandBase::Params& params)
-{
- const std::string msg = params.empty() ? "" : params[0];
- SetError("received ERROR " + msg);
-}
-
-void TreeSocket::Split(const std::string& line, std::string& tags, std::string& prefix, std::string& command, CommandBase::Params& params)
-{
- std::string token;
- irc::tokenstream tokens(line);
-
- if (!tokens.GetMiddle(token))
- return;
-
- if (token[0] == '@')
- {
- if (token.length() <= 1)
- {
- this->SendError("BUG: Received a message with empty tags: " + line);
- return;
- }
-
- tags.assign(token, 1, std::string::npos);
- if (!tokens.GetMiddle(token))
- {
- this->SendError("BUG: Received a message with no command: " + line);
- return;
- }
- }
-
- if (token[0] == ':')
- {
- if (token.length() <= 1)
- {
- this->SendError("BUG: Received a message with an empty prefix: " + line);
- return;
- }
-
- prefix.assign(token, 1, std::string::npos);
- if (!tokens.GetMiddle(token))
- {
- this->SendError("BUG: Received a message with no command: " + line);
- return;
- }
- }
-
- command.assign(token);
- while (tokens.GetTrailing(token))
- params.push_back(token);
-}
-
-void TreeSocket::ProcessLine(std::string& line)
-{
- std::string tags;
- std::string prefix;
- std::string command;
- CommandBase::Params params;
-
- ServerInstance->Logs.RawIO(MODNAME, "S[{}] I {}", GetFd(), line);
-
- Split(line, tags, prefix, command, params);
-
- if (command.empty())
- return;
-
- switch (this->LinkState)
- {
- case WAIT_AUTH_1:
- /*
- * State WAIT_AUTH_1:
- * Waiting for SERVER command from remote server. Server initiating
- * the connection sends the first SERVER command, listening server
- * replies with theirs if its happy, then if the initiator is happy,
- * it starts to send its net sync, which starts the merge, otherwise
- * it sends an ERROR.
- */
- if (command == "PASS")
- {
- /*
- * Ignore this silently. Some services packages insist on sending PASS, even
- * when it is not required (i.e. by us). We have to ignore this here, otherwise
- * as it's an unknown command (effectively), it will cause the connection to be
- * closed, which probably isn't what people want. -- w00t
- */
- }
- else if (command == "SERVER")
- {
- this->Inbound_Server(params);
- }
- else if (command == "ERROR")
- {
- this->Error(params);
- }
- else if (command == "USER")
- {
- this->SendError("Client connections to this port are prohibited.");
- }
- else if (command == "CAPAB")
- {
- this->Capab(params);
- }
- else
- {
- this->SendError("Invalid command in negotiation phase: " + command);
- }
- break;
- case WAIT_AUTH_2:
- /*
- * State WAIT_AUTH_2:
- * We have sent SERVER to the other side of the connection. Now we're waiting for them to start BURST.
- * The other option at this stage of things, of course, is for them to close our connection thanks
- * to invalid credentials.. -- w
- */
- if (command == "SERVER")
- {
- /*
- * Connection is either attempting to re-auth itself (stupid) or sending netburst without sending BURST.
- * Both of these aren't allowable, so block them here. -- w
- */
- this->SendError("You may not re-authenticate or commence netburst without sending BURST.");
- }
- else if (command == "BURST")
- {
- if (!params.empty())
- {
- time_t them = ServerCommand::ExtractTS(params[0]);
- time_t delta = them - ServerInstance->Time();
- if ((delta < -15) || (delta > 15))
- {
- ServerInstance->SNO.WriteGlobalSno('l', "\002ERROR\002: Your clocks are off by {} seconds (this is more than fifteen seconds). Link aborted, \002PLEASE SYNC YOUR CLOCKS!\002", labs((long)delta));
- SendError("Your clocks are out by "+ConvToStr(labs((long)delta))+" seconds (this is more than fifteen seconds). Link aborted, PLEASE SYNC YOUR CLOCKS!");
- return;
- }
- else if ((delta < -5) || (delta > 5))
- {
- ServerInstance->SNO.WriteGlobalSno('l', "\002WARNING\002: Your clocks are off by {} seconds. Please consider syncing your clocks.", labs((long)delta));
- }
- }
-
- // Check for duplicate server name/sid again, it's possible that a new
- // server was introduced while we were waiting for them to send BURST.
- // (we do not reserve their server name/sid when they send SERVER, we do it now)
- if (!CheckDuplicate(capab->name, capab->sid))
- return;
-
- FinishAuth(capab->name, capab->sid, capab->description, capab->hidden);
- }
- else if (command == "ERROR")
- {
- this->Error(params);
- }
- else if (command == "CAPAB")
- {
- this->Capab(params);
- }
- else
- {
- ServerInstance->Logs.Debug(MODNAME, "Unknown command from fd {} in the WAIT_AUTH_2 phase: {}",
- GetFd(), command);
- }
-
- break;
- case CONNECTING:
- /*
- * State CONNECTING:
- * We're connecting (OUTGOING) to another server. They are in state WAIT_AUTH_1 until they verify
- * our credentials, when they proceed into WAIT_AUTH_2 and send SERVER to us. We then send BURST
- * + our netburst, which will put them into CONNECTED state. -- w
- */
- if (command == "SERVER")
- {
- // Our credentials have been accepted, send netburst. (this puts US into the CONNECTED state)
- this->Outbound_Reply_Server(params);
- }
- else if (command == "ERROR")
- {
- this->Error(params);
- }
- else if (command == "CAPAB")
- {
- this->Capab(params);
- }
- else
- {
- ServerInstance->Logs.Debug(MODNAME, "Unknown command from fd {} in the CONNECTING phase: {}",
- GetFd(), command);
- }
- break;
-
- case CONNECTED:
- /*
- * State CONNECTED:
- * Credentials have been exchanged, we've gotten their 'BURST' (or sent ours).
- * Anything from here on should be accepted a little more reasonably.
- */
- this->ProcessConnectedLine(tags, prefix, command, params);
- break;
-
- case DYING:
- break;
- }
-}
-
-User* TreeSocket::FindSource(const std::string& prefix, const std::string& command)
-{
- // Empty prefix means the source is the directly connected server that sent this command
- if (prefix.empty())
- return MyRoot->ServerUser;
-
- if (prefix.size() == 3)
- {
- // Prefix looks like a sid
- TreeServer* server = Utils->FindServerID(prefix);
- if (server)
- return server->ServerUser;
- }
- else
- {
- // If the prefix string is a uuid FindUUID() returns the appropriate User object
- auto* user = ServerInstance->Users.FindUUID(prefix);
- if (user)
- return user;
- }
-
- // Some implementations wrongly send a server name as prefix occasionally, handle that too for now
- TreeServer* const server = Utils->FindServer(prefix);
- if (server)
- return server->ServerUser;
-
- /* It is important that we don't close the link here, unknown prefix can occur
- * due to various race conditions such as the KILL message for a user somehow
- * crossing the users QUIT further upstream from the server. Thanks jilles!
- */
-
- if ((prefix.length() == UIDGenerator::UUID_LENGTH) && (isdigit(prefix[0])) &&
- ((command == "FMODE") || (command == "MODE") || (command == "KICK") || (command == "TOPIC") || (command == "KILL") || (command == "ADDLINE") || (command == "DELLINE")))
- {
- /* Special case, we cannot drop these commands as they've been committed already on a
- * part of the network by the time we receive them, so in this scenario pretend the
- * command came from a server to avoid desync.
- */
-
- TreeServer* const usersserver = Utils->FindServerID(prefix.substr(0, 3));
- if (usersserver)
- return usersserver->ServerUser;
- return this->MyRoot->ServerUser;
- }
-
- // Unknown prefix
- return nullptr;
-}
-
-void TreeSocket::ProcessTag(User* source, const std::string& tag, ClientProtocol::TagMap& tags)
-{
- std::string tagkey;
- std::string tagval;
- const std::string::size_type p = tag.find('=');
- if (p != std::string::npos)
- {
- // Tag has a value
- tagkey.assign(tag, 0, p);
- tagval.assign(tag, p + 1, std::string::npos);
- }
- else
- {
- tagkey.assign(tag);
- }
-
- for (auto* subscriber : Utils->Creator->tagevprov.GetSubscribers())
- {
- ClientProtocol::MessageTagProvider* const tagprov = static_cast<ClientProtocol::MessageTagProvider*>(subscriber);
- const ModResult res = tagprov->OnProcessTag(source, tagkey, tagval);
- if (res == MOD_RES_ALLOW)
- tags.emplace(tagkey, ClientProtocol::MessageTagData(tagprov, tagval));
- else if (res == MOD_RES_DENY)
- break;
- }
-}
-
-void TreeSocket::ProcessConnectedLine(std::string& taglist, std::string& prefix, std::string& command, CommandBase::Params& params)
-{
- User* who = FindSource(prefix, command);
- if (!who)
- {
- ServerInstance->Logs.Debug(MODNAME, "Command '{}' from unknown prefix '{}'! Dropping entire command.", command, prefix);
- return;
- }
-
- /*
- * Check for fake direction here, and drop any instances that are found.
- * What is fake direction? Imagine the following server setup:
- * 0AA <-> 0AB <-> 0AC
- * Fake direction would be 0AC sending a message to 0AB claiming to be from
- * 0AA, or something similar. Basically, a message taking a path that *cannot*
- * be correct.
- *
- * When would this be seen?
- * Well, hopefully never. It could be caused by race conditions, bugs, or
- * "miscreant" servers, though, so let's check anyway. -- w
- *
- * We also check here for totally invalid prefixes (prefixes that are neither
- * a valid SID or a valid UUID, so that invalid UUID or SID never makes it
- * to the higher level functions. -- B
- */
- TreeServer* const server = TreeServer::Get(who);
- if (server->GetSocket() != this)
- {
- ServerInstance->Logs.Debug(MODNAME, "Protocol violation: Fake direction '{}' from connection '{}'", prefix, linkID);
- return;
- }
-
- // Translate commands coming from servers using an older protocol
- if (proto_version < PROTO_NEWEST)
- {
- if (!PreProcessOldProtocolMessage(who, command, params))
- return;
- }
-
- ServerCommand* scmd = Utils->Creator->CmdManager.GetHandler(command);
- CommandBase* cmdbase = scmd;
- Command* cmd = nullptr;
- if (!scmd)
- {
- // Not a special server-to-server command
- cmd = ServerInstance->Parser.GetHandler(command);
- if (!cmd)
- {
- if (command == "ERROR")
- {
- this->Error(params);
- return;
- }
- else if (command == "BURST")
- {
- // This is sent even when there is no need for it, drop it here for now
- return;
- }
-
- throw ProtocolException("Unknown command: " + command);
- }
- cmdbase = cmd;
- }
-
- if (params.size() < cmdbase->min_params)
- throw ProtocolException("Insufficient parameters");
-
- if ((!params.empty()) && (params.back().empty()) && (!cmdbase->allow_empty_last_param))
- {
- // the last param is empty and the command handler doesn't allow that, check if there will be enough params if we drop the last
- if (params.size()-1 < cmdbase->min_params)
- return;
- params.pop_back();
- }
-
- CmdResult res;
- ClientProtocol::TagMap tags;
- std::string tag;
- irc::sepstream tagstream(taglist, ';');
- while (tagstream.GetToken(tag))
- ProcessTag(who, tag, tags);
-
- CommandBase::Params newparams(params, tags);
-
- if (scmd)
- res = scmd->Handle(who, newparams);
- else
- {
- res = cmd->Handle(who, newparams);
- if (res == CmdResult::INVALID)
- throw ProtocolException("Error in command handler");
- }
-
- if (res == CmdResult::SUCCESS)
- Utils->RouteCommand(server->GetRoute(), cmdbase, newparams, who);
-}
-
-void TreeSocket::OnTimeout()
-{
- ServerInstance->SNO.WriteGlobalSno('l', "CONNECT: Connection to \002{}\002 timed out.", linkID);
-}
-
-void TreeSocket::Close()
-{
- if (!HasFd())
- return;
-
- ServerInstance->GlobalCulls.AddItem(this);
- this->BufferedSocket::Close();
- SetError("Remote host closed connection");
-
- // Connection closed.
- // If the connection is fully up (state CONNECTED)
- // then propagate a netsplit to all peers.
- if (MyRoot && !MyRoot->IsDead())
- MyRoot->SQuit(GetError(), true);
- else
- ServerInstance->SNO.WriteGlobalSno('l', "Connection to '\002{}\002' failed.", linkID);
-
- time_t server_uptime = ServerInstance->Time() - this->age;
- if (server_uptime)
- {
- std::string timestr = Duration::ToString(server_uptime);
- ServerInstance->SNO.WriteGlobalSno('l', "Connection to '\002{}\002' was established for {}", linkID, timestr);
- }
-}
-
-void TreeSocket::FinishAuth(const std::string& remotename, const std::string& remotesid, const std::string& remotedesc, bool hidden)
-{
- this->LinkState = CONNECTED;
- Utils->timeoutlist.erase(this);
-
- linkID = remotename;
-
- MyRoot = new TreeServer(remotename, remotedesc, remotesid, Utils->TreeRoot, this, hidden);
-
- // Mark the server as bursting
- MyRoot->BeginBurst();
- this->DoBurst(MyRoot);
-
- CommandServer::Builder(MyRoot).Forward(MyRoot);
-}