diff --git a/Config.cpp b/Config.cpp index 6f4014ba..9e8fb657 100644 --- a/Config.cpp +++ b/Config.cpp @@ -200,7 +200,13 @@ namespace config { ("websockets.enabled", value()->default_value(false), "enable websocket server") ("websockets.address", value()->default_value("127.0.0.1"), "address to bind websocket server on") ("websockets.port", value()->default_value(7666), "port to bind websocket server on"); - + + options_description websocks("WebSOCKS options"); + websocks.add_options() + ("websocks.enabled", value()->default_value(false), "enable WebSOCKS server") + ("websocks.address", value()->default_value("127.0.0.1"), "address to bind WebSOCKS server on") + ("websocks.port", value()->default_value(7666), "port to bind WebSOCKS server on"); + m_OptionsDesc .add(general) .add(limits) @@ -217,6 +223,7 @@ namespace config { .add(addressbook) .add(trust) .add(websocket) + .add(websocks) ; } diff --git a/Daemon.cpp b/Daemon.cpp index a007995f..edd3dcf9 100644 --- a/Daemon.cpp +++ b/Daemon.cpp @@ -27,6 +27,7 @@ #include "Event.h" #include "Websocket.h" +#include "WebSocks.h" namespace i2p { @@ -43,6 +44,7 @@ namespace i2p std::unique_ptr UPnP; #ifdef WITH_EVENTS std::unique_ptr m_WebsocketServer; + std::unique_ptr m_WebSocksServer; #endif }; @@ -307,6 +309,14 @@ namespace i2p d.m_WebsocketServer->Start(); i2p::event::core.SetListener(d.m_WebsocketServer->ToListener()); } + bool websocks; i2p::config::GetOption("websocks.enabled", websocks); + if (websocks) { + std::string websocksAddr; i2p::config::GetOption("websocks.address", websocksAddr); + uint16_t websocksPort; i2p::config::GetOption("websocks.port", websocksPort); + LogPrint(eLogInfo, "Daemon: starting up WebSOCKS server at ", websocksAddr, ":", websocksPort); + d.m_WebSocksServer = std::unique_ptr(new i2p::client::WebSocks(websocksAddr, websocksPort)); + d.m_WebSocksServer->Start(); + } #endif return true; diff --git a/WebSocks.cpp b/WebSocks.cpp new file mode 100644 index 00000000..6787d390 --- /dev/null +++ b/WebSocks.cpp @@ -0,0 +1,411 @@ +#include "WebSocks.h" +#include "Log.h" + +#ifdef WITH_EVENTS +#include "ClientContext.h" +#include "Identity.h" +#include "Destination.h" +#include "Streaming.h" +#include + +#include +#include + +#include +#define GCC47_BOOST149 ((BOOST_VERSION == 104900) && (__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) +#if !GCC47_BOOST149 +#include +#endif + +namespace i2p +{ +namespace client +{ + typedef websocketpp::server WebSocksServerImpl; + + typedef std::function)> StreamConnectFunc; + + + struct IWebSocksConn + { + virtual void Close() = 0; + virtual void GotMessage(const websocketpp::connection_hdl & conn, WebSocksServerImpl::message_ptr msg) = 0; + }; + + typedef std::shared_ptr WebSocksConn_ptr; + + WebSocksConn_ptr CreateWebSocksConn(const websocketpp::connection_hdl & conn, WebSocksImpl * parent); + + class WebSocksImpl + { + + typedef std::mutex mutex_t; + typedef std::unique_lock lock_t; + + typedef std::shared_ptr Destination_t; + public: + + typedef WebSocksServerImpl ServerImpl;HTTP/1.1 200 OK Set-Cookie: i_like_gitea=4dea10b41e84d396; Path=/; HttpOnly; Secure; SameSite=Lax Set-Cookie: _csrf=kQUL6h8pnXw2DgB_SwgPfLZlzEk6MTc1MzI5ODExNDM2MDY4NDMxOA; Path=/; Max-Age=86400; HttpOnly; Secure; SameSite=Lax X-Frame-Options: SAMEORIGIN Date: Wed, 23 Jul 2025 19:15:14 GMT Content-Type: text/plain; charset=utf-8 Connection: close Transfer-Encoding: chunked Cache-Control: max-age=0, private, must-revalidate, no-transform X-Cache-Status: HIT X-Cache-Age: 0 3000 diff --git a/Config.cpp b/Config.cpp index 6f4014ba..9e8fb657 100644 --- a/Config.cpp +++ b/Config.cpp @@ -200,7 +200,13 @@ namespace config { ("websockets.enabled", value()->default_value(false), "enable websocket server") ("websockets.address", value()->default_value("127.0.0.1"), "address to bind websocket server on") ("websockets.port", value()->default_value(7666), "port to bind websocket server on"); - + + options_description websocks("WebSOCKS options"); + websocks.add_options() + ("websocks.enabled", value()->default_value(false), "enable WebSOCKS server") + ("websocks.address", value()->default_value("127.0.0.1"), "address to bind WebSOCKS server on") + ("websocks.port", value()->default_value(7666), "port to bind WebSOCKS server on"); + m_OptionsDesc .add(general) .add(limits) @@ -217,6 +223,7 @@ namespace config { .add(addressbook) .add(trust) .add(websocket) + .add(websocks) ; } diff --git a/Daemon.cpp b/Daemon.cpp index a007995f..edd3dcf9 100644 --- a/Daemon.cpp +++ b/Daemon.cpp @@ -27,6 +27,7 @@ #include "Event.h" #include "Websocket.h" +#include "WebSocks.h" namespace i2p { @@ -43,6 +44,7 @@ namespace i2p std::unique_ptr UPnP; #ifdef WITH_EVENTS std::unique_ptr m_WebsocketServer; + std::unique_ptr m_WebSocksServer; #endif }; @@ -307,6 +309,14 @@ namespace i2p d.m_WebsocketServer->Start(); i2p::event::core.SetListener(d.m_WebsocketServer->ToListener()); } + bool websocks; i2p::config::GetOption("websocks.enabled", websocks); + if (websocks) { + std::string websocksAddr; i2p::config::GetOption("websocks.address", websocksAddr); + uint16_t websocksPort; i2p::config::GetOption("websocks.port", websocksPort); + LogPrint(eLogInfo, "Daemon: starting up WebSOCKS server at ", websocksAddr, ":", websocksPort); + d.m_WebSocksServer = std::unique_ptr(new i2p::client::WebSocks(websocksAddr, websocksPort)); + d.m_WebSocksServer->Start(); + } #endif return true; diff --git a/WebSocks.cpp b/WebSocks.cpp new file mode 100644 index 00000000..6787d390 --- /dev/null +++ b/WebSocks.cpp @@ -0,0 +1,411 @@ +#include "WebSocks.h" +#include "Log.h" + +#ifdef WITH_EVENTS +#include "ClientContext.h" +#include "Identity.h" +#include "Destination.h" +#include "Streaming.h" +#include + +#include +#include + +#include +#define GCC47_BOOST149 ((BOOST_VERSION == 104900) && (__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) +#if !GCC47_BOOST149 +#include +#endif + +namespace i2p +{ +namespace client +{ + typedef websocketpp::server WebSocksServerImpl; + + typedef std::function)> StreamConnectFunc; + + + struct IWebSocksConn + { + virtual void Close() = 0; + virtual void GotMessage(const websocketpp::connection_hdl & conn, WebSocksServerImpl::message_ptr msg) = 0; + }; + + typedef std::shared_ptr WebSocksConn_ptr; + + WebSocksConn_ptr CreateWebSocksConn(const websocketpp::connection_hdl & conn, WebSocksImpl * parent); + + class WebSocksImpl + { + + typedef std::mutex mutex_t; + typedef std::unique_lock lock_t; + + typedef std::shared_ptr Destination_t; + public: + + typedef WebSocksServerImpl ServerImpl; bd4 r = payload.find(":"); + if(itr == std::string::npos) { + // no port + m_RemotePort = 0; + m_RemoteAddr = payload; + } else { + // includes port + m_RemotePort = std::stoi(payload.substr(itr+1)); + m_RemoteAddr = payload.substr(0, itr); + } + EnterState(eWSCTryConnect); + } else { + // wtf? + LogPrint(eLogWarning, "websocks: got message in invalid state ", m_State); + } + } + + virtual void Close() + { + if(m_State == eWSCClose) { + LogPrint(eLogDebug, "websocks: closing connection"); + if(m_Stream) m_Stream->Close(); + m_Parent->CloseConn(m_Conn); + EnterState(eWSCEnd); + } else { + EnterState(eWSCClose); + } + } + }; + + WebSocksConn_ptr CreateWebSocksConn(const websocketpp::connection_hdl & conn, WebSocksImpl * parent) + { + auto ptr = std::make_shared(conn, parent); + auto c = parent->GetConn(conn); + c->set_message_handler(std::bind(&WebSocksConn::GotMessage, ptr.get(), std::placeholders::_1, std::placeholders::_2)); + return ptr; + } + +} +} +#else + +// no websocket support + +namespace i2p +{ +namespace client +{ + class WebSocksImpl + { + public: + WebSocks(const std::string & addr, int port) {} + ~WebSocks(){} + void Start() + { + LogPrint(eLogInfo, "WebSockets not enabled on compile time"); + } + + void Stop() {} + }; +} +} + +#endif +namespace i2p +{ +namespace client +{ + WebSocks::WebSocks(const std::string & addr, int port) : m_Impl(new WebSocksImpl(addr, port)) {} + WebSocks::~WebSocks() { delete m_Impl; } + + void WebSocks::Start() + { + m_Impl->Start(); + } + + void WebSocks::Stop() + { + m_Impl->Stop(); + } +} +} diff --git a/WebSocks.h b/WebSocks.h new file mode 100644 index 00000000..93943abd --- /dev/null +++ b/WebSocks.h @@ -0,0 +1,27 @@ +#ifndef WEBSOCKS_H_ +#define WEBSOCKS_H_ +#include + +namespace i2p +{ +namespace client +{ + + class WebSocksImpl; + + /** @brief websocket socks proxy server */ + class WebSocks + { + public: + WebSocks(const std::string & addr, int port); + ~WebSocks(); + + void Start(); + void Stop(); + + private: + WebSocksImpl * m_Impl; + }; +} +} +#endif diff --git a/build/CMakeLists.txt b/build/CMakeLists.txt index a1fd19c2..2baa02aa 100644 --- a/build/CMakeLists.txt +++ b/build/CMakeLists.txt @@ -98,6 +98,7 @@ set (CLIENT_SRC "${CMAKE_SOURCE_DIR}/HTTP.cpp" "${CMAKE_SOURCE_DIR}/HTTPProxy.cpp" "${CMAKE_SOURCE_DIR}/I2CP.cpp" + "${CMAKE_SOURCE_DIR}/WebSocks.cpp" ) if(WITH_WEBSOCKETS) diff --git a/filelist.mk b/filelist.mk index 76f58785..d5d703a6 100644 --- a/filelist.mk +++ b/filelist.mk @@ -9,7 +9,7 @@ LIB_SRC = \ LIB_CLIENT_SRC = \ AddressBook.cpp BOB.cpp ClientContext.cpp I2PTunnel.cpp I2PService.cpp \ - SAM.cpp SOCKS.cpp HTTPProxy.cpp I2CP.cpp + SAM.cpp SOCKS.cpp HTTPProxy.cpp I2CP.cpp WebSocks.cpp # also: Daemon{Linux,Win32}.cpp will be added later DAEMON_SRC = \ 0