diff --git a/ClientContext.cpp b/ClientContext.cpp index 939a9e43..11ed7c98 100644 --- a/ClientContext.cpp +++ b/ClientContext.cpp @@ -8,6 +8,8 @@ #include "Identity.h" #include "util.h" #include "ClientContext.h" +#include "SOCKS.h" +#include "WebSocks.h" namespace i2p { @@ -424,7 +426,11 @@ namespace client try { std::string type = section.second.get (I2P_TUNNELS_SECTION_TYPE); - if (type == I2P_TUNNELS_SECTION_TYPE_CLIENT || type == I2P_TUNNELS_SECTION_TYPE_UDPCLIENT) + if (type == I2P_TUNNELS_SECTION_TYPE_CLIENT + || type == I2P_TUNNELS_SECTION_TYPE_SOCKS + || type == I2P_TUNNELS_SECTION_TYPE_WEBSOCKS + || type == I2P_TUNNELS_SECTION_TYPE_HTTPPROXY + || type == I2P_TUNNELS_SECTION_TYPE_UDPCLIENT) { // mandatory params std::string dest = section.second.get (I2P_CLIENT_TUNNEL_DESTINATION); @@ -466,19 +472,45 @@ namespace client LogPrint(eLogError, "Clients: I2P Client forward for endpoint ", end, " already exists"); } else { - // tcp client - auto clientTunnel = new I2PClientTunnel (name, dest, address, port, localDestination, destinationPort); - if (m_ClientTunnels.insert (std::make_pair (clientTunnel->GetAcceptor ().local_endpoint (), - std::unique_ptr(clientTunnel))).second) + boost::asio::ip::tcp::endpoint clientEndpoint; + I2PService * clientTunnel = nullptr; + if (type == I2P_TUNNELS_SECTION_TYPE_SOCKS) + { + // socks proxy + clientTunnel = new i2p::proxy::SOCKSProxy(address, port, "", destinationPort, localDestination); + clientEndpoint = ((i2p::proxy::SOCKSProxy*)clientTunnel)->GetAcceptor().local_endpoint(); + } + else if (type == I2P_TUNNELS_SECTION_TYPE_HTTPPROXY) + { + // http proxy + clientTunnel = new i2p::proxy::HTTPProxy(address, port, localDestination); + clientEndpoint = ((i2p::proxy::HTTPProxy*)clientTunnel)->GetAcceptor().local_endpoint(); + } + else if (type == I2P_TUNNELS_SECTION_TYPE_WEBSOCKS) + { + // websocks proxy + clientTunnel = new WebSocks(address, port, localDestination);; + clientEndpoint = ((WebSocks*)clientTunnel)->GetLocalEndpoint(); + } + else + { + // tcp client + clientTunnel = new I2PClientTunnel (name, dest, address, port, localDestination, destinationPort); + clientEndpoint = ((I2PClientTunnel*)clientTunnel)->GetAcceptor().local_endpoint(); + } + if (m_ClientTunnels.insert (std::make_pair (clientEndpoint, std::unique_ptr(clientTunnel))).second) { clientTunnel->Start (); numClientTunnels++; } else - LogPrint (eLogError, "Clients: I2P client tunnel for endpoint ", clientTunnel->GetAcceptor ().local_endpoint (), " already exists"); + LogPrint (eLogError, "Clients: I2P client tunnel for endpoint ", clientEndpoint, "already exists"); } } - else if (type == I2P_TUNNELS_SECTION_TYPE_SERVER || type == I2P_TUNNELS_SECTION_TYPE_HTTP || type == I2P_TUNNELS_SECTION_TYPE_IRC || type == I2P_TUNNELS_SECTION_TYPE_UDPSERVER) + else if (type == I2P_TUNNELS_SECTION_TYPE_SERVER + || type == I2P_TUNNELS_SECTION_TYPE_HTTP + || type == I2P_TUNNELS_SECTION_TYPE_IRC + || type == I2P_TUNNELS_SECTION_TYPE_UDPSERVER) { // mandatory params std::string host = section.second.get (I2P_SERVER_TUNNEL_HOST); diff --git a/ClientContext.h b/ClientContext.h index 1961f411..fad042ed 100644 --- a/ClientContext.h +++ b/ClientContext.h @@ -26,6 +26,9 @@ namespace client const char I2P_TUNNELS_SECTION_TYPE_IRC[] = "irc"; const char I2P_TUNNELS_SECTION_TYPE_UDPCLIENT[] = "udpclient"; const char I2P_TUNNELS_SECTION_TYPE_UDPSERVER[] = "udpserver"; + const char I2P_TUNNELS_SECTION_TYPE_SOCKS[] = "socks"; + const char I2P_TUNNELS_SECTION_TYPE_WEBSOCKS[] = "websocks"; + const char I2P_TUNNELS_SECTION_TYPE_HTTPPROXY[] = "httpproxy"; const char I2P_CLIENT_TUNNEL_PORT[] = "port"; const char I2P_CLIENT_TUNNEL_ADDRESS[] = "address"; const char I2P_CLIENT_TUNNEL_DESTINATION[] = "destination"; @@ -93,7 +96,7 @@ namespace client i2p::proxy::HTTPProxy * m_HttpProxy; i2p::proxy::SOCKSProxy * m_SocksProxy; - std::map > m_ClientTunnels; // local endpoint->tunnel + std::map > m_ClientTunnels; // local endpoint->tunnel std::map, std::unique_ptr > m_ServerTunnels; // ->tunnel std::mutex m_ForwardsMutex; diff --git a/Config.cpp b/Config.cpp index 728b7996..64333d74 100644 --- a/Config.cpp +++ b/Config.cpp @@ -203,12 +203,6 @@ namespace config { ("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) @@ -225,7 +219,6 @@ namespace config { .add(addressbook) .add(trust) .add(websocket) - .add(websocks) ; } diff --git a/Daemon.cpp b/Daemon.cpp index edd3dcf9..c7aaa279 100644 --- a/Daemon.cpp +++ b/Daemon.cpp @@ -27,7 +27,6 @@ #include "Event.h" #include "Websocket.h" -#include "WebSocks.h" namespace i2p { @@ -44,7 +43,6 @@ namespace i2p std::unique_ptr UPnP; #ifdef WITH_EVENTS std::unique_ptr m_WebsocketServer; - std::unique_ptr m_WebSocksServer; #endif }; @@ -309,15 +307,6 @@ 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/I2PService.h b/I2PService.h index 795b075e..096443db 100644 --- a/I2PService.h +++ b/I2PService.h @@ -121,10 +121,11 @@ namespace client void Stop (); const boost::asio::ip::tcp::acceptor& GetAcceptor () const { return m_Acceptor; }; - + + virtual const char* GetName() { return "Generic TCP/IP accepting daemon"; } + protected: virtual std::shared_ptr CreateHandler(std::shared_ptr socket) = 0; - virtual const char* GetName() { return "Generic TCP/IP accepting daemon"; } private: void Accept(); void HandleAccept(const boost::system::error_code& ecode, std::shared_ptr socket); diff --git a/WebSocks.cpp b/WebSocks.cpp index a9a8751b..b6faa711 100644 --- a/WebSocks.cpp +++ b/WebSocks.cpp @@ -22,254 +22,273 @@ namespace i2p { namespace client { - typedef websocketpp::server WebSocksServerImpl; + typedef websocketpp::server WebSocksServerImpl; - typedef std::function)> StreamConnectFunc; + typedef std::function)> StreamConnectFunc; - struct IWebSocksConn - { - virtual void Close() = 0; - virtual void GotMessage(const websocketpp::connection_hdl & conn, WebSocksServerImpl::message_ptr msg) = 0; - }; + struct IWebSocksConn : public I2PServiceHandler + { + IWebSocksConn(I2PService * parent) : I2PServiceHandler(parent) {} + virtual void Close() = 0; + virtual void GotMessage(const websocketpp::connection_hdl & conn, WebSocksServerImpl::message_ptr msg) = 0; + }; - typedef std::shared_ptr WebSocksConn_ptr; + typedef std::shared_ptr WebSocksConn_ptr; - WebSocksConn_ptr CreateWebSocksConn(const websocketpp::connection_hdl & conn, WebSocksImpl * parent); + 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::mutex mutex_t; + typedef std::unique_lock lock_t; - typedef std::shared_ptr Destination_t; - public: + typedef std::shared_ptr Destination_t; + public: - typedef WebSocksServerImpl ServerImpl; - typedef ServerImpl::message_ptr MessagePtr; + typedef WebSocksServerImpl ServerImpl; + typedef ServerImpl::message_ptr MessagePtr; WebSocksImpl(const std::string & addr, int port) : - m_Run(false), - m_Addr(addr), - m_Port(port), - m_Thread(nullptr) + Parent(nullptr), + m_Run(false), + m_Addr(addr), + m_Port(port), + m_Thread(nullptr) + { + m_Server.init_asio(); + m_Server.set_open_handler(std::bind(&WebSocksImpl::ConnOpened, this, std::placeholders::_1)); + } + + void InitializeDestination(WebSocks * parent) + { + Parent = parent; + m_Dest = Parent->GetLocalDestination(); + } + + ServerImpl::connection_ptr GetConn(const websocketpp::connection_hdl & conn) + { + return m_Server.get_con_from_hdl(conn); + } + + void CloseConn(const websocketpp::connection_hdl & conn) + { + auto c = GetConn(conn); + if(c) c->close(websocketpp::close::status::normal, "closed"); + } + + void CreateStreamTo(const std::string & addr, int port, StreamConnectFunc complete) + { + auto & addressbook = i2p::client::context.GetAddressBook(); + i2p::data::IdentHash ident; + if(addressbook.GetIdentHash(addr, ident)) { + // address found + m_Dest->CreateStream(complete, ident, port); + } else { + // not found + complete(nullptr); + } + } + + void ConnOpened(websocketpp::connection_hdl conn) + { + auto ptr = CreateWebSocksConn(conn, this); + Parent->AddHandler(ptr); + m_Conns.push_back(ptr); + } + + void Start() + { + if(m_Run) return; // already started + m_Server.listen(boost::asio::ip::address::from_string(m_Addr), m_Port); + m_Server.start_accept(); + m_Run = true; + m_Thread = new std::thread([&] (){ + while(m_Run) { + try { + m_Server.run(); + } catch( std::exception & ex) { + LogPrint(eLogError, "Websocks runtime exception: ", ex.what()); + } + } + }); + m_Dest->Start(); + } + + void Stop() { - m_Server.init_asio(); - m_Server.set_open_handler(std::bind(&WebSocksImpl::ConnOpened, this, std::placeholders::_1)); - i2p::data::PrivateKeys k = i2p::data::PrivateKeys::CreateRandomKeys(i2p::data::SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519); - m_Dest = std::make_shared(k, false); + for(const auto & conn : m_Conns) + conn->Close(); + + m_Dest->Stop(); + m_Run = false; + m_Server.stop(); + if(m_Thread) { + m_Thread->join(); + delete m_Thread; + } + m_Thread = nullptr; } - ServerImpl::connection_ptr GetConn(const websocketpp::connection_hdl & conn) - { - return m_Server.get_con_from_hdl(conn); - } - - void CloseConn(const websocketpp::connection_hdl & conn) - { - auto c = GetConn(conn); - if(c) c->close(websocketpp::close::status::normal, "closed"); - } - - void CreateStreamTo(const std::string & addr, int port, StreamConnectFunc complete) - { - auto & addressbook = i2p::client::context.GetAddressBook(); - i2p::data::IdentHash ident; - if(addressbook.GetIdentHash(addr, ident)) { - // address found - m_Dest->CreateStream(complete, ident, port); - } else { - // not found - complete(nullptr); - } - } - - void ConnOpened(websocketpp::connection_hdl conn) - { - m_Conns.push_back(CreateWebSocksConn(conn, this)); - } - - void Start() - { - if(m_Run) return; // already started - m_Server.listen(boost::asio::ip::address::from_string(m_Addr), m_Port); - m_Server.start_accept(); - m_Run = true; - m_Thread = new std::thread([&] (){ - while(m_Run) { - try { - m_Server.run(); - } catch( std::exception & ex) { - LogPrint(eLogError, "Websocks runtime exception: ", ex.what()); - } - } - }); - m_Dest->Start(); - } - - void Stop() - { - for(const auto & conn : m_Conns) - conn->Close(); - - m_Dest->Stop(); - m_Run = false; - m_Server.stop(); - if(m_Thread) { - m_Thread->join(); - delete m_Thread; - } - m_Thread = nullptr; - } - - private: - std::vector m_Conns; - bool m_Run; - ServerImpl m_Server; - std::string m_Addr; - int m_Port; - std::thread * m_Thread; - Destination_t m_Dest; + boost::asio::ip::tcp::endpoint GetLocalEndpoint() + { + return boost::asio::ip::tcp::endpoint(boost::asio::ip::address::from_string(m_Addr), m_Port); + } + + WebSocks * Parent; + + private: + std::vector m_Conns; + bool m_Run; + ServerImpl m_Server; + std::string m_Addr; + int m_Port; + std::thread * m_Thread; + Destination_t m_Dest; }; - struct WebSocksConn : public IWebSocksConn - { - enum ConnState - { - eWSCInitial, - eWSCTryConnect, - eWSCFailConnect, - eWSCOkayConnect, - eWSCClose, - eWSCEnd - }; - - typedef WebSocksServerImpl ServerImpl; - typedef ServerImpl::message_ptr Message_t; - typedef websocketpp::connection_hdl ServerConn; - typedef std::shared_ptr Destination_t; - typedef std::shared_ptr StreamDest_t; - typedef std::shared_ptr Stream_t; - - ServerConn m_Conn; - Stream_t m_Stream; - ConnState m_State; - WebSocksImpl * m_Parent; - std::string m_RemoteAddr; - int m_RemotePort; - uint8_t m_RecvBuf[2048]; - - WebSocksConn(const ServerConn & conn, WebSocksImpl * parent) : - m_Conn(conn), - m_Stream(nullptr), - m_State(eWSCInitial), - m_Parent(parent) - { - - } - - ~WebSocksConn() - { - Close(); - } - - void EnterState(ConnState state) - { - LogPrint(eLogDebug, "websocks: state ", m_State, " -> ", state); - switch(m_State) - { - case eWSCInitial: - if (state == eWSCClose) { - m_State = eWSCClose; - // connection was opened but never used - LogPrint(eLogInfo, "websocks: connection closed but never used"); - Close(); - return; - } else if (state == eWSCTryConnect) { - // we will try to connect - m_State = eWSCTryConnect; - m_Parent->CreateStreamTo(m_RemoteAddr, m_RemotePort, std::bind(&WebSocksConn::ConnectResult, this, std::placeholders::_1)); - } else { - LogPrint(eLogWarning, "websocks: invalid state change ", m_State, " -> ", state); - } - return; - case eWSCTryConnect: - if(state == eWSCOkayConnect) { - // we connected okay - LogPrint(eLogDebug, "websocks: connected to ", m_RemoteAddr, ":", m_RemotePort); - SendResponse(""); - m_State = eWSCOkayConnect; - } else if(state == eWSCFailConnect) { - // we did not connect okay - LogPrint(eLogDebug, "websocks: failed to connect to ", m_RemoteAddr, ":", m_RemotePort); - SendResponse("failed to connect"); - m_State = eWSCFailConnect; - EnterState(eWSCInitial); - } else if(state == eWSCClose) { - // premature close - LogPrint(eLogWarning, "websocks: websocket connection closed prematurely"); - m_State = eWSCClose; - } else { - LogPrint(eLogWarning, "websocks: invalid state change ", m_State, " -> ", state); - } - return; - case eWSCFailConnect: - if (state == eWSCInitial) { - // reset to initial state so we can try connecting again - m_RemoteAddr = ""; - m_RemotePort = 0; - LogPrint(eLogDebug, "websocks: reset websocket conn to initial state"); - m_State = eWSCInitial; - } else if (state == eWSCClose) { - // we are going to close the connection - m_State = eWSCClose; - Close(); - } else { - LogPrint(eLogWarning, "websocks: invalid state change ", m_State, " -> ", state); - } - return; - case eWSCOkayConnect: - if(state == eWSCClose) { - // graceful close - m_State = eWSCClose; - Close(); - } else { - LogPrint(eLogWarning, "websocks: invalid state change ", m_State, " -> ", state); - } - case eWSCClose: - if(state == eWSCEnd) { - LogPrint(eLogDebug, "websocks: socket ended"); - } else { - LogPrint(eLogWarning, "websocks: invalid state change ", m_State, " -> ", state); - } - return; - default: - LogPrint(eLogError, "websocks: bad state ", m_State); - } - } - - void StartForwarding() - { - LogPrint(eLogDebug, "websocks: begin forwarding data"); + struct WebSocksConn : public IWebSocksConn , public std::enable_shared_from_this + { + enum ConnState + { + eWSCInitial, + eWSCTryConnect, + eWSCFailConnect, + eWSCOkayConnect, + eWSCClose, + eWSCEnd + }; + + typedef WebSocksServerImpl ServerImpl; + typedef ServerImpl::message_ptr Message_t; + typedef websocketpp::connection_hdl ServerConn; + typedef std::shared_ptr Destination_t; + typedef std::shared_ptr StreamDest_t; + typedef std::shared_ptr Stream_t; + + ServerConn m_Conn; + Stream_t m_Stream; + ConnState m_State; + WebSocksImpl * m_Parent; + std::string m_RemoteAddr; + int m_RemotePort; + uint8_t m_RecvBuf[2048]; + + WebSocksConn(const ServerConn & conn, WebSocksImpl * parent) : + IWebSocksConn(parent->Parent), + m_Conn(conn), + m_Stream(nullptr), + m_State(eWSCInitial), + m_Parent(parent) + { + + } + + ~WebSocksConn() + { + Close(); + } + + void EnterState(ConnState state) + { + LogPrint(eLogDebug, "websocks: state ", m_State, " -> ", state); + switch(m_State) + { + case eWSCInitial: + if (state == eWSCClose) { + m_State = eWSCClose; + // connection was opened but never used + LogPrint(eLogInfo, "websocks: connection closed but never used"); + Close(); + return; + } else if (state == eWSCTryConnect) { + // we will try to connect + m_State = eWSCTryConnect; + m_Parent->CreateStreamTo(m_RemoteAddr, m_RemotePort, std::bind(&WebSocksConn::ConnectResult, this, std::placeholders::_1)); + } else { + LogPrint(eLogWarning, "websocks: invalid state change ", m_State, " -> ", state); + } + return; + case eWSCTryConnect: + if(state == eWSCOkayConnect) { + // we connected okay + LogPrint(eLogDebug, "websocks: connected to ", m_RemoteAddr, ":", m_RemotePort); + SendResponse(""); + m_State = eWSCOkayConnect; + } else if(state == eWSCFailConnect) { + // we did not connect okay + LogPrint(eLogDebug, "websocks: failed to connect to ", m_RemoteAddr, ":", m_RemotePort); + SendResponse("failed to connect"); + m_State = eWSCFailConnect; + EnterState(eWSCInitial); + } else if(state == eWSCClose) { + // premature close + LogPrint(eLogWarning, "websocks: websocket connection closed prematurely"); + m_State = eWSCClose; + } else { + LogPrint(eLogWarning, "websocks: invalid state change ", m_State, " -> ", state); + } + return; + case eWSCFailConnect: + if (state == eWSCInitial) { + // reset to initial state so we can try connecting again + m_RemoteAddr = ""; + m_RemotePort = 0; + LogPrint(eLogDebug, "websocks: reset websocket conn to initial state"); + m_State = eWSCInitial; + } else if (state == eWSCClose) { + // we are going to close the connection + m_State = eWSCClose; + Close(); + } else { + LogPrint(eLogWarning, "websocks: invalid state change ", m_State, " -> ", state); + } + return; + case eWSCOkayConnect: + if(state == eWSCClose) { + // graceful close + m_State = eWSCClose; + Close(); + } else { + LogPrint(eLogWarning, "websocks: invalid state change ", m_State, " -> ", state); + } + case eWSCClose: + if(state == eWSCEnd) { + LogPrint(eLogDebug, "websocks: socket ended"); + Kill(); + auto me = shared_from_this(); + Done(me); + } else { + LogPrint(eLogWarning, "websocks: invalid state change ", m_State, " -> ", state); + } + return; + default: + LogPrint(eLogError, "websocks: bad state ", m_State); + } + } + + void StartForwarding() + { + LogPrint(eLogDebug, "websocks: begin forwarding data"); uint8_t b[1]; m_Stream->Send(b, 0); - AsyncRecv(); - } - - void HandleAsyncRecv(const boost::system::error_code &ec, std::size_t n) - { - if(ec) { - // error - LogPrint(eLogWarning, "websocks: connection error ", ec.message()); - EnterState(eWSCClose); - } else { - // forward data - LogPrint(eLogDebug, "websocks recv ", n); - + AsyncRecv(); + } + + void HandleAsyncRecv(const boost::system::error_code &ec, std::size_t n) + { + if(ec) { + // error + LogPrint(eLogWarning, "websocks: connection error ", ec.message()); + EnterState(eWSCClose); + } else { + // forward data + LogPrint(eLogDebug, "websocks recv ", n); + std::string str((char*)m_RecvBuf, n); auto conn = m_Parent->GetConn(m_Conn); - if(!conn) { + if(!conn) { LogPrint(eLogWarning, "websocks: connection is gone"); EnterState(eWSCClose); return; @@ -277,98 +296,98 @@ namespace client conn->send(str); AsyncRecv(); - } - } - - void AsyncRecv() - { - m_Stream->AsyncReceive( - boost::asio::buffer(m_RecvBuf, sizeof(m_RecvBuf)), - std::bind(&WebSocksConn::HandleAsyncRecv, this, std::placeholders::_1, std::placeholders::_2), 60); - } - - /** @brief send error message or empty string for success */ - void SendResponse(const std::string & errormsg) - { - boost::property_tree::ptree resp; - if(errormsg.size()) { - resp.put("error", errormsg); - resp.put("success", 0); - } else { - resp.put("success", 1); - } - std::ostringstream ss; - write_json(ss, resp); - auto conn = m_Parent->GetConn(m_Conn); - if(conn) conn->send(ss.str()); - } - - void ConnectResult(Stream_t stream) - { - m_Stream = stream; - if(m_State == eWSCClose) { - // premature close of websocket - Close(); - return; - } - if(m_Stream) { - // connect good - EnterState(eWSCOkayConnect); + } + } + + void AsyncRecv() + { + m_Stream->AsyncReceive( + boost::asio::buffer(m_RecvBuf, sizeof(m_RecvBuf)), + std::bind(&WebSocksConn::HandleAsyncRecv, this, std::placeholders::_1, std::placeholders::_2), 60); + } + + /** @brief send error message or empty string for success */ + void SendResponse(const std::string & errormsg) + { + boost::property_tree::ptree resp; + if(errormsg.size()) { + resp.put("error", errormsg); + resp.put("success", 0); + } else { + resp.put("success", 1); + } + std::ostringstream ss; + write_json(ss, resp); + auto conn = m_Parent->GetConn(m_Conn); + if(conn) conn->send(ss.str()); + } + + void ConnectResult(Stream_t stream) + { + m_Stream = stream; + if(m_State == eWSCClose) { + // premature close of websocket + Close(); + return; + } + if(m_Stream) { + // connect good + EnterState(eWSCOkayConnect); StartForwarding(); - } else { - // connect failed - EnterState(eWSCFailConnect); - } - } - - virtual void GotMessage(const websocketpp::connection_hdl & conn, WebSocksServerImpl::message_ptr msg) - { - (void) conn; - std::string payload = msg->get_payload(); - if(m_State == eWSCOkayConnect) - { - // forward to server - LogPrint(eLogDebug, "websocks: forward ", payload.size()); - m_Stream->Send((uint8_t*)payload.c_str(), payload.size()); - } else if (m_State == eWSCInitial) { - // recv connect request - auto itr = 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 { + // connect failed + EnterState(eWSCFailConnect); + } + } + + virtual void GotMessage(const websocketpp::connection_hdl & conn, WebSocksServerImpl::message_ptr msg) + { + (void) conn; + std::string payload = msg->get_payload(); + if(m_State == eWSCOkayConnect) + { + // forward to server + LogPrint(eLogDebug, "websocks: forward ", payload.size()); + m_Stream->Send((uint8_t*)payload.c_str(), payload.size()); + } else if (m_State == eWSCInitial) { + // recv connect request + auto itr = 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; + } } } @@ -383,7 +402,7 @@ namespace client class WebSocksImpl { public: - WebSocksImpl(const std::string & addr, int port) + WebSocksImpl(const std::string & addr, int port) : m_Addr(addr), m_Port(port) { } @@ -398,9 +417,20 @@ namespace client void Stop() { + } + void InitializeDestination(WebSocks * parent) + { } + boost::asio::ip::tcp::endpoint GetLocalEndpoint() + { + return boost::asio::ip::tcp::endpoint(boost::asio::ip::address::from_string(m_Addr), m_Port); + } + + std::string m_Addr; + int m_Port; + }; } } @@ -410,17 +440,28 @@ namespace i2p { namespace client { - WebSocks::WebSocks(const std::string & addr, int port) : m_Impl(new WebSocksImpl(addr, port)) {} + WebSocks::WebSocks(const std::string & addr, int port, std::shared_ptr localDestination) : m_Impl(new WebSocksImpl(addr, port)) + { + m_Impl->InitializeDestination(this); + } WebSocks::~WebSocks() { delete m_Impl; } void WebSocks::Start() { m_Impl->Start(); + GetLocalDestination()->Start(); + } + + boost::asio::ip::tcp::endpoint WebSocks::GetLocalEndpoint() const + { + return m_Impl->GetLocalEndpoint(); } void WebSocks::Stop() { m_Impl->Stop(); + GetLocalDestination()->Stop(); } } } + diff --git a/WebSocks.h b/WebSocks.h index 93943abd..2314659f 100644 --- a/WebSocks.h +++ b/WebSocks.h @@ -1,27 +1,34 @@ #ifndef WEBSOCKS_H_ #define WEBSOCKS_H_ #include +#include +#include "I2PService.h" +#include "Destination.h" namespace i2p { namespace client { - class WebSocksImpl; + class WebSocksImpl; - /** @brief websocket socks proxy server */ - class WebSocks - { - public: - WebSocks(const std::string & addr, int port); - ~WebSocks(); + /** @brief websocket socks proxy server */ + class WebSocks : public i2p::client::I2PService + { + public: + WebSocks(const std::string & addr, int port, std::shared_ptr localDestination); + ~WebSocks(); - void Start(); - void Stop(); + void Start(); + void Stop(); - private: - WebSocksImpl * m_Impl; - }; + boost::asio::ip::tcp::endpoint GetLocalEndpoint() const; + + const char * GetName() { return "WebSOCKS Proxy"; } + + private: + WebSocksImpl * m_Impl; + }; } } #endif diff --git a/android/jni/Android.mk b/android/jni/Android.mk index c44594f0..5eaa983e 100755 --- a/android/jni/Android.mk +++ b/android/jni/Android.mk @@ -59,7 +59,8 @@ LOCAL_SRC_FILES := DaemonAndroid.cpp i2pd_android.cpp \ ../../TunnelPool.cpp \ ../../Timestamp.cpp \ ../../Event.cpp \ - ../../BloomFilter.cpp \ + ../../WebSocks.cpp \ +../../BloomFilter.cpp \ ../../util.cpp \ ../../i2pd.cpp ../../UPnP.cpp