From c5f70d45592ba37ff7ee83694c95bef2ddfa49ea Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 10 Feb 2014 15:13:16 -0500 Subject: [PATCH 1/5] wait for DeliveryStatus message --- SSU.cpp | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/SSU.cpp b/SSU.cpp index a412a9c1..2892f0d7 100644 --- a/SSU.cpp +++ b/SSU.cpp @@ -47,6 +47,7 @@ namespace ssu { switch (m_State) { + case eSessionStateConfirmedSent: case eSessionStateEstablished: // most common case ProcessMessage (buf, len); @@ -132,8 +133,6 @@ namespace ssu i2p::context.UpdateAddress (ourIP.to_string ().c_str ()); uint32_t relayTag = be32toh (*(uint32_t *)(buf + sizeof (SSUHeader) + 263)); SendSessionConfirmed (buf + sizeof (SSUHeader), ourAddress, relayTag); - m_State = eSessionStateEstablished; - Established (); } } @@ -147,9 +146,9 @@ namespace ssu if ((header->flag >> 4) == PAYLOAD_TYPE_SESSION_CONFIRMED) { m_State = eSessionStateConfirmedReceived; - LogPrint ("Session confirmed received"); - // TODO: + LogPrint ("Session confirmed received"); m_State = eSessionStateEstablished; + // TODO: send DeliverStatus Established (); } else @@ -374,6 +373,7 @@ namespace ssu void SSUSession::Established () { + SendI2NPMessage (CreateDatabaseStoreMsg ()); if (!m_DelayedMessages.empty ()) { for (auto it :m_DelayedMessages) @@ -463,11 +463,25 @@ namespace ssu m_IncomleteMessages[msgID] = msg; if (isLast) { + SendMsgAck (msgID); if (fragmentNum > 0) m_IncomleteMessages.erase (msgID); msg->FromSSU (msgID); - i2p::HandleI2NPMessage (msg, false); - SendMsgAck (msgID); + if (m_State == eSessionStateEstablished) + i2p::HandleI2NPMessage (msg, false); + else + { + // we expect DeliveryStatus + if (msg->GetHeader ()->typeID == eI2NPDeliveryStatus) + { + LogPrint ("SSU session established"); + m_State = eSessionStateEstablished; + Established (); + } + else + LogPrint ("SSU unexpected message ", (int)msg->GetHeader ()->typeID); + DeleteI2NPMessage (msg); + } } } buf += fragmentSize; From 4862b594e8675a6848aca2f6b548197ad817a617 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 10 Feb 2014 19:27:55 -0500 Subject: [PATCH 2/5] use SSU if NTCP is not available --- SSU.cpp | 19 ++++++++++++------- Transports.cpp | 18 +++++++++++++++++- 2 files changed, 29 insertions(+), 8 deletions(-) diff --git a/SSU.cpp b/SSU.cpp index 2892f0d7..cb23f4f0 100644 --- a/SSU.cpp +++ b/SSU.cpp @@ -528,10 +528,13 @@ namespace ssu uint32_t fragmentNum = 0; while (len > 0) { - uint8_t buf[SSU_MTU + 18], iv[16]; - buf[0] = DATA_FLAG_WANT_REPLY; // for compatibility - buf[1] = 1; // always 1 message fragment per message - *(uint32_t *)(buf + 2) = msgID; + uint8_t buf[SSU_MTU + 18], iv[16], * payload = buf + sizeof (SSUHeader); + *payload = DATA_FLAG_WANT_REPLY; // for compatibility + payload++; + *payload = 1; // always 1 message fragment per message + payload++; + *(uint32_t *)payload = msgID; + payload += 4; bool isLast = (len <= payloadSize); size_t size = isLast ? len : payloadSize; uint32_t fragmentInfo = (fragmentNum << 17); @@ -540,10 +543,11 @@ namespace ssu fragmentInfo |= size; fragmentInfo = htobe32 (fragmentInfo); - memcpy (buf + 6, (uint8_t *)(&fragmentInfo) + 1, 3); - memcpy (buf + 9, msgBuf, size); + memcpy (payload, (uint8_t *)(&fragmentInfo) + 1, 3); + payload += 3; + memcpy (payload, msgBuf, size); - size += sizeof (SSUHeader) + 9; + size += payload - buf; if (size % 16) // make sure 16 bytes boundary size = (size/16 + 1)*16; @@ -584,6 +588,7 @@ namespace ssu void SSUServer::Stop () { + DeleteAllSessions (); m_Socket.close (); } diff --git a/Transports.cpp b/Transports.cpp index dc76b35c..ac5085fa 100644 --- a/Transports.cpp +++ b/Transports.cpp @@ -168,7 +168,23 @@ namespace i2p AddNTCPSession (session); } else - LogPrint ("No NTCP addresses available"); + { + // SSU always have lower prioprity than NTCP + // TODO: it shouldn't + LogPrint ("No NTCP addresses available. Trying SSU"); + address = r->GetSSUAddress (); + if (address && m_SSUServer) + { + auto s = m_SSUServer->GetSession (r); + if (s) + { + s->SendI2NPMessage (msg); + return; + } + } + else + LogPrint ("No SSU addresses available"); + } } else { From f8d105551fc7e0b1160e53a3fe0c0dfd4a4dd423 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 11 Feb 2014 15:51:32 -0500 Subject: [PATCH 3/5] handle session destroyed --- SSU.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/SSU.cpp b/SSU.cpp index cb23f4f0..47d40abc 100644 --- a/SSU.cpp +++ b/SSU.cpp @@ -87,15 +87,22 @@ namespace ssu LogPrint ("SSU test received"); break; case PAYLOAD_TYPE_SESSION_DESTROYED: + { LogPrint ("SSU session destroy received"); + if (m_Server) + m_Server->DeleteSession (this); // delete this + } break; default: LogPrint ("Unexpected SSU payload type ", (int)payloadType); } } - // TODO: try intro key as well + // TODO: try intro key else + { LogPrint ("MAC verifcation failed"); + m_State = eSessionStateUnknown; + } } void SSUSession::ProcessSessionRequest (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint) From 103be652ab6dc0d5ca6eee6ba2b6f7719529a73e Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 11 Feb 2014 22:19:51 -0500 Subject: [PATCH 4/5] improve exploratory --- NetDb.cpp | 38 ++++++++++++++++++++++++++++---------- NetDb.h | 1 + 2 files changed, 29 insertions(+), 10 deletions(-) diff --git a/NetDb.cpp b/NetDb.cpp index 01234ad7..aa040758 100644 --- a/NetDb.cpp +++ b/NetDb.cpp @@ -448,10 +448,18 @@ namespace data { auto r = FindRouter (router); // do we have that floodfill router in our database? - if (r) + if (r) { + // we do if (!dest->IsExcluded (r->GetIdentHash ()) && dest->GetNumExcludedPeers () < 30) // TODO: fix TunnelGateway first { + // tell floodfill about us + msgs.push_back (i2p::tunnel::TunnelMessageBlock + { + i2p::tunnel::eDeliveryTypeRouter, + r->GetIdentHash (), 0, + CreateDatabaseStoreMsg () + }); // request destination auto msg = dest->CreateRequestMessage (r, dest->GetLastReplyTunnel ()); msgs.push_back (i2p::tunnel::TunnelMessageBlock @@ -506,16 +514,15 @@ namespace data auto inbound = i2p::tunnel::tunnels.GetNextInboundTunnel (); if (outbound && inbound) { - auto floodfill = GetRandomRouter (outbound->GetEndpointRouter (), true); + CryptoPP::RandomNumberGenerator& rnd = i2p::context.GetRandomNumberGenerator (); + uint8_t randomHash[32]; + rnd.GenerateBlock (randomHash, 32); + RequestedDestination * dest = CreateRequestedDestination (IdentHash (randomHash), false, true); + dest->SetLastOutboundTunnel (outbound); + auto floodfill = GetClosestFloodfill (randomHash, dest->GetExcludedPeers ()); if (floodfill) - { + { LogPrint ("Exploring new routers ..."); - CryptoPP::RandomNumberGenerator& rnd = i2p::context.GetRandomNumberGenerator (); - uint8_t randomHash[32]; - rnd.GenerateBlock (randomHash, 32); - RequestedDestination * dest = CreateRequestedDestination (IdentHash (randomHash), false, true); - dest->SetLastOutboundTunnel (outbound); - std::vector msgs; msgs.push_back (i2p::tunnel::TunnelMessageBlock { @@ -529,8 +536,10 @@ namespace data floodfill->GetIdentHash (), 0, dest->CreateRequestMessage (floodfill, inbound) // explore }); - outbound->SendTunnelDataMsg (msgs); + outbound->SendTunnelDataMsg (msgs); } + else + DeleteRequestedDestination (dest); } } @@ -557,6 +566,15 @@ namespace data m_RequestedDestinations.erase (it); } } + + void NetDb::DeleteRequestedDestination (RequestedDestination * dest) + { + if (dest) + { + m_RequestedDestinations.erase (dest->GetDestination ()); + delete dest; + } + } const RouterInfo * NetDb::GetRandomNTCPRouter (bool floodfillOnly) const { diff --git a/NetDb.h b/NetDb.h index bcf1f23c..8f0e4125 100644 --- a/NetDb.h +++ b/NetDb.h @@ -87,6 +87,7 @@ namespace data RequestedDestination * CreateRequestedDestination (const IdentHash& dest, bool isLeaseSet, bool isExploratory = false); void DeleteRequestedDestination (const IdentHash& dest); + void DeleteRequestedDestination (RequestedDestination * dest); private: From 411ac5b898483abdb8d80d08524a29653a71edef Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 12 Feb 2014 16:36:13 -0500 Subject: [PATCH 5/5] try intro key if mac key failed --- SSU.cpp | 88 ++++++++++++++++++++++++++++++++++++++------------------- SSU.h | 3 +- 2 files changed, 61 insertions(+), 30 deletions(-) diff --git a/SSU.cpp b/SSU.cpp index 47d40abc..edac2704 100644 --- a/SSU.cpp +++ b/SSU.cpp @@ -97,10 +97,19 @@ namespace ssu LogPrint ("Unexpected SSU payload type ", (int)payloadType); } } - // TODO: try intro key else - { - LogPrint ("MAC verifcation failed"); + { + LogPrint ("MAC key failed. Trying intro key"); + auto introKey = GetIntroKey (); + if (introKey && Validate (buf, len, introKey)) + { + Decrypt (buf, len, introKey); + SSUHeader * header = (SSUHeader *)buf; + LogPrint ("Unexpected SSU payload type ", (int)(header->flag >> 4)); + // TODO: + } + else + LogPrint ("MAC verifcation failed"); m_State = eSessionStateUnknown; } } @@ -109,8 +118,7 @@ namespace ssu { LogPrint ("Process session request"); // use our intro key - if (ProcessIntroKeyEncryptedMessage (PAYLOAD_TYPE_SESSION_REQUEST, - i2p::context.GetRouterInfo (), buf, len)) + if (ProcessIntroKeyEncryptedMessage (PAYLOAD_TYPE_SESSION_REQUEST, buf, len)) { m_State = eSessionStateRequestReceived; LogPrint ("Session request received"); @@ -129,7 +137,7 @@ namespace ssu } // use remote intro key - if (ProcessIntroKeyEncryptedMessage (PAYLOAD_TYPE_SESSION_CREATED, *m_RemoteRouter, buf, len)) + if (ProcessIntroKeyEncryptedMessage (PAYLOAD_TYPE_SESSION_CREATED, buf, len)) { m_State = eSessionStateCreatedReceived; LogPrint ("Session created received"); @@ -167,10 +175,10 @@ namespace ssu void SSUSession::SendSessionRequest () { - auto address = m_RemoteRouter ? m_RemoteRouter->GetSSUAddress () : nullptr; - if (!address) + auto introKey = GetIntroKey (); + if (!introKey) { - LogPrint ("Missing remote SSU address"); + LogPrint ("SSU is not supported"); return; } @@ -183,7 +191,7 @@ namespace ssu uint8_t iv[16]; CryptoPP::RandomNumberGenerator& rnd = i2p::context.GetRandomNumberGenerator (); rnd.GenerateBlock (iv, 16); // random iv - FillHeaderAndEncrypt (PAYLOAD_TYPE_SESSION_REQUEST, buf, 304, address->key, iv, address->key); + FillHeaderAndEncrypt (PAYLOAD_TYPE_SESSION_REQUEST, buf, 304, introKey, iv, introKey); m_State = eSessionStateRequestSent; m_Server->Send (buf, 304, m_RemoteEndpoint); @@ -191,10 +199,10 @@ namespace ssu void SSUSession::SendSessionCreated (const uint8_t * x) { - auto address = m_RemoteRouter ? m_RemoteRouter->GetSSUAddress () : nullptr; - if (!address) + auto introKey = GetIntroKey (); + if (!introKey) { - LogPrint ("Missing remote SSU address"); + LogPrint ("SSU is not supported"); return; } uint8_t signedData[532]; // x,y, remote IP, remote port, our IP, our port, relayTag, signed on time @@ -230,20 +238,13 @@ namespace ssu m_Encryption.ProcessData (payload, payload, 48); // encrypt message with intro key - FillHeaderAndEncrypt (PAYLOAD_TYPE_SESSION_CREATED, buf, 368, address->key, iv, address->key); + FillHeaderAndEncrypt (PAYLOAD_TYPE_SESSION_CREATED, buf, 368, introKey, iv, introKey); m_State = eSessionStateRequestSent; m_Server->Send (buf, 368, m_RemoteEndpoint); } void SSUSession::SendSessionConfirmed (const uint8_t * y, const uint8_t * ourAddress, uint32_t relayTag) { - auto address = m_RemoteRouter ? m_RemoteRouter->GetSSUAddress () : nullptr; - if (!address) - { - LogPrint ("Missing remote SSU address"); - return; - } - uint8_t buf[480 + 18]; uint8_t * payload = buf + sizeof (SSUHeader); *payload = 1; // 1 fragment @@ -281,15 +282,15 @@ namespace ssu m_Server->Send (buf, 480, m_RemoteEndpoint); } - bool SSUSession::ProcessIntroKeyEncryptedMessage (uint8_t expectedPayloadType, const i2p::data::RouterInfo& r, uint8_t * buf, size_t len) + bool SSUSession::ProcessIntroKeyEncryptedMessage (uint8_t expectedPayloadType, uint8_t * buf, size_t len) { - auto address = r.GetSSUAddress (); - if (address) + auto introKey = GetIntroKey (); + if (introKey) { // use intro key for verification and decryption - if (Validate (buf, len, address->key)) + if (Validate (buf, len, introKey)) { - Decrypt (buf, len, address->key); + Decrypt (buf, len, introKey); SSUHeader * header = (SSUHeader *)buf; if ((header->flag >> 4) == expectedPayloadType) { @@ -303,7 +304,7 @@ namespace ssu LogPrint ("MAC verifcation failed"); } else - LogPrint ("SSU is not supported by ", r.GetIdentHashAbbreviation ()); + LogPrint ("SSU is not supported"); return false; } @@ -389,6 +390,22 @@ namespace ssu } } + const uint8_t * SSUSession::GetIntroKey () const + { + if (m_RemoteRouter) + { + // we are client + auto address = m_RemoteRouter->GetSSUAddress (); + return address ? address->key : nullptr; + } + else + { + // we are server + auto address = i2p::context.GetRouterInfo ().GetSSUAddress (); + return address ? address->key : nullptr; + } + } + void SSUSession::SendI2NPMessage (I2NPMessage * msg) { if (msg) @@ -520,8 +537,21 @@ namespace ssu uint8_t buf[48 + 18], iv[16]; CryptoPP::RandomNumberGenerator& rnd = i2p::context.GetRandomNumberGenerator (); rnd.GenerateBlock (iv, 16); // random iv - // encrypt message with session key - FillHeaderAndEncrypt (PAYLOAD_TYPE_SESSION_DESTROYED, buf, 48, m_SessionKey, iv, m_MacKey); + if (m_State == eSessionStateEstablished) + // encrypt message with session key + FillHeaderAndEncrypt (PAYLOAD_TYPE_SESSION_DESTROYED, buf, 48, m_SessionKey, iv, m_MacKey); + else + { + auto introKey = GetIntroKey (); + if (introKey) + // encrypt message with intro key + FillHeaderAndEncrypt (PAYLOAD_TYPE_SESSION_DESTROYED, buf, 48, introKey, iv, introKey); + else + { + LogPrint ("SSU: can't send SessionDestroyed message"); + return; + } + } m_Server->Send (buf, 48, m_RemoteEndpoint); } diff --git a/SSU.h b/SSU.h index 3996f02d..fccd6a8f 100644 --- a/SSU.h +++ b/SSU.h @@ -89,10 +89,11 @@ namespace ssu void SendSesionDestroyed (); void Send (i2p::I2NPMessage * msg); - bool ProcessIntroKeyEncryptedMessage (uint8_t expectedPayloadType, const i2p::data::RouterInfo& r, uint8_t * buf, size_t len); + bool ProcessIntroKeyEncryptedMessage (uint8_t expectedPayloadType, uint8_t * buf, size_t len); void FillHeaderAndEncrypt (uint8_t payloadType, uint8_t * buf, size_t len, const uint8_t * aesKey, const uint8_t * iv, const uint8_t * macKey); void Decrypt (uint8_t * buf, size_t len, const uint8_t * aesKey); bool Validate (uint8_t * buf, size_t len, const uint8_t * macKey); + const uint8_t * GetIntroKey () const; private: