From c21dd678b0935fe1aed853f5d11e41d1592a2d69 Mon Sep 17 00:00:00 2001 From: PobreGato <315121269+pobregat0@users.noreply.github.com> Date: Thu, 13 Aug 2026 01:42:05 +0300 Subject: [PATCH] protect http and socks proxy pointers with mutex --- libi2pd_client/ClientContext.cpp | 72 ++++++++++++++++++++------------ libi2pd_client/ClientContext.h | 16 ++++++- 2 files changed, 60 insertions(+), 28 deletions(-) diff --git a/libi2pd_client/ClientContext.cpp b/libi2pd_client/ClientContext.cpp index 8748f694..25b25291 100644 --- a/libi2pd_client/ClientContext.cpp +++ b/libi2pd_client/ClientContext.cpp @@ -125,20 +125,36 @@ namespace client } } + std::shared_ptr ClientContext::DetachHttpProxy () + { + std::lock_guard l(m_ProxyMutex); + auto proxy = m_HttpProxy; + m_HttpProxy = nullptr; + return proxy; + } + + std::shared_ptr ClientContext::DetachSocksProxy () + { + std::lock_guard l(m_ProxyMutex); + auto proxy = m_SocksProxy; + m_SocksProxy = nullptr; + return proxy; + } + void ClientContext::Stop () { - if (m_HttpProxy) + auto httpProxy = DetachHttpProxy (); + if (httpProxy) { LogPrint(eLogInfo, "Clients: Stopping HTTP Proxy"); - m_HttpProxy->Stop(); - m_HttpProxy = nullptr; + httpProxy->Stop(); } - if (m_SocksProxy) + auto socksProxy = DetachSocksProxy (); + if (socksProxy) { LogPrint(eLogInfo, "Clients: Stopping SOCKS Proxy"); - m_SocksProxy->Stop(); - m_SocksProxy = nullptr; + socksProxy->Stop(); } for (auto& it: m_ClientTunnels) @@ -228,19 +244,13 @@ namespace client CreateNewSharedLocalDestination (); // recreate HTTP proxy - if (m_HttpProxy) - { - m_HttpProxy->Stop (); - m_HttpProxy = nullptr; - } + auto httpProxy = DetachHttpProxy (); + if (httpProxy) httpProxy->Stop (); ReadHttpProxy (); // recreate SOCKS proxy - if (m_SocksProxy) - { - m_SocksProxy->Stop (); - m_SocksProxy = nullptr; - } + auto socksProxy = DetachSocksProxy (); + if (socksProxy) socksProxy->Stop (); ReadSocksProxy (); // handle tunnels @@ -1051,16 +1061,19 @@ namespace client } try { - m_HttpProxy = std::make_shared("HTTP Proxy", httpProxyAddr, httpProxyPort, + // publish only after it is started, so readers never see a half-built proxy + auto proxy = std::make_shared("HTTP Proxy", httpProxyAddr, httpProxyPort, httpOutProxyURL, httpAddresshelper, httpSendUserAgent, localDestination); uint64_t closeIdleTime; i2p::config::GetOption("httpproxy.i2cp.closeIdleTime", closeIdleTime); if (closeIdleTime) { - m_HttpProxy->SetCloseIdleTime(closeIdleTime); + proxy->SetCloseIdleTime(closeIdleTime); bool newDestOnResume; i2p::config::GetOption("httpproxy.i2cp.newDestOnResume", newDestOnResume); - m_HttpProxy->SetNewDestOnResume(newDestOnResume); + proxy->SetNewDestOnResume(newDestOnResume); } - m_HttpProxy->Start(); + proxy->Start(); + std::lock_guard l(m_ProxyMutex); + m_HttpProxy = proxy; } catch (std::exception& e) { @@ -1087,10 +1100,15 @@ namespace client i2p::data::SigningKeyType sigType; i2p::config::GetOption("socksproxy.signaturetype", sigType); if (sigType > i2p::data::SIGNING_KEY_TYPE_REDDSA_SHA512_ED25519) sigType = i2p::data::SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519; LogPrint(eLogInfo, "Clients: Starting SOCKS Proxy at ", socksProxyAddr, ":", socksProxyPort); + std::shared_ptr httpProxy; + { + std::lock_guard l(m_ProxyMutex); + httpProxy = m_HttpProxy; + } if (socksProxyKeys == "shareddest") localDestination = m_SharedLocalDestination; - else if (httpProxyKeys == socksProxyKeys && m_HttpProxy) - localDestination = m_HttpProxy->GetLocalDestination (); + else if (httpProxyKeys == socksProxyKeys && httpProxy) + localDestination = httpProxy->GetLocalDestination (); else if (socksProxyKeys.length () > 0) { i2p::data::PrivateKeys keys; @@ -1106,16 +1124,18 @@ namespace client } try { - m_SocksProxy = std::make_shared("SOCKS", socksProxyAddr, socksProxyPort, + auto proxy = std::make_shared("SOCKS", socksProxyAddr, socksProxyPort, socksOutProxy, socksOutProxyAddr, socksOutProxyPort, localDestination); uint64_t closeIdleTime; i2p::config::GetOption("socksproxy.i2cp.closeIdleTime", closeIdleTime); if (closeIdleTime) { - m_SocksProxy->SetCloseIdleTime(closeIdleTime); + proxy->SetCloseIdleTime(closeIdleTime); bool newDestOnResume; i2p::config::GetOption("socksproxy.i2cp.newDestOnResume", newDestOnResume); - m_SocksProxy->SetNewDestOnResume(newDestOnResume); + proxy->SetNewDestOnResume(newDestOnResume); } - m_SocksProxy->Start(); + proxy->Start(); + std::lock_guard l(m_ProxyMutex); + m_SocksProxy = proxy; } catch (std::exception& e) { diff --git a/libi2pd_client/ClientContext.h b/libi2pd_client/ClientContext.h index ad1a6af7..989f4372 100644 --- a/libi2pd_client/ClientContext.h +++ b/libi2pd_client/ClientContext.h @@ -127,6 +127,9 @@ namespace client void ReadTunnels (const std::string& tunConf, int& numClientTunnels, int& numServerTunnels); void ReadHttpProxy (); void ReadSocksProxy (); + // take the proxy out under the lock, so it can be stopped without holding it + std::shared_ptr DetachHttpProxy (); + std::shared_ptr DetachSocksProxy (); template std::string GetI2CPOption (const Section& section, const std::string& name, const Type& value) const; template @@ -153,6 +156,7 @@ namespace client AddressBook m_AddressBook; + mutable std::mutex m_ProxyMutex; std::shared_ptr m_HttpProxy, m_SocksProxy; std::map > m_ClientTunnels; // local endpoint -> tunnel std::map, std::shared_ptr > m_ServerTunnels; // -> tunnel @@ -181,8 +185,16 @@ namespace client const decltype(m_ClientForwards)& GetClientForwards () const { return m_ClientForwards; } const decltype(m_ServerForwards)& GetServerForwards () const { return m_ServerForwards; } const decltype(m_TorrentsTunnels)& GetTorrentsTunnels () const { return m_TorrentsTunnels; } - std::shared_ptr GetHttpProxy () const { return m_HttpProxy; } - std::shared_ptr GetSocksProxy () const { return m_SocksProxy; } + std::shared_ptr GetHttpProxy () const + { + std::lock_guard l(m_ProxyMutex); + return m_HttpProxy; + } + std::shared_ptr GetSocksProxy () const + { + std::lock_guard l(m_ProxyMutex); + return m_SocksProxy; + } }; extern ClientContext context;