diff --git a/ClientContext.cpp b/ClientContext.cpp index 19d841d3..ea459a13 100644 --- a/ClientContext.cpp +++ b/ClientContext.cpp @@ -303,7 +303,7 @@ namespace client LogPrint (eLogError, "Clients: I2P client tunnel with port ", port, " already exists"); numClientTunnels++; } - else if (type == I2P_TUNNELS_SECTION_TYPE_SERVER || type == I2P_TUNNELS_SECTION_TYPE_HTTP) + else if (type == I2P_TUNNELS_SECTION_TYPE_SERVER || type == I2P_TUNNELS_SECTION_TYPE_HTTP || type == I2P_TUNNELS_SECTION_TYPE_IRC) { // mandatory params std::string host = section.second.get (I2P_SERVER_TUNNEL_HOST); @@ -313,6 +313,7 @@ namespace client int inPort = section.second.get (I2P_SERVER_TUNNEL_INPORT, 0); std::string accessList = section.second.get (I2P_SERVER_TUNNEL_ACCESS_LIST, ""); std::string hostOverride = section.second.get (I2P_SERVER_TUNNEL_HOST_OVERRIDE, ""); + bool gzip = section.second.get (I2P_SERVER_TUNNEL_GZIP, true); i2p::data::SigningKeyType sigType = section.second.get (I2P_SERVER_TUNNEL_SIGNATURE_TYPE, i2p::data::SIGNING_KEY_TYPE_ECDSA_SHA256_P256); // I2CP std::map options; @@ -324,9 +325,15 @@ namespace client localDestination = FindLocalDestination (k.GetPublic ()->GetIdentHash ()); if (!localDestination) localDestination = CreateNewLocalDestination (k, true, &options); - I2PServerTunnel * serverTunnel = (type == I2P_TUNNELS_SECTION_TYPE_HTTP) ? - new I2PServerTunnelHTTP (name, host, port, localDestination, hostOverride, inPort) : - new I2PServerTunnel (name, host, port, localDestination, inPort); + + I2PServerTunnel * serverTunnel; + if (type == I2P_TUNNELS_SECTION_TYPE_HTTP) + serverTunnel = new I2PServerTunnelHTTP (name, host, port, localDestination, hostOverride, inPort, gzip); + else if (type == I2P_TUNNELS_SECTION_TYPE_IRC) + serverTunnel = new I2PServerTunnelIRC (name, host, port, localDestination, inPort, gzip); + else // regular server tunnel by default + serverTunnel = new I2PServerTunnel (name, host, port, localDestination, inPort, gzip); + if (accessList.length () > 0) { std::set idents; diff --git a/ClientContext.h b/ClientContext.h index 30e495da..8126a17a 100644 --- a/ClientContext.h +++ b/ClientContext.h @@ -21,6 +21,7 @@ namespace client const char I2P_TUNNELS_SECTION_TYPE_CLIENT[] = "client"; const char I2P_TUNNELS_SECTION_TYPE_SERVER[] = "server"; const char I2P_TUNNELS_SECTION_TYPE_HTTP[] = "http"; + const char I2P_TUNNELS_SECTION_TYPE_IRC[] = "irc"; const char I2P_CLIENT_TUNNEL_PORT[] = "port"; const char I2P_CLIENT_TUNNEL_ADDRESS[] = "address"; const char I2P_CLIENT_TUNNEL_DESTINATION[] = "destination"; @@ -34,6 +35,7 @@ namespace client const char I2P_SERVER_TUNNEL_SIGNATURE_TYPE[] = "signaturetype"; const char I2P_SERVER_TUNNEL_INPORT[] = "inport"; const char I2P_SERVER_TUNNEL_ACCESS_LIST[] = "accesslist"; + const char I2P_SERVER_TUNNEL_GZIP[] = "gzip"; class ClientContext { diff --git a/Destination.cpp b/Destination.cpp index eefd9700..c53c4ee6 100644 --- a/Destination.cpp +++ b/Destination.cpp @@ -576,9 +576,9 @@ namespace client return false; } - std::shared_ptr ClientDestination::CreateStreamingDestination (int port) + std::shared_ptr ClientDestination::CreateStreamingDestination (int port, bool gzip) { - auto dest = std::make_shared (shared_from_this (), port); + auto dest = std::make_shared (shared_from_this (), port, gzip); if (port) m_StreamingDestinationsByPorts[port] = dest; else // update default diff --git a/Destination.h b/Destination.h index 2da4c8e5..44cb7424 100644 --- a/Destination.h +++ b/Destination.h @@ -46,7 +46,7 @@ namespace client const int STREAM_REQUEST_TIMEOUT = 60; //in seconds const char I2CP_PARAM_TAGS_TO_SEND[] = "crypto.tagsToSend"; const int DEFAULT_TAGS_TO_SEND = 40; - + typedef std::function stream)> StreamRequestComplete; class ClientDestination: public i2p::garlic::GarlicDestination, @@ -82,7 +82,7 @@ namespace client void CancelDestinationRequest (const i2p::data::IdentHash& dest); // streaming - std::shared_ptr CreateStreamingDestination (int port); // additional + std::shared_ptr CreateStreamingDestination (int port, bool gzip = true); // additional std::shared_ptr GetStreamingDestination (int port = 0) const; // following methods operate with default streaming destination void CreateStream (StreamRequestComplete streamRequestComplete, const i2p::data::IdentHash& dest, int port = 0); diff --git a/I2PTunnel.cpp b/I2PTunnel.cpp index 4eb1c573..e2b75232 100644 --- a/I2PTunnel.cpp +++ b/I2PTunnel.cpp @@ -234,6 +234,45 @@ namespace client } } + I2PTunnelConnectionIRC::I2PTunnelConnectionIRC (I2PService * owner, std::shared_ptr stream, + std::shared_ptr socket, + const boost::asio::ip::tcp::endpoint& target, const std::string& host): + I2PTunnelConnection (owner, stream, socket, target), m_Host (host), m_From (stream->GetRemoteIdentity ()) + { + } + + void I2PTunnelConnectionIRC::Write (const uint8_t * buf, size_t len) + { + std::string line; + m_OutPacket.str (""); + m_InPacket.clear (); + m_InPacket.write ((const char *)buf, len); + + while (!m_InPacket.eof () && !m_InPacket.fail ()) + { + std::getline (m_InPacket, line); + if (line.length () == 0 && m_InPacket.eof ()) { + m_InPacket.str (""); + } + auto pos = line.find ("USER"); + if (pos != std::string::npos && pos == 0) + { + pos = line.find (" "); + pos++; + pos = line.find (" ", pos); + pos++; + auto nextpos = line.find (" ", pos); + m_OutPacket << line.substr (0, pos); + m_OutPacket << context.GetAddressBook ().ToAddress (m_From->GetIdentHash ()); + m_OutPacket << line.substr (nextpos) << '\n'; + } else { + m_OutPacket << line << '\n'; + } + } + I2PTunnelConnection::Write ((uint8_t *)m_OutPacket.str ().c_str (), m_OutPacket.str ().length ()); + } + + /* This handler tries to stablish a connection with the desired server and dies if it fails to do so */ class I2PClientTunnelHandler: public I2PServiceHandler, public std::enable_shared_from_this { @@ -332,10 +371,10 @@ namespace client } I2PServerTunnel::I2PServerTunnel (const std::string& name, const std::string& address, - int port, std::shared_ptr localDestination, int inport): + int port, std::shared_ptr localDestination, int inport, bool gzip): I2PService (localDestination), m_Name (name), m_Address (address), m_Port (port), m_IsAccessList (false) { - m_PortDestination = localDestination->CreateStreamingDestination (inport > 0 ? inport : port); + m_PortDestination = localDestination->CreateStreamingDestination (inport > 0 ? inport : port, gzip); } void I2PServerTunnel::Start () @@ -423,8 +462,8 @@ namespace client I2PServerTunnelHTTP::I2PServerTunnelHTTP (const std::string& name, const std::string& address, int port, std::shared_ptr localDestination, - const std::string& host, int inport): - I2PServerTunnel (name, address, port, localDestination, inport), + const std::string& host, int inport, bool gzip): + I2PServerTunnel (name, address, port, localDestination, inport, gzip), m_Host (host.length () > 0 ? host : address) { } @@ -436,5 +475,18 @@ namespace client AddHandler (conn); conn->Connect (); } + + I2PServerTunnelIRC::I2PServerTunnelIRC (const std::string& name, const std::string& address, + int port, std::shared_ptr localDestination, int inport, bool gzip): + I2PServerTunnel (name, address, port, localDestination, inport, gzip) + { + } + + void I2PServerTunnelIRC::CreateI2PConnection (std::shared_ptr stream) + { + auto conn = std::make_shared (this, stream, std::make_shared (GetService ()), GetEndpoint (), GetAddress ()); + AddHandler (conn); + conn->Connect (); + } } } diff --git a/I2PTunnel.h b/I2PTunnel.h index 834897f7..9b704033 100644 --- a/I2PTunnel.h +++ b/I2PTunnel.h @@ -80,6 +80,26 @@ namespace client std::shared_ptr m_From; }; + class I2PTunnelConnectionIRC: public I2PTunnelConnection + { + public: + + I2PTunnelConnectionIRC (I2PService * owner, std::shared_ptr stream, + std::shared_ptr socket, + const boost::asio::ip::tcp::endpoint& target, const std::string& host); + + protected: + + void Write (const uint8_t * buf, size_t len); + + private: + + std::string m_Host; + std::shared_ptr m_From; + std::stringstream m_OutPacket, m_InPacket; + }; + + class I2PClientTunnel: public TCPIPAcceptor { protected: @@ -114,7 +134,7 @@ namespace client public: I2PServerTunnel (const std::string& name, const std::string& address, int port, - std::shared_ptr localDestination, int inport = 0); + std::shared_ptr localDestination, int inport = 0, bool gzip = true); void Start (); void Stop (); @@ -153,7 +173,7 @@ namespace client I2PServerTunnelHTTP (const std::string& name, const std::string& address, int port, std::shared_ptr localDestination, const std::string& host, - int inport = 0); + int inport = 0, bool gzip = true); private: @@ -163,6 +183,19 @@ namespace client std::string m_Host; }; + + class I2PServerTunnelIRC: public I2PServerTunnel + { + public: + + I2PServerTunnelIRC (const std::string& name, const std::string& address, int port, + std::shared_ptr localDestination, int inport = 0, bool gzip = true); + + private: + + void CreateI2PConnection (std::shared_ptr stream); + }; + } } diff --git a/LeaseSet.h b/LeaseSet.h index 0afca269..f5685210 100644 --- a/LeaseSet.h +++ b/LeaseSet.h @@ -17,7 +17,7 @@ namespace tunnel namespace data { - const int LEASE_ENDDATE_THRESHOLD = 31000; // in milliseconds + const int LEASE_ENDDATE_THRESHOLD = 51000; // in milliseconds struct Lease { IdentHash tunnelGateway; diff --git a/Log.cpp b/Log.cpp index 6391bcae..6bba1b62 100644 --- a/Log.cpp +++ b/Log.cpp @@ -44,10 +44,12 @@ void Log::Flush () m_LogStream->flush(); } -void Log::SetLogFile (const std::string& fullFilePath) +void Log::SetLogFile (const std::string& fullFilePath, bool truncate) { m_FullFilePath = fullFilePath; - auto logFile = std::make_shared (fullFilePath, std::ofstream::out | std::ofstream::binary | std::ofstream::trunc); + auto mode = std::ofstream::out | std::ofstream::binary; + mode |= truncate ? std::ofstream::trunc : std::ofstream::app; + auto logFile = std::make_shared (fullFilePath, mode); if (logFile->is_open ()) { SetLogStream (logFile); @@ -59,7 +61,7 @@ void Log::ReopenLogFile () { if (m_FullFilePath.length () > 0) { - SetLogFile (m_FullFilePath); + SetLogFile (m_FullFilePath, false); // don't truncate LogPrint(eLogInfo, "Log: file ", m_FullFilePath, " reopen"); } } diff --git a/Log.h b/Log.h index 05bae7d9..5b07e2c9 100644 --- a/Log.h +++ b/Log.h @@ -38,7 +38,7 @@ class Log: public i2p::util::MsgQueue Log () { SetOnEmpty (std::bind (&Log::Flush, this)); }; ~Log () {}; - void SetLogFile (const std::string& fullFilePath); + void SetLogFile (const std::string& fullFilePath, bool truncate = true); void ReopenLogFile (); void SetLogLevel (const std::string& level); void SetLogStream (std::shared_ptr logStream); diff --git a/Streaming.cpp b/Streaming.cpp index 46644cb0..33be58b5 100644 --- a/Streaming.cpp +++ b/Streaming.cpp @@ -628,7 +628,7 @@ namespace stream std::vector msgs; for (auto it: packets) { - auto msg = m_RoutingSession->WrapSingleMessage (CreateDataMessage (it->GetBuffer (), it->GetLength ())); + auto msg = m_RoutingSession->WrapSingleMessage (m_LocalDestination.CreateDataMessage (it->GetBuffer (), it->GetLength (), m_Port)); msgs.push_back (i2p::tunnel::TunnelMessageBlock { i2p::tunnel::eDeliveryTypeTunnel, @@ -779,33 +779,9 @@ namespace stream m_CurrentRemoteLease = nullptr; } - std::shared_ptr Stream::CreateDataMessage (const uint8_t * payload, size_t len) - { - auto msg = NewI2NPShortMessage (); - if (len <= i2p::stream::COMPRESSION_THRESHOLD_SIZE) - m_LocalDestination.m_Deflator.SetCompressionLevel (Z_NO_COMPRESSION); - else - m_LocalDestination.m_Deflator.SetCompressionLevel (Z_DEFAULT_COMPRESSION); - uint8_t * buf = msg->GetPayload (); - buf += 4; // reserve for lengthlength - msg->len += 4; - size_t size = m_LocalDestination.m_Deflator.Deflate (payload, len, buf, msg->maxLen - msg->len); - if (size) - { - htobe32buf (msg->GetPayload (), size); // length - htobe16buf (buf + 4, m_LocalDestination.GetLocalPort ()); // source port - htobe16buf (buf + 6, m_Port); // destination port - buf[9] = i2p::client::PROTOCOL_TYPE_STREAMING; // streaming protocol - msg->len += size; - msg->FillI2NPMessageHeader (eI2NPData); - } - else - msg = nullptr; - return msg; - } - - StreamingDestination::StreamingDestination (std::shared_ptr owner, uint16_t localPort): - m_Owner (owner), m_LocalPort (localPort), m_PendingIncomingTimer (m_Owner->GetService ()) + StreamingDestination::StreamingDestination (std::shared_ptr owner, uint16_t localPort, bool gzip): + m_Owner (owner), m_LocalPort (localPort), m_Gzip (gzip), + m_PendingIncomingTimer (m_Owner->GetService ()) { } @@ -993,5 +969,30 @@ namespace stream else delete uncompressed; } + + std::shared_ptr StreamingDestination::CreateDataMessage (const uint8_t * payload, size_t len, uint16_t toPort) + { + auto msg = NewI2NPShortMessage (); + if (!m_Gzip || len <= i2p::stream::COMPRESSION_THRESHOLD_SIZE) + m_Deflator.SetCompressionLevel (Z_NO_COMPRESSION); + else + m_Deflator.SetCompressionLevel (Z_DEFAULT_COMPRESSION); + uint8_t * buf = msg->GetPayload (); + buf += 4; // reserve for lengthlength + msg->len += 4; + size_t size = m_Deflator.Deflate (payload, len, buf, msg->maxLen - msg->len); + if (size) + { + htobe32buf (msg->GetPayload (), size); // length + htobe16buf (buf + 4, m_LocalPort); // source port + htobe16buf (buf + 6, toPort); // destination port + buf[9] = i2p::client::PROTOCOL_TYPE_STREAMING; // streaming protocol + msg->len += size; + msg->FillI2NPMessageHeader (eI2NPData); + } + else + msg = nullptr; + return msg; + } } } diff --git a/Streaming.h b/Streaming.h index c908c6ec..c29b62f9 100644 --- a/Streaming.h +++ b/Streaming.h @@ -158,8 +158,6 @@ namespace stream void ScheduleResend (); void HandleResendTimer (const boost::system::error_code& ecode); void HandleAckSendTimer (const boost::system::error_code& ecode); - - std::shared_ptr CreateDataMessage (const uint8_t * payload, size_t len); private: @@ -195,7 +193,7 @@ namespace stream typedef std::function)> Acceptor; - StreamingDestination (std::shared_ptr owner, uint16_t localPort = 0); + StreamingDestination (std::shared_ptr owner, uint16_t localPort = 0, bool gzip = true); ~StreamingDestination (); void Start (); @@ -210,6 +208,7 @@ namespace stream uint16_t GetLocalPort () const { return m_LocalPort; }; void HandleDataMessagePayload (const uint8_t * buf, size_t len); + std::shared_ptr CreateDataMessage (const uint8_t * payload, size_t len, uint16_t toPort); private: @@ -221,6 +220,7 @@ namespace stream std::shared_ptr m_Owner; uint16_t m_LocalPort; + bool m_Gzip; // gzip compression of data messages std::mutex m_StreamsMutex; std::map > m_Streams; // sendStreamID->stream Acceptor m_Acceptor; diff --git a/contrib/certificates/reseed/zmx_at_mail.i2p.crt b/contrib/certificates/reseed/zmx_at_mail.i2p.crt new file mode 100644 index 00000000..41f4cc75 --- /dev/null +++ b/contrib/certificates/reseed/zmx_at_mail.i2p.crt @@ -0,0 +1,34 @@ +-----BEGIN CERTIFICATE----- +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 +fNr8P7NIRyZ8 +-----END CERTIFICATE-----