mirror of
https://github.com/PurpleI2P/i2pd.git
synced 2024-11-19 21:25:30 +00:00
Merge pull request #6 from PrivacySolutions/master
Merge pull request from orignal/master
This commit is contained in:
commit
2d78ad0940
28
.travis.yml
28
.travis.yml
@ -1,28 +0,0 @@
|
|||||||
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
|
|
||||||
|
|
||||||
|
|
61
Daemon.cpp
61
Daemon.cpp
@ -15,6 +15,7 @@
|
|||||||
#include "Streaming.h"
|
#include "Streaming.h"
|
||||||
#include "HTTPServer.h"
|
#include "HTTPServer.h"
|
||||||
#include "HTTPProxy.h"
|
#include "HTTPProxy.h"
|
||||||
|
#include "SOCKS.h"
|
||||||
|
|
||||||
namespace i2p
|
namespace i2p
|
||||||
{
|
{
|
||||||
@ -23,14 +24,16 @@ namespace i2p
|
|||||||
class Daemon_Singleton::Daemon_Singleton_Private
|
class Daemon_Singleton::Daemon_Singleton_Private
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Daemon_Singleton_Private() : httpServer(nullptr), httpProxy(nullptr) { };
|
Daemon_Singleton_Private() : httpServer(nullptr), httpProxy(nullptr), socksProxy(nullptr) { };
|
||||||
~Daemon_Singleton_Private() {
|
~Daemon_Singleton_Private() {
|
||||||
delete httpServer;
|
delete httpServer;
|
||||||
delete httpProxy;
|
delete httpProxy;
|
||||||
|
delete socksProxy;
|
||||||
};
|
};
|
||||||
|
|
||||||
i2p::util::HTTPServer *httpServer;
|
i2p::util::HTTPServer *httpServer;
|
||||||
i2p::proxy::HTTPProxy *httpProxy;
|
i2p::proxy::HTTPProxy *httpProxy;
|
||||||
|
i2p::proxy::SOCKSProxy *socksProxy;
|
||||||
};
|
};
|
||||||
|
|
||||||
Daemon_Singleton::Daemon_Singleton() : running(1), d(*new Daemon_Singleton_Private()) {};
|
Daemon_Singleton::Daemon_Singleton() : running(1), d(*new Daemon_Singleton_Private()) {};
|
||||||
@ -55,29 +58,35 @@ namespace i2p
|
|||||||
i2p::context.OverrideNTCPAddress(i2p::util::config::GetCharArg("-host", "127.0.0.1"),
|
i2p::context.OverrideNTCPAddress(i2p::util::config::GetCharArg("-host", "127.0.0.1"),
|
||||||
i2p::util::config::GetArg("-port", 17007));
|
i2p::util::config::GetArg("-port", 17007));
|
||||||
|
|
||||||
if (isLogging == 1)
|
LogPrint("CMD parameters:");
|
||||||
{
|
for (int i = 0; i < argc; ++i)
|
||||||
std::string logfile_path = i2p::util::filesystem::GetDataDir().string();
|
LogPrint(i, " ", argv[i]);
|
||||||
#ifndef _WIN32
|
|
||||||
logfile_path.append("/debug.log");
|
|
||||||
#else
|
|
||||||
logfile_path.append("\\debug.log");
|
|
||||||
#endif
|
|
||||||
g_Log.SetLogFile (logfile_path);
|
|
||||||
|
|
||||||
LogPrint("CMD parameters:");
|
|
||||||
for (int i = 0; i < argc; ++i)
|
|
||||||
LogPrint(i, " ", argv[i]);
|
|
||||||
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Daemon_Singleton::start()
|
bool Daemon_Singleton::start()
|
||||||
{
|
{
|
||||||
|
// initialize log
|
||||||
|
if (isLogging)
|
||||||
|
{
|
||||||
|
if (isDaemon)
|
||||||
|
{
|
||||||
|
std::string logfile_path = i2p::util::filesystem::GetDataDir().string();
|
||||||
|
#ifndef _WIN32
|
||||||
|
logfile_path.append("/debug.log");
|
||||||
|
#else
|
||||||
|
logfile_path.append("\\debug.log");
|
||||||
|
#endif
|
||||||
|
StartLog (logfile_path);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
StartLog (""); // write to stdout
|
||||||
|
}
|
||||||
|
|
||||||
d.httpServer = new i2p::util::HTTPServer(i2p::util::config::GetArg("-httpport", 7070));
|
d.httpServer = new i2p::util::HTTPServer(i2p::util::config::GetArg("-httpport", 7070));
|
||||||
d.httpServer->Start();
|
d.httpServer->Start();
|
||||||
LogPrint("HTTPServer started");
|
LogPrint("HTTP Server started");
|
||||||
|
|
||||||
i2p::data::netdb.Start();
|
i2p::data::netdb.Start();
|
||||||
LogPrint("NetDB started");
|
LogPrint("NetDB started");
|
||||||
@ -92,8 +101,10 @@ namespace i2p
|
|||||||
|
|
||||||
d.httpProxy = new i2p::proxy::HTTPProxy(i2p::util::config::GetArg("-httpproxyport", 4446));
|
d.httpProxy = new i2p::proxy::HTTPProxy(i2p::util::config::GetArg("-httpproxyport", 4446));
|
||||||
d.httpProxy->Start();
|
d.httpProxy->Start();
|
||||||
LogPrint("Proxy started");
|
LogPrint("HTTP Proxy started");
|
||||||
|
d.socksProxy = new i2p::proxy::SOCKSProxy(i2p::util::config::GetArg("-socksproxyport", 4447));
|
||||||
|
d.socksProxy->Start();
|
||||||
|
LogPrint("SOCKS Proxy Started");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -102,7 +113,9 @@ namespace i2p
|
|||||||
LogPrint("Shutdown started.");
|
LogPrint("Shutdown started.");
|
||||||
|
|
||||||
d.httpProxy->Stop();
|
d.httpProxy->Stop();
|
||||||
LogPrint("HTTPProxy stoped");
|
LogPrint("HTTP Proxy stoped");
|
||||||
|
d.socksProxy->Stop();
|
||||||
|
LogPrint("SOCKS Proxy stoped");
|
||||||
i2p::stream::StopStreaming();
|
i2p::stream::StopStreaming();
|
||||||
LogPrint("Streaming stoped");
|
LogPrint("Streaming stoped");
|
||||||
i2p::garlic::routing.Stop();
|
i2p::garlic::routing.Stop();
|
||||||
@ -114,16 +127,12 @@ namespace i2p
|
|||||||
i2p::data::netdb.Stop();
|
i2p::data::netdb.Stop();
|
||||||
LogPrint("NetDB stoped");
|
LogPrint("NetDB stoped");
|
||||||
d.httpServer->Stop();
|
d.httpServer->Stop();
|
||||||
LogPrint("HTTPServer stoped");
|
LogPrint("HTTP Server stoped");
|
||||||
|
StopLog ();
|
||||||
|
delete d.socksProxy; d.socksProxy = nullptr;
|
||||||
delete d.httpProxy; d.httpProxy = nullptr;
|
delete d.httpProxy; d.httpProxy = nullptr;
|
||||||
delete d.httpServer; d.httpServer = nullptr;
|
delete d.httpServer; d.httpServer = nullptr;
|
||||||
|
|
||||||
if (isLogging == 1)
|
|
||||||
{
|
|
||||||
fclose(stdout);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -48,24 +48,29 @@ namespace i2p
|
|||||||
{
|
{
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
pid = fork();
|
pid = fork();
|
||||||
if (pid > 0)
|
if (pid > 0) // parent
|
||||||
{
|
::exit (EXIT_SUCCESS);
|
||||||
g_Log.Stop();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (pid < 0)
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (pid < 0) // error
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// child
|
||||||
umask(0);
|
umask(0);
|
||||||
int sid = setsid();
|
int sid = setsid();
|
||||||
if (sid < 0)
|
if (sid < 0)
|
||||||
{
|
{
|
||||||
LogPrint("Error, could not create process group.");
|
LogPrint("Error, could not create process group.");
|
||||||
return -1;
|
return false;
|
||||||
}
|
}
|
||||||
chdir(i2p::util::filesystem::GetDataDir().string().c_str());
|
chdir(i2p::util::filesystem::GetDataDir().string().c_str());
|
||||||
|
|
||||||
|
// close stdin/stdout/stderr descriptors
|
||||||
|
::close (0);
|
||||||
|
::open ("/dev/null", O_RDWR);
|
||||||
|
::close (1);
|
||||||
|
::open ("/dev/null", O_RDWR);
|
||||||
|
::close (2);
|
||||||
|
::open ("/dev/null", O_RDWR);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pidfile
|
// Pidfile
|
||||||
@ -75,12 +80,12 @@ namespace i2p
|
|||||||
if (pidFilehandle == -1)
|
if (pidFilehandle == -1)
|
||||||
{
|
{
|
||||||
LogPrint("Error, could not create pid file (", pidfile, ")\nIs an instance already running?");
|
LogPrint("Error, could not create pid file (", pidfile, ")\nIs an instance already running?");
|
||||||
return -1;
|
return false;
|
||||||
}
|
}
|
||||||
if (lockf(pidFilehandle, F_TLOCK, 0) == -1)
|
if (lockf(pidFilehandle, F_TLOCK, 0) == -1)
|
||||||
{
|
{
|
||||||
LogPrint("Error, could not lock pid file (", pidfile, ")\nIs an instance already running?");
|
LogPrint("Error, could not lock pid file (", pidfile, ")\nIs an instance already running?");
|
||||||
return -1;
|
return false;
|
||||||
}
|
}
|
||||||
char pid[10];
|
char pid[10];
|
||||||
sprintf(pid, "%d\n", getpid());
|
sprintf(pid, "%d\n", getpid());
|
||||||
@ -101,12 +106,10 @@ namespace i2p
|
|||||||
|
|
||||||
bool DaemonLinux::stop()
|
bool DaemonLinux::stop()
|
||||||
{
|
{
|
||||||
Daemon_Singleton::stop();
|
|
||||||
|
|
||||||
close(pidFilehandle);
|
close(pidFilehandle);
|
||||||
unlink(pidfile.c_str());
|
unlink(pidfile.c_str());
|
||||||
|
|
||||||
return true;
|
return Daemon_Singleton::stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
85
Garlic.cpp
85
Garlic.cpp
@ -14,7 +14,7 @@ namespace i2p
|
|||||||
{
|
{
|
||||||
namespace garlic
|
namespace garlic
|
||||||
{
|
{
|
||||||
GarlicRoutingSession::GarlicRoutingSession (const i2p::data::RoutingDestination& destination, int numTags):
|
GarlicRoutingSession::GarlicRoutingSession (const i2p::data::RoutingDestination * destination, int numTags):
|
||||||
m_Destination (destination), m_FirstMsgID (0), m_IsAcknowledged (false),
|
m_Destination (destination), m_FirstMsgID (0), m_IsAcknowledged (false),
|
||||||
m_NumTags (numTags), m_NextTag (-1), m_SessionTags (0), m_TagsCreationTime (0)
|
m_NumTags (numTags), m_NextTag (-1), m_SessionTags (0), m_TagsCreationTime (0)
|
||||||
{
|
{
|
||||||
@ -23,13 +23,23 @@ namespace garlic
|
|||||||
m_Encryption.SetKey (m_SessionKey);
|
m_Encryption.SetKey (m_SessionKey);
|
||||||
if (m_NumTags > 0)
|
if (m_NumTags > 0)
|
||||||
{
|
{
|
||||||
m_SessionTags = new uint8_t[m_NumTags*32];
|
m_SessionTags = new SessionTag[m_NumTags];
|
||||||
GenerateSessionTags ();
|
GenerateSessionTags ();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
m_SessionTags = nullptr;
|
m_SessionTags = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GarlicRoutingSession::GarlicRoutingSession (const uint8_t * sessionKey, const SessionTag& sessionTag):
|
||||||
|
m_Destination (nullptr), m_FirstMsgID (0), m_IsAcknowledged (true), m_NumTags (1), m_NextTag (0)
|
||||||
|
{
|
||||||
|
memcpy (m_SessionKey, sessionKey, 32);
|
||||||
|
m_Encryption.SetKey (m_SessionKey);
|
||||||
|
m_SessionTags = new SessionTag[1]; // 1 tag
|
||||||
|
m_SessionTags[0] = sessionTag;
|
||||||
|
m_TagsCreationTime = i2p::util::GetSecondsSinceEpoch ();
|
||||||
|
}
|
||||||
|
|
||||||
GarlicRoutingSession::~GarlicRoutingSession ()
|
GarlicRoutingSession::~GarlicRoutingSession ()
|
||||||
{
|
{
|
||||||
delete[] m_SessionTags;
|
delete[] m_SessionTags;
|
||||||
@ -40,13 +50,13 @@ namespace garlic
|
|||||||
if (m_SessionTags)
|
if (m_SessionTags)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < m_NumTags; i++)
|
for (int i = 0; i < m_NumTags; i++)
|
||||||
m_Rnd.GenerateBlock (m_SessionTags + i*32, 32);
|
m_Rnd.GenerateBlock (m_SessionTags[i], 32);
|
||||||
m_TagsCreationTime = i2p::util::GetSecondsSinceEpoch ();
|
m_TagsCreationTime = i2p::util::GetSecondsSinceEpoch ();
|
||||||
SetAcknowledged (false);
|
SetAcknowledged (false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
I2NPMessage * GarlicRoutingSession::WrapSingleMessage (I2NPMessage * msg, const I2NPMessage * leaseSet)
|
I2NPMessage * GarlicRoutingSession::WrapSingleMessage (I2NPMessage * msg, I2NPMessage * leaseSet)
|
||||||
{
|
{
|
||||||
I2NPMessage * m = NewI2NPMessage ();
|
I2NPMessage * m = NewI2NPMessage ();
|
||||||
size_t len = 0;
|
size_t len = 0;
|
||||||
@ -71,13 +81,18 @@ namespace garlic
|
|||||||
// create message
|
// create message
|
||||||
if (m_NextTag < 0 || !m_NumTags) // new session
|
if (m_NextTag < 0 || !m_NumTags) // new session
|
||||||
{
|
{
|
||||||
|
if (!m_Destination)
|
||||||
|
{
|
||||||
|
LogPrint ("Can't use ElGamal for unknown destination");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
// create ElGamal block
|
// create ElGamal block
|
||||||
ElGamalBlock elGamal;
|
ElGamalBlock elGamal;
|
||||||
memcpy (elGamal.sessionKey, m_SessionKey, 32);
|
memcpy (elGamal.sessionKey, m_SessionKey, 32);
|
||||||
m_Rnd.GenerateBlock (elGamal.preIV, 32); // Pre-IV
|
m_Rnd.GenerateBlock (elGamal.preIV, 32); // Pre-IV
|
||||||
uint8_t iv[32]; // IV is first 16 bytes
|
uint8_t iv[32]; // IV is first 16 bytes
|
||||||
CryptoPP::SHA256().CalculateDigest(iv, elGamal.preIV, 32);
|
CryptoPP::SHA256().CalculateDigest(iv, elGamal.preIV, 32);
|
||||||
m_Destination.GetElGamalEncryption ()->Encrypt ((uint8_t *)&elGamal, sizeof(elGamal), buf, true);
|
m_Destination->GetElGamalEncryption ()->Encrypt ((uint8_t *)&elGamal, sizeof(elGamal), buf, true);
|
||||||
m_Encryption.SetIV (iv);
|
m_Encryption.SetIV (iv);
|
||||||
buf += 514;
|
buf += 514;
|
||||||
len += 514;
|
len += 514;
|
||||||
@ -85,9 +100,9 @@ namespace garlic
|
|||||||
else // existing session
|
else // existing session
|
||||||
{
|
{
|
||||||
// session tag
|
// session tag
|
||||||
memcpy (buf, m_SessionTags + m_NextTag*32, 32);
|
memcpy (buf, m_SessionTags[m_NextTag], 32);
|
||||||
uint8_t iv[32]; // IV is first 16 bytes
|
uint8_t iv[32]; // IV is first 16 bytes
|
||||||
CryptoPP::SHA256().CalculateDigest(iv, m_SessionTags + m_NextTag*32, 32);
|
CryptoPP::SHA256().CalculateDigest(iv, m_SessionTags[m_NextTag], 32);
|
||||||
m_Encryption.SetIV (iv);
|
m_Encryption.SetIV (iv);
|
||||||
buf += 32;
|
buf += 32;
|
||||||
len += 32;
|
len += 32;
|
||||||
@ -107,6 +122,8 @@ namespace garlic
|
|||||||
FillI2NPMessageHeader (m, eI2NPGarlic);
|
FillI2NPMessageHeader (m, eI2NPGarlic);
|
||||||
if (msg)
|
if (msg)
|
||||||
DeleteI2NPMessage (msg);
|
DeleteI2NPMessage (msg);
|
||||||
|
if (leaseSet)
|
||||||
|
DeleteI2NPMessage (leaseSet);
|
||||||
return m;
|
return m;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -117,8 +134,11 @@ namespace garlic
|
|||||||
blockSize += 2;
|
blockSize += 2;
|
||||||
if (m_NextTag < 0) // session tags recreated
|
if (m_NextTag < 0) // session tags recreated
|
||||||
{
|
{
|
||||||
memcpy (buf + blockSize, m_SessionTags, m_NumTags*32); // tags
|
for (int i = 0; i < m_NumTags; i++)
|
||||||
blockSize += m_NumTags*32;
|
{
|
||||||
|
memcpy (buf + blockSize, m_SessionTags[i], 32); // tags
|
||||||
|
blockSize += 32;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
uint32_t * payloadSize = (uint32_t *)(buf + blockSize);
|
uint32_t * payloadSize = (uint32_t *)(buf + blockSize);
|
||||||
blockSize += 4;
|
blockSize += 4;
|
||||||
@ -161,7 +181,7 @@ namespace garlic
|
|||||||
}
|
}
|
||||||
if (msg) // clove message ifself if presented
|
if (msg) // clove message ifself if presented
|
||||||
{
|
{
|
||||||
size += CreateGarlicClove (payload + size, msg, m_Destination.IsDestination ());
|
size += CreateGarlicClove (payload + size, msg, m_Destination ? m_Destination->IsDestination () : false);
|
||||||
(*numCloves)++;
|
(*numCloves)++;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -178,11 +198,11 @@ namespace garlic
|
|||||||
{
|
{
|
||||||
uint64_t ts = i2p::util::GetMillisecondsSinceEpoch () + 5000; // 5 sec
|
uint64_t ts = i2p::util::GetMillisecondsSinceEpoch () + 5000; // 5 sec
|
||||||
size_t size = 0;
|
size_t size = 0;
|
||||||
if (isDestination)
|
if (isDestination && m_Destination)
|
||||||
{
|
{
|
||||||
buf[size] = eGarlicDeliveryTypeDestination << 5;// delivery instructions flag destination
|
buf[size] = eGarlicDeliveryTypeDestination << 5;// delivery instructions flag destination
|
||||||
size++;
|
size++;
|
||||||
memcpy (buf + size, m_Destination.GetIdentHash (), 32);
|
memcpy (buf + size, m_Destination->GetIdentHash (), 32);
|
||||||
size += 32;
|
size += 32;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -249,11 +269,18 @@ namespace garlic
|
|||||||
for (auto it: m_Sessions)
|
for (auto it: m_Sessions)
|
||||||
delete it.second;
|
delete it.second;
|
||||||
m_Sessions.clear ();
|
m_Sessions.clear ();
|
||||||
for (auto it: m_SessionDecryptions)
|
// TODO: delete remaining session decryptions
|
||||||
delete it;
|
m_SessionTags.clear ();
|
||||||
m_SessionDecryptions.clear ();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GarlicRouting::AddSessionKey (const uint8_t * key, const uint8_t * tag)
|
||||||
|
{
|
||||||
|
SessionDecryption * decryption = new SessionDecryption;
|
||||||
|
decryption->SetKey (key);
|
||||||
|
decryption->SetTagCount (1);
|
||||||
|
m_SessionTags[SessionTag(tag)] = decryption;
|
||||||
|
}
|
||||||
|
|
||||||
I2NPMessage * GarlicRouting::WrapSingleMessage (const i2p::data::RoutingDestination& destination, I2NPMessage * msg)
|
I2NPMessage * GarlicRouting::WrapSingleMessage (const i2p::data::RoutingDestination& destination, I2NPMessage * msg)
|
||||||
{
|
{
|
||||||
auto it = m_Sessions.find (destination.GetIdentHash ());
|
auto it = m_Sessions.find (destination.GetIdentHash ());
|
||||||
@ -262,14 +289,14 @@ namespace garlic
|
|||||||
delete it->second;
|
delete it->second;
|
||||||
m_Sessions.erase (it);
|
m_Sessions.erase (it);
|
||||||
}
|
}
|
||||||
GarlicRoutingSession * session = new GarlicRoutingSession (destination, 0); // not follow-on messages expected
|
GarlicRoutingSession * session = new GarlicRoutingSession (&destination, 0); // not follow-on messages expected
|
||||||
m_Sessions[destination.GetIdentHash ()] = session;
|
m_Sessions[destination.GetIdentHash ()] = session;
|
||||||
|
|
||||||
return session->WrapSingleMessage (msg, nullptr);
|
return session->WrapSingleMessage (msg, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
I2NPMessage * GarlicRouting::WrapMessage (const i2p::data::RoutingDestination& destination,
|
I2NPMessage * GarlicRouting::WrapMessage (const i2p::data::RoutingDestination& destination,
|
||||||
I2NPMessage * msg, const I2NPMessage * leaseSet)
|
I2NPMessage * msg, I2NPMessage * leaseSet)
|
||||||
{
|
{
|
||||||
auto it = m_Sessions.find (destination.GetIdentHash ());
|
auto it = m_Sessions.find (destination.GetIdentHash ());
|
||||||
GarlicRoutingSession * session = nullptr;
|
GarlicRoutingSession * session = nullptr;
|
||||||
@ -277,7 +304,7 @@ namespace garlic
|
|||||||
session = it->second;
|
session = it->second;
|
||||||
if (!session)
|
if (!session)
|
||||||
{
|
{
|
||||||
session = new GarlicRoutingSession (destination, 32);
|
session = new GarlicRoutingSession (&destination, 32);
|
||||||
m_Sessions[destination.GetIdentHash ()] = session;
|
m_Sessions[destination.GetIdentHash ()] = session;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -297,8 +324,7 @@ namespace garlic
|
|||||||
uint8_t * buf = msg->GetPayload ();
|
uint8_t * buf = msg->GetPayload ();
|
||||||
uint32_t length = be32toh (*(uint32_t *)buf);
|
uint32_t length = be32toh (*(uint32_t *)buf);
|
||||||
buf += 4;
|
buf += 4;
|
||||||
std::string sessionTag((const char *)buf, 32);
|
auto it = m_SessionTags.find (SessionTag(buf));
|
||||||
auto it = m_SessionTags.find (sessionTag);
|
|
||||||
if (it != m_SessionTags.end ())
|
if (it != m_SessionTags.end ())
|
||||||
{
|
{
|
||||||
// existing session
|
// existing session
|
||||||
@ -306,7 +332,9 @@ namespace garlic
|
|||||||
CryptoPP::SHA256().CalculateDigest(iv, buf, 32);
|
CryptoPP::SHA256().CalculateDigest(iv, buf, 32);
|
||||||
it->second->SetIV (iv);
|
it->second->SetIV (iv);
|
||||||
it->second->Decrypt (buf + 32, length - 32, buf + 32);
|
it->second->Decrypt (buf + 32, length - 32, buf + 32);
|
||||||
|
it->second->UseTag ();
|
||||||
HandleAESBlock (buf + 32, length - 32, it->second);
|
HandleAESBlock (buf + 32, length - 32, it->second);
|
||||||
|
if (!it->second->GetTagCount ()) delete it->second; // all tags were used
|
||||||
m_SessionTags.erase (it); // tag might be used only once
|
m_SessionTags.erase (it); // tag might be used only once
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -320,8 +348,7 @@ namespace garlic
|
|||||||
pool ? pool->GetEncryptionPrivateKey () : i2p::context.GetPrivateKey (),
|
pool ? pool->GetEncryptionPrivateKey () : i2p::context.GetPrivateKey (),
|
||||||
buf, (uint8_t *)&elGamal, true))
|
buf, (uint8_t *)&elGamal, true))
|
||||||
{
|
{
|
||||||
i2p::crypto::CBCDecryption * decryption = new i2p::crypto::CBCDecryption;
|
SessionDecryption * decryption = new SessionDecryption;
|
||||||
m_SessionDecryptions.push_back (decryption);
|
|
||||||
decryption->SetKey (elGamal.sessionKey);
|
decryption->SetKey (elGamal.sessionKey);
|
||||||
uint8_t iv[32]; // IV is first 16 bytes
|
uint8_t iv[32]; // IV is first 16 bytes
|
||||||
CryptoPP::SHA256().CalculateDigest(iv, elGamal.preIV, 32);
|
CryptoPP::SHA256().CalculateDigest(iv, elGamal.preIV, 32);
|
||||||
@ -335,12 +362,16 @@ namespace garlic
|
|||||||
DeleteI2NPMessage (msg);
|
DeleteI2NPMessage (msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GarlicRouting::HandleAESBlock (uint8_t * buf, size_t len, i2p::crypto::CBCDecryption * decryption)
|
void GarlicRouting::HandleAESBlock (uint8_t * buf, size_t len, SessionDecryption * decryption)
|
||||||
{
|
{
|
||||||
uint16_t tagCount = be16toh (*(uint16_t *)buf);
|
uint16_t tagCount = be16toh (*(uint16_t *)buf);
|
||||||
buf += 2;
|
buf += 2;
|
||||||
for (int i = 0; i < tagCount; i++)
|
if (tagCount > 0)
|
||||||
m_SessionTags[std::string ((const char *)(buf + i*32), 32)] = decryption;
|
{
|
||||||
|
decryption->AddTagCount (tagCount);
|
||||||
|
for (int i = 0; i < tagCount; i++)
|
||||||
|
m_SessionTags[SessionTag(buf + i*32)] = decryption;
|
||||||
|
}
|
||||||
buf += tagCount*32;
|
buf += tagCount*32;
|
||||||
uint32_t payloadSize = be32toh (*(uint32_t *)buf);
|
uint32_t payloadSize = be32toh (*(uint32_t *)buf);
|
||||||
if (payloadSize > len)
|
if (payloadSize > len)
|
||||||
@ -387,7 +418,7 @@ namespace garlic
|
|||||||
{
|
{
|
||||||
case eGarlicDeliveryTypeLocal:
|
case eGarlicDeliveryTypeLocal:
|
||||||
LogPrint ("Garlic type local");
|
LogPrint ("Garlic type local");
|
||||||
i2p::HandleI2NPMessage (buf, len);
|
i2p::HandleI2NPMessage (CreateI2NPMessage (buf, len));
|
||||||
break;
|
break;
|
||||||
case eGarlicDeliveryTypeDestination:
|
case eGarlicDeliveryTypeDestination:
|
||||||
{
|
{
|
||||||
|
39
Garlic.h
39
Garlic.h
@ -36,13 +36,16 @@ namespace garlic
|
|||||||
#pragma pack()
|
#pragma pack()
|
||||||
|
|
||||||
const int TAGS_EXPIRATION_TIMEOUT = 900; // 15 minutes
|
const int TAGS_EXPIRATION_TIMEOUT = 900; // 15 minutes
|
||||||
|
|
||||||
|
typedef i2p::data::Tag<32> SessionTag;
|
||||||
class GarlicRoutingSession
|
class GarlicRoutingSession
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
GarlicRoutingSession (const i2p::data::RoutingDestination& destination, int numTags);
|
GarlicRoutingSession (const i2p::data::RoutingDestination * destination, int numTags);
|
||||||
|
GarlicRoutingSession (const uint8_t * sessionKey, const SessionTag& sessionTag); // one time encryption
|
||||||
~GarlicRoutingSession ();
|
~GarlicRoutingSession ();
|
||||||
I2NPMessage * WrapSingleMessage (I2NPMessage * msg, const I2NPMessage * leaseSet);
|
I2NPMessage * WrapSingleMessage (I2NPMessage * msg, I2NPMessage * leaseSet);
|
||||||
int GetNextTag () const { return m_NextTag; };
|
int GetNextTag () const { return m_NextTag; };
|
||||||
uint32_t GetFirstMsgID () const { return m_FirstMsgID; };
|
uint32_t GetFirstMsgID () const { return m_FirstMsgID; };
|
||||||
|
|
||||||
@ -60,12 +63,12 @@ namespace garlic
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
const i2p::data::RoutingDestination& m_Destination;
|
const i2p::data::RoutingDestination * m_Destination;
|
||||||
uint8_t m_SessionKey[32];
|
uint8_t m_SessionKey[32];
|
||||||
uint32_t m_FirstMsgID; // first message ID
|
uint32_t m_FirstMsgID; // first message ID
|
||||||
bool m_IsAcknowledged;
|
bool m_IsAcknowledged;
|
||||||
int m_NumTags, m_NextTag;
|
int m_NumTags, m_NextTag;
|
||||||
uint8_t * m_SessionTags; // m_NumTags*32 bytes
|
SessionTag * m_SessionTags; // m_NumTags*32 bytes
|
||||||
uint32_t m_TagsCreationTime; // seconds since epoch
|
uint32_t m_TagsCreationTime; // seconds since epoch
|
||||||
|
|
||||||
i2p::crypto::CBCEncryption m_Encryption;
|
i2p::crypto::CBCEncryption m_Encryption;
|
||||||
@ -74,6 +77,21 @@ namespace garlic
|
|||||||
|
|
||||||
class GarlicRouting
|
class GarlicRouting
|
||||||
{
|
{
|
||||||
|
class SessionDecryption: public i2p::crypto::CBCDecryption
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
SessionDecryption (): m_TagCount (0) {};
|
||||||
|
void SetTagCount (int tagCount) { m_TagCount = tagCount; };
|
||||||
|
void AddTagCount (int tagCount) { m_TagCount += tagCount; };
|
||||||
|
int GetTagCount () const { return m_TagCount; };
|
||||||
|
bool UseTag () { m_TagCount--; return m_TagCount > 0; };
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
int m_TagCount;
|
||||||
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
GarlicRouting ();
|
GarlicRouting ();
|
||||||
@ -81,23 +99,24 @@ namespace garlic
|
|||||||
|
|
||||||
void Start ();
|
void Start ();
|
||||||
void Stop ();
|
void Stop ();
|
||||||
|
void AddSessionKey (const uint8_t * key, const uint8_t * tag); // one tag
|
||||||
|
|
||||||
void HandleGarlicMessage (I2NPMessage * msg);
|
void HandleGarlicMessage (I2NPMessage * msg);
|
||||||
void HandleDeliveryStatusMessage (uint8_t * buf, size_t len);
|
void HandleDeliveryStatusMessage (uint8_t * buf, size_t len);
|
||||||
|
|
||||||
I2NPMessage * WrapSingleMessage (const i2p::data::RoutingDestination& destination, I2NPMessage * msg);
|
I2NPMessage * WrapSingleMessage (const i2p::data::RoutingDestination& destination, I2NPMessage * msg);
|
||||||
I2NPMessage * WrapMessage (const i2p::data::RoutingDestination& destination,
|
I2NPMessage * WrapMessage (const i2p::data::RoutingDestination& destination,
|
||||||
I2NPMessage * msg, const I2NPMessage * leaseSet = nullptr);
|
I2NPMessage * msg, I2NPMessage * leaseSet = nullptr);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void Run ();
|
void Run ();
|
||||||
void ProcessGarlicMessage (I2NPMessage * msg);
|
void ProcessGarlicMessage (I2NPMessage * msg);
|
||||||
void HandleAESBlock (uint8_t * buf, size_t len, i2p::crypto::CBCDecryption * decryption);
|
void HandleAESBlock (uint8_t * buf, size_t len, SessionDecryption * decryption);
|
||||||
void HandleGarlicPayload (uint8_t * buf, size_t len);
|
void HandleGarlicPayload (uint8_t * buf, size_t len);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
bool m_IsRunning;
|
bool m_IsRunning;
|
||||||
std::thread * m_Thread;
|
std::thread * m_Thread;
|
||||||
i2p::util::Queue<I2NPMessage> m_Queue;
|
i2p::util::Queue<I2NPMessage> m_Queue;
|
||||||
@ -105,8 +124,8 @@ namespace garlic
|
|||||||
std::map<i2p::data::IdentHash, GarlicRoutingSession *> m_Sessions;
|
std::map<i2p::data::IdentHash, GarlicRoutingSession *> m_Sessions;
|
||||||
std::map<uint32_t, GarlicRoutingSession *> m_CreatedSessions; // msgID -> session
|
std::map<uint32_t, GarlicRoutingSession *> m_CreatedSessions; // msgID -> session
|
||||||
// incoming session
|
// incoming session
|
||||||
std::list<i2p::crypto::CBCDecryption *> m_SessionDecryptions; // multiple tags refer to one decyption
|
// multiple tags refer to one decyption
|
||||||
std::map<std::string, i2p::crypto::CBCDecryption *> m_SessionTags; // tag -> decryption
|
std::map<SessionTag, SessionDecryption *> m_SessionTags; // tag -> decryption
|
||||||
};
|
};
|
||||||
|
|
||||||
extern GarlicRouting routing;
|
extern GarlicRouting routing;
|
||||||
|
185
HTTPServer.cpp
185
HTTPServer.cpp
@ -13,7 +13,7 @@ namespace i2p
|
|||||||
namespace util
|
namespace util
|
||||||
{
|
{
|
||||||
|
|
||||||
const std::string HTTPConnection::itoopieImage =
|
const std::string HTTPConnection::itoopieImage =
|
||||||
"<img alt=\"\" src=\"data:image/png;base64,"
|
"<img alt=\"\" src=\"data:image/png;base64,"
|
||||||
"iVBORw0KGgoAAAANSUhEUgAAADYAAABECAYAAAG9qPaBAAAACXBIWXMAAA7DAAAOwwHHb6h"
|
"iVBORw0KGgoAAAANSUhEUgAAADYAAABECAYAAAG9qPaBAAAACXBIWXMAAA7DAAAOwwHHb6h"
|
||||||
"kAAAStElEQVR4nMU7CXRUVbL1ek0nTUI6BLNAICEIhESWQAAFgsH8D4g5IwSHg6PfEQ/E0T"
|
"kAAAStElEQVR4nMU7CXRUVbL1ek0nTUI6BLNAICEIhESWQAAFgsH8D4g5IwSHg6PfEQ/E0T"
|
||||||
@ -108,8 +108,8 @@ namespace util
|
|||||||
"13ZO0Q0SjbAu6DCkQs4FYg4EwKcOv4WsAFLePCb04Y/ZFCY2MjQ8uGE4cTx7A9f7/dk8r/B"
|
"13ZO0Q0SjbAu6DCkQs4FYg4EwKcOv4WsAFLePCb04Y/ZFCY2MjQ8uGE4cTx7A9f7/dk8r/B"
|
||||||
"+U0vclvzH+PAAAAAElFTkSuQmCC"
|
"+U0vclvzH+PAAAAAElFTkSuQmCC"
|
||||||
"\" />";
|
"\" />";
|
||||||
|
|
||||||
namespace misc_strings
|
namespace misc_strings
|
||||||
{
|
{
|
||||||
|
|
||||||
const char name_value_separator[] = { ':', ' ' };
|
const char name_value_separator[] = { ':', ' ' };
|
||||||
@ -146,7 +146,7 @@ namespace util
|
|||||||
buffers.push_back(boost::asio::buffer(misc_strings::crlf));
|
buffers.push_back(boost::asio::buffer(misc_strings::crlf));
|
||||||
}
|
}
|
||||||
buffers.push_back(boost::asio::buffer(misc_strings::crlf));
|
buffers.push_back(boost::asio::buffer(misc_strings::crlf));
|
||||||
}
|
}
|
||||||
buffers.push_back(boost::asio::buffer(content));
|
buffers.push_back(boost::asio::buffer(content));
|
||||||
return buffers;
|
return buffers;
|
||||||
}
|
}
|
||||||
@ -154,9 +154,9 @@ namespace util
|
|||||||
void HTTPConnection::Terminate ()
|
void HTTPConnection::Terminate ()
|
||||||
{
|
{
|
||||||
if (m_Stream)
|
if (m_Stream)
|
||||||
{
|
{
|
||||||
m_Stream->Close ();
|
m_Stream->Close ();
|
||||||
DeleteStream (m_Stream);
|
DeleteStream (m_Stream);
|
||||||
}
|
}
|
||||||
m_Socket->close ();
|
m_Socket->close ();
|
||||||
delete this;
|
delete this;
|
||||||
@ -193,11 +193,11 @@ namespace util
|
|||||||
{
|
{
|
||||||
b32 = address.substr (1, pos - 1); // excluding leading '/' to next '/'
|
b32 = address.substr (1, pos - 1); // excluding leading '/' to next '/'
|
||||||
uri = address.substr (pos); // rest of line
|
uri = address.substr (pos); // rest of line
|
||||||
}
|
}
|
||||||
|
|
||||||
HandleDestinationRequest (b32, uri);
|
HandleDestinationRequest (b32, uri);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
HandleRequest ();
|
HandleRequest ();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -209,10 +209,10 @@ namespace util
|
|||||||
char * http = strstr (get, "HTTP");
|
char * http = strstr (get, "HTTP");
|
||||||
if (http)
|
if (http)
|
||||||
return std::string (get + 4, http - get - 5);
|
return std::string (get + 4, http - get - 5);
|
||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
void HTTPConnection::HandleWriteReply (const boost::system::error_code& ecode)
|
void HTTPConnection::HandleWriteReply (const boost::system::error_code& ecode)
|
||||||
{
|
{
|
||||||
Terminate ();
|
Terminate ();
|
||||||
@ -233,7 +233,7 @@ namespace util
|
|||||||
FillContent (s);
|
FillContent (s);
|
||||||
s << "</html>";
|
s << "</html>";
|
||||||
SendReply (s.str ());
|
SendReply (s.str ());
|
||||||
}
|
}
|
||||||
|
|
||||||
void HTTPConnection::FillContent (std::stringstream& s)
|
void HTTPConnection::FillContent (std::stringstream& s)
|
||||||
{
|
{
|
||||||
@ -241,7 +241,7 @@ namespace util
|
|||||||
s << "Our external address:" << "<BR>";
|
s << "Our external address:" << "<BR>";
|
||||||
for (auto& address : i2p::context.GetRouterInfo().GetAddresses())
|
for (auto& address : i2p::context.GetRouterInfo().GetAddresses())
|
||||||
{
|
{
|
||||||
switch (address.transportStyle)
|
switch (address.transportStyle)
|
||||||
{
|
{
|
||||||
case i2p::data::RouterInfo::eTransportNTCP:
|
case i2p::data::RouterInfo::eTransportNTCP:
|
||||||
s << "NTCP ";
|
s << "NTCP ";
|
||||||
@ -257,31 +257,31 @@ namespace util
|
|||||||
s << "<BR>Routers: " << i2p::data::netdb.GetNumRouters () << " ";
|
s << "<BR>Routers: " << i2p::data::netdb.GetNumRouters () << " ";
|
||||||
s << "Floodfills: " << i2p::data::netdb.GetNumFloodfills () << " ";
|
s << "Floodfills: " << i2p::data::netdb.GetNumFloodfills () << " ";
|
||||||
s << "LeaseSets: " << i2p::data::netdb.GetNumLeaseSets () << "<BR>";
|
s << "LeaseSets: " << i2p::data::netdb.GetNumLeaseSets () << "<BR>";
|
||||||
|
|
||||||
s << "<P>Tunnels</P>";
|
s << "<P>Tunnels</P>";
|
||||||
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 () && !it->GetTunnelPool ()->IsExploratory ())
|
if (it->GetTunnelPool () && !it->GetTunnelPool ()->IsExploratory ())
|
||||||
s << " " << "Pool";
|
s << " " << "Pool";
|
||||||
if (it->IsFailed ())
|
if (it->IsFailed ())
|
||||||
s << " " << "Failed";
|
s << " " << "Failed";
|
||||||
s << " " << (int)it->GetNumSentBytes () << "<BR>";
|
s << " " << (int)it->GetNumSentBytes () << "<BR>";
|
||||||
}
|
}
|
||||||
|
|
||||||
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 () && !it.second->GetTunnelPool ()->IsExploratory ())
|
if (it.second->GetTunnelPool () && !it.second->GetTunnelPool ()->IsExploratory ())
|
||||||
s << " " << "Pool";
|
s << " " << "Pool";
|
||||||
if (it.second->IsFailed ())
|
if (it.second->IsFailed ())
|
||||||
s << " " << "Failed";
|
s << " " << "Failed";
|
||||||
s << " " << (int)it.second->GetNumReceivedBytes () << "<BR>";
|
s << " " << (int)it.second->GetNumReceivedBytes () << "<BR>";
|
||||||
}
|
}
|
||||||
|
|
||||||
s << "<P>Transit tunnels</P>";
|
s << "<P>Transit tunnels</P>";
|
||||||
for (auto it: i2p::tunnel::tunnels.GetTransitTunnels ())
|
for (auto it: i2p::tunnel::tunnels.GetTransitTunnels ())
|
||||||
{
|
{
|
||||||
if (dynamic_cast<i2p::tunnel::TransitTunnelGateway *>(it.second))
|
if (dynamic_cast<i2p::tunnel::TransitTunnelGateway *>(it.second))
|
||||||
s << it.second->GetTunnelID () << "-->";
|
s << it.second->GetTunnelID () << "-->";
|
||||||
else if (dynamic_cast<i2p::tunnel::TransitTunnelEndpoint *>(it.second))
|
else if (dynamic_cast<i2p::tunnel::TransitTunnelEndpoint *>(it.second))
|
||||||
@ -289,23 +289,24 @@ namespace util
|
|||||||
else
|
else
|
||||||
s << "-->" << it.second->GetTunnelID () << "-->";
|
s << "-->" << it.second->GetTunnelID () << "-->";
|
||||||
s << " " << it.second->GetNumTransmittedBytes () << "<BR>";
|
s << " " << it.second->GetNumTransmittedBytes () << "<BR>";
|
||||||
}
|
}
|
||||||
|
|
||||||
s << "<P>Transports</P>";
|
s << "<P>Transports</P>";
|
||||||
s << "NTCP<BR>";
|
s << "NTCP<BR>";
|
||||||
for (auto it: i2p::transports.GetNTCPSessions ())
|
for (auto it: i2p::transports.GetNTCPSessions ())
|
||||||
{
|
{
|
||||||
// RouterInfo of incoming connection doesn't have address
|
// RouterInfo of incoming connection doesn't have address
|
||||||
bool outgoing = it.second->GetRemoteRouterInfo ().GetNTCPAddress ();
|
bool outgoing = it.second->GetRemoteRouterInfo ().GetNTCPAddress ();
|
||||||
if (it.second->IsEstablished ())
|
if (it.second->IsEstablished ())
|
||||||
{
|
{
|
||||||
if (outgoing) s << "-->";
|
if (outgoing) s << "-->";
|
||||||
s << it.second->GetRemoteRouterInfo ().GetIdentHashAbbreviation () << ": "
|
s << it.second->GetRemoteRouterInfo ().GetIdentHashAbbreviation () << ": "
|
||||||
<< 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 << "<BR>";
|
s << "<BR>";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
auto ssuServer = i2p::transports.GetSSUServer ();
|
auto ssuServer = i2p::transports.GetSSUServer ();
|
||||||
if (ssuServer)
|
if (ssuServer)
|
||||||
{
|
{
|
||||||
@ -318,14 +319,20 @@ namespace util
|
|||||||
if (outgoing) s << "-->";
|
if (outgoing) s << "-->";
|
||||||
s << endpoint.address ().to_string () << ":" << endpoint.port ();
|
s << endpoint.address ().to_string () << ":" << endpoint.port ();
|
||||||
if (!outgoing) s << "-->";
|
if (!outgoing) s << "-->";
|
||||||
|
s << " [" << it.second->GetNumSentBytes () << ":" << it.second->GetNumReceivedBytes () << "]";
|
||||||
s << "<BR>";
|
s << "<BR>";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
s << "<p><a href=\"zmw2cyw2vj7f6obx3msmdvdepdhnw2ctc4okza2zjxlukkdfckhq\">Flibusta</a></p>";
|
s << "<p><a href=\"zmw2cyw2vj7f6obx3msmdvdepdhnw2ctc4okza2zjxlukkdfckhq\">Flibusta</a></p>";
|
||||||
}
|
}
|
||||||
|
|
||||||
void HTTPConnection::HandleDestinationRequest (const std::string& address, const std::string& uri)
|
void HTTPConnection::HandleDestinationRequest (const std::string& address, const std::string& uri)
|
||||||
|
{
|
||||||
|
HandleDestinationRequest(address, "GET", "", uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
void HTTPConnection::HandleDestinationRequest (const std::string& address, const std::string& method, const std::string& data, const std::string& uri)
|
||||||
{
|
{
|
||||||
|
const i2p::data::LeaseSet * leaseSet = nullptr;
|
||||||
i2p::data::IdentHash destination;
|
i2p::data::IdentHash destination;
|
||||||
std::string fullAddress;
|
std::string fullAddress;
|
||||||
if (address.find(".b32.i2p") != std::string::npos)
|
if (address.find(".b32.i2p") != std::string::npos)
|
||||||
@ -354,17 +361,29 @@ namespace util
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (i2p::data::Base32ToByteStream(address.c_str(), address.length(), (uint8_t *)destination, 32) != 32)
|
if (address == "local")
|
||||||
{
|
{
|
||||||
LogPrint("Invalid Base32 address ", address);
|
// TODO: remove later
|
||||||
SendReply("<html>" + itoopieImage + "<br>Invalid Base32 address", 400);
|
fullAddress = "local.i2p";
|
||||||
return;
|
auto destination = i2p::stream::GetSharedLocalDestination ();
|
||||||
|
leaseSet = destination->GetLeaseSet ();
|
||||||
|
EepAccept (destination);
|
||||||
}
|
}
|
||||||
fullAddress = address + ".b32.i2p";
|
else
|
||||||
|
{
|
||||||
|
if (i2p::data::Base32ToByteStream(address.c_str(), address.length(), (uint8_t *)destination, 32) != 32)
|
||||||
|
{
|
||||||
|
LogPrint("Invalid Base32 address ", address);
|
||||||
|
SendReply("<html>" + itoopieImage + "<br>Invalid Base32 address", 400);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
fullAddress = address + ".b32.i2p";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto leaseSet = i2p::data::netdb.FindLeaseSet (destination);
|
if (!leaseSet)
|
||||||
|
leaseSet = i2p::data::netdb.FindLeaseSet (destination);
|
||||||
if (!leaseSet || !leaseSet->HasNonExpiredLeases ())
|
if (!leaseSet || !leaseSet->HasNonExpiredLeases ())
|
||||||
{
|
{
|
||||||
i2p::data::netdb.Subscribe(destination);
|
i2p::data::netdb.Subscribe(destination);
|
||||||
@ -374,23 +393,29 @@ namespace util
|
|||||||
{
|
{
|
||||||
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;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!m_Stream)
|
if (!m_Stream)
|
||||||
m_Stream = i2p::stream::CreateStream (*leaseSet);
|
m_Stream = i2p::stream::CreateStream (*leaseSet);
|
||||||
if (m_Stream)
|
if (m_Stream)
|
||||||
{
|
{
|
||||||
std::string request = "GET " + uri + " HTTP/1.1\n Host:" + fullAddress + "\n";
|
std::string request = method+" " + uri + " HTTP/1.1\n Host:" + fullAddress + "\r\n";
|
||||||
m_Stream->Send ((uint8_t *)request.c_str (), request.length (), 10);
|
if (!strcmp(method.c_str(), "GET"))
|
||||||
|
{
|
||||||
|
// POST/PUT, apply body
|
||||||
|
request += "\r\n"+ data;
|
||||||
|
}
|
||||||
|
LogPrint("HTTP Client Request: ", request);
|
||||||
|
m_Stream->Send ((uint8_t *)request.c_str (), request.length (), 10);
|
||||||
AsyncStreamReceive ();
|
AsyncStreamReceive ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void HTTPConnection::AsyncStreamReceive ()
|
void HTTPConnection::AsyncStreamReceive ()
|
||||||
{
|
{
|
||||||
if (m_Stream)
|
if (m_Stream)
|
||||||
m_Stream->AsyncReceive (boost::asio::buffer (m_StreamBuffer, 8192),
|
m_Stream->AsyncReceive (boost::asio::buffer (m_StreamBuffer, 8192),
|
||||||
boost::bind (&HTTPConnection::HandleStreamReceive, this,
|
boost::bind (&HTTPConnection::HandleStreamReceive, this,
|
||||||
boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred),
|
boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred),
|
||||||
45); // 45 seconds timeout
|
45); // 45 seconds timeout
|
||||||
}
|
}
|
||||||
@ -404,11 +429,11 @@ namespace util
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (m_Stream && m_Stream->IsOpen ())
|
if (ecode == boost::asio::error::timed_out)
|
||||||
SendReply ("<html>" + itoopieImage + "<br>Not responding</html>", 504);
|
SendReply ("<html>" + itoopieImage + "<br>Not responding</html>", 504);
|
||||||
else
|
else
|
||||||
Terminate ();
|
Terminate ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void HTTPConnection::SendReply (const std::string& content, int status)
|
void HTTPConnection::SendReply (const std::string& content, int status)
|
||||||
@ -421,16 +446,16 @@ namespace util
|
|||||||
m_Reply.headers[1].value = "text/html";
|
m_Reply.headers[1].value = "text/html";
|
||||||
|
|
||||||
boost::asio::async_write (*m_Socket, m_Reply.to_buffers(status),
|
boost::asio::async_write (*m_Socket, m_Reply.to_buffers(status),
|
||||||
boost::bind (&HTTPConnection::HandleWriteReply, this,
|
boost::bind (&HTTPConnection::HandleWriteReply, this,
|
||||||
boost::asio::placeholders::error));
|
boost::asio::placeholders::error));
|
||||||
}
|
}
|
||||||
|
|
||||||
HTTPServer::HTTPServer (int port):
|
HTTPServer::HTTPServer (int port):
|
||||||
m_Thread (nullptr), m_Work (m_Service),
|
m_Thread (nullptr), m_Work (m_Service),
|
||||||
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_NewSocket (nullptr)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
HTTPServer::~HTTPServer ()
|
HTTPServer::~HTTPServer ()
|
||||||
@ -450,17 +475,17 @@ namespace util
|
|||||||
m_Acceptor.close();
|
m_Acceptor.close();
|
||||||
m_Service.stop ();
|
m_Service.stop ();
|
||||||
if (m_Thread)
|
if (m_Thread)
|
||||||
{
|
{
|
||||||
m_Thread->join ();
|
m_Thread->join ();
|
||||||
delete m_Thread;
|
delete m_Thread;
|
||||||
m_Thread = nullptr;
|
m_Thread = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void HTTPServer::Run ()
|
void HTTPServer::Run ()
|
||||||
{
|
{
|
||||||
m_Service.run ();
|
m_Service.run ();
|
||||||
}
|
}
|
||||||
|
|
||||||
void HTTPServer::Accept ()
|
void HTTPServer::Accept ()
|
||||||
{
|
{
|
||||||
@ -476,13 +501,55 @@ namespace util
|
|||||||
CreateConnection(m_NewSocket); // new HTTPConnection(m_NewSocket);
|
CreateConnection(m_NewSocket); // new HTTPConnection(m_NewSocket);
|
||||||
Accept ();
|
Accept ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void HTTPServer::CreateConnection(boost::asio::ip::tcp::socket * m_NewSocket)
|
void HTTPServer::CreateConnection(boost::asio::ip::tcp::socket * m_NewSocket)
|
||||||
{
|
{
|
||||||
new HTTPConnection (m_NewSocket);
|
new HTTPConnection (m_NewSocket);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// eepSite. TODO: move away
|
||||||
|
|
||||||
|
void HTTPConnection::EepAccept (i2p::stream::StreamingDestination * destination)
|
||||||
|
{
|
||||||
|
if (destination)
|
||||||
|
destination->SetAcceptor (std::bind (&HTTPConnection::HandleEepAccept, this, std::placeholders::_1));
|
||||||
|
}
|
||||||
|
|
||||||
|
void HTTPConnection::HandleEepAccept (i2p::stream::Stream * stream)
|
||||||
|
{
|
||||||
|
if (stream)
|
||||||
|
{
|
||||||
|
auto conn = new EepSiteDummyConnection (stream);
|
||||||
|
conn->AsyncStreamReceive ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EepSiteDummyConnection::AsyncStreamReceive ()
|
||||||
|
{
|
||||||
|
if (m_Stream)
|
||||||
|
m_Stream->AsyncReceive (boost::asio::buffer (m_StreamBuffer, 8192),
|
||||||
|
boost::bind (&EepSiteDummyConnection::HandleStreamReceive, this,
|
||||||
|
boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred),
|
||||||
|
60); // 60 seconds timeout
|
||||||
|
}
|
||||||
|
|
||||||
|
void EepSiteDummyConnection::HandleStreamReceive (const boost::system::error_code& ecode, std::size_t bytes_transferred)
|
||||||
|
{
|
||||||
|
if (ecode)
|
||||||
|
{
|
||||||
|
LogPrint ("eepSite error: ", ecode.message ());
|
||||||
|
DeleteStream (m_Stream);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::string response ("HTTP/1.0 503 Not Implemented\r\n");
|
||||||
|
m_Stream->Send ((uint8_t *)response.c_str (), response.length (), 30);
|
||||||
|
m_Stream->Close ();
|
||||||
|
}
|
||||||
|
delete this;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
48
HTTPServer.h
48
HTTPServer.h
@ -14,13 +14,13 @@ namespace util
|
|||||||
class HTTPConnection
|
class HTTPConnection
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
struct header
|
struct header
|
||||||
{
|
{
|
||||||
std::string name;
|
std::string name;
|
||||||
std::string value;
|
std::string value;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct request
|
struct request
|
||||||
{
|
{
|
||||||
std::string method;
|
std::string method;
|
||||||
@ -38,7 +38,7 @@ namespace util
|
|||||||
|
|
||||||
std::vector<boost::asio::const_buffer> to_buffers (int status);
|
std::vector<boost::asio::const_buffer> to_buffers (int status);
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
HTTPConnection (boost::asio::ip::tcp::socket * socket): m_Socket (socket), m_Stream (nullptr) { Receive (); };
|
HTTPConnection (boost::asio::ip::tcp::socket * socket): m_Socket (socket), m_Stream (nullptr) { Receive (); };
|
||||||
@ -48,9 +48,9 @@ namespace util
|
|||||||
|
|
||||||
void Terminate ();
|
void Terminate ();
|
||||||
void Receive ();
|
void Receive ();
|
||||||
void HandleReceive (const boost::system::error_code& ecode, std::size_t bytes_transferred);
|
void HandleReceive (const boost::system::error_code& ecode, std::size_t bytes_transferred);
|
||||||
void AsyncStreamReceive ();
|
void AsyncStreamReceive ();
|
||||||
void HandleStreamReceive (const boost::system::error_code& ecode, std::size_t bytes_transferred);
|
void HandleStreamReceive (const boost::system::error_code& ecode, std::size_t bytes_transferred);
|
||||||
void HandleWriteReply(const boost::system::error_code& ecode);
|
void HandleWriteReply(const boost::system::error_code& ecode);
|
||||||
void HandleWrite (const boost::system::error_code& ecode);
|
void HandleWrite (const boost::system::error_code& ecode);
|
||||||
void SendReply (const std::string& content, int status = 200);
|
void SendReply (const std::string& content, int status = 200);
|
||||||
@ -58,9 +58,13 @@ namespace util
|
|||||||
void HandleRequest ();
|
void HandleRequest ();
|
||||||
void FillContent (std::stringstream& s);
|
void FillContent (std::stringstream& s);
|
||||||
std::string ExtractAddress ();
|
std::string ExtractAddress ();
|
||||||
|
|
||||||
|
// for eepsite
|
||||||
|
void EepAccept (i2p::stream::StreamingDestination * destination);
|
||||||
|
void HandleEepAccept (i2p::stream::Stream * stream);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
boost::asio::ip::tcp::socket * m_Socket;
|
boost::asio::ip::tcp::socket * m_Socket;
|
||||||
i2p::stream::Stream * m_Stream;
|
i2p::stream::Stream * m_Stream;
|
||||||
char m_Buffer[8192], m_StreamBuffer[8192];
|
char m_Buffer[8192], m_StreamBuffer[8192];
|
||||||
@ -68,14 +72,16 @@ namespace util
|
|||||||
reply m_Reply;
|
reply m_Reply;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
|
|
||||||
virtual void HandleDestinationRequest(const std::string& address, const std::string& uri);
|
virtual void HandleDestinationRequest(const std::string& address, const std::string& uri);
|
||||||
|
virtual void HandleDestinationRequest(const std::string& address, const std::string& method, const std::string& data, const std::string& uri);
|
||||||
virtual void RunRequest ();
|
virtual void RunRequest ();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
static const std::string itoopieImage;
|
static const std::string itoopieImage;
|
||||||
};
|
};
|
||||||
|
|
||||||
class HTTPServer
|
class HTTPServer
|
||||||
{
|
{
|
||||||
@ -89,10 +95,10 @@ namespace util
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void Run ();
|
void Run ();
|
||||||
void Accept ();
|
void Accept ();
|
||||||
void HandleAccept(const boost::system::error_code& ecode);
|
void HandleAccept(const boost::system::error_code& ecode);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
std::thread * m_Thread;
|
std::thread * m_Thread;
|
||||||
@ -103,7 +109,25 @@ namespace util
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void CreateConnection(boost::asio::ip::tcp::socket * m_NewSocket);
|
virtual void CreateConnection(boost::asio::ip::tcp::socket * m_NewSocket);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// TODO: move away
|
||||||
|
class EepSiteDummyConnection
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
EepSiteDummyConnection (i2p::stream::Stream * stream): m_Stream (stream) {};
|
||||||
|
void AsyncStreamReceive ();
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
void HandleStreamReceive (const boost::system::error_code& ecode, std::size_t bytes_transferred);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
i2p::stream::Stream * m_Stream;
|
||||||
|
char m_StreamBuffer[8192];
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
127
I2NPProtocol.cpp
127
I2NPProtocol.cpp
@ -1,4 +1,5 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <atomic>
|
||||||
#include "I2PEndian.h"
|
#include "I2PEndian.h"
|
||||||
#include <cryptopp/sha.h>
|
#include <cryptopp/sha.h>
|
||||||
#include <cryptopp/gzip.h>
|
#include <cryptopp/gzip.h>
|
||||||
@ -17,19 +18,25 @@ namespace i2p
|
|||||||
|
|
||||||
I2NPMessage * NewI2NPMessage ()
|
I2NPMessage * NewI2NPMessage ()
|
||||||
{
|
{
|
||||||
I2NPMessage * msg = new I2NPMessage;
|
return new I2NPMessageBuffer<I2NP_MAX_MESSAGE_SIZE>();
|
||||||
msg->offset = 2; // reserve 2 bytes for NTCP header, should reserve more for SSU in future
|
|
||||||
msg->len = sizeof (I2NPHeader) + 2;
|
|
||||||
msg->from = nullptr;
|
|
||||||
return msg;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
I2NPMessage * NewI2NPShortMessage ()
|
||||||
|
{
|
||||||
|
return new I2NPMessageBuffer<I2NP_MAX_SHORT_MESSAGE_SIZE>();
|
||||||
|
}
|
||||||
|
|
||||||
|
I2NPMessage * NewI2NPMessage (size_t len)
|
||||||
|
{
|
||||||
|
return (len < I2NP_MAX_SHORT_MESSAGE_SIZE/2) ? NewI2NPShortMessage () : NewI2NPMessage ();
|
||||||
|
}
|
||||||
|
|
||||||
void DeleteI2NPMessage (I2NPMessage * msg)
|
void DeleteI2NPMessage (I2NPMessage * msg)
|
||||||
{
|
{
|
||||||
delete msg;
|
delete msg;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t I2NPmsgID = 0; // TODO: create class
|
static std::atomic<uint32_t> I2NPmsgID(0); // TODO: create class
|
||||||
void FillI2NPMessageHeader (I2NPMessage * msg, I2NPMessageType msgType, uint32_t replyMsgID)
|
void FillI2NPMessageHeader (I2NPMessage * msg, I2NPMessageType msgType, uint32_t replyMsgID)
|
||||||
{
|
{
|
||||||
I2NPHeader * header = msg->GetHeader ();
|
I2NPHeader * header = msg->GetHeader ();
|
||||||
@ -62,7 +69,7 @@ namespace i2p
|
|||||||
|
|
||||||
I2NPMessage * CreateI2NPMessage (I2NPMessageType msgType, const uint8_t * buf, int len, uint32_t replyMsgID)
|
I2NPMessage * CreateI2NPMessage (I2NPMessageType msgType, const uint8_t * buf, int len, uint32_t replyMsgID)
|
||||||
{
|
{
|
||||||
I2NPMessage * msg = NewI2NPMessage ();
|
I2NPMessage * msg = NewI2NPMessage (len);
|
||||||
memcpy (msg->GetPayload (), buf, len);
|
memcpy (msg->GetPayload (), buf, len);
|
||||||
msg->len += len;
|
msg->len += len;
|
||||||
FillI2NPMessageHeader (msg, msgType, replyMsgID);
|
FillI2NPMessageHeader (msg, msgType, replyMsgID);
|
||||||
@ -94,7 +101,8 @@ namespace i2p
|
|||||||
}
|
}
|
||||||
|
|
||||||
I2NPMessage * CreateDatabaseLookupMsg (const uint8_t * key, const uint8_t * from,
|
I2NPMessage * CreateDatabaseLookupMsg (const uint8_t * key, const uint8_t * from,
|
||||||
uint32_t replyTunnelID, bool exploratory, std::set<i2p::data::IdentHash> * excludedPeers)
|
uint32_t replyTunnelID, bool exploratory, std::set<i2p::data::IdentHash> * excludedPeers,
|
||||||
|
bool encryption)
|
||||||
{
|
{
|
||||||
I2NPMessage * m = NewI2NPMessage ();
|
I2NPMessage * m = NewI2NPMessage ();
|
||||||
uint8_t * buf = m->GetPayload ();
|
uint8_t * buf = m->GetPayload ();
|
||||||
@ -104,12 +112,13 @@ namespace i2p
|
|||||||
buf += 32;
|
buf += 32;
|
||||||
if (replyTunnelID)
|
if (replyTunnelID)
|
||||||
{
|
{
|
||||||
*buf = 0x01; // set delivery flag
|
*buf = encryption ? 0x03: 0x01; // set delivery flag
|
||||||
*(uint32_t *)(buf+1) = htobe32 (replyTunnelID);
|
*(uint32_t *)(buf+1) = htobe32 (replyTunnelID);
|
||||||
buf += 5;
|
buf += 5;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
encryption = false; // encryption can we set for tunnels only
|
||||||
*buf = 0; // flag
|
*buf = 0; // flag
|
||||||
buf++;
|
buf++;
|
||||||
}
|
}
|
||||||
@ -142,58 +151,63 @@ namespace i2p
|
|||||||
buf += 2;
|
buf += 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (encryption)
|
||||||
|
{
|
||||||
|
// session key and tag for reply
|
||||||
|
auto& rnd = i2p::context.GetRandomNumberGenerator ();
|
||||||
|
rnd.GenerateBlock (buf, 32); // key
|
||||||
|
buf[32] = 1; // 1 tag
|
||||||
|
rnd.GenerateBlock (buf + 33, 32); // tag
|
||||||
|
i2p::garlic::routing.AddSessionKey (buf, buf + 33); // introduce new key-tag to garlic engine
|
||||||
|
buf += 65;
|
||||||
|
}
|
||||||
m->len += (buf - m->GetPayload ());
|
m->len += (buf - m->GetPayload ());
|
||||||
FillI2NPMessageHeader (m, eI2NPDatabaseLookup);
|
FillI2NPMessageHeader (m, eI2NPDatabaseLookup);
|
||||||
return m;
|
return m;
|
||||||
}
|
}
|
||||||
|
|
||||||
void HandleDatabaseLookupMsg (uint8_t * buf, size_t len)
|
I2NPMessage * CreateDatabaseSearchReply (const i2p::data::IdentHash& ident,
|
||||||
|
const i2p::data::RouterInfo * floodfill)
|
||||||
{
|
{
|
||||||
char key[48];
|
I2NPMessage * m = NewI2NPShortMessage ();
|
||||||
int l = i2p::data::ByteStreamToBase64 (buf, 32, key, 48);
|
|
||||||
key[l] = 0;
|
|
||||||
LogPrint ("DatabaseLookup for ", key, " recieved");
|
|
||||||
uint8_t flag = buf[64];
|
|
||||||
uint32_t replyTunnelID = 0;
|
|
||||||
if (flag & 0x01) //reply to yunnel
|
|
||||||
replyTunnelID = be32toh (*(uint32_t *)(buf + 64));
|
|
||||||
// TODO: implement search. We send non-found for now
|
|
||||||
I2NPMessage * replyMsg = CreateDatabaseSearchReply (buf);
|
|
||||||
if (replyTunnelID)
|
|
||||||
i2p::tunnel::tunnels.GetNextOutboundTunnel ()->SendTunnelDataMsg (buf+32, replyTunnelID, replyMsg);
|
|
||||||
else
|
|
||||||
i2p::transports.SendMessage (buf, replyMsg);
|
|
||||||
}
|
|
||||||
|
|
||||||
I2NPMessage * CreateDatabaseSearchReply (const i2p::data::IdentHash& ident)
|
|
||||||
{
|
|
||||||
I2NPMessage * m = NewI2NPMessage ();
|
|
||||||
uint8_t * buf = m->GetPayload ();
|
uint8_t * buf = m->GetPayload ();
|
||||||
|
size_t len = 0;
|
||||||
memcpy (buf, ident, 32);
|
memcpy (buf, ident, 32);
|
||||||
buf[32] = 0; // TODO:
|
len += 32;
|
||||||
memcpy (buf + 33, i2p::context.GetRouterInfo ().GetIdentHash (), 32);
|
buf[len] = floodfill ? 1 : 0; // 1 router for now
|
||||||
m->len += 65;
|
len++;
|
||||||
|
if (floodfill)
|
||||||
|
{
|
||||||
|
memcpy (buf + len, floodfill->GetIdentHash (), 32);
|
||||||
|
len += 32;
|
||||||
|
}
|
||||||
|
memcpy (buf + len, i2p::context.GetRouterInfo ().GetIdentHash (), 32);
|
||||||
|
len += 32;
|
||||||
|
m->len += len;
|
||||||
FillI2NPMessageHeader (m, eI2NPDatabaseSearchReply);
|
FillI2NPMessageHeader (m, eI2NPDatabaseSearchReply);
|
||||||
return m;
|
return m;
|
||||||
}
|
}
|
||||||
|
|
||||||
I2NPMessage * CreateDatabaseStoreMsg ()
|
I2NPMessage * CreateDatabaseStoreMsg (const i2p::data::RouterInfo * router)
|
||||||
{
|
{
|
||||||
I2NPMessage * m = NewI2NPMessage ();
|
if (!router) // we send own RouterInfo
|
||||||
|
router = &context.GetRouterInfo ();
|
||||||
|
|
||||||
|
I2NPMessage * m = NewI2NPShortMessage ();
|
||||||
I2NPDatabaseStoreMsg * msg = (I2NPDatabaseStoreMsg *)m->GetPayload ();
|
I2NPDatabaseStoreMsg * msg = (I2NPDatabaseStoreMsg *)m->GetPayload ();
|
||||||
|
|
||||||
memcpy (msg->key, context.GetRouterInfo ().GetIdentHash (), 32);
|
memcpy (msg->key, router->GetIdentHash (), 32);
|
||||||
msg->type = 0;
|
msg->type = 0;
|
||||||
msg->replyToken = 0;
|
msg->replyToken = 0;
|
||||||
|
|
||||||
CryptoPP::Gzip compressor;
|
CryptoPP::Gzip compressor;
|
||||||
compressor.Put ((uint8_t *)context.GetRouterInfo ().GetBuffer (), context.GetRouterInfo ().GetBufferLen ());
|
compressor.Put (router->GetBuffer (), router->GetBufferLen ());
|
||||||
compressor.MessageEnd();
|
compressor.MessageEnd();
|
||||||
// WARNING!!! MaxRetrievable() return uint64_t. Åñòü ïîäîçðåíèå, ÷òî ÷òî-òî íå òàê
|
auto size = compressor.MaxRetrievable ();
|
||||||
int size = compressor.MaxRetrievable ();
|
|
||||||
uint8_t * buf = m->GetPayload () + sizeof (I2NPDatabaseStoreMsg);
|
uint8_t * buf = m->GetPayload () + sizeof (I2NPDatabaseStoreMsg);
|
||||||
*(uint16_t *)buf = htobe16 (size); // size
|
*(uint16_t *)buf = htobe16 (size); // size
|
||||||
buf += 2;
|
buf += 2;
|
||||||
|
// TODO: check if size doesn't exceed buffer
|
||||||
compressor.Get (buf, size);
|
compressor.Get (buf, size);
|
||||||
m->len += sizeof (I2NPDatabaseStoreMsg) + 2 + size; // payload size
|
m->len += sizeof (I2NPDatabaseStoreMsg) + 2 + size; // payload size
|
||||||
FillI2NPMessageHeader (m, eI2NPDatabaseStore);
|
FillI2NPMessageHeader (m, eI2NPDatabaseStore);
|
||||||
@ -201,6 +215,19 @@ namespace i2p
|
|||||||
return m;
|
return m;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
I2NPMessage * CreateDatabaseStoreMsg (const i2p::data::LeaseSet * leaseSet)
|
||||||
|
{
|
||||||
|
if (!leaseSet) return nullptr;
|
||||||
|
I2NPMessage * m = NewI2NPShortMessage ();
|
||||||
|
I2NPDatabaseStoreMsg * msg = (I2NPDatabaseStoreMsg *)m->GetPayload ();
|
||||||
|
memcpy (msg->key, leaseSet->GetIdentHash (), 32);
|
||||||
|
msg->type = 1; // LeaseSet
|
||||||
|
msg->replyToken = 0;
|
||||||
|
memcpy (m->GetPayload () + sizeof (I2NPDatabaseStoreMsg), leaseSet->GetBuffer (), leaseSet->GetBufferLen ());
|
||||||
|
m->len += leaseSet->GetBufferLen () + sizeof (I2NPDatabaseStoreMsg);
|
||||||
|
FillI2NPMessageHeader (m, eI2NPDatabaseStore);
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
I2NPBuildRequestRecordClearText CreateBuildRequestRecord (
|
I2NPBuildRequestRecordClearText CreateBuildRequestRecord (
|
||||||
const uint8_t * ourIdent, uint32_t receiveTunnelID,
|
const uint8_t * ourIdent, uint32_t receiveTunnelID,
|
||||||
@ -346,6 +373,7 @@ namespace i2p
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
LogPrint ("Outbound tunnel ", tunnel->GetTunnelID (), " has been declined");
|
LogPrint ("Outbound tunnel ", tunnel->GetTunnelID (), " has been declined");
|
||||||
|
i2p::transports.CloseSession (tunnel->GetTunnelConfig ()->GetFirstHop ()->router);
|
||||||
delete tunnel;
|
delete tunnel;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -375,7 +403,7 @@ namespace i2p
|
|||||||
|
|
||||||
I2NPMessage * CreateTunnelGatewayMsg (uint32_t tunnelID, const uint8_t * buf, size_t len)
|
I2NPMessage * CreateTunnelGatewayMsg (uint32_t tunnelID, const uint8_t * buf, size_t len)
|
||||||
{
|
{
|
||||||
I2NPMessage * msg = NewI2NPMessage ();
|
I2NPMessage * msg = NewI2NPMessage (len);
|
||||||
TunnelGatewayHeader * header = (TunnelGatewayHeader *)msg->GetPayload ();
|
TunnelGatewayHeader * header = (TunnelGatewayHeader *)msg->GetPayload ();
|
||||||
header->tunnelID = htobe32 (tunnelID);
|
header->tunnelID = htobe32 (tunnelID);
|
||||||
header->length = htobe16 (len);
|
header->length = htobe16 (len);
|
||||||
@ -410,7 +438,7 @@ namespace i2p
|
|||||||
I2NPMessage * CreateTunnelGatewayMsg (uint32_t tunnelID, I2NPMessageType msgType,
|
I2NPMessage * CreateTunnelGatewayMsg (uint32_t tunnelID, I2NPMessageType msgType,
|
||||||
const uint8_t * buf, size_t len, uint32_t replyMsgID)
|
const uint8_t * buf, size_t len, uint32_t replyMsgID)
|
||||||
{
|
{
|
||||||
I2NPMessage * msg = NewI2NPMessage ();
|
I2NPMessage * msg = NewI2NPMessage (len);
|
||||||
size_t gatewayMsgOffset = sizeof (I2NPHeader) + sizeof (TunnelGatewayHeader);
|
size_t gatewayMsgOffset = sizeof (I2NPHeader) + sizeof (TunnelGatewayHeader);
|
||||||
msg->offset += gatewayMsgOffset;
|
msg->offset += gatewayMsgOffset;
|
||||||
msg->len += gatewayMsgOffset;
|
msg->len += gatewayMsgOffset;
|
||||||
@ -435,6 +463,13 @@ namespace i2p
|
|||||||
msg->offset += sizeof (I2NPHeader) + sizeof (TunnelGatewayHeader);
|
msg->offset += sizeof (I2NPHeader) + sizeof (TunnelGatewayHeader);
|
||||||
msg->len = msg->offset + len;
|
msg->len = msg->offset + len;
|
||||||
LogPrint ("TunnelGateway of ", (int)len, " bytes for tunnel ", (unsigned int)tunnelID, ". Msg type ", (int)msg->GetHeader()->typeID);
|
LogPrint ("TunnelGateway of ", (int)len, " bytes for tunnel ", (unsigned int)tunnelID, ". Msg type ", (int)msg->GetHeader()->typeID);
|
||||||
|
if (msg->GetHeader()->typeID == eI2NPDatabaseStore)
|
||||||
|
{
|
||||||
|
// transit DatabaseStore my contain new/updated RI
|
||||||
|
auto ds = NewI2NPMessage ();
|
||||||
|
*ds = *msg;
|
||||||
|
i2p::data::netdb.PostI2NPMsg (ds);
|
||||||
|
}
|
||||||
i2p::tunnel::TransitTunnel * tunnel = i2p::tunnel::tunnels.GetTransitTunnel (tunnelID);
|
i2p::tunnel::TransitTunnel * tunnel = i2p::tunnel::tunnels.GetTransitTunnel (tunnelID);
|
||||||
if (tunnel)
|
if (tunnel)
|
||||||
tunnel->SendTunnelDataMsg (msg);
|
tunnel->SendTunnelDataMsg (msg);
|
||||||
@ -477,10 +512,6 @@ namespace i2p
|
|||||||
LogPrint ("TunnelBuildReply");
|
LogPrint ("TunnelBuildReply");
|
||||||
// TODO:
|
// TODO:
|
||||||
break;
|
break;
|
||||||
case eI2NPDatabaseLookup:
|
|
||||||
LogPrint ("DatabaseLookup");
|
|
||||||
HandleDatabaseLookupMsg (buf, size);
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
LogPrint ("Unexpected message ", (int)header->typeID);
|
LogPrint ("Unexpected message ", (int)header->typeID);
|
||||||
}
|
}
|
||||||
@ -505,13 +536,11 @@ namespace i2p
|
|||||||
i2p::garlic::routing.HandleGarlicMessage (msg);
|
i2p::garlic::routing.HandleGarlicMessage (msg);
|
||||||
break;
|
break;
|
||||||
case eI2NPDatabaseStore:
|
case eI2NPDatabaseStore:
|
||||||
LogPrint ("DatabaseStore");
|
|
||||||
i2p::data::netdb.PostI2NPMsg (msg);
|
|
||||||
break;
|
|
||||||
case eI2NPDatabaseSearchReply:
|
case eI2NPDatabaseSearchReply:
|
||||||
LogPrint ("DatabaseSearchReply");
|
case eI2NPDatabaseLookup:
|
||||||
|
// forward to netDb
|
||||||
i2p::data::netdb.PostI2NPMsg (msg);
|
i2p::data::netdb.PostI2NPMsg (msg);
|
||||||
break;
|
break;
|
||||||
case eI2NPDeliveryStatus:
|
case eI2NPDeliveryStatus:
|
||||||
LogPrint ("DeliveryStatus");
|
LogPrint ("DeliveryStatus");
|
||||||
if (msg->from && msg->from->GetTunnelPool ())
|
if (msg->from && msg->from->GetTunnelPool ())
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "I2PEndian.h"
|
#include "I2PEndian.h"
|
||||||
#include "RouterInfo.h"
|
#include "RouterInfo.h"
|
||||||
|
#include "LeaseSet.h"
|
||||||
|
|
||||||
namespace i2p
|
namespace i2p
|
||||||
{
|
{
|
||||||
@ -100,13 +101,17 @@ namespace tunnel
|
|||||||
class InboundTunnel;
|
class InboundTunnel;
|
||||||
}
|
}
|
||||||
|
|
||||||
const int NTCP_MAX_MESSAGE_SIZE = 16384;
|
const size_t I2NP_MAX_MESSAGE_SIZE = 32768;
|
||||||
|
const size_t I2NP_MAX_SHORT_MESSAGE_SIZE = 2400;
|
||||||
struct I2NPMessage
|
struct I2NPMessage
|
||||||
{
|
{
|
||||||
uint8_t buf[NTCP_MAX_MESSAGE_SIZE];
|
uint8_t * buf;
|
||||||
size_t len, offset;
|
size_t len, offset, maxLen;
|
||||||
i2p::tunnel::InboundTunnel * from;
|
i2p::tunnel::InboundTunnel * from;
|
||||||
|
|
||||||
|
I2NPMessage (): buf (nullptr),len (sizeof (I2NPHeader) + 2),
|
||||||
|
offset(2), maxLen (0), from (nullptr) {};
|
||||||
|
// reserve 2 bytes for NTCP header
|
||||||
I2NPHeader * GetHeader () { return (I2NPHeader *)GetBuffer (); };
|
I2NPHeader * GetHeader () { return (I2NPHeader *)GetBuffer (); };
|
||||||
uint8_t * GetPayload () { return GetBuffer () + sizeof(I2NPHeader); };
|
uint8_t * GetPayload () { return GetBuffer () + sizeof(I2NPHeader); };
|
||||||
uint8_t * GetBuffer () { return buf + offset; };
|
uint8_t * GetBuffer () { return buf + offset; };
|
||||||
@ -143,7 +148,17 @@ namespace tunnel
|
|||||||
return be32toh (header.msgID);
|
return be32toh (header.msgID);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<int sz>
|
||||||
|
struct I2NPMessageBuffer: public I2NPMessage
|
||||||
|
{
|
||||||
|
I2NPMessageBuffer () { buf = m_Buffer; maxLen = sz; };
|
||||||
|
uint8_t m_Buffer[sz];
|
||||||
|
};
|
||||||
|
|
||||||
I2NPMessage * NewI2NPMessage ();
|
I2NPMessage * NewI2NPMessage ();
|
||||||
|
I2NPMessage * NewI2NPShortMessage ();
|
||||||
|
I2NPMessage * NewI2NPMessage (size_t len);
|
||||||
void DeleteI2NPMessage (I2NPMessage * msg);
|
void DeleteI2NPMessage (I2NPMessage * msg);
|
||||||
void FillI2NPMessageHeader (I2NPMessage * msg, I2NPMessageType msgType, uint32_t replyMsgID = 0);
|
void FillI2NPMessageHeader (I2NPMessage * msg, I2NPMessageType msgType, uint32_t replyMsgID = 0);
|
||||||
void RenewI2NPMessageHeader (I2NPMessage * msg);
|
void RenewI2NPMessageHeader (I2NPMessage * msg);
|
||||||
@ -153,12 +168,12 @@ namespace tunnel
|
|||||||
I2NPMessage * CreateDeliveryStatusMsg (uint32_t msgID);
|
I2NPMessage * CreateDeliveryStatusMsg (uint32_t msgID);
|
||||||
I2NPMessage * CreateDatabaseLookupMsg (const uint8_t * key, const uint8_t * from,
|
I2NPMessage * CreateDatabaseLookupMsg (const uint8_t * key, const uint8_t * from,
|
||||||
uint32_t replyTunnelID, bool exploratory = false,
|
uint32_t replyTunnelID, bool exploratory = false,
|
||||||
std::set<i2p::data::IdentHash> * excludedPeers = nullptr);
|
std::set<i2p::data::IdentHash> * excludedPeers = nullptr, bool encryption = false);
|
||||||
void HandleDatabaseLookupMsg (uint8_t * buf, size_t len);
|
I2NPMessage * CreateDatabaseSearchReply (const i2p::data::IdentHash& ident, const i2p::data::RouterInfo * floodfill);
|
||||||
I2NPMessage * CreateDatabaseSearchReply (const i2p::data::IdentHash& ident);
|
|
||||||
|
|
||||||
I2NPMessage * CreateDatabaseStoreMsg ();
|
|
||||||
|
|
||||||
|
I2NPMessage * CreateDatabaseStoreMsg (const i2p::data::RouterInfo * router = nullptr);
|
||||||
|
I2NPMessage * CreateDatabaseStoreMsg (const i2p::data::LeaseSet * leaseSet);
|
||||||
|
|
||||||
I2NPBuildRequestRecordClearText CreateBuildRequestRecord (
|
I2NPBuildRequestRecordClearText CreateBuildRequestRecord (
|
||||||
const uint8_t * ourIdent, uint32_t receiveTunnelID,
|
const uint8_t * ourIdent, uint32_t receiveTunnelID,
|
||||||
const uint8_t * nextIdent, uint32_t nextTunnelID,
|
const uint8_t * nextIdent, uint32_t nextTunnelID,
|
||||||
|
20
Identity.cpp
20
Identity.cpp
@ -16,20 +16,27 @@ namespace data
|
|||||||
{
|
{
|
||||||
// copy public and signing keys together
|
// copy public and signing keys together
|
||||||
memcpy (publicKey, keys.publicKey, sizeof (publicKey) + sizeof (signingKey));
|
memcpy (publicKey, keys.publicKey, sizeof (publicKey) + sizeof (signingKey));
|
||||||
memset (certificate, 0, sizeof (certificate));
|
memset (&certificate, 0, sizeof (certificate));
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Identity::FromBase64 (const std::string& s)
|
bool Identity::FromBase64 (const std::string& s)
|
||||||
{
|
{
|
||||||
size_t count = Base64ToByteStream (s.c_str(), s.length(), publicKey, sizeof (Identity));
|
size_t count = Base64ToByteStream (s.c_str(), s.length(), publicKey, DEFAULT_IDENTITY_SIZE);
|
||||||
return count == sizeof(Identity);
|
return count == DEFAULT_IDENTITY_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t Identity::FromBuffer (const uint8_t * buf, size_t len)
|
||||||
|
{
|
||||||
|
memcpy (publicKey, buf, DEFAULT_IDENTITY_SIZE);
|
||||||
|
// TODO: process certificate
|
||||||
|
return DEFAULT_IDENTITY_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
IdentHash Identity::Hash() const
|
IdentHash Identity::Hash() const
|
||||||
{
|
{
|
||||||
IdentHash hash;
|
IdentHash hash;
|
||||||
CryptoPP::SHA256().CalculateDigest(hash, publicKey, sizeof (Identity));
|
CryptoPP::SHA256().CalculateDigest(hash, publicKey, DEFAULT_IDENTITY_SIZE);
|
||||||
return hash;
|
return hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -40,11 +47,6 @@ namespace data
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IdentHash::FromBase32(const std::string& s)
|
|
||||||
{
|
|
||||||
size_t count = Base32ToByteStream(s.c_str(), s.length(), m_Hash, sizeof(m_Hash));
|
|
||||||
return count == sizeof(m_Hash);
|
|
||||||
}
|
|
||||||
|
|
||||||
Keys CreateRandomKeys ()
|
Keys CreateRandomKeys ()
|
||||||
{
|
{
|
||||||
|
99
Identity.h
99
Identity.h
@ -3,13 +3,57 @@
|
|||||||
|
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <string>
|
||||||
|
#include "base64.h"
|
||||||
#include "ElGamal.h"
|
#include "ElGamal.h"
|
||||||
|
|
||||||
namespace i2p
|
namespace i2p
|
||||||
{
|
{
|
||||||
namespace data
|
namespace data
|
||||||
{
|
{
|
||||||
class IdentHash;
|
template<int sz>
|
||||||
|
class Tag
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
Tag (const uint8_t * buf) { memcpy (m_Buf, buf, sz); };
|
||||||
|
Tag (const Tag<sz>& ) = default;
|
||||||
|
#ifndef _WIN32 // FIXME!!! msvs 2013 can't compile it
|
||||||
|
Tag (Tag<sz>&& ) = default;
|
||||||
|
#endif
|
||||||
|
Tag () = default;
|
||||||
|
|
||||||
|
Tag<sz>& operator= (const Tag<sz>& ) = default;
|
||||||
|
#ifndef _WIN32
|
||||||
|
Tag<sz>& operator= (Tag<sz>&& ) = default;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
uint8_t * operator()() { return m_Buf; };
|
||||||
|
const uint8_t * operator()() const { return m_Buf; };
|
||||||
|
|
||||||
|
operator uint8_t * () { return m_Buf; };
|
||||||
|
operator const uint8_t * () const { return m_Buf; };
|
||||||
|
|
||||||
|
bool operator== (const Tag<sz>& other) const { return !memcmp (m_Buf, other.m_Buf, sz); };
|
||||||
|
bool operator< (const Tag<sz>& other) const { return memcmp (m_Buf, other.m_Buf, sz) < 0; };
|
||||||
|
|
||||||
|
std::string ToBase64 () const
|
||||||
|
{
|
||||||
|
char str[sz*2];
|
||||||
|
int l = i2p::data::ByteStreamToBase64 (m_Buf, sz, str, sz*2);
|
||||||
|
str[l] = 0;
|
||||||
|
return std::string (str);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
union // 8 bytes alignment
|
||||||
|
{
|
||||||
|
uint8_t m_Buf[sz];
|
||||||
|
uint64_t ll[sz/8];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
typedef Tag<32> IdentHash;
|
||||||
|
|
||||||
#pragma pack(1)
|
#pragma pack(1)
|
||||||
|
|
||||||
@ -27,14 +71,28 @@ namespace data
|
|||||||
uint8_t signingKey[128];
|
uint8_t signingKey[128];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const uint8_t CERTIFICATE_TYPE_NULL = 0;
|
||||||
|
const uint8_t CERTIFICATE_TYPE_HASHCASH = 1;
|
||||||
|
const uint8_t CERTIFICATE_TYPE_HIDDEN = 2;
|
||||||
|
const uint8_t CERTIFICATE_TYPE_SIGNED = 3;
|
||||||
|
const uint8_t CERTIFICATE_TYPE_MULTIPLE = 4;
|
||||||
|
const uint8_t CERTIFICATE_TYPE_KEY = 5;
|
||||||
|
|
||||||
|
const size_t DEFAULT_IDENTITY_SIZE = 387;
|
||||||
struct Identity
|
struct Identity
|
||||||
{
|
{
|
||||||
uint8_t publicKey[256];
|
uint8_t publicKey[256];
|
||||||
uint8_t signingKey[128];
|
uint8_t signingKey[128];
|
||||||
uint8_t certificate[3];
|
struct
|
||||||
|
{
|
||||||
|
uint8_t type;
|
||||||
|
uint16_t length;
|
||||||
|
} certificate;
|
||||||
|
|
||||||
Identity& operator=(const Keys& keys);
|
Identity& operator=(const Keys& keys);
|
||||||
bool FromBase64(const std::string& );
|
bool FromBase64(const std::string& );
|
||||||
|
size_t FromBuffer (const uint8_t * buf, size_t len);
|
||||||
IdentHash Hash() const;
|
IdentHash Hash() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -52,39 +110,7 @@ namespace data
|
|||||||
};
|
};
|
||||||
|
|
||||||
#pragma pack()
|
#pragma pack()
|
||||||
|
|
||||||
class IdentHash
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
|
|
||||||
IdentHash (const uint8_t * hash) { memcpy (m_Hash, hash, 32); };
|
|
||||||
IdentHash (const IdentHash& ) = default;
|
|
||||||
#ifndef _WIN32 // FIXME!!! msvs 2013 can't compile it
|
|
||||||
IdentHash (IdentHash&& ) = default;
|
|
||||||
#endif
|
|
||||||
IdentHash () = default;
|
|
||||||
|
|
||||||
IdentHash& operator= (const IdentHash& ) = default;
|
|
||||||
#ifndef _WIN32
|
|
||||||
IdentHash& operator= (IdentHash&& ) = default;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
uint8_t * operator()() { return m_Hash; };
|
|
||||||
const uint8_t * operator()() const { return m_Hash; };
|
|
||||||
|
|
||||||
operator uint8_t * () { return m_Hash; };
|
|
||||||
operator const uint8_t * () const { return m_Hash; };
|
|
||||||
|
|
||||||
bool operator== (const IdentHash& other) const { return !memcmp (m_Hash, other.m_Hash, 32); };
|
|
||||||
bool operator< (const IdentHash& other) const { return memcmp (m_Hash, other.m_Hash, 32) < 0; };
|
|
||||||
|
|
||||||
bool FromBase32(const std::string&);
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
uint8_t m_Hash[32];
|
|
||||||
};
|
|
||||||
|
|
||||||
Keys CreateRandomKeys ();
|
Keys CreateRandomKeys ();
|
||||||
void CreateRandomDHKeysPair (DHKeysPair * keys); // for transport sessions
|
void CreateRandomDHKeysPair (DHKeysPair * keys); // for transport sessions
|
||||||
|
|
||||||
@ -141,9 +167,10 @@ namespace data
|
|||||||
|
|
||||||
virtual ~LocalDestination() {};
|
virtual ~LocalDestination() {};
|
||||||
virtual const IdentHash& GetIdentHash () const = 0;
|
virtual const IdentHash& GetIdentHash () const = 0;
|
||||||
|
virtual const Identity& GetIdentity () const = 0;
|
||||||
virtual const uint8_t * GetEncryptionPrivateKey () const = 0;
|
virtual const uint8_t * GetEncryptionPrivateKey () const = 0;
|
||||||
virtual const uint8_t * GetEncryptionPublicKey () const = 0;
|
virtual const uint8_t * GetEncryptionPublicKey () const = 0;
|
||||||
virtual void UpdateLeaseSet () = 0; // LeaseSet must be updated
|
virtual void Sign (const uint8_t * buf, int len, uint8_t * signature) const = 0;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
69
LeaseSet.cpp
69
LeaseSet.cpp
@ -4,6 +4,7 @@
|
|||||||
#include "Log.h"
|
#include "Log.h"
|
||||||
#include "Timestamp.h"
|
#include "Timestamp.h"
|
||||||
#include "NetDb.h"
|
#include "NetDb.h"
|
||||||
|
#include "TunnelPool.h"
|
||||||
#include "LeaseSet.h"
|
#include "LeaseSet.h"
|
||||||
|
|
||||||
namespace i2p
|
namespace i2p
|
||||||
@ -11,26 +12,64 @@ namespace i2p
|
|||||||
namespace data
|
namespace data
|
||||||
{
|
{
|
||||||
|
|
||||||
LeaseSet::LeaseSet (const uint8_t * buf, int len)
|
LeaseSet::LeaseSet (const uint8_t * buf, int len, bool unsolicited):
|
||||||
|
m_IsUnsolicited (unsolicited)
|
||||||
{
|
{
|
||||||
#pragma pack(1)
|
memcpy (m_Buffer, buf, len);
|
||||||
struct H
|
m_BufferLen = len;
|
||||||
{
|
ReadFromBuffer ();
|
||||||
Identity destination;
|
}
|
||||||
uint8_t encryptionKey[256];
|
|
||||||
uint8_t signingKey[128];
|
|
||||||
uint8_t num;
|
|
||||||
};
|
|
||||||
#pragma pack ()
|
|
||||||
|
|
||||||
const H * header = (const H *)buf;
|
LeaseSet::LeaseSet (const i2p::tunnel::TunnelPool& pool):
|
||||||
|
m_IsUnsolicited (false)
|
||||||
|
{
|
||||||
|
m_BufferLen = 0;
|
||||||
|
// header
|
||||||
|
const i2p::data::LocalDestination& localDestination = pool.GetLocalDestination ();
|
||||||
|
LeaseSetHeader * header = (LeaseSetHeader *)m_Buffer;
|
||||||
|
header->destination = localDestination.GetIdentity ();
|
||||||
|
memcpy (header->encryptionKey, localDestination.GetEncryptionPublicKey (), 256);
|
||||||
|
memset (header->signingKey, 0, 128);
|
||||||
|
auto tunnels = pool.GetInboundTunnels (5); // 5 tunnels maximum
|
||||||
|
header->num = tunnels.size (); // num leases
|
||||||
|
m_BufferLen += sizeof (LeaseSetHeader);
|
||||||
|
// leases
|
||||||
|
for (auto it: tunnels)
|
||||||
|
{
|
||||||
|
Lease * lease = (Lease *)(m_Buffer + m_BufferLen);
|
||||||
|
memcpy (lease->tunnelGateway, it->GetNextIdentHash (), 32);
|
||||||
|
lease->tunnelID = htobe32 (it->GetNextTunnelID ());
|
||||||
|
uint64_t ts = it->GetCreationTime () + i2p::tunnel::TUNNEL_EXPIRATION_TIMEOUT - 60; // 1 minute before expiration
|
||||||
|
ts *= 1000; // in milliseconds
|
||||||
|
lease->endDate = htobe64 (ts);
|
||||||
|
m_BufferLen += sizeof (Lease);
|
||||||
|
}
|
||||||
|
// signature
|
||||||
|
localDestination.Sign (m_Buffer, m_BufferLen, m_Buffer + m_BufferLen);
|
||||||
|
m_BufferLen += 40;
|
||||||
|
LogPrint ("Local LeaseSet of ", tunnels.size (), " leases created");
|
||||||
|
|
||||||
|
ReadFromBuffer ();
|
||||||
|
}
|
||||||
|
|
||||||
|
void LeaseSet::Update (const uint8_t * buf, int len)
|
||||||
|
{
|
||||||
|
m_Leases.clear ();
|
||||||
|
memcpy (m_Buffer, buf, len);
|
||||||
|
m_BufferLen = len;
|
||||||
|
ReadFromBuffer ();
|
||||||
|
}
|
||||||
|
|
||||||
|
void LeaseSet::ReadFromBuffer ()
|
||||||
|
{
|
||||||
|
const LeaseSetHeader * header = (const LeaseSetHeader *)m_Buffer;
|
||||||
m_Identity = header->destination;
|
m_Identity = header->destination;
|
||||||
m_IdentHash = m_Identity.Hash();
|
m_IdentHash = m_Identity.Hash();
|
||||||
memcpy (m_EncryptionKey, header->encryptionKey, 256);
|
memcpy (m_EncryptionKey, header->encryptionKey, 256);
|
||||||
LogPrint ("LeaseSet num=", (int)header->num);
|
LogPrint ("LeaseSet num=", (int)header->num);
|
||||||
|
|
||||||
// process leases
|
// process leases
|
||||||
const uint8_t * leases = buf + sizeof (H);
|
const uint8_t * leases = m_Buffer + sizeof (LeaseSetHeader);
|
||||||
for (int i = 0; i < header->num; i++)
|
for (int i = 0; i < header->num; i++)
|
||||||
{
|
{
|
||||||
Lease lease = *(Lease *)leases;
|
Lease lease = *(Lease *)leases;
|
||||||
@ -53,10 +92,10 @@ namespace data
|
|||||||
pubKey.Initialize (i2p::crypto::dsap, i2p::crypto::dsaq, i2p::crypto::dsag,
|
pubKey.Initialize (i2p::crypto::dsap, i2p::crypto::dsaq, i2p::crypto::dsag,
|
||||||
CryptoPP::Integer (m_Identity.signingKey, 128));
|
CryptoPP::Integer (m_Identity.signingKey, 128));
|
||||||
CryptoPP::DSA::Verifier verifier (pubKey);
|
CryptoPP::DSA::Verifier verifier (pubKey);
|
||||||
if (!verifier.VerifyMessage (buf, leases - buf, leases, 40))
|
if (!verifier.VerifyMessage (m_Buffer, leases - m_Buffer, leases, 40))
|
||||||
LogPrint ("LeaseSet verification failed");
|
LogPrint ("LeaseSet verification failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::vector<Lease> LeaseSet::GetNonExpiredLeases () const
|
const std::vector<Lease> LeaseSet::GetNonExpiredLeases () const
|
||||||
{
|
{
|
||||||
auto ts = i2p::util::GetMillisecondsSinceEpoch ();
|
auto ts = i2p::util::GetMillisecondsSinceEpoch ();
|
||||||
|
32
LeaseSet.h
32
LeaseSet.h
@ -8,6 +8,12 @@
|
|||||||
|
|
||||||
namespace i2p
|
namespace i2p
|
||||||
{
|
{
|
||||||
|
|
||||||
|
namespace tunnel
|
||||||
|
{
|
||||||
|
class TunnelPool;
|
||||||
|
}
|
||||||
|
|
||||||
namespace data
|
namespace data
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -28,16 +34,33 @@ namespace data
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct LeaseSetHeader
|
||||||
|
{
|
||||||
|
Identity destination;
|
||||||
|
uint8_t encryptionKey[256];
|
||||||
|
uint8_t signingKey[128];
|
||||||
|
uint8_t num;
|
||||||
|
};
|
||||||
|
|
||||||
#pragma pack()
|
#pragma pack()
|
||||||
|
|
||||||
|
const int MAX_LS_BUFFER_SIZE = 2048;
|
||||||
class LeaseSet: public RoutingDestination
|
class LeaseSet: public RoutingDestination
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
LeaseSet (const uint8_t * buf, int len);
|
LeaseSet (const uint8_t * buf, int len, bool unsolicited = false);
|
||||||
LeaseSet (const LeaseSet& ) = default;
|
LeaseSet (const LeaseSet& ) = default;
|
||||||
|
LeaseSet (const i2p::tunnel::TunnelPool& pool);
|
||||||
LeaseSet& operator=(const LeaseSet& ) = default;
|
LeaseSet& operator=(const LeaseSet& ) = default;
|
||||||
|
void Update (const uint8_t * buf, int len);
|
||||||
|
|
||||||
|
const uint8_t * GetBuffer () const { return m_Buffer; };
|
||||||
|
size_t GetBufferLen () const { return m_BufferLen; };
|
||||||
|
|
||||||
|
bool IsUnsolicited () const { return m_IsUnsolicited; };
|
||||||
|
void SetUnsolicited (bool unsolicited) { m_IsUnsolicited = unsolicited; };
|
||||||
|
|
||||||
// implements RoutingDestination
|
// implements RoutingDestination
|
||||||
const Identity& GetIdentity () const { return m_Identity; };
|
const Identity& GetIdentity () const { return m_Identity; };
|
||||||
const IdentHash& GetIdentHash () const { return m_IdentHash; };
|
const IdentHash& GetIdentHash () const { return m_IdentHash; };
|
||||||
@ -47,6 +70,10 @@ namespace data
|
|||||||
bool HasNonExpiredLeases () const;
|
bool HasNonExpiredLeases () const;
|
||||||
const uint8_t * GetEncryptionPublicKey () const { return m_EncryptionKey; };
|
const uint8_t * GetEncryptionPublicKey () const { return m_EncryptionKey; };
|
||||||
bool IsDestination () const { return true; };
|
bool IsDestination () const { return true; };
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
void ReadFromBuffer ();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
@ -54,6 +81,9 @@ namespace data
|
|||||||
Identity m_Identity;
|
Identity m_Identity;
|
||||||
IdentHash m_IdentHash;
|
IdentHash m_IdentHash;
|
||||||
uint8_t m_EncryptionKey[256];
|
uint8_t m_EncryptionKey[256];
|
||||||
|
uint8_t m_Buffer[MAX_LS_BUFFER_SIZE];
|
||||||
|
size_t m_BufferLen;
|
||||||
|
bool m_IsUnsolicited;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
4
Log.cpp
4
Log.cpp
@ -1,12 +1,10 @@
|
|||||||
#include "Log.h"
|
#include "Log.h"
|
||||||
|
|
||||||
Log g_Log;
|
Log * g_Log = nullptr;
|
||||||
|
|
||||||
void LogMsg::Process()
|
void LogMsg::Process()
|
||||||
{
|
{
|
||||||
output << s.str();
|
output << s.str();
|
||||||
|
|
||||||
std::cout << s.str (); // TODO: delete later
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Log::Flush ()
|
void Log::Flush ()
|
||||||
|
31
Log.h
31
Log.h
@ -37,7 +37,26 @@ class Log: public i2p::util::MsgQueue<LogMsg>
|
|||||||
std::ofstream * m_LogFile;
|
std::ofstream * m_LogFile;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern Log g_Log;
|
extern Log * g_Log;
|
||||||
|
|
||||||
|
inline void StartLog (const std::string& fullFilePath)
|
||||||
|
{
|
||||||
|
if (!g_Log)
|
||||||
|
{
|
||||||
|
g_Log = new Log ();
|
||||||
|
if (fullFilePath.length () > 0)
|
||||||
|
g_Log->SetLogFile (fullFilePath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void StopLog ()
|
||||||
|
{
|
||||||
|
if (g_Log)
|
||||||
|
{
|
||||||
|
delete g_Log;
|
||||||
|
g_Log = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
template<typename TValue>
|
template<typename TValue>
|
||||||
void LogPrint (std::stringstream& s, TValue arg)
|
void LogPrint (std::stringstream& s, TValue arg)
|
||||||
@ -55,10 +74,16 @@ void LogPrint (std::stringstream& s, TValue arg, TArgs... args)
|
|||||||
template<typename... TArgs>
|
template<typename... TArgs>
|
||||||
void LogPrint (TArgs... args)
|
void LogPrint (TArgs... args)
|
||||||
{
|
{
|
||||||
LogMsg * msg = g_Log.GetLogFile () ? new LogMsg (*g_Log.GetLogFile ()) : new LogMsg ();
|
LogMsg * msg = (g_Log && g_Log->GetLogFile ()) ? new LogMsg (*g_Log->GetLogFile ()) : new LogMsg ();
|
||||||
LogPrint (msg->s, args...);
|
LogPrint (msg->s, args...);
|
||||||
msg->s << std::endl;
|
msg->s << std::endl;
|
||||||
g_Log.Put (msg);
|
if (g_Log)
|
||||||
|
g_Log->Put (msg);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
msg->Process ();
|
||||||
|
delete msg;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
39
Makefile
39
Makefile
@ -1,38 +1,9 @@
|
|||||||
|
|
||||||
CC = g++
|
UNAME := $(shell uname -s)
|
||||||
CFLAGS = -g -Wall -std=c++0x
|
|
||||||
OBJECTS = obj/CryptoConst.o obj/base64.o obj/NTCPSession.o obj/RouterInfo.o obj/Transports.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/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/AddressBook.o obj/Daemon.o \
|
|
||||||
obj/DaemonLinux.o obj/SSUData.o obj/i2p.o obj/aes.o
|
|
||||||
INCFLAGS =
|
|
||||||
LDFLAGS = -Wl,-rpath,/usr/local/lib -lcryptopp -lboost_system -lboost_filesystem -lboost_regex -lboost_program_options -lpthread
|
|
||||||
LIBS =
|
|
||||||
|
|
||||||
#check if AES-NI is supported by CPU
|
ifeq ($(UNAME),Darwin)
|
||||||
ifneq ($(shell grep -c aes /proc/cpuinfo),0)
|
include Makefile.osx
|
||||||
CPU_FLAGS = -DAESNI
|
else
|
||||||
|
include Makefile.linux
|
||||||
endif
|
endif
|
||||||
|
|
||||||
all: obj i2p
|
|
||||||
|
|
||||||
i2p: $(OBJECTS:obj/%=obj/%)
|
|
||||||
$(CC) -o $@ $^ $(LDFLAGS) $(LIBS)
|
|
||||||
|
|
||||||
.SUFFIXES:
|
|
||||||
.SUFFIXES: .c .cc .C .cpp .o
|
|
||||||
|
|
||||||
obj/%.o : %.cpp
|
|
||||||
$(CC) -o $@ $< -c $(CFLAGS) $(INCFLAGS) $(CPU_FLAGS)
|
|
||||||
|
|
||||||
obj:
|
|
||||||
mkdir -p obj
|
|
||||||
|
|
||||||
clean:
|
|
||||||
rm -fr obj i2p
|
|
||||||
|
|
||||||
.PHONY: all
|
|
||||||
.PHONY: clean
|
|
||||||
|
|
||||||
|
33
Makefile.linux
Normal file
33
Makefile.linux
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
|
||||||
|
CC = g++
|
||||||
|
CFLAGS = -g -Wall -std=c++0x
|
||||||
|
include filelist.mk
|
||||||
|
INCFLAGS =
|
||||||
|
LDFLAGS = -Wl,-rpath,/usr/local/lib -lcryptopp -lboost_system -lboost_filesystem -lboost_regex -lboost_program_options -lpthread
|
||||||
|
LIBS =
|
||||||
|
|
||||||
|
#check if AES-NI is supported by CPU
|
||||||
|
ifneq ($(shell grep -c aes /proc/cpuinfo),0)
|
||||||
|
CPU_FLAGS = -DAESNI
|
||||||
|
endif
|
||||||
|
|
||||||
|
all: obj i2p
|
||||||
|
|
||||||
|
i2p: $(OBJECTS:obj/%=obj/%)
|
||||||
|
$(CC) -o $@ $^ $(LDFLAGS) $(LIBS)
|
||||||
|
|
||||||
|
.SUFFIXES:
|
||||||
|
.SUFFIXES: .c .cc .C .cpp .o
|
||||||
|
|
||||||
|
obj/%.o : %.cpp
|
||||||
|
$(CC) -o $@ $< -c $(CFLAGS) $(INCFLAGS) $(CPU_FLAGS)
|
||||||
|
|
||||||
|
obj:
|
||||||
|
mkdir -p obj
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -fr obj i2p
|
||||||
|
|
||||||
|
.PHONY: all
|
||||||
|
.PHONY: clean
|
||||||
|
|
23
Makefile.osx
23
Makefile.osx
@ -1,20 +1,15 @@
|
|||||||
#CC = clang++
|
CC = clang++
|
||||||
CC = g++
|
CFLAGS = -g -Wall -std=c++11 -lstdc++ -I/usr/local/include
|
||||||
CFLAGS = -g -Wall -std=c++11 -lstdc++
|
include filelist.mk
|
||||||
OBJECTS = obj/CryptoConst.o obj/base64.o obj/NTCPSession.o obj/RouterInfo.o obj/Transports.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/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/AddressBook.o obj/Daemon.o \
|
|
||||||
obj/DaemonLinux.o obj/SSUData.o obj/i2p.o obj/aes.o
|
|
||||||
INCFLAGS = -DCRYPTOPP_DISABLE_ASM
|
INCFLAGS = -DCRYPTOPP_DISABLE_ASM
|
||||||
LDFLAGS = -Wl,-rpath,/usr/local/lib -lcryptopp -lboost_system -lboost_filesystem -lboost_regex -lboost_program_options -lpthread
|
LDFLAGS = -Wl,-rpath,/usr/local/lib -L/usr/local/lib -lcryptopp -lboost_system -lboost_filesystem -lboost_regex -lboost_program_options -lpthread
|
||||||
LIBS =
|
LIBS =
|
||||||
|
|
||||||
#check if AES-NI is supported by CPU
|
# OSX Notes
|
||||||
ifneq ($(shell grep -c aes /proc/cpuinfo),0)
|
# http://www.hutsby.net/2011/08/macs-with-aes-ni.html
|
||||||
CPU_FLAGS = -DAESNI
|
# Seems like all recent Mac's have AES-NI, after firmware upgrade 2.2
|
||||||
endif
|
# Found no good way to detect it from command line. TODO: Might be some osx sysinfo magic
|
||||||
|
CPU_FLAGS = -DAESNI
|
||||||
|
|
||||||
# Apple Mac OSX
|
# Apple Mac OSX
|
||||||
UNAME_S := $(shell uname -s)
|
UNAME_S := $(shell uname -s)
|
||||||
|
@ -21,7 +21,8 @@ namespace ntcp
|
|||||||
{
|
{
|
||||||
NTCPSession::NTCPSession (boost::asio::io_service& service, i2p::data::RouterInfo& in_RemoteRouterInfo):
|
NTCPSession::NTCPSession (boost::asio::io_service& service, i2p::data::RouterInfo& in_RemoteRouterInfo):
|
||||||
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_NumSentBytes (0), m_NumReceivedBytes (0)
|
||||||
{
|
{
|
||||||
m_DHKeysPair = i2p::transports.GetNextDHKeysPair ();
|
m_DHKeysPair = i2p::transports.GetNextDHKeysPair ();
|
||||||
}
|
}
|
||||||
@ -402,7 +403,7 @@ namespace ntcp
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LogPrint ("Received: ", bytes_transferred);
|
m_NumReceivedBytes += bytes_transferred;
|
||||||
m_ReceiveBufferOffset += bytes_transferred;
|
m_ReceiveBufferOffset += bytes_transferred;
|
||||||
|
|
||||||
if (m_ReceiveBufferOffset >= 16)
|
if (m_ReceiveBufferOffset >= 16)
|
||||||
@ -513,7 +514,7 @@ namespace ntcp
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LogPrint ("Msg sent: ", bytes_transferred);
|
m_NumSentBytes += bytes_transferred;
|
||||||
ScheduleTermination (); // reset termination timer
|
ScheduleTermination (); // reset termination timer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -62,6 +62,7 @@ namespace ntcp
|
|||||||
|
|
||||||
#pragma pack()
|
#pragma pack()
|
||||||
|
|
||||||
|
const size_t NTCP_MAX_MESSAGE_SIZE = 16384;
|
||||||
const int NTCP_TERMINATION_TIMEOUT = 120; // 2 minutes
|
const int NTCP_TERMINATION_TIMEOUT = 120; // 2 minutes
|
||||||
class NTCPSession
|
class NTCPSession
|
||||||
{
|
{
|
||||||
@ -77,6 +78,9 @@ namespace ntcp
|
|||||||
void ClientLogin ();
|
void ClientLogin ();
|
||||||
void ServerLogin ();
|
void ServerLogin ();
|
||||||
void SendI2NPMessage (I2NPMessage * msg);
|
void SendI2NPMessage (I2NPMessage * msg);
|
||||||
|
|
||||||
|
size_t GetNumSentBytes () const { return m_NumSentBytes; };
|
||||||
|
size_t GetNumReceivedBytes () const { return m_NumReceivedBytes; };
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
@ -135,12 +139,14 @@ namespace ntcp
|
|||||||
NTCPPhase3 m_Phase3;
|
NTCPPhase3 m_Phase3;
|
||||||
NTCPPhase4 m_Phase4;
|
NTCPPhase4 m_Phase4;
|
||||||
|
|
||||||
uint8_t m_ReceiveBuffer[i2p::NTCP_MAX_MESSAGE_SIZE*2], m_TimeSyncBuffer[16];
|
uint8_t m_ReceiveBuffer[NTCP_MAX_MESSAGE_SIZE*2], m_TimeSyncBuffer[16];
|
||||||
int m_ReceiveBufferOffset;
|
int m_ReceiveBufferOffset;
|
||||||
|
|
||||||
i2p::I2NPMessage * m_NextMessage;
|
i2p::I2NPMessage * m_NextMessage;
|
||||||
std::list<i2p::I2NPMessage *> m_DelayedMessages;
|
std::list<i2p::I2NPMessage *> m_DelayedMessages;
|
||||||
size_t m_NextMessageOffset;
|
size_t m_NextMessageOffset;
|
||||||
|
|
||||||
|
size_t m_NumSentBytes, m_NumReceivedBytes;
|
||||||
};
|
};
|
||||||
|
|
||||||
class NTCPClient: public NTCPSession
|
class NTCPClient: public NTCPSession
|
||||||
|
268
NetDb.cpp
268
NetDb.cpp
@ -23,12 +23,12 @@ namespace data
|
|||||||
const i2p::tunnel::InboundTunnel * replyTunnel)
|
const i2p::tunnel::InboundTunnel * replyTunnel)
|
||||||
{
|
{
|
||||||
I2NPMessage * msg = i2p::CreateDatabaseLookupMsg (m_Destination,
|
I2NPMessage * msg = i2p::CreateDatabaseLookupMsg (m_Destination,
|
||||||
replyTunnel->GetNextIdentHash (), replyTunnel->GetNextTunnelID (), m_IsExploratory, &m_ExcludedPeers);
|
replyTunnel->GetNextIdentHash (), replyTunnel->GetNextTunnelID (), m_IsExploratory, &m_ExcludedPeers, m_IsLeaseSet);
|
||||||
if (m_IsLeaseSet) // wrap lookup message into garlic
|
if (m_IsLeaseSet) // wrap lookup message into garlic
|
||||||
msg = i2p::garlic::routing.WrapSingleMessage (*router, msg);
|
msg = i2p::garlic::routing.WrapSingleMessage (*router, msg);
|
||||||
m_ExcludedPeers.insert (router->GetIdentHash ());
|
m_ExcludedPeers.insert (router->GetIdentHash ());
|
||||||
m_LastRouter = router;
|
m_LastRouter = router;
|
||||||
m_LastReplyTunnel = replyTunnel;
|
m_CreationTime = i2p::util::GetSecondsSinceEpoch ();
|
||||||
return msg;
|
return msg;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -38,7 +38,7 @@ namespace data
|
|||||||
i2p::context.GetRouterInfo ().GetIdentHash () , 0, false, &m_ExcludedPeers);
|
i2p::context.GetRouterInfo ().GetIdentHash () , 0, false, &m_ExcludedPeers);
|
||||||
m_ExcludedPeers.insert (floodfill);
|
m_ExcludedPeers.insert (floodfill);
|
||||||
m_LastRouter = nullptr;
|
m_LastRouter = nullptr;
|
||||||
m_LastReplyTunnel = nullptr;
|
m_CreationTime = i2p::util::GetSecondsSinceEpoch ();
|
||||||
return msg;
|
return msg;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -95,7 +95,7 @@ namespace data
|
|||||||
|
|
||||||
void NetDb::Run ()
|
void NetDb::Run ()
|
||||||
{
|
{
|
||||||
uint32_t lastSave = 0, lastPublish = 0;
|
uint32_t lastSave = 0, lastPublish = 0, lastKeyspaceRotation = 0;
|
||||||
m_IsRunning = true;
|
m_IsRunning = true;
|
||||||
while (m_IsRunning)
|
while (m_IsRunning)
|
||||||
{
|
{
|
||||||
@ -106,17 +106,24 @@ namespace data
|
|||||||
{
|
{
|
||||||
while (msg)
|
while (msg)
|
||||||
{
|
{
|
||||||
if (msg->GetHeader ()->typeID == eI2NPDatabaseStore)
|
switch (msg->GetHeader ()->typeID)
|
||||||
{
|
|
||||||
HandleDatabaseStoreMsg (msg->GetPayload (), msg->GetLength ()); // TODO
|
|
||||||
i2p::DeleteI2NPMessage (msg);
|
|
||||||
}
|
|
||||||
else if (msg->GetHeader ()->typeID == eI2NPDatabaseSearchReply)
|
|
||||||
HandleDatabaseSearchReplyMsg (msg);
|
|
||||||
else // WTF?
|
|
||||||
{
|
{
|
||||||
LogPrint ("NetDb: unexpected message type ", msg->GetHeader ()->typeID);
|
case eI2NPDatabaseStore:
|
||||||
i2p::HandleI2NPMessage (msg);
|
LogPrint ("DatabaseStore");
|
||||||
|
HandleDatabaseStoreMsg (msg->GetPayload (), msg->GetLength ()); // TODO
|
||||||
|
i2p::DeleteI2NPMessage (msg);
|
||||||
|
break;
|
||||||
|
case eI2NPDatabaseSearchReply:
|
||||||
|
LogPrint ("DatabaseSearchReply");
|
||||||
|
HandleDatabaseSearchReplyMsg (msg);
|
||||||
|
break;
|
||||||
|
case eI2NPDatabaseLookup:
|
||||||
|
LogPrint ("DatabaseLookup");
|
||||||
|
HandleDatabaseLookupMsg (msg);
|
||||||
|
break;
|
||||||
|
default: // WTF?
|
||||||
|
LogPrint ("NetDb: unexpected message type ", msg->GetHeader ()->typeID);
|
||||||
|
i2p::HandleI2NPMessage (msg);
|
||||||
}
|
}
|
||||||
msg = m_Queue.Get ();
|
msg = m_Queue.Get ();
|
||||||
}
|
}
|
||||||
@ -128,11 +135,12 @@ namespace data
|
|||||||
}
|
}
|
||||||
|
|
||||||
uint64_t ts = i2p::util::GetSecondsSinceEpoch ();
|
uint64_t ts = i2p::util::GetSecondsSinceEpoch ();
|
||||||
if (ts - lastSave >= 60) // save routers and validate subscriptions every minute
|
if (ts - lastSave >= 60) // save routers, manage leasesets and validate subscriptions every minute
|
||||||
{
|
{
|
||||||
if (lastSave)
|
if (lastSave)
|
||||||
{
|
{
|
||||||
SaveUpdated (m_NetDbPath);
|
SaveUpdated (m_NetDbPath);
|
||||||
|
ManageLeaseSets ();
|
||||||
ValidateSubscriptions ();
|
ValidateSubscriptions ();
|
||||||
}
|
}
|
||||||
lastSave = ts;
|
lastSave = ts;
|
||||||
@ -142,6 +150,11 @@ namespace data
|
|||||||
Publish ();
|
Publish ();
|
||||||
lastPublish = ts;
|
lastPublish = ts;
|
||||||
}
|
}
|
||||||
|
if (ts % 86400 < 60 && ts - lastKeyspaceRotation >= 60) // wihhin 1 minutes since midnight (86400 = 24*3600)
|
||||||
|
{
|
||||||
|
KeyspaceRotation ();
|
||||||
|
lastKeyspaceRotation = ts;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (std::exception& ex)
|
catch (std::exception& ex)
|
||||||
{
|
{
|
||||||
@ -150,44 +163,40 @@ namespace data
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void NetDb::AddRouterInfo (uint8_t * buf, int len)
|
void NetDb::AddRouterInfo (const IdentHash& ident, uint8_t * buf, int len)
|
||||||
{
|
{
|
||||||
RouterInfo * r = new RouterInfo (buf, len);
|
DeleteRequestedDestination (ident);
|
||||||
DeleteRequestedDestination (r->GetIdentHash ());
|
auto it = m_RouterInfos.find(ident);
|
||||||
auto it = m_RouterInfos.find(r->GetIdentHash ());
|
|
||||||
if (it != m_RouterInfos.end ())
|
if (it != m_RouterInfos.end ())
|
||||||
{
|
{
|
||||||
if (r->GetTimestamp () > it->second->GetTimestamp ())
|
auto ts = it->second->GetTimestamp ();
|
||||||
{
|
it->second->Update (buf, len);
|
||||||
|
if (it->second->GetTimestamp () > ts)
|
||||||
LogPrint ("RouterInfo updated");
|
LogPrint ("RouterInfo updated");
|
||||||
*(it->second) = *r; // we can't replace pointer because it's used by tunnels
|
|
||||||
}
|
|
||||||
delete r;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LogPrint ("New RouterInfo added");
|
LogPrint ("New RouterInfo added");
|
||||||
|
RouterInfo * r = new RouterInfo (buf, len);
|
||||||
m_RouterInfos[r->GetIdentHash ()] = r;
|
m_RouterInfos[r->GetIdentHash ()] = r;
|
||||||
if (r->IsFloodfill ())
|
if (r->IsFloodfill ())
|
||||||
m_Floodfills.push_back (r);
|
m_Floodfills.push_back (r);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void NetDb::AddLeaseSet (uint8_t * buf, int len)
|
void NetDb::AddLeaseSet (const IdentHash& ident, uint8_t * buf, int len)
|
||||||
{
|
{
|
||||||
LeaseSet * l = new LeaseSet (buf, len);
|
bool unsolicited = !DeleteRequestedDestination (ident);
|
||||||
DeleteRequestedDestination (l->GetIdentHash ());
|
auto it = m_LeaseSets.find(ident);
|
||||||
auto it = m_LeaseSets.find(l->GetIdentHash ());
|
|
||||||
if (it != m_LeaseSets.end ())
|
if (it != m_LeaseSets.end ())
|
||||||
{
|
{
|
||||||
|
it->second->Update (buf, len);
|
||||||
LogPrint ("LeaseSet updated");
|
LogPrint ("LeaseSet updated");
|
||||||
*(it->second) = *l; // we can't replace pointer because it's used by streams
|
|
||||||
delete l;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LogPrint ("New LeaseSet added");
|
LogPrint ("New LeaseSet added");
|
||||||
m_LeaseSets[l->GetIdentHash ()] = l;
|
m_LeaseSets[ident] = new LeaseSet (buf, len, unsolicited);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -259,14 +268,25 @@ namespace data
|
|||||||
for (boost::filesystem::directory_iterator it1 (it->path ()); it1 != end; ++it1)
|
for (boost::filesystem::directory_iterator it1 (it->path ()); it1 != end; ++it1)
|
||||||
{
|
{
|
||||||
#if BOOST_VERSION > 10500
|
#if BOOST_VERSION > 10500
|
||||||
RouterInfo * r = new RouterInfo (it1->path().string().c_str ());
|
const std::string& fullPath = it1->path().string();
|
||||||
#else
|
#else
|
||||||
RouterInfo * r = new RouterInfo(it1->path().c_str());
|
const std::string& fullPath = it1->path();
|
||||||
#endif
|
#endif
|
||||||
m_RouterInfos[r->GetIdentHash ()] = r;
|
RouterInfo * r = new RouterInfo(fullPath);
|
||||||
if (r->IsFloodfill ())
|
if (!r->IsUnreachable ())
|
||||||
m_Floodfills.push_back (r);
|
{
|
||||||
numRouters++;
|
r->DeleteBuffer ();
|
||||||
|
m_RouterInfos[r->GetIdentHash ()] = r;
|
||||||
|
if (r->IsFloodfill ())
|
||||||
|
m_Floodfills.push_back (r);
|
||||||
|
numRouters++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (boost::filesystem::exists (fullPath))
|
||||||
|
boost::filesystem::remove (fullPath);
|
||||||
|
delete r;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -302,9 +322,9 @@ namespace data
|
|||||||
{
|
{
|
||||||
if (it.second->IsUpdated ())
|
if (it.second->IsUpdated ())
|
||||||
{
|
{
|
||||||
std::ofstream r (GetFilePath(fullDirectory, it.second), std::ofstream::binary);
|
it.second->SaveToFile (GetFilePath(fullDirectory, it.second));
|
||||||
r.write ((char *)it.second->GetBuffer (), it.second->GetBufferLen ());
|
|
||||||
it.second->SetUpdated (false);
|
it.second->SetUpdated (false);
|
||||||
|
it.second->DeleteBuffer ();
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -362,7 +382,6 @@ namespace data
|
|||||||
if (msgs.size () > 0)
|
if (msgs.size () > 0)
|
||||||
{
|
{
|
||||||
dest->ClearExcludedPeers ();
|
dest->ClearExcludedPeers ();
|
||||||
dest->SetLastOutboundTunnel (outbound);
|
|
||||||
outbound->SendTunnelDataMsg (msgs);
|
outbound->SendTunnelDataMsg (msgs);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -379,10 +398,7 @@ namespace data
|
|||||||
RequestedDestination * dest = CreateRequestedDestination (destination, false);
|
RequestedDestination * dest = CreateRequestedDestination (destination, false);
|
||||||
auto floodfill = GetClosestFloodfill (destination, dest->GetExcludedPeers ());
|
auto floodfill = GetClosestFloodfill (destination, dest->GetExcludedPeers ());
|
||||||
if (floodfill)
|
if (floodfill)
|
||||||
{
|
|
||||||
dest->SetLastOutboundTunnel (nullptr);
|
|
||||||
i2p::transports.SendMessage (floodfill->GetIdentHash (), dest->CreateRequestMessage (floodfill->GetIdentHash ()));
|
i2p::transports.SendMessage (floodfill->GetIdentHash (), dest->CreateRequestMessage (floodfill->GetIdentHash ()));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -395,7 +411,7 @@ namespace data
|
|||||||
if (msg->type)
|
if (msg->type)
|
||||||
{
|
{
|
||||||
LogPrint ("LeaseSet");
|
LogPrint ("LeaseSet");
|
||||||
AddLeaseSet (buf + offset, len - offset);
|
AddLeaseSet (msg->key, buf + offset, len - offset);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -413,7 +429,7 @@ namespace data
|
|||||||
uint8_t uncompressed[2048];
|
uint8_t uncompressed[2048];
|
||||||
size_t uncomressedSize = decompressor.MaxRetrievable ();
|
size_t uncomressedSize = decompressor.MaxRetrievable ();
|
||||||
decompressor.Get (uncompressed, uncomressedSize);
|
decompressor.Get (uncompressed, uncomressedSize);
|
||||||
AddRouterInfo (uncompressed, uncomressedSize);
|
AddRouterInfo (msg->key, uncompressed, uncomressedSize);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -429,10 +445,12 @@ namespace data
|
|||||||
if (it != m_RequestedDestinations.end ())
|
if (it != m_RequestedDestinations.end ())
|
||||||
{
|
{
|
||||||
RequestedDestination * dest = it->second;
|
RequestedDestination * dest = it->second;
|
||||||
|
bool deleteDest = true;
|
||||||
if (num > 0)
|
if (num > 0)
|
||||||
{
|
{
|
||||||
i2p::tunnel::OutboundTunnel * outbound = dest->GetLastOutboundTunnel ();
|
auto exploratoryPool = i2p::tunnel::tunnels.GetExploratoryPool ();
|
||||||
const i2p::tunnel::InboundTunnel * inbound = dest->GetLastReplyTunnel ();
|
auto outbound = exploratoryPool ? exploratoryPool->GetNextOutboundTunnel () : nullptr;
|
||||||
|
auto inbound = exploratoryPool ? exploratoryPool->GetNextInboundTunnel () : nullptr;
|
||||||
std::vector<i2p::tunnel::TunnelMessageBlock> msgs;
|
std::vector<i2p::tunnel::TunnelMessageBlock> msgs;
|
||||||
|
|
||||||
for (int i = 0; i < num; i++)
|
for (int i = 0; i < num; i++)
|
||||||
@ -450,11 +468,10 @@ namespace data
|
|||||||
{
|
{
|
||||||
// router with ident not found or too old (1 hour)
|
// router with ident not found or too old (1 hour)
|
||||||
LogPrint ("Found new/outdated router. Requesting RouterInfo ...");
|
LogPrint ("Found new/outdated router. Requesting RouterInfo ...");
|
||||||
if (outbound && inbound)
|
if (outbound && inbound && dest->GetLastRouter ())
|
||||||
{
|
{
|
||||||
RequestedDestination * d1 = CreateRequestedDestination (router, false, false);
|
RequestedDestination * d1 = CreateRequestedDestination (router, false, false);
|
||||||
d1->SetLastOutboundTunnel (outbound);
|
auto msg = d1->CreateRequestMessage (dest->GetLastRouter (), inbound);
|
||||||
auto msg = d1->CreateRequestMessage (dest->GetLastRouter (), dest->GetLastReplyTunnel ());
|
|
||||||
msgs.push_back (i2p::tunnel::TunnelMessageBlock
|
msgs.push_back (i2p::tunnel::TunnelMessageBlock
|
||||||
{
|
{
|
||||||
i2p::tunnel::eDeliveryTypeRouter,
|
i2p::tunnel::eDeliveryTypeRouter,
|
||||||
@ -468,7 +485,7 @@ namespace data
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// reply to our destination. Try other floodfills
|
// reply to our destination. Try other floodfills
|
||||||
if (outbound && inbound)
|
if (outbound && inbound && dest->GetLastRouter ())
|
||||||
{
|
{
|
||||||
auto r = FindRouter (router);
|
auto r = FindRouter (router);
|
||||||
// do we have that floodfill router in our database?
|
// do we have that floodfill router in our database?
|
||||||
@ -477,6 +494,7 @@ namespace data
|
|||||||
// we do
|
// we do
|
||||||
if (!dest->IsExcluded (r->GetIdentHash ()) && dest->GetNumExcludedPeers () < 30) // TODO: fix TunnelGateway first
|
if (!dest->IsExcluded (r->GetIdentHash ()) && dest->GetNumExcludedPeers () < 30) // TODO: fix TunnelGateway first
|
||||||
{
|
{
|
||||||
|
LogPrint ("Try ", key, " at floodfill ", peerHash);
|
||||||
// tell floodfill about us
|
// tell floodfill about us
|
||||||
msgs.push_back (i2p::tunnel::TunnelMessageBlock
|
msgs.push_back (i2p::tunnel::TunnelMessageBlock
|
||||||
{
|
{
|
||||||
@ -485,12 +503,13 @@ namespace data
|
|||||||
CreateDatabaseStoreMsg ()
|
CreateDatabaseStoreMsg ()
|
||||||
});
|
});
|
||||||
// request destination
|
// request destination
|
||||||
auto msg = dest->CreateRequestMessage (r, dest->GetLastReplyTunnel ());
|
auto msg = dest->CreateRequestMessage (r, inbound);
|
||||||
msgs.push_back (i2p::tunnel::TunnelMessageBlock
|
msgs.push_back (i2p::tunnel::TunnelMessageBlock
|
||||||
{
|
{
|
||||||
i2p::tunnel::eDeliveryTypeRouter,
|
i2p::tunnel::eDeliveryTypeRouter,
|
||||||
r->GetIdentHash (), 0, msg
|
r->GetIdentHash (), 0, msg
|
||||||
});
|
});
|
||||||
|
deleteDest = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -498,7 +517,6 @@ namespace data
|
|||||||
// request router
|
// request router
|
||||||
LogPrint ("Found new floodfill. Request it");
|
LogPrint ("Found new floodfill. Request it");
|
||||||
RequestedDestination * d2 = CreateRequestedDestination (router, false, false);
|
RequestedDestination * d2 = CreateRequestedDestination (router, false, false);
|
||||||
d2->SetLastOutboundTunnel (outbound);
|
|
||||||
I2NPMessage * msg = d2->CreateRequestMessage (dest->GetLastRouter (), inbound);
|
I2NPMessage * msg = d2->CreateRequestMessage (dest->GetLastRouter (), inbound);
|
||||||
msgs.push_back (i2p::tunnel::TunnelMessageBlock
|
msgs.push_back (i2p::tunnel::TunnelMessageBlock
|
||||||
{
|
{
|
||||||
@ -512,16 +530,26 @@ namespace data
|
|||||||
if (!dest->IsLeaseSet ()) // if not LeaseSet
|
if (!dest->IsLeaseSet ()) // if not LeaseSet
|
||||||
{
|
{
|
||||||
if (!dest->IsExcluded (router) && dest->GetNumExcludedPeers () < 30)
|
if (!dest->IsExcluded (router) && dest->GetNumExcludedPeers () < 30)
|
||||||
|
{
|
||||||
|
LogPrint ("Try ", key, " at floodfill ", peerHash, " directly");
|
||||||
i2p::transports.SendMessage (router, dest->CreateRequestMessage (router));
|
i2p::transports.SendMessage (router, dest->CreateRequestMessage (router));
|
||||||
|
deleteDest = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
LogPrint ("Can't request LeaseSet");
|
LogPrint ("Can't request LeaseSet");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (outbound && msgs.size () > 0)
|
if (outbound && msgs.size () > 0)
|
||||||
outbound->SendTunnelDataMsg (msgs);
|
outbound->SendTunnelDataMsg (msgs);
|
||||||
|
if (deleteDest)
|
||||||
|
{
|
||||||
|
// no more requests for tha destinationation. delete it
|
||||||
|
delete it->second;
|
||||||
|
m_RequestedDestinations.erase (it);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -535,8 +563,104 @@ namespace data
|
|||||||
i2p::DeleteI2NPMessage (msg);
|
i2p::DeleteI2NPMessage (msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NetDb::HandleDatabaseLookupMsg (I2NPMessage * msg)
|
||||||
|
{
|
||||||
|
uint8_t * buf = msg->GetPayload ();
|
||||||
|
char key[48];
|
||||||
|
int l = i2p::data::ByteStreamToBase64 (buf, 32, key, 48);
|
||||||
|
key[l] = 0;
|
||||||
|
LogPrint ("DatabaseLookup for ", key, " recieved");
|
||||||
|
uint8_t flag = buf[64];
|
||||||
|
uint8_t * excluded = buf + 65;
|
||||||
|
uint32_t replyTunnelID = 0;
|
||||||
|
if (flag & 0x01) //reply to tunnel
|
||||||
|
{
|
||||||
|
replyTunnelID = be32toh (*(uint32_t *)(buf + 64));
|
||||||
|
excluded += 4;
|
||||||
|
}
|
||||||
|
uint16_t numExcluded = be16toh (*(uint16_t *)excluded);
|
||||||
|
excluded += 2;
|
||||||
|
if (numExcluded > 512)
|
||||||
|
{
|
||||||
|
LogPrint ("Number of excluded peers", numExcluded, " exceeds 512");
|
||||||
|
numExcluded = 0; // TODO:
|
||||||
|
}
|
||||||
|
|
||||||
|
I2NPMessage * replyMsg = nullptr;
|
||||||
|
|
||||||
|
{
|
||||||
|
auto router = FindRouter (buf);
|
||||||
|
if (router)
|
||||||
|
{
|
||||||
|
LogPrint ("Requested RouterInfo ", key, " found");
|
||||||
|
router->LoadBuffer ();
|
||||||
|
if (router->GetBuffer ())
|
||||||
|
replyMsg = CreateDatabaseStoreMsg (router);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!replyMsg)
|
||||||
|
{
|
||||||
|
auto leaseSet = FindLeaseSet (buf);
|
||||||
|
if (leaseSet && leaseSet->IsUnsolicited ()) // we don't send back our LeaseSets
|
||||||
|
{
|
||||||
|
LogPrint ("Requested LeaseSet ", key, " found");
|
||||||
|
replyMsg = CreateDatabaseStoreMsg (leaseSet);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!replyMsg)
|
||||||
|
{
|
||||||
|
LogPrint ("Requested ", key, " not found. ", numExcluded, " excluded");
|
||||||
|
std::set<IdentHash> excludedRouters;
|
||||||
|
for (int i = 0; i < numExcluded; i++)
|
||||||
|
{
|
||||||
|
// TODO: check for all zeroes (exploratory)
|
||||||
|
excludedRouters.insert (excluded);
|
||||||
|
excluded += 32;
|
||||||
|
}
|
||||||
|
replyMsg = CreateDatabaseSearchReply (buf, GetClosestFloodfill (buf, excludedRouters));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
excluded += numExcluded*32; // we don't care about exluded
|
||||||
|
|
||||||
|
if (replyMsg)
|
||||||
|
{
|
||||||
|
if (replyTunnelID)
|
||||||
|
{
|
||||||
|
// encryption might be used though tunnel only
|
||||||
|
if (flag & 0x02) // encrypted reply requested
|
||||||
|
{
|
||||||
|
uint8_t * sessionKey = excluded;
|
||||||
|
uint8_t numTags = sessionKey[32];
|
||||||
|
if (numTags > 0)
|
||||||
|
{
|
||||||
|
uint8_t * sessionTag = sessionKey + 33; // take first tag
|
||||||
|
i2p::garlic::GarlicRoutingSession garlic (sessionKey, sessionTag);
|
||||||
|
replyMsg = garlic.WrapSingleMessage (replyMsg, nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
i2p::tunnel::tunnels.GetNextOutboundTunnel ()->SendTunnelDataMsg (buf+32, replyTunnelID, replyMsg);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
i2p::transports.SendMessage (buf, replyMsg);
|
||||||
|
}
|
||||||
|
i2p::DeleteI2NPMessage (msg);
|
||||||
|
}
|
||||||
|
|
||||||
void NetDb::Explore (int numDestinations)
|
void NetDb::Explore (int numDestinations)
|
||||||
{
|
{
|
||||||
|
// clean up previous exploratories
|
||||||
|
uint64_t ts = i2p::util::GetSecondsSinceEpoch ();
|
||||||
|
for (auto it = m_RequestedDestinations.begin (); it != m_RequestedDestinations.end ();)
|
||||||
|
{
|
||||||
|
if (it->second->IsExploratory () || ts > it->second->GetCreationTime () + 60) // no response for 1 minute
|
||||||
|
{
|
||||||
|
delete it->second;
|
||||||
|
it = m_RequestedDestinations.erase (it);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
it++;
|
||||||
|
}
|
||||||
|
// new requests
|
||||||
auto exploratoryPool = i2p::tunnel::tunnels.GetExploratoryPool ();
|
auto exploratoryPool = i2p::tunnel::tunnels.GetExploratoryPool ();
|
||||||
auto outbound = exploratoryPool ? exploratoryPool->GetNextOutboundTunnel () : nullptr;
|
auto outbound = exploratoryPool ? exploratoryPool->GetNextOutboundTunnel () : nullptr;
|
||||||
auto inbound = exploratoryPool ? exploratoryPool->GetNextInboundTunnel () : nullptr;
|
auto inbound = exploratoryPool ? exploratoryPool->GetNextInboundTunnel () : nullptr;
|
||||||
@ -557,7 +681,6 @@ namespace data
|
|||||||
floodfills.insert (floodfill);
|
floodfills.insert (floodfill);
|
||||||
if (throughTunnels)
|
if (throughTunnels)
|
||||||
{
|
{
|
||||||
dest->SetLastOutboundTunnel (outbound);
|
|
||||||
msgs.push_back (i2p::tunnel::TunnelMessageBlock
|
msgs.push_back (i2p::tunnel::TunnelMessageBlock
|
||||||
{
|
{
|
||||||
i2p::tunnel::eDeliveryTypeRouter,
|
i2p::tunnel::eDeliveryTypeRouter,
|
||||||
@ -572,11 +695,7 @@ namespace data
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
|
||||||
dest->SetLastOutboundTunnel (nullptr);
|
|
||||||
dest->SetLastReplyTunnel (nullptr);
|
|
||||||
i2p::transports.SendMessage (floodfill->GetIdentHash (), dest->CreateRequestMessage (floodfill->GetIdentHash ()));
|
i2p::transports.SendMessage (floodfill->GetIdentHash (), dest->CreateRequestMessage (floodfill->GetIdentHash ()));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
DeleteRequestedDestination (dest);
|
DeleteRequestedDestination (dest);
|
||||||
@ -614,14 +733,16 @@ namespace data
|
|||||||
return it->second;
|
return it->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
void NetDb::DeleteRequestedDestination (const IdentHash& dest)
|
bool NetDb::DeleteRequestedDestination (const IdentHash& dest)
|
||||||
{
|
{
|
||||||
auto it = m_RequestedDestinations.find (dest);
|
auto it = m_RequestedDestinations.find (dest);
|
||||||
if (it != m_RequestedDestinations.end ())
|
if (it != m_RequestedDestinations.end ())
|
||||||
{
|
{
|
||||||
delete it->second;
|
delete it->second;
|
||||||
m_RequestedDestinations.erase (it);
|
m_RequestedDestinations.erase (it);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void NetDb::DeleteRequestedDestination (RequestedDestination * dest)
|
void NetDb::DeleteRequestedDestination (RequestedDestination * dest)
|
||||||
@ -692,6 +813,8 @@ namespace data
|
|||||||
LogPrint ("LeaseSet requested");
|
LogPrint ("LeaseSet requested");
|
||||||
RequestDestination (ident, true);
|
RequestDestination (ident, true);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
leaseSet->SetUnsolicited (false);
|
||||||
m_Subscriptions.insert (ident);
|
m_Subscriptions.insert (ident);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -712,5 +835,28 @@ namespace data
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NetDb::KeyspaceRotation ()
|
||||||
|
{
|
||||||
|
for (auto it: m_RouterInfos)
|
||||||
|
it.second->UpdateRoutingKey ();
|
||||||
|
LogPrint ("Keyspace rotation complete");
|
||||||
|
Publish ();
|
||||||
|
}
|
||||||
|
|
||||||
|
void NetDb::ManageLeaseSets ()
|
||||||
|
{
|
||||||
|
for (auto it = m_LeaseSets.begin (); it != m_LeaseSets.end ();)
|
||||||
|
{
|
||||||
|
if (it->second->IsUnsolicited () && !it->second->HasNonExpiredLeases ()) // all leases expired
|
||||||
|
{
|
||||||
|
LogPrint ("LeaseSet ", it->second->GetIdentHash ().ToBase64 (), " expired");
|
||||||
|
delete it->second;
|
||||||
|
it = m_LeaseSets.erase (it);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
it++;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
26
NetDb.h
26
NetDb.h
@ -25,32 +25,27 @@ namespace data
|
|||||||
|
|
||||||
RequestedDestination (const IdentHash& destination, bool isLeaseSet, bool isExploratory = false):
|
RequestedDestination (const IdentHash& destination, bool isLeaseSet, bool isExploratory = false):
|
||||||
m_Destination (destination), m_IsLeaseSet (isLeaseSet), m_IsExploratory (isExploratory),
|
m_Destination (destination), m_IsLeaseSet (isLeaseSet), m_IsExploratory (isExploratory),
|
||||||
m_LastRouter (nullptr), m_LastReplyTunnel (nullptr), m_LastOutboundTunnel (nullptr) {};
|
m_LastRouter (nullptr), m_CreationTime (0) {};
|
||||||
|
|
||||||
const IdentHash& GetDestination () const { return m_Destination; };
|
const IdentHash& GetDestination () const { return m_Destination; };
|
||||||
int GetNumExcludedPeers () const { return m_ExcludedPeers.size (); };
|
int GetNumExcludedPeers () const { return m_ExcludedPeers.size (); };
|
||||||
const std::set<IdentHash>& GetExcludedPeers () { return m_ExcludedPeers; };
|
const std::set<IdentHash>& GetExcludedPeers () { return m_ExcludedPeers; };
|
||||||
void ClearExcludedPeers ();
|
void ClearExcludedPeers ();
|
||||||
const RouterInfo * GetLastRouter () const { return m_LastRouter; };
|
const RouterInfo * GetLastRouter () const { return m_LastRouter; };
|
||||||
const i2p::tunnel::InboundTunnel * GetLastReplyTunnel () const { return m_LastReplyTunnel; };
|
|
||||||
void SetLastReplyTunnel (i2p::tunnel::InboundTunnel * tunnel) { m_LastReplyTunnel = tunnel; };
|
|
||||||
bool IsExploratory () const { return m_IsExploratory; };
|
bool IsExploratory () const { return m_IsExploratory; };
|
||||||
bool IsLeaseSet () const { return m_IsLeaseSet; };
|
bool IsLeaseSet () const { return m_IsLeaseSet; };
|
||||||
bool IsExcluded (const IdentHash& ident) const { return m_ExcludedPeers.count (ident); };
|
bool IsExcluded (const IdentHash& ident) const { return m_ExcludedPeers.count (ident); };
|
||||||
|
uint64_t GetCreationTime () const { return m_CreationTime; };
|
||||||
I2NPMessage * CreateRequestMessage (const RouterInfo * router, const i2p::tunnel::InboundTunnel * replyTunnel);
|
I2NPMessage * CreateRequestMessage (const RouterInfo * router, const i2p::tunnel::InboundTunnel * replyTunnel);
|
||||||
I2NPMessage * CreateRequestMessage (const IdentHash& floodfill);
|
I2NPMessage * CreateRequestMessage (const IdentHash& floodfill);
|
||||||
|
|
||||||
i2p::tunnel::OutboundTunnel * GetLastOutboundTunnel () const { return m_LastOutboundTunnel; };
|
|
||||||
void SetLastOutboundTunnel (i2p::tunnel::OutboundTunnel * tunnel) { m_LastOutboundTunnel = tunnel; };
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
IdentHash m_Destination;
|
IdentHash m_Destination;
|
||||||
bool m_IsLeaseSet, m_IsExploratory;
|
bool m_IsLeaseSet, m_IsExploratory;
|
||||||
std::set<IdentHash> m_ExcludedPeers;
|
std::set<IdentHash> m_ExcludedPeers;
|
||||||
const RouterInfo * m_LastRouter;
|
const RouterInfo * m_LastRouter;
|
||||||
const i2p::tunnel::InboundTunnel * m_LastReplyTunnel;
|
uint64_t m_CreationTime;
|
||||||
i2p::tunnel::OutboundTunnel * m_LastOutboundTunnel;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class NetDb
|
class NetDb
|
||||||
@ -63,8 +58,8 @@ namespace data
|
|||||||
void Start ();
|
void Start ();
|
||||||
void Stop ();
|
void Stop ();
|
||||||
|
|
||||||
void AddRouterInfo (uint8_t * buf, int len);
|
void AddRouterInfo (const IdentHash& ident, uint8_t * buf, int len);
|
||||||
void AddLeaseSet (uint8_t * buf, int len);
|
void AddLeaseSet (const IdentHash& ident, uint8_t * buf, int len);
|
||||||
RouterInfo * FindRouter (const IdentHash& ident) const;
|
RouterInfo * FindRouter (const IdentHash& ident) const;
|
||||||
LeaseSet * FindLeaseSet (const IdentHash& destination) const;
|
LeaseSet * FindLeaseSet (const IdentHash& destination) const;
|
||||||
const IdentHash * FindAddress (const std::string& address) { return m_AddressBook.FindAddress (address); }; // TODO: move AddressBook away from NetDb
|
const IdentHash * FindAddress (const std::string& address) { return m_AddressBook.FindAddress (address); }; // TODO: move AddressBook away from NetDb
|
||||||
@ -75,7 +70,8 @@ namespace data
|
|||||||
|
|
||||||
void HandleDatabaseStoreMsg (uint8_t * buf, size_t len);
|
void HandleDatabaseStoreMsg (uint8_t * buf, size_t len);
|
||||||
void HandleDatabaseSearchReplyMsg (I2NPMessage * msg);
|
void HandleDatabaseSearchReplyMsg (I2NPMessage * msg);
|
||||||
|
void HandleDatabaseLookupMsg (I2NPMessage * msg);
|
||||||
|
|
||||||
const RouterInfo * GetRandomRouter (const RouterInfo * compatibleWith = nullptr) const;
|
const RouterInfo * GetRandomRouter (const RouterInfo * compatibleWith = nullptr) const;
|
||||||
|
|
||||||
void PostI2NPMsg (I2NPMessage * msg);
|
void PostI2NPMsg (I2NPMessage * msg);
|
||||||
@ -95,12 +91,14 @@ namespace data
|
|||||||
void Publish ();
|
void Publish ();
|
||||||
void ValidateSubscriptions ();
|
void ValidateSubscriptions ();
|
||||||
const RouterInfo * GetClosestFloodfill (const IdentHash& destination, const std::set<IdentHash>& excluded) const;
|
const RouterInfo * GetClosestFloodfill (const IdentHash& destination, const std::set<IdentHash>& excluded) const;
|
||||||
|
void KeyspaceRotation ();
|
||||||
|
void ManageLeaseSets ();
|
||||||
|
|
||||||
RequestedDestination * CreateRequestedDestination (const IdentHash& dest,
|
RequestedDestination * CreateRequestedDestination (const IdentHash& dest,
|
||||||
bool isLeaseSet, bool isExploratory = false);
|
bool isLeaseSet, bool isExploratory = false);
|
||||||
void DeleteRequestedDestination (const IdentHash& dest);
|
bool DeleteRequestedDestination (const IdentHash& dest); // returns true if found
|
||||||
void DeleteRequestedDestination (RequestedDestination * dest);
|
void DeleteRequestedDestination (RequestedDestination * dest);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
std::map<IdentHash, LeaseSet *> m_LeaseSets;
|
std::map<IdentHash, LeaseSet *> m_LeaseSets;
|
||||||
|
12
Queue.h
12
Queue.h
@ -65,7 +65,7 @@ namespace util
|
|||||||
return m_Queue.empty ();
|
return m_Queue.empty ();
|
||||||
}
|
}
|
||||||
|
|
||||||
void WakeUp () { m_NonEmpty.notify_one (); };
|
void WakeUp () { m_NonEmpty.notify_all (); };
|
||||||
|
|
||||||
Element * Get ()
|
Element * Get ()
|
||||||
{
|
{
|
||||||
@ -108,11 +108,15 @@ namespace util
|
|||||||
typedef std::function<void()> OnEmpty;
|
typedef std::function<void()> OnEmpty;
|
||||||
|
|
||||||
MsgQueue (): m_IsRunning (true), m_Thread (std::bind (&MsgQueue<Msg>::Run, this)) {};
|
MsgQueue (): m_IsRunning (true), m_Thread (std::bind (&MsgQueue<Msg>::Run, this)) {};
|
||||||
|
~MsgQueue () { Stop (); };
|
||||||
void Stop()
|
void Stop()
|
||||||
{
|
{
|
||||||
m_IsRunning = false;
|
if (m_IsRunning)
|
||||||
Queue<Msg>::WakeUp ();
|
{
|
||||||
m_Thread.join();
|
m_IsRunning = false;
|
||||||
|
Queue<Msg>::WakeUp ();
|
||||||
|
m_Thread.join();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetOnEmpty (OnEmpty const & e) { m_OnEmpty = e; };
|
void SetOnEmpty (OnEmpty const & e) { m_OnEmpty = e; };
|
||||||
|
@ -9,7 +9,13 @@ 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)
|
Build Statuses
|
||||||
|
---------------
|
||||||
|
|
||||||
|
- Linux x64 - [![Build Status](https://jenkins.nordcloud.no/buildStatus/icon?job=i2pd-linux)](https://jenkins.nordcloud.no/job/i2pd-linux/)
|
||||||
|
- Linux ARM - Too be added
|
||||||
|
- Mac OS X - Too be added
|
||||||
|
- Microsoft VC13 - Too be added
|
||||||
|
|
||||||
|
|
||||||
Testing
|
Testing
|
||||||
|
29
Reseed.cpp
29
Reseed.cpp
@ -19,11 +19,25 @@ namespace data
|
|||||||
"http://cowpuncher.drollette.com/netdb/",
|
"http://cowpuncher.drollette.com/netdb/",
|
||||||
"http://i2p.mooo.com/netDb/",
|
"http://i2p.mooo.com/netDb/",
|
||||||
"http://reseed.info/",
|
"http://reseed.info/",
|
||||||
"http://reseed.pkol.de/",
|
|
||||||
"http://uk.reseed.i2p2.no/",
|
"http://uk.reseed.i2p2.no/",
|
||||||
|
"http://us.reseed.i2p2.no/",
|
||||||
|
"http://jp.reseed.i2p2.no/",
|
||||||
"http://i2p-netdb.innovatio.no/",
|
"http://i2p-netdb.innovatio.no/",
|
||||||
"http://ieb9oopo.mooo.com"
|
"http://ieb9oopo.mooo.com"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//TODO: Remember to add custom port support. Not all serves on 443
|
||||||
|
static std::vector<std::string> httpsReseedHostList = {
|
||||||
|
"https://193.150.121.66/netDb/",
|
||||||
|
"https://netdb.i2p2.no/",
|
||||||
|
"https://reseed.i2p-projekt.de/",
|
||||||
|
"https://cowpuncher.drollette.com/netdb/",
|
||||||
|
"https://i2p.mooo.com/netDb/",
|
||||||
|
"https://reseed.info/",
|
||||||
|
"https://i2p-netdb.innovatio.no/",
|
||||||
|
"https://ieb9oopo.mooo.com/",
|
||||||
|
"https://ssl.webpack.de/ivae2he9.sg4.e-plaza.de/" // Only HTTPS and SU3 (v2) support
|
||||||
|
};
|
||||||
|
|
||||||
//TODO: Implement v2 reseeding. Lightweight zip library is needed.
|
//TODO: Implement v2 reseeding. Lightweight zip library is needed.
|
||||||
//TODO: Implement SU3, utils.
|
//TODO: Implement SU3, utils.
|
||||||
@ -39,6 +53,15 @@ namespace data
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
// Seems like the best place to try to intercept with SSL
|
||||||
|
/*ssl_server = true;
|
||||||
|
try {
|
||||||
|
// SSL
|
||||||
|
}
|
||||||
|
catch (std::exception& e)
|
||||||
|
{
|
||||||
|
LogPrint("Exception in SSL: ", e.what());
|
||||||
|
}*/
|
||||||
std::string reseedHost = httpReseedHostList[(rand() % httpReseedHostList.size())];
|
std::string reseedHost = httpReseedHostList[(rand() % httpReseedHostList.size())];
|
||||||
LogPrint("Reseeding from ", reseedHost);
|
LogPrint("Reseeding from ", reseedHost);
|
||||||
std::string content = i2p::util::http::httpRequest(reseedHost);
|
std::string content = i2p::util::http::httpRequest(reseedHost);
|
||||||
@ -56,7 +79,7 @@ namespace data
|
|||||||
std::string routerInfo;
|
std::string routerInfo;
|
||||||
std::string tmpUrl;
|
std::string tmpUrl;
|
||||||
std::string filename;
|
std::string filename;
|
||||||
std::string ignoreFileSuffix = ".zip";
|
std::string ignoreFileSuffix = ".su3";
|
||||||
boost::filesystem::path root = i2p::util::filesystem::GetDataDir();
|
boost::filesystem::path root = i2p::util::filesystem::GetDataDir();
|
||||||
while (i != j)
|
while (i != j)
|
||||||
{
|
{
|
||||||
|
@ -34,13 +34,13 @@ namespace i2p
|
|||||||
routerInfo.AddSSUAddress ("127.0.0.1", 17007, routerInfo.GetIdentHash ());
|
routerInfo.AddSSUAddress ("127.0.0.1", 17007, routerInfo.GetIdentHash ());
|
||||||
routerInfo.AddNTCPAddress ("127.0.0.1", 17007); // TODO:
|
routerInfo.AddNTCPAddress ("127.0.0.1", 17007); // TODO:
|
||||||
routerInfo.SetProperty ("caps", "LR");
|
routerInfo.SetProperty ("caps", "LR");
|
||||||
routerInfo.SetProperty ("coreVersion", "0.9.8.1");
|
routerInfo.SetProperty ("coreVersion", "0.9.11");
|
||||||
routerInfo.SetProperty ("netId", "2");
|
routerInfo.SetProperty ("netId", "2");
|
||||||
routerInfo.SetProperty ("router.version", "0.9.8.1");
|
routerInfo.SetProperty ("router.version", "0.9.11");
|
||||||
routerInfo.SetProperty ("start_uptime", "90m");
|
routerInfo.SetProperty ("start_uptime", "90m");
|
||||||
routerInfo.CreateBuffer ();
|
routerInfo.CreateBuffer ();
|
||||||
|
|
||||||
m_RouterInfo = routerInfo;
|
m_RouterInfo.Update (routerInfo.GetBuffer (), routerInfo.GetBufferLen ());
|
||||||
}
|
}
|
||||||
|
|
||||||
void RouterContext::OverrideNTCPAddress (const char * host, int port)
|
void RouterContext::OverrideNTCPAddress (const char * host, int port)
|
||||||
@ -64,10 +64,10 @@ namespace i2p
|
|||||||
m_RouterInfo.CreateBuffer ();
|
m_RouterInfo.CreateBuffer ();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RouterContext::Sign (uint8_t * buf, int len, uint8_t * signature)
|
void RouterContext::Sign (const uint8_t * buf, int len, uint8_t * signature) const
|
||||||
{
|
{
|
||||||
CryptoPP::DSA::Signer signer (m_SigningPrivateKey);
|
CryptoPP::DSA::Signer signer (m_SigningPrivateKey);
|
||||||
signer.SignMessage (m_Rnd, buf, len, signature);
|
signer.SignMessage (i2p::context.GetRandomNumberGenerator (), buf, len, signature);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RouterContext::Load ()
|
bool RouterContext::Load ()
|
||||||
@ -79,7 +79,8 @@ namespace i2p
|
|||||||
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_RouterInfo = i2p::data::RouterInfo (i2p::util::filesystem::GetFullPath (ROUTER_INFO).c_str ()); // TODO
|
i2p::data::RouterInfo routerInfo(i2p::util::filesystem::GetFullPath (ROUTER_INFO)); // TODO
|
||||||
|
m_RouterInfo.Update (routerInfo.GetBuffer (), routerInfo.GetBufferLen ());
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -92,7 +93,6 @@ namespace i2p
|
|||||||
fk.write ((char *)&m_Keys, sizeof (m_Keys));
|
fk.write ((char *)&m_Keys, sizeof (m_Keys));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::ofstream fi (i2p::util::filesystem::GetFullPath (ROUTER_INFO).c_str (), std::ofstream::binary | std::ofstream::out);
|
m_RouterInfo.SaveToFile (i2p::util::filesystem::GetFullPath (ROUTER_INFO));
|
||||||
fi.write ((char *)m_RouterInfo.GetBuffer (), m_RouterInfo.GetBufferLen ());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,17 +23,16 @@ namespace i2p
|
|||||||
const uint8_t * GetSigningPrivateKey () const { return m_Keys.signingPrivateKey; };
|
const uint8_t * GetSigningPrivateKey () const { return m_Keys.signingPrivateKey; };
|
||||||
const i2p::data::Identity& GetRouterIdentity () const { return m_RouterInfo.GetRouterIdentity (); };
|
const i2p::data::Identity& GetRouterIdentity () const { return m_RouterInfo.GetRouterIdentity (); };
|
||||||
CryptoPP::RandomNumberGenerator& GetRandomNumberGenerator () { return m_Rnd; };
|
CryptoPP::RandomNumberGenerator& GetRandomNumberGenerator () { return m_Rnd; };
|
||||||
|
|
||||||
void Sign (uint8_t * buf, int len, uint8_t * signature);
|
|
||||||
|
|
||||||
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
|
// implements LocalDestination
|
||||||
void UpdateLeaseSet () {};
|
|
||||||
const i2p::data::IdentHash& GetIdentHash () const { return m_RouterInfo.GetIdentHash (); };
|
const i2p::data::IdentHash& GetIdentHash () const { return m_RouterInfo.GetIdentHash (); };
|
||||||
|
const i2p::data::Identity& GetIdentity () const { return GetRouterIdentity (); };
|
||||||
const uint8_t * GetEncryptionPrivateKey () const { return GetPrivateKey (); };
|
const uint8_t * GetEncryptionPrivateKey () const { return GetPrivateKey (); };
|
||||||
const uint8_t * GetEncryptionPublicKey () const { return m_Keys.publicKey; };
|
const uint8_t * GetEncryptionPublicKey () const { return m_Keys.publicKey; };
|
||||||
|
void Sign (const uint8_t * buf, int len, uint8_t * signature) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
@ -17,52 +17,87 @@ namespace i2p
|
|||||||
{
|
{
|
||||||
namespace data
|
namespace data
|
||||||
{
|
{
|
||||||
RouterInfo::RouterInfo (const char * filename):
|
RouterInfo::RouterInfo (const std::string& fullPath):
|
||||||
m_IsUpdated (false), m_IsUnreachable (false), m_SupportedTransports (0), m_Caps (0)
|
m_FullPath (fullPath), m_IsUpdated (false), m_IsUnreachable (false),
|
||||||
|
m_SupportedTransports (0), m_Caps (0)
|
||||||
{
|
{
|
||||||
ReadFromFile (filename);
|
m_Buffer = new uint8_t[MAX_RI_BUFFER_SIZE];
|
||||||
|
ReadFromFile ();
|
||||||
}
|
}
|
||||||
|
|
||||||
RouterInfo::RouterInfo (const uint8_t * buf, int len):
|
RouterInfo::RouterInfo (const uint8_t * buf, int len):
|
||||||
m_IsUpdated (true), m_IsUnreachable (false), m_SupportedTransports (0), m_Caps (0)
|
m_IsUpdated (true), m_IsUnreachable (false), m_SupportedTransports (0), m_Caps (0)
|
||||||
{
|
{
|
||||||
|
m_Buffer = new uint8_t[MAX_RI_BUFFER_SIZE];
|
||||||
memcpy (m_Buffer, buf, len);
|
memcpy (m_Buffer, buf, len);
|
||||||
m_BufferLen = len;
|
m_BufferLen = len;
|
||||||
ReadFromBuffer ();
|
ReadFromBuffer ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RouterInfo::~RouterInfo ()
|
||||||
|
{
|
||||||
|
delete m_Buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RouterInfo::Update (const uint8_t * buf, int len)
|
||||||
|
{
|
||||||
|
if (!m_Buffer)
|
||||||
|
m_Buffer = new uint8_t[MAX_RI_BUFFER_SIZE];
|
||||||
|
m_IsUpdated = true;
|
||||||
|
m_IsUnreachable = false;
|
||||||
|
m_SupportedTransports = 0;
|
||||||
|
m_Caps = 0;
|
||||||
|
m_Addresses.clear ();
|
||||||
|
m_Properties.clear ();
|
||||||
|
memcpy (m_Buffer, buf, len);
|
||||||
|
m_BufferLen = len;
|
||||||
|
ReadFromBuffer ();
|
||||||
|
// don't delete buffer until save to file
|
||||||
|
}
|
||||||
|
|
||||||
void RouterInfo::SetRouterIdentity (const Identity& identity)
|
void RouterInfo::SetRouterIdentity (const Identity& identity)
|
||||||
{
|
{
|
||||||
m_RouterIdentity = identity;
|
m_RouterIdentity = identity;
|
||||||
m_IdentHash = m_RouterIdentity.Hash ();
|
m_IdentHash = m_RouterIdentity.Hash ();
|
||||||
UpdateIdentHashBase64 ();
|
UpdateIdentHashBase64 ();
|
||||||
UpdateRoutingKey ();
|
UpdateRoutingKey ();
|
||||||
m_Timestamp = i2p::util::GetMillisecondsSinceEpoch ();
|
m_Timestamp = i2p::util::GetMillisecondsSinceEpoch ();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RouterInfo::ReadFromFile (const char * filename)
|
bool RouterInfo::LoadFile ()
|
||||||
{
|
{
|
||||||
std::ifstream s(filename, std::ifstream::binary);
|
std::ifstream s(m_FullPath.c_str (), std::ifstream::binary);
|
||||||
if (s.is_open ())
|
if (s.is_open ())
|
||||||
{
|
{
|
||||||
s.seekg (0,std::ios::end);
|
s.seekg (0,std::ios::end);
|
||||||
m_BufferLen = s.tellg ();
|
m_BufferLen = s.tellg ();
|
||||||
if (m_BufferLen < 40)
|
if (m_BufferLen < 40)
|
||||||
{
|
{
|
||||||
LogPrint("File", filename, " is malformed");
|
LogPrint("File", m_FullPath, " is malformed");
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
s.seekg(0, std::ios::beg);
|
s.seekg(0, std::ios::beg);
|
||||||
s.read(m_Buffer,m_BufferLen);
|
if (!m_Buffer)
|
||||||
ReadFromBuffer ();
|
m_Buffer = new uint8_t[MAX_RI_BUFFER_SIZE];
|
||||||
|
s.read((char *)m_Buffer, m_BufferLen);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
LogPrint ("Can't open file ", filename);
|
{
|
||||||
|
LogPrint ("Can't open file ", m_FullPath);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RouterInfo::ReadFromFile ()
|
||||||
|
{
|
||||||
|
if (LoadFile ())
|
||||||
|
ReadFromBuffer ();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RouterInfo::ReadFromBuffer ()
|
void RouterInfo::ReadFromBuffer ()
|
||||||
{
|
{
|
||||||
std::stringstream str (std::string (m_Buffer, m_BufferLen));
|
std::stringstream str (std::string ((char *)m_Buffer, m_BufferLen));
|
||||||
ReadFromStream (str);
|
ReadFromStream (str);
|
||||||
// verify signature
|
// verify signature
|
||||||
CryptoPP::DSA::PublicKey pubKey;
|
CryptoPP::DSA::PublicKey pubKey;
|
||||||
@ -83,8 +118,10 @@ namespace data
|
|||||||
// read addresses
|
// read addresses
|
||||||
uint8_t numAddresses;
|
uint8_t numAddresses;
|
||||||
s.read ((char *)&numAddresses, sizeof (numAddresses));
|
s.read ((char *)&numAddresses, sizeof (numAddresses));
|
||||||
|
bool introducers = false;
|
||||||
for (int i = 0; i < numAddresses; i++)
|
for (int i = 0; i < numAddresses; i++)
|
||||||
{
|
{
|
||||||
|
bool isValidAddress = true;
|
||||||
Address address;
|
Address address;
|
||||||
s.read ((char *)&address.cost, sizeof (address.cost));
|
s.read ((char *)&address.cost, sizeof (address.cost));
|
||||||
s.read ((char *)&address.date, sizeof (address.date));
|
s.read ((char *)&address.date, sizeof (address.date));
|
||||||
@ -114,7 +151,7 @@ namespace data
|
|||||||
{
|
{
|
||||||
// TODO: we should try to resolve address here
|
// TODO: we should try to resolve address here
|
||||||
LogPrint ("Unexpected address ", value);
|
LogPrint ("Unexpected address ", value);
|
||||||
SetUnreachable (true);
|
isValidAddress = false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -134,6 +171,7 @@ namespace data
|
|||||||
else if (key[0] == 'i')
|
else if (key[0] == 'i')
|
||||||
{
|
{
|
||||||
// introducers
|
// introducers
|
||||||
|
introducers = true;
|
||||||
size_t l = strlen(key);
|
size_t l = strlen(key);
|
||||||
unsigned char index = key[l-1] - '0'; // TODO:
|
unsigned char index = key[l-1] - '0'; // TODO:
|
||||||
key[l-1] = 0;
|
key[l-1] = 0;
|
||||||
@ -153,7 +191,8 @@ namespace data
|
|||||||
Base64ToByteStream (value, strlen (value), introducer.iKey, 32);
|
Base64ToByteStream (value, strlen (value), introducer.iKey, 32);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
m_Addresses.push_back(address);
|
if (isValidAddress)
|
||||||
|
m_Addresses.push_back(address);
|
||||||
}
|
}
|
||||||
// read peers
|
// read peers
|
||||||
uint8_t numPeers;
|
uint8_t numPeers;
|
||||||
@ -187,7 +226,7 @@ namespace data
|
|||||||
UpdateIdentHashBase64 ();
|
UpdateIdentHashBase64 ();
|
||||||
UpdateRoutingKey ();
|
UpdateRoutingKey ();
|
||||||
|
|
||||||
if (!m_SupportedTransports)
|
if (!m_SupportedTransports || !m_Addresses.size() || (UsesIntroducer () && !introducers))
|
||||||
SetUnreachable (true);
|
SetUnreachable (true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -311,17 +350,41 @@ namespace data
|
|||||||
s.write (properties.str ().c_str (), properties.str ().size ());
|
s.write (properties.str ().c_str (), properties.str ().size ());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const uint8_t * RouterInfo::LoadBuffer ()
|
||||||
|
{
|
||||||
|
if (!m_Buffer)
|
||||||
|
{
|
||||||
|
if (LoadFile ())
|
||||||
|
LogPrint ("Buffer for ", m_IdentHashAbbreviation, " loaded from file");
|
||||||
|
}
|
||||||
|
return m_Buffer;
|
||||||
|
}
|
||||||
|
|
||||||
void RouterInfo::CreateBuffer ()
|
void RouterInfo::CreateBuffer ()
|
||||||
{
|
{
|
||||||
m_Timestamp = i2p::util::GetMillisecondsSinceEpoch (); // refresh timstamp
|
m_Timestamp = i2p::util::GetMillisecondsSinceEpoch (); // refresh timstamp
|
||||||
std::stringstream s;
|
std::stringstream s;
|
||||||
WriteToStream (s);
|
WriteToStream (s);
|
||||||
m_BufferLen = s.str ().size ();
|
m_BufferLen = s.str ().size ();
|
||||||
|
if (!m_Buffer)
|
||||||
|
m_Buffer = new uint8_t[MAX_RI_BUFFER_SIZE];
|
||||||
memcpy (m_Buffer, s.str ().c_str (), m_BufferLen);
|
memcpy (m_Buffer, s.str ().c_str (), m_BufferLen);
|
||||||
// signature
|
// signature
|
||||||
i2p::context.Sign ((uint8_t *)m_Buffer, m_BufferLen, (uint8_t *)m_Buffer + m_BufferLen);
|
i2p::context.Sign ((uint8_t *)m_Buffer, m_BufferLen, (uint8_t *)m_Buffer + m_BufferLen);
|
||||||
m_BufferLen += 40;
|
m_BufferLen += 40;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RouterInfo::SaveToFile (const std::string& fullPath)
|
||||||
|
{
|
||||||
|
m_FullPath = fullPath;
|
||||||
|
if (m_Buffer)
|
||||||
|
{
|
||||||
|
std::ofstream f (fullPath, std::ofstream::binary | std::ofstream::out);
|
||||||
|
f.write ((char *)m_Buffer, m_BufferLen);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
LogPrint ("Can't save to file");
|
||||||
|
}
|
||||||
|
|
||||||
size_t RouterInfo::ReadString (char * str, std::istream& s)
|
size_t RouterInfo::ReadString (char * str, std::istream& s)
|
||||||
{
|
{
|
||||||
|
25
RouterInfo.h
25
RouterInfo.h
@ -13,6 +13,7 @@ namespace i2p
|
|||||||
{
|
{
|
||||||
namespace data
|
namespace data
|
||||||
{
|
{
|
||||||
|
const int MAX_RI_BUFFER_SIZE = 2048;
|
||||||
class RouterInfo: public RoutingDestination
|
class RouterInfo: public RoutingDestination
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -62,11 +63,12 @@ namespace data
|
|||||||
std::vector<Introducer> introducers;
|
std::vector<Introducer> introducers;
|
||||||
};
|
};
|
||||||
|
|
||||||
RouterInfo (const char * filename);
|
RouterInfo (const std::string& fullPath);
|
||||||
RouterInfo () = default;
|
RouterInfo (): m_Buffer (nullptr) { m_IdentHashBase64[0] = 0; m_IdentHashAbbreviation[0] = 0; };
|
||||||
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);
|
||||||
|
~RouterInfo ();
|
||||||
|
|
||||||
const Identity& GetRouterIdentity () const { return m_RouterIdentity; };
|
const Identity& GetRouterIdentity () const { return m_RouterIdentity; };
|
||||||
void SetRouterIdentity (const Identity& identity);
|
void SetRouterIdentity (const Identity& identity);
|
||||||
@ -95,23 +97,31 @@ namespace data
|
|||||||
|
|
||||||
void SetUnreachable (bool unreachable) { m_IsUnreachable = unreachable; };
|
void SetUnreachable (bool unreachable) { m_IsUnreachable = unreachable; };
|
||||||
bool IsUnreachable () const { return m_IsUnreachable; };
|
bool IsUnreachable () const { return m_IsUnreachable; };
|
||||||
|
|
||||||
|
const uint8_t * GetBuffer () const { return m_Buffer; };
|
||||||
|
const uint8_t * LoadBuffer (); // load if necessary
|
||||||
|
int GetBufferLen () const { return m_BufferLen; };
|
||||||
|
|
||||||
void CreateBuffer ();
|
void CreateBuffer ();
|
||||||
void UpdateRoutingKey ();
|
void UpdateRoutingKey ();
|
||||||
const char * GetBuffer () const { return m_Buffer; };
|
|
||||||
int GetBufferLen () const { return m_BufferLen; };
|
|
||||||
|
|
||||||
bool IsUpdated () const { return m_IsUpdated; };
|
bool IsUpdated () const { return m_IsUpdated; };
|
||||||
void SetUpdated (bool updated) { m_IsUpdated = updated; };
|
void SetUpdated (bool updated) { m_IsUpdated = updated; };
|
||||||
|
void SaveToFile (const std::string& fullPath);
|
||||||
|
|
||||||
|
void Update (const uint8_t * buf, int len);
|
||||||
|
void DeleteBuffer () { delete m_Buffer; m_Buffer = nullptr; };
|
||||||
|
|
||||||
// implements RoutingDestination
|
// implements RoutingDestination
|
||||||
const IdentHash& GetIdentHash () const { return m_IdentHash; };
|
const IdentHash& GetIdentHash () const { return m_IdentHash; };
|
||||||
const uint8_t * GetEncryptionPublicKey () const { return m_RouterIdentity.publicKey; };
|
const uint8_t * GetEncryptionPublicKey () const { return m_RouterIdentity.publicKey; };
|
||||||
bool IsDestination () const { return false; };
|
bool IsDestination () const { return false; };
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void ReadFromFile (const char * filename);
|
bool LoadFile ();
|
||||||
|
void ReadFromFile ();
|
||||||
void ReadFromStream (std::istream& s);
|
void ReadFromStream (std::istream& s);
|
||||||
void ReadFromBuffer ();
|
void ReadFromBuffer ();
|
||||||
void WriteToStream (std::ostream& s);
|
void WriteToStream (std::ostream& s);
|
||||||
@ -123,11 +133,12 @@ namespace data
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
std::string m_FullPath;
|
||||||
Identity m_RouterIdentity;
|
Identity m_RouterIdentity;
|
||||||
IdentHash m_IdentHash;
|
IdentHash m_IdentHash;
|
||||||
RoutingKey m_RoutingKey;
|
RoutingKey m_RoutingKey;
|
||||||
char m_IdentHashBase64[48], m_IdentHashAbbreviation[5];
|
char m_IdentHashBase64[48], m_IdentHashAbbreviation[5];
|
||||||
char m_Buffer[2048];
|
uint8_t * m_Buffer;
|
||||||
int m_BufferLen;
|
int m_BufferLen;
|
||||||
uint64_t m_Timestamp;
|
uint64_t m_Timestamp;
|
||||||
std::vector<Address> m_Addresses;
|
std::vector<Address> m_Addresses;
|
||||||
|
282
SOCKS.cpp
Normal file
282
SOCKS.cpp
Normal file
@ -0,0 +1,282 @@
|
|||||||
|
#include "SOCKS.h"
|
||||||
|
#include "Identity.h"
|
||||||
|
#include "NetDb.h"
|
||||||
|
#include <cstring>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <boost/date_time/posix_time/posix_time.hpp>
|
||||||
|
#include <boost/bind.hpp>
|
||||||
|
|
||||||
|
namespace i2p
|
||||||
|
{
|
||||||
|
namespace proxy
|
||||||
|
{
|
||||||
|
constexpr uint8_t socks_leaseset_timeout = 10;
|
||||||
|
constexpr uint8_t socks_timeout = 60;
|
||||||
|
|
||||||
|
void SOCKS4AHandler::AsyncSockRead()
|
||||||
|
{
|
||||||
|
LogPrint("--- socks4a async sock read");
|
||||||
|
if(m_sock) {
|
||||||
|
if (m_state == INITIAL) {
|
||||||
|
m_sock->async_receive(boost::asio::buffer(m_sock_buff, socks_buffer_size),
|
||||||
|
boost::bind(&SOCKS4AHandler::HandleSockRecv, this,
|
||||||
|
boost::asio::placeholders::error,
|
||||||
|
boost::asio::placeholders::bytes_transferred));
|
||||||
|
} else {
|
||||||
|
m_sock->async_receive(boost::asio::buffer(m_sock_buff, socks_buffer_size),
|
||||||
|
boost::bind(&SOCKS4AHandler::HandleSockForward, this,
|
||||||
|
boost::asio::placeholders::error,
|
||||||
|
boost::asio::placeholders::bytes_transferred));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
LogPrint("--- socks4a no socket for read");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SOCKS4AHandler::AsyncStreamRead()
|
||||||
|
{
|
||||||
|
|
||||||
|
LogPrint("--- socks4a async stream read");
|
||||||
|
if (m_stream) {
|
||||||
|
m_stream->AsyncReceive(
|
||||||
|
boost::asio::buffer(m_stream_buff, socks_buffer_size),
|
||||||
|
boost::bind(&SOCKS4AHandler::HandleStreamRecv, this,
|
||||||
|
boost::asio::placeholders::error,
|
||||||
|
boost::asio::placeholders::bytes_transferred), socks_timeout);
|
||||||
|
} else {
|
||||||
|
LogPrint("--- socks4a no stream for read");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SOCKS4AHandler::Terminate() {
|
||||||
|
CloseStream();
|
||||||
|
CloseSock();
|
||||||
|
delete this; // ew
|
||||||
|
}
|
||||||
|
|
||||||
|
void SOCKS4AHandler::SocksFailed()
|
||||||
|
{
|
||||||
|
LogPrint("--- socks4a failed");
|
||||||
|
m_sock->send(boost::asio::buffer("\x00\x5b 12345"));
|
||||||
|
Terminate();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SOCKS4AHandler::CloseSock()
|
||||||
|
{
|
||||||
|
if (m_sock) {
|
||||||
|
LogPrint("--- socks4a close sock");
|
||||||
|
m_sock->close();
|
||||||
|
delete m_sock;
|
||||||
|
m_sock = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SOCKS4AHandler::CloseStream()
|
||||||
|
{
|
||||||
|
if (m_stream) {
|
||||||
|
LogPrint("--- socks4a close stream");
|
||||||
|
delete m_stream;
|
||||||
|
m_stream = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr size_t socks_hostname_size = 1024;
|
||||||
|
constexpr size_t socks_ident_size = 1024;
|
||||||
|
constexpr size_t destb32_len = 52;
|
||||||
|
|
||||||
|
void SOCKS4AHandler::HandleSockForward(const boost::system::error_code & ecode, std::size_t len)
|
||||||
|
{
|
||||||
|
if(ecode) {
|
||||||
|
LogPrint("--- socks4a forward got error: ", ecode);
|
||||||
|
Terminate();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LogPrint("--- socks4a sock forward: ", len);
|
||||||
|
m_stream->Send(m_sock_buff, len, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SOCKS4AHandler::HandleSockRecv(const boost::system::error_code & ecode, std::size_t len)
|
||||||
|
{
|
||||||
|
LogPrint("--- socks4a sock recv: ", len);
|
||||||
|
|
||||||
|
if(ecode) {
|
||||||
|
LogPrint(" --- sock recv got error: ", ecode);
|
||||||
|
Terminate();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_state == INITIAL) {
|
||||||
|
|
||||||
|
char hostbuff[socks_hostname_size];
|
||||||
|
char identbuff[socks_ident_size];
|
||||||
|
std::memset(hostbuff, 0, sizeof(hostbuff));
|
||||||
|
std::memset(identbuff, 0, sizeof(hostbuff));
|
||||||
|
std::string dest;
|
||||||
|
// get port
|
||||||
|
uint16_t port = 0;
|
||||||
|
uint16_t idx1 = 0;
|
||||||
|
uint16_t idx2 = 0;
|
||||||
|
|
||||||
|
LogPrint("--- socks4a state initial ", len);
|
||||||
|
|
||||||
|
// check valid request
|
||||||
|
if( m_sock_buff[0] != 4 || m_sock_buff[1] != 1 || m_sock_buff[len-1] ) {
|
||||||
|
LogPrint("--- socks4a rejected invalid");
|
||||||
|
SocksFailed();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get port
|
||||||
|
port = m_sock_buff[3] | m_sock_buff[2] << 8;
|
||||||
|
|
||||||
|
// read ident
|
||||||
|
do {
|
||||||
|
LogPrint("--- socks4a ", (int) m_sock_buff[9+idx1]);
|
||||||
|
identbuff[idx1] = m_sock_buff[8+idx1];
|
||||||
|
} while( identbuff[idx1++] && idx1 < socks_ident_size );
|
||||||
|
|
||||||
|
LogPrint("--- socks4a ident ", identbuff);
|
||||||
|
// read hostname
|
||||||
|
do {
|
||||||
|
hostbuff[idx2] = m_sock_buff[8+idx1+idx2];
|
||||||
|
} while( hostbuff[idx2++] && idx2 < socks_hostname_size );
|
||||||
|
|
||||||
|
LogPrint("--- socks4a requested ", hostbuff, ":" , port);
|
||||||
|
|
||||||
|
dest = std::string(hostbuff);
|
||||||
|
if(dest.find(".b32.i2p") == std::string::npos) {
|
||||||
|
LogPrint("--- socks4a invalid hostname: ", dest);
|
||||||
|
SocksFailed();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( i2p::data::Base32ToByteStream(hostbuff, destb32_len, (uint8_t *) m_dest, 32) != 32 ) {
|
||||||
|
LogPrint("--- sock4a invalid b32: ", dest);
|
||||||
|
}
|
||||||
|
|
||||||
|
LogPrint("--- sock4a find lease set");
|
||||||
|
m_ls = i2p::data::netdb.FindLeaseSet(m_dest);
|
||||||
|
if (!m_ls || m_ls->HasNonExpiredLeases()) {
|
||||||
|
i2p::data::netdb.Subscribe(m_dest);
|
||||||
|
m_ls_timer.expires_from_now(boost::posix_time::seconds(socks_leaseset_timeout));
|
||||||
|
m_ls_timer.async_wait(boost::bind(&SOCKS4AHandler::LeaseSetTimeout, this, boost::asio::placeholders::error));
|
||||||
|
} else {
|
||||||
|
ConnectionSuccess();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
LogPrint("--- socks4a state?? ", m_state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SOCKS4AHandler::HandleStreamRecv(const boost::system::error_code & ecode, std::size_t len)
|
||||||
|
{
|
||||||
|
if(ecode) { LogPrint("--- socks4a stream recv error: ", ecode); m_state = END; }
|
||||||
|
switch(m_state) {
|
||||||
|
case INITIAL:
|
||||||
|
case END:
|
||||||
|
Terminate();
|
||||||
|
return;
|
||||||
|
case OKAY:
|
||||||
|
LogPrint("--- socks4a stream recv ", len);
|
||||||
|
boost::asio::async_write(*m_sock, boost::asio::buffer(m_stream_buff, len),
|
||||||
|
boost::bind(&SOCKS4AHandler::StreamWrote, this,
|
||||||
|
boost::asio::placeholders::error));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SOCKS4AHandler::SockWrote(const boost::system::error_code & ecode)
|
||||||
|
{
|
||||||
|
LogPrint("--- socks4a sock wrote");
|
||||||
|
if(ecode) { LogPrint("--- socks4a SockWrote error: ",ecode); }
|
||||||
|
else { AsyncSockRead(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
void SOCKS4AHandler::StreamWrote(const boost::system::error_code & ecode)
|
||||||
|
{
|
||||||
|
|
||||||
|
LogPrint("--- socks4a stream wrote");
|
||||||
|
if(ecode) { LogPrint("--- socks4a StreamWrote error: ",ecode); }
|
||||||
|
else { AsyncStreamRead(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
void SOCKS4AHandler::LeaseSetTimeout(const boost::system::error_code & ecode)
|
||||||
|
{
|
||||||
|
m_ls = i2p::data::netdb.FindLeaseSet(m_dest);
|
||||||
|
if(m_ls) {
|
||||||
|
ConnectionSuccess();
|
||||||
|
} else {
|
||||||
|
LogPrint("--- socks4a ls timeout");
|
||||||
|
SocksFailed();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SOCKS4AHandler::ConnectionSuccess()
|
||||||
|
{
|
||||||
|
LogPrint("--- socks4a connection success");
|
||||||
|
boost::asio::async_write(*m_sock, boost::asio::buffer("\x00\x5a 12345"),
|
||||||
|
boost::bind(&SOCKS4AHandler::SentConnectionSuccess, this,
|
||||||
|
boost::asio::placeholders::error));
|
||||||
|
}
|
||||||
|
|
||||||
|
void SOCKS4AHandler::SentConnectionSuccess(const boost::system::error_code & ecode)
|
||||||
|
{
|
||||||
|
LogPrint("--- socks4a making connection");
|
||||||
|
m_stream = i2p::stream::CreateStream(*m_ls);
|
||||||
|
m_state = OKAY;
|
||||||
|
LogPrint("--- socks4a state is ", m_state);
|
||||||
|
AsyncSockRead();
|
||||||
|
AsyncStreamRead();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SOCKS4AServer::Run()
|
||||||
|
{
|
||||||
|
LogPrint("--- socks4a run");
|
||||||
|
m_run = true;
|
||||||
|
while(m_run) {
|
||||||
|
try {
|
||||||
|
m_ios.run();
|
||||||
|
} catch (std::runtime_error & exc) {
|
||||||
|
LogPrint("--- socks4a exception: ", exc.what());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SOCKS4AServer::Accept()
|
||||||
|
{
|
||||||
|
m_new_sock = new boost::asio::ip::tcp::socket(m_ios);
|
||||||
|
m_acceptor.async_accept(*m_new_sock,
|
||||||
|
boost::bind(
|
||||||
|
&SOCKS4AServer::HandleAccept, this, boost::asio::placeholders::error));
|
||||||
|
}
|
||||||
|
|
||||||
|
void SOCKS4AServer::Start()
|
||||||
|
{
|
||||||
|
m_run = true;
|
||||||
|
m_thread = new std::thread(std::bind(&SOCKS4AServer::Run, this));
|
||||||
|
m_acceptor.listen();
|
||||||
|
Accept();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SOCKS4AServer::Stop()
|
||||||
|
{
|
||||||
|
m_acceptor.close();
|
||||||
|
m_run = false;
|
||||||
|
m_ios.stop();
|
||||||
|
if (m_thread) {
|
||||||
|
m_thread->join();
|
||||||
|
delete m_thread;
|
||||||
|
m_thread = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SOCKS4AServer::HandleAccept(const boost::system::error_code & ecode)
|
||||||
|
{
|
||||||
|
if (!ecode) {
|
||||||
|
LogPrint("--- socks4a accepted");
|
||||||
|
new SOCKS4AHandler(&m_ios, m_new_sock);
|
||||||
|
Accept();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
98
SOCKS.h
Normal file
98
SOCKS.h
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
#ifndef SOCKS4A_H__
|
||||||
|
#define SOCKS4A_H__
|
||||||
|
|
||||||
|
#include <thread>
|
||||||
|
#include <boost/asio.hpp>
|
||||||
|
#include <vector>
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
|
#include "Identity.h"
|
||||||
|
#include "Streaming.h"
|
||||||
|
|
||||||
|
namespace i2p
|
||||||
|
{
|
||||||
|
namespace proxy
|
||||||
|
{
|
||||||
|
|
||||||
|
constexpr size_t socks_buffer_size = 8192;
|
||||||
|
|
||||||
|
class SOCKS4AHandler {
|
||||||
|
|
||||||
|
private:
|
||||||
|
enum state {
|
||||||
|
INITIAL,
|
||||||
|
OKAY,
|
||||||
|
END
|
||||||
|
};
|
||||||
|
|
||||||
|
void GotClientRequest(boost::system::error_code & ecode, std::string & host, uint16_t port);
|
||||||
|
void HandleSockRecv(const boost::system::error_code & ecode, std::size_t bytes_transfered);
|
||||||
|
void HandleSockForward(const boost::system::error_code & ecode, std::size_t bytes_transfered);
|
||||||
|
void HandleStreamRecv(const boost::system::error_code & ecode, std::size_t bytes_transfered);
|
||||||
|
void Terminate();
|
||||||
|
void CloseSock();
|
||||||
|
void CloseStream();
|
||||||
|
void AsyncSockRead();
|
||||||
|
void AsyncStreamRead();
|
||||||
|
void SocksFailed();
|
||||||
|
void LeaseSetTimeout(const boost::system::error_code & ecode);
|
||||||
|
void StreamWrote(const boost::system::error_code & ecode);
|
||||||
|
void SockWrote(const boost::system::error_code & ecode);
|
||||||
|
void SentConnectionSuccess(const boost::system::error_code & ecode);
|
||||||
|
void ConnectionSuccess();
|
||||||
|
|
||||||
|
uint8_t m_sock_buff[socks_buffer_size];
|
||||||
|
uint8_t m_stream_buff[socks_buffer_size];
|
||||||
|
|
||||||
|
boost::asio::io_service * m_ios;
|
||||||
|
boost::asio::ip::tcp::socket * m_sock;
|
||||||
|
boost::asio::deadline_timer m_ls_timer;
|
||||||
|
i2p::stream::Stream * m_stream;
|
||||||
|
i2p::data::LeaseSet * m_ls;
|
||||||
|
i2p::data::IdentHash m_dest;
|
||||||
|
state m_state;
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
SOCKS4AHandler(boost::asio::io_service * ios, boost::asio::ip::tcp::socket * sock) :
|
||||||
|
m_ios(ios), m_sock(sock), m_ls_timer(*ios),
|
||||||
|
m_stream(nullptr), m_ls(nullptr), m_state(INITIAL) { AsyncSockRead(); }
|
||||||
|
|
||||||
|
~SOCKS4AHandler() { CloseSock(); CloseStream(); }
|
||||||
|
bool isComplete() { return m_state == END; }
|
||||||
|
};
|
||||||
|
|
||||||
|
class SOCKS4AServer {
|
||||||
|
public:
|
||||||
|
SOCKS4AServer(int port) : m_run(false),
|
||||||
|
m_thread(nullptr),
|
||||||
|
m_work(m_ios),
|
||||||
|
m_acceptor(m_ios, boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), port)),
|
||||||
|
m_new_sock(nullptr) { }
|
||||||
|
~SOCKS4AServer() { Stop(); }
|
||||||
|
void Start();
|
||||||
|
void Stop();
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
void Run();
|
||||||
|
void Accept();
|
||||||
|
void HandleAccept(const boost::system::error_code& ecode);
|
||||||
|
|
||||||
|
bool m_run;
|
||||||
|
std::thread * m_thread;
|
||||||
|
boost::asio::io_service m_ios;
|
||||||
|
boost::asio::io_service::work m_work;
|
||||||
|
boost::asio::ip::tcp::acceptor m_acceptor;
|
||||||
|
boost::asio::ip::tcp::socket * m_new_sock;
|
||||||
|
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef SOCKS4AServer SOCKSProxy;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
75
SSU.cpp
75
SSU.cpp
@ -19,7 +19,8 @@ namespace ssu
|
|||||||
const i2p::data::RouterInfo * router, bool peerTest ):
|
const i2p::data::RouterInfo * router, bool peerTest ):
|
||||||
m_Server (server), m_RemoteEndpoint (remoteEndpoint), m_RemoteRouter (router),
|
m_Server (server), m_RemoteEndpoint (remoteEndpoint), m_RemoteRouter (router),
|
||||||
m_Timer (m_Server.GetService ()), m_PeerTest (peerTest), m_State (eSessionStateUnknown),
|
m_Timer (m_Server.GetService ()), m_PeerTest (peerTest), m_State (eSessionStateUnknown),
|
||||||
m_IsSessionKey (false), m_RelayTag (0), m_Data (*this)
|
m_IsSessionKey (false), m_RelayTag (0), m_Data (*this),
|
||||||
|
m_NumSentBytes (0), m_NumReceivedBytes (0)
|
||||||
{
|
{
|
||||||
m_DHKeysPair = i2p::transports.GetNextDHKeysPair ();
|
m_DHKeysPair = i2p::transports.GetNextDHKeysPair ();
|
||||||
}
|
}
|
||||||
@ -74,20 +75,18 @@ namespace ssu
|
|||||||
|
|
||||||
void SSUSession::ProcessNextMessage (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint)
|
void SSUSession::ProcessNextMessage (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint)
|
||||||
{
|
{
|
||||||
|
m_NumReceivedBytes += len;
|
||||||
if (m_State == eSessionStateIntroduced)
|
if (m_State == eSessionStateIntroduced)
|
||||||
{
|
{
|
||||||
// HolePunch received
|
// HolePunch received
|
||||||
LogPrint ("SSU HolePuch of ", len, " bytes received");
|
LogPrint ("SSU HolePunch of ", len, " bytes received");
|
||||||
m_State = eSessionStateUnknown;
|
m_State = eSessionStateUnknown;
|
||||||
Connect ();
|
Connect ();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ScheduleTermination ();
|
if (m_State == eSessionStateEstablished)
|
||||||
// check for duplicate
|
ScheduleTermination ();
|
||||||
const uint8_t * iv = ((SSUHeader *)buf)->iv;
|
|
||||||
if (m_ReceivedIVs.count (iv)) return; // duplicate detected
|
|
||||||
m_ReceivedIVs.insert (iv);
|
|
||||||
|
|
||||||
if (m_IsSessionKey && Validate (buf, len, m_MacKey)) // try session key first
|
if (m_IsSessionKey && Validate (buf, len, m_MacKey)) // try session key first
|
||||||
DecryptSessionKey (buf, len);
|
DecryptSessionKey (buf, len);
|
||||||
@ -151,7 +150,8 @@ namespace ssu
|
|||||||
}
|
}
|
||||||
case PAYLOAD_TYPE_RELAY_RESPONSE:
|
case PAYLOAD_TYPE_RELAY_RESPONSE:
|
||||||
ProcessRelayResponse (buf, len);
|
ProcessRelayResponse (buf, len);
|
||||||
m_Server.DeleteSession (this);
|
if (m_State != eSessionStateEstablished)
|
||||||
|
m_Server.DeleteSession (this);
|
||||||
break;
|
break;
|
||||||
case PAYLOAD_TYPE_RELAY_REQUEST:
|
case PAYLOAD_TYPE_RELAY_REQUEST:
|
||||||
LogPrint ("SSU relay request received");
|
LogPrint ("SSU relay request received");
|
||||||
@ -626,7 +626,7 @@ namespace ssu
|
|||||||
if (!m_DelayedMessages.empty ())
|
if (!m_DelayedMessages.empty ())
|
||||||
{
|
{
|
||||||
for (auto it :m_DelayedMessages)
|
for (auto it :m_DelayedMessages)
|
||||||
delete it;
|
DeleteI2NPMessage (it);
|
||||||
m_DelayedMessages.clear ();
|
m_DelayedMessages.clear ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -651,7 +651,6 @@ namespace ssu
|
|||||||
if (m_State != eSessionStateFailed)
|
if (m_State != eSessionStateFailed)
|
||||||
{
|
{
|
||||||
m_State = eSessionStateFailed;
|
m_State = eSessionStateFailed;
|
||||||
Close ();
|
|
||||||
m_Server.DeleteSession (this); // delete this
|
m_Server.DeleteSession (this); // delete this
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -821,6 +820,7 @@ namespace ssu
|
|||||||
// encrypt message with session key
|
// encrypt message with session key
|
||||||
FillHeaderAndEncrypt (PAYLOAD_TYPE_SESSION_DESTROYED, buf, 48);
|
FillHeaderAndEncrypt (PAYLOAD_TYPE_SESSION_DESTROYED, buf, 48);
|
||||||
Send (buf, 48);
|
Send (buf, 48);
|
||||||
|
LogPrint ("SSU session destoryed sent");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -841,6 +841,7 @@ namespace ssu
|
|||||||
|
|
||||||
void SSUSession::Send (const uint8_t * buf, size_t size)
|
void SSUSession::Send (const uint8_t * buf, size_t size)
|
||||||
{
|
{
|
||||||
|
m_NumSentBytes += size;
|
||||||
m_Server.Send (buf, size, m_RemoteEndpoint);
|
m_Server.Send (buf, size, m_RemoteEndpoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -909,7 +910,6 @@ namespace ssu
|
|||||||
void SSUServer::Send (const uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& to)
|
void SSUServer::Send (const uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& to)
|
||||||
{
|
{
|
||||||
m_Socket.send_to (boost::asio::buffer (buf, len), to);
|
m_Socket.send_to (boost::asio::buffer (buf, len), to);
|
||||||
LogPrint ("SSU sent ", len, " bytes");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SSUServer::Receive ()
|
void SSUServer::Receive ()
|
||||||
@ -922,7 +922,6 @@ namespace ssu
|
|||||||
{
|
{
|
||||||
if (!ecode)
|
if (!ecode)
|
||||||
{
|
{
|
||||||
LogPrint ("SSU received ", bytes_transferred, " bytes");
|
|
||||||
SSUSession * session = nullptr;
|
SSUSession * session = nullptr;
|
||||||
auto it = m_Sessions.find (m_SenderEndpoint);
|
auto it = m_Sessions.find (m_SenderEndpoint);
|
||||||
if (it != m_Sessions.end ())
|
if (it != m_Sessions.end ())
|
||||||
@ -985,30 +984,46 @@ namespace ssu
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// connect through introducer
|
// connect through introducer
|
||||||
session->WaitForIntroduction ();
|
int numIntroducers = address->introducers.size ();
|
||||||
if (address->introducers.size () > 0)
|
if (numIntroducers > 0)
|
||||||
{
|
{
|
||||||
auto& introducer = address->introducers[0]; // TODO:
|
|
||||||
boost::asio::ip::udp::endpoint introducerEndpoint (introducer.iHost, introducer.iPort);
|
|
||||||
LogPrint ("Creating new SSU session to [", router->GetIdentHashAbbreviation (),
|
|
||||||
"] through introducer ", introducerEndpoint.address ().to_string (), ":", introducerEndpoint.port ());
|
|
||||||
it = m_Sessions.find (introducerEndpoint);
|
|
||||||
SSUSession * introducerSession = nullptr;
|
SSUSession * introducerSession = nullptr;
|
||||||
if (it != m_Sessions.end ())
|
const i2p::data::RouterInfo::Introducer * introducer = nullptr;
|
||||||
|
// we might have a session to introducer already
|
||||||
|
for (int i = 0; i < numIntroducers; i++)
|
||||||
{
|
{
|
||||||
LogPrint ("Session to introducer already exists");
|
introducer = &(address->introducers[i]);
|
||||||
introducerSession = it->second;
|
it = m_Sessions.find (boost::asio::ip::udp::endpoint (introducer->iHost, introducer->iPort));
|
||||||
}
|
if (it != m_Sessions.end ())
|
||||||
else
|
{
|
||||||
{
|
introducerSession = it->second;
|
||||||
LogPrint ("New session to introducer created");
|
break;
|
||||||
introducerSession = new SSUSession (*this, introducerEndpoint, router);
|
}
|
||||||
m_Sessions[introducerEndpoint] = introducerSession;
|
|
||||||
}
|
}
|
||||||
introducerSession->Introduce (introducer.iTag, introducer.iKey);
|
|
||||||
|
if (introducerSession) // session found
|
||||||
|
LogPrint ("Session to introducer already exists");
|
||||||
|
else // create new
|
||||||
|
{
|
||||||
|
LogPrint ("Creating new session to introducer");
|
||||||
|
introducer = &(address->introducers[0]); // TODO:
|
||||||
|
boost::asio::ip::udp::endpoint introducerEndpoint (introducer->iHost, introducer->iPort);
|
||||||
|
introducerSession = new SSUSession (*this, introducerEndpoint, router);
|
||||||
|
m_Sessions[introducerEndpoint] = introducerSession;
|
||||||
|
}
|
||||||
|
// introduce
|
||||||
|
LogPrint ("Introduce new SSU session to [", router->GetIdentHashAbbreviation (),
|
||||||
|
"] through introducer ", introducer->iHost, ":", introducer->iPort);
|
||||||
|
session->WaitForIntroduction ();
|
||||||
|
introducerSession->Introduce (introducer->iTag, introducer->iKey);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
LogPrint ("Router is unreachable, but not introducers presentd. Ignored");
|
{
|
||||||
|
LogPrint ("Router is unreachable, but no introducers presented. Ignored");
|
||||||
|
m_Sessions.erase (remoteEndpoint);
|
||||||
|
delete session;
|
||||||
|
session = nullptr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
24
SSU.h
24
SSU.h
@ -31,7 +31,6 @@ namespace ssu
|
|||||||
};
|
};
|
||||||
#pragma pack()
|
#pragma pack()
|
||||||
|
|
||||||
const size_t SSU_MTU = 1484;
|
|
||||||
const int SSU_CONNECT_TIMEOUT = 5; // 5 seconds
|
const int SSU_CONNECT_TIMEOUT = 5; // 5 seconds
|
||||||
const int SSU_TERMINATION_TIMEOUT = 330; // 5.5 minutes
|
const int SSU_TERMINATION_TIMEOUT = 330; // 5.5 minutes
|
||||||
|
|
||||||
@ -74,7 +73,10 @@ namespace ssu
|
|||||||
void SendPeerTest (); // Alice
|
void SendPeerTest (); // Alice
|
||||||
|
|
||||||
SessionState GetState () const { return m_State; };
|
SessionState GetState () const { return m_State; };
|
||||||
|
size_t GetNumSentBytes () const { return m_NumSentBytes; };
|
||||||
|
size_t GetNumReceivedBytes () const { return m_NumReceivedBytes; };
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void CreateAESandMacKey (const uint8_t * pubKey);
|
void CreateAESandMacKey (const uint8_t * pubKey);
|
||||||
@ -113,21 +115,7 @@ namespace ssu
|
|||||||
void HandleTerminationTimer (const boost::system::error_code& ecode);
|
void HandleTerminationTimer (const boost::system::error_code& ecode);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
union IV
|
|
||||||
{
|
|
||||||
uint8_t buf[16];
|
|
||||||
uint64_t ll[2];
|
|
||||||
|
|
||||||
IV (const IV&) = default;
|
|
||||||
IV (const uint8_t * iv) { memcpy (buf, iv, 16); };
|
|
||||||
bool operator< (const IV& other) const
|
|
||||||
{
|
|
||||||
if (ll[0] != other.ll[0]) return ll[0] < other.ll[0];
|
|
||||||
return ll[1] < other.ll[1];
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
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;
|
||||||
@ -143,8 +131,8 @@ namespace ssu
|
|||||||
i2p::crypto::CBCDecryption m_SessionKeyDecryption;
|
i2p::crypto::CBCDecryption m_SessionKeyDecryption;
|
||||||
uint8_t m_SessionKey[32], m_MacKey[32];
|
uint8_t m_SessionKey[32], m_MacKey[32];
|
||||||
std::list<i2p::I2NPMessage *> m_DelayedMessages;
|
std::list<i2p::I2NPMessage *> m_DelayedMessages;
|
||||||
std::set<IV> m_ReceivedIVs;
|
|
||||||
SSUData m_Data;
|
SSUData m_Data;
|
||||||
|
size_t m_NumSentBytes, m_NumReceivedBytes;
|
||||||
};
|
};
|
||||||
|
|
||||||
class SSUServer
|
class SSUServer
|
||||||
|
306
SSUData.cpp
306
SSUData.cpp
@ -1,4 +1,7 @@
|
|||||||
|
#include <stdlib.h>
|
||||||
|
#include <boost/bind.hpp>
|
||||||
#include "Log.h"
|
#include "Log.h"
|
||||||
|
#include "Timestamp.h"
|
||||||
#include "SSU.h"
|
#include "SSU.h"
|
||||||
#include "SSUData.h"
|
#include "SSUData.h"
|
||||||
|
|
||||||
@ -7,7 +10,7 @@ namespace i2p
|
|||||||
namespace ssu
|
namespace ssu
|
||||||
{
|
{
|
||||||
SSUData::SSUData (SSUSession& session):
|
SSUData::SSUData (SSUSession& session):
|
||||||
m_Session (session)
|
m_Session (session), m_ResendTimer (session.m_Server.GetService ())
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -20,10 +23,7 @@ namespace ssu
|
|||||||
delete it.second;
|
delete it.second;
|
||||||
}
|
}
|
||||||
for (auto it: m_SentMessages)
|
for (auto it: m_SentMessages)
|
||||||
{
|
delete it.second;
|
||||||
for (auto f: it.second)
|
|
||||||
delete[] f;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SSUData::ProcessSentMessageAck (uint32_t msgID)
|
void SSUData::ProcessSentMessageAck (uint32_t msgID)
|
||||||
@ -31,19 +31,15 @@ namespace ssu
|
|||||||
auto it = m_SentMessages.find (msgID);
|
auto it = m_SentMessages.find (msgID);
|
||||||
if (it != m_SentMessages.end ())
|
if (it != m_SentMessages.end ())
|
||||||
{
|
{
|
||||||
// delete all ack-ed message's fragments
|
delete it->second;
|
||||||
for (auto f: it->second)
|
|
||||||
delete[] f;
|
|
||||||
m_SentMessages.erase (it);
|
m_SentMessages.erase (it);
|
||||||
|
if (m_SentMessages.empty ())
|
||||||
|
m_ResendTimer.cancel ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SSUData::ProcessMessage (uint8_t * buf, size_t len)
|
void SSUData::ProcessAcks (uint8_t *& buf, uint8_t flag)
|
||||||
{
|
{
|
||||||
//uint8_t * start = buf;
|
|
||||||
uint8_t flag = *buf;
|
|
||||||
buf++;
|
|
||||||
LogPrint ("Process SSU data flags=", (int)flag);
|
|
||||||
if (flag & DATA_FLAG_EXPLICIT_ACKS_INCLUDED)
|
if (flag & DATA_FLAG_EXPLICIT_ACKS_INCLUDED)
|
||||||
{
|
{
|
||||||
// explicit ACKs
|
// explicit ACKs
|
||||||
@ -60,13 +56,45 @@ namespace ssu
|
|||||||
buf++;
|
buf++;
|
||||||
for (int i = 0; i < numBitfields; i++)
|
for (int i = 0; i < numBitfields; i++)
|
||||||
{
|
{
|
||||||
|
uint32_t msgID = be32toh (*(uint32_t *)buf);
|
||||||
buf += 4; // msgID
|
buf += 4; // msgID
|
||||||
// TODO: process individual Ack bitfields
|
auto it = m_SentMessages.find (msgID);
|
||||||
while (*buf & 0x80) // not last
|
// process individual Ack bitfields
|
||||||
|
bool isNonLast = false;
|
||||||
|
int fragment = 0;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
uint8_t bitfield = *buf;
|
||||||
|
isNonLast = bitfield & 0x80;
|
||||||
|
bitfield &= 0x7F; // clear MSB
|
||||||
|
if (bitfield && it != m_SentMessages.end ())
|
||||||
|
{
|
||||||
|
int numSentFragments = it->second->fragments.size ();
|
||||||
|
// process bits
|
||||||
|
uint8_t mask = 0x40;
|
||||||
|
for (int j = 0; j < 7; j++)
|
||||||
|
{
|
||||||
|
if (bitfield & mask)
|
||||||
|
{
|
||||||
|
if (fragment < numSentFragments)
|
||||||
|
{
|
||||||
|
delete it->second->fragments[fragment];
|
||||||
|
it->second->fragments[fragment] = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fragment++;
|
||||||
|
mask >>= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
buf++;
|
buf++;
|
||||||
buf++; // last byte
|
}
|
||||||
|
while (isNonLast);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SSUData::ProcessFragments (uint8_t * buf)
|
||||||
|
{
|
||||||
uint8_t numFragments = *buf; // number of fragments
|
uint8_t numFragments = *buf; // number of fragments
|
||||||
buf++;
|
buf++;
|
||||||
for (int i = 0; i < numFragments; i++)
|
for (int i = 0; i < numFragments; i++)
|
||||||
@ -82,81 +110,140 @@ namespace ssu
|
|||||||
bool isLast = fragmentInfo & 0x010000; // bit 16
|
bool isLast = fragmentInfo & 0x010000; // bit 16
|
||||||
uint8_t fragmentNum = fragmentInfo >> 17; // bits 23 - 17
|
uint8_t fragmentNum = fragmentInfo >> 17; // bits 23 - 17
|
||||||
LogPrint ("SSU data fragment ", (int)fragmentNum, " of message ", msgID, " size=", (int)fragmentSize, isLast ? " last" : " non-last");
|
LogPrint ("SSU data fragment ", (int)fragmentNum, " of message ", msgID, " size=", (int)fragmentSize, isLast ? " last" : " non-last");
|
||||||
I2NPMessage * msg = nullptr;
|
|
||||||
if (fragmentNum > 0) // follow-up fragment
|
|
||||||
{
|
|
||||||
auto it = m_IncomleteMessages.find (msgID);
|
|
||||||
if (it != m_IncomleteMessages.end ())
|
|
||||||
{
|
|
||||||
if (fragmentNum == it->second->nextFragmentNum)
|
|
||||||
{
|
|
||||||
// expected fragment
|
|
||||||
msg = it->second->msg;
|
|
||||||
memcpy (msg->buf + msg->len, buf, fragmentSize);
|
|
||||||
msg->len += fragmentSize;
|
|
||||||
it->second->nextFragmentNum++;
|
|
||||||
}
|
|
||||||
else if (fragmentNum < it->second->nextFragmentNum)
|
|
||||||
// duplicate fragment
|
|
||||||
LogPrint ("Duplicate fragment ", fragmentNum, " of message ", msgID, ". Ignored");
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// missing fragment
|
|
||||||
LogPrint ("Missing fragments from ", it->second->nextFragmentNum, " to ", fragmentNum - 1, " of message ", msgID);
|
|
||||||
//TODO
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isLast)
|
|
||||||
{
|
|
||||||
if (!msg)
|
|
||||||
DeleteI2NPMessage (it->second->msg);
|
|
||||||
delete it->second;
|
|
||||||
m_IncomleteMessages.erase (it);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
// TODO:
|
|
||||||
LogPrint ("Unexpected follow-on fragment ", fragmentNum, " of message ", msgID);
|
|
||||||
}
|
|
||||||
else // first fragment
|
|
||||||
{
|
|
||||||
msg = NewI2NPMessage ();
|
|
||||||
memcpy (msg->GetSSUHeader (), buf, fragmentSize);
|
|
||||||
msg->len += fragmentSize - sizeof (I2NPHeaderShort);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (msg)
|
// find message with msgID
|
||||||
{
|
I2NPMessage * msg = nullptr;
|
||||||
if (!fragmentNum && !isLast)
|
IncompleteMessage * incompleteMessage = nullptr;
|
||||||
m_IncomleteMessages[msgID] = new IncompleteMessage (msg);
|
auto it = m_IncomleteMessages.find (msgID);
|
||||||
if (isLast)
|
if (it != m_IncomleteMessages.end ())
|
||||||
|
{
|
||||||
|
// message exists
|
||||||
|
incompleteMessage = it->second;
|
||||||
|
msg = incompleteMessage->msg;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// create new message
|
||||||
|
msg = NewI2NPMessage ();
|
||||||
|
msg->len -= sizeof (I2NPHeaderShort);
|
||||||
|
incompleteMessage = new IncompleteMessage (msg);
|
||||||
|
m_IncomleteMessages[msgID] = incompleteMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
// handle current fragment
|
||||||
|
if (fragmentNum == incompleteMessage->nextFragmentNum)
|
||||||
|
{
|
||||||
|
// expected fragment
|
||||||
|
memcpy (msg->buf + msg->len, buf, fragmentSize);
|
||||||
|
msg->len += fragmentSize;
|
||||||
|
incompleteMessage->nextFragmentNum++;
|
||||||
|
if (!isLast && !incompleteMessage->savedFragments.empty ())
|
||||||
{
|
{
|
||||||
SendMsgAck (msgID);
|
// try saved fragments
|
||||||
msg->FromSSU (msgID);
|
for (auto it1 = incompleteMessage->savedFragments.begin (); it1 != incompleteMessage->savedFragments.end ();)
|
||||||
if (m_Session.GetState () == eSessionStateEstablished)
|
|
||||||
i2p::HandleI2NPMessage (msg);
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
// we expect DeliveryStatus
|
auto savedFragment = *it1;
|
||||||
if (msg->GetHeader ()->typeID == eI2NPDeliveryStatus)
|
if (savedFragment->fragmentNum == incompleteMessage->nextFragmentNum)
|
||||||
{
|
{
|
||||||
LogPrint ("SSU session established");
|
memcpy (msg->buf + msg->len, savedFragment->buf, savedFragment->len);
|
||||||
m_Session.Established ();
|
msg->len += savedFragment->len;
|
||||||
}
|
isLast = savedFragment->isLast;
|
||||||
|
incompleteMessage->nextFragmentNum++;
|
||||||
|
incompleteMessage->savedFragments.erase (it1++);
|
||||||
|
delete savedFragment;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
LogPrint ("SSU unexpected message ", (int)msg->GetHeader ()->typeID);
|
break;
|
||||||
DeleteI2NPMessage (msg);
|
}
|
||||||
|
if (isLast)
|
||||||
|
LogPrint ("Message ", msgID, " complete");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (fragmentNum < incompleteMessage->nextFragmentNum)
|
||||||
|
// duplicate fragment
|
||||||
|
LogPrint ("Duplicate fragment ", (int)fragmentNum, " of message ", msgID, ". Ignored");
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// missing fragment
|
||||||
|
LogPrint ("Missing fragments from ", (int)incompleteMessage->nextFragmentNum, " to ", fragmentNum - 1, " of message ", msgID);
|
||||||
|
auto savedFragment = new Fragment (fragmentNum, buf, fragmentSize, isLast);
|
||||||
|
if (!incompleteMessage->savedFragments.insert (savedFragment).second)
|
||||||
|
{
|
||||||
|
LogPrint ("Fragment ", (int)fragmentNum, " of message ", msgID, " already saved");
|
||||||
|
delete savedFragment;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
isLast = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isLast)
|
||||||
|
{
|
||||||
|
// delete incomplete message
|
||||||
|
delete incompleteMessage;
|
||||||
|
m_IncomleteMessages.erase (msgID);
|
||||||
|
// process message
|
||||||
|
SendMsgAck (msgID);
|
||||||
|
msg->FromSSU (msgID);
|
||||||
|
if (m_Session.GetState () == eSessionStateEstablished)
|
||||||
|
i2p::HandleI2NPMessage (msg);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// we expect DeliveryStatus
|
||||||
|
if (msg->GetHeader ()->typeID == eI2NPDeliveryStatus)
|
||||||
|
{
|
||||||
|
LogPrint ("SSU session established");
|
||||||
|
m_Session.Established ();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
LogPrint ("SSU unexpected message ", (int)msg->GetHeader ()->typeID);
|
||||||
|
DeleteI2NPMessage (msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
SendFragmentAck (msgID, fragmentNum);
|
||||||
buf += fragmentSize;
|
buf += fragmentSize;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SSUData::ProcessMessage (uint8_t * buf, size_t len)
|
||||||
|
{
|
||||||
|
//uint8_t * start = buf;
|
||||||
|
uint8_t flag = *buf;
|
||||||
|
buf++;
|
||||||
|
LogPrint ("Process SSU data flags=", (int)flag);
|
||||||
|
// process acks if presented
|
||||||
|
if (flag & (DATA_FLAG_ACK_BITFIELDS_INCLUDED | DATA_FLAG_EXPLICIT_ACKS_INCLUDED))
|
||||||
|
ProcessAcks (buf, flag);
|
||||||
|
// extended data if presented
|
||||||
|
if (flag & DATA_FLAG_EXTENDED_DATA_INCLUDED)
|
||||||
|
{
|
||||||
|
uint8_t extendedDataSize = *buf;
|
||||||
|
buf++; // size
|
||||||
|
LogPrint ("SSU extended data of ", extendedDataSize, " bytes presented");
|
||||||
|
buf += extendedDataSize;
|
||||||
|
}
|
||||||
|
// process data
|
||||||
|
ProcessFragments (buf);
|
||||||
|
}
|
||||||
|
|
||||||
void SSUData::Send (i2p::I2NPMessage * msg)
|
void SSUData::Send (i2p::I2NPMessage * msg)
|
||||||
{
|
{
|
||||||
uint32_t msgID = msg->ToSSU ();
|
uint32_t msgID = msg->ToSSU ();
|
||||||
auto fragments = m_SentMessages[msgID];
|
if (m_SentMessages.count (msgID) > 0)
|
||||||
|
{
|
||||||
|
LogPrint ("SSU message ", msgID, " already sent");
|
||||||
|
DeleteI2NPMessage (msg);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (m_SentMessages.empty ()) // schedule resend at first message only
|
||||||
|
ScheduleResend ();
|
||||||
|
SentMessage * sentMessage = new SentMessage;
|
||||||
|
m_SentMessages[msgID] = sentMessage;
|
||||||
|
sentMessage->nextResendTime = i2p::util::GetSecondsSinceEpoch () + RESEND_INTERVAL;
|
||||||
|
sentMessage->numResends = 0;
|
||||||
|
auto& fragments = sentMessage->fragments;
|
||||||
msgID = htobe32 (msgID);
|
msgID = htobe32 (msgID);
|
||||||
size_t payloadSize = SSU_MTU - sizeof (SSUHeader) - 9; // 9 = flag + #frg(1) + messageID(4) + frag info (3)
|
size_t payloadSize = SSU_MTU - sizeof (SSUHeader) - 9; // 9 = flag + #frg(1) + messageID(4) + frag info (3)
|
||||||
size_t len = msg->GetLength ();
|
size_t len = msg->GetLength ();
|
||||||
@ -165,8 +252,9 @@ namespace ssu
|
|||||||
uint32_t fragmentNum = 0;
|
uint32_t fragmentNum = 0;
|
||||||
while (len > 0)
|
while (len > 0)
|
||||||
{
|
{
|
||||||
uint8_t * buf = new uint8_t[SSU_MTU + 18];
|
Fragment * fragment = new Fragment;
|
||||||
fragments.push_back (buf);
|
uint8_t * buf = fragment->buf;
|
||||||
|
fragments.push_back (fragment);
|
||||||
uint8_t * payload = buf + sizeof (SSUHeader);
|
uint8_t * payload = buf + sizeof (SSUHeader);
|
||||||
*payload = DATA_FLAG_WANT_REPLY; // for compatibility
|
*payload = DATA_FLAG_WANT_REPLY; // for compatibility
|
||||||
payload++;
|
payload++;
|
||||||
@ -189,6 +277,7 @@ namespace ssu
|
|||||||
size += payload - buf;
|
size += payload - buf;
|
||||||
if (size & 0x0F) // make sure 16 bytes boundary
|
if (size & 0x0F) // make sure 16 bytes boundary
|
||||||
size = ((size >> 4) + 1) << 4; // (/16 + 1)*16
|
size = ((size >> 4) + 1) << 4; // (/16 + 1)*16
|
||||||
|
fragment->len = size;
|
||||||
|
|
||||||
// encrypt message with session key
|
// encrypt message with session key
|
||||||
m_Session.FillHeaderAndEncrypt (PAYLOAD_TYPE_DATA, buf, size);
|
m_Session.FillHeaderAndEncrypt (PAYLOAD_TYPE_DATA, buf, size);
|
||||||
@ -222,6 +311,63 @@ namespace ssu
|
|||||||
m_Session.FillHeaderAndEncrypt (PAYLOAD_TYPE_DATA, buf, 48);
|
m_Session.FillHeaderAndEncrypt (PAYLOAD_TYPE_DATA, buf, 48);
|
||||||
m_Session.Send (buf, 48);
|
m_Session.Send (buf, 48);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SSUData::SendFragmentAck (uint32_t msgID, int fragmentNum)
|
||||||
|
{
|
||||||
|
if (fragmentNum > 64)
|
||||||
|
{
|
||||||
|
LogPrint ("Fragment number ", fragmentNum, " exceeds 64");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
uint8_t buf[64 + 18];
|
||||||
|
uint8_t * payload = buf + sizeof (SSUHeader);
|
||||||
|
*payload = DATA_FLAG_ACK_BITFIELDS_INCLUDED; // flag
|
||||||
|
payload++;
|
||||||
|
*payload = 1; // number of ACK bitfields
|
||||||
|
payload++;
|
||||||
|
// one ack
|
||||||
|
*(uint32_t *)(payload) = htobe32 (msgID); // msgID
|
||||||
|
payload += 4;
|
||||||
|
div_t d = div (fragmentNum, 7);
|
||||||
|
memset (payload, 0x80, d.quot); // 0x80 means non-last
|
||||||
|
payload += d.quot;
|
||||||
|
*payload = 0x40 >> d.rem; // set corresponding bit
|
||||||
|
payload++;
|
||||||
|
*payload = 0; // number of fragments
|
||||||
|
|
||||||
|
size_t len = d.quot < 4 ? 48 : 64; // 48 = 37 + 7 + 4 (3+1)
|
||||||
|
// encrypt message with session key
|
||||||
|
m_Session.FillHeaderAndEncrypt (PAYLOAD_TYPE_DATA, buf, len);
|
||||||
|
m_Session.Send (buf, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SSUData::ScheduleResend()
|
||||||
|
{
|
||||||
|
m_ResendTimer.cancel ();
|
||||||
|
m_ResendTimer.expires_from_now (boost::posix_time::seconds(RESEND_INTERVAL));
|
||||||
|
m_ResendTimer.async_wait (boost::bind (&SSUData::HandleResendTimer,
|
||||||
|
this, boost::asio::placeholders::error));
|
||||||
|
}
|
||||||
|
|
||||||
|
void SSUData::HandleResendTimer (const boost::system::error_code& ecode)
|
||||||
|
{
|
||||||
|
if (ecode != boost::asio::error::operation_aborted)
|
||||||
|
{
|
||||||
|
uint32_t ts = i2p::util::GetSecondsSinceEpoch ();
|
||||||
|
for (auto it : m_SentMessages)
|
||||||
|
{
|
||||||
|
if (ts >= it.second->nextResendTime && it.second->numResends < MAX_NUM_RESENDS)
|
||||||
|
{
|
||||||
|
for (auto f: it.second->fragments)
|
||||||
|
if (f) m_Session.Send (f->buf, f->len); // resend
|
||||||
|
|
||||||
|
it.second->numResends++;
|
||||||
|
it.second->nextResendTime += it.second->numResends*RESEND_INTERVAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ScheduleResend ();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
66
SSUData.h
66
SSUData.h
@ -2,8 +2,11 @@
|
|||||||
#define SSU_DATA_H__
|
#define SSU_DATA_H__
|
||||||
|
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
|
#include <string.h>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <set>
|
||||||
|
#include <boost/asio.hpp>
|
||||||
#include "I2NPProtocol.h"
|
#include "I2NPProtocol.h"
|
||||||
|
|
||||||
namespace i2p
|
namespace i2p
|
||||||
@ -11,6 +14,9 @@ namespace i2p
|
|||||||
namespace ssu
|
namespace ssu
|
||||||
{
|
{
|
||||||
|
|
||||||
|
const size_t SSU_MTU = 1484;
|
||||||
|
const int RESEND_INTERVAL = 3; // in seconds
|
||||||
|
const int MAX_NUM_RESENDS = 5;
|
||||||
// data flags
|
// data flags
|
||||||
const uint8_t DATA_FLAG_EXTENDED_DATA_INCLUDED = 0x02;
|
const uint8_t DATA_FLAG_EXTENDED_DATA_INCLUDED = 0x02;
|
||||||
const uint8_t DATA_FLAG_WANT_REPLY = 0x04;
|
const uint8_t DATA_FLAG_WANT_REPLY = 0x04;
|
||||||
@ -19,6 +25,45 @@ namespace ssu
|
|||||||
const uint8_t DATA_FLAG_ACK_BITFIELDS_INCLUDED = 0x40;
|
const uint8_t DATA_FLAG_ACK_BITFIELDS_INCLUDED = 0x40;
|
||||||
const uint8_t DATA_FLAG_EXPLICIT_ACKS_INCLUDED = 0x80;
|
const uint8_t DATA_FLAG_EXPLICIT_ACKS_INCLUDED = 0x80;
|
||||||
|
|
||||||
|
struct Fragment
|
||||||
|
{
|
||||||
|
int fragmentNum;
|
||||||
|
size_t len;
|
||||||
|
bool isLast;
|
||||||
|
uint8_t buf[SSU_MTU + 18];
|
||||||
|
|
||||||
|
Fragment () = default;
|
||||||
|
Fragment (int n, const uint8_t * b, int l, bool last):
|
||||||
|
fragmentNum (n), len (l), isLast (last) { memcpy (buf, b, len); };
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FragmentCmp
|
||||||
|
{
|
||||||
|
bool operator() (const Fragment * f1, const Fragment * f2) const
|
||||||
|
{
|
||||||
|
return f1->fragmentNum < f2->fragmentNum;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct IncompleteMessage
|
||||||
|
{
|
||||||
|
I2NPMessage * msg;
|
||||||
|
int nextFragmentNum;
|
||||||
|
std::set<Fragment *, FragmentCmp> savedFragments;
|
||||||
|
|
||||||
|
IncompleteMessage (I2NPMessage * m): msg (m), nextFragmentNum (0) {};
|
||||||
|
~IncompleteMessage () { for (auto it: savedFragments) { delete it; }; };
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SentMessage
|
||||||
|
{
|
||||||
|
std::vector<Fragment *> fragments;
|
||||||
|
uint32_t nextResendTime; // in seconds
|
||||||
|
int numResends;
|
||||||
|
|
||||||
|
~SentMessage () { for (auto it: fragments) { delete it; }; };
|
||||||
|
};
|
||||||
|
|
||||||
class SSUSession;
|
class SSUSession;
|
||||||
class SSUData
|
class SSUData
|
||||||
{
|
{
|
||||||
@ -33,21 +78,20 @@ namespace ssu
|
|||||||
private:
|
private:
|
||||||
|
|
||||||
void SendMsgAck (uint32_t msgID);
|
void SendMsgAck (uint32_t msgID);
|
||||||
void ProcessSentMessageAck (uint32_t msgID);
|
void SendFragmentAck (uint32_t msgID, int fragmentNum);
|
||||||
|
void ProcessAcks (uint8_t *& buf, uint8_t flag);
|
||||||
|
void ProcessFragments (uint8_t * buf);
|
||||||
|
void ProcessSentMessageAck (uint32_t msgID);
|
||||||
|
|
||||||
private:
|
void ScheduleResend ();
|
||||||
|
void HandleResendTimer (const boost::system::error_code& ecode);
|
||||||
struct IncompleteMessage
|
|
||||||
{
|
private:
|
||||||
I2NPMessage * msg;
|
|
||||||
uint8_t nextFragmentNum;
|
|
||||||
|
|
||||||
IncompleteMessage (I2NPMessage * m): msg (m), nextFragmentNum (1) {};
|
|
||||||
};
|
|
||||||
|
|
||||||
SSUSession& m_Session;
|
SSUSession& m_Session;
|
||||||
std::map<uint32_t, IncompleteMessage *> m_IncomleteMessages;
|
std::map<uint32_t, IncompleteMessage *> m_IncomleteMessages;
|
||||||
std::map<uint32_t, std::vector<uint8_t *> > m_SentMessages; // msgID -> fragments
|
std::map<uint32_t, SentMessage *> m_SentMessages;
|
||||||
|
boost::asio::deadline_timer m_ResendTimer;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
345
Streaming.cpp
345
Streaming.cpp
@ -2,6 +2,7 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cryptopp/dh.h>
|
#include <cryptopp/dh.h>
|
||||||
#include <cryptopp/gzip.h>
|
#include <cryptopp/gzip.h>
|
||||||
|
#include "util.h"
|
||||||
#include "Log.h"
|
#include "Log.h"
|
||||||
#include "RouterInfo.h"
|
#include "RouterInfo.h"
|
||||||
#include "RouterContext.h"
|
#include "RouterContext.h"
|
||||||
@ -9,6 +10,7 @@
|
|||||||
#include "Timestamp.h"
|
#include "Timestamp.h"
|
||||||
#include "CryptoConst.h"
|
#include "CryptoConst.h"
|
||||||
#include "Garlic.h"
|
#include "Garlic.h"
|
||||||
|
#include "NetDb.h"
|
||||||
#include "Streaming.h"
|
#include "Streaming.h"
|
||||||
|
|
||||||
namespace i2p
|
namespace i2p
|
||||||
@ -17,14 +19,22 @@ 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): m_Service (service), m_SendStreamID (0),
|
||||||
m_SequenceNumber (0), m_LastReceivedSequenceNumber (0), m_IsOpen (false),
|
m_SequenceNumber (0), m_LastReceivedSequenceNumber (-1), m_IsOpen (false),
|
||||||
m_LeaseSetUpdated (true), m_LocalDestination (local), m_RemoteLeaseSet (remote),
|
m_IsOutgoing(true), m_LeaseSetUpdated (true), m_LocalDestination (local),
|
||||||
m_OutboundTunnel (nullptr), m_ReceiveTimer (m_Service)
|
m_RemoteLeaseSet (&remote), m_ReceiveTimer (m_Service)
|
||||||
{
|
{
|
||||||
m_RecvStreamID = i2p::context.GetRandomNumberGenerator ().GenerateWord32 ();
|
m_RecvStreamID = i2p::context.GetRandomNumberGenerator ().GenerateWord32 ();
|
||||||
UpdateCurrentRemoteLease ();
|
UpdateCurrentRemoteLease ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Stream::Stream (boost::asio::io_service& service, StreamingDestination * local):
|
||||||
|
m_Service (service), m_SendStreamID (0), m_SequenceNumber (0), m_LastReceivedSequenceNumber (-1),
|
||||||
|
m_IsOpen (false), m_IsOutgoing(true), m_LeaseSetUpdated (true), m_LocalDestination (local),
|
||||||
|
m_RemoteLeaseSet (nullptr), m_ReceiveTimer (m_Service)
|
||||||
|
{
|
||||||
|
m_RecvStreamID = i2p::context.GetRandomNumberGenerator ().GenerateWord32 ();
|
||||||
|
}
|
||||||
|
|
||||||
Stream::~Stream ()
|
Stream::~Stream ()
|
||||||
{
|
{
|
||||||
m_ReceiveTimer.cancel ();
|
m_ReceiveTimer.cancel ();
|
||||||
@ -40,20 +50,29 @@ namespace stream
|
|||||||
|
|
||||||
void Stream::HandleNextPacket (Packet * packet)
|
void Stream::HandleNextPacket (Packet * packet)
|
||||||
{
|
{
|
||||||
if (!m_SendStreamID)
|
if (!m_SendStreamID)
|
||||||
m_SendStreamID = packet->GetReceiveStreamID ();
|
m_SendStreamID = packet->GetReceiveStreamID ();
|
||||||
|
|
||||||
uint32_t receivedSeqn = packet->GetSeqn ();
|
int32_t receivedSeqn = packet->GetSeqn ();
|
||||||
|
bool isSyn = packet->IsSYN ();
|
||||||
|
if (!receivedSeqn && !isSyn)
|
||||||
|
{
|
||||||
|
// plain ack
|
||||||
|
LogPrint ("Plain ACK received");
|
||||||
|
delete packet;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
LogPrint ("Received seqn=", receivedSeqn);
|
LogPrint ("Received seqn=", receivedSeqn);
|
||||||
if (!receivedSeqn || receivedSeqn == m_LastReceivedSequenceNumber + 1)
|
if (isSyn || receivedSeqn == m_LastReceivedSequenceNumber + 1)
|
||||||
{
|
{
|
||||||
// we have received next in sequence message
|
// we have received next in sequence message
|
||||||
ProcessPacket (packet);
|
ProcessPacket (packet);
|
||||||
|
|
||||||
// we should also try stored messages if any
|
// we should also try stored messages if any
|
||||||
for (auto it = m_SavedPackets.begin (); it != m_SavedPackets.end ();)
|
for (auto it = m_SavedPackets.begin (); it != m_SavedPackets.end ();)
|
||||||
{
|
{
|
||||||
if ((*it)->GetSeqn () == m_LastReceivedSequenceNumber + 1)
|
if ((*it)->GetSeqn () == (uint32_t)(m_LastReceivedSequenceNumber + 1))
|
||||||
{
|
{
|
||||||
Packet * savedPacket = *it;
|
Packet * savedPacket = *it;
|
||||||
m_SavedPackets.erase (it++);
|
m_SavedPackets.erase (it++);
|
||||||
@ -66,7 +85,14 @@ namespace stream
|
|||||||
|
|
||||||
// send ack for last message
|
// send ack for last message
|
||||||
if (m_IsOpen)
|
if (m_IsOpen)
|
||||||
SendQuickAck ();
|
SendQuickAck ();
|
||||||
|
else if (isSyn)
|
||||||
|
{
|
||||||
|
// we have to send SYN back to incoming connection
|
||||||
|
m_IsOpen = true;
|
||||||
|
SendQuickAck (true);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -75,9 +101,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");
|
||||||
UpdateCurrentRemoteLease (); // pick another lease
|
UpdateCurrentRemoteLease (); // pick another lease
|
||||||
m_OutboundTunnel = i2p::tunnel::tunnels.GetNextOutboundTunnel (); // pick another tunnel
|
SendQuickAck (); // resend ack for previous message again
|
||||||
if (m_OutboundTunnel)
|
|
||||||
SendQuickAck (); // resend ack for previous message again
|
|
||||||
delete packet; // packet dropped
|
delete packet; // packet dropped
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -106,6 +130,26 @@ namespace stream
|
|||||||
{
|
{
|
||||||
LogPrint ("Synchronize");
|
LogPrint ("Synchronize");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (flags & PACKET_FLAG_DELAY_REQUESTED)
|
||||||
|
{
|
||||||
|
optionData += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flags & PACKET_FLAG_FROM_INCLUDED)
|
||||||
|
{
|
||||||
|
optionData += m_RemoteIdentity.FromBuffer (optionData, i2p::data::DEFAULT_IDENTITY_SIZE);
|
||||||
|
LogPrint ("From identity ", m_RemoteIdentity.Hash ().ToBase64 ());
|
||||||
|
if (!m_RemoteLeaseSet)
|
||||||
|
LogPrint ("Incoming stream from ", m_RemoteIdentity.Hash ().ToBase64 ());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flags & PACKET_FLAG_MAX_PACKET_SIZE_INCLUDED)
|
||||||
|
{
|
||||||
|
uint16_t maxPacketSize = be16toh (*(uint16_t *)optionData);
|
||||||
|
LogPrint ("Max packet size ", maxPacketSize);
|
||||||
|
optionData += 2;
|
||||||
|
}
|
||||||
|
|
||||||
if (flags & PACKET_FLAG_SIGNATURE_INCLUDED)
|
if (flags & PACKET_FLAG_SIGNATURE_INCLUDED)
|
||||||
{
|
{
|
||||||
@ -113,12 +157,6 @@ namespace stream
|
|||||||
optionData += 40;
|
optionData += 40;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flags & PACKET_FLAG_FROM_INCLUDED)
|
|
||||||
{
|
|
||||||
LogPrint ("From identity");
|
|
||||||
optionData += sizeof (i2p::data::Identity);
|
|
||||||
}
|
|
||||||
|
|
||||||
packet->offset = packet->GetPayload () - packet->buf;
|
packet->offset = packet->GetPayload () - packet->buf;
|
||||||
if (packet->GetLength () > 0)
|
if (packet->GetLength () > 0)
|
||||||
{
|
{
|
||||||
@ -135,6 +173,7 @@ namespace stream
|
|||||||
LogPrint ("Closed");
|
LogPrint ("Closed");
|
||||||
SendQuickAck (); // send ack for close explicitly?
|
SendQuickAck (); // send ack for close explicitly?
|
||||||
m_IsOpen = false;
|
m_IsOpen = false;
|
||||||
|
m_ReceiveTimer.cancel ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -163,10 +202,10 @@ namespace stream
|
|||||||
PACKET_FLAG_FROM_INCLUDED | PACKET_FLAG_SIGNATURE_INCLUDED |
|
PACKET_FLAG_FROM_INCLUDED | PACKET_FLAG_SIGNATURE_INCLUDED |
|
||||||
PACKET_FLAG_MAX_PACKET_SIZE_INCLUDED | PACKET_FLAG_NO_ACK);
|
PACKET_FLAG_MAX_PACKET_SIZE_INCLUDED | PACKET_FLAG_NO_ACK);
|
||||||
size += 2; // flags
|
size += 2; // flags
|
||||||
*(uint16_t *)(packet + size) = htobe16 (sizeof (i2p::data::Identity) + 40 + 2); // identity + signature + packet size
|
*(uint16_t *)(packet + size) = htobe16 (i2p::data::DEFAULT_IDENTITY_SIZE + 40 + 2); // identity + signature + packet size
|
||||||
size += 2; // options size
|
size += 2; // options size
|
||||||
memcpy (packet + size, &m_LocalDestination->GetIdentity (), sizeof (i2p::data::Identity));
|
memcpy (packet + size, &m_LocalDestination->GetIdentity (), i2p::data::DEFAULT_IDENTITY_SIZE);
|
||||||
size += sizeof (i2p::data::Identity); // from
|
size += i2p::data::DEFAULT_IDENTITY_SIZE; // 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
|
||||||
uint8_t * signature = packet + size; // set it later
|
uint8_t * signature = packet + size; // set it later
|
||||||
@ -193,7 +232,7 @@ namespace stream
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Stream::SendQuickAck ()
|
void Stream::SendQuickAck (bool syn)
|
||||||
{
|
{
|
||||||
uint8_t packet[MAX_PACKET_SIZE];
|
uint8_t packet[MAX_PACKET_SIZE];
|
||||||
size_t size = 0;
|
size_t size = 0;
|
||||||
@ -208,7 +247,7 @@ namespace stream
|
|||||||
packet[size] = 0;
|
packet[size] = 0;
|
||||||
size++; // NACK count
|
size++; // NACK count
|
||||||
size++; // resend delay
|
size++; // resend delay
|
||||||
*(uint16_t *)(packet + size) = 0; // nof flags set
|
*(uint16_t *)(packet + size) = syn ? htobe16 (PACKET_FLAG_SYNCHRONIZE) : 0; // nof flags set
|
||||||
size += 2; // flags
|
size += 2; // flags
|
||||||
*(uint16_t *)(packet + size) = 0; // no options
|
*(uint16_t *)(packet + size) = 0; // no options
|
||||||
size += 2; // options size
|
size += 2; // options size
|
||||||
@ -222,7 +261,8 @@ namespace stream
|
|||||||
if (m_IsOpen)
|
if (m_IsOpen)
|
||||||
{
|
{
|
||||||
m_IsOpen = false;
|
m_IsOpen = false;
|
||||||
uint8_t packet[MAX_PACKET_SIZE];
|
Packet * p = new Packet ();
|
||||||
|
uint8_t * packet = p->GetBuffer ();
|
||||||
size_t size = 0;
|
size_t size = 0;
|
||||||
*(uint32_t *)(packet + size) = htobe32 (m_SendStreamID);
|
*(uint32_t *)(packet + size) = htobe32 (m_SendStreamID);
|
||||||
size += 4; // sendStreamID
|
size += 4; // sendStreamID
|
||||||
@ -235,7 +275,7 @@ namespace stream
|
|||||||
packet[size] = 0;
|
packet[size] = 0;
|
||||||
size++; // NACK count
|
size++; // NACK count
|
||||||
size++; // resend delay
|
size++; // resend delay
|
||||||
*(uint16_t *)(packet + size) = 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
|
||||||
*(uint16_t *)(packet + size) = htobe16 (40); // 40 bytes signature
|
*(uint16_t *)(packet + size) = htobe16 (40); // 40 bytes signature
|
||||||
size += 2; // options size
|
size += 2; // options size
|
||||||
@ -244,8 +284,9 @@ namespace stream
|
|||||||
size += 40; // signature
|
size += 40; // signature
|
||||||
m_LocalDestination->Sign (packet, size, signature);
|
m_LocalDestination->Sign (packet, size, signature);
|
||||||
|
|
||||||
if (SendPacket (packet, size))
|
p->len = size;
|
||||||
LogPrint ("FIN sent");
|
m_Service.post (boost::bind (&Stream::SendPacket, this, p));
|
||||||
|
LogPrint ("FIN sent");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -281,27 +322,36 @@ namespace stream
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool Stream::SendPacket (const uint8_t * buf, size_t len)
|
bool Stream::SendPacket (const uint8_t * buf, size_t len)
|
||||||
{
|
{
|
||||||
const I2NPMessage * leaseSet = nullptr;
|
if (!m_RemoteLeaseSet)
|
||||||
|
{
|
||||||
|
UpdateCurrentRemoteLease ();
|
||||||
|
if (!m_RemoteLeaseSet)
|
||||||
|
{
|
||||||
|
LogPrint ("Can't send packet. Missing remote LeaseSet");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
I2NPMessage * leaseSet = nullptr;
|
||||||
|
|
||||||
if (m_LeaseSetUpdated)
|
if (m_LeaseSetUpdated)
|
||||||
{
|
{
|
||||||
leaseSet = m_LocalDestination->GetLeaseSet ();
|
leaseSet = m_LocalDestination->GetLeaseSetMsg ();
|
||||||
m_LeaseSetUpdated = false;
|
m_LeaseSetUpdated = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
I2NPMessage * msg = i2p::garlic::routing.WrapMessage (m_RemoteLeaseSet,
|
I2NPMessage * msg = i2p::garlic::routing.WrapMessage (*m_RemoteLeaseSet,
|
||||||
CreateDataMessage (this, buf, len), leaseSet);
|
CreateDataMessage (this, buf, len), leaseSet);
|
||||||
if (!m_OutboundTunnel || m_OutboundTunnel->IsFailed ())
|
auto outboundTunnel = m_LocalDestination->GetTunnelPool ()->GetNextOutboundTunnel ();
|
||||||
m_OutboundTunnel = m_LocalDestination->GetTunnelPool ()->GetNextOutboundTunnel ();
|
if (outboundTunnel)
|
||||||
if (m_OutboundTunnel)
|
|
||||||
{
|
{
|
||||||
auto ts = i2p::util::GetMillisecondsSinceEpoch ();
|
auto ts = i2p::util::GetMillisecondsSinceEpoch ();
|
||||||
if (ts >= m_CurrentRemoteLease.endDate)
|
if (ts >= m_CurrentRemoteLease.endDate)
|
||||||
UpdateCurrentRemoteLease ();
|
UpdateCurrentRemoteLease ();
|
||||||
if (ts < m_CurrentRemoteLease.endDate)
|
if (ts < m_CurrentRemoteLease.endDate)
|
||||||
{
|
{
|
||||||
m_OutboundTunnel->SendTunnelDataMsg (m_CurrentRemoteLease.tunnelGateway, m_CurrentRemoteLease.tunnelID, msg);
|
outboundTunnel->SendTunnelDataMsg (m_CurrentRemoteLease.tunnelGateway, m_CurrentRemoteLease.tunnelID, msg);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -320,18 +370,30 @@ namespace stream
|
|||||||
|
|
||||||
void Stream::UpdateCurrentRemoteLease ()
|
void Stream::UpdateCurrentRemoteLease ()
|
||||||
{
|
{
|
||||||
auto leases = m_RemoteLeaseSet.GetNonExpiredLeases ();
|
if (!m_RemoteLeaseSet)
|
||||||
if (!leases.empty ())
|
{
|
||||||
{
|
m_RemoteLeaseSet = i2p::data::netdb.FindLeaseSet (m_RemoteIdentity.Hash ());
|
||||||
uint32_t i = i2p::context.GetRandomNumberGenerator ().GenerateWord32 (0, leases.size () - 1);
|
if (!m_RemoteLeaseSet)
|
||||||
m_CurrentRemoteLease = leases[i];
|
LogPrint ("LeaseSet ", m_RemoteIdentity.Hash ().ToBase64 (), " not found");
|
||||||
}
|
}
|
||||||
|
if (m_RemoteLeaseSet)
|
||||||
|
{
|
||||||
|
auto leases = m_RemoteLeaseSet->GetNonExpiredLeases ();
|
||||||
|
if (!leases.empty ())
|
||||||
|
{
|
||||||
|
uint32_t i = i2p::context.GetRandomNumberGenerator ().GenerateWord32 (0, leases.size () - 1);
|
||||||
|
m_CurrentRemoteLease = leases[i];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
m_CurrentRemoteLease.endDate = 0;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
m_CurrentRemoteLease.endDate = 0;
|
m_CurrentRemoteLease.endDate = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
StreamingDestination::StreamingDestination (): m_LeaseSet (nullptr)
|
StreamingDestination::StreamingDestination (boost::asio::io_service& service):
|
||||||
|
m_Service (service), m_LeaseSet (nullptr)
|
||||||
{
|
{
|
||||||
m_Keys = i2p::data::CreateRandomKeys ();
|
m_Keys = i2p::data::CreateRandomKeys ();
|
||||||
|
|
||||||
@ -343,7 +405,8 @@ namespace stream
|
|||||||
m_Pool = i2p::tunnel::tunnels.CreateTunnelPool (*this, 3); // 3-hops tunnel
|
m_Pool = i2p::tunnel::tunnels.CreateTunnelPool (*this, 3); // 3-hops tunnel
|
||||||
}
|
}
|
||||||
|
|
||||||
StreamingDestination::StreamingDestination (const std::string& fullPath): m_LeaseSet (nullptr)
|
StreamingDestination::StreamingDestination (boost::asio::io_service& service, const std::string& fullPath):
|
||||||
|
m_Service (service), m_LeaseSet (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 ())
|
||||||
@ -356,38 +419,53 @@ namespace stream
|
|||||||
CryptoPP::Integer (m_Keys.signingPrivateKey, 20));
|
CryptoPP::Integer (m_Keys.signingPrivateKey, 20));
|
||||||
CryptoPP::DH dh (i2p::crypto::elgp, i2p::crypto::elgg);
|
CryptoPP::DH dh (i2p::crypto::elgp, i2p::crypto::elgg);
|
||||||
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
|
||||||
}
|
}
|
||||||
|
|
||||||
StreamingDestination::~StreamingDestination ()
|
StreamingDestination::~StreamingDestination ()
|
||||||
{
|
{
|
||||||
if (m_LeaseSet)
|
|
||||||
DeleteI2NPMessage (m_LeaseSet);
|
|
||||||
if (m_Pool)
|
if (m_Pool)
|
||||||
i2p::tunnel::tunnels.DeleteTunnelPool (m_Pool);
|
i2p::tunnel::tunnels.DeleteTunnelPool (m_Pool);
|
||||||
|
delete m_LeaseSet;
|
||||||
}
|
}
|
||||||
|
|
||||||
void StreamingDestination::HandleNextPacket (Packet * packet)
|
void StreamingDestination::HandleNextPacket (Packet * packet)
|
||||||
{
|
{
|
||||||
uint32_t sendStreamID = packet->GetSendStreamID ();
|
uint32_t sendStreamID = packet->GetSendStreamID ();
|
||||||
auto it = m_Streams.find (sendStreamID);
|
if (sendStreamID)
|
||||||
if (it != m_Streams.end ())
|
|
||||||
it->second->HandleNextPacket (packet);
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
LogPrint ("Unknown stream ", sendStreamID);
|
auto it = m_Streams.find (sendStreamID);
|
||||||
delete packet;
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Stream * StreamingDestination::CreateNewStream (boost::asio::io_service& service,
|
Stream * StreamingDestination::CreateNewOutgoingStream (const i2p::data::LeaseSet& remote)
|
||||||
const i2p::data::LeaseSet& remote)
|
|
||||||
{
|
{
|
||||||
Stream * s = new Stream (service, this, remote);
|
Stream * s = new Stream (m_Service, this, remote);
|
||||||
m_Streams[s->GetRecvStreamID ()] = s;
|
m_Streams[s->GetRecvStreamID ()] = s;
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Stream * StreamingDestination::CreateNewIncomingStream ()
|
||||||
|
{
|
||||||
|
Stream * s = new Stream (m_Service, this);
|
||||||
|
m_Streams[s->GetRecvStreamID ()] = s;
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
void StreamingDestination::DeleteStream (Stream * stream)
|
void StreamingDestination::DeleteStream (Stream * stream)
|
||||||
{
|
{
|
||||||
if (stream)
|
if (stream)
|
||||||
@ -396,68 +474,29 @@ namespace stream
|
|||||||
delete stream;
|
delete stream;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void StreamingDestination::UpdateLeaseSet ()
|
|
||||||
{
|
|
||||||
auto newLeaseSet = CreateLeaseSet ();
|
|
||||||
// TODO: make it atomic
|
|
||||||
auto oldLeaseSet = m_LeaseSet;
|
|
||||||
m_LeaseSet = newLeaseSet;
|
|
||||||
if (oldLeaseSet)
|
|
||||||
DeleteI2NPMessage (oldLeaseSet);
|
|
||||||
for (auto it: m_Streams)
|
|
||||||
it.second->SetLeaseSetUpdated ();
|
|
||||||
}
|
|
||||||
|
|
||||||
const I2NPMessage * StreamingDestination::GetLeaseSet ()
|
I2NPMessage * StreamingDestination::GetLeaseSetMsg ()
|
||||||
|
{
|
||||||
|
return CreateDatabaseStoreMsg (GetLeaseSet ());
|
||||||
|
}
|
||||||
|
|
||||||
|
const i2p::data::LeaseSet * StreamingDestination::GetLeaseSet ()
|
||||||
{
|
{
|
||||||
if (!m_LeaseSet)
|
if (!m_Pool) return nullptr;
|
||||||
m_LeaseSet = CreateLeaseSet ();
|
if (!m_LeaseSet || m_LeaseSet->HasExpiredLeases ())
|
||||||
else
|
{
|
||||||
RenewI2NPMessageHeader (m_LeaseSet);
|
auto newLeaseSet = new i2p::data::LeaseSet (*m_Pool);
|
||||||
|
// TODO: make it atomic
|
||||||
|
auto oldLeaseSet = m_LeaseSet;
|
||||||
|
m_LeaseSet = newLeaseSet;
|
||||||
|
delete oldLeaseSet;
|
||||||
|
for (auto it: m_Streams)
|
||||||
|
it.second->SetLeaseSetUpdated ();
|
||||||
|
}
|
||||||
return m_LeaseSet;
|
return m_LeaseSet;
|
||||||
}
|
}
|
||||||
|
|
||||||
I2NPMessage * StreamingDestination::CreateLeaseSet () const
|
void StreamingDestination::Sign (const uint8_t * buf, int len, uint8_t * signature) const
|
||||||
{
|
|
||||||
I2NPMessage * m = NewI2NPMessage ();
|
|
||||||
I2NPDatabaseStoreMsg * msg = (I2NPDatabaseStoreMsg *)m->GetPayload ();
|
|
||||||
memcpy (msg->key, (const uint8_t *)m_IdentHash, 32);
|
|
||||||
msg->type = 1; // LeaseSet
|
|
||||||
msg->replyToken = 0;
|
|
||||||
|
|
||||||
uint8_t * buf = m->GetPayload () + sizeof (I2NPDatabaseStoreMsg);
|
|
||||||
size_t size = 0;
|
|
||||||
memcpy (buf + size, &m_Keys.pub, sizeof (m_Keys.pub));
|
|
||||||
size += sizeof (m_Keys.pub); // destination
|
|
||||||
memcpy (buf + size, m_Pool->GetEncryptionPublicKey (), 256);
|
|
||||||
size += 256; // encryption key
|
|
||||||
memset (buf + size, 0, 128);
|
|
||||||
size += 128; // signing key
|
|
||||||
auto tunnels = m_Pool->GetInboundTunnels (5); // 5 tunnels maximum
|
|
||||||
buf[size] = tunnels.size (); // num leases
|
|
||||||
size++; // num
|
|
||||||
for (auto it: tunnels)
|
|
||||||
{
|
|
||||||
auto tunnel = it;
|
|
||||||
memcpy (buf + size, (const uint8_t *)tunnel->GetNextIdentHash (), 32);
|
|
||||||
size += 32; // tunnel_gw
|
|
||||||
*(uint32_t *)(buf + size) = htobe32 (tunnel->GetNextTunnelID ());
|
|
||||||
size += 4; // tunnel_id
|
|
||||||
uint64_t ts = tunnel->GetCreationTime () + i2p::tunnel::TUNNEL_EXPIRATION_TIMEOUT - 60; // 1 minute before expiration
|
|
||||||
ts *= 1000; // in milliseconds
|
|
||||||
*(uint64_t *)(buf + size) = htobe64 (ts);
|
|
||||||
size += 8; // end_date
|
|
||||||
}
|
|
||||||
Sign (buf, size, buf+ size);
|
|
||||||
size += 40; // signature
|
|
||||||
LogPrint ("Local LeaseSet of ", tunnels.size (), " leases created");
|
|
||||||
m->len += size + sizeof (I2NPDatabaseStoreMsg);
|
|
||||||
FillI2NPMessageHeader (m, eI2NPDatabaseStore);
|
|
||||||
return m;
|
|
||||||
}
|
|
||||||
|
|
||||||
void StreamingDestination::Sign (uint8_t * buf, int len, uint8_t * signature) const
|
|
||||||
{
|
{
|
||||||
CryptoPP::DSA::Signer signer (m_SigningPrivateKey);
|
CryptoPP::DSA::Signer signer (m_SigningPrivateKey);
|
||||||
signer.SignMessage (i2p::context.GetRandomNumberGenerator (), buf, len, signature);
|
signer.SignMessage (i2p::context.GetRandomNumberGenerator (), buf, len, signature);
|
||||||
@ -467,7 +506,11 @@ namespace stream
|
|||||||
void StreamingDestinations::Start ()
|
void StreamingDestinations::Start ()
|
||||||
{
|
{
|
||||||
if (!m_SharedLocalDestination)
|
if (!m_SharedLocalDestination)
|
||||||
m_SharedLocalDestination = new StreamingDestination ();
|
{
|
||||||
|
m_SharedLocalDestination = new StreamingDestination (m_Service);
|
||||||
|
m_Destinations[m_SharedLocalDestination->GetIdentHash ()] = m_SharedLocalDestination;
|
||||||
|
}
|
||||||
|
LoadLocalDestinations ();
|
||||||
|
|
||||||
m_IsRunning = true;
|
m_IsRunning = true;
|
||||||
m_Thread = new std::thread (std::bind (&StreamingDestinations::Run, this));
|
m_Thread = new std::thread (std::bind (&StreamingDestinations::Run, this));
|
||||||
@ -475,7 +518,10 @@ namespace stream
|
|||||||
|
|
||||||
void StreamingDestinations::Stop ()
|
void StreamingDestinations::Stop ()
|
||||||
{
|
{
|
||||||
delete m_SharedLocalDestination;
|
for (auto it: m_Destinations)
|
||||||
|
delete it.second;
|
||||||
|
m_Destinations.clear ();
|
||||||
|
m_SharedLocalDestination = 0; // deleted through m_Destination
|
||||||
|
|
||||||
m_IsRunning = false;
|
m_IsRunning = false;
|
||||||
m_Service.stop ();
|
m_Service.stop ();
|
||||||
@ -492,20 +538,49 @@ namespace stream
|
|||||||
m_Service.run ();
|
m_Service.run ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void StreamingDestinations::LoadLocalDestinations ()
|
||||||
|
{
|
||||||
|
int numDestinations = 0;
|
||||||
|
boost::filesystem::path p (i2p::util::filesystem::GetDataDir());
|
||||||
|
boost::filesystem::directory_iterator end;
|
||||||
|
for (boost::filesystem::directory_iterator it (p); it != end; ++it)
|
||||||
|
{
|
||||||
|
if (boost::filesystem::is_regular_file (*it) && it->path ().extension () == ".dat")
|
||||||
|
{
|
||||||
|
auto fullPath =
|
||||||
|
#if BOOST_VERSION > 10500
|
||||||
|
it->path().string();
|
||||||
|
#else
|
||||||
|
it->path();
|
||||||
|
#endif
|
||||||
|
auto localDestination = new StreamingDestination (m_Service, fullPath);
|
||||||
|
m_Destinations[localDestination->GetIdentHash ()] = localDestination;
|
||||||
|
numDestinations++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (numDestinations > 0)
|
||||||
|
LogPrint (numDestinations, " local destinations loaded");
|
||||||
|
}
|
||||||
|
|
||||||
Stream * StreamingDestinations::CreateClientStream (const i2p::data::LeaseSet& remote)
|
Stream * StreamingDestinations::CreateClientStream (const i2p::data::LeaseSet& remote)
|
||||||
{
|
{
|
||||||
if (!m_SharedLocalDestination) return nullptr;
|
if (!m_SharedLocalDestination) return nullptr;
|
||||||
return m_SharedLocalDestination->CreateNewStream (m_Service, remote);
|
return m_SharedLocalDestination->CreateNewOutgoingStream (remote);
|
||||||
}
|
}
|
||||||
|
|
||||||
void StreamingDestinations::DeleteClientStream (Stream * stream)
|
|
||||||
{
|
|
||||||
if (m_SharedLocalDestination)
|
|
||||||
m_SharedLocalDestination->DeleteStream (stream);
|
|
||||||
else
|
|
||||||
delete stream;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
void StreamingDestinations::DeleteStream (Stream * stream)
|
||||||
|
{
|
||||||
|
if (stream)
|
||||||
|
{
|
||||||
|
m_Service.post (
|
||||||
|
[=](void)
|
||||||
|
{
|
||||||
|
stream->GetLocalDestination ()->DeleteStream (stream);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void StreamingDestinations::HandleNextPacket (i2p::data::IdentHash destination, Packet * packet)
|
void StreamingDestinations::HandleNextPacket (i2p::data::IdentHash destination, Packet * packet)
|
||||||
{
|
{
|
||||||
m_Service.post (boost::bind (&StreamingDestinations::PostNextPacket, this, destination, packet));
|
m_Service.post (boost::bind (&StreamingDestinations::PostNextPacket, this, destination, packet));
|
||||||
@ -513,9 +588,14 @@ namespace stream
|
|||||||
|
|
||||||
void StreamingDestinations::PostNextPacket (i2p::data::IdentHash destination, Packet * packet)
|
void StreamingDestinations::PostNextPacket (i2p::data::IdentHash destination, Packet * packet)
|
||||||
{
|
{
|
||||||
// TODO: we have onle one destination, might be more
|
auto it = m_Destinations.find (destination);
|
||||||
if (m_SharedLocalDestination)
|
if (it != m_Destinations.end ())
|
||||||
m_SharedLocalDestination->HandleNextPacket (packet);
|
it->second->HandleNextPacket (packet);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LogPrint ("Local destination ", destination.ToBase64 (), " not found");
|
||||||
|
delete packet;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Stream * CreateStream (const i2p::data::LeaseSet& remote)
|
Stream * CreateStream (const i2p::data::LeaseSet& remote)
|
||||||
@ -525,7 +605,7 @@ namespace stream
|
|||||||
|
|
||||||
void DeleteStream (Stream * stream)
|
void DeleteStream (Stream * stream)
|
||||||
{
|
{
|
||||||
destinations.DeleteClientStream (stream);
|
destinations.DeleteStream (stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
void StartStreaming ()
|
void StartStreaming ()
|
||||||
@ -537,6 +617,11 @@ namespace stream
|
|||||||
{
|
{
|
||||||
destinations.Stop ();
|
destinations.Stop ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
StreamingDestination * GetSharedLocalDestination ()
|
||||||
|
{
|
||||||
|
return destinations.GetSharedLocalDestination ();
|
||||||
|
}
|
||||||
|
|
||||||
void HandleDataMessage (i2p::data::IdentHash destination, const uint8_t * buf, size_t len)
|
void HandleDataMessage (i2p::data::IdentHash destination, const uint8_t * buf, size_t len)
|
||||||
{
|
{
|
||||||
@ -554,7 +639,7 @@ namespace stream
|
|||||||
uncompressed->len = decompressor.MaxRetrievable ();
|
uncompressed->len = decompressor.MaxRetrievable ();
|
||||||
if (uncompressed->len > MAX_PACKET_SIZE)
|
if (uncompressed->len > MAX_PACKET_SIZE)
|
||||||
{
|
{
|
||||||
LogPrint ("Recieved packet size exceeds mac packet size");
|
LogPrint ("Received packet size ", uncompressed->len, " exceeds max packet size");
|
||||||
uncompressed->len = MAX_PACKET_SIZE;
|
uncompressed->len = MAX_PACKET_SIZE;
|
||||||
}
|
}
|
||||||
decompressor.Get (uncompressed->buf, uncompressed->len);
|
decompressor.Get (uncompressed->buf, uncompressed->len);
|
||||||
|
68
Streaming.h
68
Streaming.h
@ -7,6 +7,7 @@
|
|||||||
#include <set>
|
#include <set>
|
||||||
#include <queue>
|
#include <queue>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
#include <functional>
|
||||||
#include <boost/asio.hpp>
|
#include <boost/asio.hpp>
|
||||||
#include <boost/bind.hpp>
|
#include <boost/bind.hpp>
|
||||||
#include <cryptopp/dsa.h>
|
#include <cryptopp/dsa.h>
|
||||||
@ -14,7 +15,6 @@
|
|||||||
#include "Identity.h"
|
#include "Identity.h"
|
||||||
#include "LeaseSet.h"
|
#include "LeaseSet.h"
|
||||||
#include "I2NPProtocol.h"
|
#include "I2NPProtocol.h"
|
||||||
#include "Tunnel.h"
|
|
||||||
#include "TunnelPool.h"
|
#include "TunnelPool.h"
|
||||||
|
|
||||||
namespace i2p
|
namespace i2p
|
||||||
@ -34,7 +34,7 @@ namespace stream
|
|||||||
const uint16_t PACKET_FLAG_NO_ACK = 0x0400;
|
const uint16_t PACKET_FLAG_NO_ACK = 0x0400;
|
||||||
|
|
||||||
const size_t STREAMING_MTU = 1730;
|
const size_t STREAMING_MTU = 1730;
|
||||||
const size_t MAX_PACKET_SIZE = 1754;
|
const size_t MAX_PACKET_SIZE = 4096;
|
||||||
|
|
||||||
struct Packet
|
struct Packet
|
||||||
{
|
{
|
||||||
@ -55,6 +55,8 @@ namespace stream
|
|||||||
uint16_t GetOptionSize () const { return be16toh (*(uint16_t *)GetOption ()); };
|
uint16_t GetOptionSize () const { return be16toh (*(uint16_t *)GetOption ()); };
|
||||||
const uint8_t * GetOptionData () const { return GetOption () + 2; };
|
const uint8_t * GetOptionData () const { return GetOption () + 2; };
|
||||||
const uint8_t * GetPayload () const { return GetOptionData () + GetOptionSize (); };
|
const uint8_t * GetPayload () const { return GetOptionData () + GetOptionSize (); };
|
||||||
|
|
||||||
|
bool IsSYN () const { return GetFlags () & PACKET_FLAG_SYNCHRONIZE; };
|
||||||
};
|
};
|
||||||
|
|
||||||
struct PacketCmp
|
struct PacketCmp
|
||||||
@ -70,13 +72,16 @@ namespace stream
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Stream (boost::asio::io_service& service, StreamingDestination * local, const i2p::data::LeaseSet& remote);
|
Stream (boost::asio::io_service& service, StreamingDestination * local, const i2p::data::LeaseSet& remote); // outgoing
|
||||||
|
Stream (boost::asio::io_service& service, StreamingDestination * local); // incoming
|
||||||
|
|
||||||
~Stream ();
|
~Stream ();
|
||||||
uint32_t GetSendStreamID () const { return m_SendStreamID; };
|
uint32_t GetSendStreamID () const { return m_SendStreamID; };
|
||||||
uint32_t GetRecvStreamID () const { return m_RecvStreamID; };
|
uint32_t GetRecvStreamID () const { return m_RecvStreamID; };
|
||||||
const i2p::data::LeaseSet& GetRemoteLeaseSet () const { return m_RemoteLeaseSet; };
|
const i2p::data::LeaseSet * GetRemoteLeaseSet () const { return m_RemoteLeaseSet; };
|
||||||
bool IsOpen () const { return m_IsOpen; };
|
bool IsOpen () const { return m_IsOpen; };
|
||||||
bool IsEstablished () const { return m_SendStreamID; };
|
bool IsEstablished () const { return m_SendStreamID; };
|
||||||
|
StreamingDestination * GetLocalDestination () { return m_LocalDestination; };
|
||||||
|
|
||||||
void HandleNextPacket (Packet * packet);
|
void HandleNextPacket (Packet * packet);
|
||||||
size_t Send (const uint8_t * buf, size_t len, int timeout); // timeout in seconds
|
size_t Send (const uint8_t * buf, size_t len, int timeout); // timeout in seconds
|
||||||
@ -90,7 +95,7 @@ namespace stream
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void SendQuickAck ();
|
void SendQuickAck (bool syn = false);
|
||||||
bool SendPacket (Packet * packet);
|
bool SendPacket (Packet * packet);
|
||||||
bool SendPacket (const uint8_t * buf, size_t len);
|
bool SendPacket (const uint8_t * buf, size_t len);
|
||||||
|
|
||||||
@ -106,14 +111,15 @@ namespace stream
|
|||||||
private:
|
private:
|
||||||
|
|
||||||
boost::asio::io_service& m_Service;
|
boost::asio::io_service& m_Service;
|
||||||
uint32_t m_SendStreamID, m_RecvStreamID, m_SequenceNumber, m_LastReceivedSequenceNumber;
|
uint32_t m_SendStreamID, m_RecvStreamID, m_SequenceNumber;
|
||||||
bool m_IsOpen, m_LeaseSetUpdated;
|
int32_t m_LastReceivedSequenceNumber;
|
||||||
|
bool m_IsOpen, m_IsOutgoing, m_LeaseSetUpdated;
|
||||||
StreamingDestination * m_LocalDestination;
|
StreamingDestination * m_LocalDestination;
|
||||||
const i2p::data::LeaseSet& m_RemoteLeaseSet;
|
i2p::data::Identity m_RemoteIdentity;
|
||||||
|
const i2p::data::LeaseSet * m_RemoteLeaseSet;
|
||||||
i2p::data::Lease m_CurrentRemoteLease;
|
i2p::data::Lease m_CurrentRemoteLease;
|
||||||
std::queue<Packet *> m_ReceiveQueue;
|
std::queue<Packet *> m_ReceiveQueue;
|
||||||
std::set<Packet *, PacketCmp> m_SavedPackets;
|
std::set<Packet *, PacketCmp> m_SavedPackets;
|
||||||
i2p::tunnel::OutboundTunnel * m_OutboundTunnel;
|
|
||||||
boost::asio::deadline_timer m_ReceiveTimer;
|
boost::asio::deadline_timer m_ReceiveTimer;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -121,41 +127,44 @@ namespace stream
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
StreamingDestination ();
|
StreamingDestination (boost::asio::io_service& service);
|
||||||
StreamingDestination (const std::string& fullPath);
|
StreamingDestination (boost::asio::io_service& service, const std::string& fullPath);
|
||||||
~StreamingDestination ();
|
~StreamingDestination ();
|
||||||
|
|
||||||
const i2p::data::PrivateKeys& GetKeys () const { return m_Keys; };
|
const i2p::data::PrivateKeys& GetKeys () const { return m_Keys; };
|
||||||
const i2p::data::Identity& GetIdentity () const { return m_Keys.pub; };
|
I2NPMessage * GetLeaseSetMsg ();
|
||||||
const I2NPMessage * GetLeaseSet ();
|
const i2p::data::LeaseSet * GetLeaseSet ();
|
||||||
i2p::tunnel::TunnelPool * GetTunnelPool () const { return m_Pool; };
|
i2p::tunnel::TunnelPool * GetTunnelPool () const { return m_Pool; };
|
||||||
void Sign (uint8_t * buf, int len, uint8_t * signature) const;
|
|
||||||
|
|
||||||
Stream * CreateNewStream (boost::asio::io_service& service, const i2p::data::LeaseSet& remote);
|
Stream * CreateNewOutgoingStream (const i2p::data::LeaseSet& remote);
|
||||||
void DeleteStream (Stream * stream);
|
void DeleteStream (Stream * stream);
|
||||||
|
void SetAcceptor (const std::function<void (Stream *)>& acceptor) { m_Acceptor = acceptor; };
|
||||||
void HandleNextPacket (Packet * packet);
|
void HandleNextPacket (Packet * packet);
|
||||||
|
|
||||||
// implements LocalDestination
|
// implements LocalDestination
|
||||||
void UpdateLeaseSet ();
|
|
||||||
const i2p::data::IdentHash& GetIdentHash () const { return m_IdentHash; };
|
const i2p::data::IdentHash& GetIdentHash () const { return m_IdentHash; };
|
||||||
|
const i2p::data::Identity& GetIdentity () const { return m_Keys.pub; };
|
||||||
const uint8_t * GetEncryptionPrivateKey () const { return m_EncryptionPrivateKey; };
|
const uint8_t * GetEncryptionPrivateKey () const { return m_EncryptionPrivateKey; };
|
||||||
const uint8_t * GetEncryptionPublicKey () const { return m_EncryptionPublicKey; };
|
const uint8_t * GetEncryptionPublicKey () const { return m_EncryptionPublicKey; };
|
||||||
|
void Sign (const uint8_t * buf, int len, uint8_t * signature) const;
|
||||||
private:
|
|
||||||
|
private:
|
||||||
I2NPMessage * CreateLeaseSet () const;
|
|
||||||
|
Stream * CreateNewIncomingStream ();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
boost::asio::io_service& m_Service;
|
||||||
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];
|
uint8_t m_EncryptionPublicKey[256], m_EncryptionPrivateKey[256];
|
||||||
|
|
||||||
i2p::tunnel::TunnelPool * m_Pool;
|
i2p::tunnel::TunnelPool * m_Pool;
|
||||||
I2NPMessage * m_LeaseSet;
|
i2p::data::LeaseSet * m_LeaseSet;
|
||||||
|
|
||||||
CryptoPP::DSA::PrivateKey m_SigningPrivateKey;
|
CryptoPP::DSA::PrivateKey m_SigningPrivateKey;
|
||||||
|
std::function<void (Stream *)> m_Acceptor;
|
||||||
};
|
};
|
||||||
|
|
||||||
class StreamingDestinations
|
class StreamingDestinations
|
||||||
@ -172,11 +181,13 @@ namespace stream
|
|||||||
void HandleNextPacket (i2p::data::IdentHash destination, Packet * packet);
|
void HandleNextPacket (i2p::data::IdentHash destination, Packet * packet);
|
||||||
|
|
||||||
Stream * CreateClientStream (const i2p::data::LeaseSet& remote);
|
Stream * CreateClientStream (const i2p::data::LeaseSet& remote);
|
||||||
void DeleteClientStream (Stream * stream);
|
void DeleteStream (Stream * stream);
|
||||||
|
StreamingDestination * GetSharedLocalDestination () const { return m_SharedLocalDestination; };
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void Run ();
|
void Run ();
|
||||||
|
void LoadLocalDestinations ();
|
||||||
void PostNextPacket (i2p::data::IdentHash destination, Packet * packet);
|
void PostNextPacket (i2p::data::IdentHash destination, Packet * packet);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -186,6 +197,7 @@ namespace stream
|
|||||||
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;
|
||||||
|
|
||||||
|
std::map<i2p::data::IdentHash, StreamingDestination *> m_Destinations;
|
||||||
StreamingDestination * m_SharedLocalDestination;
|
StreamingDestination * m_SharedLocalDestination;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -193,6 +205,7 @@ namespace stream
|
|||||||
void DeleteStream (Stream * stream);
|
void DeleteStream (Stream * stream);
|
||||||
void StartStreaming ();
|
void StartStreaming ();
|
||||||
void StopStreaming ();
|
void StopStreaming ();
|
||||||
|
StreamingDestination * GetSharedLocalDestination ();
|
||||||
|
|
||||||
// assuming data is I2CP message
|
// assuming data is I2CP message
|
||||||
void HandleDataMessage (i2p::data::IdentHash destination, const uint8_t * buf, size_t len);
|
void HandleDataMessage (i2p::data::IdentHash destination, const uint8_t * buf, size_t len);
|
||||||
@ -213,6 +226,11 @@ namespace stream
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!m_IsOpen)
|
||||||
|
{
|
||||||
|
handler (boost::asio::error::make_error_code (boost::asio::error::connection_reset), 0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
m_ReceiveTimer.expires_from_now (boost::posix_time::seconds(timeout));
|
m_ReceiveTimer.expires_from_now (boost::posix_time::seconds(timeout));
|
||||||
m_ReceiveTimer.async_wait ([=](const boost::system::error_code& ecode)
|
m_ReceiveTimer.async_wait ([=](const boost::system::error_code& ecode)
|
||||||
{ this->HandleReceiveTimer (ecode, buffer, handler); });
|
{ this->HandleReceiveTimer (ecode, buffer, handler); });
|
||||||
|
@ -30,11 +30,11 @@ namespace tunnel
|
|||||||
EncryptTunnelMsg (tunnelMsg);
|
EncryptTunnelMsg (tunnelMsg);
|
||||||
|
|
||||||
LogPrint ("TransitTunnel: ",m_TunnelID,"->", m_NextTunnelID);
|
LogPrint ("TransitTunnel: ",m_TunnelID,"->", m_NextTunnelID);
|
||||||
|
m_NumTransmittedBytes += tunnelMsg->GetLength ();
|
||||||
*(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::transports.SendMessage (m_NextIdent, tunnelMsg);
|
||||||
m_NumTransmittedBytes += tunnelMsg->GetLength ();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TransitTunnel::SendTunnelDataMsg (i2p::I2NPMessage * msg)
|
void TransitTunnel::SendTunnelDataMsg (i2p::I2NPMessage * msg)
|
||||||
@ -48,6 +48,7 @@ namespace tunnel
|
|||||||
TunnelMessageBlock block;
|
TunnelMessageBlock block;
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -81,4 +82,4 @@ namespace tunnel
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
#define TRANSIT_TUNNEL_H__
|
#define TRANSIT_TUNNEL_H__
|
||||||
|
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
|
#include <mutex>
|
||||||
#include "aes.h"
|
#include "aes.h"
|
||||||
#include "I2NPProtocol.h"
|
#include "I2NPProtocol.h"
|
||||||
#include "TunnelEndpoint.h"
|
#include "TunnelEndpoint.h"
|
||||||
@ -55,6 +56,7 @@ namespace tunnel
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
std::mutex m_SendMutex;
|
||||||
TunnelGateway m_Gateway;
|
TunnelGateway m_Gateway;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -65,7 +67,8 @@ namespace tunnel
|
|||||||
TransitTunnelEndpoint (uint32_t receiveTunnelID,
|
TransitTunnelEndpoint (uint32_t receiveTunnelID,
|
||||||
const uint8_t * nextIdent, uint32_t nextTunnelID,
|
const uint8_t * nextIdent, uint32_t nextTunnelID,
|
||||||
const uint8_t * layerKey,const uint8_t * ivKey):
|
const uint8_t * layerKey,const uint8_t * ivKey):
|
||||||
TransitTunnel (receiveTunnelID, nextIdent, nextTunnelID, layerKey, ivKey) {};
|
TransitTunnel (receiveTunnelID, nextIdent, nextTunnelID, layerKey, ivKey),
|
||||||
|
m_Endpoint (false) {}; // transit endpoint is always outbound
|
||||||
|
|
||||||
void HandleTunnelDataMsg (i2p::I2NPMessage * tunnelMsg);
|
void HandleTunnelDataMsg (i2p::I2NPMessage * tunnelMsg);
|
||||||
size_t GetNumTransmittedBytes () const { return m_Endpoint.GetNumReceivedBytes (); }
|
size_t GetNumTransmittedBytes () const { return m_Endpoint.GetNumReceivedBytes (); }
|
||||||
|
@ -52,6 +52,7 @@ namespace i2p
|
|||||||
{
|
{
|
||||||
i2p::data::DHKeysPair * pair = new i2p::data::DHKeysPair ();
|
i2p::data::DHKeysPair * pair = new i2p::data::DHKeysPair ();
|
||||||
i2p::data::CreateRandomDHKeysPair (pair);
|
i2p::data::CreateRandomDHKeysPair (pair);
|
||||||
|
std::unique_lock<std::mutex> l(m_AcquiredMutex);
|
||||||
m_Queue.push (pair);
|
m_Queue.push (pair);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -61,6 +62,7 @@ namespace i2p
|
|||||||
{
|
{
|
||||||
if (!m_Queue.empty ())
|
if (!m_Queue.empty ())
|
||||||
{
|
{
|
||||||
|
std::unique_lock<std::mutex> l(m_AcquiredMutex);
|
||||||
auto pair = m_Queue.front ();
|
auto pair = m_Queue.front ();
|
||||||
m_Queue.pop ();
|
m_Queue.pop ();
|
||||||
m_Acquired.notify_one ();
|
m_Acquired.notify_one ();
|
||||||
@ -230,9 +232,9 @@ namespace i2p
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// existing session not found. create new
|
// existing session not found. create new
|
||||||
// try NTCP first
|
// try NTCP first if message size < 16K
|
||||||
auto address = r->GetNTCPAddress ();
|
auto address = r->GetNTCPAddress ();
|
||||||
if (address && !r->UsesIntroducer () && !r->IsUnreachable ())
|
if (address && !r->UsesIntroducer () && !r->IsUnreachable () && msg->GetLength () < i2p::ntcp::NTCP_MAX_MESSAGE_SIZE)
|
||||||
{
|
{
|
||||||
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);
|
||||||
@ -245,7 +247,10 @@ namespace i2p
|
|||||||
if (s)
|
if (s)
|
||||||
s->SendI2NPMessage (msg);
|
s->SendI2NPMessage (msg);
|
||||||
else
|
else
|
||||||
|
{
|
||||||
LogPrint ("No NTCP and SSU addresses available");
|
LogPrint ("No NTCP and SSU addresses available");
|
||||||
|
DeleteI2NPMessage (msg);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -253,10 +258,28 @@ namespace i2p
|
|||||||
{
|
{
|
||||||
LogPrint ("Router not found. Requested");
|
LogPrint ("Router not found. Requested");
|
||||||
i2p::data::netdb.RequestDestination (ident);
|
i2p::data::netdb.RequestDestination (ident);
|
||||||
|
DeleteI2NPMessage (msg); // TODO: implement a placeholder for router and send once it's available
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Transports::CloseSession (const i2p::data::RouterInfo * router)
|
||||||
|
{
|
||||||
|
if (!router) return;
|
||||||
|
m_Service.post (boost::bind (&Transports::PostCloseSession, this, router));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Transports::PostCloseSession (const i2p::data::RouterInfo * router)
|
||||||
|
{
|
||||||
|
auto ssuSession = m_SSUServer ? m_SSUServer->FindSession (router) : nullptr;
|
||||||
|
if (ssuSession) // try SSU first
|
||||||
|
{
|
||||||
|
m_SSUServer->DeleteSession (ssuSession);
|
||||||
|
LogPrint ("SSU session closed");
|
||||||
|
}
|
||||||
|
// TODO: delete NTCP
|
||||||
|
}
|
||||||
|
|
||||||
void Transports::DetectExternalIP ()
|
void Transports::DetectExternalIP ()
|
||||||
{
|
{
|
||||||
for (int i = 0; i < 5; i ++)
|
for (int i = 0; i < 5; i ++)
|
||||||
|
@ -63,13 +63,15 @@ namespace i2p
|
|||||||
i2p::ntcp::NTCPSession * FindNTCPSession (const i2p::data::IdentHash& ident);
|
i2p::ntcp::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);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void Run ();
|
void Run ();
|
||||||
void HandleAccept (i2p::ntcp::NTCPServerConnection * conn, const boost::system::error_code& error);
|
void HandleAccept (i2p::ntcp::NTCPServerConnection * conn, const boost::system::error_code& error);
|
||||||
void PostMessage (const i2p::data::IdentHash& ident, i2p::I2NPMessage * msg);
|
void PostMessage (const i2p::data::IdentHash& ident, i2p::I2NPMessage * msg);
|
||||||
|
void PostCloseSession (const i2p::data::RouterInfo * router);
|
||||||
|
|
||||||
void DetectExternalIP ();
|
void DetectExternalIP ();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
23
Tunnel.cpp
23
Tunnel.cpp
@ -14,8 +14,8 @@ namespace i2p
|
|||||||
namespace tunnel
|
namespace tunnel
|
||||||
{
|
{
|
||||||
|
|
||||||
Tunnel::Tunnel (TunnelConfig * config): m_Config (config), m_Pool (nullptr),
|
Tunnel::Tunnel (TunnelConfig * config):
|
||||||
m_IsEstablished (false), m_IsFailed (false)
|
m_Config (config), m_Pool (nullptr), m_State (eTunnelStatePending)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -111,7 +111,7 @@ namespace tunnel
|
|||||||
hop = hop->prev;
|
hop = hop->prev;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_IsEstablished = true;
|
bool established = true;
|
||||||
hop = m_Config->GetFirstHop ();
|
hop = m_Config->GetFirstHop ();
|
||||||
while (hop)
|
while (hop)
|
||||||
{
|
{
|
||||||
@ -119,10 +119,10 @@ namespace tunnel
|
|||||||
LogPrint ("Ret code=", (int)record->ret);
|
LogPrint ("Ret code=", (int)record->ret);
|
||||||
if (record->ret)
|
if (record->ret)
|
||||||
// if any of participants declined the tunnel is not established
|
// if any of participants declined the tunnel is not established
|
||||||
m_IsEstablished = false;
|
established = false;
|
||||||
hop = hop->next;
|
hop = hop->next;
|
||||||
}
|
}
|
||||||
if (m_IsEstablished)
|
if (established)
|
||||||
{
|
{
|
||||||
// change reply keys to layer keys
|
// change reply keys to layer keys
|
||||||
hop = m_Config->GetFirstHop ();
|
hop = m_Config->GetFirstHop ();
|
||||||
@ -132,7 +132,8 @@ namespace tunnel
|
|||||||
hop = hop->next;
|
hop = hop->next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return m_IsEstablished;
|
if (established) m_State = eTunnelStateEstablished;
|
||||||
|
return established;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Tunnel::EncryptTunnelMsg (I2NPMessage * tunnelMsg)
|
void Tunnel::EncryptTunnelMsg (I2NPMessage * tunnelMsg)
|
||||||
@ -148,7 +149,7 @@ namespace tunnel
|
|||||||
|
|
||||||
void InboundTunnel::HandleTunnelDataMsg (I2NPMessage * msg)
|
void InboundTunnel::HandleTunnelDataMsg (I2NPMessage * msg)
|
||||||
{
|
{
|
||||||
if (IsFailed ()) SetFailed (false); // incoming messages means a tunnel is alive
|
if (IsFailed ()) SetState (eTunnelStateEstablished); // incoming messages means a tunnel is alive
|
||||||
msg->from = this;
|
msg->from = this;
|
||||||
EncryptTunnelMsg (msg);
|
EncryptTunnelMsg (msg);
|
||||||
m_Endpoint.HandleDecryptedTunnelDataMsg (msg);
|
m_Endpoint.HandleDecryptedTunnelDataMsg (msg);
|
||||||
@ -361,10 +362,12 @@ namespace tunnel
|
|||||||
void Tunnels::ManageTunnels ()
|
void Tunnels::ManageTunnels ()
|
||||||
{
|
{
|
||||||
// check pending tunnel. if something is still there, wipe it out
|
// check pending tunnel. if something is still there, wipe it out
|
||||||
// because it wouldn't be reponded anyway
|
// because it wouldn't be responded anyway
|
||||||
for (auto& it : m_PendingTunnels)
|
for (auto& it : m_PendingTunnels)
|
||||||
{
|
{
|
||||||
LogPrint ("Pending tunnel build request ", it.first, " has not been responded. Deleted");
|
LogPrint ("Pending tunnel build request ", it.first, " has not been responded. Deleted");
|
||||||
|
if (it.second->GetTunnelConfig ()->GetFirstHop ()->isGateway) // outbound
|
||||||
|
i2p::transports.CloseSession (it.second->GetTunnelConfig ()->GetFirstHop ()->router);
|
||||||
delete it.second;
|
delete it.second;
|
||||||
}
|
}
|
||||||
m_PendingTunnels.clear ();
|
m_PendingTunnels.clear ();
|
||||||
@ -398,6 +401,7 @@ namespace tunnel
|
|||||||
auto pool = (*it)->GetTunnelPool ();
|
auto pool = (*it)->GetTunnelPool ();
|
||||||
if (pool)
|
if (pool)
|
||||||
pool->TunnelExpired (*it);
|
pool->TunnelExpired (*it);
|
||||||
|
delete *it;
|
||||||
it = m_OutboundTunnels.erase (it);
|
it = m_OutboundTunnels.erase (it);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -430,6 +434,7 @@ namespace tunnel
|
|||||||
auto pool = it->second->GetTunnelPool ();
|
auto pool = it->second->GetTunnelPool ();
|
||||||
if (pool)
|
if (pool)
|
||||||
pool->TunnelExpired (it->second);
|
pool->TunnelExpired (it->second);
|
||||||
|
delete it->second;
|
||||||
it = m_InboundTunnels.erase (it);
|
it = m_InboundTunnels.erase (it);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -465,7 +470,9 @@ namespace tunnel
|
|||||||
if (ts > it->second->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT)
|
if (ts > it->second->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT)
|
||||||
{
|
{
|
||||||
LogPrint ("Transit tunnel ", it->second->GetTunnelID (), " expired");
|
LogPrint ("Transit tunnel ", it->second->GetTunnelID (), " expired");
|
||||||
|
auto tmp = it->second;
|
||||||
it = m_TransitTunnels.erase (it);
|
it = m_TransitTunnels.erase (it);
|
||||||
|
delete tmp;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
it++;
|
it++;
|
||||||
|
19
Tunnel.h
19
Tunnel.h
@ -22,6 +22,14 @@ namespace i2p
|
|||||||
namespace tunnel
|
namespace tunnel
|
||||||
{
|
{
|
||||||
const int TUNNEL_EXPIRATION_TIMEOUT = 660; // 11 minutes
|
const int TUNNEL_EXPIRATION_TIMEOUT = 660; // 11 minutes
|
||||||
|
|
||||||
|
enum TunnelState
|
||||||
|
{
|
||||||
|
eTunnelStatePending,
|
||||||
|
eTunnelStateEstablished,
|
||||||
|
eTunnelStateTestFailed,
|
||||||
|
eTunnelStateFailed
|
||||||
|
};
|
||||||
|
|
||||||
class OutboundTunnel;
|
class OutboundTunnel;
|
||||||
class InboundTunnel;
|
class InboundTunnel;
|
||||||
@ -35,9 +43,10 @@ namespace tunnel
|
|||||||
void Build (uint32_t replyMsgID, OutboundTunnel * outboundTunnel = 0);
|
void Build (uint32_t replyMsgID, OutboundTunnel * outboundTunnel = 0);
|
||||||
|
|
||||||
TunnelConfig * GetTunnelConfig () const { return m_Config; }
|
TunnelConfig * GetTunnelConfig () const { return m_Config; }
|
||||||
bool IsEstablished () const { return m_IsEstablished; };
|
TunnelState GetState () const { return m_State; };
|
||||||
bool IsFailed () const { return m_IsFailed; };
|
void SetState (TunnelState state) { m_State = state; };
|
||||||
void SetFailed (bool failed) { m_IsFailed = failed; }
|
bool IsEstablished () const { return m_State == eTunnelStateEstablished; };
|
||||||
|
bool IsFailed () const { return m_State == eTunnelStateFailed; };
|
||||||
|
|
||||||
TunnelPool * GetTunnelPool () const { return m_Pool; };
|
TunnelPool * GetTunnelPool () const { return m_Pool; };
|
||||||
void SetTunnelPool (TunnelPool * pool) { m_Pool = pool; };
|
void SetTunnelPool (TunnelPool * pool) { m_Pool = pool; };
|
||||||
@ -53,7 +62,7 @@ namespace tunnel
|
|||||||
|
|
||||||
TunnelConfig * m_Config;
|
TunnelConfig * m_Config;
|
||||||
TunnelPool * m_Pool; // pool, tunnel belongs to, or null
|
TunnelPool * m_Pool; // pool, tunnel belongs to, or null
|
||||||
bool m_IsEstablished, m_IsFailed;
|
TunnelState m_State;
|
||||||
};
|
};
|
||||||
|
|
||||||
class OutboundTunnel: public Tunnel
|
class OutboundTunnel: public Tunnel
|
||||||
@ -81,7 +90,7 @@ namespace tunnel
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
InboundTunnel (TunnelConfig * config): Tunnel (config) {};
|
InboundTunnel (TunnelConfig * config): Tunnel (config), m_Endpoint (true) {};
|
||||||
void HandleTunnelDataMsg (I2NPMessage * msg);
|
void HandleTunnelDataMsg (I2NPMessage * msg);
|
||||||
size_t GetNumReceivedBytes () const { return m_Endpoint.GetNumReceivedBytes (); };
|
size_t GetNumReceivedBytes () const { return m_Endpoint.GetNumReceivedBytes (); };
|
||||||
|
|
||||||
|
@ -1,14 +1,22 @@
|
|||||||
#include "I2PEndian.h"
|
#include "I2PEndian.h"
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "Log.h"
|
#include "Log.h"
|
||||||
|
#include "NetDb.h"
|
||||||
#include "I2NPProtocol.h"
|
#include "I2NPProtocol.h"
|
||||||
#include "Transports.h"
|
#include "Transports.h"
|
||||||
|
#include "RouterContext.h"
|
||||||
#include "TunnelEndpoint.h"
|
#include "TunnelEndpoint.h"
|
||||||
|
|
||||||
namespace i2p
|
namespace i2p
|
||||||
{
|
{
|
||||||
namespace tunnel
|
namespace tunnel
|
||||||
{
|
{
|
||||||
|
TunnelEndpoint::~TunnelEndpoint ()
|
||||||
|
{
|
||||||
|
for (auto it: m_IncompleteMessages)
|
||||||
|
i2p::DeleteI2NPMessage (it.second.data);
|
||||||
|
}
|
||||||
|
|
||||||
void TunnelEndpoint::HandleDecryptedTunnelDataMsg (I2NPMessage * msg)
|
void TunnelEndpoint::HandleDecryptedTunnelDataMsg (I2NPMessage * msg)
|
||||||
{
|
{
|
||||||
m_NumReceivedBytes += TUNNEL_DATA_MSG_SIZE;
|
m_NumReceivedBytes += TUNNEL_DATA_MSG_SIZE;
|
||||||
@ -19,6 +27,17 @@ namespace tunnel
|
|||||||
{
|
{
|
||||||
LogPrint ("TunnelMessage: zero found at ", (int)(zero-decrypted));
|
LogPrint ("TunnelMessage: zero found at ", (int)(zero-decrypted));
|
||||||
uint8_t * fragment = zero + 1;
|
uint8_t * fragment = zero + 1;
|
||||||
|
// verify checksum
|
||||||
|
memcpy (msg->GetPayload () + TUNNEL_DATA_MSG_SIZE, msg->GetPayload () + 4, 16); // copy iv to the end
|
||||||
|
uint8_t hash[32];
|
||||||
|
CryptoPP::SHA256().CalculateDigest (hash, fragment, TUNNEL_DATA_MSG_SIZE -(fragment - msg->GetPayload ()) + 16); // payload + iv
|
||||||
|
if (memcmp (hash, decrypted, 4))
|
||||||
|
{
|
||||||
|
LogPrint ("TunnelMessage: checksum verification failed");
|
||||||
|
i2p::DeleteI2NPMessage (msg);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// process fragments
|
||||||
while (fragment < decrypted + TUNNEL_DATA_ENCRYPTED_SIZE)
|
while (fragment < decrypted + TUNNEL_DATA_ENCRYPTED_SIZE)
|
||||||
{
|
{
|
||||||
uint8_t flag = fragment[0];
|
uint8_t flag = fragment[0];
|
||||||
@ -80,7 +99,6 @@ namespace tunnel
|
|||||||
|
|
||||||
msg->offset = fragment - msg->buf;
|
msg->offset = fragment - msg->buf;
|
||||||
msg->len = msg->offset + size;
|
msg->len = msg->offset + size;
|
||||||
bool isLastMessage = false;
|
|
||||||
if (fragment + size < decrypted + TUNNEL_DATA_ENCRYPTED_SIZE)
|
if (fragment + size < decrypted + TUNNEL_DATA_ENCRYPTED_SIZE)
|
||||||
{
|
{
|
||||||
// this is not last message. we have to copy it
|
// this is not last message. we have to copy it
|
||||||
@ -90,10 +108,7 @@ namespace tunnel
|
|||||||
*(m.data) = *msg;
|
*(m.data) = *msg;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
|
||||||
m.data = msg;
|
m.data = msg;
|
||||||
isLastMessage = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isFollowOnFragment && isLastFragment)
|
if (!isFollowOnFragment && isLastFragment)
|
||||||
HandleNextMessage (m);
|
HandleNextMessage (m);
|
||||||
@ -108,36 +123,8 @@ namespace tunnel
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
auto it = m_IncompleteMessages.find (msgID);
|
m.nextFragmentNum = fragmentNum;
|
||||||
if (it != m_IncompleteMessages.end())
|
HandleFollowOnFragment (msgID, isLastFragment, m);
|
||||||
{
|
|
||||||
if (fragmentNum == it->second.nextFragmentNum)
|
|
||||||
{
|
|
||||||
I2NPMessage * incompleteMessage = it->second.data;
|
|
||||||
memcpy (incompleteMessage->buf + incompleteMessage->len, fragment, size); // concatenate fragment
|
|
||||||
incompleteMessage->len += size;
|
|
||||||
if (isLastFragment)
|
|
||||||
{
|
|
||||||
// message complete
|
|
||||||
HandleNextMessage (it->second);
|
|
||||||
m_IncompleteMessages.erase (it);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
it->second.nextFragmentNum++;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
LogPrint ("Unexpected fragment ", fragmentNum, " instead ", it->second.nextFragmentNum, " of message ", msgID, ". Discarded");
|
|
||||||
m_IncompleteMessages.erase (it); // TODO: store unexpect fragment for a while
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
LogPrint ("First fragment of message ", msgID, " not found. Discarded");
|
|
||||||
|
|
||||||
if (isLastMessage)
|
|
||||||
// last message is follow-on fragment
|
|
||||||
// not passed to anywhere because first fragment
|
|
||||||
i2p::DeleteI2NPMessage (msg);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -154,6 +141,49 @@ namespace tunnel
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TunnelEndpoint::HandleFollowOnFragment (uint32_t msgID, bool isLastFragment, const TunnelMessageBlockEx& m)
|
||||||
|
{
|
||||||
|
auto fragment = m.data->GetBuffer ();
|
||||||
|
auto size = m.data->GetLength ();
|
||||||
|
auto it = m_IncompleteMessages.find (msgID);
|
||||||
|
if (it != m_IncompleteMessages.end())
|
||||||
|
{
|
||||||
|
if (m.nextFragmentNum == it->second.nextFragmentNum)
|
||||||
|
{
|
||||||
|
I2NPMessage * incompleteMessage = it->second.data;
|
||||||
|
if (incompleteMessage->len + size < I2NP_MAX_MESSAGE_SIZE) // check if messega is not too long
|
||||||
|
{
|
||||||
|
memcpy (incompleteMessage->buf + incompleteMessage->len, fragment, size); // concatenate fragment
|
||||||
|
incompleteMessage->len += size;
|
||||||
|
if (isLastFragment)
|
||||||
|
{
|
||||||
|
// message complete
|
||||||
|
HandleNextMessage (it->second);
|
||||||
|
m_IncompleteMessages.erase (it);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
it->second.nextFragmentNum++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LogPrint ("Fragment ", m.nextFragmentNum, " of message ", msgID, "exceeds max I2NP message size. Message dropped");
|
||||||
|
i2p::DeleteI2NPMessage (it->second.data);
|
||||||
|
m_IncompleteMessages.erase (it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LogPrint ("Unexpected fragment ", m.nextFragmentNum, " instead ", it->second.nextFragmentNum, " of message ", msgID, ". Discarded");
|
||||||
|
i2p::DeleteI2NPMessage (it->second.data);
|
||||||
|
m_IncompleteMessages.erase (it); // TODO: store unexpected fragment for a while
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
LogPrint ("First fragment of message ", msgID, " not found. Discarded");
|
||||||
|
|
||||||
|
i2p::DeleteI2NPMessage (m.data);
|
||||||
|
}
|
||||||
|
|
||||||
void TunnelEndpoint::HandleNextMessage (const TunnelMessageBlock& msg)
|
void TunnelEndpoint::HandleNextMessage (const TunnelMessageBlock& msg)
|
||||||
{
|
{
|
||||||
LogPrint ("TunnelMessage: handle fragment of ", msg.data->GetLength ()," bytes. Msg type ", (int)msg.data->GetHeader()->typeID);
|
LogPrint ("TunnelMessage: handle fragment of ", msg.data->GetLength ()," bytes. Msg type ", (int)msg.data->GetHeader()->typeID);
|
||||||
@ -166,7 +196,28 @@ namespace tunnel
|
|||||||
i2p::transports.SendMessage (msg.hash, i2p::CreateTunnelGatewayMsg (msg.tunnelID, msg.data));
|
i2p::transports.SendMessage (msg.hash, i2p::CreateTunnelGatewayMsg (msg.tunnelID, msg.data));
|
||||||
break;
|
break;
|
||||||
case eDeliveryTypeRouter:
|
case eDeliveryTypeRouter:
|
||||||
i2p::transports.SendMessage (msg.hash, msg.data);
|
if (msg.hash == i2p::context.GetRouterInfo ().GetIdentHash ()) // check if message is sent to us
|
||||||
|
i2p::HandleI2NPMessage (msg.data);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// to somebody else
|
||||||
|
if (!m_IsInbound) // outbound transit tunnel
|
||||||
|
{
|
||||||
|
if (msg.data->GetHeader()->typeID == eI2NPDatabaseStore)
|
||||||
|
{
|
||||||
|
// catch RI
|
||||||
|
auto ds = NewI2NPMessage ();
|
||||||
|
*ds = *(msg.data);
|
||||||
|
i2p::data::netdb.PostI2NPMsg (ds);
|
||||||
|
}
|
||||||
|
i2p::transports.SendMessage (msg.hash, msg.data);
|
||||||
|
}
|
||||||
|
else // we shouldn't send this message. possible leakage
|
||||||
|
{
|
||||||
|
LogPrint ("Message to another router arrived from an inbound tunnel. Dropped");
|
||||||
|
i2p::DeleteI2NPMessage (msg.data);
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
LogPrint ("TunnelMessage: Unknown delivery type ", (int)msg.deliveryType);
|
LogPrint ("TunnelMessage: Unknown delivery type ", (int)msg.deliveryType);
|
||||||
|
@ -13,25 +13,28 @@ namespace tunnel
|
|||||||
{
|
{
|
||||||
class TunnelEndpoint
|
class TunnelEndpoint
|
||||||
{
|
{
|
||||||
|
struct TunnelMessageBlockEx: public TunnelMessageBlock
|
||||||
|
{
|
||||||
|
uint8_t nextFragmentNum;
|
||||||
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
TunnelEndpoint (): m_NumReceivedBytes (0) {};
|
TunnelEndpoint (bool isInbound): m_IsInbound (isInbound), m_NumReceivedBytes (0) {};
|
||||||
|
~TunnelEndpoint ();
|
||||||
size_t GetNumReceivedBytes () const { return m_NumReceivedBytes; };
|
size_t GetNumReceivedBytes () const { return m_NumReceivedBytes; };
|
||||||
|
|
||||||
void HandleDecryptedTunnelDataMsg (I2NPMessage * msg);
|
void HandleDecryptedTunnelDataMsg (I2NPMessage * msg);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
void HandleFollowOnFragment (uint32_t msgID, bool isLastFragment, const TunnelMessageBlockEx& m);
|
||||||
void HandleNextMessage (const TunnelMessageBlock& msg);
|
void HandleNextMessage (const TunnelMessageBlock& msg);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
struct TunnelMessageBlockEx: public TunnelMessageBlock
|
|
||||||
{
|
|
||||||
uint8_t nextFragmentNum;
|
|
||||||
};
|
|
||||||
|
|
||||||
std::map<uint32_t, TunnelMessageBlockEx> m_IncompleteMessages;
|
std::map<uint32_t, TunnelMessageBlockEx> m_IncompleteMessages;
|
||||||
|
bool m_IsInbound;
|
||||||
size_t m_NumReceivedBytes;
|
size_t m_NumReceivedBytes;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -107,13 +107,10 @@ namespace tunnel
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::vector<I2NPMessage *> TunnelGatewayBuffer::GetTunnelDataMsgs ()
|
void TunnelGatewayBuffer::ClearTunnelDataMsgs ()
|
||||||
{
|
{
|
||||||
CompleteCurrentTunnelDataMessage ();
|
m_TunnelDataMsgs.clear ();
|
||||||
std::vector<I2NPMessage *> ret = m_TunnelDataMsgs; // TODO: implement it better
|
}
|
||||||
m_TunnelDataMsgs.clear ();
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
void TunnelGatewayBuffer::CreateCurrentTunnelDataMessage ()
|
void TunnelGatewayBuffer::CreateCurrentTunnelDataMessage ()
|
||||||
{
|
{
|
||||||
@ -162,6 +159,7 @@ namespace tunnel
|
|||||||
|
|
||||||
void TunnelGateway::SendBuffer ()
|
void TunnelGateway::SendBuffer ()
|
||||||
{
|
{
|
||||||
|
m_Buffer.CompleteCurrentTunnelDataMessage ();
|
||||||
auto tunnelMsgs = m_Buffer.GetTunnelDataMsgs ();
|
auto tunnelMsgs = m_Buffer.GetTunnelDataMsgs ();
|
||||||
for (auto tunnelMsg : tunnelMsgs)
|
for (auto tunnelMsg : tunnelMsgs)
|
||||||
{
|
{
|
||||||
@ -170,6 +168,7 @@ namespace tunnel
|
|||||||
i2p::transports.SendMessage (m_Tunnel->GetNextIdentHash (), tunnelMsg);
|
i2p::transports.SendMessage (m_Tunnel->GetNextIdentHash (), tunnelMsg);
|
||||||
m_NumSentBytes += TUNNEL_DATA_MSG_SIZE;
|
m_NumSentBytes += TUNNEL_DATA_MSG_SIZE;
|
||||||
}
|
}
|
||||||
|
m_Buffer.ClearTunnelDataMsgs ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,12 +16,13 @@ namespace tunnel
|
|||||||
TunnelGatewayBuffer (uint32_t tunnelID): m_TunnelID (tunnelID),
|
TunnelGatewayBuffer (uint32_t tunnelID): m_TunnelID (tunnelID),
|
||||||
m_CurrentTunnelDataMsg (nullptr), m_RemainingSize (0) {};
|
m_CurrentTunnelDataMsg (nullptr), m_RemainingSize (0) {};
|
||||||
void PutI2NPMsg (const TunnelMessageBlock& block);
|
void PutI2NPMsg (const TunnelMessageBlock& block);
|
||||||
const std::vector<I2NPMessage *> GetTunnelDataMsgs ();
|
const std::vector<I2NPMessage *>& GetTunnelDataMsgs () const { return m_TunnelDataMsgs; };
|
||||||
|
void ClearTunnelDataMsgs ();
|
||||||
|
void CompleteCurrentTunnelDataMessage ();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void CreateCurrentTunnelDataMessage ();
|
void CreateCurrentTunnelDataMessage ();
|
||||||
void CompleteCurrentTunnelDataMessage ();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
@ -37,11 +38,11 @@ namespace tunnel
|
|||||||
|
|
||||||
TunnelGateway (TunnelBase * tunnel):
|
TunnelGateway (TunnelBase * tunnel):
|
||||||
m_Tunnel (tunnel), m_Buffer (tunnel->GetNextTunnelID ()), m_NumSentBytes (0) {};
|
m_Tunnel (tunnel), m_Buffer (tunnel->GetNextTunnelID ()), m_NumSentBytes (0) {};
|
||||||
void SendTunnelDataMsg (const TunnelMessageBlock& block);
|
void SendTunnelDataMsg (const TunnelMessageBlock& block);
|
||||||
void PutTunnelDataMsg (const TunnelMessageBlock& block);
|
void PutTunnelDataMsg (const TunnelMessageBlock& block);
|
||||||
void SendBuffer ();
|
void SendBuffer ();
|
||||||
size_t GetNumSentBytes () const { return m_NumSentBytes; };
|
size_t GetNumSentBytes () const { return m_NumSentBytes; };
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
TunnelBase * m_Tunnel;
|
TunnelBase * m_Tunnel;
|
||||||
|
@ -11,7 +11,7 @@ namespace i2p
|
|||||||
namespace tunnel
|
namespace tunnel
|
||||||
{
|
{
|
||||||
TunnelPool::TunnelPool (i2p::data::LocalDestination& localDestination, int numHops, int numTunnels):
|
TunnelPool::TunnelPool (i2p::data::LocalDestination& localDestination, int numHops, int numTunnels):
|
||||||
m_LocalDestination (localDestination), m_NumHops (numHops), m_NumTunnels (numTunnels), m_LastOutboundTunnel (nullptr)
|
m_LocalDestination (localDestination), m_NumHops (numHops), m_NumTunnels (numTunnels)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -34,8 +34,10 @@ namespace tunnel
|
|||||||
{
|
{
|
||||||
expiredTunnel->SetTunnelPool (nullptr);
|
expiredTunnel->SetTunnelPool (nullptr);
|
||||||
m_InboundTunnels.erase (expiredTunnel);
|
m_InboundTunnels.erase (expiredTunnel);
|
||||||
|
for (auto it: m_Tests)
|
||||||
|
if (it.second.second == expiredTunnel) it.second.second = nullptr;
|
||||||
|
|
||||||
}
|
}
|
||||||
m_LocalDestination.UpdateLeaseSet ();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TunnelPool::TunnelCreated (OutboundTunnel * createdTunnel)
|
void TunnelPool::TunnelCreated (OutboundTunnel * createdTunnel)
|
||||||
@ -49,9 +51,9 @@ namespace tunnel
|
|||||||
{
|
{
|
||||||
expiredTunnel->SetTunnelPool (nullptr);
|
expiredTunnel->SetTunnelPool (nullptr);
|
||||||
m_OutboundTunnels.erase (expiredTunnel);
|
m_OutboundTunnels.erase (expiredTunnel);
|
||||||
|
for (auto it: m_Tests)
|
||||||
|
if (it.second.first == expiredTunnel) it.second.first = nullptr;
|
||||||
}
|
}
|
||||||
if (expiredTunnel == m_LastOutboundTunnel)
|
|
||||||
m_LastOutboundTunnel = nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<InboundTunnel *> TunnelPool::GetInboundTunnels (int num) const
|
std::vector<InboundTunnel *> TunnelPool::GetInboundTunnels (int num) const
|
||||||
@ -72,19 +74,7 @@ namespace tunnel
|
|||||||
|
|
||||||
OutboundTunnel * TunnelPool::GetNextOutboundTunnel ()
|
OutboundTunnel * TunnelPool::GetNextOutboundTunnel ()
|
||||||
{
|
{
|
||||||
if (m_OutboundTunnels.empty ()) return nullptr;
|
return GetNextTunnel (m_OutboundTunnels);
|
||||||
auto tunnel = *m_OutboundTunnels.begin ();
|
|
||||||
if (m_LastOutboundTunnel && tunnel == m_LastOutboundTunnel)
|
|
||||||
{
|
|
||||||
for (auto it: m_OutboundTunnels)
|
|
||||||
if (it != m_LastOutboundTunnel && !it->IsFailed ())
|
|
||||||
{
|
|
||||||
tunnel = it;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
m_LastOutboundTunnel = tunnel;
|
|
||||||
return tunnel;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
InboundTunnel * TunnelPool::GetNextInboundTunnel ()
|
InboundTunnel * TunnelPool::GetNextInboundTunnel ()
|
||||||
@ -118,9 +108,27 @@ namespace tunnel
|
|||||||
for (auto it: m_Tests)
|
for (auto it: m_Tests)
|
||||||
{
|
{
|
||||||
LogPrint ("Tunnel test ", (int)it.first, " failed");
|
LogPrint ("Tunnel test ", (int)it.first, " failed");
|
||||||
// both outbound and inbound tunnels considered as invalid
|
// if test failed again with another tunnel we consider it failed
|
||||||
it.second.first->SetFailed (true);
|
if (it.second.first)
|
||||||
it.second.second->SetFailed (true);
|
{
|
||||||
|
if (it.second.first->GetState () == eTunnelStateTestFailed)
|
||||||
|
{
|
||||||
|
it.second.first->SetState (eTunnelStateFailed);
|
||||||
|
m_OutboundTunnels.erase (it.second.first);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
it.second.first->SetState (eTunnelStateTestFailed);
|
||||||
|
}
|
||||||
|
if (it.second.second)
|
||||||
|
{
|
||||||
|
if (it.second.second->GetState () == eTunnelStateTestFailed)
|
||||||
|
{
|
||||||
|
it.second.second->SetState (eTunnelStateFailed);
|
||||||
|
m_InboundTunnels.erase (it.second.second);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
it.second.second->SetState (eTunnelStateTestFailed);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
m_Tests.clear ();
|
m_Tests.clear ();
|
||||||
auto it1 = m_OutboundTunnels.begin ();
|
auto it1 = m_OutboundTunnels.begin ();
|
||||||
@ -139,7 +147,7 @@ namespace tunnel
|
|||||||
it2++;
|
it2++;
|
||||||
}
|
}
|
||||||
if (!failed)
|
if (!failed)
|
||||||
{
|
{
|
||||||
uint32_t msgID = rnd.GenerateWord32 ();
|
uint32_t msgID = rnd.GenerateWord32 ();
|
||||||
m_Tests[msgID] = std::make_pair (*it1, *it2);
|
m_Tests[msgID] = std::make_pair (*it1, *it2);
|
||||||
(*it1)->SendTunnelDataMsg ((*it2)->GetNextIdentHash (), (*it2)->GetNextTunnelID (),
|
(*it1)->SendTunnelDataMsg ((*it2)->GetNextIdentHash (), (*it2)->GetNextTunnelID (),
|
||||||
@ -155,6 +163,9 @@ namespace tunnel
|
|||||||
auto it = m_Tests.find (be32toh (deliveryStatus->msgID));
|
auto it = m_Tests.find (be32toh (deliveryStatus->msgID));
|
||||||
if (it != m_Tests.end ())
|
if (it != m_Tests.end ())
|
||||||
{
|
{
|
||||||
|
// restore from test failed state if any
|
||||||
|
it->second.first->SetState (eTunnelStateEstablished);
|
||||||
|
it->second.second->SetState (eTunnelStateEstablished);
|
||||||
LogPrint ("Tunnel test ", it->first, " successive. ", i2p::util::GetMillisecondsSinceEpoch () - be64toh (deliveryStatus->timestamp), " milliseconds");
|
LogPrint ("Tunnel test ", it->first, " successive. ", i2p::util::GetMillisecondsSinceEpoch () - be64toh (deliveryStatus->timestamp), " milliseconds");
|
||||||
m_Tests.erase (it);
|
m_Tests.erase (it);
|
||||||
}
|
}
|
||||||
@ -168,17 +179,28 @@ namespace tunnel
|
|||||||
OutboundTunnel * outboundTunnel = m_OutboundTunnels.size () > 0 ?
|
OutboundTunnel * outboundTunnel = m_OutboundTunnels.size () > 0 ?
|
||||||
*m_OutboundTunnels.begin () : tunnels.GetNextOutboundTunnel ();
|
*m_OutboundTunnels.begin () : tunnels.GetNextOutboundTunnel ();
|
||||||
LogPrint ("Creating destination inbound tunnel...");
|
LogPrint ("Creating destination inbound tunnel...");
|
||||||
auto firstHop = i2p::data::netdb.GetRandomRouter (outboundTunnel ? outboundTunnel->GetEndpointRouter () : nullptr);
|
const i2p::data::RouterInfo * prevHop = &i2p::context.GetRouterInfo ();
|
||||||
auto secondHop = outboundTunnel ? outboundTunnel->GetTunnelConfig ()->GetFirstHop ()->router : nullptr;
|
std::vector<const i2p::data::RouterInfo *> hops;
|
||||||
if (!secondHop || secondHop->GetIdentHash () == i2p::context.GetIdentHash ())
|
int numHops = m_NumHops;
|
||||||
secondHop = i2p::data::netdb.GetRandomRouter (firstHop);
|
if (outboundTunnel)
|
||||||
auto * tunnel = tunnels.CreateTunnel<InboundTunnel> (
|
{
|
||||||
new TunnelConfig (std::vector<const i2p::data::RouterInfo *>
|
// last hop
|
||||||
{
|
auto hop = outboundTunnel->GetTunnelConfig ()->GetFirstHop ()->router;
|
||||||
firstHop,
|
if (hop->GetIdentHash () != i2p::context.GetIdentHash ()) // outbound shouldn't be zero-hop tunnel
|
||||||
secondHop
|
{
|
||||||
}),
|
prevHop = hop;
|
||||||
outboundTunnel);
|
hops.push_back (prevHop);
|
||||||
|
numHops--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (int i = 0; i < numHops; i++)
|
||||||
|
{
|
||||||
|
auto hop = i2p::data::netdb.GetRandomRouter (prevHop);
|
||||||
|
prevHop = hop;
|
||||||
|
hops.push_back (hop);
|
||||||
|
}
|
||||||
|
std::reverse (hops.begin (), hops.end ());
|
||||||
|
auto * tunnel = tunnels.CreateTunnel<InboundTunnel> (new TunnelConfig (hops), outboundTunnel);
|
||||||
tunnel->SetTunnelPool (this);
|
tunnel->SetTunnelPool (this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,6 +28,7 @@ namespace tunnel
|
|||||||
|
|
||||||
const uint8_t * GetEncryptionPrivateKey () const { return m_LocalDestination.GetEncryptionPrivateKey (); };
|
const uint8_t * GetEncryptionPrivateKey () const { return m_LocalDestination.GetEncryptionPrivateKey (); };
|
||||||
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; };
|
||||||
bool IsExploratory () const { return m_LocalDestination.GetIdentHash () == i2p::context.GetIdentHash (); };
|
bool IsExploratory () const { return m_LocalDestination.GetIdentHash () == i2p::context.GetIdentHash (); };
|
||||||
|
|
||||||
void CreateTunnels ();
|
void CreateTunnels ();
|
||||||
@ -57,7 +58,6 @@ namespace tunnel
|
|||||||
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;
|
||||||
std::map<uint32_t, std::pair<OutboundTunnel *, InboundTunnel *> > m_Tests;
|
std::map<uint32_t, std::pair<OutboundTunnel *, InboundTunnel *> > m_Tests;
|
||||||
OutboundTunnel * m_LastOutboundTunnel;
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -43,6 +43,7 @@
|
|||||||
<ClCompile Include="..\TunnelPool.cpp" />
|
<ClCompile Include="..\TunnelPool.cpp" />
|
||||||
<ClCompile Include="..\UPnP.cpp" />
|
<ClCompile Include="..\UPnP.cpp" />
|
||||||
<ClCompile Include="..\util.cpp" />
|
<ClCompile Include="..\util.cpp" />
|
||||||
|
<ClCompile Include="..\SOCKS.cpp" />
|
||||||
<ClCompile Include="Win32Service.cpp" />
|
<ClCompile Include="Win32Service.cpp" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
@ -80,6 +81,7 @@
|
|||||||
<ClInclude Include="..\TunnelPool.h" />
|
<ClInclude Include="..\TunnelPool.h" />
|
||||||
<ClInclude Include="..\UPnP.h" />
|
<ClInclude Include="..\UPnP.h" />
|
||||||
<ClInclude Include="..\util.h" />
|
<ClInclude Include="..\util.h" />
|
||||||
|
<ClInclude Include="..\SOCKS.h" />
|
||||||
<ClInclude Include="Win32Service.h" />
|
<ClInclude Include="Win32Service.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<PropertyGroup Label="Globals">
|
<PropertyGroup Label="Globals">
|
||||||
@ -156,4 +158,4 @@
|
|||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
<ImportGroup Label="ExtensionTargets">
|
<ImportGroup Label="ExtensionTargets">
|
||||||
</ImportGroup>
|
</ImportGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
@ -75,6 +75,9 @@
|
|||||||
<ClCompile Include="..\I2PEndian.cpp">
|
<ClCompile Include="..\I2PEndian.cpp">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\SOCKS.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="..\SSU.cpp">
|
<ClCompile Include="..\SSU.cpp">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
@ -194,6 +197,9 @@
|
|||||||
<ClInclude Include="..\I2PEndian.h">
|
<ClInclude Include="..\I2PEndian.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\SOCKS.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
<ClInclude Include="..\SSU.h">
|
<ClInclude Include="..\SSU.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
@ -225,4 +231,4 @@
|
|||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
2
aes.cpp
2
aes.cpp
@ -313,6 +313,7 @@ namespace crypto
|
|||||||
);
|
);
|
||||||
#else
|
#else
|
||||||
m_IVEncryption.Encrypt ((ChipherBlock *)payload, (ChipherBlock *)payload); // iv
|
m_IVEncryption.Encrypt ((ChipherBlock *)payload, (ChipherBlock *)payload); // iv
|
||||||
|
m_LayerEncryption.SetIV (payload);
|
||||||
m_LayerEncryption.Encrypt (payload + 16, i2p::tunnel::TUNNEL_DATA_ENCRYPTED_SIZE, payload + 16); // data
|
m_LayerEncryption.Encrypt (payload + 16, i2p::tunnel::TUNNEL_DATA_ENCRYPTED_SIZE, payload + 16); // data
|
||||||
m_IVEncryption.Encrypt ((ChipherBlock *)payload, (ChipherBlock *)payload); // double iv
|
m_IVEncryption.Encrypt ((ChipherBlock *)payload, (ChipherBlock *)payload); // double iv
|
||||||
#endif
|
#endif
|
||||||
@ -348,6 +349,7 @@ namespace crypto
|
|||||||
);
|
);
|
||||||
#else
|
#else
|
||||||
m_IVDecryption.Decrypt ((ChipherBlock *)payload, (ChipherBlock *)payload); // iv
|
m_IVDecryption.Decrypt ((ChipherBlock *)payload, (ChipherBlock *)payload); // iv
|
||||||
|
m_LayerDecryption.SetIV (payload);
|
||||||
m_LayerDecryption.Decrypt (payload + 16, i2p::tunnel::TUNNEL_DATA_ENCRYPTED_SIZE, payload + 16); // data
|
m_LayerDecryption.Decrypt (payload + 16, i2p::tunnel::TUNNEL_DATA_ENCRYPTED_SIZE, payload + 16); // data
|
||||||
m_IVDecryption.Decrypt ((ChipherBlock *)payload, (ChipherBlock *)payload); // double iv
|
m_IVDecryption.Decrypt ((ChipherBlock *)payload, (ChipherBlock *)payload); // double iv
|
||||||
#endif
|
#endif
|
||||||
|
@ -38,7 +38,9 @@ set ( SOURCES
|
|||||||
TunnelEndpoint.cpp
|
TunnelEndpoint.cpp
|
||||||
TunnelPool.cpp
|
TunnelPool.cpp
|
||||||
util.cpp
|
util.cpp
|
||||||
|
aes.cpp
|
||||||
Daemon.cpp
|
Daemon.cpp
|
||||||
|
SOCKS.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
set ( HEADERS
|
set ( HEADERS
|
||||||
@ -67,7 +69,9 @@ set ( HEADERS
|
|||||||
TunnelEndpoint.h
|
TunnelEndpoint.h
|
||||||
TunnelPool.h
|
TunnelPool.h
|
||||||
util.h
|
util.h
|
||||||
|
aes.h
|
||||||
Daemon.h
|
Daemon.h
|
||||||
|
SOCKS.h
|
||||||
)
|
)
|
||||||
|
|
||||||
if (WIN32)
|
if (WIN32)
|
||||||
|
@ -1,83 +0,0 @@
|
|||||||
TEMPLATE = app
|
|
||||||
CONFIG += console
|
|
||||||
CONFIG -= app_bundle
|
|
||||||
CONFIG -= qt
|
|
||||||
|
|
||||||
TARGET = ./../../i2pd_qt
|
|
||||||
|
|
||||||
QMAKE_CXXFLAGS += -std=c++0x
|
|
||||||
|
|
||||||
LIBS += -lcrypto++
|
|
||||||
LIBS += \
|
|
||||||
-lboost_system\
|
|
||||||
-lboost_filesystem\
|
|
||||||
-lboost_regex\
|
|
||||||
-lboost_program_options\
|
|
||||||
-lpthread
|
|
||||||
|
|
||||||
SOURCES += \
|
|
||||||
../LeaseSet.cpp \
|
|
||||||
../i2p.cpp \
|
|
||||||
../HTTPServer.cpp \
|
|
||||||
../HTTPProxy.cpp \
|
|
||||||
../Garlic.cpp \
|
|
||||||
../base64.cpp \
|
|
||||||
../AddressBook.cpp \
|
|
||||||
../util.cpp \
|
|
||||||
../UPnP.cpp \
|
|
||||||
../TunnelPool.cpp \
|
|
||||||
../TunnelGateway.cpp \
|
|
||||||
../TunnelEndpoint.cpp \
|
|
||||||
../Tunnel.cpp \
|
|
||||||
../Transports.cpp \
|
|
||||||
../TransitTunnel.cpp \
|
|
||||||
../Streaming.cpp \
|
|
||||||
../SSU.cpp \
|
|
||||||
../RouterInfo.cpp \
|
|
||||||
../RouterContext.cpp \
|
|
||||||
../Reseed.cpp \
|
|
||||||
../NTCPSession.cpp \
|
|
||||||
../NetDb.cpp \
|
|
||||||
../Log.cpp \
|
|
||||||
../Identity.cpp \
|
|
||||||
../I2NPProtocol.cpp
|
|
||||||
|
|
||||||
HEADERS += \
|
|
||||||
../LeaseSet.h \
|
|
||||||
../Identity.h \
|
|
||||||
../HTTPServer.h \
|
|
||||||
../HTTPProxy.h \
|
|
||||||
../hmac.h \
|
|
||||||
../Garlic.h \
|
|
||||||
../ElGamal.h \
|
|
||||||
../CryptoConst.h \
|
|
||||||
../base64.h \
|
|
||||||
../AddressBook.h \
|
|
||||||
../util.h \
|
|
||||||
../UPnP.h \
|
|
||||||
../TunnelPool.h \
|
|
||||||
../TunnelGateway.h \
|
|
||||||
../TunnelEndpoint.h \
|
|
||||||
../TunnelConfig.h \
|
|
||||||
../TunnelBase.h \
|
|
||||||
../Tunnel.h \
|
|
||||||
../Transports.h \
|
|
||||||
../TransitTunnel.h \
|
|
||||||
../Timestamp.h \
|
|
||||||
../Streaming.h \
|
|
||||||
../SSU.h \
|
|
||||||
../RouterInfo.h \
|
|
||||||
../RouterContext.h \
|
|
||||||
../Reseed.h \
|
|
||||||
../Queue.h \
|
|
||||||
../NTCPSession.h \
|
|
||||||
../NetDb.h \
|
|
||||||
../Log.h \
|
|
||||||
../LittleBigEndian.h \
|
|
||||||
../I2PEndian.h \
|
|
||||||
../I2NPProtocol.h
|
|
||||||
|
|
||||||
OTHER_FILES += \
|
|
||||||
../README.md \
|
|
||||||
../Makefile \
|
|
||||||
../LICENSE
|
|
32
contrib/certificates/reseed/backup_at_mail.i2p.crt
Normal file
32
contrib/certificates/reseed/backup_at_mail.i2p.crt
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIFfTCCA2WgAwIBAgIEOprmhjANBgkqhkiG9w0BAQ0FADBvMQswCQYDVQQGEwJY
|
||||||
|
WDELMAkGA1UECBMCWFgxCzAJBgNVBAcTAlhYMR4wHAYDVQQKExVJMlAgQW5vbnlt
|
||||||
|
b3VzIE5ldHdvcmsxDDAKBgNVBAsTA0kyUDEYMBYGA1UEAwwPYmFja3VwQG1haWwu
|
||||||
|
aTJwMB4XDTEzMTAxMzEzNDQ1NVoXDTIzMTAxMzEzNDQ1NVowbzELMAkGA1UEBhMC
|
||||||
|
WFgxCzAJBgNVBAgTAlhYMQswCQYDVQQHEwJYWDEeMBwGA1UEChMVSTJQIEFub255
|
||||||
|
bW91cyBOZXR3b3JrMQwwCgYDVQQLEwNJMlAxGDAWBgNVBAMMD2JhY2t1cEBtYWls
|
||||||
|
LmkycDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAIoAkobXwk/Enf1d
|
||||||
|
roHyqCyvcJfZJVTwb/LgYWAvCBMCr+RGqlSgtk3g69Y3I0xU08fD2kGt3r5Pwsbr
|
||||||
|
omXIbJAcccyLqmQ5QX6QgL+X9VpMDp9C4h2RogCrqLBAWw4cuZ4RS9VCpP1Yis7H
|
||||||
|
uejYqENP86p7BsRnuW/4cYnfunAdMpss4LpRGQXt1nTX+kfgCYgnKFbFqwAHt7yV
|
||||||
|
Ds+Pe6FuBHPlp+sc1amKRcUnSvhXLsv43VicnT7xYL/kUsN83wrtHA3B4aGDx3aA
|
||||||
|
3/EzuRmIXQB0BlTZILMEyYwG/nc4OsW82QYrvEZ9BIg9A4lF/wS/KZCICPxLF2zo
|
||||||
|
dGjnmlgkiA4s8eO+va/ElHyELjckVXqmG1eXHhSkEsDvOQJy01IUuwLinvq7cUbJ
|
||||||
|
HfJBZJllEg+sLDCv3FkEqN+XjBNFfQN4oNew4w6IPY6YH1INVB9LL0Cmdu4DudLv
|
||||||
|
TY8OcI8eSfez3hmm+pYQ23PJRYYnvRDnRECyIWBegkckWRh8U/WvZUYUvETK6EDl
|
||||||
|
/0KpTtfzX6MqHA5D6bTAB8Y3ijGMLrZ/B5vj5yCoZbLiGme9X2moR2k1LEhdhtzV
|
||||||
|
exsqezCpg6dn48FTX7mHjvR5/r4kz2jqBGmdPUWIIxnjFUzDUK3llVQiHihleHpe
|
||||||
|
jL4LqnhBGKWFRTaVwaIkBG4zAfIzAgMBAAGjITAfMB0GA1UdDgQWBBQNkfW7bSMl
|
||||||
|
1/4KDbgwrkf9x1Zu/TANBgkqhkiG9w0BAQ0FAAOCAgEAGg3a3rTf0EznQocmio0T
|
||||||
|
5gCoL0n8h6yKW/PyPAIELrd9wiYjhJFcWvMTcJJJnVqmAL5vpvhaAFVtAfx70MGa
|
||||||
|
0DZ7FvytK5hEfF4IqOFDyEEVGJR5rIpVK4MeI1nmwEsxdbW+FhODjtRzgYO8XBME
|
||||||
|
Xj4aY1FWg9vxc3reUj6PSFsZtsB0aLiRgL9JDovJIiRw0Uqr1v2wXBte5yVCxDge
|
||||||
|
vTREZtpK4cKetoOa68pwSXI32JwKE18j6bfdKVBCcYQKlKP/3gHGduaDrQv3w32S
|
||||||
|
DRym5s6MREeTUOtAw4wq46KpdOX8yyAqJPrCfMwS6ORd3t+egqOw0PUnsqb97w4O
|
||||||
|
lUtrRYvb2cOj60SmRx4vJvItyuHbKqIK7o2e1RcUZPXYoAVx2ww4XB2Wk4D7LSAs
|
||||||
|
cS7nLj8yAqzJ2qqtBzxu+zILJtkVa12dKF0xmS0BxBp4sCYiBtmAVE8AWQqEuSHA
|
||||||
|
FrMWqoXcjcfdvvyX487FFWWUE7ZBIn0hee2sK9J9+SPtqczJaN7TF3K3nzo65WJG
|
||||||
|
1epltmq2Ugjb67Gz7v4y7H23DJ/qhm8yLtCHTj69HTta5I08j6Kut924WLZaiMO/
|
||||||
|
4YoEL5AE63X0sxYibKFQiq7FW5nUJA280GRlY3xSMFzlB2ggazrUV3YAWVDhfdnI
|
||||||
|
flpzWXkFM2D36OUaubfe9YY=
|
||||||
|
-----END CERTIFICATE-----
|
32
contrib/certificates/reseed/echelon_at_mail.i2p.crt
Normal file
32
contrib/certificates/reseed/echelon_at_mail.i2p.crt
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
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
|
||||||
|
/hCfobYS9FLpJCFkIMcnYrhM8g==
|
||||||
|
-----END CERTIFICATE-----
|
32
contrib/certificates/reseed/matt_at_drollette.com.crt
Normal file
32
contrib/certificates/reseed/matt_at_drollette.com.crt
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
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
|
||||||
|
fss8T6gOo19esb/KEMZGZE4pAApakWM=
|
||||||
|
-----END CERTIFICATE-----
|
32
contrib/certificates/reseed/meeh_at_mail.i2p.crt
Normal file
32
contrib/certificates/reseed/meeh_at_mail.i2p.crt
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
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
|
||||||
|
o3eNsanvTU+TIFBh2Q==
|
||||||
|
-----END CERTIFICATE-----
|
32
contrib/certificates/reseed/sindu_at_mail.i2p.crt
Normal file
32
contrib/certificates/reseed/sindu_at_mail.i2p.crt
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
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
|
||||||
|
WX89Xn2UyQf5kHifiDKL
|
||||||
|
-----END CERTIFICATE-----
|
31
contrib/certificates/reseed/swat_at_mail.i2p.crt
Normal file
31
contrib/certificates/reseed/swat_at_mail.i2p.crt
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIFVjCCAz6gAwIBAgIEU71jgDANBgkqhkiG9w0BAQ0FADBtMQswCQYDVQQGEwJY
|
||||||
|
WDELMAkGA1UECBMCWFgxCzAJBgNVBAcTAlhYMR4wHAYDVQQKExVJMlAgQW5vbnlt
|
||||||
|
b3VzIE5ldHdvcmsxDDAKBgNVBAsTA0kyUDEWMBQGA1UEAwwNc3dhdEBtYWlsLmky
|
||||||
|
cDAeFw0xNDA3MDkxNTQ1MDRaFw0yNDA3MDgxNTQ1MDRaMG0xCzAJBgNVBAYTAlhY
|
||||||
|
MQswCQYDVQQIEwJYWDELMAkGA1UEBxMCWFgxHjAcBgNVBAoTFUkyUCBBbm9ueW1v
|
||||||
|
dXMgTmV0d29yazEMMAoGA1UECxMDSTJQMRYwFAYDVQQDDA1zd2F0QG1haWwuaTJw
|
||||||
|
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAjSj53hsbTqtzbnlf5LbR
|
||||||
|
HmfdC2br9QZaB9e5IQKprlTptdzqTrt2LRS6ZaJ06BKJgX3AfLflvyeUDUPoyg63
|
||||||
|
I9a1kb1AsrcxvMkHXTUwPaO09caO5/CiQ3zx/iuTl4e0MmGe3cz7jsvZNdOVH0ba
|
||||||
|
B691GB2UBq2QjobGx01qjWtACCmoQIcEur2ns/l+VzAextBL70dSPN6EJAonQnWc
|
||||||
|
JvHf1vhXp5DWasaIovm8haNo48QpCo7NllsAjiONQM9rrJITvzFG9hX9cv/B1Kr4
|
||||||
|
LCebTXv58ViXXFsnxYhktAFwP33fn1eCLraJ/BpaDR4+s3ovMC/7S+g5//+sQTd1
|
||||||
|
pR/kXx4BmZWZdzs083Z/2skQON75j/qnMhUQqpFCqUImm4lOhlIGbzFJ4GQM6VCR
|
||||||
|
V4BbvC3XuDc6vlivLzWpUEU7Kc6YnfGgi2G//ZCj2CAoR7qZs/n9997C8oAvGY5z
|
||||||
|
XGVC/GqIFHuFvnDfPDvxGovYjLJ0KrNtAmp2Rb5812glnVdPwbRYRUBg3ICbNey3
|
||||||
|
rmGPURDq0aHMTzX4gtM+/hCYYVnkzNMQvYuw9EZLZrK/XdM1a0U4kajZSKKJsTmW
|
||||||
|
uQwXSUVjTKQh//yL4zPoELucFk5r7apLePEm6aCeWuY2wVkR8KEFgNanwDckWQAm
|
||||||
|
Lk9r2t+Y/l2jS2NqBWFyr+cCAwEAATANBgkqhkiG9w0BAQ0FAAOCAgEAgFSquj/0
|
||||||
|
iZYpFI1XarSIVpGMo0WLAmb9GZCn5yoXSeE6eypI/hHhXA4Bjdk2Ae33pXPNcCV8
|
||||||
|
oT/gHj8943Wx7CTxty2zHzIsd92/HG2EG6U/HPp5l7yIJQaWoe/9tjQoaBhipZOK
|
||||||
|
+MiytkoBWkyXFqXnKQPExiadWB8axHtt66vrikOcSx6Ur3u5DPKybvY4fsuvo4+I
|
||||||
|
cLLgoueFm6I1WhmkVmjtm4k2yZ/Z3NEYjg52rv8NuYhRwK2JrQeRzMZv/zt5KhOt
|
||||||
|
05woHrzymjfFBu0M8uxX7EGZBIsc8zcEY7JL/NSMArw/QCgLU5bQF6+CsyxWUkt1
|
||||||
|
obMRXU1oS9GjC/1F0kw52NOz2qzBn9tZBc1zs8+GLpYBUf9KiUMFOfJpkr706VqC
|
||||||
|
orgxRYwncicq+de2PlesxJb3DNPFuAzUNzAqxcVYDoFPAiL1zCEl0nhBrbN+x93X
|
||||||
|
ojTfV3UlbMjMkQKveYJxsi5/+jO1dHIkXpzK4bwFwHmJ2RCa6PualWhuXldX6mR+
|
||||||
|
APoY6xeoPRlyKk+POrSwU+hywUudyPuFyzDMo8n1w4CyqL+/ky3YsLfGBM1phbb2
|
||||||
|
GEnZ0J1HW34Pnie1rzaCak+3RfaZsImCwh1xXl/H7Ka9bLeUIfOuipSSroctdaiG
|
||||||
|
84wIiEjxgjW2ldM37gTX2XtE/blB1YPIZ5U=
|
||||||
|
-----END CERTIFICATE-----
|
32
contrib/certificates/router/killyourtv_at_mail.i2p.crt
Normal file
32
contrib/certificates/router/killyourtv_at_mail.i2p.crt
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
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
|
||||||
|
749STYJRfZXdIe69M9zpM5unxENAsiPJgQ==
|
||||||
|
-----END CERTIFICATE-----
|
32
contrib/certificates/router/str4d_at_mail.i2p.crt
Normal file
32
contrib/certificates/router/str4d_at_mail.i2p.crt
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
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
|
||||||
|
hqQ7usTy3oaWD85MbJ0q
|
||||||
|
-----END CERTIFICATE-----
|
32
contrib/certificates/router/zzz_at_mail.i2p.crt
Normal file
32
contrib/certificates/router/zzz_at_mail.i2p.crt
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
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
|
||||||
|
pwvcQcjIzbUzEK0=
|
||||||
|
-----END CERTIFICATE-----
|
21
contrib/certificates/ssl/193.150.121.66.crt
Normal file
21
contrib/certificates/ssl/193.150.121.66.crt
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDgDCCAmgCCQCAKEkFUJcEezANBgkqhkiG9w0BAQUFADCBgTELMAkGA1UEBhMC
|
||||||
|
Tk8xDTALBgNVBAgMBE9zbG8xDTALBgNVBAcMBE9zbG8xDDAKBgNVBAoMA0kyUDEM
|
||||||
|
MAoGA1UECwwDSTJQMRcwFQYDVQQDDA4xOTMuMTUwLjEyMS42NjEfMB0GCSqGSIb3
|
||||||
|
DQEJARYQbWVlaEBpMnBtYWlsLm9yZzAeFw0xMzA2MjcxODM2MjhaFw0yMDA2MjUx
|
||||||
|
ODM2MjhaMIGBMQswCQYDVQQGEwJOTzENMAsGA1UECAwET3NsbzENMAsGA1UEBwwE
|
||||||
|
T3NsbzEMMAoGA1UECgwDSTJQMQwwCgYDVQQLDANJMlAxFzAVBgNVBAMMDjE5My4x
|
||||||
|
NTAuMTIxLjY2MR8wHQYJKoZIhvcNAQkBFhBtZWVoQGkycG1haWwub3JnMIIBIjAN
|
||||||
|
BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuBuFY4ZFvsbr5l1/s/GeUBLIWQLB
|
||||||
|
nqrRkonrwCyxgjSnnG1uz/Z5nf6QDUjiVnFKMXenLaDn4KCmEi4LjWQllhK9r6pj
|
||||||
|
BRkR7C0DTHq7WqfyvWnGSZZsOJDiH2vLlivV8N9oGdjxvv0N9No3AJcsmLYrxSLi
|
||||||
|
6/JF8xZ2HGuT/oWW6aWvpIOKpIqti865BJw5P5KgYAS24J8vHRFM3FA4dfLNTBA2
|
||||||
|
IGqPqYLQA+2zfOC4z01aArmcYnT1iJLT7krgKnr/BXdJfGQ2GjxkRSt8IwB6WmXA
|
||||||
|
byz6QdNYM/0eubi102/zpD/DrySTU2kc8xKjknGUqBJvVdsL+iLK98uJrQIDAQAB
|
||||||
|
MA0GCSqGSIb3DQEBBQUAA4IBAQCTimMu3X7+ztXxlIFhwGh42GfMjeBYT0NHOLAy
|
||||||
|
ZtQNRqhNvkl3jZ4ERPLxP99+bcAfCX0wgVpgD32OWEZopwveRyMImP8HfFr4NnZ+
|
||||||
|
edbM37fRYiVJv57kbi6O0rhEC7J5JF+fnCaZVLCuvYIrIXTdxTjvxuLhyan6Ej7V
|
||||||
|
7iGDJ8t16tpLVJgcXfRg+dvAa6aDOK6x3w78j0bvh6rhvpOd9sW/Nk3LBKP4Xgkx
|
||||||
|
PHkqm3hNfDIu8Hubeav9SA1kLVMS/uce52VyYMEDauObfC65ds0GRmCtYhZqMvj+
|
||||||
|
FFCbssLraVJE9Hi/ZKGu33jNngDCG+wG+nmleksMYE1yTSRt
|
||||||
|
-----END CERTIFICATE-----
|
44
contrib/certificates/ssl/cert.smartcom.org.crt
Normal file
44
contrib/certificates/ssl/cert.smartcom.org.crt
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIHyTCCBbGgAwIBAgIBATANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJJTDEW
|
||||||
|
MBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwg
|
||||||
|
Q2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNh
|
||||||
|
dGlvbiBBdXRob3JpdHkwHhcNMDYwOTE3MTk0NjM2WhcNMzYwOTE3MTk0NjM2WjB9
|
||||||
|
MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMi
|
||||||
|
U2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3Rh
|
||||||
|
cnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUA
|
||||||
|
A4ICDwAwggIKAoICAQDBiNsJvGxGfHiflXu1M5DycmLWwTYgIiRezul38kMKogZk
|
||||||
|
pMyONvg45iPwbm2xPN1yo4UcodM9tDMr0y+v/uqwQVlntsQGfQqedIXWeUyAN3rf
|
||||||
|
OQVSWff0G0ZDpNKFhdLDcfN1YjS6LIp/Ho/u7TTQEceWzVI9ujPW3U3eCztKS5/C
|
||||||
|
Ji/6tRYccjV3yjxd5srhJosaNnZcAdt0FCX+7bWgiA/deMotHweXMAEtcnn6RtYT
|
||||||
|
Kqi5pquDSR3l8u/d5AGOGAqPY1MWhWKpDhk6zLVmpsJrdAfkK+F2PrRt2PZE4XNi
|
||||||
|
HzvEvqBTViVsUQn3qqvKv3b9bZvzndu/PWa8DFaqr5hIlTpL36dYUNk4dalb6kMM
|
||||||
|
Av+Z6+hsTXBbKWWc3apdzK8BMewM69KN6Oqce+Zu9ydmDBpI125C4z/eIT574Q1w
|
||||||
|
+2OqqGwaVLRcJXrJosmLFqa7LH4XXgVNWG4SHQHuEhANxjJ/GP/89PrNbpHoNkm+
|
||||||
|
Gkhpi8KWTRoSsmkXwQqQ1vp5Iki/untp+HDH+no32NgN0nZPV/+Qt+OR0t3vwmC3
|
||||||
|
Zzrd/qqc8NSLf3Iizsafl7b4r4qgEKjZ+xjGtrVcUjyJthkqcwEKDwOzEmDyei+B
|
||||||
|
26Nu/yYwl/WL3YlXtq09s68rxbd2AvCl1iuahhQqcvbjM4xdCUsT37uMdBNSSwID
|
||||||
|
AQABo4ICUjCCAk4wDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCAa4wHQYDVR0OBBYE
|
||||||
|
FE4L7xqkQFulF2mHMMo0aEPQQa7yMGQGA1UdHwRdMFswLKAqoCiGJmh0dHA6Ly9j
|
||||||
|
ZXJ0LnN0YXJ0Y29tLm9yZy9zZnNjYS1jcmwuY3JsMCugKaAnhiVodHRwOi8vY3Js
|
||||||
|
LnN0YXJ0Y29tLm9yZy9zZnNjYS1jcmwuY3JsMIIBXQYDVR0gBIIBVDCCAVAwggFM
|
||||||
|
BgsrBgEEAYG1NwEBATCCATswLwYIKwYBBQUHAgEWI2h0dHA6Ly9jZXJ0LnN0YXJ0
|
||||||
|
Y29tLm9yZy9wb2xpY3kucGRmMDUGCCsGAQUFBwIBFilodHRwOi8vY2VydC5zdGFy
|
||||||
|
dGNvbS5vcmcvaW50ZXJtZWRpYXRlLnBkZjCB0AYIKwYBBQUHAgIwgcMwJxYgU3Rh
|
||||||
|
cnQgQ29tbWVyY2lhbCAoU3RhcnRDb20pIEx0ZC4wAwIBARqBl0xpbWl0ZWQgTGlh
|
||||||
|
YmlsaXR5LCByZWFkIHRoZSBzZWN0aW9uICpMZWdhbCBMaW1pdGF0aW9ucyogb2Yg
|
||||||
|
dGhlIFN0YXJ0Q29tIENlcnRpZmljYXRpb24gQXV0aG9yaXR5IFBvbGljeSBhdmFp
|
||||||
|
bGFibGUgYXQgaHR0cDovL2NlcnQuc3RhcnRjb20ub3JnL3BvbGljeS5wZGYwEQYJ
|
||||||
|
YIZIAYb4QgEBBAQDAgAHMDgGCWCGSAGG+EIBDQQrFilTdGFydENvbSBGcmVlIFNT
|
||||||
|
TCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTANBgkqhkiG9w0BAQUFAAOCAgEAFmyZ
|
||||||
|
9GYMNPXQhV59CuzaEE44HF7fpiUFS5Eyweg78T3dRAlbB0mKKctmArexmvclmAk8
|
||||||
|
jhvh3TaHK0u7aNM5Zj2gJsfyOZEdUauCe37Vzlrk4gNXcGmXCPleWKYK34wGmkUW
|
||||||
|
FjgKXlf2Ysd6AgXmvB618p70qSmD+LIU424oh0TDkBreOKk8rENNZEXO3SipXPJz
|
||||||
|
ewT4F+irsfMuXGRuczE6Eri8sxHkfY+BUZo7jYn0TZNmezwD7dOaHZrzZVD1oNB1
|
||||||
|
ny+v8OqCQ5j4aZyJecRDjkZy42Q2Eq/3JR44iZB3fsNrarnDy0RLrHiQi+fHLB5L
|
||||||
|
EUTINFInzQpdn4XBidUaePKVEFMy3YCEZnXZtWgo+2EuvoSoOMCZEoalHmdkrQYu
|
||||||
|
L6lwhceWD3yJZfWOQ1QOq92lgDmUYMA0yZZwLKMS9R9Ie70cfmu3nZD0Ijuu+Pwq
|
||||||
|
yvqCUqDvr0tVk+vBtfAii6w0TiYiBKGHLHVKt+V9E9e4DGTANtLJL4YSjCMJwRuC
|
||||||
|
O3NJo2pXh5Tl1njFmUNj403gdy3hZZlyaQQaRwnmDwFWJPsfvw55qVguucQJAX6V
|
||||||
|
um0ABj6y6koQOdjQK/W/7HW/lwLFCRsI3FU34oH7N4RDYiDK51ZLZer+bMEkkySh
|
||||||
|
NOsF/5oirpt9P/FlUQqmMGqz9IgcgA38corog14=
|
||||||
|
-----END CERTIFICATE-----
|
23
contrib/certificates/ssl/i2p-netdb.innovatio.no.crt
Normal file
23
contrib/certificates/ssl/i2p-netdb.innovatio.no.crt
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIID2zCCApOgAwIBAgIBBzANBgkqhkiG9w0BAQsFADBCMR8wHQYDVQQDExZpMnAt
|
||||||
|
bmV0ZGIuaW5ub3ZhdGlvLm5vMRIwEAYDVQQKEwlJbm5vdmF0aW8xCzAJBgNVBAYT
|
||||||
|
Ak5PMCIYDzIwMTQwMTIxMDUzMzMxWhgPMjAyNDAxMTkwNTMzMzFaMEIxHzAdBgNV
|
||||||
|
BAMTFmkycC1uZXRkYi5pbm5vdmF0aW8ubm8xEjAQBgNVBAoTCUlubm92YXRpbzEL
|
||||||
|
MAkGA1UEBhMCTk8wggFSMA0GCSqGSIb3DQEBAQUAA4IBPwAwggE6AoIBMQC9WVet
|
||||||
|
EFeKAHmwgTUxJ/bRI4Gtjke3uj897eeZ15Y0SiqdHzypsEIWtXqx4G3W801xZzhv
|
||||||
|
UiAculvwRY4kpv3DnQE4sNTzbkAlvC6z4+CpFM2mhZ7o+YmozrIsNmQNCsvlxqJV
|
||||||
|
AD1mzqTFl/OB7LVtLmpSSd36IQFGmsh24XXa4pVH33e+NCZIGsdVwGsa4GoRuC9a
|
||||||
|
s/DiLI+x6zYRoY9cfOF2DuuOfKNMjSl65QUe4uHZCsRTb1q08NnPIidEFHr94kZH
|
||||||
|
Hph+MQs6MUVK1eT4yYt084S3cEWmWBQZVyAvWQ9q8EW+MoniOM7bBG2Bn9wu2F5x
|
||||||
|
kAKWTYfKSStW5CKSox9VSoopiUAtEIqhwgFGTISqhQyfOfyY97X2M47wvyWsl6dE
|
||||||
|
NxTgdvLD/o24rejBAgMBAAGjeDB2MAwGA1UdEwEB/wQCMAAwIQYDVR0RBBowGIIW
|
||||||
|
aTJwLW5ldGRiLmlubm92YXRpby5ubzATBgNVHSUEDDAKBggrBgEFBQcDATAPBgNV
|
||||||
|
HQ8BAf8EBQMDByAAMB0GA1UdDgQWBBTaTuBpTAinNiT9PfKNRdIn3HrwxTANBgkq
|
||||||
|
hkiG9w0BAQsFAAOCATEAsYtojwAHiFwUqvCMIMJa5YN0Ms/QpjqZiENuGBpxvmVF
|
||||||
|
WVImX4s8K/qoBAKED8uKcRbMQd0FeDea7kMisJt5cblDzYuSv6wfeLXYkaT8/9H2
|
||||||
|
X1pXhO/eghJ2U42RTgBkaW3mCI8ohk/GehU4tEXnbWRPHt6XDoSYDJdf2X8BPcgB
|
||||||
|
ZE10owLCw9c80QTuU+LCvbt8/F2USyNplUrogJGThzxrxZvxjGq6EcDj0iA0RRoG
|
||||||
|
5CUNrCB+JgFc+4bagI3E5B0skk/wn3Nl7mM8/Nf8b1QENmc8eYBZx2InA9769DHL
|
||||||
|
tNxzvE+OeMNlKy4M9WvLieIh6KmpYhHBG8ubJT8X+bZpJkh4rH6RzVYiXeCpX2iL
|
||||||
|
eoeSriGO0+8CJTBRbd5cXYd/COT0iAomMTelhcGVTA==
|
||||||
|
-----END CERTIFICATE-----
|
21
contrib/certificates/ssl/i2p.feared.eu.crt
Normal file
21
contrib/certificates/ssl/i2p.feared.eu.crt
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDhTCCAm2gAwIBAgIJAPVgXcMcr3zqMA0GCSqGSIb3DQEBBQUAMFkxCzAJBgNV
|
||||||
|
BAYTAkVVMQ8wDQYDVQQIDAZFdXJvcGUxDDAKBgNVBAoMA0kyUDETMBEGA1UECwwK
|
||||||
|
T3V0cHJveGllczEWMBQGA1UEAwwNaTJwLmZlYXJlZC5ldTAeFw0xMjEwMjkxNzMw
|
||||||
|
MDZaFw0yMTAxMTUxNzMwMDZaMFkxCzAJBgNVBAYTAkVVMQ8wDQYDVQQIDAZFdXJv
|
||||||
|
cGUxDDAKBgNVBAoMA0kyUDETMBEGA1UECwwKT3V0cHJveGllczEWMBQGA1UEAwwN
|
||||||
|
aTJwLmZlYXJlZC5ldTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOUh
|
||||||
|
y2+6Q4RO+b5WPXX/cZ/9fiI7aWGe/C7z0083HOEqnkgGCYgxFWUCed6/eZbYoZ7/
|
||||||
|
PV1BAuEereNwTp+Ov7fQB2H73O9sSAEejW6O4C2PZiZWaPxpZiTJNENbLOZxJnIN
|
||||||
|
+fSqmA5pqvGkYAJ2heZH4v4tayun7Vib58GWuizhzJ4EvhOrOrLq/YHrxMn++r4e
|
||||||
|
kNNbq4QzWpfxNa7ocDY9OJh5qFzuc+6wKj1m1syK6euDqs5d6X+y0aDTMgRxey2b
|
||||||
|
tkmNx9wC0flLg1oMcv9o1zN+dENy7Inkd/SqbSjLUqDTJzdq6xURVsgLoV63pb6r
|
||||||
|
B4gbGIlriYWK/mOPTTkCAwEAAaNQME4wHQYDVR0OBBYEFOI94JZ3Rb2RVmr8QjOp
|
||||||
|
u3KfVSrNMB8GA1UdIwQYMBaAFOI94JZ3Rb2RVmr8QjOpu3KfVSrNMAwGA1UdEwQF
|
||||||
|
MAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAD7bI05zg9nf9qanq4ZNw/rvEzYQRBmy
|
||||||
|
MqzZjcwBMGvbcEbS+zYAdAkfxmN3l/AT4I4z138Om0ud4ZJUQTVlRsJkMlmLD4Rt
|
||||||
|
Jbi2rl7mrY7Qupgu5hvgH+ZaEWr7LTq+tFjPycRS+zijw9NToKeAsgEex9zYIOYD
|
||||||
|
BxDUn/trvyA41ItvegWh803IsZUBb45Via+bopid9aFFkejRrck9hhcQ6fVh2yju
|
||||||
|
nuVwHrxNvGc0NmmJ7zI+nPESFS+TAYbWXikDhc5Vtyiuoz47WZU1cgXYYMejK4WA
|
||||||
|
+3GLvei7qKm4GOJSg7BngF5Iyj/n7ML1rBqTlN3KA1YOgpGCwJlKzto=
|
||||||
|
-----END CERTIFICATE-----
|
23
contrib/certificates/ssl/i2p.mooo.com.crt
Normal file
23
contrib/certificates/ssl/i2p.mooo.com.crt
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDvjCCAyegAwIBAgICZhcwDQYJKoZIhvcNAQEFBQAwdTELMAkGA1UEBhMCVVMx
|
||||||
|
DTALBgNVBAgMBG5vbmUxDTALBgNVBAcMBG5vbmUxDTALBgNVBAoMBG5vbmUxDTAL
|
||||||
|
BgNVBAsMBG5vbmUxFTATBgNVBAMMDGkycC5tb29vLmNvbTETMBEGCSqGSIb3DQEJ
|
||||||
|
ARYEbm9uZTAeFw0xMTEwMjMyMTM2NDFaFw0xOTEwMjMyMTM2NDFaMGYxCzAJBgNV
|
||||||
|
BAYTAlVTMQ0wCwYDVQQIDARub25lMQ0wCwYDVQQKDARub25lMQ0wCwYDVQQLDARu
|
||||||
|
b25lMRUwEwYDVQQDDAxpMnAubW9vby5jb20xEzARBgkqhkiG9w0BCQEWBG5vbmUw
|
||||||
|
ggGPMA0GCSqGSIb3DQEBAQUAA4IBfAAwggF3AoIBbgMG1O7HRVa7UoiKbQTmKy5m
|
||||||
|
x79Na8vjD3etcOwfc4TSenQFvn+GbAWkJwKpM8uvOcgj1CxNeHWdSaeTFH1OwJsw
|
||||||
|
vl3leJ7clMdo3hpQDhPeGzBLyOiWwFHVn15YKa9xcM7S9Op5Q6rKBHUyyx1vGSz+
|
||||||
|
/NBmkktpI6rcGFfP3ISRL0auR+db+adWv4TS6W8YiwQIVZNbSlKP6FNO9Mv1kxQZ
|
||||||
|
KoHPn8vT/LtAh1fcI6ryBuy3F5oHfbGumIwsS5dpowryFxQzwg5vtMA7AMCMKyXv
|
||||||
|
hP/W6OuaaEP5MCIxkWjQs35gOYa8eF1dLoy3AD9yVVhoNrA8Bc5FnVFJ32Qv7agy
|
||||||
|
qRY85cXBA6hT/Qzs/wWwp7WrrnZuifaSv/u/Ayi5vX42/bf86PSM2IRNIESoA98A
|
||||||
|
NFz4U2KGq9s1K2JbkQmnFy8IU0w7CMq6PvNEm/uNjSk6OE1rcCXML+EuX0zmXy8d
|
||||||
|
PjRbLzC9csSg2CqMtQIDAQABo3sweTAJBgNVHRMEAjAAMCwGCWCGSAGG+EIBDQQf
|
||||||
|
Fh1PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAdBgNVHQ4EFgQUdjuOczdG
|
||||||
|
hUpYzH0UXqKrOleT8GkwHwYDVR0jBBgwFoAU+SKWC49cM5sCodv89AFin3pkS0Yw
|
||||||
|
DQYJKoZIhvcNAQEFBQADgYEAKYyWlDIStjjbn/ZzVScKR174I8whTbdqrX/vp9dr
|
||||||
|
2hMv5m4F+aswX4Jr58WneKg2LvRaL6xEhoL7OAQ6aB/7xVSpDjIrrBLZd513NAam
|
||||||
|
X6bOPYJ6IH7Vw9ClFY3AlfzsNlgRMXno7rySKKzhg24kusNwKDH2yCphZy4BgjMn
|
||||||
|
y6A=
|
||||||
|
-----END CERTIFICATE-----
|
25
contrib/certificates/ssl/ieb9oopo.mooo.com.crt
Normal file
25
contrib/certificates/ssl/ieb9oopo.mooo.com.crt
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIESzCCAzOgAwIBAgIJALGqvElYEEqyMA0GCSqGSIb3DQEBBQUAMIG7MQswCQYD
|
||||||
|
VQQGEwJERTEaMBgGA1UECAwRaWViOW9vcG8ubW9vby5jb20xGjAYBgNVBAcMEWll
|
||||||
|
Yjlvb3BvLm1vb28uY29tMRowGAYDVQQKDBFpZWI5b29wby5tb29vLmNvbTEaMBgG
|
||||||
|
A1UECwwRaWViOW9vcG8ubW9vby5jb20xGjAYBgNVBAMMEWllYjlvb3BvLm1vb28u
|
||||||
|
Y29tMSAwHgYJKoZIhvcNAQkBFhFpZWI5b29wby5tb29vLmNvbTAeFw0xNDA0MTMx
|
||||||
|
NDI3MThaFw0zNDA0MDgxNDI3MThaMIG7MQswCQYDVQQGEwJERTEaMBgGA1UECAwR
|
||||||
|
aWViOW9vcG8ubW9vby5jb20xGjAYBgNVBAcMEWllYjlvb3BvLm1vb28uY29tMRow
|
||||||
|
GAYDVQQKDBFpZWI5b29wby5tb29vLmNvbTEaMBgGA1UECwwRaWViOW9vcG8ubW9v
|
||||||
|
by5jb20xGjAYBgNVBAMMEWllYjlvb3BvLm1vb28uY29tMSAwHgYJKoZIhvcNAQkB
|
||||||
|
FhFpZWI5b29wby5tb29vLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
|
||||||
|
ggEBAN1CusoQ3OxJFTytbVMe7LPY8lnR7GIIQt5eCs0XTLl3ECclET1KLRo1c8Mv
|
||||||
|
vj5AwDRvL3Kw/oeDS+QvSRhgxG3lJ8i0soWDC/1LIX1NS/ZXG7hbycZ7YqAovCxU
|
||||||
|
958WPjUios73sAWUJrI8BbWFTYPWBB5lbyTaCooxtf6k7yB+CSwZnstEP/lbPNkf
|
||||||
|
Iupj+9B18ba21D2kQqZXyQRLX02d/rXq963BSkPX14Dxa7abw4lgDltvh2CzcoQH
|
||||||
|
VbQh3eGfPIIQGfvAAVEGsoy9fFt+xOUxp3KO7Y1VMKzegWqa2vBtWK+2nhpHfswq
|
||||||
|
eaE1qeVh12cG5kaVNP0o0hOUxkECAwEAAaNQME4wHQYDVR0OBBYEFIQ5U4EKfr0t
|
||||||
|
4L+RFe/RBFcDVoijMB8GA1UdIwQYMBaAFIQ5U4EKfr0t4L+RFe/RBFcDVoijMAwG
|
||||||
|
A1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAGlNHzxF9tbS/Xr8jGpSdRLm
|
||||||
|
oIIoTr7+dIfFIy2TMAow0+gx1qEtWASUYIwbCP5mdMfhUjL8POfSwtTvgjw3LMoM
|
||||||
|
2zsGBvgGWs6VJbMPAgkgfsyjdJTM/IOiJtze6degn2bdZvAr1XiInLGMRMko7WyE
|
||||||
|
QQ1WJPcTUt8rNYVaCkq3CYioIlkb/C6M6ObHGSia0kwoZa6grD3CNUCa/c/dlFKO
|
||||||
|
E06qN72fsYihp0ghHkBaCxb+YfYpIAPIpfuuTSGkVYyjpY0a8EQ1JlzbJctQkX5r
|
||||||
|
sd9jfHsrZriAGCzdsL/diG8bUi9Yex/G0ip8GGEuHs5e2bJ6+7O/mPlL6SL/0tI=
|
||||||
|
-----END CERTIFICATE-----
|
33
contrib/certificates/ssl/jp.reseed.i2p2.no.crt
Normal file
33
contrib/certificates/ssl/jp.reseed.i2p2.no.crt
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
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
|
||||||
|
MHk7ixe0rSbnHcNF8g==
|
||||||
|
-----END CERTIFICATE-----
|
18
contrib/certificates/ssl/netdb.i2p2.no.crt
Normal file
18
contrib/certificates/ssl/netdb.i2p2.no.crt
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIC0DCCAjmgAwIBAgIJANdBFbakbhhOMA0GCSqGSIb3DQEBBQUAMIGAMQswCQYD
|
||||||
|
VQQGEwJOTzENMAsGA1UECAwET3NsbzENMAsGA1UEBwwET3NsbzEMMAoGA1UECgwD
|
||||||
|
STJQMQwwCgYDVQQLDANJMlAxFjAUBgNVBAMMDW5ldGRiLmkycDIubm8xHzAdBgkq
|
||||||
|
hkiG9w0BCQEWEG1lZWhAaTJwbWFpbC5vcmcwHhcNMTIxMDIzMDExMjIyWhcNMTkx
|
||||||
|
MDIyMDExMjIyWjCBgDELMAkGA1UEBhMCTk8xDTALBgNVBAgMBE9zbG8xDTALBgNV
|
||||||
|
BAcMBE9zbG8xDDAKBgNVBAoMA0kyUDEMMAoGA1UECwwDSTJQMRYwFAYDVQQDDA1u
|
||||||
|
ZXRkYi5pMnAyLm5vMR8wHQYJKoZIhvcNAQkBFhBtZWVoQGkycG1haWwub3JnMIGf
|
||||||
|
MA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDCDvmjTpff6/XpiNuqoa9ZEKMlyq1o
|
||||||
|
kas9fHwnZax/0QTM3xusSQQ9DzeVMSx1ueYxhTZ6VLmE1mTr0aIndzugxGK/g85H
|
||||||
|
Y+cUl3nw7+5gLPMCUrKAXqQokE3mYxSNY3AUeend7nmHvm9iciw4+Sa2+6ROvQQy
|
||||||
|
kD31CEN6/I04rwIDAQABo1AwTjAdBgNVHQ4EFgQUV83dJhEcLbfJ+uh+MDYNPdah
|
||||||
|
RoQwHwYDVR0jBBgwFoAUV83dJhEcLbfJ+uh+MDYNPdahRoQwDAYDVR0TBAUwAwEB
|
||||||
|
/zANBgkqhkiG9w0BAQUFAAOBgQBQQlJym7mUMUM2ryKu20z2PSUzFyq5U4rWHeo3
|
||||||
|
elbNaTsFBwi+Ot/Lg/A5I4V8gywH1fBTG5bYKDUYvWohz1qIg66G57B1zT1zK9yh
|
||||||
|
Byz9go44M3y1/kXXSsJlY9llG9DDicr1y6LfldwZJ5zFAd3iiB8D8UadP5YLqb7v
|
||||||
|
wb1F1g==
|
||||||
|
-----END CERTIFICATE-----
|
24
contrib/certificates/ssl/reseed.i2p-projekt.de.crt
Normal file
24
contrib/certificates/ssl/reseed.i2p-projekt.de.crt
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIID7TCCAtWgAwIBAgIJAOHakoadaLRiMA0GCSqGSIb3DQEBBQUAMIGMMQswCQYD
|
||||||
|
VQQGEwJBVDEQMA4GA1UECAwHQXVzdHJpYTENMAsGA1UEBwwER3JhejEMMAoGA1UE
|
||||||
|
CgwDSTJQMQ8wDQYDVQQLDAZSZXNlZWQxHjAcBgNVBAMMFXJlc2VlZC5pMnAtcHJv
|
||||||
|
amVrdC5kZTEdMBsGCSqGSIb3DQEJARYOcmVzZWVkQGkycDIuZGUwHhcNMTQwNTEw
|
||||||
|
MTAxOTM3WhcNMjQwNTA3MTAxOTM3WjCBjDELMAkGA1UEBhMCQVQxEDAOBgNVBAgM
|
||||||
|
B0F1c3RyaWExDTALBgNVBAcMBEdyYXoxDDAKBgNVBAoMA0kyUDEPMA0GA1UECwwG
|
||||||
|
UmVzZWVkMR4wHAYDVQQDDBVyZXNlZWQuaTJwLXByb2pla3QuZGUxHTAbBgkqhkiG
|
||||||
|
9w0BCQEWDnJlc2VlZEBpMnAyLmRlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
|
||||||
|
CgKCAQEA8t5igIeAUZVX9k/A2gudRWVfToIV4yvlxmnH9UTJ8DTkWfHGbY9MmW2+
|
||||||
|
b0ZdvIZDcgg1nvcLEKqCDQnIp3wLGdM8fdVSXqxA1dLyHdk6IrGVqb60qpGENeIc
|
||||||
|
EHiUeB1g0KqP4kLcj2sNlo+Vupjnu7qS8v0/LfZ3fq2m4vtx8dYnvo+JIzGL9K0f
|
||||||
|
/DOil8QIcdTZupzMbXd6P936Blm/1RdbW/uKROOuuYE38NwYOUCq2/Nd+T86S5DD
|
||||||
|
9wQBjy0U+9nNayWf6BOSuP6m2mxx/pA1CvKRq7CzI0Gqjo2Msd+i0dTL2WIO2JDp
|
||||||
|
5uykZ0GabRW3UrMEuyrzzK6U2RZ1dQIDAQABo1AwTjAdBgNVHQ4EFgQUIejD2MMl
|
||||||
|
6PpcCernYd3ku3sEWfswHwYDVR0jBBgwFoAUIejD2MMl6PpcCernYd3ku3sEWfsw
|
||||||
|
DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAupUg3ZTBSE7iRebjcZ+y
|
||||||
|
zgnRaClmgrv8Mpa1/weTuXKhJZ65k6+G5mplI5hN/crKi/3b6oyfRrYhgdTdb0rD
|
||||||
|
2CbrhBkPGGlubhkjkxWjAhibzU6Kt3a7WOjykGnslpCZhwS/hiVB7ZE2JGdphFld
|
||||||
|
aJTKt12CytyP3GyIQyyX7O2t92dk8cW4tlxRVpaPNr59lk0V50qpvNmNyhxv3yDz
|
||||||
|
taop/etfjHStq1YrltHWH0d4Dxy8ubb7nV19uvPcE0+MrR2xm7jvOBfGjAf1bQ7Z
|
||||||
|
rk7RMHio4xWFJZO7TSzL5/8EH2jX6ZqpH+hZ6sV8TmzuRWsPkm0doXWr+HBZ/gMt
|
||||||
|
5w==
|
||||||
|
-----END CERTIFICATE-----
|
20
contrib/certificates/ssl/reseed.info.crt
Normal file
20
contrib/certificates/ssl/reseed.info.crt
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDRDCCAiwCCQDCm/Zrmali9zANBgkqhkiG9w0BAQUFADBkMQswCQYDVQQGEwJB
|
||||||
|
VTETMBEGA1UECBMKU29tZS1TdGF0ZTELMAkGA1UEBxMCSEgxDDAKBgNVBAoTA0ky
|
||||||
|
UDEPMA0GA1UECxMGcmVzZWVkMRQwEgYDVQQDEwtyZXNlZWQuaW5mbzAeFw0xMjEw
|
||||||
|
MjcxODU3NDNaFw0xNjEyMDUxODU3NDNaMGQxCzAJBgNVBAYTAkFVMRMwEQYDVQQI
|
||||||
|
EwpTb21lLVN0YXRlMQswCQYDVQQHEwJISDEMMAoGA1UEChMDSTJQMQ8wDQYDVQQL
|
||||||
|
EwZyZXNlZWQxFDASBgNVBAMTC3Jlc2VlZC5pbmZvMIIBIjANBgkqhkiG9w0BAQEF
|
||||||
|
AAOCAQ8AMIIBCgKCAQEAt9nz0iUvjdX4Hkhfk0FbBOeEP4i/FG3V4VrEdQfcviSF
|
||||||
|
XgzGYeRtGsvrFWP/5+6bcGnOkIy/jrKJfij3AjKJh8gTzqiNNNnV8VcHwFSNp+hZ
|
||||||
|
D4BM+UHPACV1Pjd3HQe6f0+LvcTs3HQgIkNkwUyqRuXOm/5Mk6SWSu1740aSwHCj
|
||||||
|
Kk0x1FByzI0YBvXCPX6TVk6sJqKkQyLzK0CSGSeqUq8GvGCq+jT9k62Su7ooxCwi
|
||||||
|
GzxaFjMdVYxuI8cuT5Cni+SUw1Ia8vhESnIy6slwzk37xNI80VuMvRT6rD2KcXDH
|
||||||
|
mK7ml1qL0rJWoF5AE+x/nen4V41mouv1W9rk3wTlTQIDAQABMA0GCSqGSIb3DQEB
|
||||||
|
BQUAA4IBAQAr6RBviBDW4bnPDTcdtstTDdaYX9yzoh+zzeGB0dUR26GKoOjpSItb
|
||||||
|
B9nrsW1eJ2wbblfGBUoXhcmNByKHXXHejMhmurHjdei2BuLbTsknN8DPKXu5UF9z
|
||||||
|
cg4cKQkxgzXOcNYlaF4+sfwFXDHJ4we/8vduVgkyo8R66543/Sh/nIMvq2slRT4w
|
||||||
|
wIBOVcMb2XxlbdwHW9XALAz9sto+4GH9GAC24f8ngluOpHijMnOOIo4dHibQ5hM9
|
||||||
|
KcDpHezP0ugMTAxS2NmtVahwAqa2IjpqR7aEQ2wLvxQzDqrXo93L93+b2FKRUQXH
|
||||||
|
Duud/n/w0kVV3DaIGikOsJayoanR+9HD
|
||||||
|
-----END CERTIFICATE-----
|
33
contrib/certificates/ssl/uk.reseed.i2p2.no.crt
Normal file
33
contrib/certificates/ssl/uk.reseed.i2p2.no.crt
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIFsTCCA5mgAwIBAgIJANgzPow6thRuMA0GCSqGSIb3DQEBBQUAMG8xCzAJBgNV
|
||||||
|
BAYTAk5PMQ0wCwYDVQQIDARPc2xvMQswCQYDVQQHDAJVSzETMBEGA1UECgwKSTJQ
|
||||||
|
IFJlc2VlZDETMBEGA1UECwwKSTJQIFJlc2VlZDEaMBgGA1UEAwwRdWsucmVzZWVk
|
||||||
|
LmkycDIubm8wHhcNMTQwNjI4MjA0OTA3WhcNMjQwNjI1MjA0OTA3WjBvMQswCQYD
|
||||||
|
VQQGEwJOTzENMAsGA1UECAwET3NsbzELMAkGA1UEBwwCVUsxEzARBgNVBAoMCkky
|
||||||
|
UCBSZXNlZWQxEzARBgNVBAsMCkkyUCBSZXNlZWQxGjAYBgNVBAMMEXVrLnJlc2Vl
|
||||||
|
ZC5pMnAyLm5vMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAxlVlXWn5
|
||||||
|
Ham6ZqM6FkH6ZoXeXbncY/PnF669mCPcrPH56V2xZXwpeCXHWfu7YiHuhXXZSmzP
|
||||||
|
zwRrawHZTJulHt4e6j27JnDuEj69gmFpyi4B1djQ0kav0aJeagwCPG2do/UD7Cbr
|
||||||
|
4nITkU4CifLe47IUW/2K/EBI6bZGsRIDHJ3A+fAQmLnvehEkpvLN+cvtkpJOtZYx
|
||||||
|
6WvbwLsirkISnaio4//UY8M4poIu9mSG5pvNLagn9uoRPUSuj8jDEysB1Nmh12Zu
|
||||||
|
gFnt2XcxQB9/0krB5GnDTodrgfsz/UPbk44l4kFmQoLv5ACFndH69RKftogisauj
|
||||||
|
VVUrqCL3l9TcNsx8GLqZkeWhCwdZycZFjBhK01zihTYPEiU2HXfCNWhzLqxrM2Hh
|
||||||
|
r1ci+56fyNdn/ssO4o3hrGaWPDiayiHlEGEJxaG/ueKX2c3c0UJKkIGBPTEcdBjW
|
||||||
|
q42n/7EhY/ISaieQXPRK+gVm18I1OlGUH5FEYELO20bL88J8pr/bYuJyJnC8fiMP
|
||||||
|
YzKZuiVhey6dPr0zZgNDHyRbOlZqQllzKd1wbzbE4xqdUZfBWYwtRpdOJKDw4eoi
|
||||||
|
M69TwPQFfudeiudnMcR1gN37OkxS7UTEdsYIB5urgLb6qQD+tYFsxpcVPkedJw62
|
||||||
|
3TobhZjucaEZWzePd4u9faT9mQBXBAgY6VcCAwEAAaNQME4wHQYDVR0OBBYEFDTN
|
||||||
|
QRqhzaLc6XX2gFg26K//e0+8MB8GA1UdIwQYMBaAFDTNQRqhzaLc6XX2gFg26K//
|
||||||
|
e0+8MAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggIBACcJ99Z45ghglvL3
|
||||||
|
/yMnx6IkOSneEm2/ADQoOabBQSC2grRAMBescKUiqpgbpBFalIPbPJUVrlH9tXYB
|
||||||
|
izNhqWETBY2tNy7AEHcJcCsAFuC2gOhaFH7FLgPA8V5IJmZ+McjB8REyowcN+CP4
|
||||||
|
GDY8s5/yr9S3HpKLD80UV18UX/j5m4b6I1w61QceMOSt6ahTtlnyvNBonFW94L1c
|
||||||
|
RmkdbhxYWn2eeUas62Q/+9bjr24E0weDKqopa3bbO7MWJ3mKkS4rua42j8GG3Q3q
|
||||||
|
UWPGh4zm+2+Ncjmz0Ho73RyYDDcp9IjwlAEv+NW86rz/5Pdkhoy+SzQwFYAwNgaQ
|
||||||
|
FRKb6ltpslxmu3tUdZ7Ydrj6MBGQyH2gRVm9qByro7WGI4UsyzsjP009Iu6dbhdC
|
||||||
|
2ddTGMisXF3dOmdRWh8dlggmW6gV4iaVgZkzLtrc9S0SK66utKMVXa4EUTm6XogX
|
||||||
|
F5ImPnVzIMo2qF2pP31aGDzKqJF3GNjGj+xHRVau5whz0a4ESY6V14PLTEL4Vc/H
|
||||||
|
J9uLCySifvqN+jzs5iY2QvNXjg2zPaTJbnjxxpYQJVSQHX6SyRcszhChqQzxnbyo
|
||||||
|
+S19BRclqzufRq6pp6VcOiID0BB7qPcrUHM9h1ingMXcZZlGBgHew9cY7tb5TAox
|
||||||
|
o+aTNc4k/7E543FVbs40dpOD2Fcr
|
||||||
|
-----END CERTIFICATE-----
|
20
contrib/certificates/ssl/us.reseed.i2p2.no.crt
Normal file
20
contrib/certificates/ssl/us.reseed.i2p2.no.crt
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDUDCCAjgCCQCkTcCJMdZV7zANBgkqhkiG9w0BAQUFADBqMQswCQYDVQQGEwJO
|
||||||
|
TzENMAsGA1UECAwET3NsbzENMAsGA1UEBwwET3NsbzENMAsGA1UECgwET3NsbzES
|
||||||
|
MBAGA1UECwwJTm9yZGNsb3VkMRowGAYDVQQDDBF1cy5yZXNlZWQuaTJwMi5ubzAe
|
||||||
|
Fw0xNDA2MjcyMjQxMjFaFw0yNDA2MjQyMjQxMjFaMGoxCzAJBgNVBAYTAk5PMQ0w
|
||||||
|
CwYDVQQIDARPc2xvMQ0wCwYDVQQHDARPc2xvMQ0wCwYDVQQKDARPc2xvMRIwEAYD
|
||||||
|
VQQLDAlOb3JkY2xvdWQxGjAYBgNVBAMMEXVzLnJlc2VlZC5pMnAyLm5vMIIBIjAN
|
||||||
|
BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAomVoBEc53jzy3xGMfgRaKyX6MaGG
|
||||||
|
KAmwu0uMTX6bVzGjy56JMMq3luoxOrpvgrNZF52lu7i36Tejo0HM75AHoea1es55
|
||||||
|
DNLmrlDeqzlBU2WibOnizbB8G+tlMEbx8eAGAWk/Wv/vH8CAKmxjImslmbajzZC2
|
||||||
|
LEH7inp3J5T2sVV7zmXeL9OEPKNyohbu6Mrno2IAlEOr8cu+lWAaFWzpknnR1gBX
|
||||||
|
NkB/8+7vK5Fq4MT7B0qnXPxmaWDbUOepPPni8u+2L9+qt19vZH4/6KNuH7xd7JLz
|
||||||
|
FfIdol6jy2cBQyAK7cVKWDHNk7ceB4Dl0mjBDbBIRTtLK+rfdnVmfWn8aQIDAQAB
|
||||||
|
MA0GCSqGSIb3DQEBBQUAA4IBAQCQH4QJMp5xneh2ah7fiuVdtKbiv6QNunRz7nb/
|
||||||
|
mWYyqmBX7EHL8jOG5qmPELDgDt58HmnaYMo05nEJb9JhAoviEDXSYw0s6eN4n4nc
|
||||||
|
MKqgR/HLLSiXPwT+Wi1MI57OYim5AFTUCYTSaWFUT+dZKYb0QPE1XjGpQXi3ppsJ
|
||||||
|
3TJG71tOzJmZT6vRPmdTHJO70v6ZEhr5w4SiGx07gNmcgO8WRyb5ajOwSHiGKrj6
|
||||||
|
UsuRNhtCyZaAEmelR9mfKBR1J2Nb+9jTz6mJtpT82WY3bst6mFk+A+mMWBQy7Hjt
|
||||||
|
gpdSDBCcFx9if+AKINGLgFvFKV2q8UzbfXms19NsVt9Hu7W3
|
||||||
|
-----END CERTIFICATE-----
|
41
contrib/certificates/ssl/www.cacert.org.crt
Normal file
41
contrib/certificates/ssl/www.cacert.org.crt
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIHPTCCBSWgAwIBAgIBADANBgkqhkiG9w0BAQQFADB5MRAwDgYDVQQKEwdSb290
|
||||||
|
IENBMR4wHAYDVQQLExVodHRwOi8vd3d3LmNhY2VydC5vcmcxIjAgBgNVBAMTGUNB
|
||||||
|
IENlcnQgU2lnbmluZyBBdXRob3JpdHkxITAfBgkqhkiG9w0BCQEWEnN1cHBvcnRA
|
||||||
|
Y2FjZXJ0Lm9yZzAeFw0wMzAzMzAxMjI5NDlaFw0zMzAzMjkxMjI5NDlaMHkxEDAO
|
||||||
|
BgNVBAoTB1Jvb3QgQ0ExHjAcBgNVBAsTFWh0dHA6Ly93d3cuY2FjZXJ0Lm9yZzEi
|
||||||
|
MCAGA1UEAxMZQ0EgQ2VydCBTaWduaW5nIEF1dGhvcml0eTEhMB8GCSqGSIb3DQEJ
|
||||||
|
ARYSc3VwcG9ydEBjYWNlcnQub3JnMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC
|
||||||
|
CgKCAgEAziLA4kZ97DYoB1CW8qAzQIxL8TtmPzHlawI229Z89vGIj053NgVBlfkJ
|
||||||
|
8BLPRoZzYLdufujAWGSuzbCtRRcMY/pnCujW0r8+55jE8Ez64AO7NV1sId6eINm6
|
||||||
|
zWYyN3L69wj1x81YyY7nDl7qPv4coRQKFWyGhFtkZip6qUtTefWIonvuLwphK42y
|
||||||
|
fk1WpRPs6tqSnqxEQR5YYGUFZvjARL3LlPdCfgv3ZWiYUQXw8wWRBB0bF4LsyFe7
|
||||||
|
w2t6iPGwcswlWyCR7BYCEo8y6RcYSNDHBS4CMEK4JZwFaz+qOqfrU0j36NK2B5jc
|
||||||
|
G8Y0f3/JHIJ6BVgrCFvzOKKrF11myZjXnhCLotLddJr3cQxyYN/Nb5gznZY0dj4k
|
||||||
|
epKwDpUeb+agRThHqtdB7Uq3EvbXG4OKDy7YCbZZ16oE/9KTfWgu3YtLq1i6L43q
|
||||||
|
laegw1SJpfvbi1EinbLDvhG+LJGGi5Z4rSDTii8aP8bQUWWHIbEZAWV/RRyH9XzQ
|
||||||
|
QUxPKZgh/TMfdQwEUfoZd9vUFBzugcMd9Zi3aQaRIt0AUMyBMawSB3s42mhb5ivU
|
||||||
|
fslfrejrckzzAeVLIL+aplfKkQABi6F1ITe1Yw1nPkZPcCBnzsXWWdsC4PDSy826
|
||||||
|
YreQQejdIOQpvGQpQsgi3Hia/0PsmBsJUUtaWsJx8cTLc6nloQsCAwEAAaOCAc4w
|
||||||
|
ggHKMB0GA1UdDgQWBBQWtTIb1Mfz4OaO873SsDrusjkY0TCBowYDVR0jBIGbMIGY
|
||||||
|
gBQWtTIb1Mfz4OaO873SsDrusjkY0aF9pHsweTEQMA4GA1UEChMHUm9vdCBDQTEe
|
||||||
|
MBwGA1UECxMVaHR0cDovL3d3dy5jYWNlcnQub3JnMSIwIAYDVQQDExlDQSBDZXJ0
|
||||||
|
IFNpZ25pbmcgQXV0aG9yaXR5MSEwHwYJKoZIhvcNAQkBFhJzdXBwb3J0QGNhY2Vy
|
||||||
|
dC5vcmeCAQAwDwYDVR0TAQH/BAUwAwEB/zAyBgNVHR8EKzApMCegJaAjhiFodHRw
|
||||||
|
czovL3d3dy5jYWNlcnQub3JnL3Jldm9rZS5jcmwwMAYJYIZIAYb4QgEEBCMWIWh0
|
||||||
|
dHBzOi8vd3d3LmNhY2VydC5vcmcvcmV2b2tlLmNybDA0BglghkgBhvhCAQgEJxYl
|
||||||
|
aHR0cDovL3d3dy5jYWNlcnQub3JnL2luZGV4LnBocD9pZD0xMDBWBglghkgBhvhC
|
||||||
|
AQ0ESRZHVG8gZ2V0IHlvdXIgb3duIGNlcnRpZmljYXRlIGZvciBGUkVFIGhlYWQg
|
||||||
|
b3ZlciB0byBodHRwOi8vd3d3LmNhY2VydC5vcmcwDQYJKoZIhvcNAQEEBQADggIB
|
||||||
|
ACjH7pyCArpcgBLKNQodgW+JapnM8mgPf6fhjViVPr3yBsOQWqy1YPaZQwGjiHCc
|
||||||
|
nWKdpIevZ1gNMDY75q1I08t0AoZxPuIrA2jxNGJARjtT6ij0rPtmlVOKTV39O9lg
|
||||||
|
18p5aTuxZZKmxoGCXJzN600BiqXfEVWqFcofN8CCmHBh22p8lqOOLlQ+TyGpkO/c
|
||||||
|
gr/c6EWtTZBzCDyUZbAEmXZ/4rzCahWqlwQ3JNgelE5tDlG+1sSPypZt90Pf6DBl
|
||||||
|
Jzt7u0NDY8RD97LsaMzhGY4i+5jhe1o+ATc7iwiwovOVThrLm82asduycPAtStvY
|
||||||
|
sONvRUgzEv/+PDIqVPfE94rwiCPCR/5kenHA0R6mY7AHfqQv0wGP3J8rtsYIqQ+T
|
||||||
|
SCX8Ev2fQtzzxD72V7DX3WnRBnc0CkvSyqD/HMaMyRa+xMwyN2hzXwj7UfdJUzYF
|
||||||
|
CpUCTPJ5GhD22Dp1nPMd8aINcGeGG7MW9S/lpOt5hvk9C8JzC6WZrG/8Z7jlLwum
|
||||||
|
GCSNe9FINSkYQKyTYOGWhlC0elnYjyELn8+CkcY7v2vcB5G5l1YjqrZslMZIBjzk
|
||||||
|
zk6q5PYvCdxTby78dOs6Y5nCpqyJvKeyRKANihDjbPIky/qbn3BHLt4Ui9SyIAmW
|
||||||
|
omTxJBzcoTWcFbLUvFUufQb1nA5V9FrWk9p2rSVzTMVD
|
||||||
|
-----END CERTIFICATE-----
|
18
filelist.mk
Normal file
18
filelist.mk
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
|
||||||
|
|
||||||
|
CPP_FILES := CryptoConst.cpp base64.cpp NTCPSession.cpp RouterInfo.cpp Transports.cpp \
|
||||||
|
RouterContext.cpp NetDb.cpp LeaseSet.cpp Tunnel.cpp TunnelEndpoint.cpp TunnelGateway.cpp \
|
||||||
|
TransitTunnel.cpp I2NPProtocol.cpp Log.cpp Garlic.cpp HTTPServer.cpp Streaming.cpp Identity.cpp \
|
||||||
|
SSU.cpp util.cpp Reseed.cpp DaemonLinux.cpp SSUData.cpp i2p.cpp aes.cpp SOCKS.cpp UPnP.cpp \
|
||||||
|
TunnelPool.cpp HTTPProxy.cpp AddressBook.cpp Daemon.cpp
|
||||||
|
|
||||||
|
|
||||||
|
H_FILES := CryptoConst.h base64.h NTCPSession.h RouterInfo.h Transports.h \
|
||||||
|
RouterContext.h NetDb.h LeaseSet.h Tunnel.h TunnelEndpoint.h TunnelGateway.h \
|
||||||
|
TransitTunnel.h I2NPProtocol.h Log.h Garlic.h HTTPServer.h Streaming.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
|
||||||
|
|
||||||
|
|
||||||
|
OBJECTS = $(addprefix obj/, $(notdir $(CPP_FILES:.cpp=.o)))
|
||||||
|
|
10
i2p.cpp
10
i2p.cpp
@ -5,11 +5,13 @@
|
|||||||
int main( int argc, char* argv[] )
|
int main( int argc, char* argv[] )
|
||||||
{
|
{
|
||||||
Daemon.init(argc, argv);
|
Daemon.init(argc, argv);
|
||||||
Daemon.start();
|
if (Daemon.start())
|
||||||
while (Daemon.running)
|
|
||||||
{
|
{
|
||||||
//TODO Meeh: Find something better to do here.
|
while (Daemon.running)
|
||||||
std::this_thread::sleep_for (std::chrono::seconds(1));
|
{
|
||||||
|
//TODO Meeh: Find something better to do here.
|
||||||
|
std::this_thread::sleep_for (std::chrono::seconds(1));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Daemon.stop();
|
Daemon.stop();
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
|
Loading…
Reference in New Issue
Block a user