Browse Source

Merge pull request #563 from PurpleI2P/openssl

recent changes
pull/580/head
orignal 9 years ago committed by GitHub
parent
commit
c79363ef63
  1. 4
      AddressBook.h
  2. 19
      Config.cpp
  3. 108
      Daemon.cpp
  4. 19
      Destination.cpp
  5. 11
      HTTP.cpp
  6. 25
      I2CP.cpp
  7. 3
      I2NPProtocol.cpp
  8. 6
      I2PControl.cpp
  9. 2
      LeaseSet.cpp
  10. 5
      Makefile
  11. 66
      NTCPSession.cpp
  12. 5
      NTCPSession.h
  13. 71
      NetDb.cpp
  14. 17
      NetDb.h
  15. 22
      Reseed.cpp
  16. 6
      RouterInfo.cpp
  17. 3
      RouterInfo.h
  18. 3
      SAM.cpp
  19. 32
      SSU.cpp
  20. 6
      SSU.h
  21. 4
      SSUData.h
  22. 10
      SSUSession.cpp
  23. 112
      Transports.cpp
  24. 16
      Transports.h
  25. 9
      Tunnel.cpp
  26. 2
      Tunnel.h
  27. 4
      TunnelEndpoint.cpp
  28. 6
      TunnelGateway.cpp
  29. 25
      TunnelPool.cpp
  30. 4
      appveyor.yml
  31. 14
      build/CMakeLists.txt
  32. 2
      qt/i2pd_qt/i2pd_qt.pro
  33. 12
      tests/test-http-url.cpp
  34. 47
      util.cpp
  35. 1
      util.h
  36. 5
      version.h

4
AddressBook.h

@ -18,7 +18,11 @@ namespace i2p
{ {
namespace client namespace client
{ {
#ifdef MESHNET
const char DEFAULT_SUBSCRIPTION_ADDRESS[] = "http://i42ofzetmgicvui5sshinfckpijix2udewbam4sjo6x5fbukltia.b32.i2p/hosts.txt";
#else
const char DEFAULT_SUBSCRIPTION_ADDRESS[] = "http://joajgazyztfssty4w2on5oaqksz6tqoxbduy553y34mf4byv6gpq.b32.i2p/export/alive-hosts.txt"; const char DEFAULT_SUBSCRIPTION_ADDRESS[] = "http://joajgazyztfssty4w2on5oaqksz6tqoxbduy553y34mf4byv6gpq.b32.i2p/export/alive-hosts.txt";
#endif
const int INITIAL_SUBSCRIPTION_UPDATE_TIMEOUT = 3; // in minutes const int INITIAL_SUBSCRIPTION_UPDATE_TIMEOUT = 3; // in minutes
const int INITIAL_SUBSCRIPTION_RETRY_TIMEOUT = 1; // in minutes const int INITIAL_SUBSCRIPTION_RETRY_TIMEOUT = 1; // in minutes
const int CONTINIOUS_SUBSCRIPTION_UPDATE_TIMEOUT = 720; // in minutes (12 hours) const int CONTINIOUS_SUBSCRIPTION_UPDATE_TIMEOUT = 720; // in minutes (12 hours)

19
Config.cpp

@ -27,6 +27,10 @@ namespace config {
variables_map m_Options; variables_map m_Options;
void Init() { void Init() {
bool nat = true;
#ifdef MESHNET
nat = false;
#endif
options_description general("General options"); options_description general("General options");
general.add_options() general.add_options()
("help", "Show this message") ("help", "Show this message")
@ -39,6 +43,8 @@ namespace config {
("family", value<std::string>()->default_value(""), "Specify a family, router belongs to") ("family", value<std::string>()->default_value(""), "Specify a family, router belongs to")
("datadir", value<std::string>()->default_value(""), "Path to storage of i2pd data (RI, keys, peer profiles, ...)") ("datadir", value<std::string>()->default_value(""), "Path to storage of i2pd data (RI, keys, peer profiles, ...)")
("host", value<std::string>()->default_value("0.0.0.0"), "External IP") ("host", value<std::string>()->default_value("0.0.0.0"), "External IP")
("ifname", value<std::string>()->default_value(""), "network interface to bind to")
("nat", value<bool>()->zero_tokens()->default_value(nat), "should we assume we are behind NAT?")
("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")
@ -47,6 +53,8 @@ namespace config {
("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")
("floodfill", value<bool>()->zero_tokens()->default_value(false), "Router will be floodfill") ("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 #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")
@ -128,7 +136,13 @@ namespace config {
#endif #endif
"Enable or disable elgamal precomputation table") "Enable or disable elgamal precomputation table")
; ;
options_description trust("Trust options");
trust.add_options()
("trust.enabled", value<bool>()->default_value(false), "enable explicit trust options")
("trust.family", value<std::string>()->default_value(""), "Router Familiy to trust for first hops")
("trust.hidden", value<bool>()->default_value(false), "should we hide our router from other routers?");
m_OptionsDesc m_OptionsDesc
.add(general) .add(general)
.add(limits) .add(limits)
@ -139,7 +153,8 @@ namespace config {
.add(bob) .add(bob)
.add(i2cp) .add(i2cp)
.add(i2pcontrol) .add(i2pcontrol)
.add(precomputation) .add(precomputation)
.add(trust)
; ;
} }

108
Daemon.cpp

@ -22,6 +22,7 @@
#include "I2PControl.h" #include "I2PControl.h"
#include "ClientContext.h" #include "ClientContext.h"
#include "Crypto.h" #include "Crypto.h"
#include "util.h"
#ifdef USE_UPNP #ifdef USE_UPNP
#include "UPnP.h" #include "UPnP.h"
@ -114,7 +115,7 @@ namespace i2p
} }
i2p::log::Logger().Ready(); i2p::log::Logger().Ready();
LogPrint(eLogInfo, "i2pd v", VERSION, " starting"); LogPrint(eLogInfo, "i2pd v", VERSION, " starting");
LogPrint(eLogDebug, "FS: main config file: ", config); LogPrint(eLogDebug, "FS: main config file: ", config);
LogPrint(eLogDebug, "FS: data directory: ", datadir); LogPrint(eLogDebug, "FS: data directory: ", datadir);
@ -122,6 +123,43 @@ namespace i2p
i2p::crypto::InitCrypto (precomputation); i2p::crypto::InitCrypto (precomputation);
i2p::context.Init (); i2p::context.Init ();
bool ipv6; i2p::config::GetOption("ipv6", ipv6);
bool ipv4; i2p::config::GetOption("ipv4", ipv4);
#ifdef MESHNET
// manual override for meshnet
ipv4 = false;
ipv6 = true;
#endif
i2p::context.SetSupportsV6 (ipv6);
i2p::context.SetSupportsV4 (ipv4);
bool nat; i2p::config::GetOption("nat", nat);
if (nat)
{
LogPrint(eLogInfo, "Daemon: assuming be are behind NAT");
// we are behind nat, try setting via host
std::string host; i2p::config::GetOption("host", host);
if (!i2p::config::IsDefault("host"))
{
LogPrint(eLogInfo, "Daemon: setting address for incoming connections to ", host);
i2p::context.UpdateAddress (boost::asio::ip::address::from_string (host));
}
}
else
{
// we are not behind nat
std::string ifname; i2p::config::GetOption("ifname", ifname);
if (ifname.size())
{
// bind to interface, we have no NAT so set external address too
auto addr = i2p::util::net::GetInterfaceAddress(ifname, ipv6);
LogPrint(eLogInfo, "Daemon: bind to network interface ", ifname, " with public address ", addr);
i2p::context.UpdateAddress(addr);
}
}
uint16_t port; i2p::config::GetOption("port", port); uint16_t port; i2p::config::GetOption("port", port);
if (!i2p::config::IsDefault("port")) if (!i2p::config::IsDefault("port"))
{ {
@ -129,15 +167,7 @@ namespace i2p
i2p::context.UpdatePort (port); i2p::context.UpdatePort (port);
} }
std::string host; i2p::config::GetOption("host", host);
if (!i2p::config::IsDefault("host"))
{
LogPrint(eLogInfo, "Daemon: setting address for incoming connections to ", host);
i2p::context.UpdateAddress (boost::asio::ip::address::from_string (host));
}
bool ipv6; i2p::config::GetOption("ipv6", ipv6);
bool ipv4; i2p::config::GetOption("ipv4", ipv4);
bool transit; i2p::config::GetOption("notransit", transit); bool transit; i2p::config::GetOption("notransit", transit);
i2p::context.SetSupportsV6 (ipv6); i2p::context.SetSupportsV6 (ipv6);
i2p::context.SetSupportsV4 (ipv4); i2p::context.SetSupportsV4 (ipv4);
@ -192,31 +222,62 @@ namespace i2p
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);
return true; bool trust; i2p::config::GetOption("trust.enabled", trust);
if (trust)
{
LogPrint(eLogInfo, "Daemon: explicit trust enabled");
std::string fam; i2p::config::GetOption("trust.family", fam);
if (fam.length() > 0)
{
LogPrint(eLogInfo, "Daemon: setting restricted routes to use family ", fam);
i2p::transport::transports.RestrictRoutes({fam});
} else
LogPrint(eLogError, "Daemon: no family specified for restricted routes");
}
bool hidden; i2p::config::GetOption("trust.hidden", hidden);
if (hidden)
{
LogPrint(eLogInfo, "Daemon: using hidden mode");
i2p::data::netdb.SetHidden(true);
}
return true;
} }
bool Daemon_Singleton::start() bool Daemon_Singleton::start()
{ {
bool http; i2p::config::GetOption("http.enabled", http);
if (http) {
std::string httpAddr; i2p::config::GetOption("http.address", httpAddr);
uint16_t httpPort; i2p::config::GetOption("http.port", httpPort);
LogPrint(eLogInfo, "Daemon: starting HTTP Server at ", httpAddr, ":", httpPort);
d.httpServer = std::unique_ptr<i2p::http::HTTPServer>(new i2p::http::HTTPServer(httpAddr, httpPort));
d.httpServer->Start();
}
LogPrint(eLogInfo, "Daemon: starting NetDB"); LogPrint(eLogInfo, "Daemon: starting NetDB");
i2p::data::netdb.Start(); i2p::data::netdb.Start();
#ifdef USE_UPNP #ifdef USE_UPNP
LogPrint(eLogInfo, "Daemon: starting UPnP"); LogPrint(eLogInfo, "Daemon: starting UPnP");
d.m_UPnP.Start (); d.m_UPnP.Start ();
#endif #endif
bool ntcp; i2p::config::GetOption("ntcp", ntcp);
bool ssu; i2p::config::GetOption("ssu", ssu);
LogPrint(eLogInfo, "Daemon: starting Transports"); LogPrint(eLogInfo, "Daemon: starting Transports");
i2p::transport::transports.Start(); if(!ssu) LogPrint(eLogDebug, "Daemon: ssu disabled");
if(!ntcp) LogPrint(eLogDebug, "Daemon: ntcp disabled");
i2p::transport::transports.Start(ntcp, ssu);
if (i2p::transport::transports.IsBoundNTCP() || i2p::transport::transports.IsBoundSSU()) {
LogPrint(eLogInfo, "Daemon: Transports started");
} else {
LogPrint(eLogError, "Daemon: failed to start Transports");
/** shut down netdb right away */
i2p::data::netdb.Stop();
return false;
}
bool http; i2p::config::GetOption("http.enabled", http);
if (http) {
std::string httpAddr; i2p::config::GetOption("http.address", httpAddr);
uint16_t httpPort; i2p::config::GetOption("http.port", httpPort);
LogPrint(eLogInfo, "Daemon: starting HTTP Server at ", httpAddr, ":", httpPort);
d.httpServer = std::unique_ptr<i2p::http::HTTPServer>(new i2p::http::HTTPServer(httpAddr, httpPort));
d.httpServer->Start();
}
LogPrint(eLogInfo, "Daemon: starting Tunnels"); LogPrint(eLogInfo, "Daemon: starting Tunnels");
i2p::tunnel::tunnels.Start(); i2p::tunnel::tunnels.Start();
@ -232,6 +293,7 @@ namespace i2p
d.m_I2PControlService = std::unique_ptr<i2p::client::I2PControlService>(new i2p::client::I2PControlService (i2pcpAddr, i2pcpPort)); d.m_I2PControlService = std::unique_ptr<i2p::client::I2PControlService>(new i2p::client::I2PControlService (i2pcpAddr, i2pcpPort));
d.m_I2PControlService->Start (); d.m_I2PControlService->Start ();
} }
return true; return true;
} }

19
Destination.cpp

@ -378,7 +378,7 @@ namespace client
uint32_t msgID = bufbe32toh (msg->GetPayload () + DELIVERY_STATUS_MSGID_OFFSET); uint32_t msgID = bufbe32toh (msg->GetPayload () + DELIVERY_STATUS_MSGID_OFFSET);
if (msgID == m_PublishReplyToken) if (msgID == m_PublishReplyToken)
{ {
LogPrint (eLogDebug, "Destination: Publishing LeaseSet confirmed"); LogPrint (eLogDebug, "Destination: Publishing LeaseSet confirmed for ", GetIdentHash().ToBase32());
m_ExcludedFloodfills.clear (); m_ExcludedFloodfills.clear ();
m_PublishReplyToken = 0; m_PublishReplyToken = 0;
// schedule verification // schedule verification
@ -459,19 +459,16 @@ namespace client
// "this" added due to bug in gcc 4.7-4.8 // "this" added due to bug in gcc 4.7-4.8
[s,this](std::shared_ptr<i2p::data::LeaseSet> leaseSet) [s,this](std::shared_ptr<i2p::data::LeaseSet> leaseSet)
{ {
if (leaseSet) if (leaseSet && s->m_LeaseSet)
{ {
if (s->m_LeaseSet && *s->m_LeaseSet == *leaseSet) // we got latest LeasetSet
{ LogPrint (eLogDebug, "Destination: published LeaseSet verified for ", GetIdentHash().ToBase32());
// we got latest LeasetSet s->m_PublishVerificationTimer.expires_from_now (boost::posix_time::seconds(PUBLISH_REGULAR_VERIFICATION_INTERNAL));
LogPrint (eLogDebug, "Destination: published LeaseSet verified"); s->m_PublishVerificationTimer.async_wait (std::bind (&LeaseSetDestination::HandlePublishVerificationTimer, s, std::placeholders::_1));
s->m_PublishVerificationTimer.expires_from_now (boost::posix_time::seconds(PUBLISH_REGULAR_VERIFICATION_INTERNAL)); return;
s->m_PublishVerificationTimer.async_wait (std::bind (&LeaseSetDestination::HandlePublishVerificationTimer, s, std::placeholders::_1));
return;
}
} }
else else
LogPrint (eLogWarning, "Destination: couldn't find published LeaseSet"); LogPrint (eLogWarning, "Destination: couldn't find published LeaseSet for ", GetIdentHash().ToBase32());
// we have to publish again // we have to publish again
s->Publish (); s->Publish ();
}); });

11
HTTP.cpp

@ -72,7 +72,8 @@ namespace http {
bool URL::parse(const std::string& url) { bool URL::parse(const std::string& url) {
std::size_t pos_p = 0; /* < current parse position */ std::size_t pos_p = 0; /* < current parse position */
std::size_t pos_c = 0; /* < work position */ std::size_t pos_c = 0; /* < work position */
if (url.at(0) != '/') { if(url.at(0) != '/' || pos_p > 0) {
std::size_t pos_s = 0;
/* schema */ /* schema */
pos_c = url.find("://"); pos_c = url.find("://");
if (pos_c != std::string::npos) { if (pos_c != std::string::npos) {
@ -80,9 +81,9 @@ namespace http {
pos_p = pos_c + 3; pos_p = pos_c + 3;
} }
/* user[:pass] */ /* user[:pass] */
pos_c = url.find('@', pos_p); pos_s = url.find('/', pos_p); /* find first slash */
std::size_t pos_slash = url.find('/', pos_p); pos_c = url.find('@', pos_p); /* find end of 'user' or 'user:pass' part */
if (pos_c != std::string::npos && (pos_slash == std::string::npos || pos_slash > pos_c)) { if (pos_c != std::string::npos && (pos_s == std::string::npos || pos_s > pos_c)) {
std::size_t delim = url.find(':', pos_p); std::size_t delim = url.find(':', pos_p);
if (delim != std::string::npos && delim < pos_c) { if (delim != std::string::npos && delim < pos_c) {
user = url.substr(pos_p, delim - pos_p); user = url.substr(pos_p, delim - pos_p);
@ -91,7 +92,7 @@ namespace http {
} else { } else {
user = url.substr(pos_p, pos_c - pos_p); user = url.substr(pos_p, pos_c - pos_p);
} }
pos_p = pos_c + 1; pos_p = pos_c + 1;
} }
/* hostname[:port][/path] */ /* hostname[:port][/path] */
pos_c = url.find_first_of(":/", pos_p); pos_c = url.find_first_of(":/", pos_p);

25
I2CP.cpp

@ -424,13 +424,24 @@ namespace client
if (m_Destination) if (m_Destination)
{ {
i2p::data::IdentityEx identity; i2p::data::IdentityEx identity;
offset += identity.FromBuffer (buf + offset, len - offset); size_t identsize = identity.FromBuffer (buf + offset, len - offset);
uint32_t payloadLen = bufbe32toh (buf + offset); if (identsize)
offset += 4; {
uint32_t nonce = bufbe32toh (buf + offset + payloadLen); offset += identsize;
if (m_IsSendAccepted) uint32_t payloadLen = bufbe32toh (buf + offset);
SendMessageStatusMessage (nonce, eI2CPMessageStatusAccepted); // accepted if (payloadLen + offset <= len)
m_Destination->SendMsgTo (buf + offset, payloadLen, identity.GetIdentHash (), nonce); {
offset += 4;
uint32_t nonce = bufbe32toh (buf + offset + payloadLen);
if (m_IsSendAccepted)
SendMessageStatusMessage (nonce, eI2CPMessageStatusAccepted); // accepted
m_Destination->SendMsgTo (buf + offset, payloadLen, identity.GetIdentHash (), nonce);
}
else
LogPrint(eLogError, "I2CP: cannot send message, too big");
}
else
LogPrint(eLogError, "I2CP: invalid identity");
} }
} }
else else

3
I2NPProtocol.cpp

@ -11,6 +11,7 @@
#include "Transports.h" #include "Transports.h"
#include "Garlic.h" #include "Garlic.h"
#include "I2NPProtocol.h" #include "I2NPProtocol.h"
#include "version.h"
using namespace i2p::transport; using namespace i2p::transport;
@ -101,7 +102,7 @@ namespace i2p
{ {
RAND_bytes ((uint8_t *)&msgID, 4); RAND_bytes ((uint8_t *)&msgID, 4);
htobe32buf (buf + DELIVERY_STATUS_MSGID_OFFSET, msgID); htobe32buf (buf + DELIVERY_STATUS_MSGID_OFFSET, msgID);
htobe64buf (buf + DELIVERY_STATUS_TIMESTAMP_OFFSET, 2); // netID = 2 htobe64buf (buf + DELIVERY_STATUS_TIMESTAMP_OFFSET, I2PD_NET_ID);
} }
m->len += DELIVERY_STATUS_SIZE; m->len += DELIVERY_STATUS_SIZE;
m->FillI2NPMessageHeader (eI2NPDeliveryStatus); m->FillI2NPMessageHeader (eI2NPDeliveryStatus);

6
I2PControl.cpp

@ -204,17 +204,17 @@ namespace client
return; return;
} }
/* append to json chunk of data from 1st request */ /* append to json chunk of data from 1st request */
json.write(buf->begin() + len, bytes_transferred - len); json.write(buf->data() + len, bytes_transferred - len);
remains = req.content_length() - len; remains = req.content_length() - len;
/* if request has Content-Length header, fetch rest of data and store to json buffer */ /* if request has Content-Length header, fetch rest of data and store to json buffer */
while (remains > 0) { while (remains > 0) {
len = ((long int) buf->size() < remains) ? buf->size() : remains; len = ((long int) buf->size() < remains) ? buf->size() : remains;
bytes_transferred = boost::asio::read (*socket, boost::asio::buffer (buf->data (), len)); bytes_transferred = boost::asio::read (*socket, boost::asio::buffer (buf->data (), len));
json.write(buf->begin(), bytes_transferred); json.write(buf->data(), bytes_transferred);
remains -= bytes_transferred; remains -= bytes_transferred;
} }
} else { } else {
json.write(buf->begin(), bytes_transferred); json.write(buf->data(), bytes_transferred);
} }
LogPrint(eLogDebug, "I2PControl: json from request: ", json.str()); LogPrint(eLogDebug, "I2PControl: json from request: ", json.str());
#if GCC47_BOOST149 #if GCC47_BOOST149

2
LeaseSet.cpp

@ -190,7 +190,7 @@ namespace data
bool LeaseSet::IsExpired () const bool LeaseSet::IsExpired () const
{ {
if (IsEmpty ()) return true; if (m_StoreLeases && IsEmpty ()) return true;
auto ts = i2p::util::GetMillisecondsSinceEpoch (); auto ts = i2p::util::GetMillisecondsSinceEpoch ();
return ts > m_ExpirationTime; return ts > m_ExpirationTime;
} }

5
Makefile

@ -11,6 +11,7 @@ include filelist.mk
USE_AESNI := yes USE_AESNI := yes
USE_STATIC := no USE_STATIC := no
USE_MESHNET := no
USE_UPNP := no USE_UPNP := no
ifeq ($(UNAME),Darwin) ifeq ($(UNAME),Darwin)
@ -31,6 +32,10 @@ else # win32 mingw
include Makefile.mingw include Makefile.mingw
endif endif
ifeq ($(USE_MESHNET),yes)
CXXFLAGS += -DMESHNET
endif
all: mk_obj_dir $(ARLIB) $(ARLIB_CLIENT) $(I2PD) all: mk_obj_dir $(ARLIB) $(ARLIB_CLIENT) $(I2PD)
mk_obj_dir: mk_obj_dir:

66
NTCPSession.cpp

@ -760,30 +760,46 @@ namespace transport
auto& addresses = context.GetRouterInfo ().GetAddresses (); auto& addresses = context.GetRouterInfo ().GetAddresses ();
for (auto address: addresses) for (auto address: addresses)
{ {
if (address->transportStyle == i2p::data::RouterInfo::eTransportNTCP && address->host.is_v4 ()) if (address->transportStyle == i2p::data::RouterInfo::eTransportNTCP)
{ {
m_NTCPAcceptor = new boost::asio::ip::tcp::acceptor (m_Service, if (address->host.is_v4())
boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), address->port));
LogPrint (eLogInfo, "NTCP: Start listening TCP port ", address->port);
auto conn = std::make_shared<NTCPSession>(*this);
m_NTCPAcceptor->async_accept(conn->GetSocket (), std::bind (&NTCPServer::HandleAccept, this,
conn, std::placeholders::_1));
if (context.SupportsV6 ())
{ {
m_NTCPV6Acceptor = new boost::asio::ip::tcp::acceptor (m_Service); try
m_NTCPV6Acceptor->open (boost::asio::ip::tcp::v6()); {
m_NTCPV6Acceptor->set_option (boost::asio::ip::v6_only (true)); m_NTCPAcceptor = new boost::asio::ip::tcp::acceptor (m_Service,
m_NTCPV6Acceptor->bind (boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v6(), address->port)); boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), address->port));
m_NTCPV6Acceptor->listen (); } catch ( std::exception & ex ) {
/** fail to bind ip4 */
LogPrint (eLogInfo, "NTCP: Start listening V6 TCP port ", address->port); LogPrint(eLogError, "NTCP: Failed to bind to ip4 port ",address->port, ex.what());
auto conn = std::make_shared<NTCPSession> (*this); continue;
m_NTCPV6Acceptor->async_accept(conn->GetSocket (), std::bind (&NTCPServer::HandleAcceptV6, }
this, conn, std::placeholders::_1));
LogPrint (eLogInfo, "NTCP: Start listening TCP port ", address->port);
auto conn = std::make_shared<NTCPSession>(*this);
m_NTCPAcceptor->async_accept(conn->GetSocket (), std::bind (&NTCPServer::HandleAccept, this,
conn, std::placeholders::_1));
}
else if (address->host.is_v6() && context.SupportsV6 ())
{
m_NTCPV6Acceptor = new boost::asio::ip::tcp::acceptor (m_Service);
try
{
m_NTCPV6Acceptor->open (boost::asio::ip::tcp::v6());
m_NTCPV6Acceptor->set_option (boost::asio::ip::v6_only (true));
m_NTCPV6Acceptor->bind (boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v6(), address->port));
m_NTCPV6Acceptor->listen ();
LogPrint (eLogInfo, "NTCP: Start listening V6 TCP port ", address->port);
auto conn = std::make_shared<NTCPSession> (*this);
m_NTCPV6Acceptor->async_accept(conn->GetSocket (), std::bind (&NTCPServer::HandleAcceptV6,
this, conn, std::placeholders::_1));
} catch ( std::exception & ex ) {
LogPrint(eLogError, "NTCP: failed to bind to ip6 port ", address->port);
continue;
}
} }
} }
} }
} }
} }
@ -795,9 +811,11 @@ namespace transport
if (m_IsRunning) if (m_IsRunning)
{ {
m_IsRunning = false; m_IsRunning = false;
delete m_NTCPAcceptor; if (m_NTCPAcceptor)
delete m_NTCPAcceptor;
m_NTCPAcceptor = nullptr; m_NTCPAcceptor = nullptr;
delete m_NTCPV6Acceptor; if (m_NTCPV6Acceptor)
delete m_NTCPV6Acceptor;
m_NTCPV6Acceptor = nullptr; m_NTCPV6Acceptor = nullptr;
m_Service.stop (); m_Service.stop ();

5
NTCPSession.h

@ -144,7 +144,10 @@ namespace transport
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 Connect (const boost::asio::ip::address& address, int port, std::shared_ptr<NTCPSession> conn);
bool IsBoundV4() const { return m_NTCPAcceptor != nullptr; };
bool IsBoundV6() const { return m_NTCPV6Acceptor != nullptr; };
boost::asio::io_service& GetService () { return m_Service; }; boost::asio::io_service& GetService () { return m_Service; };
void Ban (const boost::asio::ip::address& addr); void Ban (const boost::asio::ip::address& addr);

71
NetDb.cpp

@ -24,7 +24,7 @@ namespace data
{ {
NetDb netdb; NetDb netdb;
NetDb::NetDb (): m_IsRunning (false), m_Thread (nullptr), m_Reseeder (nullptr), m_Storage("netDb", "r", "routerInfo-", "dat") NetDb::NetDb (): m_IsRunning (false), m_Thread (nullptr), m_Reseeder (nullptr), m_Storage("netDb", "r", "routerInfo-", "dat"), m_HiddenMode(false)
{ {
} }
@ -67,7 +67,7 @@ namespace data
} }
m_LeaseSets.clear(); m_LeaseSets.clear();
m_Requests.Stop (); m_Requests.Stop ();
} }
} }
void NetDb::Run () void NetDb::Run ()
@ -121,8 +121,12 @@ namespace data
ManageLookupResponses (); ManageLookupResponses ();
} }
lastSave = ts; lastSave = ts;
} }
if (ts - lastPublish >= 2400) // publish every 40 minutes
// if we're in hidden mode don't publish or explore
// if (m_HiddenMode) continue;
if (ts - lastPublish >= NETDB_PUBLISH_INTERVAL) // publish
{ {
Publish (); Publish ();
lastPublish = ts; lastPublish = ts;
@ -161,6 +165,11 @@ namespace data
return false; return false;
} }
void NetDb::SetHidden(bool hide) {
// TODO: remove reachable addresses from router info
m_HiddenMode = hide;
}
bool NetDb::AddRouterInfo (const IdentHash& ident, const uint8_t * buf, int len) bool NetDb::AddRouterInfo (const IdentHash& ident, const uint8_t * buf, int len)
{ {
bool updated = true; bool updated = true;
@ -174,10 +183,8 @@ namespace data
// TODO: check if floodfill has been changed // TODO: check if floodfill has been changed
} }
else else
{
LogPrint (eLogDebug, "NetDb: RouterInfo is older: ", ident.ToBase64()); LogPrint (eLogDebug, "NetDb: RouterInfo is older: ", ident.ToBase64());
updated = false;
}
} }
else else
{ {
@ -217,29 +224,29 @@ namespace data
it->second->Update (buf, len); it->second->Update (buf, len);
if (it->second->IsValid ()) if (it->second->IsValid ())
{ {
LogPrint (eLogInfo, "NetDb: LeaseSet updated: ", ident.ToBase64()); LogPrint (eLogInfo, "NetDb: LeaseSet updated: ", ident.ToBase32());
updated = true; updated = true;
} }
else else
{ {
LogPrint (eLogWarning, "NetDb: LeaseSet update failed: ", ident.ToBase64()); LogPrint (eLogWarning, "NetDb: LeaseSet update failed: ", ident.ToBase32());
m_LeaseSets.erase (it); m_LeaseSets.erase (it);
} }
} }
else else
LogPrint (eLogDebug, "NetDb: LeaseSet is older: ", ident.ToBase64()); LogPrint (eLogDebug, "NetDb: LeaseSet is older: ", ident.ToBase32());
} }
else else
{ {
auto leaseSet = std::make_shared<LeaseSet> (buf, len, false); // we don't need leases in netdb auto leaseSet = std::make_shared<LeaseSet> (buf, len, false); // we don't need leases in netdb
if (leaseSet->IsValid ()) if (leaseSet->IsValid ())
{ {
LogPrint (eLogInfo, "NetDb: LeaseSet added: ", ident.ToBase64()); LogPrint (eLogInfo, "NetDb: LeaseSet added: ", ident.ToBase32());
m_LeaseSets[ident] = leaseSet; m_LeaseSets[ident] = leaseSet;
updated = true; updated = true;
} }
else else
LogPrint (eLogError, "NetDb: new LeaseSet validation failed: ", ident.ToBase64()); LogPrint (eLogError, "NetDb: new LeaseSet validation failed: ", ident.ToBase32());
} }
} }
return updated; return updated;
@ -461,7 +468,7 @@ namespace data
bool updated = false; bool updated = false;
if (buf[DATABASE_STORE_TYPE_OFFSET]) // type if (buf[DATABASE_STORE_TYPE_OFFSET]) // type
{ {
LogPrint (eLogDebug, "NetDb: store request: LeaseSet"); LogPrint (eLogDebug, "NetDb: store request: LeaseSet for ", ident.ToBase32());
updated = AddLeaseSet (ident, buf + offset, len - offset, m->from); updated = AddLeaseSet (ident, buf + offset, len - offset, m->from);
} }
else else
@ -487,7 +494,7 @@ namespace data
uint8_t * payload = floodMsg->GetPayload (); uint8_t * payload = floodMsg->GetPayload ();
memcpy (payload, buf, 33); // key + type memcpy (payload, buf, 33); // key + type
htobe32buf (payload + DATABASE_STORE_REPLY_TOKEN_OFFSET, 0); // zero reply token htobe32buf (payload + DATABASE_STORE_REPLY_TOKEN_OFFSET, 0); // zero reply token
auto msgLen = len - payloadOffset; size_t msgLen = len - payloadOffset;
floodMsg->len += DATABASE_STORE_HEADER_SIZE + msgLen; floodMsg->len += DATABASE_STORE_HEADER_SIZE + msgLen;
if (floodMsg->len < floodMsg->maxLen) if (floodMsg->len < floodMsg->maxLen)
{ {
@ -501,16 +508,18 @@ namespace data
auto floodfill = GetClosestFloodfill (ident, excluded); auto floodfill = GetClosestFloodfill (ident, excluded);
if (floodfill) if (floodfill)
{ {
transports.SendMessage (floodfill->GetIdentHash (), CopyI2NPMessage(floodMsg)); auto h = floodfill->GetIdentHash();
excluded.insert (floodfill->GetIdentHash ()); LogPrint(eLogDebug, "NetDb: Flood lease set for ", ident.ToBase32(), " to ", h.ToBase64());
transports.SendMessage (h, CopyI2NPMessage(floodMsg));
excluded.insert (h);
} }
else else
break; break;
} }
} }
else else
LogPrint (eLogError, "Database store message is too long ", floodMsg->len); LogPrint (eLogError, "NetDb: Database store message is too long ", floodMsg->len);
} }
} }
void NetDb::HandleDatabaseSearchReplyMsg (std::shared_ptr<const I2NPMessage> msg) void NetDb::HandleDatabaseSearchReplyMsg (std::shared_ptr<const I2NPMessage> msg)
@ -615,6 +624,9 @@ namespace data
int l = i2p::data::ByteStreamToBase64 (buf, 32, key, 48); int l = i2p::data::ByteStreamToBase64 (buf, 32, key, 48);
key[l] = 0; key[l] = 0;
uint8_t flag = buf[64]; uint8_t flag = buf[64];
IdentHash replyIdent(buf + 32);
LogPrint (eLogDebug, "NetDb: DatabaseLookup for ", key, " recieved flags=", (int)flag); LogPrint (eLogDebug, "NetDb: DatabaseLookup for ", key, " recieved flags=", (int)flag);
uint8_t lookupType = flag & DATABASE_LOOKUP_TYPE_FLAGS_MASK; uint8_t lookupType = flag & DATABASE_LOOKUP_TYPE_FLAGS_MASK;
const uint8_t * excluded = buf + 65; const uint8_t * excluded = buf + 65;
@ -673,7 +685,12 @@ namespace data
lookupType == DATABASE_LOOKUP_TYPE_NORMAL_LOOKUP)) lookupType == DATABASE_LOOKUP_TYPE_NORMAL_LOOKUP))
{ {
auto leaseSet = FindLeaseSet (ident); auto leaseSet = FindLeaseSet (ident);
if (leaseSet && !leaseSet->IsExpired ()) // we don't send back our LeaseSets if (!leaseSet)
{
// no lease set found
LogPrint(eLogDebug, "NetDb: requested LeaseSet not found for ", ident.ToBase32());
}
else if (!leaseSet->IsExpired ()) // we don't send back our LeaseSets
{ {
LogPrint (eLogDebug, "NetDb: requested LeaseSet ", key, " found"); LogPrint (eLogDebug, "NetDb: requested LeaseSet ", key, " found");
replyMsg = CreateDatabaseStoreMsg (leaseSet); replyMsg = CreateDatabaseStoreMsg (leaseSet);
@ -730,12 +747,12 @@ namespace data
auto exploratoryPool = i2p::tunnel::tunnels.GetExploratoryPool (); auto exploratoryPool = i2p::tunnel::tunnels.GetExploratoryPool ();
auto outbound = exploratoryPool ? exploratoryPool->GetNextOutboundTunnel () : nullptr; auto outbound = exploratoryPool ? exploratoryPool->GetNextOutboundTunnel () : nullptr;
if (outbound) if (outbound)
outbound->SendTunnelDataMsg (buf+32, replyTunnelID, replyMsg); outbound->SendTunnelDataMsg (replyIdent, replyTunnelID, replyMsg);
else else
transports.SendMessage (buf+32, i2p::CreateTunnelGatewayMsg (replyTunnelID, replyMsg)); transports.SendMessage (replyIdent, i2p::CreateTunnelGatewayMsg (replyTunnelID, replyMsg));
} }
else else
transports.SendMessage (buf+32, replyMsg); transports.SendMessage (replyIdent, replyMsg);
} }
} }
@ -862,7 +879,7 @@ namespace data
{ {
if (m_RouterInfos.empty()) if (m_RouterInfos.empty())
return 0; return 0;
uint32_t ind = rand () % m_RouterInfos.size (); uint32_t ind = rand () % m_RouterInfos.size ();
for (int j = 0; j < 2; j++) for (int j = 0; j < 2; j++)
{ {
uint32_t i = 0; uint32_t i = 0;
@ -966,6 +983,14 @@ namespace data
return res; return res;
} }
std::shared_ptr<const RouterInfo> NetDb::GetRandomRouterInFamily(const std::string & fam) const {
return GetRandomRouter(
[fam](std::shared_ptr<const RouterInfo> router)->bool
{
return router->IsFamily(fam);
});
}
std::shared_ptr<const RouterInfo> NetDb::GetClosestNonFloodfill (const IdentHash& destination, std::shared_ptr<const RouterInfo> NetDb::GetClosestNonFloodfill (const IdentHash& destination,
const std::set<IdentHash>& excluded) const const std::set<IdentHash>& excluded) const
{ {

17
NetDb.h

@ -31,6 +31,12 @@ namespace data
const int NETDB_INTRODUCEE_EXPIRATION_TIMEOUT = 65*60; const int NETDB_INTRODUCEE_EXPIRATION_TIMEOUT = 65*60;
const int NETDB_MIN_EXPIRATION_TIMEOUT = 90*60; // 1.5 hours const int NETDB_MIN_EXPIRATION_TIMEOUT = 90*60; // 1.5 hours
const int NETDB_MAX_EXPIRATION_TIMEOUT = 27*60*60; // 27 hours const int NETDB_MAX_EXPIRATION_TIMEOUT = 27*60*60; // 27 hours
#ifdef MESHNET
const int NETDB_PUBLISH_INTERVAL = 60;
#else
const int NETDB_PUBLISH_INTERVAL = 60*40;
#endif
class NetDb class NetDb
{ {
@ -64,10 +70,14 @@ namespace data
std::vector<IdentHash> GetClosestFloodfills (const IdentHash& destination, size_t num, std::vector<IdentHash> GetClosestFloodfills (const IdentHash& destination, size_t num,
std::set<IdentHash>& excluded, bool closeThanUsOnly = false) const; std::set<IdentHash>& excluded, bool closeThanUsOnly = false) const;
std::shared_ptr<const RouterInfo> GetClosestNonFloodfill (const IdentHash& destination, const std::set<IdentHash>& excluded) const; std::shared_ptr<const RouterInfo> GetClosestNonFloodfill (const IdentHash& destination, const std::set<IdentHash>& excluded) const;
std::shared_ptr<const RouterInfo> GetRandomRouterInFamily(const std::string & fam) const;
void SetUnreachable (const IdentHash& ident, bool unreachable); void SetUnreachable (const IdentHash& ident, bool unreachable);
void PostI2NPMsg (std::shared_ptr<const I2NPMessage> msg); void PostI2NPMsg (std::shared_ptr<const I2NPMessage> msg);
/** set hidden mode, aka don't publish our RI to netdb and don't explore */
void SetHidden(bool hide);
void Reseed (); void Reseed ();
Families& GetFamilies () { return m_Families; }; Families& GetFamilies () { return m_Families; };
@ -88,8 +98,8 @@ namespace data
void ManageRequests (); void ManageRequests ();
void ManageLookupResponses (); void ManageLookupResponses ();
template<typename Filter> template<typename Filter>
std::shared_ptr<const RouterInfo> GetRandomRouter (Filter filter) const; std::shared_ptr<const RouterInfo> GetRandomRouter (Filter filter) const;
private: private:
@ -113,6 +123,9 @@ namespace data
NetDbRequests m_Requests; NetDbRequests m_Requests;
std::map<IdentHash, std::pair<std::vector<IdentHash>, uint64_t> > m_LookupResponses; // ident->(closest FFs, timestamp) std::map<IdentHash, std::pair<std::vector<IdentHash>, uint64_t> > m_LookupResponses; // ident->(closest FFs, timestamp)
/** true if in hidden mode */
bool m_HiddenMode;
}; };
extern NetDb netdb; extern NetDb netdb;

22
Reseed.cpp

@ -20,20 +20,26 @@ namespace i2p
{ {
namespace data namespace data
{ {
static std::vector<std::string> httpsReseedHostList = static std::vector<std::string> httpsReseedHostList =
{ {
#ifdef MESHNET
// meshnet i2p reseeds
"https://reseed.i2p.rocks:8443/"
#else
// mainline i2p reseeds
"https://reseed.i2p-projekt.de/", // Only HTTPS "https://reseed.i2p-projekt.de/", // Only HTTPS
"https://i2p.mooo.com/netDb/", "https://i2p.mooo.com/netDb/",
"https://netdb.i2p2.no/", // Only SU3 (v3) support, SNI required "https://netdb.i2p2.no/", // Only SU3 (v3) support, SNI required
"https://us.reseed.i2p2.no:444/", "https://us.reseed.i2p2.no:444/",
"https://uk.reseed.i2p2.no:444/", "https://uk.reseed.i2p2.no:444/",
"https://i2p.manas.ca:8443/", "https://i2p.manas.ca:8443/",
"https://i2p-0.manas.ca:8443/", "https://i2p-0.manas.ca:8443/",
"https://reseed.i2p.vzaws.com:8443/", // Only SU3 (v3) support "https://reseed.i2p.vzaws.com:8443/", // Only SU3 (v3) support
"https://user.mx24.eu/", // Only HTTPS and SU3 (v3) support "https://user.mx24.eu/", // Only HTTPS and SU3 (v3) support
"https://download.xxlspeed.com/" // Only HTTPS and SU3 (v3) support "https://download.xxlspeed.com/" // Only HTTPS and SU3 (v3) support
#endif
}; };
Reseeder::Reseeder() Reseeder::Reseeder()
{ {
} }

6
RouterInfo.cpp

@ -290,7 +290,11 @@ namespace data
if (!m_SupportedTransports || !m_Addresses.size() || (UsesIntroducer () && !introducers)) if (!m_SupportedTransports || !m_Addresses.size() || (UsesIntroducer () && !introducers))
SetUnreachable (true); SetUnreachable (true);
} }
bool RouterInfo::IsFamily(const std::string & fam) const {
return m_Family == fam;
}
void RouterInfo::ExtractCaps (const char * value) void RouterInfo::ExtractCaps (const char * value)
{ {

3
RouterInfo.h

@ -171,6 +171,9 @@ namespace data
void DeleteBuffer () { delete[] m_Buffer; m_Buffer = nullptr; }; void DeleteBuffer () { delete[] m_Buffer; m_Buffer = nullptr; };
bool IsNewer (const uint8_t * buf, size_t len) const; bool IsNewer (const uint8_t * buf, size_t len) const;
/** return true if we are in a router family and the signature is valid */
bool IsFamily(const std::string & fam) const;
// implements RoutingDestination // implements RoutingDestination
const IdentHash& GetIdentHash () const { return m_RouterIdentity->GetIdentHash (); }; const IdentHash& GetIdentHash () const { return m_RouterIdentity->GetIdentHash (); };
const uint8_t * GetEncryptionPublicKey () const { return m_RouterIdentity->GetStandardIdentity ().publicKey; }; const uint8_t * GetEncryptionPublicKey () const { return m_RouterIdentity->GetStandardIdentity ().publicKey; };

3
SAM.cpp

@ -56,7 +56,8 @@ namespace client
if (m_Session) if (m_Session)
{ {
m_Session->DelSocket (shared_from_this ()); m_Session->DelSocket (shared_from_this ());
m_Session->localDestination->StopAcceptingStreams (); if (m_Session->localDestination)
m_Session->localDestination->StopAcceptingStreams ();
} }
break; break;
} }

32
SSU.cpp

@ -10,12 +10,31 @@ namespace i2p
{ {
namespace transport namespace transport
{ {
SSUServer::SSUServer (int port): m_Thread (nullptr), m_ThreadV6 (nullptr), m_ReceiversThread (nullptr),
SSUServer::SSUServer (const boost::asio::ip::address & addr, int port):
m_OnlyV6(true), m_IsRunning(false),
m_Thread (nullptr), m_ThreadV6 (nullptr), m_ReceiversThread (nullptr),
m_Work (m_Service), m_WorkV6 (m_ServiceV6), m_ReceiversWork (m_ReceiversService),
m_EndpointV6 (addr, port),
m_Socket (m_ReceiversService, m_Endpoint), m_SocketV6 (m_ReceiversService),
m_IntroducersUpdateTimer (m_Service), m_PeerTestsCleanupTimer (m_Service)
{
m_SocketV6.open (boost::asio::ip::udp::v6());
m_SocketV6.set_option (boost::asio::ip::v6_only (true));
m_SocketV6.set_option (boost::asio::socket_base::receive_buffer_size (65535));
m_SocketV6.set_option (boost::asio::socket_base::send_buffer_size (65535));
m_SocketV6.bind (m_EndpointV6);
}
SSUServer::SSUServer (int port):
m_OnlyV6(false), m_IsRunning(false),
m_Thread (nullptr), m_ThreadV6 (nullptr), m_ReceiversThread (nullptr),
m_Work (m_Service), m_WorkV6 (m_ServiceV6), m_ReceiversWork (m_ReceiversService), m_Work (m_Service), m_WorkV6 (m_ServiceV6), m_ReceiversWork (m_ReceiversService),
m_Endpoint (boost::asio::ip::udp::v4 (), port), m_EndpointV6 (boost::asio::ip::udp::v6 (), port), m_Endpoint (boost::asio::ip::udp::v4 (), port), m_EndpointV6 (boost::asio::ip::udp::v6 (), port),
m_Socket (m_ReceiversService, m_Endpoint), m_SocketV6 (m_ReceiversService), m_Socket (m_ReceiversService, m_Endpoint), m_SocketV6 (m_ReceiversService),
m_IntroducersUpdateTimer (m_Service), m_PeerTestsCleanupTimer (m_Service) m_IntroducersUpdateTimer (m_Service), m_PeerTestsCleanupTimer (m_Service)
{ {
m_Socket.set_option (boost::asio::socket_base::receive_buffer_size (65535)); m_Socket.set_option (boost::asio::socket_base::receive_buffer_size (65535));
m_Socket.set_option (boost::asio::socket_base::send_buffer_size (65535)); m_Socket.set_option (boost::asio::socket_base::send_buffer_size (65535));
if (context.SupportsV6 ()) if (context.SupportsV6 ())
@ -35,13 +54,16 @@ namespace transport
void SSUServer::Start () void SSUServer::Start ()
{ {
m_IsRunning = true; m_IsRunning = true;
m_ReceiversThread = new std::thread (std::bind (&SSUServer::RunReceivers, this)); m_ReceiversThread = new std::thread (std::bind (&SSUServer::RunReceivers, this));
m_Thread = new std::thread (std::bind (&SSUServer::Run, this)); if (!m_OnlyV6)
m_ReceiversService.post (std::bind (&SSUServer::Receive, this)); {
m_Thread = new std::thread (std::bind (&SSUServer::Run, this));
m_ReceiversService.post (std::bind (&SSUServer::Receive, this));
}
if (context.SupportsV6 ()) if (context.SupportsV6 ())
{ {
m_ThreadV6 = new std::thread (std::bind (&SSUServer::RunV6, this)); m_ThreadV6 = new std::thread (std::bind (&SSUServer::RunV6, this));
m_ReceiversService.post (std::bind (&SSUServer::ReceiveV6, this)); m_ReceiversService.post (std::bind (&SSUServer::ReceiveV6, this));
} }
SchedulePeerTestsCleanupTimer (); SchedulePeerTestsCleanupTimer ();
ScheduleIntroducersUpdateTimer (); // wait for 30 seconds and decide if we need introducers ScheduleIntroducersUpdateTimer (); // wait for 30 seconds and decide if we need introducers

6
SSU.h

@ -37,6 +37,7 @@ namespace transport
public: public:
SSUServer (int port); SSUServer (int port);
SSUServer (const boost::asio::ip::address & addr, int port); // ipv6 only constructor
~SSUServer (); ~SSUServer ();
void Start (); void Start ();
void Stop (); void Stop ();
@ -62,7 +63,7 @@ namespace transport
std::shared_ptr<SSUSession> GetPeerTestSession (uint32_t nonce); std::shared_ptr<SSUSession> GetPeerTestSession (uint32_t nonce);
void UpdatePeerTest (uint32_t nonce, PeerTestParticipant role); void UpdatePeerTest (uint32_t nonce, PeerTestParticipant role);
void RemovePeerTest (uint32_t nonce); void RemovePeerTest (uint32_t nonce);
private: private:
void Run (); void Run ();
@ -93,8 +94,9 @@ namespace transport
uint64_t creationTime; uint64_t creationTime;
PeerTestParticipant role; PeerTestParticipant role;
std::shared_ptr<SSUSession> session; // for Bob to Alice std::shared_ptr<SSUSession> session; // for Bob to Alice
}; };
bool m_OnlyV6;
bool m_IsRunning; bool m_IsRunning;
std::thread * m_Thread, * m_ThreadV6, * m_ReceiversThread; std::thread * m_Thread, * m_ThreadV6, * m_ReceiversThread;
boost::asio::io_service m_Service, m_ServiceV6, m_ReceiversService; boost::asio::io_service m_Service, m_ServiceV6, m_ReceiversService;

4
SSUData.h

@ -18,7 +18,11 @@ namespace transport
{ {
const size_t SSU_MTU_V4 = 1484; const size_t SSU_MTU_V4 = 1484;
#ifdef MESHNET
const size_t SSU_MTU_V6 = 1286;
#else
const size_t SSU_MTU_V6 = 1472; const size_t SSU_MTU_V6 = 1472;
#endif
const size_t IPV4_HEADER_SIZE = 20; const size_t IPV4_HEADER_SIZE = 20;
const size_t IPV6_HEADER_SIZE = 40; const size_t IPV6_HEADER_SIZE = 40;
const size_t UDP_HEADER_SIZE = 8; const size_t UDP_HEADER_SIZE = 8;

10
SSUSession.cpp

@ -20,14 +20,14 @@ namespace transport
if (router) if (router)
{ {
// we are client // we are client
auto address = router->GetSSUAddress (); auto address = router->GetSSUAddress (false);
if (address) m_IntroKey = address->key; if (address) m_IntroKey = address->key;
m_Data.AdjustPacketSize (router); // mtu m_Data.AdjustPacketSize (router); // mtu
} }
else else
{ {
// we are server // we are server
auto address = i2p::context.GetRouterInfo ().GetSSUAddress (); auto address = i2p::context.GetRouterInfo ().GetSSUAddress (false);
if (address) m_IntroKey = address->key; if (address) m_IntroKey = address->key;
} }
m_CreationTime = i2p::util::GetSecondsSinceEpoch (); m_CreationTime = i2p::util::GetSecondsSinceEpoch ();
@ -108,7 +108,7 @@ namespace transport
else else
{ {
// try own intro key // try own intro key
auto address = i2p::context.GetRouterInfo ().GetSSUAddress (); auto address = i2p::context.GetRouterInfo ().GetSSUAddress (false);
if (!address) if (!address)
{ {
LogPrint (eLogInfo, "SSU is not supported"); LogPrint (eLogInfo, "SSU is not supported");
@ -366,7 +366,7 @@ namespace transport
void SSUSession::SendRelayRequest (const i2p::data::RouterInfo::Introducer& introducer, uint32_t nonce) void SSUSession::SendRelayRequest (const i2p::data::RouterInfo::Introducer& introducer, uint32_t nonce)
{ {
auto address = i2p::context.GetRouterInfo ().GetSSUAddress (); auto address = i2p::context.GetRouterInfo ().GetSSUAddress (false);
if (!address) if (!address)
{ {
LogPrint (eLogInfo, "SSU is not supported"); LogPrint (eLogInfo, "SSU is not supported");
@ -1079,7 +1079,7 @@ namespace transport
{ {
// we are Alice // we are Alice
LogPrint (eLogDebug, "SSU: sending peer test"); LogPrint (eLogDebug, "SSU: sending peer test");
auto address = i2p::context.GetRouterInfo ().GetSSUAddress (); auto address = i2p::context.GetRouterInfo ().GetSSUAddress (false);
if (!address) if (!address)
{ {
LogPrint (eLogInfo, "SSU is not supported. Can't send peer test"); LogPrint (eLogInfo, "SSU is not supported. Can't send peer test");

112
Transports.cpp

@ -46,7 +46,7 @@ namespace transport
int num; int num;
while ((num = m_QueueSize - m_Queue.size ()) > 0) while ((num = m_QueueSize - m_Queue.size ()) > 0)
CreateDHKeysPairs (num); CreateDHKeysPairs (num);
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
} }
} }
@ -60,7 +60,7 @@ namespace transport
{ {
auto pair = std::make_shared<i2p::crypto::DHKeys> (); auto pair = std::make_shared<i2p::crypto::DHKeys> ();
pair->GenerateKeys (); pair->GenerateKeys ();
std::unique_lock<std::mutex> l(m_AcquiredMutex); std::unique_lock<std::mutex> l(m_AcquiredMutex);
m_Queue.push (pair); m_Queue.push (pair);
} }
} }
@ -69,7 +69,7 @@ namespace transport
std::shared_ptr<i2p::crypto::DHKeys> DHKeysPairSupplier::Acquire () std::shared_ptr<i2p::crypto::DHKeys> DHKeysPairSupplier::Acquire ()
{ {
{ {
std::unique_lock<std::mutex> l(m_AcquiredMutex); std::unique_lock<std::mutex> l(m_AcquiredMutex);
if (!m_Queue.empty ()) if (!m_Queue.empty ())
{ {
auto pair = m_Queue.front (); auto pair = m_Queue.front ();
@ -86,7 +86,7 @@ namespace transport
void DHKeysPairSupplier::Return (std::shared_ptr<i2p::crypto::DHKeys> pair) void DHKeysPairSupplier::Return (std::shared_ptr<i2p::crypto::DHKeys> pair)
{ {
std::unique_lock<std::mutex> l(m_AcquiredMutex); std::unique_lock<std::mutex> l(m_AcquiredMutex);
m_Queue.push (pair); m_Queue.push (pair);
} }
@ -105,7 +105,7 @@ namespace transport
Stop (); Stop ();
} }
void Transports::Start () void Transports::Start (bool enableNTCP, bool enableSSU)
{ {
m_DHKeysPairSupplier.Start (); m_DHKeysPairSupplier.Start ();
m_IsRunning = true; m_IsRunning = true;
@ -114,19 +114,36 @@ namespace transport
auto& addresses = context.GetRouterInfo ().GetAddresses (); auto& addresses = context.GetRouterInfo ().GetAddresses ();
for (auto address : addresses) for (auto address : addresses)
{ {
if (!m_NTCPServer) if (!m_NTCPServer && enableNTCP)
{ {
m_NTCPServer = new NTCPServer (); m_NTCPServer = new NTCPServer ();
m_NTCPServer->Start (); m_NTCPServer->Start ();
if (!(m_NTCPServer->IsBoundV6() || m_NTCPServer->IsBoundV4())) {
/** failed to bind to NTCP */
LogPrint(eLogError, "Transports: failed to bind to TCP");
m_NTCPServer->Stop();
delete m_NTCPServer;
m_NTCPServer = nullptr;
}
} }
if (address->transportStyle == RouterInfo::eTransportSSU && address->host.is_v4 ()) if (address->transportStyle == RouterInfo::eTransportSSU)
{ {
if (!m_SSUServer) if (!m_SSUServer && enableSSU)
{ {
m_SSUServer = new SSUServer (address->port); if (address->host.is_v4())
m_SSUServer = new SSUServer (address->port);
else
m_SSUServer = new SSUServer (address->host, address->port);
LogPrint (eLogInfo, "Transports: Start listening UDP port ", address->port); LogPrint (eLogInfo, "Transports: Start listening UDP port ", address->port);
m_SSUServer->Start (); try {
m_SSUServer->Start ();
} catch ( std::exception & ex ) {
LogPrint(eLogError, "Transports: Failed to bind to UDP port", address->port);
delete m_SSUServer;
m_SSUServer = nullptr;
continue;
}
DetectExternalIP (); DetectExternalIP ();
} }
else else
@ -206,7 +223,7 @@ namespace transport
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)
@ -231,7 +248,7 @@ namespace transport
{ {
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;
} }
@ -288,7 +305,7 @@ namespace transport
} }
} }
else else
LogPrint (eLogWarning, "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");
} }
if (peer.numAttempts == 1)// SSU if (peer.numAttempts == 1)// SSU
{ {
@ -320,7 +337,7 @@ namespace transport
} }
LogPrint (eLogError, "Transports: No NTCP or SSU addresses available"); LogPrint (eLogError, "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;
} }
@ -352,7 +369,7 @@ namespace transport
else else
{ {
LogPrint (eLogError, "Transports: RouterInfo not found, Failed to send messages"); LogPrint (eLogError, "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);
} }
} }
@ -396,7 +413,7 @@ namespace transport
} }
} }
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);
} }
} }
@ -438,7 +455,7 @@ namespace transport
} }
} }
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);
} }
} }
@ -446,7 +463,7 @@ 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)
@ -469,18 +486,21 @@ namespace transport
{ {
if (m_SSUServer) if (m_SSUServer)
{ {
#ifndef MESHNET
i2p::context.SetStatus (eRouterStatusTesting); i2p::context.SetStatus (eRouterStatusTesting);
#endif
for (int i = 0; i < 5; i++) for (int i = 0; i < 5; i++)
{ {
auto router = i2p::data::netdb.GetRandomPeerTestRouter (); auto router = i2p::data::netdb.GetRandomPeerTestRouter ();
if (router && router->IsSSU (!context.SupportsV6 ())) if (router && router->IsSSU (!context.SupportsV6 ()))
m_SSUServer->CreateSession (router, true); // peer test m_SSUServer->CreateSession (router, true); // peer test
else else
{ {
// if not peer test capable routers found pick any // if not peer test capable routers found pick any
router = i2p::data::netdb.GetRandomRouter (); router = i2p::data::netdb.GetRandomRouter ();
if (router && router->IsSSU ()) if (router && router->IsSSU ())
m_SSUServer->CreateSession (router); // no peer test m_SSUServer->CreateSession (router); // no peer test
} }
} }
} }
@ -503,7 +523,7 @@ namespace transport
statusChanged = true; statusChanged = true;
i2p::context.SetStatus (eRouterStatusTesting); // first time only i2p::context.SetStatus (eRouterStatusTesting); // first time only
} }
m_SSUServer->CreateSession (router, true); // peer test m_SSUServer->CreateSession (router, true); // peer test
} }
} }
} }
@ -522,7 +542,7 @@ 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 ();
@ -535,7 +555,7 @@ namespace transport
// check if first message is our DatabaseStore (publishing) // check if first message is our DatabaseStore (publishing)
auto firstMsg = it->second.delayedMessages[0]; auto firstMsg = it->second.delayedMessages[0];
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)
@ -547,7 +567,7 @@ namespace transport
else // incoming connection else // incoming connection
{ {
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 (), {} }));
} }
}); });
@ -556,7 +576,7 @@ namespace transport
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 ();
@ -570,7 +590,7 @@ namespace transport
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);
} }
} }
@ -595,14 +615,20 @@ namespace transport
if (it->second.sessions.empty () && ts > it->second.creationTime + SESSION_CREATION_TIMEOUT) if (it->second.sessions.empty () && ts > it->second.creationTime + SESSION_CREATION_TIMEOUT)
{ {
LogPrint (eLogWarning, "Transports: Session to peer ", it->first.ToBase64 (), " has not been created in ", SESSION_CREATION_TIMEOUT, " seconds"); LogPrint (eLogWarning, "Transports: Session to peer ", it->first.ToBase64 (), " has not been created in ", SESSION_CREATION_TIMEOUT, " seconds");
std::unique_lock<std::mutex> l(m_PeersMutex); auto profile = i2p::data::GetRouterProfile(it->first);
if (profile)
{
profile->TunnelNonReplied();
profile->Save();
}
std::unique_lock<std::mutex> l(m_PeersMutex);
it = m_Peers.erase (it); it = m_Peers.erase (it);
} }
else else
it++; it++;
} }
UpdateBandwidth (); // TODO: use separate timer(s) for it UpdateBandwidth (); // TODO: use separate timer(s) for it
if (i2p::context.GetStatus () == eRouterStatusTesting) // if still testing, repeat peer test if (i2p::context.GetStatus () == eRouterStatusTesting) // if still testing, repeat peer test
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));
@ -617,6 +643,30 @@ namespace transport
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::RestrictRoutes(std::vector<std::string> families)
{
std::lock_guard<std::mutex> lock(m_FamilyMutex);
m_TrustedFamilies.clear();
for ( auto fam : families )
m_TrustedFamilies.push_back(fam);
}
bool Transports::RoutesRestricted() const {
std::lock_guard<std::mutex> lock(m_FamilyMutex);
return m_TrustedFamilies.size() > 0;
}
/** XXX: if routes are not restricted this dies */
std::shared_ptr<const i2p::data::RouterInfo> Transports::GetRestrictedPeer() const {
std::string fam;
{
std::lock_guard<std::mutex> lock(m_FamilyMutex);
// TODO: random family (?)
fam = m_TrustedFamilies[0];
}
boost::to_lower(fam);
return i2p::data::netdb.GetRandomRouterInFamily(fam);
}
} }
} }

16
Transports.h

@ -73,8 +73,11 @@ namespace transport
Transports (); Transports ();
~Transports (); ~Transports ();
void Start (); void Start (bool enableNTCP=true, bool enableSSU=true);
void Stop (); void Stop ();
bool IsBoundNTCP() const { return m_NTCPServer != nullptr; }
bool IsBoundSSU() const { return m_SSUServer != nullptr; }
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 ();
@ -98,6 +101,13 @@ namespace transport
size_t GetNumPeers () const { return m_Peers.size (); }; size_t GetNumPeers () const { return m_Peers.size (); };
std::shared_ptr<const i2p::data::RouterInfo> GetRandomPeer () const; std::shared_ptr<const i2p::data::RouterInfo> GetRandomPeer () const;
/** get a trusted first hop for restricted routes */
std::shared_ptr<const i2p::data::RouterInfo> GetRestrictedPeer() const;
/** do we want to use restricted routes? */
bool RoutesRestricted() const;
/** restrict routes to use only these router families for first hops */
void RestrictRoutes(std::vector<std::string> families);
void PeerTest (); void PeerTest ();
private: private:
@ -140,6 +150,10 @@ namespace transport
uint64_t m_LastInBandwidthUpdateBytes, m_LastOutBandwidthUpdateBytes; uint64_t m_LastInBandwidthUpdateBytes, m_LastOutBandwidthUpdateBytes;
uint64_t m_LastBandwidthUpdateTime; uint64_t m_LastBandwidthUpdateTime;
/** which router families to trust for first hops */
std::vector<std::string> m_TrustedFamilies;
mutable std::mutex m_FamilyMutex;
public: public:
// for HTTP only // for HTTP only

9
Tunnel.cpp

@ -443,7 +443,7 @@ namespace tunnel
if (msg) if (msg)
{ {
uint32_t prevTunnelID = 0, tunnelID = 0; uint32_t prevTunnelID = 0, tunnelID = 0;
std::shared_ptr<TunnelBase> prevTunnel; std::shared_ptr<TunnelBase> prevTunnel;
do do
{ {
std::shared_ptr<TunnelBase> tunnel; std::shared_ptr<TunnelBase> tunnel;
@ -458,7 +458,7 @@ namespace tunnel
tunnel = prevTunnel; tunnel = prevTunnel;
else if (prevTunnel) else if (prevTunnel)
prevTunnel->FlushTunnelDataMsgs (); prevTunnel->FlushTunnelDataMsgs ();
if (!tunnel) if (!tunnel)
tunnel = GetTunnel (tunnelID); tunnel = GetTunnel (tunnelID);
if (tunnel) if (tunnel)
@ -468,8 +468,9 @@ namespace tunnel
else // tunnel gateway assumed else // tunnel gateway assumed
HandleTunnelGatewayMsg (tunnel, msg); HandleTunnelGatewayMsg (tunnel, msg);
} }
else else
LogPrint (eLogWarning, "Tunnel: tunnel with id ", tunnelID, " not found"); LogPrint (eLogWarning, "Tunnel: tunnel not found, tunnelID=", tunnelID, " previousTunnelID=", prevTunnelID, " type=", (int)typeID);
break; break;
} }
case eI2NPVariableTunnelBuild: case eI2NPVariableTunnelBuild:

2
Tunnel.h

@ -224,7 +224,7 @@ namespace tunnel
std::list<std::shared_ptr<TunnelPool>> m_Pools; std::list<std::shared_ptr<TunnelPool>> m_Pools;
std::shared_ptr<TunnelPool> m_ExploratoryPool; std::shared_ptr<TunnelPool> m_ExploratoryPool;
i2p::util::Queue<std::shared_ptr<I2NPMessage> > m_Queue; i2p::util::Queue<std::shared_ptr<I2NPMessage> > m_Queue;
// some stats // some stats
int m_NumSuccesiveTunnelCreations, m_NumFailedTunnelCreations; int m_NumSuccesiveTunnelCreations, m_NumFailedTunnelCreations;

4
TunnelEndpoint.cpp

@ -205,7 +205,7 @@ namespace tunnel
if (it->second.fragmentNum == msg.nextFragmentNum) if (it->second.fragmentNum == msg.nextFragmentNum)
{ {
LogPrint (eLogWarning, "TunnelMessage: Out-of-sequence fragment ", (int)it->second.fragmentNum, " of message ", msgID, " found"); LogPrint (eLogWarning, "TunnelMessage: Out-of-sequence fragment ", (int)it->second.fragmentNum, " of message ", msgID, " found");
auto size = it->second.data->GetLength (); size_t size = it->second.data->GetLength ();
if (msg.data->len + size > msg.data->maxLen) if (msg.data->len + size > msg.data->maxLen)
{ {
LogPrint (eLogWarning, "TunnelMessage: Tunnel endpoint I2NP message size ", msg.data->maxLen, " is not enough"); LogPrint (eLogWarning, "TunnelMessage: Tunnel endpoint I2NP message size ", msg.data->maxLen, " is not enough");
@ -235,7 +235,7 @@ namespace tunnel
LogPrint (eLogInfo, "TunnelMessage: message expired"); LogPrint (eLogInfo, "TunnelMessage: message expired");
return; return;
} }
auto typeID = msg.data->GetTypeID (); uint8_t typeID = msg.data->GetTypeID ();
LogPrint (eLogDebug, "TunnelMessage: handle fragment of ", msg.data->GetLength (), " bytes, msg type ", (int)typeID); LogPrint (eLogDebug, "TunnelMessage: handle fragment of ", msg.data->GetLength (), " bytes, msg type ", (int)typeID);
// catch RI or reply with new list of routers // catch RI or reply with new list of routers
if ((IsRouterInfoMsg (msg.data) || typeID == eI2NPDatabaseSearchReply) && if ((IsRouterInfoMsg (msg.data) || typeID == eI2NPDatabaseSearchReply) &&

6
TunnelGateway.cpp

@ -49,7 +49,7 @@ namespace tunnel
// create fragments // create fragments
std::shared_ptr<I2NPMessage> msg = block.data; std::shared_ptr<I2NPMessage> msg = block.data;
auto fullMsgLen = diLen + msg->GetLength () + 2; // delivery instructions + payload + 2 bytes length size_t fullMsgLen = diLen + msg->GetLength () + 2; // delivery instructions + payload + 2 bytes length
if (fullMsgLen <= m_RemainingSize) if (fullMsgLen <= m_RemainingSize)
{ {
// message fits. First and last fragment // message fits. First and last fragment
@ -66,10 +66,10 @@ namespace tunnel
{ {
if (!messageCreated) // check if we should complete previous message if (!messageCreated) // check if we should complete previous message
{ {
auto numFollowOnFragments = fullMsgLen / TUNNEL_DATA_MAX_PAYLOAD_SIZE; size_t numFollowOnFragments = fullMsgLen / TUNNEL_DATA_MAX_PAYLOAD_SIZE;
// length of bytes don't fit full tunnel message // length of bytes don't fit full tunnel message
// every follow-on fragment adds 7 bytes // every follow-on fragment adds 7 bytes
auto nonFit = (fullMsgLen + numFollowOnFragments*7) % TUNNEL_DATA_MAX_PAYLOAD_SIZE; size_t nonFit = (fullMsgLen + numFollowOnFragments*7) % TUNNEL_DATA_MAX_PAYLOAD_SIZE;
if (!nonFit || nonFit > m_RemainingSize) if (!nonFit || nonFit > m_RemainingSize)
{ {
CompleteCurrentTunnelDataMessage (); CompleteCurrentTunnelDataMessage ();

25
TunnelPool.cpp

@ -322,7 +322,7 @@ namespace tunnel
i2p::data::netdb.GetHighBandwidthRandomRouter (prevHop); i2p::data::netdb.GetHighBandwidthRandomRouter (prevHop);
if (!hop || hop->GetProfile ()->IsBad ()) if (!hop || hop->GetProfile ()->IsBad ())
hop = i2p::data::netdb.GetRandomRouter (); hop = i2p::data::netdb.GetRandomRouter (prevHop);
return hop; return hop;
} }
@ -330,20 +330,17 @@ namespace tunnel
{ {
if (m_ExplicitPeers) return SelectExplicitPeers (peers, isInbound); if (m_ExplicitPeers) return SelectExplicitPeers (peers, isInbound);
int numHops = isInbound ? m_NumInboundHops : m_NumOutboundHops; int numHops = isInbound ? m_NumInboundHops : m_NumOutboundHops;
if (numHops <= 0) return true; // peers is empty if (numHops <= 0) return true;
auto prevHop = i2p::context.GetSharedRouterInfo (); auto prevHop = i2p::context.GetSharedRouterInfo();
if (i2p::transport::transports.GetNumPeers () > 25) if(i2p::transport::transports.RoutesRestricted())
{ {
auto r = i2p::transport::transports.GetRandomPeer (); /** if routes are restricted prepend trusted first hop */
if (r && !r->GetProfile ()->IsBad ()) auto hop = i2p::transport::transports.GetRestrictedPeer();
{ if(!hop) return false;
prevHop = r; peers.push_back(hop->GetRouterIdentity());
peers.push_back (r->GetRouterIdentity ()); prevHop = hop;
numHops--;
}
} }
for(int i = 0; i < numHops; i++ )
for (int i = 0; i < numHops; i++)
{ {
auto hop = SelectNextHop (prevHop); auto hop = SelectNextHop (prevHop);
if (!hop) if (!hop)
@ -353,7 +350,7 @@ namespace tunnel
} }
prevHop = hop; prevHop = hop;
peers.push_back (hop->GetRouterIdentity ()); peers.push_back (hop->GetRouterIdentity ());
} }
return true; return true;
} }

4
appveyor.yml

@ -138,9 +138,9 @@ install:
|| type c:\projects\instdir\build_openssl.log || type c:\projects\instdir\build_openssl.log
) )
- mklink /J \OpenSSL \stage\OpenSSL-Win%bitness%-vc%msvc%-%type% - mklink /J \OpenSSL \stage\OpenSSL-Win%bitness%-vc%msvc%-%type%
- rem already there: mingw-w64-i686-openssl mingw-w64-i686-gcc cmake - rem already there: mingw-w64-i686-openssl mingw-w64-i686-gcc
- if not defined msvc ( - if not defined msvc (
C:\msys64\usr\bin\bash -lc "pacman --needed --noconfirm -Sy bash pacman pacman-mirrors msys2-runtime msys2-runtime-devel" C:\msys64\usr\bin\bash -lc "pacman --needed --noconfirm -Sy bash pacman pacman-mirrors msys2-runtime msys2-runtime-devel cmake"
&& if "%x64%" == "1" ( && if "%x64%" == "1" (
C:\msys64\usr\bin\bash -lc "pacman --noconfirm -S mingw-w64-x86_64-openssl mingw-w64-x86_64-boost mingw-w64-x86_64-miniupnpc" C:\msys64\usr\bin\bash -lc "pacman --noconfirm -S mingw-w64-x86_64-openssl mingw-w64-x86_64-boost mingw-w64-x86_64-miniupnpc"
) else ( ) else (

14
build/CMakeLists.txt

@ -12,6 +12,7 @@ option(WITH_STATIC "Static build" OFF)
option(WITH_UPNP "Include support for UPnP client" OFF) option(WITH_UPNP "Include support for UPnP client" OFF)
option(WITH_PCH "Use precompiled header" OFF) option(WITH_PCH "Use precompiled header" OFF)
option(WITH_GUI "Include GUI (currently MS Windows only)" ON) option(WITH_GUI "Include GUI (currently MS Windows only)" ON)
option(WITH_MESHNET "Build for cjdns test network" OFF)
# paths # paths
set ( CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake_modules" ) set ( CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake_modules" )
@ -90,6 +91,10 @@ set (DAEMON_SRC
"${CMAKE_SOURCE_DIR}/UPnP.cpp" "${CMAKE_SOURCE_DIR}/UPnP.cpp"
) )
if (WITH_MESHNET)
add_definitions(-DMESHNET)
endif ()
if (WITH_UPNP) if (WITH_UPNP)
add_definitions(-DUSE_UPNP) add_definitions(-DUSE_UPNP)
if (NOT MSVC AND NOT MSYS) if (NOT MSVC AND NOT MSYS)
@ -296,6 +301,14 @@ link_directories(${CMAKE_CURRENT_BINARY_DIR}/zlib/lib ${ZLIB_ROOT}/lib)
# load includes # load includes
include_directories( SYSTEM ${Boost_INCLUDE_DIRS} ${OPENSSL_INCLUDE_DIR} ${ZLIB_INCLUDE_DIR} ) include_directories( SYSTEM ${Boost_INCLUDE_DIRS} ${OPENSSL_INCLUDE_DIR} ${ZLIB_INCLUDE_DIR} )
# warn if for meshnet
if (WITH_MESHNET)
message(STATUS "Building for testnet")
message(WARNING "This build will NOT work on mainline i2p")
endif()
# show summary # show summary
message(STATUS "---------------------------------------") message(STATUS "---------------------------------------")
message(STATUS "Build type : ${CMAKE_BUILD_TYPE}") message(STATUS "Build type : ${CMAKE_BUILD_TYPE}")
@ -311,6 +324,7 @@ message(STATUS " BINARY : ${WITH_BINARY}")
message(STATUS " STATIC BUILD : ${WITH_STATIC}") message(STATUS " STATIC BUILD : ${WITH_STATIC}")
message(STATUS " UPnP : ${WITH_UPNP}") message(STATUS " UPnP : ${WITH_UPNP}")
message(STATUS " PCH : ${WITH_PCH}") message(STATUS " PCH : ${WITH_PCH}")
message(STATUS " MESHNET : ${WITH_MESHNET}")
message(STATUS "---------------------------------------") message(STATUS "---------------------------------------")
#Handle paths nicely #Handle paths nicely

2
qt/i2pd_qt/i2pd_qt.pro

@ -50,7 +50,7 @@ HEADERS += DaemonQT.h mainwindow.h \
../../Streaming.h ../../Timestamp.h ../../TransitTunnel.h ../../Transports.h \ ../../Streaming.h ../../Timestamp.h ../../TransitTunnel.h ../../Transports.h \
../../TransportSession.h ../../Tunnel.h ../../TunnelBase.h ../../TunnelConfig.h \ ../../TransportSession.h ../../Tunnel.h ../../TunnelBase.h ../../TunnelConfig.h \
../../TunnelEndpoint.h ../../TunnelGateway.h ../../TunnelPool.h ../../UPnP.h \ ../../TunnelEndpoint.h ../../TunnelGateway.h ../../TunnelPool.h ../../UPnP.h \
../../util.h ../../version.h ..//../Gzip.h ../../Tag.h ../../util.h ../../version.h ../../Gzip.h ../../Tag.h
FORMS += mainwindow.ui FORMS += mainwindow.ui

12
tests/test-http-url.cpp

@ -104,6 +104,18 @@ int main() {
assert(url->query == ""); assert(url->query == "");
delete url; delete url;
url = new URL;
assert(url->parse("http://user:password@site.com:84/asdasd/@17#frag") == true);
assert(url->schema == "http");
assert(url->user == "user");
assert(url->pass == "password");
assert(url->host == "site.com");
assert(url->port == 84);
assert(url->path == "/asdasd/@17");
assert(url->query == "");
assert(url->frag == "frag");
delete url;
return 0; return 0;
} }

47
util.cpp

@ -413,7 +413,52 @@ namespace net
return GetMTUUnix(localAddress, fallback); return GetMTUUnix(localAddress, fallback);
#endif #endif
return fallback; return fallback;
} }
const boost::asio::ip::address GetInterfaceAddress(const std::string & ifname, bool ipv6)
{
#ifdef WIN32
LogPrint(eLogError, "NetIface: cannot get address by interface name, not implemented on WIN32");
return boost::asio::ip::address::from_string("127.0.0.1");
#else
int af = (ipv6 ? AF_INET6 : AF_INET);
ifaddrs * addrs = nullptr;
if(getifaddrs(&addrs) == 0)
{
// got ifaddrs
ifaddrs * cur = addrs;
while(cur)
{
std::string cur_ifname(cur->ifa_name);
if (cur_ifname == ifname && cur->ifa_addr && cur->ifa_addr->sa_family == af)
{
// match
char * addr = new char[INET6_ADDRSTRLEN];
bzero(addr, INET6_ADDRSTRLEN);
if(af == AF_INET)
inet_ntop(af, &((sockaddr_in *)cur->ifa_addr)->sin_addr, addr, INET6_ADDRSTRLEN);
else
inet_ntop(af, &((sockaddr_in6 *)cur->ifa_addr)->sin6_addr, addr, INET6_ADDRSTRLEN);
freeifaddrs(addrs);
std::string cur_ifaddr(addr);
return boost::asio::ip::address::from_string(cur_ifaddr);
}
cur = cur->ifa_next;
}
}
if(addrs) freeifaddrs(addrs);
std::string fallback;
if(ipv6) {
fallback = "::";
LogPrint(eLogWarning, "NetIface: cannot find ipv6 address for interface ", ifname);
} else {
fallback = "127.0.0.1";
LogPrint(eLogWarning, "NetIface: cannot find ipv4 address for interface ", ifname);
}
return boost::asio::ip::address::from_string(fallback);
#endif
}
} }
} // util } // util

1
util.h

@ -66,6 +66,7 @@ namespace util
namespace net namespace net
{ {
int GetMTU (const boost::asio::ip::address& localAddress); int GetMTU (const boost::asio::ip::address& localAddress);
const boost::asio::ip::address GetInterfaceAddress(const std::string & ifname, bool ipv6=false);
} }
} }
} }

5
version.h

@ -12,7 +12,12 @@
#define I2PD_VERSION_PATCH 0 #define I2PD_VERSION_PATCH 0
#define I2PD_VERSION MAKE_VERSION(I2PD_VERSION_MAJOR, I2PD_VERSION_MINOR, I2PD_VERSION_MICRO) #define I2PD_VERSION MAKE_VERSION(I2PD_VERSION_MAJOR, I2PD_VERSION_MINOR, I2PD_VERSION_MICRO)
#define VERSION I2PD_VERSION #define VERSION I2PD_VERSION
#ifdef MESHNET
#define I2PD_NET_ID 3
#else
#define I2PD_NET_ID 2 #define I2PD_NET_ID 2
#endif
#define I2P_VERSION_MAJOR 0 #define I2P_VERSION_MAJOR 0
#define I2P_VERSION_MINOR 9 #define I2P_VERSION_MINOR 9

Loading…
Cancel
Save