|
|
|
@ -788,7 +788,8 @@ namespace transport
@@ -788,7 +788,8 @@ namespace transport
|
|
|
|
|
//-----------------------------------------
|
|
|
|
|
NTCPServer::NTCPServer (): |
|
|
|
|
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
@@ -803,6 +804,23 @@ namespace transport
|
|
|
|
|
{ |
|
|
|
|
m_IsRunning = true; |
|
|
|
|
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
|
|
|
|
|
auto& addresses = context.GetRouterInfo ().GetAddresses (); |
|
|
|
|
for (const auto& address: addresses) |
|
|
|
@ -814,8 +832,7 @@ namespace transport
@@ -814,8 +832,7 @@ namespace transport
|
|
|
|
|
{ |
|
|
|
|
try |
|
|
|
|
{ |
|
|
|
|
m_NTCPAcceptor = new boost::asio::ip::tcp::acceptor (m_Service, |
|
|
|
|
boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), address->port)); |
|
|
|
|
m_NTCPAcceptor = new boost::asio::ip::tcp::acceptor (m_Service, boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), address->port)); |
|
|
|
|
} catch ( std::exception & ex ) { |
|
|
|
|
/** fail to bind ip4 */ |
|
|
|
|
LogPrint(eLogError, "NTCP: Failed to bind to ip4 port ",address->port, ex.what()); |
|
|
|
@ -824,8 +841,7 @@ namespace transport
@@ -824,8 +841,7 @@ namespace transport
|
|
|
|
|
|
|
|
|
|
LogPrint (eLogInfo, "NTCP: Start listening TCP port ", address->port); |
|
|
|
|
auto conn = std::make_shared<NTCPSession>(*this); |
|
|
|
|
m_NTCPAcceptor->async_accept(conn->GetSocket (), std::bind (&NTCPServer::HandleAccept, this, |
|
|
|
|
conn, std::placeholders::_1)); |
|
|
|
|
m_NTCPAcceptor->async_accept(conn->GetSocket (), std::bind (&NTCPServer::HandleAccept, this, conn, std::placeholders::_1)); |
|
|
|
|
} |
|
|
|
|
else if (address->host.is_v6() && context.SupportsV6 ()) |
|
|
|
|
{ |
|
|
|
@ -834,14 +850,12 @@ namespace transport
@@ -834,14 +850,12 @@ namespace transport
|
|
|
|
|
{ |
|
|
|
|
m_NTCPV6Acceptor->open (boost::asio::ip::tcp::v6()); |
|
|
|
|
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->listen (); |
|
|
|
|
|
|
|
|
|
LogPrint (eLogInfo, "NTCP: Start listening V6 TCP port ", address->port); |
|
|
|
|
auto conn = std::make_shared<NTCPSession> (*this); |
|
|
|
|
m_NTCPV6Acceptor->async_accept(conn->GetSocket (), std::bind (&NTCPServer::HandleAcceptV6, |
|
|
|
|
this, conn, std::placeholders::_1)); |
|
|
|
|
m_NTCPV6Acceptor->async_accept(conn->GetSocket (), std::bind (&NTCPServer::HandleAcceptV6, this, conn, std::placeholders::_1)); |
|
|
|
|
} catch ( std::exception & ex ) { |
|
|
|
|
LogPrint(eLogError, "NTCP: failed to bind to ip6 port ", address->port); |
|
|
|
|
continue; |
|
|
|
@ -849,6 +863,7 @@ namespace transport
@@ -849,6 +863,7 @@ namespace transport
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
ScheduleTermination (); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
@ -886,6 +901,11 @@ namespace transport
@@ -886,6 +901,11 @@ namespace transport
|
|
|
|
|
delete m_Thread; |
|
|
|
|
m_Thread = nullptr; |
|
|
|
|
} |
|
|
|
|
if(m_SocksEndpoint) |
|
|
|
|
{ |
|
|
|
|
delete m_SocksEndpoint; |
|
|
|
|
m_SocksEndpoint = nullptr; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -989,25 +1009,50 @@ namespace transport
@@ -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); |
|
|
|
|
m_Service.post([=]() |
|
|
|
|
{ |
|
|
|
|
m_Service.post([&]() { |
|
|
|
|
if (this->AddNTCPSession (conn)) |
|
|
|
|
{ |
|
|
|
|
|
|
|
|
|
auto timer = std::make_shared<boost::asio::deadline_timer>(m_Service); |
|
|
|
|
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) |
|
|
|
|
{ |
|
|
|
|
LogPrint (eLogInfo, "NTCP: Not connected in ", NTCP_CONNECT_TIMEOUT, " seconds"); |
|
|
|
|
conn->Terminate (); |
|
|
|
|
} |
|
|
|
|
}); |
|
|
|
|
conn->GetSocket ().async_connect (boost::asio::ip::tcp::endpoint (address, port), |
|
|
|
|
std::bind (&NTCPServer::HandleConnect, this, std::placeholders::_1, conn, timer)); |
|
|
|
|
conn->GetSocket ().async_connect (boost::asio::ip::tcp::endpoint (address, port), 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
@@ -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 () |
|
|
|
|
{ |
|
|
|
|
m_TerminationTimer.expires_from_now (boost::posix_time::seconds(NTCP_TERMINATION_CHECK_TIMEOUT)); |
|
|
|
@ -1049,8 +1154,7 @@ namespace transport
@@ -1049,8 +1154,7 @@ namespace transport
|
|
|
|
|
{ |
|
|
|
|
auto session = it.second; |
|
|
|
|
// 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"); |
|
|
|
|
session->Terminate (); |
|
|
|
|
}); |
|
|
|
|