mirror of https://github.com/PurpleI2P/i2pd.git
orignal
11 years ago
3 changed files with 854 additions and 0 deletions
@ -0,0 +1,487 @@
@@ -0,0 +1,487 @@
|
||||
#include <cryptopp/sha.h> |
||||
#include "RouterContext.h" |
||||
#include "Log.h" |
||||
#include "Timestamp.h" |
||||
#include "I2NPProtocol.h" |
||||
#include "Transports.h" |
||||
#include "NetDb.h" |
||||
#include "Tunnel.h" |
||||
|
||||
namespace i2p |
||||
{ |
||||
namespace tunnel |
||||
{ |
||||
|
||||
Tunnel::Tunnel (TunnelConfig * config): m_Config (config), |
||||
m_CreationTime (i2p::util::GetSecondsSinceEpoch ()), m_IsEstablished (false) |
||||
{ |
||||
} |
||||
|
||||
Tunnel::~Tunnel () |
||||
{ |
||||
delete m_Config; |
||||
} |
||||
|
||||
void Tunnel::Build (uint32_t replyMsgID, OutboundTunnel * outboundTunnel) |
||||
{ |
||||
CryptoPP::RandomNumberGenerator& rnd = i2p::context.GetRandomNumberGenerator (); |
||||
size_t numRecords = m_Config->GetNumHops (); |
||||
I2NPMessage * msg = NewI2NPMessage (); |
||||
*msg->GetPayload () = numRecords; |
||||
msg->len += numRecords*sizeof (I2NPBuildRequestRecordElGamalEncrypted) + 1; |
||||
|
||||
I2NPBuildRequestRecordElGamalEncrypted * records = (I2NPBuildRequestRecordElGamalEncrypted *)(msg->GetPayload () + 1); |
||||
|
||||
TunnelHopConfig * hop = m_Config->GetFirstHop (); |
||||
int i = 0; |
||||
while (hop) |
||||
{ |
||||
EncryptBuildRequestRecord (*hop->router, |
||||
CreateBuildRequestRecord (hop->router->GetIdentHash (), |
||||
hop->tunnelID, |
||||
hop->nextRouter->GetIdentHash (), |
||||
hop->nextTunnelID, |
||||
hop->layerKey, hop->ivKey, |
||||
hop->replyKey, hop->replyIV, |
||||
hop->next ? rnd.GenerateWord32 () : replyMsgID, // we set replyMsgID for last hop only
|
||||
hop->isGateway, hop->isEndpoint), |
||||
records[i]); |
||||
i++; |
||||
hop = hop->next; |
||||
} |
||||
|
||||
hop = m_Config->GetLastHop ()->prev; |
||||
size_t ind = numRecords - 1; |
||||
while (hop) |
||||
{ |
||||
for (size_t i = ind; i < numRecords; i++) |
||||
{ |
||||
m_CBCDecryption.SetKeyWithIV (hop->replyKey, 32, hop->replyIV); |
||||
m_CBCDecryption.ProcessData((uint8_t *)&records[i], (uint8_t *)&records[i], sizeof (I2NPBuildRequestRecordElGamalEncrypted)); |
||||
} |
||||
hop = hop->prev; |
||||
ind--; |
||||
} |
||||
FillI2NPMessageHeader (msg, eI2NPVariableTunnelBuild); |
||||
|
||||
if (outboundTunnel) |
||||
{ |
||||
outboundTunnel->SendTunnelDataMsg (GetNextIdentHash (), 0, msg); |
||||
DeleteI2NPMessage (msg); |
||||
} |
||||
else |
||||
{ |
||||
i2p::transports.SendMessage (GetNextIdentHash (), msg); |
||||
} |
||||
} |
||||
|
||||
bool Tunnel::HandleTunnelBuildResponse (uint8_t * msg, size_t len) |
||||
{ |
||||
LogPrint ("TunnelBuildResponse ", (int)msg[0], " records."); |
||||
|
||||
TunnelHopConfig * hop = m_Config->GetLastHop (); |
||||
int num = msg[0]; |
||||
while (hop) |
||||
{ |
||||
for (int i = 0; i < num; i++) |
||||
{ |
||||
uint8_t * record = msg + 1 + i*sizeof (I2NPBuildResponseRecord); |
||||
m_CBCDecryption.SetKeyWithIV(hop->replyKey, 32, hop->replyIV); |
||||
m_CBCDecryption.ProcessData(record, record, sizeof (I2NPBuildResponseRecord)); |
||||
} |
||||
hop = hop->prev; |
||||
num--; |
||||
} |
||||
|
||||
m_IsEstablished = true; |
||||
for (int i = 0; i < msg[0]; i++) |
||||
{ |
||||
I2NPBuildResponseRecord * record = (I2NPBuildResponseRecord *)(msg + 1 + i*sizeof (I2NPBuildResponseRecord)); |
||||
LogPrint ("Ret code=", (int)record->ret); |
||||
if (record->ret) |
||||
// if any of participants declined the tunnel is not established
|
||||
m_IsEstablished = false; |
||||
} |
||||
return m_IsEstablished; |
||||
} |
||||
|
||||
void Tunnel::LayerDecrypt (const uint8_t * in, size_t len, const uint8_t * layerKey, |
||||
const uint8_t * iv, uint8_t * out) |
||||
{ |
||||
m_CBCDecryption.SetKeyWithIV (layerKey, 32, iv); |
||||
m_CBCDecryption.ProcessData(out, in, len); |
||||
} |
||||
|
||||
void Tunnel::IVDecrypt (const uint8_t * in, const uint8_t * ivKey, uint8_t * out) |
||||
{ |
||||
m_ECBDecryption.SetKey (ivKey, 32); |
||||
m_ECBDecryption.ProcessData(out, in, 16); |
||||
} |
||||
|
||||
void Tunnel::EncryptTunnelMsg (I2NPMessage * tunnelMsg) |
||||
{ |
||||
uint8_t * payload = tunnelMsg->GetPayload () + 4; |
||||
TunnelHopConfig * hop = m_Config->GetLastHop (); |
||||
while (hop) |
||||
{ |
||||
// iv + data
|
||||
IVDecrypt (payload, hop->ivKey, payload); |
||||
LayerDecrypt (payload + 16, TUNNEL_DATA_ENCRYPTED_SIZE, hop->layerKey, payload, payload+16); |
||||
IVDecrypt (payload, hop->ivKey, payload); |
||||
hop = hop->prev; |
||||
} |
||||
} |
||||
|
||||
void InboundTunnel::HandleTunnelDataMsg (I2NPMessage * msg) |
||||
{ |
||||
EncryptTunnelMsg (msg); |
||||
m_Endpoint.HandleDecryptedTunnelDataMsg (msg); |
||||
} |
||||
|
||||
void OutboundTunnel::SendTunnelDataMsg (const uint8_t * gwHash, uint32_t gwTunnel, i2p::I2NPMessage * msg) |
||||
{ |
||||
m_Gateway.SendTunnelDataMsg (gwHash, gwTunnel, msg); |
||||
} |
||||
|
||||
void OutboundTunnel::SendTunnelDataMsg (i2p::I2NPMessage * msg) |
||||
{ |
||||
SendTunnelDataMsg (nullptr, 0, msg); |
||||
} |
||||
|
||||
|
||||
Tunnels tunnels; |
||||
|
||||
Tunnels::Tunnels (): m_IsRunning (false), m_IsTunnelCreated (false), m_NextReplyMsgID (555), |
||||
m_ZeroHopsInboundTunnel (nullptr), m_ZeroHopsOutboundTunnel (nullptr), m_Thread (0) |
||||
{ |
||||
} |
||||
|
||||
Tunnels::~Tunnels () |
||||
{ |
||||
for (auto& it : m_OutboundTunnels) |
||||
delete it; |
||||
m_OutboundTunnels.clear (); |
||||
|
||||
for (auto& it : m_InboundTunnels) |
||||
delete it.second; |
||||
m_InboundTunnels.clear (); |
||||
|
||||
for (auto& it : m_TransitTunnels) |
||||
delete it.second; |
||||
m_TransitTunnels.clear (); |
||||
|
||||
for (auto& it : m_PendingTunnels) |
||||
delete it.second; |
||||
m_PendingTunnels.clear (); |
||||
|
||||
delete m_ZeroHopsInboundTunnel; |
||||
delete m_ZeroHopsOutboundTunnel; |
||||
} |
||||
|
||||
InboundTunnel * Tunnels::GetInboundTunnel (uint32_t tunnelID) |
||||
{ |
||||
auto it = m_InboundTunnels.find(tunnelID); |
||||
if (it != m_InboundTunnels.end ()) |
||||
return it->second; |
||||
return nullptr; |
||||
} |
||||
|
||||
TransitTunnel * Tunnels::GetTransitTunnel (uint32_t tunnelID) |
||||
{ |
||||
auto it = m_TransitTunnels.find(tunnelID); |
||||
if (it != m_TransitTunnels.end ()) |
||||
return it->second; |
||||
return nullptr; |
||||
} |
||||
|
||||
Tunnel * Tunnels::GetPendingTunnel (uint32_t replyMsgID) |
||||
{ |
||||
auto it = m_PendingTunnels.find(replyMsgID); |
||||
if (it != m_PendingTunnels.end ()) |
||||
{ |
||||
Tunnel * t = it->second; |
||||
m_PendingTunnels.erase (it); |
||||
return t; |
||||
} |
||||
return nullptr; |
||||
} |
||||
|
||||
InboundTunnel * Tunnels::GetNextInboundTunnel () |
||||
{ |
||||
InboundTunnel * tunnel = nullptr; |
||||
size_t minReceived = 0; |
||||
for (auto it : m_InboundTunnels) |
||||
if (!tunnel || it.second->GetNumReceivedBytes () < minReceived) |
||||
{ |
||||
tunnel = it.second; |
||||
minReceived = it.second->GetNumReceivedBytes (); |
||||
} |
||||
return tunnel; |
||||
} |
||||
|
||||
OutboundTunnel * Tunnels::GetNextOutboundTunnel () |
||||
{ |
||||
OutboundTunnel * tunnel = nullptr; |
||||
size_t minSent = 0; |
||||
for (auto it : m_OutboundTunnels) |
||||
if (!tunnel || it->GetNumSentBytes () < minSent) |
||||
{ |
||||
tunnel = it; |
||||
minSent = it->GetNumSentBytes (); |
||||
} |
||||
return tunnel; |
||||
} |
||||
|
||||
void Tunnels::AddTransitTunnel (TransitTunnel * tunnel) |
||||
{ |
||||
m_TransitTunnels[tunnel->GetTunnelID ()] = tunnel; |
||||
} |
||||
|
||||
void Tunnels::Start () |
||||
{ |
||||
m_IsRunning = true; |
||||
m_Thread = new std::thread (std::bind (&Tunnels::Run, this)); |
||||
} |
||||
|
||||
void Tunnels::Stop () |
||||
{ |
||||
m_IsRunning = false; |
||||
m_Queue.WakeUp (); |
||||
if (m_Thread) |
||||
{ |
||||
m_Thread->join (); |
||||
delete m_Thread; |
||||
m_Thread = 0; |
||||
} |
||||
} |
||||
|
||||
void Tunnels::Run () |
||||
{ |
||||
sleep (1); // wait for other parts are ready
|
||||
|
||||
// we must start with zero hops tunnels
|
||||
CreateZeroHopsInboundTunnel (); |
||||
CreateZeroHopsOutboundTunnel (); |
||||
|
||||
uint32_t lastTs = 0; |
||||
while (m_IsRunning) |
||||
{ |
||||
try |
||||
{ |
||||
I2NPMessage * msg = m_Queue.GetNextWithTimeout (1000); // 1 sec
|
||||
while (msg) |
||||
{ |
||||
uint32_t tunnelID = be32toh (*(uint32_t *)msg->GetPayload ()); |
||||
InboundTunnel * tunnel = GetInboundTunnel (tunnelID); |
||||
if (tunnel) |
||||
tunnel->HandleTunnelDataMsg (msg); |
||||
else |
||||
{ |
||||
TransitTunnel * transitTunnel = GetTransitTunnel (tunnelID); |
||||
if (transitTunnel) |
||||
transitTunnel->HandleTunnelDataMsg (msg); |
||||
else |
||||
{ |
||||
LogPrint ("Tunnel ", tunnelID, " not found"); |
||||
i2p::DeleteI2NPMessage (msg); |
||||
} |
||||
} |
||||
msg = m_Queue.Get (); |
||||
} |
||||
|
||||
uint32_t ts = i2p::util::GetSecondsSinceEpoch (); |
||||
if (ts - lastTs >= 15) // manage tunnels every 15 seconds
|
||||
{ |
||||
ManageTunnels (); |
||||
lastTs = ts; |
||||
} |
||||
} |
||||
catch (std::exception& ex) |
||||
{ |
||||
LogPrint ("Tunnels: ", ex.what ()); |
||||
} |
||||
} |
||||
} |
||||
|
||||
void Tunnels::ManageTunnels () |
||||
{ |
||||
// check pending tunnel. if something is still there, wipe it out
|
||||
// because it wouldn't be reponded anyway
|
||||
for (auto& it : m_PendingTunnels) |
||||
{ |
||||
LogPrint ("Pending tunnel build request ", it.first, " has not been responded. Deleted"); |
||||
delete it.second; |
||||
} |
||||
m_PendingTunnels.clear (); |
||||
|
||||
ManageOutboundTunnels (); |
||||
ManageInboundTunnels (); |
||||
|
||||
/* if (!m_IsTunnelCreated)
|
||||
{ |
||||
InboundTunnel * inboundTunnel = CreateOneHopInboundTestTunnel (); |
||||
if (inboundTunnel) |
||||
CreateOneHopOutboundTestTunnel (inboundTunnel); |
||||
inboundTunnel = CreateTwoHopsInboundTestTunnel (); |
||||
if (inboundTunnel) |
||||
CreateTwoHopsOutboundTestTunnel (inboundTunnel); |
||||
|
||||
m_IsTunnelCreated = true; |
||||
}*/ |
||||
} |
||||
|
||||
void Tunnels::ManageOutboundTunnels () |
||||
{ |
||||
uint32_t ts = i2p::util::GetSecondsSinceEpoch (); |
||||
for (auto it = m_OutboundTunnels.begin (); it != m_OutboundTunnels.end ();) |
||||
{ |
||||
if (ts > (*it)->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT) |
||||
{ |
||||
LogPrint ("Tunnel ", (*it)->GetTunnelID (), " expired"); |
||||
it = m_OutboundTunnels.erase (it); |
||||
} |
||||
else |
||||
it++; |
||||
} |
||||
|
||||
if (m_OutboundTunnels.size () < 10) |
||||
{ |
||||
// trying to create one more oubound tunnel
|
||||
InboundTunnel * inboundTunnel = m_ZeroHopsInboundTunnel; |
||||
if (!m_InboundTunnels.empty ()) |
||||
inboundTunnel = m_InboundTunnels.rbegin ()->second; |
||||
|
||||
if (m_OutboundTunnels.empty () || m_OutboundTunnels.size () < 3) |
||||
{ |
||||
LogPrint ("Creating one hop outbound tunnel..."); |
||||
CreateTunnel<OutboundTunnel> ( |
||||
new TunnelConfig (i2p::data::netdb.GetRandomNTCPRouter (), |
||||
inboundTunnel->GetTunnelConfig ())); |
||||
} |
||||
else |
||||
{ |
||||
OutboundTunnel * outboundTunnel = *m_OutboundTunnels.begin (); |
||||
LogPrint ("Creating two hops outbound tunnel..."); |
||||
CreateTunnel<OutboundTunnel> ( |
||||
new TunnelConfig (inboundTunnel->GetTunnelConfig ()->GetFirstHop ()->router, |
||||
i2p::data::netdb.GetRandomNTCPRouter (), |
||||
inboundTunnel->GetTunnelConfig ()), |
||||
outboundTunnel); |
||||
} |
||||
} |
||||
} |
||||
|
||||
void Tunnels::ManageInboundTunnels () |
||||
{ |
||||
uint32_t ts = i2p::util::GetSecondsSinceEpoch (); |
||||
for (auto it = m_InboundTunnels.begin (); it != m_InboundTunnels.end ();) |
||||
{ |
||||
if (ts > it->second->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT) |
||||
{ |
||||
LogPrint ("Tunnel ", it->second->GetTunnelID (), " expired"); |
||||
it = m_InboundTunnels.erase (it); |
||||
} |
||||
else |
||||
it++; |
||||
} |
||||
|
||||
if (m_InboundTunnels.size () < 10) |
||||
{ |
||||
// trying to create one more inbound tunnel
|
||||
if (m_OutboundTunnels.empty () || m_InboundTunnels.size () < 3) |
||||
{ |
||||
LogPrint ("Creating one hop inbound tunnel..."); |
||||
CreateTunnel<InboundTunnel> (new TunnelConfig (i2p::data::netdb.GetRandomNTCPRouter ())); |
||||
} |
||||
else |
||||
{ |
||||
OutboundTunnel * outboundTunnel = *m_OutboundTunnels.rbegin (); |
||||
InboundTunnel * inboundTunnel = m_InboundTunnels.rbegin ()->second; |
||||
LogPrint ("Creating two hops inbound tunnel..."); |
||||
CreateTunnel<InboundTunnel> ( |
||||
new TunnelConfig (i2p::data::netdb.GetRandomNTCPRouter (), |
||||
inboundTunnel->GetTunnelConfig ()->GetFirstHop ()->router), |
||||
outboundTunnel); |
||||
} |
||||
} |
||||
} |
||||
|
||||
void Tunnels::PostTunnelData (I2NPMessage * msg) |
||||
{ |
||||
if (msg) m_Queue.Put (msg); |
||||
} |
||||
|
||||
template<class TTunnel> |
||||
TTunnel * Tunnels::CreateTunnel (TunnelConfig * config, OutboundTunnel * outboundTunnel) |
||||
{ |
||||
TTunnel * newTunnel = new TTunnel (config); |
||||
m_PendingTunnels[m_NextReplyMsgID] = newTunnel; |
||||
newTunnel->Build (m_NextReplyMsgID, outboundTunnel); |
||||
m_NextReplyMsgID++; // TODO: should be atomic
|
||||
return newTunnel; |
||||
} |
||||
|
||||
void Tunnels::AddOutboundTunnel (OutboundTunnel * newTunnel) |
||||
{ |
||||
if (newTunnel != m_ZeroHopsOutboundTunnel) |
||||
m_OutboundTunnels.push_back (newTunnel); |
||||
} |
||||
|
||||
void Tunnels::AddInboundTunnel (InboundTunnel * newTunnel) |
||||
{ |
||||
if (newTunnel != m_ZeroHopsInboundTunnel) |
||||
m_InboundTunnels[newTunnel->GetTunnelID ()] = newTunnel; |
||||
} |
||||
|
||||
void Tunnels::CreateZeroHopsOutboundTunnel () |
||||
{ |
||||
m_ZeroHopsOutboundTunnel = CreateTunnel<OutboundTunnel> ( |
||||
new TunnelConfig (&i2p::context.GetRouterInfo (), |
||||
m_ZeroHopsInboundTunnel->GetTunnelConfig ())); |
||||
} |
||||
|
||||
void Tunnels::CreateZeroHopsInboundTunnel () |
||||
{ |
||||
m_ZeroHopsInboundTunnel = CreateTunnel<InboundTunnel> ( |
||||
new TunnelConfig (&i2p::context.GetRouterInfo ())); |
||||
} |
||||
|
||||
OutboundTunnel * Tunnels::CreateOneHopOutboundTestTunnel (InboundTunnel * replyTunnel) |
||||
{ |
||||
return CreateTunnel<OutboundTunnel> (replyTunnel->GetTunnelConfig ()->Invert ()); |
||||
} |
||||
|
||||
InboundTunnel * Tunnels::CreateOneHopInboundTestTunnel (OutboundTunnel * outboundTunnel) |
||||
{ |
||||
i2p::ntcp::NTCPSession * peer = i2p::transports.GetNextNTCPSession (); |
||||
if (peer) |
||||
{ |
||||
const i2p::data::RouterInfo& router = peer->GetRemoteRouterInfo (); |
||||
return CreateTunnel<InboundTunnel> (new TunnelConfig (&router), outboundTunnel); |
||||
} |
||||
else |
||||
LogPrint ("No established peers"); |
||||
return 0; |
||||
} |
||||
|
||||
OutboundTunnel * Tunnels::CreateTwoHopsOutboundTestTunnel (InboundTunnel * replyTunnel) |
||||
{ |
||||
return CreateTunnel<OutboundTunnel> (replyTunnel->GetTunnelConfig ()->Invert ()); |
||||
} |
||||
|
||||
InboundTunnel * Tunnels::CreateTwoHopsInboundTestTunnel (OutboundTunnel * outboundTunnel) |
||||
{ |
||||
i2p::ntcp::NTCPSession * peer = i2p::transports.GetNextNTCPSession (); |
||||
if (peer) |
||||
{ |
||||
const i2p::data::RouterInfo& router = peer->GetRemoteRouterInfo (); |
||||
return CreateTunnel<InboundTunnel> ( |
||||
new TunnelConfig (&router, &i2p::context.GetRouterInfo ()), |
||||
outboundTunnel); |
||||
} |
||||
else |
||||
LogPrint ("No established peers"); |
||||
return 0; |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,160 @@
@@ -0,0 +1,160 @@
|
||||
#ifndef TUNNEL_H__ |
||||
#define TUNNEL_H__ |
||||
|
||||
#include <inttypes.h> |
||||
#include <map> |
||||
#include <list> |
||||
#include <string> |
||||
#include <thread> |
||||
#include <cryptopp/modes.h> |
||||
#include <cryptopp/aes.h> |
||||
#include "Queue.h" |
||||
#include "TunnelConfig.h" |
||||
#include "TransitTunnel.h" |
||||
#include "TunnelEndpoint.h" |
||||
#include "TunnelGateway.h" |
||||
#include "TunnelBase.h" |
||||
#include "I2NPProtocol.h" |
||||
|
||||
namespace i2p |
||||
{ |
||||
namespace tunnel |
||||
{ |
||||
const int TUNNEL_EXPIRATION_TIMEOUT = 600; // 10 minutes
|
||||
|
||||
class OutboundTunnel; |
||||
class InboundTunnel; |
||||
class Tunnel: public TunnelBase |
||||
{ |
||||
public: |
||||
|
||||
Tunnel (TunnelConfig * config); |
||||
~Tunnel (); |
||||
|
||||
void Build (uint32_t replyMsgID, OutboundTunnel * outboundTunnel = 0); |
||||
|
||||
virtual uint32_t GetTunnelID () const = 0; // as known at our side
|
||||
TunnelConfig * GetTunnelConfig () const { return m_Config; } |
||||
uint32_t GetCreationTime () const { return m_CreationTime; }; |
||||
bool IsEstablished () const { return m_IsEstablished; }; |
||||
|
||||
bool HandleTunnelBuildResponse (uint8_t * msg, size_t len); |
||||
|
||||
// implements TunnelBase
|
||||
void EncryptTunnelMsg (I2NPMessage * tunnelMsg); |
||||
uint32_t GetNextTunnelID () const { return m_Config->GetFirstHop ()->tunnelID; }; |
||||
const i2p::data::IdentHash& GetNextIdentHash () const { return m_Config->GetFirstHop ()->router->GetIdentHash (); }; |
||||
|
||||
private: |
||||
|
||||
void LayerDecrypt (const uint8_t * in, size_t len, const uint8_t * layerKey, |
||||
const uint8_t * iv, uint8_t * out); |
||||
void IVDecrypt (const uint8_t * in, const uint8_t * ivKey, uint8_t * out); |
||||
|
||||
private: |
||||
|
||||
TunnelConfig * m_Config; |
||||
uint32_t m_CreationTime; // seconds since epoch
|
||||
bool m_IsEstablished; |
||||
|
||||
CryptoPP::ECB_Mode<CryptoPP::AES>::Decryption m_ECBDecryption; |
||||
CryptoPP::CBC_Mode<CryptoPP::AES>::Decryption m_CBCDecryption; |
||||
}; |
||||
|
||||
class OutboundTunnel: public Tunnel |
||||
{ |
||||
public: |
||||
|
||||
OutboundTunnel (TunnelConfig * config): Tunnel (config), m_Gateway (this) {}; |
||||
|
||||
void SendTunnelDataMsg (i2p::I2NPMessage * msg); //local
|
||||
void SendTunnelDataMsg (const uint8_t * gwHash, uint32_t gwTunnel, i2p::I2NPMessage * msg); |
||||
|
||||
uint32_t GetTunnelID () const { return GetNextTunnelID (); }; |
||||
TunnelGateway& GetTunnelGateway () { return m_Gateway; }; |
||||
size_t GetNumSentBytes () const { return m_Gateway.GetNumSentBytes (); }; |
||||
|
||||
private: |
||||
|
||||
TunnelGateway m_Gateway; |
||||
}; |
||||
|
||||
class InboundTunnel: public Tunnel |
||||
{ |
||||
public: |
||||
|
||||
InboundTunnel (TunnelConfig * config): Tunnel (config) {}; |
||||
void HandleTunnelDataMsg (I2NPMessage * msg); |
||||
|
||||
uint32_t GetTunnelID () const { return GetTunnelConfig ()->GetLastHop ()->nextTunnelID; }; |
||||
size_t GetNumReceivedBytes () const { return m_Endpoint.GetNumReceivedBytes (); }; |
||||
|
||||
private: |
||||
|
||||
TunnelEndpoint m_Endpoint; |
||||
}; |
||||
|
||||
|
||||
class Tunnels |
||||
{ |
||||
public: |
||||
|
||||
Tunnels (); |
||||
~Tunnels (); |
||||
|
||||
void Start (); |
||||
void Stop (); |
||||
|
||||
InboundTunnel * GetInboundTunnel (uint32_t tunnelID); |
||||
Tunnel * GetPendingTunnel (uint32_t replyMsgID); |
||||
InboundTunnel * GetNextInboundTunnel (); |
||||
OutboundTunnel * GetNextOutboundTunnel (); |
||||
TransitTunnel * GetTransitTunnel (uint32_t tunnelID); |
||||
void AddTransitTunnel (TransitTunnel * tunnel); |
||||
void AddOutboundTunnel (OutboundTunnel * newTunnel); |
||||
void AddInboundTunnel (InboundTunnel * newTunnel); |
||||
void PostTunnelData (I2NPMessage * msg); |
||||
template<class TTunnel> |
||||
TTunnel * CreateTunnel (TunnelConfig * config, OutboundTunnel * outboundTunnel = 0); |
||||
|
||||
OutboundTunnel * CreateOneHopOutboundTestTunnel (InboundTunnel * replyTunnel); |
||||
InboundTunnel * CreateOneHopInboundTestTunnel (OutboundTunnel * outboundTunnel = 0); |
||||
OutboundTunnel * CreateTwoHopsOutboundTestTunnel (InboundTunnel * replyTunnel); |
||||
InboundTunnel * CreateTwoHopsInboundTestTunnel (OutboundTunnel * outboundTunnel = 0); |
||||
|
||||
private: |
||||
|
||||
void Run (); |
||||
void ManageTunnels (); |
||||
void ManageOutboundTunnels (); |
||||
void ManageInboundTunnels (); |
||||
|
||||
void CreateZeroHopsOutboundTunnel (); |
||||
void CreateZeroHopsInboundTunnel (); |
||||
|
||||
private: |
||||
|
||||
bool m_IsRunning; |
||||
bool m_IsTunnelCreated; // TODO: temporary
|
||||
uint32_t m_NextReplyMsgID; // TODO: make it random later
|
||||
InboundTunnel * m_ZeroHopsInboundTunnel; |
||||
OutboundTunnel * m_ZeroHopsOutboundTunnel; |
||||
std::thread * m_Thread; |
||||
std::map<uint32_t, Tunnel *> m_PendingTunnels; // by replyMsgID
|
||||
std::map<uint32_t, InboundTunnel *> m_InboundTunnels; |
||||
std::list<OutboundTunnel *> m_OutboundTunnels; |
||||
std::map<uint32_t, TransitTunnel *> m_TransitTunnels; |
||||
i2p::util::Queue<I2NPMessage> m_Queue; |
||||
|
||||
public: |
||||
|
||||
// for HTTP only
|
||||
const decltype(m_OutboundTunnels)& GetOutboundTunnels () const { return m_OutboundTunnels; }; |
||||
const decltype(m_InboundTunnels)& GetInboundTunnels () const { return m_InboundTunnels; }; |
||||
}; |
||||
|
||||
extern Tunnels tunnels; |
||||
} |
||||
} |
||||
|
||||
#endif |
@ -0,0 +1,207 @@
@@ -0,0 +1,207 @@
|
||||
#ifndef TUNNEL_CONFIG_H__ |
||||
#define TUNNEL_CONFIG_H__ |
||||
|
||||
#include <inttypes.h> |
||||
#include <sstream> |
||||
#include "RouterInfo.h" |
||||
#include "RouterContext.h" |
||||
|
||||
namespace i2p |
||||
{ |
||||
namespace tunnel |
||||
{ |
||||
struct TunnelHopConfig |
||||
{ |
||||
const i2p::data::RouterInfo * router, * nextRouter; |
||||
uint32_t tunnelID, nextTunnelID; |
||||
uint8_t layerKey[32]; |
||||
uint8_t ivKey[32]; |
||||
uint8_t replyKey[32]; |
||||
uint8_t replyIV[16]; |
||||
bool isGateway, isEndpoint; |
||||
|
||||
TunnelHopConfig * next, * prev; |
||||
|
||||
TunnelHopConfig (const i2p::data::RouterInfo * r) |
||||
{ |
||||
CryptoPP::RandomNumberGenerator& rnd = i2p::context.GetRandomNumberGenerator (); |
||||
rnd.GenerateBlock (layerKey, 32); |
||||
rnd.GenerateBlock (ivKey, 32); |
||||
rnd.GenerateBlock (replyIV, 16); |
||||
tunnelID = rnd.GenerateWord32 (); |
||||
isGateway = true; |
||||
isEndpoint = true; |
||||
router = r; |
||||
nextRouter = 0; |
||||
nextTunnelID = 0; |
||||
|
||||
next = 0; |
||||
prev = 0; |
||||
} |
||||
|
||||
void SetNextRouter (const i2p::data::RouterInfo * r) |
||||
{ |
||||
nextRouter = r; |
||||
isEndpoint = false; |
||||
CryptoPP::RandomNumberGenerator& rnd = i2p::context.GetRandomNumberGenerator (); |
||||
nextTunnelID = rnd.GenerateWord32 (); |
||||
} |
||||
|
||||
void SetReplyHop (TunnelHopConfig * replyFirstHop) |
||||
{ |
||||
nextRouter = replyFirstHop->router; |
||||
nextTunnelID = replyFirstHop->tunnelID; |
||||
isEndpoint = true; |
||||
} |
||||
|
||||
void SetNext (TunnelHopConfig * n) |
||||
{ |
||||
next = n; |
||||
if (next) |
||||
{ |
||||
next->prev = this; |
||||
next->isGateway = false; |
||||
isEndpoint = false; |
||||
nextRouter = next->router; |
||||
nextTunnelID = next->tunnelID; |
||||
} |
||||
} |
||||
|
||||
void SetPrev (TunnelHopConfig * p) |
||||
{ |
||||
prev = p; |
||||
if (prev) |
||||
{ |
||||
prev->next = this; |
||||
prev->isEndpoint = false; |
||||
isGateway = false; |
||||
} |
||||
} |
||||
}; |
||||
|
||||
class TunnelConfig |
||||
{ |
||||
public: |
||||
|
||||
TunnelConfig (const i2p::data::RouterInfo * peer, TunnelConfig * replyTunnelConfig = 0) // one hop
|
||||
{ |
||||
m_FirstHop = new TunnelHopConfig (peer); |
||||
m_LastHop = m_FirstHop; |
||||
|
||||
if (replyTunnelConfig) // outbound
|
||||
{ |
||||
m_FirstHop->isGateway = false; |
||||
m_LastHop->SetReplyHop (replyTunnelConfig->GetFirstHop ()); |
||||
} |
||||
else |
||||
m_FirstHop->SetNextRouter (&i2p::context.GetRouterInfo ()); |
||||
} |
||||
|
||||
TunnelConfig (const i2p::data::RouterInfo * peer1, const i2p::data::RouterInfo * peer2, TunnelConfig * replyTunnelConfig = 0) // two hops
|
||||
{ |
||||
m_FirstHop = new TunnelHopConfig (peer1); |
||||
m_LastHop = new TunnelHopConfig (peer2); |
||||
m_FirstHop->SetNext (m_LastHop); |
||||
|
||||
if (replyTunnelConfig) |
||||
{ |
||||
m_FirstHop->isGateway = false; |
||||
m_LastHop->SetReplyHop (replyTunnelConfig->GetFirstHop ()); |
||||
} |
||||
else |
||||
m_LastHop->SetNextRouter (&i2p::context.GetRouterInfo ()); |
||||
} |
||||
|
||||
~TunnelConfig () |
||||
{ |
||||
TunnelHopConfig * hop = m_FirstHop; |
||||
|
||||
while (hop) |
||||
{ |
||||
delete hop; |
||||
hop = hop->next; |
||||
} |
||||
} |
||||
|
||||
TunnelHopConfig * GetFirstHop () const |
||||
{ |
||||
return m_FirstHop; |
||||
} |
||||
|
||||
TunnelHopConfig * GetLastHop () const |
||||
{ |
||||
return m_LastHop; |
||||
} |
||||
|
||||
size_t GetNumHops () const |
||||
{ |
||||
size_t num = 0; |
||||
TunnelHopConfig * hop = m_FirstHop; |
||||
while (hop) |
||||
{ |
||||
num++; |
||||
hop = hop->next; |
||||
} |
||||
return num; |
||||
} |
||||
|
||||
void Print (std::stringstream& s) const |
||||
{ |
||||
TunnelHopConfig * hop = m_FirstHop; |
||||
if (!m_FirstHop->isGateway) |
||||
s << "me"; |
||||
s << "-->" << m_FirstHop->tunnelID; |
||||
while (hop) |
||||
{ |
||||
s << ":" << hop->router->GetIdentHashAbbreviation () << "-->"; |
||||
if (!hop->isEndpoint) |
||||
s << hop->nextTunnelID; |
||||
else |
||||
return; |
||||
hop = hop->next; |
||||
} |
||||
// we didn't reach enpoint that mean we are last hop
|
||||
s << ":me"; |
||||
} |
||||
|
||||
TunnelConfig * Invert () const |
||||
{ |
||||
TunnelConfig * newConfig = new TunnelConfig (); |
||||
TunnelHopConfig * hop = m_FirstHop, * nextNewHop = nullptr; |
||||
while (hop) |
||||
{ |
||||
TunnelHopConfig * newHop = new TunnelHopConfig (hop->router); |
||||
if (nextNewHop) |
||||
newHop->SetNext (nextNewHop); |
||||
nextNewHop = newHop; |
||||
newHop->isEndpoint = hop->isGateway; |
||||
newHop->isGateway = hop->isEndpoint; |
||||
|
||||
if (!hop->prev) // first hop
|
||||
{ |
||||
newConfig->m_LastHop = newHop; |
||||
if (hop->isGateway) // inbound tunnel
|
||||
newHop->SetReplyHop (m_FirstHop); // use it as reply tunnel
|
||||
} |
||||
if (!hop->next) newConfig->m_FirstHop = newHop; // last hop
|
||||
|
||||
hop = hop->next; |
||||
} |
||||
return newConfig; |
||||
} |
||||
|
||||
private: |
||||
|
||||
// this constructor can't be called from outside
|
||||
TunnelConfig (): m_FirstHop (nullptr), m_LastHop (nullptr) |
||||
{ |
||||
} |
||||
|
||||
private: |
||||
|
||||
TunnelHopConfig * m_FirstHop, * m_LastHop; |
||||
}; |
||||
} |
||||
} |
||||
|
||||
#endif |
Loading…
Reference in new issue