diff --git a/libi2pd_client/I2PTunnel.cpp b/libi2pd_client/I2PTunnel.cpp index f546ad81..8f54b0e1 100644 --- a/libi2pd_client/I2PTunnel.cpp +++ b/libi2pd_client/I2PTunnel.cpp @@ -40,9 +40,12 @@ namespace client I2PTunnelConnection::I2PTunnelConnection (I2PService * owner, std::shared_ptr socket, std::shared_ptr stream): - I2PServiceHandler(owner), m_Socket (socket), m_Stream (stream), - m_RemoteEndpoint (socket->remote_endpoint ()), m_IsReceiving (false) + I2PServiceHandler(owner), m_Socket (socket), m_Stream (stream), m_IsReceiving (false) { + boost::system::error_code ec; + m_RemoteEndpoint = socket->remote_endpoint(ec); + if (ec) + LogPrint (eLogInfo, "I2PTunnel: Connection socket error ", ec.message ()); } I2PTunnelConnection::I2PTunnelConnection (I2PService * owner, std::shared_ptr stream, @@ -60,15 +63,17 @@ namespace client void I2PTunnelConnection::I2PConnect (const uint8_t * msg, size_t len) { - if (m_Stream) + if (m_Stream && m_Socket && m_Socket->is_open ()) { if (msg) m_Stream->Send (msg, len); // connect and send else m_Stream->Send (m_Buffer, 0); // connect + StreamReceive (); + Receive (); } - StreamReceive (); - Receive (); + else + Terminate (); } boost::asio::ip::address GetLoopbackAddressFor(const i2p::data::IdentHash & addr) @@ -158,12 +163,14 @@ namespace client if (m_Stream) { m_Stream->Close (); - m_Stream.reset (); + m_Stream = nullptr; + } + if (m_Socket && m_Socket->is_open ()) + { + boost::system::error_code ec; + m_Socket->shutdown(boost::asio::ip::tcp::socket::shutdown_send, ec); // avoid RST + m_Socket->close (); } - boost::system::error_code ec; - m_Socket->shutdown(boost::asio::ip::tcp::socket::shutdown_send, ec); // avoid RST - m_Socket->close (); - Done(shared_from_this ()); } diff --git a/libi2pd_client/SOCKS.cpp b/libi2pd_client/SOCKS.cpp index 20db444e..161ae635 100644 --- a/libi2pd_client/SOCKS.cpp +++ b/libi2pd_client/SOCKS.cpp @@ -1,5 +1,5 @@ /* -* Copyright (c) 2013-2025, The PurpleI2P Project +* Copyright (c) 2013-2026, The PurpleI2P Project * * This file is part of Purple i2pd project and licensed under BSD3 * @@ -155,7 +155,7 @@ namespace proxy std::shared_ptr m_sock, m_upstreamSock; #if defined(BOOST_ASIO_HAS_LOCAL_SOCKETS) std::shared_ptr m_upstreamLocalSock; -#endif +#endif std::shared_ptr m_stream; uint8_t *m_remaining_data; //Data left to be sent uint8_t *m_remaining_upstream_data; //upstream data left to be forwarded @@ -189,7 +189,7 @@ namespace proxy { m_address.ip = 0; EnterState(GET_SOCKSV); } ~SOCKSHandler() { Terminate(); } - void Handle() { AsyncSockRead(); } + void Handle() override { AsyncSockRead(); } }; void SOCKSHandler::AsyncSockRead() @@ -226,18 +226,19 @@ namespace proxy m_upstreamLocalSock->close(); m_upstreamLocalSock = nullptr; } -#endif +#endif if (m_stream) { LogPrint(eLogDebug, "SOCKS: Closing stream"); - m_stream.reset (); + m_stream->AsyncClose (); + m_stream = nullptr; } if (m_UDPTunnel) { m_UDPTunnel->Stop (); GetServer ()->ReleaseLocalUDPPort (m_UDPTunnel->GetLocalEndpoint ().port ()); m_UDPTunnel = nullptr; - } + } Done(shared_from_this()); } @@ -315,10 +316,10 @@ namespace proxy m_response[0] = 1; // Version of the subnegotiation m_response[1] = 0; // Response code LogPrint(eLogDebug, "SOCKS: v5 user/password response"); - boost::asio::async_write(*m_sock, boost::asio::const_buffer(m_response, 2), + boost::asio::async_write(*m_sock, boost::asio::const_buffer(m_response, 2), std::bind(&SOCKSHandler::SentSocksResponse, shared_from_this(), std::placeholders::_1)); - } - + } + /* All hope is lost beyond this point */ void SOCKSHandler::SocksRequestFailed(SOCKSHandler::errTypes error) { @@ -358,14 +359,14 @@ namespace proxy // TODO: implement ipv6 ad.ip = m_UDPTunnel->GetLocalEndpoint ().address ().to_v4 ().to_uint (); response = GenerateSOCKS5Response(SOCKS5_OK, ADDR_IPV4, ad, m_UDPTunnel->GetLocalEndpoint ().port ()); - } + } else - { + { auto s = i2p::client::context.GetAddressBook().ToAddress(GetOwner()->GetLocalDestination()->GetIdentHash()); address ad; ad.dns.FromString(s); // HACK only 16 bits passed in port as SOCKS5 doesn't allow for more response = GenerateSOCKS5Response(SOCKS5_OK, ADDR_DNS, ad, m_stream ? m_stream->GetRecvStreamID() : 0); - } + } break; } boost::asio::async_write(*m_sock, response, std::bind(&SOCKSHandler::SentSocksDone, shared_from_this(), std::placeholders::_1)); @@ -450,7 +451,7 @@ namespace proxy if (!Socks5ChooseAuth()) return false; if (m_authchosen == AUTH_USERPASSWD) EnterState(GET5_USERPASSWD); - else + else EnterState(GET5_REQUESTV); } break; @@ -572,14 +573,14 @@ namespace proxy SocksRequestFailed(SOCKS5_GEN_FAIL); return false; } - EnterState(GET5_USER_SIZE); - break; + EnterState(GET5_USER_SIZE); + break; case GET5_USER_SIZE: if (*sock_buff) EnterState(GET5_USER, *sock_buff); else // empty user EnterState(GET5_PASSWD_SIZE); - break; + break; case GET5_USER: // skip user for now m_parseleft--; @@ -592,17 +593,17 @@ namespace proxy { Socks5UserPasswdResponse (); EnterState(GET5_REQUESTV); - } + } break; case GET5_PASSWD: // skip passwd for now m_parseleft--; - if (m_parseleft == 0) + if (m_parseleft == 0) { Socks5UserPasswdResponse (); EnterState(GET5_REQUESTV); - } - break; + } + break; default: LogPrint(eLogError, "SOCKS: Parse state?? ", m_state); Terminate(); @@ -638,7 +639,7 @@ namespace proxy LogPrint(eLogInfo, "SOCKS: Requested ", addr, ":" , m_port); const size_t addrlen = addr.size(); // does it end with .i2p? - if (addr.rfind(".i2p") == addrlen - 4) + if (addr.rfind(".i2p") == addrlen - 4) { // yes it does switch (m_cmd) @@ -647,21 +648,21 @@ namespace proxy //make an i2p session GetOwner()->CreateStream ( std::bind (&SOCKSHandler::HandleStreamRequestComplete, shared_from_this(), std::placeholders::_1), m_address.dns.ToString(), m_port); - break; + break; case CMD_UDP: // create UDP client tunnel - LogPrint (eLogInfo, "SOCKS: New UDP associate connection"); + LogPrint (eLogInfo, "SOCKS: New UDP associate connection"); m_UDPTunnel = std::make_unique("", addr, GetServer ()->GetNextLocalUDPEndpoint (), GetOwner ()->GetLocalDestination (), m_port, false, i2p::datagram::eDatagramV3); boost::asio::post (GetOwner ()->GetService (), [this](void) { SocksRequestSuccess(); - }); + }); break; default: ; - } - } + } + } else if (m_UseUpstreamProxy) // forward it to upstream proxy ForwardSOCKS(); @@ -686,20 +687,25 @@ namespace proxy if (!ecode) { if (m_cmd == CMD_CONNECT) - { + { if (Kill()) return; - LogPrint (eLogInfo, "SOCKS: New I2PTunnel connection"); - auto connection = std::make_shared(GetOwner(), m_sock, m_stream); - GetOwner()->AddHandler (connection); - connection->I2PConnect (m_remaining_data,m_remaining_data_len); - Done(shared_from_this()); + if (m_sock && m_sock->is_open ()) + { + LogPrint (eLogInfo, "SOCKS: New I2PTunnel connection"); + auto connection = std::make_shared(GetOwner(), m_sock, m_stream); + GetOwner()->AddHandler (connection); + connection->I2PConnect (m_remaining_data,m_remaining_data_len); + Done(shared_from_this()); + } + else + Terminate (); } else if (m_cmd == CMD_UDP && m_UDPTunnel) { LogPrint (eLogInfo, "SOCKS: Start UDP tunnel"); m_UDPTunnel->Start (); AsyncSockRead (); // associate socket - } + } } else { @@ -721,8 +727,13 @@ namespace proxy { if (stream) { - m_stream = stream; - SocksRequestSuccess(); + if (m_sock && m_sock->is_open ()) + { + m_stream = stream; + SocksRequestSuccess(); + } + else + stream->AsyncClose (); } else { @@ -735,21 +746,21 @@ namespace proxy { LogPrint(eLogInfo, "SOCKS: Forwarding to upstream"); if (m_UpstreamProxyPort) // TCP - { + { EnterState(UPSTREAM_RESOLVE); - m_proxy_resolver.async_resolve(m_UpstreamProxyAddress, std::to_string(m_UpstreamProxyPort), + m_proxy_resolver.async_resolve(m_UpstreamProxyAddress, std::to_string(m_UpstreamProxyPort), std::bind(&SOCKSHandler::HandleUpstreamResolved, shared_from_this(), std::placeholders::_1, std::placeholders::_2)); - } + } else if (!m_UpstreamProxyAddress.empty ())// local { -#if defined(BOOST_ASIO_HAS_LOCAL_SOCKETS) +#if defined(BOOST_ASIO_HAS_LOCAL_SOCKETS) EnterState(UPSTREAM_CONNECT); m_upstreamLocalSock = std::make_shared(GetOwner()->GetService()); auto s = shared_from_this (); m_upstreamLocalSock->async_connect(m_UpstreamProxyAddress, [s](const boost::system::error_code& ecode) { - if (ecode) + if (ecode) { LogPrint(eLogWarning, "SOCKS: Could not connect to local upstream proxy: ", ecode.message()); s->SocksRequestFailed(SOCKS5_NET_UNREACH); @@ -767,7 +778,7 @@ namespace proxy { LogPrint(eLogError, "SOCKS: Incorrect upstream proxy address"); SocksRequestFailed(SOCKS5_ADDR_UNSUP); - } + } } template @@ -801,26 +812,26 @@ namespace proxy { LogPrint(eLogInfo, "SOCKS: Negotiating with upstream proxy"); EnterState(UPSTREAM_HANDSHAKE); - if (upstreamSock) + if (upstreamSock) { auto s = shared_from_this (); i2p::transport::Socks5Handshake (*upstreamSock, std::make_pair(m_address.dns.ToString (), m_port), [s, &upstreamSock](const boost::system::error_code& ec) { - if (!ec) + if (!ec) s->SocksUpstreamSuccess(upstreamSock); else - { + { s->SocksRequestFailed(SOCKS5_NET_UNREACH); LogPrint(eLogError, "SOCKS: Upstream proxy failure: ", ec.message ()); } - }); - } - else + }); + } + else LogPrint(eLogError, "SOCKS: No upstream socket to send handshake to"); } - void SOCKSHandler::HandleUpstreamConnected(const boost::system::error_code & ecode, + void SOCKSHandler::HandleUpstreamConnected(const boost::system::error_code & ecode, const boost::asio::ip::tcp::endpoint& ep) { if (ecode) { @@ -832,7 +843,7 @@ namespace proxy SendUpstreamRequest(m_upstreamSock); } - void SOCKSHandler::HandleUpstreamResolved(const boost::system::error_code & ecode, + void SOCKSHandler::HandleUpstreamResolved(const boost::system::error_code & ecode, boost::asio::ip::tcp::resolver::results_type endpoints) { if (ecode) { @@ -878,18 +889,18 @@ namespace proxy uint16_t port = localEndpoint.port (); #if __cplusplus >= 202002L // C++20 while (m_UDPPorts.contains (port)) -#else +#else while (m_UDPPorts.count (port) > 0) -#endif +#endif port++; m_UDPPorts.insert (port); - + return boost::asio::ip::udp::endpoint (localEndpoint.address (), port); // use proxy address - } + } void SOCKSServer::ReleaseLocalUDPPort (uint16_t port) { m_UDPPorts.erase (port); - } + } } } diff --git a/libi2pd_client/SOCKS.h b/libi2pd_client/SOCKS.h index ee16b1ad..2f5b9231 100644 --- a/libi2pd_client/SOCKS.h +++ b/libi2pd_client/SOCKS.h @@ -1,5 +1,5 @@ /* -* Copyright (c) 2013-2025, The PurpleI2P Project +* Copyright (c) 2013-2026, The PurpleI2P Project * * This file is part of Purple i2pd project and licensed under BSD3 * @@ -30,11 +30,11 @@ namespace proxy void SetUpstreamProxy(const std::string & addr, const uint16_t port); boost::asio::ip::udp::endpoint GetNextLocalUDPEndpoint (); void ReleaseLocalUDPPort (uint16_t port); - + protected: // Implements TCPIPAcceptor - std::shared_ptr CreateHandler(std::shared_ptr socket); + std::shared_ptr CreateHandler(std::shared_ptr socket) override; const char* GetName() { return m_Name.c_str (); } private: