Browse Source

Merge pull request #5 from PurpleI2P/openssl

upstream pull
pull/560/head
MXPLRS | Kirill 9 years ago committed by GitHub
parent
commit
1e56d17d39
  1. 4
      AddressBook.h
  2. 15
      Config.cpp
  3. 96
      Daemon.cpp
  4. 11
      Destination.cpp
  5. 6
      HTTP.cpp
  6. 13
      I2CP.cpp
  7. 3
      I2NPProtocol.cpp
  8. 2
      LeaseSet.cpp
  9. 5
      Makefile
  10. 24
      NTCPSession.cpp
  11. 3
      NTCPSession.h
  12. 65
      NetDb.cpp
  13. 13
      NetDb.h
  14. 6
      Reseed.cpp
  15. 4
      RouterInfo.cpp
  16. 3
      RouterInfo.h
  17. 1
      SAM.cpp
  18. 24
      SSU.cpp
  19. 2
      SSU.h
  20. 4
      SSUData.h
  21. 10
      SSUSession.cpp
  22. 60
      Transports.cpp
  23. 16
      Transports.h
  24. 3
      Tunnel.cpp
  25. 4
      TunnelEndpoint.cpp
  26. 6
      TunnelGateway.cpp
  27. 25
      TunnelPool.cpp
  28. 14
      build/CMakeLists.txt
  29. 45
      util.cpp
  30. 1
      util.h
  31. 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)

15
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")
@ -129,6 +137,12 @@ namespace config {
"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)
@ -140,6 +154,7 @@ namespace config {
.add(i2cp) .add(i2cp)
.add(i2pcontrol) .add(i2pcontrol)
.add(precomputation) .add(precomputation)
.add(trust)
; ;
} }

96
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"
@ -122,22 +123,51 @@ namespace i2p
i2p::crypto::InitCrypto (precomputation); i2p::crypto::InitCrypto (precomputation);
i2p::context.Init (); i2p::context.Init ();
uint16_t port; i2p::config::GetOption("port", port); bool ipv6; i2p::config::GetOption("ipv6", ipv6);
if (!i2p::config::IsDefault("port")) bool ipv4; i2p::config::GetOption("ipv4", ipv4);
{ #ifdef MESHNET
LogPrint(eLogInfo, "Daemon: accepting incoming connections at port ", port); // manual override for meshnet
i2p::context.UpdatePort (port); 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); std::string host; i2p::config::GetOption("host", host);
if (!i2p::config::IsDefault("host")) if (!i2p::config::IsDefault("host"))
{ {
LogPrint(eLogInfo, "Daemon: setting address for incoming connections to ", host); LogPrint(eLogInfo, "Daemon: setting address for incoming connections to ", host);
i2p::context.UpdateAddress (boost::asio::ip::address::from_string (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);
if (!i2p::config::IsDefault("port"))
{
LogPrint(eLogInfo, "Daemon: accepting incoming connections at port ", port);
i2p::context.UpdatePort (port);
}
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);
@ -193,11 +223,51 @@ namespace i2p
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);
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; return true;
} }
bool Daemon_Singleton::start() bool Daemon_Singleton::start()
{ {
LogPrint(eLogInfo, "Daemon: starting NetDB");
i2p::data::netdb.Start();
#ifdef USE_UPNP
LogPrint(eLogInfo, "Daemon: starting UPnP");
d.m_UPnP.Start ();
#endif
bool ntcp; i2p::config::GetOption("ntcp", ntcp);
bool ssu; i2p::config::GetOption("ssu", ssu);
LogPrint(eLogInfo, "Daemon: starting Transports");
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); 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);
@ -207,15 +277,6 @@ namespace i2p
d.httpServer->Start(); d.httpServer->Start();
} }
LogPrint(eLogInfo, "Daemon: starting NetDB");
i2p::data::netdb.Start();
#ifdef USE_UPNP
LogPrint(eLogInfo, "Daemon: starting UPnP");
d.m_UPnP.Start ();
#endif
LogPrint(eLogInfo, "Daemon: starting Transports");
i2p::transport::transports.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;
} }

11
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 // we got latest LeasetSet
LogPrint (eLogDebug, "Destination: published LeaseSet verified"); LogPrint (eLogDebug, "Destination: published LeaseSet verified for ", GetIdentHash().ToBase32());
s->m_PublishVerificationTimer.expires_from_now (boost::posix_time::seconds(PUBLISH_REGULAR_VERIFICATION_INTERNAL)); s->m_PublishVerificationTimer.expires_from_now (boost::posix_time::seconds(PUBLISH_REGULAR_VERIFICATION_INTERNAL));
s->m_PublishVerificationTimer.async_wait (std::bind (&LeaseSetDestination::HandlePublishVerificationTimer, s, std::placeholders::_1)); s->m_PublishVerificationTimer.async_wait (std::bind (&LeaseSetDestination::HandlePublishVerificationTimer, s, std::placeholders::_1));
return; 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 ();
}); });

6
HTTP.cpp

@ -72,7 +72,11 @@ 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) == '/' && url.find("/http://") == 0) {
/* special case for i2p.rocks inproxy */
pos_p ++;
}
if(url.at(0) != '/' || pos_p > 0) {
/* schema */ /* schema */
pos_c = url.find("://"); pos_c = url.find("://");
if (pos_c != std::string::npos) { if (pos_c != std::string::npos) {

13
I2CP.cpp

@ -424,14 +424,25 @@ 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);
if (identsize)
{
offset += identsize;
uint32_t payloadLen = bufbe32toh (buf + offset); uint32_t payloadLen = bufbe32toh (buf + offset);
if (payloadLen + offset <= len)
{
offset += 4; offset += 4;
uint32_t nonce = bufbe32toh (buf + offset + payloadLen); uint32_t nonce = bufbe32toh (buf + offset + payloadLen);
if (m_IsSendAccepted) if (m_IsSendAccepted)
SendMessageStatusMessage (nonce, eI2CPMessageStatusAccepted); // accepted SendMessageStatusMessage (nonce, eI2CPMessageStatusAccepted); // accepted
m_Destination->SendMsgTo (buf + offset, payloadLen, identity.GetIdentHash (), nonce); 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
LogPrint (eLogError, "I2CP: unexpected sessionID ", sessionID); LogPrint (eLogError, "I2CP: unexpected sessionID ", sessionID);

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);

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:

24
NTCPSession.cpp

@ -760,21 +760,33 @@ 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)
{
if (address->host.is_v4())
{
try
{ {
m_NTCPAcceptor = new boost::asio::ip::tcp::acceptor (m_Service, m_NTCPAcceptor = new boost::asio::ip::tcp::acceptor (m_Service,
boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), address->port)); boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), address->port));
} catch ( std::exception & ex ) {
/** fail to bind ip4 */
LogPrint(eLogError, "NTCP: Failed to bind to ip4 port ",address->port, ex.what());
continue;
}
LogPrint (eLogInfo, "NTCP: Start listening TCP port ", address->port); LogPrint (eLogInfo, "NTCP: Start listening TCP port ", address->port);
auto conn = std::make_shared<NTCPSession>(*this); auto conn = std::make_shared<NTCPSession>(*this);
m_NTCPAcceptor->async_accept(conn->GetSocket (), std::bind (&NTCPServer::HandleAccept, this, m_NTCPAcceptor->async_accept(conn->GetSocket (), std::bind (&NTCPServer::HandleAccept, this,
conn, std::placeholders::_1)); conn, std::placeholders::_1));
}
if (context.SupportsV6 ()) else if (address->host.is_v6() && context.SupportsV6 ())
{ {
m_NTCPV6Acceptor = new boost::asio::ip::tcp::acceptor (m_Service); m_NTCPV6Acceptor = new boost::asio::ip::tcp::acceptor (m_Service);
try
{
m_NTCPV6Acceptor->open (boost::asio::ip::tcp::v6()); m_NTCPV6Acceptor->open (boost::asio::ip::tcp::v6());
m_NTCPV6Acceptor->set_option (boost::asio::ip::v6_only (true)); 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->bind (boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v6(), address->port));
m_NTCPV6Acceptor->listen (); m_NTCPV6Acceptor->listen ();
@ -782,6 +794,10 @@ namespace transport
auto conn = std::make_shared<NTCPSession> (*this); auto conn = std::make_shared<NTCPSession> (*this);
m_NTCPV6Acceptor->async_accept(conn->GetSocket (), std::bind (&NTCPServer::HandleAcceptV6, m_NTCPV6Acceptor->async_accept(conn->GetSocket (), std::bind (&NTCPServer::HandleAcceptV6,
this, conn, std::placeholders::_1)); this, conn, std::placeholders::_1));
} catch ( std::exception & ex ) {
LogPrint(eLogError, "NTCP: failed to bind to ip6 port ", address->port);
continue;
}
} }
} }
} }
@ -795,8 +811,10 @@ namespace transport
if (m_IsRunning) if (m_IsRunning)
{ {
m_IsRunning = false; m_IsRunning = false;
if (m_NTCPAcceptor)
delete m_NTCPAcceptor; delete m_NTCPAcceptor;
m_NTCPAcceptor = nullptr; m_NTCPAcceptor = nullptr;
if (m_NTCPV6Acceptor)
delete m_NTCPV6Acceptor; delete m_NTCPV6Acceptor;
m_NTCPV6Acceptor = nullptr; m_NTCPV6Acceptor = nullptr;

3
NTCPSession.h

@ -145,6 +145,9 @@ namespace transport
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);

65
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)
{ {
} }
@ -122,7 +122,11 @@ namespace data
} }
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,15 +508,17 @@ 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);
} }
} }
@ -615,13 +624,16 @@ 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;
uint32_t replyTunnelID = 0; uint32_t replyTunnelID = 0;
if (flag & DATABASE_LOOKUP_DELIVERY_FLAG) //reply to tunnel if (flag & DATABASE_LOOKUP_DELIVERY_FLAG) //reply to tunnel
{ {
replyTunnelID = bufbe32toh (buf + 64); replyTunnelID = bufbe32toh (buf + 65);
excluded += 4; excluded += 4;
} }
uint16_t numExcluded = bufbe16toh (excluded); uint16_t numExcluded = bufbe16toh (excluded);
@ -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);
} }
} }
@ -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
{ {

13
NetDb.h

@ -32,6 +32,12 @@ namespace data
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
{ {
public: public:
@ -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; };
@ -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;

6
Reseed.cpp

@ -22,6 +22,11 @@ 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
@ -32,6 +37,7 @@ namespace data
"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()

4
RouterInfo.cpp

@ -292,6 +292,10 @@ namespace data
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)
{ {
const char * cap = value; const char * cap = 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; };

1
SAM.cpp

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

24
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 ())
@ -36,8 +55,11 @@ namespace transport
{ {
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));
if (!m_OnlyV6)
{
m_Thread = new std::thread (std::bind (&SSUServer::Run, this)); m_Thread = new std::thread (std::bind (&SSUServer::Run, this));
m_ReceiversService.post (std::bind (&SSUServer::Receive, 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));

2
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 ();
@ -95,6 +96,7 @@ namespace transport
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");

60
Transports.cpp

@ -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)
{ {
if (address->host.is_v4())
m_SSUServer = new SSUServer (address->port); 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);
try {
m_SSUServer->Start (); 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
@ -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
{ {
@ -469,7 +486,10 @@ 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 ();
@ -595,6 +615,12 @@ 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");
auto profile = i2p::data::GetRouterProfile(it->first);
if (profile)
{
profile->TunnelNonReplied();
profile->Save();
}
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);
} }
@ -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,9 +73,12 @@ 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 ();
void ReuseDHKeysPair (std::shared_ptr<i2p::crypto::DHKeys> pair); void ReuseDHKeysPair (std::shared_ptr<i2p::crypto::DHKeys> pair);
@ -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

3
Tunnel.cpp

@ -469,7 +469,8 @@ namespace tunnel
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:

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)

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

45
util.cpp

@ -414,6 +414,51 @@ namespace net
#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::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