From d04f9e723c3c2d94b529376a354cbf37fd3867da Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 6 Feb 2014 10:16:50 -0500 Subject: [PATCH 01/43] handle recieved I2NP message --- SSU.cpp | 27 ++++++++++++++++++++++++++- SSU.h | 1 + 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/SSU.cpp b/SSU.cpp index 314a62da..4fbd2696 100644 --- a/SSU.cpp +++ b/SSU.cpp @@ -382,7 +382,32 @@ namespace ssu uint16_t fragmentSize = fragmentInfo & 0x1FFF; // bits 0 - 13 bool isLast = fragmentInfo & 0x010000; // bit 16 uint8_t fragmentNum = fragmentInfo >> 17; // bits 23 - 17 - LogPrint ("SSU data fragment ", (int)fragmentNum, " of message ", msgID, " size=", (int)fragmentSize, isLast ? " last" : " non-last"); + LogPrint ("SSU data fragment ", (int)fragmentNum, " of message ", msgID, " size=", (int)fragmentSize, isLast ? " last" : " non-last"); + I2NPMessage * msg = nullptr; + if (fragmentNum > 0) // follow-up fragment + { + auto it = m_IncomleteMessages.find (msgID); + if (it != m_IncomleteMessages.end ()) + msg = it->second; + else + // TODO: + LogPrint ("Unexpected follow-on fragment ", fragmentNum, " of message ", msgID); + } + else // first fragment + msg = NewI2NPMessage (); + if (msg) + { + memcpy (msg->buf + msg->len, buf, fragmentSize); + msg->len += fragmentSize; + if (!fragmentNum && !isLast) + m_IncomleteMessages[msgID] = msg; + if (isLast) + { + if (fragmentNum > 0) + m_IncomleteMessages.erase (msgID); + i2p::HandleI2NPMessage (msg, false); + } + } buf += fragmentSize; } } diff --git a/SSU.h b/SSU.h index aee160ae..a27743a0 100644 --- a/SSU.h +++ b/SSU.h @@ -88,6 +88,7 @@ namespace ssu CryptoPP::CBC_Mode::Encryption m_Encryption; CryptoPP::CBC_Mode::Decryption m_Decryption; uint8_t m_SessionKey[32], m_MacKey[32]; + std::map m_IncomleteMessages; }; class SSUServer From 656392fe1e789910c68f988162dcd53a6f1be9ac Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 7 Feb 2014 11:26:00 -0500 Subject: [PATCH 02/43] handle SSU I2NP header --- I2NPProtocol.h | 20 ++++++++++++++++++++ SSU.cpp | 14 +++++++++++--- 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/I2NPProtocol.h b/I2NPProtocol.h index 7f47601e..3905da5b 100644 --- a/I2NPProtocol.h +++ b/I2NPProtocol.h @@ -4,6 +4,7 @@ #include #include #include +#include "I2PEndian.h" #include "RouterInfo.h" namespace i2p @@ -19,6 +20,12 @@ namespace i2p uint8_t chks; }; + struct I2NPHeaderShort + { + uint8_t typeID; + uint32_t shortExpiration; + }; + struct I2NPDatabaseStoreMsg { uint8_t key[32]; @@ -101,6 +108,19 @@ namespace i2p len = offset + other.GetLength (); return *this; } + + // for SSU only + uint8_t * GetSSUHeader () { return buf + offset + sizeof(I2NPHeader) - sizeof(I2NPHeaderShort); }; + void FromSSU (uint32_t msgID) // we have received SSU message and convert it to regular + { + I2NPHeaderShort ssu = *(I2NPHeaderShort *)GetSSUHeader (); + I2NPHeader * header = GetHeader (); + header->typeID = ssu.typeID; + header->msgID = htobe32 (msgID); + header->expiration = htobe64 (be32toh (ssu.shortExpiration)*1000LL); + header->size = htobe16 (len - offset - sizeof (I2NPHeader)); + header->chks = 0; + } }; I2NPMessage * NewI2NPMessage (); void DeleteI2NPMessage (I2NPMessage * msg); diff --git a/SSU.cpp b/SSU.cpp index 4fbd2696..ea7368bc 100644 --- a/SSU.cpp +++ b/SSU.cpp @@ -388,23 +388,31 @@ namespace ssu { auto it = m_IncomleteMessages.find (msgID); if (it != m_IncomleteMessages.end ()) + { msg = it->second; + memcpy (msg->buf + msg->len, buf, fragmentSize); + msg->len += fragmentSize; + } else // TODO: LogPrint ("Unexpected follow-on fragment ", fragmentNum, " of message ", msgID); } else // first fragment + { msg = NewI2NPMessage (); + memcpy (msg->GetSSUHeader (), buf, fragmentSize); + msg->len += fragmentSize - sizeof (I2NPHeaderShort); + } + if (msg) - { - memcpy (msg->buf + msg->len, buf, fragmentSize); - msg->len += fragmentSize; + { if (!fragmentNum && !isLast) m_IncomleteMessages[msgID] = msg; if (isLast) { if (fragmentNum > 0) m_IncomleteMessages.erase (msgID); + msg->FromSSU (msgID); i2p::HandleI2NPMessage (msg, false); } } From 1c1103dcce1863434673eb8e29ea9b55f3169450 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 7 Feb 2014 15:47:10 -0500 Subject: [PATCH 03/43] send ack --- SSU.cpp | 22 +++++++++++++++++++++- SSU.h | 9 +++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/SSU.cpp b/SSU.cpp index ea7368bc..91ae1bec 100644 --- a/SSU.cpp +++ b/SSU.cpp @@ -382,7 +382,7 @@ namespace ssu uint16_t fragmentSize = fragmentInfo & 0x1FFF; // bits 0 - 13 bool isLast = fragmentInfo & 0x010000; // bit 16 uint8_t fragmentNum = fragmentInfo >> 17; // bits 23 - 17 - LogPrint ("SSU data fragment ", (int)fragmentNum, " of message ", msgID, " size=", (int)fragmentSize, isLast ? " last" : " non-last"); + LogPrint ("SSU data fragment ", (int)fragmentNum, " of message ", msgID, " size=", (int)fragmentSize, isLast ? " last" : " non-last"); I2NPMessage * msg = nullptr; if (fragmentNum > 0) // follow-up fragment { @@ -414,15 +414,35 @@ namespace ssu m_IncomleteMessages.erase (msgID); msg->FromSSU (msgID); i2p::HandleI2NPMessage (msg, false); + SendMsgAck (msgID); } } buf += fragmentSize; } } + void SSUSession::SendMsgAck (uint32_t msgID) + { + uint8_t buf[48]; // actual length is 44 = 37 + 7 but pad it to multiple of 16 + uint8_t iv[16]; + *buf = DATA_FLAG_EXPLICIT_ACKS_INCLUDED; // flag + buf[1] = 1; // number of ACKs + *(uint32_t *)(buf + 2) = htobe32 (msgID); // msgID + buf[6] = 0; // number of fragments + + CryptoPP::RandomNumberGenerator& rnd = i2p::context.GetRandomNumberGenerator (); + rnd.GenerateBlock (iv, 16); // random iv + // encrypt message with session key + FillHeaderAndEncrypt (PAYLOAD_TYPE_DATA, buf, 48, m_SessionKey, iv, m_MacKey); + m_State = eSessionStateConfirmedSent; + m_Server->Send (buf, 48, m_RemoteEndpoint); + } + SSUServer::SSUServer (boost::asio::io_service& service, int port): m_Endpoint (boost::asio::ip::udp::v4 (), port), m_Socket (service, m_Endpoint) { + m_Socket.set_option (boost::asio::socket_base::receive_buffer_size (65535)); + m_Socket.set_option (boost::asio::socket_base::send_buffer_size (65535)); } SSUServer::~SSUServer () diff --git a/SSU.h b/SSU.h index a27743a0..0ddaa5c5 100644 --- a/SSU.h +++ b/SSU.h @@ -37,6 +37,14 @@ namespace ssu const uint8_t PAYLOAD_TYPE_TEST = 7; const uint8_t PAYLOAD_TYPE_SESSION_DESTROY = 8; + // data flags + const uint8_t DATA_FLAG_EXTENDED_DATA_INCLUDED = 0x02; + const uint8_t DATA_FLAG_WANT_REPLY = 0x04; + const uint8_t DATA_FLAG_REQUEST_PREVIOUS_ACKS = 0x08; + const uint8_t DATA_FLAG_EXPLICIT_CONGESTION_NOTIFICATION = 0x10; + const uint8_t DATA_FLAG_ACK_BITFIELDS_INCLUDED = 0x40; + const uint8_t DATA_FLAG_EXPLICIT_ACKS_INCLUDED = 0x80; + enum SessionState { eSessionStateUnknown, @@ -73,6 +81,7 @@ namespace ssu void ProcessSessionConfirmed (uint8_t * buf, size_t len); void SendSessionConfirmed (const uint8_t * y, const uint8_t * ourAddress, uint32_t relayTag); void ProcessData (uint8_t * buf, size_t len); + void SendMsgAck (uint32_t msgID); bool ProcessIntroKeyEncryptedMessage (uint8_t expectedPayloadType, i2p::data::RouterInfo& r, uint8_t * buf, size_t len); void FillHeaderAndEncrypt (uint8_t payloadType, uint8_t * buf, size_t len, uint8_t * aesKey, uint8_t * iv, uint8_t * macKey); From 9897a49e1ad42c7a44205cc0c01813bd91c93f8c Mon Sep 17 00:00:00 2001 From: Meeh Date: Sat, 8 Feb 2014 03:15:08 +0100 Subject: [PATCH 04/43] Rewrite the thread stop in Queue --- Queue.h | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Queue.h b/Queue.h index 449ff806..316084a9 100644 --- a/Queue.h +++ b/Queue.h @@ -98,17 +98,18 @@ namespace util { public: - MsgQueue (): m_Thread (std::bind (&MsgQueue::Run, this)) {}; + MsgQueue (): m_Thread (std::bind (&MsgQueue::Run, this)) , running(1) {}; void Stop() { - m_Thread.detach(); + running = 0; + m_Thread.join(); } private: void Run () { Msg * msg = nullptr; - while ((msg = Queue::GetNext ()) != nullptr) + while ((msg = Queue::GetNext ()) != nullptr && running) { msg->Process (); delete msg; @@ -117,6 +118,7 @@ namespace util private: std::thread m_Thread; + int running; }; } } From 9b1e7956cb8b897628960e721571ce7c69bdfe1d Mon Sep 17 00:00:00 2001 From: Meeh Date: Sat, 8 Feb 2014 03:16:52 +0100 Subject: [PATCH 05/43] defining vars should cost less than function calls --- i2p.cpp | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/i2p.cpp b/i2p.cpp index 355c2003..97914b5e 100644 --- a/i2p.cpp +++ b/i2p.cpp @@ -27,6 +27,7 @@ // Global int running = 1; +int isDaemon; #ifndef _WIN32 void handle_signal(int sig) @@ -59,6 +60,7 @@ void handle_signal(int sig) int main( int argc, char* argv[] ) { i2p::util::config::OptionParser(argc,argv); + isDaemon = i2p::util::config::GetArg("-daemon", 0); #ifdef _WIN32 setlocale(LC_CTYPE, ""); SetConsoleCP(1251); @@ -71,8 +73,22 @@ int main( int argc, char* argv[] ) LogPrint("data directory: ", i2p::util::filesystem::GetDataDir().string()); i2p::util::filesystem::ReadConfigFile(i2p::util::config::mapArgs, i2p::util::config::mapMultiArgs); + int isLogging = i2p::util::config::GetArg("-log", 0); + if (isLogging == 1) + { + std::string logfile = i2p::util::filesystem::GetDataDir().string(); +#ifndef _WIN32 + logfile.append("/debug.log"); +#else + logfile.append("\\debug.log"); +#endif + freopen(logfile.c_str(),"a",stdout); + LogPrint("Logging to file enabled."); + } + + #ifndef _WIN32 - if (i2p::util::config::GetArg("-daemon", 0) == 1) + if (isDaemon == 1) { pid_t pid; pid = fork(); @@ -125,18 +141,6 @@ int main( int argc, char* argv[] ) sigaction(SIGINT,&sa,0); #endif - if (i2p::util::config::GetArg("-log", 0) == 1) - { - std::string logfile = i2p::util::filesystem::GetDataDir().string(); -#ifndef _WIN32 - logfile.append("/debug.log"); -#else - logfile.append("\\debug.log"); -#endif - LogPrint("Logging to file enabled."); - freopen(logfile.c_str(),"a",stdout); - } - //TODO: This is an ugly workaround. fix it. //TODO: Autodetect public IP. i2p::context.OverrideNTCPAddress(i2p::util::config::GetCharArg("-host", "127.0.0.1"), @@ -161,7 +165,7 @@ int main( int argc, char* argv[] ) i2p::data::netdb.Stop (); httpServer.Stop (); - if (i2p::util::config::GetArg("-log", 0) == 1) + if (isLogging == 1) { fclose (stdout); } From 202e3eeb2ad7e66a35fa416abe131a6f8e4e85bf Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 7 Feb 2014 21:42:35 -0500 Subject: [PATCH 06/43] process ACKs --- SSU.cpp | 41 +++++++++++++++++++++++++++++++++-------- SSU.h | 2 +- 2 files changed, 34 insertions(+), 9 deletions(-) diff --git a/SSU.cpp b/SSU.cpp index 91ae1bec..2c85f137 100644 --- a/SSU.cpp +++ b/SSU.cpp @@ -47,7 +47,7 @@ namespace ssu { switch (m_State) { - case eSessionStateEstablised: + case eSessionStateEstablished: // most common case ProcessMessage (buf, len); break; @@ -131,7 +131,7 @@ namespace ssu LogPrint ("Our external address is ", ourIP.to_string (), ":", ourPort); uint32_t relayTag = be32toh (*(uint32_t *)(buf + sizeof (SSUHeader) + 263)); SendSessionConfirmed (buf + sizeof (SSUHeader), ourAddress, relayTag); - m_State = eSessionStateEstablised; + m_State = eSessionStateEstablished; } } @@ -147,7 +147,7 @@ namespace ssu m_State = eSessionStateConfirmedReceived; LogPrint ("Session confirmed received"); // TODO: - m_State = eSessionStateEstablised; + m_State = eSessionStateEstablished; } else LogPrint ("Unexpected payload type ", (int)(header->flag >> 4)); @@ -368,6 +368,28 @@ namespace ssu uint8_t flag = *buf; buf++; LogPrint ("Process SSU data flags=", (int)flag); + if (flag & DATA_FLAG_EXPLICIT_ACKS_INCLUDED) + { + // explicit ACKs + uint8_t numAcks =*buf; + buf++; + // TODO: process ACKs + buf += numAcks*4; + } + if (flag & DATA_FLAG_ACK_BITFIELDS_INCLUDED) + { + // explicit ACK bitfields + uint8_t numBitfields =*buf; + buf++; + for (int i = 0; i < numBitfields; i++) + { + buf += 4; // msgID + // TODO: process ACH bitfields + while (*buf & 0x80) // not last + buf++; + buf++; // last byte + } + } uint8_t numFragments = *buf; // number of fragments buf++; for (int i = 0; i < numFragments; i++) @@ -425,16 +447,19 @@ namespace ssu { uint8_t buf[48]; // actual length is 44 = 37 + 7 but pad it to multiple of 16 uint8_t iv[16]; - *buf = DATA_FLAG_EXPLICIT_ACKS_INCLUDED; // flag - buf[1] = 1; // number of ACKs - *(uint32_t *)(buf + 2) = htobe32 (msgID); // msgID - buf[6] = 0; // number of fragments + uint8_t * payload = buf + sizeof (SSUHeader); + *payload = DATA_FLAG_EXPLICIT_ACKS_INCLUDED; // flag + payload++; + *payload = 1; // number of ACKs + payload++; + *(uint32_t *)(payload) = htobe32 (msgID); // msgID + payload += 4; + *payload = 0; // number of fragments CryptoPP::RandomNumberGenerator& rnd = i2p::context.GetRandomNumberGenerator (); rnd.GenerateBlock (iv, 16); // random iv // encrypt message with session key FillHeaderAndEncrypt (PAYLOAD_TYPE_DATA, buf, 48, m_SessionKey, iv, m_MacKey); - m_State = eSessionStateConfirmedSent; m_Server->Send (buf, 48, m_RemoteEndpoint); } diff --git a/SSU.h b/SSU.h index 0ddaa5c5..3a6c029c 100644 --- a/SSU.h +++ b/SSU.h @@ -54,7 +54,7 @@ namespace ssu eSessionStateCreatedReceived, eSessionStateConfirmedSent, eSessionStateConfirmedReceived, - eSessionStateEstablised + eSessionStateEstablished }; class SSUServer; From acf59f0b7e88451330980a75040a1c51c3dc89be Mon Sep 17 00:00:00 2001 From: Meeh Date: Sat, 8 Feb 2014 22:06:01 +0100 Subject: [PATCH 07/43] Adding volatile keyword --- Queue.h | 2 +- i2p.cpp | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Queue.h b/Queue.h index 316084a9..85114bc1 100644 --- a/Queue.h +++ b/Queue.h @@ -118,7 +118,7 @@ namespace util private: std::thread m_Thread; - int running; + volatile int running; }; } } diff --git a/i2p.cpp b/i2p.cpp index 97914b5e..967435cb 100644 --- a/i2p.cpp +++ b/i2p.cpp @@ -26,8 +26,8 @@ // Global -int running = 1; -int isDaemon; +volatile int running = 1; +volatile int isDaemon; #ifndef _WIN32 void handle_signal(int sig) @@ -60,7 +60,7 @@ void handle_signal(int sig) int main( int argc, char* argv[] ) { i2p::util::config::OptionParser(argc,argv); - isDaemon = i2p::util::config::GetArg("-daemon", 0); + volatile int isDaemon = i2p::util::config::GetArg("-daemon", 0); #ifdef _WIN32 setlocale(LC_CTYPE, ""); SetConsoleCP(1251); @@ -73,7 +73,7 @@ int main( int argc, char* argv[] ) LogPrint("data directory: ", i2p::util::filesystem::GetDataDir().string()); i2p::util::filesystem::ReadConfigFile(i2p::util::config::mapArgs, i2p::util::config::mapMultiArgs); - int isLogging = i2p::util::config::GetArg("-log", 0); + volatile int isLogging = i2p::util::config::GetArg("-log", 0); if (isLogging == 1) { std::string logfile = i2p::util::filesystem::GetDataDir().string(); From ec5eafafebef3ddaf6e521a93dcf1ffe6fb28569 Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 8 Feb 2014 21:06:40 -0500 Subject: [PATCH 08/43] external IP detection --- RouterContext.cpp | 7 +++++++ RouterContext.h | 1 + RouterInfo.cpp | 8 ++++++++ RouterInfo.h | 3 ++- SSU.cpp | 40 ++++++++++++++++++++++++++++++++++++++-- SSU.h | 11 ++++++++--- Transports.cpp | 41 ++++++++++++++++++++++++++++++++++++++--- Transports.h | 4 ++++ 8 files changed, 106 insertions(+), 9 deletions(-) diff --git a/RouterContext.cpp b/RouterContext.cpp index 68f6508a..768b92a3 100644 --- a/RouterContext.cpp +++ b/RouterContext.cpp @@ -52,6 +52,13 @@ namespace i2p m_RouterInfo.CreateBuffer (); } + + void RouterContext::UpdateAddress (const char * host) + { + for (auto& address : m_RouterInfo.GetAddresses ()) + address.host = boost::asio::ip::address::from_string (host); + m_RouterInfo.CreateBuffer (); + } void RouterContext::Sign (uint8_t * buf, int len, uint8_t * signature) { diff --git a/RouterContext.h b/RouterContext.h index f43094c1..0cbd0bc7 100644 --- a/RouterContext.h +++ b/RouterContext.h @@ -28,6 +28,7 @@ namespace i2p void Sign (uint8_t * buf, int len, uint8_t * signature); void OverrideNTCPAddress (const char * host, int port); // temporary + void UpdateAddress (const char * host); // called from SSU private: diff --git a/RouterInfo.cpp b/RouterInfo.cpp index 3b0054a0..f4668921 100644 --- a/RouterInfo.cpp +++ b/RouterInfo.cpp @@ -294,6 +294,14 @@ namespace data else return m_SupportedTransports & (eNTCPV4 | eNTCPV6); } + + bool RouterInfo::IsSSU (bool v4only) const + { + if (v4only) + return m_SupportedTransports & eSSUV4; + else + return m_SupportedTransports & (eSSUV4 | eSSUV6); + } RouterInfo::Address * RouterInfo::GetNTCPAddress (bool v4only) { diff --git a/RouterInfo.h b/RouterInfo.h index d7fc6dd9..3b28fee7 100644 --- a/RouterInfo.h +++ b/RouterInfo.h @@ -53,7 +53,7 @@ namespace data const char * GetIdentHashBase64 () const { return m_IdentHashBase64; }; const char * GetIdentHashAbbreviation () const { return m_IdentHashAbbreviation; }; uint64_t GetTimestamp () const { return m_Timestamp; }; - const std::vector
& GetAddresses () const { return m_Addresses; }; + std::vector
& GetAddresses () { return m_Addresses; }; Address * GetNTCPAddress (bool v4only = true); Address * GetSSUAddress (bool v4only = true); const RoutingKey& GetRoutingKey () const { return m_RoutingKey; }; @@ -63,6 +63,7 @@ namespace data const char * GetProperty (const char * key) const; bool IsFloodfill () const; bool IsNTCP (bool v4only = true) const; + bool IsSSU (bool v4only = true) const; bool IsCompatible (const RouterInfo& other) const { return m_SupportedTransports & other.m_SupportedTransports; }; void SetUnreachable (bool unreachable) { m_IsUnreachable = unreachable; }; diff --git a/SSU.cpp b/SSU.cpp index 2c85f137..57ebdce9 100644 --- a/SSU.cpp +++ b/SSU.cpp @@ -85,7 +85,7 @@ namespace ssu case PAYLOAD_TYPE_TEST: LogPrint ("SSU test received"); break; - case PAYLOAD_TYPE_SESSION_DESTROY: + case PAYLOAD_TYPE_SESSION_DESTROYED: LogPrint ("SSU session destroy received"); break; default: @@ -129,6 +129,7 @@ namespace ssu boost::asio::ip::address_v4 ourIP (be32toh (*(uint32_t* )(ourAddress))); uint16_t ourPort = be16toh (*(uint16_t *)(ourAddress + 4)); LogPrint ("Our external address is ", ourIP.to_string (), ":", ourPort); + 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; @@ -357,6 +358,11 @@ namespace ssu SendSessionRequest (); } + void SSUSession::Close () + { + SendSesionDestroyed (); + } + void SSUSession::SendI2NPMessage (I2NPMessage * msg) { // TODO: @@ -445,7 +451,7 @@ namespace ssu void SSUSession::SendMsgAck (uint32_t msgID) { - uint8_t buf[48]; // actual length is 44 = 37 + 7 but pad it to multiple of 16 + uint8_t buf[48 + 18]; // actual length is 44 = 37 + 7 but pad it to multiple of 16 uint8_t iv[16]; uint8_t * payload = buf + sizeof (SSUHeader); *payload = DATA_FLAG_EXPLICIT_ACKS_INCLUDED; // flag @@ -463,6 +469,16 @@ namespace ssu m_Server->Send (buf, 48, m_RemoteEndpoint); } + void SSUSession::SendSesionDestroyed () + { + 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); + m_Server->Send (buf, 48, m_RemoteEndpoint); + } + SSUServer::SSUServer (boost::asio::io_service& service, int port): m_Endpoint (boost::asio::ip::udp::v4 (), port), m_Socket (service, m_Endpoint) { @@ -546,6 +562,26 @@ namespace ssu } return session; } + + void SSUServer::DeleteSession (SSUSession * session) + { + if (session) + { + session->Close (); + m_Sessions.erase (session->GetRemoteEndpoint ()); + delete session; + } + } + + void SSUServer::DeleteAllSessions () + { + for (auto it: m_Sessions) + { + it.second->Close (); + delete it.second; + } + m_Sessions.clear (); + } } } diff --git a/SSU.h b/SSU.h index 3a6c029c..15467262 100644 --- a/SSU.h +++ b/SSU.h @@ -35,7 +35,7 @@ namespace ssu const uint8_t PAYLOAD_TYPE_RELAY_INTRO = 5; const uint8_t PAYLOAD_TYPE_DATA = 6; const uint8_t PAYLOAD_TYPE_TEST = 7; - const uint8_t PAYLOAD_TYPE_SESSION_DESTROY = 8; + const uint8_t PAYLOAD_TYPE_SESSION_DESTROYED = 8; // data flags const uint8_t DATA_FLAG_EXTENDED_DATA_INCLUDED = 0x02; @@ -67,6 +67,8 @@ namespace ssu void ProcessNextMessage (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint); void Connect (); + void Close (); + boost::asio::ip::udp::endpoint& GetRemoteEndpoint () { return m_RemoteEndpoint; }; void SendI2NPMessage (I2NPMessage * msg); private: @@ -82,7 +84,8 @@ namespace ssu void SendSessionConfirmed (const uint8_t * y, const uint8_t * ourAddress, uint32_t relayTag); void ProcessData (uint8_t * buf, size_t len); void SendMsgAck (uint32_t msgID); - + void SendSesionDestroyed (); + bool ProcessIntroKeyEncryptedMessage (uint8_t expectedPayloadType, i2p::data::RouterInfo& r, uint8_t * buf, size_t len); void FillHeaderAndEncrypt (uint8_t payloadType, uint8_t * buf, size_t len, uint8_t * aesKey, uint8_t * iv, uint8_t * macKey); void Decrypt (uint8_t * buf, size_t len, uint8_t * aesKey); @@ -109,7 +112,9 @@ namespace ssu void Start (); void Stop (); SSUSession * GetSession (i2p::data::RouterInfo * router); - + void DeleteSession (SSUSession * session); + void DeleteAllSessions (); + const boost::asio::ip::udp::endpoint& GetEndpoint () const { return m_Endpoint; }; void Send (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& to); diff --git a/Transports.cpp b/Transports.cpp index c3b96d78..8ea6c05f 100644 --- a/Transports.cpp +++ b/Transports.cpp @@ -25,6 +25,7 @@ namespace i2p { m_IsRunning = true; m_Thread = new std::thread (std::bind (&Transports::Run, this)); + m_Timer = new boost::asio::deadline_timer (m_Service); // create acceptors auto addresses = context.GetRouterInfo ().GetAddresses (); for (auto& address : addresses) @@ -38,9 +39,11 @@ namespace i2p auto conn = new i2p::ntcp::NTCPServerConnection (m_Service); m_NTCPAcceptor->async_accept(conn->GetSocket (), boost::bind (&Transports::HandleAccept, this, conn, boost::asio::placeholders::error)); - } + // temporary always run SSU server + // TODO: uncomment following lines later + /*} else if (address.transportStyle == RouterInfo::eTransportSSU) - { + {*/ if (!m_SSUServer) { m_SSUServer = new i2p::ssu::SSUServer (m_Service, address.port); @@ -51,6 +54,9 @@ namespace i2p LogPrint ("SSU server already exists"); } } + + // TODO: do it for SSU only + DetectExternalIP (); } void Transports::Stop () @@ -59,7 +65,10 @@ namespace i2p delete session.second; m_NTCPSessions.clear (); delete m_NTCPAcceptor; - + + m_Timer->cancel (); + delete m_Timer; + if (m_SSUServer) { m_SSUServer->Stop (); @@ -173,4 +182,30 @@ namespace i2p else LogPrint ("Session not found"); } + + void Transports::DetectExternalIP () + { + for (int i = 0; i < 5; i ++) + { + auto router = i2p::data::netdb.GetRandomRouter (); + if (router && router->IsSSU () && m_SSUServer) + m_SSUServer->GetSession (const_cast(router)); //TODO + } + if (m_Timer) + { + m_Timer->expires_from_now (boost::posix_time::seconds(5)); // 5 seconds + m_Timer->async_wait (boost::bind (&Transports::HandleTimer, this, boost::asio::placeholders::error)); + } + } + + void Transports::HandleTimer (const boost::system::error_code& ecode) + { + if (ecode != boost::asio::error::operation_aborted) + { + // end of external IP detection + if (m_SSUServer) + m_SSUServer->DeleteAllSessions (); + } + } + } diff --git a/Transports.h b/Transports.h index 03f6cf35..12bd8f21 100644 --- a/Transports.h +++ b/Transports.h @@ -38,6 +38,9 @@ namespace i2p void Run (); void HandleAccept (i2p::ntcp::NTCPServerConnection * conn, const boost::system::error_code& error); void PostMessage (const i2p::data::IdentHash& ident, i2p::I2NPMessage * msg); + + void DetectExternalIP (); + void HandleTimer (const boost::system::error_code& ecode); private: @@ -49,6 +52,7 @@ namespace i2p std::map m_NTCPSessions; i2p::ssu::SSUServer * m_SSUServer; + boost::asio::deadline_timer * m_Timer; public: From c2665755281215018f6542bf3570445b29376199 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 9 Feb 2014 08:52:56 -0500 Subject: [PATCH 09/43] eliminate unnecessary const_cast --- RouterContext.cpp | 2 +- RouterInfo.cpp | 6 +++--- RouterInfo.h | 6 +++--- SSU.cpp | 15 ++++++++------- SSU.h | 16 ++++++++-------- Transports.cpp | 5 ++--- hmac.h | 2 +- 7 files changed, 26 insertions(+), 26 deletions(-) diff --git a/RouterContext.cpp b/RouterContext.cpp index 768b92a3..1d3d2c02 100644 --- a/RouterContext.cpp +++ b/RouterContext.cpp @@ -43,7 +43,7 @@ namespace i2p void RouterContext::OverrideNTCPAddress (const char * host, int port) { m_RouterInfo.CreateBuffer (); - auto address = m_RouterInfo.GetNTCPAddress (); + auto address = const_cast(m_RouterInfo.GetNTCPAddress ()); if (address) { address->host = boost::asio::ip::address::from_string (host); diff --git a/RouterInfo.cpp b/RouterInfo.cpp index f4668921..e1ae0a2d 100644 --- a/RouterInfo.cpp +++ b/RouterInfo.cpp @@ -303,17 +303,17 @@ namespace data return m_SupportedTransports & (eSSUV4 | eSSUV6); } - RouterInfo::Address * RouterInfo::GetNTCPAddress (bool v4only) + const RouterInfo::Address * RouterInfo::GetNTCPAddress (bool v4only) const { return GetAddress (eTransportNTCP, v4only); } - RouterInfo::Address * RouterInfo::GetSSUAddress (bool v4only) + const RouterInfo::Address * RouterInfo::GetSSUAddress (bool v4only) const { return GetAddress (eTransportSSU, v4only); } - RouterInfo::Address * RouterInfo::GetAddress (TransportStyle s, bool v4only) + const RouterInfo::Address * RouterInfo::GetAddress (TransportStyle s, bool v4only) const { for (auto& address : m_Addresses) { diff --git a/RouterInfo.h b/RouterInfo.h index 3b28fee7..3c08d8d1 100644 --- a/RouterInfo.h +++ b/RouterInfo.h @@ -54,8 +54,8 @@ namespace data const char * GetIdentHashAbbreviation () const { return m_IdentHashAbbreviation; }; uint64_t GetTimestamp () const { return m_Timestamp; }; std::vector
& GetAddresses () { return m_Addresses; }; - Address * GetNTCPAddress (bool v4only = true); - Address * GetSSUAddress (bool v4only = true); + const Address * GetNTCPAddress (bool v4only = true) const; + const Address * GetSSUAddress (bool v4only = true) const; const RoutingKey& GetRoutingKey () const { return m_RoutingKey; }; void AddNTCPAddress (const char * host, int port); @@ -91,7 +91,7 @@ namespace data size_t ReadString (char * str, std::istream& s); void WriteString (const std::string& str, std::ostream& s); void UpdateIdentHashBase64 (); - Address * GetAddress (TransportStyle s, bool v4only); + const Address * GetAddress (TransportStyle s, bool v4only) const; private: diff --git a/SSU.cpp b/SSU.cpp index 57ebdce9..c0715d9e 100644 --- a/SSU.cpp +++ b/SSU.cpp @@ -14,8 +14,8 @@ namespace i2p namespace ssu { - SSUSession::SSUSession (SSUServer * server, const boost::asio::ip::udp::endpoint& remoteEndpoint, - i2p::data::RouterInfo * router): m_Server (server), m_RemoteEndpoint (remoteEndpoint), + SSUSession::SSUSession (SSUServer * server, boost::asio::ip::udp::endpoint& remoteEndpoint, + const i2p::data::RouterInfo * router): m_Server (server), m_RemoteEndpoint (remoteEndpoint), m_RemoteRouter (router), m_State (eSessionStateUnknown) { } @@ -273,7 +273,7 @@ namespace ssu m_Server->Send (buf, 480, m_RemoteEndpoint); } - bool SSUSession::ProcessIntroKeyEncryptedMessage (uint8_t expectedPayloadType, i2p::data::RouterInfo& r, uint8_t * buf, size_t len) + bool SSUSession::ProcessIntroKeyEncryptedMessage (uint8_t expectedPayloadType, const i2p::data::RouterInfo& r, uint8_t * buf, size_t len) { auto address = r.GetSSUAddress (); if (address) @@ -299,7 +299,8 @@ namespace ssu return false; } - void SSUSession::FillHeaderAndEncrypt (uint8_t payloadType, uint8_t * buf, size_t len, uint8_t * aesKey, uint8_t * iv, uint8_t * macKey) + void SSUSession::FillHeaderAndEncrypt (uint8_t payloadType, uint8_t * buf, size_t len, + const uint8_t * aesKey, const uint8_t * iv, const uint8_t * macKey) { if (len < sizeof (SSUHeader)) { @@ -320,7 +321,7 @@ namespace ssu i2p::crypto::HMACMD5Digest (encrypted, encryptedLen + 18, macKey, header->mac); } - void SSUSession::Decrypt (uint8_t * buf, size_t len, uint8_t * aesKey) + void SSUSession::Decrypt (uint8_t * buf, size_t len, const uint8_t * aesKey) { if (len < sizeof (SSUHeader)) { @@ -335,7 +336,7 @@ namespace ssu m_Decryption.ProcessData (encrypted, encrypted, encryptedLen); } - bool SSUSession::Validate (uint8_t * buf, size_t len, uint8_t * macKey) + bool SSUSession::Validate (uint8_t * buf, size_t len, const uint8_t * macKey) { if (len < sizeof (SSUHeader)) { @@ -535,7 +536,7 @@ namespace ssu LogPrint ("SSU receive error: ", ecode.message ()); } - SSUSession * SSUServer::GetSession (i2p::data::RouterInfo * router) + SSUSession * SSUServer::GetSession (const i2p::data::RouterInfo * router) { SSUSession * session = nullptr; if (router) diff --git a/SSU.h b/SSU.h index 15467262..fd2b8304 100644 --- a/SSU.h +++ b/SSU.h @@ -62,8 +62,8 @@ namespace ssu { public: - SSUSession (SSUServer * server, const boost::asio::ip::udp::endpoint& remoteEndpoint, - i2p::data::RouterInfo * router = nullptr); + SSUSession (SSUServer * server, boost::asio::ip::udp::endpoint& remoteEndpoint, + const i2p::data::RouterInfo * router = nullptr); void ProcessNextMessage (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint); void Connect (); @@ -86,16 +86,16 @@ namespace ssu void SendMsgAck (uint32_t msgID); void SendSesionDestroyed (); - bool ProcessIntroKeyEncryptedMessage (uint8_t expectedPayloadType, i2p::data::RouterInfo& r, uint8_t * buf, size_t len); - void FillHeaderAndEncrypt (uint8_t payloadType, uint8_t * buf, size_t len, uint8_t * aesKey, uint8_t * iv, uint8_t * macKey); - void Decrypt (uint8_t * buf, size_t len, uint8_t * aesKey); - bool Validate (uint8_t * buf, size_t len, uint8_t * macKey); + bool ProcessIntroKeyEncryptedMessage (uint8_t expectedPayloadType, const i2p::data::RouterInfo& r, 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); private: SSUServer * m_Server; boost::asio::ip::udp::endpoint m_RemoteEndpoint; - i2p::data::RouterInfo * m_RemoteRouter; + const i2p::data::RouterInfo * m_RemoteRouter; SessionState m_State; CryptoPP::CBC_Mode::Encryption m_Encryption; CryptoPP::CBC_Mode::Decryption m_Decryption; @@ -111,7 +111,7 @@ namespace ssu ~SSUServer (); void Start (); void Stop (); - SSUSession * GetSession (i2p::data::RouterInfo * router); + SSUSession * GetSession (const i2p::data::RouterInfo * router); void DeleteSession (SSUSession * session); void DeleteAllSessions (); diff --git a/Transports.cpp b/Transports.cpp index 8ea6c05f..dc76b35c 100644 --- a/Transports.cpp +++ b/Transports.cpp @@ -55,8 +55,7 @@ namespace i2p } } - // TODO: do it for SSU only - DetectExternalIP (); + //DetectExternalIP (); } void Transports::Stop () @@ -189,7 +188,7 @@ namespace i2p { auto router = i2p::data::netdb.GetRandomRouter (); if (router && router->IsSSU () && m_SSUServer) - m_SSUServer->GetSession (const_cast(router)); //TODO + m_SSUServer->GetSession (router); } if (m_Timer) { diff --git a/hmac.h b/hmac.h index 6e9c042b..971b9f1a 100644 --- a/hmac.h +++ b/hmac.h @@ -13,7 +13,7 @@ namespace crypto const uint64_t IPAD = 0x3636363636363636; const uint64_t OPAD = 0x5C5C5C5C5C5C5C5C; - inline void HMACMD5Digest (uint8_t * msg, size_t len, uint8_t * key, uint8_t * digest) + inline void HMACMD5Digest (uint8_t * msg, size_t len, const uint8_t * key, uint8_t * digest) // key is 32 bytes // digest is 16 bytes // block size is 64 bytes From 290c1890cc702779c8c8df4a22ec7747c4989686 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 9 Feb 2014 15:15:47 -0500 Subject: [PATCH 10/43] UPnP added --- Makefile | 3 ++- UPnP.cpp | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ UPnP.h | 41 ++++++++++++++++++++++++++++++++++ 3 files changed, 111 insertions(+), 1 deletion(-) create mode 100644 UPnP.cpp create mode 100644 UPnP.h diff --git a/Makefile b/Makefile index b5739c46..d9d9b4c9 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,8 @@ CFLAGS = -g -Wall -std=c++0x OBJECTS = obj/i2p.o obj/base64.o obj/NTCPSession.o obj/RouterInfo.o obj/Transports.o \ obj/RouterContext.o obj/NetDb.o obj/LeaseSet.o obj/Tunnel.o obj/TunnelEndpoint.o \ obj/TunnelGateway.o obj/TransitTunnel.o obj/I2NPProtocol.o obj/Log.o obj/Garlic.o \ - obj/HTTPServer.o obj/Streaming.o obj/Identity.o obj/SSU.o obj/util.o obj/Reseed.o + obj/HTTPServer.o obj/Streaming.o obj/Identity.o obj/SSU.o obj/util.o obj/Reseed.o \ + obj/UPnP.o INCFLAGS = LDFLAGS = -Wl,-rpath,/usr/local/lib -lcryptopp -lboost_system -lboost_filesystem -lboost_regex -lboost_program_options -lpthread LIBS = diff --git a/UPnP.cpp b/UPnP.cpp new file mode 100644 index 00000000..ebadc80f --- /dev/null +++ b/UPnP.cpp @@ -0,0 +1,68 @@ +#include +#include +#include +#include "Log.h" +#include "UPnP.h" + +namespace i2p +{ + UPnP::UPnP (): m_Timer (m_Service), + m_Endpoint (boost::asio::ip::udp::v4 (), UPNP_REPLY_PORT), + m_MulticastEndpoint (boost::asio::ip::address::from_string (UPNP_GROUP), UPNP_PORT), + m_Socket (m_Service, m_Endpoint.protocol ()) + { + m_Socket.set_option (boost::asio::socket_base::receive_buffer_size (65535)); + m_Socket.set_option (boost::asio::socket_base::send_buffer_size (65535)); + m_Socket.set_option(boost::asio::ip::udp::socket::reuse_address(true)); + } + + UPnP::~UPnP () + { + } + + void UPnP::Run () + { + DiscoverRouter (); + m_Service.run (); + } + + void UPnP::DiscoverRouter () + { + m_Timer.expires_from_now (boost::posix_time::seconds(5)); // 5 seconds + m_Timer.async_wait (boost::bind (&UPnP::HandleTimer, this, boost::asio::placeholders::error)); + + std::string address = UPNP_GROUP; + address += ":" + boost::lexical_cast(UPNP_PORT); + std::string request = "M-SEARCH * HTTP/1.1\r\n" + "HOST: " + address + "\r\n" + "ST:" + UPNP_ROUTER + "\r\n" + "MAN:\"ssdp:discover\"\r\n" + "MX:3\r\n" + "\r\n\r\n"; + m_Socket.send_to (boost::asio::buffer (request.c_str (), request.length ()), m_MulticastEndpoint); + Receive (); + } + + void UPnP::Receive () + { + m_Socket.async_receive_from (boost::asio::buffer (m_ReceiveBuffer, UPNP_MAX_PACKET_LEN), m_SenderEndpoint, + boost::bind (&UPnP::HandleReceivedFrom, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); + } + + void UPnP::HandleReceivedFrom (const boost::system::error_code& ecode, size_t bytes_transferred) + { + LogPrint ("UPnP: ", bytes_transferred, " received from ", m_SenderEndpoint.address ()); + std::string str (m_ReceiveBuffer, bytes_transferred); + LogPrint (str); + m_Timer.cancel (); + } + + void UPnP::HandleTimer (const boost::system::error_code& ecode) + { + if (ecode != boost::asio::error::operation_aborted) + { + LogPrint ("UPnP: timeout expired"); + m_Service.stop (); + } + } +} diff --git a/UPnP.h b/UPnP.h new file mode 100644 index 00000000..3b5122d1 --- /dev/null +++ b/UPnP.h @@ -0,0 +1,41 @@ +#ifndef UPNP_H__ +#define UPNP_H__ + +#include + +namespace i2p +{ + const int UPNP_MAX_PACKET_LEN = 1500; + const char UPNP_GROUP[] = "239.255.255.250"; + const int UPNP_PORT = 1900; + const int UPNP_REPLY_PORT = 1901; + const char UPNP_ROUTER[] = "urn:schemas-upnp-org:device:InternetGatewayDevice:1"; + + class UPnP + { + public: + + UPnP (); + ~UPnP (); + + void Run (); + + + private: + + void DiscoverRouter (); + void Receive (); + void HandleReceivedFrom (const boost::system::error_code& ecode, size_t bytes_transferred); + void HandleTimer (const boost::system::error_code& ecode); + + private: + + boost::asio::io_service m_Service; + boost::asio::deadline_timer m_Timer; + boost::asio::ip::udp::endpoint m_Endpoint, m_MulticastEndpoint, m_SenderEndpoint; + boost::asio::ip::udp::socket m_Socket; + char m_ReceiveBuffer[UPNP_MAX_PACKET_LEN]; + }; +} + +#endif From 735f6bd72ad64857d0fef064439a16bc452ee5bf Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 9 Feb 2014 18:28:34 -0500 Subject: [PATCH 11/43] SSU send message --- I2NPProtocol.h | 9 ++++++ SSU.cpp | 75 ++++++++++++++++++++++++++++++++++++++++++++++++-- SSU.h | 4 +++ 3 files changed, 86 insertions(+), 2 deletions(-) diff --git a/I2NPProtocol.h b/I2NPProtocol.h index 3905da5b..e7c04d16 100644 --- a/I2NPProtocol.h +++ b/I2NPProtocol.h @@ -121,6 +121,15 @@ namespace i2p header->size = htobe16 (len - offset - sizeof (I2NPHeader)); header->chks = 0; } + uint32_t ToSSU () // return msgID + { + I2NPHeader header = *GetHeader (); + I2NPHeaderShort * ssu = (I2NPHeaderShort *)GetSSUHeader (); + ssu->typeID = header.typeID; + ssu->shortExpiration = htobe32 (be64toh (header.expiration)/1000LL); + len = offset + sizeof (I2NPHeaderShort) + be16toh (header.size); + return be32toh (header.msgID); + } }; I2NPMessage * NewI2NPMessage (); void DeleteI2NPMessage (I2NPMessage * msg); diff --git a/SSU.cpp b/SSU.cpp index c0715d9e..a412a9c1 100644 --- a/SSU.cpp +++ b/SSU.cpp @@ -133,6 +133,7 @@ namespace ssu uint32_t relayTag = be32toh (*(uint32_t *)(buf + sizeof (SSUHeader) + 263)); SendSessionConfirmed (buf + sizeof (SSUHeader), ourAddress, relayTag); m_State = eSessionStateEstablished; + Established (); } } @@ -149,6 +150,7 @@ namespace ssu LogPrint ("Session confirmed received"); // TODO: m_State = eSessionStateEstablished; + Established (); } else LogPrint ("Unexpected payload type ", (int)(header->flag >> 4)); @@ -362,13 +364,35 @@ namespace ssu void SSUSession::Close () { SendSesionDestroyed (); + if (!m_DelayedMessages.empty ()) + { + for (auto it :m_DelayedMessages) + delete it; + m_DelayedMessages.clear (); + } + } + + void SSUSession::Established () + { + if (!m_DelayedMessages.empty ()) + { + for (auto it :m_DelayedMessages) + Send (it); + m_DelayedMessages.clear (); + } } void SSUSession::SendI2NPMessage (I2NPMessage * msg) { - // TODO: + if (msg) + { + if (m_State == eSessionStateEstablished) + Send (msg); + else + m_DelayedMessages.push_back (msg); + } } - + void SSUSession::ProcessData (uint8_t * buf, size_t len) { //uint8_t * start = buf; @@ -479,6 +503,52 @@ namespace ssu FillHeaderAndEncrypt (PAYLOAD_TYPE_SESSION_DESTROYED, buf, 48, m_SessionKey, iv, m_MacKey); m_Server->Send (buf, 48, m_RemoteEndpoint); } + + void SSUSession::Send (i2p::I2NPMessage * msg) + { + uint32_t msgID = htobe32 (msg->ToSSU ()); + size_t payloadSize = SSU_MTU - sizeof (SSUHeader) - 9; // 9 = flag + #frg(1) + messageID(4) + frag info (3) + size_t len = msg->GetLength (); + uint8_t * msgBuf = msg->GetSSUHeader (); + + 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; + bool isLast = (len <= payloadSize); + size_t size = isLast ? len : payloadSize; + uint32_t fragmentInfo = (fragmentNum << 17); + if (isLast) + fragmentInfo |= 0x010000; + + fragmentInfo |= size; + fragmentInfo = htobe32 (fragmentInfo); + memcpy (buf + 6, (uint8_t *)(&fragmentInfo) + 1, 3); + memcpy (buf + 9, msgBuf, size); + + size += sizeof (SSUHeader) + 9; + if (size % 16) // make sure 16 bytes boundary + size = (size/16 + 1)*16; + + CryptoPP::RandomNumberGenerator& rnd = i2p::context.GetRandomNumberGenerator (); + rnd.GenerateBlock (iv, 16); // random iv + // encrypt message with session key + FillHeaderAndEncrypt (PAYLOAD_TYPE_DATA, buf, size, m_SessionKey, iv, m_MacKey); + m_Server->Send (buf, size, m_RemoteEndpoint); + + if (!isLast) + { + len -= payloadSize; + msgBuf += payloadSize; + } + else + len = 0; + fragmentNum++; + } + } SSUServer::SSUServer (boost::asio::io_service& service, int port): m_Endpoint (boost::asio::ip::udp::v4 (), port), m_Socket (service, m_Endpoint) @@ -506,6 +576,7 @@ namespace ssu void SSUServer::Send (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& to) { m_Socket.send_to (boost::asio::buffer (buf, len), to); + LogPrint ("SSU sent ", len, " bytes"); } void SSUServer::Receive () diff --git a/SSU.h b/SSU.h index fd2b8304..3996f02d 100644 --- a/SSU.h +++ b/SSU.h @@ -3,6 +3,7 @@ #include #include +#include #include #include #include @@ -82,9 +83,11 @@ namespace ssu void SendSessionCreated (const uint8_t * x); void ProcessSessionConfirmed (uint8_t * buf, size_t len); void SendSessionConfirmed (const uint8_t * y, const uint8_t * ourAddress, uint32_t relayTag); + void Established (); void ProcessData (uint8_t * buf, size_t len); void SendMsgAck (uint32_t msgID); void SendSesionDestroyed (); + void Send (i2p::I2NPMessage * msg); bool ProcessIntroKeyEncryptedMessage (uint8_t expectedPayloadType, const i2p::data::RouterInfo& r, 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); @@ -101,6 +104,7 @@ namespace ssu CryptoPP::CBC_Mode::Decryption m_Decryption; uint8_t m_SessionKey[32], m_MacKey[32]; std::map m_IncomleteMessages; + std::list m_DelayedMessages; }; class SSUServer From c5f70d45592ba37ff7ee83694c95bef2ddfa49ea Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 10 Feb 2014 15:13:16 -0500 Subject: [PATCH 12/43] 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 13/43] 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 14/43] 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 15/43] 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 16/43] 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: From ce722e7a5e15cdda16b32923496c4caf977c9f4c Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 12 Feb 2014 22:02:39 -0500 Subject: [PATCH 17/43] publish --- NetDb.cpp | 24 ++++++++++++++++++++---- NetDb.h | 1 + 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/NetDb.cpp b/NetDb.cpp index aa040758..f9da5263 100644 --- a/NetDb.cpp +++ b/NetDb.cpp @@ -90,7 +90,7 @@ namespace data void NetDb::Run () { - uint32_t lastTs = 0; + uint32_t lastSave = 0, lastPublish = 0; m_IsRunning = true; while (m_IsRunning) { @@ -120,11 +120,16 @@ namespace data Explore (); uint64_t ts = i2p::util::GetSecondsSinceEpoch (); - if (ts - lastTs >= 60) // save routers every minute + if (ts - lastSave >= 60) // save routers every minute { - if (lastTs) + if (lastSave) SaveUpdated (m_NetDbPath); - lastTs = ts; + lastSave = ts; + } + if (ts - lastPublish >= 600) // publish every 10 minutes + { + Publish (); + lastPublish = ts; } } catch (std::exception& ex) @@ -543,6 +548,17 @@ namespace data } } + void NetDb::Publish () + { + std::set excluded; // TODO: fill up later + auto floodfill = GetClosestFloodfill (i2p::context.GetRouterInfo ().GetIdentHash (), excluded); + if (floodfill) + { + LogPrint ("Publishing our RouterInfo to ", floodfill->GetIdentHashAbbreviation ()); + transports.SendMessage (floodfill->GetIdentHash (), CreateDatabaseStoreMsg ()); + } + } + RequestedDestination * NetDb::CreateRequestedDestination (const IdentHash& dest, bool isLeaseSet, bool isExploratory) { diff --git a/NetDb.h b/NetDb.h index 8f0e4125..68c136bc 100644 --- a/NetDb.h +++ b/NetDb.h @@ -82,6 +82,7 @@ namespace data void SaveUpdated (const char * directory); void Run (); // exploratory thread void Explore (); + void Publish (); const RouterInfo * GetClosestFloodfill (const IdentHash& destination, const std::set& excluded) const; RequestedDestination * CreateRequestedDestination (const IdentHash& dest, From 1545a21682bb86afa018b09bc0145698291d26f4 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 14 Feb 2014 16:10:25 -0500 Subject: [PATCH 18/43] subscribe to LeaseSet --- HTTPServer.cpp | 9 +-------- NetDb.cpp | 33 ++++++++++++++++++++++++++++++++- NetDb.h | 6 +++++- 3 files changed, 38 insertions(+), 10 deletions(-) diff --git a/HTTPServer.cpp b/HTTPServer.cpp index 5aeac9ed..3589c0df 100644 --- a/HTTPServer.cpp +++ b/HTTPServer.cpp @@ -156,7 +156,7 @@ namespace util auto leaseSet = i2p::data::netdb.FindLeaseSet (destination); if (!leaseSet || !leaseSet->HasNonExpiredLeases ()) { - i2p::data::netdb.RequestDestination (i2p::data::IdentHash (destination), true); + i2p::data::netdb.Subscribe(destination); std::this_thread::sleep_for (std::chrono::seconds(10)); // wait for 10 seconds leaseSet = i2p::data::netdb.FindLeaseSet (destination); if (!leaseSet || !leaseSet->HasNonExpiredLeases ()) // still no LeaseSet @@ -170,13 +170,6 @@ namespace util return; } } - // we found LeaseSet - if (leaseSet->HasExpiredLeases ()) - { - // we should re-request LeaseSet - LogPrint ("LeaseSet re-requested"); - i2p::data::netdb.RequestDestination (i2p::data::IdentHash (destination), true); - } auto s = i2p::stream::CreateStream (leaseSet); if (s) { diff --git a/NetDb.cpp b/NetDb.cpp index f9da5263..0ebafb66 100644 --- a/NetDb.cpp +++ b/NetDb.cpp @@ -120,10 +120,13 @@ namespace data Explore (); uint64_t ts = i2p::util::GetSecondsSinceEpoch (); - if (ts - lastSave >= 60) // save routers every minute + if (ts - lastSave >= 60) // save routers and validate subscriptions every minute { if (lastSave) + { SaveUpdated (m_NetDbPath); + ValidateSubscriptions (); + } lastSave = ts; } if (ts - lastPublish >= 600) // publish every 10 minutes @@ -660,5 +663,33 @@ namespace data return r; } + void NetDb::Subscribe (const IdentHash& ident) + { + LeaseSet * leaseSet = FindLeaseSet (ident); + if (!leaseSet) + { + LogPrint ("LeaseSet requested"); + RequestDestination (ident, true); + } + m_Subscriptions.insert (ident); + } + + void NetDb::Unsubscribe (const IdentHash& ident) + { + m_Subscriptions.erase (ident); + } + + void NetDb::ValidateSubscriptions () + { + for (auto it : m_Subscriptions) + { + LeaseSet * leaseSet = FindLeaseSet (it); + if (!leaseSet || leaseSet->HasExpiredLeases ()) + { + LogPrint ("LeaseSet re-requested"); + RequestDestination (it, true); + } + } + } } } diff --git a/NetDb.h b/NetDb.h index 68c136bc..39f87df0 100644 --- a/NetDb.h +++ b/NetDb.h @@ -63,7 +63,9 @@ namespace data void AddLeaseSet (uint8_t * buf, int len); RouterInfo * FindRouter (const IdentHash& ident) const; LeaseSet * FindLeaseSet (const IdentHash& destination) const; - + void Subscribe (const IdentHash& ident); // keep LeaseSets upto date + void Unsubscribe (const IdentHash& ident); + void RequestDestination (const char * b32); // in base32 void RequestDestination (const IdentHash& destination, bool isLeaseSet = false); @@ -83,6 +85,7 @@ namespace data void Run (); // exploratory thread void Explore (); void Publish (); + void ValidateSubscriptions (); const RouterInfo * GetClosestFloodfill (const IdentHash& destination, const std::set& excluded) const; RequestedDestination * CreateRequestedDestination (const IdentHash& dest, @@ -95,6 +98,7 @@ namespace data std::map m_LeaseSets; std::map m_RouterInfos; std::map m_RequestedDestinations; + std::set m_Subscriptions; bool m_IsRunning; int m_ReseedRetries; From 759fd0815d0e9f6b12384394f3a9648479df2a46 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 14 Feb 2014 22:11:49 -0500 Subject: [PATCH 19/43] limit depth of exploratory sent directly --- HTTPServer.cpp | 2 +- NetDb.cpp | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/HTTPServer.cpp b/HTTPServer.cpp index 3589c0df..0ae7a3dc 100644 --- a/HTTPServer.cpp +++ b/HTTPServer.cpp @@ -60,7 +60,7 @@ namespace util { m_Buffer[bytes_transferred] = 0; auto address = ExtractAddress (); - LogPrint (address); + //LogPrint (address); if (address.length () > 1) // not just '/' HandleDestinationRequest (address.substr (1)); // exclude '/' else diff --git a/NetDb.cpp b/NetDb.cpp index 0ebafb66..9dd78204 100644 --- a/NetDb.cpp +++ b/NetDb.cpp @@ -494,7 +494,10 @@ namespace data else // we should send directly { if (!dest->IsLeaseSet ()) // if not LeaseSet - i2p::transports.SendMessage (router, dest->CreateRequestMessage (router)); + { + if (!dest->IsExcluded (router) && dest->GetNumExcludedPeers () < 30) + i2p::transports.SendMessage (router, dest->CreateRequestMessage (router)); + } else LogPrint ("Can't request LeaseSet"); } From 10c7e05ff416225f0aa4d743a5b553fc0e527411 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 16 Feb 2014 08:57:50 -0500 Subject: [PATCH 20/43] fixed crash --- Transports.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/Transports.cpp b/Transports.cpp index ac5085fa..cc56a86f 100644 --- a/Transports.cpp +++ b/Transports.cpp @@ -64,9 +64,12 @@ namespace i2p delete session.second; m_NTCPSessions.clear (); delete m_NTCPAcceptor; - - m_Timer->cancel (); - delete m_Timer; + + if (m_Timer) + { + m_Timer->cancel (); + delete m_Timer; + } if (m_SSUServer) { From f5fa953458baf1a06c83db29ebf630ea102b0fe4 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 17 Feb 2014 17:47:21 -0500 Subject: [PATCH 21/43] process b32 address with path --- HTTPServer.cpp | 27 +++++++++++++++++++++------ HTTPServer.h | 2 +- Streaming.cpp | 2 +- 3 files changed, 23 insertions(+), 8 deletions(-) diff --git a/HTTPServer.cpp b/HTTPServer.cpp index 0ae7a3dc..3cf956cc 100644 --- a/HTTPServer.cpp +++ b/HTTPServer.cpp @@ -60,9 +60,20 @@ namespace util { m_Buffer[bytes_transferred] = 0; auto address = ExtractAddress (); - //LogPrint (address); if (address.length () > 1) // not just '/' - HandleDestinationRequest (address.substr (1)); // exclude '/' + { + std::string uri ("/"), b32; + size_t pos = address.find ('/', 1); + if (pos == std::string::npos) + b32 = address.substr (1); // excluding leading '/' to end of line + else + { + b32 = address.substr (1, pos - 1); // excluding leading '/' to next '/' + uri = address.substr (pos); // rest of line + } + + HandleDestinationRequest (b32, uri); + } else HandleRequest (); boost::asio::async_write (*m_Socket, m_Reply.to_buffers(), @@ -149,10 +160,14 @@ namespace util s << "

Flibusta

"; } - void HTTPConnection::HandleDestinationRequest (std::string b32) + void HTTPConnection::HandleDestinationRequest (const std::string& b32, const std::string& uri) { uint8_t destination[32]; - i2p::data::Base32ToByteStream (b32.c_str (), b32.length (), destination, 32); + if (i2p::data::Base32ToByteStream (b32.c_str (), b32.length (), destination, 32) != 32) + { + LogPrint ("Invalid Base32 address ", b32); + return; + } auto leaseSet = i2p::data::netdb.FindLeaseSet (destination); if (!leaseSet || !leaseSet->HasNonExpiredLeases ()) { @@ -173,7 +188,7 @@ namespace util auto s = i2p::stream::CreateStream (leaseSet); if (s) { - std::string request = "GET / HTTP/1.1\n Host:" + b32 + ".b32.i2p\n"; + std::string request = "GET " + uri + " HTTP/1.1\n Host:" + b32 + ".b32.i2p\n"; s->Send ((uint8_t *)request.c_str (), request.length (), 10); std::stringstream ss; uint8_t buf[8192]; @@ -193,7 +208,7 @@ namespace util else // nothing received ss << "Not responding"; s->Close (); - //DeleteStream (s); + DeleteStream (s); m_Reply.content = ss.str (); m_Reply.headers.resize(2); diff --git a/HTTPServer.h b/HTTPServer.h index 90aacfc0..a62a2074 100644 --- a/HTTPServer.h +++ b/HTTPServer.h @@ -48,7 +48,7 @@ namespace util void HandleWrite(const boost::system::error_code& ecode); void HandleRequest (); - void HandleDestinationRequest (std::string b32); + void HandleDestinationRequest (const std::string& b32, const std::string& uri); void FillContent (std::stringstream& s); std::string ExtractAddress (); diff --git a/Streaming.cpp b/Streaming.cpp index 05f838fa..3f4f53e6 100644 --- a/Streaming.cpp +++ b/Streaming.cpp @@ -318,7 +318,7 @@ namespace stream void StreamingDestination::HandleNextPacket (Packet * packet) { - uint32_t sendStreamID = be32toh (*(uint32_t *)(packet->buf)); + uint32_t sendStreamID = packet->GetSendStreamID (); auto it = m_Streams.find (sendStreamID); if (it != m_Streams.end ()) it->second->HandleNextPacket (packet); From 154105a05986cd0b29cfe97389f3b0d37988f4d9 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 19 Feb 2014 21:24:55 -0500 Subject: [PATCH 22/43] pass delivery intructions to tunnel gateway --- I2NPProtocol.cpp | 2 +- NTCPSession.h | 2 +- TransitTunnel.cpp | 6 +++--- TransitTunnel.h | 4 ++-- Tunnel.cpp | 17 +--------------- Tunnel.h | 2 +- TunnelGateway.cpp | 52 +++++++++++++++++++++++++++++++++-------------- TunnelGateway.h | 6 ++++-- 8 files changed, 50 insertions(+), 41 deletions(-) diff --git a/I2NPProtocol.cpp b/I2NPProtocol.cpp index 6503d70f..f42d9f9d 100644 --- a/I2NPProtocol.cpp +++ b/I2NPProtocol.cpp @@ -392,7 +392,7 @@ namespace i2p LogPrint ("TunnelGateway of ", (int)len, " bytes for tunnel ", (unsigned int)tunnelID, ". Msg type ", (int)msg->GetHeader()->typeID); i2p::tunnel::TransitTunnel * tunnel = i2p::tunnel::tunnels.GetTransitTunnel (tunnelID); if (tunnel) - tunnel->SendTunnelDataMsg (nullptr, 0, msg); + tunnel->SendTunnelDataMsg (msg); else { LogPrint ("Tunnel ", (unsigned int)tunnelID, " not found"); diff --git a/NTCPSession.h b/NTCPSession.h index 71cf5af9..0976581d 100644 --- a/NTCPSession.h +++ b/NTCPSession.h @@ -60,7 +60,7 @@ namespace ntcp #pragma pack() - const int TERMINATION_TIMEOUT = 60; // 1 minute + const int TERMINATION_TIMEOUT = 150; // 2.5 minutes class NTCPSession { public: diff --git a/TransitTunnel.cpp b/TransitTunnel.cpp index 6c9a4f6f..2435cbe5 100644 --- a/TransitTunnel.cpp +++ b/TransitTunnel.cpp @@ -47,15 +47,15 @@ namespace tunnel m_NumTransmittedBytes += tunnelMsg->GetLength (); } - void TransitTunnel::SendTunnelDataMsg (const uint8_t * gwHash, uint32_t gwTunnel, i2p::I2NPMessage * msg) + void TransitTunnel::SendTunnelDataMsg (i2p::I2NPMessage * msg) { LogPrint ("We are not a gateway for transit tunnel ", m_TunnelID); i2p::DeleteI2NPMessage (msg); } - void TransitTunnelGateway::SendTunnelDataMsg (const uint8_t * gwHash, uint32_t gwTunnel, i2p::I2NPMessage * msg) + void TransitTunnelGateway::SendTunnelDataMsg (i2p::I2NPMessage * msg) { - m_Gateway.SendTunnelDataMsg (gwHash, gwTunnel, msg); + m_Gateway.SendTunnelDataMsg (msg); } void TransitTunnelEndpoint::HandleTunnelDataMsg (i2p::I2NPMessage * tunnelMsg) diff --git a/TransitTunnel.h b/TransitTunnel.h index 570429f5..feeeaa58 100644 --- a/TransitTunnel.h +++ b/TransitTunnel.h @@ -22,7 +22,7 @@ namespace tunnel const uint8_t * layerKey,const uint8_t * ivKey); virtual void HandleTunnelDataMsg (i2p::I2NPMessage * tunnelMsg); - virtual void SendTunnelDataMsg (const uint8_t * gwHash, uint32_t gwTunnel, i2p::I2NPMessage * msg); + virtual void SendTunnelDataMsg (i2p::I2NPMessage * msg); virtual size_t GetNumTransmittedBytes () const { return m_NumTransmittedBytes; }; uint32_t GetTunnelID () const { return m_TunnelID; }; @@ -54,7 +54,7 @@ namespace tunnel TransitTunnel (receiveTunnelID, nextIdent, nextTunnelID, layerKey, ivKey), m_Gateway(this) {}; - void SendTunnelDataMsg (const uint8_t * gwHash, uint32_t gwTunnel, i2p::I2NPMessage * msg); + void SendTunnelDataMsg (i2p::I2NPMessage * msg); size_t GetNumTransmittedBytes () const { return m_Gateway.GetNumSentBytes (); }; private: diff --git a/Tunnel.cpp b/Tunnel.cpp index 1163f47e..88ab9534 100644 --- a/Tunnel.cpp +++ b/Tunnel.cpp @@ -142,22 +142,7 @@ namespace tunnel void OutboundTunnel::SendTunnelDataMsg (std::vector msgs) { for (auto& it : msgs) - { - switch (it.deliveryType) - { - case eDeliveryTypeLocal: - m_Gateway.SendTunnelDataMsg (nullptr, 0, it.data); - break; - case eDeliveryTypeTunnel: - m_Gateway.SendTunnelDataMsg (it.hash, it.tunnelID, it.data); - break; - case eDeliveryTypeRouter: - m_Gateway.SendTunnelDataMsg (it.hash, 0, it.data); - break; - default: - LogPrint ("Unexpected delivery type ", (int)it.deliveryType); - } - } + m_Gateway.PutTunnelDataMsg (it); m_Gateway.SendBuffer (); } diff --git a/Tunnel.h b/Tunnel.h index 3498eae3..7e7f94d5 100644 --- a/Tunnel.h +++ b/Tunnel.h @@ -21,7 +21,7 @@ namespace i2p { namespace tunnel { - const int TUNNEL_EXPIRATION_TIMEOUT = 600; // 10 minutes + const int TUNNEL_EXPIRATION_TIMEOUT = 660; // 11 minutes class OutboundTunnel; class InboundTunnel; diff --git a/TunnelGateway.cpp b/TunnelGateway.cpp index 55d78326..50eb1c7f 100644 --- a/TunnelGateway.cpp +++ b/TunnelGateway.cpp @@ -10,7 +10,7 @@ namespace i2p { namespace tunnel { - void TunnelGatewayBuffer::PutI2NPMsg (const uint8_t * gwHash, uint32_t gwTunnel, I2NPMessage * msg) + void TunnelGatewayBuffer::PutI2NPMsg (const TunnelMessageBlock& block) { if (!m_CurrentTunnelDataMsg) CreateCurrentTunnelDataMessage (); @@ -18,24 +18,21 @@ namespace tunnel // create delivery instructions uint8_t di[43]; // max delivery instruction length is 43 for tunnel size_t diLen = 1;// flag - TunnelDeliveryType dt = eDeliveryTypeLocal; - if (gwHash) + if (block.deliveryType != eDeliveryTypeLocal) // tunnel or router { - if (gwTunnel) + if (block.deliveryType == eDeliveryTypeTunnel) { - *(uint32_t *)(di + diLen) = htobe32 (gwTunnel); + *(uint32_t *)(di + diLen) = htobe32 (block.tunnelID); diLen += 4; // tunnelID - dt = eDeliveryTypeTunnel; } - else - dt = eDeliveryTypeRouter; - memcpy (di + diLen, gwHash, 32); + memcpy (di + diLen, block.hash, 32); diLen += 32; //len } - di[0] = dt << 5; // set delivery type + di[0] = block.deliveryType << 5; // set delivery type // create fragments + I2NPMessage * msg = block.data; if (diLen + msg->GetLength () + 2<= m_RemainingSize) { // message fits. First and last fragment @@ -104,7 +101,7 @@ namespace tunnel { // delivery instructions don't fit. Create new message CompleteCurrentTunnelDataMessage (); - PutI2NPMsg (gwHash, gwTunnel, msg); + PutI2NPMsg (block); // don't delete msg because it's taken care inside } } @@ -151,16 +148,41 @@ namespace tunnel m_TunnelDataMsgs.push_back (m_CurrentTunnelDataMsg); m_CurrentTunnelDataMsg = nullptr; } - + + void TunnelGateway::SendTunnelDataMsg (i2p::I2NPMessage * msg) + { + SendTunnelDataMsg (nullptr, 0, msg); + } + void TunnelGateway::SendTunnelDataMsg (const uint8_t * gwHash, uint32_t gwTunnel, i2p::I2NPMessage * msg) { - PutTunnelDataMsg (gwHash, gwTunnel, msg); + TunnelMessageBlock block; + if (gwHash) + { + block.hash = gwHash; + if (gwTunnel) + { + block.deliveryType = eDeliveryTypeTunnel; + block.tunnelID = gwTunnel; + } + else + block.deliveryType = eDeliveryTypeRouter; + } + else + block.deliveryType = eDeliveryTypeLocal; + block.data = msg; + SendTunnelDataMsg (block); + } + + void TunnelGateway::SendTunnelDataMsg (const TunnelMessageBlock& block) + { + PutTunnelDataMsg (block); SendBuffer (); } - void TunnelGateway::PutTunnelDataMsg (const uint8_t * gwHash, uint32_t gwTunnel, i2p::I2NPMessage * msg) + void TunnelGateway::PutTunnelDataMsg (const TunnelMessageBlock& block) { - m_Buffer.PutI2NPMsg (gwHash, gwTunnel, msg); + m_Buffer.PutI2NPMsg (block); } void TunnelGateway::SendBuffer () diff --git a/TunnelGateway.h b/TunnelGateway.h index d68c8580..6226c8ec 100644 --- a/TunnelGateway.h +++ b/TunnelGateway.h @@ -15,7 +15,7 @@ namespace tunnel public: TunnelGatewayBuffer (uint32_t tunnelID): m_TunnelID (tunnelID), m_CurrentTunnelDataMsg (nullptr), m_RemainingSize (0) {}; - void PutI2NPMsg (const uint8_t * gwHash, uint32_t gwTunnel, I2NPMessage * msg); + void PutI2NPMsg (const TunnelMessageBlock& block); std::vector GetTunnelDataMsgs (); private: @@ -37,8 +37,10 @@ namespace tunnel TunnelGateway (TunnelBase * tunnel): m_Tunnel (tunnel), m_Buffer (tunnel->GetNextTunnelID ()), m_NumSentBytes (0) {}; + void SendTunnelDataMsg (i2p::I2NPMessage * msg); void SendTunnelDataMsg (const uint8_t * gwHash, uint32_t gwTunnel, i2p::I2NPMessage * msg); - void PutTunnelDataMsg (const uint8_t * gwHash, uint32_t gwTunnel, i2p::I2NPMessage * msg); + void SendTunnelDataMsg (const TunnelMessageBlock& block); + void PutTunnelDataMsg (const TunnelMessageBlock& block); void SendBuffer (); size_t GetNumSentBytes () const { return m_NumSentBytes; }; From 345be142ae841f80ee041563a0a8cdbfebcc57d0 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 19 Feb 2014 22:08:57 -0500 Subject: [PATCH 23/43] always pass delivery instructions to tunnel gateway --- NTCPSession.h | 2 +- TransitTunnel.cpp | 5 ++++- Tunnel.cpp | 17 ++++++++++++++++- TunnelGateway.cpp | 25 ------------------------- TunnelGateway.h | 2 -- 5 files changed, 21 insertions(+), 30 deletions(-) diff --git a/NTCPSession.h b/NTCPSession.h index 0976581d..eb31951d 100644 --- a/NTCPSession.h +++ b/NTCPSession.h @@ -60,7 +60,7 @@ namespace ntcp #pragma pack() - const int TERMINATION_TIMEOUT = 150; // 2.5 minutes + const int TERMINATION_TIMEOUT = 120; // 2 minutes class NTCPSession { public: diff --git a/TransitTunnel.cpp b/TransitTunnel.cpp index 2435cbe5..a96f3d05 100644 --- a/TransitTunnel.cpp +++ b/TransitTunnel.cpp @@ -55,7 +55,10 @@ namespace tunnel void TransitTunnelGateway::SendTunnelDataMsg (i2p::I2NPMessage * msg) { - m_Gateway.SendTunnelDataMsg (msg); + TunnelMessageBlock block; + block.deliveryType = eDeliveryTypeLocal; + block.data = msg; + m_Gateway.SendTunnelDataMsg (block); } void TransitTunnelEndpoint::HandleTunnelDataMsg (i2p::I2NPMessage * tunnelMsg) diff --git a/Tunnel.cpp b/Tunnel.cpp index 88ab9534..9d58c875 100644 --- a/Tunnel.cpp +++ b/Tunnel.cpp @@ -136,7 +136,22 @@ namespace tunnel void OutboundTunnel::SendTunnelDataMsg (const uint8_t * gwHash, uint32_t gwTunnel, i2p::I2NPMessage * msg) { - m_Gateway.SendTunnelDataMsg (gwHash, gwTunnel, msg); + TunnelMessageBlock block; + if (gwHash) + { + block.hash = gwHash; + if (gwTunnel) + { + block.deliveryType = eDeliveryTypeTunnel; + block.tunnelID = gwTunnel; + } + else + block.deliveryType = eDeliveryTypeRouter; + } + else + block.deliveryType = eDeliveryTypeLocal; + block.data = msg; + m_Gateway.SendTunnelDataMsg (block); } void OutboundTunnel::SendTunnelDataMsg (std::vector msgs) diff --git a/TunnelGateway.cpp b/TunnelGateway.cpp index 50eb1c7f..cc1189e0 100644 --- a/TunnelGateway.cpp +++ b/TunnelGateway.cpp @@ -148,31 +148,6 @@ namespace tunnel m_TunnelDataMsgs.push_back (m_CurrentTunnelDataMsg); m_CurrentTunnelDataMsg = nullptr; } - - void TunnelGateway::SendTunnelDataMsg (i2p::I2NPMessage * msg) - { - SendTunnelDataMsg (nullptr, 0, msg); - } - - void TunnelGateway::SendTunnelDataMsg (const uint8_t * gwHash, uint32_t gwTunnel, i2p::I2NPMessage * msg) - { - TunnelMessageBlock block; - if (gwHash) - { - block.hash = gwHash; - if (gwTunnel) - { - block.deliveryType = eDeliveryTypeTunnel; - block.tunnelID = gwTunnel; - } - else - block.deliveryType = eDeliveryTypeRouter; - } - else - block.deliveryType = eDeliveryTypeLocal; - block.data = msg; - SendTunnelDataMsg (block); - } void TunnelGateway::SendTunnelDataMsg (const TunnelMessageBlock& block) { diff --git a/TunnelGateway.h b/TunnelGateway.h index 6226c8ec..8c390eef 100644 --- a/TunnelGateway.h +++ b/TunnelGateway.h @@ -37,8 +37,6 @@ namespace tunnel TunnelGateway (TunnelBase * tunnel): m_Tunnel (tunnel), m_Buffer (tunnel->GetNextTunnelID ()), m_NumSentBytes (0) {}; - void SendTunnelDataMsg (i2p::I2NPMessage * msg); - void SendTunnelDataMsg (const uint8_t * gwHash, uint32_t gwTunnel, i2p::I2NPMessage * msg); void SendTunnelDataMsg (const TunnelMessageBlock& block); void PutTunnelDataMsg (const TunnelMessageBlock& block); void SendBuffer (); From b14cdc80529f5c376a3131405a84415fb4dea61c Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 20 Feb 2014 12:25:28 -0500 Subject: [PATCH 24/43] ElGamalEncryptor added --- ElGamal.h | 80 +++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 63 insertions(+), 17 deletions(-) diff --git a/ElGamal.h b/ElGamal.h index 387e02bb..ca82f19a 100644 --- a/ElGamal.h +++ b/ElGamal.h @@ -12,25 +12,48 @@ namespace i2p { namespace crypto { - inline void ElGamalEncrypt (const uint8_t * key, const uint8_t * data, int len, - uint8_t * encrypted, bool zeroPadding = false) // 514 with padding and 512 without + + class ElGamalEncryptor { - CryptoPP::AutoSeededRandomPool rnd; - CryptoPP::Integer y(key, 256), k(rnd, CryptoPP::Integer::One(), elgp-1); + public: - if (zeroPadding) - { - encrypted[0] = 0; - encrypted[257] = 0; - } - a_exp_b_mod_c (elgg, k, elgp).Encode (zeroPadding ? encrypted + 1 : encrypted, 256); - uint8_t m[255]; - m[0] = 0xFF; - memcpy (m+33, data, len); - CryptoPP::SHA256().CalculateDigest(m+1, m+33, 222); - a_times_b_mod_c (a_exp_b_mod_c (y, k, elgp), - CryptoPP::Integer (m, 255), elgp).Encode (zeroPadding ? encrypted + 258 : encrypted + 256, 256); - } + ElGamalEncryptor (const uint8_t * key, bool zeroPadding = false): + y (key, 256), k (rnd, CryptoPP::Integer::One(), elgp-1), + a (a_exp_b_mod_c (elgg, k, elgp)), b1 (a_exp_b_mod_c (y, k, elgp)), + m_ZeroPadding (zeroPadding) + { + } + + void Encrypt (const uint8_t * data, int len, uint8_t * encrypted) + { + // calculate b = b1*m mod p + uint8_t m[255]; + m[0] = 0xFF; + memcpy (m+33, data, len); + CryptoPP::SHA256().CalculateDigest(m+1, m+33, 222); + CryptoPP::Integer b (a_times_b_mod_c (b1, CryptoPP::Integer (m, 255), elgp)); + + // copy a and b + if (m_ZeroPadding) + { + encrypted[0] = 0; + a.Encode (encrypted + 1, 256); + encrypted[257] = 0; + b.Encode (encrypted + 258, 256); + } + else + { + a.Encode (encrypted, 256); + b.Encode (encrypted + 256, 256); + } + } + + private: + + CryptoPP::AutoSeededRandomPool rnd; + CryptoPP::Integer y, k, a, b1; + bool m_ZeroPadding; + }; inline bool ElGamalDecrypt (const uint8_t * key, const uint8_t * encrypted, uint8_t * data, bool zeroPadding = false) @@ -49,6 +72,29 @@ namespace crypto memcpy (data, m + 33, 222); return true; } + + +// deprecated + + inline void ElGamalEncrypt (const uint8_t * key, const uint8_t * data, int len, + uint8_t * encrypted, bool zeroPadding = false) // 514 with padding and 512 without + { + CryptoPP::AutoSeededRandomPool rnd; + CryptoPP::Integer y(key, 256), k(rnd, CryptoPP::Integer::One(), elgp-1); + + if (zeroPadding) + { + encrypted[0] = 0; + encrypted[257] = 0; + } + a_exp_b_mod_c (elgg, k, elgp).Encode (zeroPadding ? encrypted + 1 : encrypted, 256); + uint8_t m[255]; + m[0] = 0xFF; + memcpy (m+33, data, len); + CryptoPP::SHA256().CalculateDigest(m+1, m+33, 222); + a_times_b_mod_c (a_exp_b_mod_c (y, k, elgp), + CryptoPP::Integer (m, 255), elgp).Encode (zeroPadding ? encrypted + 258 : encrypted + 256, 256); + } } } From 354015e9ca1bec2f792504d49d3e22c5128e58cd Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 20 Feb 2014 16:15:12 -0500 Subject: [PATCH 25/43] parse introducers from RouterInfo --- RouterInfo.cpp | 21 +++++++++++++++++++++ RouterInfo.h | 12 +++++++++++- 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/RouterInfo.cpp b/RouterInfo.cpp index e1ae0a2d..337ae7b3 100644 --- a/RouterInfo.cpp +++ b/RouterInfo.cpp @@ -129,6 +129,27 @@ namespace data address.port = boost::lexical_cast(value); else if (!strcmp (key, "key")) Base64ToByteStream (value, strlen (value), address.key, 32); + else if (key[0] == 'i') + { + // introducers + size_t l = strlen(key); + unsigned char index = key[l-1]; // TODO: + key[l-1] = 0; + if (index >= address.introducers.size ()) + address.introducers.resize (index + 1); + Introducer& introducer = address.introducers.at (index); + if (!strcmp (key, "ihost")) + { + boost::system::error_code ecode; + introducer.iHost = boost::asio::ip::address::from_string (value, ecode); + } + else if (!strcmp (key, "iport")) + introducer.iPort = boost::lexical_cast(value); + else if (!strcmp (key, "itag")) + introducer.iTag = boost::lexical_cast(value); + else if (!strcmp (key, "ikey")) + Base64ToByteStream (value, strlen (value), introducer.iKey, 32); + } } m_Addresses.push_back(address); } diff --git a/RouterInfo.h b/RouterInfo.h index 3c08d8d1..be3d59a2 100644 --- a/RouterInfo.h +++ b/RouterInfo.h @@ -32,6 +32,14 @@ namespace data eTransportSSU }; + struct Introducer + { + boost::asio::ip::address iHost; + int iPort; + uint8_t iKey[32]; + uint32_t iTag; + }; + struct Address { TransportStyle transportStyle; @@ -39,7 +47,9 @@ namespace data int port; uint64_t date; uint8_t cost; - uint8_t key[32]; // into key for SSU + // SSU only + uint8_t key[32]; // intro key for SSU + std::vector introducers; }; RouterInfo (const char * filename); From 8d6c08ec78fc5e47d496bb1ac4fa6fa737932805 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 20 Feb 2014 18:42:55 -0500 Subject: [PATCH 26/43] use ElGamalEcryption for garlic encryption --- ElGamal.h | 4 ++-- Garlic.cpp | 26 ++++++++++++-------------- Garlic.h | 10 ++++++---- HTTPServer.cpp | 2 +- NetDb.cpp | 2 +- Streaming.cpp | 12 ++++++------ Streaming.h | 10 +++++----- 7 files changed, 33 insertions(+), 33 deletions(-) diff --git a/ElGamal.h b/ElGamal.h index ca82f19a..745c3840 100644 --- a/ElGamal.h +++ b/ElGamal.h @@ -13,11 +13,11 @@ namespace i2p namespace crypto { - class ElGamalEncryptor + class ElGamalEncryption { public: - ElGamalEncryptor (const uint8_t * key, bool zeroPadding = false): + ElGamalEncryption (const uint8_t * key, bool zeroPadding = false): y (key, 256), k (rnd, CryptoPP::Integer::One(), elgp-1), a (a_exp_b_mod_c (elgg, k, elgp)), b1 (a_exp_b_mod_c (y, k, elgp)), m_ZeroPadding (zeroPadding) diff --git a/Garlic.cpp b/Garlic.cpp index cdb8860e..80a267c7 100644 --- a/Garlic.cpp +++ b/Garlic.cpp @@ -2,7 +2,6 @@ #include "I2PEndian.h" #include #include -#include "ElGamal.h" #include "RouterContext.h" #include "I2NPProtocol.h" #include "Tunnel.h" @@ -14,9 +13,10 @@ namespace i2p { namespace garlic { - GarlicRoutingSession::GarlicRoutingSession (const i2p::data::RoutingDestination * destination, int numTags): + GarlicRoutingSession::GarlicRoutingSession (const i2p::data::RoutingDestination& destination, int numTags): m_Destination (destination), m_FirstMsgID (0), m_IsAcknowledged (false), - m_NumTags (numTags), m_NextTag (-1), m_SessionTags (0) + m_NumTags (numTags), m_NextTag (-1), m_SessionTags (0), + m_ElGamalEncryption (m_Destination.GetEncryptionPublicKey (), true) { // create new session tags and session key m_Rnd.GenerateBlock (m_SessionKey, 32); @@ -56,7 +56,7 @@ namespace garlic m_Rnd.GenerateBlock (elGamal.preIV, 32); // Pre-IV uint8_t iv[32]; // IV is first 16 bytes CryptoPP::SHA256().CalculateDigest(iv, elGamal.preIV, 32); - i2p::crypto::ElGamalEncrypt (m_Destination->GetEncryptionPublicKey (), (uint8_t *)&elGamal, sizeof(elGamal), buf, true); + m_ElGamalEncryption.Encrypt ((uint8_t *)&elGamal, sizeof(elGamal), buf); m_Encryption.SetKeyWithIV (m_SessionKey, 32, iv); buf += 514; len += 514; @@ -140,7 +140,7 @@ namespace garlic } if (msg) // clove message ifself if presented { - size += CreateGarlicClove (payload + size, msg, m_Destination->IsDestination ()); + size += CreateGarlicClove (payload + size, msg, m_Destination.IsDestination ()); (*numCloves)++; } @@ -161,7 +161,7 @@ namespace garlic { buf[size] = eGarlicDeliveryTypeDestination << 5;// delivery instructions flag destination size++; - memcpy (buf + size, m_Destination->GetIdentHash (), 32); + memcpy (buf + size, m_Destination.GetIdentHash (), 32); size += 32; } else @@ -230,33 +230,31 @@ namespace garlic m_Sessions.clear (); } - I2NPMessage * GarlicRouting::WrapSingleMessage (const i2p::data::RoutingDestination * destination, I2NPMessage * msg) + I2NPMessage * GarlicRouting::WrapSingleMessage (const i2p::data::RoutingDestination& destination, I2NPMessage * msg) { - if (!destination) return nullptr; - auto it = m_Sessions.find (destination->GetIdentHash ()); + auto it = m_Sessions.find (destination.GetIdentHash ()); if (it != m_Sessions.end ()) { delete it->second; m_Sessions.erase (it); } GarlicRoutingSession * session = new GarlicRoutingSession (destination, 0); // not follow-on messages expected - m_Sessions[destination->GetIdentHash ()] = session; + m_Sessions[destination.GetIdentHash ()] = session; return session->WrapSingleMessage (msg, nullptr); } - I2NPMessage * GarlicRouting::WrapMessage (const i2p::data::RoutingDestination * destination, + I2NPMessage * GarlicRouting::WrapMessage (const i2p::data::RoutingDestination& destination, I2NPMessage * msg, I2NPMessage * leaseSet) { - if (!destination) return nullptr; - auto it = m_Sessions.find (destination->GetIdentHash ()); + auto it = m_Sessions.find (destination.GetIdentHash ()); GarlicRoutingSession * session = nullptr; if (it != m_Sessions.end ()) session = it->second; if (!session) { session = new GarlicRoutingSession (destination, 4); // TODO: change it later - m_Sessions[destination->GetIdentHash ()] = session; + m_Sessions[destination.GetIdentHash ()] = session; } I2NPMessage * ret = session->WrapSingleMessage (msg, leaseSet); diff --git a/Garlic.h b/Garlic.h index c640eee3..ca6bae64 100644 --- a/Garlic.h +++ b/Garlic.h @@ -9,6 +9,7 @@ #include #include "I2NPProtocol.h" #include "LeaseSet.h" +#include "ElGamal.h" namespace i2p { @@ -37,7 +38,7 @@ namespace garlic { public: - GarlicRoutingSession (const i2p::data::RoutingDestination * destination, int numTags); + GarlicRoutingSession (const i2p::data::RoutingDestination& destination, int numTags); ~GarlicRoutingSession (); I2NPMessage * WrapSingleMessage (I2NPMessage * msg, I2NPMessage * leaseSet); int GetNextTag () const { return m_NextTag; }; @@ -57,7 +58,7 @@ namespace garlic private: - const i2p::data::RoutingDestination * m_Destination; + const i2p::data::RoutingDestination& m_Destination; uint8_t m_SessionKey[32]; uint32_t m_FirstMsgID; // first message ID bool m_IsAcknowledged; @@ -65,6 +66,7 @@ namespace garlic uint8_t * m_SessionTags; // m_NumTags*32 bytes CryptoPP::CBC_Mode::Encryption m_Encryption; + i2p::crypto::ElGamalEncryption m_ElGamalEncryption; CryptoPP::AutoSeededRandomPool m_Rnd; }; @@ -78,8 +80,8 @@ namespace garlic void HandleGarlicMessage (uint8_t * buf, size_t len, bool isFromTunnel); void HandleDeliveryStatusMessage (uint8_t * buf, size_t len); - I2NPMessage * WrapSingleMessage (const i2p::data::RoutingDestination * destination, I2NPMessage * msg); - I2NPMessage * WrapMessage (const i2p::data::RoutingDestination * destination, + I2NPMessage * WrapSingleMessage (const i2p::data::RoutingDestination& destination, I2NPMessage * msg); + I2NPMessage * WrapMessage (const i2p::data::RoutingDestination& destination, I2NPMessage * msg, I2NPMessage * leaseSet = nullptr); private: diff --git a/HTTPServer.cpp b/HTTPServer.cpp index 3cf956cc..833dca51 100644 --- a/HTTPServer.cpp +++ b/HTTPServer.cpp @@ -185,7 +185,7 @@ namespace util return; } } - auto s = i2p::stream::CreateStream (leaseSet); + auto s = i2p::stream::CreateStream (*leaseSet); if (s) { std::string request = "GET " + uri + " HTTP/1.1\n Host:" + b32 + ".b32.i2p\n"; diff --git a/NetDb.cpp b/NetDb.cpp index 9dd78204..14a33353 100644 --- a/NetDb.cpp +++ b/NetDb.cpp @@ -25,7 +25,7 @@ namespace data I2NPMessage * msg = i2p::CreateDatabaseLookupMsg (m_Destination, replyTunnel->GetNextIdentHash (), replyTunnel->GetNextTunnelID (), m_IsExploratory, &m_ExcludedPeers); if (m_IsLeaseSet) // wrap lookup message into garlic - msg = i2p::garlic::routing.WrapSingleMessage (router, msg); + msg = i2p::garlic::routing.WrapSingleMessage (*router, msg); m_ExcludedPeers.insert (router->GetIdentHash ()); m_LastRouter = router; m_LastReplyTunnel = replyTunnel; diff --git a/Streaming.cpp b/Streaming.cpp index 3f4f53e6..6caa2a0f 100644 --- a/Streaming.cpp +++ b/Streaming.cpp @@ -14,7 +14,7 @@ namespace i2p { namespace stream { - Stream::Stream (StreamingDestination * local, const i2p::data::LeaseSet * remote): + Stream::Stream (StreamingDestination * local, const i2p::data::LeaseSet& remote): m_SendStreamID (0), m_SequenceNumber (0), m_LastReceivedSequenceNumber (0), m_IsOpen (false), m_LocalDestination (local), m_RemoteLeaseSet (remote), m_OutboundTunnel (nullptr) { @@ -172,7 +172,7 @@ namespace stream if (!m_OutboundTunnel) m_OutboundTunnel = i2p::tunnel::tunnels.GetNextOutboundTunnel (); - auto leases = m_RemoteLeaseSet->GetNonExpiredLeases (); + auto leases = m_RemoteLeaseSet.GetNonExpiredLeases (); if (m_OutboundTunnel && !leases.empty ()) { auto& lease = *leases.begin (); // TODO: @@ -206,7 +206,7 @@ namespace stream CreateDataMessage (this, packet, size)); if (m_OutboundTunnel) { - auto leases = m_RemoteLeaseSet->GetNonExpiredLeases (); + auto leases = m_RemoteLeaseSet.GetNonExpiredLeases (); if (!leases.empty ()) { auto& lease = *leases.begin (); // TODO: @@ -252,7 +252,7 @@ namespace stream I2NPMessage * msg = i2p::garlic::routing.WrapSingleMessage (m_RemoteLeaseSet, CreateDataMessage (this, packet, size)); - auto leases = m_RemoteLeaseSet->GetNonExpiredLeases (); + auto leases = m_RemoteLeaseSet.GetNonExpiredLeases (); if (m_OutboundTunnel && !leases.empty ()) { auto& lease = *leases.begin (); // TODO: @@ -329,7 +329,7 @@ namespace stream } } - Stream * StreamingDestination::CreateNewStream (const i2p::data::LeaseSet * remote) + Stream * StreamingDestination::CreateNewStream (const i2p::data::LeaseSet& remote) { Stream * s = new Stream (this, remote); m_Streams[s->GetRecvStreamID ()] = s; @@ -399,7 +399,7 @@ namespace stream signer.SignMessage (i2p::context.GetRandomNumberGenerator (), buf, len, signature); } - Stream * CreateStream (const i2p::data::LeaseSet * remote) + Stream * CreateStream (const i2p::data::LeaseSet& remote) { if (!sharedLocalDestination) sharedLocalDestination = new StreamingDestination (); diff --git a/Streaming.h b/Streaming.h index 18d09b5d..4e33d111 100644 --- a/Streaming.h +++ b/Streaming.h @@ -65,11 +65,11 @@ namespace stream { public: - Stream (StreamingDestination * local, const i2p::data::LeaseSet * remote); + Stream (StreamingDestination * local, const i2p::data::LeaseSet& remote); ~Stream (); uint32_t GetSendStreamID () const { return m_SendStreamID; }; uint32_t GetRecvStreamID () const { return m_RecvStreamID; }; - const i2p::data::LeaseSet * GetRemoteLeaseSet () const { return m_RemoteLeaseSet; }; + const i2p::data::LeaseSet& GetRemoteLeaseSet () const { return m_RemoteLeaseSet; }; bool IsOpen () const { return m_IsOpen; }; bool IsEstablished () const { return m_SendStreamID; }; @@ -91,7 +91,7 @@ namespace stream uint32_t m_SendStreamID, m_RecvStreamID, m_SequenceNumber, m_LastReceivedSequenceNumber; bool m_IsOpen; StreamingDestination * m_LocalDestination; - const i2p::data::LeaseSet * m_RemoteLeaseSet; + const i2p::data::LeaseSet& m_RemoteLeaseSet; i2p::util::Queue m_ReceiveQueue; std::set m_SavedPackets; i2p::tunnel::OutboundTunnel * m_OutboundTunnel; @@ -109,7 +109,7 @@ namespace stream I2NPMessage * GetLeaseSet (); void Sign (uint8_t * buf, int len, uint8_t * signature) const; - Stream * CreateNewStream (const i2p::data::LeaseSet * remote); + Stream * CreateNewStream (const i2p::data::LeaseSet& remote); void DeleteStream (Stream * stream); void HandleNextPacket (Packet * packet); @@ -129,7 +129,7 @@ namespace stream CryptoPP::DSA::PrivateKey m_SigningPrivateKey; }; - Stream * CreateStream (const i2p::data::LeaseSet * remote); + Stream * CreateStream (const i2p::data::LeaseSet& remote); void DeleteStream (Stream * stream); // assuming data is I2CP message From 3c8f859169cb3c51807a814ae2e336c2ae124c5b Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 20 Feb 2014 20:28:41 -0500 Subject: [PATCH 27/43] replaced ElGamalEncrypt to ElGamalEncryption --- ElGamal.h | 32 ++++---------------------------- Garlic.cpp | 5 ++--- Garlic.h | 2 -- I2NPProtocol.cpp | 2 +- Identity.h | 16 ++++++++++++++++ 5 files changed, 23 insertions(+), 34 deletions(-) diff --git a/ElGamal.h b/ElGamal.h index 745c3840..b3f0e44f 100644 --- a/ElGamal.h +++ b/ElGamal.h @@ -17,14 +17,13 @@ namespace crypto { public: - ElGamalEncryption (const uint8_t * key, bool zeroPadding = false): + ElGamalEncryption (const uint8_t * key): y (key, 256), k (rnd, CryptoPP::Integer::One(), elgp-1), - a (a_exp_b_mod_c (elgg, k, elgp)), b1 (a_exp_b_mod_c (y, k, elgp)), - m_ZeroPadding (zeroPadding) + a (a_exp_b_mod_c (elgg, k, elgp)), b1 (a_exp_b_mod_c (y, k, elgp)) { } - void Encrypt (const uint8_t * data, int len, uint8_t * encrypted) + void Encrypt (const uint8_t * data, int len, uint8_t * encrypted, bool zeroPadding = false) { // calculate b = b1*m mod p uint8_t m[255]; @@ -34,7 +33,7 @@ namespace crypto CryptoPP::Integer b (a_times_b_mod_c (b1, CryptoPP::Integer (m, 255), elgp)); // copy a and b - if (m_ZeroPadding) + if (zeroPadding) { encrypted[0] = 0; a.Encode (encrypted + 1, 256); @@ -72,29 +71,6 @@ namespace crypto memcpy (data, m + 33, 222); return true; } - - -// deprecated - - inline void ElGamalEncrypt (const uint8_t * key, const uint8_t * data, int len, - uint8_t * encrypted, bool zeroPadding = false) // 514 with padding and 512 without - { - CryptoPP::AutoSeededRandomPool rnd; - CryptoPP::Integer y(key, 256), k(rnd, CryptoPP::Integer::One(), elgp-1); - - if (zeroPadding) - { - encrypted[0] = 0; - encrypted[257] = 0; - } - a_exp_b_mod_c (elgg, k, elgp).Encode (zeroPadding ? encrypted + 1 : encrypted, 256); - uint8_t m[255]; - m[0] = 0xFF; - memcpy (m+33, data, len); - CryptoPP::SHA256().CalculateDigest(m+1, m+33, 222); - a_times_b_mod_c (a_exp_b_mod_c (y, k, elgp), - CryptoPP::Integer (m, 255), elgp).Encode (zeroPadding ? encrypted + 258 : encrypted + 256, 256); - } } } diff --git a/Garlic.cpp b/Garlic.cpp index 80a267c7..e73a6f02 100644 --- a/Garlic.cpp +++ b/Garlic.cpp @@ -15,8 +15,7 @@ namespace garlic { GarlicRoutingSession::GarlicRoutingSession (const i2p::data::RoutingDestination& destination, int numTags): m_Destination (destination), m_FirstMsgID (0), m_IsAcknowledged (false), - m_NumTags (numTags), m_NextTag (-1), m_SessionTags (0), - m_ElGamalEncryption (m_Destination.GetEncryptionPublicKey (), true) + m_NumTags (numTags), m_NextTag (-1), m_SessionTags (0) { // create new session tags and session key m_Rnd.GenerateBlock (m_SessionKey, 32); @@ -56,7 +55,7 @@ namespace garlic m_Rnd.GenerateBlock (elGamal.preIV, 32); // Pre-IV uint8_t iv[32]; // IV is first 16 bytes CryptoPP::SHA256().CalculateDigest(iv, elGamal.preIV, 32); - m_ElGamalEncryption.Encrypt ((uint8_t *)&elGamal, sizeof(elGamal), buf); + m_Destination.GetElGamalEncryption ()->Encrypt ((uint8_t *)&elGamal, sizeof(elGamal), buf, true); m_Encryption.SetKeyWithIV (m_SessionKey, 32, iv); buf += 514; len += 514; diff --git a/Garlic.h b/Garlic.h index ca6bae64..0383b030 100644 --- a/Garlic.h +++ b/Garlic.h @@ -9,7 +9,6 @@ #include #include "I2NPProtocol.h" #include "LeaseSet.h" -#include "ElGamal.h" namespace i2p { @@ -66,7 +65,6 @@ namespace garlic uint8_t * m_SessionTags; // m_NumTags*32 bytes CryptoPP::CBC_Mode::Encryption m_Encryption; - i2p::crypto::ElGamalEncryption m_ElGamalEncryption; CryptoPP::AutoSeededRandomPool m_Rnd; }; diff --git a/I2NPProtocol.cpp b/I2NPProtocol.cpp index f42d9f9d..25549a09 100644 --- a/I2NPProtocol.cpp +++ b/I2NPProtocol.cpp @@ -212,7 +212,7 @@ namespace i2p const I2NPBuildRequestRecordClearText& clearText, I2NPBuildRequestRecordElGamalEncrypted& record) { - i2p::crypto::ElGamalEncrypt (router.GetRouterIdentity ().publicKey, (uint8_t *)&clearText, sizeof(clearText), record.encrypted); + router.GetElGamalEncryption ()->Encrypt ((uint8_t *)&clearText, sizeof(clearText), record.encrypted); memcpy (record.toPeer, (const uint8_t *)router.GetIdentHash (), 16); } diff --git a/Identity.h b/Identity.h index e17b27be..10af227c 100644 --- a/Identity.h +++ b/Identity.h @@ -3,6 +3,7 @@ #include #include +#include "ElGamal.h" namespace i2p { @@ -84,9 +85,24 @@ namespace data class RoutingDestination { public: + + RoutingDestination (): m_ElGamalEncryption (nullptr) {}; + virtual ~RoutingDestination () { delete m_ElGamalEncryption; }; + virtual const IdentHash& GetIdentHash () const = 0; virtual const uint8_t * GetEncryptionPublicKey () const = 0; virtual bool IsDestination () const = 0; // for garlic + + i2p::crypto::ElGamalEncryption * GetElGamalEncryption () const + { + if (!m_ElGamalEncryption) + m_ElGamalEncryption = new i2p::crypto::ElGamalEncryption (GetEncryptionPublicKey ()); + return m_ElGamalEncryption; + } + + private: + + mutable i2p::crypto::ElGamalEncryption * m_ElGamalEncryption; // use lazy initialization }; } } From 64aa588a9b01ca4b08ad7bcdb9f800db9448cb5e Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 21 Feb 2014 16:13:36 -0500 Subject: [PATCH 28/43] establish SSU session through relay --- RouterInfo.cpp | 7 +++ RouterInfo.h | 1 + SSU.cpp | 134 +++++++++++++++++++++++++++++++++++++++++++++---- SSU.h | 10 +++- 4 files changed, 141 insertions(+), 11 deletions(-) diff --git a/RouterInfo.cpp b/RouterInfo.cpp index 337ae7b3..24ca7bb9 100644 --- a/RouterInfo.cpp +++ b/RouterInfo.cpp @@ -323,6 +323,13 @@ namespace data else return m_SupportedTransports & (eSSUV4 | eSSUV6); } + + bool RouterInfo::UsesIntroducer () const + { + if (!IsSSU ()) return false; + auto address = GetSSUAddress (true); // no introducers for v6 + return address && !address->introducers.empty (); + } const RouterInfo::Address * RouterInfo::GetNTCPAddress (bool v4only) const { diff --git a/RouterInfo.h b/RouterInfo.h index be3d59a2..990a0db3 100644 --- a/RouterInfo.h +++ b/RouterInfo.h @@ -75,6 +75,7 @@ namespace data bool IsNTCP (bool v4only = true) const; bool IsSSU (bool v4only = true) const; bool IsCompatible (const RouterInfo& other) const { return m_SupportedTransports & other.m_SupportedTransports; }; + bool UsesIntroducer () const; void SetUnreachable (bool unreachable) { m_IsUnreachable = unreachable; }; bool IsUnreachable () const { return m_IsUnreachable; }; diff --git a/SSU.cpp b/SSU.cpp index edac2704..4417733b 100644 --- a/SSU.cpp +++ b/SSU.cpp @@ -65,6 +65,15 @@ namespace ssu // session confirmed ProcessSessionConfirmed (buf, len); break; + case eSessionRelayRequestSent: + // relay response + ProcessRelayResponse (buf,len); + break; + case eSessionRelayRequestReceived: + // HolePunch + m_State = eSessionStateUnknown; + Connect (); + break; default: LogPrint ("SSU state not implemented yet"); } @@ -91,8 +100,12 @@ namespace ssu LogPrint ("SSU session destroy received"); if (m_Server) m_Server->DeleteSession (this); // delete this - } - break; + break; + } + case PAYLOAD_TYPE_RELAY_INTRO: + LogPrint ("SSU relay intro received"); + // TODO: + break; default: LogPrint ("Unexpected SSU payload type ", (int)payloadType); } @@ -197,6 +210,37 @@ namespace ssu m_Server->Send (buf, 304, m_RemoteEndpoint); } + void SSUSession::SendRelayRequest (const i2p::data::RouterInfo::Introducer& introducer) + { + auto address = i2p::context.GetRouterInfo ().GetSSUAddress (); + if (!address) + { + LogPrint ("SSU is not supported"); + return; + } + + uint8_t buf[96 + 18]; + uint8_t * payload = buf + sizeof (SSUHeader); + *(uint32_t *)payload = htobe32 (introducer.iTag); + payload += 4; + *payload = 0; // no address + payload++; + *(uint16_t *)payload = 0; // port = 0 + payload += 2; + *payload = 0; // challenge + payload++; + memcpy (payload, address->key, 32); + payload += 32; + CryptoPP::RandomNumberGenerator& rnd = i2p::context.GetRandomNumberGenerator (); + *(uint32_t *)payload = htobe32 (rnd.GenerateWord32 ()); // nonce + + uint8_t iv[16]; + rnd.GenerateBlock (iv, 16); // random iv + FillHeaderAndEncrypt (PAYLOAD_TYPE_RELAY_REQUEST, buf, 96, introducer.iKey, iv, introducer.iKey); + m_State = eSessionRelayRequestSent; + m_Server->Send (buf, 96, m_RemoteEndpoint); + } + void SSUSession::SendSessionCreated (const uint8_t * x) { auto introKey = GetIntroKey (); @@ -282,6 +326,46 @@ namespace ssu m_Server->Send (buf, 480, m_RemoteEndpoint); } + void SSUSession::ProcessRelayResponse (uint8_t * buf, size_t len) + { + LogPrint ("Process relay response"); + auto address = i2p::context.GetRouterInfo ().GetSSUAddress (); + if (!address) + { + LogPrint ("SSU is not supported"); + return; + } + + if (Validate (buf, len, address->key)) + { + Decrypt (buf, len, address->key); + SSUHeader * header = (SSUHeader *)buf; + if ((header->flag >> 4) == PAYLOAD_TYPE_RELAY_RESPONSE) + { + LogPrint ("Relay response received"); + m_State = eSessionRelayRequestReceived; + uint8_t * payload = buf + sizeof (SSUHeader); + payload++; + boost::asio::ip::address_v4 remoteIP (be32toh (*(uint32_t* )(payload))); + payload += 4; + uint16_t remotePort = be16toh (*(uint16_t *)(payload)); + payload += 2; + boost::asio::ip::udp::endpoint newRemoteEndpoint(remoteIP, remotePort); + m_Server->ReassignSession (m_RemoteEndpoint, newRemoteEndpoint); + m_RemoteEndpoint = newRemoteEndpoint; + payload++; + boost::asio::ip::address_v4 ourIP (be32toh (*(uint32_t* )(payload))); + payload += 4; + uint16_t ourPort = be16toh (*(uint16_t *)(payload)); + payload += 2; + LogPrint ("Our external address is ", ourIP.to_string (), ":", ourPort); + i2p::context.UpdateAddress (ourIP.to_string ().c_str ()); + } + else + LogPrint ("Unexpected payload type ", (int)(header->flag >> 4)); + } + } + bool SSUSession::ProcessIntroKeyEncryptedMessage (uint8_t expectedPayloadType, uint8_t * buf, size_t len) { auto introKey = GetIntroKey (); @@ -301,7 +385,7 @@ namespace ssu LogPrint ("Unexpected payload type ", (int)(header->flag >> 4)); } else - LogPrint ("MAC verifcation failed"); + LogPrint ("MAC verification failed"); } else LogPrint ("SSU is not supported"); @@ -368,6 +452,11 @@ namespace ssu SendSessionRequest (); } + void SSUSession::ConnectThroughIntroducer (const i2p::data::RouterInfo::Introducer& introducer) + { + SendRelayRequest (introducer); + } + void SSUSession::Close () { SendSesionDestroyed (); @@ -677,12 +766,27 @@ namespace ssu session = it->second; else { - // otherwise create new session - session = new SSUSession (this, remoteEndpoint, router); - m_Sessions[remoteEndpoint] = session; - LogPrint ("New SSU session to [", router->GetIdentHashAbbreviation (), "] ", - remoteEndpoint.address ().to_string (), ":", remoteEndpoint.port (), " created"); - session->Connect (); + // otherwise create new session + if (!router->UsesIntroducer ()) + { + // connect directly + session = new SSUSession (this, remoteEndpoint, router); + m_Sessions[remoteEndpoint] = session; + LogPrint ("New SSU session to [", router->GetIdentHashAbbreviation (), "] ", + remoteEndpoint.address ().to_string (), ":", remoteEndpoint.port (), " created"); + session->Connect (); + } + else + { + // connect to introducer + auto& introducer = address->introducers[0]; // TODO: + boost::asio::ip::udp::endpoint introducerEndpoint (introducer.iHost, introducer.iPort); + session = new SSUSession (this, introducerEndpoint, router); + m_Sessions[introducerEndpoint] = session; + LogPrint ("New SSU session to [", router->GetIdentHashAbbreviation (), + "] created through introducer ", introducerEndpoint.address ().to_string (), ":", introducerEndpoint.port ()); + session->ConnectThroughIntroducer (introducer); + } } } else @@ -709,6 +813,18 @@ namespace ssu delete it.second; } m_Sessions.clear (); + } + + void SSUServer::ReassignSession (const boost::asio::ip::udp::endpoint& oldEndpoint, const boost::asio::ip::udp::endpoint& newEndpoint) + { + auto it = m_Sessions.find (oldEndpoint); + if (it != m_Sessions.end ()) + { + m_Sessions.erase (it); + m_Sessions[newEndpoint] = it->second; + LogPrint ("SSU session ressigned from ", oldEndpoint.address ().to_string (), ":", oldEndpoint.port (), + " to ", newEndpoint.address ().to_string (), ":", newEndpoint.port ()); + } } } } diff --git a/SSU.h b/SSU.h index fccd6a8f..f5efc862 100644 --- a/SSU.h +++ b/SSU.h @@ -55,6 +55,8 @@ namespace ssu eSessionStateCreatedReceived, eSessionStateConfirmedSent, eSessionStateConfirmedReceived, + eSessionRelayRequestSent, + eSessionRelayRequestReceived, eSessionStateEstablished }; @@ -68,6 +70,7 @@ namespace ssu void ProcessNextMessage (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint); void Connect (); + void ConnectThroughIntroducer (const i2p::data::RouterInfo::Introducer& introducer); void Close (); boost::asio::ip::udp::endpoint& GetRemoteEndpoint () { return m_RemoteEndpoint; }; void SendI2NPMessage (I2NPMessage * msg); @@ -79,10 +82,12 @@ namespace ssu void ProcessMessage (uint8_t * buf, size_t len); // call for established session void ProcessSessionRequest (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint); void SendSessionRequest (); + void SendRelayRequest (const i2p::data::RouterInfo::Introducer& introducer); void ProcessSessionCreated (uint8_t * buf, size_t len); void SendSessionCreated (const uint8_t * x); void ProcessSessionConfirmed (uint8_t * buf, size_t len); void SendSessionConfirmed (const uint8_t * y, const uint8_t * ourAddress, uint32_t relayTag); + void ProcessRelayResponse (uint8_t * buf, size_t len); void Established (); void ProcessData (uint8_t * buf, size_t len); void SendMsgAck (uint32_t msgID); @@ -118,10 +123,11 @@ namespace ssu void Stop (); SSUSession * GetSession (const i2p::data::RouterInfo * router); void DeleteSession (SSUSession * session); - void DeleteAllSessions (); - + void DeleteAllSessions (); + const boost::asio::ip::udp::endpoint& GetEndpoint () const { return m_Endpoint; }; void Send (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& to); + void ReassignSession (const boost::asio::ip::udp::endpoint& oldEndpoint, const boost::asio::ip::udp::endpoint& newEndpoint); private: From 662e4161b0c4da1573dd888b4dcf1daacad25aaf Mon Sep 17 00:00:00 2001 From: Meeh Date: Sat, 22 Feb 2014 00:21:30 +0100 Subject: [PATCH 29/43] Save/Load router.info/router.key from data directory --- RouterContext.cpp | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/RouterContext.cpp b/RouterContext.cpp index 1d3d2c02..9b78e3e4 100644 --- a/RouterContext.cpp +++ b/RouterContext.cpp @@ -68,24 +68,46 @@ namespace i2p bool RouterContext::Load () { - std::ifstream fk (ROUTER_KEYS, std::ifstream::binary | std::ofstream::in); + std::string dataDir = i2p::util::filesystem::GetDataDir ().string (); +#ifndef _WIN32 + dataDir.append ("/"); +#else + dataDir.append ("\\"); +#endif + std::string router_keys = dataDir; + router_keys.append (ROUTER_KEYS); + std::string router_info = dataDir; + router_info.append (ROUTER_INFO); + + std::ifstream fk (router_keys.c_str (), std::ifstream::binary | std::ofstream::in); if (!fk.is_open ()) return false; fk.read ((char *)&m_Keys, sizeof (m_Keys)); m_SigningPrivateKey.Initialize (i2p::crypto::dsap, i2p::crypto::dsaq, i2p::crypto::dsag, CryptoPP::Integer (m_Keys.signingPrivateKey, 20)); - m_RouterInfo = i2p::data::RouterInfo (ROUTER_INFO); // TODO + m_RouterInfo = i2p::data::RouterInfo (router_info.c_str ()); // TODO return true; } void RouterContext::Save () { - std::ofstream fk (ROUTER_KEYS, std::ofstream::binary | std::ofstream::out); + std::string dataDir = i2p::util::filesystem::GetDataDir ().string (); +#ifndef _WIN32 + dataDir.append ("/"); +#else + dataDir.append ("\\"); +#endif + std::string router_keys = dataDir; + router_keys.append (ROUTER_KEYS); + std::string router_info = dataDir; + router_info.append (ROUTER_INFO); + + std::ofstream fk (router_keys.c_str (), std::ofstream::binary | std::ofstream::out); fk.write ((char *)&m_Keys, sizeof (m_Keys)); - std::ofstream fi (ROUTER_INFO, std::ofstream::binary | std::ofstream::out); + std::ofstream fi (router_info.c_str (), std::ofstream::binary | std::ofstream::out); fi.write ((char *)m_RouterInfo.GetBuffer (), m_RouterInfo.GetBufferLen ()); } } From a73014a629a37559b0cb85c19d18e988adfd76d5 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 23 Feb 2014 11:48:09 -0500 Subject: [PATCH 30/43] create SSU address --- RouterContext.cpp | 23 ++++++++++++++++------- RouterContext.h | 3 ++- RouterInfo.cpp | 23 ++++++++++++++++++++++- RouterInfo.h | 1 + 4 files changed, 41 insertions(+), 9 deletions(-) diff --git a/RouterContext.cpp b/RouterContext.cpp index 9b78e3e4..2b8c9c1d 100644 --- a/RouterContext.cpp +++ b/RouterContext.cpp @@ -25,11 +25,16 @@ namespace i2p m_Keys = i2p::data::CreateRandomKeys (); m_SigningPrivateKey.Initialize (i2p::crypto::dsap, i2p::crypto::dsaq, i2p::crypto::dsag, CryptoPP::Integer (m_Keys.signingPrivateKey, 20)); - + UpdateRouterInfo (); + } + + void RouterContext::UpdateRouterInfo () + { i2p::data::Identity ident; ident = m_Keys; m_RouterInfo.SetRouterIdentity (ident); + //m_RouterInfo.AddSSUAddress ("127.0.0.1", 17007, m_RouterInfo.GetIdentHash ()); m_RouterInfo.AddNTCPAddress ("127.0.0.1", 17007); // TODO: m_RouterInfo.SetProperty ("caps", "LR"); m_RouterInfo.SetProperty ("coreVersion", "0.9.8.1"); @@ -38,8 +43,8 @@ namespace i2p m_RouterInfo.SetProperty ("start_uptime", "90m"); m_RouterInfo.CreateBuffer (); - } - + } + void RouterContext::OverrideNTCPAddress (const char * host, int port) { m_RouterInfo.CreateBuffer (); @@ -51,6 +56,7 @@ namespace i2p } m_RouterInfo.CreateBuffer (); + Save (true); } void RouterContext::UpdateAddress (const char * host) @@ -91,7 +97,7 @@ namespace i2p return true; } - void RouterContext::Save () + void RouterContext::Save (bool infoOnly) { std::string dataDir = i2p::util::filesystem::GetDataDir ().string (); #ifndef _WIN32 @@ -104,9 +110,12 @@ namespace i2p std::string router_info = dataDir; router_info.append (ROUTER_INFO); - std::ofstream fk (router_keys.c_str (), std::ofstream::binary | std::ofstream::out); - fk.write ((char *)&m_Keys, sizeof (m_Keys)); - + if (!infoOnly) + { + std::ofstream fk (router_keys.c_str (), std::ofstream::binary | std::ofstream::out); + fk.write ((char *)&m_Keys, sizeof (m_Keys)); + } + std::ofstream fi (router_info.c_str (), std::ofstream::binary | std::ofstream::out); fi.write ((char *)m_RouterInfo.GetBuffer (), m_RouterInfo.GetBufferLen ()); } diff --git a/RouterContext.h b/RouterContext.h index 0cbd0bc7..092c50b5 100644 --- a/RouterContext.h +++ b/RouterContext.h @@ -33,8 +33,9 @@ namespace i2p private: void CreateNewRouter (); + void UpdateRouterInfo (); bool Load (); - void Save (); + void Save (bool infoOnly = false); private: diff --git a/RouterInfo.cpp b/RouterInfo.cpp index 24ca7bb9..ae5e03e3 100644 --- a/RouterInfo.cpp +++ b/RouterInfo.cpp @@ -208,14 +208,23 @@ namespace data { s.write ((char *)&address.cost, sizeof (address.cost)); s.write ((char *)&address.date, sizeof (address.date)); + std::stringstream properties; if (address.transportStyle == eTransportNTCP) WriteString ("NTCP", s); else if (address.transportStyle == eTransportSSU) + { WriteString ("SSU", s); + // wtite intro key + WriteString ("key", properties); + properties << '='; + char value[64]; + ByteStreamToBase64 (address.key, 32, value, 64); + WriteString (value, properties); + properties << ';'; + } else WriteString ("", s); - std::stringstream properties; WriteString ("host", properties); properties << '='; WriteString (address.host.to_string (), properties); @@ -287,6 +296,18 @@ namespace data m_Addresses.push_back(addr); } + void RouterInfo::AddSSUAddress (const char * host, int port, const uint8_t * key) + { + Address addr; + addr.host = boost::asio::ip::address::from_string (host); + addr.port = port; + addr.transportStyle = eTransportSSU; + addr.cost = 10; // NTCP should have prioprity over SSU + addr.date = 0; + memcpy (addr.key, key, 32); + m_Addresses.push_back(addr); + } + void RouterInfo::SetProperty (const char * key, const char * value) { m_Properties[key] = value; diff --git a/RouterInfo.h b/RouterInfo.h index 990a0db3..52a8d9e9 100644 --- a/RouterInfo.h +++ b/RouterInfo.h @@ -69,6 +69,7 @@ namespace data const RoutingKey& GetRoutingKey () const { return m_RoutingKey; }; void AddNTCPAddress (const char * host, int port); + void AddSSUAddress (const char * host, int port, const uint8_t * key); void SetProperty (const char * key, const char * value); const char * GetProperty (const char * key) const; bool IsFloodfill () const; From 53230a405165b9025986d6fcee0cbfafef54d8e0 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 23 Feb 2014 20:48:28 -0500 Subject: [PATCH 31/43] fill caps for SSU --- RouterContext.cpp | 20 +++++++++++--------- RouterInfo.cpp | 21 +++++++++++++++------ 2 files changed, 26 insertions(+), 15 deletions(-) diff --git a/RouterContext.cpp b/RouterContext.cpp index 2b8c9c1d..6279ee21 100644 --- a/RouterContext.cpp +++ b/RouterContext.cpp @@ -32,17 +32,19 @@ namespace i2p { i2p::data::Identity ident; ident = m_Keys; - m_RouterInfo.SetRouterIdentity (ident); - //m_RouterInfo.AddSSUAddress ("127.0.0.1", 17007, m_RouterInfo.GetIdentHash ()); - m_RouterInfo.AddNTCPAddress ("127.0.0.1", 17007); // TODO: - m_RouterInfo.SetProperty ("caps", "LR"); - m_RouterInfo.SetProperty ("coreVersion", "0.9.8.1"); - m_RouterInfo.SetProperty ("netId", "2"); - m_RouterInfo.SetProperty ("router.version", "0.9.8.1"); - m_RouterInfo.SetProperty ("start_uptime", "90m"); + i2p::data::RouterInfo routerInfo; + routerInfo.SetRouterIdentity (ident); + //routerInfo.AddSSUAddress ("127.0.0.1", 17007, routerInfo.GetIdentHash ()); + routerInfo.AddNTCPAddress ("127.0.0.1", 17007); // TODO: + routerInfo.SetProperty ("caps", "LR"); + routerInfo.SetProperty ("coreVersion", "0.9.8.1"); + routerInfo.SetProperty ("netId", "2"); + routerInfo.SetProperty ("router.version", "0.9.8.1"); + routerInfo.SetProperty ("start_uptime", "90m"); + routerInfo.CreateBuffer (); - m_RouterInfo.CreateBuffer (); + m_RouterInfo = routerInfo; } void RouterContext::OverrideNTCPAddress (const char * host, int port) diff --git a/RouterInfo.cpp b/RouterInfo.cpp index ae5e03e3..cd97d89d 100644 --- a/RouterInfo.cpp +++ b/RouterInfo.cpp @@ -133,7 +133,7 @@ namespace data { // introducers size_t l = strlen(key); - unsigned char index = key[l-1]; // TODO: + unsigned char index = key[l-1] - '0'; // TODO: key[l-1] = 0; if (index >= address.introducers.size ()) address.introducers.resize (index + 1); @@ -214,12 +214,10 @@ namespace data else if (address.transportStyle == eTransportSSU) { WriteString ("SSU", s); - // wtite intro key - WriteString ("key", properties); + // caps + WriteString ("caps", properties); properties << '='; - char value[64]; - ByteStreamToBase64 (address.key, 32, value, 64); - WriteString (value, properties); + WriteString ("BC", properties); // TODO: properties << ';'; } else @@ -229,6 +227,17 @@ namespace data properties << '='; WriteString (address.host.to_string (), properties); properties << ';'; + if (address.transportStyle == eTransportSSU) + { + // wtite intro key + WriteString ("key", properties); + properties << '='; + char value[64]; + size_t l = ByteStreamToBase64 (address.key, 32, value, 64); + value[l] = 0; + WriteString (value, properties); + properties << ';'; + } WriteString ("port", properties); properties << '='; WriteString (boost::lexical_cast(address.port), properties); From b9031c331dff942776b512dcd48d1b7e051e149c Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 24 Feb 2014 15:16:39 -0500 Subject: [PATCH 32/43] send SSU DeliveryStatus --- I2NPProtocol.cpp | 13 +++++++++++-- RouterInfo.cpp | 2 +- SSU.cpp | 2 +- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/I2NPProtocol.cpp b/I2NPProtocol.cpp index 25549a09..9d7ccf18 100644 --- a/I2NPProtocol.cpp +++ b/I2NPProtocol.cpp @@ -70,8 +70,17 @@ namespace i2p I2NPMessage * CreateDeliveryStatusMsg (uint32_t msgID) { I2NPDeliveryStatusMsg msg; - msg.msgID = htobe32 (msgID); - msg.timestamp = htobe64 (i2p::util::GetMillisecondsSinceEpoch ()); + if (msgID) + { + msg.msgID = htobe32 (msgID); + msg.timestamp = htobe64 (i2p::util::GetMillisecondsSinceEpoch ()); + } + else // for SSU establishment + { + auto rnd = i2p::context.GetRandomNumberGenerator (); + msg.msgID = htobe32 (rnd.GenerateWord32 ()); + msg.timestamp = htobe64 (2); // netID = 2 + } return CreateI2NPMessage (eI2NPDeliveryStatus, (uint8_t *)&msg, sizeof (msg)); } diff --git a/RouterInfo.cpp b/RouterInfo.cpp index cd97d89d..88118e5e 100644 --- a/RouterInfo.cpp +++ b/RouterInfo.cpp @@ -217,7 +217,7 @@ namespace data // caps WriteString ("caps", properties); properties << '='; - WriteString ("BC", properties); // TODO: + WriteString ("B", properties); // TODO: should be 'BC' for introducers properties << ';'; } else diff --git a/SSU.cpp b/SSU.cpp index 4417733b..e713159b 100644 --- a/SSU.cpp +++ b/SSU.cpp @@ -176,7 +176,7 @@ namespace ssu m_State = eSessionStateConfirmedReceived; LogPrint ("Session confirmed received"); m_State = eSessionStateEstablished; - // TODO: send DeliverStatus + SendI2NPMessage (CreateDeliveryStatusMsg (0)); Established (); } else From adb6f284e8b332ee44bda8328bcea3c3c37bdec6 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 24 Feb 2014 19:25:26 -0500 Subject: [PATCH 33/43] enable SSU --- RouterContext.cpp | 2 +- RouterInfo.cpp | 2 ++ Transports.cpp | 9 +++------ 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/RouterContext.cpp b/RouterContext.cpp index 6279ee21..af88c84a 100644 --- a/RouterContext.cpp +++ b/RouterContext.cpp @@ -35,7 +35,7 @@ namespace i2p i2p::data::RouterInfo routerInfo; routerInfo.SetRouterIdentity (ident); - //routerInfo.AddSSUAddress ("127.0.0.1", 17007, routerInfo.GetIdentHash ()); + routerInfo.AddSSUAddress ("127.0.0.1", 17007, routerInfo.GetIdentHash ()); routerInfo.AddNTCPAddress ("127.0.0.1", 17007); // TODO: routerInfo.SetProperty ("caps", "LR"); routerInfo.SetProperty ("coreVersion", "0.9.8.1"); diff --git a/RouterInfo.cpp b/RouterInfo.cpp index 88118e5e..8740ef9d 100644 --- a/RouterInfo.cpp +++ b/RouterInfo.cpp @@ -303,6 +303,7 @@ namespace data addr.cost = 2; addr.date = 0; m_Addresses.push_back(addr); + m_SupportedTransports |= eNTCPV4; } void RouterInfo::AddSSUAddress (const char * host, int port, const uint8_t * key) @@ -315,6 +316,7 @@ namespace data addr.date = 0; memcpy (addr.key, key, 32); m_Addresses.push_back(addr); + m_SupportedTransports |= eSSUV4; } void RouterInfo::SetProperty (const char * key, const char * value) diff --git a/Transports.cpp b/Transports.cpp index cc56a86f..c0c0ea8f 100644 --- a/Transports.cpp +++ b/Transports.cpp @@ -39,23 +39,20 @@ namespace i2p auto conn = new i2p::ntcp::NTCPServerConnection (m_Service); m_NTCPAcceptor->async_accept(conn->GetSocket (), boost::bind (&Transports::HandleAccept, this, conn, boost::asio::placeholders::error)); - // temporary always run SSU server - // TODO: uncomment following lines later - /*} + } else if (address.transportStyle == RouterInfo::eTransportSSU) - {*/ + { if (!m_SSUServer) { m_SSUServer = new i2p::ssu::SSUServer (m_Service, address.port); LogPrint ("Start listening UDP port ", address.port); m_SSUServer->Start (); + DetectExternalIP (); } else LogPrint ("SSU server already exists"); } } - - //DetectExternalIP (); } void Transports::Stop () From 2ac36b1d31f92db0bac112d5c7919d344b773b71 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 24 Feb 2014 21:43:26 -0500 Subject: [PATCH 34/43] verify SessionCreated --- SSU.cpp | 42 ++++++++++++++++++++++++++++++++++-------- 1 file changed, 34 insertions(+), 8 deletions(-) diff --git a/SSU.cpp b/SSU.cpp index e713159b..26530125 100644 --- a/SSU.cpp +++ b/SSU.cpp @@ -154,13 +154,38 @@ namespace ssu { m_State = eSessionStateCreatedReceived; LogPrint ("Session created received"); - uint8_t * ourAddress = buf + sizeof (SSUHeader) + 257; - boost::asio::ip::address_v4 ourIP (be32toh (*(uint32_t* )(ourAddress))); - uint16_t ourPort = be16toh (*(uint16_t *)(ourAddress + 4)); + uint8_t signedData[532]; // x,y, our IP, our port, remote IP, remote port, relayTag, signed on time + uint8_t * payload = buf + sizeof (SSUHeader); + uint8_t * y = payload; + memcpy (signedData, i2p::context.GetRouterIdentity ().publicKey, 256); // x + memcpy (signedData + 256, y, 256); // y + payload += 256; + payload += 1; // size, assume 4 + uint8_t * ourAddress = payload; + boost::asio::ip::address_v4 ourIP (be32toh (*(uint32_t* )ourAddress)); + payload += 4; // address + uint16_t ourPort = be16toh (*(uint16_t *)payload); + payload += 2; // port + memcpy (signedData + 512, ourAddress, 6); // our IP and port LogPrint ("Our external address is ", ourIP.to_string (), ":", ourPort); i2p::context.UpdateAddress (ourIP.to_string ().c_str ()); - uint32_t relayTag = be32toh (*(uint32_t *)(buf + sizeof (SSUHeader) + 263)); - SendSessionConfirmed (buf + sizeof (SSUHeader), ourAddress, relayTag); + *(uint32_t *)(signedData + 518) = htobe32 (m_RemoteEndpoint.address ().to_v4 ().to_ulong ()); // remote IP + *(uint16_t *)(signedData + 522) = htobe16 (m_RemoteEndpoint.port ()); // remote port + memcpy (signedData + 524, payload, 8); // relayTag and signed on time + uint32_t relayTag = be32toh (*(uint32_t *)payload); + payload += 4; // relayTag + payload += 4; // signed on time + // decrypt DSA signature + m_Decryption.SetKeyWithIV (m_SessionKey, 32, ((SSUHeader *)buf)->iv); + m_Decryption.ProcessData (payload, payload, 48); + // verify + CryptoPP::DSA::PublicKey pubKey; + pubKey.Initialize (i2p::crypto::dsap, i2p::crypto::dsaq, i2p::crypto::dsag, CryptoPP::Integer (m_RemoteRouter->GetRouterIdentity ().signingKey, 128)); + CryptoPP::DSA::Verifier verifier (pubKey); + if (!verifier.VerifyMessage (signedData, 532, payload, 40)) + LogPrint ("SSU signature verification failed"); + + SendSessionConfirmed (y, ourAddress, relayTag); } } @@ -244,7 +269,8 @@ namespace ssu void SSUSession::SendSessionCreated (const uint8_t * x) { auto introKey = GetIntroKey (); - if (!introKey) + auto address = i2p::context.GetRouterInfo ().GetSSUAddress (); + if (!introKey || !address) { LogPrint ("SSU is not supported"); return; @@ -264,8 +290,8 @@ namespace ssu *(uint16_t *)(payload) = htobe16 (m_RemoteEndpoint.port ()); payload += 2; memcpy (signedData + 512, payload - 6, 6); // remote endpoint IP and port - *(uint32_t *)(signedData + 518) = htobe32 (m_Server->GetEndpoint ().address ().to_v4 ().to_ulong ()); // our IP - *(uint16_t *)(signedData + 522) = htobe16 (m_Server->GetEndpoint ().port ()); // our port + *(uint32_t *)(signedData + 518) = htobe32 (address->host.to_v4 ().to_ulong ()); // our IP + *(uint16_t *)(signedData + 522) = htobe16 (address->port); // our port *(uint32_t *)(payload) = 0; // relay tag, always 0 for now payload += 4; *(uint32_t *)(payload) = htobe32 (i2p::util::GetSecondsSinceEpoch ()); // signed on time From 303855f59a2b8ccbecf00a60a19354157e5af8e3 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 24 Feb 2014 22:28:28 -0500 Subject: [PATCH 35/43] show SSU sessions --- HTTPServer.cpp | 11 +++++++++++ SSU.h | 6 +++++- Transports.h | 1 + 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/HTTPServer.cpp b/HTTPServer.cpp index 833dca51..a27992ba 100644 --- a/HTTPServer.cpp +++ b/HTTPServer.cpp @@ -144,6 +144,7 @@ namespace util } s << "

Transports

"; + s << "NTCP
"; for (auto it: i2p::transports.GetNTCPSessions ()) { // RouterInfo of incoming connection doesn't have address @@ -157,6 +158,16 @@ namespace util s << "
"; } } + auto ssuServer = i2p::transports.GetSSUServer (); + if (ssuServer) + { + s << "
SSU
"; + for (auto it: ssuServer->GetSessions ()) + { + auto endpoint = it.second->GetRemoteEndpoint (); + s << endpoint.address ().to_string () << ":" << endpoint.port () << "
"; + } + } s << "

Flibusta

"; } diff --git a/SSU.h b/SSU.h index f5efc862..ff08f1f1 100644 --- a/SSU.h +++ b/SSU.h @@ -74,7 +74,7 @@ namespace ssu void Close (); boost::asio::ip::udp::endpoint& GetRemoteEndpoint () { return m_RemoteEndpoint; }; void SendI2NPMessage (I2NPMessage * msg); - + private: void CreateAESandMacKey (uint8_t * pubKey, uint8_t * aesKey, uint8_t * macKey); @@ -141,6 +141,10 @@ namespace ssu boost::asio::ip::udp::endpoint m_SenderEndpoint; uint8_t m_ReceiveBuffer[2*SSU_MTU]; std::map m_Sessions; + + public: + // for HTTP only + const decltype(m_Sessions)& GetSessions () const { return m_Sessions; }; }; } } diff --git a/Transports.h b/Transports.h index 12bd8f21..aedd51b2 100644 --- a/Transports.h +++ b/Transports.h @@ -58,6 +58,7 @@ namespace i2p // for HTTP only const decltype(m_NTCPSessions)& GetNTCPSessions () const { return m_NTCPSessions; }; + const i2p::ssu::SSUServer * GetSSUServer () const { return m_SSUServer; }; }; extern Transports transports; From 730079203383f40e5d4e22cc1ed933689cd96e9d Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 25 Feb 2014 20:37:39 -0500 Subject: [PATCH 36/43] set SessionCreated state --- I2NPProtocol.cpp | 3 +-- SSU.cpp | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/I2NPProtocol.cpp b/I2NPProtocol.cpp index 9d7ccf18..0e189218 100644 --- a/I2NPProtocol.cpp +++ b/I2NPProtocol.cpp @@ -77,8 +77,7 @@ namespace i2p } else // for SSU establishment { - auto rnd = i2p::context.GetRandomNumberGenerator (); - msg.msgID = htobe32 (rnd.GenerateWord32 ()); + msg.msgID = htobe32 (i2p::context.GetRandomNumberGenerator ().GenerateWord32 ()); msg.timestamp = htobe64 (2); // netID = 2 } return CreateI2NPMessage (eI2NPDeliveryStatus, (uint8_t *)&msg, sizeof (msg)); diff --git a/SSU.cpp b/SSU.cpp index 26530125..aed6b218 100644 --- a/SSU.cpp +++ b/SSU.cpp @@ -309,7 +309,7 @@ namespace ssu // encrypt message with intro key FillHeaderAndEncrypt (PAYLOAD_TYPE_SESSION_CREATED, buf, 368, introKey, iv, introKey); - m_State = eSessionStateRequestSent; + m_State = eSessionStateCreatedSent; m_Server->Send (buf, 368, m_RemoteEndpoint); } From 567816e6a5d6515959ecce6d97ac312454a964ef Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 26 Feb 2014 22:53:19 -0500 Subject: [PATCH 37/43] create tunnel through any type of transports --- RouterInfo.cpp | 3 +++ Tunnel.cpp | 11 ++++++----- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/RouterInfo.cpp b/RouterInfo.cpp index 8740ef9d..adae686c 100644 --- a/RouterInfo.cpp +++ b/RouterInfo.cpp @@ -180,6 +180,9 @@ namespace data CryptoPP::SHA256().CalculateDigest(m_IdentHash, (uint8_t *)&m_RouterIdentity, sizeof (m_RouterIdentity)); UpdateIdentHashBase64 (); UpdateRoutingKey (); + + if (!m_SupportedTransports) + SetUnreachable (true); } void RouterInfo::UpdateIdentHashBase64 () diff --git a/Tunnel.cpp b/Tunnel.cpp index 9d58c875..601586ae 100644 --- a/Tunnel.cpp +++ b/Tunnel.cpp @@ -389,7 +389,7 @@ namespace tunnel CreateTunnel ( new TunnelConfig (std::vector { - i2p::data::netdb.GetRandomNTCPRouter () + i2p::data::netdb.GetRandomRouter () }, inboundTunnel->GetTunnelConfig ())); } @@ -397,7 +397,7 @@ namespace tunnel { LogPrint ("Creating two hops outbound tunnel..."); - auto firstHop = i2p::data::netdb.GetRandomNTCPRouter (); // first hop must be NTCP + auto firstHop = i2p::data::netdb.GetRandomRouter (); CreateTunnel ( new TunnelConfig (std::vector { @@ -439,7 +439,7 @@ namespace tunnel CreateTunnel ( new TunnelConfig (std::vector { - i2p::data::netdb.GetRandomNTCPRouter () + i2p::data::netdb.GetRandomRouter () })); } else @@ -447,11 +447,12 @@ namespace tunnel OutboundTunnel * outboundTunnel = GetNextOutboundTunnel (); LogPrint ("Creating two hops inbound tunnel..."); auto router = outboundTunnel->GetTunnelConfig ()->GetFirstHop ()->router; + auto firstHop = i2p::data::netdb.GetRandomRouter (outboundTunnel->GetEndpointRouter ()); CreateTunnel ( new TunnelConfig (std::vector { - i2p::data::netdb.GetRandomRouter (outboundTunnel->GetEndpointRouter ()), - router != &i2p::context.GetRouterInfo () ? router : i2p::data::netdb.GetRandomNTCPRouter () // last hop must be NTCP + firstHop, + router != &i2p::context.GetRouterInfo () ? router : i2p::data::netdb.GetRandomRouter (firstHop) }), outboundTunnel); } From 48737864a3d2de7f7ea96203bab787098bac9bb6 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 28 Feb 2014 21:28:05 -0500 Subject: [PATCH 38/43] process HolePunch --- SSU.cpp | 6 ++++++ SSU.h | 1 + 2 files changed, 7 insertions(+) diff --git a/SSU.cpp b/SSU.cpp index aed6b218..ea4d4de1 100644 --- a/SSU.cpp +++ b/SSU.cpp @@ -69,6 +69,11 @@ namespace ssu // relay response ProcessRelayResponse (buf,len); break; + case eSessionRelayResponseReceived: + // HolePunch received + LogPrint ("SSU HolePuch of ", len, " bytes received"); + Established (); + break; case eSessionRelayRequestReceived: // HolePunch m_State = eSessionStateUnknown; @@ -386,6 +391,7 @@ namespace ssu payload += 2; LogPrint ("Our external address is ", ourIP.to_string (), ":", ourPort); i2p::context.UpdateAddress (ourIP.to_string ().c_str ()); + m_State= eSessionRelayResponseReceived; } else LogPrint ("Unexpected payload type ", (int)(header->flag >> 4)); diff --git a/SSU.h b/SSU.h index ff08f1f1..0976fc80 100644 --- a/SSU.h +++ b/SSU.h @@ -57,6 +57,7 @@ namespace ssu eSessionStateConfirmedReceived, eSessionRelayRequestSent, eSessionRelayRequestReceived, + eSessionRelayResponseReceived, eSessionStateEstablished }; From 5dfe19c6ed5ff44769e68741d8c6fc4edc21f2a3 Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 1 Mar 2014 11:56:28 -0500 Subject: [PATCH 39/43] set established state after hole punch --- SSU.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/SSU.cpp b/SSU.cpp index ea4d4de1..9eb5cb7c 100644 --- a/SSU.cpp +++ b/SSU.cpp @@ -72,6 +72,7 @@ namespace ssu case eSessionRelayResponseReceived: // HolePunch received LogPrint ("SSU HolePuch of ", len, " bytes received"); + m_State = eSessionStateEstablished; Established (); break; case eSessionRelayRequestReceived: From 695f1949eb6abe32ce79cb38dfec6b2e89bf9fcc Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 12 Mar 2014 07:21:58 -0400 Subject: [PATCH 40/43] don't call mapArgs from GetDataDir because it's not initialized yet --- util.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/util.cpp b/util.cpp index 1917a984..262b6e25 100644 --- a/util.cpp +++ b/util.cpp @@ -99,11 +99,12 @@ namespace filesystem { static boost::filesystem::path path; - if (i2p::util::config::mapArgs.count("-datadir")) { + // TODO: datadir parameter is useless because GetDataDir is called before OptionParser + // and mapArgs is not initialized yet + /*if (i2p::util::config::mapArgs.count("-datadir")) path = boost::filesystem::system_complete(i2p::util::config::mapArgs["-datadir"]); - } else { + else */ path = GetDefaultDataDir(); - } if (!boost::filesystem::exists( path )) { @@ -115,9 +116,8 @@ namespace filesystem return path; } } - if (!boost::filesystem::is_directory(path)) { + if (!boost::filesystem::is_directory(path)) path = GetDefaultDataDir(); - } return path; } From 27c7ea28012692b3eedba6785508a23637be1ed5 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 12 Mar 2014 07:37:43 -0400 Subject: [PATCH 41/43] print direction of SSU session --- HTTPServer.cpp | 7 ++++++- SSU.h | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/HTTPServer.cpp b/HTTPServer.cpp index a27992ba..d71deb3c 100644 --- a/HTTPServer.cpp +++ b/HTTPServer.cpp @@ -164,8 +164,13 @@ namespace util s << "
SSU
"; for (auto it: ssuServer->GetSessions ()) { + // incoming connections don't have remote router + bool outgoing = it.second->GetRemoteRouter (); auto endpoint = it.second->GetRemoteEndpoint (); - s << endpoint.address ().to_string () << ":" << endpoint.port () << "
"; + if (outgoing) s << "-->"; + s << endpoint.address ().to_string () << ":" << endpoint.port (); + if (!outgoing) s << "-->"; + s << "
"; } } s << "

Flibusta

"; diff --git a/SSU.h b/SSU.h index 0976fc80..c61d09bb 100644 --- a/SSU.h +++ b/SSU.h @@ -74,6 +74,7 @@ namespace ssu void ConnectThroughIntroducer (const i2p::data::RouterInfo::Introducer& introducer); void Close (); boost::asio::ip::udp::endpoint& GetRemoteEndpoint () { return m_RemoteEndpoint; }; + const i2p::data::RouterInfo * GetRemoteRouter () const { return m_RemoteRouter; }; void SendI2NPMessage (I2NPMessage * msg); private: From 6732ba21f92e973f2c7a1a1f2a7c90a20fbd580e Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 12 Mar 2014 20:13:49 -0400 Subject: [PATCH 42/43] inbound tunnel where an I2NP messages has been received from --- Garlic.cpp | 9 +++++---- Garlic.h | 3 ++- I2NPProtocol.cpp | 18 +++++++++--------- I2NPProtocol.h | 11 +++++++++-- NTCPSession.cpp | 2 +- NetDb.cpp | 2 +- SSU.cpp | 2 +- Transports.cpp | 2 +- Tunnel.cpp | 1 + TunnelEndpoint.cpp | 2 +- 10 files changed, 31 insertions(+), 21 deletions(-) diff --git a/Garlic.cpp b/Garlic.cpp index e73a6f02..a269daa5 100644 --- a/Garlic.cpp +++ b/Garlic.cpp @@ -262,8 +262,9 @@ namespace garlic return ret; } - void GarlicRouting::HandleGarlicMessage (uint8_t * buf, size_t len, bool isFromTunnel) + void GarlicRouting::HandleGarlicMessage (I2NPMessage * msg) { + uint8_t * buf = msg->GetPayload (); uint32_t length = be32toh (*(uint32_t *)buf); buf += 4; std::string sessionTag((const char *)buf, 32); @@ -284,7 +285,7 @@ namespace garlic // new session ElGamalBlock elGamal; if (i2p::crypto::ElGamalDecrypt ( - isFromTunnel ? i2p::context.GetLeaseSetPrivateKey () : i2p::context.GetPrivateKey (), + msg->from ? i2p::context.GetLeaseSetPrivateKey () : i2p::context.GetPrivateKey (), buf, (uint8_t *)&elGamal, true)) { uint8_t iv[32]; // IV is first 16 bytes @@ -296,7 +297,7 @@ namespace garlic else LogPrint ("Failed to decrypt garlic"); } - + DeleteI2NPMessage (msg); } void GarlicRouting::HandleAESBlock (uint8_t * buf, size_t len, uint8_t * sessionKey) @@ -351,7 +352,7 @@ namespace garlic { case eGarlicDeliveryTypeLocal: LogPrint ("Garlic type local"); - i2p::HandleI2NPMessage (buf, len, false); + i2p::HandleI2NPMessage (buf, len); break; case eGarlicDeliveryTypeDestination: { diff --git a/Garlic.h b/Garlic.h index 0383b030..a31b14cf 100644 --- a/Garlic.h +++ b/Garlic.h @@ -9,6 +9,7 @@ #include #include "I2NPProtocol.h" #include "LeaseSet.h" +#include "Tunnel.h" namespace i2p { @@ -75,7 +76,7 @@ namespace garlic GarlicRouting (); ~GarlicRouting (); - void HandleGarlicMessage (uint8_t * buf, size_t len, bool isFromTunnel); + void HandleGarlicMessage (I2NPMessage * msg); void HandleDeliveryStatusMessage (uint8_t * buf, size_t len); I2NPMessage * WrapSingleMessage (const i2p::data::RoutingDestination& destination, I2NPMessage * msg); diff --git a/I2NPProtocol.cpp b/I2NPProtocol.cpp index 0e189218..8990da3b 100644 --- a/I2NPProtocol.cpp +++ b/I2NPProtocol.cpp @@ -22,6 +22,7 @@ namespace i2p I2NPMessage * msg = new I2NPMessage; msg->offset = 2; // reserve 2 bytes for NTCP header, should reserve more for SSU in future msg->len = sizeof (I2NPHeader) + 2; + msg->from = nullptr; return msg; } @@ -414,7 +415,7 @@ namespace i2p return be16toh (header->size) + sizeof (I2NPHeader); } - void HandleI2NPMessage (uint8_t * msg, size_t len, bool isFromTunnel) + void HandleI2NPMessage (uint8_t * msg, size_t len) { I2NPHeader * header = (I2NPHeader *)msg; uint32_t msgID = be32toh (header->msgID); @@ -423,12 +424,7 @@ namespace i2p uint8_t * buf = msg + sizeof (I2NPHeader); int size = be16toh (header->size); switch (header->typeID) - { - case eI2NPGarlic: - LogPrint ("Garlic"); - i2p::garlic::routing.HandleGarlicMessage (buf, size, isFromTunnel); - break; - break; + { case eI2NPDeliveryStatus: LogPrint ("DeliveryStatus"); // we assume DeliveryStatusMessage is sent with garlic only @@ -451,7 +447,7 @@ namespace i2p } } - void HandleI2NPMessage (I2NPMessage * msg, bool isFromTunnel) + void HandleI2NPMessage (I2NPMessage * msg) { if (msg) { @@ -473,8 +469,12 @@ namespace i2p LogPrint ("DatabaseSearchReply"); i2p::data::netdb.PostI2NPMsg (msg); break; + case eI2NPGarlic: + LogPrint ("Garlic"); + i2p::garlic::routing.HandleGarlicMessage (msg); + break; default: - HandleI2NPMessage (msg->GetBuffer (), msg->GetLength (), isFromTunnel); + HandleI2NPMessage (msg->GetBuffer (), msg->GetLength ()); DeleteI2NPMessage (msg); } } diff --git a/I2NPProtocol.h b/I2NPProtocol.h index e7c04d16..2030bdad 100644 --- a/I2NPProtocol.h +++ b/I2NPProtocol.h @@ -91,11 +91,17 @@ namespace i2p eI2NPVariableTunnelBuildReply = 24 }; +namespace tunnel +{ + class InboundTunnel; +} + const int NTCP_MAX_MESSAGE_SIZE = 16384; struct I2NPMessage { uint8_t buf[NTCP_MAX_MESSAGE_SIZE]; size_t len, offset; + i2p::tunnel::InboundTunnel * from; I2NPHeader * GetHeader () { return (I2NPHeader *)(buf + offset); }; uint8_t * GetPayload () { return buf + offset + sizeof(I2NPHeader); }; @@ -106,6 +112,7 @@ namespace i2p { memcpy (buf + offset, other.buf + other.offset, other.GetLength ()); len = offset + other.GetLength (); + from = other.from; return *this; } @@ -169,8 +176,8 @@ namespace i2p I2NPMessage * CreateTunnelGatewayMsg (uint32_t tunnelID, I2NPMessage * msg); size_t GetI2NPMessageLength (uint8_t * msg); - void HandleI2NPMessage (uint8_t * msg, size_t len, bool isFromTunnel); - void HandleI2NPMessage (I2NPMessage * msg, bool isFromTunnel); + void HandleI2NPMessage (uint8_t * msg, size_t len); + void HandleI2NPMessage (I2NPMessage * msg); } #endif diff --git a/NTCPSession.cpp b/NTCPSession.cpp index e2686248..1a72fdbc 100644 --- a/NTCPSession.cpp +++ b/NTCPSession.cpp @@ -424,7 +424,7 @@ namespace ntcp if (m_NextMessageOffset >= m_NextMessage->len + 4) // +checksum { // we have a complete I2NP message - i2p::HandleI2NPMessage (m_NextMessage, false); + i2p::HandleI2NPMessage (m_NextMessage); m_NextMessage = nullptr; } } diff --git a/NetDb.cpp b/NetDb.cpp index 14a33353..1b115c63 100644 --- a/NetDb.cpp +++ b/NetDb.cpp @@ -111,7 +111,7 @@ namespace data else // WTF? { LogPrint ("NetDb: unexpected message type ", msg->GetHeader ()->typeID); - i2p::HandleI2NPMessage (msg, false); + i2p::HandleI2NPMessage (msg); } msg = m_Queue.Get (); } diff --git a/SSU.cpp b/SSU.cpp index 9eb5cb7c..7efd14e4 100644 --- a/SSU.cpp +++ b/SSU.cpp @@ -614,7 +614,7 @@ namespace ssu m_IncomleteMessages.erase (msgID); msg->FromSSU (msgID); if (m_State == eSessionStateEstablished) - i2p::HandleI2NPMessage (msg, false); + i2p::HandleI2NPMessage (msg); else { // we expect DeliveryStatus diff --git a/Transports.cpp b/Transports.cpp index c0c0ea8f..9dc733c4 100644 --- a/Transports.cpp +++ b/Transports.cpp @@ -148,7 +148,7 @@ namespace i2p { if (ident == i2p::context.GetRouterInfo ().GetIdentHash ()) // we send it to ourself - i2p::HandleI2NPMessage (msg, false); + i2p::HandleI2NPMessage (msg); else m_Service.post (boost::bind (&Transports::PostMessage, this, ident, msg)); } diff --git a/Tunnel.cpp b/Tunnel.cpp index 601586ae..ed9708cb 100644 --- a/Tunnel.cpp +++ b/Tunnel.cpp @@ -130,6 +130,7 @@ namespace tunnel void InboundTunnel::HandleTunnelDataMsg (I2NPMessage * msg) { + msg->from = this; EncryptTunnelMsg (msg); m_Endpoint.HandleDecryptedTunnelDataMsg (msg); } diff --git a/TunnelEndpoint.cpp b/TunnelEndpoint.cpp index 0e23a837..fc92ec29 100644 --- a/TunnelEndpoint.cpp +++ b/TunnelEndpoint.cpp @@ -147,7 +147,7 @@ namespace tunnel switch (msg.deliveryType) { case eDeliveryTypeLocal: - i2p::HandleI2NPMessage (msg.data, true); + i2p::HandleI2NPMessage (msg.data); break; case eDeliveryTypeTunnel: i2p::transports.SendMessage (msg.hash, i2p::CreateTunnelGatewayMsg (msg.tunnelID, msg.data)); From 28cc50fecea55cea8fde7395865fd365bf176f95 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 12 Mar 2014 21:13:54 -0400 Subject: [PATCH 43/43] handle garlic message in separate thread --- Garlic.cpp | 40 ++++++++++++++++++++++++++++++++++++++++ Garlic.h | 10 ++++++++++ i2p.cpp | 3 +++ 3 files changed, 53 insertions(+) diff --git a/Garlic.cpp b/Garlic.cpp index a269daa5..32639142 100644 --- a/Garlic.cpp +++ b/Garlic.cpp @@ -263,6 +263,11 @@ namespace garlic } void GarlicRouting::HandleGarlicMessage (I2NPMessage * msg) + { + if (msg) m_Queue.Put (msg); + } + + void GarlicRouting::ProcessGarlicMessage (I2NPMessage * msg) { uint8_t * buf = msg->GetPayload (); uint32_t length = be32toh (*(uint32_t *)buf); @@ -411,5 +416,40 @@ namespace garlic LogPrint ("Garlic message ", be32toh (msg->msgID), " acknowledged"); } } + + void GarlicRouting::Start () + { + m_IsRunning = true; + m_Thread = new std::thread (std::bind (&GarlicRouting::Run, this)); + } + + void GarlicRouting::Stop () + { + m_IsRunning = false; + m_Queue.WakeUp (); + if (m_Thread) + { + m_Thread->join (); + delete m_Thread; + m_Thread = 0; + } + } + + void GarlicRouting::Run () + { + while (m_IsRunning) + { + try + { + I2NPMessage * msg = m_Queue.GetNext (); + if (msg) + ProcessGarlicMessage (msg); + } + catch (std::exception& ex) + { + LogPrint ("GarlicRouting: ", ex.what ()); + } + } + } } } diff --git a/Garlic.h b/Garlic.h index a31b14cf..3fb8ba50 100644 --- a/Garlic.h +++ b/Garlic.h @@ -4,12 +4,14 @@ #include #include #include +#include #include #include #include #include "I2NPProtocol.h" #include "LeaseSet.h" #include "Tunnel.h" +#include "Queue.h" namespace i2p { @@ -76,6 +78,9 @@ namespace garlic GarlicRouting (); ~GarlicRouting (); + void Start (); + void Stop (); + void HandleGarlicMessage (I2NPMessage * msg); void HandleDeliveryStatusMessage (uint8_t * buf, size_t len); @@ -85,11 +90,16 @@ namespace garlic private: + void Run (); + void ProcessGarlicMessage (I2NPMessage * msg); void HandleAESBlock (uint8_t * buf, size_t len, uint8_t * sessionKey); void HandleGarlicPayload (uint8_t * buf, size_t len); private: + bool m_IsRunning; + std::thread * m_Thread; + i2p::util::Queue m_Queue; // outgoing sessions std::map m_Sessions; std::map m_CreatedSessions; // msgID -> session diff --git a/i2p.cpp b/i2p.cpp index 967435cb..839e7c01 100644 --- a/i2p.cpp +++ b/i2p.cpp @@ -22,6 +22,7 @@ #include "Tunnel.h" #include "NetDb.h" #include "HTTPServer.h" +#include "Garlic.h" #include "util.h" @@ -152,6 +153,7 @@ int main( int argc, char* argv[] ) i2p::data::netdb.Start (); i2p::transports.Start (); i2p::tunnel::tunnels.Start (); + i2p::garlic::routing.Start (); while (running) { @@ -160,6 +162,7 @@ int main( int argc, char* argv[] ) } LogPrint("Shutdown started."); + i2p::garlic::routing.Stop (); i2p::tunnel::tunnels.Stop (); i2p::transports.Stop (); i2p::data::netdb.Stop ();