Example #1
0
bool TreeSocket::CheckDuplicate(const std::string& sname, const std::string& sid)
{
	// Check if the server name is not in use by a server that's already fully connected
	TreeServer* CheckDupe = Utils->FindServer(sname);
	if (CheckDupe)
	{
		std::string pname = CheckDupe->GetParent() ? CheckDupe->GetParent()->GetName() : "<ourself>";
		SendError("Server "+sname+" already exists on server "+pname+"!");
		ServerInstance->SNO->WriteToSnoMask('l',"Server connection from \2"+sname+"\2 denied, already exists on server "+pname);
		return false;
	}

	// Check if the id is not in use by a server that's already fully connected
	ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Looking for dupe SID %s", sid.c_str());
	CheckDupe = Utils->FindServerID(sid);

	if (CheckDupe)
	{
		this->SendError("Server ID "+CheckDupe->GetID()+" already exists on server "+CheckDupe->GetName()+"! You may want to specify the server ID for the server manually with <server:id> so they do not conflict.");
		ServerInstance->SNO->WriteToSnoMask('l',"Server connection from \2"+sname+"\2 denied, server ID '"+CheckDupe->GetID()+
				"' already exists on server "+CheckDupe->GetName());
		return false;
	}

	return true;
}
Example #2
0
bool SpanningTreeProtocolInterface::SendEncapsulatedData(const std::string& targetmask, const std::string& cmd, const parameterlist& params, User* source)
{
	if (!source)
		source = ServerInstance->FakeClient;

	CmdBuilder encap(source, "ENCAP");

	// Are there any wildcards in the target string?
	if (targetmask.find_first_of("*?") != std::string::npos)
	{
		// Yes, send the target string as-is; servers will decide whether or not it matches them
		encap.push(targetmask).push(cmd).insert(params).Broadcast();
	}
	else
	{
		// No wildcards which means the target string has to be the name of a known server
		TreeServer* server = Utils->FindServer(targetmask);
		if (!server)
			return false;

		// Use the SID of the target in the message instead of the server name
		encap.push(server->GetID()).push(cmd).insert(params).Unicast(server->ServerUser);
	}

	return true;
}
Example #3
0
bool TreeSocket::CheckDuplicate(const std::string& sname, const std::string& sid)
{
	/* Check for fully initialized instances of the server by name */
	TreeServer* CheckDupe = Utils->FindServer(sname);
	if (CheckDupe)
	{
		std::string pname = CheckDupe->GetParent() ? CheckDupe->GetParent()->GetName() : "<ourself>";
		SendError("Server "+sname+" already exists on server "+pname+"!");
		ServerInstance->SNO->WriteToSnoMask('l',"Server connection from \2"+sname+"\2 denied, already exists on server "+pname);
		return false;
	}

	/* Check for fully initialized instances of the server by id */
	ServerInstance->Logs->Log("m_spanningtree",DEBUG,"Looking for dupe SID %s", sid.c_str());
	CheckDupe = Utils->FindServerID(sid);

	if (CheckDupe)
	{
		this->SendError("Server ID "+CheckDupe->GetID()+" already exists on server "+CheckDupe->GetName()+"! You may want to specify the server ID for the server manually with <server:id> so they do not conflict.");
		ServerInstance->SNO->WriteToSnoMask('l',"Server connection from \2"+sname+"\2 denied, server ID '"+CheckDupe->GetID()+
				"' already exists on server "+CheckDupe->GetName());
		return false;
	}

	return true;
}
Example #4
0
void ModuleSpanningTree::DoPingChecks(time_t curtime)
{
	/*
	 * Cancel remote burst mode on any servers which still have it enabled due to latency/lack of data.
	 * This prevents lost REMOTECONNECT notices
	 */
	long ts = ServerInstance->Time() * 1000 + (ServerInstance->Time_ns() / 1000000);

restart:
	for (server_hash::iterator i = Utils->serverlist.begin(); i != Utils->serverlist.end(); i++)
	{
		TreeServer *s = i->second;

		// Skip myself
		if (s->IsRoot())
			continue;

		// Do not ping servers that are not fully connected yet!
		// Servers which are connected to us have IsLocal() == true and if they're fully connected
		// then Socket->LinkState == CONNECTED. Servers that are linked to another server are always fully connected.
		if (s->IsLocal() && s->GetSocket()->GetLinkState() != CONNECTED)
			continue;

		// Now do PING checks on all servers
		// Only ping if this server needs one
		if (curtime >= s->NextPingTime())
		{
			// And if they answered the last
			if (s->AnsweredLastPing())
			{
				// They did, send a ping to them
				s->SetNextPingTime(curtime + Utils->PingFreq);
				s->GetSocket()->WriteLine(CmdBuilder("PING").push(s->GetID()));
				s->LastPingMsec = ts;
			}
			else
			{
				// They didn't answer the last ping, if they are locally connected, get rid of them.
				if (s->IsLocal())
				{
					TreeSocket* sock = s->GetSocket();
					sock->SendError("Ping timeout");
					sock->Close();
					goto restart;
				}
			}
		}

		// If warn on ping enabled and not warned and the difference is sufficient and they didn't answer the last ping...
		if ((Utils->PingWarnTime) && (!s->Warned) && (curtime >= s->NextPingTime() - (Utils->PingFreq - Utils->PingWarnTime)) && (!s->AnsweredLastPing()))
		{
			/* The server hasnt responded, send a warning to opers */
			ServerInstance->SNO->WriteToSnoMask('l',"Server \002%s\002 has not responded to PING for %d seconds, high latency.", s->GetName().c_str(), Utils->PingWarnTime);
			s->Warned = true;
		}
	}
}
Example #5
0
/** send all users and their oper state/modes */
void TreeSocket::SendUsers()
{
	char data[MAXBUF];
	std::string dataline;
	for (user_hash::iterator u = ServerInstance->Users->clientlist->begin(); u != ServerInstance->Users->clientlist->end(); u++)
	{
		if (u->second->registered == REG_ALL)
		{
			TreeServer* theirserver = Utils->FindServer(u->second->server);
			if (theirserver)
			{
				snprintf(data,MAXBUF,":%s UID %s %lu %s %s %s %s %s %lu +%s :%s",
						theirserver->GetID().c_str(),	/* Prefix: SID */
						u->second->uuid.c_str(),	/* 0: UUID */
						(unsigned long)u->second->age,	/* 1: TS */
						u->second->nick.c_str(),	/* 2: Nick */
						u->second->host.c_str(),	/* 3: Displayed Host */
						u->second->dhost.c_str(),	/* 4: Real host */
						u->second->ident.c_str(),	/* 5: Ident */
						u->second->GetIPString().c_str(),	/* 6: IP string */
						(unsigned long)u->second->signon, /* 7: Signon time for WHOWAS */
						u->second->FormatModes(true),	/* 8...n: Modes and params */
						u->second->fullname.c_str());	/* size-1: GECOS */
				this->WriteLine(data);
				if (u->second->IsOper())
				{
					snprintf(data,MAXBUF,":%s OPERTYPE %s", u->second->uuid.c_str(), u->second->oper->name.c_str());
					this->WriteLine(data);
				}
				if (u->second->IsAway())
				{
					snprintf(data,MAXBUF,":%s AWAY %ld :%s", u->second->uuid.c_str(), (long)u->second->awaytime, u->second->awaymsg.c_str());
					this->WriteLine(data);
				}
			}

			for(Extensible::ExtensibleStore::const_iterator i = u->second->GetExtList().begin(); i != u->second->GetExtList().end(); i++)
			{
				ExtensionItem* item = i->first;
				std::string value = item->serialize(FORMAT_NETWORK, u->second, i->second);
				if (!value.empty())
					Utils->Creator->ProtoSendMetaData(this, u->second, item->name, value);
			}

			FOREACH_MOD(I_OnSyncUser,OnSyncUser(u->second,Utils->Creator,this));
		}
	}
}
Example #6
0
/** send all users and their oper state/modes */
void TreeSocket::SendUsers(TreeServer* Current)
{
	char data[MAXBUF];
	std::deque<std::string> list;
	std::string dataline;
	for (user_hash::iterator u = this->ServerInstance->Users->clientlist->begin(); u != this->ServerInstance->Users->clientlist->end(); u++)
	{
		if (u->second->registered == REG_ALL)
		{
			TreeServer* theirserver = Utils->FindServer(u->second->server);
			if (theirserver)
			{
				snprintf(data,MAXBUF,":%s UID %s %lu %s %s %s %s %s %lu +%s :%s",
						theirserver->GetID().c_str(),	/* Prefix: SID */
						u->second->uuid.c_str(),	/* 0: UUID */
						(unsigned long)u->second->age,	/* 1: TS */
						u->second->nick.c_str(),	/* 2: Nick */
						u->second->host.c_str(),	/* 3: Displayed Host */
						u->second->dhost.c_str(),	/* 4: Real host */
						u->second->ident.c_str(),	/* 5: Ident */
						u->second->GetIPString(),	/* 6: IP string */
						(unsigned long)u->second->signon, /* 7: Signon time for WHOWAS */
						u->second->FormatModes(true),	/* 8...n: Modes and params */
						u->second->fullname.c_str());	/* size-1: GECOS */
				this->WriteLine(data);
				if (IS_OPER(u->second))
				{
					snprintf(data,MAXBUF,":%s OPERTYPE %s", u->second->uuid.c_str(), u->second->oper.c_str());
					this->WriteLine(data);
				}
				if (IS_AWAY(u->second))
				{
					snprintf(data,MAXBUF,":%s AWAY :%s", u->second->uuid.c_str(), u->second->awaymsg.c_str());
					this->WriteLine(data);
				}
			}

			FOREACH_MOD_I(this->ServerInstance,I_OnSyncUser,OnSyncUser(u->second,(Module*)Utils->Creator,(void*)this));
			list.clear();
			u->second->GetExtList(list);
			for (unsigned int j = 0; j < list.size(); j++)
			{
				FOREACH_MOD_I(this->ServerInstance,I_OnSyncUserMetaData,OnSyncUserMetaData(u->second,(Module*)Utils->Creator,(void*)this,list[j]));
			}
		}
	}
}
Example #7
0
bool TreeSocket::PreProcessOldProtocolMessage(User*& who, std::string& cmd, std::vector<std::string>& params)
{
	if ((cmd == "METADATA") && (params.size() >= 3))
	{
		// :20D METADATA #channel extname :extdata
		return InsertCurrentChannelTS(params);
	}
	else if ((cmd == "FTOPIC") && (params.size() >= 4))
	{
		// :20D FTOPIC #channel 100 Attila :topic text
		return InsertCurrentChannelTS(params);
	}
	else if ((cmd == "PING") || (cmd == "PONG"))
	{
		if (params.size() == 1)
		{
			// If it's a PING with 1 parameter, reply with a PONG now, if it's a PONG with 1 parameter (weird), do nothing
			if (cmd[1] == 'I')
				this->WriteData(":" + ServerInstance->Config->GetSID() + " PONG " + params[0] + newline);

			// Don't process this message further
			return false;
		}

		// :20D PING 20D 22D
		// :20D PONG 20D 22D
		// Drop the first parameter
		params.erase(params.begin());

		// If the target is a server name, translate it to a SID
		if (!InspIRCd::IsSID(params[0]))
		{
			TreeServer* server = Utils->FindServer(params[0]);
			if (!server)
			{
				// We've no idea what this is, log and stop processing
				ServerInstance->Logs->Log("m_spanningtree", LOG_DEFAULT, "Received a " + cmd + " with an unknown target: \"" + params[0] + "\", command dropped");
				return false;
			}

			params[0] = server->GetID();
		}
	}

	return true; // Passthru
}
Example #8
0
void SpanningTreeUtilities::RouteCommand(TreeServer* origin, CommandBase* thiscmd, const parameterlist& parameters, User* user)
{
	const std::string& command = thiscmd->name;
	RouteDescriptor routing = thiscmd->GetRouting(user, parameters);
	if (routing.type == ROUTE_TYPE_LOCALONLY)
		return;

	const bool encap = ((routing.type == ROUTE_TYPE_OPT_BCAST) || (routing.type == ROUTE_TYPE_OPT_UCAST));
	CmdBuilder params(user, encap ? "ENCAP" : command.c_str());

	if (routing.type == ROUTE_TYPE_OPT_BCAST)
	{
		params.push('*');
		params.push_back(command);
	}
	else if (routing.type == ROUTE_TYPE_OPT_UCAST)
	{
		TreeServer* sdest = FindServer(routing.serverdest);
		if (!sdest)
		{
			ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Trying to route ENCAP to nonexistant server %s",
				routing.serverdest.c_str());
			return;
		}
		params.push_back(sdest->GetID());
		params.push_back(command);
	}
	else
	{
		Module* srcmodule = thiscmd->creator;
		Version ver = srcmodule->GetVersion();

		if (!(ver.Flags & (VF_COMMON | VF_CORE)) && srcmodule != Creator)
		{
			ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Routed command %s from non-VF_COMMON module %s",
				command.c_str(), srcmodule->ModuleSourceFile.c_str());
			return;
		}
	}

	std::string output_text = CommandParser::TranslateUIDs(thiscmd->translation, parameters, true, thiscmd);

	params.push_back(output_text);

	if (routing.type == ROUTE_TYPE_MESSAGE)
	{
		char pfx = 0;
		std::string dest = routing.serverdest;
		if (ServerInstance->Modes->FindPrefix(dest[0]))
		{
			pfx = dest[0];
			dest = dest.substr(1);
		}
		if (dest[0] == '#')
		{
			Channel* c = ServerInstance->FindChan(dest);
			if (!c)
				return;
			// TODO OnBuildExemptList hook was here
			CUList exempts;
			SendChannelMessage(user->uuid, c, parameters[1], pfx, exempts, command.c_str(), origin ? origin->GetSocket() : NULL);
		}
		else if (dest[0] == '$')
		{
			params.Forward(origin);
		}
		else
		{
			// user target?
			User* d = ServerInstance->FindNick(dest);
			if (!d)
				return;
			TreeServer* tsd = BestRouteTo(d->server);
			if (tsd == origin)
				// huh? no routing stuff around in a circle, please.
				return;
			params.Unicast(d);
		}
	}
	else if (routing.type == ROUTE_TYPE_BROADCAST || routing.type == ROUTE_TYPE_OPT_BCAST)
	{
		params.Forward(origin);
	}
	else if (routing.type == ROUTE_TYPE_UNICAST || routing.type == ROUTE_TYPE_OPT_UCAST)
	{
		if (origin && routing.serverdest == origin->GetName())
			return;
		params.Unicast(routing.serverdest);
	}
}
Example #9
0
void SpanningTreeUtilities::RouteCommand(TreeServer* origin, Command* thiscmd, const parameterlist& parameters, User* user)
{
	const std::string& command = thiscmd->name;
	RouteDescriptor routing = thiscmd->GetRouting(user, parameters);

	std::string sent_cmd = command;
	parameterlist params;

	if (routing.type == ROUTE_TYPE_LOCALONLY)
	{
		return;
	}
	else if (routing.type == ROUTE_TYPE_OPT_BCAST)
	{
		params.push_back("*");
		params.push_back(command);
		sent_cmd = "ENCAP";
	}
	else if (routing.type == ROUTE_TYPE_OPT_UCAST)
	{
		TreeServer* sdest = FindServer(routing.serverdest);
		if (!sdest)
		{
			ServerInstance->Logs->Log("m_spanningtree", LOG_DEFAULT, "Trying to route ENCAP to nonexistant server %s",
				routing.serverdest.c_str());
			return;
		}
		params.push_back(sdest->GetID());
		params.push_back(command);
		sent_cmd = "ENCAP";
	}
	else
	{
		Module* srcmodule = thiscmd->creator;
		Version ver = srcmodule->GetVersion();

		if (!(ver.Flags & (VF_COMMON | VF_CORE)) && srcmodule != Creator)
		{
			ServerInstance->Logs->Log("m_spanningtree", LOG_DEFAULT, "Routed command %s from non-VF_COMMON module %s",
				command.c_str(), srcmodule->ModuleSourceFile.c_str());
			return;
		}
	}

	std::string output_text = CommandParser::TranslateUIDs(thiscmd->translation, parameters, true, thiscmd);

	params.push_back(output_text);

	if (routing.type == ROUTE_TYPE_MESSAGE)
	{
		char pfx = 0;
		std::string dest = routing.serverdest;
		if (ServerInstance->Modes->FindPrefix(dest[0]))
		{
			pfx = dest[0];
			dest = dest.substr(1);
		}
		if (dest[0] == '#')
		{
			Channel* c = ServerInstance->FindChan(dest);
			if (!c)
				return;
			TreeServerList list;
			// TODO OnBuildExemptList hook was here
			GetListOfServersForChannel(c,list,pfx, CUList());
			std::string data = ":" + user->uuid + " " + sent_cmd;
			for (unsigned int x = 0; x < params.size(); x++)
				data += " " + params[x];
			for (TreeServerList::iterator i = list.begin(); i != list.end(); i++)
			{
				TreeSocket* Sock = (*i)->GetSocket();
				if (origin && origin->GetSocket() == Sock)
					continue;
				if (Sock)
					Sock->WriteLine(data);
			}
		}
		else if (dest[0] == '$')
		{
			if (origin)
				DoOneToAllButSender(user->uuid, sent_cmd, params, origin->GetName());
			else
				DoOneToMany(user->uuid, sent_cmd, params);
		}
		else
		{
			// user target?
			User* d = ServerInstance->FindNick(dest);
			if (!d)
				return;
			TreeServer* tsd = BestRouteTo(d->server);
			if (tsd == origin)
				// huh? no routing stuff around in a circle, please.
				return;
			DoOneToOne(user->uuid, sent_cmd, params, d->server);
		}
	}
	else if (routing.type == ROUTE_TYPE_BROADCAST || routing.type == ROUTE_TYPE_OPT_BCAST)
	{
		if (origin)
			DoOneToAllButSender(user->uuid, sent_cmd, params, origin->GetName());
		else
			DoOneToMany(user->uuid, sent_cmd, params);
	}
	else if (routing.type == ROUTE_TYPE_UNICAST || routing.type == ROUTE_TYPE_OPT_UCAST)
	{
		if (origin && routing.serverdest == origin->GetName())
			return;
		DoOneToOne(user->uuid, sent_cmd, params, routing.serverdest);
	}
}
Example #10
0
void SpanningTreeUtilities::RouteCommand(TreeServer* origin, CommandBase* thiscmd, const CommandBase::Params& parameters, User* user)
{
	const std::string& command = thiscmd->name;
	RouteDescriptor routing = thiscmd->GetRouting(user, parameters);
	if (routing.type == ROUTE_TYPE_LOCALONLY)
		return;

	const bool encap = ((routing.type == ROUTE_TYPE_OPT_BCAST) || (routing.type == ROUTE_TYPE_OPT_UCAST));
	CmdBuilder params(user, encap ? "ENCAP" : command.c_str());
	params.push_tags(parameters.GetTags());
	TreeServer* sdest = NULL;

	if (routing.type == ROUTE_TYPE_OPT_BCAST)
	{
		params.push('*');
		params.push_back(command);
	}
	else if (routing.type == ROUTE_TYPE_UNICAST || routing.type == ROUTE_TYPE_OPT_UCAST)
	{
		sdest = static_cast<TreeServer*>(routing.server);
		if (!sdest)
		{
			// Assume the command handler already validated routing.serverdest and have only returned success if the target is something that the
			// user executing the command is allowed to look up e.g. target is not an uuid if user is local.
			sdest = FindRouteTarget(routing.serverdest);
			if (!sdest)
			{
				ServerInstance->Logs.Log(MODNAME, LOG_DEFAULT, "Trying to route %s%s to nonexistent server %s", (encap ? "ENCAP " : ""), command.c_str(), routing.serverdest.c_str());
				return;
			}
		}

		if (encap)
		{
			params.push_back(sdest->GetID());
			params.push_back(command);
		}
	}
	else
	{
		Module* srcmodule = thiscmd->creator;
		Version ver = srcmodule->GetVersion();

		if (!(ver.Flags & (VF_COMMON | VF_CORE)) && srcmodule != Creator)
		{
			ServerInstance->Logs.Log(MODNAME, LOG_DEFAULT, "Routed command %s from non-VF_COMMON module %s",
				command.c_str(), srcmodule->ModuleSourceFile.c_str());
			return;
		}
	}

	std::string output_text = CommandParser::TranslateUIDs(thiscmd->translation, parameters, true, thiscmd);

	params.push_back(output_text);

	if (routing.type == ROUTE_TYPE_MESSAGE)
	{
		char pfx = 0;
		std::string dest = routing.serverdest;
		if (ServerInstance->Modes.FindPrefix(dest[0]))
		{
			pfx = dest[0];
			dest.erase(dest.begin());
		}
		if (dest[0] == '#')
		{
			Channel* c = ServerInstance->FindChan(dest);
			if (!c)
				return;
			// TODO OnBuildExemptList hook was here
			CUList exempts;
			std::string message;
			if (parameters.size() >= 2)
				message.assign(parameters[1]);
			SendChannelMessage(user->uuid, c, message, pfx, parameters.GetTags(), exempts, command.c_str(), origin ? origin->GetSocket() : NULL);
		}
		else if (dest[0] == '$')
		{
			params.Forward(origin);
		}
		else
		{
			// user target?
			User* d = ServerInstance->FindNick(dest);
			if (!d || IS_LOCAL(d))
				return;
			TreeServer* tsd = TreeServer::Get(d)->GetRoute();
			if (tsd == origin)
				// huh? no routing stuff around in a circle, please.
				return;
			params.Unicast(d);
		}
	}
	else if (routing.type == ROUTE_TYPE_BROADCAST || routing.type == ROUTE_TYPE_OPT_BCAST)
	{
		params.Forward(origin);
	}
	else if (routing.type == ROUTE_TYPE_UNICAST || routing.type == ROUTE_TYPE_OPT_UCAST)
	{
		params.Unicast(sdest->ServerUser);
	}
}
Example #11
0
bool TreeSocket::PreProcessOldProtocolMessage(User*& who, std::string& cmd, std::vector<std::string>& params)
{
	if ((cmd == "METADATA") && (params.size() >= 3) && (params[0][0] == '#'))
	{
		// :20D METADATA #channel extname :extdata
		return InsertCurrentChannelTS(params);
	}
	else if ((cmd == "FTOPIC") && (params.size() >= 4))
	{
		// :20D FTOPIC #channel 100 Attila :topic text
		return InsertCurrentChannelTS(params);
	}
	else if ((cmd == "PING") || (cmd == "PONG"))
	{
		if (params.size() == 1)
		{
			// If it's a PING with 1 parameter, reply with a PONG now, if it's a PONG with 1 parameter (weird), do nothing
			if (cmd[1] == 'I')
				this->WriteData(":" + ServerInstance->Config->GetSID() + " PONG " + params[0] + newline);

			// Don't process this message further
			return false;
		}

		// :20D PING 20D 22D
		// :20D PONG 20D 22D
		// Drop the first parameter
		params.erase(params.begin());

		// If the target is a server name, translate it to a SID
		if (!InspIRCd::IsSID(params[0]))
		{
			TreeServer* server = Utils->FindServer(params[0]);
			if (!server)
			{
				// We've no idea what this is, log and stop processing
				ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Received a " + cmd + " with an unknown target: \"" + params[0] + "\", command dropped");
				return false;
			}

			params[0] = server->GetID();
		}
	}
	else if ((cmd == "GLINE") || (cmd == "KLINE") || (cmd == "ELINE") || (cmd == "ZLINE") || (cmd == "QLINE"))
	{
		// Fix undocumented protocol usage: translate GLINE, ZLINE, etc. into ADDLINE or DELLINE
		if ((params.size() != 1) && (params.size() != 3))
			return false;

		parameterlist p;
		p.push_back(cmd.substr(0, 1));
		p.push_back(params[0]);

		if (params.size() == 3)
		{
			cmd = "ADDLINE";
			p.push_back(who->nick);
			p.push_back(ConvToStr(ServerInstance->Time()));
			p.push_back(ConvToStr(InspIRCd::Duration(params[1])));
			p.push_back(params[2]);
		}
		else
			cmd = "DELLINE";

		params.swap(p);
	}
	else if (cmd == "SVSMODE")
	{
		cmd = "MODE";
	}
	else if (cmd == "OPERQUIT")
	{
		// Translate OPERQUIT into METADATA
		if (params.empty())
			return false;

		cmd = "METADATA";
		params.insert(params.begin(), who->uuid);
		params.insert(params.begin()+1, "operquit");
		who = MyRoot->ServerUser;
	}
	else if ((cmd == "TOPIC") && (params.size() >= 2))
	{
		// :20DAAAAAC TOPIC #chan :new topic
		cmd = "FTOPIC";
		if (!InsertCurrentChannelTS(params))
			return false;

		params.insert(params.begin()+2, ConvToStr(ServerInstance->Time()));
	}
	else if (cmd == "MODENOTICE")
	{
		// MODENOTICE is always supported by 2.0 but it's optional in 2.2.
		params.insert(params.begin(), "*");
		params.insert(params.begin()+1, cmd);
		cmd = "ENCAP";
	}
	else if (cmd == "RULES")
	{
		return false;
	}
	else if (cmd == "INVITE")
	{
		// :20D INVITE 22DAAABBB #chan
		// :20D INVITE 22DAAABBB #chan 123456789
		// Insert channel timestamp after the channel name; the 3rd parameter, if there, is the invite expiration time
		return InsertCurrentChannelTS(params, 1, 2);
	}
	else if (cmd == "VERSION")
	{
		// :20D VERSION :InspIRCd-2.0
		// change to
		// :20D SINFO version :InspIRCd-2.0
		cmd = "SINFO";
		params.insert(params.begin(), "version");
	}
	else if (cmd == "JOIN")
	{
		// 2.0 allows and forwards legacy JOINs but we don't, so translate them to FJOINs before processing
		if ((params.size() != 1) || (IS_SERVER(who)))
			return false; // Huh?

		cmd = "FJOIN";
		Channel* chan = ServerInstance->FindChan(params[0]);
		params.push_back(ConvToStr(chan ? chan->age : ServerInstance->Time()));
		params.push_back("+");
		params.push_back(",");
		params.back().append(who->uuid);
		who = TreeServer::Get(who)->ServerUser;
	}
	else if ((cmd == "FMODE") && (params.size() >= 2))
	{
		// Translate user mode changes with timestamp to MODE
		if (params[0][0] != '#')
		{
			User* user = ServerInstance->FindUUID(params[0]);
			if (!user)
				return false;

			// Emulate the old nonsensical behavior
			if (user->age < ServerCommand::ExtractTS(params[1]))
				return false;

			cmd = "MODE";
			params.erase(params.begin()+1);
		}
	}

	return true; // Passthru
}
Example #12
0
void ModuleSpanningTree::DoPingChecks(time_t curtime)
{
	/*
	 * Cancel remote burst mode on any servers which still have it enabled due to latency/lack of data.
	 * This prevents lost REMOTECONNECT notices
	 */
	timeval t;
	gettimeofday(&t, NULL);
	long ts = (t.tv_sec * 1000) + (t.tv_usec / 1000);

	for (server_hash::iterator i = Utils->serverlist.begin(); i != Utils->serverlist.end(); i++)
	{
		TreeServer *s = i->second;

		// Fix for bug #792, do not ping servers that are not connected yet!
		// Remote servers have Socket == NULL and local connected servers have
		// Socket->LinkState == CONNECTED
		if (s->GetSocket() && s->GetSocket()->GetLinkState() != CONNECTED)
			continue;

		// Now do PING checks on all servers
		TreeServer *mts = Utils->BestRouteTo(s->GetID());

		if (mts)
		{
			// Only ping if this server needs one
			if (curtime >= s->NextPingTime())
			{
				// And if they answered the last
				if (s->AnsweredLastPing())
				{
					// They did, send a ping to them
					s->SetNextPingTime(curtime + Utils->PingFreq);
					TreeSocket *tsock = mts->GetSocket();

					// ... if we can find a proper route to them
					if (tsock)
					{
						tsock->WriteLine(std::string(":") + ServerInstance->Config->GetSID() + " PING " +
								ServerInstance->Config->GetSID() + " " + s->GetID());
						s->LastPingMsec = ts;
					}
				}
				else
				{
					// They didn't answer the last ping, if they are locally connected, get rid of them.
					TreeSocket *sock = s->GetSocket();
					if (sock)
					{
						sock->SendError("Ping timeout");
						sock->Squit(s,"Ping timeout");
						ServerInstance->SE->DelFd(sock);
						sock->Close();
						return;
					}
				}
			}

			// If warn on ping enabled and not warned and the difference is sufficient and they didn't answer the last ping...
			if ((Utils->PingWarnTime) && (!s->Warned) && (curtime >= s->NextPingTime() - (Utils->PingFreq - Utils->PingWarnTime)) && (!s->AnsweredLastPing()))
			{
				/* The server hasnt responded, send a warning to opers */
				ServerInstance->SNO->WriteToSnoMask('l',"Server \002%s\002 has not responded to PING for %d seconds, high latency.", s->GetName().c_str(), Utils->PingWarnTime);
				s->Warned = true;
			}
		}
	}
}