mirror of
https://github.com/PurpleI2P/i2pd
synced 2024-11-10 00:00:29 +03:00
Tunnel added
This commit is contained in:
parent
885e996a8a
commit
d07f5d0310
487
Tunnel.cpp
Normal file
487
Tunnel.cpp
Normal file
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
160
Tunnel.h
Normal file
160
Tunnel.h
Normal file
@ -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
|
207
TunnelConfig.h
Normal file
207
TunnelConfig.h
Normal file
@ -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
Block a user