diff --git a/ClientContext.cpp b/ClientContext.cpp index 31f5e640..939a9e43 100644 --- a/ClientContext.cpp +++ b/ClientContext.cpp @@ -493,7 +493,8 @@ namespace client i2p::data::SigningKeyType sigType = section.second.get (I2P_SERVER_TUNNEL_SIGNATURE_TYPE, i2p::data::SIGNING_KEY_TYPE_ECDSA_SHA256_P256); uint32_t maxConns = section.second.get(i2p::stream::I2CP_PARAM_STREAMING_MAX_CONNS_PER_MIN, i2p::stream::DEFAULT_MAX_CONNS_PER_MIN); std::string address = section.second.get (I2P_SERVER_TUNNEL_ADDRESS, "127.0.0.1"); - + bool mapToLoopback = section.second.get(I2P_SERVER_TUNNEL_MAPTOLOOPBACK, true); + // I2CP std::map options; ReadI2CPOptions (section, options); @@ -512,6 +513,10 @@ namespace client auto localAddress = boost::asio::ip::address::from_string(address); boost::asio::ip::udp::endpoint endpoint(boost::asio::ip::address::from_string(host), port); I2PUDPServerTunnel * serverTunnel = new I2PUDPServerTunnel(name, localDestination, localAddress, endpoint, port); + if(!mapToLoopback) { + LogPrint(eLogInfo, "Clients: disabling loopback address mapping"); + } + serverTunnel->SetMapToLoopback(mapToLoopback); std::lock_guard lock(m_ForwardsMutex); if(m_ServerForwards.insert( std::make_pair( @@ -538,7 +543,9 @@ namespace client LogPrint(eLogInfo, "Clients: Set Max Conns To ", maxConns); serverTunnel->SetMaxConnsPerMinute(maxConns); - + if(!mapToLoopback) + LogPrint(eLogInfo, "Clients: disabling loopback address mapping"); + serverTunnel->SetMapToLoopback(mapToLoopback); if (accessList.length () > 0) { diff --git a/ClientContext.h b/ClientContext.h index db74a19e..e013671f 100644 --- a/ClientContext.h +++ b/ClientContext.h @@ -42,7 +42,8 @@ namespace client const char I2P_SERVER_TUNNEL_GZIP[] = "gzip"; const char I2P_SERVER_TUNNEL_WEBIRC_PASSWORD[] = "webircpassword"; const char I2P_SERVER_TUNNEL_ADDRESS[] = "address"; - + const char I2P_SERVER_TUNNEL_MAPTOLOOPBACK[] = "maploopback"; + class ClientContext { public: diff --git a/I2PTunnel.cpp b/I2PTunnel.cpp index 57006621..5a8d6160 100644 --- a/I2PTunnel.cpp +++ b/I2PTunnel.cpp @@ -58,25 +58,39 @@ namespace client StreamReceive (); Receive (); } - - void I2PTunnelConnection::Connect () + + static boost::asio::ip::address GetLoopbackAddressFor(const i2p::data::IdentHash & addr) + { + boost::asio::ip::address_v4::bytes_type bytes; + const uint8_t * ident = addr; + bytes[0] = 127; + memcpy (bytes.data ()+1, ident, 3); + boost::asio::ip::address ourIP = boost::asio::ip::address_v4 (bytes); + return ourIP; + } + + static void MapToLoopback(const std::shared_ptr & sock, const i2p::data::IdentHash & addr) + { + + // bind to 127.x.x.x address + // where x.x.x are first three bytes from ident + auto ourIP = GetLoopbackAddressFor(addr); + sock->bind (boost::asio::ip::tcp::endpoint (ourIP, 0)); + + } + + void I2PTunnelConnection::Connect (bool mapToLoopback) { I2PTunnelSetSocketOptions(m_Socket); if (m_Socket) { -#ifdef __linux__ - // bind to 127.x.x.x address - // where x.x.x are first three bytes from ident +#ifdef __linux__ if (m_RemoteEndpoint.address ().is_v4 () && - m_RemoteEndpoint.address ().to_v4 ().to_bytes ()[0] == 127) + m_RemoteEndpoint.address ().to_v4 ().to_bytes ()[0] == 127 && mapToLoopback) { m_Socket->open (boost::asio::ip::tcp::v4 ()); - boost::asio::ip::address_v4::bytes_type bytes; - const uint8_t * ident = m_Stream->GetRemoteIdentity ()->GetIdentHash (); - bytes[0] = 127; - memcpy (bytes.data ()+1, ident, 3); - boost::asio::ip::address ourIP = boost::asio::ip::address_v4 (bytes); - m_Socket->bind (boost::asio::ip::tcp::endpoint (ourIP, 0)); + auto ident = m_Stream->GetRemoteIdentity()->GetIdentHash(); + MapToLoopback(m_Socket, ident); } #endif m_Socket->async_connect (m_RemoteEndpoint, std::bind (&I2PTunnelConnection::HandleConnect, @@ -417,7 +431,7 @@ namespace client I2PServerTunnel::I2PServerTunnel (const std::string& name, const std::string& address, int port, std::shared_ptr localDestination, int inport, bool gzip): - I2PService (localDestination), m_Name (name), m_Address (address), m_Port (port), m_IsAccessList (false) + I2PService (localDestination), m_MapToLoopback(true), m_Name (name), m_Address (address), m_Port (port), m_IsAccessList (false) { m_PortDestination = localDestination->CreateStreamingDestination (inport > 0 ? inport : port, gzip); } @@ -502,7 +516,7 @@ namespace client { auto conn = std::make_shared (this, stream, std::make_shared (GetService ()), GetEndpoint ()); AddHandler (conn); - conn->Connect (); + conn->Connect (m_MapToLoopback); } I2PServerTunnelHTTP::I2PServerTunnelHTTP (const std::string& name, const std::string& address, @@ -581,8 +595,15 @@ namespace client return s; } } - /** create new udp session */ - boost::asio::ip::udp::endpoint ep(m_LocalAddress, 0); + boost::asio::ip::address addr; + /** create new udp session */ + if(m_LocalAddress.is_loopback() && m_MapToLoopback) { + auto ident = from.GetIdentHash(); + addr = GetLoopbackAddressFor(ident); + } else { + addr = m_LocalAddress; + } + boost::asio::ip::udp::endpoint ep(addr, 0); m_Sessions.push_back(std::make_shared(ep, m_LocalDest, m_RemoteEndpoint, &ih, localPort, remotePort)); auto & back = m_Sessions.back(); return back; @@ -627,6 +648,7 @@ namespace client I2PUDPServerTunnel::I2PUDPServerTunnel(const std::string & name, std::shared_ptr localDestination, boost::asio::ip::address localAddress, boost::asio::ip::udp::endpoint forwardTo, uint16_t port) : + m_MapToLoopback(true), m_Name(name), m_LocalAddress(localAddress), m_RemoteEndpoint(forwardTo) @@ -768,8 +790,6 @@ namespace client // found convo if (len > 0) { LogPrint(eLogDebug, "UDP Client: got ", len, "B from ", from.GetIdentHash().ToBase32()); - uint8_t sendbuf[len]; - memcpy(sendbuf, buf, len); m_LocalSocket.send_to(boost::asio::buffer(buf, len), itr->second.first); // mark convo as active itr->second.second = i2p::util::GetMillisecondsSinceEpoch(); diff --git a/I2PTunnel.h b/I2PTunnel.h index bde3d820..2b895508 100644 --- a/I2PTunnel.h +++ b/I2PTunnel.h @@ -38,7 +38,7 @@ namespace client const boost::asio::ip::tcp::endpoint& target, bool quiet = true); // from I2P ~I2PTunnelConnection (); void I2PConnect (const uint8_t * msg = nullptr, size_t len = 0); - void Connect (); + void Connect (bool mapToLoopback = true); protected: @@ -201,12 +201,15 @@ namespace client std::vector > GetSessions(); std::shared_ptr GetLocalDestination () const { return m_LocalDest; } + void SetMapToLoopback(bool mapToLoopback = true) { m_MapToLoopback = mapToLoopback; } + private: void HandleRecvFromI2P(const i2p::data::IdentityEx& from, uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len); UDPSessionPtr ObtainUDPSession(const i2p::data::IdentityEx& from, uint16_t localPort, uint16_t remotePort); private: + bool m_MapToLoopback; const std::string m_Name; boost::asio::ip::address m_LocalAddress; boost::asio::ip::udp::endpoint m_RemoteEndpoint; @@ -264,6 +267,8 @@ namespace client void SetAccessList (const std::set& accessList); + void SetMapToLoopback(bool mapToLoopback) { m_MapToLoopback = mapToLoopback; } + const std::string& GetAddress() const { return m_Address; } int GetPort () const { return m_Port; }; uint16_t GetLocalPort () const { return m_PortDestination->GetLocalPort (); }; @@ -283,7 +288,7 @@ namespace client virtual void CreateI2PConnection (std::shared_ptr stream); private: - + bool m_MapToLoopback; std::string m_Name, m_Address; int m_Port; boost::asio::ip::tcp::endpoint m_Endpoint;