From 74c0b729c22b181c42b5e38ab342d99f51e528ac Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 11 Jun 2018 12:29:30 -0400 Subject: [PATCH] connect to NTCP2 --- libi2pd/NTCP2.cpp | 109 ++++++++++++++++++++++++++++++++++++++++++++-- libi2pd/NTCP2.h | 28 +++++++++--- 2 files changed, 129 insertions(+), 8 deletions(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index ac2805e0..6b21e900 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -16,7 +16,9 @@ namespace transport { NTCP2Session::NTCP2Session (NTCP2Server& server, std::shared_ptr in_RemoteRouter): TransportSession (in_RemoteRouter, 30), - m_Server (server), m_Socket (m_Server.GetService ()), m_SessionRequestBuffer (nullptr) + m_Server (server), m_Socket (m_Server.GetService ()), + m_IsEstablished (false), m_IsTerminated (false), + m_SessionRequestBuffer (nullptr), m_SessionCreatedBuffer (nullptr) { auto addr = in_RemoteRouter->GetNTCPAddress (); if (addr->ntcp2) @@ -31,9 +33,21 @@ namespace transport NTCP2Session::~NTCP2Session () { delete[] m_SessionRequestBuffer; + delete[] m_SessionCreatedBuffer; } - bool NTCP2Session::KeyDerivationFunction (const uint8_t * rs, const uint8_t * pub, uint8_t * derived) + void NTCP2Session::Terminate () + { + if (!m_IsTerminated) + { + m_IsTerminated = true; + m_IsEstablished = false; + m_Socket.close (); + LogPrint (eLogDebug, "NTCP2: session terminated"); + } + } + + bool NTCP2Session::KeyDerivationFunction1 (const uint8_t * rs, const uint8_t * pub, uint8_t * derived) { static const char protocolName[] = "Noise_XK_25519_ChaChaPoly_SHA256"; // 32 bytes uint8_t h[64], ck[33]; @@ -84,7 +98,7 @@ namespace transport encryption.Encrypt (2, x.GetChipherBlock (), x.GetChipherBlock ()); // encryption key for next block uint8_t key[32]; - KeyDerivationFunction (m_RemoteStaticKey, x, key); + KeyDerivationFunction1 (m_RemoteStaticKey, x, key); // fill options uint8_t options[32]; // actual options size is 16 bytes memset (options, 0, 16); @@ -115,13 +129,102 @@ namespace transport if (ecode) { LogPrint (eLogInfo, "NTCP2: couldn't send SessionRequest message: ", ecode.message ()); + Terminate (); + } + else + { + m_SessionCreatedBuffer = new uint8_t[287]; // TODO: determine actual max size + // we receive first 56 bytes (32 Y, and 24 ChaCha/Poly frame) first + boost::asio::async_read (m_Socket, boost::asio::buffer(m_SessionCreatedBuffer, sizeof (56)), boost::asio::transfer_all (), + std::bind(&NTCP2Session::HandleSessionCreatedReceived, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); } } + void NTCP2Session::HandleSessionCreatedReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred) + { + (void) bytes_transferred; + delete[] m_SessionCreatedBuffer; m_SessionCreatedBuffer = nullptr; + if (ecode) + LogPrint (eLogInfo, "NTCP: Phase 2 read error: ", ecode.message ()); + Terminate (); // TODO: continue + } + void NTCP2Session::ClientLogin () { SendSessionRequest (); } + + NTCP2Server::NTCP2Server (): + m_IsRunning (false), m_Thread (nullptr), m_Work (m_Service) + { + } + + NTCP2Server::~NTCP2Server () + { + Stop (); + } + + void NTCP2Server::Start () + { + if (!m_IsRunning) + { + m_IsRunning = true; + m_Thread = new std::thread (std::bind (&NTCP2Server::Run, this)); + } + } + + void NTCP2Server::Stop () + { + if (m_IsRunning) + { + m_IsRunning = false; + m_Service.stop (); + if (m_Thread) + { + m_Thread->join (); + delete m_Thread; + m_Thread = nullptr; + } + } + } + + void NTCP2Server::Run () + { + while (m_IsRunning) + { + try + { + m_Service.run (); + } + catch (std::exception& ex) + { + LogPrint (eLogError, "NTCP2: runtime exception: ", ex.what ()); + } + } + } + + void NTCP2Server::Connect(const boost::asio::ip::address & address, uint16_t port, std::shared_ptr conn) + { + LogPrint (eLogDebug, "NTCP: Connecting to ", address ,":", port); + m_Service.post([this, address, port, conn]() + { + conn->GetSocket ().async_connect (boost::asio::ip::tcp::endpoint (address, port), std::bind (&NTCP2Server::HandleConnect, this, std::placeholders::_1, conn)); + }); + } + + void NTCP2Server::HandleConnect (const boost::system::error_code& ecode, std::shared_ptr conn) + { + if (ecode) + { + LogPrint (eLogInfo, "NTCP2: Connect error ", ecode.message ()); + conn->Terminate (); + } + else + { + LogPrint (eLogDebug, "NTCP2: Connected to ", conn->GetSocket ().remote_endpoint ()); + conn->ClientLogin (); + } + } } } diff --git a/libi2pd/NTCP2.h b/libi2pd/NTCP2.h index 059f46c5..a4f30920 100644 --- a/libi2pd/NTCP2.h +++ b/libi2pd/NTCP2.h @@ -18,6 +18,7 @@ namespace transport NTCP2Session (NTCP2Server& server, std::shared_ptr in_RemoteRouter = nullptr); // TODO ~NTCP2Session (); + void Terminate (); boost::asio::ip::tcp::socket& GetSocket () { return m_Socket; }; @@ -25,32 +26,49 @@ namespace transport private: - bool KeyDerivationFunction (const uint8_t * rs, const uint8_t * pub, uint8_t * derived); + bool KeyDerivationFunction1 (const uint8_t * rs, const uint8_t * pub, uint8_t * derived); // for SessionRequest void CreateEphemeralKey (uint8_t * pub); void SendSessionRequest (); void HandleSessionRequestSent (const boost::system::error_code& ecode, std::size_t bytes_transferred); + void HandleSessionCreatedReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred); private: NTCP2Server& m_Server; boost::asio::ip::tcp::socket m_Socket; + bool m_IsEstablished, m_IsTerminated; + uint8_t m_ExpandedPrivateKey[64]; // x25519 ephemeral key uint8_t m_RemoteStaticKey[32], m_RemoteIV[16]; - uint8_t * m_SessionRequestBuffer; + uint8_t * m_SessionRequestBuffer, * m_SessionCreatedBuffer; }; class NTCP2Server { public: - NTCP2Server () {}; - ~NTCP2Server () {} ; + NTCP2Server (); + ~NTCP2Server (); + + void Start (); + void Stop (); + boost::asio::io_service& GetService () { return m_Service; }; - + + void Connect(const boost::asio::ip::address & address, uint16_t port, std::shared_ptr conn); + + private: + + void Run (); + void HandleConnect (const boost::system::error_code& ecode, std::shared_ptr conn); + private: + bool m_IsRunning; + std::thread * m_Thread; boost::asio::io_service m_Service; + boost::asio::io_service::work m_Work; }; } }