Browse Source

ntcp socks proxy (initial)

pull/881/head
Jeff Becker 8 years ago
parent
commit
3ea1eca350
  1. 41
      daemon/Daemon.cpp
  2. 87
      libi2pd/Config.cpp
  3. 714
      libi2pd/NTCPSession.cpp
  4. 78
      libi2pd/NTCPSession.h
  5. 308
      libi2pd/Transports.cpp
  6. 44
      libi2pd/Transports.h

41
daemon/Daemon.cpp

@ -140,7 +140,7 @@ namespace i2p
} }
i2p::context.SetSupportsV6 (ipv6); i2p::context.SetSupportsV6 (ipv6);
i2p::context.SetSupportsV4 (ipv4); i2p::context.SetSupportsV4 (ipv4);
bool transit; i2p::config::GetOption("notransit", transit); bool transit; i2p::config::GetOption("notransit", transit);
i2p::context.SetAcceptsTunnels (!transit); i2p::context.SetAcceptsTunnels (!transit);
uint16_t transitTunnels; i2p::config::GetOption("limits.transittunnels", transitTunnels); uint16_t transitTunnels; i2p::config::GetOption("limits.transittunnels", transitTunnels);
@ -157,17 +157,17 @@ namespace i2p
/* this section also honors 'floodfill' flag, if set above */ /* this section also honors 'floodfill' flag, if set above */
std::string bandwidth; i2p::config::GetOption("bandwidth", bandwidth); std::string bandwidth; i2p::config::GetOption("bandwidth", bandwidth);
if (bandwidth.length () > 0) if (bandwidth.length () > 0)
{ {
if (bandwidth[0] >= 'K' && bandwidth[0] <= 'X') if (bandwidth[0] >= 'K' && bandwidth[0] <= 'X')
{ {
i2p::context.SetBandwidth (bandwidth[0]); i2p::context.SetBandwidth (bandwidth[0]);
LogPrint(eLogInfo, "Daemon: bandwidth set to ", i2p::context.GetBandwidthLimit (), "KBps"); LogPrint(eLogInfo, "Daemon: bandwidth set to ", i2p::context.GetBandwidthLimit (), "KBps");
} }
else else
{ {
auto value = std::atoi(bandwidth.c_str()); auto value = std::atoi(bandwidth.c_str());
if (value > 0) if (value > 0)
{ {
i2p::context.SetBandwidth (value); i2p::context.SetBandwidth (value);
LogPrint(eLogInfo, "Daemon: bandwidth set to ", i2p::context.GetBandwidthLimit (), " KBps"); LogPrint(eLogInfo, "Daemon: bandwidth set to ", i2p::context.GetBandwidthLimit (), " KBps");
} }
@ -175,19 +175,19 @@ namespace i2p
{ {
LogPrint(eLogInfo, "Daemon: unexpected bandwidth ", bandwidth, ". Set to 'low'"); LogPrint(eLogInfo, "Daemon: unexpected bandwidth ", bandwidth, ". Set to 'low'");
i2p::context.SetBandwidth (i2p::data::CAPS_FLAG_LOW_BANDWIDTH2); i2p::context.SetBandwidth (i2p::data::CAPS_FLAG_LOW_BANDWIDTH2);
} }
} }
} }
else if (isFloodfill) else if (isFloodfill)
{ {
LogPrint(eLogInfo, "Daemon: floodfill bandwidth set to 'extra'"); LogPrint(eLogInfo, "Daemon: floodfill bandwidth set to 'extra'");
i2p::context.SetBandwidth (i2p::data::CAPS_FLAG_EXTRA_BANDWIDTH1); i2p::context.SetBandwidth (i2p::data::CAPS_FLAG_EXTRA_BANDWIDTH1);
} }
else else
{ {
LogPrint(eLogInfo, "Daemon: bandwidth set to 'low'"); LogPrint(eLogInfo, "Daemon: bandwidth set to 'low'");
i2p::context.SetBandwidth (i2p::data::CAPS_FLAG_LOW_BANDWIDTH2); i2p::context.SetBandwidth (i2p::data::CAPS_FLAG_LOW_BANDWIDTH2);
} }
int shareRatio; i2p::config::GetOption("share", shareRatio); int shareRatio; i2p::config::GetOption("share", shareRatio);
i2p::context.SetShareRatio (shareRatio); i2p::context.SetShareRatio (shareRatio);
@ -195,7 +195,7 @@ namespace i2p
std::string family; i2p::config::GetOption("family", family); std::string family; i2p::config::GetOption("family", family);
i2p::context.SetFamily (family); i2p::context.SetFamily (family);
if (family.length () > 0) if (family.length () > 0)
LogPrint(eLogInfo, "Daemon: family set to ", family); LogPrint(eLogInfo, "Daemon: family set to ", family);
bool trust; i2p::config::GetOption("trust.enabled", trust); bool trust; i2p::config::GetOption("trust.enabled", trust);
if (trust) if (trust)
@ -214,7 +214,7 @@ namespace i2p
fams.insert (fam.substr (pos, comma != std::string::npos ? comma - pos : std::string::npos)); fams.insert (fam.substr (pos, comma != std::string::npos ? comma - pos : std::string::npos));
pos = comma + 1; pos = comma + 1;
} }
while (comma != std::string::npos); while (comma != std::string::npos);
i2p::transport::transports.RestrictRoutesToFamilies(fams); i2p::transport::transports.RestrictRoutesToFamilies(fams);
restricted = fams.size() > 0; restricted = fams.size() > 0;
} }
@ -225,11 +225,11 @@ namespace i2p
{ {
comma = routers.find (',', pos); comma = routers.find (',', pos);
i2p::data::IdentHash ident; i2p::data::IdentHash ident;
ident.FromBase64 (routers.substr (pos, comma != std::string::npos ? comma - pos : std::string::npos)); ident.FromBase64 (routers.substr (pos, comma != std::string::npos ? comma - pos : std::string::npos));
idents.insert (ident); idents.insert (ident);
pos = comma + 1; pos = comma + 1;
} }
while (comma != std::string::npos); while (comma != std::string::npos);
LogPrint(eLogInfo, "Daemon: setting restricted routes to use ", idents.size(), " trusted routesrs"); LogPrint(eLogInfo, "Daemon: setting restricted routes to use ", idents.size(), " trusted routesrs");
i2p::transport::transports.RestrictRoutesToRouters(idents); i2p::transport::transports.RestrictRoutesToRouters(idents);
restricted = idents.size() > 0; restricted = idents.size() > 0;
@ -245,7 +245,7 @@ namespace i2p
} }
return true; return true;
} }
bool Daemon_Singleton::start() bool Daemon_Singleton::start()
{ {
i2p::log::Logger().Start(); i2p::log::Logger().Start();
@ -263,6 +263,7 @@ namespace i2p
LogPrint(eLogInfo, "Daemon: starting Transports"); LogPrint(eLogInfo, "Daemon: starting Transports");
if(!ssu) LogPrint(eLogInfo, "Daemon: ssu disabled"); if(!ssu) LogPrint(eLogInfo, "Daemon: ssu disabled");
if(!ntcp) LogPrint(eLogInfo, "Daemon: ntcp disabled"); if(!ntcp) LogPrint(eLogInfo, "Daemon: ntcp disabled");
i2p::transport::transports.Start(ntcp, ssu); i2p::transport::transports.Start(ntcp, ssu);
if (i2p::transport::transports.IsBoundNTCP() || i2p::transport::transports.IsBoundSSU()) { if (i2p::transport::transports.IsBoundNTCP() || i2p::transport::transports.IsBoundSSU()) {
LogPrint(eLogInfo, "Daemon: Transports started"); LogPrint(eLogInfo, "Daemon: Transports started");
@ -273,7 +274,7 @@ namespace i2p
i2p::data::netdb.Stop(); i2p::data::netdb.Stop();
return false; return false;
} }
bool http; i2p::config::GetOption("http.enabled", http); bool http; i2p::config::GetOption("http.enabled", http);
if (http) { if (http) {
std::string httpAddr; i2p::config::GetOption("http.address", httpAddr); std::string httpAddr; i2p::config::GetOption("http.address", httpAddr);
@ -283,7 +284,7 @@ namespace i2p
d.httpServer->Start(); d.httpServer->Start();
} }
LogPrint(eLogInfo, "Daemon: starting Tunnels"); LogPrint(eLogInfo, "Daemon: starting Tunnels");
i2p::tunnel::tunnels.Start(); i2p::tunnel::tunnels.Start();

87
libi2pd/Config.cpp

@ -48,7 +48,7 @@ namespace config {
("port", value<uint16_t>()->default_value(0), "Port to listen for incoming connections (default: auto)") ("port", value<uint16_t>()->default_value(0), "Port to listen for incoming connections (default: auto)")
("ipv4", value<bool>()->zero_tokens()->default_value(true), "Enable communication through ipv4") ("ipv4", value<bool>()->zero_tokens()->default_value(true), "Enable communication through ipv4")
("ipv6", value<bool>()->zero_tokens()->default_value(false), "Enable communication through ipv6") ("ipv6", value<bool>()->zero_tokens()->default_value(false), "Enable communication through ipv6")
("netid", value<int>()->default_value(I2PD_NET_ID), "Specify NetID. Main I2P is 2") ("netid", value<int>()->default_value(I2PD_NET_ID), "Specify NetID. Main I2P is 2")
("daemon", value<bool>()->zero_tokens()->default_value(false), "Router will go to background after start") ("daemon", value<bool>()->zero_tokens()->default_value(false), "Router will go to background after start")
("service", value<bool>()->zero_tokens()->default_value(false), "Router will use system folders like '/var/lib/i2pd'") ("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") ("notransit", value<bool>()->zero_tokens()->default_value(false), "Router will not accept transit tunnels at startup")
@ -57,13 +57,14 @@ namespace config {
("share", value<int>()->default_value(100), "Limit of transit traffic from max bandwidth in percents. (default: 100") ("share", value<int>()->default_value(100), "Limit of transit traffic from max bandwidth in percents. (default: 100")
("ntcp", value<bool>()->zero_tokens()->default_value(true), "Enable NTCP transport") ("ntcp", value<bool>()->zero_tokens()->default_value(true), "Enable NTCP transport")
("ssu", value<bool>()->zero_tokens()->default_value(true), "Enable SSU transport") ("ssu", value<bool>()->zero_tokens()->default_value(true), "Enable SSU transport")
("ntcpproxy", value<std::string>()->default_value(""), "proxy url for ntcp transport")
#ifdef _WIN32 #ifdef _WIN32
("svcctl", value<std::string>()->default_value(""), "Windows service management ('install' or 'remove')") ("svcctl", value<std::string>()->default_value(""), "Windows service management ('install' or 'remove')")
("insomnia", value<bool>()->zero_tokens()->default_value(false), "Prevent system from sleeping") ("insomnia", value<bool>()->zero_tokens()->default_value(false), "Prevent system from sleeping")
("close", value<std::string>()->default_value("ask"), "Action on close: minimize, exit, ask") // TODO: add custom validator or something ("close", value<std::string>()->default_value("ask"), "Action on close: minimize, exit, ask") // TODO: add custom validator or something
#endif #endif
; ;
options_description limits("Limits options"); options_description limits("Limits options");
limits.add_options() limits.add_options()
("limits.coresize", value<uint32_t>()->default_value(0), "Maximum size of corefile in Kb (0 - use system limit)") ("limits.coresize", value<uint32_t>()->default_value(0), "Maximum size of corefile in Kb (0 - use system limit)")
@ -87,12 +88,12 @@ namespace config {
("httpproxy.address", value<std::string>()->default_value("127.0.0.1"), "HTTP Proxy listen address") ("httpproxy.address", value<std::string>()->default_value("127.0.0.1"), "HTTP Proxy listen address")
("httpproxy.port", value<uint16_t>()->default_value(4444), "HTTP Proxy listen port") ("httpproxy.port", value<uint16_t>()->default_value(4444), "HTTP Proxy listen port")
("httpproxy.keys", value<std::string>()->default_value(""), "File to persist HTTP Proxy keys") ("httpproxy.keys", value<std::string>()->default_value(""), "File to persist HTTP Proxy keys")
("httpproxy.signaturetype", value<i2p::data::SigningKeyType>()->default_value(i2p::data::SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519), "Signature type for new keys. 7 (EdDSA) by default") ("httpproxy.signaturetype", value<i2p::data::SigningKeyType>()->default_value(i2p::data::SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519), "Signature type for new keys. 7 (EdDSA) by default")
("httpproxy.inbound.length", value<std::string>()->default_value("3"), "HTTP proxy inbound tunnel length") ("httpproxy.inbound.length", value<std::string>()->default_value("3"), "HTTP proxy inbound tunnel length")
("httpproxy.outbound.length", value<std::string>()->default_value("3"), "HTTP proxy outbound tunnel length") ("httpproxy.outbound.length", value<std::string>()->default_value("3"), "HTTP proxy outbound tunnel length")
("httpproxy.inbound.quantity", value<std::string>()->default_value("5"), "HTTP proxy inbound tunnels quantity") ("httpproxy.inbound.quantity", value<std::string>()->default_value("5"), "HTTP proxy inbound tunnels quantity")
("httpproxy.outbound.quantity", value<std::string>()->default_value("5"), "HTTP proxy outbound tunnels quantity") ("httpproxy.outbound.quantity", value<std::string>()->default_value("5"), "HTTP proxy outbound tunnels quantity")
("httpproxy.latency.min", value<std::string>()->default_value("0"), "HTTP proxy min latency for tunnels") ("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.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.outproxy", value<std::string>()->default_value(""), "HTTP proxy upstream out proxy url")
("httpproxy.addresshelper", value<bool>()->default_value(true), "Enable or disable addresshelper") ("httpproxy.addresshelper", value<bool>()->default_value(true), "Enable or disable addresshelper")
@ -104,13 +105,13 @@ namespace config {
("socksproxy.address", value<std::string>()->default_value("127.0.0.1"), "SOCKS Proxy listen address") ("socksproxy.address", value<std::string>()->default_value("127.0.0.1"), "SOCKS Proxy listen address")
("socksproxy.port", value<uint16_t>()->default_value(4447), "SOCKS Proxy listen port") ("socksproxy.port", value<uint16_t>()->default_value(4447), "SOCKS Proxy listen port")
("socksproxy.keys", value<std::string>()->default_value(""), "File to persist SOCKS Proxy keys") ("socksproxy.keys", value<std::string>()->default_value(""), "File to persist SOCKS Proxy keys")
("socksproxy.signaturetype", value<i2p::data::SigningKeyType>()->default_value(i2p::data::SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519), "Signature type for new keys. 7 (EdDSA) by default") ("socksproxy.signaturetype", value<i2p::data::SigningKeyType>()->default_value(i2p::data::SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519), "Signature type for new keys. 7 (EdDSA) by default")
("socksproxy.inbound.length", value<std::string>()->default_value("3"), "SOCKS proxy inbound tunnel length") ("socksproxy.inbound.length", value<std::string>()->default_value("3"), "SOCKS proxy inbound tunnel length")
("socksproxy.outbound.length", value<std::string>()->default_value("3"), "SOCKS proxy outbound tunnel length") ("socksproxy.outbound.length", value<std::string>()->default_value("3"), "SOCKS proxy outbound tunnel length")
("socksproxy.inbound.quantity", value<std::string>()->default_value("5"), "SOCKS proxy inbound tunnels quantity") ("socksproxy.inbound.quantity", value<std::string>()->default_value("5"), "SOCKS proxy inbound tunnels quantity")
("socksproxy.outbound.quantity", value<std::string>()->default_value("5"), "SOCKS proxy outbound tunnels quantity") ("socksproxy.outbound.quantity", value<std::string>()->default_value("5"), "SOCKS proxy outbound tunnels quantity")
("socksproxy.latency.min", value<std::string>()->default_value("0"), "SOCKS proxy min latency for tunnels") ("socksproxy.latency.min", value<std::string>()->default_value("0"), "SOCKS proxy min latency for tunnels")
("socksproxy.latency.max", value<std::string>()->default_value("0"), "SOCKS proxy max latency for tunnels") ("socksproxy.latency.max", value<std::string>()->default_value("0"), "SOCKS proxy max latency for tunnels")
("socksproxy.outproxy", value<std::string>()->default_value("127.0.0.1"), "Upstream outproxy address for SOCKS Proxy") ("socksproxy.outproxy", value<std::string>()->default_value("127.0.0.1"), "Upstream outproxy address for SOCKS Proxy")
("socksproxy.outproxyport", value<uint16_t>()->default_value(9050), "Upstream outproxy port for SOCKS Proxy") ("socksproxy.outproxyport", value<uint16_t>()->default_value(9050), "Upstream outproxy port for SOCKS Proxy")
; ;
@ -148,26 +149,26 @@ namespace config {
bool upnp_default = false; bool upnp_default = false;
#if (defined(USE_UPNP) && (defined(WIN32_APP) || defined(ANDROID))) #if (defined(USE_UPNP) && (defined(WIN32_APP) || defined(ANDROID)))
upnp_default = true; // enable UPNP for windows GUI and android by default upnp_default = true; // enable UPNP for windows GUI and android by default
#endif #endif
options_description upnp("UPnP options"); options_description upnp("UPnP options");
upnp.add_options() upnp.add_options()
("upnp.enabled", value<bool>()->default_value(upnp_default), "Enable or disable UPnP: automatic port forwarding") ("upnp.enabled", value<bool>()->default_value(upnp_default), "Enable or disable UPnP: automatic port forwarding")
("upnp.name", value<std::string>()->default_value("I2Pd"), "Name i2pd appears in UPnP forwardings list") ("upnp.name", value<std::string>()->default_value("I2Pd"), "Name i2pd appears in UPnP forwardings list")
; ;
options_description precomputation("Precomputation options"); options_description precomputation("Precomputation options");
precomputation.add_options() precomputation.add_options()
("precomputation.elgamal", ("precomputation.elgamal",
#if defined(__x86_64__) #if defined(__x86_64__)
value<bool>()->default_value(false), value<bool>()->default_value(false),
#else #else
value<bool>()->default_value(true), value<bool>()->default_value(true),
#endif #endif
"Enable or disable elgamal precomputation table") "Enable or disable elgamal precomputation table")
; ;
options_description reseed("Reseed options"); options_description reseed("Reseed options");
reseed.add_options() reseed.add_options()
("reseed.verify", value<bool>()->default_value(false), "Verify .su3 signature") ("reseed.verify", value<bool>()->default_value(false), "Verify .su3 signature")
("reseed.threshold", value<uint16_t>()->default_value(25), "Minimum number of known routers before requesting reseed") ("reseed.threshold", value<uint16_t>()->default_value(25), "Minimum number of known routers before requesting reseed")
@ -188,16 +189,16 @@ namespace config {
"https://reseed.memcpy.io/," "https://reseed.memcpy.io/,"
"https://reseed.onion.im/," "https://reseed.onion.im/,"
"https://itoopie.atomike.ninja/" "https://itoopie.atomike.ninja/"
// "https://randomrng.ddns.net/" // dead // "https://randomrng.ddns.net/" // dead
), "Reseed URLs, separated by comma") ), "Reseed URLs, separated by comma")
; ;
options_description addressbook("AddressBook options"); options_description addressbook("AddressBook options");
addressbook.add_options() addressbook.add_options()
("addressbook.defaulturl", value<std::string>()->default_value( ("addressbook.defaulturl", value<std::string>()->default_value(
"http://joajgazyztfssty4w2on5oaqksz6tqoxbduy553y34mf4byv6gpq.b32.i2p/export/alive-hosts.txt" "http://joajgazyztfssty4w2on5oaqksz6tqoxbduy553y34mf4byv6gpq.b32.i2p/export/alive-hosts.txt"
), "AddressBook subscription URL for initial setup") ), "AddressBook subscription URL for initial setup")
("addressbook.subscriptions", value<std::string>()->default_value(""), ("addressbook.subscriptions", value<std::string>()->default_value(""),
"AddressBook subscriptions URLs, separated by comma"); "AddressBook subscriptions URLs, separated by comma");
options_description trust("Trust options"); options_description trust("Trust options");
@ -206,7 +207,7 @@ namespace config {
("trust.family", value<std::string>()->default_value(""), "Router Familiy to trust for first hops") ("trust.family", value<std::string>()->default_value(""), "Router Familiy to trust for first hops")
("trust.routers", value<std::string>()->default_value(""), "Only Connect to these routers") ("trust.routers", value<std::string>()->default_value(""), "Only Connect to these routers")
("trust.hidden", value<bool>()->default_value(false), "Should we hide our router from other routers?"); ("trust.hidden", value<bool>()->default_value(false), "Should we hide our router from other routers?");
options_description websocket("Websocket Options"); options_description websocket("Websocket Options");
websocket.add_options() websocket.add_options()
("websockets.enabled", value<bool>()->default_value(false), "enable websocket server") ("websockets.enabled", value<bool>()->default_value(false), "enable websocket server")
@ -215,50 +216,50 @@ namespace config {
options_description exploratory("Exploratory Options"); options_description exploratory("Exploratory Options");
exploratory.add_options() exploratory.add_options()
("exploratory.inbound.length", value<int>()->default_value(2), "Exploratory inbound tunnel length") ("exploratory.inbound.length", value<int>()->default_value(2), "Exploratory inbound tunnel length")
("exploratory.outbound.length", value<int>()->default_value(2), "Exploratory outbound tunnel length") ("exploratory.outbound.length", value<int>()->default_value(2), "Exploratory outbound tunnel length")
("exploratory.inbound.quantity", value<int>()->default_value(3), "Exploratory inbound tunnels quantity") ("exploratory.inbound.quantity", value<int>()->default_value(3), "Exploratory inbound tunnels quantity")
("exploratory.outbound.quantity", value<int>()->default_value(3), "Exploratory outbound tunnels quantity"); ("exploratory.outbound.quantity", value<int>()->default_value(3), "Exploratory outbound tunnels quantity");
m_OptionsDesc m_OptionsDesc
.add(general) .add(general)
.add(limits) .add(limits)
.add(httpserver) .add(httpserver)
.add(httpproxy) .add(httpproxy)
.add(socksproxy) .add(socksproxy)
.add(sam) .add(sam)
.add(bob) .add(bob)
.add(i2cp) .add(i2cp)
.add(i2pcontrol) .add(i2pcontrol)
.add(upnp) .add(upnp)
.add(precomputation) .add(precomputation)
.add(reseed) .add(reseed)
.add(addressbook) .add(addressbook)
.add(trust) .add(trust)
.add(websocket) .add(websocket)
.add(exploratory) .add(exploratory)
; ;
} }
void ParseCmdline(int argc, char* argv[], bool ignoreUnknown) void ParseCmdline(int argc, char* argv[], bool ignoreUnknown)
{ {
try try
{ {
auto style = boost::program_options::command_line_style::unix_style auto style = boost::program_options::command_line_style::unix_style
| boost::program_options::command_line_style::allow_long_disguise; | boost::program_options::command_line_style::allow_long_disguise;
style &= ~ boost::program_options::command_line_style::allow_guessing; style &= ~ boost::program_options::command_line_style::allow_guessing;
if (ignoreUnknown) if (ignoreUnknown)
store(command_line_parser(argc, argv).options(m_OptionsDesc).style (style).allow_unregistered().run(), m_Options); store(command_line_parser(argc, argv).options(m_OptionsDesc).style (style).allow_unregistered().run(), m_Options);
else else
store(parse_command_line(argc, argv, m_OptionsDesc, style), m_Options); store(parse_command_line(argc, argv, m_OptionsDesc, style), m_Options);
} }
catch (boost::program_options::error& e) catch (boost::program_options::error& e)
{ {
std::cerr << "args: " << e.what() << std::endl; std::cerr << "args: " << e.what() << std::endl;
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
if (!ignoreUnknown && (m_Options.count("help") || m_Options.count("h"))) if (!ignoreUnknown && (m_Options.count("help") || m_Options.count("h")))
{ {
std::cout << "i2pd version " << I2PD_VERSION << " (" << I2P_VERSION << ")" << std::endl; std::cout << "i2pd version " << I2PD_VERSION << " (" << I2P_VERSION << ")" << std::endl;
std::cout << m_OptionsDesc; std::cout << m_OptionsDesc;
@ -271,17 +272,17 @@ namespace config {
std::ifstream config(path, std::ios::in); std::ifstream config(path, std::ios::in);
if (!config.is_open()) if (!config.is_open())
{ {
std::cerr << "missing/unreadable config file: " << path << std::endl; std::cerr << "missing/unreadable config file: " << path << std::endl;
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
try try
{ {
store(boost::program_options::parse_config_file(config, m_OptionsDesc), m_Options); store(boost::program_options::parse_config_file(config, m_OptionsDesc), m_Options);
} }
catch (boost::program_options::error& e) catch (boost::program_options::error& e)
{ {
std::cerr << e.what() << std::endl; std::cerr << e.what() << std::endl;
exit(EXIT_FAILURE); exit(EXIT_FAILURE);

714
libi2pd/NTCPSession.cpp

File diff suppressed because it is too large Load Diff

78
libi2pd/NTCPSession.h

@ -21,8 +21,8 @@ namespace transport
{ {
uint8_t pubKey[256]; uint8_t pubKey[256];
uint8_t HXxorHI[32]; uint8_t HXxorHI[32];
}; };
struct NTCPPhase2 struct NTCPPhase2
{ {
uint8_t pubKey[256]; uint8_t pubKey[256];
@ -31,17 +31,17 @@ namespace transport
uint8_t hxy[32]; uint8_t hxy[32];
uint8_t timestamp[4]; uint8_t timestamp[4];
uint8_t filler[12]; uint8_t filler[12];
} encrypted; } encrypted;
}; };
const size_t NTCP_MAX_MESSAGE_SIZE = 16384; const size_t NTCP_MAX_MESSAGE_SIZE = 16384;
const size_t NTCP_BUFFER_SIZE = 1028; // fits 1 tunnel data message const size_t NTCP_BUFFER_SIZE = 1028; // fits 1 tunnel data message
const int NTCP_CONNECT_TIMEOUT = 5; // 5 seconds const int NTCP_CONNECT_TIMEOUT = 5; // 5 seconds
const int NTCP_ESTABLISH_TIMEOUT = 10; // 10 seconds const int NTCP_ESTABLISH_TIMEOUT = 10; // 10 seconds
const int NTCP_TERMINATION_TIMEOUT = 120; // 2 minutes const int NTCP_TERMINATION_TIMEOUT = 120; // 2 minutes
const int NTCP_TERMINATION_CHECK_TIMEOUT = 30; // 30 seconds const int NTCP_TERMINATION_CHECK_TIMEOUT = 30; // 30 seconds
const size_t NTCP_DEFAULT_PHASE3_SIZE = 2/*size*/ + i2p::data::DEFAULT_IDENTITY_SIZE/*387*/ + 4/*ts*/ + 15/*padding*/ + 40/*signature*/; // 448 const size_t NTCP_DEFAULT_PHASE3_SIZE = 2/*size*/ + i2p::data::DEFAULT_IDENTITY_SIZE/*387*/ + 4/*ts*/ + 15/*padding*/ + 40/*signature*/; // 448
const int NTCP_CLOCK_SKEW = 60; // in seconds const int NTCP_CLOCK_SKEW = 60; // in seconds
const int NTCP_MAX_OUTGOING_QUEUE_SIZE = 200; // how many messages we can queue up const int NTCP_MAX_OUTGOING_QUEUE_SIZE = 200; // how many messages we can queue up
class NTCPServer; class NTCPServer;
@ -55,13 +55,13 @@ namespace transport
void Done (); void Done ();
boost::asio::ip::tcp::socket& GetSocket () { return m_Socket; }; boost::asio::ip::tcp::socket& GetSocket () { return m_Socket; };
bool IsEstablished () const { return m_IsEstablished; }; bool IsEstablished () const { return m_IsEstablished; };
bool IsTerminated () const { return m_IsTerminated; }; bool IsTerminated () const { return m_IsTerminated; };
void ClientLogin (); void ClientLogin ();
void ServerLogin (); void ServerLogin ();
void SendI2NPMessages (const std::vector<std::shared_ptr<I2NPMessage> >& msgs); void SendI2NPMessages (const std::vector<std::shared_ptr<I2NPMessage> >& msgs);
private: private:
void PostI2NPMessages (std::vector<std::shared_ptr<I2NPMessage> > msgs); void PostI2NPMessages (std::vector<std::shared_ptr<I2NPMessage> > msgs);
@ -70,7 +70,7 @@ namespace transport
void SetIsEstablished (bool isEstablished) { m_IsEstablished = isEstablished; } void SetIsEstablished (bool isEstablished) { m_IsEstablished = isEstablished; }
void CreateAESKey (uint8_t * pubKey); void CreateAESKey (uint8_t * pubKey);
// client // client
void SendPhase3 (); void SendPhase3 ();
void HandlePhase1Sent (const boost::system::error_code& ecode, std::size_t bytes_transferred); void HandlePhase1Sent (const boost::system::error_code& ecode, std::size_t bytes_transferred);
@ -88,35 +88,35 @@ namespace transport
void HandlePhase3ExtraReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred, uint32_t tsB, size_t paddingLen); void HandlePhase3ExtraReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred, uint32_t tsB, size_t paddingLen);
void HandlePhase3 (uint32_t tsB, size_t paddingLen); void HandlePhase3 (uint32_t tsB, size_t paddingLen);
void HandlePhase4Sent (const boost::system::error_code& ecode, std::size_t bytes_transferred); void HandlePhase4Sent (const boost::system::error_code& ecode, std::size_t bytes_transferred);
// common // common
void Receive (); 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);
bool DecryptNextBlock (const uint8_t * encrypted); bool DecryptNextBlock (const uint8_t * encrypted);
void Send (std::shared_ptr<i2p::I2NPMessage> msg); void Send (std::shared_ptr<i2p::I2NPMessage> msg);
boost::asio::const_buffers_1 CreateMsgBuffer (std::shared_ptr<I2NPMessage> msg); boost::asio::const_buffers_1 CreateMsgBuffer (std::shared_ptr<I2NPMessage> msg);
void Send (const std::vector<std::shared_ptr<I2NPMessage> >& msgs); void Send (const std::vector<std::shared_ptr<I2NPMessage> >& msgs);
void HandleSent (const boost::system::error_code& ecode, std::size_t bytes_transferred, std::vector<std::shared_ptr<I2NPMessage> > msgs); void HandleSent (const boost::system::error_code& ecode, std::size_t bytes_transferred, std::vector<std::shared_ptr<I2NPMessage> > msgs);
private: private:
NTCPServer& m_Server; NTCPServer& m_Server;
boost::asio::ip::tcp::socket m_Socket; boost::asio::ip::tcp::socket m_Socket;
bool m_IsEstablished, m_IsTerminated; bool m_IsEstablished, m_IsTerminated;
i2p::crypto::CBCDecryption m_Decryption; i2p::crypto::CBCDecryption m_Decryption;
i2p::crypto::CBCEncryption m_Encryption; i2p::crypto::CBCEncryption m_Encryption;
struct Establisher struct Establisher
{ {
NTCPPhase1 phase1; NTCPPhase1 phase1;
NTCPPhase2 phase2; NTCPPhase2 phase2;
} * m_Establisher; } * m_Establisher;
i2p::crypto::AESAlignedBuffer<NTCP_BUFFER_SIZE + 16> m_ReceiveBuffer; i2p::crypto::AESAlignedBuffer<NTCP_BUFFER_SIZE + 16> m_ReceiveBuffer;
i2p::crypto::AESAlignedBuffer<16> m_TimeSyncBuffer; i2p::crypto::AESAlignedBuffer<16> m_TimeSyncBuffer;
int m_ReceiveBufferOffset; int m_ReceiveBufferOffset;
std::shared_ptr<I2NPMessage> m_NextMessage; std::shared_ptr<I2NPMessage> m_NextMessage;
size_t m_NextMessageOffset; size_t m_NextMessageOffset;
@ -124,7 +124,7 @@ namespace transport
bool m_IsSending; bool m_IsSending;
std::vector<std::shared_ptr<I2NPMessage> > m_SendQueue; std::vector<std::shared_ptr<I2NPMessage> > m_SendQueue;
}; };
// TODO: move to NTCP.h/.cpp // TODO: move to NTCP.h/.cpp
class NTCPServer class NTCPServer
@ -140,12 +140,17 @@ namespace transport
bool AddNTCPSession (std::shared_ptr<NTCPSession> session); bool AddNTCPSession (std::shared_ptr<NTCPSession> session);
void RemoveNTCPSession (std::shared_ptr<NTCPSession> session); void RemoveNTCPSession (std::shared_ptr<NTCPSession> session);
std::shared_ptr<NTCPSession> FindNTCPSession (const i2p::data::IdentHash& ident); std::shared_ptr<NTCPSession> FindNTCPSession (const i2p::data::IdentHash& ident);
void Connect (const boost::asio::ip::address& address, int port, std::shared_ptr<NTCPSession> conn); void ConnectSocks (const std::string& addr, uint16_t port, std::shared_ptr<NTCPSession> conn);
void Connect(const boost::asio::ip::address & address, uint16_t port, std::shared_ptr<NTCPSession> conn);
bool IsBoundV4() const { return m_NTCPAcceptor != nullptr; };
bool IsBoundV6() const { return m_NTCPV6Acceptor != nullptr; };
bool NetworkIsReady() const { return IsBoundV4() || IsBoundV6() || m_UseSocks; };
bool UsingSocksProxy() const { return m_UseSocks; };
void UseSocksProxy(const std::string & address, uint16_t port);
bool IsBoundV4() const { return m_NTCPAcceptor != nullptr; }; boost::asio::io_service& GetService () { return m_Service; };
bool IsBoundV6() const { return m_NTCPV6Acceptor != nullptr; };
boost::asio::io_service& GetService () { return m_Service; };
private: private:
@ -155,14 +160,16 @@ namespace transport
void HandleConnect (const boost::system::error_code& ecode, std::shared_ptr<NTCPSession> conn, std::shared_ptr<boost::asio::deadline_timer> timer); void HandleConnect (const boost::system::error_code& ecode, std::shared_ptr<NTCPSession> conn, std::shared_ptr<boost::asio::deadline_timer> timer);
void HandleSocksConnect(const boost::system::error_code& ecode, std::shared_ptr<NTCPSession> conn, std::shared_ptr<boost::asio::deadline_timer> timer, const std::string & host, uint16_t port);
// timer // timer
void ScheduleTermination (); void ScheduleTermination ();
void HandleTerminationTimer (const boost::system::error_code& ecode); void HandleTerminationTimer (const boost::system::error_code& ecode);
private: private:
bool m_IsRunning; bool m_IsRunning;
std::thread * m_Thread; std::thread * m_Thread;
boost::asio::io_service m_Service; boost::asio::io_service m_Service;
boost::asio::io_service::work m_Work; boost::asio::io_service::work m_Work;
boost::asio::deadline_timer m_TerminationTimer; boost::asio::deadline_timer m_TerminationTimer;
@ -170,12 +177,17 @@ namespace transport
std::map<i2p::data::IdentHash, std::shared_ptr<NTCPSession> > m_NTCPSessions; // access from m_Thread only std::map<i2p::data::IdentHash, std::shared_ptr<NTCPSession> > m_NTCPSessions; // access from m_Thread only
std::list<std::shared_ptr<NTCPSession> > m_PendingIncomingSessions; std::list<std::shared_ptr<NTCPSession> > m_PendingIncomingSessions;
bool m_UseSocks;
std::string m_SocksAddress;
uint16_t m_SocksPort;
boost::asio::ip::tcp::resolver m_Resolver;
boost::asio::ip::tcp::endpoint * m_SocksEndpoint;
public: public:
// for HTTP/I2PControl // for HTTP/I2PControl
const decltype(m_NTCPSessions)& GetNTCPSessions () const { return m_NTCPSessions; }; const decltype(m_NTCPSessions)& GetNTCPSessions () const { return m_NTCPSessions; };
}; };
} }
} }
#endif #endif

308
libi2pd/Transports.cpp

@ -5,6 +5,7 @@
#include "NetDb.hpp" #include "NetDb.hpp"
#include "Transports.h" #include "Transports.h"
#include "Config.h" #include "Config.h"
#include "HTTP.h"
#ifdef WITH_EVENTS #ifdef WITH_EVENTS
#include "Event.h" #include "Event.h"
#include "util.h" #include "util.h"
@ -19,7 +20,7 @@ namespace transport
DHKeysPairSupplier::DHKeysPairSupplier (int size): DHKeysPairSupplier::DHKeysPairSupplier (int size):
m_QueueSize (size), m_IsRunning (false), m_Thread (nullptr) m_QueueSize (size), m_IsRunning (false), m_Thread (nullptr)
{ {
} }
DHKeysPairSupplier::~DHKeysPairSupplier () DHKeysPairSupplier::~DHKeysPairSupplier ()
{ {
@ -35,13 +36,13 @@ namespace transport
void DHKeysPairSupplier::Stop () void DHKeysPairSupplier::Stop ()
{ {
m_IsRunning = false; m_IsRunning = false;
m_Acquired.notify_one (); m_Acquired.notify_one ();
if (m_Thread) if (m_Thread)
{ {
m_Thread->join (); m_Thread->join ();
delete m_Thread; delete m_Thread;
m_Thread = 0; m_Thread = 0;
} }
} }
void DHKeysPairSupplier::Run () void DHKeysPairSupplier::Run ()
@ -50,7 +51,7 @@ namespace transport
{ {
int num, total = 0; int num, total = 0;
while ((num = m_QueueSize - (int)m_Queue.size ()) > 0 && total < 20) while ((num = m_QueueSize - (int)m_Queue.size ()) > 0 && total < 20)
{ {
CreateDHKeysPairs (num); CreateDHKeysPairs (num);
total += num; total += num;
} }
@ -63,9 +64,9 @@ namespace transport
{ {
std::unique_lock<std::mutex> l(m_AcquiredMutex); std::unique_lock<std::mutex> l(m_AcquiredMutex);
m_Acquired.wait (l); // wait for element gets aquired m_Acquired.wait (l); // wait for element gets aquired
} }
} }
} }
void DHKeysPairSupplier::CreateDHKeysPairs (int num) void DHKeysPairSupplier::CreateDHKeysPairs (int num)
{ {
@ -91,8 +92,8 @@ namespace transport
m_Queue.pop (); m_Queue.pop ();
m_Acquired.notify_one (); m_Acquired.notify_one ();
return pair; return pair;
} }
} }
// queue is empty, create new // queue is empty, create new
auto pair = std::make_shared<i2p::crypto::DHKeys> (); auto pair = std::make_shared<i2p::crypto::DHKeys> ();
pair->GenerateKeys (); pair->GenerateKeys ();
@ -106,21 +107,21 @@ namespace transport
m_Queue.push (pair); m_Queue.push (pair);
} }
Transports transports; Transports transports;
Transports::Transports (): Transports::Transports ():
m_IsOnline (true), m_IsRunning (false), m_Thread (nullptr), m_Service (nullptr), m_IsOnline (true), m_IsRunning (false), m_Thread (nullptr), m_Service (nullptr),
m_Work (nullptr), m_PeerCleanupTimer (nullptr), m_PeerTestTimer (nullptr), m_Work (nullptr), m_PeerCleanupTimer (nullptr), m_PeerTestTimer (nullptr),
m_NTCPServer (nullptr), m_SSUServer (nullptr), m_DHKeysPairSupplier (5), // 5 pre-generated keys m_NTCPServer (nullptr), m_SSUServer (nullptr), m_DHKeysPairSupplier (5), // 5 pre-generated keys
m_TotalSentBytes(0), m_TotalReceivedBytes(0), m_TotalTransitTransmittedBytes (0), m_TotalSentBytes(0), m_TotalReceivedBytes(0), m_TotalTransitTransmittedBytes (0),
m_InBandwidth (0), m_OutBandwidth (0), m_TransitBandwidth(0), m_InBandwidth (0), m_OutBandwidth (0), m_TransitBandwidth(0),
m_LastInBandwidthUpdateBytes (0), m_LastOutBandwidthUpdateBytes (0), m_LastInBandwidthUpdateBytes (0), m_LastOutBandwidthUpdateBytes (0),
m_LastTransitBandwidthUpdateBytes (0), m_LastBandwidthUpdateTime (0) m_LastTransitBandwidthUpdateBytes (0), m_LastBandwidthUpdateTime (0)
{ {
} }
Transports::~Transports () Transports::~Transports ()
{ {
Stop (); Stop ();
if (m_Service) if (m_Service)
{ {
@ -128,8 +129,8 @@ namespace transport
delete m_PeerTestTimer; m_PeerTestTimer = nullptr; delete m_PeerTestTimer; m_PeerTestTimer = nullptr;
delete m_Work; m_Work = nullptr; delete m_Work; m_Work = nullptr;
delete m_Service; m_Service = nullptr; delete m_Service; m_Service = nullptr;
} }
} }
void Transports::Start (bool enableNTCP, bool enableSSU) void Transports::Start (bool enableNTCP, bool enableSSU)
{ {
@ -144,6 +145,34 @@ namespace transport
m_DHKeysPairSupplier.Start (); m_DHKeysPairSupplier.Start ();
m_IsRunning = true; m_IsRunning = true;
m_Thread = new std::thread (std::bind (&Transports::Run, this)); m_Thread = new std::thread (std::bind (&Transports::Run, this));
std::string ntcpproxy; i2p::config::GetOption("ntcpproxy", ntcpproxy);
i2p::http::URL proxyurl;
if(ntcpproxy.size() && enableNTCP)
{
if(proxyurl.parse(ntcpproxy))
{
if(proxyurl.schema == "socks")
{
m_NTCPServer = new NTCPServer();
m_NTCPServer->UseSocksProxy(proxyurl.host, proxyurl.port) ;
m_NTCPServer->Start();
if(!m_NTCPServer->NetworkIsReady())
{
LogPrint(eLogError, "Transports: NTCP failed to start with socks proxy");
m_NTCPServer->Stop();
delete m_NTCPServer;
m_NTCPServer = nullptr;
}
}
else
LogPrint(eLogError, "Transports: unsupported NTCP proxy URL ", ntcpproxy);
}
else
LogPrint(eLogError, "Transports: invalid NTCP proxy url ", ntcpproxy);
return;
}
// create acceptors // create acceptors
auto& addresses = context.GetRouterInfo ().GetAddresses (); auto& addresses = context.GetRouterInfo ().GetAddresses ();
for (const auto& address : addresses) for (const auto& address : addresses)
@ -160,8 +189,8 @@ namespace transport
delete m_NTCPServer; delete m_NTCPServer;
m_NTCPServer = nullptr; m_NTCPServer = nullptr;
} }
} }
if (address->transportStyle == RouterInfo::eTransportSSU) if (address->transportStyle == RouterInfo::eTransportSSU)
{ {
if (m_SSUServer == nullptr && enableSSU) if (m_SSUServer == nullptr && enableSSU)
@ -184,16 +213,16 @@ namespace transport
else else
LogPrint (eLogError, "Transports: SSU server already exists"); LogPrint (eLogError, "Transports: SSU server already exists");
} }
} }
m_PeerCleanupTimer->expires_from_now (boost::posix_time::seconds(5*SESSION_CREATION_TIMEOUT)); m_PeerCleanupTimer->expires_from_now (boost::posix_time::seconds(5*SESSION_CREATION_TIMEOUT));
m_PeerCleanupTimer->async_wait (std::bind (&Transports::HandlePeerCleanupTimer, this, std::placeholders::_1)); m_PeerCleanupTimer->async_wait (std::bind (&Transports::HandlePeerCleanupTimer, this, std::placeholders::_1));
m_PeerTestTimer->expires_from_now (boost::posix_time::minutes(PEER_TEST_INTERVAL)); m_PeerTestTimer->expires_from_now (boost::posix_time::minutes(PEER_TEST_INTERVAL));
m_PeerTestTimer->async_wait (std::bind (&Transports::HandlePeerTestTimer, this, std::placeholders::_1)); m_PeerTestTimer->async_wait (std::bind (&Transports::HandlePeerTestTimer, this, std::placeholders::_1));
} }
void Transports::Stop () void Transports::Stop ()
{ {
if (m_PeerCleanupTimer) m_PeerCleanupTimer->cancel (); if (m_PeerCleanupTimer) m_PeerCleanupTimer->cancel ();
if (m_PeerTestTimer) m_PeerTestTimer->cancel (); if (m_PeerTestTimer) m_PeerTestTimer->cancel ();
m_Peers.clear (); m_Peers.clear ();
if (m_SSUServer) if (m_SSUServer)
@ -201,40 +230,40 @@ namespace transport
m_SSUServer->Stop (); m_SSUServer->Stop ();
delete m_SSUServer; delete m_SSUServer;
m_SSUServer = nullptr; m_SSUServer = nullptr;
} }
if (m_NTCPServer) if (m_NTCPServer)
{ {
m_NTCPServer->Stop (); m_NTCPServer->Stop ();
delete m_NTCPServer; delete m_NTCPServer;
m_NTCPServer = nullptr; m_NTCPServer = nullptr;
} }
m_DHKeysPairSupplier.Stop (); m_DHKeysPairSupplier.Stop ();
m_IsRunning = false; m_IsRunning = false;
if (m_Service) m_Service->stop (); if (m_Service) 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 Transports::Run () void Transports::Run ()
{ {
while (m_IsRunning && m_Service) while (m_IsRunning && m_Service)
{ {
try try
{ {
m_Service->run (); m_Service->run ();
} }
catch (std::exception& ex) catch (std::exception& ex)
{ {
LogPrint (eLogError, "Transports: runtime exception: ", ex.what ()); LogPrint (eLogError, "Transports: runtime exception: ", ex.what ());
} }
} }
} }
void Transports::UpdateBandwidth () void Transports::UpdateBandwidth ()
{ {
uint64_t ts = i2p::util::GetMillisecondsSinceEpoch (); uint64_t ts = i2p::util::GetMillisecondsSinceEpoch ();
@ -243,15 +272,15 @@ namespace transport
auto delta = ts - m_LastBandwidthUpdateTime; auto delta = ts - m_LastBandwidthUpdateTime;
if (delta > 0) if (delta > 0)
{ {
m_InBandwidth = (m_TotalReceivedBytes - m_LastInBandwidthUpdateBytes)*1000/delta; // per second m_InBandwidth = (m_TotalReceivedBytes - m_LastInBandwidthUpdateBytes)*1000/delta; // per second
m_OutBandwidth = (m_TotalSentBytes - m_LastOutBandwidthUpdateBytes)*1000/delta; // per second m_OutBandwidth = (m_TotalSentBytes - m_LastOutBandwidthUpdateBytes)*1000/delta; // per second
m_TransitBandwidth = (m_TotalTransitTransmittedBytes - m_LastTransitBandwidthUpdateBytes)*1000/delta; m_TransitBandwidth = (m_TotalTransitTransmittedBytes - m_LastTransitBandwidthUpdateBytes)*1000/delta;
} }
} }
m_LastBandwidthUpdateTime = ts; m_LastBandwidthUpdateTime = ts;
m_LastInBandwidthUpdateBytes = m_TotalReceivedBytes; m_LastInBandwidthUpdateBytes = m_TotalReceivedBytes;
m_LastOutBandwidthUpdateBytes = m_TotalSentBytes; m_LastOutBandwidthUpdateBytes = m_TotalSentBytes;
m_LastTransitBandwidthUpdateBytes = m_TotalTransitTransmittedBytes; m_LastTransitBandwidthUpdateBytes = m_TotalTransitTransmittedBytes;
} }
bool Transports::IsBandwidthExceeded () const bool Transports::IsBandwidthExceeded () const
@ -265,12 +294,12 @@ namespace transport
{ {
auto limit = i2p::context.GetTransitBandwidthLimit() * 1024; // convert to bytes auto limit = i2p::context.GetTransitBandwidthLimit() * 1024; // convert to bytes
return m_TransitBandwidth > limit; return m_TransitBandwidth > limit;
} }
void Transports::SendMessage (const i2p::data::IdentHash& ident, std::shared_ptr<i2p::I2NPMessage> msg) void Transports::SendMessage (const i2p::data::IdentHash& ident, std::shared_ptr<i2p::I2NPMessage> msg)
{ {
SendMessages (ident, std::vector<std::shared_ptr<i2p::I2NPMessage> > {msg }); SendMessages (ident, std::vector<std::shared_ptr<i2p::I2NPMessage> > {msg });
} }
void Transports::SendMessages (const i2p::data::IdentHash& ident, const std::vector<std::shared_ptr<i2p::I2NPMessage> >& msgs) void Transports::SendMessages (const i2p::data::IdentHash& ident, const std::vector<std::shared_ptr<i2p::I2NPMessage> >& msgs)
{ {
@ -278,12 +307,12 @@ namespace transport
QueueIntEvent("transport.send", ident.ToBase64(), msgs.size()); QueueIntEvent("transport.send", ident.ToBase64(), msgs.size());
#endif #endif
m_Service->post (std::bind (&Transports::PostMessages, this, ident, msgs)); m_Service->post (std::bind (&Transports::PostMessages, this, ident, msgs));
} }
void Transports::PostMessages (i2p::data::IdentHash ident, std::vector<std::shared_ptr<i2p::I2NPMessage> > msgs) void Transports::PostMessages (i2p::data::IdentHash ident, std::vector<std::shared_ptr<i2p::I2NPMessage> > msgs)
{ {
if (ident == i2p::context.GetRouterInfo ().GetIdentHash ()) if (ident == i2p::context.GetRouterInfo ().GetIdentHash ())
{ {
// we send it to ourself // we send it to ourself
for (auto& it: msgs) for (auto& it: msgs)
m_LoopbackHandler.PutNextMessage (it); m_LoopbackHandler.PutNextMessage (it);
@ -294,12 +323,12 @@ namespace transport
auto it = m_Peers.find (ident); auto it = m_Peers.find (ident);
if (it == m_Peers.end ()) if (it == m_Peers.end ())
{ {
bool connected = false; bool connected = false;
try try
{ {
auto r = netdb.FindRouter (ident); auto r = netdb.FindRouter (ident);
{ {
std::unique_lock<std::mutex> l(m_PeersMutex); std::unique_lock<std::mutex> l(m_PeersMutex);
it = m_Peers.insert (std::pair<i2p::data::IdentHash, Peer>(ident, { 0, r, {}, it = m_Peers.insert (std::pair<i2p::data::IdentHash, Peer>(ident, { 0, r, {},
i2p::util::GetSecondsSinceEpoch (), {} })).first; i2p::util::GetSecondsSinceEpoch (), {} })).first;
} }
@ -310,29 +339,29 @@ namespace transport
LogPrint (eLogError, "Transports: PostMessages exception:", ex.what ()); LogPrint (eLogError, "Transports: PostMessages exception:", ex.what ());
} }
if (!connected) return; if (!connected) return;
} }
if (!it->second.sessions.empty ()) if (!it->second.sessions.empty ())
it->second.sessions.front ()->SendI2NPMessages (msgs); it->second.sessions.front ()->SendI2NPMessages (msgs);
else else
{ {
if (it->second.delayedMessages.size () < MAX_NUM_DELAYED_MESSAGES) if (it->second.delayedMessages.size () < MAX_NUM_DELAYED_MESSAGES)
{ {
for (auto& it1: msgs) for (auto& it1: msgs)
it->second.delayedMessages.push_back (it1); it->second.delayedMessages.push_back (it1);
} }
else else
{ {
LogPrint (eLogWarning, "Transports: delayed messages queue size exceeds ", MAX_NUM_DELAYED_MESSAGES); LogPrint (eLogWarning, "Transports: delayed messages queue size exceeds ", MAX_NUM_DELAYED_MESSAGES);
std::unique_lock<std::mutex> l(m_PeersMutex); std::unique_lock<std::mutex> l(m_PeersMutex);
m_Peers.erase (it); m_Peers.erase (it);
} }
} }
} }
bool Transports::ConnectToPeer (const i2p::data::IdentHash& ident, Peer& peer) bool Transports::ConnectToPeer (const i2p::data::IdentHash& ident, Peer& peer)
{ {
if (peer.router) // we have RI already if (peer.router) // we have RI already
{ {
if (!peer.numAttempts) // NTCP if (!peer.numAttempts) // NTCP
{ {
peer.numAttempts++; peer.numAttempts++;
@ -343,14 +372,20 @@ namespace transport
if (!address->host.is_unspecified ()) // we have address now if (!address->host.is_unspecified ()) // we have address now
#else #else
boost::system::error_code ecode; boost::system::error_code ecode;
address->host.to_string (ecode); address->host.to_string (ecode);
if (!ecode) if (!ecode)
#endif #endif
{ {
if (!peer.router->UsesIntroducer () && !peer.router->IsUnreachable ()) if (!peer.router->UsesIntroducer () && !peer.router->IsUnreachable ())
{ {
auto s = std::make_shared<NTCPSession> (*m_NTCPServer, peer.router); auto s = std::make_shared<NTCPSession> (*m_NTCPServer, peer.router);
m_NTCPServer->Connect (address->host, address->port, s); if(m_NTCPServer->UsingSocksProxy())
{
std::string addr = address->host.to_string();
m_NTCPServer->ConnectSocks(addr, address->port, s);
}
else
m_NTCPServer->Connect (address->host, address->port, s);
return true; return true;
} }
} }
@ -358,12 +393,20 @@ namespace transport
{ {
if (address->addressString.length () > 0) // trying to resolve if (address->addressString.length () > 0) // trying to resolve
{ {
LogPrint (eLogDebug, "Transports: Resolving NTCP ", address->addressString); if(m_NTCPServer->UsingSocksProxy())
NTCPResolve (address->addressString, ident); {
auto s = std::make_shared<NTCPSession> (*m_NTCPServer, peer.router);
m_NTCPServer->ConnectSocks(address->addressString, address->port, s);
}
else
{
LogPrint (eLogDebug, "Transports: Resolving NTCP ", address->addressString);
NTCPResolve (address->addressString, ident);
}
return true; return true;
} }
} }
} }
else else
LogPrint (eLogDebug, "Transports: NTCP address is not present for ", i2p::data::GetIdentHashAbbreviation (ident), ", trying SSU"); LogPrint (eLogDebug, "Transports: NTCP address is not present for ", i2p::data::GetIdentHashAbbreviation (ident), ", trying SSU");
} }
@ -394,56 +437,56 @@ namespace transport
} }
} }
} }
} }
LogPrint (eLogInfo, "Transports: No NTCP or SSU addresses available"); LogPrint (eLogInfo, "Transports: No NTCP or SSU addresses available");
peer.Done (); peer.Done ();
std::unique_lock<std::mutex> l(m_PeersMutex); std::unique_lock<std::mutex> l(m_PeersMutex);
m_Peers.erase (ident); m_Peers.erase (ident);
return false; return false;
} }
else // otherwise request RI else // otherwise request RI
{ {
LogPrint (eLogInfo, "Transports: RouterInfo for ", ident.ToBase64 (), " not found, requested"); LogPrint (eLogInfo, "Transports: RouterInfo for ", ident.ToBase64 (), " not found, requested");
i2p::data::netdb.RequestDestination (ident, std::bind ( i2p::data::netdb.RequestDestination (ident, std::bind (
&Transports::RequestComplete, this, std::placeholders::_1, ident)); &Transports::RequestComplete, this, std::placeholders::_1, ident));
} }
return true; return true;
} }
void Transports::RequestComplete (std::shared_ptr<const i2p::data::RouterInfo> r, const i2p::data::IdentHash& ident) void Transports::RequestComplete (std::shared_ptr<const i2p::data::RouterInfo> r, const i2p::data::IdentHash& ident)
{ {
m_Service->post (std::bind (&Transports::HandleRequestComplete, this, r, ident)); m_Service->post (std::bind (&Transports::HandleRequestComplete, this, r, ident));
} }
void Transports::HandleRequestComplete (std::shared_ptr<const i2p::data::RouterInfo> r, i2p::data::IdentHash ident) void Transports::HandleRequestComplete (std::shared_ptr<const i2p::data::RouterInfo> r, i2p::data::IdentHash ident)
{ {
auto it = m_Peers.find (ident); auto it = m_Peers.find (ident);
if (it != m_Peers.end ()) if (it != m_Peers.end ())
{ {
if (r) if (r)
{ {
LogPrint (eLogDebug, "Transports: RouterInfo for ", ident.ToBase64 (), " found, Trying to connect"); LogPrint (eLogDebug, "Transports: RouterInfo for ", ident.ToBase64 (), " found, Trying to connect");
it->second.router = r; it->second.router = r;
ConnectToPeer (ident, it->second); ConnectToPeer (ident, it->second);
} }
else else
{ {
LogPrint (eLogWarning, "Transports: RouterInfo not found, Failed to send messages"); LogPrint (eLogWarning, "Transports: RouterInfo not found, Failed to send messages");
std::unique_lock<std::mutex> l(m_PeersMutex); std::unique_lock<std::mutex> l(m_PeersMutex);
m_Peers.erase (it); m_Peers.erase (it);
} }
} }
} }
void Transports::NTCPResolve (const std::string& addr, const i2p::data::IdentHash& ident) void Transports::NTCPResolve (const std::string& addr, const i2p::data::IdentHash& ident)
{ {
auto resolver = std::make_shared<boost::asio::ip::tcp::resolver>(*m_Service); auto resolver = std::make_shared<boost::asio::ip::tcp::resolver>(*m_Service);
resolver->async_resolve (boost::asio::ip::tcp::resolver::query (addr, ""), resolver->async_resolve (boost::asio::ip::tcp::resolver::query (addr, ""),
std::bind (&Transports::HandleNTCPResolve, this, std::bind (&Transports::HandleNTCPResolve, this,
std::placeholders::_1, std::placeholders::_2, ident, resolver)); std::placeholders::_1, std::placeholders::_2, ident, resolver));
} }
void Transports::HandleNTCPResolve (const boost::system::error_code& ecode, boost::asio::ip::tcp::resolver::iterator it, void Transports::HandleNTCPResolve (const boost::system::error_code& ecode, boost::asio::ip::tcp::resolver::iterator it,
i2p::data::IdentHash ident, std::shared_ptr<boost::asio::ip::tcp::resolver> resolver) i2p::data::IdentHash ident, std::shared_ptr<boost::asio::ip::tcp::resolver> resolver)
{ {
auto it1 = m_Peers.find (ident); auto it1 = m_Peers.find (ident);
@ -453,7 +496,7 @@ namespace transport
if (!ecode && peer.router) if (!ecode && peer.router)
{ {
while (it != boost::asio::ip::tcp::resolver::iterator()) while (it != boost::asio::ip::tcp::resolver::iterator())
{ {
auto address = (*it).endpoint ().address (); auto address = (*it).endpoint ().address ();
LogPrint (eLogDebug, "Transports: ", (*it).host_name (), " has been resolved to ", address); LogPrint (eLogDebug, "Transports: ", (*it).host_name (), " has been resolved to ", address);
if (address.is_v4 () || context.SupportsV6 ()) if (address.is_v4 () || context.SupportsV6 ())
@ -466,14 +509,14 @@ namespace transport
return; return;
} }
break; break;
} }
else else
LogPrint (eLogInfo, "Transports: NTCP ", address, " is not supported"); LogPrint (eLogInfo, "Transports: NTCP ", address, " is not supported");
it++; it++;
} }
} }
LogPrint (eLogError, "Transports: Unable to resolve NTCP address: ", ecode.message ()); LogPrint (eLogError, "Transports: Unable to resolve NTCP address: ", ecode.message ());
std::unique_lock<std::mutex> l(m_PeersMutex); std::unique_lock<std::mutex> l(m_PeersMutex);
m_Peers.erase (it1); m_Peers.erase (it1);
} }
} }
@ -481,12 +524,12 @@ namespace transport
void Transports::SSUResolve (const std::string& addr, const i2p::data::IdentHash& ident) void Transports::SSUResolve (const std::string& addr, const i2p::data::IdentHash& ident)
{ {
auto resolver = std::make_shared<boost::asio::ip::tcp::resolver>(*m_Service); auto resolver = std::make_shared<boost::asio::ip::tcp::resolver>(*m_Service);
resolver->async_resolve (boost::asio::ip::tcp::resolver::query (addr, ""), resolver->async_resolve (boost::asio::ip::tcp::resolver::query (addr, ""),
std::bind (&Transports::HandleSSUResolve, this, std::bind (&Transports::HandleSSUResolve, this,
std::placeholders::_1, std::placeholders::_2, ident, resolver)); std::placeholders::_1, std::placeholders::_2, ident, resolver));
} }
void Transports::HandleSSUResolve (const boost::system::error_code& ecode, boost::asio::ip::tcp::resolver::iterator it, void Transports::HandleSSUResolve (const boost::system::error_code& ecode, boost::asio::ip::tcp::resolver::iterator it,
i2p::data::IdentHash ident, std::shared_ptr<boost::asio::ip::tcp::resolver> resolver) i2p::data::IdentHash ident, std::shared_ptr<boost::asio::ip::tcp::resolver> resolver)
{ {
auto it1 = m_Peers.find (ident); auto it1 = m_Peers.find (ident);
@ -496,7 +539,7 @@ namespace transport
if (!ecode && peer.router) if (!ecode && peer.router)
{ {
while (it != boost::asio::ip::tcp::resolver::iterator()) while (it != boost::asio::ip::tcp::resolver::iterator())
{ {
auto address = (*it).endpoint ().address (); auto address = (*it).endpoint ().address ();
LogPrint (eLogDebug, "Transports: ", (*it).host_name (), " has been resolved to ", address); LogPrint (eLogDebug, "Transports: ", (*it).host_name (), " has been resolved to ", address);
if (address.is_v4 () || context.SupportsV6 ()) if (address.is_v4 () || context.SupportsV6 ())
@ -512,10 +555,10 @@ namespace transport
else else
LogPrint (eLogInfo, "Transports: SSU ", address, " is not supported"); LogPrint (eLogInfo, "Transports: SSU ", address, " is not supported");
it++; it++;
} }
} }
LogPrint (eLogError, "Transports: Unable to resolve SSU address: ", ecode.message ()); LogPrint (eLogError, "Transports: Unable to resolve SSU address: ", ecode.message ());
std::unique_lock<std::mutex> l(m_PeersMutex); std::unique_lock<std::mutex> l(m_PeersMutex);
m_Peers.erase (it1); m_Peers.erase (it1);
} }
} }
@ -523,14 +566,14 @@ namespace transport
void Transports::CloseSession (std::shared_ptr<const i2p::data::RouterInfo> router) void Transports::CloseSession (std::shared_ptr<const i2p::data::RouterInfo> router)
{ {
if (!router) return; if (!router) return;
m_Service->post (std::bind (&Transports::PostCloseSession, this, router)); m_Service->post (std::bind (&Transports::PostCloseSession, this, router));
} }
void Transports::PostCloseSession (std::shared_ptr<const i2p::data::RouterInfo> router) void Transports::PostCloseSession (std::shared_ptr<const i2p::data::RouterInfo> router)
{ {
auto ssuSession = m_SSUServer ? m_SSUServer->FindSession (router) : nullptr; auto ssuSession = m_SSUServer ? m_SSUServer->FindSession (router) : nullptr;
if (ssuSession) // try SSU first if (ssuSession) // try SSU first
{ {
m_SSUServer->DeleteSession (ssuSession); m_SSUServer->DeleteSession (ssuSession);
LogPrint (eLogDebug, "Transports: SSU session closed"); LogPrint (eLogDebug, "Transports: SSU session closed");
} }
@ -540,8 +583,8 @@ namespace transport
ntcpSession->Terminate (); ntcpSession->Terminate ();
LogPrint(eLogDebug, "Transports: NTCP session closed"); LogPrint(eLogDebug, "Transports: NTCP session closed");
} }
} }
void Transports::DetectExternalIP () void Transports::DetectExternalIP ()
{ {
if (RoutesRestricted()) if (RoutesRestricted())
@ -560,7 +603,7 @@ namespace transport
{ {
auto router = i2p::data::netdb.GetRandomPeerTestRouter (isv4); // v4 only if v4 auto router = i2p::data::netdb.GetRandomPeerTestRouter (isv4); // v4 only if v4
if (router) if (router)
m_SSUServer->CreateSession (router, true, isv4); // peer test m_SSUServer->CreateSession (router, true, isv4); // peer test
else else
{ {
// if not peer test capable routers found pick any // if not peer test capable routers found pick any
@ -568,7 +611,7 @@ namespace transport
if (router && router->IsSSU ()) if (router && router->IsSSU ())
m_SSUServer->CreateSession (router); // no peer test m_SSUServer->CreateSession (router); // no peer test
} }
} }
} }
else else
LogPrint (eLogError, "Transports: Can't detect external IP. SSU is not available"); LogPrint (eLogError, "Transports: Can't detect external IP. SSU is not available");
@ -578,26 +621,26 @@ namespace transport
{ {
if (RoutesRestricted() || !i2p::context.SupportsV4 ()) return; if (RoutesRestricted() || !i2p::context.SupportsV4 ()) return;
if (m_SSUServer) if (m_SSUServer)
{ {
bool statusChanged = false; bool statusChanged = false;
for (int i = 0; i < 5; i++) for (int i = 0; i < 5; i++)
{ {
auto router = i2p::data::netdb.GetRandomPeerTestRouter (true); // v4 only auto router = i2p::data::netdb.GetRandomPeerTestRouter (true); // v4 only
if (router) if (router)
{ {
if (!statusChanged) if (!statusChanged)
{ {
statusChanged = true; statusChanged = true;
i2p::context.SetStatus (eRouterStatusTesting); // first time only i2p::context.SetStatus (eRouterStatusTesting); // first time only
} }
m_SSUServer->CreateSession (router, true, true); // peer test v4 m_SSUServer->CreateSession (router, true, true); // peer test v4
} }
} }
if (!statusChanged) if (!statusChanged)
LogPrint (eLogWarning, "Can't find routers for peer test"); LogPrint (eLogWarning, "Can't find routers for peer test");
} }
} }
std::shared_ptr<i2p::crypto::DHKeys> Transports::GetNextDHKeysPair () std::shared_ptr<i2p::crypto::DHKeys> Transports::GetNextDHKeysPair ()
{ {
return m_DHKeysPairSupplier.Acquire (); return m_DHKeysPairSupplier.Acquire ();
@ -611,8 +654,8 @@ namespace transport
void Transports::PeerConnected (std::shared_ptr<TransportSession> session) void Transports::PeerConnected (std::shared_ptr<TransportSession> session)
{ {
m_Service->post([session, this]() m_Service->post([session, this]()
{ {
auto remoteIdentity = session->GetRemoteIdentity (); auto remoteIdentity = session->GetRemoteIdentity ();
if (!remoteIdentity) return; if (!remoteIdentity) return;
auto ident = remoteIdentity->GetIdentHash (); auto ident = remoteIdentity->GetIdentHash ();
auto it = m_Peers.find (ident); auto it = m_Peers.find (ident);
@ -629,7 +672,7 @@ namespace transport
if (firstMsg && firstMsg->GetTypeID () == eI2NPDatabaseStore && if (firstMsg && firstMsg->GetTypeID () == eI2NPDatabaseStore &&
i2p::data::IdentHash(firstMsg->GetPayload () + DATABASE_STORE_KEY_OFFSET) == i2p::context.GetIdentHash ()) i2p::data::IdentHash(firstMsg->GetPayload () + DATABASE_STORE_KEY_OFFSET) == i2p::context.GetIdentHash ())
sendDatabaseStore = false; // we have it in the list already sendDatabaseStore = false; // we have it in the list already
} }
if (sendDatabaseStore) if (sendDatabaseStore)
session->SendI2NPMessages ({ CreateDatabaseStoreMsg () }); session->SendI2NPMessages ({ CreateDatabaseStoreMsg () });
else else
@ -650,17 +693,17 @@ namespace transport
EmitEvent({{"type" , "transport.connected"}, {"ident", ident.ToBase64()}, {"inbound", "true"}}); EmitEvent({{"type" , "transport.connected"}, {"ident", ident.ToBase64()}, {"inbound", "true"}});
#endif #endif
session->SendI2NPMessages ({ CreateDatabaseStoreMsg () }); // send DatabaseStore session->SendI2NPMessages ({ CreateDatabaseStoreMsg () }); // send DatabaseStore
std::unique_lock<std::mutex> l(m_PeersMutex); std::unique_lock<std::mutex> l(m_PeersMutex);
m_Peers.insert (std::make_pair (ident, Peer{ 0, nullptr, { session }, i2p::util::GetSecondsSinceEpoch (), {} })); m_Peers.insert (std::make_pair (ident, Peer{ 0, nullptr, { session }, i2p::util::GetSecondsSinceEpoch (), {} }));
} }
}); });
} }
void Transports::PeerDisconnected (std::shared_ptr<TransportSession> session) void Transports::PeerDisconnected (std::shared_ptr<TransportSession> session)
{ {
m_Service->post([session, this]() m_Service->post([session, this]()
{ {
auto remoteIdentity = session->GetRemoteIdentity (); auto remoteIdentity = session->GetRemoteIdentity ();
if (!remoteIdentity) return; if (!remoteIdentity) return;
auto ident = remoteIdentity->GetIdentHash (); auto ident = remoteIdentity->GetIdentHash ();
#ifdef WITH_EVENTS #ifdef WITH_EVENTS
@ -671,26 +714,26 @@ namespace transport
{ {
it->second.sessions.remove (session); it->second.sessions.remove (session);
if (it->second.sessions.empty ()) // TODO: why? if (it->second.sessions.empty ()) // TODO: why?
{ {
if (it->second.delayedMessages.size () > 0) if (it->second.delayedMessages.size () > 0)
ConnectToPeer (ident, it->second); ConnectToPeer (ident, it->second);
else else
{ {
std::unique_lock<std::mutex> l(m_PeersMutex); std::unique_lock<std::mutex> l(m_PeersMutex);
m_Peers.erase (it); m_Peers.erase (it);
} }
} }
} }
}); });
} }
bool Transports::IsConnected (const i2p::data::IdentHash& ident) const bool Transports::IsConnected (const i2p::data::IdentHash& ident) const
{ {
std::unique_lock<std::mutex> l(m_PeersMutex); std::unique_lock<std::mutex> l(m_PeersMutex);
auto it = m_Peers.find (ident); auto it = m_Peers.find (ident);
return it != m_Peers.end (); return it != m_Peers.end ();
} }
void Transports::HandlePeerCleanupTimer (const boost::system::error_code& ecode) void Transports::HandlePeerCleanupTimer (const boost::system::error_code& ecode)
{ {
if (ecode != boost::asio::error::operation_aborted) if (ecode != boost::asio::error::operation_aborted)
@ -707,7 +750,7 @@ namespace transport
profile->TunnelNonReplied(); profile->TunnelNonReplied();
profile->Save(it->first); profile->Save(it->first);
} }
std::unique_lock<std::mutex> l(m_PeersMutex); std::unique_lock<std::mutex> l(m_PeersMutex);
it = m_Peers.erase (it); it = m_Peers.erase (it);
} }
else else
@ -718,7 +761,7 @@ namespace transport
DetectExternalIP (); DetectExternalIP ();
m_PeerCleanupTimer->expires_from_now (boost::posix_time::seconds(5*SESSION_CREATION_TIMEOUT)); m_PeerCleanupTimer->expires_from_now (boost::posix_time::seconds(5*SESSION_CREATION_TIMEOUT));
m_PeerCleanupTimer->async_wait (std::bind (&Transports::HandlePeerCleanupTimer, this, std::placeholders::_1)); m_PeerCleanupTimer->async_wait (std::bind (&Transports::HandlePeerCleanupTimer, this, std::placeholders::_1));
} }
} }
void Transports::HandlePeerTestTimer (const boost::system::error_code& ecode) void Transports::HandlePeerTestTimer (const boost::system::error_code& ecode)
@ -728,15 +771,15 @@ namespace transport
PeerTest (); PeerTest ();
m_PeerTestTimer->expires_from_now (boost::posix_time::minutes(PEER_TEST_INTERVAL)); m_PeerTestTimer->expires_from_now (boost::posix_time::minutes(PEER_TEST_INTERVAL));
m_PeerTestTimer->async_wait (std::bind (&Transports::HandlePeerTestTimer, this, std::placeholders::_1)); m_PeerTestTimer->async_wait (std::bind (&Transports::HandlePeerTestTimer, this, std::placeholders::_1));
} }
} }
std::shared_ptr<const i2p::data::RouterInfo> Transports::GetRandomPeer () const std::shared_ptr<const i2p::data::RouterInfo> Transports::GetRandomPeer () const
{ {
if (m_Peers.empty ()) return nullptr; if (m_Peers.empty ()) return nullptr;
std::unique_lock<std::mutex> l(m_PeersMutex); std::unique_lock<std::mutex> l(m_PeersMutex);
auto it = m_Peers.begin (); auto it = m_Peers.begin ();
std::advance (it, rand () % m_Peers.size ()); std::advance (it, rand () % m_Peers.size ());
return it != m_Peers.end () ? it->second.router : nullptr; return it != m_Peers.end () ? it->second.router : nullptr;
} }
void Transports::RestrictRoutesToFamilies(std::set<std::string> families) void Transports::RestrictRoutesToFamilies(std::set<std::string> families)
@ -754,7 +797,7 @@ namespace transport
for (const auto & ri : routers ) for (const auto & ri : routers )
m_TrustedRouters.push_back(ri); m_TrustedRouters.push_back(ri);
} }
bool Transports::RoutesRestricted() const { bool Transports::RoutesRestricted() const {
std::unique_lock<std::mutex> famlock(m_FamilyMutex); std::unique_lock<std::mutex> famlock(m_FamilyMutex);
std::unique_lock<std::mutex> routerslock(m_TrustedRoutersMutex); std::unique_lock<std::mutex> routerslock(m_TrustedRoutersMutex);
@ -814,4 +857,3 @@ namespace transport
} }
} }
} }

44
libi2pd/Transports.h

@ -45,7 +45,7 @@ namespace transport
std::queue<std::shared_ptr<i2p::crypto::DHKeys> > m_Queue; std::queue<std::shared_ptr<i2p::crypto::DHKeys> > m_Queue;
bool m_IsRunning; bool m_IsRunning;
std::thread * m_Thread; std::thread * m_Thread;
std::condition_variable m_Acquired; std::condition_variable m_Acquired;
std::mutex m_AcquiredMutex; std::mutex m_AcquiredMutex;
}; };
@ -62,12 +62,12 @@ namespace transport
{ {
for (auto& it: sessions) for (auto& it: sessions)
it->Done (); it->Done ();
} }
}; };
const size_t SESSION_CREATION_TIMEOUT = 10; // in seconds const size_t SESSION_CREATION_TIMEOUT = 10; // in seconds
const int PEER_TEST_INTERVAL = 71; // in minutes const int PEER_TEST_INTERVAL = 71; // in minutes
const int MAX_NUM_DELAYED_MESSAGES = 50; const int MAX_NUM_DELAYED_MESSAGES = 50;
class Transports class Transports
{ {
public: public:
@ -80,12 +80,12 @@ namespace transport
bool IsBoundNTCP() const { return m_NTCPServer != nullptr; } bool IsBoundNTCP() const { return m_NTCPServer != nullptr; }
bool IsBoundSSU() const { return m_SSUServer != nullptr; } bool IsBoundSSU() const { return m_SSUServer != nullptr; }
bool IsOnline() const { return m_IsOnline; }; bool IsOnline() const { return m_IsOnline; };
void SetOnline (bool online) { m_IsOnline = online; }; void SetOnline (bool online) { m_IsOnline = online; };
boost::asio::io_service& GetService () { return *m_Service; }; boost::asio::io_service& GetService () { return *m_Service; };
std::shared_ptr<i2p::crypto::DHKeys> GetNextDHKeysPair (); std::shared_ptr<i2p::crypto::DHKeys> GetNextDHKeysPair ();
void ReuseDHKeysPair (std::shared_ptr<i2p::crypto::DHKeys> pair); void ReuseDHKeysPair (std::shared_ptr<i2p::crypto::DHKeys> pair);
void SendMessage (const i2p::data::IdentHash& ident, std::shared_ptr<i2p::I2NPMessage> msg); void SendMessage (const i2p::data::IdentHash& ident, std::shared_ptr<i2p::I2NPMessage> msg);
@ -95,7 +95,7 @@ namespace transport
void PeerConnected (std::shared_ptr<TransportSession> session); void PeerConnected (std::shared_ptr<TransportSession> session);
void PeerDisconnected (std::shared_ptr<TransportSession> session); void PeerDisconnected (std::shared_ptr<TransportSession> session);
bool IsConnected (const i2p::data::IdentHash& ident) const; bool IsConnected (const i2p::data::IdentHash& ident) const;
void UpdateSentBytes (uint64_t numBytes) { m_TotalSentBytes += numBytes; }; void UpdateSentBytes (uint64_t numBytes) { m_TotalSentBytes += numBytes; };
void UpdateReceivedBytes (uint64_t numBytes) { m_TotalReceivedBytes += numBytes; }; void UpdateReceivedBytes (uint64_t numBytes) { m_TotalReceivedBytes += numBytes; };
uint64_t GetTotalSentBytes () const { return m_TotalSentBytes; }; uint64_t GetTotalSentBytes () const { return m_TotalSentBytes; };
@ -113,16 +113,16 @@ namespace transport
/** get a trusted first hop for restricted routes */ /** get a trusted first hop for restricted routes */
std::shared_ptr<const i2p::data::RouterInfo> GetRestrictedPeer() const; std::shared_ptr<const i2p::data::RouterInfo> GetRestrictedPeer() const;
/** do we want to use restricted routes? */ /** do we want to use restricted routes? */
bool RoutesRestricted() const; bool RoutesRestricted() const;
/** restrict routes to use only these router families for first hops */ /** restrict routes to use only these router families for first hops */
void RestrictRoutesToFamilies(std::set<std::string> families); void RestrictRoutesToFamilies(std::set<std::string> families);
/** restrict routes to use only these routers for first hops */ /** restrict routes to use only these routers for first hops */
void RestrictRoutesToRouters(std::set<i2p::data::IdentHash> routers); void RestrictRoutesToRouters(std::set<i2p::data::IdentHash> routers);
bool IsRestrictedPeer(const i2p::data::IdentHash & ident) const; bool IsRestrictedPeer(const i2p::data::IdentHash & ident) const;
void PeerTest (); void PeerTest ();
private: private:
void Run (); void Run ();
@ -131,9 +131,9 @@ namespace transport
void PostMessages (i2p::data::IdentHash ident, std::vector<std::shared_ptr<i2p::I2NPMessage> > msgs); void PostMessages (i2p::data::IdentHash ident, std::vector<std::shared_ptr<i2p::I2NPMessage> > msgs);
void PostCloseSession (std::shared_ptr<const i2p::data::RouterInfo> router); void PostCloseSession (std::shared_ptr<const i2p::data::RouterInfo> router);
bool ConnectToPeer (const i2p::data::IdentHash& ident, Peer& peer); bool ConnectToPeer (const i2p::data::IdentHash& ident, Peer& peer);
void HandlePeerCleanupTimer (const boost::system::error_code& ecode); void HandlePeerCleanupTimer (const boost::system::error_code& ecode);
void HandlePeerTestTimer (const boost::system::error_code& ecode); void HandlePeerTestTimer (const boost::system::error_code& ecode);
void NTCPResolve (const std::string& addr, const i2p::data::IdentHash& ident); void NTCPResolve (const std::string& addr, const i2p::data::IdentHash& ident);
void HandleNTCPResolve (const boost::system::error_code& ecode, boost::asio::ip::tcp::resolver::iterator it, void HandleNTCPResolve (const boost::system::error_code& ecode, boost::asio::ip::tcp::resolver::iterator it,
i2p::data::IdentHash ident, std::shared_ptr<boost::asio::ip::tcp::resolver> resolver); i2p::data::IdentHash ident, std::shared_ptr<boost::asio::ip::tcp::resolver> resolver);
@ -143,11 +143,11 @@ namespace transport
void UpdateBandwidth (); void UpdateBandwidth ();
void DetectExternalIP (); void DetectExternalIP ();
private: private:
bool m_IsOnline, m_IsRunning; bool m_IsOnline, m_IsRunning;
std::thread * m_Thread; std::thread * m_Thread;
boost::asio::io_service * m_Service; boost::asio::io_service * m_Service;
boost::asio::io_service::work * m_Work; boost::asio::io_service::work * m_Work;
boost::asio::deadline_timer * m_PeerCleanupTimer, * m_PeerTestTimer; boost::asio::deadline_timer * m_PeerCleanupTimer, * m_PeerTestTimer;
@ -156,13 +156,13 @@ namespace transport
SSUServer * m_SSUServer; SSUServer * m_SSUServer;
mutable std::mutex m_PeersMutex; mutable std::mutex m_PeersMutex;
std::map<i2p::data::IdentHash, Peer> m_Peers; std::map<i2p::data::IdentHash, Peer> m_Peers;
DHKeysPairSupplier m_DHKeysPairSupplier; DHKeysPairSupplier m_DHKeysPairSupplier;
std::atomic<uint64_t> m_TotalSentBytes, m_TotalReceivedBytes, m_TotalTransitTransmittedBytes; std::atomic<uint64_t> m_TotalSentBytes, m_TotalReceivedBytes, m_TotalTransitTransmittedBytes;
uint32_t m_InBandwidth, m_OutBandwidth, m_TransitBandwidth; // bytes per second uint32_t m_InBandwidth, m_OutBandwidth, m_TransitBandwidth; // bytes per second
uint64_t m_LastInBandwidthUpdateBytes, m_LastOutBandwidthUpdateBytes, m_LastTransitBandwidthUpdateBytes; uint64_t m_LastInBandwidthUpdateBytes, m_LastOutBandwidthUpdateBytes, m_LastTransitBandwidthUpdateBytes;
uint64_t m_LastBandwidthUpdateTime; uint64_t m_LastBandwidthUpdateTime;
/** which router families to trust for first hops */ /** which router families to trust for first hops */
std::vector<std::string> m_TrustedFamilies; std::vector<std::string> m_TrustedFamilies;
@ -172,18 +172,18 @@ namespace transport
std::vector<i2p::data::IdentHash> m_TrustedRouters; std::vector<i2p::data::IdentHash> m_TrustedRouters;
mutable std::mutex m_TrustedRoutersMutex; mutable std::mutex m_TrustedRoutersMutex;
i2p::I2NPMessagesHandler m_LoopbackHandler; i2p::I2NPMessagesHandler m_LoopbackHandler;
public: public:
// for HTTP only // for HTTP only
const NTCPServer * GetNTCPServer () const { return m_NTCPServer; }; const NTCPServer * GetNTCPServer () const { return m_NTCPServer; };
const SSUServer * GetSSUServer () const { return m_SSUServer; }; const SSUServer * GetSSUServer () const { return m_SSUServer; };
const decltype(m_Peers)& GetPeers () const { return m_Peers; }; const decltype(m_Peers)& GetPeers () const { return m_Peers; };
}; };
extern Transports transports; extern Transports transports;
} }
} }
#endif #endif

Loading…
Cancel
Save