diff --git a/AddressBook.cpp b/AddressBook.cpp index 2d0d2624..7fc39841 100644 --- a/AddressBook.cpp +++ b/AddressBook.cpp @@ -11,14 +11,14 @@ namespace i2p { -namespace data +namespace client { AddressBook::AddressBook (): m_IsLoaded (false), m_IsDowloading (false) { } - bool AddressBook::GetIdentHash (const std::string& address, IdentHash& ident) + bool AddressBook::GetIdentHash (const std::string& address, i2p::data::IdentHash& ident) { auto pos = address.find(".b32.i2p"); if (pos != std::string::npos) @@ -42,7 +42,7 @@ namespace data return false; } - const IdentHash * AddressBook::FindAddress (const std::string& address) + const i2p::data::IdentHash * AddressBook::FindAddress (const std::string& address) { if (!m_IsLoaded) LoadHosts (); @@ -57,7 +57,7 @@ namespace data void AddressBook::InsertAddress (const std::string& address, const std::string& base64) { - IdentityEx ident; + i2p::data::IdentityEx ident; ident.FromBase64 (base64); m_Addresses[address] = ident.GetIdentHash (); LogPrint (address,"->",ident.GetIdentHash ().ToBase32 (), ".b32.i2p added"); @@ -118,7 +118,7 @@ namespace data std::string name = s.substr(0, pos++); std::string addr = s.substr(pos); - IdentityEx ident; + i2p::data::IdentityEx ident; ident.FromBase64(addr); m_Addresses[name] = ident.GetIdentHash (); numAddresses++; diff --git a/AddressBook.h b/AddressBook.h index db9d2319..8131a032 100644 --- a/AddressBook.h +++ b/AddressBook.h @@ -11,15 +11,15 @@ namespace i2p { -namespace data +namespace client { class AddressBook { public: AddressBook (); - bool GetIdentHash (const std::string& address, IdentHash& ident); - const IdentHash * FindAddress (const std::string& address); + bool GetIdentHash (const std::string& address, i2p::data::IdentHash& ident); + const i2p::data::IdentHash * FindAddress (const std::string& address); void InsertAddress (const std::string& address, const std::string& base64); // for jump service private: @@ -27,7 +27,7 @@ namespace data void LoadHosts (); void LoadHostsFromI2P (); - std::map m_Addresses; + std::map m_Addresses; bool m_IsLoaded, m_IsDowloading; }; } diff --git a/ClientContext.cpp b/ClientContext.cpp index aa8e8c95..5937e8f8 100644 --- a/ClientContext.cpp +++ b/ClientContext.cpp @@ -27,7 +27,7 @@ namespace client { if (!m_SharedLocalDestination) { - m_SharedLocalDestination = new i2p::stream::StreamingDestination (false, i2p::data::SIGNING_KEY_TYPE_DSA_SHA1); // non-public, DSA + m_SharedLocalDestination = new ClientDestination (false, i2p::data::SIGNING_KEY_TYPE_DSA_SHA1); // non-public, DSA m_Destinations[m_SharedLocalDestination->GetIdentity ().GetIdentHash ()] = m_SharedLocalDestination; m_SharedLocalDestination->Start (); } @@ -41,7 +41,7 @@ namespace client std::string ircDestination = i2p::util::config::GetArg("-ircdest", ""); if (ircDestination.length () > 0) // ircdest is presented { - i2p::stream::StreamingDestination * localDestination = nullptr; + ClientDestination * localDestination = nullptr; std::string ircKeys = i2p::util::config::GetArg("-irckeys", ""); if (ircKeys.length () > 0) localDestination = i2p::client::context.LoadLocalDestination (ircKeys, false); @@ -125,7 +125,7 @@ namespace client #else it->path(); #endif - auto localDestination = new i2p::stream::StreamingDestination (fullPath, true); + auto localDestination = new ClientDestination (fullPath, true); m_Destinations[localDestination->GetIdentHash ()] = localDestination; numDestinations++; } @@ -134,25 +134,25 @@ namespace client LogPrint (numDestinations, " local destinations loaded"); } - i2p::stream::StreamingDestination * ClientContext::LoadLocalDestination (const std::string& filename, bool isPublic) + ClientDestination * ClientContext::LoadLocalDestination (const std::string& filename, bool isPublic) { - auto localDestination = new i2p::stream::StreamingDestination (i2p::util::filesystem::GetFullPath (filename), isPublic); + auto localDestination = new ClientDestination (i2p::util::filesystem::GetFullPath (filename), isPublic); std::unique_lock l(m_DestinationsMutex); m_Destinations[localDestination->GetIdentHash ()] = localDestination; localDestination->Start (); return localDestination; } - i2p::stream::StreamingDestination * ClientContext::CreateNewLocalDestination (bool isPublic, i2p::data::SigningKeyType sigType) + ClientDestination * ClientContext::CreateNewLocalDestination (bool isPublic, i2p::data::SigningKeyType sigType) { - auto localDestination = new i2p::stream::StreamingDestination (isPublic, sigType); + auto localDestination = new ClientDestination (isPublic, sigType); std::unique_lock l(m_DestinationsMutex); m_Destinations[localDestination->GetIdentHash ()] = localDestination; localDestination->Start (); return localDestination; } - void ClientContext::DeleteLocalDestination (i2p::stream::StreamingDestination * destination) + void ClientContext::DeleteLocalDestination (ClientDestination * destination) { if (!destination) return; auto it = m_Destinations.find (destination->GetIdentHash ()); @@ -168,7 +168,7 @@ namespace client } } - i2p::stream::StreamingDestination * ClientContext::CreateNewLocalDestination (const i2p::data::PrivateKeys& keys, bool isPublic) + ClientDestination * ClientContext::CreateNewLocalDestination (const i2p::data::PrivateKeys& keys, bool isPublic) { auto it = m_Destinations.find (keys.GetPublic ().GetIdentHash ()); if (it != m_Destinations.end ()) @@ -181,14 +181,14 @@ namespace client } return nullptr; } - auto localDestination = new i2p::stream::StreamingDestination (keys, isPublic); + auto localDestination = new ClientDestination (keys, isPublic); std::unique_lock l(m_DestinationsMutex); m_Destinations[keys.GetPublic ().GetIdentHash ()] = localDestination; localDestination->Start (); return localDestination; } - i2p::stream::StreamingDestination * ClientContext::FindLocalDestination (const i2p::data::IdentHash& destination) const + ClientDestination * ClientContext::FindLocalDestination (const i2p::data::IdentHash& destination) const { auto it = m_Destinations.find (destination); if (it != m_Destinations.end ()) diff --git a/ClientContext.h b/ClientContext.h index 8fbef267..da65f3f8 100644 --- a/ClientContext.h +++ b/ClientContext.h @@ -7,6 +7,7 @@ #include "SOCKS.h" #include "I2PTunnel.h" #include "SAM.h" +#include "AddressBook.h" namespace i2p { @@ -22,12 +23,14 @@ namespace client void Start (); void Stop (); - i2p::stream::StreamingDestination * GetSharedLocalDestination () const { return m_SharedLocalDestination; }; - i2p::stream::StreamingDestination * CreateNewLocalDestination (bool isPublic = true, i2p::data::SigningKeyType sigType = i2p::data::SIGNING_KEY_TYPE_DSA_SHA1); // transient - i2p::stream::StreamingDestination * CreateNewLocalDestination (const i2p::data::PrivateKeys& keys, bool isPublic = true); - void DeleteLocalDestination (i2p::stream::StreamingDestination * destination); - i2p::stream::StreamingDestination * FindLocalDestination (const i2p::data::IdentHash& destination) const; - i2p::stream::StreamingDestination * LoadLocalDestination (const std::string& filename, bool isPublic); + ClientDestination * GetSharedLocalDestination () const { return m_SharedLocalDestination; }; + ClientDestination * CreateNewLocalDestination (bool isPublic = true, i2p::data::SigningKeyType sigType = i2p::data::SIGNING_KEY_TYPE_DSA_SHA1); // transient + ClientDestination * CreateNewLocalDestination (const i2p::data::PrivateKeys& keys, bool isPublic = true); + void DeleteLocalDestination (ClientDestination * destination); + ClientDestination * FindLocalDestination (const i2p::data::IdentHash& destination) const; + ClientDestination * LoadLocalDestination (const std::string& filename, bool isPublic); + + AddressBook& GetAddressBook () { return m_AddressBook; }; private: @@ -36,8 +39,10 @@ namespace client private: std::mutex m_DestinationsMutex; - std::map m_Destinations; - i2p::stream::StreamingDestination * m_SharedLocalDestination; + std::map m_Destinations; + ClientDestination * m_SharedLocalDestination; + + AddressBook m_AddressBook; i2p::proxy::HTTPProxy * m_HttpProxy; i2p::proxy::SOCKSProxy * m_SocksProxy; diff --git a/Daemon.cpp b/Daemon.cpp index 13f99db6..3836bd96 100644 --- a/Daemon.cpp +++ b/Daemon.cpp @@ -72,6 +72,8 @@ namespace i2p if (i2p::util::config::GetArg("-unreachable", 0)) i2p::context.SetUnreachable (); + i2p::context.SetSupportsV6 (i2p::util::config::GetArg("-v6", 0)); + LogPrint("CMD parameters:"); for (int i = 0; i < argc; ++i) LogPrint(i, " ", argv[i]); @@ -103,7 +105,7 @@ namespace i2p LogPrint("HTTP Server started"); i2p::data::netdb.Start(); LogPrint("NetDB started"); - i2p::transports.Start(); + i2p::transport::transports.Start(); LogPrint("Transports started"); i2p::tunnel::tunnels.Start(); LogPrint("Tunnels started"); @@ -120,7 +122,7 @@ namespace i2p LogPrint("Client stoped"); i2p::tunnel::tunnels.Stop(); LogPrint("Tunnels stoped"); - i2p::transports.Stop(); + i2p::transport::transports.Stop(); LogPrint("Transports stoped"); i2p::data::netdb.Stop(); LogPrint("NetDB stoped"); diff --git a/Datagram.cpp b/Datagram.cpp new file mode 100644 index 00000000..a154fc5b --- /dev/null +++ b/Datagram.cpp @@ -0,0 +1,132 @@ +#include +#include +#include +#include +#include "Log.h" +#include "TunnelBase.h" +#include "RouterContext.h" +#include "Destination.h" +#include "Datagram.h" + +namespace i2p +{ +namespace datagram +{ + DatagramDestination::DatagramDestination (i2p::client::ClientDestination& owner): + m_Owner (owner) + { + } + + void DatagramDestination::SendDatagramTo (const uint8_t * payload, size_t len, const i2p::data::LeaseSet& remote) + { + uint8_t buf[MAX_DATAGRAM_SIZE]; + auto identityLen = m_Owner.GetIdentity ().ToBuffer (buf, MAX_DATAGRAM_SIZE); + uint8_t * signature = buf + identityLen; + auto signatureLen = m_Owner.GetIdentity ().GetSignatureLen (); + uint8_t * buf1 = signature + signatureLen; + size_t headerLen = identityLen + signatureLen; + + memcpy (buf1, payload, len); + if (m_Owner.GetIdentity ().GetSigningKeyType () == i2p::data::SIGNING_KEY_TYPE_DSA_SHA1) + { + uint8_t hash[32]; + CryptoPP::SHA256().CalculateDigest (hash, buf1, len); + m_Owner.Sign (hash, 32, signature); + } + else + m_Owner.Sign (buf1, len, signature); + + auto service = m_Owner.GetService (); + if (service) + service->post (boost::bind (&DatagramDestination::SendMsg, this, + CreateDataMessage (buf, len + headerLen), remote)); + else + LogPrint ("Failed to send datagram. Destination is not running"); + } + + void DatagramDestination::SendMsg (I2NPMessage * msg, const i2p::data::LeaseSet& remote) + { + auto leases = remote.GetNonExpiredLeases (); + if (!leases.empty ()) + { + std::vector msgs; + uint32_t i = i2p::context.GetRandomNumberGenerator ().GenerateWord32 (0, leases.size () - 1); + auto garlic = m_Owner.WrapMessage (remote, msg, true); + msgs.push_back (i2p::tunnel::TunnelMessageBlock + { + i2p::tunnel::eDeliveryTypeTunnel, + leases[i].tunnelGateway, leases[i].tunnelID, + garlic + }); + m_Owner.SendTunnelDataMsgs (msgs); + } + else + { + LogPrint ("Failed to send datagram. All leases expired"); + DeleteI2NPMessage (msg); + } + } + + void DatagramDestination::HandleDatagram (const uint8_t * buf, size_t len) + { + i2p::data::IdentityEx identity; + size_t identityLen = identity.FromBuffer (buf, len); + const uint8_t * signature = buf + identityLen; + size_t headerLen = identityLen + identity.GetSignatureLen (); + + bool verified = false; + if (identity.GetSigningKeyType () == i2p::data::SIGNING_KEY_TYPE_DSA_SHA1) + { + uint8_t hash[32]; + CryptoPP::SHA256().CalculateDigest (hash, buf + headerLen, len - headerLen); + verified = identity.Verify (hash, 32, signature); + } + else + verified = identity.Verify (buf + headerLen, len - headerLen, signature); + + if (verified) + { + // TODO: invoke datagram handler + } + else + LogPrint ("Datagram signature verification failed"); + } + + void DatagramDestination::HandleDataMessagePayload (const uint8_t * buf, size_t len) + { + // unzip it + CryptoPP::Gunzip decompressor; + decompressor.Put (buf, len); + decompressor.MessageEnd(); + uint8_t uncompressed[MAX_DATAGRAM_SIZE]; + auto uncompressedLen = decompressor.MaxRetrievable (); + if (uncompressedLen <= MAX_DATAGRAM_SIZE) + { + decompressor.Get (uncompressed, uncompressedLen); + HandleDatagram (uncompressed, uncompressedLen); + } + else + LogPrint ("Received datagram size ", uncompressedLen, " exceeds max size"); + + } + + I2NPMessage * DatagramDestination::CreateDataMessage (const uint8_t * payload, size_t len) + { + I2NPMessage * msg = NewI2NPMessage (); + CryptoPP::Gzip compressor; // default level + compressor.Put (payload, len); + compressor.MessageEnd(); + int size = compressor.MaxRetrievable (); + uint8_t * buf = msg->GetPayload (); + *(uint32_t *)buf = htobe32 (size); // length + buf += 4; + compressor.Get (buf, size); + memset (buf + 4, 0, 4); // source and destination are zeroes + buf[9] = i2p::client::PROTOCOL_TYPE_DATAGRAM; // datagram protocol + msg->len += size + 4; + FillI2NPMessageHeader (msg, eI2NPData); + return msg; + } +} +} + diff --git a/Datagram.h b/Datagram.h new file mode 100644 index 00000000..fd4c3cc4 --- /dev/null +++ b/Datagram.h @@ -0,0 +1,41 @@ +#ifndef DATAGRAM_H__ +#define DATAGRAM_H__ + +#include +#include "LeaseSet.h" +#include "I2NPProtocol.h" + +namespace i2p +{ +namespace client +{ + class ClientDestination; +} +namespace datagram +{ + const size_t MAX_DATAGRAM_SIZE = 32768; + class DatagramDestination + { + public: + + DatagramDestination (i2p::client::ClientDestination& owner); + ~DatagramDestination () {}; + + void SendDatagramTo (const uint8_t * payload, size_t len, const i2p::data::LeaseSet& remote); + void HandleDataMessagePayload (const uint8_t * buf, size_t len); + + private: + + I2NPMessage * CreateDataMessage (const uint8_t * payload, size_t len); + void SendMsg (I2NPMessage * msg, const i2p::data::LeaseSet& remote); + void HandleDatagram (const uint8_t * buf, size_t len); + + private: + + i2p::client::ClientDestination& m_Owner; + }; +} +} + +#endif + diff --git a/Destination.cpp b/Destination.cpp index da877f53..eb793d7f 100644 --- a/Destination.cpp +++ b/Destination.cpp @@ -1,7 +1,6 @@ #include #include #include -#include #include "Log.h" #include "util.h" #include "NetDb.h" @@ -13,7 +12,8 @@ namespace client { ClientDestination::ClientDestination (bool isPublic, i2p::data::SigningKeyType sigType): m_IsRunning (false), m_Thread (nullptr), m_Service (nullptr), m_Work (nullptr), - m_CurrentOutboundTunnel (nullptr), m_LeaseSet (nullptr), m_IsPublic (isPublic) + m_CurrentOutboundTunnel (nullptr), m_LeaseSet (nullptr), m_IsPublic (isPublic), + m_DatagramDestination (nullptr) { m_Keys = i2p::data::PrivateKeys::CreateRandomKeys (sigType); CryptoPP::DH dh (i2p::crypto::elgp, i2p::crypto::elgg); @@ -21,11 +21,13 @@ namespace client m_Pool = i2p::tunnel::tunnels.CreateTunnelPool (*this, 3); // 3-hops tunnel if (m_IsPublic) LogPrint ("Local address ", GetIdentHash ().ToBase32 (), ".b32.i2p created"); + m_StreamingDestination = new i2p::stream::StreamingDestination (*this); // TODO: } ClientDestination::ClientDestination (const std::string& fullPath, bool isPublic): m_IsRunning (false), m_Thread (nullptr), m_Service (nullptr), m_Work (nullptr), - m_CurrentOutboundTunnel (nullptr), m_LeaseSet (nullptr), m_IsPublic (isPublic) + m_CurrentOutboundTunnel (nullptr), m_LeaseSet (nullptr), m_IsPublic (isPublic), + m_DatagramDestination (nullptr) { std::ifstream s(fullPath.c_str (), std::ifstream::binary); if (s.is_open ()) @@ -56,17 +58,20 @@ namespace client CryptoPP::DH dh (i2p::crypto::elgp, i2p::crypto::elgg); dh.GenerateKeyPair(i2p::context.GetRandomNumberGenerator (), m_EncryptionPrivateKey, m_EncryptionPublicKey); m_Pool = i2p::tunnel::tunnels.CreateTunnelPool (*this, 3); // 3-hops tunnel + m_StreamingDestination = new i2p::stream::StreamingDestination (*this); // TODO: } ClientDestination::ClientDestination (const i2p::data::PrivateKeys& keys, bool isPublic): m_IsRunning (false), m_Thread (nullptr), m_Service (nullptr), m_Work (nullptr), - m_Keys (keys), m_CurrentOutboundTunnel (nullptr), m_LeaseSet (nullptr), m_IsPublic (isPublic) + m_Keys (keys), m_CurrentOutboundTunnel (nullptr), m_LeaseSet (nullptr), m_IsPublic (isPublic), + m_DatagramDestination (nullptr) { CryptoPP::DH dh (i2p::crypto::elgp, i2p::crypto::elgg); dh.GenerateKeyPair(i2p::context.GetRandomNumberGenerator (), m_EncryptionPrivateKey, m_EncryptionPublicKey); m_Pool = i2p::tunnel::tunnels.CreateTunnelPool (*this, 3); // 3-hops tunnel if (m_IsPublic) LogPrint ("Local address ", GetIdentHash ().ToBase32 (), ".b32.i2p created"); + m_StreamingDestination = new i2p::stream::StreamingDestination (*this); // TODO: } ClientDestination::~ClientDestination () @@ -79,6 +84,8 @@ namespace client delete m_LeaseSet; delete m_Work; delete m_Service; + delete m_StreamingDestination; + delete m_DatagramDestination; } void ClientDestination::Run () @@ -94,10 +101,12 @@ namespace client m_Pool->SetActive (true); m_IsRunning = true; m_Thread = new std::thread (std::bind (&ClientDestination::Run, this)); + m_StreamingDestination->Start (); } void ClientDestination::Stop () { + m_StreamingDestination->Stop (); if (m_Pool) i2p::tunnel::tunnels.StopTunnelPool (m_Pool); m_IsRunning = false; @@ -238,135 +247,57 @@ namespace client uint32_t length = be32toh (*(uint32_t *)buf); buf += 4; // we assume I2CP payload - if (buf[9] == 6) // streaming protocol - { - // unzip it - CryptoPP::Gunzip decompressor; - decompressor.Put (buf, length); - decompressor.MessageEnd(); - i2p::stream::Packet * uncompressed = new i2p::stream::Packet; - uncompressed->offset = 0; - uncompressed->len = decompressor.MaxRetrievable (); - if (uncompressed->len <= i2p::stream::MAX_PACKET_SIZE) - { - decompressor.Get (uncompressed->buf, uncompressed->len); - HandleNextPacket (uncompressed); - } - else - { - LogPrint ("Received packet size ", uncompressed->len, " exceeds max packet size. Skipped"); - decompressor.Skip (); - delete uncompressed; - } - } - else - LogPrint ("Data: unexpected protocol ", buf[9]); - } - - I2NPMessage * ClientDestination::CreateDataMessage (const uint8_t * payload, size_t len) - { - I2NPMessage * msg = NewI2NPShortMessage (); - CryptoPP::Gzip compressor; - if (len <= i2p::stream::COMPRESSION_THRESHOLD_SIZE) - compressor.SetDeflateLevel (CryptoPP::Gzip::MIN_DEFLATE_LEVEL); - else - compressor.SetDeflateLevel (CryptoPP::Gzip::DEFAULT_DEFLATE_LEVEL); - compressor.Put (payload, len); - compressor.MessageEnd(); - int size = compressor.MaxRetrievable (); - uint8_t * buf = msg->GetPayload (); - *(uint32_t *)buf = htobe32 (size); // length - buf += 4; - compressor.Get (buf, size); - memset (buf + 4, 0, 4); // source and destination ports. TODO: fill with proper values later - buf[9] = 6; // streaming protocol - msg->len += size + 4; - FillI2NPMessageHeader (msg, eI2NPData); - - return msg; - } -} - -namespace stream -{ - - void StreamingDestination::Start () - { - ClientDestination::Start (); - } - - void StreamingDestination::Stop () - { - ResetAcceptor (); + switch (buf[9]) { - std::unique_lock l(m_StreamsMutex); - for (auto it: m_Streams) - delete it.second; - m_Streams.clear (); - } - ClientDestination::Stop (); + case PROTOCOL_TYPE_STREAMING: + // streaming protocol + if (m_StreamingDestination) + m_StreamingDestination->HandleDataMessagePayload (buf, length); + else + LogPrint ("Missing streaming destination"); + break; + case PROTOCOL_TYPE_DATAGRAM: + // datagram protocol + if (m_DatagramDestination) + m_DatagramDestination->HandleDataMessagePayload (buf, length); + else + LogPrint ("Missing streaming destination"); + break; + default: + LogPrint ("Data: unexpected protocol ", buf[9]); + } } - - void StreamingDestination::HandleNextPacket (Packet * packet) + i2p::stream::Stream * ClientDestination::CreateStream (const i2p::data::LeaseSet& remote, int port) { - uint32_t sendStreamID = packet->GetSendStreamID (); - if (sendStreamID) - { - auto it = m_Streams.find (sendStreamID); - if (it != m_Streams.end ()) - it->second->HandleNextPacket (packet); - else - { - LogPrint ("Unknown stream ", sendStreamID); - delete packet; - } - } - else // new incoming stream - { - auto incomingStream = CreateNewIncomingStream (); - incomingStream->HandleNextPacket (packet); - if (m_Acceptor != nullptr) - m_Acceptor (incomingStream); - else - { - LogPrint ("Acceptor for incoming stream is not set"); - DeleteStream (incomingStream); - } - } - } + if (m_StreamingDestination) + return m_StreamingDestination->CreateNewOutgoingStream (remote, port); + return nullptr; + } - Stream * StreamingDestination::CreateNewOutgoingStream (const i2p::data::LeaseSet& remote) + void ClientDestination::AcceptStreams (const std::function& acceptor) { - Stream * s = new Stream (*GetService (), *this, remote); - std::unique_lock l(m_StreamsMutex); - m_Streams[s->GetRecvStreamID ()] = s; - return s; - } + if (m_StreamingDestination) + m_StreamingDestination->SetAcceptor (acceptor); + } - Stream * StreamingDestination::CreateNewIncomingStream () + void ClientDestination::StopAcceptingStreams () { - Stream * s = new Stream (*GetService (), *this); - std::unique_lock l(m_StreamsMutex); - m_Streams[s->GetRecvStreamID ()] = s; - return s; + if (m_StreamingDestination) + m_StreamingDestination->ResetAcceptor (); } - void StreamingDestination::DeleteStream (Stream * stream) + bool ClientDestination::IsAcceptingStreams () const { - if (stream) - { - std::unique_lock l(m_StreamsMutex); - auto it = m_Streams.find (stream->GetRecvStreamID ()); - if (it != m_Streams.end ()) - { - m_Streams.erase (it); - if (GetService ()) - GetService ()->post ([stream](void) { delete stream; }); - else - delete stream; - } - } + if (m_StreamingDestination) + return m_StreamingDestination->IsAcceptorSet (); + return false; } -} + + void ClientDestination::CreateDatagramDestination () + { + if (!m_DatagramDestination) + m_DatagramDestination = new i2p::datagram::DatagramDestination (*this); + } +} } diff --git a/Destination.h b/Destination.h index 6b41b231..35a1653b 100644 --- a/Destination.h +++ b/Destination.h @@ -9,11 +9,16 @@ #include "LeaseSet.h" #include "Garlic.h" #include "Streaming.h" +#include "Datagram.h" namespace i2p { namespace client { + const uint8_t PROTOCOL_TYPE_STREAMING = 6; + const uint8_t PROTOCOL_TYPE_DATAGRAM = 17; + const uint8_t PROTOCOL_TYPE_RAW = 18; + class ClientDestination: public i2p::garlic::GarlicDestination { public: @@ -34,6 +39,17 @@ namespace client const i2p::data::LeaseSet * FindLeaseSet (const i2p::data::IdentHash& ident); void SendTunnelDataMsgs (const std::vector& msgs); + // streaming + i2p::stream::StreamingDestination * GetStreamingDestination () const { return m_StreamingDestination; }; + i2p::stream::Stream * CreateStream (const i2p::data::LeaseSet& remote, int port = 0); + void AcceptStreams (const std::function& acceptor); + void StopAcceptingStreams (); + bool IsAcceptingStreams () const; + + // datagram + i2p::datagram::DatagramDestination * GetDatagramDestination () const { return m_DatagramDestination; }; + void CreateDatagramDestination (); + // implements LocalDestination const i2p::data::PrivateKeys& GetPrivateKeys () const { return m_Keys; }; const uint8_t * GetEncryptionPrivateKey () const { return m_EncryptionPrivateKey; }; @@ -50,11 +66,6 @@ namespace client // I2CP void HandleDataMessage (const uint8_t * buf, size_t len); - I2NPMessage * CreateDataMessage (const uint8_t * payload, size_t len); - - protected: - - virtual void HandleNextPacket (i2p::stream::Packet * packet) = 0; // TODO private: @@ -77,55 +88,15 @@ namespace client i2p::data::LeaseSet * m_LeaseSet; bool m_IsPublic; + i2p::stream::StreamingDestination * m_StreamingDestination; + i2p::datagram::DatagramDestination * m_DatagramDestination; + public: // for HTTP only int GetNumRemoteLeaseSets () const { return m_RemoteLeaseSets.size (); }; }; -} - -namespace stream -{ - class StreamingDestination: public i2p::client::ClientDestination - { - public: - - StreamingDestination (bool isPublic, i2p::data::SigningKeyType sigType): - ClientDestination (isPublic, sigType) {}; - StreamingDestination (const std::string& fullPath, bool isPublic): - ClientDestination (fullPath, isPublic) {}; - StreamingDestination (const i2p::data::PrivateKeys& keys, bool isPublic): - ClientDestination (keys, isPublic) {}; - ~StreamingDestination () {}; - - void Start (); - void Stop (); - - Stream * CreateNewOutgoingStream (const i2p::data::LeaseSet& remote); - void DeleteStream (Stream * stream); - void SetAcceptor (const std::function& acceptor) { m_Acceptor = acceptor; }; - void ResetAcceptor () { m_Acceptor = nullptr; }; - bool IsAcceptorSet () const { return m_Acceptor != nullptr; }; - - // ClientDestination - void HandleNextPacket (Packet * packet); - - private: - - Stream * CreateNewIncomingStream (); - - private: - - std::mutex m_StreamsMutex; - std::map m_Streams; - std::function m_Acceptor; - - public: - - // for HTTP only - const decltype(m_Streams)& GetStreams () const { return m_Streams; }; - }; -} +} } #endif diff --git a/HTTPProxy.cpp b/HTTPProxy.cpp index 7ad64cfa..ae644b6a 100644 --- a/HTTPProxy.cpp +++ b/HTTPProxy.cpp @@ -1,7 +1,7 @@ #include #include -#include "NetDb.h" +#include "ClientContext.h" #include "HTTPProxy.h" namespace i2p @@ -52,10 +52,11 @@ namespace proxy } path=m[4].str(); } - LogPrint("server is: ",server, "\n path is: ",path); + LogPrint("server is: ",server, " port is: ", port, "\n path is: ",path); r.uri = path; r.method = method; r.host = server; + r.port = boost::lexical_cast(port); } @@ -73,12 +74,12 @@ namespace proxy { LogPrint ("Jump service for ", r.host, " found. Inserting to address book"); auto base64 = r.uri.substr (addressPos + 1); - i2p::data::netdb.GetAddressBook ().InsertAddress (r.host, base64); + i2p::client::context.GetAddressBook ().InsertAddress (r.host, base64); } } - LogPrint("Requesting ", r.host, " with path ", r.uri, " and method ", r.method); - SendToAddress (r.host, m_Buffer, m_BufferLen); + LogPrint("Requesting ", r.host, ":", r.port, " with path ", r.uri, " and method ", r.method); + SendToAddress (r.host, r.port, m_Buffer, m_BufferLen); } } diff --git a/HTTPServer.cpp b/HTTPServer.cpp index b08948d1..57656334 100644 --- a/HTTPServer.cpp +++ b/HTTPServer.cpp @@ -517,7 +517,7 @@ namespace util if (m_Stream) { m_Stream->Close (); - i2p::client::context.GetSharedLocalDestination ()->DeleteStream (m_Stream); + i2p::stream::DeleteStream (m_Stream); m_Stream = nullptr; } m_Socket->close (); @@ -644,7 +644,10 @@ namespace util switch (address.transportStyle) { case i2p::data::RouterInfo::eTransportNTCP: - s << "NTCP  "; + if (address.host.is_v6 ()) + s << "NTCP6  "; + else + s << "NTCP  "; break; case i2p::data::RouterInfo::eTransportSSU: s << "SSU     "; @@ -699,14 +702,14 @@ namespace util void HTTPConnection::ShowTransports (std::stringstream& s) { s << "NTCP
"; - for (auto it: i2p::transports.GetNTCPSessions ()) + for (auto it: i2p::transport::transports.GetNTCPSessions ()) { - // RouterInfo of incoming connection doesn't have address - bool outgoing = it.second->GetRemoteRouterInfo ().GetNTCPAddress (); if (it.second->IsEstablished ()) { + // incoming connection doesn't have remote RI + bool outgoing = it.second->GetRemoteRouter (); if (outgoing) s << "-->"; - s << it.second->GetRemoteRouterInfo ().GetIdentHashAbbreviation () << ": " + s << it.second->GetRemoteIdentity ().GetIdentHash ().ToBase64 ().substr (0, 4) << ": " << it.second->GetSocket ().remote_endpoint().address ().to_string (); if (!outgoing) s << "-->"; s << " [" << it.second->GetNumSentBytes () << ":" << it.second->GetNumReceivedBytes () << "]"; @@ -714,7 +717,7 @@ namespace util } s << std::endl; } - auto ssuServer = i2p::transports.GetSSUServer (); + auto ssuServer = i2p::transport::transports.GetSSUServer (); if (ssuServer) { s << "
SSU
"; @@ -813,7 +816,7 @@ namespace util } } s << "
Streams:
"; - for (auto it: dest->GetStreams ()) + for (auto it: dest->GetStreamingDestination ()->GetStreams ()) { s << it.first << "->" << it.second->GetRemoteIdentity ().GetIdentHash ().ToBase32 () << ".b32.i2p "; s << " [" << it.second->GetNumSentBytes () << ":" << it.second->GetNumReceivedBytes () << "]"; @@ -839,45 +842,56 @@ namespace util { std::string request = "GET " + uri + " HTTP/1.1\r\nHost:" + address + "\r\n"; LogPrint("HTTP Client Request: ", request); - SendToAddress (address, request.c_str (), request.size ()); + SendToAddress (address, 80, request.c_str (), request.size ()); } - void HTTPConnection::SendToAddress (const std::string& address, const char * buf, size_t len) + void HTTPConnection::SendToAddress (const std::string& address, int port, const char * buf, size_t len) { i2p::data::IdentHash destination; - if (!i2p::data::netdb.GetAddressBook ().GetIdentHash (address, destination)) + if (!i2p::client::context.GetAddressBook ().GetIdentHash (address, destination)) { LogPrint ("Unknown address ", address); SendReply ("" + itoopieImage + "
Unknown address " + address + "", 404); return; } - SendToDestination (destination, buf, len); - } - - void HTTPConnection::SendToDestination (const i2p::data::IdentHash& destination, const char * buf, size_t len) - { auto leaseSet = i2p::client::context.GetSharedLocalDestination ()->FindLeaseSet (destination); - if (!leaseSet || !leaseSet->HasNonExpiredLeases ()) + if (leaseSet && leaseSet->HasNonExpiredLeases ()) + SendToDestination (leaseSet, port, buf, len); + else { i2p::data::netdb.RequestDestination (destination, true, i2p::client::context.GetSharedLocalDestination ()->GetTunnelPool ()); - std::this_thread::sleep_for (std::chrono::seconds(10)); // wait for 10 seconds - leaseSet = i2p::client::context.GetSharedLocalDestination ()->FindLeaseSet (destination); - if (!leaseSet || !leaseSet->HasNonExpiredLeases ()) // still no LeaseSet - { + m_Timer.expires_from_now (boost::posix_time::seconds(HTTP_DESTINATION_REQUEST_TIMEOUT)); + m_Timer.async_wait (boost::bind (&HTTPConnection::HandleDestinationRequestTimeout, + this, boost::asio::placeholders::error, destination, port, buf, len)); + } + } + + void HTTPConnection::HandleDestinationRequestTimeout (const boost::system::error_code& ecode, + i2p::data::IdentHash destination, int port, const char * buf, size_t len) + { + if (ecode != boost::asio::error::operation_aborted) + { + auto leaseSet = i2p::client::context.GetSharedLocalDestination ()->FindLeaseSet (destination); + if (leaseSet && leaseSet->HasNonExpiredLeases ()) + SendToDestination (leaseSet, port, buf, len); + else + // still no LeaseSet SendReply (leaseSet ? "" + itoopieImage + "
Leases expired" : "" + itoopieImage + "LeaseSet not found", 504); - return; - } } + } + + void HTTPConnection::SendToDestination (const i2p::data::LeaseSet * remote, int port, const char * buf, size_t len) + { if (!m_Stream) - m_Stream = i2p::client::context.GetSharedLocalDestination ()->CreateNewOutgoingStream (*leaseSet); + m_Stream = i2p::client::context.GetSharedLocalDestination ()->CreateStream (*remote, port); if (m_Stream) { m_Stream->Send ((uint8_t *)buf, len); AsyncStreamReceive (); } - } - + } + void HTTPConnection::AsyncStreamReceive () { if (m_Stream) diff --git a/HTTPServer.h b/HTTPServer.h index 7559b975..c7d6b0e4 100644 --- a/HTTPServer.h +++ b/HTTPServer.h @@ -5,6 +5,7 @@ #include #include #include +#include "LeaseSet.h" #include "Streaming.h" namespace i2p @@ -12,6 +13,7 @@ namespace i2p namespace util { const size_t HTTP_CONNECTION_BUFFER_SIZE = 8192; + const int HTTP_DESTINATION_REQUEST_TIMEOUT = 10; // in seconds class HTTPConnection { protected: @@ -27,6 +29,7 @@ namespace util std::string method; std::string uri; std::string host; + int port; int http_version_major; int http_version_minor; std::vector
headers; @@ -43,7 +46,8 @@ namespace util public: HTTPConnection (boost::asio::ip::tcp::socket * socket): - m_Socket (socket), m_Stream (nullptr), m_BufferLen (0) { Receive (); }; + m_Socket (socket), m_Timer (socket->get_io_service ()), + m_Stream (nullptr), m_BufferLen (0) { Receive (); }; virtual ~HTTPConnection() { delete m_Socket; } private: @@ -74,6 +78,7 @@ namespace util protected: boost::asio::ip::tcp::socket * m_Socket; + boost::asio::deadline_timer m_Timer; i2p::stream::Stream * m_Stream; char m_Buffer[HTTP_CONNECTION_BUFFER_SIZE + 1], m_StreamBuffer[HTTP_CONNECTION_BUFFER_SIZE + 1]; size_t m_BufferLen; @@ -84,8 +89,10 @@ namespace util virtual void RunRequest (); void HandleDestinationRequest(const std::string& address, const std::string& uri); - void SendToAddress (const std::string& address, const char * buf, size_t len); - void SendToDestination (const i2p::data::IdentHash& destination, const char * buf, size_t len); + void SendToAddress (const std::string& address, int port, const char * buf, size_t len); + void HandleDestinationRequestTimeout (const boost::system::error_code& ecode, + i2p::data::IdentHash destination, int port, const char * buf, size_t len); + void SendToDestination (const i2p::data::LeaseSet * remote, int port, const char * buf, size_t len); public: diff --git a/I2NPProtocol.cpp b/I2NPProtocol.cpp index 12ee678f..75606295 100644 --- a/I2NPProtocol.cpp +++ b/I2NPProtocol.cpp @@ -13,9 +13,10 @@ #include "Garlic.h" #include "I2NPProtocol.h" +using namespace i2p::transport; + namespace i2p { - I2NPMessage * NewI2NPMessage () { return new I2NPMessageBuffer(); @@ -289,7 +290,7 @@ namespace i2p { LogPrint ("Record ",i," is ours"); - i2p::crypto::ElGamalDecrypt (i2p::context.GetPrivateKey (), records[i].encrypted, (uint8_t *)&clearText); + i2p::crypto::ElGamalDecrypt (i2p::context.GetEncryptionPrivateKey (), records[i].encrypted, (uint8_t *)&clearText); // replace record to reply I2NPBuildResponseRecord * reply = (I2NPBuildResponseRecord *)(records + i); if (i2p::context.AcceptsTunnels ()) @@ -353,13 +354,13 @@ namespace i2p if (clearText.flag & 0x40) // we are endpoint of outboud tunnel { // so we send it to reply tunnel - i2p::transports.SendMessage (clearText.nextIdent, + transports.SendMessage (clearText.nextIdent, CreateTunnelGatewayMsg (be32toh (clearText.nextTunnel), eI2NPVariableTunnelBuildReply, buf, len, be32toh (clearText.nextMessageID))); } else - i2p::transports.SendMessage (clearText.nextIdent, + transports.SendMessage (clearText.nextIdent, CreateI2NPMessage (eI2NPVariableTunnelBuild, buf, len, be32toh (clearText.nextMessageID))); } } @@ -373,13 +374,13 @@ namespace i2p if (clearText.flag & 0x40) // we are endpoint of outbound tunnel { // so we send it to reply tunnel - i2p::transports.SendMessage (clearText.nextIdent, + transports.SendMessage (clearText.nextIdent, CreateTunnelGatewayMsg (be32toh (clearText.nextTunnel), eI2NPTunnelBuildReply, buf, len, be32toh (clearText.nextMessageID))); } else - i2p::transports.SendMessage (clearText.nextIdent, + transports.SendMessage (clearText.nextIdent, CreateI2NPMessage (eI2NPTunnelBuild, buf, len, be32toh (clearText.nextMessageID))); } } diff --git a/I2PTunnel.cpp b/I2PTunnel.cpp index 3c8b9234..8dadabae 100644 --- a/I2PTunnel.cpp +++ b/I2PTunnel.cpp @@ -14,7 +14,7 @@ namespace client boost::asio::ip::tcp::socket * socket, const i2p::data::LeaseSet * leaseSet): m_Socket (socket), m_Owner (owner) { - m_Stream = m_Owner->GetLocalDestination ()->CreateNewOutgoingStream (*leaseSet); + m_Stream = m_Owner->GetLocalDestination ()->CreateStream (*leaseSet); m_Stream->Send (m_Buffer, 0); // connect StreamReceive (); Receive (); @@ -39,7 +39,7 @@ namespace client if (m_Stream) { m_Stream->Close (); - m_Owner->GetLocalDestination ()->DeleteStream (m_Stream); + i2p::stream::DeleteStream (m_Stream); m_Stream = nullptr; } m_Socket->close (); @@ -115,7 +115,7 @@ namespace client if (ecode != boost::asio::error::operation_aborted) { if (m_Stream) m_Stream->Close (); - m_Owner->GetLocalDestination ()->DeleteStream (m_Stream); + i2p::stream::DeleteStream (m_Stream); m_Stream = nullptr; } } @@ -145,7 +145,7 @@ namespace client } I2PClientTunnel::I2PClientTunnel (boost::asio::io_service& service, const std::string& destination, - int port, i2p::stream::StreamingDestination * localDestination): + int port, ClientDestination * localDestination): I2PTunnel (service, localDestination ? localDestination : i2p::client::context.CreateNewLocalDestination (false, i2p::data::SIGNING_KEY_TYPE_ECDSA_SHA256_P256)), m_Acceptor (service, boost::asio::ip::tcp::endpoint (boost::asio::ip::tcp::v4(), port)), @@ -162,7 +162,7 @@ namespace client void I2PClientTunnel::Start () { i2p::data::IdentHash identHash; - if (i2p::data::netdb.GetAddressBook ().GetIdentHash (m_Destination, identHash)) + if (i2p::client::context.GetAddressBook ().GetIdentHash (m_Destination, identHash)) m_DestinationIdentHash = new i2p::data::IdentHash (identHash); if (!m_DestinationIdentHash) LogPrint ("I2PTunnel unknown destination ", m_Destination); @@ -192,7 +192,7 @@ namespace client if (!m_DestinationIdentHash) { i2p::data::IdentHash identHash; - if (i2p::data::netdb.GetAddressBook ().GetIdentHash (m_Destination, identHash)) + if (i2p::client::context.GetAddressBook ().GetIdentHash (m_Destination, identHash)) m_DestinationIdentHash = new i2p::data::IdentHash (identHash); } if (m_DestinationIdentHash) @@ -251,7 +251,7 @@ namespace client } I2PServerTunnel::I2PServerTunnel (boost::asio::io_service& service, const std::string& address, int port, - i2p::stream::StreamingDestination * localDestination): I2PTunnel (service, localDestination), + ClientDestination * localDestination): I2PTunnel (service, localDestination), m_Endpoint (boost::asio::ip::address::from_string (address), port) { } @@ -270,7 +270,7 @@ namespace client { auto localDestination = GetLocalDestination (); if (localDestination) - localDestination->SetAcceptor (std::bind (&I2PServerTunnel::HandleAccept, this, std::placeholders::_1)); + localDestination->AcceptStreams (std::bind (&I2PServerTunnel::HandleAccept, this, std::placeholders::_1)); else LogPrint ("Local destination not set for server tunnel"); } diff --git a/I2PTunnel.h b/I2PTunnel.h index 47d7e212..4f99bc79 100644 --- a/I2PTunnel.h +++ b/I2PTunnel.h @@ -6,6 +6,7 @@ #include #include #include "Identity.h" +#include "Destination.h" #include "Streaming.h" namespace i2p @@ -51,22 +52,22 @@ namespace client { public: - I2PTunnel (boost::asio::io_service& service, i2p::stream::StreamingDestination * localDestination): + I2PTunnel (boost::asio::io_service& service, ClientDestination * localDestination): m_Service (service), m_LocalDestination (localDestination) {}; virtual ~I2PTunnel () { ClearConnections (); }; void AddConnection (I2PTunnelConnection * conn); void RemoveConnection (I2PTunnelConnection * conn); void ClearConnections (); - i2p::stream::StreamingDestination * GetLocalDestination () { return m_LocalDestination; }; - void SetLocalDestination (i2p::stream::StreamingDestination * dest) { m_LocalDestination = dest; }; + ClientDestination * GetLocalDestination () { return m_LocalDestination; }; + void SetLocalDestination (ClientDestination * dest) { m_LocalDestination = dest; }; boost::asio::io_service& GetService () { return m_Service; }; private: boost::asio::io_service& m_Service; - i2p::stream::StreamingDestination * m_LocalDestination; + ClientDestination * m_LocalDestination; std::set m_Connections; }; @@ -75,7 +76,7 @@ namespace client public: I2PClientTunnel (boost::asio::io_service& service, const std::string& destination, int port, - i2p::stream::StreamingDestination * localDestination = nullptr); + ClientDestination * localDestination = nullptr); ~I2PClientTunnel (); void Start (); @@ -102,7 +103,7 @@ namespace client public: I2PServerTunnel (boost::asio::io_service& service, const std::string& address, int port, - i2p::stream::StreamingDestination * localDestination); + ClientDestination * localDestination); void Start (); void Stop (); diff --git a/Identity.cpp b/Identity.cpp index 67bdd900..24a7f50c 100644 --- a/Identity.cpp +++ b/Identity.cpp @@ -2,7 +2,6 @@ #include #include #include -#include #include #include "base64.h" #include "CryptoConst.h" @@ -293,14 +292,6 @@ namespace data return keys; } - void CreateRandomDHKeysPair (DHKeysPair * keys) - { - if (!keys) return; - CryptoPP::AutoSeededRandomPool rnd; - CryptoPP::DH dh (i2p::crypto::elgp, i2p::crypto::elgg); - dh.GenerateKeyPair(rnd, keys->privateKey, keys->publicKey); - } - IdentHash CreateRoutingKey (const IdentHash& ident) { uint8_t buf[41]; // ident + yyyymmdd diff --git a/Identity.h b/Identity.h index 290422ea..baa40106 100644 --- a/Identity.h +++ b/Identity.h @@ -67,13 +67,6 @@ namespace data typedef Tag<32> IdentHash; #pragma pack(1) - - struct DHKeysPair // transient keys for transport sessions - { - uint8_t publicKey[256]; - uint8_t privateKey[256]; - }; - struct Keys { uint8_t privateKey[256]; @@ -82,7 +75,6 @@ namespace data uint8_t signingKey[128]; }; - const uint8_t CERTIFICATE_TYPE_NULL = 0; const uint8_t CERTIFICATE_TYPE_HASHCASH = 1; const uint8_t CERTIFICATE_TYPE_HIDDEN = 2; @@ -105,7 +97,10 @@ namespace data Identity& operator=(const Keys& keys); size_t FromBuffer (const uint8_t * buf, size_t len); IdentHash Hash () const; - }; + }; +#pragma pack() + Keys CreateRandomKeys (); + const size_t DEFAULT_IDENTITY_SIZE = sizeof (Identity); // 387 bytes const uint16_t CRYPTO_KEY_TYPE_ELGAMAL = 0; @@ -183,11 +178,6 @@ namespace data uint8_t m_SigningPrivateKey[128]; // assume private key doesn't exceed 128 bytes i2p::crypto::Signer * m_Signer; }; - -#pragma pack() - - Keys CreateRandomKeys (); - void CreateRandomDHKeysPair (DHKeysPair * keys); // for transport sessions // kademlia struct XORMetric diff --git a/Makefile.osx b/Makefile.osx index fb4d5a45..56c9d0c7 100644 --- a/Makefile.osx +++ b/Makefile.osx @@ -9,7 +9,7 @@ LIBS = # http://www.hutsby.net/2011/08/macs-with-aes-ni.html # Seems like all recent Mac's have AES-NI, after firmware upgrade 2.2 # Found no good way to detect it from command line. TODO: Might be some osx sysinfo magic -CFLAGS += -DAESNI +CFLAGS += -maes -DAESNI # Apple Mac OSX UNAME_S := $(shell uname -s) diff --git a/NTCPSession.cpp b/NTCPSession.cpp index 5c9c8a8a..c75755b3 100644 --- a/NTCPSession.cpp +++ b/NTCPSession.cpp @@ -3,7 +3,6 @@ #include "I2PEndian.h" #include #include -#include #include "base64.h" #include "Log.h" #include "Timestamp.h" @@ -11,28 +10,27 @@ #include "I2NPProtocol.h" #include "RouterContext.h" #include "Transports.h" +#include "NetDb.h" #include "NTCPSession.h" using namespace i2p::crypto; namespace i2p { -namespace ntcp +namespace transport { - NTCPSession::NTCPSession (boost::asio::io_service& service, i2p::data::RouterInfo& in_RemoteRouterInfo): - m_Socket (service), m_TerminationTimer (service), m_IsEstablished (false), - m_DHKeysPair (nullptr), m_RemoteRouterInfo (in_RemoteRouterInfo), - m_ReceiveBufferOffset (0), m_NextMessage (nullptr), - m_NumSentBytes (0), m_NumReceivedBytes (0) + NTCPSession::NTCPSession (boost::asio::io_service& service, const i2p::data::RouterInfo * in_RemoteRouter): + TransportSession (in_RemoteRouter), m_Socket (service), + m_TerminationTimer (service), m_IsEstablished (false), m_ReceiveBufferOffset (0), + m_NextMessage (nullptr), m_NumSentBytes (0), m_NumReceivedBytes (0) { - m_DHKeysPair = i2p::transports.GetNextDHKeysPair (); + m_DHKeysPair = transports.GetNextDHKeysPair (); m_Establisher = new Establisher; } NTCPSession::~NTCPSession () { delete m_Establisher; - delete m_DHKeysPair; if (m_NextMessage) i2p::DeleteI2NPMessage (m_NextMessage); for (auto it :m_DelayedMessages) @@ -79,12 +77,13 @@ namespace ntcp { m_IsEstablished = false; m_Socket.close (); - i2p::transports.RemoveNTCPSession (this); + transports.RemoveNTCPSession (this); int numDelayed = 0; for (auto it :m_DelayedMessages) { // try to send them again - i2p::transports.SendMessage (m_RemoteRouterInfo.GetIdentHash (), it); + if (m_RemoteRouter) + transports.SendMessage (m_RemoteRouter->GetIdentHash (), it); numDelayed++; } m_DelayedMessages.clear (); @@ -121,12 +120,12 @@ namespace ntcp void NTCPSession::ClientLogin () { if (!m_DHKeysPair) - m_DHKeysPair = i2p::transports.GetNextDHKeysPair (); + m_DHKeysPair = transports.GetNextDHKeysPair (); // send Phase1 const uint8_t * x = m_DHKeysPair->publicKey; memcpy (m_Establisher->phase1.pubKey, x, 256); CryptoPP::SHA256().CalculateDigest(m_Establisher->phase1.HXxorHI, x, 256); - const uint8_t * ident = m_RemoteRouterInfo.GetIdentHash (); + const uint8_t * ident = m_RemoteIdentity.GetIdentHash (); for (int i = 0; i < 32; i++) m_Establisher->phase1.HXxorHI[i] ^= ident[i]; @@ -191,7 +190,7 @@ namespace ntcp void NTCPSession::SendPhase2 () { if (!m_DHKeysPair) - m_DHKeysPair = i2p::transports.GetNextDHKeysPair (); + m_DHKeysPair = transports.GetNextDHKeysPair (); const uint8_t * y = m_DHKeysPair->publicKey; memcpy (m_Establisher->phase2.pubKey, y, 256); uint8_t xy[512]; @@ -239,8 +238,9 @@ namespace ntcp LogPrint ("Phase 2 read error: ", ecode.message (), ". Wrong ident assumed"); if (ecode != boost::asio::error::operation_aborted) { - GetRemoteRouterInfo ().SetUnreachable (true); // this RouterInfo is not valid - i2p::transports.ReuseDHKeysPair (m_DHKeysPair); + // this RI is not valid + i2p::data::netdb.SetUnreachable (GetRemoteIdentity ().GetIdentHash (), true); + transports.ReuseDHKeysPair (m_DHKeysPair); m_DHKeysPair = nullptr; Terminate (); } @@ -265,7 +265,7 @@ namespace ntcp if (memcmp (hxy, m_Establisher->phase2.encrypted.hxy, 32)) { LogPrint ("Incorrect hash"); - i2p::transports.ReuseDHKeysPair (m_DHKeysPair); + transports.ReuseDHKeysPair (m_DHKeysPair); m_DHKeysPair = nullptr; Terminate (); return ; @@ -277,14 +277,14 @@ namespace ntcp void NTCPSession::SendPhase3 () { m_Establisher->phase3.size = htons (i2p::data::DEFAULT_IDENTITY_SIZE); - memcpy (&m_Establisher->phase3.ident, &i2p::context.GetRouterIdentity (), i2p::data::DEFAULT_IDENTITY_SIZE); + memcpy (&m_Establisher->phase3.ident, &i2p::context.GetIdentity ().GetStandardIdentity (), i2p::data::DEFAULT_IDENTITY_SIZE); // TODO: uint32_t tsA = htobe32 (i2p::util::GetSecondsSinceEpoch ()); m_Establisher->phase3.timestamp = tsA; SignedData s; memcpy (s.x, m_Establisher->phase1.pubKey, 256); memcpy (s.y, m_Establisher->phase2.pubKey, 256); - memcpy (s.ident, m_RemoteRouterInfo.GetIdentHash (), 32); + memcpy (s.ident, m_RemoteIdentity.GetIdentHash (), 32); s.tsA = tsA; s.tsB = m_Establisher->phase2.encrypted.timestamp; i2p::context.Sign ((uint8_t *)&s, sizeof (s), m_Establisher->phase3.signature); @@ -324,7 +324,7 @@ namespace ntcp { LogPrint ("Phase 3 received: ", bytes_transferred); m_Decryption.Decrypt ((uint8_t *)&m_Establisher->phase3, sizeof(NTCPPhase3), (uint8_t *)&m_Establisher->phase3); - m_RemoteRouterInfo.SetRouterIdentity (m_Establisher->phase3.ident); + m_RemoteIdentity = m_Establisher->phase3.ident; SignedData s; memcpy (s.x, m_Establisher->phase1.pubKey, 256); @@ -333,10 +333,7 @@ namespace ntcp s.tsA = m_Establisher->phase3.timestamp; s.tsB = tsB; - CryptoPP::DSA::PublicKey pubKey; - pubKey.Initialize (dsap, dsaq, dsag, CryptoPP::Integer (m_RemoteRouterInfo.GetRouterIdentity ().signingKey, 128)); - CryptoPP::DSA::Verifier verifier (pubKey); - if (!verifier.VerifyMessage ((uint8_t *)&s, sizeof(s), m_Establisher->phase3.signature, 40)) + if (!m_RemoteIdentity.Verify ((uint8_t *)&s, sizeof(s), m_Establisher->phase3.signature)) { LogPrint ("signature verification failed"); Terminate (); @@ -352,7 +349,7 @@ namespace ntcp SignedData s; memcpy (s.x, m_Establisher->phase1.pubKey, 256); memcpy (s.y, m_Establisher->phase2.pubKey, 256); - memcpy (s.ident, m_RemoteRouterInfo.GetIdentHash (), 32); + memcpy (s.ident, m_RemoteIdentity.GetIdentHash (), 32); s.tsA = m_Establisher->phase3.timestamp; s.tsB = tsB; i2p::context.Sign ((uint8_t *)&s, sizeof (s), m_Establisher->phase4.signature); @@ -387,7 +384,8 @@ namespace ntcp LogPrint ("Phase 4 read error: ", ecode.message ()); if (ecode != boost::asio::error::operation_aborted) { - GetRemoteRouterInfo ().SetUnreachable (true); // this router doesn't like us + // this router doesn't like us + i2p::data::netdb.SetUnreachable (GetRemoteIdentity ().GetIdentHash (), true); Terminate (); } } @@ -404,10 +402,7 @@ namespace ntcp s.tsA = tsA; s.tsB = m_Establisher->phase2.encrypted.timestamp; - CryptoPP::DSA::PublicKey pubKey; - pubKey.Initialize (dsap, dsaq, dsag, CryptoPP::Integer (m_RemoteRouterInfo.GetRouterIdentity ().signingKey, 128)); - CryptoPP::DSA::Verifier verifier (pubKey); - if (!verifier.VerifyMessage ((uint8_t *)&s, sizeof(s), m_Establisher->phase4.signature, 40)) + if (!m_RemoteIdentity.Verify ((uint8_t *)&s, sizeof(s), m_Establisher->phase4.signature)) { LogPrint ("signature verification failed"); Terminate (); @@ -601,9 +596,8 @@ namespace ntcp NTCPClient::NTCPClient (boost::asio::io_service& service, const boost::asio::ip::address& address, - int port, i2p::data::RouterInfo& in_RouterInfo): - NTCPSession (service, in_RouterInfo), - m_Endpoint (address, port) + int port, const i2p::data::RouterInfo& in_RouterInfo): + NTCPSession (service, &in_RouterInfo), m_Endpoint (address, port) { Connect (); } @@ -622,13 +616,15 @@ namespace ntcp LogPrint ("Connect error: ", ecode.message ()); if (ecode != boost::asio::error::operation_aborted) { - GetRemoteRouterInfo ().SetUnreachable (true); + i2p::data::netdb.SetUnreachable (GetRemoteIdentity ().GetIdentHash (), true); Terminate (); } } else { LogPrint ("Connected"); + if (GetSocket ().local_endpoint ().protocol () == boost::asio::ip::tcp::v6()) // ipv6 + context.UpdateV6Address (GetSocket ().local_endpoint ().address ().to_string ()); ClientLogin (); } } @@ -636,11 +632,8 @@ namespace ntcp void NTCPServerConnection::Connected () { LogPrint ("NTCP server session connected"); - SetIsEstablished (true); - i2p::transports.AddNTCPSession (this); - - SendTimeSyncMessage (); - SendI2NPMessage (CreateDatabaseStoreMsg ()); // we tell immediately who we are + transports.AddNTCPSession (this); + NTCPSession::Connected (); } } } diff --git a/NTCPSession.h b/NTCPSession.h index 363a81cf..61113772 100644 --- a/NTCPSession.h +++ b/NTCPSession.h @@ -11,10 +11,11 @@ #include "Identity.h" #include "RouterInfo.h" #include "I2NPProtocol.h" +#include "TransportSession.h" namespace i2p { -namespace ntcp +namespace transport { #pragma pack(1) @@ -65,16 +66,16 @@ namespace ntcp const size_t NTCP_MAX_MESSAGE_SIZE = 16384; const size_t NTCP_BUFFER_SIZE = 1040; // fits one tunnel message (1028) const int NTCP_TERMINATION_TIMEOUT = 120; // 2 minutes - class NTCPSession + + class NTCPSession: public TransportSession { public: - NTCPSession (boost::asio::io_service& service, i2p::data::RouterInfo& in_RemoteRouterInfo); - virtual ~NTCPSession (); + NTCPSession (boost::asio::io_service& service, const i2p::data::RouterInfo * in_RemoteRouter = nullptr); + ~NTCPSession (); boost::asio::ip::tcp::socket& GetSocket () { return m_Socket; }; bool IsEstablished () const { return m_IsEstablished; }; - i2p::data::RouterInfo& GetRemoteRouterInfo () { return m_RemoteRouterInfo; }; void ClientLogin (); void ServerLogin (); @@ -127,13 +128,10 @@ namespace ntcp boost::asio::ip::tcp::socket m_Socket; boost::asio::deadline_timer m_TerminationTimer; bool m_IsEstablished; - i2p::data::DHKeysPair * m_DHKeysPair; // X - for client and Y - for server i2p::crypto::CBCDecryption m_Decryption; i2p::crypto::CBCEncryption m_Encryption; CryptoPP::Adler32 m_Adler; - - i2p::data::RouterInfo& m_RemoteRouterInfo; struct Establisher { @@ -157,7 +155,7 @@ namespace ntcp { public: - NTCPClient (boost::asio::io_service& service, const boost::asio::ip::address& address, int port, i2p::data::RouterInfo& in_RouterInfo); + NTCPClient (boost::asio::io_service& service, const boost::asio::ip::address& address, int port, const i2p::data::RouterInfo& in_RouterInfo); private: @@ -174,15 +172,11 @@ namespace ntcp public: NTCPServerConnection (boost::asio::io_service& service): - NTCPSession (service, m_DummyRemoteRouterInfo) {}; + NTCPSession (service) {}; protected: virtual void Connected (); - - private: - - i2p::data::RouterInfo m_DummyRemoteRouterInfo; }; } } diff --git a/NetDb.cpp b/NetDb.cpp index eb7561f7..eb2800a2 100644 --- a/NetDb.cpp +++ b/NetDb.cpp @@ -15,6 +15,8 @@ #include "Reseed.h" #include "util.h" +using namespace i2p::transport; + namespace i2p { namespace data @@ -227,6 +229,13 @@ namespace data return nullptr; } + void NetDb::SetUnreachable (const IdentHash& ident, bool unreachable) + { + auto it = m_RouterInfos.find (ident); + if (it != m_RouterInfos.end ()) + return it->second->SetUnreachable (unreachable); + } + // TODO: Move to reseed and/or scheduled tasks. (In java version, scheduler fix this as well as sort RIs.) bool NetDb::CreateNetDb(boost::filesystem::path directory) { @@ -403,7 +412,7 @@ namespace data RequestedDestination * dest = CreateRequestedDestination (destination, false, false, pool); auto floodfill = GetClosestFloodfill (destination, dest->GetExcludedPeers ()); if (floodfill) - i2p::transports.SendMessage (floodfill->GetIdentHash (), dest->CreateRequestMessage (floodfill->GetIdentHash ())); + transports.SendMessage (floodfill->GetIdentHash (), dest->CreateRequestMessage (floodfill->GetIdentHash ())); } } @@ -655,10 +664,10 @@ namespace data if (outbound) outbound->SendTunnelDataMsg (buf+32, replyTunnelID, replyMsg); else - i2p::transports.SendMessage (buf+32, i2p::CreateTunnelGatewayMsg (replyTunnelID, replyMsg)); + transports.SendMessage (buf+32, i2p::CreateTunnelGatewayMsg (replyTunnelID, replyMsg)); } else - i2p::transports.SendMessage (buf+32, replyMsg); + transports.SendMessage (buf+32, replyMsg); } i2p::DeleteI2NPMessage (msg); } @@ -712,7 +721,7 @@ namespace data }); } else - i2p::transports.SendMessage (floodfill->GetIdentHash (), dest->CreateRequestMessage (floodfill->GetIdentHash ())); + i2p::transport::transports.SendMessage (floodfill->GetIdentHash (), dest->CreateRequestMessage (floodfill->GetIdentHash ())); } else DeleteRequestedDestination (dest); diff --git a/NetDb.h b/NetDb.h index ca62163c..b90bef19 100644 --- a/NetDb.h +++ b/NetDb.h @@ -15,7 +15,6 @@ #include "LeaseSet.h" #include "Tunnel.h" #include "TunnelPool.h" -#include "AddressBook.h" namespace i2p { @@ -67,7 +66,6 @@ namespace data void AddLeaseSet (const IdentHash& ident, const uint8_t * buf, int len, i2p::tunnel::InboundTunnel * from); RouterInfo * FindRouter (const IdentHash& ident) const; LeaseSet * FindLeaseSet (const IdentHash& destination) const; - AddressBook& GetAddressBook () { return m_AddressBook; };// TODO: move AddressBook away from NetDb void PublishLeaseSet (const LeaseSet * leaseSet, i2p::tunnel::TunnelPool * pool); void RequestDestination (const IdentHash& destination, bool isLeaseSet = false, @@ -80,7 +78,8 @@ namespace data const RouterInfo * GetRandomRouter () const; const RouterInfo * GetRandomRouter (const RouterInfo * compatibleWith) const; const RouterInfo * GetHighBandwidthRandomRouter (const RouterInfo * compatibleWith) const; - + void SetUnreachable (const IdentHash& ident, bool unreachable); + void PostI2NPMsg (I2NPMessage * msg); // for web interface @@ -120,7 +119,6 @@ namespace data int m_ReseedRetries; std::thread * m_Thread; i2p::util::Queue m_Queue; // of I2NPDatabaseStoreMsg - AddressBook m_AddressBook; static const char m_NetDbPath[]; }; diff --git a/README.md b/README.md index 695986e9..395500c3 100644 --- a/README.md +++ b/README.md @@ -35,10 +35,10 @@ $ ./i2p --host=YOUR_PUBLIC_IP The client should now reseed by itself. To visit an I2P page, you need to find the b32 address of your destination. -After that, go to the webconsole and add it behind the url. (Remove http:// and b32.i2p from the address) +After that, go to the webconsole and add it behind the url. (Remove http:// from the address) This should resulting in for example: -http://localhost:7070/4oes3rlgrpbkmzv4lqcfili23h3cvpwslqcfjlk6vvguxyggspwa +http://localhost:7070/4oes3rlgrpbkmzv4lqcfili23h3cvpwslqcfjlk6vvguxyggspwa.b32.i2p Options @@ -51,6 +51,7 @@ Options * --daemon= - Enable or disable daemon mode. 1 for yes, 0 for no. * --service= - 1 if uses system folders (/var/run/i2pd.pid, /var/log/i2pd.log, /var/lib/i2pd). * --unreachable= - 1 if router is declared as unreachable and works through introducers. +* --v6= - 1 if supports communication through ipv6, off by default * --httpproxyport= - The port to listen on (HTTP Proxy) * --socksproxyport= - The port to listen on (SOCKS Proxy) * --ircport= - The local port of IRC tunnel to listen on. 6668 by default diff --git a/RouterContext.cpp b/RouterContext.cpp index 2560e6d4..65905196 100644 --- a/RouterContext.cpp +++ b/RouterContext.cpp @@ -78,7 +78,7 @@ namespace i2p auto newAddress = boost::asio::ip::address::from_string (host); for (auto& address : m_RouterInfo.GetAddresses ()) { - if (address.host != newAddress) + if (address.host != newAddress && address.IsCompatible (newAddress)) { address.host = newAddress; updated = true; @@ -130,7 +130,45 @@ namespace i2p // update UpdateRouterInfo (); } - + + void RouterContext::SetSupportsV6 (bool supportsV6) + { + if (supportsV6) + m_RouterInfo.EnableV6 (); + else + m_RouterInfo.DisableV6 (); + } + + void RouterContext::UpdateV6Address (const std::string& host) + { + bool updated = false, found = false; + int port = 0; + auto newAddress = boost::asio::ip::address::from_string (host); + auto& addresses = m_RouterInfo.GetAddresses (); + for (auto& addr : addresses) + { + if (addr.host.is_v6 ()) + { + if (addr.host != newAddress) + { + addr.host = newAddress; + updated = true; + } + found = true; + } + else + port = addr.port; + } + if (!found) + { + // create new address + m_RouterInfo.AddNTCPAddress (host.c_str (), port); + updated = true; + } + if (updated) + UpdateRouterInfo (); + } + bool RouterContext::Load () { std::ifstream fk (i2p::util::filesystem::GetFullPath (ROUTER_KEYS).c_str (), std::ifstream::binary | std::ofstream::in); diff --git a/RouterContext.h b/RouterContext.h index 777482b8..e2e5b24e 100644 --- a/RouterContext.h +++ b/RouterContext.h @@ -2,6 +2,7 @@ #define ROUTER_CONTEXT_H__ #include +#include #include #include #include "Identity.h" @@ -22,9 +23,6 @@ namespace i2p void Init (); i2p::data::RouterInfo& GetRouterInfo () { return m_RouterInfo; }; - const uint8_t * GetPrivateKey () const { return m_Keys.GetPrivateKey (); }; - const i2p::data::Identity& GetRouterIdentity () const { return m_RouterInfo.GetRouterIdentity (); }; - const i2p::data::IdentHash& GetRouterIdentHash () const { return m_RouterInfo.GetIdentHash (); }; CryptoPP::RandomNumberGenerator& GetRandomNumberGenerator () { return m_Rnd; }; void UpdatePort (int port); // called from Daemon @@ -35,6 +33,9 @@ namespace i2p void SetUnreachable (); bool AcceptsTunnels () const { return m_AcceptsTunnels; }; void SetAcceptsTunnels (bool acceptsTunnels) { m_AcceptsTunnels = acceptsTunnels; }; + bool SupportsV6 () const { return m_RouterInfo.IsV6 (); }; + void SetSupportsV6 (bool supportsV6); + void UpdateV6Address (const std::string& host); // called from NTCP session // implements LocalDestination const i2p::data::PrivateKeys& GetPrivateKeys () const { return m_Keys; }; diff --git a/RouterInfo.cpp b/RouterInfo.cpp index f6203a1d..960db401 100644 --- a/RouterInfo.cpp +++ b/RouterInfo.cpp @@ -59,7 +59,6 @@ namespace data { m_RouterIdentity = identity; m_IdentHash = m_RouterIdentity.Hash (); - UpdateIdentHashBase64 (); m_Timestamp = i2p::util::GetMillisecondsSinceEpoch (); } @@ -226,7 +225,6 @@ namespace data } CryptoPP::SHA256().CalculateDigest(m_IdentHash, (uint8_t *)&m_RouterIdentity, sizeof (m_RouterIdentity)); - UpdateIdentHashBase64 (); if (!m_SupportedTransports || !m_Addresses.size() || (UsesIntroducer () && !introducers)) SetUnreachable (true); @@ -279,18 +277,9 @@ namespace data SetProperty ("caps", caps.c_str ()); } - - void RouterInfo::UpdateIdentHashBase64 () - { - size_t l = i2p::data::ByteStreamToBase64 (m_IdentHash, 32, m_IdentHashBase64, 48); - m_IdentHashBase64[l] = 0; - memcpy (m_IdentHashAbbreviation, m_IdentHashBase64, 4); - m_IdentHashAbbreviation[4] = 0; - } void RouterInfo::WriteToStream (std::ostream& s) { - s.write ((char *)&m_RouterIdentity, sizeof (m_RouterIdentity)); uint64_t ts = htobe64 (m_Timestamp); s.write ((char *)&ts, sizeof (ts)); @@ -410,7 +399,7 @@ namespace data if (!m_Buffer) { if (LoadFile ()) - LogPrint ("Buffer for ", m_IdentHashAbbreviation, " loaded from file"); + LogPrint ("Buffer for ", GetIdentHashAbbreviation (), " loaded from file"); } return m_Buffer; } @@ -419,6 +408,9 @@ namespace data { m_Timestamp = i2p::util::GetMillisecondsSinceEpoch (); // refresh timstamp std::stringstream s; + uint8_t ident[1024]; + auto identLen = privateKeys.GetPublic ().ToBuffer (ident, 1024); + s.write ((char *)ident, identLen); WriteToStream (s); m_BufferLen = s.str ().size (); if (!m_Buffer) @@ -466,7 +458,7 @@ namespace data addr.cost = 2; addr.date = 0; m_Addresses.push_back(addr); - m_SupportedTransports |= eNTCPV4; + m_SupportedTransports |= addr.host.is_v6 () ? eNTCPV6 : eNTCPV4; } void RouterInfo::AddSSUAddress (const char * host, int port, const uint8_t * key) @@ -479,7 +471,7 @@ namespace data addr.date = 0; memcpy (addr.key, key, 32); m_Addresses.push_back(addr); - m_SupportedTransports |= eSSUV4; + m_SupportedTransports |= addr.host.is_v6 () ? eNTCPV6 : eSSUV4; m_Caps |= eSSUTesting; m_Caps |= eSSUIntroducer; } @@ -568,6 +560,34 @@ namespace data return m_SupportedTransports & (eSSUV4 | eSSUV6); } + bool RouterInfo::IsV6 () const + { + return m_SupportedTransports & (eNTCPV6 | eSSUV6); + } + + void RouterInfo::EnableV6 () + { + if (!IsV6 ()) + m_SupportedTransports |= eNTCPV6; + } + + void RouterInfo::DisableV6 () + { + if (IsV6 ()) + { + m_SupportedTransports &= ~eNTCPV6; + for (size_t i = 0; i < m_Addresses.size (); i++) + { + if (m_Addresses[i].transportStyle == i2p::data::RouterInfo::eTransportNTCP && + m_Addresses[i].host.is_v6 ()) + { + m_Addresses.erase (m_Addresses.begin () + i); + break; + } + } + } + } + bool RouterInfo::UsesIntroducer () const { return m_Caps & Caps::eUnreachable; // non-reachable diff --git a/RouterInfo.h b/RouterInfo.h index 669c85bd..d5d775b1 100644 --- a/RouterInfo.h +++ b/RouterInfo.h @@ -75,10 +75,16 @@ namespace data // SSU only Tag<32> key; // intro key for SSU std::vector introducers; + + bool IsCompatible (const boost::asio::ip::address& other) const + { + return (host.is_v4 () && other.is_v4 ()) || + (host.is_v6 () && other.is_v6 ()); + } }; RouterInfo (const std::string& fullPath); - RouterInfo (): m_Buffer (nullptr) { m_IdentHashBase64[0] = 0; m_IdentHashAbbreviation[0] = 0; }; + RouterInfo (): m_Buffer (nullptr) { }; RouterInfo (const RouterInfo& ) = default; RouterInfo& operator=(const RouterInfo& ) = default; RouterInfo (const uint8_t * buf, int len); @@ -86,8 +92,8 @@ namespace data const Identity& GetRouterIdentity () const { return m_RouterIdentity; }; void SetRouterIdentity (const Identity& identity); - const char * GetIdentHashBase64 () const { return m_IdentHashBase64; }; - const char * GetIdentHashAbbreviation () const { return m_IdentHashAbbreviation; }; + std::string GetIdentHashBase64 () const { return m_IdentHash.ToBase64 (); }; + std::string GetIdentHashAbbreviation () const { return m_IdentHash.ToBase64 ().substr (0, 4); }; uint64_t GetTimestamp () const { return m_Timestamp; }; std::vector
& GetAddresses () { return m_Addresses; }; const Address * GetNTCPAddress (bool v4only = true) const; @@ -102,6 +108,9 @@ namespace data bool IsFloodfill () const; bool IsNTCP (bool v4only = true) const; bool IsSSU (bool v4only = true) const; + bool IsV6 () const; + void EnableV6 (); + void DisableV6 (); bool IsCompatible (const RouterInfo& other) const { return m_SupportedTransports & other.m_SupportedTransports; }; bool UsesIntroducer () const; bool IsIntroducer () const { return m_Caps & eSSUIntroducer; }; @@ -143,7 +152,6 @@ namespace data size_t ReadString (char * str, std::istream& s); void WriteString (const std::string& str, std::ostream& s); void ExtractCaps (const char * value); - void UpdateIdentHashBase64 (); const Address * GetAddress (TransportStyle s, bool v4only) const; void UpdateCapsProperty (); @@ -152,7 +160,6 @@ namespace data std::string m_FullPath; Identity m_RouterIdentity; IdentHash m_IdentHash; - char m_IdentHashBase64[48], m_IdentHashAbbreviation[5]; uint8_t * m_Buffer; int m_BufferLen; uint64_t m_Timestamp; diff --git a/SAM.cpp b/SAM.cpp index 45bb515f..a803d5ba 100644 --- a/SAM.cpp +++ b/SAM.cpp @@ -28,8 +28,8 @@ namespace client if (m_Stream) { m_Stream->Close (); - if (m_Session && m_Session->localDestination) - m_Session->localDestination->DeleteStream (m_Stream); + i2p::stream::DeleteStream (m_Stream); + m_Stream = nullptr; } } @@ -38,8 +38,7 @@ namespace client if (m_Stream) { m_Stream->Close (); - if (m_Session && m_Session->localDestination) - m_Session->localDestination->DeleteStream (m_Stream); + i2p::stream::DeleteStream (m_Stream); m_Stream = nullptr; } switch (m_SocketType) @@ -58,7 +57,7 @@ namespace client if (m_Session) { m_Session->sockets.remove (this); - m_Session->localDestination->ResetAcceptor (); + m_Session->localDestination->StopAcceptingStreams (); } break; } @@ -210,6 +209,7 @@ namespace client LogPrint ("SAM session create: ", buf); std::map params; ExtractParams (buf, len, params); + std::string& style = params[SAM_PARAM_STYLE]; std::string& id = params[SAM_PARAM_ID]; std::string& destination = params[SAM_PARAM_DESTINATION]; m_ID = id; @@ -224,7 +224,11 @@ namespace client { m_SocketType = eSAMSocketTypeSession; if (m_Session->localDestination->IsReady ()) + { + if (style == SAM_VALUE_DATAGRAM) + m_Session->localDestination->CreateDatagramDestination (); SendSessionCreateReplyOk (); + } else { m_Timer.expires_from_now (boost::posix_time::seconds(SAM_SESSION_READINESS_CHECK_INTERVAL)); @@ -260,7 +264,7 @@ namespace client priv[l1] = 0; #ifdef _MSC_VER size_t l2 = sprintf_s (m_Buffer, SAM_SOCKET_BUFFER_SIZE, SAM_SESSION_CREATE_REPLY_OK, priv); -#else +#else size_t l2 = snprintf (m_Buffer, SAM_SOCKET_BUFFER_SIZE, SAM_SESSION_CREATE_REPLY_OK, priv); #endif SendMessageReply (m_Buffer, l2, false); @@ -302,7 +306,7 @@ namespace client { m_SocketType = eSAMSocketTypeStream; m_Session->sockets.push_back (this); - m_Stream = m_Session->localDestination->CreateNewOutgoingStream (remote); + m_Stream = m_Session->localDestination->CreateStream (remote); m_Stream->Send ((uint8_t *)m_Buffer, 0); // connect I2PReceive (); SendMessageReply (SAM_STREAM_STATUS_OK, strlen(SAM_STREAM_STATUS_OK), false); @@ -355,11 +359,11 @@ namespace client m_Session = m_Owner.FindSession (id); if (m_Session) { - if (!m_Session->localDestination->IsAcceptorSet ()) + if (!m_Session->localDestination->IsAcceptingStreams ()) { m_SocketType = eSAMSocketTypeAcceptor; m_Session->sockets.push_back (this); - m_Session->localDestination->SetAcceptor (std::bind (&SAMSocket::HandleI2PAccept, this, std::placeholders::_1)); + m_Session->localDestination->AcceptStreams (std::bind (&SAMSocket::HandleI2PAccept, this, std::placeholders::_1)); SendMessageReply (SAM_STREAM_STATUS_OK, strlen(SAM_STREAM_STATUS_OK), false); } else @@ -385,8 +389,8 @@ namespace client l1 = i2p::data::ByteStreamToBase64 (buf, l, pub, 1024); pub[l1] = 0; #ifdef _MSC_VER - size_t len = sprintf_s (m_Buffer, SAM_SOCKET_BUFFER_SIZE, SAM_DEST_REPLY, pub, priv); -#else + size_t len = sprintf_s (m_Buffer, SAM_SOCKET_BUFFER_SIZE, SAM_DEST_REPLY, pub, priv); +#else size_t len = snprintf (m_Buffer, SAM_SOCKET_BUFFER_SIZE, SAM_DEST_REPLY, pub, priv); #endif SendMessageReply (m_Buffer, len, true); @@ -404,7 +408,7 @@ namespace client i2p::data::IdentHash ident; if (name == "ME") SendNamingLookupReply (nullptr); - else if (m_Session && i2p::data::netdb.GetAddressBook ().GetIdentHash (name, ident)) + else if (m_Session && context.GetAddressBook ().GetIdentHash (name, ident)) { auto leaseSet = m_Session->localDestination->FindLeaseSet (ident); if (leaseSet) @@ -421,7 +425,7 @@ namespace client { #ifdef _MSC_VER size_t len = sprintf_s (m_Buffer, SAM_SOCKET_BUFFER_SIZE, SAM_NAMING_REPLY_INVALID_KEY, name.c_str()); -#else +#else size_t len = snprintf (m_Buffer, SAM_SOCKET_BUFFER_SIZE, SAM_NAMING_REPLY_INVALID_KEY, name.c_str()); #endif SendMessageReply (m_Buffer, len, false); @@ -437,8 +441,8 @@ namespace client size_t l1 = i2p::data::ByteStreamToBase64 (buf, l, pub, 1024); pub[l1] = 0; #ifdef _MSC_VER - size_t l2 = sprintf_s (m_Buffer, SAM_SOCKET_BUFFER_SIZE, SAM_NAMING_REPLY, pub); -#else + size_t l2 = sprintf_s (m_Buffer, SAM_SOCKET_BUFFER_SIZE, SAM_NAMING_REPLY, pub); +#else size_t l2 = snprintf (m_Buffer, SAM_SOCKET_BUFFER_SIZE, SAM_NAMING_REPLY, pub); #endif SendMessageReply (m_Buffer, l2, false); @@ -530,7 +534,7 @@ namespace client m_Stream = stream; auto session = m_Owner.FindSession (m_ID); if (session) - session->localDestination->ResetAcceptor (); + session->localDestination->StopAcceptingStreams (); if (!m_IsSilent) { // send remote peer address @@ -547,7 +551,8 @@ namespace client SAMBridge::SAMBridge (int port): m_IsRunning (false), m_Thread (nullptr), m_Acceptor (m_Service, boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), port)), - m_NewSocket (nullptr) + m_DatagramEndpoint (boost::asio::ip::udp::v4 (), port-1), m_DatagramSocket (m_Service, m_DatagramEndpoint), + m_NewSocket (nullptr) { } @@ -560,6 +565,7 @@ namespace client void SAMBridge::Start () { Accept (); + ReceiveDatagram (); m_IsRunning = true; m_Thread = new std::thread (std::bind (&SAMBridge::Run, this)); } @@ -618,7 +624,7 @@ namespace client SAMSession * SAMBridge::CreateSession (const std::string& id, const std::string& destination) { - i2p::stream::StreamingDestination * localDestination = nullptr; + ClientDestination * localDestination = nullptr; if (destination != "") { uint8_t * buf = new uint8_t[destination.length ()]; @@ -665,5 +671,62 @@ namespace client return &it->second; return nullptr; } + + void SAMBridge::ReceiveDatagram () + { + m_DatagramSocket.async_receive_from ( + boost::asio::buffer (m_DatagramReceiveBuffer, i2p::datagram::MAX_DATAGRAM_SIZE), + m_SenderEndpoint, + boost::bind (&SAMBridge::HandleReceivedDatagram, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); + } + + void SAMBridge::HandleReceivedDatagram (const boost::system::error_code& ecode, std::size_t bytes_transferred) + { + if (!ecode) + { + m_DatagramReceiveBuffer[bytes_transferred] = 0; + char * eol = strchr ((char *)m_DatagramReceiveBuffer, '\n'); + *eol = 0; eol++; + size_t payloadLen = bytes_transferred - ((uint8_t *)eol - m_DatagramReceiveBuffer); + LogPrint ("SAM datagram received ", m_DatagramReceiveBuffer," size=", payloadLen); + char * sessionID = strchr ((char *)m_DatagramReceiveBuffer, ' '); + if (sessionID) + { + sessionID++; + char * destination = strchr (sessionID, ' '); + if (destination) + { + *destination = 0; destination++; + auto session = FindSession (sessionID); + if (session) + { + uint8_t ident[1024]; + size_t l = i2p::data::Base64ToByteStream (destination, strlen(destination), ident, 1024); + i2p::data::IdentityEx dest; + dest.FromBuffer (ident, l); + auto leaseSet = i2p::data::netdb.FindLeaseSet (dest.GetIdentHash ()); + if (leaseSet) + session->localDestination->GetDatagramDestination ()-> + SendDatagramTo ((uint8_t *)eol, payloadLen, *leaseSet); + else + { + LogPrint ("SAM datagram destination not found"); + i2p::data::netdb.RequestDestination (dest.GetIdentHash (), true, + session->localDestination->GetTunnelPool ()); + } + } + else + LogPrint ("Session ", sessionID, " not found"); + } + else + LogPrint ("Missing destination key"); + } + else + LogPrint ("Missing sessionID"); + ReceiveDatagram (); + } + else + LogPrint ("SAM datagram receive error: ", ecode.message ()); + } } } diff --git a/SAM.h b/SAM.h index dff0e8e2..e1e369b6 100644 --- a/SAM.h +++ b/SAM.h @@ -11,6 +11,7 @@ #include "Identity.h" #include "LeaseSet.h" #include "Streaming.h" +#include "Destination.h" namespace i2p { @@ -46,6 +47,9 @@ namespace client const char SAM_PARAM_DESTINATION[] = "DESTINATION"; const char SAM_PARAM_NAME[] = "NAME"; const char SAM_VALUE_TRANSIENT[] = "TRANSIENT"; + const char SAM_VALUE_STREAM[] = "STREAM"; + const char SAM_VALUE_DATAGRAM[] = "DATAGRAM"; + const char SAM_VALUE_RAW[] = "RAW"; const char SAM_VALUE_TRUE[] = "true"; const char SAM_VALUE_FALSE[] = "false"; @@ -115,7 +119,7 @@ namespace client struct SAMSession { - i2p::stream::StreamingDestination * localDestination; + ClientDestination * localDestination; std::list sockets; }; @@ -141,15 +145,21 @@ namespace client void Accept (); void HandleAccept(const boost::system::error_code& ecode); + void ReceiveDatagram (); + void HandleReceivedDatagram (const boost::system::error_code& ecode, std::size_t bytes_transferred); + private: bool m_IsRunning; std::thread * m_Thread; boost::asio::io_service m_Service; boost::asio::ip::tcp::acceptor m_Acceptor; + boost::asio::ip::udp::endpoint m_DatagramEndpoint, m_SenderEndpoint; + boost::asio::ip::udp::socket m_DatagramSocket; SAMSocket * m_NewSocket; std::mutex m_SessionsMutex; std::map m_Sessions; + uint8_t m_DatagramReceiveBuffer[i2p::datagram::MAX_DATAGRAM_SIZE+1]; }; } } diff --git a/SOCKS.cpp b/SOCKS.cpp index 83f8a5d0..f2386321 100644 --- a/SOCKS.cpp +++ b/SOCKS.cpp @@ -224,7 +224,7 @@ namespace proxy void SOCKS4AHandler::SentConnectionSuccess(const boost::system::error_code & ecode) { LogPrint("--- socks4a making connection"); - m_stream = i2p::client::context.GetSharedLocalDestination ()->CreateNewOutgoingStream(*m_ls); + m_stream = i2p::client::context.GetSharedLocalDestination ()->CreateStream(*m_ls); m_state = OKAY; LogPrint("--- socks4a state is ", m_state); AsyncSockRead(); diff --git a/SSU.cpp b/SSU.cpp index b26b8319..27eb6c03 100644 --- a/SSU.cpp +++ b/SSU.cpp @@ -12,13 +12,13 @@ namespace i2p { -namespace ssu +namespace transport { 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_DHKeysPair (nullptr), m_PeerTest (peerTest), + const i2p::data::RouterInfo * router, bool peerTest ): TransportSession (router), + m_Server (server), m_RemoteEndpoint (remoteEndpoint), + m_Timer (m_Server.GetService ()), m_PeerTest (peerTest), m_State (eSessionStateUnknown), m_IsSessionKey (false), m_RelayTag (0), m_Data (*this), m_NumSentBytes (0), m_NumReceivedBytes (0) { @@ -28,8 +28,7 @@ namespace ssu } SSUSession::~SSUSession () - { - delete m_DHKeysPair; + { } void SSUSession::CreateAESandMacKey (const uint8_t * pubKey) @@ -174,7 +173,7 @@ namespace ssu LogPrint ("Session request received"); m_RemoteEndpoint = senderEndpoint; if (!m_DHKeysPair) - m_DHKeysPair = i2p::transports.GetNextDHKeysPair (); + m_DHKeysPair = transports.GetNextDHKeysPair (); CreateAESandMacKey (buf + sizeof (SSUHeader)); SendSessionCreated (buf + sizeof (SSUHeader)); } @@ -215,10 +214,7 @@ namespace ssu m_SessionKeyDecryption.SetIV (((SSUHeader *)buf)->iv); m_SessionKeyDecryption.Decrypt (payload, 48, payload); // 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)) + if (!m_RemoteIdentity.Verify (signedData, 532, payload)) LogPrint ("SSU signature verification failed"); SendSessionConfirmed (y, ourAddress); @@ -231,17 +227,15 @@ namespace ssu payload++; // identity fragment info uint16_t identitySize = be16toh (*(uint16_t *)payload); payload += 2; // size of identity fragment - if (identitySize == i2p::data::DEFAULT_IDENTITY_SIZE) - { - i2p::data::Identity ident; - ident.FromBuffer (payload, identitySize); - m_RemoteIdent = ident.Hash (); - m_Data.UpdatePacketSize (m_RemoteIdent); - } - else - LogPrint ("SSU unexpected identity size ", identitySize); + m_RemoteIdentity.FromBuffer (payload, identitySize); + m_Data.UpdatePacketSize (m_RemoteIdentity.GetIdentHash ()); payload += identitySize; // identity - // TODO: verify signature + payload += 4; // signed-on time + size_t paddingSize = (payload - buf) + m_RemoteIdentity.GetSignatureLen (); + paddingSize >>= 4; // %16 + if (paddingSize > 0) paddingSize = 16 - paddingSize; + payload += paddingSize; + // TODO: verify signature (need data from session request), payload points to signature SendI2NPMessage (CreateDeliveryStatusMsg (0)); Established (); } @@ -360,10 +354,10 @@ namespace ssu uint8_t * payload = buf + sizeof (SSUHeader); *payload = 1; // 1 fragment payload++; // info - size_t identLen = sizeof (i2p::context.GetRouterIdentity ()); // 387 bytes + size_t identLen = i2p::data::DEFAULT_IDENTITY_SIZE; // 387 bytes *(uint16_t *)(payload) = htobe16 (identLen); payload += 2; // cursize - memcpy (payload, (uint8_t *)&i2p::context.GetRouterIdentity (), identLen); + memcpy (payload, (uint8_t *)&i2p::context.GetIdentity ().GetStandardIdentity (), identLen); // TODO payload += identLen; uint32_t signedOnTime = i2p::util::GetSecondsSinceEpoch (); *(uint32_t *)(payload) = htobe32 (signedOnTime); // signed on time @@ -609,7 +603,7 @@ namespace ssu { // set connect timer ScheduleConnectTimer (); - m_DHKeysPair = i2p::transports.GetNextDHKeysPair (); + m_DHKeysPair = transports.GetNextDHKeysPair (); SendSessionRequest (); } } diff --git a/SSU.h b/SSU.h index f69f8c4e..b9fb781e 100644 --- a/SSU.h +++ b/SSU.h @@ -13,11 +13,12 @@ #include "Identity.h" #include "RouterInfo.h" #include "I2NPProtocol.h" +#include "TransportSession.h" #include "SSUData.h" namespace i2p { -namespace ssu +namespace transport { #pragma pack(1) struct SSUHeader @@ -57,7 +58,7 @@ namespace ssu }; class SSUServer; - class SSUSession + class SSUSession: public TransportSession { public: @@ -71,7 +72,6 @@ namespace ssu void WaitForIntroduction (); void Close (); 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 @@ -128,10 +128,7 @@ namespace ssu friend class SSUData; // TODO: change in later SSUServer& m_Server; boost::asio::ip::udp::endpoint m_RemoteEndpoint; - const i2p::data::RouterInfo * m_RemoteRouter; - i2p::data::IdentHash m_RemoteIdent; // if m_RemoteRouter is null boost::asio::deadline_timer m_Timer; - i2p::data::DHKeysPair * m_DHKeysPair; // X - for client and Y - for server bool m_PeerTest; SessionState m_State; bool m_IsSessionKey; diff --git a/SSUData.cpp b/SSUData.cpp index 377c8fbb..8eb69051 100644 --- a/SSUData.cpp +++ b/SSUData.cpp @@ -8,7 +8,7 @@ namespace i2p { -namespace ssu +namespace transport { SSUData::SSUData (SSUSession& session): m_Session (session), m_ResendTimer (session.m_Server.GetService ()) diff --git a/SSUData.h b/SSUData.h index 9ac431a2..2b6abead 100644 --- a/SSUData.h +++ b/SSUData.h @@ -13,7 +13,7 @@ namespace i2p { -namespace ssu +namespace transport { const size_t SSU_MTU = 1484; diff --git a/Streaming.cpp b/Streaming.cpp index 5b871cf2..dba42d29 100644 --- a/Streaming.cpp +++ b/Streaming.cpp @@ -1,3 +1,4 @@ +#include #include "Log.h" #include "RouterInfo.h" #include "RouterContext.h" @@ -11,12 +12,12 @@ namespace i2p namespace stream { Stream::Stream (boost::asio::io_service& service, StreamingDestination& local, - const i2p::data::LeaseSet& remote): m_Service (service), m_SendStreamID (0), + const i2p::data::LeaseSet& remote, int port): m_Service (service), m_SendStreamID (0), m_SequenceNumber (0), m_LastReceivedSequenceNumber (-1), m_IsOpen (false), m_IsReset (false), m_IsAckSendScheduled (false), m_LocalDestination (local), m_RemoteLeaseSet (&remote), m_RoutingSession (nullptr), m_ReceiveTimer (m_Service), m_ResendTimer (m_Service), m_AckSendTimer (m_Service), m_NumSentBytes (0), - m_NumReceivedBytes (0) + m_NumReceivedBytes (0), m_Port (port) { m_RecvStreamID = i2p::context.GetRandomNumberGenerator ().GenerateWord32 (); UpdateCurrentRemoteLease (); @@ -27,7 +28,7 @@ namespace stream m_IsOpen (false), m_IsReset (false), m_IsAckSendScheduled (false), m_LocalDestination (local), m_RemoteLeaseSet (nullptr), m_RoutingSession (nullptr), m_ReceiveTimer (m_Service), m_ResendTimer (m_Service), m_AckSendTimer (m_Service), m_NumSentBytes (0), - m_NumReceivedBytes (0) + m_NumReceivedBytes (0), m_Port (0) { m_RecvStreamID = i2p::context.GetRandomNumberGenerator ().GenerateWord32 (); } @@ -115,7 +116,7 @@ namespace stream { // we have received duplicate. Most likely our outbound tunnel is dead LogPrint ("Duplicate message ", receivedSeqn, " received"); - m_LocalDestination.ResetCurrentOutboundTunnel (); // pick another outbound tunnel + m_LocalDestination.GetOwner ().ResetCurrentOutboundTunnel (); // pick another outbound tunnel UpdateCurrentRemoteLease (); // pick another lease SendQuickAck (); // resend ack for previous message again delete packet; // packet dropped @@ -274,11 +275,11 @@ namespace stream if (isNoAck) flags |= PACKET_FLAG_NO_ACK; *(uint16_t *)(packet + size) = htobe16 (flags); size += 2; // flags - size_t identityLen = m_LocalDestination.GetIdentity ().GetFullLen (); - size_t signatureLen = m_LocalDestination.GetIdentity ().GetSignatureLen (); + size_t identityLen = m_LocalDestination.GetOwner ().GetIdentity ().GetFullLen (); + size_t signatureLen = m_LocalDestination.GetOwner ().GetIdentity ().GetSignatureLen (); *(uint16_t *)(packet + size) = htobe16 (identityLen + signatureLen + 2); // identity + signature + packet size size += 2; // options size - m_LocalDestination.GetIdentity ().ToBuffer (packet + size, identityLen); + m_LocalDestination.GetOwner ().GetIdentity ().ToBuffer (packet + size, identityLen); size += identityLen; // from *(uint16_t *)(packet + size) = htobe16 (STREAMING_MTU); size += 2; // max packet size @@ -291,7 +292,7 @@ namespace stream buf += sentLen; len -= sentLen; size += sentLen; // payload - m_LocalDestination.Sign (packet, size, signature); + m_LocalDestination.GetOwner ().Sign (packet, size, signature); } else { @@ -362,13 +363,13 @@ namespace stream size++; // resend delay *(uint16_t *)(packet + size) = htobe16 (PACKET_FLAG_CLOSE | PACKET_FLAG_SIGNATURE_INCLUDED); size += 2; // flags - size_t signatureLen = m_LocalDestination.GetIdentity ().GetSignatureLen (); + size_t signatureLen = m_LocalDestination.GetOwner ().GetIdentity ().GetSignatureLen (); *(uint16_t *)(packet + size) = htobe16 (signatureLen); // signature only size += 2; // options size uint8_t * signature = packet + size; memset (packet + size, 0, signatureLen); size += signatureLen; // signature - m_LocalDestination.Sign (packet, size, signature); + m_LocalDestination.GetOwner ().Sign (packet, size, signature); p->len = size; SendPacket (p); @@ -440,8 +441,7 @@ namespace stream std::vector msgs; for (auto it: packets) { - auto msg = m_RoutingSession->WrapSingleMessage ( - m_LocalDestination.CreateDataMessage (it->GetBuffer (), it->GetLength ())); + auto msg = m_RoutingSession->WrapSingleMessage (CreateDataMessage (it->GetBuffer (), it->GetLength ())); msgs.push_back (i2p::tunnel::TunnelMessageBlock { i2p::tunnel::eDeliveryTypeTunnel, @@ -450,7 +450,7 @@ namespace stream }); m_NumSentBytes += it->GetLength (); } - m_LocalDestination.SendTunnelDataMsgs (msgs); + m_LocalDestination.GetOwner ().SendTunnelDataMsgs (msgs); } else LogPrint ("All leases are expired"); @@ -484,7 +484,7 @@ namespace stream } if (packets.size () > 0) { - m_LocalDestination.ResetCurrentOutboundTunnel (); // pick another outbound tunnel + m_LocalDestination.GetOwner ().ResetCurrentOutboundTunnel (); // pick another outbound tunnel UpdateCurrentRemoteLease (); // pick another lease SendPackets (packets); } @@ -506,14 +506,14 @@ namespace stream { if (!m_RemoteLeaseSet) { - m_RemoteLeaseSet = m_LocalDestination.FindLeaseSet (m_RemoteIdentity.GetIdentHash ()); + m_RemoteLeaseSet = m_LocalDestination.GetOwner ().FindLeaseSet (m_RemoteIdentity.GetIdentHash ()); if (!m_RemoteLeaseSet) LogPrint ("LeaseSet ", m_RemoteIdentity.GetIdentHash ().ToBase64 (), " not found"); } if (m_RemoteLeaseSet) { if (!m_RoutingSession) - m_RoutingSession = m_LocalDestination.GetRoutingSession (*m_RemoteLeaseSet, 32); + m_RoutingSession = m_LocalDestination.GetOwner ().GetRoutingSession (*m_RemoteLeaseSet, 32); auto leases = m_RemoteLeaseSet->GetNonExpiredLeases (); if (!leases.empty ()) { @@ -522,12 +522,139 @@ namespace stream } else { - m_RemoteLeaseSet = m_LocalDestination.FindLeaseSet (m_RemoteIdentity.GetIdentHash ()); // re-request expired + m_RemoteLeaseSet = m_LocalDestination.GetOwner ().FindLeaseSet (m_RemoteIdentity.GetIdentHash ()); // re-request expired m_CurrentRemoteLease.endDate = 0; } } else m_CurrentRemoteLease.endDate = 0; + } + + I2NPMessage * Stream::CreateDataMessage (const uint8_t * payload, size_t len) + { + I2NPMessage * msg = NewI2NPShortMessage (); + CryptoPP::Gzip compressor; + if (len <= i2p::stream::COMPRESSION_THRESHOLD_SIZE) + compressor.SetDeflateLevel (CryptoPP::Gzip::MIN_DEFLATE_LEVEL); + else + compressor.SetDeflateLevel (CryptoPP::Gzip::DEFAULT_DEFLATE_LEVEL); + compressor.Put (payload, len); + compressor.MessageEnd(); + int size = compressor.MaxRetrievable (); + uint8_t * buf = msg->GetPayload (); + *(uint32_t *)buf = htobe32 (size); // length + buf += 4; + compressor.Get (buf, size); + *(uint16_t *)(buf + 4) = 0; // source port + *(uint16_t *)(buf + 6) = htobe16 (m_Port); // destination port + buf[9] = i2p::client::PROTOCOL_TYPE_STREAMING; // streaming protocol + msg->len += size + 4; + FillI2NPMessageHeader (msg, eI2NPData); + + return msg; + } + + void StreamingDestination::Start () + { + } + + void StreamingDestination::Stop () + { + ResetAcceptor (); + { + std::unique_lock l(m_StreamsMutex); + for (auto it: m_Streams) + delete it.second; + m_Streams.clear (); + } + } + + void StreamingDestination::HandleNextPacket (Packet * packet) + { + uint32_t sendStreamID = packet->GetSendStreamID (); + if (sendStreamID) + { + auto it = m_Streams.find (sendStreamID); + if (it != m_Streams.end ()) + it->second->HandleNextPacket (packet); + else + { + LogPrint ("Unknown stream ", sendStreamID); + delete packet; + } + } + else // new incoming stream + { + auto incomingStream = CreateNewIncomingStream (); + incomingStream->HandleNextPacket (packet); + if (m_Acceptor != nullptr) + m_Acceptor (incomingStream); + else + { + LogPrint ("Acceptor for incoming stream is not set"); + DeleteStream (incomingStream); + } + } + } + + Stream * StreamingDestination::CreateNewOutgoingStream (const i2p::data::LeaseSet& remote, int port) + { + Stream * s = new Stream (*m_Owner.GetService (), *this, remote, port); + std::unique_lock l(m_StreamsMutex); + m_Streams[s->GetRecvStreamID ()] = s; + return s; + } + + Stream * StreamingDestination::CreateNewIncomingStream () + { + Stream * s = new Stream (*m_Owner.GetService (), *this); + std::unique_lock l(m_StreamsMutex); + m_Streams[s->GetRecvStreamID ()] = s; + return s; + } + + void StreamingDestination::DeleteStream (Stream * stream) + { + if (stream) + { + std::unique_lock l(m_StreamsMutex); + auto it = m_Streams.find (stream->GetRecvStreamID ()); + if (it != m_Streams.end ()) + { + m_Streams.erase (it); + if (m_Owner.GetService ()) + m_Owner.GetService ()->post ([stream](void) { delete stream; }); + else + delete stream; + } + } } + + void StreamingDestination::HandleDataMessagePayload (const uint8_t * buf, size_t len) + { + // unzip it + CryptoPP::Gunzip decompressor; + decompressor.Put (buf, len); + decompressor.MessageEnd(); + Packet * uncompressed = new Packet; + uncompressed->offset = 0; + uncompressed->len = decompressor.MaxRetrievable (); + if (uncompressed->len <= MAX_PACKET_SIZE) + { + decompressor.Get (uncompressed->buf, uncompressed->len); + HandleNextPacket (uncompressed); + } + else + { + LogPrint ("Received packet size ", uncompressed->len, " exceeds max packet size. Skipped"); + delete uncompressed; + } + } + + void DeleteStream (Stream * stream) + { + if (stream) + stream->GetLocalDestination ().DeleteStream (stream); + } } } diff --git a/Streaming.h b/Streaming.h index 5c02913d..1c8958b2 100644 --- a/Streaming.h +++ b/Streaming.h @@ -18,6 +18,10 @@ namespace i2p { +namespace client +{ + class ClientDestination; +} namespace stream { const uint16_t PACKET_FLAG_SYNCHRONIZE = 0x0001; @@ -78,7 +82,8 @@ namespace stream { public: - Stream (boost::asio::io_service& service, StreamingDestination& local, const i2p::data::LeaseSet& remote); // outgoing + Stream (boost::asio::io_service& service, StreamingDestination& local, + const i2p::data::LeaseSet& remote, int port = 0); // outgoing Stream (boost::asio::io_service& service, StreamingDestination& local); // incoming ~Stream (); @@ -122,6 +127,8 @@ namespace stream void ScheduleResend (); void HandleResendTimer (const boost::system::error_code& ecode); void HandleAckSendTimer (const boost::system::error_code& ecode); + + I2NPMessage * CreateDataMessage (const uint8_t * payload, size_t len); private: @@ -139,8 +146,48 @@ namespace stream std::set m_SentPackets; boost::asio::deadline_timer m_ReceiveTimer, m_ResendTimer, m_AckSendTimer; size_t m_NumSentBytes, m_NumReceivedBytes; + uint16_t m_Port; }; + class StreamingDestination + { + public: + + StreamingDestination (i2p::client::ClientDestination& owner): m_Owner (owner) {}; + ~StreamingDestination () {}; + + void Start (); + void Stop (); + + Stream * CreateNewOutgoingStream (const i2p::data::LeaseSet& remote, int port = 0); + void DeleteStream (Stream * stream); + void SetAcceptor (const std::function& acceptor) { m_Acceptor = acceptor; }; + void ResetAcceptor () { m_Acceptor = nullptr; }; + bool IsAcceptorSet () const { return m_Acceptor != nullptr; }; + i2p::client::ClientDestination& GetOwner () { return m_Owner; }; + + void HandleDataMessagePayload (const uint8_t * buf, size_t len); + + private: + + void HandleNextPacket (Packet * packet); + Stream * CreateNewIncomingStream (); + + private: + + i2p::client::ClientDestination& m_Owner; + std::mutex m_StreamsMutex; + std::map m_Streams; + std::function m_Acceptor; + + public: + + // for HTTP only + const decltype(m_Streams)& GetStreams () const { return m_Streams; }; + }; + + void DeleteStream (Stream * stream); + //------------------------------------------------- template diff --git a/TransitTunnel.cpp b/TransitTunnel.cpp index 9ed8a542..25b82424 100644 --- a/TransitTunnel.cpp +++ b/TransitTunnel.cpp @@ -34,7 +34,7 @@ namespace tunnel *(uint32_t *)(tunnelMsg->GetPayload ()) = htobe32 (m_NextTunnelID); FillI2NPMessageHeader (tunnelMsg, eI2NPTunnelData); - i2p::transports.SendMessage (m_NextIdent, tunnelMsg); + i2p::transport::transports.SendMessage (m_NextIdent, tunnelMsg); } void TransitTunnel::SendTunnelDataMsg (i2p::I2NPMessage * msg) diff --git a/TransportSession.h b/TransportSession.h new file mode 100644 index 00000000..0e993508 --- /dev/null +++ b/TransportSession.h @@ -0,0 +1,43 @@ +#ifndef TRANSPORT_SESSION_H__ +#define TRANSPORT_SESSION_H__ + +#include +#include "Identity.h" +#include "RouterInfo.h" + +namespace i2p +{ +namespace transport +{ + struct DHKeysPair // transient keys for transport sessions + { + uint8_t publicKey[256]; + uint8_t privateKey[256]; + }; + + class TransportSession + { + public: + + TransportSession (const i2p::data::RouterInfo * in_RemoteRouter): + m_RemoteRouter (in_RemoteRouter), m_DHKeysPair (nullptr) + { + if (m_RemoteRouter) + m_RemoteIdentity = m_RemoteRouter->GetRouterIdentity (); + } + + virtual ~TransportSession () { delete m_DHKeysPair; }; + + const i2p::data::RouterInfo * GetRemoteRouter () { return m_RemoteRouter; }; + const i2p::data::IdentityEx& GetRemoteIdentity () { return m_RemoteIdentity; }; + + protected: + + const i2p::data::RouterInfo * m_RemoteRouter; + i2p::data::IdentityEx m_RemoteIdentity; + DHKeysPair * m_DHKeysPair; // X - for client and Y - for server + }; +} +} + +#endif diff --git a/Transports.cpp b/Transports.cpp index a49923c1..c0c7bfca 100644 --- a/Transports.cpp +++ b/Transports.cpp @@ -1,5 +1,7 @@ +#include #include #include "Log.h" +#include "CryptoConst.h" #include "RouterContext.h" #include "I2NPProtocol.h" #include "NetDb.h" @@ -9,6 +11,13 @@ using namespace i2p::data; namespace i2p { +namespace transport +{ + DHKeysPairSupplier::DHKeysPairSupplier (int size): + m_QueueSize (size), m_IsRunning (false), m_Thread (nullptr) + { + } + DHKeysPairSupplier::~DHKeysPairSupplier () { Stop (); @@ -48,17 +57,18 @@ namespace i2p { if (num > 0) { + CryptoPP::DH dh (i2p::crypto::elgp, i2p::crypto::elgg); for (int i = 0; i < num; i++) { - i2p::data::DHKeysPair * pair = new i2p::data::DHKeysPair (); - i2p::data::CreateRandomDHKeysPair (pair); + i2p::transport::DHKeysPair * pair = new i2p::transport::DHKeysPair (); + dh.GenerateKeyPair(m_Rnd, pair->privateKey, pair->publicKey); std::unique_lock l(m_AcquiredMutex); m_Queue.push (pair); } } } - i2p::data::DHKeysPair * DHKeysPairSupplier::Acquire () + DHKeysPair * DHKeysPairSupplier::Acquire () { if (!m_Queue.empty ()) { @@ -70,13 +80,14 @@ namespace i2p } else // queue is empty, create new { - i2p::data::DHKeysPair * pair = new i2p::data::DHKeysPair (); - i2p::data::CreateRandomDHKeysPair (pair); + DHKeysPair * pair = new DHKeysPair (); + CryptoPP::DH dh (i2p::crypto::elgp, i2p::crypto::elgg); + dh.GenerateKeyPair(m_Rnd, pair->privateKey, pair->publicKey); return pair; } } - void DHKeysPairSupplier::Return (i2p::data::DHKeysPair * pair) + void DHKeysPairSupplier::Return (DHKeysPair * pair) { std::unique_lock l(m_AcquiredMutex); m_Queue.push (pair); @@ -85,7 +96,7 @@ namespace i2p Transports transports; Transports::Transports (): - m_Thread (nullptr), m_Work (m_Service), m_NTCPAcceptor (nullptr), + m_Thread (nullptr), m_Work (m_Service), m_NTCPAcceptor (nullptr), m_NTCPV6Acceptor (nullptr), m_SSUServer (nullptr), m_DHKeysPairSupplier (5) // 5 pre-generated keys { } @@ -110,15 +121,26 @@ namespace i2p boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), address.port)); LogPrint ("Start listening TCP port ", address.port); - auto conn = new i2p::ntcp::NTCPServerConnection (m_Service); + auto conn = new NTCPServerConnection (m_Service); m_NTCPAcceptor->async_accept(conn->GetSocket (), boost::bind (&Transports::HandleAccept, this, conn, boost::asio::placeholders::error)); + + if (context.SupportsV6 ()) + { + m_NTCPV6Acceptor = new boost::asio::ip::tcp::acceptor (m_Service, + boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v6(), address.port)); + + LogPrint ("Start listening V6 TCP port ", address.port); + auto conn = new NTCPServerConnection (m_Service); + m_NTCPV6Acceptor->async_accept(conn->GetSocket (), boost::bind (&Transports::HandleAcceptV6, + this, conn, boost::asio::placeholders::error)); + } } else if (address.transportStyle == RouterInfo::eTransportSSU) { if (!m_SSUServer) { - m_SSUServer = new i2p::ssu::SSUServer (address.port); + m_SSUServer = new SSUServer (address.port); LogPrint ("Start listening UDP port ", address.port); m_SSUServer->Start (); DetectExternalIP (); @@ -143,6 +165,8 @@ namespace i2p m_NTCPSessions.clear (); delete m_NTCPAcceptor; m_NTCPAcceptor = nullptr; + delete m_NTCPV6Acceptor; + m_NTCPV6Acceptor = nullptr; m_DHKeysPairSupplier.Stop (); m_IsRunning = false; @@ -170,19 +194,19 @@ namespace i2p } } - void Transports::AddNTCPSession (i2p::ntcp::NTCPSession * session) + void Transports::AddNTCPSession (NTCPSession * session) { if (session) - m_NTCPSessions[session->GetRemoteRouterInfo ().GetIdentHash ()] = session; + m_NTCPSessions[session->GetRemoteIdentity ().GetIdentHash ()] = session; } - void Transports::RemoveNTCPSession (i2p::ntcp::NTCPSession * session) + void Transports::RemoveNTCPSession (NTCPSession * session) { if (session) - m_NTCPSessions.erase (session->GetRemoteRouterInfo ().GetIdentHash ()); + m_NTCPSessions.erase (session->GetRemoteIdentity ().GetIdentHash ()); } - void Transports::HandleAccept (i2p::ntcp::NTCPServerConnection * conn, const boost::system::error_code& error) + void Transports::HandleAccept (NTCPServerConnection * conn, const boost::system::error_code& error) { if (!error) { @@ -194,13 +218,31 @@ namespace i2p if (error != boost::asio::error::operation_aborted) { - conn = new i2p::ntcp::NTCPServerConnection (m_Service); + conn = new NTCPServerConnection (m_Service); m_NTCPAcceptor->async_accept(conn->GetSocket (), boost::bind (&Transports::HandleAccept, this, conn, boost::asio::placeholders::error)); } } - i2p::ntcp::NTCPSession * Transports::GetNextNTCPSession () + void Transports::HandleAcceptV6 (NTCPServerConnection * conn, const boost::system::error_code& error) + { + if (!error) + { + LogPrint ("Connected from ", conn->GetSocket ().remote_endpoint().address ().to_string ()); + conn->ServerLogin (); + } + else + delete conn; + + if (error != boost::asio::error::operation_aborted) + { + conn = new NTCPServerConnection (m_Service); + m_NTCPV6Acceptor->async_accept(conn->GetSocket (), boost::bind (&Transports::HandleAcceptV6, this, + conn, boost::asio::placeholders::error)); + } + } + + NTCPSession * Transports::GetNextNTCPSession () { for (auto session: m_NTCPSessions) if (session.second->IsEstablished ()) @@ -208,7 +250,7 @@ namespace i2p return 0; } - i2p::ntcp::NTCPSession * Transports::FindNTCPSession (const i2p::data::IdentHash& ident) + NTCPSession * Transports::FindNTCPSession (const i2p::data::IdentHash& ident) { auto it = m_NTCPSessions.find (ident); if (it != m_NTCPSessions.end ()) @@ -242,10 +284,10 @@ namespace i2p { // existing session not found. create new // try NTCP first if message size < 16K - auto address = r->GetNTCPAddress (); - if (address && !r->UsesIntroducer () && !r->IsUnreachable () && msg->GetLength () < i2p::ntcp::NTCP_MAX_MESSAGE_SIZE) + auto address = r->GetNTCPAddress (!context.SupportsV6 ()); + if (address && !r->UsesIntroducer () && !r->IsUnreachable () && msg->GetLength () < NTCP_MAX_MESSAGE_SIZE) { - auto s = new i2p::ntcp::NTCPClient (m_Service, address->host, address->port, *r); + auto s = new NTCPClient (m_Service, address->host, address->port, *r); AddNTCPSession (s); s->SendI2NPMessage (msg); } @@ -318,15 +360,16 @@ namespace i2p m_SSUServer->GetSession (router, true); // peer test } } - - - i2p::data::DHKeysPair * Transports::GetNextDHKeysPair () + + DHKeysPair * Transports::GetNextDHKeysPair () { return m_DHKeysPairSupplier.Acquire (); } - void Transports::ReuseDHKeysPair (i2p::data::DHKeysPair * pair) + void Transports::ReuseDHKeysPair (DHKeysPair * pair) { m_DHKeysPairSupplier.Return (pair); } } +} + diff --git a/Transports.h b/Transports.h index 88f43b26..d306de77 100644 --- a/Transports.h +++ b/Transports.h @@ -8,7 +8,9 @@ #include #include #include +#include #include +#include "TransportSession.h" #include "NTCPSession.h" #include "SSU.h" #include "RouterInfo.h" @@ -16,17 +18,19 @@ #include "Identity.h" namespace i2p +{ +namespace transport { class DHKeysPairSupplier { public: - DHKeysPairSupplier (int size): m_QueueSize (size), m_IsRunning (false), m_Thread (nullptr) {}; + DHKeysPairSupplier (int size); ~DHKeysPairSupplier (); void Start (); void Stop (); - i2p::data::DHKeysPair * Acquire (); - void Return (i2p::data::DHKeysPair * pair); + DHKeysPair * Acquire (); + void Return (DHKeysPair * pair); private: @@ -36,12 +40,13 @@ namespace i2p private: const int m_QueueSize; - std::queue m_Queue; + std::queue m_Queue; bool m_IsRunning; std::thread * m_Thread; std::condition_variable m_Acquired; std::mutex m_AcquiredMutex; + CryptoPP::AutoSeededRandomPool m_Rnd; }; class Transports @@ -55,14 +60,14 @@ namespace i2p void Stop (); boost::asio::io_service& GetService () { return m_Service; }; - i2p::data::DHKeysPair * GetNextDHKeysPair (); - void ReuseDHKeysPair (i2p::data::DHKeysPair * pair); + i2p::transport::DHKeysPair * GetNextDHKeysPair (); + void ReuseDHKeysPair (DHKeysPair * pair); - void AddNTCPSession (i2p::ntcp::NTCPSession * session); - void RemoveNTCPSession (i2p::ntcp::NTCPSession * session); + void AddNTCPSession (NTCPSession * session); + void RemoveNTCPSession (NTCPSession * session); - i2p::ntcp::NTCPSession * GetNextNTCPSession (); - i2p::ntcp::NTCPSession * FindNTCPSession (const i2p::data::IdentHash& ident); + NTCPSession * GetNextNTCPSession (); + NTCPSession * FindNTCPSession (const i2p::data::IdentHash& ident); void SendMessage (const i2p::data::IdentHash& ident, i2p::I2NPMessage * msg); void CloseSession (const i2p::data::RouterInfo * router); @@ -70,7 +75,8 @@ namespace i2p private: void Run (); - void HandleAccept (i2p::ntcp::NTCPServerConnection * conn, const boost::system::error_code& error); + void HandleAccept (NTCPServerConnection * conn, const boost::system::error_code& error); + void HandleAcceptV6 (NTCPServerConnection * conn, const boost::system::error_code& error); void HandleResendTimer (const boost::system::error_code& ecode, boost::asio::deadline_timer * timer, const i2p::data::IdentHash& ident, i2p::I2NPMessage * msg); void PostMessage (const i2p::data::IdentHash& ident, i2p::I2NPMessage * msg); @@ -84,10 +90,10 @@ namespace i2p std::thread * m_Thread; boost::asio::io_service m_Service; boost::asio::io_service::work m_Work; - boost::asio::ip::tcp::acceptor * m_NTCPAcceptor; + boost::asio::ip::tcp::acceptor * m_NTCPAcceptor, * m_NTCPV6Acceptor; - std::map m_NTCPSessions; - i2p::ssu::SSUServer * m_SSUServer; + std::map m_NTCPSessions; + SSUServer * m_SSUServer; DHKeysPairSupplier m_DHKeysPairSupplier; @@ -95,10 +101,11 @@ namespace i2p // for HTTP only const decltype(m_NTCPSessions)& GetNTCPSessions () const { return m_NTCPSessions; }; - const i2p::ssu::SSUServer * GetSSUServer () const { return m_SSUServer; }; + const SSUServer * GetSSUServer () const { return m_SSUServer; }; }; extern Transports transports; } +} #endif diff --git a/Tunnel.cpp b/Tunnel.cpp index 2da68772..c16981ae 100644 --- a/Tunnel.cpp +++ b/Tunnel.cpp @@ -92,7 +92,7 @@ namespace tunnel if (outboundTunnel) outboundTunnel->SendTunnelDataMsg (GetNextIdentHash (), 0, msg); else - i2p::transports.SendMessage (GetNextIdentHash (), msg); + i2p::transport::transports.SendMessage (GetNextIdentHash (), msg); } bool Tunnel::HandleTunnelBuildResponse (uint8_t * msg, size_t len) diff --git a/TunnelEndpoint.cpp b/TunnelEndpoint.cpp index ca46199a..6074254e 100644 --- a/TunnelEndpoint.cpp +++ b/TunnelEndpoint.cpp @@ -235,7 +235,7 @@ namespace tunnel i2p::HandleI2NPMessage (msg.data); break; case eDeliveryTypeTunnel: - i2p::transports.SendMessage (msg.hash, i2p::CreateTunnelGatewayMsg (msg.tunnelID, msg.data)); + i2p::transport::transports.SendMessage (msg.hash, i2p::CreateTunnelGatewayMsg (msg.tunnelID, msg.data)); break; case eDeliveryTypeRouter: if (msg.hash == i2p::context.GetRouterInfo ().GetIdentHash ()) // check if message is sent to us @@ -253,7 +253,7 @@ namespace tunnel *ds = *(msg.data); i2p::data::netdb.PostI2NPMsg (ds); } - i2p::transports.SendMessage (msg.hash, msg.data); + i2p::transport::transports.SendMessage (msg.hash, msg.data); } else // we shouldn't send this message. possible leakage { diff --git a/TunnelGateway.cpp b/TunnelGateway.cpp index be9c6a4b..d2996b17 100644 --- a/TunnelGateway.cpp +++ b/TunnelGateway.cpp @@ -12,8 +12,12 @@ namespace tunnel { void TunnelGatewayBuffer::PutI2NPMsg (const TunnelMessageBlock& block) { + bool messageCreated = false; if (!m_CurrentTunnelDataMsg) + { CreateCurrentTunnelDataMessage (); + messageCreated = true; + } // create delivery instructions uint8_t di[43]; // max delivery instruction length is 43 for tunnel @@ -33,7 +37,8 @@ namespace tunnel // create fragments I2NPMessage * msg = block.data; - if (diLen + msg->GetLength () + 2<= m_RemainingSize) + auto fullMsgLen = diLen + msg->GetLength () + 2; // delivery instructions + payload + 2 bytes length + if (fullMsgLen <= m_RemainingSize) { // message fits. First and last fragment *(uint16_t *)(di + diLen) = htobe16 (msg->GetLength ()); @@ -48,6 +53,18 @@ namespace tunnel } else { + if (!messageCreated) // check if we should complete previous message + { + auto numFollowOnFragments = fullMsgLen / TUNNEL_DATA_MAX_PAYLOAD_SIZE; + // length of bytes don't fit full tunnel message + // every follow-on fragment adds 7 bytes + auto nonFit = (fullMsgLen + numFollowOnFragments*7) % TUNNEL_DATA_MAX_PAYLOAD_SIZE; + if (!nonFit || nonFit > m_RemainingSize) + { + CompleteCurrentTunnelDataMessage (); + CreateCurrentTunnelDataMessage (); + } + } if (diLen + 6 <= m_RemainingSize) { // delivery instructions fit @@ -169,7 +186,7 @@ namespace tunnel { m_Tunnel->EncryptTunnelMsg (tunnelMsg); FillI2NPMessageHeader (tunnelMsg, eI2NPTunnelData); - i2p::transports.SendMessage (m_Tunnel->GetNextIdentHash (), tunnelMsg); + i2p::transport::transports.SendMessage (m_Tunnel->GetNextIdentHash (), tunnelMsg); m_NumSentBytes += TUNNEL_DATA_MSG_SIZE; } m_Buffer.ClearTunnelDataMsgs (); diff --git a/TunnelPool.cpp b/TunnelPool.cpp index ac63cf7b..f756ebd4 100644 --- a/TunnelPool.cpp +++ b/TunnelPool.cpp @@ -257,7 +257,7 @@ namespace tunnel { // last hop auto hop = outboundTunnel->GetTunnelConfig ()->GetFirstHop ()->router; - if (hop->GetIdentHash () != i2p::context.GetRouterIdentHash ()) // outbound shouldn't be zero-hop tunnel + if (hop->GetIdentHash () != i2p::context.GetIdentHash ()) // outbound shouldn't be zero-hop tunnel { prevHop = hop; hops.push_back (prevHop); diff --git a/TunnelPool.h b/TunnelPool.h index da59866c..76ba45d8 100644 --- a/TunnelPool.h +++ b/TunnelPool.h @@ -33,7 +33,7 @@ namespace tunnel const uint8_t * GetEncryptionPublicKey () const { return m_LocalDestination.GetEncryptionPublicKey (); }; const i2p::data::LocalDestination& GetLocalDestination () const { return m_LocalDestination; }; i2p::garlic::GarlicDestination& GetGarlicDestination () const { return m_LocalDestination; }; - bool IsExploratory () const { return GetIdentHash () == i2p::context.GetRouterIdentHash (); }; + bool IsExploratory () const { return GetIdentHash () == i2p::context.GetIdentHash (); }; void CreateTunnels (); void TunnelCreated (InboundTunnel * createdTunnel); diff --git a/Win32/i2pd.vcxproj b/Win32/i2pd.vcxproj index c071c131..2bbba99b 100644 --- a/Win32/i2pd.vcxproj +++ b/Win32/i2pd.vcxproj @@ -47,6 +47,7 @@ + @@ -91,6 +92,8 @@ + + diff --git a/build/CMakeLists.txt b/build/CMakeLists.txt index 55b5e6e5..02475c0d 100644 --- a/build/CMakeLists.txt +++ b/build/CMakeLists.txt @@ -43,7 +43,8 @@ set (SOURCES "${CMAKE_SOURCE_DIR}/i2p.cpp" "${CMAKE_SOURCE_DIR}/util.cpp" "${CMAKE_SOURCE_DIR}/SAM.cpp" - "${CMAKE_SOURCE_DIR}/ClientContext.cpp" + "${CMAKE_SOURCE_DIR}/ClientContext.cpp" + "${CMAKE_SOURCE_DIR}/Datagram.cpp" ) file (GLOB HEADERS "${CMAKE_SOURCE_DIR}/*.h") diff --git a/build/autotools/Makefile.in b/build/autotools/Makefile.in index 16b2cc2b..d80dfd62 100644 --- a/build/autotools/Makefile.in +++ b/build/autotools/Makefile.in @@ -325,7 +325,7 @@ i2p_SOURCES = AddressBook.cpp CryptoConst.cpp Daemon.cpp \ Transports.cpp Tunnel.cpp TunnelEndpoint.cpp \ TunnelGateway.cpp TunnelPool.cpp UPnP.cpp aes.cpp \ base64.cpp i2p.cpp util.cpp SAM.cpp Destination.cpp \ - ClientContext.cpp \ + ClientContext.cpp DataFram.cpp \ \ AddressBook.h CryptoConst.h Daemon.h ElGamal.h \ Garlic.h HTTPProxy.h HTTPServer.h I2NPProtocol.h \ @@ -336,7 +336,8 @@ i2p_SOURCES = AddressBook.cpp CryptoConst.cpp Daemon.cpp \ TransitTunnel.h Transports.h Tunnel.h TunnelBase.h \ TunnelConfig.h TunnelEndpoint.h TunnelGateway.h \ TunnelPool.h UPnP.h aes.h base64.h config.h hmac.h \ - util.h version.h Destination.h ClientContext.h + util.h version.h Destination.h ClientContext.h \ + TransportSession.h Datagram.h AM_LDFLAGS = @BOOST_DATE_TIME_LIB@ @BOOST_FILESYSTEM_LIB@ \ @BOOST_PROGRAM_OPTIONS_LIB@ @BOOST_REGEX_LIB@ \ @@ -485,6 +486,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SAM.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ClientContext.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Datagram.Po@am__quote@ .cpp.o: @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< diff --git a/debian/init.d b/debian/i2pd.init similarity index 88% rename from debian/init.d rename to debian/i2pd.init index 79dea50a..eda135c6 100644 --- a/debian/init.d +++ b/debian/i2pd.init @@ -57,10 +57,10 @@ do_stop() } # Function that sends a SIGHUP to the daemon/service -#do_reload() { -# start-stop-daemon --stop --signal 1 --quiet --pidfile $PIDFILE --name $NAME -# return 0 -#} +do_reload() { + start-stop-daemon --stop --signal 1 --quiet --pidfile $PIDFILE --name $NAME + return 0 +} case "$1" in start) @@ -82,14 +82,12 @@ case "$1" in status) status_of_proc "$DAEMON" "$NAME" && exit 0 || exit $? ;; - #reload|force-reload) - #log_daemon_msg "Reloading $DESC" "$NAME" - #do_reload - #log_end_msg $? - #;; - restart|force-reload) - # If the "reload" option is implemented then remove the - # 'force-reload' alias + reload|force-reload) + log_daemon_msg "Reloading $DESC" "$NAME" + do_reload + log_end_msg $? + ;; + restart) log_daemon_msg "Restarting $DESC" "$NAME" do_stop case "$?" in diff --git a/debian/i2pd.upstart b/debian/i2pd.upstart new file mode 100644 index 00000000..0527935d --- /dev/null +++ b/debian/i2pd.upstart @@ -0,0 +1,10 @@ +description "i2p client daemon" + +start on runlevel [2345] +stop on runlevel [016] or unmounting-filesystem + +# these can be overridden in /etc/init/i2pd.override +env I2P_HOST="1.2.3.4" +env I2P_PORT="4567" + +exec /usr/sbin/i2pd --daemon=0 --log=1 --host=$I2P_HOST --port=$I2P_PORT diff --git a/filelist.mk b/filelist.mk index 1c413f7d..3ca5e9a5 100644 --- a/filelist.mk +++ b/filelist.mk @@ -5,7 +5,7 @@ CPP_FILES := CryptoConst.cpp base64.cpp NTCPSession.cpp RouterInfo.cpp Transport TransitTunnel.cpp I2NPProtocol.cpp Log.cpp Garlic.cpp HTTPServer.cpp Streaming.cpp \ Destination.cpp Identity.cpp SSU.cpp util.cpp Reseed.cpp DaemonLinux.cpp SSUData.cpp \ aes.cpp SOCKS.cpp UPnP.cpp TunnelPool.cpp HTTPProxy.cpp AddressBook.cpp Daemon.cpp \ - I2PTunnel.cpp SAM.cpp ClientContext.cpp i2p.cpp + I2PTunnel.cpp SAM.cpp ClientContext.cpp Datagram.cpp i2p.cpp H_FILES := CryptoConst.h base64.h NTCPSession.h RouterInfo.h Transports.h \ @@ -13,7 +13,7 @@ H_FILES := CryptoConst.h base64.h NTCPSession.h RouterInfo.h Transports.h \ TransitTunnel.h I2NPProtocol.h Log.h Garlic.h HTTPServer.h Streaming.h Destination.h \ Identity.h SSU.h util.h Reseed.h DaemonLinux.h SSUData.h i2p.h aes.h SOCKS.h \ UPnP.h TunnelPool.h HTTPProxy.h AddressBook.h Daemon.h I2PTunnel.h version.h \ - Signature.h SAM.h ClientContext.h + Signature.h SAM.h ClientContext.h TransportSession.h Datagram.h OBJECTS = $(addprefix obj/, $(notdir $(CPP_FILES:.cpp=.o)))