Browse Source

Merge pull request #26 from orignal/master

Merge pull request from orignal/master
pull/52/head
chertov 11 years ago
parent
commit
85884a5b84
  1. 2
      .gitignore
  2. 28
      .travis.yml
  3. 70
      AddressBook.cpp
  4. 44
      AddressBook.h
  5. 4
      HTTPServer.cpp
  6. 6
      I2PEndian.h
  7. 8
      Identity.cpp
  8. 12
      Identity.h
  9. 2
      Makefile
  10. 27
      NTCPSession.cpp
  11. 4
      NTCPSession.h
  12. 11
      NetDb.cpp
  13. 2
      README.md
  14. 9
      RouterContext.h
  15. 65
      SSU.cpp
  16. 8
      SSU.h
  17. 9
      Streaming.cpp
  18. 4
      Streaming.h
  19. 76
      Transports.cpp
  20. 33
      Transports.h
  21. 123
      Tunnel.cpp
  22. 14
      Tunnel.h
  23. 25
      TunnelPool.cpp
  24. 15
      TunnelPool.h
  25. 113
      build/CMakeLists.txt
  26. 35
      build/cmake_modules/FindCryptoPP.cmake

2
.gitignore vendored

@ -53,7 +53,6 @@ local.properties
[Dd]ebug/ [Dd]ebug/
[Rr]elease/ [Rr]elease/
x64/ x64/
build/
[Bb]in/ [Bb]in/
[Oo]bj/ [Oo]bj/
@ -200,7 +199,6 @@ $RECYCLE.BIN/
*.egg *.egg
*.egg-info *.egg-info
dist/ dist/
build/
eggs/ eggs/
parts/ parts/
var/ var/

28
.travis.yml

@ -0,0 +1,28 @@
language: cpp
compiler: gcc
cache: apt
branches:
only:
- master
before_install:
- sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test # GCC 4.7
- sudo add-apt-repository -y "deb http://archive.ubuntu.com/ubuntu/ quantal main universe" # Boost 1.50
- sudo apt-get update -qq
- sudo apt-get install -qq libboost1.50-all-dev libcrypto++9 libcrypto++-dev
script:
- make
notifications:
email:
recipients:
- meeh@sigterm.no
on_success: change
on_failure: always
irc:
channels:
- "irc.freenode.net#i2p-dev"
template:
- "%{repository}/%{branch} (%{commit} - %{author}): %{message}"
on_failure: always
on_success: change

70
AddressBook.cpp

@ -0,0 +1,70 @@
#include <string.h>
#include <string>
#include <map>
#include "base64.h"
#include "util.h"
#include "Identity.h"
#include "Log.h"
#include "AddressBook.h"
namespace i2p
{
namespace data
{
AddressBook::AddressBook (): m_IsLoaded (false)
{
}
const IdentHash * AddressBook::FindAddress (const std::string& address)
{
if (!m_IsLoaded)
LoadHosts ();
auto it = m_Addresses.find (address);
if (it != m_Addresses.end ())
return &it->second;
else
return nullptr;
}
void AddressBook::LoadHosts ()
{
m_IsLoaded = true;
std::ifstream f (i2p::util::filesystem::GetFullPath ("hosts.txt").c_str (), std::ofstream::in); // in text mode
if (!f.is_open ())
{
LogPrint ("hosts.txt not found");
return;
}
int numAddresses = 0;
std::string s;
while (!f.eof ())
{
getline(f, s);
if (!s.length())
break;
size_t pos = s.find('=');
if (pos != std::string::npos)
{
std::string name = s.substr(0, pos++);
std::string addr = s.substr(pos);
Identity ident;
Base64ToByteStream (addr.c_str(), addr.length(), (uint8_t *)&ident, sizeof (ident));
m_Addresses[name] = CalculateIdentHash (ident);
numAddresses++;
}
}
LogPrint (numAddresses, " addresses loaded");
}
}
}

44
AddressBook.h

@ -17,50 +17,12 @@ namespace data
{ {
public: public:
AddressBook (): m_IsLoaded (false) {}; AddressBook ();
const IdentHash * FindAddress (const std::string& address);
const IdentHash * FindAddress (const std::string& address)
{
if (!m_IsLoaded)
LoadHosts ();
auto it = m_Addresses.find (address);
if (it != m_Addresses.end ())
return &it->second;
else
return nullptr;
}
private: private:
void LoadHosts () void LoadHosts ();
{
m_IsLoaded = true;
std::ifstream f (i2p::util::filesystem::GetFullPath ("hosts.txt").c_str (), std::ofstream::in); // in text mode
if (!f.is_open ())
{
LogPrint ("hosts.txt not found");
return;
}
int numAddresses = 0;
char str[1024];
while (!f.eof ())
{
f.getline (str, 1024);
char * key = strchr (str, '=');
if (key)
{
*key = 0;
key++;
Identity ident;
Base64ToByteStream (key, strlen(key), (uint8_t *)&ident, sizeof (ident));
m_Addresses[str] = CalculateIdentHash (ident);
numAddresses++;
}
}
LogPrint (numAddresses, " addresses loaded");
}
private:
std::map<std::string, IdentHash> m_Addresses; std::map<std::string, IdentHash> m_Addresses;
bool m_IsLoaded; bool m_IsLoaded;

4
HTTPServer.cpp

@ -245,7 +245,7 @@ namespace util
for (auto it: i2p::tunnel::tunnels.GetOutboundTunnels ()) for (auto it: i2p::tunnel::tunnels.GetOutboundTunnels ())
{ {
it->GetTunnelConfig ()->Print (s); it->GetTunnelConfig ()->Print (s);
if (it->GetTunnelPool ()) if (it->GetTunnelPool () && !it->GetTunnelPool ()->IsExploratory ())
s << " " << "Pool"; s << " " << "Pool";
if (it->IsFailed ()) if (it->IsFailed ())
s << " " << "Failed"; s << " " << "Failed";
@ -255,7 +255,7 @@ namespace util
for (auto it: i2p::tunnel::tunnels.GetInboundTunnels ()) for (auto it: i2p::tunnel::tunnels.GetInboundTunnels ())
{ {
it.second->GetTunnelConfig ()->Print (s); it.second->GetTunnelConfig ()->Print (s);
if (it.second->GetTunnelPool ()) if (it.second->GetTunnelPool () && !it.second->GetTunnelPool ()->IsExploratory ())
s << " " << "Pool"; s << " " << "Pool";
if (it.second->IsFailed ()) if (it.second->IsFailed ())
s << " " << "Failed"; s << " " << "Failed";

6
I2PEndian.h

@ -1,8 +1,12 @@
#ifndef I2PENDIAN_H__ #ifndef I2PENDIAN_H__
#define I2PENDIAN_H__ #define I2PENDIAN_H__
#ifndef _WIN32 #ifdef __linux__
#include <endian.h> #include <endian.h>
#elif __FreeBSD__
#include <sys/endian.h>
#elif __MACH__ // Mac OS X
#include <machine/endian.h>
#else #else
#include <cstdint> #include <cstdint>

8
Identity.cpp

@ -53,6 +53,14 @@ 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);
}
RoutingKey CreateRoutingKey (const IdentHash& ident) RoutingKey CreateRoutingKey (const IdentHash& ident)
{ {
uint8_t buf[41]; // ident + yyyymmdd uint8_t buf[41]; // ident + yyyymmdd

12
Identity.h

@ -11,6 +11,12 @@ namespace data
{ {
#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];
@ -71,6 +77,7 @@ namespace data
IdentHash CalculateIdentHash (const Identity& identity); IdentHash CalculateIdentHash (const Identity& identity);
Keys CreateRandomKeys (); Keys CreateRandomKeys ();
void CreateRandomDHKeysPair (DHKeysPair * keys); // for transport sessions
// kademlia // kademlia
struct RoutingKey struct RoutingKey
@ -118,7 +125,10 @@ namespace data
{ {
public: public:
virtual void UpdateLeaseSet () = 0; // LeaseSet must be update virtual const IdentHash& GetIdentHash () const = 0;
virtual const uint8_t * GetEncryptionPrivateKey () const = 0;
virtual const uint8_t * GetEncryptionPublicKey () const = 0;
virtual void UpdateLeaseSet () = 0; // LeaseSet must be updated
}; };
} }
} }

2
Makefile

@ -5,7 +5,7 @@ OBJECTS = obj/i2p.o obj/base64.o obj/NTCPSession.o obj/RouterInfo.o obj/Transpor
obj/RouterContext.o obj/NetDb.o obj/LeaseSet.o obj/Tunnel.o obj/TunnelEndpoint.o \ obj/RouterContext.o obj/NetDb.o obj/LeaseSet.o obj/Tunnel.o obj/TunnelEndpoint.o \
obj/TunnelGateway.o obj/TransitTunnel.o obj/I2NPProtocol.o obj/Log.o obj/Garlic.o \ obj/TunnelGateway.o obj/TransitTunnel.o obj/I2NPProtocol.o obj/Log.o obj/Garlic.o \
obj/HTTPServer.o obj/Streaming.o obj/Identity.o obj/SSU.o obj/util.o obj/Reseed.o \ obj/HTTPServer.o obj/Streaming.o obj/Identity.o obj/SSU.o obj/util.o obj/Reseed.o \
obj/UPnP.o obj/TunnelPool.o obj/HTTPProxy.o obj/UPnP.o obj/TunnelPool.o obj/HTTPProxy.o obj/AddressBook.o
INCFLAGS = INCFLAGS =
LDFLAGS = -Wl,-rpath,/usr/local/lib -lcryptopp -lboost_system -lboost_filesystem -lboost_regex -lboost_program_options -lpthread LDFLAGS = -Wl,-rpath,/usr/local/lib -lcryptopp -lboost_system -lboost_filesystem -lboost_regex -lboost_program_options -lpthread
LIBS = LIBS =

27
NTCPSession.cpp

@ -24,13 +24,19 @@ namespace ntcp
m_Socket (service), m_TerminationTimer (service), m_IsEstablished (false), m_Socket (service), m_TerminationTimer (service), m_IsEstablished (false),
m_RemoteRouterInfo (in_RemoteRouterInfo), m_ReceiveBufferOffset (0), m_NextMessage (nullptr) m_RemoteRouterInfo (in_RemoteRouterInfo), m_ReceiveBufferOffset (0), m_NextMessage (nullptr)
{ {
m_DHKeysPair = i2p::transports.GetNextDHKeysPair ();
}
NTCPSession::~NTCPSession ()
{
delete m_DHKeysPair;
} }
void NTCPSession::CreateAESKey (uint8_t * pubKey, uint8_t * aesKey) void NTCPSession::CreateAESKey (uint8_t * pubKey, uint8_t * aesKey)
{ {
CryptoPP::DH dh (elgp, elgg); CryptoPP::DH dh (elgp, elgg);
CryptoPP::SecByteBlock secretKey(dh.AgreedValueLength()); CryptoPP::SecByteBlock secretKey(dh.AgreedValueLength());
if (!dh.Agree (secretKey, i2p::context.GetPrivateKey (), pubKey)) if (!dh.Agree (secretKey, m_DHKeysPair->privateKey, pubKey))
{ {
LogPrint ("Couldn't create shared key"); LogPrint ("Couldn't create shared key");
Terminate (); Terminate ();
@ -50,11 +56,19 @@ namespace ntcp
{ {
m_IsEstablished = false; m_IsEstablished = false;
m_Socket.close (); m_Socket.close ();
i2p::transports.RemoveNTCPSession (this);
int numDelayed = 0;
for (auto it :m_DelayedMessages) for (auto it :m_DelayedMessages)
delete it; {
// try to send them again
i2p::transports.SendMessage (m_RemoteRouterInfo.GetIdentHash (), it);
numDelayed++;
}
m_DelayedMessages.clear (); m_DelayedMessages.clear ();
if (numDelayed > 0)
LogPrint ("NTCP session ", numDelayed, " not sent");
// TODO: notify tunnels // TODO: notify tunnels
i2p::transports.RemoveNTCPSession (this);
delete this; delete this;
LogPrint ("NTCP session terminated"); LogPrint ("NTCP session terminated");
} }
@ -78,7 +92,7 @@ namespace ntcp
void NTCPSession::ClientLogin () void NTCPSession::ClientLogin ()
{ {
// send Phase1 // send Phase1
const uint8_t * x = i2p::context.GetRouterIdentity ().publicKey; const uint8_t * x = m_DHKeysPair->publicKey;
memcpy (m_Phase1.pubKey, x, 256); memcpy (m_Phase1.pubKey, x, 256);
CryptoPP::SHA256().CalculateDigest(m_Phase1.HXxorHI, x, 256); CryptoPP::SHA256().CalculateDigest(m_Phase1.HXxorHI, x, 256);
const uint8_t * ident = m_RemoteRouterInfo.GetIdentHash (); const uint8_t * ident = m_RemoteRouterInfo.GetIdentHash ();
@ -143,7 +157,7 @@ namespace ntcp
void NTCPSession::SendPhase2 () void NTCPSession::SendPhase2 ()
{ {
const uint8_t * y = i2p::context.GetRouterIdentity ().publicKey; const uint8_t * y = m_DHKeysPair->publicKey;
memcpy (m_Phase2.pubKey, y, 256); memcpy (m_Phase2.pubKey, y, 256);
uint8_t xy[512]; uint8_t xy[512];
memcpy (xy, m_Phase1.pubKey, 256); memcpy (xy, m_Phase1.pubKey, 256);
@ -200,7 +214,7 @@ namespace ntcp
m_Decryption.ProcessData((uint8_t *)&m_Phase2.encrypted, (uint8_t *)&m_Phase2.encrypted, sizeof(m_Phase2.encrypted)); m_Decryption.ProcessData((uint8_t *)&m_Phase2.encrypted, (uint8_t *)&m_Phase2.encrypted, sizeof(m_Phase2.encrypted));
// verify // verify
uint8_t xy[512], hxy[32]; uint8_t xy[512], hxy[32];
memcpy (xy, i2p::context.GetRouterIdentity ().publicKey, 256); memcpy (xy, m_DHKeysPair->publicKey, 256);
memcpy (xy + 256, m_Phase2.pubKey, 256); memcpy (xy + 256, m_Phase2.pubKey, 256);
CryptoPP::SHA256().CalculateDigest(hxy, xy, 512); CryptoPP::SHA256().CalculateDigest(hxy, xy, 512);
if (memcmp (hxy, m_Phase2.encrypted.hxy, 32)) if (memcmp (hxy, m_Phase2.encrypted.hxy, 32))
@ -321,6 +335,7 @@ namespace ntcp
if (ecode) if (ecode)
{ {
LogPrint ("Phase 4 read error: ", ecode.message ()); LogPrint ("Phase 4 read error: ", ecode.message ());
GetRemoteRouterInfo ().SetUnreachable (true); // this router doesn't like us
Terminate (); Terminate ();
} }
else else

4
NTCPSession.h

@ -7,6 +7,7 @@
#include <cryptopp/modes.h> #include <cryptopp/modes.h>
#include <cryptopp/aes.h> #include <cryptopp/aes.h>
#include <cryptopp/adler32.h> #include <cryptopp/adler32.h>
#include "Identity.h"
#include "RouterInfo.h" #include "RouterInfo.h"
#include "I2NPProtocol.h" #include "I2NPProtocol.h"
@ -66,7 +67,7 @@ namespace ntcp
public: public:
NTCPSession (boost::asio::io_service& service, i2p::data::RouterInfo& in_RemoteRouterInfo); NTCPSession (boost::asio::io_service& service, i2p::data::RouterInfo& in_RemoteRouterInfo);
virtual ~NTCPSession () {}; virtual ~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; };
@ -120,6 +121,7 @@ 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
CryptoPP::CBC_Mode<CryptoPP::AES>::Decryption m_Decryption; CryptoPP::CBC_Mode<CryptoPP::AES>::Decryption m_Decryption;
CryptoPP::CBC_Mode<CryptoPP::AES>::Encryption m_Encryption; CryptoPP::CBC_Mode<CryptoPP::AES>::Encryption m_Encryption;

11
NetDb.cpp

@ -442,9 +442,11 @@ namespace data
if (dest->IsExploratory ()) if (dest->IsExploratory ())
{ {
if (!FindRouter (router)) // router with ident not found auto r = FindRouter (router);
if (!r || i2p::util::GetMillisecondsSinceEpoch () > r->GetTimestamp () + 3600*1000LL)
{ {
LogPrint ("Found new router. Requesting RouterInfo ..."); // router with ident not found or too old (1 hour)
LogPrint ("Found new/outdated router. Requesting RouterInfo ...");
if (outbound && inbound) if (outbound && inbound)
{ {
RequestedDestination * d1 = CreateRequestedDestination (router, false, false); RequestedDestination * d1 = CreateRequestedDestination (router, false, false);
@ -532,8 +534,9 @@ namespace data
void NetDb::Explore () void NetDb::Explore ()
{ {
auto outbound = i2p::tunnel::tunnels.GetNextOutboundTunnel (); auto exploratoryPool = i2p::tunnel::tunnels.GetExploratoryPool ();
auto inbound = i2p::tunnel::tunnels.GetNextInboundTunnel (); auto outbound = exploratoryPool ? exploratoryPool->GetNextOutboundTunnel () : nullptr;
auto inbound = exploratoryPool ? exploratoryPool->GetNextInboundTunnel () : nullptr;
if (outbound && inbound) if (outbound && inbound)
{ {
CryptoPP::RandomNumberGenerator& rnd = i2p::context.GetRandomNumberGenerator (); CryptoPP::RandomNumberGenerator& rnd = i2p::context.GetRandomNumberGenerator ();

2
README.md

@ -9,6 +9,8 @@ on Windows
Requires msvs2013, boost 1.46 and higher, crypto++ Requires msvs2013, boost 1.46 and higher, crypto++
[![Build Status](https://travis-ci.org/orignal/i2pd.svg?branch=master)](https://travis-ci.org/orignal/i2pd)
Testing Testing
------- -------

9
RouterContext.h

@ -4,6 +4,7 @@
#include <inttypes.h> #include <inttypes.h>
#include <cryptopp/dsa.h> #include <cryptopp/dsa.h>
#include <cryptopp/osrng.h> #include <cryptopp/osrng.h>
#include "Identity.h"
#include "RouterInfo.h" #include "RouterInfo.h"
namespace i2p namespace i2p
@ -11,7 +12,7 @@ namespace i2p
const char ROUTER_INFO[] = "router.info"; const char ROUTER_INFO[] = "router.info";
const char ROUTER_KEYS[] = "router.keys"; const char ROUTER_KEYS[] = "router.keys";
class RouterContext class RouterContext: public i2p::data::LocalDestination
{ {
public: public:
@ -28,6 +29,12 @@ namespace i2p
void OverrideNTCPAddress (const char * host, int port); // temporary void OverrideNTCPAddress (const char * host, int port); // temporary
void UpdateAddress (const char * host); // called from SSU void UpdateAddress (const char * host); // called from SSU
// implements LocalDestination
void UpdateLeaseSet () {};
const i2p::data::IdentHash& GetIdentHash () const { return m_RouterInfo.GetIdentHash (); };
const uint8_t * GetEncryptionPrivateKey () const { return GetPrivateKey (); };
const uint8_t * GetEncryptionPublicKey () const { return m_Keys.publicKey; };
private: private:
void CreateNewRouter (); void CreateNewRouter ();

65
SSU.cpp

@ -6,6 +6,7 @@
#include "Log.h" #include "Log.h"
#include "Timestamp.h" #include "Timestamp.h"
#include "RouterContext.h" #include "RouterContext.h"
#include "Transports.h"
#include "hmac.h" #include "hmac.h"
#include "SSU.h" #include "SSU.h"
@ -14,23 +15,23 @@ namespace i2p
namespace ssu namespace ssu
{ {
SSUSession::SSUSession (SSUServer * server, boost::asio::ip::udp::endpoint& remoteEndpoint, SSUSession::SSUSession (SSUServer& server, boost::asio::ip::udp::endpoint& remoteEndpoint,
const i2p::data::RouterInfo * router): m_Server (server), m_RemoteEndpoint (remoteEndpoint), const i2p::data::RouterInfo * router): m_Server (server), m_RemoteEndpoint (remoteEndpoint),
m_RemoteRouter (router), m_ConnectTimer (nullptr),m_State (eSessionStateUnknown) m_RemoteRouter (router), m_Timer (m_Server.GetService ()), m_State (eSessionStateUnknown)
{ {
m_DHKeysPair = i2p::transports.GetNextDHKeysPair ();
} }
SSUSession::~SSUSession () SSUSession::~SSUSession ()
{ {
if (m_ConnectTimer) delete m_DHKeysPair;
delete m_ConnectTimer;
} }
void SSUSession::CreateAESandMacKey (uint8_t * pubKey, uint8_t * aesKey, uint8_t * macKey) void SSUSession::CreateAESandMacKey (uint8_t * pubKey, uint8_t * aesKey, uint8_t * macKey)
{ {
CryptoPP::DH dh (i2p::crypto::elgp, i2p::crypto::elgg); CryptoPP::DH dh (i2p::crypto::elgp, i2p::crypto::elgg);
CryptoPP::SecByteBlock secretKey(dh.AgreedValueLength()); CryptoPP::SecByteBlock secretKey(dh.AgreedValueLength());
if (!dh.Agree (secretKey, i2p::context.GetPrivateKey (), pubKey)) if (!dh.Agree (secretKey, m_DHKeysPair->privateKey, pubKey))
{ {
LogPrint ("Couldn't create shared key"); LogPrint ("Couldn't create shared key");
return; return;
@ -110,8 +111,7 @@ namespace ssu
case PAYLOAD_TYPE_SESSION_DESTROYED: case PAYLOAD_TYPE_SESSION_DESTROYED:
{ {
LogPrint ("SSU session destroy received"); LogPrint ("SSU session destroy received");
if (m_Server) m_Server.DeleteSession (this); // delete this
m_Server->DeleteSession (this); // delete this
break; break;
} }
case PAYLOAD_TYPE_RELAY_INTRO: case PAYLOAD_TYPE_RELAY_INTRO:
@ -166,11 +166,11 @@ namespace ssu
{ {
m_State = eSessionStateCreatedReceived; m_State = eSessionStateCreatedReceived;
LogPrint ("Session created received"); LogPrint ("Session created received");
if (m_ConnectTimer) m_ConnectTimer->cancel (); m_Timer.cancel (); // connect timer
uint8_t signedData[532]; // x,y, our IP, our port, remote IP, remote port, relayTag, signed on time uint8_t signedData[532]; // x,y, our IP, our port, remote IP, remote port, relayTag, signed on time
uint8_t * payload = buf + sizeof (SSUHeader); uint8_t * payload = buf + sizeof (SSUHeader);
uint8_t * y = payload; uint8_t * y = payload;
memcpy (signedData, i2p::context.GetRouterIdentity ().publicKey, 256); // x memcpy (signedData, m_DHKeysPair->publicKey, 256); // x
memcpy (signedData + 256, y, 256); // y memcpy (signedData + 256, y, 256); // y
payload += 256; payload += 256;
payload += 1; // size, assume 4 payload += 1; // size, assume 4
@ -235,7 +235,7 @@ namespace ssu
uint8_t buf[304 + 18]; // 304 bytes for ipv4 (320 for ipv6) uint8_t buf[304 + 18]; // 304 bytes for ipv4 (320 for ipv6)
uint8_t * payload = buf + sizeof (SSUHeader); uint8_t * payload = buf + sizeof (SSUHeader);
memcpy (payload, i2p::context.GetRouterIdentity ().publicKey, 256); memcpy (payload, m_DHKeysPair->publicKey, 256); // x
payload[256] = 4; // we assume ipv4 payload[256] = 4; // we assume ipv4
*(uint32_t *)(payload + 257) = htobe32 (m_RemoteEndpoint.address ().to_v4 ().to_ulong ()); *(uint32_t *)(payload + 257) = htobe32 (m_RemoteEndpoint.address ().to_v4 ().to_ulong ());
@ -245,7 +245,7 @@ namespace ssu
FillHeaderAndEncrypt (PAYLOAD_TYPE_SESSION_REQUEST, buf, 304, introKey, iv, introKey); FillHeaderAndEncrypt (PAYLOAD_TYPE_SESSION_REQUEST, buf, 304, introKey, iv, introKey);
m_State = eSessionStateRequestSent; m_State = eSessionStateRequestSent;
m_Server->Send (buf, 304, m_RemoteEndpoint); m_Server.Send (buf, 304, m_RemoteEndpoint);
} }
void SSUSession::SendRelayRequest (const i2p::data::RouterInfo::Introducer& introducer) void SSUSession::SendRelayRequest (const i2p::data::RouterInfo::Introducer& introducer)
@ -276,7 +276,7 @@ namespace ssu
rnd.GenerateBlock (iv, 16); // random iv rnd.GenerateBlock (iv, 16); // random iv
FillHeaderAndEncrypt (PAYLOAD_TYPE_RELAY_REQUEST, buf, 96, introducer.iKey, iv, introducer.iKey); FillHeaderAndEncrypt (PAYLOAD_TYPE_RELAY_REQUEST, buf, 96, introducer.iKey, iv, introducer.iKey);
m_State = eSessionRelayRequestSent; m_State = eSessionRelayRequestSent;
m_Server->Send (buf, 96, m_RemoteEndpoint); m_Server.Send (buf, 96, m_RemoteEndpoint);
} }
void SSUSession::SendSessionCreated (const uint8_t * x) void SSUSession::SendSessionCreated (const uint8_t * x)
@ -293,7 +293,7 @@ namespace ssu
uint8_t buf[368 + 18]; uint8_t buf[368 + 18];
uint8_t * payload = buf + sizeof (SSUHeader); uint8_t * payload = buf + sizeof (SSUHeader);
memcpy (payload, i2p::context.GetRouterIdentity ().publicKey, 256); memcpy (payload, m_DHKeysPair->publicKey, 256);
memcpy (signedData + 256, payload, 256); // y memcpy (signedData + 256, payload, 256); // y
payload += 256; payload += 256;
*payload = 4; // we assume ipv4 *payload = 4; // we assume ipv4
@ -323,7 +323,7 @@ namespace ssu
// encrypt message with intro key // encrypt message with intro key
FillHeaderAndEncrypt (PAYLOAD_TYPE_SESSION_CREATED, buf, 368, introKey, iv, introKey); FillHeaderAndEncrypt (PAYLOAD_TYPE_SESSION_CREATED, buf, 368, introKey, iv, introKey);
m_State = eSessionStateCreatedSent; m_State = eSessionStateCreatedSent;
m_Server->Send (buf, 368, m_RemoteEndpoint); m_Server.Send (buf, 368, m_RemoteEndpoint);
} }
void SSUSession::SendSessionConfirmed (const uint8_t * y, const uint8_t * ourAddress, uint32_t relayTag) void SSUSession::SendSessionConfirmed (const uint8_t * y, const uint8_t * ourAddress, uint32_t relayTag)
@ -347,7 +347,7 @@ namespace ssu
// signature // signature
uint8_t signedData[532]; // x,y, our IP, our port, remote IP, remote port, relayTag, our signed on time uint8_t signedData[532]; // x,y, our IP, our port, remote IP, remote port, relayTag, our signed on time
memcpy (signedData, i2p::context.GetRouterIdentity ().publicKey, 256); // x memcpy (signedData, m_DHKeysPair->publicKey, 256); // x
memcpy (signedData + 256, y, 256); // y memcpy (signedData + 256, y, 256); // y
memcpy (signedData + 512, ourAddress, 6); // our address/port as seem by party memcpy (signedData + 512, ourAddress, 6); // our address/port as seem by party
*(uint32_t *)(signedData + 518) = htobe32 (m_RemoteEndpoint.address ().to_v4 ().to_ulong ()); // remote IP *(uint32_t *)(signedData + 518) = htobe32 (m_RemoteEndpoint.address ().to_v4 ().to_ulong ()); // remote IP
@ -362,7 +362,7 @@ namespace ssu
// encrypt message with session key // encrypt message with session key
FillHeaderAndEncrypt (PAYLOAD_TYPE_SESSION_CONFIRMED, buf, 480, m_SessionKey, iv, m_MacKey); FillHeaderAndEncrypt (PAYLOAD_TYPE_SESSION_CONFIRMED, buf, 480, m_SessionKey, iv, m_MacKey);
m_State = eSessionStateConfirmedSent; m_State = eSessionStateConfirmedSent;
m_Server->Send (buf, 480, m_RemoteEndpoint); m_Server.Send (buf, 480, m_RemoteEndpoint);
} }
void SSUSession::ProcessRelayResponse (uint8_t * buf, size_t len) void SSUSession::ProcessRelayResponse (uint8_t * buf, size_t len)
@ -390,7 +390,7 @@ namespace ssu
uint16_t remotePort = be16toh (*(uint16_t *)(payload)); uint16_t remotePort = be16toh (*(uint16_t *)(payload));
payload += 2; payload += 2;
boost::asio::ip::udp::endpoint newRemoteEndpoint(remoteIP, remotePort); boost::asio::ip::udp::endpoint newRemoteEndpoint(remoteIP, remotePort);
m_Server->ReassignSession (m_RemoteEndpoint, newRemoteEndpoint); m_Server.ReassignSession (m_RemoteEndpoint, newRemoteEndpoint);
m_RemoteEndpoint = newRemoteEndpoint; m_RemoteEndpoint = newRemoteEndpoint;
payload++; payload++;
boost::asio::ip::address_v4 ourIP (be32toh (*(uint32_t* )(payload))); boost::asio::ip::address_v4 ourIP (be32toh (*(uint32_t* )(payload)));
@ -494,13 +494,10 @@ namespace ssu
{ {
if (m_State == eSessionStateUnknown) if (m_State == eSessionStateUnknown)
{ {
if (m_Server) // set connect timer
{ m_Timer.expires_from_now (boost::posix_time::seconds(SSU_CONNECT_TIMEOUT));
m_ConnectTimer = new boost::asio::deadline_timer (m_Server->GetService ()); m_Timer.async_wait (boost::bind (&SSUSession::HandleConnectTimer,
m_ConnectTimer->expires_from_now (boost::posix_time::seconds(SSU_CONNECT_TIMEOUT));
m_ConnectTimer->async_wait (boost::bind (&SSUSession::HandleConnectTimer,
this, boost::asio::placeholders::error)); this, boost::asio::placeholders::error));
}
SendSessionRequest (); SendSessionRequest ();
} }
} }
@ -517,8 +514,15 @@ namespace ssu
void SSUSession::ConnectThroughIntroducer (const i2p::data::RouterInfo::Introducer& introducer) void SSUSession::ConnectThroughIntroducer (const i2p::data::RouterInfo::Introducer& introducer)
{ {
if (m_State == eSessionStateUnknown)
{
// set connect timer
m_Timer.expires_from_now (boost::posix_time::seconds(SSU_CONNECT_TIMEOUT));
m_Timer.async_wait (boost::bind (&SSUSession::HandleConnectTimer,
this, boost::asio::placeholders::error));
SendRelayRequest (introducer); SendRelayRequest (introducer);
} }
}
void SSUSession::Close () void SSUSession::Close ()
{ {
@ -548,8 +552,7 @@ namespace ssu
{ {
m_State = eSessionStateFailed; m_State = eSessionStateFailed;
Close (); Close ();
if (m_Server) m_Server.DeleteSession (this); // delete this
m_Server->DeleteSession (this); // delete this
} }
} }
@ -692,7 +695,7 @@ namespace ssu
rnd.GenerateBlock (iv, 16); // random iv rnd.GenerateBlock (iv, 16); // random iv
// encrypt message with session key // encrypt message with session key
FillHeaderAndEncrypt (PAYLOAD_TYPE_DATA, buf, 48, m_SessionKey, iv, m_MacKey); FillHeaderAndEncrypt (PAYLOAD_TYPE_DATA, buf, 48, m_SessionKey, iv, m_MacKey);
m_Server->Send (buf, 48, m_RemoteEndpoint); m_Server.Send (buf, 48, m_RemoteEndpoint);
} }
void SSUSession::SendSesionDestroyed () void SSUSession::SendSesionDestroyed ()
@ -715,7 +718,7 @@ namespace ssu
return; return;
} }
} }
m_Server->Send (buf, 48, m_RemoteEndpoint); m_Server.Send (buf, 48, m_RemoteEndpoint);
} }
void SSUSession::Send (i2p::I2NPMessage * msg) void SSUSession::Send (i2p::I2NPMessage * msg)
@ -755,7 +758,7 @@ namespace ssu
rnd.GenerateBlock (iv, 16); // random iv rnd.GenerateBlock (iv, 16); // random iv
// encrypt message with session key // encrypt message with session key
FillHeaderAndEncrypt (PAYLOAD_TYPE_DATA, buf, size, m_SessionKey, iv, m_MacKey); FillHeaderAndEncrypt (PAYLOAD_TYPE_DATA, buf, size, m_SessionKey, iv, m_MacKey);
m_Server->Send (buf, size, m_RemoteEndpoint); m_Server.Send (buf, size, m_RemoteEndpoint);
if (!isLast) if (!isLast)
{ {
@ -815,7 +818,7 @@ namespace ssu
session = it->second; session = it->second;
if (!session) if (!session)
{ {
session = new SSUSession (this, m_SenderEndpoint); session = new SSUSession (*this, m_SenderEndpoint);
m_Sessions[m_SenderEndpoint] = session; m_Sessions[m_SenderEndpoint] = session;
LogPrint ("New SSU session from ", m_SenderEndpoint.address ().to_string (), ":", m_SenderEndpoint.port (), " created"); LogPrint ("New SSU session from ", m_SenderEndpoint.address ().to_string (), ":", m_SenderEndpoint.port (), " created");
} }
@ -856,7 +859,7 @@ namespace ssu
if (!router->UsesIntroducer ()) if (!router->UsesIntroducer ())
{ {
// connect directly // connect directly
session = new SSUSession (this, remoteEndpoint, router); session = new SSUSession (*this, remoteEndpoint, router);
m_Sessions[remoteEndpoint] = session; m_Sessions[remoteEndpoint] = session;
LogPrint ("New SSU session to [", router->GetIdentHashAbbreviation (), "] ", LogPrint ("New SSU session to [", router->GetIdentHashAbbreviation (), "] ",
remoteEndpoint.address ().to_string (), ":", remoteEndpoint.port (), " created"); remoteEndpoint.address ().to_string (), ":", remoteEndpoint.port (), " created");
@ -869,7 +872,7 @@ namespace ssu
{ {
auto& introducer = address->introducers[0]; // TODO: auto& introducer = address->introducers[0]; // TODO:
boost::asio::ip::udp::endpoint introducerEndpoint (introducer.iHost, introducer.iPort); boost::asio::ip::udp::endpoint introducerEndpoint (introducer.iHost, introducer.iPort);
session = new SSUSession (this, introducerEndpoint, router); session = new SSUSession (*this, introducerEndpoint, router);
m_Sessions[introducerEndpoint] = session; m_Sessions[introducerEndpoint] = session;
LogPrint ("New SSU session to [", router->GetIdentHashAbbreviation (), LogPrint ("New SSU session to [", router->GetIdentHashAbbreviation (),
"] through introducer ", introducerEndpoint.address ().to_string (), ":", introducerEndpoint.port ()); "] through introducer ", introducerEndpoint.address ().to_string (), ":", introducerEndpoint.port ());

8
SSU.h

@ -8,6 +8,7 @@
#include <cryptopp/modes.h> #include <cryptopp/modes.h>
#include <cryptopp/aes.h> #include <cryptopp/aes.h>
#include "I2PEndian.h" #include "I2PEndian.h"
#include "Identity.h"
#include "RouterInfo.h" #include "RouterInfo.h"
#include "I2NPProtocol.h" #include "I2NPProtocol.h"
@ -68,7 +69,7 @@ namespace ssu
{ {
public: public:
SSUSession (SSUServer * server, boost::asio::ip::udp::endpoint& remoteEndpoint, SSUSession (SSUServer& server, boost::asio::ip::udp::endpoint& remoteEndpoint,
const i2p::data::RouterInfo * router = nullptr); const i2p::data::RouterInfo * router = nullptr);
void ProcessNextMessage (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint); void ProcessNextMessage (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint);
~SSUSession (); ~SSUSession ();
@ -109,10 +110,11 @@ namespace ssu
private: private:
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; const i2p::data::RouterInfo * m_RemoteRouter;
boost::asio::deadline_timer * m_ConnectTimer; boost::asio::deadline_timer m_Timer;
i2p::data::DHKeysPair * m_DHKeysPair; // X - for client and Y - for server
SessionState m_State; SessionState m_State;
CryptoPP::CBC_Mode<CryptoPP::AES>::Encryption m_Encryption; CryptoPP::CBC_Mode<CryptoPP::AES>::Encryption m_Encryption;
CryptoPP::CBC_Mode<CryptoPP::AES>::Decryption m_Decryption; CryptoPP::CBC_Mode<CryptoPP::AES>::Decryption m_Decryption;

9
Streaming.cpp

@ -1,5 +1,6 @@
#include <fstream> #include <fstream>
#include <algorithm> #include <algorithm>
#include <cryptopp/dh.h>
#include <cryptopp/gzip.h> #include <cryptopp/gzip.h>
#include "Log.h" #include "Log.h"
#include "RouterInfo.h" #include "RouterInfo.h"
@ -347,7 +348,9 @@ namespace stream
m_IdentHash = i2p::data::CalculateIdentHash (m_Keys.pub); m_IdentHash = i2p::data::CalculateIdentHash (m_Keys.pub);
m_SigningPrivateKey.Initialize (i2p::crypto::dsap, i2p::crypto::dsaq, i2p::crypto::dsag, m_SigningPrivateKey.Initialize (i2p::crypto::dsap, i2p::crypto::dsaq, i2p::crypto::dsag,
CryptoPP::Integer (m_Keys.signingPrivateKey, 20)); CryptoPP::Integer (m_Keys.signingPrivateKey, 20));
m_Pool = i2p::tunnel::tunnels.CreateTunnelPool (this); CryptoPP::DH dh (i2p::crypto::elgp, i2p::crypto::elgg);
dh.GenerateKeyPair(i2p::context.GetRandomNumberGenerator (), m_EncryptionPrivateKey, m_EncryptionPublicKey);
m_Pool = i2p::tunnel::tunnels.CreateTunnelPool (*this);
} }
StreamingDestination::StreamingDestination (const std::string& fullPath): m_LeaseSet (nullptr) StreamingDestination::StreamingDestination (const std::string& fullPath): m_LeaseSet (nullptr)
@ -357,7 +360,9 @@ namespace stream
s.read ((char *)&m_Keys, sizeof (m_Keys)); s.read ((char *)&m_Keys, sizeof (m_Keys));
else else
LogPrint ("Can't open file ", fullPath); LogPrint ("Can't open file ", fullPath);
m_Pool = i2p::tunnel::tunnels.CreateTunnelPool (this); CryptoPP::DH dh (i2p::crypto::elgp, i2p::crypto::elgg);
dh.GenerateKeyPair(i2p::context.GetRandomNumberGenerator (), m_EncryptionPrivateKey, m_EncryptionPublicKey);
m_Pool = i2p::tunnel::tunnels.CreateTunnelPool (*this);
} }
StreamingDestination::~StreamingDestination () StreamingDestination::~StreamingDestination ()

4
Streaming.h

@ -138,6 +138,9 @@ namespace stream
// implements LocalDestination // implements LocalDestination
void UpdateLeaseSet (); void UpdateLeaseSet ();
const i2p::data::IdentHash& GetIdentHash () const { return m_IdentHash; };
const uint8_t * GetEncryptionPrivateKey () const { return m_EncryptionPrivateKey; };
const uint8_t * GetEncryptionPublicKey () const { return m_EncryptionPublicKey; };
private: private:
@ -148,6 +151,7 @@ namespace stream
std::map<uint32_t, Stream *> m_Streams; std::map<uint32_t, Stream *> m_Streams;
i2p::data::PrivateKeys m_Keys; i2p::data::PrivateKeys m_Keys;
i2p::data::IdentHash m_IdentHash; i2p::data::IdentHash m_IdentHash;
uint8_t m_EncryptionPublicKey[256], m_EncryptionPrivateKey[256];
i2p::tunnel::TunnelPool * m_Pool; i2p::tunnel::TunnelPool * m_Pool;
I2NPMessage * m_LeaseSet; I2NPMessage * m_LeaseSet;

76
Transports.cpp

@ -9,10 +9,76 @@ using namespace i2p::data;
namespace i2p namespace i2p
{ {
DHKeysPairSupplier::~DHKeysPairSupplier ()
{
Stop ();
}
void DHKeysPairSupplier::Start ()
{
m_IsRunning = true;
m_Thread = new std::thread (std::bind (&DHKeysPairSupplier::Run, this));
}
void DHKeysPairSupplier::Stop ()
{
m_IsRunning = false;
m_Acquired.notify_one ();
if (m_Thread)
{
m_Thread->join ();
delete m_Thread;
m_Thread = 0;
}
}
void DHKeysPairSupplier::Run ()
{
while (m_IsRunning)
{
int num;
while ((num = m_QueueSize - m_Queue.size ()) > 0)
CreateDHKeysPairs (num);
std::unique_lock<std::mutex> l(m_AcquiredMutex);
m_Acquired.wait (l); // wait for element gets aquired
}
}
void DHKeysPairSupplier::CreateDHKeysPairs (int num)
{
if (num > 0)
{
for (int i = 0; i < num; i++)
{
i2p::data::DHKeysPair * pair = new i2p::data::DHKeysPair ();
i2p::data::CreateRandomDHKeysPair (pair);
m_Queue.push (pair);
}
}
}
i2p::data::DHKeysPair * DHKeysPairSupplier::Acquire ()
{
if (!m_Queue.empty ())
{
auto pair = m_Queue.front ();
m_Queue.pop ();
m_Acquired.notify_one ();
return pair;
}
else // queue is empty, create new
{
i2p::data::DHKeysPair * pair = new i2p::data::DHKeysPair ();
i2p::data::CreateRandomDHKeysPair (pair);
return pair;
}
}
Transports transports; Transports transports;
Transports::Transports (): Transports::Transports ():
m_Thread (nullptr), m_Work (m_Service),m_NTCPAcceptor (nullptr), m_SSUServer (nullptr) m_Thread (nullptr), m_Work (m_Service), m_NTCPAcceptor (nullptr),
m_SSUServer (nullptr), m_DHKeysPairSupplier (5) // 5 pre-generated keys
{ {
} }
@ -23,6 +89,7 @@ namespace i2p
void Transports::Start () void Transports::Start ()
{ {
m_DHKeysPairSupplier.Start ();
m_IsRunning = true; m_IsRunning = true;
m_Thread = new std::thread (std::bind (&Transports::Run, this)); m_Thread = new std::thread (std::bind (&Transports::Run, this));
m_Timer = new boost::asio::deadline_timer (m_Service); m_Timer = new boost::asio::deadline_timer (m_Service);
@ -74,6 +141,7 @@ namespace i2p
delete m_SSUServer; delete m_SSUServer;
} }
m_DHKeysPairSupplier.Stop ();
m_IsRunning = false; m_IsRunning = false;
m_Service.stop (); m_Service.stop ();
if (m_Thread) if (m_Thread)
@ -171,7 +239,7 @@ namespace i2p
// existing session not found. create new // existing session not found. create new
// try NTCP first // try NTCP first
auto address = r->GetNTCPAddress (); auto address = r->GetNTCPAddress ();
if (address) if (address && !r->UsesIntroducer () && !r->IsUnreachable ())
{ {
auto s = new i2p::ntcp::NTCPClient (m_Service, address->host, address->port, *r); auto s = new i2p::ntcp::NTCPClient (m_Service, address->host, address->port, *r);
AddNTCPSession (s); AddNTCPSession (s);
@ -221,4 +289,8 @@ namespace i2p
} }
} }
i2p::data::DHKeysPair * Transports::GetNextDHKeysPair ()
{
return m_DHKeysPairSupplier.Acquire ();
}
} }

33
Transports.h

@ -2,17 +2,47 @@
#define TRANSPORTS_H__ #define TRANSPORTS_H__
#include <thread> #include <thread>
#include <mutex>
#include <condition_variable>
#include <functional> #include <functional>
#include <map> #include <map>
#include <queue>
#include <string> #include <string>
#include <boost/asio.hpp> #include <boost/asio.hpp>
#include "NTCPSession.h" #include "NTCPSession.h"
#include "SSU.h" #include "SSU.h"
#include "RouterInfo.h" #include "RouterInfo.h"
#include "I2NPProtocol.h" #include "I2NPProtocol.h"
#include "Identity.h"
namespace i2p namespace i2p
{ {
class DHKeysPairSupplier
{
public:
DHKeysPairSupplier (int size): m_QueueSize (size), m_IsRunning (false), m_Thread (nullptr) {};
~DHKeysPairSupplier ();
void Start ();
void Stop ();
i2p::data::DHKeysPair * Acquire ();
private:
void Run ();
void CreateDHKeysPairs (int num);
private:
int m_QueueSize;
std::queue<i2p::data::DHKeysPair *> m_Queue;
bool m_IsRunning;
std::thread * m_Thread;
std::condition_variable m_Acquired;
std::mutex m_AcquiredMutex;
};
class Transports class Transports
{ {
public: public:
@ -24,6 +54,7 @@ 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 ();
void AddNTCPSession (i2p::ntcp::NTCPSession * session); void AddNTCPSession (i2p::ntcp::NTCPSession * session);
void RemoveNTCPSession (i2p::ntcp::NTCPSession * session); void RemoveNTCPSession (i2p::ntcp::NTCPSession * session);
@ -54,6 +85,8 @@ namespace i2p
i2p::ssu::SSUServer * m_SSUServer; i2p::ssu::SSUServer * m_SSUServer;
boost::asio::deadline_timer * m_Timer; boost::asio::deadline_timer * m_Timer;
DHKeysPairSupplier m_DHKeysPairSupplier;
public: public:
// for HTTP only // for HTTP only

123
Tunnel.cpp

@ -154,11 +154,14 @@ namespace tunnel
else else
block.deliveryType = eDeliveryTypeLocal; block.deliveryType = eDeliveryTypeLocal;
block.data = msg; block.data = msg;
std::unique_lock<std::mutex> l(m_SendMutex);
m_Gateway.SendTunnelDataMsg (block); m_Gateway.SendTunnelDataMsg (block);
} }
void OutboundTunnel::SendTunnelDataMsg (std::vector<TunnelMessageBlock> msgs) void OutboundTunnel::SendTunnelDataMsg (std::vector<TunnelMessageBlock> msgs)
{ {
std::unique_lock<std::mutex> l(m_SendMutex);
for (auto& it : msgs) for (auto& it : msgs)
m_Gateway.PutTunnelDataMsg (it); m_Gateway.PutTunnelDataMsg (it);
m_Gateway.SendBuffer (); m_Gateway.SendBuffer ();
@ -167,7 +170,7 @@ namespace tunnel
Tunnels tunnels; Tunnels tunnels;
Tunnels::Tunnels (): m_IsRunning (false), m_IsTunnelCreated (false), Tunnels::Tunnels (): m_IsRunning (false), m_IsTunnelCreated (false),
m_NextReplyMsgID (555),m_Thread (0) m_NextReplyMsgID (555), m_Thread (nullptr), m_ExploratoryPool (nullptr)
{ {
} }
@ -190,7 +193,7 @@ namespace tunnel
m_PendingTunnels.clear (); m_PendingTunnels.clear ();
for (auto& it: m_Pools) for (auto& it: m_Pools)
delete it; delete it.second;
m_Pools.clear (); m_Pools.clear ();
} }
@ -238,23 +241,6 @@ namespace tunnel
return tunnel; return tunnel;
} }
std::vector<InboundTunnel *> Tunnels::GetInboundTunnels (int num) const
{
std::vector<InboundTunnel *> v;
int i = 0;
for (auto it : m_InboundTunnels)
{
if (i >= num) break;
if (!it.second->IsFailed () && it.second->GetNextIdentHash () != i2p::context.GetRouterInfo ().GetIdentHash ())
{
// exclude one hop tunnels
v.push_back (it.second);
i++;
}
}
return v;
}
OutboundTunnel * Tunnels::GetNextOutboundTunnel () OutboundTunnel * Tunnels::GetNextOutboundTunnel ()
{ {
CryptoPP::RandomNumberGenerator& rnd = i2p::context.GetRandomNumberGenerator (); CryptoPP::RandomNumberGenerator& rnd = i2p::context.GetRandomNumberGenerator ();
@ -272,18 +258,21 @@ namespace tunnel
return tunnel; return tunnel;
} }
TunnelPool * Tunnels::CreateTunnelPool (i2p::data::LocalDestination * localDestination) TunnelPool * Tunnels::CreateTunnelPool (i2p::data::LocalDestination& localDestination)
{ {
auto pool = new TunnelPool (localDestination); auto pool = new TunnelPool (localDestination);
m_Pools.push_back (pool); m_Pools[pool->GetIdentHash ()] = pool;
return pool; return pool;
} }
void Tunnels::DeleteTunnelPool (TunnelPool * pool) void Tunnels::DeleteTunnelPool (TunnelPool * pool)
{ {
m_Pools.remove (pool); if (pool)
{
m_Pools.erase (pool->GetIdentHash ());
delete pool; delete pool;
} }
}
void Tunnels::AddTransitTunnel (TransitTunnel * tunnel) void Tunnels::AddTransitTunnel (TransitTunnel * tunnel)
{ {
@ -398,14 +387,11 @@ namespace tunnel
it++; it++;
} }
if (m_OutboundTunnels.size () < 15) // TODO: store exploratory tunnels explicitly if (m_OutboundTunnels.size () < 5)
{ {
// trying to create one more oubound tunnel // trying to create one more oubound tunnel
if (m_InboundTunnels.empty ()) return;
InboundTunnel * inboundTunnel = GetNextInboundTunnel (); InboundTunnel * inboundTunnel = GetNextInboundTunnel ();
if (m_OutboundTunnels.empty () || m_OutboundTunnels.size () < 3) if (!inboundTunnel) return;
{
LogPrint ("Creating one hop outbound tunnel..."); LogPrint ("Creating one hop outbound tunnel...");
CreateTunnel<OutboundTunnel> ( CreateTunnel<OutboundTunnel> (
new TunnelConfig (std::vector<const i2p::data::RouterInfo *> new TunnelConfig (std::vector<const i2p::data::RouterInfo *>
@ -414,20 +400,6 @@ namespace tunnel
}, },
inboundTunnel->GetTunnelConfig ())); inboundTunnel->GetTunnelConfig ()));
} }
else
{
LogPrint ("Creating two hops outbound tunnel...");
auto firstHop = i2p::data::netdb.GetRandomRouter ();
CreateTunnel<OutboundTunnel> (
new TunnelConfig (std::vector<const i2p::data::RouterInfo *>
{
firstHop,
i2p::data::netdb.GetRandomRouter (firstHop)
},
inboundTunnel->GetTunnelConfig ()));
}
}
} }
void Tunnels::ManageInboundTunnels () void Tunnels::ManageInboundTunnels ()
@ -451,14 +423,14 @@ namespace tunnel
{ {
LogPrint ("Creating zero hops inbound tunnel..."); LogPrint ("Creating zero hops inbound tunnel...");
CreateZeroHopsInboundTunnel (); CreateZeroHopsInboundTunnel ();
if (!m_ExploratoryPool)
m_ExploratoryPool = CreateTunnelPool (i2p::context);
return; return;
} }
if (m_InboundTunnels.size () < 15) // TODO: store exploratory tunnels explicitly if (m_OutboundTunnels.empty () || m_InboundTunnels.size () < 5)
{ {
// trying to create one more inbound tunnel // trying to create one more inbound tunnel
if (m_OutboundTunnels.empty () || m_InboundTunnels.size () < 3)
{
LogPrint ("Creating one hop inbound tunnel..."); LogPrint ("Creating one hop inbound tunnel...");
CreateTunnel<InboundTunnel> ( CreateTunnel<InboundTunnel> (
new TunnelConfig (std::vector<const i2p::data::RouterInfo *> new TunnelConfig (std::vector<const i2p::data::RouterInfo *>
@ -466,21 +438,6 @@ namespace tunnel
i2p::data::netdb.GetRandomRouter () i2p::data::netdb.GetRandomRouter ()
})); }));
} }
else
{
OutboundTunnel * outboundTunnel = GetNextOutboundTunnel ();
LogPrint ("Creating two hops inbound tunnel...");
auto router = outboundTunnel->GetTunnelConfig ()->GetFirstHop ()->router;
auto firstHop = i2p::data::netdb.GetRandomRouter (outboundTunnel->GetEndpointRouter ());
CreateTunnel<InboundTunnel> (
new TunnelConfig (std::vector<const i2p::data::RouterInfo *>
{
firstHop,
router != &i2p::context.GetRouterInfo () ? router : i2p::data::netdb.GetRandomRouter (firstHop)
}),
outboundTunnel);
}
}
} }
void Tunnels::ManageTransitTunnels () void Tunnels::ManageTransitTunnels ()
@ -502,8 +459,8 @@ namespace tunnel
{ {
for (auto& it: m_Pools) for (auto& it: m_Pools)
{ {
it->CreateTunnels (); it.second->CreateTunnels ();
it->TestTunnels (); it.second->TestTunnels ();
} }
} }
@ -552,49 +509,5 @@ namespace tunnel
&i2p::context.GetRouterInfo () &i2p::context.GetRouterInfo ()
})); }));
} }
OutboundTunnel * Tunnels::CreateOneHopOutboundTestTunnel (InboundTunnel * replyTunnel)
{
return CreateTunnel<OutboundTunnel> (replyTunnel->GetTunnelConfig ()->Invert ());
}
InboundTunnel * Tunnels::CreateOneHopInboundTestTunnel (OutboundTunnel * outboundTunnel)
{
i2p::ntcp::NTCPSession * peer = i2p::transports.GetNextNTCPSession ();
if (peer)
{
const i2p::data::RouterInfo& router = peer->GetRemoteRouterInfo ();
return CreateTunnel<InboundTunnel> (
new TunnelConfig (std::vector<const i2p::data::RouterInfo *>{&router}),
outboundTunnel);
}
else
LogPrint ("No established peers");
return 0;
}
OutboundTunnel * Tunnels::CreateTwoHopsOutboundTestTunnel (InboundTunnel * replyTunnel)
{
return CreateTunnel<OutboundTunnel> (replyTunnel->GetTunnelConfig ()->Invert ());
}
InboundTunnel * Tunnels::CreateTwoHopsInboundTestTunnel (OutboundTunnel * outboundTunnel)
{
i2p::ntcp::NTCPSession * peer = i2p::transports.GetNextNTCPSession ();
if (peer)
{
const i2p::data::RouterInfo& router = peer->GetRemoteRouterInfo ();
return CreateTunnel<InboundTunnel> (
new TunnelConfig (std::vector<const i2p::data::RouterInfo *>
{
&router,
&i2p::context.GetRouterInfo ()
}),
outboundTunnel);
}
else
LogPrint ("No established peers");
return 0;
}
} }
} }

14
Tunnel.h

@ -7,6 +7,7 @@
#include <vector> #include <vector>
#include <string> #include <string>
#include <thread> #include <thread>
#include <mutex>
#include <cryptopp/modes.h> #include <cryptopp/modes.h>
#include <cryptopp/aes.h> #include <cryptopp/aes.h>
#include "Queue.h" #include "Queue.h"
@ -83,6 +84,7 @@ namespace tunnel
private: private:
std::mutex m_SendMutex;
TunnelGateway m_Gateway; TunnelGateway m_Gateway;
}; };
@ -114,8 +116,8 @@ namespace tunnel
InboundTunnel * GetInboundTunnel (uint32_t tunnelID); InboundTunnel * GetInboundTunnel (uint32_t tunnelID);
Tunnel * GetPendingTunnel (uint32_t replyMsgID); Tunnel * GetPendingTunnel (uint32_t replyMsgID);
InboundTunnel * GetNextInboundTunnel (); InboundTunnel * GetNextInboundTunnel ();
std::vector<InboundTunnel *> GetInboundTunnels (int num) const;
OutboundTunnel * GetNextOutboundTunnel (); OutboundTunnel * GetNextOutboundTunnel ();
TunnelPool * GetExploratoryPool () const { return m_ExploratoryPool; };
TransitTunnel * GetTransitTunnel (uint32_t tunnelID); TransitTunnel * GetTransitTunnel (uint32_t tunnelID);
void AddTransitTunnel (TransitTunnel * tunnel); void AddTransitTunnel (TransitTunnel * tunnel);
void AddOutboundTunnel (OutboundTunnel * newTunnel); void AddOutboundTunnel (OutboundTunnel * newTunnel);
@ -123,14 +125,9 @@ namespace tunnel
void PostTunnelData (I2NPMessage * msg); void PostTunnelData (I2NPMessage * msg);
template<class TTunnel> template<class TTunnel>
TTunnel * CreateTunnel (TunnelConfig * config, OutboundTunnel * outboundTunnel = 0); TTunnel * CreateTunnel (TunnelConfig * config, OutboundTunnel * outboundTunnel = 0);
TunnelPool * CreateTunnelPool (i2p::data::LocalDestination * localDestination); TunnelPool * CreateTunnelPool (i2p::data::LocalDestination& localDestination);
void DeleteTunnelPool (TunnelPool * pool); void DeleteTunnelPool (TunnelPool * pool);
OutboundTunnel * CreateOneHopOutboundTestTunnel (InboundTunnel * replyTunnel);
InboundTunnel * CreateOneHopInboundTestTunnel (OutboundTunnel * outboundTunnel = 0);
OutboundTunnel * CreateTwoHopsOutboundTestTunnel (InboundTunnel * replyTunnel);
InboundTunnel * CreateTwoHopsInboundTestTunnel (OutboundTunnel * outboundTunnel = 0);
private: private:
void Run (); void Run ();
@ -152,7 +149,8 @@ namespace tunnel
std::map<uint32_t, InboundTunnel *> m_InboundTunnels; std::map<uint32_t, InboundTunnel *> m_InboundTunnels;
std::list<OutboundTunnel *> m_OutboundTunnels; std::list<OutboundTunnel *> m_OutboundTunnels;
std::map<uint32_t, TransitTunnel *> m_TransitTunnels; std::map<uint32_t, TransitTunnel *> m_TransitTunnels;
std::list<TunnelPool *> m_Pools; std::map<i2p::data::IdentHash, TunnelPool *> m_Pools;
TunnelPool * m_ExploratoryPool;
i2p::util::Queue<I2NPMessage> m_Queue; i2p::util::Queue<I2NPMessage> m_Queue;
public: public:

25
TunnelPool.cpp

@ -1,10 +1,8 @@
#include <cryptopp/dh.h>
#include "I2PEndian.h" #include "I2PEndian.h"
#include "CryptoConst.h" #include "CryptoConst.h"
#include "Tunnel.h" #include "Tunnel.h"
#include "NetDb.h" #include "NetDb.h"
#include "Timestamp.h" #include "Timestamp.h"
#include "RouterContext.h"
#include "Garlic.h" #include "Garlic.h"
#include "TunnelPool.h" #include "TunnelPool.h"
@ -12,12 +10,9 @@ namespace i2p
{ {
namespace tunnel namespace tunnel
{ {
TunnelPool::TunnelPool (i2p::data::LocalDestination * localDestination, int numTunnels): TunnelPool::TunnelPool (i2p::data::LocalDestination& localDestination, int numTunnels):
m_LocalDestination (localDestination), m_NumTunnels (numTunnels), m_LastOutboundTunnel (nullptr) m_LocalDestination (localDestination), m_NumTunnels (numTunnels), m_LastOutboundTunnel (nullptr)
{ {
CryptoPP::AutoSeededRandomPool rnd;
CryptoPP::DH dh (i2p::crypto::elgp, i2p::crypto::elgg);
dh.GenerateKeyPair(i2p::context.GetRandomNumberGenerator (), m_EncryptionPrivateKey, m_EncryptionPublicKey);
} }
TunnelPool::~TunnelPool () TunnelPool::~TunnelPool ()
@ -40,8 +35,7 @@ namespace tunnel
expiredTunnel->SetTunnelPool (nullptr); expiredTunnel->SetTunnelPool (nullptr);
m_InboundTunnels.erase (expiredTunnel); m_InboundTunnels.erase (expiredTunnel);
} }
if (m_LocalDestination) m_LocalDestination.UpdateLeaseSet ();
m_LocalDestination->UpdateLeaseSet ();
} }
void TunnelPool::TunnelCreated (OutboundTunnel * createdTunnel) void TunnelPool::TunnelCreated (OutboundTunnel * createdTunnel)
@ -93,6 +87,21 @@ namespace tunnel
return tunnel; return tunnel;
} }
InboundTunnel * TunnelPool::GetNextInboundTunnel ()
{
return GetNextTunnel (m_InboundTunnels);
}
template<class TTunnels>
typename TTunnels::value_type TunnelPool::GetNextTunnel (TTunnels& tunnels)
{
if (tunnels.empty ()) return nullptr;
for (auto it: tunnels)
if (!it->IsFailed ())
return it;
return nullptr;
}
void TunnelPool::CreateTunnels () void TunnelPool::CreateTunnels ()
{ {
int num = m_InboundTunnels.size (); int num = m_InboundTunnels.size ();

15
TunnelPool.h

@ -9,6 +9,7 @@
#include "LeaseSet.h" #include "LeaseSet.h"
#include "I2NPProtocol.h" #include "I2NPProtocol.h"
#include "TunnelBase.h" #include "TunnelBase.h"
#include "RouterContext.h"
namespace i2p namespace i2p
{ {
@ -22,11 +23,12 @@ namespace tunnel
{ {
public: public:
TunnelPool (i2p::data::LocalDestination * localDestination, int numTunnels = 5); TunnelPool (i2p::data::LocalDestination& localDestination, int numTunnels = 5);
~TunnelPool (); ~TunnelPool ();
const uint8_t * GetEncryptionPrivateKey () const { return m_EncryptionPrivateKey; }; const uint8_t * GetEncryptionPrivateKey () const { return m_LocalDestination.GetEncryptionPrivateKey (); };
const uint8_t * GetEncryptionPublicKey () const { return m_EncryptionPublicKey; }; const uint8_t * GetEncryptionPublicKey () const { return m_LocalDestination.GetEncryptionPublicKey (); };
bool IsExploratory () const { return m_LocalDestination.GetIdentHash () == i2p::context.GetIdentHash (); };
void CreateTunnels (); void CreateTunnels ();
void TunnelCreated (InboundTunnel * createdTunnel); void TunnelCreated (InboundTunnel * createdTunnel);
@ -35,6 +37,8 @@ namespace tunnel
void TunnelExpired (OutboundTunnel * expiredTunnel); void TunnelExpired (OutboundTunnel * expiredTunnel);
std::vector<InboundTunnel *> GetInboundTunnels (int num) const; std::vector<InboundTunnel *> GetInboundTunnels (int num) const;
OutboundTunnel * GetNextOutboundTunnel (); OutboundTunnel * GetNextOutboundTunnel ();
InboundTunnel * GetNextInboundTunnel ();
const i2p::data::IdentHash& GetIdentHash () { return m_LocalDestination.GetIdentHash (); };
void TestTunnels (); void TestTunnels ();
void ProcessDeliveryStatus (I2NPMessage * msg); void ProcessDeliveryStatus (I2NPMessage * msg);
@ -43,11 +47,12 @@ namespace tunnel
void CreateInboundTunnel (); void CreateInboundTunnel ();
void CreateOutboundTunnel (); void CreateOutboundTunnel ();
template<class TTunnels>
typename TTunnels::value_type GetNextTunnel (TTunnels& tunnels);
private: private:
uint8_t m_EncryptionPublicKey[256], m_EncryptionPrivateKey[256]; i2p::data::LocalDestination& m_LocalDestination;
i2p::data::LocalDestination * m_LocalDestination;
int m_NumTunnels; int m_NumTunnels;
std::set<InboundTunnel *, TunnelCreationTimeCmp> m_InboundTunnels; // recent tunnel appears first std::set<InboundTunnel *, TunnelCreationTimeCmp> m_InboundTunnels; // recent tunnel appears first
std::set<OutboundTunnel *, TunnelCreationTimeCmp> m_OutboundTunnels; std::set<OutboundTunnel *, TunnelCreationTimeCmp> m_OutboundTunnels;

113
build/CMakeLists.txt

@ -0,0 +1,113 @@
cmake_minimum_required ( VERSION 2.8 )
project ( i2pd )
# Default build is Debug
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Wall")
#set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -Wall")
set ( SRC_DIR ".." )
set ( INC_DIR ".." )
add_definitions ( "-std=c++0x -Wall" )
set ( SOURCES
AddressBook.cpp
Garlic.cpp
HTTPServer.cpp
i2p.cpp
Identity.cpp
Log.cpp
NTCPSession.cpp
RouterContext.cpp
SSU.cpp
TransitTunnel.cpp
Tunnel.cpp
TunnelGateway.cpp
UPnP.cpp
base64.cpp
HTTPProxy.cpp
I2NPProtocol.cpp
LeaseSet.cpp
NetDb.cpp
Reseed.cpp
RouterInfo.cpp
Streaming.cpp
Transports.cpp
TunnelEndpoint.cpp
TunnelPool.cpp
util.cpp
)
set ( HEADERS
AddressBook.h
Garlic.h
HTTPServer.h
Identity.h
Log.h
NTCPSession.h
RouterContext.h
SSU.h
TransitTunnel.h
Tunnel.h
TunnelGateway.h
UPnP.h
base64.h
HTTPProxy.h
I2NPProtocol.h
LeaseSet.h
NetDb.h
Reseed.h
RouterInfo.h
Streaming.h
Transports.h
TunnelEndpoint.h
TunnelPool.h
util.h
)
source_group ("Header Files" FILES ${HEADERS})
source_group ("Source Files" FILES ${SOURCES})
set ( CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake_modules" )
find_package ( Threads REQUIRED )
find_package ( Boost COMPONENTS system filesystem regex program_options REQUIRED )
find_package ( CryptoPP REQUIRED )
# Check for libraries
if(NOT DEFINED Boost_INCLUDE_DIRS)
message(FATAL_ERROR "Boost is not found, or your boost version was bellow 1.46. Please download Boost!")
return()
endif()
if(NOT DEFINED CRYPTO++_INCLUDE_DIR)
message(FATAL_ERROR "Could not find Crypto++. Please download and install it first!")
return()
endif()
# End checks
include_directories ( ${Boost_INCLUDE_DIRS} ${CRYPTO++_INCLUDE_DIR})
unset ( TMP )
foreach ( src ${SOURCES} )
list ( APPEND TMP "${SRC_DIR}/${src}" )
endforeach ()
set ( SOURCES ${TMP} )
unset ( TMP )
foreach ( hdr ${HEADERS} )
list ( APPEND TMP "${INC_DIR}/${hdr}" )
endforeach ()
set ( HEADERS ${TMP} )
add_executable ( ${PROJECT_NAME} WIN32 ${HEADERS} ${SOURCES} )
target_link_libraries( ${PROJECT_NAME} ${Boost_LIBRARIES} ${CRYPTO++_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} )

35
build/cmake_modules/FindCryptoPP.cmake

@ -0,0 +1,35 @@
# - Find Crypto++
if(CRYPTO++_INCLUDE_DIR AND CRYPTO++_LIBRARIES)
set(CRYPTO++_FOUND TRUE)
else(CRYPTO++_INCLUDE_DIR AND CRYPTO++_LIBRARIES)
find_path(CRYPTO++_INCLUDE_DIR cryptlib.h
/usr/include/crypto++
/usr/include/cryptopp
/usr/local/include/crypto++
/usr/local/include/cryptopp
/opt/local/include/crypto++
/opt/local/include/cryptopp
$ENV{SystemDrive}/Crypto++/include
)
find_library(CRYPTO++_LIBRARIES NAMES cryptopp
PATHS
/usr/lib
/usr/local/lib
/opt/local/lib
$ENV{SystemDrive}/Crypto++/lib
)
if(CRYPTO++_INCLUDE_DIR AND CRYPTO++_LIBRARIES)
set(CRYPTO++_FOUND TRUE)
message(STATUS "Found Crypto++: ${CRYPTO++_INCLUDE_DIR}, ${CRYPTO++_LIBRARIES}")
else(CRYPTO++_INCLUDE_DIR AND CRYPTO++_LIBRARIES)
set(CRYPTO++_FOUND FALSE)
message(STATUS "Crypto++ not found.")
endif(CRYPTO++_INCLUDE_DIR AND CRYPTO++_LIBRARIES)
mark_as_advanced(CRYPTO++_INCLUDE_DIR CRYPTO++_LIBRARIES)
endif(CRYPTO++_INCLUDE_DIR AND CRYPTO++_LIBRARIES)
Loading…
Cancel
Save