mirror of https://github.com/PurpleI2P/i2pd.git
I2P: End-to-End encrypted and anonymous Internet
https://i2pd.website/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
202 lines
6.7 KiB
202 lines
6.7 KiB
/* |
|
* Copyright (c) 2013-2023, The PurpleI2P Project |
|
* |
|
* This file is part of Purple i2pd project and licensed under BSD3 |
|
* |
|
* See full license text in LICENSE file at top of project tree |
|
*/ |
|
|
|
#ifndef TRANSPORT_SESSION_H__ |
|
#define TRANSPORT_SESSION_H__ |
|
|
|
#include <inttypes.h> |
|
#include <iostream> |
|
#include <memory> |
|
#include <vector> |
|
#include <mutex> |
|
#include "Identity.h" |
|
#include "Crypto.h" |
|
#include "RouterInfo.h" |
|
#include "I2NPProtocol.h" |
|
#include "Timestamp.h" |
|
|
|
namespace i2p |
|
{ |
|
namespace transport |
|
{ |
|
const size_t IPV4_HEADER_SIZE = 20; |
|
const size_t IPV6_HEADER_SIZE = 40; |
|
const size_t UDP_HEADER_SIZE = 8; |
|
|
|
class SignedData |
|
{ |
|
public: |
|
|
|
SignedData () {} |
|
SignedData (const SignedData& other) |
|
{ |
|
m_Stream << other.m_Stream.rdbuf (); |
|
} |
|
|
|
void Reset () |
|
{ |
|
m_Stream.str(""); |
|
} |
|
|
|
void Insert (const uint8_t * buf, size_t len) |
|
{ |
|
m_Stream.write ((char *)buf, len); |
|
} |
|
|
|
template<typename T> |
|
void Insert (T t) |
|
{ |
|
m_Stream.write ((char *)&t, sizeof (T)); |
|
} |
|
|
|
bool Verify (std::shared_ptr<const i2p::data::IdentityEx> ident, const uint8_t * signature) const |
|
{ |
|
return ident->Verify ((const uint8_t *)m_Stream.str ().c_str (), m_Stream.str ().size (), signature); |
|
} |
|
|
|
void Sign (const i2p::data::PrivateKeys& keys, uint8_t * signature) const |
|
{ |
|
keys.Sign ((const uint8_t *)m_Stream.str ().c_str (), m_Stream.str ().size (), signature); |
|
} |
|
|
|
private: |
|
|
|
std::stringstream m_Stream; |
|
}; |
|
|
|
const int64_t TRANSPORT_SESSION_SLOWNESS_THRESHOLD = 500; // in milliseconds |
|
const int64_t TRANSPORT_SESSION_MAX_HANDSHAKE_INTERVAL = 10000; // in milliseconds |
|
const uint64_t TRANSPORT_SESSION_BANDWIDTH_UPDATE_MIN_INTERVAL = 5; // in seconds |
|
class TransportSession |
|
{ |
|
public: |
|
|
|
TransportSession (std::shared_ptr<const i2p::data::RouterInfo> router, int terminationTimeout): |
|
m_IsOutgoing (router), m_TerminationTimeout (terminationTimeout), m_HandshakeInterval (0), |
|
m_SendQueueSize (0), m_NumSentBytes (0), m_NumReceivedBytes (0), |
|
m_LastBandWidthUpdateNumSentBytes (0), m_LastBandWidthUpdateNumReceivedBytes (0), |
|
m_LastActivityTimestamp (i2p::util::GetSecondsSinceEpoch ()), |
|
m_LastBandwidthUpdateTimestamp (m_LastActivityTimestamp), m_InBandwidth (0), m_OutBandwidth (0) |
|
{ |
|
if (router) |
|
m_RemoteIdentity = router->GetRouterIdentity (); |
|
m_CreationTime = m_LastActivityTimestamp; |
|
} |
|
|
|
virtual ~TransportSession () {}; |
|
virtual void Done () = 0; |
|
|
|
std::string GetIdentHashBase64() const { return m_RemoteIdentity ? m_RemoteIdentity->GetIdentHash().ToBase64() : ""; } |
|
|
|
std::shared_ptr<const i2p::data::IdentityEx> GetRemoteIdentity () |
|
{ |
|
std::lock_guard<std::mutex> l(m_RemoteIdentityMutex); |
|
return m_RemoteIdentity; |
|
} |
|
void SetRemoteIdentity (std::shared_ptr<const i2p::data::IdentityEx> ident) |
|
{ |
|
std::lock_guard<std::mutex> l(m_RemoteIdentityMutex); |
|
m_RemoteIdentity = ident; |
|
} |
|
|
|
size_t GetNumSentBytes () const { return m_NumSentBytes; }; |
|
void UpdateNumSentBytes (size_t len) |
|
{ |
|
m_LastActivityTimestamp = i2p::util::GetSecondsSinceEpoch (); |
|
m_NumSentBytes += len; |
|
UpdateBandwidth (); |
|
} |
|
size_t GetNumReceivedBytes () const { return m_NumReceivedBytes; }; |
|
void UpdateNumReceivedBytes (size_t len) |
|
{ |
|
m_LastActivityTimestamp = i2p::util::GetSecondsSinceEpoch (); |
|
m_NumReceivedBytes += len; |
|
UpdateBandwidth (); |
|
} |
|
size_t GetSendQueueSize () const { return m_SendQueueSize; }; |
|
void SetSendQueueSize (size_t s) { m_SendQueueSize = s; }; |
|
bool IsOutgoing () const { return m_IsOutgoing; }; |
|
bool IsSlow () const { return m_HandshakeInterval > TRANSPORT_SESSION_SLOWNESS_THRESHOLD && |
|
m_HandshakeInterval < TRANSPORT_SESSION_MAX_HANDSHAKE_INTERVAL; }; |
|
bool IsBandwidthExceeded (bool isHighBandwidth) const |
|
{ |
|
auto limit = isHighBandwidth ? i2p::data::HIGH_BANDWIDTH_LIMIT*1024 : i2p::data::LOW_BANDWIDTH_LIMIT*1024; // convert to bytes |
|
return std::max (m_InBandwidth, m_OutBandwidth) > limit; |
|
} |
|
|
|
int GetTerminationTimeout () const { return m_TerminationTimeout; }; |
|
void SetTerminationTimeout (int terminationTimeout) { m_TerminationTimeout = terminationTimeout; }; |
|
bool IsTerminationTimeoutExpired (uint64_t ts) const |
|
{ |
|
return ts >= m_LastActivityTimestamp + GetTerminationTimeout () || |
|
ts + GetTerminationTimeout () < m_LastActivityTimestamp; |
|
}; |
|
|
|
uint32_t GetCreationTime () const { return m_CreationTime; }; |
|
void SetCreationTime (uint32_t ts) { m_CreationTime = ts; }; // for introducers |
|
|
|
uint64_t GetLastActivityTimestamp () const { return m_LastActivityTimestamp; }; |
|
void SetLastActivityTimestamp (uint64_t ts) { m_LastActivityTimestamp = ts; }; |
|
|
|
virtual uint32_t GetRelayTag () const { return 0; }; |
|
virtual void SendLocalRouterInfo (bool update = false) { SendI2NPMessages ({ CreateDatabaseStoreMsg () }); }; |
|
virtual void SendI2NPMessages (const std::vector<std::shared_ptr<I2NPMessage> >& msgs) = 0; |
|
virtual bool IsEstablished () const = 0; |
|
|
|
private: |
|
|
|
void UpdateBandwidth () |
|
{ |
|
int64_t interval = m_LastActivityTimestamp - m_LastBandwidthUpdateTimestamp; |
|
if (interval < 0 || interval > 60*10) // 10 minutes |
|
{ |
|
// clock was adjusted, copy new values |
|
m_LastBandWidthUpdateNumSentBytes = m_NumSentBytes; |
|
m_LastBandWidthUpdateNumReceivedBytes = m_NumReceivedBytes; |
|
m_LastBandwidthUpdateTimestamp = m_LastActivityTimestamp; |
|
return; |
|
} |
|
if ((uint64_t)interval > TRANSPORT_SESSION_BANDWIDTH_UPDATE_MIN_INTERVAL) |
|
{ |
|
m_OutBandwidth = (m_NumSentBytes - m_LastBandWidthUpdateNumSentBytes)/interval; |
|
m_LastBandWidthUpdateNumSentBytes = m_NumSentBytes; |
|
m_InBandwidth = (m_NumReceivedBytes - m_LastBandWidthUpdateNumReceivedBytes)/interval; |
|
m_LastBandWidthUpdateNumReceivedBytes = m_NumReceivedBytes; |
|
m_LastBandwidthUpdateTimestamp = m_LastActivityTimestamp; |
|
} |
|
} |
|
|
|
protected: |
|
|
|
std::shared_ptr<const i2p::data::IdentityEx> m_RemoteIdentity; |
|
mutable std::mutex m_RemoteIdentityMutex; |
|
bool m_IsOutgoing; |
|
int m_TerminationTimeout; |
|
uint32_t m_CreationTime; // seconds since epoch |
|
int64_t m_HandshakeInterval; // in milliseconds between SessionRequest->SessionCreated or SessionCreated->SessionConfirmed |
|
|
|
private: |
|
|
|
size_t m_SendQueueSize, m_NumSentBytes, m_NumReceivedBytes, |
|
m_LastBandWidthUpdateNumSentBytes, m_LastBandWidthUpdateNumReceivedBytes; |
|
uint64_t m_LastActivityTimestamp, m_LastBandwidthUpdateTimestamp; |
|
uint32_t m_InBandwidth, m_OutBandwidth; |
|
}; |
|
|
|
// SOCKS5 proxy |
|
const uint8_t SOCKS5_VER = 0x05; |
|
const uint8_t SOCKS5_CMD_CONNECT = 0x01; |
|
const uint8_t SOCKS5_CMD_UDP_ASSOCIATE = 0x03; |
|
const uint8_t SOCKS5_ATYP_IPV4 = 0x01; |
|
const uint8_t SOCKS5_ATYP_IPV6 = 0x04; |
|
const size_t SOCKS5_UDP_IPV4_REQUEST_HEADER_SIZE = 10; |
|
const size_t SOCKS5_UDP_IPV6_REQUEST_HEADER_SIZE = 22; |
|
} |
|
} |
|
|
|
#endif
|
|
|