diff --git a/libi2pd/SSU2.cpp b/libi2pd/SSU2.cpp index 0c71b14e..51ff9bd3 100644 --- a/libi2pd/SSU2.cpp +++ b/libi2pd/SSU2.cpp @@ -24,7 +24,7 @@ namespace transport m_AddressV4 (boost::asio::ip::address_v4()), m_AddressV6 (boost::asio::ip::address_v6()), m_TerminationTimer (GetService ()), m_ResendTimer (GetService ()), m_IntroducersUpdateTimer (GetService ()), m_IntroducersUpdateTimerV6 (GetService ()), - m_IsPublished (true), m_IsSyncClockFromPeers (true) + m_IsPublished (true), m_IsSyncClockFromPeers (true), m_IsThroughProxy (false) { } @@ -112,6 +112,12 @@ namespace transport m_SocketV4.close (); m_SocketV6.close (); + if (m_UDPAssociateSocket) + { + m_UDPAssociateSocket->close (); + m_UDPAssociateSocket.reset (nullptr); + } + StopIOService (); m_Sessions.clear (); @@ -1033,5 +1039,39 @@ namespace transport } } } + + void SSU2Server::SendThroughProxy (const uint8_t * header, size_t headerLen, const uint8_t * headerX, size_t headerXLen, + const uint8_t * payload, size_t payloadLen, const boost::asio::ip::udp::endpoint& to) + { + if (!m_ProxyRelayEndpoint) return; + size_t requestHeaderSize = 0; + memset (m_UDPRequestHeader, 0, 3); + if (to.address ().is_v6 ()) + { + m_UDPRequestHeader[3] = SOCKS5_ATYP_IPV6; + memcpy (m_UDPRequestHeader + 4, to.address ().to_v6().to_bytes().data(), 16); + requestHeaderSize = SOCKS5_UDP_IPV6_REQUEST_HEADER_SIZE; + } + else + { + m_UDPRequestHeader[3] = SOCKS5_ATYP_IPV4; + memcpy (m_UDPRequestHeader + 4, to.address ().to_v4().to_bytes().data(), 4); + requestHeaderSize = SOCKS5_UDP_IPV4_REQUEST_HEADER_SIZE; + } + htobe16buf (m_UDPRequestHeader + requestHeaderSize - 2, to.port ()); + + std::vector bufs; + bufs.push_back (boost::asio::buffer (m_UDPRequestHeader, requestHeaderSize)); + bufs.push_back (boost::asio::buffer (header, headerLen)); + if (headerX) bufs.push_back (boost::asio::buffer (headerX, headerXLen)); + bufs.push_back (boost::asio::buffer (payload, payloadLen)); + + boost::system::error_code ec; + m_SocketV4.send_to (bufs, *m_ProxyRelayEndpoint, 0, ec); // TODO: implement ipv6 proxy + if (!ec) + i2p::transport::transports.UpdateSentBytes (headerLen + payloadLen); + else + LogPrint (eLogError, "SSU2: Send exception: ", ec.message (), " to ", to); + } } } diff --git a/libi2pd/SSU2.h b/libi2pd/SSU2.h index 773eb669..ceee890e 100644 --- a/libi2pd/SSU2.h +++ b/libi2pd/SSU2.h @@ -118,6 +118,9 @@ namespace transport void HandleIntroducersUpdateTimer (const boost::system::error_code& ecode, bool v4); void ScheduleIntroducersUpdateTimerV6 (); + void SendThroughProxy (const uint8_t * header, size_t headerLen, const uint8_t * headerX, size_t headerXLen, + const uint8_t * payload, size_t payloadLen, const boost::asio::ip::udp::endpoint& to); + private: ReceiveService m_ReceiveService; @@ -137,6 +140,13 @@ namespace transport bool m_IsPublished; // if we maintain introducers bool m_IsSyncClockFromPeers; + // proxy + bool m_IsThroughProxy; + uint8_t m_UDPRequestHeader[SOCKS5_UDP_IPV6_REQUEST_HEADER_SIZE]; + std::unique_ptr m_ProxyEndpoint; + std::unique_ptr m_UDPAssociateSocket; + std::unique_ptr m_ProxyRelayEndpoint; + public: // for HTTP/I2PControl diff --git a/libi2pd/TransportSession.h b/libi2pd/TransportSession.h index a939d540..3ad146cb 100644 --- a/libi2pd/TransportSession.h +++ b/libi2pd/TransportSession.h @@ -131,6 +131,8 @@ namespace transport const uint8_t SOCKS5_CMD_UDP_ASSOCIATE = 0x03; const uint8_t SOCKS5_ATYP_IPV4 = 0x01; const uint8_t SOCKS5_ATYP_IPV6 = 0x04; + const size_t SOCKS5_UDP_IPV4_REQUEST_HEADER_SIZE = 10; + const size_t SOCKS5_UDP_IPV6_REQUEST_HEADER_SIZE = 22; } }