From 13a88c4e92c191814fc77a29dd5b159ef916d5c4 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 6 Apr 2014 16:42:29 -0400 Subject: [PATCH 01/21] fixed build error --- util.cpp | 5 +++++ util.h | 8 ++++---- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/util.cpp b/util.cpp index 40e585aa..8b95e2e3 100644 --- a/util.cpp +++ b/util.cpp @@ -249,6 +249,11 @@ namespace http } } + std::string url::portstr_ = "80"; + unsigned int url::port_ = 80; + std::string url::user_ = ""; + std::string url::pass_ = ""; + url::url(const std::string& url_s) { parse(url_s); diff --git a/util.h b/util.h index 5f8a2b13..8766a516 100644 --- a/util.h +++ b/util.h @@ -41,10 +41,10 @@ namespace util void parse(const std::string& url_s); public: std::string protocol_, host_, path_, query_; - std::string portstr_ = "80"; - unsigned int port_ = 80; - std::string user_ = ""; - std::string pass_ = ""; + static std::string portstr_; + static unsigned int port_; + static std::string user_; + static std::string pass_; }; } } From cf6fa2d41d0c9bf695b67f2eb2c73bbcbc67efe5 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 6 Apr 2014 18:30:27 -0400 Subject: [PATCH 02/21] speedup inbound tunnels creation --- TunnelPool.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/TunnelPool.cpp b/TunnelPool.cpp index 33f6cbda..875a51f6 100644 --- a/TunnelPool.cpp +++ b/TunnelPool.cpp @@ -169,14 +169,14 @@ namespace tunnel *m_OutboundTunnels.begin () : tunnels.GetNextOutboundTunnel (); LogPrint ("Creating destination inbound tunnel..."); auto firstHop = i2p::data::netdb.GetRandomRouter (outboundTunnel ? outboundTunnel->GetEndpointRouter () : nullptr); - auto secondHop = i2p::data::netdb.GetRandomRouter (firstHop); + auto secondHop = outboundTunnel ? outboundTunnel->GetTunnelConfig ()->GetFirstHop ()->router : nullptr; + if (!secondHop || secondHop->GetIdentHash () == i2p::context.GetIdentHash ()) + secondHop = i2p::data::netdb.GetRandomRouter (firstHop); auto * tunnel = tunnels.CreateTunnel ( new TunnelConfig (std::vector { firstHop, secondHop - // TODO: switch to 3-hops later - /*i2p::data::netdb.GetRandomRouter (secondHop) */ }), outboundTunnel); tunnel->SetTunnelPool (this); From 19333d5697c7d9c1b6aa52c396f6f6e197376c86 Mon Sep 17 00:00:00 2001 From: cpubug Date: Mon, 7 Apr 2014 21:47:40 +0400 Subject: [PATCH 03/21] load Ident from base64 string --- Identity.cpp | 7 +++++++ Identity.h | 1 + 2 files changed, 8 insertions(+) diff --git a/Identity.cpp b/Identity.cpp index 387eef50..652dc1e1 100644 --- a/Identity.cpp +++ b/Identity.cpp @@ -6,6 +6,7 @@ #include #include "CryptoConst.h" #include "Identity.h" +#include "base64.h" namespace i2p { @@ -17,6 +18,12 @@ namespace data memcpy (publicKey, keys.publicKey, sizeof (publicKey) + sizeof (signingKey)); memset (certificate, 0, sizeof (certificate)); return *this; + } + + bool Identity::FromBase64 (const std::string& s) + { + size_t count = Base64ToByteStream (s.c_str(), s.length(), reinterpret_cast (this), sizeof (Identity)); + return count == sizeof(Identity); } PrivateKeys& PrivateKeys::operator=(const Keys& keys) diff --git a/Identity.h b/Identity.h index 1dafdef4..19e5a007 100644 --- a/Identity.h +++ b/Identity.h @@ -32,6 +32,7 @@ namespace data uint8_t certificate[3]; Identity& operator=(const Keys& keys); + bool FromBase64(const std::string&); }; struct PrivateKeys // for eepsites From a82bd628c1635d97ceea48308665295314d51bb2 Mon Sep 17 00:00:00 2001 From: cpubug Date: Mon, 7 Apr 2014 22:01:24 +0400 Subject: [PATCH 04/21] compute IdentHash in Identity method --- Identity.cpp | 7 +++++++ Identity.h | 3 +++ 2 files changed, 10 insertions(+) diff --git a/Identity.cpp b/Identity.cpp index 652dc1e1..435c0c9b 100644 --- a/Identity.cpp +++ b/Identity.cpp @@ -24,6 +24,13 @@ namespace data { size_t count = Base64ToByteStream (s.c_str(), s.length(), reinterpret_cast (this), sizeof (Identity)); return count == sizeof(Identity); + } + + IdentHash Identity::Hash() + { + IdentHash hash; + CryptoPP::SHA256().CalculateDigest(reinterpret_cast(&hash), reinterpret_cast (this), sizeof (Identity)); + return hash; } PrivateKeys& PrivateKeys::operator=(const Keys& keys) diff --git a/Identity.h b/Identity.h index 19e5a007..902153dc 100644 --- a/Identity.h +++ b/Identity.h @@ -9,6 +9,8 @@ namespace i2p { namespace data { + class IdentHash; + #pragma pack(1) struct DHKeysPair // transient keys for transport sessions @@ -33,6 +35,7 @@ namespace data Identity& operator=(const Keys& keys); bool FromBase64(const std::string&); + IdentHash Hash(); }; struct PrivateKeys // for eepsites From 8725599d96d9b358a8ba7d4931a6a33fdbe3f50e Mon Sep 17 00:00:00 2001 From: cpubug Date: Mon, 7 Apr 2014 22:04:29 +0400 Subject: [PATCH 05/21] improve hosts.txt loading --- AddressBook.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/AddressBook.cpp b/AddressBook.cpp index 75ca5761..dfd788bf 100644 --- a/AddressBook.cpp +++ b/AddressBook.cpp @@ -80,7 +80,7 @@ void AddressBook::LoadHosts () getline(f, s); if (!s.length()) - break; + continue; // skip empty line size_t pos = s.find('='); @@ -90,8 +90,11 @@ void AddressBook::LoadHosts () std::string addr = s.substr(pos); Identity ident; - Base64ToByteStream (addr.c_str(), addr.length(), (uint8_t *)&ident, sizeof (ident)); - m_Addresses[name] = CalculateIdentHash (ident); + if (!ident.FromBase64(addr)) { + LogPrint ("hosts.txt: ignore ", name); + continue; + } + m_Addresses[name] = ident.Hash(); numAddresses++; } } From 130e1c2daf141002c65944062e2659d22b8172ec Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 7 Apr 2014 15:31:38 -0400 Subject: [PATCH 06/21] handle PeerTest --- SSU.cpp | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++++++--- SSU.h | 11 +++++--- 2 files changed, 82 insertions(+), 8 deletions(-) diff --git a/SSU.cpp b/SSU.cpp index a43e04f6..fc957d14 100644 --- a/SSU.cpp +++ b/SSU.cpp @@ -57,7 +57,7 @@ namespace ssu case eSessionStateConfirmedSent: case eSessionStateEstablished: // most common case - ProcessMessage (buf, len); + ProcessMessage (buf, len, senderEndpoint); break; // establishing case eSessionStateUnknown: @@ -92,7 +92,7 @@ namespace ssu } } - void SSUSession::ProcessMessage (uint8_t * buf, size_t len) + void SSUSession::ProcessMessage (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint) { if (Validate (buf, len, m_MacKey)) { @@ -105,8 +105,9 @@ namespace ssu LogPrint ("SSU data received"); ProcessData (buf + sizeof (SSUHeader), len - sizeof (SSUHeader)); break; - case PAYLOAD_TYPE_TEST: - LogPrint ("SSU test received"); + case PAYLOAD_TYPE_PEER_TEST: + LogPrint ("SSU peer test received"); + ProcessPeerTest (buf + sizeof (SSUHeader), len - sizeof (SSUHeader), senderEndpoint); break; case PAYLOAD_TYPE_SESSION_DESTROYED: { @@ -678,6 +679,58 @@ namespace ssu } } + + void SSUSession::ProcessPeerTest (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint) + { + uint8_t * buf1 = buf; + uint32_t nonce = be32toh (*(uint32_t *)buf); + buf += 4; // nonce + uint8_t size = *buf; + buf++; // size + uint8_t * address = (size == 4) ? buf : nullptr; + buf += size; // address + uint16_t port = *(uint16_t *)buf; // use it as is + buf += 2; // port + uint8_t * introKey = buf; + if (port) + { + LogPrint ("SSU peer test. We are Charlie"); + Send (PAYLOAD_TYPE_PEER_TEST, buf1, len); // back to Bob + if (address) + SendPeerTest (nonce, be32toh (*(uint32_t *)address), be16toh (port), introKey); // to Alice + else + LogPrint ("Address of ", size, " bytes not supported"); + } + else + { + LogPrint ("SSU peer test. We are Bob"); + // TODO: + } + } + + void SSUSession::SendPeerTest (uint32_t nonce, uint32_t address, uint16_t port, uint8_t * introKey) + { + uint8_t buf[80 + 18]; + uint8_t iv[16]; + uint8_t * payload = buf + sizeof (SSUHeader); + *(uint32_t *)payload = htobe32 (nonce); + payload += 4; // nonce + *payload = 4; + payload++; // size + *(uint32_t *)payload = htobe32 (address); + payload += 4; // address + *(uint16_t *)payload = htobe32 (port); + payload += 2; // port + memcpy (payload, introKey, 32); // intro key + + CryptoPP::RandomNumberGenerator& rnd = i2p::context.GetRandomNumberGenerator (); + rnd.GenerateBlock (iv, 16); // random iv + // encrypt message with specified intro key + FillHeaderAndEncrypt (PAYLOAD_TYPE_PEER_TEST, buf, 80, introKey, iv, introKey); + boost::asio::ip::udp::endpoint e (boost::asio::ip::address_v4 (address), port); + m_Server.Send (buf, 80, e); + } + void SSUSession::SendMsgAck (uint32_t msgID) { uint8_t buf[48 + 18]; // actual length is 44 = 37 + 7 but pad it to multiple of 16 @@ -771,6 +824,24 @@ namespace ssu } } + void SSUSession::Send (uint8_t type, const uint8_t * payload, size_t len) + { + uint8_t buf[SSU_MTU + 18]; + uint8_t iv[16]; + size_t msgSize = len + sizeof (SSUHeader); + if (msgSize > SSU_MTU) + { + LogPrint ("SSU payload size ", msgSize, " exceeds MTU"); + return; + } + memcpy (buf + sizeof (SSUHeader), payload, len); + CryptoPP::RandomNumberGenerator& rnd = i2p::context.GetRandomNumberGenerator (); + rnd.GenerateBlock (iv, 16); // random iv + // encrypt message with session key + FillHeaderAndEncrypt (type, buf, msgSize, m_SessionKey, iv, m_MacKey); + m_Server.Send (buf, msgSize, m_RemoteEndpoint); + } + SSUServer::SSUServer (boost::asio::io_service& service, int port): m_Endpoint (boost::asio::ip::udp::v4 (), port), m_Socket (service, m_Endpoint) { diff --git a/SSU.h b/SSU.h index e528d30b..78c818ea 100644 --- a/SSU.h +++ b/SSU.h @@ -26,7 +26,7 @@ namespace ssu }; #pragma pack() - const int SSU_MTU = 1484; + const size_t SSU_MTU = 1484; const int SSU_CONNECT_TIMEOUT = 5; // 5 seconds // payload types (4 bits) @@ -37,7 +37,7 @@ namespace ssu const uint8_t PAYLOAD_TYPE_RELAY_RESPONSE = 4; 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_PEER_TEST = 7; const uint8_t PAYLOAD_TYPE_SESSION_DESTROYED = 8; // data flags @@ -85,7 +85,7 @@ namespace ssu void CreateAESandMacKey (uint8_t * pubKey, uint8_t * aesKey, uint8_t * macKey); - void ProcessMessage (uint8_t * buf, size_t len); // call for established session + void ProcessMessage (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint); // 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); @@ -97,10 +97,13 @@ namespace ssu void Established (); void Failed (); void HandleConnectTimer (const boost::system::error_code& ecode); - void ProcessData (uint8_t * buf, size_t len); + void ProcessPeerTest (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint); + void SendPeerTest (uint32_t nonce, uint32_t address, uint16_t port, uint8_t * introKey); // Charlie to Alice + void ProcessData (uint8_t * buf, size_t len); void SendMsgAck (uint32_t msgID); void SendSesionDestroyed (); void Send (i2p::I2NPMessage * msg); + void Send (uint8_t type, const uint8_t * payload, size_t len); // with session key 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); From 45d157155976cbc995c11c75f90e8949c9092be3 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 7 Apr 2014 16:19:33 -0400 Subject: [PATCH 07/21] send peer test by Alice --- SSU.cpp | 31 +++++++++++++++++++++++++++++-- SSU.h | 3 ++- 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/SSU.cpp b/SSU.cpp index fc957d14..ed822f3c 100644 --- a/SSU.cpp +++ b/SSU.cpp @@ -731,6 +731,33 @@ namespace ssu m_Server.Send (buf, 80, e); } + void SSUSession::SendPeerTest () + { + auto introKey = GetIntroKey (); + if (!introKey) + { + LogPrint ("SSU is not supported. Can't send peer test"); + return; + } + uint8_t buf[80 + 18]; + uint8_t * payload = buf + sizeof (SSUHeader); + CryptoPP::RandomNumberGenerator& rnd = i2p::context.GetRandomNumberGenerator (); + uint32_t nonce = 0; + rnd.GenerateWord32 (nonce); + *(uint32_t *)payload = htobe32 (nonce); + payload += 4; // nonce + *payload = 4; + payload++; // size + memset (payload, 0, 6); // address and port always zero for Alice + payload += 6; // address and port + memcpy (payload, introKey, 32); // intro key + uint8_t iv[16]; + rnd.GenerateBlock (iv, 16); // random iv + // encrypt message with session key + FillHeaderAndEncrypt (PAYLOAD_TYPE_PEER_TEST, buf, 80, m_SessionKey, iv, m_MacKey); + m_Server.Send (buf, 80, m_RemoteEndpoint); + } + void SSUSession::SendMsgAck (uint32_t msgID) { uint8_t buf[48 + 18]; // actual length is 44 = 37 + 7 but pad it to multiple of 16 @@ -822,8 +849,8 @@ namespace ssu len = 0; fragmentNum++; } - } - + } + void SSUSession::Send (uint8_t type, const uint8_t * payload, size_t len) { uint8_t buf[SSU_MTU + 18]; diff --git a/SSU.h b/SSU.h index 78c818ea..6387038c 100644 --- a/SSU.h +++ b/SSU.h @@ -80,7 +80,8 @@ namespace ssu boost::asio::ip::udp::endpoint& GetRemoteEndpoint () { return m_RemoteEndpoint; }; const i2p::data::RouterInfo * GetRemoteRouter () const { return m_RemoteRouter; }; void SendI2NPMessage (I2NPMessage * msg); - + void SendPeerTest (); // Alice + private: void CreateAESandMacKey (uint8_t * pubKey, uint8_t * aesKey, uint8_t * macKey); From 64f195868e7d29a8d520b38ea17fb83ccf343fa3 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 7 Apr 2014 16:41:29 -0400 Subject: [PATCH 08/21] process intro key message --- SSU.cpp | 64 ++++++++++++++++++++++++++++++++++----------------------- SSU.h | 6 +++++- 2 files changed, 43 insertions(+), 27 deletions(-) diff --git a/SSU.cpp b/SSU.cpp index ed822f3c..5d3f9ab2 100644 --- a/SSU.cpp +++ b/SSU.cpp @@ -59,10 +59,10 @@ namespace ssu // most common case ProcessMessage (buf, len, senderEndpoint); break; - // establishing + // establishing or testing case eSessionStateUnknown: - // session request - ProcessSessionRequest (buf, len, senderEndpoint); + // we must use intro key + ProcessIntroKeyMessage (buf, len, senderEndpoint); break; case eSessionStateRequestSent: // session created @@ -98,8 +98,7 @@ namespace ssu { Decrypt (buf, len, m_SessionKey); SSUHeader * header = (SSUHeader *)buf; - uint8_t payloadType = header->flag >> 4; - switch (payloadType) + switch (header->GetPayloadType ()) { case PAYLOAD_TYPE_DATA: LogPrint ("SSU data received"); @@ -120,7 +119,7 @@ namespace ssu // TODO: break; default: - LogPrint ("Unexpected SSU payload type ", (int)payloadType); + LogPrint ("Unexpected SSU payload type ", (int)header->GetPayloadType ()); } } else @@ -140,17 +139,30 @@ namespace ssu } } - void SSUSession::ProcessSessionRequest (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint) + void SSUSession::ProcessIntroKeyMessage (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint) { - LogPrint ("Process session request"); - // use our intro key - if (ProcessIntroKeyEncryptedMessage (PAYLOAD_TYPE_SESSION_REQUEST, buf, len)) + if (ProcessIntroKeyEncryptedMessage (buf, len)) { - m_State = eSessionStateRequestReceived; - LogPrint ("Session request received"); - m_RemoteEndpoint = senderEndpoint; - SendSessionCreated (buf + sizeof (SSUHeader)); - } + SSUHeader * header = (SSUHeader *)buf; + switch (header->GetPayloadType ()) + { + case PAYLOAD_TYPE_SESSION_REQUEST: + ProcessSessionRequest (buf + sizeof (SSUHeader), len - sizeof (SSUHeader), senderEndpoint); + break; + case PAYLOAD_TYPE_PEER_TEST: + // TODO + break; + default: ; + } + } + } + + void SSUSession::ProcessSessionRequest (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint) + { + m_State = eSessionStateRequestReceived; + LogPrint ("Session request received"); + m_RemoteEndpoint = senderEndpoint; + SendSessionCreated (buf); } void SSUSession::ProcessSessionCreated (uint8_t * buf, size_t len) @@ -163,8 +175,14 @@ namespace ssu } // use remote intro key - if (ProcessIntroKeyEncryptedMessage (PAYLOAD_TYPE_SESSION_CREATED, buf, len)) + if (ProcessIntroKeyEncryptedMessage (buf, len)) { + SSUHeader * header = (SSUHeader *)buf; + if (header->GetPayloadType () != PAYLOAD_TYPE_SESSION_CONFIRMED) + { + LogPrint ("Unexpected payload type ", header->GetPayloadType ()); + return; + } m_State = eSessionStateCreatedReceived; LogPrint ("Session created received"); m_Timer.cancel (); // connect timer @@ -210,7 +228,7 @@ namespace ssu { Decrypt (buf, len, m_SessionKey); SSUHeader * header = (SSUHeader *)buf; - if ((header->flag >> 4) == PAYLOAD_TYPE_SESSION_CONFIRMED) + if (header->GetPayloadType () == PAYLOAD_TYPE_SESSION_CONFIRMED) { m_State = eSessionStateConfirmedReceived; LogPrint ("Session confirmed received"); @@ -407,7 +425,7 @@ namespace ssu } } - bool SSUSession::ProcessIntroKeyEncryptedMessage (uint8_t expectedPayloadType, uint8_t * buf, size_t len) + bool SSUSession::ProcessIntroKeyEncryptedMessage (uint8_t * buf, size_t len) { auto introKey = GetIntroKey (); if (introKey) @@ -416,14 +434,8 @@ namespace ssu if (Validate (buf, len, introKey)) { Decrypt (buf, len, introKey); - SSUHeader * header = (SSUHeader *)buf; - if ((header->flag >> 4) == expectedPayloadType) - { - CreateAESandMacKey (buf + sizeof (SSUHeader), m_SessionKey, m_MacKey); - return true; - } - else - LogPrint ("Unexpected payload type ", (int)(header->flag >> 4)); + CreateAESandMacKey (buf + sizeof (SSUHeader), m_SessionKey, m_MacKey); + return true; } else { diff --git a/SSU.h b/SSU.h index 6387038c..b0c7632d 100644 --- a/SSU.h +++ b/SSU.h @@ -23,6 +23,8 @@ namespace ssu uint8_t iv[16]; uint8_t flag; uint32_t time; + + uint8_t GetPayloadType () const { return flag >> 4; }; }; #pragma pack() @@ -87,6 +89,8 @@ namespace ssu void CreateAESandMacKey (uint8_t * pubKey, uint8_t * aesKey, uint8_t * macKey); void ProcessMessage (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint); // call for established session + void ProcessIntroKeyMessage (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint); // call for non-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); @@ -106,7 +110,7 @@ namespace ssu void Send (i2p::I2NPMessage * msg); void Send (uint8_t type, const uint8_t * payload, size_t len); // with session key - bool ProcessIntroKeyEncryptedMessage (uint8_t expectedPayloadType, uint8_t * buf, size_t len); + bool ProcessIntroKeyEncryptedMessage (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); From be563dcbd13f825e2eca617b29c6fff928d1c2ce Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 7 Apr 2014 16:53:28 -0400 Subject: [PATCH 09/21] process session created after decryption with intro key --- SSU.cpp | 93 +++++++++++++++++++++++++-------------------------------- 1 file changed, 41 insertions(+), 52 deletions(-) diff --git a/SSU.cpp b/SSU.cpp index 5d3f9ab2..845aee1c 100644 --- a/SSU.cpp +++ b/SSU.cpp @@ -61,13 +61,10 @@ namespace ssu break; // establishing or testing case eSessionStateUnknown: + case eSessionStateRequestSent: // we must use intro key ProcessIntroKeyMessage (buf, len, senderEndpoint); break; - case eSessionStateRequestSent: - // session created - ProcessSessionCreated (buf, len); - break; case eSessionStateCreatedSent: // session confirmed ProcessSessionConfirmed (buf, len); @@ -147,7 +144,10 @@ namespace ssu switch (header->GetPayloadType ()) { case PAYLOAD_TYPE_SESSION_REQUEST: - ProcessSessionRequest (buf + sizeof (SSUHeader), len - sizeof (SSUHeader), senderEndpoint); + ProcessSessionRequest (buf, len, senderEndpoint); + break; + case PAYLOAD_TYPE_SESSION_CREATED: + ProcessSessionCreated (buf, len); break; case PAYLOAD_TYPE_PEER_TEST: // TODO @@ -162,63 +162,52 @@ namespace ssu m_State = eSessionStateRequestReceived; LogPrint ("Session request received"); m_RemoteEndpoint = senderEndpoint; - SendSessionCreated (buf); + SendSessionCreated (buf + sizeof (SSUHeader)); } void SSUSession::ProcessSessionCreated (uint8_t * buf, size_t len) { - LogPrint ("Process session created"); if (!m_RemoteRouter) { LogPrint ("Unsolicited session created message"); return; } - // use remote intro key - if (ProcessIntroKeyEncryptedMessage (buf, len)) - { - SSUHeader * header = (SSUHeader *)buf; - if (header->GetPayloadType () != PAYLOAD_TYPE_SESSION_CONFIRMED) - { - LogPrint ("Unexpected payload type ", header->GetPayloadType ()); - return; - } - m_State = eSessionStateCreatedReceived; - LogPrint ("Session created received"); - m_Timer.cancel (); // connect timer - 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, m_DHKeysPair->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 *)(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); - } + m_State = eSessionStateCreatedReceived; + LogPrint ("Session created received"); + m_Timer.cancel (); // connect timer + 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, m_DHKeysPair->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 *)(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); } void SSUSession::ProcessSessionConfirmed (uint8_t * buf, size_t len) From 9f8f91a2ee7ef1663ab8848e39d8e624df1bc9f1 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 7 Apr 2014 18:54:28 -0400 Subject: [PATCH 10/21] fixed small issues --- SSU.cpp | 75 +++++++++++++++++++++++++++------------------------------ SSU.h | 1 - 2 files changed, 36 insertions(+), 40 deletions(-) diff --git a/SSU.cpp b/SSU.cpp index 845aee1c..5ae377e2 100644 --- a/SSU.cpp +++ b/SSU.cpp @@ -138,23 +138,42 @@ namespace ssu void SSUSession::ProcessIntroKeyMessage (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint) { - if (ProcessIntroKeyEncryptedMessage (buf, len)) + auto introKey = GetIntroKey (); + if (!introKey) { - SSUHeader * header = (SSUHeader *)buf; - switch (header->GetPayloadType ()) + LogPrint ("SSU is not supported"); + return; + } + // use intro key for verification and decryption + if (!Validate (buf, len, introKey)) + { + LogPrint ("MAC verification intro key failed"); + Failed (); + return; + } + + Decrypt (buf, len, introKey); + CreateAESandMacKey (buf + sizeof (SSUHeader), m_SessionKey, m_MacKey); + SSUHeader * header = (SSUHeader *)buf; + switch (header->GetPayloadType ()) + { + case PAYLOAD_TYPE_SESSION_REQUEST: + ProcessSessionRequest (buf, len, senderEndpoint); + break; + case PAYLOAD_TYPE_SESSION_CREATED: + ProcessSessionCreated (buf, len); + break; + case PAYLOAD_TYPE_SESSION_DESTROYED: { - case PAYLOAD_TYPE_SESSION_REQUEST: - ProcessSessionRequest (buf, len, senderEndpoint); - break; - case PAYLOAD_TYPE_SESSION_CREATED: - ProcessSessionCreated (buf, len); + LogPrint ("SSU session destroy with into key received"); + m_Server.DeleteSession (this); // delete this break; - case PAYLOAD_TYPE_PEER_TEST: - // TODO - break; - default: ; - } - } + } + case PAYLOAD_TYPE_PEER_TEST: + // TODO + break; + default: ; + } } void SSUSession::ProcessSessionRequest (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint) @@ -414,29 +433,6 @@ namespace ssu } } - bool SSUSession::ProcessIntroKeyEncryptedMessage (uint8_t * buf, size_t len) - { - auto introKey = GetIntroKey (); - if (introKey) - { - // use intro key for verification and decryption - if (Validate (buf, len, introKey)) - { - Decrypt (buf, len, introKey); - CreateAESandMacKey (buf + sizeof (SSUHeader), m_SessionKey, m_MacKey); - return true; - } - else - { - LogPrint ("MAC verification failed"); - Failed (); - } - } - else - LogPrint ("SSU is not supported"); - return false; - } - void SSUSession::FillHeaderAndEncrypt (uint8_t payloadType, uint8_t * buf, size_t len, const uint8_t * aesKey, const uint8_t * iv, const uint8_t * macKey) { @@ -734,12 +730,13 @@ namespace ssu void SSUSession::SendPeerTest () { - auto introKey = GetIntroKey (); - if (!introKey) + auto address = i2p::context.GetRouterInfo ().GetSSUAddress (); + if (!address) { LogPrint ("SSU is not supported. Can't send peer test"); return; } + auto introKey = address->key; uint8_t buf[80 + 18]; uint8_t * payload = buf + sizeof (SSUHeader); CryptoPP::RandomNumberGenerator& rnd = i2p::context.GetRandomNumberGenerator (); diff --git a/SSU.h b/SSU.h index b0c7632d..b299d852 100644 --- a/SSU.h +++ b/SSU.h @@ -110,7 +110,6 @@ namespace ssu void Send (i2p::I2NPMessage * msg); void Send (uint8_t type, const uint8_t * payload, size_t len); // with session key - bool ProcessIntroKeyEncryptedMessage (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); From 03a5059617ea623e4b98fa085410e68f719e3266 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 7 Apr 2014 19:28:06 -0400 Subject: [PATCH 11/21] peer test --- SSU.cpp | 25 +++++++++++++++---------- SSU.h | 5 +++-- Transports.cpp | 2 +- 3 files changed, 19 insertions(+), 13 deletions(-) diff --git a/SSU.cpp b/SSU.cpp index 5ae377e2..36817a65 100644 --- a/SSU.cpp +++ b/SSU.cpp @@ -16,8 +16,9 @@ namespace ssu { 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_Timer (m_Server.GetService ()), m_State (eSessionStateUnknown) + const i2p::data::RouterInfo * router, bool peerTest ): + m_Server (server), m_RemoteEndpoint (remoteEndpoint), m_RemoteRouter (router), + m_Timer (m_Server.GetService ()), m_PeerTest (peerTest), m_State (eSessionStateUnknown) { m_DHKeysPair = i2p::transports.GetNextDHKeysPair (); } @@ -170,7 +171,8 @@ namespace ssu break; } case PAYLOAD_TYPE_PEER_TEST: - // TODO + LogPrint ("SSU peer test received"); + // TODO: break; default: ; } @@ -541,7 +543,9 @@ namespace ssu for (auto it :m_DelayedMessages) Send (it); m_DelayedMessages.clear (); - } + } + if (m_PeerTest) + SendPeerTest (); } void SSUSession::Failed () @@ -730,6 +734,7 @@ namespace ssu void SSUSession::SendPeerTest () { + LogPrint ("SSU sending peer test"); auto address = i2p::context.GetRouterInfo ().GetSSUAddress (); if (!address) { @@ -937,7 +942,7 @@ namespace ssu return nullptr; } - SSUSession * SSUServer::GetSession (const i2p::data::RouterInfo * router) + SSUSession * SSUServer::GetSession (const i2p::data::RouterInfo * router, bool peerTest) { SSUSession * session = nullptr; if (router) @@ -955,10 +960,10 @@ namespace ssu if (!router->UsesIntroducer ()) { // connect directly - session = new SSUSession (*this, remoteEndpoint, router); + session = new SSUSession (*this, remoteEndpoint, router, peerTest); m_Sessions[remoteEndpoint] = session; - LogPrint ("New SSU session to [", router->GetIdentHashAbbreviation (), "] ", - remoteEndpoint.address ().to_string (), ":", remoteEndpoint.port (), " created"); + LogPrint ("Creating new SSU session to [", router->GetIdentHashAbbreviation (), "] ", + remoteEndpoint.address ().to_string (), ":", remoteEndpoint.port ()); session->Connect (); } else @@ -970,7 +975,7 @@ namespace ssu 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 (), + LogPrint ("Creating new SSU session to [", router->GetIdentHashAbbreviation (), "] through introducer ", introducerEndpoint.address ().to_string (), ":", introducerEndpoint.port ()); session->ConnectThroughIntroducer (introducer); } @@ -1013,7 +1018,7 @@ namespace ssu auto session = it->second; m_Sessions.erase (it); m_Sessions[newEndpoint] = session; - LogPrint ("SSU session ressigned from ", oldEndpoint.address ().to_string (), ":", oldEndpoint.port (), + LogPrint ("SSU session reassigned from ", oldEndpoint.address ().to_string (), ":", oldEndpoint.port (), " to ", newEndpoint.address ().to_string (), ":", newEndpoint.port ()); } } diff --git a/SSU.h b/SSU.h index b299d852..88e3dd45 100644 --- a/SSU.h +++ b/SSU.h @@ -72,7 +72,7 @@ namespace ssu public: SSUSession (SSUServer& server, boost::asio::ip::udp::endpoint& remoteEndpoint, - const i2p::data::RouterInfo * router = nullptr); + const i2p::data::RouterInfo * router = nullptr, bool peerTest = false); void ProcessNextMessage (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint); ~SSUSession (); @@ -122,6 +122,7 @@ namespace ssu const i2p::data::RouterInfo * m_RemoteRouter; boost::asio::deadline_timer m_Timer; i2p::data::DHKeysPair * m_DHKeysPair; // X - for client and Y - for server + bool m_PeerTest; SessionState m_State; CryptoPP::CBC_Mode::Encryption m_Encryption; CryptoPP::CBC_Mode::Decryption m_Decryption; @@ -138,7 +139,7 @@ namespace ssu ~SSUServer (); void Start (); void Stop (); - SSUSession * GetSession (const i2p::data::RouterInfo * router); + SSUSession * GetSession (const i2p::data::RouterInfo * router, bool peerTest = false); SSUSession * FindSession (const i2p::data::RouterInfo * router); void DeleteSession (SSUSession * session); void DeleteAllSessions (); diff --git a/Transports.cpp b/Transports.cpp index 9d86d605..a0c968d6 100644 --- a/Transports.cpp +++ b/Transports.cpp @@ -270,7 +270,7 @@ namespace i2p { auto router = i2p::data::netdb.GetRandomRouter (); if (router && router->IsSSU () && m_SSUServer) - m_SSUServer->GetSession (router); + m_SSUServer->GetSession (router, true); // peer test } if (m_Timer) { From 3c6793745b80d5c782c7d979f5e9317ca5a5b99e Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 7 Apr 2014 20:34:22 -0400 Subject: [PATCH 12/21] don't delete initial SSU sessions --- Transports.cpp | 21 --------------------- Transports.h | 2 -- 2 files changed, 23 deletions(-) diff --git a/Transports.cpp b/Transports.cpp index a0c968d6..d427635c 100644 --- a/Transports.cpp +++ b/Transports.cpp @@ -92,7 +92,6 @@ namespace i2p m_DHKeysPairSupplier.Start (); 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) @@ -128,12 +127,6 @@ namespace i2p delete session.second; m_NTCPSessions.clear (); delete m_NTCPAcceptor; - - if (m_Timer) - { - m_Timer->cancel (); - delete m_Timer; - } if (m_SSUServer) { @@ -272,22 +265,8 @@ namespace i2p if (router && router->IsSSU () && m_SSUServer) m_SSUServer->GetSession (router, true); // peer test } - 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 (); - } - } i2p::data::DHKeysPair * Transports::GetNextDHKeysPair () { diff --git a/Transports.h b/Transports.h index bcec7690..b0ff8455 100644 --- a/Transports.h +++ b/Transports.h @@ -71,7 +71,6 @@ namespace i2p void PostMessage (const i2p::data::IdentHash& ident, i2p::I2NPMessage * msg); void DetectExternalIP (); - void HandleTimer (const boost::system::error_code& ecode); private: @@ -83,7 +82,6 @@ namespace i2p std::map m_NTCPSessions; i2p::ssu::SSUServer * m_SSUServer; - boost::asio::deadline_timer * m_Timer; DHKeysPairSupplier m_DHKeysPairSupplier; From c30dd2639a6141931e3db3d57a3bb62be6fd8ccc Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 7 Apr 2014 21:40:28 -0400 Subject: [PATCH 13/21] SSU timeout --- NTCPSession.cpp | 4 ++-- NTCPSession.h | 2 +- SSU.cpp | 21 ++++++++++++++++++++- SSU.h | 4 ++++ 4 files changed, 27 insertions(+), 4 deletions(-) diff --git a/NTCPSession.cpp b/NTCPSession.cpp index e21e8d18..ad71e3b0 100644 --- a/NTCPSession.cpp +++ b/NTCPSession.cpp @@ -519,7 +519,7 @@ namespace ntcp void NTCPSession::ScheduleTermination () { m_TerminationTimer.cancel (); - m_TerminationTimer.expires_from_now (boost::posix_time::seconds(TERMINATION_TIMEOUT)); + m_TerminationTimer.expires_from_now (boost::posix_time::seconds(NTCP_TERMINATION_TIMEOUT)); m_TerminationTimer.async_wait (boost::bind (&NTCPSession::HandleTerminationTimer, this, boost::asio::placeholders::error)); } @@ -528,7 +528,7 @@ namespace ntcp { if (ecode != boost::asio::error::operation_aborted) { - LogPrint ("No activity fo ", TERMINATION_TIMEOUT, " seconds"); + LogPrint ("No activity fo ", NTCP_TERMINATION_TIMEOUT, " seconds"); m_Socket.close (); } } diff --git a/NTCPSession.h b/NTCPSession.h index 4202c5c9..83396e11 100644 --- a/NTCPSession.h +++ b/NTCPSession.h @@ -61,7 +61,7 @@ namespace ntcp #pragma pack() - const int TERMINATION_TIMEOUT = 120; // 2 minutes + const int NTCP_TERMINATION_TIMEOUT = 120; // 2 minutes class NTCPSession { public: diff --git a/SSU.cpp b/SSU.cpp index 36817a65..2b0f2c7a 100644 --- a/SSU.cpp +++ b/SSU.cpp @@ -546,6 +546,7 @@ namespace ssu } if (m_PeerTest) SendPeerTest (); + ScheduleTermination (); } void SSUSession::Failed () @@ -557,7 +558,24 @@ namespace ssu m_Server.DeleteSession (this); // delete this } } - + + void SSUSession::ScheduleTermination () + { + m_Timer.cancel (); + m_Timer.expires_from_now (boost::posix_time::seconds(SSU_TERMINATION_TIMEOUT)); + m_Timer.async_wait (boost::bind (&SSUSession::HandleTerminationTimer, + this, boost::asio::placeholders::error)); + } + + void SSUSession::HandleTerminationTimer (const boost::system::error_code& ecode) + { + if (ecode != boost::asio::error::operation_aborted) + { + LogPrint ("SSU no activity fo ", SSU_TERMINATION_TIMEOUT, " seconds"); + Close (); + } + } + const uint8_t * SSUSession::GetIntroKey () const { if (m_RemoteRouter) @@ -587,6 +605,7 @@ namespace ssu void SSUSession::ProcessData (uint8_t * buf, size_t len) { + ScheduleTermination (); //uint8_t * start = buf; uint8_t flag = *buf; buf++; diff --git a/SSU.h b/SSU.h index 88e3dd45..196da273 100644 --- a/SSU.h +++ b/SSU.h @@ -30,6 +30,7 @@ namespace ssu const size_t SSU_MTU = 1484; const int SSU_CONNECT_TIMEOUT = 5; // 5 seconds + const int SSU_TERMINATION_TIMEOUT = 270; // 4.5 minutes // payload types (4 bits) const uint8_t PAYLOAD_TYPE_SESSION_REQUEST = 0; @@ -115,6 +116,9 @@ namespace ssu bool Validate (uint8_t * buf, size_t len, const uint8_t * macKey); const uint8_t * GetIntroKey () const; + void ScheduleTermination (); + void HandleTerminationTimer (const boost::system::error_code& ecode); + private: SSUServer& m_Server; From 40d54894295ca108b2ed98b1ba5cb7789f540dd6 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 7 Apr 2014 22:26:18 -0400 Subject: [PATCH 14/21] delete inactive SSU sessions --- SSU.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SSU.cpp b/SSU.cpp index 2b0f2c7a..1d1581a0 100644 --- a/SSU.cpp +++ b/SSU.cpp @@ -572,7 +572,7 @@ namespace ssu if (ecode != boost::asio::error::operation_aborted) { LogPrint ("SSU no activity fo ", SSU_TERMINATION_TIMEOUT, " seconds"); - Close (); + Failed (); } } From b3ee41bd91709593865541278a345db180a212f6 Mon Sep 17 00:00:00 2001 From: cpubug Date: Tue, 8 Apr 2014 11:11:48 +0400 Subject: [PATCH 15/21] replace CalcuateIdentHash to identity.Hash to avoid duplication --- Identity.cpp | 7 ------- Identity.h | 1 - LeaseSet.cpp | 2 +- RouterInfo.cpp | 2 +- Streaming.cpp | 2 +- 5 files changed, 3 insertions(+), 11 deletions(-) diff --git a/Identity.cpp b/Identity.cpp index 435c0c9b..c7c3ed0e 100644 --- a/Identity.cpp +++ b/Identity.cpp @@ -40,13 +40,6 @@ namespace data return *this; } - IdentHash CalculateIdentHash (const Identity& identity) - { - IdentHash hash; - CryptoPP::SHA256().CalculateDigest((uint8_t *)hash, (uint8_t *)&identity, sizeof (Identity)); - return hash; - } - Keys CreateRandomKeys () { Keys keys; diff --git a/Identity.h b/Identity.h index 902153dc..c5e90a16 100644 --- a/Identity.h +++ b/Identity.h @@ -79,7 +79,6 @@ namespace data uint8_t m_Hash[32]; }; - IdentHash CalculateIdentHash (const Identity& identity); Keys CreateRandomKeys (); void CreateRandomDHKeysPair (DHKeysPair * keys); // for transport sessions diff --git a/LeaseSet.cpp b/LeaseSet.cpp index 1383792e..7a7ebbc0 100644 --- a/LeaseSet.cpp +++ b/LeaseSet.cpp @@ -25,7 +25,7 @@ namespace data const H * header = (const H *)buf; m_Identity = header->destination; - m_IdentHash = CalculateIdentHash (m_Identity); + m_IdentHash = m_Identity.Hash(); memcpy (m_EncryptionKey, header->encryptionKey, 256); LogPrint ("LeaseSet num=", (int)header->num); diff --git a/RouterInfo.cpp b/RouterInfo.cpp index 735453c8..d3cbb865 100644 --- a/RouterInfo.cpp +++ b/RouterInfo.cpp @@ -34,7 +34,7 @@ namespace data void RouterInfo::SetRouterIdentity (const Identity& identity) { m_RouterIdentity = identity; - m_IdentHash = CalculateIdentHash (m_RouterIdentity); + m_IdentHash = m_RouterIdentity.Hash (); UpdateIdentHashBase64 (); UpdateRoutingKey (); m_Timestamp = i2p::util::GetMillisecondsSinceEpoch (); diff --git a/Streaming.cpp b/Streaming.cpp index 9291235a..090a0d04 100644 --- a/Streaming.cpp +++ b/Streaming.cpp @@ -345,7 +345,7 @@ namespace stream StreamingDestination::StreamingDestination (): m_LeaseSet (nullptr) { m_Keys = i2p::data::CreateRandomKeys (); - m_IdentHash = i2p::data::CalculateIdentHash (m_Keys.pub); + m_IdentHash = m_Keys.pub.Hash (); m_SigningPrivateKey.Initialize (i2p::crypto::dsap, i2p::crypto::dsaq, i2p::crypto::dsag, CryptoPP::Integer (m_Keys.signingPrivateKey, 20)); CryptoPP::DH dh (i2p::crypto::elgp, i2p::crypto::elgg); From 61001ef0470076b72583d36f8e7a075d68ea08b0 Mon Sep 17 00:00:00 2001 From: cpubug Date: Tue, 8 Apr 2014 11:24:34 +0400 Subject: [PATCH 16/21] added pointer check in RoutingDestination destructor --- Identity.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Identity.h b/Identity.h index c5e90a16..a4fb8f95 100644 --- a/Identity.h +++ b/Identity.h @@ -106,7 +106,7 @@ namespace data public: RoutingDestination (): m_ElGamalEncryption (nullptr) {}; - virtual ~RoutingDestination () { delete m_ElGamalEncryption; }; + virtual ~RoutingDestination () { if (m_ElGamalEncryption) delete m_ElGamalEncryption; }; virtual const IdentHash& GetIdentHash () const = 0; virtual const uint8_t * GetEncryptionPublicKey () const = 0; From ad8559d91162cab0000704b5d530fa5908dc0756 Mon Sep 17 00:00:00 2001 From: cpubug Date: Tue, 8 Apr 2014 21:01:14 +0400 Subject: [PATCH 17/21] fix gcc warning: deleting object of polymorphic class type 'i2p::stream::StreamingDestination' which has non-virtual destructor might cause undefined behaviour [-Wdelete-non-virtual-dtor] --- Identity.h | 1 + 1 file changed, 1 insertion(+) diff --git a/Identity.h b/Identity.h index a4fb8f95..ff35a7db 100644 --- a/Identity.h +++ b/Identity.h @@ -128,6 +128,7 @@ namespace data { public: + virtual ~LocalDestination() {}; virtual const IdentHash& GetIdentHash () const = 0; virtual const uint8_t * GetEncryptionPrivateKey () const = 0; virtual const uint8_t * GetEncryptionPublicKey () const = 0; From 702b352be9a64560481989391ae6d180c3335e8b Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 8 Apr 2014 13:25:19 -0400 Subject: [PATCH 18/21] use seesion key only for SesssionDestroy message --- SSU.cpp | 22 +++------------------- SSU.h | 2 +- 2 files changed, 4 insertions(+), 20 deletions(-) diff --git a/SSU.cpp b/SSU.cpp index 1d1581a0..7d21c8ca 100644 --- a/SSU.cpp +++ b/SSU.cpp @@ -58,6 +58,7 @@ namespace ssu case eSessionStateConfirmedSent: case eSessionStateEstablished: // most common case + ScheduleTermination (); ProcessMessage (buf, len, senderEndpoint); break; // establishing or testing @@ -164,12 +165,6 @@ namespace ssu case PAYLOAD_TYPE_SESSION_CREATED: ProcessSessionCreated (buf, len); break; - case PAYLOAD_TYPE_SESSION_DESTROYED: - { - LogPrint ("SSU session destroy with into key received"); - m_Server.DeleteSession (this); // delete this - break; - } case PAYLOAD_TYPE_PEER_TEST: LogPrint ("SSU peer test received"); // TODO: @@ -605,7 +600,6 @@ namespace ssu void SSUSession::ProcessData (uint8_t * buf, size_t len) { - ScheduleTermination (); //uint8_t * start = buf; uint8_t flag = *buf; buf++; @@ -806,21 +800,11 @@ namespace ssu CryptoPP::RandomNumberGenerator& rnd = i2p::context.GetRandomNumberGenerator (); rnd.GenerateBlock (iv, 16); // random iv 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); } - m_Server.Send (buf, 48, m_RemoteEndpoint); } void SSUSession::Send (i2p::I2NPMessage * msg) diff --git a/SSU.h b/SSU.h index 196da273..e680c7f1 100644 --- a/SSU.h +++ b/SSU.h @@ -30,7 +30,7 @@ namespace ssu const size_t SSU_MTU = 1484; const int SSU_CONNECT_TIMEOUT = 5; // 5 seconds - const int SSU_TERMINATION_TIMEOUT = 270; // 4.5 minutes + const int SSU_TERMINATION_TIMEOUT = 330; // 5.5 minutes // payload types (4 bits) const uint8_t PAYLOAD_TYPE_SESSION_REQUEST = 0; From 76cb75f7c06de3ce8d83099dbf875ea23f6a3f9d Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 8 Apr 2014 14:03:15 -0400 Subject: [PATCH 19/21] process relay intro --- SSU.cpp | 18 +++++++++++++++++- SSU.h | 1 + 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/SSU.cpp b/SSU.cpp index 7d21c8ca..f00cf622 100644 --- a/SSU.cpp +++ b/SSU.cpp @@ -115,7 +115,7 @@ namespace ssu } case PAYLOAD_TYPE_RELAY_INTRO: LogPrint ("SSU relay intro received"); - // TODO: + ProcessRelayIntro (buf + sizeof (SSUHeader), len - sizeof (SSUHeader)); break; default: LogPrint ("Unexpected SSU payload type ", (int)header->GetPayloadType ()); @@ -430,6 +430,22 @@ namespace ssu } } + void SSUSession::ProcessRelayIntro (uint8_t * buf, size_t len) + { + uint8_t size = *buf; + if (size == 4) + { + buf++; // size + boost::asio::ip::address_v4 address (be32toh (*(uint32_t* )buf)); + buf += 4; // address + uint16_t port = be16toh (*(uint16_t *)buf); + // send hole punch of 1 byte + m_Server.Send (buf, 1, boost::asio::ip::udp::endpoint (address, port)); + } + else + LogPrint ("Address size ", size, " is not supported"); + } + void SSUSession::FillHeaderAndEncrypt (uint8_t payloadType, uint8_t * buf, size_t len, const uint8_t * aesKey, const uint8_t * iv, const uint8_t * macKey) { diff --git a/SSU.h b/SSU.h index e680c7f1..6294f10e 100644 --- a/SSU.h +++ b/SSU.h @@ -100,6 +100,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 ProcessRelayResponse (uint8_t * buf, size_t len); + void ProcessRelayIntro (uint8_t * buf, size_t len); void Established (); void Failed (); void HandleConnectTimer (const boost::system::error_code& ecode); From 8de75a2a90e275554a507bdfaafe9c7437f1bad8 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 8 Apr 2014 15:35:08 -0400 Subject: [PATCH 20/21] save relay tag --- SSU.cpp | 30 ++++++++++++++++++++---------- SSU.h | 5 +++-- 2 files changed, 23 insertions(+), 12 deletions(-) diff --git a/SSU.cpp b/SSU.cpp index f00cf622..a036d1ff 100644 --- a/SSU.cpp +++ b/SSU.cpp @@ -18,7 +18,8 @@ namespace ssu SSUSession::SSUSession (SSUServer& server, boost::asio::ip::udp::endpoint& remoteEndpoint, const i2p::data::RouterInfo * router, bool peerTest ): m_Server (server), m_RemoteEndpoint (remoteEndpoint), m_RemoteRouter (router), - m_Timer (m_Server.GetService ()), m_PeerTest (peerTest), m_State (eSessionStateUnknown) + m_Timer (m_Server.GetService ()), m_PeerTest (peerTest), m_State (eSessionStateUnknown), + m_RelayTag (0) { m_DHKeysPair = i2p::transports.GetNextDHKeysPair (); } @@ -210,7 +211,7 @@ namespace ssu *(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); + m_RelayTag = be32toh (*(uint32_t *)payload); payload += 4; // relayTag payload += 4; // signed on time // decrypt DSA signature @@ -223,7 +224,7 @@ namespace ssu if (!verifier.VerifyMessage (signedData, 532, payload, 40)) LogPrint ("SSU signature verification failed"); - SendSessionConfirmed (y, ourAddress, relayTag); + SendSessionConfirmed (y, ourAddress); } void SSUSession::ProcessSessionConfirmed (uint8_t * buf, size_t len) @@ -350,7 +351,7 @@ namespace ssu m_Server.Send (buf, 368, m_RemoteEndpoint); } - void SSUSession::SendSessionConfirmed (const uint8_t * y, const uint8_t * ourAddress, uint32_t relayTag) + void SSUSession::SendSessionConfirmed (const uint8_t * y, const uint8_t * ourAddress) { uint8_t buf[480 + 18]; uint8_t * payload = buf + sizeof (SSUHeader); @@ -376,7 +377,7 @@ namespace ssu memcpy (signedData + 512, ourAddress, 6); // our address/port as seem by party *(uint32_t *)(signedData + 518) = htobe32 (m_RemoteEndpoint.address ().to_v4 ().to_ulong ()); // remote IP *(uint16_t *)(signedData + 522) = htobe16 (m_RemoteEndpoint.port ()); // remote port - *(uint32_t *)(signedData + 524) = htobe32 (relayTag); // relay tag + *(uint32_t *)(signedData + 524) = htobe32 (m_RelayTag); // relay tag *(uint32_t *)(signedData + 528) = htobe32 (signedOnTime); // signed on time i2p::context.Sign (signedData, 532, payload); // DSA signature @@ -992,11 +993,20 @@ namespace ssu { 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 ("Creating new SSU session to [", router->GetIdentHashAbbreviation (), - "] through introducer ", introducerEndpoint.address ().to_string (), ":", introducerEndpoint.port ()); - session->ConnectThroughIntroducer (introducer); + it = m_Sessions.find (introducerEndpoint); + if (it == m_Sessions.end ()) + { + session = new SSUSession (*this, introducerEndpoint, router); + m_Sessions[introducerEndpoint] = session; + LogPrint ("Creating new SSU session to [", router->GetIdentHashAbbreviation (), + "] through introducer ", introducerEndpoint.address ().to_string (), ":", introducerEndpoint.port ()); + session->ConnectThroughIntroducer (introducer); + } + else + { + LogPrint ("Session to introducer already exists"); + // TODO: + } } else LogPrint ("Router is unreachable, but not introducers presentd. Ignored"); diff --git a/SSU.h b/SSU.h index 6294f10e..ab60c71b 100644 --- a/SSU.h +++ b/SSU.h @@ -98,7 +98,7 @@ namespace ssu 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 SendSessionConfirmed (const uint8_t * y, const uint8_t * ourAddress); void ProcessRelayResponse (uint8_t * buf, size_t len); void ProcessRelayIntro (uint8_t * buf, size_t len); void Established (); @@ -128,7 +128,8 @@ namespace ssu boost::asio::deadline_timer m_Timer; i2p::data::DHKeysPair * m_DHKeysPair; // X - for client and Y - for server bool m_PeerTest; - SessionState m_State; + SessionState m_State; + uint32_t m_RelayTag; CryptoPP::CBC_Mode::Encryption m_Encryption; CryptoPP::CBC_Mode::Decryption m_Decryption; uint8_t m_SessionKey[32], m_MacKey[32]; From 6d42cccadc5391aab9d5bc7ca7adb830bad2e444 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 8 Apr 2014 21:56:34 -0400 Subject: [PATCH 21/21] extract SSU caps --- RouterInfo.cpp | 17 ++++++++++++++--- RouterInfo.h | 6 +++++- Transports.cpp | 12 ++++++------ 3 files changed, 25 insertions(+), 10 deletions(-) diff --git a/RouterInfo.cpp b/RouterInfo.cpp index d3cbb865..9a4f8f97 100644 --- a/RouterInfo.cpp +++ b/RouterInfo.cpp @@ -129,6 +129,8 @@ namespace data address.port = boost::lexical_cast(value); else if (!strcmp (key, "key")) Base64ToByteStream (value, strlen (value), address.key, 32); + else if (!strcmp (key, "caps")) + ExtractCaps (value); else if (key[0] == 'i') { // introducers @@ -191,7 +193,6 @@ namespace data void RouterInfo::ExtractCaps (const char * value) { - m_Caps = 0; const char * cap = value; while (*cap) { @@ -208,6 +209,12 @@ namespace data case 'R': m_Caps |= Caps::eReachable; break; + case 'B': + m_Caps |= Caps::eSSUTesting; + break; + case 'C': + m_Caps |= Caps::eSSUIntroducer; + break; default: ; } cap++; @@ -249,7 +256,10 @@ namespace data // caps WriteString ("caps", properties); properties << '='; - WriteString ("B", properties); // TODO: should be 'BC' for introducers + std::string caps; + if (IsPeerTesting ()) caps += 'B'; + if (IsIntroducer ()) caps += 'C'; + WriteString (caps, properties); properties << ';'; } else @@ -344,11 +354,12 @@ namespace data 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.cost = 10; // NTCP should have priority over SSU addr.date = 0; memcpy (addr.key, key, 32); m_Addresses.push_back(addr); m_SupportedTransports |= eSSUV4; + m_Caps |= eSSUTesting; // TODO } void RouterInfo::SetProperty (const char * key, const char * value) diff --git a/RouterInfo.h b/RouterInfo.h index 19521a6d..d730c5f8 100644 --- a/RouterInfo.h +++ b/RouterInfo.h @@ -29,7 +29,9 @@ namespace data { eFloodfill = 0x01, eHighBandwidth = 0x02, - eReachable = 0x04 + eReachable = 0x04, + eSSUTesting = 0x08, + eSSUIntroducer = 0x10 }; enum TransportStyle @@ -84,6 +86,8 @@ namespace data bool IsSSU (bool v4only = true) const; bool IsCompatible (const RouterInfo& other) const { return m_SupportedTransports & other.m_SupportedTransports; }; bool UsesIntroducer () const; + bool IsIntroducer () const { return m_Caps & eSSUIntroducer; }; + bool IsPeerTesting () const { return m_Caps & eSSUTesting; }; uint8_t GetCaps () const { return m_Caps; }; void SetUnreachable (bool unreachable) { m_IsUnreachable = unreachable; }; diff --git a/Transports.cpp b/Transports.cpp index d427635c..d7bdd634 100644 --- a/Transports.cpp +++ b/Transports.cpp @@ -123,16 +123,16 @@ namespace i2p void Transports::Stop () { - for (auto session: m_NTCPSessions) - delete session.second; - m_NTCPSessions.clear (); - delete m_NTCPAcceptor; - if (m_SSUServer) { m_SSUServer->Stop (); delete m_SSUServer; - } + } + + for (auto session: m_NTCPSessions) + delete session.second; + m_NTCPSessions.clear (); + delete m_NTCPAcceptor; m_DHKeysPairSupplier.Stop (); m_IsRunning = false;