1 /* 2 * Copyright (c) 2013-2021, The PurpleI2P Project 3 * 4 * This file is part of Purple i2pd project and licensed under BSD3 5 * 6 * See full license text in LICENSE file at top of project tree 7 */ 8 9 #ifndef TUNNEL_H__ 10 #define TUNNEL_H__ 11 12 #include <inttypes.h> 13 #include <map> 14 #include <unordered_map> 15 #include <list> 16 #include <vector> 17 #include <string> 18 #include <thread> 19 #include <mutex> 20 #include <memory> 21 #include "util.h" 22 #include "Queue.h" 23 #include "Crypto.h" 24 #include "TunnelConfig.h" 25 #include "TunnelPool.h" 26 #include "TransitTunnel.h" 27 #include "TunnelEndpoint.h" 28 #include "TunnelGateway.h" 29 #include "TunnelBase.h" 30 #include "I2NPProtocol.h" 31 32 namespace i2p 33 { 34 namespace tunnel 35 { 36 const int TUNNEL_EXPIRATION_TIMEOUT = 660; // 11 minutes 37 const int TUNNEL_EXPIRATION_THRESHOLD = 60; // 1 minute 38 const int TUNNEL_RECREATION_THRESHOLD = 90; // 1.5 minutes 39 const int TUNNEL_CREATION_TIMEOUT = 30; // 30 seconds 40 const int STANDARD_NUM_RECORDS = 4; // in VariableTunnelBuild message 41 const int MAX_NUM_RECORDS = 8; 42 const int HIGH_LATENCY_PER_HOP = 250; // in milliseconds 43 44 const size_t I2NP_TUNNEL_MESSAGE_SIZE = TUNNEL_DATA_MSG_SIZE + I2NP_HEADER_SIZE + 34; // reserved for alignment and NTCP 16 + 6 + 12 45 const size_t I2NP_TUNNEL_ENPOINT_MESSAGE_SIZE = 2*TUNNEL_DATA_MSG_SIZE + I2NP_HEADER_SIZE + TUNNEL_GATEWAY_HEADER_SIZE + 28; // reserved for alignment and NTCP 16 + 6 + 6 46 47 enum TunnelState 48 { 49 eTunnelStatePending, 50 eTunnelStateBuildReplyReceived, 51 eTunnelStateBuildFailed, 52 eTunnelStateEstablished, 53 eTunnelStateTestFailed, 54 eTunnelStateFailed, 55 eTunnelStateExpiring 56 }; 57 58 class OutboundTunnel; 59 class InboundTunnel; 60 class Tunnel: public TunnelBase 61 { 62 struct TunnelHop 63 { 64 std::shared_ptr<const i2p::data::IdentityEx> ident; 65 i2p::crypto::TunnelDecryption decryption; 66 }; 67 68 public: 69 70 Tunnel (std::shared_ptr<const TunnelConfig> config); 71 ~Tunnel (); 72 73 void Build (uint32_t replyMsgID, std::shared_ptr<OutboundTunnel> outboundTunnel = nullptr); 74 GetTunnelConfig()75 std::shared_ptr<const TunnelConfig> GetTunnelConfig () const { return m_Config; } 76 std::vector<std::shared_ptr<const i2p::data::IdentityEx> > GetPeers () const; 77 std::vector<std::shared_ptr<const i2p::data::IdentityEx> > GetInvertedPeers () const; IsShortBuildMessage()78 bool IsShortBuildMessage () const { return m_IsShortBuildMessage; }; GetFarEndTransports()79 i2p::data::RouterInfo::CompatibleTransports GetFarEndTransports () const { return m_FarEndTransports; }; GetState()80 TunnelState GetState () const { return m_State; }; 81 void SetState (TunnelState state); IsEstablished()82 bool IsEstablished () const { return m_State == eTunnelStateEstablished; }; IsFailed()83 bool IsFailed () const { return m_State == eTunnelStateFailed; }; IsRecreated()84 bool IsRecreated () const { return m_IsRecreated; }; SetRecreated(bool recreated)85 void SetRecreated (bool recreated) { m_IsRecreated = recreated; }; GetNumHops()86 int GetNumHops () const { return m_Hops.size (); }; 87 virtual bool IsInbound() const = 0; 88 GetTunnelPool()89 std::shared_ptr<TunnelPool> GetTunnelPool () const { return m_Pool; }; SetTunnelPool(std::shared_ptr<TunnelPool> pool)90 void SetTunnelPool (std::shared_ptr<TunnelPool> pool) { m_Pool = pool; }; 91 92 bool HandleTunnelBuildResponse (uint8_t * msg, size_t len); 93 Print(std::stringstream &)94 virtual void Print (std::stringstream&) const {}; 95 96 // implements TunnelBase 97 void SendTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage> msg); 98 void EncryptTunnelMsg (std::shared_ptr<const I2NPMessage> in, std::shared_ptr<I2NPMessage> out); 99 100 /** @brief add latency sample */ AddLatencySample(const uint64_t ms)101 void AddLatencySample(const uint64_t ms) { m_Latency = (m_Latency + ms) >> 1; } 102 /** @brief get this tunnel's estimated latency */ GetMeanLatency()103 uint64_t GetMeanLatency() const { return m_Latency; } 104 /** @brief return true if this tunnel's latency fits in range [lowerbound, upperbound] */ 105 bool LatencyFitsRange(uint64_t lowerbound, uint64_t upperbound) const; 106 LatencyIsKnown()107 bool LatencyIsKnown() const { return m_Latency > 0; } IsSlow()108 bool IsSlow () const { return LatencyIsKnown() && (int)m_Latency > HIGH_LATENCY_PER_HOP*GetNumHops (); } 109 110 protected: 111 112 void PrintHops (std::stringstream& s) const; 113 114 private: 115 116 std::shared_ptr<const TunnelConfig> m_Config; 117 std::vector<TunnelHop> m_Hops; 118 bool m_IsShortBuildMessage; 119 std::shared_ptr<TunnelPool> m_Pool; // pool, tunnel belongs to, or null 120 TunnelState m_State; 121 i2p::data::RouterInfo::CompatibleTransports m_FarEndTransports; 122 bool m_IsRecreated; // if tunnel is replaced by new, or new tunnel requested to replace 123 uint64_t m_Latency; // in milliseconds 124 }; 125 126 class OutboundTunnel: public Tunnel 127 { 128 public: 129 OutboundTunnel(std::shared_ptr<const TunnelConfig> config)130 OutboundTunnel (std::shared_ptr<const TunnelConfig> config): 131 Tunnel (config), m_Gateway (this), m_EndpointIdentHash (config->GetLastIdentHash ()) {}; 132 133 void SendTunnelDataMsg (const uint8_t * gwHash, uint32_t gwTunnel, std::shared_ptr<i2p::I2NPMessage> msg); 134 virtual void SendTunnelDataMsg (const std::vector<TunnelMessageBlock>& msgs); // multiple messages GetEndpointIdentHash()135 const i2p::data::IdentHash& GetEndpointIdentHash () const { return m_EndpointIdentHash; }; GetNumSentBytes()136 virtual size_t GetNumSentBytes () const { return m_Gateway.GetNumSentBytes (); }; 137 void Print (std::stringstream& s) const; 138 139 // implements TunnelBase 140 void HandleTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage>&& tunnelMsg); 141 IsInbound()142 bool IsInbound() const { return false; } 143 144 private: 145 146 std::mutex m_SendMutex; 147 TunnelGateway m_Gateway; 148 i2p::data::IdentHash m_EndpointIdentHash; 149 }; 150 151 class InboundTunnel: public Tunnel, public std::enable_shared_from_this<InboundTunnel> 152 { 153 public: 154 InboundTunnel(std::shared_ptr<const TunnelConfig> config)155 InboundTunnel (std::shared_ptr<const TunnelConfig> config): Tunnel (config), m_Endpoint (true) {}; 156 void HandleTunnelDataMsg (std::shared_ptr<I2NPMessage>&& msg); GetNumReceivedBytes()157 virtual size_t GetNumReceivedBytes () const { return m_Endpoint.GetNumReceivedBytes (); }; 158 void Print (std::stringstream& s) const; IsInbound()159 bool IsInbound() const { return true; } 160 161 // override TunnelBase Cleanup()162 void Cleanup () { m_Endpoint.Cleanup (); }; 163 164 private: 165 166 TunnelEndpoint m_Endpoint; 167 }; 168 169 class ZeroHopsInboundTunnel: public InboundTunnel 170 { 171 public: 172 173 ZeroHopsInboundTunnel (); 174 void SendTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage> msg); 175 void Print (std::stringstream& s) const; GetNumReceivedBytes()176 size_t GetNumReceivedBytes () const { return m_NumReceivedBytes; }; 177 178 private: 179 180 size_t m_NumReceivedBytes; 181 }; 182 183 class ZeroHopsOutboundTunnel: public OutboundTunnel 184 { 185 public: 186 187 ZeroHopsOutboundTunnel (); 188 void SendTunnelDataMsg (const std::vector<TunnelMessageBlock>& msgs); 189 void Print (std::stringstream& s) const; GetNumSentBytes()190 size_t GetNumSentBytes () const { return m_NumSentBytes; }; 191 192 private: 193 194 size_t m_NumSentBytes; 195 }; 196 197 class Tunnels 198 { 199 public: 200 201 Tunnels (); 202 ~Tunnels (); 203 void Start (); 204 void Stop (); 205 206 std::shared_ptr<InboundTunnel> GetPendingInboundTunnel (uint32_t replyMsgID); 207 std::shared_ptr<OutboundTunnel> GetPendingOutboundTunnel (uint32_t replyMsgID); 208 std::shared_ptr<InboundTunnel> GetNextInboundTunnel (); 209 std::shared_ptr<OutboundTunnel> GetNextOutboundTunnel (); GetExploratoryPool()210 std::shared_ptr<TunnelPool> GetExploratoryPool () const { return m_ExploratoryPool; }; 211 std::shared_ptr<TunnelBase> GetTunnel (uint32_t tunnelID); 212 int GetTransitTunnelsExpirationTimeout (); 213 void AddTransitTunnel (std::shared_ptr<TransitTunnel> tunnel); 214 void AddOutboundTunnel (std::shared_ptr<OutboundTunnel> newTunnel); 215 void AddInboundTunnel (std::shared_ptr<InboundTunnel> newTunnel); 216 std::shared_ptr<InboundTunnel> CreateInboundTunnel (std::shared_ptr<TunnelConfig> config, std::shared_ptr<TunnelPool> pool, std::shared_ptr<OutboundTunnel> outboundTunnel); 217 std::shared_ptr<OutboundTunnel> CreateOutboundTunnel (std::shared_ptr<TunnelConfig> config, std::shared_ptr<TunnelPool> pool); 218 void PostTunnelData (std::shared_ptr<I2NPMessage> msg); 219 void PostTunnelData (const std::vector<std::shared_ptr<I2NPMessage> >& msgs); 220 void AddPendingTunnel (uint32_t replyMsgID, std::shared_ptr<InboundTunnel> tunnel); 221 void AddPendingTunnel (uint32_t replyMsgID, std::shared_ptr<OutboundTunnel> tunnel); 222 std::shared_ptr<TunnelPool> CreateTunnelPool (int numInboundHops, 223 int numOuboundHops, int numInboundTunnels, int numOutboundTunnels); 224 void DeleteTunnelPool (std::shared_ptr<TunnelPool> pool); 225 void StopTunnelPool (std::shared_ptr<TunnelPool> pool); 226 227 std::shared_ptr<I2NPMessage> NewI2NPTunnelMessage (bool endpoint); 228 229 private: 230 231 template<class TTunnel> 232 std::shared_ptr<TTunnel> CreateTunnel (std::shared_ptr<TunnelConfig> config, 233 std::shared_ptr<TunnelPool> pool, std::shared_ptr<OutboundTunnel> outboundTunnel = nullptr); 234 235 template<class TTunnel> 236 std::shared_ptr<TTunnel> GetPendingTunnel (uint32_t replyMsgID, const std::map<uint32_t, std::shared_ptr<TTunnel> >& pendingTunnels); 237 238 void HandleTunnelGatewayMsg (std::shared_ptr<TunnelBase> tunnel, std::shared_ptr<I2NPMessage> msg); 239 240 void Run (); 241 void ManageTunnels (); 242 void ManageOutboundTunnels (); 243 void ManageInboundTunnels (); 244 void ManageTransitTunnels (); 245 void ManagePendingTunnels (); 246 template<class PendingTunnels> 247 void ManagePendingTunnels (PendingTunnels& pendingTunnels); 248 void ManageTunnelPools (uint64_t ts); 249 250 std::shared_ptr<ZeroHopsInboundTunnel> CreateZeroHopsInboundTunnel (std::shared_ptr<TunnelPool> pool); 251 std::shared_ptr<ZeroHopsOutboundTunnel> CreateZeroHopsOutboundTunnel (std::shared_ptr<TunnelPool> pool); 252 253 private: 254 255 bool m_IsRunning; 256 std::thread * m_Thread; 257 std::map<uint32_t, std::shared_ptr<InboundTunnel> > m_PendingInboundTunnels; // by replyMsgID 258 std::map<uint32_t, std::shared_ptr<OutboundTunnel> > m_PendingOutboundTunnels; // by replyMsgID 259 std::list<std::shared_ptr<InboundTunnel> > m_InboundTunnels; 260 std::list<std::shared_ptr<OutboundTunnel> > m_OutboundTunnels; 261 std::list<std::shared_ptr<TransitTunnel> > m_TransitTunnels; 262 std::unordered_map<uint32_t, std::shared_ptr<TunnelBase> > m_Tunnels; // tunnelID->tunnel known by this id 263 std::mutex m_PoolsMutex; 264 std::list<std::shared_ptr<TunnelPool>> m_Pools; 265 std::shared_ptr<TunnelPool> m_ExploratoryPool; 266 i2p::util::Queue<std::shared_ptr<I2NPMessage> > m_Queue; 267 i2p::util::MemoryPoolMt<I2NPMessageBuffer<I2NP_TUNNEL_ENPOINT_MESSAGE_SIZE> > m_I2NPTunnelEndpointMessagesMemoryPool; 268 i2p::util::MemoryPoolMt<I2NPMessageBuffer<I2NP_TUNNEL_MESSAGE_SIZE> > m_I2NPTunnelMessagesMemoryPool; 269 270 // some stats 271 int m_NumSuccesiveTunnelCreations, m_NumFailedTunnelCreations; 272 273 public: 274 275 // for HTTP only decltype(m_OutboundTunnels)276 const decltype(m_OutboundTunnels)& GetOutboundTunnels () const { return m_OutboundTunnels; }; decltype(m_InboundTunnels)277 const decltype(m_InboundTunnels)& GetInboundTunnels () const { return m_InboundTunnels; }; decltype(m_TransitTunnels)278 const decltype(m_TransitTunnels)& GetTransitTunnels () const { return m_TransitTunnels; }; 279 280 size_t CountTransitTunnels() const; 281 size_t CountInboundTunnels() const; 282 size_t CountOutboundTunnels() const; 283 GetQueueSize()284 int GetQueueSize () { return m_Queue.GetSize (); }; GetTunnelCreationSuccessRate()285 int GetTunnelCreationSuccessRate () const // in percents 286 { 287 int totalNum = m_NumSuccesiveTunnelCreations + m_NumFailedTunnelCreations; 288 return totalNum ? m_NumSuccesiveTunnelCreations*100/totalNum : 0; 289 } 290 }; 291 292 extern Tunnels tunnels; 293 } 294 } 295 296 #endif 297