From 43d458cf726d59f352082d414f8436b343c32ee0 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 16 Mar 2021 13:08:10 -0400 Subject: [PATCH 01/87] publish and upublish NTCP2 and yggdrasil addresses separatly --- daemon/Daemon.cpp | 6 +++--- libi2pd/RouterContext.cpp | 10 ++++++---- libi2pd/RouterContext.h | 2 +- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/daemon/Daemon.cpp b/daemon/Daemon.cpp index 51783068..882e94f6 100644 --- a/daemon/Daemon.cpp +++ b/daemon/Daemon.cpp @@ -218,7 +218,7 @@ namespace util { uint16_t ntcp2port; i2p::config::GetOption("ntcp2.port", ntcp2port); if (!ntcp2port) ntcp2port = port; // use standard port - i2p::context.PublishNTCP2Address (ntcp2port, true); // publish + i2p::context.PublishNTCP2Address (ntcp2port, true, ipv4, ipv6, false); // publish if (ipv6) { std::string ipv6Addr; i2p::config::GetOption("ntcp2.addressv6", ipv6Addr); @@ -228,12 +228,12 @@ namespace util } } else - i2p::context.PublishNTCP2Address (port, false); // unpublish + i2p::context.PublishNTCP2Address (port, false, ipv4, ipv6, false); // unpublish } if (ygg) { if (!ntcp2) - i2p::context.PublishNTCP2Address (port, true); + i2p::context.PublishNTCP2Address (port, true, false, false, true); i2p::context.UpdateNTCP2V6Address (yggaddr); if (!ipv4 && !ipv6) i2p::context.SetStatus (eRouterStatusMesh); diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index 00d467db..9451cca5 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -225,13 +225,15 @@ namespace i2p UpdateRouterInfo (); } - void RouterContext::PublishNTCP2Address (int port, bool publish, bool v4only) + void RouterContext::PublishNTCP2Address (int port, bool publish, bool v4, bool v6, bool ygg) { if (!m_NTCP2Keys) return; bool updated = false; for (auto& address : m_RouterInfo.GetAddresses ()) { - if (address->IsNTCP2 () && (address->port != port || address->ntcp2->isPublished != publish) && (!v4only || address->IsV4 ())) + if (address->IsNTCP2 () && (address->port != port || address->ntcp2->isPublished != publish) + && ((v4 && address->IsV4 ()) || (v6 && address->IsV6 ()) || + (ygg && i2p::util::net::IsYggdrasilAddress (address->host)))) { if (!port && !address->port) { @@ -457,7 +459,7 @@ namespace i2p // remove NTCP2 v4 address bool ntcp2; i2p::config::GetOption("ntcp2.enabled", ntcp2); if (ntcp2) - PublishNTCP2Address (port, false, true); + PublishNTCP2Address (port, false, true, false, false); // ipv4 only // update UpdateRouterInfo (); } @@ -491,7 +493,7 @@ namespace i2p { uint16_t ntcp2Port; i2p::config::GetOption ("ntcp2.port", ntcp2Port); if (!ntcp2Port) ntcp2Port = port; - PublishNTCP2Address (ntcp2Port, true, true); + PublishNTCP2Address (ntcp2Port, true, true, false, false); // ipv4 only } } // update diff --git a/libi2pd/RouterContext.h b/libi2pd/RouterContext.h index fe6c9ec9..ee66a83c 100644 --- a/libi2pd/RouterContext.h +++ b/libi2pd/RouterContext.h @@ -97,7 +97,7 @@ namespace garlic void UpdatePort (int port); // called from Daemon void UpdateAddress (const boost::asio::ip::address& host); // called from SSU or Daemon - void PublishNTCP2Address (int port, bool publish = true, bool v4only = false); + void PublishNTCP2Address (int port, bool publish, bool v4, bool v6, bool ygg); void UpdateNTCP2Address (bool enable); void RemoveNTCPAddress (bool v4only = true); // delete NTCP address for older routers. TODO: remove later bool AddIntroducer (const i2p::data::RouterInfo::Introducer& introducer); From 1d5d06f7311a3e82a4a888c7ad8306b3c1efe3a5 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 16 Mar 2021 15:23:00 -0400 Subject: [PATCH 02/87] find actual router for peer --- libi2pd/Transports.cpp | 13 +++++++++---- libi2pd/TunnelPool.cpp | 6 ++++-- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/libi2pd/Transports.cpp b/libi2pd/Transports.cpp index 9265f289..9f3e75b7 100644 --- a/libi2pd/Transports.cpp +++ b/libi2pd/Transports.cpp @@ -772,10 +772,15 @@ namespace transport std::shared_ptr Transports::GetRandomPeer () const { if (m_Peers.empty ()) return nullptr; - std::unique_lock l(m_PeersMutex); - auto it = m_Peers.begin (); - std::advance (it, rand () % m_Peers.size ()); - return it != m_Peers.end () ? it->second.router : nullptr; + i2p::data::IdentHash ident; + { + std::unique_lock l(m_PeersMutex); + auto it = m_Peers.begin (); + std::advance (it, rand () % m_Peers.size ()); + if (it == m_Peers.end () || it->second.router) return nullptr; // not connected + ident = it->first; + } + return i2p::data::netdb.FindRouter (ident); } void Transports::RestrictRoutesToFamilies(std::set families) { diff --git a/libi2pd/TunnelPool.cpp b/libi2pd/TunnelPool.cpp index 417f5f15..038bbb0f 100644 --- a/libi2pd/TunnelPool.cpp +++ b/libi2pd/TunnelPool.cpp @@ -406,6 +406,7 @@ namespace tunnel bool StandardSelectPeers(Path & peers, int numHops, bool inbound, SelectHopFunc nextHop) { + int start = 0; auto prevHop = i2p::context.GetSharedRouterInfo (); if(i2p::transport::transports.RoutesRestricted()) { @@ -414,6 +415,7 @@ namespace tunnel if(!hop) return false; peers.push_back(hop->GetRouterIdentity()); prevHop = hop; + start++; } else if (i2p::transport::transports.GetNumPeers () > 25) { @@ -423,11 +425,11 @@ namespace tunnel { prevHop = r; peers.push_back (r->GetRouterIdentity ()); - numHops--; + start++; } } - for(int i = 0; i < numHops; i++ ) + for(int i = start; i < numHops; i++ ) { auto hop = nextHop (prevHop, inbound); if (!hop && !i) // if no suitable peer found for first hop, try already connected From 820a36547465a5d21cc7d0bf47a5af37a44d32d8 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 16 Mar 2021 18:45:51 -0400 Subject: [PATCH 03/87] select random peer for first hop for outbound tunnel if number of connections < 100 --- libi2pd/TunnelPool.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libi2pd/TunnelPool.cpp b/libi2pd/TunnelPool.cpp index 038bbb0f..7cb79956 100644 --- a/libi2pd/TunnelPool.cpp +++ b/libi2pd/TunnelPool.cpp @@ -417,7 +417,8 @@ namespace tunnel prevHop = hop; start++; } - else if (i2p::transport::transports.GetNumPeers () > 25) + else if (i2p::transport::transports.GetNumPeers () > 100 || + (inbound && i2p::transport::transports.GetNumPeers () > 25)) { auto r = i2p::transport::transports.GetRandomPeer (); if (r && !r->GetProfile ()->IsBad () && From a7b56bbbb748c05bfdaf0c13a68493817ef7d41f Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 17 Mar 2021 11:26:52 -0400 Subject: [PATCH 04/87] publish Yggdrasil address when enabled --- daemon/Daemon.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/daemon/Daemon.cpp b/daemon/Daemon.cpp index 882e94f6..9fffe5a8 100644 --- a/daemon/Daemon.cpp +++ b/daemon/Daemon.cpp @@ -232,8 +232,7 @@ namespace util } if (ygg) { - if (!ntcp2) - i2p::context.PublishNTCP2Address (port, true, false, false, true); + i2p::context.PublishNTCP2Address (port, true, false, false, true); i2p::context.UpdateNTCP2V6Address (yggaddr); if (!ipv4 && !ipv6) i2p::context.SetStatus (eRouterStatusMesh); From ff9ee5873f9591cdc4704dc1deab7eabfd911199 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 17 Mar 2021 15:10:14 -0400 Subject: [PATCH 05/87] post LeaseSet creation to I2CP destnation's thread --- libi2pd_client/I2CP.cpp | 5 +++++ libi2pd_client/I2CP.h | 2 ++ 2 files changed, 7 insertions(+) diff --git a/libi2pd_client/I2CP.cpp b/libi2pd_client/I2CP.cpp index c9db4a82..5cd1812a 100644 --- a/libi2pd_client/I2CP.cpp +++ b/libi2pd_client/I2CP.cpp @@ -85,6 +85,11 @@ namespace client } void I2CPDestination::CreateNewLeaseSet (std::vector > tunnels) + { + GetService ().post (std::bind (&I2CPDestination::PostCreateNewLeaseSet, this, tunnels)); + } + + void I2CPDestination::PostCreateNewLeaseSet (std::vector > tunnels) { if (m_IsCreatingLeaseSet) { diff --git a/libi2pd_client/I2CP.h b/libi2pd_client/I2CP.h index da7d8ffa..983951a4 100644 --- a/libi2pd_client/I2CP.h +++ b/libi2pd_client/I2CP.h @@ -101,6 +101,8 @@ namespace client { return std::static_pointer_cast(shared_from_this ()); } bool SendMsg (std::shared_ptr msg, std::shared_ptr remote); + void PostCreateNewLeaseSet (std::vector > tunnels); + private: std::shared_ptr m_Owner; From ef1dfb153cad6158584e4e90b2cf4d3912f71c1e Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 18 Mar 2021 18:37:02 -0400 Subject: [PATCH 06/87] handle ipv6 address for RelayIntro --- libi2pd/SSUSession.cpp | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/libi2pd/SSUSession.cpp b/libi2pd/SSUSession.cpp index f9dbee5e..5e0c9b9b 100644 --- a/libi2pd/SSUSession.cpp +++ b/libi2pd/SSUSession.cpp @@ -716,18 +716,36 @@ namespace transport void SSUSession::ProcessRelayIntro (const uint8_t * buf, size_t len) { + if (!len) return; uint8_t size = *buf; + if ((int)len < 1 + size + 2) // size + address + port + { + LogPrint (eLogWarning, "SSU: Relay intro is too short ", len); + return; + } + buf++; // size + boost::asio::ip::address ip; if (size == 4) { - buf++; // size - boost::asio::ip::address_v4 address (bufbe32toh (buf)); - buf += 4; // address - uint16_t port = bufbe16toh (buf); - // send hole punch of 0 bytes - m_Server.Send (buf, 0, boost::asio::ip::udp::endpoint (address, port)); + boost::asio::ip::address_v4::bytes_type bytes; + memcpy (bytes.data (), buf, 4); + ip = boost::asio::ip::address_v4 (bytes); } + else if (size == 16) + { + boost::asio::ip::address_v6::bytes_type bytes; + memcpy (bytes.data (), buf, 16); + ip = boost::asio::ip::address_v6 (bytes); + } else + { LogPrint (eLogWarning, "SSU: Address size ", size, " is not supported"); + return; + } + buf += size; + uint16_t port = bufbe16toh (buf); + // send hole punch of 0 bytes + m_Server.Send (buf, 0, boost::asio::ip::udp::endpoint (ip, port)); } void SSUSession::FillHeaderAndEncrypt (uint8_t payloadType, uint8_t * buf, size_t len, From a9c7d0d59878c5e7eb231963c7309a6daf25a79a Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 18 Mar 2021 20:11:24 -0400 Subject: [PATCH 07/87] common ExtractIPAddressAndPort --- libi2pd/SSUSession.cpp | 94 ++++++++++++++++++++---------------------- libi2pd/SSUSession.h | 2 + 2 files changed, 46 insertions(+), 50 deletions(-) diff --git a/libi2pd/SSUSession.cpp b/libi2pd/SSUSession.cpp index 5e0c9b9b..47c5e017 100644 --- a/libi2pd/SSUSession.cpp +++ b/libi2pd/SSUSession.cpp @@ -257,27 +257,14 @@ namespace transport s.Insert (m_DHKeysPair->GetPublicKey (), 256); // x s.Insert (y, 256); // y payload += 256; - uint8_t addressSize = *payload; - payload += 1; // size - uint8_t * ourAddress = payload; boost::asio::ip::address ourIP; - if (addressSize == 4) // v4 - { - boost::asio::ip::address_v4::bytes_type bytes; - memcpy (bytes.data (), ourAddress, 4); - ourIP = boost::asio::ip::address_v4 (bytes); - } - else // v6 - { - boost::asio::ip::address_v6::bytes_type bytes; - memcpy (bytes.data (), ourAddress, 16); - ourIP = boost::asio::ip::address_v6 (bytes); - } - s.Insert (ourAddress, addressSize); // our IP - payload += addressSize; // address - uint16_t ourPort = bufbe16toh (payload); - s.Insert (payload, 2); // our port - payload += 2; // port + uint16_t ourPort = 0; + auto addressAndPortLen = ExtractIPAddressAndPort (payload, len, ourIP, ourPort); + if (!addressAndPortLen) return; + uint8_t * ourAddressAndPort = payload + 1; + payload += addressAndPortLen; + addressAndPortLen--; // -1 byte address size + s.Insert (ourAddressAndPort, addressAndPortLen); // address + port if (m_RemoteEndpoint.address ().is_v4 ()) s.Insert (m_RemoteEndpoint.address ().to_v4 ().to_bytes ().data (), 4); // remote IP v4 else @@ -309,7 +296,7 @@ namespace transport { LogPrint (eLogInfo, "SSU: Our external address is ", ourIP.to_string (), ":", ourPort); i2p::context.UpdateAddress (ourIP); - SendSessionConfirmed (y, ourAddress, addressSize + 2); + SendSessionConfirmed (y, ourAddressAndPort, addressAndPortLen); } else { @@ -716,36 +703,12 @@ namespace transport void SSUSession::ProcessRelayIntro (const uint8_t * buf, size_t len) { - if (!len) return; - uint8_t size = *buf; - if ((int)len < 1 + size + 2) // size + address + port - { - LogPrint (eLogWarning, "SSU: Relay intro is too short ", len); - return; - } - buf++; // size boost::asio::ip::address ip; - if (size == 4) - { - boost::asio::ip::address_v4::bytes_type bytes; - memcpy (bytes.data (), buf, 4); - ip = boost::asio::ip::address_v4 (bytes); - } - else if (size == 16) - { - boost::asio::ip::address_v6::bytes_type bytes; - memcpy (bytes.data (), buf, 16); - ip = boost::asio::ip::address_v6 (bytes); - } - else - { - LogPrint (eLogWarning, "SSU: Address size ", size, " is not supported"); - return; - } - buf += size; - uint16_t port = bufbe16toh (buf); - // send hole punch of 0 bytes - m_Server.Send (buf, 0, boost::asio::ip::udp::endpoint (ip, port)); + uint16_t port = 0; + ExtractIPAddressAndPort (buf, len, ip, port); + if (!ip.is_unspecified () && port) + // send hole punch of 0 bytes + m_Server.Send (buf, 0, boost::asio::ip::udp::endpoint (ip, port)); } void SSUSession::FillHeaderAndEncrypt (uint8_t payloadType, uint8_t * buf, size_t len, @@ -1251,5 +1214,36 @@ namespace transport i2p::transport::transports.UpdateSentBytes (size); m_Server.Send (buf, size, m_RemoteEndpoint); } + + size_t SSUSession::ExtractIPAddressAndPort (const uint8_t * buf, size_t len, boost::asio::ip::address& ip, uint16_t& port) + { + if (!len) return 0; + uint8_t size = *buf; + size_t s = 1 + size + 2; // size + address + port + if (len < s) + { + LogPrint (eLogWarning, "SSU: Address is too short ", len); + port = 0; + return len; + } + buf++; // size + if (size == 4) + { + boost::asio::ip::address_v4::bytes_type bytes; + memcpy (bytes.data (), buf, 4); + ip = boost::asio::ip::address_v4 (bytes); + } + else if (size == 16) + { + boost::asio::ip::address_v6::bytes_type bytes; + memcpy (bytes.data (), buf, 16); + ip = boost::asio::ip::address_v6 (bytes); + } + else + LogPrint (eLogWarning, "SSU: Address size ", size, " is not supported"); + buf += size; + port = bufbe16toh (buf); + return s; + } } } diff --git a/libi2pd/SSUSession.h b/libi2pd/SSUSession.h index 3aa04638..ece8f5bf 100644 --- a/libi2pd/SSUSession.h +++ b/libi2pd/SSUSession.h @@ -145,6 +145,8 @@ namespace transport void Reset (); + static size_t ExtractIPAddressAndPort (const uint8_t * buf, size_t len, boost::asio::ip::address& ip, uint16_t& port); // returns actual buf size + private: friend class SSUData; // TODO: change in later From 6b0c7c2313b60bb218d8924480fb6820ffe3b59a Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 18 Mar 2021 21:29:39 -0400 Subject: [PATCH 08/87] handle ipv6 address in RelayResponse --- libi2pd/SSUSession.cpp | 32 +++++++++----------------------- 1 file changed, 9 insertions(+), 23 deletions(-) diff --git a/libi2pd/SSUSession.cpp b/libi2pd/SSUSession.cpp index 47c5e017..d1dc7aec 100644 --- a/libi2pd/SSUSession.cpp +++ b/libi2pd/SSUSession.cpp @@ -645,30 +645,16 @@ namespace transport void SSUSession::ProcessRelayResponse (const uint8_t * buf, size_t len) { LogPrint (eLogDebug, "SSU message: Relay response received"); - uint8_t remoteSize = *buf; - buf++; // remote size - boost::asio::ip::address_v4 remoteIP (bufbe32toh (buf)); - buf += remoteSize; // remote address - uint16_t remotePort = bufbe16toh (buf); - buf += 2; // remote port - uint8_t ourSize = *buf; - buf++; // our size + boost::asio::ip::address remoteIP; + uint16_t remotePort = 0; + auto remoteSize = ExtractIPAddressAndPort (buf, len, remoteIP, remotePort); + if (!remoteSize) return; + buf += remoteSize; len -= remoteSize; boost::asio::ip::address ourIP; - if (ourSize == 4) - { - boost::asio::ip::address_v4::bytes_type bytes; - memcpy (bytes.data (), buf, 4); - ourIP = boost::asio::ip::address_v4 (bytes); - } - else - { - boost::asio::ip::address_v6::bytes_type bytes; - memcpy (bytes.data (), buf, 16); - ourIP = boost::asio::ip::address_v6 (bytes); - } - buf += ourSize; // our address - uint16_t ourPort = bufbe16toh (buf); - buf += 2; // our port + uint16_t ourPort = 0; + auto ourSize = ExtractIPAddressAndPort (buf, len, ourIP, ourPort); + if (!ourSize) return; + buf += ourSize; len -= ourSize; LogPrint (eLogInfo, "SSU: Our external address is ", ourIP.to_string (), ":", ourPort); i2p::context.UpdateAddress (ourIP); if (ourPort != m_Server.GetPort ()) From 589049ef0f20b0d19480d509386a2aab66ecbada Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 19 Mar 2021 10:20:02 -0400 Subject: [PATCH 09/87] connect to ipv6 address through introducer --- libi2pd/SSU.cpp | 34 +++++++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/libi2pd/SSU.cpp b/libi2pd/SSU.cpp index 3b2dc122..04da5f7c 100644 --- a/libi2pd/SSU.cpp +++ b/libi2pd/SSU.cpp @@ -482,12 +482,16 @@ namespace transport { if (router && router->UsesIntroducer () && address) { + if (address->IsV4 () && !i2p::context.SupportsV4 ()) return; + if (address->IsV6 () && !i2p::context.SupportsV6 ()) return; if (!address->host.is_unspecified () && address->port) { + // we rarely come here + auto& sessions = address->host.is_v6 () ? m_SessionsV6 : m_Sessions; boost::asio::ip::udp::endpoint remoteEndpoint (address->host, address->port); - auto it = m_Sessions.find (remoteEndpoint); + auto it = sessions.find (remoteEndpoint); // check if session is presented already - if (it != m_Sessions.end ()) + if (it != sessions.end ()) { auto session = it->second; if (peerTest && session->GetState () == eSessionStateEstablished) @@ -508,9 +512,9 @@ namespace transport auto intr = &(address->ssu->introducers[i]); if (intr->iExp > 0 && ts > intr->iExp) continue; // skip expired introducer boost::asio::ip::udp::endpoint ep (intr->iHost, intr->iPort); - if (ep.address ().is_v4 ()) // ipv4 only + if (ep.address ().is_v4 () && address->IsV4 ()) // ipv4 { - if (!introducer) introducer = intr; // we pick first one for now + if (!introducer) introducer = intr; auto it = m_Sessions.find (ep); if (it != m_Sessions.end ()) { @@ -518,10 +522,20 @@ namespace transport break; } } + if (ep.address ().is_v6 () && address->IsV6 ()) // ipv6 + { + if (!introducer) introducer = intr; + auto it = m_SessionsV6.find (ep); + if (it != m_SessionsV6.end ()) + { + introducerSession = it->second; + break; + } + } } if (!introducer) { - LogPrint (eLogWarning, "SSU: Can't connect to unreachable router and no ipv4 non-expired introducers presented"); + LogPrint (eLogWarning, "SSU: Can't connect to unreachable router and no compatibe non-expired introducers presented"); return; } @@ -532,14 +546,20 @@ namespace transport LogPrint (eLogDebug, "SSU: Creating new session to introducer ", introducer->iHost); boost::asio::ip::udp::endpoint introducerEndpoint (introducer->iHost, introducer->iPort); introducerSession = std::make_shared (*this, introducerEndpoint, router); - m_Sessions[introducerEndpoint] = introducerSession; + if (introducerEndpoint.address ().is_v4 ()) + m_Sessions[introducerEndpoint] = introducerSession; + else if (introducerEndpoint.address ().is_v6 ()) + m_SessionsV6[introducerEndpoint] = introducerSession; } if (!address->host.is_unspecified () && address->port) { // create session boost::asio::ip::udp::endpoint remoteEndpoint (address->host, address->port); auto session = std::make_shared (*this, remoteEndpoint, router, peerTest); - m_Sessions[remoteEndpoint] = session; + if (address->host.is_v4 ()) + m_Sessions[remoteEndpoint] = session; + else if (address->host.is_v6 ()) + m_SessionsV6[remoteEndpoint] = session; // introduce LogPrint (eLogInfo, "SSU: Introduce new session to [", i2p::data::GetIdentHashAbbreviation (router->GetIdentHash ()), From 991b74f036acae38e717ab1dc1d65ccafd876b12 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 19 Mar 2021 13:10:24 -0400 Subject: [PATCH 10/87] bind ipv6 or yggdrasil acceptor to specified address --- libi2pd/NTCP2.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index ffd9bb7d..e872eeaa 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -1193,7 +1193,12 @@ namespace transport m_NTCP2V6Acceptor->open (boost::asio::ip::tcp::v6()); m_NTCP2V6Acceptor->set_option (boost::asio::ip::v6_only (true)); m_NTCP2V6Acceptor->set_option (boost::asio::socket_base::reuse_address (true)); - m_NTCP2V6Acceptor->bind (boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v6(), address->port)); + auto ep = boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v6(), address->port); + if (m_Address6 && !context.SupportsMesh ()) + ep = boost::asio::ip::tcp::endpoint (m_Address6->address(), address->port); + else if (m_YggdrasilAddress && !context.SupportsV6 ()) + ep = boost::asio::ip::tcp::endpoint (m_YggdrasilAddress->address(), address->port); + m_NTCP2V6Acceptor->bind (ep); m_NTCP2V6Acceptor->listen (); LogPrint (eLogInfo, "NTCP2: Start listening v6 TCP port ", address->port); From ac10f3055d648c8718c668ae772d4f94c0145503 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 19 Mar 2021 21:51:45 -0400 Subject: [PATCH 11/87] pick correct local SSU address for sending peer test --- libi2pd/SSUSession.cpp | 32 ++++++++++---------------------- 1 file changed, 10 insertions(+), 22 deletions(-) diff --git a/libi2pd/SSUSession.cpp b/libi2pd/SSUSession.cpp index d1dc7aec..f7d5214e 100644 --- a/libi2pd/SSUSession.cpp +++ b/libi2pd/SSUSession.cpp @@ -1,5 +1,5 @@ /* -* Copyright (c) 2013-2020, The PurpleI2P Project +* Copyright (c) 2013-2021, The PurpleI2P Project * * This file is part of Purple i2pd project and licensed under BSD3 * @@ -953,15 +953,15 @@ namespace transport void SSUSession::ProcessPeerTest (const uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint) { uint32_t nonce = bufbe32toh (buf); // 4 bytes - uint8_t size = buf[4]; // 1 byte - const uint8_t * address = buf + 5; // big endian, size bytes - uint16_t port = buf16toh(buf + size + 5); // big endian, 2 bytes - const uint8_t * introKey = buf + size + 7; - if (port && (size != 4) && (size != 16)) + boost::asio::ip::address addr; // Alice's addresss + uint16_t port = 0; // and port + auto size = ExtractIPAddressAndPort (buf + 4, len - 4, addr, port); + if (port && (size != 7) && (size != 19)) { - LogPrint (eLogWarning, "SSU: Address of ", size, " bytes not supported"); + LogPrint (eLogWarning, "SSU: Address of ", size - 3, " bytes not supported"); return; } + const uint8_t * introKey = buf + 4 + size; switch (m_Server.GetPeerTestParticipant (nonce)) { // existing test @@ -1027,20 +1027,7 @@ namespace transport LogPrint (eLogDebug, "SSU: peer test from Bob. We are Charlie"); m_Server.NewPeerTest (nonce, ePeerTestParticipantCharlie); Send (PAYLOAD_TYPE_PEER_TEST, buf, len); // back to Bob - boost::asio::ip::address addr; // Alice's address - if (size == 4) // v4 - { - boost::asio::ip::address_v4::bytes_type bytes; - memcpy (bytes.data (), address, 4); - addr = boost::asio::ip::address_v4 (bytes); - } - else // v6 - { - boost::asio::ip::address_v6::bytes_type bytes; - memcpy (bytes.data (), address, 16); - addr = boost::asio::ip::address_v6 (bytes); - } - SendPeerTest (nonce, addr, be16toh (port), introKey); // to Alice with her address received from Bob + SendPeerTest (nonce, addr, port, introKey); // to Alice with her address received from Bob } else { @@ -1097,7 +1084,8 @@ namespace transport if (toAddress) { // send our intro key to address instead of its own - auto addr = i2p::context.GetRouterInfo ().GetSSUAddress (); + auto addr = address.is_v4 () ? i2p::context.GetRouterInfo ().GetSSUAddress (true) : // ipv4 + i2p::context.GetRouterInfo ().GetSSUV6Address (); if (addr) memcpy (payload, addr->ssu->key, 32); // intro key else From 34eee2fc26826b5a9544523d148c8a47f4ccfc73 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 22 Mar 2021 20:12:58 -0400 Subject: [PATCH 12/87] fixed #1644. check leaseset buffer size --- libi2pd/LeaseSet.cpp | 33 ++++++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/libi2pd/LeaseSet.cpp b/libi2pd/LeaseSet.cpp index b90d6d85..2279319a 100644 --- a/libi2pd/LeaseSet.cpp +++ b/libi2pd/LeaseSet.cpp @@ -72,6 +72,12 @@ namespace data } size += 256; // encryption key size += m_Identity->GetSigningPublicKeyLen (); // unused signing key + if (size + 1 > m_BufferLen) + { + LogPrint (eLogError, "LeaseSet: ", size, " exceeds buffer size ", m_BufferLen); + m_IsValid = false; + return; + } uint8_t num = m_Buffer[size]; size++; // num LogPrint (eLogDebug, "LeaseSet: read num=", (int)num); @@ -81,9 +87,14 @@ namespace data m_IsValid = false; return; } - + if (size + num*LEASE_SIZE > m_BufferLen) + { + LogPrint (eLogError, "LeaseSet: ", size, " exceeds buffer size ", m_BufferLen); + m_IsValid = false; + return; + } + UpdateLeasesBegin (); - // process leases m_ExpirationTime = 0; auto ts = i2p::util::GetMillisecondsSinceEpoch (); @@ -106,14 +117,22 @@ namespace data return; } m_ExpirationTime += LEASE_ENDDATE_THRESHOLD; - UpdateLeasesEnd (); // verify - if (verifySignature && !m_Identity->Verify (m_Buffer, leases - m_Buffer, leases)) - { - LogPrint (eLogWarning, "LeaseSet: verification failed"); - m_IsValid = false; + if (verifySignature) + { + auto signedSize = leases - m_Buffer; + if (signedSize + m_Identity->GetSignatureLen () > m_BufferLen) + { + LogPrint (eLogError, "LeaseSet: Signature exceeds buffer size ", m_BufferLen); + m_IsValid = false; + } + else if (!m_Identity->Verify (m_Buffer, signedSize, leases)) + { + LogPrint (eLogWarning, "LeaseSet: verification failed"); + m_IsValid = false; + } } } From 9e050d1a23678f0adbe156a33b343d858e8da7e2 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 23 Mar 2021 15:36:57 -0400 Subject: [PATCH 13/87] peer test for ipv6 --- daemon/HTTPServer.cpp | 23 +++++++++---- libi2pd/NetDb.cpp | 6 ++-- libi2pd/NetDb.hpp | 2 +- libi2pd/RouterContext.cpp | 8 ++++- libi2pd/RouterContext.h | 4 ++- libi2pd/RouterInfo.cpp | 12 +++---- libi2pd/RouterInfo.h | 2 +- libi2pd/SSUSession.cpp | 17 ++++++++-- libi2pd/Transports.cpp | 70 +++++++++++++++++---------------------- 9 files changed, 82 insertions(+), 62 deletions(-) diff --git a/daemon/HTTPServer.cpp b/daemon/HTTPServer.cpp index 4741e5cf..c263cea9 100644 --- a/daemon/HTTPServer.cpp +++ b/daemon/HTTPServer.cpp @@ -242,13 +242,9 @@ namespace http { s << "ERROR: " << string << "
\r\n"; } - void ShowStatus (std::stringstream& s, bool includeHiddenContent, i2p::http::OutputFormatEnum outputFormat) + static void ShowNetworkStatus (std::stringstream& s, RouterStatus status) { - s << "Uptime: "; - ShowUptime(s, i2p::context.GetUptime ()); - s << "
\r\n"; - s << "Network status: "; - switch (i2p::context.GetStatus ()) + switch (status) { case eRouterStatusOK: s << "OK"; break; case eRouterStatusTesting: s << "Testing"; break; @@ -276,7 +272,22 @@ namespace http { } default: s << "Unknown"; } + } + + void ShowStatus (std::stringstream& s, bool includeHiddenContent, i2p::http::OutputFormatEnum outputFormat) + { + s << "Uptime: "; + ShowUptime(s, i2p::context.GetUptime ()); s << "
\r\n"; + s << "Network status: "; + ShowNetworkStatus (s, i2p::context.GetStatus ()); + s << "
\r\n"; + if (i2p::context.SupportsV6 ()) + { + s << "Network status 6: "; + ShowNetworkStatus (s, i2p::context.GetStatusV6 ()); + s << "
\r\n"; + } #if ((!defined(WIN32) && !defined(QT_GUI_LIB) && !defined(ANDROID)) || defined(ANDROID_BINARY)) if (auto remains = Daemon.gracefulShutdownInterval) { s << "Stopping in: "; diff --git a/libi2pd/NetDb.cpp b/libi2pd/NetDb.cpp index 076a8665..a50a796f 100644 --- a/libi2pd/NetDb.cpp +++ b/libi2pd/NetDb.cpp @@ -1149,12 +1149,12 @@ namespace data }); } - std::shared_ptr NetDb::GetRandomPeerTestRouter (bool v4only) const + std::shared_ptr NetDb::GetRandomPeerTestRouter (bool v4) const { return GetRandomRouter ( - [v4only](std::shared_ptr router)->bool + [v4](std::shared_ptr router)->bool { - return !router->IsHidden () && router->IsPeerTesting (v4only); + return !router->IsHidden () && router->IsPeerTesting (v4); }); } diff --git a/libi2pd/NetDb.hpp b/libi2pd/NetDb.hpp index 5dbef743..891bc35d 100644 --- a/libi2pd/NetDb.hpp +++ b/libi2pd/NetDb.hpp @@ -85,7 +85,7 @@ namespace data std::shared_ptr GetRandomRouter () const; std::shared_ptr GetRandomRouter (std::shared_ptr compatibleWith, bool reverse) const; std::shared_ptr GetHighBandwidthRandomRouter (std::shared_ptr compatibleWith, bool reverse) const; - std::shared_ptr GetRandomPeerTestRouter (bool v4only = true) const; + std::shared_ptr GetRandomPeerTestRouter (bool v4) const; std::shared_ptr GetRandomSSUV6Router () const; // TODO: change to v6 peer test later std::shared_ptr GetRandomIntroducer () const; std::shared_ptr GetClosestFloodfill (const IdentHash& destination, const std::set& excluded, bool closeThanUsOnly = false) const; diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index 9451cca5..ff0063a7 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -28,7 +28,7 @@ namespace i2p RouterContext::RouterContext (): m_LastUpdateTime (0), m_AcceptsTunnels (true), m_IsFloodfill (false), - m_ShareRatio (100), m_Status (eRouterStatusUnknown), + m_ShareRatio (100), m_Status (eRouterStatusUnknown), m_StatusV6 (eRouterStatusOK), m_Error (eRouterErrorNone), m_NetID (I2PD_NET_ID) { } @@ -210,6 +210,12 @@ namespace i2p } } + void RouterContext::SetStatusV6 (RouterStatus status) + { + if (status != m_StatusV6) + m_StatusV6 = status; + } + void RouterContext::UpdatePort (int port) { bool updated = false; diff --git a/libi2pd/RouterContext.h b/libi2pd/RouterContext.h index ee66a83c..158dd809 100644 --- a/libi2pd/RouterContext.h +++ b/libi2pd/RouterContext.h @@ -91,6 +91,8 @@ namespace garlic void SetStatus (RouterStatus status); RouterError GetError () const { return m_Error; }; void SetError (RouterError error) { m_Status = eRouterStatusError; m_Error = error; }; + RouterStatus GetStatusV6 () const { return m_StatusV6; }; + void SetStatusV6 (RouterStatus status); int GetNetID () const { return m_NetID; }; void SetNetID (int netID) { m_NetID = netID; }; bool DecryptTunnelBuildRecord (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx); @@ -168,7 +170,7 @@ namespace garlic std::chrono::time_point m_StartupTime; uint64_t m_BandwidthLimit; // allowed bandwidth int m_ShareRatio; - RouterStatus m_Status; + RouterStatus m_Status, m_StatusV6; RouterError m_Error; int m_NetID; std::mutex m_GarlicMutex; diff --git a/libi2pd/RouterInfo.cpp b/libi2pd/RouterInfo.cpp index 2157dd37..53077235 100644 --- a/libi2pd/RouterInfo.cpp +++ b/libi2pd/RouterInfo.cpp @@ -1100,15 +1100,15 @@ namespace data GetIdentity ()->GetSigningKeyType () != SIGNING_KEY_TYPE_DSA_SHA1; } - bool RouterInfo::IsPeerTesting (bool v4only) const + bool RouterInfo::IsPeerTesting (bool v4) const { - auto supportedTransports = m_SupportedTransports & (eSSUV4 | eSSUV6); - if (!supportedTransports) return false; // no SSU - if (v4only && !(supportedTransports & eSSUV4)) return false; // no SSU v4 + auto supportedTransports = m_SupportedTransports & (v4 ? eSSUV4 : eSSUV6); + if (!supportedTransports) return false; return (bool)GetAddress ( - [](std::shared_ptr address)->bool + [v4](std::shared_ptr address)->bool { - return (address->transportStyle == eTransportSSU) && address->IsPeerTesting (); + return (address->transportStyle == eTransportSSU) && address->IsPeerTesting () && + ((v4 && address->IsV4 ()) || (!v4 && address->IsV6 ())); }); } diff --git a/libi2pd/RouterInfo.h b/libi2pd/RouterInfo.h index 93746e95..72818931 100644 --- a/libi2pd/RouterInfo.h +++ b/libi2pd/RouterInfo.h @@ -209,7 +209,7 @@ namespace data bool IsHighBandwidth () const { return m_Caps & RouterInfo::eHighBandwidth; }; bool IsExtraBandwidth () const { return m_Caps & RouterInfo::eExtraBandwidth; }; bool IsEligibleFloodfill () const; - bool IsPeerTesting (bool v4only) const; + bool IsPeerTesting (bool v4) const; bool IsIntroducer () const; uint8_t GetCaps () const { return m_Caps; }; diff --git a/libi2pd/SSUSession.cpp b/libi2pd/SSUSession.cpp index f7d5214e..66579a16 100644 --- a/libi2pd/SSUSession.cpp +++ b/libi2pd/SSUSession.cpp @@ -970,7 +970,12 @@ namespace transport if (m_Server.GetPeerTestSession (nonce) == shared_from_this ()) // Alice-Bob { LogPrint (eLogDebug, "SSU: peer test from Bob. We are Alice"); - if (i2p::context.GetStatus () == eRouterStatusTesting) // still not OK + if (IsV6 ()) + { + if (i2p::context.GetStatusV6 () == eRouterStatusTesting) + i2p::context.SetStatusV6 (eRouterStatusFirewalled); + } + else if (i2p::context.GetStatus () == eRouterStatusTesting) // still not OK { i2p::context.SetStatus (eRouterStatusFirewalled); m_Server.RescheduleIntroducersUpdateTimer (); @@ -981,7 +986,10 @@ namespace transport LogPrint (eLogDebug, "SSU: first peer test from Charlie. We are Alice"); if (m_State == eSessionStateEstablished) LogPrint (eLogWarning, "SSU: first peer test from Charlie through established session. We are Alice"); - i2p::context.SetStatus (eRouterStatusOK); + if (IsV6 ()) + i2p::context.SetStatusV6 (eRouterStatusOK); + else + i2p::context.SetStatus (eRouterStatusOK); m_Server.UpdatePeerTest (nonce, ePeerTestParticipantAlice2); SendPeerTest (nonce, senderEndpoint.address (), senderEndpoint.port (), introKey, true, false); // to Charlie } @@ -995,7 +1003,10 @@ namespace transport { // peer test successive LogPrint (eLogDebug, "SSU: second peer test from Charlie. We are Alice"); - i2p::context.SetStatus (eRouterStatusOK); + if (IsV6 ()) + i2p::context.SetStatusV6 (eRouterStatusOK); + else + i2p::context.SetStatus (eRouterStatusOK); m_Server.RemovePeerTest (nonce); } break; diff --git a/libi2pd/Transports.cpp b/libi2pd/Transports.cpp index 9f3e75b7..78b45e32 100644 --- a/libi2pd/Transports.cpp +++ b/libi2pd/Transports.cpp @@ -576,55 +576,21 @@ namespace transport return; } if (m_SSUServer) - { - bool isv4 = i2p::context.SupportsV4 (); - if (m_IsNAT && isv4) - i2p::context.SetStatus (eRouterStatusTesting); - for (int i = 0; i < 5; i++) - { - auto router = i2p::data::netdb.GetRandomPeerTestRouter (isv4); // v4 only if v4 - if (router) - m_SSUServer->CreateSession (router, true, isv4); // peer test - else - { - // if not peer test capable routers found pick any - router = i2p::data::netdb.GetRandomRouter (); - if (router && router->IsSSU ()) - m_SSUServer->CreateSession (router); // no peer test - } - } - if (i2p::context.SupportsV6 ()) - { - // try to connect to few v6 addresses to get our address back - for (int i = 0; i < 3; i++) - { - auto router = i2p::data::netdb.GetRandomSSUV6Router (); - if (router) - { - auto addr = router->GetSSUV6Address (); - if (addr) - m_SSUServer->GetService ().post ([this, router, addr] - { - m_SSUServer->CreateDirectSession (router, { addr->host, (uint16_t)addr->port }, false); - }); - } - } - } - } + PeerTest (); else LogPrint (eLogError, "Transports: Can't detect external IP. SSU is not available"); } void Transports::PeerTest () { - if (RoutesRestricted() || !i2p::context.SupportsV4 ()) return; - if (m_SSUServer) + if (RoutesRestricted() || !m_SSUServer) return; + if (i2p::context.SupportsV4 ()) { - LogPrint (eLogInfo, "Transports: Started peer test"); + LogPrint (eLogInfo, "Transports: Started peer test ipv4"); bool statusChanged = false; for (int i = 0; i < 5; i++) { - auto router = i2p::data::netdb.GetRandomPeerTestRouter (true); // v4 only + auto router = i2p::data::netdb.GetRandomPeerTestRouter (true); // v4 if (router) { if (!statusChanged) @@ -636,8 +602,32 @@ namespace transport } } if (!statusChanged) - LogPrint (eLogWarning, "Transports: Can't find routers for peer test"); + LogPrint (eLogWarning, "Transports: Can't find routers for peer test ipv4"); } + if (i2p::context.SupportsV6 ()) + { + LogPrint (eLogInfo, "Transports: Started peer test ipv6"); + bool statusChanged = false; + for (int i = 0; i < 5; i++) + { + auto router = i2p::data::netdb.GetRandomPeerTestRouter (false); // v6 + if (router) + { + auto addr = router->GetSSUV6Address (); + if (addr) + { + if (!statusChanged) + { + statusChanged = true; + i2p::context.SetStatusV6 (eRouterStatusTesting); // first time only + } + m_SSUServer->CreateSession (router, addr, true); // peer test v6 + } + } + } + if (!statusChanged) + LogPrint (eLogWarning, "Transports: Can't find routers for peer test ipv6"); + } } std::shared_ptr Transports::GetNextX25519KeysPair () From 3695aa924b723f9e25ad66a1f427a15c7bff6ac4 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 24 Mar 2021 10:32:15 -0400 Subject: [PATCH 14/87] doesn't send peer test to a reserved address --- libi2pd/SSUSession.cpp | 22 +++++++++++++--------- libi2pd/Transports.cpp | 16 ++++++++++------ 2 files changed, 23 insertions(+), 15 deletions(-) diff --git a/libi2pd/SSUSession.cpp b/libi2pd/SSUSession.cpp index 66579a16..2e49e970 100644 --- a/libi2pd/SSUSession.cpp +++ b/libi2pd/SSUSession.cpp @@ -273,7 +273,7 @@ namespace transport s.Insert (payload, 8); // relayTag and signed on time m_RelayTag = bufbe32toh (payload); payload += 4; // relayTag - if (i2p::context.GetStatus () == eRouterStatusTesting) + if (ourIP.is_v4 () && i2p::context.GetStatus () == eRouterStatusTesting) { auto ts = i2p::util::GetSecondsSinceEpoch (); uint32_t signedOnTime = bufbe32toh(payload); @@ -358,7 +358,9 @@ namespace transport uint8_t * payload = buf + sizeof (SSUHeader); uint8_t flag = 0; // fill extended options, 3 bytes extended options don't change message size - if (i2p::context.GetStatus () == eRouterStatusOK) // we don't need relays + bool isV4 = m_RemoteEndpoint.address ().is_v4 (); + if ((isV4 && i2p::context.GetStatus () == eRouterStatusOK) || + (!isV4 && i2p::context.GetStatusV6 () == eRouterStatusOK)) // we don't need relays { // tell out peer to now assign relay tag flag = SSU_HEADER_EXTENDED_OPTIONS_INCLUDED; @@ -369,7 +371,6 @@ namespace transport } // fill payload memcpy (payload, m_DHKeysPair->GetPublicKey (), 256); // x - bool isV4 = m_RemoteEndpoint.address ().is_v4 (); if (isV4) { payload[256] = 4; @@ -657,13 +658,16 @@ namespace transport buf += ourSize; len -= ourSize; LogPrint (eLogInfo, "SSU: Our external address is ", ourIP.to_string (), ":", ourPort); i2p::context.UpdateAddress (ourIP); - if (ourPort != m_Server.GetPort ()) + if (ourIP.is_v4 ()) { - if (i2p::context.GetStatus () == eRouterStatusTesting) - i2p::context.SetError (eRouterErrorSymmetricNAT); - } - else if (i2p::context.GetStatus () == eRouterStatusError && i2p::context.GetError () == eRouterErrorSymmetricNAT) - i2p::context.SetStatus (eRouterStatusTesting); + if (ourPort != m_Server.GetPort ()) + { + if (i2p::context.GetStatus () == eRouterStatusTesting) + i2p::context.SetError (eRouterErrorSymmetricNAT); + } + else if (i2p::context.GetStatus () == eRouterStatusError && i2p::context.GetError () == eRouterErrorSymmetricNAT) + i2p::context.SetStatus (eRouterStatusTesting); + } uint32_t nonce = bufbe32toh (buf); buf += 4; // nonce auto it = m_RelayRequests.find (nonce); diff --git a/libi2pd/Transports.cpp b/libi2pd/Transports.cpp index 78b45e32..13c1d210 100644 --- a/libi2pd/Transports.cpp +++ b/libi2pd/Transports.cpp @@ -593,12 +593,16 @@ namespace transport auto router = i2p::data::netdb.GetRandomPeerTestRouter (true); // v4 if (router) { - if (!statusChanged) + auto addr = router->GetSSUAddress (true); // ipv4 + if (addr && !i2p::util::net::IsInReservedRange(addr->host)) { - statusChanged = true; - i2p::context.SetStatus (eRouterStatusTesting); // first time only - } - m_SSUServer->CreateSession (router, true, true); // peer test v4 + if (!statusChanged) + { + statusChanged = true; + i2p::context.SetStatus (eRouterStatusTesting); // first time only + } + m_SSUServer->CreateSession (router, addr, true); // peer test v4 + } } } if (!statusChanged) @@ -614,7 +618,7 @@ namespace transport if (router) { auto addr = router->GetSSUV6Address (); - if (addr) + if (addr && !i2p::util::net::IsInReservedRange(addr->host)) { if (!statusChanged) { From a6ea37a21ed637d4c5220455ca64843626b9da83 Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 27 Mar 2021 15:16:56 -0400 Subject: [PATCH 15/87] set ipv6 address caps depending on peer test --- libi2pd/RouterContext.cpp | 37 +++++++++++++++++++++++++------------ libi2pd/RouterContext.h | 4 ++-- libi2pd/SSU.cpp | 2 +- 3 files changed, 28 insertions(+), 15 deletions(-) diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index ff0063a7..fadbb51a 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -28,7 +28,7 @@ namespace i2p RouterContext::RouterContext (): m_LastUpdateTime (0), m_AcceptsTunnels (true), m_IsFloodfill (false), - m_ShareRatio (100), m_Status (eRouterStatusUnknown), m_StatusV6 (eRouterStatusOK), + m_ShareRatio (100), m_Status (eRouterStatusUnknown), m_StatusV6 (eRouterStatusUnknown), m_Error (eRouterErrorNone), m_NetID (I2PD_NET_ID) { } @@ -199,10 +199,10 @@ namespace i2p switch (m_Status) { case eRouterStatusOK: - SetReachable (); + SetReachable (true, false); // ipv4 break; case eRouterStatusFirewalled: - SetUnreachable (); + SetUnreachable (true, false); // ipv4 break; default: ; @@ -213,7 +213,20 @@ namespace i2p void RouterContext::SetStatusV6 (RouterStatus status) { if (status != m_StatusV6) + { m_StatusV6 = status; + switch (m_StatusV6) + { + case eRouterStatusOK: + SetReachable (false, true); // ipv6 + break; + case eRouterStatusFirewalled: + SetUnreachable (false, true); // ipv6 + break; + default: + ; + } + } } void RouterContext::UpdatePort (int port) @@ -443,7 +456,7 @@ namespace i2p } } - void RouterContext::SetUnreachable () + void RouterContext::SetUnreachable (bool v4, bool v6) { // set caps uint8_t caps = m_RouterInfo.GetCaps (); @@ -455,22 +468,22 @@ namespace i2p // delete previous introducers auto& addresses = m_RouterInfo.GetAddresses (); for (auto& addr : addresses) - if (addr->ssu) + if (addr->ssu && ((v4 && addr->IsV4 ()) || (v6 && addr->IsV6 ()))) { addr->cost = i2p::data::COST_SSU_THROUGH_INTRODUCERS; addr->caps &= ~i2p::data::RouterInfo::eSSUIntroducer; // can't be introducer addr->ssu->introducers.clear (); port = addr->port; } - // remove NTCP2 v4 address + // unpiblish NTCP2 addreeses bool ntcp2; i2p::config::GetOption("ntcp2.enabled", ntcp2); if (ntcp2) - PublishNTCP2Address (port, false, true, false, false); // ipv4 only + PublishNTCP2Address (port, false, v4, v6, false); // update UpdateRouterInfo (); } - void RouterContext::SetReachable () + void RouterContext::SetReachable (bool v4, bool v6) { // update caps uint8_t caps = m_RouterInfo.GetCaps (); @@ -483,14 +496,14 @@ namespace i2p // delete previous introducers auto& addresses = m_RouterInfo.GetAddresses (); for (auto& addr : addresses) - if (addr->ssu) + if (addr->ssu && ((v4 && addr->IsV4 ()) || (v6 && addr->IsV6 ()))) { addr->cost = i2p::data::COST_SSU_DIRECT; addr->caps |= i2p::data::RouterInfo::eSSUIntroducer; addr->ssu->introducers.clear (); port = addr->port; } - // insert NTCP2 back + // publish NTCP2 bool ntcp2; i2p::config::GetOption("ntcp2.enabled", ntcp2); if (ntcp2) { @@ -499,7 +512,7 @@ namespace i2p { uint16_t ntcp2Port; i2p::config::GetOption ("ntcp2.port", ntcp2Port); if (!ntcp2Port) ntcp2Port = port; - PublishNTCP2Address (ntcp2Port, true, true, false, false); // ipv4 only + PublishNTCP2Address (ntcp2Port, true, v4, v6, false); } } // update @@ -757,7 +770,7 @@ namespace i2p } if (IsUnreachable ()) - SetReachable (); // we assume reachable until we discover firewall through peer tests + SetReachable (true, true); // we assume reachable until we discover firewall through peer tests // read NTCP2 bool ntcp2; i2p::config::GetOption("ntcp2.enabled", ntcp2); diff --git a/libi2pd/RouterContext.h b/libi2pd/RouterContext.h index 158dd809..a7594e36 100644 --- a/libi2pd/RouterContext.h +++ b/libi2pd/RouterContext.h @@ -105,8 +105,8 @@ namespace garlic bool AddIntroducer (const i2p::data::RouterInfo::Introducer& introducer); void RemoveIntroducer (const boost::asio::ip::udp::endpoint& e); bool IsUnreachable () const; - void SetUnreachable (); - void SetReachable (); + void SetUnreachable (bool v4, bool v6); + void SetReachable (bool v4, bool v6); bool IsFloodfill () const { return m_IsFloodfill; }; void SetFloodfill (bool floodfill); void SetFamily (const std::string& family); diff --git a/libi2pd/SSU.cpp b/libi2pd/SSU.cpp index 04da5f7c..b9b3a04e 100644 --- a/libi2pd/SSU.cpp +++ b/libi2pd/SSU.cpp @@ -706,7 +706,7 @@ namespace transport return; } // we are firewalled - if (!i2p::context.IsUnreachable ()) i2p::context.SetUnreachable (); + if (!i2p::context.IsUnreachable ()) i2p::context.SetUnreachable (true, false); // ipv4 std::list newList; size_t numIntroducers = 0; uint32_t ts = i2p::util::GetSecondsSinceEpoch (); From 86415bc61f784922399ea2df719ba6469fbf5eb7 Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 27 Mar 2021 18:49:35 -0400 Subject: [PATCH 16/87] publish introducer cap for ipv6 address --- libi2pd/RouterInfo.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libi2pd/RouterInfo.cpp b/libi2pd/RouterInfo.cpp index 53077235..1644d93d 100644 --- a/libi2pd/RouterInfo.cpp +++ b/libi2pd/RouterInfo.cpp @@ -558,7 +558,10 @@ namespace data caps += CAPS_FLAG_V4; } else if (address.host.is_v6 ()) + { isPublished = true; + if (address.IsIntroducer ()) caps += CAPS_FLAG_SSU_INTRODUCER; + } else { if (address.caps & AddressCaps::eV4) caps += CAPS_FLAG_V4; From 167d3a0e3cdaad6b3b82cea9835359855b896a8a Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 28 Mar 2021 12:14:02 -0400 Subject: [PATCH 17/87] don't create BN_CTX for ECIES tunnel build record decryption --- libi2pd/I2NPProtocol.cpp | 5 +---- libi2pd/RouterContext.cpp | 11 ++++++++--- libi2pd/RouterContext.h | 2 +- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/libi2pd/I2NPProtocol.cpp b/libi2pd/I2NPProtocol.cpp index 6897148b..7f059d72 100644 --- a/libi2pd/I2NPProtocol.cpp +++ b/libi2pd/I2NPProtocol.cpp @@ -371,10 +371,7 @@ namespace i2p if (!memcmp (record + BUILD_REQUEST_RECORD_TO_PEER_OFFSET, (const uint8_t *)i2p::context.GetRouterInfo ().GetIdentHash (), 16)) { LogPrint (eLogDebug, "I2NP: Build request record ", i, " is ours"); - BN_CTX * ctx = BN_CTX_new (); - bool success = i2p::context.DecryptTunnelBuildRecord (record + BUILD_REQUEST_RECORD_ENCRYPTED_OFFSET, clearText, ctx); - BN_CTX_free (ctx); - if(!success) return false; + if (!i2p::context.DecryptTunnelBuildRecord (record + BUILD_REQUEST_RECORD_ENCRYPTED_OFFSET, clearText)) return false; uint8_t retCode = 0; bool isECIES = i2p::context.IsECIES (); // replace record to reply diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index fadbb51a..4d1cdec3 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -865,7 +865,7 @@ namespace i2p return m_Decryptor ? m_Decryptor->Decrypt (encrypted, data, ctx, true) : false; } - bool RouterContext::DecryptTunnelBuildRecord (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx) + bool RouterContext::DecryptTunnelBuildRecord (const uint8_t * encrypted, uint8_t * data) { if (!m_TunnelDecryptor) return false; if (IsECIES ()) @@ -875,7 +875,7 @@ namespace i2p m_CurrentNoiseState.reset (new i2p::crypto::NoiseSymmetricState (*m_InitialNoiseState)); m_CurrentNoiseState->MixHash (encrypted, 32); // h = SHA256(h || sepk) uint8_t sharedSecret[32]; - if (!m_TunnelDecryptor->Decrypt (encrypted, sharedSecret, ctx, false)) + if (!m_TunnelDecryptor->Decrypt (encrypted, sharedSecret, nullptr, false)) { LogPrint (eLogWarning, "Router: Incorrect ephemeral public key"); return false; @@ -894,7 +894,12 @@ namespace i2p return true; } else - return m_TunnelDecryptor->Decrypt (encrypted, data, ctx, false); + { + BN_CTX * ctx = BN_CTX_new (); + bool success = m_TunnelDecryptor->Decrypt (encrypted, data, ctx, false); + BN_CTX_free (ctx); + return success; + } } i2p::crypto::X25519Keys& RouterContext::GetStaticKeys () diff --git a/libi2pd/RouterContext.h b/libi2pd/RouterContext.h index a7594e36..a4d18f82 100644 --- a/libi2pd/RouterContext.h +++ b/libi2pd/RouterContext.h @@ -95,7 +95,7 @@ namespace garlic void SetStatusV6 (RouterStatus status); int GetNetID () const { return m_NetID; }; void SetNetID (int netID) { m_NetID = netID; }; - bool DecryptTunnelBuildRecord (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx); + bool DecryptTunnelBuildRecord (const uint8_t * encrypted, uint8_t * data); void UpdatePort (int port); // called from Daemon void UpdateAddress (const boost::asio::ip::address& host); // called from SSU or Daemon From edf3b7e2fcee704a1dab809545597257b3f3a8ff Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 28 Mar 2021 13:13:00 -0400 Subject: [PATCH 18/87] set X bandiwth for floodfill by default --- daemon/Daemon.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/daemon/Daemon.cpp b/daemon/Daemon.cpp index 9fffe5a8..c87de4aa 100644 --- a/daemon/Daemon.cpp +++ b/daemon/Daemon.cpp @@ -280,7 +280,7 @@ namespace util else if (isFloodfill) { LogPrint(eLogInfo, "Daemon: floodfill bandwidth set to 'extra'"); - i2p::context.SetBandwidth (i2p::data::CAPS_FLAG_EXTRA_BANDWIDTH1); + i2p::context.SetBandwidth (i2p::data::CAPS_FLAG_EXTRA_BANDWIDTH2); } else { From 2b0d18a6d745cb5e6dbaaf9b16f2ef73326afca9 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 29 Mar 2021 14:44:50 -0400 Subject: [PATCH 19/87] don't change router status from ipv6 --- libi2pd/RouterContext.cpp | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index 4d1cdec3..48240c89 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -458,12 +458,15 @@ namespace i2p void RouterContext::SetUnreachable (bool v4, bool v6) { - // set caps - uint8_t caps = m_RouterInfo.GetCaps (); - caps &= ~i2p::data::RouterInfo::eReachable; - caps |= i2p::data::RouterInfo::eUnreachable; - caps &= ~i2p::data::RouterInfo::eFloodfill; // can't be floodfill - m_RouterInfo.SetCaps (caps); + if (v4) + { + // set caps + uint8_t caps = m_RouterInfo.GetCaps (); + caps &= ~i2p::data::RouterInfo::eReachable; + caps |= i2p::data::RouterInfo::eUnreachable; + caps &= ~i2p::data::RouterInfo::eFloodfill; // can't be floodfill + m_RouterInfo.SetCaps (caps); + } uint16_t port = 0; // delete previous introducers auto& addresses = m_RouterInfo.GetAddresses (); @@ -485,13 +488,16 @@ namespace i2p void RouterContext::SetReachable (bool v4, bool v6) { - // update caps - uint8_t caps = m_RouterInfo.GetCaps (); - caps &= ~i2p::data::RouterInfo::eUnreachable; - caps |= i2p::data::RouterInfo::eReachable; - if (m_IsFloodfill) - caps |= i2p::data::RouterInfo::eFloodfill; - m_RouterInfo.SetCaps (caps); + if (v4) + { + // update caps + uint8_t caps = m_RouterInfo.GetCaps (); + caps &= ~i2p::data::RouterInfo::eUnreachable; + caps |= i2p::data::RouterInfo::eReachable; + if (m_IsFloodfill) + caps |= i2p::data::RouterInfo::eFloodfill; + m_RouterInfo.SetCaps (caps); + } uint16_t port = 0; // delete previous introducers auto& addresses = m_RouterInfo.GetAddresses (); From 8462d382f4e5ab12e2b6b01c071cf83dce63f22d Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 29 Mar 2021 15:16:39 -0400 Subject: [PATCH 20/87] don't create SSU session for HolePunch --- libi2pd/SSU.cpp | 4 ++-- libi2pd/SSUSession.cpp | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/libi2pd/SSU.cpp b/libi2pd/SSU.cpp index b9b3a04e..111f9407 100644 --- a/libi2pd/SSU.cpp +++ b/libi2pd/SSU.cpp @@ -1,5 +1,5 @@ /* -* Copyright (c) 2013-2020, The PurpleI2P Project +* Copyright (c) 2013-2021, The PurpleI2P Project * * This file is part of Purple i2pd project and licensed under BSD3 * @@ -385,7 +385,7 @@ namespace transport auto it = sessions->find (packet->from); if (it != sessions->end ()) session = it->second; - if (!session) + if (!session && packet->len > 0) { session = std::make_shared (*this, packet->from); session->WaitForConnect (); diff --git a/libi2pd/SSUSession.cpp b/libi2pd/SSUSession.cpp index 2e49e970..09be219f 100644 --- a/libi2pd/SSUSession.cpp +++ b/libi2pd/SSUSession.cpp @@ -418,6 +418,7 @@ namespace transport else FillHeaderAndEncrypt (PAYLOAD_TYPE_RELAY_REQUEST, buf, 96, introducer.iKey, iv, introducer.iKey); m_Server.Send (buf, 96, m_RemoteEndpoint); + LogPrint (eLogDebug, "SSU: relay request sent"); } void SSUSession::SendSessionCreated (const uint8_t * x, bool sendRelayTag) @@ -682,6 +683,7 @@ namespace transport LogPrint (eLogInfo, "SSU: RelayReponse connecting to endpoint ", remoteEndpoint); if (i2p::context.GetRouterInfo ().UsesIntroducer ()) // if we are unreachable m_Server.Send (buf, 0, remoteEndpoint); // send HolePunch + // we assume that HolePunch has been sent by this time and our SessionRequest will go through m_Server.CreateDirectSession (it->second, remoteEndpoint, false); } // delete request From 5cca5472e615cb76ea13270dc69e1c8d123931ee Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 29 Mar 2021 15:50:33 -0400 Subject: [PATCH 21/87] don't handle unsilicited HolePunch --- libi2pd/SSU.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libi2pd/SSU.cpp b/libi2pd/SSU.cpp index 111f9407..2ee0d2a4 100644 --- a/libi2pd/SSU.cpp +++ b/libi2pd/SSU.cpp @@ -393,7 +393,8 @@ namespace transport LogPrint (eLogDebug, "SSU: new session from ", packet->from.address ().to_string (), ":", packet->from.port (), " created"); } } - session->ProcessNextMessage (packet->buf, packet->len, packet->from); + if (session) + session->ProcessNextMessage (packet->buf, packet->len, packet->from); } catch (std::exception& ex) { From 25eae3c1162c401d99b134944fca04d0ff1881ea Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 30 Mar 2021 11:31:11 -0400 Subject: [PATCH 22/87] return relay tag for ipv6 introducer --- libi2pd/NetDb.cpp | 2 +- libi2pd/RouterInfo.cpp | 13 ++++++------- libi2pd/RouterInfo.h | 2 +- libi2pd/SSUSession.cpp | 4 ++-- 4 files changed, 10 insertions(+), 11 deletions(-) diff --git a/libi2pd/NetDb.cpp b/libi2pd/NetDb.cpp index a50a796f..18228d72 100644 --- a/libi2pd/NetDb.cpp +++ b/libi2pd/NetDb.cpp @@ -1172,7 +1172,7 @@ namespace data return GetRandomRouter ( [](std::shared_ptr router)->bool { - return router->IsIntroducer () && !router->IsHidden () && !router->IsFloodfill (); // floodfills don't send relay tag + return router->IsIntroducer (true) && !router->IsHidden () && !router->IsFloodfill (); // floodfills don't send relay tag }); } diff --git a/libi2pd/RouterInfo.cpp b/libi2pd/RouterInfo.cpp index 1644d93d..554be691 100644 --- a/libi2pd/RouterInfo.cpp +++ b/libi2pd/RouterInfo.cpp @@ -1105,8 +1105,7 @@ namespace data bool RouterInfo::IsPeerTesting (bool v4) const { - auto supportedTransports = m_SupportedTransports & (v4 ? eSSUV4 : eSSUV6); - if (!supportedTransports) return false; + if (!(m_SupportedTransports & (v4 ? eSSUV4 : eSSUV6))) return false; return (bool)GetAddress ( [v4](std::shared_ptr address)->bool { @@ -1115,14 +1114,14 @@ namespace data }); } - bool RouterInfo::IsIntroducer () const + bool RouterInfo::IsIntroducer (bool v4) const { - // TODO: support ipv6 - if (!(m_SupportedTransports & eSSUV4)) return false; + if (!(m_SupportedTransports & (v4 ? eSSUV4 : eSSUV6))) return false; return (bool)GetAddress ( - [](std::shared_ptr address)->bool + [v4](std::shared_ptr address)->bool { - return (address->transportStyle == eTransportSSU) && address->IsIntroducer (); + return (address->transportStyle == eTransportSSU) && address->IsIntroducer () && + ((v4 && address->IsV4 ()) || (!v4 && address->IsV6 ())); }); } diff --git a/libi2pd/RouterInfo.h b/libi2pd/RouterInfo.h index 72818931..8572741d 100644 --- a/libi2pd/RouterInfo.h +++ b/libi2pd/RouterInfo.h @@ -210,7 +210,7 @@ namespace data bool IsExtraBandwidth () const { return m_Caps & RouterInfo::eExtraBandwidth; }; bool IsEligibleFloodfill () const; bool IsPeerTesting (bool v4) const; - bool IsIntroducer () const; + bool IsIntroducer (bool v4) const; uint8_t GetCaps () const { return m_Caps; }; void SetCaps (uint8_t caps); diff --git a/libi2pd/SSUSession.cpp b/libi2pd/SSUSession.cpp index 09be219f..d699f2c4 100644 --- a/libi2pd/SSUSession.cpp +++ b/libi2pd/SSUSession.cpp @@ -212,7 +212,7 @@ namespace transport { uint8_t extendedOptionsLen = buf[headerSize]; headerSize++; - if (extendedOptionsLen >= 3) // options are presented + if (extendedOptionsLen >= 2) // options are presented { uint16_t flags = bufbe16toh (buf + headerSize); sendRelayTag = flags & EXTENDED_OPTIONS_FLAG_REQUEST_RELAY_TAG; @@ -464,7 +464,7 @@ namespace transport else s.Insert (address->host.to_v6 ().to_bytes ().data (), 16); // our IP V6 s.Insert (htobe16 (address->port)); // our port - if (sendRelayTag && i2p::context.GetRouterInfo ().IsIntroducer () && !IsV6 ()) + if (sendRelayTag && i2p::context.GetRouterInfo ().IsIntroducer (!IsV6 ())) { RAND_bytes((uint8_t *)&m_SentRelayTag, 4); if (!m_SentRelayTag) m_SentRelayTag = 1; From bd7328345fff56ad37758f453d94268b1c5c0aba Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 30 Mar 2021 19:27:40 -0400 Subject: [PATCH 23/87] Don't change Yddrasil address if router becomes unreachable through ipv6 --- libi2pd/RouterContext.cpp | 35 ++++++++++++++++++++++------------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index 48240c89..e1e19604 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -250,21 +250,30 @@ namespace i2p bool updated = false; for (auto& address : m_RouterInfo.GetAddresses ()) { - if (address->IsNTCP2 () && (address->port != port || address->ntcp2->isPublished != publish) - && ((v4 && address->IsV4 ()) || (v6 && address->IsV6 ()) || - (ygg && i2p::util::net::IsYggdrasilAddress (address->host)))) + if (address->IsNTCP2 () && (address->port != port || address->ntcp2->isPublished != publish)) { - if (!port && !address->port) - { - // select random port only if address's port is not set - port = rand () % (30777 - 9111) + 9111; // I2P network ports range - if (port == 9150) port = 9151; // Tor browser + bool isAddr = v4 && address->IsV4 (); + if (!isAddr && (v6 || ygg)) + { + if (i2p::util::net::IsYggdrasilAddress (address->host)) + isAddr = ygg; + else + isAddr = v6 && address->IsV6 (); } - if (port) address->port = port; - address->cost = publish ? i2p::data::COST_NTCP2_PUBLISHED : i2p::data::COST_NTCP2_NON_PUBLISHED; - address->ntcp2->isPublished = publish; - address->ntcp2->iv = m_NTCP2Keys->iv; - updated = true; + if (isAddr) + { + if (!port && !address->port) + { + // select random port only if address's port is not set + port = rand () % (30777 - 9111) + 9111; // I2P network ports range + if (port == 9150) port = 9151; // Tor browser + } + if (port) address->port = port; + address->cost = publish ? i2p::data::COST_NTCP2_PUBLISHED : i2p::data::COST_NTCP2_NON_PUBLISHED; + address->ntcp2->isPublished = publish; + address->ntcp2->iv = m_NTCP2Keys->iv; + updated = true; + } } } if (updated) From f3b728d82841373a36bc213ac0ce26968fcc8506 Mon Sep 17 00:00:00 2001 From: acetone <63557806+acetoneRu@users.noreply.github.com> Date: Wed, 31 Mar 2021 08:45:56 -0400 Subject: [PATCH 24/87] Yggdrasil configuration added [meshnets] section --- contrib/i2pd.conf | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/contrib/i2pd.conf b/contrib/i2pd.conf index 0c2ec5bc..3fb585c2 100644 --- a/contrib/i2pd.conf +++ b/contrib/i2pd.conf @@ -171,6 +171,13 @@ enabled = true ## Name i2pd appears in UPnP forwardings list (default = I2Pd) # name = I2Pd +[meshnets] +## Enable connectivity over the Yggdrasil network +# yggdrasil = false +## You can bind address from your Yggdrasil subnet 300::/64 +## The address must first be added to the network interface +# yggaddress = + [reseed] ## Options for bootstrapping into I2P network, aka reseeding ## Enable or disable reseed data verification. @@ -195,7 +202,7 @@ verify = true ## Default: reg.i2p at "mainline" I2P Network # defaulturl = http://shx5vqsw7usdaunyzr2qmes2fq37oumybpudrd4jjj4e4vk4uusa.b32.i2p/hosts.txt ## Optional subscriptions URLs, separated by comma -# subscriptions = http://inr.i2p/export/alive-hosts.txt,http://stats.i2p/cgi-bin/newhosts.txt,http://rus.i2p/hosts.txt +# subscriptions = http://identiguy.i2p/hosts.txt,http://stats.i2p/cgi-bin/newhosts.txt,http://rus.i2p/hosts.txt [limits] ## Maximum active transit sessions (default:2500) From 22865f8ee4f68ddae68f3a2bcaa2cf010d43c5fb Mon Sep 17 00:00:00 2001 From: acetone <63557806+acetoneRu@users.noreply.github.com> Date: Wed, 31 Mar 2021 12:05:23 -0400 Subject: [PATCH 25/87] reseed.yggurl and persist.addressbook added --- contrib/i2pd.conf | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/contrib/i2pd.conf b/contrib/i2pd.conf index 3fb585c2..bc3554fa 100644 --- a/contrib/i2pd.conf +++ b/contrib/i2pd.conf @@ -185,6 +185,8 @@ verify = true ## URLs to request reseed data from, separated by comma ## Default: "mainline" I2P Network reseeds # urls = https://reseed.i2p-projekt.de/,https://i2p.mooo.com/netDb/,https://netdb.i2p2.no/ +## Reseed URLs through the Yggdrasil, separated by comma +# yggurls = http://[324:9de3:fea4:f6ac::ace]:7070/ ## Path to local reseed data file (.su3) for manual reseeding # file = /path/to/i2pseeds.su3 ## or HTTPS URL to reseed from @@ -236,6 +238,8 @@ verify = true [persist] ## Save peer profiles on disk (default: true) # profiles = true +## Save full addresses on disk (default: true) +# addressbook = true [cpuext] ## Use CPU AES-NI instructions set when work with cryptography when available (default: true) From 881bca6ae379678f77b55b01affce35eced5d555 Mon Sep 17 00:00:00 2001 From: acetone <63557806+acetoneRu@users.noreply.github.com> Date: Wed, 31 Mar 2021 12:09:06 -0400 Subject: [PATCH 26/87] Depricated "nat" deleted --- contrib/i2pd.conf | 3 --- 1 file changed, 3 deletions(-) diff --git a/contrib/i2pd.conf b/contrib/i2pd.conf index bc3554fa..fa75b68d 100644 --- a/contrib/i2pd.conf +++ b/contrib/i2pd.conf @@ -68,9 +68,6 @@ ipv6 = false ## Enable SSU transport (default = true) # ssu = true -## Should we assume we are behind NAT? (false only in MeshNet) -# nat = true - ## Bandwidth configuration ## L limit bandwidth to 32KBs/sec, O - to 256KBs/sec, P - to 2048KBs/sec, ## X - unlimited From 094541caa6b74a19f94b6cee5c6c4556132451df Mon Sep 17 00:00:00 2001 From: acetone <63557806+acetoneRu@users.noreply.github.com> Date: Wed, 31 Mar 2021 12:16:06 -0400 Subject: [PATCH 27/87] reg.i2p to subscriptions --- contrib/i2pd.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/i2pd.conf b/contrib/i2pd.conf index fa75b68d..523fd41b 100644 --- a/contrib/i2pd.conf +++ b/contrib/i2pd.conf @@ -201,7 +201,7 @@ verify = true ## Default: reg.i2p at "mainline" I2P Network # defaulturl = http://shx5vqsw7usdaunyzr2qmes2fq37oumybpudrd4jjj4e4vk4uusa.b32.i2p/hosts.txt ## Optional subscriptions URLs, separated by comma -# subscriptions = http://identiguy.i2p/hosts.txt,http://stats.i2p/cgi-bin/newhosts.txt,http://rus.i2p/hosts.txt +# subscriptions = http://reg.i2p/hosts.txt,http://identiguy.i2p/hosts.txt,http://stats.i2p/cgi-bin/newhosts.txt,http://rus.i2p/hosts.txt [limits] ## Maximum active transit sessions (default:2500) From 5412352dec60172a5b7abd5cdc75fb8414fe44f7 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 31 Mar 2021 13:42:57 -0400 Subject: [PATCH 28/87] publish ipv6 introducers for ipv6 addresses --- libi2pd/RouterInfo.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/libi2pd/RouterInfo.cpp b/libi2pd/RouterInfo.cpp index 554be691..abe923d1 100644 --- a/libi2pd/RouterInfo.cpp +++ b/libi2pd/RouterInfo.cpp @@ -826,7 +826,8 @@ namespace data { for (auto& addr : *m_Addresses) { - if (addr->transportStyle == eTransportSSU && addr->host.is_v4 ()) + if (addr->transportStyle == eTransportSSU && + ((addr->IsV4 () && introducer.iHost.is_v4 ()) || (addr->IsV6 () && introducer.iHost.is_v6 ()))) { for (auto& intro: addr->ssu->introducers) if (intro.iTag == introducer.iTag) return false; // already presented @@ -841,10 +842,11 @@ namespace data { for (auto& addr: *m_Addresses) { - if (addr->transportStyle == eTransportSSU && addr->host.is_v4 ()) + if (addr->transportStyle == eTransportSSU && + ((addr->IsV4 () && e.address ().is_v4 ()) || (addr->IsV6 () && e.address ().is_v6 ()))) { for (auto it = addr->ssu->introducers.begin (); it != addr->ssu->introducers.end (); ++it) - if ( boost::asio::ip::udp::endpoint (it->iHost, it->iPort) == e) + if (boost::asio::ip::udp::endpoint (it->iHost, it->iPort) == e) { addr->ssu->introducers.erase (it); return true; From 94ca2514af5a5a07d35efa18d84159eee550cf39 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 1 Apr 2021 10:29:03 -0400 Subject: [PATCH 29/87] set zero expiration timeout if no tunnels --- libi2pd/LeaseSet.cpp | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/libi2pd/LeaseSet.cpp b/libi2pd/LeaseSet.cpp index 2279319a..e986092f 100644 --- a/libi2pd/LeaseSet.cpp +++ b/libi2pd/LeaseSet.cpp @@ -862,9 +862,18 @@ namespace data offset += 4; // end date } // update expiration - SetExpirationTime (expirationTime*1000LL); - auto expires = expirationTime - timestamp; - htobe16buf (expiresBuf, expires > 0 ? expires : 0); + if (expirationTime) + { + SetExpirationTime (expirationTime*1000LL); + auto expires = (int)expirationTime - timestamp; + htobe16buf (expiresBuf, expires > 0 ? expires : 0); + } + else + { + // no tunnels or withdraw + SetExpirationTime (timestamp*1000LL); + memset (expiresBuf, 0, 2); // expires immeditely + } // sign keys.Sign (m_Buffer, offset, m_Buffer + offset); // LS + leading store type } From bb5ed0b40c8b58a1c377dbd9452af0d4ad926091 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 1 Apr 2021 11:02:29 -0400 Subject: [PATCH 30/87] assign correct 6 or 4 cap to unpublished address --- libi2pd/RouterInfo.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libi2pd/RouterInfo.cpp b/libi2pd/RouterInfo.cpp index abe923d1..2c5cdd49 100644 --- a/libi2pd/RouterInfo.cpp +++ b/libi2pd/RouterInfo.cpp @@ -529,8 +529,8 @@ namespace data WriteString ("caps", properties); properties << '='; std::string caps; - if (address.caps & AddressCaps::eV4) caps += CAPS_FLAG_V4; - if (address.caps & AddressCaps::eV6) caps += CAPS_FLAG_V6; + if (address.IsV4 ()) caps += CAPS_FLAG_V4; + if (address.IsV6 ()) caps += CAPS_FLAG_V6; if (caps.empty ()) caps += CAPS_FLAG_V4; WriteString (caps, properties); properties << ';'; @@ -564,8 +564,8 @@ namespace data } else { - if (address.caps & AddressCaps::eV4) caps += CAPS_FLAG_V4; - if (address.caps & AddressCaps::eV6) caps += CAPS_FLAG_V6; + if (address.IsV4 ()) caps += CAPS_FLAG_V4; + if (address.IsV6 ()) caps += CAPS_FLAG_V6; if (caps.empty ()) caps += CAPS_FLAG_V4; } WriteString (caps, properties); From 823b499a0207801f17a56024282d824c4921e400 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 1 Apr 2021 11:45:50 -0400 Subject: [PATCH 31/87] remove already expired LeaseSets --- libi2pd/Destination.cpp | 4 ++-- libi2pd/NetDb.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/libi2pd/Destination.cpp b/libi2pd/Destination.cpp index 52ede959..7b8d32d7 100644 --- a/libi2pd/Destination.cpp +++ b/libi2pd/Destination.cpp @@ -386,7 +386,7 @@ namespace client if (leaseSet->IsNewer (buf + offset, len - offset)) { leaseSet->Update (buf + offset, len - offset); - if (leaseSet->IsValid () && leaseSet->GetIdentHash () == key) + if (leaseSet->IsValid () && leaseSet->GetIdentHash () == key && !leaseSet->IsExpired ()) LogPrint (eLogDebug, "Destination: Remote LeaseSet updated"); else { @@ -405,7 +405,7 @@ namespace client leaseSet = std::make_shared (buf + offset, len - offset); // LeaseSet else leaseSet = std::make_shared (buf[DATABASE_STORE_TYPE_OFFSET], buf + offset, len - offset, true, GetPreferredCryptoType () ); // LeaseSet2 - if (leaseSet->IsValid () && leaseSet->GetIdentHash () == key) + if (leaseSet->IsValid () && leaseSet->GetIdentHash () == key && !leaseSet->IsExpired ()) { if (leaseSet->GetIdentHash () != GetIdentHash ()) { diff --git a/libi2pd/NetDb.cpp b/libi2pd/NetDb.cpp index 18228d72..d52f9844 100644 --- a/libi2pd/NetDb.cpp +++ b/libi2pd/NetDb.cpp @@ -336,7 +336,7 @@ namespace data if (it == m_LeaseSets.end () || it->second->GetStoreType () != storeType || leaseSet->GetPublishedTimestamp () > it->second->GetPublishedTimestamp ()) { - if (leaseSet->IsPublic ()) + if (leaseSet->IsPublic () && !leaseSet->IsExpired ()) { // TODO: implement actual update LogPrint (eLogInfo, "NetDb: LeaseSet2 updated: ", ident.ToBase32()); @@ -345,7 +345,7 @@ namespace data } else { - LogPrint (eLogWarning, "NetDb: Unpublished LeaseSet2 received: ", ident.ToBase32()); + LogPrint (eLogWarning, "NetDb: Unpublished or expired LeaseSet2 received: ", ident.ToBase32()); m_LeaseSets.erase (ident); } } From 51ef7ef61cf02cc5bc3b9ea122747b21c643bba8 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 1 Apr 2021 13:37:21 -0400 Subject: [PATCH 32/87] don't publish LeaseSet without tunnels --- libi2pd/Destination.cpp | 8 ++++++-- libi2pd/Destination.h | 4 ++-- libi2pd/LeaseSet.cpp | 2 +- libi2pd/LeaseSet.h | 2 +- libi2pd_client/I2CP.cpp | 2 +- libi2pd_client/I2CP.h | 2 +- 6 files changed, 12 insertions(+), 8 deletions(-) diff --git a/libi2pd/Destination.cpp b/libi2pd/Destination.cpp index 7b8d32d7..f47ac421 100644 --- a/libi2pd/Destination.cpp +++ b/libi2pd/Destination.cpp @@ -300,7 +300,11 @@ namespace client { int numTunnels = m_Pool->GetNumInboundTunnels () + 2; // 2 backup tunnels if (numTunnels > i2p::data::MAX_NUM_LEASES) numTunnels = i2p::data::MAX_NUM_LEASES; // 16 tunnels maximum - CreateNewLeaseSet (m_Pool->GetInboundTunnels (numTunnels)); + auto tunnels = m_Pool->GetInboundTunnels (numTunnels); + if (!tunnels.empty ()) + CreateNewLeaseSet (tunnels); + else + LogPrint (eLogInfo, "Destination: No inbound tunnels for LeaseSet"); } bool LeaseSetDestination::SubmitSessionKey (const uint8_t * key, const uint8_t * tag) @@ -1176,7 +1180,7 @@ namespace client LogPrint(eLogError, "Destinations: Can't save keys to ", path); } - void ClientDestination::CreateNewLeaseSet (std::vector > tunnels) + void ClientDestination::CreateNewLeaseSet (const std::vector >& tunnels) { std::shared_ptr leaseSet; if (GetLeaseSetType () == i2p::data::NETDB_STORE_TYPE_LEASESET) diff --git a/libi2pd/Destination.h b/libi2pd/Destination.h index ffe41212..f04431c7 100644 --- a/libi2pd/Destination.h +++ b/libi2pd/Destination.h @@ -152,7 +152,7 @@ namespace client virtual void CleanupDestination () {}; // additional clean up in derived classes // I2CP virtual void HandleDataMessage (const uint8_t * buf, size_t len) = 0; - virtual void CreateNewLeaseSet (std::vector > tunnels) = 0; + virtual void CreateNewLeaseSet (const std::vector >& tunnels) = 0; private: @@ -262,7 +262,7 @@ namespace client void CleanupDestination (); // I2CP void HandleDataMessage (const uint8_t * buf, size_t len); - void CreateNewLeaseSet (std::vector > tunnels); + void CreateNewLeaseSet (const std::vector >& tunnels); private: diff --git a/libi2pd/LeaseSet.cpp b/libi2pd/LeaseSet.cpp index e986092f..a0b14385 100644 --- a/libi2pd/LeaseSet.cpp +++ b/libi2pd/LeaseSet.cpp @@ -797,7 +797,7 @@ namespace data } LocalLeaseSet2::LocalLeaseSet2 (uint8_t storeType, const i2p::data::PrivateKeys& keys, - const KeySections& encryptionKeys, std::vector > tunnels, + const KeySections& encryptionKeys, const std::vector >& tunnels, bool isPublic, bool isPublishedEncrypted): LocalLeaseSet (keys.GetPublic (), nullptr, 0) { diff --git a/libi2pd/LeaseSet.h b/libi2pd/LeaseSet.h index cd31bf30..cd6535df 100644 --- a/libi2pd/LeaseSet.h +++ b/libi2pd/LeaseSet.h @@ -251,7 +251,7 @@ namespace data LocalLeaseSet2 (uint8_t storeType, const i2p::data::PrivateKeys& keys, const KeySections& encryptionKeys, - std::vector > tunnels, + const std::vector >& tunnels, bool isPublic, bool isPublishedEncrypted = false); LocalLeaseSet2 (uint8_t storeType, std::shared_ptr identity, const uint8_t * buf, size_t len); // from I2CP diff --git a/libi2pd_client/I2CP.cpp b/libi2pd_client/I2CP.cpp index 5cd1812a..d07c6248 100644 --- a/libi2pd_client/I2CP.cpp +++ b/libi2pd_client/I2CP.cpp @@ -84,7 +84,7 @@ namespace client m_Owner->SendMessagePayloadMessage (buf + 4, length); } - void I2CPDestination::CreateNewLeaseSet (std::vector > tunnels) + void I2CPDestination::CreateNewLeaseSet (const std::vector >& tunnels) { GetService ().post (std::bind (&I2CPDestination::PostCreateNewLeaseSet, this, tunnels)); } diff --git a/libi2pd_client/I2CP.h b/libi2pd_client/I2CP.h index 983951a4..085bf30a 100644 --- a/libi2pd_client/I2CP.h +++ b/libi2pd_client/I2CP.h @@ -93,7 +93,7 @@ namespace client // I2CP void HandleDataMessage (const uint8_t * buf, size_t len); - void CreateNewLeaseSet (std::vector > tunnels); + void CreateNewLeaseSet (const std::vector >& tunnels); private: From 43033695f6e911521ee0da56d2863fbc01f9da23 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 2 Apr 2021 21:31:14 -0400 Subject: [PATCH 33/87] select apropriate address for peer test --- libi2pd/SSUSession.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd/SSUSession.cpp b/libi2pd/SSUSession.cpp index d699f2c4..c2fa86a8 100644 --- a/libi2pd/SSUSession.cpp +++ b/libi2pd/SSUSession.cpp @@ -1132,7 +1132,7 @@ namespace transport { // we are Alice LogPrint (eLogDebug, "SSU: sending peer test"); - auto address = i2p::context.GetRouterInfo ().GetSSUAddress (i2p::context.SupportsV4 ()); + auto address = IsV6 () ? i2p::context.GetRouterInfo ().GetSSUV6Address () : i2p::context.GetRouterInfo ().GetSSUAddress (true); if (!address) { LogPrint (eLogInfo, "SSU is not supported. Can't send peer test"); From bea384abea9ad8722027c52be7373c25832429d4 Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 3 Apr 2021 18:56:50 -0400 Subject: [PATCH 34/87] recongnize v4 and v6 SSU addresses without host --- libi2pd/RouterInfo.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libi2pd/RouterInfo.cpp b/libi2pd/RouterInfo.cpp index 2c5cdd49..ed7e3757 100644 --- a/libi2pd/RouterInfo.cpp +++ b/libi2pd/RouterInfo.cpp @@ -1017,7 +1017,7 @@ namespace data return GetAddress ( [v4only](std::shared_ptr address)->bool { - return (address->transportStyle == eTransportSSU) && (!v4only || address->host.is_v4 ()); + return (address->transportStyle == eTransportSSU) && (!v4only || address->IsV4 ()); }); } @@ -1026,7 +1026,7 @@ namespace data return GetAddress ( [](std::shared_ptr address)->bool { - return (address->transportStyle == eTransportSSU) && address->host.is_v6 (); + return (address->transportStyle == eTransportSSU) && address->IsV6(); }); } From 4f3333c841543a9ef00888b5a111cfb8b4a651ef Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 3 Apr 2021 19:24:07 -0400 Subject: [PATCH 35/87] don't check range ffor unspecified address --- libi2pd/util.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libi2pd/util.cpp b/libi2pd/util.cpp index e75b7c19..69fc366a 100644 --- a/libi2pd/util.cpp +++ b/libi2pd/util.cpp @@ -524,6 +524,7 @@ namespace net bool IsInReservedRange (const boost::asio::ip::address& host) { // https://en.wikipedia.org/wiki/Reserved_IP_addresses + if (host.is_unspecified ()) return false; if(host.is_v4()) { static const std::vector< std::pair > reservedIPv4Ranges { From 0f166973cac0fb30cffae59f60c96e0ba876a40b Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 3 Apr 2021 20:03:19 -0400 Subject: [PATCH 36/87] check ureachable cap and actual introducers separately --- libi2pd/NetDb.cpp | 4 ++-- libi2pd/RouterInfo.cpp | 5 ----- libi2pd/RouterInfo.h | 3 ++- libi2pd/SSU.cpp | 6 +++--- libi2pd/SSUSession.cpp | 2 +- 5 files changed, 8 insertions(+), 12 deletions(-) diff --git a/libi2pd/NetDb.cpp b/libi2pd/NetDb.cpp index d52f9844..cfd4bff6 100644 --- a/libi2pd/NetDb.cpp +++ b/libi2pd/NetDb.cpp @@ -454,7 +454,7 @@ namespace data { auto r = std::make_shared(path); if (r->GetRouterIdentity () && !r->IsUnreachable () && - (!r->UsesIntroducer () || m_LastLoad < r->GetTimestamp () + NETDB_INTRODUCEE_EXPIRATION_TIMEOUT*1000LL)) // 1 hour + (!r->HasUnreachableCap () || m_LastLoad < r->GetTimestamp () + NETDB_INTRODUCEE_EXPIRATION_TIMEOUT*1000LL)) // 1 hour { r->DeleteBuffer (); r->ClearProperties (); // properties are not used for regular routers @@ -584,7 +584,7 @@ namespace data if (it.second->IsUnreachable () && total - deletedCount < NETDB_MIN_ROUTERS) it.second->SetUnreachable (false); // find & mark expired routers - if (it.second->UsesIntroducer ()) + if (it.second->HasUnreachableCap ()) { if (ts > it.second->GetTimestamp () + NETDB_INTRODUCEE_EXPIRATION_TIMEOUT*1000LL) // RouterInfo expires after 1 hour if uses introducer diff --git a/libi2pd/RouterInfo.cpp b/libi2pd/RouterInfo.cpp index ed7e3757..0fc8c2dc 100644 --- a/libi2pd/RouterInfo.cpp +++ b/libi2pd/RouterInfo.cpp @@ -1007,11 +1007,6 @@ namespace data } } - bool RouterInfo::UsesIntroducer () const - { - return m_Caps & Caps::eUnreachable; // non-reachable - } - std::shared_ptr RouterInfo::GetSSUAddress (bool v4only) const { return GetAddress ( diff --git a/libi2pd/RouterInfo.h b/libi2pd/RouterInfo.h index 8572741d..b91fa682 100644 --- a/libi2pd/RouterInfo.h +++ b/libi2pd/RouterInfo.h @@ -148,6 +148,7 @@ namespace data bool IsNTCP2 () const { return (bool)ntcp2; }; bool IsPublishedNTCP2 () const { return IsNTCP2 () && ntcp2->isPublished; }; bool IsReachableSSU () const { return (bool)ssu && (!host.is_unspecified () || !ssu->introducers.empty ()); }; + bool UsesIntroducer () const { return (bool)ssu && !ssu->introducers.empty (); }; bool IsIntroducer () const { return caps & eSSUIntroducer; }; bool IsPeerTesting () const { return caps & eSSUTesting; }; @@ -188,6 +189,7 @@ namespace data void SetUnreachableAddressesTransportCaps (uint8_t transports); // bitmask of AddressCaps bool IsFloodfill () const { return m_Caps & Caps::eFloodfill; }; bool IsReachable () const { return m_Caps & Caps::eReachable; }; + bool HasUnreachableCap () const { return m_Caps & Caps::eUnreachable; }; bool IsSSU (bool v4only = true) const; bool IsSSUV6 () const; bool IsNTCP2 (bool v4only = true) const; @@ -204,7 +206,6 @@ namespace data bool IsCompatible (const RouterInfo& other) const { return m_SupportedTransports & other.m_SupportedTransports; }; bool IsReachableFrom (const RouterInfo& other) const; bool HasValidAddresses () const { return m_SupportedTransports; }; - bool UsesIntroducer () const; bool IsHidden () const { return m_Caps & eHidden; }; bool IsHighBandwidth () const { return m_Caps & RouterInfo::eHighBandwidth; }; bool IsExtraBandwidth () const { return m_Caps & RouterInfo::eExtraBandwidth; }; diff --git a/libi2pd/SSU.cpp b/libi2pd/SSU.cpp index 2ee0d2a4..f8bdd9a0 100644 --- a/libi2pd/SSU.cpp +++ b/libi2pd/SSU.cpp @@ -445,7 +445,7 @@ namespace transport { if (router && address) { - if (router->UsesIntroducer ()) + if (address->UsesIntroducer ()) m_Service.post (std::bind (&SSUServer::CreateSessionThroughIntroducer, this, router, address, peerTest)); // always V4 thread else { @@ -481,7 +481,7 @@ namespace transport void SSUServer::CreateSessionThroughIntroducer (std::shared_ptr router, std::shared_ptr address, bool peerTest) { - if (router && router->UsesIntroducer () && address) + if (router && address && address->UsesIntroducer ()) { if (address->IsV4 () && !i2p::context.SupportsV4 ()) return; if (address->IsV6 () && !i2p::context.SupportsV6 ()) return; @@ -566,7 +566,7 @@ namespace transport LogPrint (eLogInfo, "SSU: Introduce new session to [", i2p::data::GetIdentHashAbbreviation (router->GetIdentHash ()), "] through introducer ", introducer->iHost, ":", introducer->iPort); session->WaitForIntroduction (); - if (i2p::context.GetRouterInfo ().UsesIntroducer ()) // if we are unreachable + if (i2p::context.GetRouterInfo ().HasUnreachableCap ()) // if we are unreachable. TODO: ipv4 and ipv6 { uint8_t buf[1]; Send (buf, 0, remoteEndpoint); // send HolePunch diff --git a/libi2pd/SSUSession.cpp b/libi2pd/SSUSession.cpp index c2fa86a8..8ca24805 100644 --- a/libi2pd/SSUSession.cpp +++ b/libi2pd/SSUSession.cpp @@ -681,7 +681,7 @@ namespace transport // we didn't have correct endpoint when sent relay request // now we do LogPrint (eLogInfo, "SSU: RelayReponse connecting to endpoint ", remoteEndpoint); - if (i2p::context.GetRouterInfo ().UsesIntroducer ()) // if we are unreachable + if (i2p::context.GetRouterInfo ().HasUnreachableCap ()) // if we are unreachable. TODO: ipv4 and ipv6 m_Server.Send (buf, 0, remoteEndpoint); // send HolePunch // we assume that HolePunch has been sent by this time and our SessionRequest will go through m_Server.CreateDirectSession (it->second, remoteEndpoint, false); From 67b32005f6f31461ccbcafa1f14130ef2c46a00f Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 3 Apr 2021 22:18:09 -0400 Subject: [PATCH 37/87] check if host if unspecified --- libi2pd/RouterInfo.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libi2pd/RouterInfo.h b/libi2pd/RouterInfo.h index b91fa682..46472bdf 100644 --- a/libi2pd/RouterInfo.h +++ b/libi2pd/RouterInfo.h @@ -153,8 +153,8 @@ namespace data bool IsIntroducer () const { return caps & eSSUIntroducer; }; bool IsPeerTesting () const { return caps & eSSUTesting; }; - bool IsV4 () const { return (caps & AddressCaps::eV4) || host.is_v4 (); }; - bool IsV6 () const { return (caps & AddressCaps::eV6) || host.is_v6 (); }; + bool IsV4 () const { return (caps & AddressCaps::eV4) || (host.is_v4 () && !host.is_unspecified ()); }; + bool IsV6 () const { return (caps & AddressCaps::eV6) || (host.is_v6 () && !host.is_unspecified ()); }; }; typedef std::list > Addresses; From 2cc9791bf2b5845da64229cd74ef1490352201b2 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 4 Apr 2021 10:36:22 -0400 Subject: [PATCH 38/87] exclude already expired introducers --- libi2pd/RouterInfo.cpp | 15 +++++++++++++++ libi2pd/RouterInfo.h | 2 +- libi2pd/SSU.cpp | 12 +++++++++--- libi2pd/SSU.h | 4 ++-- libi2pd/Transports.cpp | 4 ++-- 5 files changed, 29 insertions(+), 8 deletions(-) diff --git a/libi2pd/RouterInfo.cpp b/libi2pd/RouterInfo.cpp index 0fc8c2dc..ad57f685 100644 --- a/libi2pd/RouterInfo.cpp +++ b/libi2pd/RouterInfo.cpp @@ -333,6 +333,21 @@ namespace data } else supportedTransports |= eSSUV4; // in case if host or 6 caps is not preasented, we assume 4 + if (address->ssu && !address->ssu->introducers.empty ()) + { + // exclude invalid introducers + uint32_t ts = i2p::util::GetSecondsSinceEpoch (); + int numValid = 0; + for (auto& it: address->ssu->introducers) + { + if (ts <= it.iExp && it.iPort > 0 && + ((it.iHost.is_v4 () && address->IsV4 ()) || (it.iHost.is_v6 () && address->IsV6 ()))) + numValid++; + else + it.iPort = 0; + } + if (!numValid) address->ssu->introducers.resize (0); + } } } if (supportedTransports) diff --git a/libi2pd/RouterInfo.h b/libi2pd/RouterInfo.h index 46472bdf..336d7741 100644 --- a/libi2pd/RouterInfo.h +++ b/libi2pd/RouterInfo.h @@ -96,7 +96,7 @@ namespace data typedef Tag<32> IntroKey; // should be castable to MacKey and AESKey struct Introducer { - Introducer (): iExp (0) {}; + Introducer (): iPort (0), iExp (0) {}; boost::asio::ip::address iHost; int iPort; IntroKey iKey; diff --git a/libi2pd/SSU.cpp b/libi2pd/SSU.cpp index f8bdd9a0..b3118c96 100644 --- a/libi2pd/SSU.cpp +++ b/libi2pd/SSU.cpp @@ -431,16 +431,17 @@ namespace transport return nullptr; } - void SSUServer::CreateSession (std::shared_ptr router, bool peerTest, bool v4only) + bool SSUServer::CreateSession (std::shared_ptr router, bool peerTest, bool v4only) { auto address = router->GetSSUAddress (v4only || !context.SupportsV6 ()); if (address) - CreateSession (router, address, peerTest); + return CreateSession (router, address, peerTest); else LogPrint (eLogWarning, "SSU: Router ", i2p::data::GetIdentHashAbbreviation (router->GetIdentHash ()), " doesn't have SSU address"); + return false; } - void SSUServer::CreateSession (std::shared_ptr router, + bool SSUServer::CreateSession (std::shared_ptr router, std::shared_ptr address, bool peerTest) { if (router && address) @@ -449,10 +450,14 @@ namespace transport m_Service.post (std::bind (&SSUServer::CreateSessionThroughIntroducer, this, router, address, peerTest)); // always V4 thread else { + if (address->host.is_unspecified ()) return false; boost::asio::ip::udp::endpoint remoteEndpoint (address->host, address->port); m_Service.post (std::bind (&SSUServer::CreateDirectSession, this, router, remoteEndpoint, peerTest)); } } + else + return false; + return true; } void SSUServer::CreateDirectSession (std::shared_ptr router, boost::asio::ip::udp::endpoint remoteEndpoint, bool peerTest) @@ -511,6 +516,7 @@ namespace transport for (int i = 0; i < numIntroducers; i++) { auto intr = &(address->ssu->introducers[i]); + if (!intr->iPort) continue; // skip invalid introducer if (intr->iExp > 0 && ts > intr->iExp) continue; // skip expired introducer boost::asio::ip::udp::endpoint ep (intr->iHost, intr->iPort); if (ep.address ().is_v4 () && address->IsV4 ()) // ipv4 diff --git a/libi2pd/SSU.h b/libi2pd/SSU.h index daaa83f3..606651d7 100644 --- a/libi2pd/SSU.h +++ b/libi2pd/SSU.h @@ -51,8 +51,8 @@ namespace transport ~SSUServer (); void Start (); void Stop (); - void CreateSession (std::shared_ptr router, bool peerTest = false, bool v4only = false); - void CreateSession (std::shared_ptr router, + bool CreateSession (std::shared_ptr router, bool peerTest = false, bool v4only = false); + bool CreateSession (std::shared_ptr router, std::shared_ptr address, bool peerTest = false); void CreateDirectSession (std::shared_ptr router, boost::asio::ip::udp::endpoint remoteEndpoint, bool peerTest); std::shared_ptr FindSession (std::shared_ptr router) const; diff --git a/libi2pd/Transports.cpp b/libi2pd/Transports.cpp index 13c1d210..cf136608 100644 --- a/libi2pd/Transports.cpp +++ b/libi2pd/Transports.cpp @@ -505,8 +505,8 @@ namespace transport } if (address && address->IsReachableSSU ()) { - m_SSUServer->CreateSession (peer.router, address); - return true; + if (m_SSUServer->CreateSession (peer.router, address)) + return true; } } else From ff89edf1272c0146e05f4381193ab53ecad7b75e Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 5 Apr 2021 18:22:48 -0400 Subject: [PATCH 39/87] pick random introducer --- libi2pd/SSU.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libi2pd/SSU.cpp b/libi2pd/SSU.cpp index b3118c96..bc036d51 100644 --- a/libi2pd/SSU.cpp +++ b/libi2pd/SSU.cpp @@ -513,9 +513,10 @@ namespace transport std::shared_ptr introducerSession; const i2p::data::RouterInfo::Introducer * introducer = nullptr; // we might have a session to introducer already + auto offset = rand (); for (int i = 0; i < numIntroducers; i++) { - auto intr = &(address->ssu->introducers[i]); + auto intr = &(address->ssu->introducers[(offset + i)%numIntroducers]); if (!intr->iPort) continue; // skip invalid introducer if (intr->iExp > 0 && ts > intr->iExp) continue; // skip expired introducer boost::asio::ip::udp::endpoint ep (intr->iHost, intr->iPort); From 5c9b478e46ab1b7def7389f4d057e116a8ae644d Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 5 Apr 2021 21:45:48 -0400 Subject: [PATCH 40/87] published field for SSU addresses --- libi2pd/RouterContext.cpp | 6 ++++-- libi2pd/RouterInfo.cpp | 20 ++++++++++++++------ libi2pd/RouterInfo.h | 4 ++-- 3 files changed, 20 insertions(+), 10 deletions(-) diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index e1e19604..a75b0201 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -250,7 +250,7 @@ namespace i2p bool updated = false; for (auto& address : m_RouterInfo.GetAddresses ()) { - if (address->IsNTCP2 () && (address->port != port || address->ntcp2->isPublished != publish)) + if (address->IsNTCP2 () && (address->port != port || address->published != publish)) { bool isAddr = v4 && address->IsV4 (); if (!isAddr && (v6 || ygg)) @@ -270,7 +270,7 @@ namespace i2p } if (port) address->port = port; address->cost = publish ? i2p::data::COST_NTCP2_PUBLISHED : i2p::data::COST_NTCP2_NON_PUBLISHED; - address->ntcp2->isPublished = publish; + address->published = publish; address->ntcp2->iv = m_NTCP2Keys->iv; updated = true; } @@ -483,6 +483,7 @@ namespace i2p if (addr->ssu && ((v4 && addr->IsV4 ()) || (v6 && addr->IsV6 ()))) { addr->cost = i2p::data::COST_SSU_THROUGH_INTRODUCERS; + addr->published = false; addr->caps &= ~i2p::data::RouterInfo::eSSUIntroducer; // can't be introducer addr->ssu->introducers.clear (); port = addr->port; @@ -514,6 +515,7 @@ namespace i2p if (addr->ssu && ((v4 && addr->IsV4 ()) || (v6 && addr->IsV6 ()))) { addr->cost = i2p::data::COST_SSU_DIRECT; + addr->published = true; addr->caps |= i2p::data::RouterInfo::eSSUIntroducer; addr->ssu->introducers.clear (); port = addr->port; diff --git a/libi2pd/RouterInfo.cpp b/libi2pd/RouterInfo.cpp index ad57f685..9d4826dc 100644 --- a/libi2pd/RouterInfo.cpp +++ b/libi2pd/RouterInfo.cpp @@ -260,7 +260,7 @@ namespace data else if (!strcmp (key, "i")) // ntcp2 iv { Base64ToByteStream (value, strlen (value), address->ntcp2->iv, 16); - address->ntcp2->isPublished = true; // presence if "i" means "published" + address->published = true; // presence if "i" means "published" } else if (key[0] == 'i') { @@ -308,7 +308,7 @@ namespace data else supportedTransports |= eNTCP2V4; } - else if (!address->ntcp2->isPublished) + else if (!address->published) { if (address->caps) { @@ -348,6 +348,8 @@ namespace data } if (!numValid) address->ssu->introducers.resize (0); } + else if (isHost && address->port) + address->published = true; } } if (supportedTransports) @@ -564,7 +566,7 @@ namespace data if (address.IsPeerTesting ()) caps += CAPS_FLAG_SSU_TESTING; if (address.host.is_v4 ()) { - if (IsReachable ()) + if (address.published) { isPublished = true; if (address.IsIntroducer ()) caps += CAPS_FLAG_SSU_INTRODUCER; @@ -574,8 +576,13 @@ namespace data } else if (address.host.is_v6 ()) { - isPublished = true; - if (address.IsIntroducer ()) caps += CAPS_FLAG_SSU_INTRODUCER; + if (address.published) + { + isPublished = true; + if (address.IsIntroducer ()) caps += CAPS_FLAG_SSU_INTRODUCER; + } + else + caps += CAPS_FLAG_V6; } else { @@ -807,6 +814,7 @@ namespace data addr->port = port; addr->transportStyle = eTransportSSU; addr->cost = COST_SSU_DIRECT; // NTCP2 should have priority over SSU + addr->published = true; addr->caps = i2p::data::RouterInfo::eSSUTesting | i2p::data::RouterInfo::eSSUIntroducer; // BC; addr->date = 0; addr->ssu.reset (new SSUExt ()); @@ -831,7 +839,7 @@ namespace data addr->caps = 0; addr->date = 0; addr->ntcp2.reset (new NTCP2Ext ()); - if (port) addr->ntcp2->isPublished = true; + if (port) addr->published = true; memcpy (addr->ntcp2->staticKey, staticKey, 32); memcpy (addr->ntcp2->iv, iv, 16); m_Addresses->push_back(std::move(addr)); diff --git a/libi2pd/RouterInfo.h b/libi2pd/RouterInfo.h index 336d7741..284d9301 100644 --- a/libi2pd/RouterInfo.h +++ b/libi2pd/RouterInfo.h @@ -115,7 +115,6 @@ namespace data { Tag<32> staticKey; Tag<16> iv; - bool isPublished = false; }; struct Address @@ -125,6 +124,7 @@ namespace data int port; uint64_t date; uint8_t cost, caps; + bool published = false; std::unique_ptr ssu; // not null for SSU std::unique_ptr ntcp2; // not null for NTCP2 @@ -146,7 +146,7 @@ namespace data } bool IsNTCP2 () const { return (bool)ntcp2; }; - bool IsPublishedNTCP2 () const { return IsNTCP2 () && ntcp2->isPublished; }; + bool IsPublishedNTCP2 () const { return IsNTCP2 () && published; }; bool IsReachableSSU () const { return (bool)ssu && (!host.is_unspecified () || !ssu->introducers.empty ()); }; bool UsesIntroducer () const { return (bool)ssu && !ssu->introducers.empty (); }; From 277cef5ec43169fa47d5fc6b4597cc5710cfae1c Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 7 Apr 2021 13:05:38 -0400 Subject: [PATCH 41/87] eliminate cost field --- libi2pd/RouterContext.cpp | 3 --- libi2pd/RouterInfo.cpp | 15 ++++++++++----- libi2pd/RouterInfo.h | 2 +- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index a75b0201..54843073 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -269,7 +269,6 @@ namespace i2p if (port == 9150) port = 9151; // Tor browser } if (port) address->port = port; - address->cost = publish ? i2p::data::COST_NTCP2_PUBLISHED : i2p::data::COST_NTCP2_NON_PUBLISHED; address->published = publish; address->ntcp2->iv = m_NTCP2Keys->iv; updated = true; @@ -482,7 +481,6 @@ namespace i2p for (auto& addr : addresses) if (addr->ssu && ((v4 && addr->IsV4 ()) || (v6 && addr->IsV6 ()))) { - addr->cost = i2p::data::COST_SSU_THROUGH_INTRODUCERS; addr->published = false; addr->caps &= ~i2p::data::RouterInfo::eSSUIntroducer; // can't be introducer addr->ssu->introducers.clear (); @@ -514,7 +512,6 @@ namespace i2p for (auto& addr : addresses) if (addr->ssu && ((v4 && addr->IsV4 ()) || (v6 && addr->IsV6 ()))) { - addr->cost = i2p::data::COST_SSU_DIRECT; addr->published = true; addr->caps |= i2p::data::RouterInfo::eSSUIntroducer; addr->ssu->introducers.clear (); diff --git a/libi2pd/RouterInfo.cpp b/libi2pd/RouterInfo.cpp index 9d4826dc..e9f27d96 100644 --- a/libi2pd/RouterInfo.cpp +++ b/libi2pd/RouterInfo.cpp @@ -197,7 +197,8 @@ namespace data { uint8_t supportedTransports = 0; auto address = std::make_shared
(); - s.read ((char *)&address->cost, sizeof (address->cost)); + uint8_t cost; // ignore + s.read ((char *)&cost, sizeof (cost)); s.read ((char *)&address->date, sizeof (address->date)); bool isHost = false, isIntroKey = false, isStaticKey = false; char transportStyle[6]; @@ -530,7 +531,13 @@ namespace data for (const auto& addr_ptr : *m_Addresses) { const Address& address = *addr_ptr; - s.write ((const char *)&address.cost, sizeof (address.cost)); + // calculate cost + uint8_t cost = 0x7f; + if (address.transportStyle == eTransportNTCP) + cost = address.published ? COST_NTCP2_PUBLISHED : COST_NTCP2_NON_PUBLISHED; + else if (address.transportStyle == eTransportSSU) + cost = address.published ? COST_SSU_DIRECT : COST_SSU_THROUGH_INTRODUCERS; + s.write ((const char *)&cost, sizeof (cost)); s.write ((const char *)&address.date, sizeof (address.date)); std::stringstream properties; bool isPublished = false; @@ -813,7 +820,6 @@ namespace data addr->host = boost::asio::ip::address::from_string (host); addr->port = port; addr->transportStyle = eTransportSSU; - addr->cost = COST_SSU_DIRECT; // NTCP2 should have priority over SSU addr->published = true; addr->caps = i2p::data::RouterInfo::eSSUTesting | i2p::data::RouterInfo::eSSUIntroducer; // BC; addr->date = 0; @@ -834,8 +840,7 @@ namespace data auto addr = std::make_shared
(); addr->host = host; addr->port = port; - addr->transportStyle = eTransportNTCP; - addr->cost = port ? COST_NTCP2_PUBLISHED : COST_NTCP2_NON_PUBLISHED; // override from RouterContext::PublishNTCP2Address + addr->transportStyle = eTransportNTCP; addr->caps = 0; addr->date = 0; addr->ntcp2.reset (new NTCP2Ext ()); diff --git a/libi2pd/RouterInfo.h b/libi2pd/RouterInfo.h index 284d9301..bdb92b8a 100644 --- a/libi2pd/RouterInfo.h +++ b/libi2pd/RouterInfo.h @@ -123,7 +123,7 @@ namespace data boost::asio::ip::address host; int port; uint64_t date; - uint8_t cost, caps; + uint8_t caps; bool published = false; std::unique_ptr ssu; // not null for SSU std::unique_ptr ntcp2; // not null for NTCP2 From 3e873f88c98ce1e1e8145fa875eb79d62e488393 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 7 Apr 2021 15:55:38 -0400 Subject: [PATCH 42/87] don't drop introducers without iExp --- libi2pd/RouterInfo.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd/RouterInfo.cpp b/libi2pd/RouterInfo.cpp index e9f27d96..00b78771 100644 --- a/libi2pd/RouterInfo.cpp +++ b/libi2pd/RouterInfo.cpp @@ -341,7 +341,7 @@ namespace data int numValid = 0; for (auto& it: address->ssu->introducers) { - if (ts <= it.iExp && it.iPort > 0 && + if ((!it.iExp || ts <= it.iExp) && it.iPort > 0 && ((it.iHost.is_v4 () && address->IsV4 ()) || (it.iHost.is_v6 () && address->IsV6 ()))) numValid++; else From b9a2d5df02dc0adf12e751237669ee751295ed59 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 8 Apr 2021 21:07:14 -0400 Subject: [PATCH 43/87] send HolePunch back based on actual address type --- libi2pd/SSU.cpp | 3 ++- libi2pd/SSUSession.cpp | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/libi2pd/SSU.cpp b/libi2pd/SSU.cpp index bc036d51..31269558 100644 --- a/libi2pd/SSU.cpp +++ b/libi2pd/SSU.cpp @@ -573,7 +573,8 @@ namespace transport LogPrint (eLogInfo, "SSU: Introduce new session to [", i2p::data::GetIdentHashAbbreviation (router->GetIdentHash ()), "] through introducer ", introducer->iHost, ":", introducer->iPort); session->WaitForIntroduction (); - if (i2p::context.GetRouterInfo ().HasUnreachableCap ()) // if we are unreachable. TODO: ipv4 and ipv6 + if ((address->host.is_v4 () && i2p::context.GetStatus () == eRouterStatusFirewalled) || + (address->host.is_v6 () && i2p::context.GetStatusV6 () == eRouterStatusFirewalled)) { uint8_t buf[1]; Send (buf, 0, remoteEndpoint); // send HolePunch diff --git a/libi2pd/SSUSession.cpp b/libi2pd/SSUSession.cpp index 8ca24805..0833d994 100644 --- a/libi2pd/SSUSession.cpp +++ b/libi2pd/SSUSession.cpp @@ -681,7 +681,8 @@ namespace transport // we didn't have correct endpoint when sent relay request // now we do LogPrint (eLogInfo, "SSU: RelayReponse connecting to endpoint ", remoteEndpoint); - if (i2p::context.GetRouterInfo ().HasUnreachableCap ()) // if we are unreachable. TODO: ipv4 and ipv6 + if ((remoteIP.is_v4 () && i2p::context.GetStatus () == eRouterStatusFirewalled) || + (remoteIP.is_v6 () && i2p::context.GetStatusV6 () == eRouterStatusFirewalled)) m_Server.Send (buf, 0, remoteEndpoint); // send HolePunch // we assume that HolePunch has been sent by this time and our SessionRequest will go through m_Server.CreateDirectSession (it->second, remoteEndpoint, false); From ac47c9c67333764351a3df1680a4e93871265eb9 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 9 Apr 2021 10:56:46 -0400 Subject: [PATCH 44/87] don't check U cap --- libi2pd/NetDb.cpp | 4 ++-- libi2pd/RouterInfo.h | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/libi2pd/NetDb.cpp b/libi2pd/NetDb.cpp index cfd4bff6..bc49d720 100644 --- a/libi2pd/NetDb.cpp +++ b/libi2pd/NetDb.cpp @@ -454,7 +454,7 @@ namespace data { auto r = std::make_shared(path); if (r->GetRouterIdentity () && !r->IsUnreachable () && - (!r->HasUnreachableCap () || m_LastLoad < r->GetTimestamp () + NETDB_INTRODUCEE_EXPIRATION_TIMEOUT*1000LL)) // 1 hour + (r->IsReachable () || !r->IsSSU (false) || m_LastLoad < r->GetTimestamp () + NETDB_INTRODUCEE_EXPIRATION_TIMEOUT*1000LL)) // 1 hour { r->DeleteBuffer (); r->ClearProperties (); // properties are not used for regular routers @@ -584,7 +584,7 @@ namespace data if (it.second->IsUnreachable () && total - deletedCount < NETDB_MIN_ROUTERS) it.second->SetUnreachable (false); // find & mark expired routers - if (it.second->HasUnreachableCap ()) + if (!it.second->IsReachable () && it.second->IsSSU (false)) { if (ts > it.second->GetTimestamp () + NETDB_INTRODUCEE_EXPIRATION_TIMEOUT*1000LL) // RouterInfo expires after 1 hour if uses introducer diff --git a/libi2pd/RouterInfo.h b/libi2pd/RouterInfo.h index bdb92b8a..dd3e7e13 100644 --- a/libi2pd/RouterInfo.h +++ b/libi2pd/RouterInfo.h @@ -189,7 +189,6 @@ namespace data void SetUnreachableAddressesTransportCaps (uint8_t transports); // bitmask of AddressCaps bool IsFloodfill () const { return m_Caps & Caps::eFloodfill; }; bool IsReachable () const { return m_Caps & Caps::eReachable; }; - bool HasUnreachableCap () const { return m_Caps & Caps::eUnreachable; }; bool IsSSU (bool v4only = true) const; bool IsSSUV6 () const; bool IsNTCP2 (bool v4only = true) const; From df858d9143dbf302d742f90157b167bc59016c7d Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 9 Apr 2021 13:29:07 -0400 Subject: [PATCH 45/87] publish iexp --- libi2pd/RouterInfo.cpp | 24 ++++++++++++------------ libi2pd/SSU.cpp | 1 + 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/libi2pd/RouterInfo.cpp b/libi2pd/RouterInfo.cpp index 00b78771..d54c2e97 100644 --- a/libi2pd/RouterInfo.cpp +++ b/libi2pd/RouterInfo.cpp @@ -617,6 +617,18 @@ namespace data { int i = 0; for (const auto& introducer: address.ssu->introducers) + { + if (introducer.iExp) // expiration is specified + { + WriteString ("iexp" + boost::lexical_cast(i), properties); + properties << '='; + WriteString (boost::lexical_cast(introducer.iExp), properties); + properties << ';'; + } + i++; + } + i = 0; + for (const auto& introducer: address.ssu->introducers) { WriteString ("ihost" + boost::lexical_cast(i), properties); properties << '='; @@ -654,18 +666,6 @@ namespace data properties << ';'; i++; } - i = 0; - for (const auto& introducer: address.ssu->introducers) - { - if (introducer.iExp) // expiration is specified - { - WriteString ("iexp" + boost::lexical_cast(i), properties); - properties << '='; - WriteString (boost::lexical_cast(introducer.iExp), properties); - properties << ';'; - } - i++; - } } // write intro key WriteString ("key", properties); diff --git a/libi2pd/SSU.cpp b/libi2pd/SSU.cpp index 31269558..aad117cd 100644 --- a/libi2pd/SSU.cpp +++ b/libi2pd/SSU.cpp @@ -744,6 +744,7 @@ namespace transport introducer.iPort = ep.port (); introducer.iTag = it1->GetRelayTag (); introducer.iKey = it1->GetIntroKey (); + introducer.iExp = it1->GetCreationTime () + SSU_TO_INTRODUCER_SESSION_DURATION; if (i2p::context.AddIntroducer (introducer)) { newList.push_back (ep); From 83fc1b0b8e945759becce8c03a1d651802fd2eeb Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 11 Apr 2021 17:26:45 -0400 Subject: [PATCH 46/87] support b32 and b33 addresses in STREAM CONNECT --- libi2pd_client/SAM.cpp | 39 +++++++++++++++++++++++++++++---------- 1 file changed, 29 insertions(+), 10 deletions(-) diff --git a/libi2pd_client/SAM.cpp b/libi2pd_client/SAM.cpp index 9f7e771e..1eb38a7e 100644 --- a/libi2pd_client/SAM.cpp +++ b/libi2pd_client/SAM.cpp @@ -495,20 +495,39 @@ namespace client else m_BufferOffset = 0; - auto dest = std::make_shared (); - size_t l = dest->FromBase64(destination); - if (l > 0) + std::shared_ptr
addr; + auto pos = destination.find(".b32.i2p"); + if (pos != std::string::npos) + addr = std::make_shared
(destination.substr (0, pos)); + else { - context.GetAddressBook().InsertFullAddress(dest); - auto leaseSet = session->localDestination->FindLeaseSet(dest->GetIdentHash()); - if (leaseSet) - Connect(leaseSet, session); - else + auto dest = std::make_shared (); + size_t l = dest->FromBase64(destination); + if (l > 0) { - session->localDestination->RequestDestination(dest->GetIdentHash(), + context.GetAddressBook().InsertFullAddress(dest); + addr = std::make_shared
(dest->GetIdentHash ()); + } + } + + if (addr && addr->IsValid ()) + { + if (addr->IsIdentHash ()) + { + auto leaseSet = session->localDestination->FindLeaseSet(addr->identHash); + if (leaseSet) + Connect(leaseSet, session); + else + { + session->localDestination->RequestDestination(addr->identHash, + std::bind(&SAMSocket::HandleConnectLeaseSetRequestComplete, + shared_from_this(), std::placeholders::_1)); + } + } + else // B33 + session->localDestination->RequestDestinationWithEncryptedLeaseSet (addr->blindedPublicKey, std::bind(&SAMSocket::HandleConnectLeaseSetRequestComplete, shared_from_this(), std::placeholders::_1)); - } } else SendMessageReply (SAM_STREAM_STATUS_INVALID_KEY, strlen(SAM_STREAM_STATUS_INVALID_KEY), true); From 4543e14c57e6ae884ebcadd9d773f2e7a948a1a8 Mon Sep 17 00:00:00 2001 From: acetone <63557806+acetoneRu@users.noreply.github.com> Date: Tue, 13 Apr 2021 02:43:42 -0400 Subject: [PATCH 47/87] SAM section fixed --- contrib/i2pd.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/i2pd.conf b/contrib/i2pd.conf index 523fd41b..6979d4d8 100644 --- a/contrib/i2pd.conf +++ b/contrib/i2pd.conf @@ -128,7 +128,7 @@ port = 4447 ## socksproxy section also accepts I2CP parameters, like "inbound.length" etc. [sam] -## Uncomment and set to 'true' to enable SAM Bridge +## Comment or set to 'false' to disable SAM Bridge enabled = true ## Address and port service will listen on # address = 127.0.0.1 From 27833372841b73f489ec5fcc06afa9ce6b8e41d2 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 13 Apr 2021 09:16:52 -0400 Subject: [PATCH 48/87] require ipv4 for IBGW --- libi2pd/TunnelPool.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/libi2pd/TunnelPool.cpp b/libi2pd/TunnelPool.cpp index 7cb79956..ed9a1a82 100644 --- a/libi2pd/TunnelPool.cpp +++ b/libi2pd/TunnelPool.cpp @@ -422,7 +422,7 @@ namespace tunnel { auto r = i2p::transport::transports.GetRandomPeer (); if (r && !r->GetProfile ()->IsBad () && - (numHops > 1 || (!inbound && r->IsV4 ()) || r->IsReachable ())) // first inbound must be reachable + (numHops > 1 || (r->IsV4 () && (!inbound || r->IsReachable ())))) // first inbound must be reachable { prevHop = r; peers.push_back (r->GetRouterIdentity ()); @@ -443,9 +443,8 @@ namespace tunnel LogPrint (eLogError, "Tunnels: Can't select next hop for ", prevHop->GetIdentHashBase64 ()); return false; } - if ((i == numHops - 1) && - ((inbound && !hop->IsReachable ()) || // IBGW is not reachable - (!inbound && !hop->IsV4 ()))) // OBEP is not ipv4 + if ((i == numHops - 1) && (!hop->IsV4 () || // doesn't support ipv4 + (inbound && !hop->IsReachable ()))) // IBGW is not reachable { auto hop1 = nextHop (prevHop, true); if (hop1) hop = hop1; From be48dc6e870f5017be00940e1daceaeef244a8f4 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 13 Apr 2021 15:11:37 -0400 Subject: [PATCH 49/87] pick correct local address for intro key --- libi2pd/SSUSession.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/libi2pd/SSUSession.cpp b/libi2pd/SSUSession.cpp index 0833d994..433b6513 100644 --- a/libi2pd/SSUSession.cpp +++ b/libi2pd/SSUSession.cpp @@ -120,7 +120,8 @@ namespace transport else { // try own intro key - auto address = i2p::context.GetRouterInfo ().GetSSUAddress (false); + auto address = IsV6 () ? i2p::context.GetRouterInfo ().GetSSUV6Address () : + i2p::context.GetRouterInfo ().GetSSUAddress (true); if (!address) { LogPrint (eLogInfo, "SSU is not supported"); @@ -390,7 +391,8 @@ namespace transport void SSUSession::SendRelayRequest (const i2p::data::RouterInfo::Introducer& introducer, uint32_t nonce) { - auto address = i2p::context.GetRouterInfo ().GetSSUAddress (false); + auto address = IsV6 () ? i2p::context.GetRouterInfo ().GetSSUV6Address () : + i2p::context.GetRouterInfo ().GetSSUAddress (true); if (!address) { LogPrint (eLogInfo, "SSU is not supported"); @@ -689,6 +691,8 @@ namespace transport } // delete request m_RelayRequests.erase (it); + // cancel connect timer + m_ConnectTimer.cancel (); } else LogPrint (eLogError, "SSU: Unsolicited RelayResponse, nonce=", nonce); From 39d4464be072e99d3468101c8f511ae17bb6eea6 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 15 Apr 2021 11:43:43 -0400 Subject: [PATCH 50/87] make sure that introducer or peer test router is reachable by SSU --- libi2pd/RouterInfo.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libi2pd/RouterInfo.cpp b/libi2pd/RouterInfo.cpp index d54c2e97..87a987fe 100644 --- a/libi2pd/RouterInfo.cpp +++ b/libi2pd/RouterInfo.cpp @@ -1135,7 +1135,7 @@ namespace data [v4](std::shared_ptr address)->bool { return (address->transportStyle == eTransportSSU) && address->IsPeerTesting () && - ((v4 && address->IsV4 ()) || (!v4 && address->IsV6 ())); + ((v4 && address->IsV4 ()) || (!v4 && address->IsV6 ())) && address->IsReachableSSU (); }); } @@ -1146,7 +1146,7 @@ namespace data [v4](std::shared_ptr address)->bool { return (address->transportStyle == eTransportSSU) && address->IsIntroducer () && - ((v4 && address->IsV4 ()) || (!v4 && address->IsV6 ())); + ((v4 && address->IsV4 ()) || (!v4 && address->IsV6 ())) && !address->host.is_unspecified (); }); } From 74d0c04314b7244afa0614430827f0f13a575312 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 15 Apr 2021 16:06:02 -0400 Subject: [PATCH 51/87] ipv6 address for relay reponse and relay intro --- libi2pd/SSUSession.cpp | 60 +++++++++++++++++++++++++++++------------- 1 file changed, 41 insertions(+), 19 deletions(-) diff --git a/libi2pd/SSUSession.cpp b/libi2pd/SSUSession.cpp index 433b6513..c135ae1d 100644 --- a/libi2pd/SSUSession.cpp +++ b/libi2pd/SSUSession.cpp @@ -570,22 +570,33 @@ namespace transport void SSUSession::SendRelayResponse (uint32_t nonce, const boost::asio::ip::udp::endpoint& from, const uint8_t * introKey, const boost::asio::ip::udp::endpoint& to) { - // Charlie's address always v4 - if (!to.address ().is_v4 ()) + bool isV4 = to.address ().is_v4 (); // Charle's + bool isV4A = from.address ().is_v4 (); // Alice's + if ((isV4 && !isV4A) || (!isV4 && isV4A)) { - LogPrint (eLogWarning, "SSU: Charlie's IP must be v4"); + LogPrint (eLogWarning, "SSU: Charlie's IP and Alice's IP belong to different networks for relay response"); return; } - uint8_t buf[80 + 18] = {0}; // 64 Alice's ipv4 and 80 Alice's ipv6 + uint8_t buf[80 + 18] = {0}; // 64 for ipv4 and 80 for ipv6 uint8_t * payload = buf + sizeof (SSUHeader); - *payload = 4; - payload++; // size - htobe32buf (payload, to.address ().to_v4 ().to_ulong ()); // Charlie's IP - payload += 4; // address + // Charlie + if (isV4) + { + *payload = 4; + payload++; // size + memcpy (payload, to.address ().to_v4 ().to_bytes ().data (), 4); // Charlie's IP V4 + payload += 4; // address + } + else + { + *payload = 16; + payload++; // size + memcpy (payload, to.address ().to_v6 ().to_bytes ().data (), 16); // Alice's IP V6 + payload += 16; // address + } htobe16buf (payload, to.port ()); // Charlie's port payload += 2; // port // Alice - bool isV4 = from.address ().is_v4 (); // Alice's if (isV4) { *payload = 4; @@ -624,25 +635,36 @@ namespace transport void SSUSession::SendRelayIntro (std::shared_ptr session, const boost::asio::ip::udp::endpoint& from) { if (!session) return; - // Alice's address always v4 - if (!from.address ().is_v4 ()) + bool isV4 = from.address ().is_v4 (); // Alice's + bool isV4C = session->m_RemoteEndpoint.address ().is_v4 (); // Charlie's + if ((isV4 && !isV4C) || (!isV4 && isV4C)) { - LogPrint (eLogWarning, "SSU: Alice's IP must be v4"); + LogPrint (eLogWarning, "SSU: Charlie's IP and Alice's IP belong to different networks for relay intro"); return; } - uint8_t buf[48 + 18] = {0}; + uint8_t buf[64 + 18] = {0}; // 48 for ipv4 and 64 for ipv6 uint8_t * payload = buf + sizeof (SSUHeader); - *payload = 4; - payload++; // size - htobe32buf (payload, from.address ().to_v4 ().to_ulong ()); // Alice's IP - payload += 4; // address + if (isV4) + { + *payload = 4; + payload++; // size + memcpy (payload, from.address ().to_v4 ().to_bytes ().data (), 4); // Alice's IP V4 + payload += 4; // address + } + else + { + *payload = 16; + payload++; // size + memcpy (payload, from.address ().to_v6 ().to_bytes ().data (), 16); // Alice's IP V6 + payload += 16; // address + } htobe16buf (payload, from.port ()); // Alice's port payload += 2; // port *payload = 0; // challenge size uint8_t iv[16]; RAND_bytes (iv, 16); // random iv - FillHeaderAndEncrypt (PAYLOAD_TYPE_RELAY_INTRO, buf, 48, session->m_SessionKey, iv, session->m_MacKey); - m_Server.Send (buf, 48, session->m_RemoteEndpoint); + FillHeaderAndEncrypt (PAYLOAD_TYPE_RELAY_INTRO, buf, isV4 ? 48 : 64, session->m_SessionKey, iv, session->m_MacKey); + m_Server.Send (buf, isV4 ? 48 : 64, session->m_RemoteEndpoint); LogPrint (eLogDebug, "SSU: relay intro sent"); } From 5edb2569907a9a8bd880f93907e500ade61d811c Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 16 Apr 2021 19:31:49 -0400 Subject: [PATCH 52/87] check if our external IP is valid --- libi2pd/SSUSession.cpp | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/libi2pd/SSUSession.cpp b/libi2pd/SSUSession.cpp index c135ae1d..19ccd1ce 100644 --- a/libi2pd/SSUSession.cpp +++ b/libi2pd/SSUSession.cpp @@ -296,8 +296,16 @@ namespace transport if (s.Verify (m_RemoteIdentity, payload)) { LogPrint (eLogInfo, "SSU: Our external address is ", ourIP.to_string (), ":", ourPort); - i2p::context.UpdateAddress (ourIP); - SendSessionConfirmed (y, ourAddressAndPort, addressAndPortLen); + if (!i2p::util::net::IsInReservedRange (ourIP)) + { + i2p::context.UpdateAddress (ourIP); + SendSessionConfirmed (y, ourAddressAndPort, addressAndPortLen); + } + else + { + LogPrint (eLogError, "SSU: Wrong external address ", ourIP.to_string ()); + Failed (); + } } else { @@ -682,7 +690,10 @@ namespace transport if (!ourSize) return; buf += ourSize; len -= ourSize; LogPrint (eLogInfo, "SSU: Our external address is ", ourIP.to_string (), ":", ourPort); - i2p::context.UpdateAddress (ourIP); + if (!i2p::util::net::IsInReservedRange (ourIP)) + i2p::context.UpdateAddress (ourIP); + else + LogPrint (eLogWarning, "SSU: Wrong external address ", ourIP.to_string ()); if (ourIP.is_v4 ()) { if (ourPort != m_Server.GetPort ()) From d5b61ed544db61662832fcd7d5ad1eaf03268fb3 Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 17 Apr 2021 14:33:53 -0400 Subject: [PATCH 53/87] select different routers for peer test --- libi2pd/NetDb.cpp | 7 ++++--- libi2pd/NetDb.hpp | 2 +- libi2pd/Transports.cpp | 10 +++++++--- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/libi2pd/NetDb.cpp b/libi2pd/NetDb.cpp index bc49d720..80029ece 100644 --- a/libi2pd/NetDb.cpp +++ b/libi2pd/NetDb.cpp @@ -1149,12 +1149,13 @@ namespace data }); } - std::shared_ptr NetDb::GetRandomPeerTestRouter (bool v4) const + std::shared_ptr NetDb::GetRandomPeerTestRouter (bool v4, const std::set& excluded) const { return GetRandomRouter ( - [v4](std::shared_ptr router)->bool + [v4, &excluded](std::shared_ptr router)->bool { - return !router->IsHidden () && router->IsPeerTesting (v4); + return !router->IsHidden () && router->IsPeerTesting (v4) && + !excluded.count (router->GetIdentHash ()); }); } diff --git a/libi2pd/NetDb.hpp b/libi2pd/NetDb.hpp index 891bc35d..b782872c 100644 --- a/libi2pd/NetDb.hpp +++ b/libi2pd/NetDb.hpp @@ -85,7 +85,7 @@ namespace data std::shared_ptr GetRandomRouter () const; std::shared_ptr GetRandomRouter (std::shared_ptr compatibleWith, bool reverse) const; std::shared_ptr GetHighBandwidthRandomRouter (std::shared_ptr compatibleWith, bool reverse) const; - std::shared_ptr GetRandomPeerTestRouter (bool v4) const; + std::shared_ptr GetRandomPeerTestRouter (bool v4, const std::set& excluded) const; std::shared_ptr GetRandomSSUV6Router () const; // TODO: change to v6 peer test later std::shared_ptr GetRandomIntroducer () const; std::shared_ptr GetClosestFloodfill (const IdentHash& destination, const std::set& excluded, bool closeThanUsOnly = false) const; diff --git a/libi2pd/Transports.cpp b/libi2pd/Transports.cpp index cf136608..4ad13518 100644 --- a/libi2pd/Transports.cpp +++ b/libi2pd/Transports.cpp @@ -587,10 +587,11 @@ namespace transport if (i2p::context.SupportsV4 ()) { LogPrint (eLogInfo, "Transports: Started peer test ipv4"); + std::set excluded; bool statusChanged = false; for (int i = 0; i < 5; i++) { - auto router = i2p::data::netdb.GetRandomPeerTestRouter (true); // v4 + auto router = i2p::data::netdb.GetRandomPeerTestRouter (true, excluded); // v4 if (router) { auto addr = router->GetSSUAddress (true); // ipv4 @@ -601,8 +602,9 @@ namespace transport statusChanged = true; i2p::context.SetStatus (eRouterStatusTesting); // first time only } - m_SSUServer->CreateSession (router, addr, true); // peer test v4 + m_SSUServer->CreateSession (router, addr, true); // peer test v4 } + excluded.insert (router->GetIdentHash ()); } } if (!statusChanged) @@ -611,10 +613,11 @@ namespace transport if (i2p::context.SupportsV6 ()) { LogPrint (eLogInfo, "Transports: Started peer test ipv6"); + std::set excluded; bool statusChanged = false; for (int i = 0; i < 5; i++) { - auto router = i2p::data::netdb.GetRandomPeerTestRouter (false); // v6 + auto router = i2p::data::netdb.GetRandomPeerTestRouter (false, excluded); // v6 if (router) { auto addr = router->GetSSUV6Address (); @@ -627,6 +630,7 @@ namespace transport } m_SSUServer->CreateSession (router, addr, true); // peer test v6 } + excluded.insert (router->GetIdentHash ()); } } if (!statusChanged) From ca77ca6ef0eeb00263da3656d6852c461634d3d3 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 18 Apr 2021 17:27:50 -0400 Subject: [PATCH 54/87] reseed from compatible address --- libi2pd/Reseed.cpp | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/libi2pd/Reseed.cpp b/libi2pd/Reseed.cpp index a712975e..41111ecc 100644 --- a/libi2pd/Reseed.cpp +++ b/libi2pd/Reseed.cpp @@ -678,8 +678,31 @@ namespace data // direct connection auto it = boost::asio::ip::tcp::resolver(service).resolve ( boost::asio::ip::tcp::resolver::query (url.host, std::to_string(url.port)), ecode); - if(!ecode) - s.lowest_layer().connect (*it, ecode); + if (!ecode) + { + bool connected = false; + boost::asio::ip::tcp::resolver::iterator end; + while (it != end) + { + boost::asio::ip::tcp::endpoint ep = *it; + if ((ep.address ().is_v4 () && i2p::context.SupportsV4 ()) || + (ep.address ().is_v6 () && i2p::context.SupportsV6 ())) + { + s.lowest_layer().connect (ep, ecode); + if (!ecode) + { + connected = true; + break; + } + } + it++; + } + if (!connected) + { + LogPrint(eLogError, "Reseed: Failed to connect to ", url.host); + return ""; + } + } } if (!ecode) { From 7978adc5778be4a0798f12978ca611e0eee6a0ae Mon Sep 17 00:00:00 2001 From: acetone <63557806+acetoneRu@users.noreply.github.com> Date: Mon, 19 Apr 2021 06:43:51 -0400 Subject: [PATCH 55/87] =?UTF-8?q?=D0=A3=D1=82=D0=BE=D1=87=D0=BD=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D0=B5=20=D0=BF=D1=80=D0=BE=20=D0=BB=D0=BE=D0=B3?= =?UTF-8?q?=D0=B8=D1=80=D0=BE=D0=B2=D0=B0=D0=BD=D0=B8=D0=B5=20=D0=B2=20Win?= =?UTF-8?q?dows?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- contrib/i2pd.conf | 1 + 1 file changed, 1 insertion(+) diff --git a/contrib/i2pd.conf b/contrib/i2pd.conf index 6979d4d8..2e1b296a 100644 --- a/contrib/i2pd.conf +++ b/contrib/i2pd.conf @@ -20,6 +20,7 @@ ## Logging configuration section ## By default logs go to stdout with level 'info' and higher +## For Windows OS by default logs go to file with level 'warn' and higher ## ## Logs destination (valid values: stdout, file, syslog) ## * stdout - print log entries to stdout From ad019da5535b9599973e3e7aea736b229fb41498 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 20 Apr 2021 20:02:30 -0400 Subject: [PATCH 56/87] publish ipv6 introducers --- libi2pd/RouterContext.cpp | 4 +- libi2pd/SSU.cpp | 107 ++++++++++++++++++++++++++------------ libi2pd/SSU.h | 12 +++-- libi2pd/SSUSession.cpp | 3 ++ 4 files changed, 85 insertions(+), 41 deletions(-) diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index 54843073..e4697f2b 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -466,7 +466,7 @@ namespace i2p void RouterContext::SetUnreachable (bool v4, bool v6) { - if (v4) + if (v4 || (v6 && !SupportsV4 ())) { // set caps uint8_t caps = m_RouterInfo.GetCaps (); @@ -496,7 +496,7 @@ namespace i2p void RouterContext::SetReachable (bool v4, bool v6) { - if (v4) + if (v4 || (v6 && !SupportsV4 ())) { // update caps uint8_t caps = m_RouterInfo.GetCaps (); diff --git a/libi2pd/SSU.cpp b/libi2pd/SSU.cpp index aad117cd..5ffcf890 100644 --- a/libi2pd/SSU.cpp +++ b/libi2pd/SSU.cpp @@ -28,8 +28,8 @@ namespace transport m_ReceiversWork (m_ReceiversService), m_ReceiversWorkV6 (m_ReceiversServiceV6), m_Endpoint (boost::asio::ip::udp::v4 (), port), m_EndpointV6 (boost::asio::ip::udp::v6 (), port), m_Socket (m_ReceiversService), m_SocketV6 (m_ReceiversServiceV6), - m_IntroducersUpdateTimer (m_Service), m_PeerTestsCleanupTimer (m_Service), - m_TerminationTimer (m_Service), m_TerminationTimerV6 (m_Service) + m_IntroducersUpdateTimer (m_Service), m_IntroducersUpdateTimerV6 (m_Service), + m_PeerTestsCleanupTimer (m_Service), m_TerminationTimer (m_Service), m_TerminationTimerV6 (m_Service) { } @@ -82,6 +82,7 @@ namespace transport m_ReceiversThread = new std::thread (std::bind (&SSUServer::RunReceivers, this)); m_ReceiversService.post (std::bind (&SSUServer::Receive, this)); ScheduleTermination (); + ScheduleIntroducersUpdateTimer (); // wait for 30 seconds and decide if we need introducers } if (context.SupportsV6 ()) { @@ -89,9 +90,9 @@ namespace transport m_ReceiversThreadV6 = new std::thread (std::bind (&SSUServer::RunReceiversV6, this)); m_ReceiversServiceV6.post (std::bind (&SSUServer::ReceiveV6, this)); ScheduleTerminationV6 (); + ScheduleIntroducersUpdateTimerV6 (); // wait for 30 seconds and decide if we need introducers } SchedulePeerTestsCleanupTimer (); - ScheduleIntroducersUpdateTimer (); // wait for 30 seconds and decide if we need introducers } void SSUServer::Stop () @@ -100,6 +101,8 @@ namespace transport m_IsRunning = false; m_TerminationTimer.cancel (); m_TerminationTimerV6.cancel (); + m_IntroducersUpdateTimer.cancel (); + m_IntroducersUpdateTimerV6.cancel (); m_Service.stop (); m_Socket.close (); m_SocketV6.close (); @@ -659,20 +662,19 @@ namespace transport ); } - std::set SSUServer::FindIntroducers (int maxNumIntroducers) + std::set SSUServer::FindIntroducers (int maxNumIntroducers, bool v4) { uint32_t ts = i2p::util::GetSecondsSinceEpoch (); std::set ret; + auto filter = [&ret, ts](std::shared_ptr session)->bool + { + return session->GetRelayTag () && !ret.count (session.get ()) && + session->GetState () == eSessionStateEstablished && + ts < session->GetCreationTime () + SSU_TO_INTRODUCER_SESSION_DURATION; + }; for (int i = 0; i < maxNumIntroducers; i++) { - auto session = GetRandomV4Session ( - [&ret, ts](std::shared_ptr session)->bool - { - return session->GetRelayTag () && !ret.count (session.get ()) && - session->GetState () == eSessionStateEstablished && - ts < session->GetCreationTime () + SSU_TO_INTRODUCER_SESSION_DURATION; - } - ); + auto session = v4 ? GetRandomV4Session (filter) : GetRandomV6Session (filter); if (session) { ret.insert (session.get ()); @@ -687,39 +689,73 @@ namespace transport m_IntroducersUpdateTimer.cancel (); m_IntroducersUpdateTimer.expires_from_now (boost::posix_time::seconds(SSU_KEEP_ALIVE_INTERVAL/2)); m_IntroducersUpdateTimer.async_wait (std::bind (&SSUServer::HandleIntroducersUpdateTimer, - this, std::placeholders::_1)); + this, std::placeholders::_1, true)); } void SSUServer::ScheduleIntroducersUpdateTimer () { m_IntroducersUpdateTimer.expires_from_now (boost::posix_time::seconds(SSU_KEEP_ALIVE_INTERVAL)); m_IntroducersUpdateTimer.async_wait (std::bind (&SSUServer::HandleIntroducersUpdateTimer, - this, std::placeholders::_1)); + this, std::placeholders::_1, true)); } - void SSUServer::HandleIntroducersUpdateTimer (const boost::system::error_code& ecode) + void SSUServer::RescheduleIntroducersUpdateTimerV6 () + { + m_IntroducersUpdateTimerV6.cancel (); + m_IntroducersUpdateTimerV6.expires_from_now (boost::posix_time::seconds(SSU_KEEP_ALIVE_INTERVAL/2)); + m_IntroducersUpdateTimerV6.async_wait (std::bind (&SSUServer::HandleIntroducersUpdateTimer, + this, std::placeholders::_1, false)); + } + + void SSUServer::ScheduleIntroducersUpdateTimerV6 () + { + m_IntroducersUpdateTimerV6.expires_from_now (boost::posix_time::seconds(SSU_KEEP_ALIVE_INTERVAL)); + m_IntroducersUpdateTimerV6.async_wait (std::bind (&SSUServer::HandleIntroducersUpdateTimer, + this, std::placeholders::_1, false)); + } + + void SSUServer::HandleIntroducersUpdateTimer (const boost::system::error_code& ecode, bool v4) { if (ecode != boost::asio::error::operation_aborted) { // timeout expired - if (i2p::context.GetStatus () == eRouterStatusTesting) - { - // we still don't know if we need introducers - ScheduleIntroducersUpdateTimer (); - return; - } - if (i2p::context.GetStatus () != eRouterStatusFirewalled) + if (v4) { - // we don't need introducers - m_Introducers.clear (); - return; + if (i2p::context.GetStatus () == eRouterStatusTesting) + { + // we still don't know if we need introducers + ScheduleIntroducersUpdateTimer (); + return; + } + if (i2p::context.GetStatus () != eRouterStatusFirewalled) + { + // we don't need introducers + m_Introducers.clear (); + return; + } + } + else + { + if (i2p::context.GetStatusV6 () == eRouterStatusTesting) + { + // we still don't know if we need introducers + ScheduleIntroducersUpdateTimerV6 (); + return; + } + if (i2p::context.GetStatusV6 () != eRouterStatusFirewalled) + { + // we don't need introducers + m_IntroducersV6.clear (); + return; + } } // we are firewalled - if (!i2p::context.IsUnreachable ()) i2p::context.SetUnreachable (true, false); // ipv4 + if (!i2p::context.IsUnreachable () || !v4) i2p::context.SetUnreachable (v4, !v4); std::list newList; size_t numIntroducers = 0; uint32_t ts = i2p::util::GetSecondsSinceEpoch (); - for (const auto& it : m_Introducers) + auto& introducers = v4 ? m_Introducers : m_IntroducersV6; + for (const auto& it : introducers) { auto session = FindSession (it); if (session && ts < session->GetCreationTime () + SSU_TO_INTRODUCER_SESSION_DURATION) @@ -735,8 +771,8 @@ namespace transport if (numIntroducers < SSU_MAX_NUM_INTRODUCERS) { // create new - auto introducers = FindIntroducers (SSU_MAX_NUM_INTRODUCERS); - for (const auto& it1: introducers) + auto sessions = FindIntroducers (SSU_MAX_NUM_INTRODUCERS, true); + for (const auto& it1: sessions) { const auto& ep = it1->GetRemoteEndpoint (); i2p::data::RouterInfo::Introducer introducer; @@ -752,11 +788,11 @@ namespace transport } } } - m_Introducers = newList; - if (m_Introducers.size () < SSU_MAX_NUM_INTRODUCERS) + introducers = newList; + if (introducers.size () < SSU_MAX_NUM_INTRODUCERS) { std::set > requested; - for (auto i = m_Introducers.size (); i < SSU_MAX_NUM_INTRODUCERS; i++) + for (auto i = introducers.size (); i < SSU_MAX_NUM_INTRODUCERS; i++) { auto introducer = i2p::data::netdb.GetRandomIntroducer (); if (introducer && !requested.count (introducer)) // not requested already @@ -765,7 +801,7 @@ namespace transport if (address && !address->host.is_unspecified ()) { boost::asio::ip::udp::endpoint ep (address->host, address->port); - if (std::find (m_Introducers.begin (), m_Introducers.end (), ep) == m_Introducers.end ()) // not connected yet + if (std::find (introducers.begin (), introducers.end (), ep) == introducers.end ()) // not connected yet { CreateDirectSession (introducer, ep, false); requested.insert (introducer); @@ -774,7 +810,10 @@ namespace transport } } } - ScheduleIntroducersUpdateTimer (); + if (v4) + ScheduleIntroducersUpdateTimer (); + else + ScheduleIntroducersUpdateTimerV6 (); } } diff --git a/libi2pd/SSU.h b/libi2pd/SSU.h index 606651d7..cfeaf85f 100644 --- a/libi2pd/SSU.h +++ b/libi2pd/SSU.h @@ -71,6 +71,7 @@ namespace transport void RemoveRelay (uint32_t tag); std::shared_ptr FindRelaySession (uint32_t tag); void RescheduleIntroducersUpdateTimer (); + void RescheduleIntroducersUpdateTimerV6 (); void NewPeerTest (uint32_t nonce, PeerTestParticipant role, std::shared_ptr session = nullptr); PeerTestParticipant GetPeerTestParticipant (uint32_t nonce); @@ -99,9 +100,10 @@ namespace transport template std::shared_ptr GetRandomV6Session (Filter filter); - std::set FindIntroducers (int maxNumIntroducers); + std::set FindIntroducers (int maxNumIntroducers, bool v4); void ScheduleIntroducersUpdateTimer (); - void HandleIntroducersUpdateTimer (const boost::system::error_code& ecode); + void ScheduleIntroducersUpdateTimerV6 (); + void HandleIntroducersUpdateTimer (const boost::system::error_code& ecode, bool v4); void SchedulePeerTestsCleanupTimer (); void HandlePeerTestsCleanupTimer (const boost::system::error_code& ecode); @@ -127,9 +129,9 @@ namespace transport boost::asio::io_service::work m_Work, m_ReceiversWork, m_ReceiversWorkV6; boost::asio::ip::udp::endpoint m_Endpoint, m_EndpointV6; boost::asio::ip::udp::socket m_Socket, m_SocketV6; - boost::asio::deadline_timer m_IntroducersUpdateTimer, m_PeerTestsCleanupTimer, - m_TerminationTimer, m_TerminationTimerV6; - std::list m_Introducers; // introducers we are connected to + boost::asio::deadline_timer m_IntroducersUpdateTimer, m_IntroducersUpdateTimerV6, + m_PeerTestsCleanupTimer, m_TerminationTimer, m_TerminationTimerV6; + std::list m_Introducers, m_IntroducersV6; // introducers we are connected to std::map > m_Sessions, m_SessionsV6; std::map > m_Relays; // we are introducer std::map m_PeerTests; // nonce -> creation time in milliseconds diff --git a/libi2pd/SSUSession.cpp b/libi2pd/SSUSession.cpp index 19ccd1ce..7b7355a4 100644 --- a/libi2pd/SSUSession.cpp +++ b/libi2pd/SSUSession.cpp @@ -1017,7 +1017,10 @@ namespace transport if (IsV6 ()) { if (i2p::context.GetStatusV6 () == eRouterStatusTesting) + { i2p::context.SetStatusV6 (eRouterStatusFirewalled); + m_Server.RescheduleIntroducersUpdateTimerV6 (); + } } else if (i2p::context.GetStatus () == eRouterStatusTesting) // still not OK { From 060e30d2830a7bfae519880a208aa46ffabca24e Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 21 Apr 2021 08:16:13 -0400 Subject: [PATCH 57/87] select ipv6 random introducer --- libi2pd/NetDb.cpp | 6 +++--- libi2pd/NetDb.hpp | 2 +- libi2pd/SSU.cpp | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/libi2pd/NetDb.cpp b/libi2pd/NetDb.cpp index 80029ece..a71bb891 100644 --- a/libi2pd/NetDb.cpp +++ b/libi2pd/NetDb.cpp @@ -1168,12 +1168,12 @@ namespace data }); } - std::shared_ptr NetDb::GetRandomIntroducer () const + std::shared_ptr NetDb::GetRandomIntroducer (bool v4) const { return GetRandomRouter ( - [](std::shared_ptr router)->bool + [v4](std::shared_ptr router)->bool { - return router->IsIntroducer (true) && !router->IsHidden () && !router->IsFloodfill (); // floodfills don't send relay tag + return router->IsIntroducer (v4) && !router->IsHidden () && !router->IsFloodfill (); // floodfills don't send relay tag }); } diff --git a/libi2pd/NetDb.hpp b/libi2pd/NetDb.hpp index b782872c..244ff39b 100644 --- a/libi2pd/NetDb.hpp +++ b/libi2pd/NetDb.hpp @@ -87,7 +87,7 @@ namespace data std::shared_ptr GetHighBandwidthRandomRouter (std::shared_ptr compatibleWith, bool reverse) const; std::shared_ptr GetRandomPeerTestRouter (bool v4, const std::set& excluded) const; std::shared_ptr GetRandomSSUV6Router () const; // TODO: change to v6 peer test later - std::shared_ptr GetRandomIntroducer () const; + std::shared_ptr GetRandomIntroducer (bool v4) const; std::shared_ptr GetClosestFloodfill (const IdentHash& destination, const std::set& excluded, bool closeThanUsOnly = false) const; std::vector GetClosestFloodfills (const IdentHash& destination, size_t num, std::set& excluded, bool closeThanUsOnly = false) const; diff --git a/libi2pd/SSU.cpp b/libi2pd/SSU.cpp index 5ffcf890..b0ad1710 100644 --- a/libi2pd/SSU.cpp +++ b/libi2pd/SSU.cpp @@ -794,10 +794,10 @@ namespace transport std::set > requested; for (auto i = introducers.size (); i < SSU_MAX_NUM_INTRODUCERS; i++) { - auto introducer = i2p::data::netdb.GetRandomIntroducer (); + auto introducer = i2p::data::netdb.GetRandomIntroducer (v4); if (introducer && !requested.count (introducer)) // not requested already { - auto address = introducer->GetSSUAddress (true); // v4 + auto address = v4 ? introducer->GetSSUAddress (true) : introducer->GetSSUV6Address (); if (address && !address->host.is_unspecified ()) { boost::asio::ip::udp::endpoint ep (address->host, address->port); From 01e591b2617219875273a9e1a5bad16bad19a85d Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 21 Apr 2021 09:55:36 -0400 Subject: [PATCH 58/87] find ipv6 intrioducer session --- libi2pd/SSU.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd/SSU.cpp b/libi2pd/SSU.cpp index b0ad1710..fb7b7da1 100644 --- a/libi2pd/SSU.cpp +++ b/libi2pd/SSU.cpp @@ -771,7 +771,7 @@ namespace transport if (numIntroducers < SSU_MAX_NUM_INTRODUCERS) { // create new - auto sessions = FindIntroducers (SSU_MAX_NUM_INTRODUCERS, true); + auto sessions = FindIntroducers (SSU_MAX_NUM_INTRODUCERS, v4); for (const auto& it1: sessions) { const auto& ep = it1->GetRemoteEndpoint (); From 9c8c3b91747f8f557db8011005b1f4c07e2c2fc4 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 21 Apr 2021 10:56:39 -0400 Subject: [PATCH 59/87] select few introducers at the time --- libi2pd/SSU.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/libi2pd/SSU.cpp b/libi2pd/SSU.cpp index fb7b7da1..578c09eb 100644 --- a/libi2pd/SSU.cpp +++ b/libi2pd/SSU.cpp @@ -676,10 +676,9 @@ namespace transport { auto session = v4 ? GetRandomV4Session (filter) : GetRandomV6Session (filter); if (session) - { ret.insert (session.get ()); + else break; - } } return ret; } @@ -771,7 +770,7 @@ namespace transport if (numIntroducers < SSU_MAX_NUM_INTRODUCERS) { // create new - auto sessions = FindIntroducers (SSU_MAX_NUM_INTRODUCERS, v4); + auto sessions = FindIntroducers (SSU_MAX_NUM_INTRODUCERS - numIntroducers, v4); for (const auto& it1: sessions) { const auto& ep = it1->GetRemoteEndpoint (); From b5618af308301b5f8eec1204202ec80c68b1d639 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 21 Apr 2021 15:41:04 -0400 Subject: [PATCH 60/87] find all introducers at the time --- libi2pd/SSU.cpp | 37 +++++++++++++++++++++---------------- libi2pd/SSU.h | 2 +- 2 files changed, 22 insertions(+), 17 deletions(-) diff --git a/libi2pd/SSU.cpp b/libi2pd/SSU.cpp index 578c09eb..7a7400f9 100644 --- a/libi2pd/SSU.cpp +++ b/libi2pd/SSU.cpp @@ -662,24 +662,29 @@ namespace transport ); } - std::set SSUServer::FindIntroducers (int maxNumIntroducers, bool v4) + std::list > SSUServer::FindIntroducers (int maxNumIntroducers, bool v4) { uint32_t ts = i2p::util::GetSecondsSinceEpoch (); - std::set ret; - auto filter = [&ret, ts](std::shared_ptr session)->bool - { - return session->GetRelayTag () && !ret.count (session.get ()) && - session->GetState () == eSessionStateEstablished && - ts < session->GetCreationTime () + SSU_TO_INTRODUCER_SESSION_DURATION; - }; - for (int i = 0; i < maxNumIntroducers; i++) + std::list > ret; + const auto& sessions = v4 ? m_Sessions : m_SessionsV6; + for (const auto& s : sessions) + { + if (s.second->GetRelayTag () && s.second->GetState () == eSessionStateEstablished && + ts < s.second->GetCreationTime () + SSU_TO_INTRODUCER_SESSION_DURATION) + ret.push_back (s.second); + } + if ((int)ret.size () > maxNumIntroducers) { - auto session = v4 ? GetRandomV4Session (filter) : GetRandomV6Session (filter); - if (session) - ret.insert (session.get ()); - else - break; - } + // shink ret randomly + int sz = ret.size () - maxNumIntroducers; + for (int i = 0; i < sz; i++) + { + auto ind = rand () % ret.size (); + auto it = ret.begin (); + std::advance (it, ind); + ret.erase (it); + } + } return ret; } @@ -770,7 +775,7 @@ namespace transport if (numIntroducers < SSU_MAX_NUM_INTRODUCERS) { // create new - auto sessions = FindIntroducers (SSU_MAX_NUM_INTRODUCERS - numIntroducers, v4); + auto sessions = FindIntroducers (SSU_MAX_NUM_INTRODUCERS, v4); // try to find if duplicates for (const auto& it1: sessions) { const auto& ep = it1->GetRemoteEndpoint (); diff --git a/libi2pd/SSU.h b/libi2pd/SSU.h index cfeaf85f..e1751e0d 100644 --- a/libi2pd/SSU.h +++ b/libi2pd/SSU.h @@ -100,7 +100,7 @@ namespace transport template std::shared_ptr GetRandomV6Session (Filter filter); - std::set FindIntroducers (int maxNumIntroducers, bool v4); + std::list > FindIntroducers (int maxNumIntroducers, bool v4); void ScheduleIntroducersUpdateTimer (); void ScheduleIntroducersUpdateTimerV6 (); void HandleIntroducersUpdateTimer (const boost::system::error_code& ecode, bool v4); From b43a9cc80d63d770aa4d29b25347d639bc3185d0 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 21 Apr 2021 19:30:20 -0400 Subject: [PATCH 61/87] handle master session creation --- libi2pd_client/SAM.cpp | 1 + libi2pd_client/SAM.h | 6 ++++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/libi2pd_client/SAM.cpp b/libi2pd_client/SAM.cpp index 1eb38a7e..c662c283 100644 --- a/libi2pd_client/SAM.cpp +++ b/libi2pd_client/SAM.cpp @@ -352,6 +352,7 @@ namespace client if (style == SAM_VALUE_STREAM) type = eSAMSessionTypeStream; else if (style == SAM_VALUE_DATAGRAM) type = eSAMSessionTypeDatagram; else if (style == SAM_VALUE_RAW) type = eSAMSessionTypeRaw; + else if (style == SAM_VALUE_MASTER) type = eSAMSessionTypeMaster; if (type == eSAMSessionTypeUnknown) { // unknown style diff --git a/libi2pd_client/SAM.h b/libi2pd_client/SAM.h index 9495bf6f..8969c50e 100644 --- a/libi2pd_client/SAM.h +++ b/libi2pd_client/SAM.h @@ -76,6 +76,7 @@ namespace client const char SAM_VALUE_STREAM[] = "STREAM"; const char SAM_VALUE_DATAGRAM[] = "DATAGRAM"; const char SAM_VALUE_RAW[] = "RAW"; + const char SAM_VALUE_MASTER[] = "MASTER"; const char SAM_VALUE_TRUE[] = "true"; const char SAM_VALUE_FALSE[] = "false"; @@ -171,7 +172,8 @@ namespace client eSAMSessionTypeUnknown, eSAMSessionTypeStream, eSAMSessionTypeDatagram, - eSAMSessionTypeRaw + eSAMSessionTypeRaw, + eSAMSessionTypeMaster }; struct SAMSession @@ -187,7 +189,7 @@ namespace client void CloseStreams (); }; - + class SAMBridge: private i2p::util::RunnableService { public: From 9d79b265060d8afb9667fab473fef8c0364d09f3 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 22 Apr 2021 19:32:47 -0400 Subject: [PATCH 62/87] check if port if specified --- libi2pd/SSU.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libi2pd/SSU.cpp b/libi2pd/SSU.cpp index 7a7400f9..6bdd8661 100644 --- a/libi2pd/SSU.cpp +++ b/libi2pd/SSU.cpp @@ -453,7 +453,7 @@ namespace transport m_Service.post (std::bind (&SSUServer::CreateSessionThroughIntroducer, this, router, address, peerTest)); // always V4 thread else { - if (address->host.is_unspecified ()) return false; + if (address->host.is_unspecified () || !address->port) return false; boost::asio::ip::udp::endpoint remoteEndpoint (address->host, address->port); m_Service.post (std::bind (&SSUServer::CreateDirectSession, this, router, remoteEndpoint, peerTest)); } @@ -802,7 +802,7 @@ namespace transport if (introducer && !requested.count (introducer)) // not requested already { auto address = v4 ? introducer->GetSSUAddress (true) : introducer->GetSSUV6Address (); - if (address && !address->host.is_unspecified ()) + if (address && !address->host.is_unspecified () && address->port) { boost::asio::ip::udp::endpoint ep (address->host, address->port); if (std::find (introducers.begin (), introducers.end (), ep) == introducers.end ()) // not connected yet From 7a19533380195a1a2d42c68bac34ab42d522dc89 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 23 Apr 2021 12:17:48 -0400 Subject: [PATCH 63/87] reuse current introducers if no more available --- libi2pd/SSU.cpp | 33 ++++++++++++++++++++++++++------- libi2pd/SSU.h | 1 + libi2pd/SSUSession.h | 3 ++- 3 files changed, 29 insertions(+), 8 deletions(-) diff --git a/libi2pd/SSU.cpp b/libi2pd/SSU.cpp index 6bdd8661..49ce7e3e 100644 --- a/libi2pd/SSU.cpp +++ b/libi2pd/SSU.cpp @@ -670,7 +670,7 @@ namespace transport for (const auto& s : sessions) { if (s.second->GetRelayTag () && s.second->GetState () == eSessionStateEstablished && - ts < s.second->GetCreationTime () + SSU_TO_INTRODUCER_SESSION_DURATION) + ts < s.second->GetCreationTime () + SSU_TO_INTRODUCER_SESSION_EXPIRATION) ret.push_back (s.second); } if ((int)ret.size () > maxNumIntroducers) @@ -762,13 +762,19 @@ namespace transport for (const auto& it : introducers) { auto session = FindSession (it); - if (session && ts < session->GetCreationTime () + SSU_TO_INTRODUCER_SESSION_DURATION) + if (session) { - session->SendKeepAlive (); - newList.push_back (it); - numIntroducers++; + if (ts < session->GetCreationTime () + SSU_TO_INTRODUCER_SESSION_EXPIRATION) + session->SendKeepAlive (); + if (ts < session->GetCreationTime () + SSU_TO_INTRODUCER_SESSION_DURATION) + { + newList.push_back (it); + numIntroducers++; + } + else + session = nullptr; } - else + if (!session) i2p::context.RemoveIntroducer (it); } @@ -776,6 +782,19 @@ namespace transport { // create new auto sessions = FindIntroducers (SSU_MAX_NUM_INTRODUCERS, v4); // try to find if duplicates + if (sessions.empty () && !introducers.empty ()) + { + // bump creation time for previous introducers if no new sessions found + LogPrint (eLogDebug, "SSU: no new introducers found. Trying to reuse existing"); + for (const auto& it : introducers) + { + auto session = FindSession (it); + if (session) + session->SetCreationTime (session->GetCreationTime () + SSU_TO_INTRODUCER_SESSION_DURATION); + } + // try again + sessions = FindIntroducers (SSU_MAX_NUM_INTRODUCERS, v4); + } for (const auto& it1: sessions) { const auto& ep = it1->GetRemoteEndpoint (); @@ -784,7 +803,7 @@ namespace transport introducer.iPort = ep.port (); introducer.iTag = it1->GetRelayTag (); introducer.iKey = it1->GetIntroKey (); - introducer.iExp = it1->GetCreationTime () + SSU_TO_INTRODUCER_SESSION_DURATION; + introducer.iExp = it1->GetCreationTime () + SSU_TO_INTRODUCER_SESSION_EXPIRATION; if (i2p::context.AddIntroducer (introducer)) { newList.push_back (ep); diff --git a/libi2pd/SSU.h b/libi2pd/SSU.h index e1751e0d..cbe51e6b 100644 --- a/libi2pd/SSU.h +++ b/libi2pd/SSU.h @@ -31,6 +31,7 @@ namespace transport const int SSU_KEEP_ALIVE_INTERVAL = 30; // 30 seconds const int SSU_PEER_TEST_TIMEOUT = 60; // 60 seconds const int SSU_TO_INTRODUCER_SESSION_DURATION = 3600; // 1 hour + const int SSU_TO_INTRODUCER_SESSION_EXPIRATION = 4800; // 80 minutes const int SSU_TERMINATION_CHECK_TIMEOUT = 30; // 30 seconds const size_t SSU_MAX_NUM_INTRODUCERS = 3; const size_t SSU_SOCKET_RECEIVE_BUFFER_SIZE = 0x1FFFF; // 128K diff --git a/libi2pd/SSUSession.h b/libi2pd/SSUSession.h index ece8f5bf..43d0d595 100644 --- a/libi2pd/SSUSession.h +++ b/libi2pd/SSUSession.h @@ -102,7 +102,8 @@ namespace transport uint32_t GetRelayTag () const { return m_RelayTag; }; const i2p::data::RouterInfo::IntroKey& GetIntroKey () const { return m_IntroKey; }; uint32_t GetCreationTime () const { return m_CreationTime; }; - + void SetCreationTime (uint32_t ts) { m_CreationTime = ts; }; // for introducers + void FlushData (); private: From db93a7315f7408cfd5438a6e7ec194e8f3fdb50a Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 24 Apr 2021 11:11:12 -0400 Subject: [PATCH 64/87] find new introducers to connect --- libi2pd/NetDb.cpp | 7 ++++--- libi2pd/NetDb.hpp | 2 +- libi2pd/SSU.cpp | 9 +++++---- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/libi2pd/NetDb.cpp b/libi2pd/NetDb.cpp index a71bb891..a1d97cba 100644 --- a/libi2pd/NetDb.cpp +++ b/libi2pd/NetDb.cpp @@ -1168,12 +1168,13 @@ namespace data }); } - std::shared_ptr NetDb::GetRandomIntroducer (bool v4) const + std::shared_ptr NetDb::GetRandomIntroducer (bool v4, const std::set& excluded) const { return GetRandomRouter ( - [v4](std::shared_ptr router)->bool + [v4, &excluded](std::shared_ptr router)->bool { - return router->IsIntroducer (v4) && !router->IsHidden () && !router->IsFloodfill (); // floodfills don't send relay tag + return router->IsIntroducer (v4) && !excluded.count (router->GetIdentHash ()) && + !router->IsHidden () && !router->IsFloodfill (); // floodfills don't send relay tag }); } diff --git a/libi2pd/NetDb.hpp b/libi2pd/NetDb.hpp index 244ff39b..364cae4b 100644 --- a/libi2pd/NetDb.hpp +++ b/libi2pd/NetDb.hpp @@ -87,7 +87,7 @@ namespace data std::shared_ptr GetHighBandwidthRandomRouter (std::shared_ptr compatibleWith, bool reverse) const; std::shared_ptr GetRandomPeerTestRouter (bool v4, const std::set& excluded) const; std::shared_ptr GetRandomSSUV6Router () const; // TODO: change to v6 peer test later - std::shared_ptr GetRandomIntroducer (bool v4) const; + std::shared_ptr GetRandomIntroducer (bool v4, const std::set& excluded) const; std::shared_ptr GetClosestFloodfill (const IdentHash& destination, const std::set& excluded, bool closeThanUsOnly = false) const; std::vector GetClosestFloodfills (const IdentHash& destination, size_t num, std::set& excluded, bool closeThanUsOnly = false) const; diff --git a/libi2pd/SSU.cpp b/libi2pd/SSU.cpp index 49ce7e3e..9d75a069 100644 --- a/libi2pd/SSU.cpp +++ b/libi2pd/SSU.cpp @@ -778,6 +778,7 @@ namespace transport i2p::context.RemoveIntroducer (it); } + std::set excluded; if (numIntroducers < SSU_MAX_NUM_INTRODUCERS) { // create new @@ -809,16 +810,16 @@ namespace transport newList.push_back (ep); if (newList.size () >= SSU_MAX_NUM_INTRODUCERS) break; } + excluded.insert (it1->GetRemoteIdentity ()->GetIdentHash ()); } } introducers = newList; if (introducers.size () < SSU_MAX_NUM_INTRODUCERS) { - std::set > requested; for (auto i = introducers.size (); i < SSU_MAX_NUM_INTRODUCERS; i++) { - auto introducer = i2p::data::netdb.GetRandomIntroducer (v4); - if (introducer && !requested.count (introducer)) // not requested already + auto introducer = i2p::data::netdb.GetRandomIntroducer (v4, excluded); + if (introducer) { auto address = v4 ? introducer->GetSSUAddress (true) : introducer->GetSSUV6Address (); if (address && !address->host.is_unspecified () && address->port) @@ -827,7 +828,7 @@ namespace transport if (std::find (introducers.begin (), introducers.end (), ep) == introducers.end ()) // not connected yet { CreateDirectSession (introducer, ep, false); - requested.insert (introducer); + excluded.insert (introducer->GetIdentHash ()); } } } From 94555b9c431ff5fb7ed8d1fb1887cbd6cddc5af5 Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 24 Apr 2021 14:56:34 -0400 Subject: [PATCH 65/87] don't select next introducers from existing sessions --- libi2pd/SSU.cpp | 29 ++++++++++++----------------- libi2pd/SSU.h | 3 +-- 2 files changed, 13 insertions(+), 19 deletions(-) diff --git a/libi2pd/SSU.cpp b/libi2pd/SSU.cpp index 9d75a069..ad91a7c4 100644 --- a/libi2pd/SSU.cpp +++ b/libi2pd/SSU.cpp @@ -410,20 +410,6 @@ namespace transport if (session) session->FlushData (); } - std::shared_ptr SSUServer::FindSession (std::shared_ptr router) const - { - if (!router) return nullptr; - auto address = router->GetSSUAddress (true); // v4 only - if (!address) return nullptr; - auto session = FindSession (boost::asio::ip::udp::endpoint (address->host, address->port)); - if (session || !context.SupportsV6 ()) - return session; - // try v6 - address = router->GetSSUV6Address (); - if (!address) return nullptr; - return FindSession (boost::asio::ip::udp::endpoint (address->host, address->port)); - } - std::shared_ptr SSUServer::FindSession (const boost::asio::ip::udp::endpoint& e) const { auto& sessions = e.address ().is_v6 () ? m_SessionsV6 : m_Sessions; @@ -662,7 +648,8 @@ namespace transport ); } - std::list > SSUServer::FindIntroducers (int maxNumIntroducers, bool v4) + std::list > SSUServer::FindIntroducers (int maxNumIntroducers, + bool v4, std::set& excluded) { uint32_t ts = i2p::util::GetSecondsSinceEpoch (); std::list > ret; @@ -672,6 +659,8 @@ namespace transport if (s.second->GetRelayTag () && s.second->GetState () == eSessionStateEstablished && ts < s.second->GetCreationTime () + SSU_TO_INTRODUCER_SESSION_EXPIRATION) ret.push_back (s.second); + else + excluded.insert (s.second->GetRemoteIdentity ()->GetIdentHash ()); } if ((int)ret.size () > maxNumIntroducers) { @@ -782,7 +771,7 @@ namespace transport if (numIntroducers < SSU_MAX_NUM_INTRODUCERS) { // create new - auto sessions = FindIntroducers (SSU_MAX_NUM_INTRODUCERS, v4); // try to find if duplicates + auto sessions = FindIntroducers (SSU_MAX_NUM_INTRODUCERS, v4, excluded); // try to find if duplicates if (sessions.empty () && !introducers.empty ()) { // bump creation time for previous introducers if no new sessions found @@ -794,7 +783,8 @@ namespace transport session->SetCreationTime (session->GetCreationTime () + SSU_TO_INTRODUCER_SESSION_DURATION); } // try again - sessions = FindIntroducers (SSU_MAX_NUM_INTRODUCERS, v4); + excluded.clear (); + sessions = FindIntroducers (SSU_MAX_NUM_INTRODUCERS, v4, excluded); } for (const auto& it1: sessions) { @@ -831,6 +821,11 @@ namespace transport excluded.insert (introducer->GetIdentHash ()); } } + } + else + { + LogPrint (eLogDebug, "SSU: can't find more introducers"); + break; } } } diff --git a/libi2pd/SSU.h b/libi2pd/SSU.h index cbe51e6b..aad3a384 100644 --- a/libi2pd/SSU.h +++ b/libi2pd/SSU.h @@ -56,7 +56,6 @@ namespace transport bool CreateSession (std::shared_ptr router, std::shared_ptr address, bool peerTest = false); void CreateDirectSession (std::shared_ptr router, boost::asio::ip::udp::endpoint remoteEndpoint, bool peerTest); - std::shared_ptr FindSession (std::shared_ptr router) const; std::shared_ptr FindSession (const boost::asio::ip::udp::endpoint& e) const; std::shared_ptr GetRandomEstablishedV4Session (std::shared_ptr excluded); std::shared_ptr GetRandomEstablishedV6Session (std::shared_ptr excluded); @@ -101,7 +100,7 @@ namespace transport template std::shared_ptr GetRandomV6Session (Filter filter); - std::list > FindIntroducers (int maxNumIntroducers, bool v4); + std::list > FindIntroducers (int maxNumIntroducers, bool v4, std::set& excluded); void ScheduleIntroducersUpdateTimer (); void ScheduleIntroducersUpdateTimerV6 (); void HandleIntroducersUpdateTimer (const boost::system::error_code& ecode, bool v4); From 90dee900f043ad34908e75dfec5b2085b5bd0528 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 25 Apr 2021 10:57:31 -0400 Subject: [PATCH 66/87] fixed crash --- libi2pd/SSU.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libi2pd/SSU.cpp b/libi2pd/SSU.cpp index ad91a7c4..38e0196b 100644 --- a/libi2pd/SSU.cpp +++ b/libi2pd/SSU.cpp @@ -659,7 +659,7 @@ namespace transport if (s.second->GetRelayTag () && s.second->GetState () == eSessionStateEstablished && ts < s.second->GetCreationTime () + SSU_TO_INTRODUCER_SESSION_EXPIRATION) ret.push_back (s.second); - else + else if (s.second->GetRemoteIdentity ()) excluded.insert (s.second->GetRemoteIdentity ()->GetIdentHash ()); } if ((int)ret.size () > maxNumIntroducers) @@ -800,7 +800,8 @@ namespace transport newList.push_back (ep); if (newList.size () >= SSU_MAX_NUM_INTRODUCERS) break; } - excluded.insert (it1->GetRemoteIdentity ()->GetIdentHash ()); + if (it1->GetRemoteIdentity ()) + excluded.insert (it1->GetRemoteIdentity ()->GetIdentHash ()); } } introducers = newList; From 4a0dbec4fbdc389334457423404a664f2ba54d33 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 25 Apr 2021 16:42:09 -0400 Subject: [PATCH 67/87] recognize non-published NTCP2 address --- libi2pd/RouterContext.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index e4697f2b..a59f0602 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -547,7 +547,7 @@ namespace i2p { if (addr->transportStyle == i2p::data::RouterInfo::eTransportSSU) foundSSU = true; - else if (addr->IsPublishedNTCP2 ()) + else if (addr->transportStyle == i2p::data::RouterInfo::eTransportNTCP) foundNTCP2 = true; } port = addr->port; From e091eba83107e22d8a656c7fe28bc9a030f7f467 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 25 Apr 2021 17:55:13 -0400 Subject: [PATCH 68/87] don't cleanup ipv6 introducers list twice --- libi2pd/SSU.cpp | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/libi2pd/SSU.cpp b/libi2pd/SSU.cpp index 38e0196b..11fab97f 100644 --- a/libi2pd/SSU.cpp +++ b/libi2pd/SSU.cpp @@ -726,6 +726,8 @@ namespace transport m_Introducers.clear (); return; } + // we are firewalled + if (!i2p::context.IsUnreachable ()) i2p::context.SetUnreachable (true, false); // v4 } else { @@ -740,13 +742,17 @@ namespace transport // we don't need introducers m_IntroducersV6.clear (); return; - } + } + // we are firewalled + auto addr = i2p::context.GetRouterInfo ().GetSSUV6Address (); + if (addr && addr->ssu && addr->ssu->introducers.empty ()) + i2p::context.SetUnreachable (false, true); // v6 } - // we are firewalled - if (!i2p::context.IsUnreachable () || !v4) i2p::context.SetUnreachable (v4, !v4); + std::list newList; size_t numIntroducers = 0; uint32_t ts = i2p::util::GetSecondsSinceEpoch (); + std::set excluded; auto& introducers = v4 ? m_Introducers : m_IntroducersV6; for (const auto& it : introducers) { @@ -759,6 +765,8 @@ namespace transport { newList.push_back (it); numIntroducers++; + if (session->GetRemoteIdentity ()) + excluded.insert (session->GetRemoteIdentity ()->GetIdentHash ()); } else session = nullptr; @@ -766,8 +774,6 @@ namespace transport if (!session) i2p::context.RemoveIntroducer (it); } - - std::set excluded; if (numIntroducers < SSU_MAX_NUM_INTRODUCERS) { // create new From bd33ac202f7fc2a255524e9c8538d06642e6d577 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 26 Apr 2021 18:21:00 -0400 Subject: [PATCH 69/87] handle hostname for STREAM CREATE --- libi2pd_client/SAM.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/libi2pd_client/SAM.cpp b/libi2pd_client/SAM.cpp index c662c283..41d08147 100644 --- a/libi2pd_client/SAM.cpp +++ b/libi2pd_client/SAM.cpp @@ -496,10 +496,9 @@ namespace client else m_BufferOffset = 0; - std::shared_ptr
addr; - auto pos = destination.find(".b32.i2p"); - if (pos != std::string::npos) - addr = std::make_shared
(destination.substr (0, pos)); + std::shared_ptr addr; + if (destination.find(".i2p") != std::string::npos) + addr = context.GetAddressBook().GetAddress (destination); else { auto dest = std::make_shared (); From 4018cf9d76f330cceb92ab51a35dd28bbafa1d64 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 26 Apr 2021 21:11:36 -0400 Subject: [PATCH 70/87] SAM single and master sessions --- daemon/HTTPServer.cpp | 4 +-- daemon/I2PControl.cpp | 4 +-- libi2pd_client/SAM.cpp | 68 ++++++++++++++++++++++-------------------- libi2pd_client/SAM.h | 31 ++++++++++++++----- 4 files changed, 64 insertions(+), 43 deletions(-) diff --git a/daemon/HTTPServer.cpp b/daemon/HTTPServer.cpp index c263cea9..6410a044 100644 --- a/daemon/HTTPServer.cpp +++ b/daemon/HTTPServer.cpp @@ -842,7 +842,7 @@ namespace http { s << "SAM Sessions:
\r\n
\r\n"; for (auto& it: sam->GetSessions ()) { - auto& name = it.second->localDestination->GetNickname (); + auto& name = it.second->GetLocalDestination ()->GetNickname (); s << "\r\n" << std::endl; } @@ -868,7 +868,7 @@ namespace http { std::string webroot; i2p::config::GetOption("http.webroot", webroot); s << "SAM Session:
\r\n
\r\n"; - auto& ident = session->localDestination->GetIdentHash(); + auto& ident = session->GetLocalDestination ()->GetIdentHash(); s << "\r\n"; s << "
\r\n"; diff --git a/daemon/I2PControl.cpp b/daemon/I2PControl.cpp index 3f0033e5..d71a9f1c 100644 --- a/daemon/I2PControl.cpp +++ b/daemon/I2PControl.cpp @@ -714,8 +714,8 @@ namespace client for (auto& it: sam->GetSessions ()) { boost::property_tree::ptree sam_session, sam_session_sockets; - auto& name = it.second->localDestination->GetNickname (); - auto& ident = it.second->localDestination->GetIdentHash(); + auto& name = it.second->GetLocalDestination ()->GetNickname (); + auto& ident = it.second->GetLocalDestination ()->GetIdentHash(); sam_session.put("name", name); sam_session.put("address", i2p::client::context.GetAddressBook ().ToAddress(ident)); diff --git a/libi2pd_client/SAM.cpp b/libi2pd_client/SAM.cpp index 41d08147..c9c88709 100644 --- a/libi2pd_client/SAM.cpp +++ b/libi2pd_client/SAM.cpp @@ -58,8 +58,8 @@ namespace client { if (Session) { - if (m_IsAccepting && Session->localDestination) - Session->localDestination->StopAcceptingStreams (); + if (m_IsAccepting && Session->GetLocalDestination ()) + Session->GetLocalDestination ()->StopAcceptingStreams (); } break; } @@ -410,7 +410,7 @@ namespace client if (type == eSAMSessionTypeDatagram || type == eSAMSessionTypeRaw) { session->UDPEndpoint = forward; - auto dest = session->localDestination->CreateDatagramDestination (); + auto dest = session->GetLocalDestination ()->CreateDatagramDestination (); if (type == eSAMSessionTypeDatagram) dest->SetReceiver (std::bind (&SAMSocket::HandleI2PDatagramReceive, shared_from_this (), std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5)); @@ -419,7 +419,7 @@ namespace client std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4)); } - if (session->localDestination->IsReady ()) + if (session->GetLocalDestination ()->IsReady ()) SendSessionCreateReplyOk (); else { @@ -439,7 +439,7 @@ namespace client auto session = m_Owner.FindSession(m_ID); if(session) { - if (session->localDestination->IsReady ()) + if (session->GetLocalDestination ()->IsReady ()) SendSessionCreateReplyOk (); else { @@ -458,7 +458,7 @@ namespace client { uint8_t buf[1024]; char priv[1024]; - size_t l = session->localDestination->GetPrivateKeys ().ToBuffer (buf, 1024); + size_t l = session->GetLocalDestination ()->GetPrivateKeys ().ToBuffer (buf, 1024); size_t l1 = i2p::data::ByteStreamToBase64 (buf, l, priv, 1024); priv[l1] = 0; #ifdef _MSC_VER @@ -514,18 +514,18 @@ namespace client { if (addr->IsIdentHash ()) { - auto leaseSet = session->localDestination->FindLeaseSet(addr->identHash); + auto leaseSet = session->GetLocalDestination ()->FindLeaseSet(addr->identHash); if (leaseSet) Connect(leaseSet, session); else { - session->localDestination->RequestDestination(addr->identHash, + session->GetLocalDestination ()->RequestDestination(addr->identHash, std::bind(&SAMSocket::HandleConnectLeaseSetRequestComplete, shared_from_this(), std::placeholders::_1)); } } else // B33 - session->localDestination->RequestDestinationWithEncryptedLeaseSet (addr->blindedPublicKey, + session->GetLocalDestination ()->RequestDestinationWithEncryptedLeaseSet (addr->blindedPublicKey, std::bind(&SAMSocket::HandleConnectLeaseSetRequestComplete, shared_from_this(), std::placeholders::_1)); } @@ -542,7 +542,7 @@ namespace client if (session) { m_SocketType = eSAMSocketTypeStream; - m_Stream = session->localDestination->CreateStream (remote); + m_Stream = session->GetLocalDestination ()->CreateStream (remote); if (m_Stream) { m_Stream->Send ((uint8_t *)m_Buffer, m_BufferOffset); // connect and send @@ -586,10 +586,10 @@ namespace client if (session) { m_SocketType = eSAMSocketTypeAcceptor; - if (!session->localDestination->IsAcceptingStreams ()) + if (!session->GetLocalDestination ()->IsAcceptingStreams ()) { m_IsAccepting = true; - session->localDestination->AcceptOnce (std::bind (&SAMSocket::HandleI2PAccept, shared_from_this (), std::placeholders::_1)); + session->GetLocalDestination ()->AcceptOnce (std::bind (&SAMSocket::HandleI2PAccept, shared_from_this (), std::placeholders::_1)); } SendMessageReply (SAM_STREAM_STATUS_OK, strlen(SAM_STREAM_STATUS_OK), false); } @@ -609,7 +609,7 @@ namespace client SendMessageReply (SAM_STREAM_STATUS_INVALID_ID, strlen(SAM_STREAM_STATUS_INVALID_ID), true); return; } - if (session->localDestination->IsAcceptingStreams ()) + if (session->GetLocalDestination ()->IsAcceptingStreams ()) { SendI2PError ("Already accepting"); return; @@ -639,7 +639,7 @@ namespace client m_IsAccepting = true; std::string& silent = params[SAM_PARAM_SILENT]; if (silent == SAM_VALUE_TRUE) m_IsSilent = true; - session->localDestination->AcceptStreams (std::bind (&SAMSocket::HandleI2PForward, + session->GetLocalDestination ()->AcceptStreams (std::bind (&SAMSocket::HandleI2PForward, shared_from_this (), std::placeholders::_1, ep)); SendMessageReply (SAM_STREAM_STATUS_OK, strlen(SAM_STREAM_STATUS_OK), false); } @@ -655,7 +655,7 @@ namespace client auto session = m_Owner.FindSession(m_ID); if (session) { - auto d = session->localDestination->GetDatagramDestination (); + auto d = session->GetLocalDestination ()->GetDatagramDestination (); if (d) { i2p::data::IdentityEx dest; @@ -725,7 +725,7 @@ namespace client std::shared_ptr identity; std::shared_ptr addr; auto session = m_Owner.FindSession(m_ID); - auto dest = session == nullptr ? context.GetSharedLocalDestination() : session->localDestination; + auto dest = session == nullptr ? context.GetSharedLocalDestination() : session->GetLocalDestination (); if (name == "ME") SendNamingLookupReply (name, dest->GetIdentity ()); else if ((identity = context.GetAddressBook ().GetFullAddress (name)) != nullptr) @@ -971,7 +971,7 @@ namespace client if (it->m_SocketType == eSAMSocketTypeAcceptor) { it->m_IsAccepting = true; - session->localDestination->AcceptOnce (std::bind (&SAMSocket::HandleI2PAccept, it, std::placeholders::_1)); + session->GetLocalDestination ()->AcceptOnce (std::bind (&SAMSocket::HandleI2PAccept, it, std::placeholders::_1)); break; } } @@ -1109,19 +1109,11 @@ namespace client m_Owner.GetService ().post (std::bind( !ec ? &SAMSocket::Receive : &SAMSocket::TerminateClose, shared_from_this())); } - SAMSession::SAMSession (SAMBridge & parent, const std::string & id, SAMSessionType type, std::shared_ptr dest): - m_Bridge(parent), - localDestination (dest), - UDPEndpoint(nullptr), - Name(id), Type (type) + SAMSession::SAMSession (SAMBridge & parent, const std::string & id, SAMSessionType type): + m_Bridge(parent), Name(id), Type (type), UDPEndpoint(nullptr) { } - SAMSession::~SAMSession () - { - i2p::client::context.DeleteLocalDestination (localDestination); - } - void SAMSession::CloseStreams () { for(const auto & itr : m_Bridge.ListSockets(Name)) @@ -1130,6 +1122,17 @@ namespace client } } + SAMSingleSession::SAMSingleSession (SAMBridge & parent, const std::string & name, SAMSessionType type, std::shared_ptr dest): + SAMSession (parent, name, type), + localDestination (dest) + { + } + + SAMSingleSession::~SAMSingleSession () + { + i2p::client::context.DeleteLocalDestination (localDestination); + } + SAMBridge::SAMBridge (const std::string& address, int port, bool singleThread): RunnableService ("SAM"), m_IsSingleThread (singleThread), m_Acceptor (GetIOService (), boost::asio::ip::tcp::endpoint(boost::asio::ip::address::from_string(address), port)), @@ -1267,7 +1270,8 @@ namespace client if (localDestination) { localDestination->Acquire (); - auto session = std::make_shared(*this, id, type, localDestination); + auto session = (type == eSAMSessionTypeMaster) ? std::make_shared(*this, id, localDestination) : + std::make_shared(*this, id, type, localDestination); std::unique_lock l(m_SessionsMutex); auto ret = m_Sessions.insert (std::make_pair(id, session)); if (!ret.second) @@ -1291,8 +1295,8 @@ namespace client } if (session) { - session->localDestination->Release (); - session->localDestination->StopAcceptingStreams (); + session->GetLocalDestination ()->Release (); + session->GetLocalDestination ()->StopAcceptingStreams (); session->CloseStreams (); if (m_IsSingleThread) { @@ -1368,10 +1372,10 @@ namespace client i2p::data::IdentityEx dest; dest.FromBase64 (destination); if (session->Type == eSAMSessionTypeDatagram) - session->localDestination->GetDatagramDestination ()-> + session->GetLocalDestination ()->GetDatagramDestination ()-> SendDatagramTo ((uint8_t *)eol, payloadLen, dest.GetIdentHash ()); else // raw - session->localDestination->GetDatagramDestination ()-> + session->GetLocalDestination ()->GetDatagramDestination ()-> SendRawDatagramTo ((uint8_t *)eol, payloadLen, dest.GetIdentHash ()); } else diff --git a/libi2pd_client/SAM.h b/libi2pd_client/SAM.h index 8969c50e..2c2729cf 100644 --- a/libi2pd_client/SAM.h +++ b/libi2pd_client/SAM.h @@ -179,17 +179,34 @@ namespace client struct SAMSession { SAMBridge & m_Bridge; - std::shared_ptr localDestination; - std::shared_ptr UDPEndpoint; std::string Name; SAMSessionType Type; - - SAMSession (SAMBridge & parent, const std::string & name, SAMSessionType type, std::shared_ptr dest); - ~SAMSession (); - + std::shared_ptr UDPEndpoint; // TODO: move + + SAMSession (SAMBridge & parent, const std::string & name, SAMSessionType type); + virtual ~SAMSession () {}; + + virtual std::shared_ptr GetLocalDestination () = 0; + void CloseStreams (); }; - + + struct SAMSingleSession: public SAMSession + { + std::shared_ptr localDestination; + + SAMSingleSession (SAMBridge & parent, const std::string & name, SAMSessionType type, std::shared_ptr dest); + ~SAMSingleSession (); + + std::shared_ptr GetLocalDestination () { return localDestination; }; + }; + + struct SAMMasterSession: public SAMSingleSession + { + SAMMasterSession (SAMBridge & parent, const std::string & name, std::shared_ptr dest): + SAMSingleSession (parent, name, eSAMSessionTypeMaster, dest) {}; + }; + class SAMBridge: private i2p::util::RunnableService { public: From d8d8a688143cc3bf9f69fd34a730e70c97da1b6b Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 30 Apr 2021 15:19:31 -0400 Subject: [PATCH 71/87] rekey all routers but floodfills --- libi2pd/RouterContext.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index a59f0602..9602fe17 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -740,8 +740,8 @@ namespace i2p if (!rekey && m_Keys.GetPublic ()->GetCryptoKeyType () == i2p::data::CRYPTO_KEY_TYPE_ELGAMAL) { // rekey routers with bandwidth = L (or default) this time - std::string bandwidth; i2p::config::GetOption("bandwidth", bandwidth); - if (bandwidth.empty () || bandwidth[0] == 'L') rekey = true; + bool isFloodfill; i2p::config::GetOption("floodfill", isFloodfill); + if (!isFloodfill) rekey = true; } if (rekey) { From 7f143a7f232584ea269b467e8ac0ce3ecc6d40e1 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 2 May 2021 15:02:52 -0400 Subject: [PATCH 72/87] support EdDSA for blinding --- libi2pd/Blinding.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/libi2pd/Blinding.cpp b/libi2pd/Blinding.cpp index 6770d223..dbab9b94 100644 --- a/libi2pd/Blinding.cpp +++ b/libi2pd/Blinding.cpp @@ -1,5 +1,5 @@ /* -* Copyright (c) 2013-2020, The PurpleI2P Project +* Copyright (c) 2013-2021, The PurpleI2P Project * * This file is part of Purple i2pd project and licensed under BSD3 * @@ -272,11 +272,19 @@ namespace data case i2p::data::SIGNING_KEY_TYPE_ECDSA_SHA384_P384: case i2p::data::SIGNING_KEY_TYPE_ECDSA_SHA512_P521: publicKeyLength = BlindECDSA (m_SigType, priv, seed, BlindEncodedPrivateKeyECDSA, blindedPriv, blindedPub); - break; + break; case i2p::data::SIGNING_KEY_TYPE_REDDSA_SHA512_ED25519: i2p::crypto::GetEd25519 ()->BlindPrivateKey (priv, seed, blindedPriv, blindedPub); publicKeyLength = i2p::crypto::EDDSA25519_PUBLIC_KEY_LENGTH; break; + case i2p::data::SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519: + { + uint8_t exp[64]; + i2p::crypto::Ed25519::ExpandPrivateKey (priv, exp); + i2p::crypto::GetEd25519 ()->BlindPrivateKey (exp, seed, blindedPriv, blindedPub); + publicKeyLength = i2p::crypto::EDDSA25519_PUBLIC_KEY_LENGTH; + break; + } default: LogPrint (eLogError, "Blinding: can't blind signature type ", (int)m_SigType); } From 0b9cb4e75b8931fd9bdde52a60f1615871a59799 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 3 May 2021 19:05:25 -0400 Subject: [PATCH 73/87] check identity and signature length for SessionConfirmed --- libi2pd/SSUSession.cpp | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/libi2pd/SSUSession.cpp b/libi2pd/SSUSession.cpp index 7b7355a4..3c519d6b 100644 --- a/libi2pd/SSUSession.cpp +++ b/libi2pd/SSUSession.cpp @@ -321,12 +321,17 @@ namespace transport auto headerSize = GetSSUHeaderSize (buf); if (headerSize >= len) { - LogPrint (eLogError, "SSU: Session confirmed header size ", len, " exceeds packet length ", len); + LogPrint (eLogError, "SSU: Session confirmed header size ", headerSize, " exceeds packet length ", len); return; } const uint8_t * payload = buf + headerSize; payload++; // identity fragment info uint16_t identitySize = bufbe16toh (payload); + if (identitySize + headerSize + 7 > len) // 7 = fragment info + fragment size + signed on time + { + LogPrint (eLogError, "SSU: Session confirmed identity size ", identitySize, " exceeds packet length ", len); + return; + } payload += 2; // size of identity fragment auto identity = std::make_shared (payload, identitySize); auto existing = i2p::data::netdb.FindRouter (identity->GetIdentHash ()); // check if exists already @@ -344,10 +349,15 @@ namespace transport if (m_SignedData) m_SignedData->Insert (payload, 4); // insert Alice's signed on time payload += 4; // signed-on time - size_t paddingSize = (payload - buf) + m_RemoteIdentity->GetSignatureLen (); - paddingSize &= 0x0F; // %16 + size_t fullSize = (payload - buf) + m_RemoteIdentity->GetSignatureLen (); + size_t paddingSize = fullSize & 0x0F; // %16 if (paddingSize > 0) paddingSize = 16 - paddingSize; payload += paddingSize; + if (fullSize + paddingSize > len) + { + LogPrint (eLogError, "SSU: Session confirmed message is too short ", len); + return; + } // verify signature if (m_SignedData && m_SignedData->Verify (m_RemoteIdentity, payload)) { From fffa550bb0bfeda045a6b98dc1631ec68cf0166d Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 4 May 2021 14:27:06 -0400 Subject: [PATCH 74/87] SAM subsessions --- libi2pd/Destination.cpp | 19 ++++++++++++++-- libi2pd/Destination.h | 1 + libi2pd_client/SAM.cpp | 50 +++++++++++++++++++++++++++++++++++++++-- libi2pd_client/SAM.h | 19 +++++++++++++++- 4 files changed, 84 insertions(+), 5 deletions(-) diff --git a/libi2pd/Destination.cpp b/libi2pd/Destination.cpp index f47ac421..22ba0b39 100644 --- a/libi2pd/Destination.cpp +++ b/libi2pd/Destination.cpp @@ -1131,13 +1131,28 @@ namespace client return dest; } + std::shared_ptr ClientDestination::RemoveStreamingDestination (int port) + { + if (port) + { + auto it = m_StreamingDestinationsByPorts.find (port); + if (it != m_StreamingDestinationsByPorts.end ()) + { + auto ret = it->second; + m_StreamingDestinationsByPorts.erase (it); + return ret; + } + } + return nullptr; + } + i2p::datagram::DatagramDestination * ClientDestination::CreateDatagramDestination (bool gzip) { if (m_DatagramDestination == nullptr) m_DatagramDestination = new i2p::datagram::DatagramDestination (GetSharedFromThis (), gzip); return m_DatagramDestination; - } - + } + std::vector > ClientDestination::GetAllStreams () const { std::vector > ret; diff --git a/libi2pd/Destination.h b/libi2pd/Destination.h index f04431c7..6e149cf5 100644 --- a/libi2pd/Destination.h +++ b/libi2pd/Destination.h @@ -236,6 +236,7 @@ namespace client // streaming std::shared_ptr CreateStreamingDestination (int port, bool gzip = true); // additional std::shared_ptr GetStreamingDestination (int port = 0) const; + std::shared_ptr RemoveStreamingDestination (int port); // following methods operate with default streaming destination void CreateStream (StreamRequestComplete streamRequestComplete, const i2p::data::IdentHash& dest, int port = 0); void CreateStream (StreamRequestComplete streamRequestComplete, std::shared_ptr dest, int port = 0); diff --git a/libi2pd_client/SAM.cpp b/libi2pd_client/SAM.cpp index c9c88709..061cc820 100644 --- a/libi2pd_client/SAM.cpp +++ b/libi2pd_client/SAM.cpp @@ -270,6 +270,10 @@ namespace client ProcessDestGenerate (separator + 1, bytes_transferred - (separator - m_Buffer) - 1); else if (!strcmp (m_Buffer, SAM_NAMING_LOOKUP)) ProcessNamingLookup (separator + 1, bytes_transferred - (separator - m_Buffer) - 1); + else if (!strcmp (m_Buffer, SAM_SESSION_ADD)) + ProcessSessionAdd (separator + 1, bytes_transferred - (separator - m_Buffer) - 1); + else if (!strcmp (m_Buffer, SAM_SESSION_REMOVE)) + ProcessSessionRemove (separator + 1, bytes_transferred - (separator - m_Buffer) - 1); else if (!strcmp (m_Buffer, SAM_DATAGRAM_SEND) || !strcmp (m_Buffer, SAM_RAW_SEND)) { size_t len = bytes_transferred - (separator - m_Buffer) - 1; @@ -759,6 +763,16 @@ namespace client } } + void SAMSocket::ProcessSessionAdd (char * buf, size_t len) + { + // TODO: implement + } + + void SAMSocket::ProcessSessionRemove (char * buf, size_t len) + { + // TODO: implement + } + void SAMSocket::SendI2PError(const std::string & msg) { LogPrint (eLogError, "SAM: i2p error ", msg); @@ -1132,6 +1146,39 @@ namespace client { i2p::client::context.DeleteLocalDestination (localDestination); } + + void SAMSingleSession::StopLocalDestination () + { + localDestination->Release (); + localDestination->StopAcceptingStreams (); + } + + SAMSubSession::SAMSubSession (std::shared_ptr master, const std::string& name, SAMSessionType type, int port): + SAMSession (master->m_Bridge, name, type), masterSession (master), inPort (port) + { + if (Type == eSAMSessionTypeStream) + { + auto d = masterSession->GetLocalDestination ()->CreateStreamingDestination (inPort); + if (d) d->Start (); + } + // TODO: implement datagrams + } + + std::shared_ptr SAMSubSession::GetLocalDestination () + { + return masterSession ? masterSession->GetLocalDestination () : nullptr; + } + + void SAMSubSession::StopLocalDestination () + { + auto dest = GetLocalDestination (); + if (dest && Type == eSAMSessionTypeStream) + { + auto d = dest->RemoveStreamingDestination (inPort); + if (d) d->Stop (); + } + // TODO: implement datagrams + } SAMBridge::SAMBridge (const std::string& address, int port, bool singleThread): RunnableService ("SAM"), m_IsSingleThread (singleThread), @@ -1295,8 +1342,7 @@ namespace client } if (session) { - session->GetLocalDestination ()->Release (); - session->GetLocalDestination ()->StopAcceptingStreams (); + session->StopLocalDestination (); session->CloseStreams (); if (m_IsSingleThread) { diff --git a/libi2pd_client/SAM.h b/libi2pd_client/SAM.h index 2c2729cf..8669538a 100644 --- a/libi2pd_client/SAM.h +++ b/libi2pd_client/SAM.h @@ -41,6 +41,8 @@ namespace client const char SAM_SESSION_CREATE_INVALID_ID[] = "SESSION STATUS RESULT=INVALID_ID\n"; const char SAM_SESSION_STATUS_INVALID_KEY[] = "SESSION STATUS RESULT=INVALID_KEY\n"; const char SAM_SESSION_STATUS_I2P_ERROR[] = "SESSION STATUS RESULT=I2P_ERROR MESSAGE=%s\n"; + const char SAM_SESSION_ADD[] = "SESSION ADD"; + const char SAM_SESSION_REMOVE[] = "SESSION REMOVE"; const char SAM_STREAM_CONNECT[] = "STREAM CONNECT"; const char SAM_STREAM_STATUS_OK[] = "STREAM STATUS RESULT=OK\n"; const char SAM_STREAM_STATUS_INVALID_ID[] = "STREAM STATUS RESULT=INVALID_ID\n"; @@ -135,6 +137,8 @@ namespace client void ProcessStreamForward (char * buf, size_t len); void ProcessDestGenerate (char * buf, size_t len); void ProcessNamingLookup (char * buf, size_t len); + void ProcessSessionAdd (char * buf, size_t len); + void ProcessSessionRemove (char * buf, size_t len); void SendI2PError(const std::string & msg); size_t ProcessDatagramSend (char * buf, size_t len, const char * data); // from SAM 1.0 void ExtractParams (char * buf, std::map& params); @@ -187,6 +191,7 @@ namespace client virtual ~SAMSession () {}; virtual std::shared_ptr GetLocalDestination () = 0; + virtual void StopLocalDestination () = 0; void CloseStreams (); }; @@ -199,6 +204,7 @@ namespace client ~SAMSingleSession (); std::shared_ptr GetLocalDestination () { return localDestination; }; + void StopLocalDestination (); }; struct SAMMasterSession: public SAMSingleSession @@ -206,7 +212,18 @@ namespace client SAMMasterSession (SAMBridge & parent, const std::string & name, std::shared_ptr dest): SAMSingleSession (parent, name, eSAMSessionTypeMaster, dest) {}; }; - + + struct SAMSubSession: public SAMSession + { + std::shared_ptr masterSession; + int inPort; + + SAMSubSession (std::shared_ptr master, const std::string& name, SAMSessionType type, int port); + // implements SAMSession + std::shared_ptr GetLocalDestination (); + void StopLocalDestination (); + }; + class SAMBridge: private i2p::util::RunnableService { public: From 5ad4c2a65ec3d8338e03c67ed57aee8b2708cec0 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 4 May 2021 14:59:25 -0400 Subject: [PATCH 75/87] run ipv6 peer test again if still testing --- libi2pd/Transports.cpp | 15 +++++++++------ libi2pd/Transports.h | 6 +++--- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/libi2pd/Transports.cpp b/libi2pd/Transports.cpp index 4ad13518..8413c859 100644 --- a/libi2pd/Transports.cpp +++ b/libi2pd/Transports.cpp @@ -581,10 +581,10 @@ namespace transport LogPrint (eLogError, "Transports: Can't detect external IP. SSU is not available"); } - void Transports::PeerTest () + void Transports::PeerTest (bool ipv4, bool ipv6) { if (RoutesRestricted() || !m_SSUServer) return; - if (i2p::context.SupportsV4 ()) + if (ipv4 && i2p::context.SupportsV4 ()) { LogPrint (eLogInfo, "Transports: Started peer test ipv4"); std::set excluded; @@ -610,7 +610,7 @@ namespace transport if (!statusChanged) LogPrint (eLogWarning, "Transports: Can't find routers for peer test ipv4"); } - if (i2p::context.SupportsV6 ()) + if (ipv6 && i2p::context.SupportsV6 ()) { LogPrint (eLogInfo, "Transports: Started peer test ipv6"); std::set excluded; @@ -750,9 +750,12 @@ namespace transport ++it; } UpdateBandwidth (); // TODO: use separate timer(s) for it - if (i2p::context.GetStatus () == eRouterStatusTesting) // if still testing, repeat peer test - DetectExternalIP (); - m_PeerCleanupTimer->expires_from_now (boost::posix_time::seconds(5*SESSION_CREATION_TIMEOUT)); + bool ipv4Testing = i2p::context.GetStatus () == eRouterStatusTesting; + bool ipv6Testing = i2p::context.GetStatusV6 () == eRouterStatusTesting; + // if still testing, repeat peer test + if (ipv4Testing || ipv6Testing) + PeerTest (ipv4Testing, ipv6Testing); + m_PeerCleanupTimer->expires_from_now (boost::posix_time::seconds(3*SESSION_CREATION_TIMEOUT)); m_PeerCleanupTimer->async_wait (std::bind (&Transports::HandlePeerCleanupTimer, this, std::placeholders::_1)); } } diff --git a/libi2pd/Transports.h b/libi2pd/Transports.h index d480840a..9377286c 100644 --- a/libi2pd/Transports.h +++ b/libi2pd/Transports.h @@ -76,9 +76,9 @@ namespace transport } }; - const size_t SESSION_CREATION_TIMEOUT = 10; // in seconds + const size_t SESSION_CREATION_TIMEOUT = 15; // in seconds const int PEER_TEST_INTERVAL = 71; // in minutes - const int MAX_NUM_DELAYED_MESSAGES = 50; + const int MAX_NUM_DELAYED_MESSAGES = 150; class Transports { public: @@ -131,7 +131,7 @@ namespace transport bool IsRestrictedPeer(const i2p::data::IdentHash & ident) const; - void PeerTest (); + void PeerTest (bool ipv4 = true, bool ipv6 = true); void SetCheckReserved (bool check) { m_CheckReserved = check; }; bool IsCheckReserved () { return m_CheckReserved; }; From 79dbf2a43e3b5b2bdbecb9c3727e04f22b4c3edb Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 7 May 2021 22:15:12 -0400 Subject: [PATCH 76/87] request encrypted LeaseSet if expired --- libi2pd/Streaming.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/libi2pd/Streaming.cpp b/libi2pd/Streaming.cpp index 0d482303..a484c433 100644 --- a/libi2pd/Streaming.cpp +++ b/libi2pd/Streaming.cpp @@ -942,15 +942,21 @@ namespace stream { if (!m_RemoteLeaseSet || m_RemoteLeaseSet->IsExpired ()) { - m_RemoteLeaseSet = m_LocalDestination.GetOwner ()->FindLeaseSet (m_RemoteIdentity->GetIdentHash ()); - if (!m_RemoteLeaseSet) + auto remoteLeaseSet = m_LocalDestination.GetOwner ()->FindLeaseSet (m_RemoteIdentity->GetIdentHash ()); + if (!remoteLeaseSet) { - LogPrint (eLogWarning, "Streaming: LeaseSet ", m_RemoteIdentity->GetIdentHash ().ToBase64 (), " not found"); - m_LocalDestination.GetOwner ()->RequestDestination (m_RemoteIdentity->GetIdentHash ()); // try to request for a next attempt + LogPrint (eLogWarning, "Streaming: LeaseSet ", m_RemoteIdentity->GetIdentHash ().ToBase64 (), m_RemoteLeaseSet ? " expired" : " not found"); + if (m_RemoteLeaseSet && m_RemoteLeaseSet->IsPublishedEncrypted ()) + m_LocalDestination.GetOwner ()->RequestDestinationWithEncryptedLeaseSet ( + std::make_shared(m_RemoteIdentity)); + else + m_LocalDestination.GetOwner ()->RequestDestination (m_RemoteIdentity->GetIdentHash ()); // try to request for a next attempt + return; } else { // LeaseSet updated + m_RemoteLeaseSet = remoteLeaseSet; m_RemoteIdentity = m_RemoteLeaseSet->GetIdentity (); m_TransientVerifier = m_RemoteLeaseSet->GetTransientVerifier (); } From d6f5640685dd542454771882181a29ec23885feb Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 9 May 2021 07:33:26 -0400 Subject: [PATCH 77/87] attach updated LeaseSet to ECIESx25519 incoming sessions --- libi2pd/ECIESX25519AEADRatchetSession.cpp | 6 ++++-- libi2pd/ECIESX25519AEADRatchetSession.h | 2 +- libi2pd/Streaming.cpp | 9 +++++++-- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/libi2pd/ECIESX25519AEADRatchetSession.cpp b/libi2pd/ECIESX25519AEADRatchetSession.cpp index f956fa67..0f2518f7 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.cpp +++ b/libi2pd/ECIESX25519AEADRatchetSession.cpp @@ -160,9 +160,10 @@ namespace garlic return true; } - ECIESX25519AEADRatchetSession::ECIESX25519AEADRatchetSession (GarlicDestination * owner, bool attachLeaseSet): - GarlicRoutingSession (owner, attachLeaseSet) + ECIESX25519AEADRatchetSession::ECIESX25519AEADRatchetSession (GarlicDestination * owner, bool attachLeaseSetNS): + GarlicRoutingSession (owner, true) { + if (!attachLeaseSetNS) SetLeaseSetUpdateStatus (eLeaseSetUpToDate); RAND_bytes (m_PaddingSizes, 32); m_NextPaddingSize = 0; } @@ -1101,6 +1102,7 @@ namespace garlic RouterIncomingRatchetSession::RouterIncomingRatchetSession (const i2p::crypto::NoiseSymmetricState& initState): ECIESX25519AEADRatchetSession (&i2p::context, false) { + SetLeaseSetUpdateStatus (eLeaseSetDoNotSend); SetNoiseState (initState); } diff --git a/libi2pd/ECIESX25519AEADRatchetSession.h b/libi2pd/ECIESX25519AEADRatchetSession.h index bd6d55e3..24bffae2 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.h +++ b/libi2pd/ECIESX25519AEADRatchetSession.h @@ -160,7 +160,7 @@ namespace garlic public: - ECIESX25519AEADRatchetSession (GarlicDestination * owner, bool attachLeaseSet); + ECIESX25519AEADRatchetSession (GarlicDestination * owner, bool attachLeaseSetNS); ~ECIESX25519AEADRatchetSession (); bool HandleNextMessage (uint8_t * buf, size_t len, std::shared_ptr receiveTagset, int index = 0); diff --git a/libi2pd/Streaming.cpp b/libi2pd/Streaming.cpp index a484c433..612b1058 100644 --- a/libi2pd/Streaming.cpp +++ b/libi2pd/Streaming.cpp @@ -946,12 +946,17 @@ namespace stream if (!remoteLeaseSet) { LogPrint (eLogWarning, "Streaming: LeaseSet ", m_RemoteIdentity->GetIdentHash ().ToBase64 (), m_RemoteLeaseSet ? " expired" : " not found"); - if (m_RemoteLeaseSet && m_RemoteLeaseSet->IsPublishedEncrypted ()) + if (m_RemoteLeaseSet && m_RemoteLeaseSet->IsPublishedEncrypted ()) + { m_LocalDestination.GetOwner ()->RequestDestinationWithEncryptedLeaseSet ( std::make_shared(m_RemoteIdentity)); + return; // we keep m_RemoteLeaseSet for possible next request + } else + { + m_RemoteLeaseSet = nullptr; m_LocalDestination.GetOwner ()->RequestDestination (m_RemoteIdentity->GetIdentHash ()); // try to request for a next attempt - return; + } } else { From a8e1cd9a13d14978af7a6df8e9ccded9bb8f4dd1 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 10 May 2021 11:04:08 -0400 Subject: [PATCH 78/87] don't throw exception if local bind fails --- libi2pd_client/I2PTunnel.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/libi2pd_client/I2PTunnel.cpp b/libi2pd_client/I2PTunnel.cpp index b15b47b0..5476bfe2 100644 --- a/libi2pd_client/I2PTunnel.cpp +++ b/libi2pd_client/I2PTunnel.cpp @@ -84,7 +84,11 @@ namespace client // bind to 127.x.x.x address // where x.x.x are first three bytes from ident auto ourIP = GetLoopbackAddressFor(addr); - sock->bind (boost::asio::ip::tcp::endpoint (ourIP, 0)); + boost::system::error_code ec; + sock->bind (boost::asio::ip::tcp::endpoint (ourIP, 0), ec); + if (ec) + LogPrint (eLogError, "I2PTunnel: can't bind ourIP to ", ourIP.to_string (), ": ", ec.message ()); + } #endif From 1285e30b3ec13c6c9a1e69ec3217ec1ac7c85b45 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 10 May 2021 18:55:39 -0400 Subject: [PATCH 79/87] more pre-calculated x25519 --- libi2pd/ECIESX25519AEADRatchetSession.cpp | 2 +- libi2pd/Garlic.cpp | 1 + libi2pd/Transports.cpp | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/libi2pd/ECIESX25519AEADRatchetSession.cpp b/libi2pd/ECIESX25519AEADRatchetSession.cpp index 0f2518f7..9eab8af2 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.cpp +++ b/libi2pd/ECIESX25519AEADRatchetSession.cpp @@ -196,7 +196,7 @@ namespace garlic i2p::transport::transports.ReuseX25519KeysPair (m_EphemeralKeys); } // we still didn't find elligator eligible pair - for (int i = 0; i < 10; i++) + for (int i = 0; i < 25; i++) { // create new m_EphemeralKeys = std::make_shared(); diff --git a/libi2pd/Garlic.cpp b/libi2pd/Garlic.cpp index 42aca5be..220c5fed 100644 --- a/libi2pd/Garlic.cpp +++ b/libi2pd/Garlic.cpp @@ -556,6 +556,7 @@ namespace garlic if (m_LastTagset && m_LastTagset->GetNextIndex () < 2*ECIESX25519_TAGSET_MAX_NUM_TAGS) { auto maxTags = std::max (m_NumRatchetInboundTags, ECIESX25519_MAX_NUM_GENERATED_TAGS); + LogPrint (eLogWarning, "Garlic: trying to generate more ECIES-X25519-AEAD-Ratchet tags"); for (int i = 0; i < maxTags; i++) { auto nextTag = AddECIESx25519SessionNextTag (m_LastTagset); diff --git a/libi2pd/Transports.cpp b/libi2pd/Transports.cpp index 8413c859..1e40f88c 100644 --- a/libi2pd/Transports.cpp +++ b/libi2pd/Transports.cpp @@ -137,7 +137,7 @@ namespace transport m_IsOnline (true), m_IsRunning (false), m_IsNAT (true), m_CheckReserved(true), m_Thread (nullptr), m_Service (nullptr), m_Work (nullptr), m_PeerCleanupTimer (nullptr), m_PeerTestTimer (nullptr), m_SSUServer (nullptr), m_NTCP2Server (nullptr), - m_X25519KeysPairSupplier (5), // 5 pre-generated keys + m_X25519KeysPairSupplier (15), // 15 pre-generated keys m_TotalSentBytes(0), m_TotalReceivedBytes(0), m_TotalTransitTransmittedBytes (0), m_InBandwidth (0), m_OutBandwidth (0), m_TransitBandwidth(0), m_LastInBandwidthUpdateBytes (0), m_LastOutBandwidthUpdateBytes (0), From c6cdb26f47cb09befb1a973cd8855f987b3acac4 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 10 May 2021 20:20:25 -0400 Subject: [PATCH 80/87] reduce range for extra tags --- libi2pd/ECIESX25519AEADRatchetSession.h | 3 ++- libi2pd/Garlic.cpp | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/libi2pd/ECIESX25519AEADRatchetSession.h b/libi2pd/ECIESX25519AEADRatchetSession.h index 24bffae2..bdbb7111 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.h +++ b/libi2pd/ECIESX25519AEADRatchetSession.h @@ -88,7 +88,8 @@ namespace garlic bool IsNS () const { return m_IsNS; }; std::shared_ptr GetSession () { return m_Session; }; void SetTrimBehind (int index) { if (index > m_TrimBehindIndex) m_TrimBehindIndex = index; }; - + int GetTrimBehind () const { return m_TrimBehindIndex; }; + void Expire (); bool IsExpired (uint64_t ts) const; diff --git a/libi2pd/Garlic.cpp b/libi2pd/Garlic.cpp index 220c5fed..27db6b63 100644 --- a/libi2pd/Garlic.cpp +++ b/libi2pd/Garlic.cpp @@ -553,7 +553,7 @@ namespace garlic if (!session->HandleNextMessage (buf, length, nullptr, 0)) { // try to gererate more tags for last tagset - if (m_LastTagset && m_LastTagset->GetNextIndex () < 2*ECIESX25519_TAGSET_MAX_NUM_TAGS) + if (m_LastTagset && (m_LastTagset->GetNextIndex () - m_LastTagset->GetTrimBehind () < 3*ECIESX25519_MAX_NUM_GENERATED_TAGS)) { auto maxTags = std::max (m_NumRatchetInboundTags, ECIESX25519_MAX_NUM_GENERATED_TAGS); LogPrint (eLogWarning, "Garlic: trying to generate more ECIES-X25519-AEAD-Ratchet tags"); From 43b587636b783326fdf7f6c5300ff52785e5d743 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 11 May 2021 18:49:17 -0400 Subject: [PATCH 81/87] delete tags of termiated session right away --- libi2pd/Garlic.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/libi2pd/Garlic.cpp b/libi2pd/Garlic.cpp index 27db6b63..66a3b62f 100644 --- a/libi2pd/Garlic.cpp +++ b/libi2pd/Garlic.cpp @@ -880,8 +880,12 @@ namespace garlic { auto session = it->second.tagset->GetSession (); if (!session || session->IsTerminated()) - it->second.tagset->Expire (); - ++it; + { + it = m_ECIESx25519Tags.erase (it); + numExpiredTags++; + } + else + ++it; } } if (numExpiredTags > 0) From baec22610e3936cf5ea7678e6ef70f2b00c06e16 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 12 May 2021 07:57:37 -0400 Subject: [PATCH 82/87] always set expiration time for NSR tagset --- libi2pd/ECIESX25519AEADRatchetSession.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd/ECIESX25519AEADRatchetSession.cpp b/libi2pd/ECIESX25519AEADRatchetSession.cpp index 9eab8af2..f9d5672f 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.cpp +++ b/libi2pd/ECIESX25519AEADRatchetSession.cpp @@ -512,6 +512,7 @@ namespace garlic { auto tagsetNsr = std::make_shared(shared_from_this (), true); InitNewSessionTagset (tagsetNsr); + tagsetNsr->Expire (); // let non-replied session expire GenerateMoreReceiveTags (tagsetNsr, ECIESX25519_NSR_NUM_GENERATED_TAGS); } } @@ -814,7 +815,6 @@ namespace garlic case eSessionStateNew: return HandleNewIncomingSession (buf, len); case eSessionStateNewSessionSent: - receiveTagset->Expire (); // NSR tagset return HandleNewOutgoingSessionReply (buf, len); default: return false; From 2b22bfadbc81810ecb985fcadf975d310ffa4c32 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 12 May 2021 11:48:27 -0400 Subject: [PATCH 83/87] show version in hidden content --- daemon/HTTPServer.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/daemon/HTTPServer.cpp b/daemon/HTTPServer.cpp index 6410a044..f0a4b616 100644 --- a/daemon/HTTPServer.cpp +++ b/daemon/HTTPServer.cpp @@ -325,6 +325,7 @@ namespace http { if (!i2p::context.GetRouterInfo().GetProperty("family").empty()) s << "Router Family: " << i2p::context.GetRouterInfo().GetProperty("family") << "
\r\n"; s << "Router Caps: " << i2p::context.GetRouterInfo().GetProperty("caps") << "
\r\n"; + s << "Version: " VERSION "
\r\n"; s << "Our external address:" << "
\r\n\r\n"; for (const auto& address : i2p::context.GetRouterInfo().GetAddresses()) { From d299cbaabdf46e88549a350e4d23e4289b36a61a Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 13 May 2021 19:30:54 -0400 Subject: [PATCH 84/87] Add/Remove subsession --- libi2pd_client/SAM.cpp | 80 +++++++++++++++++++++++++++++++++++++++--- libi2pd_client/SAM.h | 6 ++++ 2 files changed, 82 insertions(+), 4 deletions(-) diff --git a/libi2pd_client/SAM.cpp b/libi2pd_client/SAM.cpp index 061cc820..af9ba6a8 100644 --- a/libi2pd_client/SAM.cpp +++ b/libi2pd_client/SAM.cpp @@ -765,12 +765,69 @@ namespace client void SAMSocket::ProcessSessionAdd (char * buf, size_t len) { - // TODO: implement + auto session = m_Owner.FindSession(m_ID); + if (session && session->Type == eSAMSessionTypeMaster) + { + LogPrint (eLogDebug, "SAM: subsession add: ", buf); + auto masterSession = std::static_pointer_cast(session); + std::map params; + ExtractParams (buf, params); + std::string& id = params[SAM_PARAM_ID]; + if (masterSession->subsessions.count (id) > 1) + { + // session exists + SendMessageReply (SAM_SESSION_CREATE_DUPLICATED_ID, strlen(SAM_SESSION_CREATE_DUPLICATED_ID), false); + return; + } + std::string& style = params[SAM_PARAM_STYLE]; + SAMSessionType type = eSAMSessionTypeUnknown; + if (style == SAM_VALUE_STREAM) type = eSAMSessionTypeStream; + // TODO: implement other styles + if (type == eSAMSessionTypeUnknown) + { + // unknown style + SendI2PError("Unsupported STYLE"); + return; + } + auto fromPort = std::stoi(params[SAM_PARAM_FROM_PORT]); + if (fromPort == -1) + { + SendI2PError("Invalid from port"); + return; + } + auto subsession = std::make_shared(masterSession, id, type, fromPort); + if (m_Owner.AddSession (subsession)) + { + masterSession->subsessions.insert (id); + SendSessionCreateReplyOk (); + } + else + SendMessageReply (SAM_SESSION_CREATE_DUPLICATED_ID, strlen(SAM_SESSION_CREATE_DUPLICATED_ID), false); + } + else + SendI2PError ("Wrong session type"); } void SAMSocket::ProcessSessionRemove (char * buf, size_t len) { - // TODO: implement + auto session = m_Owner.FindSession(m_ID); + if (session && session->Type == eSAMSessionTypeMaster) + { + LogPrint (eLogDebug, "SAM: subsession remove: ", buf); + auto masterSession = std::static_pointer_cast(session); + std::map params; + ExtractParams (buf, params); + std::string& id = params[SAM_PARAM_ID]; + if (!masterSession->subsessions.erase (id)) + { + SendMessageReply (SAM_SESSION_STATUS_INVALID_KEY, strlen(SAM_SESSION_STATUS_INVALID_KEY), false); + return; + } + m_Owner.CloseSession (id); + SendSessionCreateReplyOk (); + } + else + SendI2PError ("Wrong session type"); } void SAMSocket::SendI2PError(const std::string & msg) @@ -1153,6 +1210,14 @@ namespace client localDestination->StopAcceptingStreams (); } + void SAMMasterSession::Close () + { + SAMSingleSession::Close (); + for (const auto& it: subsessions) + m_Bridge.CloseSession (it); + subsessions.clear (); + } + SAMSubSession::SAMSubSession (std::shared_ptr master, const std::string& name, SAMSessionType type, int port): SAMSession (master->m_Bridge, name, type), masterSession (master), inPort (port) { @@ -1225,7 +1290,7 @@ namespace client { std::unique_lock l(m_SessionsMutex); for (auto& it: m_Sessions) - it.second->CloseStreams (); + it.second->Close (); m_Sessions.clear (); } StopIOService (); @@ -1328,6 +1393,13 @@ namespace client return nullptr; } + bool SAMBridge::AddSession (std::shared_ptr session) + { + if (!session) return false; + auto ret = m_Sessions.emplace (session->Name, session); + return ret.second; + } + void SAMBridge::CloseSession (const std::string& id) { std::shared_ptr session; @@ -1343,7 +1415,7 @@ namespace client if (session) { session->StopLocalDestination (); - session->CloseStreams (); + session->Close (); if (m_IsSingleThread) { auto timer = std::make_shared(GetService ()); diff --git a/libi2pd_client/SAM.h b/libi2pd_client/SAM.h index 8669538a..d92cf009 100644 --- a/libi2pd_client/SAM.h +++ b/libi2pd_client/SAM.h @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -74,6 +75,7 @@ namespace client const char SAM_PARAM_SIZE[] = "SIZE"; const char SAM_PARAM_HOST[] = "HOST"; const char SAM_PARAM_PORT[] = "PORT"; + const char SAM_PARAM_FROM_PORT[] = "FROM_PORT"; const char SAM_VALUE_TRANSIENT[] = "TRANSIENT"; const char SAM_VALUE_STREAM[] = "STREAM"; const char SAM_VALUE_DATAGRAM[] = "DATAGRAM"; @@ -192,6 +194,7 @@ namespace client virtual std::shared_ptr GetLocalDestination () = 0; virtual void StopLocalDestination () = 0; + virtual void Close () { CloseStreams (); }; void CloseStreams (); }; @@ -209,8 +212,10 @@ namespace client struct SAMMasterSession: public SAMSingleSession { + std::set subsessions; SAMMasterSession (SAMBridge & parent, const std::string & name, std::shared_ptr dest): SAMSingleSession (parent, name, eSAMSessionTypeMaster, dest) {}; + void Close (); }; struct SAMSubSession: public SAMSession @@ -237,6 +242,7 @@ namespace client boost::asio::io_service& GetService () { return GetIOService (); }; std::shared_ptr CreateSession (const std::string& id, SAMSessionType type, const std::string& destination, // empty string means transient const std::map * params); + bool AddSession (std::shared_ptr session); void CloseSession (const std::string& id); std::shared_ptr FindSession (const std::string& id) const; From c359c6e634fdc106298291c8630b3a1ccb8aa131 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Sat, 15 May 2021 16:28:16 +0300 Subject: [PATCH 85/87] update config file example, add v6 status to windows daemon window, code cleanup Signed-off-by: R4SAS --- Win32/Win32App.cpp | 50 +++++++++---- contrib/i2pd.conf | 54 +++++++------ daemon/Daemon.cpp | 26 +++---- daemon/HTTPServer.cpp | 22 +++--- daemon/I2PControl.cpp | 4 + libi2pd/Config.cpp | 14 ++-- libi2pd/Destination.cpp | 5 +- libi2pd/NTCP2.cpp | 56 +++++++------- libi2pd/RouterContext.cpp | 154 +++++++++++++++++++------------------- libi2pd/SSU.cpp | 98 ++++++++++++------------ libi2pd/SSUSession.cpp | 2 +- 11 files changed, 258 insertions(+), 227 deletions(-) diff --git a/Win32/Win32App.cpp b/Win32/Win32App.cpp index 15157355..db5a1f3d 100644 --- a/Win32/Win32App.cpp +++ b/Win32/Win32App.cpp @@ -142,25 +142,47 @@ namespace win32 s << bytes << " Bytes\n"; } + static void ShowNetworkStatus (std::stringstream& s, RouterStatus status) + { + switch (status) + { + case eRouterStatusOK: s << "OK"; break; + case eRouterStatusTesting: s << "Test"; break; + case eRouterStatusFirewalled: s << "FW"; break; + case eRouterStatusUnknown: s << "Unk"; break; + case eRouterStatusProxy: s << "Proxy"; break; + case eRouterStatusMesh: s << "Mesh"; break; + case eRouterStatusError: + { + s << "Err"; + switch (i2p::context.GetError ()) + { + case eRouterErrorClockSkew: + s << " - Clock skew"; + break; + case eRouterErrorOffline: + s << " - Offline"; + break; + case eRouterErrorSymmetricNAT: + s << " - Symmetric NAT"; + break; + default: ; + } + break; + } + default: s << "Unk"; + } + } + static void PrintMainWindowText (std::stringstream& s) { s << "\n"; s << "Status: "; - switch (i2p::context.GetStatus()) + ShowNetworkStatus (s, i2p::context.GetStatus ()); + if (i2p::context.SupportsV6 ()) { - case eRouterStatusOK: s << "OK"; break; - case eRouterStatusTesting: s << "Testing"; break; - case eRouterStatusFirewalled: s << "Firewalled"; break; - case eRouterStatusError: - { - switch (i2p::context.GetError()) - { - case eRouterErrorClockSkew: s << "Clock skew"; break; - default: s << "Error"; - } - break; - } - default: s << "Unknown"; + s << " / "; + ShowNetworkStatus (s, i2p::context.GetStatusV6 ()); } s << "; "; s << "Success Rate: " << i2p::tunnel::tunnels.GetTunnelCreationSuccessRate() << "%\n"; diff --git a/contrib/i2pd.conf b/contrib/i2pd.conf index 2e1b296a..09f9c155 100644 --- a/contrib/i2pd.conf +++ b/contrib/i2pd.conf @@ -35,14 +35,30 @@ ## Write full CLF-formatted date and time to log (default: write only time) # logclftime = true -## Daemon mode. Router will go to background after start +## Daemon mode. Router will go to background after start. Ignored on Windows # daemon = true ## Specify a family, router belongs to (default - none) # family = -## External IP address to listen for connections +## Network interface to bind to +## Updates address4/6 options if they are not set +# ifname = +## You can specify different interfaces for IPv4 and IPv6 +# ifname4 = +# ifname6 = + +## Local address to bind transport sockets to +## Overrides host option if: +## For ipv4: if ipv4 = true and nat = false +## For ipv6: if 'host' is not set or ipv4 = true +# address4 = +# address6 = + +## External IPv4 or IPv6 address to listen for connections ## By default i2pd sets IP automatically +## Sets published NTCP2v4/SSUv4 address to 'host' value if nat = true +## Sets published NTCP2v6/SSUv6 address to 'host' value if ipv4 = false # host = 1.2.3.4 ## Port to listen for connections @@ -55,17 +71,6 @@ ipv4 = true ## Enable communication through ipv6 ipv6 = false -## Network interface to bind to -# ifname = -## You can specify different interfaces for IPv4 and IPv6 -# ifname4 = -# ifname6 = - -## Enable NTCP transport (default = true) -# ntcp = true -## If you run i2pd behind a proxy server, you can only use NTCP transport with ntcpproxy option -## Should be http://address:port or socks://address:port -# ntcpproxy = http://127.0.0.1:8118 ## Enable SSU transport (default = true) # ssu = true @@ -82,6 +87,7 @@ ipv6 = false # notransit = true ## Router will be floodfill +## Note: that mode uses much more network connections and CPU! # floodfill = true [http] @@ -93,7 +99,7 @@ address = 127.0.0.1 port = 7070 ## Path to web console, default "/" # webroot = / -## Uncomment following lines to enable Web Console authentication +## Uncomment following lines to enable Web Console authentication # auth = true # user = i2pd # pass = changeme @@ -170,11 +176,11 @@ enabled = true # name = I2Pd [meshnets] -## Enable connectivity over the Yggdrasil network +## Enable connectivity over the Yggdrasil network # yggdrasil = false ## You can bind address from your Yggdrasil subnet 300::/64 -## The address must first be added to the network interface -# yggaddress = +## The address must first be added to the network interface +# yggaddress = [reseed] ## Options for bootstrapping into I2P network, aka reseeding @@ -207,13 +213,13 @@ verify = true [limits] ## Maximum active transit sessions (default:2500) # transittunnels = 2500 -## Limit number of open file descriptors (0 - use system limit) +## Limit number of open file descriptors (0 - use system limit) # openfiles = 0 -## Maximum size of corefile in Kb (0 - use system limit) +## Maximum size of corefile in Kb (0 - use system limit) # coresize = 0 -## Threshold to start probabalistic backoff with ntcp sessions (0 - use system limit) +## Threshold to start probabalistic backoff with ntcp sessions (0 - use system limit) # ntcpsoft = 0 -## Maximum number of ntcp sessions (0 - use system limit) +## Maximum number of ntcp sessions (0 - use system limit) # ntcphard = 0 [trust] @@ -222,13 +228,13 @@ verify = true ## Make direct I2P connections only to routers in specified Family. # family = MyFamily ## Make direct I2P connections only to routers specified here. Comma separated list of base64 identities. -# routers = +# routers = ## Should we hide our router from other routers? false by default # hidden = true [exploratory] ## Exploratory tunnels settings with default values -# inbound.length = 2 +# inbound.length = 2 # inbound.quantity = 3 # outbound.length = 2 # outbound.quantity = 3 @@ -237,7 +243,7 @@ verify = true ## Save peer profiles on disk (default: true) # profiles = true ## Save full addresses on disk (default: true) -# addressbook = true +# addressbook = true [cpuext] ## Use CPU AES-NI instructions set when work with cryptography when available (default: true) diff --git a/daemon/Daemon.cpp b/daemon/Daemon.cpp index c87de4aa..77000652 100644 --- a/daemon/Daemon.cpp +++ b/daemon/Daemon.cpp @@ -142,23 +142,23 @@ namespace util i2p::context.SetNetID (netID); i2p::context.Init (); - bool ipv6; i2p::config::GetOption("ipv6", ipv6); - bool ipv4; i2p::config::GetOption("ipv4", ipv4); + 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 // ifname -> address - std::string ifname; i2p::config::GetOption("ifname", ifname); + std::string ifname; i2p::config::GetOption("ifname", ifname); if (ipv4 && i2p::config::IsDefault ("address4")) { std::string ifname4; i2p::config::GetOption("ifname4", ifname4); if (!ifname4.empty ()) i2p::config::SetOption ("address4", i2p::util::net::GetInterfaceAddress(ifname4, false).to_string ()); // v4 else if (!ifname.empty ()) - i2p::config::SetOption ("address4", i2p::util::net::GetInterfaceAddress(ifname, false).to_string ()); // v4 - } + i2p::config::SetOption ("address4", i2p::util::net::GetInterfaceAddress(ifname, false).to_string ()); // v4 + } if (ipv6 && i2p::config::IsDefault ("address6")) { std::string ifname6; i2p::config::GetOption("ifname6", ifname6); @@ -166,8 +166,8 @@ namespace util i2p::config::SetOption ("address6", i2p::util::net::GetInterfaceAddress(ifname6, true).to_string ()); // v6 else if (!ifname.empty ()) i2p::config::SetOption ("address6", i2p::util::net::GetInterfaceAddress(ifname, true).to_string ()); // v6 - } - + } + bool ygg; i2p::config::GetOption("meshnets.yggdrasil", ygg); boost::asio::ip::address_v6 yggaddr; if (ygg) @@ -210,10 +210,10 @@ namespace util { bool published; i2p::config::GetOption("ntcp2.published", published); if (published) - { + { std::string ntcp2proxy; i2p::config::GetOption("ntcp2.proxy", ntcp2proxy); if (!ntcp2proxy.empty ()) published = false; - } + } if (published) { uint16_t ntcp2port; i2p::config::GetOption("ntcp2.port", ntcp2port); @@ -232,12 +232,12 @@ namespace util } if (ygg) { - i2p::context.PublishNTCP2Address (port, true, false, false, true); + i2p::context.PublishNTCP2Address (port, true, false, false, true); i2p::context.UpdateNTCP2V6Address (yggaddr); if (!ipv4 && !ipv6) - i2p::context.SetStatus (eRouterStatusMesh); - } - + i2p::context.SetStatus (eRouterStatusMesh); + } + bool transit; i2p::config::GetOption("notransit", transit); i2p::context.SetAcceptsTunnels (!transit); uint16_t transitTunnels; i2p::config::GetOption("limits.transittunnels", transitTunnels); diff --git a/daemon/HTTPServer.cpp b/daemon/HTTPServer.cpp index f0a4b616..d56c2894 100644 --- a/daemon/HTTPServer.cpp +++ b/daemon/HTTPServer.cpp @@ -265,15 +265,15 @@ namespace http { break; case eRouterErrorSymmetricNAT: s << " - Symmetric NAT"; - break; + break; default: ; } break; } default: s << "Unknown"; } - } - + } + void ShowStatus (std::stringstream& s, bool includeHiddenContent, i2p::http::OutputFormatEnum outputFormat) { s << "Uptime: "; @@ -287,7 +287,7 @@ namespace http { s << "Network status 6: "; ShowNetworkStatus (s, i2p::context.GetStatusV6 ()); s << "
\r\n"; - } + } #if ((!defined(WIN32) && !defined(QT_GUI_LIB) && !defined(ANDROID)) || defined(ANDROID_BINARY)) if (auto remains = Daemon.gracefulShutdownInterval) { s << "Stopping in: "; @@ -1276,14 +1276,14 @@ namespace http { ident.FromBase32 (b32); auto dest = i2p::client::context.FindLocalDestination (ident); - if (dest) + if (dest) { std::size_t pos; pos = name.find (".i2p"); - if (pos == (name.length () - 4)) + if (pos == (name.length () - 4)) { pos = name.find (".b32.i2p"); - if (pos == std::string::npos) + if (pos == std::string::npos) { auto signatureLen = dest->GetIdentity ()->GetSignatureLen (); uint8_t * signature = new uint8_t[signatureLen]; @@ -1303,13 +1303,13 @@ namespace http { "\r\n
\r\n"; delete[] signature; delete[] sig; - } - else + } + else s << "ERROR: Domain can't end with .b32.i2p\r\n
\r\n
\r\n"; - } + } else s << "ERROR: Domain must end with .i2p\r\n
\r\n
\r\n"; - } + } else s << "ERROR: Such destination is not found\r\n
\r\n
\r\n"; diff --git a/daemon/I2PControl.cpp b/daemon/I2PControl.cpp index d71a9f1c..12602c99 100644 --- a/daemon/I2PControl.cpp +++ b/daemon/I2PControl.cpp @@ -2,6 +2,10 @@ #include #include #include + +// Use global placeholders from boost introduced when local_time.hpp is loaded +#define BOOST_BIND_GLOBAL_PLACEHOLDERS + #include #include #include diff --git a/libi2pd/Config.cpp b/libi2pd/Config.cpp index cdbe1bff..b316ba83 100644 --- a/libi2pd/Config.cpp +++ b/libi2pd/Config.cpp @@ -62,11 +62,11 @@ namespace config { ("floodfill", bool_switch()->default_value(false), "Router will be floodfill (default: disabled)") ("bandwidth", value()->default_value(""), "Bandwidth limit: integer in KBps or letters: L (32), O (256), P (2048), X (>9000)") ("share", value()->default_value(100), "Limit of transit traffic from max bandwidth in percents. (default: 100)") - ("ntcp", bool_switch()->default_value(false), "Ignored. Always false") + ("ntcp", bool_switch()->default_value(false), "Deprecated option. Always false") ("ssu", bool_switch()->default_value(true), "Enable SSU transport (default: enabled)") - ("ntcpproxy", value()->default_value(""), "Ignored") + ("ntcpproxy", value()->default_value(""), "Deprecated option") #ifdef _WIN32 - ("svcctl", value()->default_value(""), "Ignored") + ("svcctl", value()->default_value(""), "Deprecated option") ("insomnia", bool_switch()->default_value(false), "Prevent system from sleeping (default: disabled)") ("close", value()->default_value("ask"), "Action on close: minimize, exit, ask") #endif @@ -77,9 +77,9 @@ namespace config { ("limits.coresize", value()->default_value(0), "Maximum size of corefile in Kb (0 - use system limit)") ("limits.openfiles", value()->default_value(0), "Maximum number of open files (0 - use system default)") ("limits.transittunnels", value()->default_value(2500), "Maximum active transit sessions (default:2500)") - ("limits.ntcpsoft", value()->default_value(0), "Threshold to start probabilistic backoff with ntcp sessions (default: use system limit)") - ("limits.ntcphard", value()->default_value(0), "Maximum number of ntcp sessions (default: use system limit)") - ("limits.ntcpthreads", value()->default_value(1), "Maximum number of threads used by NTCP DH worker (default: 1)") + ("limits.ntcpsoft", value()->default_value(0), "Deprecated option") + ("limits.ntcphard", value()->default_value(0), "Deprecated option") + ("limits.ntcpthreads", value()->default_value(1), "Deprecated option") ; options_description httpserver("HTTP Server options"); @@ -281,7 +281,7 @@ namespace config { options_description meshnets("Meshnet transports options"); meshnets.add_options() - ("meshnets.yggdrasil", bool_switch()->default_value(false), "Support transports through the Yggdrasil (deafult: false)") + ("meshnets.yggdrasil", bool_switch()->default_value(false), "Support transports through the Yggdrasil (default: false)") ("meshnets.yggaddress", value()->default_value(""), "Yggdrasil address to publish") ; diff --git a/libi2pd/Destination.cpp b/libi2pd/Destination.cpp index 22ba0b39..9962599b 100644 --- a/libi2pd/Destination.cpp +++ b/libi2pd/Destination.cpp @@ -509,7 +509,7 @@ namespace client // schedule verification m_PublishVerificationTimer.expires_from_now (boost::posix_time::seconds(PUBLISH_VERIFICATION_TIMEOUT)); m_PublishVerificationTimer.async_wait (std::bind (&LeaseSetDestination::HandlePublishVerificationTimer, - shared_from_this (), std::placeholders::_1)); + shared_from_this (), std::placeholders::_1)); } else i2p::garlic::GarlicDestination::HandleDeliveryStatusMessage (msgID); @@ -592,8 +592,7 @@ namespace client // assume it successive and try to verify m_PublishVerificationTimer.expires_from_now (boost::posix_time::seconds(PUBLISH_VERIFICATION_TIMEOUT)); m_PublishVerificationTimer.async_wait (std::bind (&LeaseSetDestination::HandlePublishVerificationTimer, - shared_from_this (), std::placeholders::_1)); - + shared_from_this (), std::placeholders::_1)); } } } diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index e872eeaa..d5a03d1c 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -342,7 +342,7 @@ namespace transport else LogPrint (eLogWarning, "NTCP2: Missing NTCP2 address"); } - m_NextRouterInfoResendTime = i2p::util::GetSecondsSinceEpoch () + NTCP2_ROUTERINFO_RESEND_INTERVAL + + m_NextRouterInfoResendTime = i2p::util::GetSecondsSinceEpoch () + NTCP2_ROUTERINFO_RESEND_INTERVAL + rand ()%NTCP2_ROUTERINFO_RESEND_INTERVAL_THRESHOLD; } @@ -717,7 +717,7 @@ namespace transport m_Establisher->m_SessionRequestBuffer = new uint8_t[287]; // 287 bytes max for now boost::asio::async_read (m_Socket, boost::asio::buffer(m_Establisher->m_SessionRequestBuffer, 64), boost::asio::transfer_all (), std::bind(&NTCP2Session::HandleSessionRequestReceived, shared_from_this (), - std::placeholders::_1, std::placeholders::_2)); + std::placeholders::_1, std::placeholders::_2)); } void NTCP2Session::ReceiveLength () @@ -726,7 +726,7 @@ namespace transport #ifdef __linux__ const int one = 1; setsockopt(m_Socket.native_handle(), IPPROTO_TCP, TCP_QUICKACK, &one, sizeof(one)); -#endif +#endif boost::asio::async_read (m_Socket, boost::asio::buffer(&m_NextReceivedLen, 2), boost::asio::transfer_all (), std::bind(&NTCP2Session::HandleReceivedLength, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); } @@ -780,8 +780,8 @@ namespace transport if (IsTerminated ()) return; #ifdef __linux__ const int one = 1; - setsockopt(m_Socket.native_handle(), IPPROTO_TCP, TCP_QUICKACK, &one, sizeof(one)); -#endif + setsockopt(m_Socket.native_handle(), IPPROTO_TCP, TCP_QUICKACK, &one, sizeof(one)); +#endif boost::asio::async_read (m_Socket, boost::asio::buffer(m_NextReceivedBuffer, m_NextReceivedLen), boost::asio::transfer_all (), std::bind(&NTCP2Session::HandleReceived, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); } @@ -1009,11 +1009,11 @@ namespace transport LogPrint (eLogDebug, "NTCP2: Next frame sent ", bytes_transferred); if (m_LastActivityTimestamp > m_NextRouterInfoResendTime) { - m_NextRouterInfoResendTime += NTCP2_ROUTERINFO_RESEND_INTERVAL + + m_NextRouterInfoResendTime += NTCP2_ROUTERINFO_RESEND_INTERVAL + rand ()%NTCP2_ROUTERINFO_RESEND_INTERVAL_THRESHOLD; - SendRouterInfo (); - } - else + SendRouterInfo (); + } + else SendQueue (); } } @@ -1113,7 +1113,7 @@ namespace transport SendQueue (); else if (m_SendQueue.size () > NTCP2_MAX_OUTGOING_QUEUE_SIZE) { - LogPrint (eLogWarning, "NTCP2: outgoing messages queue size to ", + LogPrint (eLogWarning, "NTCP2: outgoing messages queue size to ", GetIdentHashBase64(), " exceeds ", NTCP2_MAX_OUTGOING_QUEUE_SIZE); Terminate (); } @@ -1279,7 +1279,7 @@ namespace transport { LogPrint (eLogError, "NTCP2: Can't connect to unspecified address"); return; - } + } LogPrint (eLogDebug, "NTCP2: Connecting to ", conn->GetRemoteEndpoint ()); GetService ().post([this, conn]() { @@ -1300,25 +1300,25 @@ namespace transport // bind to local address std::shared_ptr localAddress; if (conn->GetRemoteEndpoint ().address ().is_v6 ()) - { + { if (i2p::util::net::IsYggdrasilAddress (conn->GetRemoteEndpoint ().address ())) localAddress = m_YggdrasilAddress; - else + else localAddress = m_Address6; conn->GetSocket ().open (boost::asio::ip::tcp::v6 ()); - } + } else - { + { localAddress = m_Address4; conn->GetSocket ().open (boost::asio::ip::tcp::v4 ()); - } + } if (localAddress) { boost::system::error_code ec; conn->GetSocket ().bind (*localAddress, ec); if (ec) - LogPrint (eLogError, "NTCP2: can't bind to ", localAddress->address ().to_string (), ": ", ec.message ()); - } + LogPrint (eLogError, "NTCP2: can't bind to ", localAddress->address ().to_string (), ": ", ec.message ()); + } conn->GetSocket ().async_connect (conn->GetRemoteEndpoint (), std::bind (&NTCP2Server::HandleConnect, this, std::placeholders::_1, conn, timer)); } else @@ -1448,8 +1448,8 @@ namespace transport { LogPrint (eLogError, "NTCP2: Can't connect to unspecified address"); return; - } - GetService().post([this, conn]() + } + GetService().post([this, conn]() { if (this->AddNTCP2Session (conn)) { @@ -1546,10 +1546,10 @@ namespace transport if(ep.address ().is_v6 ()) req.uri = "[" + ep.address ().to_string() + "]:" + std::to_string(ep.port ()); else - req.uri = ep.address ().to_string() + ":" + std::to_string(ep.port ()); + req.uri = ep.address ().to_string() + ":" + std::to_string(ep.port ()); if (!m_ProxyAuthorization.empty ()) req.AddHeader("Proxy-Authorization", m_ProxyAuthorization); - + boost::asio::streambuf writebuff; std::ostream out(&writebuff); out << req.to_string(); @@ -1627,7 +1627,7 @@ namespace transport sz += 16; memcpy(buff->data () + 4, addrbytes.data(), 16); } - else + else { // We mustn't really fall here because all connections are made to IP addresses LogPrint(eLogError, "NTCP2: Tried to connect to unexpected address via proxy"); @@ -1666,17 +1666,17 @@ namespace transport } void NTCP2Server::SetLocalAddress (const boost::asio::ip::address& localAddress) - { + { auto addr = std::make_shared(boost::asio::ip::tcp::endpoint(localAddress, 0)); if (localAddress.is_v6 ()) - { + { if (i2p::util::net::IsYggdrasilAddress (localAddress)) m_YggdrasilAddress = addr; - else + else m_Address6 = addr; - } + } else m_Address4 = addr; - } + } } } diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index 9602fe17..ad6576ed 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -28,7 +28,7 @@ namespace i2p RouterContext::RouterContext (): m_LastUpdateTime (0), m_AcceptsTunnels (true), m_IsFloodfill (false), - m_ShareRatio (100), m_Status (eRouterStatusUnknown), m_StatusV6 (eRouterStatusUnknown), + m_ShareRatio (100), m_Status (eRouterStatusUnknown), m_StatusV6 (eRouterStatusUnknown), m_Error (eRouterErrorNone), m_NetID (I2PD_NET_ID) { } @@ -44,12 +44,12 @@ namespace i2p m_TunnelDecryptor = m_Keys.CreateDecryptor (nullptr); UpdateRouterInfo (); if (IsECIES ()) - { + { auto initState = new i2p::crypto::NoiseSymmetricState (); i2p::crypto::InitNoiseNState (*initState, GetIdentity ()->GetEncryptionPublicKey ()); - m_InitialNoiseState.reset (initState); + m_InitialNoiseState.reset (initState); m_ECIESSession = std::make_shared(*initState); - } + } } void RouterContext::CreateNewRouter () @@ -74,21 +74,21 @@ namespace i2p bool ipv6; i2p::config::GetOption("ipv6", ipv6); bool ssu; i2p::config::GetOption("ssu", ssu); bool ntcp2; i2p::config::GetOption("ntcp2.enabled", ntcp2); - bool ygg; i2p::config::GetOption("meshnets.yggdrasil", ygg); + bool ygg; i2p::config::GetOption("meshnets.yggdrasil", ygg); bool nat; i2p::config::GetOption("nat", nat); - + if ((ntcp2 || ygg) && !m_NTCP2Keys) - NewNTCP2Keys (); - bool ntcp2Published = false; + NewNTCP2Keys (); + bool ntcp2Published = false; if (ntcp2) - { + { i2p::config::GetOption("ntcp2.published", ntcp2Published); if (ntcp2Published) { std::string ntcp2proxy; i2p::config::GetOption("ntcp2.proxy", ntcp2proxy); if (!ntcp2proxy.empty ()) ntcp2Published = false; - } - } + } + } uint8_t caps = 0, addressCaps = 0; if (ipv4) { @@ -100,8 +100,8 @@ namespace i2p // we have no NAT so set external address from local address std::string address4; i2p::config::GetOption("address4", address4); if (!address4.empty ()) host = address4; - } - + } + if (ntcp2) { if (ntcp2Published) @@ -109,26 +109,26 @@ namespace i2p else // add non-published NTCP2 address { addressCaps = i2p::data::RouterInfo::AddressCaps::eV4; - routerInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv); - } - } + routerInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv); + } + } if (ssu) - { + { routerInfo.AddSSUAddress (host.c_str(), port, nullptr); caps |= i2p::data::RouterInfo::eReachable; // R - } + } } if (ipv6) { std::string host = "::1"; if (!i2p::config::IsDefault("host") && !ipv4) // override if v6 only i2p::config::GetOption("host", host); - else + else { std::string address6; i2p::config::GetOption("address6", address6); if (!address6.empty ()) host = address6; } - + if (ntcp2) { if (ntcp2Published) @@ -140,29 +140,29 @@ namespace i2p ntcp2Host = host; routerInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv, boost::asio::ip::address_v6::from_string (ntcp2Host), port); } - else - { + else + { if (!ipv4) // no other ntcp2 addresses yet routerInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv); addressCaps |= i2p::data::RouterInfo::AddressCaps::eV6; - } - } + } + } if (ssu) - { + { routerInfo.AddSSUAddress (host.c_str(), port, nullptr); caps |= i2p::data::RouterInfo::eReachable; // R - } + } } if (ygg) { auto yggaddr = i2p::util::net::GetYggdrasilAddress (); if (!yggaddr.is_unspecified ()) routerInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv, yggaddr, port); - } + } if (addressCaps) routerInfo.SetUnreachableAddressesTransportCaps (addressCaps); - routerInfo.SetCaps (caps); // caps + L + routerInfo.SetCaps (caps); // caps + L routerInfo.SetProperty ("netId", std::to_string (m_NetID)); routerInfo.SetProperty ("router.version", I2P_VERSION); routerInfo.CreateBuffer (m_Keys); @@ -213,7 +213,7 @@ namespace i2p void RouterContext::SetStatusV6 (RouterStatus status) { if (status != m_StatusV6) - { + { m_StatusV6 = status; switch (m_StatusV6) { @@ -226,9 +226,9 @@ namespace i2p default: ; } - } - } - + } + } + void RouterContext::UpdatePort (int port) { bool updated = false; @@ -250,18 +250,18 @@ namespace i2p bool updated = false; for (auto& address : m_RouterInfo.GetAddresses ()) { - if (address->IsNTCP2 () && (address->port != port || address->published != publish)) + if (address->IsNTCP2 () && (address->port != port || address->published != publish)) { bool isAddr = v4 && address->IsV4 (); if (!isAddr && (v6 || ygg)) - { + { if (i2p::util::net::IsYggdrasilAddress (address->host)) isAddr = ygg; else isAddr = v6 && address->IsV6 (); } if (isAddr) - { + { if (!port && !address->port) { // select random port only if address's port is not set @@ -272,7 +272,7 @@ namespace i2p address->published = publish; address->ntcp2->iv = m_NTCP2Keys->iv; updated = true; - } + } } } if (updated) @@ -310,7 +310,7 @@ namespace i2p bool updated = false; for (auto& address : m_RouterInfo.GetAddresses ()) { - if (address->host != host && address->IsCompatible (host) && + if (address->host != host && address->IsCompatible (host) && !i2p::util::net::IsYggdrasilAddress (address->host)) { address->host = host; @@ -402,7 +402,7 @@ namespace i2p case i2p::data::CAPS_FLAG_EXTRA_BANDWIDTH1 : limit = 2048; type = extra; break; case i2p::data::CAPS_FLAG_EXTRA_BANDWIDTH2 : limit = 1000000; type = unlim; break; // 1Gbyte/s default: - limit = 48; type = low; + limit = 48; type = low; } /* update caps & flags in RI */ auto caps = m_RouterInfo.GetCaps (); @@ -416,8 +416,8 @@ namespace i2p #if (__cplusplus >= 201703L) // C++ 17 or higher [[fallthrough]]; #endif - // no break here, extra + high means 'X' - case high : caps |= i2p::data::RouterInfo::eHighBandwidth; break; + // no break here, extra + high means 'X' + case high : caps |= i2p::data::RouterInfo::eHighBandwidth; break; } m_RouterInfo.SetCaps (caps); UpdateRouterInfo (); @@ -467,14 +467,14 @@ namespace i2p void RouterContext::SetUnreachable (bool v4, bool v6) { if (v4 || (v6 && !SupportsV4 ())) - { + { // set caps uint8_t caps = m_RouterInfo.GetCaps (); caps &= ~i2p::data::RouterInfo::eReachable; caps |= i2p::data::RouterInfo::eUnreachable; caps &= ~i2p::data::RouterInfo::eFloodfill; // can't be floodfill m_RouterInfo.SetCaps (caps); - } + } uint16_t port = 0; // delete previous introducers auto& addresses = m_RouterInfo.GetAddresses (); @@ -497,7 +497,7 @@ namespace i2p void RouterContext::SetReachable (bool v4, bool v6) { if (v4 || (v6 && !SupportsV4 ())) - { + { // update caps uint8_t caps = m_RouterInfo.GetCaps (); caps &= ~i2p::data::RouterInfo::eUnreachable; @@ -505,7 +505,7 @@ namespace i2p if (m_IsFloodfill) caps |= i2p::data::RouterInfo::eFloodfill; m_RouterInfo.SetCaps (caps); - } + } uint16_t port = 0; // delete previous introducers auto& addresses = m_RouterInfo.GetAddresses (); @@ -526,7 +526,7 @@ namespace i2p { uint16_t ntcp2Port; i2p::config::GetOption ("ntcp2.port", ntcp2Port); if (!ntcp2Port) ntcp2Port = port; - PublishNTCP2Address (ntcp2Port, true, v4, v6, false); + PublishNTCP2Address (ntcp2Port, true, v4, v6, false); } } // update @@ -596,7 +596,7 @@ namespace i2p if (supportsV4) { bool foundSSU = false, foundNTCP2 = false; - std::string host = "127.0.0.1"; + std::string host = "127.0.0.1"; uint16_t port = 0; auto& addresses = m_RouterInfo.GetAddresses (); for (auto& addr: addresses) @@ -626,26 +626,26 @@ namespace i2p { bool ntcp2Published; i2p::config::GetOption("ntcp2.published", ntcp2Published); if (ntcp2Published) - { + { uint16_t ntcp2Port; i2p::config::GetOption ("ntcp2.port", ntcp2Port); if (!ntcp2Port) ntcp2Port = port; m_RouterInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv, boost::asio::ip::address::from_string (host), ntcp2Port); - } + } else m_RouterInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv); - } - } + } + } m_RouterInfo.EnableV4 (); - } + } else m_RouterInfo.DisableV4 (); UpdateRouterInfo (); } void RouterContext::SetSupportsMesh (bool supportsmesh, const boost::asio::ip::address_v6& host) - { + { if (supportsmesh) - { + { m_RouterInfo.EnableMesh (); uint16_t port = 0; i2p::config::GetOption ("ntcp2.port", port); @@ -659,16 +659,16 @@ namespace i2p { foundMesh = true; break; - } + } } if (!foundMesh) m_RouterInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv, host, port); - } + } else m_RouterInfo.DisableMesh (); UpdateRouterInfo (); } - + void RouterContext::UpdateNTCP2V6Address (const boost::asio::ip::address& host) { bool isYgg = i2p::util::net::IsYggdrasilAddress (host); @@ -742,7 +742,7 @@ namespace i2p // rekey routers with bandwidth = L (or default) this time bool isFloodfill; i2p::config::GetOption("floodfill", isFloodfill); if (!isFloodfill) rekey = true; - } + } if (rekey) { // update keys @@ -751,7 +751,7 @@ namespace i2p m_Keys = i2p::data::PrivateKeys::CreateRandomKeys (i2p::data::SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519, i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD); SaveKeys (); - } + } // read NTCP2 keys if available std::ifstream n2k (i2p::fs::DataDirPath (NTCP2_KEYS), std::ifstream::in | std::ifstream::binary); if (n2k) @@ -787,8 +787,8 @@ namespace i2p SetReachable (true, true); // we assume reachable until we discover firewall through peer tests // read NTCP2 - bool ntcp2; i2p::config::GetOption("ntcp2.enabled", ntcp2); - bool ygg; i2p::config::GetOption("meshnets.yggdrasil", ygg); + bool ntcp2; i2p::config::GetOption("ntcp2.enabled", ntcp2); + bool ygg; i2p::config::GetOption("meshnets.yggdrasil", ygg); if (ntcp2 || ygg) { if (!m_NTCP2Keys) NewNTCP2Keys (); @@ -821,15 +821,15 @@ namespace i2p i2p::HandleI2NPMessage (CreateI2NPMessage (buf, GetI2NPMessageLength (buf, len))); } - bool RouterContext::HandleCloveI2NPMessage (I2NPMessageType typeID, const uint8_t * payload, size_t len) - { + bool RouterContext::HandleCloveI2NPMessage (I2NPMessageType typeID, const uint8_t * payload, size_t len) + { auto msg = CreateI2NPMessage (typeID, payload, len); if (!msg) return false; i2p::HandleI2NPMessage (msg); - return true; - } + return true; + } + - void RouterContext::ProcessGarlicMessage (std::shared_ptr msg) { std::unique_lock l(m_GarlicMutex); @@ -847,8 +847,8 @@ namespace i2p m_ECIESSession->HandleNextMessage (buf, len); else LogPrint (eLogError, "Router: Session is not set for ECIES router"); - } - else + } + else i2p::garlic::GarlicDestination::ProcessGarlicMessage (msg); } @@ -857,10 +857,10 @@ namespace i2p if (i2p::data::netdb.GetPublishReplyToken () == bufbe32toh (msg->GetPayload () + DELIVERY_STATUS_MSGID_OFFSET)) i2p::data::netdb.PostI2NPMsg (msg); else - { + { std::unique_lock l(m_GarlicMutex); i2p::garlic::GarlicDestination::ProcessDeliveryStatusMessage (msg); - } + } } void RouterContext::CleanupDestination () @@ -886,34 +886,34 @@ namespace i2p { if (!m_InitialNoiseState) return false; // m_InitialNoiseState is h = SHA256(h || hepk) - m_CurrentNoiseState.reset (new i2p::crypto::NoiseSymmetricState (*m_InitialNoiseState)); + m_CurrentNoiseState.reset (new i2p::crypto::NoiseSymmetricState (*m_InitialNoiseState)); m_CurrentNoiseState->MixHash (encrypted, 32); // h = SHA256(h || sepk) uint8_t sharedSecret[32]; if (!m_TunnelDecryptor->Decrypt (encrypted, sharedSecret, nullptr, false)) { LogPrint (eLogWarning, "Router: Incorrect ephemeral public key"); return false; - } - m_CurrentNoiseState->MixKey (sharedSecret); + } + m_CurrentNoiseState->MixKey (sharedSecret); encrypted += 32; uint8_t nonce[12]; memset (nonce, 0, 12); - if (!i2p::crypto::AEADChaCha20Poly1305 (encrypted, ECIES_BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE, + if (!i2p::crypto::AEADChaCha20Poly1305 (encrypted, ECIES_BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE, m_CurrentNoiseState->m_H, 32, m_CurrentNoiseState->m_CK + 32, nonce, data, ECIES_BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE, false)) // decrypt { LogPrint (eLogWarning, "Router: Tunnel record AEAD decryption failed"); return false; - } + } m_CurrentNoiseState->MixHash (encrypted, ECIES_BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE + 16); // h = SHA256(h || ciphertext) return true; - } - else + } + else { BN_CTX * ctx = BN_CTX_new (); bool success = m_TunnelDecryptor->Decrypt (encrypted, data, ctx, false); BN_CTX_free (ctx); return success; - } + } } i2p::crypto::X25519Keys& RouterContext::GetStaticKeys () diff --git a/libi2pd/SSU.cpp b/libi2pd/SSU.cpp index 11fab97f..f7801bb0 100644 --- a/libi2pd/SSU.cpp +++ b/libi2pd/SSU.cpp @@ -28,7 +28,7 @@ namespace transport m_ReceiversWork (m_ReceiversService), m_ReceiversWorkV6 (m_ReceiversServiceV6), m_Endpoint (boost::asio::ip::udp::v4 (), port), m_EndpointV6 (boost::asio::ip::udp::v6 (), port), m_Socket (m_ReceiversService), m_SocketV6 (m_ReceiversServiceV6), - m_IntroducersUpdateTimer (m_Service), m_IntroducersUpdateTimerV6 (m_Service), + m_IntroducersUpdateTimer (m_Service), m_IntroducersUpdateTimerV6 (m_Service), m_PeerTestsCleanupTimer (m_Service), m_TerminationTimer (m_Service), m_TerminationTimerV6 (m_Service) { } @@ -79,7 +79,7 @@ namespace transport if (context.SupportsV4 ()) { OpenSocket (); - m_ReceiversThread = new std::thread (std::bind (&SSUServer::RunReceivers, this)); + m_ReceiversThread = new std::thread (std::bind (&SSUServer::RunReceivers, this)); m_ReceiversService.post (std::bind (&SSUServer::Receive, this)); ScheduleTermination (); ScheduleIntroducersUpdateTimer (); // wait for 30 seconds and decide if we need introducers @@ -125,7 +125,7 @@ namespace transport m_Thread->join (); delete m_Thread; m_Thread = nullptr; - } + } } void SSUServer::Run () @@ -198,8 +198,8 @@ namespace transport m_EndpointV6.address (localAddress); else if (localAddress.is_v4 ()) m_Endpoint.address (localAddress); - } - + } + void SSUServer::AddRelay (uint32_t tag, std::shared_ptr relay) { m_Relays[tag] = relay; @@ -412,7 +412,7 @@ namespace transport std::shared_ptr SSUServer::FindSession (const boost::asio::ip::udp::endpoint& e) const { - auto& sessions = e.address ().is_v6 () ? m_SessionsV6 : m_Sessions; + auto& sessions = e.address ().is_v6 () ? m_SessionsV6 : m_Sessions; auto it = sessions.find (e); if (it != sessions.end ()) return it->second; @@ -439,7 +439,7 @@ namespace transport m_Service.post (std::bind (&SSUServer::CreateSessionThroughIntroducer, this, router, address, peerTest)); // always V4 thread else { - if (address->host.is_unspecified () || !address->port) return false; + if (address->host.is_unspecified () || !address->port) return false; boost::asio::ip::udp::endpoint remoteEndpoint (address->host, address->port); m_Service.post (std::bind (&SSUServer::CreateDirectSession, this, router, remoteEndpoint, peerTest)); } @@ -472,15 +472,15 @@ namespace transport } } - void SSUServer::CreateSessionThroughIntroducer (std::shared_ptr router, + void SSUServer::CreateSessionThroughIntroducer (std::shared_ptr router, std::shared_ptr address, bool peerTest) { if (router && address && address->UsesIntroducer ()) - { + { if (address->IsV4 () && !i2p::context.SupportsV4 ()) return; if (address->IsV6 () && !i2p::context.SupportsV6 ()) return; if (!address->host.is_unspecified () && address->port) - { + { // we rarely come here auto& sessions = address->host.is_v6 () ? m_SessionsV6 : m_Sessions; boost::asio::ip::udp::endpoint remoteEndpoint (address->host, address->port); @@ -493,7 +493,7 @@ namespace transport session->SendPeerTest (); return; } - } + } // create new session int numIntroducers = address->ssu->introducers.size (); if (numIntroducers > 0) @@ -509,9 +509,9 @@ namespace transport if (!intr->iPort) continue; // skip invalid introducer if (intr->iExp > 0 && ts > intr->iExp) continue; // skip expired introducer boost::asio::ip::udp::endpoint ep (intr->iHost, intr->iPort); - if (ep.address ().is_v4 () && address->IsV4 ()) // ipv4 + if (ep.address ().is_v4 () && address->IsV4 ()) // ipv4 { - if (!introducer) introducer = intr; + if (!introducer) introducer = intr; auto it = m_Sessions.find (ep); if (it != m_Sessions.end ()) { @@ -519,9 +519,9 @@ namespace transport break; } } - if (ep.address ().is_v6 () && address->IsV6 ()) // ipv6 + if (ep.address ().is_v6 () && address->IsV6 ()) // ipv6 { - if (!introducer) introducer = intr; + if (!introducer) introducer = intr; auto it = m_SessionsV6.find (ep); if (it != m_SessionsV6.end ()) { @@ -546,7 +546,7 @@ namespace transport if (introducerEndpoint.address ().is_v4 ()) m_Sessions[introducerEndpoint] = introducerSession; else if (introducerEndpoint.address ().is_v6 ()) - m_SessionsV6[introducerEndpoint] = introducerSession; + m_SessionsV6[introducerEndpoint] = introducerSession; } if (!address->host.is_unspecified () && address->port) { @@ -563,7 +563,7 @@ namespace transport "] through introducer ", introducer->iHost, ":", introducer->iPort); session->WaitForIntroduction (); if ((address->host.is_v4 () && i2p::context.GetStatus () == eRouterStatusFirewalled) || - (address->host.is_v6 () && i2p::context.GetStatusV6 () == eRouterStatusFirewalled)) + (address->host.is_v6 () && i2p::context.GetStatusV6 () == eRouterStatusFirewalled)) { uint8_t buf[1]; Send (buf, 0, remoteEndpoint); // send HolePunch @@ -648,23 +648,23 @@ namespace transport ); } - std::list > SSUServer::FindIntroducers (int maxNumIntroducers, + std::list > SSUServer::FindIntroducers (int maxNumIntroducers, bool v4, std::set& excluded) { uint32_t ts = i2p::util::GetSecondsSinceEpoch (); std::list > ret; const auto& sessions = v4 ? m_Sessions : m_SessionsV6; for (const auto& s : sessions) - { + { if (s.second->GetRelayTag () && s.second->GetState () == eSessionStateEstablished && ts < s.second->GetCreationTime () + SSU_TO_INTRODUCER_SESSION_EXPIRATION) ret.push_back (s.second); else if (s.second->GetRemoteIdentity ()) excluded.insert (s.second->GetRemoteIdentity ()->GetIdentHash ()); - } + } if ((int)ret.size () > maxNumIntroducers) { - // shink ret randomly + // shink ret randomly int sz = ret.size () - maxNumIntroducers; for (int i = 0; i < sz; i++) { @@ -672,8 +672,8 @@ namespace transport auto it = ret.begin (); std::advance (it, ind); ret.erase (it); - } - } + } + } return ret; } @@ -683,8 +683,8 @@ namespace transport m_IntroducersUpdateTimer.expires_from_now (boost::posix_time::seconds(SSU_KEEP_ALIVE_INTERVAL/2)); m_IntroducersUpdateTimer.async_wait (std::bind (&SSUServer::HandleIntroducersUpdateTimer, this, std::placeholders::_1, true)); - } - + } + void SSUServer::ScheduleIntroducersUpdateTimer () { m_IntroducersUpdateTimer.expires_from_now (boost::posix_time::seconds(SSU_KEEP_ALIVE_INTERVAL)); @@ -698,22 +698,22 @@ namespace transport m_IntroducersUpdateTimerV6.expires_from_now (boost::posix_time::seconds(SSU_KEEP_ALIVE_INTERVAL/2)); m_IntroducersUpdateTimerV6.async_wait (std::bind (&SSUServer::HandleIntroducersUpdateTimer, this, std::placeholders::_1, false)); - } - + } + void SSUServer::ScheduleIntroducersUpdateTimerV6 () { m_IntroducersUpdateTimerV6.expires_from_now (boost::posix_time::seconds(SSU_KEEP_ALIVE_INTERVAL)); m_IntroducersUpdateTimerV6.async_wait (std::bind (&SSUServer::HandleIntroducersUpdateTimer, this, std::placeholders::_1, false)); } - + void SSUServer::HandleIntroducersUpdateTimer (const boost::system::error_code& ecode, bool v4) { if (ecode != boost::asio::error::operation_aborted) { // timeout expired if (v4) - { + { if (i2p::context.GetStatus () == eRouterStatusTesting) { // we still don't know if we need introducers @@ -721,14 +721,14 @@ namespace transport return; } if (i2p::context.GetStatus () != eRouterStatusFirewalled) - { + { // we don't need introducers m_Introducers.clear (); - return; - } + return; + } // we are firewalled if (!i2p::context.IsUnreachable ()) i2p::context.SetUnreachable (true, false); // v4 - } + } else { if (i2p::context.GetStatusV6 () == eRouterStatusTesting) @@ -738,17 +738,17 @@ namespace transport return; } if (i2p::context.GetStatusV6 () != eRouterStatusFirewalled) - { + { // we don't need introducers m_IntroducersV6.clear (); - return; + return; } // we are firewalled auto addr = i2p::context.GetRouterInfo ().GetSSUV6Address (); if (addr && addr->ssu && addr->ssu->introducers.empty ()) i2p::context.SetUnreachable (false, true); // v6 - } - + } + std::list newList; size_t numIntroducers = 0; uint32_t ts = i2p::util::GetSecondsSinceEpoch (); @@ -762,7 +762,7 @@ namespace transport if (ts < session->GetCreationTime () + SSU_TO_INTRODUCER_SESSION_EXPIRATION) session->SendKeepAlive (); if (ts < session->GetCreationTime () + SSU_TO_INTRODUCER_SESSION_DURATION) - { + { newList.push_back (it); numIntroducers++; if (session->GetRemoteIdentity ()) @@ -787,11 +787,11 @@ namespace transport auto session = FindSession (it); if (session) session->SetCreationTime (session->GetCreationTime () + SSU_TO_INTRODUCER_SESSION_DURATION); - } + } // try again excluded.clear (); sessions = FindIntroducers (SSU_MAX_NUM_INTRODUCERS, v4, excluded); - } + } for (const auto& it1: sessions) { const auto& ep = it1->GetRemoteEndpoint (); @@ -814,27 +814,27 @@ namespace transport if (introducers.size () < SSU_MAX_NUM_INTRODUCERS) { for (auto i = introducers.size (); i < SSU_MAX_NUM_INTRODUCERS; i++) - { + { auto introducer = i2p::data::netdb.GetRandomIntroducer (v4, excluded); if (introducer) - { + { auto address = v4 ? introducer->GetSSUAddress (true) : introducer->GetSSUV6Address (); if (address && !address->host.is_unspecified () && address->port) { boost::asio::ip::udp::endpoint ep (address->host, address->port); if (std::find (introducers.begin (), introducers.end (), ep) == introducers.end ()) // not connected yet - { - CreateDirectSession (introducer, ep, false); + { + CreateDirectSession (introducer, ep, false); excluded.insert (introducer->GetIdentHash ()); - } - } + } + } } else - { + { LogPrint (eLogDebug, "SSU: can't find more introducers"); break; - } - } + } + } } if (v4) ScheduleIntroducersUpdateTimer (); diff --git a/libi2pd/SSUSession.cpp b/libi2pd/SSUSession.cpp index 3c519d6b..339ac8df 100644 --- a/libi2pd/SSUSession.cpp +++ b/libi2pd/SSUSession.cpp @@ -383,7 +383,7 @@ namespace transport { // tell out peer to now assign relay tag flag = SSU_HEADER_EXTENDED_OPTIONS_INCLUDED; - *payload = 2; payload++; // 1 byte length + *payload = 2; payload++; // 1 byte length uint16_t flags = 0; // clear EXTENDED_OPTIONS_FLAG_REQUEST_RELAY_TAG htobe16buf (payload, flags); payload += 2; From e37244fa0df8dcb281b78e2f46c5ee6014b23234 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Sat, 15 May 2021 16:35:38 +0300 Subject: [PATCH 86/87] remove deprecated options from config file example Signed-off-by: R4SAS --- contrib/i2pd.conf | 4 ---- 1 file changed, 4 deletions(-) diff --git a/contrib/i2pd.conf b/contrib/i2pd.conf index 09f9c155..e8c397f5 100644 --- a/contrib/i2pd.conf +++ b/contrib/i2pd.conf @@ -217,10 +217,6 @@ verify = true # openfiles = 0 ## Maximum size of corefile in Kb (0 - use system limit) # coresize = 0 -## Threshold to start probabalistic backoff with ntcp sessions (0 - use system limit) -# ntcpsoft = 0 -## Maximum number of ntcp sessions (0 - use system limit) -# ntcphard = 0 [trust] ## Enable explicit trust options. false by default From f22eaa6db51e36d0a064c56907589164752035c5 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 16 May 2021 14:26:00 -0400 Subject: [PATCH 87/87] 2.38.0 --- ChangeLog | 31 +++++++++++++++++++++++++++++++ appveyor.yml | 2 +- contrib/rpm/i2pd-git.spec | 5 ++++- contrib/rpm/i2pd.spec | 5 ++++- debian/changelog | 6 ++++++ libi2pd/version.h | 4 ++-- 6 files changed, 48 insertions(+), 5 deletions(-) diff --git a/ChangeLog b/ChangeLog index 3b2f40eb..9a79440e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,37 @@ # for this file format description, # see https://github.com/olivierlacan/keep-a-changelog +## [2.38.0] - 2021-03-17 +### Added +- Publish ipv6 introducers +- Bind ipv6 or yggdrasil NTCP2 acceptor to specified address +- Support .b32.i2p addresses and hostnames for SAM STREAM CREATE +- ipv6 peer tests +- Publish iexp param for introducers +- Show ipv6 network status on the webconsole +- EdDSA signing keys can also be blinded +- Show router version on the webconsole +### Changed +- Rekey of all routers but floodfills to ECIES +- Increased number of precalculated x25519 keys to 15 +- Don't publish LeaseSet without inbound tunnels +- Reseed from compatible address(ipv4 or ipv6) +- Recongnize v4 and v6 SSU addresses without host +- Inbound tunnel gateway must be ipv4 compatible +- Don't select next introducers from existing sessions +- Set X bandwidth for floodfill by default +### Fixed +- Incoming ECIES-x25519 session doesn't send updated LeaseSet +- Unique local address for server tunnels +- Race condition for LeaseSet creation in I2CP +- Relay tag for ipv6 introducer +- Already expired introducers +- Find connected router for first peer in tunnel +- Failed outgoing ECIES-x25519 session's tagset stays forever +- Yggdrasil address disappears if router becomes unreachable through ipv6 +- Ignore SSU address/introducers if port is not specified +- Check identity and signature length for SSU SessionConfirmed + ## [2.37.0] - 2021-03-15 ### Added - Address registration line for reg.i2p and stats.i2p through the web console diff --git a/appveyor.yml b/appveyor.yml index cf760242..89d85494 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,4 +1,4 @@ -version: 2.37.0.{build} +version: 2.38.0.{build} pull_requests: do_not_increment_build_number: true branches: diff --git a/contrib/rpm/i2pd-git.spec b/contrib/rpm/i2pd-git.spec index e0985eda..1061fc8f 100644 --- a/contrib/rpm/i2pd-git.spec +++ b/contrib/rpm/i2pd-git.spec @@ -1,7 +1,7 @@ %define git_hash %(git rev-parse HEAD | cut -c -7) Name: i2pd-git -Version: 2.37.0 +Version: 2.38.0 Release: git%{git_hash}%{?dist} Summary: I2P router written in C++ Conflicts: i2pd @@ -137,6 +137,9 @@ getent passwd i2pd >/dev/null || \ %changelog +* Mon May 17 2021 orignal - 2.38.0 +- update to 2.38.0 + * Mon Mar 15 2021 orignal - 2.37.0 - update to 2.37.0 diff --git a/contrib/rpm/i2pd.spec b/contrib/rpm/i2pd.spec index 8cb54bba..a2994f28 100644 --- a/contrib/rpm/i2pd.spec +++ b/contrib/rpm/i2pd.spec @@ -1,5 +1,5 @@ Name: i2pd -Version: 2.37.0 +Version: 2.38.0 Release: 1%{?dist} Summary: I2P router written in C++ Conflicts: i2pd-git @@ -135,6 +135,9 @@ getent passwd i2pd >/dev/null || \ %changelog +* Mon May 17 2021 orignal - 2.38.0 +- update to 2.38.0 + * Mon Mar 15 2021 orignal - 2.37.0 - update to 2.37.0 diff --git a/debian/changelog b/debian/changelog index fa7d1a92..777b6216 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +i2pd (2.38.0-1) unstable; urgency=medium + + * updated to version 2.38.0/0.9.50 + + -- orignal Mon, 17 May 2021 16:00:00 +0000 + i2pd (2.37.0-1) unstable; urgency=medium * updated to version 2.37.0 diff --git a/libi2pd/version.h b/libi2pd/version.h index dd6511f1..028d1692 100644 --- a/libi2pd/version.h +++ b/libi2pd/version.h @@ -16,7 +16,7 @@ #define MAKE_VERSION_NUMBER(a,b,c) ((a*100+b)*100+c) #define I2PD_VERSION_MAJOR 2 -#define I2PD_VERSION_MINOR 37 +#define I2PD_VERSION_MINOR 38 #define I2PD_VERSION_MICRO 0 #define I2PD_VERSION_PATCH 0 #define I2PD_VERSION MAKE_VERSION(I2PD_VERSION_MAJOR, I2PD_VERSION_MINOR, I2PD_VERSION_MICRO) @@ -30,7 +30,7 @@ #define I2P_VERSION_MAJOR 0 #define I2P_VERSION_MINOR 9 -#define I2P_VERSION_MICRO 49 +#define I2P_VERSION_MICRO 50 #define I2P_VERSION_PATCH 0 #define I2P_VERSION MAKE_VERSION(I2P_VERSION_MAJOR, I2P_VERSION_MINOR, I2P_VERSION_MICRO) #define I2P_VERSION_NUMBER MAKE_VERSION_NUMBER(I2P_VERSION_MAJOR, I2P_VERSION_MINOR, I2P_VERSION_MICRO)