From 9500d967896522a836d3f652322d450fa3151c3b Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 5 Sep 2014 16:35:02 -0400 Subject: [PATCH] session to introducer --- SSU.cpp | 95 ++++++++++++++++++++++++++++++++++++++++++++++++--------- SSU.h | 17 +++++++++-- 2 files changed, 94 insertions(+), 18 deletions(-) diff --git a/SSU.cpp b/SSU.cpp index 66d35c0f..0193e22f 100644 --- a/SSU.cpp +++ b/SSU.cpp @@ -18,8 +18,8 @@ namespace ssu SSUSession::SSUSession (SSUServer& server, boost::asio::ip::udp::endpoint& remoteEndpoint, const i2p::data::RouterInfo * router, bool peerTest ): m_Server (server), m_RemoteEndpoint (remoteEndpoint), m_RemoteRouter (router), - m_Timer (m_Server.GetService ()), m_PeerTest (peerTest), m_State (eSessionStateUnknown), - m_IsSessionKey (false), m_RelayTag (0), m_Data (*this), + m_Timer (m_Server.GetService ()), m_PeerTest (peerTest), m_ToIntroducer (false), + m_State (eSessionStateUnknown), m_IsSessionKey (false), m_RelayTag (0), m_Data (*this), m_NumSentBytes (0), m_NumReceivedBytes (0) { m_DHKeysPair = i2p::transports.GetNextDHKeysPair (); @@ -87,10 +87,10 @@ namespace ssu } else { - if (m_State == eSessionStateEstablished) - ScheduleTermination (); - if (!len) return; // ignore zero-length packets + if (m_State == eSessionStateEstablished && !m_ToIntroducer) + ScheduleTermination (); + if (m_IsSessionKey && Validate (buf, len, m_MacKey)) // try session key first DecryptSessionKey (buf, len); else @@ -416,10 +416,8 @@ namespace ssu payload += 2; // port *(uint32_t *)payload = htobe32 (nonce); - uint8_t iv[16]; - CryptoPP::RandomNumberGenerator& rnd = i2p::context.GetRandomNumberGenerator (); - rnd.GenerateBlock (iv, 16); // random iv - FillHeaderAndEncrypt (PAYLOAD_TYPE_RELAY_RESPONSE, buf, 64, m_SessionKey, iv, m_MacKey); + // encrypt with session key + FillHeaderAndEncrypt (PAYLOAD_TYPE_RELAY_RESPONSE, buf, 64); Send (buf, 64); } @@ -672,7 +670,22 @@ namespace ssu Failed (); } } - + + void SSUSession::ScheduleKeepAlive () + { + m_Timer.cancel (); + m_Timer.expires_from_now (boost::posix_time::seconds(SSU_KEEP_ALIVE_INETRVAL)); + m_Timer.async_wait (boost::bind (&SSUSession::HandleKeepAliveTimer, + this, boost::asio::placeholders::error)); + } + + void SSUSession::HandleKeepAliveTimer (const boost::system::error_code& ecode) + { + if (ecode != boost::asio::error::operation_aborted) + SendKeepAlive (); + } + + const uint8_t * SSUSession::GetIntroKey () const { if (m_RemoteRouter) @@ -765,7 +778,7 @@ namespace ssu else { LogPrint ("SSU peer test from Alice. We are Bob"); - auto session = m_Server.GetRandomEstablishedSession (); // charlie + auto session = m_Server.GetRandomEstablishedSession (this); // charlie if (session) session->SendPeerTest (nonce, senderEndpoint.address ().to_v4 ().to_ulong (), senderEndpoint.port (), introKey, false); @@ -821,6 +834,18 @@ namespace ssu SendPeerTest (nonce, 0, 0, address->key, false); // address and port always zero for Alice } + void SSUSession::SendKeepAlive () + { + uint8_t buf[48 + 18]; + uint8_t * payload = buf + sizeof (SSUHeader); + *payload = 0; // flags + payload++; + *payload = 0; // num fragments + // encrypt message with session key + FillHeaderAndEncrypt (PAYLOAD_TYPE_SESSION_DESTROYED, buf, 48); + Send (buf, 48); + LogPrint ("SSU keep-alive sent"); + } void SSUSession::SendSesionDestroyed () { @@ -855,6 +880,24 @@ namespace ssu m_Server.Send (buf, size, m_RemoteEndpoint); } + void SSUSession::StartToIntroducer () + { + if (m_State == eSessionStateEstablished) + { + m_ToIntroducer = true; + ScheduleKeepAlive (); + } + } + + void SSUSession::StopToIntroducer () + { + if (m_State == eSessionStateEstablished) + { + m_ToIntroducer = false; + ScheduleTermination (); + } + } + SSUServer::SSUServer (int port): m_Thread (nullptr), m_Work (m_Service), m_Endpoint (boost::asio::ip::udp::v4 (), port), m_Socket (m_Service, m_Endpoint) { @@ -1077,14 +1120,36 @@ namespace ssu return nullptr; } - SSUSession * SSUServer::GetRandomEstablishedSession () + SSUSession * SSUServer::GetRandomEstablishedSession (const SSUSession * excluded) { return GetRandomSession ( - [](SSUSession * session)->bool + [excluded](SSUSession * session)->bool + { + return session->GetState () == eSessionStateEstablished && + session != excluded; + } + ); + } + + std::set SSUServer::GetIntroducers (int maxNumIntroducers) + { + std::set ret; + for (int i = 0; i < maxNumIntroducers; i++) + { + auto session = GetRandomSession ( + [&ret](SSUSession * session)->bool { - return session->GetState () == eSessionStateEstablished; + return session->GetRelayTag () && !ret.count (session) && + session->GetState () == eSessionStateEstablished; } - ); + ); + if (session) + { + ret.insert (session); + break; + } + } + return ret; } } } diff --git a/SSU.h b/SSU.h index e51961ad..ca3e8029 100644 --- a/SSU.h +++ b/SSU.h @@ -33,6 +33,8 @@ namespace ssu const int SSU_CONNECT_TIMEOUT = 5; // 5 seconds const int SSU_TERMINATION_TIMEOUT = 330; // 5.5 minutes + const int SSU_KEEP_ALIVE_INETRVAL = 30; // 30 seconds + const int SSU_TO_INTRODUCER_SESSION_DURATION = 3600; // 1 hour // payload types (4 bits) const uint8_t PAYLOAD_TYPE_SESSION_REQUEST = 0; @@ -76,7 +78,10 @@ namespace ssu size_t GetNumSentBytes () const { return m_NumSentBytes; }; size_t GetNumReceivedBytes () const { return m_NumReceivedBytes; }; - + void StartToIntroducer (); + void StopToIntroducer (); + uint32_t GetRelayTag () const { return m_RelayTag; }; + private: void CreateAESandMacKey (const uint8_t * pubKey); @@ -103,6 +108,7 @@ namespace ssu void SendPeerTest (uint32_t nonce, uint32_t address, uint16_t port, const uint8_t * introKey, bool toAddress = true); void ProcessData (uint8_t * buf, size_t len); void SendSesionDestroyed (); + void SendKeepAlive (); void Send (uint8_t type, const uint8_t * payload, size_t len); // with session key void Send (const uint8_t * buf, size_t size); @@ -116,6 +122,9 @@ namespace ssu void ScheduleTermination (); void HandleTerminationTimer (const boost::system::error_code& ecode); + void ScheduleKeepAlive (); + void HandleKeepAliveTimer (const boost::system::error_code& ecode); + private: friend class SSUData; // TODO: change in later @@ -124,7 +133,7 @@ namespace ssu const i2p::data::RouterInfo * m_RemoteRouter; boost::asio::deadline_timer m_Timer; i2p::data::DHKeysPair * m_DHKeysPair; // X - for client and Y - for server - bool m_PeerTest; + bool m_PeerTest, m_ToIntroducer; SessionState m_State; bool m_IsSessionKey; uint32_t m_RelayTag; @@ -148,7 +157,7 @@ namespace ssu SSUSession * GetSession (const i2p::data::RouterInfo * router, bool peerTest = false); SSUSession * FindSession (const i2p::data::RouterInfo * router); SSUSession * FindSession (const boost::asio::ip::udp::endpoint& e); - SSUSession * GetRandomEstablishedSession (); + SSUSession * GetRandomEstablishedSession (const SSUSession * excluded); void DeleteSession (SSUSession * session); void DeleteAllSessions (); @@ -163,6 +172,8 @@ namespace ssu void Run (); void Receive (); void HandleReceivedFrom (const boost::system::error_code& ecode, std::size_t bytes_transferred); + + std::set GetIntroducers (int maxNumIntroducers); template SSUSession * GetRandomSession (Filter filter);