Пример #1
0
/** Because most of the I/O gubbins are encapsulated within
 * BufferedSocket, we just call the superclass constructor for
 * most of the action, and append a few of our own values
 * to it.
 */
TreeSocket::TreeSocket(SpanningTreeUtilities* Util, Link* link, Autoconnect* myac, const std::string& ipaddr)
	: Utils(Util)
{
	age = ServerInstance->Time();
	linkID = assign(link->Name);
	capab = new CapabData;
	capab->link = link;
	capab->ac = myac;
	capab->capab_phase = 0;
	MyRoot = NULL;
	proto_version = 0;
	ConnectionFailureShown = false;
	LinkState = CONNECTING;
	if (!link->Hook.empty())
	{
		ServiceProvider* prov = ServerInstance->Modules->FindService(SERVICE_IOHOOK, link->Hook);
		if (!prov)
		{
			SetError("Could not find hook '" + link->Hook + "' for connection to " + linkID);
			return;
		}
		AddIOHook(prov->creator);
	}
	DoConnect(ipaddr, link->Port, link->Timeout, link->Bind);
	Utils->timeoutlist[this] = std::pair<std::string, int>(linkID, link->Timeout);
	SendCapabilities(1);
}
Пример #2
0
/** Constructor for incoming connections
 */
TreeSocket::TreeSocket(int newfd, ListenSocket* via, irc::sockets::sockaddrs* client, irc::sockets::sockaddrs* server)
	: BufferedSocket(newfd)
	, linkID("inbound from " + client->addr()), LinkState(WAIT_AUTH_1), MyRoot(NULL), proto_version(0)
	, burstsent(false), age(ServerInstance->Time())
{
	capab = new CapabData;
	capab->capab_phase = 0;

	for (ListenSocket::IOHookProvList::iterator i = via->iohookprovs.begin(); i != via->iohookprovs.end(); ++i)
	{
		ListenSocket::IOHookProvRef& iohookprovref = *i;
		if (!iohookprovref)
			continue;

		iohookprovref->OnAccept(this, client, server);
		// IOHook could have encountered a fatal error, e.g. if the TLS ClientHello was already in the queue and there was no common TLS version
		if (!getError().empty())
		{
			TreeSocket::OnError(I_ERR_OTHER);
			return;
		}
	}

	SendCapabilities(1);

	Utils->timeoutlist[this] = std::pair<std::string, int>(linkID, 30);
}
Пример #3
0
/** Because most of the I/O gubbins are encapsulated within
 * BufferedSocket, we just call the superclass constructor for
 * most of the action, and append a few of our own values
 * to it.
 */
TreeSocket::TreeSocket(Link* link, Autoconnect* myac, const std::string& ipaddr)
	: linkID(assign(link->Name)), LinkState(CONNECTING), MyRoot(NULL), proto_version(0), ConnectionFailureShown(false)
	, age(ServerInstance->Time())
{
	capab = new CapabData;
	capab->link = link;
	capab->ac = myac;
	capab->capab_phase = 0;

	DoConnect(ipaddr, link->Port, link->Timeout, link->Bind);
	Utils->timeoutlist[this] = std::pair<std::string, int>(linkID, link->Timeout);
	SendCapabilities(1);
}
Пример #4
0
/** When a listening socket gives us a new file descriptor,
 * we must associate it with a socket without creating a new
 * connection. This constructor is used for this purpose.
 */
TreeSocket::TreeSocket(int newfd, ListenSocket* via, irc::sockets::sockaddrs* client, irc::sockets::sockaddrs* server)
	: BufferedSocket(newfd)
	, linkID("inbound from " + client->addr()), LinkState(WAIT_AUTH_1), MyRoot(NULL), proto_version(0)
	, ConnectionFailureShown(false), age(ServerInstance->Time())
{
	capab = new CapabData;
	capab->capab_phase = 0;

	if (via->iohookprov)
		via->iohookprov->OnAccept(this, client, server);
	SendCapabilities(1);

	Utils->timeoutlist[this] = std::pair<std::string, int>(linkID, 30);
}
Пример #5
0
/** When a listening socket gives us a new file descriptor,
 * we must associate it with a socket without creating a new
 * connection. This constructor is used for this purpose.
 */
TreeSocket::TreeSocket(SpanningTreeUtilities* Util, int newfd, ListenSocket* via, irc::sockets::sockaddrs* client, irc::sockets::sockaddrs* server)
	: BufferedSocket(newfd), Utils(Util)
{
	capab = new CapabData;
	capab->capab_phase = 0;
	MyRoot = NULL;
	age = ServerInstance->Time();
	LinkState = WAIT_AUTH_1;
	proto_version = 0;
	ConnectionFailureShown = false;
	linkID = "inbound from " + client->addr();

	FOREACH_MOD(I_OnHookIO, OnHookIO(this, via));
	if (GetIOHook())
		GetIOHook()->OnStreamSocketAccept(this, client, server);
	SendCapabilities(1);

	Utils->timeoutlist[this] = std::pair<std::string, int>(linkID, 30);
}
Пример #6
0
/** Because most of the I/O gubbins are encapsulated within
 * BufferedSocket, we just call the superclass constructor for
 * most of the action, and append a few of our own values
 * to it.
 */
TreeSocket::TreeSocket(Link* link, Autoconnect* myac, const std::string& ipaddr)
	: linkID(assign(link->Name)), LinkState(CONNECTING), MyRoot(NULL), proto_version(0), ConnectionFailureShown(false)
	, age(ServerInstance->Time())
{
	capab = new CapabData;
	capab->link = link;
	capab->ac = myac;
	capab->capab_phase = 0;
	if (!link->Hook.empty())
	{
		ServiceProvider* prov = ServerInstance->Modules->FindService(SERVICE_IOHOOK, link->Hook);
		if (!prov)
		{
			SetError("Could not find hook '" + link->Hook + "' for connection to " + linkID);
			return;
		}
		AddIOHook(static_cast<IOHook*>(prov));
	}
	DoConnect(ipaddr, link->Port, link->Timeout, link->Bind);
	Utils->timeoutlist[this] = std::pair<std::string, int>(linkID, link->Timeout);
	SendCapabilities(1);
}
Пример #7
0
bool TreeSocket::Capab(const parameterlist &params)
{
	if (params.size() < 1)
	{
		this->SendError("Invalid number of parameters for CAPAB - Mismatched version");
		return false;
	}
	if (params[0] == "START")
	{
		capab->ModuleList.clear();
		capab->OptModuleList.clear();
		capab->CapKeys.clear();
		if (params.size() > 1)
			proto_version = atoi(params[1].c_str());
		SendCapabilities(2);
	}
	else if (params[0] == "END")
	{
		std::string reason;
		/* Compare ModuleList and check CapKeys */
		if ((this->capab->ModuleList != this->MyModules(VF_COMMON)) && (this->capab->ModuleList.length()))
		{
			std::string diffIneed, diffUneed;
			ListDifference(this->capab->ModuleList, this->MyModules(VF_COMMON), ' ', diffIneed, diffUneed);
			if (diffIneed.length() || diffUneed.length())
			{
				reason = "Modules incorrectly matched on these servers.";
				if (diffIneed.length())
					reason += " Not loaded here:" + diffIneed;
				if (diffUneed.length())
					reason += " Not loaded there:" + diffUneed;
				this->SendError("CAPAB negotiation failed: "+reason);
				return false;
			}
		}
		if (this->capab->OptModuleList != this->MyModules(VF_OPTCOMMON) && this->capab->OptModuleList.length())
		{
			std::string diffIneed, diffUneed;
			ListDifference(this->capab->OptModuleList, this->MyModules(VF_OPTCOMMON), ' ', diffIneed, diffUneed);
			if (diffIneed.length() || diffUneed.length())
			{
				if (Utils->AllowOptCommon)
				{
					ServerInstance->SNO->WriteToSnoMask('l',
						"Optional module lists do not match, some commands may not work globally.%s%s%s%s",
						diffIneed.length() ? " Not loaded here:" : "", diffIneed.c_str(),
						diffUneed.length() ? " Not loaded there:" : "", diffUneed.c_str());
				}
				else
				{
					reason = "Optional modules incorrectly matched on these servers, and options::allowmismatch not set.";
					if (diffIneed.length())
						reason += " Not loaded here:" + diffIneed;
					if (diffUneed.length())
						reason += " Not loaded there:" + diffUneed;
					this->SendError("CAPAB negotiation failed: "+reason);
					return false;
				}
			}
		}

		if (this->capab->CapKeys.find("PROTOCOL") == this->capab->CapKeys.end())
		{
			reason = "Protocol version not specified";
		}
		else
		{
			proto_version = atoi(capab->CapKeys.find("PROTOCOL")->second.c_str());
			if (proto_version < MinCompatProtocol)
			{
				reason = "Server is using protocol version " + ConvToStr(proto_version) +
					" which is too old to link with this server (version " + ConvToStr(ProtocolVersion)
					+ (ProtocolVersion != MinCompatProtocol ? ", links with " + ConvToStr(MinCompatProtocol) + " and above)" : ")");
			}
		}

		if(this->capab->CapKeys.find("PREFIX") != this->capab->CapKeys.end() && this->capab->CapKeys.find("PREFIX")->second != ServerInstance->Modes->BuildPrefixes())
			reason = "One or more of the prefixes on the remote server are invalid on this server.";

		if (!capab->ChanModes.empty())
		{
			if (capab->ChanModes != BuildModeList(MODETYPE_CHANNEL))
			{
				std::string diffIneed, diffUneed;
				ListDifference(capab->ChanModes, BuildModeList(MODETYPE_CHANNEL), ' ', diffIneed, diffUneed);
				if (diffIneed.length() || diffUneed.length())
				{
					reason = "Channel modes not matched on these servers.";
					if (diffIneed.length())
						reason += " Not loaded here:" + diffIneed;
					if (diffUneed.length())
						reason += " Not loaded there:" + diffUneed;
				}
			}
		}
		else if (this->capab->CapKeys.find("CHANMODES") != this->capab->CapKeys.end())
		{
			if (this->capab->CapKeys.find("CHANMODES")->second != ServerInstance->Modes->GiveModeList(MASK_CHANNEL))
				reason = "One or more of the channel modes on the remote server are invalid on this server.";
		}

		if (!capab->UserModes.empty())
		{
			if (capab->UserModes != BuildModeList(MODETYPE_USER))
			{
				std::string diffIneed, diffUneed;
				ListDifference(capab->UserModes, BuildModeList(MODETYPE_USER), ' ', diffIneed, diffUneed);
				if (diffIneed.length() || diffUneed.length())
				{
					reason = "User modes not matched on these servers.";
					if (diffIneed.length())
						reason += " Not loaded here:" + diffIneed;
					if (diffUneed.length())
						reason += " Not loaded there:" + diffUneed;
				}
			}
		}
		else if (this->capab->CapKeys.find("USERMODES") != this->capab->CapKeys.end())
		{
			if (this->capab->CapKeys.find("USERMODES")->second != ServerInstance->Modes->GiveModeList(MASK_USER))
				reason = "One or more of the user modes on the remote server are invalid on this server.";
		}

		/* Challenge response, store their challenge for our password */
		std::map<std::string,std::string>::iterator n = this->capab->CapKeys.find("CHALLENGE");
		if (Utils->ChallengeResponse && (n != this->capab->CapKeys.end()) && (ServerInstance->Modules->Find("m_sha256.so")))
		{
			/* Challenge-response is on now */
			this->SetTheirChallenge(n->second);
			if (!this->GetTheirChallenge().empty() && (this->LinkState == CONNECTING))
			{
				this->SendCapabilities(2);
				this->WriteLine("SERVER "+ServerInstance->Config->ServerName+" "+this->MakePass(capab->link->SendPass, capab->theirchallenge)+" 0 "+ServerInstance->Config->GetSID()+" :"+ServerInstance->Config->ServerDesc);
			}
		}
		else
		{
			/* They didnt specify a challenge or we don't have m_sha256.so, we use plaintext */
			if (this->LinkState == CONNECTING)
			{
				this->SendCapabilities(2);
				this->WriteLine("SERVER "+ServerInstance->Config->ServerName+" "+capab->link->SendPass+" 0 "+ServerInstance->Config->GetSID()+" :"+ServerInstance->Config->ServerDesc);
			}
		}

		if (reason.length())
		{
			this->SendError("CAPAB negotiation failed: "+reason);
			return false;
		}
	}
	else if ((params[0] == "MODULES") && (params.size() == 2))
	{
		if (!capab->ModuleList.length())
		{
			capab->ModuleList = params[1];
		}
		else
		{
			capab->ModuleList.push_back(' ');
			capab->ModuleList.append(params[1]);
		}
	}
	else if ((params[0] == "MODSUPPORT") && (params.size() == 2))
	{
		if (!capab->OptModuleList.length())
		{
			capab->OptModuleList = params[1];
		}
		else
		{
			capab->OptModuleList.push_back(' ');
			capab->OptModuleList.append(params[1]);
		}
	}
	else if ((params[0] == "CHANMODES") && (params.size() == 2))
	{
		capab->ChanModes = params[1];
	}
	else if ((params[0] == "USERMODES") && (params.size() == 2))
	{
		capab->UserModes = params[1];
	}
	else if ((params[0] == "CAPABILITIES") && (params.size() == 2))
	{
		irc::tokenstream capabs(params[1]);
		std::string item;
		while (capabs.GetToken(item))
		{
			/* Process each key/value pair */
			std::string::size_type equals = item.find('=');
			if (equals != std::string::npos)
			{
				std::string var = item.substr(0, equals);
				std::string value = item.substr(equals+1, item.length());
				capab->CapKeys[var] = value;
			}
		}
	}
	return true;
}