mirror of
https://github.com/PurpleI2P/i2pd
synced 2024-11-10 08:00:38 +03:00
Merge pull request #28 from orignal/master
Merge pull request from orignal/master
This commit is contained in:
commit
b6b9c61217
@ -80,7 +80,7 @@ void AddressBook::LoadHosts ()
|
|||||||
getline(f, s);
|
getline(f, s);
|
||||||
|
|
||||||
if (!s.length())
|
if (!s.length())
|
||||||
break;
|
continue; // skip empty line
|
||||||
|
|
||||||
size_t pos = s.find('=');
|
size_t pos = s.find('=');
|
||||||
|
|
||||||
@ -90,8 +90,11 @@ void AddressBook::LoadHosts ()
|
|||||||
std::string addr = s.substr(pos);
|
std::string addr = s.substr(pos);
|
||||||
|
|
||||||
Identity ident;
|
Identity ident;
|
||||||
Base64ToByteStream (addr.c_str(), addr.length(), (uint8_t *)&ident, sizeof (ident));
|
if (!ident.FromBase64(addr)) {
|
||||||
m_Addresses[name] = CalculateIdentHash (ident);
|
LogPrint ("hosts.txt: ignore ", name);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
m_Addresses[name] = ident.Hash();
|
||||||
numAddresses++;
|
numAddresses++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
21
Identity.cpp
21
Identity.cpp
@ -6,6 +6,7 @@
|
|||||||
#include <cryptopp/dsa.h>
|
#include <cryptopp/dsa.h>
|
||||||
#include "CryptoConst.h"
|
#include "CryptoConst.h"
|
||||||
#include "Identity.h"
|
#include "Identity.h"
|
||||||
|
#include "base64.h"
|
||||||
|
|
||||||
namespace i2p
|
namespace i2p
|
||||||
{
|
{
|
||||||
@ -19,6 +20,19 @@ namespace data
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Identity::FromBase64 (const std::string& s)
|
||||||
|
{
|
||||||
|
size_t count = Base64ToByteStream (s.c_str(), s.length(), reinterpret_cast<uint8_t*> (this), sizeof (Identity));
|
||||||
|
return count == sizeof(Identity);
|
||||||
|
}
|
||||||
|
|
||||||
|
IdentHash Identity::Hash()
|
||||||
|
{
|
||||||
|
IdentHash hash;
|
||||||
|
CryptoPP::SHA256().CalculateDigest(reinterpret_cast<uint8_t*>(&hash), reinterpret_cast<uint8_t*> (this), sizeof (Identity));
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
PrivateKeys& PrivateKeys::operator=(const Keys& keys)
|
PrivateKeys& PrivateKeys::operator=(const Keys& keys)
|
||||||
{
|
{
|
||||||
pub = keys;
|
pub = keys;
|
||||||
@ -26,13 +40,6 @@ namespace data
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
IdentHash CalculateIdentHash (const Identity& identity)
|
|
||||||
{
|
|
||||||
IdentHash hash;
|
|
||||||
CryptoPP::SHA256().CalculateDigest((uint8_t *)hash, (uint8_t *)&identity, sizeof (Identity));
|
|
||||||
return hash;
|
|
||||||
}
|
|
||||||
|
|
||||||
Keys CreateRandomKeys ()
|
Keys CreateRandomKeys ()
|
||||||
{
|
{
|
||||||
Keys keys;
|
Keys keys;
|
||||||
|
@ -9,6 +9,8 @@ namespace i2p
|
|||||||
{
|
{
|
||||||
namespace data
|
namespace data
|
||||||
{
|
{
|
||||||
|
class IdentHash;
|
||||||
|
|
||||||
#pragma pack(1)
|
#pragma pack(1)
|
||||||
|
|
||||||
struct DHKeysPair // transient keys for transport sessions
|
struct DHKeysPair // transient keys for transport sessions
|
||||||
@ -32,6 +34,8 @@ namespace data
|
|||||||
uint8_t certificate[3];
|
uint8_t certificate[3];
|
||||||
|
|
||||||
Identity& operator=(const Keys& keys);
|
Identity& operator=(const Keys& keys);
|
||||||
|
bool FromBase64(const std::string&);
|
||||||
|
IdentHash Hash();
|
||||||
};
|
};
|
||||||
|
|
||||||
struct PrivateKeys // for eepsites
|
struct PrivateKeys // for eepsites
|
||||||
@ -75,7 +79,6 @@ namespace data
|
|||||||
uint8_t m_Hash[32];
|
uint8_t m_Hash[32];
|
||||||
};
|
};
|
||||||
|
|
||||||
IdentHash CalculateIdentHash (const Identity& identity);
|
|
||||||
Keys CreateRandomKeys ();
|
Keys CreateRandomKeys ();
|
||||||
void CreateRandomDHKeysPair (DHKeysPair * keys); // for transport sessions
|
void CreateRandomDHKeysPair (DHKeysPair * keys); // for transport sessions
|
||||||
|
|
||||||
@ -103,7 +106,7 @@ namespace data
|
|||||||
public:
|
public:
|
||||||
|
|
||||||
RoutingDestination (): m_ElGamalEncryption (nullptr) {};
|
RoutingDestination (): m_ElGamalEncryption (nullptr) {};
|
||||||
virtual ~RoutingDestination () { delete m_ElGamalEncryption; };
|
virtual ~RoutingDestination () { if (m_ElGamalEncryption) 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;
|
||||||
@ -125,6 +128,7 @@ namespace data
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
virtual ~LocalDestination() {};
|
||||||
virtual const IdentHash& GetIdentHash () const = 0;
|
virtual const IdentHash& GetIdentHash () const = 0;
|
||||||
virtual const uint8_t * GetEncryptionPrivateKey () const = 0;
|
virtual const uint8_t * GetEncryptionPrivateKey () const = 0;
|
||||||
virtual const uint8_t * GetEncryptionPublicKey () const = 0;
|
virtual const uint8_t * GetEncryptionPublicKey () const = 0;
|
||||||
|
@ -25,7 +25,7 @@ namespace data
|
|||||||
|
|
||||||
const H * header = (const H *)buf;
|
const H * header = (const H *)buf;
|
||||||
m_Identity = header->destination;
|
m_Identity = header->destination;
|
||||||
m_IdentHash = CalculateIdentHash (m_Identity);
|
m_IdentHash = m_Identity.Hash();
|
||||||
memcpy (m_EncryptionKey, header->encryptionKey, 256);
|
memcpy (m_EncryptionKey, header->encryptionKey, 256);
|
||||||
LogPrint ("LeaseSet num=", (int)header->num);
|
LogPrint ("LeaseSet num=", (int)header->num);
|
||||||
|
|
||||||
|
@ -519,7 +519,7 @@ namespace ntcp
|
|||||||
void NTCPSession::ScheduleTermination ()
|
void NTCPSession::ScheduleTermination ()
|
||||||
{
|
{
|
||||||
m_TerminationTimer.cancel ();
|
m_TerminationTimer.cancel ();
|
||||||
m_TerminationTimer.expires_from_now (boost::posix_time::seconds(TERMINATION_TIMEOUT));
|
m_TerminationTimer.expires_from_now (boost::posix_time::seconds(NTCP_TERMINATION_TIMEOUT));
|
||||||
m_TerminationTimer.async_wait (boost::bind (&NTCPSession::HandleTerminationTimer,
|
m_TerminationTimer.async_wait (boost::bind (&NTCPSession::HandleTerminationTimer,
|
||||||
this, boost::asio::placeholders::error));
|
this, boost::asio::placeholders::error));
|
||||||
}
|
}
|
||||||
@ -528,7 +528,7 @@ namespace ntcp
|
|||||||
{
|
{
|
||||||
if (ecode != boost::asio::error::operation_aborted)
|
if (ecode != boost::asio::error::operation_aborted)
|
||||||
{
|
{
|
||||||
LogPrint ("No activity fo ", TERMINATION_TIMEOUT, " seconds");
|
LogPrint ("No activity fo ", NTCP_TERMINATION_TIMEOUT, " seconds");
|
||||||
m_Socket.close ();
|
m_Socket.close ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -61,7 +61,7 @@ namespace ntcp
|
|||||||
|
|
||||||
#pragma pack()
|
#pragma pack()
|
||||||
|
|
||||||
const int TERMINATION_TIMEOUT = 120; // 2 minutes
|
const int NTCP_TERMINATION_TIMEOUT = 120; // 2 minutes
|
||||||
class NTCPSession
|
class NTCPSession
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -34,7 +34,7 @@ namespace data
|
|||||||
void RouterInfo::SetRouterIdentity (const Identity& identity)
|
void RouterInfo::SetRouterIdentity (const Identity& identity)
|
||||||
{
|
{
|
||||||
m_RouterIdentity = identity;
|
m_RouterIdentity = identity;
|
||||||
m_IdentHash = CalculateIdentHash (m_RouterIdentity);
|
m_IdentHash = m_RouterIdentity.Hash ();
|
||||||
UpdateIdentHashBase64 ();
|
UpdateIdentHashBase64 ();
|
||||||
UpdateRoutingKey ();
|
UpdateRoutingKey ();
|
||||||
m_Timestamp = i2p::util::GetMillisecondsSinceEpoch ();
|
m_Timestamp = i2p::util::GetMillisecondsSinceEpoch ();
|
||||||
@ -129,6 +129,8 @@ 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 (!strcmp (key, "caps"))
|
||||||
|
ExtractCaps (value);
|
||||||
else if (key[0] == 'i')
|
else if (key[0] == 'i')
|
||||||
{
|
{
|
||||||
// introducers
|
// introducers
|
||||||
@ -191,7 +193,6 @@ namespace data
|
|||||||
|
|
||||||
void RouterInfo::ExtractCaps (const char * value)
|
void RouterInfo::ExtractCaps (const char * value)
|
||||||
{
|
{
|
||||||
m_Caps = 0;
|
|
||||||
const char * cap = value;
|
const char * cap = value;
|
||||||
while (*cap)
|
while (*cap)
|
||||||
{
|
{
|
||||||
@ -208,6 +209,12 @@ namespace data
|
|||||||
case 'R':
|
case 'R':
|
||||||
m_Caps |= Caps::eReachable;
|
m_Caps |= Caps::eReachable;
|
||||||
break;
|
break;
|
||||||
|
case 'B':
|
||||||
|
m_Caps |= Caps::eSSUTesting;
|
||||||
|
break;
|
||||||
|
case 'C':
|
||||||
|
m_Caps |= Caps::eSSUIntroducer;
|
||||||
|
break;
|
||||||
default: ;
|
default: ;
|
||||||
}
|
}
|
||||||
cap++;
|
cap++;
|
||||||
@ -249,7 +256,10 @@ namespace data
|
|||||||
// caps
|
// caps
|
||||||
WriteString ("caps", properties);
|
WriteString ("caps", properties);
|
||||||
properties << '=';
|
properties << '=';
|
||||||
WriteString ("B", properties); // TODO: should be 'BC' for introducers
|
std::string caps;
|
||||||
|
if (IsPeerTesting ()) caps += 'B';
|
||||||
|
if (IsIntroducer ()) caps += 'C';
|
||||||
|
WriteString (caps, properties);
|
||||||
properties << ';';
|
properties << ';';
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -344,11 +354,12 @@ namespace data
|
|||||||
addr.host = boost::asio::ip::address::from_string (host);
|
addr.host = boost::asio::ip::address::from_string (host);
|
||||||
addr.port = port;
|
addr.port = port;
|
||||||
addr.transportStyle = eTransportSSU;
|
addr.transportStyle = eTransportSSU;
|
||||||
addr.cost = 10; // NTCP should have prioprity over SSU
|
addr.cost = 10; // NTCP should have priority over SSU
|
||||||
addr.date = 0;
|
addr.date = 0;
|
||||||
memcpy (addr.key, key, 32);
|
memcpy (addr.key, key, 32);
|
||||||
m_Addresses.push_back(addr);
|
m_Addresses.push_back(addr);
|
||||||
m_SupportedTransports |= eSSUV4;
|
m_SupportedTransports |= eSSUV4;
|
||||||
|
m_Caps |= eSSUTesting; // TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
void RouterInfo::SetProperty (const char * key, const char * value)
|
void RouterInfo::SetProperty (const char * key, const char * value)
|
||||||
|
@ -29,7 +29,9 @@ namespace data
|
|||||||
{
|
{
|
||||||
eFloodfill = 0x01,
|
eFloodfill = 0x01,
|
||||||
eHighBandwidth = 0x02,
|
eHighBandwidth = 0x02,
|
||||||
eReachable = 0x04
|
eReachable = 0x04,
|
||||||
|
eSSUTesting = 0x08,
|
||||||
|
eSSUIntroducer = 0x10
|
||||||
};
|
};
|
||||||
|
|
||||||
enum TransportStyle
|
enum TransportStyle
|
||||||
@ -84,6 +86,8 @@ namespace data
|
|||||||
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;
|
bool UsesIntroducer () const;
|
||||||
|
bool IsIntroducer () const { return m_Caps & eSSUIntroducer; };
|
||||||
|
bool IsPeerTesting () const { return m_Caps & eSSUTesting; };
|
||||||
uint8_t GetCaps () const { return m_Caps; };
|
uint8_t GetCaps () const { return m_Caps; };
|
||||||
|
|
||||||
void SetUnreachable (bool unreachable) { m_IsUnreachable = unreachable; };
|
void SetUnreachable (bool unreachable) { m_IsUnreachable = unreachable; };
|
||||||
|
274
SSU.cpp
274
SSU.cpp
@ -16,8 +16,10 @@ namespace ssu
|
|||||||
{
|
{
|
||||||
|
|
||||||
SSUSession::SSUSession (SSUServer& server, boost::asio::ip::udp::endpoint& remoteEndpoint,
|
SSUSession::SSUSession (SSUServer& server, boost::asio::ip::udp::endpoint& remoteEndpoint,
|
||||||
const i2p::data::RouterInfo * router): m_Server (server), m_RemoteEndpoint (remoteEndpoint),
|
const i2p::data::RouterInfo * router, bool peerTest ):
|
||||||
m_RemoteRouter (router), m_Timer (m_Server.GetService ()), m_State (eSessionStateUnknown)
|
m_Server (server), m_RemoteEndpoint (remoteEndpoint), m_RemoteRouter (router),
|
||||||
|
m_Timer (m_Server.GetService ()), m_PeerTest (peerTest), m_State (eSessionStateUnknown),
|
||||||
|
m_RelayTag (0)
|
||||||
{
|
{
|
||||||
m_DHKeysPair = i2p::transports.GetNextDHKeysPair ();
|
m_DHKeysPair = i2p::transports.GetNextDHKeysPair ();
|
||||||
}
|
}
|
||||||
@ -57,16 +59,14 @@ namespace ssu
|
|||||||
case eSessionStateConfirmedSent:
|
case eSessionStateConfirmedSent:
|
||||||
case eSessionStateEstablished:
|
case eSessionStateEstablished:
|
||||||
// most common case
|
// most common case
|
||||||
ProcessMessage (buf, len);
|
ScheduleTermination ();
|
||||||
|
ProcessMessage (buf, len, senderEndpoint);
|
||||||
break;
|
break;
|
||||||
// establishing
|
// establishing or testing
|
||||||
case eSessionStateUnknown:
|
case eSessionStateUnknown:
|
||||||
// session request
|
|
||||||
ProcessSessionRequest (buf, len, senderEndpoint);
|
|
||||||
break;
|
|
||||||
case eSessionStateRequestSent:
|
case eSessionStateRequestSent:
|
||||||
// session created
|
// we must use intro key
|
||||||
ProcessSessionCreated (buf, len);
|
ProcessIntroKeyMessage (buf, len, senderEndpoint);
|
||||||
break;
|
break;
|
||||||
case eSessionStateCreatedSent:
|
case eSessionStateCreatedSent:
|
||||||
// session confirmed
|
// session confirmed
|
||||||
@ -92,21 +92,21 @@ namespace ssu
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SSUSession::ProcessMessage (uint8_t * buf, size_t len)
|
void SSUSession::ProcessMessage (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint)
|
||||||
{
|
{
|
||||||
if (Validate (buf, len, m_MacKey))
|
if (Validate (buf, len, m_MacKey))
|
||||||
{
|
{
|
||||||
Decrypt (buf, len, m_SessionKey);
|
Decrypt (buf, len, m_SessionKey);
|
||||||
SSUHeader * header = (SSUHeader *)buf;
|
SSUHeader * header = (SSUHeader *)buf;
|
||||||
uint8_t payloadType = header->flag >> 4;
|
switch (header->GetPayloadType ())
|
||||||
switch (payloadType)
|
|
||||||
{
|
{
|
||||||
case PAYLOAD_TYPE_DATA:
|
case PAYLOAD_TYPE_DATA:
|
||||||
LogPrint ("SSU data received");
|
LogPrint ("SSU data received");
|
||||||
ProcessData (buf + sizeof (SSUHeader), len - sizeof (SSUHeader));
|
ProcessData (buf + sizeof (SSUHeader), len - sizeof (SSUHeader));
|
||||||
break;
|
break;
|
||||||
case PAYLOAD_TYPE_TEST:
|
case PAYLOAD_TYPE_PEER_TEST:
|
||||||
LogPrint ("SSU test received");
|
LogPrint ("SSU peer test received");
|
||||||
|
ProcessPeerTest (buf + sizeof (SSUHeader), len - sizeof (SSUHeader), senderEndpoint);
|
||||||
break;
|
break;
|
||||||
case PAYLOAD_TYPE_SESSION_DESTROYED:
|
case PAYLOAD_TYPE_SESSION_DESTROYED:
|
||||||
{
|
{
|
||||||
@ -116,10 +116,10 @@ namespace ssu
|
|||||||
}
|
}
|
||||||
case PAYLOAD_TYPE_RELAY_INTRO:
|
case PAYLOAD_TYPE_RELAY_INTRO:
|
||||||
LogPrint ("SSU relay intro received");
|
LogPrint ("SSU relay intro received");
|
||||||
// TODO:
|
ProcessRelayIntro (buf + sizeof (SSUHeader), len - sizeof (SSUHeader));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
LogPrint ("Unexpected SSU payload type ", (int)payloadType);
|
LogPrint ("Unexpected SSU payload type ", (int)header->GetPayloadType ());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -139,31 +139,57 @@ namespace ssu
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SSUSession::ProcessSessionRequest (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint)
|
void SSUSession::ProcessIntroKeyMessage (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint)
|
||||||
{
|
{
|
||||||
LogPrint ("Process session request");
|
auto introKey = GetIntroKey ();
|
||||||
// use our intro key
|
if (!introKey)
|
||||||
if (ProcessIntroKeyEncryptedMessage (PAYLOAD_TYPE_SESSION_REQUEST, buf, len))
|
{
|
||||||
|
LogPrint ("SSU is not supported");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// use intro key for verification and decryption
|
||||||
|
if (!Validate (buf, len, introKey))
|
||||||
|
{
|
||||||
|
LogPrint ("MAC verification intro key failed");
|
||||||
|
Failed ();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Decrypt (buf, len, introKey);
|
||||||
|
CreateAESandMacKey (buf + sizeof (SSUHeader), m_SessionKey, m_MacKey);
|
||||||
|
SSUHeader * header = (SSUHeader *)buf;
|
||||||
|
switch (header->GetPayloadType ())
|
||||||
|
{
|
||||||
|
case PAYLOAD_TYPE_SESSION_REQUEST:
|
||||||
|
ProcessSessionRequest (buf, len, senderEndpoint);
|
||||||
|
break;
|
||||||
|
case PAYLOAD_TYPE_SESSION_CREATED:
|
||||||
|
ProcessSessionCreated (buf, len);
|
||||||
|
break;
|
||||||
|
case PAYLOAD_TYPE_PEER_TEST:
|
||||||
|
LogPrint ("SSU peer test received");
|
||||||
|
// TODO:
|
||||||
|
break;
|
||||||
|
default: ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SSUSession::ProcessSessionRequest (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint)
|
||||||
{
|
{
|
||||||
m_State = eSessionStateRequestReceived;
|
m_State = eSessionStateRequestReceived;
|
||||||
LogPrint ("Session request received");
|
LogPrint ("Session request received");
|
||||||
m_RemoteEndpoint = senderEndpoint;
|
m_RemoteEndpoint = senderEndpoint;
|
||||||
SendSessionCreated (buf + sizeof (SSUHeader));
|
SendSessionCreated (buf + sizeof (SSUHeader));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void SSUSession::ProcessSessionCreated (uint8_t * buf, size_t len)
|
void SSUSession::ProcessSessionCreated (uint8_t * buf, size_t len)
|
||||||
{
|
{
|
||||||
LogPrint ("Process session created");
|
|
||||||
if (!m_RemoteRouter)
|
if (!m_RemoteRouter)
|
||||||
{
|
{
|
||||||
LogPrint ("Unsolicited session created message");
|
LogPrint ("Unsolicited session created message");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// use remote intro key
|
|
||||||
if (ProcessIntroKeyEncryptedMessage (PAYLOAD_TYPE_SESSION_CREATED, buf, len))
|
|
||||||
{
|
|
||||||
m_State = eSessionStateCreatedReceived;
|
m_State = eSessionStateCreatedReceived;
|
||||||
LogPrint ("Session created received");
|
LogPrint ("Session created received");
|
||||||
m_Timer.cancel (); // connect timer
|
m_Timer.cancel (); // connect timer
|
||||||
@ -185,7 +211,7 @@ namespace ssu
|
|||||||
*(uint32_t *)(signedData + 518) = htobe32 (m_RemoteEndpoint.address ().to_v4 ().to_ulong ()); // remote IP
|
*(uint32_t *)(signedData + 518) = htobe32 (m_RemoteEndpoint.address ().to_v4 ().to_ulong ()); // remote IP
|
||||||
*(uint16_t *)(signedData + 522) = htobe16 (m_RemoteEndpoint.port ()); // remote port
|
*(uint16_t *)(signedData + 522) = htobe16 (m_RemoteEndpoint.port ()); // remote port
|
||||||
memcpy (signedData + 524, payload, 8); // relayTag and signed on time
|
memcpy (signedData + 524, payload, 8); // relayTag and signed on time
|
||||||
uint32_t relayTag = be32toh (*(uint32_t *)payload);
|
m_RelayTag = be32toh (*(uint32_t *)payload);
|
||||||
payload += 4; // relayTag
|
payload += 4; // relayTag
|
||||||
payload += 4; // signed on time
|
payload += 4; // signed on time
|
||||||
// decrypt DSA signature
|
// decrypt DSA signature
|
||||||
@ -198,8 +224,7 @@ namespace ssu
|
|||||||
if (!verifier.VerifyMessage (signedData, 532, payload, 40))
|
if (!verifier.VerifyMessage (signedData, 532, payload, 40))
|
||||||
LogPrint ("SSU signature verification failed");
|
LogPrint ("SSU signature verification failed");
|
||||||
|
|
||||||
SendSessionConfirmed (y, ourAddress, relayTag);
|
SendSessionConfirmed (y, ourAddress);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SSUSession::ProcessSessionConfirmed (uint8_t * buf, size_t len)
|
void SSUSession::ProcessSessionConfirmed (uint8_t * buf, size_t len)
|
||||||
@ -209,7 +234,7 @@ namespace ssu
|
|||||||
{
|
{
|
||||||
Decrypt (buf, len, m_SessionKey);
|
Decrypt (buf, len, m_SessionKey);
|
||||||
SSUHeader * header = (SSUHeader *)buf;
|
SSUHeader * header = (SSUHeader *)buf;
|
||||||
if ((header->flag >> 4) == PAYLOAD_TYPE_SESSION_CONFIRMED)
|
if (header->GetPayloadType () == PAYLOAD_TYPE_SESSION_CONFIRMED)
|
||||||
{
|
{
|
||||||
m_State = eSessionStateConfirmedReceived;
|
m_State = eSessionStateConfirmedReceived;
|
||||||
LogPrint ("Session confirmed received");
|
LogPrint ("Session confirmed received");
|
||||||
@ -326,7 +351,7 @@ namespace ssu
|
|||||||
m_Server.Send (buf, 368, m_RemoteEndpoint);
|
m_Server.Send (buf, 368, m_RemoteEndpoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SSUSession::SendSessionConfirmed (const uint8_t * y, const uint8_t * ourAddress, uint32_t relayTag)
|
void SSUSession::SendSessionConfirmed (const uint8_t * y, const uint8_t * ourAddress)
|
||||||
{
|
{
|
||||||
uint8_t buf[480 + 18];
|
uint8_t buf[480 + 18];
|
||||||
uint8_t * payload = buf + sizeof (SSUHeader);
|
uint8_t * payload = buf + sizeof (SSUHeader);
|
||||||
@ -352,7 +377,7 @@ namespace ssu
|
|||||||
memcpy (signedData + 512, ourAddress, 6); // our address/port as seem by party
|
memcpy (signedData + 512, ourAddress, 6); // our address/port as seem by party
|
||||||
*(uint32_t *)(signedData + 518) = htobe32 (m_RemoteEndpoint.address ().to_v4 ().to_ulong ()); // remote IP
|
*(uint32_t *)(signedData + 518) = htobe32 (m_RemoteEndpoint.address ().to_v4 ().to_ulong ()); // remote IP
|
||||||
*(uint16_t *)(signedData + 522) = htobe16 (m_RemoteEndpoint.port ()); // remote port
|
*(uint16_t *)(signedData + 522) = htobe16 (m_RemoteEndpoint.port ()); // remote port
|
||||||
*(uint32_t *)(signedData + 524) = htobe32 (relayTag); // relay tag
|
*(uint32_t *)(signedData + 524) = htobe32 (m_RelayTag); // relay tag
|
||||||
*(uint32_t *)(signedData + 528) = htobe32 (signedOnTime); // signed on time
|
*(uint32_t *)(signedData + 528) = htobe32 (signedOnTime); // signed on time
|
||||||
i2p::context.Sign (signedData, 532, payload); // DSA signature
|
i2p::context.Sign (signedData, 532, payload); // DSA signature
|
||||||
|
|
||||||
@ -406,33 +431,20 @@ namespace ssu
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SSUSession::ProcessIntroKeyEncryptedMessage (uint8_t expectedPayloadType, uint8_t * buf, size_t len)
|
void SSUSession::ProcessRelayIntro (uint8_t * buf, size_t len)
|
||||||
{
|
{
|
||||||
auto introKey = GetIntroKey ();
|
uint8_t size = *buf;
|
||||||
if (introKey)
|
if (size == 4)
|
||||||
{
|
{
|
||||||
// use intro key for verification and decryption
|
buf++; // size
|
||||||
if (Validate (buf, len, introKey))
|
boost::asio::ip::address_v4 address (be32toh (*(uint32_t* )buf));
|
||||||
{
|
buf += 4; // address
|
||||||
Decrypt (buf, len, introKey);
|
uint16_t port = be16toh (*(uint16_t *)buf);
|
||||||
SSUHeader * header = (SSUHeader *)buf;
|
// send hole punch of 1 byte
|
||||||
if ((header->flag >> 4) == expectedPayloadType)
|
m_Server.Send (buf, 1, boost::asio::ip::udp::endpoint (address, port));
|
||||||
{
|
|
||||||
CreateAESandMacKey (buf + sizeof (SSUHeader), m_SessionKey, m_MacKey);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
LogPrint ("Unexpected payload type ", (int)(header->flag >> 4));
|
LogPrint ("Address size ", size, " is not supported");
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
LogPrint ("MAC verification failed");
|
|
||||||
Failed ();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
LogPrint ("SSU is not supported");
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SSUSession::FillHeaderAndEncrypt (uint8_t payloadType, uint8_t * buf, size_t len,
|
void SSUSession::FillHeaderAndEncrypt (uint8_t payloadType, uint8_t * buf, size_t len,
|
||||||
@ -544,6 +556,9 @@ namespace ssu
|
|||||||
Send (it);
|
Send (it);
|
||||||
m_DelayedMessages.clear ();
|
m_DelayedMessages.clear ();
|
||||||
}
|
}
|
||||||
|
if (m_PeerTest)
|
||||||
|
SendPeerTest ();
|
||||||
|
ScheduleTermination ();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SSUSession::Failed ()
|
void SSUSession::Failed ()
|
||||||
@ -556,6 +571,23 @@ namespace ssu
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SSUSession::ScheduleTermination ()
|
||||||
|
{
|
||||||
|
m_Timer.cancel ();
|
||||||
|
m_Timer.expires_from_now (boost::posix_time::seconds(SSU_TERMINATION_TIMEOUT));
|
||||||
|
m_Timer.async_wait (boost::bind (&SSUSession::HandleTerminationTimer,
|
||||||
|
this, boost::asio::placeholders::error));
|
||||||
|
}
|
||||||
|
|
||||||
|
void SSUSession::HandleTerminationTimer (const boost::system::error_code& ecode)
|
||||||
|
{
|
||||||
|
if (ecode != boost::asio::error::operation_aborted)
|
||||||
|
{
|
||||||
|
LogPrint ("SSU no activity fo ", SSU_TERMINATION_TIMEOUT, " seconds");
|
||||||
|
Failed ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const uint8_t * SSUSession::GetIntroKey () const
|
const uint8_t * SSUSession::GetIntroKey () const
|
||||||
{
|
{
|
||||||
if (m_RemoteRouter)
|
if (m_RemoteRouter)
|
||||||
@ -678,6 +710,87 @@ namespace ssu
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void SSUSession::ProcessPeerTest (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint)
|
||||||
|
{
|
||||||
|
uint8_t * buf1 = buf;
|
||||||
|
uint32_t nonce = be32toh (*(uint32_t *)buf);
|
||||||
|
buf += 4; // nonce
|
||||||
|
uint8_t size = *buf;
|
||||||
|
buf++; // size
|
||||||
|
uint8_t * address = (size == 4) ? buf : nullptr;
|
||||||
|
buf += size; // address
|
||||||
|
uint16_t port = *(uint16_t *)buf; // use it as is
|
||||||
|
buf += 2; // port
|
||||||
|
uint8_t * introKey = buf;
|
||||||
|
if (port)
|
||||||
|
{
|
||||||
|
LogPrint ("SSU peer test. We are Charlie");
|
||||||
|
Send (PAYLOAD_TYPE_PEER_TEST, buf1, len); // back to Bob
|
||||||
|
if (address)
|
||||||
|
SendPeerTest (nonce, be32toh (*(uint32_t *)address), be16toh (port), introKey); // to Alice
|
||||||
|
else
|
||||||
|
LogPrint ("Address of ", size, " bytes not supported");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LogPrint ("SSU peer test. We are Bob");
|
||||||
|
// TODO:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SSUSession::SendPeerTest (uint32_t nonce, uint32_t address, uint16_t port, uint8_t * introKey)
|
||||||
|
{
|
||||||
|
uint8_t buf[80 + 18];
|
||||||
|
uint8_t iv[16];
|
||||||
|
uint8_t * payload = buf + sizeof (SSUHeader);
|
||||||
|
*(uint32_t *)payload = htobe32 (nonce);
|
||||||
|
payload += 4; // nonce
|
||||||
|
*payload = 4;
|
||||||
|
payload++; // size
|
||||||
|
*(uint32_t *)payload = htobe32 (address);
|
||||||
|
payload += 4; // address
|
||||||
|
*(uint16_t *)payload = htobe32 (port);
|
||||||
|
payload += 2; // port
|
||||||
|
memcpy (payload, introKey, 32); // intro key
|
||||||
|
|
||||||
|
CryptoPP::RandomNumberGenerator& rnd = i2p::context.GetRandomNumberGenerator ();
|
||||||
|
rnd.GenerateBlock (iv, 16); // random iv
|
||||||
|
// encrypt message with specified intro key
|
||||||
|
FillHeaderAndEncrypt (PAYLOAD_TYPE_PEER_TEST, buf, 80, introKey, iv, introKey);
|
||||||
|
boost::asio::ip::udp::endpoint e (boost::asio::ip::address_v4 (address), port);
|
||||||
|
m_Server.Send (buf, 80, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SSUSession::SendPeerTest ()
|
||||||
|
{
|
||||||
|
LogPrint ("SSU sending peer test");
|
||||||
|
auto address = i2p::context.GetRouterInfo ().GetSSUAddress ();
|
||||||
|
if (!address)
|
||||||
|
{
|
||||||
|
LogPrint ("SSU is not supported. Can't send peer test");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto introKey = address->key;
|
||||||
|
uint8_t buf[80 + 18];
|
||||||
|
uint8_t * payload = buf + sizeof (SSUHeader);
|
||||||
|
CryptoPP::RandomNumberGenerator& rnd = i2p::context.GetRandomNumberGenerator ();
|
||||||
|
uint32_t nonce = 0;
|
||||||
|
rnd.GenerateWord32 (nonce);
|
||||||
|
*(uint32_t *)payload = htobe32 (nonce);
|
||||||
|
payload += 4; // nonce
|
||||||
|
*payload = 4;
|
||||||
|
payload++; // size
|
||||||
|
memset (payload, 0, 6); // address and port always zero for Alice
|
||||||
|
payload += 6; // address and port
|
||||||
|
memcpy (payload, introKey, 32); // intro key
|
||||||
|
uint8_t iv[16];
|
||||||
|
rnd.GenerateBlock (iv, 16); // random iv
|
||||||
|
// encrypt message with session key
|
||||||
|
FillHeaderAndEncrypt (PAYLOAD_TYPE_PEER_TEST, buf, 80, m_SessionKey, iv, m_MacKey);
|
||||||
|
m_Server.Send (buf, 80, m_RemoteEndpoint);
|
||||||
|
}
|
||||||
|
|
||||||
void SSUSession::SendMsgAck (uint32_t msgID)
|
void SSUSession::SendMsgAck (uint32_t msgID)
|
||||||
{
|
{
|
||||||
uint8_t buf[48 + 18]; // actual length is 44 = 37 + 7 but pad it to multiple of 16
|
uint8_t buf[48 + 18]; // actual length is 44 = 37 + 7 but pad it to multiple of 16
|
||||||
@ -704,22 +817,12 @@ namespace ssu
|
|||||||
CryptoPP::RandomNumberGenerator& rnd = i2p::context.GetRandomNumberGenerator ();
|
CryptoPP::RandomNumberGenerator& rnd = i2p::context.GetRandomNumberGenerator ();
|
||||||
rnd.GenerateBlock (iv, 16); // random iv
|
rnd.GenerateBlock (iv, 16); // random iv
|
||||||
if (m_State == eSessionStateEstablished)
|
if (m_State == eSessionStateEstablished)
|
||||||
|
{
|
||||||
// encrypt message with session key
|
// encrypt message with session key
|
||||||
FillHeaderAndEncrypt (PAYLOAD_TYPE_SESSION_DESTROYED, buf, 48, m_SessionKey, iv, m_MacKey);
|
FillHeaderAndEncrypt (PAYLOAD_TYPE_SESSION_DESTROYED, buf, 48, m_SessionKey, iv, m_MacKey);
|
||||||
else
|
|
||||||
{
|
|
||||||
auto introKey = GetIntroKey ();
|
|
||||||
if (introKey)
|
|
||||||
// encrypt message with intro key
|
|
||||||
FillHeaderAndEncrypt (PAYLOAD_TYPE_SESSION_DESTROYED, buf, 48, introKey, iv, introKey);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
LogPrint ("SSU: can't send SessionDestroyed message");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
m_Server.Send (buf, 48, m_RemoteEndpoint);
|
m_Server.Send (buf, 48, m_RemoteEndpoint);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void SSUSession::Send (i2p::I2NPMessage * msg)
|
void SSUSession::Send (i2p::I2NPMessage * msg)
|
||||||
{
|
{
|
||||||
@ -771,6 +874,24 @@ namespace ssu
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SSUSession::Send (uint8_t type, const uint8_t * payload, size_t len)
|
||||||
|
{
|
||||||
|
uint8_t buf[SSU_MTU + 18];
|
||||||
|
uint8_t iv[16];
|
||||||
|
size_t msgSize = len + sizeof (SSUHeader);
|
||||||
|
if (msgSize > SSU_MTU)
|
||||||
|
{
|
||||||
|
LogPrint ("SSU payload size ", msgSize, " exceeds MTU");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
memcpy (buf + sizeof (SSUHeader), payload, len);
|
||||||
|
CryptoPP::RandomNumberGenerator& rnd = i2p::context.GetRandomNumberGenerator ();
|
||||||
|
rnd.GenerateBlock (iv, 16); // random iv
|
||||||
|
// encrypt message with session key
|
||||||
|
FillHeaderAndEncrypt (type, buf, msgSize, m_SessionKey, iv, m_MacKey);
|
||||||
|
m_Server.Send (buf, msgSize, m_RemoteEndpoint);
|
||||||
|
}
|
||||||
|
|
||||||
SSUServer::SSUServer (boost::asio::io_service& service, int port):
|
SSUServer::SSUServer (boost::asio::io_service& service, int port):
|
||||||
m_Endpoint (boost::asio::ip::udp::v4 (), port), m_Socket (service, m_Endpoint)
|
m_Endpoint (boost::asio::ip::udp::v4 (), port), m_Socket (service, m_Endpoint)
|
||||||
{
|
{
|
||||||
@ -841,7 +962,7 @@ namespace ssu
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
SSUSession * SSUServer::GetSession (const i2p::data::RouterInfo * router)
|
SSUSession * SSUServer::GetSession (const i2p::data::RouterInfo * router, bool peerTest)
|
||||||
{
|
{
|
||||||
SSUSession * session = nullptr;
|
SSUSession * session = nullptr;
|
||||||
if (router)
|
if (router)
|
||||||
@ -859,10 +980,10 @@ namespace ssu
|
|||||||
if (!router->UsesIntroducer ())
|
if (!router->UsesIntroducer ())
|
||||||
{
|
{
|
||||||
// connect directly
|
// connect directly
|
||||||
session = new SSUSession (*this, remoteEndpoint, router);
|
session = new SSUSession (*this, remoteEndpoint, router, peerTest);
|
||||||
m_Sessions[remoteEndpoint] = session;
|
m_Sessions[remoteEndpoint] = session;
|
||||||
LogPrint ("New SSU session to [", router->GetIdentHashAbbreviation (), "] ",
|
LogPrint ("Creating new SSU session to [", router->GetIdentHashAbbreviation (), "] ",
|
||||||
remoteEndpoint.address ().to_string (), ":", remoteEndpoint.port (), " created");
|
remoteEndpoint.address ().to_string (), ":", remoteEndpoint.port ());
|
||||||
session->Connect ();
|
session->Connect ();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -872,12 +993,21 @@ namespace ssu
|
|||||||
{
|
{
|
||||||
auto& introducer = address->introducers[0]; // TODO:
|
auto& introducer = address->introducers[0]; // TODO:
|
||||||
boost::asio::ip::udp::endpoint introducerEndpoint (introducer.iHost, introducer.iPort);
|
boost::asio::ip::udp::endpoint introducerEndpoint (introducer.iHost, introducer.iPort);
|
||||||
|
it = m_Sessions.find (introducerEndpoint);
|
||||||
|
if (it == m_Sessions.end ())
|
||||||
|
{
|
||||||
session = new SSUSession (*this, introducerEndpoint, router);
|
session = new SSUSession (*this, introducerEndpoint, router);
|
||||||
m_Sessions[introducerEndpoint] = session;
|
m_Sessions[introducerEndpoint] = session;
|
||||||
LogPrint ("New SSU session to [", router->GetIdentHashAbbreviation (),
|
LogPrint ("Creating new SSU session to [", router->GetIdentHashAbbreviation (),
|
||||||
"] through introducer ", introducerEndpoint.address ().to_string (), ":", introducerEndpoint.port ());
|
"] through introducer ", introducerEndpoint.address ().to_string (), ":", introducerEndpoint.port ());
|
||||||
session->ConnectThroughIntroducer (introducer);
|
session->ConnectThroughIntroducer (introducer);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LogPrint ("Session to introducer already exists");
|
||||||
|
// TODO:
|
||||||
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
LogPrint ("Router is unreachable, but not introducers presentd. Ignored");
|
LogPrint ("Router is unreachable, but not introducers presentd. Ignored");
|
||||||
}
|
}
|
||||||
@ -917,7 +1047,7 @@ namespace ssu
|
|||||||
auto session = it->second;
|
auto session = it->second;
|
||||||
m_Sessions.erase (it);
|
m_Sessions.erase (it);
|
||||||
m_Sessions[newEndpoint] = session;
|
m_Sessions[newEndpoint] = session;
|
||||||
LogPrint ("SSU session ressigned from ", oldEndpoint.address ().to_string (), ":", oldEndpoint.port (),
|
LogPrint ("SSU session reassigned from ", oldEndpoint.address ().to_string (), ":", oldEndpoint.port (),
|
||||||
" to ", newEndpoint.address ().to_string (), ":", newEndpoint.port ());
|
" to ", newEndpoint.address ().to_string (), ":", newEndpoint.port ());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
28
SSU.h
28
SSU.h
@ -23,11 +23,14 @@ namespace ssu
|
|||||||
uint8_t iv[16];
|
uint8_t iv[16];
|
||||||
uint8_t flag;
|
uint8_t flag;
|
||||||
uint32_t time;
|
uint32_t time;
|
||||||
|
|
||||||
|
uint8_t GetPayloadType () const { return flag >> 4; };
|
||||||
};
|
};
|
||||||
#pragma pack()
|
#pragma pack()
|
||||||
|
|
||||||
const int SSU_MTU = 1484;
|
const size_t SSU_MTU = 1484;
|
||||||
const int SSU_CONNECT_TIMEOUT = 5; // 5 seconds
|
const int SSU_CONNECT_TIMEOUT = 5; // 5 seconds
|
||||||
|
const int SSU_TERMINATION_TIMEOUT = 330; // 5.5 minutes
|
||||||
|
|
||||||
// payload types (4 bits)
|
// payload types (4 bits)
|
||||||
const uint8_t PAYLOAD_TYPE_SESSION_REQUEST = 0;
|
const uint8_t PAYLOAD_TYPE_SESSION_REQUEST = 0;
|
||||||
@ -37,7 +40,7 @@ namespace ssu
|
|||||||
const uint8_t PAYLOAD_TYPE_RELAY_RESPONSE = 4;
|
const uint8_t PAYLOAD_TYPE_RELAY_RESPONSE = 4;
|
||||||
const uint8_t PAYLOAD_TYPE_RELAY_INTRO = 5;
|
const uint8_t PAYLOAD_TYPE_RELAY_INTRO = 5;
|
||||||
const uint8_t PAYLOAD_TYPE_DATA = 6;
|
const uint8_t PAYLOAD_TYPE_DATA = 6;
|
||||||
const uint8_t PAYLOAD_TYPE_TEST = 7;
|
const uint8_t PAYLOAD_TYPE_PEER_TEST = 7;
|
||||||
const uint8_t PAYLOAD_TYPE_SESSION_DESTROYED = 8;
|
const uint8_t PAYLOAD_TYPE_SESSION_DESTROYED = 8;
|
||||||
|
|
||||||
// data flags
|
// data flags
|
||||||
@ -70,7 +73,7 @@ namespace ssu
|
|||||||
public:
|
public:
|
||||||
|
|
||||||
SSUSession (SSUServer& server, boost::asio::ip::udp::endpoint& remoteEndpoint,
|
SSUSession (SSUServer& server, boost::asio::ip::udp::endpoint& remoteEndpoint,
|
||||||
const i2p::data::RouterInfo * router = nullptr);
|
const i2p::data::RouterInfo * router = nullptr, bool peerTest = false);
|
||||||
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);
|
||||||
~SSUSession ();
|
~SSUSession ();
|
||||||
|
|
||||||
@ -80,34 +83,43 @@ namespace ssu
|
|||||||
boost::asio::ip::udp::endpoint& GetRemoteEndpoint () { return m_RemoteEndpoint; };
|
boost::asio::ip::udp::endpoint& GetRemoteEndpoint () { return m_RemoteEndpoint; };
|
||||||
const i2p::data::RouterInfo * GetRemoteRouter () const { return m_RemoteRouter; };
|
const i2p::data::RouterInfo * GetRemoteRouter () const { return m_RemoteRouter; };
|
||||||
void SendI2NPMessage (I2NPMessage * msg);
|
void SendI2NPMessage (I2NPMessage * msg);
|
||||||
|
void SendPeerTest (); // Alice
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void CreateAESandMacKey (uint8_t * pubKey, uint8_t * aesKey, uint8_t * macKey);
|
void CreateAESandMacKey (uint8_t * pubKey, uint8_t * aesKey, uint8_t * macKey);
|
||||||
|
|
||||||
void ProcessMessage (uint8_t * buf, size_t len); // call for established session
|
void ProcessMessage (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint); // call for established session
|
||||||
|
void ProcessIntroKeyMessage (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint); // call for non-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 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);
|
||||||
void ProcessRelayResponse (uint8_t * buf, size_t len);
|
void ProcessRelayResponse (uint8_t * buf, size_t len);
|
||||||
|
void ProcessRelayIntro (uint8_t * buf, size_t len);
|
||||||
void Established ();
|
void Established ();
|
||||||
void Failed ();
|
void Failed ();
|
||||||
void HandleConnectTimer (const boost::system::error_code& ecode);
|
void HandleConnectTimer (const boost::system::error_code& ecode);
|
||||||
|
void ProcessPeerTest (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint);
|
||||||
|
void SendPeerTest (uint32_t nonce, uint32_t address, uint16_t port, uint8_t * introKey); // Charlie to Alice
|
||||||
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);
|
||||||
void SendSesionDestroyed ();
|
void SendSesionDestroyed ();
|
||||||
void Send (i2p::I2NPMessage * msg);
|
void Send (i2p::I2NPMessage * msg);
|
||||||
|
void Send (uint8_t type, const uint8_t * payload, size_t len); // with session key
|
||||||
|
|
||||||
bool ProcessIntroKeyEncryptedMessage (uint8_t expectedPayloadType, uint8_t * buf, size_t len);
|
|
||||||
void FillHeaderAndEncrypt (uint8_t payloadType, uint8_t * buf, size_t len, const uint8_t * aesKey, const uint8_t * iv, const uint8_t * macKey);
|
void FillHeaderAndEncrypt (uint8_t payloadType, uint8_t * buf, size_t len, const uint8_t * aesKey, const uint8_t * iv, const uint8_t * macKey);
|
||||||
void Decrypt (uint8_t * buf, size_t len, const uint8_t * aesKey);
|
void Decrypt (uint8_t * buf, size_t len, const uint8_t * aesKey);
|
||||||
bool Validate (uint8_t * buf, size_t len, const uint8_t * macKey);
|
bool Validate (uint8_t * buf, size_t len, const uint8_t * macKey);
|
||||||
const uint8_t * GetIntroKey () const;
|
const uint8_t * GetIntroKey () const;
|
||||||
|
|
||||||
|
void ScheduleTermination ();
|
||||||
|
void HandleTerminationTimer (const boost::system::error_code& ecode);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
SSUServer& m_Server;
|
SSUServer& m_Server;
|
||||||
@ -115,7 +127,9 @@ namespace ssu
|
|||||||
const i2p::data::RouterInfo * m_RemoteRouter;
|
const i2p::data::RouterInfo * m_RemoteRouter;
|
||||||
boost::asio::deadline_timer m_Timer;
|
boost::asio::deadline_timer m_Timer;
|
||||||
i2p::data::DHKeysPair * m_DHKeysPair; // X - for client and Y - for server
|
i2p::data::DHKeysPair * m_DHKeysPair; // X - for client and Y - for server
|
||||||
|
bool m_PeerTest;
|
||||||
SessionState m_State;
|
SessionState m_State;
|
||||||
|
uint32_t m_RelayTag;
|
||||||
CryptoPP::CBC_Mode<CryptoPP::AES>::Encryption m_Encryption;
|
CryptoPP::CBC_Mode<CryptoPP::AES>::Encryption m_Encryption;
|
||||||
CryptoPP::CBC_Mode<CryptoPP::AES>::Decryption m_Decryption;
|
CryptoPP::CBC_Mode<CryptoPP::AES>::Decryption m_Decryption;
|
||||||
uint8_t m_SessionKey[32], m_MacKey[32];
|
uint8_t m_SessionKey[32], m_MacKey[32];
|
||||||
@ -131,7 +145,7 @@ namespace ssu
|
|||||||
~SSUServer ();
|
~SSUServer ();
|
||||||
void Start ();
|
void Start ();
|
||||||
void Stop ();
|
void Stop ();
|
||||||
SSUSession * GetSession (const i2p::data::RouterInfo * router);
|
SSUSession * GetSession (const i2p::data::RouterInfo * router, bool peerTest = false);
|
||||||
SSUSession * FindSession (const i2p::data::RouterInfo * router);
|
SSUSession * FindSession (const i2p::data::RouterInfo * router);
|
||||||
void DeleteSession (SSUSession * session);
|
void DeleteSession (SSUSession * session);
|
||||||
void DeleteAllSessions ();
|
void DeleteAllSessions ();
|
||||||
|
@ -345,7 +345,7 @@ namespace stream
|
|||||||
StreamingDestination::StreamingDestination (): m_LeaseSet (nullptr)
|
StreamingDestination::StreamingDestination (): m_LeaseSet (nullptr)
|
||||||
{
|
{
|
||||||
m_Keys = i2p::data::CreateRandomKeys ();
|
m_Keys = i2p::data::CreateRandomKeys ();
|
||||||
m_IdentHash = i2p::data::CalculateIdentHash (m_Keys.pub);
|
m_IdentHash = m_Keys.pub.Hash ();
|
||||||
m_SigningPrivateKey.Initialize (i2p::crypto::dsap, i2p::crypto::dsaq, i2p::crypto::dsag,
|
m_SigningPrivateKey.Initialize (i2p::crypto::dsap, i2p::crypto::dsaq, i2p::crypto::dsag,
|
||||||
CryptoPP::Integer (m_Keys.signingPrivateKey, 20));
|
CryptoPP::Integer (m_Keys.signingPrivateKey, 20));
|
||||||
CryptoPP::DH dh (i2p::crypto::elgp, i2p::crypto::elgg);
|
CryptoPP::DH dh (i2p::crypto::elgp, i2p::crypto::elgg);
|
||||||
|
@ -92,7 +92,6 @@ namespace i2p
|
|||||||
m_DHKeysPairSupplier.Start ();
|
m_DHKeysPairSupplier.Start ();
|
||||||
m_IsRunning = true;
|
m_IsRunning = true;
|
||||||
m_Thread = new std::thread (std::bind (&Transports::Run, this));
|
m_Thread = new std::thread (std::bind (&Transports::Run, this));
|
||||||
m_Timer = new boost::asio::deadline_timer (m_Service);
|
|
||||||
// create acceptors
|
// create acceptors
|
||||||
auto addresses = context.GetRouterInfo ().GetAddresses ();
|
auto addresses = context.GetRouterInfo ().GetAddresses ();
|
||||||
for (auto& address : addresses)
|
for (auto& address : addresses)
|
||||||
@ -124,23 +123,17 @@ namespace i2p
|
|||||||
|
|
||||||
void Transports::Stop ()
|
void Transports::Stop ()
|
||||||
{
|
{
|
||||||
for (auto session: m_NTCPSessions)
|
|
||||||
delete session.second;
|
|
||||||
m_NTCPSessions.clear ();
|
|
||||||
delete m_NTCPAcceptor;
|
|
||||||
|
|
||||||
if (m_Timer)
|
|
||||||
{
|
|
||||||
m_Timer->cancel ();
|
|
||||||
delete m_Timer;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_SSUServer)
|
if (m_SSUServer)
|
||||||
{
|
{
|
||||||
m_SSUServer->Stop ();
|
m_SSUServer->Stop ();
|
||||||
delete m_SSUServer;
|
delete m_SSUServer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (auto session: m_NTCPSessions)
|
||||||
|
delete session.second;
|
||||||
|
m_NTCPSessions.clear ();
|
||||||
|
delete m_NTCPAcceptor;
|
||||||
|
|
||||||
m_DHKeysPairSupplier.Stop ();
|
m_DHKeysPairSupplier.Stop ();
|
||||||
m_IsRunning = false;
|
m_IsRunning = false;
|
||||||
m_Service.stop ();
|
m_Service.stop ();
|
||||||
@ -270,24 +263,10 @@ namespace i2p
|
|||||||
{
|
{
|
||||||
auto router = i2p::data::netdb.GetRandomRouter ();
|
auto router = i2p::data::netdb.GetRandomRouter ();
|
||||||
if (router && router->IsSSU () && m_SSUServer)
|
if (router && router->IsSSU () && m_SSUServer)
|
||||||
m_SSUServer->GetSession (router);
|
m_SSUServer->GetSession (router, true); // peer test
|
||||||
}
|
|
||||||
if (m_Timer)
|
|
||||||
{
|
|
||||||
m_Timer->expires_from_now (boost::posix_time::seconds(5)); // 5 seconds
|
|
||||||
m_Timer->async_wait (boost::bind (&Transports::HandleTimer, this, boost::asio::placeholders::error));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Transports::HandleTimer (const boost::system::error_code& ecode)
|
|
||||||
{
|
|
||||||
if (ecode != boost::asio::error::operation_aborted)
|
|
||||||
{
|
|
||||||
// end of external IP detection
|
|
||||||
if (m_SSUServer)
|
|
||||||
m_SSUServer->DeleteAllSessions ();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
i2p::data::DHKeysPair * Transports::GetNextDHKeysPair ()
|
i2p::data::DHKeysPair * Transports::GetNextDHKeysPair ()
|
||||||
{
|
{
|
||||||
|
@ -71,7 +71,6 @@ namespace i2p
|
|||||||
void PostMessage (const i2p::data::IdentHash& ident, i2p::I2NPMessage * msg);
|
void PostMessage (const i2p::data::IdentHash& ident, i2p::I2NPMessage * msg);
|
||||||
|
|
||||||
void DetectExternalIP ();
|
void DetectExternalIP ();
|
||||||
void HandleTimer (const boost::system::error_code& ecode);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
@ -83,7 +82,6 @@ namespace i2p
|
|||||||
|
|
||||||
std::map<i2p::data::IdentHash, i2p::ntcp::NTCPSession *> m_NTCPSessions;
|
std::map<i2p::data::IdentHash, i2p::ntcp::NTCPSession *> m_NTCPSessions;
|
||||||
i2p::ssu::SSUServer * m_SSUServer;
|
i2p::ssu::SSUServer * m_SSUServer;
|
||||||
boost::asio::deadline_timer * m_Timer;
|
|
||||||
|
|
||||||
DHKeysPairSupplier m_DHKeysPairSupplier;
|
DHKeysPairSupplier m_DHKeysPairSupplier;
|
||||||
|
|
||||||
|
@ -169,14 +169,14 @@ namespace tunnel
|
|||||||
*m_OutboundTunnels.begin () : tunnels.GetNextOutboundTunnel ();
|
*m_OutboundTunnels.begin () : tunnels.GetNextOutboundTunnel ();
|
||||||
LogPrint ("Creating destination inbound tunnel...");
|
LogPrint ("Creating destination inbound tunnel...");
|
||||||
auto firstHop = i2p::data::netdb.GetRandomRouter (outboundTunnel ? outboundTunnel->GetEndpointRouter () : nullptr);
|
auto firstHop = i2p::data::netdb.GetRandomRouter (outboundTunnel ? outboundTunnel->GetEndpointRouter () : nullptr);
|
||||||
auto secondHop = i2p::data::netdb.GetRandomRouter (firstHop);
|
auto secondHop = outboundTunnel ? outboundTunnel->GetTunnelConfig ()->GetFirstHop ()->router : nullptr;
|
||||||
|
if (!secondHop || secondHop->GetIdentHash () == i2p::context.GetIdentHash ())
|
||||||
|
secondHop = i2p::data::netdb.GetRandomRouter (firstHop);
|
||||||
auto * tunnel = tunnels.CreateTunnel<InboundTunnel> (
|
auto * tunnel = tunnels.CreateTunnel<InboundTunnel> (
|
||||||
new TunnelConfig (std::vector<const i2p::data::RouterInfo *>
|
new TunnelConfig (std::vector<const i2p::data::RouterInfo *>
|
||||||
{
|
{
|
||||||
firstHop,
|
firstHop,
|
||||||
secondHop
|
secondHop
|
||||||
// TODO: switch to 3-hops later
|
|
||||||
/*i2p::data::netdb.GetRandomRouter (secondHop) */
|
|
||||||
}),
|
}),
|
||||||
outboundTunnel);
|
outboundTunnel);
|
||||||
tunnel->SetTunnelPool (this);
|
tunnel->SetTunnelPool (this);
|
||||||
|
5
util.cpp
5
util.cpp
@ -249,6 +249,11 @@ namespace http
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string url::portstr_ = "80";
|
||||||
|
unsigned int url::port_ = 80;
|
||||||
|
std::string url::user_ = "";
|
||||||
|
std::string url::pass_ = "";
|
||||||
|
|
||||||
url::url(const std::string& url_s)
|
url::url(const std::string& url_s)
|
||||||
{
|
{
|
||||||
parse(url_s);
|
parse(url_s);
|
||||||
|
8
util.h
8
util.h
@ -41,10 +41,10 @@ namespace util
|
|||||||
void parse(const std::string& url_s);
|
void parse(const std::string& url_s);
|
||||||
public:
|
public:
|
||||||
std::string protocol_, host_, path_, query_;
|
std::string protocol_, host_, path_, query_;
|
||||||
std::string portstr_ = "80";
|
static std::string portstr_;
|
||||||
unsigned int port_ = 80;
|
static unsigned int port_;
|
||||||
std::string user_ = "";
|
static std::string user_;
|
||||||
std::string pass_ = "";
|
static std::string pass_;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user