Browse Source

Merge branch 'master' of https://github.com/orignal/i2pd

pull/40/head
Meeh 11 years ago
parent
commit
d071c50c4d
  1. 58
      ElGamal.h
  2. 23
      Garlic.cpp
  3. 8
      Garlic.h
  4. 38
      HTTPServer.cpp
  5. 2
      HTTPServer.h
  6. 4
      I2NPProtocol.cpp
  7. 16
      Identity.h
  8. 2
      NTCPSession.h
  9. 62
      NetDb.cpp
  10. 7
      NetDb.h
  11. 28
      RouterInfo.cpp
  12. 13
      RouterInfo.h
  13. 134
      SSU.cpp
  14. 10
      SSU.h
  15. 14
      Streaming.cpp
  16. 10
      Streaming.h
  17. 9
      TransitTunnel.cpp
  18. 4
      TransitTunnel.h
  19. 9
      Transports.cpp
  20. 34
      Tunnel.cpp
  21. 2
      Tunnel.h
  22. 27
      TunnelGateway.cpp
  23. 6
      TunnelGateway.h

58
ElGamal.h

@ -12,25 +12,47 @@ namespace i2p
{ {
namespace crypto namespace crypto
{ {
inline void ElGamalEncrypt (const uint8_t * key, const uint8_t * data, int len,
uint8_t * encrypted, bool zeroPadding = false) // 514 with padding and 512 without class ElGamalEncryption
{ {
CryptoPP::AutoSeededRandomPool rnd; public:
CryptoPP::Integer y(key, 256), k(rnd, CryptoPP::Integer::One(), elgp-1);
ElGamalEncryption (const uint8_t * key):
if (zeroPadding) y (key, 256), k (rnd, CryptoPP::Integer::One(), elgp-1),
{ a (a_exp_b_mod_c (elgg, k, elgp)), b1 (a_exp_b_mod_c (y, k, elgp))
encrypted[0] = 0; {
encrypted[257] = 0; }
}
a_exp_b_mod_c (elgg, k, elgp).Encode (zeroPadding ? encrypted + 1 : encrypted, 256); void Encrypt (const uint8_t * data, int len, uint8_t * encrypted, bool zeroPadding = false)
uint8_t m[255]; {
m[0] = 0xFF; // calculate b = b1*m mod p
memcpy (m+33, data, len); uint8_t m[255];
CryptoPP::SHA256().CalculateDigest(m+1, m+33, 222); m[0] = 0xFF;
a_times_b_mod_c (a_exp_b_mod_c (y, k, elgp), memcpy (m+33, data, len);
CryptoPP::Integer (m, 255), elgp).Encode (zeroPadding ? encrypted + 258 : encrypted + 256, 256); CryptoPP::SHA256().CalculateDigest(m+1, m+33, 222);
} CryptoPP::Integer b (a_times_b_mod_c (b1, CryptoPP::Integer (m, 255), elgp));
// copy a and b
if (zeroPadding)
{
encrypted[0] = 0;
a.Encode (encrypted + 1, 256);
encrypted[257] = 0;
b.Encode (encrypted + 258, 256);
}
else
{
a.Encode (encrypted, 256);
b.Encode (encrypted + 256, 256);
}
}
private:
CryptoPP::AutoSeededRandomPool rnd;
CryptoPP::Integer y, k, a, b1;
bool m_ZeroPadding;
};
inline bool ElGamalDecrypt (const uint8_t * key, const uint8_t * encrypted, inline bool ElGamalDecrypt (const uint8_t * key, const uint8_t * encrypted,
uint8_t * data, bool zeroPadding = false) uint8_t * data, bool zeroPadding = false)

23
Garlic.cpp

@ -2,7 +2,6 @@
#include "I2PEndian.h" #include "I2PEndian.h"
#include <map> #include <map>
#include <string> #include <string>
#include "ElGamal.h"
#include "RouterContext.h" #include "RouterContext.h"
#include "I2NPProtocol.h" #include "I2NPProtocol.h"
#include "Tunnel.h" #include "Tunnel.h"
@ -14,7 +13,7 @@ namespace i2p
{ {
namespace garlic namespace garlic
{ {
GarlicRoutingSession::GarlicRoutingSession (const i2p::data::RoutingDestination * destination, int numTags): GarlicRoutingSession::GarlicRoutingSession (const i2p::data::RoutingDestination& destination, int numTags):
m_Destination (destination), m_FirstMsgID (0), m_IsAcknowledged (false), m_Destination (destination), m_FirstMsgID (0), m_IsAcknowledged (false),
m_NumTags (numTags), m_NextTag (-1), m_SessionTags (0) m_NumTags (numTags), m_NextTag (-1), m_SessionTags (0)
{ {
@ -56,7 +55,7 @@ namespace garlic
m_Rnd.GenerateBlock (elGamal.preIV, 32); // Pre-IV m_Rnd.GenerateBlock (elGamal.preIV, 32); // Pre-IV
uint8_t iv[32]; // IV is first 16 bytes uint8_t iv[32]; // IV is first 16 bytes
CryptoPP::SHA256().CalculateDigest(iv, elGamal.preIV, 32); CryptoPP::SHA256().CalculateDigest(iv, elGamal.preIV, 32);
i2p::crypto::ElGamalEncrypt (m_Destination->GetEncryptionPublicKey (), (uint8_t *)&elGamal, sizeof(elGamal), buf, true); m_Destination.GetElGamalEncryption ()->Encrypt ((uint8_t *)&elGamal, sizeof(elGamal), buf, true);
m_Encryption.SetKeyWithIV (m_SessionKey, 32, iv); m_Encryption.SetKeyWithIV (m_SessionKey, 32, iv);
buf += 514; buf += 514;
len += 514; len += 514;
@ -140,7 +139,7 @@ namespace garlic
} }
if (msg) // clove message ifself if presented if (msg) // clove message ifself if presented
{ {
size += CreateGarlicClove (payload + size, msg, m_Destination->IsDestination ()); size += CreateGarlicClove (payload + size, msg, m_Destination.IsDestination ());
(*numCloves)++; (*numCloves)++;
} }
@ -161,7 +160,7 @@ namespace garlic
{ {
buf[size] = eGarlicDeliveryTypeDestination << 5;// delivery instructions flag destination buf[size] = eGarlicDeliveryTypeDestination << 5;// delivery instructions flag destination
size++; size++;
memcpy (buf + size, m_Destination->GetIdentHash (), 32); memcpy (buf + size, m_Destination.GetIdentHash (), 32);
size += 32; size += 32;
} }
else else
@ -230,33 +229,31 @@ namespace garlic
m_Sessions.clear (); m_Sessions.clear ();
} }
I2NPMessage * GarlicRouting::WrapSingleMessage (const i2p::data::RoutingDestination * destination, I2NPMessage * msg) I2NPMessage * GarlicRouting::WrapSingleMessage (const i2p::data::RoutingDestination& destination, I2NPMessage * msg)
{ {
if (!destination) return nullptr; auto it = m_Sessions.find (destination.GetIdentHash ());
auto it = m_Sessions.find (destination->GetIdentHash ());
if (it != m_Sessions.end ()) if (it != m_Sessions.end ())
{ {
delete it->second; delete it->second;
m_Sessions.erase (it); m_Sessions.erase (it);
} }
GarlicRoutingSession * session = new GarlicRoutingSession (destination, 0); // not follow-on messages expected GarlicRoutingSession * session = new GarlicRoutingSession (destination, 0); // not follow-on messages expected
m_Sessions[destination->GetIdentHash ()] = session; m_Sessions[destination.GetIdentHash ()] = session;
return session->WrapSingleMessage (msg, nullptr); return session->WrapSingleMessage (msg, nullptr);
} }
I2NPMessage * GarlicRouting::WrapMessage (const i2p::data::RoutingDestination * destination, I2NPMessage * GarlicRouting::WrapMessage (const i2p::data::RoutingDestination& destination,
I2NPMessage * msg, I2NPMessage * leaseSet) I2NPMessage * msg, I2NPMessage * leaseSet)
{ {
if (!destination) return nullptr; auto it = m_Sessions.find (destination.GetIdentHash ());
auto it = m_Sessions.find (destination->GetIdentHash ());
GarlicRoutingSession * session = nullptr; GarlicRoutingSession * session = nullptr;
if (it != m_Sessions.end ()) if (it != m_Sessions.end ())
session = it->second; session = it->second;
if (!session) if (!session)
{ {
session = new GarlicRoutingSession (destination, 4); // TODO: change it later session = new GarlicRoutingSession (destination, 4); // TODO: change it later
m_Sessions[destination->GetIdentHash ()] = session; m_Sessions[destination.GetIdentHash ()] = session;
} }
I2NPMessage * ret = session->WrapSingleMessage (msg, leaseSet); I2NPMessage * ret = session->WrapSingleMessage (msg, leaseSet);

8
Garlic.h

@ -37,7 +37,7 @@ namespace garlic
{ {
public: public:
GarlicRoutingSession (const i2p::data::RoutingDestination * destination, int numTags); GarlicRoutingSession (const i2p::data::RoutingDestination& destination, int numTags);
~GarlicRoutingSession (); ~GarlicRoutingSession ();
I2NPMessage * WrapSingleMessage (I2NPMessage * msg, I2NPMessage * leaseSet); I2NPMessage * WrapSingleMessage (I2NPMessage * msg, I2NPMessage * leaseSet);
int GetNextTag () const { return m_NextTag; }; int GetNextTag () const { return m_NextTag; };
@ -57,7 +57,7 @@ namespace garlic
private: private:
const i2p::data::RoutingDestination * m_Destination; const i2p::data::RoutingDestination& m_Destination;
uint8_t m_SessionKey[32]; uint8_t m_SessionKey[32];
uint32_t m_FirstMsgID; // first message ID uint32_t m_FirstMsgID; // first message ID
bool m_IsAcknowledged; bool m_IsAcknowledged;
@ -78,8 +78,8 @@ namespace garlic
void HandleGarlicMessage (uint8_t * buf, size_t len, bool isFromTunnel); void HandleGarlicMessage (uint8_t * buf, size_t len, bool isFromTunnel);
void HandleDeliveryStatusMessage (uint8_t * buf, size_t len); void HandleDeliveryStatusMessage (uint8_t * buf, size_t len);
I2NPMessage * WrapSingleMessage (const i2p::data::RoutingDestination * destination, I2NPMessage * msg); I2NPMessage * WrapSingleMessage (const i2p::data::RoutingDestination& destination, I2NPMessage * msg);
I2NPMessage * WrapMessage (const i2p::data::RoutingDestination * destination, I2NPMessage * WrapMessage (const i2p::data::RoutingDestination& destination,
I2NPMessage * msg, I2NPMessage * leaseSet = nullptr); I2NPMessage * msg, I2NPMessage * leaseSet = nullptr);
private: private:

38
HTTPServer.cpp

@ -60,9 +60,20 @@ namespace util
{ {
m_Buffer[bytes_transferred] = 0; m_Buffer[bytes_transferred] = 0;
auto address = ExtractAddress (); auto address = ExtractAddress ();
LogPrint (address);
if (address.length () > 1) // not just '/' if (address.length () > 1) // not just '/'
HandleDestinationRequest (address.substr (1)); // exclude '/' {
std::string uri ("/"), b32;
size_t pos = address.find ('/', 1);
if (pos == std::string::npos)
b32 = address.substr (1); // excluding leading '/' to end of line
else
{
b32 = address.substr (1, pos - 1); // excluding leading '/' to next '/'
uri = address.substr (pos); // rest of line
}
HandleDestinationRequest (b32, uri);
}
else else
HandleRequest (); HandleRequest ();
boost::asio::async_write (*m_Socket, m_Reply.to_buffers(), boost::asio::async_write (*m_Socket, m_Reply.to_buffers(),
@ -149,14 +160,18 @@ namespace util
s << "<p><a href=\"zmw2cyw2vj7f6obx3msmdvdepdhnw2ctc4okza2zjxlukkdfckhq\">Flibusta</a></p>"; s << "<p><a href=\"zmw2cyw2vj7f6obx3msmdvdepdhnw2ctc4okza2zjxlukkdfckhq\">Flibusta</a></p>";
} }
void HTTPConnection::HandleDestinationRequest (std::string b32) void HTTPConnection::HandleDestinationRequest (const std::string& b32, const std::string& uri)
{ {
uint8_t destination[32]; uint8_t destination[32];
i2p::data::Base32ToByteStream (b32.c_str (), b32.length (), destination, 32); if (i2p::data::Base32ToByteStream (b32.c_str (), b32.length (), destination, 32) != 32)
{
LogPrint ("Invalid Base32 address ", b32);
return;
}
auto leaseSet = i2p::data::netdb.FindLeaseSet (destination); auto leaseSet = i2p::data::netdb.FindLeaseSet (destination);
if (!leaseSet || !leaseSet->HasNonExpiredLeases ()) if (!leaseSet || !leaseSet->HasNonExpiredLeases ())
{ {
i2p::data::netdb.RequestDestination (i2p::data::IdentHash (destination), true); i2p::data::netdb.Subscribe(destination);
std::this_thread::sleep_for (std::chrono::seconds(10)); // wait for 10 seconds std::this_thread::sleep_for (std::chrono::seconds(10)); // wait for 10 seconds
leaseSet = i2p::data::netdb.FindLeaseSet (destination); leaseSet = i2p::data::netdb.FindLeaseSet (destination);
if (!leaseSet || !leaseSet->HasNonExpiredLeases ()) // still no LeaseSet if (!leaseSet || !leaseSet->HasNonExpiredLeases ()) // still no LeaseSet
@ -170,17 +185,10 @@ namespace util
return; return;
} }
} }
// we found LeaseSet auto s = i2p::stream::CreateStream (*leaseSet);
if (leaseSet->HasExpiredLeases ())
{
// we should re-request LeaseSet
LogPrint ("LeaseSet re-requested");
i2p::data::netdb.RequestDestination (i2p::data::IdentHash (destination), true);
}
auto s = i2p::stream::CreateStream (leaseSet);
if (s) if (s)
{ {
std::string request = "GET / HTTP/1.1\n Host:" + b32 + ".b32.i2p\n"; std::string request = "GET " + uri + " HTTP/1.1\n Host:" + b32 + ".b32.i2p\n";
s->Send ((uint8_t *)request.c_str (), request.length (), 10); s->Send ((uint8_t *)request.c_str (), request.length (), 10);
std::stringstream ss; std::stringstream ss;
uint8_t buf[8192]; uint8_t buf[8192];
@ -200,7 +208,7 @@ namespace util
else // nothing received else // nothing received
ss << "<html>Not responding</html>"; ss << "<html>Not responding</html>";
s->Close (); s->Close ();
//DeleteStream (s); DeleteStream (s);
m_Reply.content = ss.str (); m_Reply.content = ss.str ();
m_Reply.headers.resize(2); m_Reply.headers.resize(2);

2
HTTPServer.h

@ -48,7 +48,7 @@ namespace util
void HandleWrite(const boost::system::error_code& ecode); void HandleWrite(const boost::system::error_code& ecode);
void HandleRequest (); void HandleRequest ();
void HandleDestinationRequest (std::string b32); void HandleDestinationRequest (const std::string& b32, const std::string& uri);
void FillContent (std::stringstream& s); void FillContent (std::stringstream& s);
std::string ExtractAddress (); std::string ExtractAddress ();

4
I2NPProtocol.cpp

@ -212,7 +212,7 @@ namespace i2p
const I2NPBuildRequestRecordClearText& clearText, const I2NPBuildRequestRecordClearText& clearText,
I2NPBuildRequestRecordElGamalEncrypted& record) I2NPBuildRequestRecordElGamalEncrypted& record)
{ {
i2p::crypto::ElGamalEncrypt (router.GetRouterIdentity ().publicKey, (uint8_t *)&clearText, sizeof(clearText), record.encrypted); router.GetElGamalEncryption ()->Encrypt ((uint8_t *)&clearText, sizeof(clearText), record.encrypted);
memcpy (record.toPeer, (const uint8_t *)router.GetIdentHash (), 16); memcpy (record.toPeer, (const uint8_t *)router.GetIdentHash (), 16);
} }
@ -392,7 +392,7 @@ namespace i2p
LogPrint ("TunnelGateway of ", (int)len, " bytes for tunnel ", (unsigned int)tunnelID, ". Msg type ", (int)msg->GetHeader()->typeID); LogPrint ("TunnelGateway of ", (int)len, " bytes for tunnel ", (unsigned int)tunnelID, ". Msg type ", (int)msg->GetHeader()->typeID);
i2p::tunnel::TransitTunnel * tunnel = i2p::tunnel::tunnels.GetTransitTunnel (tunnelID); i2p::tunnel::TransitTunnel * tunnel = i2p::tunnel::tunnels.GetTransitTunnel (tunnelID);
if (tunnel) if (tunnel)
tunnel->SendTunnelDataMsg (nullptr, 0, msg); tunnel->SendTunnelDataMsg (msg);
else else
{ {
LogPrint ("Tunnel ", (unsigned int)tunnelID, " not found"); LogPrint ("Tunnel ", (unsigned int)tunnelID, " not found");

16
Identity.h

@ -3,6 +3,7 @@
#include <inttypes.h> #include <inttypes.h>
#include <string.h> #include <string.h>
#include "ElGamal.h"
namespace i2p namespace i2p
{ {
@ -84,9 +85,24 @@ namespace data
class RoutingDestination class RoutingDestination
{ {
public: public:
RoutingDestination (): m_ElGamalEncryption (nullptr) {};
virtual ~RoutingDestination () { delete m_ElGamalEncryption; };
virtual const IdentHash& GetIdentHash () const = 0; virtual const IdentHash& GetIdentHash () const = 0;
virtual const uint8_t * GetEncryptionPublicKey () const = 0; virtual const uint8_t * GetEncryptionPublicKey () const = 0;
virtual bool IsDestination () const = 0; // for garlic virtual bool IsDestination () const = 0; // for garlic
i2p::crypto::ElGamalEncryption * GetElGamalEncryption () const
{
if (!m_ElGamalEncryption)
m_ElGamalEncryption = new i2p::crypto::ElGamalEncryption (GetEncryptionPublicKey ());
return m_ElGamalEncryption;
}
private:
mutable i2p::crypto::ElGamalEncryption * m_ElGamalEncryption; // use lazy initialization
}; };
} }
} }

2
NTCPSession.h

@ -60,7 +60,7 @@ namespace ntcp
#pragma pack() #pragma pack()
const int TERMINATION_TIMEOUT = 60; // 1 minute const int TERMINATION_TIMEOUT = 120; // 2 minutes
class NTCPSession class NTCPSession
{ {
public: public:

62
NetDb.cpp

@ -25,7 +25,7 @@ namespace data
I2NPMessage * msg = i2p::CreateDatabaseLookupMsg (m_Destination, I2NPMessage * msg = i2p::CreateDatabaseLookupMsg (m_Destination,
replyTunnel->GetNextIdentHash (), replyTunnel->GetNextTunnelID (), m_IsExploratory, &m_ExcludedPeers); replyTunnel->GetNextIdentHash (), replyTunnel->GetNextTunnelID (), m_IsExploratory, &m_ExcludedPeers);
if (m_IsLeaseSet) // wrap lookup message into garlic if (m_IsLeaseSet) // wrap lookup message into garlic
msg = i2p::garlic::routing.WrapSingleMessage (router, msg); msg = i2p::garlic::routing.WrapSingleMessage (*router, msg);
m_ExcludedPeers.insert (router->GetIdentHash ()); m_ExcludedPeers.insert (router->GetIdentHash ());
m_LastRouter = router; m_LastRouter = router;
m_LastReplyTunnel = replyTunnel; m_LastReplyTunnel = replyTunnel;
@ -90,7 +90,7 @@ namespace data
void NetDb::Run () void NetDb::Run ()
{ {
uint32_t lastTs = 0; uint32_t lastSave = 0, lastPublish = 0;
m_IsRunning = true; m_IsRunning = true;
while (m_IsRunning) while (m_IsRunning)
{ {
@ -120,11 +120,19 @@ namespace data
Explore (); Explore ();
uint64_t ts = i2p::util::GetSecondsSinceEpoch (); uint64_t ts = i2p::util::GetSecondsSinceEpoch ();
if (ts - lastTs >= 60) // save routers every minute if (ts - lastSave >= 60) // save routers and validate subscriptions every minute
{ {
if (lastTs) if (lastSave)
{
SaveUpdated (m_NetDbPath); SaveUpdated (m_NetDbPath);
lastTs = ts; ValidateSubscriptions ();
}
lastSave = ts;
}
if (ts - lastPublish >= 600) // publish every 10 minutes
{
Publish ();
lastPublish = ts;
} }
} }
catch (std::exception& ex) catch (std::exception& ex)
@ -486,7 +494,10 @@ namespace data
else // we should send directly else // we should send directly
{ {
if (!dest->IsLeaseSet ()) // if not LeaseSet if (!dest->IsLeaseSet ()) // if not LeaseSet
i2p::transports.SendMessage (router, dest->CreateRequestMessage (router)); {
if (!dest->IsExcluded (router) && dest->GetNumExcludedPeers () < 30)
i2p::transports.SendMessage (router, dest->CreateRequestMessage (router));
}
else else
LogPrint ("Can't request LeaseSet"); LogPrint ("Can't request LeaseSet");
} }
@ -543,6 +554,17 @@ namespace data
} }
} }
void NetDb::Publish ()
{
std::set<IdentHash> excluded; // TODO: fill up later
auto floodfill = GetClosestFloodfill (i2p::context.GetRouterInfo ().GetIdentHash (), excluded);
if (floodfill)
{
LogPrint ("Publishing our RouterInfo to ", floodfill->GetIdentHashAbbreviation ());
transports.SendMessage (floodfill->GetIdentHash (), CreateDatabaseStoreMsg ());
}
}
RequestedDestination * NetDb::CreateRequestedDestination (const IdentHash& dest, RequestedDestination * NetDb::CreateRequestedDestination (const IdentHash& dest,
bool isLeaseSet, bool isExploratory) bool isLeaseSet, bool isExploratory)
{ {
@ -644,5 +666,33 @@ namespace data
return r; return r;
} }
void NetDb::Subscribe (const IdentHash& ident)
{
LeaseSet * leaseSet = FindLeaseSet (ident);
if (!leaseSet)
{
LogPrint ("LeaseSet requested");
RequestDestination (ident, true);
}
m_Subscriptions.insert (ident);
}
void NetDb::Unsubscribe (const IdentHash& ident)
{
m_Subscriptions.erase (ident);
}
void NetDb::ValidateSubscriptions ()
{
for (auto it : m_Subscriptions)
{
LeaseSet * leaseSet = FindLeaseSet (it);
if (!leaseSet || leaseSet->HasExpiredLeases ())
{
LogPrint ("LeaseSet re-requested");
RequestDestination (it, true);
}
}
}
} }
} }

7
NetDb.h

@ -63,7 +63,9 @@ namespace data
void AddLeaseSet (uint8_t * buf, int len); void AddLeaseSet (uint8_t * buf, int len);
RouterInfo * FindRouter (const IdentHash& ident) const; RouterInfo * FindRouter (const IdentHash& ident) const;
LeaseSet * FindLeaseSet (const IdentHash& destination) const; LeaseSet * FindLeaseSet (const IdentHash& destination) const;
void Subscribe (const IdentHash& ident); // keep LeaseSets upto date
void Unsubscribe (const IdentHash& ident);
void RequestDestination (const char * b32); // in base32 void RequestDestination (const char * b32); // in base32
void RequestDestination (const IdentHash& destination, bool isLeaseSet = false); void RequestDestination (const IdentHash& destination, bool isLeaseSet = false);
@ -82,6 +84,8 @@ namespace data
void SaveUpdated (const char * directory); void SaveUpdated (const char * directory);
void Run (); // exploratory thread void Run (); // exploratory thread
void Explore (); void Explore ();
void Publish ();
void ValidateSubscriptions ();
const RouterInfo * GetClosestFloodfill (const IdentHash& destination, const std::set<IdentHash>& excluded) const; const RouterInfo * GetClosestFloodfill (const IdentHash& destination, const std::set<IdentHash>& excluded) const;
RequestedDestination * CreateRequestedDestination (const IdentHash& dest, RequestedDestination * CreateRequestedDestination (const IdentHash& dest,
@ -94,6 +98,7 @@ namespace data
std::map<IdentHash, LeaseSet *> m_LeaseSets; std::map<IdentHash, LeaseSet *> m_LeaseSets;
std::map<IdentHash, RouterInfo *> m_RouterInfos; std::map<IdentHash, RouterInfo *> m_RouterInfos;
std::map<IdentHash, RequestedDestination *> m_RequestedDestinations; std::map<IdentHash, RequestedDestination *> m_RequestedDestinations;
std::set<IdentHash> m_Subscriptions;
bool m_IsRunning; bool m_IsRunning;
int m_ReseedRetries; int m_ReseedRetries;

28
RouterInfo.cpp

@ -129,6 +129,27 @@ namespace data
address.port = boost::lexical_cast<int>(value); address.port = boost::lexical_cast<int>(value);
else if (!strcmp (key, "key")) else if (!strcmp (key, "key"))
Base64ToByteStream (value, strlen (value), address.key, 32); Base64ToByteStream (value, strlen (value), address.key, 32);
else if (key[0] == 'i')
{
// introducers
size_t l = strlen(key);
unsigned char index = key[l-1]; // TODO:
key[l-1] = 0;
if (index >= address.introducers.size ())
address.introducers.resize (index + 1);
Introducer& introducer = address.introducers.at (index);
if (!strcmp (key, "ihost"))
{
boost::system::error_code ecode;
introducer.iHost = boost::asio::ip::address::from_string (value, ecode);
}
else if (!strcmp (key, "iport"))
introducer.iPort = boost::lexical_cast<int>(value);
else if (!strcmp (key, "itag"))
introducer.iTag = boost::lexical_cast<uint32_t>(value);
else if (!strcmp (key, "ikey"))
Base64ToByteStream (value, strlen (value), introducer.iKey, 32);
}
} }
m_Addresses.push_back(address); m_Addresses.push_back(address);
} }
@ -302,6 +323,13 @@ namespace data
else else
return m_SupportedTransports & (eSSUV4 | eSSUV6); return m_SupportedTransports & (eSSUV4 | eSSUV6);
} }
bool RouterInfo::UsesIntroducer () const
{
if (!IsSSU ()) return false;
auto address = GetSSUAddress (true); // no introducers for v6
return address && !address->introducers.empty ();
}
const RouterInfo::Address * RouterInfo::GetNTCPAddress (bool v4only) const const RouterInfo::Address * RouterInfo::GetNTCPAddress (bool v4only) const
{ {

13
RouterInfo.h

@ -32,6 +32,14 @@ namespace data
eTransportSSU eTransportSSU
}; };
struct Introducer
{
boost::asio::ip::address iHost;
int iPort;
uint8_t iKey[32];
uint32_t iTag;
};
struct Address struct Address
{ {
TransportStyle transportStyle; TransportStyle transportStyle;
@ -39,7 +47,9 @@ namespace data
int port; int port;
uint64_t date; uint64_t date;
uint8_t cost; uint8_t cost;
uint8_t key[32]; // into key for SSU // SSU only
uint8_t key[32]; // intro key for SSU
std::vector<Introducer> introducers;
}; };
RouterInfo (const char * filename); RouterInfo (const char * filename);
@ -65,6 +75,7 @@ namespace data
bool IsNTCP (bool v4only = true) const; bool IsNTCP (bool v4only = true) const;
bool IsSSU (bool v4only = true) const; bool IsSSU (bool v4only = true) const;
bool IsCompatible (const RouterInfo& other) const { return m_SupportedTransports & other.m_SupportedTransports; }; bool IsCompatible (const RouterInfo& other) const { return m_SupportedTransports & other.m_SupportedTransports; };
bool UsesIntroducer () const;
void SetUnreachable (bool unreachable) { m_IsUnreachable = unreachable; }; void SetUnreachable (bool unreachable) { m_IsUnreachable = unreachable; };
bool IsUnreachable () const { return m_IsUnreachable; }; bool IsUnreachable () const { return m_IsUnreachable; };

134
SSU.cpp

@ -65,6 +65,15 @@ namespace ssu
// session confirmed // session confirmed
ProcessSessionConfirmed (buf, len); ProcessSessionConfirmed (buf, len);
break; break;
case eSessionRelayRequestSent:
// relay response
ProcessRelayResponse (buf,len);
break;
case eSessionRelayRequestReceived:
// HolePunch
m_State = eSessionStateUnknown;
Connect ();
break;
default: default:
LogPrint ("SSU state not implemented yet"); LogPrint ("SSU state not implemented yet");
} }
@ -91,8 +100,12 @@ namespace ssu
LogPrint ("SSU session destroy received"); LogPrint ("SSU session destroy received");
if (m_Server) if (m_Server)
m_Server->DeleteSession (this); // delete this m_Server->DeleteSession (this); // delete this
} break;
break; }
case PAYLOAD_TYPE_RELAY_INTRO:
LogPrint ("SSU relay intro received");
// TODO:
break;
default: default:
LogPrint ("Unexpected SSU payload type ", (int)payloadType); LogPrint ("Unexpected SSU payload type ", (int)payloadType);
} }
@ -197,6 +210,37 @@ namespace ssu
m_Server->Send (buf, 304, m_RemoteEndpoint); m_Server->Send (buf, 304, m_RemoteEndpoint);
} }
void SSUSession::SendRelayRequest (const i2p::data::RouterInfo::Introducer& introducer)
{
auto address = i2p::context.GetRouterInfo ().GetSSUAddress ();
if (!address)
{
LogPrint ("SSU is not supported");
return;
}
uint8_t buf[96 + 18];
uint8_t * payload = buf + sizeof (SSUHeader);
*(uint32_t *)payload = htobe32 (introducer.iTag);
payload += 4;
*payload = 0; // no address
payload++;
*(uint16_t *)payload = 0; // port = 0
payload += 2;
*payload = 0; // challenge
payload++;
memcpy (payload, address->key, 32);
payload += 32;
CryptoPP::RandomNumberGenerator& rnd = i2p::context.GetRandomNumberGenerator ();
*(uint32_t *)payload = htobe32 (rnd.GenerateWord32 ()); // nonce
uint8_t iv[16];
rnd.GenerateBlock (iv, 16); // random iv
FillHeaderAndEncrypt (PAYLOAD_TYPE_RELAY_REQUEST, buf, 96, introducer.iKey, iv, introducer.iKey);
m_State = eSessionRelayRequestSent;
m_Server->Send (buf, 96, m_RemoteEndpoint);
}
void SSUSession::SendSessionCreated (const uint8_t * x) void SSUSession::SendSessionCreated (const uint8_t * x)
{ {
auto introKey = GetIntroKey (); auto introKey = GetIntroKey ();
@ -282,6 +326,46 @@ namespace ssu
m_Server->Send (buf, 480, m_RemoteEndpoint); m_Server->Send (buf, 480, m_RemoteEndpoint);
} }
void SSUSession::ProcessRelayResponse (uint8_t * buf, size_t len)
{
LogPrint ("Process relay response");
auto address = i2p::context.GetRouterInfo ().GetSSUAddress ();
if (!address)
{
LogPrint ("SSU is not supported");
return;
}
if (Validate (buf, len, address->key))
{
Decrypt (buf, len, address->key);
SSUHeader * header = (SSUHeader *)buf;
if ((header->flag >> 4) == PAYLOAD_TYPE_RELAY_RESPONSE)
{
LogPrint ("Relay response received");
m_State = eSessionRelayRequestReceived;
uint8_t * payload = buf + sizeof (SSUHeader);
payload++;
boost::asio::ip::address_v4 remoteIP (be32toh (*(uint32_t* )(payload)));
payload += 4;
uint16_t remotePort = be16toh (*(uint16_t *)(payload));
payload += 2;
boost::asio::ip::udp::endpoint newRemoteEndpoint(remoteIP, remotePort);
m_Server->ReassignSession (m_RemoteEndpoint, newRemoteEndpoint);
m_RemoteEndpoint = newRemoteEndpoint;
payload++;
boost::asio::ip::address_v4 ourIP (be32toh (*(uint32_t* )(payload)));
payload += 4;
uint16_t ourPort = be16toh (*(uint16_t *)(payload));
payload += 2;
LogPrint ("Our external address is ", ourIP.to_string (), ":", ourPort);
i2p::context.UpdateAddress (ourIP.to_string ().c_str ());
}
else
LogPrint ("Unexpected payload type ", (int)(header->flag >> 4));
}
}
bool SSUSession::ProcessIntroKeyEncryptedMessage (uint8_t expectedPayloadType, uint8_t * buf, size_t len) bool SSUSession::ProcessIntroKeyEncryptedMessage (uint8_t expectedPayloadType, uint8_t * buf, size_t len)
{ {
auto introKey = GetIntroKey (); auto introKey = GetIntroKey ();
@ -301,7 +385,7 @@ namespace ssu
LogPrint ("Unexpected payload type ", (int)(header->flag >> 4)); LogPrint ("Unexpected payload type ", (int)(header->flag >> 4));
} }
else else
LogPrint ("MAC verifcation failed"); LogPrint ("MAC verification failed");
} }
else else
LogPrint ("SSU is not supported"); LogPrint ("SSU is not supported");
@ -368,6 +452,11 @@ namespace ssu
SendSessionRequest (); SendSessionRequest ();
} }
void SSUSession::ConnectThroughIntroducer (const i2p::data::RouterInfo::Introducer& introducer)
{
SendRelayRequest (introducer);
}
void SSUSession::Close () void SSUSession::Close ()
{ {
SendSesionDestroyed (); SendSesionDestroyed ();
@ -677,12 +766,27 @@ namespace ssu
session = it->second; session = it->second;
else else
{ {
// otherwise create new session // otherwise create new session
session = new SSUSession (this, remoteEndpoint, router); if (!router->UsesIntroducer ())
m_Sessions[remoteEndpoint] = session; {
LogPrint ("New SSU session to [", router->GetIdentHashAbbreviation (), "] ", // connect directly
remoteEndpoint.address ().to_string (), ":", remoteEndpoint.port (), " created"); session = new SSUSession (this, remoteEndpoint, router);
session->Connect (); m_Sessions[remoteEndpoint] = session;
LogPrint ("New SSU session to [", router->GetIdentHashAbbreviation (), "] ",
remoteEndpoint.address ().to_string (), ":", remoteEndpoint.port (), " created");
session->Connect ();
}
else
{
// connect to introducer
auto& introducer = address->introducers[0]; // TODO:
boost::asio::ip::udp::endpoint introducerEndpoint (introducer.iHost, introducer.iPort);
session = new SSUSession (this, introducerEndpoint, router);
m_Sessions[introducerEndpoint] = session;
LogPrint ("New SSU session to [", router->GetIdentHashAbbreviation (),
"] created through introducer ", introducerEndpoint.address ().to_string (), ":", introducerEndpoint.port ());
session->ConnectThroughIntroducer (introducer);
}
} }
} }
else else
@ -709,6 +813,18 @@ namespace ssu
delete it.second; delete it.second;
} }
m_Sessions.clear (); m_Sessions.clear ();
}
void SSUServer::ReassignSession (const boost::asio::ip::udp::endpoint& oldEndpoint, const boost::asio::ip::udp::endpoint& newEndpoint)
{
auto it = m_Sessions.find (oldEndpoint);
if (it != m_Sessions.end ())
{
m_Sessions.erase (it);
m_Sessions[newEndpoint] = it->second;
LogPrint ("SSU session ressigned from ", oldEndpoint.address ().to_string (), ":", oldEndpoint.port (),
" to ", newEndpoint.address ().to_string (), ":", newEndpoint.port ());
}
} }
} }
} }

10
SSU.h

@ -55,6 +55,8 @@ namespace ssu
eSessionStateCreatedReceived, eSessionStateCreatedReceived,
eSessionStateConfirmedSent, eSessionStateConfirmedSent,
eSessionStateConfirmedReceived, eSessionStateConfirmedReceived,
eSessionRelayRequestSent,
eSessionRelayRequestReceived,
eSessionStateEstablished eSessionStateEstablished
}; };
@ -68,6 +70,7 @@ namespace ssu
void ProcessNextMessage (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint); void ProcessNextMessage (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint);
void Connect (); void Connect ();
void ConnectThroughIntroducer (const i2p::data::RouterInfo::Introducer& introducer);
void Close (); void Close ();
boost::asio::ip::udp::endpoint& GetRemoteEndpoint () { return m_RemoteEndpoint; }; boost::asio::ip::udp::endpoint& GetRemoteEndpoint () { return m_RemoteEndpoint; };
void SendI2NPMessage (I2NPMessage * msg); void SendI2NPMessage (I2NPMessage * msg);
@ -79,10 +82,12 @@ namespace ssu
void ProcessMessage (uint8_t * buf, size_t len); // call for established session void ProcessMessage (uint8_t * buf, size_t len); // call for established session
void ProcessSessionRequest (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint); void ProcessSessionRequest (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint);
void SendSessionRequest (); void SendSessionRequest ();
void SendRelayRequest (const i2p::data::RouterInfo::Introducer& introducer);
void ProcessSessionCreated (uint8_t * buf, size_t len); void ProcessSessionCreated (uint8_t * buf, size_t len);
void SendSessionCreated (const uint8_t * x); void SendSessionCreated (const uint8_t * x);
void ProcessSessionConfirmed (uint8_t * buf, size_t len); void ProcessSessionConfirmed (uint8_t * buf, size_t len);
void SendSessionConfirmed (const uint8_t * y, const uint8_t * ourAddress, uint32_t relayTag); void SendSessionConfirmed (const uint8_t * y, const uint8_t * ourAddress, uint32_t relayTag);
void ProcessRelayResponse (uint8_t * buf, size_t len);
void Established (); void Established ();
void ProcessData (uint8_t * buf, size_t len); void ProcessData (uint8_t * buf, size_t len);
void SendMsgAck (uint32_t msgID); void SendMsgAck (uint32_t msgID);
@ -118,10 +123,11 @@ namespace ssu
void Stop (); void Stop ();
SSUSession * GetSession (const i2p::data::RouterInfo * router); SSUSession * GetSession (const i2p::data::RouterInfo * router);
void DeleteSession (SSUSession * session); void DeleteSession (SSUSession * session);
void DeleteAllSessions (); void DeleteAllSessions ();
const boost::asio::ip::udp::endpoint& GetEndpoint () const { return m_Endpoint; }; 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); void Send (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& to);
void ReassignSession (const boost::asio::ip::udp::endpoint& oldEndpoint, const boost::asio::ip::udp::endpoint& newEndpoint);
private: private:

14
Streaming.cpp

@ -14,7 +14,7 @@ namespace i2p
{ {
namespace stream namespace stream
{ {
Stream::Stream (StreamingDestination * local, const i2p::data::LeaseSet * remote): Stream::Stream (StreamingDestination * local, const i2p::data::LeaseSet& remote):
m_SendStreamID (0), m_SequenceNumber (0), m_LastReceivedSequenceNumber (0), m_IsOpen (false), m_SendStreamID (0), m_SequenceNumber (0), m_LastReceivedSequenceNumber (0), m_IsOpen (false),
m_LocalDestination (local), m_RemoteLeaseSet (remote), m_OutboundTunnel (nullptr) m_LocalDestination (local), m_RemoteLeaseSet (remote), m_OutboundTunnel (nullptr)
{ {
@ -172,7 +172,7 @@ namespace stream
if (!m_OutboundTunnel) if (!m_OutboundTunnel)
m_OutboundTunnel = i2p::tunnel::tunnels.GetNextOutboundTunnel (); m_OutboundTunnel = i2p::tunnel::tunnels.GetNextOutboundTunnel ();
auto leases = m_RemoteLeaseSet->GetNonExpiredLeases (); auto leases = m_RemoteLeaseSet.GetNonExpiredLeases ();
if (m_OutboundTunnel && !leases.empty ()) if (m_OutboundTunnel && !leases.empty ())
{ {
auto& lease = *leases.begin (); // TODO: auto& lease = *leases.begin (); // TODO:
@ -206,7 +206,7 @@ namespace stream
CreateDataMessage (this, packet, size)); CreateDataMessage (this, packet, size));
if (m_OutboundTunnel) if (m_OutboundTunnel)
{ {
auto leases = m_RemoteLeaseSet->GetNonExpiredLeases (); auto leases = m_RemoteLeaseSet.GetNonExpiredLeases ();
if (!leases.empty ()) if (!leases.empty ())
{ {
auto& lease = *leases.begin (); // TODO: auto& lease = *leases.begin (); // TODO:
@ -252,7 +252,7 @@ namespace stream
I2NPMessage * msg = i2p::garlic::routing.WrapSingleMessage (m_RemoteLeaseSet, I2NPMessage * msg = i2p::garlic::routing.WrapSingleMessage (m_RemoteLeaseSet,
CreateDataMessage (this, packet, size)); CreateDataMessage (this, packet, size));
auto leases = m_RemoteLeaseSet->GetNonExpiredLeases (); auto leases = m_RemoteLeaseSet.GetNonExpiredLeases ();
if (m_OutboundTunnel && !leases.empty ()) if (m_OutboundTunnel && !leases.empty ())
{ {
auto& lease = *leases.begin (); // TODO: auto& lease = *leases.begin (); // TODO:
@ -318,7 +318,7 @@ namespace stream
void StreamingDestination::HandleNextPacket (Packet * packet) void StreamingDestination::HandleNextPacket (Packet * packet)
{ {
uint32_t sendStreamID = be32toh (*(uint32_t *)(packet->buf)); uint32_t sendStreamID = packet->GetSendStreamID ();
auto it = m_Streams.find (sendStreamID); auto it = m_Streams.find (sendStreamID);
if (it != m_Streams.end ()) if (it != m_Streams.end ())
it->second->HandleNextPacket (packet); it->second->HandleNextPacket (packet);
@ -329,7 +329,7 @@ namespace stream
} }
} }
Stream * StreamingDestination::CreateNewStream (const i2p::data::LeaseSet * remote) Stream * StreamingDestination::CreateNewStream (const i2p::data::LeaseSet& remote)
{ {
Stream * s = new Stream (this, remote); Stream * s = new Stream (this, remote);
m_Streams[s->GetRecvStreamID ()] = s; m_Streams[s->GetRecvStreamID ()] = s;
@ -399,7 +399,7 @@ namespace stream
signer.SignMessage (i2p::context.GetRandomNumberGenerator (), buf, len, signature); signer.SignMessage (i2p::context.GetRandomNumberGenerator (), buf, len, signature);
} }
Stream * CreateStream (const i2p::data::LeaseSet * remote) Stream * CreateStream (const i2p::data::LeaseSet& remote)
{ {
if (!sharedLocalDestination) if (!sharedLocalDestination)
sharedLocalDestination = new StreamingDestination (); sharedLocalDestination = new StreamingDestination ();

10
Streaming.h

@ -65,11 +65,11 @@ namespace stream
{ {
public: public:
Stream (StreamingDestination * local, const i2p::data::LeaseSet * remote); Stream (StreamingDestination * local, const i2p::data::LeaseSet& remote);
~Stream (); ~Stream ();
uint32_t GetSendStreamID () const { return m_SendStreamID; }; uint32_t GetSendStreamID () const { return m_SendStreamID; };
uint32_t GetRecvStreamID () const { return m_RecvStreamID; }; uint32_t GetRecvStreamID () const { return m_RecvStreamID; };
const i2p::data::LeaseSet * GetRemoteLeaseSet () const { return m_RemoteLeaseSet; }; const i2p::data::LeaseSet& GetRemoteLeaseSet () const { return m_RemoteLeaseSet; };
bool IsOpen () const { return m_IsOpen; }; bool IsOpen () const { return m_IsOpen; };
bool IsEstablished () const { return m_SendStreamID; }; bool IsEstablished () const { return m_SendStreamID; };
@ -91,7 +91,7 @@ namespace stream
uint32_t m_SendStreamID, m_RecvStreamID, m_SequenceNumber, m_LastReceivedSequenceNumber; uint32_t m_SendStreamID, m_RecvStreamID, m_SequenceNumber, m_LastReceivedSequenceNumber;
bool m_IsOpen; bool m_IsOpen;
StreamingDestination * m_LocalDestination; StreamingDestination * m_LocalDestination;
const i2p::data::LeaseSet * m_RemoteLeaseSet; const i2p::data::LeaseSet& m_RemoteLeaseSet;
i2p::util::Queue<Packet> m_ReceiveQueue; i2p::util::Queue<Packet> m_ReceiveQueue;
std::set<Packet *, PacketCmp> m_SavedPackets; std::set<Packet *, PacketCmp> m_SavedPackets;
i2p::tunnel::OutboundTunnel * m_OutboundTunnel; i2p::tunnel::OutboundTunnel * m_OutboundTunnel;
@ -109,7 +109,7 @@ namespace stream
I2NPMessage * GetLeaseSet (); I2NPMessage * GetLeaseSet ();
void Sign (uint8_t * buf, int len, uint8_t * signature) const; void Sign (uint8_t * buf, int len, uint8_t * signature) const;
Stream * CreateNewStream (const i2p::data::LeaseSet * remote); Stream * CreateNewStream (const i2p::data::LeaseSet& remote);
void DeleteStream (Stream * stream); void DeleteStream (Stream * stream);
void HandleNextPacket (Packet * packet); void HandleNextPacket (Packet * packet);
@ -129,7 +129,7 @@ namespace stream
CryptoPP::DSA::PrivateKey m_SigningPrivateKey; CryptoPP::DSA::PrivateKey m_SigningPrivateKey;
}; };
Stream * CreateStream (const i2p::data::LeaseSet * remote); Stream * CreateStream (const i2p::data::LeaseSet& remote);
void DeleteStream (Stream * stream); void DeleteStream (Stream * stream);
// assuming data is I2CP message // assuming data is I2CP message

9
TransitTunnel.cpp

@ -47,15 +47,18 @@ namespace tunnel
m_NumTransmittedBytes += tunnelMsg->GetLength (); m_NumTransmittedBytes += tunnelMsg->GetLength ();
} }
void TransitTunnel::SendTunnelDataMsg (const uint8_t * gwHash, uint32_t gwTunnel, i2p::I2NPMessage * msg) void TransitTunnel::SendTunnelDataMsg (i2p::I2NPMessage * msg)
{ {
LogPrint ("We are not a gateway for transit tunnel ", m_TunnelID); LogPrint ("We are not a gateway for transit tunnel ", m_TunnelID);
i2p::DeleteI2NPMessage (msg); i2p::DeleteI2NPMessage (msg);
} }
void TransitTunnelGateway::SendTunnelDataMsg (const uint8_t * gwHash, uint32_t gwTunnel, i2p::I2NPMessage * msg) void TransitTunnelGateway::SendTunnelDataMsg (i2p::I2NPMessage * msg)
{ {
m_Gateway.SendTunnelDataMsg (gwHash, gwTunnel, msg); TunnelMessageBlock block;
block.deliveryType = eDeliveryTypeLocal;
block.data = msg;
m_Gateway.SendTunnelDataMsg (block);
} }
void TransitTunnelEndpoint::HandleTunnelDataMsg (i2p::I2NPMessage * tunnelMsg) void TransitTunnelEndpoint::HandleTunnelDataMsg (i2p::I2NPMessage * tunnelMsg)

4
TransitTunnel.h

@ -22,7 +22,7 @@ namespace tunnel
const uint8_t * layerKey,const uint8_t * ivKey); const uint8_t * layerKey,const uint8_t * ivKey);
virtual void HandleTunnelDataMsg (i2p::I2NPMessage * tunnelMsg); virtual void HandleTunnelDataMsg (i2p::I2NPMessage * tunnelMsg);
virtual void SendTunnelDataMsg (const uint8_t * gwHash, uint32_t gwTunnel, i2p::I2NPMessage * msg); virtual void SendTunnelDataMsg (i2p::I2NPMessage * msg);
virtual size_t GetNumTransmittedBytes () const { return m_NumTransmittedBytes; }; virtual size_t GetNumTransmittedBytes () const { return m_NumTransmittedBytes; };
uint32_t GetTunnelID () const { return m_TunnelID; }; uint32_t GetTunnelID () const { return m_TunnelID; };
@ -54,7 +54,7 @@ namespace tunnel
TransitTunnel (receiveTunnelID, nextIdent, nextTunnelID, TransitTunnel (receiveTunnelID, nextIdent, nextTunnelID,
layerKey, ivKey), m_Gateway(this) {}; layerKey, ivKey), m_Gateway(this) {};
void SendTunnelDataMsg (const uint8_t * gwHash, uint32_t gwTunnel, i2p::I2NPMessage * msg); void SendTunnelDataMsg (i2p::I2NPMessage * msg);
size_t GetNumTransmittedBytes () const { return m_Gateway.GetNumSentBytes (); }; size_t GetNumTransmittedBytes () const { return m_Gateway.GetNumSentBytes (); };
private: private:

9
Transports.cpp

@ -64,9 +64,12 @@ namespace i2p
delete session.second; delete session.second;
m_NTCPSessions.clear (); m_NTCPSessions.clear ();
delete m_NTCPAcceptor; delete m_NTCPAcceptor;
m_Timer->cancel (); if (m_Timer)
delete m_Timer; {
m_Timer->cancel ();
delete m_Timer;
}
if (m_SSUServer) if (m_SSUServer)
{ {

34
Tunnel.cpp

@ -136,28 +136,28 @@ namespace tunnel
void OutboundTunnel::SendTunnelDataMsg (const uint8_t * gwHash, uint32_t gwTunnel, i2p::I2NPMessage * msg) void OutboundTunnel::SendTunnelDataMsg (const uint8_t * gwHash, uint32_t gwTunnel, i2p::I2NPMessage * msg)
{ {
m_Gateway.SendTunnelDataMsg (gwHash, gwTunnel, msg); TunnelMessageBlock block;
if (gwHash)
{
block.hash = gwHash;
if (gwTunnel)
{
block.deliveryType = eDeliveryTypeTunnel;
block.tunnelID = gwTunnel;
}
else
block.deliveryType = eDeliveryTypeRouter;
}
else
block.deliveryType = eDeliveryTypeLocal;
block.data = msg;
m_Gateway.SendTunnelDataMsg (block);
} }
void OutboundTunnel::SendTunnelDataMsg (std::vector<TunnelMessageBlock> msgs) void OutboundTunnel::SendTunnelDataMsg (std::vector<TunnelMessageBlock> msgs)
{ {
for (auto& it : msgs) for (auto& it : msgs)
{ m_Gateway.PutTunnelDataMsg (it);
switch (it.deliveryType)
{
case eDeliveryTypeLocal:
m_Gateway.SendTunnelDataMsg (nullptr, 0, it.data);
break;
case eDeliveryTypeTunnel:
m_Gateway.SendTunnelDataMsg (it.hash, it.tunnelID, it.data);
break;
case eDeliveryTypeRouter:
m_Gateway.SendTunnelDataMsg (it.hash, 0, it.data);
break;
default:
LogPrint ("Unexpected delivery type ", (int)it.deliveryType);
}
}
m_Gateway.SendBuffer (); m_Gateway.SendBuffer ();
} }

2
Tunnel.h

@ -21,7 +21,7 @@ namespace i2p
{ {
namespace tunnel namespace tunnel
{ {
const int TUNNEL_EXPIRATION_TIMEOUT = 600; // 10 minutes const int TUNNEL_EXPIRATION_TIMEOUT = 660; // 11 minutes
class OutboundTunnel; class OutboundTunnel;
class InboundTunnel; class InboundTunnel;

27
TunnelGateway.cpp

@ -10,7 +10,7 @@ namespace i2p
{ {
namespace tunnel namespace tunnel
{ {
void TunnelGatewayBuffer::PutI2NPMsg (const uint8_t * gwHash, uint32_t gwTunnel, I2NPMessage * msg) void TunnelGatewayBuffer::PutI2NPMsg (const TunnelMessageBlock& block)
{ {
if (!m_CurrentTunnelDataMsg) if (!m_CurrentTunnelDataMsg)
CreateCurrentTunnelDataMessage (); CreateCurrentTunnelDataMessage ();
@ -18,24 +18,21 @@ namespace tunnel
// create delivery instructions // create delivery instructions
uint8_t di[43]; // max delivery instruction length is 43 for tunnel uint8_t di[43]; // max delivery instruction length is 43 for tunnel
size_t diLen = 1;// flag size_t diLen = 1;// flag
TunnelDeliveryType dt = eDeliveryTypeLocal; if (block.deliveryType != eDeliveryTypeLocal) // tunnel or router
if (gwHash)
{ {
if (gwTunnel) if (block.deliveryType == eDeliveryTypeTunnel)
{ {
*(uint32_t *)(di + diLen) = htobe32 (gwTunnel); *(uint32_t *)(di + diLen) = htobe32 (block.tunnelID);
diLen += 4; // tunnelID diLen += 4; // tunnelID
dt = eDeliveryTypeTunnel;
} }
else
dt = eDeliveryTypeRouter;
memcpy (di + diLen, gwHash, 32); memcpy (di + diLen, block.hash, 32);
diLen += 32; //len diLen += 32; //len
} }
di[0] = dt << 5; // set delivery type di[0] = block.deliveryType << 5; // set delivery type
// create fragments // create fragments
I2NPMessage * msg = block.data;
if (diLen + msg->GetLength () + 2<= m_RemainingSize) if (diLen + msg->GetLength () + 2<= m_RemainingSize)
{ {
// message fits. First and last fragment // message fits. First and last fragment
@ -104,7 +101,7 @@ namespace tunnel
{ {
// delivery instructions don't fit. Create new message // delivery instructions don't fit. Create new message
CompleteCurrentTunnelDataMessage (); CompleteCurrentTunnelDataMessage ();
PutI2NPMsg (gwHash, gwTunnel, msg); PutI2NPMsg (block);
// don't delete msg because it's taken care inside // don't delete msg because it's taken care inside
} }
} }
@ -152,15 +149,15 @@ namespace tunnel
m_CurrentTunnelDataMsg = nullptr; m_CurrentTunnelDataMsg = nullptr;
} }
void TunnelGateway::SendTunnelDataMsg (const uint8_t * gwHash, uint32_t gwTunnel, i2p::I2NPMessage * msg) void TunnelGateway::SendTunnelDataMsg (const TunnelMessageBlock& block)
{ {
PutTunnelDataMsg (gwHash, gwTunnel, msg); PutTunnelDataMsg (block);
SendBuffer (); SendBuffer ();
} }
void TunnelGateway::PutTunnelDataMsg (const uint8_t * gwHash, uint32_t gwTunnel, i2p::I2NPMessage * msg) void TunnelGateway::PutTunnelDataMsg (const TunnelMessageBlock& block)
{ {
m_Buffer.PutI2NPMsg (gwHash, gwTunnel, msg); m_Buffer.PutI2NPMsg (block);
} }
void TunnelGateway::SendBuffer () void TunnelGateway::SendBuffer ()

6
TunnelGateway.h

@ -15,7 +15,7 @@ namespace tunnel
public: public:
TunnelGatewayBuffer (uint32_t tunnelID): m_TunnelID (tunnelID), TunnelGatewayBuffer (uint32_t tunnelID): m_TunnelID (tunnelID),
m_CurrentTunnelDataMsg (nullptr), m_RemainingSize (0) {}; m_CurrentTunnelDataMsg (nullptr), m_RemainingSize (0) {};
void PutI2NPMsg (const uint8_t * gwHash, uint32_t gwTunnel, I2NPMessage * msg); void PutI2NPMsg (const TunnelMessageBlock& block);
std::vector<I2NPMessage *> GetTunnelDataMsgs (); std::vector<I2NPMessage *> GetTunnelDataMsgs ();
private: private:
@ -37,8 +37,8 @@ namespace tunnel
TunnelGateway (TunnelBase * tunnel): TunnelGateway (TunnelBase * tunnel):
m_Tunnel (tunnel), m_Buffer (tunnel->GetNextTunnelID ()), m_NumSentBytes (0) {}; m_Tunnel (tunnel), m_Buffer (tunnel->GetNextTunnelID ()), m_NumSentBytes (0) {};
void SendTunnelDataMsg (const uint8_t * gwHash, uint32_t gwTunnel, i2p::I2NPMessage * msg); void SendTunnelDataMsg (const TunnelMessageBlock& block);
void PutTunnelDataMsg (const uint8_t * gwHash, uint32_t gwTunnel, i2p::I2NPMessage * msg); void PutTunnelDataMsg (const TunnelMessageBlock& block);
void SendBuffer (); void SendBuffer ();
size_t GetNumSentBytes () const { return m_NumSentBytes; }; size_t GetNumSentBytes () const { return m_NumSentBytes; };

Loading…
Cancel
Save