Browse Source

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
parent
commit
af0bdc2a5e
  1. 10
      AddressBook.cpp
  2. 8
      AddressBook.h
  3. 22
      ClientContext.cpp
  4. 21
      ClientContext.h
  5. 6
      Daemon.cpp
  6. 132
      Datagram.cpp
  7. 41
      Datagram.h
  8. 177
      Destination.cpp
  9. 69
      Destination.h
  10. 11
      HTTPProxy.cpp
  11. 66
      HTTPServer.cpp
  12. 13
      HTTPServer.h
  13. 13
      I2NPProtocol.cpp
  14. 16
      I2PTunnel.cpp
  15. 13
      I2PTunnel.h
  16. 9
      Identity.cpp
  17. 18
      Identity.h
  18. 2
      Makefile.osx
  19. 71
      NTCPSession.cpp
  20. 22
      NTCPSession.h
  21. 17
      NetDb.cpp
  22. 6
      NetDb.h
  23. 5
      README.md
  24. 42
      RouterContext.cpp
  25. 7
      RouterContext.h
  26. 48
      RouterInfo.cpp
  27. 17
      RouterInfo.h
  28. 99
      SAM.cpp
  29. 12
      SAM.h
  30. 2
      SOCKS.cpp
  31. 42
      SSU.cpp
  32. 9
      SSU.h
  33. 2
      SSUData.cpp
  34. 2
      SSUData.h
  35. 161
      Streaming.cpp
  36. 49
      Streaming.h
  37. 2
      TransitTunnel.cpp
  38. 43
      TransportSession.h
  39. 91
      Transports.cpp
  40. 37
      Transports.h
  41. 2
      Tunnel.cpp
  42. 4
      TunnelEndpoint.cpp
  43. 21
      TunnelGateway.cpp
  44. 2
      TunnelPool.cpp
  45. 2
      TunnelPool.h
  46. 3
      Win32/i2pd.vcxproj
  47. 3
      build/CMakeLists.txt
  48. 6
      build/autotools/Makefile.in
  49. 22
      debian/i2pd.init
  50. 10
      debian/i2pd.upstart
  51. 4
      filelist.mk

10
AddressBook.cpp

@ -11,14 +11,14 @@
namespace i2p namespace i2p
{ {
namespace data namespace client
{ {
AddressBook::AddressBook (): m_IsLoaded (false), m_IsDowloading (false) 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"); auto pos = address.find(".b32.i2p");
if (pos != std::string::npos) if (pos != std::string::npos)
@ -42,7 +42,7 @@ namespace data
return false; return false;
} }
const IdentHash * AddressBook::FindAddress (const std::string& address) const i2p::data::IdentHash * AddressBook::FindAddress (const std::string& address)
{ {
if (!m_IsLoaded) if (!m_IsLoaded)
LoadHosts (); LoadHosts ();
@ -57,7 +57,7 @@ namespace data
void AddressBook::InsertAddress (const std::string& address, const std::string& base64) void AddressBook::InsertAddress (const std::string& address, const std::string& base64)
{ {
IdentityEx ident; i2p::data::IdentityEx ident;
ident.FromBase64 (base64); ident.FromBase64 (base64);
m_Addresses[address] = ident.GetIdentHash (); m_Addresses[address] = ident.GetIdentHash ();
LogPrint (address,"->",ident.GetIdentHash ().ToBase32 (), ".b32.i2p added"); LogPrint (address,"->",ident.GetIdentHash ().ToBase32 (), ".b32.i2p added");
@ -118,7 +118,7 @@ namespace data
std::string name = s.substr(0, pos++); std::string name = s.substr(0, pos++);
std::string addr = s.substr(pos); std::string addr = s.substr(pos);
IdentityEx ident; i2p::data::IdentityEx ident;
ident.FromBase64(addr); ident.FromBase64(addr);
m_Addresses[name] = ident.GetIdentHash (); m_Addresses[name] = ident.GetIdentHash ();
numAddresses++; numAddresses++;

8
AddressBook.h

@ -11,15 +11,15 @@
namespace i2p namespace i2p
{ {
namespace data namespace client
{ {
class AddressBook class AddressBook
{ {
public: public:
AddressBook (); AddressBook ();
bool GetIdentHash (const std::string& address, IdentHash& ident); bool GetIdentHash (const std::string& address, i2p::data::IdentHash& ident);
const IdentHash * FindAddress (const std::string& address); const i2p::data::IdentHash * FindAddress (const std::string& address);
void InsertAddress (const std::string& address, const std::string& base64); // for jump service void InsertAddress (const std::string& address, const std::string& base64); // for jump service
private: private:
@ -27,7 +27,7 @@ namespace data
void LoadHosts (); void LoadHosts ();
void LoadHostsFromI2P (); void LoadHostsFromI2P ();
std::map<std::string, IdentHash> m_Addresses; std::map<std::string, i2p::data::IdentHash> m_Addresses;
bool m_IsLoaded, m_IsDowloading; bool m_IsLoaded, m_IsDowloading;
}; };
} }

22
ClientContext.cpp

@ -27,7 +27,7 @@ namespace client
{ {
if (!m_SharedLocalDestination) 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_Destinations[m_SharedLocalDestination->GetIdentity ().GetIdentHash ()] = m_SharedLocalDestination;
m_SharedLocalDestination->Start (); m_SharedLocalDestination->Start ();
} }
@ -41,7 +41,7 @@ namespace client
std::string ircDestination = i2p::util::config::GetArg("-ircdest", ""); std::string ircDestination = i2p::util::config::GetArg("-ircdest", "");
if (ircDestination.length () > 0) // ircdest is presented if (ircDestination.length () > 0) // ircdest is presented
{ {
i2p::stream::StreamingDestination * localDestination = nullptr; ClientDestination * localDestination = nullptr;
std::string ircKeys = i2p::util::config::GetArg("-irckeys", ""); std::string ircKeys = i2p::util::config::GetArg("-irckeys", "");
if (ircKeys.length () > 0) if (ircKeys.length () > 0)
localDestination = i2p::client::context.LoadLocalDestination (ircKeys, false); localDestination = i2p::client::context.LoadLocalDestination (ircKeys, false);
@ -125,7 +125,7 @@ namespace client
#else #else
it->path(); it->path();
#endif #endif
auto localDestination = new i2p::stream::StreamingDestination (fullPath, true); auto localDestination = new ClientDestination (fullPath, true);
m_Destinations[localDestination->GetIdentHash ()] = localDestination; m_Destinations[localDestination->GetIdentHash ()] = localDestination;
numDestinations++; numDestinations++;
} }
@ -134,25 +134,25 @@ namespace client
LogPrint (numDestinations, " local destinations loaded"); 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); std::unique_lock<std::mutex> l(m_DestinationsMutex);
m_Destinations[localDestination->GetIdentHash ()] = localDestination; m_Destinations[localDestination->GetIdentHash ()] = localDestination;
localDestination->Start (); localDestination->Start ();
return localDestination; 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); std::unique_lock<std::mutex> l(m_DestinationsMutex);
m_Destinations[localDestination->GetIdentHash ()] = localDestination; m_Destinations[localDestination->GetIdentHash ()] = localDestination;
localDestination->Start (); localDestination->Start ();
return localDestination; return localDestination;
} }
void ClientContext::DeleteLocalDestination (i2p::stream::StreamingDestination * destination) void ClientContext::DeleteLocalDestination (ClientDestination * destination)
{ {
if (!destination) return; if (!destination) return;
auto it = m_Destinations.find (destination->GetIdentHash ()); 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 ()); auto it = m_Destinations.find (keys.GetPublic ().GetIdentHash ());
if (it != m_Destinations.end ()) if (it != m_Destinations.end ())
@ -181,14 +181,14 @@ namespace client
} }
return nullptr; return nullptr;
} }
auto localDestination = new i2p::stream::StreamingDestination (keys, isPublic); auto localDestination = new ClientDestination (keys, isPublic);
std::unique_lock<std::mutex> l(m_DestinationsMutex); std::unique_lock<std::mutex> l(m_DestinationsMutex);
m_Destinations[keys.GetPublic ().GetIdentHash ()] = localDestination; m_Destinations[keys.GetPublic ().GetIdentHash ()] = localDestination;
localDestination->Start (); localDestination->Start ();
return localDestination; 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); auto it = m_Destinations.find (destination);
if (it != m_Destinations.end ()) if (it != m_Destinations.end ())

21
ClientContext.h

@ -7,6 +7,7 @@
#include "SOCKS.h" #include "SOCKS.h"
#include "I2PTunnel.h" #include "I2PTunnel.h"
#include "SAM.h" #include "SAM.h"
#include "AddressBook.h"
namespace i2p namespace i2p
{ {
@ -22,12 +23,14 @@ namespace client
void Start (); void Start ();
void Stop (); void Stop ();
i2p::stream::StreamingDestination * GetSharedLocalDestination () const { return m_SharedLocalDestination; }; ClientDestination * GetSharedLocalDestination () const { return m_SharedLocalDestination; };
i2p::stream::StreamingDestination * CreateNewLocalDestination (bool isPublic = true, i2p::data::SigningKeyType sigType = i2p::data::SIGNING_KEY_TYPE_DSA_SHA1); // transient ClientDestination * 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); ClientDestination * CreateNewLocalDestination (const i2p::data::PrivateKeys& keys, bool isPublic = true);
void DeleteLocalDestination (i2p::stream::StreamingDestination * destination); void DeleteLocalDestination (ClientDestination * destination);
i2p::stream::StreamingDestination * FindLocalDestination (const i2p::data::IdentHash& destination) const; ClientDestination * FindLocalDestination (const i2p::data::IdentHash& destination) const;
i2p::stream::StreamingDestination * LoadLocalDestination (const std::string& filename, bool isPublic); ClientDestination * LoadLocalDestination (const std::string& filename, bool isPublic);
AddressBook& GetAddressBook () { return m_AddressBook; };
private: private:
@ -36,8 +39,10 @@ namespace client
private: private:
std::mutex m_DestinationsMutex; std::mutex m_DestinationsMutex;
std::map<i2p::data::IdentHash, i2p::stream::StreamingDestination *> m_Destinations; std::map<i2p::data::IdentHash, ClientDestination *> m_Destinations;
i2p::stream::StreamingDestination * m_SharedLocalDestination; ClientDestination * m_SharedLocalDestination;
AddressBook m_AddressBook;
i2p::proxy::HTTPProxy * m_HttpProxy; i2p::proxy::HTTPProxy * m_HttpProxy;
i2p::proxy::SOCKSProxy * m_SocksProxy; i2p::proxy::SOCKSProxy * m_SocksProxy;

6
Daemon.cpp

@ -72,6 +72,8 @@ namespace i2p
if (i2p::util::config::GetArg("-unreachable", 0)) if (i2p::util::config::GetArg("-unreachable", 0))
i2p::context.SetUnreachable (); i2p::context.SetUnreachable ();
i2p::context.SetSupportsV6 (i2p::util::config::GetArg("-v6", 0));
LogPrint("CMD parameters:"); LogPrint("CMD parameters:");
for (int i = 0; i < argc; ++i) for (int i = 0; i < argc; ++i)
LogPrint(i, " ", argv[i]); LogPrint(i, " ", argv[i]);
@ -103,7 +105,7 @@ namespace i2p
LogPrint("HTTP Server started"); LogPrint("HTTP Server started");
i2p::data::netdb.Start(); i2p::data::netdb.Start();
LogPrint("NetDB started"); LogPrint("NetDB started");
i2p::transports.Start(); i2p::transport::transports.Start();
LogPrint("Transports started"); LogPrint("Transports started");
i2p::tunnel::tunnels.Start(); i2p::tunnel::tunnels.Start();
LogPrint("Tunnels started"); LogPrint("Tunnels started");
@ -120,7 +122,7 @@ namespace i2p
LogPrint("Client stoped"); LogPrint("Client stoped");
i2p::tunnel::tunnels.Stop(); i2p::tunnel::tunnels.Stop();
LogPrint("Tunnels stoped"); LogPrint("Tunnels stoped");
i2p::transports.Stop(); i2p::transport::transports.Stop();
LogPrint("Transports stoped"); LogPrint("Transports stoped");
i2p::data::netdb.Stop(); i2p::data::netdb.Stop();
LogPrint("NetDB stoped"); LogPrint("NetDB stoped");

132
Datagram.cpp

@ -0,0 +1,132 @@
#include <string.h>
#include <vector>
#include <cryptopp/sha.h>
#include <cryptopp/gzip.h>
#include "Log.h"
#include "TunnelBase.h"
#include "RouterContext.h"
#include "Destination.h"
#include "Datagram.h"
namespace i2p
{
namespace datagram
{
DatagramDestination::DatagramDestination (i2p::client::ClientDestination& owner):
m_Owner (owner)
{
}
void DatagramDestination::SendDatagramTo (const uint8_t * payload, size_t len, const i2p::data::LeaseSet& remote)
{
uint8_t buf[MAX_DATAGRAM_SIZE];
auto identityLen = m_Owner.GetIdentity ().ToBuffer (buf, MAX_DATAGRAM_SIZE);
uint8_t * signature = buf + identityLen;
auto signatureLen = m_Owner.GetIdentity ().GetSignatureLen ();
uint8_t * buf1 = signature + signatureLen;
size_t headerLen = identityLen + signatureLen;
memcpy (buf1, payload, len);
if (m_Owner.GetIdentity ().GetSigningKeyType () == i2p::data::SIGNING_KEY_TYPE_DSA_SHA1)
{
uint8_t hash[32];
CryptoPP::SHA256().CalculateDigest (hash, buf1, len);
m_Owner.Sign (hash, 32, signature);
}
else
m_Owner.Sign (buf1, len, signature);
auto service = m_Owner.GetService ();
if (service)
service->post (boost::bind (&DatagramDestination::SendMsg, this,
CreateDataMessage (buf, len + headerLen), remote));
else
LogPrint ("Failed to send datagram. Destination is not running");
}
void DatagramDestination::SendMsg (I2NPMessage * msg, const i2p::data::LeaseSet& remote)
{
auto leases = remote.GetNonExpiredLeases ();
if (!leases.empty ())
{
std::vector<i2p::tunnel::TunnelMessageBlock> msgs;
uint32_t i = i2p::context.GetRandomNumberGenerator ().GenerateWord32 (0, leases.size () - 1);
auto garlic = m_Owner.WrapMessage (remote, msg, true);
msgs.push_back (i2p::tunnel::TunnelMessageBlock
{
i2p::tunnel::eDeliveryTypeTunnel,
leases[i].tunnelGateway, leases[i].tunnelID,
garlic
});
m_Owner.SendTunnelDataMsgs (msgs);
}
else
{
LogPrint ("Failed to send datagram. All leases expired");
DeleteI2NPMessage (msg);
}
}
void DatagramDestination::HandleDatagram (const uint8_t * buf, size_t len)
{
i2p::data::IdentityEx identity;
size_t identityLen = identity.FromBuffer (buf, len);
const uint8_t * signature = buf + identityLen;
size_t headerLen = identityLen + identity.GetSignatureLen ();
bool verified = false;
if (identity.GetSigningKeyType () == i2p::data::SIGNING_KEY_TYPE_DSA_SHA1)
{
uint8_t hash[32];
CryptoPP::SHA256().CalculateDigest (hash, buf + headerLen, len - headerLen);
verified = identity.Verify (hash, 32, signature);
}
else
verified = identity.Verify (buf + headerLen, len - headerLen, signature);
if (verified)
{
// TODO: invoke datagram handler
}
else
LogPrint ("Datagram signature verification failed");
}
void DatagramDestination::HandleDataMessagePayload (const uint8_t * buf, size_t len)
{
// unzip it
CryptoPP::Gunzip decompressor;
decompressor.Put (buf, len);
decompressor.MessageEnd();
uint8_t uncompressed[MAX_DATAGRAM_SIZE];
auto uncompressedLen = decompressor.MaxRetrievable ();
if (uncompressedLen <= MAX_DATAGRAM_SIZE)
{
decompressor.Get (uncompressed, uncompressedLen);
HandleDatagram (uncompressed, uncompressedLen);
}
else
LogPrint ("Received datagram size ", uncompressedLen, " exceeds max size");
}
I2NPMessage * DatagramDestination::CreateDataMessage (const uint8_t * payload, size_t len)
{
I2NPMessage * msg = NewI2NPMessage ();
CryptoPP::Gzip compressor; // default level
compressor.Put (payload, len);
compressor.MessageEnd();
int size = compressor.MaxRetrievable ();
uint8_t * buf = msg->GetPayload ();
*(uint32_t *)buf = htobe32 (size); // length
buf += 4;
compressor.Get (buf, size);
memset (buf + 4, 0, 4); // source and destination are zeroes
buf[9] = i2p::client::PROTOCOL_TYPE_DATAGRAM; // datagram protocol
msg->len += size + 4;
FillI2NPMessageHeader (msg, eI2NPData);
return msg;
}
}
}

41
Datagram.h

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

177
Destination.cpp

@ -1,7 +1,6 @@
#include <fstream> #include <fstream>
#include <algorithm> #include <algorithm>
#include <cryptopp/dh.h> #include <cryptopp/dh.h>
#include <cryptopp/gzip.h>
#include "Log.h" #include "Log.h"
#include "util.h" #include "util.h"
#include "NetDb.h" #include "NetDb.h"
@ -13,7 +12,8 @@ namespace client
{ {
ClientDestination::ClientDestination (bool isPublic, i2p::data::SigningKeyType sigType): ClientDestination::ClientDestination (bool isPublic, i2p::data::SigningKeyType sigType):
m_IsRunning (false), m_Thread (nullptr), m_Service (nullptr), m_Work (nullptr), 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); m_Keys = i2p::data::PrivateKeys::CreateRandomKeys (sigType);
CryptoPP::DH dh (i2p::crypto::elgp, i2p::crypto::elgg); 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 m_Pool = i2p::tunnel::tunnels.CreateTunnelPool (*this, 3); // 3-hops tunnel
if (m_IsPublic) if (m_IsPublic)
LogPrint ("Local address ", GetIdentHash ().ToBase32 (), ".b32.i2p created"); LogPrint ("Local address ", GetIdentHash ().ToBase32 (), ".b32.i2p created");
m_StreamingDestination = new i2p::stream::StreamingDestination (*this); // TODO:
} }
ClientDestination::ClientDestination (const std::string& fullPath, bool isPublic): ClientDestination::ClientDestination (const std::string& fullPath, bool isPublic):
m_IsRunning (false), m_Thread (nullptr), m_Service (nullptr), m_Work (nullptr), 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); std::ifstream s(fullPath.c_str (), std::ifstream::binary);
if (s.is_open ()) if (s.is_open ())
@ -56,17 +58,20 @@ namespace client
CryptoPP::DH dh (i2p::crypto::elgp, i2p::crypto::elgg); CryptoPP::DH dh (i2p::crypto::elgp, i2p::crypto::elgg);
dh.GenerateKeyPair(i2p::context.GetRandomNumberGenerator (), m_EncryptionPrivateKey, m_EncryptionPublicKey); dh.GenerateKeyPair(i2p::context.GetRandomNumberGenerator (), m_EncryptionPrivateKey, m_EncryptionPublicKey);
m_Pool = i2p::tunnel::tunnels.CreateTunnelPool (*this, 3); // 3-hops tunnel 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): ClientDestination::ClientDestination (const i2p::data::PrivateKeys& keys, bool isPublic):
m_IsRunning (false), m_Thread (nullptr), m_Service (nullptr), m_Work (nullptr), 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); CryptoPP::DH dh (i2p::crypto::elgp, i2p::crypto::elgg);
dh.GenerateKeyPair(i2p::context.GetRandomNumberGenerator (), m_EncryptionPrivateKey, m_EncryptionPublicKey); dh.GenerateKeyPair(i2p::context.GetRandomNumberGenerator (), m_EncryptionPrivateKey, m_EncryptionPublicKey);
m_Pool = i2p::tunnel::tunnels.CreateTunnelPool (*this, 3); // 3-hops tunnel m_Pool = i2p::tunnel::tunnels.CreateTunnelPool (*this, 3); // 3-hops tunnel
if (m_IsPublic) if (m_IsPublic)
LogPrint ("Local address ", GetIdentHash ().ToBase32 (), ".b32.i2p created"); LogPrint ("Local address ", GetIdentHash ().ToBase32 (), ".b32.i2p created");
m_StreamingDestination = new i2p::stream::StreamingDestination (*this); // TODO:
} }
ClientDestination::~ClientDestination () ClientDestination::~ClientDestination ()
@ -79,6 +84,8 @@ namespace client
delete m_LeaseSet; delete m_LeaseSet;
delete m_Work; delete m_Work;
delete m_Service; delete m_Service;
delete m_StreamingDestination;
delete m_DatagramDestination;
} }
void ClientDestination::Run () void ClientDestination::Run ()
@ -94,10 +101,12 @@ namespace client
m_Pool->SetActive (true); m_Pool->SetActive (true);
m_IsRunning = true; m_IsRunning = true;
m_Thread = new std::thread (std::bind (&ClientDestination::Run, this)); m_Thread = new std::thread (std::bind (&ClientDestination::Run, this));
m_StreamingDestination->Start ();
} }
void ClientDestination::Stop () void ClientDestination::Stop ()
{ {
m_StreamingDestination->Stop ();
if (m_Pool) if (m_Pool)
i2p::tunnel::tunnels.StopTunnelPool (m_Pool); i2p::tunnel::tunnels.StopTunnelPool (m_Pool);
m_IsRunning = false; m_IsRunning = false;
@ -238,135 +247,57 @@ namespace client
uint32_t length = be32toh (*(uint32_t *)buf); uint32_t length = be32toh (*(uint32_t *)buf);
buf += 4; buf += 4;
// we assume I2CP payload // we assume I2CP payload
if (buf[9] == 6) // streaming protocol switch (buf[9])
{
// unzip it
CryptoPP::Gunzip decompressor;
decompressor.Put (buf, length);
decompressor.MessageEnd();
i2p::stream::Packet * uncompressed = new i2p::stream::Packet;
uncompressed->offset = 0;
uncompressed->len = decompressor.MaxRetrievable ();
if (uncompressed->len <= i2p::stream::MAX_PACKET_SIZE)
{
decompressor.Get (uncompressed->buf, uncompressed->len);
HandleNextPacket (uncompressed);
}
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 ();
{ {
std::unique_lock<std::mutex> l(m_StreamsMutex); case PROTOCOL_TYPE_STREAMING:
for (auto it: m_Streams) // streaming protocol
delete it.second; if (m_StreamingDestination)
m_Streams.clear (); m_StreamingDestination->HandleDataMessagePayload (buf, length);
} else
ClientDestination::Stop (); 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]);
}
} }
i2p::stream::Stream * ClientDestination::CreateStream (const i2p::data::LeaseSet& remote, int port)
void StreamingDestination::HandleNextPacket (Packet * packet)
{ {
uint32_t sendStreamID = packet->GetSendStreamID (); if (m_StreamingDestination)
if (sendStreamID) return m_StreamingDestination->CreateNewOutgoingStream (remote, port);
{ return nullptr;
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) void ClientDestination::AcceptStreams (const std::function<void (i2p::stream::Stream *)>& acceptor)
{ {
Stream * s = new Stream (*GetService (), *this, remote); if (m_StreamingDestination)
std::unique_lock<std::mutex> l(m_StreamsMutex); m_StreamingDestination->SetAcceptor (acceptor);
m_Streams[s->GetRecvStreamID ()] = s; }
return s;
}
Stream * StreamingDestination::CreateNewIncomingStream () void ClientDestination::StopAcceptingStreams ()
{ {
Stream * s = new Stream (*GetService (), *this); if (m_StreamingDestination)
std::unique_lock<std::mutex> l(m_StreamsMutex); m_StreamingDestination->ResetAcceptor ();
m_Streams[s->GetRecvStreamID ()] = s;
return s;
} }
void StreamingDestination::DeleteStream (Stream * stream) bool ClientDestination::IsAcceptingStreams () const
{ {
if (stream) if (m_StreamingDestination)
{ return m_StreamingDestination->IsAcceptorSet ();
std::unique_lock<std::mutex> l(m_StreamsMutex); return false;
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;
}
}
} }
}
void ClientDestination::CreateDatagramDestination ()
{
if (!m_DatagramDestination)
m_DatagramDestination = new i2p::datagram::DatagramDestination (*this);
}
}
} }

69
Destination.h

@ -9,11 +9,16 @@
#include "LeaseSet.h" #include "LeaseSet.h"
#include "Garlic.h" #include "Garlic.h"
#include "Streaming.h" #include "Streaming.h"
#include "Datagram.h"
namespace i2p namespace i2p
{ {
namespace client 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 class ClientDestination: public i2p::garlic::GarlicDestination
{ {
public: public:
@ -34,6 +39,17 @@ namespace client
const i2p::data::LeaseSet * FindLeaseSet (const i2p::data::IdentHash& ident); const i2p::data::LeaseSet * FindLeaseSet (const i2p::data::IdentHash& ident);
void SendTunnelDataMsgs (const std::vector<i2p::tunnel::TunnelMessageBlock>& msgs); 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 // implements LocalDestination
const i2p::data::PrivateKeys& GetPrivateKeys () const { return m_Keys; }; const i2p::data::PrivateKeys& GetPrivateKeys () const { return m_Keys; };
const uint8_t * GetEncryptionPrivateKey () const { return m_EncryptionPrivateKey; }; const uint8_t * GetEncryptionPrivateKey () const { return m_EncryptionPrivateKey; };
@ -50,11 +66,6 @@ namespace client
// I2CP // I2CP
void HandleDataMessage (const uint8_t * buf, size_t len); 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: private:
@ -77,55 +88,15 @@ namespace client
i2p::data::LeaseSet * m_LeaseSet; i2p::data::LeaseSet * m_LeaseSet;
bool m_IsPublic; bool m_IsPublic;
i2p::stream::StreamingDestination * m_StreamingDestination;
i2p::datagram::DatagramDestination * m_DatagramDestination;
public: public:
// for HTTP only // for HTTP only
int GetNumRemoteLeaseSets () const { return m_RemoteLeaseSets.size (); }; 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 #endif

11
HTTPProxy.cpp

@ -1,7 +1,7 @@
#include <boost/lexical_cast.hpp> #include <boost/lexical_cast.hpp>
#include <boost/regex.hpp> #include <boost/regex.hpp>
#include "NetDb.h" #include "ClientContext.h"
#include "HTTPProxy.h" #include "HTTPProxy.h"
namespace i2p namespace i2p
@ -52,10 +52,11 @@ namespace proxy
} }
path=m[4].str(); 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.uri = path;
r.method = method; r.method = method;
r.host = server; 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"); LogPrint ("Jump service for ", r.host, " found. Inserting to address book");
auto base64 = r.uri.substr (addressPos + 1); 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); LogPrint("Requesting ", r.host, ":", r.port, " with path ", r.uri, " and method ", r.method);
SendToAddress (r.host, m_Buffer, m_BufferLen); SendToAddress (r.host, r.port, m_Buffer, m_BufferLen);
} }
} }

66
HTTPServer.cpp

@ -517,7 +517,7 @@ namespace util
if (m_Stream) if (m_Stream)
{ {
m_Stream->Close (); m_Stream->Close ();
i2p::client::context.GetSharedLocalDestination ()->DeleteStream (m_Stream); i2p::stream::DeleteStream (m_Stream);
m_Stream = nullptr; m_Stream = nullptr;
} }
m_Socket->close (); m_Socket->close ();
@ -644,7 +644,10 @@ namespace util
switch (address.transportStyle) switch (address.transportStyle)
{ {
case i2p::data::RouterInfo::eTransportNTCP: case i2p::data::RouterInfo::eTransportNTCP:
s << "NTCP&nbsp;&nbsp;"; if (address.host.is_v6 ())
s << "NTCP6&nbsp;&nbsp;";
else
s << "NTCP&nbsp;&nbsp;";
break; break;
case i2p::data::RouterInfo::eTransportSSU: case i2p::data::RouterInfo::eTransportSSU:
s << "SSU&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"; s << "SSU&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;";
@ -699,14 +702,14 @@ namespace util
void HTTPConnection::ShowTransports (std::stringstream& s) void HTTPConnection::ShowTransports (std::stringstream& s)
{ {
s << "NTCP<br>"; 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 ()) if (it.second->IsEstablished ())
{ {
// incoming connection doesn't have remote RI
bool outgoing = it.second->GetRemoteRouter ();
if (outgoing) s << "-->"; 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 (); << it.second->GetSocket ().remote_endpoint().address ().to_string ();
if (!outgoing) s << "-->"; if (!outgoing) s << "-->";
s << " [" << it.second->GetNumSentBytes () << ":" << it.second->GetNumReceivedBytes () << "]"; s << " [" << it.second->GetNumSentBytes () << ":" << it.second->GetNumReceivedBytes () << "]";
@ -714,7 +717,7 @@ namespace util
} }
s << std::endl; s << std::endl;
} }
auto ssuServer = i2p::transports.GetSSUServer (); auto ssuServer = i2p::transport::transports.GetSSUServer ();
if (ssuServer) if (ssuServer)
{ {
s << "<br>SSU<br>"; s << "<br>SSU<br>";
@ -813,7 +816,7 @@ namespace util
} }
} }
s << "<br><b>Streams:</b><br>"; 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.first << "->" << it.second->GetRemoteIdentity ().GetIdentHash ().ToBase32 () << ".b32.i2p ";
s << " [" << it.second->GetNumSentBytes () << ":" << it.second->GetNumReceivedBytes () << "]"; 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"; std::string request = "GET " + uri + " HTTP/1.1\r\nHost:" + address + "\r\n";
LogPrint("HTTP Client Request: ", request); 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; i2p::data::IdentHash destination;
if (!i2p::data::netdb.GetAddressBook ().GetIdentHash (address, destination)) if (!i2p::client::context.GetAddressBook ().GetIdentHash (address, destination))
{ {
LogPrint ("Unknown address ", address); LogPrint ("Unknown address ", address);
SendReply ("<html>" + itoopieImage + "<br>Unknown address " + address + "</html>", 404); SendReply ("<html>" + itoopieImage + "<br>Unknown address " + address + "</html>", 404);
return; 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); 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 ()); i2p::data::netdb.RequestDestination (destination, true, i2p::client::context.GetSharedLocalDestination ()->GetTunnelPool ());
std::this_thread::sleep_for (std::chrono::seconds(10)); // wait for 10 seconds m_Timer.expires_from_now (boost::posix_time::seconds(HTTP_DESTINATION_REQUEST_TIMEOUT));
leaseSet = i2p::client::context.GetSharedLocalDestination ()->FindLeaseSet (destination); m_Timer.async_wait (boost::bind (&HTTPConnection::HandleDestinationRequestTimeout,
if (!leaseSet || !leaseSet->HasNonExpiredLeases ()) // still no LeaseSet 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); 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) if (!m_Stream)
m_Stream = i2p::client::context.GetSharedLocalDestination ()->CreateNewOutgoingStream (*leaseSet); m_Stream = i2p::client::context.GetSharedLocalDestination ()->CreateStream (*remote, port);
if (m_Stream) if (m_Stream)
{ {
m_Stream->Send ((uint8_t *)buf, len); m_Stream->Send ((uint8_t *)buf, len);
AsyncStreamReceive (); AsyncStreamReceive ();
} }
} }
void HTTPConnection::AsyncStreamReceive () void HTTPConnection::AsyncStreamReceive ()
{ {
if (m_Stream) if (m_Stream)

13
HTTPServer.h

@ -5,6 +5,7 @@
#include <thread> #include <thread>
#include <boost/asio.hpp> #include <boost/asio.hpp>
#include <boost/array.hpp> #include <boost/array.hpp>
#include "LeaseSet.h"
#include "Streaming.h" #include "Streaming.h"
namespace i2p namespace i2p
@ -12,6 +13,7 @@ namespace i2p
namespace util namespace util
{ {
const size_t HTTP_CONNECTION_BUFFER_SIZE = 8192; const size_t HTTP_CONNECTION_BUFFER_SIZE = 8192;
const int HTTP_DESTINATION_REQUEST_TIMEOUT = 10; // in seconds
class HTTPConnection class HTTPConnection
{ {
protected: protected:
@ -27,6 +29,7 @@ namespace util
std::string method; std::string method;
std::string uri; std::string uri;
std::string host; std::string host;
int port;
int http_version_major; int http_version_major;
int http_version_minor; int http_version_minor;
std::vector<header> headers; std::vector<header> headers;
@ -43,7 +46,8 @@ namespace util
public: public:
HTTPConnection (boost::asio::ip::tcp::socket * socket): 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; } virtual ~HTTPConnection() { delete m_Socket; }
private: private:
@ -74,6 +78,7 @@ namespace util
protected: protected:
boost::asio::ip::tcp::socket * m_Socket; boost::asio::ip::tcp::socket * m_Socket;
boost::asio::deadline_timer m_Timer;
i2p::stream::Stream * m_Stream; i2p::stream::Stream * m_Stream;
char m_Buffer[HTTP_CONNECTION_BUFFER_SIZE + 1], m_StreamBuffer[HTTP_CONNECTION_BUFFER_SIZE + 1]; char m_Buffer[HTTP_CONNECTION_BUFFER_SIZE + 1], m_StreamBuffer[HTTP_CONNECTION_BUFFER_SIZE + 1];
size_t m_BufferLen; size_t m_BufferLen;
@ -84,8 +89,10 @@ namespace util
virtual void RunRequest (); virtual void RunRequest ();
void HandleDestinationRequest(const std::string& address, const std::string& uri); void HandleDestinationRequest(const std::string& address, const std::string& uri);
void SendToAddress (const std::string& address, const char * buf, size_t len); void SendToAddress (const std::string& address, int port, const char * buf, size_t len);
void SendToDestination (const i2p::data::IdentHash& destination, 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: public:

13
I2NPProtocol.cpp

@ -13,9 +13,10 @@
#include "Garlic.h" #include "Garlic.h"
#include "I2NPProtocol.h" #include "I2NPProtocol.h"
using namespace i2p::transport;
namespace i2p namespace i2p
{ {
I2NPMessage * NewI2NPMessage () I2NPMessage * NewI2NPMessage ()
{ {
return new I2NPMessageBuffer<I2NP_MAX_MESSAGE_SIZE>(); return new I2NPMessageBuffer<I2NP_MAX_MESSAGE_SIZE>();
@ -289,7 +290,7 @@ namespace i2p
{ {
LogPrint ("Record ",i," is ours"); 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 // replace record to reply
I2NPBuildResponseRecord * reply = (I2NPBuildResponseRecord *)(records + i); I2NPBuildResponseRecord * reply = (I2NPBuildResponseRecord *)(records + i);
if (i2p::context.AcceptsTunnels ()) if (i2p::context.AcceptsTunnels ())
@ -353,13 +354,13 @@ namespace i2p
if (clearText.flag & 0x40) // we are endpoint of outboud tunnel if (clearText.flag & 0x40) // we are endpoint of outboud tunnel
{ {
// so we send it to reply tunnel // so we send it to reply tunnel
i2p::transports.SendMessage (clearText.nextIdent, transports.SendMessage (clearText.nextIdent,
CreateTunnelGatewayMsg (be32toh (clearText.nextTunnel), CreateTunnelGatewayMsg (be32toh (clearText.nextTunnel),
eI2NPVariableTunnelBuildReply, buf, len, eI2NPVariableTunnelBuildReply, buf, len,
be32toh (clearText.nextMessageID))); be32toh (clearText.nextMessageID)));
} }
else else
i2p::transports.SendMessage (clearText.nextIdent, transports.SendMessage (clearText.nextIdent,
CreateI2NPMessage (eI2NPVariableTunnelBuild, buf, len, be32toh (clearText.nextMessageID))); CreateI2NPMessage (eI2NPVariableTunnelBuild, buf, len, be32toh (clearText.nextMessageID)));
} }
} }
@ -373,13 +374,13 @@ namespace i2p
if (clearText.flag & 0x40) // we are endpoint of outbound tunnel if (clearText.flag & 0x40) // we are endpoint of outbound tunnel
{ {
// so we send it to reply tunnel // so we send it to reply tunnel
i2p::transports.SendMessage (clearText.nextIdent, transports.SendMessage (clearText.nextIdent,
CreateTunnelGatewayMsg (be32toh (clearText.nextTunnel), CreateTunnelGatewayMsg (be32toh (clearText.nextTunnel),
eI2NPTunnelBuildReply, buf, len, eI2NPTunnelBuildReply, buf, len,
be32toh (clearText.nextMessageID))); be32toh (clearText.nextMessageID)));
} }
else else
i2p::transports.SendMessage (clearText.nextIdent, transports.SendMessage (clearText.nextIdent,
CreateI2NPMessage (eI2NPTunnelBuild, buf, len, be32toh (clearText.nextMessageID))); CreateI2NPMessage (eI2NPTunnelBuild, buf, len, be32toh (clearText.nextMessageID)));
} }
} }

16
I2PTunnel.cpp

@ -14,7 +14,7 @@ namespace client
boost::asio::ip::tcp::socket * socket, const i2p::data::LeaseSet * leaseSet): boost::asio::ip::tcp::socket * socket, const i2p::data::LeaseSet * leaseSet):
m_Socket (socket), m_Owner (owner) 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 m_Stream->Send (m_Buffer, 0); // connect
StreamReceive (); StreamReceive ();
Receive (); Receive ();
@ -39,7 +39,7 @@ namespace client
if (m_Stream) if (m_Stream)
{ {
m_Stream->Close (); m_Stream->Close ();
m_Owner->GetLocalDestination ()->DeleteStream (m_Stream); i2p::stream::DeleteStream (m_Stream);
m_Stream = nullptr; m_Stream = nullptr;
} }
m_Socket->close (); m_Socket->close ();
@ -115,7 +115,7 @@ namespace client
if (ecode != boost::asio::error::operation_aborted) if (ecode != boost::asio::error::operation_aborted)
{ {
if (m_Stream) m_Stream->Close (); if (m_Stream) m_Stream->Close ();
m_Owner->GetLocalDestination ()->DeleteStream (m_Stream); i2p::stream::DeleteStream (m_Stream);
m_Stream = nullptr; m_Stream = nullptr;
} }
} }
@ -145,7 +145,7 @@ namespace client
} }
I2PClientTunnel::I2PClientTunnel (boost::asio::io_service& service, const std::string& destination, 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 : I2PTunnel (service, localDestination ? localDestination :
i2p::client::context.CreateNewLocalDestination (false, i2p::data::SIGNING_KEY_TYPE_ECDSA_SHA256_P256)), 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)), m_Acceptor (service, boost::asio::ip::tcp::endpoint (boost::asio::ip::tcp::v4(), port)),
@ -162,7 +162,7 @@ namespace client
void I2PClientTunnel::Start () void I2PClientTunnel::Start ()
{ {
i2p::data::IdentHash identHash; 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); m_DestinationIdentHash = new i2p::data::IdentHash (identHash);
if (!m_DestinationIdentHash) if (!m_DestinationIdentHash)
LogPrint ("I2PTunnel unknown destination ", m_Destination); LogPrint ("I2PTunnel unknown destination ", m_Destination);
@ -192,7 +192,7 @@ namespace client
if (!m_DestinationIdentHash) if (!m_DestinationIdentHash)
{ {
i2p::data::IdentHash identHash; 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); m_DestinationIdentHash = new i2p::data::IdentHash (identHash);
} }
if (m_DestinationIdentHash) if (m_DestinationIdentHash)
@ -251,7 +251,7 @@ namespace client
} }
I2PServerTunnel::I2PServerTunnel (boost::asio::io_service& service, const std::string& address, int port, 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) m_Endpoint (boost::asio::ip::address::from_string (address), port)
{ {
} }
@ -270,7 +270,7 @@ namespace client
{ {
auto localDestination = GetLocalDestination (); auto localDestination = GetLocalDestination ();
if (localDestination) if (localDestination)
localDestination->SetAcceptor (std::bind (&I2PServerTunnel::HandleAccept, this, std::placeholders::_1)); localDestination->AcceptStreams (std::bind (&I2PServerTunnel::HandleAccept, this, std::placeholders::_1));
else else
LogPrint ("Local destination not set for server tunnel"); LogPrint ("Local destination not set for server tunnel");
} }

13
I2PTunnel.h

@ -6,6 +6,7 @@
#include <set> #include <set>
#include <boost/asio.hpp> #include <boost/asio.hpp>
#include "Identity.h" #include "Identity.h"
#include "Destination.h"
#include "Streaming.h" #include "Streaming.h"
namespace i2p namespace i2p
@ -51,22 +52,22 @@ namespace client
{ {
public: 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) {}; m_Service (service), m_LocalDestination (localDestination) {};
virtual ~I2PTunnel () { ClearConnections (); }; virtual ~I2PTunnel () { ClearConnections (); };
void AddConnection (I2PTunnelConnection * conn); void AddConnection (I2PTunnelConnection * conn);
void RemoveConnection (I2PTunnelConnection * conn); void RemoveConnection (I2PTunnelConnection * conn);
void ClearConnections (); void ClearConnections ();
i2p::stream::StreamingDestination * GetLocalDestination () { return m_LocalDestination; }; ClientDestination * GetLocalDestination () { return m_LocalDestination; };
void SetLocalDestination (i2p::stream::StreamingDestination * dest) { m_LocalDestination = dest; }; void SetLocalDestination (ClientDestination * dest) { m_LocalDestination = dest; };
boost::asio::io_service& GetService () { return m_Service; }; boost::asio::io_service& GetService () { return m_Service; };
private: private:
boost::asio::io_service& m_Service; boost::asio::io_service& m_Service;
i2p::stream::StreamingDestination * m_LocalDestination; ClientDestination * m_LocalDestination;
std::set<I2PTunnelConnection *> m_Connections; std::set<I2PTunnelConnection *> m_Connections;
}; };
@ -75,7 +76,7 @@ namespace client
public: public:
I2PClientTunnel (boost::asio::io_service& service, const std::string& destination, int port, I2PClientTunnel (boost::asio::io_service& service, const std::string& destination, int port,
i2p::stream::StreamingDestination * localDestination = nullptr); ClientDestination * localDestination = nullptr);
~I2PClientTunnel (); ~I2PClientTunnel ();
void Start (); void Start ();
@ -102,7 +103,7 @@ namespace client
public: public:
I2PServerTunnel (boost::asio::io_service& service, const std::string& address, int port, I2PServerTunnel (boost::asio::io_service& service, const std::string& address, int port,
i2p::stream::StreamingDestination * localDestination); ClientDestination * localDestination);
void Start (); void Start ();
void Stop (); void Stop ();

9
Identity.cpp

@ -2,7 +2,6 @@
#include <stdio.h> #include <stdio.h>
#include <cryptopp/sha.h> #include <cryptopp/sha.h>
#include <cryptopp/osrng.h> #include <cryptopp/osrng.h>
#include <cryptopp/dh.h>
#include <cryptopp/dsa.h> #include <cryptopp/dsa.h>
#include "base64.h" #include "base64.h"
#include "CryptoConst.h" #include "CryptoConst.h"
@ -293,14 +292,6 @@ namespace data
return keys; 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) IdentHash CreateRoutingKey (const IdentHash& ident)
{ {
uint8_t buf[41]; // ident + yyyymmdd uint8_t buf[41]; // ident + yyyymmdd

18
Identity.h

@ -67,13 +67,6 @@ namespace data
typedef Tag<32> IdentHash; typedef Tag<32> IdentHash;
#pragma pack(1) #pragma pack(1)
struct DHKeysPair // transient keys for transport sessions
{
uint8_t publicKey[256];
uint8_t privateKey[256];
};
struct Keys struct Keys
{ {
uint8_t privateKey[256]; uint8_t privateKey[256];
@ -82,7 +75,6 @@ namespace data
uint8_t signingKey[128]; uint8_t signingKey[128];
}; };
const uint8_t CERTIFICATE_TYPE_NULL = 0; const uint8_t CERTIFICATE_TYPE_NULL = 0;
const uint8_t CERTIFICATE_TYPE_HASHCASH = 1; const uint8_t CERTIFICATE_TYPE_HASHCASH = 1;
const uint8_t CERTIFICATE_TYPE_HIDDEN = 2; const uint8_t CERTIFICATE_TYPE_HIDDEN = 2;
@ -105,7 +97,10 @@ namespace data
Identity& operator=(const Keys& keys); Identity& operator=(const Keys& keys);
size_t FromBuffer (const uint8_t * buf, size_t len); size_t FromBuffer (const uint8_t * buf, size_t len);
IdentHash Hash () const; IdentHash Hash () const;
}; };
#pragma pack()
Keys CreateRandomKeys ();
const size_t DEFAULT_IDENTITY_SIZE = sizeof (Identity); // 387 bytes const size_t DEFAULT_IDENTITY_SIZE = sizeof (Identity); // 387 bytes
const uint16_t CRYPTO_KEY_TYPE_ELGAMAL = 0; 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 uint8_t m_SigningPrivateKey[128]; // assume private key doesn't exceed 128 bytes
i2p::crypto::Signer * m_Signer; i2p::crypto::Signer * m_Signer;
}; };
#pragma pack()
Keys CreateRandomKeys ();
void CreateRandomDHKeysPair (DHKeysPair * keys); // for transport sessions
// kademlia // kademlia
struct XORMetric struct XORMetric

2
Makefile.osx vendored

@ -9,7 +9,7 @@ LIBS =
# http://www.hutsby.net/2011/08/macs-with-aes-ni.html # 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 # 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 # 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 # Apple Mac OSX
UNAME_S := $(shell uname -s) UNAME_S := $(shell uname -s)

71
NTCPSession.cpp

@ -3,7 +3,6 @@
#include "I2PEndian.h" #include "I2PEndian.h"
#include <boost/bind.hpp> #include <boost/bind.hpp>
#include <cryptopp/dh.h> #include <cryptopp/dh.h>
#include <cryptopp/dsa.h>
#include "base64.h" #include "base64.h"
#include "Log.h" #include "Log.h"
#include "Timestamp.h" #include "Timestamp.h"
@ -11,28 +10,27 @@
#include "I2NPProtocol.h" #include "I2NPProtocol.h"
#include "RouterContext.h" #include "RouterContext.h"
#include "Transports.h" #include "Transports.h"
#include "NetDb.h"
#include "NTCPSession.h" #include "NTCPSession.h"
using namespace i2p::crypto; using namespace i2p::crypto;
namespace i2p namespace i2p
{ {
namespace ntcp namespace transport
{ {
NTCPSession::NTCPSession (boost::asio::io_service& service, i2p::data::RouterInfo& in_RemoteRouterInfo): NTCPSession::NTCPSession (boost::asio::io_service& service, const i2p::data::RouterInfo * in_RemoteRouter):
m_Socket (service), m_TerminationTimer (service), m_IsEstablished (false), TransportSession (in_RemoteRouter), m_Socket (service),
m_DHKeysPair (nullptr), m_RemoteRouterInfo (in_RemoteRouterInfo), m_TerminationTimer (service), m_IsEstablished (false), m_ReceiveBufferOffset (0),
m_ReceiveBufferOffset (0), m_NextMessage (nullptr), m_NextMessage (nullptr), m_NumSentBytes (0), m_NumReceivedBytes (0)
m_NumSentBytes (0), m_NumReceivedBytes (0)
{ {
m_DHKeysPair = i2p::transports.GetNextDHKeysPair (); m_DHKeysPair = transports.GetNextDHKeysPair ();
m_Establisher = new Establisher; m_Establisher = new Establisher;
} }
NTCPSession::~NTCPSession () NTCPSession::~NTCPSession ()
{ {
delete m_Establisher; delete m_Establisher;
delete m_DHKeysPair;
if (m_NextMessage) if (m_NextMessage)
i2p::DeleteI2NPMessage (m_NextMessage); i2p::DeleteI2NPMessage (m_NextMessage);
for (auto it :m_DelayedMessages) for (auto it :m_DelayedMessages)
@ -79,12 +77,13 @@ namespace ntcp
{ {
m_IsEstablished = false; m_IsEstablished = false;
m_Socket.close (); m_Socket.close ();
i2p::transports.RemoveNTCPSession (this); transports.RemoveNTCPSession (this);
int numDelayed = 0; int numDelayed = 0;
for (auto it :m_DelayedMessages) for (auto it :m_DelayedMessages)
{ {
// try to send them again // try to send them again
i2p::transports.SendMessage (m_RemoteRouterInfo.GetIdentHash (), it); if (m_RemoteRouter)
transports.SendMessage (m_RemoteRouter->GetIdentHash (), it);
numDelayed++; numDelayed++;
} }
m_DelayedMessages.clear (); m_DelayedMessages.clear ();
@ -121,12 +120,12 @@ namespace ntcp
void NTCPSession::ClientLogin () void NTCPSession::ClientLogin ()
{ {
if (!m_DHKeysPair) if (!m_DHKeysPair)
m_DHKeysPair = i2p::transports.GetNextDHKeysPair (); m_DHKeysPair = transports.GetNextDHKeysPair ();
// send Phase1 // send Phase1
const uint8_t * x = m_DHKeysPair->publicKey; const uint8_t * x = m_DHKeysPair->publicKey;
memcpy (m_Establisher->phase1.pubKey, x, 256); memcpy (m_Establisher->phase1.pubKey, x, 256);
CryptoPP::SHA256().CalculateDigest(m_Establisher->phase1.HXxorHI, 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++) for (int i = 0; i < 32; i++)
m_Establisher->phase1.HXxorHI[i] ^= ident[i]; m_Establisher->phase1.HXxorHI[i] ^= ident[i];
@ -191,7 +190,7 @@ namespace ntcp
void NTCPSession::SendPhase2 () void NTCPSession::SendPhase2 ()
{ {
if (!m_DHKeysPair) if (!m_DHKeysPair)
m_DHKeysPair = i2p::transports.GetNextDHKeysPair (); m_DHKeysPair = transports.GetNextDHKeysPair ();
const uint8_t * y = m_DHKeysPair->publicKey; const uint8_t * y = m_DHKeysPair->publicKey;
memcpy (m_Establisher->phase2.pubKey, y, 256); memcpy (m_Establisher->phase2.pubKey, y, 256);
uint8_t xy[512]; uint8_t xy[512];
@ -239,8 +238,9 @@ namespace ntcp
LogPrint ("Phase 2 read error: ", ecode.message (), ". Wrong ident assumed"); LogPrint ("Phase 2 read error: ", ecode.message (), ". Wrong ident assumed");
if (ecode != boost::asio::error::operation_aborted) if (ecode != boost::asio::error::operation_aborted)
{ {
GetRemoteRouterInfo ().SetUnreachable (true); // this RouterInfo is not valid // this RI is not valid
i2p::transports.ReuseDHKeysPair (m_DHKeysPair); i2p::data::netdb.SetUnreachable (GetRemoteIdentity ().GetIdentHash (), true);
transports.ReuseDHKeysPair (m_DHKeysPair);
m_DHKeysPair = nullptr; m_DHKeysPair = nullptr;
Terminate (); Terminate ();
} }
@ -265,7 +265,7 @@ namespace ntcp
if (memcmp (hxy, m_Establisher->phase2.encrypted.hxy, 32)) if (memcmp (hxy, m_Establisher->phase2.encrypted.hxy, 32))
{ {
LogPrint ("Incorrect hash"); LogPrint ("Incorrect hash");
i2p::transports.ReuseDHKeysPair (m_DHKeysPair); transports.ReuseDHKeysPair (m_DHKeysPair);
m_DHKeysPair = nullptr; m_DHKeysPair = nullptr;
Terminate (); Terminate ();
return ; return ;
@ -277,14 +277,14 @@ namespace ntcp
void NTCPSession::SendPhase3 () void NTCPSession::SendPhase3 ()
{ {
m_Establisher->phase3.size = htons (i2p::data::DEFAULT_IDENTITY_SIZE); 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 ()); uint32_t tsA = htobe32 (i2p::util::GetSecondsSinceEpoch ());
m_Establisher->phase3.timestamp = tsA; m_Establisher->phase3.timestamp = tsA;
SignedData s; SignedData s;
memcpy (s.x, m_Establisher->phase1.pubKey, 256); memcpy (s.x, m_Establisher->phase1.pubKey, 256);
memcpy (s.y, m_Establisher->phase2.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.tsA = tsA;
s.tsB = m_Establisher->phase2.encrypted.timestamp; s.tsB = m_Establisher->phase2.encrypted.timestamp;
i2p::context.Sign ((uint8_t *)&s, sizeof (s), m_Establisher->phase3.signature); i2p::context.Sign ((uint8_t *)&s, sizeof (s), m_Establisher->phase3.signature);
@ -324,7 +324,7 @@ namespace ntcp
{ {
LogPrint ("Phase 3 received: ", bytes_transferred); LogPrint ("Phase 3 received: ", bytes_transferred);
m_Decryption.Decrypt ((uint8_t *)&m_Establisher->phase3, sizeof(NTCPPhase3), (uint8_t *)&m_Establisher->phase3); 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; SignedData s;
memcpy (s.x, m_Establisher->phase1.pubKey, 256); memcpy (s.x, m_Establisher->phase1.pubKey, 256);
@ -333,10 +333,7 @@ namespace ntcp
s.tsA = m_Establisher->phase3.timestamp; s.tsA = m_Establisher->phase3.timestamp;
s.tsB = tsB; s.tsB = tsB;
CryptoPP::DSA::PublicKey pubKey; if (!m_RemoteIdentity.Verify ((uint8_t *)&s, sizeof(s), m_Establisher->phase3.signature))
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))
{ {
LogPrint ("signature verification failed"); LogPrint ("signature verification failed");
Terminate (); Terminate ();
@ -352,7 +349,7 @@ namespace ntcp
SignedData s; SignedData s;
memcpy (s.x, m_Establisher->phase1.pubKey, 256); memcpy (s.x, m_Establisher->phase1.pubKey, 256);
memcpy (s.y, m_Establisher->phase2.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.tsA = m_Establisher->phase3.timestamp;
s.tsB = tsB; s.tsB = tsB;
i2p::context.Sign ((uint8_t *)&s, sizeof (s), m_Establisher->phase4.signature); 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 ()); LogPrint ("Phase 4 read error: ", ecode.message ());
if (ecode != boost::asio::error::operation_aborted) 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 (); Terminate ();
} }
} }
@ -404,10 +402,7 @@ namespace ntcp
s.tsA = tsA; s.tsA = tsA;
s.tsB = m_Establisher->phase2.encrypted.timestamp; s.tsB = m_Establisher->phase2.encrypted.timestamp;
CryptoPP::DSA::PublicKey pubKey; if (!m_RemoteIdentity.Verify ((uint8_t *)&s, sizeof(s), m_Establisher->phase4.signature))
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))
{ {
LogPrint ("signature verification failed"); LogPrint ("signature verification failed");
Terminate (); Terminate ();
@ -601,9 +596,8 @@ namespace ntcp
NTCPClient::NTCPClient (boost::asio::io_service& service, const boost::asio::ip::address& address, NTCPClient::NTCPClient (boost::asio::io_service& service, const boost::asio::ip::address& address,
int port, i2p::data::RouterInfo& in_RouterInfo): int port, const i2p::data::RouterInfo& in_RouterInfo):
NTCPSession (service, in_RouterInfo), NTCPSession (service, &in_RouterInfo), m_Endpoint (address, port)
m_Endpoint (address, port)
{ {
Connect (); Connect ();
} }
@ -622,13 +616,15 @@ namespace ntcp
LogPrint ("Connect error: ", ecode.message ()); LogPrint ("Connect error: ", ecode.message ());
if (ecode != boost::asio::error::operation_aborted) if (ecode != boost::asio::error::operation_aborted)
{ {
GetRemoteRouterInfo ().SetUnreachable (true); i2p::data::netdb.SetUnreachable (GetRemoteIdentity ().GetIdentHash (), true);
Terminate (); Terminate ();
} }
} }
else else
{ {
LogPrint ("Connected"); LogPrint ("Connected");
if (GetSocket ().local_endpoint ().protocol () == boost::asio::ip::tcp::v6()) // ipv6
context.UpdateV6Address (GetSocket ().local_endpoint ().address ().to_string ());
ClientLogin (); ClientLogin ();
} }
} }
@ -636,11 +632,8 @@ namespace ntcp
void NTCPServerConnection::Connected () void NTCPServerConnection::Connected ()
{ {
LogPrint ("NTCP server session connected"); LogPrint ("NTCP server session connected");
SetIsEstablished (true); transports.AddNTCPSession (this);
i2p::transports.AddNTCPSession (this); NTCPSession::Connected ();
SendTimeSyncMessage ();
SendI2NPMessage (CreateDatabaseStoreMsg ()); // we tell immediately who we are
} }
} }
} }

22
NTCPSession.h

@ -11,10 +11,11 @@
#include "Identity.h" #include "Identity.h"
#include "RouterInfo.h" #include "RouterInfo.h"
#include "I2NPProtocol.h" #include "I2NPProtocol.h"
#include "TransportSession.h"
namespace i2p namespace i2p
{ {
namespace ntcp namespace transport
{ {
#pragma pack(1) #pragma pack(1)
@ -65,16 +66,16 @@ namespace ntcp
const size_t NTCP_MAX_MESSAGE_SIZE = 16384; const size_t NTCP_MAX_MESSAGE_SIZE = 16384;
const size_t NTCP_BUFFER_SIZE = 1040; // fits one tunnel message (1028) const size_t NTCP_BUFFER_SIZE = 1040; // fits one tunnel message (1028)
const int NTCP_TERMINATION_TIMEOUT = 120; // 2 minutes const int NTCP_TERMINATION_TIMEOUT = 120; // 2 minutes
class NTCPSession
class NTCPSession: public TransportSession
{ {
public: public:
NTCPSession (boost::asio::io_service& service, i2p::data::RouterInfo& in_RemoteRouterInfo); NTCPSession (boost::asio::io_service& service, const i2p::data::RouterInfo * in_RemoteRouter = nullptr);
virtual ~NTCPSession (); ~NTCPSession ();
boost::asio::ip::tcp::socket& GetSocket () { return m_Socket; }; boost::asio::ip::tcp::socket& GetSocket () { return m_Socket; };
bool IsEstablished () const { return m_IsEstablished; }; bool IsEstablished () const { return m_IsEstablished; };
i2p::data::RouterInfo& GetRemoteRouterInfo () { return m_RemoteRouterInfo; };
void ClientLogin (); void ClientLogin ();
void ServerLogin (); void ServerLogin ();
@ -127,13 +128,10 @@ namespace ntcp
boost::asio::ip::tcp::socket m_Socket; boost::asio::ip::tcp::socket m_Socket;
boost::asio::deadline_timer m_TerminationTimer; boost::asio::deadline_timer m_TerminationTimer;
bool m_IsEstablished; bool m_IsEstablished;
i2p::data::DHKeysPair * m_DHKeysPair; // X - for client and Y - for server
i2p::crypto::CBCDecryption m_Decryption; i2p::crypto::CBCDecryption m_Decryption;
i2p::crypto::CBCEncryption m_Encryption; i2p::crypto::CBCEncryption m_Encryption;
CryptoPP::Adler32 m_Adler; CryptoPP::Adler32 m_Adler;
i2p::data::RouterInfo& m_RemoteRouterInfo;
struct Establisher struct Establisher
{ {
@ -157,7 +155,7 @@ namespace ntcp
{ {
public: 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: private:
@ -174,15 +172,11 @@ namespace ntcp
public: public:
NTCPServerConnection (boost::asio::io_service& service): NTCPServerConnection (boost::asio::io_service& service):
NTCPSession (service, m_DummyRemoteRouterInfo) {}; NTCPSession (service) {};
protected: protected:
virtual void Connected (); virtual void Connected ();
private:
i2p::data::RouterInfo m_DummyRemoteRouterInfo;
}; };
} }
} }

17
NetDb.cpp

@ -15,6 +15,8 @@
#include "Reseed.h" #include "Reseed.h"
#include "util.h" #include "util.h"
using namespace i2p::transport;
namespace i2p namespace i2p
{ {
namespace data namespace data
@ -227,6 +229,13 @@ namespace data
return nullptr; 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.) // 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) bool NetDb::CreateNetDb(boost::filesystem::path directory)
{ {
@ -403,7 +412,7 @@ namespace data
RequestedDestination * dest = CreateRequestedDestination (destination, false, false, pool); RequestedDestination * dest = CreateRequestedDestination (destination, false, false, pool);
auto floodfill = GetClosestFloodfill (destination, dest->GetExcludedPeers ()); auto floodfill = GetClosestFloodfill (destination, dest->GetExcludedPeers ());
if (floodfill) 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) if (outbound)
outbound->SendTunnelDataMsg (buf+32, replyTunnelID, replyMsg); outbound->SendTunnelDataMsg (buf+32, replyTunnelID, replyMsg);
else else
i2p::transports.SendMessage (buf+32, i2p::CreateTunnelGatewayMsg (replyTunnelID, replyMsg)); transports.SendMessage (buf+32, i2p::CreateTunnelGatewayMsg (replyTunnelID, replyMsg));
} }
else else
i2p::transports.SendMessage (buf+32, replyMsg); transports.SendMessage (buf+32, replyMsg);
} }
i2p::DeleteI2NPMessage (msg); i2p::DeleteI2NPMessage (msg);
} }
@ -712,7 +721,7 @@ namespace data
}); });
} }
else else
i2p::transports.SendMessage (floodfill->GetIdentHash (), dest->CreateRequestMessage (floodfill->GetIdentHash ())); i2p::transport::transports.SendMessage (floodfill->GetIdentHash (), dest->CreateRequestMessage (floodfill->GetIdentHash ()));
} }
else else
DeleteRequestedDestination (dest); DeleteRequestedDestination (dest);

6
NetDb.h

@ -15,7 +15,6 @@
#include "LeaseSet.h" #include "LeaseSet.h"
#include "Tunnel.h" #include "Tunnel.h"
#include "TunnelPool.h" #include "TunnelPool.h"
#include "AddressBook.h"
namespace i2p namespace i2p
{ {
@ -67,7 +66,6 @@ namespace data
void AddLeaseSet (const IdentHash& ident, const uint8_t * buf, int len, i2p::tunnel::InboundTunnel * from); void AddLeaseSet (const IdentHash& ident, const uint8_t * buf, int len, i2p::tunnel::InboundTunnel * from);
RouterInfo * FindRouter (const IdentHash& ident) const; RouterInfo * FindRouter (const IdentHash& ident) const;
LeaseSet * FindLeaseSet (const IdentHash& destination) 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 PublishLeaseSet (const LeaseSet * leaseSet, i2p::tunnel::TunnelPool * pool);
void RequestDestination (const IdentHash& destination, bool isLeaseSet = false, void RequestDestination (const IdentHash& destination, bool isLeaseSet = false,
@ -80,7 +78,8 @@ namespace data
const RouterInfo * GetRandomRouter () const; const RouterInfo * GetRandomRouter () const;
const RouterInfo * GetRandomRouter (const RouterInfo * compatibleWith) const; const RouterInfo * GetRandomRouter (const RouterInfo * compatibleWith) const;
const RouterInfo * GetHighBandwidthRandomRouter (const RouterInfo * compatibleWith) const; const RouterInfo * GetHighBandwidthRandomRouter (const RouterInfo * compatibleWith) const;
void SetUnreachable (const IdentHash& ident, bool unreachable);
void PostI2NPMsg (I2NPMessage * msg); void PostI2NPMsg (I2NPMessage * msg);
// for web interface // for web interface
@ -120,7 +119,6 @@ namespace data
int m_ReseedRetries; int m_ReseedRetries;
std::thread * m_Thread; std::thread * m_Thread;
i2p::util::Queue<I2NPMessage> m_Queue; // of I2NPDatabaseStoreMsg i2p::util::Queue<I2NPMessage> m_Queue; // of I2NPDatabaseStoreMsg
AddressBook m_AddressBook;
static const char m_NetDbPath[]; static const char m_NetDbPath[];
}; };

5
README.md

@ -35,10 +35,10 @@ $ ./i2p --host=YOUR_PUBLIC_IP
The client should now reseed by itself. The client should now reseed by itself.
To visit an I2P page, you need to find the b32 address of your destination. 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: This should resulting in for example:
http://localhost:7070/4oes3rlgrpbkmzv4lqcfili23h3cvpwslqcfjlk6vvguxyggspwa http://localhost:7070/4oes3rlgrpbkmzv4lqcfili23h3cvpwslqcfjlk6vvguxyggspwa.b32.i2p
Options Options
@ -51,6 +51,7 @@ Options
* --daemon= - Enable or disable daemon mode. 1 for yes, 0 for no. * --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). * --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. * --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) * --httpproxyport= - The port to listen on (HTTP Proxy)
* --socksproxyport= - The port to listen on (SOCKS Proxy) * --socksproxyport= - The port to listen on (SOCKS Proxy)
* --ircport= - The local port of IRC tunnel to listen on. 6668 by default * --ircport= - The local port of IRC tunnel to listen on. 6668 by default

42
RouterContext.cpp

@ -78,7 +78,7 @@ namespace i2p
auto newAddress = boost::asio::ip::address::from_string (host); auto newAddress = boost::asio::ip::address::from_string (host);
for (auto& address : m_RouterInfo.GetAddresses ()) for (auto& address : m_RouterInfo.GetAddresses ())
{ {
if (address.host != newAddress) if (address.host != newAddress && address.IsCompatible (newAddress))
{ {
address.host = newAddress; address.host = newAddress;
updated = true; updated = true;
@ -130,7 +130,45 @@ namespace i2p
// update // update
UpdateRouterInfo (); 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 () bool RouterContext::Load ()
{ {
std::ifstream fk (i2p::util::filesystem::GetFullPath (ROUTER_KEYS).c_str (), std::ifstream::binary | std::ofstream::in); std::ifstream fk (i2p::util::filesystem::GetFullPath (ROUTER_KEYS).c_str (), std::ifstream::binary | std::ofstream::in);

7
RouterContext.h

@ -2,6 +2,7 @@
#define ROUTER_CONTEXT_H__ #define ROUTER_CONTEXT_H__
#include <inttypes.h> #include <inttypes.h>
#include <string>
#include <cryptopp/dsa.h> #include <cryptopp/dsa.h>
#include <cryptopp/osrng.h> #include <cryptopp/osrng.h>
#include "Identity.h" #include "Identity.h"
@ -22,9 +23,6 @@ namespace i2p
void Init (); void Init ();
i2p::data::RouterInfo& GetRouterInfo () { return m_RouterInfo; }; 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; }; CryptoPP::RandomNumberGenerator& GetRandomNumberGenerator () { return m_Rnd; };
void UpdatePort (int port); // called from Daemon void UpdatePort (int port); // called from Daemon
@ -35,6 +33,9 @@ namespace i2p
void SetUnreachable (); void SetUnreachable ();
bool AcceptsTunnels () const { return m_AcceptsTunnels; }; bool AcceptsTunnels () const { return m_AcceptsTunnels; };
void SetAcceptsTunnels (bool acceptsTunnels) { m_AcceptsTunnels = 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 // implements LocalDestination
const i2p::data::PrivateKeys& GetPrivateKeys () const { return m_Keys; }; const i2p::data::PrivateKeys& GetPrivateKeys () const { return m_Keys; };

48
RouterInfo.cpp

@ -59,7 +59,6 @@ namespace data
{ {
m_RouterIdentity = identity; m_RouterIdentity = identity;
m_IdentHash = m_RouterIdentity.Hash (); m_IdentHash = m_RouterIdentity.Hash ();
UpdateIdentHashBase64 ();
m_Timestamp = i2p::util::GetMillisecondsSinceEpoch (); m_Timestamp = i2p::util::GetMillisecondsSinceEpoch ();
} }
@ -226,7 +225,6 @@ namespace data
} }
CryptoPP::SHA256().CalculateDigest(m_IdentHash, (uint8_t *)&m_RouterIdentity, sizeof (m_RouterIdentity)); CryptoPP::SHA256().CalculateDigest(m_IdentHash, (uint8_t *)&m_RouterIdentity, sizeof (m_RouterIdentity));
UpdateIdentHashBase64 ();
if (!m_SupportedTransports || !m_Addresses.size() || (UsesIntroducer () && !introducers)) if (!m_SupportedTransports || !m_Addresses.size() || (UsesIntroducer () && !introducers))
SetUnreachable (true); SetUnreachable (true);
@ -279,18 +277,9 @@ namespace data
SetProperty ("caps", caps.c_str ()); 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) void RouterInfo::WriteToStream (std::ostream& s)
{ {
s.write ((char *)&m_RouterIdentity, sizeof (m_RouterIdentity));
uint64_t ts = htobe64 (m_Timestamp); uint64_t ts = htobe64 (m_Timestamp);
s.write ((char *)&ts, sizeof (ts)); s.write ((char *)&ts, sizeof (ts));
@ -410,7 +399,7 @@ namespace data
if (!m_Buffer) if (!m_Buffer)
{ {
if (LoadFile ()) if (LoadFile ())
LogPrint ("Buffer for ", m_IdentHashAbbreviation, " loaded from file"); LogPrint ("Buffer for ", GetIdentHashAbbreviation (), " loaded from file");
} }
return m_Buffer; return m_Buffer;
} }
@ -419,6 +408,9 @@ namespace data
{ {
m_Timestamp = i2p::util::GetMillisecondsSinceEpoch (); // refresh timstamp m_Timestamp = i2p::util::GetMillisecondsSinceEpoch (); // refresh timstamp
std::stringstream s; std::stringstream s;
uint8_t ident[1024];
auto identLen = privateKeys.GetPublic ().ToBuffer (ident, 1024);
s.write ((char *)ident, identLen);
WriteToStream (s); WriteToStream (s);
m_BufferLen = s.str ().size (); m_BufferLen = s.str ().size ();
if (!m_Buffer) if (!m_Buffer)
@ -466,7 +458,7 @@ namespace data
addr.cost = 2; addr.cost = 2;
addr.date = 0; addr.date = 0;
m_Addresses.push_back(addr); 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) void RouterInfo::AddSSUAddress (const char * host, int port, const uint8_t * key)
@ -479,7 +471,7 @@ namespace data
addr.date = 0; addr.date = 0;
memcpy (addr.key, key, 32); memcpy (addr.key, key, 32);
m_Addresses.push_back(addr); m_Addresses.push_back(addr);
m_SupportedTransports |= eSSUV4; m_SupportedTransports |= addr.host.is_v6 () ? eNTCPV6 : eSSUV4;
m_Caps |= eSSUTesting; m_Caps |= eSSUTesting;
m_Caps |= eSSUIntroducer; m_Caps |= eSSUIntroducer;
} }
@ -568,6 +560,34 @@ namespace data
return m_SupportedTransports & (eSSUV4 | eSSUV6); 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 bool RouterInfo::UsesIntroducer () const
{ {
return m_Caps & Caps::eUnreachable; // non-reachable return m_Caps & Caps::eUnreachable; // non-reachable

17
RouterInfo.h

@ -75,10 +75,16 @@ namespace data
// SSU only // SSU only
Tag<32> key; // intro key for SSU Tag<32> key; // intro key for SSU
std::vector<Introducer> introducers; 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 (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 (const RouterInfo& ) = default;
RouterInfo& operator=(const RouterInfo& ) = default; RouterInfo& operator=(const RouterInfo& ) = default;
RouterInfo (const uint8_t * buf, int len); RouterInfo (const uint8_t * buf, int len);
@ -86,8 +92,8 @@ namespace data
const Identity& GetRouterIdentity () const { return m_RouterIdentity; }; const Identity& GetRouterIdentity () const { return m_RouterIdentity; };
void SetRouterIdentity (const Identity& identity); void SetRouterIdentity (const Identity& identity);
const char * GetIdentHashBase64 () const { return m_IdentHashBase64; }; std::string GetIdentHashBase64 () const { return m_IdentHash.ToBase64 (); };
const char * GetIdentHashAbbreviation () const { return m_IdentHashAbbreviation; }; std::string GetIdentHashAbbreviation () const { return m_IdentHash.ToBase64 ().substr (0, 4); };
uint64_t GetTimestamp () const { return m_Timestamp; }; uint64_t GetTimestamp () const { return m_Timestamp; };
std::vector<Address>& GetAddresses () { return m_Addresses; }; std::vector<Address>& GetAddresses () { return m_Addresses; };
const Address * GetNTCPAddress (bool v4only = true) const; const Address * GetNTCPAddress (bool v4only = true) const;
@ -102,6 +108,9 @@ namespace data
bool IsFloodfill () const; bool IsFloodfill () const;
bool IsNTCP (bool v4only = true) const; bool IsNTCP (bool v4only = true) const;
bool IsSSU (bool v4only = true) const; bool IsSSU (bool v4only = true) const;
bool IsV6 () const;
void EnableV6 ();
void DisableV6 ();
bool IsCompatible (const RouterInfo& other) const { return m_SupportedTransports & other.m_SupportedTransports; }; bool IsCompatible (const RouterInfo& other) const { return m_SupportedTransports & other.m_SupportedTransports; };
bool UsesIntroducer () const; bool UsesIntroducer () const;
bool IsIntroducer () const { return m_Caps & eSSUIntroducer; }; bool IsIntroducer () const { return m_Caps & eSSUIntroducer; };
@ -143,7 +152,6 @@ namespace data
size_t ReadString (char * str, std::istream& s); size_t ReadString (char * str, std::istream& s);
void WriteString (const std::string& str, std::ostream& s); void WriteString (const std::string& str, std::ostream& s);
void ExtractCaps (const char * value); void ExtractCaps (const char * value);
void UpdateIdentHashBase64 ();
const Address * GetAddress (TransportStyle s, bool v4only) const; const Address * GetAddress (TransportStyle s, bool v4only) const;
void UpdateCapsProperty (); void UpdateCapsProperty ();
@ -152,7 +160,6 @@ namespace data
std::string m_FullPath; std::string m_FullPath;
Identity m_RouterIdentity; Identity m_RouterIdentity;
IdentHash m_IdentHash; IdentHash m_IdentHash;
char m_IdentHashBase64[48], m_IdentHashAbbreviation[5];
uint8_t * m_Buffer; uint8_t * m_Buffer;
int m_BufferLen; int m_BufferLen;
uint64_t m_Timestamp; uint64_t m_Timestamp;

99
SAM.cpp

@ -28,8 +28,8 @@ namespace client
if (m_Stream) if (m_Stream)
{ {
m_Stream->Close (); m_Stream->Close ();
if (m_Session && m_Session->localDestination) i2p::stream::DeleteStream (m_Stream);
m_Session->localDestination->DeleteStream (m_Stream); m_Stream = nullptr;
} }
} }
@ -38,8 +38,7 @@ namespace client
if (m_Stream) if (m_Stream)
{ {
m_Stream->Close (); m_Stream->Close ();
if (m_Session && m_Session->localDestination) i2p::stream::DeleteStream (m_Stream);
m_Session->localDestination->DeleteStream (m_Stream);
m_Stream = nullptr; m_Stream = nullptr;
} }
switch (m_SocketType) switch (m_SocketType)
@ -58,7 +57,7 @@ namespace client
if (m_Session) if (m_Session)
{ {
m_Session->sockets.remove (this); m_Session->sockets.remove (this);
m_Session->localDestination->ResetAcceptor (); m_Session->localDestination->StopAcceptingStreams ();
} }
break; break;
} }
@ -210,6 +209,7 @@ namespace client
LogPrint ("SAM session create: ", buf); LogPrint ("SAM session create: ", buf);
std::map<std::string, std::string> params; std::map<std::string, std::string> params;
ExtractParams (buf, len, params); ExtractParams (buf, len, params);
std::string& style = params[SAM_PARAM_STYLE];
std::string& id = params[SAM_PARAM_ID]; std::string& id = params[SAM_PARAM_ID];
std::string& destination = params[SAM_PARAM_DESTINATION]; std::string& destination = params[SAM_PARAM_DESTINATION];
m_ID = id; m_ID = id;
@ -224,7 +224,11 @@ namespace client
{ {
m_SocketType = eSAMSocketTypeSession; m_SocketType = eSAMSocketTypeSession;
if (m_Session->localDestination->IsReady ()) if (m_Session->localDestination->IsReady ())
{
if (style == SAM_VALUE_DATAGRAM)
m_Session->localDestination->CreateDatagramDestination ();
SendSessionCreateReplyOk (); SendSessionCreateReplyOk ();
}
else else
{ {
m_Timer.expires_from_now (boost::posix_time::seconds(SAM_SESSION_READINESS_CHECK_INTERVAL)); m_Timer.expires_from_now (boost::posix_time::seconds(SAM_SESSION_READINESS_CHECK_INTERVAL));
@ -260,7 +264,7 @@ namespace client
priv[l1] = 0; priv[l1] = 0;
#ifdef _MSC_VER #ifdef _MSC_VER
size_t l2 = sprintf_s (m_Buffer, SAM_SOCKET_BUFFER_SIZE, SAM_SESSION_CREATE_REPLY_OK, priv); 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); size_t l2 = snprintf (m_Buffer, SAM_SOCKET_BUFFER_SIZE, SAM_SESSION_CREATE_REPLY_OK, priv);
#endif #endif
SendMessageReply (m_Buffer, l2, false); SendMessageReply (m_Buffer, l2, false);
@ -302,7 +306,7 @@ namespace client
{ {
m_SocketType = eSAMSocketTypeStream; m_SocketType = eSAMSocketTypeStream;
m_Session->sockets.push_back (this); 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 m_Stream->Send ((uint8_t *)m_Buffer, 0); // connect
I2PReceive (); I2PReceive ();
SendMessageReply (SAM_STREAM_STATUS_OK, strlen(SAM_STREAM_STATUS_OK), false); SendMessageReply (SAM_STREAM_STATUS_OK, strlen(SAM_STREAM_STATUS_OK), false);
@ -355,11 +359,11 @@ namespace client
m_Session = m_Owner.FindSession (id); m_Session = m_Owner.FindSession (id);
if (m_Session) if (m_Session)
{ {
if (!m_Session->localDestination->IsAcceptorSet ()) if (!m_Session->localDestination->IsAcceptingStreams ())
{ {
m_SocketType = eSAMSocketTypeAcceptor; m_SocketType = eSAMSocketTypeAcceptor;
m_Session->sockets.push_back (this); 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); SendMessageReply (SAM_STREAM_STATUS_OK, strlen(SAM_STREAM_STATUS_OK), false);
} }
else else
@ -385,8 +389,8 @@ namespace client
l1 = i2p::data::ByteStreamToBase64 (buf, l, pub, 1024); l1 = i2p::data::ByteStreamToBase64 (buf, l, pub, 1024);
pub[l1] = 0; pub[l1] = 0;
#ifdef _MSC_VER #ifdef _MSC_VER
size_t len = sprintf_s (m_Buffer, SAM_SOCKET_BUFFER_SIZE, SAM_DEST_REPLY, pub, priv); size_t len = sprintf_s (m_Buffer, SAM_SOCKET_BUFFER_SIZE, SAM_DEST_REPLY, pub, priv);
#else #else
size_t len = snprintf (m_Buffer, SAM_SOCKET_BUFFER_SIZE, SAM_DEST_REPLY, pub, priv); size_t len = snprintf (m_Buffer, SAM_SOCKET_BUFFER_SIZE, SAM_DEST_REPLY, pub, priv);
#endif #endif
SendMessageReply (m_Buffer, len, true); SendMessageReply (m_Buffer, len, true);
@ -404,7 +408,7 @@ namespace client
i2p::data::IdentHash ident; i2p::data::IdentHash ident;
if (name == "ME") if (name == "ME")
SendNamingLookupReply (nullptr); 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); auto leaseSet = m_Session->localDestination->FindLeaseSet (ident);
if (leaseSet) if (leaseSet)
@ -421,7 +425,7 @@ namespace client
{ {
#ifdef _MSC_VER #ifdef _MSC_VER
size_t len = sprintf_s (m_Buffer, SAM_SOCKET_BUFFER_SIZE, SAM_NAMING_REPLY_INVALID_KEY, name.c_str()); 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()); size_t len = snprintf (m_Buffer, SAM_SOCKET_BUFFER_SIZE, SAM_NAMING_REPLY_INVALID_KEY, name.c_str());
#endif #endif
SendMessageReply (m_Buffer, len, false); SendMessageReply (m_Buffer, len, false);
@ -437,8 +441,8 @@ namespace client
size_t l1 = i2p::data::ByteStreamToBase64 (buf, l, pub, 1024); size_t l1 = i2p::data::ByteStreamToBase64 (buf, l, pub, 1024);
pub[l1] = 0; pub[l1] = 0;
#ifdef _MSC_VER #ifdef _MSC_VER
size_t l2 = sprintf_s (m_Buffer, SAM_SOCKET_BUFFER_SIZE, SAM_NAMING_REPLY, pub); size_t l2 = sprintf_s (m_Buffer, SAM_SOCKET_BUFFER_SIZE, SAM_NAMING_REPLY, pub);
#else #else
size_t l2 = snprintf (m_Buffer, SAM_SOCKET_BUFFER_SIZE, SAM_NAMING_REPLY, pub); size_t l2 = snprintf (m_Buffer, SAM_SOCKET_BUFFER_SIZE, SAM_NAMING_REPLY, pub);
#endif #endif
SendMessageReply (m_Buffer, l2, false); SendMessageReply (m_Buffer, l2, false);
@ -530,7 +534,7 @@ namespace client
m_Stream = stream; m_Stream = stream;
auto session = m_Owner.FindSession (m_ID); auto session = m_Owner.FindSession (m_ID);
if (session) if (session)
session->localDestination->ResetAcceptor (); session->localDestination->StopAcceptingStreams ();
if (!m_IsSilent) if (!m_IsSilent)
{ {
// send remote peer address // send remote peer address
@ -547,7 +551,8 @@ namespace client
SAMBridge::SAMBridge (int port): SAMBridge::SAMBridge (int port):
m_IsRunning (false), m_Thread (nullptr), m_IsRunning (false), m_Thread (nullptr),
m_Acceptor (m_Service, boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), port)), 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 () void SAMBridge::Start ()
{ {
Accept (); Accept ();
ReceiveDatagram ();
m_IsRunning = true; m_IsRunning = true;
m_Thread = new std::thread (std::bind (&SAMBridge::Run, this)); 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) SAMSession * SAMBridge::CreateSession (const std::string& id, const std::string& destination)
{ {
i2p::stream::StreamingDestination * localDestination = nullptr; ClientDestination * localDestination = nullptr;
if (destination != "") if (destination != "")
{ {
uint8_t * buf = new uint8_t[destination.length ()]; uint8_t * buf = new uint8_t[destination.length ()];
@ -665,5 +671,62 @@ namespace client
return &it->second; return &it->second;
return nullptr; 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 "Identity.h"
#include "LeaseSet.h" #include "LeaseSet.h"
#include "Streaming.h" #include "Streaming.h"
#include "Destination.h"
namespace i2p namespace i2p
{ {
@ -46,6 +47,9 @@ namespace client
const char SAM_PARAM_DESTINATION[] = "DESTINATION"; const char SAM_PARAM_DESTINATION[] = "DESTINATION";
const char SAM_PARAM_NAME[] = "NAME"; const char SAM_PARAM_NAME[] = "NAME";
const char SAM_VALUE_TRANSIENT[] = "TRANSIENT"; 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_TRUE[] = "true";
const char SAM_VALUE_FALSE[] = "false"; const char SAM_VALUE_FALSE[] = "false";
@ -115,7 +119,7 @@ namespace client
struct SAMSession struct SAMSession
{ {
i2p::stream::StreamingDestination * localDestination; ClientDestination * localDestination;
std::list<SAMSocket *> sockets; std::list<SAMSocket *> sockets;
}; };
@ -141,15 +145,21 @@ namespace client
void Accept (); void Accept ();
void HandleAccept(const boost::system::error_code& ecode); void HandleAccept(const boost::system::error_code& ecode);
void ReceiveDatagram ();
void HandleReceivedDatagram (const boost::system::error_code& ecode, std::size_t bytes_transferred);
private: private:
bool m_IsRunning; bool m_IsRunning;
std::thread * m_Thread; std::thread * m_Thread;
boost::asio::io_service m_Service; boost::asio::io_service m_Service;
boost::asio::ip::tcp::acceptor m_Acceptor; 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; SAMSocket * m_NewSocket;
std::mutex m_SessionsMutex; std::mutex m_SessionsMutex;
std::map<std::string, SAMSession> m_Sessions; std::map<std::string, SAMSession> m_Sessions;
uint8_t m_DatagramReceiveBuffer[i2p::datagram::MAX_DATAGRAM_SIZE+1];
}; };
} }
} }

2
SOCKS.cpp

@ -224,7 +224,7 @@ namespace proxy
void SOCKS4AHandler::SentConnectionSuccess(const boost::system::error_code & ecode) void SOCKS4AHandler::SentConnectionSuccess(const boost::system::error_code & ecode)
{ {
LogPrint("--- socks4a making connection"); 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; m_state = OKAY;
LogPrint("--- socks4a state is ", m_state); LogPrint("--- socks4a state is ", m_state);
AsyncSockRead(); AsyncSockRead();

42
SSU.cpp

@ -12,13 +12,13 @@
namespace i2p namespace i2p
{ {
namespace ssu namespace transport
{ {
SSUSession::SSUSession (SSUServer& server, boost::asio::ip::udp::endpoint& remoteEndpoint, SSUSession::SSUSession (SSUServer& server, boost::asio::ip::udp::endpoint& remoteEndpoint,
const i2p::data::RouterInfo * router, bool peerTest ): const i2p::data::RouterInfo * router, bool peerTest ): TransportSession (router),
m_Server (server), m_RemoteEndpoint (remoteEndpoint), m_RemoteRouter (router), m_Server (server), m_RemoteEndpoint (remoteEndpoint),
m_Timer (m_Server.GetService ()), m_DHKeysPair (nullptr), m_PeerTest (peerTest), m_Timer (m_Server.GetService ()), m_PeerTest (peerTest),
m_State (eSessionStateUnknown), m_IsSessionKey (false), m_RelayTag (0), m_State (eSessionStateUnknown), m_IsSessionKey (false), m_RelayTag (0),
m_Data (*this), m_NumSentBytes (0), m_NumReceivedBytes (0) m_Data (*this), m_NumSentBytes (0), m_NumReceivedBytes (0)
{ {
@ -28,8 +28,7 @@ namespace ssu
} }
SSUSession::~SSUSession () SSUSession::~SSUSession ()
{ {
delete m_DHKeysPair;
} }
void SSUSession::CreateAESandMacKey (const uint8_t * pubKey) void SSUSession::CreateAESandMacKey (const uint8_t * pubKey)
@ -174,7 +173,7 @@ namespace ssu
LogPrint ("Session request received"); LogPrint ("Session request received");
m_RemoteEndpoint = senderEndpoint; m_RemoteEndpoint = senderEndpoint;
if (!m_DHKeysPair) if (!m_DHKeysPair)
m_DHKeysPair = i2p::transports.GetNextDHKeysPair (); m_DHKeysPair = transports.GetNextDHKeysPair ();
CreateAESandMacKey (buf + sizeof (SSUHeader)); CreateAESandMacKey (buf + sizeof (SSUHeader));
SendSessionCreated (buf + sizeof (SSUHeader)); SendSessionCreated (buf + sizeof (SSUHeader));
} }
@ -215,10 +214,7 @@ namespace ssu
m_SessionKeyDecryption.SetIV (((SSUHeader *)buf)->iv); m_SessionKeyDecryption.SetIV (((SSUHeader *)buf)->iv);
m_SessionKeyDecryption.Decrypt (payload, 48, payload); m_SessionKeyDecryption.Decrypt (payload, 48, payload);
// verify // verify
CryptoPP::DSA::PublicKey pubKey; if (!m_RemoteIdentity.Verify (signedData, 532, payload))
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))
LogPrint ("SSU signature verification failed"); LogPrint ("SSU signature verification failed");
SendSessionConfirmed (y, ourAddress); SendSessionConfirmed (y, ourAddress);
@ -231,17 +227,15 @@ namespace ssu
payload++; // identity fragment info payload++; // identity fragment info
uint16_t identitySize = be16toh (*(uint16_t *)payload); uint16_t identitySize = be16toh (*(uint16_t *)payload);
payload += 2; // size of identity fragment payload += 2; // size of identity fragment
if (identitySize == i2p::data::DEFAULT_IDENTITY_SIZE) m_RemoteIdentity.FromBuffer (payload, identitySize);
{ m_Data.UpdatePacketSize (m_RemoteIdentity.GetIdentHash ());
i2p::data::Identity ident;
ident.FromBuffer (payload, identitySize);
m_RemoteIdent = ident.Hash ();
m_Data.UpdatePacketSize (m_RemoteIdent);
}
else
LogPrint ("SSU unexpected identity size ", identitySize);
payload += identitySize; // identity 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)); SendI2NPMessage (CreateDeliveryStatusMsg (0));
Established (); Established ();
} }
@ -360,10 +354,10 @@ namespace ssu
uint8_t * payload = buf + sizeof (SSUHeader); uint8_t * payload = buf + sizeof (SSUHeader);
*payload = 1; // 1 fragment *payload = 1; // 1 fragment
payload++; // info 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); *(uint16_t *)(payload) = htobe16 (identLen);
payload += 2; // cursize payload += 2; // cursize
memcpy (payload, (uint8_t *)&i2p::context.GetRouterIdentity (), identLen); memcpy (payload, (uint8_t *)&i2p::context.GetIdentity ().GetStandardIdentity (), identLen); // TODO
payload += identLen; payload += identLen;
uint32_t signedOnTime = i2p::util::GetSecondsSinceEpoch (); uint32_t signedOnTime = i2p::util::GetSecondsSinceEpoch ();
*(uint32_t *)(payload) = htobe32 (signedOnTime); // signed on time *(uint32_t *)(payload) = htobe32 (signedOnTime); // signed on time
@ -609,7 +603,7 @@ namespace ssu
{ {
// set connect timer // set connect timer
ScheduleConnectTimer (); ScheduleConnectTimer ();
m_DHKeysPair = i2p::transports.GetNextDHKeysPair (); m_DHKeysPair = transports.GetNextDHKeysPair ();
SendSessionRequest (); SendSessionRequest ();
} }
} }

9
SSU.h

@ -13,11 +13,12 @@
#include "Identity.h" #include "Identity.h"
#include "RouterInfo.h" #include "RouterInfo.h"
#include "I2NPProtocol.h" #include "I2NPProtocol.h"
#include "TransportSession.h"
#include "SSUData.h" #include "SSUData.h"
namespace i2p namespace i2p
{ {
namespace ssu namespace transport
{ {
#pragma pack(1) #pragma pack(1)
struct SSUHeader struct SSUHeader
@ -57,7 +58,7 @@ namespace ssu
}; };
class SSUServer; class SSUServer;
class SSUSession class SSUSession: public TransportSession
{ {
public: public:
@ -71,7 +72,6 @@ namespace ssu
void WaitForIntroduction (); void WaitForIntroduction ();
void Close (); void Close ();
boost::asio::ip::udp::endpoint& GetRemoteEndpoint () { return m_RemoteEndpoint; }; boost::asio::ip::udp::endpoint& GetRemoteEndpoint () { return m_RemoteEndpoint; };
const i2p::data::RouterInfo * GetRemoteRouter () const { return m_RemoteRouter; };
void SendI2NPMessage (I2NPMessage * msg); void SendI2NPMessage (I2NPMessage * msg);
void SendPeerTest (); // Alice void SendPeerTest (); // Alice
@ -128,10 +128,7 @@ namespace ssu
friend class SSUData; // TODO: change in later friend class SSUData; // TODO: change in later
SSUServer& m_Server; SSUServer& m_Server;
boost::asio::ip::udp::endpoint m_RemoteEndpoint; 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; boost::asio::deadline_timer m_Timer;
i2p::data::DHKeysPair * m_DHKeysPair; // X - for client and Y - for server
bool m_PeerTest; bool m_PeerTest;
SessionState m_State; SessionState m_State;
bool m_IsSessionKey; bool m_IsSessionKey;

2
SSUData.cpp

@ -8,7 +8,7 @@
namespace i2p namespace i2p
{ {
namespace ssu namespace transport
{ {
SSUData::SSUData (SSUSession& session): SSUData::SSUData (SSUSession& session):
m_Session (session), m_ResendTimer (session.m_Server.GetService ()) m_Session (session), m_ResendTimer (session.m_Server.GetService ())

2
SSUData.h

@ -13,7 +13,7 @@
namespace i2p namespace i2p
{ {
namespace ssu namespace transport
{ {
const size_t SSU_MTU = 1484; const size_t SSU_MTU = 1484;

161
Streaming.cpp

@ -1,3 +1,4 @@
#include <cryptopp/gzip.h>
#include "Log.h" #include "Log.h"
#include "RouterInfo.h" #include "RouterInfo.h"
#include "RouterContext.h" #include "RouterContext.h"
@ -11,12 +12,12 @@ namespace i2p
namespace stream namespace stream
{ {
Stream::Stream (boost::asio::io_service& service, StreamingDestination& local, 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_SequenceNumber (0), m_LastReceivedSequenceNumber (-1), m_IsOpen (false),
m_IsReset (false), m_IsAckSendScheduled (false), m_LocalDestination (local), m_IsReset (false), m_IsAckSendScheduled (false), m_LocalDestination (local),
m_RemoteLeaseSet (&remote), m_RoutingSession (nullptr), m_ReceiveTimer (m_Service), m_RemoteLeaseSet (&remote), m_RoutingSession (nullptr), m_ReceiveTimer (m_Service),
m_ResendTimer (m_Service), m_AckSendTimer (m_Service), m_NumSentBytes (0), 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 (); m_RecvStreamID = i2p::context.GetRandomNumberGenerator ().GenerateWord32 ();
UpdateCurrentRemoteLease (); UpdateCurrentRemoteLease ();
@ -27,7 +28,7 @@ namespace stream
m_IsOpen (false), m_IsReset (false), m_IsAckSendScheduled (false), m_LocalDestination (local), m_IsOpen (false), m_IsReset (false), m_IsAckSendScheduled (false), m_LocalDestination (local),
m_RemoteLeaseSet (nullptr), m_RoutingSession (nullptr), m_ReceiveTimer (m_Service), m_RemoteLeaseSet (nullptr), m_RoutingSession (nullptr), m_ReceiveTimer (m_Service),
m_ResendTimer (m_Service), m_AckSendTimer (m_Service), m_NumSentBytes (0), 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 (); m_RecvStreamID = i2p::context.GetRandomNumberGenerator ().GenerateWord32 ();
} }
@ -115,7 +116,7 @@ namespace stream
{ {
// we have received duplicate. Most likely our outbound tunnel is dead // we have received duplicate. Most likely our outbound tunnel is dead
LogPrint ("Duplicate message ", receivedSeqn, " received"); LogPrint ("Duplicate message ", receivedSeqn, " received");
m_LocalDestination.ResetCurrentOutboundTunnel (); // pick another outbound tunnel m_LocalDestination.GetOwner ().ResetCurrentOutboundTunnel (); // pick another outbound tunnel
UpdateCurrentRemoteLease (); // pick another lease UpdateCurrentRemoteLease (); // pick another lease
SendQuickAck (); // resend ack for previous message again SendQuickAck (); // resend ack for previous message again
delete packet; // packet dropped delete packet; // packet dropped
@ -274,11 +275,11 @@ namespace stream
if (isNoAck) flags |= PACKET_FLAG_NO_ACK; if (isNoAck) flags |= PACKET_FLAG_NO_ACK;
*(uint16_t *)(packet + size) = htobe16 (flags); *(uint16_t *)(packet + size) = htobe16 (flags);
size += 2; // flags size += 2; // flags
size_t identityLen = m_LocalDestination.GetIdentity ().GetFullLen (); size_t identityLen = m_LocalDestination.GetOwner ().GetIdentity ().GetFullLen ();
size_t signatureLen = m_LocalDestination.GetIdentity ().GetSignatureLen (); size_t signatureLen = m_LocalDestination.GetOwner ().GetIdentity ().GetSignatureLen ();
*(uint16_t *)(packet + size) = htobe16 (identityLen + signatureLen + 2); // identity + signature + packet size *(uint16_t *)(packet + size) = htobe16 (identityLen + signatureLen + 2); // identity + signature + packet size
size += 2; // options size size += 2; // options size
m_LocalDestination.GetIdentity ().ToBuffer (packet + size, identityLen); m_LocalDestination.GetOwner ().GetIdentity ().ToBuffer (packet + size, identityLen);
size += identityLen; // from size += identityLen; // from
*(uint16_t *)(packet + size) = htobe16 (STREAMING_MTU); *(uint16_t *)(packet + size) = htobe16 (STREAMING_MTU);
size += 2; // max packet size size += 2; // max packet size
@ -291,7 +292,7 @@ namespace stream
buf += sentLen; buf += sentLen;
len -= sentLen; len -= sentLen;
size += sentLen; // payload size += sentLen; // payload
m_LocalDestination.Sign (packet, size, signature); m_LocalDestination.GetOwner ().Sign (packet, size, signature);
} }
else else
{ {
@ -362,13 +363,13 @@ namespace stream
size++; // resend delay size++; // resend delay
*(uint16_t *)(packet + size) = htobe16 (PACKET_FLAG_CLOSE | PACKET_FLAG_SIGNATURE_INCLUDED); *(uint16_t *)(packet + size) = htobe16 (PACKET_FLAG_CLOSE | PACKET_FLAG_SIGNATURE_INCLUDED);
size += 2; // flags 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 *(uint16_t *)(packet + size) = htobe16 (signatureLen); // signature only
size += 2; // options size size += 2; // options size
uint8_t * signature = packet + size; uint8_t * signature = packet + size;
memset (packet + size, 0, signatureLen); memset (packet + size, 0, signatureLen);
size += signatureLen; // signature size += signatureLen; // signature
m_LocalDestination.Sign (packet, size, signature); m_LocalDestination.GetOwner ().Sign (packet, size, signature);
p->len = size; p->len = size;
SendPacket (p); SendPacket (p);
@ -440,8 +441,7 @@ namespace stream
std::vector<i2p::tunnel::TunnelMessageBlock> msgs; std::vector<i2p::tunnel::TunnelMessageBlock> msgs;
for (auto it: packets) for (auto it: packets)
{ {
auto msg = m_RoutingSession->WrapSingleMessage ( auto msg = m_RoutingSession->WrapSingleMessage (CreateDataMessage (it->GetBuffer (), it->GetLength ()));
m_LocalDestination.CreateDataMessage (it->GetBuffer (), it->GetLength ()));
msgs.push_back (i2p::tunnel::TunnelMessageBlock msgs.push_back (i2p::tunnel::TunnelMessageBlock
{ {
i2p::tunnel::eDeliveryTypeTunnel, i2p::tunnel::eDeliveryTypeTunnel,
@ -450,7 +450,7 @@ namespace stream
}); });
m_NumSentBytes += it->GetLength (); m_NumSentBytes += it->GetLength ();
} }
m_LocalDestination.SendTunnelDataMsgs (msgs); m_LocalDestination.GetOwner ().SendTunnelDataMsgs (msgs);
} }
else else
LogPrint ("All leases are expired"); LogPrint ("All leases are expired");
@ -484,7 +484,7 @@ namespace stream
} }
if (packets.size () > 0) if (packets.size () > 0)
{ {
m_LocalDestination.ResetCurrentOutboundTunnel (); // pick another outbound tunnel m_LocalDestination.GetOwner ().ResetCurrentOutboundTunnel (); // pick another outbound tunnel
UpdateCurrentRemoteLease (); // pick another lease UpdateCurrentRemoteLease (); // pick another lease
SendPackets (packets); SendPackets (packets);
} }
@ -506,14 +506,14 @@ namespace stream
{ {
if (!m_RemoteLeaseSet) if (!m_RemoteLeaseSet)
{ {
m_RemoteLeaseSet = m_LocalDestination.FindLeaseSet (m_RemoteIdentity.GetIdentHash ()); m_RemoteLeaseSet = m_LocalDestination.GetOwner ().FindLeaseSet (m_RemoteIdentity.GetIdentHash ());
if (!m_RemoteLeaseSet) if (!m_RemoteLeaseSet)
LogPrint ("LeaseSet ", m_RemoteIdentity.GetIdentHash ().ToBase64 (), " not found"); LogPrint ("LeaseSet ", m_RemoteIdentity.GetIdentHash ().ToBase64 (), " not found");
} }
if (m_RemoteLeaseSet) if (m_RemoteLeaseSet)
{ {
if (!m_RoutingSession) 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 (); auto leases = m_RemoteLeaseSet->GetNonExpiredLeases ();
if (!leases.empty ()) if (!leases.empty ())
{ {
@ -522,12 +522,139 @@ namespace stream
} }
else 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; m_CurrentRemoteLease.endDate = 0;
} }
} }
else else
m_CurrentRemoteLease.endDate = 0; m_CurrentRemoteLease.endDate = 0;
}
I2NPMessage * Stream::CreateDataMessage (const uint8_t * payload, size_t len)
{
I2NPMessage * msg = NewI2NPShortMessage ();
CryptoPP::Gzip compressor;
if (len <= i2p::stream::COMPRESSION_THRESHOLD_SIZE)
compressor.SetDeflateLevel (CryptoPP::Gzip::MIN_DEFLATE_LEVEL);
else
compressor.SetDeflateLevel (CryptoPP::Gzip::DEFAULT_DEFLATE_LEVEL);
compressor.Put (payload, len);
compressor.MessageEnd();
int size = compressor.MaxRetrievable ();
uint8_t * buf = msg->GetPayload ();
*(uint32_t *)buf = htobe32 (size); // length
buf += 4;
compressor.Get (buf, size);
*(uint16_t *)(buf + 4) = 0; // source port
*(uint16_t *)(buf + 6) = htobe16 (m_Port); // destination port
buf[9] = i2p::client::PROTOCOL_TYPE_STREAMING; // streaming protocol
msg->len += size + 4;
FillI2NPMessageHeader (msg, eI2NPData);
return msg;
}
void StreamingDestination::Start ()
{
}
void StreamingDestination::Stop ()
{
ResetAcceptor ();
{
std::unique_lock<std::mutex> l(m_StreamsMutex);
for (auto it: m_Streams)
delete it.second;
m_Streams.clear ();
}
}
void StreamingDestination::HandleNextPacket (Packet * packet)
{
uint32_t sendStreamID = packet->GetSendStreamID ();
if (sendStreamID)
{
auto it = m_Streams.find (sendStreamID);
if (it != m_Streams.end ())
it->second->HandleNextPacket (packet);
else
{
LogPrint ("Unknown stream ", sendStreamID);
delete packet;
}
}
else // new incoming stream
{
auto incomingStream = CreateNewIncomingStream ();
incomingStream->HandleNextPacket (packet);
if (m_Acceptor != nullptr)
m_Acceptor (incomingStream);
else
{
LogPrint ("Acceptor for incoming stream is not set");
DeleteStream (incomingStream);
}
}
}
Stream * StreamingDestination::CreateNewOutgoingStream (const i2p::data::LeaseSet& remote, int port)
{
Stream * s = new Stream (*m_Owner.GetService (), *this, remote, port);
std::unique_lock<std::mutex> l(m_StreamsMutex);
m_Streams[s->GetRecvStreamID ()] = s;
return s;
}
Stream * StreamingDestination::CreateNewIncomingStream ()
{
Stream * s = new Stream (*m_Owner.GetService (), *this);
std::unique_lock<std::mutex> l(m_StreamsMutex);
m_Streams[s->GetRecvStreamID ()] = s;
return s;
}
void StreamingDestination::DeleteStream (Stream * stream)
{
if (stream)
{
std::unique_lock<std::mutex> l(m_StreamsMutex);
auto it = m_Streams.find (stream->GetRecvStreamID ());
if (it != m_Streams.end ())
{
m_Streams.erase (it);
if (m_Owner.GetService ())
m_Owner.GetService ()->post ([stream](void) { delete stream; });
else
delete stream;
}
}
} }
void StreamingDestination::HandleDataMessagePayload (const uint8_t * buf, size_t len)
{
// unzip it
CryptoPP::Gunzip decompressor;
decompressor.Put (buf, len);
decompressor.MessageEnd();
Packet * uncompressed = new Packet;
uncompressed->offset = 0;
uncompressed->len = decompressor.MaxRetrievable ();
if (uncompressed->len <= MAX_PACKET_SIZE)
{
decompressor.Get (uncompressed->buf, uncompressed->len);
HandleNextPacket (uncompressed);
}
else
{
LogPrint ("Received packet size ", uncompressed->len, " exceeds max packet size. Skipped");
delete uncompressed;
}
}
void DeleteStream (Stream * stream)
{
if (stream)
stream->GetLocalDestination ().DeleteStream (stream);
}
} }
} }

49
Streaming.h

@ -18,6 +18,10 @@
namespace i2p namespace i2p
{ {
namespace client
{
class ClientDestination;
}
namespace stream namespace stream
{ {
const uint16_t PACKET_FLAG_SYNCHRONIZE = 0x0001; const uint16_t PACKET_FLAG_SYNCHRONIZE = 0x0001;
@ -78,7 +82,8 @@ namespace stream
{ {
public: 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 (boost::asio::io_service& service, StreamingDestination& local); // incoming
~Stream (); ~Stream ();
@ -122,6 +127,8 @@ namespace stream
void ScheduleResend (); void ScheduleResend ();
void HandleResendTimer (const boost::system::error_code& ecode); void HandleResendTimer (const boost::system::error_code& ecode);
void HandleAckSendTimer (const boost::system::error_code& ecode); void HandleAckSendTimer (const boost::system::error_code& ecode);
I2NPMessage * CreateDataMessage (const uint8_t * payload, size_t len);
private: private:
@ -139,8 +146,48 @@ namespace stream
std::set<Packet *, PacketCmp> m_SentPackets; std::set<Packet *, PacketCmp> m_SentPackets;
boost::asio::deadline_timer m_ReceiveTimer, m_ResendTimer, m_AckSendTimer; boost::asio::deadline_timer m_ReceiveTimer, m_ResendTimer, m_AckSendTimer;
size_t m_NumSentBytes, m_NumReceivedBytes; 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> template<typename Buffer, typename ReceiveHandler>

2
TransitTunnel.cpp

@ -34,7 +34,7 @@ namespace tunnel
*(uint32_t *)(tunnelMsg->GetPayload ()) = htobe32 (m_NextTunnelID); *(uint32_t *)(tunnelMsg->GetPayload ()) = htobe32 (m_NextTunnelID);
FillI2NPMessageHeader (tunnelMsg, eI2NPTunnelData); FillI2NPMessageHeader (tunnelMsg, eI2NPTunnelData);
i2p::transports.SendMessage (m_NextIdent, tunnelMsg); i2p::transport::transports.SendMessage (m_NextIdent, tunnelMsg);
} }
void TransitTunnel::SendTunnelDataMsg (i2p::I2NPMessage * msg) void TransitTunnel::SendTunnelDataMsg (i2p::I2NPMessage * msg)

43
TransportSession.h

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

91
Transports.cpp

@ -1,5 +1,7 @@
#include <cryptopp/dh.h>
#include <boost/bind.hpp> #include <boost/bind.hpp>
#include "Log.h" #include "Log.h"
#include "CryptoConst.h"
#include "RouterContext.h" #include "RouterContext.h"
#include "I2NPProtocol.h" #include "I2NPProtocol.h"
#include "NetDb.h" #include "NetDb.h"
@ -9,6 +11,13 @@ using namespace i2p::data;
namespace i2p namespace i2p
{ {
namespace transport
{
DHKeysPairSupplier::DHKeysPairSupplier (int size):
m_QueueSize (size), m_IsRunning (false), m_Thread (nullptr)
{
}
DHKeysPairSupplier::~DHKeysPairSupplier () DHKeysPairSupplier::~DHKeysPairSupplier ()
{ {
Stop (); Stop ();
@ -48,17 +57,18 @@ namespace i2p
{ {
if (num > 0) if (num > 0)
{ {
CryptoPP::DH dh (i2p::crypto::elgp, i2p::crypto::elgg);
for (int i = 0; i < num; i++) for (int i = 0; i < num; i++)
{ {
i2p::data::DHKeysPair * pair = new i2p::data::DHKeysPair (); i2p::transport::DHKeysPair * pair = new i2p::transport::DHKeysPair ();
i2p::data::CreateRandomDHKeysPair (pair); dh.GenerateKeyPair(m_Rnd, pair->privateKey, pair->publicKey);
std::unique_lock<std::mutex> l(m_AcquiredMutex); std::unique_lock<std::mutex> l(m_AcquiredMutex);
m_Queue.push (pair); m_Queue.push (pair);
} }
} }
} }
i2p::data::DHKeysPair * DHKeysPairSupplier::Acquire () DHKeysPair * DHKeysPairSupplier::Acquire ()
{ {
if (!m_Queue.empty ()) if (!m_Queue.empty ())
{ {
@ -70,13 +80,14 @@ namespace i2p
} }
else // queue is empty, create new else // queue is empty, create new
{ {
i2p::data::DHKeysPair * pair = new i2p::data::DHKeysPair (); DHKeysPair * pair = new DHKeysPair ();
i2p::data::CreateRandomDHKeysPair (pair); CryptoPP::DH dh (i2p::crypto::elgp, i2p::crypto::elgg);
dh.GenerateKeyPair(m_Rnd, pair->privateKey, pair->publicKey);
return pair; return pair;
} }
} }
void DHKeysPairSupplier::Return (i2p::data::DHKeysPair * pair) void DHKeysPairSupplier::Return (DHKeysPair * pair)
{ {
std::unique_lock<std::mutex> l(m_AcquiredMutex); std::unique_lock<std::mutex> l(m_AcquiredMutex);
m_Queue.push (pair); m_Queue.push (pair);
@ -85,7 +96,7 @@ namespace i2p
Transports transports; Transports transports;
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 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)); boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), address.port));
LogPrint ("Start listening TCP port ", 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, m_NTCPAcceptor->async_accept(conn->GetSocket (), boost::bind (&Transports::HandleAccept, this,
conn, boost::asio::placeholders::error)); 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) else if (address.transportStyle == RouterInfo::eTransportSSU)
{ {
if (!m_SSUServer) if (!m_SSUServer)
{ {
m_SSUServer = new i2p::ssu::SSUServer (address.port); m_SSUServer = new SSUServer (address.port);
LogPrint ("Start listening UDP port ", address.port); LogPrint ("Start listening UDP port ", address.port);
m_SSUServer->Start (); m_SSUServer->Start ();
DetectExternalIP (); DetectExternalIP ();
@ -143,6 +165,8 @@ namespace i2p
m_NTCPSessions.clear (); m_NTCPSessions.clear ();
delete m_NTCPAcceptor; delete m_NTCPAcceptor;
m_NTCPAcceptor = nullptr; m_NTCPAcceptor = nullptr;
delete m_NTCPV6Acceptor;
m_NTCPV6Acceptor = nullptr;
m_DHKeysPairSupplier.Stop (); m_DHKeysPairSupplier.Stop ();
m_IsRunning = false; m_IsRunning = false;
@ -170,19 +194,19 @@ namespace i2p
} }
} }
void Transports::AddNTCPSession (i2p::ntcp::NTCPSession * session) void Transports::AddNTCPSession (NTCPSession * session)
{ {
if (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) 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) if (!error)
{ {
@ -194,13 +218,31 @@ namespace i2p
if (error != boost::asio::error::operation_aborted) 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, m_NTCPAcceptor->async_accept(conn->GetSocket (), boost::bind (&Transports::HandleAccept, this,
conn, boost::asio::placeholders::error)); 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) for (auto session: m_NTCPSessions)
if (session.second->IsEstablished ()) if (session.second->IsEstablished ())
@ -208,7 +250,7 @@ namespace i2p
return 0; 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); auto it = m_NTCPSessions.find (ident);
if (it != m_NTCPSessions.end ()) if (it != m_NTCPSessions.end ())
@ -242,10 +284,10 @@ namespace i2p
{ {
// existing session not found. create new // existing session not found. create new
// try NTCP first if message size < 16K // try NTCP first if message size < 16K
auto address = r->GetNTCPAddress (); auto address = r->GetNTCPAddress (!context.SupportsV6 ());
if (address && !r->UsesIntroducer () && !r->IsUnreachable () && msg->GetLength () < i2p::ntcp::NTCP_MAX_MESSAGE_SIZE) 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); AddNTCPSession (s);
s->SendI2NPMessage (msg); s->SendI2NPMessage (msg);
} }
@ -318,15 +360,16 @@ namespace i2p
m_SSUServer->GetSession (router, true); // peer test m_SSUServer->GetSession (router, true); // peer test
} }
} }
DHKeysPair * Transports::GetNextDHKeysPair ()
i2p::data::DHKeysPair * Transports::GetNextDHKeysPair ()
{ {
return m_DHKeysPairSupplier.Acquire (); return m_DHKeysPairSupplier.Acquire ();
} }
void Transports::ReuseDHKeysPair (i2p::data::DHKeysPair * pair) void Transports::ReuseDHKeysPair (DHKeysPair * pair)
{ {
m_DHKeysPairSupplier.Return (pair); m_DHKeysPairSupplier.Return (pair);
} }
} }
}

37
Transports.h

@ -8,7 +8,9 @@
#include <map> #include <map>
#include <queue> #include <queue>
#include <string> #include <string>
#include <cryptopp/osrng.h>
#include <boost/asio.hpp> #include <boost/asio.hpp>
#include "TransportSession.h"
#include "NTCPSession.h" #include "NTCPSession.h"
#include "SSU.h" #include "SSU.h"
#include "RouterInfo.h" #include "RouterInfo.h"
@ -16,17 +18,19 @@
#include "Identity.h" #include "Identity.h"
namespace i2p namespace i2p
{
namespace transport
{ {
class DHKeysPairSupplier class DHKeysPairSupplier
{ {
public: public:
DHKeysPairSupplier (int size): m_QueueSize (size), m_IsRunning (false), m_Thread (nullptr) {}; DHKeysPairSupplier (int size);
~DHKeysPairSupplier (); ~DHKeysPairSupplier ();
void Start (); void Start ();
void Stop (); void Stop ();
i2p::data::DHKeysPair * Acquire (); DHKeysPair * Acquire ();
void Return (i2p::data::DHKeysPair * pair); void Return (DHKeysPair * pair);
private: private:
@ -36,12 +40,13 @@ namespace i2p
private: private:
const int m_QueueSize; const int m_QueueSize;
std::queue<i2p::data::DHKeysPair *> m_Queue; std::queue<DHKeysPair *> m_Queue;
bool m_IsRunning; bool m_IsRunning;
std::thread * m_Thread; std::thread * m_Thread;
std::condition_variable m_Acquired; std::condition_variable m_Acquired;
std::mutex m_AcquiredMutex; std::mutex m_AcquiredMutex;
CryptoPP::AutoSeededRandomPool m_Rnd;
}; };
class Transports class Transports
@ -55,14 +60,14 @@ namespace i2p
void Stop (); void Stop ();
boost::asio::io_service& GetService () { return m_Service; }; boost::asio::io_service& GetService () { return m_Service; };
i2p::data::DHKeysPair * GetNextDHKeysPair (); i2p::transport::DHKeysPair * GetNextDHKeysPair ();
void ReuseDHKeysPair (i2p::data::DHKeysPair * pair); void ReuseDHKeysPair (DHKeysPair * pair);
void AddNTCPSession (i2p::ntcp::NTCPSession * session); void AddNTCPSession (NTCPSession * session);
void RemoveNTCPSession (i2p::ntcp::NTCPSession * session); void RemoveNTCPSession (NTCPSession * session);
i2p::ntcp::NTCPSession * GetNextNTCPSession (); NTCPSession * GetNextNTCPSession ();
i2p::ntcp::NTCPSession * FindNTCPSession (const i2p::data::IdentHash& ident); NTCPSession * FindNTCPSession (const i2p::data::IdentHash& ident);
void SendMessage (const i2p::data::IdentHash& ident, i2p::I2NPMessage * msg); void SendMessage (const i2p::data::IdentHash& ident, i2p::I2NPMessage * msg);
void CloseSession (const i2p::data::RouterInfo * router); void CloseSession (const i2p::data::RouterInfo * router);
@ -70,7 +75,8 @@ namespace i2p
private: private:
void Run (); 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, void HandleResendTimer (const boost::system::error_code& ecode, boost::asio::deadline_timer * timer,
const i2p::data::IdentHash& ident, i2p::I2NPMessage * msg); const i2p::data::IdentHash& ident, i2p::I2NPMessage * msg);
void PostMessage (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; std::thread * m_Thread;
boost::asio::io_service m_Service; boost::asio::io_service m_Service;
boost::asio::io_service::work m_Work; 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; std::map<i2p::data::IdentHash, NTCPSession *> m_NTCPSessions;
i2p::ssu::SSUServer * m_SSUServer; SSUServer * m_SSUServer;
DHKeysPairSupplier m_DHKeysPairSupplier; DHKeysPairSupplier m_DHKeysPairSupplier;
@ -95,10 +101,11 @@ namespace i2p
// for HTTP only // for HTTP only
const decltype(m_NTCPSessions)& GetNTCPSessions () const { return m_NTCPSessions; }; 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; extern Transports transports;
} }
}
#endif #endif

2
Tunnel.cpp

@ -92,7 +92,7 @@ namespace tunnel
if (outboundTunnel) if (outboundTunnel)
outboundTunnel->SendTunnelDataMsg (GetNextIdentHash (), 0, msg); outboundTunnel->SendTunnelDataMsg (GetNextIdentHash (), 0, msg);
else else
i2p::transports.SendMessage (GetNextIdentHash (), msg); i2p::transport::transports.SendMessage (GetNextIdentHash (), msg);
} }
bool Tunnel::HandleTunnelBuildResponse (uint8_t * msg, size_t len) bool Tunnel::HandleTunnelBuildResponse (uint8_t * msg, size_t len)

4
TunnelEndpoint.cpp

@ -235,7 +235,7 @@ namespace tunnel
i2p::HandleI2NPMessage (msg.data); i2p::HandleI2NPMessage (msg.data);
break; break;
case eDeliveryTypeTunnel: 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; break;
case eDeliveryTypeRouter: case eDeliveryTypeRouter:
if (msg.hash == i2p::context.GetRouterInfo ().GetIdentHash ()) // check if message is sent to us if (msg.hash == i2p::context.GetRouterInfo ().GetIdentHash ()) // check if message is sent to us
@ -253,7 +253,7 @@ namespace tunnel
*ds = *(msg.data); *ds = *(msg.data);
i2p::data::netdb.PostI2NPMsg (ds); 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 else // we shouldn't send this message. possible leakage
{ {

21
TunnelGateway.cpp

@ -12,8 +12,12 @@ namespace tunnel
{ {
void TunnelGatewayBuffer::PutI2NPMsg (const TunnelMessageBlock& block) void TunnelGatewayBuffer::PutI2NPMsg (const TunnelMessageBlock& block)
{ {
bool messageCreated = false;
if (!m_CurrentTunnelDataMsg) if (!m_CurrentTunnelDataMsg)
{
CreateCurrentTunnelDataMessage (); CreateCurrentTunnelDataMessage ();
messageCreated = true;
}
// create delivery instructions // create delivery instructions
uint8_t di[43]; // max delivery instruction length is 43 for tunnel uint8_t di[43]; // max delivery instruction length is 43 for tunnel
@ -33,7 +37,8 @@ namespace tunnel
// create fragments // create fragments
I2NPMessage * msg = block.data; 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 // message fits. First and last fragment
*(uint16_t *)(di + diLen) = htobe16 (msg->GetLength ()); *(uint16_t *)(di + diLen) = htobe16 (msg->GetLength ());
@ -48,6 +53,18 @@ namespace tunnel
} }
else 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) if (diLen + 6 <= m_RemainingSize)
{ {
// delivery instructions fit // delivery instructions fit
@ -169,7 +186,7 @@ namespace tunnel
{ {
m_Tunnel->EncryptTunnelMsg (tunnelMsg); m_Tunnel->EncryptTunnelMsg (tunnelMsg);
FillI2NPMessageHeader (tunnelMsg, eI2NPTunnelData); 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_NumSentBytes += TUNNEL_DATA_MSG_SIZE;
} }
m_Buffer.ClearTunnelDataMsgs (); m_Buffer.ClearTunnelDataMsgs ();

2
TunnelPool.cpp

@ -257,7 +257,7 @@ namespace tunnel
{ {
// last hop // last hop
auto hop = outboundTunnel->GetTunnelConfig ()->GetFirstHop ()->router; 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; prevHop = hop;
hops.push_back (prevHop); hops.push_back (prevHop);

2
TunnelPool.h

@ -33,7 +33,7 @@ namespace tunnel
const uint8_t * GetEncryptionPublicKey () const { return m_LocalDestination.GetEncryptionPublicKey (); }; const uint8_t * GetEncryptionPublicKey () const { return m_LocalDestination.GetEncryptionPublicKey (); };
const i2p::data::LocalDestination& GetLocalDestination () const { return m_LocalDestination; }; const i2p::data::LocalDestination& GetLocalDestination () const { return m_LocalDestination; };
i2p::garlic::GarlicDestination& GetGarlicDestination () 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 CreateTunnels ();
void TunnelCreated (InboundTunnel * createdTunnel); void TunnelCreated (InboundTunnel * createdTunnel);

3
Win32/i2pd.vcxproj

@ -47,6 +47,7 @@
<ClCompile Include="..\SOCKS.cpp" /> <ClCompile Include="..\SOCKS.cpp" />
<ClCompile Include="..\I2PTunnel.cpp" /> <ClCompile Include="..\I2PTunnel.cpp" />
<ClCompile Include="..\ClientContext.cpp" /> <ClCompile Include="..\ClientContext.cpp" />
<ClCompile Include="..\Datagram.cpp" />
<ClCompile Include="Win32Service.cpp" /> <ClCompile Include="Win32Service.cpp" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
@ -91,6 +92,8 @@
<ClInclude Include="..\version.h" /> <ClInclude Include="..\version.h" />
<ClInclude Include="..\Signature.h" /> <ClInclude Include="..\Signature.h" />
<ClInclude Include="..\ClientContext.h" /> <ClInclude Include="..\ClientContext.h" />
<ClCompile Include="..\TransportSession.h" />
<ClCompile Include="..\Datagram.h" />
<ClInclude Include="Win32Service.h" /> <ClInclude Include="Win32Service.h" />
</ItemGroup> </ItemGroup>
<PropertyGroup Label="Globals"> <PropertyGroup Label="Globals">

3
build/CMakeLists.txt

@ -43,7 +43,8 @@ set (SOURCES
"${CMAKE_SOURCE_DIR}/i2p.cpp" "${CMAKE_SOURCE_DIR}/i2p.cpp"
"${CMAKE_SOURCE_DIR}/util.cpp" "${CMAKE_SOURCE_DIR}/util.cpp"
"${CMAKE_SOURCE_DIR}/SAM.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") file (GLOB HEADERS "${CMAKE_SOURCE_DIR}/*.h")

6
build/autotools/Makefile.in

@ -325,7 +325,7 @@ i2p_SOURCES = AddressBook.cpp CryptoConst.cpp Daemon.cpp \
Transports.cpp Tunnel.cpp TunnelEndpoint.cpp \ Transports.cpp Tunnel.cpp TunnelEndpoint.cpp \
TunnelGateway.cpp TunnelPool.cpp UPnP.cpp aes.cpp \ TunnelGateway.cpp TunnelPool.cpp UPnP.cpp aes.cpp \
base64.cpp i2p.cpp util.cpp SAM.cpp Destination.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 \ AddressBook.h CryptoConst.h Daemon.h ElGamal.h \
Garlic.h HTTPProxy.h HTTPServer.h I2NPProtocol.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 \ TransitTunnel.h Transports.h Tunnel.h TunnelBase.h \
TunnelConfig.h TunnelEndpoint.h TunnelGateway.h \ TunnelConfig.h TunnelEndpoint.h TunnelGateway.h \
TunnelPool.h UPnP.h aes.h base64.h config.h hmac.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@ \ AM_LDFLAGS = @BOOST_DATE_TIME_LIB@ @BOOST_FILESYSTEM_LIB@ \
@BOOST_PROGRAM_OPTIONS_LIB@ @BOOST_REGEX_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)/util.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SAM.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)/ClientContext.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Datagram.Po@am__quote@
.cpp.o: .cpp.o:
@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<

22
debian/init.d → debian/i2pd.init vendored

@ -57,10 +57,10 @@ do_stop()
} }
# Function that sends a SIGHUP to the daemon/service # Function that sends a SIGHUP to the daemon/service
#do_reload() { do_reload() {
# start-stop-daemon --stop --signal 1 --quiet --pidfile $PIDFILE --name $NAME start-stop-daemon --stop --signal 1 --quiet --pidfile $PIDFILE --name $NAME
# return 0 return 0
#} }
case "$1" in case "$1" in
start) start)
@ -82,14 +82,12 @@ case "$1" in
status) status)
status_of_proc "$DAEMON" "$NAME" && exit 0 || exit $? status_of_proc "$DAEMON" "$NAME" && exit 0 || exit $?
;; ;;
#reload|force-reload) reload|force-reload)
#log_daemon_msg "Reloading $DESC" "$NAME" log_daemon_msg "Reloading $DESC" "$NAME"
#do_reload do_reload
#log_end_msg $? log_end_msg $?
#;; ;;
restart|force-reload) restart)
# If the "reload" option is implemented then remove the
# 'force-reload' alias
log_daemon_msg "Restarting $DESC" "$NAME" log_daemon_msg "Restarting $DESC" "$NAME"
do_stop do_stop
case "$?" in case "$?" in

10
debian/i2pd.upstart vendored

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

4
filelist.mk

@ -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 \ 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 \ 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 \ 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 \ 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 \ 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 \ 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 \ 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))) OBJECTS = $(addprefix obj/, $(notdir $(CPP_FILES:.cpp=.o)))

Loading…
Cancel
Save