mirror of
https://github.com/PurpleI2P/i2pd.git
synced 2025-01-22 13:27:17 +01:00
Merge branch 'master' of github-meeh420:PrivacySolutions/i2pd
Note; we use _MSC_VER instead of _WIN32 for MSVC spesific code. * 'master' of github-meeh420:PrivacySolutions/i2pd: (35 commits) handle incoming datagramms send datagram through destination's thread incoming ipv6 connections support ipv6 for outgoing NTCP connections some cleanup Update Daemon.cpp Add Upstart job to debian packaging Implement reload in init script Rename init.d to i2pd.init Decouple logging and daemonization verify signature through remore identity moved remote RI and identity to TransportSession set unreachable trough NetDb moved AddressBook to ClientContext initialize router identity don't specify RI for inbound NTCP connections use remote router indentity take identity of local RI from private keys send datagram from SAM fixed windows build ... Conflicts: SAM.cpp
This commit is contained in:
commit
af0bdc2a5e
|
@ -11,14 +11,14 @@
|
|||
|
||||
namespace i2p
|
||||
{
|
||||
namespace data
|
||||
namespace client
|
||||
{
|
||||
|
||||
AddressBook::AddressBook (): m_IsLoaded (false), m_IsDowloading (false)
|
||||
{
|
||||
}
|
||||
|
||||
bool AddressBook::GetIdentHash (const std::string& address, IdentHash& ident)
|
||||
bool AddressBook::GetIdentHash (const std::string& address, i2p::data::IdentHash& ident)
|
||||
{
|
||||
auto pos = address.find(".b32.i2p");
|
||||
if (pos != std::string::npos)
|
||||
|
@ -42,7 +42,7 @@ namespace data
|
|||
return false;
|
||||
}
|
||||
|
||||
const IdentHash * AddressBook::FindAddress (const std::string& address)
|
||||
const i2p::data::IdentHash * AddressBook::FindAddress (const std::string& address)
|
||||
{
|
||||
if (!m_IsLoaded)
|
||||
LoadHosts ();
|
||||
|
@ -57,7 +57,7 @@ namespace data
|
|||
|
||||
void AddressBook::InsertAddress (const std::string& address, const std::string& base64)
|
||||
{
|
||||
IdentityEx ident;
|
||||
i2p::data::IdentityEx ident;
|
||||
ident.FromBase64 (base64);
|
||||
m_Addresses[address] = ident.GetIdentHash ();
|
||||
LogPrint (address,"->",ident.GetIdentHash ().ToBase32 (), ".b32.i2p added");
|
||||
|
@ -118,7 +118,7 @@ namespace data
|
|||
std::string name = s.substr(0, pos++);
|
||||
std::string addr = s.substr(pos);
|
||||
|
||||
IdentityEx ident;
|
||||
i2p::data::IdentityEx ident;
|
||||
ident.FromBase64(addr);
|
||||
m_Addresses[name] = ident.GetIdentHash ();
|
||||
numAddresses++;
|
||||
|
|
|
@ -11,15 +11,15 @@
|
|||
|
||||
namespace i2p
|
||||
{
|
||||
namespace data
|
||||
namespace client
|
||||
{
|
||||
class AddressBook
|
||||
{
|
||||
public:
|
||||
|
||||
AddressBook ();
|
||||
bool GetIdentHash (const std::string& address, IdentHash& ident);
|
||||
const IdentHash * FindAddress (const std::string& address);
|
||||
bool GetIdentHash (const std::string& address, i2p::data::IdentHash& ident);
|
||||
const i2p::data::IdentHash * FindAddress (const std::string& address);
|
||||
void InsertAddress (const std::string& address, const std::string& base64); // for jump service
|
||||
|
||||
private:
|
||||
|
@ -27,7 +27,7 @@ namespace data
|
|||
void LoadHosts ();
|
||||
void LoadHostsFromI2P ();
|
||||
|
||||
std::map<std::string, IdentHash> m_Addresses;
|
||||
std::map<std::string, i2p::data::IdentHash> m_Addresses;
|
||||
bool m_IsLoaded, m_IsDowloading;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@ namespace client
|
|||
{
|
||||
if (!m_SharedLocalDestination)
|
||||
{
|
||||
m_SharedLocalDestination = new i2p::stream::StreamingDestination (false, i2p::data::SIGNING_KEY_TYPE_DSA_SHA1); // non-public, DSA
|
||||
m_SharedLocalDestination = new ClientDestination (false, i2p::data::SIGNING_KEY_TYPE_DSA_SHA1); // non-public, DSA
|
||||
m_Destinations[m_SharedLocalDestination->GetIdentity ().GetIdentHash ()] = m_SharedLocalDestination;
|
||||
m_SharedLocalDestination->Start ();
|
||||
}
|
||||
|
@ -41,7 +41,7 @@ namespace client
|
|||
std::string ircDestination = i2p::util::config::GetArg("-ircdest", "");
|
||||
if (ircDestination.length () > 0) // ircdest is presented
|
||||
{
|
||||
i2p::stream::StreamingDestination * localDestination = nullptr;
|
||||
ClientDestination * localDestination = nullptr;
|
||||
std::string ircKeys = i2p::util::config::GetArg("-irckeys", "");
|
||||
if (ircKeys.length () > 0)
|
||||
localDestination = i2p::client::context.LoadLocalDestination (ircKeys, false);
|
||||
|
@ -125,7 +125,7 @@ namespace client
|
|||
#else
|
||||
it->path();
|
||||
#endif
|
||||
auto localDestination = new i2p::stream::StreamingDestination (fullPath, true);
|
||||
auto localDestination = new ClientDestination (fullPath, true);
|
||||
m_Destinations[localDestination->GetIdentHash ()] = localDestination;
|
||||
numDestinations++;
|
||||
}
|
||||
|
@ -134,25 +134,25 @@ namespace client
|
|||
LogPrint (numDestinations, " local destinations loaded");
|
||||
}
|
||||
|
||||
i2p::stream::StreamingDestination * ClientContext::LoadLocalDestination (const std::string& filename, bool isPublic)
|
||||
ClientDestination * ClientContext::LoadLocalDestination (const std::string& filename, bool isPublic)
|
||||
{
|
||||
auto localDestination = new i2p::stream::StreamingDestination (i2p::util::filesystem::GetFullPath (filename), isPublic);
|
||||
auto localDestination = new ClientDestination (i2p::util::filesystem::GetFullPath (filename), isPublic);
|
||||
std::unique_lock<std::mutex> l(m_DestinationsMutex);
|
||||
m_Destinations[localDestination->GetIdentHash ()] = localDestination;
|
||||
localDestination->Start ();
|
||||
return localDestination;
|
||||
}
|
||||
|
||||
i2p::stream::StreamingDestination * ClientContext::CreateNewLocalDestination (bool isPublic, i2p::data::SigningKeyType sigType)
|
||||
ClientDestination * ClientContext::CreateNewLocalDestination (bool isPublic, i2p::data::SigningKeyType sigType)
|
||||
{
|
||||
auto localDestination = new i2p::stream::StreamingDestination (isPublic, sigType);
|
||||
auto localDestination = new ClientDestination (isPublic, sigType);
|
||||
std::unique_lock<std::mutex> l(m_DestinationsMutex);
|
||||
m_Destinations[localDestination->GetIdentHash ()] = localDestination;
|
||||
localDestination->Start ();
|
||||
return localDestination;
|
||||
}
|
||||
|
||||
void ClientContext::DeleteLocalDestination (i2p::stream::StreamingDestination * destination)
|
||||
void ClientContext::DeleteLocalDestination (ClientDestination * destination)
|
||||
{
|
||||
if (!destination) return;
|
||||
auto it = m_Destinations.find (destination->GetIdentHash ());
|
||||
|
@ -168,7 +168,7 @@ namespace client
|
|||
}
|
||||
}
|
||||
|
||||
i2p::stream::StreamingDestination * ClientContext::CreateNewLocalDestination (const i2p::data::PrivateKeys& keys, bool isPublic)
|
||||
ClientDestination * ClientContext::CreateNewLocalDestination (const i2p::data::PrivateKeys& keys, bool isPublic)
|
||||
{
|
||||
auto it = m_Destinations.find (keys.GetPublic ().GetIdentHash ());
|
||||
if (it != m_Destinations.end ())
|
||||
|
@ -181,14 +181,14 @@ namespace client
|
|||
}
|
||||
return nullptr;
|
||||
}
|
||||
auto localDestination = new i2p::stream::StreamingDestination (keys, isPublic);
|
||||
auto localDestination = new ClientDestination (keys, isPublic);
|
||||
std::unique_lock<std::mutex> l(m_DestinationsMutex);
|
||||
m_Destinations[keys.GetPublic ().GetIdentHash ()] = localDestination;
|
||||
localDestination->Start ();
|
||||
return localDestination;
|
||||
}
|
||||
|
||||
i2p::stream::StreamingDestination * ClientContext::FindLocalDestination (const i2p::data::IdentHash& destination) const
|
||||
ClientDestination * ClientContext::FindLocalDestination (const i2p::data::IdentHash& destination) const
|
||||
{
|
||||
auto it = m_Destinations.find (destination);
|
||||
if (it != m_Destinations.end ())
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include "SOCKS.h"
|
||||
#include "I2PTunnel.h"
|
||||
#include "SAM.h"
|
||||
#include "AddressBook.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
|
@ -22,12 +23,14 @@ namespace client
|
|||
void Start ();
|
||||
void Stop ();
|
||||
|
||||
i2p::stream::StreamingDestination * GetSharedLocalDestination () const { return m_SharedLocalDestination; };
|
||||
i2p::stream::StreamingDestination * CreateNewLocalDestination (bool isPublic = true, i2p::data::SigningKeyType sigType = i2p::data::SIGNING_KEY_TYPE_DSA_SHA1); // transient
|
||||
i2p::stream::StreamingDestination * CreateNewLocalDestination (const i2p::data::PrivateKeys& keys, bool isPublic = true);
|
||||
void DeleteLocalDestination (i2p::stream::StreamingDestination * destination);
|
||||
i2p::stream::StreamingDestination * FindLocalDestination (const i2p::data::IdentHash& destination) const;
|
||||
i2p::stream::StreamingDestination * LoadLocalDestination (const std::string& filename, bool isPublic);
|
||||
ClientDestination * GetSharedLocalDestination () const { return m_SharedLocalDestination; };
|
||||
ClientDestination * CreateNewLocalDestination (bool isPublic = true, i2p::data::SigningKeyType sigType = i2p::data::SIGNING_KEY_TYPE_DSA_SHA1); // transient
|
||||
ClientDestination * CreateNewLocalDestination (const i2p::data::PrivateKeys& keys, bool isPublic = true);
|
||||
void DeleteLocalDestination (ClientDestination * destination);
|
||||
ClientDestination * FindLocalDestination (const i2p::data::IdentHash& destination) const;
|
||||
ClientDestination * LoadLocalDestination (const std::string& filename, bool isPublic);
|
||||
|
||||
AddressBook& GetAddressBook () { return m_AddressBook; };
|
||||
|
||||
private:
|
||||
|
||||
|
@ -36,8 +39,10 @@ namespace client
|
|||
private:
|
||||
|
||||
std::mutex m_DestinationsMutex;
|
||||
std::map<i2p::data::IdentHash, i2p::stream::StreamingDestination *> m_Destinations;
|
||||
i2p::stream::StreamingDestination * m_SharedLocalDestination;
|
||||
std::map<i2p::data::IdentHash, ClientDestination *> m_Destinations;
|
||||
ClientDestination * m_SharedLocalDestination;
|
||||
|
||||
AddressBook m_AddressBook;
|
||||
|
||||
i2p::proxy::HTTPProxy * m_HttpProxy;
|
||||
i2p::proxy::SOCKSProxy * m_SocksProxy;
|
||||
|
|
|
@ -72,6 +72,8 @@ namespace i2p
|
|||
if (i2p::util::config::GetArg("-unreachable", 0))
|
||||
i2p::context.SetUnreachable ();
|
||||
|
||||
i2p::context.SetSupportsV6 (i2p::util::config::GetArg("-v6", 0));
|
||||
|
||||
LogPrint("CMD parameters:");
|
||||
for (int i = 0; i < argc; ++i)
|
||||
LogPrint(i, " ", argv[i]);
|
||||
|
@ -103,7 +105,7 @@ namespace i2p
|
|||
LogPrint("HTTP Server started");
|
||||
i2p::data::netdb.Start();
|
||||
LogPrint("NetDB started");
|
||||
i2p::transports.Start();
|
||||
i2p::transport::transports.Start();
|
||||
LogPrint("Transports started");
|
||||
i2p::tunnel::tunnels.Start();
|
||||
LogPrint("Tunnels started");
|
||||
|
@ -120,7 +122,7 @@ namespace i2p
|
|||
LogPrint("Client stoped");
|
||||
i2p::tunnel::tunnels.Stop();
|
||||
LogPrint("Tunnels stoped");
|
||||
i2p::transports.Stop();
|
||||
i2p::transport::transports.Stop();
|
||||
LogPrint("Transports stoped");
|
||||
i2p::data::netdb.Stop();
|
||||
LogPrint("NetDB stoped");
|
||||
|
|
132
Datagram.cpp
Normal file
132
Datagram.cpp
Normal file
|
@ -0,0 +1,132 @@
|
|||
#include <string.h>
|
||||
#include <vector>
|
||||
#include <cryptopp/sha.h>
|
||||
#include <cryptopp/gzip.h>
|
||||
#include "Log.h"
|
||||
#include "TunnelBase.h"
|
||||
#include "RouterContext.h"
|
||||
#include "Destination.h"
|
||||
#include "Datagram.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace datagram
|
||||
{
|
||||
DatagramDestination::DatagramDestination (i2p::client::ClientDestination& owner):
|
||||
m_Owner (owner)
|
||||
{
|
||||
}
|
||||
|
||||
void DatagramDestination::SendDatagramTo (const uint8_t * payload, size_t len, const i2p::data::LeaseSet& remote)
|
||||
{
|
||||
uint8_t buf[MAX_DATAGRAM_SIZE];
|
||||
auto identityLen = m_Owner.GetIdentity ().ToBuffer (buf, MAX_DATAGRAM_SIZE);
|
||||
uint8_t * signature = buf + identityLen;
|
||||
auto signatureLen = m_Owner.GetIdentity ().GetSignatureLen ();
|
||||
uint8_t * buf1 = signature + signatureLen;
|
||||
size_t headerLen = identityLen + signatureLen;
|
||||
|
||||
memcpy (buf1, payload, len);
|
||||
if (m_Owner.GetIdentity ().GetSigningKeyType () == i2p::data::SIGNING_KEY_TYPE_DSA_SHA1)
|
||||
{
|
||||
uint8_t hash[32];
|
||||
CryptoPP::SHA256().CalculateDigest (hash, buf1, len);
|
||||
m_Owner.Sign (hash, 32, signature);
|
||||
}
|
||||
else
|
||||
m_Owner.Sign (buf1, len, signature);
|
||||
|
||||
auto service = m_Owner.GetService ();
|
||||
if (service)
|
||||
service->post (boost::bind (&DatagramDestination::SendMsg, this,
|
||||
CreateDataMessage (buf, len + headerLen), remote));
|
||||
else
|
||||
LogPrint ("Failed to send datagram. Destination is not running");
|
||||
}
|
||||
|
||||
void DatagramDestination::SendMsg (I2NPMessage * msg, const i2p::data::LeaseSet& remote)
|
||||
{
|
||||
auto leases = remote.GetNonExpiredLeases ();
|
||||
if (!leases.empty ())
|
||||
{
|
||||
std::vector<i2p::tunnel::TunnelMessageBlock> msgs;
|
||||
uint32_t i = i2p::context.GetRandomNumberGenerator ().GenerateWord32 (0, leases.size () - 1);
|
||||
auto garlic = m_Owner.WrapMessage (remote, msg, true);
|
||||
msgs.push_back (i2p::tunnel::TunnelMessageBlock
|
||||
{
|
||||
i2p::tunnel::eDeliveryTypeTunnel,
|
||||
leases[i].tunnelGateway, leases[i].tunnelID,
|
||||
garlic
|
||||
});
|
||||
m_Owner.SendTunnelDataMsgs (msgs);
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrint ("Failed to send datagram. All leases expired");
|
||||
DeleteI2NPMessage (msg);
|
||||
}
|
||||
}
|
||||
|
||||
void DatagramDestination::HandleDatagram (const uint8_t * buf, size_t len)
|
||||
{
|
||||
i2p::data::IdentityEx identity;
|
||||
size_t identityLen = identity.FromBuffer (buf, len);
|
||||
const uint8_t * signature = buf + identityLen;
|
||||
size_t headerLen = identityLen + identity.GetSignatureLen ();
|
||||
|
||||
bool verified = false;
|
||||
if (identity.GetSigningKeyType () == i2p::data::SIGNING_KEY_TYPE_DSA_SHA1)
|
||||
{
|
||||
uint8_t hash[32];
|
||||
CryptoPP::SHA256().CalculateDigest (hash, buf + headerLen, len - headerLen);
|
||||
verified = identity.Verify (hash, 32, signature);
|
||||
}
|
||||
else
|
||||
verified = identity.Verify (buf + headerLen, len - headerLen, signature);
|
||||
|
||||
if (verified)
|
||||
{
|
||||
// TODO: invoke datagram handler
|
||||
}
|
||||
else
|
||||
LogPrint ("Datagram signature verification failed");
|
||||
}
|
||||
|
||||
void DatagramDestination::HandleDataMessagePayload (const uint8_t * buf, size_t len)
|
||||
{
|
||||
// unzip it
|
||||
CryptoPP::Gunzip decompressor;
|
||||
decompressor.Put (buf, len);
|
||||
decompressor.MessageEnd();
|
||||
uint8_t uncompressed[MAX_DATAGRAM_SIZE];
|
||||
auto uncompressedLen = decompressor.MaxRetrievable ();
|
||||
if (uncompressedLen <= MAX_DATAGRAM_SIZE)
|
||||
{
|
||||
decompressor.Get (uncompressed, uncompressedLen);
|
||||
HandleDatagram (uncompressed, uncompressedLen);
|
||||
}
|
||||
else
|
||||
LogPrint ("Received datagram size ", uncompressedLen, " exceeds max size");
|
||||
|
||||
}
|
||||
|
||||
I2NPMessage * DatagramDestination::CreateDataMessage (const uint8_t * payload, size_t len)
|
||||
{
|
||||
I2NPMessage * msg = NewI2NPMessage ();
|
||||
CryptoPP::Gzip compressor; // default level
|
||||
compressor.Put (payload, len);
|
||||
compressor.MessageEnd();
|
||||
int size = compressor.MaxRetrievable ();
|
||||
uint8_t * buf = msg->GetPayload ();
|
||||
*(uint32_t *)buf = htobe32 (size); // length
|
||||
buf += 4;
|
||||
compressor.Get (buf, size);
|
||||
memset (buf + 4, 0, 4); // source and destination are zeroes
|
||||
buf[9] = i2p::client::PROTOCOL_TYPE_DATAGRAM; // datagram protocol
|
||||
msg->len += size + 4;
|
||||
FillI2NPMessageHeader (msg, eI2NPData);
|
||||
return msg;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
41
Datagram.h
Normal file
41
Datagram.h
Normal file
|
@ -0,0 +1,41 @@
|
|||
#ifndef DATAGRAM_H__
|
||||
#define DATAGRAM_H__
|
||||
|
||||
#include <inttypes.h>
|
||||
#include "LeaseSet.h"
|
||||
#include "I2NPProtocol.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace client
|
||||
{
|
||||
class ClientDestination;
|
||||
}
|
||||
namespace datagram
|
||||
{
|
||||
const size_t MAX_DATAGRAM_SIZE = 32768;
|
||||
class DatagramDestination
|
||||
{
|
||||
public:
|
||||
|
||||
DatagramDestination (i2p::client::ClientDestination& owner);
|
||||
~DatagramDestination () {};
|
||||
|
||||
void SendDatagramTo (const uint8_t * payload, size_t len, const i2p::data::LeaseSet& remote);
|
||||
void HandleDataMessagePayload (const uint8_t * buf, size_t len);
|
||||
|
||||
private:
|
||||
|
||||
I2NPMessage * CreateDataMessage (const uint8_t * payload, size_t len);
|
||||
void SendMsg (I2NPMessage * msg, const i2p::data::LeaseSet& remote);
|
||||
void HandleDatagram (const uint8_t * buf, size_t len);
|
||||
|
||||
private:
|
||||
|
||||
i2p::client::ClientDestination& m_Owner;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
157
Destination.cpp
157
Destination.cpp
|
@ -1,7 +1,6 @@
|
|||
#include <fstream>
|
||||
#include <algorithm>
|
||||
#include <cryptopp/dh.h>
|
||||
#include <cryptopp/gzip.h>
|
||||
#include "Log.h"
|
||||
#include "util.h"
|
||||
#include "NetDb.h"
|
||||
|
@ -13,7 +12,8 @@ namespace client
|
|||
{
|
||||
ClientDestination::ClientDestination (bool isPublic, i2p::data::SigningKeyType sigType):
|
||||
m_IsRunning (false), m_Thread (nullptr), m_Service (nullptr), m_Work (nullptr),
|
||||
m_CurrentOutboundTunnel (nullptr), m_LeaseSet (nullptr), m_IsPublic (isPublic)
|
||||
m_CurrentOutboundTunnel (nullptr), m_LeaseSet (nullptr), m_IsPublic (isPublic),
|
||||
m_DatagramDestination (nullptr)
|
||||
{
|
||||
m_Keys = i2p::data::PrivateKeys::CreateRandomKeys (sigType);
|
||||
CryptoPP::DH dh (i2p::crypto::elgp, i2p::crypto::elgg);
|
||||
|
@ -21,11 +21,13 @@ namespace client
|
|||
m_Pool = i2p::tunnel::tunnels.CreateTunnelPool (*this, 3); // 3-hops tunnel
|
||||
if (m_IsPublic)
|
||||
LogPrint ("Local address ", GetIdentHash ().ToBase32 (), ".b32.i2p created");
|
||||
m_StreamingDestination = new i2p::stream::StreamingDestination (*this); // TODO:
|
||||
}
|
||||
|
||||
ClientDestination::ClientDestination (const std::string& fullPath, bool isPublic):
|
||||
m_IsRunning (false), m_Thread (nullptr), m_Service (nullptr), m_Work (nullptr),
|
||||
m_CurrentOutboundTunnel (nullptr), m_LeaseSet (nullptr), m_IsPublic (isPublic)
|
||||
m_CurrentOutboundTunnel (nullptr), m_LeaseSet (nullptr), m_IsPublic (isPublic),
|
||||
m_DatagramDestination (nullptr)
|
||||
{
|
||||
std::ifstream s(fullPath.c_str (), std::ifstream::binary);
|
||||
if (s.is_open ())
|
||||
|
@ -56,17 +58,20 @@ namespace client
|
|||
CryptoPP::DH dh (i2p::crypto::elgp, i2p::crypto::elgg);
|
||||
dh.GenerateKeyPair(i2p::context.GetRandomNumberGenerator (), m_EncryptionPrivateKey, m_EncryptionPublicKey);
|
||||
m_Pool = i2p::tunnel::tunnels.CreateTunnelPool (*this, 3); // 3-hops tunnel
|
||||
m_StreamingDestination = new i2p::stream::StreamingDestination (*this); // TODO:
|
||||
}
|
||||
|
||||
ClientDestination::ClientDestination (const i2p::data::PrivateKeys& keys, bool isPublic):
|
||||
m_IsRunning (false), m_Thread (nullptr), m_Service (nullptr), m_Work (nullptr),
|
||||
m_Keys (keys), m_CurrentOutboundTunnel (nullptr), m_LeaseSet (nullptr), m_IsPublic (isPublic)
|
||||
m_Keys (keys), m_CurrentOutboundTunnel (nullptr), m_LeaseSet (nullptr), m_IsPublic (isPublic),
|
||||
m_DatagramDestination (nullptr)
|
||||
{
|
||||
CryptoPP::DH dh (i2p::crypto::elgp, i2p::crypto::elgg);
|
||||
dh.GenerateKeyPair(i2p::context.GetRandomNumberGenerator (), m_EncryptionPrivateKey, m_EncryptionPublicKey);
|
||||
m_Pool = i2p::tunnel::tunnels.CreateTunnelPool (*this, 3); // 3-hops tunnel
|
||||
if (m_IsPublic)
|
||||
LogPrint ("Local address ", GetIdentHash ().ToBase32 (), ".b32.i2p created");
|
||||
m_StreamingDestination = new i2p::stream::StreamingDestination (*this); // TODO:
|
||||
}
|
||||
|
||||
ClientDestination::~ClientDestination ()
|
||||
|
@ -79,6 +84,8 @@ namespace client
|
|||
delete m_LeaseSet;
|
||||
delete m_Work;
|
||||
delete m_Service;
|
||||
delete m_StreamingDestination;
|
||||
delete m_DatagramDestination;
|
||||
}
|
||||
|
||||
void ClientDestination::Run ()
|
||||
|
@ -94,10 +101,12 @@ namespace client
|
|||
m_Pool->SetActive (true);
|
||||
m_IsRunning = true;
|
||||
m_Thread = new std::thread (std::bind (&ClientDestination::Run, this));
|
||||
m_StreamingDestination->Start ();
|
||||
}
|
||||
|
||||
void ClientDestination::Stop ()
|
||||
{
|
||||
m_StreamingDestination->Stop ();
|
||||
if (m_Pool)
|
||||
i2p::tunnel::tunnels.StopTunnelPool (m_Pool);
|
||||
m_IsRunning = false;
|
||||
|
@ -238,135 +247,57 @@ namespace client
|
|||
uint32_t length = be32toh (*(uint32_t *)buf);
|
||||
buf += 4;
|
||||
// we assume I2CP payload
|
||||
if (buf[9] == 6) // streaming protocol
|
||||
switch (buf[9])
|
||||
{
|
||||
// unzip it
|
||||
CryptoPP::Gunzip decompressor;
|
||||
decompressor.Put (buf, length);
|
||||
decompressor.MessageEnd();
|
||||
i2p::stream::Packet * uncompressed = new i2p::stream::Packet;
|
||||
uncompressed->offset = 0;
|
||||
uncompressed->len = decompressor.MaxRetrievable ();
|
||||
if (uncompressed->len <= i2p::stream::MAX_PACKET_SIZE)
|
||||
{
|
||||
decompressor.Get (uncompressed->buf, uncompressed->len);
|
||||
HandleNextPacket (uncompressed);
|
||||
}
|
||||
case PROTOCOL_TYPE_STREAMING:
|
||||
// streaming protocol
|
||||
if (m_StreamingDestination)
|
||||
m_StreamingDestination->HandleDataMessagePayload (buf, length);
|
||||
else
|
||||
{
|
||||
LogPrint ("Received packet size ", uncompressed->len, " exceeds max packet size. Skipped");
|
||||
decompressor.Skip ();
|
||||
delete uncompressed;
|
||||
}
|
||||
}
|
||||
LogPrint ("Missing streaming destination");
|
||||
break;
|
||||
case PROTOCOL_TYPE_DATAGRAM:
|
||||
// datagram protocol
|
||||
if (m_DatagramDestination)
|
||||
m_DatagramDestination->HandleDataMessagePayload (buf, length);
|
||||
else
|
||||
LogPrint ("Missing streaming destination");
|
||||
break;
|
||||
default:
|
||||
LogPrint ("Data: unexpected protocol ", buf[9]);
|
||||
}
|
||||
|
||||
I2NPMessage * ClientDestination::CreateDataMessage (const uint8_t * payload, size_t len)
|
||||
{
|
||||
I2NPMessage * msg = NewI2NPShortMessage ();
|
||||
CryptoPP::Gzip compressor;
|
||||
if (len <= i2p::stream::COMPRESSION_THRESHOLD_SIZE)
|
||||
compressor.SetDeflateLevel (CryptoPP::Gzip::MIN_DEFLATE_LEVEL);
|
||||
else
|
||||
compressor.SetDeflateLevel (CryptoPP::Gzip::DEFAULT_DEFLATE_LEVEL);
|
||||
compressor.Put (payload, len);
|
||||
compressor.MessageEnd();
|
||||
int size = compressor.MaxRetrievable ();
|
||||
uint8_t * buf = msg->GetPayload ();
|
||||
*(uint32_t *)buf = htobe32 (size); // length
|
||||
buf += 4;
|
||||
compressor.Get (buf, size);
|
||||
memset (buf + 4, 0, 4); // source and destination ports. TODO: fill with proper values later
|
||||
buf[9] = 6; // streaming protocol
|
||||
msg->len += size + 4;
|
||||
FillI2NPMessageHeader (msg, eI2NPData);
|
||||
|
||||
return msg;
|
||||
}
|
||||
}
|
||||
|
||||
namespace stream
|
||||
i2p::stream::Stream * ClientDestination::CreateStream (const i2p::data::LeaseSet& remote, int port)
|
||||
{
|
||||
|
||||
void StreamingDestination::Start ()
|
||||
{
|
||||
ClientDestination::Start ();
|
||||
if (m_StreamingDestination)
|
||||
return m_StreamingDestination->CreateNewOutgoingStream (remote, port);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void StreamingDestination::Stop ()
|
||||
void ClientDestination::AcceptStreams (const std::function<void (i2p::stream::Stream *)>& acceptor)
|
||||
{
|
||||
ResetAcceptor ();
|
||||
{
|
||||
std::unique_lock<std::mutex> l(m_StreamsMutex);
|
||||
for (auto it: m_Streams)
|
||||
delete it.second;
|
||||
m_Streams.clear ();
|
||||
}
|
||||
ClientDestination::Stop ();
|
||||
if (m_StreamingDestination)
|
||||
m_StreamingDestination->SetAcceptor (acceptor);
|
||||
}
|
||||
|
||||
|
||||
void StreamingDestination::HandleNextPacket (Packet * packet)
|
||||
void ClientDestination::StopAcceptingStreams ()
|
||||
{
|
||||
uint32_t sendStreamID = packet->GetSendStreamID ();
|
||||
if (sendStreamID)
|
||||
{
|
||||
auto it = m_Streams.find (sendStreamID);
|
||||
if (it != m_Streams.end ())
|
||||
it->second->HandleNextPacket (packet);
|
||||
else
|
||||
{
|
||||
LogPrint ("Unknown stream ", sendStreamID);
|
||||
delete packet;
|
||||
}
|
||||
}
|
||||
else // new incoming stream
|
||||
{
|
||||
auto incomingStream = CreateNewIncomingStream ();
|
||||
incomingStream->HandleNextPacket (packet);
|
||||
if (m_Acceptor != nullptr)
|
||||
m_Acceptor (incomingStream);
|
||||
else
|
||||
{
|
||||
LogPrint ("Acceptor for incoming stream is not set");
|
||||
DeleteStream (incomingStream);
|
||||
}
|
||||
}
|
||||
if (m_StreamingDestination)
|
||||
m_StreamingDestination->ResetAcceptor ();
|
||||
}
|
||||
|
||||
Stream * StreamingDestination::CreateNewOutgoingStream (const i2p::data::LeaseSet& remote)
|
||||
bool ClientDestination::IsAcceptingStreams () const
|
||||
{
|
||||
Stream * s = new Stream (*GetService (), *this, remote);
|
||||
std::unique_lock<std::mutex> l(m_StreamsMutex);
|
||||
m_Streams[s->GetRecvStreamID ()] = s;
|
||||
return s;
|
||||
if (m_StreamingDestination)
|
||||
return m_StreamingDestination->IsAcceptorSet ();
|
||||
return false;
|
||||
}
|
||||
|
||||
Stream * StreamingDestination::CreateNewIncomingStream ()
|
||||
void ClientDestination::CreateDatagramDestination ()
|
||||
{
|
||||
Stream * s = new Stream (*GetService (), *this);
|
||||
std::unique_lock<std::mutex> l(m_StreamsMutex);
|
||||
m_Streams[s->GetRecvStreamID ()] = s;
|
||||
return s;
|
||||
}
|
||||
|
||||
void StreamingDestination::DeleteStream (Stream * stream)
|
||||
{
|
||||
if (stream)
|
||||
{
|
||||
std::unique_lock<std::mutex> l(m_StreamsMutex);
|
||||
auto it = m_Streams.find (stream->GetRecvStreamID ());
|
||||
if (it != m_Streams.end ())
|
||||
{
|
||||
m_Streams.erase (it);
|
||||
if (GetService ())
|
||||
GetService ()->post ([stream](void) { delete stream; });
|
||||
else
|
||||
delete stream;
|
||||
}
|
||||
}
|
||||
if (!m_DatagramDestination)
|
||||
m_DatagramDestination = new i2p::datagram::DatagramDestination (*this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,11 +9,16 @@
|
|||
#include "LeaseSet.h"
|
||||
#include "Garlic.h"
|
||||
#include "Streaming.h"
|
||||
#include "Datagram.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace client
|
||||
{
|
||||
const uint8_t PROTOCOL_TYPE_STREAMING = 6;
|
||||
const uint8_t PROTOCOL_TYPE_DATAGRAM = 17;
|
||||
const uint8_t PROTOCOL_TYPE_RAW = 18;
|
||||
|
||||
class ClientDestination: public i2p::garlic::GarlicDestination
|
||||
{
|
||||
public:
|
||||
|
@ -34,6 +39,17 @@ namespace client
|
|||
const i2p::data::LeaseSet * FindLeaseSet (const i2p::data::IdentHash& ident);
|
||||
void SendTunnelDataMsgs (const std::vector<i2p::tunnel::TunnelMessageBlock>& msgs);
|
||||
|
||||
// streaming
|
||||
i2p::stream::StreamingDestination * GetStreamingDestination () const { return m_StreamingDestination; };
|
||||
i2p::stream::Stream * CreateStream (const i2p::data::LeaseSet& remote, int port = 0);
|
||||
void AcceptStreams (const std::function<void (i2p::stream::Stream *)>& acceptor);
|
||||
void StopAcceptingStreams ();
|
||||
bool IsAcceptingStreams () const;
|
||||
|
||||
// datagram
|
||||
i2p::datagram::DatagramDestination * GetDatagramDestination () const { return m_DatagramDestination; };
|
||||
void CreateDatagramDestination ();
|
||||
|
||||
// implements LocalDestination
|
||||
const i2p::data::PrivateKeys& GetPrivateKeys () const { return m_Keys; };
|
||||
const uint8_t * GetEncryptionPrivateKey () const { return m_EncryptionPrivateKey; };
|
||||
|
@ -50,11 +66,6 @@ namespace client
|
|||
|
||||
// I2CP
|
||||
void HandleDataMessage (const uint8_t * buf, size_t len);
|
||||
I2NPMessage * CreateDataMessage (const uint8_t * payload, size_t len);
|
||||
|
||||
protected:
|
||||
|
||||
virtual void HandleNextPacket (i2p::stream::Packet * packet) = 0; // TODO
|
||||
|
||||
private:
|
||||
|
||||
|
@ -77,55 +88,15 @@ namespace client
|
|||
i2p::data::LeaseSet * m_LeaseSet;
|
||||
bool m_IsPublic;
|
||||
|
||||
i2p::stream::StreamingDestination * m_StreamingDestination;
|
||||
i2p::datagram::DatagramDestination * m_DatagramDestination;
|
||||
|
||||
public:
|
||||
|
||||
// for HTTP only
|
||||
int GetNumRemoteLeaseSets () const { return m_RemoteLeaseSets.size (); };
|
||||
};
|
||||
}
|
||||
|
||||
namespace stream
|
||||
{
|
||||
class StreamingDestination: public i2p::client::ClientDestination
|
||||
{
|
||||
public:
|
||||
|
||||
StreamingDestination (bool isPublic, i2p::data::SigningKeyType sigType):
|
||||
ClientDestination (isPublic, sigType) {};
|
||||
StreamingDestination (const std::string& fullPath, bool isPublic):
|
||||
ClientDestination (fullPath, isPublic) {};
|
||||
StreamingDestination (const i2p::data::PrivateKeys& keys, bool isPublic):
|
||||
ClientDestination (keys, isPublic) {};
|
||||
~StreamingDestination () {};
|
||||
|
||||
void Start ();
|
||||
void Stop ();
|
||||
|
||||
Stream * CreateNewOutgoingStream (const i2p::data::LeaseSet& remote);
|
||||
void DeleteStream (Stream * stream);
|
||||
void SetAcceptor (const std::function<void (Stream *)>& acceptor) { m_Acceptor = acceptor; };
|
||||
void ResetAcceptor () { m_Acceptor = nullptr; };
|
||||
bool IsAcceptorSet () const { return m_Acceptor != nullptr; };
|
||||
|
||||
// ClientDestination
|
||||
void HandleNextPacket (Packet * packet);
|
||||
|
||||
private:
|
||||
|
||||
Stream * CreateNewIncomingStream ();
|
||||
|
||||
private:
|
||||
|
||||
std::mutex m_StreamsMutex;
|
||||
std::map<uint32_t, Stream *> m_Streams;
|
||||
std::function<void (Stream *)> m_Acceptor;
|
||||
|
||||
public:
|
||||
|
||||
// for HTTP only
|
||||
const decltype(m_Streams)& GetStreams () const { return m_Streams; };
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/regex.hpp>
|
||||
|
||||
#include "NetDb.h"
|
||||
#include "ClientContext.h"
|
||||
#include "HTTPProxy.h"
|
||||
|
||||
namespace i2p
|
||||
|
@ -52,10 +52,11 @@ namespace proxy
|
|||
}
|
||||
path=m[4].str();
|
||||
}
|
||||
LogPrint("server is: ",server, "\n path is: ",path);
|
||||
LogPrint("server is: ",server, " port is: ", port, "\n path is: ",path);
|
||||
r.uri = path;
|
||||
r.method = method;
|
||||
r.host = server;
|
||||
r.port = boost::lexical_cast<int>(port);
|
||||
}
|
||||
|
||||
|
||||
|
@ -73,12 +74,12 @@ namespace proxy
|
|||
{
|
||||
LogPrint ("Jump service for ", r.host, " found. Inserting to address book");
|
||||
auto base64 = r.uri.substr (addressPos + 1);
|
||||
i2p::data::netdb.GetAddressBook ().InsertAddress (r.host, base64);
|
||||
i2p::client::context.GetAddressBook ().InsertAddress (r.host, base64);
|
||||
}
|
||||
}
|
||||
|
||||
LogPrint("Requesting ", r.host, " with path ", r.uri, " and method ", r.method);
|
||||
SendToAddress (r.host, m_Buffer, m_BufferLen);
|
||||
LogPrint("Requesting ", r.host, ":", r.port, " with path ", r.uri, " and method ", r.method);
|
||||
SendToAddress (r.host, r.port, m_Buffer, m_BufferLen);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -517,7 +517,7 @@ namespace util
|
|||
if (m_Stream)
|
||||
{
|
||||
m_Stream->Close ();
|
||||
i2p::client::context.GetSharedLocalDestination ()->DeleteStream (m_Stream);
|
||||
i2p::stream::DeleteStream (m_Stream);
|
||||
m_Stream = nullptr;
|
||||
}
|
||||
m_Socket->close ();
|
||||
|
@ -644,6 +644,9 @@ namespace util
|
|||
switch (address.transportStyle)
|
||||
{
|
||||
case i2p::data::RouterInfo::eTransportNTCP:
|
||||
if (address.host.is_v6 ())
|
||||
s << "NTCP6 ";
|
||||
else
|
||||
s << "NTCP ";
|
||||
break;
|
||||
case i2p::data::RouterInfo::eTransportSSU:
|
||||
|
@ -699,14 +702,14 @@ namespace util
|
|||
void HTTPConnection::ShowTransports (std::stringstream& s)
|
||||
{
|
||||
s << "NTCP<br>";
|
||||
for (auto it: i2p::transports.GetNTCPSessions ())
|
||||
for (auto it: i2p::transport::transports.GetNTCPSessions ())
|
||||
{
|
||||
// RouterInfo of incoming connection doesn't have address
|
||||
bool outgoing = it.second->GetRemoteRouterInfo ().GetNTCPAddress ();
|
||||
if (it.second->IsEstablished ())
|
||||
{
|
||||
// incoming connection doesn't have remote RI
|
||||
bool outgoing = it.second->GetRemoteRouter ();
|
||||
if (outgoing) s << "-->";
|
||||
s << it.second->GetRemoteRouterInfo ().GetIdentHashAbbreviation () << ": "
|
||||
s << it.second->GetRemoteIdentity ().GetIdentHash ().ToBase64 ().substr (0, 4) << ": "
|
||||
<< it.second->GetSocket ().remote_endpoint().address ().to_string ();
|
||||
if (!outgoing) s << "-->";
|
||||
s << " [" << it.second->GetNumSentBytes () << ":" << it.second->GetNumReceivedBytes () << "]";
|
||||
|
@ -714,7 +717,7 @@ namespace util
|
|||
}
|
||||
s << std::endl;
|
||||
}
|
||||
auto ssuServer = i2p::transports.GetSSUServer ();
|
||||
auto ssuServer = i2p::transport::transports.GetSSUServer ();
|
||||
if (ssuServer)
|
||||
{
|
||||
s << "<br>SSU<br>";
|
||||
|
@ -813,7 +816,7 @@ namespace util
|
|||
}
|
||||
}
|
||||
s << "<br><b>Streams:</b><br>";
|
||||
for (auto it: dest->GetStreams ())
|
||||
for (auto it: dest->GetStreamingDestination ()->GetStreams ())
|
||||
{
|
||||
s << it.first << "->" << it.second->GetRemoteIdentity ().GetIdentHash ().ToBase32 () << ".b32.i2p ";
|
||||
s << " [" << it.second->GetNumSentBytes () << ":" << it.second->GetNumReceivedBytes () << "]";
|
||||
|
@ -839,38 +842,49 @@ namespace util
|
|||
{
|
||||
std::string request = "GET " + uri + " HTTP/1.1\r\nHost:" + address + "\r\n";
|
||||
LogPrint("HTTP Client Request: ", request);
|
||||
SendToAddress (address, request.c_str (), request.size ());
|
||||
SendToAddress (address, 80, request.c_str (), request.size ());
|
||||
}
|
||||
|
||||
void HTTPConnection::SendToAddress (const std::string& address, const char * buf, size_t len)
|
||||
void HTTPConnection::SendToAddress (const std::string& address, int port, const char * buf, size_t len)
|
||||
{
|
||||
i2p::data::IdentHash destination;
|
||||
if (!i2p::data::netdb.GetAddressBook ().GetIdentHash (address, destination))
|
||||
if (!i2p::client::context.GetAddressBook ().GetIdentHash (address, destination))
|
||||
{
|
||||
LogPrint ("Unknown address ", address);
|
||||
SendReply ("<html>" + itoopieImage + "<br>Unknown address " + address + "</html>", 404);
|
||||
return;
|
||||
}
|
||||
|
||||
SendToDestination (destination, buf, len);
|
||||
}
|
||||
|
||||
void HTTPConnection::SendToDestination (const i2p::data::IdentHash& destination, const char * buf, size_t len)
|
||||
{
|
||||
auto leaseSet = i2p::client::context.GetSharedLocalDestination ()->FindLeaseSet (destination);
|
||||
if (!leaseSet || !leaseSet->HasNonExpiredLeases ())
|
||||
if (leaseSet && leaseSet->HasNonExpiredLeases ())
|
||||
SendToDestination (leaseSet, port, buf, len);
|
||||
else
|
||||
{
|
||||
i2p::data::netdb.RequestDestination (destination, true, i2p::client::context.GetSharedLocalDestination ()->GetTunnelPool ());
|
||||
std::this_thread::sleep_for (std::chrono::seconds(10)); // wait for 10 seconds
|
||||
leaseSet = i2p::client::context.GetSharedLocalDestination ()->FindLeaseSet (destination);
|
||||
if (!leaseSet || !leaseSet->HasNonExpiredLeases ()) // still no LeaseSet
|
||||
m_Timer.expires_from_now (boost::posix_time::seconds(HTTP_DESTINATION_REQUEST_TIMEOUT));
|
||||
m_Timer.async_wait (boost::bind (&HTTPConnection::HandleDestinationRequestTimeout,
|
||||
this, boost::asio::placeholders::error, destination, port, buf, len));
|
||||
}
|
||||
}
|
||||
|
||||
void HTTPConnection::HandleDestinationRequestTimeout (const boost::system::error_code& ecode,
|
||||
i2p::data::IdentHash destination, int port, const char * buf, size_t len)
|
||||
{
|
||||
if (ecode != boost::asio::error::operation_aborted)
|
||||
{
|
||||
auto leaseSet = i2p::client::context.GetSharedLocalDestination ()->FindLeaseSet (destination);
|
||||
if (leaseSet && leaseSet->HasNonExpiredLeases ())
|
||||
SendToDestination (leaseSet, port, buf, len);
|
||||
else
|
||||
// still no LeaseSet
|
||||
SendReply (leaseSet ? "<html>" + itoopieImage + "<br>Leases expired</html>" : "<html>" + itoopieImage + "LeaseSet not found</html>", 504);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void HTTPConnection::SendToDestination (const i2p::data::LeaseSet * remote, int port, const char * buf, size_t len)
|
||||
{
|
||||
if (!m_Stream)
|
||||
m_Stream = i2p::client::context.GetSharedLocalDestination ()->CreateNewOutgoingStream (*leaseSet);
|
||||
m_Stream = i2p::client::context.GetSharedLocalDestination ()->CreateStream (*remote, port);
|
||||
if (m_Stream)
|
||||
{
|
||||
m_Stream->Send ((uint8_t *)buf, len);
|
||||
|
|
13
HTTPServer.h
13
HTTPServer.h
|
@ -5,6 +5,7 @@
|
|||
#include <thread>
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/array.hpp>
|
||||
#include "LeaseSet.h"
|
||||
#include "Streaming.h"
|
||||
|
||||
namespace i2p
|
||||
|
@ -12,6 +13,7 @@ namespace i2p
|
|||
namespace util
|
||||
{
|
||||
const size_t HTTP_CONNECTION_BUFFER_SIZE = 8192;
|
||||
const int HTTP_DESTINATION_REQUEST_TIMEOUT = 10; // in seconds
|
||||
class HTTPConnection
|
||||
{
|
||||
protected:
|
||||
|
@ -27,6 +29,7 @@ namespace util
|
|||
std::string method;
|
||||
std::string uri;
|
||||
std::string host;
|
||||
int port;
|
||||
int http_version_major;
|
||||
int http_version_minor;
|
||||
std::vector<header> headers;
|
||||
|
@ -43,7 +46,8 @@ namespace util
|
|||
public:
|
||||
|
||||
HTTPConnection (boost::asio::ip::tcp::socket * socket):
|
||||
m_Socket (socket), m_Stream (nullptr), m_BufferLen (0) { Receive (); };
|
||||
m_Socket (socket), m_Timer (socket->get_io_service ()),
|
||||
m_Stream (nullptr), m_BufferLen (0) { Receive (); };
|
||||
virtual ~HTTPConnection() { delete m_Socket; }
|
||||
|
||||
private:
|
||||
|
@ -74,6 +78,7 @@ namespace util
|
|||
protected:
|
||||
|
||||
boost::asio::ip::tcp::socket * m_Socket;
|
||||
boost::asio::deadline_timer m_Timer;
|
||||
i2p::stream::Stream * m_Stream;
|
||||
char m_Buffer[HTTP_CONNECTION_BUFFER_SIZE + 1], m_StreamBuffer[HTTP_CONNECTION_BUFFER_SIZE + 1];
|
||||
size_t m_BufferLen;
|
||||
|
@ -84,8 +89,10 @@ namespace util
|
|||
|
||||
virtual void RunRequest ();
|
||||
void HandleDestinationRequest(const std::string& address, const std::string& uri);
|
||||
void SendToAddress (const std::string& address, const char * buf, size_t len);
|
||||
void SendToDestination (const i2p::data::IdentHash& destination, const char * buf, size_t len);
|
||||
void SendToAddress (const std::string& address, int port, const char * buf, size_t len);
|
||||
void HandleDestinationRequestTimeout (const boost::system::error_code& ecode,
|
||||
i2p::data::IdentHash destination, int port, const char * buf, size_t len);
|
||||
void SendToDestination (const i2p::data::LeaseSet * remote, int port, const char * buf, size_t len);
|
||||
|
||||
public:
|
||||
|
||||
|
|
|
@ -13,9 +13,10 @@
|
|||
#include "Garlic.h"
|
||||
#include "I2NPProtocol.h"
|
||||
|
||||
using namespace i2p::transport;
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
|
||||
I2NPMessage * NewI2NPMessage ()
|
||||
{
|
||||
return new I2NPMessageBuffer<I2NP_MAX_MESSAGE_SIZE>();
|
||||
|
@ -289,7 +290,7 @@ namespace i2p
|
|||
{
|
||||
LogPrint ("Record ",i," is ours");
|
||||
|
||||
i2p::crypto::ElGamalDecrypt (i2p::context.GetPrivateKey (), records[i].encrypted, (uint8_t *)&clearText);
|
||||
i2p::crypto::ElGamalDecrypt (i2p::context.GetEncryptionPrivateKey (), records[i].encrypted, (uint8_t *)&clearText);
|
||||
// replace record to reply
|
||||
I2NPBuildResponseRecord * reply = (I2NPBuildResponseRecord *)(records + i);
|
||||
if (i2p::context.AcceptsTunnels ())
|
||||
|
@ -353,13 +354,13 @@ namespace i2p
|
|||
if (clearText.flag & 0x40) // we are endpoint of outboud tunnel
|
||||
{
|
||||
// so we send it to reply tunnel
|
||||
i2p::transports.SendMessage (clearText.nextIdent,
|
||||
transports.SendMessage (clearText.nextIdent,
|
||||
CreateTunnelGatewayMsg (be32toh (clearText.nextTunnel),
|
||||
eI2NPVariableTunnelBuildReply, buf, len,
|
||||
be32toh (clearText.nextMessageID)));
|
||||
}
|
||||
else
|
||||
i2p::transports.SendMessage (clearText.nextIdent,
|
||||
transports.SendMessage (clearText.nextIdent,
|
||||
CreateI2NPMessage (eI2NPVariableTunnelBuild, buf, len, be32toh (clearText.nextMessageID)));
|
||||
}
|
||||
}
|
||||
|
@ -373,13 +374,13 @@ namespace i2p
|
|||
if (clearText.flag & 0x40) // we are endpoint of outbound tunnel
|
||||
{
|
||||
// so we send it to reply tunnel
|
||||
i2p::transports.SendMessage (clearText.nextIdent,
|
||||
transports.SendMessage (clearText.nextIdent,
|
||||
CreateTunnelGatewayMsg (be32toh (clearText.nextTunnel),
|
||||
eI2NPTunnelBuildReply, buf, len,
|
||||
be32toh (clearText.nextMessageID)));
|
||||
}
|
||||
else
|
||||
i2p::transports.SendMessage (clearText.nextIdent,
|
||||
transports.SendMessage (clearText.nextIdent,
|
||||
CreateI2NPMessage (eI2NPTunnelBuild, buf, len, be32toh (clearText.nextMessageID)));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ namespace client
|
|||
boost::asio::ip::tcp::socket * socket, const i2p::data::LeaseSet * leaseSet):
|
||||
m_Socket (socket), m_Owner (owner)
|
||||
{
|
||||
m_Stream = m_Owner->GetLocalDestination ()->CreateNewOutgoingStream (*leaseSet);
|
||||
m_Stream = m_Owner->GetLocalDestination ()->CreateStream (*leaseSet);
|
||||
m_Stream->Send (m_Buffer, 0); // connect
|
||||
StreamReceive ();
|
||||
Receive ();
|
||||
|
@ -39,7 +39,7 @@ namespace client
|
|||
if (m_Stream)
|
||||
{
|
||||
m_Stream->Close ();
|
||||
m_Owner->GetLocalDestination ()->DeleteStream (m_Stream);
|
||||
i2p::stream::DeleteStream (m_Stream);
|
||||
m_Stream = nullptr;
|
||||
}
|
||||
m_Socket->close ();
|
||||
|
@ -115,7 +115,7 @@ namespace client
|
|||
if (ecode != boost::asio::error::operation_aborted)
|
||||
{
|
||||
if (m_Stream) m_Stream->Close ();
|
||||
m_Owner->GetLocalDestination ()->DeleteStream (m_Stream);
|
||||
i2p::stream::DeleteStream (m_Stream);
|
||||
m_Stream = nullptr;
|
||||
}
|
||||
}
|
||||
|
@ -145,7 +145,7 @@ namespace client
|
|||
}
|
||||
|
||||
I2PClientTunnel::I2PClientTunnel (boost::asio::io_service& service, const std::string& destination,
|
||||
int port, i2p::stream::StreamingDestination * localDestination):
|
||||
int port, ClientDestination * localDestination):
|
||||
I2PTunnel (service, localDestination ? localDestination :
|
||||
i2p::client::context.CreateNewLocalDestination (false, i2p::data::SIGNING_KEY_TYPE_ECDSA_SHA256_P256)),
|
||||
m_Acceptor (service, boost::asio::ip::tcp::endpoint (boost::asio::ip::tcp::v4(), port)),
|
||||
|
@ -162,7 +162,7 @@ namespace client
|
|||
void I2PClientTunnel::Start ()
|
||||
{
|
||||
i2p::data::IdentHash identHash;
|
||||
if (i2p::data::netdb.GetAddressBook ().GetIdentHash (m_Destination, identHash))
|
||||
if (i2p::client::context.GetAddressBook ().GetIdentHash (m_Destination, identHash))
|
||||
m_DestinationIdentHash = new i2p::data::IdentHash (identHash);
|
||||
if (!m_DestinationIdentHash)
|
||||
LogPrint ("I2PTunnel unknown destination ", m_Destination);
|
||||
|
@ -192,7 +192,7 @@ namespace client
|
|||
if (!m_DestinationIdentHash)
|
||||
{
|
||||
i2p::data::IdentHash identHash;
|
||||
if (i2p::data::netdb.GetAddressBook ().GetIdentHash (m_Destination, identHash))
|
||||
if (i2p::client::context.GetAddressBook ().GetIdentHash (m_Destination, identHash))
|
||||
m_DestinationIdentHash = new i2p::data::IdentHash (identHash);
|
||||
}
|
||||
if (m_DestinationIdentHash)
|
||||
|
@ -251,7 +251,7 @@ namespace client
|
|||
}
|
||||
|
||||
I2PServerTunnel::I2PServerTunnel (boost::asio::io_service& service, const std::string& address, int port,
|
||||
i2p::stream::StreamingDestination * localDestination): I2PTunnel (service, localDestination),
|
||||
ClientDestination * localDestination): I2PTunnel (service, localDestination),
|
||||
m_Endpoint (boost::asio::ip::address::from_string (address), port)
|
||||
{
|
||||
}
|
||||
|
@ -270,7 +270,7 @@ namespace client
|
|||
{
|
||||
auto localDestination = GetLocalDestination ();
|
||||
if (localDestination)
|
||||
localDestination->SetAcceptor (std::bind (&I2PServerTunnel::HandleAccept, this, std::placeholders::_1));
|
||||
localDestination->AcceptStreams (std::bind (&I2PServerTunnel::HandleAccept, this, std::placeholders::_1));
|
||||
else
|
||||
LogPrint ("Local destination not set for server tunnel");
|
||||
}
|
||||
|
|
13
I2PTunnel.h
13
I2PTunnel.h
|
@ -6,6 +6,7 @@
|
|||
#include <set>
|
||||
#include <boost/asio.hpp>
|
||||
#include "Identity.h"
|
||||
#include "Destination.h"
|
||||
#include "Streaming.h"
|
||||
|
||||
namespace i2p
|
||||
|
@ -51,22 +52,22 @@ namespace client
|
|||
{
|
||||
public:
|
||||
|
||||
I2PTunnel (boost::asio::io_service& service, i2p::stream::StreamingDestination * localDestination):
|
||||
I2PTunnel (boost::asio::io_service& service, ClientDestination * localDestination):
|
||||
m_Service (service), m_LocalDestination (localDestination) {};
|
||||
virtual ~I2PTunnel () { ClearConnections (); };
|
||||
|
||||
void AddConnection (I2PTunnelConnection * conn);
|
||||
void RemoveConnection (I2PTunnelConnection * conn);
|
||||
void ClearConnections ();
|
||||
i2p::stream::StreamingDestination * GetLocalDestination () { return m_LocalDestination; };
|
||||
void SetLocalDestination (i2p::stream::StreamingDestination * dest) { m_LocalDestination = dest; };
|
||||
ClientDestination * GetLocalDestination () { return m_LocalDestination; };
|
||||
void SetLocalDestination (ClientDestination * dest) { m_LocalDestination = dest; };
|
||||
|
||||
boost::asio::io_service& GetService () { return m_Service; };
|
||||
|
||||
private:
|
||||
|
||||
boost::asio::io_service& m_Service;
|
||||
i2p::stream::StreamingDestination * m_LocalDestination;
|
||||
ClientDestination * m_LocalDestination;
|
||||
std::set<I2PTunnelConnection *> m_Connections;
|
||||
};
|
||||
|
||||
|
@ -75,7 +76,7 @@ namespace client
|
|||
public:
|
||||
|
||||
I2PClientTunnel (boost::asio::io_service& service, const std::string& destination, int port,
|
||||
i2p::stream::StreamingDestination * localDestination = nullptr);
|
||||
ClientDestination * localDestination = nullptr);
|
||||
~I2PClientTunnel ();
|
||||
|
||||
void Start ();
|
||||
|
@ -102,7 +103,7 @@ namespace client
|
|||
public:
|
||||
|
||||
I2PServerTunnel (boost::asio::io_service& service, const std::string& address, int port,
|
||||
i2p::stream::StreamingDestination * localDestination);
|
||||
ClientDestination * localDestination);
|
||||
|
||||
void Start ();
|
||||
void Stop ();
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
#include <stdio.h>
|
||||
#include <cryptopp/sha.h>
|
||||
#include <cryptopp/osrng.h>
|
||||
#include <cryptopp/dh.h>
|
||||
#include <cryptopp/dsa.h>
|
||||
#include "base64.h"
|
||||
#include "CryptoConst.h"
|
||||
|
@ -293,14 +292,6 @@ namespace data
|
|||
return keys;
|
||||
}
|
||||
|
||||
void CreateRandomDHKeysPair (DHKeysPair * keys)
|
||||
{
|
||||
if (!keys) return;
|
||||
CryptoPP::AutoSeededRandomPool rnd;
|
||||
CryptoPP::DH dh (i2p::crypto::elgp, i2p::crypto::elgg);
|
||||
dh.GenerateKeyPair(rnd, keys->privateKey, keys->publicKey);
|
||||
}
|
||||
|
||||
IdentHash CreateRoutingKey (const IdentHash& ident)
|
||||
{
|
||||
uint8_t buf[41]; // ident + yyyymmdd
|
||||
|
|
16
Identity.h
16
Identity.h
|
@ -67,13 +67,6 @@ namespace data
|
|||
typedef Tag<32> IdentHash;
|
||||
|
||||
#pragma pack(1)
|
||||
|
||||
struct DHKeysPair // transient keys for transport sessions
|
||||
{
|
||||
uint8_t publicKey[256];
|
||||
uint8_t privateKey[256];
|
||||
};
|
||||
|
||||
struct Keys
|
||||
{
|
||||
uint8_t privateKey[256];
|
||||
|
@ -82,7 +75,6 @@ namespace data
|
|||
uint8_t signingKey[128];
|
||||
};
|
||||
|
||||
|
||||
const uint8_t CERTIFICATE_TYPE_NULL = 0;
|
||||
const uint8_t CERTIFICATE_TYPE_HASHCASH = 1;
|
||||
const uint8_t CERTIFICATE_TYPE_HIDDEN = 2;
|
||||
|
@ -106,6 +98,9 @@ namespace data
|
|||
size_t FromBuffer (const uint8_t * buf, size_t len);
|
||||
IdentHash Hash () const;
|
||||
};
|
||||
#pragma pack()
|
||||
Keys CreateRandomKeys ();
|
||||
|
||||
const size_t DEFAULT_IDENTITY_SIZE = sizeof (Identity); // 387 bytes
|
||||
|
||||
const uint16_t CRYPTO_KEY_TYPE_ELGAMAL = 0;
|
||||
|
@ -184,11 +179,6 @@ namespace data
|
|||
i2p::crypto::Signer * m_Signer;
|
||||
};
|
||||
|
||||
#pragma pack()
|
||||
|
||||
Keys CreateRandomKeys ();
|
||||
void CreateRandomDHKeysPair (DHKeysPair * keys); // for transport sessions
|
||||
|
||||
// kademlia
|
||||
struct XORMetric
|
||||
{
|
||||
|
|
|
@ -9,7 +9,7 @@ LIBS =
|
|||
# http://www.hutsby.net/2011/08/macs-with-aes-ni.html
|
||||
# Seems like all recent Mac's have AES-NI, after firmware upgrade 2.2
|
||||
# Found no good way to detect it from command line. TODO: Might be some osx sysinfo magic
|
||||
CFLAGS += -DAESNI
|
||||
CFLAGS += -maes -DAESNI
|
||||
|
||||
# Apple Mac OSX
|
||||
UNAME_S := $(shell uname -s)
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
#include "I2PEndian.h"
|
||||
#include <boost/bind.hpp>
|
||||
#include <cryptopp/dh.h>
|
||||
#include <cryptopp/dsa.h>
|
||||
#include "base64.h"
|
||||
#include "Log.h"
|
||||
#include "Timestamp.h"
|
||||
|
@ -11,28 +10,27 @@
|
|||
#include "I2NPProtocol.h"
|
||||
#include "RouterContext.h"
|
||||
#include "Transports.h"
|
||||
#include "NetDb.h"
|
||||
#include "NTCPSession.h"
|
||||
|
||||
using namespace i2p::crypto;
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace ntcp
|
||||
namespace transport
|
||||
{
|
||||
NTCPSession::NTCPSession (boost::asio::io_service& service, i2p::data::RouterInfo& in_RemoteRouterInfo):
|
||||
m_Socket (service), m_TerminationTimer (service), m_IsEstablished (false),
|
||||
m_DHKeysPair (nullptr), m_RemoteRouterInfo (in_RemoteRouterInfo),
|
||||
m_ReceiveBufferOffset (0), m_NextMessage (nullptr),
|
||||
m_NumSentBytes (0), m_NumReceivedBytes (0)
|
||||
NTCPSession::NTCPSession (boost::asio::io_service& service, const i2p::data::RouterInfo * in_RemoteRouter):
|
||||
TransportSession (in_RemoteRouter), m_Socket (service),
|
||||
m_TerminationTimer (service), m_IsEstablished (false), m_ReceiveBufferOffset (0),
|
||||
m_NextMessage (nullptr), m_NumSentBytes (0), m_NumReceivedBytes (0)
|
||||
{
|
||||
m_DHKeysPair = i2p::transports.GetNextDHKeysPair ();
|
||||
m_DHKeysPair = transports.GetNextDHKeysPair ();
|
||||
m_Establisher = new Establisher;
|
||||
}
|
||||
|
||||
NTCPSession::~NTCPSession ()
|
||||
{
|
||||
delete m_Establisher;
|
||||
delete m_DHKeysPair;
|
||||
if (m_NextMessage)
|
||||
i2p::DeleteI2NPMessage (m_NextMessage);
|
||||
for (auto it :m_DelayedMessages)
|
||||
|
@ -79,12 +77,13 @@ namespace ntcp
|
|||
{
|
||||
m_IsEstablished = false;
|
||||
m_Socket.close ();
|
||||
i2p::transports.RemoveNTCPSession (this);
|
||||
transports.RemoveNTCPSession (this);
|
||||
int numDelayed = 0;
|
||||
for (auto it :m_DelayedMessages)
|
||||
{
|
||||
// try to send them again
|
||||
i2p::transports.SendMessage (m_RemoteRouterInfo.GetIdentHash (), it);
|
||||
if (m_RemoteRouter)
|
||||
transports.SendMessage (m_RemoteRouter->GetIdentHash (), it);
|
||||
numDelayed++;
|
||||
}
|
||||
m_DelayedMessages.clear ();
|
||||
|
@ -121,12 +120,12 @@ namespace ntcp
|
|||
void NTCPSession::ClientLogin ()
|
||||
{
|
||||
if (!m_DHKeysPair)
|
||||
m_DHKeysPair = i2p::transports.GetNextDHKeysPair ();
|
||||
m_DHKeysPair = transports.GetNextDHKeysPair ();
|
||||
// send Phase1
|
||||
const uint8_t * x = m_DHKeysPair->publicKey;
|
||||
memcpy (m_Establisher->phase1.pubKey, x, 256);
|
||||
CryptoPP::SHA256().CalculateDigest(m_Establisher->phase1.HXxorHI, x, 256);
|
||||
const uint8_t * ident = m_RemoteRouterInfo.GetIdentHash ();
|
||||
const uint8_t * ident = m_RemoteIdentity.GetIdentHash ();
|
||||
for (int i = 0; i < 32; i++)
|
||||
m_Establisher->phase1.HXxorHI[i] ^= ident[i];
|
||||
|
||||
|
@ -191,7 +190,7 @@ namespace ntcp
|
|||
void NTCPSession::SendPhase2 ()
|
||||
{
|
||||
if (!m_DHKeysPair)
|
||||
m_DHKeysPair = i2p::transports.GetNextDHKeysPair ();
|
||||
m_DHKeysPair = transports.GetNextDHKeysPair ();
|
||||
const uint8_t * y = m_DHKeysPair->publicKey;
|
||||
memcpy (m_Establisher->phase2.pubKey, y, 256);
|
||||
uint8_t xy[512];
|
||||
|
@ -239,8 +238,9 @@ namespace ntcp
|
|||
LogPrint ("Phase 2 read error: ", ecode.message (), ". Wrong ident assumed");
|
||||
if (ecode != boost::asio::error::operation_aborted)
|
||||
{
|
||||
GetRemoteRouterInfo ().SetUnreachable (true); // this RouterInfo is not valid
|
||||
i2p::transports.ReuseDHKeysPair (m_DHKeysPair);
|
||||
// this RI is not valid
|
||||
i2p::data::netdb.SetUnreachable (GetRemoteIdentity ().GetIdentHash (), true);
|
||||
transports.ReuseDHKeysPair (m_DHKeysPair);
|
||||
m_DHKeysPair = nullptr;
|
||||
Terminate ();
|
||||
}
|
||||
|
@ -265,7 +265,7 @@ namespace ntcp
|
|||
if (memcmp (hxy, m_Establisher->phase2.encrypted.hxy, 32))
|
||||
{
|
||||
LogPrint ("Incorrect hash");
|
||||
i2p::transports.ReuseDHKeysPair (m_DHKeysPair);
|
||||
transports.ReuseDHKeysPair (m_DHKeysPair);
|
||||
m_DHKeysPair = nullptr;
|
||||
Terminate ();
|
||||
return ;
|
||||
|
@ -277,14 +277,14 @@ namespace ntcp
|
|||
void NTCPSession::SendPhase3 ()
|
||||
{
|
||||
m_Establisher->phase3.size = htons (i2p::data::DEFAULT_IDENTITY_SIZE);
|
||||
memcpy (&m_Establisher->phase3.ident, &i2p::context.GetRouterIdentity (), i2p::data::DEFAULT_IDENTITY_SIZE);
|
||||
memcpy (&m_Establisher->phase3.ident, &i2p::context.GetIdentity ().GetStandardIdentity (), i2p::data::DEFAULT_IDENTITY_SIZE); // TODO:
|
||||
uint32_t tsA = htobe32 (i2p::util::GetSecondsSinceEpoch ());
|
||||
m_Establisher->phase3.timestamp = tsA;
|
||||
|
||||
SignedData s;
|
||||
memcpy (s.x, m_Establisher->phase1.pubKey, 256);
|
||||
memcpy (s.y, m_Establisher->phase2.pubKey, 256);
|
||||
memcpy (s.ident, m_RemoteRouterInfo.GetIdentHash (), 32);
|
||||
memcpy (s.ident, m_RemoteIdentity.GetIdentHash (), 32);
|
||||
s.tsA = tsA;
|
||||
s.tsB = m_Establisher->phase2.encrypted.timestamp;
|
||||
i2p::context.Sign ((uint8_t *)&s, sizeof (s), m_Establisher->phase3.signature);
|
||||
|
@ -324,7 +324,7 @@ namespace ntcp
|
|||
{
|
||||
LogPrint ("Phase 3 received: ", bytes_transferred);
|
||||
m_Decryption.Decrypt ((uint8_t *)&m_Establisher->phase3, sizeof(NTCPPhase3), (uint8_t *)&m_Establisher->phase3);
|
||||
m_RemoteRouterInfo.SetRouterIdentity (m_Establisher->phase3.ident);
|
||||
m_RemoteIdentity = m_Establisher->phase3.ident;
|
||||
|
||||
SignedData s;
|
||||
memcpy (s.x, m_Establisher->phase1.pubKey, 256);
|
||||
|
@ -333,10 +333,7 @@ namespace ntcp
|
|||
s.tsA = m_Establisher->phase3.timestamp;
|
||||
s.tsB = tsB;
|
||||
|
||||
CryptoPP::DSA::PublicKey pubKey;
|
||||
pubKey.Initialize (dsap, dsaq, dsag, CryptoPP::Integer (m_RemoteRouterInfo.GetRouterIdentity ().signingKey, 128));
|
||||
CryptoPP::DSA::Verifier verifier (pubKey);
|
||||
if (!verifier.VerifyMessage ((uint8_t *)&s, sizeof(s), m_Establisher->phase3.signature, 40))
|
||||
if (!m_RemoteIdentity.Verify ((uint8_t *)&s, sizeof(s), m_Establisher->phase3.signature))
|
||||
{
|
||||
LogPrint ("signature verification failed");
|
||||
Terminate ();
|
||||
|
@ -352,7 +349,7 @@ namespace ntcp
|
|||
SignedData s;
|
||||
memcpy (s.x, m_Establisher->phase1.pubKey, 256);
|
||||
memcpy (s.y, m_Establisher->phase2.pubKey, 256);
|
||||
memcpy (s.ident, m_RemoteRouterInfo.GetIdentHash (), 32);
|
||||
memcpy (s.ident, m_RemoteIdentity.GetIdentHash (), 32);
|
||||
s.tsA = m_Establisher->phase3.timestamp;
|
||||
s.tsB = tsB;
|
||||
i2p::context.Sign ((uint8_t *)&s, sizeof (s), m_Establisher->phase4.signature);
|
||||
|
@ -387,7 +384,8 @@ namespace ntcp
|
|||
LogPrint ("Phase 4 read error: ", ecode.message ());
|
||||
if (ecode != boost::asio::error::operation_aborted)
|
||||
{
|
||||
GetRemoteRouterInfo ().SetUnreachable (true); // this router doesn't like us
|
||||
// this router doesn't like us
|
||||
i2p::data::netdb.SetUnreachable (GetRemoteIdentity ().GetIdentHash (), true);
|
||||
Terminate ();
|
||||
}
|
||||
}
|
||||
|
@ -404,10 +402,7 @@ namespace ntcp
|
|||
s.tsA = tsA;
|
||||
s.tsB = m_Establisher->phase2.encrypted.timestamp;
|
||||
|
||||
CryptoPP::DSA::PublicKey pubKey;
|
||||
pubKey.Initialize (dsap, dsaq, dsag, CryptoPP::Integer (m_RemoteRouterInfo.GetRouterIdentity ().signingKey, 128));
|
||||
CryptoPP::DSA::Verifier verifier (pubKey);
|
||||
if (!verifier.VerifyMessage ((uint8_t *)&s, sizeof(s), m_Establisher->phase4.signature, 40))
|
||||
if (!m_RemoteIdentity.Verify ((uint8_t *)&s, sizeof(s), m_Establisher->phase4.signature))
|
||||
{
|
||||
LogPrint ("signature verification failed");
|
||||
Terminate ();
|
||||
|
@ -601,9 +596,8 @@ namespace ntcp
|
|||
|
||||
|
||||
NTCPClient::NTCPClient (boost::asio::io_service& service, const boost::asio::ip::address& address,
|
||||
int port, i2p::data::RouterInfo& in_RouterInfo):
|
||||
NTCPSession (service, in_RouterInfo),
|
||||
m_Endpoint (address, port)
|
||||
int port, const i2p::data::RouterInfo& in_RouterInfo):
|
||||
NTCPSession (service, &in_RouterInfo), m_Endpoint (address, port)
|
||||
{
|
||||
Connect ();
|
||||
}
|
||||
|
@ -622,13 +616,15 @@ namespace ntcp
|
|||
LogPrint ("Connect error: ", ecode.message ());
|
||||
if (ecode != boost::asio::error::operation_aborted)
|
||||
{
|
||||
GetRemoteRouterInfo ().SetUnreachable (true);
|
||||
i2p::data::netdb.SetUnreachable (GetRemoteIdentity ().GetIdentHash (), true);
|
||||
Terminate ();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrint ("Connected");
|
||||
if (GetSocket ().local_endpoint ().protocol () == boost::asio::ip::tcp::v6()) // ipv6
|
||||
context.UpdateV6Address (GetSocket ().local_endpoint ().address ().to_string ());
|
||||
ClientLogin ();
|
||||
}
|
||||
}
|
||||
|
@ -636,11 +632,8 @@ namespace ntcp
|
|||
void NTCPServerConnection::Connected ()
|
||||
{
|
||||
LogPrint ("NTCP server session connected");
|
||||
SetIsEstablished (true);
|
||||
i2p::transports.AddNTCPSession (this);
|
||||
|
||||
SendTimeSyncMessage ();
|
||||
SendI2NPMessage (CreateDatabaseStoreMsg ()); // we tell immediately who we are
|
||||
transports.AddNTCPSession (this);
|
||||
NTCPSession::Connected ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,10 +11,11 @@
|
|||
#include "Identity.h"
|
||||
#include "RouterInfo.h"
|
||||
#include "I2NPProtocol.h"
|
||||
#include "TransportSession.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace ntcp
|
||||
namespace transport
|
||||
{
|
||||
|
||||
#pragma pack(1)
|
||||
|
@ -65,16 +66,16 @@ namespace ntcp
|
|||
const size_t NTCP_MAX_MESSAGE_SIZE = 16384;
|
||||
const size_t NTCP_BUFFER_SIZE = 1040; // fits one tunnel message (1028)
|
||||
const int NTCP_TERMINATION_TIMEOUT = 120; // 2 minutes
|
||||
class NTCPSession
|
||||
|
||||
class NTCPSession: public TransportSession
|
||||
{
|
||||
public:
|
||||
|
||||
NTCPSession (boost::asio::io_service& service, i2p::data::RouterInfo& in_RemoteRouterInfo);
|
||||
virtual ~NTCPSession ();
|
||||
NTCPSession (boost::asio::io_service& service, const i2p::data::RouterInfo * in_RemoteRouter = nullptr);
|
||||
~NTCPSession ();
|
||||
|
||||
boost::asio::ip::tcp::socket& GetSocket () { return m_Socket; };
|
||||
bool IsEstablished () const { return m_IsEstablished; };
|
||||
i2p::data::RouterInfo& GetRemoteRouterInfo () { return m_RemoteRouterInfo; };
|
||||
|
||||
void ClientLogin ();
|
||||
void ServerLogin ();
|
||||
|
@ -127,14 +128,11 @@ namespace ntcp
|
|||
boost::asio::ip::tcp::socket m_Socket;
|
||||
boost::asio::deadline_timer m_TerminationTimer;
|
||||
bool m_IsEstablished;
|
||||
i2p::data::DHKeysPair * m_DHKeysPair; // X - for client and Y - for server
|
||||
|
||||
i2p::crypto::CBCDecryption m_Decryption;
|
||||
i2p::crypto::CBCEncryption m_Encryption;
|
||||
CryptoPP::Adler32 m_Adler;
|
||||
|
||||
i2p::data::RouterInfo& m_RemoteRouterInfo;
|
||||
|
||||
struct Establisher
|
||||
{
|
||||
NTCPPhase1 phase1;
|
||||
|
@ -157,7 +155,7 @@ namespace ntcp
|
|||
{
|
||||
public:
|
||||
|
||||
NTCPClient (boost::asio::io_service& service, const boost::asio::ip::address& address, int port, i2p::data::RouterInfo& in_RouterInfo);
|
||||
NTCPClient (boost::asio::io_service& service, const boost::asio::ip::address& address, int port, const i2p::data::RouterInfo& in_RouterInfo);
|
||||
|
||||
private:
|
||||
|
||||
|
@ -174,15 +172,11 @@ namespace ntcp
|
|||
public:
|
||||
|
||||
NTCPServerConnection (boost::asio::io_service& service):
|
||||
NTCPSession (service, m_DummyRemoteRouterInfo) {};
|
||||
NTCPSession (service) {};
|
||||
|
||||
protected:
|
||||
|
||||
virtual void Connected ();
|
||||
|
||||
private:
|
||||
|
||||
i2p::data::RouterInfo m_DummyRemoteRouterInfo;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
17
NetDb.cpp
17
NetDb.cpp
|
@ -15,6 +15,8 @@
|
|||
#include "Reseed.h"
|
||||
#include "util.h"
|
||||
|
||||
using namespace i2p::transport;
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace data
|
||||
|
@ -227,6 +229,13 @@ namespace data
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
void NetDb::SetUnreachable (const IdentHash& ident, bool unreachable)
|
||||
{
|
||||
auto it = m_RouterInfos.find (ident);
|
||||
if (it != m_RouterInfos.end ())
|
||||
return it->second->SetUnreachable (unreachable);
|
||||
}
|
||||
|
||||
// TODO: Move to reseed and/or scheduled tasks. (In java version, scheduler fix this as well as sort RIs.)
|
||||
bool NetDb::CreateNetDb(boost::filesystem::path directory)
|
||||
{
|
||||
|
@ -403,7 +412,7 @@ namespace data
|
|||
RequestedDestination * dest = CreateRequestedDestination (destination, false, false, pool);
|
||||
auto floodfill = GetClosestFloodfill (destination, dest->GetExcludedPeers ());
|
||||
if (floodfill)
|
||||
i2p::transports.SendMessage (floodfill->GetIdentHash (), dest->CreateRequestMessage (floodfill->GetIdentHash ()));
|
||||
transports.SendMessage (floodfill->GetIdentHash (), dest->CreateRequestMessage (floodfill->GetIdentHash ()));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -655,10 +664,10 @@ namespace data
|
|||
if (outbound)
|
||||
outbound->SendTunnelDataMsg (buf+32, replyTunnelID, replyMsg);
|
||||
else
|
||||
i2p::transports.SendMessage (buf+32, i2p::CreateTunnelGatewayMsg (replyTunnelID, replyMsg));
|
||||
transports.SendMessage (buf+32, i2p::CreateTunnelGatewayMsg (replyTunnelID, replyMsg));
|
||||
}
|
||||
else
|
||||
i2p::transports.SendMessage (buf+32, replyMsg);
|
||||
transports.SendMessage (buf+32, replyMsg);
|
||||
}
|
||||
i2p::DeleteI2NPMessage (msg);
|
||||
}
|
||||
|
@ -712,7 +721,7 @@ namespace data
|
|||
});
|
||||
}
|
||||
else
|
||||
i2p::transports.SendMessage (floodfill->GetIdentHash (), dest->CreateRequestMessage (floodfill->GetIdentHash ()));
|
||||
i2p::transport::transports.SendMessage (floodfill->GetIdentHash (), dest->CreateRequestMessage (floodfill->GetIdentHash ()));
|
||||
}
|
||||
else
|
||||
DeleteRequestedDestination (dest);
|
||||
|
|
4
NetDb.h
4
NetDb.h
|
@ -15,7 +15,6 @@
|
|||
#include "LeaseSet.h"
|
||||
#include "Tunnel.h"
|
||||
#include "TunnelPool.h"
|
||||
#include "AddressBook.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
|
@ -67,7 +66,6 @@ namespace data
|
|||
void AddLeaseSet (const IdentHash& ident, const uint8_t * buf, int len, i2p::tunnel::InboundTunnel * from);
|
||||
RouterInfo * FindRouter (const IdentHash& ident) const;
|
||||
LeaseSet * FindLeaseSet (const IdentHash& destination) const;
|
||||
AddressBook& GetAddressBook () { return m_AddressBook; };// TODO: move AddressBook away from NetDb
|
||||
|
||||
void PublishLeaseSet (const LeaseSet * leaseSet, i2p::tunnel::TunnelPool * pool);
|
||||
void RequestDestination (const IdentHash& destination, bool isLeaseSet = false,
|
||||
|
@ -80,6 +78,7 @@ namespace data
|
|||
const RouterInfo * GetRandomRouter () const;
|
||||
const RouterInfo * GetRandomRouter (const RouterInfo * compatibleWith) const;
|
||||
const RouterInfo * GetHighBandwidthRandomRouter (const RouterInfo * compatibleWith) const;
|
||||
void SetUnreachable (const IdentHash& ident, bool unreachable);
|
||||
|
||||
void PostI2NPMsg (I2NPMessage * msg);
|
||||
|
||||
|
@ -120,7 +119,6 @@ namespace data
|
|||
int m_ReseedRetries;
|
||||
std::thread * m_Thread;
|
||||
i2p::util::Queue<I2NPMessage> m_Queue; // of I2NPDatabaseStoreMsg
|
||||
AddressBook m_AddressBook;
|
||||
|
||||
static const char m_NetDbPath[];
|
||||
};
|
||||
|
|
|
@ -35,10 +35,10 @@ $ ./i2p --host=YOUR_PUBLIC_IP
|
|||
The client should now reseed by itself.
|
||||
|
||||
To visit an I2P page, you need to find the b32 address of your destination.
|
||||
After that, go to the webconsole and add it behind the url. (Remove http:// and b32.i2p from the address)
|
||||
After that, go to the webconsole and add it behind the url. (Remove http:// from the address)
|
||||
|
||||
This should resulting in for example:
|
||||
http://localhost:7070/4oes3rlgrpbkmzv4lqcfili23h3cvpwslqcfjlk6vvguxyggspwa
|
||||
http://localhost:7070/4oes3rlgrpbkmzv4lqcfili23h3cvpwslqcfjlk6vvguxyggspwa.b32.i2p
|
||||
|
||||
|
||||
Options
|
||||
|
@ -51,6 +51,7 @@ Options
|
|||
* --daemon= - Enable or disable daemon mode. 1 for yes, 0 for no.
|
||||
* --service= - 1 if uses system folders (/var/run/i2pd.pid, /var/log/i2pd.log, /var/lib/i2pd).
|
||||
* --unreachable= - 1 if router is declared as unreachable and works through introducers.
|
||||
* --v6= - 1 if supports communication through ipv6, off by default
|
||||
* --httpproxyport= - The port to listen on (HTTP Proxy)
|
||||
* --socksproxyport= - The port to listen on (SOCKS Proxy)
|
||||
* --ircport= - The local port of IRC tunnel to listen on. 6668 by default
|
||||
|
|
|
@ -78,7 +78,7 @@ namespace i2p
|
|||
auto newAddress = boost::asio::ip::address::from_string (host);
|
||||
for (auto& address : m_RouterInfo.GetAddresses ())
|
||||
{
|
||||
if (address.host != newAddress)
|
||||
if (address.host != newAddress && address.IsCompatible (newAddress))
|
||||
{
|
||||
address.host = newAddress;
|
||||
updated = true;
|
||||
|
@ -131,6 +131,44 @@ namespace i2p
|
|||
UpdateRouterInfo ();
|
||||
}
|
||||
|
||||
void RouterContext::SetSupportsV6 (bool supportsV6)
|
||||
{
|
||||
if (supportsV6)
|
||||
m_RouterInfo.EnableV6 ();
|
||||
else
|
||||
m_RouterInfo.DisableV6 ();
|
||||
}
|
||||
|
||||
void RouterContext::UpdateV6Address (const std::string& host)
|
||||
{
|
||||
bool updated = false, found = false;
|
||||
int port = 0;
|
||||
auto newAddress = boost::asio::ip::address::from_string (host);
|
||||
auto& addresses = m_RouterInfo.GetAddresses ();
|
||||
for (auto& addr : addresses)
|
||||
{
|
||||
if (addr.host.is_v6 ())
|
||||
{
|
||||
if (addr.host != newAddress)
|
||||
{
|
||||
addr.host = newAddress;
|
||||
updated = true;
|
||||
}
|
||||
found = true;
|
||||
}
|
||||
else
|
||||
port = addr.port;
|
||||
}
|
||||
if (!found)
|
||||
{
|
||||
// create new address
|
||||
m_RouterInfo.AddNTCPAddress (host.c_str (), port);
|
||||
updated = true;
|
||||
}
|
||||
if (updated)
|
||||
UpdateRouterInfo ();
|
||||
}
|
||||
|
||||
bool RouterContext::Load ()
|
||||
{
|
||||
std::ifstream fk (i2p::util::filesystem::GetFullPath (ROUTER_KEYS).c_str (), std::ifstream::binary | std::ofstream::in);
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#define ROUTER_CONTEXT_H__
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <string>
|
||||
#include <cryptopp/dsa.h>
|
||||
#include <cryptopp/osrng.h>
|
||||
#include "Identity.h"
|
||||
|
@ -22,9 +23,6 @@ namespace i2p
|
|||
void Init ();
|
||||
|
||||
i2p::data::RouterInfo& GetRouterInfo () { return m_RouterInfo; };
|
||||
const uint8_t * GetPrivateKey () const { return m_Keys.GetPrivateKey (); };
|
||||
const i2p::data::Identity& GetRouterIdentity () const { return m_RouterInfo.GetRouterIdentity (); };
|
||||
const i2p::data::IdentHash& GetRouterIdentHash () const { return m_RouterInfo.GetIdentHash (); };
|
||||
CryptoPP::RandomNumberGenerator& GetRandomNumberGenerator () { return m_Rnd; };
|
||||
|
||||
void UpdatePort (int port); // called from Daemon
|
||||
|
@ -35,6 +33,9 @@ namespace i2p
|
|||
void SetUnreachable ();
|
||||
bool AcceptsTunnels () const { return m_AcceptsTunnels; };
|
||||
void SetAcceptsTunnels (bool acceptsTunnels) { m_AcceptsTunnels = acceptsTunnels; };
|
||||
bool SupportsV6 () const { return m_RouterInfo.IsV6 (); };
|
||||
void SetSupportsV6 (bool supportsV6);
|
||||
void UpdateV6Address (const std::string& host); // called from NTCP session
|
||||
|
||||
// implements LocalDestination
|
||||
const i2p::data::PrivateKeys& GetPrivateKeys () const { return m_Keys; };
|
||||
|
|
|
@ -59,7 +59,6 @@ namespace data
|
|||
{
|
||||
m_RouterIdentity = identity;
|
||||
m_IdentHash = m_RouterIdentity.Hash ();
|
||||
UpdateIdentHashBase64 ();
|
||||
m_Timestamp = i2p::util::GetMillisecondsSinceEpoch ();
|
||||
}
|
||||
|
||||
|
@ -226,7 +225,6 @@ namespace data
|
|||
}
|
||||
|
||||
CryptoPP::SHA256().CalculateDigest(m_IdentHash, (uint8_t *)&m_RouterIdentity, sizeof (m_RouterIdentity));
|
||||
UpdateIdentHashBase64 ();
|
||||
|
||||
if (!m_SupportedTransports || !m_Addresses.size() || (UsesIntroducer () && !introducers))
|
||||
SetUnreachable (true);
|
||||
|
@ -280,17 +278,8 @@ namespace data
|
|||
SetProperty ("caps", caps.c_str ());
|
||||
}
|
||||
|
||||
void RouterInfo::UpdateIdentHashBase64 ()
|
||||
{
|
||||
size_t l = i2p::data::ByteStreamToBase64 (m_IdentHash, 32, m_IdentHashBase64, 48);
|
||||
m_IdentHashBase64[l] = 0;
|
||||
memcpy (m_IdentHashAbbreviation, m_IdentHashBase64, 4);
|
||||
m_IdentHashAbbreviation[4] = 0;
|
||||
}
|
||||
|
||||
void RouterInfo::WriteToStream (std::ostream& s)
|
||||
{
|
||||
s.write ((char *)&m_RouterIdentity, sizeof (m_RouterIdentity));
|
||||
uint64_t ts = htobe64 (m_Timestamp);
|
||||
s.write ((char *)&ts, sizeof (ts));
|
||||
|
||||
|
@ -410,7 +399,7 @@ namespace data
|
|||
if (!m_Buffer)
|
||||
{
|
||||
if (LoadFile ())
|
||||
LogPrint ("Buffer for ", m_IdentHashAbbreviation, " loaded from file");
|
||||
LogPrint ("Buffer for ", GetIdentHashAbbreviation (), " loaded from file");
|
||||
}
|
||||
return m_Buffer;
|
||||
}
|
||||
|
@ -419,6 +408,9 @@ namespace data
|
|||
{
|
||||
m_Timestamp = i2p::util::GetMillisecondsSinceEpoch (); // refresh timstamp
|
||||
std::stringstream s;
|
||||
uint8_t ident[1024];
|
||||
auto identLen = privateKeys.GetPublic ().ToBuffer (ident, 1024);
|
||||
s.write ((char *)ident, identLen);
|
||||
WriteToStream (s);
|
||||
m_BufferLen = s.str ().size ();
|
||||
if (!m_Buffer)
|
||||
|
@ -466,7 +458,7 @@ namespace data
|
|||
addr.cost = 2;
|
||||
addr.date = 0;
|
||||
m_Addresses.push_back(addr);
|
||||
m_SupportedTransports |= eNTCPV4;
|
||||
m_SupportedTransports |= addr.host.is_v6 () ? eNTCPV6 : eNTCPV4;
|
||||
}
|
||||
|
||||
void RouterInfo::AddSSUAddress (const char * host, int port, const uint8_t * key)
|
||||
|
@ -479,7 +471,7 @@ namespace data
|
|||
addr.date = 0;
|
||||
memcpy (addr.key, key, 32);
|
||||
m_Addresses.push_back(addr);
|
||||
m_SupportedTransports |= eSSUV4;
|
||||
m_SupportedTransports |= addr.host.is_v6 () ? eNTCPV6 : eSSUV4;
|
||||
m_Caps |= eSSUTesting;
|
||||
m_Caps |= eSSUIntroducer;
|
||||
}
|
||||
|
@ -568,6 +560,34 @@ namespace data
|
|||
return m_SupportedTransports & (eSSUV4 | eSSUV6);
|
||||
}
|
||||
|
||||
bool RouterInfo::IsV6 () const
|
||||
{
|
||||
return m_SupportedTransports & (eNTCPV6 | eSSUV6);
|
||||
}
|
||||
|
||||
void RouterInfo::EnableV6 ()
|
||||
{
|
||||
if (!IsV6 ())
|
||||
m_SupportedTransports |= eNTCPV6;
|
||||
}
|
||||
|
||||
void RouterInfo::DisableV6 ()
|
||||
{
|
||||
if (IsV6 ())
|
||||
{
|
||||
m_SupportedTransports &= ~eNTCPV6;
|
||||
for (size_t i = 0; i < m_Addresses.size (); i++)
|
||||
{
|
||||
if (m_Addresses[i].transportStyle == i2p::data::RouterInfo::eTransportNTCP &&
|
||||
m_Addresses[i].host.is_v6 ())
|
||||
{
|
||||
m_Addresses.erase (m_Addresses.begin () + i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool RouterInfo::UsesIntroducer () const
|
||||
{
|
||||
return m_Caps & Caps::eUnreachable; // non-reachable
|
||||
|
|
17
RouterInfo.h
17
RouterInfo.h
|
@ -75,10 +75,16 @@ namespace data
|
|||
// SSU only
|
||||
Tag<32> key; // intro key for SSU
|
||||
std::vector<Introducer> introducers;
|
||||
|
||||
bool IsCompatible (const boost::asio::ip::address& other) const
|
||||
{
|
||||
return (host.is_v4 () && other.is_v4 ()) ||
|
||||
(host.is_v6 () && other.is_v6 ());
|
||||
}
|
||||
};
|
||||
|
||||
RouterInfo (const std::string& fullPath);
|
||||
RouterInfo (): m_Buffer (nullptr) { m_IdentHashBase64[0] = 0; m_IdentHashAbbreviation[0] = 0; };
|
||||
RouterInfo (): m_Buffer (nullptr) { };
|
||||
RouterInfo (const RouterInfo& ) = default;
|
||||
RouterInfo& operator=(const RouterInfo& ) = default;
|
||||
RouterInfo (const uint8_t * buf, int len);
|
||||
|
@ -86,8 +92,8 @@ namespace data
|
|||
|
||||
const Identity& GetRouterIdentity () const { return m_RouterIdentity; };
|
||||
void SetRouterIdentity (const Identity& identity);
|
||||
const char * GetIdentHashBase64 () const { return m_IdentHashBase64; };
|
||||
const char * GetIdentHashAbbreviation () const { return m_IdentHashAbbreviation; };
|
||||
std::string GetIdentHashBase64 () const { return m_IdentHash.ToBase64 (); };
|
||||
std::string GetIdentHashAbbreviation () const { return m_IdentHash.ToBase64 ().substr (0, 4); };
|
||||
uint64_t GetTimestamp () const { return m_Timestamp; };
|
||||
std::vector<Address>& GetAddresses () { return m_Addresses; };
|
||||
const Address * GetNTCPAddress (bool v4only = true) const;
|
||||
|
@ -102,6 +108,9 @@ namespace data
|
|||
bool IsFloodfill () const;
|
||||
bool IsNTCP (bool v4only = true) const;
|
||||
bool IsSSU (bool v4only = true) const;
|
||||
bool IsV6 () const;
|
||||
void EnableV6 ();
|
||||
void DisableV6 ();
|
||||
bool IsCompatible (const RouterInfo& other) const { return m_SupportedTransports & other.m_SupportedTransports; };
|
||||
bool UsesIntroducer () const;
|
||||
bool IsIntroducer () const { return m_Caps & eSSUIntroducer; };
|
||||
|
@ -143,7 +152,6 @@ namespace data
|
|||
size_t ReadString (char * str, std::istream& s);
|
||||
void WriteString (const std::string& str, std::ostream& s);
|
||||
void ExtractCaps (const char * value);
|
||||
void UpdateIdentHashBase64 ();
|
||||
const Address * GetAddress (TransportStyle s, bool v4only) const;
|
||||
void UpdateCapsProperty ();
|
||||
|
||||
|
@ -152,7 +160,6 @@ namespace data
|
|||
std::string m_FullPath;
|
||||
Identity m_RouterIdentity;
|
||||
IdentHash m_IdentHash;
|
||||
char m_IdentHashBase64[48], m_IdentHashAbbreviation[5];
|
||||
uint8_t * m_Buffer;
|
||||
int m_BufferLen;
|
||||
uint64_t m_Timestamp;
|
||||
|
|
85
SAM.cpp
85
SAM.cpp
|
@ -28,8 +28,8 @@ namespace client
|
|||
if (m_Stream)
|
||||
{
|
||||
m_Stream->Close ();
|
||||
if (m_Session && m_Session->localDestination)
|
||||
m_Session->localDestination->DeleteStream (m_Stream);
|
||||
i2p::stream::DeleteStream (m_Stream);
|
||||
m_Stream = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -38,8 +38,7 @@ namespace client
|
|||
if (m_Stream)
|
||||
{
|
||||
m_Stream->Close ();
|
||||
if (m_Session && m_Session->localDestination)
|
||||
m_Session->localDestination->DeleteStream (m_Stream);
|
||||
i2p::stream::DeleteStream (m_Stream);
|
||||
m_Stream = nullptr;
|
||||
}
|
||||
switch (m_SocketType)
|
||||
|
@ -58,7 +57,7 @@ namespace client
|
|||
if (m_Session)
|
||||
{
|
||||
m_Session->sockets.remove (this);
|
||||
m_Session->localDestination->ResetAcceptor ();
|
||||
m_Session->localDestination->StopAcceptingStreams ();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -210,6 +209,7 @@ namespace client
|
|||
LogPrint ("SAM session create: ", buf);
|
||||
std::map<std::string, std::string> params;
|
||||
ExtractParams (buf, len, params);
|
||||
std::string& style = params[SAM_PARAM_STYLE];
|
||||
std::string& id = params[SAM_PARAM_ID];
|
||||
std::string& destination = params[SAM_PARAM_DESTINATION];
|
||||
m_ID = id;
|
||||
|
@ -224,7 +224,11 @@ namespace client
|
|||
{
|
||||
m_SocketType = eSAMSocketTypeSession;
|
||||
if (m_Session->localDestination->IsReady ())
|
||||
{
|
||||
if (style == SAM_VALUE_DATAGRAM)
|
||||
m_Session->localDestination->CreateDatagramDestination ();
|
||||
SendSessionCreateReplyOk ();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Timer.expires_from_now (boost::posix_time::seconds(SAM_SESSION_READINESS_CHECK_INTERVAL));
|
||||
|
@ -302,7 +306,7 @@ namespace client
|
|||
{
|
||||
m_SocketType = eSAMSocketTypeStream;
|
||||
m_Session->sockets.push_back (this);
|
||||
m_Stream = m_Session->localDestination->CreateNewOutgoingStream (remote);
|
||||
m_Stream = m_Session->localDestination->CreateStream (remote);
|
||||
m_Stream->Send ((uint8_t *)m_Buffer, 0); // connect
|
||||
I2PReceive ();
|
||||
SendMessageReply (SAM_STREAM_STATUS_OK, strlen(SAM_STREAM_STATUS_OK), false);
|
||||
|
@ -355,11 +359,11 @@ namespace client
|
|||
m_Session = m_Owner.FindSession (id);
|
||||
if (m_Session)
|
||||
{
|
||||
if (!m_Session->localDestination->IsAcceptorSet ())
|
||||
if (!m_Session->localDestination->IsAcceptingStreams ())
|
||||
{
|
||||
m_SocketType = eSAMSocketTypeAcceptor;
|
||||
m_Session->sockets.push_back (this);
|
||||
m_Session->localDestination->SetAcceptor (std::bind (&SAMSocket::HandleI2PAccept, this, std::placeholders::_1));
|
||||
m_Session->localDestination->AcceptStreams (std::bind (&SAMSocket::HandleI2PAccept, this, std::placeholders::_1));
|
||||
SendMessageReply (SAM_STREAM_STATUS_OK, strlen(SAM_STREAM_STATUS_OK), false);
|
||||
}
|
||||
else
|
||||
|
@ -404,7 +408,7 @@ namespace client
|
|||
i2p::data::IdentHash ident;
|
||||
if (name == "ME")
|
||||
SendNamingLookupReply (nullptr);
|
||||
else if (m_Session && i2p::data::netdb.GetAddressBook ().GetIdentHash (name, ident))
|
||||
else if (m_Session && context.GetAddressBook ().GetIdentHash (name, ident))
|
||||
{
|
||||
auto leaseSet = m_Session->localDestination->FindLeaseSet (ident);
|
||||
if (leaseSet)
|
||||
|
@ -530,7 +534,7 @@ namespace client
|
|||
m_Stream = stream;
|
||||
auto session = m_Owner.FindSession (m_ID);
|
||||
if (session)
|
||||
session->localDestination->ResetAcceptor ();
|
||||
session->localDestination->StopAcceptingStreams ();
|
||||
if (!m_IsSilent)
|
||||
{
|
||||
// send remote peer address
|
||||
|
@ -547,6 +551,7 @@ namespace client
|
|||
SAMBridge::SAMBridge (int port):
|
||||
m_IsRunning (false), m_Thread (nullptr),
|
||||
m_Acceptor (m_Service, boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), port)),
|
||||
m_DatagramEndpoint (boost::asio::ip::udp::v4 (), port-1), m_DatagramSocket (m_Service, m_DatagramEndpoint),
|
||||
m_NewSocket (nullptr)
|
||||
{
|
||||
}
|
||||
|
@ -560,6 +565,7 @@ namespace client
|
|||
void SAMBridge::Start ()
|
||||
{
|
||||
Accept ();
|
||||
ReceiveDatagram ();
|
||||
m_IsRunning = true;
|
||||
m_Thread = new std::thread (std::bind (&SAMBridge::Run, this));
|
||||
}
|
||||
|
@ -618,7 +624,7 @@ namespace client
|
|||
|
||||
SAMSession * SAMBridge::CreateSession (const std::string& id, const std::string& destination)
|
||||
{
|
||||
i2p::stream::StreamingDestination * localDestination = nullptr;
|
||||
ClientDestination * localDestination = nullptr;
|
||||
if (destination != "")
|
||||
{
|
||||
uint8_t * buf = new uint8_t[destination.length ()];
|
||||
|
@ -665,5 +671,62 @@ namespace client
|
|||
return &it->second;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void SAMBridge::ReceiveDatagram ()
|
||||
{
|
||||
m_DatagramSocket.async_receive_from (
|
||||
boost::asio::buffer (m_DatagramReceiveBuffer, i2p::datagram::MAX_DATAGRAM_SIZE),
|
||||
m_SenderEndpoint,
|
||||
boost::bind (&SAMBridge::HandleReceivedDatagram, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
|
||||
}
|
||||
|
||||
void SAMBridge::HandleReceivedDatagram (const boost::system::error_code& ecode, std::size_t bytes_transferred)
|
||||
{
|
||||
if (!ecode)
|
||||
{
|
||||
m_DatagramReceiveBuffer[bytes_transferred] = 0;
|
||||
char * eol = strchr ((char *)m_DatagramReceiveBuffer, '\n');
|
||||
*eol = 0; eol++;
|
||||
size_t payloadLen = bytes_transferred - ((uint8_t *)eol - m_DatagramReceiveBuffer);
|
||||
LogPrint ("SAM datagram received ", m_DatagramReceiveBuffer," size=", payloadLen);
|
||||
char * sessionID = strchr ((char *)m_DatagramReceiveBuffer, ' ');
|
||||
if (sessionID)
|
||||
{
|
||||
sessionID++;
|
||||
char * destination = strchr (sessionID, ' ');
|
||||
if (destination)
|
||||
{
|
||||
*destination = 0; destination++;
|
||||
auto session = FindSession (sessionID);
|
||||
if (session)
|
||||
{
|
||||
uint8_t ident[1024];
|
||||
size_t l = i2p::data::Base64ToByteStream (destination, strlen(destination), ident, 1024);
|
||||
i2p::data::IdentityEx dest;
|
||||
dest.FromBuffer (ident, l);
|
||||
auto leaseSet = i2p::data::netdb.FindLeaseSet (dest.GetIdentHash ());
|
||||
if (leaseSet)
|
||||
session->localDestination->GetDatagramDestination ()->
|
||||
SendDatagramTo ((uint8_t *)eol, payloadLen, *leaseSet);
|
||||
else
|
||||
{
|
||||
LogPrint ("SAM datagram destination not found");
|
||||
i2p::data::netdb.RequestDestination (dest.GetIdentHash (), true,
|
||||
session->localDestination->GetTunnelPool ());
|
||||
}
|
||||
}
|
||||
else
|
||||
LogPrint ("Session ", sessionID, " not found");
|
||||
}
|
||||
else
|
||||
LogPrint ("Missing destination key");
|
||||
}
|
||||
else
|
||||
LogPrint ("Missing sessionID");
|
||||
ReceiveDatagram ();
|
||||
}
|
||||
else
|
||||
LogPrint ("SAM datagram receive error: ", ecode.message ());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
12
SAM.h
12
SAM.h
|
@ -11,6 +11,7 @@
|
|||
#include "Identity.h"
|
||||
#include "LeaseSet.h"
|
||||
#include "Streaming.h"
|
||||
#include "Destination.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
|
@ -46,6 +47,9 @@ namespace client
|
|||
const char SAM_PARAM_DESTINATION[] = "DESTINATION";
|
||||
const char SAM_PARAM_NAME[] = "NAME";
|
||||
const char SAM_VALUE_TRANSIENT[] = "TRANSIENT";
|
||||
const char SAM_VALUE_STREAM[] = "STREAM";
|
||||
const char SAM_VALUE_DATAGRAM[] = "DATAGRAM";
|
||||
const char SAM_VALUE_RAW[] = "RAW";
|
||||
const char SAM_VALUE_TRUE[] = "true";
|
||||
const char SAM_VALUE_FALSE[] = "false";
|
||||
|
||||
|
@ -115,7 +119,7 @@ namespace client
|
|||
|
||||
struct SAMSession
|
||||
{
|
||||
i2p::stream::StreamingDestination * localDestination;
|
||||
ClientDestination * localDestination;
|
||||
std::list<SAMSocket *> sockets;
|
||||
};
|
||||
|
||||
|
@ -141,15 +145,21 @@ namespace client
|
|||
void Accept ();
|
||||
void HandleAccept(const boost::system::error_code& ecode);
|
||||
|
||||
void ReceiveDatagram ();
|
||||
void HandleReceivedDatagram (const boost::system::error_code& ecode, std::size_t bytes_transferred);
|
||||
|
||||
private:
|
||||
|
||||
bool m_IsRunning;
|
||||
std::thread * m_Thread;
|
||||
boost::asio::io_service m_Service;
|
||||
boost::asio::ip::tcp::acceptor m_Acceptor;
|
||||
boost::asio::ip::udp::endpoint m_DatagramEndpoint, m_SenderEndpoint;
|
||||
boost::asio::ip::udp::socket m_DatagramSocket;
|
||||
SAMSocket * m_NewSocket;
|
||||
std::mutex m_SessionsMutex;
|
||||
std::map<std::string, SAMSession> m_Sessions;
|
||||
uint8_t m_DatagramReceiveBuffer[i2p::datagram::MAX_DATAGRAM_SIZE+1];
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -224,7 +224,7 @@ namespace proxy
|
|||
void SOCKS4AHandler::SentConnectionSuccess(const boost::system::error_code & ecode)
|
||||
{
|
||||
LogPrint("--- socks4a making connection");
|
||||
m_stream = i2p::client::context.GetSharedLocalDestination ()->CreateNewOutgoingStream(*m_ls);
|
||||
m_stream = i2p::client::context.GetSharedLocalDestination ()->CreateStream(*m_ls);
|
||||
m_state = OKAY;
|
||||
LogPrint("--- socks4a state is ", m_state);
|
||||
AsyncSockRead();
|
||||
|
|
40
SSU.cpp
40
SSU.cpp
|
@ -12,13 +12,13 @@
|
|||
|
||||
namespace i2p
|
||||
{
|
||||
namespace ssu
|
||||
namespace transport
|
||||
{
|
||||
|
||||
SSUSession::SSUSession (SSUServer& server, boost::asio::ip::udp::endpoint& remoteEndpoint,
|
||||
const i2p::data::RouterInfo * router, bool peerTest ):
|
||||
m_Server (server), m_RemoteEndpoint (remoteEndpoint), m_RemoteRouter (router),
|
||||
m_Timer (m_Server.GetService ()), m_DHKeysPair (nullptr), m_PeerTest (peerTest),
|
||||
const i2p::data::RouterInfo * router, bool peerTest ): TransportSession (router),
|
||||
m_Server (server), m_RemoteEndpoint (remoteEndpoint),
|
||||
m_Timer (m_Server.GetService ()), m_PeerTest (peerTest),
|
||||
m_State (eSessionStateUnknown), m_IsSessionKey (false), m_RelayTag (0),
|
||||
m_Data (*this), m_NumSentBytes (0), m_NumReceivedBytes (0)
|
||||
{
|
||||
|
@ -29,7 +29,6 @@ namespace ssu
|
|||
|
||||
SSUSession::~SSUSession ()
|
||||
{
|
||||
delete m_DHKeysPair;
|
||||
}
|
||||
|
||||
void SSUSession::CreateAESandMacKey (const uint8_t * pubKey)
|
||||
|
@ -174,7 +173,7 @@ namespace ssu
|
|||
LogPrint ("Session request received");
|
||||
m_RemoteEndpoint = senderEndpoint;
|
||||
if (!m_DHKeysPair)
|
||||
m_DHKeysPair = i2p::transports.GetNextDHKeysPair ();
|
||||
m_DHKeysPair = transports.GetNextDHKeysPair ();
|
||||
CreateAESandMacKey (buf + sizeof (SSUHeader));
|
||||
SendSessionCreated (buf + sizeof (SSUHeader));
|
||||
}
|
||||
|
@ -215,10 +214,7 @@ namespace ssu
|
|||
m_SessionKeyDecryption.SetIV (((SSUHeader *)buf)->iv);
|
||||
m_SessionKeyDecryption.Decrypt (payload, 48, payload);
|
||||
// verify
|
||||
CryptoPP::DSA::PublicKey pubKey;
|
||||
pubKey.Initialize (i2p::crypto::dsap, i2p::crypto::dsaq, i2p::crypto::dsag, CryptoPP::Integer (m_RemoteRouter->GetRouterIdentity ().signingKey, 128));
|
||||
CryptoPP::DSA::Verifier verifier (pubKey);
|
||||
if (!verifier.VerifyMessage (signedData, 532, payload, 40))
|
||||
if (!m_RemoteIdentity.Verify (signedData, 532, payload))
|
||||
LogPrint ("SSU signature verification failed");
|
||||
|
||||
SendSessionConfirmed (y, ourAddress);
|
||||
|
@ -231,17 +227,15 @@ namespace ssu
|
|||
payload++; // identity fragment info
|
||||
uint16_t identitySize = be16toh (*(uint16_t *)payload);
|
||||
payload += 2; // size of identity fragment
|
||||
if (identitySize == i2p::data::DEFAULT_IDENTITY_SIZE)
|
||||
{
|
||||
i2p::data::Identity ident;
|
||||
ident.FromBuffer (payload, identitySize);
|
||||
m_RemoteIdent = ident.Hash ();
|
||||
m_Data.UpdatePacketSize (m_RemoteIdent);
|
||||
}
|
||||
else
|
||||
LogPrint ("SSU unexpected identity size ", identitySize);
|
||||
m_RemoteIdentity.FromBuffer (payload, identitySize);
|
||||
m_Data.UpdatePacketSize (m_RemoteIdentity.GetIdentHash ());
|
||||
payload += identitySize; // identity
|
||||
// TODO: verify signature
|
||||
payload += 4; // signed-on time
|
||||
size_t paddingSize = (payload - buf) + m_RemoteIdentity.GetSignatureLen ();
|
||||
paddingSize >>= 4; // %16
|
||||
if (paddingSize > 0) paddingSize = 16 - paddingSize;
|
||||
payload += paddingSize;
|
||||
// TODO: verify signature (need data from session request), payload points to signature
|
||||
SendI2NPMessage (CreateDeliveryStatusMsg (0));
|
||||
Established ();
|
||||
}
|
||||
|
@ -360,10 +354,10 @@ namespace ssu
|
|||
uint8_t * payload = buf + sizeof (SSUHeader);
|
||||
*payload = 1; // 1 fragment
|
||||
payload++; // info
|
||||
size_t identLen = sizeof (i2p::context.GetRouterIdentity ()); // 387 bytes
|
||||
size_t identLen = i2p::data::DEFAULT_IDENTITY_SIZE; // 387 bytes
|
||||
*(uint16_t *)(payload) = htobe16 (identLen);
|
||||
payload += 2; // cursize
|
||||
memcpy (payload, (uint8_t *)&i2p::context.GetRouterIdentity (), identLen);
|
||||
memcpy (payload, (uint8_t *)&i2p::context.GetIdentity ().GetStandardIdentity (), identLen); // TODO
|
||||
payload += identLen;
|
||||
uint32_t signedOnTime = i2p::util::GetSecondsSinceEpoch ();
|
||||
*(uint32_t *)(payload) = htobe32 (signedOnTime); // signed on time
|
||||
|
@ -609,7 +603,7 @@ namespace ssu
|
|||
{
|
||||
// set connect timer
|
||||
ScheduleConnectTimer ();
|
||||
m_DHKeysPair = i2p::transports.GetNextDHKeysPair ();
|
||||
m_DHKeysPair = transports.GetNextDHKeysPair ();
|
||||
SendSessionRequest ();
|
||||
}
|
||||
}
|
||||
|
|
9
SSU.h
9
SSU.h
|
@ -13,11 +13,12 @@
|
|||
#include "Identity.h"
|
||||
#include "RouterInfo.h"
|
||||
#include "I2NPProtocol.h"
|
||||
#include "TransportSession.h"
|
||||
#include "SSUData.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace ssu
|
||||
namespace transport
|
||||
{
|
||||
#pragma pack(1)
|
||||
struct SSUHeader
|
||||
|
@ -57,7 +58,7 @@ namespace ssu
|
|||
};
|
||||
|
||||
class SSUServer;
|
||||
class SSUSession
|
||||
class SSUSession: public TransportSession
|
||||
{
|
||||
public:
|
||||
|
||||
|
@ -71,7 +72,6 @@ namespace ssu
|
|||
void WaitForIntroduction ();
|
||||
void Close ();
|
||||
boost::asio::ip::udp::endpoint& GetRemoteEndpoint () { return m_RemoteEndpoint; };
|
||||
const i2p::data::RouterInfo * GetRemoteRouter () const { return m_RemoteRouter; };
|
||||
void SendI2NPMessage (I2NPMessage * msg);
|
||||
void SendPeerTest (); // Alice
|
||||
|
||||
|
@ -128,10 +128,7 @@ namespace ssu
|
|||
friend class SSUData; // TODO: change in later
|
||||
SSUServer& m_Server;
|
||||
boost::asio::ip::udp::endpoint m_RemoteEndpoint;
|
||||
const i2p::data::RouterInfo * m_RemoteRouter;
|
||||
i2p::data::IdentHash m_RemoteIdent; // if m_RemoteRouter is null
|
||||
boost::asio::deadline_timer m_Timer;
|
||||
i2p::data::DHKeysPair * m_DHKeysPair; // X - for client and Y - for server
|
||||
bool m_PeerTest;
|
||||
SessionState m_State;
|
||||
bool m_IsSessionKey;
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
namespace i2p
|
||||
{
|
||||
namespace ssu
|
||||
namespace transport
|
||||
{
|
||||
SSUData::SSUData (SSUSession& session):
|
||||
m_Session (session), m_ResendTimer (session.m_Server.GetService ())
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
|
||||
namespace i2p
|
||||
{
|
||||
namespace ssu
|
||||
namespace transport
|
||||
{
|
||||
|
||||
const size_t SSU_MTU = 1484;
|
||||
|
|
161
Streaming.cpp
161
Streaming.cpp
|
@ -1,3 +1,4 @@
|
|||
#include <cryptopp/gzip.h>
|
||||
#include "Log.h"
|
||||
#include "RouterInfo.h"
|
||||
#include "RouterContext.h"
|
||||
|
@ -11,12 +12,12 @@ namespace i2p
|
|||
namespace stream
|
||||
{
|
||||
Stream::Stream (boost::asio::io_service& service, StreamingDestination& local,
|
||||
const i2p::data::LeaseSet& remote): m_Service (service), m_SendStreamID (0),
|
||||
const i2p::data::LeaseSet& remote, int port): m_Service (service), m_SendStreamID (0),
|
||||
m_SequenceNumber (0), m_LastReceivedSequenceNumber (-1), m_IsOpen (false),
|
||||
m_IsReset (false), m_IsAckSendScheduled (false), m_LocalDestination (local),
|
||||
m_RemoteLeaseSet (&remote), m_RoutingSession (nullptr), m_ReceiveTimer (m_Service),
|
||||
m_ResendTimer (m_Service), m_AckSendTimer (m_Service), m_NumSentBytes (0),
|
||||
m_NumReceivedBytes (0)
|
||||
m_NumReceivedBytes (0), m_Port (port)
|
||||
{
|
||||
m_RecvStreamID = i2p::context.GetRandomNumberGenerator ().GenerateWord32 ();
|
||||
UpdateCurrentRemoteLease ();
|
||||
|
@ -27,7 +28,7 @@ namespace stream
|
|||
m_IsOpen (false), m_IsReset (false), m_IsAckSendScheduled (false), m_LocalDestination (local),
|
||||
m_RemoteLeaseSet (nullptr), m_RoutingSession (nullptr), m_ReceiveTimer (m_Service),
|
||||
m_ResendTimer (m_Service), m_AckSendTimer (m_Service), m_NumSentBytes (0),
|
||||
m_NumReceivedBytes (0)
|
||||
m_NumReceivedBytes (0), m_Port (0)
|
||||
{
|
||||
m_RecvStreamID = i2p::context.GetRandomNumberGenerator ().GenerateWord32 ();
|
||||
}
|
||||
|
@ -115,7 +116,7 @@ namespace stream
|
|||
{
|
||||
// we have received duplicate. Most likely our outbound tunnel is dead
|
||||
LogPrint ("Duplicate message ", receivedSeqn, " received");
|
||||
m_LocalDestination.ResetCurrentOutboundTunnel (); // pick another outbound tunnel
|
||||
m_LocalDestination.GetOwner ().ResetCurrentOutboundTunnel (); // pick another outbound tunnel
|
||||
UpdateCurrentRemoteLease (); // pick another lease
|
||||
SendQuickAck (); // resend ack for previous message again
|
||||
delete packet; // packet dropped
|
||||
|
@ -274,11 +275,11 @@ namespace stream
|
|||
if (isNoAck) flags |= PACKET_FLAG_NO_ACK;
|
||||
*(uint16_t *)(packet + size) = htobe16 (flags);
|
||||
size += 2; // flags
|
||||
size_t identityLen = m_LocalDestination.GetIdentity ().GetFullLen ();
|
||||
size_t signatureLen = m_LocalDestination.GetIdentity ().GetSignatureLen ();
|
||||
size_t identityLen = m_LocalDestination.GetOwner ().GetIdentity ().GetFullLen ();
|
||||
size_t signatureLen = m_LocalDestination.GetOwner ().GetIdentity ().GetSignatureLen ();
|
||||
*(uint16_t *)(packet + size) = htobe16 (identityLen + signatureLen + 2); // identity + signature + packet size
|
||||
size += 2; // options size
|
||||
m_LocalDestination.GetIdentity ().ToBuffer (packet + size, identityLen);
|
||||
m_LocalDestination.GetOwner ().GetIdentity ().ToBuffer (packet + size, identityLen);
|
||||
size += identityLen; // from
|
||||
*(uint16_t *)(packet + size) = htobe16 (STREAMING_MTU);
|
||||
size += 2; // max packet size
|
||||
|
@ -291,7 +292,7 @@ namespace stream
|
|||
buf += sentLen;
|
||||
len -= sentLen;
|
||||
size += sentLen; // payload
|
||||
m_LocalDestination.Sign (packet, size, signature);
|
||||
m_LocalDestination.GetOwner ().Sign (packet, size, signature);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -362,13 +363,13 @@ namespace stream
|
|||
size++; // resend delay
|
||||
*(uint16_t *)(packet + size) = htobe16 (PACKET_FLAG_CLOSE | PACKET_FLAG_SIGNATURE_INCLUDED);
|
||||
size += 2; // flags
|
||||
size_t signatureLen = m_LocalDestination.GetIdentity ().GetSignatureLen ();
|
||||
size_t signatureLen = m_LocalDestination.GetOwner ().GetIdentity ().GetSignatureLen ();
|
||||
*(uint16_t *)(packet + size) = htobe16 (signatureLen); // signature only
|
||||
size += 2; // options size
|
||||
uint8_t * signature = packet + size;
|
||||
memset (packet + size, 0, signatureLen);
|
||||
size += signatureLen; // signature
|
||||
m_LocalDestination.Sign (packet, size, signature);
|
||||
m_LocalDestination.GetOwner ().Sign (packet, size, signature);
|
||||
|
||||
p->len = size;
|
||||
SendPacket (p);
|
||||
|
@ -440,8 +441,7 @@ namespace stream
|
|||
std::vector<i2p::tunnel::TunnelMessageBlock> msgs;
|
||||
for (auto it: packets)
|
||||
{
|
||||
auto msg = m_RoutingSession->WrapSingleMessage (
|
||||
m_LocalDestination.CreateDataMessage (it->GetBuffer (), it->GetLength ()));
|
||||
auto msg = m_RoutingSession->WrapSingleMessage (CreateDataMessage (it->GetBuffer (), it->GetLength ()));
|
||||
msgs.push_back (i2p::tunnel::TunnelMessageBlock
|
||||
{
|
||||
i2p::tunnel::eDeliveryTypeTunnel,
|
||||
|
@ -450,7 +450,7 @@ namespace stream
|
|||
});
|
||||
m_NumSentBytes += it->GetLength ();
|
||||
}
|
||||
m_LocalDestination.SendTunnelDataMsgs (msgs);
|
||||
m_LocalDestination.GetOwner ().SendTunnelDataMsgs (msgs);
|
||||
}
|
||||
else
|
||||
LogPrint ("All leases are expired");
|
||||
|
@ -484,7 +484,7 @@ namespace stream
|
|||
}
|
||||
if (packets.size () > 0)
|
||||
{
|
||||
m_LocalDestination.ResetCurrentOutboundTunnel (); // pick another outbound tunnel
|
||||
m_LocalDestination.GetOwner ().ResetCurrentOutboundTunnel (); // pick another outbound tunnel
|
||||
UpdateCurrentRemoteLease (); // pick another lease
|
||||
SendPackets (packets);
|
||||
}
|
||||
|
@ -506,14 +506,14 @@ namespace stream
|
|||
{
|
||||
if (!m_RemoteLeaseSet)
|
||||
{
|
||||
m_RemoteLeaseSet = m_LocalDestination.FindLeaseSet (m_RemoteIdentity.GetIdentHash ());
|
||||
m_RemoteLeaseSet = m_LocalDestination.GetOwner ().FindLeaseSet (m_RemoteIdentity.GetIdentHash ());
|
||||
if (!m_RemoteLeaseSet)
|
||||
LogPrint ("LeaseSet ", m_RemoteIdentity.GetIdentHash ().ToBase64 (), " not found");
|
||||
}
|
||||
if (m_RemoteLeaseSet)
|
||||
{
|
||||
if (!m_RoutingSession)
|
||||
m_RoutingSession = m_LocalDestination.GetRoutingSession (*m_RemoteLeaseSet, 32);
|
||||
m_RoutingSession = m_LocalDestination.GetOwner ().GetRoutingSession (*m_RemoteLeaseSet, 32);
|
||||
auto leases = m_RemoteLeaseSet->GetNonExpiredLeases ();
|
||||
if (!leases.empty ())
|
||||
{
|
||||
|
@ -522,12 +522,139 @@ namespace stream
|
|||
}
|
||||
else
|
||||
{
|
||||
m_RemoteLeaseSet = m_LocalDestination.FindLeaseSet (m_RemoteIdentity.GetIdentHash ()); // re-request expired
|
||||
m_RemoteLeaseSet = m_LocalDestination.GetOwner ().FindLeaseSet (m_RemoteIdentity.GetIdentHash ()); // re-request expired
|
||||
m_CurrentRemoteLease.endDate = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
m_CurrentRemoteLease.endDate = 0;
|
||||
}
|
||||
|
||||
I2NPMessage * Stream::CreateDataMessage (const uint8_t * payload, size_t len)
|
||||
{
|
||||
I2NPMessage * msg = NewI2NPShortMessage ();
|
||||
CryptoPP::Gzip compressor;
|
||||
if (len <= i2p::stream::COMPRESSION_THRESHOLD_SIZE)
|
||||
compressor.SetDeflateLevel (CryptoPP::Gzip::MIN_DEFLATE_LEVEL);
|
||||
else
|
||||
compressor.SetDeflateLevel (CryptoPP::Gzip::DEFAULT_DEFLATE_LEVEL);
|
||||
compressor.Put (payload, len);
|
||||
compressor.MessageEnd();
|
||||
int size = compressor.MaxRetrievable ();
|
||||
uint8_t * buf = msg->GetPayload ();
|
||||
*(uint32_t *)buf = htobe32 (size); // length
|
||||
buf += 4;
|
||||
compressor.Get (buf, size);
|
||||
*(uint16_t *)(buf + 4) = 0; // source port
|
||||
*(uint16_t *)(buf + 6) = htobe16 (m_Port); // destination port
|
||||
buf[9] = i2p::client::PROTOCOL_TYPE_STREAMING; // streaming protocol
|
||||
msg->len += size + 4;
|
||||
FillI2NPMessageHeader (msg, eI2NPData);
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
||||
void StreamingDestination::Start ()
|
||||
{
|
||||
}
|
||||
|
||||
void StreamingDestination::Stop ()
|
||||
{
|
||||
ResetAcceptor ();
|
||||
{
|
||||
std::unique_lock<std::mutex> l(m_StreamsMutex);
|
||||
for (auto it: m_Streams)
|
||||
delete it.second;
|
||||
m_Streams.clear ();
|
||||
}
|
||||
}
|
||||
|
||||
void StreamingDestination::HandleNextPacket (Packet * packet)
|
||||
{
|
||||
uint32_t sendStreamID = packet->GetSendStreamID ();
|
||||
if (sendStreamID)
|
||||
{
|
||||
auto it = m_Streams.find (sendStreamID);
|
||||
if (it != m_Streams.end ())
|
||||
it->second->HandleNextPacket (packet);
|
||||
else
|
||||
{
|
||||
LogPrint ("Unknown stream ", sendStreamID);
|
||||
delete packet;
|
||||
}
|
||||
}
|
||||
else // new incoming stream
|
||||
{
|
||||
auto incomingStream = CreateNewIncomingStream ();
|
||||
incomingStream->HandleNextPacket (packet);
|
||||
if (m_Acceptor != nullptr)
|
||||
m_Acceptor (incomingStream);
|
||||
else
|
||||
{
|
||||
LogPrint ("Acceptor for incoming stream is not set");
|
||||
DeleteStream (incomingStream);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Stream * StreamingDestination::CreateNewOutgoingStream (const i2p::data::LeaseSet& remote, int port)
|
||||
{
|
||||
Stream * s = new Stream (*m_Owner.GetService (), *this, remote, port);
|
||||
std::unique_lock<std::mutex> l(m_StreamsMutex);
|
||||
m_Streams[s->GetRecvStreamID ()] = s;
|
||||
return s;
|
||||
}
|
||||
|
||||
Stream * StreamingDestination::CreateNewIncomingStream ()
|
||||
{
|
||||
Stream * s = new Stream (*m_Owner.GetService (), *this);
|
||||
std::unique_lock<std::mutex> l(m_StreamsMutex);
|
||||
m_Streams[s->GetRecvStreamID ()] = s;
|
||||
return s;
|
||||
}
|
||||
|
||||
void StreamingDestination::DeleteStream (Stream * stream)
|
||||
{
|
||||
if (stream)
|
||||
{
|
||||
std::unique_lock<std::mutex> l(m_StreamsMutex);
|
||||
auto it = m_Streams.find (stream->GetRecvStreamID ());
|
||||
if (it != m_Streams.end ())
|
||||
{
|
||||
m_Streams.erase (it);
|
||||
if (m_Owner.GetService ())
|
||||
m_Owner.GetService ()->post ([stream](void) { delete stream; });
|
||||
else
|
||||
delete stream;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void StreamingDestination::HandleDataMessagePayload (const uint8_t * buf, size_t len)
|
||||
{
|
||||
// unzip it
|
||||
CryptoPP::Gunzip decompressor;
|
||||
decompressor.Put (buf, len);
|
||||
decompressor.MessageEnd();
|
||||
Packet * uncompressed = new Packet;
|
||||
uncompressed->offset = 0;
|
||||
uncompressed->len = decompressor.MaxRetrievable ();
|
||||
if (uncompressed->len <= MAX_PACKET_SIZE)
|
||||
{
|
||||
decompressor.Get (uncompressed->buf, uncompressed->len);
|
||||
HandleNextPacket (uncompressed);
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrint ("Received packet size ", uncompressed->len, " exceeds max packet size. Skipped");
|
||||
delete uncompressed;
|
||||
}
|
||||
}
|
||||
|
||||
void DeleteStream (Stream * stream)
|
||||
{
|
||||
if (stream)
|
||||
stream->GetLocalDestination ().DeleteStream (stream);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
49
Streaming.h
49
Streaming.h
|
@ -18,6 +18,10 @@
|
|||
|
||||
namespace i2p
|
||||
{
|
||||
namespace client
|
||||
{
|
||||
class ClientDestination;
|
||||
}
|
||||
namespace stream
|
||||
{
|
||||
const uint16_t PACKET_FLAG_SYNCHRONIZE = 0x0001;
|
||||
|
@ -78,7 +82,8 @@ namespace stream
|
|||
{
|
||||
public:
|
||||
|
||||
Stream (boost::asio::io_service& service, StreamingDestination& local, const i2p::data::LeaseSet& remote); // outgoing
|
||||
Stream (boost::asio::io_service& service, StreamingDestination& local,
|
||||
const i2p::data::LeaseSet& remote, int port = 0); // outgoing
|
||||
Stream (boost::asio::io_service& service, StreamingDestination& local); // incoming
|
||||
|
||||
~Stream ();
|
||||
|
@ -123,6 +128,8 @@ namespace stream
|
|||
void HandleResendTimer (const boost::system::error_code& ecode);
|
||||
void HandleAckSendTimer (const boost::system::error_code& ecode);
|
||||
|
||||
I2NPMessage * CreateDataMessage (const uint8_t * payload, size_t len);
|
||||
|
||||
private:
|
||||
|
||||
boost::asio::io_service& m_Service;
|
||||
|
@ -139,8 +146,48 @@ namespace stream
|
|||
std::set<Packet *, PacketCmp> m_SentPackets;
|
||||
boost::asio::deadline_timer m_ReceiveTimer, m_ResendTimer, m_AckSendTimer;
|
||||
size_t m_NumSentBytes, m_NumReceivedBytes;
|
||||
uint16_t m_Port;
|
||||
};
|
||||
|
||||
class StreamingDestination
|
||||
{
|
||||
public:
|
||||
|
||||
StreamingDestination (i2p::client::ClientDestination& owner): m_Owner (owner) {};
|
||||
~StreamingDestination () {};
|
||||
|
||||
void Start ();
|
||||
void Stop ();
|
||||
|
||||
Stream * CreateNewOutgoingStream (const i2p::data::LeaseSet& remote, int port = 0);
|
||||
void DeleteStream (Stream * stream);
|
||||
void SetAcceptor (const std::function<void (Stream *)>& acceptor) { m_Acceptor = acceptor; };
|
||||
void ResetAcceptor () { m_Acceptor = nullptr; };
|
||||
bool IsAcceptorSet () const { return m_Acceptor != nullptr; };
|
||||
i2p::client::ClientDestination& GetOwner () { return m_Owner; };
|
||||
|
||||
void HandleDataMessagePayload (const uint8_t * buf, size_t len);
|
||||
|
||||
private:
|
||||
|
||||
void HandleNextPacket (Packet * packet);
|
||||
Stream * CreateNewIncomingStream ();
|
||||
|
||||
private:
|
||||
|
||||
i2p::client::ClientDestination& m_Owner;
|
||||
std::mutex m_StreamsMutex;
|
||||
std::map<uint32_t, Stream *> m_Streams;
|
||||
std::function<void (Stream *)> m_Acceptor;
|
||||
|
||||
public:
|
||||
|
||||
// for HTTP only
|
||||
const decltype(m_Streams)& GetStreams () const { return m_Streams; };
|
||||
};
|
||||
|
||||
void DeleteStream (Stream * stream);
|
||||
|
||||
//-------------------------------------------------
|
||||
|
||||
template<typename Buffer, typename ReceiveHandler>
|
||||
|
|
|
@ -34,7 +34,7 @@ namespace tunnel
|
|||
*(uint32_t *)(tunnelMsg->GetPayload ()) = htobe32 (m_NextTunnelID);
|
||||
FillI2NPMessageHeader (tunnelMsg, eI2NPTunnelData);
|
||||
|
||||
i2p::transports.SendMessage (m_NextIdent, tunnelMsg);
|
||||
i2p::transport::transports.SendMessage (m_NextIdent, tunnelMsg);
|
||||
}
|
||||
|
||||
void TransitTunnel::SendTunnelDataMsg (i2p::I2NPMessage * msg)
|
||||
|
|
43
TransportSession.h
Normal file
43
TransportSession.h
Normal file
|
@ -0,0 +1,43 @@
|
|||
#ifndef TRANSPORT_SESSION_H__
|
||||
#define TRANSPORT_SESSION_H__
|
||||
|
||||
#include <inttypes.h>
|
||||
#include "Identity.h"
|
||||
#include "RouterInfo.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace transport
|
||||
{
|
||||
struct DHKeysPair // transient keys for transport sessions
|
||||
{
|
||||
uint8_t publicKey[256];
|
||||
uint8_t privateKey[256];
|
||||
};
|
||||
|
||||
class TransportSession
|
||||
{
|
||||
public:
|
||||
|
||||
TransportSession (const i2p::data::RouterInfo * in_RemoteRouter):
|
||||
m_RemoteRouter (in_RemoteRouter), m_DHKeysPair (nullptr)
|
||||
{
|
||||
if (m_RemoteRouter)
|
||||
m_RemoteIdentity = m_RemoteRouter->GetRouterIdentity ();
|
||||
}
|
||||
|
||||
virtual ~TransportSession () { delete m_DHKeysPair; };
|
||||
|
||||
const i2p::data::RouterInfo * GetRemoteRouter () { return m_RemoteRouter; };
|
||||
const i2p::data::IdentityEx& GetRemoteIdentity () { return m_RemoteIdentity; };
|
||||
|
||||
protected:
|
||||
|
||||
const i2p::data::RouterInfo * m_RemoteRouter;
|
||||
i2p::data::IdentityEx m_RemoteIdentity;
|
||||
DHKeysPair * m_DHKeysPair; // X - for client and Y - for server
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,5 +1,7 @@
|
|||
#include <cryptopp/dh.h>
|
||||
#include <boost/bind.hpp>
|
||||
#include "Log.h"
|
||||
#include "CryptoConst.h"
|
||||
#include "RouterContext.h"
|
||||
#include "I2NPProtocol.h"
|
||||
#include "NetDb.h"
|
||||
|
@ -9,6 +11,13 @@ using namespace i2p::data;
|
|||
|
||||
namespace i2p
|
||||
{
|
||||
namespace transport
|
||||
{
|
||||
DHKeysPairSupplier::DHKeysPairSupplier (int size):
|
||||
m_QueueSize (size), m_IsRunning (false), m_Thread (nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
DHKeysPairSupplier::~DHKeysPairSupplier ()
|
||||
{
|
||||
Stop ();
|
||||
|
@ -48,17 +57,18 @@ namespace i2p
|
|||
{
|
||||
if (num > 0)
|
||||
{
|
||||
CryptoPP::DH dh (i2p::crypto::elgp, i2p::crypto::elgg);
|
||||
for (int i = 0; i < num; i++)
|
||||
{
|
||||
i2p::data::DHKeysPair * pair = new i2p::data::DHKeysPair ();
|
||||
i2p::data::CreateRandomDHKeysPair (pair);
|
||||
i2p::transport::DHKeysPair * pair = new i2p::transport::DHKeysPair ();
|
||||
dh.GenerateKeyPair(m_Rnd, pair->privateKey, pair->publicKey);
|
||||
std::unique_lock<std::mutex> l(m_AcquiredMutex);
|
||||
m_Queue.push (pair);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
i2p::data::DHKeysPair * DHKeysPairSupplier::Acquire ()
|
||||
DHKeysPair * DHKeysPairSupplier::Acquire ()
|
||||
{
|
||||
if (!m_Queue.empty ())
|
||||
{
|
||||
|
@ -70,13 +80,14 @@ namespace i2p
|
|||
}
|
||||
else // queue is empty, create new
|
||||
{
|
||||
i2p::data::DHKeysPair * pair = new i2p::data::DHKeysPair ();
|
||||
i2p::data::CreateRandomDHKeysPair (pair);
|
||||
DHKeysPair * pair = new DHKeysPair ();
|
||||
CryptoPP::DH dh (i2p::crypto::elgp, i2p::crypto::elgg);
|
||||
dh.GenerateKeyPair(m_Rnd, pair->privateKey, pair->publicKey);
|
||||
return pair;
|
||||
}
|
||||
}
|
||||
|
||||
void DHKeysPairSupplier::Return (i2p::data::DHKeysPair * pair)
|
||||
void DHKeysPairSupplier::Return (DHKeysPair * pair)
|
||||
{
|
||||
std::unique_lock<std::mutex> l(m_AcquiredMutex);
|
||||
m_Queue.push (pair);
|
||||
|
@ -85,7 +96,7 @@ namespace i2p
|
|||
Transports transports;
|
||||
|
||||
Transports::Transports ():
|
||||
m_Thread (nullptr), m_Work (m_Service), m_NTCPAcceptor (nullptr),
|
||||
m_Thread (nullptr), m_Work (m_Service), m_NTCPAcceptor (nullptr), m_NTCPV6Acceptor (nullptr),
|
||||
m_SSUServer (nullptr), m_DHKeysPairSupplier (5) // 5 pre-generated keys
|
||||
{
|
||||
}
|
||||
|
@ -110,15 +121,26 @@ namespace i2p
|
|||
boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), address.port));
|
||||
|
||||
LogPrint ("Start listening TCP port ", address.port);
|
||||
auto conn = new i2p::ntcp::NTCPServerConnection (m_Service);
|
||||
auto conn = new NTCPServerConnection (m_Service);
|
||||
m_NTCPAcceptor->async_accept(conn->GetSocket (), boost::bind (&Transports::HandleAccept, this,
|
||||
conn, boost::asio::placeholders::error));
|
||||
|
||||
if (context.SupportsV6 ())
|
||||
{
|
||||
m_NTCPV6Acceptor = new boost::asio::ip::tcp::acceptor (m_Service,
|
||||
boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v6(), address.port));
|
||||
|
||||
LogPrint ("Start listening V6 TCP port ", address.port);
|
||||
auto conn = new NTCPServerConnection (m_Service);
|
||||
m_NTCPV6Acceptor->async_accept(conn->GetSocket (), boost::bind (&Transports::HandleAcceptV6,
|
||||
this, conn, boost::asio::placeholders::error));
|
||||
}
|
||||
}
|
||||
else if (address.transportStyle == RouterInfo::eTransportSSU)
|
||||
{
|
||||
if (!m_SSUServer)
|
||||
{
|
||||
m_SSUServer = new i2p::ssu::SSUServer (address.port);
|
||||
m_SSUServer = new SSUServer (address.port);
|
||||
LogPrint ("Start listening UDP port ", address.port);
|
||||
m_SSUServer->Start ();
|
||||
DetectExternalIP ();
|
||||
|
@ -143,6 +165,8 @@ namespace i2p
|
|||
m_NTCPSessions.clear ();
|
||||
delete m_NTCPAcceptor;
|
||||
m_NTCPAcceptor = nullptr;
|
||||
delete m_NTCPV6Acceptor;
|
||||
m_NTCPV6Acceptor = nullptr;
|
||||
|
||||
m_DHKeysPairSupplier.Stop ();
|
||||
m_IsRunning = false;
|
||||
|
@ -170,19 +194,19 @@ namespace i2p
|
|||
}
|
||||
}
|
||||
|
||||
void Transports::AddNTCPSession (i2p::ntcp::NTCPSession * session)
|
||||
void Transports::AddNTCPSession (NTCPSession * session)
|
||||
{
|
||||
if (session)
|
||||
m_NTCPSessions[session->GetRemoteRouterInfo ().GetIdentHash ()] = session;
|
||||
m_NTCPSessions[session->GetRemoteIdentity ().GetIdentHash ()] = session;
|
||||
}
|
||||
|
||||
void Transports::RemoveNTCPSession (i2p::ntcp::NTCPSession * session)
|
||||
void Transports::RemoveNTCPSession (NTCPSession * session)
|
||||
{
|
||||
if (session)
|
||||
m_NTCPSessions.erase (session->GetRemoteRouterInfo ().GetIdentHash ());
|
||||
m_NTCPSessions.erase (session->GetRemoteIdentity ().GetIdentHash ());
|
||||
}
|
||||
|
||||
void Transports::HandleAccept (i2p::ntcp::NTCPServerConnection * conn, const boost::system::error_code& error)
|
||||
void Transports::HandleAccept (NTCPServerConnection * conn, const boost::system::error_code& error)
|
||||
{
|
||||
if (!error)
|
||||
{
|
||||
|
@ -194,13 +218,31 @@ namespace i2p
|
|||
|
||||
if (error != boost::asio::error::operation_aborted)
|
||||
{
|
||||
conn = new i2p::ntcp::NTCPServerConnection (m_Service);
|
||||
conn = new NTCPServerConnection (m_Service);
|
||||
m_NTCPAcceptor->async_accept(conn->GetSocket (), boost::bind (&Transports::HandleAccept, this,
|
||||
conn, boost::asio::placeholders::error));
|
||||
}
|
||||
}
|
||||
|
||||
i2p::ntcp::NTCPSession * Transports::GetNextNTCPSession ()
|
||||
void Transports::HandleAcceptV6 (NTCPServerConnection * conn, const boost::system::error_code& error)
|
||||
{
|
||||
if (!error)
|
||||
{
|
||||
LogPrint ("Connected from ", conn->GetSocket ().remote_endpoint().address ().to_string ());
|
||||
conn->ServerLogin ();
|
||||
}
|
||||
else
|
||||
delete conn;
|
||||
|
||||
if (error != boost::asio::error::operation_aborted)
|
||||
{
|
||||
conn = new NTCPServerConnection (m_Service);
|
||||
m_NTCPV6Acceptor->async_accept(conn->GetSocket (), boost::bind (&Transports::HandleAcceptV6, this,
|
||||
conn, boost::asio::placeholders::error));
|
||||
}
|
||||
}
|
||||
|
||||
NTCPSession * Transports::GetNextNTCPSession ()
|
||||
{
|
||||
for (auto session: m_NTCPSessions)
|
||||
if (session.second->IsEstablished ())
|
||||
|
@ -208,7 +250,7 @@ namespace i2p
|
|||
return 0;
|
||||
}
|
||||
|
||||
i2p::ntcp::NTCPSession * Transports::FindNTCPSession (const i2p::data::IdentHash& ident)
|
||||
NTCPSession * Transports::FindNTCPSession (const i2p::data::IdentHash& ident)
|
||||
{
|
||||
auto it = m_NTCPSessions.find (ident);
|
||||
if (it != m_NTCPSessions.end ())
|
||||
|
@ -242,10 +284,10 @@ namespace i2p
|
|||
{
|
||||
// existing session not found. create new
|
||||
// try NTCP first if message size < 16K
|
||||
auto address = r->GetNTCPAddress ();
|
||||
if (address && !r->UsesIntroducer () && !r->IsUnreachable () && msg->GetLength () < i2p::ntcp::NTCP_MAX_MESSAGE_SIZE)
|
||||
auto address = r->GetNTCPAddress (!context.SupportsV6 ());
|
||||
if (address && !r->UsesIntroducer () && !r->IsUnreachable () && msg->GetLength () < NTCP_MAX_MESSAGE_SIZE)
|
||||
{
|
||||
auto s = new i2p::ntcp::NTCPClient (m_Service, address->host, address->port, *r);
|
||||
auto s = new NTCPClient (m_Service, address->host, address->port, *r);
|
||||
AddNTCPSession (s);
|
||||
s->SendI2NPMessage (msg);
|
||||
}
|
||||
|
@ -319,14 +361,15 @@ namespace i2p
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
i2p::data::DHKeysPair * Transports::GetNextDHKeysPair ()
|
||||
DHKeysPair * Transports::GetNextDHKeysPair ()
|
||||
{
|
||||
return m_DHKeysPairSupplier.Acquire ();
|
||||
}
|
||||
|
||||
void Transports::ReuseDHKeysPair (i2p::data::DHKeysPair * pair)
|
||||
void Transports::ReuseDHKeysPair (DHKeysPair * pair)
|
||||
{
|
||||
m_DHKeysPairSupplier.Return (pair);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
37
Transports.h
37
Transports.h
|
@ -8,7 +8,9 @@
|
|||
#include <map>
|
||||
#include <queue>
|
||||
#include <string>
|
||||
#include <cryptopp/osrng.h>
|
||||
#include <boost/asio.hpp>
|
||||
#include "TransportSession.h"
|
||||
#include "NTCPSession.h"
|
||||
#include "SSU.h"
|
||||
#include "RouterInfo.h"
|
||||
|
@ -16,17 +18,19 @@
|
|||
#include "Identity.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace transport
|
||||
{
|
||||
class DHKeysPairSupplier
|
||||
{
|
||||
public:
|
||||
|
||||
DHKeysPairSupplier (int size): m_QueueSize (size), m_IsRunning (false), m_Thread (nullptr) {};
|
||||
DHKeysPairSupplier (int size);
|
||||
~DHKeysPairSupplier ();
|
||||
void Start ();
|
||||
void Stop ();
|
||||
i2p::data::DHKeysPair * Acquire ();
|
||||
void Return (i2p::data::DHKeysPair * pair);
|
||||
DHKeysPair * Acquire ();
|
||||
void Return (DHKeysPair * pair);
|
||||
|
||||
private:
|
||||
|
||||
|
@ -36,12 +40,13 @@ namespace i2p
|
|||
private:
|
||||
|
||||
const int m_QueueSize;
|
||||
std::queue<i2p::data::DHKeysPair *> m_Queue;
|
||||
std::queue<DHKeysPair *> m_Queue;
|
||||
|
||||
bool m_IsRunning;
|
||||
std::thread * m_Thread;
|
||||
std::condition_variable m_Acquired;
|
||||
std::mutex m_AcquiredMutex;
|
||||
CryptoPP::AutoSeededRandomPool m_Rnd;
|
||||
};
|
||||
|
||||
class Transports
|
||||
|
@ -55,14 +60,14 @@ namespace i2p
|
|||
void Stop ();
|
||||
|
||||
boost::asio::io_service& GetService () { return m_Service; };
|
||||
i2p::data::DHKeysPair * GetNextDHKeysPair ();
|
||||
void ReuseDHKeysPair (i2p::data::DHKeysPair * pair);
|
||||
i2p::transport::DHKeysPair * GetNextDHKeysPair ();
|
||||
void ReuseDHKeysPair (DHKeysPair * pair);
|
||||
|
||||
void AddNTCPSession (i2p::ntcp::NTCPSession * session);
|
||||
void RemoveNTCPSession (i2p::ntcp::NTCPSession * session);
|
||||
void AddNTCPSession (NTCPSession * session);
|
||||
void RemoveNTCPSession (NTCPSession * session);
|
||||
|
||||
i2p::ntcp::NTCPSession * GetNextNTCPSession ();
|
||||
i2p::ntcp::NTCPSession * FindNTCPSession (const i2p::data::IdentHash& ident);
|
||||
NTCPSession * GetNextNTCPSession ();
|
||||
NTCPSession * FindNTCPSession (const i2p::data::IdentHash& ident);
|
||||
|
||||
void SendMessage (const i2p::data::IdentHash& ident, i2p::I2NPMessage * msg);
|
||||
void CloseSession (const i2p::data::RouterInfo * router);
|
||||
|
@ -70,7 +75,8 @@ namespace i2p
|
|||
private:
|
||||
|
||||
void Run ();
|
||||
void HandleAccept (i2p::ntcp::NTCPServerConnection * conn, const boost::system::error_code& error);
|
||||
void HandleAccept (NTCPServerConnection * conn, const boost::system::error_code& error);
|
||||
void HandleAcceptV6 (NTCPServerConnection * conn, const boost::system::error_code& error);
|
||||
void HandleResendTimer (const boost::system::error_code& ecode, boost::asio::deadline_timer * timer,
|
||||
const i2p::data::IdentHash& ident, i2p::I2NPMessage * msg);
|
||||
void PostMessage (const i2p::data::IdentHash& ident, i2p::I2NPMessage * msg);
|
||||
|
@ -84,10 +90,10 @@ namespace i2p
|
|||
std::thread * m_Thread;
|
||||
boost::asio::io_service m_Service;
|
||||
boost::asio::io_service::work m_Work;
|
||||
boost::asio::ip::tcp::acceptor * m_NTCPAcceptor;
|
||||
boost::asio::ip::tcp::acceptor * m_NTCPAcceptor, * m_NTCPV6Acceptor;
|
||||
|
||||
std::map<i2p::data::IdentHash, i2p::ntcp::NTCPSession *> m_NTCPSessions;
|
||||
i2p::ssu::SSUServer * m_SSUServer;
|
||||
std::map<i2p::data::IdentHash, NTCPSession *> m_NTCPSessions;
|
||||
SSUServer * m_SSUServer;
|
||||
|
||||
DHKeysPairSupplier m_DHKeysPairSupplier;
|
||||
|
||||
|
@ -95,10 +101,11 @@ namespace i2p
|
|||
|
||||
// for HTTP only
|
||||
const decltype(m_NTCPSessions)& GetNTCPSessions () const { return m_NTCPSessions; };
|
||||
const i2p::ssu::SSUServer * GetSSUServer () const { return m_SSUServer; };
|
||||
const SSUServer * GetSSUServer () const { return m_SSUServer; };
|
||||
};
|
||||
|
||||
extern Transports transports;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -92,7 +92,7 @@ namespace tunnel
|
|||
if (outboundTunnel)
|
||||
outboundTunnel->SendTunnelDataMsg (GetNextIdentHash (), 0, msg);
|
||||
else
|
||||
i2p::transports.SendMessage (GetNextIdentHash (), msg);
|
||||
i2p::transport::transports.SendMessage (GetNextIdentHash (), msg);
|
||||
}
|
||||
|
||||
bool Tunnel::HandleTunnelBuildResponse (uint8_t * msg, size_t len)
|
||||
|
|
|
@ -235,7 +235,7 @@ namespace tunnel
|
|||
i2p::HandleI2NPMessage (msg.data);
|
||||
break;
|
||||
case eDeliveryTypeTunnel:
|
||||
i2p::transports.SendMessage (msg.hash, i2p::CreateTunnelGatewayMsg (msg.tunnelID, msg.data));
|
||||
i2p::transport::transports.SendMessage (msg.hash, i2p::CreateTunnelGatewayMsg (msg.tunnelID, msg.data));
|
||||
break;
|
||||
case eDeliveryTypeRouter:
|
||||
if (msg.hash == i2p::context.GetRouterInfo ().GetIdentHash ()) // check if message is sent to us
|
||||
|
@ -253,7 +253,7 @@ namespace tunnel
|
|||
*ds = *(msg.data);
|
||||
i2p::data::netdb.PostI2NPMsg (ds);
|
||||
}
|
||||
i2p::transports.SendMessage (msg.hash, msg.data);
|
||||
i2p::transport::transports.SendMessage (msg.hash, msg.data);
|
||||
}
|
||||
else // we shouldn't send this message. possible leakage
|
||||
{
|
||||
|
|
|
@ -12,8 +12,12 @@ namespace tunnel
|
|||
{
|
||||
void TunnelGatewayBuffer::PutI2NPMsg (const TunnelMessageBlock& block)
|
||||
{
|
||||
bool messageCreated = false;
|
||||
if (!m_CurrentTunnelDataMsg)
|
||||
{
|
||||
CreateCurrentTunnelDataMessage ();
|
||||
messageCreated = true;
|
||||
}
|
||||
|
||||
// create delivery instructions
|
||||
uint8_t di[43]; // max delivery instruction length is 43 for tunnel
|
||||
|
@ -33,7 +37,8 @@ namespace tunnel
|
|||
|
||||
// create fragments
|
||||
I2NPMessage * msg = block.data;
|
||||
if (diLen + msg->GetLength () + 2<= m_RemainingSize)
|
||||
auto fullMsgLen = diLen + msg->GetLength () + 2; // delivery instructions + payload + 2 bytes length
|
||||
if (fullMsgLen <= m_RemainingSize)
|
||||
{
|
||||
// message fits. First and last fragment
|
||||
*(uint16_t *)(di + diLen) = htobe16 (msg->GetLength ());
|
||||
|
@ -48,6 +53,18 @@ namespace tunnel
|
|||
}
|
||||
else
|
||||
{
|
||||
if (!messageCreated) // check if we should complete previous message
|
||||
{
|
||||
auto numFollowOnFragments = fullMsgLen / TUNNEL_DATA_MAX_PAYLOAD_SIZE;
|
||||
// length of bytes don't fit full tunnel message
|
||||
// every follow-on fragment adds 7 bytes
|
||||
auto nonFit = (fullMsgLen + numFollowOnFragments*7) % TUNNEL_DATA_MAX_PAYLOAD_SIZE;
|
||||
if (!nonFit || nonFit > m_RemainingSize)
|
||||
{
|
||||
CompleteCurrentTunnelDataMessage ();
|
||||
CreateCurrentTunnelDataMessage ();
|
||||
}
|
||||
}
|
||||
if (diLen + 6 <= m_RemainingSize)
|
||||
{
|
||||
// delivery instructions fit
|
||||
|
@ -169,7 +186,7 @@ namespace tunnel
|
|||
{
|
||||
m_Tunnel->EncryptTunnelMsg (tunnelMsg);
|
||||
FillI2NPMessageHeader (tunnelMsg, eI2NPTunnelData);
|
||||
i2p::transports.SendMessage (m_Tunnel->GetNextIdentHash (), tunnelMsg);
|
||||
i2p::transport::transports.SendMessage (m_Tunnel->GetNextIdentHash (), tunnelMsg);
|
||||
m_NumSentBytes += TUNNEL_DATA_MSG_SIZE;
|
||||
}
|
||||
m_Buffer.ClearTunnelDataMsgs ();
|
||||
|
|
|
@ -257,7 +257,7 @@ namespace tunnel
|
|||
{
|
||||
// last hop
|
||||
auto hop = outboundTunnel->GetTunnelConfig ()->GetFirstHop ()->router;
|
||||
if (hop->GetIdentHash () != i2p::context.GetRouterIdentHash ()) // outbound shouldn't be zero-hop tunnel
|
||||
if (hop->GetIdentHash () != i2p::context.GetIdentHash ()) // outbound shouldn't be zero-hop tunnel
|
||||
{
|
||||
prevHop = hop;
|
||||
hops.push_back (prevHop);
|
||||
|
|
|
@ -33,7 +33,7 @@ namespace tunnel
|
|||
const uint8_t * GetEncryptionPublicKey () const { return m_LocalDestination.GetEncryptionPublicKey (); };
|
||||
const i2p::data::LocalDestination& GetLocalDestination () const { return m_LocalDestination; };
|
||||
i2p::garlic::GarlicDestination& GetGarlicDestination () const { return m_LocalDestination; };
|
||||
bool IsExploratory () const { return GetIdentHash () == i2p::context.GetRouterIdentHash (); };
|
||||
bool IsExploratory () const { return GetIdentHash () == i2p::context.GetIdentHash (); };
|
||||
|
||||
void CreateTunnels ();
|
||||
void TunnelCreated (InboundTunnel * createdTunnel);
|
||||
|
|
|
@ -47,6 +47,7 @@
|
|||
<ClCompile Include="..\SOCKS.cpp" />
|
||||
<ClCompile Include="..\I2PTunnel.cpp" />
|
||||
<ClCompile Include="..\ClientContext.cpp" />
|
||||
<ClCompile Include="..\Datagram.cpp" />
|
||||
<ClCompile Include="Win32Service.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
@ -91,6 +92,8 @@
|
|||
<ClInclude Include="..\version.h" />
|
||||
<ClInclude Include="..\Signature.h" />
|
||||
<ClInclude Include="..\ClientContext.h" />
|
||||
<ClCompile Include="..\TransportSession.h" />
|
||||
<ClCompile Include="..\Datagram.h" />
|
||||
<ClInclude Include="Win32Service.h" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
|
|
|
@ -44,6 +44,7 @@ set (SOURCES
|
|||
"${CMAKE_SOURCE_DIR}/util.cpp"
|
||||
"${CMAKE_SOURCE_DIR}/SAM.cpp"
|
||||
"${CMAKE_SOURCE_DIR}/ClientContext.cpp"
|
||||
"${CMAKE_SOURCE_DIR}/Datagram.cpp"
|
||||
)
|
||||
|
||||
file (GLOB HEADERS "${CMAKE_SOURCE_DIR}/*.h")
|
||||
|
|
|
@ -325,7 +325,7 @@ i2p_SOURCES = AddressBook.cpp CryptoConst.cpp Daemon.cpp \
|
|||
Transports.cpp Tunnel.cpp TunnelEndpoint.cpp \
|
||||
TunnelGateway.cpp TunnelPool.cpp UPnP.cpp aes.cpp \
|
||||
base64.cpp i2p.cpp util.cpp SAM.cpp Destination.cpp \
|
||||
ClientContext.cpp \
|
||||
ClientContext.cpp DataFram.cpp \
|
||||
\
|
||||
AddressBook.h CryptoConst.h Daemon.h ElGamal.h \
|
||||
Garlic.h HTTPProxy.h HTTPServer.h I2NPProtocol.h \
|
||||
|
@ -336,7 +336,8 @@ i2p_SOURCES = AddressBook.cpp CryptoConst.cpp Daemon.cpp \
|
|||
TransitTunnel.h Transports.h Tunnel.h TunnelBase.h \
|
||||
TunnelConfig.h TunnelEndpoint.h TunnelGateway.h \
|
||||
TunnelPool.h UPnP.h aes.h base64.h config.h hmac.h \
|
||||
util.h version.h Destination.h ClientContext.h
|
||||
util.h version.h Destination.h ClientContext.h \
|
||||
TransportSession.h Datagram.h
|
||||
|
||||
AM_LDFLAGS = @BOOST_DATE_TIME_LIB@ @BOOST_FILESYSTEM_LIB@ \
|
||||
@BOOST_PROGRAM_OPTIONS_LIB@ @BOOST_REGEX_LIB@ \
|
||||
|
@ -485,6 +486,7 @@ distclean-compile:
|
|||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SAM.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ClientContext.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Datagram.Po@am__quote@
|
||||
|
||||
.cpp.o:
|
||||
@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
|
||||
|
|
22
debian/init.d → debian/i2pd.init
vendored
22
debian/init.d → debian/i2pd.init
vendored
|
@ -57,10 +57,10 @@ do_stop()
|
|||
}
|
||||
|
||||
# Function that sends a SIGHUP to the daemon/service
|
||||
#do_reload() {
|
||||
# start-stop-daemon --stop --signal 1 --quiet --pidfile $PIDFILE --name $NAME
|
||||
# return 0
|
||||
#}
|
||||
do_reload() {
|
||||
start-stop-daemon --stop --signal 1 --quiet --pidfile $PIDFILE --name $NAME
|
||||
return 0
|
||||
}
|
||||
|
||||
case "$1" in
|
||||
start)
|
||||
|
@ -82,14 +82,12 @@ case "$1" in
|
|||
status)
|
||||
status_of_proc "$DAEMON" "$NAME" && exit 0 || exit $?
|
||||
;;
|
||||
#reload|force-reload)
|
||||
#log_daemon_msg "Reloading $DESC" "$NAME"
|
||||
#do_reload
|
||||
#log_end_msg $?
|
||||
#;;
|
||||
restart|force-reload)
|
||||
# If the "reload" option is implemented then remove the
|
||||
# 'force-reload' alias
|
||||
reload|force-reload)
|
||||
log_daemon_msg "Reloading $DESC" "$NAME"
|
||||
do_reload
|
||||
log_end_msg $?
|
||||
;;
|
||||
restart)
|
||||
log_daemon_msg "Restarting $DESC" "$NAME"
|
||||
do_stop
|
||||
case "$?" in
|
10
debian/i2pd.upstart
vendored
Normal file
10
debian/i2pd.upstart
vendored
Normal file
|
@ -0,0 +1,10 @@
|
|||
description "i2p client daemon"
|
||||
|
||||
start on runlevel [2345]
|
||||
stop on runlevel [016] or unmounting-filesystem
|
||||
|
||||
# these can be overridden in /etc/init/i2pd.override
|
||||
env I2P_HOST="1.2.3.4"
|
||||
env I2P_PORT="4567"
|
||||
|
||||
exec /usr/sbin/i2pd --daemon=0 --log=1 --host=$I2P_HOST --port=$I2P_PORT
|
|
@ -5,7 +5,7 @@ CPP_FILES := CryptoConst.cpp base64.cpp NTCPSession.cpp RouterInfo.cpp Transport
|
|||
TransitTunnel.cpp I2NPProtocol.cpp Log.cpp Garlic.cpp HTTPServer.cpp Streaming.cpp \
|
||||
Destination.cpp Identity.cpp SSU.cpp util.cpp Reseed.cpp DaemonLinux.cpp SSUData.cpp \
|
||||
aes.cpp SOCKS.cpp UPnP.cpp TunnelPool.cpp HTTPProxy.cpp AddressBook.cpp Daemon.cpp \
|
||||
I2PTunnel.cpp SAM.cpp ClientContext.cpp i2p.cpp
|
||||
I2PTunnel.cpp SAM.cpp ClientContext.cpp Datagram.cpp i2p.cpp
|
||||
|
||||
|
||||
H_FILES := CryptoConst.h base64.h NTCPSession.h RouterInfo.h Transports.h \
|
||||
|
@ -13,7 +13,7 @@ H_FILES := CryptoConst.h base64.h NTCPSession.h RouterInfo.h Transports.h \
|
|||
TransitTunnel.h I2NPProtocol.h Log.h Garlic.h HTTPServer.h Streaming.h Destination.h \
|
||||
Identity.h SSU.h util.h Reseed.h DaemonLinux.h SSUData.h i2p.h aes.h SOCKS.h \
|
||||
UPnP.h TunnelPool.h HTTPProxy.h AddressBook.h Daemon.h I2PTunnel.h version.h \
|
||||
Signature.h SAM.h ClientContext.h
|
||||
Signature.h SAM.h ClientContext.h TransportSession.h Datagram.h
|
||||
|
||||
|
||||
OBJECTS = $(addprefix obj/, $(notdir $(CPP_FILES:.cpp=.o)))
|
||||
|
|
Loading…
Reference in a new issue