From ec5eafafebef3ddaf6e521a93dcf1ffe6fb28569 Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 8 Feb 2014 21:06:40 -0500 Subject: [PATCH] external IP detection --- RouterContext.cpp | 7 +++++++ RouterContext.h | 1 + RouterInfo.cpp | 8 ++++++++ RouterInfo.h | 3 ++- SSU.cpp | 40 ++++++++++++++++++++++++++++++++++++++-- SSU.h | 11 ++++++++--- Transports.cpp | 41 ++++++++++++++++++++++++++++++++++++++--- Transports.h | 4 ++++ 8 files changed, 106 insertions(+), 9 deletions(-) diff --git a/RouterContext.cpp b/RouterContext.cpp index 68f6508a..768b92a3 100644 --- a/RouterContext.cpp +++ b/RouterContext.cpp @@ -52,6 +52,13 @@ namespace i2p m_RouterInfo.CreateBuffer (); } + + void RouterContext::UpdateAddress (const char * host) + { + for (auto& address : m_RouterInfo.GetAddresses ()) + address.host = boost::asio::ip::address::from_string (host); + m_RouterInfo.CreateBuffer (); + } void RouterContext::Sign (uint8_t * buf, int len, uint8_t * signature) { diff --git a/RouterContext.h b/RouterContext.h index f43094c1..0cbd0bc7 100644 --- a/RouterContext.h +++ b/RouterContext.h @@ -28,6 +28,7 @@ namespace i2p void Sign (uint8_t * buf, int len, uint8_t * signature); void OverrideNTCPAddress (const char * host, int port); // temporary + void UpdateAddress (const char * host); // called from SSU private: diff --git a/RouterInfo.cpp b/RouterInfo.cpp index 3b0054a0..f4668921 100644 --- a/RouterInfo.cpp +++ b/RouterInfo.cpp @@ -294,6 +294,14 @@ namespace data else return m_SupportedTransports & (eNTCPV4 | eNTCPV6); } + + bool RouterInfo::IsSSU (bool v4only) const + { + if (v4only) + return m_SupportedTransports & eSSUV4; + else + return m_SupportedTransports & (eSSUV4 | eSSUV6); + } RouterInfo::Address * RouterInfo::GetNTCPAddress (bool v4only) { diff --git a/RouterInfo.h b/RouterInfo.h index d7fc6dd9..3b28fee7 100644 --- a/RouterInfo.h +++ b/RouterInfo.h @@ -53,7 +53,7 @@ namespace data const char * GetIdentHashBase64 () const { return m_IdentHashBase64; }; const char * GetIdentHashAbbreviation () const { return m_IdentHashAbbreviation; }; uint64_t GetTimestamp () const { return m_Timestamp; }; - const std::vector
& GetAddresses () const { return m_Addresses; }; + std::vector
& GetAddresses () { return m_Addresses; }; Address * GetNTCPAddress (bool v4only = true); Address * GetSSUAddress (bool v4only = true); const RoutingKey& GetRoutingKey () const { return m_RoutingKey; }; @@ -63,6 +63,7 @@ namespace data const char * GetProperty (const char * key) const; bool IsFloodfill () const; bool IsNTCP (bool v4only = true) const; + bool IsSSU (bool v4only = true) const; bool IsCompatible (const RouterInfo& other) const { return m_SupportedTransports & other.m_SupportedTransports; }; void SetUnreachable (bool unreachable) { m_IsUnreachable = unreachable; }; diff --git a/SSU.cpp b/SSU.cpp index 2c85f137..57ebdce9 100644 --- a/SSU.cpp +++ b/SSU.cpp @@ -85,7 +85,7 @@ namespace ssu case PAYLOAD_TYPE_TEST: LogPrint ("SSU test received"); break; - case PAYLOAD_TYPE_SESSION_DESTROY: + case PAYLOAD_TYPE_SESSION_DESTROYED: LogPrint ("SSU session destroy received"); break; default: @@ -129,6 +129,7 @@ namespace ssu boost::asio::ip::address_v4 ourIP (be32toh (*(uint32_t* )(ourAddress))); uint16_t ourPort = be16toh (*(uint16_t *)(ourAddress + 4)); LogPrint ("Our external address is ", ourIP.to_string (), ":", ourPort); + i2p::context.UpdateAddress (ourIP.to_string ().c_str ()); uint32_t relayTag = be32toh (*(uint32_t *)(buf + sizeof (SSUHeader) + 263)); SendSessionConfirmed (buf + sizeof (SSUHeader), ourAddress, relayTag); m_State = eSessionStateEstablished; @@ -357,6 +358,11 @@ namespace ssu SendSessionRequest (); } + void SSUSession::Close () + { + SendSesionDestroyed (); + } + void SSUSession::SendI2NPMessage (I2NPMessage * msg) { // TODO: @@ -445,7 +451,7 @@ namespace ssu void SSUSession::SendMsgAck (uint32_t msgID) { - uint8_t buf[48]; // actual length is 44 = 37 + 7 but pad it to multiple of 16 + uint8_t buf[48 + 18]; // actual length is 44 = 37 + 7 but pad it to multiple of 16 uint8_t iv[16]; uint8_t * payload = buf + sizeof (SSUHeader); *payload = DATA_FLAG_EXPLICIT_ACKS_INCLUDED; // flag @@ -463,6 +469,16 @@ namespace ssu m_Server->Send (buf, 48, m_RemoteEndpoint); } + void SSUSession::SendSesionDestroyed () + { + uint8_t buf[48 + 18], iv[16]; + CryptoPP::RandomNumberGenerator& rnd = i2p::context.GetRandomNumberGenerator (); + rnd.GenerateBlock (iv, 16); // random iv + // encrypt message with session key + FillHeaderAndEncrypt (PAYLOAD_TYPE_SESSION_DESTROYED, buf, 48, m_SessionKey, iv, m_MacKey); + m_Server->Send (buf, 48, m_RemoteEndpoint); + } + SSUServer::SSUServer (boost::asio::io_service& service, int port): m_Endpoint (boost::asio::ip::udp::v4 (), port), m_Socket (service, m_Endpoint) { @@ -546,6 +562,26 @@ namespace ssu } return session; } + + void SSUServer::DeleteSession (SSUSession * session) + { + if (session) + { + session->Close (); + m_Sessions.erase (session->GetRemoteEndpoint ()); + delete session; + } + } + + void SSUServer::DeleteAllSessions () + { + for (auto it: m_Sessions) + { + it.second->Close (); + delete it.second; + } + m_Sessions.clear (); + } } } diff --git a/SSU.h b/SSU.h index 3a6c029c..15467262 100644 --- a/SSU.h +++ b/SSU.h @@ -35,7 +35,7 @@ namespace ssu const uint8_t PAYLOAD_TYPE_RELAY_INTRO = 5; const uint8_t PAYLOAD_TYPE_DATA = 6; const uint8_t PAYLOAD_TYPE_TEST = 7; - const uint8_t PAYLOAD_TYPE_SESSION_DESTROY = 8; + const uint8_t PAYLOAD_TYPE_SESSION_DESTROYED = 8; // data flags const uint8_t DATA_FLAG_EXTENDED_DATA_INCLUDED = 0x02; @@ -67,6 +67,8 @@ namespace ssu void ProcessNextMessage (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint); void Connect (); + void Close (); + boost::asio::ip::udp::endpoint& GetRemoteEndpoint () { return m_RemoteEndpoint; }; void SendI2NPMessage (I2NPMessage * msg); private: @@ -82,7 +84,8 @@ namespace ssu void SendSessionConfirmed (const uint8_t * y, const uint8_t * ourAddress, uint32_t relayTag); void ProcessData (uint8_t * buf, size_t len); void SendMsgAck (uint32_t msgID); - + void SendSesionDestroyed (); + bool ProcessIntroKeyEncryptedMessage (uint8_t expectedPayloadType, i2p::data::RouterInfo& r, uint8_t * buf, size_t len); void FillHeaderAndEncrypt (uint8_t payloadType, uint8_t * buf, size_t len, uint8_t * aesKey, uint8_t * iv, uint8_t * macKey); void Decrypt (uint8_t * buf, size_t len, uint8_t * aesKey); @@ -109,7 +112,9 @@ namespace ssu void Start (); void Stop (); SSUSession * GetSession (i2p::data::RouterInfo * router); - + void DeleteSession (SSUSession * session); + void DeleteAllSessions (); + const boost::asio::ip::udp::endpoint& GetEndpoint () const { return m_Endpoint; }; void Send (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& to); diff --git a/Transports.cpp b/Transports.cpp index c3b96d78..8ea6c05f 100644 --- a/Transports.cpp +++ b/Transports.cpp @@ -25,6 +25,7 @@ namespace i2p { m_IsRunning = true; m_Thread = new std::thread (std::bind (&Transports::Run, this)); + m_Timer = new boost::asio::deadline_timer (m_Service); // create acceptors auto addresses = context.GetRouterInfo ().GetAddresses (); for (auto& address : addresses) @@ -38,9 +39,11 @@ namespace i2p auto conn = new i2p::ntcp::NTCPServerConnection (m_Service); m_NTCPAcceptor->async_accept(conn->GetSocket (), boost::bind (&Transports::HandleAccept, this, conn, boost::asio::placeholders::error)); - } + // temporary always run SSU server + // TODO: uncomment following lines later + /*} else if (address.transportStyle == RouterInfo::eTransportSSU) - { + {*/ if (!m_SSUServer) { m_SSUServer = new i2p::ssu::SSUServer (m_Service, address.port); @@ -51,6 +54,9 @@ namespace i2p LogPrint ("SSU server already exists"); } } + + // TODO: do it for SSU only + DetectExternalIP (); } void Transports::Stop () @@ -59,7 +65,10 @@ namespace i2p delete session.second; m_NTCPSessions.clear (); delete m_NTCPAcceptor; - + + m_Timer->cancel (); + delete m_Timer; + if (m_SSUServer) { m_SSUServer->Stop (); @@ -173,4 +182,30 @@ namespace i2p else LogPrint ("Session not found"); } + + void Transports::DetectExternalIP () + { + for (int i = 0; i < 5; i ++) + { + auto router = i2p::data::netdb.GetRandomRouter (); + if (router && router->IsSSU () && m_SSUServer) + m_SSUServer->GetSession (const_cast(router)); //TODO + } + if (m_Timer) + { + m_Timer->expires_from_now (boost::posix_time::seconds(5)); // 5 seconds + m_Timer->async_wait (boost::bind (&Transports::HandleTimer, this, boost::asio::placeholders::error)); + } + } + + void Transports::HandleTimer (const boost::system::error_code& ecode) + { + if (ecode != boost::asio::error::operation_aborted) + { + // end of external IP detection + if (m_SSUServer) + m_SSUServer->DeleteAllSessions (); + } + } + } diff --git a/Transports.h b/Transports.h index 03f6cf35..12bd8f21 100644 --- a/Transports.h +++ b/Transports.h @@ -38,6 +38,9 @@ namespace i2p void Run (); void HandleAccept (i2p::ntcp::NTCPServerConnection * conn, const boost::system::error_code& error); void PostMessage (const i2p::data::IdentHash& ident, i2p::I2NPMessage * msg); + + void DetectExternalIP (); + void HandleTimer (const boost::system::error_code& ecode); private: @@ -49,6 +52,7 @@ namespace i2p std::map m_NTCPSessions; i2p::ssu::SSUServer * m_SSUServer; + boost::asio::deadline_timer * m_Timer; public: