mirror of
https://github.com/PurpleI2P/i2pd.git
synced 2025-03-13 21:06:39 +01:00
commit
55c14819a3
24 changed files with 646 additions and 345 deletions
|
@ -10,20 +10,21 @@
|
|||
#include "ClientContext.h"
|
||||
#include "SOCKS.h"
|
||||
#include "WebSocks.h"
|
||||
#include "MatchedDestination.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace client
|
||||
{
|
||||
ClientContext context;
|
||||
ClientContext context;
|
||||
|
||||
ClientContext::ClientContext (): m_SharedLocalDestination (nullptr),
|
||||
m_HttpProxy (nullptr), m_SocksProxy (nullptr), m_SamBridge (nullptr),
|
||||
m_HttpProxy (nullptr), m_SocksProxy (nullptr), m_SamBridge (nullptr),
|
||||
m_BOBCommandChannel (nullptr), m_I2CPServer (nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
ClientContext::~ClientContext ()
|
||||
|
||||
ClientContext::~ClientContext ()
|
||||
{
|
||||
delete m_HttpProxy;
|
||||
delete m_SocksProxy;
|
||||
|
@ -31,20 +32,20 @@ namespace client
|
|||
delete m_BOBCommandChannel;
|
||||
delete m_I2CPServer;
|
||||
}
|
||||
|
||||
|
||||
void ClientContext::Start ()
|
||||
{
|
||||
if (!m_SharedLocalDestination)
|
||||
{
|
||||
{
|
||||
m_SharedLocalDestination = CreateNewLocalDestination (); // non-public, DSA
|
||||
m_Destinations[m_SharedLocalDestination->GetIdentity ()->GetIdentHash ()] = m_SharedLocalDestination;
|
||||
m_SharedLocalDestination->Start ();
|
||||
}
|
||||
|
||||
|
||||
m_AddressBook.Start ();
|
||||
|
||||
std::shared_ptr<ClientDestination> localDestination;
|
||||
|
||||
m_AddressBook.Start ();
|
||||
|
||||
std::shared_ptr<ClientDestination> localDestination;
|
||||
bool httproxy; i2p::config::GetOption("httpproxy.enabled", httproxy);
|
||||
if (httproxy) {
|
||||
std::string httpProxyKeys; i2p::config::GetOption("httpproxy.keys", httpProxyKeys);
|
||||
|
@ -60,7 +61,7 @@ namespace client
|
|||
std::map<std::string, std::string> params;
|
||||
ReadI2CPOptionsFromConfig ("httpproxy.", params);
|
||||
localDestination = CreateNewLocalDestination (keys, false, ¶ms);
|
||||
}
|
||||
}
|
||||
else
|
||||
LogPrint(eLogError, "Clients: failed to load HTTP Proxy key");
|
||||
}
|
||||
|
@ -71,10 +72,10 @@ namespace client
|
|||
LogPrint(eLogError, "Clients: Exception in HTTP Proxy: ", e.what());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
localDestination = nullptr;
|
||||
bool socksproxy; i2p::config::GetOption("socksproxy.enabled", socksproxy);
|
||||
if (socksproxy)
|
||||
if (socksproxy)
|
||||
{
|
||||
std::string socksProxyKeys; i2p::config::GetOption("socksproxy.keys", socksProxyKeys);
|
||||
std::string socksProxyAddr; i2p::config::GetOption("socksproxy.address", socksProxyAddr);
|
||||
|
@ -104,8 +105,8 @@ namespace client
|
|||
}
|
||||
|
||||
// I2P tunnels
|
||||
ReadTunnels ();
|
||||
|
||||
ReadTunnels ();
|
||||
|
||||
// SAM
|
||||
bool sam; i2p::config::GetOption("sam.enabled", sam);
|
||||
if (sam) {
|
||||
|
@ -118,7 +119,7 @@ namespace client
|
|||
} catch (std::exception& e) {
|
||||
LogPrint(eLogError, "Clients: Exception in SAM bridge: ", e.what());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// BOB
|
||||
bool bob; i2p::config::GetOption("bob.enabled", bob);
|
||||
|
@ -132,27 +133,27 @@ namespace client
|
|||
} catch (std::exception& e) {
|
||||
LogPrint(eLogError, "Clients: Exception in BOB bridge: ", e.what());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// I2CP
|
||||
bool i2cp; i2p::config::GetOption("i2cp.enabled", i2cp);
|
||||
if (i2cp)
|
||||
if (i2cp)
|
||||
{
|
||||
std::string i2cpAddr; i2p::config::GetOption("i2cp.address", i2cpAddr);
|
||||
uint16_t i2cpPort; i2p::config::GetOption("i2cp.port", i2cpPort);
|
||||
LogPrint(eLogInfo, "Clients: starting I2CP at ", i2cpAddr, ":", i2cpPort);
|
||||
try
|
||||
try
|
||||
{
|
||||
m_I2CPServer = new I2CPServer (i2cpAddr, i2cpPort);
|
||||
m_I2CPServer->Start ();
|
||||
}
|
||||
catch (std::exception& e)
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
LogPrint(eLogError, "Clients: Exception in I2CP: ", e.what());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_AddressBook.StartResolvers ();
|
||||
m_AddressBook.StartResolvers ();
|
||||
|
||||
// start UDP cleanup
|
||||
if (!m_ServerForwards.empty ())
|
||||
|
@ -161,7 +162,7 @@ namespace client
|
|||
ScheduleCleanupUDP();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ClientContext::Stop ()
|
||||
{
|
||||
if (m_HttpProxy)
|
||||
|
@ -185,28 +186,28 @@ namespace client
|
|||
LogPrint(eLogInfo, "Clients: stopping I2P client tunnel on port ", it.first);
|
||||
it.second->Stop ();
|
||||
}
|
||||
m_ClientTunnels.clear ();
|
||||
m_ClientTunnels.clear ();
|
||||
|
||||
for (auto& it: m_ServerTunnels)
|
||||
{
|
||||
LogPrint(eLogInfo, "Clients: stopping I2P server tunnel");
|
||||
it.second->Stop ();
|
||||
}
|
||||
m_ServerTunnels.clear ();
|
||||
m_ServerTunnels.clear ();
|
||||
|
||||
if (m_SamBridge)
|
||||
{
|
||||
LogPrint(eLogInfo, "Clients: stopping SAM bridge");
|
||||
m_SamBridge->Stop ();
|
||||
delete m_SamBridge;
|
||||
delete m_SamBridge;
|
||||
m_SamBridge = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_BOBCommandChannel)
|
||||
{
|
||||
LogPrint(eLogInfo, "Clients: stopping BOB command channel");
|
||||
m_BOBCommandChannel->Stop ();
|
||||
delete m_BOBCommandChannel;
|
||||
delete m_BOBCommandChannel;
|
||||
m_BOBCommandChannel = nullptr;
|
||||
}
|
||||
|
||||
|
@ -214,7 +215,7 @@ namespace client
|
|||
{
|
||||
LogPrint(eLogInfo, "Clients: stopping I2CP");
|
||||
m_I2CPServer->Stop ();
|
||||
delete m_I2CPServer;
|
||||
delete m_I2CPServer;
|
||||
m_I2CPServer = nullptr;
|
||||
}
|
||||
|
||||
|
@ -226,18 +227,18 @@ namespace client
|
|||
m_ServerForwards.clear();
|
||||
m_ClientForwards.clear();
|
||||
}
|
||||
|
||||
|
||||
if (m_CleanupUDPTimer)
|
||||
{
|
||||
m_CleanupUDPTimer->cancel ();
|
||||
m_CleanupUDPTimer = nullptr;
|
||||
m_CleanupUDPTimer->cancel ();
|
||||
m_CleanupUDPTimer = nullptr;
|
||||
}
|
||||
|
||||
for (auto& it: m_Destinations)
|
||||
it.second->Stop ();
|
||||
m_Destinations.clear ();
|
||||
m_SharedLocalDestination = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void ClientContext::ReloadConfig ()
|
||||
{
|
||||
|
@ -246,14 +247,14 @@ namespace client
|
|||
Stop();
|
||||
Start();
|
||||
}
|
||||
|
||||
|
||||
bool ClientContext::LoadPrivateKeys (i2p::data::PrivateKeys& keys, const std::string& filename, i2p::data::SigningKeyType sigType)
|
||||
{
|
||||
bool success = true;
|
||||
std::string fullPath = i2p::fs::DataDirPath (filename);
|
||||
std::ifstream s(fullPath, std::ifstream::binary);
|
||||
if (s.is_open ())
|
||||
{
|
||||
if (s.is_open ())
|
||||
{
|
||||
s.seekg (0, std::ios::end);
|
||||
size_t len = s.tellg();
|
||||
s.seekg (0, std::ios::beg);
|
||||
|
@ -267,18 +268,18 @@ namespace client
|
|||
else
|
||||
LogPrint (eLogInfo, "Clients: Local address ", m_AddressBook.ToAddress(keys.GetPublic ()->GetIdentHash ()), " loaded");
|
||||
delete[] buf;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrint (eLogError, "Clients: can't open file ", fullPath, " Creating new one with signature type ", sigType);
|
||||
keys = i2p::data::PrivateKeys::CreateRandomKeys (sigType);
|
||||
keys = i2p::data::PrivateKeys::CreateRandomKeys (sigType);
|
||||
std::ofstream f (fullPath, std::ofstream::binary | std::ofstream::out);
|
||||
size_t len = keys.GetFullLen ();
|
||||
uint8_t * buf = new uint8_t[len];
|
||||
len = keys.ToBuffer (buf, len);
|
||||
f.write ((char *)buf, len);
|
||||
delete[] buf;
|
||||
|
||||
|
||||
LogPrint (eLogInfo, "Clients: New private keys file ", fullPath, " for ", m_AddressBook.ToAddress(keys.GetPublic ()->GetIdentHash ()), " created");
|
||||
}
|
||||
return success;
|
||||
|
@ -306,9 +307,9 @@ namespace client
|
|||
}
|
||||
return infos;
|
||||
}
|
||||
|
||||
|
||||
std::shared_ptr<ClientDestination> ClientContext::CreateNewLocalDestination (bool isPublic, i2p::data::SigningKeyType sigType,
|
||||
const std::map<std::string, std::string> * params)
|
||||
const std::map<std::string, std::string> * params)
|
||||
{
|
||||
i2p::data::PrivateKeys keys = i2p::data::PrivateKeys::CreateRandomKeys (sigType);
|
||||
auto localDestination = std::make_shared<ClientDestination> (keys, isPublic, params);
|
||||
|
@ -318,6 +319,16 @@ namespace client
|
|||
return localDestination;
|
||||
}
|
||||
|
||||
std::shared_ptr<ClientDestination> ClientContext::CreateNewMatchedTunnelDestination(const i2p::data::PrivateKeys &keys, const std::string & name, const std::map<std::string, std::string> * params)
|
||||
{
|
||||
MatchedTunnelDestination * cl = new MatchedTunnelDestination(keys, name, params);
|
||||
auto localDestination = std::shared_ptr<ClientDestination>(cl);
|
||||
std::unique_lock<std::mutex> l(m_DestinationsMutex);
|
||||
m_Destinations[localDestination->GetIdentHash ()] = localDestination;
|
||||
localDestination->Start ();
|
||||
return localDestination;
|
||||
}
|
||||
|
||||
void ClientContext::DeleteLocalDestination (std::shared_ptr<ClientDestination> destination)
|
||||
{
|
||||
if (!destination) return;
|
||||
|
@ -328,7 +339,7 @@ namespace client
|
|||
{
|
||||
std::unique_lock<std::mutex> l(m_DestinationsMutex);
|
||||
m_Destinations.erase (it);
|
||||
}
|
||||
}
|
||||
d->Stop ();
|
||||
}
|
||||
}
|
||||
|
@ -341,32 +352,32 @@ namespace client
|
|||
{
|
||||
LogPrint (eLogWarning, "Clients: Local destination ", m_AddressBook.ToAddress(keys.GetPublic ()->GetIdentHash ()), " exists");
|
||||
if (!it->second->IsRunning ())
|
||||
{
|
||||
{
|
||||
it->second->Start ();
|
||||
return it->second;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
auto localDestination = std::make_shared<ClientDestination> (keys, isPublic, params);
|
||||
std::unique_lock<std::mutex> l(m_DestinationsMutex);
|
||||
m_Destinations[keys.GetPublic ()->GetIdentHash ()] = localDestination;
|
||||
localDestination->Start ();
|
||||
return localDestination;
|
||||
}
|
||||
|
||||
|
||||
std::shared_ptr<ClientDestination> ClientContext::FindLocalDestination (const i2p::data::IdentHash& destination) const
|
||||
{
|
||||
auto it = m_Destinations.find (destination);
|
||||
if (it != m_Destinations.end ())
|
||||
return it->second;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Section, typename Type>
|
||||
std::string ClientContext::GetI2CPOption (const Section& section, const std::string& name, const Type& value) const
|
||||
{
|
||||
return section.second.get (boost::property_tree::ptree::path_type (name, '/'), std::to_string (value));
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Section>
|
||||
void ClientContext::ReadI2CPOptions (const Section& section, std::map<std::string, std::string>& options) const
|
||||
|
@ -378,24 +389,24 @@ namespace client
|
|||
options[I2CP_PARAM_TAGS_TO_SEND] = GetI2CPOption (section, I2CP_PARAM_TAGS_TO_SEND, DEFAULT_TAGS_TO_SEND);
|
||||
options[I2CP_PARAM_MIN_TUNNEL_LATENCY] = GetI2CPOption(section, I2CP_PARAM_MIN_TUNNEL_LATENCY, DEFAULT_MIN_TUNNEL_LATENCY);
|
||||
options[I2CP_PARAM_MAX_TUNNEL_LATENCY] = GetI2CPOption(section, I2CP_PARAM_MAX_TUNNEL_LATENCY, DEFAULT_MAX_TUNNEL_LATENCY);
|
||||
}
|
||||
}
|
||||
|
||||
void ClientContext::ReadI2CPOptionsFromConfig (const std::string& prefix, std::map<std::string, std::string>& options) const
|
||||
{
|
||||
std::string value;
|
||||
if (i2p::config::GetOption(prefix + I2CP_PARAM_INBOUND_TUNNEL_LENGTH, value))
|
||||
std::string value;
|
||||
if (i2p::config::GetOption(prefix + I2CP_PARAM_INBOUND_TUNNEL_LENGTH, value))
|
||||
options[I2CP_PARAM_INBOUND_TUNNEL_LENGTH] = value;
|
||||
if (i2p::config::GetOption(prefix + I2CP_PARAM_INBOUND_TUNNELS_QUANTITY, value))
|
||||
options[I2CP_PARAM_INBOUND_TUNNELS_QUANTITY] = value;
|
||||
if (i2p::config::GetOption(prefix + I2CP_PARAM_OUTBOUND_TUNNEL_LENGTH, value))
|
||||
if (i2p::config::GetOption(prefix + I2CP_PARAM_INBOUND_TUNNELS_QUANTITY, value))
|
||||
options[I2CP_PARAM_INBOUND_TUNNELS_QUANTITY] = value;
|
||||
if (i2p::config::GetOption(prefix + I2CP_PARAM_OUTBOUND_TUNNEL_LENGTH, value))
|
||||
options[I2CP_PARAM_OUTBOUND_TUNNEL_LENGTH] = value;
|
||||
if (i2p::config::GetOption(prefix + I2CP_PARAM_OUTBOUND_TUNNELS_QUANTITY, value))
|
||||
if (i2p::config::GetOption(prefix + I2CP_PARAM_OUTBOUND_TUNNELS_QUANTITY, value))
|
||||
options[I2CP_PARAM_OUTBOUND_TUNNELS_QUANTITY] = value;
|
||||
if (i2p::config::GetOption(prefix + I2CP_PARAM_MIN_TUNNEL_LATENCY, value))
|
||||
options[I2CP_PARAM_MIN_TUNNEL_LATENCY] = value;
|
||||
if (i2p::config::GetOption(prefix + I2CP_PARAM_MAX_TUNNEL_LATENCY, value))
|
||||
options[I2CP_PARAM_MAX_TUNNEL_LATENCY] = value;
|
||||
}
|
||||
}
|
||||
|
||||
void ClientContext::ReadTunnels ()
|
||||
{
|
||||
|
@ -411,20 +422,20 @@ namespace client
|
|||
}
|
||||
}
|
||||
LogPrint(eLogDebug, "FS: tunnels config file: ", tunConf);
|
||||
try
|
||||
try
|
||||
{
|
||||
boost::property_tree::read_ini (tunConf, pt);
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
LogPrint (eLogWarning, "Clients: Can't read ", tunConf, ": ", ex.what ());
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
int numClientTunnels = 0, numServerTunnels = 0;
|
||||
for (auto& section: pt)
|
||||
{
|
||||
std::string name = section.first;
|
||||
std::string name = section.first;
|
||||
try
|
||||
{
|
||||
std::string type = section.second.get<std::string> (I2P_TUNNELS_SECTION_TYPE);
|
||||
|
@ -440,13 +451,14 @@ namespace client
|
|||
dest = section.second.get<std::string> (I2P_CLIENT_TUNNEL_DESTINATION);
|
||||
int port = section.second.get<int> (I2P_CLIENT_TUNNEL_PORT);
|
||||
// optional params
|
||||
bool matchTunnels = section.second.get(I2P_CLIENT_TUNNEL_MATCH_TUNNELS, false);
|
||||
std::string keys = section.second.get (I2P_CLIENT_TUNNEL_KEYS, "");
|
||||
std::string address = section.second.get (I2P_CLIENT_TUNNEL_ADDRESS, "127.0.0.1");
|
||||
int destinationPort = section.second.get (I2P_CLIENT_TUNNEL_DESTINATION_PORT, 0);
|
||||
i2p::data::SigningKeyType sigType = section.second.get (I2P_CLIENT_TUNNEL_SIGNATURE_TYPE, i2p::data::SIGNING_KEY_TYPE_ECDSA_SHA256_P256);
|
||||
// I2CP
|
||||
std::map<std::string, std::string> options;
|
||||
ReadI2CPOptions (section, options);
|
||||
std::map<std::string, std::string> options;
|
||||
ReadI2CPOptions (section, options);
|
||||
|
||||
std::shared_ptr<ClientDestination> localDestination = nullptr;
|
||||
if (keys.length () > 0)
|
||||
|
@ -456,9 +468,15 @@ namespace client
|
|||
{
|
||||
localDestination = FindLocalDestination (k.GetPublic ()->GetIdentHash ());
|
||||
if (!localDestination)
|
||||
localDestination = CreateNewLocalDestination (k, type == I2P_TUNNELS_SECTION_TYPE_UDPCLIENT, &options);
|
||||
{
|
||||
if(matchTunnels)
|
||||
localDestination = CreateNewMatchedTunnelDestination(k, dest, &options);
|
||||
else
|
||||
localDestination = CreateNewLocalDestination (k, type == I2P_TUNNELS_SECTION_TYPE_UDPCLIENT, &options);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (type == I2P_TUNNELS_SECTION_TYPE_UDPCLIENT) {
|
||||
// udp client
|
||||
// TODO: hostnames
|
||||
|
@ -515,7 +533,7 @@ namespace client
|
|||
|| type == I2P_TUNNELS_SECTION_TYPE_HTTP
|
||||
|| type == I2P_TUNNELS_SECTION_TYPE_IRC
|
||||
|| type == I2P_TUNNELS_SECTION_TYPE_UDPSERVER)
|
||||
{
|
||||
{
|
||||
// mandatory params
|
||||
std::string host = section.second.get<std::string> (I2P_SERVER_TUNNEL_HOST);
|
||||
int port = section.second.get<int> (I2P_SERVER_TUNNEL_PORT);
|
||||
|
@ -532,15 +550,15 @@ namespace client
|
|||
bool isUniqueLocal = section.second.get(I2P_SERVER_TUNNEL_ENABLE_UNIQUE_LOCAL, true);
|
||||
|
||||
// I2CP
|
||||
std::map<std::string, std::string> options;
|
||||
ReadI2CPOptions (section, options);
|
||||
std::map<std::string, std::string> options;
|
||||
ReadI2CPOptions (section, options);
|
||||
|
||||
std::shared_ptr<ClientDestination> localDestination = nullptr;
|
||||
i2p::data::PrivateKeys k;
|
||||
if(!LoadPrivateKeys (k, keys, sigType))
|
||||
continue;
|
||||
localDestination = FindLocalDestination (k.GetPublic ()->GetIdentHash ());
|
||||
if (!localDestination)
|
||||
if (!localDestination)
|
||||
localDestination = CreateNewLocalDestination (k, true, &options);
|
||||
if (type == I2P_TUNNELS_SECTION_TYPE_UDPSERVER)
|
||||
{
|
||||
|
@ -549,7 +567,7 @@ namespace client
|
|||
auto localAddress = boost::asio::ip::address::from_string(address);
|
||||
boost::asio::ip::udp::endpoint endpoint(boost::asio::ip::address::from_string(host), port);
|
||||
I2PUDPServerTunnel * serverTunnel = new I2PUDPServerTunnel(name, localDestination, localAddress, endpoint, port);
|
||||
if(!isUniqueLocal)
|
||||
if(!isUniqueLocal)
|
||||
{
|
||||
LogPrint(eLogInfo, "Clients: disabling loopback address mapping");
|
||||
serverTunnel->SetUniqueLocal(isUniqueLocal);
|
||||
|
@ -566,10 +584,10 @@ namespace client
|
|||
}
|
||||
else
|
||||
LogPrint(eLogError, "Clients: I2P Server Forward for destination/port ", m_AddressBook.ToAddress(localDestination->GetIdentHash()), "/", port, "already exists");
|
||||
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
I2PServerTunnel * serverTunnel;
|
||||
if (type == I2P_TUNNELS_SECTION_TYPE_HTTP)
|
||||
serverTunnel = new I2PServerTunnelHTTP (name, host, port, localDestination, hostOverride, inPort, gzip);
|
||||
|
@ -594,7 +612,7 @@ namespace client
|
|||
{
|
||||
comma = accessList.find (',', pos);
|
||||
i2p::data::IdentHash ident;
|
||||
ident.FromBase32 (accessList.substr (pos, comma != std::string::npos ? comma - pos : std::string::npos));
|
||||
ident.FromBase32 (accessList.substr (pos, comma != std::string::npos ? comma - pos : std::string::npos));
|
||||
idents.insert (ident);
|
||||
pos = comma + 1;
|
||||
}
|
||||
|
@ -602,7 +620,7 @@ namespace client
|
|||
serverTunnel->SetAccessList (idents);
|
||||
}
|
||||
if (m_ServerTunnels.insert (std::make_pair (
|
||||
std::make_pair (localDestination->GetIdentHash (), inPort),
|
||||
std::make_pair (localDestination->GetIdentHash (), inPort),
|
||||
std::unique_ptr<I2PServerTunnel>(serverTunnel))).second)
|
||||
{
|
||||
serverTunnel->Start ();
|
||||
|
@ -610,21 +628,21 @@ namespace client
|
|||
}
|
||||
else
|
||||
LogPrint (eLogError, "Clients: I2P server tunnel for destination/port ", m_AddressBook.ToAddress(localDestination->GetIdentHash ()), "/", inPort, " already exists");
|
||||
|
||||
|
||||
}
|
||||
else
|
||||
LogPrint (eLogWarning, "Clients: Unknown section type=", type, " of ", name, " in ", tunConf);
|
||||
|
||||
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
LogPrint (eLogError, "Clients: Can't read tunnel ", name, " params: ", ex.what ());
|
||||
}
|
||||
}
|
||||
}
|
||||
LogPrint (eLogInfo, "Clients: ", numClientTunnels, " I2P client tunnels created");
|
||||
LogPrint (eLogInfo, "Clients: ", numServerTunnels, " I2P server tunnels created");
|
||||
}
|
||||
|
||||
|
||||
void ClientContext::ScheduleCleanupUDP()
|
||||
{
|
||||
if (m_CleanupUDPTimer)
|
||||
|
@ -644,5 +662,5 @@ namespace client
|
|||
ScheduleCleanupUDP();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,19 +34,21 @@ namespace client
|
|||
const char I2P_CLIENT_TUNNEL_DESTINATION[] = "destination";
|
||||
const char I2P_CLIENT_TUNNEL_KEYS[] = "keys";
|
||||
const char I2P_CLIENT_TUNNEL_SIGNATURE_TYPE[] = "signaturetype";
|
||||
const char I2P_CLIENT_TUNNEL_DESTINATION_PORT[] = "destinationport";
|
||||
const char I2P_SERVER_TUNNEL_HOST[] = "host";
|
||||
const char I2P_SERVER_TUNNEL_HOST_OVERRIDE[] = "hostoverride";
|
||||
const char I2P_CLIENT_TUNNEL_DESTINATION_PORT[] = "destinationport";
|
||||
const char I2P_CLIENT_TUNNEL_MATCH_TUNNELS[] = "matchtunnels";
|
||||
const char I2P_SERVER_TUNNEL_HOST[] = "host";
|
||||
const char I2P_SERVER_TUNNEL_HOST_OVERRIDE[] = "hostoverride";
|
||||
const char I2P_SERVER_TUNNEL_PORT[] = "port";
|
||||
const char I2P_SERVER_TUNNEL_KEYS[] = "keys";
|
||||
const char I2P_SERVER_TUNNEL_SIGNATURE_TYPE[] = "signaturetype";
|
||||
const char I2P_SERVER_TUNNEL_INPORT[] = "inport";
|
||||
const char I2P_SERVER_TUNNEL_ACCESS_LIST[] = "accesslist";
|
||||
const char I2P_SERVER_TUNNEL_ACCESS_LIST[] = "accesslist";
|
||||
const char I2P_SERVER_TUNNEL_GZIP[] = "gzip";
|
||||
const char I2P_SERVER_TUNNEL_WEBIRC_PASSWORD[] = "webircpassword";
|
||||
const char I2P_SERVER_TUNNEL_ADDRESS[] = "address";
|
||||
const char I2P_SERVER_TUNNEL_ENABLE_UNIQUE_LOCAL[] = "enableuniquelocal";
|
||||
|
||||
|
||||
class ClientContext
|
||||
{
|
||||
public:
|
||||
|
@ -62,10 +64,11 @@ namespace client
|
|||
std::shared_ptr<ClientDestination> GetSharedLocalDestination () const { return m_SharedLocalDestination; };
|
||||
std::shared_ptr<ClientDestination> CreateNewLocalDestination (bool isPublic = false, i2p::data::SigningKeyType sigType = i2p::data::SIGNING_KEY_TYPE_DSA_SHA1,
|
||||
const std::map<std::string, std::string> * params = nullptr); // transient
|
||||
std::shared_ptr<ClientDestination> CreateNewLocalDestination (const i2p::data::PrivateKeys& keys, bool isPublic = true,
|
||||
const std::map<std::string, std::string> * params = nullptr);
|
||||
std::shared_ptr<ClientDestination> CreateNewLocalDestination (const i2p::data::PrivateKeys& keys, bool isPublic = true,
|
||||
const std::map<std::string, std::string> * params = nullptr);
|
||||
std::shared_ptr<ClientDestination> CreateNewMatchedTunnelDestination(const i2p::data::PrivateKeys &keys, const std::string & name, const std::map<std::string, std::string> * params = nullptr);
|
||||
void DeleteLocalDestination (std::shared_ptr<ClientDestination> destination);
|
||||
std::shared_ptr<ClientDestination> FindLocalDestination (const i2p::data::IdentHash& destination) const;
|
||||
std::shared_ptr<ClientDestination> FindLocalDestination (const i2p::data::IdentHash& destination) const;
|
||||
bool LoadPrivateKeys (i2p::data::PrivateKeys& keys, const std::string& filename, i2p::data::SigningKeyType sigType = i2p::data::SIGNING_KEY_TYPE_ECDSA_SHA256_P256);
|
||||
|
||||
AddressBook& GetAddressBook () { return m_AddressBook; };
|
||||
|
@ -81,16 +84,16 @@ namespace client
|
|||
std::string GetI2CPOption (const Section& section, const std::string& name, const Type& value) const;
|
||||
template<typename Section>
|
||||
void ReadI2CPOptions (const Section& section, std::map<std::string, std::string>& options) const;
|
||||
void ReadI2CPOptionsFromConfig (const std::string& prefix, std::map<std::string, std::string>& options) const;
|
||||
void ReadI2CPOptionsFromConfig (const std::string& prefix, std::map<std::string, std::string>& options) const;
|
||||
|
||||
void CleanupUDP(const boost::system::error_code & ecode);
|
||||
void ScheduleCleanupUDP();
|
||||
|
||||
|
||||
private:
|
||||
|
||||
std::mutex m_DestinationsMutex;
|
||||
std::map<i2p::data::IdentHash, std::shared_ptr<ClientDestination> > m_Destinations;
|
||||
std::shared_ptr<ClientDestination> m_SharedLocalDestination;
|
||||
std::shared_ptr<ClientDestination> m_SharedLocalDestination;
|
||||
|
||||
AddressBook m_AddressBook;
|
||||
|
||||
|
@ -99,16 +102,16 @@ namespace client
|
|||
std::map<boost::asio::ip::tcp::endpoint, std::unique_ptr<I2PService> > m_ClientTunnels; // local endpoint->tunnel
|
||||
std::map<std::pair<i2p::data::IdentHash, int>, std::unique_ptr<I2PServerTunnel> > m_ServerTunnels; // <destination,port>->tunnel
|
||||
|
||||
std::mutex m_ForwardsMutex;
|
||||
std::mutex m_ForwardsMutex;
|
||||
std::map<boost::asio::ip::udp::endpoint, std::unique_ptr<I2PUDPClientTunnel> > m_ClientForwards; // local endpoint -> udp tunnel
|
||||
std::map<std::pair<i2p::data::IdentHash, int>, std::unique_ptr<I2PUDPServerTunnel> > m_ServerForwards; // <destination,port> -> udp tunnel
|
||||
|
||||
|
||||
SAMBridge * m_SamBridge;
|
||||
BOBCommandChannel * m_BOBCommandChannel;
|
||||
I2CPServer * m_I2CPServer;
|
||||
|
||||
std::unique_ptr<boost::asio::deadline_timer> m_CleanupUDPTimer;
|
||||
|
||||
|
||||
public:
|
||||
// for HTTP
|
||||
const decltype(m_Destinations)& GetDestinations () const { return m_Destinations; };
|
||||
|
@ -119,9 +122,9 @@ namespace client
|
|||
const i2p::proxy::HTTPProxy * GetHttpProxy () const { return m_HttpProxy; }
|
||||
const i2p::proxy::SOCKSProxy * GetSocksProxy () const { return m_SocksProxy; }
|
||||
};
|
||||
|
||||
extern ClientContext context;
|
||||
}
|
||||
}
|
||||
|
||||
extern ClientContext context;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -53,7 +53,7 @@ namespace config {
|
|||
("service", value<bool>()->zero_tokens()->default_value(false), "Router will use system folders like '/var/lib/i2pd'")
|
||||
("notransit", value<bool>()->zero_tokens()->default_value(false), "Router will not accept transit tunnels at startup")
|
||||
("floodfill", value<bool>()->zero_tokens()->default_value(false), "Router will be floodfill")
|
||||
("bandwidth", value<std::string>()->default_value(""), "Bandwidth limit: integer in kbps or letters: L (32), O (256), P (2048), X (>9000)")
|
||||
("bandwidth", value<std::string>()->default_value(""), "Bandwidth limit: integer in KBps or letters: L (32), O (256), P (2048), X (>9000)")
|
||||
("ntcp", value<bool>()->zero_tokens()->default_value(true), "Enable NTCP transport")
|
||||
("ssu", value<bool>()->zero_tokens()->default_value(true), "Enable SSU transport")
|
||||
#ifdef _WIN32
|
||||
|
@ -94,6 +94,7 @@ namespace config {
|
|||
("httpproxy.latency.min", value<std::string>()->default_value("0"), "HTTP proxy min latency for tunnels")
|
||||
("httpproxy.latency.max", value<std::string>()->default_value("0"), "HTTP proxy max latency for tunnels")
|
||||
("httpproxy.outproxy", value<std::string>()->default_value(""), "HTTP proxy upstream out proxy url")
|
||||
("httpproxy.addresshelper", value<bool>()->default_value(true), "Enable or disable addresshelper")
|
||||
;
|
||||
|
||||
options_description socksproxy("SOCKS Proxy options");
|
||||
|
|
19
Datagram.cpp
19
Datagram.cpp
|
@ -255,9 +255,11 @@ namespace datagram
|
|||
}
|
||||
if(m_CurrentRemoteLease && m_CurrentRemoteLease->ExpiresWithin(DATAGRAM_SESSION_LEASE_HANDOVER_WINDOW)) {
|
||||
// bad lease, switch to next one
|
||||
if(m_RemoteLeaseSet && m_RemoteLeaseSet->IsExpired())
|
||||
m_RemoteLeaseSet = m_LocalDestination->FindLeaseSet(m_RemoteIdent);
|
||||
if(m_RemoteLeaseSet) {
|
||||
auto ls = m_RemoteLeaseSet->GetNonExpiredLeasesExcluding([&](const i2p::data::Lease& l) -> bool {
|
||||
return l.tunnelGateway == m_CurrentRemoteLease->tunnelGateway;
|
||||
return l.tunnelID == m_CurrentRemoteLease->tunnelID;
|
||||
});
|
||||
auto sz = ls.size();
|
||||
if (sz) {
|
||||
|
@ -278,7 +280,7 @@ namespace datagram
|
|||
m_CurrentOutboundTunnel = m_LocalDestination->GetTunnelPool()->GetNextOutboundTunnel(m_CurrentOutboundTunnel);
|
||||
}
|
||||
// switch lease if bad
|
||||
if(m_CurrentRemoteLease == nullptr || m_CurrentRemoteLease->ExpiresWithin(DATAGRAM_SESSION_LEASE_HANDOVER_WINDOW)) {
|
||||
if(m_CurrentRemoteLease && m_CurrentRemoteLease->ExpiresWithin(DATAGRAM_SESSION_LEASE_HANDOVER_WINDOW)) {
|
||||
if(!m_RemoteLeaseSet) {
|
||||
m_RemoteLeaseSet = m_LocalDestination->FindLeaseSet(m_RemoteIdent);
|
||||
}
|
||||
|
@ -299,6 +301,17 @@ namespace datagram
|
|||
LogPrint(eLogWarning, "DatagramSession: no remote lease set found for ", m_RemoteIdent.ToBase32());
|
||||
return nullptr;
|
||||
}
|
||||
} else if (!m_CurrentRemoteLease) {
|
||||
if(!m_RemoteLeaseSet) m_RemoteLeaseSet = m_LocalDestination->FindLeaseSet(m_RemoteIdent);
|
||||
if (m_RemoteLeaseSet)
|
||||
{
|
||||
auto ls = m_RemoteLeaseSet->GetNonExpiredLeases();
|
||||
auto sz = ls.size();
|
||||
if (sz) {
|
||||
auto idx = rand() % sz;
|
||||
m_CurrentRemoteLease = ls[idx];
|
||||
}
|
||||
}
|
||||
}
|
||||
path->outboundTunnel = m_CurrentOutboundTunnel;
|
||||
path->remoteLease = m_CurrentRemoteLease;
|
||||
|
@ -346,7 +359,7 @@ namespace datagram
|
|||
|
||||
void DatagramSession::ScheduleFlushSendQueue()
|
||||
{
|
||||
boost::posix_time::milliseconds dlt(100);
|
||||
boost::posix_time::milliseconds dlt(10);
|
||||
m_SendQueueTimer.expires_from_now(dlt);
|
||||
auto self = shared_from_this();
|
||||
m_SendQueueTimer.async_wait([self](const boost::system::error_code & ec) { if(ec) return; self->FlushSendQueue(); });
|
||||
|
|
31
Datagram.h
31
Datagram.h
|
@ -19,28 +19,28 @@ namespace client
|
|||
}
|
||||
namespace datagram
|
||||
{
|
||||
// milliseconds for max session idle time
|
||||
// milliseconds for max session idle time
|
||||
const uint64_t DATAGRAM_SESSION_MAX_IDLE = 10 * 60 * 1000;
|
||||
// milliseconds for how long we try sticking to a dead routing path before trying to switch
|
||||
const uint64_t DATAGRAM_SESSION_PATH_TIMEOUT = 10 * 1000;
|
||||
// milliseconds interval a routing path is used before switching
|
||||
const uint64_t DATAGRAM_SESSION_PATH_SWITCH_INTERVAL = 20 * 60 * 1000;
|
||||
// milliseconds before lease expire should we try switching leases
|
||||
const uint64_t DATAGRAM_SESSION_LEASE_HANDOVER_WINDOW = 10 * 1000;
|
||||
const uint64_t DATAGRAM_SESSION_LEASE_HANDOVER_WINDOW = 30 * 1000;
|
||||
// milliseconds fudge factor for leases handover
|
||||
const uint64_t DATAGRAM_SESSION_LEASE_HANDOVER_FUDGE = 1000;
|
||||
// milliseconds minimum time between path switches
|
||||
const uint64_t DATAGRAM_SESSION_PATH_MIN_LIFETIME = 5 * 1000;
|
||||
// max 64 messages buffered in send queue for each datagram session
|
||||
const size_t DATAGRAM_SEND_QUEUE_MAX_SIZE = 64;
|
||||
|
||||
|
||||
class DatagramSession : public std::enable_shared_from_this<DatagramSession>
|
||||
{
|
||||
public:
|
||||
DatagramSession(i2p::client::ClientDestination * localDestination, const i2p::data::IdentHash & remoteIdent);
|
||||
|
||||
void Start ();
|
||||
void Stop ();
|
||||
void Stop ();
|
||||
|
||||
|
||||
/** @brief ack the garlic routing path */
|
||||
|
@ -56,7 +56,7 @@ namespace datagram
|
|||
std::shared_ptr<const i2p::data::IdentHash> IBGW;
|
||||
std::shared_ptr<const i2p::data::IdentHash> OBEP;
|
||||
const uint64_t activity;
|
||||
|
||||
|
||||
Info() : IBGW(nullptr), OBEP(nullptr), activity(0) {}
|
||||
Info(const uint8_t * ibgw, const uint8_t * obep, const uint64_t a) :
|
||||
activity(a) {
|
||||
|
@ -77,7 +77,7 @@ namespace datagram
|
|||
void HandleSend(std::shared_ptr<I2NPMessage> msg);
|
||||
|
||||
std::shared_ptr<i2p::garlic::GarlicRoutingPath> GetSharedRoutingPath();
|
||||
|
||||
|
||||
void HandleLeaseSetUpdated(std::shared_ptr<i2p::data::LeaseSet> ls);
|
||||
|
||||
private:
|
||||
|
@ -95,16 +95,16 @@ namespace datagram
|
|||
|
||||
typedef std::shared_ptr<DatagramSession> DatagramSession_ptr;
|
||||
|
||||
const size_t MAX_DATAGRAM_SIZE = 32768;
|
||||
const size_t MAX_DATAGRAM_SIZE = 32768;
|
||||
class DatagramDestination
|
||||
{
|
||||
typedef std::function<void (const i2p::data::IdentityEx& from, uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len)> Receiver;
|
||||
|
||||
public:
|
||||
|
||||
|
||||
DatagramDestination (std::shared_ptr<i2p::client::ClientDestination> owner);
|
||||
~DatagramDestination ();
|
||||
|
||||
DatagramDestination (std::shared_ptr<i2p::client::ClientDestination> owner);
|
||||
~DatagramDestination ();
|
||||
|
||||
void SendDatagramTo (const uint8_t * payload, size_t len, const i2p::data::IdentHash & ident, uint16_t fromPort = 0, uint16_t toPort = 0);
|
||||
void HandleDataMessagePayload (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len);
|
||||
|
@ -116,21 +116,21 @@ namespace datagram
|
|||
void ResetReceiver (uint16_t port) { std::lock_guard<std::mutex> lock(m_ReceiversMutex); m_ReceiversByPorts.erase (port); };
|
||||
|
||||
std::shared_ptr<DatagramSession::Info> GetInfoForRemote(const i2p::data::IdentHash & remote);
|
||||
|
||||
|
||||
// clean up stale sessions
|
||||
void CleanUp ();
|
||||
|
||||
private:
|
||||
|
||||
|
||||
std::shared_ptr<DatagramSession> ObtainSession(const i2p::data::IdentHash & ident);
|
||||
|
||||
|
||||
std::shared_ptr<I2NPMessage> CreateDataMessage (const uint8_t * payload, size_t len, uint16_t fromPort, uint16_t toPort);
|
||||
|
||||
void HandleDatagram (uint16_t fromPort, uint16_t toPort, uint8_t *const& buf, size_t len);
|
||||
|
||||
/** find a receiver by port, if none by port is found try default receiever, otherwise returns nullptr */
|
||||
Receiver FindReceiver(uint16_t port);
|
||||
|
||||
|
||||
private:
|
||||
i2p::client::ClientDestination * m_Owner;
|
||||
i2p::data::IdentityEx m_Identity;
|
||||
|
@ -142,9 +142,8 @@ namespace datagram
|
|||
|
||||
i2p::data::GzipInflator m_Inflator;
|
||||
i2p::data::GzipDeflator m_Deflator;
|
||||
};
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -27,16 +27,16 @@ namespace client
|
|||
{
|
||||
const uint8_t PROTOCOL_TYPE_STREAMING = 6;
|
||||
const uint8_t PROTOCOL_TYPE_DATAGRAM = 17;
|
||||
const uint8_t PROTOCOL_TYPE_RAW = 18;
|
||||
const uint8_t PROTOCOL_TYPE_RAW = 18;
|
||||
const int PUBLISH_CONFIRMATION_TIMEOUT = 5; // in seconds
|
||||
const int PUBLISH_VERIFICATION_TIMEOUT = 10; // in seconds after successfull publish
|
||||
const int PUBLISH_MIN_INTERVAL = 20; // in seconds
|
||||
const int PUBLISH_REGULAR_VERIFICATION_INTERNAL = 100; // in seconds periodically
|
||||
const int PUBLISH_MIN_INTERVAL = 20; // in seconds
|
||||
const int PUBLISH_REGULAR_VERIFICATION_INTERNAL = 100; // in seconds periodically
|
||||
const int LEASESET_REQUEST_TIMEOUT = 5; // in seconds
|
||||
const int MAX_LEASESET_REQUEST_TIMEOUT = 40; // in seconds
|
||||
const int DESTINATION_CLEANUP_TIMEOUT = 3; // in minutes
|
||||
const int DESTINATION_CLEANUP_TIMEOUT = 3; // in minutes
|
||||
const unsigned int MAX_NUM_FLOODFILLS_PER_REQUEST = 7;
|
||||
|
||||
|
||||
// I2CP
|
||||
const char I2CP_PARAM_INBOUND_TUNNEL_LENGTH[] = "inbound.length";
|
||||
const int DEFAULT_INBOUND_TUNNEL_LENGTH = 3;
|
||||
|
@ -56,7 +56,7 @@ namespace client
|
|||
const int DEFAULT_MIN_TUNNEL_LATENCY = 0;
|
||||
const char I2CP_PARAM_MAX_TUNNEL_LATENCY[] = "latency.max";
|
||||
const int DEFAULT_MAX_TUNNEL_LATENCY = 0;
|
||||
|
||||
|
||||
typedef std::function<void (std::shared_ptr<i2p::stream::Stream> stream)> StreamRequestComplete;
|
||||
|
||||
class LeaseSetDestination: public i2p::garlic::GarlicDestination,
|
||||
|
@ -78,24 +78,24 @@ namespace client
|
|||
{
|
||||
for (auto& it: requestComplete) it (ls);
|
||||
requestComplete.clear ();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
public:
|
||||
|
||||
LeaseSetDestination (bool isPublic, const std::map<std::string, std::string> * params = nullptr);
|
||||
~LeaseSetDestination ();
|
||||
~LeaseSetDestination ();
|
||||
|
||||
virtual bool Start ();
|
||||
virtual bool Stop ();
|
||||
bool IsRunning () const { return m_IsRunning; };
|
||||
boost::asio::io_service& GetService () { return m_Service; };
|
||||
std::shared_ptr<i2p::tunnel::TunnelPool> GetTunnelPool () { return m_Pool; };
|
||||
std::shared_ptr<i2p::tunnel::TunnelPool> GetTunnelPool () { return m_Pool; };
|
||||
bool IsReady () const { return m_LeaseSet && !m_LeaseSet->IsExpired () && m_Pool->GetOutboundTunnels ().size () > 0; };
|
||||
std::shared_ptr<const i2p::data::LeaseSet> FindLeaseSet (const i2p::data::IdentHash& ident);
|
||||
bool RequestDestination (const i2p::data::IdentHash& dest, RequestComplete requestComplete = nullptr);
|
||||
void CancelDestinationRequest (const i2p::data::IdentHash& dest, bool notify = true);
|
||||
void CancelDestinationRequest (const i2p::data::IdentHash& dest, bool notify = true);
|
||||
|
||||
// implements GarlicDestination
|
||||
std::shared_ptr<const i2p::data::LocalLeaseSet> GetLeaseSet ();
|
||||
|
@ -105,7 +105,7 @@ namespace client
|
|||
// override GarlicDestination
|
||||
bool SubmitSessionKey (const uint8_t * key, const uint8_t * tag);
|
||||
void ProcessGarlicMessage (std::shared_ptr<I2NPMessage> msg);
|
||||
void ProcessDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg);
|
||||
void ProcessDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg);
|
||||
void SetLeaseSetUpdated ();
|
||||
|
||||
protected:
|
||||
|
@ -115,10 +115,10 @@ namespace client
|
|||
// I2CP
|
||||
virtual void HandleDataMessage (const uint8_t * buf, size_t len) = 0;
|
||||
virtual void CreateNewLeaseSet (std::vector<std::shared_ptr<i2p::tunnel::InboundTunnel> > tunnels) = 0;
|
||||
|
||||
|
||||
private:
|
||||
|
||||
void Run ();
|
||||
|
||||
void Run ();
|
||||
void UpdateLeaseSet ();
|
||||
void Publish ();
|
||||
void HandlePublishConfirmationTimer (const boost::system::error_code& ecode);
|
||||
|
@ -126,18 +126,18 @@ namespace client
|
|||
void HandlePublishDelayTimer (const boost::system::error_code& ecode);
|
||||
void HandleDatabaseStoreMessage (const uint8_t * buf, size_t len);
|
||||
void HandleDatabaseSearchReplyMessage (const uint8_t * buf, size_t len);
|
||||
void HandleDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg);
|
||||
void HandleDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg);
|
||||
|
||||
void RequestLeaseSet (const i2p::data::IdentHash& dest, RequestComplete requestComplete);
|
||||
bool SendLeaseSetRequest (const i2p::data::IdentHash& dest, std::shared_ptr<const i2p::data::RouterInfo> nextFloodfill, std::shared_ptr<LeaseSetRequest> request);
|
||||
bool SendLeaseSetRequest (const i2p::data::IdentHash& dest, std::shared_ptr<const i2p::data::RouterInfo> nextFloodfill, std::shared_ptr<LeaseSetRequest> request);
|
||||
void HandleRequestTimoutTimer (const boost::system::error_code& ecode, const i2p::data::IdentHash& dest);
|
||||
void HandleCleanupTimer (const boost::system::error_code& ecode);
|
||||
void CleanupRemoteLeaseSets ();
|
||||
|
||||
void CleanupRemoteLeaseSets ();
|
||||
|
||||
private:
|
||||
|
||||
volatile bool m_IsRunning;
|
||||
std::thread * m_Thread;
|
||||
std::thread * m_Thread;
|
||||
boost::asio::io_service m_Service;
|
||||
mutable std::mutex m_RemoteLeaseSetsMutex;
|
||||
std::map<i2p::data::IdentHash, std::shared_ptr<i2p::data::LeaseSet> > m_RemoteLeaseSets;
|
||||
|
@ -150,16 +150,16 @@ namespace client
|
|||
uint32_t m_PublishReplyToken;
|
||||
uint64_t m_LastSubmissionTime; // in seconds
|
||||
std::set<i2p::data::IdentHash> m_ExcludedFloodfills; // for publishing
|
||||
|
||||
boost::asio::deadline_timer m_PublishConfirmationTimer, m_PublishVerificationTimer,
|
||||
|
||||
boost::asio::deadline_timer m_PublishConfirmationTimer, m_PublishVerificationTimer,
|
||||
m_PublishDelayTimer, m_CleanupTimer;
|
||||
|
||||
public:
|
||||
|
||||
|
||||
// for HTTP only
|
||||
int GetNumRemoteLeaseSets () const { return m_RemoteLeaseSets.size (); };
|
||||
const decltype(m_RemoteLeaseSets)& GetLeaseSets () const { return m_RemoteLeaseSets; };
|
||||
};
|
||||
};
|
||||
|
||||
class ClientDestination: public LeaseSetDestination
|
||||
{
|
||||
|
@ -171,16 +171,16 @@ namespace client
|
|||
// if cancelled before ready, informs promise with nullptr
|
||||
void Ready(ReadyPromise & p);
|
||||
#endif
|
||||
|
||||
|
||||
ClientDestination (const i2p::data::PrivateKeys& keys, bool isPublic, const std::map<std::string, std::string> * params = nullptr);
|
||||
~ClientDestination ();
|
||||
|
||||
bool Start ();
|
||||
bool Stop ();
|
||||
|
||||
|
||||
virtual bool Start ();
|
||||
virtual bool Stop ();
|
||||
|
||||
const i2p::data::PrivateKeys& GetPrivateKeys () const { return m_Keys; };
|
||||
void Sign (const uint8_t * buf, int len, uint8_t * signature) const { m_Keys.Sign (buf, len, signature); };
|
||||
|
||||
void Sign (const uint8_t * buf, int len, uint8_t * signature) const { m_Keys.Sign (buf, len, signature); };
|
||||
|
||||
// streaming
|
||||
std::shared_ptr<i2p::stream::StreamingDestination> CreateStreamingDestination (int port, bool gzip = true); // additional
|
||||
std::shared_ptr<i2p::stream::StreamingDestination> GetStreamingDestination (int port = 0) const;
|
||||
|
@ -191,31 +191,31 @@ namespace client
|
|||
void StopAcceptingStreams ();
|
||||
bool IsAcceptingStreams () const;
|
||||
void AcceptOnce (const i2p::stream::StreamingDestination::Acceptor& acceptor);
|
||||
|
||||
|
||||
// datagram
|
||||
i2p::datagram::DatagramDestination * GetDatagramDestination () const { return m_DatagramDestination; };
|
||||
i2p::datagram::DatagramDestination * CreateDatagramDestination ();
|
||||
|
||||
// implements LocalDestination
|
||||
|
||||
// implements LocalDestination
|
||||
const uint8_t * GetEncryptionPrivateKey () const { return m_EncryptionPrivateKey; };
|
||||
std::shared_ptr<const i2p::data::IdentityEx> GetIdentity () const { return m_Keys.GetPublic (); };
|
||||
std::shared_ptr<const i2p::data::IdentityEx> GetIdentity () const { return m_Keys.GetPublic (); };
|
||||
|
||||
protected:
|
||||
|
||||
|
||||
void CleanupDestination ();
|
||||
// I2CP
|
||||
void HandleDataMessage (const uint8_t * buf, size_t len);
|
||||
void CreateNewLeaseSet (std::vector<std::shared_ptr<i2p::tunnel::InboundTunnel> > tunnels);
|
||||
|
||||
|
||||
private:
|
||||
|
||||
std::shared_ptr<ClientDestination> GetSharedFromThis ()
|
||||
{ return std::static_pointer_cast<ClientDestination>(shared_from_this ()); }
|
||||
{ return std::static_pointer_cast<ClientDestination>(shared_from_this ()); }
|
||||
void PersistTemporaryKeys ();
|
||||
#ifdef I2LUA
|
||||
void ScheduleCheckForReady(ReadyPromise * p);
|
||||
void HandleCheckForReady(const boost::system::error_code & ecode, ReadyPromise * p);
|
||||
#endif
|
||||
#endif
|
||||
private:
|
||||
|
||||
i2p::data::PrivateKeys m_Keys;
|
||||
|
@ -226,13 +226,13 @@ namespace client
|
|||
i2p::datagram::DatagramDestination * m_DatagramDestination;
|
||||
|
||||
boost::asio::deadline_timer m_ReadyChecker;
|
||||
|
||||
|
||||
public:
|
||||
|
||||
// for HTTP only
|
||||
std::vector<std::shared_ptr<const i2p::stream::Stream> > GetAllStreams () const;
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -437,17 +437,18 @@ namespace garlic
|
|||
if (it != m_Tags.end ())
|
||||
{
|
||||
// tag found. Use AES
|
||||
auto decryption = it->second;
|
||||
m_Tags.erase (it); // tag might be used only once
|
||||
if (length >= 32)
|
||||
{
|
||||
uint8_t iv[32]; // IV is first 16 bytes
|
||||
SHA256(buf, 32, iv);
|
||||
it->second->SetIV (iv);
|
||||
it->second->Decrypt (buf + 32, length - 32, buf + 32);
|
||||
HandleAESBlock (buf + 32, length - 32, it->second, msg->from);
|
||||
decryption->SetIV (iv);
|
||||
decryption->Decrypt (buf + 32, length - 32, buf + 32);
|
||||
HandleAESBlock (buf + 32, length - 32, decryption, msg->from);
|
||||
}
|
||||
else
|
||||
LogPrint (eLogWarning, "Garlic: message length ", length, " is less than 32 bytes");
|
||||
m_Tags.erase (it); // tag might be used only once
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
87
Gost.cpp
87
Gost.cpp
|
@ -438,5 +438,92 @@ namespace crypto
|
|||
memset (iv, 0, 64);
|
||||
H (iv, buf, len, digest);
|
||||
}
|
||||
|
||||
// reverse order
|
||||
struct GOSTR3411_2012_CTX
|
||||
{
|
||||
GOST3411Block h, N, s, m;
|
||||
size_t len;
|
||||
bool is512;
|
||||
};
|
||||
|
||||
GOSTR3411_2012_CTX * GOSTR3411_2012_CTX_new ()
|
||||
{
|
||||
return new GOSTR3411_2012_CTX;
|
||||
}
|
||||
|
||||
void GOSTR3411_2012_CTX_free (GOSTR3411_2012_CTX * ctx)
|
||||
{
|
||||
delete ctx;
|
||||
}
|
||||
|
||||
void GOSTR3411_2012_CTX_Init (GOSTR3411_2012_CTX * ctx, bool is512)
|
||||
{
|
||||
uint8_t iv[64];
|
||||
memset (iv, is512 ? 0 : 1, 64);
|
||||
memcpy (ctx->h.buf, iv, 64);
|
||||
memset (ctx->N.buf, 0, 64);
|
||||
memset (ctx->s.buf, 0, 64);
|
||||
ctx->len = 0;
|
||||
ctx->is512 = is512;
|
||||
}
|
||||
|
||||
void GOSTR3411_2012_CTX_Update (const uint8_t * buf, size_t len, GOSTR3411_2012_CTX * ctx)
|
||||
{
|
||||
if (!len) return;
|
||||
if (ctx->len > 0) // something left from buffer
|
||||
{
|
||||
size_t l = 64 - ctx->len;
|
||||
if (len < l) l = len;
|
||||
for (size_t i = 0; i < l; i++)
|
||||
ctx->m.buf[ctx->len + i] = buf[l-i-1]; // invert
|
||||
ctx->len += l; len -= l; buf += l;
|
||||
|
||||
ctx->h = gN (ctx->N, ctx->h, ctx->m);
|
||||
ctx->N.Add (512);
|
||||
ctx->s = ctx->m + ctx->s;
|
||||
}
|
||||
while (len >= 64)
|
||||
{
|
||||
for (size_t i = 0; i < 64; i++)
|
||||
ctx->m.buf[i] = buf[63-i]; // invert
|
||||
len -= 64; buf += 64;
|
||||
ctx->h = gN (ctx->N, ctx->h, ctx->m);
|
||||
ctx->N.Add (512);
|
||||
ctx->s = ctx->m + ctx->s;
|
||||
}
|
||||
if (len > 0) // carry remaining
|
||||
{
|
||||
for (size_t i = 0; i < len; i++)
|
||||
ctx->m.buf[i] = buf[len-i-1]; // invert
|
||||
}
|
||||
ctx->len = len;
|
||||
}
|
||||
|
||||
void GOSTR3411_2012_CTX_Finish (uint8_t * digest, GOSTR3411_2012_CTX * ctx)
|
||||
{
|
||||
GOST3411Block m;
|
||||
size_t padding = 64 - ctx->len;
|
||||
if (padding)
|
||||
{
|
||||
memset (m.buf, 0, padding - 1);
|
||||
m.buf[padding - 1] = 1;
|
||||
}
|
||||
memcpy (m.buf + padding, ctx->m.buf, ctx->len);
|
||||
|
||||
ctx->h = gN (ctx->N, ctx->h, m);
|
||||
ctx->N.Add (ctx->len*8);
|
||||
ctx->s = m + ctx->s;
|
||||
|
||||
GOST3411Block N0;
|
||||
memset (N0.buf, 0, 64);
|
||||
ctx->h = gN (N0, ctx->h, ctx->N);
|
||||
ctx->h = gN (N0, ctx->h, ctx->s);
|
||||
|
||||
size_t sz = ctx->is512 ? 64 : 32;
|
||||
for (size_t i = 0; i < sz; i++)
|
||||
digest[i] = ctx->h.buf[sz - i - 1];
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
9
Gost.h
9
Gost.h
|
@ -45,8 +45,17 @@ namespace crypto
|
|||
|
||||
std::unique_ptr<GOSTR3410Curve>& GetGOSTR3410Curve (GOSTR3410ParamSet paramSet);
|
||||
|
||||
// Big Endian
|
||||
void GOSTR3411_2012_256 (const uint8_t * buf, size_t len, uint8_t * digest);
|
||||
void GOSTR3411_2012_512 (const uint8_t * buf, size_t len, uint8_t * digest);
|
||||
|
||||
// Little Endian
|
||||
struct GOSTR3411_2012_CTX;
|
||||
GOSTR3411_2012_CTX * GOSTR3411_2012_CTX_new ();
|
||||
void GOSTR3411_2012_CTX_Init (GOSTR3411_2012_CTX * ctx, bool is512 = true);
|
||||
void GOSTR3411_2012_CTX_Update (const uint8_t * buf, size_t len, GOSTR3411_2012_CTX * ctx);
|
||||
void GOSTR3411_2012_CTX_Finish (uint8_t * digest, GOSTR3411_2012_CTX * ctx);
|
||||
void GOSTR3411_2012_CTX_free (GOSTR3411_2012_CTX * ctx);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -237,7 +237,15 @@ namespace proxy {
|
|||
LogPrint(eLogDebug, "HTTPProxy: requested: ", m_ClientRequest.uri);
|
||||
m_RequestURL.parse(m_ClientRequest.uri);
|
||||
|
||||
if (ExtractAddressHelper(m_RequestURL, b64)) {
|
||||
if (ExtractAddressHelper(m_RequestURL, b64))
|
||||
{
|
||||
bool addresshelper; i2p::config::GetOption("httpproxy.addresshelper", addresshelper);
|
||||
if (!addresshelper)
|
||||
{
|
||||
LogPrint(eLogWarning, "HTTPProxy: addresshelper disabled");
|
||||
GenericProxyError("Invalid request", "adddresshelper is not supported");
|
||||
return true;
|
||||
}
|
||||
i2p::client::context.GetAddressBook ().InsertAddress (m_RequestURL.host, b64);
|
||||
LogPrint (eLogInfo, "HTTPProxy: added b64 from addresshelper for ", m_RequestURL.host);
|
||||
std::string full_url = m_RequestURL.to_string();
|
||||
|
|
|
@ -209,6 +209,7 @@ namespace tunnel
|
|||
|
||||
std::shared_ptr<I2NPMessage> NewI2NPMessage ();
|
||||
std::shared_ptr<I2NPMessage> NewI2NPShortMessage ();
|
||||
std::shared_ptr<I2NPMessage> NewI2NPTunnelMessage ();
|
||||
std::shared_ptr<I2NPMessage> NewI2NPMessage (size_t len);
|
||||
|
||||
std::shared_ptr<I2NPMessage> CreateI2NPMessage (I2NPMessageType msgType, const uint8_t * buf, size_t len, uint32_t replyMsgID = 0);
|
||||
|
|
94
I2PTunnel.h
94
I2PTunnel.h
|
@ -19,9 +19,9 @@ namespace i2p
|
|||
namespace client
|
||||
{
|
||||
const size_t I2P_TUNNEL_CONNECTION_BUFFER_SIZE = 65536;
|
||||
const int I2P_TUNNEL_CONNECTION_MAX_IDLE = 3600; // in seconds
|
||||
const int I2P_TUNNEL_CONNECTION_MAX_IDLE = 3600; // in seconds
|
||||
const int I2P_TUNNEL_DESTINATION_REQUEST_TIMEOUT = 10; // in seconds
|
||||
// for HTTP tunnels
|
||||
// for HTTP tunnels
|
||||
const char X_I2P_DEST_HASH[] = "X-I2P-DestHash"; // hash in base64
|
||||
const char X_I2P_DEST_B64[] = "X-I2P-DestB64"; // full address in base64
|
||||
const char X_I2P_DEST_B32[] = "X-I2P-DestB32"; // .b32.i2p address
|
||||
|
@ -33,21 +33,21 @@ namespace client
|
|||
I2PTunnelConnection (I2PService * owner, std::shared_ptr<boost::asio::ip::tcp::socket> socket,
|
||||
std::shared_ptr<const i2p::data::LeaseSet> leaseSet, int port = 0); // to I2P
|
||||
I2PTunnelConnection (I2PService * owner, std::shared_ptr<boost::asio::ip::tcp::socket> socket,
|
||||
std::shared_ptr<i2p::stream::Stream> stream); // to I2P using simplified API
|
||||
I2PTunnelConnection (I2PService * owner, std::shared_ptr<i2p::stream::Stream> stream, std::shared_ptr<boost::asio::ip::tcp::socket> socket,
|
||||
std::shared_ptr<i2p::stream::Stream> stream); // to I2P using simplified API
|
||||
I2PTunnelConnection (I2PService * owner, std::shared_ptr<i2p::stream::Stream> stream, std::shared_ptr<boost::asio::ip::tcp::socket> socket,
|
||||
const boost::asio::ip::tcp::endpoint& target, bool quiet = true); // from I2P
|
||||
~I2PTunnelConnection ();
|
||||
void I2PConnect (const uint8_t * msg = nullptr, size_t len = 0);
|
||||
void Connect (bool isUniqueLocal = true);
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
void Terminate ();
|
||||
void Terminate ();
|
||||
|
||||
void Receive ();
|
||||
void HandleReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred);
|
||||
void HandleReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred);
|
||||
virtual void Write (const uint8_t * buf, size_t len); // can be overloaded
|
||||
void HandleWrite (const boost::system::error_code& ecode);
|
||||
void HandleWrite (const boost::system::error_code& ecode);
|
||||
|
||||
void StreamReceive ();
|
||||
void HandleStreamReceive (const boost::system::error_code& ecode, std::size_t bytes_transferred);
|
||||
|
@ -75,28 +75,28 @@ namespace client
|
|||
|
||||
protected:
|
||||
|
||||
void Write (const uint8_t * buf, size_t len);
|
||||
|
||||
private:
|
||||
void Write (const uint8_t * buf, size_t len);
|
||||
|
||||
private:
|
||||
|
||||
std::stringstream m_InHeader, m_OutHeader;
|
||||
bool m_HeaderSent, m_ConnectionSent, m_ProxyConnectionSent;
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
class I2PServerTunnelConnectionHTTP: public I2PTunnelConnection
|
||||
{
|
||||
public:
|
||||
|
||||
|
||||
I2PServerTunnelConnectionHTTP (I2PService * owner, std::shared_ptr<i2p::stream::Stream> stream,
|
||||
std::shared_ptr<boost::asio::ip::tcp::socket> socket,
|
||||
const boost::asio::ip::tcp::endpoint& target, const std::string& host);
|
||||
std::shared_ptr<boost::asio::ip::tcp::socket> socket,
|
||||
const boost::asio::ip::tcp::endpoint& target, const std::string& host);
|
||||
|
||||
protected:
|
||||
|
||||
void Write (const uint8_t * buf, size_t len);
|
||||
|
||||
private:
|
||||
|
||||
|
||||
std::string m_Host;
|
||||
std::stringstream m_InHeader, m_OutHeader;
|
||||
bool m_HeaderSent;
|
||||
|
@ -106,21 +106,21 @@ namespace client
|
|||
class I2PTunnelConnectionIRC: public I2PTunnelConnection
|
||||
{
|
||||
public:
|
||||
|
||||
|
||||
I2PTunnelConnectionIRC (I2PService * owner, std::shared_ptr<i2p::stream::Stream> stream,
|
||||
std::shared_ptr<boost::asio::ip::tcp::socket> socket,
|
||||
const boost::asio::ip::tcp::endpoint& target, const std::string& m_WebircPass);
|
||||
std::shared_ptr<boost::asio::ip::tcp::socket> socket,
|
||||
const boost::asio::ip::tcp::endpoint& target, const std::string& m_WebircPass);
|
||||
|
||||
protected:
|
||||
|
||||
void Write (const uint8_t * buf, size_t len);
|
||||
|
||||
private:
|
||||
|
||||
|
||||
std::shared_ptr<const i2p::data::IdentityEx> m_From;
|
||||
std::stringstream m_OutPacket, m_InPacket;
|
||||
bool m_NeedsWebIrc;
|
||||
std::string m_WebircPass;
|
||||
std::string m_WebircPass;
|
||||
};
|
||||
|
||||
|
||||
|
@ -133,24 +133,24 @@ namespace client
|
|||
|
||||
public:
|
||||
|
||||
I2PClientTunnel (const std::string& name, const std::string& destination,
|
||||
I2PClientTunnel (const std::string& name, const std::string& destination,
|
||||
const std::string& address, int port, std::shared_ptr<ClientDestination> localDestination, int destinationPort = 0);
|
||||
~I2PClientTunnel () {}
|
||||
|
||||
|
||||
void Start ();
|
||||
void Stop ();
|
||||
|
||||
const char* GetName() { return m_Name.c_str (); }
|
||||
|
||||
const char* GetName() { return m_Name.c_str (); }
|
||||
|
||||
private:
|
||||
|
||||
const i2p::data::IdentHash * GetIdentHash ();
|
||||
|
||||
private:
|
||||
|
||||
|
||||
std::string m_Name, m_Destination;
|
||||
const i2p::data::IdentHash * m_DestinationIdentHash;
|
||||
int m_DestinationPort;
|
||||
int m_DestinationPort;
|
||||
};
|
||||
|
||||
|
||||
|
@ -173,7 +173,7 @@ namespace client
|
|||
uint16_t RemotePort;
|
||||
|
||||
uint8_t m_Buffer[I2P_UDP_MAX_MTU];
|
||||
|
||||
|
||||
UDPSession(boost::asio::ip::udp::endpoint localEndpoint,
|
||||
const std::shared_ptr<i2p::client::ClientDestination> & localDestination,
|
||||
boost::asio::ip::udp::endpoint remote, const i2p::data::IdentHash * ident,
|
||||
|
@ -182,7 +182,7 @@ namespace client
|
|||
void Receive();
|
||||
};
|
||||
|
||||
|
||||
|
||||
/** read only info about a datagram session */
|
||||
struct DatagramSessionInfo
|
||||
{
|
||||
|
@ -205,7 +205,7 @@ namespace client
|
|||
};
|
||||
|
||||
typedef std::shared_ptr<UDPSession> UDPSessionPtr;
|
||||
|
||||
|
||||
/** server side udp tunnel, many i2p inbound to 1 ip outbound */
|
||||
class I2PUDPServerTunnel
|
||||
{
|
||||
|
@ -239,7 +239,7 @@ namespace client
|
|||
std::shared_ptr<i2p::client::ClientDestination> m_LocalDest;
|
||||
};
|
||||
|
||||
class I2PUDPClientTunnel
|
||||
class I2PUDPClientTunnel
|
||||
{
|
||||
public:
|
||||
I2PUDPClientTunnel(const std::string & name, const std::string &remoteDest,
|
||||
|
@ -249,7 +249,7 @@ namespace client
|
|||
void Start();
|
||||
const char * GetName() const { return m_Name.c_str(); }
|
||||
std::vector<std::shared_ptr<DatagramSessionInfo> > GetSessions();
|
||||
|
||||
|
||||
bool IsLocalDestination(const i2p::data::IdentHash & destination) const { return destination == m_LocalDest->GetIdentHash(); }
|
||||
|
||||
std::shared_ptr<ClientDestination> GetLocalDestination () const { return m_LocalDest; }
|
||||
|
@ -275,18 +275,18 @@ namespace client
|
|||
uint16_t RemotePort;
|
||||
bool m_cancel_resolve;
|
||||
};
|
||||
|
||||
|
||||
class I2PServerTunnel: public I2PService
|
||||
{
|
||||
public:
|
||||
|
||||
I2PServerTunnel (const std::string& name, const std::string& address, int port,
|
||||
std::shared_ptr<ClientDestination> localDestination, int inport = 0, bool gzip = true);
|
||||
I2PServerTunnel (const std::string& name, const std::string& address, int port,
|
||||
std::shared_ptr<ClientDestination> localDestination, int inport = 0, bool gzip = true);
|
||||
|
||||
void Start ();
|
||||
void Stop ();
|
||||
|
||||
void SetAccessList (const std::set<i2p::data::IdentHash>& accessList);
|
||||
void SetAccessList (const std::set<i2p::data::IdentHash>& accessList);
|
||||
|
||||
void SetUniqueLocal (bool isUniqueLocal) { m_IsUniqueLocal = isUniqueLocal; }
|
||||
bool IsUniqueLocal () const { return m_IsUniqueLocal; }
|
||||
|
@ -296,13 +296,13 @@ namespace client
|
|||
uint16_t GetLocalPort () const { return m_PortDestination->GetLocalPort (); };
|
||||
const boost::asio::ip::tcp::endpoint& GetEndpoint () const { return m_Endpoint; }
|
||||
|
||||
const char* GetName() { return m_Name.c_str (); }
|
||||
const char* GetName() { return m_Name.c_str (); }
|
||||
|
||||
void SetMaxConnsPerMinute(const uint32_t conns) { m_PortDestination->SetMaxConnsPerMinute(conns); }
|
||||
|
||||
private:
|
||||
|
||||
void HandleResolve (const boost::system::error_code& ecode, boost::asio::ip::tcp::resolver::iterator it,
|
||||
void HandleResolve (const boost::system::error_code& ecode, boost::asio::ip::tcp::resolver::iterator it,
|
||||
std::shared_ptr<boost::asio::ip::tcp::resolver> resolver);
|
||||
|
||||
void Accept ();
|
||||
|
@ -310,11 +310,11 @@ namespace client
|
|||
virtual std::shared_ptr<I2PTunnelConnection> CreateI2PConnection (std::shared_ptr<i2p::stream::Stream> stream);
|
||||
|
||||
private:
|
||||
|
||||
|
||||
bool m_IsUniqueLocal;
|
||||
std::string m_Name, m_Address;
|
||||
int m_Port;
|
||||
boost::asio::ip::tcp::endpoint m_Endpoint;
|
||||
boost::asio::ip::tcp::endpoint m_Endpoint;
|
||||
std::shared_ptr<i2p::stream::StreamingDestination> m_PortDestination;
|
||||
std::set<i2p::data::IdentHash> m_AccessList;
|
||||
bool m_IsAccessList;
|
||||
|
@ -324,9 +324,9 @@ namespace client
|
|||
{
|
||||
public:
|
||||
|
||||
I2PServerTunnelHTTP (const std::string& name, const std::string& address, int port,
|
||||
I2PServerTunnelHTTP (const std::string& name, const std::string& address, int port,
|
||||
std::shared_ptr<ClientDestination> localDestination, const std::string& host,
|
||||
int inport = 0, bool gzip = true);
|
||||
int inport = 0, bool gzip = true);
|
||||
|
||||
private:
|
||||
|
||||
|
@ -336,14 +336,14 @@ namespace client
|
|||
|
||||
std::string m_Host;
|
||||
};
|
||||
|
||||
|
||||
class I2PServerTunnelIRC: public I2PServerTunnel
|
||||
{
|
||||
public:
|
||||
|
||||
I2PServerTunnelIRC (const std::string& name, const std::string& address, int port,
|
||||
I2PServerTunnelIRC (const std::string& name, const std::string& address, int port,
|
||||
std::shared_ptr<ClientDestination> localDestination, const std::string& webircpass,
|
||||
int inport = 0, bool gzip = true);
|
||||
int inport = 0, bool gzip = true);
|
||||
|
||||
private:
|
||||
|
||||
|
@ -355,6 +355,6 @@ namespace client
|
|||
};
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -30,7 +30,8 @@ namespace data
|
|||
bool ExpiresWithin( const uint64_t t, const uint64_t fudge = 1000 ) const {
|
||||
auto expire = i2p::util::GetMillisecondsSinceEpoch ();
|
||||
if(fudge) expire += rand() % fudge;
|
||||
return endDate - expire >= t;
|
||||
if (endDate < expire) return true;
|
||||
return (endDate - expire) < t;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ INCFLAGS ?=
|
|||
# detect proper flag for c++11 support by compilers
|
||||
CXXVER := $(shell $(CXX) -dumpversion)
|
||||
ifeq ($(shell expr match $(CXX) 'clang'),5)
|
||||
NEEDED_CXXFLAGS += -std=c++11
|
||||
NEEDED_CXXFLAGS += -std=c++11
|
||||
else ifeq ($(shell expr match ${CXXVER} "4\.[0-9][0-9]"),4) # gcc >= 4.10
|
||||
NEEDED_CXXFLAGS += -std=c++11
|
||||
else ifeq ($(shell expr match ${CXXVER} "4\.[7-9]"),3) # >= 4.7
|
||||
|
|
113
MatchedDestination.cpp
Normal file
113
MatchedDestination.cpp
Normal file
|
@ -0,0 +1,113 @@
|
|||
#include "MatchedDestination.h"
|
||||
#include "Log.h"
|
||||
#include "ClientContext.h"
|
||||
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace client
|
||||
{
|
||||
MatchedTunnelDestination::MatchedTunnelDestination(const i2p::data::PrivateKeys & keys, const std::string & remoteName, const std::map<std::string, std::string> * params)
|
||||
: ClientDestination(keys, false, params),
|
||||
m_RemoteName(remoteName) {}
|
||||
|
||||
|
||||
void MatchedTunnelDestination::ResolveCurrentLeaseSet()
|
||||
{
|
||||
if(i2p::client::context.GetAddressBook().GetIdentHash(m_RemoteName, m_RemoteIdent))
|
||||
{
|
||||
auto ls = FindLeaseSet(m_RemoteIdent);
|
||||
if(ls)
|
||||
{
|
||||
HandleFoundCurrentLeaseSet(ls);
|
||||
}
|
||||
else
|
||||
RequestDestination(m_RemoteIdent, std::bind(&MatchedTunnelDestination::HandleFoundCurrentLeaseSet, this, std::placeholders::_1));
|
||||
}
|
||||
else
|
||||
LogPrint(eLogWarning, "Destination: failed to resolve ", m_RemoteName);
|
||||
}
|
||||
|
||||
void MatchedTunnelDestination::HandleFoundCurrentLeaseSet(std::shared_ptr<const i2p::data::LeaseSet> ls)
|
||||
{
|
||||
if(ls)
|
||||
{
|
||||
LogPrint(eLogDebug, "Destination: resolved remote lease set for ", m_RemoteName);
|
||||
m_RemoteLeaseSet = ls;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_ResolveTimer->expires_from_now(boost::posix_time::seconds(1));
|
||||
m_ResolveTimer->async_wait([&](const boost::system::error_code & ec) {
|
||||
if(!ec) ResolveCurrentLeaseSet();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool MatchedTunnelDestination::Start()
|
||||
{
|
||||
if(ClientDestination::Start())
|
||||
{
|
||||
m_ResolveTimer = std::make_shared<boost::asio::deadline_timer>(GetService());
|
||||
GetTunnelPool()->SetCustomPeerSelector(this);
|
||||
ResolveCurrentLeaseSet();
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MatchedTunnelDestination::Stop()
|
||||
{
|
||||
if(ClientDestination::Stop())
|
||||
{
|
||||
if(m_ResolveTimer)
|
||||
m_ResolveTimer->cancel();
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool MatchedTunnelDestination::SelectPeers(i2p::tunnel::Path & path, int hops, bool inbound)
|
||||
{
|
||||
auto pool = GetTunnelPool();
|
||||
if(!i2p::tunnel::StandardSelectPeers(path, hops, inbound, std::bind(&i2p::tunnel::TunnelPool::SelectNextHop, pool, std::placeholders::_1)))
|
||||
return false;
|
||||
// more here for outbound tunnels
|
||||
if(!inbound && m_RemoteLeaseSet)
|
||||
{
|
||||
if(m_RemoteLeaseSet->IsExpired())
|
||||
{
|
||||
ResolveCurrentLeaseSet();
|
||||
}
|
||||
if(m_RemoteLeaseSet && !m_RemoteLeaseSet->IsExpired())
|
||||
{
|
||||
// remote lease set is good
|
||||
auto leases = m_RemoteLeaseSet->GetNonExpiredLeases();
|
||||
// pick lease
|
||||
std::shared_ptr<i2p::data::RouterInfo> obep;
|
||||
while(!obep && leases.size() > 0) {
|
||||
auto idx = rand() % leases.size();
|
||||
auto lease = leases[idx];
|
||||
obep = i2p::data::netdb.FindRouter(lease->tunnelGateway);
|
||||
leases.erase(leases.begin()+idx);
|
||||
}
|
||||
if(obep) {
|
||||
path.push_back(obep->GetRouterIdentity());
|
||||
LogPrint(eLogDebug, "Destination: found OBEP matching IBGW");
|
||||
} else
|
||||
LogPrint(eLogWarning, "Destination: could not find proper IBGW for matched outbound tunnel");
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MatchedTunnelDestination::OnBuildResult(const i2p::tunnel::Path & path, bool inbound, i2p::tunnel::TunnelBuildResult result)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
36
MatchedDestination.h
Normal file
36
MatchedDestination.h
Normal file
|
@ -0,0 +1,36 @@
|
|||
#ifndef MATCHED_DESTINATION_H_
|
||||
#define MATCHED_DESTINATION_H_
|
||||
#include "Destination.h"
|
||||
#include <string>
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace client
|
||||
{
|
||||
/**
|
||||
client tunnel that uses same OBEP as IBGW of each remote lease for a remote destination
|
||||
*/
|
||||
class MatchedTunnelDestination : public ClientDestination, public i2p::tunnel::ITunnelPeerSelector
|
||||
{
|
||||
public:
|
||||
MatchedTunnelDestination(const i2p::data::PrivateKeys& keys, const std::string & remoteName, const std::map<std::string, std::string> * params = nullptr);
|
||||
bool Start();
|
||||
bool Stop();
|
||||
|
||||
bool SelectPeers(i2p::tunnel::Path & peers, int hops, bool inbound);
|
||||
bool OnBuildResult(const i2p::tunnel::Path & peers, bool inbound, i2p::tunnel::TunnelBuildResult result);
|
||||
|
||||
private:
|
||||
void ResolveCurrentLeaseSet();
|
||||
void HandleFoundCurrentLeaseSet(std::shared_ptr<const i2p::data::LeaseSet> ls);
|
||||
|
||||
private:
|
||||
std::string m_RemoteName;
|
||||
i2p::data::IdentHash m_RemoteIdent;
|
||||
std::shared_ptr<const i2p::data::LeaseSet> m_RemoteLeaseSet;
|
||||
std::shared_ptr<boost::asio::deadline_timer> m_ResolveTimer;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -99,7 +99,7 @@ namespace tunnel
|
|||
if (fragment + size < decrypted + TUNNEL_DATA_ENCRYPTED_SIZE)
|
||||
{
|
||||
// this is not last message. we have to copy it
|
||||
m.data = NewI2NPShortMessage ();
|
||||
m.data = NewI2NPTunnelMessage ();
|
||||
m.data->offset += TUNNEL_GATEWAY_HEADER_SIZE; // reserve room for TunnelGateway header
|
||||
m.data->len += TUNNEL_GATEWAY_HEADER_SIZE;
|
||||
*(m.data) = *msg;
|
||||
|
@ -154,7 +154,7 @@ namespace tunnel
|
|||
{
|
||||
if (msg.data->len + size > msg.data->maxLen)
|
||||
{
|
||||
LogPrint (eLogWarning, "TunnelMessage: I2NP message size ", msg.data->maxLen, " is not enough");
|
||||
// LogPrint (eLogWarning, "TunnelMessage: I2NP message size ", msg.data->maxLen, " is not enough");
|
||||
auto newMsg = NewI2NPMessage ();
|
||||
*newMsg = *(msg.data);
|
||||
msg.data = newMsg;
|
||||
|
|
192
TunnelPool.cpp
192
TunnelPool.cpp
|
@ -18,7 +18,7 @@ namespace i2p
|
|||
{
|
||||
namespace tunnel
|
||||
{
|
||||
|
||||
|
||||
TunnelPool::TunnelPool (int numInboundHops, int numOutboundHops, int numInboundTunnels, int numOutboundTunnels):
|
||||
m_NumInboundHops (numInboundHops), m_NumOutboundHops (numOutboundHops),
|
||||
m_NumInboundTunnels (numInboundTunnels), m_NumOutboundTunnels (numOutboundTunnels), m_IsActive (true),
|
||||
|
@ -37,25 +37,25 @@ namespace tunnel
|
|||
if (m_ExplicitPeers)
|
||||
{
|
||||
int size = m_ExplicitPeers->size ();
|
||||
if (m_NumInboundHops > size)
|
||||
if (m_NumInboundHops > size)
|
||||
{
|
||||
m_NumInboundHops = size;
|
||||
LogPrint (eLogInfo, "Tunnels: Inbound tunnel length has beed adjusted to ", size, " for explicit peers");
|
||||
}
|
||||
if (m_NumOutboundHops > size)
|
||||
}
|
||||
if (m_NumOutboundHops > size)
|
||||
{
|
||||
m_NumOutboundHops = size;
|
||||
LogPrint (eLogInfo, "Tunnels: Outbound tunnel length has beed adjusted to ", size, " for explicit peers");
|
||||
}
|
||||
}
|
||||
m_NumInboundTunnels = 1;
|
||||
m_NumOutboundTunnels = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TunnelPool::DetachTunnels ()
|
||||
{
|
||||
{
|
||||
std::unique_lock<std::mutex> l(m_InboundTunnelsMutex);
|
||||
std::unique_lock<std::mutex> l(m_InboundTunnelsMutex);
|
||||
for (auto& it: m_InboundTunnels)
|
||||
it->SetTunnelPool (nullptr);
|
||||
m_InboundTunnels.clear ();
|
||||
|
@ -67,21 +67,21 @@ namespace tunnel
|
|||
m_OutboundTunnels.clear ();
|
||||
}
|
||||
m_Tests.clear ();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void TunnelPool::TunnelCreated (std::shared_ptr<InboundTunnel> createdTunnel)
|
||||
{
|
||||
if (!m_IsActive) return;
|
||||
{
|
||||
#ifdef WITH_EVENTS
|
||||
#ifdef WITH_EVENTS
|
||||
EmitTunnelEvent("tunnels.created", createdTunnel);
|
||||
#endif
|
||||
#endif
|
||||
std::unique_lock<std::mutex> l(m_InboundTunnelsMutex);
|
||||
m_InboundTunnels.insert (createdTunnel);
|
||||
}
|
||||
if (m_LocalDestination)
|
||||
m_LocalDestination->SetLeaseSetUpdated ();
|
||||
|
||||
|
||||
OnTunnelBuildResult(createdTunnel, eBuildResultOkay);
|
||||
}
|
||||
|
||||
|
@ -89,25 +89,25 @@ namespace tunnel
|
|||
{
|
||||
if (expiredTunnel)
|
||||
{
|
||||
#ifdef WITH_EVENTS
|
||||
#ifdef WITH_EVENTS
|
||||
EmitTunnelEvent("tunnels.expired", expiredTunnel);
|
||||
#endif
|
||||
#endif
|
||||
expiredTunnel->SetTunnelPool (nullptr);
|
||||
for (auto& it: m_Tests)
|
||||
if (it.second.second == expiredTunnel) it.second.second = nullptr;
|
||||
|
||||
std::unique_lock<std::mutex> l(m_InboundTunnelsMutex);
|
||||
m_InboundTunnels.erase (expiredTunnel);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TunnelPool::TunnelCreated (std::shared_ptr<OutboundTunnel> createdTunnel)
|
||||
{
|
||||
if (!m_IsActive) return;
|
||||
{
|
||||
#ifdef WITH_EVENTS
|
||||
#ifdef WITH_EVENTS
|
||||
EmitTunnelEvent("tunnels.created", createdTunnel);
|
||||
#endif
|
||||
#endif
|
||||
std::unique_lock<std::mutex> l(m_OutboundTunnelsMutex);
|
||||
m_OutboundTunnels.insert (createdTunnel);
|
||||
}
|
||||
|
@ -120,9 +120,9 @@ namespace tunnel
|
|||
{
|
||||
if (expiredTunnel)
|
||||
{
|
||||
#ifdef WITH_EVENTS
|
||||
#ifdef WITH_EVENTS
|
||||
EmitTunnelEvent("tunnels.expired", expiredTunnel);
|
||||
#endif
|
||||
#endif
|
||||
expiredTunnel->SetTunnelPool (nullptr);
|
||||
for (auto& it: m_Tests)
|
||||
if (it.second.first == expiredTunnel) it.second.first = nullptr;
|
||||
|
@ -131,7 +131,7 @@ namespace tunnel
|
|||
m_OutboundTunnels.erase (expiredTunnel);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::vector<std::shared_ptr<InboundTunnel> > TunnelPool::GetInboundTunnels (int num) const
|
||||
{
|
||||
std::vector<std::shared_ptr<InboundTunnel> > v;
|
||||
|
@ -144,8 +144,8 @@ namespace tunnel
|
|||
{
|
||||
v.push_back (it);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
|
@ -153,7 +153,7 @@ namespace tunnel
|
|||
{
|
||||
std::unique_lock<std::mutex> l(m_OutboundTunnelsMutex);
|
||||
return GetNextTunnel (m_OutboundTunnels, excluded);
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<InboundTunnel> TunnelPool::GetNextInboundTunnel (std::shared_ptr<InboundTunnel> excluded) const
|
||||
{
|
||||
|
@ -164,11 +164,11 @@ namespace tunnel
|
|||
template<class TTunnels>
|
||||
typename TTunnels::value_type TunnelPool::GetNextTunnel (TTunnels& tunnels, typename TTunnels::value_type excluded) const
|
||||
{
|
||||
if (tunnels.empty ()) return nullptr;
|
||||
if (tunnels.empty ()) return nullptr;
|
||||
uint32_t ind = rand () % (tunnels.size ()/2 + 1), i = 0;
|
||||
typename TTunnels::value_type tunnel = nullptr;
|
||||
for (const auto& it: tunnels)
|
||||
{
|
||||
{
|
||||
if (it->IsEstablished () && it != excluded)
|
||||
{
|
||||
if(HasLatencyRequirement() && it->LatencyIsKnown() && !it->LatencyFitsRange(m_MinLatency, m_MaxLatency)) {
|
||||
|
@ -183,7 +183,7 @@ namespace tunnel
|
|||
if(HasLatencyRequirement() && !tunnel) {
|
||||
ind = rand () % (tunnels.size ()/2 + 1), i = 0;
|
||||
for (const auto& it: tunnels)
|
||||
{
|
||||
{
|
||||
if (it->IsEstablished () && it != excluded)
|
||||
{
|
||||
tunnel = it;
|
||||
|
@ -199,10 +199,10 @@ namespace tunnel
|
|||
std::shared_ptr<OutboundTunnel> TunnelPool::GetNewOutboundTunnel (std::shared_ptr<OutboundTunnel> old) const
|
||||
{
|
||||
if (old && old->IsEstablished ()) return old;
|
||||
std::shared_ptr<OutboundTunnel> tunnel;
|
||||
std::shared_ptr<OutboundTunnel> tunnel;
|
||||
if (old)
|
||||
{
|
||||
std::unique_lock<std::mutex> l(m_OutboundTunnelsMutex);
|
||||
std::unique_lock<std::mutex> l(m_OutboundTunnelsMutex);
|
||||
for (const auto& it: m_OutboundTunnels)
|
||||
if (it->IsEstablished () && old->GetEndpointIdentHash () == it->GetEndpointIdentHash ())
|
||||
{
|
||||
|
@ -210,9 +210,9 @@ namespace tunnel
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!tunnel)
|
||||
tunnel = GetNextOutboundTunnel ();
|
||||
tunnel = GetNextOutboundTunnel ();
|
||||
return tunnel;
|
||||
}
|
||||
|
||||
|
@ -220,12 +220,12 @@ namespace tunnel
|
|||
{
|
||||
int num = 0;
|
||||
{
|
||||
std::unique_lock<std::mutex> l(m_OutboundTunnelsMutex);
|
||||
std::unique_lock<std::mutex> l(m_OutboundTunnelsMutex);
|
||||
for (const auto& it : m_OutboundTunnels)
|
||||
if (it->IsEstablished ()) num++;
|
||||
}
|
||||
for (int i = num; i < m_NumOutboundTunnels; i++)
|
||||
CreateOutboundTunnel ();
|
||||
CreateOutboundTunnel ();
|
||||
|
||||
num = 0;
|
||||
{
|
||||
|
@ -253,20 +253,20 @@ namespace tunnel
|
|||
LogPrint (eLogWarning, "Tunnels: test of tunnel ", it.first, " failed");
|
||||
// if test failed again with another tunnel we consider it failed
|
||||
if (it.second.first)
|
||||
{
|
||||
{
|
||||
if (it.second.first->GetState () == eTunnelStateTestFailed)
|
||||
{
|
||||
{
|
||||
it.second.first->SetState (eTunnelStateFailed);
|
||||
std::unique_lock<std::mutex> l(m_OutboundTunnelsMutex);
|
||||
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);
|
||||
{
|
||||
std::unique_lock<std::mutex> l(m_InboundTunnelsMutex);
|
||||
|
@ -274,25 +274,25 @@ namespace tunnel
|
|||
}
|
||||
if (m_LocalDestination)
|
||||
m_LocalDestination->SetLeaseSetUpdated ();
|
||||
}
|
||||
}
|
||||
else
|
||||
it.second.second->SetState (eTunnelStateTestFailed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// new tests
|
||||
|
||||
// new tests
|
||||
auto it1 = m_OutboundTunnels.begin ();
|
||||
auto it2 = m_InboundTunnels.begin ();
|
||||
while (it1 != m_OutboundTunnels.end () && it2 != m_InboundTunnels.end ())
|
||||
{
|
||||
bool failed = false;
|
||||
if ((*it1)->IsFailed ())
|
||||
{
|
||||
{
|
||||
failed = true;
|
||||
++it1;
|
||||
}
|
||||
if ((*it2)->IsFailed ())
|
||||
{
|
||||
{
|
||||
failed = true;
|
||||
++it2;
|
||||
}
|
||||
|
@ -307,7 +307,7 @@ namespace tunnel
|
|||
(*it1)->SendTunnelDataMsg ((*it2)->GetNextIdentHash (), (*it2)->GetNextTunnelID (),
|
||||
CreateDeliveryStatusMsg (msgID));
|
||||
++it1; ++it2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -317,24 +317,24 @@ namespace tunnel
|
|||
m_LocalDestination->ProcessGarlicMessage (msg);
|
||||
else
|
||||
LogPrint (eLogWarning, "Tunnels: local destination doesn't exist, dropped");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void TunnelPool::ProcessDeliveryStatus (std::shared_ptr<I2NPMessage> msg)
|
||||
{
|
||||
const uint8_t * buf = msg->GetPayload ();
|
||||
uint32_t msgID = bufbe32toh (buf);
|
||||
buf += 4;
|
||||
buf += 4;
|
||||
uint64_t timestamp = bufbe64toh (buf);
|
||||
|
||||
decltype(m_Tests)::mapped_type test;
|
||||
bool found = false;
|
||||
bool found = false;
|
||||
{
|
||||
std::unique_lock<std::mutex> l(m_TestsMutex);
|
||||
auto it = m_Tests.find (msgID);
|
||||
if (it != m_Tests.end ())
|
||||
{
|
||||
found = true;
|
||||
test = it->second;
|
||||
test = it->second;
|
||||
m_Tests.erase (it);
|
||||
}
|
||||
}
|
||||
|
@ -358,35 +358,23 @@ namespace tunnel
|
|||
m_LocalDestination->ProcessDeliveryStatusMessage (msg);
|
||||
else
|
||||
LogPrint (eLogWarning, "Tunnels: Local destination doesn't exist, dropped");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<const i2p::data::RouterInfo> TunnelPool::SelectNextHop (std::shared_ptr<const i2p::data::RouterInfo> prevHop) const
|
||||
{
|
||||
bool isExploratory = (i2p::tunnel::tunnels.GetExploratoryPool () == shared_from_this ());
|
||||
auto hop = isExploratory ? i2p::data::netdb.GetRandomRouter (prevHop):
|
||||
auto hop = isExploratory ? i2p::data::netdb.GetRandomRouter (prevHop):
|
||||
i2p::data::netdb.GetHighBandwidthRandomRouter (prevHop);
|
||||
|
||||
if (!hop || hop->GetProfile ()->IsBad ())
|
||||
hop = i2p::data::netdb.GetRandomRouter (prevHop);
|
||||
return hop;
|
||||
}
|
||||
return hop;
|
||||
}
|
||||
|
||||
bool TunnelPool::SelectPeers (std::vector<std::shared_ptr<const i2p::data::IdentityEx> >& peers, bool isInbound)
|
||||
bool StandardSelectPeers(Path & peers, int numHops, bool inbound, SelectHopFunc nextHop)
|
||||
{
|
||||
int numHops = isInbound ? m_NumInboundHops : m_NumOutboundHops;
|
||||
// peers is empty
|
||||
if (numHops <= 0) return true;
|
||||
// custom peer selector in use ?
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_CustomPeerSelectorMutex);
|
||||
if (m_CustomPeerSelector)
|
||||
return m_CustomPeerSelector->SelectPeers(peers, numHops, isInbound);
|
||||
}
|
||||
// explicit peers in use
|
||||
if (m_ExplicitPeers) return SelectExplicitPeers (peers, isInbound);
|
||||
|
||||
auto prevHop = i2p::context.GetSharedRouterInfo ();
|
||||
auto prevHop = i2p::context.GetSharedRouterInfo ();
|
||||
if(i2p::transport::transports.RoutesRestricted())
|
||||
{
|
||||
/** if routes are restricted prepend trusted first hop */
|
||||
|
@ -405,30 +393,46 @@ namespace tunnel
|
|||
numHops--;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for(int i = 0; i < numHops; i++ )
|
||||
{
|
||||
auto hop = SelectNextHop (prevHop);
|
||||
auto hop = nextHop (prevHop);
|
||||
if (!hop)
|
||||
{
|
||||
LogPrint (eLogError, "Tunnels: Can't select next hop for ", prevHop->GetIdentHashBase64 ());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
prevHop = hop;
|
||||
peers.push_back (hop->GetRouterIdentity ());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool TunnelPool::SelectPeers (std::vector<std::shared_ptr<const i2p::data::IdentityEx> >& peers, bool isInbound)
|
||||
{
|
||||
int numHops = isInbound ? m_NumInboundHops : m_NumOutboundHops;
|
||||
// peers is empty
|
||||
if (numHops <= 0) return true;
|
||||
// custom peer selector in use ?
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_CustomPeerSelectorMutex);
|
||||
if (m_CustomPeerSelector)
|
||||
return m_CustomPeerSelector->SelectPeers(peers, numHops, isInbound);
|
||||
}
|
||||
// explicit peers in use
|
||||
if (m_ExplicitPeers) return SelectExplicitPeers (peers, isInbound);
|
||||
return StandardSelectPeers(peers, numHops, isInbound, std::bind(&TunnelPool::SelectNextHop, this, std::placeholders::_1));
|
||||
}
|
||||
|
||||
bool TunnelPool::SelectExplicitPeers (std::vector<std::shared_ptr<const i2p::data::IdentityEx> >& peers, bool isInbound)
|
||||
{
|
||||
int size = m_ExplicitPeers->size ();
|
||||
std::vector<int> peerIndicies;
|
||||
for (int i = 0; i < size; i++) peerIndicies.push_back(i);
|
||||
std::random_shuffle (peerIndicies.begin(), peerIndicies.end());
|
||||
|
||||
int numHops = isInbound ? m_NumInboundHops : m_NumOutboundHops;
|
||||
for (int i = 0; i < numHops; i++)
|
||||
|
||||
int numHops = isInbound ? m_NumInboundHops : m_NumOutboundHops;
|
||||
for (int i = 0; i < numHops; i++)
|
||||
{
|
||||
auto& ident = (*m_ExplicitPeers)[peerIndicies[i]];
|
||||
auto r = i2p::data::netdb.FindRouter (ident);
|
||||
|
@ -443,7 +447,7 @@ namespace tunnel
|
|||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void TunnelPool::CreateInboundTunnel ()
|
||||
{
|
||||
auto outboundTunnel = GetNextOutboundTunnel ();
|
||||
|
@ -455,15 +459,15 @@ namespace tunnel
|
|||
{
|
||||
std::shared_ptr<TunnelConfig> config;
|
||||
if (m_NumInboundHops > 0)
|
||||
{
|
||||
std::reverse (peers.begin (), peers.end ());
|
||||
{
|
||||
std::reverse (peers.begin (), peers.end ());
|
||||
config = std::make_shared<TunnelConfig> (peers);
|
||||
}
|
||||
}
|
||||
auto tunnel = tunnels.CreateInboundTunnel (config, outboundTunnel);
|
||||
tunnel->SetTunnelPool (shared_from_this ());
|
||||
if (tunnel->IsEstablished ()) // zero hops
|
||||
TunnelCreated (tunnel);
|
||||
}
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "Tunnels: Can't create inbound tunnel, no peers available");
|
||||
}
|
||||
|
@ -480,41 +484,41 @@ namespace tunnel
|
|||
newTunnel->SetTunnelPool (shared_from_this());
|
||||
if (newTunnel->IsEstablished ()) // zero hops
|
||||
TunnelCreated (newTunnel);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void TunnelPool::CreateOutboundTunnel ()
|
||||
{
|
||||
auto inboundTunnel = GetNextInboundTunnel ();
|
||||
if (!inboundTunnel)
|
||||
inboundTunnel = tunnels.GetNextInboundTunnel ();
|
||||
if (inboundTunnel)
|
||||
{
|
||||
{
|
||||
LogPrint (eLogDebug, "Tunnels: Creating destination outbound tunnel...");
|
||||
std::vector<std::shared_ptr<const i2p::data::IdentityEx> > peers;
|
||||
if (SelectPeers (peers, false))
|
||||
{
|
||||
{
|
||||
std::shared_ptr<TunnelConfig> config;
|
||||
if (m_NumOutboundHops > 0)
|
||||
if (m_NumOutboundHops > 0)
|
||||
config = std::make_shared<TunnelConfig>(peers, inboundTunnel->GetNextTunnelID (), inboundTunnel->GetNextIdentHash ());
|
||||
auto tunnel = tunnels.CreateOutboundTunnel (config);
|
||||
tunnel->SetTunnelPool (shared_from_this ());
|
||||
if (tunnel->IsEstablished ()) // zero hops
|
||||
TunnelCreated (tunnel);
|
||||
}
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "Tunnels: Can't create outbound tunnel, no peers available");
|
||||
}
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "Tunnels: Can't create outbound tunnel, no inbound tunnels found");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void TunnelPool::RecreateOutboundTunnel (std::shared_ptr<OutboundTunnel> tunnel)
|
||||
{
|
||||
auto inboundTunnel = GetNextInboundTunnel ();
|
||||
if (!inboundTunnel)
|
||||
inboundTunnel = tunnels.GetNextInboundTunnel ();
|
||||
if (inboundTunnel)
|
||||
{
|
||||
{
|
||||
LogPrint (eLogDebug, "Tunnels: Re-creating destination outbound tunnel...");
|
||||
std::shared_ptr<TunnelConfig> config;
|
||||
if (m_NumOutboundHops > 0)
|
||||
|
@ -523,10 +527,10 @@ namespace tunnel
|
|||
newTunnel->SetTunnelPool (shared_from_this ());
|
||||
if (newTunnel->IsEstablished ()) // zero hops
|
||||
TunnelCreated (newTunnel);
|
||||
}
|
||||
}
|
||||
else
|
||||
LogPrint (eLogDebug, "Tunnels: Can't re-create outbound tunnel, no inbound tunnels found");
|
||||
}
|
||||
}
|
||||
|
||||
void TunnelPool::CreatePairedInboundTunnel (std::shared_ptr<OutboundTunnel> outboundTunnel)
|
||||
{
|
||||
|
@ -535,7 +539,7 @@ namespace tunnel
|
|||
tunnel->SetTunnelPool (shared_from_this ());
|
||||
}
|
||||
|
||||
void TunnelPool::SetCustomPeerSelector(TunnelPeerSelector selector)
|
||||
void TunnelPool::SetCustomPeerSelector(ITunnelPeerSelector * selector)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_CustomPeerSelectorMutex);
|
||||
m_CustomPeerSelector = selector;
|
||||
|
@ -567,7 +571,7 @@ namespace tunnel
|
|||
}
|
||||
return tun;
|
||||
}
|
||||
|
||||
|
||||
std::shared_ptr<OutboundTunnel> TunnelPool::GetLowestLatencyOutboundTunnel(std::shared_ptr<OutboundTunnel> exclude) const
|
||||
{
|
||||
std::shared_ptr<OutboundTunnel> tun = nullptr;
|
||||
|
|
45
TunnelPool.h
45
TunnelPool.h
|
@ -30,25 +30,29 @@ namespace tunnel
|
|||
eBuildResultTimeout // tunnel build timed out
|
||||
};
|
||||
|
||||
typedef std::shared_ptr<const i2p::data::IdentityEx> Peer;
|
||||
typedef std::vector<Peer> Path;
|
||||
|
||||
/** interface for custom tunnel peer selection algorithm */
|
||||
struct ITunnelPeerSelector
|
||||
{
|
||||
typedef std::shared_ptr<const i2p::data::IdentityEx> Peer;
|
||||
typedef std::vector<Peer> TunnelPath;
|
||||
|
||||
virtual bool SelectPeers(TunnelPath & peers, int hops, bool isInbound) = 0;
|
||||
virtual bool OnBuildResult(TunnelPath & peers, bool isInbound, TunnelBuildResult result) = 0;
|
||||
virtual ~ITunnelPeerSelector() {};
|
||||
virtual bool SelectPeers(Path & peers, int hops, bool isInbound) = 0;
|
||||
virtual bool OnBuildResult(const Path & peers, bool isInbound, TunnelBuildResult result) = 0;
|
||||
};
|
||||
|
||||
typedef std::shared_ptr<ITunnelPeerSelector> TunnelPeerSelector;
|
||||
|
||||
|
||||
typedef std::function<std::shared_ptr<const i2p::data::RouterInfo>(std::shared_ptr<const i2p::data::RouterInfo>)> SelectHopFunc;
|
||||
// standard peer selection algorithm
|
||||
bool StandardSelectPeers(Path & path, int hops, bool inbound, SelectHopFunc nextHop);
|
||||
|
||||
class TunnelPool: public std::enable_shared_from_this<TunnelPool> // per local destination
|
||||
{
|
||||
public:
|
||||
|
||||
TunnelPool (int numInboundHops, int numOutboundHops, int numInboundTunnels, int numOutboundTunnels);
|
||||
~TunnelPool ();
|
||||
|
||||
|
||||
std::shared_ptr<i2p::garlic::GarlicDestination> GetLocalDestination () const { return m_LocalDestination; };
|
||||
void SetLocalDestination (std::shared_ptr<i2p::garlic::GarlicDestination> destination) { m_LocalDestination = destination; };
|
||||
void SetExplicitPeers (std::shared_ptr<std::vector<i2p::data::IdentHash> > explicitPeers);
|
||||
|
@ -62,7 +66,7 @@ namespace tunnel
|
|||
void RecreateOutboundTunnel (std::shared_ptr<OutboundTunnel> tunnel);
|
||||
std::vector<std::shared_ptr<InboundTunnel> > GetInboundTunnels (int num) const;
|
||||
std::shared_ptr<OutboundTunnel> GetNextOutboundTunnel (std::shared_ptr<OutboundTunnel> excluded = nullptr) const;
|
||||
std::shared_ptr<InboundTunnel> GetNextInboundTunnel (std::shared_ptr<InboundTunnel> excluded = nullptr) const;
|
||||
std::shared_ptr<InboundTunnel> GetNextInboundTunnel (std::shared_ptr<InboundTunnel> excluded = nullptr) const;
|
||||
std::shared_ptr<OutboundTunnel> GetNewOutboundTunnel (std::shared_ptr<OutboundTunnel> old) const;
|
||||
void TestTunnels ();
|
||||
void ProcessGarlicMessage (std::shared_ptr<I2NPMessage> msg);
|
||||
|
@ -75,7 +79,7 @@ namespace tunnel
|
|||
int GetNumInboundTunnels () const { return m_NumInboundTunnels; };
|
||||
int GetNumOutboundTunnels () const { return m_NumOutboundTunnels; };
|
||||
|
||||
void SetCustomPeerSelector(TunnelPeerSelector selector);
|
||||
void SetCustomPeerSelector(ITunnelPeerSelector * selector);
|
||||
void UnsetCustomPeerSelector();
|
||||
bool HasCustomPeerSelector();
|
||||
|
||||
|
@ -90,23 +94,25 @@ namespace tunnel
|
|||
std::shared_ptr<OutboundTunnel> GetLowestLatencyOutboundTunnel(std::shared_ptr<OutboundTunnel> exclude=nullptr) const;
|
||||
|
||||
void OnTunnelBuildResult(std::shared_ptr<Tunnel> tunnel, TunnelBuildResult result);
|
||||
|
||||
|
||||
// for overriding tunnel peer selection
|
||||
std::shared_ptr<const i2p::data::RouterInfo> SelectNextHop (std::shared_ptr<const i2p::data::RouterInfo> prevHop) const;
|
||||
|
||||
private:
|
||||
|
||||
void CreateInboundTunnel ();
|
||||
|
||||
void CreateInboundTunnel ();
|
||||
void CreateOutboundTunnel ();
|
||||
void CreatePairedInboundTunnel (std::shared_ptr<OutboundTunnel> outboundTunnel);
|
||||
template<class TTunnels>
|
||||
typename TTunnels::value_type GetNextTunnel (TTunnels& tunnels, typename TTunnels::value_type excluded) const;
|
||||
std::shared_ptr<const i2p::data::RouterInfo> SelectNextHop (std::shared_ptr<const i2p::data::RouterInfo> prevHop) const;
|
||||
bool SelectPeers (std::vector<std::shared_ptr<const i2p::data::IdentityEx> >& hops, bool isInbound);
|
||||
bool SelectExplicitPeers (std::vector<std::shared_ptr<const i2p::data::IdentityEx> >& hops, bool isInbound);
|
||||
bool SelectExplicitPeers (std::vector<std::shared_ptr<const i2p::data::IdentityEx> >& hops, bool isInbound);
|
||||
|
||||
private:
|
||||
|
||||
std::shared_ptr<i2p::garlic::GarlicDestination> m_LocalDestination;
|
||||
int m_NumInboundHops, m_NumOutboundHops, m_NumInboundTunnels, m_NumOutboundTunnels;
|
||||
std::shared_ptr<std::vector<i2p::data::IdentHash> > m_ExplicitPeers;
|
||||
std::shared_ptr<std::vector<i2p::data::IdentHash> > m_ExplicitPeers;
|
||||
mutable std::mutex m_InboundTunnelsMutex;
|
||||
std::set<std::shared_ptr<InboundTunnel>, TunnelCreationTimeCmp> m_InboundTunnels; // recent tunnel appears first
|
||||
mutable std::mutex m_OutboundTunnelsMutex;
|
||||
|
@ -115,20 +121,19 @@ namespace tunnel
|
|||
std::map<uint32_t, std::pair<std::shared_ptr<OutboundTunnel>, std::shared_ptr<InboundTunnel> > > m_Tests;
|
||||
bool m_IsActive;
|
||||
std::mutex m_CustomPeerSelectorMutex;
|
||||
TunnelPeerSelector m_CustomPeerSelector;
|
||||
ITunnelPeerSelector * m_CustomPeerSelector;
|
||||
|
||||
uint64_t m_MinLatency=0; // if > 0 this tunnel pool will try building tunnels with minimum latency by ms
|
||||
uint64_t m_MaxLatency=0; // if > 0 this tunnel pool will try building tunnels with maximum latency by ms
|
||||
|
||||
|
||||
public:
|
||||
|
||||
// for HTTP only
|
||||
const decltype(m_OutboundTunnels)& GetOutboundTunnels () const { return m_OutboundTunnels; };
|
||||
const decltype(m_InboundTunnels)& GetInboundTunnels () const { return m_InboundTunnels; };
|
||||
|
||||
};
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -61,7 +61,8 @@ LOCAL_SRC_FILES := DaemonAndroid.cpp i2pd_android.cpp \
|
|||
../../Event.cpp \
|
||||
../../Gost.cpp \
|
||||
../../WebSocks.cpp \
|
||||
../../BloomFilter.cpp \
|
||||
../../BloomFilter.cpp \
|
||||
../../MatchedDestination.cpp \
|
||||
../../util.cpp \
|
||||
../../i2pd.cpp ../../UPnP.cpp
|
||||
|
||||
|
|
|
@ -37,7 +37,7 @@ set (LIBI2PD_SRC
|
|||
"${CMAKE_SOURCE_DIR}/FS.cpp"
|
||||
"${CMAKE_SOURCE_DIR}/Log.cpp"
|
||||
"${CMAKE_SOURCE_DIR}/NTCPSession.cpp"
|
||||
"${CMAKE_SOURCE_DIR}/NetDbRequests.cpp"
|
||||
"${CMAKE_SOURCE_DIR}/NetDbRequests.cpp"
|
||||
"${CMAKE_SOURCE_DIR}/NetDb.cpp"
|
||||
"${CMAKE_SOURCE_DIR}/Profiling.cpp"
|
||||
"${CMAKE_SOURCE_DIR}/Reseed.cpp"
|
||||
|
@ -47,7 +47,7 @@ set (LIBI2PD_SRC
|
|||
"${CMAKE_SOURCE_DIR}/SSUData.cpp"
|
||||
"${CMAKE_SOURCE_DIR}/SSUSession.cpp"
|
||||
"${CMAKE_SOURCE_DIR}/Streaming.cpp"
|
||||
"${CMAKE_SOURCE_DIR}/Destination.cpp"
|
||||
"${CMAKE_SOURCE_DIR}/Destination.cpp"
|
||||
"${CMAKE_SOURCE_DIR}/TransitTunnel.cpp"
|
||||
"${CMAKE_SOURCE_DIR}/Tunnel.cpp"
|
||||
"${CMAKE_SOURCE_DIR}/TunnelGateway.cpp"
|
||||
|
@ -59,16 +59,16 @@ set (LIBI2PD_SRC
|
|||
"${CMAKE_SOURCE_DIR}/Datagram.cpp"
|
||||
"${CMAKE_SOURCE_DIR}/Family.cpp"
|
||||
"${CMAKE_SOURCE_DIR}/Signature.cpp"
|
||||
"${CMAKE_SOURCE_DIR}/Timestamp.cpp"
|
||||
"${CMAKE_SOURCE_DIR}/Timestamp.cpp"
|
||||
"${CMAKE_SOURCE_DIR}/api.cpp"
|
||||
"${CMAKE_SOURCE_DIR}/Event.cpp"
|
||||
"${CMAKE_SOURCE_DIR}/Gost.cpp"
|
||||
"${CMAKE_SOURCE_DIR}/Gost.cpp"
|
||||
)
|
||||
|
||||
if (WITH_WEBSOCKETS)
|
||||
add_definitions(-DWITH_EVENTS)
|
||||
find_package(websocketpp REQUIRED)
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
if (CMAKE_SYSTEM_NAME STREQUAL "Windows" OR MSYS)
|
||||
list (APPEND LIBI2PD_SRC "${CMAKE_SOURCE_DIR}/I2PEndian.cpp")
|
||||
|
@ -90,8 +90,9 @@ install(TARGETS libi2pd
|
|||
|
||||
set (CLIENT_SRC
|
||||
"${CMAKE_SOURCE_DIR}/AddressBook.cpp"
|
||||
"${CMAKE_SOURCE_DIR}/BOB.cpp"
|
||||
"${CMAKE_SOURCE_DIR}/BOB.cpp"
|
||||
"${CMAKE_SOURCE_DIR}/ClientContext.cpp"
|
||||
"${CMAKE_SOURCE_DIR}/MatchedDestination.cpp"
|
||||
"${CMAKE_SOURCE_DIR}/I2PTunnel.cpp"
|
||||
"${CMAKE_SOURCE_DIR}/I2PService.cpp"
|
||||
"${CMAKE_SOURCE_DIR}/SAM.cpp"
|
||||
|
@ -357,7 +358,7 @@ include_directories( SYSTEM ${Boost_INCLUDE_DIRS} ${OPENSSL_INCLUDE_DIR} ${ZLIB_
|
|||
# warn if for meshnet
|
||||
if (WITH_MESHNET)
|
||||
message(STATUS "Building for testnet")
|
||||
message(WARNING "This build will NOT work on mainline i2p")
|
||||
message(WARNING "This build will NOT work on mainline i2p")
|
||||
endif()
|
||||
|
||||
|
||||
|
|
|
@ -64,7 +64,7 @@ ipv6 = false
|
|||
# nat = true
|
||||
|
||||
## Bandwidth configuration
|
||||
## L limit bandwidth to 32Kbs/sec, O - to 256Kbs/sec, P - to 2048Kbs/sec,
|
||||
## L limit bandwidth to 32KBs/sec, O - to 256KBs/sec, P - to 2048KBs/sec,
|
||||
## X - unlimited
|
||||
## Default is X for floodfill, L for regular node
|
||||
# bandwidth = L
|
||||
|
|
|
@ -8,10 +8,9 @@ LIB_SRC = \
|
|||
Config.cpp HTTP.cpp Timestamp.cpp util.cpp api.cpp Event.cpp Gost.cpp
|
||||
|
||||
LIB_CLIENT_SRC = \
|
||||
AddressBook.cpp BOB.cpp ClientContext.cpp I2PTunnel.cpp I2PService.cpp \
|
||||
AddressBook.cpp BOB.cpp ClientContext.cpp I2PTunnel.cpp I2PService.cpp MatchedDestination.cpp \
|
||||
SAM.cpp SOCKS.cpp HTTPProxy.cpp I2CP.cpp WebSocks.cpp
|
||||
|
||||
# also: Daemon{Linux,Win32}.cpp will be added later
|
||||
DAEMON_SRC = \
|
||||
HTTPServer.cpp I2PControl.cpp UPnP.cpp Daemon.cpp i2pd.cpp
|
||||
|
||||
|
|
|
@ -36,7 +36,8 @@ SOURCES += DaemonQT.cpp mainwindow.cpp \
|
|||
../../SSUData.cpp ../../SSUSession.cpp ../../Streaming.cpp ../../TransitTunnel.cpp \
|
||||
../../Transports.cpp ../../Tunnel.cpp ../../TunnelEndpoint.cpp ../../TunnelGateway.cpp \
|
||||
../../TunnelPool.cpp ../../UPnP.cpp ../../Gzip.cpp ../../Timestamp.cpp ../../util.cpp \
|
||||
../../Event.cpp ../../BloomFiler.cpp ../../Gost.cpp ../../i2pd.cpp
|
||||
../../Event.cpp ../../BloomFiler.cpp ../../Gost.cpp ../../MatchedDestination.cpp \
|
||||
../../i2pd.cpp
|
||||
|
||||
HEADERS += DaemonQT.h mainwindow.h \
|
||||
../../HTTPServer.h ../../I2PControl.h ../../UPnP.h ../../Daemon.h ../../Config.h \
|
||||
|
@ -51,7 +52,7 @@ HEADERS += DaemonQT.h mainwindow.h \
|
|||
../../TransportSession.h ../../Tunnel.h ../../TunnelBase.h ../../TunnelConfig.h \
|
||||
../../TunnelEndpoint.h ../../TunnelGateway.h ../../TunnelPool.h ../../UPnP.h \
|
||||
../../util.h ../../version.h ../../Gzip.h ../../Tag.h \
|
||||
../../BloomFiler.h ../../Event.h ../../Gost.h
|
||||
../../BloomFiler.h ../../Event.h ../../Gost.h ../../MatchedDestination.h
|
||||
|
||||
FORMS += mainwindow.ui
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue