mirror of
https://github.com/PurpleI2P/i2pd.git
synced 2025-01-11 17:37:53 +00:00
* add websocks
* enable socks, websocks and httpproxy as client tunnels * remove old websocks config
This commit is contained in:
parent
43c1a87c48
commit
c5d3c0c6f8
@ -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<std::string> (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<std::string> (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<I2PClientTunnel>(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<I2PService>(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<std::string> (I2P_SERVER_TUNNEL_HOST);
|
||||
|
@ -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<boost::asio::ip::tcp::endpoint, std::unique_ptr<I2PClientTunnel> > m_ClientTunnels; // local endpoint->tunnel
|
||||
std::map<boost::asio::ip::tcp::endpoint, std::unique_ptr<I2PService> > m_ClientTunnels; // local endpoint->tunnel
|
||||
std::map<std::pair<i2p::data::IdentHash, int>, std::unique_ptr<I2PServerTunnel> > m_ServerTunnels; // <destination,port>->tunnel
|
||||
|
||||
std::mutex m_ForwardsMutex;
|
||||
|
@ -203,12 +203,6 @@ namespace config {
|
||||
("websockets.address", value<std::string>()->default_value("127.0.0.1"), "address to bind websocket server on")
|
||||
("websockets.port", value<uint16_t>()->default_value(7666), "port to bind websocket server on");
|
||||
|
||||
options_description websocks("WebSOCKS options");
|
||||
websocks.add_options()
|
||||
("websocks.enabled", value<bool>()->default_value(false), "enable WebSOCKS server")
|
||||
("websocks.address", value<std::string>()->default_value("127.0.0.1"), "address to bind WebSOCKS server on")
|
||||
("websocks.port", value<uint16_t>()->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)
|
||||
;
|
||||
}
|
||||
|
||||
|
11
Daemon.cpp
11
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<i2p::transport::UPnP> UPnP;
|
||||
#ifdef WITH_EVENTS
|
||||
std::unique_ptr<i2p::event::WebsocketServer> m_WebsocketServer;
|
||||
std::unique_ptr<i2p::client::WebSocks> 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<i2p::client::WebSocks>(new i2p::client::WebSocks(websocksAddr, websocksPort));
|
||||
d.m_WebSocksServer->Start();
|
||||
}
|
||||
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
@ -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<I2PServiceHandler> CreateHandler(std::shared_ptr<boost::asio::ip::tcp::socket> 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<boost::asio::ip::tcp::socket> socket);
|
||||
|
641
WebSocks.cpp
641
WebSocks.cpp
@ -22,254 +22,273 @@ namespace i2p
|
||||
{
|
||||
namespace client
|
||||
{
|
||||
typedef websocketpp::server<websocketpp::config::asio> WebSocksServerImpl;
|
||||
typedef websocketpp::server<websocketpp::config::asio> WebSocksServerImpl;
|
||||
|
||||
typedef std::function<void(std::shared_ptr<i2p::stream::Stream>)> StreamConnectFunc;
|
||||
typedef std::function<void(std::shared_ptr<i2p::stream::Stream>)> 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<IWebSocksConn> WebSocksConn_ptr;
|
||||
typedef std::shared_ptr<IWebSocksConn> 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<mutex_t> lock_t;
|
||||
typedef std::mutex mutex_t;
|
||||
typedef std::unique_lock<mutex_t> lock_t;
|
||||
|
||||
typedef std::shared_ptr<ClientDestination> Destination_t;
|
||||
public:
|
||||
typedef std::shared_ptr<ClientDestination> 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));
|
||||
i2p::data::PrivateKeys k = i2p::data::PrivateKeys::CreateRandomKeys(i2p::data::SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519);
|
||||
m_Dest = std::make_shared<ClientDestination>(k, false);
|
||||
m_Server.init_asio();
|
||||
m_Server.set_open_handler(std::bind(&WebSocksImpl::ConnOpened, this, std::placeholders::_1));
|
||||
}
|
||||
|
||||
ServerImpl::connection_ptr GetConn(const websocketpp::connection_hdl & conn)
|
||||
{
|
||||
return m_Server.get_con_from_hdl(conn);
|
||||
}
|
||||
void InitializeDestination(WebSocks * parent)
|
||||
{
|
||||
Parent = parent;
|
||||
m_Dest = Parent->GetLocalDestination();
|
||||
}
|
||||
|
||||
void CloseConn(const websocketpp::connection_hdl & conn)
|
||||
{
|
||||
auto c = GetConn(conn);
|
||||
if(c) c->close(websocketpp::close::status::normal, "closed");
|
||||
}
|
||||
ServerImpl::connection_ptr GetConn(const websocketpp::connection_hdl & conn)
|
||||
{
|
||||
return m_Server.get_con_from_hdl(conn);
|
||||
}
|
||||
|
||||
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 CloseConn(const websocketpp::connection_hdl & conn)
|
||||
{
|
||||
auto c = GetConn(conn);
|
||||
if(c) c->close(websocketpp::close::status::normal, "closed");
|
||||
}
|
||||
|
||||
void ConnOpened(websocketpp::connection_hdl conn)
|
||||
{
|
||||
m_Conns.push_back(CreateWebSocksConn(conn, this));
|
||||
}
|
||||
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 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 ConnOpened(websocketpp::connection_hdl conn)
|
||||
{
|
||||
auto ptr = CreateWebSocksConn(conn, this);
|
||||
Parent->AddHandler(ptr);
|
||||
m_Conns.push_back(ptr);
|
||||
}
|
||||
|
||||
void Stop()
|
||||
{
|
||||
for(const auto & conn : m_Conns)
|
||||
conn->Close();
|
||||
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();
|
||||
}
|
||||
|
||||
m_Dest->Stop();
|
||||
m_Run = false;
|
||||
m_Server.stop();
|
||||
if(m_Thread) {
|
||||
m_Thread->join();
|
||||
delete m_Thread;
|
||||
}
|
||||
m_Thread = nullptr;
|
||||
}
|
||||
void Stop()
|
||||
{
|
||||
for(const auto & conn : m_Conns)
|
||||
conn->Close();
|
||||
|
||||
private:
|
||||
std::vector<WebSocksConn_ptr> m_Conns;
|
||||
bool m_Run;
|
||||
ServerImpl m_Server;
|
||||
std::string m_Addr;
|
||||
int m_Port;
|
||||
std::thread * m_Thread;
|
||||
Destination_t m_Dest;
|
||||
m_Dest->Stop();
|
||||
m_Run = false;
|
||||
m_Server.stop();
|
||||
if(m_Thread) {
|
||||
m_Thread->join();
|
||||
delete m_Thread;
|
||||
}
|
||||
m_Thread = nullptr;
|
||||
}
|
||||
|
||||
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<WebSocksConn_ptr> 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
|
||||
};
|
||||
struct WebSocksConn : public IWebSocksConn , public std::enable_shared_from_this<WebSocksConn>
|
||||
{
|
||||
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<ClientDestination> Destination_t;
|
||||
typedef std::shared_ptr<i2p::stream::StreamingDestination> StreamDest_t;
|
||||
typedef std::shared_ptr<i2p::stream::Stream> Stream_t;
|
||||
typedef WebSocksServerImpl ServerImpl;
|
||||
typedef ServerImpl::message_ptr Message_t;
|
||||
typedef websocketpp::connection_hdl ServerConn;
|
||||
typedef std::shared_ptr<ClientDestination> Destination_t;
|
||||
typedef std::shared_ptr<i2p::stream::StreamingDestination> StreamDest_t;
|
||||
typedef std::shared_ptr<i2p::stream::Stream> 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];
|
||||
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(const ServerConn & conn, WebSocksImpl * parent) :
|
||||
IWebSocksConn(parent->Parent),
|
||||
m_Conn(conn),
|
||||
m_Stream(nullptr),
|
||||
m_State(eWSCInitial),
|
||||
m_Parent(parent)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
~WebSocksConn()
|
||||
{
|
||||
Close();
|
||||
}
|
||||
~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 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");
|
||||
void StartForwarding()
|
||||
{
|
||||
LogPrint(eLogDebug, "websocks: begin forwarding data");
|
||||
uint8_t b[1];
|
||||
m_Stream->Send(b, 0);
|
||||
AsyncRecv();
|
||||
}
|
||||
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);
|
||||
|
||||
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);
|
||||
}
|
||||
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());
|
||||
}
|
||||
/** @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 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);
|
||||
}
|
||||
}
|
||||
} 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);
|
||||
}
|
||||
}
|
||||
};
|
||||
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<WebSocksConn>(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;
|
||||
}
|
||||
WebSocksConn_ptr CreateWebSocksConn(const websocketpp::connection_hdl & conn, WebSocksImpl * parent)
|
||||
{
|
||||
auto ptr = std::make_shared<WebSocksConn>(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<ClientDestination> 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
31
WebSocks.h
31
WebSocks.h
@ -1,27 +1,34 @@
|
||||
#ifndef WEBSOCKS_H_
|
||||
#define WEBSOCKS_H_
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#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<ClientDestination> 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
|
||||
|
@ -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
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user