|
|
|
@ -12,6 +12,7 @@
@@ -12,6 +12,7 @@
|
|
|
|
|
#include "Transports.h" |
|
|
|
|
#include "NetDb.hpp" |
|
|
|
|
#include "NTCPSession.h" |
|
|
|
|
#include "HTTP.h" |
|
|
|
|
#ifdef WITH_EVENTS |
|
|
|
|
#include "Event.h" |
|
|
|
|
#endif |
|
|
|
@ -116,7 +117,7 @@ namespace transport
@@ -116,7 +117,7 @@ namespace transport
|
|
|
|
|
m_Establisher->phase1.HXxorHI[i] ^= ident[i]; |
|
|
|
|
|
|
|
|
|
boost::asio::async_write (m_Socket, boost::asio::buffer (&m_Establisher->phase1, sizeof (NTCPPhase1)), boost::asio::transfer_all (), |
|
|
|
|
std::bind(&NTCPSession::HandlePhase1Sent, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); |
|
|
|
|
std::bind(&NTCPSession::HandlePhase1Sent, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void NTCPSession::ServerLogin () |
|
|
|
@ -132,7 +133,7 @@ namespace transport
@@ -132,7 +133,7 @@ namespace transport
|
|
|
|
|
{ |
|
|
|
|
(void) bytes_transferred; |
|
|
|
|
if (ecode) |
|
|
|
|
{ |
|
|
|
|
{ |
|
|
|
|
LogPrint (eLogInfo, "NTCP: couldn't send Phase 1 message: ", ecode.message ()); |
|
|
|
|
if (ecode != boost::asio::error::operation_aborted) |
|
|
|
|
Terminate (); |
|
|
|
@ -149,7 +150,7 @@ namespace transport
@@ -149,7 +150,7 @@ namespace transport
|
|
|
|
|
{ |
|
|
|
|
(void) bytes_transferred; |
|
|
|
|
if (ecode) |
|
|
|
|
{ |
|
|
|
|
{ |
|
|
|
|
LogPrint (eLogInfo, "NTCP: phase 1 read error: ", ecode.message ()); |
|
|
|
|
if (ecode != boost::asio::error::operation_aborted) |
|
|
|
|
Terminate (); |
|
|
|
@ -185,10 +186,10 @@ namespace transport
@@ -185,10 +186,10 @@ namespace transport
|
|
|
|
|
s->CreateAESKey (s->m_Establisher->phase1.pubKey); |
|
|
|
|
}).share (); |
|
|
|
|
m_Server.GetService ().post ([s, keyCreated]() |
|
|
|
|
{ |
|
|
|
|
keyCreated.get (); |
|
|
|
|
s->SendPhase2 (); |
|
|
|
|
}); |
|
|
|
|
{ |
|
|
|
|
keyCreated.get (); |
|
|
|
|
s->SendPhase2 (); |
|
|
|
|
}); |
|
|
|
|
#endif |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
@ -210,7 +211,7 @@ namespace transport
@@ -210,7 +211,7 @@ namespace transport
|
|
|
|
|
|
|
|
|
|
m_Encryption.Encrypt ((uint8_t *)&m_Establisher->phase2.encrypted, sizeof(m_Establisher->phase2.encrypted), (uint8_t *)&m_Establisher->phase2.encrypted); |
|
|
|
|
boost::asio::async_write (m_Socket, boost::asio::buffer (&m_Establisher->phase2, sizeof (NTCPPhase2)), boost::asio::transfer_all (), |
|
|
|
|
std::bind(&NTCPSession::HandlePhase2Sent, shared_from_this (), std::placeholders::_1, std::placeholders::_2, tsB)); |
|
|
|
|
std::bind(&NTCPSession::HandlePhase2Sent, shared_from_this (), std::placeholders::_1, std::placeholders::_2, tsB)); |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -218,7 +219,7 @@ namespace transport
@@ -218,7 +219,7 @@ namespace transport
|
|
|
|
|
{ |
|
|
|
|
(void) bytes_transferred; |
|
|
|
|
if (ecode) |
|
|
|
|
{ |
|
|
|
|
{ |
|
|
|
|
LogPrint (eLogInfo, "NTCP: Couldn't send Phase 2 message: ", ecode.message ()); |
|
|
|
|
if (ecode != boost::asio::error::operation_aborted) |
|
|
|
|
Terminate (); |
|
|
|
@ -235,7 +236,7 @@ namespace transport
@@ -235,7 +236,7 @@ namespace transport
|
|
|
|
|
{ |
|
|
|
|
(void) bytes_transferred; |
|
|
|
|
if (ecode) |
|
|
|
|
{ |
|
|
|
|
{ |
|
|
|
|
LogPrint (eLogInfo, "NTCP: Phase 2 read error: ", ecode.message (), ". Wrong ident assumed"); |
|
|
|
|
if (ecode != boost::asio::error::operation_aborted) |
|
|
|
|
{ |
|
|
|
@ -318,20 +319,20 @@ namespace transport
@@ -318,20 +319,20 @@ namespace transport
|
|
|
|
|
s.Insert (m_Establisher->phase1.pubKey, 256); // x
|
|
|
|
|
s.Insert (m_Establisher->phase2.pubKey, 256); // y
|
|
|
|
|
s.Insert (m_RemoteIdentity->GetIdentHash (), 32); // ident
|
|
|
|
|
s.Insert (tsA); // tsA
|
|
|
|
|
s.Insert (tsA); // tsA
|
|
|
|
|
s.Insert (m_Establisher->phase2.encrypted.timestamp, 4); // tsB
|
|
|
|
|
s.Sign (keys, buf); |
|
|
|
|
|
|
|
|
|
m_Encryption.Encrypt(m_ReceiveBuffer, len, m_ReceiveBuffer); |
|
|
|
|
boost::asio::async_write (m_Socket, boost::asio::buffer (m_ReceiveBuffer, len), boost::asio::transfer_all (), |
|
|
|
|
std::bind(&NTCPSession::HandlePhase3Sent, shared_from_this (), std::placeholders::_1, std::placeholders::_2, tsA)); |
|
|
|
|
std::bind(&NTCPSession::HandlePhase3Sent, shared_from_this (), std::placeholders::_1, std::placeholders::_2, tsA)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void NTCPSession::HandlePhase3Sent (const boost::system::error_code& ecode, std::size_t bytes_transferred, uint32_t tsA) |
|
|
|
|
{ |
|
|
|
|
(void) bytes_transferred; |
|
|
|
|
if (ecode) |
|
|
|
|
{ |
|
|
|
|
{ |
|
|
|
|
LogPrint (eLogInfo, "NTCP: Couldn't send Phase 3 message: ", ecode.message ()); |
|
|
|
|
if (ecode != boost::asio::error::operation_aborted) |
|
|
|
|
Terminate (); |
|
|
|
@ -351,7 +352,7 @@ namespace transport
@@ -351,7 +352,7 @@ namespace transport
|
|
|
|
|
void NTCPSession::HandlePhase3Received (const boost::system::error_code& ecode, std::size_t bytes_transferred, uint32_t tsB) |
|
|
|
|
{ |
|
|
|
|
if (ecode) |
|
|
|
|
{ |
|
|
|
|
{ |
|
|
|
|
LogPrint (eLogInfo, "NTCP: Phase 3 read error: ", ecode.message ()); |
|
|
|
|
if (ecode != boost::asio::error::operation_aborted) |
|
|
|
|
Terminate (); |
|
|
|
@ -389,7 +390,7 @@ namespace transport
@@ -389,7 +390,7 @@ namespace transport
|
|
|
|
|
void NTCPSession::HandlePhase3ExtraReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred, uint32_t tsB, size_t paddingLen) |
|
|
|
|
{ |
|
|
|
|
if (ecode) |
|
|
|
|
{ |
|
|
|
|
{ |
|
|
|
|
LogPrint (eLogInfo, "NTCP: Phase 3 extra read error: ", ecode.message ()); |
|
|
|
|
if (ecode != boost::asio::error::operation_aborted) |
|
|
|
|
Terminate (); |
|
|
|
@ -444,21 +445,21 @@ namespace transport
@@ -444,21 +445,21 @@ namespace transport
|
|
|
|
|
s.Insert (tsA); // tsA
|
|
|
|
|
s.Insert (tsB); // tsB
|
|
|
|
|
auto& keys = i2p::context.GetPrivateKeys (); |
|
|
|
|
auto signatureLen = keys.GetPublic ()->GetSignatureLen (); |
|
|
|
|
auto signatureLen = keys.GetPublic ()->GetSignatureLen (); |
|
|
|
|
s.Sign (keys, m_ReceiveBuffer); |
|
|
|
|
size_t paddingSize = signatureLen & 0x0F; // %16
|
|
|
|
|
if (paddingSize > 0) signatureLen += (16 - paddingSize); |
|
|
|
|
m_Encryption.Encrypt (m_ReceiveBuffer, signatureLen, m_ReceiveBuffer); |
|
|
|
|
|
|
|
|
|
boost::asio::async_write (m_Socket, boost::asio::buffer (m_ReceiveBuffer, signatureLen), boost::asio::transfer_all (), |
|
|
|
|
std::bind(&NTCPSession::HandlePhase4Sent, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); |
|
|
|
|
std::bind(&NTCPSession::HandlePhase4Sent, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void NTCPSession::HandlePhase4Sent (const boost::system::error_code& ecode, std::size_t bytes_transferred) |
|
|
|
|
{ |
|
|
|
|
(void) bytes_transferred; |
|
|
|
|
if (ecode) |
|
|
|
|
{ |
|
|
|
|
{ |
|
|
|
|
LogPrint (eLogWarning, "NTCP: Couldn't send Phase 4 message: ", ecode.message ()); |
|
|
|
|
if (ecode != boost::asio::error::operation_aborted) |
|
|
|
|
Terminate (); |
|
|
|
@ -478,7 +479,7 @@ namespace transport
@@ -478,7 +479,7 @@ namespace transport
|
|
|
|
|
void NTCPSession::HandlePhase4Received (const boost::system::error_code& ecode, std::size_t bytes_transferred, uint32_t tsA) |
|
|
|
|
{ |
|
|
|
|
if (ecode) |
|
|
|
|
{ |
|
|
|
|
{ |
|
|
|
|
LogPrint (eLogError, "NTCP: Phase 4 read error: ", ecode.message (), ". Check your clock"); |
|
|
|
|
if (ecode != boost::asio::error::operation_aborted) |
|
|
|
|
{ |
|
|
|
@ -673,13 +674,13 @@ namespace transport
@@ -673,13 +674,13 @@ namespace transport
|
|
|
|
|
m_NextMessage = nullptr; |
|
|
|
|
} |
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void NTCPSession::Send (std::shared_ptr<i2p::I2NPMessage> msg) |
|
|
|
|
{ |
|
|
|
|
m_IsSending = true; |
|
|
|
|
boost::asio::async_write (m_Socket, CreateMsgBuffer (msg), boost::asio::transfer_all (), |
|
|
|
|
std::bind(&NTCPSession::HandleSent, shared_from_this (), std::placeholders::_1, std::placeholders::_2, std::vector<std::shared_ptr<I2NPMessage> >{ msg })); |
|
|
|
|
std::bind(&NTCPSession::HandleSent, shared_from_this (), std::placeholders::_1, std::placeholders::_2, std::vector<std::shared_ptr<I2NPMessage> >{ msg })); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
boost::asio::const_buffers_1 NTCPSession::CreateMsgBuffer (std::shared_ptr<I2NPMessage> msg) |
|
|
|
@ -726,7 +727,7 @@ namespace transport
@@ -726,7 +727,7 @@ namespace transport
|
|
|
|
|
for (const auto& it: msgs) |
|
|
|
|
bufs.push_back (CreateMsgBuffer (it)); |
|
|
|
|
boost::asio::async_write (m_Socket, bufs, boost::asio::transfer_all (), |
|
|
|
|
std::bind(&NTCPSession::HandleSent, shared_from_this (), std::placeholders::_1, std::placeholders::_2, msgs)); |
|
|
|
|
std::bind(&NTCPSession::HandleSent, shared_from_this (), std::placeholders::_1, std::placeholders::_2, msgs)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void NTCPSession::HandleSent (const boost::system::error_code& ecode, std::size_t bytes_transferred, std::vector<std::shared_ptr<I2NPMessage> > msgs) |
|
|
|
@ -734,7 +735,7 @@ namespace transport
@@ -734,7 +735,7 @@ namespace transport
|
|
|
|
|
(void) msgs; |
|
|
|
|
m_IsSending = false; |
|
|
|
|
if (ecode) |
|
|
|
|
{ |
|
|
|
|
{ |
|
|
|
|
LogPrint (eLogWarning, "NTCP: Couldn't send msgs: ", ecode.message ()); |
|
|
|
|
// we shouldn't call Terminate () here, because HandleReceive takes care
|
|
|
|
|
// TODO: 'delete this' statement in Terminate () must be eliminated later
|
|
|
|
@ -788,7 +789,8 @@ namespace transport
@@ -788,7 +789,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_ProxyType(eNoProxy), m_Resolver(m_Service), m_ProxyEndpoint(nullptr) |
|
|
|
|
{ |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -803,48 +805,63 @@ namespace transport
@@ -803,48 +805,63 @@ namespace transport
|
|
|
|
|
{ |
|
|
|
|
m_IsRunning = true; |
|
|
|
|
m_Thread = new std::thread (std::bind (&NTCPServer::Run, this)); |
|
|
|
|
// create acceptors
|
|
|
|
|
auto& addresses = context.GetRouterInfo ().GetAddresses (); |
|
|
|
|
for (const auto& address: addresses) |
|
|
|
|
// we are using a proxy, don't create any acceptors
|
|
|
|
|
if(UsingProxy()) |
|
|
|
|
{ |
|
|
|
|
if (!address) continue; |
|
|
|
|
if (address->transportStyle == i2p::data::RouterInfo::eTransportNTCP) |
|
|
|
|
// TODO: resolve proxy until it is resolved
|
|
|
|
|
boost::asio::ip::tcp::resolver::query q(m_ProxyAddress, std::to_string(m_ProxyPort)); |
|
|
|
|
boost::system::error_code e; |
|
|
|
|
auto itr = m_Resolver.resolve(q, e); |
|
|
|
|
if(e) |
|
|
|
|
{ |
|
|
|
|
if (address->host.is_v4()) |
|
|
|
|
LogPrint(eLogError, "NTCP: Failed to resolve proxy ", e.message()); |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
m_ProxyEndpoint = new boost::asio::ip::tcp::endpoint(*itr); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
// create acceptors
|
|
|
|
|
auto& addresses = context.GetRouterInfo ().GetAddresses (); |
|
|
|
|
for (const auto& address: addresses) |
|
|
|
|
{ |
|
|
|
|
if (!address) continue; |
|
|
|
|
if (address->transportStyle == i2p::data::RouterInfo::eTransportNTCP) |
|
|
|
|
{ |
|
|
|
|
try |
|
|
|
|
if (address->host.is_v4()) |
|
|
|
|
{ |
|
|
|
|
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()); |
|
|
|
|
continue; |
|
|
|
|
try |
|
|
|
|
{ |
|
|
|
|
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()); |
|
|
|
|
continue; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
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)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
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)); |
|
|
|
|
} |
|
|
|
|
else if (address->host.is_v6() && context.SupportsV6 ()) |
|
|
|
|
{ |
|
|
|
|
m_NTCPV6Acceptor = new boost::asio::ip::tcp::acceptor (m_Service); |
|
|
|
|
try |
|
|
|
|
else if (address->host.is_v6() && context.SupportsV6 ()) |
|
|
|
|
{ |
|
|
|
|
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)); |
|
|
|
|
} catch ( std::exception & ex ) { |
|
|
|
|
LogPrint(eLogError, "NTCP: failed to bind to ip6 port ", address->port); |
|
|
|
|
continue; |
|
|
|
|
m_NTCPV6Acceptor = new boost::asio::ip::tcp::acceptor (m_Service); |
|
|
|
|
try |
|
|
|
|
{ |
|
|
|
|
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)); |
|
|
|
|
} catch ( std::exception & ex ) { |
|
|
|
|
LogPrint(eLogError, "NTCP: failed to bind to ip6 port ", address->port); |
|
|
|
|
continue; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
@ -869,14 +886,14 @@ namespace transport
@@ -869,14 +886,14 @@ namespace transport
|
|
|
|
|
{ |
|
|
|
|
m_IsRunning = false; |
|
|
|
|
m_TerminationTimer.cancel (); |
|
|
|
|
if (m_NTCPAcceptor) |
|
|
|
|
if (m_NTCPAcceptor) |
|
|
|
|
{ |
|
|
|
|
delete m_NTCPAcceptor; |
|
|
|
|
delete m_NTCPAcceptor; |
|
|
|
|
m_NTCPAcceptor = nullptr; |
|
|
|
|
} |
|
|
|
|
if (m_NTCPV6Acceptor) |
|
|
|
|
if (m_NTCPV6Acceptor) |
|
|
|
|
{ |
|
|
|
|
delete m_NTCPV6Acceptor; |
|
|
|
|
delete m_NTCPV6Acceptor; |
|
|
|
|
m_NTCPV6Acceptor = nullptr; |
|
|
|
|
} |
|
|
|
|
m_Service.stop (); |
|
|
|
@ -886,6 +903,11 @@ namespace transport
@@ -886,6 +903,11 @@ namespace transport
|
|
|
|
|
delete m_Thread; |
|
|
|
|
m_Thread = nullptr; |
|
|
|
|
} |
|
|
|
|
if(m_ProxyEndpoint) |
|
|
|
|
{ |
|
|
|
|
delete m_ProxyEndpoint; |
|
|
|
|
m_ProxyEndpoint = nullptr; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -956,7 +978,7 @@ namespace transport
@@ -956,7 +978,7 @@ namespace transport
|
|
|
|
|
|
|
|
|
|
if (error != boost::asio::error::operation_aborted) |
|
|
|
|
{ |
|
|
|
|
conn = std::make_shared<NTCPSession> (*this); |
|
|
|
|
conn = std::make_shared<NTCPSession> (*this); |
|
|
|
|
m_NTCPAcceptor->async_accept(conn->GetSocket (), std::bind (&NTCPServer::HandleAccept, this, |
|
|
|
|
conn, std::placeholders::_1)); |
|
|
|
|
} |
|
|
|
@ -983,31 +1005,56 @@ namespace transport
@@ -983,31 +1005,56 @@ namespace transport
|
|
|
|
|
|
|
|
|
|
if (error != boost::asio::error::operation_aborted) |
|
|
|
|
{ |
|
|
|
|
conn = std::make_shared<NTCPSession> (*this); |
|
|
|
|
conn = std::make_shared<NTCPSession> (*this); |
|
|
|
|
m_NTCPV6Acceptor->async_accept(conn->GetSocket (), std::bind (&NTCPServer::HandleAcceptV6, this, |
|
|
|
|
conn, std::placeholders::_1)); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
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) |
|
|
|
|
{ |
|
|
|
|
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)); |
|
|
|
|
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)); |
|
|
|
|
} |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void NTCPServer::ConnectWithProxy (const std::string& host, uint16_t port, RemoteAddressType addrtype, std::shared_ptr<NTCPSession> conn) |
|
|
|
|
{ |
|
|
|
|
if(m_ProxyEndpoint == nullptr) |
|
|
|
|
{ |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
m_Service.post([=]() { |
|
|
|
|
if (this->AddNTCPSession (conn)) |
|
|
|
|
{ |
|
|
|
|
|
|
|
|
|
auto timer = std::make_shared<boost::asio::deadline_timer>(m_Service); |
|
|
|
|
auto timeout = NTCP_CONNECT_TIMEOUT * 5; |
|
|
|
|
conn->SetTerminationTimeout(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_ProxyEndpoint, std::bind (&NTCPServer::HandleProxyConnect, this, std::placeholders::_1, conn, timer, host, port, addrtype)); |
|
|
|
|
} |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
@ -1016,7 +1063,7 @@ namespace transport
@@ -1016,7 +1063,7 @@ namespace transport
|
|
|
|
|
{ |
|
|
|
|
timer->cancel (); |
|
|
|
|
if (ecode) |
|
|
|
|
{ |
|
|
|
|
{ |
|
|
|
|
LogPrint (eLogInfo, "NTCP: Connect error ", ecode.message ()); |
|
|
|
|
if (ecode != boost::asio::error::operation_aborted) |
|
|
|
|
i2p::data::netdb.SetUnreachable (conn->GetRemoteIdentity ()->GetIdentHash (), true); |
|
|
|
@ -1031,6 +1078,191 @@ namespace transport
@@ -1031,6 +1078,191 @@ namespace transport
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void NTCPServer::UseProxy(ProxyType proxytype, const std::string & addr, uint16_t port) |
|
|
|
|
{ |
|
|
|
|
m_ProxyType = proxytype; |
|
|
|
|
m_ProxyAddress = addr; |
|
|
|
|
m_ProxyPort = port; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void NTCPServer::HandleProxyConnect(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, RemoteAddressType addrtype) |
|
|
|
|
{ |
|
|
|
|
if(ecode) |
|
|
|
|
{ |
|
|
|
|
LogPrint(eLogWarning, "NTCP: failed to connect to proxy ", ecode.message()); |
|
|
|
|
timer->cancel(); |
|
|
|
|
conn->Terminate(); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
if(m_ProxyType == eSocksProxy) |
|
|
|
|
{ |
|
|
|
|
// TODO: support username/password auth etc
|
|
|
|
|
uint8_t buff[3] = {0x05, 0x01, 0x00}; |
|
|
|
|
boost::asio::async_write(conn->GetSocket(), boost::asio::buffer(buff, 3), boost::asio::transfer_all(), [=] (const boost::system::error_code & ec, std::size_t transferred) { |
|
|
|
|
(void) transferred; |
|
|
|
|
if(ec) |
|
|
|
|
{ |
|
|
|
|
LogPrint(eLogWarning, "NTCP: socks5 write error ", ec.message()); |
|
|
|
|
} |
|
|
|
|
}); |
|
|
|
|
uint8_t readbuff[2]; |
|
|
|
|
boost::asio::async_read(conn->GetSocket(), boost::asio::buffer(readbuff, 2), [=](const boost::system::error_code & ec, std::size_t transferred) { |
|
|
|
|
if(ec) |
|
|
|
|
{ |
|
|
|
|
LogPrint(eLogError, "NTCP: socks5 read error ", ec.message()); |
|
|
|
|
timer->cancel(); |
|
|
|
|
conn->Terminate(); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
else if(transferred == 2) |
|
|
|
|
{ |
|
|
|
|
if(readbuff[1] == 0x00) |
|
|
|
|
{ |
|
|
|
|
AfterSocksHandshake(conn, timer, host, port, addrtype); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
else if (readbuff[1] == 0xff) |
|
|
|
|
{ |
|
|
|
|
LogPrint(eLogError, "NTCP: socks5 proxy rejected authentication"); |
|
|
|
|
timer->cancel(); |
|
|
|
|
conn->Terminate(); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
LogPrint(eLogError, "NTCP: socks5 server gave invalid response"); |
|
|
|
|
timer->cancel(); |
|
|
|
|
conn->Terminate(); |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
else if(m_ProxyType == eHTTPProxy) |
|
|
|
|
{ |
|
|
|
|
i2p::http::HTTPReq req; |
|
|
|
|
req.method = "CONNECT"; |
|
|
|
|
req.version ="HTTP/1.1"; |
|
|
|
|
if(addrtype == eIP6Address) |
|
|
|
|
req.uri = "[" + host + "]:" + std::to_string(port); |
|
|
|
|
else |
|
|
|
|
req.uri = host + ":" + std::to_string(port); |
|
|
|
|
|
|
|
|
|
boost::asio::streambuf writebuff; |
|
|
|
|
std::ostream out(&writebuff); |
|
|
|
|
out << req.to_string(); |
|
|
|
|
|
|
|
|
|
boost::asio::async_write(conn->GetSocket(), writebuff.data(), boost::asio::transfer_all(), [=](const boost::system::error_code & ec, std::size_t transferred) { |
|
|
|
|
(void) transferred; |
|
|
|
|
if(ec) |
|
|
|
|
LogPrint(eLogError, "NTCP: http proxy write error ", ec.message()); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
boost::asio::streambuf * readbuff = new boost::asio::streambuf; |
|
|
|
|
boost::asio::async_read_until(conn->GetSocket(), *readbuff, "\r\n\r\n", [=] (const boost::system::error_code & ec, std::size_t transferred) { |
|
|
|
|
if(ec) |
|
|
|
|
{ |
|
|
|
|
LogPrint(eLogError, "NTCP: http proxy read error ", ec.message()); |
|
|
|
|
timer->cancel(); |
|
|
|
|
conn->Terminate(); |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
readbuff->commit(transferred); |
|
|
|
|
i2p::http::HTTPRes res; |
|
|
|
|
if(res.parse(boost::asio::buffer_cast<const char*>(readbuff->data()), readbuff->size()) > 0) |
|
|
|
|
{ |
|
|
|
|
if(res.code == 200) |
|
|
|
|
{ |
|
|
|
|
timer->cancel(); |
|
|
|
|
conn->ClientLogin(); |
|
|
|
|
delete readbuff; |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
LogPrint(eLogError, "NTCP: http proxy rejected request ", res.code); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
LogPrint(eLogError, "NTCP: http proxy gave malformed response"); |
|
|
|
|
timer->cancel(); |
|
|
|
|
conn->Terminate(); |
|
|
|
|
delete readbuff; |
|
|
|
|
} |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
LogPrint(eLogError, "NTCP: unknown proxy type, invalid state"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void NTCPServer::AfterSocksHandshake(std::shared_ptr<NTCPSession> conn, std::shared_ptr<boost::asio::deadline_timer> timer, const std::string & host, uint16_t port, RemoteAddressType addrtype) |
|
|
|
|
{ |
|
|
|
|
|
|
|
|
|
// build request
|
|
|
|
|
size_t sz = 0; |
|
|
|
|
uint8_t buff[256]; |
|
|
|
|
uint8_t readbuff[256]; |
|
|
|
|
buff[0] = 0x05; |
|
|
|
|
buff[1] = 0x01; |
|
|
|
|
buff[2] = 0x00; |
|
|
|
|
|
|
|
|
|
if(addrtype == eIP4Address) |
|
|
|
|
{ |
|
|
|
|
buff[3] = 0x01; |
|
|
|
|
auto addr = boost::asio::ip::address::from_string(host).to_v4(); |
|
|
|
|
auto addrbytes = addr.to_bytes(); |
|
|
|
|
auto addrsize = addrbytes.size(); |
|
|
|
|
memcpy(buff+4, addrbytes.data(), addrsize); |
|
|
|
|
} |
|
|
|
|
else if (addrtype == eIP6Address) |
|
|
|
|
{ |
|
|
|
|
buff[3] = 0x04; |
|
|
|
|
auto addr = boost::asio::ip::address::from_string(host).to_v6(); |
|
|
|
|
auto addrbytes = addr.to_bytes(); |
|
|
|
|
auto addrsize = addrbytes.size(); |
|
|
|
|
memcpy(buff+4, addrbytes.data(), addrsize); |
|
|
|
|
} |
|
|
|
|
else if (addrtype == eHostname) |
|
|
|
|
{ |
|
|
|
|
buff[3] = 0x03; |
|
|
|
|
size_t addrsize = host.size(); |
|
|
|
|
sz = addrsize + 1 + 4; |
|
|
|
|
if (2 + sz > sizeof(buff)) |
|
|
|
|
{ |
|
|
|
|
// too big
|
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
buff[4] = (uint8_t) addrsize; |
|
|
|
|
memcpy(buff+4, host.c_str(), addrsize); |
|
|
|
|
} |
|
|
|
|
htobe16buf(buff+sz, port); |
|
|
|
|
sz += 2; |
|
|
|
|
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, sz), [=](const boost::system::error_code & e, std::size_t transferred) { |
|
|
|
|
if(e) |
|
|
|
|
{ |
|
|
|
|
LogPrint(eLogError, "NTCP: socks proxy read error ", e.message()); |
|
|
|
|
} |
|
|
|
|
else if(transferred == sz) |
|
|
|
|
{ |
|
|
|
|
if( readbuff[1] == 0x00) |
|
|
|
|
{ |
|
|
|
|
timer->cancel(); |
|
|
|
|
conn->ClientLogin(); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
if(!e) |
|
|
|
|
i2p::data::netdb.SetUnreachable (conn->GetRemoteIdentity ()->GetIdentHash (), true); |
|
|
|
|
timer->cancel(); |
|
|
|
|
conn->Terminate(); |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void NTCPServer::ScheduleTermination () |
|
|
|
|
{ |
|
|
|
|
m_TerminationTimer.expires_from_now (boost::posix_time::seconds(NTCP_TERMINATION_CHECK_TIMEOUT)); |
|
|
|
@ -1045,15 +1277,14 @@ namespace transport
@@ -1045,15 +1277,14 @@ namespace transport
|
|
|
|
|
auto ts = i2p::util::GetSecondsSinceEpoch (); |
|
|
|
|
// established
|
|
|
|
|
for (auto& it: m_NTCPSessions) |
|
|
|
|
if (it.second->IsTerminationTimeoutExpired (ts)) |
|
|
|
|
if (it.second->IsTerminationTimeoutExpired (ts)) |
|
|
|
|
{ |
|
|
|
|
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 (); |
|
|
|
|
}); |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
// pending
|
|
|
|
|
for (auto it = m_PendingIncomingSessions.begin (); it != m_PendingIncomingSessions.end ();) |
|
|
|
|