Beispiel #1
0
void CKadHandler::HandleRouteReq(const CVariant& RouteReq, CKadNode* pNode, CComChannel* pChannel)
{
	if(GetParent<CKademlia>()->Cfg()->GetBool("DebugRU"))
		LogLine(LOG_DEBUG, L"Recived 'Route Resuest' from %s", pNode->GetID().ToHex().c_str());

	CVariant RouteRes(CVariant::EMap);

	SKadData* pData = pChannel->GetData<SKadData>();
	CPointer<CKadRelay> pRelay = pData->pLookup->Cast<CKadRelay>();
	if(!pRelay)
	{
		if(!RouteReq.Has("TID")) // this is optional it is not send on a refresn
			throw CException(LOG_ERROR, L"Invalid Lookup Request");

		if(pData->pLookup)
			throw CException(LOG_ERROR, L"Recived Route Resuest for a lookup that is not a CKadRelay");

		CLookupManager* pLookupManager = GetParent<CKademlia>()->Manager();
		pRelay = pLookupManager->GetRelayEx(RouteReq["EID"], RouteReq["TID"]); // find already existing relay for this Entity and target combination
		//ASSERT(pRelay == pLookupManager->GetLookup(RouteReq["LID"])->Cast<CKadRelay>()); // lookup ID should be consistent

		if(!pRelay)
		{
			pRelay = new CKadRelay(RouteReq["TID"], pLookupManager);
			if(pRelay->InitRelay(RouteReq)) // if false it means the lookup is invalid
			{
				pRelay->SetHopLimit(RouteReq.Get("JMPS"));
				pRelay->SetJumpCount(RouteReq.Get("HOPS"));

				pRelay->SetBrancheCount(RouteReq.Get("BRCH"));

				pRelay->SetLookupID(RouteReq["LID"]);
				pLookupManager->StartLookup(pRelay.Obj());

				if(RouteReq.Has("TRACE"))
					pRelay->EnableTrace();
			}
		}

		// For this cahnnel the relay was new, setup BC
		pData->pLookup = CPointer<CKadLookup>(pRelay, true); // weak pointer
		pChannel->AddUpLimit(pData->pLookup->GetUpLimit());
		pChannel->AddDownLimit(pData->pLookup->GetDownLimit());
	}

	string Error = pRelay->AddDownLink(pNode, pChannel); // add or update
	if(!Error.empty())
		RouteRes["ERR"] = Error;

	if(GetParent<CKademlia>()->Cfg()->GetBool("DebugRU"))
		LogLine(LOG_DEBUG, L"Sending 'Route Response' to %s", pNode->GetID().ToHex().c_str());
	pChannel->QueuePacket(KAD_ROUTE_RESPONSE, RouteRes);
}
Beispiel #2
0
CVariant CKadOperation::AddLoadRes(const CVariant& LoadRes, CKadNode* pNode)
{
	SOpProgress* pProgress = GetProgress(pNode);

	CVariant FilteredRes = LoadRes.Clone(false); // Make a Shellow Copy
	const CVariant& LoadedList = LoadRes["RES"];

	CVariant FilteredList;
	for(uint32 i=0; i < LoadedList.Count(); i++)
	{
		CVariant Loaded = LoadedList.At(i).Clone(false); // Make a Shellow Copy
		const CVariant& XID = Loaded["XID"];

		// Counting
		if(pProgress) // might be NULL if we filter our own index response right now
		{
			SOpStatus &Status = pProgress->Loads[XID];
			Status.Results++;
			if(!Loaded.Get("MORE"))
				Status.Done = true; // this marks that no more results are to be expected form this node
		}

		SOpStatus* pStatus = &m_LoadMap[XID].Status;
		pStatus->Results++;
		if(!pStatus->Done)
			pStatus->Done = IsDone(SOpProgress::GetLoads, XID);
		
		if(!pStatus->Done)
			Loaded.Insert("MORE", true);
		else
			Loaded.Remove("MORE");
		//

		if(Loaded.Has("ERR"))
		{
			FilteredList.Append(Loaded);
			continue;
		}

		// Filtering
		CVariant UniquePayloads;
		const CVariant& Payloads = Loaded["PLD"];
		for(uint32 j=0; j < Payloads.Count(); j++)
		{
			const CVariant& Payload = Payloads.At(j);
			if(m_LoadFilter[XID].insert(Payload["DATA"].GetFP()).second)
				UniquePayloads.Append(Payload);
		}

		// Note: we must add this even if UniquePayloads is empty or else we will misscount replys
		CVariant NewLoaded;
		NewLoaded["XID"] = XID;
		NewLoaded["PLD"] = UniquePayloads;
		FilteredList.Append(NewLoaded);
		//
	}

	FilteredRes.Insert("RES", FilteredList);
	return FilteredRes;
}
Beispiel #3
0
bool CKadScript::LoadData(const wstring& Path)
{
	CVariant Data;
	if(!ReadFile(Path, Data))
		return false;

	try
	{
		m_LastUsed = Data["LastUsed"].To<uint64>();
		if(!m_LastUsed)
			m_LastUsed = GetTime();

		m_Data->Set(Data["Data"]);

		if(Data.Has("KEY"))
		{
			CVariant SecretKey = Data["KEY"];
			if(SecretKey.Decrypt(GetParent<CKademlia>()->Root()->GetID().GetPrivateKey()))
			{
				m_SecretKey = new CAbstractKey;
				if(!m_SecretKey->SetKey(SecretKey.GetData(), SecretKey.GetSize()))
					m_SecretKey = NULL;
			}
		}

		m_Authentication = Data.Get("AUTH");
	}
	catch(const CException&)
	{
		return false;
	}
	return true;
}
Beispiel #4
0
void CKadHandler::HandleNodeReq(const CVariant& NodeReq, CKadNode* pNode, CComChannel* pChannel)
{
	if(GetParent<CKademlia>()->Cfg()->GetBool("DebugRT"))
		LogLine(LOG_DEBUG, L"Recived 'Node Resuest' to %s", pNode->GetID().ToHex().c_str());

	CVariant NodeRes;

	uint32 uDesiredCount = NodeReq["RCT"];
	if(uDesiredCount == 0)
		throw CException(LOG_ERROR, L"node requested 0 nodes");

	int iMaxState = NodeReq.Get("MNC", NODE_2ND_CLASS);

	NodeMap Nodes;
	if(!NodeReq.Has("TID"))
		GetParent<CKademlia>()->Root()->GetBootstrapNodes(GetParent<CKademlia>()->Root()->GetID(), Nodes, uDesiredCount, pChannel->GetAddress().GetProtocol(), iMaxState);
	else
		GetParent<CKademlia>()->Root()->GetClosestNodes(NodeReq["TID"], Nodes, uDesiredCount, pChannel->GetAddress().GetProtocol(), iMaxState);
	
	CVariant List;
	for(NodeMap::iterator I = Nodes.begin(); I != Nodes.end(); I++)
		List.Append(I->second->Store());
	NodeRes["LIST"] = List;

	if(GetParent<CKademlia>()->Cfg()->GetBool("DebugRT"))
		LogLine(LOG_DEBUG, L"Sending 'Node Response' to %s", pNode->GetID().ToHex().c_str());
	pChannel->QueuePacket(KAD_NODE_RESPONSE, NodeRes);
}
Beispiel #5
0
void CKadHandler::HandleRouteRes(const CVariant& RouteRes, CKadNode* pNode, CComChannel* pChannel)
{
	if(GetParent<CKademlia>()->Cfg()->GetBool("DebugRU"))
		LogLine(LOG_DEBUG, L"Recived 'Route Response' from %s", pNode->GetID().ToHex().c_str());

	SKadData* pData = pChannel->GetData<SKadData>();
	CKadRelay* pRelay = pData->pLookup->Cast<CKadRelay>();
	if(!pRelay)
		throw CException(LOG_ERROR, L"Recived Route Response for a lookup that is not a CKadRelay");

	// Note: this is for trace only, it does not have any deeper purpose
	if(pRelay->IsTraced())
	{
		CVariant Trace = RouteRes.Get("TRACE").Clone();
		Trace.Append(pNode->GetID());

		if(!pRelay->Inherits("CKadRoute")) // if its just a relay we have to relay the trace back
		{
			CVariant RouteRel;
			RouteRel["TID"] = RouteRes["TID"]; // pRelay->GetID()
			RouteRel["TRACE"] = Trace;

			if(CFrameRelay* pDownLink = pRelay->GetDownLink())
			{
				CFrameRelay::TRelayMap& DownNodes = pDownLink->GetNodes();
				for(CFrameRelay::TRelayMap::iterator I = DownNodes.begin(); I != DownNodes.end(); I++)
				{
					if(I->first.pChannel->IsConnected())
					{
						if(GetParent<CKademlia>()->Cfg()->GetBool("DebugLU"))
							LogLine(LOG_DEBUG, L"Relaying 'Route Response' from %s to %s", pNode->GetID().ToHex().c_str(), I->first.pNode->GetID().ToHex().c_str());
						I->first.pChannel->QueuePacket(KAD_ROUTE_RESPONSE, RouteRel);
					}
				}
			}
		}
		else
			pRelay->RecivedTraceResults(Trace);
	}

	if(RouteRes.Has("TRACE")) // if this is set its a pro forma trace response ignore it
		return;
	
	pRelay->UpLinkResponse(pNode, pChannel, RouteRes.Get("ERR"));
}
Beispiel #6
0
bool CKadHandler::SendRelayRes(CKadNode* pNode, CComChannel* pChannel, const CVariant& Frame, const string& Error, const CVariant& Load)
{
	CVariant RelayRes;

	CVariant FrameRes;
	if(Frame.Has("TID"))
		FrameRes["TID"] = Frame["TID"];
	FrameRes["EID"] = Frame["EID"];
	FrameRes["RID"] = Frame["RID"];
	FrameRes["FID"] = Frame["FID"]; // peer to peer (local) ACK
	if(!Error.empty())
		FrameRes["ERR"] = Error;
	if(Load.IsValid())
		FrameRes["LOAD"] = Load;
	RelayRes["FRM"] = FrameRes;

	if(GetParent<CKademlia>()->Cfg()->GetBool("DebugRE"))
		LogLine(LOG_DEBUG, L"Sending 'Relay Response' to %s", pNode->GetID().ToHex().c_str());
	return pChannel->QueuePacket(KAD_RELAY_RESPONSE, RelayRes);
}
Beispiel #7
0
CVariant CKadOperation::AddCallRes(const CVariant& CallRes, CKadNode* pNode)
{
	SOpProgress* pProgress = GetProgress(pNode);

	CVariant FilteredRes = CallRes.Clone(false); // Make a Shellow Copy
	const CVariant& Results = CallRes["RET"];

	CVariant Filtered;
	for(uint32 i=0; i < Results.Count(); i++)
	{
        CVariant Result = Results.At(i).Clone(false); // Make a Shellow Copy
		const CVariant& XID = Result["XID"];

		// this checks if this particular response is the last and and if this node is done
		if(pProgress) // might be NULL if we filter our own index response right now
		{
			SOpStatus &Status = pProgress->Calls[XID];
			Status.Results++;
			if(!Result.Get("MORE"))
				Status.Done = true; // this marks that no more results are to be expected form this node
		}

		SOpStatus* pStatus = NULL;
		TCallOpMap::iterator I = m_CallMap.find(XID);
		if(I != m_CallMap.end())
		{
			pStatus = &I->second.Status;
			pStatus->Results++; // count the response even if it gets filtered lateron
			if(!pStatus->Done)
				pStatus->Done = IsDone(SOpProgress::GetCalls, XID);
		}

		if(m_pOperator)
		{
			CKadOperator::TRequestMap& ResuestMap = m_pOperator->GetRequests();
			CKadOperator::TRequestMap::iterator I = ResuestMap.find(XID);
			if(I != ResuestMap.end()) // this should not fail
			{
				SOpStatus* pAuxStatus = &I->second.Status;
				pAuxStatus->Results++; // count the response even if it gets filtered lateron
				if(!pAuxStatus->Done)
					pAuxStatus->Done = IsDone(SOpProgress::GetCalls, XID);
			}
		}

		if(!Result.Has("ERR"))
		{
			if(m_pOperator && m_pOperator->IsValid())
			{
				try
				{
					if(m_pOperator->AddCallRes(Result["RET"], XID))
						continue; // intercepted response - Note: if we add a response to this request now it wil be marked as no more results if thats so
				}
				catch(const CJSException& Exception)
				{
					LogReport(Exception.GetFlag(), Exception.GetLine(), Exception.GetError());
				}
			}
		}
		//else 
		//	LogLine(LOG_ERROR | LOG_DEBUG, L"Got Execution Error %s", Result["ERR"].To<wstring>().c_str());

		// check if this is a call we issued, that is one not present in the call map, in that case its never to be relayed
		if(pStatus)
		{
			// UpdateMore sets the "MORE" flag on the packet we relay further down to the source, and checks if we considder this request done
			if(!pStatus->Done)
				Result.Insert("MORE", true);
			else
				Result.Remove("MORE");

			Filtered.Append(Result);
		}
	}

	if(m_pOperator) // add new result to the filtered list
		Filtered.Merge(m_pOperator->GetResponses());
	FilteredRes.Insert("RET", Filtered);
	return FilteredRes;
}
Beispiel #8
0
void CKadHandler::HandleCryptoResponse(const CVariant& Response, CKadNode* pNode, CComChannel* pChannel)
{
	SKadData* pData = pChannel->GetData<SKadData>();
	if(GetParent<CKademlia>()->Cfg()->GetBool("DebugTL"))
		LogLine(LOG_DEBUG, L"Recived 'CryptoResponse' to %s", pNode->GetID().ToHex().c_str());

	SKeyExchange* Key = NULL;
	TExchangeMap::iterator I = m_KeyExchanges.find(SKadNode(pNode));
	for(; I != m_KeyExchanges.end() && I->first.pNode == pNode; I++)
	{
		if(I->first.pChannel == pChannel)
		{
			Key = &I->second;
			break;
		}
	}
	if(!Key)
		throw CException(LOG_ERROR | LOG_DEBUG, L"Unsolicited Crypto Response");

	CScoped<CSymmetricKey> pCryptoKey;
	try
	{
		if(Response.Has("ERR"))
		{
			string Error = Response["ERR"];
			if(Error == "UnknownKey")
			{
				pNode->SetTrustedKey(NULL);
				Key->pExchange = NULL;
				ResumeExchange(I->first.pNode);
				return;
			}
			else
				throw CException(LOG_ERROR | LOG_DEBUG, L"Crypto Response Returned Error: %S", Error.c_str());
		}

		CScoped<CAbstractKey> pSessionKey;
		if(Key->pExchange->GetAlgorithm() & CAbstractKey::eKeyExchange)
		{
			if(!Response.Has("EK"))
				throw "MissingEK";
			CScoped<CAbstractKey> pRemKey = new CAbstractKey(Response["EK"].GetData(), Response["EK"].GetSize());
			pSessionKey = Key->pExchange->FinaliseKeyExchange(pRemKey);
			if(!pSessionKey)
				throw "ExchangeFailed";

			if(Key->bAuthenticate)
			{
				CPublicKey* pPubKey;
				if(Response.Has("PK")) 
					pPubKey = pNode->SetIDKey(Response);
				else
					pPubKey = pNode->GetID().GetKey();

				if(!pPubKey)
					throw "MissingKey";

				if(!Response.Verify(pPubKey))
					throw "InvalidSign";
			}

			pData->Authenticated = Key->bAuthenticate;
			pNode->SetTrustedKey(new CTrustedKey(pSessionKey->GetKey(), pSessionKey->GetSize(), Key->bAuthenticate));

			ResumeExchange(I->first.pNode);
		}
		else
		{
			pData->Authenticated = Key->bAuthenticate;
			pSessionKey = Key->pExchange->FinaliseKeyExchange(NULL);
		}

		if(Response.Has("IV"))
		{
			UINT eAlgorithm = PrepSC(Key->eAlgorithm); // UINT eAlgorithm = PrepSC(Key->pExchange->GetIV()->GetAlgorithm());

			CAbstractKey InIV(Response["IV"].GetData(), Response["IV"].GetSize());

			pCryptoKey = NewSymmetricKey(eAlgorithm, pSessionKey, &InIV, Key->pExchange->GetIV());
		}
	}
	catch(const char* Error)
	{
		throw CException(LOG_ERROR | LOG_DEBUG, L"Crypto Response Error: %S", Error);
	}

	m_KeyExchanges.erase(I);

	if(pCryptoKey)
	{
		pChannel->Encrypt(pCryptoKey.Detache());
		pChannel->SetQueueLock(false); // release the packet queue lock such that we can start sending encrypted payload packets
	}
}
Beispiel #9
0
void CKadHandler::HandleCryptoRequest(const CVariant& Request, CKadNode* pNode, CComChannel* pChannel)
{
	SKadData* pData = pChannel->GetData<SKadData>();
	if(GetParent<CKademlia>()->Cfg()->GetBool("DebugTL"))
		LogLine(LOG_DEBUG, L"Recived 'CryptoRequest' to %s", pNode->GetID().ToHex().c_str());

	CVariant Response(CVariant::EMap);

	CScoped<CSymmetricKey> pCryptoKey;
	try
	{
		CScoped<CAbstractKey> pSessionKey;
		if(Request.Has("EK"))
		{
			UINT eExAlgorithm = 0;
			string Param;
			if(Request.Has("KA"))
				eExAlgorithm = ParseKA(Request["KA"], Param);
			UINT eAlgorithm = PrepKA(eExAlgorithm, Param);
			CScoped<CKeyExchange> pKeyExchange = NewKeyExchange(eAlgorithm, Param);

			CScoped<CAbstractKey> pKey = pKeyExchange->InitialsieKeyExchange();
			Response["EK"] = CVariant(pKey->GetKey(), pKey->GetSize());

			CScoped<CAbstractKey> pRemKey = new CAbstractKey(Request["EK"].GetData(), Request["EK"].GetSize());
			pSessionKey = pKeyExchange->FinaliseKeyExchange(pRemKey);
			if(!pSessionKey)
				throw "ExchangeFailed";

			bool bAuthenticated = Request.IsSigned();
			if(bAuthenticated)
			{
				CPublicKey* pPubKey;
				if(Request.Has("PK"))
					pPubKey = pNode->SetIDKey(Request);
				else
					pPubKey = pNode->GetID().GetKey();
			
				if(!pPubKey)
					throw "MissingKey";

				if(!Request.Verify(pPubKey))
					throw "InvalidSign";
			}

			pData->Authenticated = bAuthenticated;
			pNode->SetTrustedKey(new CTrustedKey(pSessionKey->GetKey(), pSessionKey->GetSize(), bAuthenticated, eAlgorithm & CAbstractKey::eHashFunkt));
		}
		else if(Request.Has("FP"))
		{
			CTrustedKey* pTrustedKey = pNode->GetTrustedKey();
			if(!pTrustedKey || pTrustedKey->GetFingerPrint() != Request["FP"].To<uint64>())
				throw "UnknownKey";

			pData->Authenticated = pTrustedKey->IsAuthenticated();
			pSessionKey = new CAbstractKey(pTrustedKey->GetKey(), pTrustedKey->GetSize());
		}
		else
			throw "UnknownMethod";

		if(Request.Has("IV"))
		{
			CAbstractKey OutIV(KEY_128BIT, true);
			Response["IV"] = CVariant(OutIV.GetKey(), OutIV.GetSize());

			UINT eSymAlgorithm = 0;
			if(Request.Has("SC"))
				eSymAlgorithm = ParseSC(Request["SC"]);
			UINT eAlgorithm = PrepSC(eSymAlgorithm);

			CAbstractKey InIV(Request["IV"].GetData(), Request["IV"].GetSize());

			pCryptoKey = NewSymmetricKey(eAlgorithm, pSessionKey, &InIV, &OutIV);
		}

		if(Request.IsSigned() && pData->Authenticated)
		{
			const CMyKadID& MyID = GetParent<CKademlia>()->Root()->GetID();
			Response["PK"] = CVariant(MyID.GetKey()->GetKey(), MyID.GetKey()->GetSize());
			if((MyID.GetKey()->GetAlgorithm() & CAbstractKey::eHashFunkt) != 0)
				Response["HK"] = CAbstractKey::Algorithm2Str((MyID.GetKey()->GetAlgorithm() & CAbstractKey::eHashFunkt));
		
			Response.Sign(MyID.GetPrivateKey());
		}
	}
	catch(const char* Error)
	{
		delete pCryptoKey.Detache();
		Response["ERR"] = Error;
	}

	if(GetParent<CKademlia>()->Cfg()->GetBool("DebugTL"))
		LogLine(LOG_DEBUG, L"Sending 'CryptoResponse' to %s", pNode->GetID().ToHex().c_str());
	pChannel->SendPacket(KAD_CRYPTO_RESPONSE, Response);

	if(pCryptoKey)
	{
		pChannel->SetQueueLock(true);
		pChannel->Encrypt(pCryptoKey.Detache());
		pChannel->SetQueueLock(false);
	}
}