Browse Source

* add websocks

* enable socks, websocks and httpproxy as client tunnels

* remove old websocks config
pull/771/head
Jeff Becker 8 years ago
parent
commit
c5d3c0c6f8
  1. 46
      ClientContext.cpp
  2. 5
      ClientContext.h
  3. 7
      Config.cpp
  4. 11
      Daemon.cpp
  5. 5
      I2PService.h
  6. 679
      WebSocks.cpp
  7. 31
      WebSocks.h
  8. 3
      android/jni/Android.mk

46
ClientContext.cpp

@ -8,6 +8,8 @@
#include "Identity.h" #include "Identity.h"
#include "util.h" #include "util.h"
#include "ClientContext.h" #include "ClientContext.h"
#include "SOCKS.h"
#include "WebSocks.h"
namespace i2p namespace i2p
{ {
@ -424,7 +426,11 @@ namespace client
try try
{ {
std::string type = section.second.get<std::string> (I2P_TUNNELS_SECTION_TYPE); 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 // mandatory params
std::string dest = section.second.get<std::string> (I2P_CLIENT_TUNNEL_DESTINATION); 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"); LogPrint(eLogError, "Clients: I2P Client forward for endpoint ", end, " already exists");
} else { } else {
// tcp client boost::asio::ip::tcp::endpoint clientEndpoint;
auto clientTunnel = new I2PClientTunnel (name, dest, address, port, localDestination, destinationPort); I2PService * clientTunnel = nullptr;
if (m_ClientTunnels.insert (std::make_pair (clientTunnel->GetAcceptor ().local_endpoint (), if (type == I2P_TUNNELS_SECTION_TYPE_SOCKS)
std::unique_ptr<I2PClientTunnel>(clientTunnel))).second) {
// 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 (); clientTunnel->Start ();
numClientTunnels++; numClientTunnels++;
} }
else 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 // mandatory params
std::string host = section.second.get<std::string> (I2P_SERVER_TUNNEL_HOST); std::string host = section.second.get<std::string> (I2P_SERVER_TUNNEL_HOST);

5
ClientContext.h

@ -26,6 +26,9 @@ namespace client
const char I2P_TUNNELS_SECTION_TYPE_IRC[] = "irc"; const char I2P_TUNNELS_SECTION_TYPE_IRC[] = "irc";
const char I2P_TUNNELS_SECTION_TYPE_UDPCLIENT[] = "udpclient"; const char I2P_TUNNELS_SECTION_TYPE_UDPCLIENT[] = "udpclient";
const char I2P_TUNNELS_SECTION_TYPE_UDPSERVER[] = "udpserver"; 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_PORT[] = "port";
const char I2P_CLIENT_TUNNEL_ADDRESS[] = "address"; const char I2P_CLIENT_TUNNEL_ADDRESS[] = "address";
const char I2P_CLIENT_TUNNEL_DESTINATION[] = "destination"; const char I2P_CLIENT_TUNNEL_DESTINATION[] = "destination";
@ -93,7 +96,7 @@ namespace client
i2p::proxy::HTTPProxy * m_HttpProxy; i2p::proxy::HTTPProxy * m_HttpProxy;
i2p::proxy::SOCKSProxy * m_SocksProxy; 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::map<std::pair<i2p::data::IdentHash, int>, std::unique_ptr<I2PServerTunnel> > m_ServerTunnels; // <destination,port>->tunnel
std::mutex m_ForwardsMutex; std::mutex m_ForwardsMutex;

7
Config.cpp

@ -203,12 +203,6 @@ namespace config {
("websockets.address", value<std::string>()->default_value("127.0.0.1"), "address to bind websocket server on") ("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"); ("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 m_OptionsDesc
.add(general) .add(general)
.add(limits) .add(limits)
@ -225,7 +219,6 @@ namespace config {
.add(addressbook) .add(addressbook)
.add(trust) .add(trust)
.add(websocket) .add(websocket)
.add(websocks)
; ;
} }

11
Daemon.cpp

@ -27,7 +27,6 @@
#include "Event.h" #include "Event.h"
#include "Websocket.h" #include "Websocket.h"
#include "WebSocks.h"
namespace i2p namespace i2p
{ {
@ -44,7 +43,6 @@ namespace i2p
std::unique_ptr<i2p::transport::UPnP> UPnP; std::unique_ptr<i2p::transport::UPnP> UPnP;
#ifdef WITH_EVENTS #ifdef WITH_EVENTS
std::unique_ptr<i2p::event::WebsocketServer> m_WebsocketServer; std::unique_ptr<i2p::event::WebsocketServer> m_WebsocketServer;
std::unique_ptr<i2p::client::WebSocks> m_WebSocksServer;
#endif #endif
}; };
@ -309,15 +307,6 @@ namespace i2p
d.m_WebsocketServer->Start(); d.m_WebsocketServer->Start();
i2p::event::core.SetListener(d.m_WebsocketServer->ToListener()); 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 #endif
return true; return true;
} }

5
I2PService.h

@ -121,10 +121,11 @@ namespace client
void Stop (); void Stop ();
const boost::asio::ip::tcp::acceptor& GetAcceptor () const { return m_Acceptor; }; const boost::asio::ip::tcp::acceptor& GetAcceptor () const { return m_Acceptor; };
virtual const char* GetName() { return "Generic TCP/IP accepting daemon"; }
protected: protected:
virtual std::shared_ptr<I2PServiceHandler> CreateHandler(std::shared_ptr<boost::asio::ip::tcp::socket> socket) = 0; 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: private:
void Accept(); void Accept();
void HandleAccept(const boost::system::error_code& ecode, std::shared_ptr<boost::asio::ip::tcp::socket> socket); void HandleAccept(const boost::system::error_code& ecode, std::shared_ptr<boost::asio::ip::tcp::socket> socket);

679
WebSocks.cpp

@ -22,254 +22,273 @@ namespace i2p
{ {
namespace client 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 struct IWebSocksConn : public I2PServiceHandler
{ {
virtual void Close() = 0; IWebSocksConn(I2PService * parent) : I2PServiceHandler(parent) {}
virtual void GotMessage(const websocketpp::connection_hdl & conn, WebSocksServerImpl::message_ptr msg) = 0; 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 class WebSocksImpl
{ {
typedef std::mutex mutex_t; typedef std::mutex mutex_t;
typedef std::unique_lock<mutex_t> lock_t; typedef std::unique_lock<mutex_t> lock_t;
typedef std::shared_ptr<ClientDestination> Destination_t; typedef std::shared_ptr<ClientDestination> Destination_t;
public: public:
typedef WebSocksServerImpl ServerImpl; typedef WebSocksServerImpl ServerImpl;
typedef ServerImpl::message_ptr MessagePtr; typedef ServerImpl::message_ptr MessagePtr;
WebSocksImpl(const std::string & addr, int port) : WebSocksImpl(const std::string & addr, int port) :
m_Run(false), Parent(nullptr),
m_Addr(addr), m_Run(false),
m_Port(port), m_Addr(addr),
m_Thread(nullptr) 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(); for(const auto & conn : m_Conns)
m_Server.set_open_handler(std::bind(&WebSocksImpl::ConnOpened, this, std::placeholders::_1)); conn->Close();
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_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) boost::asio::ip::tcp::endpoint GetLocalEndpoint()
{ {
return m_Server.get_con_from_hdl(conn); return boost::asio::ip::tcp::endpoint(boost::asio::ip::address::from_string(m_Addr), m_Port);
} }
void CloseConn(const websocketpp::connection_hdl & conn) WebSocks * Parent;
{
auto c = GetConn(conn); private:
if(c) c->close(websocketpp::close::status::normal, "closed"); std::vector<WebSocksConn_ptr> m_Conns;
} bool m_Run;
ServerImpl m_Server;
void CreateStreamTo(const std::string & addr, int port, StreamConnectFunc complete) std::string m_Addr;
{ int m_Port;
auto & addressbook = i2p::client::context.GetAddressBook(); std::thread * m_Thread;
i2p::data::IdentHash ident; Destination_t m_Dest;
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<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 struct WebSocksConn : public IWebSocksConn , public std::enable_shared_from_this<WebSocksConn>
{ {
enum ConnState enum ConnState
{ {
eWSCInitial, eWSCInitial,
eWSCTryConnect, eWSCTryConnect,
eWSCFailConnect, eWSCFailConnect,
eWSCOkayConnect, eWSCOkayConnect,
eWSCClose, eWSCClose,
eWSCEnd eWSCEnd
}; };
typedef WebSocksServerImpl ServerImpl; typedef WebSocksServerImpl ServerImpl;
typedef ServerImpl::message_ptr Message_t; typedef ServerImpl::message_ptr Message_t;
typedef websocketpp::connection_hdl ServerConn; typedef websocketpp::connection_hdl ServerConn;
typedef std::shared_ptr<ClientDestination> Destination_t; typedef std::shared_ptr<ClientDestination> Destination_t;
typedef std::shared_ptr<i2p::stream::StreamingDestination> StreamDest_t; typedef std::shared_ptr<i2p::stream::StreamingDestination> StreamDest_t;
typedef std::shared_ptr<i2p::stream::Stream> Stream_t; typedef std::shared_ptr<i2p::stream::Stream> Stream_t;
ServerConn m_Conn; ServerConn m_Conn;
Stream_t m_Stream; Stream_t m_Stream;
ConnState m_State; ConnState m_State;
WebSocksImpl * m_Parent; WebSocksImpl * m_Parent;
std::string m_RemoteAddr; std::string m_RemoteAddr;
int m_RemotePort; int m_RemotePort;
uint8_t m_RecvBuf[2048]; uint8_t m_RecvBuf[2048];
WebSocksConn(const ServerConn & conn, WebSocksImpl * parent) : WebSocksConn(const ServerConn & conn, WebSocksImpl * parent) :
m_Conn(conn), IWebSocksConn(parent->Parent),
m_Stream(nullptr), m_Conn(conn),
m_State(eWSCInitial), m_Stream(nullptr),
m_Parent(parent) m_State(eWSCInitial),
{ m_Parent(parent)
{
}
}
~WebSocksConn()
{ ~WebSocksConn()
Close(); {
} Close();
}
void EnterState(ConnState state)
{ void EnterState(ConnState state)
LogPrint(eLogDebug, "websocks: state ", m_State, " -> ", state); {
switch(m_State) LogPrint(eLogDebug, "websocks: state ", m_State, " -> ", state);
{ switch(m_State)
case eWSCInitial: {
if (state == eWSCClose) { case eWSCInitial:
m_State = eWSCClose; if (state == eWSCClose) {
// connection was opened but never used m_State = eWSCClose;
LogPrint(eLogInfo, "websocks: connection closed but never used"); // connection was opened but never used
Close(); LogPrint(eLogInfo, "websocks: connection closed but never used");
return; Close();
} else if (state == eWSCTryConnect) { return;
// we will try to connect } else if (state == eWSCTryConnect) {
m_State = eWSCTryConnect; // we will try to connect
m_Parent->CreateStreamTo(m_RemoteAddr, m_RemotePort, std::bind(&WebSocksConn::ConnectResult, this, std::placeholders::_1)); m_State = eWSCTryConnect;
} else { m_Parent->CreateStreamTo(m_RemoteAddr, m_RemotePort, std::bind(&WebSocksConn::ConnectResult, this, std::placeholders::_1));
LogPrint(eLogWarning, "websocks: invalid state change ", m_State, " -> ", state); } else {
} LogPrint(eLogWarning, "websocks: invalid state change ", m_State, " -> ", state);
return; }
case eWSCTryConnect: return;
if(state == eWSCOkayConnect) { case eWSCTryConnect:
// we connected okay if(state == eWSCOkayConnect) {
LogPrint(eLogDebug, "websocks: connected to ", m_RemoteAddr, ":", m_RemotePort); // we connected okay
SendResponse(""); LogPrint(eLogDebug, "websocks: connected to ", m_RemoteAddr, ":", m_RemotePort);
m_State = eWSCOkayConnect; SendResponse("");
} else if(state == eWSCFailConnect) { m_State = eWSCOkayConnect;
// we did not connect okay } else if(state == eWSCFailConnect) {
LogPrint(eLogDebug, "websocks: failed to connect to ", m_RemoteAddr, ":", m_RemotePort); // we did not connect okay
SendResponse("failed to connect"); LogPrint(eLogDebug, "websocks: failed to connect to ", m_RemoteAddr, ":", m_RemotePort);
m_State = eWSCFailConnect; SendResponse("failed to connect");
EnterState(eWSCInitial); m_State = eWSCFailConnect;
} else if(state == eWSCClose) { EnterState(eWSCInitial);
// premature close } else if(state == eWSCClose) {
LogPrint(eLogWarning, "websocks: websocket connection closed prematurely"); // premature close
m_State = eWSCClose; LogPrint(eLogWarning, "websocks: websocket connection closed prematurely");
} else { m_State = eWSCClose;
LogPrint(eLogWarning, "websocks: invalid state change ", m_State, " -> ", state); } else {
} LogPrint(eLogWarning, "websocks: invalid state change ", m_State, " -> ", state);
return; }
case eWSCFailConnect: return;
if (state == eWSCInitial) { case eWSCFailConnect:
// reset to initial state so we can try connecting again if (state == eWSCInitial) {
m_RemoteAddr = ""; // reset to initial state so we can try connecting again
m_RemotePort = 0; m_RemoteAddr = "";
LogPrint(eLogDebug, "websocks: reset websocket conn to initial state"); m_RemotePort = 0;
m_State = eWSCInitial; LogPrint(eLogDebug, "websocks: reset websocket conn to initial state");
} else if (state == eWSCClose) { m_State = eWSCInitial;
// we are going to close the connection } else if (state == eWSCClose) {
m_State = eWSCClose; // we are going to close the connection
Close(); m_State = eWSCClose;
} else { Close();
LogPrint(eLogWarning, "websocks: invalid state change ", m_State, " -> ", state); } else {
} LogPrint(eLogWarning, "websocks: invalid state change ", m_State, " -> ", state);
return; }
case eWSCOkayConnect: return;
if(state == eWSCClose) { case eWSCOkayConnect:
// graceful close if(state == eWSCClose) {
m_State = eWSCClose; // graceful close
Close(); m_State = eWSCClose;
} else { Close();
LogPrint(eLogWarning, "websocks: invalid state change ", m_State, " -> ", state); } else {
} LogPrint(eLogWarning, "websocks: invalid state change ", m_State, " -> ", state);
case eWSCClose: }
if(state == eWSCEnd) { case eWSCClose:
LogPrint(eLogDebug, "websocks: socket ended"); if(state == eWSCEnd) {
} else { LogPrint(eLogDebug, "websocks: socket ended");
LogPrint(eLogWarning, "websocks: invalid state change ", m_State, " -> ", state); Kill();
} auto me = shared_from_this();
return; Done(me);
default: } else {
LogPrint(eLogError, "websocks: bad state ", m_State); LogPrint(eLogWarning, "websocks: invalid state change ", m_State, " -> ", state);
} }
} return;
default:
void StartForwarding() LogPrint(eLogError, "websocks: bad state ", m_State);
{ }
LogPrint(eLogDebug, "websocks: begin forwarding data"); }
void StartForwarding()
{
LogPrint(eLogDebug, "websocks: begin forwarding data");
uint8_t b[1]; uint8_t b[1];
m_Stream->Send(b, 0); m_Stream->Send(b, 0);
AsyncRecv(); AsyncRecv();
} }
void HandleAsyncRecv(const boost::system::error_code &ec, std::size_t n) void HandleAsyncRecv(const boost::system::error_code &ec, std::size_t n)
{ {
if(ec) { if(ec) {
// error // error
LogPrint(eLogWarning, "websocks: connection error ", ec.message()); LogPrint(eLogWarning, "websocks: connection error ", ec.message());
EnterState(eWSCClose); EnterState(eWSCClose);
} else { } else {
// forward data // forward data
LogPrint(eLogDebug, "websocks recv ", n); LogPrint(eLogDebug, "websocks recv ", n);
std::string str((char*)m_RecvBuf, n); std::string str((char*)m_RecvBuf, n);
auto conn = m_Parent->GetConn(m_Conn); auto conn = m_Parent->GetConn(m_Conn);
if(!conn) { if(!conn) {
LogPrint(eLogWarning, "websocks: connection is gone"); LogPrint(eLogWarning, "websocks: connection is gone");
EnterState(eWSCClose); EnterState(eWSCClose);
return; return;
@ -277,98 +296,98 @@ namespace client
conn->send(str); conn->send(str);
AsyncRecv(); AsyncRecv();
} }
} }
void AsyncRecv() void AsyncRecv()
{ {
m_Stream->AsyncReceive( m_Stream->AsyncReceive(
boost::asio::buffer(m_RecvBuf, sizeof(m_RecvBuf)), boost::asio::buffer(m_RecvBuf, sizeof(m_RecvBuf)),
std::bind(&WebSocksConn::HandleAsyncRecv, this, std::placeholders::_1, std::placeholders::_2), 60); std::bind(&WebSocksConn::HandleAsyncRecv, this, std::placeholders::_1, std::placeholders::_2), 60);
} }
/** @brief send error message or empty string for success */ /** @brief send error message or empty string for success */
void SendResponse(const std::string & errormsg) void SendResponse(const std::string & errormsg)
{ {
boost::property_tree::ptree resp; boost::property_tree::ptree resp;
if(errormsg.size()) { if(errormsg.size()) {
resp.put("error", errormsg); resp.put("error", errormsg);
resp.put("success", 0); resp.put("success", 0);
} else { } else {
resp.put("success", 1); resp.put("success", 1);
} }
std::ostringstream ss; std::ostringstream ss;
write_json(ss, resp); write_json(ss, resp);
auto conn = m_Parent->GetConn(m_Conn); auto conn = m_Parent->GetConn(m_Conn);
if(conn) conn->send(ss.str()); if(conn) conn->send(ss.str());
} }
void ConnectResult(Stream_t stream) void ConnectResult(Stream_t stream)
{ {
m_Stream = stream; m_Stream = stream;
if(m_State == eWSCClose) { if(m_State == eWSCClose) {
// premature close of websocket // premature close of websocket
Close(); Close();
return; return;
} }
if(m_Stream) { if(m_Stream) {
// connect good // connect good
EnterState(eWSCOkayConnect); EnterState(eWSCOkayConnect);
StartForwarding(); StartForwarding();
} else { } else {
// connect failed // connect failed
EnterState(eWSCFailConnect); EnterState(eWSCFailConnect);
} }
} }
virtual void GotMessage(const websocketpp::connection_hdl & conn, WebSocksServerImpl::message_ptr msg) virtual void GotMessage(const websocketpp::connection_hdl & conn, WebSocksServerImpl::message_ptr msg)
{ {
(void) conn; (void) conn;
std::string payload = msg->get_payload(); std::string payload = msg->get_payload();
if(m_State == eWSCOkayConnect) if(m_State == eWSCOkayConnect)
{ {
// forward to server // forward to server
LogPrint(eLogDebug, "websocks: forward ", payload.size()); LogPrint(eLogDebug, "websocks: forward ", payload.size());
m_Stream->Send((uint8_t*)payload.c_str(), payload.size()); m_Stream->Send((uint8_t*)payload.c_str(), payload.size());
} else if (m_State == eWSCInitial) { } else if (m_State == eWSCInitial) {
// recv connect request // recv connect request
auto itr = payload.find(":"); auto itr = payload.find(":");
if(itr == std::string::npos) { if(itr == std::string::npos) {
// no port // no port
m_RemotePort = 0; m_RemotePort = 0;
m_RemoteAddr = payload; m_RemoteAddr = payload;
} else { } else {
// includes port // includes port
m_RemotePort = std::stoi(payload.substr(itr+1)); m_RemotePort = std::stoi(payload.substr(itr+1));
m_RemoteAddr = payload.substr(0, itr); m_RemoteAddr = payload.substr(0, itr);
} }
EnterState(eWSCTryConnect); EnterState(eWSCTryConnect);
} else { } else {
// wtf? // wtf?
LogPrint(eLogWarning, "websocks: got message in invalid state ", m_State); LogPrint(eLogWarning, "websocks: got message in invalid state ", m_State);
} }
} }
virtual void Close() virtual void Close()
{ {
if(m_State == eWSCClose) { if(m_State == eWSCClose) {
LogPrint(eLogDebug, "websocks: closing connection"); LogPrint(eLogDebug, "websocks: closing connection");
if(m_Stream) m_Stream->Close(); if(m_Stream) m_Stream->Close();
m_Parent->CloseConn(m_Conn); m_Parent->CloseConn(m_Conn);
EnterState(eWSCEnd); EnterState(eWSCEnd);
} else { } else {
EnterState(eWSCClose); EnterState(eWSCClose);
} }
} }
}; };
WebSocksConn_ptr CreateWebSocksConn(const websocketpp::connection_hdl & conn, WebSocksImpl * parent) WebSocksConn_ptr CreateWebSocksConn(const websocketpp::connection_hdl & conn, WebSocksImpl * parent)
{ {
auto ptr = std::make_shared<WebSocksConn>(conn, parent); auto ptr = std::make_shared<WebSocksConn>(conn, parent);
auto c = parent->GetConn(conn); auto c = parent->GetConn(conn);
c->set_message_handler(std::bind(&WebSocksConn::GotMessage, ptr.get(), std::placeholders::_1, std::placeholders::_2)); c->set_message_handler(std::bind(&WebSocksConn::GotMessage, ptr.get(), std::placeholders::_1, std::placeholders::_2));
return ptr; return ptr;
} }
} }
} }
@ -383,7 +402,7 @@ namespace client
class WebSocksImpl class WebSocksImpl
{ {
public: 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 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 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; } WebSocks::~WebSocks() { delete m_Impl; }
void WebSocks::Start() void WebSocks::Start()
{ {
m_Impl->Start(); m_Impl->Start();
GetLocalDestination()->Start();
}
boost::asio::ip::tcp::endpoint WebSocks::GetLocalEndpoint() const
{
return m_Impl->GetLocalEndpoint();
} }
void WebSocks::Stop() void WebSocks::Stop()
{ {
m_Impl->Stop(); m_Impl->Stop();
GetLocalDestination()->Stop();
} }
} }
} }

31
WebSocks.h

@ -1,27 +1,34 @@
#ifndef WEBSOCKS_H_ #ifndef WEBSOCKS_H_
#define WEBSOCKS_H_ #define WEBSOCKS_H_
#include <string> #include <string>
#include <memory>
#include "I2PService.h"
#include "Destination.h"
namespace i2p namespace i2p
{ {
namespace client namespace client
{ {
class WebSocksImpl; class WebSocksImpl;
/** @brief websocket socks proxy server */ /** @brief websocket socks proxy server */
class WebSocks class WebSocks : public i2p::client::I2PService
{ {
public: public:
WebSocks(const std::string & addr, int port); WebSocks(const std::string & addr, int port, std::shared_ptr<ClientDestination> localDestination);
~WebSocks(); ~WebSocks();
void Start(); void Start();
void Stop(); void Stop();
private: boost::asio::ip::tcp::endpoint GetLocalEndpoint() const;
WebSocksImpl * m_Impl;
}; const char * GetName() { return "WebSOCKS Proxy"; }
private:
WebSocksImpl * m_Impl;
};
} }
} }
#endif #endif

3
android/jni/Android.mk

@ -59,7 +59,8 @@ LOCAL_SRC_FILES := DaemonAndroid.cpp i2pd_android.cpp \
../../TunnelPool.cpp \ ../../TunnelPool.cpp \
../../Timestamp.cpp \ ../../Timestamp.cpp \
../../Event.cpp \ ../../Event.cpp \
../../BloomFilter.cpp \ ../../WebSocks.cpp \
../../BloomFilter.cpp \
../../util.cpp \ ../../util.cpp \
../../i2pd.cpp ../../UPnP.cpp ../../i2pd.cpp ../../UPnP.cpp

Loading…
Cancel
Save