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
pull/106/head
Meeh 10 years ago
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");

@ -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;
}
}
}

@ -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

@ -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
{
// 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);
}
else
{
LogPrint ("Received packet size ", uncompressed->len, " exceeds max packet size. Skipped");
decompressor.Skip ();
delete uncompressed;
}
}
else
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
{
void StreamingDestination::Start ()
{
ClientDestination::Start ();
}
void StreamingDestination::Stop ()
{
ResetAcceptor ();
switch (buf[9])
{
std::unique_lock<std::mutex> l(m_StreamsMutex);
for (auto it: m_Streams)
delete it.second;
m_Streams.clear ();
}
ClientDestination::Stop ();
case PROTOCOL_TYPE_STREAMING:
// streaming protocol
if (m_StreamingDestination)
m_StreamingDestination->HandleDataMessagePayload (buf, length);
else
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]);
}
}
void StreamingDestination::HandleNextPacket (Packet * packet)
i2p::stream::Stream * ClientDestination::CreateStream (const i2p::data::LeaseSet& remote, int port)
{
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)
return m_StreamingDestination->CreateNewOutgoingStream (remote, port);
return nullptr;
}
Stream * StreamingDestination::CreateNewOutgoingStream (const i2p::data::LeaseSet& remote)
void ClientDestination::AcceptStreams (const std::function<void (i2p::stream::Stream *)>& acceptor)
{
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)
m_StreamingDestination->SetAcceptor (acceptor);
}
Stream * StreamingDestination::CreateNewIncomingStream ()
void ClientDestination::StopAcceptingStreams ()
{
Stream * s = new Stream (*GetService (), *this);
std::unique_lock<std::mutex> l(m_StreamsMutex);
m_Streams[s->GetRecvStreamID ()] = s;
return s;
if (m_StreamingDestination)
m_StreamingDestination->ResetAcceptor ();
}
void StreamingDestination::DeleteStream (Stream * stream)
bool ClientDestination::IsAcceptingStreams () const
{
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_StreamingDestination)
return m_StreamingDestination->IsAcceptorSet ();
return false;
}
}
void ClientDestination::CreateDatagramDestination ()
{
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,7 +644,10 @@ namespace util
switch (address.transportStyle)
{
case i2p::data::RouterInfo::eTransportNTCP:
s << "NTCP&nbsp;&nbsp;";
if (address.host.is_v6 ())
s << "NTCP6&nbsp;&nbsp;";
else
s << "NTCP&nbsp;&nbsp;";
break;
case i2p::data::RouterInfo::eTransportSSU:
s << "SSU&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;";
@ -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,45 +842,56 @@ 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);
AsyncStreamReceive ();
}
}
}
void HTTPConnection::AsyncStreamReceive ()
{
if (m_Stream)

@ -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");
}

@ -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

@ -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;
@ -105,7 +97,10 @@ namespace data
Identity& operator=(const Keys& keys);
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;
@ -183,11 +178,6 @@ namespace data
uint8_t m_SigningPrivateKey[128]; // assume private key doesn't exceed 128 bytes
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,13 +128,10 @@ 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
{
@ -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;
};
}
}

@ -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);

@ -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,7 +78,8 @@ 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);
// for web interface
@ -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;
@ -130,7 +130,45 @@ namespace i2p
// update
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);
@ -279,18 +277,9 @@ 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

@ -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;

@ -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));
@ -260,7 +264,7 @@ namespace client
priv[l1] = 0;
#ifdef _MSC_VER
size_t l2 = sprintf_s (m_Buffer, SAM_SOCKET_BUFFER_SIZE, SAM_SESSION_CREATE_REPLY_OK, priv);
#else
#else
size_t l2 = snprintf (m_Buffer, SAM_SOCKET_BUFFER_SIZE, SAM_SESSION_CREATE_REPLY_OK, priv);
#endif
SendMessageReply (m_Buffer, l2, false);
@ -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
@ -385,8 +389,8 @@ namespace client
l1 = i2p::data::ByteStreamToBase64 (buf, l, pub, 1024);
pub[l1] = 0;
#ifdef _MSC_VER
size_t len = sprintf_s (m_Buffer, SAM_SOCKET_BUFFER_SIZE, SAM_DEST_REPLY, pub, priv);
#else
size_t len = sprintf_s (m_Buffer, SAM_SOCKET_BUFFER_SIZE, SAM_DEST_REPLY, pub, priv);
#else
size_t len = snprintf (m_Buffer, SAM_SOCKET_BUFFER_SIZE, SAM_DEST_REPLY, pub, priv);
#endif
SendMessageReply (m_Buffer, len, true);
@ -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)
@ -421,7 +425,7 @@ namespace client
{
#ifdef _MSC_VER
size_t len = sprintf_s (m_Buffer, SAM_SOCKET_BUFFER_SIZE, SAM_NAMING_REPLY_INVALID_KEY, name.c_str());
#else
#else
size_t len = snprintf (m_Buffer, SAM_SOCKET_BUFFER_SIZE, SAM_NAMING_REPLY_INVALID_KEY, name.c_str());
#endif
SendMessageReply (m_Buffer, len, false);
@ -437,8 +441,8 @@ namespace client
size_t l1 = i2p::data::ByteStreamToBase64 (buf, l, pub, 1024);
pub[l1] = 0;
#ifdef _MSC_VER
size_t l2 = sprintf_s (m_Buffer, SAM_SOCKET_BUFFER_SIZE, SAM_NAMING_REPLY, pub);
#else
size_t l2 = sprintf_s (m_Buffer, SAM_SOCKET_BUFFER_SIZE, SAM_NAMING_REPLY, pub);
#else
size_t l2 = snprintf (m_Buffer, SAM_SOCKET_BUFFER_SIZE, SAM_NAMING_REPLY, pub);
#endif
SendMessageReply (m_Buffer, l2, false);
@ -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,7 +551,8 @@ 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_NewSocket (nullptr)
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

@ -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();

@ -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)
{
@ -28,8 +28,7 @@ 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 ();
}
}

@ -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;

@ -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);
}
}
}

@ -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 ();
@ -122,6 +127,8 @@ namespace stream
void ScheduleResend ();
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:
@ -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)

@ -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);
}
@ -318,15 +360,16 @@ namespace i2p
m_SSUServer->GetSession (router, true); // peer test
}
}
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);
}
}
}

@ -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">

@ -43,7 +43,8 @@ set (SOURCES
"${CMAKE_SOURCE_DIR}/i2p.cpp"
"${CMAKE_SOURCE_DIR}/util.cpp"
"${CMAKE_SOURCE_DIR}/SAM.cpp"
"${CMAKE_SOURCE_DIR}/ClientContext.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 $@ $<

@ -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

@ -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…
Cancel
Save