Browse Source

ntcp socks proxy (initial)

pull/881/head
Jeff Becker 8 years ago
parent
commit
3ea1eca350
  1. 1
      daemon/Daemon.cpp
  2. 1
      libi2pd/Config.cpp
  3. 138
      libi2pd/NTCPSession.cpp
  4. 14
      libi2pd/NTCPSession.h
  5. 44
      libi2pd/Transports.cpp

1
daemon/Daemon.cpp

@ -263,6 +263,7 @@ namespace i2p
LogPrint(eLogInfo, "Daemon: starting Transports"); LogPrint(eLogInfo, "Daemon: starting Transports");
if(!ssu) LogPrint(eLogInfo, "Daemon: ssu disabled"); if(!ssu) LogPrint(eLogInfo, "Daemon: ssu disabled");
if(!ntcp) LogPrint(eLogInfo, "Daemon: ntcp disabled"); if(!ntcp) LogPrint(eLogInfo, "Daemon: ntcp disabled");
i2p::transport::transports.Start(ntcp, ssu); i2p::transport::transports.Start(ntcp, ssu);
if (i2p::transport::transports.IsBoundNTCP() || i2p::transport::transports.IsBoundSSU()) { if (i2p::transport::transports.IsBoundNTCP() || i2p::transport::transports.IsBoundSSU()) {
LogPrint(eLogInfo, "Daemon: Transports started"); LogPrint(eLogInfo, "Daemon: Transports started");

1
libi2pd/Config.cpp

@ -57,6 +57,7 @@ namespace config {
("share", value<int>()->default_value(100), "Limit of transit traffic from max bandwidth in percents. (default: 100") ("share", value<int>()->default_value(100), "Limit of transit traffic from max bandwidth in percents. (default: 100")
("ntcp", value<bool>()->zero_tokens()->default_value(true), "Enable NTCP transport") ("ntcp", value<bool>()->zero_tokens()->default_value(true), "Enable NTCP transport")
("ssu", value<bool>()->zero_tokens()->default_value(true), "Enable SSU transport") ("ssu", value<bool>()->zero_tokens()->default_value(true), "Enable SSU transport")
("ntcpproxy", value<std::string>()->default_value(""), "proxy url for ntcp transport")
#ifdef _WIN32 #ifdef _WIN32
("svcctl", value<std::string>()->default_value(""), "Windows service management ('install' or 'remove')") ("svcctl", value<std::string>()->default_value(""), "Windows service management ('install' or 'remove')")
("insomnia", value<bool>()->zero_tokens()->default_value(false), "Prevent system from sleeping") ("insomnia", value<bool>()->zero_tokens()->default_value(false), "Prevent system from sleeping")

138
libi2pd/NTCPSession.cpp

@ -788,7 +788,8 @@ namespace transport
//----------------------------------------- //-----------------------------------------
NTCPServer::NTCPServer (): NTCPServer::NTCPServer ():
m_IsRunning (false), m_Thread (nullptr), m_Work (m_Service), m_IsRunning (false), m_Thread (nullptr), m_Work (m_Service),
m_TerminationTimer (m_Service), m_NTCPAcceptor (nullptr), m_NTCPV6Acceptor (nullptr) m_TerminationTimer (m_Service), m_NTCPAcceptor (nullptr), m_NTCPV6Acceptor (nullptr),
m_UseSocks(false), m_Resolver(m_Service), m_SocksEndpoint(nullptr)
{ {
} }
@ -803,6 +804,23 @@ namespace transport
{ {
m_IsRunning = true; m_IsRunning = true;
m_Thread = new std::thread (std::bind (&NTCPServer::Run, this)); m_Thread = new std::thread (std::bind (&NTCPServer::Run, this));
// we are using a socks proxy, don't create any acceptors
if(m_UseSocks)
{
boost::asio::ip::tcp::resolver::query q(m_SocksAddress, std::to_string(m_SocksPort));
boost::system::error_code e;
auto itr = m_Resolver.resolve(q, e);
if(e)
{
LogPrint(eLogError, "NTCP: Failed to resolve proxy ", e.message());
}
else
{
m_SocksEndpoint = new boost::asio::ip::tcp::endpoint(*itr);
}
}
else
{
// create acceptors // create acceptors
auto& addresses = context.GetRouterInfo ().GetAddresses (); auto& addresses = context.GetRouterInfo ().GetAddresses ();
for (const auto& address: addresses) for (const auto& address: addresses)
@ -814,8 +832,7 @@ namespace transport
{ {
try try
{ {
m_NTCPAcceptor = new boost::asio::ip::tcp::acceptor (m_Service, m_NTCPAcceptor = new boost::asio::ip::tcp::acceptor (m_Service, boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), address->port));
boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), address->port));
} catch ( std::exception & ex ) { } catch ( std::exception & ex ) {
/** fail to bind ip4 */ /** fail to bind ip4 */
LogPrint(eLogError, "NTCP: Failed to bind to ip4 port ",address->port, ex.what()); LogPrint(eLogError, "NTCP: Failed to bind to ip4 port ",address->port, ex.what());
@ -824,8 +841,7 @@ namespace transport
LogPrint (eLogInfo, "NTCP: Start listening TCP port ", address->port); LogPrint (eLogInfo, "NTCP: Start listening TCP port ", address->port);
auto conn = std::make_shared<NTCPSession>(*this); auto conn = std::make_shared<NTCPSession>(*this);
m_NTCPAcceptor->async_accept(conn->GetSocket (), std::bind (&NTCPServer::HandleAccept, this, m_NTCPAcceptor->async_accept(conn->GetSocket (), std::bind (&NTCPServer::HandleAccept, this, conn, std::placeholders::_1));
conn, std::placeholders::_1));
} }
else if (address->host.is_v6() && context.SupportsV6 ()) else if (address->host.is_v6() && context.SupportsV6 ())
{ {
@ -834,14 +850,12 @@ namespace transport
{ {
m_NTCPV6Acceptor->open (boost::asio::ip::tcp::v6()); m_NTCPV6Acceptor->open (boost::asio::ip::tcp::v6());
m_NTCPV6Acceptor->set_option (boost::asio::ip::v6_only (true)); m_NTCPV6Acceptor->set_option (boost::asio::ip::v6_only (true));
m_NTCPV6Acceptor->bind (boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v6(), address->port)); m_NTCPV6Acceptor->bind (boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v6(), address->port));
m_NTCPV6Acceptor->listen (); m_NTCPV6Acceptor->listen ();
LogPrint (eLogInfo, "NTCP: Start listening V6 TCP port ", address->port); LogPrint (eLogInfo, "NTCP: Start listening V6 TCP port ", address->port);
auto conn = std::make_shared<NTCPSession> (*this); auto conn = std::make_shared<NTCPSession> (*this);
m_NTCPV6Acceptor->async_accept(conn->GetSocket (), std::bind (&NTCPServer::HandleAcceptV6, m_NTCPV6Acceptor->async_accept(conn->GetSocket (), std::bind (&NTCPServer::HandleAcceptV6, this, conn, std::placeholders::_1));
this, conn, std::placeholders::_1));
} catch ( std::exception & ex ) { } catch ( std::exception & ex ) {
LogPrint(eLogError, "NTCP: failed to bind to ip6 port ", address->port); LogPrint(eLogError, "NTCP: failed to bind to ip6 port ", address->port);
continue; continue;
@ -849,6 +863,7 @@ namespace transport
} }
} }
} }
}
ScheduleTermination (); ScheduleTermination ();
} }
} }
@ -886,6 +901,11 @@ namespace transport
delete m_Thread; delete m_Thread;
m_Thread = nullptr; m_Thread = nullptr;
} }
if(m_SocksEndpoint)
{
delete m_SocksEndpoint;
m_SocksEndpoint = nullptr;
}
} }
} }
@ -989,25 +1009,50 @@ namespace transport
} }
} }
void NTCPServer::Connect (const boost::asio::ip::address& address, int port, std::shared_ptr<NTCPSession> conn) void NTCPServer::Connect(const boost::asio::ip::address & address, uint16_t port, std::shared_ptr<NTCPSession> conn)
{ {
LogPrint (eLogDebug, "NTCP: Connecting to ", address ,":", port); LogPrint (eLogDebug, "NTCP: Connecting to ", address ,":", port);
m_Service.post([=]() m_Service.post([&]() {
{
if (this->AddNTCPSession (conn)) if (this->AddNTCPSession (conn))
{ {
auto timer = std::make_shared<boost::asio::deadline_timer>(m_Service); auto timer = std::make_shared<boost::asio::deadline_timer>(m_Service);
timer->expires_from_now (boost::posix_time::seconds(NTCP_CONNECT_TIMEOUT)); timer->expires_from_now (boost::posix_time::seconds(NTCP_CONNECT_TIMEOUT));
timer->async_wait ([conn](const boost::system::error_code& ecode) timer->async_wait ([conn](const boost::system::error_code& ecode) {
{
if (ecode != boost::asio::error::operation_aborted) if (ecode != boost::asio::error::operation_aborted)
{ {
LogPrint (eLogInfo, "NTCP: Not connected in ", NTCP_CONNECT_TIMEOUT, " seconds"); LogPrint (eLogInfo, "NTCP: Not connected in ", NTCP_CONNECT_TIMEOUT, " seconds");
conn->Terminate (); conn->Terminate ();
} }
}); });
conn->GetSocket ().async_connect (boost::asio::ip::tcp::endpoint (address, port), conn->GetSocket ().async_connect (boost::asio::ip::tcp::endpoint (address, port), std::bind (&NTCPServer::HandleConnect, this, std::placeholders::_1, conn, timer));
std::bind (&NTCPServer::HandleConnect, this, std::placeholders::_1, conn, timer)); }
});
}
void NTCPServer::ConnectSocks (const std::string& host, uint16_t port, std::shared_ptr<NTCPSession> conn)
{
if(m_SocksEndpoint == nullptr)
{
return;
}
LogPrint (eLogDebug, "NTCP: Connecting to ", host ,":", port, " Via socks proxy");
m_Service.post([=]() {
if (this->AddNTCPSession (conn))
{
auto timer = std::make_shared<boost::asio::deadline_timer>(m_Service);
auto timeout = NTCP_CONNECT_TIMEOUT * 2;
timer->expires_from_now (boost::posix_time::seconds(timeout));
timer->async_wait ([conn, timeout](const boost::system::error_code& ecode) {
if (ecode != boost::asio::error::operation_aborted)
{
LogPrint (eLogInfo, "NTCP: Not connected in ", timeout, " seconds");
i2p::data::netdb.SetUnreachable (conn->GetRemoteIdentity ()->GetIdentHash (), true);
conn->Terminate ();
}
});
conn->GetSocket ().async_connect (*m_SocksEndpoint, std::bind (&NTCPServer::HandleSocksConnect, this, std::placeholders::_1, conn, timer, host, port));
} }
}); });
} }
@ -1031,6 +1076,66 @@ namespace transport
} }
} }
void NTCPServer::UseSocksProxy(const std::string & addr, uint16_t port)
{
m_UseSocks = true;
m_SocksAddress = addr;
m_SocksPort = port;
}
void NTCPServer::HandleSocksConnect(const boost::system::error_code& ecode, std::shared_ptr<NTCPSession> conn, std::shared_ptr<boost::asio::deadline_timer> timer, const std::string & host, uint16_t port)
{
if(ecode)
{
LogPrint(eLogInfo, "NTCP: Socks Proxy connect error ", ecode.message());
return;
}
LogPrint(eLogDebug, "NTCP: connecting via socks proxy to ",host, ":", port);
uint8_t readbuff[8];
// build socks4a request
size_t addrsz = host.size();
size_t sz = 8 + 1 + 4 + addrsz + 1;
uint8_t buff[256];
if(sz > 256)
{
// hostname too big
return;
}
buff[0] = 4;
buff[1] = 1;
htobe16buf(buff+2, port);
buff[4] = 0;
buff[5] = 0;
buff[6] = 0;
buff[7] = 1;
buff[8] = 105; // i
buff[9] = 50; // 2
buff[10] = 112; // p
buff[11] = 100; // d
buff[12] = 0;
memcpy(buff+12, host.c_str(), addrsz);
buff[12+addrsz] = 0;
boost::asio::async_write(conn->GetSocket(), boost::asio::buffer(buff, sz), boost::asio::transfer_all(), [&](const boost::system::error_code & ec, std::size_t written) {
if(ec)
{
LogPrint(eLogError, "NTCP: failed to write handshake to socks proxy ", ec.message());
return;
}
});
boost::asio::async_read(conn->GetSocket(), boost::asio::buffer(readbuff, 8), [&](const boost::system::error_code & e, std::size_t transferred) {
if(transferred == 8 && readbuff[1] == 0x5a)
{
timer->cancel();
conn->ClientLogin();
LogPrint(eLogDebug, "NTCP: connected via socks");
}
else
LogPrint(eLogDebug, "NTCP: connection via socks failed");
});
}
void NTCPServer::ScheduleTermination () void NTCPServer::ScheduleTermination ()
{ {
m_TerminationTimer.expires_from_now (boost::posix_time::seconds(NTCP_TERMINATION_CHECK_TIMEOUT)); m_TerminationTimer.expires_from_now (boost::posix_time::seconds(NTCP_TERMINATION_CHECK_TIMEOUT));
@ -1049,8 +1154,7 @@ namespace transport
{ {
auto session = it.second; auto session = it.second;
// Termniate modifies m_NTCPSession, so we postpone it // Termniate modifies m_NTCPSession, so we postpone it
m_Service.post ([session] m_Service.post ([session] {
{
LogPrint (eLogDebug, "NTCP: No activity for ", session->GetTerminationTimeout (), " seconds"); LogPrint (eLogDebug, "NTCP: No activity for ", session->GetTerminationTimeout (), " seconds");
session->Terminate (); session->Terminate ();
}); });

14
libi2pd/NTCPSession.h

@ -140,10 +140,15 @@ namespace transport
bool AddNTCPSession (std::shared_ptr<NTCPSession> session); bool AddNTCPSession (std::shared_ptr<NTCPSession> session);
void RemoveNTCPSession (std::shared_ptr<NTCPSession> session); void RemoveNTCPSession (std::shared_ptr<NTCPSession> session);
std::shared_ptr<NTCPSession> FindNTCPSession (const i2p::data::IdentHash& ident); std::shared_ptr<NTCPSession> FindNTCPSession (const i2p::data::IdentHash& ident);
void Connect (const boost::asio::ip::address& address, int port, std::shared_ptr<NTCPSession> conn); void ConnectSocks (const std::string& addr, uint16_t port, std::shared_ptr<NTCPSession> conn);
void Connect(const boost::asio::ip::address & address, uint16_t port, std::shared_ptr<NTCPSession> conn);
bool IsBoundV4() const { return m_NTCPAcceptor != nullptr; }; bool IsBoundV4() const { return m_NTCPAcceptor != nullptr; };
bool IsBoundV6() const { return m_NTCPV6Acceptor != nullptr; }; bool IsBoundV6() const { return m_NTCPV6Acceptor != nullptr; };
bool NetworkIsReady() const { return IsBoundV4() || IsBoundV6() || m_UseSocks; };
bool UsingSocksProxy() const { return m_UseSocks; };
void UseSocksProxy(const std::string & address, uint16_t port);
boost::asio::io_service& GetService () { return m_Service; }; boost::asio::io_service& GetService () { return m_Service; };
@ -155,6 +160,8 @@ namespace transport
void HandleConnect (const boost::system::error_code& ecode, std::shared_ptr<NTCPSession> conn, std::shared_ptr<boost::asio::deadline_timer> timer); void HandleConnect (const boost::system::error_code& ecode, std::shared_ptr<NTCPSession> conn, std::shared_ptr<boost::asio::deadline_timer> timer);
void HandleSocksConnect(const boost::system::error_code& ecode, std::shared_ptr<NTCPSession> conn, std::shared_ptr<boost::asio::deadline_timer> timer, const std::string & host, uint16_t port);
// timer // timer
void ScheduleTermination (); void ScheduleTermination ();
void HandleTerminationTimer (const boost::system::error_code& ecode); void HandleTerminationTimer (const boost::system::error_code& ecode);
@ -170,6 +177,11 @@ namespace transport
std::map<i2p::data::IdentHash, std::shared_ptr<NTCPSession> > m_NTCPSessions; // access from m_Thread only std::map<i2p::data::IdentHash, std::shared_ptr<NTCPSession> > m_NTCPSessions; // access from m_Thread only
std::list<std::shared_ptr<NTCPSession> > m_PendingIncomingSessions; std::list<std::shared_ptr<NTCPSession> > m_PendingIncomingSessions;
bool m_UseSocks;
std::string m_SocksAddress;
uint16_t m_SocksPort;
boost::asio::ip::tcp::resolver m_Resolver;
boost::asio::ip::tcp::endpoint * m_SocksEndpoint;
public: public:
// for HTTP/I2PControl // for HTTP/I2PControl

44
libi2pd/Transports.cpp

@ -5,6 +5,7 @@
#include "NetDb.hpp" #include "NetDb.hpp"
#include "Transports.h" #include "Transports.h"
#include "Config.h" #include "Config.h"
#include "HTTP.h"
#ifdef WITH_EVENTS #ifdef WITH_EVENTS
#include "Event.h" #include "Event.h"
#include "util.h" #include "util.h"
@ -144,6 +145,34 @@ namespace transport
m_DHKeysPairSupplier.Start (); m_DHKeysPairSupplier.Start ();
m_IsRunning = true; m_IsRunning = true;
m_Thread = new std::thread (std::bind (&Transports::Run, this)); m_Thread = new std::thread (std::bind (&Transports::Run, this));
std::string ntcpproxy; i2p::config::GetOption("ntcpproxy", ntcpproxy);
i2p::http::URL proxyurl;
if(ntcpproxy.size() && enableNTCP)
{
if(proxyurl.parse(ntcpproxy))
{
if(proxyurl.schema == "socks")
{
m_NTCPServer = new NTCPServer();
m_NTCPServer->UseSocksProxy(proxyurl.host, proxyurl.port) ;
m_NTCPServer->Start();
if(!m_NTCPServer->NetworkIsReady())
{
LogPrint(eLogError, "Transports: NTCP failed to start with socks proxy");
m_NTCPServer->Stop();
delete m_NTCPServer;
m_NTCPServer = nullptr;
}
}
else
LogPrint(eLogError, "Transports: unsupported NTCP proxy URL ", ntcpproxy);
}
else
LogPrint(eLogError, "Transports: invalid NTCP proxy url ", ntcpproxy);
return;
}
// create acceptors // create acceptors
auto& addresses = context.GetRouterInfo ().GetAddresses (); auto& addresses = context.GetRouterInfo ().GetAddresses ();
for (const auto& address : addresses) for (const auto& address : addresses)
@ -350,6 +379,12 @@ namespace transport
if (!peer.router->UsesIntroducer () && !peer.router->IsUnreachable ()) if (!peer.router->UsesIntroducer () && !peer.router->IsUnreachable ())
{ {
auto s = std::make_shared<NTCPSession> (*m_NTCPServer, peer.router); auto s = std::make_shared<NTCPSession> (*m_NTCPServer, peer.router);
if(m_NTCPServer->UsingSocksProxy())
{
std::string addr = address->host.to_string();
m_NTCPServer->ConnectSocks(addr, address->port, s);
}
else
m_NTCPServer->Connect (address->host, address->port, s); m_NTCPServer->Connect (address->host, address->port, s);
return true; return true;
} }
@ -357,9 +392,17 @@ namespace transport
else // we don't have address else // we don't have address
{ {
if (address->addressString.length () > 0) // trying to resolve if (address->addressString.length () > 0) // trying to resolve
{
if(m_NTCPServer->UsingSocksProxy())
{
auto s = std::make_shared<NTCPSession> (*m_NTCPServer, peer.router);
m_NTCPServer->ConnectSocks(address->addressString, address->port, s);
}
else
{ {
LogPrint (eLogDebug, "Transports: Resolving NTCP ", address->addressString); LogPrint (eLogDebug, "Transports: Resolving NTCP ", address->addressString);
NTCPResolve (address->addressString, ident); NTCPResolve (address->addressString, ident);
}
return true; return true;
} }
} }
@ -814,4 +857,3 @@ namespace transport
} }
} }
} }

Loading…
Cancel
Save