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); }
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; }
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; }
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); }
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")); }
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); }
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; }
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 } }
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); } }