From 28db337166f8aabcffcc7b3255e8d7bdf6afd039 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 30 Jun 2022 12:53:50 -0400 Subject: [PATCH 001/219] give priority to SSU2 over SSU --- libi2pd/Transports.cpp | 106 ++++++++++++++++++++--------------------- 1 file changed, 53 insertions(+), 53 deletions(-) diff --git a/libi2pd/Transports.cpp b/libi2pd/Transports.cpp index 31abad6e..2c678058 100644 --- a/libi2pd/Transports.cpp +++ b/libi2pd/Transports.cpp @@ -453,7 +453,7 @@ namespace transport peer.router = netdb.FindRouter (ident); // try to get new one from netdb if (peer.router) // we have RI already { - if (peer.numAttempts < 2) // NTCP2, 0 - ipv6, 1- ipv4 + if (peer.numAttempts < 2) // NTCP2, 0 - ipv6, 1 - ipv4 { if (m_NTCP2Server) // we support NTCP2 { @@ -491,60 +491,12 @@ namespace transport else peer.numAttempts = 2; // switch to SSU } - if (peer.numAttempts == 2 || peer.numAttempts == 3) // SSU - { - if (m_SSUServer) - { - std::shared_ptr address; - if (peer.numAttempts == 2) // SSU ipv6 - { - if (context.GetRouterInfo ().IsSSUV6 () && peer.router->IsReachableBy (RouterInfo::eSSUV6)) - { - address = peer.router->GetSSUV6Address (); - if (address && m_CheckReserved && i2p::util::net::IsInReservedRange(address->host)) - address = nullptr; - } - peer.numAttempts++; - } - if (!address && peer.numAttempts == 3) // SSU ipv4 - { - if (context.GetRouterInfo ().IsSSU (true) && peer.router->IsReachableBy (RouterInfo::eSSUV4)) - { - address = peer.router->GetSSUAddress (true); - if (address && m_CheckReserved && i2p::util::net::IsInReservedRange(address->host)) - address = nullptr; - } - peer.numAttempts++; - } - if (address && address->IsReachableSSU ()) - { - if (m_SSUServer->CreateSession (peer.router, address)) - return true; - } - } - else - peer.numAttempts += 2; // switch to Mesh - } - if (peer.numAttempts == 4) // Mesh - { - peer.numAttempts++; - if (m_NTCP2Server && context.GetRouterInfo ().IsMesh () && peer.router->IsMesh ()) - { - auto address = peer.router->GetYggdrasilAddress (); - if (address) - { - auto s = std::make_shared (*m_NTCP2Server, peer.router, address); - m_NTCP2Server->Connect (s); - return true; - } - } - } - if (peer.numAttempts == 5 || peer.numAttempts == 6) // SSU2 + if (peer.numAttempts == 2 || peer.numAttempts == 3) // SSU2, 2 - ipv6, 3 - ipv4 { if (m_SSU2Server) { std::shared_ptr address; - if (peer.numAttempts == 5) // SSU2 ipv6 + if (peer.numAttempts == 2) // SSU2 ipv6 { if (context.GetRouterInfo ().IsSSU2V6 () && peer.router->IsReachableBy (RouterInfo::eSSU2V6)) { @@ -554,7 +506,7 @@ namespace transport } peer.numAttempts++; } - if (!address && peer.numAttempts == 6) // SSU2 ipv4 + if (!address && peer.numAttempts == 3) // SSU2 ipv4 { if (context.GetRouterInfo ().IsSSU2V4 () && peer.router->IsReachableBy (RouterInfo::eSSU2V4)) { @@ -571,7 +523,55 @@ namespace transport } } else - peer.numAttempts += 2; + peer.numAttempts += 2; // switch to mesh + } + if (peer.numAttempts == 4) // Mesh + { + peer.numAttempts++; + if (m_NTCP2Server && context.GetRouterInfo ().IsMesh () && peer.router->IsMesh ()) + { + auto address = peer.router->GetYggdrasilAddress (); + if (address) + { + auto s = std::make_shared (*m_NTCP2Server, peer.router, address); + m_NTCP2Server->Connect (s); + return true; + } + } + } + if (peer.numAttempts == 5 || peer.numAttempts == 6) // SSU, 5 - ipv6, 6 - ipv4 + { + if (m_SSUServer) + { + std::shared_ptr address; + if (peer.numAttempts == 5) // SSU ipv6 + { + if (context.GetRouterInfo ().IsSSUV6 () && peer.router->IsReachableBy (RouterInfo::eSSUV6)) + { + address = peer.router->GetSSUV6Address (); + if (address && m_CheckReserved && i2p::util::net::IsInReservedRange(address->host)) + address = nullptr; + } + peer.numAttempts++; + } + if (!address && peer.numAttempts == 6) // SSU ipv4 + { + if (context.GetRouterInfo ().IsSSU (true) && peer.router->IsReachableBy (RouterInfo::eSSUV4)) + { + address = peer.router->GetSSUAddress (true); + if (address && m_CheckReserved && i2p::util::net::IsInReservedRange(address->host)) + address = nullptr; + } + peer.numAttempts++; + } + if (address && address->IsReachableSSU ()) + { + if (m_SSUServer->CreateSession (peer.router, address)) + return true; + } + } + else + peer.numAttempts += 2; } LogPrint (eLogInfo, "Transports: No compatble NTCP2 or SSU addresses available"); i2p::data::netdb.SetUnreachable (ident, true); // we are here because all connection attempts failed From d375299fa926aff325ba0270d9cd1f7d49b975b9 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 30 Jun 2022 20:00:18 -0400 Subject: [PATCH 002/219] send token in relay response block --- libi2pd/SSU2Session.cpp | 22 ++++++++++++++++------ libi2pd/SSU2Session.h | 4 ++-- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index 55c07b90..ecd61f94 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -887,7 +887,8 @@ namespace transport return true; } - void SSU2Session::SendHolePunch (uint32_t nonce, const boost::asio::ip::udp::endpoint& ep, const uint8_t * introKey) + void SSU2Session::SendHolePunch (uint32_t nonce, const boost::asio::ip::udp::endpoint& ep, + const uint8_t * introKey, uint64_t token) { // we are Charlie Header header; @@ -910,7 +911,7 @@ namespace transport size_t payloadSize = 7; payloadSize += CreateAddressBlock (payload + payloadSize, SSU2_MAX_PAYLOAD_SIZE - payloadSize, ep); payloadSize += CreateRelayResponseBlock (payload + payloadSize, SSU2_MAX_PAYLOAD_SIZE - payloadSize, - eSSU2RelayResponseCodeAccept ,nonce, true); + eSSU2RelayResponseCodeAccept, nonce, true, token); payloadSize += CreatePaddingBlock (payload + payloadSize, SSU2_MAX_PAYLOAD_SIZE - payloadSize); // encrypt uint8_t n[12]; @@ -1365,7 +1366,7 @@ namespace transport // send relay response back to Alice uint8_t payload[SSU2_MAX_PAYLOAD_SIZE]; size_t payloadSize = CreateRelayResponseBlock (payload, SSU2_MAX_PAYLOAD_SIZE, - eSSU2RelayResponseCodeBobRelayTagNotFound, bufbe32toh (buf + 1), false); + eSSU2RelayResponseCodeBobRelayTagNotFound, bufbe32toh (buf + 1), false, 0); payloadSize += CreatePaddingBlock (payload + payloadSize, SSU2_MAX_PAYLOAD_SIZE - payloadSize); SendData (payload, payloadSize); return; @@ -1393,6 +1394,7 @@ namespace transport { // we are Charlie SSU2RelayResponseCode code = eSSU2RelayResponseCodeAccept; + uint64_t token = 0; auto r = i2p::data::netdb.FindRouter (buf + 1); // Alice if (r) { @@ -1413,7 +1415,10 @@ namespace transport if (addr) { if (m_Server.IsSupported (ep.address ())) - SendHolePunch (bufbe32toh (buf + 33), ep, addr->i); + { + token = m_Server.GetIncomingToken (ep); + SendHolePunch (bufbe32toh (buf + 33), ep, addr->i, token); + } else code = eSSU2RelayResponseCodeCharlieUnsupportedAddress; } @@ -1438,7 +1443,7 @@ namespace transport // send relay response to Bob uint8_t payload[SSU2_MAX_PAYLOAD_SIZE]; size_t payloadSize = CreateRelayResponseBlock (payload, SSU2_MAX_PAYLOAD_SIZE, - code, bufbe32toh (buf + 33), true); + code, bufbe32toh (buf + 33), true, token); payloadSize += CreatePaddingBlock (payload + payloadSize, SSU2_MAX_PAYLOAD_SIZE - payloadSize); SendData (payload, payloadSize); } @@ -1959,7 +1964,7 @@ namespace transport } size_t SSU2Session::CreateRelayResponseBlock (uint8_t * buf, size_t len, - SSU2RelayResponseCode code, uint32_t nonce, bool endpoint) + SSU2RelayResponseCode code, uint32_t nonce, bool endpoint, uint64_t token) { buf[0] = eSSU2BlkRelayResponse; buf[3] = 0; // flag @@ -1981,6 +1986,11 @@ namespace transport s.Insert (buf + 5, 10 + csz); // nonce, timestamp, ver, csz and Charlie's endpoint s.Sign (i2p::context.GetPrivateKeys (), buf + 15 + csz); size_t payloadSize = 12 + csz + i2p::context.GetIdentity ()->GetSignatureLen (); + if (!code) + { + memcpy (buf + payloadSize, &token, 8); + payloadSize += 8; + } htobe16buf (buf + 1, payloadSize); // size return payloadSize + 3; } diff --git a/libi2pd/SSU2Session.h b/libi2pd/SSU2Session.h index f1dba8a7..8bd42199 100644 --- a/libi2pd/SSU2Session.h +++ b/libi2pd/SSU2Session.h @@ -229,7 +229,7 @@ namespace transport uint32_t SendData (const uint8_t * buf, size_t len); // returns packet num void SendQuickAck (); void SendTermination (); - void SendHolePunch (uint32_t nonce, const boost::asio::ip::udp::endpoint& ep, const uint8_t * introKey); + void SendHolePunch (uint32_t nonce, const boost::asio::ip::udp::endpoint& ep, const uint8_t * introKey, uint64_t token); void SendPeerTest (uint8_t msg, const uint8_t * signedData, size_t signedDataLen, const uint8_t * introKey); // PeerTest message void HandlePayload (const uint8_t * buf, size_t len); @@ -257,7 +257,7 @@ namespace transport size_t CreateFirstFragmentBlock (uint8_t * buf, size_t len, std::shared_ptr msg); size_t CreateFollowOnFragmentBlock (uint8_t * buf, size_t len, std::shared_ptr msg, uint8_t& fragmentNum, uint32_t msgID); size_t CreateRelayIntroBlock (uint8_t * buf, size_t len, const uint8_t * introData, size_t introDataLen); - size_t CreateRelayResponseBlock (uint8_t * buf, size_t len, SSU2RelayResponseCode code, uint32_t nonce, bool endpoint); // add endpoint for Chralie and no endpoint for Bob + size_t CreateRelayResponseBlock (uint8_t * buf, size_t len, SSU2RelayResponseCode code, uint32_t nonce, bool endpoint, uint64_t token); // add endpoint for Chralie and no endpoint for Bob size_t CreatePeerTestBlock (uint8_t * buf, size_t len, uint8_t msg, SSU2PeerTestCode code, const uint8_t * routerHash, const uint8_t * signedData, size_t signedDataLen); size_t CreatePeerTestBlock (uint8_t * buf, size_t len, uint32_t nonce); // Alice From 455390f1215b465beba676216d314255a30c5665 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 1 Jul 2022 10:52:10 -0400 Subject: [PATCH 003/219] clean up first out of sequence packet if too many --- libi2pd/SSU2Session.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index ecd61f94..753da03a 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -2126,6 +2126,19 @@ namespace transport m_ReceivePacketNum = *m_OutOfSequencePackets.rbegin (); m_OutOfSequencePackets.clear (); } + else if (m_OutOfSequencePackets.size () > SSU2_MAX_NUM_ACK_RANGES) + { + uint32_t packet = *m_OutOfSequencePackets.begin (); + if (packet > m_ReceivePacketNum + 1) + { + // like we've just received all packets before first + m_ReceivePacketNum = packet - 1; + UpdateReceivePacketNum (packet); + } + else + LogPrint (eLogError, "SSU2: Out of sequence packet ", packet, " is less than last received", m_ReceivePacketNum); + } + for (auto it = m_RelaySessions.begin (); it != m_RelaySessions.end ();) { if (ts > it->second.second + SSU2_RELAY_NONCE_EXPIRATION_TIMEOUT) From 50419f200d7ec68afbf30ee86ffa2987e235f39c Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 1 Jul 2022 17:35:38 -0400 Subject: [PATCH 004/219] fixed 1 packet off for out of sequence clean up --- libi2pd/SSU2Session.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index 753da03a..31e7f189 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -2132,11 +2132,12 @@ namespace transport if (packet > m_ReceivePacketNum + 1) { // like we've just received all packets before first + packet--; m_ReceivePacketNum = packet - 1; UpdateReceivePacketNum (packet); } else - LogPrint (eLogError, "SSU2: Out of sequence packet ", packet, " is less than last received", m_ReceivePacketNum); + LogPrint (eLogError, "SSU2: Out of sequence packet ", packet, " is less than last received ", m_ReceivePacketNum); } for (auto it = m_RelaySessions.begin (); it != m_RelaySessions.end ();) From 6143515ac6d82a9b1c55893160727d03b28bbc6c Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 3 Jul 2022 09:31:20 -0400 Subject: [PATCH 005/219] update our IP adress from SSU2 --- libi2pd/SSU2Session.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index 31e7f189..7bbee4c4 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -719,13 +719,13 @@ namespace transport return false; } SetRemoteIdentity (ri->GetRouterIdentity ()); - m_Server.AddSessionByRouterHash (shared_from_this ()); // we know remote router now m_Address = ri->GetSSU2AddressWithStaticKey (S, m_RemoteEndpoint.address ().is_v6 ()); if (!m_Address) { LogPrint (eLogError, "SSU2: No SSU2 address with static key found in SessionConfirmed"); return false; } + m_Server.AddSessionByRouterHash (shared_from_this ()); // we know remote router now m_RemoteTransports = ri->GetCompatibleTransports (false); i2p::data::netdb.PostI2NPMsg (CreateDatabaseStoreMsg (ri)); // TODO: should insert ri // handle other blocks @@ -1177,7 +1177,11 @@ namespace transport { boost::asio::ip::udp::endpoint ep; if (ExtractEndpoint (buf + offset, size, ep)) + { LogPrint (eLogInfo, "SSU2: Our external address is ", ep); + if (!i2p::util::net::IsInReservedRange (ep.address ())) + i2p::context.UpdateAddress (ep.address ()); + } break; } case eSSU2BlkIntroKey: From 0e6ad548b2d89cbacbabf4cff5563e65c0adbb7c Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 4 Jul 2022 18:54:20 -0400 Subject: [PATCH 006/219] invoke SSU2 peer test updates --- libi2pd/RouterContext.cpp | 28 ++++++++++++++++++++++++++-- libi2pd/RouterContext.h | 3 +++ libi2pd/SSU2Session.cpp | 11 +++++++++++ 3 files changed, 40 insertions(+), 2 deletions(-) diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index 1c8914e5..0cc91a95 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -225,6 +225,13 @@ namespace i2p fk.write ((char *)m_SSU2Keys.get (), sizeof (SSU2PrivateKeys)); } + bool RouterContext::IsSSU2Only () const + { + auto transports = m_RouterInfo.GetCompatibleTransports (false); + return (transports & (i2p::data::RouterInfo::eSSU2V4 | i2p::data::RouterInfo::eSSU2V6)) && + (transports & ~(i2p::data::RouterInfo::eSSUV4 | i2p::data::RouterInfo::eSSUV6)); + } + void RouterContext::SetStatus (RouterStatus status) { if (status != m_Status) @@ -245,6 +252,12 @@ namespace i2p } } + void RouterContext::SetStatusSSU2 (RouterStatus status) + { + if (IsSSU2Only ()) + SetStatus (status); + } + void RouterContext::SetStatusV6 (RouterStatus status) { if (status != m_StatusV6) @@ -264,6 +277,12 @@ namespace i2p } } + void RouterContext::SetStatusV6SSU2 (RouterStatus status) + { + if (IsSSU2Only ()) + SetStatusV6 (status); + } + void RouterContext::UpdatePort (int port) { bool updated = false; @@ -568,7 +587,8 @@ namespace i2p // delete previous introducers auto& addresses = m_RouterInfo.GetAddresses (); for (auto& addr : addresses) - if (addr->ssu && !addr->IsSSU2 () && ((v4 && addr->IsV4 ()) || (v6 && addr->IsV6 ()))) + if (addr->ssu && (!addr->IsSSU2 () || IsSSU2Only ()) && + ((v4 && addr->IsV4 ()) || (v6 && addr->IsV6 ()))) { addr->published = false; addr->caps &= ~i2p::data::RouterInfo::eSSUIntroducer; // can't be introducer @@ -598,9 +618,13 @@ namespace i2p } uint16_t port = 0; // delete previous introducers + bool isSSU2Published = IsSSU2Only (); // TODO + if (isSSU2Published) + i2p::config::GetOption ("ssu2.published", isSSU2Published); auto& addresses = m_RouterInfo.GetAddresses (); for (auto& addr : addresses) - if (addr->ssu && !addr->IsSSU2 () && ((v4 && addr->IsV4 ()) || (v6 && addr->IsV6 ()))) + if (addr->ssu && (!addr->IsSSU2 () || isSSU2Published) && + ((v4 && addr->IsV4 ()) || (v6 && addr->IsV6 ()))) { addr->published = true; addr->caps |= i2p::data::RouterInfo::eSSUIntroducer; diff --git a/libi2pd/RouterContext.h b/libi2pd/RouterContext.h index eb5db38f..7a878c7d 100644 --- a/libi2pd/RouterContext.h +++ b/libi2pd/RouterContext.h @@ -103,10 +103,12 @@ namespace garlic uint64_t GetTransitBandwidthLimit () const { return (m_BandwidthLimit*m_ShareRatio)/100LL; }; RouterStatus GetStatus () const { return m_Status; }; void SetStatus (RouterStatus status); + void SetStatusSSU2 (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); + void SetStatusV6SSU2 (RouterStatus status); int GetNetID () const { return m_NetID; }; void SetNetID (int netID) { m_NetID = netID; }; bool DecryptTunnelBuildRecord (const uint8_t * encrypted, uint8_t * data); @@ -173,6 +175,7 @@ namespace garlic void UpdateRouterInfo (); void NewNTCP2Keys (); void NewSSU2Keys (); + bool IsSSU2Only () const; // SSU2 and no SSU bool Load (); void SaveKeys (); diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index 7bbee4c4..401c6768 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -1691,6 +1691,13 @@ namespace transport it->second.first->m_State = eSSU2SessionStatePeerTest; it->second.first->SendPeerTest (6, buf + offset, len - offset, addr->i); } + else + { + if (m_Address->IsV4 () && i2p::context.GetStatus () == eRouterStatusTesting) + i2p::context.SetStatusSSU2 (eRouterStatusFirewalled); + if (m_Address->IsV6 () && i2p::context.GetStatusV6 () == eRouterStatusTesting) + i2p::context.SetStatusV6SSU2 (eRouterStatusFirewalled); + } } else { @@ -1737,6 +1744,10 @@ namespace transport break; case 7: // Alice from Charlie 2 m_Server.RemoveSession (htobe64 (((uint64_t)nonce << 32) | nonce)); + if (m_Address->IsV6 ()) + i2p::context.SetStatusV6 (eRouterStatusOK); // set status OK for ipv6 even if from SSU2 + else + i2p::context.SetStatusSSU2 (eRouterStatusOK); break; default: LogPrint (eLogWarning, "SSU2: PeerTest unexpected msg num ", buf[0]); From 473159be0f5805f92a5fb6cb62437035c674c52a Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 4 Jul 2022 19:32:43 -0400 Subject: [PATCH 007/219] don't use port from SSU2 address --- libi2pd/RouterContext.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index 0cc91a95..31ed7cbf 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -629,7 +629,8 @@ namespace i2p addr->published = true; addr->caps |= i2p::data::RouterInfo::eSSUIntroducer; addr->ssu->introducers.clear (); - port = addr->port; + if (!addr->IsSSU2 ()) + port = addr->port; } // publish NTCP2 bool ntcp2; i2p::config::GetOption("ntcp2.enabled", ntcp2); From 6039cdceb03c4082656a871cb2f65db36b7cd3b7 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 4 Jul 2022 20:01:45 -0400 Subject: [PATCH 008/219] correct SSU2 only detection --- libi2pd/RouterContext.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index 31ed7cbf..b401b8c6 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -229,7 +229,7 @@ namespace i2p { auto transports = m_RouterInfo.GetCompatibleTransports (false); return (transports & (i2p::data::RouterInfo::eSSU2V4 | i2p::data::RouterInfo::eSSU2V6)) && - (transports & ~(i2p::data::RouterInfo::eSSUV4 | i2p::data::RouterInfo::eSSUV6)); + !(transports & (i2p::data::RouterInfo::eSSUV4 | i2p::data::RouterInfo::eSSUV6)); } void RouterContext::SetStatus (RouterStatus status) From 2a24584d45523851874f7858eaf5d44e32037315 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 4 Jul 2022 23:00:16 -0400 Subject: [PATCH 009/219] set SSU2 port if not specified --- daemon/Daemon.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/daemon/Daemon.cpp b/daemon/Daemon.cpp index c6e6465a..1afa25e9 100644 --- a/daemon/Daemon.cpp +++ b/daemon/Daemon.cpp @@ -257,6 +257,12 @@ namespace util if (published) { uint16_t ssu2port; i2p::config::GetOption("ssu2.port", ssu2port); + if (!ssu2port) + { + ssu2port = port; + bool ssu; i2p::config::GetOption("ssu", ssu); + if (ssu) ssu2port++; + } i2p::context.PublishSSU2Address (ssu2port, true, ipv4, ipv6); // publish } else From a5a35b1fa67a3e31258ef68866a41283fde134e8 Mon Sep 17 00:00:00 2001 From: r4sas Date: Tue, 5 Jul 2022 06:11:16 +0000 Subject: [PATCH 010/219] [daemon] check for SSU2 transport at start Signed-off-by: r4sas --- daemon/Daemon.cpp | 2 +- libi2pd/Transports.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/daemon/Daemon.cpp b/daemon/Daemon.cpp index 1afa25e9..6c895c5e 100644 --- a/daemon/Daemon.cpp +++ b/daemon/Daemon.cpp @@ -410,7 +410,7 @@ namespace util i2p::transport::transports.SetCheckReserved(checkInReserved); i2p::transport::transports.Start(ntcp2, ssu, ssu2); - if (i2p::transport::transports.IsBoundSSU() || i2p::transport::transports.IsBoundNTCP2()) + if (i2p::transport::transports.IsBoundSSU() || i2p::transport::transports.IsBoundSSU2() || i2p::transport::transports.IsBoundNTCP2()) LogPrint(eLogInfo, "Daemon: Transports started"); else { diff --git a/libi2pd/Transports.h b/libi2pd/Transports.h index 8fdf6055..78088a8d 100644 --- a/libi2pd/Transports.h +++ b/libi2pd/Transports.h @@ -93,6 +93,7 @@ namespace transport void Stop (); bool IsBoundSSU() const { return m_SSUServer != nullptr; } + bool IsBoundSSU2() const { return m_SSU2Server != nullptr; } bool IsBoundNTCP2() const { return m_NTCP2Server != nullptr; } bool IsOnline() const { return m_IsOnline; }; From a1e414c3b74cfad8ba2318770a83adda6f1fdc17 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 5 Jul 2022 12:55:11 -0400 Subject: [PATCH 011/219] make SSU2 server eligible for peer test --- libi2pd/Transports.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd/Transports.cpp b/libi2pd/Transports.cpp index 2c678058..d81c0141 100644 --- a/libi2pd/Transports.cpp +++ b/libi2pd/Transports.cpp @@ -630,7 +630,7 @@ namespace transport void Transports::PeerTest (bool ipv4, bool ipv6) { - if (RoutesRestricted() || !m_SSUServer) return; + if (RoutesRestricted() || (!m_SSUServer && !m_SSU2Server)) return; if (ipv4 && i2p::context.SupportsV4 ()) { LogPrint (eLogInfo, "Transports: Started peer test IPv4"); From 3ed625f9495888b67b5715ba0a3ba28615d780e6 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 5 Jul 2022 13:07:23 -0400 Subject: [PATCH 012/219] don't try SSU peer test if SSU is disabled --- libi2pd/Transports.cpp | 65 +++++++++++++++++++++++------------------- 1 file changed, 35 insertions(+), 30 deletions(-) diff --git a/libi2pd/Transports.cpp b/libi2pd/Transports.cpp index d81c0141..800c358a 100644 --- a/libi2pd/Transports.cpp +++ b/libi2pd/Transports.cpp @@ -636,28 +636,30 @@ namespace transport LogPrint (eLogInfo, "Transports: Started peer test IPv4"); std::set excluded; excluded.insert (i2p::context.GetIdentHash ()); // don't pick own router - bool statusChanged = false; - for (int i = 0; i < 5; i++) - { - auto router = i2p::data::netdb.GetRandomPeerTestRouter (true, excluded); // v4 - if (router) + if (m_SSUServer) + { + bool statusChanged = false; + for (int i = 0; i < 5; i++) { - auto addr = router->GetSSUAddress (true); // ipv4 - if (addr && !i2p::util::net::IsInReservedRange(addr->host)) + auto router = i2p::data::netdb.GetRandomPeerTestRouter (true, excluded); // 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 + if (!statusChanged) + { + 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 ()); } - excluded.insert (router->GetIdentHash ()); } + if (!statusChanged) + LogPrint (eLogWarning, "Transports: Can't find routers for peer test IPv4"); } - if (!statusChanged) - LogPrint (eLogWarning, "Transports: Can't find routers for peer test IPv4"); - // SSU2 if (m_SSU2Server) { @@ -673,28 +675,31 @@ namespace transport LogPrint (eLogInfo, "Transports: Started peer test IPv6"); std::set excluded; excluded.insert (i2p::context.GetIdentHash ()); // don't pick own router - bool statusChanged = false; - for (int i = 0; i < 5; i++) - { - auto router = i2p::data::netdb.GetRandomPeerTestRouter (false, excluded); // v6 - if (router) + if (m_SSUServer) + { + bool statusChanged = false; + for (int i = 0; i < 5; i++) { - auto addr = router->GetSSUV6Address (); - if (addr && !i2p::util::net::IsInReservedRange(addr->host)) + auto router = i2p::data::netdb.GetRandomPeerTestRouter (false, excluded); // v6 + if (router) { - if (!statusChanged) + auto addr = router->GetSSUV6Address (); + if (addr && !i2p::util::net::IsInReservedRange(addr->host)) { - statusChanged = true; - i2p::context.SetStatusV6 (eRouterStatusTesting); // first time only + if (!statusChanged) + { + statusChanged = true; + i2p::context.SetStatusV6 (eRouterStatusTesting); // first time only + } + m_SSUServer->CreateSession (router, addr, true); // peer test v6 } - m_SSUServer->CreateSession (router, addr, true); // peer test v6 + excluded.insert (router->GetIdentHash ()); } - excluded.insert (router->GetIdentHash ()); } + if (!statusChanged) + LogPrint (eLogWarning, "Transports: Can't find routers for peer test IPv6"); } - if (!statusChanged) - LogPrint (eLogWarning, "Transports: Can't find routers for peer test IPv6"); - + // SSU2 if (m_SSU2Server) { From e3eebe537b2e0779e53b537d59cd249c76f43604 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 5 Jul 2022 14:00:30 -0400 Subject: [PATCH 013/219] set correct port for unpublished SSU2 addresses --- daemon/Daemon.cpp | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/daemon/Daemon.cpp b/daemon/Daemon.cpp index 6c895c5e..5ea1bfc0 100644 --- a/daemon/Daemon.cpp +++ b/daemon/Daemon.cpp @@ -253,20 +253,13 @@ namespace util bool ssu2; i2p::config::GetOption("ssu2.enabled", ssu2); if (ssu2) { + uint16_t ssu2port; i2p::config::GetOption("ssu2.port", ssu2port); + if (!ssu2port) ssu2port = port; bool published; i2p::config::GetOption("ssu2.published", published); if (published) - { - uint16_t ssu2port; i2p::config::GetOption("ssu2.port", ssu2port); - if (!ssu2port) - { - ssu2port = port; - bool ssu; i2p::config::GetOption("ssu", ssu); - if (ssu) ssu2port++; - } i2p::context.PublishSSU2Address (ssu2port, true, ipv4, ipv6); // publish - } else - i2p::context.PublishSSU2Address (0, false, ipv4, ipv6); // unpublish + i2p::context.PublishSSU2Address (ssu2port, false, ipv4, ipv6); // unpublish } bool transit; i2p::config::GetOption("notransit", transit); From 66bc29d0754520992917e16d7c01db8195bd99ed Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 5 Jul 2022 19:15:50 -0400 Subject: [PATCH 014/219] insert received RouterInfo into netdb immediately --- libi2pd/SSU2Session.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index 401c6768..0941b662 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -1119,11 +1119,11 @@ namespace transport break; case eSSU2BlkRouterInfo: { - // not from SessionConfirmed + // not from SessionConfirmed, we must add it instantly to use in next block LogPrint (eLogDebug, "SSU2: RouterInfo"); auto ri = ExtractRouterInfo (buf + offset, size); if (ri) - i2p::data::netdb.PostI2NPMsg (CreateI2NPMessage (eI2NPDummyMsg, ri->GetBuffer (), ri->GetBufferLen ())); // TODO: should insert ri + i2p::data::netdb.AddRouterInfo (ri->GetBuffer (), ri->GetBufferLen ()); // TODO: add ri break; } case eSSU2BlkI2NPMessage: From a2f4e08b001bd749a089e7277c092560e79f27f2 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 5 Jul 2022 19:38:24 -0400 Subject: [PATCH 015/219] set testing status for SSU2 peer test --- libi2pd/Transports.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/libi2pd/Transports.cpp b/libi2pd/Transports.cpp index 800c358a..2d1af187 100644 --- a/libi2pd/Transports.cpp +++ b/libi2pd/Transports.cpp @@ -667,7 +667,10 @@ namespace transport excluded.insert (i2p::context.GetIdentHash ()); auto router = i2p::data::netdb.GetRandomSSU2PeerTestRouter (true, excluded); // v4 if (router) + { + i2p::context.SetStatusSSU2 (eRouterStatusTesting); m_SSU2Server->StartPeerTest (router, true); + } } } if (ipv6 && i2p::context.SupportsV6 ()) @@ -707,7 +710,10 @@ namespace transport excluded.insert (i2p::context.GetIdentHash ()); auto router = i2p::data::netdb.GetRandomSSU2PeerTestRouter (false, excluded); // v6 if (router) + { + i2p::context.SetStatusV6SSU2 (eRouterStatusTesting); m_SSU2Server->StartPeerTest (router, false); + } } } } From aa21748e9aee1f586a51fb8babca9dd16466a292 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 6 Jul 2022 12:41:51 -0400 Subject: [PATCH 016/219] set status OK after peer test msg 5 --- libi2pd/SSU2Session.cpp | 34 +++++++++++++++++++++++++++------- libi2pd/SSU2Session.h | 3 +++ 2 files changed, 30 insertions(+), 7 deletions(-) diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index 0941b662..fcde3cfc 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -9,7 +9,6 @@ #include #include #include "Log.h" -#include "RouterContext.h" #include "Transports.h" #include "Gzip.h" #include "NetDb.hpp" @@ -1693,10 +1692,8 @@ namespace transport } else { - if (m_Address->IsV4 () && i2p::context.GetStatus () == eRouterStatusTesting) - i2p::context.SetStatusSSU2 (eRouterStatusFirewalled); - if (m_Address->IsV6 () && i2p::context.GetStatusV6 () == eRouterStatusTesting) - i2p::context.SetStatusV6SSU2 (eRouterStatusFirewalled); + if (GetRouterStatus () == eRouterStatusTesting) + SetRouterStatus (eRouterStatusFirewalled); } } else @@ -1715,6 +1712,7 @@ namespace transport else { LogPrint (eLogInfo, "SSU2: Peer test 4 error code ", (int)buf[1]); + SetRouterStatus (eRouterStatusUnknown); it->second.first->Terminate (); } m_PeerTests.erase (it); @@ -1731,6 +1729,7 @@ namespace transport else // we received msg 5 before msg 4 m_State = eSSU2SessionStatePeerTestReceived; + SetRouterStatus (eRouterStatusOK); } else LogPrint (eLogWarning, "SSU2: Peer test 5 nonce mismatch ", nonce, " connID=", m_SourceConnID); @@ -1746,8 +1745,6 @@ namespace transport m_Server.RemoveSession (htobe64 (((uint64_t)nonce << 32) | nonce)); if (m_Address->IsV6 ()) i2p::context.SetStatusV6 (eRouterStatusOK); // set status OK for ipv6 even if from SSU2 - else - i2p::context.SetStatusSSU2 (eRouterStatusOK); break; default: LogPrint (eLogWarning, "SSU2: PeerTest unexpected msg num ", buf[0]); @@ -1808,6 +1805,29 @@ namespace transport return i2p::context.GetRouterInfo ().GetSSU2Address (m_Address->IsV4 ()); return nullptr; } + + RouterStatus SSU2Session::GetRouterStatus () const + { + if (m_Address) + { + if (m_Address->IsV4 ()) + return i2p::context.GetStatus (); + if (m_Address->IsV6 ()) + return i2p::context.GetStatusV6 (); + } + return eRouterStatusUnknown; + } + + void SSU2Session::SetRouterStatus (RouterStatus status) const + { + if (m_Address) + { + if (m_Address->IsV4 ()) + i2p::context.SetStatusSSU2 (status); + else if (m_Address->IsV6 ()) + i2p::context.SetStatusV6SSU2 (status); + } + } size_t SSU2Session::CreateAddressBlock (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& ep) { diff --git a/libi2pd/SSU2Session.h b/libi2pd/SSU2Session.h index 8bd42199..f18f51f6 100644 --- a/libi2pd/SSU2Session.h +++ b/libi2pd/SSU2Session.h @@ -17,6 +17,7 @@ #include #include "Crypto.h" #include "RouterInfo.h" +#include "RouterContext.h" #include "TransportSession.h" namespace i2p @@ -238,6 +239,8 @@ namespace transport bool ExtractEndpoint (const uint8_t * buf, size_t size, boost::asio::ip::udp::endpoint& ep); size_t CreateEndpoint (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& ep); std::shared_ptr FindLocalAddress () const; + RouterStatus GetRouterStatus () const; + void SetRouterStatus (RouterStatus status) const; std::shared_ptr ExtractRouterInfo (const uint8_t * buf, size_t size); void CreateNonce (uint64_t seqn, uint8_t * nonce); bool UpdateReceivePacketNum (uint32_t packetNum); // for Ack, returns false if duplicate From f7e9e6a1c499744ec443bc9df2eea54697d0d85e Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 6 Jul 2022 13:35:04 -0400 Subject: [PATCH 017/219] set status OK after both peer test msg 4 and 5 --- libi2pd/SSU2Session.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index fcde3cfc..305c8452 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -1687,6 +1687,7 @@ namespace transport if (it->second.first->m_State == eSSU2SessionStatePeerTestReceived) { // msg 5 already received. send msg 6 + SetRouterStatus (eRouterStatusOK); it->second.first->m_State = eSSU2SessionStatePeerTest; it->second.first->SendPeerTest (6, buf + offset, len - offset, addr->i); } @@ -1725,11 +1726,13 @@ namespace transport if (htobe64 (((uint64_t)nonce << 32) | nonce) == m_SourceConnID) { if (m_Address) + { + SetRouterStatus (eRouterStatusOK); SendPeerTest (6, buf + offset, len - offset, m_Address->i); + } else // we received msg 5 before msg 4 m_State = eSSU2SessionStatePeerTestReceived; - SetRouterStatus (eRouterStatusOK); } else LogPrint (eLogWarning, "SSU2: Peer test 5 nonce mismatch ", nonce, " connID=", m_SourceConnID); From 83f43ab166709bc56054b1bd2b57bf8b91ad8934 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 6 Jul 2022 19:33:02 -0400 Subject: [PATCH 018/219] pick 3 routers for SSU2 peer test --- libi2pd/SSU2.cpp | 1 + libi2pd/SSU2Session.cpp | 6 ++++-- libi2pd/Transports.cpp | 30 ++++++++++++++++++++---------- 3 files changed, 25 insertions(+), 12 deletions(-) diff --git a/libi2pd/SSU2.cpp b/libi2pd/SSU2.cpp index beca55cd..a2125320 100644 --- a/libi2pd/SSU2.cpp +++ b/libi2pd/SSU2.cpp @@ -463,6 +463,7 @@ namespace transport bool isValidEndpoint = !address->host.is_unspecified () && address->port; if (isValidEndpoint) { + if (i2p::util::net::IsInReservedRange(address->host)) return false; auto s = FindPendingOutgoingSession (boost::asio::ip::udp::endpoint (address->host, address->port)); if (s) { diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index 305c8452..27bebac4 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -1712,8 +1712,10 @@ namespace transport } else { - LogPrint (eLogInfo, "SSU2: Peer test 4 error code ", (int)buf[1]); - SetRouterStatus (eRouterStatusUnknown); + LogPrint (eLogInfo, "SSU2: Peer test 4 error code ", (int)buf[1], " from ", + i2p::data::GetIdentHashAbbreviation (buf[1] < 64 ? GetRemoteIdentity ()->GetIdentHash () : i2p::data::IdentHash (buf + 3))); + if (GetRouterStatus () == eRouterStatusTesting) + SetRouterStatus (eRouterStatusUnknown); it->second.first->Terminate (); } m_PeerTests.erase (it); diff --git a/libi2pd/Transports.cpp b/libi2pd/Transports.cpp index 2d1af187..b76bbc30 100644 --- a/libi2pd/Transports.cpp +++ b/libi2pd/Transports.cpp @@ -665,11 +665,16 @@ namespace transport { excluded.clear (); excluded.insert (i2p::context.GetIdentHash ()); - auto router = i2p::data::netdb.GetRandomSSU2PeerTestRouter (true, excluded); // v4 - if (router) - { - i2p::context.SetStatusSSU2 (eRouterStatusTesting); - m_SSU2Server->StartPeerTest (router, true); + for (int i = 0; i < 3; i++) + { + auto router = i2p::data::netdb.GetRandomSSU2PeerTestRouter (true, excluded); // v4 + if (router) + { + if (i2p::context.GetStatus () != eRouterStatusTesting) + i2p::context.SetStatusSSU2 (eRouterStatusTesting); + m_SSU2Server->StartPeerTest (router, true); + excluded.insert (router->GetIdentHash ()); + } } } } @@ -708,11 +713,16 @@ namespace transport { excluded.clear (); excluded.insert (i2p::context.GetIdentHash ()); - auto router = i2p::data::netdb.GetRandomSSU2PeerTestRouter (false, excluded); // v6 - if (router) - { - i2p::context.SetStatusV6SSU2 (eRouterStatusTesting); - m_SSU2Server->StartPeerTest (router, false); + for (int i = 0; i < 3; i++) + { + auto router = i2p::data::netdb.GetRandomSSU2PeerTestRouter (false, excluded); // v6 + if (router) + { + if (i2p::context.GetStatusV6 () != eRouterStatusTesting) + i2p::context.SetStatusV6SSU2 (eRouterStatusTesting); + m_SSU2Server->StartPeerTest (router, false); + } + excluded.insert (router->GetIdentHash ()); } } } From fa9c17426462ab32c6257faa85b4a6ac0794be30 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 6 Jul 2022 21:28:53 -0400 Subject: [PATCH 019/219] handle first packet from Bob --- libi2pd/SSU2Session.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index 27bebac4..a7dbaace 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -1089,7 +1089,7 @@ namespace transport } m_LastActivityTimestamp = i2p::util::GetSecondsSinceEpoch (); m_NumReceivedBytes += len; - if (UpdateReceivePacketNum (packetNum)) + if (!packetNum || UpdateReceivePacketNum (packetNum)) HandlePayload (payload, payloadSize); } From fbb961b43c8ac9e31e50542a0f60f92b0e513df5 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 7 Jul 2022 13:23:51 -0400 Subject: [PATCH 020/219] extract correct endpoint from peer test msg 2 --- libi2pd/SSU2Session.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index a7dbaace..a47677fe 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -1596,7 +1596,7 @@ namespace transport { boost::asio::ip::udp::endpoint ep; std::shared_ptr addr; - if (ExtractEndpoint (buf + offset + 9, len - offset - 9, ep)) + if (ExtractEndpoint (buf + offset + 10, asz, ep)) addr = r->GetSSU2Address (ep.address ().is_v4 ()); if (addr && m_Server.IsSupported (ep.address ())) { From ca4414d15afe1be65997bbb99b3b73fb67214c71 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 8 Jul 2022 13:52:09 -0400 Subject: [PATCH 021/219] request relay tag if firewalled --- libi2pd/SSU2Session.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index a47677fe..7041aad9 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -406,6 +406,13 @@ namespace transport htobe16buf (payload + 1, 4); htobe32buf (payload + 3, ts); size_t payloadSize = 7; + if (GetRouterStatus () == eRouterStatusFirewalled) + { + // relay tag request + payload[payloadSize] = eSSU2BlkRelayTagRequest; + memset (payload + payloadSize + 1, 0, 2); // size = 0 + payloadSize += 3; + } payloadSize += CreatePaddingBlock (payload + payloadSize, 40 - payloadSize, 1); // KDF for session request m_NoiseState->MixHash ({ {header.buf, 16}, {headerX, 16} }); // h = SHA256(h || header) From 2f44d99a74566b49bf7ca4687d9967523ed09f8c Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 8 Jul 2022 19:06:09 -0400 Subject: [PATCH 022/219] session closing state --- libi2pd/SSU2.cpp | 27 +++++++++++++++------------ libi2pd/SSU2Session.cpp | 13 ++++++++----- libi2pd/SSU2Session.h | 3 ++- 3 files changed, 25 insertions(+), 18 deletions(-) diff --git a/libi2pd/SSU2.cpp b/libi2pd/SSU2.cpp index a2125320..209d3352 100644 --- a/libi2pd/SSU2.cpp +++ b/libi2pd/SSU2.cpp @@ -239,6 +239,8 @@ namespace transport auto ident = it->second->GetRemoteIdentity (); if (ident) m_SessionsByRouterHash.erase (ident->GetIdentHash ()); + if (m_LastSession == it->second) + m_LastSession = nullptr; m_Sessions.erase (it); } } @@ -385,6 +387,9 @@ namespace transport m_LastSession->SetRemoteEndpoint (senderEndpoint); m_LastSession->ProcessPeerTest (buf, len); break; + case eSSU2SessionStateClosing: + m_LastSession->RequestTermination (); // send termination again + break; case eSSU2SessionStateTerminated: m_LastSession = nullptr; break; @@ -617,22 +622,20 @@ namespace transport it++; } - for (auto it = m_Sessions.begin (); it != m_Sessions.end ();) + for (auto it: m_Sessions) { - if (it->second->GetState () == eSSU2SessionStateTerminated || - it->second->IsTerminationTimeoutExpired (ts)) + auto state = it.second->GetState (); + if (state == eSSU2SessionStateTerminated || state == eSSU2SessionStateClosing) + GetService ().post (std::bind (&SSU2Session::Terminate, it.second)); + else if (it.second->IsTerminationTimeoutExpired (ts)) { - if (it->second->IsEstablished ()) - it->second->TerminateByTimeout (); - if (it->second == m_LastSession) - m_LastSession = nullptr; - it = m_Sessions.erase (it); + if (it.second->IsEstablished ()) + it.second->RequestTermination (); + else + GetService ().post (std::bind (&SSU2Session::Terminate, it.second)); } else - { - it->second->CleanUp (ts); - it++; - } + it.second->CleanUp (ts); } for (auto it = m_IncomingTokens.begin (); it != m_IncomingTokens.end (); ) diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index 7041aad9..7ed1e5a7 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -168,12 +168,15 @@ namespace transport } } - void SSU2Session::TerminateByTimeout () + void SSU2Session::RequestTermination () { - SendTermination (); - m_Server.GetService ().post (std::bind (&SSU2Session::Terminate, shared_from_this ())); - } - + if (m_State == eSSU2SessionStateEstablished || m_State == eSSU2SessionStateClosing) + { + m_State = eSSU2SessionStateClosing; + SendTermination (); + } + } + void SSU2Session::Established () { m_State = eSSU2SessionStateEstablished; diff --git a/libi2pd/SSU2Session.h b/libi2pd/SSU2Session.h index f18f51f6..348cff56 100644 --- a/libi2pd/SSU2Session.h +++ b/libi2pd/SSU2Session.h @@ -86,6 +86,7 @@ namespace transport eSSU2SessionStateSessionCreatedSent, eSSU2SessionStateSessionConfirmedSent, eSSU2SessionStateEstablished, + eSSU2SessionStateClosing, eSSU2SessionStateTerminated, eSSU2SessionStateFailed, eSSU2SessionStateIntroduced, @@ -188,7 +189,7 @@ namespace transport void WaitForIntroduction (); void SendPeerTest (); // Alice, Data message void Terminate (); - void TerminateByTimeout (); + void RequestTermination (); void CleanUp (uint64_t ts); void FlushData (); void Done () override; From bb6227281abefd99080d2381778dc94b31ab7219 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 8 Jul 2022 21:31:44 -0400 Subject: [PATCH 023/219] teminate session after 5 unacked resends --- libi2pd/SSU2Session.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index 7ed1e5a7..d3fc2555 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -325,7 +325,13 @@ namespace transport if (ts >= it->second->nextResendTime) { if (it->second->numResends > SSU2_MAX_NUM_RESENDS) - it = m_SentPackets.erase (it); + { + LogPrint (eLogInfo, "SSU2: Packet was not Acked after ", it->second->numResends, " attempts. Terminate session"); + m_SentPackets.clear (); + m_SendQueue.clear (); + RequestTermination (); + return; + } else { uint32_t packetNum = SendData (it->second->payload, it->second->payloadSize); From 3ff3417ff24c2e997c75f246a2b4ead83c5fab9e Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 9 Jul 2022 17:05:23 -0400 Subject: [PATCH 024/219] send termiation with reason --- libi2pd/SSU2.cpp | 6 +++--- libi2pd/SSU2.h | 2 +- libi2pd/SSU2Session.cpp | 21 ++++++++++++++------- libi2pd/SSU2Session.h | 31 ++++++++++++++++++++++++++++++- 4 files changed, 48 insertions(+), 12 deletions(-) diff --git a/libi2pd/SSU2.cpp b/libi2pd/SSU2.cpp index 209d3352..f99c67b6 100644 --- a/libi2pd/SSU2.cpp +++ b/libi2pd/SSU2.cpp @@ -148,7 +148,7 @@ namespace transport void SSU2Server::Receive (boost::asio::ip::udp::socket& socket) { Packet * packet = m_PacketsPool.AcquireMt (); - socket.async_receive_from (boost::asio::buffer (packet->buf, SSU2_MTU), packet->from, + socket.async_receive_from (boost::asio::buffer (packet->buf, SSU2_MAX_PACKET_SIZE), packet->from, std::bind (&SSU2Server::HandleReceivedFrom, this, std::placeholders::_1, std::placeholders::_2, packet, std::ref (socket))); } @@ -388,7 +388,7 @@ namespace transport m_LastSession->ProcessPeerTest (buf, len); break; case eSSU2SessionStateClosing: - m_LastSession->RequestTermination (); // send termination again + m_LastSession->RequestTermination (eSSU2TerminationReasonIdleTimeout); // send termination again break; case eSSU2SessionStateTerminated: m_LastSession = nullptr; @@ -630,7 +630,7 @@ namespace transport else if (it.second->IsTerminationTimeoutExpired (ts)) { if (it.second->IsEstablished ()) - it.second->RequestTermination (); + it.second->RequestTermination (eSSU2TerminationReasonIdleTimeout); else GetService ().post (std::bind (&SSU2Session::Terminate, it.second)); } diff --git a/libi2pd/SSU2.h b/libi2pd/SSU2.h index 429cfdb7..99862947 100644 --- a/libi2pd/SSU2.h +++ b/libi2pd/SSU2.h @@ -25,7 +25,7 @@ namespace transport { struct Packet { - uint8_t buf[SSU2_MTU]; + uint8_t buf[SSU2_MAX_PACKET_SIZE]; size_t len; boost::asio::ip::udp::endpoint from; }; diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index d3fc2555..4e1d63ca 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -25,7 +25,7 @@ namespace transport m_DestConnID (0), m_SourceConnID (0), m_State (eSSU2SessionStateUnknown), m_SendPacketNum (0), m_ReceivePacketNum (0), m_IsDataReceived (false), m_WindowSize (SSU2_MAX_WINDOW_SIZE), m_RelayTag (0), - m_ConnectTimer (server.GetService ()) + m_ConnectTimer (server.GetService ()), m_TerminationReason (eSSU2TerminationReasonNormalClose) { m_NoiseState.reset (new i2p::crypto::NoiseSymmetricState); if (in_RemoteRouter && m_Address) @@ -168,11 +168,12 @@ namespace transport } } - void SSU2Session::RequestTermination () + void SSU2Session::RequestTermination (SSU2TerminationReason reason) { if (m_State == eSSU2SessionStateEstablished || m_State == eSSU2SessionStateClosing) { m_State = eSSU2SessionStateClosing; + m_TerminationReason = reason; SendTermination (); } } @@ -329,7 +330,7 @@ namespace transport LogPrint (eLogInfo, "SSU2: Packet was not Acked after ", it->second->numResends, " attempts. Terminate session"); m_SentPackets.clear (); m_SendQueue.clear (); - RequestTermination (); + RequestTermination (eSSU2TerminationReasonTimeout); return; } else @@ -2097,6 +2098,15 @@ namespace transport return CreatePeerTestBlock (buf, len, 1, eSSU2PeerTestCodeAccept, nullptr, signedData, 10 + asz + i2p::context.GetIdentity ()->GetSignatureLen ()); } + + size_t SSU2Session::CreateTerminationBlock (uint8_t * buf, size_t len) + { + buf[0] = eSSU2BlkTermination; + htobe16buf (buf + 1, 9); + htobe64buf (buf + 3, m_ReceivePacketNum); + buf[11] = (uint8_t)m_TerminationReason; + return 12; + } std::shared_ptr SSU2Session::ExtractRouterInfo (const uint8_t * buf, size_t size) { @@ -2157,10 +2167,7 @@ namespace transport void SSU2Session::SendTermination () { uint8_t payload[32]; - size_t payloadSize = 12; - payload[0] = eSSU2BlkTermination; - htobe16buf (payload + 1, 9); - memset (payload + 3, 0, 9); + size_t payloadSize = CreateTerminationBlock (payload, 32); payloadSize += CreatePaddingBlock (payload + payloadSize, 32 - payloadSize); SendData (payload, payloadSize); } diff --git a/libi2pd/SSU2Session.h b/libi2pd/SSU2Session.h index 348cff56..a287a6de 100644 --- a/libi2pd/SSU2Session.h +++ b/libi2pd/SSU2Session.h @@ -31,6 +31,7 @@ namespace transport const int SSU2_TOKEN_EXPIRATION_THRESHOLD = 2; // in seconds const int SSU2_RELAY_NONCE_EXPIRATION_TIMEOUT = 10; // in seconds const int SSU2_PEER_TEST_EXPIRATION_TIMEOUT = 60; // 60 seconds + const size_t SSU2_MAX_PACKET_SIZE = 1500; const size_t SSU2_MTU = 1440; // TODO: should be 1456 for ipv4 const size_t SSU2_MAX_PAYLOAD_SIZE = SSU2_MTU - 32; const int SSU2_HANDSHAKE_RESEND_INTERVAL = 1; // in seconds @@ -119,6 +120,32 @@ namespace transport eSSU2RelayResponseCodeCharlieSignatureFailure = 67, eSSU2RelayResponseCodeCharlieAliceIsUnknown = 70 }; + + enum SSU2TerminationReason + { + eSSU2TerminationReasonNormalClose = 0, + eSSU2TerminationReasonTerminationReceived = 1, + eSSU2TerminationReasonIdleTimeout = 2, + eSSU2TerminationReasonRouterShutdown = 3, + eSSU2TerminationReasonDataPhaseAEADFailure= 4, + eSSU2TerminationReasonIncompatibleOptions = 5, + eSSU2TerminationReasonTncompatibleSignatureType = 6, + eSSU2TerminationReasonClockSkew = 7, + eSSU2TerminationPaddingViolation = 8, + eSSU2TerminationReasonAEADFramingError = 9, + eSSU2TerminationReasonPayloadFormatError = 10, + eSSU2TerminationReasonSessionRequestError = 11, + eSSU2TerminationReasonSessionCreatedError = 12, + eSSU2TerminationReasonSessionConfirmedError = 13, + eSSU2TerminationReasonTimeout = 14, + eSSU2TerminationReasonRouterInfoSignatureVerificationFail = 15, + eSSU2TerminationReasonInvalidS = 16, + eSSU2TerminationReasonBanned = 17, + eSSU2TerminationReasonBadToken = 18, + eSSU2TerminationReasonConnectionLimits = 19, + eSSU2TerminationReasonIncompatibleVersion = 20, + eSSU2TerminationReasonWrongNetID = 21 + }; struct SSU2IncompleteMessage { @@ -189,7 +216,7 @@ namespace transport void WaitForIntroduction (); void SendPeerTest (); // Alice, Data message void Terminate (); - void RequestTermination (); + void RequestTermination (SSU2TerminationReason reason); void CleanUp (uint64_t ts); void FlushData (); void Done () override; @@ -264,6 +291,7 @@ namespace transport size_t CreateRelayResponseBlock (uint8_t * buf, size_t len, SSU2RelayResponseCode code, uint32_t nonce, bool endpoint, uint64_t token); // add endpoint for Chralie and no endpoint for Bob size_t CreatePeerTestBlock (uint8_t * buf, size_t len, uint8_t msg, SSU2PeerTestCode code, const uint8_t * routerHash, const uint8_t * signedData, size_t signedDataLen); size_t CreatePeerTestBlock (uint8_t * buf, size_t len, uint32_t nonce); // Alice + size_t CreateTerminationBlock (uint8_t * buf, size_t len); private: @@ -291,6 +319,7 @@ namespace transport uint32_t m_RelayTag; // between Bob and Charlie OnEstablished m_OnEstablished; // callback from Established boost::asio::deadline_timer m_ConnectTimer; + SSU2TerminationReason m_TerminationReason; }; inline uint64_t CreateHeaderMask (const uint8_t * kh, const uint8_t * nonce) From fdebbc4498948435075d427abfa99b18baf7c8c0 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 10 Jul 2022 17:13:25 -0400 Subject: [PATCH 025/219] select sessions for introducers --- libi2pd/SSU2.cpp | 61 ++++++++++++++++++++++++++++++++++++++++- libi2pd/SSU2.h | 11 ++++++-- libi2pd/SSU2Session.cpp | 12 +++++++- libi2pd/SSU2Session.h | 1 + 4 files changed, 81 insertions(+), 4 deletions(-) diff --git a/libi2pd/SSU2.cpp b/libi2pd/SSU2.cpp index f99c67b6..b48274c4 100644 --- a/libi2pd/SSU2.cpp +++ b/libi2pd/SSU2.cpp @@ -84,11 +84,17 @@ namespace transport void SSU2Server::Stop () { for (auto& it: m_Sessions) + { + it.second->RequestTermination (eSSU2TerminationReasonRouterShutdown); it.second->Done (); + } m_Sessions.clear (); m_SessionsByRouterHash.clear (); m_PendingOutgoingSessions.clear (); - + m_Relays.clear (); + m_Introducers.clear (); + m_IntroducersV6.clear (); + if (context.SupportsV4 () || context.SupportsV6 ()) m_ReceiveService.Stop (); @@ -715,5 +721,58 @@ namespace transport m_IncomingTokens.emplace (ep, ret); return ret; } + + std::list > SSU2Server::FindIntroducers (int maxNumIntroducers, + bool v4, const std::set& excluded) const + { + std::list > ret; + for (const auto& s : m_Sessions) + { + if (s.second->IsEstablished () && (s.second->GetRelayTag () && !s.second->IsOutgoing ()) && + !excluded.count (s.second->GetRemoteIdentity ()->GetIdentHash ()) && + ((v4 && (s.second->GetRemoteTransports () | i2p::data::RouterInfo::eSSU2V4)) || + (!v4 && (s.second->GetRemoteTransports () | i2p::data::RouterInfo::eSSU2V6)))) + ret.push_back (s.second); + } + if ((int)ret.size () > maxNumIntroducers) + { + // 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; + } + + void SSU2Server::UpdateIntroducers (bool v4) + { + std::list> newList; + auto& introducers = v4 ? m_Introducers : m_IntroducersV6; + for (const auto& it : introducers) + { + if (it->IsEstablished ()) + { + it->SendKeepAlive (); + newList.push_back (it); + } + } + if (newList.size () < SSU2_MAX_NUM_INTRODUCERS) + { + std::set excluded; + for (auto& it1: newList) + excluded.insert (it1->GetRemoteIdentity ()->GetIdentHash ()); + auto sessions = FindIntroducers (SSU_MAX_NUM_INTRODUCERS - newList.size (), v4, excluded); + for (const auto& it : sessions) + { + newList.push_back (it); + } + } + introducers = newList; + } } } diff --git a/libi2pd/SSU2.h b/libi2pd/SSU2.h index 99862947..b9d59d68 100644 --- a/libi2pd/SSU2.h +++ b/libi2pd/SSU2.h @@ -20,6 +20,9 @@ namespace transport const int SSU2_TERMINATION_CHECK_TIMEOUT = 30; // 30 seconds const size_t SSU2_SOCKET_RECEIVE_BUFFER_SIZE = 0x1FFFF; // 128K const size_t SSU2_SOCKET_SEND_BUFFER_SIZE = 0x1FFFF; // 128K + const size_t SSU2_MAX_NUM_INTRODUCERS = 3; + const int SSU2_TO_INTRODUCER_SESSION_DURATION = 3600; // 1 hour + const int SSU2_TO_INTRODUCER_SESSION_EXPIRATION = 4800; // 80 minutes class SSU2Server: private i2p::util::RunnableServiceWithWork { @@ -97,7 +100,10 @@ namespace transport void HandleResendTimer (const boost::system::error_code& ecode); void ConnectThroughIntroducer (std::shared_ptr session); - + std::list > FindIntroducers (int maxNumIntroducers, + bool v4, const std::set& excluded) const; + void UpdateIntroducers (bool v4); + private: ReceiveService m_ReceiveService; @@ -108,10 +114,11 @@ namespace transport std::map > m_PendingOutgoingSessions; std::map > m_IncomingTokens, m_OutgoingTokens; // remote endpoint -> (token, expires in seconds) std::map > m_Relays; // we are introducer, relay tag -> session + std::list > m_Introducers, m_IntroducersV6; // introducers we are connected to i2p::util::MemoryPoolMt m_PacketsPool; boost::asio::deadline_timer m_TerminationTimer, m_ResendTimer; std::shared_ptr m_LastSession; - + public: // for HTTP/I2PControl diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index 4e1d63ca..aaa7ebff 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -150,6 +150,16 @@ namespace transport payloadSize += CreatePaddingBlock (payload + payloadSize, SSU2_MAX_PAYLOAD_SIZE - payloadSize); SendData (payload, payloadSize); } + + void SSU2Session::SendKeepAlive () + { + if (IsEstablished ()) + { + uint8_t payload[20]; + size_t payloadSize = CreatePaddingBlock (payload, 20, 5); + SendData (payload, payloadSize); + } + } void SSU2Session::Terminate () { @@ -416,7 +426,7 @@ namespace transport htobe16buf (payload + 1, 4); htobe32buf (payload + 3, ts); size_t payloadSize = 7; - if (GetRouterStatus () == eRouterStatusFirewalled) + if (GetRouterStatus () == eRouterStatusFirewalled && m_Address->IsIntroducer ()) { // relay tag request payload[payloadSize] = eSSU2BlkRelayTagRequest; diff --git a/libi2pd/SSU2Session.h b/libi2pd/SSU2Session.h index a287a6de..f5964b8f 100644 --- a/libi2pd/SSU2Session.h +++ b/libi2pd/SSU2Session.h @@ -215,6 +215,7 @@ namespace transport bool Introduce (std::shared_ptr session, uint32_t relayTag); void WaitForIntroduction (); void SendPeerTest (); // Alice, Data message + void SendKeepAlive (); void Terminate (); void RequestTermination (SSU2TerminationReason reason); void CleanUp (uint64_t ts); From 8b649aaaf886ea546b687a1789260a54ba80ece9 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 10 Jul 2022 18:50:02 -0400 Subject: [PATCH 026/219] NACKs and Acks only Ack ranges --- libi2pd/SSU2Session.cpp | 42 ++++++++++++++++++++++++++++------------- 1 file changed, 29 insertions(+), 13 deletions(-) diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index aaa7ebff..9853d897 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -1917,22 +1917,38 @@ namespace transport uint32_t lastNum = ackThrough - acnt; while (it != m_OutOfSequencePackets.rend () && numRanges < SSU2_MAX_NUM_ACK_RANGES) { - if (lastNum - (*it) < 255) - { - buf[8 + numRanges*2] = lastNum - (*it) - 1; // NACKs - lastNum = *it; it++; - uint8_t numAcks = 1; - while (it != m_OutOfSequencePackets.rend () && numAcks < 255 && lastNum > 0 && *it == lastNum - 1) + if (lastNum - (*it) > 255) + { + // NACKs only ranges + if (lastNum > (*it) + 255*(SSU2_MAX_NUM_ACK_RANGES - numRanges)) break; // too many NACKs + while (lastNum - (*it) > 255) { - numAcks++; lastNum--; - it++; + buf[8 + numRanges*2] = 255; buf[8 + numRanges*2 + 1] = 0; // NACKs 255, Acks 0 + lastNum -= 255; + numRanges++; } - buf[8 + numRanges*2 + 1] = numAcks; // Acks - numRanges++; - if (numAcks == 255) break; + } + // NACKs and Acks ranges + buf[8 + numRanges*2] = lastNum - (*it) - 1; // NACKs + lastNum = *it; it++; + int numAcks = 1; + while (it != m_OutOfSequencePackets.rend () && lastNum > 0 && *it == lastNum - 1) + { + numAcks++; lastNum--; + it++; } - else - break; + while (numAcks > 255) + { + // Acks only ranges + buf[8 + numRanges*2 + 1] = 255; // Acks 255 + numAcks -= 255; + numRanges++; + buf[8 + numRanges*2] = 0; // NACKs 0 + if (numRanges >= SSU2_MAX_NUM_ACK_RANGES) break; + } + if (numAcks > 255) numAcks = 255; + buf[8 + numRanges*2 + 1] = (uint8_t)numAcks; // Acks + numRanges++; } if (numRanges < SSU2_MAX_NUM_ACK_RANGES && it == m_OutOfSequencePackets.rend ()) { From 3cf809e99d05918c87e52c321848f96ecd093fc1 Mon Sep 17 00:00:00 2001 From: Simon Vetter Date: Mon, 11 Jul 2022 08:16:07 +0000 Subject: [PATCH 027/219] fix SSU2 introducers selection logic --- libi2pd/SSU2.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libi2pd/SSU2.cpp b/libi2pd/SSU2.cpp index b48274c4..1c142db1 100644 --- a/libi2pd/SSU2.cpp +++ b/libi2pd/SSU2.cpp @@ -730,8 +730,8 @@ namespace transport { if (s.second->IsEstablished () && (s.second->GetRelayTag () && !s.second->IsOutgoing ()) && !excluded.count (s.second->GetRemoteIdentity ()->GetIdentHash ()) && - ((v4 && (s.second->GetRemoteTransports () | i2p::data::RouterInfo::eSSU2V4)) || - (!v4 && (s.second->GetRemoteTransports () | i2p::data::RouterInfo::eSSU2V6)))) + ((v4 && (s.second->GetRemoteTransports () & i2p::data::RouterInfo::eSSU2V4)) || + (!v4 && (s.second->GetRemoteTransports () & i2p::data::RouterInfo::eSSU2V6)))) ret.push_back (s.second); } if ((int)ret.size () > maxNumIntroducers) From c50e453af6d60d2cafe36ced1b49f388b8529c59 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 11 Jul 2022 18:16:05 -0400 Subject: [PATCH 028/219] check out of sequence messages range --- libi2pd/SSU2Session.cpp | 39 ++++++++++++++++++++++----------------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index 9853d897..2715b621 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -1174,7 +1174,7 @@ namespace transport m_IsDataReceived = true; break; case eSSU2BlkTermination: - LogPrint (eLogDebug, "SSU2: Termination"); + LogPrint (eLogDebug, "SSU2: Termination reason=", (int)buf[11]); Terminate (); break; case eSSU2BlkRelayRequest: @@ -2210,23 +2210,28 @@ namespace transport else ++it; } - if (m_OutOfSequencePackets.size () > 255) - { - m_ReceivePacketNum = *m_OutOfSequencePackets.rbegin (); - m_OutOfSequencePackets.clear (); - } - else if (m_OutOfSequencePackets.size () > SSU2_MAX_NUM_ACK_RANGES) - { - uint32_t packet = *m_OutOfSequencePackets.begin (); - if (packet > m_ReceivePacketNum + 1) + if (!m_OutOfSequencePackets.empty ()) + { + if (m_OutOfSequencePackets.size () > 2*SSU2_MAX_NUM_ACK_RANGES || + *m_OutOfSequencePackets.rbegin () > m_ReceivePacketNum + 255*8) { - // like we've just received all packets before first - packet--; - m_ReceivePacketNum = packet - 1; - UpdateReceivePacketNum (packet); - } - else - LogPrint (eLogError, "SSU2: Out of sequence packet ", packet, " is less than last received ", m_ReceivePacketNum); + uint32_t packet = *m_OutOfSequencePackets.begin (); + if (packet > m_ReceivePacketNum + 1) + { + // like we've just received all packets before first + packet--; + m_ReceivePacketNum = packet - 1; + UpdateReceivePacketNum (packet); + } + else + LogPrint (eLogError, "SSU2: Out of sequence packet ", packet, " is less than last received ", m_ReceivePacketNum); + } + if (m_OutOfSequencePackets.size () > 255*4) + { + // seems we have a serious network issue + m_ReceivePacketNum = *m_OutOfSequencePackets.rbegin (); + m_OutOfSequencePackets.clear (); + } } for (auto it = m_RelaySessions.begin (); it != m_RelaySessions.end ();) From b0d962b49ac28ced6c780d78bc794dd56fab0114 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 11 Jul 2022 19:00:23 -0400 Subject: [PATCH 029/219] send ack for retransmitted SessionConfirmed --- libi2pd/SSU2Session.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index 2715b621..dffa8550 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -668,7 +668,7 @@ namespace transport header.ll[1] ^= CreateHeaderMask (kh2, buf + (len - 12)); if (header.h.type != eSSU2SessionConfirmed) { - LogPrint (eLogWarning, "SSU2: Unexpected message type ", (int)header.h.type); + LogPrint (eLogWarning, "SSU2: Unexpected message type ", (int)header.h.type, " instead ", (int)eSSU2SessionConfirmed); return false; } // check if fragmented @@ -886,7 +886,7 @@ namespace transport header.ll[1] ^= CreateHeaderMask (m_Address->i, buf + (len - 12)); if (header.h.type != eSSU2Retry) { - LogPrint (eLogWarning, "SSU2: Unexpected message type ", (int)header.h.type); + LogPrint (eLogWarning, "SSU2: Unexpected message type ", (int)header.h.type, " instead ", (int)eSSU2Retry); return false; } uint8_t nonce[12] = {0}; @@ -962,7 +962,7 @@ namespace transport header.ll[1] ^= CreateHeaderMask (i2p::context.GetSSU2IntroKey (), buf + (len - 12)); if (header.h.type != eSSU2HolePunch) { - LogPrint (eLogWarning, "SSU2: Unexpected message type ", (int)header.h.type); + LogPrint (eLogWarning, "SSU2: Unexpected message type ", (int)header.h.type, " instead ", (int)eSSU2HolePunch); return false; } uint8_t nonce[12] = {0}; @@ -1044,7 +1044,7 @@ namespace transport header.ll[1] ^= CreateHeaderMask (i2p::context.GetSSU2IntroKey (), buf + (len - 12)); if (header.h.type != eSSU2PeerTest) { - LogPrint (eLogWarning, "SSU2: Unexpected message type ", (int)header.h.type); + LogPrint (eLogWarning, "SSU2: Unexpected message type ", (int)header.h.type, " instead ", (int)eSSU2PeerTest); return false; } uint8_t nonce[12] = {0}; @@ -1100,7 +1100,8 @@ namespace transport header.ll[1] ^= CreateHeaderMask (m_KeyDataReceive + 32, buf + (len - 12)); if (header.h.type != eSSU2Data) { - LogPrint (eLogWarning, "SSU2: Unexpected message type ", (int)header.h.type); + LogPrint (eLogWarning, "SSU2: Unexpected message type ", (int)header.h.type, " instead ", (int)eSSU2Data); + SendQuickAck (); // in case it was SessionConfirmed return; } uint8_t payload[SSU2_MTU]; From f1d3d6a7b598a63c25798f0d238be0186591c874 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 12 Jul 2022 10:50:21 -0400 Subject: [PATCH 030/219] set max compression for SessionConfirmed --- libi2pd/SSU2Session.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index dffa8550..367663da 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -1885,6 +1885,7 @@ namespace transport else { i2p::data::GzipDeflator deflator; + deflator.SetCompressionLevel (9); size = deflator.Deflate (r->GetBuffer (), r->GetBufferLen (), buf + 5, len - 5); if (!size) return 0; // doesn't fit buf[3] = SSU2_ROUTER_INFO_FLAG_GZIP; // flag From 0c34189d9454e4bc27a113e2172bf18d89dbc055 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 12 Jul 2022 12:17:58 -0400 Subject: [PATCH 031/219] correct buffer size for fragments of SessionConfirmed --- libi2pd/SSU2.cpp | 6 +++++- libi2pd/SSU2Session.cpp | 22 ++++++++++++---------- libi2pd/SSU2Session.h | 5 ++++- 3 files changed, 21 insertions(+), 12 deletions(-) diff --git a/libi2pd/SSU2.cpp b/libi2pd/SSU2.cpp index 1c142db1..c1eb09f3 100644 --- a/libi2pd/SSU2.cpp +++ b/libi2pd/SSU2.cpp @@ -374,7 +374,11 @@ namespace transport m_LastSession->ProcessData (buf, len); break; case eSSU2SessionStateSessionCreatedSent: - m_LastSession->ProcessSessionConfirmed (buf, len); + if (!m_LastSession->ProcessSessionConfirmed (buf, len)) + { + m_LastSession->Terminate (); + m_LastSession = nullptr; + } break; case eSSU2SessionStateIntroduced: if (m_LastSession->GetRemoteEndpoint ().address ().is_unspecified ()) diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index 367663da..d081e957 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -325,7 +325,6 @@ namespace transport LogPrint (eLogDebug, "SSU2: Resending ", (int)m_State); m_Server.Send (m_SentHandshakePacket->header.buf, 16, m_SentHandshakePacket->headerX, 48, m_SentHandshakePacket->payload, m_SentHandshakePacket->payloadSize, m_RemoteEndpoint); - m_SentHandshakePacket->numResends++; m_SentHandshakePacket->nextResendTime = ts + SSU2_HANDSHAKE_RESEND_INTERVAL; return; } @@ -678,22 +677,24 @@ namespace transport if (!(header.h.flags[0] & 0xF0)) { // first fragment - m_SessionConfirmedFragment1.reset (new HandshakePacket); - m_SessionConfirmedFragment1->header = header; - memcpy (m_SessionConfirmedFragment1->payload, buf + 16, len - 16); - m_SessionConfirmedFragment1->payloadSize = len - 16; + if (!m_SessionConfirmedFragment1) + { + m_SessionConfirmedFragment1.reset (new HandshakePacket); + m_SessionConfirmedFragment1->header = header; + memcpy (m_SessionConfirmedFragment1->payload, buf + 16, len - 16); + m_SessionConfirmedFragment1->payloadSize = len - 16; + } return true; // wait for second fragment } else { // second fragment if (!m_SessionConfirmedFragment1) return false; // out of sequence - uint8_t fullMsg[2*SSU2_MTU]; header = m_SessionConfirmedFragment1->header; - memcpy (fullMsg + 16, m_SessionConfirmedFragment1->payload, m_SessionConfirmedFragment1->payloadSize); - memcpy (fullMsg + 16 + m_SessionConfirmedFragment1->payloadSize, buf + 16, len - 16); - buf = fullMsg; - len += m_SessionConfirmedFragment1->payloadSize; + memcpy (m_SessionConfirmedFragment1->payload + m_SessionConfirmedFragment1->payloadSize, buf + 16, len - 16); + m_SessionConfirmedFragment1->payloadSize += (len - 16); + buf = m_SessionConfirmedFragment1->payload - 16; + len = m_SessionConfirmedFragment1->payloadSize + 16; } } // KDF for Session Confirmed part 1 @@ -724,6 +725,7 @@ namespace transport return false; } m_NoiseState->MixHash (payload, len - 64); // h = SHA256(h || ciphertext); + if (m_SessionConfirmedFragment1) m_SessionConfirmedFragment1.reset (nullptr); // payload // handle RouterInfo block that must be first if (decryptedPayload[0] != eSSU2BlkRouterInfo) diff --git a/libi2pd/SSU2Session.h b/libi2pd/SSU2Session.h index f5964b8f..e9adfe8e 100644 --- a/libi2pd/SSU2Session.h +++ b/libi2pd/SSU2Session.h @@ -190,10 +190,13 @@ namespace transport int numResends = 0; }; - struct HandshakePacket: public SentPacket + struct HandshakePacket { Header header; uint8_t headerX[48]; // part1 for SessionConfirmed + uint8_t payload[SSU2_MAX_PACKET_SIZE*2]; + size_t payloadSize = 0; + uint32_t nextResendTime = 0; // in seconds }; typedef std::function OnEstablished; From 90981f628e14822d1452c77f3c49da7c7ef0335d Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 12 Jul 2022 19:04:03 -0400 Subject: [PATCH 032/219] Send fragmented SessionConfirmed --- libi2pd/SSU2Session.cpp | 70 +++++++++++++++++++++++++++++++---------- libi2pd/SSU2Session.h | 4 +-- 2 files changed, 56 insertions(+), 18 deletions(-) diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index d081e957..51ff30a4 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -193,7 +193,7 @@ namespace transport m_State = eSSU2SessionStateEstablished; m_EphemeralKeys = nullptr; m_NoiseState.reset (nullptr); - m_SessionConfirmedFragment1.reset (nullptr); + m_SessionConfirmedFragment.reset (nullptr); m_SentHandshakePacket.reset (nullptr); m_ConnectTimer.cancel (); SetTerminationTimeout (SSU2_TERMINATION_TIMEOUT); @@ -326,6 +326,10 @@ namespace transport m_Server.Send (m_SentHandshakePacket->header.buf, 16, m_SentHandshakePacket->headerX, 48, m_SentHandshakePacket->payload, m_SentHandshakePacket->payloadSize, m_RemoteEndpoint); m_SentHandshakePacket->nextResendTime = ts + SSU2_HANDSHAKE_RESEND_INTERVAL; + if (m_SessionConfirmedFragment && m_State == eSSU2SessionStateSessionConfirmedSent) + // resend second fragment of SessionConfirmed + m_Server.Send (m_SessionConfirmedFragment->header.buf, 16, + m_SessionConfirmedFragment->payload, m_SessionConfirmedFragment->payloadSize, m_RemoteEndpoint); return; } // resend data packets @@ -623,10 +627,17 @@ namespace transport memset (header.h.flags, 0, 3); header.h.flags[0] = 1; // frag, total fragments always 1 // payload - const size_t maxPayloadSize = SSU2_MAX_PAYLOAD_SIZE - 48; // part 2 + size_t maxPayloadSize = SSU2_MAX_PAYLOAD_SIZE - 64; // part 2 uint8_t * payload = m_SentHandshakePacket->payload; size_t payloadSize = CreateRouterInfoBlock (payload, maxPayloadSize, i2p::context.GetSharedRouterInfo ()); - // TODO: check is RouterInfo doesn't fit and split by two fragments + if (!payloadSize) + { + // split by two fragments + maxPayloadSize += SSU2_MAX_PAYLOAD_SIZE; + payloadSize = CreateRouterInfoBlock (payload, maxPayloadSize, i2p::context.GetSharedRouterInfo ()); + header.h.flags[0] = 0x02; // frag 0, total fragments 2 + // TODO: check if we need more fragments + } if (payloadSize < maxPayloadSize) payloadSize += CreatePaddingBlock (payload + payloadSize, maxPayloadSize - payloadSize); // KDF for Session Confirmed part 1 @@ -646,14 +657,42 @@ namespace transport i2p::crypto::AEADChaCha20Poly1305 (payload, payloadSize, m_NoiseState->m_H, 32, m_NoiseState->m_CK + 32, nonce, payload, payloadSize + 16, true); payloadSize += 16; m_NoiseState->MixHash (payload, payloadSize); // h = SHA256(h || ciphertext); + m_SentHandshakePacket->payloadSize = payloadSize; + if (header.h.flags[0] > 1) + { + if (payloadSize > SSU2_MAX_PAYLOAD_SIZE - 64) + { + payloadSize = SSU2_MAX_PAYLOAD_SIZE - 64 - (rand () % 16); + if (m_SentHandshakePacket->payloadSize - payloadSize < 24) + payloadSize -= 24; + } + else + header.h.flags[0] = 1; + } // Encrypt header header.ll[0] ^= CreateHeaderMask (m_Address->i, payload + (payloadSize - 24)); header.ll[1] ^= CreateHeaderMask (kh2, payload + (payloadSize - 12)); m_State = eSSU2SessionStateSessionConfirmedSent; - m_SentHandshakePacket->payloadSize = payloadSize; // send m_Server.Send (header.buf, 16, part1, 48, payload, payloadSize, m_RemoteEndpoint); m_SendPacketNum++; + if (m_SentHandshakePacket->payloadSize > payloadSize) + { + // send second fragment + m_SessionConfirmedFragment.reset (new HandshakePacket); + Header& header = m_SessionConfirmedFragment->header; + header.h.connID = m_DestConnID; // dest id + header.h.packetNum = 0; + header.h.type = eSSU2SessionConfirmed; + memset (header.h.flags, 0, 3); + header.h.flags[0] = 0x12; // frag 1, total fragments 2 + m_SessionConfirmedFragment->payloadSize = m_SentHandshakePacket->payloadSize - payloadSize; + memcpy (m_SessionConfirmedFragment->payload, m_SentHandshakePacket->payload + payloadSize, m_SessionConfirmedFragment->payloadSize); + m_SentHandshakePacket->payloadSize = payloadSize; + header.ll[0] ^= CreateHeaderMask (m_Address->i, m_SessionConfirmedFragment->payload + (m_SessionConfirmedFragment->payloadSize - 24)); + header.ll[1] ^= CreateHeaderMask (kh2, m_SessionConfirmedFragment->payload + (m_SessionConfirmedFragment->payloadSize - 12)); + m_Server.Send (header.buf, 16, m_SessionConfirmedFragment->payload, m_SessionConfirmedFragment->payloadSize, m_RemoteEndpoint); + } } bool SSU2Session::ProcessSessionConfirmed (uint8_t * buf, size_t len) @@ -677,24 +716,24 @@ namespace transport if (!(header.h.flags[0] & 0xF0)) { // first fragment - if (!m_SessionConfirmedFragment1) + if (!m_SessionConfirmedFragment) { - m_SessionConfirmedFragment1.reset (new HandshakePacket); - m_SessionConfirmedFragment1->header = header; - memcpy (m_SessionConfirmedFragment1->payload, buf + 16, len - 16); - m_SessionConfirmedFragment1->payloadSize = len - 16; + m_SessionConfirmedFragment.reset (new HandshakePacket); + m_SessionConfirmedFragment->header = header; + memcpy (m_SessionConfirmedFragment->payload, buf + 16, len - 16); + m_SessionConfirmedFragment->payloadSize = len - 16; } return true; // wait for second fragment } else { // second fragment - if (!m_SessionConfirmedFragment1) return false; // out of sequence - header = m_SessionConfirmedFragment1->header; - memcpy (m_SessionConfirmedFragment1->payload + m_SessionConfirmedFragment1->payloadSize, buf + 16, len - 16); - m_SessionConfirmedFragment1->payloadSize += (len - 16); - buf = m_SessionConfirmedFragment1->payload - 16; - len = m_SessionConfirmedFragment1->payloadSize + 16; + if (!m_SessionConfirmedFragment) return false; // out of sequence + header = m_SessionConfirmedFragment->header; + memcpy (m_SessionConfirmedFragment->payload + m_SessionConfirmedFragment->payloadSize, buf + 16, len - 16); + m_SessionConfirmedFragment->payloadSize += (len - 16); + buf = m_SessionConfirmedFragment->payload - 16; + len = m_SessionConfirmedFragment->payloadSize + 16; } } // KDF for Session Confirmed part 1 @@ -725,7 +764,6 @@ namespace transport return false; } m_NoiseState->MixHash (payload, len - 64); // h = SHA256(h || ciphertext); - if (m_SessionConfirmedFragment1) m_SessionConfirmedFragment1.reset (nullptr); // payload // handle RouterInfo block that must be first if (decryptedPayload[0] != eSSU2BlkRouterInfo) diff --git a/libi2pd/SSU2Session.h b/libi2pd/SSU2Session.h index e9adfe8e..a8e0309c 100644 --- a/libi2pd/SSU2Session.h +++ b/libi2pd/SSU2Session.h @@ -302,8 +302,8 @@ namespace transport SSU2Server& m_Server; std::shared_ptr m_EphemeralKeys; std::unique_ptr m_NoiseState; - std::unique_ptr m_SessionConfirmedFragment1; // for Bob if applicable - std::unique_ptr m_SentHandshakePacket; // SessionRequest or SessionCreated + std::unique_ptr m_SessionConfirmedFragment; // for Bob if applicable or second fragment for Alice + std::unique_ptr m_SentHandshakePacket; // SessionRequest, SessionCreated or SessionConfirmed std::shared_ptr m_Address; boost::asio::ip::udp::endpoint m_RemoteEndpoint; i2p::data::RouterInfo::CompatibleTransports m_RemoteTransports; // for peer tests From 5c62726992a7252997ce31faaad57c4a15ca5446 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 13 Jul 2022 12:45:20 -0400 Subject: [PATCH 033/219] check clock skew and terminate --- libi2pd/SSU2Session.cpp | 18 ++++++++++++++++-- libi2pd/SSU2Session.h | 2 ++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index 51ff30a4..41d1b264 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -497,6 +497,7 @@ namespace transport } m_NoiseState->MixHash (payload, len - 64); // h = SHA256(h || encrypted payload from Session Request) for SessionCreated // payload + m_State = eSSU2SessionStateSessionRequestReceived; HandlePayload (decryptedPayload.data (), decryptedPayload.size ()); m_Server.AddSession (shared_from_this ()); @@ -527,11 +528,12 @@ namespace transport memset (headerX + 8, 0, 8); // token = 0 memcpy (headerX + 16, m_EphemeralKeys->GetPublicKey (), 32); // Y // payload + const size_t maxPayloadSize = SSU2_MAX_PAYLOAD_SIZE - 48; payload[0] = eSSU2BlkDateTime; htobe16buf (payload + 1, 4); htobe32buf (payload + 3, ts); size_t payloadSize = 7; - payloadSize += CreateAddressBlock (payload + payloadSize, 80 - payloadSize, m_RemoteEndpoint); + payloadSize += CreateAddressBlock (payload + payloadSize, maxPayloadSize - payloadSize, m_RemoteEndpoint); if (m_RelayTag) { payload[payloadSize] = eSSU2BlkRelayTag; @@ -548,7 +550,9 @@ namespace transport memcpy (payload + payloadSize + 7, &token.first, 8); // token payloadSize += 15; } - payloadSize += CreatePaddingBlock (payload + payloadSize, 80 - payloadSize); + if (m_TerminationReason != eSSU2TerminationReasonNormalClose) + payloadSize += CreateTerminationBlock (payload + payloadSize, maxPayloadSize - payloadSize); + payloadSize += CreatePaddingBlock (payload + payloadSize, maxPayloadSize - payloadSize); // KDF for SessionCreated m_NoiseState->MixHash ( { {header.buf, 16}, {headerX, 16} } ); // h = SHA256(h || header) m_NoiseState->MixHash (headerX + 16, 32); // h = SHA256(h || bepk); @@ -567,6 +571,9 @@ namespace transport m_SentHandshakePacket->payloadSize = payloadSize; // send m_Server.Send (header.buf, 16, headerX, 48, payload, payloadSize, m_RemoteEndpoint); + // terminate if errors + if (m_TerminationReason != eSSU2TerminationReasonNormalClose) + Terminate (); } bool SSU2Session::ProcessSessionCreated (uint8_t * buf, size_t len) @@ -1180,6 +1187,13 @@ namespace transport { case eSSU2BlkDateTime: LogPrint (eLogDebug, "SSU2: Datetime"); + if (m_State == eSSU2SessionStateSessionRequestReceived) + { + auto ts = i2p::util::GetSecondsSinceEpoch (); + uint32_t signedOnTime = bufbe32toh (buf + offset); + if (signedOnTime < ts - SSU2_CLOCK_SKEW || signedOnTime > ts + SSU2_CLOCK_SKEW) + m_TerminationReason = eSSU2TerminationReasonClockSkew; + }; break; case eSSU2BlkOptions: LogPrint (eLogDebug, "SSU2: Options"); diff --git a/libi2pd/SSU2Session.h b/libi2pd/SSU2Session.h index a8e0309c..7a6a4a5c 100644 --- a/libi2pd/SSU2Session.h +++ b/libi2pd/SSU2Session.h @@ -26,6 +26,7 @@ namespace transport { const int SSU2_CONNECT_TIMEOUT = 5; // 5 seconds const int SSU2_TERMINATION_TIMEOUT = 330; // 5.5 minutes + const int SSU2_CLOCK_SKEW = 60; // in seconds const int SSU2_TOKEN_EXPIRATION_TIMEOUT = 9; // for Retry message, in seconds const int SSU2_NEXT_TOKEN_EXPIRATION_TIMEOUT = 52*60; // for next token block, in seconds const int SSU2_TOKEN_EXPIRATION_THRESHOLD = 2; // in seconds @@ -84,6 +85,7 @@ namespace transport eSSU2SessionStateUnknown, eSSU2SessionStateTokenReceived, eSSU2SessionStateSessionRequestSent, + eSSU2SessionStateSessionRequestReceived, eSSU2SessionStateSessionCreatedSent, eSSU2SessionStateSessionConfirmedSent, eSSU2SessionStateEstablished, From 1dd2bd00139f09eb3f4d186c1998daaa35d75468 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 13 Jul 2022 15:52:19 -0400 Subject: [PATCH 034/219] publish MTU for ipv6 SSU2 address. Max MTU of 1488 for SSU1 --- libi2pd/RouterContext.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index b401b8c6..de845b3b 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -421,16 +421,18 @@ namespace i2p !i2p::util::net::IsYggdrasilAddress (address->host)) { address->host = host; - if (host.is_v6 () && address->transportStyle == i2p::data::RouterInfo::eTransportSSU) + if (host.is_v6 () && (address->transportStyle == i2p::data::RouterInfo::eTransportSSU || address->IsSSU2 ())) { // update MTU auto mtu = i2p::util::net::GetMTU (host); if (mtu) { LogPrint (eLogDebug, "Router: Our v6 MTU=", mtu); - if (mtu > 1472) { // TODO: magic constant - mtu = 1472; - LogPrint(eLogWarning, "Router: MTU dropped to upper limit of 1472 bytes"); + int maxMTU = address->IsSSU2 () ? 1500 : 1488; // must be multiple of 16 for SSU1 + if (mtu > maxMTU) + { + mtu = maxMTU; + LogPrint(eLogWarning, "Router: MTU dropped to upper limit of ", maxMTU, " bytes"); } if (address->ssu) address->ssu->mtu = mtu; } From 3394bb4b8d36eafd67c788c95def6f9f832f6123 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 13 Jul 2022 19:35:18 -0400 Subject: [PATCH 035/219] calculate SSU2 session MTU and max payload size --- libi2pd/SSU2Session.cpp | 155 +++++++++++++++++++++---------------- libi2pd/SSU2Session.h | 6 +- libi2pd/SSUData.h | 5 +- libi2pd/TransportSession.h | 6 +- 4 files changed, 97 insertions(+), 75 deletions(-) diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index 41d1b264..64b39b6f 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -25,7 +25,8 @@ namespace transport m_DestConnID (0), m_SourceConnID (0), m_State (eSSU2SessionStateUnknown), m_SendPacketNum (0), m_ReceivePacketNum (0), m_IsDataReceived (false), m_WindowSize (SSU2_MAX_WINDOW_SIZE), m_RelayTag (0), - m_ConnectTimer (server.GetService ()), m_TerminationReason (eSSU2TerminationReasonNormalClose) + m_ConnectTimer (server.GetService ()), m_TerminationReason (eSSU2TerminationReasonNormalClose), + m_MaxPayloadSize (SSU2_MAX_PAYLOAD_SIZE) { m_NoiseState.reset (new i2p::crypto::NoiseSymmetricState); if (in_RemoteRouter && m_Address) @@ -94,7 +95,7 @@ namespace transport RAND_bytes ((uint8_t *)&nonce, 4); auto ts = i2p::util::GetSecondsSinceEpoch (); // payload - uint8_t payload[SSU2_MAX_PAYLOAD_SIZE]; + uint8_t payload[SSU2_MAX_PACKET_SIZE]; size_t payloadSize = 0; payload[0] = eSSU2BlkRelayRequest; payload[3] = 0; // flag @@ -102,7 +103,7 @@ namespace transport htobe32buf (payload + 8, relayTag); htobe32buf (payload + 12, ts); payload[16] = 2; // ver - size_t asz = CreateEndpoint (payload + 18, SSU2_MAX_PAYLOAD_SIZE - 18, boost::asio::ip::udp::endpoint (localAddress->host, localAddress->port)); + size_t asz = CreateEndpoint (payload + 18, m_MaxPayloadSize - 18, boost::asio::ip::udp::endpoint (localAddress->host, localAddress->port)); if (!asz) return false; payload[17] = asz; payloadSize += asz + 18; @@ -114,7 +115,7 @@ namespace transport s.Sign (i2p::context.GetPrivateKeys (), payload + payloadSize); payloadSize += i2p::context.GetIdentity ()->GetSignatureLen (); htobe16buf (payload + 1, payloadSize - 3); // size - payloadSize += CreatePaddingBlock (payload + payloadSize, SSU2_MAX_PAYLOAD_SIZE - payloadSize); + payloadSize += CreatePaddingBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize); // send m_RelaySessions.emplace (nonce, std::make_pair (session, ts)); session->m_SourceConnID = htobe64 (((uint64_t)nonce << 32) | nonce); @@ -145,9 +146,9 @@ namespace transport session->m_DestConnID = ~session->m_SourceConnID; m_Server.AddSession (session); // peer test block - uint8_t payload[SSU2_MAX_PAYLOAD_SIZE]; - size_t payloadSize = CreatePeerTestBlock (payload, SSU2_MAX_PAYLOAD_SIZE, nonce); - payloadSize += CreatePaddingBlock (payload + payloadSize, SSU2_MAX_PAYLOAD_SIZE - payloadSize); + uint8_t payload[SSU2_MAX_PACKET_SIZE]; + size_t payloadSize = CreatePeerTestBlock (payload, m_MaxPayloadSize, nonce); + payloadSize += CreatePaddingBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize); SendData (payload, payloadSize); } @@ -218,12 +219,12 @@ namespace transport m_Server.GetService ().post ([s]() { if (!s->IsEstablished ()) return; - uint8_t payload[SSU2_MAX_PAYLOAD_SIZE]; - size_t payloadSize = s->CreateRouterInfoBlock (payload, SSU2_MAX_PAYLOAD_SIZE - 32, i2p::context.GetSharedRouterInfo ()); + uint8_t payload[SSU2_MAX_PACKET_SIZE]; + size_t payloadSize = s->CreateRouterInfoBlock (payload, s->m_MaxPayloadSize - 32, i2p::context.GetSharedRouterInfo ()); if (payloadSize) { - if (payloadSize < SSU2_MAX_PAYLOAD_SIZE) - payloadSize += s->CreatePaddingBlock (payload + payloadSize, SSU2_MAX_PAYLOAD_SIZE - payloadSize); + if (payloadSize < s->m_MaxPayloadSize) + payloadSize += s->CreatePaddingBlock (payload + payloadSize, s->m_MaxPayloadSize - payloadSize); s->SendData (payload, payloadSize); } else @@ -251,17 +252,17 @@ namespace transport { auto nextResend = i2p::util::GetSecondsSinceEpoch () + SSU2_RESEND_INTERVAL; auto packet = std::make_shared(); - packet->payloadSize += CreateAckBlock (packet->payload + packet->payloadSize, SSU2_MAX_PAYLOAD_SIZE - packet->payloadSize); + packet->payloadSize += CreateAckBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize); while (!m_SendQueue.empty () && m_SentPackets.size () <= m_WindowSize) { auto msg = m_SendQueue.front (); size_t len = msg->GetNTCP2Length (); - if (len + 3 < SSU2_MAX_PAYLOAD_SIZE - packet->payloadSize) + if (len + 3 < m_MaxPayloadSize - packet->payloadSize) { m_SendQueue.pop_front (); - packet->payloadSize += CreateI2NPBlock (packet->payload + packet->payloadSize, SSU2_MAX_PAYLOAD_SIZE - packet->payloadSize, std::move (msg)); + packet->payloadSize += CreateI2NPBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize, std::move (msg)); } - else if (len > SSU2_MAX_PAYLOAD_SIZE) // message too long + else if (len > m_MaxPayloadSize) // message too long { m_SendQueue.pop_front (); SendFragmentedMessage (msg); @@ -269,19 +270,19 @@ namespace transport else { // send right a way - if (packet->payloadSize + 16 < SSU2_MAX_PAYLOAD_SIZE) - packet->payloadSize += CreatePaddingBlock (packet->payload + packet->payloadSize, SSU2_MAX_PAYLOAD_SIZE - packet->payloadSize); + if (packet->payloadSize + 16 < m_MaxPayloadSize) + packet->payloadSize += CreatePaddingBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize); uint32_t packetNum = SendData (packet->payload, packet->payloadSize); packet->nextResendTime = nextResend; m_SentPackets.emplace (packetNum, packet); packet = std::make_shared(); - packet->payloadSize += CreateAckBlock (packet->payload + packet->payloadSize, SSU2_MAX_PAYLOAD_SIZE - packet->payloadSize); + packet->payloadSize += CreateAckBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize); } }; if (packet->payloadSize) { - if (packet->payloadSize + 16 < SSU2_MAX_PAYLOAD_SIZE) - packet->payloadSize += CreatePaddingBlock (packet->payload + packet->payloadSize, SSU2_MAX_PAYLOAD_SIZE - packet->payloadSize); + if (packet->payloadSize + 16 < m_MaxPayloadSize) + packet->payloadSize += CreatePaddingBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize); uint32_t packetNum = SendData (packet->payload, packet->payloadSize); packet->nextResendTime = nextResend; m_SentPackets.emplace (packetNum, packet); @@ -297,11 +298,11 @@ namespace transport memcpy (&msgID, msg->GetHeader () + I2NP_HEADER_MSGID_OFFSET, 4); auto nextResend = i2p::util::GetSecondsSinceEpoch () + SSU2_RESEND_INTERVAL; auto packet = std::make_shared(); - packet->payloadSize = CreateAckBlock (packet->payload, SSU2_MAX_PAYLOAD_SIZE); - auto size = CreateFirstFragmentBlock (packet->payload + packet->payloadSize, SSU2_MAX_PAYLOAD_SIZE - 16 - packet->payloadSize, msg); + packet->payloadSize = CreateAckBlock (packet->payload, m_MaxPayloadSize); + auto size = CreateFirstFragmentBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - 16 - packet->payloadSize, msg); if (!size) return; packet->payloadSize += size; - packet->payloadSize += CreatePaddingBlock (packet->payload + packet->payloadSize, SSU2_MAX_PAYLOAD_SIZE - 16 - packet->payloadSize); + packet->payloadSize += CreatePaddingBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - 16 - packet->payloadSize); uint32_t firstPacketNum = SendData (packet->payload, packet->payloadSize); packet->nextResendTime = nextResend; m_SentPackets.emplace (firstPacketNum, packet); @@ -309,8 +310,8 @@ namespace transport while (msg->offset < msg->len) { packet = std::make_shared(); - packet->payloadSize = CreateFollowOnFragmentBlock (packet->payload, SSU2_MAX_PAYLOAD_SIZE - 16, msg, fragmentNum, msgID); - packet->payloadSize += CreatePaddingBlock (packet->payload + packet->payloadSize, SSU2_MAX_PAYLOAD_SIZE - 16 - packet->payloadSize); + packet->payloadSize = CreateFollowOnFragmentBlock (packet->payload, m_MaxPayloadSize - 16, msg, fragmentNum, msgID); + packet->payloadSize += CreatePaddingBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - 16 - packet->payloadSize); uint32_t followonPacketNum = SendData (packet->payload, packet->payloadSize); packet->nextResendTime = nextResend; m_SentPackets.emplace (followonPacketNum, packet); @@ -528,7 +529,7 @@ namespace transport memset (headerX + 8, 0, 8); // token = 0 memcpy (headerX + 16, m_EphemeralKeys->GetPublicKey (), 32); // Y // payload - const size_t maxPayloadSize = SSU2_MAX_PAYLOAD_SIZE - 48; + size_t maxPayloadSize = m_MaxPayloadSize - 48; payload[0] = eSSU2BlkDateTime; htobe16buf (payload + 1, 4); htobe32buf (payload + 3, ts); @@ -611,6 +612,7 @@ namespace transport HandlePayload (decryptedPayload.data (), decryptedPayload.size ()); m_Server.AddSession (shared_from_this ()); + AdjustMaxPayloadSize (); SendSessionConfirmed (headerX + 16); KDFDataPhase (m_KeyDataSend, m_KeyDataReceive); @@ -634,13 +636,13 @@ namespace transport memset (header.h.flags, 0, 3); header.h.flags[0] = 1; // frag, total fragments always 1 // payload - size_t maxPayloadSize = SSU2_MAX_PAYLOAD_SIZE - 64; // part 2 + size_t maxPayloadSize = m_MaxPayloadSize - 48; // for part 2, 48 is part1 uint8_t * payload = m_SentHandshakePacket->payload; size_t payloadSize = CreateRouterInfoBlock (payload, maxPayloadSize, i2p::context.GetSharedRouterInfo ()); if (!payloadSize) { // split by two fragments - maxPayloadSize += SSU2_MAX_PAYLOAD_SIZE; + maxPayloadSize += m_MaxPayloadSize; payloadSize = CreateRouterInfoBlock (payload, maxPayloadSize, i2p::context.GetSharedRouterInfo ()); header.h.flags[0] = 0x02; // frag 0, total fragments 2 // TODO: check if we need more fragments @@ -798,6 +800,7 @@ namespace transport LogPrint (eLogError, "SSU2: No SSU2 address with static key found in SessionConfirmed"); return false; } + AdjustMaxPayloadSize (); m_Server.AddSessionByRouterHash (shared_from_this ()); // we know remote router now m_RemoteTransports = ri->GetCompatibleTransports (false); i2p::data::netdb.PostI2NPMsg (CreateDatabaseStoreMsg (ri)); // TODO: should insert ri @@ -965,7 +968,7 @@ namespace transport { // we are Charlie Header header; - uint8_t h[32], payload[SSU2_MAX_PAYLOAD_SIZE]; + uint8_t h[32], payload[SSU2_MAX_PACKET_SIZE]; // fill packet header.h.connID = htobe64 (((uint64_t)nonce << 32) | nonce); // dest id RAND_bytes (header.buf + 8, 4); // random packet num @@ -982,10 +985,10 @@ namespace transport htobe16buf (payload + 1, 4); htobe32buf (payload + 3, i2p::util::GetSecondsSinceEpoch ()); size_t payloadSize = 7; - payloadSize += CreateAddressBlock (payload + payloadSize, SSU2_MAX_PAYLOAD_SIZE - payloadSize, ep); - payloadSize += CreateRelayResponseBlock (payload + payloadSize, SSU2_MAX_PAYLOAD_SIZE - payloadSize, + payloadSize += CreateAddressBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize, ep); + payloadSize += CreateRelayResponseBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize, eSSU2RelayResponseCodeAccept, nonce, true, token); - payloadSize += CreatePaddingBlock (payload + payloadSize, SSU2_MAX_PAYLOAD_SIZE - payloadSize); + payloadSize += CreatePaddingBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize); // encrypt uint8_t n[12]; CreateNonce (be32toh (header.h.packetNum), n); @@ -1049,7 +1052,7 @@ namespace transport void SSU2Session::SendPeerTest (uint8_t msg, const uint8_t * signedData, size_t signedDataLen, const uint8_t * introKey) { Header header; - uint8_t h[32], payload[SSU2_MAX_PAYLOAD_SIZE]; + uint8_t h[32], payload[SSU2_MAX_PACKET_SIZE]; // fill packet header.h.connID = m_DestConnID; // dest id RAND_bytes (header.buf + 8, 4); // random packet num @@ -1065,10 +1068,10 @@ namespace transport htobe32buf (payload + 3, i2p::util::GetSecondsSinceEpoch ()); size_t payloadSize = 7; if (msg == 6 || msg == 7) - payloadSize += CreateAddressBlock (payload + payloadSize, SSU2_MAX_PAYLOAD_SIZE - payloadSize, m_RemoteEndpoint); - payloadSize += CreatePeerTestBlock (payload + payloadSize, SSU2_MAX_PAYLOAD_SIZE - payloadSize, + payloadSize += CreateAddressBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize, m_RemoteEndpoint); + payloadSize += CreatePeerTestBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize, msg, eSSU2PeerTestCodeAccept, nullptr, signedData, signedDataLen); - payloadSize += CreatePaddingBlock (payload + payloadSize, SSU2_MAX_PAYLOAD_SIZE - payloadSize); + payloadSize += CreatePaddingBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize); // encrypt uint8_t n[12]; CreateNonce (be32toh (header.h.packetNum), n); @@ -1449,10 +1452,10 @@ namespace transport { LogPrint (eLogWarning, "SSU2: RelayRequest session with relay tag ", relayTag, " not found"); // send relay response back to Alice - uint8_t payload[SSU2_MAX_PAYLOAD_SIZE]; - size_t payloadSize = CreateRelayResponseBlock (payload, SSU2_MAX_PAYLOAD_SIZE, + uint8_t payload[SSU2_MAX_PACKET_SIZE]; + size_t payloadSize = CreateRelayResponseBlock (payload, m_MaxPayloadSize, eSSU2RelayResponseCodeBobRelayTagNotFound, bufbe32toh (buf + 1), false, 0); - payloadSize += CreatePaddingBlock (payload + payloadSize, SSU2_MAX_PAYLOAD_SIZE - payloadSize); + payloadSize += CreatePaddingBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize); SendData (payload, payloadSize); return; } @@ -1466,12 +1469,12 @@ namespace transport else LogPrint (eLogWarning, "SSU2: RelayRequest Alice's router info not found"); uint8_t payload[SSU2_MAX_PAYLOAD_SIZE]; - size_t payloadSize = r ? CreateRouterInfoBlock (payload, SSU2_MAX_PAYLOAD_SIZE - len - 32, r) : 0; + size_t payloadSize = r ? CreateRouterInfoBlock (payload, m_MaxPayloadSize - len - 32, r) : 0; if (!payloadSize && r) session->SendFragmentedMessage (CreateDatabaseStoreMsg (r)); - payloadSize += CreateRelayIntroBlock (payload + payloadSize, SSU2_MAX_PAYLOAD_SIZE - payloadSize, buf + 1, len -1); + payloadSize += CreateRelayIntroBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize, buf + 1, len -1); if (payloadSize < SSU2_MAX_PAYLOAD_SIZE) - payloadSize += CreatePaddingBlock (payload + payloadSize, SSU2_MAX_PAYLOAD_SIZE - payloadSize); + payloadSize += CreatePaddingBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize); session->SendData (payload, payloadSize); } @@ -1526,10 +1529,10 @@ namespace transport code = eSSU2RelayResponseCodeCharlieAliceIsUnknown; } // send relay response to Bob - uint8_t payload[SSU2_MAX_PAYLOAD_SIZE]; - size_t payloadSize = CreateRelayResponseBlock (payload, SSU2_MAX_PAYLOAD_SIZE, + uint8_t payload[SSU2_MAX_PACKET_SIZE]; + size_t payloadSize = CreateRelayResponseBlock (payload, m_MaxPayloadSize, code, bufbe32toh (buf + 33), true, token); - payloadSize += CreatePaddingBlock (payload + payloadSize, SSU2_MAX_PAYLOAD_SIZE - payloadSize); + payloadSize += CreatePaddingBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize); SendData (payload, payloadSize); } @@ -1558,12 +1561,12 @@ namespace transport if (it->second.first && it->second.first->IsEstablished ()) { // we are Bob, message from Charlie - uint8_t payload[SSU2_MAX_PAYLOAD_SIZE]; + uint8_t payload[SSU2_MAX_PACKET_SIZE]; payload[0] = eSSU2BlkRelayResponse; htobe16buf (payload + 1, len); memcpy (payload + 3, buf, len); // forward to Alice as is size_t payloadSize = len + 3; - payloadSize += CreatePaddingBlock (payload + payloadSize, SSU2_MAX_PAYLOAD_SIZE - payloadSize); + payloadSize += CreatePaddingBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize); it->second.first->SendData (payload, payloadSize); } else @@ -1618,32 +1621,32 @@ namespace transport if (session) // session with Charlie { session->m_PeerTests.emplace (nonce, std::make_pair (shared_from_this (), i2p::util::GetSecondsSinceEpoch ())); - uint8_t payload[SSU2_MAX_PAYLOAD_SIZE]; + uint8_t payload[SSU2_MAX_PACKET_SIZE]; // Alice's RouterInfo auto r = i2p::data::netdb.FindRouter (GetRemoteIdentity ()->GetIdentHash ()); if (r) i2p::data::netdb.PopulateRouterInfoBuffer (r); - size_t payloadSize = r ? CreateRouterInfoBlock (payload, SSU2_MAX_PAYLOAD_SIZE - len - 32, r) : 0; + size_t payloadSize = r ? CreateRouterInfoBlock (payload, m_MaxPayloadSize - len - 32, r) : 0; if (!payloadSize && r) session->SendFragmentedMessage (CreateDatabaseStoreMsg (r)); - if (payloadSize + len + 48 > SSU2_MAX_PAYLOAD_SIZE) + if (payloadSize + len + 48 > m_MaxPayloadSize) { // doesn't fit one message, send RouterInfo in separate message session->SendData (payload, payloadSize); payloadSize = 0; } // PeerTest to Charlie - payloadSize += CreatePeerTestBlock (payload + payloadSize, SSU2_MAX_PAYLOAD_SIZE - payloadSize, 2, + payloadSize += CreatePeerTestBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize, 2, eSSU2PeerTestCodeAccept, GetRemoteIdentity ()->GetIdentHash (), buf + offset, len - offset); - payloadSize += CreatePaddingBlock (payload + payloadSize, SSU2_MAX_PAYLOAD_SIZE - payloadSize); + payloadSize += CreatePaddingBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize); session->SendData (payload, payloadSize); } else { // Charlie not found, send error back to Alice - uint8_t payload[SSU2_MAX_PAYLOAD_SIZE], zeroHash[32] = {0}; - size_t payloadSize = CreatePeerTestBlock (payload, SSU2_MAX_PAYLOAD_SIZE, 4, + uint8_t payload[SSU2_MAX_PACKET_SIZE], zeroHash[32] = {0}; + size_t payloadSize = CreatePeerTestBlock (payload, m_MaxPayloadSize, 4, eSSU2PeerTestCodeBobNoCharlieAvailable, zeroHash, buf + offset, len - offset); - payloadSize += CreatePaddingBlock (payload + payloadSize, SSU2_MAX_PAYLOAD_SIZE - payloadSize); + payloadSize += CreatePaddingBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize); SendData (payload, payloadSize); } break; @@ -1706,10 +1709,10 @@ namespace transport else code = eSSU2PeerTestCodeCharlieAliceIsUnknown; // send msg 3 back to Bob - uint8_t payload[SSU2_MAX_PAYLOAD_SIZE]; - size_t payloadSize = CreatePeerTestBlock (payload, SSU2_MAX_PAYLOAD_SIZE, 3, + uint8_t payload[SSU2_MAX_PACKET_SIZE]; + size_t payloadSize = CreatePeerTestBlock (payload, m_MaxPayloadSize, 3, code, nullptr, newSignedData.data (), newSignedData.size ()); - payloadSize += CreatePaddingBlock (payload + payloadSize, SSU2_MAX_PAYLOAD_SIZE - payloadSize); + payloadSize += CreatePaddingBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize); SendData (payload, payloadSize); break; } @@ -1718,24 +1721,24 @@ namespace transport auto it = m_PeerTests.find (nonce); if (it != m_PeerTests.end () && it->second.first) { - uint8_t payload[SSU2_MAX_PAYLOAD_SIZE]; + uint8_t payload[SSU2_MAX_PACKET_SIZE]; // Charlie's RouterInfo auto r = i2p::data::netdb.FindRouter (GetRemoteIdentity ()->GetIdentHash ()); if (r) i2p::data::netdb.PopulateRouterInfoBuffer (r); - size_t payloadSize = r ? CreateRouterInfoBlock (payload, SSU2_MAX_PAYLOAD_SIZE - len - 32, r) : 0; + size_t payloadSize = r ? CreateRouterInfoBlock (payload, m_MaxPayloadSize - len - 32, r) : 0; if (!payloadSize && r) it->second.first->SendFragmentedMessage (CreateDatabaseStoreMsg (r)); - if (payloadSize + len + 16 > SSU2_MAX_PAYLOAD_SIZE) + if (payloadSize + len + 16 > m_MaxPayloadSize) { // doesn't fit one message, send RouterInfo in separate message it->second.first->SendData (payload, payloadSize); payloadSize = 0; } // PeerTest to Alice - payloadSize += CreatePeerTestBlock (payload + payloadSize, SSU2_MAX_PAYLOAD_SIZE, 4, + payloadSize += CreatePeerTestBlock (payload + payloadSize, m_MaxPayloadSize, 4, (SSU2PeerTestCode)buf[1], GetRemoteIdentity ()->GetIdentHash (), buf + offset, len - offset); - if (payloadSize < SSU2_MAX_PAYLOAD_SIZE) - payloadSize += CreatePaddingBlock (payload + payloadSize, SSU2_MAX_PAYLOAD_SIZE - payloadSize); + if (payloadSize < m_MaxPayloadSize) + payloadSize += CreatePaddingBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize); it->second.first->SendData (payload, payloadSize); m_PeerTests.erase (it); } @@ -1893,6 +1896,22 @@ namespace transport return nullptr; } + void SSU2Session::AdjustMaxPayloadSize () + { + auto addr = FindLocalAddress (); + if (addr && addr->ssu) + { + int mtu = addr->ssu->mtu; + if (m_Address && m_Address->ssu && (!mtu || m_Address->ssu->mtu < mtu)) + mtu = m_Address->ssu->mtu; + if (mtu) + { + m_MaxPayloadSize = mtu - (addr->IsV6 () ? IPV6_HEADER_SIZE: IPV4_HEADER_SIZE) - UDP_HEADER_SIZE - 32; + LogPrint (eLogDebug, "SSU2: Session MTU=", mtu, ", max payload size=", m_MaxPayloadSize); + } + } + } + RouterStatus SSU2Session::GetRouterStatus () const { if (m_Address) @@ -2240,9 +2259,9 @@ namespace transport void SSU2Session::SendQuickAck () { - uint8_t payload[SSU2_MTU]; - size_t payloadSize = CreateAckBlock (payload, SSU2_MTU); - payloadSize += CreatePaddingBlock (payload + payloadSize, SSU2_MTU - payloadSize); + uint8_t payload[SSU2_MAX_PACKET_SIZE]; + size_t payloadSize = CreateAckBlock (payload, m_MaxPayloadSize); + payloadSize += CreatePaddingBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize); SendData (payload, payloadSize); } @@ -2253,7 +2272,7 @@ namespace transport payloadSize += CreatePaddingBlock (payload + payloadSize, 32 - payloadSize); SendData (payload, payloadSize); } - + void SSU2Session::CleanUp (uint64_t ts) { for (auto it = m_IncompleteMessages.begin (); it != m_IncompleteMessages.end ();) diff --git a/libi2pd/SSU2Session.h b/libi2pd/SSU2Session.h index 7a6a4a5c..bb6f4d55 100644 --- a/libi2pd/SSU2Session.h +++ b/libi2pd/SSU2Session.h @@ -33,7 +33,7 @@ namespace transport const int SSU2_RELAY_NONCE_EXPIRATION_TIMEOUT = 10; // in seconds const int SSU2_PEER_TEST_EXPIRATION_TIMEOUT = 60; // 60 seconds const size_t SSU2_MAX_PACKET_SIZE = 1500; - const size_t SSU2_MTU = 1440; // TODO: should be 1456 for ipv4 + const size_t SSU2_MTU = SSU2_MAX_PACKET_SIZE - IPV6_HEADER_SIZE - UDP_HEADER_SIZE; // TODO: ipv4 const size_t SSU2_MAX_PAYLOAD_SIZE = SSU2_MTU - 32; const int SSU2_HANDSHAKE_RESEND_INTERVAL = 1; // in seconds const int SSU2_RESEND_INTERVAL = 3; // in seconds @@ -186,7 +186,7 @@ namespace transport struct SentPacket { - uint8_t payload[SSU2_MAX_PAYLOAD_SIZE]; + uint8_t payload[SSU2_MAX_PACKET_SIZE]; size_t payloadSize = 0; uint32_t nextResendTime; // in seconds int numResends = 0; @@ -273,6 +273,7 @@ namespace transport bool ExtractEndpoint (const uint8_t * buf, size_t size, boost::asio::ip::udp::endpoint& ep); size_t CreateEndpoint (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& ep); std::shared_ptr FindLocalAddress () const; + void AdjustMaxPayloadSize (); RouterStatus GetRouterStatus () const; void SetRouterStatus (RouterStatus status) const; std::shared_ptr ExtractRouterInfo (const uint8_t * buf, size_t size); @@ -326,6 +327,7 @@ namespace transport OnEstablished m_OnEstablished; // callback from Established boost::asio::deadline_timer m_ConnectTimer; SSU2TerminationReason m_TerminationReason; + size_t m_MaxPayloadSize; }; inline uint64_t CreateHeaderMask (const uint8_t * kh, const uint8_t * nonce) diff --git a/libi2pd/SSUData.h b/libi2pd/SSUData.h index 1746dcd8..eba0fc28 100644 --- a/libi2pd/SSUData.h +++ b/libi2pd/SSUData.h @@ -19,17 +19,14 @@ #include "I2NPProtocol.h" #include "Identity.h" #include "RouterInfo.h" +#include "TransportSession.h" namespace i2p { namespace transport { - const size_t SSU_MTU_V4 = 1484; const size_t SSU_MTU_V6 = 1488; - const size_t IPV4_HEADER_SIZE = 20; - const size_t IPV6_HEADER_SIZE = 40; - const size_t UDP_HEADER_SIZE = 8; const size_t SSU_V4_MAX_PACKET_SIZE = SSU_MTU_V4 - IPV4_HEADER_SIZE - UDP_HEADER_SIZE; // 1456 const size_t SSU_V6_MAX_PACKET_SIZE = SSU_MTU_V6 - IPV6_HEADER_SIZE - UDP_HEADER_SIZE; // 1440 const int RESEND_INTERVAL = 3; // in seconds diff --git a/libi2pd/TransportSession.h b/libi2pd/TransportSession.h index a51207af..c05b46ac 100644 --- a/libi2pd/TransportSession.h +++ b/libi2pd/TransportSession.h @@ -24,6 +24,10 @@ namespace i2p { namespace transport { + const size_t IPV4_HEADER_SIZE = 20; + const size_t IPV6_HEADER_SIZE = 40; + const size_t UDP_HEADER_SIZE = 8; + class SignedData { public: @@ -64,7 +68,7 @@ namespace transport std::stringstream m_Stream; }; - + class TransportSession { public: From 8feac310af891ca80938457059806cbf993eb7b2 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 13 Jul 2022 19:56:55 -0400 Subject: [PATCH 036/219] start initial peer test if SSU2 only --- libi2pd/Transports.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libi2pd/Transports.cpp b/libi2pd/Transports.cpp index b76bbc30..2ae495fa 100644 --- a/libi2pd/Transports.cpp +++ b/libi2pd/Transports.cpp @@ -285,9 +285,9 @@ namespace transport delete m_SSUServer; m_SSUServer = nullptr; } - if (m_SSUServer) DetectExternalIP (); } - + if (m_SSUServer || m_SSU2Server) DetectExternalIP (); + m_PeerCleanupTimer->expires_from_now (boost::posix_time::seconds(5*SESSION_CREATION_TIMEOUT)); m_PeerCleanupTimer->async_wait (std::bind (&Transports::HandlePeerCleanupTimer, this, std::placeholders::_1)); @@ -622,10 +622,10 @@ namespace transport i2p::context.SetStatus (eRouterStatusOK); return; } - if (m_SSUServer) + if (m_SSUServer || m_SSU2Server) PeerTest (); else - LogPrint (eLogError, "Transports: Can't detect external IP. SSU is not available"); + LogPrint (eLogWarning, "Transports: Can't detect external IP. SSU or SSU2 is not available"); } void Transports::PeerTest (bool ipv4, bool ipv6) From 665a914dc3f1ae16d05ca35a4c1d244e442e3751 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 13 Jul 2022 20:08:57 -0400 Subject: [PATCH 037/219] set max MTU for ipv4 --- libi2pd/SSU2Session.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index 64b39b6f..80d6e795 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -1902,6 +1902,7 @@ namespace transport if (addr && addr->ssu) { int mtu = addr->ssu->mtu; + if (!mtu && addr->IsV4 ()) mtu = SSU2_MAX_PACKET_SIZE; if (m_Address && m_Address->ssu && (!mtu || m_Address->ssu->mtu < mtu)) mtu = m_Address->ssu->mtu; if (mtu) From 14a6947b021a74c7ec0bc7fedb0dace5253ecd42 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 14 Jul 2022 07:58:55 -0400 Subject: [PATCH 038/219] round MTU to multiple of 16 for SSU1 --- libi2pd/RouterContext.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index de845b3b..404e14de 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -434,6 +434,8 @@ namespace i2p mtu = maxMTU; LogPrint(eLogWarning, "Router: MTU dropped to upper limit of ", maxMTU, " bytes"); } + else if (mtu && !address->IsSSU2 ()) // SSU1 + mtu = (mtu >> 4) << 4; // round to multiple of 16 if (address->ssu) address->ssu->mtu = mtu; } } From 014e4b0e1d36f90569704ca462bed4e240964527 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 14 Jul 2022 13:48:28 -0400 Subject: [PATCH 039/219] detect MTU for some known ipv6 tunnel brokers --- libi2pd/RouterContext.cpp | 4 ++-- libi2pd/util.cpp | 20 ++++++++++++++++++++ libi2pd/util.h | 3 ++- 3 files changed, 24 insertions(+), 3 deletions(-) diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index 404e14de..a3048f4d 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -428,13 +428,13 @@ namespace i2p if (mtu) { LogPrint (eLogDebug, "Router: Our v6 MTU=", mtu); - int maxMTU = address->IsSSU2 () ? 1500 : 1488; // must be multiple of 16 for SSU1 + int maxMTU = i2p::util::net::GetMaxMTU (host.to_v6 ()); if (mtu > maxMTU) { mtu = maxMTU; LogPrint(eLogWarning, "Router: MTU dropped to upper limit of ", maxMTU, " bytes"); } - else if (mtu && !address->IsSSU2 ()) // SSU1 + if (mtu && !address->IsSSU2 ()) // SSU1 mtu = (mtu >> 4) << 4; // round to multiple of 16 if (address->ssu) address->ssu->mtu = mtu; } diff --git a/libi2pd/util.cpp b/libi2pd/util.cpp index 07681dbd..a3eefffe 100644 --- a/libi2pd/util.cpp +++ b/libi2pd/util.cpp @@ -12,6 +12,7 @@ #include "util.h" #include "Log.h" +#include "I2PEndian.h" #if not defined (__FreeBSD__) #include @@ -423,6 +424,25 @@ namespace net #endif } + int GetMaxMTU (const boost::asio::ip::address_v6& localAddress) + { + uint32_t prefix = bufbe32toh (localAddress.to_bytes ().data ()); + switch (prefix) + { + case 0x20010470: + case 0x260070ff: + // Hurricane Electric + return 1480; + break; + case 0x2a06a004: + // route48 + return 1420; + break; + default: ; + } + return 1500; + } + static bool IsYggdrasilAddress (const uint8_t addr[16]) { return addr[0] == 0x02 || addr[0] == 0x03; diff --git a/libi2pd/util.h b/libi2pd/util.h index 2c74d4dd..9420060b 100644 --- a/libi2pd/util.h +++ b/libi2pd/util.h @@ -1,5 +1,5 @@ /* -* Copyright (c) 2013-2021, The PurpleI2P Project +* Copyright (c) 2013-2022, The PurpleI2P Project * * This file is part of Purple i2pd project and licensed under BSD3 * @@ -218,6 +218,7 @@ namespace util namespace net { int GetMTU (const boost::asio::ip::address& localAddress); + int GetMaxMTU (const boost::asio::ip::address_v6& localAddress); // check tunnel broker for ipv6 address const boost::asio::ip::address GetInterfaceAddress (const std::string & ifname, bool ipv6=false); boost::asio::ip::address_v6 GetYggdrasilAddress (); bool IsLocalAddress (const boost::asio::ip::address& addr); From 5026dbc1b37903b3577fc35d6211d880677cae28 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 14 Jul 2022 20:12:27 -0400 Subject: [PATCH 040/219] receive bigger packets --- libi2pd/SSU2.cpp | 2 +- libi2pd/SSU2Session.cpp | 16 ++++++++-------- libi2pd/SSU2Session.h | 5 ++--- 3 files changed, 11 insertions(+), 12 deletions(-) diff --git a/libi2pd/SSU2.cpp b/libi2pd/SSU2.cpp index c1eb09f3..438dfa41 100644 --- a/libi2pd/SSU2.cpp +++ b/libi2pd/SSU2.cpp @@ -175,7 +175,7 @@ namespace transport while (moreBytes && packets.size () < 32) { packet = m_PacketsPool.AcquireMt (); - packet->len = socket.receive_from (boost::asio::buffer (packet->buf, SSU2_MTU), packet->from, 0, ec); + packet->len = socket.receive_from (boost::asio::buffer (packet->buf, SSU2_MAX_PACKET_SIZE), packet->from, 0, ec); if (!ec) { i2p::transport::transports.UpdateReceivedBytes (packet->len); diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index 80d6e795..1b53a156 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -26,7 +26,7 @@ namespace transport m_SendPacketNum (0), m_ReceivePacketNum (0), m_IsDataReceived (false), m_WindowSize (SSU2_MAX_WINDOW_SIZE), m_RelayTag (0), m_ConnectTimer (server.GetService ()), m_TerminationReason (eSSU2TerminationReasonNormalClose), - m_MaxPayloadSize (SSU2_MAX_PAYLOAD_SIZE) + m_MaxPayloadSize (SSU2_MIN_PACKET_SIZE - IPV6_HEADER_SIZE - UDP_HEADER_SIZE - 32) // min size { m_NoiseState.reset (new i2p::crypto::NoiseSymmetricState); if (in_RemoteRouter && m_Address) @@ -669,9 +669,9 @@ namespace transport m_SentHandshakePacket->payloadSize = payloadSize; if (header.h.flags[0] > 1) { - if (payloadSize > SSU2_MAX_PAYLOAD_SIZE - 64) + if (payloadSize > m_MaxPayloadSize - 48) { - payloadSize = SSU2_MAX_PAYLOAD_SIZE - 64 - (rand () % 16); + payloadSize = m_MaxPayloadSize - 48 - (rand () % 16); if (m_SentHandshakePacket->payloadSize - payloadSize < 24) payloadSize -= 24; } @@ -1131,8 +1131,8 @@ namespace transport memset (header.h.flags, 0, 3); uint8_t nonce[12]; CreateNonce (m_SendPacketNum, nonce); - uint8_t payload[SSU2_MTU]; - i2p::crypto::AEADChaCha20Poly1305 (buf, len, header.buf, 16, m_KeyDataSend, nonce, payload, SSU2_MTU, true); + uint8_t payload[SSU2_MAX_PACKET_SIZE]; + i2p::crypto::AEADChaCha20Poly1305 (buf, len, header.buf, 16, m_KeyDataSend, nonce, payload, SSU2_MAX_PACKET_SIZE, true); header.ll[0] ^= CreateHeaderMask (m_Address->i, payload + (len - 8)); header.ll[1] ^= CreateHeaderMask (m_KeyDataSend + 32, payload + (len + 4)); m_Server.Send (header.buf, 16, payload, len + 16, m_RemoteEndpoint); @@ -1154,7 +1154,7 @@ namespace transport SendQuickAck (); // in case it was SessionConfirmed return; } - uint8_t payload[SSU2_MTU]; + uint8_t payload[SSU2_MAX_PACKET_SIZE]; size_t payloadSize = len - 32; uint32_t packetNum = be32toh (header.h.packetNum); uint8_t nonce[12]; @@ -1468,12 +1468,12 @@ namespace transport i2p::data::netdb.PopulateRouterInfoBuffer (r); else LogPrint (eLogWarning, "SSU2: RelayRequest Alice's router info not found"); - uint8_t payload[SSU2_MAX_PAYLOAD_SIZE]; + uint8_t payload[SSU2_MAX_PACKET_SIZE]; size_t payloadSize = r ? CreateRouterInfoBlock (payload, m_MaxPayloadSize - len - 32, r) : 0; if (!payloadSize && r) session->SendFragmentedMessage (CreateDatabaseStoreMsg (r)); payloadSize += CreateRelayIntroBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize, buf + 1, len -1); - if (payloadSize < SSU2_MAX_PAYLOAD_SIZE) + if (payloadSize < m_MaxPayloadSize) payloadSize += CreatePaddingBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize); session->SendData (payload, payloadSize); } diff --git a/libi2pd/SSU2Session.h b/libi2pd/SSU2Session.h index bb6f4d55..7ee89edd 100644 --- a/libi2pd/SSU2Session.h +++ b/libi2pd/SSU2Session.h @@ -33,8 +33,7 @@ namespace transport const int SSU2_RELAY_NONCE_EXPIRATION_TIMEOUT = 10; // in seconds const int SSU2_PEER_TEST_EXPIRATION_TIMEOUT = 60; // 60 seconds const size_t SSU2_MAX_PACKET_SIZE = 1500; - const size_t SSU2_MTU = SSU2_MAX_PACKET_SIZE - IPV6_HEADER_SIZE - UDP_HEADER_SIZE; // TODO: ipv4 - const size_t SSU2_MAX_PAYLOAD_SIZE = SSU2_MTU - 32; + const size_t SSU2_MIN_PACKET_SIZE = 1280; const int SSU2_HANDSHAKE_RESEND_INTERVAL = 1; // in seconds const int SSU2_RESEND_INTERVAL = 3; // in seconds const int SSU2_MAX_NUM_RESENDS = 5; @@ -153,7 +152,7 @@ namespace transport { struct Fragment { - uint8_t buf[SSU2_MTU]; + uint8_t buf[SSU2_MAX_PACKET_SIZE]; size_t len; bool isLast; }; From 4f8b0e6484c174d293e9468330336e59c459aec0 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 15 Jul 2022 15:01:46 -0400 Subject: [PATCH 041/219] send more SessionConfirmed termination messages. Limit send queue --- libi2pd/SSU2Session.cpp | 26 ++++++++++++++++++++++++-- libi2pd/SSU2Session.h | 1 + 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index 1b53a156..3a64bd38 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -175,6 +175,10 @@ namespace transport m_Server.RemoveRelay (m_RelayTag); m_SentHandshakePacket.reset (nullptr); m_SendQueue.clear (); + m_SentPackets.clear (); + m_IncompleteMessages.clear (); + m_RelaySessions.clear (); + m_PeerTests.clear (); LogPrint (eLogDebug, "SSU2: Session terminated"); } } @@ -241,9 +245,17 @@ namespace transport void SSU2Session::PostI2NPMessages (std::vector > msgs) { + if (m_State == eSSU2SessionStateTerminated) return; for (auto it: msgs) m_SendQueue.push_back (it); SendQueue (); + + if (m_SendQueue.size () > SSU2_MAX_OUTGOING_QUEUE_SIZE) + { + LogPrint (eLogWarning, "SSU2: Outgoing messages queue size to ", + GetIdentHashBase64(), " exceeds ", SSU2_MAX_OUTGOING_QUEUE_SIZE); + RequestTermination (eSSU2TerminationReasonTimeout); + } } bool SSU2Session::SendQueue () @@ -758,10 +770,11 @@ namespace transport return false; } m_NoiseState->MixHash (buf + 16, 48); // h = SHA256(h || ciphertext); - // KDF for Session Confirmed part 2 + // KDF for Session Confirmed part 2 and data phase uint8_t sharedSecret[32]; m_EphemeralKeys->Agree (S, sharedSecret); m_NoiseState->MixKey (sharedSecret); + KDFDataPhase (m_KeyDataReceive, m_KeyDataSend); // decrypt part2 memset (nonce, 0, 12); uint8_t * payload = buf + 64; @@ -770,6 +783,8 @@ namespace transport m_NoiseState->m_CK + 32, nonce, decryptedPayload.data (), decryptedPayload.size (), false)) { LogPrint (eLogWarning, "SSU2: SessionConfirmed part 2 AEAD verification failed "); + m_TerminationReason = eSSU2TerminationReasonSessionConfirmedError; + SendTermination (); return false; } m_NoiseState->MixHash (payload, len - 64); // h = SHA256(h || ciphertext); @@ -778,12 +793,16 @@ namespace transport if (decryptedPayload[0] != eSSU2BlkRouterInfo) { LogPrint (eLogError, "SSU2: SessionConfirmed unexpected first block type ", (int)decryptedPayload[0]); + m_TerminationReason = eSSU2TerminationReasonPayloadFormatError; + SendTermination (); return false; } size_t riSize = bufbe16toh (decryptedPayload.data () + 1); if (riSize + 3 > decryptedPayload.size ()) { LogPrint (eLogError, "SSU2: SessionConfirmed RouterInfo block is too long ", riSize); + m_TerminationReason = eSSU2TerminationReasonPayloadFormatError; + SendTermination (); return false; } LogPrint (eLogDebug, "SSU2: RouterInfo in SessionConfirmed"); @@ -791,6 +810,8 @@ namespace transport if (!ri) { LogPrint (eLogError, "SSU2: SessionConfirmed malformed RouterInfo block"); + m_TerminationReason = eSSU2TerminationReasonRouterInfoSignatureVerificationFail; + SendTermination (); return false; } SetRemoteIdentity (ri->GetRouterIdentity ()); @@ -798,6 +819,8 @@ namespace transport if (!m_Address) { LogPrint (eLogError, "SSU2: No SSU2 address with static key found in SessionConfirmed"); + m_TerminationReason = eSSU2TerminationReasonInvalidS; + SendTermination (); return false; } AdjustMaxPayloadSize (); @@ -806,7 +829,6 @@ namespace transport i2p::data::netdb.PostI2NPMsg (CreateDatabaseStoreMsg (ri)); // TODO: should insert ri // handle other blocks HandlePayload (decryptedPayload.data () + riSize + 3, decryptedPayload.size () - riSize - 3); - KDFDataPhase (m_KeyDataReceive, m_KeyDataSend); Established (); SendQuickAck (); diff --git a/libi2pd/SSU2Session.h b/libi2pd/SSU2Session.h index 7ee89edd..e3886a7d 100644 --- a/libi2pd/SSU2Session.h +++ b/libi2pd/SSU2Session.h @@ -39,6 +39,7 @@ namespace transport const int SSU2_MAX_NUM_RESENDS = 5; const int SSU2_INCOMPLETE_MESSAGES_CLEANUP_TIMEOUT = 30; // in seconds const size_t SSU2_MAX_WINDOW_SIZE = 128; // in packets + const size_t SSU2_MAX_OUTGOING_QUEUE_SIZE = 300; // in messages const int SSU2_MAX_NUM_ACK_RANGES = 32; // to send enum SSU2MessageType From 16290bf66f8f6d65bb142cf3f52de1b7d7eb214a Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 15 Jul 2022 18:22:18 -0400 Subject: [PATCH 042/219] fixed race condition on session termination --- libi2pd/SSU2Session.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index 3a64bd38..12da45f7 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -168,9 +168,7 @@ namespace transport { m_State = eSSU2SessionStateTerminated; m_ConnectTimer.cancel (); - transports.PeerDisconnected (shared_from_this ()); m_OnEstablished = nullptr; - m_Server.RemoveSession (m_SourceConnID); if (m_RelayTag) m_Server.RemoveRelay (m_RelayTag); m_SentHandshakePacket.reset (nullptr); @@ -179,6 +177,8 @@ namespace transport m_IncompleteMessages.clear (); m_RelaySessions.clear (); m_PeerTests.clear (); + m_Server.RemoveSession (m_SourceConnID); + transports.PeerDisconnected (shared_from_this ()); LogPrint (eLogDebug, "SSU2: Session terminated"); } } From 412a245e88f873a17bb295e38d024f81300603e7 Mon Sep 17 00:00:00 2001 From: Simon Vetter Date: Sat, 16 Jul 2022 15:22:25 +0200 Subject: [PATCH 043/219] leaseset: add missing bound checks This builds on ChadF's issue and patch (https://github.com/PurpleI2P/i2pd/issues/1772) and fixes other potential bound check issues. --- libi2pd/LeaseSet.cpp | 35 ++++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/libi2pd/LeaseSet.cpp b/libi2pd/LeaseSet.cpp index c844ab60..60c9ea5a 100644 --- a/libi2pd/LeaseSet.cpp +++ b/libi2pd/LeaseSet.cpp @@ -59,9 +59,9 @@ namespace data if (readIdentity || !m_Identity) m_Identity = std::make_shared(m_Buffer, m_BufferLen); size_t size = m_Identity->GetFullLen (); - if (size > m_BufferLen) + if (size + 256 > m_BufferLen) { - LogPrint (eLogError, "LeaseSet: Identity length ", size, " exceeds buffer size ", m_BufferLen); + LogPrint (eLogError, "LeaseSet: Identity length ", int(size), " exceeds buffer size ", int(m_BufferLen)); m_IsValid = false; return; } @@ -74,7 +74,7 @@ namespace data size += m_Identity->GetSigningPublicKeyLen (); // unused signing key if (size + 1 > m_BufferLen) { - LogPrint (eLogError, "LeaseSet: ", size, " exceeds buffer size ", m_BufferLen); + LogPrint (eLogError, "LeaseSet: ", int(size), " exceeds buffer size ", int(m_BufferLen)); m_IsValid = false; return; } @@ -89,7 +89,7 @@ namespace data } if (size + num*LEASE_SIZE > m_BufferLen) { - LogPrint (eLogError, "LeaseSet: ", size, " exceeds buffer size ", m_BufferLen); + LogPrint (eLogError, "LeaseSet: ", int(size), " exceeds buffer size ", int(m_BufferLen)); m_IsValid = false; return; } @@ -125,7 +125,7 @@ namespace data auto signedSize = leases - m_Buffer; if (signedSize + m_Identity->GetSignatureLen () > m_BufferLen) { - LogPrint (eLogError, "LeaseSet: Signature exceeds buffer size ", m_BufferLen); + LogPrint (eLogError, "LeaseSet: Signature exceeds buffer size ", int(m_BufferLen)); m_IsValid = false; } else if (!m_Identity->Verify (m_Buffer, signedSize, leases)) @@ -274,7 +274,7 @@ namespace data { if (len <= m_BufferLen) m_BufferLen = len; else - LogPrint (eLogError, "LeaseSet2: Actual buffer size ", len , " exceeds full buffer size ", m_BufferLen); + LogPrint (eLogError, "LeaseSet2: Actual buffer size ", int(len) , " exceeds full buffer size ", int(m_BufferLen)); } LeaseSet2::LeaseSet2 (uint8_t storeType, const uint8_t * buf, size_t len, bool storeLeases, CryptoKeyType preferredCrypto): @@ -320,7 +320,7 @@ namespace data else identity = GetIdentity (); size_t offset = identity->GetFullLen (); - if (offset + 8 >= len) return; + if (offset + 8 > len) return; m_PublishedTimestamp = bufbe32toh (buf + offset); offset += 4; // published timestamp (seconds) uint16_t expires = bufbe16toh (buf + offset); offset += 2; // expires (seconds) SetExpirationTime ((m_PublishedTimestamp + expires)*1000LL); // in milliseconds @@ -364,6 +364,10 @@ namespace data SetIsValid (verified); } offset += m_TransientVerifier ? m_TransientVerifier->GetSignatureLen () : identity->GetSignatureLen (); + if (offset > len) { + LogPrint (eLogWarning, "LeaseSet2: short buffer: wanted ", int(offset), "bytes, have ", int(len)); + return; + } SetBufferLen (offset); } @@ -388,17 +392,17 @@ namespace data // properties uint16_t propertiesLen = bufbe16toh (buf + offset); offset += 2; offset += propertiesLen; // skip for now. TODO: implement properties - if (offset + 1 >= len) return 0; // key sections CryptoKeyType preferredKeyType = m_EncryptionType; bool preferredKeyFound = false; + if (offset + 1 > len) return 0; int numKeySections = buf[offset]; offset++; for (int i = 0; i < numKeySections; i++) { + if (offset + 4 > len) return 0; uint16_t keyType = bufbe16toh (buf + offset); offset += 2; // encryption key type - if (offset + 2 >= len) return 0; uint16_t encryptionKeyLen = bufbe16toh (buf + offset); offset += 2; - if (offset + encryptionKeyLen >= len) return 0; + if (offset + encryptionKeyLen > len) return 0; if (IsStoreLeases () && !preferredKeyFound) // create encryptor with leases only { // we pick first valid key if preferred not found @@ -413,7 +417,7 @@ namespace data offset += encryptionKeyLen; } // leases - if (offset + 1 >= len) return 0; + if (offset + 1 > len) return 0; int numLeases = buf[offset]; offset++; auto ts = i2p::util::GetMillisecondsSinceEpoch (); if (IsStoreLeases ()) @@ -432,7 +436,8 @@ namespace data } else offset += numLeases*LEASE2_SIZE; // 40 bytes per lease - return offset; + + return (offset > len ? 0 : offset); } size_t LeaseSet2::ReadMetaLS2TypeSpecificPart (const uint8_t * buf, size_t len) @@ -442,18 +447,18 @@ namespace data uint16_t propertiesLen = bufbe16toh (buf + offset); offset += 2; offset += propertiesLen; // skip for now. TODO: implement properties // entries - if (offset + 1 >= len) return 0; + if (offset + 1 > len) return 0; int numEntries = buf[offset]; offset++; for (int i = 0; i < numEntries; i++) { - if (offset + 40 >= len) return 0; + if (offset + LEASE2_SIZE > len) return 0; offset += 32; // hash offset += 3; // flags offset += 1; // cost offset += 4; // expires } // revocations - if (offset + 1 >= len) return 0; + if (offset + 1 > len) return 0; int numRevocations = buf[offset]; offset++; for (int i = 0; i < numRevocations; i++) { From dc30cd1112fa6c298c4e5cae196427008dbe8d72 Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 16 Jul 2022 16:08:55 -0400 Subject: [PATCH 044/219] handle SessionConfirmed fragments in reversed order --- libi2pd/SSU2Session.cpp | 31 ++++++++++++++++++++++++++----- libi2pd/SSU2Session.h | 1 + 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index 12da45f7..cd18b281 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -409,7 +409,7 @@ namespace transport } default: { - LogPrint (eLogWarning, "SSU2: Unexpected message type ", (int)header.h.type, " from ", m_RemoteEndpoint); + LogPrint (eLogWarning, "SSU2: Unexpected message type ", (int)header.h.type, " from ", m_RemoteEndpoint, " of ", len, " bytes"); return false; } } @@ -727,8 +727,9 @@ namespace transport header.ll[1] ^= CreateHeaderMask (kh2, buf + (len - 12)); if (header.h.type != eSSU2SessionConfirmed) { - LogPrint (eLogWarning, "SSU2: Unexpected message type ", (int)header.h.type, " instead ", (int)eSSU2SessionConfirmed); - return false; + LogPrint (eLogInfo, "SSU2: Unexpected message type ", (int)header.h.type, " instead ", (int)eSSU2SessionConfirmed); + // TODO: queue up + return true; } // check if fragmented if ((header.h.flags[0] & 0x0F) > 1) @@ -743,13 +744,33 @@ namespace transport m_SessionConfirmedFragment->header = header; memcpy (m_SessionConfirmedFragment->payload, buf + 16, len - 16); m_SessionConfirmedFragment->payloadSize = len - 16; + return true; // wait for second fragment + } + else if (m_SessionConfirmedFragment->isSecondFragment) + { + // we have second fragment + m_SessionConfirmedFragment->header = header; + memmove (m_SessionConfirmedFragment->payload + (len - 16), m_SessionConfirmedFragment->payload, m_SessionConfirmedFragment->payloadSize); + memcpy (m_SessionConfirmedFragment->payload, buf + 16, len - 16); + m_SessionConfirmedFragment->payloadSize += (len - 16); + buf = m_SessionConfirmedFragment->payload - 16; + len = m_SessionConfirmedFragment->payloadSize + 16; } - return true; // wait for second fragment + else + return true; } else { // second fragment - if (!m_SessionConfirmedFragment) return false; // out of sequence + if (!m_SessionConfirmedFragment) + { + // out of sequence, save it + m_SessionConfirmedFragment.reset (new HandshakePacket); + memcpy (m_SessionConfirmedFragment->payload, buf + 16, len - 16); + m_SessionConfirmedFragment->payloadSize = len - 16; + m_SessionConfirmedFragment->isSecondFragment = true; + return true; + } header = m_SessionConfirmedFragment->header; memcpy (m_SessionConfirmedFragment->payload + m_SessionConfirmedFragment->payloadSize, buf + 16, len - 16); m_SessionConfirmedFragment->payloadSize += (len - 16); diff --git a/libi2pd/SSU2Session.h b/libi2pd/SSU2Session.h index e3886a7d..e7fcabac 100644 --- a/libi2pd/SSU2Session.h +++ b/libi2pd/SSU2Session.h @@ -199,6 +199,7 @@ namespace transport uint8_t payload[SSU2_MAX_PACKET_SIZE*2]; size_t payloadSize = 0; uint32_t nextResendTime = 0; // in seconds + bool isSecondFragment = false; // for SessionConfirmed }; typedef std::function OnEstablished; From 206c068d8ea62ca8878dd5523be825fa776fe712 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 17 Jul 2022 07:44:11 -0400 Subject: [PATCH 045/219] don't send termination without address --- libi2pd/SSU2Session.cpp | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index cd18b281..71fa471b 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -804,8 +804,6 @@ namespace transport m_NoiseState->m_CK + 32, nonce, decryptedPayload.data (), decryptedPayload.size (), false)) { LogPrint (eLogWarning, "SSU2: SessionConfirmed part 2 AEAD verification failed "); - m_TerminationReason = eSSU2TerminationReasonSessionConfirmedError; - SendTermination (); return false; } m_NoiseState->MixHash (payload, len - 64); // h = SHA256(h || ciphertext); @@ -814,16 +812,12 @@ namespace transport if (decryptedPayload[0] != eSSU2BlkRouterInfo) { LogPrint (eLogError, "SSU2: SessionConfirmed unexpected first block type ", (int)decryptedPayload[0]); - m_TerminationReason = eSSU2TerminationReasonPayloadFormatError; - SendTermination (); return false; } size_t riSize = bufbe16toh (decryptedPayload.data () + 1); if (riSize + 3 > decryptedPayload.size ()) { LogPrint (eLogError, "SSU2: SessionConfirmed RouterInfo block is too long ", riSize); - m_TerminationReason = eSSU2TerminationReasonPayloadFormatError; - SendTermination (); return false; } LogPrint (eLogDebug, "SSU2: RouterInfo in SessionConfirmed"); @@ -831,8 +825,6 @@ namespace transport if (!ri) { LogPrint (eLogError, "SSU2: SessionConfirmed malformed RouterInfo block"); - m_TerminationReason = eSSU2TerminationReasonRouterInfoSignatureVerificationFail; - SendTermination (); return false; } SetRemoteIdentity (ri->GetRouterIdentity ()); @@ -840,8 +832,6 @@ namespace transport if (!m_Address) { LogPrint (eLogError, "SSU2: No SSU2 address with static key found in SessionConfirmed"); - m_TerminationReason = eSSU2TerminationReasonInvalidS; - SendTermination (); return false; } AdjustMaxPayloadSize (); From ffab29890b13adbeb93dcdae76c44c2b5f1a0584 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 17 Jul 2022 15:22:41 -0400 Subject: [PATCH 046/219] created additional ranges if acnt > 255 --- libi2pd/SSU2Session.cpp | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index 71fa471b..480d2f0b 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -2008,7 +2008,7 @@ namespace transport buf[0] = eSSU2BlkAck; uint32_t ackThrough = m_OutOfSequencePackets.empty () ? m_ReceivePacketNum : *m_OutOfSequencePackets.rbegin (); htobe32buf (buf + 3, ackThrough); // Ack Through - uint8_t acnt = 0; + uint16_t acnt = 0; int numRanges = 0; if (ackThrough) { @@ -2024,6 +2024,27 @@ namespace transport } // ranges uint32_t lastNum = ackThrough - acnt; + if (acnt > 255) + { + auto d = std::div (acnt - 255, 255); + acnt = 255; + if (d.quot > SSU2_MAX_NUM_ACK_RANGES) + { + d.quot = SSU2_MAX_NUM_ACK_RANGES; + d.rem = 0; + } + // Acks only ragnes for acnt + for (int i = 0; i < d.quot; i++) + { + buf[8 + numRanges*2] = 0; buf[8 + numRanges*2 + 1] = 255; // NACKs 0, Acks 255 + numRanges++; + } + if (d.rem > 0) + { + buf[8 + numRanges*2] = 0; buf[8 + numRanges*2 + 1] = d.rem; + numRanges++; + } + } while (it != m_OutOfSequencePackets.rend () && numRanges < SSU2_MAX_NUM_ACK_RANGES) { if (lastNum - (*it) > 255) @@ -2073,7 +2094,7 @@ namespace transport } } } - buf[7] = acnt; // acnt + buf[7] = (uint8_t)acnt; // acnt htobe16buf (buf + 1, 5 + numRanges*2); return 8 + numRanges*2; } From 9fec1a86cf1e175e03c8fe2c8ee4b7a3f252f12e Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 18 Jul 2022 19:58:19 -0400 Subject: [PATCH 047/219] send ack for peer test --- libi2pd/SSU2Session.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index 480d2f0b..054a0e0f 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -1283,6 +1283,8 @@ namespace transport case eSSU2BlkPeerTest: LogPrint (eLogDebug, "SSU2: PeerTest msg=", (int)buf[offset], " code=", (int)buf[offset+1]); HandlePeerTest (buf + offset, size); + if (buf[offset] < 5) + m_IsDataReceived = true; break; case eSSU2BlkNextNonce: break; From a3e19931f090e3575a52b7b5777af1237f3514bd Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 19 Jul 2022 14:06:00 -0400 Subject: [PATCH 048/219] insert RouterInfo from SessionConfirmed into netdb immediately --- libi2pd/NetDb.cpp | 14 ++++++++------ libi2pd/NetDb.hpp | 2 +- libi2pd/SSU2Session.cpp | 10 ++++++++-- 3 files changed, 17 insertions(+), 9 deletions(-) diff --git a/libi2pd/NetDb.cpp b/libi2pd/NetDb.cpp index 8566380a..f043764f 100644 --- a/libi2pd/NetDb.cpp +++ b/libi2pd/NetDb.cpp @@ -240,11 +240,10 @@ namespace data m_HiddenMode = hide; } - bool NetDb::AddRouterInfo (const uint8_t * buf, int len) + std::shared_ptr NetDb::AddRouterInfo (const uint8_t * buf, int len) { bool updated; - AddRouterInfo (buf, len, updated); - return updated; + return AddRouterInfo (buf, len, updated); } std::shared_ptr NetDb::AddRouterInfo (const uint8_t * buf, int len, bool& updated) @@ -436,12 +435,15 @@ namespace data // try reseeding from floodfill first if specified std::string riPath; - if(i2p::config::GetOption("reseed.floodfill", riPath)) { + if(i2p::config::GetOption("reseed.floodfill", riPath)) + { auto ri = std::make_shared(riPath); - if (ri->IsFloodfill()) { + if (ri->IsFloodfill()) + { const uint8_t * riData = ri->GetBuffer(); int riLen = ri->GetBufferLen(); - if(!i2p::data::netdb.AddRouterInfo(riData, riLen)) { + if (!i2p::data::netdb.AddRouterInfo(riData, riLen)) + { // bad router info LogPrint(eLogError, "NetDb: Bad router info"); return; diff --git a/libi2pd/NetDb.hpp b/libi2pd/NetDb.hpp index 1a07903c..3cd26c2c 100644 --- a/libi2pd/NetDb.hpp +++ b/libi2pd/NetDb.hpp @@ -69,7 +69,7 @@ namespace data void Start (); void Stop (); - bool AddRouterInfo (const uint8_t * buf, int len); + std::shared_ptr AddRouterInfo (const uint8_t * buf, int len); bool AddRouterInfo (const IdentHash& ident, const uint8_t * buf, int len); bool AddLeaseSet (const IdentHash& ident, const uint8_t * buf, int len); bool AddLeaseSet2 (const IdentHash& ident, const uint8_t * buf, int len, uint8_t storeType); diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index 054a0e0f..42aa01e9 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -827,17 +827,23 @@ namespace transport LogPrint (eLogError, "SSU2: SessionConfirmed malformed RouterInfo block"); return false; } - SetRemoteIdentity (ri->GetRouterIdentity ()); m_Address = ri->GetSSU2AddressWithStaticKey (S, m_RemoteEndpoint.address ().is_v6 ()); if (!m_Address) { LogPrint (eLogError, "SSU2: No SSU2 address with static key found in SessionConfirmed"); return false; } + // update RouterInfo in netdb + ri = i2p::data::netdb.AddRouterInfo (ri->GetBuffer (), ri->GetBufferLen ()); // ri points to one from netdb now + if (!ri) + { + LogPrint (eLogError, "SSU2: Couldn't update RouterInfo from SessionConfirmed in netdb"); + return false; + } + SetRemoteIdentity (ri->GetRouterIdentity ()); AdjustMaxPayloadSize (); m_Server.AddSessionByRouterHash (shared_from_this ()); // we know remote router now m_RemoteTransports = ri->GetCompatibleTransports (false); - i2p::data::netdb.PostI2NPMsg (CreateDatabaseStoreMsg (ri)); // TODO: should insert ri // handle other blocks HandlePayload (decryptedPayload.data () + riSize + 3, decryptedPayload.size () - riSize - 3); Established (); From 000e0358a7120efd67307337aa06fb165953a9b4 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 19 Jul 2022 16:09:16 -0400 Subject: [PATCH 049/219] resend SessionConfirmed immediately if another SessionCreated received --- libi2pd/SSU2Session.cpp | 25 ++++++++++++++++++------- libi2pd/SSU2Session.h | 3 ++- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index 42aa01e9..fb5dd1e6 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -336,13 +336,8 @@ namespace transport if (m_SentHandshakePacket && ts >= m_SentHandshakePacket->nextResendTime) { LogPrint (eLogDebug, "SSU2: Resending ", (int)m_State); - m_Server.Send (m_SentHandshakePacket->header.buf, 16, m_SentHandshakePacket->headerX, 48, - m_SentHandshakePacket->payload, m_SentHandshakePacket->payloadSize, m_RemoteEndpoint); + ResendHandshakePacket (); m_SentHandshakePacket->nextResendTime = ts + SSU2_HANDSHAKE_RESEND_INTERVAL; - if (m_SessionConfirmedFragment && m_State == eSSU2SessionStateSessionConfirmedSent) - // resend second fragment of SessionConfirmed - m_Server.Send (m_SessionConfirmedFragment->header.buf, 16, - m_SessionConfirmedFragment->payload, m_SessionConfirmedFragment->payloadSize, m_RemoteEndpoint); return; } // resend data packets @@ -382,6 +377,19 @@ namespace transport SendQueue (); } + void SSU2Session::ResendHandshakePacket () + { + if (m_SentHandshakePacket) + { + m_Server.Send (m_SentHandshakePacket->header.buf, 16, m_SentHandshakePacket->headerX, 48, + m_SentHandshakePacket->payload, m_SentHandshakePacket->payloadSize, m_RemoteEndpoint); + if (m_SessionConfirmedFragment && m_State == eSSU2SessionStateSessionConfirmedSent) + // resend second fragment of SessionConfirmed + m_Server.Send (m_SessionConfirmedFragment->header.buf, 16, + m_SessionConfirmedFragment->payload, m_SessionConfirmedFragment->payloadSize, m_RemoteEndpoint); + } + } + bool SSU2Session::ProcessFirstIncomingMessage (uint64_t connID, uint8_t * buf, size_t len) { // we are Bob @@ -1190,7 +1198,10 @@ namespace transport if (header.h.type != eSSU2Data) { LogPrint (eLogWarning, "SSU2: Unexpected message type ", (int)header.h.type, " instead ", (int)eSSU2Data); - SendQuickAck (); // in case it was SessionConfirmed + if (IsEstablished ()) + SendQuickAck (); // in case it was SessionConfirmed + else + ResendHandshakePacket (); // assume we receive return; } uint8_t payload[SSU2_MAX_PACKET_SIZE]; diff --git a/libi2pd/SSU2Session.h b/libi2pd/SSU2Session.h index e7fcabac..79640177 100644 --- a/libi2pd/SSU2Session.h +++ b/libi2pd/SSU2Session.h @@ -252,7 +252,8 @@ namespace transport void PostI2NPMessages (std::vector > msgs); bool SendQueue (); void SendFragmentedMessage (std::shared_ptr msg); - + void ResendHandshakePacket (); + void ProcessSessionRequest (Header& header, uint8_t * buf, size_t len); void ProcessTokenRequest (Header& header, uint8_t * buf, size_t len); From 6f7ab49346897e259d792a0b94d5b55a24c96c69 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 19 Jul 2022 17:02:37 -0400 Subject: [PATCH 050/219] moved creation time to TransportSession --- libi2pd/SSUSession.cpp | 1 - libi2pd/SSUSession.h | 3 --- libi2pd/TransportSession.h | 5 +++++ 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/libi2pd/SSUSession.cpp b/libi2pd/SSUSession.cpp index 817133e8..76b6486b 100644 --- a/libi2pd/SSUSession.cpp +++ b/libi2pd/SSUSession.cpp @@ -41,7 +41,6 @@ namespace transport i2p::context.GetRouterInfo ().GetSSUAddress (true); if (address) m_IntroKey = address->i; } - m_CreationTime = i2p::util::GetSecondsSinceEpoch (); } SSUSession::~SSUSession () diff --git a/libi2pd/SSUSession.h b/libi2pd/SSUSession.h index 535de328..e28b4991 100644 --- a/libi2pd/SSUSession.h +++ b/libi2pd/SSUSession.h @@ -103,8 +103,6 @@ namespace transport void SendKeepAlive (); 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 (); void CleanUp (uint64_t ts); @@ -167,7 +165,6 @@ namespace transport i2p::crypto::AESKey m_SessionKey; i2p::crypto::MACKey m_MacKey; i2p::data::RouterInfo::IntroKey m_IntroKey; - uint32_t m_CreationTime; // seconds since epoch SSUData m_Data; bool m_IsDataReceived; std::unique_ptr m_SignedData; // we need it for SessionConfirmed only diff --git a/libi2pd/TransportSession.h b/libi2pd/TransportSession.h index c05b46ac..53192816 100644 --- a/libi2pd/TransportSession.h +++ b/libi2pd/TransportSession.h @@ -79,6 +79,7 @@ namespace transport { if (router) m_RemoteIdentity = router->GetRouterIdentity (); + m_CreationTime = m_LastActivityTimestamp; } virtual ~TransportSession () {}; @@ -106,6 +107,9 @@ namespace transport bool IsTerminationTimeoutExpired (uint64_t ts) const { return ts >= m_LastActivityTimestamp + GetTerminationTimeout (); }; + uint32_t GetCreationTime () const { return m_CreationTime; }; + void SetCreationTime (uint32_t ts) { m_CreationTime = ts; }; // for introducers + virtual uint32_t GetRelayTag () const { return 0; }; virtual void SendLocalRouterInfo (bool update = false) { SendI2NPMessages ({ CreateDatabaseStoreMsg () }); }; virtual void SendI2NPMessages (const std::vector >& msgs) = 0; @@ -118,6 +122,7 @@ namespace transport bool m_IsOutgoing; int m_TerminationTimeout; uint64_t m_LastActivityTimestamp; + uint32_t m_CreationTime; // seconds since epoch }; } } From cf0d3b5f61d47745f0b00b1d255f70b117b4d680 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 19 Jul 2022 18:38:58 -0400 Subject: [PATCH 051/219] create new list of SSU2 introducers --- libi2pd/NetDb.cpp | 10 ++++++++ libi2pd/NetDb.hpp | 1 + libi2pd/RouterInfo.cpp | 11 +++++++++ libi2pd/RouterInfo.h | 1 + libi2pd/SSU2.cpp | 52 +++++++++++++++++++++++++++++++++++++----- 5 files changed, 69 insertions(+), 6 deletions(-) diff --git a/libi2pd/NetDb.cpp b/libi2pd/NetDb.cpp index f043764f..42d73c97 100644 --- a/libi2pd/NetDb.cpp +++ b/libi2pd/NetDb.cpp @@ -1233,6 +1233,16 @@ namespace data }); } + std::shared_ptr NetDb::GetRandomSSU2Introducer (bool v4, const std::set& excluded) const + { + return GetRandomRouter ( + [v4, &excluded](std::shared_ptr router)->bool + { + return !router->IsHidden () && router->IsSSU2Introducer (v4) && + !excluded.count (router->GetIdentHash ()); + }); + } + std::shared_ptr NetDb::GetHighBandwidthRandomRouter (std::shared_ptr compatibleWith, bool reverse) const { return GetRandomRouter ( diff --git a/libi2pd/NetDb.hpp b/libi2pd/NetDb.hpp index 3cd26c2c..ebd6acbe 100644 --- a/libi2pd/NetDb.hpp +++ b/libi2pd/NetDb.hpp @@ -93,6 +93,7 @@ namespace data std::shared_ptr GetRandomSSU2PeerTestRouter (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::set& excluded) const; + std::shared_ptr GetRandomSSU2Introducer (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/RouterInfo.cpp b/libi2pd/RouterInfo.cpp index 1575cbbc..26351a0b 100644 --- a/libi2pd/RouterInfo.cpp +++ b/libi2pd/RouterInfo.cpp @@ -1065,6 +1065,17 @@ namespace data }); } + bool RouterInfo::IsSSU2Introducer (bool v4) const + { + if (!(m_SupportedTransports & (v4 ? eSSU2V4 : eSSU2V6))) return false; + return (bool)GetAddress ( + [v4](std::shared_ptr address)->bool + { + return (address->IsSSU2 ()) && address->IsIntroducer () && + ((v4 && address->IsV4 ()) || (!v4 && address->IsV6 ())) && !address->host.is_unspecified (); + }); + } + void RouterInfo::SetUnreachableAddressesTransportCaps (uint8_t transports) { for (auto& addr: *m_Addresses) diff --git a/libi2pd/RouterInfo.h b/libi2pd/RouterInfo.h index 1aa90ce3..fca6352a 100644 --- a/libi2pd/RouterInfo.h +++ b/libi2pd/RouterInfo.h @@ -235,6 +235,7 @@ namespace data bool IsPeerTesting (bool v4) const; bool IsSSU2PeerTesting (bool v4) const; bool IsIntroducer (bool v4) const; + bool IsSSU2Introducer (bool v4) const; uint8_t GetCaps () const { return m_Caps; }; void SetCaps (uint8_t caps) { m_Caps = caps; }; diff --git a/libi2pd/SSU2.cpp b/libi2pd/SSU2.cpp index 438dfa41..62ae7358 100644 --- a/libi2pd/SSU2.cpp +++ b/libi2pd/SSU2.cpp @@ -755,28 +755,68 @@ namespace transport void SSU2Server::UpdateIntroducers (bool v4) { + uint32_t ts = i2p::util::GetSecondsSinceEpoch (); std::list> newList; auto& introducers = v4 ? m_Introducers : m_IntroducersV6; + std::set excluded; for (const auto& it : introducers) { if (it->IsEstablished ()) { - it->SendKeepAlive (); - newList.push_back (it); + if (ts < it->GetCreationTime () + SSU2_TO_INTRODUCER_SESSION_EXPIRATION) + it->SendKeepAlive (); + if (ts < it->GetCreationTime () + SSU2_TO_INTRODUCER_SESSION_DURATION) + { + newList.push_back (it); + excluded.insert (it->GetRemoteIdentity ()->GetIdentHash ()); + } + // TODO: remove introducer } } if (newList.size () < SSU2_MAX_NUM_INTRODUCERS) { - std::set excluded; - for (auto& it1: newList) - excluded.insert (it1->GetRemoteIdentity ()->GetIdentHash ()); - auto sessions = FindIntroducers (SSU_MAX_NUM_INTRODUCERS - newList.size (), v4, excluded); + auto sessions = FindIntroducers (SSU2_MAX_NUM_INTRODUCERS - newList.size (), v4, excluded); + if (sessions.empty () && !introducers.empty ()) + { + // bump creation time for previous introducers if no new sessions found + LogPrint (eLogDebug, "SSU2: No new introducers found. Trying to reuse existing"); + for (auto& it : introducers) + it->SetCreationTime (it->GetCreationTime () + SSU2_TO_INTRODUCER_SESSION_DURATION); + // try again + excluded.clear (); + sessions = FindIntroducers (SSU2_MAX_NUM_INTRODUCERS - newList.size (), v4, excluded); + } + for (const auto& it : sessions) { + // TODO: add introducer newList.push_back (it); + if (newList.size () >= SSU2_MAX_NUM_INTRODUCERS) break; } } introducers = newList; + + if (introducers.size () < SSU2_MAX_NUM_INTRODUCERS) + { + for (auto i = introducers.size (); i < SSU2_MAX_NUM_INTRODUCERS; i++) + { + auto introducer = i2p::data::netdb.GetRandomSSU2Introducer (v4, excluded); + if (introducer) + { + auto address = v4 ? introducer->GetSSU2V4Address () : introducer->GetSSU2V6Address (); + if (address) + { + CreateSession (introducer, address); + excluded.insert (introducer->GetIdentHash ()); + } + } + else + { + LogPrint (eLogDebug, "SSU2: Can't find more introducers"); + break; + } + } + } } } } From 2197cd86208b5e5617f0070d2039675c12fe53f7 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 20 Jul 2022 16:01:08 -0400 Subject: [PATCH 052/219] add/remove SSU2 introducers to local RouterInfo --- libi2pd/RouterContext.cpp | 14 ++++++++++++++ libi2pd/RouterContext.h | 2 ++ libi2pd/RouterInfo.cpp | 35 +++++++++++++++++++++++++++++++++++ libi2pd/RouterInfo.h | 5 +++++ libi2pd/SSU2.cpp | 18 ++++++++++++++---- 5 files changed, 70 insertions(+), 4 deletions(-) diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index a3048f4d..c9e4972c 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -461,6 +461,20 @@ namespace i2p UpdateRouterInfo (); } + bool RouterContext::AddSSU2Introducer (const i2p::data::RouterInfo::Introducer& introducer, bool v4) + { + bool ret = m_RouterInfo.AddSSU2Introducer (introducer, v4); + if (ret) + UpdateRouterInfo (); + return ret; + } + + void RouterContext::RemoveSSU2Introducer (const i2p::data::IdentHash& h, bool v4) + { + if (m_RouterInfo.RemoveSSU2Introducer (h, v4)) + UpdateRouterInfo (); + } + void RouterContext::SetFloodfill (bool floodfill) { m_IsFloodfill = floodfill; diff --git a/libi2pd/RouterContext.h b/libi2pd/RouterContext.h index 7a878c7d..6d575912 100644 --- a/libi2pd/RouterContext.h +++ b/libi2pd/RouterContext.h @@ -123,6 +123,8 @@ namespace garlic void RemoveNTCPAddress (bool v4only = true); // delete NTCP address for older routers. TODO: remove later bool AddIntroducer (const i2p::data::RouterInfo::Introducer& introducer); void RemoveIntroducer (const boost::asio::ip::udp::endpoint& e); + bool AddSSU2Introducer (const i2p::data::RouterInfo::Introducer& introducer, bool v4); + void RemoveSSU2Introducer (const i2p::data::IdentHash& h, bool v4); bool IsUnreachable () const; void SetUnreachable (bool v4, bool v6); void SetReachable (bool v4, bool v6); diff --git a/libi2pd/RouterInfo.cpp b/libi2pd/RouterInfo.cpp index 26351a0b..4dae397e 100644 --- a/libi2pd/RouterInfo.cpp +++ b/libi2pd/RouterInfo.cpp @@ -1478,5 +1478,40 @@ namespace data { return std::make_shared (); } + + bool LocalRouterInfo::AddSSU2Introducer (const Introducer& introducer, bool v4) + { + for (auto& addr : GetAddresses ()) + { + if (addr->IsSSU2 () && ((v4 && addr->IsV4 ()) || (!v4 && addr->IsV6 ()))) + { + for (auto& intro: addr->ssu->introducers) + if (intro.iTag == introducer.iTag) return false; // already presented + addr->ssu->introducers.push_back (introducer); + SetReachableTransports (GetReachableTransports () | ((addr->IsV4 () ? eSSU2V4 : eSSU2V6))); + return true; + } + } + return false; + } + + bool LocalRouterInfo::RemoveSSU2Introducer (const IdentHash& h, bool v4) + { + for (auto& addr: GetAddresses ()) + { + if (addr->IsSSU2 () && ((v4 && addr->IsV4 ()) || (!v4 && addr->IsV6 ()))) + { + for (auto it = addr->ssu->introducers.begin (); it != addr->ssu->introducers.end (); ++it) + if (h == it->iKey) + { + addr->ssu->introducers.erase (it); + if (addr->ssu->introducers.empty ()) + SetReachableTransports (GetReachableTransports () & ~(addr->IsV4 () ? eSSU2V4 : eSSU2V6)); + return true; + } + } + } + return false; + } } } diff --git a/libi2pd/RouterInfo.h b/libi2pd/RouterInfo.h index fca6352a..6bc66b35 100644 --- a/libi2pd/RouterInfo.h +++ b/libi2pd/RouterInfo.h @@ -275,6 +275,8 @@ namespace data void SetBufferLen (size_t len) { m_BufferLen = len; }; void RefreshTimestamp (); const Addresses& GetAddresses () const { return *m_Addresses; }; + CompatibleTransports GetReachableTransports () const { return m_ReachableTransports; }; + void SetReachableTransports (CompatibleTransports transports) { m_ReachableTransports = transports; }; private: @@ -317,6 +319,9 @@ namespace data std::string GetProperty (const std::string& key) const; void ClearProperties () override { m_Properties.clear (); }; + bool AddSSU2Introducer (const Introducer& introducer, bool v4); + bool RemoveSSU2Introducer (const IdentHash& h, bool v4); + private: void WriteToStream (std::ostream& s) const; diff --git a/libi2pd/SSU2.cpp b/libi2pd/SSU2.cpp index 62ae7358..e667b337 100644 --- a/libi2pd/SSU2.cpp +++ b/libi2pd/SSU2.cpp @@ -770,8 +770,11 @@ namespace transport newList.push_back (it); excluded.insert (it->GetRemoteIdentity ()->GetIdentHash ()); } - // TODO: remove introducer + else + i2p::context.RemoveSSU2Introducer (it->GetRemoteIdentity ()->GetIdentHash (), it->GetAddress ()->IsV4 ()); } + else + i2p::context.RemoveSSU2Introducer (it->GetRemoteIdentity ()->GetIdentHash (), it->GetAddress ()->IsV4 ()); } if (newList.size () < SSU2_MAX_NUM_INTRODUCERS) { @@ -789,9 +792,16 @@ namespace transport for (const auto& it : sessions) { - // TODO: add introducer - newList.push_back (it); - if (newList.size () >= SSU2_MAX_NUM_INTRODUCERS) break; + i2p::data::RouterInfo::Introducer introducer; + introducer.iTag = it->GetRelayTag (); + introducer.iKey = it->GetRemoteIdentity ()->GetIdentHash (); + introducer.iExp = it->GetCreationTime () + SSU2_TO_INTRODUCER_SESSION_EXPIRATION; + excluded.insert (it->GetRemoteIdentity ()->GetIdentHash ()); + if (i2p::context.AddSSU2Introducer (introducer, it->GetAddress ()->IsV4 ())) + { + newList.push_back (it); + if (newList.size () >= SSU2_MAX_NUM_INTRODUCERS) break; + } } } introducers = newList; From 4a3e481a83c66e780d2386d39690f510aff8904f Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 20 Jul 2022 16:13:00 -0400 Subject: [PATCH 053/219] don't publish introducers for non-published SSU2 address --- libi2pd/RouterInfo.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd/RouterInfo.cpp b/libi2pd/RouterInfo.cpp index 4dae397e..4bb0fb05 100644 --- a/libi2pd/RouterInfo.cpp +++ b/libi2pd/RouterInfo.cpp @@ -1321,7 +1321,7 @@ namespace data size_t len = address.IsSSU2 () ? 32 : 16; WriteString (address.i.ToBase64 (len), properties); properties << ';'; } - if (address.transportStyle == eTransportSSU || address.IsSSU2 ()) + if (address.transportStyle == eTransportSSU || (address.IsSSU2 () && isPublished)) { // write introducers if any if (address.ssu && !address.ssu->introducers.empty()) From ea0ed9e844c99b980f64224fbc037a2f33ee70ec Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 20 Jul 2022 21:55:48 -0400 Subject: [PATCH 054/219] update SSU2 introducers if Firewalled --- libi2pd/RouterInfo.cpp | 2 +- libi2pd/SSU2.cpp | 91 ++++++++++++++++++++++++++++++++++++++++- libi2pd/SSU2.h | 14 +++++-- libi2pd/SSU2Session.cpp | 6 +++ 4 files changed, 108 insertions(+), 5 deletions(-) diff --git a/libi2pd/RouterInfo.cpp b/libi2pd/RouterInfo.cpp index 4bb0fb05..4dae397e 100644 --- a/libi2pd/RouterInfo.cpp +++ b/libi2pd/RouterInfo.cpp @@ -1321,7 +1321,7 @@ namespace data size_t len = address.IsSSU2 () ? 32 : 16; WriteString (address.i.ToBase64 (len), properties); properties << ';'; } - if (address.transportStyle == eTransportSSU || (address.IsSSU2 () && isPublished)) + if (address.transportStyle == eTransportSSU || address.IsSSU2 ()) { // write introducers if any if (address.ssu && !address.ssu->introducers.empty()) diff --git a/libi2pd/SSU2.cpp b/libi2pd/SSU2.cpp index e667b337..52a38244 100644 --- a/libi2pd/SSU2.cpp +++ b/libi2pd/SSU2.cpp @@ -21,7 +21,9 @@ namespace transport RunnableServiceWithWork ("SSU2"), m_ReceiveService ("SSU2r"), m_SocketV4 (m_ReceiveService.GetService ()), m_SocketV6 (m_ReceiveService.GetService ()), m_AddressV4 (boost::asio::ip::address_v4()), m_AddressV6 (boost::asio::ip::address_v6()), - m_TerminationTimer (GetService ()), m_ResendTimer (GetService ()) + m_TerminationTimer (GetService ()), m_ResendTimer (GetService ()), + m_IntroducersUpdateTimer (GetService ()), m_IntroducersUpdateTimerV6 (GetService ()), + m_IsPublished (true) { } @@ -30,6 +32,7 @@ namespace transport if (!IsRunning ()) { StartIOService (); + i2p::config::GetOption ("ssu2.published", m_IsPublished); bool found = false; auto& addresses = i2p::context.GetRouterInfo ().GetAddresses (); for (const auto& address: addresses) @@ -59,6 +62,7 @@ namespace transport { Receive (m_SocketV4); }); + ScheduleIntroducersUpdateTimer (); // wait for 30 seconds and decide if we need introducers } if (address->IsV6 ()) { @@ -69,6 +73,7 @@ namespace transport { Receive (m_SocketV6); }); + ScheduleIntroducersUpdateTimerV6 (); // wait for 30 seconds and decide if we need introducers } } else @@ -827,6 +832,90 @@ namespace transport } } } + } + + void SSU2Server::ScheduleIntroducersUpdateTimer () + { + if (m_IsPublished) + { + m_IntroducersUpdateTimer.expires_from_now (boost::posix_time::seconds(SSU2_KEEP_ALIVE_INTERVAL)); + m_IntroducersUpdateTimer.async_wait (std::bind (&SSU2Server::HandleIntroducersUpdateTimer, + this, std::placeholders::_1, true)); + } + } + + void SSU2Server::RescheduleIntroducersUpdateTimer () + { + if (m_IsPublished) + { + m_IntroducersUpdateTimer.cancel (); + m_IntroducersUpdateTimer.expires_from_now (boost::posix_time::seconds(SSU2_KEEP_ALIVE_INTERVAL/2)); + m_IntroducersUpdateTimer.async_wait (std::bind (&SSU2Server::HandleIntroducersUpdateTimer, + this, std::placeholders::_1, true)); + } + } + + void SSU2Server::ScheduleIntroducersUpdateTimerV6 () + { + if (m_IsPublished) + { + m_IntroducersUpdateTimerV6.expires_from_now (boost::posix_time::seconds(SSU2_KEEP_ALIVE_INTERVAL)); + m_IntroducersUpdateTimerV6.async_wait (std::bind (&SSU2Server::HandleIntroducersUpdateTimer, + this, std::placeholders::_1, false)); + } + } + + void SSU2Server::RescheduleIntroducersUpdateTimerV6 () + { + if (m_IsPublished) + { + m_IntroducersUpdateTimerV6.cancel (); + m_IntroducersUpdateTimerV6.expires_from_now (boost::posix_time::seconds(SSU2_KEEP_ALIVE_INTERVAL/2)); + m_IntroducersUpdateTimerV6.async_wait (std::bind (&SSU2Server::HandleIntroducersUpdateTimer, + this, std::placeholders::_1, false)); + } + } + + void SSU2Server::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 + ScheduleIntroducersUpdateTimer (); + return; + } + if (i2p::context.GetStatus () != eRouterStatusFirewalled) + { + // we don't need introducers + m_Introducers.clear (); + return; + } + UpdateIntroducers (true); + ScheduleIntroducersUpdateTimer (); + } + 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; + } + UpdateIntroducers (false); + ScheduleIntroducersUpdateTimerV6 (); + } + } } } } diff --git a/libi2pd/SSU2.h b/libi2pd/SSU2.h index b9d59d68..5e0bba6b 100644 --- a/libi2pd/SSU2.h +++ b/libi2pd/SSU2.h @@ -23,6 +23,7 @@ namespace transport const size_t SSU2_MAX_NUM_INTRODUCERS = 3; const int SSU2_TO_INTRODUCER_SESSION_DURATION = 3600; // 1 hour const int SSU2_TO_INTRODUCER_SESSION_EXPIRATION = 4800; // 80 minutes + const int SSU2_KEEP_ALIVE_INTERVAL = 30; // 30 seconds class SSU2Server: private i2p::util::RunnableServiceWithWork { @@ -82,7 +83,9 @@ namespace transport uint64_t GetIncomingToken (const boost::asio::ip::udp::endpoint& ep); std::pair NewIncomingToken (const boost::asio::ip::udp::endpoint& ep); - + void RescheduleIntroducersUpdateTimer (); + void RescheduleIntroducersUpdateTimerV6 (); + private: boost::asio::ip::udp::socket& OpenSocket (const boost::asio::ip::udp::endpoint& localEndpoint); @@ -103,7 +106,10 @@ namespace transport std::list > FindIntroducers (int maxNumIntroducers, bool v4, const std::set& excluded) const; void UpdateIntroducers (bool v4); - + void ScheduleIntroducersUpdateTimer (); + void HandleIntroducersUpdateTimer (const boost::system::error_code& ecode, bool v4); + void ScheduleIntroducersUpdateTimerV6 (); + private: ReceiveService m_ReceiveService; @@ -116,8 +122,10 @@ namespace transport std::map > m_Relays; // we are introducer, relay tag -> session std::list > m_Introducers, m_IntroducersV6; // introducers we are connected to i2p::util::MemoryPoolMt m_PacketsPool; - boost::asio::deadline_timer m_TerminationTimer, m_ResendTimer; + boost::asio::deadline_timer m_TerminationTimer, m_ResendTimer, + m_IntroducersUpdateTimer, m_IntroducersUpdateTimerV6; std::shared_ptr m_LastSession; + bool m_IsPublished; // if we maintain introducers public: diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index fb5dd1e6..4890a61d 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -1831,7 +1831,13 @@ namespace transport else { if (GetRouterStatus () == eRouterStatusTesting) + { SetRouterStatus (eRouterStatusFirewalled); + if (m_Address->IsV4 ()) + m_Server.RescheduleIntroducersUpdateTimer (); + else + m_Server.RescheduleIntroducersUpdateTimerV6 (); + } } } else From 098fdf0596e95f5445d7fb2dc9f562840b0e5c9f Mon Sep 17 00:00:00 2001 From: R4SAS Date: Thu, 21 Jul 2022 23:36:51 +0300 Subject: [PATCH 055/219] [gha] update freebsd action --- .github/workflows/build-freebsd.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-freebsd.yml b/.github/workflows/build-freebsd.yml index b11569b7..16953ed0 100644 --- a/.github/workflows/build-freebsd.yml +++ b/.github/workflows/build-freebsd.yml @@ -4,13 +4,13 @@ on: [push, pull_request] jobs: build: - runs-on: macos-10.15 + runs-on: macos-12 name: with UPnP steps: - uses: actions/checkout@v2 - name: Test in FreeBSD id: test - uses: vmactions/freebsd-vm@v0.1.5 + uses: vmactions/freebsd-vm@v0.2.0 with: usesh: true mem: 2048 From 5ff34b93c0b92ab1665e27d410a8a67b8c10d40f Mon Sep 17 00:00:00 2001 From: R4SAS Date: Sun, 17 Jul 2022 23:34:32 +0300 Subject: [PATCH 056/219] print detected MTU Signed-off-by: R4SAS --- libi2pd/util.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libi2pd/util.cpp b/libi2pd/util.cpp index a3eefffe..4c66e07b 100644 --- a/libi2pd/util.cpp +++ b/libi2pd/util.cpp @@ -195,6 +195,8 @@ namespace net { auto result = pAddresses->Mtu; FREE(pAddresses); + pAddresses = nullptr; + LogPrint(eLogInfo, "NetIface: GetMTU(): Using ", result, " bytes for IPv4"); return result; } pUnicast = pUnicast->Next; @@ -259,6 +261,7 @@ namespace net auto result = pAddresses->Mtu; FREE(pAddresses); pAddresses = nullptr; + LogPrint(eLogInfo, "NetIface: GetMTU(): Using ", result, " bytes for IPv6"); return result; } pUnicast = pUnicast->Next; From 33a5968eb73b5617d95e2f9f8d91fc811e308903 Mon Sep 17 00:00:00 2001 From: Gecero-Sensei <27288418+Gecero@users.noreply.github.com> Date: Sat, 16 Jul 2022 19:45:22 +0200 Subject: [PATCH 057/219] Improved German translation --- i18n/German.cpp | 68 ++++++++++++++++++++++++------------------------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/i18n/German.cpp b/i18n/German.cpp index fcef4cff..33e40a0f 100644 --- a/i18n/German.cpp +++ b/i18n/German.cpp @@ -36,24 +36,24 @@ namespace german // language namespace {"GiB", "GiB"}, {"building", "In Bau"}, {"failed", "fehlgeschlagen"}, - {"expiring", "läuft ab in"}, + {"expiring", "läuft ab"}, {"established", "hergestellt"}, {"unknown", "Unbekannt"}, - {"exploratory", "erforschende"}, + {"exploratory", "erforschend"}, {"i2pd webconsole", "i2pd Webkonsole"}, {"Main page", "Startseite"}, - {"Router commands", "Router Befehle"}, - {"Local Destinations", "Lokale Destination"}, + {"Router commands", "Routerbefehle"}, + {"Local Destinations", "Lokale Ziele"}, {"LeaseSets", "LeaseSets"}, {"Tunnels", "Tunnel"}, {"Transit Tunnels", "Transittunnel"}, {"Transports", "Transporte"}, - {"I2P tunnels", "I2P Tunnel"}, - {"SAM sessions", "SAM Sitzungen"}, + {"I2P tunnels", "I2P-Tunnel"}, + {"SAM sessions", "SAM-Sitzungen"}, {"ERROR", "FEHLER"}, {"OK", "OK"}, {"Testing", "Testen"}, - {"Firewalled", "Hinter eine Firewall"}, + {"Firewalled", "Hinter einer Firewall"}, {"Unknown", "Unbekannt"}, {"Proxy", "Proxy"}, {"Mesh", "Mesh"}, @@ -66,7 +66,7 @@ namespace german // language namespace {"Network status v6", "Netzwerkstatus v6"}, {"Stopping in", "Stoppt in"}, {"Family", "Familie"}, - {"Tunnel creation success rate", "Erfolgsrate der Tunnelerstellung"}, + {"Tunnel creation success rate", "Tunnelerstellungs-Erfolgsrate"}, {"Received", "Eingegangen"}, {"KiB/s", "KiB/s"}, {"Sent", "Gesendet"}, @@ -81,12 +81,12 @@ namespace german // language namespace {"supported", "unterstützt"}, {"Routers", "Router"}, {"Floodfills", "Floodfills"}, - {"Client Tunnels", "Klienttunnel"}, + {"Client Tunnels", "Clienttunnel"}, {"Services", "Services"}, {"Enabled", "Aktiviert"}, {"Disabled", "Deaktiviert"}, {"Encrypted B33 address", "Verschlüsselte B33 Adresse"}, - {"Address registration line", "Adresseregistrierungszeile"}, + {"Address registration line", "Adressregistrierungszeile"}, {"Domain", "Domain"}, {"Generate", "Generieren"}, {"Note: result string can be used only for registering 2LD domains (example.i2p). For registering subdomains please use i2pd-tools.", "Hinweis: Der resultierende String kann nur für die Registrierung einer 2LD Domain (beispiel.i2p) benutzt werden. Für die Registrierung von Subdomains kann i2pd-tools verwendet werden."}, @@ -99,12 +99,12 @@ namespace german // language namespace {"Tags", "Tags"}, {"Incoming", "Eingehend"}, {"Outgoing", "Ausgehend"}, - {"Destination", "Destination"}, + {"Destination", "Ziel"}, {"Amount", "Anzahl"}, {"Incoming Tags", "Eingehende Tags"}, {"Tags sessions", "Tags Sitzungen"}, {"Status", "Status"}, - {"Local Destination", "Lokale Destination"}, + {"Local Destination", "Lokales Ziel"}, {"Streams", "Streams"}, {"Close stream", "Stream schließen"}, {"I2CP session not found", "I2CP Sitzung nicht gefunden"}, @@ -118,66 +118,66 @@ namespace german // language namespace {"EndDate", "Enddatum"}, {"not floodfill", "kein Floodfill"}, {"Queue size", "Warteschlangengröße"}, - {"Run peer test", "Peer-Test ausführen"}, + {"Run peer test", "Peer-Test durchführen"}, {"Decline transit tunnels", "Transittunnel ablehnen"}, {"Accept transit tunnels", "Transittunnel akzeptieren"}, {"Cancel graceful shutdown", "Beende das kontrollierte herunterfahren"}, {"Start graceful shutdown", "Starte das kontrollierte Herunterfahren"}, {"Force shutdown", "Herunterfahren erzwingen"}, - {"Reload external CSS styles", "Lade externe CSS-Styles neu"}, + {"Reload external CSS styles", "Lade externe CSS-Stile neu"}, {"Note: any action done here are not persistent and not changes your config files.", "Hinweis: Alle hier durchgeführten Aktionen sind nicht dauerhaft und ändern die Konfigurationsdateien nicht."}, {"Logging level", "Protokollierungslevel"}, {"Transit tunnels limit", "Limit für Transittunnel"}, - {"Change", "Verändern"}, + {"Change", "Ändern"}, {"Change language", "Sprache ändern"}, {"no transit tunnels currently built", "derzeit keine Transittunnel aufgebaut"}, {"SAM disabled", "SAM deaktiviert"}, {"no sessions currently running", "Derzeit keine laufenden Sitzungen"}, - {"SAM session not found", "SAM Sitzung nicht gefunden"}, - {"SAM Session", "SAM Sitzung"}, + {"SAM session not found", "SAM-Sitzung nicht gefunden"}, + {"SAM Session", "SAM-Sitzung"}, {"Server Tunnels", "Servertunnel"}, - {"Client Forwards", "Klient-Weiterleitungen"}, + {"Client Forwards", "Client-Weiterleitungen"}, {"Server Forwards", "Server-Weiterleitungen"}, {"Unknown page", "Unbekannte Seite"}, {"Invalid token", "Ungültiger Token"}, {"SUCCESS", "ERFOLGREICH"}, {"Stream closed", "Stream geschlossen"}, {"Stream not found or already was closed", "Stream nicht gefunden oder bereits geschlossen"}, - {"Destination not found", "Destination nicht gefunden"}, + {"Destination not found", "Ziel nicht gefunden"}, {"StreamID can't be null", "StreamID kann nicht null sein"}, - {"Return to destination page", "Zurück zur Destination-Seite"}, + {"Return to destination page", "Zurück zur Ziel-Seite"}, {"You will be redirected in 5 seconds", "Du wirst in 5 Sekunden weitergeleitet"}, {"Transit tunnels count must not exceed 65535", "Es darf maximal 65535 Transittunnel geben"}, - {"Back to commands list", "Zurück zur Kommandoliste"}, + {"Back to commands list", "Zurück zur Befehlsliste"}, {"Register at reg.i2p", "Auf reg.i2p registrieren"}, {"Description", "Beschreibung"}, - {"A bit information about service on domain", "Ein bisschen Informationen über den Service auf der Domain"}, - {"Submit", "Einreichen"}, - {"Domain can't end with .b32.i2p", "Domain kann nicht mit .b32.i2p enden"}, - {"Domain must end with .i2p", "Domain muss mit .i2p enden"}, - {"Such destination is not found", "Eine solche Destination konnte nicht gefunden werden"}, + {"A bit information about service on domain", "Ein paar Informationen über den Service auf der Domain"}, + {"Submit", "Absenden"}, + {"Domain can't end with .b32.i2p", "Domain kann nicht auf .b32.i2p enden"}, + {"Domain must end with .i2p", "Domain muss auf .i2p enden"}, + {"Such destination is not found", "Ein solches Ziel konnte nicht gefunden werden"}, {"Unknown command", "Unbekannter Befehl"}, {"Command accepted", "Befehl akzeptiert"}, {"Proxy error", "Proxy-Fehler"}, {"Proxy info", "Proxy-Info"}, {"Proxy error: Host not found", "Proxy-Fehler: Host nicht gefunden"}, - {"Remote host not found in router's addressbook", "Remote-Host nicht im Router Adressbuch gefunden"}, - {"You may try to find this host on jump services below", "Vielleicht kannst du diesen Host auf einen der Jump-Services unten finden"}, + {"Remote host not found in router's addressbook", "Remote-Host nicht im Router-Adressbuch gefunden"}, + {"You may try to find this host on jump services below", "Vielleicht kannst du diesen Host auf einem der nachfolgenden Jump-Services finden"}, {"Invalid request", "Ungültige Anfrage"}, - {"Proxy unable to parse your request", "Proxy konnte die Anfrage nicht interpretieren"}, - {"addresshelper is not supported", "addresshelper wird nicht unterstützt"}, + {"Proxy unable to parse your request", "Proxy konnte die Anfrage nicht verarbeiten"}, + {"addresshelper is not supported", "Addresshelfer wird nicht unterstützt"}, {"Host", "Host"}, - {"added to router's addressbook from helper", "vom Helfer zum Router Adressbuch hinzugefügt"}, + {"added to router's addressbook from helper", "vom Helfer zum Router-Adressbuch hinzugefügt"}, {"Click here to proceed:", "Klicke hier um fortzufahren:"}, {"Continue", "Fortsetzen"}, {"Addresshelper found", "Adresshelfer gefunden"}, {"already in router's addressbook", "bereits im Adressbuch des Routers"}, {"Click here to update record:", "Klicke hier, um den Eintrag zu aktualisieren:"}, {"invalid request uri", "ungültige Anfrage-URI"}, - {"Can't detect destination host from request", "Kann Anhand der Anfrage den Destination-Host nicht erkennen"}, + {"Can't detect destination host from request", "Kann den Ziel-Host von der Anfrage nicht erkennen"}, {"Outproxy failure", "Outproxy-Fehler"}, {"bad outproxy settings", "ungültige Outproxy-Einstellungen"}, - {"not inside I2P network, but outproxy is not enabled", "nicht innerhalb des I2P-Netzwerks, aber Outproxy ist nicht aktiviert"}, + {"not inside I2P network, but outproxy is not enabled", "außerhalb des I2P-Netzwerks, aber Outproxy ist nicht aktiviert"}, {"unknown outproxy url", "unbekannte Outproxy-URL"}, {"cannot resolve upstream proxy", "kann den Upstream-Proxy nicht auflösen"}, {"hostname too long", "Hostname zu lang"}, @@ -192,7 +192,7 @@ namespace german // language namespace {"http out proxy not implemented", "HTTP-Outproxy nicht implementiert"}, {"cannot connect to upstream http proxy", "Kann nicht zu Upstream-HTTP-Proxy verbinden"}, {"Host is down", "Host ist offline"}, - {"Can't create connection to requested host, it may be down. Please try again later.", "Konnte keine Verbindung zum angefragten Host aufbaunen, vielleicht ist es offline. Versuche es später noch einmal."}, + {"Can't create connection to requested host, it may be down. Please try again later.", "Konnte keine Verbindung zum angefragten Host aufbauen, vielleicht ist er offline. Versuche es später noch mal."}, {"", ""}, }; From 5dbc7a8ca401c84e9f84d08164073fb9e7e71208 Mon Sep 17 00:00:00 2001 From: Gecero-Sensei <27288418+Gecero@users.noreply.github.com> Date: Tue, 19 Jul 2022 21:57:17 +0200 Subject: [PATCH 058/219] Minor corrections and wording changes --- i18n/German.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/i18n/German.cpp b/i18n/German.cpp index 33e40a0f..b4b15cd9 100644 --- a/i18n/German.cpp +++ b/i18n/German.cpp @@ -40,7 +40,7 @@ namespace german // language namespace {"established", "hergestellt"}, {"unknown", "Unbekannt"}, {"exploratory", "erforschend"}, - {"i2pd webconsole", "i2pd Webkonsole"}, + {"i2pd webconsole", "i2pd-Webkonsole"}, {"Main page", "Startseite"}, {"Router commands", "Routerbefehle"}, {"Local Destinations", "Lokale Ziele"}, @@ -66,7 +66,7 @@ namespace german // language namespace {"Network status v6", "Netzwerkstatus v6"}, {"Stopping in", "Stoppt in"}, {"Family", "Familie"}, - {"Tunnel creation success rate", "Tunnelerstellungs-Erfolgsrate"}, + {"Tunnel creation success rate", "Erfolgsrate der Tunnelerstellung"}, {"Received", "Eingegangen"}, {"KiB/s", "KiB/s"}, {"Sent", "Gesendet"}, @@ -85,11 +85,11 @@ namespace german // language namespace {"Services", "Services"}, {"Enabled", "Aktiviert"}, {"Disabled", "Deaktiviert"}, - {"Encrypted B33 address", "Verschlüsselte B33 Adresse"}, + {"Encrypted B33 address", "Verschlüsselte B33-Adresse"}, {"Address registration line", "Adressregistrierungszeile"}, {"Domain", "Domain"}, {"Generate", "Generieren"}, - {"Note: result string can be used only for registering 2LD domains (example.i2p). For registering subdomains please use i2pd-tools.", "Hinweis: Der resultierende String kann nur für die Registrierung einer 2LD Domain (beispiel.i2p) benutzt werden. Für die Registrierung von Subdomains kann i2pd-tools verwendet werden."}, + {"Note: result string can be used only for registering 2LD domains (example.i2p). For registering subdomains please use i2pd-tools.", "Hinweis: Der resultierende String kann nur für die Registrierung einer 2LD-Domain (beispiel.i2p) benutzt werden. Für die Registrierung von Subdomains kann i2pd-tools verwendet werden."}, {"Address", "Adresse"}, {"Type", "Typ"}, {"EncType", "Verschlüsselungstyp"}, @@ -102,12 +102,12 @@ namespace german // language namespace {"Destination", "Ziel"}, {"Amount", "Anzahl"}, {"Incoming Tags", "Eingehende Tags"}, - {"Tags sessions", "Tags Sitzungen"}, + {"Tags sessions", "Tags-Sitzungen"}, {"Status", "Status"}, {"Local Destination", "Lokales Ziel"}, {"Streams", "Streams"}, {"Close stream", "Stream schließen"}, - {"I2CP session not found", "I2CP Sitzung nicht gefunden"}, + {"I2CP session not found", "I2CP-Sitzung nicht gefunden"}, {"I2CP is not enabled", "I2CP ist nicht aktiviert"}, {"Invalid", "Ungültig"}, {"Store type", "Speichertyp"}, @@ -117,11 +117,11 @@ namespace german // language namespace {"TunnelID", "TunnelID"}, {"EndDate", "Enddatum"}, {"not floodfill", "kein Floodfill"}, - {"Queue size", "Warteschlangengröße"}, + {"Queue size", "Größe der Warteschlange"}, {"Run peer test", "Peer-Test durchführen"}, {"Decline transit tunnels", "Transittunnel ablehnen"}, {"Accept transit tunnels", "Transittunnel akzeptieren"}, - {"Cancel graceful shutdown", "Beende das kontrollierte herunterfahren"}, + {"Cancel graceful shutdown", "Beende das kontrollierte Herunterfahren"}, {"Start graceful shutdown", "Starte das kontrollierte Herunterfahren"}, {"Force shutdown", "Herunterfahren erzwingen"}, {"Reload external CSS styles", "Lade externe CSS-Stile neu"}, From 5f9f23eb3f5e087bb6674e536c11bba0a49b6e99 Mon Sep 17 00:00:00 2001 From: Gecero-Sensei <27288418+Gecero@users.noreply.github.com> Date: Tue, 19 Jul 2022 22:49:56 +0200 Subject: [PATCH 059/219] Added translation of webconsole site title --- daemon/HTTPServer.cpp | 2 +- i18n/German.cpp | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/daemon/HTTPServer.cpp b/daemon/HTTPServer.cpp index a325ad4b..b0b537e6 100644 --- a/daemon/HTTPServer.cpp +++ b/daemon/HTTPServer.cpp @@ -182,7 +182,7 @@ namespace http { " \r\n" " \r\n" " \r\n" - " Purple I2P Webconsole\r\n"; + " " << tr("Purple I2P Webconsole") << "\r\n"; GetStyles(s); s << "\r\n" diff --git a/i18n/German.cpp b/i18n/German.cpp index b4b15cd9..f114bf8e 100644 --- a/i18n/German.cpp +++ b/i18n/German.cpp @@ -31,6 +31,7 @@ namespace german // language namespace static std::map strings { + {"Purple I2P Webconsole", "Purple-I2P-Webkonsole"}, {"KiB", "KiB"}, {"MiB", "MiB"}, {"GiB", "GiB"}, From d33aeb4bb203aacfa05e6691a76f478c24725b25 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 21 Jul 2022 19:38:18 -0400 Subject: [PATCH 060/219] set unreachable if firewalled. Store router's hash of introducer instead session --- libi2pd/RouterContext.cpp | 6 ++++++ libi2pd/RouterContext.h | 1 + libi2pd/SSU2.cpp | 44 ++++++++++++++++++++++++++++----------- libi2pd/SSU2.h | 2 +- 4 files changed, 40 insertions(+), 13 deletions(-) diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index c9e4972c..1d5afc06 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -589,6 +589,12 @@ namespace i2p } } + void RouterContext::SetUnreachableSSU2 (bool v4, bool v6) + { + if (IsSSU2Only ()) + SetUnreachable (v4, v6); + } + void RouterContext::SetUnreachable (bool v4, bool v6) { if (v4 || (v6 && !SupportsV4 ())) diff --git a/libi2pd/RouterContext.h b/libi2pd/RouterContext.h index 6d575912..ad3514bf 100644 --- a/libi2pd/RouterContext.h +++ b/libi2pd/RouterContext.h @@ -127,6 +127,7 @@ namespace garlic void RemoveSSU2Introducer (const i2p::data::IdentHash& h, bool v4); bool IsUnreachable () const; void SetUnreachable (bool v4, bool v6); + void SetUnreachableSSU2 (bool v4, bool v6); void SetReachable (bool v4, bool v6); bool IsFloodfill () const { return m_IsFloodfill; }; void SetFloodfill (bool floodfill); diff --git a/libi2pd/SSU2.cpp b/libi2pd/SSU2.cpp index 52a38244..2a6058bc 100644 --- a/libi2pd/SSU2.cpp +++ b/libi2pd/SSU2.cpp @@ -761,25 +761,29 @@ namespace transport void SSU2Server::UpdateIntroducers (bool v4) { uint32_t ts = i2p::util::GetSecondsSinceEpoch (); - std::list> newList; + std::list newList; auto& introducers = v4 ? m_Introducers : m_IntroducersV6; std::set excluded; for (const auto& it : introducers) { - if (it->IsEstablished ()) + std::shared_ptr session; + auto it1 = m_SessionsByRouterHash.find (it); + if (it1 != m_SessionsByRouterHash.end ()) + session = it1->second; + if (session && session->IsEstablished ()) { - if (ts < it->GetCreationTime () + SSU2_TO_INTRODUCER_SESSION_EXPIRATION) - it->SendKeepAlive (); - if (ts < it->GetCreationTime () + SSU2_TO_INTRODUCER_SESSION_DURATION) + if (ts < session->GetCreationTime () + SSU2_TO_INTRODUCER_SESSION_EXPIRATION) + session->SendKeepAlive (); + if (ts < session->GetCreationTime () + SSU2_TO_INTRODUCER_SESSION_DURATION) { newList.push_back (it); - excluded.insert (it->GetRemoteIdentity ()->GetIdentHash ()); + excluded.insert (it); } else - i2p::context.RemoveSSU2Introducer (it->GetRemoteIdentity ()->GetIdentHash (), it->GetAddress ()->IsV4 ()); + session = nullptr; } - else - i2p::context.RemoveSSU2Introducer (it->GetRemoteIdentity ()->GetIdentHash (), it->GetAddress ()->IsV4 ()); + if (!session) + i2p::context.RemoveSSU2Introducer (it, v4); } if (newList.size () < SSU2_MAX_NUM_INTRODUCERS) { @@ -789,7 +793,11 @@ namespace transport // bump creation time for previous introducers if no new sessions found LogPrint (eLogDebug, "SSU2: No new introducers found. Trying to reuse existing"); for (auto& it : introducers) - it->SetCreationTime (it->GetCreationTime () + SSU2_TO_INTRODUCER_SESSION_DURATION); + { + auto it1 = m_SessionsByRouterHash.find (it); + if (it1 != m_SessionsByRouterHash.end ()) + it1->second->SetCreationTime (it1->second->GetCreationTime () + SSU2_TO_INTRODUCER_SESSION_DURATION); + } // try again excluded.clear (); sessions = FindIntroducers (SSU2_MAX_NUM_INTRODUCERS - newList.size (), v4, excluded); @@ -802,9 +810,11 @@ namespace transport introducer.iKey = it->GetRemoteIdentity ()->GetIdentHash (); introducer.iExp = it->GetCreationTime () + SSU2_TO_INTRODUCER_SESSION_EXPIRATION; excluded.insert (it->GetRemoteIdentity ()->GetIdentHash ()); - if (i2p::context.AddSSU2Introducer (introducer, it->GetAddress ()->IsV4 ())) + if (i2p::context.AddSSU2Introducer (introducer, v4)) { - newList.push_back (it); + LogPrint (eLogDebug, "SSU2: Introducer added ", it->GetRelayTag (), " at ", + i2p::data::GetIdentHashAbbreviation (it->GetRemoteIdentity ()->GetIdentHash ())); + newList.push_back (it->GetRemoteIdentity ()->GetIdentHash ()); if (newList.size () >= SSU2_MAX_NUM_INTRODUCERS) break; } } @@ -895,6 +905,11 @@ namespace transport m_Introducers.clear (); return; } + // we are firewalled + auto addr = i2p::context.GetRouterInfo ().GetSSU2V4Address (); + if (addr && addr->ssu && addr->ssu->introducers.empty ()) + i2p::context.SetUnreachableSSU2 (true, false); // v4 + UpdateIntroducers (true); ScheduleIntroducersUpdateTimer (); } @@ -912,6 +927,11 @@ namespace transport m_IntroducersV6.clear (); return; } + // we are firewalled + auto addr = i2p::context.GetRouterInfo ().GetSSU2V6Address (); + if (addr && addr->ssu && addr->ssu->introducers.empty ()) + i2p::context.SetUnreachableSSU2 (false, true); // v6 + UpdateIntroducers (false); ScheduleIntroducersUpdateTimerV6 (); } diff --git a/libi2pd/SSU2.h b/libi2pd/SSU2.h index 5e0bba6b..b705f222 100644 --- a/libi2pd/SSU2.h +++ b/libi2pd/SSU2.h @@ -120,7 +120,7 @@ namespace transport std::map > m_PendingOutgoingSessions; std::map > m_IncomingTokens, m_OutgoingTokens; // remote endpoint -> (token, expires in seconds) std::map > m_Relays; // we are introducer, relay tag -> session - std::list > m_Introducers, m_IntroducersV6; // introducers we are connected to + std::list m_Introducers, m_IntroducersV6; // introducers we are connected to i2p::util::MemoryPoolMt m_PacketsPool; boost::asio::deadline_timer m_TerminationTimer, m_ResendTimer, m_IntroducersUpdateTimer, m_IntroducersUpdateTimerV6; From 454fa9ee9b8243edb49a85d0e1a01a48fcd9896d Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 22 Jul 2022 14:52:24 -0400 Subject: [PATCH 061/219] update SSU2 port --- libi2pd/RouterContext.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index 1d5afc06..0624ff3e 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -288,7 +288,7 @@ namespace i2p bool updated = false; for (auto& address : m_RouterInfo.GetAddresses ()) { - if (!address->IsNTCP2 () && !address->IsSSU2 () && address->port != port) + if (address->port != port && (address->transportStyle == i2p::data::RouterInfo::eTransportSSU || IsSSU2Only ())) { address->port = port; updated = true; @@ -653,7 +653,7 @@ namespace i2p addr->published = true; addr->caps |= i2p::data::RouterInfo::eSSUIntroducer; addr->ssu->introducers.clear (); - if (!addr->IsSSU2 ()) + if (addr->port && (!addr->IsSSU2 () || IsSSU2Only ())) port = addr->port; } // publish NTCP2 @@ -744,6 +744,7 @@ namespace i2p if (ssu2Published) { uint16_t ssu2Port; i2p::config::GetOption ("ssu2.port", ssu2Port); + if (!ssu2Port) ssu2Port = port; m_RouterInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, boost::asio::ip::address::from_string ("::1"), ssu2Port); } else @@ -824,6 +825,7 @@ namespace i2p if (ssu2Published) { uint16_t ssu2Port; i2p::config::GetOption ("ssu2.port", ssu2Port); + if (!ssu2Port) ssu2Port = port; m_RouterInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, boost::asio::ip::address::from_string ("127.0.0.1"), ssu2Port); } else From 3683ec6a959ff97c5ec578fa652ac0c33cccdb15 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 22 Jul 2022 15:16:42 -0400 Subject: [PATCH 062/219] fixed race condition --- libi2pd/NetDb.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/libi2pd/NetDb.cpp b/libi2pd/NetDb.cpp index 42d73c97..e36e4f13 100644 --- a/libi2pd/NetDb.cpp +++ b/libi2pd/NetDb.cpp @@ -271,7 +271,10 @@ namespace data if (r->IsNewer (buf, len)) { bool wasFloodfill = r->IsFloodfill (); - r->Update (buf, len); + { + std::unique_lock l(m_RouterInfosMutex); + r->Update (buf, len); + } LogPrint (eLogInfo, "NetDb: RouterInfo updated: ", ident.ToBase64()); if (wasFloodfill != r->IsFloodfill ()) // if floodfill status updated { From 6ff64352d3397af3e812a4e9616fd6bff450deb4 Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 23 Jul 2022 14:32:16 -0400 Subject: [PATCH 063/219] don't create and oublish duplicates --- libi2pd/SSU2.cpp | 33 +++++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/libi2pd/SSU2.cpp b/libi2pd/SSU2.cpp index 2a6058bc..c9b3551e 100644 --- a/libi2pd/SSU2.cpp +++ b/libi2pd/SSU2.cpp @@ -479,7 +479,19 @@ namespace transport { if (router && address) { - // check is no peding session + // check if no session + auto it = m_SessionsByRouterHash.find (router->GetIdentHash ()); + if (it != m_SessionsByRouterHash.end ()) + { + // session with router found, trying to send peer test if requested + if (peerTest && it->second->IsEstablished ()) + { + auto session = it->second; + GetService ().post ([session]() { session->SendPeerTest (); }); + } + return false; + } + // check is no pending session bool isValidEndpoint = !address->host.is_unspecified () && address->port; if (isValidEndpoint) { @@ -769,16 +781,16 @@ namespace transport std::shared_ptr session; auto it1 = m_SessionsByRouterHash.find (it); if (it1 != m_SessionsByRouterHash.end ()) + { session = it1->second; + excluded.insert (it); + } if (session && session->IsEstablished ()) { if (ts < session->GetCreationTime () + SSU2_TO_INTRODUCER_SESSION_EXPIRATION) session->SendKeepAlive (); if (ts < session->GetCreationTime () + SSU2_TO_INTRODUCER_SESSION_DURATION) - { newList.push_back (it); - excluded.insert (it); - } else session = nullptr; } @@ -796,11 +808,16 @@ namespace transport { auto it1 = m_SessionsByRouterHash.find (it); if (it1 != m_SessionsByRouterHash.end ()) - it1->second->SetCreationTime (it1->second->GetCreationTime () + SSU2_TO_INTRODUCER_SESSION_DURATION); + { + auto session = it1->second; + if (session->IsEstablished ()) + { + session->SetCreationTime (session->GetCreationTime () + SSU2_TO_INTRODUCER_SESSION_DURATION); + if (std::find (newList.begin (), newList.end (), it) == newList.end ()) + newList.push_back (it); + } + } } - // try again - excluded.clear (); - sessions = FindIntroducers (SSU2_MAX_NUM_INTRODUCERS - newList.size (), v4, excluded); } for (const auto& it : sessions) From b860a4799d5250ffc7028e85ea325fb7742afe44 Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 23 Jul 2022 16:17:30 -0400 Subject: [PATCH 064/219] testing cap for published SSU2 address --- libi2pd/RouterInfo.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd/RouterInfo.cpp b/libi2pd/RouterInfo.cpp index 4dae397e..9293c35e 100644 --- a/libi2pd/RouterInfo.cpp +++ b/libi2pd/RouterInfo.cpp @@ -727,7 +727,7 @@ namespace data addr->host = host; addr->port = port; addr->published = true; - addr->caps = 0; + addr->caps = i2p::data::RouterInfo::eSSUTesting | i2p::data::RouterInfo::eSSUIntroducer; // BC; addr->date = 0; addr->ssu.reset (new SSUExt ()); addr->ssu->mtu = 0; From 4d0047ae7c9fda2d1b8e57a472da334abed37c2b Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 23 Jul 2022 18:48:53 -0400 Subject: [PATCH 065/219] request termination for existing session --- libi2pd/SSU2.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/libi2pd/SSU2.cpp b/libi2pd/SSU2.cpp index c9b3551e..de58d728 100644 --- a/libi2pd/SSU2.cpp +++ b/libi2pd/SSU2.cpp @@ -267,9 +267,9 @@ namespace transport if (!ret.second) { // session already exists - LogPrint (eLogWarning, "SSU2: Session to ", ident->GetIdentHash ().ToBase64 (), " aready exists"); + LogPrint (eLogWarning, "SSU2: Session to ", ident->GetIdentHash ().ToBase64 (), " already exists"); // terminate existing - GetService ().post (std::bind (&SSU2Session::Terminate, ret.first->second)); + GetService ().post (std::bind (&SSU2Session::RequestTermination, ret.first->second, eSSU2TerminationReasonTerminationReceived)); // update session ret.first->second = session; } @@ -572,7 +572,8 @@ namespace transport auto addr = address->IsV6 () ? r->GetSSU2V6Address () : r->GetSSU2V4Address (); if (addr) { - bool isValidEndpoint = !addr->host.is_unspecified () && addr->port; + bool isValidEndpoint = !addr->host.is_unspecified () && addr->port && + !i2p::util::net::IsInReservedRange(addr->host); if (isValidEndpoint) { auto s = FindPendingOutgoingSession (boost::asio::ip::udp::endpoint (addr->host, addr->port)); From 09aa96e4863832ce676f25bef0e012737708c22f Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 23 Jul 2022 19:48:37 -0400 Subject: [PATCH 066/219] always bring to closing state if termination requested --- libi2pd/SSU2Session.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index 4890a61d..8593981d 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -187,10 +187,10 @@ namespace transport { if (m_State == eSSU2SessionStateEstablished || m_State == eSSU2SessionStateClosing) { - m_State = eSSU2SessionStateClosing; m_TerminationReason = reason; SendTermination (); - } + } + m_State = eSSU2SessionStateClosing; } void SSU2Session::Established () From dbb9295063cfd32edb298d828b6cfba96f235230 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 24 Jul 2022 15:24:01 -0400 Subject: [PATCH 067/219] set MTU if local address is specified explicitly. update MTU for ipv6 if not set --- libi2pd/RouterContext.cpp | 76 +++++++++++++++++++++++++++++---------- libi2pd/RouterContext.h | 1 + libi2pd/SSU2.cpp | 13 +++++++ 3 files changed, 72 insertions(+), 18 deletions(-) diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index 0624ff3e..e9489475 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -420,27 +420,30 @@ namespace i2p if (address->host != host && address->IsCompatible (host) && !i2p::util::net::IsYggdrasilAddress (address->host)) { + // update host address->host = host; - if (host.is_v6 () && (address->transportStyle == i2p::data::RouterInfo::eTransportSSU || address->IsSSU2 ())) - { - // update MTU - auto mtu = i2p::util::net::GetMTU (host); - if (mtu) - { - LogPrint (eLogDebug, "Router: Our v6 MTU=", mtu); - int maxMTU = i2p::util::net::GetMaxMTU (host.to_v6 ()); - if (mtu > maxMTU) - { - mtu = maxMTU; - LogPrint(eLogWarning, "Router: MTU dropped to upper limit of ", maxMTU, " bytes"); - } - if (mtu && !address->IsSSU2 ()) // SSU1 - mtu = (mtu >> 4) << 4; // round to multiple of 16 - if (address->ssu) address->ssu->mtu = mtu; - } - } updated = true; } + if (host.is_v6 () && address->IsV6 () && address->ssu && + (!address->ssu->mtu || updated)) + { + // update MTU + auto mtu = i2p::util::net::GetMTU (host); + if (mtu) + { + LogPrint (eLogDebug, "Router: Our v6 MTU=", mtu); + int maxMTU = i2p::util::net::GetMaxMTU (host.to_v6 ()); + if (mtu > maxMTU) + { + mtu = maxMTU; + LogPrint(eLogWarning, "Router: MTU dropped to upper limit of ", maxMTU, " bytes"); + } + if (mtu && !address->IsSSU2 ()) // SSU1 + mtu = (mtu >> 4) << 4; // round to multiple of 16 + address->ssu->mtu = mtu; + updated = true; + } + } } auto ts = i2p::util::GetSecondsSinceEpoch (); if (updated || ts > m_LastUpdateTime + ROUTER_INFO_UPDATE_INTERVAL) @@ -866,6 +869,43 @@ namespace i2p UpdateRouterInfo (); } + void RouterContext::SetMTU (int mtu, bool v4) + { + if (mtu < 1280 || mtu > 1500) return; + auto& addresses = m_RouterInfo.GetAddresses (); + for (auto& addr: addresses) + { + if (addr->ssu && ((v4 && addr->IsV4 ()) || (!v4 && addr->IsV6 ()))) + { + if (!addr->IsSSU2 ()) // SSU1 + { + // round to multiple of 16 + if (v4) + { + if (mtu > 1484) mtu = 1484; + else + { + mtu -= 12; + mtu = (mtu >> 4) << 4; + mtu += 12; + } + } + else + { + if (mtu > 1488) mtu = 1488; + else + mtu = (mtu >> 4) << 4; + } + } + if (mtu) + { + addr->ssu->mtu = mtu; + LogPrint (eLogDebug, "Router: MTU for ", v4 ? "ipv4" : "ipv6", " address is set to ", mtu); + } + } + } + } + void RouterContext::UpdateNTCP2V6Address (const boost::asio::ip::address& host) { bool isYgg = i2p::util::net::IsYggdrasilAddress (host); diff --git a/libi2pd/RouterContext.h b/libi2pd/RouterContext.h index ad3514bf..4946b7ca 100644 --- a/libi2pd/RouterContext.h +++ b/libi2pd/RouterContext.h @@ -144,6 +144,7 @@ namespace garlic void SetSupportsV6 (bool supportsV6); void SetSupportsV4 (bool supportsV4); void SetSupportsMesh (bool supportsmesh, const boost::asio::ip::address_v6& host); + void SetMTU (int mtu, bool v4); i2p::crypto::NoiseSymmetricState& GetCurrentNoiseState () { return m_CurrentNoiseState; }; void UpdateNTCP2V6Address (const boost::asio::ip::address& host); // called from Daemon. TODO: remove diff --git a/libi2pd/SSU2.cpp b/libi2pd/SSU2.cpp index de58d728..2c754e6b 100644 --- a/libi2pd/SSU2.cpp +++ b/libi2pd/SSU2.cpp @@ -115,9 +115,22 @@ namespace transport { if (localAddress.is_unspecified ()) return; if (localAddress.is_v4 ()) + { m_AddressV4 = localAddress; + int mtu = i2p::util::net::GetMTU (localAddress); + if (mtu < (int)SSU2_MIN_PACKET_SIZE) mtu = SSU2_MIN_PACKET_SIZE; + if (mtu > (int)SSU2_MAX_PACKET_SIZE) mtu = SSU2_MAX_PACKET_SIZE; + i2p::context.SetMTU (mtu, true); + } else if (localAddress.is_v6 ()) + { m_AddressV6 = localAddress; + int maxMTU = i2p::util::net::GetMaxMTU (localAddress.to_v6 ()); + int mtu = i2p::util::net::GetMTU (localAddress); + if (mtu > maxMTU) mtu = maxMTU; + if (mtu < (int)SSU2_MIN_PACKET_SIZE) mtu = SSU2_MIN_PACKET_SIZE; + i2p::context.SetMTU (mtu, false); + } } bool SSU2Server::IsSupported (const boost::asio::ip::address& addr) const From 93d879b2975ef60d12d8417114d951e0d6faf7ba Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 24 Jul 2022 15:39:46 -0400 Subject: [PATCH 068/219] more tunnel brokers ranges --- libi2pd/util.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libi2pd/util.cpp b/libi2pd/util.cpp index 4c66e07b..5bd0fb00 100644 --- a/libi2pd/util.cpp +++ b/libi2pd/util.cpp @@ -436,8 +436,10 @@ namespace net case 0x260070ff: // Hurricane Electric return 1480; - break; + break; + case 0x2a06a003: case 0x2a06a004: + case 0x2a06a005: // route48 return 1420; break; From fe744f8f81e84079f30f9be17a8bd1da7a4d8d0e Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 24 Jul 2022 16:44:02 -0400 Subject: [PATCH 069/219] more routine cleanup --- libi2pd/SSU2.cpp | 19 ++++++++++++++++++- libi2pd/SSU2.h | 2 +- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/libi2pd/SSU2.cpp b/libi2pd/SSU2.cpp index 2c754e6b..2f7c1e74 100644 --- a/libi2pd/SSU2.cpp +++ b/libi2pd/SSU2.cpp @@ -679,6 +679,22 @@ namespace transport it.second->CleanUp (ts); } + for (auto it = m_SessionsByRouterHash.begin (); it != m_SessionsByRouterHash.begin ();) + { + if (it->second && it->second->GetState () == eSSU2SessionStateTerminated) + it = m_SessionsByRouterHash.erase (it); + else + it++; + } + + for (auto it = m_Relays.begin (); it != m_Relays.begin ();) + { + if (it->second && it->second->GetState () == eSSU2SessionStateTerminated) + it = m_Relays.erase (it); + else + it++; + } + for (auto it = m_IncomingTokens.begin (); it != m_IncomingTokens.end (); ) { if (ts > it->second.second) @@ -694,7 +710,8 @@ namespace transport else it++; } - + + m_PacketsPool.CleanUpMt (); ScheduleTermination (); } } diff --git a/libi2pd/SSU2.h b/libi2pd/SSU2.h index b705f222..1625080b 100644 --- a/libi2pd/SSU2.h +++ b/libi2pd/SSU2.h @@ -116,7 +116,7 @@ namespace transport boost::asio::ip::udp::socket m_SocketV4, m_SocketV6; boost::asio::ip::address m_AddressV4, m_AddressV6; std::unordered_map > m_Sessions; - std::map > m_SessionsByRouterHash; + std::unordered_map > m_SessionsByRouterHash; std::map > m_PendingOutgoingSessions; std::map > m_IncomingTokens, m_OutgoingTokens; // remote endpoint -> (token, expires in seconds) std::map > m_Relays; // we are introducer, relay tag -> session From 617f45bc59fea3350ab0da605fb4f5bfdc208625 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 24 Jul 2022 19:44:49 -0400 Subject: [PATCH 070/219] try to send I2NP message in one packet, reduce or drop Ack block if necessary --- libi2pd/SSU2Session.cpp | 49 +++++++++++++++++++++++++++++++---------- 1 file changed, 37 insertions(+), 12 deletions(-) diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index 8593981d..afa38df7 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -264,31 +264,56 @@ namespace transport { auto nextResend = i2p::util::GetSecondsSinceEpoch () + SSU2_RESEND_INTERVAL; auto packet = std::make_shared(); - packet->payloadSize += CreateAckBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize); + size_t ackBlockSize = CreateAckBlock (packet->payload, m_MaxPayloadSize); + packet->payloadSize += ackBlockSize; while (!m_SendQueue.empty () && m_SentPackets.size () <= m_WindowSize) { auto msg = m_SendQueue.front (); - size_t len = msg->GetNTCP2Length (); - if (len + 3 < m_MaxPayloadSize - packet->payloadSize) - { - m_SendQueue.pop_front (); - packet->payloadSize += CreateI2NPBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize, std::move (msg)); - } - else if (len > m_MaxPayloadSize) // message too long + size_t len = msg->GetNTCP2Length () + 3; + if (len > m_MaxPayloadSize) // message too long { m_SendQueue.pop_front (); SendFragmentedMessage (msg); } + else if (packet->payloadSize + len <= m_MaxPayloadSize) + { + m_SendQueue.pop_front (); + packet->payloadSize += CreateI2NPBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize, std::move (msg)); + } else { + // create new packet and copy ack block + auto newPacket = std::make_shared(); + memcpy (newPacket->payload, packet->payload, ackBlockSize); + newPacket->payloadSize = ackBlockSize; + // complete current packet + if (packet->payloadSize > ackBlockSize) // more than just ack block + { + // try to add padding + if (packet->payloadSize + 16 < m_MaxPayloadSize) + packet->payloadSize += CreatePaddingBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize); + } + else + { + // reduce ack block + if (len + 8 < m_MaxPayloadSize) + { + // keep Ack block and drop some ranges + packet->payloadSize = m_MaxPayloadSize - len; + if (packet->payloadSize & 0x01) packet->payloadSize--; // make it even + htobe16buf (packet->payload + 1, packet->payloadSize - 3); // new block size + } + else // drop Ack block completely + packet->payloadSize = 0; + // msg fits single packet + m_SendQueue.pop_front (); + packet->payloadSize += CreateI2NPBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize, std::move (msg)); + } // send right a way - if (packet->payloadSize + 16 < m_MaxPayloadSize) - packet->payloadSize += CreatePaddingBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize); uint32_t packetNum = SendData (packet->payload, packet->payloadSize); packet->nextResendTime = nextResend; m_SentPackets.emplace (packetNum, packet); - packet = std::make_shared(); - packet->payloadSize += CreateAckBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize); + packet = newPacket; // just ack block } }; if (packet->payloadSize) From e537878b8abee59317cac24a38bfe7291e7c471a Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 25 Jul 2022 13:42:59 -0400 Subject: [PATCH 071/219] check Ack block bufer size and shrink ranges if necessary --- libi2pd/SSU2Session.cpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index afa38df7..8a67d9ca 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -2055,6 +2055,8 @@ namespace transport size_t SSU2Session::CreateAckBlock (uint8_t * buf, size_t len) { if (len < 8) return 0; + int maxNumRanges = (len - 8) >> 1; + if (maxNumRanges > SSU2_MAX_NUM_ACK_RANGES) maxNumRanges = SSU2_MAX_NUM_ACK_RANGES; buf[0] = eSSU2BlkAck; uint32_t ackThrough = m_OutOfSequencePackets.empty () ? m_ReceivePacketNum : *m_OutOfSequencePackets.rbegin (); htobe32buf (buf + 3, ackThrough); // Ack Through @@ -2078,9 +2080,9 @@ namespace transport { auto d = std::div (acnt - 255, 255); acnt = 255; - if (d.quot > SSU2_MAX_NUM_ACK_RANGES) + if (d.quot > maxNumRanges) { - d.quot = SSU2_MAX_NUM_ACK_RANGES; + d.quot = maxNumRanges; d.rem = 0; } // Acks only ragnes for acnt @@ -2095,12 +2097,12 @@ namespace transport numRanges++; } } - while (it != m_OutOfSequencePackets.rend () && numRanges < SSU2_MAX_NUM_ACK_RANGES) + while (it != m_OutOfSequencePackets.rend () && numRanges < maxNumRanges) { if (lastNum - (*it) > 255) { // NACKs only ranges - if (lastNum > (*it) + 255*(SSU2_MAX_NUM_ACK_RANGES - numRanges)) break; // too many NACKs + if (lastNum > (*it) + 255*(maxNumRanges - numRanges)) break; // too many NACKs while (lastNum - (*it) > 255) { buf[8 + numRanges*2] = 255; buf[8 + numRanges*2 + 1] = 0; // NACKs 255, Acks 0 @@ -2124,13 +2126,13 @@ namespace transport numAcks -= 255; numRanges++; buf[8 + numRanges*2] = 0; // NACKs 0 - if (numRanges >= SSU2_MAX_NUM_ACK_RANGES) break; + if (numRanges >= maxNumRanges) break; } if (numAcks > 255) numAcks = 255; buf[8 + numRanges*2 + 1] = (uint8_t)numAcks; // Acks numRanges++; } - if (numRanges < SSU2_MAX_NUM_ACK_RANGES && it == m_OutOfSequencePackets.rend ()) + if (numRanges < maxNumRanges && it == m_OutOfSequencePackets.rend ()) { // add range between out-of-seqence and received int nacks = *m_OutOfSequencePackets.begin () - m_ReceivePacketNum - 1; From 987497bb109df7f347620f81fdf859e5972c4b80 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 25 Jul 2022 15:23:52 -0400 Subject: [PATCH 072/219] don't publish invalid host/port --- libi2pd/RouterInfo.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libi2pd/RouterInfo.cpp b/libi2pd/RouterInfo.cpp index 9293c35e..8a164852 100644 --- a/libi2pd/RouterInfo.cpp +++ b/libi2pd/RouterInfo.cpp @@ -1307,7 +1307,7 @@ namespace data else WriteString ("", s); - if (isPublished) + if (isPublished && !address.host.is_unspecified ()) { WriteString ("host", properties); properties << '='; @@ -1410,7 +1410,7 @@ namespace data properties << ';'; } } - if (isPublished || (address.ssu && !address.IsSSU2 ())) + if ((isPublished || (address.ssu && !address.IsSSU2 ())) && address.port) { WriteString ("port", properties); properties << '='; From f8a609f692633383242ad972d221093005100c04 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 25 Jul 2022 18:46:25 -0400 Subject: [PATCH 073/219] respond to termination --- libi2pd/SSU2.cpp | 10 +++++++--- libi2pd/SSU2Session.cpp | 5 ++++- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/libi2pd/SSU2.cpp b/libi2pd/SSU2.cpp index 2f7c1e74..aebeaa05 100644 --- a/libi2pd/SSU2.cpp +++ b/libi2pd/SSU2.cpp @@ -234,7 +234,8 @@ namespace transport { ProcessNextPacket (packet->buf, packet->len, packet->from); m_PacketsPool.ReleaseMt (packet); - if (m_LastSession) m_LastSession->FlushData (); + if (m_LastSession && m_LastSession->GetState () != eSSU2SessionStateTerminated) + m_LastSession->FlushData (); } } @@ -243,7 +244,8 @@ namespace transport for (auto& packet: packets) ProcessNextPacket (packet->buf, packet->len, packet->from); m_PacketsPool.ReleaseMt (packets); - if (m_LastSession) m_LastSession->FlushData (); + if (m_LastSession && m_LastSession->GetState () != eSSU2SessionStateTerminated) + m_LastSession->FlushData (); } void SSU2Server::AddSession (std::shared_ptr session) @@ -416,7 +418,9 @@ namespace transport m_LastSession->ProcessPeerTest (buf, len); break; case eSSU2SessionStateClosing: - m_LastSession->RequestTermination (eSSU2TerminationReasonIdleTimeout); // send termination again + m_LastSession->ProcessData (buf, len); // we might receive termintaion block + if (m_LastSession && m_LastSession->GetState () != eSSU2SessionStateTerminated) + m_LastSession->RequestTermination (eSSU2TerminationReasonIdleTimeout); // send termination again break; case eSSU2SessionStateTerminated: m_LastSession = nullptr; diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index 8a67d9ca..5d440c54 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -1308,7 +1308,10 @@ namespace transport break; case eSSU2BlkTermination: LogPrint (eLogDebug, "SSU2: Termination reason=", (int)buf[11]); - Terminate (); + if (IsEstablished () && buf[11] != eSSU2TerminationReasonTerminationReceived) + RequestTermination (eSSU2TerminationReasonTerminationReceived); + else + Terminate (); break; case eSSU2BlkRelayRequest: LogPrint (eLogDebug, "SSU2: RelayRequest"); From 46a549c875d9207ff2c407ec9073aef4e89d600e Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 26 Jul 2022 13:00:41 -0400 Subject: [PATCH 074/219] random size of fragments --- libi2pd/SSU2Session.cpp | 49 ++++++++++++++++++++++++++++++++--------- libi2pd/SSU2Session.h | 4 ++-- 2 files changed, 40 insertions(+), 13 deletions(-) diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index 5d440c54..f3a5713a 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -265,6 +265,7 @@ namespace transport auto nextResend = i2p::util::GetSecondsSinceEpoch () + SSU2_RESEND_INTERVAL; auto packet = std::make_shared(); size_t ackBlockSize = CreateAckBlock (packet->payload, m_MaxPayloadSize); + bool ackBlockSent = false; packet->payloadSize += ackBlockSize; while (!m_SendQueue.empty () && m_SentPackets.size () <= m_WindowSize) { @@ -273,7 +274,8 @@ namespace transport if (len > m_MaxPayloadSize) // message too long { m_SendQueue.pop_front (); - SendFragmentedMessage (msg); + if (SendFragmentedMessage (msg)) + ackBlockSent = true; } else if (packet->payloadSize + len <= m_MaxPayloadSize) { @@ -289,6 +291,7 @@ namespace transport // complete current packet if (packet->payloadSize > ackBlockSize) // more than just ack block { + ackBlockSent = true; // try to add padding if (packet->payloadSize + 16 < m_MaxPayloadSize) packet->payloadSize += CreatePaddingBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize); @@ -299,6 +302,7 @@ namespace transport if (len + 8 < m_MaxPayloadSize) { // keep Ack block and drop some ranges + ackBlockSent = true; packet->payloadSize = m_MaxPayloadSize - len; if (packet->payloadSize & 0x01) packet->payloadSize--; // make it even htobe16buf (packet->payload + 1, packet->payloadSize - 3); // new block size @@ -316,43 +320,66 @@ namespace transport packet = newPacket; // just ack block } }; - if (packet->payloadSize) + if (packet->payloadSize > ackBlockSize) { + ackBlockSent = true; if (packet->payloadSize + 16 < m_MaxPayloadSize) packet->payloadSize += CreatePaddingBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize); uint32_t packetNum = SendData (packet->payload, packet->payloadSize); packet->nextResendTime = nextResend; m_SentPackets.emplace (packetNum, packet); } - return true; + return ackBlockSent; } return false; } - void SSU2Session::SendFragmentedMessage (std::shared_ptr msg) + bool SSU2Session::SendFragmentedMessage (std::shared_ptr msg) { + size_t lastFragmentSize = (msg->GetNTCP2Length () + 3 - m_MaxPayloadSize) % (m_MaxPayloadSize - 8); + size_t extraSize = m_MaxPayloadSize - lastFragmentSize; + bool ackBlockSent = false; uint32_t msgID; memcpy (&msgID, msg->GetHeader () + I2NP_HEADER_MSGID_OFFSET, 4); auto nextResend = i2p::util::GetSecondsSinceEpoch () + SSU2_RESEND_INTERVAL; auto packet = std::make_shared(); - packet->payloadSize = CreateAckBlock (packet->payload, m_MaxPayloadSize); - auto size = CreateFirstFragmentBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - 16 - packet->payloadSize, msg); - if (!size) return; + if (extraSize >= 8) + { + packet->payloadSize = CreateAckBlock (packet->payload, extraSize); + ackBlockSent = true; + if (packet->payloadSize + 12 < m_MaxPayloadSize) + { + uint32_t packetNum = SendData (packet->payload, packet->payloadSize); + packet->nextResendTime = nextResend; + m_SentPackets.emplace (packetNum, packet); + packet = std::make_shared(); + } + else + extraSize -= packet->payloadSize; + } + size_t offset = extraSize > 0 ? (rand () % extraSize) : 0; + if (offset + packet->payloadSize >= m_MaxPayloadSize) offset = 0; + auto size = CreateFirstFragmentBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - offset - packet->payloadSize, msg); + if (!size) return false; + extraSize -= offset; packet->payloadSize += size; - packet->payloadSize += CreatePaddingBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - 16 - packet->payloadSize); uint32_t firstPacketNum = SendData (packet->payload, packet->payloadSize); packet->nextResendTime = nextResend; m_SentPackets.emplace (firstPacketNum, packet); uint8_t fragmentNum = 0; while (msg->offset < msg->len) { + offset = extraSize > 0 ? (rand () % extraSize) : 0; packet = std::make_shared(); - packet->payloadSize = CreateFollowOnFragmentBlock (packet->payload, m_MaxPayloadSize - 16, msg, fragmentNum, msgID); - packet->payloadSize += CreatePaddingBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - 16 - packet->payloadSize); + packet->payloadSize = CreateFollowOnFragmentBlock (packet->payload, m_MaxPayloadSize - offset, msg, fragmentNum, msgID); + extraSize -= offset; + if (msg->offset >= msg->len && packet->payloadSize + 16 < m_MaxPayloadSize) // last fragment + packet->payloadSize += CreatePaddingBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize); uint32_t followonPacketNum = SendData (packet->payload, packet->payloadSize); packet->nextResendTime = nextResend; m_SentPackets.emplace (followonPacketNum, packet); } + return ackBlockSent; } void SSU2Session::Resend (uint64_t ts) @@ -863,7 +890,7 @@ namespace transport m_Address = ri->GetSSU2AddressWithStaticKey (S, m_RemoteEndpoint.address ().is_v6 ()); if (!m_Address) { - LogPrint (eLogError, "SSU2: No SSU2 address with static key found in SessionConfirmed"); + LogPrint (eLogError, "SSU2: No SSU2 address with static key found in SessionConfirmed from ", i2p::data::GetIdentHashAbbreviation (ri->GetIdentHash ())); return false; } // update RouterInfo in netdb diff --git a/libi2pd/SSU2Session.h b/libi2pd/SSU2Session.h index 79640177..c18ca4b4 100644 --- a/libi2pd/SSU2Session.h +++ b/libi2pd/SSU2Session.h @@ -250,8 +250,8 @@ namespace transport void ScheduleConnectTimer (); void HandleConnectTimer (const boost::system::error_code& ecode); void PostI2NPMessages (std::vector > msgs); - bool SendQueue (); - void SendFragmentedMessage (std::shared_ptr msg); + bool SendQueue (); // returns true if ack block was sent + bool SendFragmentedMessage (std::shared_ptr msg); void ResendHandshakePacket (); void ProcessSessionRequest (Header& header, uint8_t * buf, size_t len); From a0419e4f34a8d2fda5c7a1e43619b8feca922909 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 26 Jul 2022 13:55:31 -0400 Subject: [PATCH 075/219] add SSU2 introducer if SSU2 only --- libi2pd/RouterContext.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index e9489475..cb91b8ae 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -466,6 +466,7 @@ namespace i2p bool RouterContext::AddSSU2Introducer (const i2p::data::RouterInfo::Introducer& introducer, bool v4) { + if (!IsSSU2Only ()) return false bool ret = m_RouterInfo.AddSSU2Introducer (introducer, v4); if (ret) UpdateRouterInfo (); @@ -474,6 +475,7 @@ namespace i2p void RouterContext::RemoveSSU2Introducer (const i2p::data::IdentHash& h, bool v4) { + if (!IsSSU2Only ()) return; if (m_RouterInfo.RemoveSSU2Introducer (h, v4)) UpdateRouterInfo (); } From f9106b77bbd806eec5aa12a731414d2cded0d415 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 26 Jul 2022 13:57:37 -0400 Subject: [PATCH 076/219] add SSU2 introducer if SSU2 only --- libi2pd/RouterContext.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index cb91b8ae..9e53f23b 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -466,7 +466,7 @@ namespace i2p bool RouterContext::AddSSU2Introducer (const i2p::data::RouterInfo::Introducer& introducer, bool v4) { - if (!IsSSU2Only ()) return false + if (!IsSSU2Only ()) return false; bool ret = m_RouterInfo.AddSSU2Introducer (introducer, v4); if (ret) UpdateRouterInfo (); From bc0cdaa66974c9dea01ab270fd7b3b7c5fd7d0b8 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Wed, 27 Jul 2022 00:37:48 +0300 Subject: [PATCH 077/219] [i18n] update gettext file, add translation context, change comments Signed-off-by: R4SAS --- contrib/i18n/English.po | 388 ++++++++++++++++++----------------- daemon/HTTPServer.cpp | 56 ++--- libi2pd_client/HTTPProxy.cpp | 18 +- 3 files changed, 239 insertions(+), 223 deletions(-) diff --git a/contrib/i18n/English.po b/contrib/i18n/English.po index 25378f82..c9ded966 100644 --- a/contrib/i18n/English.po +++ b/contrib/i18n/English.po @@ -1,13 +1,13 @@ # i2pd -# Copyright (C) 2021 PurpleI2P team +# Copyright (C) 2021-2022 PurpleI2P team # This file is distributed under the same license as the i2pd package. -# R4SAS , 2021. +# R4SAS , 2021-2022. # msgid "" msgstr "" "Project-Id-Version: i2pd\n" "Report-Msgid-Bugs-To: https://github.com/PurpleI2P/i2pd/issues\n" -"POT-Creation-Date: 2021-08-06 17:12\n" +"POT-Creation-Date: 2022-07-26 21:22\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" @@ -18,706 +18,712 @@ msgstr "" "X-Poedit-SearchPath-0: daemon/HTTPServer.cpp\n" "X-Poedit-SearchPath-1: libi2pd_client/HTTPProxy.cpp\n" -#: daemon/HTTPServer.cpp:177 +#: daemon/HTTPServer.cpp:108 msgid "day" msgid_plural "days" msgstr[0] "" msgstr[1] "" -#: daemon/HTTPServer.cpp:181 +#: daemon/HTTPServer.cpp:112 msgid "hour" msgid_plural "hours" msgstr[0] "" msgstr[1] "" -#: daemon/HTTPServer.cpp:185 +#: daemon/HTTPServer.cpp:116 msgid "minute" msgid_plural "minutes" msgstr[0] "" msgstr[1] "" -#: daemon/HTTPServer.cpp:188 +#: daemon/HTTPServer.cpp:119 msgid "second" msgid_plural "seconds" msgstr[0] "" msgstr[1] "" #. tr: Kibibit -#: daemon/HTTPServer.cpp:196 daemon/HTTPServer.cpp:224 +#: daemon/HTTPServer.cpp:127 daemon/HTTPServer.cpp:155 msgid "KiB" msgstr "" #. tr: Mebibit -#: daemon/HTTPServer.cpp:198 +#: daemon/HTTPServer.cpp:129 msgid "MiB" msgstr "" #. tr: Gibibit -#: daemon/HTTPServer.cpp:200 +#: daemon/HTTPServer.cpp:131 msgid "GiB" msgstr "" -#: daemon/HTTPServer.cpp:217 +#: daemon/HTTPServer.cpp:148 msgid "building" msgstr "" -#: daemon/HTTPServer.cpp:218 +#: daemon/HTTPServer.cpp:149 msgid "failed" msgstr "" -#: daemon/HTTPServer.cpp:219 +#: daemon/HTTPServer.cpp:150 msgid "expiring" msgstr "" -#: daemon/HTTPServer.cpp:220 +#: daemon/HTTPServer.cpp:151 msgid "established" msgstr "" -#: daemon/HTTPServer.cpp:221 +#: daemon/HTTPServer.cpp:152 msgid "unknown" msgstr "" -#: daemon/HTTPServer.cpp:223 +#: daemon/HTTPServer.cpp:154 msgid "exploratory" msgstr "" -#: daemon/HTTPServer.cpp:259 +#. tr: Webconsole page title +#: daemon/HTTPServer.cpp:185 +msgid "Purple I2P Webconsole" +msgstr "" + +#: daemon/HTTPServer.cpp:190 msgid "i2pd webconsole" msgstr "" -#: daemon/HTTPServer.cpp:262 +#: daemon/HTTPServer.cpp:193 msgid "Main page" msgstr "" -#: daemon/HTTPServer.cpp:263 daemon/HTTPServer.cpp:725 +#: daemon/HTTPServer.cpp:194 daemon/HTTPServer.cpp:700 msgid "Router commands" msgstr "" -#: daemon/HTTPServer.cpp:264 daemon/HTTPServer.cpp:448 -#: daemon/HTTPServer.cpp:460 +#: daemon/HTTPServer.cpp:195 daemon/HTTPServer.cpp:382 +#: daemon/HTTPServer.cpp:394 msgid "Local Destinations" msgstr "" -#: daemon/HTTPServer.cpp:266 daemon/HTTPServer.cpp:418 -#: daemon/HTTPServer.cpp:504 daemon/HTTPServer.cpp:510 -#: daemon/HTTPServer.cpp:641 daemon/HTTPServer.cpp:684 -#: daemon/HTTPServer.cpp:688 +#: daemon/HTTPServer.cpp:197 daemon/HTTPServer.cpp:352 +#: daemon/HTTPServer.cpp:438 daemon/HTTPServer.cpp:444 +#: daemon/HTTPServer.cpp:597 daemon/HTTPServer.cpp:640 +#: daemon/HTTPServer.cpp:644 msgid "LeaseSets" msgstr "" -#: daemon/HTTPServer.cpp:268 daemon/HTTPServer.cpp:694 +#: daemon/HTTPServer.cpp:199 daemon/HTTPServer.cpp:650 msgid "Tunnels" msgstr "" -#: daemon/HTTPServer.cpp:269 daemon/HTTPServer.cpp:425 -#: daemon/HTTPServer.cpp:787 daemon/HTTPServer.cpp:803 +#: daemon/HTTPServer.cpp:201 daemon/HTTPServer.cpp:359 +#: daemon/HTTPServer.cpp:770 daemon/HTTPServer.cpp:786 msgid "Transit Tunnels" msgstr "" -#: daemon/HTTPServer.cpp:270 daemon/HTTPServer.cpp:852 +#: daemon/HTTPServer.cpp:203 daemon/HTTPServer.cpp:839 msgid "Transports" msgstr "" -#: daemon/HTTPServer.cpp:271 +#: daemon/HTTPServer.cpp:204 msgid "I2P tunnels" msgstr "" -#: daemon/HTTPServer.cpp:273 daemon/HTTPServer.cpp:914 -#: daemon/HTTPServer.cpp:924 +#: daemon/HTTPServer.cpp:206 daemon/HTTPServer.cpp:908 +#: daemon/HTTPServer.cpp:918 msgid "SAM sessions" msgstr "" -#: daemon/HTTPServer.cpp:289 daemon/HTTPServer.cpp:1306 -#: daemon/HTTPServer.cpp:1309 daemon/HTTPServer.cpp:1312 -#: daemon/HTTPServer.cpp:1326 daemon/HTTPServer.cpp:1371 -#: daemon/HTTPServer.cpp:1374 daemon/HTTPServer.cpp:1377 +#: daemon/HTTPServer.cpp:222 daemon/HTTPServer.cpp:1302 +#: daemon/HTTPServer.cpp:1305 daemon/HTTPServer.cpp:1308 +#: daemon/HTTPServer.cpp:1322 daemon/HTTPServer.cpp:1367 +#: daemon/HTTPServer.cpp:1370 daemon/HTTPServer.cpp:1373 msgid "ERROR" msgstr "" -#: daemon/HTTPServer.cpp:296 +#: daemon/HTTPServer.cpp:229 msgid "OK" msgstr "" -#: daemon/HTTPServer.cpp:297 +#: daemon/HTTPServer.cpp:230 msgid "Testing" msgstr "" -#: daemon/HTTPServer.cpp:298 +#: daemon/HTTPServer.cpp:231 msgid "Firewalled" msgstr "" -#: daemon/HTTPServer.cpp:299 daemon/HTTPServer.cpp:320 -#: daemon/HTTPServer.cpp:406 +#: daemon/HTTPServer.cpp:232 daemon/HTTPServer.cpp:253 +#: daemon/HTTPServer.cpp:325 msgid "Unknown" msgstr "" -#: daemon/HTTPServer.cpp:300 daemon/HTTPServer.cpp:435 -#: daemon/HTTPServer.cpp:436 daemon/HTTPServer.cpp:982 -#: daemon/HTTPServer.cpp:991 +#: daemon/HTTPServer.cpp:233 daemon/HTTPServer.cpp:369 +#: daemon/HTTPServer.cpp:370 daemon/HTTPServer.cpp:976 +#: daemon/HTTPServer.cpp:985 msgid "Proxy" msgstr "" -#: daemon/HTTPServer.cpp:301 +#: daemon/HTTPServer.cpp:234 msgid "Mesh" msgstr "" -#: daemon/HTTPServer.cpp:304 +#: daemon/HTTPServer.cpp:237 msgid "Error" msgstr "" -#: daemon/HTTPServer.cpp:308 +#: daemon/HTTPServer.cpp:241 msgid "Clock skew" msgstr "" -#: daemon/HTTPServer.cpp:311 +#: daemon/HTTPServer.cpp:244 msgid "Offline" msgstr "" -#: daemon/HTTPServer.cpp:314 +#: daemon/HTTPServer.cpp:247 msgid "Symmetric NAT" msgstr "" -#: daemon/HTTPServer.cpp:326 +#: daemon/HTTPServer.cpp:259 msgid "Uptime" msgstr "" -#: daemon/HTTPServer.cpp:329 +#: daemon/HTTPServer.cpp:262 msgid "Network status" msgstr "" -#: daemon/HTTPServer.cpp:334 +#: daemon/HTTPServer.cpp:267 msgid "Network status v6" msgstr "" -#: daemon/HTTPServer.cpp:340 daemon/HTTPServer.cpp:347 +#: daemon/HTTPServer.cpp:273 daemon/HTTPServer.cpp:280 msgid "Stopping in" msgstr "" -#: daemon/HTTPServer.cpp:354 +#: daemon/HTTPServer.cpp:287 msgid "Family" msgstr "" -#: daemon/HTTPServer.cpp:355 +#: daemon/HTTPServer.cpp:288 msgid "Tunnel creation success rate" msgstr "" -#: daemon/HTTPServer.cpp:356 +#: daemon/HTTPServer.cpp:289 msgid "Received" msgstr "" #. tr: Kibibit/s -#: daemon/HTTPServer.cpp:358 daemon/HTTPServer.cpp:361 -#: daemon/HTTPServer.cpp:364 +#: daemon/HTTPServer.cpp:291 daemon/HTTPServer.cpp:294 +#: daemon/HTTPServer.cpp:297 msgid "KiB/s" msgstr "" -#: daemon/HTTPServer.cpp:359 +#: daemon/HTTPServer.cpp:292 msgid "Sent" msgstr "" -#: daemon/HTTPServer.cpp:362 +#: daemon/HTTPServer.cpp:295 msgid "Transit" msgstr "" -#: daemon/HTTPServer.cpp:365 +#: daemon/HTTPServer.cpp:298 msgid "Data path" msgstr "" -#: daemon/HTTPServer.cpp:368 +#: daemon/HTTPServer.cpp:301 msgid "Hidden content. Press on text to see." msgstr "" -#: daemon/HTTPServer.cpp:371 +#: daemon/HTTPServer.cpp:304 msgid "Router Ident" msgstr "" -#: daemon/HTTPServer.cpp:373 +#: daemon/HTTPServer.cpp:306 msgid "Router Family" msgstr "" -#: daemon/HTTPServer.cpp:374 +#: daemon/HTTPServer.cpp:307 msgid "Router Caps" msgstr "" -#: daemon/HTTPServer.cpp:375 +#: daemon/HTTPServer.cpp:308 msgid "Version" msgstr "" -#: daemon/HTTPServer.cpp:376 +#: daemon/HTTPServer.cpp:309 msgid "Our external address" msgstr "" -#: daemon/HTTPServer.cpp:384 +#: daemon/HTTPServer.cpp:337 msgid "supported" msgstr "" -#: daemon/HTTPServer.cpp:416 +#: daemon/HTTPServer.cpp:350 msgid "Routers" msgstr "" -#: daemon/HTTPServer.cpp:417 +#: daemon/HTTPServer.cpp:351 msgid "Floodfills" msgstr "" -#: daemon/HTTPServer.cpp:424 daemon/HTTPServer.cpp:968 +#: daemon/HTTPServer.cpp:358 daemon/HTTPServer.cpp:962 msgid "Client Tunnels" msgstr "" -#: daemon/HTTPServer.cpp:434 +#: daemon/HTTPServer.cpp:368 msgid "Services" msgstr "" -#: daemon/HTTPServer.cpp:435 daemon/HTTPServer.cpp:436 -#: daemon/HTTPServer.cpp:437 daemon/HTTPServer.cpp:438 -#: daemon/HTTPServer.cpp:439 daemon/HTTPServer.cpp:440 +#: daemon/HTTPServer.cpp:369 daemon/HTTPServer.cpp:370 +#: daemon/HTTPServer.cpp:371 daemon/HTTPServer.cpp:372 +#: daemon/HTTPServer.cpp:373 daemon/HTTPServer.cpp:374 msgid "Enabled" msgstr "" -#: daemon/HTTPServer.cpp:435 daemon/HTTPServer.cpp:436 -#: daemon/HTTPServer.cpp:437 daemon/HTTPServer.cpp:438 -#: daemon/HTTPServer.cpp:439 daemon/HTTPServer.cpp:440 +#: daemon/HTTPServer.cpp:369 daemon/HTTPServer.cpp:370 +#: daemon/HTTPServer.cpp:371 daemon/HTTPServer.cpp:372 +#: daemon/HTTPServer.cpp:373 daemon/HTTPServer.cpp:374 msgid "Disabled" msgstr "" -#: daemon/HTTPServer.cpp:483 +#: daemon/HTTPServer.cpp:417 msgid "Encrypted B33 address" msgstr "" -#: daemon/HTTPServer.cpp:492 +#: daemon/HTTPServer.cpp:426 msgid "Address registration line" msgstr "" -#: daemon/HTTPServer.cpp:497 +#: daemon/HTTPServer.cpp:431 msgid "Domain" msgstr "" -#: daemon/HTTPServer.cpp:498 +#: daemon/HTTPServer.cpp:432 msgid "Generate" msgstr "" -#: daemon/HTTPServer.cpp:499 +#: daemon/HTTPServer.cpp:433 msgid "" "Note: result string can be used only for registering 2LD domains " "(example.i2p). For registering subdomains please use i2pd-tools." msgstr "" -#: daemon/HTTPServer.cpp:505 +#: daemon/HTTPServer.cpp:439 msgid "Address" msgstr "" -#: daemon/HTTPServer.cpp:505 +#: daemon/HTTPServer.cpp:439 msgid "Type" msgstr "" -#: daemon/HTTPServer.cpp:505 +#: daemon/HTTPServer.cpp:439 msgid "EncType" msgstr "" -#: daemon/HTTPServer.cpp:515 daemon/HTTPServer.cpp:699 +#: daemon/HTTPServer.cpp:449 daemon/HTTPServer.cpp:655 msgid "Inbound tunnels" msgstr "" #. tr: Milliseconds -#: daemon/HTTPServer.cpp:520 daemon/HTTPServer.cpp:530 -#: daemon/HTTPServer.cpp:704 daemon/HTTPServer.cpp:714 +#: daemon/HTTPServer.cpp:464 daemon/HTTPServer.cpp:484 +#: daemon/HTTPServer.cpp:669 daemon/HTTPServer.cpp:689 msgid "ms" msgstr "" -#: daemon/HTTPServer.cpp:525 daemon/HTTPServer.cpp:709 +#: daemon/HTTPServer.cpp:469 daemon/HTTPServer.cpp:674 msgid "Outbound tunnels" msgstr "" -#: daemon/HTTPServer.cpp:537 +#: daemon/HTTPServer.cpp:491 msgid "Tags" msgstr "" -#: daemon/HTTPServer.cpp:537 +#: daemon/HTTPServer.cpp:491 msgid "Incoming" msgstr "" -#: daemon/HTTPServer.cpp:544 daemon/HTTPServer.cpp:547 +#: daemon/HTTPServer.cpp:498 daemon/HTTPServer.cpp:501 msgid "Outgoing" msgstr "" -#: daemon/HTTPServer.cpp:545 daemon/HTTPServer.cpp:561 +#: daemon/HTTPServer.cpp:499 daemon/HTTPServer.cpp:515 msgid "Destination" msgstr "" -#: daemon/HTTPServer.cpp:545 +#: daemon/HTTPServer.cpp:499 msgid "Amount" msgstr "" -#: daemon/HTTPServer.cpp:552 +#: daemon/HTTPServer.cpp:506 msgid "Incoming Tags" msgstr "" -#: daemon/HTTPServer.cpp:560 daemon/HTTPServer.cpp:563 +#: daemon/HTTPServer.cpp:514 daemon/HTTPServer.cpp:517 msgid "Tags sessions" msgstr "" -#: daemon/HTTPServer.cpp:561 +#: daemon/HTTPServer.cpp:515 msgid "Status" msgstr "" -#: daemon/HTTPServer.cpp:570 daemon/HTTPServer.cpp:626 +#: daemon/HTTPServer.cpp:524 daemon/HTTPServer.cpp:582 msgid "Local Destination" msgstr "" -#: daemon/HTTPServer.cpp:580 daemon/HTTPServer.cpp:947 +#: daemon/HTTPServer.cpp:535 daemon/HTTPServer.cpp:941 msgid "Streams" msgstr "" -#: daemon/HTTPServer.cpp:602 +#: daemon/HTTPServer.cpp:558 msgid "Close stream" msgstr "" -#: daemon/HTTPServer.cpp:631 +#: daemon/HTTPServer.cpp:587 msgid "I2CP session not found" msgstr "" -#: daemon/HTTPServer.cpp:634 +#: daemon/HTTPServer.cpp:590 msgid "I2CP is not enabled" msgstr "" -#: daemon/HTTPServer.cpp:660 +#: daemon/HTTPServer.cpp:616 msgid "Invalid" msgstr "" -#: daemon/HTTPServer.cpp:663 +#: daemon/HTTPServer.cpp:619 msgid "Store type" msgstr "" -#: daemon/HTTPServer.cpp:664 +#: daemon/HTTPServer.cpp:620 msgid "Expires" msgstr "" -#: daemon/HTTPServer.cpp:669 +#: daemon/HTTPServer.cpp:625 msgid "Non Expired Leases" msgstr "" -#: daemon/HTTPServer.cpp:672 +#: daemon/HTTPServer.cpp:628 msgid "Gateway" msgstr "" -#: daemon/HTTPServer.cpp:673 +#: daemon/HTTPServer.cpp:629 msgid "TunnelID" msgstr "" -#: daemon/HTTPServer.cpp:674 +#: daemon/HTTPServer.cpp:630 msgid "EndDate" msgstr "" -#: daemon/HTTPServer.cpp:684 +#: daemon/HTTPServer.cpp:640 msgid "not floodfill" msgstr "" -#: daemon/HTTPServer.cpp:695 +#: daemon/HTTPServer.cpp:651 msgid "Queue size" msgstr "" -#: daemon/HTTPServer.cpp:726 +#: daemon/HTTPServer.cpp:701 msgid "Run peer test" msgstr "" -#: daemon/HTTPServer.cpp:731 +#: daemon/HTTPServer.cpp:706 msgid "Decline transit tunnels" msgstr "" -#: daemon/HTTPServer.cpp:733 +#: daemon/HTTPServer.cpp:708 msgid "Accept transit tunnels" msgstr "" -#: daemon/HTTPServer.cpp:737 daemon/HTTPServer.cpp:742 +#: daemon/HTTPServer.cpp:712 daemon/HTTPServer.cpp:717 msgid "Cancel graceful shutdown" msgstr "" -#: daemon/HTTPServer.cpp:739 daemon/HTTPServer.cpp:744 +#: daemon/HTTPServer.cpp:714 daemon/HTTPServer.cpp:719 msgid "Start graceful shutdown" msgstr "" -#: daemon/HTTPServer.cpp:747 +#: daemon/HTTPServer.cpp:722 msgid "Force shutdown" msgstr "" -#: daemon/HTTPServer.cpp:748 +#: daemon/HTTPServer.cpp:723 msgid "Reload external CSS styles" msgstr "" -#: daemon/HTTPServer.cpp:751 +#: daemon/HTTPServer.cpp:726 msgid "" "Note: any action done here are not persistent and not changes your " "config files." msgstr "" -#: daemon/HTTPServer.cpp:753 +#: daemon/HTTPServer.cpp:728 msgid "Logging level" msgstr "" -#: daemon/HTTPServer.cpp:761 +#: daemon/HTTPServer.cpp:736 msgid "Transit tunnels limit" msgstr "" -#: daemon/HTTPServer.cpp:766 daemon/HTTPServer.cpp:778 +#: daemon/HTTPServer.cpp:741 daemon/HTTPServer.cpp:760 msgid "Change" msgstr "" -#: daemon/HTTPServer.cpp:770 +#: daemon/HTTPServer.cpp:748 msgid "Change language" msgstr "" -#: daemon/HTTPServer.cpp:803 +#: daemon/HTTPServer.cpp:786 msgid "no transit tunnels currently built" msgstr "" -#: daemon/HTTPServer.cpp:908 daemon/HTTPServer.cpp:931 +#: daemon/HTTPServer.cpp:902 daemon/HTTPServer.cpp:925 msgid "SAM disabled" msgstr "" -#: daemon/HTTPServer.cpp:924 +#: daemon/HTTPServer.cpp:918 msgid "no sessions currently running" msgstr "" -#: daemon/HTTPServer.cpp:937 +#: daemon/HTTPServer.cpp:931 msgid "SAM session not found" msgstr "" -#: daemon/HTTPServer.cpp:942 +#: daemon/HTTPServer.cpp:936 msgid "SAM Session" msgstr "" -#: daemon/HTTPServer.cpp:999 +#: daemon/HTTPServer.cpp:993 msgid "Server Tunnels" msgstr "" -#: daemon/HTTPServer.cpp:1015 +#: daemon/HTTPServer.cpp:1009 msgid "Client Forwards" msgstr "" -#: daemon/HTTPServer.cpp:1029 +#: daemon/HTTPServer.cpp:1023 msgid "Server Forwards" msgstr "" -#: daemon/HTTPServer.cpp:1227 +#: daemon/HTTPServer.cpp:1223 msgid "Unknown page" msgstr "" -#: daemon/HTTPServer.cpp:1246 +#: daemon/HTTPServer.cpp:1242 msgid "Invalid token" msgstr "" -#: daemon/HTTPServer.cpp:1304 daemon/HTTPServer.cpp:1361 -#: daemon/HTTPServer.cpp:1401 +#: daemon/HTTPServer.cpp:1300 daemon/HTTPServer.cpp:1357 +#: daemon/HTTPServer.cpp:1397 msgid "SUCCESS" msgstr "" -#: daemon/HTTPServer.cpp:1304 +#: daemon/HTTPServer.cpp:1300 msgid "Stream closed" msgstr "" -#: daemon/HTTPServer.cpp:1306 +#: daemon/HTTPServer.cpp:1302 msgid "Stream not found or already was closed" msgstr "" -#: daemon/HTTPServer.cpp:1309 +#: daemon/HTTPServer.cpp:1305 msgid "Destination not found" msgstr "" -#: daemon/HTTPServer.cpp:1312 +#: daemon/HTTPServer.cpp:1308 msgid "StreamID can't be null" msgstr "" -#: daemon/HTTPServer.cpp:1314 daemon/HTTPServer.cpp:1379 +#: daemon/HTTPServer.cpp:1310 daemon/HTTPServer.cpp:1375 msgid "Return to destination page" msgstr "" -#: daemon/HTTPServer.cpp:1315 daemon/HTTPServer.cpp:1328 -#: daemon/HTTPServer.cpp:1403 +#: daemon/HTTPServer.cpp:1311 daemon/HTTPServer.cpp:1324 +#: daemon/HTTPServer.cpp:1399 msgid "You will be redirected in 5 seconds" msgstr "" -#: daemon/HTTPServer.cpp:1326 +#: daemon/HTTPServer.cpp:1322 msgid "Transit tunnels count must not exceed 65535" msgstr "" -#: daemon/HTTPServer.cpp:1327 daemon/HTTPServer.cpp:1402 +#: daemon/HTTPServer.cpp:1323 daemon/HTTPServer.cpp:1398 msgid "Back to commands list" msgstr "" -#: daemon/HTTPServer.cpp:1363 +#: daemon/HTTPServer.cpp:1359 msgid "Register at reg.i2p" msgstr "" -#: daemon/HTTPServer.cpp:1364 +#: daemon/HTTPServer.cpp:1360 msgid "Description" msgstr "" -#: daemon/HTTPServer.cpp:1364 +#: daemon/HTTPServer.cpp:1360 msgid "A bit information about service on domain" msgstr "" -#: daemon/HTTPServer.cpp:1365 +#: daemon/HTTPServer.cpp:1361 msgid "Submit" msgstr "" -#: daemon/HTTPServer.cpp:1371 +#: daemon/HTTPServer.cpp:1367 msgid "Domain can't end with .b32.i2p" msgstr "" -#: daemon/HTTPServer.cpp:1374 +#: daemon/HTTPServer.cpp:1370 msgid "Domain must end with .i2p" msgstr "" -#: daemon/HTTPServer.cpp:1377 +#: daemon/HTTPServer.cpp:1373 msgid "Such destination is not found" msgstr "" -#: daemon/HTTPServer.cpp:1397 +#: daemon/HTTPServer.cpp:1393 msgid "Unknown command" msgstr "" -#: daemon/HTTPServer.cpp:1401 +#: daemon/HTTPServer.cpp:1397 msgid "Command accepted" msgstr "" -#: libi2pd_client/HTTPProxy.cpp:157 +#: libi2pd_client/HTTPProxy.cpp:163 msgid "Proxy error" msgstr "" -#: libi2pd_client/HTTPProxy.cpp:165 +#: libi2pd_client/HTTPProxy.cpp:171 msgid "Proxy info" msgstr "" -#: libi2pd_client/HTTPProxy.cpp:173 +#: libi2pd_client/HTTPProxy.cpp:179 msgid "Proxy error: Host not found" msgstr "" -#: libi2pd_client/HTTPProxy.cpp:174 +#: libi2pd_client/HTTPProxy.cpp:180 msgid "Remote host not found in router's addressbook" msgstr "" -#: libi2pd_client/HTTPProxy.cpp:175 +#: libi2pd_client/HTTPProxy.cpp:181 msgid "You may try to find this host on jump services below" msgstr "" -#: libi2pd_client/HTTPProxy.cpp:273 libi2pd_client/HTTPProxy.cpp:288 -#: libi2pd_client/HTTPProxy.cpp:322 libi2pd_client/HTTPProxy.cpp:365 +#: libi2pd_client/HTTPProxy.cpp:282 libi2pd_client/HTTPProxy.cpp:297 +#: libi2pd_client/HTTPProxy.cpp:331 libi2pd_client/HTTPProxy.cpp:372 msgid "Invalid request" msgstr "" -#: libi2pd_client/HTTPProxy.cpp:273 +#: libi2pd_client/HTTPProxy.cpp:282 msgid "Proxy unable to parse your request" msgstr "" -#: libi2pd_client/HTTPProxy.cpp:288 +#: libi2pd_client/HTTPProxy.cpp:297 msgid "addresshelper is not supported" msgstr "" -#: libi2pd_client/HTTPProxy.cpp:297 libi2pd_client/HTTPProxy.cpp:306 -#: libi2pd_client/HTTPProxy.cpp:385 +#: libi2pd_client/HTTPProxy.cpp:306 libi2pd_client/HTTPProxy.cpp:315 +#: libi2pd_client/HTTPProxy.cpp:392 msgid "Host" msgstr "" -#: libi2pd_client/HTTPProxy.cpp:297 +#: libi2pd_client/HTTPProxy.cpp:306 msgid "added to router's addressbook from helper" msgstr "" -#: libi2pd_client/HTTPProxy.cpp:298 +#: libi2pd_client/HTTPProxy.cpp:307 msgid "Click here to proceed:" msgstr "" -#: libi2pd_client/HTTPProxy.cpp:298 libi2pd_client/HTTPProxy.cpp:308 +#: libi2pd_client/HTTPProxy.cpp:307 libi2pd_client/HTTPProxy.cpp:317 msgid "Continue" msgstr "" -#: libi2pd_client/HTTPProxy.cpp:299 libi2pd_client/HTTPProxy.cpp:309 +#: libi2pd_client/HTTPProxy.cpp:308 libi2pd_client/HTTPProxy.cpp:318 msgid "Addresshelper found" msgstr "" -#: libi2pd_client/HTTPProxy.cpp:306 +#: libi2pd_client/HTTPProxy.cpp:315 msgid "already in router's addressbook" msgstr "" -#: libi2pd_client/HTTPProxy.cpp:307 +#. tr: The "record" means addressbook's record. That message appears when domain was already added to addressbook, but helper link is opened for it. +#: libi2pd_client/HTTPProxy.cpp:316 msgid "Click here to update record:" msgstr "" -#: libi2pd_client/HTTPProxy.cpp:322 +#: libi2pd_client/HTTPProxy.cpp:331 msgid "invalid request uri" msgstr "" -#: libi2pd_client/HTTPProxy.cpp:365 +#: libi2pd_client/HTTPProxy.cpp:372 msgid "Can't detect destination host from request" msgstr "" -#: libi2pd_client/HTTPProxy.cpp:382 libi2pd_client/HTTPProxy.cpp:386 +#: libi2pd_client/HTTPProxy.cpp:389 libi2pd_client/HTTPProxy.cpp:393 msgid "Outproxy failure" msgstr "" -#: libi2pd_client/HTTPProxy.cpp:382 +#: libi2pd_client/HTTPProxy.cpp:389 msgid "bad outproxy settings" msgstr "" -#: libi2pd_client/HTTPProxy.cpp:385 +#: libi2pd_client/HTTPProxy.cpp:392 msgid "not inside I2P network, but outproxy is not enabled" msgstr "" -#: libi2pd_client/HTTPProxy.cpp:474 +#: libi2pd_client/HTTPProxy.cpp:482 msgid "unknown outproxy url" msgstr "" -#: libi2pd_client/HTTPProxy.cpp:480 +#: libi2pd_client/HTTPProxy.cpp:490 msgid "cannot resolve upstream proxy" msgstr "" -#: libi2pd_client/HTTPProxy.cpp:488 +#: libi2pd_client/HTTPProxy.cpp:498 msgid "hostname too long" msgstr "" -#: libi2pd_client/HTTPProxy.cpp:515 +#: libi2pd_client/HTTPProxy.cpp:525 msgid "cannot connect to upstream socks proxy" msgstr "" -#: libi2pd_client/HTTPProxy.cpp:521 +#: libi2pd_client/HTTPProxy.cpp:531 msgid "Cannot negotiate with socks proxy" msgstr "" -#: libi2pd_client/HTTPProxy.cpp:563 +#: libi2pd_client/HTTPProxy.cpp:573 msgid "CONNECT error" msgstr "" -#: libi2pd_client/HTTPProxy.cpp:563 +#: libi2pd_client/HTTPProxy.cpp:573 msgid "Failed to Connect" msgstr "" -#: libi2pd_client/HTTPProxy.cpp:574 libi2pd_client/HTTPProxy.cpp:600 +#: libi2pd_client/HTTPProxy.cpp:584 libi2pd_client/HTTPProxy.cpp:610 msgid "socks proxy error" msgstr "" -#: libi2pd_client/HTTPProxy.cpp:582 +#: libi2pd_client/HTTPProxy.cpp:592 msgid "failed to send request to upstream" msgstr "" -#: libi2pd_client/HTTPProxy.cpp:603 +#: libi2pd_client/HTTPProxy.cpp:613 msgid "No Reply From socks proxy" msgstr "" -#: libi2pd_client/HTTPProxy.cpp:610 +#: libi2pd_client/HTTPProxy.cpp:620 msgid "cannot connect" msgstr "" -#: libi2pd_client/HTTPProxy.cpp:610 +#: libi2pd_client/HTTPProxy.cpp:620 msgid "http out proxy not implemented" msgstr "" -#: libi2pd_client/HTTPProxy.cpp:611 +#: libi2pd_client/HTTPProxy.cpp:621 msgid "cannot connect to upstream http proxy" msgstr "" -#: libi2pd_client/HTTPProxy.cpp:644 +#: libi2pd_client/HTTPProxy.cpp:654 msgid "Host is down" msgstr "" -#: libi2pd_client/HTTPProxy.cpp:644 +#: libi2pd_client/HTTPProxy.cpp:654 msgid "" "Can't create connection to requested host, it may be down. Please try again " "later." diff --git a/daemon/HTTPServer.cpp b/daemon/HTTPServer.cpp index b0b537e6..9bc49f38 100644 --- a/daemon/HTTPServer.cpp +++ b/daemon/HTTPServer.cpp @@ -182,7 +182,7 @@ namespace http { " \r\n" " \r\n" " \r\n" - " " << tr("Purple I2P Webconsole") << "\r\n"; + " " << tr(/* tr: Webconsole page title */ "Purple I2P Webconsole") << "\r\n"; GetStyles(s); s << "\r\n" @@ -531,19 +531,21 @@ namespace http { ShowLeaseSetDestination (s, dest, token); // Print table with streams information - s << "\r\n\r\n\r\n"; - s << ""; - s << ""; - s << ""; - s << ""; - s << ""; - s << ""; - s << ""; - s << ""; - s << ""; - s << ""; - s << "\r\n\r\n\r\n"; + s << "
" << tr("Streams") << "
StreamID"; // Stream closing button column - s << "DestinationSentReceivedOutInBufRTTWindowStatus
\r\n\r\n\r\n" + << "" + << "" + << "" + << "" + << "" + << "" + << "" + << "" + << "" + << "" + << "\r\n\r\n\r\n"; for (const auto& it: dest->GetAllStreams ()) { @@ -739,17 +741,25 @@ namespace http { s << " \r\n"; s << "\r\n
\r\n"; - std::string currLang = i2p::client::context.GetLanguage ()->GetLanguage(); // get current used language - s << "" << tr("Change language") << "
\r\n"; - s << "\r\n"; - s << " \r\n"; - s << " \r\n"; - s << " \r\n" + << " \r\n" + << " \r\n"; - s << " \r\n"; - s << "\r\n
\r\n"; + + s << " \r\n" + << " \r\n" + << "\r\n
\r\n"; } diff --git a/libi2pd_client/HTTPProxy.cpp b/libi2pd_client/HTTPProxy.cpp index 5cb08bfb..73677836 100644 --- a/libi2pd_client/HTTPProxy.cpp +++ b/libi2pd_client/HTTPProxy.cpp @@ -313,7 +313,7 @@ namespace proxy { std::string full_url = m_RequestURL.to_string(); std::stringstream ss; ss << tr("Host") << " " << m_RequestURL.host << " " << tr("already in router's addressbook") << ". "; - ss << tr("Click here to update record:") << " " << tr("Continue") << "."; GenericProxyInfo(tr("Addresshelper found"), ss.str()); return true; /* request processed */ @@ -422,8 +422,8 @@ namespace proxy { void HTTPReqHandler::ForwardToUpstreamProxy() { LogPrint(eLogDebug, "HTTPProxy: Forwarded to upstream"); - // build http request + /* build http request */ m_ClientRequestURL = m_RequestURL; LogPrint(eLogDebug, "HTTPProxy: ", m_ClientRequestURL.host); m_ClientRequestURL.schema = ""; @@ -431,17 +431,17 @@ namespace proxy { std::string origURI = m_ClientRequest.uri; // TODO: what do we need to change uri for? m_ClientRequest.uri = m_ClientRequestURL.to_string(); - // update User-Agent to ESR version of Firefox, same as Tor Browser below version 8, for non-HTTPS connections + /* update User-Agent to ESR version of Firefox, same as Tor Browser below version 8, for non-HTTPS connections */ if(m_ClientRequest.method != "CONNECT") m_ClientRequest.UpdateHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1; rv:60.0) Gecko/20100101 Firefox/60.0"); m_ClientRequest.write(m_ClientRequestBuffer); m_ClientRequestBuffer << m_recv_buf.substr(m_req_len); - // assume http if empty schema + /* assume http if empty schema */ if (m_ProxyURL.schema == "" || m_ProxyURL.schema == "http") { - // handle upstream http proxy + /* handle upstream http proxy */ if (!m_ProxyURL.port) m_ProxyURL.port = 80; if (m_ProxyURL.is_i2p()) { @@ -449,9 +449,9 @@ namespace proxy { auto auth = i2p::http::CreateBasicAuthorizationString (m_ProxyURL.user, m_ProxyURL.pass); if (!auth.empty ()) { - // remove existing authorization if any + /* remove existing authorization if any */ m_ClientRequest.RemoveHeader("Proxy-"); - // add own http proxy authorization + /* add own http proxy authorization */ m_ClientRequest.AddHeader("Proxy-Authorization", auth); } m_send_buf = m_ClientRequest.to_string(); @@ -470,7 +470,7 @@ namespace proxy { } else if (m_ProxyURL.schema == "socks") { - // handle upstream socks proxy + /* handle upstream socks proxy */ if (!m_ProxyURL.port) m_ProxyURL.port = 9050; // default to tor default if not specified boost::asio::ip::tcp::resolver::query q(m_ProxyURL.host, std::to_string(m_ProxyURL.port)); m_proxy_resolver.async_resolve(q, std::bind(&HTTPReqHandler::HandleUpstreamProxyResolved, this, std::placeholders::_1, std::placeholders::_2, [&](boost::asio::ip::tcp::endpoint ep) { @@ -479,7 +479,7 @@ namespace proxy { } else { - // unknown type, complain + /* unknown type, complain */ GenericProxyError(tr("unknown outproxy url"), m_ProxyURL.to_string()); } } From b574aaf99c383af6f14c6de44f9ed6dc5083ca36 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 26 Jul 2022 18:46:05 -0400 Subject: [PATCH 078/219] fix SSU2 crash on shutdown --- libi2pd/SSU2.cpp | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/libi2pd/SSU2.cpp b/libi2pd/SSU2.cpp index aebeaa05..2c91aeb9 100644 --- a/libi2pd/SSU2.cpp +++ b/libi2pd/SSU2.cpp @@ -88,27 +88,34 @@ namespace transport void SSU2Server::Stop () { - for (auto& it: m_Sessions) + if (IsRunning ()) + { + m_TerminationTimer.cancel (); + m_ResendTimer.cancel (); + m_IntroducersUpdateTimer.cancel (); + m_IntroducersUpdateTimerV6.cancel (); + } + + auto sessions = m_Sessions; + for (auto& it: sessions) { it.second->RequestTermination (eSSU2TerminationReasonRouterShutdown); it.second->Done (); } + + if (context.SupportsV4 () || context.SupportsV6 ()) + m_ReceiveService.Stop (); + m_SocketV4.close (); + m_SocketV6.close (); + + StopIOService (); + m_Sessions.clear (); m_SessionsByRouterHash.clear (); m_PendingOutgoingSessions.clear (); m_Relays.clear (); m_Introducers.clear (); m_IntroducersV6.clear (); - - if (context.SupportsV4 () || context.SupportsV6 ()) - m_ReceiveService.Stop (); - - m_SocketV4.close (); - m_SocketV6.close (); - if (IsRunning ()) - m_TerminationTimer.cancel (); - - StopIOService (); } void SSU2Server::SetLocalAddress (const boost::asio::ip::address& localAddress) From 4b1f5c9c9bc5962bfb66d22dd75ff947c8a958ea Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 26 Jul 2022 19:56:30 -0400 Subject: [PATCH 079/219] terminate session in separate task --- libi2pd/SSU2.cpp | 8 ++++---- libi2pd/SSU2Session.cpp | 12 ++++++------ libi2pd/SSU2Session.h | 2 +- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/libi2pd/SSU2.cpp b/libi2pd/SSU2.cpp index 2c91aeb9..b8d5b61e 100644 --- a/libi2pd/SSU2.cpp +++ b/libi2pd/SSU2.cpp @@ -403,7 +403,7 @@ namespace transport case eSSU2SessionStateSessionCreatedSent: if (!m_LastSession->ProcessSessionConfirmed (buf, len)) { - m_LastSession->Terminate (); + m_LastSession->Done (); m_LastSession = nullptr; } break; @@ -416,7 +416,7 @@ namespace transport { LogPrint (eLogWarning, "SSU2: HolePunch endpoint ", senderEndpoint, " doesn't match RelayResponse ", m_LastSession->GetRemoteEndpoint ()); - m_LastSession->Terminate (); + m_LastSession->Done (); m_LastSession = nullptr; } break; @@ -678,13 +678,13 @@ namespace transport { auto state = it.second->GetState (); if (state == eSSU2SessionStateTerminated || state == eSSU2SessionStateClosing) - GetService ().post (std::bind (&SSU2Session::Terminate, it.second)); + it.second->Done (); else if (it.second->IsTerminationTimeoutExpired (ts)) { if (it.second->IsEstablished ()) it.second->RequestTermination (eSSU2TerminationReasonIdleTimeout); else - GetService ().post (std::bind (&SSU2Session::Terminate, it.second)); + it.second->Done (); } else it.second->CleanUp (ts); diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index f3a5713a..8e3b3445 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -1338,7 +1338,7 @@ namespace transport if (IsEstablished () && buf[11] != eSSU2TerminationReasonTerminationReceived) RequestTermination (eSSU2TerminationReasonTerminationReceived); else - Terminate (); + Done (); break; case eSSU2BlkRelayRequest: LogPrint (eLogDebug, "SSU2: RelayRequest"); @@ -1696,13 +1696,13 @@ namespace transport else { LogPrint (eLogWarning, "SSU2: RelayResponse signature verification failed"); - m_Server.GetService ().post (std::bind (&SSU2Session::Terminate, it->second.first)); + it->second.first->Done (); } } else { LogPrint (eLogInfo, "SSU2: RelayResponse status code=", (int)buf[1]); - m_Server.GetService ().post (std::bind (&SSU2Session::Terminate, it->second.first)); + it->second.first->Done (); } } m_RelaySessions.erase (it); @@ -1898,13 +1898,13 @@ namespace transport else { LogPrint (eLogWarning, "SSU2: Peer test 4 address not found"); - it->second.first->Terminate (); + it->second.first->Done (); } } else { LogPrint (eLogWarning, "SSU2: Peer test 4 signature verification failed"); - it->second.first->Terminate (); + it->second.first->Done (); } } } @@ -1914,7 +1914,7 @@ namespace transport i2p::data::GetIdentHashAbbreviation (buf[1] < 64 ? GetRemoteIdentity ()->GetIdentHash () : i2p::data::IdentHash (buf + 3))); if (GetRouterStatus () == eRouterStatusTesting) SetRouterStatus (eRouterStatusUnknown); - it->second.first->Terminate (); + it->second.first->Done (); } m_PeerTests.erase (it); } diff --git a/libi2pd/SSU2Session.h b/libi2pd/SSU2Session.h index c18ca4b4..7a9f5842 100644 --- a/libi2pd/SSU2Session.h +++ b/libi2pd/SSU2Session.h @@ -222,7 +222,6 @@ namespace transport void WaitForIntroduction (); void SendPeerTest (); // Alice, Data message void SendKeepAlive (); - void Terminate (); void RequestTermination (SSU2TerminationReason reason); void CleanUp (uint64_t ts); void FlushData (); @@ -246,6 +245,7 @@ namespace transport private: + void Terminate (); void Established (); void ScheduleConnectTimer (); void HandleConnectTimer (const boost::system::error_code& ecode); From fdeb884fe5bf95777ab3022261a84e3bcbbcf2ef Mon Sep 17 00:00:00 2001 From: R4SAS Date: Wed, 27 Jul 2022 13:24:07 +0300 Subject: [PATCH 080/219] fixed getting MTU on windows, add address to log messages with MTU Signed-off-by: R4SAS --- libi2pd/RouterContext.cpp | 54 ++++++++++++++++++------------------- libi2pd/util.cpp | 56 ++++++++++++++++++++++----------------- 2 files changed, 58 insertions(+), 52 deletions(-) diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index 9e53f23b..636d47ce 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -230,8 +230,8 @@ namespace i2p auto transports = m_RouterInfo.GetCompatibleTransports (false); return (transports & (i2p::data::RouterInfo::eSSU2V4 | i2p::data::RouterInfo::eSSU2V6)) && !(transports & (i2p::data::RouterInfo::eSSUV4 | i2p::data::RouterInfo::eSSUV6)); - } - + } + void RouterContext::SetStatus (RouterStatus status) { if (status != m_Status) @@ -256,8 +256,8 @@ namespace i2p { if (IsSSU2Only ()) SetStatus (status); - } - + } + void RouterContext::SetStatusV6 (RouterStatus status) { if (status != m_StatusV6) @@ -281,8 +281,8 @@ namespace i2p { if (IsSSU2Only ()) SetStatusV6 (status); - } - + } + void RouterContext::UpdatePort (int port) { bool updated = false; @@ -472,14 +472,14 @@ namespace i2p UpdateRouterInfo (); return ret; } - + void RouterContext::RemoveSSU2Introducer (const i2p::data::IdentHash& h, bool v4) { if (!IsSSU2Only ()) return; if (m_RouterInfo.RemoveSSU2Introducer (h, v4)) UpdateRouterInfo (); - } - + } + void RouterContext::SetFloodfill (bool floodfill) { m_IsFloodfill = floodfill; @@ -598,8 +598,8 @@ namespace i2p { if (IsSSU2Only ()) SetUnreachable (v4, v6); - } - + } + void RouterContext::SetUnreachable (bool v4, bool v6) { if (v4 || (v6 && !SupportsV4 ())) @@ -649,7 +649,7 @@ namespace i2p // delete previous introducers bool isSSU2Published = IsSSU2Only (); // TODO if (isSSU2Published) - i2p::config::GetOption ("ssu2.published", isSSU2Published); + i2p::config::GetOption ("ssu2.published", isSSU2Published); auto& addresses = m_RouterInfo.GetAddresses (); for (auto& addr : addresses) if (addr->ssu && (!addr->IsSSU2 () || isSSU2Published) && @@ -880,34 +880,34 @@ namespace i2p if (addr->ssu && ((v4 && addr->IsV4 ()) || (!v4 && addr->IsV6 ()))) { if (!addr->IsSSU2 ()) // SSU1 - { + { // round to multiple of 16 if (v4) - { + { if (mtu > 1484) mtu = 1484; else - { + { mtu -= 12; mtu = (mtu >> 4) << 4; mtu += 12; - } - } - else + } + } + else { if (mtu > 1488) mtu = 1488; else mtu = (mtu >> 4) << 4; - } - } + } + } if (mtu) - { + { addr->ssu->mtu = mtu; - LogPrint (eLogDebug, "Router: MTU for ", v4 ? "ipv4" : "ipv6", " address is set to ", mtu); - } - } - } - } - + LogPrint (eLogDebug, "Router: MTU for ", v4 ? "ipv4" : "ipv6", " address ", addr->host.to_string(), " is set to ", mtu); + } + } + } + } + void RouterContext::UpdateNTCP2V6Address (const boost::asio::ip::address& host) { bool isYgg = i2p::util::net::IsYggdrasilAddress (host); diff --git a/libi2pd/util.cpp b/libi2pd/util.cpp index 5bd0fb00..e8d51dc9 100644 --- a/libi2pd/util.cpp +++ b/libi2pd/util.cpp @@ -173,7 +173,7 @@ namespace net if(dwRetVal != NO_ERROR) { - LogPrint(eLogError, "NetIface: GetMTU(): Enclosed GetAdaptersAddresses() call has failed"); + LogPrint(eLogError, "NetIface: GetMTU: Enclosed GetAdaptersAddresses() call has failed"); FREE(pAddresses); return fallback; } @@ -185,7 +185,7 @@ namespace net pUnicast = pCurrAddresses->FirstUnicastAddress; if(pUnicast == nullptr) - LogPrint(eLogError, "NetIface: GetMTU(): Not a unicast IPv4 address, this is not supported"); + LogPrint(eLogError, "NetIface: GetMTU: Not a unicast IPv4 address, this is not supported"); for(int i = 0; pUnicast != nullptr; ++i) { @@ -193,10 +193,13 @@ namespace net sockaddr_in* localInterfaceAddress = (sockaddr_in*) lpAddr; if(localInterfaceAddress->sin_addr.S_un.S_addr == inputAddress.sin_addr.S_un.S_addr) { - auto result = pAddresses->Mtu; + char addr[INET_ADDRSTRLEN]; + inet_ntop(AF_INET, &(((struct sockaddr_in *)localInterfaceAddress)->sin_addr), addr, INET_ADDRSTRLEN); + + auto result = pCurrAddresses->Mtu; FREE(pAddresses); pAddresses = nullptr; - LogPrint(eLogInfo, "NetIface: GetMTU(): Using ", result, " bytes for IPv4"); + LogPrint(eLogInfo, "NetIface: GetMTU: Using ", result, " bytes for IPv4 address ", addr); return result; } pUnicast = pUnicast->Next; @@ -204,7 +207,7 @@ namespace net pCurrAddresses = pCurrAddresses->Next; } - LogPrint(eLogError, "NetIface: GetMTU(): No usable unicast IPv4 addresses found"); + LogPrint(eLogError, "NetIface: GetMTU: No usable unicast IPv4 addresses found"); FREE(pAddresses); return fallback; } @@ -216,7 +219,7 @@ namespace net PIP_ADAPTER_ADDRESSES pCurrAddresses = nullptr; PIP_ADAPTER_UNICAST_ADDRESS pUnicast = nullptr; - if(GetAdaptersAddresses(AF_INET6, GAA_FLAG_INCLUDE_PREFIX, nullptr, pAddresses, &outBufLen) + if (GetAdaptersAddresses(AF_INET6, GAA_FLAG_INCLUDE_PREFIX, nullptr, pAddresses, &outBufLen) == ERROR_BUFFER_OVERFLOW) { FREE(pAddresses); @@ -227,23 +230,23 @@ namespace net AF_INET6, GAA_FLAG_INCLUDE_PREFIX, nullptr, pAddresses, &outBufLen ); - if(dwRetVal != NO_ERROR) + if (dwRetVal != NO_ERROR) { - LogPrint(eLogError, "NetIface: GetMTU(): Enclosed GetAdaptersAddresses() call has failed"); + LogPrint(eLogError, "NetIface: GetMTU: Enclosed GetAdaptersAddresses() call has failed"); FREE(pAddresses); return fallback; } bool found_address = false; pCurrAddresses = pAddresses; - while(pCurrAddresses) + while (pCurrAddresses) { PIP_ADAPTER_UNICAST_ADDRESS firstUnicastAddress = pCurrAddresses->FirstUnicastAddress; pUnicast = pCurrAddresses->FirstUnicastAddress; - if(pUnicast == nullptr) - LogPrint(eLogError, "NetIface: GetMTU(): Not a unicast IPv6 address, this is not supported"); + if (pUnicast == nullptr) + LogPrint(eLogError, "NetIface: GetMTU: Not a unicast IPv6 address, this is not supported"); - for(int i = 0; pUnicast != nullptr; ++i) + for (int i = 0; pUnicast != nullptr; ++i) { LPSOCKADDR lpAddr = pUnicast->Address.lpSockaddr; sockaddr_in6 *localInterfaceAddress = (sockaddr_in6*) lpAddr; @@ -258,10 +261,13 @@ namespace net if (found_address) { - auto result = pAddresses->Mtu; + char addr[INET6_ADDRSTRLEN]; + inet_ntop(AF_INET6, &(((struct sockaddr_in6 *)localInterfaceAddress)->sin6_addr), addr, INET6_ADDRSTRLEN); + + auto result = pCurrAddresses->Mtu; FREE(pAddresses); pAddresses = nullptr; - LogPrint(eLogInfo, "NetIface: GetMTU(): Using ", result, " bytes for IPv6"); + LogPrint(eLogInfo, "NetIface: GetMTU: Using ", result, " bytes for IPv6 address ", addr); return result; } pUnicast = pUnicast->Next; @@ -270,7 +276,7 @@ namespace net pCurrAddresses = pCurrAddresses->Next; } - LogPrint(eLogError, "NetIface: GetMTU(): No usable unicast IPv6 addresses found"); + LogPrint(eLogError, "NetIface: GetMTU: No usable unicast IPv6 addresses found"); FREE(pAddresses); return fallback; } @@ -302,7 +308,7 @@ namespace net } else { - LogPrint(eLogError, "NetIface: GetMTU(): Address family is not supported"); + LogPrint(eLogError, "NetIface: GetMTU: Address family is not supported"); return fallback; } } @@ -434,20 +440,20 @@ namespace net { case 0x20010470: case 0x260070ff: - // Hurricane Electric + // Hurricane Electric return 1480; break; - case 0x2a06a003: + case 0x2a06a003: case 0x2a06a004: - case 0x2a06a005: - // route48 + case 0x2a06a005: + // route48 return 1420; - break; - default: ; - } + break; + default: ; + } return 1500; - } - + } + static bool IsYggdrasilAddress (const uint8_t addr[16]) { return addr[0] == 0x02 || addr[0] == 0x03; From 991e37d0bfd4e2a3c2bd1a836476aee6771be770 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Wed, 27 Jul 2022 13:38:28 +0300 Subject: [PATCH 081/219] [peertest] fixed ssu2 router exclusion Signed-off-by: R4SAS --- libi2pd/Transports.cpp | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/libi2pd/Transports.cpp b/libi2pd/Transports.cpp index 2ae495fa..b37ef7b2 100644 --- a/libi2pd/Transports.cpp +++ b/libi2pd/Transports.cpp @@ -287,7 +287,7 @@ namespace transport } } if (m_SSUServer || m_SSU2Server) DetectExternalIP (); - + m_PeerCleanupTimer->expires_from_now (boost::posix_time::seconds(5*SESSION_CREATION_TIMEOUT)); m_PeerCleanupTimer->async_wait (std::bind (&Transports::HandlePeerCleanupTimer, this, std::placeholders::_1)); @@ -637,7 +637,7 @@ namespace transport std::set excluded; excluded.insert (i2p::context.GetIdentHash ()); // don't pick own router if (m_SSUServer) - { + { bool statusChanged = false; for (int i = 0; i < 5; i++) { @@ -666,7 +666,7 @@ namespace transport excluded.clear (); excluded.insert (i2p::context.GetIdentHash ()); for (int i = 0; i < 3; i++) - { + { auto router = i2p::data::netdb.GetRandomSSU2PeerTestRouter (true, excluded); // v4 if (router) { @@ -674,9 +674,9 @@ namespace transport i2p::context.SetStatusSSU2 (eRouterStatusTesting); m_SSU2Server->StartPeerTest (router, true); excluded.insert (router->GetIdentHash ()); - } - } - } + } + } + } } if (ipv6 && i2p::context.SupportsV6 ()) { @@ -684,7 +684,7 @@ namespace transport std::set excluded; excluded.insert (i2p::context.GetIdentHash ()); // don't pick own router if (m_SSUServer) - { + { bool statusChanged = false; for (int i = 0; i < 5; i++) { @@ -707,24 +707,24 @@ namespace transport if (!statusChanged) LogPrint (eLogWarning, "Transports: Can't find routers for peer test IPv6"); } - + // SSU2 if (m_SSU2Server) { excluded.clear (); excluded.insert (i2p::context.GetIdentHash ()); for (int i = 0; i < 3; i++) - { + { auto router = i2p::data::netdb.GetRandomSSU2PeerTestRouter (false, excluded); // v6 if (router) { if (i2p::context.GetStatusV6 () != eRouterStatusTesting) i2p::context.SetStatusV6SSU2 (eRouterStatusTesting); m_SSU2Server->StartPeerTest (router, false); + excluded.insert (router->GetIdentHash ()); } - excluded.insert (router->GetIdentHash ()); - } - } + } + } } } @@ -847,9 +847,9 @@ namespace transport session->SendLocalRouterInfo (true); it->second.nextRouterInfoUpdateTime = ts + PEER_ROUTER_INFO_UPDATE_INTERVAL + rand () % PEER_ROUTER_INFO_UPDATE_INTERVAL_VARIANCE; - } + } ++it; - } + } } UpdateBandwidth (); // TODO: use separate timer(s) for it bool ipv4Testing = i2p::context.GetStatus () == eRouterStatusTesting; From a344c09d0d843417b3ab150771711801a478ed19 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Wed, 27 Jul 2022 15:41:14 +0300 Subject: [PATCH 082/219] [util] add inet_ntop for XP Signed-off-by: R4SAS --- libi2pd/util.cpp | 56 +++++++++++++++++++++++++++++------------------- 1 file changed, 34 insertions(+), 22 deletions(-) diff --git a/libi2pd/util.cpp b/libi2pd/util.cpp index e8d51dc9..10de346f 100644 --- a/libi2pd/util.cpp +++ b/libi2pd/util.cpp @@ -36,7 +36,7 @@ #define MALLOC(x) HeapAlloc(GetProcessHeap(), 0, (x)) #define FREE(x) HeapFree(GetProcessHeap(), 0, (x)) -// inet_pton exists Windows since Vista, but XP doesn't have that function! +// inet_pton and inet_ntop have been in Windows since Vista, but XP doesn't have these functions! // This function was written by Petar Korponai?. See http://stackoverflow.com/questions/15660203/inet-pton-identifier-not-found int inet_pton_xp (int af, const char *src, void *dst) { @@ -62,6 +62,29 @@ int inet_pton_xp (int af, const char *src, void *dst) } return 0; } + +const char *inet_ntop_xp(int af, const void *src, char *dst, socklen_t size) +{ + struct sockaddr_storage ss; + unsigned long s = size; + + ZeroMemory(&ss, sizeof(ss)); + ss.ss_family = af; + + switch(af) { + case AF_INET: + ((struct sockaddr_in *)&ss)->sin_addr = *(struct in_addr *)src; + break; + case AF_INET6: + ((struct sockaddr_in6 *)&ss)->sin6_addr = *(struct in6_addr *)src; + break; + default: + return NULL; + } + /* cannot direclty use &size because of strict aliasing rules */ + return (WSAAddressToString((struct sockaddr *)&ss, sizeof(ss), NULL, dst, &s) == 0)? dst : NULL; +} + #else /* !_WIN32 => UNIX */ #include #ifdef ANDROID @@ -134,27 +157,12 @@ namespace util namespace net { #ifdef _WIN32 - bool IsWindowsXPorLater () - { - static bool isRequested = false; - static bool isXP = false; - if (!isRequested) - { - // request - OSVERSIONINFO osvi; - - ZeroMemory(&osvi, sizeof(OSVERSIONINFO)); - osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); - GetVersionEx(&osvi); - - isXP = osvi.dwMajorVersion <= 5; - isRequested = true; - } - return isXP; - } - int GetMTUWindowsIpv4 (sockaddr_in inputAddress, int fallback) { + typedef const char *(* IPN)(int af, const void *src, char *dst, socklen_t size); + IPN inetntop = (IPN)GetProcAddress (GetModuleHandle ("ws2_32.dll"), "InetNtop"); + if (!inetntop) inetntop = inet_ntop_xp; // use own implementation if not found + ULONG outBufLen = 0; PIP_ADAPTER_ADDRESSES pAddresses = nullptr; PIP_ADAPTER_ADDRESSES pCurrAddresses = nullptr; @@ -194,7 +202,7 @@ namespace net if(localInterfaceAddress->sin_addr.S_un.S_addr == inputAddress.sin_addr.S_un.S_addr) { char addr[INET_ADDRSTRLEN]; - inet_ntop(AF_INET, &(((struct sockaddr_in *)localInterfaceAddress)->sin_addr), addr, INET_ADDRSTRLEN); + inetntop(AF_INET, &(((struct sockaddr_in *)localInterfaceAddress)->sin_addr), addr, INET_ADDRSTRLEN); auto result = pCurrAddresses->Mtu; FREE(pAddresses); @@ -214,6 +222,10 @@ namespace net int GetMTUWindowsIpv6 (sockaddr_in6 inputAddress, int fallback) { + typedef const char *(* IPN)(int af, const void *src, char *dst, socklen_t size); + IPN inetntop = (IPN)GetProcAddress (GetModuleHandle ("ws2_32.dll"), "InetNtop"); + if (!inetntop) inetntop = inet_ntop_xp; // use own implementation if not found + ULONG outBufLen = 0; PIP_ADAPTER_ADDRESSES pAddresses = nullptr; PIP_ADAPTER_ADDRESSES pCurrAddresses = nullptr; @@ -262,7 +274,7 @@ namespace net if (found_address) { char addr[INET6_ADDRSTRLEN]; - inet_ntop(AF_INET6, &(((struct sockaddr_in6 *)localInterfaceAddress)->sin6_addr), addr, INET6_ADDRSTRLEN); + inetntop(AF_INET6, &(((struct sockaddr_in6 *)localInterfaceAddress)->sin6_addr), addr, INET6_ADDRSTRLEN); auto result = pCurrAddresses->Mtu; FREE(pAddresses); From ae73e8a30518470f5a7c9dc190b1685fc094f8b8 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 27 Jul 2022 10:19:25 -0400 Subject: [PATCH 083/219] find SSU2 address with static key if supports both ipv4 and ipv6 --- libi2pd/RouterInfo.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libi2pd/RouterInfo.cpp b/libi2pd/RouterInfo.cpp index 8a164852..42a0a347 100644 --- a/libi2pd/RouterInfo.cpp +++ b/libi2pd/RouterInfo.cpp @@ -979,7 +979,8 @@ namespace data return GetAddress ( [key, isV6](std::shared_ptr address)->bool { - return address->IsSSU2 () && !memcmp (address->s, key, 32) && address->IsV6 () == isV6; + return address->IsSSU2 () && !memcmp (address->s, key, 32) && + ((isV6 && address->IsV6 ()) || (!isV6 && address->IsV4 ())); }); } From 8a6fe0f3210c3082439dfe441a61ad1bb9c32950 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 27 Jul 2022 10:55:08 -0400 Subject: [PATCH 084/219] check if address type matches peer's address type for peer test msg 1 --- libi2pd/SSU2Session.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index 8e3b3445..96635cec 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -148,8 +148,11 @@ namespace transport // peer test block uint8_t payload[SSU2_MAX_PACKET_SIZE]; size_t payloadSize = CreatePeerTestBlock (payload, m_MaxPayloadSize, nonce); - payloadSize += CreatePaddingBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize); - SendData (payload, payloadSize); + if (payloadSize > 0) + { + payloadSize += CreatePaddingBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize); + SendData (payload, payloadSize); + } } void SSU2Session::SendKeepAlive () @@ -2314,7 +2317,8 @@ namespace transport size_t SSU2Session::CreatePeerTestBlock (uint8_t * buf, size_t len, uint32_t nonce) { auto localAddress = FindLocalAddress (); - if (!localAddress || !localAddress->port || localAddress->host.is_unspecified ()) + if (!localAddress || !localAddress->port || localAddress->host.is_unspecified () || + localAddress->host.is_v4 () != m_RemoteEndpoint.address ().is_v4 ()) { LogPrint (eLogWarning, "SSU2: Can't find local address for peer test"); return 0; From fd41fba069f14fb8e53f9caf27d147c37c0b6d9e Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 27 Jul 2022 20:00:03 -0400 Subject: [PATCH 085/219] variable retranmission window --- libi2pd/SSU2Session.cpp | 16 ++++++++++++++-- libi2pd/SSU2Session.h | 1 + 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index 96635cec..5b451e00 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -24,7 +24,7 @@ namespace transport m_Server (server), m_Address (addr), m_RemoteTransports (0), m_DestConnID (0), m_SourceConnID (0), m_State (eSSU2SessionStateUnknown), m_SendPacketNum (0), m_ReceivePacketNum (0), m_IsDataReceived (false), - m_WindowSize (SSU2_MAX_WINDOW_SIZE), m_RelayTag (0), + m_WindowSize (SSU2_MIN_WINDOW_SIZE), m_RelayTag (0), m_ConnectTimer (server.GetService ()), m_TerminationReason (eSSU2TerminationReasonNormalClose), m_MaxPayloadSize (SSU2_MIN_PACKET_SIZE - IPV6_HEADER_SIZE - UDP_HEADER_SIZE - 32) // min size { @@ -428,6 +428,8 @@ namespace transport #else m_SentPackets.insert (resentPackets.begin (), resentPackets.end ()); #endif + m_WindowSize >>= 1; // /2 + if (m_WindowSize < SSU2_MIN_WINDOW_SIZE) m_WindowSize = SSU2_MIN_WINDOW_SIZE; } SendQueue (); } @@ -1451,8 +1453,18 @@ namespace transport while (it != m_SentPackets.end () && it->first < firstPacketNum) it++; // find first acked packet if (it == m_SentPackets.end () || it->first > lastPacketNum) return; // not found auto it1 = it; - while (it1 != m_SentPackets.end () && it1->first <= lastPacketNum) it1++; + int numPackets = 0; + while (it1 != m_SentPackets.end () && it1->first <= lastPacketNum) + { + it1++; + numPackets++; + } m_SentPackets.erase (it, it1); + if (numPackets > 0) + { + m_WindowSize += numPackets; + if (m_WindowSize > SSU2_MAX_WINDOW_SIZE) m_WindowSize = SSU2_MAX_WINDOW_SIZE; + } } void SSU2Session::HandleFirstFragment (const uint8_t * buf, size_t len) diff --git a/libi2pd/SSU2Session.h b/libi2pd/SSU2Session.h index 7a9f5842..deb198f8 100644 --- a/libi2pd/SSU2Session.h +++ b/libi2pd/SSU2Session.h @@ -38,6 +38,7 @@ namespace transport const int SSU2_RESEND_INTERVAL = 3; // in seconds const int SSU2_MAX_NUM_RESENDS = 5; const int SSU2_INCOMPLETE_MESSAGES_CLEANUP_TIMEOUT = 30; // in seconds + const size_t SSU2_MIN_WINDOW_SIZE = 8; // in packets const size_t SSU2_MAX_WINDOW_SIZE = 128; // in packets const size_t SSU2_MAX_OUTGOING_QUEUE_SIZE = 300; // in messages const int SSU2_MAX_NUM_ACK_RANGES = 32; // to send From e70d57dcb48e5f707629617a06b395937ae8c4f3 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 28 Jul 2022 19:30:08 -0400 Subject: [PATCH 086/219] resend intervals in milliseconds --- libi2pd/SSU2.cpp | 4 ++-- libi2pd/SSU2.h | 3 ++- libi2pd/SSU2Session.cpp | 16 +++++++--------- libi2pd/SSU2Session.h | 6 +++--- 4 files changed, 14 insertions(+), 15 deletions(-) diff --git a/libi2pd/SSU2.cpp b/libi2pd/SSU2.cpp index b8d5b61e..fc92c747 100644 --- a/libi2pd/SSU2.cpp +++ b/libi2pd/SSU2.cpp @@ -729,7 +729,7 @@ namespace transport void SSU2Server::ScheduleResend () { - m_ResendTimer.expires_from_now (boost::posix_time::seconds(SSU2_RESEND_INTERVAL)); + m_ResendTimer.expires_from_now (boost::posix_time::milliseconds(SSU2_RESEND_CHECK_TIMEOUT)); m_ResendTimer.async_wait (std::bind (&SSU2Server::HandleResendTimer, this, std::placeholders::_1)); } @@ -738,7 +738,7 @@ namespace transport { if (ecode != boost::asio::error::operation_aborted) { - auto ts = i2p::util::GetSecondsSinceEpoch (); + auto ts = i2p::util::GetMillisecondsSinceEpoch (); for (auto it: m_Sessions) it.second->Resend (ts); for (auto it: m_PendingOutgoingSessions) diff --git a/libi2pd/SSU2.h b/libi2pd/SSU2.h index 1625080b..010c2c00 100644 --- a/libi2pd/SSU2.h +++ b/libi2pd/SSU2.h @@ -17,7 +17,8 @@ namespace i2p { namespace transport { - const int SSU2_TERMINATION_CHECK_TIMEOUT = 30; // 30 seconds + const int SSU2_TERMINATION_CHECK_TIMEOUT = 30; // in seconds + const int SSU2_RESEND_CHECK_TIMEOUT = 500; // in milliseconds const size_t SSU2_SOCKET_RECEIVE_BUFFER_SIZE = 0x1FFFF; // 128K const size_t SSU2_SOCKET_SEND_BUFFER_SIZE = 0x1FFFF; // 128K const size_t SSU2_MAX_NUM_INTRODUCERS = 3; diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index 5b451e00..4846446f 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -265,7 +265,7 @@ namespace transport { if (!m_SendQueue.empty () && m_SentPackets.size () <= m_WindowSize) { - auto nextResend = i2p::util::GetSecondsSinceEpoch () + SSU2_RESEND_INTERVAL; + auto nextResend = i2p::util::GetMillisecondsSinceEpoch () + SSU2_RESEND_INTERVAL; auto packet = std::make_shared(); size_t ackBlockSize = CreateAckBlock (packet->payload, m_MaxPayloadSize); bool ackBlockSent = false; @@ -344,7 +344,7 @@ namespace transport bool ackBlockSent = false; uint32_t msgID; memcpy (&msgID, msg->GetHeader () + I2NP_HEADER_MSGID_OFFSET, 4); - auto nextResend = i2p::util::GetSecondsSinceEpoch () + SSU2_RESEND_INTERVAL; + auto nextResend = i2p::util::GetMillisecondsSinceEpoch () + SSU2_RESEND_INTERVAL; auto packet = std::make_shared(); if (extraSize >= 8) { @@ -414,7 +414,6 @@ namespace transport uint32_t packetNum = SendData (it->second->payload, it->second->payloadSize); it->second->numResends++; it->second->nextResendTime = ts + it->second->numResends*SSU2_RESEND_INTERVAL; - m_LastActivityTimestamp = ts; resentPackets.emplace (packetNum, it->second); it = m_SentPackets.erase (it); } @@ -486,7 +485,7 @@ namespace transport // we are Alice m_EphemeralKeys = i2p::transport::transports.GetNextX25519KeysPair (); m_SentHandshakePacket.reset (new HandshakePacket); - auto ts = i2p::util::GetSecondsSinceEpoch (); + auto ts = i2p::util::GetMillisecondsSinceEpoch (); m_SentHandshakePacket->nextResendTime = ts + SSU2_HANDSHAKE_RESEND_INTERVAL; Header& header = m_SentHandshakePacket->header; @@ -505,7 +504,7 @@ namespace transport // payload payload[0] = eSSU2BlkDateTime; htobe16buf (payload + 1, 4); - htobe32buf (payload + 3, ts); + htobe32buf (payload + 3, ts/1000); size_t payloadSize = 7; if (GetRouterStatus () == eRouterStatusFirewalled && m_Address->IsIntroducer ()) { @@ -587,7 +586,7 @@ namespace transport // we are Bob m_EphemeralKeys = i2p::transport::transports.GetNextX25519KeysPair (); m_SentHandshakePacket.reset (new HandshakePacket); - auto ts = i2p::util::GetSecondsSinceEpoch (); + auto ts = i2p::util::GetMillisecondsSinceEpoch (); m_SentHandshakePacket->nextResendTime = ts + SSU2_HANDSHAKE_RESEND_INTERVAL; uint8_t kh2[32]; @@ -609,7 +608,7 @@ namespace transport size_t maxPayloadSize = m_MaxPayloadSize - 48; payload[0] = eSSU2BlkDateTime; htobe16buf (payload + 1, 4); - htobe32buf (payload + 3, ts); + htobe32buf (payload + 3, ts/1000); size_t payloadSize = 7; payloadSize += CreateAddressBlock (payload + payloadSize, maxPayloadSize - payloadSize, m_RemoteEndpoint); if (m_RelayTag) @@ -700,8 +699,7 @@ namespace transport { // we are Alice m_SentHandshakePacket.reset (new HandshakePacket); - auto ts = i2p::util::GetSecondsSinceEpoch (); - m_SentHandshakePacket->nextResendTime = ts + SSU2_HANDSHAKE_RESEND_INTERVAL; + m_SentHandshakePacket->nextResendTime = i2p::util::GetMillisecondsSinceEpoch () + SSU2_HANDSHAKE_RESEND_INTERVAL; uint8_t kh2[32]; i2p::crypto::HKDF (m_NoiseState->m_CK, nullptr, 0, "SessionConfirmed", kh2, 32); // k_header_2 = HKDF(chainKey, ZEROLEN, "SessionConfirmed", 32) diff --git a/libi2pd/SSU2Session.h b/libi2pd/SSU2Session.h index deb198f8..d8c7ce4f 100644 --- a/libi2pd/SSU2Session.h +++ b/libi2pd/SSU2Session.h @@ -35,7 +35,7 @@ namespace transport const size_t SSU2_MAX_PACKET_SIZE = 1500; const size_t SSU2_MIN_PACKET_SIZE = 1280; const int SSU2_HANDSHAKE_RESEND_INTERVAL = 1; // in seconds - const int SSU2_RESEND_INTERVAL = 3; // in seconds + const int SSU2_RESEND_INTERVAL = 300; // in milliseconds const int SSU2_MAX_NUM_RESENDS = 5; const int SSU2_INCOMPLETE_MESSAGES_CLEANUP_TIMEOUT = 30; // in seconds const size_t SSU2_MIN_WINDOW_SIZE = 8; // in packets @@ -189,7 +189,7 @@ namespace transport { uint8_t payload[SSU2_MAX_PACKET_SIZE]; size_t payloadSize = 0; - uint32_t nextResendTime; // in seconds + uint64_t nextResendTime; // in milliseconds int numResends = 0; }; @@ -199,7 +199,7 @@ namespace transport uint8_t headerX[48]; // part1 for SessionConfirmed uint8_t payload[SSU2_MAX_PACKET_SIZE*2]; size_t payloadSize = 0; - uint32_t nextResendTime = 0; // in seconds + uint64_t nextResendTime = 0; // in milliseconds bool isSecondFragment = false; // for SessionConfirmed }; From 01fe642beb859cf2018298b2d331cf7e544dd1fd Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 29 Jul 2022 12:48:23 -0400 Subject: [PATCH 087/219] don't create another session for peer test --- libi2pd/SSU2.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libi2pd/SSU2.cpp b/libi2pd/SSU2.cpp index fc92c747..21c70a44 100644 --- a/libi2pd/SSU2.cpp +++ b/libi2pd/SSU2.cpp @@ -646,8 +646,9 @@ namespace transport else s->SetOnEstablished ([s]() { s->SendPeerTest (); }); return true; - } - CreateSession (router, addr, true); + } + else + CreateSession (router, addr, true); return true; } From 3bd40fc8b30f0da063c061a9e39ad7a7d75861fc Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 29 Jul 2022 15:24:24 -0400 Subject: [PATCH 088/219] calculate RTT and RTO --- libi2pd/SSU2Session.cpp | 49 ++++++++++++++++++++++++++--------------- libi2pd/SSU2Session.h | 10 +++++---- 2 files changed, 37 insertions(+), 22 deletions(-) diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index 4846446f..5f1b4bb5 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -24,7 +24,8 @@ namespace transport m_Server (server), m_Address (addr), m_RemoteTransports (0), m_DestConnID (0), m_SourceConnID (0), m_State (eSSU2SessionStateUnknown), m_SendPacketNum (0), m_ReceivePacketNum (0), m_IsDataReceived (false), - m_WindowSize (SSU2_MIN_WINDOW_SIZE), m_RelayTag (0), + m_WindowSize (SSU2_MIN_WINDOW_SIZE), m_RTT (SSU2_RESEND_INTERVAL), + m_RTO (SSU2_RESEND_INTERVAL*1.5), m_RelayTag (0), m_ConnectTimer (server.GetService ()), m_TerminationReason (eSSU2TerminationReasonNormalClose), m_MaxPayloadSize (SSU2_MIN_PACKET_SIZE - IPV6_HEADER_SIZE - UDP_HEADER_SIZE - 32) // min size { @@ -265,7 +266,7 @@ namespace transport { if (!m_SendQueue.empty () && m_SentPackets.size () <= m_WindowSize) { - auto nextResend = i2p::util::GetMillisecondsSinceEpoch () + SSU2_RESEND_INTERVAL; + auto ts = i2p::util::GetMillisecondsSinceEpoch (); auto packet = std::make_shared(); size_t ackBlockSize = CreateAckBlock (packet->payload, m_MaxPayloadSize); bool ackBlockSent = false; @@ -318,7 +319,7 @@ namespace transport } // send right a way uint32_t packetNum = SendData (packet->payload, packet->payloadSize); - packet->nextResendTime = nextResend; + packet->sendTime = ts; m_SentPackets.emplace (packetNum, packet); packet = newPacket; // just ack block } @@ -329,7 +330,7 @@ namespace transport if (packet->payloadSize + 16 < m_MaxPayloadSize) packet->payloadSize += CreatePaddingBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize); uint32_t packetNum = SendData (packet->payload, packet->payloadSize); - packet->nextResendTime = nextResend; + packet->sendTime = ts; m_SentPackets.emplace (packetNum, packet); } return ackBlockSent; @@ -344,7 +345,7 @@ namespace transport bool ackBlockSent = false; uint32_t msgID; memcpy (&msgID, msg->GetHeader () + I2NP_HEADER_MSGID_OFFSET, 4); - auto nextResend = i2p::util::GetMillisecondsSinceEpoch () + SSU2_RESEND_INTERVAL; + auto ts = i2p::util::GetMillisecondsSinceEpoch (); auto packet = std::make_shared(); if (extraSize >= 8) { @@ -353,7 +354,7 @@ namespace transport if (packet->payloadSize + 12 < m_MaxPayloadSize) { uint32_t packetNum = SendData (packet->payload, packet->payloadSize); - packet->nextResendTime = nextResend; + packet->sendTime = ts; m_SentPackets.emplace (packetNum, packet); packet = std::make_shared(); } @@ -367,7 +368,7 @@ namespace transport extraSize -= offset; packet->payloadSize += size; uint32_t firstPacketNum = SendData (packet->payload, packet->payloadSize); - packet->nextResendTime = nextResend; + packet->sendTime = ts; m_SentPackets.emplace (firstPacketNum, packet); uint8_t fragmentNum = 0; while (msg->offset < msg->len) @@ -379,7 +380,7 @@ namespace transport if (msg->offset >= msg->len && packet->payloadSize + 16 < m_MaxPayloadSize) // last fragment packet->payloadSize += CreatePaddingBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize); uint32_t followonPacketNum = SendData (packet->payload, packet->payloadSize); - packet->nextResendTime = nextResend; + packet->sendTime = ts; m_SentPackets.emplace (followonPacketNum, packet); } return ackBlockSent; @@ -388,18 +389,18 @@ namespace transport void SSU2Session::Resend (uint64_t ts) { // resend handshake packet - if (m_SentHandshakePacket && ts >= m_SentHandshakePacket->nextResendTime) + if (m_SentHandshakePacket && ts >= m_SentHandshakePacket->sendTime + SSU2_HANDSHAKE_RESEND_INTERVAL) { LogPrint (eLogDebug, "SSU2: Resending ", (int)m_State); ResendHandshakePacket (); - m_SentHandshakePacket->nextResendTime = ts + SSU2_HANDSHAKE_RESEND_INTERVAL; + m_SentHandshakePacket->sendTime = ts; return; } // resend data packets if (m_SentPackets.empty ()) return; std::map > resentPackets; for (auto it = m_SentPackets.begin (); it != m_SentPackets.end (); ) - if (ts >= it->second->nextResendTime) + if (ts >= it->second->sendTime + it->second->numResends*m_RTO) { if (it->second->numResends > SSU2_MAX_NUM_RESENDS) { @@ -413,7 +414,7 @@ namespace transport { uint32_t packetNum = SendData (it->second->payload, it->second->payloadSize); it->second->numResends++; - it->second->nextResendTime = ts + it->second->numResends*SSU2_RESEND_INTERVAL; + it->second->sendTime = ts; resentPackets.emplace (packetNum, it->second); it = m_SentPackets.erase (it); } @@ -486,7 +487,7 @@ namespace transport m_EphemeralKeys = i2p::transport::transports.GetNextX25519KeysPair (); m_SentHandshakePacket.reset (new HandshakePacket); auto ts = i2p::util::GetMillisecondsSinceEpoch (); - m_SentHandshakePacket->nextResendTime = ts + SSU2_HANDSHAKE_RESEND_INTERVAL; + m_SentHandshakePacket->sendTime = ts; Header& header = m_SentHandshakePacket->header; uint8_t * headerX = m_SentHandshakePacket->headerX, @@ -587,7 +588,7 @@ namespace transport m_EphemeralKeys = i2p::transport::transports.GetNextX25519KeysPair (); m_SentHandshakePacket.reset (new HandshakePacket); auto ts = i2p::util::GetMillisecondsSinceEpoch (); - m_SentHandshakePacket->nextResendTime = ts + SSU2_HANDSHAKE_RESEND_INTERVAL; + m_SentHandshakePacket->sendTime = ts; uint8_t kh2[32]; i2p::crypto::HKDF (m_NoiseState->m_CK, nullptr, 0, "SessCreateHeader", kh2, 32); // k_header_2 = HKDF(chainKey, ZEROLEN, "SessCreateHeader", 32) @@ -699,7 +700,7 @@ namespace transport { // we are Alice m_SentHandshakePacket.reset (new HandshakePacket); - m_SentHandshakePacket->nextResendTime = i2p::util::GetMillisecondsSinceEpoch () + SSU2_HANDSHAKE_RESEND_INTERVAL; + m_SentHandshakePacket->sendTime = i2p::util::GetMillisecondsSinceEpoch (); uint8_t kh2[32]; i2p::crypto::HKDF (m_NoiseState->m_CK, nullptr, 0, "SessionConfirmed", kh2, 32); // k_header_2 = HKDF(chainKey, ZEROLEN, "SessionConfirmed", 32) @@ -1428,7 +1429,7 @@ namespace transport // acnt uint32_t ackThrough = bufbe32toh (buf); uint32_t firstPacketNum = ackThrough > buf[4] ? ackThrough - buf[4] : 0; - HandleAckRange (firstPacketNum, ackThrough); // acnt + HandleAckRange (firstPacketNum, ackThrough, i2p::util::GetMillisecondsSinceEpoch ()); // acnt // ranges len -= 5; const uint8_t * ranges = buf + 5; @@ -1440,11 +1441,11 @@ namespace transport if (*ranges > lastPacketNum + 1) break; firstPacketNum = lastPacketNum - *ranges + 1; ranges++; // acks len -= 2; - HandleAckRange (firstPacketNum, lastPacketNum); + HandleAckRange (firstPacketNum, lastPacketNum, 0); } } - void SSU2Session::HandleAckRange (uint32_t firstPacketNum, uint32_t lastPacketNum) + void SSU2Session::HandleAckRange (uint32_t firstPacketNum, uint32_t lastPacketNum, uint64_t ts) { if (firstPacketNum > lastPacketNum) return; auto it = m_SentPackets.begin (); @@ -1454,6 +1455,18 @@ namespace transport int numPackets = 0; while (it1 != m_SentPackets.end () && it1->first <= lastPacketNum) { + if (ts && !it1->second->numResends) + { + if (ts > it1->second->sendTime) + { + auto rtt = ts - it1->second->sendTime; + m_RTT = (m_RTT*m_SendPacketNum + rtt)/(m_SendPacketNum + 1); + m_RTO = m_RTT*1.5; + if (m_RTO < SSU2_MIN_RTO) m_RTO = SSU2_MIN_RTO; + if (m_RTO > SSU2_MAX_RTO) m_RTO = SSU2_MAX_RTO; + } + ts = 0; // update RTT one time per range + } it1++; numPackets++; } diff --git a/libi2pd/SSU2Session.h b/libi2pd/SSU2Session.h index d8c7ce4f..14ec04a2 100644 --- a/libi2pd/SSU2Session.h +++ b/libi2pd/SSU2Session.h @@ -40,6 +40,8 @@ namespace transport const int SSU2_INCOMPLETE_MESSAGES_CLEANUP_TIMEOUT = 30; // in seconds const size_t SSU2_MIN_WINDOW_SIZE = 8; // in packets const size_t SSU2_MAX_WINDOW_SIZE = 128; // in packets + const size_t SSU2_MIN_RTO = 10; // in milliseconds + const size_t SSU2_MAX_RTO = 2000; // in milliseconds const size_t SSU2_MAX_OUTGOING_QUEUE_SIZE = 300; // in messages const int SSU2_MAX_NUM_ACK_RANGES = 32; // to send @@ -189,7 +191,7 @@ namespace transport { uint8_t payload[SSU2_MAX_PACKET_SIZE]; size_t payloadSize = 0; - uint64_t nextResendTime; // in milliseconds + uint64_t sendTime; // in milliseconds int numResends = 0; }; @@ -199,7 +201,7 @@ namespace transport uint8_t headerX[48]; // part1 for SessionConfirmed uint8_t payload[SSU2_MAX_PACKET_SIZE*2]; size_t payloadSize = 0; - uint64_t nextResendTime = 0; // in milliseconds + uint64_t sendTime = 0; // in milliseconds bool isSecondFragment = false; // for SessionConfirmed }; @@ -272,7 +274,7 @@ namespace transport void HandlePayload (const uint8_t * buf, size_t len); void HandleAck (const uint8_t * buf, size_t len); - void HandleAckRange (uint32_t firstPacketNum, uint32_t lastPacketNum); + void HandleAckRange (uint32_t firstPacketNum, uint32_t lastPacketNum, uint64_t ts); bool ExtractEndpoint (const uint8_t * buf, size_t size, boost::asio::ip::udp::endpoint& ep); size_t CreateEndpoint (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& ep); std::shared_ptr FindLocalAddress () const; @@ -325,7 +327,7 @@ namespace transport std::list > m_SendQueue; i2p::I2NPMessagesHandler m_Handler; bool m_IsDataReceived; - size_t m_WindowSize; + size_t m_WindowSize, m_RTT, m_RTO; uint32_t m_RelayTag; // between Bob and Charlie OnEstablished m_OnEstablished; // callback from Established boost::asio::deadline_timer m_ConnectTimer; From 9afe3b5f39e22fa9f40f730609c288274afe8c98 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 29 Jul 2022 18:27:21 -0400 Subject: [PATCH 089/219] fixed typo --- libi2pd/SSU2.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd/SSU2.cpp b/libi2pd/SSU2.cpp index 21c70a44..59ffaf42 100644 --- a/libi2pd/SSU2.cpp +++ b/libi2pd/SSU2.cpp @@ -792,7 +792,7 @@ namespace transport std::list > ret; for (const auto& s : m_Sessions) { - if (s.second->IsEstablished () && (s.second->GetRelayTag () && !s.second->IsOutgoing ()) && + if (s.second->IsEstablished () && (s.second->GetRelayTag () && s.second->IsOutgoing ()) && !excluded.count (s.second->GetRemoteIdentity ()->GetIdentHash ()) && ((v4 && (s.second->GetRemoteTransports () & i2p::data::RouterInfo::eSSU2V4)) || (!v4 && (s.second->GetRemoteTransports () & i2p::data::RouterInfo::eSSU2V6)))) From 0e6d888ed316b885e3e661c818e93d48c1ddca77 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 29 Jul 2022 18:45:02 -0400 Subject: [PATCH 090/219] changed some retransmission params --- libi2pd/SSU2Session.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/libi2pd/SSU2Session.h b/libi2pd/SSU2Session.h index 14ec04a2..b2d61e80 100644 --- a/libi2pd/SSU2Session.h +++ b/libi2pd/SSU2Session.h @@ -34,15 +34,15 @@ namespace transport const int SSU2_PEER_TEST_EXPIRATION_TIMEOUT = 60; // 60 seconds const size_t SSU2_MAX_PACKET_SIZE = 1500; const size_t SSU2_MIN_PACKET_SIZE = 1280; - const int SSU2_HANDSHAKE_RESEND_INTERVAL = 1; // in seconds + const int SSU2_HANDSHAKE_RESEND_INTERVAL = 1000; // in millseconds const int SSU2_RESEND_INTERVAL = 300; // in milliseconds const int SSU2_MAX_NUM_RESENDS = 5; const int SSU2_INCOMPLETE_MESSAGES_CLEANUP_TIMEOUT = 30; // in seconds - const size_t SSU2_MIN_WINDOW_SIZE = 8; // in packets - const size_t SSU2_MAX_WINDOW_SIZE = 128; // in packets - const size_t SSU2_MIN_RTO = 10; // in milliseconds - const size_t SSU2_MAX_RTO = 2000; // in milliseconds - const size_t SSU2_MAX_OUTGOING_QUEUE_SIZE = 300; // in messages + const size_t SSU2_MIN_WINDOW_SIZE = 16; // in packets + const size_t SSU2_MAX_WINDOW_SIZE = 256; // in packets + const size_t SSU2_MIN_RTO = 100; // in milliseconds + const size_t SSU2_MAX_RTO = 2500; // in milliseconds + const size_t SSU2_MAX_OUTGOING_QUEUE_SIZE = 500; // in messages const int SSU2_MAX_NUM_ACK_RANGES = 32; // to send enum SSU2MessageType From fc63ca6982fb9bdcfa0acbd678ed2e6b6815ecd8 Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 30 Jul 2022 14:28:09 -0400 Subject: [PATCH 091/219] correct excluded routers size for exploratory request --- libi2pd/NetDb.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/libi2pd/NetDb.cpp b/libi2pd/NetDb.cpp index e36e4f13..8bbabff4 100644 --- a/libi2pd/NetDb.cpp +++ b/libi2pd/NetDb.cpp @@ -945,9 +945,9 @@ namespace data } uint16_t numExcluded = bufbe16toh (excluded); excluded += 2; - if (numExcluded > 512) + if (numExcluded > 512 || (excluded - buf) + numExcluded*32 > (int)msg->GetPayloadLength ()) { - LogPrint (eLogWarning, "NetDb: Number of excluded peers", numExcluded, " exceeds 512"); + LogPrint (eLogWarning, "NetDb: Number of excluded peers", numExcluded, " is too much"); return; } @@ -956,10 +956,11 @@ namespace data { LogPrint (eLogInfo, "NetDb: Exploratory close to ", key, " ", numExcluded, " excluded"); std::set excludedRouters; + const uint8_t * excluded_ident = excluded; for (int i = 0; i < numExcluded; i++) { - excludedRouters.insert (excluded); - excluded += 32; + excludedRouters.insert (excluded_ident); + excluded_ident += 32; } std::vector routers; for (int i = 0; i < 3; i++) @@ -1017,7 +1018,7 @@ namespace data if (closestFloodfills.empty ()) LogPrint (eLogWarning, "NetDb: Requested ", key, " not found, ", numExcluded, " peers excluded"); replyMsg = CreateDatabaseSearchReply (ident, closestFloodfills); - } + } } excluded += numExcluded * 32; if (replyMsg) From 71766ecd16bbbc76a64cca9d19c50c460dcfc632 Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 30 Jul 2022 16:31:44 -0400 Subject: [PATCH 092/219] select introducers randomly. More logging for RelayIntro --- libi2pd/SSU2.cpp | 34 ++++++++++++++++++++++------------ libi2pd/SSU2Session.cpp | 6 +++++- 2 files changed, 27 insertions(+), 13 deletions(-) diff --git a/libi2pd/SSU2.cpp b/libi2pd/SSU2.cpp index 59ffaf42..f8f6e69d 100644 --- a/libi2pd/SSU2.cpp +++ b/libi2pd/SSU2.cpp @@ -6,6 +6,7 @@ * See full license text in LICENSE file at top of project tree */ +#include #include "Log.h" #include "RouterContext.h" #include "Transports.h" @@ -576,18 +577,27 @@ namespace transport auto ts = i2p::util::GetSecondsSinceEpoch (); std::shared_ptr r; uint32_t relayTag = 0; - for (auto& it: address->ssu->introducers) - { - if (it.iTag && ts < it.iExp) - { - r = i2p::data::netdb.FindRouter (it.iKey); - if (r && r->IsReachableFrom (i2p::context.GetRouterInfo ())) - { - relayTag = it.iTag; - if (relayTag) break; - } - } - } + if (!address->ssu->introducers.empty ()) + { + std::vector indicies; + for (int i = 0; i < (int)address->ssu->introducers.size (); i++) indicies.push_back(i); + if (indicies.size () > 1) + std::shuffle (indicies.begin(), indicies.end(), std::mt19937(std::random_device()())); + + for (auto i: indicies) + { + const auto& introducer = address->ssu->introducers[indicies[i]]; + if (introducer.iTag && ts < introducer.iExp) + { + r = i2p::data::netdb.FindRouter (introducer.iKey); + if (r && r->IsReachableFrom (i2p::context.GetRouterInfo ())) + { + relayTag = introducer.iTag; + if (relayTag) break; + } + } + } + } if (r) { if (relayTag) diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index 5f1b4bb5..ddeebbe8 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -1070,6 +1070,7 @@ namespace transport const uint8_t * introKey, uint64_t token) { // we are Charlie + LogPrint (eLogDebug, "SSU2: Sending HolePunch to ", ep); Header header; uint8_t h[32], payload[SSU2_MAX_PACKET_SIZE]; // fill packet @@ -1641,11 +1642,14 @@ namespace transport SendHolePunch (bufbe32toh (buf + 33), ep, addr->i, token); } else + { + LogPrint (eLogWarning, "SSU2: RelayIntro unsupported address"); code = eSSU2RelayResponseCodeCharlieUnsupportedAddress; + } } else { - LogPrint (eLogWarning, "SSU2: RelayInfo unknown address"); + LogPrint (eLogWarning, "SSU2: RelayIntro unknown address"); code = eSSU2RelayResponseCodeCharlieAliceIsUnknown; } } From ff5fa1d137863b92636fa9e8c730ca3f3dc2e178 Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 30 Jul 2022 18:50:43 -0400 Subject: [PATCH 093/219] 3 bytes off for token in RelayResponse --- libi2pd/SSU2Session.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index ddeebbe8..cc358778 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -2313,7 +2313,7 @@ namespace transport size_t payloadSize = 12 + csz + i2p::context.GetIdentity ()->GetSignatureLen (); if (!code) { - memcpy (buf + payloadSize, &token, 8); + memcpy (buf + 3 + payloadSize, &token, 8); payloadSize += 8; } htobe16buf (buf + 1, payloadSize); // size From eba4626589e33ba05983de7ea848c6e1c2b4aa86 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 31 Jul 2022 09:45:18 -0400 Subject: [PATCH 094/219] kappa for RTO culculation --- libi2pd/SSU2Session.cpp | 4 ++-- libi2pd/SSU2Session.h | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index cc358778..761fdf8e 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -25,7 +25,7 @@ namespace transport m_DestConnID (0), m_SourceConnID (0), m_State (eSSU2SessionStateUnknown), m_SendPacketNum (0), m_ReceivePacketNum (0), m_IsDataReceived (false), m_WindowSize (SSU2_MIN_WINDOW_SIZE), m_RTT (SSU2_RESEND_INTERVAL), - m_RTO (SSU2_RESEND_INTERVAL*1.5), m_RelayTag (0), + m_RTO (SSU2_RESEND_INTERVAL*SSU2_kAPPA), m_RelayTag (0), m_ConnectTimer (server.GetService ()), m_TerminationReason (eSSU2TerminationReasonNormalClose), m_MaxPayloadSize (SSU2_MIN_PACKET_SIZE - IPV6_HEADER_SIZE - UDP_HEADER_SIZE - 32) // min size { @@ -1462,7 +1462,7 @@ namespace transport { auto rtt = ts - it1->second->sendTime; m_RTT = (m_RTT*m_SendPacketNum + rtt)/(m_SendPacketNum + 1); - m_RTO = m_RTT*1.5; + m_RTO = m_RTT*SSU2_kAPPA; if (m_RTO < SSU2_MIN_RTO) m_RTO = SSU2_MIN_RTO; if (m_RTO > SSU2_MAX_RTO) m_RTO = SSU2_MAX_RTO; } diff --git a/libi2pd/SSU2Session.h b/libi2pd/SSU2Session.h index b2d61e80..0ca4933a 100644 --- a/libi2pd/SSU2Session.h +++ b/libi2pd/SSU2Session.h @@ -42,6 +42,7 @@ namespace transport const size_t SSU2_MAX_WINDOW_SIZE = 256; // in packets const size_t SSU2_MIN_RTO = 100; // in milliseconds const size_t SSU2_MAX_RTO = 2500; // in milliseconds + const float SSU2_kAPPA = 1.8; const size_t SSU2_MAX_OUTGOING_QUEUE_SIZE = 500; // in messages const int SSU2_MAX_NUM_ACK_RANGES = 32; // to send From 9d9d5e3e5d183c0d63067895f669a62232cd9780 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 31 Jul 2022 09:47:04 -0400 Subject: [PATCH 095/219] show ports for tranport links --- daemon/HTTPServer.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/daemon/HTTPServer.cpp b/daemon/HTTPServer.cpp index 9bc49f38..2a083dea 100644 --- a/daemon/HTTPServer.cpp +++ b/daemon/HTTPServer.cpp @@ -793,12 +793,13 @@ namespace http { std::stringstream tmp_s, tmp_s6; uint16_t cnt = 0, cnt6 = 0; for (const auto& it: sessions ) { - if (it.second && it.second->IsEstablished () && !it.second->GetRemoteEndpoint ().address ().is_v6 ()) + auto endpoint = it.second->GetRemoteEndpoint (); + if (it.second && it.second->IsEstablished () && endpoint.address ().is_v4 ()) { tmp_s << "
\r\n"; if (it.second->IsOutgoing ()) tmp_s << " ⇒ "; tmp_s << i2p::data::GetIdentHashAbbreviation (it.second->GetRemoteIdentity ()->GetIdentHash ()) << ": " - << it.second->GetRemoteEndpoint ().address ().to_string (); + << endpoint.address ().to_string () << ":" << endpoint.port (); if (!it.second->IsOutgoing ()) tmp_s << " ⇒ "; tmp_s << " [" << it.second->GetNumSentBytes () << ":" << it.second->GetNumReceivedBytes () << "]"; if (it.second->GetRelayTag ()) @@ -806,12 +807,12 @@ namespace http { tmp_s << "
\r\n" << std::endl; cnt++; } - if (it.second && it.second->IsEstablished () && it.second->GetRemoteEndpoint ().address ().is_v6 ()) + if (it.second && it.second->IsEstablished () && endpoint.address ().is_v6 ()) { tmp_s6 << "
\r\n"; if (it.second->IsOutgoing ()) tmp_s6 << " ⇒ "; tmp_s6 << i2p::data::GetIdentHashAbbreviation (it.second->GetRemoteIdentity ()->GetIdentHash ()) << ": " - << "[" << it.second->GetRemoteEndpoint ().address ().to_string () << "]"; + << "[" << endpoint.address ().to_string () << "]:" << endpoint.port (); if (!it.second->IsOutgoing ()) tmp_s6 << " ⇒ "; tmp_s6 << " [" << it.second->GetNumSentBytes () << ":" << it.second->GetNumReceivedBytes () << "]"; if (it.second->GetRelayTag ()) From 98d2ce584555a4e397a7fbcc3af0feaec9896eda Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 2 Aug 2022 13:35:18 -0400 Subject: [PATCH 096/219] Respond to path challenge. Correct termination reason for duplicated session --- libi2pd/SSU2.cpp | 2 +- libi2pd/SSU2Session.cpp | 16 ++++++++++++++++ libi2pd/SSU2Session.h | 4 +++- 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/libi2pd/SSU2.cpp b/libi2pd/SSU2.cpp index f8f6e69d..551dd148 100644 --- a/libi2pd/SSU2.cpp +++ b/libi2pd/SSU2.cpp @@ -292,7 +292,7 @@ namespace transport // session already exists LogPrint (eLogWarning, "SSU2: Session to ", ident->GetIdentHash ().ToBase64 (), " already exists"); // terminate existing - GetService ().post (std::bind (&SSU2Session::RequestTermination, ret.first->second, eSSU2TerminationReasonTerminationReceived)); + GetService ().post (std::bind (&SSU2Session::RequestTermination, ret.first->second, eSSU2TerminationReasonReplacedByNewSession)); // update session ret.first->second = session; } diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index 761fdf8e..475d7cef 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -1403,8 +1403,11 @@ namespace transport break; } case eSSU2BlkPathChallenge: + LogPrint (eLogDebug, "SSU2: Path challenge"); + SendPathResponse (buf + offset, size); break; case eSSU2BlkPathResponse: + LogPrint (eLogDebug, "SSU2: Path response"); break; case eSSU2BlkFirstPacketNumber: break; @@ -2440,6 +2443,19 @@ namespace transport payloadSize += CreatePaddingBlock (payload + payloadSize, 32 - payloadSize); SendData (payload, payloadSize); } + + void SSU2Session::SendPathResponse (const uint8_t * data, size_t len) + { + if (len < 8 || len > m_MaxPayloadSize - 3) + { + LogPrint (eLogWarning, "SSU2: Incorrect data size for path response ", len); + return; + } + uint8_t payload[SSU2_MAX_PACKET_SIZE]; + payload[0] = eSSU2BlkPathResponse; + htobe16buf (payload + 1, len); + SendData (payload, len + 3); + } void SSU2Session::CleanUp (uint64_t ts) { diff --git a/libi2pd/SSU2Session.h b/libi2pd/SSU2Session.h index 0ca4933a..3971358c 100644 --- a/libi2pd/SSU2Session.h +++ b/libi2pd/SSU2Session.h @@ -150,7 +150,8 @@ namespace transport eSSU2TerminationReasonBadToken = 18, eSSU2TerminationReasonConnectionLimits = 19, eSSU2TerminationReasonIncompatibleVersion = 20, - eSSU2TerminationReasonWrongNetID = 21 + eSSU2TerminationReasonWrongNetID = 21, + eSSU2TerminationReasonReplacedByNewSession = 22 }; struct SSU2IncompleteMessage @@ -272,6 +273,7 @@ namespace transport void SendTermination (); void SendHolePunch (uint32_t nonce, const boost::asio::ip::udp::endpoint& ep, const uint8_t * introKey, uint64_t token); void SendPeerTest (uint8_t msg, const uint8_t * signedData, size_t signedDataLen, const uint8_t * introKey); // PeerTest message + void SendPathResponse (const uint8_t * data, size_t len); void HandlePayload (const uint8_t * buf, size_t len); void HandleAck (const uint8_t * buf, size_t len); From ed5c5339825f750ef863cfb2b8cb07f9fc1d88f6 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 2 Aug 2022 20:02:55 -0400 Subject: [PATCH 097/219] recgnize symmetric NAT from SSU2 --- daemon/HTTPServer.cpp | 8 +++--- libi2pd/RouterContext.cpp | 3 ++- libi2pd/RouterContext.h | 4 ++- libi2pd/SSU2.cpp | 8 ++++++ libi2pd/SSU2.h | 1 + libi2pd/SSU2Session.cpp | 54 +++++++++++++++++++++++++++++++-------- libi2pd/SSU2Session.h | 1 + 7 files changed, 63 insertions(+), 16 deletions(-) diff --git a/daemon/HTTPServer.cpp b/daemon/HTTPServer.cpp index 2a083dea..d236ca3d 100644 --- a/daemon/HTTPServer.cpp +++ b/daemon/HTTPServer.cpp @@ -222,7 +222,7 @@ namespace http { s << "" << tr("ERROR") << ": " << string << "
\r\n"; } - static void ShowNetworkStatus (std::stringstream& s, RouterStatus status) + static void ShowNetworkStatus (std::stringstream& s, RouterStatus status, RouterError error) { switch (status) { @@ -235,7 +235,7 @@ namespace http { case eRouterStatusError: { s << tr("Error"); - switch (i2p::context.GetError ()) + switch (error) { case eRouterErrorClockSkew: s << " - " << tr("Clock skew"); @@ -260,12 +260,12 @@ namespace http { ShowUptime(s, i2p::context.GetUptime ()); s << "
\r\n"; s << "" << tr("Network status") << ": "; - ShowNetworkStatus (s, i2p::context.GetStatus ()); + ShowNetworkStatus (s, i2p::context.GetStatus (), i2p::context.GetError ()); s << "
\r\n"; if (i2p::context.SupportsV6 ()) { s << "" << tr("Network status v6") << ": "; - ShowNetworkStatus (s, i2p::context.GetStatusV6 ()); + ShowNetworkStatus (s, i2p::context.GetStatusV6 (), i2p::context.GetErrorV6 ()); s << "
\r\n"; } #if ((!defined(WIN32) && !defined(QT_GUI_LIB) && !defined(ANDROID)) || defined(ANDROID_BINARY)) diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index 636d47ce..2095a465 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -29,7 +29,7 @@ namespace i2p RouterContext::RouterContext (): m_LastUpdateTime (0), m_AcceptsTunnels (true), m_IsFloodfill (false), m_ShareRatio (100), m_Status (eRouterStatusUnknown), m_StatusV6 (eRouterStatusUnknown), - m_Error (eRouterErrorNone), m_NetID (I2PD_NET_ID) + m_Error (eRouterErrorNone), m_ErrorV6 (eRouterErrorNone), m_NetID (I2PD_NET_ID) { } @@ -263,6 +263,7 @@ namespace i2p if (status != m_StatusV6) { m_StatusV6 = status; + m_ErrorV6 = eRouterErrorNone; switch (m_StatusV6) { case eRouterStatusOK: diff --git a/libi2pd/RouterContext.h b/libi2pd/RouterContext.h index 4946b7ca..9e02b5d5 100644 --- a/libi2pd/RouterContext.h +++ b/libi2pd/RouterContext.h @@ -109,6 +109,8 @@ namespace garlic RouterStatus GetStatusV6 () const { return m_StatusV6; }; void SetStatusV6 (RouterStatus status); void SetStatusV6SSU2 (RouterStatus status); + RouterError GetErrorV6 () const { return m_ErrorV6; }; + void SetErrorV6 (RouterError error) { m_StatusV6 = eRouterStatusError; m_ErrorV6 = error; }; int GetNetID () const { return m_NetID; }; void SetNetID (int netID) { m_NetID = netID; }; bool DecryptTunnelBuildRecord (const uint8_t * encrypted, uint8_t * data); @@ -197,7 +199,7 @@ namespace garlic uint64_t m_BandwidthLimit; // allowed bandwidth int m_ShareRatio; RouterStatus m_Status, m_StatusV6; - RouterError m_Error; + RouterError m_Error, m_ErrorV6; int m_NetID; std::mutex m_GarlicMutex; std::unique_ptr m_NTCP2Keys; diff --git a/libi2pd/SSU2.cpp b/libi2pd/SSU2.cpp index 551dd148..e551010a 100644 --- a/libi2pd/SSU2.cpp +++ b/libi2pd/SSU2.cpp @@ -155,6 +155,14 @@ namespace transport } return false; } + + uint16_t SSU2Server::GetPort (bool v4) const + { + boost::system::error_code ec; + boost::asio::ip::udp::endpoint ep = v4 ? m_SocketV4.local_endpoint (ec) : m_SocketV6.local_endpoint (ec); + if (ec) return 0; + return ep.port (); + } boost::asio::ip::udp::socket& SSU2Server::OpenSocket (const boost::asio::ip::udp::endpoint& localEndpoint) { diff --git a/libi2pd/SSU2.h b/libi2pd/SSU2.h index 010c2c00..00e944e4 100644 --- a/libi2pd/SSU2.h +++ b/libi2pd/SSU2.h @@ -55,6 +55,7 @@ namespace transport boost::asio::io_service& GetService () { return GetIOService (); }; void SetLocalAddress (const boost::asio::ip::address& localAddress); bool IsSupported (const boost::asio::ip::address& addr) const; + uint16_t GetPort (bool v4) const; void AddSession (std::shared_ptr session); void RemoveSession (uint64_t connID); diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index 475d7cef..e463e6fc 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -1370,16 +1370,9 @@ namespace transport HandleAck (buf + offset, size); break; case eSSU2BlkAddress: - { - boost::asio::ip::udp::endpoint ep; - if (ExtractEndpoint (buf + offset, size, ep)) - { - LogPrint (eLogInfo, "SSU2: Our external address is ", ep); - if (!i2p::util::net::IsInReservedRange (ep.address ())) - i2p::context.UpdateAddress (ep.address ()); - } - break; - } + LogPrint (eLogDebug, "SSU2: Address"); + HandleAddress (buf + offset, size); + break; case eSSU2BlkIntroKey: break; case eSSU2BlkRelayTagRequest: @@ -1482,6 +1475,47 @@ namespace transport } } + void SSU2Session::HandleAddress (const uint8_t * buf, size_t len) + { + boost::asio::ip::udp::endpoint ep; + if (ExtractEndpoint (buf, len, ep)) + { + LogPrint (eLogInfo, "SSU2: Our external address is ", ep); + if (!i2p::util::net::IsInReservedRange (ep.address ())) + { + i2p::context.UpdateAddress (ep.address ()); + // check our port + bool isV4 = ep.address ().is_v4 (); + if (ep.port () != m_Server.GetPort (isV4)) + { + if (isV4) + { + if (i2p::context.GetStatus () == eRouterStatusTesting) + i2p::context.SetError (eRouterErrorSymmetricNAT); + } + else + { + if (i2p::context.GetStatusV6 () == eRouterStatusTesting) + i2p::context.SetErrorV6 (eRouterErrorSymmetricNAT); + } + } + else + { + if (isV4) + { + if (i2p::context.GetStatus () == eRouterStatusError && i2p::context.GetError () == eRouterErrorSymmetricNAT) + i2p::context.SetStatus (eRouterStatusTesting); + } + else + { + if (i2p::context.GetStatusV6 () == eRouterStatusError && i2p::context.GetErrorV6 () == eRouterErrorSymmetricNAT) + i2p::context.SetStatusV6 (eRouterStatusTesting); + } + } + } + } + } + void SSU2Session::HandleFirstFragment (const uint8_t * buf, size_t len) { uint32_t msgID; memcpy (&msgID, buf + 1, 4); diff --git a/libi2pd/SSU2Session.h b/libi2pd/SSU2Session.h index 3971358c..eae593c2 100644 --- a/libi2pd/SSU2Session.h +++ b/libi2pd/SSU2Session.h @@ -278,6 +278,7 @@ namespace transport void HandlePayload (const uint8_t * buf, size_t len); void HandleAck (const uint8_t * buf, size_t len); void HandleAckRange (uint32_t firstPacketNum, uint32_t lastPacketNum, uint64_t ts); + void HandleAddress (const uint8_t * buf, size_t len); bool ExtractEndpoint (const uint8_t * buf, size_t size, boost::asio::ip::udp::endpoint& ep); size_t CreateEndpoint (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& ep); std::shared_ptr FindLocalAddress () const; From fbb590d9a975dd0092fb36f00099cfb29546bc39 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Wed, 3 Aug 2022 11:48:10 +0300 Subject: [PATCH 098/219] [i18n] add simplified chinese translation (thanks to sklhioq) Signed-off-by: R4SAS --- contrib/i18n/README.md | 2 +- contrib/i2pd.conf | 4 +- i18n/Chinese.cpp | 217 +++++++++++++++++++++++++++++++++++++++++ i18n/I18N_langs.h | 2 + 4 files changed, 222 insertions(+), 3 deletions(-) create mode 100644 i18n/Chinese.cpp diff --git a/contrib/i18n/README.md b/contrib/i18n/README.md index 04779473..4efc26d0 100644 --- a/contrib/i18n/README.md +++ b/contrib/i18n/README.md @@ -9,7 +9,7 @@ Regex for transforming gettext translations to our format: --- ``` -in: msgid\ \"(.*)\"\nmsgid_plural\ \"(.*)\"\nmsgstr\[0\]\ \"(.*)\"\nmsgstr\[1\]\ \"(.*)\"\n(msgstr\[2\]\ \"(.*)\"\n)?(msgstr\[3\]\ \"(.*)\"\n)?(msgstr\[4\]\ \"(.*)\"\n)?(msgstr\[5\]\ \"(.*)\"\n)? +in: msgid\ \"(.*)\"\nmsgid_plural\ \"(.*)\"\nmsgstr\[0\]\ \"(.*)\"\n(msgstr\[1\]\ \"(.*)\"\n)?(msgstr\[2\]\ \"(.*)\"\n)?(msgstr\[3\]\ \"(.*)\"\n)?(msgstr\[4\]\ \"(.*)\"\n)?(msgstr\[5\]\ \"(.*)\"\n)? out: #{"$2", {"$3", "$4", "$6", "$8", "$10"}},\n ``` diff --git a/contrib/i2pd.conf b/contrib/i2pd.conf index 43cf7ddd..0fdc3809 100644 --- a/contrib/i2pd.conf +++ b/contrib/i2pd.conf @@ -110,8 +110,8 @@ port = 7070 # user = i2pd # pass = changeme ## Select webconsole language -## Currently supported english (default), afrikaans, armenian, french, german, -## russian, turkmen, ukrainian and uzbek languages +## Currently supported english (default), afrikaans, armenian, chinese, french, +## german, russian, turkmen, ukrainian and uzbek languages # lang = english [httpproxy] diff --git a/i18n/Chinese.cpp b/i18n/Chinese.cpp new file mode 100644 index 00000000..90d2a901 --- /dev/null +++ b/i18n/Chinese.cpp @@ -0,0 +1,217 @@ +/* +* Copyright (c) 2022, The PurpleI2P Project +* +* This file is part of Purple i2pd project and licensed under BSD3 +* +* See full license text in LICENSE file at top of project tree +*/ + +#include +#include +#include +#include +#include "I18N.h" + +// English localization file +// This is an example translation file without strings in it. + +namespace i2p +{ +namespace i18n +{ +namespace chinese // language namespace +{ + // language name in lowercase + static std::string language = "chinese"; + + // See for language plural forms here: + // https://localization-guide.readthedocs.io/en/latest/l10n/pluralforms.html + static int plural (int n) { + return 0; + } + + static std::map strings + { + {"KiB", "KiB"}, + {"MiB", "MiB"}, + {"GiB", "GiB"}, + {"building", "正在构建"}, + {"failed", "连接失败"}, + {"expiring", "即将过期"}, + {"established", "连接建立"}, + {"unknown", "未知"}, + {"exploratory", "探索隧道"}, + {"Purple I2P Webconsole", "Purple I2P 网页控制台"}, + {"i2pd webconsole", "i2pd 网页控制台"}, + {"Main page", "主页"}, + {"Router commands", "路由命令"}, + {"Local Destinations", "本地目标"}, + {"LeaseSets", "租约集"}, + {"Tunnels", "隧道"}, + {"Transit Tunnels", "中转隧道"}, + {"Transports", "传输"}, + {"I2P tunnels", "I2P 隧道"}, + {"SAM sessions", "SAM 会话"}, + {"ERROR", "错误"}, + {"OK", "良好"}, + {"Testing", "测试中"}, + {"Firewalled", "被防火墙阻挡"}, + {"Unknown", "未知"}, + {"Proxy", "代理"}, + {"Mesh", "网格组网"}, + {"Error", "错误"}, + {"Clock skew", "时钟偏移"}, + {"Offline", "离线"}, + {"Symmetric NAT", "对称 NAT"}, + {"Uptime", "在线时间"}, + {"Network status", "IPv4 网络状态"}, + {"Network status v6", "IPv6 网络状态"}, + {"Stopping in", "距停止还有:"}, + {"Family", "家族"}, + {"Tunnel creation success rate", "隧道创建成功率"}, + {"Received", "已接收"}, + {"KiB/s", "KiB/s"}, + {"Sent", "已发送"}, + {"Transit", "中转"}, + {"Data path", "数据文件路径"}, + {"Hidden content. Press on text to see.", "隐藏内容 请点击文本查看。"}, + {"Router Ident", "路由器标识"}, + {"Router Family", "路由器家族"}, + {"Router Caps", "路由器分类"}, + {"Version", "版本"}, + {"Our external address", "外部地址"}, + {"supported", "支持"}, + {"Routers", "路由节点"}, + {"Floodfills", "洪泛节点"}, + {"Client Tunnels", "客户端隧道"}, + {"Services", "服务"}, + {"Enabled", "启用"}, + {"Disabled", "禁用"}, + {"Encrypted B33 address", "加密的 B33 地址"}, + {"Address registration line", "地址域名注册"}, + {"Domain", "域名"}, + {"Generate", "生成"}, + {"Note: result string can be used only for registering 2LD domains (example.i2p). For registering subdomains please use i2pd-tools.", "注意: 结果字符串可以用于注册次级域名(例如:example.i2p)。若想注册次级域名,请使用 i2pd-tools。"}, + {"Address", "地址"}, + {"Type", "类型"}, + {"EncType", "加密类型"}, + {"Inbound tunnels", "入站隧道"}, + {"ms", "毫秒"}, + {"Outbound tunnels", "出站隧道"}, + {"Tags", "标签"}, + {"Incoming", "传入"}, + {"Outgoing", "传出"}, + {"Destination", "目标"}, + {"Amount", "数量"}, + {"Incoming Tags", "传入标签"}, + {"Tags sessions", "标签会话"}, + {"Status", "状态"}, + {"Local Destination", "本地目标"}, + {"Streams", "流"}, + {"Close stream", "断开流"}, + {"I2CP session not found", "未找到 I2CP 会话"}, + {"I2CP is not enabled", "I2CP 未启用"}, + {"Invalid", "无效"}, + {"Store type", "存储类型"}, + {"Expires", "过期时间"}, + {"Non Expired Leases", "未到期的租约"}, + {"Gateway", "网关"}, + {"TunnelID", "隧道 ID"}, + {"EndDate", "结束日期"}, + {"not floodfill", "非洪泛"}, + {"Queue size", "队列大小"}, + {"Run peer test", "运行群体测试"}, + {"Decline transit tunnels", "拒绝中转隧道"}, + {"Accept transit tunnels", "允许中转隧道"}, + {"Cancel graceful shutdown", "取消计划的停止"}, + {"Start graceful shutdown", "待他人断线后停止"}, + {"Force shutdown", "强制停止"}, + {"Reload external CSS styles", "重载外部 CSS 样式"}, + {"Note: any action done here are not persistent and not changes your config files.", "注意: 此处完成的任何操作都不是永久的,不会更改您的配置文件。"}, + {"Logging level", "日志级别"}, + {"Transit tunnels limit", "中转隧道限制"}, + {"Change", "更换"}, + {"Change language", "更换语言"}, + {"no transit tunnels currently built", "目前未构建中转隧道"}, + {"SAM disabled", "SAM 已禁用"}, + {"no sessions currently running", "没有正在运行的会话"}, + {"SAM session not found", "未找到 SAM 会话"}, + {"SAM Session", "SAM 会话"}, + {"Server Tunnels", "服务器隧道"}, + {"Client Forwards", "客户端转发"}, + {"Server Forwards", "服务器转发"}, + {"Unknown page", "未知页面"}, + {"Invalid token", "无效凭证"}, + {"SUCCESS", "成功"}, + {"Stream closed", "流已关闭"}, + {"Stream not found or already was closed", "流未找到或已关闭"}, + {"Destination not found", "找不到目标"}, + {"StreamID can't be null", "StreamID 不能为空"}, + {"Return to destination page", "返回目标页面"}, + {"You will be redirected in 5 seconds", "您将在5秒内被重定向"}, + {"Transit tunnels count must not exceed 65535", "中转隧道数量不能超过 65535"}, + {"Back to commands list", "返回命令列表"}, + {"Register at reg.i2p", "在 reg.i2p 注册域名"}, + {"Description", "描述"}, + {"A bit information about service on domain", "在此域名上运行的服务的一些信息"}, + {"Submit", "提交"}, + {"Domain can't end with .b32.i2p", "域名不能以 .b32.i2p 结尾"}, + {"Domain must end with .i2p", "域名必须以 .i2p 结尾"}, + {"Such destination is not found", "找不到此目标"}, + {"Unknown command", "未知指令"}, + {"Command accepted", "已接受指令"}, + {"Proxy error", "代理错误"}, + {"Proxy info", "代理信息"}, + {"Proxy error: Host not found", "代理错误:找不到主机"}, + {"Remote host not found in router's addressbook", "在路由的地址簿中找不到远程主机"}, + {"You may try to find this host on jump services below", "您可以尝试在下方的跳转服务上找到这个主机"}, + {"Invalid request", "无效请求"}, + {"Proxy unable to parse your request", "代理无法解析您的请求"}, + {"addresshelper is not supported", "不支持地址助手"}, + {"Host", "主机"}, + {"added to router's addressbook from helper", "将此地址从地址助手添加到地址簿"}, + {"Click here to proceed:", "点击此处继续:"}, + {"Continue", "继续"}, + {"Addresshelper found", "找到地址助手"}, + {"already in router's addressbook", "已在路由器的地址簿中"}, + {"Click here to update record:", "点击此处更新地址簿记录"}, + {"invalid request uri", "无效的 URL 请求"}, + {"Can't detect destination host from request", "无法从请求中检测到目标主机"}, + {"Outproxy failure", "出口代理失效"}, + {"bad outproxy settings", "错误的出口代理设置"}, + {"not inside I2P network, but outproxy is not enabled", "该地址不在 I2P 网络内,但未启用出口代理"}, + {"unknown outproxy url", "未知的出口代理地址"}, + {"cannot resolve upstream proxy", "无法解析上游代理"}, + {"hostname too long", "主机名过长"}, + {"cannot connect to upstream socks proxy", "无法连接到上游 socks 代理"}, + {"Cannot negotiate with socks proxy", "无法与 socks 代理协商"}, + {"CONNECT error", "连接错误"}, + {"Failed to Connect", "连接失败"}, + {"socks proxy error", "socks 代理错误"}, + {"failed to send request to upstream", "向上游发送请求失败"}, + {"No Reply From socks proxy", "没有来自 socks 代理的回复"}, + {"cannot connect", "无法连接"}, + {"http out proxy not implemented", "http 出口代理未实现"}, + {"cannot connect to upstream http proxy", "无法连接到上游 http 代理"}, + {"Host is down", "主机已关闭"}, + {"Can't create connection to requested host, it may be down. Please try again later.", "无法创建到目标主机的连接。主机可能已下线,请稍后再试。"}, + {"", ""}, + }; + + static std::map> plurals + { + {"days", {"日"}}, + {"hours", {"时"}}, + {"minutes", {"分"}}, + {"seconds", {"秒"}}, + {"", {""}}, + }; + + std::shared_ptr GetLocale() + { + return std::make_shared(language, strings, plurals, [] (int n)->int { return plural(n); }); + } + +} // language +} // i18n +} // i2p diff --git a/i18n/I18N_langs.h b/i18n/I18N_langs.h index f3fc6691..87bc503e 100644 --- a/i18n/I18N_langs.h +++ b/i18n/I18N_langs.h @@ -73,6 +73,7 @@ namespace i18n // Add localization here with language name as namespace namespace afrikaans { std::shared_ptr GetLocale (); } namespace armenian { std::shared_ptr GetLocale (); } + namespace chinese { std::shared_ptr GetLocale (); } namespace english { std::shared_ptr GetLocale (); } namespace french { std::shared_ptr GetLocale (); } namespace german { std::shared_ptr GetLocale (); } @@ -88,6 +89,7 @@ namespace i18n { { "afrikaans", {"Afrikaans", "af", i2p::i18n::afrikaans::GetLocale} }, { "armenian", {"հայերէն", "hy", i2p::i18n::armenian::GetLocale} }, + { "chinese", {"简体字", "zh-CN", i2p::i18n::chinese::GetLocale} }, { "english", {"English", "en", i2p::i18n::english::GetLocale} }, { "french", {"Français", "fr", i2p::i18n::french::GetLocale} }, { "german", {"Deutsch", "de", i2p::i18n::german::GetLocale} }, From 34b75dac02380a732ad82830484e05f15d831068 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Wed, 3 Aug 2022 11:50:32 +0300 Subject: [PATCH 099/219] change language file comment Signed-off-by: R4SAS --- i18n/Chinese.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/i18n/Chinese.cpp b/i18n/Chinese.cpp index 90d2a901..e7989594 100644 --- a/i18n/Chinese.cpp +++ b/i18n/Chinese.cpp @@ -12,7 +12,7 @@ #include #include "I18N.h" -// English localization file +// Simplified Chinese localization file // This is an example translation file without strings in it. namespace i2p From cb959ab14cec786349a968a3e32a0c52e7f77944 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 3 Aug 2022 10:26:55 -0400 Subject: [PATCH 100/219] allocate tunnel message buffer for I2NP block with tunnel data message type --- libi2pd/SSU2Session.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index e463e6fc..962f3805 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -1320,7 +1320,7 @@ namespace transport case eSSU2BlkI2NPMessage: { LogPrint (eLogDebug, "SSU2: I2NP message"); - auto nextMsg = NewI2NPShortMessage (); + auto nextMsg = (buf[offset] == eI2NPTunnelData) ? NewI2NPTunnelMessage (true) : NewI2NPShortMessage (); nextMsg->len = nextMsg->offset + size + 7; // 7 more bytes for full I2NP header memcpy (nextMsg->GetNTCP2Header (), buf + offset, size); nextMsg->FromNTCP2 (); // SSU2 has the same format as NTCP2 From 771c4a0d022b391db588cdc3356a68e0880185fe Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 3 Aug 2022 16:06:07 -0400 Subject: [PATCH 101/219] allocate smaller I2NP buffer for fragmented message. Limit number of fragments by 64 --- libi2pd/SSU2Session.cpp | 31 +++++++++++++++++++++++++------ libi2pd/SSU2Session.h | 3 +++ 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index 962f3805..a2f17b13 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -18,6 +18,21 @@ namespace i2p { namespace transport { + void SSU2IncompleteMessage::AttachNextFragment (const uint8_t * fragment, size_t fragmentSize) + { + if (msg->len + fragmentSize > msg->maxLen) + { + LogPrint (eLogInfo, "SSU2: I2NP message size ", msg->maxLen, " is not enough"); + auto newMsg = NewI2NPMessage (); + *newMsg = *msg; + msg = newMsg; + } + if (msg->Concat (fragment, fragmentSize) < fragmentSize) + LogPrint (eLogError, "SSU2: I2NP buffer overflow ", msg->maxLen); + nextFragmentNum++; + } + + SSU2Session::SSU2Session (SSU2Server& server, std::shared_ptr in_RemoteRouter, std::shared_ptr addr): TransportSession (in_RemoteRouter, SSU2_CONNECT_TIMEOUT), @@ -1519,7 +1534,7 @@ namespace transport void SSU2Session::HandleFirstFragment (const uint8_t * buf, size_t len) { uint32_t msgID; memcpy (&msgID, buf + 1, 4); - auto msg = NewI2NPMessage (); + auto msg = NewI2NPShortMessage (); // same format as I2NP message block msg->len = msg->offset + len + 7; memcpy (msg->GetNTCP2Header (), buf, len); @@ -1557,10 +1572,11 @@ namespace transport auto it = m_IncompleteMessages.find (msgID); if (it != m_IncompleteMessages.end ()) { - if (it->second->nextFragmentNum == fragmentNum && it->second->msg) + if (it->second->nextFragmentNum == fragmentNum && fragmentNum < SSU2_MAX_NUM_FRAGMENTS && + it->second->msg) { // in sequence - it->second->msg->Concat (buf + 5, len - 5); + it->second->AttachNextFragment (buf + 5, len - 5); if (isLast) { it->second->msg->FromNTCP2 (); @@ -1569,7 +1585,6 @@ namespace transport } else { - it->second->nextFragmentNum++; if (ConcatOutOfSequenceFragments (it->second)) { m_Handler.PutNextMessage (std::move (it->second->msg)); @@ -1589,6 +1604,11 @@ namespace transport it = m_IncompleteMessages.emplace (msgID, msg).first; } // insert out of sequence fragment + if (fragmentNum >= SSU2_MAX_NUM_FRAGMENTS) + { + LogPrint (eLogWarning, "SSU2: Fragment number ", fragmentNum, " exceeds ", SSU2_MAX_NUM_FRAGMENTS); + return; + } auto fragment = std::make_shared (); memcpy (fragment->buf, buf + 5, len -5); fragment->len = len - 5; @@ -1604,10 +1624,9 @@ namespace transport for (auto it = m->outOfSequenceFragments.begin (); it != m->outOfSequenceFragments.end ();) if (it->first == m->nextFragmentNum) { - m->msg->Concat (it->second->buf, it->second->len); + m->AttachNextFragment (it->second->buf, it->second->len); isLast = it->second->isLast; it = m->outOfSequenceFragments.erase (it); - m->nextFragmentNum++; } else break; diff --git a/libi2pd/SSU2Session.h b/libi2pd/SSU2Session.h index eae593c2..299c79f1 100644 --- a/libi2pd/SSU2Session.h +++ b/libi2pd/SSU2Session.h @@ -45,6 +45,7 @@ namespace transport const float SSU2_kAPPA = 1.8; const size_t SSU2_MAX_OUTGOING_QUEUE_SIZE = 500; // in messages const int SSU2_MAX_NUM_ACK_RANGES = 32; // to send + const uint8_t SSU2_MAX_NUM_FRAGMENTS = 64; enum SSU2MessageType { @@ -167,6 +168,8 @@ namespace transport int nextFragmentNum; uint32_t lastFragmentInsertTime; // in seconds std::map > outOfSequenceFragments; + + void AttachNextFragment (const uint8_t * fragment, size_t fragmentSize); }; // RouterInfo flags From df073bb3065dd79bc37d6a6bd80d063299d5dd44 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 4 Aug 2022 15:15:19 -0400 Subject: [PATCH 102/219] send local address in RelayResponse block --- libi2pd/SSU2Session.cpp | 49 +++++++++++++++++++++++++++++++++-------- libi2pd/SSU2Session.h | 2 +- 2 files changed, 41 insertions(+), 10 deletions(-) diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index a2f17b13..a0789281 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -1106,7 +1106,7 @@ namespace transport size_t payloadSize = 7; payloadSize += CreateAddressBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize, ep); payloadSize += CreateRelayResponseBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize, - eSSU2RelayResponseCodeAccept, nonce, true, token); + eSSU2RelayResponseCodeAccept, nonce, token, ep.address ().is_v4 ()); payloadSize += CreatePaddingBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize); // encrypt uint8_t n[12]; @@ -1644,7 +1644,7 @@ namespace transport // send relay response back to Alice uint8_t payload[SSU2_MAX_PACKET_SIZE]; size_t payloadSize = CreateRelayResponseBlock (payload, m_MaxPayloadSize, - eSSU2RelayResponseCodeBobRelayTagNotFound, bufbe32toh (buf + 1), false, 0); + eSSU2RelayResponseCodeBobRelayTagNotFound, bufbe32toh (buf + 1), 0, false); payloadSize += CreatePaddingBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize); SendData (payload, payloadSize); return; @@ -1673,6 +1673,7 @@ namespace transport // we are Charlie SSU2RelayResponseCode code = eSSU2RelayResponseCodeAccept; uint64_t token = 0; + bool isV4 = false; auto r = i2p::data::netdb.FindRouter (buf + 1); // Alice if (r) { @@ -1695,6 +1696,7 @@ namespace transport if (m_Server.IsSupported (ep.address ())) { token = m_Server.GetIncomingToken (ep); + isV4 = ep.address ().is_v4 (); SendHolePunch (bufbe32toh (buf + 33), ep, addr->i, token); } else @@ -1709,6 +1711,11 @@ namespace transport code = eSSU2RelayResponseCodeCharlieAliceIsUnknown; } } + else + { + LogPrint (eLogWarning, "SSU2: RelayIntro can't extract endpoint"); + code = eSSU2RelayResponseCodeCharlieAliceIsUnknown; + } } else { @@ -1724,7 +1731,7 @@ namespace transport // send relay response to Bob uint8_t payload[SSU2_MAX_PACKET_SIZE]; size_t payloadSize = CreateRelayResponseBlock (payload, m_MaxPayloadSize, - code, bufbe32toh (buf + 33), true, token); + code, bufbe32toh (buf + 33), token, isV4); payloadSize += CreatePaddingBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize); SendData (payload, payloadSize); } @@ -2345,7 +2352,7 @@ namespace transport } size_t SSU2Session::CreateRelayResponseBlock (uint8_t * buf, size_t len, - SSU2RelayResponseCode code, uint32_t nonce, bool endpoint, uint64_t token) + SSU2RelayResponseCode code, uint32_t nonce, uint64_t token, bool v4) { buf[0] = eSSU2BlkRelayResponse; buf[3] = 0; // flag @@ -2354,21 +2361,45 @@ namespace transport htobe32buf (buf + 9, i2p::util::GetSecondsSinceEpoch ()); // timestamp buf[13] = 2; // ver size_t csz = 0; - if (endpoint) + if (code == eSSU2RelayResponseCodeAccept) { - csz = CreateEndpoint (buf + 15, len - 15, boost::asio::ip::udp::endpoint (m_Address->host, m_Address->port)); - if (!csz) return 0; + auto addr = i2p::context.GetRouterInfo ().GetSSU2Address (v4); + if (!addr) + { + LogPrint (eLogError, "SSU2: Can't find local address for RelayResponse"); + return 0; + } + csz = CreateEndpoint (buf + 15, len - 15, boost::asio::ip::udp::endpoint (addr->host, addr->port)); + if (!csz) + { + LogPrint (eLogError, "SSU2: Can't create local endpoint for RelayResponse"); + return 0; + } } buf[14] = csz; // csz // signature + size_t signatureLen = i2p::context.GetIdentity ()->GetSignatureLen (); + if (15 + csz + signatureLen > len) + { + LogPrint (eLogError, "SSU2: Buffer for RelayResponse signature is too small ", len); + return 0; + } SignedData s; s.Insert ((const uint8_t *)"RelayAgreementOK", 16); // prologue - s.Insert (endpoint ? GetRemoteIdentity ()->GetIdentHash () : i2p::context.GetIdentity ()->GetIdentHash (), 32); // bhash + if (code == eSSU2RelayResponseCodeAccept || code >= 64) // Charlie + s.Insert (GetRemoteIdentity ()->GetIdentHash (), 32); // bhash + else // Bob's reject + s.Insert (i2p::context.GetIdentity ()->GetIdentHash (), 32); // bhash s.Insert (buf + 5, 10 + csz); // nonce, timestamp, ver, csz and Charlie's endpoint s.Sign (i2p::context.GetPrivateKeys (), buf + 15 + csz); - size_t payloadSize = 12 + csz + i2p::context.GetIdentity ()->GetSignatureLen (); + size_t payloadSize = 12 + csz + signatureLen; if (!code) { + if (payloadSize + 11 > len) + { + LogPrint (eLogError, "SSU2: Buffer for RelayResponse token is too small ", len); + return 0; + } memcpy (buf + 3 + payloadSize, &token, 8); payloadSize += 8; } diff --git a/libi2pd/SSU2Session.h b/libi2pd/SSU2Session.h index 299c79f1..1a00f38a 100644 --- a/libi2pd/SSU2Session.h +++ b/libi2pd/SSU2Session.h @@ -307,7 +307,7 @@ namespace transport size_t CreateFirstFragmentBlock (uint8_t * buf, size_t len, std::shared_ptr msg); size_t CreateFollowOnFragmentBlock (uint8_t * buf, size_t len, std::shared_ptr msg, uint8_t& fragmentNum, uint32_t msgID); size_t CreateRelayIntroBlock (uint8_t * buf, size_t len, const uint8_t * introData, size_t introDataLen); - size_t CreateRelayResponseBlock (uint8_t * buf, size_t len, SSU2RelayResponseCode code, uint32_t nonce, bool endpoint, uint64_t token); // add endpoint for Chralie and no endpoint for Bob + size_t CreateRelayResponseBlock (uint8_t * buf, size_t len, SSU2RelayResponseCode code, uint32_t nonce, uint64_t token, bool v4); size_t CreatePeerTestBlock (uint8_t * buf, size_t len, uint8_t msg, SSU2PeerTestCode code, const uint8_t * routerHash, const uint8_t * signedData, size_t signedDataLen); size_t CreatePeerTestBlock (uint8_t * buf, size_t len, uint32_t nonce); // Alice size_t CreateTerminationBlock (uint8_t * buf, size_t len); From 3e408529992b5d1db9c281e649d76ff2be14651c Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 4 Aug 2022 18:13:44 -0400 Subject: [PATCH 103/219] memory pool for sent packets --- libi2pd/SSU2.cpp | 1 + libi2pd/SSU2.h | 3 +++ libi2pd/SSU2Session.cpp | 12 ++++++------ libi2pd/SSU2Session.h | 18 +++++++++--------- 4 files changed, 19 insertions(+), 15 deletions(-) diff --git a/libi2pd/SSU2.cpp b/libi2pd/SSU2.cpp index e551010a..680cde63 100644 --- a/libi2pd/SSU2.cpp +++ b/libi2pd/SSU2.cpp @@ -742,6 +742,7 @@ namespace transport } m_PacketsPool.CleanUpMt (); + m_SentPacketsPool.CleanUp (); ScheduleTermination (); } } diff --git a/libi2pd/SSU2.h b/libi2pd/SSU2.h index 00e944e4..8bada7a6 100644 --- a/libi2pd/SSU2.h +++ b/libi2pd/SSU2.h @@ -87,6 +87,8 @@ namespace transport void RescheduleIntroducersUpdateTimer (); void RescheduleIntroducersUpdateTimerV6 (); + + i2p::util::MemoryPool& GetSentPacketsPool () { return m_SentPacketsPool; }; private: @@ -124,6 +126,7 @@ namespace transport std::map > m_Relays; // we are introducer, relay tag -> session std::list m_Introducers, m_IntroducersV6; // introducers we are connected to i2p::util::MemoryPoolMt m_PacketsPool; + i2p::util::MemoryPool m_SentPacketsPool; boost::asio::deadline_timer m_TerminationTimer, m_ResendTimer, m_IntroducersUpdateTimer, m_IntroducersUpdateTimerV6; std::shared_ptr m_LastSession; diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index a0789281..fd109609 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -282,7 +282,7 @@ namespace transport if (!m_SendQueue.empty () && m_SentPackets.size () <= m_WindowSize) { auto ts = i2p::util::GetMillisecondsSinceEpoch (); - auto packet = std::make_shared(); + auto packet = m_Server.GetSentPacketsPool ().AcquireShared (); size_t ackBlockSize = CreateAckBlock (packet->payload, m_MaxPayloadSize); bool ackBlockSent = false; packet->payloadSize += ackBlockSize; @@ -304,7 +304,7 @@ namespace transport else { // create new packet and copy ack block - auto newPacket = std::make_shared(); + auto newPacket = m_Server.GetSentPacketsPool ().AcquireShared (); memcpy (newPacket->payload, packet->payload, ackBlockSize); newPacket->payloadSize = ackBlockSize; // complete current packet @@ -361,7 +361,7 @@ namespace transport uint32_t msgID; memcpy (&msgID, msg->GetHeader () + I2NP_HEADER_MSGID_OFFSET, 4); auto ts = i2p::util::GetMillisecondsSinceEpoch (); - auto packet = std::make_shared(); + auto packet = m_Server.GetSentPacketsPool ().AcquireShared (); if (extraSize >= 8) { packet->payloadSize = CreateAckBlock (packet->payload, extraSize); @@ -371,7 +371,7 @@ namespace transport uint32_t packetNum = SendData (packet->payload, packet->payloadSize); packet->sendTime = ts; m_SentPackets.emplace (packetNum, packet); - packet = std::make_shared(); + packet = m_Server.GetSentPacketsPool ().AcquireShared (); } else extraSize -= packet->payloadSize; @@ -389,7 +389,7 @@ namespace transport while (msg->offset < msg->len) { offset = extraSize > 0 ? (rand () % extraSize) : 0; - packet = std::make_shared(); + packet = m_Server.GetSentPacketsPool ().AcquireShared (); packet->payloadSize = CreateFollowOnFragmentBlock (packet->payload, m_MaxPayloadSize - offset, msg, fragmentNum, msgID); extraSize -= offset; if (msg->offset >= msg->len && packet->payloadSize + 16 < m_MaxPayloadSize) // last fragment @@ -413,7 +413,7 @@ namespace transport } // resend data packets if (m_SentPackets.empty ()) return; - std::map > resentPackets; + std::map > resentPackets; for (auto it = m_SentPackets.begin (); it != m_SentPackets.end (); ) if (ts >= it->second->sendTime + it->second->numResends*m_RTO) { diff --git a/libi2pd/SSU2Session.h b/libi2pd/SSU2Session.h index 1a00f38a..767c3e04 100644 --- a/libi2pd/SSU2Session.h +++ b/libi2pd/SSU2Session.h @@ -172,6 +172,14 @@ namespace transport void AttachNextFragment (const uint8_t * fragment, size_t fragmentSize); }; + struct SSU2SentPacket + { + uint8_t payload[SSU2_MAX_PACKET_SIZE]; + size_t payloadSize = 0; + uint64_t sendTime; // in milliseconds + int numResends = 0; + }; + // RouterInfo flags const uint8_t SSU2_ROUTER_INFO_FLAG_REQUEST_FLOOD = 0x01; const uint8_t SSU2_ROUTER_INFO_FLAG_GZIP = 0x02; @@ -192,14 +200,6 @@ namespace transport } h; }; - struct SentPacket - { - uint8_t payload[SSU2_MAX_PACKET_SIZE]; - size_t payloadSize = 0; - uint64_t sendTime; // in milliseconds - int numResends = 0; - }; - struct HandshakePacket { Header header; @@ -327,7 +327,7 @@ namespace transport uint8_t m_KeyDataSend[64], m_KeyDataReceive[64]; uint32_t m_SendPacketNum, m_ReceivePacketNum; std::set m_OutOfSequencePackets; // packet nums > receive packet num - std::map > m_SentPackets; // packetNum -> packet + std::map > m_SentPackets; // packetNum -> packet std::map > m_IncompleteMessages; // I2NP std::map, uint64_t > > m_RelaySessions; // nonce->(Alice, timestamp) for Bob or nonce->(Charlie, timestamp) for Alice std::map, uint64_t > > m_PeerTests; // same as for relay sessions From f43e86099826e447d763f21366e19ad39e58a1eb Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 5 Aug 2022 21:23:23 -0400 Subject: [PATCH 104/219] cleanup introducers if router is not longer firewalled --- libi2pd/RouterContext.cpp | 15 +++++++++++++++ libi2pd/RouterContext.h | 1 + libi2pd/SSU2.cpp | 2 ++ 3 files changed, 18 insertions(+) diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index 2095a465..0a7b8342 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -481,6 +481,21 @@ namespace i2p UpdateRouterInfo (); } + void RouterContext::ClearSSU2Introducers (bool v4) + { + bool updated = false; + auto& addresses = m_RouterInfo.GetAddresses (); + for (auto& addr : addresses) + if (addr->IsSSU2 () && ((v4 && addr->IsV4 ()) || (!v4 && addr->IsV6 ())) && + addr->ssu && !addr->ssu->introducers.empty ()) + { + addr->ssu->introducers.clear (); + updated = true; + } + if (updated) + UpdateRouterInfo (); + } + void RouterContext::SetFloodfill (bool floodfill) { m_IsFloodfill = floodfill; diff --git a/libi2pd/RouterContext.h b/libi2pd/RouterContext.h index 9e02b5d5..0c1acc7b 100644 --- a/libi2pd/RouterContext.h +++ b/libi2pd/RouterContext.h @@ -127,6 +127,7 @@ namespace garlic void RemoveIntroducer (const boost::asio::ip::udp::endpoint& e); bool AddSSU2Introducer (const i2p::data::RouterInfo::Introducer& introducer, bool v4); void RemoveSSU2Introducer (const i2p::data::IdentHash& h, bool v4); + void ClearSSU2Introducers (bool v4); bool IsUnreachable () const; void SetUnreachable (bool v4, bool v6); void SetUnreachableSSU2 (bool v4, bool v6); diff --git a/libi2pd/SSU2.cpp b/libi2pd/SSU2.cpp index 680cde63..ef076447 100644 --- a/libi2pd/SSU2.cpp +++ b/libi2pd/SSU2.cpp @@ -981,6 +981,7 @@ namespace transport if (i2p::context.GetStatus () != eRouterStatusFirewalled) { // we don't need introducers + i2p::context.ClearSSU2Introducers (true); m_Introducers.clear (); return; } @@ -1003,6 +1004,7 @@ namespace transport if (i2p::context.GetStatusV6 () != eRouterStatusFirewalled) { // we don't need introducers + i2p::context.ClearSSU2Introducers (false); m_IntroducersV6.clear (); return; } From a94ae7d77dce5a3d3c3440f8dfc3a2ce5a4c0d0e Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 6 Aug 2022 16:25:46 -0400 Subject: [PATCH 105/219] update keys for NTCP2 and SSU2 addreses --- libi2pd/RouterContext.cpp | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index 0a7b8342..2c24fc65 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -338,18 +338,22 @@ namespace i2p { auto& addresses = m_RouterInfo.GetAddresses (); bool found = false, updated = false; - for (auto it = addresses.begin (); it != addresses.end (); ++it) + for (auto it = addresses.begin (); it != addresses.end ();) { if ((*it)->IsNTCP2 ()) { found = true; - if (!enable) + if (enable) { - addresses.erase (it); - updated= true; - } - break; + (*it)->s = m_NTCP2Keys->staticPublicKey; + memcpy ((*it)->i, m_NTCP2Keys->iv, 16); + } + else + it = addresses.erase (it); + updated = true;; } + else + it++; } if (enable && !found) { @@ -386,18 +390,22 @@ namespace i2p { auto& addresses = m_RouterInfo.GetAddresses (); bool found = false, updated = false; - for (auto it = addresses.begin (); it != addresses.end (); ++it) + for (auto it = addresses.begin (); it != addresses.end ();) { if ((*it)->IsSSU2 ()) { found = true; - if (!enable) + if (enable) { - addresses.erase (it); - updated= true; - } - break; + (*it)->s = m_SSU2Keys->staticPublicKey; + (*it)->i = m_SSU2Keys->intro; + } + else + it = addresses.erase (it); + updated = true; } + else + it++; } if (enable && !found) { From 53934a470bec3723d429d59a202b93a9d1348565 Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 6 Aug 2022 16:30:49 -0400 Subject: [PATCH 106/219] update keys for NTCP2 and SSU2 addreses --- libi2pd/RouterContext.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index 2c24fc65..eb034194 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -347,10 +347,11 @@ namespace i2p { (*it)->s = m_NTCP2Keys->staticPublicKey; memcpy ((*it)->i, m_NTCP2Keys->iv, 16); + it++; } else it = addresses.erase (it); - updated = true;; + updated = true; } else it++; @@ -399,6 +400,7 @@ namespace i2p { (*it)->s = m_SSU2Keys->staticPublicKey; (*it)->i = m_SSU2Keys->intro; + it++; } else it = addresses.erase (it); From 8bb9a57908224ba7c2c5cf6f2a8f4e9655b8dd73 Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 6 Aug 2022 20:05:08 -0400 Subject: [PATCH 107/219] re-insert introducer back --- libi2pd/SSU2.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/libi2pd/SSU2.cpp b/libi2pd/SSU2.cpp index ef076447..ed3dc185 100644 --- a/libi2pd/SSU2.cpp +++ b/libi2pd/SSU2.cpp @@ -876,7 +876,10 @@ namespace transport { session->SetCreationTime (session->GetCreationTime () + SSU2_TO_INTRODUCER_SESSION_DURATION); if (std::find (newList.begin (), newList.end (), it) == newList.end ()) - newList.push_back (it); + { + newList.push_back (it); + sessions.push_back (session); + } } } } From b9970e19081d59e8d7e26a46f06fde57f4d6c911 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 7 Aug 2022 09:50:30 -0400 Subject: [PATCH 108/219] cleanup introducers upon reschedule --- libi2pd/SSU2.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libi2pd/SSU2.cpp b/libi2pd/SSU2.cpp index ed3dc185..fd0c5a22 100644 --- a/libi2pd/SSU2.cpp +++ b/libi2pd/SSU2.cpp @@ -941,6 +941,8 @@ namespace transport if (m_IsPublished) { m_IntroducersUpdateTimer.cancel (); + i2p::context.ClearSSU2Introducers (true); + m_Introducers.clear (); m_IntroducersUpdateTimer.expires_from_now (boost::posix_time::seconds(SSU2_KEEP_ALIVE_INTERVAL/2)); m_IntroducersUpdateTimer.async_wait (std::bind (&SSU2Server::HandleIntroducersUpdateTimer, this, std::placeholders::_1, true)); @@ -962,6 +964,8 @@ namespace transport if (m_IsPublished) { m_IntroducersUpdateTimerV6.cancel (); + i2p::context.ClearSSU2Introducers (false); + m_IntroducersV6.clear (); m_IntroducersUpdateTimerV6.expires_from_now (boost::posix_time::seconds(SSU2_KEEP_ALIVE_INTERVAL/2)); m_IntroducersUpdateTimerV6.async_wait (std::bind (&SSU2Server::HandleIntroducersUpdateTimer, this, std::placeholders::_1, false)); From c6f898b8ca90a6ae1415c19065bfc66a367f0431 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 8 Aug 2022 13:08:12 -0400 Subject: [PATCH 109/219] connect to Charlie if RelayResponse from Bob was received before HolePunch --- libi2pd/SSU2Session.cpp | 49 +++++++++++++++++++++++++++++------------ libi2pd/SSU2Session.h | 1 + 2 files changed, 36 insertions(+), 14 deletions(-) diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index fd109609..205da574 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -147,6 +147,22 @@ namespace transport m_State = eSSU2SessionStateIntroduced; ScheduleConnectTimer (); } + + void SSU2Session::ConnectAfterIntroduction () + { + if (m_State == eSSU2SessionStateIntroduced) + { + // create new connID + uint64_t oldConnID = GetConnID (); + RAND_bytes ((uint8_t *)&m_DestConnID, 8); + RAND_bytes ((uint8_t *)&m_SourceConnID, 8); + // connect + m_State = eSSU2SessionStateTokenReceived; + m_Server.AddPendingOutgoingSession (shared_from_this ()); + m_Server.RemoveSession (oldConnID); + Connect (); + } + } void SSU2Session::SendPeerTest () { @@ -486,7 +502,10 @@ namespace transport i2p::crypto::ChaCha20 (buf + 16, 16, i2p::context.GetSSU2IntroKey (), nonce, (uint8_t *)headerX); LogPrint (eLogWarning, "SSU2: Unexpected PeerTest message SourceConnID=", connID, " DestConnID=", headerX[0]); break; - } + } + case eSSU2HolePunch: + LogPrint (eLogDebug, "SSU2: Late HolePunch for ", connID); + break; default: { LogPrint (eLogWarning, "SSU2: Unexpected message type ", (int)header.h.type, " from ", m_RemoteEndpoint, " of ", len, " bytes"); @@ -1152,18 +1171,7 @@ namespace transport } HandlePayload (payload, len - 48); // connect to Charlie - if (m_State == eSSU2SessionStateIntroduced) - { - // create new connID - uint64_t oldConnID = GetConnID (); - RAND_bytes ((uint8_t *)&m_DestConnID, 8); - RAND_bytes ((uint8_t *)&m_SourceConnID, 8); - // connect - m_State = eSSU2SessionStateTokenReceived; - m_Server.AddPendingOutgoingSession (shared_from_this ()); - m_Server.RemoveSession (oldConnID); - Connect (); - } + ConnectAfterIntroduction (); return true; } @@ -1783,8 +1791,21 @@ namespace transport if (s.Verify (it->second.first->GetRemoteIdentity (), buf + 12 + csz)) { if (it->second.first->m_State == eSSU2SessionStateIntroduced) // HolePunch not received yet + { // update Charlie's endpoint - ExtractEndpoint (buf + 12, csz, it->second.first->m_RemoteEndpoint); + if (ExtractEndpoint (buf + 12, csz, it->second.first->m_RemoteEndpoint)) + { + // update token + uint64_t token; + memcpy (&token, buf + len - 8, 8); + m_Server.UpdateOutgoingToken (it->second.first->m_RemoteEndpoint, + token, i2p::util::GetSecondsSinceEpoch () + SSU2_TOKEN_EXPIRATION_TIMEOUT); + // connect to Charlie, HolePunch will be ignored + it->second.first->ConnectAfterIntroduction (); + } + else + LogPrint (eLogWarning, "SSU2: RelayResponse can't extract endpoint"); + } } else { diff --git a/libi2pd/SSU2Session.h b/libi2pd/SSU2Session.h index 767c3e04..9a9ac0d6 100644 --- a/libi2pd/SSU2Session.h +++ b/libi2pd/SSU2Session.h @@ -261,6 +261,7 @@ namespace transport bool SendQueue (); // returns true if ack block was sent bool SendFragmentedMessage (std::shared_ptr msg); void ResendHandshakePacket (); + void ConnectAfterIntroduction (); void ProcessSessionRequest (Header& header, uint8_t * buf, size_t len); void ProcessTokenRequest (Header& header, uint8_t * buf, size_t len); From 457b3cf16853ebc939d6d86629a3406387c32efa Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 8 Aug 2022 17:53:02 -0400 Subject: [PATCH 110/219] disable ElGamal table if no SSU --- daemon/Daemon.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/daemon/Daemon.cpp b/daemon/Daemon.cpp index 5ea1bfc0..d9ddfcc9 100644 --- a/daemon/Daemon.cpp +++ b/daemon/Daemon.cpp @@ -153,6 +153,9 @@ namespace util bool aesni; i2p::config::GetOption("cpuext.aesni", aesni); bool avx; i2p::config::GetOption("cpuext.avx", avx); bool forceCpuExt; i2p::config::GetOption("cpuext.force", forceCpuExt); + bool ssu; i2p::config::GetOption("ssu", ssu); + if (!ssu && i2p::config::IsDefault ("precomputation.elgamal")) + precomputation = false; // we don't elgamal table if no ssu, unless it's specified explicitly i2p::crypto::InitCrypto (precomputation, aesni, avx, forceCpuExt); int netID; i2p::config::GetOption("netid", netID); From ab606a11210d32424e85ea8177e8753ce2b5dee2 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 8 Aug 2022 19:57:48 -0400 Subject: [PATCH 111/219] adjust clock from SSU2 --- libi2pd/SSU2.cpp | 3 ++- libi2pd/SSU2.h | 2 ++ libi2pd/SSU2Session.cpp | 41 ++++++++++++++++++++++++++++++++++------- libi2pd/SSU2Session.h | 3 +++ 4 files changed, 41 insertions(+), 8 deletions(-) diff --git a/libi2pd/SSU2.cpp b/libi2pd/SSU2.cpp index fd0c5a22..73bd8077 100644 --- a/libi2pd/SSU2.cpp +++ b/libi2pd/SSU2.cpp @@ -24,7 +24,7 @@ namespace transport m_AddressV4 (boost::asio::ip::address_v4()), m_AddressV6 (boost::asio::ip::address_v6()), m_TerminationTimer (GetService ()), m_ResendTimer (GetService ()), m_IntroducersUpdateTimer (GetService ()), m_IntroducersUpdateTimerV6 (GetService ()), - m_IsPublished (true) + m_IsPublished (true), m_IsSyncClockFromPeers (true) { } @@ -34,6 +34,7 @@ namespace transport { StartIOService (); i2p::config::GetOption ("ssu2.published", m_IsPublished); + i2p::config::GetOption("nettime.frompeers", m_IsSyncClockFromPeers); bool found = false; auto& addresses = i2p::context.GetRouterInfo ().GetAddresses (); for (const auto& address: addresses) diff --git a/libi2pd/SSU2.h b/libi2pd/SSU2.h index 8bada7a6..8ad64692 100644 --- a/libi2pd/SSU2.h +++ b/libi2pd/SSU2.h @@ -56,6 +56,7 @@ namespace transport void SetLocalAddress (const boost::asio::ip::address& localAddress); bool IsSupported (const boost::asio::ip::address& addr) const; uint16_t GetPort (bool v4) const; + bool IsSyncClockFromPeers () const { return m_IsSyncClockFromPeers; }; void AddSession (std::shared_ptr session); void RemoveSession (uint64_t connID); @@ -131,6 +132,7 @@ namespace transport m_IntroducersUpdateTimer, m_IntroducersUpdateTimerV6; std::shared_ptr m_LastSession; bool m_IsPublished; // if we maintain introducers + bool m_IsSyncClockFromPeers; public: diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index 205da574..f8c190c1 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -720,6 +720,7 @@ namespace transport } m_NoiseState->MixHash (payload, len - 64); // h = SHA256(h || encrypted payload from SessionCreated) for SessionConfirmed // payload + m_State = eSSU2SessionStateSessionCreatedReceived; HandlePayload (decryptedPayload.data (), decryptedPayload.size ()); m_Server.AddSession (shared_from_this ()); @@ -1320,13 +1321,7 @@ namespace transport { case eSSU2BlkDateTime: LogPrint (eLogDebug, "SSU2: Datetime"); - if (m_State == eSSU2SessionStateSessionRequestReceived) - { - auto ts = i2p::util::GetSecondsSinceEpoch (); - uint32_t signedOnTime = bufbe32toh (buf + offset); - if (signedOnTime < ts - SSU2_CLOCK_SKEW || signedOnTime > ts + SSU2_CLOCK_SKEW) - m_TerminationReason = eSSU2TerminationReasonClockSkew; - }; + HandleDateTime (buf + offset, size); break; case eSSU2BlkOptions: LogPrint (eLogDebug, "SSU2: Options"); @@ -1437,6 +1432,38 @@ namespace transport } } + void SSU2Session::HandleDateTime (const uint8_t * buf, size_t len) + { + int64_t offset = (int64_t)i2p::util::GetSecondsSinceEpoch () - (int64_t)bufbe32toh (buf); + switch (m_State) + { + case eSSU2SessionStateSessionRequestReceived: + if (std::abs (offset) > SSU2_CLOCK_SKEW) + m_TerminationReason = eSSU2TerminationReasonClockSkew; + break; + case eSSU2SessionStateSessionCreatedReceived: + if ((m_RemoteEndpoint.address ().is_v4 () && i2p::context.GetStatus () == eRouterStatusTesting) || + (m_RemoteEndpoint.address ().is_v6 () && i2p::context.GetStatusV6 () == eRouterStatusTesting)) + { + if (m_Server.IsSyncClockFromPeers ()) + { + if (std::abs (offset) > SSU2_CLOCK_THRESHOLD) + { + LogPrint (eLogWarning, "SSU2: Clock adjusted by ", -offset, " seconds"); + i2p::util::AdjustTimeOffset (-offset); + } + } + else if (std::abs (offset) > SSU2_CLOCK_SKEW) + { + LogPrint (eLogError, "SSU2: Clock skew detected ", offset, ". Check your clock"); + i2p::context.SetError (eRouterErrorClockSkew); + } + } + break; + default: ; + }; + } + void SSU2Session::HandleAck (const uint8_t * buf, size_t len) { if (m_State == eSSU2SessionStateSessionConfirmedSent) diff --git a/libi2pd/SSU2Session.h b/libi2pd/SSU2Session.h index 9a9ac0d6..1730a939 100644 --- a/libi2pd/SSU2Session.h +++ b/libi2pd/SSU2Session.h @@ -27,6 +27,7 @@ namespace transport const int SSU2_CONNECT_TIMEOUT = 5; // 5 seconds const int SSU2_TERMINATION_TIMEOUT = 330; // 5.5 minutes const int SSU2_CLOCK_SKEW = 60; // in seconds + const int SSU2_CLOCK_THRESHOLD = 15; // in seconds, if more we should adjust const int SSU2_TOKEN_EXPIRATION_TIMEOUT = 9; // for Retry message, in seconds const int SSU2_NEXT_TOKEN_EXPIRATION_TIMEOUT = 52*60; // for next token block, in seconds const int SSU2_TOKEN_EXPIRATION_THRESHOLD = 2; // in seconds @@ -92,6 +93,7 @@ namespace transport eSSU2SessionStateSessionRequestSent, eSSU2SessionStateSessionRequestReceived, eSSU2SessionStateSessionCreatedSent, + eSSU2SessionStateSessionCreatedReceived, eSSU2SessionStateSessionConfirmedSent, eSSU2SessionStateEstablished, eSSU2SessionStateClosing, @@ -280,6 +282,7 @@ namespace transport void SendPathResponse (const uint8_t * data, size_t len); void HandlePayload (const uint8_t * buf, size_t len); + void HandleDateTime (const uint8_t * buf, size_t len); void HandleAck (const uint8_t * buf, size_t len); void HandleAckRange (uint32_t firstPacketNum, uint32_t lastPacketNum, uint64_t ts); void HandleAddress (const uint8_t * buf, size_t len); From df92a851596eb0b62ef37ee20f0ca21adee3c0e9 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 9 Aug 2022 14:08:13 -0400 Subject: [PATCH 112/219] set SSU2 port +1 if not specified --- daemon/Daemon.cpp | 2 +- libi2pd/RouterContext.cpp | 37 ++++++++++++++++++++----------------- libi2pd/RouterInfo.cpp | 1 + libi2pd/SSU2.cpp | 3 ++- 4 files changed, 24 insertions(+), 19 deletions(-) diff --git a/daemon/Daemon.cpp b/daemon/Daemon.cpp index d9ddfcc9..b3ac755d 100644 --- a/daemon/Daemon.cpp +++ b/daemon/Daemon.cpp @@ -257,7 +257,7 @@ namespace util if (ssu2) { uint16_t ssu2port; i2p::config::GetOption("ssu2.port", ssu2port); - if (!ssu2port) ssu2port = port; + if (!ssu2port) ssu2port = ssu ? (port + 1) : port; bool published; i2p::config::GetOption("ssu2.published", published); if (published) i2p::context.PublishSSU2Address (ssu2port, true, ipv4, ipv6); // publish diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index eb034194..fa5c4fdc 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -121,7 +121,11 @@ namespace i2p if (ssu2) { if (ssu2Published) - routerInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, boost::asio::ip::address_v4::from_string (host), port); + { + uint16_t ssu2Port; i2p::config::GetOption ("ssu2.port", ssu2Port); + if (!ssu2Port) ssu2Port = ssu ? (port + 1) : port; + routerInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, boost::asio::ip::address_v4::from_string (host), ssu2Port); + } else { addressCaps |= i2p::data::RouterInfo::AddressCaps::eV4; @@ -166,7 +170,11 @@ namespace i2p if (ssu2) { if (ssu2Published) - routerInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, boost::asio::ip::address_v6::from_string (host), port); + { + uint16_t ssu2Port; i2p::config::GetOption ("ssu2.port", ssu2Port); + if (!ssu2Port) ssu2Port = ssu ? (port + 1) : port; + routerInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, boost::asio::ip::address_v6::from_string (host), ssu2Port); + } else { if (!ipv4) // no other ssu2 addresses yet @@ -734,14 +742,11 @@ namespace i2p } if (!port) i2p::config::GetOption("port", port); // SSU - if (!foundSSU) + bool ssu; i2p::config::GetOption("ssu", ssu); + if (!foundSSU && ssu) { - bool ssu; i2p::config::GetOption("ssu", ssu); - if (ssu) - { - std::string host = "::1"; // TODO: read host - m_RouterInfo.AddSSUAddress (host.c_str (), port, nullptr); - } + std::string host = "::1"; // TODO: read host + m_RouterInfo.AddSSUAddress (host.c_str (), port, nullptr); } // NTCP2 if (!foundNTCP2) @@ -775,7 +780,7 @@ namespace i2p if (ssu2Published) { uint16_t ssu2Port; i2p::config::GetOption ("ssu2.port", ssu2Port); - if (!ssu2Port) ssu2Port = port; + if (!ssu2Port) ssu2Port = ssu ? (port + 1) : port; m_RouterInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, boost::asio::ip::address::from_string ("::1"), ssu2Port); } else @@ -823,12 +828,10 @@ namespace i2p } if (!port) i2p::config::GetOption("port", port); // SSU - if (!foundSSU) - { - bool ssu; i2p::config::GetOption("ssu", ssu); - if (ssu) - m_RouterInfo.AddSSUAddress (host.c_str (), port, nullptr); - } + bool ssu; i2p::config::GetOption("ssu", ssu); + if (!foundSSU && ssu) + m_RouterInfo.AddSSUAddress (host.c_str (), port, nullptr); + // NTCP2 if (!foundNTCP2) { @@ -856,7 +859,7 @@ namespace i2p if (ssu2Published) { uint16_t ssu2Port; i2p::config::GetOption ("ssu2.port", ssu2Port); - if (!ssu2Port) ssu2Port = port; + if (!ssu2Port) ssu2Port = ssu ? (port + 1) : port; m_RouterInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, boost::asio::ip::address::from_string ("127.0.0.1"), ssu2Port); } else diff --git a/libi2pd/RouterInfo.cpp b/libi2pd/RouterInfo.cpp index 42a0a347..7368001d 100644 --- a/libi2pd/RouterInfo.cpp +++ b/libi2pd/RouterInfo.cpp @@ -708,6 +708,7 @@ namespace data { auto addr = std::make_shared
(); addr->transportStyle = eTransportSSU2; + addr->port = 0; addr->caps = caps; addr->date = 0; addr->ssu.reset (new SSUExt ()); diff --git a/libi2pd/SSU2.cpp b/libi2pd/SSU2.cpp index 73bd8077..019fffca 100644 --- a/libi2pd/SSU2.cpp +++ b/libi2pd/SSU2.cpp @@ -49,8 +49,9 @@ namespace transport if (ssu2Port) port = ssu2Port; else { + bool ssu; i2p::config::GetOption("ssu", ssu); uint16_t p; i2p::config::GetOption ("port", p); - if (p) port = p; + if (p) port = ssu ? (p + 1) : p; } } if (port) From 3dd78a2589d13204422e6954608976a14b290fa1 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 9 Aug 2022 19:12:11 -0400 Subject: [PATCH 113/219] remove SSU address if SSU is off --- daemon/Daemon.cpp | 1 + libi2pd/RouterContext.cpp | 12 ++++++++++++ libi2pd/RouterContext.h | 1 + 3 files changed, 14 insertions(+) diff --git a/daemon/Daemon.cpp b/daemon/Daemon.cpp index b3ac755d..0b69f511 100644 --- a/daemon/Daemon.cpp +++ b/daemon/Daemon.cpp @@ -253,6 +253,7 @@ namespace util if (!ipv4 && !ipv6) i2p::context.SetStatus (eRouterStatusMesh); } + if (!ssu) i2p::context.RemoveSSUAddress (); // TODO: remove later bool ssu2; i2p::config::GetOption("ssu2.enabled", ssu2); if (ssu2) { diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index fa5c4fdc..7ef59037 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -628,6 +628,18 @@ namespace i2p } } + void RouterContext::RemoveSSUAddress () + { + auto& addresses = m_RouterInfo.GetAddresses (); + for (auto it = addresses.begin (); it != addresses.end ();) + { + if ((*it)->transportStyle == i2p::data::RouterInfo::eTransportSSU) + it = addresses.erase (it); + else + ++it; + } + } + void RouterContext::SetUnreachableSSU2 (bool v4, bool v6) { if (IsSSU2Only ()) diff --git a/libi2pd/RouterContext.h b/libi2pd/RouterContext.h index 0c1acc7b..d4f219e1 100644 --- a/libi2pd/RouterContext.h +++ b/libi2pd/RouterContext.h @@ -123,6 +123,7 @@ namespace garlic void PublishSSU2Address (int port, bool publish, bool v4, bool v6); void UpdateSSU2Address (bool enable); void RemoveNTCPAddress (bool v4only = true); // delete NTCP address for older routers. TODO: remove later + void RemoveSSUAddress (); // delete SSU address for older routers bool AddIntroducer (const i2p::data::RouterInfo::Introducer& introducer); void RemoveIntroducer (const boost::asio::ip::udp::endpoint& e); bool AddSSU2Introducer (const i2p::data::RouterInfo::Introducer& introducer, bool v4); From 8f5768f85b1d761c44bb6cf7e2b7d6d7155112a6 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 9 Aug 2022 19:40:07 -0400 Subject: [PATCH 114/219] memory pool for leases --- libi2pd/LeaseSet.cpp | 4 ++-- libi2pd/NetDb.cpp | 1 + libi2pd/NetDb.hpp | 2 ++ 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/libi2pd/LeaseSet.cpp b/libi2pd/LeaseSet.cpp index 60c9ea5a..387527e3 100644 --- a/libi2pd/LeaseSet.cpp +++ b/libi2pd/LeaseSet.cpp @@ -1,5 +1,5 @@ /* -* Copyright (c) 2013-2021, The PurpleI2P Project +* Copyright (c) 2013-2022, The PurpleI2P Project * * This file is part of Purple i2pd project and licensed under BSD3 * @@ -172,7 +172,7 @@ namespace data m_ExpirationTime = lease.endDate; if (m_StoreLeases) { - auto ret = m_Leases.insert (std::make_shared(lease)); + auto ret = m_Leases.insert (i2p::data::netdb.NewLease (lease)); if (!ret.second) (*ret.first)->endDate = lease.endDate; // update existing (*ret.first)->isUpdated = true; } diff --git a/libi2pd/NetDb.cpp b/libi2pd/NetDb.cpp index 8bbabff4..7f31fc7d 100644 --- a/libi2pd/NetDb.cpp +++ b/libi2pd/NetDb.cpp @@ -1447,6 +1447,7 @@ namespace data else ++it; } + m_LeasesPool.CleanUpMt (); } void NetDb::PopulateRouterInfoBuffer (std::shared_ptr r) diff --git a/libi2pd/NetDb.hpp b/libi2pd/NetDb.hpp index ebd6acbe..b14b84e7 100644 --- a/libi2pd/NetDb.hpp +++ b/libi2pd/NetDb.hpp @@ -126,6 +126,7 @@ namespace data void ClearRouterInfos () { m_RouterInfos.clear (); }; std::shared_ptr NewRouterInfoBuffer () { return m_RouterInfoBuffersPool.AcquireSharedMt (); }; void PopulateRouterInfoBuffer (std::shared_ptr r); + std::shared_ptr NewLease (const Lease& lease) { return m_LeasesPool.AcquireSharedMt (lease); }; uint32_t GetPublishReplyToken () const { return m_PublishReplyToken; }; @@ -182,6 +183,7 @@ namespace data uint32_t m_PublishReplyToken = 0; i2p::util::MemoryPoolMt m_RouterInfoBuffersPool; + i2p::util::MemoryPoolMt m_LeasesPool; }; extern NetDb netdb; From e9e641afbe7a3de5db78fcb3eef558501159e8b7 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 10 Aug 2022 11:28:59 -0400 Subject: [PATCH 115/219] check if datagram destination exists before sending --- libi2pd_client/SAM.cpp | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/libi2pd_client/SAM.cpp b/libi2pd_client/SAM.cpp index fc56b2c9..5d0f4425 100644 --- a/libi2pd_client/SAM.cpp +++ b/libi2pd_client/SAM.cpp @@ -1,5 +1,5 @@ /* -* Copyright (c) 2013-2021, The PurpleI2P Project +* Copyright (c) 2013-2022, The PurpleI2P Project * * This file is part of Purple i2pd project and licensed under BSD3 * @@ -1478,14 +1478,21 @@ namespace client auto session = FindSession (sessionID); if (session) { - i2p::data::IdentityEx dest; - dest.FromBase64 (destination); - if (session->Type == eSAMSessionTypeDatagram) - session->GetLocalDestination ()->GetDatagramDestination ()-> - SendDatagramTo ((uint8_t *)eol, payloadLen, dest.GetIdentHash ()); - else // raw - session->GetLocalDestination ()->GetDatagramDestination ()-> - SendRawDatagramTo ((uint8_t *)eol, payloadLen, dest.GetIdentHash ()); + auto localDest = session->GetLocalDestination (); + auto datagramDest = localDest ? localDest->GetDatagramDestination () : nullptr; + if (datagramDest) + { + i2p::data::IdentityEx dest; + dest.FromBase64 (destination); + if (session->Type == eSAMSessionTypeDatagram) + datagramDest->SendDatagramTo ((uint8_t *)eol, payloadLen, dest.GetIdentHash ()); + else if (session->Type == eSAMSessionTypeRaw) + datagramDest->SendRawDatagramTo ((uint8_t *)eol, payloadLen, dest.GetIdentHash ()); + else + LogPrint (eLogError, "SAM: Unexpected session type ", (int)session->Type, "for session ", sessionID); + } + else + LogPrint (eLogError, "SAM: Datagram destination is not set for session ", sessionID); } else LogPrint (eLogError, "SAM: Session ", sessionID, " not found"); From f4d6a08d576c58367ec3eb4c937400beeeaad408 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 10 Aug 2022 15:50:30 -0400 Subject: [PATCH 116/219] create separate addresses for published SSU2 --- libi2pd/RouterContext.cpp | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index 7ef59037..2864251f 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -419,12 +419,21 @@ namespace i2p } if (enable && !found) { - uint8_t addressCaps = 0; bool ipv4; i2p::config::GetOption("ipv4", ipv4); bool ipv6; i2p::config::GetOption("ipv6", ipv6); - if (ipv4) addressCaps |= i2p::data::RouterInfo::AddressCaps::eV4; - if (ipv6) addressCaps |= i2p::data::RouterInfo::AddressCaps::eV6; - m_RouterInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, addressCaps); + bool published; i2p::config::GetOption("ntcp2.published", published); + if (published) + { + if (ipv4) m_RouterInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, i2p::data::RouterInfo::AddressCaps::eV4); + if (ipv6) m_RouterInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, i2p::data::RouterInfo::AddressCaps::eV6); + } + else + { + uint8_t addressCaps = 0; + if (ipv4) addressCaps |= i2p::data::RouterInfo::AddressCaps::eV4; + if (ipv6) addressCaps |= i2p::data::RouterInfo::AddressCaps::eV6; + m_RouterInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, addressCaps); + } updated = true; } if (updated) @@ -875,7 +884,7 @@ namespace i2p m_RouterInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, boost::asio::ip::address::from_string ("127.0.0.1"), ssu2Port); } else - m_RouterInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, i2p::data::RouterInfo::eV6); + m_RouterInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, i2p::data::RouterInfo::eV4); } } m_RouterInfo.EnableV4 (); From 9d123fa5ad0e1a8606ac2492763a2fe8f65ea557 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 10 Aug 2022 22:00:11 -0400 Subject: [PATCH 117/219] select random port if port not found or specified --- libi2pd/RouterContext.cpp | 32 +++++++++++++++++++------------- libi2pd/RouterContext.h | 1 + 2 files changed, 20 insertions(+), 13 deletions(-) diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index 2864251f..5ebacfcc 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -60,11 +60,7 @@ namespace i2p i2p::data::LocalRouterInfo routerInfo; routerInfo.SetRouterIdentity (GetIdentity ()); uint16_t port; i2p::config::GetOption("port", port); - if (!port) - { - port = rand () % (30777 - 9111) + 9111; // I2P network ports range - if (port == 9150) port = 9151; // Tor browser - } + if (!port) port = SelectRandomPort (); bool ipv4; i2p::config::GetOption("ipv4", ipv4); bool ipv6; i2p::config::GetOption("ipv6", ipv6); bool ssu; i2p::config::GetOption("ssu", ssu); @@ -200,6 +196,13 @@ namespace i2p m_RouterInfo.Update (routerInfo.GetBuffer (), routerInfo.GetBufferLen ()); } + uint16_t RouterContext::SelectRandomPort () const + { + uint16_t port = rand () % (30777 - 9111) + 9111; // I2P network ports range + if (port == 9150) port = 9151; // Tor browser + return port; + } + void RouterContext::UpdateRouterInfo () { m_RouterInfo.CreateBuffer (m_Keys); @@ -325,12 +328,7 @@ namespace i2p } 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 = SelectRandomPort (); if (port) address->port = port; address->published = publish; memcpy (address->i, m_NTCP2Keys->iv, 16); @@ -761,7 +759,11 @@ namespace i2p } port = addr->port; } - if (!port) i2p::config::GetOption("port", port); + if (!port) + { + i2p::config::GetOption("port", port); + if (!port) port = SelectRandomPort (); + } // SSU bool ssu; i2p::config::GetOption("ssu", ssu); if (!foundSSU && ssu) @@ -847,7 +849,11 @@ namespace i2p } if (addr->port) port = addr->port; } - if (!port) i2p::config::GetOption("port", port); + if (!port) + { + i2p::config::GetOption("port", port); + if (!port) port = SelectRandomPort (); + } // SSU bool ssu; i2p::config::GetOption("ssu", ssu); if (!foundSSU && ssu) diff --git a/libi2pd/RouterContext.h b/libi2pd/RouterContext.h index d4f219e1..b6d3e7f0 100644 --- a/libi2pd/RouterContext.h +++ b/libi2pd/RouterContext.h @@ -186,6 +186,7 @@ namespace garlic bool IsSSU2Only () const; // SSU2 and no SSU bool Load (); void SaveKeys (); + uint16_t SelectRandomPort () const; bool DecryptECIESTunnelBuildRecord (const uint8_t * encrypted, uint8_t * data, size_t clearTextSize); From d10c86b849f77e6bffb3156cc5f61ed6832509f4 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Thu, 11 Aug 2022 21:06:22 +0300 Subject: [PATCH 118/219] [rpm] fix fedora build Signed-off-by: R4SAS --- contrib/rpm/i2pd-git.spec | 6 ------ contrib/rpm/i2pd.spec | 6 ------ 2 files changed, 12 deletions(-) diff --git a/contrib/rpm/i2pd-git.spec b/contrib/rpm/i2pd-git.spec index dc6aae70..6c710c3a 100644 --- a/contrib/rpm/i2pd-git.spec +++ b/contrib/rpm/i2pd-git.spec @@ -62,9 +62,7 @@ pushd redhat-linux-build %endif %if 0%{?fedora} >= 35 -%if 0%{?fedora} < 37 pushd redhat-linux-build -%endif %else %if 0%{?fedora} >= 33 pushd %{_target_platform} @@ -82,10 +80,8 @@ popd %endif %if 0%{?fedora} >= 33 -%if 0%{?fedora} < 37 popd %endif -%endif %if 0%{?mageia} > 7 popd @@ -99,9 +95,7 @@ pushd redhat-linux-build %endif %if 0%{?fedora} >= 35 -%if 0%{?fedora} < 37 pushd redhat-linux-build -%endif %else %if 0%{?fedora} >= 33 pushd %{_target_platform} diff --git a/contrib/rpm/i2pd.spec b/contrib/rpm/i2pd.spec index 98c804c6..22ebdf99 100644 --- a/contrib/rpm/i2pd.spec +++ b/contrib/rpm/i2pd.spec @@ -59,9 +59,7 @@ pushd redhat-linux-build %endif %if 0%{?fedora} >= 35 -%if 0%{?fedora} < 37 pushd redhat-linux-build -%endif %else %if 0%{?fedora} >= 33 pushd %{_target_platform} @@ -79,10 +77,8 @@ popd %endif %if 0%{?fedora} >= 33 -%if 0%{?fedora} < 37 popd %endif -%endif %if 0%{?mageia} > 7 popd @@ -96,9 +92,7 @@ pushd redhat-linux-build %endif %if 0%{?fedora} >= 35 -%if 0%{?fedora} < 37 pushd redhat-linux-build -%endif %else %if 0%{?fedora} >= 33 pushd %{_target_platform} From 81f53d313ca034b0e1c4d4a191bae5751686e96d Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 11 Aug 2022 20:16:08 -0400 Subject: [PATCH 119/219] alsways set some port to SSU2 address --- libi2pd/RouterContext.cpp | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index 5ebacfcc..a663cf92 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -373,14 +373,26 @@ namespace i2p void RouterContext::PublishSSU2Address (int port, bool publish, bool v4, bool v6) { - if (!m_SSU2Keys || (publish && !port)) return; + if (!m_SSU2Keys) return; + int newPort = 0; + if (!port) + { + for (const auto& address : m_RouterInfo.GetAddresses ()) + if (address->port) + { + newPort = address->port; + break; + } + if (!newPort) newPort = SelectRandomPort (); + } bool updated = false; for (auto& address : m_RouterInfo.GetAddresses ()) { - if (address->IsSSU2 () && (address->port != port || address->published != publish) && + if (address->IsSSU2 () && (!address->port || address->port != port || address->published != publish) && ((v4 && address->IsV4 ()) || (v6 && address->IsV6 ()))) { - address->port = port; + if (port) address->port = port; + else if (!address->port) address->port = newPort; address->published = publish; if (publish) address->caps |= (i2p::data::RouterInfo::eSSUIntroducer | i2p::data::RouterInfo::eSSUTesting); From 3ae885d120482be3aef86a632dee082b7c08a8ee Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 12 Aug 2022 16:12:30 -0400 Subject: [PATCH 120/219] change status back to Testing from Unknow if next test was accepted --- libi2pd/SSU2Session.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index f8c190c1..cfb530d1 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -2001,6 +2001,8 @@ namespace transport { if (buf[1] == eSSU2PeerTestCodeAccept) { + if (GetRouterStatus () == eRouterStatusUnknown) + SetRouterStatus (eRouterStatusTesting); auto r = i2p::data::netdb.FindRouter (buf + 3); // find Charlie if (r && it->second.first) { From c3dd7ed73aaf312fe4e635a3aa1ec726d8137e39 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 12 Aug 2022 18:56:58 -0400 Subject: [PATCH 121/219] try to resend if window is full --- libi2pd/SSU2Session.cpp | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index cfb530d1..56d87049 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -284,13 +284,18 @@ namespace transport for (auto it: msgs) m_SendQueue.push_back (it); SendQueue (); - - if (m_SendQueue.size () > SSU2_MAX_OUTGOING_QUEUE_SIZE) - { - LogPrint (eLogWarning, "SSU2: Outgoing messages queue size to ", - GetIdentHashBase64(), " exceeds ", SSU2_MAX_OUTGOING_QUEUE_SIZE); - RequestTermination (eSSU2TerminationReasonTimeout); - } + + if (m_SendQueue.size () > 0) // windows is full + { + if (m_SendQueue.size () <= SSU2_MAX_OUTGOING_QUEUE_SIZE) + Resend (i2p::util::GetMillisecondsSinceEpoch ()); + else + { + LogPrint (eLogWarning, "SSU2: Outgoing messages queue size to ", + GetIdentHashBase64(), " exceeds ", SSU2_MAX_OUTGOING_QUEUE_SIZE); + RequestTermination (eSSU2TerminationReasonTimeout); + } + } } bool SSU2Session::SendQueue () @@ -462,7 +467,6 @@ namespace transport m_WindowSize >>= 1; // /2 if (m_WindowSize < SSU2_MIN_WINDOW_SIZE) m_WindowSize = SSU2_MIN_WINDOW_SIZE; } - SendQueue (); } void SSU2Session::ResendHandshakePacket () From 75611866ebe33a924814f6526a5b821334b1098c Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 14 Aug 2022 10:43:16 -0400 Subject: [PATCH 122/219] update router's transports when SSU or NTCP address was deleted --- libi2pd/RouterContext.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index a663cf92..77d3763d 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -633,6 +633,7 @@ namespace i2p void RouterContext::RemoveNTCPAddress (bool v4only) { + bool updated = false; auto& addresses = m_RouterInfo.GetAddresses (); for (auto it = addresses.begin (); it != addresses.end ();) { @@ -640,23 +641,32 @@ namespace i2p (!v4only || (*it)->host.is_v4 ())) { it = addresses.erase (it); + updated = true; if (v4only) break; // otherwise might be more than one address } else ++it; } + if (updated) + m_RouterInfo.UpdateSupportedTransports (); } void RouterContext::RemoveSSUAddress () { + bool updated = false; auto& addresses = m_RouterInfo.GetAddresses (); for (auto it = addresses.begin (); it != addresses.end ();) { if ((*it)->transportStyle == i2p::data::RouterInfo::eTransportSSU) + { it = addresses.erase (it); + updated = true; + } else ++it; } + if (updated) + m_RouterInfo.UpdateSupportedTransports (); } void RouterContext::SetUnreachableSSU2 (bool v4, bool v6) From f8758233577e3d3ab8f9bbc6ebf214e2df492c89 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 15 Aug 2022 15:32:55 -0400 Subject: [PATCH 123/219] copy path challenge to response --- libi2pd/SSU2Session.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index 56d87049..da7a9434 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -2592,6 +2592,7 @@ namespace transport uint8_t payload[SSU2_MAX_PACKET_SIZE]; payload[0] = eSSU2BlkPathResponse; htobe16buf (payload + 1, len); + memcpy (payload + 3, data, len); SendData (payload, len + 3); } From 7f0845dfd36617078daf169bdca869d9fd44dbb3 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 16 Aug 2022 14:06:13 -0400 Subject: [PATCH 124/219] reset acceptor on stop of server tunnel --- libi2pd_client/I2PTunnel.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/libi2pd_client/I2PTunnel.cpp b/libi2pd_client/I2PTunnel.cpp index 4d749927..c2839c62 100644 --- a/libi2pd_client/I2PTunnel.cpp +++ b/libi2pd_client/I2PTunnel.cpp @@ -660,6 +660,12 @@ namespace client void I2PServerTunnel::Stop () { + if (m_PortDestination) + m_PortDestination->ResetAcceptor (); + auto localDestination = GetLocalDestination (); + if (localDestination) + localDestination->StopAcceptingStreams (); + ClearHandlers (); } From 66fcbcae9639a7dc89e711f839877f9207b47eca Mon Sep 17 00:00:00 2001 From: r4sas Date: Fri, 19 Aug 2022 19:27:34 +0000 Subject: [PATCH 125/219] add ntcp2 and ssu2 options in example config Signed-off-by: r4sas --- contrib/i2pd.conf | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/contrib/i2pd.conf b/contrib/i2pd.conf index 0fdc3809..ebe394f0 100644 --- a/contrib/i2pd.conf +++ b/contrib/i2pd.conf @@ -96,6 +96,22 @@ ipv6 = false ## Note: that mode uses much more network connections and CPU! # floodfill = true +[ntcp2] +## Enable NTCP2 transport (default = true) +# enabled = true +## Publish address in RouterInfo (default = true) +# published = true +## Port for incoming connections (default is global port option value) +# port = 4567 + +[ssu2] +## Enable SSU2 transport (default = false for 2.43.0) +enabled = true +## Publish address in RouterInfo (default = false for 2.43.0) +published = true +## Port for incoming connections (default is global port option value or port + 1 if SSU is enabled) +# port = 4567 + [http] ## Web Console settings ## Uncomment and set to 'false' to disable Web Console From 4fa7e431623e5f21ae6d47edbb64f0c6a2120d39 Mon Sep 17 00:00:00 2001 From: r4sas Date: Fri, 19 Aug 2022 19:38:54 +0000 Subject: [PATCH 126/219] disable ssu in example config file Signed-off-by: r4sas --- contrib/i2pd.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/i2pd.conf b/contrib/i2pd.conf index ebe394f0..1c4d814c 100644 --- a/contrib/i2pd.conf +++ b/contrib/i2pd.conf @@ -76,7 +76,7 @@ ipv4 = true ipv6 = false ## Enable SSU transport (default = true) -# ssu = true +ssu = false ## Bandwidth configuration ## L limit bandwidth to 32KBs/sec, O - to 256KBs/sec, P - to 2048KBs/sec, From b40f1b67b934ee7af322016551400c6fc858ef1a Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 21 Aug 2022 14:52:55 -0400 Subject: [PATCH 127/219] 2.43.0 --- ChangeLog | 28 ++++++++++++++++++++++++++++ contrib/rpm/i2pd-git.spec | 5 ++++- contrib/rpm/i2pd.spec | 5 ++++- debian/changelog | 6 ++++++ libi2pd/version.h | 6 +++--- 5 files changed, 45 insertions(+), 5 deletions(-) diff --git a/ChangeLog b/ChangeLog index b4e815e4..acc41795 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,34 @@ # for this file format description, # see https://github.com/olivierlacan/keep-a-changelog +## [2.43.0] - 2022-08-22 +### Added +- Complete SSU2 implementation +- Localization to Chinese +- Send RouterInfo update for long live sessions +- Explicit ipv6 ranges of known tunnel brokers for MTU detection +- Always send Connection: close and strip out Keep-Alive for server HTTP tunnel +- Show ports for all transports in web console +- Translation of webconsole site title +- Support for Windows ProgramData path when running as service +- Ability to turn off address book +- Handle signals TSTP and CONT to stop and resume network +### Changed +- Case insensitive headers for server HTTP tunnel +- Do not show 'Address registration' line if LeaseSet is encrypted +- SSU2 transports have higher priority than SSU +- Disable ElGamal precalculated table if no SSU +- Deprecate limits.ntcpsoft, limits.ntcphard and limits.ntcpthreads config options +- SSU2 is enabled and SSU is disabled by default for new installations +### Fixed +- Can't handle garlic message from an exploratory tunnel +- Incorrect encryption key for exploratory lookup reply +- MTU detection on Windows +- Crash on stop of active server tunnel +- Send datagram to wrong destination in SAM +- Incorrect static key in RouterInfo if the keys were regenerated +- Duplicated sessions in BOB + ## [2.42.1] - 2022-05-24 ### Fixed - Incorrect jump link in HTTP Proxy diff --git a/contrib/rpm/i2pd-git.spec b/contrib/rpm/i2pd-git.spec index 6c710c3a..95a64402 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.42.1 +Version: 2.43.0 Release: git%{git_hash}%{?dist} Summary: I2P router written in C++ Conflicts: i2pd @@ -158,6 +158,9 @@ getent passwd i2pd >/dev/null || \ %changelog +* Mon Aug 22 2022 orignal - 2.43.0 +- update to 2.43.0 + * Tue May 24 2022 r4sas - 2.42.1 - update to 2.42.1 diff --git a/contrib/rpm/i2pd.spec b/contrib/rpm/i2pd.spec index 22ebdf99..eda2914e 100644 --- a/contrib/rpm/i2pd.spec +++ b/contrib/rpm/i2pd.spec @@ -1,5 +1,5 @@ Name: i2pd -Version: 2.42.1 +Version: 2.43.0 Release: 1%{?dist} Summary: I2P router written in C++ Conflicts: i2pd-git @@ -155,6 +155,9 @@ getent passwd i2pd >/dev/null || \ %changelog +* Mon Aug 22 2022 orignal - 2.43.0 +- update to 2.43.0 + * Tue May 24 2022 r4sas - 2.42.1 - update to 2.42.1 diff --git a/debian/changelog b/debian/changelog index 3b4d88f6..78ce9472 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +i2pd (2.43.0-1) unstable; urgency=medium + + * updated to version 2.43.0/0.9.55 + + -- orignal Mon, 22 Aug 2022 16:00:00 +0000 + i2pd (2.42.1-1) unstable; urgency=medium * updated to version 2.42.1/0.9.54 diff --git a/libi2pd/version.h b/libi2pd/version.h index be27358f..5b6925cc 100644 --- a/libi2pd/version.h +++ b/libi2pd/version.h @@ -16,8 +16,8 @@ #define MAKE_VERSION_NUMBER(a,b,c) ((a*100+b)*100+c) #define I2PD_VERSION_MAJOR 2 -#define I2PD_VERSION_MINOR 42 -#define I2PD_VERSION_MICRO 1 +#define I2PD_VERSION_MINOR 43 +#define I2PD_VERSION_MICRO 0 #define I2PD_VERSION_PATCH 0 #ifdef GITVER #define I2PD_VERSION GITVER @@ -31,7 +31,7 @@ #define I2P_VERSION_MAJOR 0 #define I2P_VERSION_MINOR 9 -#define I2P_VERSION_MICRO 54 +#define I2P_VERSION_MICRO 55 #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) From e45d68ad3acb5cb63180dd03a08f735e5066546b Mon Sep 17 00:00:00 2001 From: R4SAS Date: Sun, 21 Aug 2022 22:38:40 +0300 Subject: [PATCH 128/219] [i18n] pull translations from Crowdin Signed-off-by: R4SAS --- i18n/Chinese.cpp | 26 +++++------ i18n/French.cpp | 115 +++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 125 insertions(+), 16 deletions(-) diff --git a/i18n/Chinese.cpp b/i18n/Chinese.cpp index e7989594..b933df3d 100644 --- a/i18n/Chinese.cpp +++ b/i18n/Chinese.cpp @@ -38,15 +38,15 @@ namespace chinese // language namespace {"building", "正在构建"}, {"failed", "连接失败"}, {"expiring", "即将过期"}, - {"established", "连接建立"}, + {"established", "连接已建立"}, {"unknown", "未知"}, - {"exploratory", "探索隧道"}, + {"exploratory", "探测"}, {"Purple I2P Webconsole", "Purple I2P 网页控制台"}, {"i2pd webconsole", "i2pd 网页控制台"}, {"Main page", "主页"}, {"Router commands", "路由命令"}, {"Local Destinations", "本地目标"}, - {"LeaseSets", "租约集"}, + {"LeaseSets", "租契集"}, {"Tunnels", "隧道"}, {"Transit Tunnels", "中转隧道"}, {"Transports", "传输"}, @@ -55,15 +55,15 @@ namespace chinese // language namespace {"ERROR", "错误"}, {"OK", "良好"}, {"Testing", "测试中"}, - {"Firewalled", "被防火墙阻挡"}, + {"Firewalled", "受到防火墙限制"}, {"Unknown", "未知"}, {"Proxy", "代理"}, - {"Mesh", "网格组网"}, + {"Mesh", "Mesh组网"}, {"Error", "错误"}, {"Clock skew", "时钟偏移"}, {"Offline", "离线"}, {"Symmetric NAT", "对称 NAT"}, - {"Uptime", "在线时间"}, + {"Uptime", "运行时间"}, {"Network status", "IPv4 网络状态"}, {"Network status v6", "IPv6 网络状态"}, {"Stopping in", "距停止还有:"}, @@ -74,10 +74,10 @@ namespace chinese // language namespace {"Sent", "已发送"}, {"Transit", "中转"}, {"Data path", "数据文件路径"}, - {"Hidden content. Press on text to see.", "隐藏内容 请点击文本查看。"}, - {"Router Ident", "路由器标识"}, + {"Hidden content. Press on text to see.", "隐藏内容 请点击此处查看。"}, + {"Router Ident", "路由身份"}, {"Router Family", "路由器家族"}, - {"Router Caps", "路由器分类"}, + {"Router Caps", "路由器类型"}, {"Version", "版本"}, {"Our external address", "外部地址"}, {"supported", "支持"}, @@ -91,7 +91,7 @@ namespace chinese // language namespace {"Address registration line", "地址域名注册"}, {"Domain", "域名"}, {"Generate", "生成"}, - {"Note: result string can be used only for registering 2LD domains (example.i2p). For registering subdomains please use i2pd-tools.", "注意: 结果字符串可以用于注册次级域名(例如:example.i2p)。若想注册次级域名,请使用 i2pd-tools。"}, + {"Note: result string can be used only for registering 2LD domains (example.i2p). For registering subdomains please use i2pd-tools.", "注意: 结果字符串可以用于注册次级域名(例如:example.i2p)。若需注册次级域名,请使用 i2pd-tools。"}, {"Address", "地址"}, {"Type", "类型"}, {"EncType", "加密类型"}, @@ -123,8 +123,8 @@ namespace chinese // language namespace {"Run peer test", "运行群体测试"}, {"Decline transit tunnels", "拒绝中转隧道"}, {"Accept transit tunnels", "允许中转隧道"}, - {"Cancel graceful shutdown", "取消计划的停止"}, - {"Start graceful shutdown", "待他人断线后停止"}, + {"Cancel graceful shutdown", "取消离线"}, + {"Start graceful shutdown", "优雅地离线"}, {"Force shutdown", "强制停止"}, {"Reload external CSS styles", "重载外部 CSS 样式"}, {"Note: any action done here are not persistent and not changes your config files.", "注意: 此处完成的任何操作都不是永久的,不会更改您的配置文件。"}, @@ -200,7 +200,7 @@ namespace chinese // language namespace static std::map> plurals { - {"days", {"日"}}, + {"days", {"天"}}, {"hours", {"时"}}, {"minutes", {"分"}}, {"seconds", {"秒"}}, diff --git a/i18n/French.cpp b/i18n/French.cpp index d41d215b..1a49ddfc 100644 --- a/i18n/French.cpp +++ b/i18n/French.cpp @@ -35,24 +35,33 @@ namespace french // language namespace {"MiB", "Mio"}, {"GiB", "Gio"}, {"building", "En construction"}, - {"failed", "echoué"}, + {"failed", "échoué"}, {"expiring", "expiré"}, {"established", "établi"}, {"unknown", "inconnu"}, {"exploratory", "exploratoire"}, + {"Purple I2P Webconsole", "Console web Purple I2P"}, {"i2pd webconsole", "Console web i2pd"}, {"Main page", "Page principale"}, {"Router commands", "Commandes du routeur"}, {"Local Destinations", "Destinations locales"}, + {"LeaseSets", "Jeu de baux"}, {"Tunnels", "Tunnels"}, {"Transit Tunnels", "Tunnels transitoires"}, + {"Transports", "Transports"}, {"I2P tunnels", "Tunnels I2P"}, {"SAM sessions", "Sessions SAM"}, {"ERROR", "ERREUR"}, {"OK", "OK"}, + {"Testing", "Test en cours"}, {"Firewalled", "Derrière un pare-feu"}, + {"Unknown", "Inconnu"}, + {"Proxy", "Proxy"}, + {"Mesh", "Maillé"}, {"Error", "Erreur"}, + {"Clock skew", "Horloge décalée"}, {"Offline", "Hors ligne"}, + {"Symmetric NAT", "NAT symétrique"}, {"Uptime", "Temps de fonctionnement"}, {"Network status", "État du réseau"}, {"Network status v6", "État du réseau v6"}, @@ -62,24 +71,124 @@ namespace french // language namespace {"Received", "Reçu"}, {"KiB/s", "kio/s"}, {"Sent", "Envoyé"}, - {"Transit", "Transit"}, - {"Hidden content. Press on text to see.", "Contenu caché. Cliquez sur le texte pour regarder."}, + {"Transit", "Transité"}, + {"Data path", "Emplacement des données"}, + {"Hidden content. Press on text to see.", "Contenu caché. Cliquez sur le texte pour afficher."}, {"Router Ident", "Identifiant du routeur"}, {"Router Family", "Famille du routeur"}, + {"Router Caps", "Limiteurs du routeur"}, {"Version", "Version"}, {"Our external address", "Notre adresse externe"}, + {"supported", "supporté"}, + {"Routers", "Routeurs"}, {"Client Tunnels", "Tunnels clients"}, {"Services", "Services"}, {"Enabled", "Activé"}, {"Disabled", "Désactivé"}, {"Encrypted B33 address", "Adresse B33 chiffrée"}, + {"Address registration line", "Ligne d'inscription de l'adresse"}, {"Domain", "Domaine"}, + {"Generate", "Générer"}, {"Note: result string can be used only for registering 2LD domains (example.i2p). For registering subdomains please use i2pd-tools.", "Note: La chaîne résultante peut seulement être utilisée pour enregistrer les domaines 2LD (exemple.i2p). Pour enregistrer des sous-domaines, veuillez utiliser i2pd-tools."}, {"Address", "Adresse"}, + {"Type", "Type"}, + {"Inbound tunnels", "Tunnels entrants"}, {"ms", "ms"}, {"Outbound tunnels", "Tunnels sortants"}, + {"Tags", "Balises"}, + {"Incoming", "Entrant"}, + {"Outgoing", "Sortant"}, {"Destination", "Destination"}, + {"Amount", "Quantité"}, + {"Incoming Tags", "Balises entrantes"}, + {"Tags sessions", "Sessions des balises"}, + {"Status", "Statut"}, {"Local Destination", "Destination locale"}, + {"Streams", "Flux"}, + {"Close stream", "Fermer le flux"}, + {"I2CP session not found", "Session I2CP introuvable"}, + {"I2CP is not enabled", "I2CP est désactivé"}, + {"Invalid", "Invalide"}, + {"Store type", "Type de stockage"}, + {"Expires", "Expire"}, + {"Non Expired Leases", "Baux non expirés"}, + {"Gateway", "Passerelle"}, + {"TunnelID", "ID du tunnel"}, + {"EndDate", "Date de fin"}, + {"Queue size", "Longueur de la file"}, + {"Run peer test", "Lancer test des pairs"}, + {"Decline transit tunnels", "Refuser les tunnels transitoires"}, + {"Accept transit tunnels", "Accepter les tunnels transitoires"}, + {"Cancel graceful shutdown", "Annuler l'arrêt gracieux"}, + {"Start graceful shutdown", "Démarrer l'arrêt gracieux"}, + {"Force shutdown", "Forcer l'arrêt"}, + {"Reload external CSS styles", "Rafraîchir les styles CSS externes"}, + {"Note: any action done here are not persistent and not changes your config files.", "Note: Toute action effectuée ici n'est pas permanente et ne modifie pas vos fichiers de configuration."}, + {"Logging level", "Niveau de journalisation"}, + {"Transit tunnels limit", "Limite sur les tunnels transitoires"}, + {"Change", "Changer"}, + {"Change language", "Changer la langue"}, + {"no transit tunnels currently built", "aucun tunnel transitoire présentement établi"}, + {"SAM disabled", "SAM désactivé"}, + {"no sessions currently running", "aucune session présentement en cours"}, + {"SAM session not found", "session SAM introuvable"}, + {"SAM Session", "Session SAM"}, + {"Server Tunnels", "Tunnels serveurs"}, + {"Unknown page", "Page inconnue"}, + {"Invalid token", "Jeton invalide"}, + {"SUCCESS", "SUCCÈS"}, + {"Stream closed", "Flux fermé"}, + {"Stream not found or already was closed", "Flux introuvable ou déjà fermé"}, + {"Destination not found", "Destination introuvable"}, + {"StreamID can't be null", "StreamID ne peut pas être vide"}, + {"Return to destination page", "Retourner à la page de destination"}, + {"You will be redirected in 5 seconds", "Vous allez être redirigé dans cinq secondes"}, + {"Transit tunnels count must not exceed 65535", "Le nombre de tunnels transitoires ne doit pas dépasser 65535"}, + {"Back to commands list", "Retour à la liste des commandes"}, + {"Register at reg.i2p", "Inscription à reg.i2p"}, + {"Description", "Description"}, + {"A bit information about service on domain", "Un peu d'information à propos des services disponibles dans le domaine"}, + {"Submit", "Soumettre"}, + {"Domain can't end with .b32.i2p", "Le domaine ne peut pas terminer par .b32.i2p"}, + {"Domain must end with .i2p", "Le domaine doit terminer par .i2p"}, + {"Such destination is not found", "Cette destination est introuvable"}, + {"Unknown command", "Commande inconnue"}, + {"Command accepted", "Commande acceptée"}, + {"Proxy error", "Erreur de proxy"}, + {"Proxy info", "Information sur le proxy"}, + {"Proxy error: Host not found", "Erreur de proxy: Hôte introuvable"}, + {"Remote host not found in router's addressbook", "Hôte distant introuvable dans le carnet d'adresse du routeur"}, + {"You may try to find this host on jump services below", "Vous pouvez essayer de trouver cet hôte sur des services de redirection ci-dessous"}, + {"Invalid request", "Requête invalide"}, + {"Proxy unable to parse your request", "Proxy incapable de comprendre votre requête"}, + {"addresshelper is not supported", "Assistant d'adresse non supporté"}, + {"Host", "Hôte"}, + {"added to router's addressbook from helper", "Ajouté au carnet d'adresse du routeur par l'assistant"}, + {"Click here to proceed:", "Cliquez ici pour continuer:"}, + {"Continue", "Continuer"}, + {"Addresshelper found", "Assistant d'adresse trouvé"}, + {"already in router's addressbook", "déjà dans le carnet d'adresses du routeur"}, + {"Click here to update record:", "Cliquez ici pour mettre à jour le carnet d'adresse:"}, + {"invalid request uri", "uri de la requête invalide"}, + {"Can't detect destination host from request", "Impossible de détecter l'hôte de destination à partir de la requête"}, + {"Outproxy failure", "Échec de proxy de sortie"}, + {"bad outproxy settings", "Mauvaise configuration du proxy de sortie"}, + {"not inside I2P network, but outproxy is not enabled", "pas dans le réseau I2P, mais le proxy de sortie n'est pas activé"}, + {"unknown outproxy url", "URL du proxy de sortie inconnu"}, + {"cannot resolve upstream proxy", "impossible de résoudre l'adresse du proxy en amont"}, + {"hostname too long", "nom d'hôte trop long"}, + {"cannot connect to upstream socks proxy", "impossible de se connecter au proxy socks en amont"}, + {"Cannot negotiate with socks proxy", "Impossible de négocier avec le proxy socks"}, + {"CONNECT error", "Erreur de connexion"}, + {"Failed to Connect", "Échec de connexion"}, + {"socks proxy error", "Erreur de proxy socks"}, + {"failed to send request to upstream", "Erreur lors de l'envoie de la requête en amont"}, + {"No Reply From socks proxy", "Pas de réponse du proxy socks"}, + {"cannot connect", "impossible de connecter"}, + {"http out proxy not implemented", "Proxy de sortie HTTP non implémenté"}, + {"cannot connect to upstream http proxy", "impossible de se connecter au proxy HTTP en amont"}, + {"Host is down", "Hôte hors service"}, + {"Can't create connection to requested host, it may be down. Please try again later.", "Impossible d'établir une connexion avec l'hôte, il est peut-être hors service. Veuillez réessayer plus tard."}, {"", ""}, }; From 79b97ef2f7606bc2e2e4b529b247ed2abbf8b5ca Mon Sep 17 00:00:00 2001 From: R4SAS Date: Sun, 21 Aug 2022 22:40:41 +0300 Subject: [PATCH 129/219] 2.43.0 Signed-off-by: R4SAS --- ChangeLog | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/ChangeLog b/ChangeLog index acc41795..95bc2c46 100644 --- a/ChangeLog +++ b/ChangeLog @@ -7,22 +7,24 @@ - Localization to Chinese - Send RouterInfo update for long live sessions - Explicit ipv6 ranges of known tunnel brokers for MTU detection -- Always send Connection: close and strip out Keep-Alive for server HTTP tunnel +- Always send "Connection: close" and strip out Keep-Alive for server HTTP tunnel - Show ports for all transports in web console -- Translation of webconsole site title -- Support for Windows ProgramData path when running as service +- Translation of webconsole site title +- Support for Windows ProgramData path when running as service - Ability to turn off address book - Handle signals TSTP and CONT to stop and resume network ### Changed - Case insensitive headers for server HTTP tunnel -- Do not show 'Address registration' line if LeaseSet is encrypted +- Do not show 'Address registration' line if LeaseSet is encrypted - SSU2 transports have higher priority than SSU -- Disable ElGamal precalculated table if no SSU +- Disable ElGamal precalculated table if no SSU - Deprecate limits.ntcpsoft, limits.ntcphard and limits.ntcpthreads config options - SSU2 is enabled and SSU is disabled by default for new installations ### Fixed +- Typo with Referer header name in HTTP proxy - Can't handle garlic message from an exploratory tunnel - Incorrect encryption key for exploratory lookup reply +- Bound checks issues in LeaseSets code - MTU detection on Windows - Crash on stop of active server tunnel - Send datagram to wrong destination in SAM From 150b8f8cbd643ba9aceacd00226674bc115d8f83 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 23 Aug 2022 15:11:10 -0400 Subject: [PATCH 130/219] Handle long HTTP headers --- libi2pd_client/I2PTunnel.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libi2pd_client/I2PTunnel.cpp b/libi2pd_client/I2PTunnel.cpp index c2839c62..1213b439 100644 --- a/libi2pd_client/I2PTunnel.cpp +++ b/libi2pd_client/I2PTunnel.cpp @@ -321,6 +321,8 @@ namespace client m_HeaderSent = true; I2PTunnelConnection::Write ((uint8_t *)m_OutHeader.str ().c_str (), m_OutHeader.str ().length ()); } + else + StreamReceive (); // read more header } } @@ -404,6 +406,8 @@ namespace client m_HeaderSent = true; I2PTunnelConnection::Write ((uint8_t *)m_OutHeader.str ().c_str (), m_OutHeader.str ().length ()); } + else + StreamReceive (); // read more header } } From 5b19237a85b59bb98f6e3dc4254dd5aff909b495 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 23 Aug 2022 19:06:28 -0400 Subject: [PATCH 131/219] limit HTTP header size --- libi2pd_client/I2PTunnel.cpp | 14 ++++++++++++-- libi2pd_client/I2PTunnel.h | 3 ++- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/libi2pd_client/I2PTunnel.cpp b/libi2pd_client/I2PTunnel.cpp index 1213b439..12c6485f 100644 --- a/libi2pd_client/I2PTunnel.cpp +++ b/libi2pd_client/I2PTunnel.cpp @@ -321,8 +321,13 @@ namespace client m_HeaderSent = true; I2PTunnelConnection::Write ((uint8_t *)m_OutHeader.str ().c_str (), m_OutHeader.str ().length ()); } - else + else if (m_OutHeader.tellp () < I2P_TUNNEL_HTTP_MAX_HEADER_SIZE) StreamReceive (); // read more header + else + { + LogPrint (eLogError, "I2PTunnel: HTTP header exceeds max size ", I2P_TUNNEL_HTTP_MAX_HEADER_SIZE); + Terminate (); + } } } @@ -406,8 +411,13 @@ namespace client m_HeaderSent = true; I2PTunnelConnection::Write ((uint8_t *)m_OutHeader.str ().c_str (), m_OutHeader.str ().length ()); } + else if (m_OutHeader.tellp () < I2P_TUNNEL_HTTP_MAX_HEADER_SIZE) + StreamReceive (); // read more header else - StreamReceive (); // read more header + { + LogPrint (eLogError, "I2PTunnel: HTTP header exceeds max size ", I2P_TUNNEL_HTTP_MAX_HEADER_SIZE); + Terminate (); + } } } diff --git a/libi2pd_client/I2PTunnel.h b/libi2pd_client/I2PTunnel.h index dfa23fb2..90c5864e 100644 --- a/libi2pd_client/I2PTunnel.h +++ b/libi2pd_client/I2PTunnel.h @@ -34,7 +34,8 @@ namespace client const char X_I2P_DEST_HASH[] = "X-I2P-DestHash"; // hash in base64 const char X_I2P_DEST_B64[] = "X-I2P-DestB64"; // full address in base64 const char X_I2P_DEST_B32[] = "X-I2P-DestB32"; // .b32.i2p address - + const int I2P_TUNNEL_HTTP_MAX_HEADER_SIZE = 8192; + class I2PTunnelConnection: public I2PServiceHandler, public std::enable_shared_from_this { public: From 63227ab2f163ab9710bc66d92c955a9015d22876 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Tue, 23 Aug 2022 22:19:23 +0300 Subject: [PATCH 132/219] fix log message Signed-off-by: R4SAS --- libi2pd/Streaming.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd/Streaming.cpp b/libi2pd/Streaming.cpp index af0a359f..72562675 100644 --- a/libi2pd/Streaming.cpp +++ b/libi2pd/Streaming.cpp @@ -729,7 +729,7 @@ namespace stream Terminate (); break; default: - LogPrint (eLogWarning, "Streaming: Unexpected stream status ", (int)m_Status, "sSID=", m_SendStreamID); + LogPrint (eLogWarning, "Streaming: Unexpected stream status=", (int)m_Status, " for sSID=", m_SendStreamID); }; } From c85bf82749a2a1947c8d44c0a9777b8554a0daea Mon Sep 17 00:00:00 2001 From: R4SAS Date: Wed, 24 Aug 2022 11:25:02 +0300 Subject: [PATCH 133/219] [i18n] pull Chinese translation update Signed-off-by: R4SAS --- i18n/Chinese.cpp | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/i18n/Chinese.cpp b/i18n/Chinese.cpp index b933df3d..8a55ab6a 100644 --- a/i18n/Chinese.cpp +++ b/i18n/Chinese.cpp @@ -91,7 +91,7 @@ namespace chinese // language namespace {"Address registration line", "地址域名注册"}, {"Domain", "域名"}, {"Generate", "生成"}, - {"Note: result string can be used only for registering 2LD domains (example.i2p). For registering subdomains please use i2pd-tools.", "注意: 结果字符串可以用于注册次级域名(例如:example.i2p)。若需注册次级域名,请使用 i2pd-tools。"}, + {"Note: result string can be used only for registering 2LD domains (example.i2p). For registering subdomains please use i2pd-tools.", "注意: 结果字符串只能用于注册次级域名(例如:example.i2p)。若需注册子域名,请使用 i2pd-tools。"}, {"Address", "地址"}, {"Type", "类型"}, {"EncType", "加密类型"}, @@ -120,18 +120,18 @@ namespace chinese // language namespace {"EndDate", "结束日期"}, {"not floodfill", "非洪泛"}, {"Queue size", "队列大小"}, - {"Run peer test", "运行群体测试"}, + {"Run peer test", "运行节点测试"}, {"Decline transit tunnels", "拒绝中转隧道"}, {"Accept transit tunnels", "允许中转隧道"}, - {"Cancel graceful shutdown", "取消离线"}, + {"Cancel graceful shutdown", "取消优雅地离线"}, {"Start graceful shutdown", "优雅地离线"}, {"Force shutdown", "强制停止"}, {"Reload external CSS styles", "重载外部 CSS 样式"}, {"Note: any action done here are not persistent and not changes your config files.", "注意: 此处完成的任何操作都不是永久的,不会更改您的配置文件。"}, - {"Logging level", "日志级别"}, + {"Logging level", "日志记录级别"}, {"Transit tunnels limit", "中转隧道限制"}, - {"Change", "更换"}, - {"Change language", "更换语言"}, + {"Change", "更改"}, + {"Change language", "更改语言"}, {"no transit tunnels currently built", "目前未构建中转隧道"}, {"SAM disabled", "SAM 已禁用"}, {"no sessions currently running", "没有正在运行的会话"}, @@ -141,7 +141,7 @@ namespace chinese // language namespace {"Client Forwards", "客户端转发"}, {"Server Forwards", "服务器转发"}, {"Unknown page", "未知页面"}, - {"Invalid token", "无效凭证"}, + {"Invalid token", "无效令牌"}, {"SUCCESS", "成功"}, {"Stream closed", "流已关闭"}, {"Stream not found or already was closed", "流未找到或已关闭"}, @@ -162,22 +162,22 @@ namespace chinese // language namespace {"Command accepted", "已接受指令"}, {"Proxy error", "代理错误"}, {"Proxy info", "代理信息"}, - {"Proxy error: Host not found", "代理错误:找不到主机"}, - {"Remote host not found in router's addressbook", "在路由的地址簿中找不到远程主机"}, - {"You may try to find this host on jump services below", "您可以尝试在下方的跳转服务上找到这个主机"}, + {"Proxy error: Host not found", "代理错误:未找到主机"}, + {"Remote host not found in router's addressbook", "在路由地址簿中未找到远程主机"}, + {"You may try to find this host on jump services below", "您可以尝试在下方的跳转服务中找到该主机"}, {"Invalid request", "无效请求"}, {"Proxy unable to parse your request", "代理无法解析您的请求"}, {"addresshelper is not supported", "不支持地址助手"}, {"Host", "主机"}, - {"added to router's addressbook from helper", "将此地址从地址助手添加到地址簿"}, + {"added to router's addressbook from helper", "将此地址从地址助手添加到路由地址簿"}, {"Click here to proceed:", "点击此处继续:"}, {"Continue", "继续"}, - {"Addresshelper found", "找到地址助手"}, - {"already in router's addressbook", "已在路由器的地址簿中"}, + {"Addresshelper found", "已找到地址助手"}, + {"already in router's addressbook", "已在路由地址簿中"}, {"Click here to update record:", "点击此处更新地址簿记录"}, {"invalid request uri", "无效的 URL 请求"}, {"Can't detect destination host from request", "无法从请求中检测到目标主机"}, - {"Outproxy failure", "出口代理失效"}, + {"Outproxy failure", "出口代理故障"}, {"bad outproxy settings", "错误的出口代理设置"}, {"not inside I2P network, but outproxy is not enabled", "该地址不在 I2P 网络内,但未启用出口代理"}, {"unknown outproxy url", "未知的出口代理地址"}, From 150c89e48a5a56e102f626e980bf7990625c9314 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 25 Aug 2022 15:14:45 -0400 Subject: [PATCH 134/219] don't request session if zero token received --- libi2pd/SSU2Session.cpp | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index da7a9434..df320d2b 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -1084,7 +1084,9 @@ namespace transport uint8_t nonce[12] = {0}; uint64_t headerX[2]; // sourceConnID, token i2p::crypto::ChaCha20 (buf + 16, 16, m_Address->i, nonce, (uint8_t *)headerX); - m_Server.UpdateOutgoingToken (m_RemoteEndpoint, headerX[1], i2p::util::GetSecondsSinceEpoch () + SSU2_TOKEN_EXPIRATION_TIMEOUT); + uint64_t token = headerX[1]; + if (token) + m_Server.UpdateOutgoingToken (m_RemoteEndpoint, token, i2p::util::GetSecondsSinceEpoch () + SSU2_TOKEN_EXPIRATION_TIMEOUT); // decrypt and handle payload uint8_t * payload = buf + 32; CreateNonce (be32toh (header.h.packetNum), nonce); @@ -1094,14 +1096,19 @@ namespace transport if (!i2p::crypto::AEADChaCha20Poly1305 (payload, len - 48, h, 32, m_Address->i, nonce, payload, len - 48, false)) { - LogPrint (eLogWarning, "SSU2: Retry AEAD verification failed "); + LogPrint (eLogWarning, "SSU2: Retry AEAD verification failed"); return false; } - HandlePayload (payload, len - 48); - m_State = eSSU2SessionStateTokenReceived; + HandlePayload (payload, len - 48); + if (!token) + { + // we should handle payload even for zero token to handle Datetime block and adjust clock in case of clock skew + LogPrint (eLogWarning, "SSU2: Retry token is zero"); + return false; + } InitNoiseXKState1 (*m_NoiseState, m_Address->s); // reset Noise TODO: check state - SendSessionRequest (headerX[1]); + SendSessionRequest (token); return true; } @@ -1446,6 +1453,7 @@ namespace transport m_TerminationReason = eSSU2TerminationReasonClockSkew; break; case eSSU2SessionStateSessionCreatedReceived: + case eSSU2SessionStateTokenReceived: if ((m_RemoteEndpoint.address ().is_v4 () && i2p::context.GetStatus () == eRouterStatusTesting) || (m_RemoteEndpoint.address ().is_v6 () && i2p::context.GetStatusV6 () == eRouterStatusTesting)) { From f98780b1d792035b707171b75c0505235f09fe01 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 25 Aug 2022 18:48:26 -0400 Subject: [PATCH 135/219] check timestamp for token request --- libi2pd/SSU2Session.cpp | 14 ++++++++++---- libi2pd/SSU2Session.h | 3 ++- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index df320d2b..e9c79b9f 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -1029,6 +1029,7 @@ namespace transport return; } // payload + m_State = eSSU2SessionStateTokenRequestReceived; HandlePayload (payload, len - 48); SendRetry (); } @@ -1037,7 +1038,7 @@ namespace transport { // we are Bob Header header; - uint8_t h[32], payload[64]; + uint8_t h[32], payload[72]; // fill packet header.h.connID = m_DestConnID; // dest id RAND_bytes (header.buf + 8, 4); // random packet num @@ -1047,15 +1048,19 @@ namespace transport header.h.flags[2] = 0; // flag memcpy (h, header.buf, 16); memcpy (h + 16, &m_SourceConnID, 8); // source id - uint64_t token = m_Server.GetIncomingToken (m_RemoteEndpoint); + uint64_t token = 0; + if (m_TerminationReason == eSSU2TerminationReasonNormalClose) + token = m_Server.GetIncomingToken (m_RemoteEndpoint); memcpy (h + 24, &token, 8); // token // payload payload[0] = eSSU2BlkDateTime; htobe16buf (payload + 1, 4); htobe32buf (payload + 3, i2p::util::GetSecondsSinceEpoch ()); size_t payloadSize = 7; - payloadSize += CreateAddressBlock (payload + payloadSize, 64 - payloadSize, m_RemoteEndpoint); - payloadSize += CreatePaddingBlock (payload + payloadSize, 64 - payloadSize); + payloadSize += CreateAddressBlock (payload + payloadSize, 56 - payloadSize, m_RemoteEndpoint); + if (m_TerminationReason != eSSU2TerminationReasonNormalClose) + payloadSize += CreateTerminationBlock (payload + payloadSize, 56 - payloadSize); + payloadSize += CreatePaddingBlock (payload + payloadSize, 56 - payloadSize); // encrypt uint8_t nonce[12]; CreateNonce (be32toh (header.h.packetNum), nonce); @@ -1449,6 +1454,7 @@ namespace transport switch (m_State) { case eSSU2SessionStateSessionRequestReceived: + case eSSU2SessionStateTokenRequestReceived: if (std::abs (offset) > SSU2_CLOCK_SKEW) m_TerminationReason = eSSU2TerminationReasonClockSkew; break; diff --git a/libi2pd/SSU2Session.h b/libi2pd/SSU2Session.h index 1730a939..7f8020f2 100644 --- a/libi2pd/SSU2Session.h +++ b/libi2pd/SSU2Session.h @@ -101,7 +101,8 @@ namespace transport eSSU2SessionStateFailed, eSSU2SessionStateIntroduced, eSSU2SessionStatePeerTest, - eSSU2SessionStatePeerTestReceived // 5 before 4 + eSSU2SessionStatePeerTestReceived, // 5 before 4 + eSSU2SessionStateTokenRequestReceived }; enum SSU2PeerTestCode From 95f19a5fb23e5a2e8c3c429c397b3ae6ae8f0039 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 26 Aug 2022 10:14:30 -0400 Subject: [PATCH 136/219] send Retry instead SessionCreated if clock skew --- libi2pd/SSU2Session.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index e9c79b9f..b66c44ef 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -616,8 +616,13 @@ namespace transport m_State = eSSU2SessionStateSessionRequestReceived; HandlePayload (decryptedPayload.data (), decryptedPayload.size ()); - m_Server.AddSession (shared_from_this ()); - SendSessionCreated (headerX + 16); + if (m_TerminationReason == eSSU2TerminationReasonNormalClose) + { + m_Server.AddSession (shared_from_this ()); + SendSessionCreated (headerX + 16); + } + else + SendRetry (); } void SSU2Session::SendSessionCreated (const uint8_t * X) @@ -666,8 +671,6 @@ namespace transport memcpy (payload + payloadSize + 7, &token.first, 8); // token payloadSize += 15; } - if (m_TerminationReason != eSSU2TerminationReasonNormalClose) - payloadSize += CreateTerminationBlock (payload + payloadSize, maxPayloadSize - payloadSize); payloadSize += CreatePaddingBlock (payload + payloadSize, maxPayloadSize - payloadSize); // KDF for SessionCreated m_NoiseState->MixHash ( { {header.buf, 16}, {headerX, 16} } ); // h = SHA256(h || header) @@ -687,9 +690,6 @@ namespace transport m_SentHandshakePacket->payloadSize = payloadSize; // send m_Server.Send (header.buf, 16, headerX, 48, payload, payloadSize, m_RemoteEndpoint); - // terminate if errors - if (m_TerminationReason != eSSU2TerminationReasonNormalClose) - Terminate (); } bool SSU2Session::ProcessSessionCreated (uint8_t * buf, size_t len) From b4d73683d12c7afe3c09e3c19a425adfb7771e31 Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 27 Aug 2022 22:18:30 -0400 Subject: [PATCH 137/219] spilt to I2PControl and I2PControlHandlers --- daemon/I2PControl.cpp | 190 +----------------------------- daemon/I2PControl.h | 16 +-- daemon/I2PControlHandlers.cpp | 211 ++++++++++++++++++++++++++++++++++ daemon/I2PControlHandlers.h | 50 ++++++++ 4 files changed, 265 insertions(+), 202 deletions(-) create mode 100644 daemon/I2PControlHandlers.cpp create mode 100644 daemon/I2PControlHandlers.h diff --git a/daemon/I2PControl.cpp b/daemon/I2PControl.cpp index 46a219bf..33aaf50d 100644 --- a/daemon/I2PControl.cpp +++ b/daemon/I2PControl.cpp @@ -72,7 +72,7 @@ namespace client m_MethodHandlers["RouterInfo"] = &I2PControlService::RouterInfoHandler; m_MethodHandlers["RouterManager"] = &I2PControlService::RouterManagerHandler; m_MethodHandlers["NetworkSetting"] = &I2PControlService::NetworkSettingHandler; - m_MethodHandlers["ClientServicesInfo"] = &I2PControlService::ClientServicesInfoHandler; + m_MethodHandlers["ClientServicesInfo"] = &I2PControlHandlers::ClientServicesInfoHandler; // I2PControl m_I2PControlHandlers["i2pcontrol.password"] = &I2PControlService::PasswordHandler; @@ -99,14 +99,6 @@ namespace client // NetworkSetting m_NetworkSettingHandlers["i2p.router.net.bw.in"] = &I2PControlService::InboundBandwidthLimit; m_NetworkSettingHandlers["i2p.router.net.bw.out"] = &I2PControlService::OutboundBandwidthLimit; - - // ClientServicesInfo - m_ClientServicesInfoHandlers["I2PTunnel"] = &I2PControlService::I2PTunnelInfoHandler; - m_ClientServicesInfoHandlers["HTTPProxy"] = &I2PControlService::HTTPProxyInfoHandler; - m_ClientServicesInfoHandlers["SOCKS"] = &I2PControlService::SOCKSInfoHandler; - m_ClientServicesInfoHandlers["SAM"] = &I2PControlService::SAMInfoHandler; - m_ClientServicesInfoHandlers["BOB"] = &I2PControlService::BOBInfoHandler; - m_ClientServicesInfoHandlers["I2CP"] = &I2PControlService::I2CPInfoHandler; } I2PControlService::~I2PControlService () @@ -304,13 +296,6 @@ namespace client ss << "\"" << name << "\":" << std::fixed << std::setprecision(2) << value; } - void I2PControlService::InsertParam (std::ostringstream& ss, const std::string& name, const boost::property_tree::ptree& value) const - { - std::ostringstream buf; - boost::property_tree::write_json (buf, value, false); - ss << "\"" << name << "\":" << buf.str(); - } - void I2PControlService::SendResponse (std::shared_ptr socket, std::shared_ptr buf, std::ostringstream& response, bool isHtml) { @@ -611,178 +596,5 @@ namespace client } EVP_PKEY_free (pkey); } - -// ClientServicesInfo - - void I2PControlService::ClientServicesInfoHandler (const boost::property_tree::ptree& params, std::ostringstream& results) - { - for (auto it = params.begin (); it != params.end (); it++) - { - LogPrint (eLogDebug, "I2PControl: ClientServicesInfo request: ", it->first); - auto it1 = m_ClientServicesInfoHandlers.find (it->first); - if (it1 != m_ClientServicesInfoHandlers.end ()) - { - if (it != params.begin ()) results << ","; - (this->*(it1->second))(results); - } - else - LogPrint (eLogError, "I2PControl: ClientServicesInfo unknown request ", it->first); - } - } - - void I2PControlService::I2PTunnelInfoHandler (std::ostringstream& results) - { - boost::property_tree::ptree pt; - boost::property_tree::ptree client_tunnels, server_tunnels; - - for (auto& it: i2p::client::context.GetClientTunnels ()) - { - auto& ident = it.second->GetLocalDestination ()->GetIdentHash(); - boost::property_tree::ptree ct; - ct.put("address", i2p::client::context.GetAddressBook ().ToAddress(ident)); - client_tunnels.add_child(it.second->GetName (), ct); - } - - auto& serverTunnels = i2p::client::context.GetServerTunnels (); - if (!serverTunnels.empty ()) { - for (auto& it: serverTunnels) - { - auto& ident = it.second->GetLocalDestination ()->GetIdentHash(); - boost::property_tree::ptree st; - st.put("address", i2p::client::context.GetAddressBook ().ToAddress(ident)); - st.put("port", it.second->GetLocalPort ()); - server_tunnels.add_child(it.second->GetName (), st); - } - } - - auto& clientForwards = i2p::client::context.GetClientForwards (); - if (!clientForwards.empty ()) - { - for (auto& it: clientForwards) - { - auto& ident = it.second->GetLocalDestination ()->GetIdentHash(); - boost::property_tree::ptree ct; - ct.put("address", i2p::client::context.GetAddressBook ().ToAddress(ident)); - client_tunnels.add_child(it.second->GetName (), ct); - } - } - - auto& serverForwards = i2p::client::context.GetServerForwards (); - if (!serverForwards.empty ()) - { - for (auto& it: serverForwards) - { - auto& ident = it.second->GetLocalDestination ()->GetIdentHash(); - boost::property_tree::ptree st; - st.put("address", i2p::client::context.GetAddressBook ().ToAddress(ident)); - server_tunnels.add_child(it.second->GetName (), st); - } - } - - pt.add_child("client", client_tunnels); - pt.add_child("server", server_tunnels); - - InsertParam (results, "I2PTunnel", pt); - } - - void I2PControlService::HTTPProxyInfoHandler (std::ostringstream& results) - { - boost::property_tree::ptree pt; - - auto httpProxy = i2p::client::context.GetHttpProxy (); - if (httpProxy) - { - auto& ident = httpProxy->GetLocalDestination ()->GetIdentHash(); - pt.put("enabled", true); - pt.put("address", i2p::client::context.GetAddressBook ().ToAddress(ident)); - } - else - pt.put("enabled", false); - - InsertParam (results, "HTTPProxy", pt); - } - - void I2PControlService::SOCKSInfoHandler (std::ostringstream& results) - { - boost::property_tree::ptree pt; - - auto socksProxy = i2p::client::context.GetSocksProxy (); - if (socksProxy) - { - auto& ident = socksProxy->GetLocalDestination ()->GetIdentHash(); - pt.put("enabled", true); - pt.put("address", i2p::client::context.GetAddressBook ().ToAddress(ident)); - } - else - pt.put("enabled", false); - - InsertParam (results, "SOCKS", pt); - } - - void I2PControlService::SAMInfoHandler (std::ostringstream& results) - { - boost::property_tree::ptree pt; - auto sam = i2p::client::context.GetSAMBridge (); - if (sam) - { - pt.put("enabled", true); - boost::property_tree::ptree sam_sessions; - for (auto& it: sam->GetSessions ()) - { - boost::property_tree::ptree sam_session, sam_session_sockets; - 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)); - - for (const auto& socket: sam->ListSockets(it.first)) - { - boost::property_tree::ptree stream; - stream.put("type", socket->GetSocketType ()); - stream.put("peer", socket->GetSocket ().remote_endpoint()); - - sam_session_sockets.push_back(std::make_pair("", stream)); - } - sam_session.add_child("sockets", sam_session_sockets); - sam_sessions.add_child(it.first, sam_session); - } - - pt.add_child("sessions", sam_sessions); - } - else - pt.put("enabled", false); - - InsertParam (results, "SAM", pt); - } - - void I2PControlService::BOBInfoHandler (std::ostringstream& results) - { - boost::property_tree::ptree pt; - auto bob = i2p::client::context.GetBOBCommandChannel (); - if (bob) - { - /* TODO more info */ - pt.put("enabled", true); - } - else - pt.put("enabled", false); - - InsertParam (results, "BOB", pt); - } - - void I2PControlService::I2CPInfoHandler (std::ostringstream& results) - { - boost::property_tree::ptree pt; - auto i2cp = i2p::client::context.GetI2CPServer (); - if (i2cp) - { - /* TODO more info */ - pt.put("enabled", true); - } - else - pt.put("enabled", false); - - InsertParam (results, "I2CP", pt); - } } } diff --git a/daemon/I2PControl.h b/daemon/I2PControl.h index 32b8933c..40973401 100644 --- a/daemon/I2PControl.h +++ b/daemon/I2PControl.h @@ -20,6 +20,7 @@ #include #include #include +#include "I2PControlHandlers.h" namespace i2p { @@ -32,7 +33,7 @@ namespace client const char I2P_CONTROL_CERTIFICATE_COMMON_NAME[] = "i2pd.i2pcontrol"; const char I2P_CONTROL_CERTIFICATE_ORGANIZATION[] = "Purple I2P"; - class I2PControlService + class I2PControlService: public I2PControlHandlers { typedef boost::asio::ssl::stream ssl_socket; @@ -66,8 +67,7 @@ namespace client void InsertParam (std::ostringstream& ss, const std::string& name, int value) const; void InsertParam (std::ostringstream& ss, const std::string& name, double value) const; void InsertParam (std::ostringstream& ss, const std::string& name, const std::string& value, bool quotes = true) const; - void InsertParam (std::ostringstream& ss, const std::string& name, const boost::property_tree::ptree& value) const; - + // methods typedef void (I2PControlService::*MethodHandler)(const boost::property_tree::ptree& params, std::ostringstream& results); @@ -109,15 +109,6 @@ namespace client void InboundBandwidthLimit (const std::string& value, std::ostringstream& results); void OutboundBandwidthLimit (const std::string& value, std::ostringstream& results); - // ClientServicesInfo - typedef void (I2PControlService::*ClientServicesInfoRequestHandler)(std::ostringstream& results); - void I2PTunnelInfoHandler (std::ostringstream& results); - void HTTPProxyInfoHandler (std::ostringstream& results); - void SOCKSInfoHandler (std::ostringstream& results); - void SAMInfoHandler (std::ostringstream& results); - void BOBInfoHandler (std::ostringstream& results); - void I2CPInfoHandler (std::ostringstream& results); - private: std::string m_Password; @@ -135,7 +126,6 @@ namespace client std::map m_RouterInfoHandlers; std::map m_RouterManagerHandlers; std::map m_NetworkSettingHandlers; - std::map m_ClientServicesInfoHandlers; }; } } diff --git a/daemon/I2PControlHandlers.cpp b/daemon/I2PControlHandlers.cpp new file mode 100644 index 00000000..8e2e3d16 --- /dev/null +++ b/daemon/I2PControlHandlers.cpp @@ -0,0 +1,211 @@ +/* +* Copyright (c) 2013-2022, The PurpleI2P Project +* +* This file is part of Purple i2pd project and licensed under BSD3 +* +* See full license text in LICENSE file at top of project tree +*/ + +#include +#include +#include +#include "Log.h" +#include "ClientContext.h" +#include "I2PControlHandlers.h" + +namespace i2p +{ +namespace client +{ + I2PControlHandlers::I2PControlHandlers () + { + // ClientServicesInfo + m_ClientServicesInfoHandlers["I2PTunnel"] = &I2PControlHandlers::I2PTunnelInfoHandler; + m_ClientServicesInfoHandlers["HTTPProxy"] = &I2PControlHandlers::HTTPProxyInfoHandler; + m_ClientServicesInfoHandlers["SOCKS"] = &I2PControlHandlers::SOCKSInfoHandler; + m_ClientServicesInfoHandlers["SAM"] = &I2PControlHandlers::SAMInfoHandler; + m_ClientServicesInfoHandlers["BOB"] = &I2PControlHandlers::BOBInfoHandler; + m_ClientServicesInfoHandlers["I2CP"] = &I2PControlHandlers::I2CPInfoHandler; + } + + void I2PControlHandlers::InsertParam (std::ostringstream& ss, const std::string& name, const boost::property_tree::ptree& value) const + { + std::ostringstream buf; + boost::property_tree::write_json (buf, value, false); + ss << "\"" << name << "\":" << buf.str(); + } + +// ClientServicesInfo + + void I2PControlHandlers::ClientServicesInfoHandler (const boost::property_tree::ptree& params, std::ostringstream& results) + { + for (auto it = params.begin (); it != params.end (); it++) + { + LogPrint (eLogDebug, "I2PControl: ClientServicesInfo request: ", it->first); + auto it1 = m_ClientServicesInfoHandlers.find (it->first); + if (it1 != m_ClientServicesInfoHandlers.end ()) + { + if (it != params.begin ()) results << ","; + (this->*(it1->second))(results); + } + else + LogPrint (eLogError, "I2PControl: ClientServicesInfo unknown request ", it->first); + } + } + + void I2PControlHandlers::I2PTunnelInfoHandler (std::ostringstream& results) + { + boost::property_tree::ptree pt; + boost::property_tree::ptree client_tunnels, server_tunnels; + + for (auto& it: i2p::client::context.GetClientTunnels ()) + { + auto& ident = it.second->GetLocalDestination ()->GetIdentHash(); + boost::property_tree::ptree ct; + ct.put("address", i2p::client::context.GetAddressBook ().ToAddress(ident)); + client_tunnels.add_child(it.second->GetName (), ct); + } + + auto& serverTunnels = i2p::client::context.GetServerTunnels (); + if (!serverTunnels.empty ()) { + for (auto& it: serverTunnels) + { + auto& ident = it.second->GetLocalDestination ()->GetIdentHash(); + boost::property_tree::ptree st; + st.put("address", i2p::client::context.GetAddressBook ().ToAddress(ident)); + st.put("port", it.second->GetLocalPort ()); + server_tunnels.add_child(it.second->GetName (), st); + } + } + + auto& clientForwards = i2p::client::context.GetClientForwards (); + if (!clientForwards.empty ()) + { + for (auto& it: clientForwards) + { + auto& ident = it.second->GetLocalDestination ()->GetIdentHash(); + boost::property_tree::ptree ct; + ct.put("address", i2p::client::context.GetAddressBook ().ToAddress(ident)); + client_tunnels.add_child(it.second->GetName (), ct); + } + } + + auto& serverForwards = i2p::client::context.GetServerForwards (); + if (!serverForwards.empty ()) + { + for (auto& it: serverForwards) + { + auto& ident = it.second->GetLocalDestination ()->GetIdentHash(); + boost::property_tree::ptree st; + st.put("address", i2p::client::context.GetAddressBook ().ToAddress(ident)); + server_tunnels.add_child(it.second->GetName (), st); + } + } + + pt.add_child("client", client_tunnels); + pt.add_child("server", server_tunnels); + + InsertParam (results, "I2PTunnel", pt); + } + + void I2PControlHandlers::HTTPProxyInfoHandler (std::ostringstream& results) + { + boost::property_tree::ptree pt; + + auto httpProxy = i2p::client::context.GetHttpProxy (); + if (httpProxy) + { + auto& ident = httpProxy->GetLocalDestination ()->GetIdentHash(); + pt.put("enabled", true); + pt.put("address", i2p::client::context.GetAddressBook ().ToAddress(ident)); + } + else + pt.put("enabled", false); + + InsertParam (results, "HTTPProxy", pt); + } + + void I2PControlHandlers::SOCKSInfoHandler (std::ostringstream& results) + { + boost::property_tree::ptree pt; + + auto socksProxy = i2p::client::context.GetSocksProxy (); + if (socksProxy) + { + auto& ident = socksProxy->GetLocalDestination ()->GetIdentHash(); + pt.put("enabled", true); + pt.put("address", i2p::client::context.GetAddressBook ().ToAddress(ident)); + } + else + pt.put("enabled", false); + + InsertParam (results, "SOCKS", pt); + } + + void I2PControlHandlers::SAMInfoHandler (std::ostringstream& results) + { + boost::property_tree::ptree pt; + auto sam = i2p::client::context.GetSAMBridge (); + if (sam) + { + pt.put("enabled", true); + boost::property_tree::ptree sam_sessions; + for (auto& it: sam->GetSessions ()) + { + boost::property_tree::ptree sam_session, sam_session_sockets; + 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)); + + for (const auto& socket: sam->ListSockets(it.first)) + { + boost::property_tree::ptree stream; + stream.put("type", socket->GetSocketType ()); + stream.put("peer", socket->GetSocket ().remote_endpoint()); + + sam_session_sockets.push_back(std::make_pair("", stream)); + } + sam_session.add_child("sockets", sam_session_sockets); + sam_sessions.add_child(it.first, sam_session); + } + + pt.add_child("sessions", sam_sessions); + } + else + pt.put("enabled", false); + + InsertParam (results, "SAM", pt); + } + + void I2PControlHandlers::BOBInfoHandler (std::ostringstream& results) + { + boost::property_tree::ptree pt; + auto bob = i2p::client::context.GetBOBCommandChannel (); + if (bob) + { + /* TODO more info */ + pt.put("enabled", true); + } + else + pt.put("enabled", false); + + InsertParam (results, "BOB", pt); + } + + void I2PControlHandlers::I2CPInfoHandler (std::ostringstream& results) + { + boost::property_tree::ptree pt; + auto i2cp = i2p::client::context.GetI2CPServer (); + if (i2cp) + { + /* TODO more info */ + pt.put("enabled", true); + } + else + pt.put("enabled", false); + + InsertParam (results, "I2CP", pt); + } +} +} diff --git a/daemon/I2PControlHandlers.h b/daemon/I2PControlHandlers.h new file mode 100644 index 00000000..41d969d5 --- /dev/null +++ b/daemon/I2PControlHandlers.h @@ -0,0 +1,50 @@ +/* +* Copyright (c) 2013-2022, The PurpleI2P Project +* +* This file is part of Purple i2pd project and licensed under BSD3 +* +* See full license text in LICENSE file at top of project tree +*/ + +#ifndef I2P_CONTROL_HANDLERS_H__ +#define I2P_CONTROL_HANDLERS_H__ + +#include +#include +#include +#include + +namespace i2p +{ +namespace client +{ + class I2PControlHandlers + { + public: + + I2PControlHandlers (); + + // TODO: make protected + void ClientServicesInfoHandler (const boost::property_tree::ptree& params, std::ostringstream& results); + + private: + + void InsertParam (std::ostringstream& ss, const std::string& name, const boost::property_tree::ptree& value) const; + + // ClientServicesInfo + typedef void (I2PControlHandlers::*ClientServicesInfoRequestHandler)(std::ostringstream& results); + void I2PTunnelInfoHandler (std::ostringstream& results); + void HTTPProxyInfoHandler (std::ostringstream& results); + void SOCKSInfoHandler (std::ostringstream& results); + void SAMInfoHandler (std::ostringstream& results); + void BOBInfoHandler (std::ostringstream& results); + void I2CPInfoHandler (std::ostringstream& results); + + private: + + std::map m_ClientServicesInfoHandlers; + }; +} +} + +#endif From d32475440afdf4ad91871457bfc8133ab9bd0201 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 28 Aug 2022 06:58:50 -0400 Subject: [PATCH 138/219] fixed cmake build --- build/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/build/CMakeLists.txt b/build/CMakeLists.txt index d35bd526..b73415ae 100644 --- a/build/CMakeLists.txt +++ b/build/CMakeLists.txt @@ -85,6 +85,7 @@ set(DAEMON_SRC "${DAEMON_SRC_DIR}/Daemon.cpp" "${DAEMON_SRC_DIR}/HTTPServer.cpp" "${DAEMON_SRC_DIR}/I2PControl.cpp" + "${DAEMON_SRC_DIR}/I2PControlHeaders.cpp" "${DAEMON_SRC_DIR}/i2pd.cpp" "${DAEMON_SRC_DIR}/UPnP.cpp" ) From 2470ba76f0e3a5210954c9f8edb81fef9f988ac0 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 28 Aug 2022 07:15:02 -0400 Subject: [PATCH 139/219] fixed cmake build --- build/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/CMakeLists.txt b/build/CMakeLists.txt index b73415ae..0c40d5a9 100644 --- a/build/CMakeLists.txt +++ b/build/CMakeLists.txt @@ -85,7 +85,7 @@ set(DAEMON_SRC "${DAEMON_SRC_DIR}/Daemon.cpp" "${DAEMON_SRC_DIR}/HTTPServer.cpp" "${DAEMON_SRC_DIR}/I2PControl.cpp" - "${DAEMON_SRC_DIR}/I2PControlHeaders.cpp" + "${DAEMON_SRC_DIR}/I2PControlHandlers.cpp" "${DAEMON_SRC_DIR}/i2pd.cpp" "${DAEMON_SRC_DIR}/UPnP.cpp" ) From 36eddd48c3ae997fae25721766bacf4e5b24a6b4 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 28 Aug 2022 15:46:16 -0400 Subject: [PATCH 140/219] move more handlers from I2PControl to I2PControlHandlers --- daemon/I2PControl.cpp | 174 +--------------------------------- daemon/I2PControl.h | 31 +----- daemon/I2PControlHandlers.cpp | 163 +++++++++++++++++++++++++++++++ daemon/I2PControlHandlers.h | 32 ++++++- 4 files changed, 199 insertions(+), 201 deletions(-) diff --git a/daemon/I2PControl.cpp b/daemon/I2PControl.cpp index 33aaf50d..da2443fd 100644 --- a/daemon/I2PControl.cpp +++ b/daemon/I2PControl.cpp @@ -14,25 +14,17 @@ // Use global placeholders from boost introduced when local_time.hpp is loaded #define BOOST_BIND_GLOBAL_PLACEHOLDERS -#include #include #include -#include #include +#include -#include "Crypto.h" #include "FS.h" #include "Log.h" #include "Config.h" #include "NetDb.hpp" -#include "RouterContext.h" -#include "Daemon.h" #include "Tunnel.h" -#include "Timestamp.h" -#include "Transports.h" -#include "version.h" -#include "util.h" -#include "ClientContext.h" +#include "Daemon.h" #include "I2PControl.h" namespace i2p @@ -69,36 +61,18 @@ namespace client m_MethodHandlers["Authenticate"] = &I2PControlService::AuthenticateHandler; m_MethodHandlers["Echo"] = &I2PControlService::EchoHandler; m_MethodHandlers["I2PControl"] = &I2PControlService::I2PControlHandler; - m_MethodHandlers["RouterInfo"] = &I2PControlService::RouterInfoHandler; + m_MethodHandlers["RouterInfo"] = &I2PControlHandlers::RouterInfoHandler; m_MethodHandlers["RouterManager"] = &I2PControlService::RouterManagerHandler; - m_MethodHandlers["NetworkSetting"] = &I2PControlService::NetworkSettingHandler; + m_MethodHandlers["NetworkSetting"] = &I2PControlHandlers::NetworkSettingHandler; m_MethodHandlers["ClientServicesInfo"] = &I2PControlHandlers::ClientServicesInfoHandler; // I2PControl m_I2PControlHandlers["i2pcontrol.password"] = &I2PControlService::PasswordHandler; - // RouterInfo - m_RouterInfoHandlers["i2p.router.uptime"] = &I2PControlService::UptimeHandler; - m_RouterInfoHandlers["i2p.router.version"] = &I2PControlService::VersionHandler; - m_RouterInfoHandlers["i2p.router.status"] = &I2PControlService::StatusHandler; - m_RouterInfoHandlers["i2p.router.netdb.knownpeers"] = &I2PControlService::NetDbKnownPeersHandler; - m_RouterInfoHandlers["i2p.router.netdb.activepeers"] = &I2PControlService::NetDbActivePeersHandler; - m_RouterInfoHandlers["i2p.router.net.bw.inbound.1s"] = &I2PControlService::InboundBandwidth1S; - m_RouterInfoHandlers["i2p.router.net.bw.outbound.1s"] = &I2PControlService::OutboundBandwidth1S; - m_RouterInfoHandlers["i2p.router.net.status"] = &I2PControlService::NetStatusHandler; - m_RouterInfoHandlers["i2p.router.net.tunnels.participating"] = &I2PControlService::TunnelsParticipatingHandler; - m_RouterInfoHandlers["i2p.router.net.tunnels.successrate"] = &I2PControlService::TunnelsSuccessRateHandler; - m_RouterInfoHandlers["i2p.router.net.total.received.bytes"] = &I2PControlService::NetTotalReceivedBytes; - m_RouterInfoHandlers["i2p.router.net.total.sent.bytes"] = &I2PControlService::NetTotalSentBytes; - // RouterManager m_RouterManagerHandlers["Reseed"] = &I2PControlService::ReseedHandler; m_RouterManagerHandlers["Shutdown"] = &I2PControlService::ShutdownHandler; m_RouterManagerHandlers["ShutdownGraceful"] = &I2PControlService::ShutdownGracefulHandler; - - // NetworkSetting - m_NetworkSettingHandlers["i2p.router.net.bw.in"] = &I2PControlService::InboundBandwidthLimit; - m_NetworkSettingHandlers["i2p.router.net.bw.out"] = &I2PControlService::OutboundBandwidthLimit; } I2PControlService::~I2PControlService () @@ -272,30 +246,6 @@ namespace client } } - void I2PControlService::InsertParam (std::ostringstream& ss, const std::string& name, int value) const - { - ss << "\"" << name << "\":" << value; - } - - void I2PControlService::InsertParam (std::ostringstream& ss, const std::string& name, const std::string& value, bool quotes) const - { - ss << "\"" << name << "\":"; - if (value.length () > 0) - { - if (quotes) - ss << "\"" << value << "\""; - else - ss << value; - } - else - ss << "null"; - } - - void I2PControlService::InsertParam (std::ostringstream& ss, const std::string& name, double value) const - { - ss << "\"" << name << "\":" << std::fixed << std::setprecision(2) << value; - } - void I2PControlService::SendResponse (std::shared_ptr socket, std::shared_ptr buf, std::ostringstream& response, bool isHtml) { @@ -381,91 +331,6 @@ namespace client m_Tokens.clear (); } -// RouterInfo - - void I2PControlService::RouterInfoHandler (const boost::property_tree::ptree& params, std::ostringstream& results) - { - bool first = true; - for (auto it = params.begin (); it != params.end (); it++) - { - LogPrint (eLogDebug, "I2PControl: RouterInfo request: ", it->first); - auto it1 = m_RouterInfoHandlers.find (it->first); - if (it1 != m_RouterInfoHandlers.end ()) - { - if (!first) results << ","; - else first = false; - (this->*(it1->second))(results); - } - else - LogPrint (eLogError, "I2PControl: RouterInfo unknown request ", it->first); - } - } - - void I2PControlService::UptimeHandler (std::ostringstream& results) - { - InsertParam (results, "i2p.router.uptime", std::to_string (i2p::context.GetUptime ()*1000LL), false); - } - - void I2PControlService::VersionHandler (std::ostringstream& results) - { - InsertParam (results, "i2p.router.version", VERSION); - } - - void I2PControlService::StatusHandler (std::ostringstream& results) - { - auto dest = i2p::client::context.GetSharedLocalDestination (); - InsertParam (results, "i2p.router.status", (dest && dest->IsReady ()) ? "1" : "0"); - } - - void I2PControlService::NetDbKnownPeersHandler (std::ostringstream& results) - { - InsertParam (results, "i2p.router.netdb.knownpeers", i2p::data::netdb.GetNumRouters ()); - } - - void I2PControlService::NetDbActivePeersHandler (std::ostringstream& results) - { - InsertParam (results, "i2p.router.netdb.activepeers", (int)i2p::transport::transports.GetPeers ().size ()); - } - - void I2PControlService::NetStatusHandler (std::ostringstream& results) - { - InsertParam (results, "i2p.router.net.status", (int)i2p::context.GetStatus ()); - } - - void I2PControlService::TunnelsParticipatingHandler (std::ostringstream& results) - { - int transit = i2p::tunnel::tunnels.GetTransitTunnels ().size (); - InsertParam (results, "i2p.router.net.tunnels.participating", transit); - } - - void I2PControlService::TunnelsSuccessRateHandler (std::ostringstream& results) - { - int rate = i2p::tunnel::tunnels.GetTunnelCreationSuccessRate (); - InsertParam (results, "i2p.router.net.tunnels.successrate", rate); - } - - void I2PControlService::InboundBandwidth1S (std::ostringstream& results) - { - double bw = i2p::transport::transports.GetInBandwidth (); - InsertParam (results, "i2p.router.net.bw.inbound.1s", bw); - } - - void I2PControlService::OutboundBandwidth1S (std::ostringstream& results) - { - double bw = i2p::transport::transports.GetOutBandwidth (); - InsertParam (results, "i2p.router.net.bw.outbound.1s", bw); - } - - void I2PControlService::NetTotalReceivedBytes (std::ostringstream& results) - { - InsertParam (results, "i2p.router.net.total.received.bytes", (double)i2p::transport::transports.GetTotalReceivedBytes ()); - } - - void I2PControlService::NetTotalSentBytes (std::ostringstream& results) - { - InsertParam (results, "i2p.router.net.total.sent.bytes", (double)i2p::transport::transports.GetTotalSentBytes ()); - } - // RouterManager @@ -517,37 +382,6 @@ namespace client i2p::data::netdb.Reseed (); } -// network setting - void I2PControlService::NetworkSettingHandler (const boost::property_tree::ptree& params, std::ostringstream& results) - { - for (auto it = params.begin (); it != params.end (); it++) - { - LogPrint (eLogDebug, "I2PControl: NetworkSetting request: ", it->first); - auto it1 = m_NetworkSettingHandlers.find (it->first); - if (it1 != m_NetworkSettingHandlers.end ()) { - if (it != params.begin ()) results << ","; - (this->*(it1->second))(it->second.data (), results); - } else - LogPrint (eLogError, "I2PControl: NetworkSetting unknown request: ", it->first); - } - } - - void I2PControlService::InboundBandwidthLimit (const std::string& value, std::ostringstream& results) - { - if (value != "null") - i2p::context.SetBandwidth (std::atoi(value.c_str())); - int bw = i2p::context.GetBandwidthLimit(); - InsertParam (results, "i2p.router.net.bw.in", bw); - } - - void I2PControlService::OutboundBandwidthLimit (const std::string& value, std::ostringstream& results) - { - if (value != "null") - i2p::context.SetBandwidth (std::atoi(value.c_str())); - int bw = i2p::context.GetBandwidthLimit(); - InsertParam (results, "i2p.router.net.bw.out", bw); - } - // certificate void I2PControlService::CreateCertificate (const char *crt_path, const char *key_path) { diff --git a/daemon/I2PControl.h b/daemon/I2PControl.h index 40973401..9a80da9a 100644 --- a/daemon/I2PControl.h +++ b/daemon/I2PControl.h @@ -63,10 +63,6 @@ namespace client void CreateCertificate (const char *crt_path, const char *key_path); private: - - void InsertParam (std::ostringstream& ss, const std::string& name, int value) const; - void InsertParam (std::ostringstream& ss, const std::string& name, double value) const; - void InsertParam (std::ostringstream& ss, const std::string& name, const std::string& value, bool quotes = true) const; // methods typedef void (I2PControlService::*MethodHandler)(const boost::property_tree::ptree& params, std::ostringstream& results); @@ -74,41 +70,18 @@ namespace client void AuthenticateHandler (const boost::property_tree::ptree& params, std::ostringstream& results); void EchoHandler (const boost::property_tree::ptree& params, std::ostringstream& results); void I2PControlHandler (const boost::property_tree::ptree& params, std::ostringstream& results); - void RouterInfoHandler (const boost::property_tree::ptree& params, std::ostringstream& results); void RouterManagerHandler (const boost::property_tree::ptree& params, std::ostringstream& results); - void NetworkSettingHandler (const boost::property_tree::ptree& params, std::ostringstream& results); - void ClientServicesInfoHandler (const boost::property_tree::ptree& params, std::ostringstream& results); - + // I2PControl typedef void (I2PControlService::*I2PControlRequestHandler)(const std::string& value); void PasswordHandler (const std::string& value); - // RouterInfo - typedef void (I2PControlService::*RouterInfoRequestHandler)(std::ostringstream& results); - void UptimeHandler (std::ostringstream& results); - void VersionHandler (std::ostringstream& results); - void StatusHandler (std::ostringstream& results); - void NetDbKnownPeersHandler (std::ostringstream& results); - void NetDbActivePeersHandler (std::ostringstream& results); - void NetStatusHandler (std::ostringstream& results); - void TunnelsParticipatingHandler (std::ostringstream& results); - void TunnelsSuccessRateHandler (std::ostringstream& results); - void InboundBandwidth1S (std::ostringstream& results); - void OutboundBandwidth1S (std::ostringstream& results); - void NetTotalReceivedBytes (std::ostringstream& results); - void NetTotalSentBytes (std::ostringstream& results); - // RouterManager typedef void (I2PControlService::*RouterManagerRequestHandler)(std::ostringstream& results); void ShutdownHandler (std::ostringstream& results); void ShutdownGracefulHandler (std::ostringstream& results); void ReseedHandler (std::ostringstream& results); - // NetworkSetting - typedef void (I2PControlService::*NetworkSettingRequestHandler)(const std::string& value, std::ostringstream& results); - void InboundBandwidthLimit (const std::string& value, std::ostringstream& results); - void OutboundBandwidthLimit (const std::string& value, std::ostringstream& results); - private: std::string m_Password; @@ -123,9 +96,7 @@ namespace client std::map m_MethodHandlers; std::map m_I2PControlHandlers; - std::map m_RouterInfoHandlers; std::map m_RouterManagerHandlers; - std::map m_NetworkSettingHandlers; }; } } diff --git a/daemon/I2PControlHandlers.cpp b/daemon/I2PControlHandlers.cpp index 8e2e3d16..067c7ddd 100644 --- a/daemon/I2PControlHandlers.cpp +++ b/daemon/I2PControlHandlers.cpp @@ -10,6 +10,11 @@ #include #include #include "Log.h" +#include "RouterContext.h" +#include "NetDb.hpp" +#include "Tunnel.h" +#include "Transports.h" +#include "version.h" #include "ClientContext.h" #include "I2PControlHandlers.h" @@ -19,6 +24,24 @@ namespace client { I2PControlHandlers::I2PControlHandlers () { + // RouterInfo + m_RouterInfoHandlers["i2p.router.uptime"] = &I2PControlHandlers::UptimeHandler; + m_RouterInfoHandlers["i2p.router.version"] = &I2PControlHandlers::VersionHandler; + m_RouterInfoHandlers["i2p.router.status"] = &I2PControlHandlers::StatusHandler; + m_RouterInfoHandlers["i2p.router.netdb.knownpeers"] = &I2PControlHandlers::NetDbKnownPeersHandler; + m_RouterInfoHandlers["i2p.router.netdb.activepeers"] = &I2PControlHandlers::NetDbActivePeersHandler; + m_RouterInfoHandlers["i2p.router.net.bw.inbound.1s"] = &I2PControlHandlers::InboundBandwidth1S; + m_RouterInfoHandlers["i2p.router.net.bw.outbound.1s"] = &I2PControlHandlers::OutboundBandwidth1S; + m_RouterInfoHandlers["i2p.router.net.status"] = &I2PControlHandlers::NetStatusHandler; + m_RouterInfoHandlers["i2p.router.net.tunnels.participating"] = &I2PControlHandlers::TunnelsParticipatingHandler; + m_RouterInfoHandlers["i2p.router.net.tunnels.successrate"] = &I2PControlHandlers::TunnelsSuccessRateHandler; + m_RouterInfoHandlers["i2p.router.net.total.received.bytes"] = &I2PControlHandlers::NetTotalReceivedBytes; + m_RouterInfoHandlers["i2p.router.net.total.sent.bytes"] = &I2PControlHandlers::NetTotalSentBytes; + + // NetworkSetting + m_NetworkSettingHandlers["i2p.router.net.bw.in"] = &I2PControlHandlers::InboundBandwidthLimit; + m_NetworkSettingHandlers["i2p.router.net.bw.out"] = &I2PControlHandlers::OutboundBandwidthLimit; + // ClientServicesInfo m_ClientServicesInfoHandlers["I2PTunnel"] = &I2PControlHandlers::I2PTunnelInfoHandler; m_ClientServicesInfoHandlers["HTTPProxy"] = &I2PControlHandlers::HTTPProxyInfoHandler; @@ -28,6 +51,30 @@ namespace client m_ClientServicesInfoHandlers["I2CP"] = &I2PControlHandlers::I2CPInfoHandler; } + void I2PControlHandlers::InsertParam (std::ostringstream& ss, const std::string& name, int value) const + { + ss << "\"" << name << "\":" << value; + } + + void I2PControlHandlers::InsertParam (std::ostringstream& ss, const std::string& name, const std::string& value, bool quotes) const + { + ss << "\"" << name << "\":"; + if (value.length () > 0) + { + if (quotes) + ss << "\"" << value << "\""; + else + ss << value; + } + else + ss << "null"; + } + + void I2PControlHandlers::InsertParam (std::ostringstream& ss, const std::string& name, double value) const + { + ss << "\"" << name << "\":" << std::fixed << std::setprecision(2) << value; + } + void I2PControlHandlers::InsertParam (std::ostringstream& ss, const std::string& name, const boost::property_tree::ptree& value) const { std::ostringstream buf; @@ -35,6 +82,122 @@ namespace client ss << "\"" << name << "\":" << buf.str(); } +// RouterInfo + + void I2PControlHandlers::RouterInfoHandler (const boost::property_tree::ptree& params, std::ostringstream& results) + { + bool first = true; + for (auto it = params.begin (); it != params.end (); it++) + { + LogPrint (eLogDebug, "I2PControl: RouterInfo request: ", it->first); + auto it1 = m_RouterInfoHandlers.find (it->first); + if (it1 != m_RouterInfoHandlers.end ()) + { + if (!first) results << ","; + else first = false; + (this->*(it1->second))(results); + } + else + LogPrint (eLogError, "I2PControl: RouterInfo unknown request ", it->first); + } + } + + void I2PControlHandlers::UptimeHandler (std::ostringstream& results) + { + InsertParam (results, "i2p.router.uptime", std::to_string (i2p::context.GetUptime ()*1000LL), false); + } + + void I2PControlHandlers::VersionHandler (std::ostringstream& results) + { + InsertParam (results, "i2p.router.version", VERSION); + } + + void I2PControlHandlers::StatusHandler (std::ostringstream& results) + { + auto dest = i2p::client::context.GetSharedLocalDestination (); + InsertParam (results, "i2p.router.status", (dest && dest->IsReady ()) ? "1" : "0"); + } + + void I2PControlHandlers::NetDbKnownPeersHandler (std::ostringstream& results) + { + InsertParam (results, "i2p.router.netdb.knownpeers", i2p::data::netdb.GetNumRouters ()); + } + + void I2PControlHandlers::NetDbActivePeersHandler (std::ostringstream& results) + { + InsertParam (results, "i2p.router.netdb.activepeers", (int)i2p::transport::transports.GetPeers ().size ()); + } + + void I2PControlHandlers::NetStatusHandler (std::ostringstream& results) + { + InsertParam (results, "i2p.router.net.status", (int)i2p::context.GetStatus ()); + } + + void I2PControlHandlers::TunnelsParticipatingHandler (std::ostringstream& results) + { + int transit = i2p::tunnel::tunnels.GetTransitTunnels ().size (); + InsertParam (results, "i2p.router.net.tunnels.participating", transit); + } + + void I2PControlHandlers::TunnelsSuccessRateHandler (std::ostringstream& results) + { + int rate = i2p::tunnel::tunnels.GetTunnelCreationSuccessRate (); + InsertParam (results, "i2p.router.net.tunnels.successrate", rate); + } + + void I2PControlHandlers::InboundBandwidth1S (std::ostringstream& results) + { + double bw = i2p::transport::transports.GetInBandwidth (); + InsertParam (results, "i2p.router.net.bw.inbound.1s", bw); + } + + void I2PControlHandlers::OutboundBandwidth1S (std::ostringstream& results) + { + double bw = i2p::transport::transports.GetOutBandwidth (); + InsertParam (results, "i2p.router.net.bw.outbound.1s", bw); + } + + void I2PControlHandlers::NetTotalReceivedBytes (std::ostringstream& results) + { + InsertParam (results, "i2p.router.net.total.received.bytes", (double)i2p::transport::transports.GetTotalReceivedBytes ()); + } + + void I2PControlHandlers::NetTotalSentBytes (std::ostringstream& results) + { + InsertParam (results, "i2p.router.net.total.sent.bytes", (double)i2p::transport::transports.GetTotalSentBytes ()); + } + +// network setting + void I2PControlHandlers::NetworkSettingHandler (const boost::property_tree::ptree& params, std::ostringstream& results) + { + for (auto it = params.begin (); it != params.end (); it++) + { + LogPrint (eLogDebug, "I2PControl: NetworkSetting request: ", it->first); + auto it1 = m_NetworkSettingHandlers.find (it->first); + if (it1 != m_NetworkSettingHandlers.end ()) { + if (it != params.begin ()) results << ","; + (this->*(it1->second))(it->second.data (), results); + } else + LogPrint (eLogError, "I2PControl: NetworkSetting unknown request: ", it->first); + } + } + + void I2PControlHandlers::InboundBandwidthLimit (const std::string& value, std::ostringstream& results) + { + if (value != "null") + i2p::context.SetBandwidth (std::atoi(value.c_str())); + int bw = i2p::context.GetBandwidthLimit(); + InsertParam (results, "i2p.router.net.bw.in", bw); + } + + void I2PControlHandlers::OutboundBandwidthLimit (const std::string& value, std::ostringstream& results) + { + if (value != "null") + i2p::context.SetBandwidth (std::atoi(value.c_str())); + int bw = i2p::context.GetBandwidthLimit(); + InsertParam (results, "i2p.router.net.bw.out", bw); + } + // ClientServicesInfo void I2PControlHandlers::ClientServicesInfoHandler (const boost::property_tree::ptree& params, std::ostringstream& results) diff --git a/daemon/I2PControlHandlers.h b/daemon/I2PControlHandlers.h index 41d969d5..32adce8b 100644 --- a/daemon/I2PControlHandlers.h +++ b/daemon/I2PControlHandlers.h @@ -24,12 +24,40 @@ namespace client I2PControlHandlers (); + // methods // TODO: make protected + void RouterInfoHandler (const boost::property_tree::ptree& params, std::ostringstream& results); + void NetworkSettingHandler (const boost::property_tree::ptree& params, std::ostringstream& results); void ClientServicesInfoHandler (const boost::property_tree::ptree& params, std::ostringstream& results); + protected: + + void InsertParam (std::ostringstream& ss, const std::string& name, int value) const; + void InsertParam (std::ostringstream& ss, const std::string& name, double value) const; + void InsertParam (std::ostringstream& ss, const std::string& name, const std::string& value, bool quotes = true) const; + void InsertParam (std::ostringstream& ss, const std::string& name, const boost::property_tree::ptree& value) const; + private: - void InsertParam (std::ostringstream& ss, const std::string& name, const boost::property_tree::ptree& value) const; + // RouterInfo + typedef void (I2PControlHandlers::*RouterInfoRequestHandler)(std::ostringstream& results); + void UptimeHandler (std::ostringstream& results); + void VersionHandler (std::ostringstream& results); + void StatusHandler (std::ostringstream& results); + void NetDbKnownPeersHandler (std::ostringstream& results); + void NetDbActivePeersHandler (std::ostringstream& results); + void NetStatusHandler (std::ostringstream& results); + void TunnelsParticipatingHandler (std::ostringstream& results); + void TunnelsSuccessRateHandler (std::ostringstream& results); + void InboundBandwidth1S (std::ostringstream& results); + void OutboundBandwidth1S (std::ostringstream& results); + void NetTotalReceivedBytes (std::ostringstream& results); + void NetTotalSentBytes (std::ostringstream& results); + + // NetworkSetting + typedef void (I2PControlHandlers::*NetworkSettingRequestHandler)(const std::string& value, std::ostringstream& results); + void InboundBandwidthLimit (const std::string& value, std::ostringstream& results); + void OutboundBandwidthLimit (const std::string& value, std::ostringstream& results); // ClientServicesInfo typedef void (I2PControlHandlers::*ClientServicesInfoRequestHandler)(std::ostringstream& results); @@ -42,6 +70,8 @@ namespace client private: + std::map m_RouterInfoHandlers; + std::map m_NetworkSettingHandlers; std::map m_ClientServicesInfoHandlers; }; } From 8fd466c5a9f00c0e92a928c1fae8190d2f78296b Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 29 Aug 2022 21:11:17 -0400 Subject: [PATCH 141/219] separate network status and errors --- daemon/HTTPServer.cpp | 35 +++++++++++++++++------------------ libi2pd/RouterContext.h | 11 +++++------ libi2pd/SSU2Session.cpp | 8 ++++---- libi2pd/SSUSession.cpp | 4 ++-- 4 files changed, 28 insertions(+), 30 deletions(-) diff --git a/daemon/HTTPServer.cpp b/daemon/HTTPServer.cpp index d236ca3d..071627e2 100644 --- a/daemon/HTTPServer.cpp +++ b/daemon/HTTPServer.cpp @@ -232,26 +232,25 @@ namespace http { case eRouterStatusUnknown: s << tr("Unknown"); break; case eRouterStatusProxy: s << tr("Proxy"); break; case eRouterStatusMesh: s << tr("Mesh"); break; - case eRouterStatusError: - { - s << tr("Error"); - switch (error) - { - case eRouterErrorClockSkew: - s << " - " << tr("Clock skew"); - break; - case eRouterErrorOffline: - s << " - " << tr("Offline"); - break; - case eRouterErrorSymmetricNAT: - s << " - " << tr("Symmetric NAT"); - break; - default: ; - } - break; - } default: s << tr("Unknown"); } + if (error != eRouterErrorNone) + { + s << "
"; + switch (error) + { + case eRouterErrorClockSkew: + s << " - " << tr("Clock skew"); + break; + case eRouterErrorOffline: + s << " - " << tr("Offline"); + break; + case eRouterErrorSymmetricNAT: + s << " - " << tr("Symmetric NAT"); + break; + default: ; + } + } } void ShowStatus (std::stringstream& s, bool includeHiddenContent, i2p::http::OutputFormatEnum outputFormat) diff --git a/libi2pd/RouterContext.h b/libi2pd/RouterContext.h index b6d3e7f0..cf394162 100644 --- a/libi2pd/RouterContext.h +++ b/libi2pd/RouterContext.h @@ -37,10 +37,9 @@ namespace garlic eRouterStatusOK = 0, eRouterStatusTesting = 1, eRouterStatusFirewalled = 2, - eRouterStatusError = 3, - eRouterStatusUnknown = 4, - eRouterStatusProxy = 5, - eRouterStatusMesh = 6 + eRouterStatusUnknown = 3, + eRouterStatusProxy = 4, + eRouterStatusMesh = 5 }; enum RouterError @@ -105,12 +104,12 @@ namespace garlic void SetStatus (RouterStatus status); void SetStatusSSU2 (RouterStatus status); RouterError GetError () const { return m_Error; }; - void SetError (RouterError error) { m_Status = eRouterStatusError; m_Error = error; }; + void SetError (RouterError error) { m_Error = error; }; RouterStatus GetStatusV6 () const { return m_StatusV6; }; void SetStatusV6 (RouterStatus status); void SetStatusV6SSU2 (RouterStatus status); RouterError GetErrorV6 () const { return m_ErrorV6; }; - void SetErrorV6 (RouterError error) { m_StatusV6 = eRouterStatusError; m_ErrorV6 = error; }; + void SetErrorV6 (RouterError error) { m_ErrorV6 = error; }; int GetNetID () const { return m_NetID; }; void SetNetID (int netID) { m_NetID = netID; }; bool DecryptTunnelBuildRecord (const uint8_t * encrypted, uint8_t * data); diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index b66c44ef..8a642384 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -1571,13 +1571,13 @@ namespace transport { if (isV4) { - if (i2p::context.GetStatus () == eRouterStatusError && i2p::context.GetError () == eRouterErrorSymmetricNAT) - i2p::context.SetStatus (eRouterStatusTesting); + if (i2p::context.GetError () == eRouterErrorSymmetricNAT) + i2p::context.SetError (eRouterErrorNone); } else { - if (i2p::context.GetStatusV6 () == eRouterStatusError && i2p::context.GetErrorV6 () == eRouterErrorSymmetricNAT) - i2p::context.SetStatusV6 (eRouterStatusTesting); + if (i2p::context.GetErrorV6 () == eRouterErrorSymmetricNAT) + i2p::context.SetErrorV6 (eRouterErrorNone); } } } diff --git a/libi2pd/SSUSession.cpp b/libi2pd/SSUSession.cpp index 76b6486b..73f9cdb1 100644 --- a/libi2pd/SSUSession.cpp +++ b/libi2pd/SSUSession.cpp @@ -719,8 +719,8 @@ namespace transport if (i2p::context.GetStatus () == eRouterStatusTesting) i2p::context.SetError (eRouterErrorSymmetricNAT); } - else if (i2p::context.GetStatus () == eRouterStatusError && i2p::context.GetError () == eRouterErrorSymmetricNAT) - i2p::context.SetStatus (eRouterStatusTesting); + else if (i2p::context.GetError () == eRouterErrorSymmetricNAT) + i2p::context.SetError (eRouterErrorNone); } uint32_t nonce = bufbe32toh (buf); buf += 4; // nonce From f37811988923978d45a5f3de692c270d083b591a Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 29 Aug 2022 21:27:02 -0400 Subject: [PATCH 142/219] 5 SSU2 peer tests if no SSU --- libi2pd/Transports.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/libi2pd/Transports.cpp b/libi2pd/Transports.cpp index b37ef7b2..e80972b8 100644 --- a/libi2pd/Transports.cpp +++ b/libi2pd/Transports.cpp @@ -665,7 +665,8 @@ namespace transport { excluded.clear (); excluded.insert (i2p::context.GetIdentHash ()); - for (int i = 0; i < 3; i++) + int numTests = m_SSUServer ? 3 : 5; + for (int i = 0; i < numTests; i++) { auto router = i2p::data::netdb.GetRandomSSU2PeerTestRouter (true, excluded); // v4 if (router) @@ -713,7 +714,8 @@ namespace transport { excluded.clear (); excluded.insert (i2p::context.GetIdentHash ()); - for (int i = 0; i < 3; i++) + int numTests = m_SSUServer ? 3 : 5; + for (int i = 0; i < numTests; i++) { auto router = i2p::data::netdb.GetRandomSSU2PeerTestRouter (false, excluded); // v6 if (router) From f32b288785606671c6e25a65fdb2487506c284ac Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 29 Aug 2022 21:58:19 -0400 Subject: [PATCH 143/219] print error on separate line for windows --- Win32/Win32App.cpp | 39 +++++++++++++++++++-------------------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/Win32/Win32App.cpp b/Win32/Win32App.cpp index 377e1076..a625b7e2 100644 --- a/Win32/Win32App.cpp +++ b/Win32/Win32App.cpp @@ -1,5 +1,5 @@ /* -* Copyright (c) 2013-2020, The PurpleI2P Project +* Copyright (c) 2013-2022, The PurpleI2P Project * * This file is part of Purple i2pd project and licensed under BSD3 * @@ -154,26 +154,25 @@ namespace win32 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"; - } + }; + if (i2p::context.GetError () != eRouterErrorNone) + { + s << "\n Error"; + switch (i2p::context.GetError ()) + { + case eRouterErrorClockSkew: + s << " - Clock skew"; + break; + case eRouterErrorOffline: + s << " - Offline"; + break; + case eRouterErrorSymmetricNAT: + s << " - Symmetric NAT"; + break; + default: ; + } + } } static void PrintMainWindowText (std::stringstream& s) From 9b5a885b3b82bbf0e32d499eb430d6bc313a4a41 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 30 Aug 2022 08:48:28 -0400 Subject: [PATCH 144/219] check if I2NP message to send is not null --- libi2pd/SSU2Session.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index 8a642384..87181da6 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -310,6 +310,11 @@ namespace transport while (!m_SendQueue.empty () && m_SentPackets.size () <= m_WindowSize) { auto msg = m_SendQueue.front (); + if (!msg) + { + m_SendQueue.pop_front (); + continue; + } size_t len = msg->GetNTCP2Length () + 3; if (len > m_MaxPayloadSize) // message too long { @@ -376,6 +381,7 @@ namespace transport bool SSU2Session::SendFragmentedMessage (std::shared_ptr msg) { + if (!msg) return false; size_t lastFragmentSize = (msg->GetNTCP2Length () + 3 - m_MaxPayloadSize) % (m_MaxPayloadSize - 8); size_t extraSize = m_MaxPayloadSize - lastFragmentSize; bool ackBlockSent = false; From 9df757a3fdaba8a84be9a3059ba95e427c71b0fa Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 30 Aug 2022 13:10:26 -0400 Subject: [PATCH 145/219] fixed warning --- daemon/I2PControlHandlers.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/daemon/I2PControlHandlers.cpp b/daemon/I2PControlHandlers.cpp index 067c7ddd..02508f29 100644 --- a/daemon/I2PControlHandlers.cpp +++ b/daemon/I2PControlHandlers.cpp @@ -7,8 +7,10 @@ */ #include +#define BOOST_BIND_GLOBAL_PLACEHOLDERS #include #include + #include "Log.h" #include "RouterContext.h" #include "NetDb.hpp" From c54fc7ee447c7fdfa468bb1817b4b239bd33cc79 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Tue, 30 Aug 2022 20:45:35 +0300 Subject: [PATCH 146/219] [win32] remove reworked error status Signed-off-by: R4SAS --- Win32/Win32App.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Win32/Win32App.cpp b/Win32/Win32App.cpp index a625b7e2..37458046 100644 --- a/Win32/Win32App.cpp +++ b/Win32/Win32App.cpp @@ -158,7 +158,6 @@ namespace win32 }; if (i2p::context.GetError () != eRouterErrorNone) { - s << "\n Error"; switch (i2p::context.GetError ()) { case eRouterErrorClockSkew: @@ -172,7 +171,7 @@ namespace win32 break; default: ; } - } + } } static void PrintMainWindowText (std::stringstream& s) From 9abc4cf359e27ef1799e167c948e46a3b7a345d0 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 30 Aug 2022 15:18:31 -0400 Subject: [PATCH 147/219] fixed crash at startup if addressbook is disbaled --- libi2pd_client/AddressBook.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libi2pd_client/AddressBook.cpp b/libi2pd_client/AddressBook.cpp index e67e3f06..7928792f 100644 --- a/libi2pd_client/AddressBook.cpp +++ b/libi2pd_client/AddressBook.cpp @@ -567,6 +567,7 @@ namespace client void AddressBook::LoadLocal () { + if (!m_Storage) return; std::map> localAddresses; m_Storage->LoadLocal (localAddresses); for (const auto& it: localAddresses) From f4e230f1adab07a0ec8ab8a3b1da1f10a4ac11d1 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Tue, 30 Aug 2022 23:59:26 +0300 Subject: [PATCH 148/219] [i18n] add Italian translation, update Chinese Thanks for italian translation to Albano Battistella and Fabio Roman Signed-off-by: R4SAS --- contrib/i18n/README.md | 2 +- i18n/Chinese.cpp | 8 +- i18n/I18N_langs.h | 2 + i18n/Italian.cpp | 216 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 223 insertions(+), 5 deletions(-) create mode 100644 i18n/Italian.cpp diff --git a/contrib/i18n/README.md b/contrib/i18n/README.md index 4efc26d0..57021f60 100644 --- a/contrib/i18n/README.md +++ b/contrib/i18n/README.md @@ -10,7 +10,7 @@ Regex for transforming gettext translations to our format: ``` in: msgid\ \"(.*)\"\nmsgid_plural\ \"(.*)\"\nmsgstr\[0\]\ \"(.*)\"\n(msgstr\[1\]\ \"(.*)\"\n)?(msgstr\[2\]\ \"(.*)\"\n)?(msgstr\[3\]\ \"(.*)\"\n)?(msgstr\[4\]\ \"(.*)\"\n)?(msgstr\[5\]\ \"(.*)\"\n)? -out: #{"$2", {"$3", "$4", "$6", "$8", "$10"}},\n +out: #{"$2", {"$3", "$5", "$7", "$9", "$11"}},\n ``` ``` diff --git a/i18n/Chinese.cpp b/i18n/Chinese.cpp index 8a55ab6a..8c5ec3bc 100644 --- a/i18n/Chinese.cpp +++ b/i18n/Chinese.cpp @@ -38,9 +38,9 @@ namespace chinese // language namespace {"building", "正在构建"}, {"failed", "连接失败"}, {"expiring", "即将过期"}, - {"established", "连接已建立"}, + {"established", "连接成功"}, {"unknown", "未知"}, - {"exploratory", "探测"}, + {"exploratory", "探索"}, {"Purple I2P Webconsole", "Purple I2P 网页控制台"}, {"i2pd webconsole", "i2pd 网页控制台"}, {"Main page", "主页"}, @@ -130,7 +130,7 @@ namespace chinese // language namespace {"Note: any action done here are not persistent and not changes your config files.", "注意: 此处完成的任何操作都不是永久的,不会更改您的配置文件。"}, {"Logging level", "日志记录级别"}, {"Transit tunnels limit", "中转隧道限制"}, - {"Change", "更改"}, + {"Change", "修改"}, {"Change language", "更改语言"}, {"no transit tunnels currently built", "目前未构建中转隧道"}, {"SAM disabled", "SAM 已禁用"}, @@ -200,7 +200,7 @@ namespace chinese // language namespace static std::map> plurals { - {"days", {"天"}}, + {"days", {"日"}}, {"hours", {"时"}}, {"minutes", {"分"}}, {"seconds", {"秒"}}, diff --git a/i18n/I18N_langs.h b/i18n/I18N_langs.h index 87bc503e..88ba9721 100644 --- a/i18n/I18N_langs.h +++ b/i18n/I18N_langs.h @@ -77,6 +77,7 @@ namespace i18n namespace english { std::shared_ptr GetLocale (); } namespace french { std::shared_ptr GetLocale (); } namespace german { std::shared_ptr GetLocale (); } + namespace italian { std::shared_ptr GetLocale (); } namespace russian { std::shared_ptr GetLocale (); } namespace turkmen { std::shared_ptr GetLocale (); } namespace ukrainian { std::shared_ptr GetLocale (); } @@ -93,6 +94,7 @@ namespace i18n { "english", {"English", "en", i2p::i18n::english::GetLocale} }, { "french", {"Français", "fr", i2p::i18n::french::GetLocale} }, { "german", {"Deutsch", "de", i2p::i18n::german::GetLocale} }, + { "italian", {"Italiano", "it", i2p::i18n::italian::GetLocale} }, { "russian", {"русский язык", "ru", i2p::i18n::russian::GetLocale} }, { "turkmen", {"türkmen dili", "tk", i2p::i18n::turkmen::GetLocale} }, { "ukrainian", {"украї́нська мо́ва", "uk", i2p::i18n::ukrainian::GetLocale} }, diff --git a/i18n/Italian.cpp b/i18n/Italian.cpp new file mode 100644 index 00000000..ef2e26d0 --- /dev/null +++ b/i18n/Italian.cpp @@ -0,0 +1,216 @@ +/* +* Copyright (c) 2022, The PurpleI2P Project +* +* This file is part of Purple i2pd project and licensed under BSD3 +* +* See full license text in LICENSE file at top of project tree +*/ + +#include +#include +#include +#include +#include "I18N.h" + +// Italian localization file + +namespace i2p +{ +namespace i18n +{ +namespace italian // language namespace +{ + // language name in lowercase + static std::string language = "italian"; + + // See for language plural forms here: + // https://localization-guide.readthedocs.io/en/latest/l10n/pluralforms.html + static int plural (int n) { + return n != 1 ? 1 : 0; + } + + static std::map strings + { + {"KiB", "KiB"}, + {"MiB", "MiB"}, + {"GiB", "GiB"}, + {"building", "in costruzione"}, + {"failed", "fallito"}, + {"expiring", "in scadenza"}, + {"established", "stabilita"}, + {"unknown", "sconosciuto"}, + {"exploratory", "esplorativo"}, + {"Purple I2P Webconsole", "Terminale web Purple I2P"}, + {"i2pd webconsole", "Terminal web i2pd"}, + {"Main page", "Pagina principale"}, + {"Router commands", "Comandi router"}, + {"Local Destinations", "Destinazioni locali"}, + {"LeaseSets", "LeaseSets"}, + {"Tunnels", "Tunnel"}, + {"Transit Tunnels", "Tunnel di transito"}, + {"Transports", "Trasporti"}, + {"I2P tunnels", "Tunnel I2P"}, + {"SAM sessions", "Sessioni SAM"}, + {"ERROR", "ERRORE"}, + {"OK", "OK"}, + {"Testing", "Testando"}, + {"Firewalled", "Protetto da firewall"}, + {"Unknown", "Sconosciuto"}, + {"Proxy", "Proxy"}, + {"Mesh", "Mesh"}, + {"Error", "Errore"}, + {"Clock skew", "Orologio disallineato"}, + {"Offline", "Disconnesso"}, + {"Symmetric NAT", "NAT simmetrico"}, + {"Uptime", "In funzione da"}, + {"Network status", "Stato della rete"}, + {"Network status v6", "Stato della rete v6"}, + {"Stopping in", "Arresto in"}, + {"Family", "Famiglia"}, + {"Tunnel creation success rate", "Percentuale di tunnel creati con successo"}, + {"Received", "Ricevuti"}, + {"KiB/s", "KiB/s"}, + {"Sent", "Inviati"}, + {"Transit", "Transitati"}, + {"Data path", "Percorso dati"}, + {"Hidden content. Press on text to see.", "Contenuto nascosto. Premi sul testo per vedere."}, + {"Router Ident", "Identificativo del router"}, + {"Router Family", "Famiglia del router"}, + {"Router Caps", "Limiti del router"}, + {"Version", "Versione"}, + {"Our external address", "Il nostro indirizzo esterno"}, + {"supported", "supportato"}, + {"Routers", "Router"}, + {"Floodfills", "Floodfill"}, + {"Client Tunnels", "Tunnel client"}, + {"Services", "Servizi"}, + {"Enabled", "Abilitato"}, + {"Disabled", "Disabilitato"}, + {"Encrypted B33 address", "Indirizzo criptato B33"}, + {"Address registration line", "Linea di registrazione indirizzo"}, + {"Domain", "Dominio"}, + {"Generate", "Genera"}, + {"Note: result string can be used only for registering 2LD domains (example.i2p). For registering subdomains please use i2pd-tools.", "Nota: la stringa risultante può essere utilizzata solo per registrare domini 2LD (example.i2p). Per registrare i sottodomini, si prega di utilizzare i2pd-tools."}, + {"Address", "Indirizzo"}, + {"Type", "Tipologia"}, + {"EncType", "Tipo di crittografia"}, + {"Inbound tunnels", "Tunnel in entrata"}, + {"ms", "ms"}, + {"Outbound tunnels", "Tunnel in uscita"}, + {"Tags", "Tag"}, + {"Incoming", "In entrata"}, + {"Outgoing", "In uscita"}, + {"Destination", "Destinazione"}, + {"Amount", "Quantità"}, + {"Incoming Tags", "Tag in entrata"}, + {"Tags sessions", "Sessioni dei tag"}, + {"Status", "Stato"}, + {"Local Destination", "Destinazione locale"}, + {"Streams", "Flussi"}, + {"Close stream", "Interrompi il flusso"}, + {"I2CP session not found", "Sessione I2CP non trovata"}, + {"I2CP is not enabled", "I2CP non è abilitato"}, + {"Invalid", "Invalido"}, + {"Store type", "Tipologia di archivio"}, + {"Expires", "Scade"}, + {"Non Expired Leases", "Lease non scaduti"}, + {"Gateway", "Gateway"}, + {"TunnelID", "TunnelID"}, + {"EndDate", "Data di fine"}, + {"not floodfill", "no floodfill"}, + {"Queue size", "Dimensione della coda"}, + {"Run peer test", "Esegui il test dei peer"}, + {"Decline transit tunnels", "Rifiuta tunnel di transito"}, + {"Accept transit tunnels", "Accetta tunnel di transito"}, + {"Cancel graceful shutdown", "Annulla l'interruzione controllata"}, + {"Start graceful shutdown", "Avvia l'interruzione controllata"}, + {"Force shutdown", "Forza l'arresto"}, + {"Reload external CSS styles", "Ricarica gli stili CSS esterni"}, + {"Note: any action done here are not persistent and not changes your config files.", "Nota: qualsiasi azione effettuata qui non è persistente e non modifica i file di configurazione."}, + {"Logging level", "Livello di log"}, + {"Transit tunnels limit", "Limite di tunnel di transito"}, + {"Change", "Modifica"}, + {"Change language", "Modifica linguaggio"}, + {"no transit tunnels currently built", "Attualmente non ci sono tunnel di transito instaurati"}, + {"SAM disabled", "SAM disabilitato"}, + {"no sessions currently running", "Attualmente non ci sono sessioni attive"}, + {"SAM session not found", "Sessione SAM non trovata"}, + {"SAM Session", "Sessione SAM"}, + {"Server Tunnels", "Tunnel server"}, + {"Client Forwards", "Client di inoltro"}, + {"Server Forwards", "Server di inoltro"}, + {"Unknown page", "Pagina sconosciuta"}, + {"Invalid token", "Token non valido"}, + {"SUCCESS", "SUCCESSO"}, + {"Stream closed", "Flusso terminato"}, + {"Stream not found or already was closed", "Il flusso non è stato trovato oppure è già stato terminato"}, + {"Destination not found", "Destinazione non trovata"}, + {"StreamID can't be null", "Lo StreamID non può essere null"}, + {"Return to destination page", "Ritorna alla pagina di destinazione"}, + {"You will be redirected in 5 seconds", "Verrai reindirizzato in 5 secondi"}, + {"Transit tunnels count must not exceed 65535", "Il numero di tunnel di transito non può superare i 65535"}, + {"Back to commands list", "Ritorna alla lista dei comandi"}, + {"Register at reg.i2p", "Registra a reg.i2p"}, + {"Description", "Descrizione"}, + {"A bit information about service on domain", "Alcune informazioni riguardo il servizio sul dominio"}, + {"Submit", "Invia"}, + {"Domain can't end with .b32.i2p", "I domini non possono terminare con .b32.i2p"}, + {"Domain must end with .i2p", "I domini devono terminare con .i2p"}, + {"Such destination is not found", "Questa destinazione non è stata trovata"}, + {"Unknown command", "Comando sconosciuto"}, + {"Command accepted", "Comando accettato"}, + {"Proxy error", "Errore del proxy"}, + {"Proxy info", "Informazioni del proxy"}, + {"Proxy error: Host not found", "Errore del proxy: Host non trovato"}, + {"Remote host not found in router's addressbook", "L'host remoto non è stato trovato nella rubrica del router"}, + {"You may try to find this host on jump services below", "Si può provare a trovare questo host sui servizi di salto qui sotto"}, + {"Invalid request", "Richiesta non valida"}, + {"Proxy unable to parse your request", "Il proxy non è in grado di elaborare la tua richiesta"}, + {"addresshelper is not supported", "addresshelper non è supportato"}, + {"Host", "Host"}, + {"added to router's addressbook from helper", "aggiunto alla rubrica tramite l'helper"}, + {"Click here to proceed:", "Clicca qui per procedere:"}, + {"Continue", "Continua"}, + {"Addresshelper found", "Addresshelper trovato"}, + {"already in router's addressbook", "già presente nella rubrica del router"}, + {"Click here to update record:", "Clicca qui per aggiornare l'elemento:"}, + {"invalid request uri", "uri della richiesta non valido"}, + {"Can't detect destination host from request", "Impossibile determinare l'host di destinazione dalla richiesta"}, + {"Outproxy failure", "Fallimento del proxy di uscita"}, + {"bad outproxy settings", "impostazioni errate del proxy di uscita"}, + {"not inside I2P network, but outproxy is not enabled", "non all'interno della rete I2P, ma il proxy di uscita non è abilitato"}, + {"unknown outproxy url", "url del proxy di uscita sconosciuto"}, + {"cannot resolve upstream proxy", "impossibile identificare il flusso a monte del proxy"}, + {"hostname too long", "il nome dell'host è troppo lungo"}, + {"cannot connect to upstream socks proxy", "impossibile connettersi al flusso a monte del proxy socks"}, + {"Cannot negotiate with socks proxy", "Impossibile negoziare con il proxy socks"}, + {"CONNECT error", "Errore di connessione"}, + {"Failed to Connect", "Connessione fallita"}, + {"socks proxy error", "errore del proxy socks"}, + {"failed to send request to upstream", "invio della richiesta a monte non riuscito"}, + {"No Reply From socks proxy", "Nessuna risposta dal proxy socks"}, + {"cannot connect", "impossibile connettersi"}, + {"http out proxy not implemented", "proxy http di uscita non implementato"}, + {"cannot connect to upstream http proxy", "impossibile connettersi al proxy http a monte"}, + {"Host is down", "L'host è offline"}, + {"Can't create connection to requested host, it may be down. Please try again later.", "Impossibile creare la connessione all'host richiesto, probabilmente è offline. Riprova più tardi."}, + {"", ""}, + }; + + static std::map> plurals + { + {"days", {"giorno", "giorni"}}, + {"hours", {"ora", "ore"}}, + {"minutes", {"minuto", "minuti"}}, + {"seconds", {"secondo", "secondi"}}, + {"", {"", ""}}, + }; + + std::shared_ptr GetLocale() + { + return std::make_shared(language, strings, plurals, [] (int n)->int { return plural(n); }); + } + +} // language +} // i18n +} // i2p From 1a32c55ca3b8194324d64d6c32588c981a6a85d9 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 31 Aug 2022 13:10:52 -0400 Subject: [PATCH 149/219] delete routers with expired SSU2 introducers --- libi2pd/NetDb.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libi2pd/NetDb.cpp b/libi2pd/NetDb.cpp index 7f31fc7d..6042eaf2 100644 --- a/libi2pd/NetDb.cpp +++ b/libi2pd/NetDb.cpp @@ -628,7 +628,8 @@ namespace data (it.second->IsFloodfill () && totalFloodfills - deletedFloodfillsCount < NETDB_MIN_FLOODFILLS))) it.second->SetUnreachable (false); // find & mark expired routers - if (!it.second->IsReachable () && it.second->IsSSU (false)) + if (!it.second->IsReachable () && (it.second->GetCompatibleTransports (true) & (RouterInfo::eSSUV4 | RouterInfo::eSSU2V4))) + // non-reachable router, but reachable by ipv4 SSU or SSU2 means introducers { if (ts > it.second->GetTimestamp () + NETDB_INTRODUCEE_EXPIRATION_TIMEOUT*1000LL) // RouterInfo expires after 1 hour if uses introducer From 1a9c65883644c892a4f73add373f4c1e17301fe6 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 1 Sep 2022 18:40:54 -0400 Subject: [PATCH 150/219] immediate ack request flag --- libi2pd/SSU2Session.cpp | 13 ++++++++++--- libi2pd/SSU2Session.h | 5 ++++- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index 87181da6..2a6ef162 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -367,10 +367,11 @@ namespace transport }; if (packet->payloadSize > ackBlockSize) { + // last ackBlockSent = true; if (packet->payloadSize + 16 < m_MaxPayloadSize) packet->payloadSize += CreatePaddingBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize); - uint32_t packetNum = SendData (packet->payload, packet->payloadSize); + uint32_t packetNum = SendData (packet->payload, packet->payloadSize, SSU2_FLAG_IMMEDIATE_ACK_REQUESTED); packet->sendTime = ts; m_SentPackets.emplace (packetNum, packet); } @@ -419,9 +420,14 @@ namespace transport packet = m_Server.GetSentPacketsPool ().AcquireShared (); packet->payloadSize = CreateFollowOnFragmentBlock (packet->payload, m_MaxPayloadSize - offset, msg, fragmentNum, msgID); extraSize -= offset; + uint8_t flags = 0; if (msg->offset >= msg->len && packet->payloadSize + 16 < m_MaxPayloadSize) // last fragment + { packet->payloadSize += CreatePaddingBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize); - uint32_t followonPacketNum = SendData (packet->payload, packet->payloadSize); + if (fragmentNum > 2) // 3 or more fragments + flags |= SSU2_FLAG_IMMEDIATE_ACK_REQUESTED; + } + uint32_t followonPacketNum = SendData (packet->payload, packet->payloadSize, flags); packet->sendTime = ts; m_SentPackets.emplace (followonPacketNum, packet); } @@ -1267,7 +1273,7 @@ namespace transport return true; } - uint32_t SSU2Session::SendData (const uint8_t * buf, size_t len) + uint32_t SSU2Session::SendData (const uint8_t * buf, size_t len, uint8_t flags) { if (len < 8) { @@ -1279,6 +1285,7 @@ namespace transport header.h.packetNum = htobe32 (m_SendPacketNum); header.h.type = eSSU2Data; memset (header.h.flags, 0, 3); + if (flags) header.h.flags[0] = flags; uint8_t nonce[12]; CreateNonce (m_SendPacketNum, nonce); uint8_t payload[SSU2_MAX_PACKET_SIZE]; diff --git a/libi2pd/SSU2Session.h b/libi2pd/SSU2Session.h index 7f8020f2..1e2644ab 100644 --- a/libi2pd/SSU2Session.h +++ b/libi2pd/SSU2Session.h @@ -48,6 +48,9 @@ namespace transport const int SSU2_MAX_NUM_ACK_RANGES = 32; // to send const uint8_t SSU2_MAX_NUM_FRAGMENTS = 64; + // flags + const uint8_t SSU2_FLAG_IMMEDIATE_ACK_REQUESTED = 0x01; + enum SSU2MessageType { eSSU2SessionRequest = 0, @@ -275,7 +278,7 @@ namespace transport void KDFDataPhase (uint8_t * keydata_ab, uint8_t * keydata_ba); void SendTokenRequest (); void SendRetry (); - uint32_t SendData (const uint8_t * buf, size_t len); // returns packet num + uint32_t SendData (const uint8_t * buf, size_t len, uint8_t flags = 0); // returns packet num void SendQuickAck (); void SendTermination (); void SendHolePunch (uint32_t nonce, const boost::asio::ip::udp::endpoint& ep, const uint8_t * introKey, uint64_t token); From 4634bff9f0d4f49d46bd21cf71f8592c361f274a Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 3 Sep 2022 15:38:52 -0400 Subject: [PATCH 151/219] limit number of resent packets. Resend interval variance --- libi2pd/SSU2.cpp | 14 ++++++++++---- libi2pd/SSU2.h | 7 +++++-- libi2pd/SSU2Session.cpp | 10 ++++++---- libi2pd/SSU2Session.h | 2 +- 4 files changed, 22 insertions(+), 11 deletions(-) diff --git a/libi2pd/SSU2.cpp b/libi2pd/SSU2.cpp index 019fffca..156bc2b0 100644 --- a/libi2pd/SSU2.cpp +++ b/libi2pd/SSU2.cpp @@ -86,6 +86,7 @@ namespace transport if (found) m_ReceiveService.Start (); ScheduleTermination (); + ScheduleResend (false); } } @@ -749,9 +750,10 @@ namespace transport } } - void SSU2Server::ScheduleResend () + void SSU2Server::ScheduleResend (bool more) { - m_ResendTimer.expires_from_now (boost::posix_time::milliseconds(SSU2_RESEND_CHECK_TIMEOUT)); + m_ResendTimer.expires_from_now (boost::posix_time::milliseconds (more ? SSU2_RESEND_CHECK_MORE_TIMEOUT : + (SSU2_RESEND_CHECK_TIMEOUT + rand () % SSU2_RESEND_CHECK_TIMEOUT_VARIANCE))); m_ResendTimer.async_wait (std::bind (&SSU2Server::HandleResendTimer, this, std::placeholders::_1)); } @@ -760,12 +762,16 @@ namespace transport { if (ecode != boost::asio::error::operation_aborted) { + size_t resentPacketsNum = 0; auto ts = i2p::util::GetMillisecondsSinceEpoch (); for (auto it: m_Sessions) - it.second->Resend (ts); + { + resentPacketsNum += it.second->Resend (ts); + if (resentPacketsNum > SSU2_MAX_RESEND_PACKETS) break; + } for (auto it: m_PendingOutgoingSessions) it.second->Resend (ts); - ScheduleResend (); + ScheduleResend (resentPacketsNum > SSU2_MAX_RESEND_PACKETS); } } diff --git a/libi2pd/SSU2.h b/libi2pd/SSU2.h index 8ad64692..27af6bf8 100644 --- a/libi2pd/SSU2.h +++ b/libi2pd/SSU2.h @@ -18,7 +18,10 @@ namespace i2p namespace transport { const int SSU2_TERMINATION_CHECK_TIMEOUT = 30; // in seconds - const int SSU2_RESEND_CHECK_TIMEOUT = 500; // in milliseconds + const int SSU2_RESEND_CHECK_TIMEOUT = 400; // in milliseconds + const int SSU2_RESEND_CHECK_TIMEOUT_VARIANCE = 100; // in milliseconds + const int SSU2_RESEND_CHECK_MORE_TIMEOUT = 10; // in milliseconds + const size_t SSU2_MAX_RESEND_PACKETS = 128; // packets to resend at the time const size_t SSU2_SOCKET_RECEIVE_BUFFER_SIZE = 0x1FFFF; // 128K const size_t SSU2_SOCKET_SEND_BUFFER_SIZE = 0x1FFFF; // 128K const size_t SSU2_MAX_NUM_INTRODUCERS = 3; @@ -104,7 +107,7 @@ namespace transport void ScheduleTermination (); void HandleTerminationTimer (const boost::system::error_code& ecode); - void ScheduleResend (); + void ScheduleResend (bool more); void HandleResendTimer (const boost::system::error_code& ecode); void ConnectThroughIntroducer (std::shared_ptr session); diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index 2a6ef162..5053dc94 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -434,7 +434,7 @@ namespace transport return ackBlockSent; } - void SSU2Session::Resend (uint64_t ts) + size_t SSU2Session::Resend (uint64_t ts) { // resend handshake packet if (m_SentHandshakePacket && ts >= m_SentHandshakePacket->sendTime + SSU2_HANDSHAKE_RESEND_INTERVAL) @@ -442,10 +442,10 @@ namespace transport LogPrint (eLogDebug, "SSU2: Resending ", (int)m_State); ResendHandshakePacket (); m_SentHandshakePacket->sendTime = ts; - return; + return 0; } // resend data packets - if (m_SentPackets.empty ()) return; + if (m_SentPackets.empty ()) return 0; std::map > resentPackets; for (auto it = m_SentPackets.begin (); it != m_SentPackets.end (); ) if (ts >= it->second->sendTime + it->second->numResends*m_RTO) @@ -456,7 +456,7 @@ namespace transport m_SentPackets.clear (); m_SendQueue.clear (); RequestTermination (eSSU2TerminationReasonTimeout); - return; + return resentPackets.size (); } else { @@ -478,7 +478,9 @@ namespace transport #endif m_WindowSize >>= 1; // /2 if (m_WindowSize < SSU2_MIN_WINDOW_SIZE) m_WindowSize = SSU2_MIN_WINDOW_SIZE; + return resentPackets.size (); } + return 0; } void SSU2Session::ResendHandshakePacket () diff --git a/libi2pd/SSU2Session.h b/libi2pd/SSU2Session.h index 1e2644ab..72211bf6 100644 --- a/libi2pd/SSU2Session.h +++ b/libi2pd/SSU2Session.h @@ -243,7 +243,7 @@ namespace transport void SendLocalRouterInfo (bool update) override; void SendI2NPMessages (const std::vector >& msgs) override; uint32_t GetRelayTag () const override { return m_RelayTag; }; - void Resend (uint64_t ts); + size_t Resend (uint64_t ts); // return number or resent packets bool IsEstablished () const { return m_State == eSSU2SessionStateEstablished; }; uint64_t GetConnID () const { return m_SourceConnID; }; SSU2SessionState GetState () const { return m_State; }; From cf41df82e294ad3d03bfbc5330c743fa60079198 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Sun, 4 Sep 2022 22:24:56 +0300 Subject: [PATCH 152/219] [i18n] add spanish translation Thanks to Liboide Signed-off-by: R4SAS --- contrib/i2pd.conf | 2 +- i18n/I18N_langs.h | 10 ++- i18n/Spanish.cpp | 216 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 223 insertions(+), 5 deletions(-) create mode 100644 i18n/Spanish.cpp diff --git a/contrib/i2pd.conf b/contrib/i2pd.conf index 1c4d814c..d0a9e141 100644 --- a/contrib/i2pd.conf +++ b/contrib/i2pd.conf @@ -127,7 +127,7 @@ port = 7070 # pass = changeme ## Select webconsole language ## Currently supported english (default), afrikaans, armenian, chinese, french, -## german, russian, turkmen, ukrainian and uzbek languages +## german, italian, russian, spanish, turkmen, ukrainian and uzbek languages # lang = english [httpproxy] diff --git a/i18n/I18N_langs.h b/i18n/I18N_langs.h index 88ba9721..da70e578 100644 --- a/i18n/I18N_langs.h +++ b/i18n/I18N_langs.h @@ -79,6 +79,7 @@ namespace i18n namespace german { std::shared_ptr GetLocale (); } namespace italian { std::shared_ptr GetLocale (); } namespace russian { std::shared_ptr GetLocale (); } + namespace spanish { std::shared_ptr GetLocale (); } namespace turkmen { std::shared_ptr GetLocale (); } namespace ukrainian { std::shared_ptr GetLocale (); } namespace uzbek { std::shared_ptr GetLocale (); } @@ -89,15 +90,16 @@ namespace i18n static std::map languages { { "afrikaans", {"Afrikaans", "af", i2p::i18n::afrikaans::GetLocale} }, - { "armenian", {"հայերէն", "hy", i2p::i18n::armenian::GetLocale} }, + { "armenian", {"hայերէն", "hy", i2p::i18n::armenian::GetLocale} }, { "chinese", {"简体字", "zh-CN", i2p::i18n::chinese::GetLocale} }, { "english", {"English", "en", i2p::i18n::english::GetLocale} }, { "french", {"Français", "fr", i2p::i18n::french::GetLocale} }, { "german", {"Deutsch", "de", i2p::i18n::german::GetLocale} }, { "italian", {"Italiano", "it", i2p::i18n::italian::GetLocale} }, - { "russian", {"русский язык", "ru", i2p::i18n::russian::GetLocale} }, - { "turkmen", {"türkmen dili", "tk", i2p::i18n::turkmen::GetLocale} }, - { "ukrainian", {"украї́нська мо́ва", "uk", i2p::i18n::ukrainian::GetLocale} }, + { "russian", {"Русский язык", "ru", i2p::i18n::russian::GetLocale} }, + { "spanish", {"Español", "es", i2p::i18n::spanish::GetLocale} }, + { "turkmen", {"Türkmen dili", "tk", i2p::i18n::turkmen::GetLocale} }, + { "ukrainian", {"Украї́нська мо́ва", "uk", i2p::i18n::ukrainian::GetLocale} }, { "uzbek", {"Oʻzbek", "uz", i2p::i18n::uzbek::GetLocale} }, }; diff --git a/i18n/Spanish.cpp b/i18n/Spanish.cpp new file mode 100644 index 00000000..a2f53927 --- /dev/null +++ b/i18n/Spanish.cpp @@ -0,0 +1,216 @@ +/* +* Copyright (c) 2022, The PurpleI2P Project +* +* This file is part of Purple i2pd project and licensed under BSD3 +* +* See full license text in LICENSE file at top of project tree +*/ + +#include +#include +#include +#include +#include "I18N.h" + +// Spanish localization file + +namespace i2p +{ +namespace i18n +{ +namespace spanish // language namespace +{ + // language name in lowercase + static std::string language = "spanish"; + + // See for language plural forms here: + // https://localization-guide.readthedocs.io/en/latest/l10n/pluralforms.html + static int plural (int n) { + return n != 1 ? 1 : 0; + } + + static std::map strings + { + {"KiB", "KiB"}, + {"MiB", "MiB"}, + {"GiB", "GiB"}, + {"building", "pendiente"}, + {"failed", "fallido"}, + {"expiring", "expiró"}, + {"established", "establecido"}, + {"unknown", "desconocido"}, + {"exploratory", "exploratorio"}, + {"Purple I2P Webconsole", "Consola web de Purple I2P"}, + {"i2pd webconsole", "Consola web de i2pd"}, + {"Main page", "Inicio"}, + {"Router commands", "Comandos de enrutador"}, + {"Local Destinations", "Destinos locales"}, + {"LeaseSets", "LeaseSets"}, + {"Tunnels", "Túneles"}, + {"Transit Tunnels", "Túneles de Tránsito"}, + {"Transports", "Transportes"}, + {"I2P tunnels", "Túneles I2P"}, + {"SAM sessions", "Sesiones SAM"}, + {"ERROR", "ERROR"}, + {"OK", "VALE"}, + {"Testing", "Probando"}, + {"Firewalled", "Con cortafuegos"}, + {"Unknown", "Desconocido"}, + {"Proxy", "Proxy"}, + {"Mesh", "Malla"}, + {"Error", "Error"}, + {"Clock skew", "Reloj desfasado"}, + {"Offline", "Desconectado"}, + {"Symmetric NAT", "NAT simétrico"}, + {"Uptime", "Tiempo en línea"}, + {"Network status", "Estado de red"}, + {"Network status v6", "Estado de red v6"}, + {"Stopping in", "Parando en"}, + {"Family", "Familia"}, + {"Tunnel creation success rate", "Tasa de éxito de creación de túneles"}, + {"Received", "Recibido"}, + {"KiB/s", "KiB/s"}, + {"Sent", "Enviado"}, + {"Transit", "Tránsito"}, + {"Data path", "Ruta de datos"}, + {"Hidden content. Press on text to see.", "Contenido oculto. Presione para ver."}, + {"Router Ident", "Ident del Enrutador"}, + {"Router Family", "Familia de enrutador"}, + {"Router Caps", "Atributos del Enrutador"}, + {"Version", "Versión"}, + {"Our external address", "Nuestra dirección externa"}, + {"supported", "soportado"}, + {"Routers", "Enrutadores"}, + {"Floodfills", "Inundaciones"}, + {"Client Tunnels", "Túneles de cliente"}, + {"Services", "Servicios"}, + {"Enabled", "Activado"}, + {"Disabled", "Desactivado"}, + {"Encrypted B33 address", "Dirección encriptada B33"}, + {"Address registration line", "Línea para registrar direcciones"}, + {"Domain", "Dominio"}, + {"Generate", "Generar"}, + {"Note: result string can be used only for registering 2LD domains (example.i2p). For registering subdomains please use i2pd-tools.", "Nota: la cadena resultante solo se puede usar para registrar dominios 2LD (ejemplo.i2p). Para registrar subdominios, por favor utilice i2pd-tools."}, + {"Address", "Dirección"}, + {"Type", "Tipo"}, + {"EncType", "TipoEncrip"}, + {"Inbound tunnels", "Túneles entrantes"}, + {"ms", "ms"}, + {"Outbound tunnels", "Túneles salientes"}, + {"Tags", "Etiquetas"}, + {"Incoming", "Entrante"}, + {"Outgoing", "Saliente"}, + {"Destination", "Destino"}, + {"Amount", "Cantidad"}, + {"Incoming Tags", "Etiquetas entrantes"}, + {"Tags sessions", "Sesiones de etiquetas"}, + {"Status", "Estado"}, + {"Local Destination", "Destino Local"}, + {"Streams", "Flujos"}, + {"Close stream", "Cerrar flujo"}, + {"I2CP session not found", "Sesión I2CP no encontrada"}, + {"I2CP is not enabled", "I2CP no está activado"}, + {"Invalid", "Inválido"}, + {"Store type", "Tipo de almacenamiento"}, + {"Expires", "Caduca"}, + {"Non Expired Leases", "Sesiones No Expiradas"}, + {"Gateway", "Puerta de enlace"}, + {"TunnelID", "TunnelID"}, + {"EndDate", "FechaVenc"}, + {"not floodfill", "no inundado"}, + {"Queue size", "Tamaño de cola"}, + {"Run peer test", "Ejecutar prueba de par"}, + {"Decline transit tunnels", "Rechazar túneles de tránsito"}, + {"Accept transit tunnels", "Aceptar túneles de tránsito"}, + {"Cancel graceful shutdown", "Cancelar apagado con gracia"}, + {"Start graceful shutdown", "Iniciar apagado con gracia"}, + {"Force shutdown", "Forzar apagado"}, + {"Reload external CSS styles", "Recargar estilos CSS externos"}, + {"Note: any action done here are not persistent and not changes your config files.", "Nota: cualquier acción hecha aquí no es persistente y no cambia tus archivos de configuración."}, + {"Logging level", "Nivel de registro de errores"}, + {"Transit tunnels limit", "Límite de túneles de tránsito"}, + {"Change", "Cambiar"}, + {"Change language", "Cambiar idioma"}, + {"no transit tunnels currently built", "no hay túneles de tránsito actualmente construidos"}, + {"SAM disabled", "SAM desactivado"}, + {"no sessions currently running", "no hay sesiones ejecutándose ahora"}, + {"SAM session not found", "Sesión SAM no encontrada"}, + {"SAM Session", "Sesión SAM"}, + {"Server Tunnels", "Túneles de Servidor"}, + {"Client Forwards", "Redirecciones de Cliente"}, + {"Server Forwards", "Redirecciones de Servidor"}, + {"Unknown page", "Página desconocida"}, + {"Invalid token", "Token inválido"}, + {"SUCCESS", "ÉXITO"}, + {"Stream closed", "Transmisión cerrada"}, + {"Stream not found or already was closed", "No se encontró la transmisión o ya se cerró"}, + {"Destination not found", "Destino no encontrado"}, + {"StreamID can't be null", "StreamID no puede ser nulo"}, + {"Return to destination page", "Volver a la página de destino"}, + {"You will be redirected in 5 seconds", "Serás redirigido en 5 segundos"}, + {"Transit tunnels count must not exceed 65535", "La cantidad de túneles de tránsito no puede exceder 65535"}, + {"Back to commands list", "Volver a lista de comandos"}, + {"Register at reg.i2p", "Registrar en reg.i2p"}, + {"Description", "Descripción"}, + {"A bit information about service on domain", "Un poco de información sobre el servicio en el dominio"}, + {"Submit", "Enviar"}, + {"Domain can't end with .b32.i2p", "El dominio no puede terminar con .b32.i2p"}, + {"Domain must end with .i2p", "El dominio debe terminar con .i2p"}, + {"Such destination is not found", "No se encontró el destino"}, + {"Unknown command", "Comando desconocido"}, + {"Command accepted", "Comando aceptado"}, + {"Proxy error", "Error de proxy"}, + {"Proxy info", "Información del proxy"}, + {"Proxy error: Host not found", "Error de proxy: Host no encontrado"}, + {"Remote host not found in router's addressbook", "Servidor remoto no encontrado en la libreta de direcciones del enrutador"}, + {"You may try to find this host on jump services below", "Puede intentar encontrar este dominio en los siguientes servicios de salto"}, + {"Invalid request", "Solicitud inválida"}, + {"Proxy unable to parse your request", "Proxy no puede procesar su solicitud"}, + {"addresshelper is not supported", "ayudante de dirección no soportado"}, + {"Host", "Dominio"}, + {"added to router's addressbook from helper", "añadido a la libreta de direcciones desde el ayudante"}, + {"Click here to proceed:", "Haga clic aquí para continuar:"}, + {"Continue", "Continuar"}, + {"Addresshelper found", "Se encontró ayudante de dirección"}, + {"already in router's addressbook", "ya se encontró en libreta de direcciones"}, + {"Click here to update record:", "Haga clic aquí para actualizar el registro:"}, + {"invalid request uri", "uri de solicitud inválida"}, + {"Can't detect destination host from request", "No se puede detectar el host de destino de la solicitud"}, + {"Outproxy failure", "Fallo en el proxy saliente"}, + {"bad outproxy settings", "configuración de outproxy incorrecta"}, + {"not inside I2P network, but outproxy is not enabled", "no está dentro de la red I2P, pero el proxy de salida no está activado"}, + {"unknown outproxy url", "url de proxy outproxy desconocido"}, + {"cannot resolve upstream proxy", "no se puede resolver el proxy de upstream"}, + {"hostname too long", "nombre de dominio muy largo"}, + {"cannot connect to upstream socks proxy", "no se puede conectar al proxy socks principal"}, + {"Cannot negotiate with socks proxy", "No se puede negociar con el proxy socks"}, + {"CONNECT error", "Error de CONNECT"}, + {"Failed to Connect", "Error al Conectar"}, + {"socks proxy error", "error de proxy socks"}, + {"failed to send request to upstream", "no se pudo enviar petición al principal"}, + {"No Reply From socks proxy", "Sin respuesta del proxy socks"}, + {"cannot connect", "no se puede conectar"}, + {"http out proxy not implemented", "proxy externo http no implementado"}, + {"cannot connect to upstream http proxy", "no se puede conectar al proxy http principal"}, + {"Host is down", "Servidor caído"}, + {"Can't create connection to requested host, it may be down. Please try again later.", "No se puede crear la conexión al servidor solicitado, puede estar caído. Intente de nuevo más tarde."}, + {"", ""}, + }; + + static std::map> plurals + { + {"days", {"día", "días"}}, + {"hours", {"hora", "horas"}}, + {"minutes", {"minuto", "minutos"}}, + {"seconds", {"segundo", "segundos"}}, + {"", {"", ""}}, + }; + + std::shared_ptr GetLocale() + { + return std::make_shared(language, strings, plurals, [] (int n)->int { return plural(n); }); + } + +} // language +} // i18n +} // i2p From cf27581c76387d8d2c4d9d2b5605fa4ef4c65c74 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 5 Sep 2022 15:27:38 -0400 Subject: [PATCH 153/219] check min MTU 1280 --- libi2pd/SSU2Session.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index 5053dc94..4df9a076 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -2196,6 +2196,7 @@ namespace transport mtu = m_Address->ssu->mtu; if (mtu) { + if (mtu < (int)SSU2_MIN_PACKET_SIZE) mtu = SSU2_MIN_PACKET_SIZE; m_MaxPayloadSize = mtu - (addr->IsV6 () ? IPV6_HEADER_SIZE: IPV4_HEADER_SIZE) - UDP_HEADER_SIZE - 32; LogPrint (eLogDebug, "SSU2: Session MTU=", mtu, ", max payload size=", m_MaxPayloadSize); } From 3bdef5f58dad4237a9e6040583d256426452d2fb Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 7 Sep 2022 19:11:33 -0400 Subject: [PATCH 154/219] update remote endpoint and send path challenge --- libi2pd/SSU2.cpp | 4 ++-- libi2pd/SSU2Session.cpp | 22 +++++++++++++++++++++- libi2pd/SSU2Session.h | 3 ++- 3 files changed, 25 insertions(+), 4 deletions(-) diff --git a/libi2pd/SSU2.cpp b/libi2pd/SSU2.cpp index 156bc2b0..245169d8 100644 --- a/libi2pd/SSU2.cpp +++ b/libi2pd/SSU2.cpp @@ -410,7 +410,7 @@ namespace transport { case eSSU2SessionStateEstablished: case eSSU2SessionStateSessionConfirmedSent: - m_LastSession->ProcessData (buf, len); + m_LastSession->ProcessData (buf, len, senderEndpoint); break; case eSSU2SessionStateSessionCreatedSent: if (!m_LastSession->ProcessSessionConfirmed (buf, len)) @@ -437,7 +437,7 @@ namespace transport m_LastSession->ProcessPeerTest (buf, len); break; case eSSU2SessionStateClosing: - m_LastSession->ProcessData (buf, len); // we might receive termintaion block + m_LastSession->ProcessData (buf, len, senderEndpoint); // we might receive termintaion block if (m_LastSession && m_LastSession->GetState () != eSSU2SessionStateTerminated) m_LastSession->RequestTermination (eSSU2TerminationReasonIdleTimeout); // send termination again break; diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index 4df9a076..e5430054 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -1301,7 +1301,7 @@ namespace transport return m_SendPacketNum - 1; } - void SSU2Session::ProcessData (uint8_t * buf, size_t len) + void SSU2Session::ProcessData (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& from) { Header header; header.ll[0] = m_SourceConnID; @@ -1316,6 +1316,12 @@ namespace transport ResendHandshakePacket (); // assume we receive return; } + if (from != m_RemoteEndpoint) + { + LogPrint (eLogInfo, "SSU2: Remote endpoint update ", m_RemoteEndpoint, "->", from); + m_RemoteEndpoint = from; + SendPathChallenge (); + } uint8_t payload[SSU2_MAX_PACKET_SIZE]; size_t payloadSize = len - 32; uint32_t packetNum = be32toh (header.h.packetNum); @@ -2625,6 +2631,20 @@ namespace transport memcpy (payload + 3, data, len); SendData (payload, len + 3); } + + void SSU2Session::SendPathChallenge () + { + uint8_t payload[SSU2_MAX_PACKET_SIZE]; + payload[0] = eSSU2BlkPathChallenge; + size_t len = rand () % (m_MaxPayloadSize - 3); + htobe16buf (payload + 1, len); + if (len > 0) + RAND_bytes (payload + 3, len); + len += 3; + if (len < m_MaxPayloadSize) + len += CreatePaddingBlock (payload + len, m_MaxPayloadSize - len); + SendData (payload, len); + } void SSU2Session::CleanUp (uint64_t ts) { diff --git a/libi2pd/SSU2Session.h b/libi2pd/SSU2Session.h index 72211bf6..a7aa5557 100644 --- a/libi2pd/SSU2Session.h +++ b/libi2pd/SSU2Session.h @@ -255,7 +255,7 @@ namespace transport bool ProcessRetry (uint8_t * buf, size_t len); bool ProcessHolePunch (uint8_t * buf, size_t len); bool ProcessPeerTest (uint8_t * buf, size_t len); - void ProcessData (uint8_t * buf, size_t len); + void ProcessData (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& from); private: @@ -284,6 +284,7 @@ namespace transport void SendHolePunch (uint32_t nonce, const boost::asio::ip::udp::endpoint& ep, const uint8_t * introKey, uint64_t token); void SendPeerTest (uint8_t msg, const uint8_t * signedData, size_t signedDataLen, const uint8_t * introKey); // PeerTest message void SendPathResponse (const uint8_t * data, size_t len); + void SendPathChallenge (); void HandlePayload (const uint8_t * buf, size_t len); void HandleDateTime (const uint8_t * buf, size_t len); From 23e18a34d40b3d130454393cc996e7d6d101bdc3 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 8 Sep 2022 18:46:48 -0400 Subject: [PATCH 155/219] check if new address is in reserved range --- libi2pd/SSU2Session.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index e5430054..b7e33b3a 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -1316,7 +1316,7 @@ namespace transport ResendHandshakePacket (); // assume we receive return; } - if (from != m_RemoteEndpoint) + if (from != m_RemoteEndpoint && !i2p::util::net::IsInReservedRange (from.address ())) { LogPrint (eLogInfo, "SSU2: Remote endpoint update ", m_RemoteEndpoint, "->", from); m_RemoteEndpoint = from; From 09e6e2940f85e97dee631021a31594f04457c34e Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 9 Sep 2022 07:23:46 -0400 Subject: [PATCH 156/219] correct max paddign size --- libi2pd/SSU2Session.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index b7e33b3a..fab1a397 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -2366,10 +2366,10 @@ namespace transport size_t SSU2Session::CreatePaddingBlock (uint8_t * buf, size_t len, size_t minSize) { - if (len < minSize) return 0; - uint8_t paddingSize = rand () & 0x0F; // 0 - 15 - if (paddingSize > len) paddingSize = len; - else if (paddingSize < minSize) paddingSize = minSize; + if (len < 3 || len < minSize) return 0; + size_t paddingSize = rand () & 0x0F; // 0 - 15 + if (paddingSize + 3 > len) paddingSize = len - 3; + else if (paddingSize + 3 < minSize) paddingSize = minSize - 3; if (paddingSize) { buf[0] = eSSU2BlkPadding; From 857a2bc39948ccdbb3ce48756b480ff632ffec26 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 14 Sep 2022 19:08:14 -0400 Subject: [PATCH 157/219] verify path response --- libi2pd/SSU2Session.cpp | 20 +++++++++++++++++++- libi2pd/SSU2Session.h | 1 + 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index fab1a397..3a818175 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -207,6 +207,8 @@ namespace transport if (m_RelayTag) m_Server.RemoveRelay (m_RelayTag); m_SentHandshakePacket.reset (nullptr); + m_SessionConfirmedFragment.reset (nullptr); + m_PathChallenge.reset (nullptr); m_SendQueue.clear (); m_SentPackets.clear (); m_IncompleteMessages.clear (); @@ -1455,8 +1457,17 @@ namespace transport SendPathResponse (buf + offset, size); break; case eSSU2BlkPathResponse: + { LogPrint (eLogDebug, "SSU2: Path response"); - break; + if (m_PathChallenge) + { + i2p::data::IdentHash hash; + SHA256 (buf + offset, size, hash); + if (hash == *m_PathChallenge) + m_PathChallenge.reset (nullptr); + } + break; + } case eSSU2BlkFirstPacketNumber: break; case eSSU2BlkPadding: @@ -2639,7 +2650,12 @@ namespace transport size_t len = rand () % (m_MaxPayloadSize - 3); htobe16buf (payload + 1, len); if (len > 0) + { RAND_bytes (payload + 3, len); + i2p::data::IdentHash * hash = new i2p::data::IdentHash (); + SHA256 (payload + 3, len, *hash); + m_PathChallenge.reset (hash); + } len += 3; if (len < m_MaxPayloadSize) len += CreatePaddingBlock (payload + len, m_MaxPayloadSize - len); @@ -2702,6 +2718,8 @@ namespace transport else ++it; } + if (m_PathChallenge) + RequestTermination (eSSU2TerminationReasonNormalClose); } void SSU2Session::FlushData () diff --git a/libi2pd/SSU2Session.h b/libi2pd/SSU2Session.h index a7aa5557..6797e8ce 100644 --- a/libi2pd/SSU2Session.h +++ b/libi2pd/SSU2Session.h @@ -349,6 +349,7 @@ namespace transport boost::asio::deadline_timer m_ConnectTimer; SSU2TerminationReason m_TerminationReason; size_t m_MaxPayloadSize; + std::unique_ptr m_PathChallenge; }; inline uint64_t CreateHeaderMask (const uint8_t * kh, const uint8_t * nonce) From 030af11d8601303215baf20e39b814d965ed49de Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 18 Sep 2022 21:13:38 -0400 Subject: [PATCH 158/219] don't merge duppicated fragment of SessionConfirmed --- libi2pd/SSU2Session.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index 3a818175..5bbea6e8 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -872,6 +872,7 @@ namespace transport memmove (m_SessionConfirmedFragment->payload + (len - 16), m_SessionConfirmedFragment->payload, m_SessionConfirmedFragment->payloadSize); memcpy (m_SessionConfirmedFragment->payload, buf + 16, len - 16); m_SessionConfirmedFragment->payloadSize += (len - 16); + m_SessionConfirmedFragment->isSecondFragment = false; buf = m_SessionConfirmedFragment->payload - 16; len = m_SessionConfirmedFragment->payloadSize + 16; } @@ -891,8 +892,11 @@ namespace transport return true; } header = m_SessionConfirmedFragment->header; - memcpy (m_SessionConfirmedFragment->payload + m_SessionConfirmedFragment->payloadSize, buf + 16, len - 16); - m_SessionConfirmedFragment->payloadSize += (len - 16); + if (m_SessionConfirmedFragment->payloadSize + (len - 16) <= SSU2_MAX_PACKET_SIZE*2) + { + memcpy (m_SessionConfirmedFragment->payload + m_SessionConfirmedFragment->payloadSize, buf + 16, len - 16); + m_SessionConfirmedFragment->payloadSize += (len - 16); + } buf = m_SessionConfirmedFragment->payload - 16; len = m_SessionConfirmedFragment->payloadSize + 16; } From 24ae8d5443376a6276c8fd3848f04e608e0580bd Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 20 Sep 2022 18:32:29 -0400 Subject: [PATCH 159/219] don't handle more than 2 fragments in SessionConfirmed --- libi2pd/SSU2Session.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index 5bbea6e8..68b26223 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -851,9 +851,15 @@ namespace transport return true; } // check if fragmented - if ((header.h.flags[0] & 0x0F) > 1) + uint8_t numFragments = header.h.flags[0] & 0x0F; + if (numFragments > 1) { // fragmented + if (numFragments > 2) + { + LogPrint (eLogError, "SSU2: Too many fragments ", numFragments, " in SessionConfirmed"); + return false; + } if (!(header.h.flags[0] & 0xF0)) { // first fragment @@ -911,6 +917,7 @@ namespace transport m_NoiseState->m_CK + 32, nonce, S, 32, false)) { LogPrint (eLogWarning, "SSU2: SessionConfirmed part 1 AEAD verification failed "); + if (m_SessionConfirmedFragment) m_SessionConfirmedFragment.reset (nullptr); return false; } m_NoiseState->MixHash (buf + 16, 48); // h = SHA256(h || ciphertext); @@ -927,9 +934,11 @@ namespace transport m_NoiseState->m_CK + 32, nonce, decryptedPayload.data (), decryptedPayload.size (), false)) { LogPrint (eLogWarning, "SSU2: SessionConfirmed part 2 AEAD verification failed "); + if (m_SessionConfirmedFragment) m_SessionConfirmedFragment.reset (nullptr); return false; } m_NoiseState->MixHash (payload, len - 64); // h = SHA256(h || ciphertext); + if (m_SessionConfirmedFragment) m_SessionConfirmedFragment.reset (nullptr); // payload // handle RouterInfo block that must be first if (decryptedPayload[0] != eSSU2BlkRouterInfo) From 8eade8662420434c8110abb5e2684514c6be6c07 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 23 Sep 2022 21:27:11 -0400 Subject: [PATCH 160/219] moved InitTransports code from Daemon to Transports --- daemon/Daemon.cpp | 107 +--------------------------------------- libi2pd/Transports.cpp | 109 +++++++++++++++++++++++++++++++++++++++++ libi2pd/Transports.h | 2 + libi2pd/api.cpp | 3 +- 4 files changed, 115 insertions(+), 106 deletions(-) diff --git a/daemon/Daemon.cpp b/daemon/Daemon.cpp index 0b69f511..4d793c67 100644 --- a/daemon/Daemon.cpp +++ b/daemon/Daemon.cpp @@ -31,7 +31,6 @@ #include "Crypto.h" #include "UPnP.h" #include "Timestamp.h" -#include "util.h" #include "I18N.h" namespace i2p @@ -162,110 +161,8 @@ namespace util i2p::context.SetNetID (netID); i2p::context.Init (); - bool ipv6; i2p::config::GetOption("ipv6", ipv6); - bool ipv4; i2p::config::GetOption("ipv4", ipv4); - - // ifname -> address - 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 - } - if (ipv6 && i2p::config::IsDefault ("address6")) - { - std::string ifname6; i2p::config::GetOption("ifname6", ifname6); - if (!ifname6.empty ()) - 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) - { - std::string yggaddress; i2p::config::GetOption ("meshnets.yggaddress", yggaddress); - if (!yggaddress.empty ()) - { - yggaddr = boost::asio::ip::address_v6::from_string (yggaddress); - if (yggaddr.is_unspecified () || !i2p::util::net::IsYggdrasilAddress (yggaddr) || - !i2p::util::net::IsLocalAddress (yggaddr)) - { - LogPrint(eLogWarning, "Daemon: Can't find Yggdrasil address ", yggaddress); - ygg = false; - } - } - else - { - yggaddr = i2p::util::net::GetYggdrasilAddress (); - if (yggaddr.is_unspecified ()) - { - LogPrint(eLogWarning, "Daemon: Yggdrasil is not running. Disabled"); - ygg = false; - } - } - } - - uint16_t port; i2p::config::GetOption("port", port); - if (!i2p::config::IsDefault("port")) - { - LogPrint(eLogInfo, "Daemon: Accepting incoming connections at port ", port); - i2p::context.UpdatePort (port); - } - i2p::context.SetSupportsV6 (ipv6); - i2p::context.SetSupportsV4 (ipv4); - i2p::context.SetSupportsMesh (ygg, yggaddr); - - i2p::context.RemoveNTCPAddress (!ipv6); // TODO: remove later - bool ntcp2; i2p::config::GetOption("ntcp2.enabled", ntcp2); - if (ntcp2) - { - 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); - if (!ntcp2port) ntcp2port = port; // use standard port - i2p::context.PublishNTCP2Address (ntcp2port, true, ipv4, ipv6, false); // publish - if (ipv6) - { - std::string ipv6Addr; i2p::config::GetOption("ntcp2.addressv6", ipv6Addr); - auto addr = boost::asio::ip::address_v6::from_string (ipv6Addr); - if (!addr.is_unspecified () && addr != boost::asio::ip::address_v6::any ()) - i2p::context.UpdateNTCP2V6Address (addr); // set ipv6 address if configured - } - } - else - i2p::context.PublishNTCP2Address (port, false, ipv4, ipv6, false); // unpublish - } - if (ygg) - { - i2p::context.PublishNTCP2Address (port, true, false, false, true); - i2p::context.UpdateNTCP2V6Address (yggaddr); - if (!ipv4 && !ipv6) - i2p::context.SetStatus (eRouterStatusMesh); - } - if (!ssu) i2p::context.RemoveSSUAddress (); // TODO: remove later - bool ssu2; i2p::config::GetOption("ssu2.enabled", ssu2); - if (ssu2) - { - uint16_t ssu2port; i2p::config::GetOption("ssu2.port", ssu2port); - if (!ssu2port) ssu2port = ssu ? (port + 1) : port; - bool published; i2p::config::GetOption("ssu2.published", published); - if (published) - i2p::context.PublishSSU2Address (ssu2port, true, ipv4, ipv6); // publish - else - i2p::context.PublishSSU2Address (ssu2port, false, ipv4, ipv6); // unpublish - } - + i2p::transport::InitTransports (); + bool transit; i2p::config::GetOption("notransit", transit); i2p::context.SetAcceptsTunnels (!transit); uint16_t transitTunnels; i2p::config::GetOption("limits.transittunnels", transitTunnels); diff --git a/libi2pd/Transports.cpp b/libi2pd/Transports.cpp index e80972b8..4dabe37e 100644 --- a/libi2pd/Transports.cpp +++ b/libi2pd/Transports.cpp @@ -977,5 +977,114 @@ namespace transport i2p::context.SetError (eRouterErrorOffline); } } + + void InitTransports () + { + bool ipv6; i2p::config::GetOption("ipv6", ipv6); + bool ipv4; i2p::config::GetOption("ipv4", ipv4); + + // ifname -> address + 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 + } + if (ipv6 && i2p::config::IsDefault ("address6")) + { + std::string ifname6; i2p::config::GetOption("ifname6", ifname6); + if (!ifname6.empty ()) + 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) + { + std::string yggaddress; i2p::config::GetOption ("meshnets.yggaddress", yggaddress); + if (!yggaddress.empty ()) + { + yggaddr = boost::asio::ip::address_v6::from_string (yggaddress); + if (yggaddr.is_unspecified () || !i2p::util::net::IsYggdrasilAddress (yggaddr) || + !i2p::util::net::IsLocalAddress (yggaddr)) + { + LogPrint(eLogWarning, "Transports: Can't find Yggdrasil address ", yggaddress); + ygg = false; + } + } + else + { + yggaddr = i2p::util::net::GetYggdrasilAddress (); + if (yggaddr.is_unspecified ()) + { + LogPrint(eLogWarning, "Transports: Yggdrasil is not running. Disabled"); + ygg = false; + } + } + } + + uint16_t port; i2p::config::GetOption("port", port); + if (!i2p::config::IsDefault("port")) + { + LogPrint(eLogInfo, "Transports: Accepting incoming connections at port ", port); + i2p::context.UpdatePort (port); + } + i2p::context.SetSupportsV6 (ipv6); + i2p::context.SetSupportsV4 (ipv4); + i2p::context.SetSupportsMesh (ygg, yggaddr); + + i2p::context.RemoveNTCPAddress (!ipv6); // TODO: remove later + bool ntcp2; i2p::config::GetOption("ntcp2.enabled", ntcp2); + if (ntcp2) + { + 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); + if (!ntcp2port) ntcp2port = port; // use standard port + i2p::context.PublishNTCP2Address (ntcp2port, true, ipv4, ipv6, false); // publish + if (ipv6) + { + std::string ipv6Addr; i2p::config::GetOption("ntcp2.addressv6", ipv6Addr); + auto addr = boost::asio::ip::address_v6::from_string (ipv6Addr); + if (!addr.is_unspecified () && addr != boost::asio::ip::address_v6::any ()) + i2p::context.UpdateNTCP2V6Address (addr); // set ipv6 address if configured + } + } + else + i2p::context.PublishNTCP2Address (port, false, ipv4, ipv6, false); // unpublish + } + if (ygg) + { + i2p::context.PublishNTCP2Address (port, true, false, false, true); + i2p::context.UpdateNTCP2V6Address (yggaddr); + if (!ipv4 && !ipv6) + i2p::context.SetStatus (eRouterStatusMesh); + } + bool ssu; i2p::config::GetOption("ssu", ssu); + if (!ssu) i2p::context.RemoveSSUAddress (); // TODO: remove later + bool ssu2; i2p::config::GetOption("ssu2.enabled", ssu2); + if (ssu2) + { + uint16_t ssu2port; i2p::config::GetOption("ssu2.port", ssu2port); + if (!ssu2port) ssu2port = ssu ? (port + 1) : port; + bool published; i2p::config::GetOption("ssu2.published", published); + if (published) + i2p::context.PublishSSU2Address (ssu2port, true, ipv4, ipv6); // publish + else + i2p::context.PublishSSU2Address (ssu2port, false, ipv4, ipv6); // unpublish + } + + } } } diff --git a/libi2pd/Transports.h b/libi2pd/Transports.h index 78088a8d..4f33b317 100644 --- a/libi2pd/Transports.h +++ b/libi2pd/Transports.h @@ -195,6 +195,8 @@ namespace transport }; extern Transports transports; + + void InitTransports (); } } diff --git a/libi2pd/api.cpp b/libi2pd/api.cpp index 905fab75..a298e4b4 100644 --- a/libi2pd/api.cpp +++ b/libi2pd/api.cpp @@ -1,5 +1,5 @@ /* -* Copyright (c) 2013-2020, The PurpleI2P Project +* Copyright (c) 2013-2022, The PurpleI2P Project * * This file is part of Purple i2pd project and licensed under BSD3 * @@ -60,6 +60,7 @@ namespace api else i2p::log::Logger().SendTo (i2p::fs::DataDirPath (i2p::fs::GetAppName () + ".log")); i2p::log::Logger().Start (); + i2p::transport::InitTransports (); LogPrint(eLogInfo, "API: Starting NetDB"); i2p::data::netdb.Start(); LogPrint(eLogInfo, "API: Starting Transports"); From 638c376e5b0d9669e6769d685a2b78abc2737c28 Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 24 Sep 2022 16:37:18 -0400 Subject: [PATCH 161/219] enable SSU2 and disable SSU by default --- libi2pd/Config.cpp | 6 +++--- libi2pd/Transports.cpp | 2 ++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/libi2pd/Config.cpp b/libi2pd/Config.cpp index 56da9b7c..2a9955c2 100644 --- a/libi2pd/Config.cpp +++ b/libi2pd/Config.cpp @@ -64,7 +64,7 @@ namespace config { ("bandwidth", value()->default_value(""), "Transit traffic 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") - ("ssu", bool_switch()->default_value(true), "Enable SSU transport (default: enabled)") + ("ssu", bool_switch()->default_value(false), "Enable SSU transport (default: disabled)") ("ntcpproxy", value()->default_value(""), "Ignored") #ifdef _WIN32 ("svcctl", value()->default_value(""), "Ignored") @@ -274,8 +274,8 @@ namespace config { options_description ssu2("SSU2 Options"); ssu2.add_options() - ("ssu2.enabled", value()->default_value(false), "Enable SSU2 (default: disabled)") - ("ssu2.published", value()->default_value(false), "Publish SSU2 (default: disabled)") + ("ssu2.enabled", value()->default_value(true), "Enable SSU2 (default: enabled)") + ("ssu2.published", value()->default_value(true), "Publish SSU2 (default: enabled)") ("ssu2.port", value()->default_value(0), "Port to listen for incoming SSU2 packets (default: auto)") ; diff --git a/libi2pd/Transports.cpp b/libi2pd/Transports.cpp index 4dabe37e..cb6e5dd2 100644 --- a/libi2pd/Transports.cpp +++ b/libi2pd/Transports.cpp @@ -1074,6 +1074,8 @@ namespace transport bool ssu; i2p::config::GetOption("ssu", ssu); if (!ssu) i2p::context.RemoveSSUAddress (); // TODO: remove later bool ssu2; i2p::config::GetOption("ssu2.enabled", ssu2); + if (ssu2 && i2p::config::IsDefault ("ssu2.enabled") && !ipv4 && !ipv6) + ssu2 = false; // don't enable ssu2 for yggdrasil only router if (ssu2) { uint16_t ssu2port; i2p::config::GetOption("ssu2.port", ssu2port); From e338ce7da9b89c2a2a5a6cb2efab108fec91f0ca Mon Sep 17 00:00:00 2001 From: R4SAS Date: Thu, 29 Sep 2022 23:54:50 +0300 Subject: [PATCH 162/219] [docker] update dockerfile, add configuration file (#1788) Signed-off-by: R4SAS --- contrib/docker/Dockerfile | 37 ++++++++++++++++------- contrib/docker/i2pd-docker.conf | 52 +++++++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+), 10 deletions(-) create mode 100644 contrib/docker/i2pd-docker.conf diff --git a/contrib/docker/Dockerfile b/contrib/docker/Dockerfile index 71af141e..129c5ff3 100644 --- a/contrib/docker/Dockerfile +++ b/contrib/docker/Dockerfile @@ -1,5 +1,18 @@ +# +# Copyright (c) 2017-2022, The PurpleI2P Project +# +# This file is part of Purple i2pd project and licensed under BSD3 +# +# See full license text in LICENSE file at top of project tree +# + FROM alpine:latest -LABEL authors "Mikal Villa , Darknet Villain " +LABEL authors="Mikal Villa , Darknet Villain " +LABEL maintainer="R4SAS " + +LABEL org.opencontainers.image.source=https://github.com/PurpleI2P/i2pd +LABEL org.opencontainers.image.documentation=https://i2pd.readthedocs.io/en/latest/ +LABEL org.opencontainers.image.licenses=BSD3 # Expose git branch, tag and URL variables as arguments ARG GIT_BRANCH="openssl" @@ -11,27 +24,28 @@ ENV REPO_URL=${REPO_URL} ENV I2PD_HOME="/home/i2pd" ENV DATA_DIR="${I2PD_HOME}/data" -ENV DEFAULT_ARGS=" --datadir=$DATA_DIR --reseed.verify=true --upnp.enabled=false --http.enabled=true --http.address=0.0.0.0 --httpproxy.enabled=true --httpproxy.address=0.0.0.0 --socksproxy.enabled=true --socksproxy.address=0.0.0.0 --sam.enabled=true --sam.address=0.0.0.0" +ENV DEFAULT_ARGS=" --datadir=$DATA_DIR" RUN mkdir -p "$I2PD_HOME" "$DATA_DIR" \ && adduser -S -h "$I2PD_HOME" i2pd \ && chown -R i2pd:nobody "$I2PD_HOME" -# -# Each RUN is a layer, adding the dependencies and building i2pd in one layer takes around 8-900Mb, so to keep the -# image under 20mb we need to remove all the build dependencies in the same "RUN" / layer. -# -# 1. install deps, clone and build. -# 2. strip binaries. -# 3. Purge all dependencies and other unrelated packages, including build directory. +# 1. Building binary +# Each RUN is a layer, adding the dependencies and building i2pd in one layer takes around 8-900Mb, so to keep the +# image under 20mb we need to remove all the build dependencies in the same "RUN" / layer. +# +# 1. install deps, clone and build. +# 2. strip binaries. +# 3. Purge all dependencies and other unrelated packages, including build directory. + RUN apk update \ && apk --no-cache --virtual build-dependendencies add make gcc g++ libtool zlib-dev boost-dev build-base openssl-dev openssl miniupnpc-dev git \ && mkdir -p /tmp/build \ && cd /tmp/build && git clone -b ${GIT_BRANCH} ${REPO_URL} \ && cd i2pd \ && if [ -n "${GIT_TAG}" ]; then git checkout tags/${GIT_TAG}; fi \ - && make USE_UPNP=yes \ + && make -j$(nproc) USE_UPNP=yes \ && cp -R contrib/certificates /i2pd_certificates \ && mkdir -p /usr/local/bin \ && mv i2pd /usr/local/bin \ @@ -45,6 +59,9 @@ RUN apk update \ # 2. Adding required libraries to run i2pd to ensure it will run. RUN apk --no-cache add boost-filesystem boost-system boost-program_options boost-date_time boost-thread boost-iostreams openssl miniupnpc musl-utils libstdc++ +# 3. Copy preconfigured config file and entrypoint +COPY i2pd-docker.conf "$I2PD_HOME/i2pd.conf" +RUN chown i2pd:nobody "$I2PD_HOME/i2pd.conf" COPY entrypoint.sh /entrypoint.sh RUN chmod a+x /entrypoint.sh diff --git a/contrib/docker/i2pd-docker.conf b/contrib/docker/i2pd-docker.conf new file mode 100644 index 00000000..3b91a235 --- /dev/null +++ b/contrib/docker/i2pd-docker.conf @@ -0,0 +1,52 @@ +## Preconfigured i2pd configuration file for a Docker container +## See https://i2pd.readthedocs.io/en/latest/user-guide/configuration/ +## for more options you can use in this file. + +## Note that for exposing ports outside of container you need to bind all services to 0.0.0.0 + +log = file +loglevel = none + +ipv4 = true +ipv6 = false + +# bandwidth = L +# notransit = false +# floodfill = false + +[ntcp2] +enabled = true +published = true + +[ssu2] +enabled = true +published = true + +[http] +enabled = true +address = 0.0.0.0 +port = 7070 + +[httpproxy] +enabled = true +address = 0.0.0.0 +port = 4444 + +[socksproxy] +enabled = true +address = 0.0.0.0 +port = 4447 + +[sam] +enabled = true +address = 0.0.0.0 +port = 7656 + +[upnp] +enabled = false + +[reseed] +verify = true + +[limits] +# transittunnels = 2500 From cef2263a7f4889573424f30e197cc944b0f1df7d Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 30 Sep 2022 19:24:36 -0400 Subject: [PATCH 163/219] Transports priority for peer --- libi2pd/Transports.cpp | 218 ++++++++++++++++++----------------------- libi2pd/Transports.h | 8 ++ 2 files changed, 104 insertions(+), 122 deletions(-) diff --git a/libi2pd/Transports.cpp b/libi2pd/Transports.cpp index cb6e5dd2..17b0e80e 100644 --- a/libi2pd/Transports.cpp +++ b/libi2pd/Transports.cpp @@ -417,8 +417,7 @@ namespace transport { auto ts = i2p::util::GetSecondsSinceEpoch (); std::unique_lock l(m_PeersMutex); - it = m_Peers.insert (std::pair(ident, { 0, r, {}, - ts, ts + PEER_ROUTER_INFO_UPDATE_INTERVAL, {} })).first; + it = m_Peers.insert (std::pair(ident, {r, ts})).first; } connected = ConnectToPeer (ident, it->second); } @@ -453,127 +452,81 @@ namespace transport peer.router = netdb.FindRouter (ident); // try to get new one from netdb if (peer.router) // we have RI already { - if (peer.numAttempts < 2) // NTCP2, 0 - ipv6, 1 - ipv4 - { - if (m_NTCP2Server) // we support NTCP2 - { - std::shared_ptr address; - if (!peer.numAttempts) // NTCP2 ipv6 - { - if (context.GetRouterInfo ().IsNTCP2V6 () && peer.router->IsReachableBy (RouterInfo::eNTCP2V6)) - { - address = peer.router->GetPublishedNTCP2V6Address (); - if (address && m_CheckReserved && i2p::util::net::IsInReservedRange(address->host)) - address = nullptr; - } - peer.numAttempts++; - } - if (!address && peer.numAttempts == 1) // NTCP2 ipv4 - { - if (context.GetRouterInfo ().IsNTCP2 (true) && peer.router->IsReachableBy (RouterInfo::eNTCP2V4)) - { - address = peer.router->GetPublishedNTCP2V4Address (); - if (address && m_CheckReserved && i2p::util::net::IsInReservedRange(address->host)) - address = nullptr; - } - peer.numAttempts++; - } - if (address) - { - auto s = std::make_shared (*m_NTCP2Server, peer.router, address); - if( m_NTCP2Server->UsingProxy()) - m_NTCP2Server->ConnectWithProxy(s); - else - m_NTCP2Server->Connect (s); - return true; - } - } - else - peer.numAttempts = 2; // switch to SSU - } - if (peer.numAttempts == 2 || peer.numAttempts == 3) // SSU2, 2 - ipv6, 3 - ipv4 - { - if (m_SSU2Server) - { - std::shared_ptr address; - if (peer.numAttempts == 2) // SSU2 ipv6 - { - if (context.GetRouterInfo ().IsSSU2V6 () && peer.router->IsReachableBy (RouterInfo::eSSU2V6)) - { - address = peer.router->GetSSU2V6Address (); - if (address && m_CheckReserved && i2p::util::net::IsInReservedRange(address->host)) - address = nullptr; - } - peer.numAttempts++; - } - if (!address && peer.numAttempts == 3) // SSU2 ipv4 - { - if (context.GetRouterInfo ().IsSSU2V4 () && peer.router->IsReachableBy (RouterInfo::eSSU2V4)) - { - address = peer.router->GetSSU2V4Address (); - if (address && m_CheckReserved && i2p::util::net::IsInReservedRange(address->host)) - address = nullptr; - } - peer.numAttempts++; - } - if (address && address->IsReachableSSU ()) - { - if (m_SSU2Server->CreateSession (peer.router, address)) - return true; - } - } - else - peer.numAttempts += 2; // switch to mesh - } - if (peer.numAttempts == 4) // Mesh + if (peer.priority.empty ()) + SetPriority (peer); + while (peer.numAttempts < (int)peer.priority.size ()) { + auto tr = peer.priority[peer.numAttempts]; peer.numAttempts++; - if (m_NTCP2Server && context.GetRouterInfo ().IsMesh () && peer.router->IsMesh ()) + switch (tr) { - auto address = peer.router->GetYggdrasilAddress (); - if (address) - { - auto s = std::make_shared (*m_NTCP2Server, peer.router, address); - m_NTCP2Server->Connect (s); - return true; - } - } - } - if (peer.numAttempts == 5 || peer.numAttempts == 6) // SSU, 5 - ipv6, 6 - ipv4 - { - if (m_SSUServer) - { - std::shared_ptr address; - if (peer.numAttempts == 5) // SSU ipv6 - { - if (context.GetRouterInfo ().IsSSUV6 () && peer.router->IsReachableBy (RouterInfo::eSSUV6)) + case i2p::data::RouterInfo::eNTCP2V4: + case i2p::data::RouterInfo::eNTCP2V6: + { + if (!m_NTCP2Server) continue; + std::shared_ptr address = (tr == i2p::data::RouterInfo::eNTCP2V6) ? + peer.router->GetPublishedNTCP2V6Address () : peer.router->GetPublishedNTCP2V4Address (); + if (address && m_CheckReserved && i2p::util::net::IsInReservedRange(address->host)) + address = nullptr; + if (address) { - address = peer.router->GetSSUV6Address (); - if (address && m_CheckReserved && i2p::util::net::IsInReservedRange(address->host)) - address = nullptr; - } - peer.numAttempts++; - } - if (!address && peer.numAttempts == 6) // SSU ipv4 - { - if (context.GetRouterInfo ().IsSSU (true) && peer.router->IsReachableBy (RouterInfo::eSSUV4)) - { - address = peer.router->GetSSUAddress (true); - if (address && m_CheckReserved && i2p::util::net::IsInReservedRange(address->host)) - address = nullptr; - } - peer.numAttempts++; - } - if (address && address->IsReachableSSU ()) - { - if (m_SSUServer->CreateSession (peer.router, address)) + auto s = std::make_shared (*m_NTCP2Server, peer.router, address); + if( m_NTCP2Server->UsingProxy()) + m_NTCP2Server->ConnectWithProxy(s); + else + m_NTCP2Server->Connect (s); return true; + } + break; } - } - else - peer.numAttempts += 2; - } - LogPrint (eLogInfo, "Transports: No compatble NTCP2 or SSU addresses available"); + case i2p::data::RouterInfo::eSSU2V4: + case i2p::data::RouterInfo::eSSU2V6: + { + if (!m_SSU2Server) continue; + std::shared_ptr address = (tr == i2p::data::RouterInfo::eSSU2V6) ? + peer.router->GetSSU2V6Address () : peer.router->GetSSU2V4Address (); + if (address && m_CheckReserved && i2p::util::net::IsInReservedRange(address->host)) + address = nullptr; + if (address && address->IsReachableSSU ()) + { + if (m_SSU2Server->CreateSession (peer.router, address)) + return true; + } + break; + } + case i2p::data::RouterInfo::eSSUV4: + case i2p::data::RouterInfo::eSSUV6: + { + if (!m_SSUServer) continue; + std::shared_ptr address = (tr == i2p::data::RouterInfo::eSSUV6) ? + peer.router->GetSSUV6Address () : peer.router->GetSSUAddress (true); + if (address && m_CheckReserved && i2p::util::net::IsInReservedRange(address->host)) + address = nullptr; + if (address && address->IsReachableSSU ()) + { + if (m_SSUServer->CreateSession (peer.router, address)) + return true; + } + break; + } + case i2p::data::RouterInfo::eNTCP2V6Mesh: + { + if (!m_NTCP2Server) continue; + auto address = peer.router->GetYggdrasilAddress (); + if (address) + { + auto s = std::make_shared (*m_NTCP2Server, peer.router, address); + m_NTCP2Server->Connect (s); + return true; + } + break; + } + default: + LogPrint (eLogError, "Transports: Unknown transport ", (int)tr); + } + } + + LogPrint (eLogInfo, "Transports: No compatible addresses available"); i2p::data::netdb.SetUnreachable (ident, true); // we are here because all connection attempts failed peer.Done (); std::unique_lock l(m_PeersMutex); @@ -585,10 +538,32 @@ namespace transport LogPrint (eLogInfo, "Transports: RouterInfo for ", ident.ToBase64 (), " not found, requested"); i2p::data::netdb.RequestDestination (ident, std::bind ( &Transports::RequestComplete, this, std::placeholders::_1, ident)); - } + } return true; - } - + } + + void Transports::SetPriority (Peer& peer) const + { + static const std::vector ntcp2Priority = + { + i2p::data::RouterInfo::eNTCP2V6, + i2p::data::RouterInfo::eNTCP2V4, + i2p::data::RouterInfo::eSSU2V6, + i2p::data::RouterInfo::eSSU2V4, + i2p::data::RouterInfo::eNTCP2V6Mesh, + i2p::data::RouterInfo::eSSUV6, + i2p::data::RouterInfo::eSSUV4 + }; + if (!peer.router) return; + auto compatibleTransports = context.GetRouterInfo ().GetCompatibleTransports (false) & + peer.router->GetCompatibleTransports (true); + peer.numAttempts = 0; + peer.priority.clear (); + for (auto transport: ntcp2Priority) + if (transport & compatibleTransports) + peer.priority.push_back (transport); + } + void Transports::RequestComplete (std::shared_ptr r, const i2p::data::IdentHash& ident) { m_Service->post (std::bind (&Transports::HandleRequestComplete, this, r, ident)); @@ -779,8 +754,7 @@ namespace transport session->SendI2NPMessages ({ CreateDatabaseStoreMsg () }); // send DatabaseStore auto ts = i2p::util::GetSecondsSinceEpoch (); std::unique_lock l(m_PeersMutex); - m_Peers.insert (std::make_pair (ident, Peer{ 0, nullptr, { session }, - ts, ts + PEER_ROUTER_INFO_UPDATE_INTERVAL, {} })); + m_Peers.insert (std::make_pair (ident, Peer{ nullptr, ts })); } }); } diff --git a/libi2pd/Transports.h b/libi2pd/Transports.h index 4f33b317..362c5ead 100644 --- a/libi2pd/Transports.h +++ b/libi2pd/Transports.h @@ -71,7 +71,14 @@ namespace transport std::list > sessions; uint64_t creationTime, nextRouterInfoUpdateTime; std::vector > delayedMessages; + std::vector priority; + Peer (std::shared_ptr r, uint64_t ts): + numAttempts (0), router (r), creationTime (ts), + nextRouterInfoUpdateTime (ts + PEER_ROUTER_INFO_UPDATE_INTERVAL) + { + } + void Done () { for (auto& it: sessions) @@ -147,6 +154,7 @@ namespace transport void HandleRequestComplete (std::shared_ptr r, i2p::data::IdentHash ident); void PostMessages (i2p::data::IdentHash ident, std::vector > msgs); bool ConnectToPeer (const i2p::data::IdentHash& ident, Peer& peer); + void SetPriority (Peer& peer) const; void HandlePeerCleanupTimer (const boost::system::error_code& ecode); void HandlePeerTestTimer (const boost::system::error_code& ecode); From 0a0c2350f2c931b843baa31fbd1cc480b6b805db Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 1 Oct 2022 19:39:08 -0400 Subject: [PATCH 164/219] random seelection between NTCP2 and SSU2 priority --- libi2pd/Transports.cpp | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/libi2pd/Transports.cpp b/libi2pd/Transports.cpp index 17b0e80e..b582ce50 100644 --- a/libi2pd/Transports.cpp +++ b/libi2pd/Transports.cpp @@ -544,7 +544,8 @@ namespace transport void Transports::SetPriority (Peer& peer) const { - static const std::vector ntcp2Priority = + static const std::vector + ntcp2Priority = { i2p::data::RouterInfo::eNTCP2V6, i2p::data::RouterInfo::eNTCP2V4, @@ -553,13 +554,25 @@ namespace transport i2p::data::RouterInfo::eNTCP2V6Mesh, i2p::data::RouterInfo::eSSUV6, i2p::data::RouterInfo::eSSUV4 + }, + ssu2Priority = + { + i2p::data::RouterInfo::eSSU2V6, + i2p::data::RouterInfo::eSSU2V4, + i2p::data::RouterInfo::eNTCP2V6, + i2p::data::RouterInfo::eNTCP2V4, + i2p::data::RouterInfo::eNTCP2V6Mesh, + i2p::data::RouterInfo::eSSUV6, + i2p::data::RouterInfo::eSSUV4 }; if (!peer.router) return; auto compatibleTransports = context.GetRouterInfo ().GetCompatibleTransports (false) & peer.router->GetCompatibleTransports (true); peer.numAttempts = 0; peer.priority.clear (); - for (auto transport: ntcp2Priority) + bool ssu2 = rand () & 1; + const auto& priority = ssu2 ? ssu2Priority : ntcp2Priority; + for (auto transport: priority) if (transport & compatibleTransports) peer.priority.push_back (transport); } From 549dcbee3229f6278f0e96cb60460cce29e1519b Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 3 Oct 2022 15:40:25 -0400 Subject: [PATCH 165/219] don't set port=1 --- libi2pd/Transports.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd/Transports.cpp b/libi2pd/Transports.cpp index b582ce50..f1214889 100644 --- a/libi2pd/Transports.cpp +++ b/libi2pd/Transports.cpp @@ -1066,7 +1066,7 @@ namespace transport if (ssu2) { uint16_t ssu2port; i2p::config::GetOption("ssu2.port", ssu2port); - if (!ssu2port) ssu2port = ssu ? (port + 1) : port; + if (!ssu2port && port) ssu2port = ssu ? (port + 1) : port; bool published; i2p::config::GetOption("ssu2.published", published); if (published) i2p::context.PublishSSU2Address (ssu2port, true, ipv4, ipv6); // publish From 3945f34e9643a66135a5d08145db48118e93c17e Mon Sep 17 00:00:00 2001 From: R4SAS Date: Tue, 4 Oct 2022 09:58:43 +0000 Subject: [PATCH 166/219] [gha] subsequent containers build (#1791) --- .github/workflows/docker.yml | 114 ++++++++++++++++++++++++++++------- 1 file changed, 92 insertions(+), 22 deletions(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 1ac5b552..e4b13645 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -4,16 +4,26 @@ on: push: branches: - openssl + - docker tags: - '*' jobs: - docker: + build: runs-on: ubuntu-latest permissions: packages: write contents: read + strategy: + matrix: + include: [ + { platform: 'linux/amd64', archname: 'amd64' }, + { platform: 'linux/386', archname: 'i386' }, + { platform: 'linux/arm64', archname: 'arm64' }, + { platform: 'linux/arm/v7', archname: 'armv7' }, + ] + steps: - name: Checkout uses: actions/checkout@v2 @@ -25,46 +35,106 @@ jobs: uses: docker/setup-buildx-action@v1 - name: Login to DockerHub - uses: docker/login-action@v1 + uses: docker/login-action@v1 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Login to GitHub Container registry - uses: docker/login-action@v1 + uses: docker/login-action@v1 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - - name: Build and push trunk container - if: ${{ !startsWith(github.ref, 'refs/tags/') }} - uses: docker/build-push-action@v2 + - name: Build container for ${{ matrix.archname }} + uses: docker/build-push-action@v3 with: context: ./contrib/docker file: ./contrib/docker/Dockerfile - platforms: linux/amd64,linux/386,linux/arm64,linux/arm/v7 + platforms: ${{ matrix.platform }} push: true tags: | - purplei2p/i2pd:latest - ghcr.io/purplei2p/i2pd:latest + purplei2p/i2pd:latest-${{ matrix.archname }} + ghcr.io/purplei2p/i2pd:latest-${{ matrix.archname }} - - name: Set env + push: + runs-on: ubuntu-latest + permissions: + packages: write + contents: read + + needs: build + + steps: + - name: Checkout + uses: actions/checkout@v2 + + - name: Set up QEMU + uses: docker/setup-qemu-action@v1 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v1 + + - name: Login to DockerHub + uses: docker/login-action@v1 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Login to GitHub Container registry + uses: docker/login-action@v1 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Create and push latest manifest image to Docker Hub + uses: Noelware/docker-manifest-action@master + with: + base-image: purplei2p/i2pd:latest + extra-images: purplei2p/i2pd:latest-amd64,purplei2p/i2pd:latest-i386,purplei2p/i2pd:latest-arm64,purplei2p/i2pd:latest-armv7 + push: true + + - name: Create and push latest manifest image to GHCR + uses: Noelware/docker-manifest-action@master + with: + base-image: ghcr.io/purplei2p/i2pd:latest + extra-images: ghcr.io/purplei2p/i2pd:latest-amd64,ghcr.io/purplei2p/i2pd:latest-i386,ghcr.io/purplei2p/i2pd:latest-arm64,ghcr.io/purplei2p/i2pd:latest-armv7 + push: true + + - name: Store release version to env if: ${{ startsWith(github.ref, 'refs/tags/') }} run: echo "RELEASE_VERSION=${GITHUB_REF:10}" >> $GITHUB_ENV - - name: Build and push release container + - name: Create and push release manifest image to Docker Hub if: ${{ startsWith(github.ref, 'refs/tags/') }} - uses: docker/build-push-action@v2 + uses: Noelware/docker-manifest-action@master with: - context: ./contrib/docker - file: ./contrib/docker/Dockerfile - platforms: linux/amd64,linux/386,linux/arm64,linux/arm/v7 + base-image: purplei2p/i2pd:latest-release + extra-images: purplei2p/i2pd:latest-amd64,purplei2p/i2pd:latest-i386,purplei2p/i2pd:latest-arm64,purplei2p/i2pd:latest-armv7 + push: true + + - name: Create and push release manifest image to GHCR + if: ${{ startsWith(github.ref, 'refs/tags/') }} + uses: Noelware/docker-manifest-action@master + with: + base-image: ghcr.io/purplei2p/i2pd:latest-release + extra-images: ghcr.io/purplei2p/i2pd:latest-amd64,ghcr.io/purplei2p/i2pd:latest-i386,ghcr.io/purplei2p/i2pd:latest-arm64,ghcr.io/purplei2p/i2pd:latest-armv7 + push: true + + - name: Create and push versioned manifest image to Docker Hub + if: ${{ startsWith(github.ref, 'refs/tags/') }} + uses: Noelware/docker-manifest-action@master + with: + base-image: purplei2p/i2pd:release-${{ env.RELEASE_VERSION }} + extra-images: purplei2p/i2pd:latest-amd64,purplei2p/i2pd:latest-i386,purplei2p/i2pd:latest-arm64,purplei2p/i2pd:latest-armv7 + push: true + + - name: Create and push versioned manifest image to GHCR + if: ${{ startsWith(github.ref, 'refs/tags/') }} + uses: Noelware/docker-manifest-action@master + with: + base-image: ghcr.io/purplei2p/i2pd:release-${{ env.RELEASE_VERSION }} + extra-images: ghcr.io/purplei2p/i2pd:latest-amd64,ghcr.io/purplei2p/i2pd:latest-i386,ghcr.io/purplei2p/i2pd:latest-arm64,ghcr.io/purplei2p/i2pd:latest-armv7 push: true - tags: | - purplei2p/i2pd:latest - purplei2p/i2pd:latest-release - purplei2p/i2pd:release-${{ env.RELEASE_VERSION }} - ghcr.io/purplei2p/i2pd:latest - ghcr.io/purplei2p/i2pd:latest-release - ghcr.io/purplei2p/i2pd:release-${{ env.RELEASE_VERSION }} From 69ca3bc75da0e9c872657f6fc02de5251ac21ecd Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 6 Oct 2022 18:48:17 -0400 Subject: [PATCH 167/219] catch lexical_cast exceptions --- libi2pd/RouterInfo.cpp | 59 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 52 insertions(+), 7 deletions(-) diff --git a/libi2pd/RouterInfo.cpp b/libi2pd/RouterInfo.cpp index 7368001d..60fd3358 100644 --- a/libi2pd/RouterInfo.cpp +++ b/libi2pd/RouterInfo.cpp @@ -257,20 +257,38 @@ namespace data if (!ecode && !address->host.is_unspecified ()) isHost = true; } else if (!strcmp (key, "port")) - address->port = boost::lexical_cast(value); + { + try + { + address->port = boost::lexical_cast(value); + } + catch (std::exception& ex) + { + LogPrint (eLogWarning, "RouterInfo: 'port' exception ", ex.what ()); + } + } else if (!strcmp (key, "mtu")) { if (address->ssu) - address->ssu->mtu = boost::lexical_cast(value); + { + try + { + address->ssu->mtu = boost::lexical_cast(value); + } + catch (std::exception& ex) + { + LogPrint (eLogWarning, "RouterInfo: 'mtu' exception ", ex.what ()); + } + } else - LogPrint (eLogWarning, "RouterInfo: Unexpected field 'mtu' for NTCP"); + LogPrint (eLogWarning, "RouterInfo: Unexpected field 'mtu' for NTCP2"); } else if (!strcmp (key, "key")) { if (address->ssu) isIntroKey = (Base64ToByteStream (value, strlen (value), address->i, 32) == 32); else - LogPrint (eLogWarning, "RouterInfo: Unexpected field 'key' for NTCP"); + LogPrint (eLogWarning, "RouterInfo: Unexpected field 'key' for NTCP2"); } else if (!strcmp (key, "caps")) address->caps = ExtractAddressCaps (value); @@ -327,13 +345,40 @@ namespace data introducer.iHost = boost::asio::ip::address::from_string (value, ecode); } else if (!strcmp (key, "iport")) - introducer.iPort = boost::lexical_cast(value); + { + try + { + introducer.iPort = boost::lexical_cast(value); + } + catch (std::exception& ex) + { + LogPrint (eLogWarning, "RouterInfo: 'iport' exception ", ex.what ()); + } + } else if (!strcmp (key, "itag")) - introducer.iTag = boost::lexical_cast(value); + { + try + { + introducer.iTag = boost::lexical_cast(value); + } + catch (std::exception& ex) + { + LogPrint (eLogWarning, "RouterInfo: 'itag' exception ", ex.what ()); + } + } else if (!strcmp (key, "ikey") || !strcmp (key, "ih")) Base64ToByteStream (value, strlen (value), introducer.iKey, 32); else if (!strcmp (key, "iexp")) - introducer.iExp = boost::lexical_cast(value); + { + try + { + introducer.iExp = boost::lexical_cast(value); + } + catch (std::exception& ex) + { + LogPrint (eLogWarning, "RouterInfo: 'iexp' exception ", ex.what ()); + } + } } if (!s) return; } From 8f9dae85569ddfc4bdf7130b689b027be3c7de62 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Sun, 9 Oct 2022 02:06:50 +0300 Subject: [PATCH 168/219] [webconsole] enable tunnels reload command (closes #1781) Signed-off-by: R4SAS --- daemon/HTTPServer.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/daemon/HTTPServer.cpp b/daemon/HTTPServer.cpp index 071627e2..dfead4d2 100644 --- a/daemon/HTTPServer.cpp +++ b/daemon/HTTPServer.cpp @@ -80,7 +80,7 @@ namespace http { const char HTTP_COMMAND_SHUTDOWN_CANCEL[] = "shutdown_cancel"; const char HTTP_COMMAND_SHUTDOWN_NOW[] = "terminate"; const char HTTP_COMMAND_RUN_PEER_TEST[] = "run_peer_test"; - const char HTTP_COMMAND_RELOAD_CONFIG[] = "reload_config"; + const char HTTP_COMMAND_RELOAD_TUNNELS_CONFIG[] = "reload_tunnels_config"; const char HTTP_COMMAND_LOGLEVEL[] = "set_loglevel"; const char HTTP_COMMAND_KILLSTREAM[] = "closestream"; const char HTTP_COMMAND_LIMITTRANSIT[] = "limittransit"; @@ -698,8 +698,7 @@ namespace http { s << "" << tr("Router commands") << "
\r\n
\r\n
\r\n"; s << " " << tr("Run peer test") << "
\r\n"; - - // s << " Reload config
\r\n"; + s << " " << tr("Reload tunnels configuration") << "
\r\n"; if (i2p::context.AcceptsTunnels ()) s << " " << tr("Decline transit tunnels") << "
\r\n"; @@ -1246,7 +1245,7 @@ namespace http { std::string cmd = params["cmd"]; if (cmd == HTTP_COMMAND_RUN_PEER_TEST) i2p::transport::transports.PeerTest (); - else if (cmd == HTTP_COMMAND_RELOAD_CONFIG) + else if (cmd == HTTP_COMMAND_RELOAD_TUNNELS_CONFIG) i2p::client::context.ReloadConfig (); else if (cmd == HTTP_COMMAND_ENABLE_TRANSIT) i2p::context.SetAcceptsTunnels (true); From e82662b3899fb9c0123e34db91c244b1fbb97162 Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 8 Oct 2022 21:41:28 -0400 Subject: [PATCH 169/219] SSL support for server tunnels --- libi2pd_client/BOB.cpp | 2 +- libi2pd_client/ClientContext.cpp | 7 +- libi2pd_client/ClientContext.h | 4 +- libi2pd_client/I2PTunnel.cpp | 140 +++++++++++++++++++++---------- libi2pd_client/I2PTunnel.h | 35 +++++--- 5 files changed, 126 insertions(+), 62 deletions(-) diff --git a/libi2pd_client/BOB.cpp b/libi2pd_client/BOB.cpp index a8520e9b..f956186f 100644 --- a/libi2pd_client/BOB.cpp +++ b/libi2pd_client/BOB.cpp @@ -156,7 +156,7 @@ namespace client { if (stream) { - auto conn = std::make_shared (this, stream, std::make_shared (GetService ()), m_Endpoint, m_IsQuiet); + auto conn = std::make_shared (this, stream, m_Endpoint, m_IsQuiet); AddHandler (conn); conn->Connect (); } diff --git a/libi2pd_client/ClientContext.cpp b/libi2pd_client/ClientContext.cpp index 3f670f06..a5e1c67c 100644 --- a/libi2pd_client/ClientContext.cpp +++ b/libi2pd_client/ClientContext.cpp @@ -726,7 +726,8 @@ namespace client std::string address = section.second.get (I2P_SERVER_TUNNEL_ADDRESS, ""); bool isUniqueLocal = section.second.get(I2P_SERVER_TUNNEL_ENABLE_UNIQUE_LOCAL, true); - + bool ssl = section.second.get(I2P_SERVER_TUNNEL_SSL, false); + // I2CP std::map options; ReadI2CPOptions (section, true, options); @@ -799,11 +800,13 @@ namespace client if (!address.empty ()) serverTunnel->SetLocalAddress (address); - if(!isUniqueLocal) + if (!isUniqueLocal) { LogPrint(eLogInfo, "Clients: Disabling loopback address mapping"); serverTunnel->SetUniqueLocal(isUniqueLocal); } + if (ssl) + serverTunnel->SetSSL (true); if (accessList.length () > 0) { std::set idents; diff --git a/libi2pd_client/ClientContext.h b/libi2pd_client/ClientContext.h index d512a55b..ded8ea75 100644 --- a/libi2pd_client/ClientContext.h +++ b/libi2pd_client/ClientContext.h @@ -1,5 +1,5 @@ /* -* Copyright (c) 2013-2021, The PurpleI2P Project +* Copyright (c) 2013-2022, The PurpleI2P Project * * This file is part of Purple i2pd project and licensed under BSD3 * @@ -61,7 +61,7 @@ namespace client const char I2P_SERVER_TUNNEL_WEBIRC_PASSWORD[] = "webircpassword"; const char I2P_SERVER_TUNNEL_ADDRESS[] = "address"; const char I2P_SERVER_TUNNEL_ENABLE_UNIQUE_LOCAL[] = "enableuniquelocal"; - + const char I2P_SERVER_TUNNEL_SSL[] = "ssl"; class ClientContext { diff --git a/libi2pd_client/I2PTunnel.cpp b/libi2pd_client/I2PTunnel.cpp index 12c6485f..ab73c672 100644 --- a/libi2pd_client/I2PTunnel.cpp +++ b/libi2pd_client/I2PTunnel.cpp @@ -21,7 +21,7 @@ namespace client { /** set standard socket options */ - static void I2PTunnelSetSocketOptions(std::shared_ptr socket) + static void I2PTunnelSetSocketOptions (std::shared_ptr socket) { if (socket && socket->is_open()) { @@ -46,10 +46,13 @@ namespace client } I2PTunnelConnection::I2PTunnelConnection (I2PService * owner, std::shared_ptr stream, - std::shared_ptr socket, const boost::asio::ip::tcp::endpoint& target, bool quiet): - I2PServiceHandler(owner), m_Socket (socket), m_Stream (stream), - m_RemoteEndpoint (target), m_IsQuiet (quiet) + const boost::asio::ip::tcp::endpoint& target, bool quiet, + std::shared_ptr sslCtx): + I2PServiceHandler(owner), m_Stream (stream), m_RemoteEndpoint (target), m_IsQuiet (quiet) { + m_Socket = std::make_shared (owner->GetService ()); + if (sslCtx) + m_SSL = std::make_shared > (*m_Socket, *sslCtx); } I2PTunnelConnection::~I2PTunnelConnection () @@ -80,24 +83,26 @@ namespace client } #ifdef __linux__ - static void MapToLoopback(const std::shared_ptr & sock, const i2p::data::IdentHash & addr) + static void MapToLoopback(std::shared_ptr sock, const i2p::data::IdentHash & addr) { - // bind to 127.x.x.x address - // where x.x.x are first three bytes from ident - auto ourIP = GetLoopbackAddressFor(addr); - 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 ()); - + if (sock) + { + // bind to 127.x.x.x address + // where x.x.x are first three bytes from ident + auto ourIP = GetLoopbackAddressFor(addr); + 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 void I2PTunnelConnection::Connect (bool isUniqueLocal) { - I2PTunnelSetSocketOptions(m_Socket); if (m_Socket) - { + { + I2PTunnelSetSocketOptions (m_Socket); #ifdef __linux__ if (isUniqueLocal && m_RemoteEndpoint.address ().is_v4 () && m_RemoteEndpoint.address ().to_v4 ().to_bytes ()[0] == 127) @@ -127,10 +132,11 @@ namespace client } Connect (false); } - + void I2PTunnelConnection::Terminate () { if (Kill()) return; + if (m_SSL) m_SSL = nullptr; if (m_Stream) { m_Stream->Close (); @@ -145,12 +151,17 @@ namespace client void I2PTunnelConnection::Receive () { - m_Socket->async_read_some (boost::asio::buffer(m_Buffer, I2P_TUNNEL_CONNECTION_BUFFER_SIZE), - std::bind(&I2PTunnelConnection::HandleReceived, shared_from_this (), - std::placeholders::_1, std::placeholders::_2)); + if (m_SSL) + m_Socket->async_read_some (boost::asio::buffer(m_Buffer, I2P_TUNNEL_CONNECTION_BUFFER_SIZE), + std::bind(&I2PTunnelConnection::HandleReceive, shared_from_this (), + std::placeholders::_1, std::placeholders::_2)); + else + m_Socket->async_read_some (boost::asio::buffer(m_Buffer, I2P_TUNNEL_CONNECTION_BUFFER_SIZE), + std::bind(&I2PTunnelConnection::HandleReceive, shared_from_this (), + std::placeholders::_1, std::placeholders::_2)); } - void I2PTunnelConnection::HandleReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred) + void I2PTunnelConnection::HandleReceive (const boost::system::error_code& ecode, std::size_t bytes_transferred) { if (ecode) { @@ -239,8 +250,12 @@ namespace client void I2PTunnelConnection::Write (const uint8_t * buf, size_t len) { - boost::asio::async_write (*m_Socket, boost::asio::buffer (buf, len), boost::asio::transfer_all (), - std::bind (&I2PTunnelConnection::HandleWrite, shared_from_this (), std::placeholders::_1)); + if (m_SSL) + boost::asio::async_write (*m_SSL, boost::asio::buffer (buf, len), boost::asio::transfer_all (), + std::bind (&I2PTunnelConnection::HandleWrite, shared_from_this (), std::placeholders::_1)); + else + boost::asio::async_write (*m_Socket, boost::asio::buffer (buf, len), boost::asio::transfer_all (), + std::bind (&I2PTunnelConnection::HandleWrite, shared_from_this (), std::placeholders::_1)); } void I2PTunnelConnection::HandleConnect (const boost::system::error_code& ecode) @@ -253,22 +268,45 @@ namespace client else { LogPrint (eLogDebug, "I2PTunnel: Connected"); - if (m_IsQuiet) - StreamReceive (); - else - { - // send destination first like received from I2P - std::string dest = m_Stream->GetRemoteIdentity ()->ToBase64 (); - dest += "\n"; - if(sizeof(m_StreamBuffer) >= dest.size()) { - memcpy (m_StreamBuffer, dest.c_str (), dest.size ()); - } - HandleStreamReceive (boost::system::error_code (), dest.size ()); - } - Receive (); + if (m_SSL) + m_SSL->async_handshake (boost::asio::ssl::stream_base::client, + std::bind (&I2PTunnelConnection::HandleHandshake, shared_from_this (), std::placeholders::_1)); + else + Established (); } } + void I2PTunnelConnection::HandleHandshake (const boost::system::error_code& ecode) + { + if (ecode) + { + LogPrint (eLogError, "I2PTunnel: Handshake error: ", ecode.message ()); + Terminate (); + } + else + { + LogPrint (eLogDebug, "I2PTunnel: SSL connected"); + Established (); + } + } + + void I2PTunnelConnection::Established () + { + if (m_IsQuiet) + StreamReceive (); + else + { + // send destination first like received from I2P + std::string dest = m_Stream->GetRemoteIdentity ()->ToBase64 (); + dest += "\n"; + if(sizeof(m_StreamBuffer) >= dest.size()) { + memcpy (m_StreamBuffer, dest.c_str (), dest.size ()); + } + HandleStreamReceive (boost::system::error_code (), dest.size ()); + } + Receive (); + } + void I2PClientTunnelConnectionHTTP::Write (const uint8_t * buf, size_t len) { if (m_HeaderSent) @@ -332,11 +370,13 @@ namespace client } I2PServerTunnelConnectionHTTP::I2PServerTunnelConnectionHTTP (I2PService * owner, std::shared_ptr stream, - std::shared_ptr socket, - const boost::asio::ip::tcp::endpoint& target, const std::string& host): - I2PTunnelConnection (owner, stream, socket, target), m_Host (host), + const boost::asio::ip::tcp::endpoint& target, const std::string& host, + std::shared_ptr sslCtx): + I2PTunnelConnection (owner, stream, target, true, sslCtx), m_Host (host), m_HeaderSent (false), m_ResponseHeaderSent (false), m_From (stream->GetRemoteIdentity ()) { + if (sslCtx) + SSL_set_tlsext_host_name(GetSSL ()->native_handle(), host.c_str ()); } void I2PServerTunnelConnectionHTTP::Write (const uint8_t * buf, size_t len) @@ -474,9 +514,8 @@ namespace client } I2PTunnelConnectionIRC::I2PTunnelConnectionIRC (I2PService * owner, std::shared_ptr stream, - std::shared_ptr socket, const boost::asio::ip::tcp::endpoint& target, const std::string& webircpass): - I2PTunnelConnection (owner, stream, socket, target), m_From (stream->GetRemoteIdentity ()), + I2PTunnelConnection (owner, stream, target), m_From (stream->GetRemoteIdentity ()), m_NeedsWebIrc (webircpass.length() ? true : false), m_WebircPass (webircpass) { } @@ -487,7 +526,8 @@ namespace client if (m_NeedsWebIrc) { m_NeedsWebIrc = false; - m_OutPacket << "WEBIRC " << m_WebircPass << " cgiirc " << context.GetAddressBook ().ToAddress (m_From->GetIdentHash ()) << " " << GetSocket ()->local_endpoint ().address () << std::endl; + m_OutPacket << "WEBIRC " << m_WebircPass << " cgiirc " << context.GetAddressBook ().ToAddress (m_From->GetIdentHash ()) + << " " << GetSocket ()->local_endpoint ().address () << std::endl; } m_InPacket.clear (); @@ -753,6 +793,17 @@ namespace client LogPrint (eLogError, "I2PTunnel: Can't set local address ", localAddress); } + void I2PServerTunnel::SetSSL (bool ssl) + { + if (ssl) + { + m_SSLCtx = std::make_shared (boost::asio::ssl::context::sslv23); + m_SSLCtx->set_verify_mode(boost::asio::ssl::context::verify_none); + } + else + m_SSLCtx = nullptr; + } + void I2PServerTunnel::Accept () { if (m_PortDestination) @@ -793,7 +844,7 @@ namespace client std::shared_ptr I2PServerTunnel::CreateI2PConnection (std::shared_ptr stream) { - return std::make_shared (this, stream, std::make_shared (GetService ()), GetEndpoint ()); + return std::make_shared (this, stream, GetEndpoint (), true, m_SSLCtx); } @@ -807,8 +858,7 @@ namespace client std::shared_ptr I2PServerTunnelHTTP::CreateI2PConnection (std::shared_ptr stream) { - return std::make_shared (this, stream, - std::make_shared (GetService ()), GetEndpoint (), m_Host); + return std::make_shared (this, stream, GetEndpoint (), m_Host, GetSSLCtx ()); } I2PServerTunnelIRC::I2PServerTunnelIRC (const std::string& name, const std::string& address, @@ -821,7 +871,7 @@ namespace client std::shared_ptr I2PServerTunnelIRC::CreateI2PConnection (std::shared_ptr stream) { - return std::make_shared (this, stream, std::make_shared (GetService ()), GetEndpoint (), this->m_WebircPass); + return std::make_shared (this, stream, GetEndpoint (), m_WebircPass); } void I2PUDPServerTunnel::HandleRecvFromI2P(const i2p::data::IdentityEx& from, uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len) diff --git a/libi2pd_client/I2PTunnel.h b/libi2pd_client/I2PTunnel.h index 90c5864e..4f61ef91 100644 --- a/libi2pd_client/I2PTunnel.h +++ b/libi2pd_client/I2PTunnel.h @@ -16,6 +16,7 @@ #include #include #include +#include #include "Identity.h" #include "Destination.h" #include "Datagram.h" @@ -44,8 +45,9 @@ namespace client std::shared_ptr leaseSet, int port = 0); // to I2P I2PTunnelConnection (I2PService * owner, std::shared_ptr socket, std::shared_ptr stream); // to I2P using simplified API - I2PTunnelConnection (I2PService * owner, std::shared_ptr stream, std::shared_ptr socket, - const boost::asio::ip::tcp::endpoint& target, bool quiet = true); // from I2P + I2PTunnelConnection (I2PService * owner, std::shared_ptr stream, + const boost::asio::ip::tcp::endpoint& target, bool quiet = true, + std::shared_ptr sslCtx = nullptr); // from I2P ~I2PTunnelConnection (); void I2PConnect (const uint8_t * msg = nullptr, size_t len = 0); void Connect (bool isUniqueLocal = true); @@ -56,21 +58,27 @@ namespace client void Terminate (); void Receive (); - void HandleReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred); + void StreamReceive (); virtual void Write (const uint8_t * buf, size_t len); // can be overloaded - void HandleWrite (const boost::system::error_code& ecode); virtual void WriteToStream (const uint8_t * buf, size_t len); // can be overloaded - void StreamReceive (); - void HandleStreamReceive (const boost::system::error_code& ecode, std::size_t bytes_transferred); + std::shared_ptr GetSocket () const { return m_Socket; }; + std::shared_ptr > GetSSL () const { return m_SSL; }; + + private: + void HandleConnect (const boost::system::error_code& ecode); - - std::shared_ptr GetSocket () const { return m_Socket; }; - + void HandleHandshake (const boost::system::error_code& ecode); + void Established (); + void HandleReceive (const boost::system::error_code& ecode, std::size_t bytes_transferred); + void HandleWrite (const boost::system::error_code& ecode); + void HandleStreamReceive (const boost::system::error_code& ecode, std::size_t bytes_transferred); + private: uint8_t m_Buffer[I2P_TUNNEL_CONNECTION_BUFFER_SIZE], m_StreamBuffer[I2P_TUNNEL_CONNECTION_BUFFER_SIZE]; std::shared_ptr m_Socket; + std::shared_ptr > m_SSL; std::shared_ptr m_Stream; boost::asio::ip::tcp::endpoint m_RemoteEndpoint; bool m_IsQuiet; // don't send destination @@ -100,8 +108,8 @@ namespace client public: I2PServerTunnelConnectionHTTP (I2PService * owner, std::shared_ptr stream, - std::shared_ptr socket, - const boost::asio::ip::tcp::endpoint& target, const std::string& host); + const boost::asio::ip::tcp::endpoint& target, const std::string& host, + std::shared_ptr sslCtx = nullptr); protected: @@ -121,7 +129,6 @@ namespace client public: I2PTunnelConnectionIRC (I2PService * owner, std::shared_ptr stream, - std::shared_ptr socket, const boost::asio::ip::tcp::endpoint& target, const std::string& m_WebircPass); protected: @@ -343,6 +350,9 @@ namespace client void SetUniqueLocal (bool isUniqueLocal) { m_IsUniqueLocal = isUniqueLocal; } bool IsUniqueLocal () const { return m_IsUniqueLocal; } + void SetSSL (bool ssl); + std::shared_ptr GetSSLCtx () const { return m_SSLCtx; }; + void SetLocalAddress (const std::string& localAddress); const std::string& GetAddress() const { return m_Address; } @@ -371,6 +381,7 @@ namespace client std::set m_AccessList; bool m_IsAccessList; std::unique_ptr m_LocalAddress; + std::shared_ptr m_SSLCtx; }; class I2PServerTunnelHTTP: public I2PServerTunnel From 6b939eba597f2d6e20190464708552b5573119ec Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 9 Oct 2022 09:54:48 -0400 Subject: [PATCH 170/219] fixed typo --- libi2pd_client/I2PTunnel.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd_client/I2PTunnel.cpp b/libi2pd_client/I2PTunnel.cpp index ab73c672..8bf0e38d 100644 --- a/libi2pd_client/I2PTunnel.cpp +++ b/libi2pd_client/I2PTunnel.cpp @@ -152,7 +152,7 @@ namespace client void I2PTunnelConnection::Receive () { if (m_SSL) - m_Socket->async_read_some (boost::asio::buffer(m_Buffer, I2P_TUNNEL_CONNECTION_BUFFER_SIZE), + m_SSL->async_read_some (boost::asio::buffer(m_Buffer, I2P_TUNNEL_CONNECTION_BUFFER_SIZE), std::bind(&I2PTunnelConnection::HandleReceive, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); else From 714b3856a23fd93038a11ab33cb0af9d483fce9d Mon Sep 17 00:00:00 2001 From: R4SAS Date: Sun, 9 Oct 2022 18:04:54 +0300 Subject: [PATCH 171/219] [SSU2] print to log when peer test is sent Signed-off-by: R4SAS --- libi2pd/SSU2Session.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index 68b26223..cddb45d4 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -184,6 +184,7 @@ namespace transport { payloadSize += CreatePaddingBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize); SendData (payload, payloadSize); + LogPrint (eLogInfo, "SSU2: Peer test sent to ", i2p::data::GetIdentHashAbbreviation (GetRemoteIdentity ()->GetIdentHash ())); } } From 650b7abef62afdd5397e3c4c6f70f8987c5d0831 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Sun, 9 Oct 2022 19:17:28 +0300 Subject: [PATCH 172/219] [SSU2] add log messages about peertest Signed-off-by: R4SAS --- libi2pd/SSU2Session.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index cddb45d4..8dd4884e 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -184,7 +184,7 @@ namespace transport { payloadSize += CreatePaddingBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize); SendData (payload, payloadSize); - LogPrint (eLogInfo, "SSU2: Peer test sent to ", i2p::data::GetIdentHashAbbreviation (GetRemoteIdentity ()->GetIdentHash ())); + LogPrint (eLogDebug, "SSU2: PeerTest sent to ", i2p::data::GetIdentHashAbbreviation (GetRemoteIdentity ()->GetIdentHash ())); } } @@ -2100,7 +2100,9 @@ namespace transport else m_Server.RescheduleIntroducersUpdateTimerV6 (); } - } + } + LogPrint (eLogDebug, "SSU2: Peer test 4 received from ", i2p::data::GetIdentHashAbbreviation (GetRemoteIdentity ()->GetIdentHash ()), + " with information about ", i2p::data::GetIdentHashAbbreviation (i2p::data::IdentHash (buf + 3))); } else { @@ -2114,6 +2116,10 @@ namespace transport it->second.first->Done (); } } + else + { + LogPrint (eLogWarning, "SSU2: Peer test 4 Charlie's Router Info is not found"); + } } else { From 96c4463d39ac74a8ceb7527f3619775704a52cd6 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Sun, 9 Oct 2022 20:24:43 +0300 Subject: [PATCH 173/219] clean code Signed-off-by: R4SAS --- daemon/Daemon.cpp | 2 +- daemon/HTTPServer.cpp | 2 +- daemon/I2PControl.h | 4 +- daemon/I2PControlHandlers.cpp | 14 +- daemon/I2PControlHandlers.h | 12 +- libi2pd/NetDb.cpp | 18 +- libi2pd/NetDb.hpp | 4 +- libi2pd/RouterContext.cpp | 54 +-- libi2pd/RouterInfo.cpp | 78 ++--- libi2pd/RouterInfo.h | 4 +- libi2pd/SSU2.cpp | 242 +++++++------- libi2pd/SSU2.h | 18 +- libi2pd/SSU2Session.cpp | 546 +++++++++++++++---------------- libi2pd/SSU2Session.h | 22 +- libi2pd/TransportSession.h | 10 +- libi2pd/Transports.cpp | 42 +-- libi2pd/Transports.h | 8 +- libi2pd_client/AddressBook.cpp | 4 +- libi2pd_client/ClientContext.cpp | 4 +- libi2pd_client/I2PTunnel.cpp | 48 +-- libi2pd_client/I2PTunnel.h | 8 +- libi2pd_client/SAM.cpp | 4 +- 22 files changed, 574 insertions(+), 574 deletions(-) diff --git a/daemon/Daemon.cpp b/daemon/Daemon.cpp index 4d793c67..bff17e09 100644 --- a/daemon/Daemon.cpp +++ b/daemon/Daemon.cpp @@ -162,7 +162,7 @@ namespace util i2p::context.Init (); i2p::transport::InitTransports (); - + 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 dfead4d2..8d57dedb 100644 --- a/daemon/HTTPServer.cpp +++ b/daemon/HTTPServer.cpp @@ -250,7 +250,7 @@ namespace http { break; default: ; } - } + } } void ShowStatus (std::stringstream& s, bool includeHiddenContent, i2p::http::OutputFormatEnum outputFormat) diff --git a/daemon/I2PControl.h b/daemon/I2PControl.h index 9a80da9a..af152631 100644 --- a/daemon/I2PControl.h +++ b/daemon/I2PControl.h @@ -63,7 +63,7 @@ namespace client void CreateCertificate (const char *crt_path, const char *key_path); private: - + // methods typedef void (I2PControlService::*MethodHandler)(const boost::property_tree::ptree& params, std::ostringstream& results); @@ -71,7 +71,7 @@ namespace client void EchoHandler (const boost::property_tree::ptree& params, std::ostringstream& results); void I2PControlHandler (const boost::property_tree::ptree& params, std::ostringstream& results); void RouterManagerHandler (const boost::property_tree::ptree& params, std::ostringstream& results); - + // I2PControl typedef void (I2PControlService::*I2PControlRequestHandler)(const std::string& value); void PasswordHandler (const std::string& value); diff --git a/daemon/I2PControlHandlers.cpp b/daemon/I2PControlHandlers.cpp index 02508f29..15763948 100644 --- a/daemon/I2PControlHandlers.cpp +++ b/daemon/I2PControlHandlers.cpp @@ -43,7 +43,7 @@ namespace client // NetworkSetting m_NetworkSettingHandlers["i2p.router.net.bw.in"] = &I2PControlHandlers::InboundBandwidthLimit; m_NetworkSettingHandlers["i2p.router.net.bw.out"] = &I2PControlHandlers::OutboundBandwidthLimit; - + // ClientServicesInfo m_ClientServicesInfoHandlers["I2PTunnel"] = &I2PControlHandlers::I2PTunnelInfoHandler; m_ClientServicesInfoHandlers["HTTPProxy"] = &I2PControlHandlers::HTTPProxyInfoHandler; @@ -51,7 +51,7 @@ namespace client m_ClientServicesInfoHandlers["SAM"] = &I2PControlHandlers::SAMInfoHandler; m_ClientServicesInfoHandlers["BOB"] = &I2PControlHandlers::BOBInfoHandler; m_ClientServicesInfoHandlers["I2CP"] = &I2PControlHandlers::I2CPInfoHandler; - } + } void I2PControlHandlers::InsertParam (std::ostringstream& ss, const std::string& name, int value) const { @@ -76,7 +76,7 @@ namespace client { ss << "\"" << name << "\":" << std::fixed << std::setprecision(2) << value; } - + void I2PControlHandlers::InsertParam (std::ostringstream& ss, const std::string& name, const boost::property_tree::ptree& value) const { std::ostringstream buf; @@ -167,8 +167,8 @@ namespace client void I2PControlHandlers::NetTotalSentBytes (std::ostringstream& results) { InsertParam (results, "i2p.router.net.total.sent.bytes", (double)i2p::transport::transports.GetTotalSentBytes ()); - } - + } + // network setting void I2PControlHandlers::NetworkSettingHandler (const boost::property_tree::ptree& params, std::ostringstream& results) { @@ -199,7 +199,7 @@ namespace client int bw = i2p::context.GetBandwidthLimit(); InsertParam (results, "i2p.router.net.bw.out", bw); } - + // ClientServicesInfo void I2PControlHandlers::ClientServicesInfoHandler (const boost::property_tree::ptree& params, std::ostringstream& results) @@ -217,7 +217,7 @@ namespace client LogPrint (eLogError, "I2PControl: ClientServicesInfo unknown request ", it->first); } } - + void I2PControlHandlers::I2PTunnelInfoHandler (std::ostringstream& results) { boost::property_tree::ptree pt; diff --git a/daemon/I2PControlHandlers.h b/daemon/I2PControlHandlers.h index 32adce8b..e33a19fc 100644 --- a/daemon/I2PControlHandlers.h +++ b/daemon/I2PControlHandlers.h @@ -29,14 +29,14 @@ namespace client void RouterInfoHandler (const boost::property_tree::ptree& params, std::ostringstream& results); void NetworkSettingHandler (const boost::property_tree::ptree& params, std::ostringstream& results); void ClientServicesInfoHandler (const boost::property_tree::ptree& params, std::ostringstream& results); - + protected: void InsertParam (std::ostringstream& ss, const std::string& name, int value) const; void InsertParam (std::ostringstream& ss, const std::string& name, double value) const; void InsertParam (std::ostringstream& ss, const std::string& name, const std::string& value, bool quotes = true) const; - void InsertParam (std::ostringstream& ss, const std::string& name, const boost::property_tree::ptree& value) const; - + void InsertParam (std::ostringstream& ss, const std::string& name, const boost::property_tree::ptree& value) const; + private: // RouterInfo @@ -53,12 +53,12 @@ namespace client void OutboundBandwidth1S (std::ostringstream& results); void NetTotalReceivedBytes (std::ostringstream& results); void NetTotalSentBytes (std::ostringstream& results); - + // NetworkSetting typedef void (I2PControlHandlers::*NetworkSettingRequestHandler)(const std::string& value, std::ostringstream& results); void InboundBandwidthLimit (const std::string& value, std::ostringstream& results); void OutboundBandwidthLimit (const std::string& value, std::ostringstream& results); - + // ClientServicesInfo typedef void (I2PControlHandlers::*ClientServicesInfoRequestHandler)(std::ostringstream& results); void I2PTunnelInfoHandler (std::ostringstream& results); @@ -67,7 +67,7 @@ namespace client void SAMInfoHandler (std::ostringstream& results); void BOBInfoHandler (std::ostringstream& results); void I2CPInfoHandler (std::ostringstream& results); - + private: std::map m_RouterInfoHandlers; diff --git a/libi2pd/NetDb.cpp b/libi2pd/NetDb.cpp index 6042eaf2..5abe2fdc 100644 --- a/libi2pd/NetDb.cpp +++ b/libi2pd/NetDb.cpp @@ -274,7 +274,7 @@ namespace data { std::unique_lock l(m_RouterInfosMutex); r->Update (buf, len); - } + } LogPrint (eLogInfo, "NetDb: RouterInfo updated: ", ident.ToBase64()); if (wasFloodfill != r->IsFloodfill ()) // if floodfill status updated { @@ -438,14 +438,14 @@ namespace data // try reseeding from floodfill first if specified std::string riPath; - if(i2p::config::GetOption("reseed.floodfill", riPath)) + if(i2p::config::GetOption("reseed.floodfill", riPath)) { auto ri = std::make_shared(riPath); - if (ri->IsFloodfill()) + if (ri->IsFloodfill()) { const uint8_t * riData = ri->GetBuffer(); int riLen = ri->GetBufferLen(); - if (!i2p::data::netdb.AddRouterInfo(riData, riLen)) + if (!i2p::data::netdb.AddRouterInfo(riData, riLen)) { // bad router info LogPrint(eLogError, "NetDb: Bad router info"); @@ -629,7 +629,7 @@ namespace data it.second->SetUnreachable (false); // find & mark expired routers if (!it.second->IsReachable () && (it.second->GetCompatibleTransports (true) & (RouterInfo::eSSUV4 | RouterInfo::eSSU2V4))) - // non-reachable router, but reachable by ipv4 SSU or SSU2 means introducers + // non-reachable router, but reachable by ipv4 SSU or SSU2 means introducers { if (ts > it.second->GetTimestamp () + NETDB_INTRODUCEE_EXPIRATION_TIMEOUT*1000LL) // RouterInfo expires after 1 hour if uses introducer @@ -1218,7 +1218,7 @@ namespace data router->IsSSU2PeerTesting (v4) && !excluded.count (router->GetIdentHash ()); }); } - + std::shared_ptr NetDb::GetRandomSSUV6Router () const { return GetRandomRouter ( @@ -1243,11 +1243,11 @@ namespace data return GetRandomRouter ( [v4, &excluded](std::shared_ptr router)->bool { - return !router->IsHidden () && router->IsSSU2Introducer (v4) && + return !router->IsHidden () && router->IsSSU2Introducer (v4) && !excluded.count (router->GetIdentHash ()); }); } - + std::shared_ptr NetDb::GetHighBandwidthRandomRouter (std::shared_ptr compatibleWith, bool reverse) const { return GetRandomRouter ( @@ -1455,6 +1455,6 @@ namespace data { if (!r || r->GetBuffer ()) return; r->LoadBuffer (m_Storage.Path (r->GetIdentHashBase64 ())); - } + } } } diff --git a/libi2pd/NetDb.hpp b/libi2pd/NetDb.hpp index b14b84e7..26e0a41b 100644 --- a/libi2pd/NetDb.hpp +++ b/libi2pd/NetDb.hpp @@ -125,8 +125,8 @@ namespace data void ClearRouterInfos () { m_RouterInfos.clear (); }; std::shared_ptr NewRouterInfoBuffer () { return m_RouterInfoBuffersPool.AcquireSharedMt (); }; - void PopulateRouterInfoBuffer (std::shared_ptr r); - std::shared_ptr NewLease (const Lease& lease) { return m_LeasesPool.AcquireSharedMt (lease); }; + void PopulateRouterInfoBuffer (std::shared_ptr r); + std::shared_ptr NewLease (const Lease& lease) { return m_LeasesPool.AcquireSharedMt (lease); }; uint32_t GetPublishReplyToken () const { return m_PublishReplyToken; }; diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index 77d3763d..423bcfd7 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -121,7 +121,7 @@ namespace i2p uint16_t ssu2Port; i2p::config::GetOption ("ssu2.port", ssu2Port); if (!ssu2Port) ssu2Port = ssu ? (port + 1) : port; routerInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, boost::asio::ip::address_v4::from_string (host), ssu2Port); - } + } else { addressCaps |= i2p::data::RouterInfo::AddressCaps::eV4; @@ -170,7 +170,7 @@ namespace i2p uint16_t ssu2Port; i2p::config::GetOption ("ssu2.port", ssu2Port); if (!ssu2Port) ssu2Port = ssu ? (port + 1) : port; routerInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, boost::asio::ip::address_v6::from_string (host), ssu2Port); - } + } else { if (!ipv4) // no other ssu2 addresses yet @@ -201,8 +201,8 @@ namespace i2p uint16_t port = rand () % (30777 - 9111) + 9111; // I2P network ports range if (port == 9150) port = 9151; // Tor browser return port; - } - + } + void RouterContext::UpdateRouterInfo () { m_RouterInfo.CreateBuffer (m_Keys); @@ -354,7 +354,7 @@ namespace i2p (*it)->s = m_NTCP2Keys->staticPublicKey; memcpy ((*it)->i, m_NTCP2Keys->iv, 16); it++; - } + } else it = addresses.erase (it); updated = true; @@ -382,9 +382,9 @@ namespace i2p { newPort = address->port; break; - } + } if (!newPort) newPort = SelectRandomPort (); - } + } bool updated = false; for (auto& address : m_RouterInfo.GetAddresses ()) { @@ -419,8 +419,8 @@ namespace i2p (*it)->s = m_SSU2Keys->staticPublicKey; (*it)->i = m_SSU2Keys->intro; it++; - } - else + } + else it = addresses.erase (it); updated = true; } @@ -438,12 +438,12 @@ namespace i2p if (ipv6) m_RouterInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, i2p::data::RouterInfo::AddressCaps::eV6); } else - { + { uint8_t addressCaps = 0; if (ipv4) addressCaps |= i2p::data::RouterInfo::AddressCaps::eV4; if (ipv6) addressCaps |= i2p::data::RouterInfo::AddressCaps::eV6; m_RouterInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, addressCaps); - } + } updated = true; } if (updated) @@ -462,7 +462,7 @@ namespace i2p address->host = host; updated = true; } - if (host.is_v6 () && address->IsV6 () && address->ssu && + if (host.is_v6 () && address->IsV6 () && address->ssu && (!address->ssu->mtu || updated)) { // update MTU @@ -471,8 +471,8 @@ namespace i2p { LogPrint (eLogDebug, "Router: Our v6 MTU=", mtu); int maxMTU = i2p::util::net::GetMaxMTU (host.to_v6 ()); - if (mtu > maxMTU) - { + if (mtu > maxMTU) + { mtu = maxMTU; LogPrint(eLogWarning, "Router: MTU dropped to upper limit of ", maxMTU, " bytes"); } @@ -531,8 +531,8 @@ namespace i2p } if (updated) UpdateRouterInfo (); - } - + } + void RouterContext::SetFloodfill (bool floodfill) { m_IsFloodfill = floodfill; @@ -658,17 +658,17 @@ namespace i2p for (auto it = addresses.begin (); it != addresses.end ();) { if ((*it)->transportStyle == i2p::data::RouterInfo::eTransportSSU) - { + { it = addresses.erase (it); updated = true; - } + } else ++it; } if (updated) m_RouterInfo.UpdateSupportedTransports (); } - + void RouterContext::SetUnreachableSSU2 (bool v4, bool v6) { if (IsSSU2Only ()) @@ -691,7 +691,7 @@ namespace i2p // delete previous introducers auto& addresses = m_RouterInfo.GetAddresses (); for (auto& addr : addresses) - if (addr->ssu && (!addr->IsSSU2 () || IsSSU2Only ()) && + if (addr->ssu && (!addr->IsSSU2 () || IsSSU2Only ()) && ((v4 && addr->IsV4 ()) || (v6 && addr->IsV6 ()))) { addr->published = false; @@ -727,7 +727,7 @@ namespace i2p i2p::config::GetOption ("ssu2.published", isSSU2Published); auto& addresses = m_RouterInfo.GetAddresses (); for (auto& addr : addresses) - if (addr->ssu && (!addr->IsSSU2 () || isSSU2Published) && + if (addr->ssu && (!addr->IsSSU2 () || isSSU2Published) && ((v4 && addr->IsV4 ()) || (v6 && addr->IsV6 ()))) { addr->published = true; @@ -781,11 +781,11 @@ namespace i2p } port = addr->port; } - if (!port) - { + if (!port) + { i2p::config::GetOption("port", port); if (!port) port = SelectRandomPort (); - } + } // SSU bool ssu; i2p::config::GetOption("ssu", ssu); if (!foundSSU && ssu) @@ -871,11 +871,11 @@ namespace i2p } if (addr->port) port = addr->port; } - if (!port) - { + if (!port) + { i2p::config::GetOption("port", port); if (!port) port = SelectRandomPort (); - } + } // SSU bool ssu; i2p::config::GetOption("ssu", ssu); if (!foundSSU && ssu) diff --git a/libi2pd/RouterInfo.cpp b/libi2pd/RouterInfo.cpp index 60fd3358..d9c966d7 100644 --- a/libi2pd/RouterInfo.cpp +++ b/libi2pd/RouterInfo.cpp @@ -257,29 +257,29 @@ namespace data if (!ecode && !address->host.is_unspecified ()) isHost = true; } else if (!strcmp (key, "port")) - { - try - { + { + try + { address->port = boost::lexical_cast(value); } catch (std::exception& ex) { LogPrint (eLogWarning, "RouterInfo: 'port' exception ", ex.what ()); - } - } + } + } else if (!strcmp (key, "mtu")) { if (address->ssu) { try - { + { address->ssu->mtu = boost::lexical_cast(value); } catch (std::exception& ex) { LogPrint (eLogWarning, "RouterInfo: 'mtu' exception ", ex.what ()); - } - } + } + } else LogPrint (eLogWarning, "RouterInfo: Unexpected field 'mtu' for NTCP2"); } @@ -347,38 +347,38 @@ namespace data else if (!strcmp (key, "iport")) { try - { + { introducer.iPort = boost::lexical_cast(value); } catch (std::exception& ex) { LogPrint (eLogWarning, "RouterInfo: 'iport' exception ", ex.what ()); - } - } + } + } else if (!strcmp (key, "itag")) { try - { + { introducer.iTag = boost::lexical_cast(value); - } + } catch (std::exception& ex) { LogPrint (eLogWarning, "RouterInfo: 'itag' exception ", ex.what ()); - } + } } else if (!strcmp (key, "ikey") || !strcmp (key, "ih")) Base64ToByteStream (value, strlen (value), introducer.iKey, 32); else if (!strcmp (key, "iexp")) { try - { + { introducer.iExp = boost::lexical_cast(value); } catch (std::exception& ex) { LogPrint (eLogWarning, "RouterInfo: 'iexp' exception ", ex.what ()); - } - } + } + } } if (!s) return; } @@ -431,10 +431,10 @@ namespace data ((it.iHost.is_v4 () && address->IsV4 ()) || (it.iHost.is_v6 () && address->IsV6 ()))) numValid++; else - { + { it.iPort = 0; if (isV2) numValid++; - } + } } if (numValid) m_ReachableTransports |= supportedTransports; @@ -467,16 +467,16 @@ namespace data int numValid = 0; for (auto& it: address->ssu->introducers) { - if (it.iTag && ts <= it.iExp) + if (it.iTag && ts <= it.iExp) numValid++; - else + else it.iTag = 0; } if (numValid) m_ReachableTransports |= supportedTransports; else address->ssu->introducers.resize (0); - } + } } else { @@ -490,15 +490,15 @@ namespace data ssu2addr->ssu.reset (new SSUExt ()); ssu2addr->ssu->mtu = address->ssu->mtu; uint32_t ts = i2p::util::GetSecondsSinceEpoch (); if (!address->ssu->introducers.empty ()) - { + { for (const auto& introducer: address->ssu->introducers) if (!introducer.iPort && introducer.iHost.is_unspecified () && ts < introducer.iExp) // SSU2 ssu2addr->ssu->introducers.push_back (introducer); if (!ssu2addr->ssu->introducers.empty ()) m_ReachableTransports |= supportedTransports; - } + } addresses->push_back(ssu2addr); - } + } } if (supportedTransports) { @@ -982,7 +982,7 @@ namespace data std::shared_ptr RouterInfo::GetSSU2Address (bool v4) const { if (v4) - { + { if (m_SupportedTransports & eSSU2V4) return GetSSU2V4Address (); } @@ -990,10 +990,10 @@ namespace data { if (m_SupportedTransports & eSSU2V6) return GetSSU2V6Address (); - } + } return nullptr; - } - + } + template std::shared_ptr RouterInfo::GetAddress (Filter filter) const { @@ -1025,7 +1025,7 @@ namespace data return GetAddress ( [key, isV6](std::shared_ptr address)->bool { - return address->IsSSU2 () && !memcmp (address->s, key, 32) && + return address->IsSSU2 () && !memcmp (address->s, key, 32) && ((isV6 && address->IsV6 ()) || (!isV6 && address->IsV4 ())); }); } @@ -1099,8 +1099,8 @@ namespace data return (address->IsSSU2 ()) && address->IsPeerTesting () && ((v4 && address->IsV4 ()) || (!v4 && address->IsV6 ())) && address->IsReachableSSU (); }); - } - + } + bool RouterInfo::IsIntroducer (bool v4) const { if (!(m_SupportedTransports & (v4 ? eSSUV4 : eSSUV6))) return false; @@ -1122,7 +1122,7 @@ namespace data ((v4 && address->IsV4 ()) || (!v4 && address->IsV6 ())) && !address->host.is_unspecified (); }); } - + void RouterInfo::SetUnreachableAddressesTransportCaps (uint8_t transports) { for (auto& addr: *m_Addresses) @@ -1144,7 +1144,7 @@ namespace data { uint8_t transports = 0; switch (addr->transportStyle) - { + { case eTransportNTCP: if (addr->IsV4 ()) transports |= eNTCP2V4; if (addr->IsV6 ()) @@ -1163,9 +1163,9 @@ namespace data if (addr->IsV6 ()) transports |= eSSU2V6; if (addr->IsReachableSSU ()) m_ReachableTransports |= transports; - break; - default: ; - } + break; + default: ; + } m_SupportedTransports |= transports; } } @@ -1540,7 +1540,7 @@ namespace data } } return false; - } + } bool LocalRouterInfo::RemoveSSU2Introducer (const IdentHash& h, bool v4) { @@ -1559,6 +1559,6 @@ namespace data } } return false; - } + } } } diff --git a/libi2pd/RouterInfo.h b/libi2pd/RouterInfo.h index 6bc66b35..8f76707c 100644 --- a/libi2pd/RouterInfo.h +++ b/libi2pd/RouterInfo.h @@ -276,7 +276,7 @@ namespace data void RefreshTimestamp (); const Addresses& GetAddresses () const { return *m_Addresses; }; CompatibleTransports GetReachableTransports () const { return m_ReachableTransports; }; - void SetReachableTransports (CompatibleTransports transports) { m_ReachableTransports = transports; }; + void SetReachableTransports (CompatibleTransports transports) { m_ReachableTransports = transports; }; private: @@ -321,7 +321,7 @@ namespace data bool AddSSU2Introducer (const Introducer& introducer, bool v4); bool RemoveSSU2Introducer (const IdentHash& h, bool v4); - + private: void WriteToStream (std::ostream& s) const; diff --git a/libi2pd/SSU2.cpp b/libi2pd/SSU2.cpp index 245169d8..0c71b14e 100644 --- a/libi2pd/SSU2.cpp +++ b/libi2pd/SSU2.cpp @@ -17,12 +17,12 @@ namespace i2p { namespace transport -{ +{ SSU2Server::SSU2Server (): RunnableServiceWithWork ("SSU2"), m_ReceiveService ("SSU2r"), m_SocketV4 (m_ReceiveService.GetService ()), m_SocketV6 (m_ReceiveService.GetService ()), m_AddressV4 (boost::asio::ip::address_v4()), m_AddressV6 (boost::asio::ip::address_v6()), - m_TerminationTimer (GetService ()), m_ResendTimer (GetService ()), + m_TerminationTimer (GetService ()), m_ResendTimer (GetService ()), m_IntroducersUpdateTimer (GetService ()), m_IntroducersUpdateTimerV6 (GetService ()), m_IsPublished (true), m_IsSyncClockFromPeers (true) { @@ -93,25 +93,25 @@ namespace transport void SSU2Server::Stop () { if (IsRunning ()) - { + { m_TerminationTimer.cancel (); m_ResendTimer.cancel (); m_IntroducersUpdateTimer.cancel (); m_IntroducersUpdateTimerV6.cancel (); - } - + } + auto sessions = m_Sessions; for (auto& it: sessions) - { + { it.second->RequestTermination (eSSU2TerminationReasonRouterShutdown); it.second->Done (); - } - + } + if (context.SupportsV4 () || context.SupportsV6 ()) m_ReceiveService.Stop (); m_SocketV4.close (); m_SocketV6.close (); - + StopIOService (); m_Sessions.clear (); @@ -126,38 +126,38 @@ namespace transport { if (localAddress.is_unspecified ()) return; if (localAddress.is_v4 ()) - { + { m_AddressV4 = localAddress; int mtu = i2p::util::net::GetMTU (localAddress); if (mtu < (int)SSU2_MIN_PACKET_SIZE) mtu = SSU2_MIN_PACKET_SIZE; if (mtu > (int)SSU2_MAX_PACKET_SIZE) mtu = SSU2_MAX_PACKET_SIZE; i2p::context.SetMTU (mtu, true); - } + } else if (localAddress.is_v6 ()) - { + { m_AddressV6 = localAddress; int maxMTU = i2p::util::net::GetMaxMTU (localAddress.to_v6 ()); int mtu = i2p::util::net::GetMTU (localAddress); if (mtu > maxMTU) mtu = maxMTU; if (mtu < (int)SSU2_MIN_PACKET_SIZE) mtu = SSU2_MIN_PACKET_SIZE; i2p::context.SetMTU (mtu, false); - } - } + } + } bool SSU2Server::IsSupported (const boost::asio::ip::address& addr) const { if (addr.is_v4 ()) - { - if (m_SocketV4.is_open ()) + { + if (m_SocketV4.is_open ()) return true; - } + } else if (addr.is_v6 ()) - { - if (m_SocketV6.is_open ()) + { + if (m_SocketV6.is_open ()) return true; } return false; - } + } uint16_t SSU2Server::GetPort (bool v4) const { @@ -165,8 +165,8 @@ namespace transport boost::asio::ip::udp::endpoint ep = v4 ? m_SocketV4.local_endpoint (ec) : m_SocketV6.local_endpoint (ec); if (ec) return 0; return ep.port (); - } - + } + boost::asio::ip::udp::socket& SSU2Server::OpenSocket (const boost::asio::ip::udp::endpoint& localEndpoint) { boost::asio::ip::udp::socket& socket = localEndpoint.address ().is_v6 () ? m_SocketV6 : m_SocketV4; @@ -253,7 +253,7 @@ namespace transport { ProcessNextPacket (packet->buf, packet->len, packet->from); m_PacketsPool.ReleaseMt (packet); - if (m_LastSession && m_LastSession->GetState () != eSSU2SessionStateTerminated) + if (m_LastSession && m_LastSession->GetState () != eSSU2SessionStateTerminated) m_LastSession->FlushData (); } } @@ -263,7 +263,7 @@ namespace transport for (auto& packet: packets) ProcessNextPacket (packet->buf, packet->len, packet->from); m_PacketsPool.ReleaseMt (packets); - if (m_LastSession && m_LastSession->GetState () != eSSU2SessionStateTerminated) + if (m_LastSession && m_LastSession->GetState () != eSSU2SessionStateTerminated) m_LastSession->FlushData (); } @@ -289,7 +289,7 @@ namespace transport m_Sessions.erase (it); } } - + void SSU2Server::AddSessionByRouterHash (std::shared_ptr session) { if (session) @@ -323,10 +323,10 @@ namespace transport if (it != m_SessionsByRouterHash.end ()) return it->second; return nullptr; - } + } std::shared_ptr SSU2Server::FindPendingOutgoingSession (const boost::asio::ip::udp::endpoint& ep) const - { + { auto it = m_PendingOutgoingSessions.find (ep); if (it != m_PendingOutgoingSessions.end ()) return it->second; @@ -336,8 +336,8 @@ namespace transport void SSU2Server::RemovePendingOutgoingSession (const boost::asio::ip::udp::endpoint& ep) { m_PendingOutgoingSessions.erase (ep); - } - + } + std::shared_ptr SSU2Server::GetRandomSession ( i2p::data::RouterInfo::CompatibleTransports remoteTransports, const i2p::data::IdentHash& excluded) const { @@ -349,7 +349,7 @@ namespace transport std::advance (it, ind); while (it != m_Sessions.end ()) { - if ((it->second->GetRemoteTransports () & remoteTransports) && + if ((it->second->GetRemoteTransports () & remoteTransports) && it->second->GetRemoteIdentity ()->GetIdentHash () != excluded) return it->second; it++; @@ -358,14 +358,14 @@ namespace transport it = m_Sessions.begin (); while (it != m_Sessions.end () && ind) { - if ((it->second->GetRemoteTransports () & remoteTransports) && + if ((it->second->GetRemoteTransports () & remoteTransports) && it->second->GetRemoteIdentity ()->GetIdentHash () != excluded) return it->second; it++; ind--; - } + } return nullptr; - } - + } + void SSU2Server::AddRelay (uint32_t tag, std::shared_ptr relay) { m_Relays.emplace (tag, relay); @@ -409,7 +409,7 @@ namespace transport switch (m_LastSession->GetState ()) { case eSSU2SessionStateEstablished: - case eSSU2SessionStateSessionConfirmedSent: + case eSSU2SessionStateSessionConfirmedSent: m_LastSession->ProcessData (buf, len, senderEndpoint); break; case eSSU2SessionStateSessionCreatedSent: @@ -417,10 +417,10 @@ namespace transport { m_LastSession->Done (); m_LastSession = nullptr; - } + } break; case eSSU2SessionStateIntroduced: - if (m_LastSession->GetRemoteEndpoint ().address ().is_unspecified ()) + if (m_LastSession->GetRemoteEndpoint ().address ().is_unspecified ()) m_LastSession->SetRemoteEndpoint (senderEndpoint); if (m_LastSession->GetRemoteEndpoint () == senderEndpoint) m_LastSession->ProcessHolePunch (buf, len); @@ -429,8 +429,8 @@ namespace transport LogPrint (eLogWarning, "SSU2: HolePunch endpoint ", senderEndpoint, " doesn't match RelayResponse ", m_LastSession->GetRemoteEndpoint ()); m_LastSession->Done (); - m_LastSession = nullptr; - } + m_LastSession = nullptr; + } break; case eSSU2SessionStatePeerTest: m_LastSession->SetRemoteEndpoint (senderEndpoint); @@ -440,10 +440,10 @@ namespace transport m_LastSession->ProcessData (buf, len, senderEndpoint); // we might receive termintaion block if (m_LastSession && m_LastSession->GetState () != eSSU2SessionStateTerminated) m_LastSession->RequestTermination (eSSU2TerminationReasonIdleTimeout); // send termination again - break; + break; case eSSU2SessionStateTerminated: m_LastSession = nullptr; - break; + break; default: LogPrint (eLogWarning, "SSU2: Invalid session state ", (int)m_LastSession->GetState ()); } @@ -456,7 +456,7 @@ namespace transport { if (it1->second->GetState () == eSSU2SessionStateSessionRequestSent && it1->second->ProcessSessionCreated (buf, len)) - m_PendingOutgoingSessions.erase (it1); // we are done with that endpoint + m_PendingOutgoingSessions.erase (it1); // we are done with that endpoint else it1->second->ProcessRetry (buf, len); } @@ -524,41 +524,41 @@ namespace transport { auto session = it->second; GetService ().post ([session]() { session->SendPeerTest (); }); - } + } return false; - } + } // check is no pending session bool isValidEndpoint = !address->host.is_unspecified () && address->port; if (isValidEndpoint) - { + { if (i2p::util::net::IsInReservedRange(address->host)) return false; auto s = FindPendingOutgoingSession (boost::asio::ip::udp::endpoint (address->host, address->port)); if (s) - { + { if (peerTest) { // if peer test requested add it to the list for pending session auto onEstablished = s->GetOnEstablished (); if (onEstablished) - s->SetOnEstablished ([s, onEstablished]() - { - onEstablished (); - s->SendPeerTest (); - }); - else + s->SetOnEstablished ([s, onEstablished]() + { + onEstablished (); + s->SendPeerTest (); + }); + else s->SetOnEstablished ([s]() { s->SendPeerTest (); }); - } + } return false; - } - } - + } + } + auto session = std::make_shared (*this, router, address); if (peerTest) session->SetOnEstablished ([session]() {session->SendPeerTest (); }); if (address->UsesIntroducer ()) GetService ().post (std::bind (&SSU2Server::ConnectThroughIntroducer, this, session)); - else if (isValidEndpoint) // we can't connect without endpoint + else if (isValidEndpoint) // we can't connect without endpoint GetService ().post ([session]() { session->Connect (); }); else return false; @@ -589,7 +589,7 @@ namespace transport std::shared_ptr r; uint32_t relayTag = 0; if (!address->ssu->introducers.empty ()) - { + { std::vector indicies; for (int i = 0; i < (int)address->ssu->introducers.size (); i++) indicies.push_back(i); if (indicies.size () > 1) @@ -597,18 +597,18 @@ namespace transport for (auto i: indicies) { - const auto& introducer = address->ssu->introducers[indicies[i]]; + const auto& introducer = address->ssu->introducers[indicies[i]]; if (introducer.iTag && ts < introducer.iExp) - { + { r = i2p::data::netdb.FindRouter (introducer.iKey); if (r && r->IsReachableFrom (i2p::context.GetRouterInfo ())) { relayTag = introducer.iTag; if (relayTag) break; } - } + } } - } + } if (r) { if (relayTag) @@ -620,10 +620,10 @@ namespace transport bool isValidEndpoint = !addr->host.is_unspecified () && addr->port && !i2p::util::net::IsInReservedRange(addr->host); if (isValidEndpoint) - { + { auto s = FindPendingOutgoingSession (boost::asio::ip::udp::endpoint (addr->host, addr->port)); if (!s) - { + { s = std::make_shared (*this, r, addr); s->SetOnEstablished ([session, s, relayTag]() { s->Introduce (session, relayTag); }); s->Connect (); @@ -637,10 +637,10 @@ namespace transport onEstablished (); s->Introduce (session, relayTag); }); - else + else s->SetOnEstablished ([session, s, relayTag]() {s->Introduce (session, relayTag); }); - } - } + } + } } } } @@ -664,15 +664,15 @@ namespace transport auto s = it->second; if (it->second->IsEstablished ()) GetService ().post ([s]() { s->SendPeerTest (); }); - else - s->SetOnEstablished ([s]() { s->SendPeerTest (); }); - return true; + else + s->SetOnEstablished ([s]() { s->SendPeerTest (); }); + return true; } - else + else CreateSession (router, addr, true); return true; - } - + } + void SSU2Server::ScheduleTermination () { m_TerminationTimer.expires_from_now (boost::posix_time::seconds(SSU2_TERMINATION_CHECK_TIMEOUT)); @@ -718,7 +718,7 @@ namespace transport it = m_SessionsByRouterHash.erase (it); else it++; - } + } for (auto it = m_Relays.begin (); it != m_Relays.begin ();) { @@ -726,8 +726,8 @@ namespace transport it = m_Relays.erase (it); else it++; - } - + } + for (auto it = m_IncomingTokens.begin (); it != m_IncomingTokens.end (); ) { if (ts > it->second.second) @@ -743,7 +743,7 @@ namespace transport else it++; } - + m_PacketsPool.CleanUpMt (); m_SentPacketsPool.CleanUp (); ScheduleTermination (); @@ -752,7 +752,7 @@ namespace transport void SSU2Server::ScheduleResend (bool more) { - m_ResendTimer.expires_from_now (boost::posix_time::milliseconds (more ? SSU2_RESEND_CHECK_MORE_TIMEOUT : + m_ResendTimer.expires_from_now (boost::posix_time::milliseconds (more ? SSU2_RESEND_CHECK_MORE_TIMEOUT : (SSU2_RESEND_CHECK_TIMEOUT + rand () % SSU2_RESEND_CHECK_TIMEOUT_VARIANCE))); m_ResendTimer.async_wait (std::bind (&SSU2Server::HandleResendTimer, this, std::placeholders::_1)); @@ -765,10 +765,10 @@ namespace transport size_t resentPacketsNum = 0; auto ts = i2p::util::GetMillisecondsSinceEpoch (); for (auto it: m_Sessions) - { + { resentPacketsNum += it.second->Resend (ts); if (resentPacketsNum > SSU2_MAX_RESEND_PACKETS) break; - } + } for (auto it: m_PendingOutgoingSessions) it.second->Resend (ts); ScheduleResend (resentPacketsNum > SSU2_MAX_RESEND_PACKETS); @@ -788,7 +788,7 @@ namespace transport if (i2p::util::GetSecondsSinceEpoch () + SSU2_TOKEN_EXPIRATION_THRESHOLD > it->second.second) return 0; // token expired return it->second.first; - } + } return 0; } @@ -808,23 +808,23 @@ namespace transport m_IncomingTokens.erase (ep); // drop previous uint64_t token; RAND_bytes ((uint8_t *)&token, 8); - auto ret = std::make_pair (token, i2p::util::GetSecondsSinceEpoch () + SSU2_NEXT_TOKEN_EXPIRATION_TIMEOUT); + auto ret = std::make_pair (token, i2p::util::GetSecondsSinceEpoch () + SSU2_NEXT_TOKEN_EXPIRATION_TIMEOUT); m_IncomingTokens.emplace (ep, ret); return ret; - } + } - std::list > SSU2Server::FindIntroducers (int maxNumIntroducers, + std::list > SSU2Server::FindIntroducers (int maxNumIntroducers, bool v4, const std::set& excluded) const { std::list > ret; for (const auto& s : m_Sessions) { - if (s.second->IsEstablished () && (s.second->GetRelayTag () && s.second->IsOutgoing ()) && + if (s.second->IsEstablished () && (s.second->GetRelayTag () && s.second->IsOutgoing ()) && !excluded.count (s.second->GetRemoteIdentity ()->GetIdentHash ()) && ((v4 && (s.second->GetRemoteTransports () & i2p::data::RouterInfo::eSSU2V4)) || - (!v4 && (s.second->GetRemoteTransports () & i2p::data::RouterInfo::eSSU2V6)))) + (!v4 && (s.second->GetRemoteTransports () & i2p::data::RouterInfo::eSSU2V6)))) ret.push_back (s.second); - } + } if ((int)ret.size () > maxNumIntroducers) { // shink ret randomly @@ -838,7 +838,7 @@ namespace transport } } return ret; - } + } void SSU2Server::UpdateIntroducers (bool v4) { @@ -850,11 +850,11 @@ namespace transport { std::shared_ptr session; auto it1 = m_SessionsByRouterHash.find (it); - if (it1 != m_SessionsByRouterHash.end ()) - { + if (it1 != m_SessionsByRouterHash.end ()) + { session = it1->second; excluded.insert (it); - } + } if (session && session->IsEstablished ()) { if (ts < session->GetCreationTime () + SSU2_TO_INTRODUCER_SESSION_EXPIRATION) @@ -863,10 +863,10 @@ namespace transport newList.push_back (it); else session = nullptr; - } + } if (!session) - i2p::context.RemoveSSU2Introducer (it, v4); - } + i2p::context.RemoveSSU2Introducer (it, v4); + } if (newList.size () < SSU2_MAX_NUM_INTRODUCERS) { auto sessions = FindIntroducers (SSU2_MAX_NUM_INTRODUCERS - newList.size (), v4, excluded); @@ -875,24 +875,24 @@ namespace transport // bump creation time for previous introducers if no new sessions found LogPrint (eLogDebug, "SSU2: No new introducers found. Trying to reuse existing"); for (auto& it : introducers) - { + { auto it1 = m_SessionsByRouterHash.find (it); if (it1 != m_SessionsByRouterHash.end ()) { auto session = it1->second; if (session->IsEstablished ()) - { + { session->SetCreationTime (session->GetCreationTime () + SSU2_TO_INTRODUCER_SESSION_DURATION); - if (std::find (newList.begin (), newList.end (), it) == newList.end ()) - { + if (std::find (newList.begin (), newList.end (), it) == newList.end ()) + { newList.push_back (it); sessions.push_back (session); - } - } - } - } - } - + } + } + } + } + } + for (const auto& it : sessions) { i2p::data::RouterInfo::Introducer introducer; @@ -902,13 +902,13 @@ namespace transport excluded.insert (it->GetRemoteIdentity ()->GetIdentHash ()); if (i2p::context.AddSSU2Introducer (introducer, v4)) { - LogPrint (eLogDebug, "SSU2: Introducer added ", it->GetRelayTag (), " at ", + LogPrint (eLogDebug, "SSU2: Introducer added ", it->GetRelayTag (), " at ", i2p::data::GetIdentHashAbbreviation (it->GetRemoteIdentity ()->GetIdentHash ())); newList.push_back (it->GetRemoteIdentity ()->GetIdentHash ()); if (newList.size () >= SSU2_MAX_NUM_INTRODUCERS) break; - } - } - } + } + } + } introducers = newList; if (introducers.size () < SSU2_MAX_NUM_INTRODUCERS) @@ -937,12 +937,12 @@ namespace transport void SSU2Server::ScheduleIntroducersUpdateTimer () { if (m_IsPublished) - { + { m_IntroducersUpdateTimer.expires_from_now (boost::posix_time::seconds(SSU2_KEEP_ALIVE_INTERVAL)); m_IntroducersUpdateTimer.async_wait (std::bind (&SSU2Server::HandleIntroducersUpdateTimer, this, std::placeholders::_1, true)); - } - } + } + } void SSU2Server::RescheduleIntroducersUpdateTimer () { @@ -954,18 +954,18 @@ namespace transport m_IntroducersUpdateTimer.expires_from_now (boost::posix_time::seconds(SSU2_KEEP_ALIVE_INTERVAL/2)); m_IntroducersUpdateTimer.async_wait (std::bind (&SSU2Server::HandleIntroducersUpdateTimer, this, std::placeholders::_1, true)); - } + } } void SSU2Server::ScheduleIntroducersUpdateTimerV6 () { if (m_IsPublished) - { + { m_IntroducersUpdateTimerV6.expires_from_now (boost::posix_time::seconds(SSU2_KEEP_ALIVE_INTERVAL)); m_IntroducersUpdateTimerV6.async_wait (std::bind (&SSU2Server::HandleIntroducersUpdateTimer, this, std::placeholders::_1, false)); - } - } + } + } void SSU2Server::RescheduleIntroducersUpdateTimerV6 () { @@ -977,9 +977,9 @@ namespace transport m_IntroducersUpdateTimerV6.expires_from_now (boost::posix_time::seconds(SSU2_KEEP_ALIVE_INTERVAL/2)); m_IntroducersUpdateTimerV6.async_wait (std::bind (&SSU2Server::HandleIntroducersUpdateTimer, this, std::placeholders::_1, false)); - } + } } - + void SSU2Server::HandleIntroducersUpdateTimer (const boost::system::error_code& ecode, bool v4) { if (ecode != boost::asio::error::operation_aborted) @@ -1004,7 +1004,7 @@ namespace transport auto addr = i2p::context.GetRouterInfo ().GetSSU2V4Address (); if (addr && addr->ssu && addr->ssu->introducers.empty ()) i2p::context.SetUnreachableSSU2 (true, false); // v4 - + UpdateIntroducers (true); ScheduleIntroducersUpdateTimer (); } @@ -1027,11 +1027,11 @@ namespace transport auto addr = i2p::context.GetRouterInfo ().GetSSU2V6Address (); if (addr && addr->ssu && addr->ssu->introducers.empty ()) i2p::context.SetUnreachableSSU2 (false, true); // v6 - + UpdateIntroducers (false); ScheduleIntroducersUpdateTimerV6 (); - } + } } - } + } } } diff --git a/libi2pd/SSU2.h b/libi2pd/SSU2.h index 27af6bf8..773eb669 100644 --- a/libi2pd/SSU2.h +++ b/libi2pd/SSU2.h @@ -28,7 +28,7 @@ namespace transport const int SSU2_TO_INTRODUCER_SESSION_DURATION = 3600; // 1 hour const int SSU2_TO_INTRODUCER_SESSION_EXPIRATION = 4800; // 80 minutes const int SSU2_KEEP_ALIVE_INTERVAL = 30; // 30 seconds - + class SSU2Server: private i2p::util::RunnableServiceWithWork { struct Packet @@ -60,7 +60,7 @@ namespace transport bool IsSupported (const boost::asio::ip::address& addr) const; uint16_t GetPort (bool v4) const; bool IsSyncClockFromPeers () const { return m_IsSyncClockFromPeers; }; - + void AddSession (std::shared_ptr session); void RemoveSession (uint64_t connID); void AddSessionByRouterHash (std::shared_ptr session); @@ -70,7 +70,7 @@ namespace transport std::shared_ptr FindPendingOutgoingSession (const boost::asio::ip::udp::endpoint& ep) const; std::shared_ptr GetRandomSession (i2p::data::RouterInfo::CompatibleTransports remoteTransports, const i2p::data::IdentHash& excluded) const; - + void AddRelay (uint32_t tag, std::shared_ptr relay); void RemoveRelay (uint32_t tag); std::shared_ptr FindRelaySession (uint32_t tag); @@ -83,17 +83,17 @@ namespace transport bool CreateSession (std::shared_ptr router, std::shared_ptr address, bool peerTest = false); bool StartPeerTest (std::shared_ptr router, bool v4); - + void UpdateOutgoingToken (const boost::asio::ip::udp::endpoint& ep, uint64_t token, uint32_t exp); uint64_t FindOutgoingToken (const boost::asio::ip::udp::endpoint& ep) const; uint64_t GetIncomingToken (const boost::asio::ip::udp::endpoint& ep); std::pair NewIncomingToken (const boost::asio::ip::udp::endpoint& ep); - + void RescheduleIntroducersUpdateTimer (); void RescheduleIntroducersUpdateTimerV6 (); i2p::util::MemoryPool& GetSentPacketsPool () { return m_SentPacketsPool; }; - + private: boost::asio::ip::udp::socket& OpenSocket (const boost::asio::ip::udp::endpoint& localEndpoint); @@ -111,13 +111,13 @@ namespace transport void HandleResendTimer (const boost::system::error_code& ecode); void ConnectThroughIntroducer (std::shared_ptr session); - std::list > FindIntroducers (int maxNumIntroducers, + std::list > FindIntroducers (int maxNumIntroducers, bool v4, const std::set& excluded) const; void UpdateIntroducers (bool v4); void ScheduleIntroducersUpdateTimer (); void HandleIntroducersUpdateTimer (const boost::system::error_code& ecode, bool v4); void ScheduleIntroducersUpdateTimerV6 (); - + private: ReceiveService m_ReceiveService; @@ -136,7 +136,7 @@ namespace transport std::shared_ptr m_LastSession; bool m_IsPublished; // if we maintain introducers bool m_IsSyncClockFromPeers; - + public: // for HTTP/I2PControl diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index 8dd4884e..7a6845d8 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -31,16 +31,16 @@ namespace transport LogPrint (eLogError, "SSU2: I2NP buffer overflow ", msg->maxLen); nextFragmentNum++; } - - + + SSU2Session::SSU2Session (SSU2Server& server, std::shared_ptr in_RemoteRouter, std::shared_ptr addr): TransportSession (in_RemoteRouter, SSU2_CONNECT_TIMEOUT), m_Server (server), m_Address (addr), m_RemoteTransports (0), m_DestConnID (0), m_SourceConnID (0), m_State (eSSU2SessionStateUnknown), - m_SendPacketNum (0), m_ReceivePacketNum (0), m_IsDataReceived (false), - m_WindowSize (SSU2_MIN_WINDOW_SIZE), m_RTT (SSU2_RESEND_INTERVAL), - m_RTO (SSU2_RESEND_INTERVAL*SSU2_kAPPA), m_RelayTag (0), + m_SendPacketNum (0), m_ReceivePacketNum (0), m_IsDataReceived (false), + m_WindowSize (SSU2_MIN_WINDOW_SIZE), m_RTT (SSU2_RESEND_INTERVAL), + m_RTO (SSU2_RESEND_INTERVAL*SSU2_kAPPA), m_RelayTag (0), m_ConnectTimer (server.GetService ()), m_TerminationReason (eSSU2TerminationReasonNormalClose), m_MaxPayloadSize (SSU2_MIN_PACKET_SIZE - IPV6_HEADER_SIZE - UDP_HEADER_SIZE - 32) // min size { @@ -68,17 +68,17 @@ namespace transport void SSU2Session::Connect () { if (m_State == eSSU2SessionStateUnknown || m_State == eSSU2SessionStateTokenReceived) - { + { ScheduleConnectTimer (); auto token = m_Server.FindOutgoingToken (m_RemoteEndpoint); if (token) SendSessionRequest (token); else - { - m_State = eSSU2SessionStateUnknown; + { + m_State = eSSU2SessionStateUnknown; SendTokenRequest (); - } - } + } + } } void SSU2Session::ScheduleConnectTimer () @@ -98,7 +98,7 @@ namespace transport Terminate (); } } - + bool SSU2Session::Introduce (std::shared_ptr session, uint32_t relayTag) { // we are Alice @@ -155,15 +155,15 @@ namespace transport // create new connID uint64_t oldConnID = GetConnID (); RAND_bytes ((uint8_t *)&m_DestConnID, 8); - RAND_bytes ((uint8_t *)&m_SourceConnID, 8); + RAND_bytes ((uint8_t *)&m_SourceConnID, 8); // connect m_State = eSSU2SessionStateTokenReceived; m_Server.AddPendingOutgoingSession (shared_from_this ()); m_Server.RemoveSession (oldConnID); Connect (); } - } - + } + void SSU2Session::SendPeerTest () { // we are Alice @@ -181,23 +181,23 @@ namespace transport uint8_t payload[SSU2_MAX_PACKET_SIZE]; size_t payloadSize = CreatePeerTestBlock (payload, m_MaxPayloadSize, nonce); if (payloadSize > 0) - { + { payloadSize += CreatePaddingBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize); SendData (payload, payloadSize); LogPrint (eLogDebug, "SSU2: PeerTest sent to ", i2p::data::GetIdentHashAbbreviation (GetRemoteIdentity ()->GetIdentHash ())); - } - } + } + } void SSU2Session::SendKeepAlive () { if (IsEstablished ()) - { + { uint8_t payload[20]; size_t payloadSize = CreatePaddingBlock (payload, 20, 5); SendData (payload, payloadSize); - } - } - + } + } + void SSU2Session::Terminate () { if (m_State != eSSU2SessionStateTerminated) @@ -229,8 +229,8 @@ namespace transport SendTermination (); } m_State = eSSU2SessionStateClosing; - } - + } + void SSU2Session::Established () { m_State = eSSU2SessionStateEstablished; @@ -241,11 +241,11 @@ namespace transport m_ConnectTimer.cancel (); SetTerminationTimeout (SSU2_TERMINATION_TIMEOUT); transports.PeerConnected (shared_from_this ()); - if (m_OnEstablished) - { + if (m_OnEstablished) + { m_OnEstablished (); m_OnEstablished = nullptr; - } + } } void SSU2Session::Done () @@ -256,7 +256,7 @@ namespace transport void SSU2Session::SendLocalRouterInfo (bool update) { if (update || !IsOutgoing ()) - { + { auto s = shared_from_this (); m_Server.GetService ().post ([s]() { @@ -268,14 +268,14 @@ namespace transport if (payloadSize < s->m_MaxPayloadSize) payloadSize += s->CreatePaddingBlock (payload + payloadSize, s->m_MaxPayloadSize - payloadSize); s->SendData (payload, payloadSize); - } + } else s->SendFragmentedMessage (CreateDatabaseStoreMsg ()); }); - } + } + + } - } - void SSU2Session::SendI2NPMessages (const std::vector >& msgs) { m_Server.GetService ().post (std::bind (&SSU2Session::PostI2NPMessages, shared_from_this (), msgs)); @@ -289,16 +289,16 @@ namespace transport SendQueue (); if (m_SendQueue.size () > 0) // windows is full - { + { if (m_SendQueue.size () <= SSU2_MAX_OUTGOING_QUEUE_SIZE) Resend (i2p::util::GetMillisecondsSinceEpoch ()); - else + else { LogPrint (eLogWarning, "SSU2: Outgoing messages queue size to ", GetIdentHashBase64(), " exceeds ", SSU2_MAX_OUTGOING_QUEUE_SIZE); RequestTermination (eSSU2TerminationReasonTimeout); } - } + } } bool SSU2Session::SendQueue () @@ -317,7 +317,7 @@ namespace transport { m_SendQueue.pop_front (); continue; - } + } size_t len = msg->GetNTCP2Length () + 3; if (len > m_MaxPayloadSize) // message too long { @@ -338,12 +338,12 @@ namespace transport newPacket->payloadSize = ackBlockSize; // complete current packet if (packet->payloadSize > ackBlockSize) // more than just ack block - { + { ackBlockSent = true; // try to add padding if (packet->payloadSize + 16 < m_MaxPayloadSize) packet->payloadSize += CreatePaddingBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize); - } + } else { // reduce ack block @@ -352,15 +352,15 @@ namespace transport // keep Ack block and drop some ranges ackBlockSent = true; packet->payloadSize = m_MaxPayloadSize - len; - if (packet->payloadSize & 0x01) packet->payloadSize--; // make it even + if (packet->payloadSize & 0x01) packet->payloadSize--; // make it even htobe16buf (packet->payload + 1, packet->payloadSize - 3); // new block size - } + } else // drop Ack block completely - packet->payloadSize = 0; + packet->payloadSize = 0; // msg fits single packet m_SendQueue.pop_front (); packet->payloadSize += CreateI2NPBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize, std::move (msg)); - } + } // send right a way uint32_t packetNum = SendData (packet->payload, packet->payloadSize); packet->sendTime = ts; @@ -394,7 +394,7 @@ namespace transport auto ts = i2p::util::GetMillisecondsSinceEpoch (); auto packet = m_Server.GetSentPacketsPool ().AcquireShared (); if (extraSize >= 8) - { + { packet->payloadSize = CreateAckBlock (packet->payload, extraSize); ackBlockSent = true; if (packet->payloadSize + 12 < m_MaxPayloadSize) @@ -403,10 +403,10 @@ namespace transport packet->sendTime = ts; m_SentPackets.emplace (packetNum, packet); packet = m_Server.GetSentPacketsPool ().AcquireShared (); - } - else + } + else extraSize -= packet->payloadSize; - } + } size_t offset = extraSize > 0 ? (rand () % extraSize) : 0; if (offset + packet->payloadSize >= m_MaxPayloadSize) offset = 0; auto size = CreateFirstFragmentBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - offset - packet->payloadSize, msg); @@ -425,11 +425,11 @@ namespace transport extraSize -= offset; uint8_t flags = 0; if (msg->offset >= msg->len && packet->payloadSize + 16 < m_MaxPayloadSize) // last fragment - { + { packet->payloadSize += CreatePaddingBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize); if (fragmentNum > 2) // 3 or more fragments flags |= SSU2_FLAG_IMMEDIATE_ACK_REQUESTED; - } + } uint32_t followonPacketNum = SendData (packet->payload, packet->payloadSize, flags); packet->sendTime = ts; m_SentPackets.emplace (followonPacketNum, packet); @@ -446,7 +446,7 @@ namespace transport ResendHandshakePacket (); m_SentHandshakePacket->sendTime = ts; return 0; - } + } // resend data packets if (m_SentPackets.empty ()) return 0; std::map > resentPackets; @@ -460,7 +460,7 @@ namespace transport m_SendQueue.clear (); RequestTermination (eSSU2TerminationReasonTimeout); return resentPackets.size (); - } + } else { uint32_t packetNum = SendData (it->second->payload, it->second->payloadSize); @@ -489,16 +489,16 @@ namespace transport void SSU2Session::ResendHandshakePacket () { if (m_SentHandshakePacket) - { - m_Server.Send (m_SentHandshakePacket->header.buf, 16, m_SentHandshakePacket->headerX, 48, + { + m_Server.Send (m_SentHandshakePacket->header.buf, 16, m_SentHandshakePacket->headerX, 48, m_SentHandshakePacket->payload, m_SentHandshakePacket->payloadSize, m_RemoteEndpoint); if (m_SessionConfirmedFragment && m_State == eSSU2SessionStateSessionConfirmedSent) // resend second fragment of SessionConfirmed - m_Server.Send (m_SessionConfirmedFragment->header.buf, 16, + m_Server.Send (m_SessionConfirmedFragment->header.buf, 16, m_SessionConfirmedFragment->payload, m_SessionConfirmedFragment->payloadSize, m_RemoteEndpoint); - } - } - + } + } + bool SSU2Session::ProcessFirstIncomingMessage (uint64_t connID, uint8_t * buf, size_t len) { // we are Bob @@ -517,16 +517,16 @@ namespace transport break; case eSSU2PeerTest: { - // TODO: remove later - const uint8_t nonce[12] = {0}; - uint64_t headerX[2]; - i2p::crypto::ChaCha20 (buf + 16, 16, i2p::context.GetSSU2IntroKey (), nonce, (uint8_t *)headerX); + // TODO: remove later + const uint8_t nonce[12] = {0}; + uint64_t headerX[2]; + i2p::crypto::ChaCha20 (buf + 16, 16, i2p::context.GetSSU2IntroKey (), nonce, (uint8_t *)headerX); LogPrint (eLogWarning, "SSU2: Unexpected PeerTest message SourceConnID=", connID, " DestConnID=", headerX[0]); break; - } + } case eSSU2HolePunch: LogPrint (eLogDebug, "SSU2: Late HolePunch for ", connID); - break; + break; default: { LogPrint (eLogWarning, "SSU2: Unexpected message type ", (int)header.h.type, " from ", m_RemoteEndpoint, " of ", len, " bytes"); @@ -543,9 +543,9 @@ namespace transport m_SentHandshakePacket.reset (new HandshakePacket); auto ts = i2p::util::GetMillisecondsSinceEpoch (); m_SentHandshakePacket->sendTime = ts; - + Header& header = m_SentHandshakePacket->header; - uint8_t * headerX = m_SentHandshakePacket->headerX, + uint8_t * headerX = m_SentHandshakePacket->headerX, * payload = m_SentHandshakePacket->payload; // fill packet header.h.connID = m_DestConnID; // dest id @@ -568,7 +568,7 @@ namespace transport payload[payloadSize] = eSSU2BlkRelayTagRequest; memset (payload + payloadSize + 1, 0, 2); // size = 0 payloadSize += 3; - } + } payloadSize += CreatePaddingBlock (payload + payloadSize, 40 - payloadSize, 1); // KDF for session request m_NoiseState->MixHash ({ {header.buf, 16}, {headerX, 16} }); // h = SHA256(h || header) @@ -587,15 +587,15 @@ namespace transport m_SentHandshakePacket->payloadSize = payloadSize; // send if (m_State == eSSU2SessionStateTokenReceived || m_Server.AddPendingOutgoingSession (shared_from_this ())) - { + { m_State = eSSU2SessionStateSessionRequestSent; m_Server.Send (header.buf, 16, headerX, 48, payload, payloadSize, m_RemoteEndpoint); - } + } else { - LogPrint (eLogWarning, "SSU2: SessionRequest request to ", m_RemoteEndpoint, " already pending"); + LogPrint (eLogWarning, "SSU2: SessionRequest request to ", m_RemoteEndpoint, " already pending"); Terminate (); - } + } } void SSU2Session::ProcessSessionRequest (Header& header, uint8_t * buf, size_t len) @@ -634,10 +634,10 @@ namespace transport HandlePayload (decryptedPayload.data (), decryptedPayload.size ()); if (m_TerminationReason == eSSU2TerminationReasonNormalClose) - { + { m_Server.AddSession (shared_from_this ()); SendSessionCreated (headerX + 16); - } + } else SendRetry (); } @@ -649,12 +649,12 @@ namespace transport m_SentHandshakePacket.reset (new HandshakePacket); auto ts = i2p::util::GetMillisecondsSinceEpoch (); m_SentHandshakePacket->sendTime = ts; - + uint8_t kh2[32]; i2p::crypto::HKDF (m_NoiseState->m_CK, nullptr, 0, "SessCreateHeader", kh2, 32); // k_header_2 = HKDF(chainKey, ZEROLEN, "SessCreateHeader", 32) // fill packet Header& header = m_SentHandshakePacket->header; - uint8_t * headerX = m_SentHandshakePacket->headerX, + uint8_t * headerX = m_SentHandshakePacket->headerX, * payload = m_SentHandshakePacket->payload; header.h.connID = m_DestConnID; // dest id header.h.packetNum = 0; @@ -681,13 +681,13 @@ namespace transport } auto token = m_Server.NewIncomingToken (m_RemoteEndpoint); if (ts + SSU2_TOKEN_EXPIRATION_THRESHOLD > token.second) // not expired? - { + { payload[payloadSize] = eSSU2BlkNewToken; htobe16buf (payload + payloadSize + 1, 12); htobe32buf (payload + payloadSize + 3, token.second - SSU2_TOKEN_EXPIRATION_THRESHOLD); // expires memcpy (payload + payloadSize + 7, &token.first, 8); // token payloadSize += 15; - } + } payloadSize += CreatePaddingBlock (payload + payloadSize, maxPayloadSize - payloadSize); // KDF for SessionCreated m_NoiseState->MixHash ( { {header.buf, 16}, {headerX, 16} } ); // h = SHA256(h || header) @@ -757,7 +757,7 @@ namespace transport // we are Alice m_SentHandshakePacket.reset (new HandshakePacket); m_SentHandshakePacket->sendTime = i2p::util::GetMillisecondsSinceEpoch (); - + uint8_t kh2[32]; i2p::crypto::HKDF (m_NoiseState->m_CK, nullptr, 0, "SessionConfirmed", kh2, 32); // k_header_2 = HKDF(chainKey, ZEROLEN, "SessionConfirmed", 32) // fill packet @@ -778,7 +778,7 @@ namespace transport payloadSize = CreateRouterInfoBlock (payload, maxPayloadSize, i2p::context.GetSharedRouterInfo ()); header.h.flags[0] = 0x02; // frag 0, total fragments 2 // TODO: check if we need more fragments - } + } if (payloadSize < maxPayloadSize) payloadSize += CreatePaddingBlock (payload + payloadSize, maxPayloadSize - payloadSize); // KDF for Session Confirmed part 1 @@ -806,10 +806,10 @@ namespace transport payloadSize = m_MaxPayloadSize - 48 - (rand () % 16); if (m_SentHandshakePacket->payloadSize - payloadSize < 24) payloadSize -= 24; - } + } else header.h.flags[0] = 1; - } + } // Encrypt header header.ll[0] ^= CreateHeaderMask (m_Address->i, payload + (payloadSize - 24)); header.ll[1] ^= CreateHeaderMask (kh2, payload + (payloadSize - 12)); @@ -828,12 +828,12 @@ namespace transport memset (header.h.flags, 0, 3); header.h.flags[0] = 0x12; // frag 1, total fragments 2 m_SessionConfirmedFragment->payloadSize = m_SentHandshakePacket->payloadSize - payloadSize; - memcpy (m_SessionConfirmedFragment->payload, m_SentHandshakePacket->payload + payloadSize, m_SessionConfirmedFragment->payloadSize); + memcpy (m_SessionConfirmedFragment->payload, m_SentHandshakePacket->payload + payloadSize, m_SessionConfirmedFragment->payloadSize); m_SentHandshakePacket->payloadSize = payloadSize; header.ll[0] ^= CreateHeaderMask (m_Address->i, m_SessionConfirmedFragment->payload + (m_SessionConfirmedFragment->payloadSize - 24)); header.ll[1] ^= CreateHeaderMask (kh2, m_SessionConfirmedFragment->payload + (m_SessionConfirmedFragment->payloadSize - 12)); m_Server.Send (header.buf, 16, m_SessionConfirmedFragment->payload, m_SessionConfirmedFragment->payloadSize, m_RemoteEndpoint); - } + } } bool SSU2Session::ProcessSessionConfirmed (uint8_t * buf, size_t len) @@ -860,18 +860,18 @@ namespace transport { LogPrint (eLogError, "SSU2: Too many fragments ", numFragments, " in SessionConfirmed"); return false; - } + } if (!(header.h.flags[0] & 0xF0)) { // first fragment if (!m_SessionConfirmedFragment) - { + { m_SessionConfirmedFragment.reset (new HandshakePacket); m_SessionConfirmedFragment->header = header; memcpy (m_SessionConfirmedFragment->payload, buf + 16, len - 16); m_SessionConfirmedFragment->payloadSize = len - 16; return true; // wait for second fragment - } + } else if (m_SessionConfirmedFragment->isSecondFragment) { // we have second fragment @@ -882,28 +882,28 @@ namespace transport m_SessionConfirmedFragment->isSecondFragment = false; buf = m_SessionConfirmedFragment->payload - 16; len = m_SessionConfirmedFragment->payloadSize + 16; - } + } else return true; } else { // second fragment - if (!m_SessionConfirmedFragment) - { + if (!m_SessionConfirmedFragment) + { // out of sequence, save it m_SessionConfirmedFragment.reset (new HandshakePacket); memcpy (m_SessionConfirmedFragment->payload, buf + 16, len - 16); m_SessionConfirmedFragment->payloadSize = len - 16; m_SessionConfirmedFragment->isSecondFragment = true; - return true; - } + return true; + } header = m_SessionConfirmedFragment->header; if (m_SessionConfirmedFragment->payloadSize + (len - 16) <= SSU2_MAX_PACKET_SIZE*2) - { + { memcpy (m_SessionConfirmedFragment->payload + m_SessionConfirmedFragment->payloadSize, buf + 16, len - 16); m_SessionConfirmedFragment->payloadSize += (len - 16); - } + } buf = m_SessionConfirmedFragment->payload - 16; len = m_SessionConfirmedFragment->payloadSize + 16; } @@ -972,7 +972,7 @@ namespace transport { LogPrint (eLogError, "SSU2: Couldn't update RouterInfo from SessionConfirmed in netdb"); return false; - } + } SetRemoteIdentity (ri->GetRouterIdentity ()); AdjustMaxPayloadSize (); m_Server.AddSessionByRouterHash (shared_from_this ()); // we know remote router now @@ -1027,13 +1027,13 @@ namespace transport memset (nonce, 0, 12); i2p::crypto::ChaCha20 (h + 16, 16, m_Address->i, nonce, h + 16); // send - if (m_Server.AddPendingOutgoingSession (shared_from_this ())) + if (m_Server.AddPendingOutgoingSession (shared_from_this ())) m_Server.Send (header.buf, 16, h + 16, 16, payload, payloadSize, m_RemoteEndpoint); else { - LogPrint (eLogWarning, "SSU2: TokenRequest request to ", m_RemoteEndpoint, " already pending"); + LogPrint (eLogWarning, "SSU2: TokenRequest request to ", m_RemoteEndpoint, " already pending"); Terminate (); - } + } } void SSU2Session::ProcessTokenRequest (Header& header, uint8_t * buf, size_t len) @@ -1043,7 +1043,7 @@ namespace transport { LogPrint (eLogWarning, "SSU2: Incorrect TokenRequest len ", len); return; - } + } uint8_t nonce[12] = {0}; uint8_t h[32]; memcpy (h, header.buf, 16); @@ -1141,13 +1141,13 @@ namespace transport // we should handle payload even for zero token to handle Datetime block and adjust clock in case of clock skew LogPrint (eLogWarning, "SSU2: Retry token is zero"); return false; - } + } InitNoiseXKState1 (*m_NoiseState, m_Address->s); // reset Noise TODO: check state SendSessionRequest (token); return true; } - void SSU2Session::SendHolePunch (uint32_t nonce, const boost::asio::ip::udp::endpoint& ep, + void SSU2Session::SendHolePunch (uint32_t nonce, const boost::asio::ip::udp::endpoint& ep, const uint8_t * introKey, uint64_t token) { // we are Charlie @@ -1171,7 +1171,7 @@ namespace transport htobe32buf (payload + 3, i2p::util::GetSecondsSinceEpoch ()); size_t payloadSize = 7; payloadSize += CreateAddressBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize, ep); - payloadSize += CreateRelayResponseBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize, + payloadSize += CreateRelayResponseBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize, eSSU2RelayResponseCodeAccept, nonce, token, ep.address ().is_v4 ()); payloadSize += CreatePaddingBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize); // encrypt @@ -1243,7 +1243,7 @@ namespace transport size_t payloadSize = 7; if (msg == 6 || msg == 7) payloadSize += CreateAddressBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize, m_RemoteEndpoint); - payloadSize += CreatePeerTestBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize, + payloadSize += CreatePeerTestBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize, msg, eSSU2PeerTestCodeAccept, nullptr, signedData, signedDataLen); payloadSize += CreatePaddingBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize); // encrypt @@ -1257,8 +1257,8 @@ namespace transport i2p::crypto::ChaCha20 (h + 16, 16, introKey, n, h + 16); // send m_Server.Send (header.buf, 16, h + 16, 16, payload, payloadSize, m_RemoteEndpoint); - } - + } + bool SSU2Session::ProcessPeerTest (uint8_t * buf, size_t len) { // we are Alice or Charlie @@ -1337,7 +1337,7 @@ namespace transport LogPrint (eLogInfo, "SSU2: Remote endpoint update ", m_RemoteEndpoint, "->", from); m_RemoteEndpoint = from; SendPathChallenge (); - } + } uint8_t payload[SSU2_MAX_PACKET_SIZE]; size_t payloadSize = len - 32; uint32_t packetNum = be32toh (header.h.packetNum); @@ -1385,7 +1385,7 @@ namespace transport LogPrint (eLogDebug, "SSU2: RouterInfo"); auto ri = ExtractRouterInfo (buf + offset, size); if (ri) - i2p::data::netdb.AddRouterInfo (ri->GetBuffer (), ri->GetBufferLen ()); // TODO: add ri + i2p::data::netdb.AddRouterInfo (ri->GetBuffer (), ri->GetBufferLen ()); // TODO: add ri break; } case eSSU2BlkI2NPMessage: @@ -1413,7 +1413,7 @@ namespace transport LogPrint (eLogDebug, "SSU2: Termination reason=", (int)buf[11]); if (IsEstablished () && buf[11] != eSSU2TerminationReasonTerminationReceived) RequestTermination (eSSU2TerminationReasonTerminationReceived); - else + else Done (); break; case eSSU2BlkRelayRequest: @@ -1471,7 +1471,7 @@ namespace transport SendPathResponse (buf + offset, size); break; case eSSU2BlkPathResponse: - { + { LogPrint (eLogDebug, "SSU2: Path response"); if (m_PathChallenge) { @@ -1479,9 +1479,9 @@ namespace transport SHA256 (buf + offset, size, hash); if (hash == *m_PathChallenge) m_PathChallenge.reset (nullptr); - } + } break; - } + } case eSSU2BlkFirstPacketNumber: break; case eSSU2BlkPadding: @@ -1500,11 +1500,11 @@ namespace transport switch (m_State) { case eSSU2SessionStateSessionRequestReceived: - case eSSU2SessionStateTokenRequestReceived: + case eSSU2SessionStateTokenRequestReceived: if (std::abs (offset) > SSU2_CLOCK_SKEW) m_TerminationReason = eSSU2TerminationReasonClockSkew; break; - case eSSU2SessionStateSessionCreatedReceived: + case eSSU2SessionStateSessionCreatedReceived: case eSSU2SessionStateTokenReceived: if ((m_RemoteEndpoint.address ().is_v4 () && i2p::context.GetStatus () == eRouterStatusTesting) || (m_RemoteEndpoint.address ().is_v6 () && i2p::context.GetStatusV6 () == eRouterStatusTesting)) @@ -1522,19 +1522,19 @@ namespace transport LogPrint (eLogError, "SSU2: Clock skew detected ", offset, ". Check your clock"); i2p::context.SetError (eRouterErrorClockSkew); } - } - break; - default: ; - }; - } - + } + break; + default: ; + }; + } + void SSU2Session::HandleAck (const uint8_t * buf, size_t len) { if (m_State == eSSU2SessionStateSessionConfirmedSent) { Established (); return; - } + } if (m_SentPackets.empty ()) return; if (len < 5) return; // acnt @@ -1564,8 +1564,8 @@ namespace transport if (it == m_SentPackets.end () || it->first > lastPacketNum) return; // not found auto it1 = it; int numPackets = 0; - while (it1 != m_SentPackets.end () && it1->first <= lastPacketNum) - { + while (it1 != m_SentPackets.end () && it1->first <= lastPacketNum) + { if (ts && !it1->second->numResends) { if (ts > it1->second->sendTime) @@ -1575,28 +1575,28 @@ namespace transport m_RTO = m_RTT*SSU2_kAPPA; if (m_RTO < SSU2_MIN_RTO) m_RTO = SSU2_MIN_RTO; if (m_RTO > SSU2_MAX_RTO) m_RTO = SSU2_MAX_RTO; - } + } ts = 0; // update RTT one time per range - } + } it1++; numPackets++; - } + } m_SentPackets.erase (it, it1); if (numPackets > 0) { m_WindowSize += numPackets; if (m_WindowSize > SSU2_MAX_WINDOW_SIZE) m_WindowSize = SSU2_MAX_WINDOW_SIZE; - } + } } void SSU2Session::HandleAddress (const uint8_t * buf, size_t len) { boost::asio::ip::udp::endpoint ep; if (ExtractEndpoint (buf, len, ep)) - { + { LogPrint (eLogInfo, "SSU2: Our external address is ", ep); if (!i2p::util::net::IsInReservedRange (ep.address ())) - { + { i2p::context.UpdateAddress (ep.address ()); // check our port bool isV4 = ep.address ().is_v4 (); @@ -1606,30 +1606,30 @@ namespace transport { if (i2p::context.GetStatus () == eRouterStatusTesting) i2p::context.SetError (eRouterErrorSymmetricNAT); - } + } else { if (i2p::context.GetStatusV6 () == eRouterStatusTesting) i2p::context.SetErrorV6 (eRouterErrorSymmetricNAT); - } - } + } + } else { if (isV4) { if (i2p::context.GetError () == eRouterErrorSymmetricNAT) i2p::context.SetError (eRouterErrorNone); - } + } else { if (i2p::context.GetErrorV6 () == eRouterErrorSymmetricNAT) i2p::context.SetErrorV6 (eRouterErrorNone); - } - } - } - } - } - + } + } + } + } + } + void SSU2Session::HandleFirstFragment (const uint8_t * buf, size_t len) { uint32_t msgID; memcpy (&msgID, buf + 1, 4); @@ -1671,7 +1671,7 @@ namespace transport auto it = m_IncompleteMessages.find (msgID); if (it != m_IncompleteMessages.end ()) { - if (it->second->nextFragmentNum == fragmentNum && fragmentNum < SSU2_MAX_NUM_FRAGMENTS && + if (it->second->nextFragmentNum == fragmentNum && fragmentNum < SSU2_MAX_NUM_FRAGMENTS && it->second->msg) { // in sequence @@ -1707,7 +1707,7 @@ namespace transport { LogPrint (eLogWarning, "SSU2: Fragment number ", fragmentNum, " exceeds ", SSU2_MAX_NUM_FRAGMENTS); return; - } + } auto fragment = std::make_shared (); memcpy (fragment->buf, buf + 5, len -5); fragment->len = len - 5; @@ -1742,18 +1742,18 @@ namespace transport LogPrint (eLogWarning, "SSU2: RelayRequest session with relay tag ", relayTag, " not found"); // send relay response back to Alice uint8_t payload[SSU2_MAX_PACKET_SIZE]; - size_t payloadSize = CreateRelayResponseBlock (payload, m_MaxPayloadSize, + size_t payloadSize = CreateRelayResponseBlock (payload, m_MaxPayloadSize, eSSU2RelayResponseCodeBobRelayTagNotFound, bufbe32toh (buf + 1), 0, false); payloadSize += CreatePaddingBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize); SendData (payload, payloadSize); - return; + return; } session->m_RelaySessions.emplace (bufbe32toh (buf + 1), // nonce std::make_pair (shared_from_this (), i2p::util::GetSecondsSinceEpoch ()) ); // send relay intro to Charlie auto r = i2p::data::netdb.FindRouter (GetRemoteIdentity ()->GetIdentHash ()); // Alice's RI - if (r) + if (r) i2p::data::netdb.PopulateRouterInfoBuffer (r); else LogPrint (eLogWarning, "SSU2: RelayRequest Alice's router info not found"); @@ -1775,7 +1775,7 @@ namespace transport bool isV4 = false; auto r = i2p::data::netdb.FindRouter (buf + 1); // Alice if (r) - { + { SignedData s; s.Insert ((const uint8_t *)"RelayRequestData", 16); // prologue s.Insert (GetRemoteIdentity ()->GetIdentHash (), 32); // bhash @@ -1797,49 +1797,49 @@ namespace transport token = m_Server.GetIncomingToken (ep); isV4 = ep.address ().is_v4 (); SendHolePunch (bufbe32toh (buf + 33), ep, addr->i, token); - } + } else - { + { LogPrint (eLogWarning, "SSU2: RelayIntro unsupported address"); code = eSSU2RelayResponseCodeCharlieUnsupportedAddress; - } - } + } + } else { LogPrint (eLogWarning, "SSU2: RelayIntro unknown address"); - code = eSSU2RelayResponseCodeCharlieAliceIsUnknown; - } + code = eSSU2RelayResponseCodeCharlieAliceIsUnknown; + } } else { LogPrint (eLogWarning, "SSU2: RelayIntro can't extract endpoint"); - code = eSSU2RelayResponseCodeCharlieAliceIsUnknown; - } + code = eSSU2RelayResponseCodeCharlieAliceIsUnknown; + } } else { LogPrint (eLogWarning, "SSU2: RelayIntro signature verification failed"); code = eSSU2RelayResponseCodeCharlieSignatureFailure; } - } + } else { LogPrint (eLogError, "SSU2: RelayIntro unknown router to introduce"); code = eSSU2RelayResponseCodeCharlieAliceIsUnknown; - } + } // send relay response to Bob uint8_t payload[SSU2_MAX_PACKET_SIZE]; - size_t payloadSize = CreateRelayResponseBlock (payload, m_MaxPayloadSize, + size_t payloadSize = CreateRelayResponseBlock (payload, m_MaxPayloadSize, code, bufbe32toh (buf + 33), token, isV4); payloadSize += CreatePaddingBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize); SendData (payload, payloadSize); } void SSU2Session::HandleRelayResponse (const uint8_t * buf, size_t len) - { + { uint32_t nonce = bufbe32toh (buf + 2); - if (m_State == eSSU2SessionStateIntroduced) - { + if (m_State == eSSU2SessionStateIntroduced) + { // HolePunch from Charlie // TODO: verify address and signature // verify nonce @@ -1848,17 +1848,17 @@ namespace transport if (len >= 8) { // new token - uint64_t token; + uint64_t token; memcpy (&token, buf + len - 8, 8); m_Server.UpdateOutgoingToken (m_RemoteEndpoint, token, i2p::util::GetSecondsSinceEpoch () + SSU2_TOKEN_EXPIRATION_TIMEOUT); - } - return; - } - auto it = m_RelaySessions.find (nonce); + } + return; + } + auto it = m_RelaySessions.find (nonce); if (it != m_RelaySessions.end ()) { if (it->second.first && it->second.first->IsEstablished ()) - { + { // we are Bob, message from Charlie uint8_t payload[SSU2_MAX_PACKET_SIZE]; payload[0] = eSSU2BlkRelayResponse; @@ -1866,8 +1866,8 @@ namespace transport memcpy (payload + 3, buf, len); // forward to Alice as is size_t payloadSize = len + 3; payloadSize += CreatePaddingBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize); - it->second.first->SendData (payload, payloadSize); - } + it->second.first->SendData (payload, payloadSize); + } else { // we are Alice, message from Bob @@ -1882,12 +1882,12 @@ namespace transport if (s.Verify (it->second.first->GetRemoteIdentity (), buf + 12 + csz)) { if (it->second.first->m_State == eSSU2SessionStateIntroduced) // HolePunch not received yet - { + { // update Charlie's endpoint if (ExtractEndpoint (buf + 12, csz, it->second.first->m_RemoteEndpoint)) - { + { // update token - uint64_t token; + uint64_t token; memcpy (&token, buf + len - 8, 8); m_Server.UpdateOutgoingToken (it->second.first->m_RemoteEndpoint, token, i2p::util::GetSecondsSinceEpoch () + SSU2_TOKEN_EXPIRATION_TIMEOUT); @@ -1896,19 +1896,19 @@ namespace transport } else LogPrint (eLogWarning, "SSU2: RelayResponse can't extract endpoint"); - } + } } else - { + { LogPrint (eLogWarning, "SSU2: RelayResponse signature verification failed"); it->second.first->Done (); - } + } } else - { + { LogPrint (eLogInfo, "SSU2: RelayResponse status code=", (int)buf[1]); it->second.first->Done (); - } + } } m_RelaySessions.erase (it); } @@ -1921,13 +1921,13 @@ namespace transport if (len < 3) return; uint8_t msg = buf[0]; size_t offset = 3; // points to signed data - if (msg == 2 || msg == 4) offset += 32; // hash is presented for msg 2 and 4 only - if (len < offset + 5) return; - uint32_t nonce = bufbe32toh (buf + offset + 1); + if (msg == 2 || msg == 4) offset += 32; // hash is presented for msg 2 and 4 only + if (len < offset + 5) return; + uint32_t nonce = bufbe32toh (buf + offset + 1); switch (msg) // msg { case 1: // Bob from Alice - { + { auto session = m_Server.GetRandomSession ((buf[12] == 6) ? i2p::data::RouterInfo::eSSU2V4 : i2p::data::RouterInfo::eSSU2V6, GetRemoteIdentity ()->GetIdentHash ()); if (session) // session with Charlie @@ -1945,9 +1945,9 @@ namespace transport // doesn't fit one message, send RouterInfo in separate message session->SendData (payload, payloadSize); payloadSize = 0; - } + } // PeerTest to Charlie - payloadSize += CreatePeerTestBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize, 2, + payloadSize += CreatePeerTestBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize, 2, eSSU2PeerTestCodeAccept, GetRemoteIdentity ()->GetIdentHash (), buf + offset, len - offset); payloadSize += CreatePaddingBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize); session->SendData (payload, payloadSize); @@ -1956,11 +1956,11 @@ namespace transport { // Charlie not found, send error back to Alice uint8_t payload[SSU2_MAX_PACKET_SIZE], zeroHash[32] = {0}; - size_t payloadSize = CreatePeerTestBlock (payload, m_MaxPayloadSize, 4, + size_t payloadSize = CreatePeerTestBlock (payload, m_MaxPayloadSize, 4, eSSU2PeerTestCodeBobNoCharlieAvailable, zeroHash, buf + offset, len - offset); payloadSize += CreatePaddingBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize); SendData (payload, payloadSize); - } + } break; } case 2: // Charlie from Bob @@ -1973,7 +1973,7 @@ namespace transport s.Insert ((const uint8_t *)"PeerTestValidate", 16); // prologue s.Insert (GetRemoteIdentity ()->GetIdentHash (), 32); // bhash s.Insert (buf + 3, 32); // ahash - s.Insert (newSignedData.data (), asz + 10); // ver, nonce, ts, asz, Alice's endpoint + s.Insert (newSignedData.data (), asz + 10); // ver, nonce, ts, asz, Alice's endpoint s.Sign (i2p::context.GetPrivateKeys (), newSignedData.data () + 10 + asz); // send response (msg 3) back and msg 5 if accepted SSU2PeerTestCode code = eSSU2PeerTestCodeAccept; @@ -1982,39 +1982,39 @@ namespace transport { size_t signatureLen = r->GetIdentity ()->GetSignatureLen (); if (len >= offset + asz + 10 + signatureLen) - { + { s.Reset (); s.Insert ((const uint8_t *)"PeerTestValidate", 16); // prologue s.Insert (GetRemoteIdentity ()->GetIdentHash (), 32); // bhash s.Insert (buf + offset, asz + 10); // signed data if (s.Verify (r->GetIdentity (), buf + offset + asz + 10)) - { + { if (!m_Server.FindSession (r->GetIdentity ()->GetIdentHash ())) - { + { boost::asio::ip::udp::endpoint ep; std::shared_ptr addr; if (ExtractEndpoint (buf + offset + 10, asz, ep)) addr = r->GetSSU2Address (ep.address ().is_v4 ()); if (addr && m_Server.IsSupported (ep.address ())) - { + { // send msg 5 to Alice auto session = std::make_shared (m_Server, r, addr); - session->SetState (eSSU2SessionStatePeerTest); + session->SetState (eSSU2SessionStatePeerTest); session->m_RemoteEndpoint = ep; // might be different session->m_DestConnID = htobe64 (((uint64_t)nonce << 32) | nonce); session->m_SourceConnID = ~session->m_DestConnID; m_Server.AddSession (session); session->SendPeerTest (5, newSignedData.data (), newSignedData.size (), addr->i); - } + } else code = eSSU2PeerTestCodeCharlieUnsupportedAddress; } else code = eSSU2PeerTestCodeCharlieAliceIsAlreadyConnected; } - else - code = eSSU2PeerTestCodeCharlieSignatureFailure; - } + else + code = eSSU2PeerTestCodeCharlieSignatureFailure; + } else // maformed message code = eSSU2PeerTestCodeCharlieReasonUnspecified; } @@ -2022,12 +2022,12 @@ namespace transport code = eSSU2PeerTestCodeCharlieAliceIsUnknown; // send msg 3 back to Bob uint8_t payload[SSU2_MAX_PACKET_SIZE]; - size_t payloadSize = CreatePeerTestBlock (payload, m_MaxPayloadSize, 3, + size_t payloadSize = CreatePeerTestBlock (payload, m_MaxPayloadSize, 3, code, nullptr, newSignedData.data (), newSignedData.size ()); payloadSize += CreatePaddingBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize); SendData (payload, payloadSize); break; - } + } case 3: // Bob from Charlie { auto it = m_PeerTests.find (nonce); @@ -2047,7 +2047,7 @@ namespace transport payloadSize = 0; } // PeerTest to Alice - payloadSize += CreatePeerTestBlock (payload + payloadSize, m_MaxPayloadSize, 4, + payloadSize += CreatePeerTestBlock (payload + payloadSize, m_MaxPayloadSize, 4, (SSU2PeerTestCode)buf[1], GetRemoteIdentity ()->GetIdentHash (), buf + offset, len - offset); if (payloadSize < m_MaxPayloadSize) payloadSize += CreatePaddingBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize); @@ -2059,33 +2059,33 @@ namespace transport break; } case 4: // Alice from Bob - { + { auto it = m_PeerTests.find (nonce); if (it != m_PeerTests.end ()) { if (buf[1] == eSSU2PeerTestCodeAccept) - { + { if (GetRouterStatus () == eRouterStatusUnknown) SetRouterStatus (eRouterStatusTesting); auto r = i2p::data::netdb.FindRouter (buf + 3); // find Charlie if (r && it->second.first) - { + { uint8_t asz = buf[offset + 9]; SignedData s; s.Insert ((const uint8_t *)"PeerTestValidate", 16); // prologue s.Insert (GetRemoteIdentity ()->GetIdentHash (), 32); // bhash s.Insert (i2p::context.GetIdentity ()->GetIdentHash (), 32); // ahash - s.Insert (buf + offset, asz + 10); // ver, nonce, ts, asz, Alice's endpoint + s.Insert (buf + offset, asz + 10); // ver, nonce, ts, asz, Alice's endpoint if (s.Verify (r->GetIdentity (), buf + offset + asz + 10)) { it->second.first->SetRemoteIdentity (r->GetIdentity ()); auto addr = r->GetSSU2Address (m_Address->IsV4 ()); if (addr) - { + { it->second.first->m_Address = addr; if (it->second.first->m_State == eSSU2SessionStatePeerTestReceived) { - // msg 5 already received. send msg 6 + // msg 5 already received. send msg 6 SetRouterStatus (eRouterStatusOK); it->second.first->m_State = eSSU2SessionStatePeerTest; it->second.first->SendPeerTest (6, buf + offset, len - offset, addr->i); @@ -2093,13 +2093,13 @@ namespace transport else { if (GetRouterStatus () == eRouterStatusTesting) - { + { SetRouterStatus (eRouterStatusFirewalled); if (m_Address->IsV4 ()) m_Server.RescheduleIntroducersUpdateTimer (); else m_Server.RescheduleIntroducersUpdateTimerV6 (); - } + } } LogPrint (eLogDebug, "SSU2: Peer test 4 received from ", i2p::data::GetIdentHashAbbreviation (GetRemoteIdentity ()->GetIdentHash ()), " with information about ", i2p::data::GetIdentHashAbbreviation (i2p::data::IdentHash (buf + 3))); @@ -2108,14 +2108,14 @@ namespace transport { LogPrint (eLogWarning, "SSU2: Peer test 4 address not found"); it->second.first->Done (); - } + } } else - { + { LogPrint (eLogWarning, "SSU2: Peer test 4 signature verification failed"); it->second.first->Done (); - } - } + } + } else { LogPrint (eLogWarning, "SSU2: Peer test 4 Charlie's Router Info is not found"); @@ -2128,25 +2128,25 @@ namespace transport if (GetRouterStatus () == eRouterStatusTesting) SetRouterStatus (eRouterStatusUnknown); it->second.first->Done (); - } + } m_PeerTests.erase (it); - } + } else LogPrint (eLogWarning, "SSU2: Unknown peer test 4 nonce ", nonce); break; - } + } case 5: // Alice from Charlie 1 if (htobe64 (((uint64_t)nonce << 32) | nonce) == m_SourceConnID) { if (m_Address) - { + { SetRouterStatus (eRouterStatusOK); SendPeerTest (6, buf + offset, len - offset, m_Address->i); - } + } else // we received msg 5 before msg 4 m_State = eSSU2SessionStatePeerTestReceived; - } + } else LogPrint (eLogWarning, "SSU2: Peer test 5 nonce mismatch ", nonce, " connID=", m_SourceConnID); break; @@ -2220,49 +2220,49 @@ namespace transport if (m_Address) return i2p::context.GetRouterInfo ().GetSSU2Address (m_Address->IsV4 ()); return nullptr; - } + } void SSU2Session::AdjustMaxPayloadSize () { auto addr = FindLocalAddress (); - if (addr && addr->ssu) - { + if (addr && addr->ssu) + { int mtu = addr->ssu->mtu; if (!mtu && addr->IsV4 ()) mtu = SSU2_MAX_PACKET_SIZE; - if (m_Address && m_Address->ssu && (!mtu || m_Address->ssu->mtu < mtu)) + if (m_Address && m_Address->ssu && (!mtu || m_Address->ssu->mtu < mtu)) mtu = m_Address->ssu->mtu; if (mtu) - { + { if (mtu < (int)SSU2_MIN_PACKET_SIZE) mtu = SSU2_MIN_PACKET_SIZE; m_MaxPayloadSize = mtu - (addr->IsV6 () ? IPV6_HEADER_SIZE: IPV4_HEADER_SIZE) - UDP_HEADER_SIZE - 32; LogPrint (eLogDebug, "SSU2: Session MTU=", mtu, ", max payload size=", m_MaxPayloadSize); - } - } - } - + } + } + } + RouterStatus SSU2Session::GetRouterStatus () const { if (m_Address) { - if (m_Address->IsV4 ()) + if (m_Address->IsV4 ()) return i2p::context.GetStatus (); - if (m_Address->IsV6 ()) + if (m_Address->IsV6 ()) return i2p::context.GetStatusV6 (); - } + } return eRouterStatusUnknown; - } - + } + void SSU2Session::SetRouterStatus (RouterStatus status) const { if (m_Address) - { + { if (m_Address->IsV4 ()) i2p::context.SetStatusSSU2 (status); else if (m_Address->IsV6 ()) i2p::context.SetStatusV6SSU2 (status); - } - } - + } + } + size_t SSU2Session::CreateAddressBlock (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& ep) { if (len < 9) return 0; @@ -2324,11 +2324,11 @@ namespace transport { auto d = std::div (acnt - 255, 255); acnt = 255; - if (d.quot > maxNumRanges) - { + if (d.quot > maxNumRanges) + { d.quot = maxNumRanges; d.rem = 0; - } + } // Acks only ragnes for acnt for (int i = 0; i < d.quot; i++) { @@ -2339,21 +2339,21 @@ namespace transport { buf[8 + numRanges*2] = 0; buf[8 + numRanges*2 + 1] = d.rem; numRanges++; - } - } + } + } while (it != m_OutOfSequencePackets.rend () && numRanges < maxNumRanges) { if (lastNum - (*it) > 255) - { + { // NACKs only ranges - if (lastNum > (*it) + 255*(maxNumRanges - numRanges)) break; // too many NACKs + if (lastNum > (*it) + 255*(maxNumRanges - numRanges)) break; // too many NACKs while (lastNum - (*it) > 255) { buf[8 + numRanges*2] = 255; buf[8 + numRanges*2 + 1] = 0; // NACKs 255, Acks 0 lastNum -= 255; numRanges++; } - } + } // NACKs and Acks ranges buf[8 + numRanges*2] = lastNum - (*it) - 1; // NACKs lastNum = *it; it++; @@ -2369,12 +2369,12 @@ namespace transport buf[8 + numRanges*2 + 1] = 255; // Acks 255 numAcks -= 255; numRanges++; - buf[8 + numRanges*2] = 0; // NACKs 0 + buf[8 + numRanges*2] = 0; // NACKs 0 if (numRanges >= maxNumRanges) break; - } + } if (numAcks > 255) numAcks = 255; buf[8 + numRanges*2 + 1] = (uint8_t)numAcks; // Acks - numRanges++; + numRanges++; } if (numRanges < maxNumRanges && it == m_OutOfSequencePackets.rend ()) { @@ -2386,8 +2386,8 @@ namespace transport buf[8 + numRanges*2] = nacks; buf[8 + numRanges*2 + 1] = std::min ((int)m_ReceivePacketNum + 1, 255); numRanges++; - } - } + } + } } } buf[7] = (uint8_t)acnt; // acnt @@ -2472,7 +2472,7 @@ namespace transport return payloadSize + 3; } - size_t SSU2Session::CreateRelayResponseBlock (uint8_t * buf, size_t len, + size_t SSU2Session::CreateRelayResponseBlock (uint8_t * buf, size_t len, SSU2RelayResponseCode code, uint32_t nonce, uint64_t token, bool v4) { buf[0] = eSSU2BlkRelayResponse; @@ -2483,20 +2483,20 @@ namespace transport buf[13] = 2; // ver size_t csz = 0; if (code == eSSU2RelayResponseCodeAccept) - { + { auto addr = i2p::context.GetRouterInfo ().GetSSU2Address (v4); if (!addr) { LogPrint (eLogError, "SSU2: Can't find local address for RelayResponse"); return 0; - } + } csz = CreateEndpoint (buf + 15, len - 15, boost::asio::ip::udp::endpoint (addr->host, addr->port)); - if (!csz) - { + if (!csz) + { LogPrint (eLogError, "SSU2: Can't create local endpoint for RelayResponse"); return 0; - } - } + } + } buf[14] = csz; // csz // signature size_t signatureLen = i2p::context.GetIdentity ()->GetSignatureLen (); @@ -2504,7 +2504,7 @@ namespace transport { LogPrint (eLogError, "SSU2: Buffer for RelayResponse signature is too small ", len); return 0; - } + } SignedData s; s.Insert ((const uint8_t *)"RelayAgreementOK", 16); // prologue if (code == eSSU2RelayResponseCodeAccept || code >= 64) // Charlie @@ -2520,14 +2520,14 @@ namespace transport { LogPrint (eLogError, "SSU2: Buffer for RelayResponse token is too small ", len); return 0; - } + } memcpy (buf + 3 + payloadSize, &token, 8); payloadSize += 8; - } + } htobe16buf (buf + 1, payloadSize); // size return payloadSize + 3; } - + size_t SSU2Session::CreatePeerTestBlock (uint8_t * buf, size_t len, uint8_t msg, SSU2PeerTestCode code, const uint8_t * routerHash, const uint8_t * signedData, size_t signedDataLen) { @@ -2541,23 +2541,23 @@ namespace transport buf[5] = 0; //flag size_t offset = 6; if (routerHash) - { + { memcpy (buf + offset, routerHash, 32); // router hash offset += 32; - } + } memcpy (buf + offset, signedData, signedDataLen); return payloadSize + 3; } size_t SSU2Session::CreatePeerTestBlock (uint8_t * buf, size_t len, uint32_t nonce) { - auto localAddress = FindLocalAddress (); + auto localAddress = FindLocalAddress (); if (!localAddress || !localAddress->port || localAddress->host.is_unspecified () || - localAddress->host.is_v4 () != m_RemoteEndpoint.address ().is_v4 ()) + localAddress->host.is_v4 () != m_RemoteEndpoint.address ().is_v4 ()) { LogPrint (eLogWarning, "SSU2: Can't find local address for peer test"); return 0; - } + } // signed data auto ts = i2p::util::GetSecondsSinceEpoch (); uint8_t signedData[96]; @@ -2570,21 +2570,21 @@ namespace transport SignedData s; s.Insert ((const uint8_t *)"PeerTestValidate", 16); // prologue s.Insert (GetRemoteIdentity ()->GetIdentHash (), 32); // bhash - s.Insert (signedData, 10 + asz); // ver, nonce, ts, asz, Alice's endpoint + s.Insert (signedData, 10 + asz); // ver, nonce, ts, asz, Alice's endpoint s.Sign (i2p::context.GetPrivateKeys (), signedData + 10 + asz); - return CreatePeerTestBlock (buf, len, 1, eSSU2PeerTestCodeAccept, nullptr, + return CreatePeerTestBlock (buf, len, 1, eSSU2PeerTestCodeAccept, nullptr, signedData, 10 + asz + i2p::context.GetIdentity ()->GetSignatureLen ()); - } + } size_t SSU2Session::CreateTerminationBlock (uint8_t * buf, size_t len) - { + { buf[0] = eSSU2BlkTermination; htobe16buf (buf + 1, 9); htobe64buf (buf + 3, m_ReceivePacketNum); buf[11] = (uint8_t)m_TerminationReason; return 12; } - + std::shared_ptr SSU2Session::ExtractRouterInfo (const uint8_t * buf, size_t size) { if (size < 2) return nullptr; @@ -2655,13 +2655,13 @@ namespace transport { LogPrint (eLogWarning, "SSU2: Incorrect data size for path response ", len); return; - } + } uint8_t payload[SSU2_MAX_PACKET_SIZE]; payload[0] = eSSU2BlkPathResponse; htobe16buf (payload + 1, len); memcpy (payload + 3, data, len); SendData (payload, len + 3); - } + } void SSU2Session::SendPathChallenge () { @@ -2670,18 +2670,18 @@ namespace transport size_t len = rand () % (m_MaxPayloadSize - 3); htobe16buf (payload + 1, len); if (len > 0) - { + { RAND_bytes (payload + 3, len); i2p::data::IdentHash * hash = new i2p::data::IdentHash (); SHA256 (payload + 3, len, *hash); m_PathChallenge.reset (hash); - } + } len += 3; if (len < m_MaxPayloadSize) len += CreatePaddingBlock (payload + len, m_MaxPayloadSize - len); SendData (payload, len); - } - + } + void SSU2Session::CleanUp (uint64_t ts) { for (auto it = m_IncompleteMessages.begin (); it != m_IncompleteMessages.end ();) @@ -2695,8 +2695,8 @@ namespace transport ++it; } if (!m_OutOfSequencePackets.empty ()) - { - if (m_OutOfSequencePackets.size () > 2*SSU2_MAX_NUM_ACK_RANGES || + { + if (m_OutOfSequencePackets.size () > 2*SSU2_MAX_NUM_ACK_RANGES || *m_OutOfSequencePackets.rbegin () > m_ReceivePacketNum + 255*8) { uint32_t packet = *m_OutOfSequencePackets.begin (); @@ -2706,9 +2706,9 @@ namespace transport packet--; m_ReceivePacketNum = packet - 1; UpdateReceivePacketNum (packet); - } + } else - LogPrint (eLogError, "SSU2: Out of sequence packet ", packet, " is less than last received ", m_ReceivePacketNum); + LogPrint (eLogError, "SSU2: Out of sequence packet ", packet, " is less than last received ", m_ReceivePacketNum); } if (m_OutOfSequencePackets.size () > 255*4) { @@ -2716,8 +2716,8 @@ namespace transport m_ReceivePacketNum = *m_OutOfSequencePackets.rbegin (); m_OutOfSequencePackets.clear (); } - } - + } + for (auto it = m_RelaySessions.begin (); it != m_RelaySessions.end ();) { if (ts > it->second.second + SSU2_RELAY_NONCE_EXPIRATION_TIMEOUT) diff --git a/libi2pd/SSU2Session.h b/libi2pd/SSU2Session.h index 6797e8ce..a4306e68 100644 --- a/libi2pd/SSU2Session.h +++ b/libi2pd/SSU2Session.h @@ -49,8 +49,8 @@ namespace transport const uint8_t SSU2_MAX_NUM_FRAGMENTS = 64; // flags - const uint8_t SSU2_FLAG_IMMEDIATE_ACK_REQUESTED = 0x01; - + const uint8_t SSU2_FLAG_IMMEDIATE_ACK_REQUESTED = 0x01; + enum SSU2MessageType { eSSU2SessionRequest = 0, @@ -123,7 +123,7 @@ namespace transport eSSU2PeerTestCodeCharlieAliceIsBanned = 69, eSSU2PeerTestCodeCharlieAliceIsUnknown = 70, eSSU2PeerTestCodeUnspecified = 128 - }; + }; enum SSU2RelayResponseCode { @@ -132,7 +132,7 @@ namespace transport eSSU2RelayResponseCodeCharlieUnsupportedAddress = 65, eSSU2RelayResponseCodeCharlieSignatureFailure = 67, eSSU2RelayResponseCodeCharlieAliceIsUnknown = 70 - }; + }; enum SSU2TerminationReason { @@ -159,8 +159,8 @@ namespace transport eSSU2TerminationReasonIncompatibleVersion = 20, eSSU2TerminationReasonWrongNetID = 21, eSSU2TerminationReasonReplacedByNewSession = 22 - }; - + }; + struct SSU2IncompleteMessage { struct Fragment @@ -185,7 +185,7 @@ namespace transport uint64_t sendTime; // in milliseconds int numResends = 0; }; - + // RouterInfo flags const uint8_t SSU2_ROUTER_INFO_FLAG_REQUEST_FLOOD = 0x01; const uint8_t SSU2_ROUTER_INFO_FLAG_GZIP = 0x02; @@ -268,7 +268,7 @@ namespace transport bool SendFragmentedMessage (std::shared_ptr msg); void ResendHandshakePacket (); void ConnectAfterIntroduction (); - + void ProcessSessionRequest (Header& header, uint8_t * buf, size_t len); void ProcessTokenRequest (Header& header, uint8_t * buf, size_t len); @@ -282,10 +282,10 @@ namespace transport void SendQuickAck (); void SendTermination (); void SendHolePunch (uint32_t nonce, const boost::asio::ip::udp::endpoint& ep, const uint8_t * introKey, uint64_t token); - void SendPeerTest (uint8_t msg, const uint8_t * signedData, size_t signedDataLen, const uint8_t * introKey); // PeerTest message + void SendPeerTest (uint8_t msg, const uint8_t * signedData, size_t signedDataLen, const uint8_t * introKey); // PeerTest message void SendPathResponse (const uint8_t * data, size_t len); void SendPathChallenge (); - + void HandlePayload (const uint8_t * buf, size_t len); void HandleDateTime (const uint8_t * buf, size_t len); void HandleAck (const uint8_t * buf, size_t len); @@ -316,7 +316,7 @@ namespace transport size_t CreateFirstFragmentBlock (uint8_t * buf, size_t len, std::shared_ptr msg); size_t CreateFollowOnFragmentBlock (uint8_t * buf, size_t len, std::shared_ptr msg, uint8_t& fragmentNum, uint32_t msgID); size_t CreateRelayIntroBlock (uint8_t * buf, size_t len, const uint8_t * introData, size_t introDataLen); - size_t CreateRelayResponseBlock (uint8_t * buf, size_t len, SSU2RelayResponseCode code, uint32_t nonce, uint64_t token, bool v4); + size_t CreateRelayResponseBlock (uint8_t * buf, size_t len, SSU2RelayResponseCode code, uint32_t nonce, uint64_t token, bool v4); size_t CreatePeerTestBlock (uint8_t * buf, size_t len, uint8_t msg, SSU2PeerTestCode code, const uint8_t * routerHash, const uint8_t * signedData, size_t signedDataLen); size_t CreatePeerTestBlock (uint8_t * buf, size_t len, uint32_t nonce); // Alice size_t CreateTerminationBlock (uint8_t * buf, size_t len); diff --git a/libi2pd/TransportSession.h b/libi2pd/TransportSession.h index 53192816..ecaef425 100644 --- a/libi2pd/TransportSession.h +++ b/libi2pd/TransportSession.h @@ -27,7 +27,7 @@ namespace transport const size_t IPV4_HEADER_SIZE = 20; const size_t IPV6_HEADER_SIZE = 40; const size_t UDP_HEADER_SIZE = 8; - + class SignedData { public: @@ -42,7 +42,7 @@ namespace transport { m_Stream.str(""); } - + void Insert (const uint8_t * buf, size_t len) { m_Stream.write ((char *)buf, len); @@ -68,7 +68,7 @@ namespace transport std::stringstream m_Stream; }; - + class TransportSession { public: @@ -79,7 +79,7 @@ namespace transport { if (router) m_RemoteIdentity = router->GetRouterIdentity (); - m_CreationTime = m_LastActivityTimestamp; + m_CreationTime = m_LastActivityTimestamp; } virtual ~TransportSession () {}; @@ -109,7 +109,7 @@ namespace transport uint32_t GetCreationTime () const { return m_CreationTime; }; void SetCreationTime (uint32_t ts) { m_CreationTime = ts; }; // for introducers - + virtual uint32_t GetRelayTag () const { return 0; }; virtual void SendLocalRouterInfo (bool update = false) { SendI2NPMessages ({ CreateDatabaseStoreMsg () }); }; virtual void SendI2NPMessages (const std::vector >& msgs) = 0; diff --git a/libi2pd/Transports.cpp b/libi2pd/Transports.cpp index f1214889..fdd32d35 100644 --- a/libi2pd/Transports.cpp +++ b/libi2pd/Transports.cpp @@ -462,7 +462,7 @@ namespace transport { case i2p::data::RouterInfo::eNTCP2V4: case i2p::data::RouterInfo::eNTCP2V6: - { + { if (!m_NTCP2Server) continue; std::shared_ptr address = (tr == i2p::data::RouterInfo::eNTCP2V6) ? peer.router->GetPublishedNTCP2V6Address () : peer.router->GetPublishedNTCP2V4Address (); @@ -493,7 +493,7 @@ namespace transport return true; } break; - } + } case i2p::data::RouterInfo::eSSUV4: case i2p::data::RouterInfo::eSSUV6: { @@ -508,7 +508,7 @@ namespace transport return true; } break; - } + } case i2p::data::RouterInfo::eNTCP2V6Mesh: { if (!m_NTCP2Server) continue; @@ -518,14 +518,14 @@ namespace transport auto s = std::make_shared (*m_NTCP2Server, peer.router, address); m_NTCP2Server->Connect (s); return true; - } + } break; - } + } default: LogPrint (eLogError, "Transports: Unknown transport ", (int)tr); - } - } - + } + } + LogPrint (eLogInfo, "Transports: No compatible addresses available"); i2p::data::netdb.SetUnreachable (ident, true); // we are here because all connection attempts failed peer.Done (); @@ -538,14 +538,14 @@ namespace transport LogPrint (eLogInfo, "Transports: RouterInfo for ", ident.ToBase64 (), " not found, requested"); i2p::data::netdb.RequestDestination (ident, std::bind ( &Transports::RequestComplete, this, std::placeholders::_1, ident)); - } + } return true; - } - + } + void Transports::SetPriority (Peer& peer) const { - static const std::vector - ntcp2Priority = + static const std::vector + ntcp2Priority = { i2p::data::RouterInfo::eNTCP2V6, i2p::data::RouterInfo::eNTCP2V4, @@ -554,8 +554,8 @@ namespace transport i2p::data::RouterInfo::eNTCP2V6Mesh, i2p::data::RouterInfo::eSSUV6, i2p::data::RouterInfo::eSSUV4 - }, - ssu2Priority = + }, + ssu2Priority = { i2p::data::RouterInfo::eSSU2V6, i2p::data::RouterInfo::eSSU2V4, @@ -564,7 +564,7 @@ namespace transport i2p::data::RouterInfo::eNTCP2V6Mesh, i2p::data::RouterInfo::eSSUV6, i2p::data::RouterInfo::eSSUV4 - }; + }; if (!peer.router) return; auto compatibleTransports = context.GetRouterInfo ().GetCompatibleTransports (false) & peer.router->GetCompatibleTransports (true); @@ -574,9 +574,9 @@ namespace transport const auto& priority = ssu2 ? ssu2Priority : ntcp2Priority; for (auto transport: priority) if (transport & compatibleTransports) - peer.priority.push_back (transport); - } - + peer.priority.push_back (transport); + } + void Transports::RequestComplete (std::shared_ptr r, const i2p::data::IdentHash& ident) { m_Service->post (std::bind (&Transports::HandleRequestComplete, this, r, ident)); @@ -834,7 +834,7 @@ namespace transport auto session = it->second.sessions.front (); if (session) session->SendLocalRouterInfo (true); - it->second.nextRouterInfoUpdateTime = ts + PEER_ROUTER_INFO_UPDATE_INTERVAL + + it->second.nextRouterInfoUpdateTime = ts + PEER_ROUTER_INFO_UPDATE_INTERVAL + rand () % PEER_ROUTER_INFO_UPDATE_INTERVAL_VARIANCE; } ++it; @@ -1074,6 +1074,6 @@ namespace transport i2p::context.PublishSSU2Address (ssu2port, false, ipv4, ipv6); // unpublish } - } + } } } diff --git a/libi2pd/Transports.h b/libi2pd/Transports.h index 362c5ead..c9e1c5f4 100644 --- a/libi2pd/Transports.h +++ b/libi2pd/Transports.h @@ -62,8 +62,8 @@ namespace transport }; typedef EphemeralKeysSupplier X25519KeysPairSupplier; - const int PEER_ROUTER_INFO_UPDATE_INTERVAL = 31*60; // in seconds - const int PEER_ROUTER_INFO_UPDATE_INTERVAL_VARIANCE = 7*60; // in seconds + const int PEER_ROUTER_INFO_UPDATE_INTERVAL = 31*60; // in seconds + const int PEER_ROUTER_INFO_UPDATE_INTERVAL_VARIANCE = 7*60; // in seconds struct Peer { int numAttempts; @@ -77,8 +77,8 @@ namespace transport numAttempts (0), router (r), creationTime (ts), nextRouterInfoUpdateTime (ts + PEER_ROUTER_INFO_UPDATE_INTERVAL) { - } - + } + void Done () { for (auto& it: sessions) diff --git a/libi2pd_client/AddressBook.cpp b/libi2pd_client/AddressBook.cpp index 7928792f..fe655643 100644 --- a/libi2pd_client/AddressBook.cpp +++ b/libi2pd_client/AddressBook.cpp @@ -313,14 +313,14 @@ namespace client { i2p::config::GetOption("addressbook.enabled", m_IsEnabled); if (m_IsEnabled) - { + { if (!m_Storage) m_Storage = new AddressBookFilesystemStorage; m_Storage->Init(); LoadHosts (); /* try storage, then hosts.txt, then download */ StartSubscriptions (); StartLookups (); - } + } } void AddressBook::StartResolvers () diff --git a/libi2pd_client/ClientContext.cpp b/libi2pd_client/ClientContext.cpp index a5e1c67c..33500705 100644 --- a/libi2pd_client/ClientContext.cpp +++ b/libi2pd_client/ClientContext.cpp @@ -727,7 +727,7 @@ namespace client std::string address = section.second.get (I2P_SERVER_TUNNEL_ADDRESS, ""); bool isUniqueLocal = section.second.get(I2P_SERVER_TUNNEL_ENABLE_UNIQUE_LOCAL, true); bool ssl = section.second.get(I2P_SERVER_TUNNEL_SSL, false); - + // I2CP std::map options; ReadI2CPOptions (section, true, options); @@ -868,7 +868,7 @@ namespace client std::string httpOutProxyURL; i2p::config::GetOption("httpproxy.outproxy", httpOutProxyURL); bool httpAddresshelper; i2p::config::GetOption("httpproxy.addresshelper", httpAddresshelper); if (httpAddresshelper) - i2p::config::GetOption("addressbook.enabled", httpAddresshelper); // addresshelper is not supported without address book + i2p::config::GetOption("addressbook.enabled", httpAddresshelper); // addresshelper is not supported without address book i2p::data::SigningKeyType sigType; i2p::config::GetOption("httpproxy.signaturetype", sigType); LogPrint(eLogInfo, "Clients: Starting HTTP Proxy at ", httpProxyAddr, ":", httpProxyPort); if (httpProxyKeys.length () > 0) diff --git a/libi2pd_client/I2PTunnel.cpp b/libi2pd_client/I2PTunnel.cpp index 8bf0e38d..49c837f5 100644 --- a/libi2pd_client/I2PTunnel.cpp +++ b/libi2pd_client/I2PTunnel.cpp @@ -86,7 +86,7 @@ namespace client static void MapToLoopback(std::shared_ptr sock, const i2p::data::IdentHash & addr) { if (sock) - { + { // bind to 127.x.x.x address // where x.x.x are first three bytes from ident auto ourIP = GetLoopbackAddressFor(addr); @@ -101,7 +101,7 @@ namespace client void I2PTunnelConnection::Connect (bool isUniqueLocal) { if (m_Socket) - { + { I2PTunnelSetSocketOptions (m_Socket); #ifdef __linux__ if (isUniqueLocal && m_RemoteEndpoint.address ().is_v4 () && @@ -132,7 +132,7 @@ namespace client } Connect (false); } - + void I2PTunnelConnection::Terminate () { if (Kill()) return; @@ -155,7 +155,7 @@ namespace client m_SSL->async_read_some (boost::asio::buffer(m_Buffer, I2P_TUNNEL_CONNECTION_BUFFER_SIZE), std::bind(&I2PTunnelConnection::HandleReceive, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); - else + else m_Socket->async_read_some (boost::asio::buffer(m_Buffer, I2P_TUNNEL_CONNECTION_BUFFER_SIZE), std::bind(&I2PTunnelConnection::HandleReceive, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); @@ -253,7 +253,7 @@ namespace client if (m_SSL) boost::asio::async_write (*m_SSL, boost::asio::buffer (buf, len), boost::asio::transfer_all (), std::bind (&I2PTunnelConnection::HandleWrite, shared_from_this (), std::placeholders::_1)); - else + else boost::asio::async_write (*m_Socket, boost::asio::buffer (buf, len), boost::asio::transfer_all (), std::bind (&I2PTunnelConnection::HandleWrite, shared_from_this (), std::placeholders::_1)); } @@ -269,9 +269,9 @@ namespace client { LogPrint (eLogDebug, "I2PTunnel: Connected"); if (m_SSL) - m_SSL->async_handshake (boost::asio::ssl::stream_base::client, + m_SSL->async_handshake (boost::asio::ssl::stream_base::client, std::bind (&I2PTunnelConnection::HandleHandshake, shared_from_this (), std::placeholders::_1)); - else + else Established (); } } @@ -289,7 +289,7 @@ namespace client Established (); } } - + void I2PTunnelConnection::Established () { if (m_IsQuiet) @@ -305,8 +305,8 @@ namespace client HandleStreamReceive (boost::system::error_code (), dest.size ()); } Receive (); - } - + } + void I2PClientTunnelConnectionHTTP::Write (const uint8_t * buf, size_t len) { if (m_HeaderSent) @@ -363,9 +363,9 @@ namespace client StreamReceive (); // read more header else { - LogPrint (eLogError, "I2PTunnel: HTTP header exceeds max size ", I2P_TUNNEL_HTTP_MAX_HEADER_SIZE); + LogPrint (eLogError, "I2PTunnel: HTTP header exceeds max size ", I2P_TUNNEL_HTTP_MAX_HEADER_SIZE); Terminate (); - } + } } } @@ -376,7 +376,7 @@ namespace client m_HeaderSent (false), m_ResponseHeaderSent (false), m_From (stream->GetRemoteIdentity ()) { if (sslCtx) - SSL_set_tlsext_host_name(GetSSL ()->native_handle(), host.c_str ()); + SSL_set_tlsext_host_name(GetSSL ()->native_handle(), host.c_str ()); } void I2PServerTunnelConnectionHTTP::Write (const uint8_t * buf, size_t len) @@ -400,7 +400,7 @@ namespace client // strip up some headers static const std::vector excluded // list of excluded headers { - "Keep-Alive:", "X-I2P" + "Keep-Alive:", "X-I2P" }; bool matched = false; for (const auto& it: excluded) @@ -422,8 +422,8 @@ namespace client else m_OutHeader << "Connection: close\r\n"; connection = true; - } - else // forward as is + } + else // forward as is m_OutHeader << line << "\n"; } } @@ -455,7 +455,7 @@ namespace client StreamReceive (); // read more header else { - LogPrint (eLogError, "I2PTunnel: HTTP header exceeds max size ", I2P_TUNNEL_HTTP_MAX_HEADER_SIZE); + LogPrint (eLogError, "I2PTunnel: HTTP header exceeds max size ", I2P_TUNNEL_HTTP_MAX_HEADER_SIZE); Terminate (); } } @@ -526,7 +526,7 @@ namespace client if (m_NeedsWebIrc) { m_NeedsWebIrc = false; - m_OutPacket << "WEBIRC " << m_WebircPass << " cgiirc " << context.GetAddressBook ().ToAddress (m_From->GetIdentHash ()) + m_OutPacket << "WEBIRC " << m_WebircPass << " cgiirc " << context.GetAddressBook ().ToAddress (m_From->GetIdentHash ()) << " " << GetSocket ()->local_endpoint ().address () << std::endl; } @@ -719,7 +719,7 @@ namespace client auto localDestination = GetLocalDestination (); if (localDestination) localDestination->StopAcceptingStreams (); - + ClearHandlers (); } @@ -796,14 +796,14 @@ namespace client void I2PServerTunnel::SetSSL (bool ssl) { if (ssl) - { + { m_SSLCtx = std::make_shared (boost::asio::ssl::context::sslv23); m_SSLCtx->set_verify_mode(boost::asio::ssl::context::verify_none); - } + } else m_SSLCtx = nullptr; - } - + } + void I2PServerTunnel::Accept () { if (m_PortDestination) @@ -1004,7 +1004,7 @@ namespace client I2PUDPServerTunnel::I2PUDPServerTunnel (const std::string & name, std::shared_ptr localDestination, boost::asio::ip::address localAddress, boost::asio::ip::udp::endpoint forwardTo, uint16_t port, bool gzip) : - m_IsUniqueLocal (true), m_Name (name), m_LocalAddress (localAddress), + m_IsUniqueLocal (true), m_Name (name), m_LocalAddress (localAddress), m_RemoteEndpoint (forwardTo), m_LocalDest (localDestination), m_Gzip (gzip) { } diff --git a/libi2pd_client/I2PTunnel.h b/libi2pd_client/I2PTunnel.h index 4f61ef91..658f1cc7 100644 --- a/libi2pd_client/I2PTunnel.h +++ b/libi2pd_client/I2PTunnel.h @@ -36,7 +36,7 @@ namespace client const char X_I2P_DEST_B64[] = "X-I2P-DestB64"; // full address in base64 const char X_I2P_DEST_B32[] = "X-I2P-DestB32"; // .b32.i2p address const int I2P_TUNNEL_HTTP_MAX_HEADER_SIZE = 8192; - + class I2PTunnelConnection: public I2PServiceHandler, public std::enable_shared_from_this { public: @@ -73,7 +73,7 @@ namespace client void HandleReceive (const boost::system::error_code& ecode, std::size_t bytes_transferred); void HandleWrite (const boost::system::error_code& ecode); void HandleStreamReceive (const boost::system::error_code& ecode, std::size_t bytes_transferred); - + private: uint8_t m_Buffer[I2P_TUNNEL_CONNECTION_BUFFER_SIZE], m_StreamBuffer[I2P_TUNNEL_CONNECTION_BUFFER_SIZE]; @@ -350,9 +350,9 @@ namespace client void SetUniqueLocal (bool isUniqueLocal) { m_IsUniqueLocal = isUniqueLocal; } bool IsUniqueLocal () const { return m_IsUniqueLocal; } - void SetSSL (bool ssl); + void SetSSL (bool ssl); std::shared_ptr GetSSLCtx () const { return m_SSLCtx; }; - + void SetLocalAddress (const std::string& localAddress); const std::string& GetAddress() const { return m_Address; } diff --git a/libi2pd_client/SAM.cpp b/libi2pd_client/SAM.cpp index 5d0f4425..77a48efc 100644 --- a/libi2pd_client/SAM.cpp +++ b/libi2pd_client/SAM.cpp @@ -1481,7 +1481,7 @@ namespace client auto localDest = session->GetLocalDestination (); auto datagramDest = localDest ? localDest->GetDatagramDestination () : nullptr; if (datagramDest) - { + { i2p::data::IdentityEx dest; dest.FromBase64 (destination); if (session->Type == eSAMSessionTypeDatagram) @@ -1490,7 +1490,7 @@ namespace client datagramDest->SendRawDatagramTo ((uint8_t *)eol, payloadLen, dest.GetIdentHash ()); else LogPrint (eLogError, "SAM: Unexpected session type ", (int)session->Type, "for session ", sessionID); - } + } else LogPrint (eLogError, "SAM: Datagram destination is not set for session ", sessionID); } From 3544f77e90034ff104fd8aaddf32da45e0d0f900 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 9 Oct 2022 15:03:32 -0400 Subject: [PATCH 174/219] terminate peer session if Charlie's RouterInfo not found --- libi2pd/SSU2Session.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index 7a6845d8..d2024c2f 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -2118,7 +2118,9 @@ namespace transport } else { - LogPrint (eLogWarning, "SSU2: Peer test 4 Charlie's Router Info is not found"); + LogPrint (eLogWarning, "SSU2: Peer test 4 router not found"); + if (it->second.first) + it->second.first->Done (); } } else From 798dd8b27b48cb164b29285d832bd816fc3c19d7 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Sun, 9 Oct 2022 22:13:49 +0300 Subject: [PATCH 175/219] [HTTP Proxy] skip addresshelper page if destination is not changed (closes #1789) Signed-off-by: R4SAS --- libi2pd_client/AddressBook.cpp | 13 +++++++++++++ libi2pd_client/AddressBook.h | 2 ++ libi2pd_client/HTTPProxy.cpp | 32 ++++++++++++++++++++++++++------ 3 files changed, 41 insertions(+), 6 deletions(-) diff --git a/libi2pd_client/AddressBook.cpp b/libi2pd_client/AddressBook.cpp index fe655643..3a35a817 100644 --- a/libi2pd_client/AddressBook.cpp +++ b/libi2pd_client/AddressBook.cpp @@ -397,6 +397,19 @@ namespace client return nullptr; } + bool AddressBook::RecordExists (const std::string& address, const std::string& jump) + { + auto addr = FindAddress(address); + if (!addr) + return false; + + i2p::data::IdentityEx ident; + if (ident.FromBase64 (jump) && ident.GetIdentHash () == addr->identHash) + return true; + + return false; + } + void AddressBook::InsertAddress (const std::string& address, const std::string& jump) { auto pos = jump.find(".b32.i2p"); diff --git a/libi2pd_client/AddressBook.h b/libi2pd_client/AddressBook.h index 192c4ebb..9b2c7e7e 100644 --- a/libi2pd_client/AddressBook.h +++ b/libi2pd_client/AddressBook.h @@ -90,6 +90,8 @@ namespace client void InsertAddress (const std::string& address, const std::string& jump); // for jump links void InsertFullAddress (std::shared_ptr address); + bool RecordExists (const std::string& address, const std::string& jump); + bool LoadHostsFromStream (std::istream& f, bool is_update); void DownloadComplete (bool success, const i2p::data::IdentHash& subscription, const std::string& etag, const std::string& lastModified); //This method returns the ".b32.i2p" address diff --git a/libi2pd_client/HTTPProxy.cpp b/libi2pd_client/HTTPProxy.cpp index 73677836..499d12a9 100644 --- a/libi2pd_client/HTTPProxy.cpp +++ b/libi2pd_client/HTTPProxy.cpp @@ -80,8 +80,9 @@ namespace proxy { /* error helpers */ void GenericProxyError(const std::string& title, const std::string& description); void GenericProxyInfo(const std::string& title, const std::string& description); - void HostNotFound(std::string & host); - void SendProxyError(std::string & content); + void HostNotFound(std::string& host); + void SendProxyError(std::string& content); + void SendRedirect(std::string& address); void ForwardToUpstreamProxy(); void HandleUpstreamHTTPProxyConnect(const boost::system::error_code & ec); @@ -174,7 +175,7 @@ namespace proxy { SendProxyError(content); } - void HTTPReqHandler::HostNotFound(std::string & host) { + void HTTPReqHandler::HostNotFound(std::string& host) { std::stringstream ss; ss << "

" << tr("Proxy error: Host not found") << "

\r\n" << "

" << tr("Remote host not found in router's addressbook") << "

\r\n" @@ -191,7 +192,7 @@ namespace proxy { SendProxyError(content); } - void HTTPReqHandler::SendProxyError(std::string & content) + void HTTPReqHandler::SendProxyError(std::string& content) { i2p::http::HTTPRes res; res.code = 500; @@ -207,6 +208,17 @@ namespace proxy { std::bind(&HTTPReqHandler::SentHTTPFailed, shared_from_this(), std::placeholders::_1)); } + void HTTPReqHandler::SendRedirect(std::string& address) + { + i2p::http::HTTPRes res; + res.code = 302; + res.add_header("Location", address); + res.add_header("Connection", "close"); + std::string response = res.to_string(); + boost::asio::async_write(*m_sock, boost::asio::buffer(response), boost::asio::transfer_all(), + std::bind(&HTTPReqHandler::SentHTTPFailed, shared_from_this(), std::placeholders::_1)); + } + bool HTTPReqHandler::ExtractAddressHelper(i2p::http::URL & url, std::string & b64, bool & confirm) { confirm = false; @@ -297,7 +309,14 @@ namespace proxy { GenericProxyError(tr("Invalid request"), tr("addresshelper is not supported")); return true; } - if (!i2p::client::context.GetAddressBook ().FindAddress (m_RequestURL.host) || m_Confirm) + + if (i2p::client::context.GetAddressBook ().RecordExists (m_RequestURL.host, jump)) + { + std::string full_url = m_RequestURL.to_string(); + SendRedirect(full_url); + return true; + } + else if (!i2p::client::context.GetAddressBook ().FindAddress (m_RequestURL.host) || m_Confirm) { i2p::client::context.GetAddressBook ().InsertAddress (m_RequestURL.host, jump); LogPrint (eLogInfo, "HTTPProxy: Added address from addresshelper for ", m_RequestURL.host); @@ -313,7 +332,8 @@ namespace proxy { std::string full_url = m_RequestURL.to_string(); std::stringstream ss; ss << tr("Host") << " " << m_RequestURL.host << " " << tr("already in router's addressbook") << ". "; - ss << tr(/* tr: The "record" means addressbook's record. That message appears when domain was already added to addressbook, but helper link is opened for it. */ "Click here to update record:" ) << " " << tr("Continue") << "."; GenericProxyInfo(tr("Addresshelper found"), ss.str()); return true; /* request processed */ From 1d9d89b1157e6a29832ec81ea6adbf52a930d5de Mon Sep 17 00:00:00 2001 From: R4SAS Date: Mon, 10 Oct 2022 15:43:37 +0300 Subject: [PATCH 176/219] [transports] get addresses on interfaeces before initializing RouterContext Signed-off-by: R4SAS --- daemon/Daemon.cpp | 2 ++ libi2pd/Transports.cpp | 12 +++++++++--- libi2pd/Transports.h | 1 + 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/daemon/Daemon.cpp b/daemon/Daemon.cpp index bff17e09..7b09feeb 100644 --- a/daemon/Daemon.cpp +++ b/daemon/Daemon.cpp @@ -157,6 +157,8 @@ namespace util precomputation = false; // we don't elgamal table if no ssu, unless it's specified explicitly i2p::crypto::InitCrypto (precomputation, aesni, avx, forceCpuExt); + i2p::transport::InitAddressFromIface (); // get address4/6 from interfaces + int netID; i2p::config::GetOption("netid", netID); i2p::context.SetNetID (netID); i2p::context.Init (); diff --git a/libi2pd/Transports.cpp b/libi2pd/Transports.cpp index fdd32d35..6dac23de 100644 --- a/libi2pd/Transports.cpp +++ b/libi2pd/Transports.cpp @@ -965,7 +965,7 @@ namespace transport } } - void InitTransports () + void InitAddressFromIface () { bool ipv6; i2p::config::GetOption("ipv6", ipv6); bool ipv4; i2p::config::GetOption("ipv4", ipv4); @@ -988,8 +988,15 @@ namespace transport else if (!ifname.empty ()) i2p::config::SetOption ("address6", i2p::util::net::GetInterfaceAddress(ifname, true).to_string ()); // v6 } + } + + void InitTransports () + { + bool ipv6; i2p::config::GetOption("ipv6", ipv6); + bool ipv4; i2p::config::GetOption("ipv4", ipv4); + bool ygg; i2p::config::GetOption("meshnets.yggdrasil", ygg); + uint16_t port; i2p::config::GetOption("port", port); - bool ygg; i2p::config::GetOption("meshnets.yggdrasil", ygg); boost::asio::ip::address_v6 yggaddr; if (ygg) { @@ -1015,7 +1022,6 @@ namespace transport } } - uint16_t port; i2p::config::GetOption("port", port); if (!i2p::config::IsDefault("port")) { LogPrint(eLogInfo, "Transports: Accepting incoming connections at port ", port); diff --git a/libi2pd/Transports.h b/libi2pd/Transports.h index c9e1c5f4..4ee08af2 100644 --- a/libi2pd/Transports.h +++ b/libi2pd/Transports.h @@ -204,6 +204,7 @@ namespace transport extern Transports transports; + void InitAddressFromIface (); void InitTransports (); } } From c2f91ea63b50f1345fd401fc2f97b2abdf216676 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 10 Oct 2022 11:02:19 -0400 Subject: [PATCH 177/219] SSL connection for IRC server tunnel --- libi2pd_client/I2PTunnel.cpp | 7 ++++--- libi2pd_client/I2PTunnel.h | 3 ++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/libi2pd_client/I2PTunnel.cpp b/libi2pd_client/I2PTunnel.cpp index 49c837f5..12fa08e2 100644 --- a/libi2pd_client/I2PTunnel.cpp +++ b/libi2pd_client/I2PTunnel.cpp @@ -514,8 +514,9 @@ namespace client } I2PTunnelConnectionIRC::I2PTunnelConnectionIRC (I2PService * owner, std::shared_ptr stream, - const boost::asio::ip::tcp::endpoint& target, const std::string& webircpass): - I2PTunnelConnection (owner, stream, target), m_From (stream->GetRemoteIdentity ()), + const boost::asio::ip::tcp::endpoint& target, const std::string& webircpass, + std::shared_ptr sslCtx): + I2PTunnelConnection (owner, stream, target, true, sslCtx), m_From (stream->GetRemoteIdentity ()), m_NeedsWebIrc (webircpass.length() ? true : false), m_WebircPass (webircpass) { } @@ -871,7 +872,7 @@ namespace client std::shared_ptr I2PServerTunnelIRC::CreateI2PConnection (std::shared_ptr stream) { - return std::make_shared (this, stream, GetEndpoint (), m_WebircPass); + return std::make_shared (this, stream, GetEndpoint (), m_WebircPass, GetSSLCtx ()); } void I2PUDPServerTunnel::HandleRecvFromI2P(const i2p::data::IdentityEx& from, uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len) diff --git a/libi2pd_client/I2PTunnel.h b/libi2pd_client/I2PTunnel.h index 658f1cc7..0da11a46 100644 --- a/libi2pd_client/I2PTunnel.h +++ b/libi2pd_client/I2PTunnel.h @@ -129,7 +129,8 @@ namespace client public: I2PTunnelConnectionIRC (I2PService * owner, std::shared_ptr stream, - const boost::asio::ip::tcp::endpoint& target, const std::string& m_WebircPass); + const boost::asio::ip::tcp::endpoint& target, const std::string& m_WebircPass, + std::shared_ptr sslCtx = nullptr); protected: From 55976fd9dc3d75ae0c21a4085a112a85b6e809ef Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 10 Oct 2022 16:34:08 -0400 Subject: [PATCH 178/219] resend PeerTest msg 1 --- libi2pd/SSU2Session.cpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index d2024c2f..64a6cbdc 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -178,13 +178,15 @@ namespace transport session->m_DestConnID = ~session->m_SourceConnID; m_Server.AddSession (session); // peer test block - uint8_t payload[SSU2_MAX_PACKET_SIZE]; - size_t payloadSize = CreatePeerTestBlock (payload, m_MaxPayloadSize, nonce); - if (payloadSize > 0) + auto packet = m_Server.GetSentPacketsPool ().AcquireShared (); + packet->payloadSize = CreatePeerTestBlock (packet->payload, m_MaxPayloadSize, nonce); + if (packet->payloadSize > 0) { - payloadSize += CreatePaddingBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize); - SendData (payload, payloadSize); - LogPrint (eLogDebug, "SSU2: PeerTest sent to ", i2p::data::GetIdentHashAbbreviation (GetRemoteIdentity ()->GetIdentHash ())); + packet->payloadSize += CreatePaddingBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize); + uint32_t packetNum = SendData (packet->payload, packet->payloadSize, SSU2_FLAG_IMMEDIATE_ACK_REQUESTED); + packet->sendTime = ts; + m_SentPackets.emplace (packetNum, packet); + LogPrint (eLogDebug, "SSU2: PeerTest msg=1 sent to ", i2p::data::GetIdentHashAbbreviation (GetRemoteIdentity ()->GetIdentHash ())); } } From 6e3cec653d4202fd9214f1b9166bf38717817ee3 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 11 Oct 2022 15:27:19 -0400 Subject: [PATCH 179/219] resend PeerTest msg 2 --- libi2pd/SSU2Session.cpp | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index 64a6cbdc..3f41ad3f 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -1925,6 +1925,7 @@ namespace transport size_t offset = 3; // points to signed data if (msg == 2 || msg == 4) offset += 32; // hash is presented for msg 2 and 4 only if (len < offset + 5) return; + auto ts = i2p::util::GetSecondsSinceEpoch (); uint32_t nonce = bufbe32toh (buf + offset + 1); switch (msg) // msg { @@ -1935,24 +1936,28 @@ namespace transport if (session) // session with Charlie { session->m_PeerTests.emplace (nonce, std::make_pair (shared_from_this (), i2p::util::GetSecondsSinceEpoch ())); - uint8_t payload[SSU2_MAX_PACKET_SIZE]; + auto packet = m_Server.GetSentPacketsPool ().AcquireShared (); // Alice's RouterInfo auto r = i2p::data::netdb.FindRouter (GetRemoteIdentity ()->GetIdentHash ()); if (r) i2p::data::netdb.PopulateRouterInfoBuffer (r); - size_t payloadSize = r ? CreateRouterInfoBlock (payload, m_MaxPayloadSize - len - 32, r) : 0; - if (!payloadSize && r) + packet->payloadSize = r ? CreateRouterInfoBlock (packet->payload, m_MaxPayloadSize - len - 32, r) : 0; + if (!packet->payloadSize && r) session->SendFragmentedMessage (CreateDatabaseStoreMsg (r)); - if (payloadSize + len + 48 > m_MaxPayloadSize) + if (packet->payloadSize + len + 48 > m_MaxPayloadSize) { // doesn't fit one message, send RouterInfo in separate message - session->SendData (payload, payloadSize); - payloadSize = 0; + uint32_t packetNum = session->SendData (packet->payload, packet->payloadSize, SSU2_FLAG_IMMEDIATE_ACK_REQUESTED); + packet->sendTime = ts; + session->m_SentPackets.emplace (packetNum, packet); + packet = m_Server.GetSentPacketsPool ().AcquireShared (); // new packet } // PeerTest to Charlie - payloadSize += CreatePeerTestBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize, 2, + packet->payloadSize += CreatePeerTestBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize, 2, eSSU2PeerTestCodeAccept, GetRemoteIdentity ()->GetIdentHash (), buf + offset, len - offset); - payloadSize += CreatePaddingBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize); - session->SendData (payload, payloadSize); + packet->payloadSize += CreatePaddingBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize); + uint32_t packetNum = session->SendData (packet->payload, packet->payloadSize, SSU2_FLAG_IMMEDIATE_ACK_REQUESTED); + packet->sendTime = ts; + session->m_SentPackets.emplace (packetNum, packet); } else { From e5553f7528c7fe205f17f5b7487678bd2321b1f4 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 11 Oct 2022 18:21:04 -0400 Subject: [PATCH 180/219] milliseconds for peer test send time --- libi2pd/SSU2Session.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index 3f41ad3f..493a8a76 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -169,11 +169,11 @@ namespace transport // we are Alice uint32_t nonce; RAND_bytes ((uint8_t *)&nonce, 4); - auto ts = i2p::util::GetSecondsSinceEpoch (); + auto ts = i2p::util::GetMillisecondsSinceEpoch (); // session for message 5 auto session = std::make_shared (m_Server); session->SetState (eSSU2SessionStatePeerTest); - m_PeerTests.emplace (nonce, std::make_pair (session, ts)); + m_PeerTests.emplace (nonce, std::make_pair (session, ts/1000)); session->m_SourceConnID = htobe64 (((uint64_t)nonce << 32) | nonce); session->m_DestConnID = ~session->m_SourceConnID; m_Server.AddSession (session); @@ -1925,7 +1925,7 @@ namespace transport size_t offset = 3; // points to signed data if (msg == 2 || msg == 4) offset += 32; // hash is presented for msg 2 and 4 only if (len < offset + 5) return; - auto ts = i2p::util::GetSecondsSinceEpoch (); + auto ts = i2p::util::GetMillisecondsSinceEpoch (); uint32_t nonce = bufbe32toh (buf + offset + 1); switch (msg) // msg { From 6c2aec8854cfa9c39358f29720baf242d1209b6a Mon Sep 17 00:00:00 2001 From: R4SAS Date: Wed, 12 Oct 2022 02:30:53 +0300 Subject: [PATCH 181/219] [gha] update docker workflow Signed-off-by: R4SAS --- .github/workflows/docker.yml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index e4b13645..899a7eec 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -29,19 +29,19 @@ jobs: uses: actions/checkout@v2 - name: Set up QEMU - uses: docker/setup-qemu-action@v1 + uses: docker/setup-qemu-action@v2 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v1 + uses: docker/setup-buildx-action@v2 - name: Login to DockerHub - uses: docker/login-action@v1 + uses: docker/login-action@v2 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Login to GitHub Container registry - uses: docker/login-action@v1 + uses: docker/login-action@v2 with: registry: ghcr.io username: ${{ github.actor }} @@ -71,19 +71,19 @@ jobs: uses: actions/checkout@v2 - name: Set up QEMU - uses: docker/setup-qemu-action@v1 + uses: docker/setup-qemu-action@v2 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v1 + uses: docker/setup-buildx-action@v2 - name: Login to DockerHub - uses: docker/login-action@v1 + uses: docker/login-action@v2 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Login to GitHub Container registry - uses: docker/login-action@v1 + uses: docker/login-action@v2 with: registry: ghcr.io username: ${{ github.actor }} From 63fd05c7d3b8b7fcea7afb5bfd9e1cdc31820478 Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 15 Oct 2022 21:37:00 -0400 Subject: [PATCH 182/219] SOCKS5 constants --- libi2pd/NTCP2.cpp | 10 +++++----- libi2pd/TransportSession.h | 7 +++++++ 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index 8a2d6c7c..76c40d27 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -1558,7 +1558,7 @@ namespace transport case eSocksProxy: { // TODO: support username/password auth etc - static const uint8_t buff[3] = {0x05, 0x01, 0x00}; + static const uint8_t buff[3] = {SOCKS5_VER, 0x01, 0x00}; boost::asio::async_write(conn->GetSocket(), boost::asio::buffer(buff, 3), boost::asio::transfer_all(), [] (const boost::system::error_code & ec, std::size_t transferred) { @@ -1672,21 +1672,21 @@ namespace transport size_t sz = 6; // header + port auto buff = std::make_shared >(256); auto readbuff = std::make_shared >(256); - (*buff)[0] = 0x05; - (*buff)[1] = 0x01; + (*buff)[0] = SOCKS5_VER; + (*buff)[1] = SOCKS5_CMD_CONNECT; (*buff)[2] = 0x00; auto& ep = conn->GetRemoteEndpoint (); if(ep.address ().is_v4 ()) { - (*buff)[3] = 0x01; + (*buff)[3] = SOCKS5_ATYP_IPV4; auto addrbytes = ep.address ().to_v4().to_bytes(); sz += 4; memcpy(buff->data () + 4, addrbytes.data(), 4); } else if (ep.address ().is_v6 ()) { - (*buff)[3] = 0x04; + (*buff)[3] = SOCKS5_ATYP_IPV6; auto addrbytes = ep.address ().to_v6().to_bytes(); sz += 16; memcpy(buff->data () + 4, addrbytes.data(), 16); diff --git a/libi2pd/TransportSession.h b/libi2pd/TransportSession.h index ecaef425..a939d540 100644 --- a/libi2pd/TransportSession.h +++ b/libi2pd/TransportSession.h @@ -124,6 +124,13 @@ namespace transport uint64_t m_LastActivityTimestamp; uint32_t m_CreationTime; // seconds since epoch }; + + // SOCKS5 proxy + const uint8_t SOCKS5_VER = 0x05; + const uint8_t SOCKS5_CMD_CONNECT = 0x01; + const uint8_t SOCKS5_CMD_UDP_ASSOCIATE = 0x03; + const uint8_t SOCKS5_ATYP_IPV4 = 0x01; + const uint8_t SOCKS5_ATYP_IPV6 = 0x04; } } From fe25260ee25c14a529c2b5811f8d0f31e612cabc Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 16 Oct 2022 21:23:28 -0400 Subject: [PATCH 183/219] send UDP request to proxy relay --- libi2pd/SSU2.cpp | 42 +++++++++++++++++++++++++++++++++++++- libi2pd/SSU2.h | 10 +++++++++ libi2pd/TransportSession.h | 2 ++ 3 files changed, 53 insertions(+), 1 deletion(-) diff --git a/libi2pd/SSU2.cpp b/libi2pd/SSU2.cpp index 0c71b14e..51ff9bd3 100644 --- a/libi2pd/SSU2.cpp +++ b/libi2pd/SSU2.cpp @@ -24,7 +24,7 @@ namespace transport m_AddressV4 (boost::asio::ip::address_v4()), m_AddressV6 (boost::asio::ip::address_v6()), m_TerminationTimer (GetService ()), m_ResendTimer (GetService ()), m_IntroducersUpdateTimer (GetService ()), m_IntroducersUpdateTimerV6 (GetService ()), - m_IsPublished (true), m_IsSyncClockFromPeers (true) + m_IsPublished (true), m_IsSyncClockFromPeers (true), m_IsThroughProxy (false) { } @@ -112,6 +112,12 @@ namespace transport m_SocketV4.close (); m_SocketV6.close (); + if (m_UDPAssociateSocket) + { + m_UDPAssociateSocket->close (); + m_UDPAssociateSocket.reset (nullptr); + } + StopIOService (); m_Sessions.clear (); @@ -1033,5 +1039,39 @@ namespace transport } } } + + void SSU2Server::SendThroughProxy (const uint8_t * header, size_t headerLen, const uint8_t * headerX, size_t headerXLen, + const uint8_t * payload, size_t payloadLen, const boost::asio::ip::udp::endpoint& to) + { + if (!m_ProxyRelayEndpoint) return; + size_t requestHeaderSize = 0; + memset (m_UDPRequestHeader, 0, 3); + if (to.address ().is_v6 ()) + { + m_UDPRequestHeader[3] = SOCKS5_ATYP_IPV6; + memcpy (m_UDPRequestHeader + 4, to.address ().to_v6().to_bytes().data(), 16); + requestHeaderSize = SOCKS5_UDP_IPV6_REQUEST_HEADER_SIZE; + } + else + { + m_UDPRequestHeader[3] = SOCKS5_ATYP_IPV4; + memcpy (m_UDPRequestHeader + 4, to.address ().to_v4().to_bytes().data(), 4); + requestHeaderSize = SOCKS5_UDP_IPV4_REQUEST_HEADER_SIZE; + } + htobe16buf (m_UDPRequestHeader + requestHeaderSize - 2, to.port ()); + + std::vector bufs; + bufs.push_back (boost::asio::buffer (m_UDPRequestHeader, requestHeaderSize)); + bufs.push_back (boost::asio::buffer (header, headerLen)); + if (headerX) bufs.push_back (boost::asio::buffer (headerX, headerXLen)); + bufs.push_back (boost::asio::buffer (payload, payloadLen)); + + boost::system::error_code ec; + m_SocketV4.send_to (bufs, *m_ProxyRelayEndpoint, 0, ec); // TODO: implement ipv6 proxy + if (!ec) + i2p::transport::transports.UpdateSentBytes (headerLen + payloadLen); + else + LogPrint (eLogError, "SSU2: Send exception: ", ec.message (), " to ", to); + } } } diff --git a/libi2pd/SSU2.h b/libi2pd/SSU2.h index 773eb669..ceee890e 100644 --- a/libi2pd/SSU2.h +++ b/libi2pd/SSU2.h @@ -118,6 +118,9 @@ namespace transport void HandleIntroducersUpdateTimer (const boost::system::error_code& ecode, bool v4); void ScheduleIntroducersUpdateTimerV6 (); + void SendThroughProxy (const uint8_t * header, size_t headerLen, const uint8_t * headerX, size_t headerXLen, + const uint8_t * payload, size_t payloadLen, const boost::asio::ip::udp::endpoint& to); + private: ReceiveService m_ReceiveService; @@ -137,6 +140,13 @@ namespace transport bool m_IsPublished; // if we maintain introducers bool m_IsSyncClockFromPeers; + // proxy + bool m_IsThroughProxy; + uint8_t m_UDPRequestHeader[SOCKS5_UDP_IPV6_REQUEST_HEADER_SIZE]; + std::unique_ptr m_ProxyEndpoint; + std::unique_ptr m_UDPAssociateSocket; + std::unique_ptr m_ProxyRelayEndpoint; + public: // for HTTP/I2PControl diff --git a/libi2pd/TransportSession.h b/libi2pd/TransportSession.h index a939d540..3ad146cb 100644 --- a/libi2pd/TransportSession.h +++ b/libi2pd/TransportSession.h @@ -131,6 +131,8 @@ namespace transport const uint8_t SOCKS5_CMD_UDP_ASSOCIATE = 0x03; const uint8_t SOCKS5_ATYP_IPV4 = 0x01; const uint8_t SOCKS5_ATYP_IPV6 = 0x04; + const size_t SOCKS5_UDP_IPV4_REQUEST_HEADER_SIZE = 10; + const size_t SOCKS5_UDP_IPV6_REQUEST_HEADER_SIZE = 22; } } From 39a86ce5c9197c335a5388c654af57553e513f73 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 16 Oct 2022 22:16:16 -0400 Subject: [PATCH 184/219] handle UDP packet from proxy relay --- libi2pd/SSU2.cpp | 39 +++++++++++++++++++++++++++++++++++++-- libi2pd/SSU2.h | 1 + 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/libi2pd/SSU2.cpp b/libi2pd/SSU2.cpp index 51ff9bd3..c33d916e 100644 --- a/libi2pd/SSU2.cpp +++ b/libi2pd/SSU2.cpp @@ -394,7 +394,7 @@ namespace transport } return nullptr; } - + void SSU2Server::ProcessNextPacket (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint) { if (len < 24) return; @@ -475,7 +475,7 @@ namespace transport } } } - + void SSU2Server::Send (const uint8_t * header, size_t headerLen, const uint8_t * payload, size_t payloadLen, const boost::asio::ip::udp::endpoint& to) { @@ -1073,5 +1073,40 @@ namespace transport else LogPrint (eLogError, "SSU2: Send exception: ", ec.message (), " to ", to); } + + void SSU2Server::ProcessNextPacketFromProxy (uint8_t * buf, size_t len) + { + size_t offset = 0; + boost::asio::ip::udp::endpoint ep; + switch (buf[3]) // ATYP + { + case SOCKS5_ATYP_IPV4: + { + offset = SOCKS5_UDP_IPV4_REQUEST_HEADER_SIZE; + if (offset > len) return; + boost::asio::ip::address_v4::bytes_type bytes; + memcpy (bytes.data (), buf + 4, 4); + uint16_t port = bufbe16toh (buf + 8); + ep = boost::asio::ip::udp::endpoint (boost::asio::ip::address_v4 (bytes), port); + break; + } + case SOCKS5_ATYP_IPV6: + { + offset = SOCKS5_UDP_IPV6_REQUEST_HEADER_SIZE; + if (offset > len) return; + boost::asio::ip::address_v6::bytes_type bytes; + memcpy (bytes.data (), buf + 4, 16); + uint16_t port = bufbe16toh (buf + 20); + ep = boost::asio::ip::udp::endpoint (boost::asio::ip::address_v6 (bytes), port); + break; + } + default: + { + LogPrint (eLogWarning, "SSU2: Unknown ATYP ", (int)buf[3], " from proxy relay"); + return; + } + } + ProcessNextPacket (buf + offset, len - offset, ep); + } } } diff --git a/libi2pd/SSU2.h b/libi2pd/SSU2.h index ceee890e..77254626 100644 --- a/libi2pd/SSU2.h +++ b/libi2pd/SSU2.h @@ -120,6 +120,7 @@ namespace transport void SendThroughProxy (const uint8_t * header, size_t headerLen, const uint8_t * headerX, size_t headerXLen, const uint8_t * payload, size_t payloadLen, const boost::asio::ip::udp::endpoint& to); + void ProcessNextPacketFromProxy (uint8_t * buf, size_t len); private: From 08fd32b3bf9edae8748ae1df9ff2c17af41b5721 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 17 Oct 2022 18:38:44 -0400 Subject: [PATCH 185/219] allow different ports from RelayReponse and HolePunch --- libi2pd/SSU2.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libi2pd/SSU2.cpp b/libi2pd/SSU2.cpp index c33d916e..d8d569da 100644 --- a/libi2pd/SSU2.cpp +++ b/libi2pd/SSU2.cpp @@ -428,12 +428,12 @@ namespace transport case eSSU2SessionStateIntroduced: if (m_LastSession->GetRemoteEndpoint ().address ().is_unspecified ()) m_LastSession->SetRemoteEndpoint (senderEndpoint); - if (m_LastSession->GetRemoteEndpoint () == senderEndpoint) + if (m_LastSession->GetRemoteEndpoint ().address () == senderEndpoint.address ()) // port might be different m_LastSession->ProcessHolePunch (buf, len); else { - LogPrint (eLogWarning, "SSU2: HolePunch endpoint ", senderEndpoint, - " doesn't match RelayResponse ", m_LastSession->GetRemoteEndpoint ()); + LogPrint (eLogWarning, "SSU2: HolePunch address ", senderEndpoint.address (), + " doesn't match RelayResponse ", m_LastSession->GetRemoteEndpoint ().address ()); m_LastSession->Done (); m_LastSession = nullptr; } From f3aada9e1ad58905c5c9c137e53e09f55221a9ab Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 18 Oct 2022 21:11:06 -0400 Subject: [PATCH 186/219] Proxy connection and UDP associate request --- libi2pd/SSU2.cpp | 142 +++++++++++++++++++++++++++++++++++++++++++++++ libi2pd/SSU2.h | 6 ++ 2 files changed, 148 insertions(+) diff --git a/libi2pd/SSU2.cpp b/libi2pd/SSU2.cpp index d8d569da..c323002c 100644 --- a/libi2pd/SSU2.cpp +++ b/libi2pd/SSU2.cpp @@ -1108,5 +1108,147 @@ namespace transport } ProcessNextPacket (buf + offset, len - offset, ep); } + + void SSU2Server::ConnectToProxy () + { + if (!m_ProxyEndpoint) return; + m_UDPAssociateSocket.reset (new boost::asio::ip::tcp::socket (m_ReceiveService.GetService ())); + m_UDPAssociateSocket->async_connect (*m_ProxyEndpoint, + [this] (const boost::system::error_code& ecode) + { + if (ecode) + { + LogPrint (eLogError, "SSU2: Can't connect to proxy ", *m_ProxyEndpoint, " ", ecode.message ()); + m_UDPAssociateSocket.reset (nullptr); + } + else + HandshakeWithProxy (); + }); + } + + void SSU2Server::HandshakeWithProxy () + { + if (!m_UDPAssociateSocket) return; + m_UDPRequestHeader[0] = SOCKS5_VER; + m_UDPRequestHeader[1] = 1; // 1 method + m_UDPRequestHeader[2] = 0; // no authentication + boost::asio::async_write (*m_UDPAssociateSocket, boost::asio::buffer (m_UDPRequestHeader, 3), boost::asio::transfer_all(), + [this] (const boost::system::error_code& ecode, std::size_t bytes_transferred) + { + (void) bytes_transferred; + if (ecode) + { + LogPrint(eLogError, "SSU2: Proxy write error ", ecode.message()); + m_UDPAssociateSocket.reset (nullptr); + } + else + ReadHandshakeWithProxyReply (); + }); + } + + void SSU2Server::ReadHandshakeWithProxyReply () + { + if (!m_UDPAssociateSocket) return; + boost::asio::async_read (*m_UDPAssociateSocket, boost::asio::buffer (m_UDPRequestHeader, 2), boost::asio::transfer_all(), + [this] (const boost::system::error_code& ecode, std::size_t bytes_transferred) + { + (void) bytes_transferred; + if (ecode) + { + LogPrint(eLogError, "SSU2: Proxy read error ", ecode.message()); + m_UDPAssociateSocket.reset (nullptr); + } + else + { + if (m_UDPRequestHeader[0] == SOCKS5_VER && !m_UDPRequestHeader[1]) + SendUDPAssociateRequest (); + else + { + LogPrint(eLogError, "SSU2: Invalid proxy reply"); + m_UDPAssociateSocket.reset (nullptr); + } + } + }); + } + + void SSU2Server::SendUDPAssociateRequest () + { + if (!m_UDPAssociateSocket) return; + m_UDPRequestHeader[0] = SOCKS5_VER; + m_UDPRequestHeader[1] = SOCKS5_CMD_UDP_ASSOCIATE; + m_UDPRequestHeader[2] = 0; // RSV + m_UDPRequestHeader[3] = SOCKS5_ATYP_IPV4; // TODO: implement ipv6 proxy + memset (m_UDPRequestHeader + 4, 0, 6); // address and port all zeros + boost::asio::async_write (*m_UDPAssociateSocket, boost::asio::buffer (m_UDPRequestHeader, SOCKS5_UDP_IPV4_REQUEST_HEADER_SIZE), boost::asio::transfer_all(), + [this] (const boost::system::error_code& ecode, std::size_t bytes_transferred) + { + (void) bytes_transferred; + if (ecode) + { + LogPrint(eLogError, "SSU2: Proxy write error ", ecode.message()); + m_UDPAssociateSocket.reset (nullptr); + } + else + ReadUDPAssociateReply (); + }); + } + + void SSU2Server::ReadUDPAssociateReply () + { + if (!m_UDPAssociateSocket) return; + boost::asio::async_read (*m_UDPAssociateSocket, boost::asio::buffer (m_UDPRequestHeader, SOCKS5_UDP_IPV4_REQUEST_HEADER_SIZE), boost::asio::transfer_all(), + [this] (const boost::system::error_code& ecode, std::size_t bytes_transferred) + { + (void) bytes_transferred; + if (ecode) + { + LogPrint(eLogError, "SSU2: Proxy read error ", ecode.message()); + m_UDPAssociateSocket.reset (nullptr); + } + else + { + if (m_UDPRequestHeader[0] == SOCKS5_VER && !m_UDPRequestHeader[1]) + { + if (m_UDPRequestHeader[3] == SOCKS5_ATYP_IPV4) + { + boost::asio::ip::address_v4::bytes_type bytes; + memcpy (bytes.data (), m_UDPRequestHeader + 4, 4); + uint16_t port = bufbe16toh (m_UDPRequestHeader + 8); + m_ProxyRelayEndpoint.reset (new boost::asio::ip::udp::endpoint (boost::asio::ip::address_v4 (bytes), port)); + m_SocketV4.open (boost::asio::ip::udp::v4 ()); + Receive (m_SocketV4); + ReadUDPAssociateSocket (); + } + else + { + LogPrint(eLogError, "SSU2: Proxy UDP associate unsupported ATYP ", (int)m_UDPRequestHeader[3]); + m_UDPAssociateSocket.reset (nullptr); + } + } + else + { + LogPrint(eLogError, "SSU2: Proxy UDP associate error ", (int)m_UDPRequestHeader[1]); + m_UDPAssociateSocket.reset (nullptr); + } + } + }); + } + + void SSU2Server::ReadUDPAssociateSocket () + { + if (!m_UDPAssociateSocket) return; + m_UDPAssociateSocket->async_read_some (boost::asio::buffer (m_UDPRequestHeader, 1), + [this] (const boost::system::error_code& ecode, std::size_t bytes_transferred) + { + (void) bytes_transferred; + if (ecode) + { + LogPrint(eLogError, "SSU2: Proxy UDP Associate socket error ", ecode.message()); + m_UDPAssociateSocket.reset (nullptr); + } + else + ReadUDPAssociateSocket (); + }); + } } } diff --git a/libi2pd/SSU2.h b/libi2pd/SSU2.h index 77254626..6eff7109 100644 --- a/libi2pd/SSU2.h +++ b/libi2pd/SSU2.h @@ -121,6 +121,12 @@ namespace transport void SendThroughProxy (const uint8_t * header, size_t headerLen, const uint8_t * headerX, size_t headerXLen, const uint8_t * payload, size_t payloadLen, const boost::asio::ip::udp::endpoint& to); void ProcessNextPacketFromProxy (uint8_t * buf, size_t len); + void ConnectToProxy (); + void HandshakeWithProxy (); + void ReadHandshakeWithProxyReply (); + void SendUDPAssociateRequest (); + void ReadUDPAssociateReply (); + void ReadUDPAssociateSocket (); // handle if closed by peer private: From 01ea1854bc5cc7535d550aa0fe571ba90cf70eea Mon Sep 17 00:00:00 2001 From: Jigen <111368404+jiigen@users.noreply.github.com> Date: Sun, 23 Oct 2022 18:33:52 +0000 Subject: [PATCH 187/219] Update HTTPProxy.cpp (#1794) Remove DoNotTrack flag from HTTP Request header. --- libi2pd_client/HTTPProxy.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libi2pd_client/HTTPProxy.cpp b/libi2pd_client/HTTPProxy.cpp index 499d12a9..1673de5a 100644 --- a/libi2pd_client/HTTPProxy.cpp +++ b/libi2pd_client/HTTPProxy.cpp @@ -249,6 +249,7 @@ namespace proxy { req.RemoveHeader("Via"); req.RemoveHeader("From"); req.RemoveHeader("Forwarded"); + req.RemoveHeader("DNT"); // Useless DoNotTrack flag req.RemoveHeader("Accept", "Accept-Encoding"); // Accept*, but Accept-Encoding /* drop proxy-disclosing headers */ req.RemoveHeader("X-Forwarded"); From 3d4d3ce80df5f18cfd5a6c8887a1ecd2937f89e4 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 24 Oct 2022 15:12:07 -0400 Subject: [PATCH 188/219] compressable crypto key and padding for routers and destination --- libi2pd/Identity.cpp | 29 +++++++++++++++++++++-------- libi2pd/Identity.h | 4 ++-- libi2pd_client/BOB.cpp | 2 +- libi2pd_client/ClientContext.cpp | 8 ++++---- libi2pd_client/SAM.cpp | 2 +- 5 files changed, 29 insertions(+), 16 deletions(-) diff --git a/libi2pd/Identity.cpp b/libi2pd/Identity.cpp index cff0c37d..f2dbb054 100644 --- a/libi2pd/Identity.cpp +++ b/libi2pd/Identity.cpp @@ -1,5 +1,5 @@ /* -* Copyright (c) 2013-2020, The PurpleI2P Project +* Copyright (c) 2013-2022, The PurpleI2P Project * * This file is part of Purple i2pd project and licensed under BSD3 * @@ -49,13 +49,22 @@ namespace data IdentityEx::IdentityEx(const uint8_t * publicKey, const uint8_t * signingKey, SigningKeyType type, CryptoKeyType cryptoType) { + uint8_t randomPaddingBlock[32]; + RAND_bytes (randomPaddingBlock, 32); if (cryptoType == CRYPTO_KEY_TYPE_ECIES_X25519_AEAD) { - memcpy (m_StandardIdentity.publicKey, publicKey, 32); - RAND_bytes (m_StandardIdentity.publicKey + 32, 224); + memcpy (m_StandardIdentity.publicKey, publicKey ? publicKey : randomPaddingBlock, 32); + for (int i = 0; i < 7; i++) // 224 bytes + memcpy (m_StandardIdentity.publicKey + 32*i, randomPaddingBlock, 32); } else - memcpy (m_StandardIdentity.publicKey, publicKey, 256); + { + if (publicKey) + memcpy (m_StandardIdentity.publicKey, publicKey, 256); + else + for (int i = 0; i < 8; i++) // 256 bytes + memcpy (m_StandardIdentity.publicKey + 32*i, randomPaddingBlock, 32); + } if (type != SIGNING_KEY_TYPE_DSA_SHA1) { size_t excessLen = 0; @@ -93,7 +102,8 @@ namespace data case SIGNING_KEY_TYPE_REDDSA_SHA512_ED25519: { size_t padding = 128 - i2p::crypto::EDDSA25519_PUBLIC_KEY_LENGTH; // 96 = 128 - 32 - RAND_bytes (m_StandardIdentity.signingKey, padding); + for (int i = 0; i < 3; i++) // 96 bytes + memcpy (m_StandardIdentity.signingKey + 32*i, randomPaddingBlock, 32); memcpy (m_StandardIdentity.signingKey + padding, signingKey, i2p::crypto::EDDSA25519_PUBLIC_KEY_LENGTH); break; } @@ -695,7 +705,7 @@ namespace data return nullptr; } - PrivateKeys PrivateKeys::CreateRandomKeys (SigningKeyType type, CryptoKeyType cryptoType) + PrivateKeys PrivateKeys::CreateRandomKeys (SigningKeyType type, CryptoKeyType cryptoType, bool isDestination) { if (type != SIGNING_KEY_TYPE_DSA_SHA1) { @@ -705,9 +715,12 @@ namespace data GenerateSigningKeyPair (type, keys.m_SigningPrivateKey, signingPublicKey); // encryption uint8_t publicKey[256]; - GenerateCryptoKeyPair (cryptoType, keys.m_PrivateKey, publicKey); + if (isDestination) + RAND_bytes (keys.m_PrivateKey, 256); + else + GenerateCryptoKeyPair (cryptoType, keys.m_PrivateKey, publicKey); // identity - keys.m_Public = std::make_shared (publicKey, signingPublicKey, type, cryptoType); + keys.m_Public = std::make_shared (isDestination ? nullptr : publicKey, signingPublicKey, type, cryptoType); keys.CreateSigner (); return keys; diff --git a/libi2pd/Identity.h b/libi2pd/Identity.h index 10f1d5ed..d5a2da21 100644 --- a/libi2pd/Identity.h +++ b/libi2pd/Identity.h @@ -1,5 +1,5 @@ /* -* Copyright (c) 2013-2021, The PurpleI2P Project +* Copyright (c) 2013-2022, The PurpleI2P Project * * This file is part of Purple i2pd project and licensed under BSD3 * @@ -171,7 +171,7 @@ namespace data std::shared_ptr CreateDecryptor (const uint8_t * key) const; static std::shared_ptr CreateDecryptor (CryptoKeyType cryptoType, const uint8_t * key); - static PrivateKeys CreateRandomKeys (SigningKeyType type = SIGNING_KEY_TYPE_DSA_SHA1, CryptoKeyType cryptoType = CRYPTO_KEY_TYPE_ELGAMAL); + static PrivateKeys CreateRandomKeys (SigningKeyType type = SIGNING_KEY_TYPE_DSA_SHA1, CryptoKeyType cryptoType = CRYPTO_KEY_TYPE_ELGAMAL, bool isDestination = false); static void GenerateSigningKeyPair (SigningKeyType type, uint8_t * priv, uint8_t * pub); static void GenerateCryptoKeyPair (CryptoKeyType type, uint8_t * priv, uint8_t * pub); // priv and pub are 256 bytes long static i2p::crypto::Signer * CreateSigner (SigningKeyType keyType, const uint8_t * priv); diff --git a/libi2pd_client/BOB.cpp b/libi2pd_client/BOB.cpp index f956186f..5f738380 100644 --- a/libi2pd_client/BOB.cpp +++ b/libi2pd_client/BOB.cpp @@ -547,7 +547,7 @@ namespace client } - m_Keys = i2p::data::PrivateKeys::CreateRandomKeys (signatureType, cryptoType); + m_Keys = i2p::data::PrivateKeys::CreateRandomKeys (signatureType, cryptoType, true); SendReplyOK (m_Keys.GetPublic ()->ToBase64 ().c_str ()); } diff --git a/libi2pd_client/ClientContext.cpp b/libi2pd_client/ClientContext.cpp index 33500705..3881f2e1 100644 --- a/libi2pd_client/ClientContext.cpp +++ b/libi2pd_client/ClientContext.cpp @@ -261,7 +261,7 @@ namespace client static const std::string transient("transient"); if (!filename.compare (0, transient.length (), transient)) // starts with transient { - keys = i2p::data::PrivateKeys::CreateRandomKeys (sigType, cryptoType); + keys = i2p::data::PrivateKeys::CreateRandomKeys (sigType, cryptoType, true); LogPrint (eLogInfo, "Clients: New transient keys address ", m_AddressBook.ToAddress(keys.GetPublic ()->GetIdentHash ()), " created"); return true; } @@ -288,7 +288,7 @@ namespace client else { LogPrint (eLogError, "Clients: Can't open file ", fullPath, " Creating new one with signature type ", sigType, " crypto type ", cryptoType); - keys = i2p::data::PrivateKeys::CreateRandomKeys (sigType, cryptoType); + keys = i2p::data::PrivateKeys::CreateRandomKeys (sigType, cryptoType, true); std::ofstream f (fullPath, std::ofstream::binary | std::ofstream::out); size_t len = keys.GetFullLen (); uint8_t * buf = new uint8_t[len]; @@ -328,7 +328,7 @@ namespace client i2p::data::SigningKeyType sigType, i2p::data::CryptoKeyType cryptoType, const std::map * params) { - i2p::data::PrivateKeys keys = i2p::data::PrivateKeys::CreateRandomKeys (sigType, cryptoType); + i2p::data::PrivateKeys keys = i2p::data::PrivateKeys::CreateRandomKeys (sigType, cryptoType, true); auto localDestination = std::make_shared (keys, isPublic, params); AddLocalDestination (localDestination); return localDestination; @@ -339,7 +339,7 @@ namespace client i2p::data::SigningKeyType sigType, i2p::data::CryptoKeyType cryptoType, const std::map * params) { - i2p::data::PrivateKeys keys = i2p::data::PrivateKeys::CreateRandomKeys (sigType, cryptoType); + i2p::data::PrivateKeys keys = i2p::data::PrivateKeys::CreateRandomKeys (sigType, cryptoType, true); auto localDestination = std::make_shared (service, keys, isPublic, params); AddLocalDestination (localDestination); return localDestination; diff --git a/libi2pd_client/SAM.cpp b/libi2pd_client/SAM.cpp index 77a48efc..8b991802 100644 --- a/libi2pd_client/SAM.cpp +++ b/libi2pd_client/SAM.cpp @@ -709,7 +709,7 @@ namespace client LogPrint (eLogWarning, "SAM: ", SAM_PARAM_CRYPTO_TYPE, "error: ", ex.what ()); } } - auto keys = i2p::data::PrivateKeys::CreateRandomKeys (signatureType, cryptoType); + auto keys = i2p::data::PrivateKeys::CreateRandomKeys (signatureType, cryptoType, true); #ifdef _MSC_VER size_t l = sprintf_s (m_Buffer, SAM_SOCKET_BUFFER_SIZE, SAM_DEST_REPLY, keys.GetPublic ()->ToBase64 ().c_str (), keys.ToBase64 ().c_str ()); From b2767304e9ae0940ad1108b46fd0c6b9f56d65dd Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 24 Oct 2022 18:07:04 -0400 Subject: [PATCH 189/219] correct padding offset --- libi2pd/Identity.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd/Identity.cpp b/libi2pd/Identity.cpp index f2dbb054..310e6081 100644 --- a/libi2pd/Identity.cpp +++ b/libi2pd/Identity.cpp @@ -55,7 +55,7 @@ namespace data { memcpy (m_StandardIdentity.publicKey, publicKey ? publicKey : randomPaddingBlock, 32); for (int i = 0; i < 7; i++) // 224 bytes - memcpy (m_StandardIdentity.publicKey + 32*i, randomPaddingBlock, 32); + memcpy (m_StandardIdentity.publicKey + 32*(i + 1), randomPaddingBlock, 32); } else { From c6e8873d57e4936b4771fabcc3c15faac869a234 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 24 Oct 2022 19:21:58 -0400 Subject: [PATCH 190/219] always compress SYN packet --- libi2pd/Streaming.cpp | 10 ++++------ libi2pd/Streaming.h | 6 +++--- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/libi2pd/Streaming.cpp b/libi2pd/Streaming.cpp index 72562675..f7737646 100644 --- a/libi2pd/Streaming.cpp +++ b/libi2pd/Streaming.cpp @@ -855,7 +855,7 @@ namespace stream for (const auto& it: packets) { auto msg = m_RoutingSession->WrapSingleMessage (m_LocalDestination.CreateDataMessage ( - it->GetBuffer (), it->GetLength (), m_Port, !m_RoutingSession->IsRatchets ())); + it->GetBuffer (), it->GetLength (), m_Port, !m_RoutingSession->IsRatchets (), it->IsSYN ())); msgs.push_back (i2p::tunnel::TunnelMessageBlock { i2p::tunnel::eDeliveryTypeTunnel, @@ -1085,8 +1085,6 @@ namespace stream m_Owner (owner), m_LocalPort (localPort), m_Gzip (gzip), m_PendingIncomingTimer (m_Owner->GetService ()) { - if (m_Gzip) - m_Deflator.reset (new i2p::data::GzipDeflator); } StreamingDestination::~StreamingDestination () @@ -1365,7 +1363,7 @@ namespace stream } std::shared_ptr StreamingDestination::CreateDataMessage ( - const uint8_t * payload, size_t len, uint16_t toPort, bool checksum) + const uint8_t * payload, size_t len, uint16_t toPort, bool checksum, bool gzip) { size_t size; auto msg = m_I2NPMsgsPool.AcquireShared (); @@ -1373,8 +1371,8 @@ namespace stream buf += 4; // reserve for lengthlength msg->len += 4; - if (m_Gzip && m_Deflator) - size = m_Deflator->Deflate (payload, len, buf, msg->maxLen - msg->len); + if (m_Gzip || gzip) + size = m_Deflator.Deflate (payload, len, buf, msg->maxLen - msg->len); else size = i2p::data::GzipNoCompression (payload, len, buf, msg->maxLen - msg->len); diff --git a/libi2pd/Streaming.h b/libi2pd/Streaming.h index 088c2e11..19f2f8f6 100644 --- a/libi2pd/Streaming.h +++ b/libi2pd/Streaming.h @@ -1,5 +1,5 @@ /* -* Copyright (c) 2013-2021, The PurpleI2P Project +* Copyright (c) 2013-2022, The PurpleI2P Project * * This file is part of Purple i2pd project and licensed under BSD3 * @@ -284,7 +284,7 @@ namespace stream uint16_t GetLocalPort () const { return m_LocalPort; }; void HandleDataMessagePayload (const uint8_t * buf, size_t len); - std::shared_ptr CreateDataMessage (const uint8_t * payload, size_t len, uint16_t toPort, bool checksum = true); + std::shared_ptr CreateDataMessage (const uint8_t * payload, size_t len, uint16_t toPort, bool checksum = true, bool gzip = false); Packet * NewPacket () { return m_PacketsPool.Acquire(); } void DeletePacket (Packet * p) { return m_PacketsPool.Release(p); } @@ -315,7 +315,7 @@ namespace stream public: i2p::data::GzipInflator m_Inflator; - std::unique_ptr m_Deflator; + i2p::data::GzipDeflator m_Deflator; // for HTTP only const decltype(m_Streams)& GetStreams () const { return m_Streams; }; From f9b0bb0383f13330eed01c9cccf63871e8f9901c Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 25 Oct 2022 15:30:12 -0400 Subject: [PATCH 191/219] I2PTunnel/UDPTunnel split --- libi2pd/Datagram.h | 3 +- libi2pd_client/ClientContext.h | 1 + libi2pd_client/I2PTunnel.cpp | 366 +------------------------------ libi2pd_client/I2PTunnel.h | 159 +------------- libi2pd_client/UDPTunnel.cpp | 384 +++++++++++++++++++++++++++++++++ libi2pd_client/UDPTunnel.h | 186 ++++++++++++++++ 6 files changed, 576 insertions(+), 523 deletions(-) create mode 100644 libi2pd_client/UDPTunnel.cpp create mode 100644 libi2pd_client/UDPTunnel.h diff --git a/libi2pd/Datagram.h b/libi2pd/Datagram.h index a55c8edf..8f3d5ceb 100644 --- a/libi2pd/Datagram.h +++ b/libi2pd/Datagram.h @@ -1,5 +1,5 @@ /* -* Copyright (c) 2013-2021, The PurpleI2P Project +* Copyright (c) 2013-2022, The PurpleI2P Project * * This file is part of Purple i2pd project and licensed under BSD3 * @@ -15,6 +15,7 @@ #include #include #include "Base.h" +#include "Gzip.h" #include "Identity.h" #include "LeaseSet.h" #include "I2NPProtocol.h" diff --git a/libi2pd_client/ClientContext.h b/libi2pd_client/ClientContext.h index ded8ea75..4e969a6b 100644 --- a/libi2pd_client/ClientContext.h +++ b/libi2pd_client/ClientContext.h @@ -18,6 +18,7 @@ #include "HTTPProxy.h" #include "SOCKS.h" #include "I2PTunnel.h" +#include "UDPTunnel.h" #include "SAM.h" #include "BOB.h" #include "I2CP.h" diff --git a/libi2pd_client/I2PTunnel.cpp b/libi2pd_client/I2PTunnel.cpp index 12fa08e2..5558cd8d 100644 --- a/libi2pd_client/I2PTunnel.cpp +++ b/libi2pd_client/I2PTunnel.cpp @@ -72,7 +72,7 @@ namespace client Receive (); } - static boost::asio::ip::address GetLoopbackAddressFor(const i2p::data::IdentHash & addr) + boost::asio::ip::address GetLoopbackAddressFor(const i2p::data::IdentHash & addr) { boost::asio::ip::address_v4::bytes_type bytes; const uint8_t * ident = addr; @@ -874,370 +874,6 @@ namespace client { return std::make_shared (this, stream, GetEndpoint (), m_WebircPass, GetSSLCtx ()); } - - void I2PUDPServerTunnel::HandleRecvFromI2P(const i2p::data::IdentityEx& from, uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len) - { - if (!m_LastSession || m_LastSession->Identity.GetLL()[0] != from.GetIdentHash ().GetLL()[0] || fromPort != m_LastSession->RemotePort) - { - std::lock_guard lock(m_SessionsMutex); - m_LastSession = ObtainUDPSession(from, toPort, fromPort); - } - m_LastSession->IPSocket.send_to(boost::asio::buffer(buf, len), m_RemoteEndpoint); - m_LastSession->LastActivity = i2p::util::GetMillisecondsSinceEpoch(); - } - - void I2PUDPServerTunnel::HandleRecvFromI2PRaw (uint16_t, uint16_t, const uint8_t * buf, size_t len) - { - if (m_LastSession) - { - m_LastSession->IPSocket.send_to(boost::asio::buffer(buf, len), m_RemoteEndpoint); - m_LastSession->LastActivity = i2p::util::GetMillisecondsSinceEpoch(); - } - } - - void I2PUDPServerTunnel::ExpireStale(const uint64_t delta) - { - std::lock_guard lock(m_SessionsMutex); - uint64_t now = i2p::util::GetMillisecondsSinceEpoch(); - auto itr = m_Sessions.begin(); - while(itr != m_Sessions.end()) { - if(now - (*itr)->LastActivity >= delta ) - itr = m_Sessions.erase(itr); - else - ++itr; - } - } - - void I2PUDPClientTunnel::ExpireStale(const uint64_t delta) - { - std::lock_guard lock(m_SessionsMutex); - uint64_t now = i2p::util::GetMillisecondsSinceEpoch(); - std::vector removePorts; - for (const auto & s : m_Sessions) { - if (now - s.second->second >= delta) - removePorts.push_back(s.first); - } - for(auto port : removePorts) { - m_Sessions.erase(port); - } - } - - UDPSessionPtr I2PUDPServerTunnel::ObtainUDPSession(const i2p::data::IdentityEx& from, uint16_t localPort, uint16_t remotePort) - { - auto ih = from.GetIdentHash(); - for (auto & s : m_Sessions ) - { - if (s->Identity.GetLL()[0] == ih.GetLL()[0] && remotePort == s->RemotePort) - { - /** found existing session */ - LogPrint(eLogDebug, "UDPServer: Found session ", s->IPSocket.local_endpoint(), " ", ih.ToBase32()); - return s; - } - } - boost::asio::ip::address addr; - /** create new udp session */ - if(m_IsUniqueLocal && m_LocalAddress.is_loopback()) - { - auto ident = from.GetIdentHash(); - addr = GetLoopbackAddressFor(ident); - } - else - addr = m_LocalAddress; - boost::asio::ip::udp::endpoint ep(addr, 0); - m_Sessions.push_back(std::make_shared(ep, m_LocalDest, m_RemoteEndpoint, &ih, localPort, remotePort)); - auto & back = m_Sessions.back(); - return back; - } - - UDPSession::UDPSession(boost::asio::ip::udp::endpoint localEndpoint, - const std::shared_ptr & localDestination, - boost::asio::ip::udp::endpoint endpoint, const i2p::data::IdentHash * to, - uint16_t ourPort, uint16_t theirPort) : - m_Destination(localDestination->GetDatagramDestination()), - IPSocket(localDestination->GetService(), localEndpoint), - SendEndpoint(endpoint), - LastActivity(i2p::util::GetMillisecondsSinceEpoch()), - LocalPort(ourPort), - RemotePort(theirPort) - { - IPSocket.set_option (boost::asio::socket_base::receive_buffer_size (I2P_UDP_MAX_MTU )); - memcpy(Identity, to->data(), 32); - Receive(); - } - - void UDPSession::Receive() - { - LogPrint(eLogDebug, "UDPSession: Receive"); - IPSocket.async_receive_from(boost::asio::buffer(m_Buffer, I2P_UDP_MAX_MTU), - FromEndpoint, std::bind(&UDPSession::HandleReceived, this, std::placeholders::_1, std::placeholders::_2)); - } - - void UDPSession::HandleReceived(const boost::system::error_code & ecode, std::size_t len) - { - if(!ecode) - { - LogPrint(eLogDebug, "UDPSession: Forward ", len, "B from ", FromEndpoint); - auto ts = i2p::util::GetMillisecondsSinceEpoch(); - auto session = m_Destination->GetSession (Identity); - if (ts > LastActivity + I2P_UDP_REPLIABLE_DATAGRAM_INTERVAL) - m_Destination->SendDatagram(session, m_Buffer, len, LocalPort, RemotePort); - else - m_Destination->SendRawDatagram(session, m_Buffer, len, LocalPort, RemotePort); - size_t numPackets = 0; - while (numPackets < i2p::datagram::DATAGRAM_SEND_QUEUE_MAX_SIZE) - { - boost::system::error_code ec; - size_t moreBytes = IPSocket.available(ec); - if (ec || !moreBytes) break; - len = IPSocket.receive_from (boost::asio::buffer (m_Buffer, I2P_UDP_MAX_MTU), FromEndpoint, 0, ec); - m_Destination->SendRawDatagram (session, m_Buffer, len, LocalPort, RemotePort); - numPackets++; - } - if (numPackets > 0) - LogPrint(eLogDebug, "UDPSession: Forward more ", numPackets, "packets B from ", FromEndpoint); - m_Destination->FlushSendQueue (session); - LastActivity = ts; - Receive(); - } - else - LogPrint(eLogError, "UDPSession: ", ecode.message()); - } - - I2PUDPServerTunnel::I2PUDPServerTunnel (const std::string & name, std::shared_ptr localDestination, - boost::asio::ip::address localAddress, boost::asio::ip::udp::endpoint forwardTo, uint16_t port, bool gzip) : - m_IsUniqueLocal (true), m_Name (name), m_LocalAddress (localAddress), - m_RemoteEndpoint (forwardTo), m_LocalDest (localDestination), m_Gzip (gzip) - { - } - - I2PUDPServerTunnel::~I2PUDPServerTunnel () - { - Stop (); - } - - void I2PUDPServerTunnel::Start () - { - m_LocalDest->Start (); - - auto dgram = m_LocalDest->CreateDatagramDestination (m_Gzip); - dgram->SetReceiver (std::bind (&I2PUDPServerTunnel::HandleRecvFromI2P, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5)); - dgram->SetRawReceiver (std::bind (&I2PUDPServerTunnel::HandleRecvFromI2PRaw, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4)); - } - - void I2PUDPServerTunnel::Stop () - { - auto dgram = m_LocalDest->GetDatagramDestination (); - if (dgram) dgram->ResetReceiver (); - } - - std::vector > I2PUDPServerTunnel::GetSessions () - { - std::vector > sessions; - std::lock_guard lock (m_SessionsMutex); - - for (UDPSessionPtr s: m_Sessions) - { - if (!s->m_Destination) continue; - auto info = s->m_Destination->GetInfoForRemote (s->Identity); - if (!info) continue; - - auto sinfo = std::make_shared (); - sinfo->Name = m_Name; - sinfo->LocalIdent = std::make_shared (m_LocalDest->GetIdentHash ().data ()); - sinfo->RemoteIdent = std::make_shared (s->Identity.data ()); - sinfo->CurrentIBGW = info->IBGW; - sinfo->CurrentOBEP = info->OBEP; - sessions.push_back (sinfo); - } - return sessions; - } - - I2PUDPClientTunnel::I2PUDPClientTunnel (const std::string & name, const std::string &remoteDest, - boost::asio::ip::udp::endpoint localEndpoint, - std::shared_ptr localDestination, - uint16_t remotePort, bool gzip) : - m_Name (name), m_RemoteDest (remoteDest), m_LocalDest (localDestination), m_LocalEndpoint (localEndpoint), - m_RemoteIdent (nullptr), m_ResolveThread (nullptr), m_LocalSocket (nullptr), RemotePort (remotePort), - m_LastPort (0), m_cancel_resolve (false), m_Gzip (gzip) - { - } - - I2PUDPClientTunnel::~I2PUDPClientTunnel () - { - Stop (); - } - - void I2PUDPClientTunnel::Start () - { - // Reset flag in case of tunnel reload - if (m_cancel_resolve) m_cancel_resolve = false; - - m_LocalSocket.reset (new boost::asio::ip::udp::socket (m_LocalDest->GetService (), m_LocalEndpoint)); - m_LocalSocket->set_option (boost::asio::socket_base::receive_buffer_size (I2P_UDP_MAX_MTU)); - m_LocalSocket->set_option (boost::asio::socket_base::reuse_address (true)); - - auto dgram = m_LocalDest->CreateDatagramDestination (m_Gzip); - dgram->SetReceiver (std::bind (&I2PUDPClientTunnel::HandleRecvFromI2P, this, - std::placeholders::_1, std::placeholders::_2, - std::placeholders::_3, std::placeholders::_4, - std::placeholders::_5)); - dgram->SetRawReceiver (std::bind (&I2PUDPClientTunnel::HandleRecvFromI2PRaw, this, - std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4)); - - m_LocalDest->Start (); - if (m_ResolveThread == nullptr) - m_ResolveThread = new std::thread (std::bind (&I2PUDPClientTunnel::TryResolving, this)); - RecvFromLocal (); - } - - void I2PUDPClientTunnel::Stop () - { - auto dgram = m_LocalDest->GetDatagramDestination (); - if (dgram) dgram->ResetReceiver (); - m_cancel_resolve = true; - - m_Sessions.clear(); - - if(m_LocalSocket && m_LocalSocket->is_open ()) - m_LocalSocket->close (); - - if(m_ResolveThread) - { - m_ResolveThread->join (); - delete m_ResolveThread; - m_ResolveThread = nullptr; - } - if (m_RemoteIdent) - { - delete m_RemoteIdent; - m_RemoteIdent = nullptr; - } - } - - void I2PUDPClientTunnel::RecvFromLocal () - { - m_LocalSocket->async_receive_from (boost::asio::buffer (m_RecvBuff, I2P_UDP_MAX_MTU), - m_RecvEndpoint, std::bind (&I2PUDPClientTunnel::HandleRecvFromLocal, this, std::placeholders::_1, std::placeholders::_2)); - } - - void I2PUDPClientTunnel::HandleRecvFromLocal (const boost::system::error_code & ec, std::size_t transferred) - { - if (m_cancel_resolve) { - LogPrint (eLogDebug, "UDP Client: Ignoring incomming data: stopping"); - return; - } - if (ec) { - LogPrint (eLogError, "UDP Client: Reading from socket error: ", ec.message (), ". Restarting listener..."); - RecvFromLocal (); // Restart listener and continue work - return; - } - if (!m_RemoteIdent) { - LogPrint (eLogWarning, "UDP Client: Remote endpoint not resolved yet"); - RecvFromLocal (); - return; // drop, remote not resolved - } - auto remotePort = m_RecvEndpoint.port (); - if (!m_LastPort || m_LastPort != remotePort) - { - auto itr = m_Sessions.find (remotePort); - if (itr != m_Sessions.end ()) - m_LastSession = itr->second; - else - { - m_LastSession = std::make_shared (boost::asio::ip::udp::endpoint (m_RecvEndpoint), 0); - m_Sessions.emplace (remotePort, m_LastSession); - } - m_LastPort = remotePort; - } - // send off to remote i2p destination - auto ts = i2p::util::GetMillisecondsSinceEpoch (); - LogPrint (eLogDebug, "UDP Client: Send ", transferred, " to ", m_RemoteIdent->ToBase32 (), ":", RemotePort); - auto session = m_LocalDest->GetDatagramDestination ()->GetSession (*m_RemoteIdent); - if (ts > m_LastSession->second + I2P_UDP_REPLIABLE_DATAGRAM_INTERVAL) - m_LocalDest->GetDatagramDestination ()->SendDatagram (session, m_RecvBuff, transferred, remotePort, RemotePort); - else - m_LocalDest->GetDatagramDestination ()->SendRawDatagram (session, m_RecvBuff, transferred, remotePort, RemotePort); - size_t numPackets = 0; - while (numPackets < i2p::datagram::DATAGRAM_SEND_QUEUE_MAX_SIZE) - { - boost::system::error_code ec; - size_t moreBytes = m_LocalSocket->available (ec); - if (ec || !moreBytes) break; - transferred = m_LocalSocket->receive_from (boost::asio::buffer (m_RecvBuff, I2P_UDP_MAX_MTU), m_RecvEndpoint, 0, ec); - remotePort = m_RecvEndpoint.port (); - // TODO: check remotePort - m_LocalDest->GetDatagramDestination ()->SendRawDatagram (session, m_RecvBuff, transferred, remotePort, RemotePort); - numPackets++; - } - if (numPackets) - LogPrint (eLogDebug, "UDP Client: Sent ", numPackets, " more packets to ", m_RemoteIdent->ToBase32 ()); - m_LocalDest->GetDatagramDestination ()->FlushSendQueue (session); - - // mark convo as active - if (m_LastSession) - m_LastSession->second = ts; - RecvFromLocal (); - } - - std::vector > I2PUDPClientTunnel::GetSessions () - { - // TODO: implement - std::vector > infos; - return infos; - } - - void I2PUDPClientTunnel::TryResolving () - { - i2p::util::SetThreadName ("UDP Resolver"); - LogPrint (eLogInfo, "UDP Tunnel: Trying to resolve ", m_RemoteDest); - - std::shared_ptr addr; - while (!(addr = context.GetAddressBook().GetAddress(m_RemoteDest)) && !m_cancel_resolve) - { - LogPrint (eLogWarning, "UDP Tunnel: Failed to lookup ", m_RemoteDest); - std::this_thread::sleep_for (std::chrono::seconds (1)); - } - if (m_cancel_resolve) - { - LogPrint(eLogError, "UDP Tunnel: Lookup of ", m_RemoteDest, " was cancelled"); - return; - } - if (!addr || !addr->IsIdentHash ()) - { - LogPrint (eLogError, "UDP Tunnel: ", m_RemoteDest, " not found"); - return; - } - m_RemoteIdent = new i2p::data::IdentHash; - *m_RemoteIdent = addr->identHash; - LogPrint(eLogInfo, "UDP Tunnel: Resolved ", m_RemoteDest, " to ", m_RemoteIdent->ToBase32 ()); - } - - void I2PUDPClientTunnel::HandleRecvFromI2P (const i2p::data::IdentityEx& from, uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len) - { - if (m_RemoteIdent && from.GetIdentHash() == *m_RemoteIdent) - HandleRecvFromI2PRaw (fromPort, toPort, buf, len); - else - LogPrint(eLogWarning, "UDP Client: Unwarranted traffic from ", from.GetIdentHash().ToBase32 ()); - } - - void I2PUDPClientTunnel::HandleRecvFromI2PRaw (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len) - { - auto itr = m_Sessions.find (toPort); - // found convo ? - if (itr != m_Sessions.end ()) - { - // found convo - if (len > 0) - { - LogPrint (eLogDebug, "UDP Client: Got ", len, "B from ", m_RemoteIdent ? m_RemoteIdent->ToBase32 () : ""); - m_LocalSocket->send_to (boost::asio::buffer (buf, len), itr->second->first); - // mark convo as active - itr->second->second = i2p::util::GetMillisecondsSinceEpoch (); - } - } - else - LogPrint (eLogWarning, "UDP Client: Not tracking udp session using port ", (int) toPort); - } } } diff --git a/libi2pd_client/I2PTunnel.h b/libi2pd_client/I2PTunnel.h index 0da11a46..4c7b2002 100644 --- a/libi2pd_client/I2PTunnel.h +++ b/libi2pd_client/I2PTunnel.h @@ -19,7 +19,6 @@ #include #include "Identity.h" #include "Destination.h" -#include "Datagram.h" #include "Streaming.h" #include "I2PService.h" #include "AddressBook.h" @@ -180,162 +179,6 @@ namespace client std::unique_ptr m_KeepAliveTimer; }; - - /** 2 minute timeout for udp sessions */ - const uint64_t I2P_UDP_SESSION_TIMEOUT = 1000 * 60 * 2; - const uint64_t I2P_UDP_REPLIABLE_DATAGRAM_INTERVAL = 100; // in milliseconds - - /** max size for i2p udp */ - const size_t I2P_UDP_MAX_MTU = 64*1024; - - struct UDPSession - { - i2p::datagram::DatagramDestination * m_Destination; - boost::asio::ip::udp::socket IPSocket; - i2p::data::IdentHash Identity; - boost::asio::ip::udp::endpoint FromEndpoint; - boost::asio::ip::udp::endpoint SendEndpoint; - uint64_t LastActivity; - - uint16_t LocalPort; - uint16_t RemotePort; - - uint8_t m_Buffer[I2P_UDP_MAX_MTU]; - - UDPSession(boost::asio::ip::udp::endpoint localEndpoint, - const std::shared_ptr & localDestination, - boost::asio::ip::udp::endpoint remote, const i2p::data::IdentHash * ident, - uint16_t ourPort, uint16_t theirPort); - void HandleReceived(const boost::system::error_code & ecode, std::size_t len); - void Receive(); - }; - - - /** read only info about a datagram session */ - struct DatagramSessionInfo - { - /** the name of this forward */ - std::string Name; - /** ident hash of local destination */ - std::shared_ptr LocalIdent; - /** ident hash of remote destination */ - std::shared_ptr RemoteIdent; - /** ident hash of IBGW in use currently in this session or nullptr if none is set */ - std::shared_ptr CurrentIBGW; - /** ident hash of OBEP in use for this session or nullptr if none is set */ - std::shared_ptr CurrentOBEP; - /** i2p router's udp endpoint */ - boost::asio::ip::udp::endpoint LocalEndpoint; - /** client's udp endpoint */ - boost::asio::ip::udp::endpoint RemoteEndpoint; - /** how long has this converstation been idle in ms */ - uint64_t idle; - }; - - typedef std::shared_ptr UDPSessionPtr; - - /** server side udp tunnel, many i2p inbound to 1 ip outbound */ - class I2PUDPServerTunnel - { - public: - - I2PUDPServerTunnel (const std::string & name, - std::shared_ptr localDestination, - boost::asio::ip::address localAddress, - boost::asio::ip::udp::endpoint forwardTo, uint16_t port, bool gzip); - ~I2PUDPServerTunnel (); - - /** expire stale udp conversations */ - void ExpireStale (const uint64_t delta=I2P_UDP_SESSION_TIMEOUT); - void Start (); - void Stop (); - const char * GetName () const { return m_Name.c_str(); } - std::vector > GetSessions (); - std::shared_ptr GetLocalDestination () const { return m_LocalDest; } - - void SetUniqueLocal (bool isUniqueLocal = true) { m_IsUniqueLocal = isUniqueLocal; } - - private: - - void HandleRecvFromI2P (const i2p::data::IdentityEx& from, uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len); - void HandleRecvFromI2PRaw (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len); - UDPSessionPtr ObtainUDPSession (const i2p::data::IdentityEx& from, uint16_t localPort, uint16_t remotePort); - - private: - - bool m_IsUniqueLocal; - const std::string m_Name; - boost::asio::ip::address m_LocalAddress; - boost::asio::ip::udp::endpoint m_RemoteEndpoint; - std::mutex m_SessionsMutex; - std::vector m_Sessions; - std::shared_ptr m_LocalDest; - UDPSessionPtr m_LastSession; - bool m_Gzip; - - public: - - bool isUpdated; // transient, used during reload only - }; - - class I2PUDPClientTunnel - { - public: - - I2PUDPClientTunnel (const std::string & name, const std::string &remoteDest, - boost::asio::ip::udp::endpoint localEndpoint, std::shared_ptr localDestination, - uint16_t remotePort, bool gzip); - ~I2PUDPClientTunnel (); - - void Start (); - void Stop (); - const char * GetName () const { return m_Name.c_str(); } - std::vector > GetSessions (); - - bool IsLocalDestination (const i2p::data::IdentHash & destination) const { return destination == m_LocalDest->GetIdentHash(); } - - std::shared_ptr GetLocalDestination () const { return m_LocalDest; } - inline void SetLocalDestination (std::shared_ptr dest) - { - if (m_LocalDest) m_LocalDest->Release (); - if (dest) dest->Acquire (); - m_LocalDest = dest; - } - - void ExpireStale (const uint64_t delta=I2P_UDP_SESSION_TIMEOUT); - - private: - - typedef std::pair UDPConvo; - void RecvFromLocal (); - void HandleRecvFromLocal (const boost::system::error_code & e, std::size_t transferred); - void HandleRecvFromI2P (const i2p::data::IdentityEx& from, uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len); - void HandleRecvFromI2PRaw (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len); - void TryResolving (); - - private: - - const std::string m_Name; - std::mutex m_SessionsMutex; - std::unordered_map > m_Sessions; // maps i2p port -> local udp convo - const std::string m_RemoteDest; - std::shared_ptr m_LocalDest; - const boost::asio::ip::udp::endpoint m_LocalEndpoint; - i2p::data::IdentHash * m_RemoteIdent; - std::thread * m_ResolveThread; - std::unique_ptr m_LocalSocket; - boost::asio::ip::udp::endpoint m_RecvEndpoint; - uint8_t m_RecvBuff[I2P_UDP_MAX_MTU]; - uint16_t RemotePort, m_LastPort; - bool m_cancel_resolve; - bool m_Gzip; - std::shared_ptr m_LastSession; - - public: - - bool isUpdated; // transient, used during reload only - }; - class I2PServerTunnel: public I2PService { public: @@ -418,6 +261,8 @@ namespace client std::string m_WebircPass; }; + + boost::asio::ip::address GetLoopbackAddressFor(const i2p::data::IdentHash & addr); } } diff --git a/libi2pd_client/UDPTunnel.cpp b/libi2pd_client/UDPTunnel.cpp new file mode 100644 index 00000000..a2c9061c --- /dev/null +++ b/libi2pd_client/UDPTunnel.cpp @@ -0,0 +1,384 @@ +/* +* Copyright (c) 2013-2022, The PurpleI2P Project +* +* This file is part of Purple i2pd project and licensed under BSD3 +* +* See full license text in LICENSE file at top of project tree +*/ + +#include "Log.h" +#include "util.h" +#include "ClientContext.h" +#include "I2PTunnel.h" // for GetLoopbackAddressFor +#include "UDPTunnel.h" + +namespace i2p +{ +namespace client +{ + void I2PUDPServerTunnel::HandleRecvFromI2P(const i2p::data::IdentityEx& from, uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len) + { + if (!m_LastSession || m_LastSession->Identity.GetLL()[0] != from.GetIdentHash ().GetLL()[0] || fromPort != m_LastSession->RemotePort) + { + std::lock_guard lock(m_SessionsMutex); + m_LastSession = ObtainUDPSession(from, toPort, fromPort); + } + m_LastSession->IPSocket.send_to(boost::asio::buffer(buf, len), m_RemoteEndpoint); + m_LastSession->LastActivity = i2p::util::GetMillisecondsSinceEpoch(); + } + + void I2PUDPServerTunnel::HandleRecvFromI2PRaw (uint16_t, uint16_t, const uint8_t * buf, size_t len) + { + if (m_LastSession) + { + m_LastSession->IPSocket.send_to(boost::asio::buffer(buf, len), m_RemoteEndpoint); + m_LastSession->LastActivity = i2p::util::GetMillisecondsSinceEpoch(); + } + } + + void I2PUDPServerTunnel::ExpireStale(const uint64_t delta) + { + std::lock_guard lock(m_SessionsMutex); + uint64_t now = i2p::util::GetMillisecondsSinceEpoch(); + auto itr = m_Sessions.begin(); + while(itr != m_Sessions.end()) { + if(now - (*itr)->LastActivity >= delta ) + itr = m_Sessions.erase(itr); + else + ++itr; + } + } + + void I2PUDPClientTunnel::ExpireStale(const uint64_t delta) + { + std::lock_guard lock(m_SessionsMutex); + uint64_t now = i2p::util::GetMillisecondsSinceEpoch(); + std::vector removePorts; + for (const auto & s : m_Sessions) { + if (now - s.second->second >= delta) + removePorts.push_back(s.first); + } + for(auto port : removePorts) { + m_Sessions.erase(port); + } + } + + UDPSessionPtr I2PUDPServerTunnel::ObtainUDPSession(const i2p::data::IdentityEx& from, uint16_t localPort, uint16_t remotePort) + { + auto ih = from.GetIdentHash(); + for (auto & s : m_Sessions ) + { + if (s->Identity.GetLL()[0] == ih.GetLL()[0] && remotePort == s->RemotePort) + { + /** found existing session */ + LogPrint(eLogDebug, "UDPServer: Found session ", s->IPSocket.local_endpoint(), " ", ih.ToBase32()); + return s; + } + } + boost::asio::ip::address addr; + /** create new udp session */ + if(m_IsUniqueLocal && m_LocalAddress.is_loopback()) + { + auto ident = from.GetIdentHash(); + addr = GetLoopbackAddressFor(ident); + } + else + addr = m_LocalAddress; + boost::asio::ip::udp::endpoint ep(addr, 0); + m_Sessions.push_back(std::make_shared(ep, m_LocalDest, m_RemoteEndpoint, &ih, localPort, remotePort)); + auto & back = m_Sessions.back(); + return back; + } + + UDPSession::UDPSession(boost::asio::ip::udp::endpoint localEndpoint, + const std::shared_ptr & localDestination, + boost::asio::ip::udp::endpoint endpoint, const i2p::data::IdentHash * to, + uint16_t ourPort, uint16_t theirPort) : + m_Destination(localDestination->GetDatagramDestination()), + IPSocket(localDestination->GetService(), localEndpoint), + SendEndpoint(endpoint), + LastActivity(i2p::util::GetMillisecondsSinceEpoch()), + LocalPort(ourPort), + RemotePort(theirPort) + { + IPSocket.set_option (boost::asio::socket_base::receive_buffer_size (I2P_UDP_MAX_MTU )); + memcpy(Identity, to->data(), 32); + Receive(); + } + + void UDPSession::Receive() + { + LogPrint(eLogDebug, "UDPSession: Receive"); + IPSocket.async_receive_from(boost::asio::buffer(m_Buffer, I2P_UDP_MAX_MTU), + FromEndpoint, std::bind(&UDPSession::HandleReceived, this, std::placeholders::_1, std::placeholders::_2)); + } + + void UDPSession::HandleReceived(const boost::system::error_code & ecode, std::size_t len) + { + if(!ecode) + { + LogPrint(eLogDebug, "UDPSession: Forward ", len, "B from ", FromEndpoint); + auto ts = i2p::util::GetMillisecondsSinceEpoch(); + auto session = m_Destination->GetSession (Identity); + if (ts > LastActivity + I2P_UDP_REPLIABLE_DATAGRAM_INTERVAL) + m_Destination->SendDatagram(session, m_Buffer, len, LocalPort, RemotePort); + else + m_Destination->SendRawDatagram(session, m_Buffer, len, LocalPort, RemotePort); + size_t numPackets = 0; + while (numPackets < i2p::datagram::DATAGRAM_SEND_QUEUE_MAX_SIZE) + { + boost::system::error_code ec; + size_t moreBytes = IPSocket.available(ec); + if (ec || !moreBytes) break; + len = IPSocket.receive_from (boost::asio::buffer (m_Buffer, I2P_UDP_MAX_MTU), FromEndpoint, 0, ec); + m_Destination->SendRawDatagram (session, m_Buffer, len, LocalPort, RemotePort); + numPackets++; + } + if (numPackets > 0) + LogPrint(eLogDebug, "UDPSession: Forward more ", numPackets, "packets B from ", FromEndpoint); + m_Destination->FlushSendQueue (session); + LastActivity = ts; + Receive(); + } + else + LogPrint(eLogError, "UDPSession: ", ecode.message()); + } + + I2PUDPServerTunnel::I2PUDPServerTunnel (const std::string & name, std::shared_ptr localDestination, + boost::asio::ip::address localAddress, boost::asio::ip::udp::endpoint forwardTo, uint16_t port, bool gzip) : + m_IsUniqueLocal (true), m_Name (name), m_LocalAddress (localAddress), + m_RemoteEndpoint (forwardTo), m_LocalDest (localDestination), m_Gzip (gzip) + { + } + + I2PUDPServerTunnel::~I2PUDPServerTunnel () + { + Stop (); + } + + void I2PUDPServerTunnel::Start () + { + m_LocalDest->Start (); + + auto dgram = m_LocalDest->CreateDatagramDestination (m_Gzip); + dgram->SetReceiver (std::bind (&I2PUDPServerTunnel::HandleRecvFromI2P, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5)); + dgram->SetRawReceiver (std::bind (&I2PUDPServerTunnel::HandleRecvFromI2PRaw, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4)); + } + + void I2PUDPServerTunnel::Stop () + { + auto dgram = m_LocalDest->GetDatagramDestination (); + if (dgram) dgram->ResetReceiver (); + } + + std::vector > I2PUDPServerTunnel::GetSessions () + { + std::vector > sessions; + std::lock_guard lock (m_SessionsMutex); + + for (UDPSessionPtr s: m_Sessions) + { + if (!s->m_Destination) continue; + auto info = s->m_Destination->GetInfoForRemote (s->Identity); + if (!info) continue; + + auto sinfo = std::make_shared (); + sinfo->Name = m_Name; + sinfo->LocalIdent = std::make_shared (m_LocalDest->GetIdentHash ().data ()); + sinfo->RemoteIdent = std::make_shared (s->Identity.data ()); + sinfo->CurrentIBGW = info->IBGW; + sinfo->CurrentOBEP = info->OBEP; + sessions.push_back (sinfo); + } + return sessions; + } + + I2PUDPClientTunnel::I2PUDPClientTunnel (const std::string & name, const std::string &remoteDest, + boost::asio::ip::udp::endpoint localEndpoint, + std::shared_ptr localDestination, + uint16_t remotePort, bool gzip) : + m_Name (name), m_RemoteDest (remoteDest), m_LocalDest (localDestination), m_LocalEndpoint (localEndpoint), + m_RemoteIdent (nullptr), m_ResolveThread (nullptr), m_LocalSocket (nullptr), RemotePort (remotePort), + m_LastPort (0), m_cancel_resolve (false), m_Gzip (gzip) + { + } + + I2PUDPClientTunnel::~I2PUDPClientTunnel () + { + Stop (); + } + + void I2PUDPClientTunnel::Start () + { + // Reset flag in case of tunnel reload + if (m_cancel_resolve) m_cancel_resolve = false; + + m_LocalSocket.reset (new boost::asio::ip::udp::socket (m_LocalDest->GetService (), m_LocalEndpoint)); + m_LocalSocket->set_option (boost::asio::socket_base::receive_buffer_size (I2P_UDP_MAX_MTU)); + m_LocalSocket->set_option (boost::asio::socket_base::reuse_address (true)); + + auto dgram = m_LocalDest->CreateDatagramDestination (m_Gzip); + dgram->SetReceiver (std::bind (&I2PUDPClientTunnel::HandleRecvFromI2P, this, + std::placeholders::_1, std::placeholders::_2, + std::placeholders::_3, std::placeholders::_4, + std::placeholders::_5)); + dgram->SetRawReceiver (std::bind (&I2PUDPClientTunnel::HandleRecvFromI2PRaw, this, + std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4)); + + m_LocalDest->Start (); + if (m_ResolveThread == nullptr) + m_ResolveThread = new std::thread (std::bind (&I2PUDPClientTunnel::TryResolving, this)); + RecvFromLocal (); + } + + void I2PUDPClientTunnel::Stop () + { + auto dgram = m_LocalDest->GetDatagramDestination (); + if (dgram) dgram->ResetReceiver (); + m_cancel_resolve = true; + + m_Sessions.clear(); + + if(m_LocalSocket && m_LocalSocket->is_open ()) + m_LocalSocket->close (); + + if(m_ResolveThread) + { + m_ResolveThread->join (); + delete m_ResolveThread; + m_ResolveThread = nullptr; + } + if (m_RemoteIdent) + { + delete m_RemoteIdent; + m_RemoteIdent = nullptr; + } + } + + void I2PUDPClientTunnel::RecvFromLocal () + { + m_LocalSocket->async_receive_from (boost::asio::buffer (m_RecvBuff, I2P_UDP_MAX_MTU), + m_RecvEndpoint, std::bind (&I2PUDPClientTunnel::HandleRecvFromLocal, this, std::placeholders::_1, std::placeholders::_2)); + } + + void I2PUDPClientTunnel::HandleRecvFromLocal (const boost::system::error_code & ec, std::size_t transferred) + { + if (m_cancel_resolve) { + LogPrint (eLogDebug, "UDP Client: Ignoring incomming data: stopping"); + return; + } + if (ec) { + LogPrint (eLogError, "UDP Client: Reading from socket error: ", ec.message (), ". Restarting listener..."); + RecvFromLocal (); // Restart listener and continue work + return; + } + if (!m_RemoteIdent) { + LogPrint (eLogWarning, "UDP Client: Remote endpoint not resolved yet"); + RecvFromLocal (); + return; // drop, remote not resolved + } + auto remotePort = m_RecvEndpoint.port (); + if (!m_LastPort || m_LastPort != remotePort) + { + auto itr = m_Sessions.find (remotePort); + if (itr != m_Sessions.end ()) + m_LastSession = itr->second; + else + { + m_LastSession = std::make_shared (boost::asio::ip::udp::endpoint (m_RecvEndpoint), 0); + m_Sessions.emplace (remotePort, m_LastSession); + } + m_LastPort = remotePort; + } + // send off to remote i2p destination + auto ts = i2p::util::GetMillisecondsSinceEpoch (); + LogPrint (eLogDebug, "UDP Client: Send ", transferred, " to ", m_RemoteIdent->ToBase32 (), ":", RemotePort); + auto session = m_LocalDest->GetDatagramDestination ()->GetSession (*m_RemoteIdent); + if (ts > m_LastSession->second + I2P_UDP_REPLIABLE_DATAGRAM_INTERVAL) + m_LocalDest->GetDatagramDestination ()->SendDatagram (session, m_RecvBuff, transferred, remotePort, RemotePort); + else + m_LocalDest->GetDatagramDestination ()->SendRawDatagram (session, m_RecvBuff, transferred, remotePort, RemotePort); + size_t numPackets = 0; + while (numPackets < i2p::datagram::DATAGRAM_SEND_QUEUE_MAX_SIZE) + { + boost::system::error_code ec; + size_t moreBytes = m_LocalSocket->available (ec); + if (ec || !moreBytes) break; + transferred = m_LocalSocket->receive_from (boost::asio::buffer (m_RecvBuff, I2P_UDP_MAX_MTU), m_RecvEndpoint, 0, ec); + remotePort = m_RecvEndpoint.port (); + // TODO: check remotePort + m_LocalDest->GetDatagramDestination ()->SendRawDatagram (session, m_RecvBuff, transferred, remotePort, RemotePort); + numPackets++; + } + if (numPackets) + LogPrint (eLogDebug, "UDP Client: Sent ", numPackets, " more packets to ", m_RemoteIdent->ToBase32 ()); + m_LocalDest->GetDatagramDestination ()->FlushSendQueue (session); + + // mark convo as active + if (m_LastSession) + m_LastSession->second = ts; + RecvFromLocal (); + } + + std::vector > I2PUDPClientTunnel::GetSessions () + { + // TODO: implement + std::vector > infos; + return infos; + } + + void I2PUDPClientTunnel::TryResolving () + { + i2p::util::SetThreadName ("UDP Resolver"); + LogPrint (eLogInfo, "UDP Tunnel: Trying to resolve ", m_RemoteDest); + + std::shared_ptr addr; + while (!(addr = context.GetAddressBook().GetAddress(m_RemoteDest)) && !m_cancel_resolve) + { + LogPrint (eLogWarning, "UDP Tunnel: Failed to lookup ", m_RemoteDest); + std::this_thread::sleep_for (std::chrono::seconds (1)); + } + if (m_cancel_resolve) + { + LogPrint(eLogError, "UDP Tunnel: Lookup of ", m_RemoteDest, " was cancelled"); + return; + } + if (!addr || !addr->IsIdentHash ()) + { + LogPrint (eLogError, "UDP Tunnel: ", m_RemoteDest, " not found"); + return; + } + m_RemoteIdent = new i2p::data::IdentHash; + *m_RemoteIdent = addr->identHash; + LogPrint(eLogInfo, "UDP Tunnel: Resolved ", m_RemoteDest, " to ", m_RemoteIdent->ToBase32 ()); + } + + void I2PUDPClientTunnel::HandleRecvFromI2P (const i2p::data::IdentityEx& from, uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len) + { + if (m_RemoteIdent && from.GetIdentHash() == *m_RemoteIdent) + HandleRecvFromI2PRaw (fromPort, toPort, buf, len); + else + LogPrint(eLogWarning, "UDP Client: Unwarranted traffic from ", from.GetIdentHash().ToBase32 ()); + } + + void I2PUDPClientTunnel::HandleRecvFromI2PRaw (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len) + { + auto itr = m_Sessions.find (toPort); + // found convo ? + if (itr != m_Sessions.end ()) + { + // found convo + if (len > 0) + { + LogPrint (eLogDebug, "UDP Client: Got ", len, "B from ", m_RemoteIdent ? m_RemoteIdent->ToBase32 () : ""); + m_LocalSocket->send_to (boost::asio::buffer (buf, len), itr->second->first); + // mark convo as active + itr->second->second = i2p::util::GetMillisecondsSinceEpoch (); + } + } + else + LogPrint (eLogWarning, "UDP Client: Not tracking udp session using port ", (int) toPort); + } + +} +} diff --git a/libi2pd_client/UDPTunnel.h b/libi2pd_client/UDPTunnel.h new file mode 100644 index 00000000..4bba8768 --- /dev/null +++ b/libi2pd_client/UDPTunnel.h @@ -0,0 +1,186 @@ +/* +* Copyright (c) 2013-2022, The PurpleI2P Project +* +* This file is part of Purple i2pd project and licensed under BSD3 +* +* See full license text in LICENSE file at top of project tree +*/ + +#ifndef UDPTUNNEL_H__ +#define UDPTUNNEL_H__ + +#include +#include +#include +#include +#include +#include +#include +#include "Identity.h" +#include "Destination.h" +#include "Datagram.h" + +namespace i2p +{ +namespace client +{ + /** 2 minute timeout for udp sessions */ + const uint64_t I2P_UDP_SESSION_TIMEOUT = 1000 * 60 * 2; + const uint64_t I2P_UDP_REPLIABLE_DATAGRAM_INTERVAL = 100; // in milliseconds + + /** max size for i2p udp */ + const size_t I2P_UDP_MAX_MTU = 64*1024; + + struct UDPSession + { + i2p::datagram::DatagramDestination * m_Destination; + boost::asio::ip::udp::socket IPSocket; + i2p::data::IdentHash Identity; + boost::asio::ip::udp::endpoint FromEndpoint; + boost::asio::ip::udp::endpoint SendEndpoint; + uint64_t LastActivity; + + uint16_t LocalPort; + uint16_t RemotePort; + + uint8_t m_Buffer[I2P_UDP_MAX_MTU]; + + UDPSession(boost::asio::ip::udp::endpoint localEndpoint, + const std::shared_ptr & localDestination, + boost::asio::ip::udp::endpoint remote, const i2p::data::IdentHash * ident, + uint16_t ourPort, uint16_t theirPort); + void HandleReceived(const boost::system::error_code & ecode, std::size_t len); + void Receive(); + }; + + + /** read only info about a datagram session */ + struct DatagramSessionInfo + { + /** the name of this forward */ + std::string Name; + /** ident hash of local destination */ + std::shared_ptr LocalIdent; + /** ident hash of remote destination */ + std::shared_ptr RemoteIdent; + /** ident hash of IBGW in use currently in this session or nullptr if none is set */ + std::shared_ptr CurrentIBGW; + /** ident hash of OBEP in use for this session or nullptr if none is set */ + std::shared_ptr CurrentOBEP; + /** i2p router's udp endpoint */ + boost::asio::ip::udp::endpoint LocalEndpoint; + /** client's udp endpoint */ + boost::asio::ip::udp::endpoint RemoteEndpoint; + /** how long has this converstation been idle in ms */ + uint64_t idle; + }; + + typedef std::shared_ptr UDPSessionPtr; + + /** server side udp tunnel, many i2p inbound to 1 ip outbound */ + class I2PUDPServerTunnel + { + public: + + I2PUDPServerTunnel (const std::string & name, + std::shared_ptr localDestination, + boost::asio::ip::address localAddress, + boost::asio::ip::udp::endpoint forwardTo, uint16_t port, bool gzip); + ~I2PUDPServerTunnel (); + + /** expire stale udp conversations */ + void ExpireStale (const uint64_t delta=I2P_UDP_SESSION_TIMEOUT); + void Start (); + void Stop (); + const char * GetName () const { return m_Name.c_str(); } + std::vector > GetSessions (); + std::shared_ptr GetLocalDestination () const { return m_LocalDest; } + + void SetUniqueLocal (bool isUniqueLocal = true) { m_IsUniqueLocal = isUniqueLocal; } + + private: + + void HandleRecvFromI2P (const i2p::data::IdentityEx& from, uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len); + void HandleRecvFromI2PRaw (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len); + UDPSessionPtr ObtainUDPSession (const i2p::data::IdentityEx& from, uint16_t localPort, uint16_t remotePort); + + private: + + bool m_IsUniqueLocal; + const std::string m_Name; + boost::asio::ip::address m_LocalAddress; + boost::asio::ip::udp::endpoint m_RemoteEndpoint; + std::mutex m_SessionsMutex; + std::vector m_Sessions; + std::shared_ptr m_LocalDest; + UDPSessionPtr m_LastSession; + bool m_Gzip; + + public: + + bool isUpdated; // transient, used during reload only + }; + + class I2PUDPClientTunnel + { + public: + + I2PUDPClientTunnel (const std::string & name, const std::string &remoteDest, + boost::asio::ip::udp::endpoint localEndpoint, std::shared_ptr localDestination, + uint16_t remotePort, bool gzip); + ~I2PUDPClientTunnel (); + + void Start (); + void Stop (); + const char * GetName () const { return m_Name.c_str(); } + std::vector > GetSessions (); + + bool IsLocalDestination (const i2p::data::IdentHash & destination) const { return destination == m_LocalDest->GetIdentHash(); } + + std::shared_ptr GetLocalDestination () const { return m_LocalDest; } + inline void SetLocalDestination (std::shared_ptr dest) + { + if (m_LocalDest) m_LocalDest->Release (); + if (dest) dest->Acquire (); + m_LocalDest = dest; + } + + void ExpireStale (const uint64_t delta=I2P_UDP_SESSION_TIMEOUT); + + private: + + typedef std::pair UDPConvo; + void RecvFromLocal (); + void HandleRecvFromLocal (const boost::system::error_code & e, std::size_t transferred); + void HandleRecvFromI2P (const i2p::data::IdentityEx& from, uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len); + void HandleRecvFromI2PRaw (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len); + void TryResolving (); + + private: + + const std::string m_Name; + std::mutex m_SessionsMutex; + std::unordered_map > m_Sessions; // maps i2p port -> local udp convo + const std::string m_RemoteDest; + std::shared_ptr m_LocalDest; + const boost::asio::ip::udp::endpoint m_LocalEndpoint; + i2p::data::IdentHash * m_RemoteIdent; + std::thread * m_ResolveThread; + std::unique_ptr m_LocalSocket; + boost::asio::ip::udp::endpoint m_RecvEndpoint; + uint8_t m_RecvBuff[I2P_UDP_MAX_MTU]; + uint16_t RemotePort, m_LastPort; + bool m_cancel_resolve; + bool m_Gzip; + std::shared_ptr m_LastSession; + + public: + + bool isUpdated; // transient, used during reload only + }; + + +} +} + +#endif From 2b6d9eaa8bd7e6f813c7a2f154d8c17bf0ca1f65 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 26 Oct 2022 13:26:16 -0400 Subject: [PATCH 192/219] disable compressible padding for now --- libi2pd/Identity.cpp | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/libi2pd/Identity.cpp b/libi2pd/Identity.cpp index 310e6081..64d87f74 100644 --- a/libi2pd/Identity.cpp +++ b/libi2pd/Identity.cpp @@ -49,21 +49,29 @@ namespace data IdentityEx::IdentityEx(const uint8_t * publicKey, const uint8_t * signingKey, SigningKeyType type, CryptoKeyType cryptoType) { - uint8_t randomPaddingBlock[32]; - RAND_bytes (randomPaddingBlock, 32); + /*uint8_t randomPaddingBlock[32]; + RAND_bytes (randomPaddingBlock, 32);*/ if (cryptoType == CRYPTO_KEY_TYPE_ECIES_X25519_AEAD) { - memcpy (m_StandardIdentity.publicKey, publicKey ? publicKey : randomPaddingBlock, 32); + /*memcpy (m_StandardIdentity.publicKey, publicKey ? publicKey : randomPaddingBlock, 32); for (int i = 0; i < 7; i++) // 224 bytes - memcpy (m_StandardIdentity.publicKey + 32*(i + 1), randomPaddingBlock, 32); + memcpy (m_StandardIdentity.publicKey + 32*(i + 1), randomPaddingBlock, 32);*/ + if (publicKey) + { + memcpy (m_StandardIdentity.publicKey, publicKey, 32); + RAND_bytes (m_StandardIdentity.publicKey + 32, 224); + } + else + RAND_bytes (m_StandardIdentity.publicKey, 256); } else { if (publicKey) memcpy (m_StandardIdentity.publicKey, publicKey, 256); else - for (int i = 0; i < 8; i++) // 256 bytes - memcpy (m_StandardIdentity.publicKey + 32*i, randomPaddingBlock, 32); + RAND_bytes (m_StandardIdentity.publicKey, 256); + /*for (int i = 0; i < 8; i++) // 256 bytes + memcpy (m_StandardIdentity.publicKey + 32*i, randomPaddingBlock, 32);*/ } if (type != SIGNING_KEY_TYPE_DSA_SHA1) { @@ -102,8 +110,9 @@ namespace data case SIGNING_KEY_TYPE_REDDSA_SHA512_ED25519: { size_t padding = 128 - i2p::crypto::EDDSA25519_PUBLIC_KEY_LENGTH; // 96 = 128 - 32 - for (int i = 0; i < 3; i++) // 96 bytes - memcpy (m_StandardIdentity.signingKey + 32*i, randomPaddingBlock, 32); + /*for (int i = 0; i < 3; i++) // 96 bytes + memcpy (m_StandardIdentity.signingKey + 32*i, randomPaddingBlock, 32);*/ + RAND_bytes (m_StandardIdentity.signingKey, 96); memcpy (m_StandardIdentity.signingKey + padding, signingKey, i2p::crypto::EDDSA25519_PUBLIC_KEY_LENGTH); break; } From 2a703e08446616bc1f04b9e5a29eb1714b318c16 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 26 Oct 2022 16:05:40 -0400 Subject: [PATCH 193/219] SSU2 through a socks5 proxy --- libi2pd/Config.cpp | 1 + libi2pd/SSU2.cpp | 50 +++++++++++++++++++++++++++++++++++++++--- libi2pd/SSU2.h | 1 + libi2pd/Transports.cpp | 18 ++++++++++++++- 4 files changed, 66 insertions(+), 4 deletions(-) diff --git a/libi2pd/Config.cpp b/libi2pd/Config.cpp index 2a9955c2..94609101 100644 --- a/libi2pd/Config.cpp +++ b/libi2pd/Config.cpp @@ -277,6 +277,7 @@ namespace config { ("ssu2.enabled", value()->default_value(true), "Enable SSU2 (default: enabled)") ("ssu2.published", value()->default_value(true), "Publish SSU2 (default: enabled)") ("ssu2.port", value()->default_value(0), "Port to listen for incoming SSU2 packets (default: auto)") + ("ssu2.proxy", value()->default_value(""), "Socks5 proxy URL for SSU2 transport") ; options_description nettime("Time sync options"); diff --git a/libi2pd/SSU2.cpp b/libi2pd/SSU2.cpp index c323002c..7f6fbd42 100644 --- a/libi2pd/SSU2.cpp +++ b/libi2pd/SSU2.cpp @@ -42,6 +42,11 @@ namespace transport if (!address) continue; if (address->transportStyle == i2p::data::RouterInfo::eTransportSSU2) { + if (m_IsThroughProxy) + { + found = true; + break; // we don't need port for proxy + } auto port = address->port; if (!port) { @@ -84,7 +89,11 @@ namespace transport } } if (found) + { m_ReceiveService.Start (); + if (m_IsThroughProxy) + ConnectToProxy (); + } ScheduleTermination (); ScheduleResend (false); } @@ -257,7 +266,10 @@ namespace transport { if (packet) { - ProcessNextPacket (packet->buf, packet->len, packet->from); + if (m_IsThroughProxy) + ProcessNextPacketFromProxy (packet->buf, packet->len); + else + ProcessNextPacket (packet->buf, packet->len, packet->from); m_PacketsPool.ReleaseMt (packet); if (m_LastSession && m_LastSession->GetState () != eSSU2SessionStateTerminated) m_LastSession->FlushData (); @@ -266,8 +278,12 @@ namespace transport void SSU2Server::HandleReceivedPackets (std::vector packets) { - for (auto& packet: packets) - ProcessNextPacket (packet->buf, packet->len, packet->from); + if (m_IsThroughProxy) + for (auto& packet: packets) + ProcessNextPacketFromProxy (packet->buf, packet->len); + else + for (auto& packet: packets) + ProcessNextPacket (packet->buf, packet->len, packet->from); m_PacketsPool.ReleaseMt (packets); if (m_LastSession && m_LastSession->GetState () != eSSU2SessionStateTerminated) m_LastSession->FlushData (); @@ -479,6 +495,11 @@ namespace transport void SSU2Server::Send (const uint8_t * header, size_t headerLen, const uint8_t * payload, size_t payloadLen, const boost::asio::ip::udp::endpoint& to) { + if (m_IsThroughProxy) + { + SendThroughProxy (header, headerLen, nullptr, 0, payload, payloadLen, to); + return; + } std::vector bufs { boost::asio::buffer (header, headerLen), @@ -498,6 +519,11 @@ namespace transport void SSU2Server::Send (const uint8_t * header, size_t headerLen, const uint8_t * headerX, size_t headerXLen, const uint8_t * payload, size_t payloadLen, const boost::asio::ip::udp::endpoint& to) { + if (m_IsThroughProxy) + { + SendThroughProxy (header, headerLen, headerX, headerXLen, payload, payloadLen, to); + return; + } std::vector bufs { boost::asio::buffer (header, headerLen), @@ -1250,5 +1276,23 @@ namespace transport ReadUDPAssociateSocket (); }); } + + bool SSU2Server::SetProxy (const std::string& address, uint16_t port) + { + boost::system::error_code ecode; + auto addr = boost::asio::ip::address::from_string (address, ecode); + if (!ecode && !addr.is_unspecified () && port) + { + m_IsThroughProxy = true; + m_ProxyEndpoint.reset (new boost::asio::ip::tcp::endpoint (addr, port)); + } + else + { + if (ecode) + LogPrint (eLogError, "SSU2: Invalid proxy address ", address, " ", ecode.message()); + return false; + } + return true; + } } } diff --git a/libi2pd/SSU2.h b/libi2pd/SSU2.h index 6eff7109..767a9eb8 100644 --- a/libi2pd/SSU2.h +++ b/libi2pd/SSU2.h @@ -57,6 +57,7 @@ namespace transport void Stop (); boost::asio::io_service& GetService () { return GetIOService (); }; void SetLocalAddress (const boost::asio::ip::address& localAddress); + bool SetProxy (const std::string& address, uint16_t port); bool IsSupported (const boost::asio::ip::address& addr) const; uint16_t GetPort (bool v4) const; bool IsSyncClockFromPeers () const { return m_IsSyncClockFromPeers; }; diff --git a/libi2pd/Transports.cpp b/libi2pd/Transports.cpp index 6dac23de..04ded36f 100644 --- a/libi2pd/Transports.cpp +++ b/libi2pd/Transports.cpp @@ -218,7 +218,23 @@ namespace transport } } // create SSU2 server - if (enableSSU2) m_SSU2Server = new SSU2Server (); + if (enableSSU2) + { + m_SSU2Server = new SSU2Server (); + std::string ssu2proxy; i2p::config::GetOption("ssu2.proxy", ssu2proxy); + if (!ssu2proxy.empty()) + { + if (proxyurl.parse (ssu2proxy) && proxyurl.schema == "socks") + { + if (m_SSU2Server->SetProxy (proxyurl.host, proxyurl.port)) + i2p::context.SetStatus (eRouterStatusProxy); + else + LogPrint(eLogError, "Transports: Can't set SSU2 proxy ", ssu2proxy); + } + else + LogPrint(eLogError, "Transports: Invalid SSU2 proxy URL ", ssu2proxy); + } + } // bind to interfaces bool ipv4; i2p::config::GetOption("ipv4", ipv4); From eb75eb0e55d135d8244ae59fe98a8664fe075e25 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 26 Oct 2022 18:35:56 -0400 Subject: [PATCH 194/219] reset port value before parsing --- libi2pd/HTTP.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libi2pd/HTTP.cpp b/libi2pd/HTTP.cpp index e994b9b3..8791eadb 100644 --- a/libi2pd/HTTP.cpp +++ b/libi2pd/HTTP.cpp @@ -1,5 +1,5 @@ /* -* Copyright (c) 2013-2021, The PurpleI2P Project +* Copyright (c) 2013-2022, The PurpleI2P Project * * This file is part of Purple i2pd project and licensed under BSD3 * @@ -135,6 +135,7 @@ namespace http ? url.substr(pos_p, std::string::npos) : url.substr(pos_p, pos_c - pos_p); /* stoi throws exception on failure, we don't need it */ + port = 0; for (char c : port_str) { if (c < '0' || c > '9') return false; From 0e477bf9382000989636a6fb10425060363b060a Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 26 Oct 2022 18:55:13 -0400 Subject: [PATCH 195/219] set min MTU if through proxy --- libi2pd/SSU2.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libi2pd/SSU2.cpp b/libi2pd/SSU2.cpp index 7f6fbd42..4f3e8bf4 100644 --- a/libi2pd/SSU2.cpp +++ b/libi2pd/SSU2.cpp @@ -45,7 +45,8 @@ namespace transport if (m_IsThroughProxy) { found = true; - break; // we don't need port for proxy + i2p::context.SetMTU (SSU2_MIN_PACKET_SIZE, address->IsV4 ()); + continue; // we don't need port for proxy } auto port = address->port; if (!port) @@ -90,9 +91,9 @@ namespace transport } if (found) { - m_ReceiveService.Start (); if (m_IsThroughProxy) ConnectToProxy (); + m_ReceiveService.Start (); } ScheduleTermination (); ScheduleResend (false); From 016222463d5189ce9efbb4191723eface67987e5 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 26 Oct 2022 21:14:28 -0400 Subject: [PATCH 196/219] don't run peer test for SSU2 through proxy --- libi2pd/SSU2.h | 1 + libi2pd/Transports.cpp | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/libi2pd/SSU2.h b/libi2pd/SSU2.h index 767a9eb8..fb2925cb 100644 --- a/libi2pd/SSU2.h +++ b/libi2pd/SSU2.h @@ -58,6 +58,7 @@ namespace transport boost::asio::io_service& GetService () { return GetIOService (); }; void SetLocalAddress (const boost::asio::ip::address& localAddress); bool SetProxy (const std::string& address, uint16_t port); + bool UsesProxy () const { return m_IsThroughProxy; }; bool IsSupported (const boost::asio::ip::address& addr) const; uint16_t GetPort (bool v4) const; bool IsSyncClockFromPeers () const { return m_IsSyncClockFromPeers; }; diff --git a/libi2pd/Transports.cpp b/libi2pd/Transports.cpp index 04ded36f..676cd876 100644 --- a/libi2pd/Transports.cpp +++ b/libi2pd/Transports.cpp @@ -665,7 +665,7 @@ namespace transport LogPrint (eLogWarning, "Transports: Can't find routers for peer test IPv4"); } // SSU2 - if (m_SSU2Server) + if (m_SSU2Server && !m_SSU2Server->UsesProxy ()) { excluded.clear (); excluded.insert (i2p::context.GetIdentHash ()); @@ -714,7 +714,7 @@ namespace transport } // SSU2 - if (m_SSU2Server) + if (m_SSU2Server && !m_SSU2Server->UsesProxy ()) { excluded.clear (); excluded.insert (i2p::context.GetIdentHash ()); From 5fb1247b87f8149abe4e1996423dceb486448cab Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 27 Oct 2022 13:56:42 -0400 Subject: [PATCH 197/219] correct MTU calculation through proxy --- libi2pd/SSU2.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/libi2pd/SSU2.cpp b/libi2pd/SSU2.cpp index 4f3e8bf4..90139c10 100644 --- a/libi2pd/SSU2.cpp +++ b/libi2pd/SSU2.cpp @@ -45,7 +45,10 @@ namespace transport if (m_IsThroughProxy) { found = true; - i2p::context.SetMTU (SSU2_MIN_PACKET_SIZE, address->IsV4 ()); + if (address->IsV6 ()) + i2p::context.SetMTU (SSU2_MAX_PACKET_SIZE - SOCKS5_UDP_IPV6_REQUEST_HEADER_SIZE, false); + else + i2p::context.SetMTU (SSU2_MAX_PACKET_SIZE - SOCKS5_UDP_IPV4_REQUEST_HEADER_SIZE, true); continue; // we don't need port for proxy } auto port = address->port; @@ -162,6 +165,8 @@ namespace transport bool SSU2Server::IsSupported (const boost::asio::ip::address& addr) const { + if (m_IsThroughProxy) + return m_SocketV4.is_open (); if (addr.is_v4 ()) { if (m_SocketV4.is_open ()) @@ -178,7 +183,7 @@ namespace transport uint16_t SSU2Server::GetPort (bool v4) const { boost::system::error_code ec; - boost::asio::ip::udp::endpoint ep = v4 ? m_SocketV4.local_endpoint (ec) : m_SocketV6.local_endpoint (ec); + boost::asio::ip::udp::endpoint ep = (v4 || m_IsThroughProxy) ? m_SocketV4.local_endpoint (ec) : m_SocketV6.local_endpoint (ec); if (ec) return 0; return ep.port (); } @@ -1103,6 +1108,11 @@ namespace transport void SSU2Server::ProcessNextPacketFromProxy (uint8_t * buf, size_t len) { + if (buf[2]) // FRAG + { + LogPrint (eLogWarning, "SSU2: Proxy packet fragmentation is not supported"); + return; + } size_t offset = 0; boost::asio::ip::udp::endpoint ep; switch (buf[3]) // ATYP From 3e3f92c616b6e0e7a8343cd2f574a5496274edba Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 27 Oct 2022 15:02:54 -0400 Subject: [PATCH 198/219] set and check proxy status for ipv6 if presented --- libi2pd/RouterContext.cpp | 2 +- libi2pd/Transports.cpp | 10 ++++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index 423bcfd7..6dd3a30d 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -463,7 +463,7 @@ namespace i2p updated = true; } if (host.is_v6 () && address->IsV6 () && address->ssu && - (!address->ssu->mtu || updated)) + (!address->ssu->mtu || updated) && m_StatusV6 != eRouterStatusProxy) { // update MTU auto mtu = i2p::util::net::GetMTU (host); diff --git a/libi2pd/Transports.cpp b/libi2pd/Transports.cpp index 676cd876..84decfab 100644 --- a/libi2pd/Transports.cpp +++ b/libi2pd/Transports.cpp @@ -167,6 +167,8 @@ namespace transport m_PeerTestTimer = new boost::asio::deadline_timer (*m_Service); } + bool ipv4; i2p::config::GetOption("ipv4", ipv4); + bool ipv6; i2p::config::GetOption("ipv6", ipv6); i2p::config::GetOption("nat", m_IsNAT); m_X25519KeysPairSupplier.Start (); m_IsRunning = true; @@ -190,6 +192,8 @@ namespace transport m_NTCP2Server->UseProxy(proxytype, proxyurl.host, proxyurl.port, proxyurl.user, proxyurl.pass); i2p::context.SetStatus (eRouterStatusProxy); + if (ipv6) + i2p::context.SetStatusV6 (eRouterStatusProxy); } else LogPrint(eLogError, "Transports: Unsupported NTCP2 proxy URL ", ntcp2proxy); @@ -227,7 +231,11 @@ namespace transport if (proxyurl.parse (ssu2proxy) && proxyurl.schema == "socks") { if (m_SSU2Server->SetProxy (proxyurl.host, proxyurl.port)) + { i2p::context.SetStatus (eRouterStatusProxy); + if (ipv6) + i2p::context.SetStatusV6 (eRouterStatusProxy); + } else LogPrint(eLogError, "Transports: Can't set SSU2 proxy ", ssu2proxy); } @@ -237,7 +245,6 @@ namespace transport } // bind to interfaces - bool ipv4; i2p::config::GetOption("ipv4", ipv4); if (ipv4) { std::string address; i2p::config::GetOption("address4", address); @@ -254,7 +261,6 @@ namespace transport } } - bool ipv6; i2p::config::GetOption("ipv6", ipv6); if (ipv6) { std::string address; i2p::config::GetOption("address6", address); From 4ed5e44de72147e220504adcf93b5d9b370adf0b Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 27 Oct 2022 15:22:24 -0400 Subject: [PATCH 199/219] correct buffer size for ipv6 SOCKS proxy reply --- libi2pd/NTCP2.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index 76c40d27..50cef15a 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -1708,7 +1708,7 @@ namespace transport } }); - boost::asio::async_read(conn->GetSocket(), boost::asio::buffer(readbuff->data (), 10), + boost::asio::async_read(conn->GetSocket(), boost::asio::buffer(readbuff->data (), sz), [timer, conn, sz, readbuff](const boost::system::error_code & e, std::size_t transferred) { if(e) From f1f66d7b8f822039da76826c71bad936253ffb4f Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 27 Oct 2022 19:47:24 -0400 Subject: [PATCH 200/219] handle SOCKS connect reply for ipv6 address --- libi2pd/NTCP2.cpp | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index 50cef15a..3619e0c6 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -1708,22 +1708,24 @@ namespace transport } }); - boost::asio::async_read(conn->GetSocket(), boost::asio::buffer(readbuff->data (), sz), + boost::asio::async_read(conn->GetSocket(), boost::asio::buffer(readbuff->data (), SOCKS5_UDP_IPV4_REQUEST_HEADER_SIZE), // read min reply size + boost::asio::transfer_all(), [timer, conn, sz, readbuff](const boost::system::error_code & e, std::size_t transferred) { - if(e) - { + if (e) LogPrint(eLogError, "NTCP2: SOCKS proxy read error ", e.message()); - } - else if(transferred == sz) + else if (!(*readbuff)[1]) // succeeded { - if((*readbuff)[1] == 0x00) - { - timer->cancel(); - conn->ClientLogin(); - return; - } + boost::system::error_code ec; + size_t moreBytes = conn->GetSocket ().available(ec); + if (moreBytes) // read remaining portion of reply if ipv6 received + boost::asio::read (conn->GetSocket (), boost::asio::buffer(readbuff->data (), moreBytes), boost::asio::transfer_all (), ec); + timer->cancel(); + conn->ClientLogin(); + return; } + else + LogPrint(eLogError, "NTCP2: Proxy reply error ", (int)(*readbuff)[1]); timer->cancel(); conn->Terminate(); }); From 1738d118f70a9a34b8f2e7e619534b7ce00f8d68 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 28 Oct 2022 14:06:45 -0400 Subject: [PATCH 201/219] recconnect to proxy --- libi2pd/SSU2.cpp | 29 ++++++++++++++++++++++++++++- libi2pd/SSU2.h | 7 +++++-- 2 files changed, 33 insertions(+), 3 deletions(-) diff --git a/libi2pd/SSU2.cpp b/libi2pd/SSU2.cpp index 90139c10..ee6fe53c 100644 --- a/libi2pd/SSU2.cpp +++ b/libi2pd/SSU2.cpp @@ -1157,6 +1157,7 @@ namespace transport { LogPrint (eLogError, "SSU2: Can't connect to proxy ", *m_ProxyEndpoint, " ", ecode.message ()); m_UDPAssociateSocket.reset (nullptr); + ReconnectToProxy (); } else HandshakeWithProxy (); @@ -1177,6 +1178,7 @@ namespace transport { LogPrint(eLogError, "SSU2: Proxy write error ", ecode.message()); m_UDPAssociateSocket.reset (nullptr); + ReconnectToProxy (); } else ReadHandshakeWithProxyReply (); @@ -1194,6 +1196,7 @@ namespace transport { LogPrint(eLogError, "SSU2: Proxy read error ", ecode.message()); m_UDPAssociateSocket.reset (nullptr); + ReconnectToProxy (); } else { @@ -1224,6 +1227,7 @@ namespace transport { LogPrint(eLogError, "SSU2: Proxy write error ", ecode.message()); m_UDPAssociateSocket.reset (nullptr); + ReconnectToProxy (); } else ReadUDPAssociateReply (); @@ -1241,6 +1245,7 @@ namespace transport { LogPrint(eLogError, "SSU2: Proxy read error ", ecode.message()); m_UDPAssociateSocket.reset (nullptr); + ReconnectToProxy (); } else { @@ -1280,14 +1285,36 @@ namespace transport (void) bytes_transferred; if (ecode) { - LogPrint(eLogError, "SSU2: Proxy UDP Associate socket error ", ecode.message()); + LogPrint(eLogWarning, "SSU2: Proxy UDP Associate socket error ", ecode.message()); m_UDPAssociateSocket.reset (nullptr); + m_ProxyRelayEndpoint.reset (nullptr); + ConnectToProxy (); // try to reconnect immediately } else ReadUDPAssociateSocket (); }); } + void SSU2Server::ReconnectToProxy () + { + LogPrint(eLogInfo, "SSU2: Reconnect to proxy after ", SSU2_PROXY_CONNECT_RETRY_TIMEOUT, " seconds"); + if (m_ProxyConnectRetryTimer) + m_ProxyConnectRetryTimer->cancel (); + else + m_ProxyConnectRetryTimer.reset (new boost::asio::deadline_timer (m_ReceiveService.GetService ())); + m_ProxyConnectRetryTimer->expires_from_now (boost::posix_time::seconds (SSU2_PROXY_CONNECT_RETRY_TIMEOUT)); + m_ProxyConnectRetryTimer->async_wait ( + [this](const boost::system::error_code& ecode) + { + if (ecode != boost::asio::error::operation_aborted) + { + m_UDPAssociateSocket.reset (nullptr); + m_ProxyRelayEndpoint.reset (nullptr); + ConnectToProxy (); + } + }); + } + bool SSU2Server::SetProxy (const std::string& address, uint16_t port) { boost::system::error_code ecode; diff --git a/libi2pd/SSU2.h b/libi2pd/SSU2.h index fb2925cb..c5c2c140 100644 --- a/libi2pd/SSU2.h +++ b/libi2pd/SSU2.h @@ -27,8 +27,9 @@ namespace transport const size_t SSU2_MAX_NUM_INTRODUCERS = 3; const int SSU2_TO_INTRODUCER_SESSION_DURATION = 3600; // 1 hour const int SSU2_TO_INTRODUCER_SESSION_EXPIRATION = 4800; // 80 minutes - const int SSU2_KEEP_ALIVE_INTERVAL = 30; // 30 seconds - + const int SSU2_KEEP_ALIVE_INTERVAL = 30; // in seconds + const int SSU2_PROXY_CONNECT_RETRY_TIMEOUT = 30; // in seconds + class SSU2Server: private i2p::util::RunnableServiceWithWork { struct Packet @@ -124,6 +125,7 @@ namespace transport const uint8_t * payload, size_t payloadLen, const boost::asio::ip::udp::endpoint& to); void ProcessNextPacketFromProxy (uint8_t * buf, size_t len); void ConnectToProxy (); + void ReconnectToProxy (); void HandshakeWithProxy (); void ReadHandshakeWithProxyReply (); void SendUDPAssociateRequest (); @@ -155,6 +157,7 @@ namespace transport std::unique_ptr m_ProxyEndpoint; std::unique_ptr m_UDPAssociateSocket; std::unique_ptr m_ProxyRelayEndpoint; + std::unique_ptr m_ProxyConnectRetryTimer; public: From 4ed4e8708ea146784200ecdae4d60c77ed0b73df Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 28 Oct 2022 18:54:04 -0400 Subject: [PATCH 202/219] close relay socket if associate socket gets closed --- libi2pd/SSU2.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libi2pd/SSU2.cpp b/libi2pd/SSU2.cpp index ee6fe53c..23992640 100644 --- a/libi2pd/SSU2.cpp +++ b/libi2pd/SSU2.cpp @@ -1288,6 +1288,7 @@ namespace transport LogPrint(eLogWarning, "SSU2: Proxy UDP Associate socket error ", ecode.message()); m_UDPAssociateSocket.reset (nullptr); m_ProxyRelayEndpoint.reset (nullptr); + m_SocketV4.close (); ConnectToProxy (); // try to reconnect immediately } else @@ -1310,6 +1311,7 @@ namespace transport { m_UDPAssociateSocket.reset (nullptr); m_ProxyRelayEndpoint.reset (nullptr); + LogPrint(eLogInfo, "SSU2: Reconnecting to proxy"); ConnectToProxy (); } }); From e13f15147467e5fec00441613460f07191f06431 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 31 Oct 2022 18:11:36 -0400 Subject: [PATCH 203/219] ssu2.mtu4 and ssu2.mtu6 --- libi2pd/Config.cpp | 2 ++ libi2pd/SSU2.cpp | 29 +++++++++++++++++++++++------ libi2pd/Transports.cpp | 22 ++++++++++++++++++++++ 3 files changed, 47 insertions(+), 6 deletions(-) diff --git a/libi2pd/Config.cpp b/libi2pd/Config.cpp index 94609101..b3563c9d 100644 --- a/libi2pd/Config.cpp +++ b/libi2pd/Config.cpp @@ -277,6 +277,8 @@ namespace config { ("ssu2.enabled", value()->default_value(true), "Enable SSU2 (default: enabled)") ("ssu2.published", value()->default_value(true), "Publish SSU2 (default: enabled)") ("ssu2.port", value()->default_value(0), "Port to listen for incoming SSU2 packets (default: auto)") + ("ssu2.mtu4", value()->default_value(0), "MTU for ipv4 address (default: detect)") + ("ssu2.mtu6", value()->default_value(0), "MTU for ipv6 address (default: detect)") ("ssu2.proxy", value()->default_value(""), "Socks5 proxy URL for SSU2 transport") ; diff --git a/libi2pd/SSU2.cpp b/libi2pd/SSU2.cpp index 23992640..fdb4f1ad 100644 --- a/libi2pd/SSU2.cpp +++ b/libi2pd/SSU2.cpp @@ -46,9 +46,19 @@ namespace transport { found = true; if (address->IsV6 ()) - i2p::context.SetMTU (SSU2_MAX_PACKET_SIZE - SOCKS5_UDP_IPV6_REQUEST_HEADER_SIZE, false); + { + uint16_t mtu; i2p::config::GetOption ("ssu2.mtu6", mtu); + if (!mtu || mtu > SSU2_MAX_PACKET_SIZE - SOCKS5_UDP_IPV6_REQUEST_HEADER_SIZE) + mtu = SSU2_MAX_PACKET_SIZE - SOCKS5_UDP_IPV6_REQUEST_HEADER_SIZE; + i2p::context.SetMTU (mtu, false); + } else - i2p::context.SetMTU (SSU2_MAX_PACKET_SIZE - SOCKS5_UDP_IPV4_REQUEST_HEADER_SIZE, true); + { + uint16_t mtu; i2p::config::GetOption ("ssu2.mtu4", mtu); + if (!mtu || mtu > SSU2_MAX_PACKET_SIZE - SOCKS5_UDP_IPV4_REQUEST_HEADER_SIZE) + mtu = SSU2_MAX_PACKET_SIZE - SOCKS5_UDP_IPV4_REQUEST_HEADER_SIZE; + i2p::context.SetMTU (mtu, true); + } continue; // we don't need port for proxy } auto port = address->port; @@ -147,7 +157,8 @@ namespace transport if (localAddress.is_v4 ()) { m_AddressV4 = localAddress; - int mtu = i2p::util::net::GetMTU (localAddress); + uint16_t mtu; i2p::config::GetOption ("ssu2.mtu4", mtu); + if (!mtu) mtu = i2p::util::net::GetMTU (localAddress); if (mtu < (int)SSU2_MIN_PACKET_SIZE) mtu = SSU2_MIN_PACKET_SIZE; if (mtu > (int)SSU2_MAX_PACKET_SIZE) mtu = SSU2_MAX_PACKET_SIZE; i2p::context.SetMTU (mtu, true); @@ -155,9 +166,15 @@ namespace transport else if (localAddress.is_v6 ()) { m_AddressV6 = localAddress; - int maxMTU = i2p::util::net::GetMaxMTU (localAddress.to_v6 ()); - int mtu = i2p::util::net::GetMTU (localAddress); - if (mtu > maxMTU) mtu = maxMTU; + uint16_t mtu; i2p::config::GetOption ("ssu2.mtu6", mtu); + if (!mtu) + { + int maxMTU = i2p::util::net::GetMaxMTU (localAddress.to_v6 ()); + mtu = i2p::util::net::GetMTU (localAddress); + if (mtu > maxMTU) mtu = maxMTU; + } + else + if (mtu > (int)SSU2_MAX_PACKET_SIZE) mtu = SSU2_MAX_PACKET_SIZE; if (mtu < (int)SSU2_MIN_PACKET_SIZE) mtu = SSU2_MIN_PACKET_SIZE; i2p::context.SetMTU (mtu, false); } diff --git a/libi2pd/Transports.cpp b/libi2pd/Transports.cpp index 84decfab..0d5764cf 100644 --- a/libi2pd/Transports.cpp +++ b/libi2pd/Transports.cpp @@ -259,6 +259,17 @@ namespace transport if (m_SSU2Server) m_SSU2Server->SetLocalAddress (addr); } } + + if (enableSSU2) + { + uint16_t mtu; i2p::config::GetOption ("ssu2.mtu4", mtu); + if (mtu) + { + if (mtu < (int)SSU2_MIN_PACKET_SIZE) mtu = SSU2_MIN_PACKET_SIZE; + if (mtu > (int)SSU2_MAX_PACKET_SIZE) mtu = SSU2_MAX_PACKET_SIZE; + i2p::context.SetMTU (mtu, true); + } + } } if (ipv6) @@ -275,6 +286,17 @@ namespace transport if (m_SSU2Server) m_SSU2Server->SetLocalAddress (addr); } } + + if (enableSSU2) + { + uint16_t mtu; i2p::config::GetOption ("ssu2.mtu6", mtu); + if (mtu) + { + if (mtu < (int)SSU2_MIN_PACKET_SIZE) mtu = SSU2_MIN_PACKET_SIZE; + if (mtu > (int)SSU2_MAX_PACKET_SIZE) mtu = SSU2_MAX_PACKET_SIZE; + i2p::context.SetMTU (mtu, false); + } + } } bool ygg; i2p::config::GetOption("meshnets.yggdrasil", ygg); From b8ce0b083865d76a6b59aa809a7d59507865a023 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 3 Nov 2022 20:02:43 -0400 Subject: [PATCH 204/219] store Address instead IdentHash for UDP tunnel --- libi2pd_client/UDPTunnel.cpp | 38 +++++++++++++++--------------------- libi2pd_client/UDPTunnel.h | 11 ++++++----- 2 files changed, 22 insertions(+), 27 deletions(-) diff --git a/libi2pd_client/UDPTunnel.cpp b/libi2pd_client/UDPTunnel.cpp index a2c9061c..ab069297 100644 --- a/libi2pd_client/UDPTunnel.cpp +++ b/libi2pd_client/UDPTunnel.cpp @@ -85,24 +85,23 @@ namespace client else addr = m_LocalAddress; boost::asio::ip::udp::endpoint ep(addr, 0); - m_Sessions.push_back(std::make_shared(ep, m_LocalDest, m_RemoteEndpoint, &ih, localPort, remotePort)); + m_Sessions.push_back(std::make_shared(ep, m_LocalDest, m_RemoteEndpoint, ih, localPort, remotePort)); auto & back = m_Sessions.back(); return back; } UDPSession::UDPSession(boost::asio::ip::udp::endpoint localEndpoint, const std::shared_ptr & localDestination, - boost::asio::ip::udp::endpoint endpoint, const i2p::data::IdentHash * to, + const boost::asio::ip::udp::endpoint& endpoint, const i2p::data::IdentHash& to, uint16_t ourPort, uint16_t theirPort) : m_Destination(localDestination->GetDatagramDestination()), IPSocket(localDestination->GetService(), localEndpoint), - SendEndpoint(endpoint), + Identity (to), SendEndpoint(endpoint), LastActivity(i2p::util::GetMillisecondsSinceEpoch()), LocalPort(ourPort), RemotePort(theirPort) { IPSocket.set_option (boost::asio::socket_base::receive_buffer_size (I2P_UDP_MAX_MTU )); - memcpy(Identity, to->data(), 32); Receive(); } @@ -145,7 +144,7 @@ namespace client } I2PUDPServerTunnel::I2PUDPServerTunnel (const std::string & name, std::shared_ptr localDestination, - boost::asio::ip::address localAddress, boost::asio::ip::udp::endpoint forwardTo, uint16_t port, bool gzip) : + const boost::asio::ip::address& localAddress, const boost::asio::ip::udp::endpoint& forwardTo, uint16_t port, bool gzip) : m_IsUniqueLocal (true), m_Name (name), m_LocalAddress (localAddress), m_RemoteEndpoint (forwardTo), m_LocalDest (localDestination), m_Gzip (gzip) { @@ -194,11 +193,11 @@ namespace client } I2PUDPClientTunnel::I2PUDPClientTunnel (const std::string & name, const std::string &remoteDest, - boost::asio::ip::udp::endpoint localEndpoint, + const boost::asio::ip::udp::endpoint& localEndpoint, std::shared_ptr localDestination, uint16_t remotePort, bool gzip) : m_Name (name), m_RemoteDest (remoteDest), m_LocalDest (localDestination), m_LocalEndpoint (localEndpoint), - m_RemoteIdent (nullptr), m_ResolveThread (nullptr), m_LocalSocket (nullptr), RemotePort (remotePort), + m_ResolveThread (nullptr), m_LocalSocket (nullptr), RemotePort (remotePort), m_LastPort (0), m_cancel_resolve (false), m_Gzip (gzip) { } @@ -248,11 +247,7 @@ namespace client delete m_ResolveThread; m_ResolveThread = nullptr; } - if (m_RemoteIdent) - { - delete m_RemoteIdent; - m_RemoteIdent = nullptr; - } + m_RemoteAddr = nullptr; } void I2PUDPClientTunnel::RecvFromLocal () @@ -272,7 +267,8 @@ namespace client RecvFromLocal (); // Restart listener and continue work return; } - if (!m_RemoteIdent) { + if (!m_RemoteAddr || !m_RemoteAddr->IsIdentHash ()) // TODO: handle B33 + { LogPrint (eLogWarning, "UDP Client: Remote endpoint not resolved yet"); RecvFromLocal (); return; // drop, remote not resolved @@ -292,8 +288,8 @@ namespace client } // send off to remote i2p destination auto ts = i2p::util::GetMillisecondsSinceEpoch (); - LogPrint (eLogDebug, "UDP Client: Send ", transferred, " to ", m_RemoteIdent->ToBase32 (), ":", RemotePort); - auto session = m_LocalDest->GetDatagramDestination ()->GetSession (*m_RemoteIdent); + LogPrint (eLogDebug, "UDP Client: Send ", transferred, " to ", m_RemoteAddr->identHash.ToBase32 (), ":", RemotePort); + auto session = m_LocalDest->GetDatagramDestination ()->GetSession (m_RemoteAddr->identHash); if (ts > m_LastSession->second + I2P_UDP_REPLIABLE_DATAGRAM_INTERVAL) m_LocalDest->GetDatagramDestination ()->SendDatagram (session, m_RecvBuff, transferred, remotePort, RemotePort); else @@ -311,7 +307,7 @@ namespace client numPackets++; } if (numPackets) - LogPrint (eLogDebug, "UDP Client: Sent ", numPackets, " more packets to ", m_RemoteIdent->ToBase32 ()); + LogPrint (eLogDebug, "UDP Client: Sent ", numPackets, " more packets to ", m_RemoteAddr->identHash.ToBase32 ()); m_LocalDest->GetDatagramDestination ()->FlushSendQueue (session); // mark convo as active @@ -343,19 +339,17 @@ namespace client LogPrint(eLogError, "UDP Tunnel: Lookup of ", m_RemoteDest, " was cancelled"); return; } - if (!addr || !addr->IsIdentHash ()) + if (!addr) { LogPrint (eLogError, "UDP Tunnel: ", m_RemoteDest, " not found"); return; } - m_RemoteIdent = new i2p::data::IdentHash; - *m_RemoteIdent = addr->identHash; - LogPrint(eLogInfo, "UDP Tunnel: Resolved ", m_RemoteDest, " to ", m_RemoteIdent->ToBase32 ()); + LogPrint(eLogInfo, "UDP Tunnel: Resolved ", m_RemoteDest, " to ", m_RemoteAddr->identHash.ToBase32 ()); } void I2PUDPClientTunnel::HandleRecvFromI2P (const i2p::data::IdentityEx& from, uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len) { - if (m_RemoteIdent && from.GetIdentHash() == *m_RemoteIdent) + if (m_RemoteAddr && from.GetIdentHash() == m_RemoteAddr->identHash) HandleRecvFromI2PRaw (fromPort, toPort, buf, len); else LogPrint(eLogWarning, "UDP Client: Unwarranted traffic from ", from.GetIdentHash().ToBase32 ()); @@ -370,7 +364,7 @@ namespace client // found convo if (len > 0) { - LogPrint (eLogDebug, "UDP Client: Got ", len, "B from ", m_RemoteIdent ? m_RemoteIdent->ToBase32 () : ""); + LogPrint (eLogDebug, "UDP Client: Got ", len, "B from ", m_RemoteAddr ? m_RemoteAddr->identHash.ToBase32 () : ""); m_LocalSocket->send_to (boost::asio::buffer (buf, len), itr->second->first); // mark convo as active itr->second->second = i2p::util::GetMillisecondsSinceEpoch (); diff --git a/libi2pd_client/UDPTunnel.h b/libi2pd_client/UDPTunnel.h index 4bba8768..749ec4d3 100644 --- a/libi2pd_client/UDPTunnel.h +++ b/libi2pd_client/UDPTunnel.h @@ -19,6 +19,7 @@ #include "Identity.h" #include "Destination.h" #include "Datagram.h" +#include "AddressBook.h" namespace i2p { @@ -47,7 +48,7 @@ namespace client UDPSession(boost::asio::ip::udp::endpoint localEndpoint, const std::shared_ptr & localDestination, - boost::asio::ip::udp::endpoint remote, const i2p::data::IdentHash * ident, + const boost::asio::ip::udp::endpoint& remote, const i2p::data::IdentHash& ident, uint16_t ourPort, uint16_t theirPort); void HandleReceived(const boost::system::error_code & ecode, std::size_t len); void Receive(); @@ -84,8 +85,8 @@ namespace client I2PUDPServerTunnel (const std::string & name, std::shared_ptr localDestination, - boost::asio::ip::address localAddress, - boost::asio::ip::udp::endpoint forwardTo, uint16_t port, bool gzip); + const boost::asio::ip::address& localAddress, + const boost::asio::ip::udp::endpoint& forwardTo, uint16_t port, bool gzip); ~I2PUDPServerTunnel (); /** expire stale udp conversations */ @@ -126,7 +127,7 @@ namespace client public: I2PUDPClientTunnel (const std::string & name, const std::string &remoteDest, - boost::asio::ip::udp::endpoint localEndpoint, std::shared_ptr localDestination, + const boost::asio::ip::udp::endpoint& localEndpoint, std::shared_ptr localDestination, uint16_t remotePort, bool gzip); ~I2PUDPClientTunnel (); @@ -164,7 +165,7 @@ namespace client const std::string m_RemoteDest; std::shared_ptr m_LocalDest; const boost::asio::ip::udp::endpoint m_LocalEndpoint; - i2p::data::IdentHash * m_RemoteIdent; + std::shared_ptr m_RemoteAddr; std::thread * m_ResolveThread; std::unique_ptr m_LocalSocket; boost::asio::ip::udp::endpoint m_RecvEndpoint; From 8299f80ea5ae98abc2f359fc18efc3eb63c29a07 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 4 Nov 2022 12:55:53 -0400 Subject: [PATCH 205/219] correct assignment of remote address --- libi2pd_client/UDPTunnel.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/libi2pd_client/UDPTunnel.cpp b/libi2pd_client/UDPTunnel.cpp index ab069297..4f1b31f2 100644 --- a/libi2pd_client/UDPTunnel.cpp +++ b/libi2pd_client/UDPTunnel.cpp @@ -328,8 +328,7 @@ namespace client i2p::util::SetThreadName ("UDP Resolver"); LogPrint (eLogInfo, "UDP Tunnel: Trying to resolve ", m_RemoteDest); - std::shared_ptr addr; - while (!(addr = context.GetAddressBook().GetAddress(m_RemoteDest)) && !m_cancel_resolve) + while (!(m_RemoteAddr = context.GetAddressBook().GetAddress(m_RemoteDest)) && !m_cancel_resolve) { LogPrint (eLogWarning, "UDP Tunnel: Failed to lookup ", m_RemoteDest); std::this_thread::sleep_for (std::chrono::seconds (1)); @@ -339,7 +338,7 @@ namespace client LogPrint(eLogError, "UDP Tunnel: Lookup of ", m_RemoteDest, " was cancelled"); return; } - if (!addr) + if (!m_RemoteAddr) { LogPrint (eLogError, "UDP Tunnel: ", m_RemoteDest, " not found"); return; From e1e4924592e73f07b4618477ba50421ad94c4e80 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Fri, 4 Nov 2022 21:08:25 +0300 Subject: [PATCH 206/219] [gha] update freebsd workflow Signed-off-by: R4SAS --- .github/workflows/build-freebsd.yml | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-freebsd.yml b/.github/workflows/build-freebsd.yml index 16953ed0..557a9b13 100644 --- a/.github/workflows/build-freebsd.yml +++ b/.github/workflows/build-freebsd.yml @@ -10,12 +10,19 @@ jobs: - uses: actions/checkout@v2 - name: Test in FreeBSD id: test - uses: vmactions/freebsd-vm@v0.2.0 + uses: vmactions/freebsd-vm@v0.3.0 with: usesh: true mem: 2048 - prepare: pkg install -y devel/cmake devel/gmake devel/boost-libs security/openssl net/miniupnpc + sync: rsync + copyback: true + prepare: pkg install -y devel/cmake devel/gmake devel/boost-libs security/openssl net/miniupnpc run: | cd build cmake -DWITH_UPNP=ON -DCMAKE_BUILD_TYPE=Release . gmake -j2 + - name: Upload artifacts + uses: actions/upload-artifact@v2 + with: + name: i2pd-freebsd + path: build/i2pd \ No newline at end of file From 7f98a8b9726354a25f9aa66f243ab2671cd6bcee Mon Sep 17 00:00:00 2001 From: Sergey Fedorov Date: Sun, 6 Nov 2022 18:48:02 +0800 Subject: [PATCH 207/219] Fix definitions for Darwin PPC; do not use pthread_setname_np on unsupported OS versions (#1797) * Correct define for Darwin PPC is __POWERPC__ * util.cpp: do not use pthread_setname_np on unsupported macOS versions --- build/cmake_modules/TargetArch.cmake | 2 +- libi2pd/util.cpp | 12 +++++++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/build/cmake_modules/TargetArch.cmake b/build/cmake_modules/TargetArch.cmake index d9ebe7c9..ac7275b1 100644 --- a/build/cmake_modules/TargetArch.cmake +++ b/build/cmake_modules/TargetArch.cmake @@ -61,7 +61,7 @@ set(archdetect_c_code " #else #error cmake_ARCH mips #endif -#elif defined(__ppc__) || defined(__ppc) || defined(__powerpc__) \\ +#elif defined(__ppc__) || defined(__ppc) || defined(__powerpc__) || defined(__POWERPC__) \\ || defined(_ARCH_COM) || defined(_ARCH_PWR) || defined(_ARCH_PPC) \\ || defined(_M_MPPC) || defined(_M_PPC) #if defined(__ppc64__) || defined(__powerpc64__) || defined(__64BIT__) diff --git a/libi2pd/util.cpp b/libi2pd/util.cpp index 10de346f..b8234b39 100644 --- a/libi2pd/util.cpp +++ b/libi2pd/util.cpp @@ -22,6 +22,9 @@ #include #endif +#if defined(__APPLE__) +# include +#endif #ifdef _WIN32 #include @@ -143,8 +146,15 @@ namespace util } void SetThreadName (const char *name) { -#if defined(__APPLE__) && !defined(__powerpc__) +#if defined(__APPLE__) +# if (!defined(MAC_OS_X_VERSION_10_6) || \ + (MAC_OS_X_VERSION_MAX_ALLOWED < 1060) || \ + defined(__POWERPC__)) + /* pthread_setname_np is not there on <10.6 and all PPC. + So do nothing. */ +# else pthread_setname_np((char*)name); +# endif #elif defined(__FreeBSD__) || defined(__OpenBSD__) pthread_set_name_np(pthread_self(), name); #elif defined(__NetBSD__) From c88638afe42d2152bc6279087f1722d3413b395b Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 8 Nov 2022 10:37:34 -0500 Subject: [PATCH 208/219] reconnect to proxy if receive error --- libi2pd/SSU2.cpp | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/libi2pd/SSU2.cpp b/libi2pd/SSU2.cpp index fdb4f1ad..65f6f4f1 100644 --- a/libi2pd/SSU2.cpp +++ b/libi2pd/SSU2.cpp @@ -277,10 +277,20 @@ namespace transport if (ecode != boost::asio::error::operation_aborted) { LogPrint (eLogError, "SSU2: Receive error: code ", ecode.value(), ": ", ecode.message ()); - auto ep = socket.local_endpoint (); - socket.close (); - OpenSocket (ep); - Receive (socket); + if (m_IsThroughProxy) + { + m_UDPAssociateSocket.reset (nullptr); + m_ProxyRelayEndpoint.reset (nullptr); + m_SocketV4.close (); + ConnectToProxy (); + } + else + { + auto ep = socket.local_endpoint (); + socket.close (); + OpenSocket (ep); + Receive (socket); + } } } } From 28aeebd4c7d19b7637a283e7e05df1c51f8fd429 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Sun, 6 Nov 2022 14:05:23 +0300 Subject: [PATCH 209/219] [gha] switch to another deb build action Signed-off-by: R4SAS --- .github/workflows/build-deb.yml | 32 ++++++++++++++++++++++ .github/workflows/build.yml | 48 --------------------------------- 2 files changed, 32 insertions(+), 48 deletions(-) create mode 100644 .github/workflows/build-deb.yml diff --git a/.github/workflows/build-deb.yml b/.github/workflows/build-deb.yml new file mode 100644 index 00000000..bda12dbc --- /dev/null +++ b/.github/workflows/build-deb.yml @@ -0,0 +1,32 @@ +name: Build Debian packages + +on: [push, pull_request] + +jobs: + build: + name: ${{ matrix.dist }} + runs-on: ubuntu-latest + strategy: + matrix: + dist: ['buster', 'bullseye', 'bookworm'] + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: 0 + - name: change debian changelog + run: | + sudo apt-get update + sudo apt-get install devscripts + debchange -v "`git describe --tags`-${{ matrix.dist }}" -b -M --distribution ${{ matrix.dist }} "trunk build" + - uses: jtdor/build-deb-action@v1 + with: + docker-image: debian:${{ matrix.dist }}-slim + buildpackage-opts: --build=binary --no-sign + - uses: actions/upload-artifact@v3 + with: + name: i2pd_${{ matrix.dist }} + path: debian/artifacts/i2pd_*.deb + - uses: actions/upload-artifact@v3 + with: + name: i2pd-dbgsym_${{ matrix.dist }} + path: debian/artifacts/i2pd-dbgsym_*.deb diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index affa0b8b..d8828f61 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -38,51 +38,3 @@ jobs: cd build cmake -DWITH_UPNP=${{ matrix.with_upnp }} . make -j3 - build-deb-stretch: - name: Build package for stretch - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - with: - fetch-depth: 0 - - name: change debian changelog - run: | - sudo apt-get update - sudo apt-get install devscripts - debchange -v "`git describe --tags`-stretch" -b -M --distribution stretch "trunk build" - - uses: singingwolfboy/build-dpkg-stretch@v1 - id: build - with: - args: --unsigned-source --unsigned-changes -b - - uses: actions/upload-artifact@v1 - with: - name: ${{ steps.build.outputs.filename }} - path: ${{ steps.build.outputs.filename }} - - uses: actions/upload-artifact@v1 - with: - name: ${{ steps.build.outputs.filename-dbgsym }} - path: ${{ steps.build.outputs.filename-dbgsym }} - build-deb-buster: - name: Build package for buster - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - with: - fetch-depth: 0 - - name: change debian changelog - run: | - sudo apt-get update - sudo apt-get install devscripts - debchange -v "`git describe --tags`-buster" -b -M --distribution buster "trunk build" - - uses: singingwolfboy/build-dpkg-buster@v1 - id: build - with: - args: --unsigned-source --unsigned-changes -b - - uses: actions/upload-artifact@v1 - with: - name: ${{ steps.build.outputs.filename }} - path: ${{ steps.build.outputs.filename }} - - uses: actions/upload-artifact@v1 - with: - name: ${{ steps.build.outputs.filename-dbgsym }} - path: ${{ steps.build.outputs.filename-dbgsym }} From c6a6a4e0e8e53d7ab7a5ec4c806ec1d5c9f901de Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 8 Nov 2022 18:34:59 -0500 Subject: [PATCH 210/219] sync Receive from stream --- libi2pd/Streaming.cpp | 23 +++++++++++++++++++++++ libi2pd/Streaming.h | 10 +++++----- libi2pd_client/AddressBook.cpp | 24 ++++++++++-------------- 3 files changed, 38 insertions(+), 19 deletions(-) diff --git a/libi2pd/Streaming.cpp b/libi2pd/Streaming.cpp index f7737646..63cf20a2 100644 --- a/libi2pd/Streaming.cpp +++ b/libi2pd/Streaming.cpp @@ -474,6 +474,29 @@ namespace stream Close (); // check is all outgoing messages have been sent and we can send close } + size_t Stream::Receive (uint8_t * buf, size_t len, int timeout) + { + if (!len) return 0; + size_t ret = 0; + std::condition_variable newDataReceived; + std::mutex newDataReceivedMutex; + std::unique_lock l(newDataReceivedMutex); + AsyncReceive (boost::asio::buffer (buf, len), + [&ret, &newDataReceived, &newDataReceivedMutex](const boost::system::error_code& ecode, std::size_t bytes_transferred) + { + if (ecode == boost::asio::error::timed_out) + ret = 0; + else + ret = bytes_transferred; + std::unique_lock l(newDataReceivedMutex); + newDataReceived.notify_all (); + }, + timeout); + if (newDataReceived.wait_for (l, std::chrono::seconds (timeout)) == std::cv_status::timeout) + ret = 0; + return ret; + } + size_t Stream::Send (const uint8_t * buf, size_t len) { AsyncSend (buf, len, nullptr); diff --git a/libi2pd/Streaming.h b/libi2pd/Streaming.h index 19f2f8f6..1662f0e4 100644 --- a/libi2pd/Streaming.h +++ b/libi2pd/Streaming.h @@ -185,7 +185,8 @@ namespace stream template void AsyncReceive (const Buffer& buffer, ReceiveHandler handler, int timeout = 0); size_t ReadSome (uint8_t * buf, size_t len) { return ConcatenatePackets (buf, len); }; - + size_t Receive (uint8_t * buf, size_t len, int timeout); + void AsyncClose() { m_Service.post(std::bind(&Stream::Close, shared_from_this())); }; /** only call close from destination thread, use Stream::AsyncClose for other threads */ @@ -336,11 +337,10 @@ namespace stream int t = (timeout > MAX_RECEIVE_TIMEOUT) ? MAX_RECEIVE_TIMEOUT : timeout; s->m_ReceiveTimer.expires_from_now (boost::posix_time::seconds(t)); int left = timeout - t; - auto self = s->shared_from_this(); - self->m_ReceiveTimer.async_wait ( - [self, buffer, handler, left](const boost::system::error_code & ec) + s->m_ReceiveTimer.async_wait ( + [s, buffer, handler, left](const boost::system::error_code & ec) { - self->HandleReceiveTimer(ec, buffer, handler, left); + s->HandleReceiveTimer(ec, buffer, handler, left); }); } }); diff --git a/libi2pd_client/AddressBook.cpp b/libi2pd_client/AddressBook.cpp index 3a35a817..62a619c4 100644 --- a/libi2pd_client/AddressBook.cpp +++ b/libi2pd_client/AddressBook.cpp @@ -892,24 +892,20 @@ namespace client int numAttempts = 0; while (!end) { - stream->AsyncReceive (boost::asio::buffer (recv_buf, 4096), - [&](const boost::system::error_code& ecode, std::size_t bytes_transferred) - { - if (bytes_transferred) - response.append ((char *)recv_buf, bytes_transferred); - if (ecode == boost::asio::error::timed_out || !stream->IsOpen ()) - end = true; - newDataReceived.notify_all (); - }, - SUBSCRIPTION_REQUEST_TIMEOUT); - std::unique_lock l(newDataReceivedMutex); - // wait 1 more second - if (newDataReceived.wait_for (l, std::chrono::seconds (SUBSCRIPTION_REQUEST_TIMEOUT + 1)) == std::cv_status::timeout) + size_t received = stream->Receive (recv_buf, 4096, SUBSCRIPTION_REQUEST_TIMEOUT); + if (received) + { + response.append ((char *)recv_buf, received); + if (!stream->IsOpen ()) end = true; + } + else if (!stream->IsOpen ()) + end = true; + else { LogPrint (eLogError, "Addressbook: Subscriptions request timeout expired"); numAttempts++; if (numAttempts > 5) end = true; - } + } } // process remaining buffer while (size_t len = stream->ReadSome (recv_buf, sizeof(recv_buf))) From 9fd60b52f1d59b18dcc7e7f179cc33021887c759 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 8 Nov 2022 19:52:43 -0500 Subject: [PATCH 211/219] sync StreamCreate --- libi2pd/Destination.cpp | 29 ++++++++++++++++++++ libi2pd/Destination.h | 5 ++++ libi2pd_client/AddressBook.cpp | 49 +++++++++++----------------------- 3 files changed, 49 insertions(+), 34 deletions(-) diff --git a/libi2pd/Destination.cpp b/libi2pd/Destination.cpp index 719f5830..581fc733 100644 --- a/libi2pd/Destination.cpp +++ b/libi2pd/Destination.cpp @@ -1129,6 +1129,35 @@ namespace client }); } + template + std::shared_ptr ClientDestination::CreateStreamSync (const Dest& dest, int port) + { + std::shared_ptr stream; + std::condition_variable streamRequestComplete; + std::mutex streamRequestCompleteMutex; + std::unique_lock l(streamRequestCompleteMutex); + CreateStream ( + [&streamRequestComplete, &streamRequestCompleteMutex, &stream](std::shared_ptr s) + { + stream = s; + std::unique_lock l(streamRequestCompleteMutex); + streamRequestComplete.notify_all (); + }, + dest, port); + streamRequestComplete.wait (l); + return stream; + } + + std::shared_ptr ClientDestination::CreateStream (const i2p::data::IdentHash& dest, int port) + { + return CreateStreamSync (dest, port); + } + + std::shared_ptr ClientDestination::CreateStream (std::shared_ptr dest, int port) + { + return CreateStreamSync (dest, port); + } + std::shared_ptr ClientDestination::CreateStream (std::shared_ptr remote, int port) { if (m_StreamingDestination) diff --git a/libi2pd/Destination.h b/libi2pd/Destination.h index 4b08ec51..9d369a92 100644 --- a/libi2pd/Destination.h +++ b/libi2pd/Destination.h @@ -247,6 +247,8 @@ namespace client // 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); + std::shared_ptr CreateStream (const i2p::data::IdentHash& dest, int port = 0); // sync + std::shared_ptr CreateStream (std::shared_ptr dest, int port = 0); // sync std::shared_ptr CreateStream (std::shared_ptr remote, int port = 0); void SendPing (const i2p::data::IdentHash& to); void SendPing (std::shared_ptr to); @@ -282,6 +284,9 @@ namespace client void PersistTemporaryKeys (EncryptionKey * keys, bool isSingleKey); void ReadAuthKey (const std::string& group, const std::map * params); + template + std::shared_ptr CreateStreamSync (const Dest& dest, int port); + private: i2p::data::PrivateKeys m_Keys; diff --git a/libi2pd_client/AddressBook.cpp b/libi2pd_client/AddressBook.cpp index 62a619c4..07f91d2e 100644 --- a/libi2pd_client/AddressBook.cpp +++ b/libi2pd_client/AddressBook.cpp @@ -833,40 +833,22 @@ namespace client } else m_Ident = addr->identHash; - /* this code block still needs some love */ - std::condition_variable newDataReceived; - std::mutex newDataReceivedMutex; - auto leaseSet = i2p::client::context.GetSharedLocalDestination ()->FindLeaseSet (m_Ident); - if (!leaseSet) + // save url parts for later use + std::string dest_host = url.host; + int dest_port = url.port ? url.port : 80; + // try to create stream to addressbook site + auto stream = i2p::client::context.GetSharedLocalDestination ()->CreateStream (m_Ident, dest_port); + if (!stream) { - std::unique_lock l(newDataReceivedMutex); - i2p::client::context.GetSharedLocalDestination ()->RequestDestination (m_Ident, - [&newDataReceived, &leaseSet, &newDataReceivedMutex](std::shared_ptr ls) - { - leaseSet = ls; - std::unique_lock l1(newDataReceivedMutex); - newDataReceived.notify_all (); - }); - if (newDataReceived.wait_for (l, std::chrono::seconds (SUBSCRIPTION_REQUEST_TIMEOUT)) == std::cv_status::timeout) - { - LogPrint (eLogError, "Addressbook: Subscription LeaseSet request timeout expired"); - i2p::client::context.GetSharedLocalDestination ()->CancelDestinationRequest (m_Ident, false); // don't notify, because we know it already - return false; - } - } - if (!leaseSet) { - /* still no leaseset found */ LogPrint (eLogError, "Addressbook: LeaseSet for address ", url.host, " not found"); return false; - } - if (m_Etag.empty() && m_LastModified.empty()) { + } + if (m_Etag.empty() && m_LastModified.empty()) + { m_Book.GetEtag (m_Ident, m_Etag, m_LastModified); LogPrint (eLogDebug, "Addressbook: Loaded for ", url.host, ": ETag: ", m_Etag, ", Last-Modified: ", m_LastModified); } - /* save url parts for later use */ - std::string dest_host = url.host; - int dest_port = url.port ? url.port : 80; - /* create http request & send it */ + // create http request & send it i2p::http::HTTPReq req; req.AddHeader("Host", dest_host); req.AddHeader("User-Agent", "Wget/1.11.4"); @@ -877,15 +859,14 @@ namespace client req.AddHeader("If-None-Match", m_Etag); if (!m_LastModified.empty()) req.AddHeader("If-Modified-Since", m_LastModified); - /* convert url to relative */ + // convert url to relative url.schema = ""; url.host = ""; req.uri = url.to_string(); req.version = "HTTP/1.1"; - auto stream = i2p::client::context.GetSharedLocalDestination ()->CreateStream (leaseSet, dest_port); std::string request = req.to_string(); stream->Send ((const uint8_t *) request.data(), request.length()); - /* read response */ + // read response std::string response; uint8_t recv_buf[4096]; bool end = false; @@ -910,7 +891,7 @@ namespace client // process remaining buffer while (size_t len = stream->ReadSome (recv_buf, sizeof(recv_buf))) response.append ((char *)recv_buf, len); - /* parse response */ + // parse response i2p::http::HTTPRes res; int res_head_len = res.parse(response); if (res_head_len < 0) @@ -923,7 +904,7 @@ namespace client LogPrint(eLogError, "Addressbook: Incomplete http response from ", dest_host, ", interrupted by timeout"); return false; } - /* assert: res_head_len > 0 */ + // assert: res_head_len > 0 response.erase(0, res_head_len); if (res.code == 304) { @@ -946,7 +927,7 @@ namespace client LogPrint(eLogError, "Addressbook: Response size mismatch, expected: ", len, ", got: ", response.length(), "bytes"); return false; } - /* assert: res.code == 200 */ + // assert: res.code == 200 auto it = res.headers.find("ETag"); if (it != res.headers.end()) m_Etag = it->second; it = res.headers.find("Last-Modified"); From 85b78dfb9b600ebf2834c8e08929df052a48a4ac Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 9 Nov 2022 18:26:16 -0500 Subject: [PATCH 212/219] call stream request callback after CreateStream --- libi2pd/Destination.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/libi2pd/Destination.cpp b/libi2pd/Destination.cpp index 581fc733..c39a2533 100644 --- a/libi2pd/Destination.cpp +++ b/libi2pd/Destination.cpp @@ -1096,7 +1096,13 @@ namespace client } auto leaseSet = FindLeaseSet (dest); if (leaseSet) - streamRequestComplete(CreateStream (leaseSet, port)); + { + auto stream = CreateStream (leaseSet, port); + GetService ().post ([streamRequestComplete, stream]() + { + streamRequestComplete(stream); + }); + } else { auto s = GetSharedFromThis (); From 78357baca4fdb2ec421e6dbf49f33b96f3bc99d6 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 11 Nov 2022 13:31:54 -0500 Subject: [PATCH 213/219] sync AcceptStream --- libi2pd/Streaming.cpp | 20 ++++++++++++++++++++ libi2pd/Streaming.h | 3 ++- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/libi2pd/Streaming.cpp b/libi2pd/Streaming.cpp index 63cf20a2..9ba236d7 100644 --- a/libi2pd/Streaming.cpp +++ b/libi2pd/Streaming.cpp @@ -1362,6 +1362,26 @@ namespace stream acceptor (stream); } + std::shared_ptr StreamingDestination::AcceptStream (int timeout) + { + std::shared_ptr stream; + std::condition_variable streamAccept; + std::mutex streamAcceptMutex; + std::unique_lock l(streamAcceptMutex); + AcceptOnce ( + [&streamAccept, &streamAcceptMutex, &stream](std::shared_ptr s) + { + stream = s; + std::unique_lock l(streamAcceptMutex); + streamAccept.notify_all (); + }); + if (timeout) + streamAccept.wait_for (l, std::chrono::seconds (timeout)); + else + streamAccept.wait (l); + return stream; + } + void StreamingDestination::HandlePendingIncomingTimer (const boost::system::error_code& ecode) { if (ecode != boost::asio::error::operation_aborted) diff --git a/libi2pd/Streaming.h b/libi2pd/Streaming.h index 1662f0e4..105977e8 100644 --- a/libi2pd/Streaming.h +++ b/libi2pd/Streaming.h @@ -279,7 +279,8 @@ namespace stream bool IsAcceptorSet () const { return m_Acceptor != nullptr; }; void AcceptOnce (const Acceptor& acceptor); void AcceptOnceAcceptor (std::shared_ptr stream, Acceptor acceptor, Acceptor prev); - + std::shared_ptr AcceptStream (int timeout = 0); // sync + std::shared_ptr GetOwner () const { return m_Owner; }; void SetOwner (std::shared_ptr owner) { m_Owner = owner; }; uint16_t GetLocalPort () const { return m_LocalPort; }; From 39b39965965db923226b5ce530d96e65231a9ccc Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 14 Nov 2022 15:29:16 -0500 Subject: [PATCH 214/219] added notbob.i2p to jump services --- libi2pd_client/HTTPProxy.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libi2pd_client/HTTPProxy.cpp b/libi2pd_client/HTTPProxy.cpp index 1673de5a..eb6d29b5 100644 --- a/libi2pd_client/HTTPProxy.cpp +++ b/libi2pd_client/HTTPProxy.cpp @@ -36,12 +36,14 @@ namespace proxy { "reg.i2p", "stats.i2p", "identiguy.i2p", + "notbob.i2p" }; static const std::map jumpservices = { { "reg.i2p", "http://shx5vqsw7usdaunyzr2qmes2fq37oumybpudrd4jjj4e4vk4uusa.b32.i2p/jump/" }, { "identiguy.i2p", "http://3mzmrus2oron5fxptw7hw2puho3bnqmw2hqy7nw64dsrrjwdilva.b32.i2p/cgi-bin/query?hostname=" }, { "stats.i2p", "http://7tbay5p4kzeekxvyvbf6v7eauazemsnnl2aoyqhg5jzpr5eke7tq.b32.i2p/cgi-bin/jump.cgi?a=" }, + { "notbob.i2p", "http://nytzrhrjjfsutowojvxi7hphesskpqqr65wpistz6wa7cpajhp7a.b32.i2p/cgi-bin/jump.cgi?q=" } }; static const char *pageHead = From cf005821d7351eb885c35b39d2f6ba2ac6649539 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Sun, 20 Nov 2022 08:16:00 +0300 Subject: [PATCH 215/219] [i18n] pull translation updates Signed-off-by: R4SAS --- i18n/Chinese.cpp | 4 ++-- i18n/German.cpp | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/i18n/Chinese.cpp b/i18n/Chinese.cpp index 8c5ec3bc..2f6c14e2 100644 --- a/i18n/Chinese.cpp +++ b/i18n/Chinese.cpp @@ -123,8 +123,8 @@ namespace chinese // language namespace {"Run peer test", "运行节点测试"}, {"Decline transit tunnels", "拒绝中转隧道"}, {"Accept transit tunnels", "允许中转隧道"}, - {"Cancel graceful shutdown", "取消优雅地离线"}, - {"Start graceful shutdown", "优雅地离线"}, + {"Cancel graceful shutdown", "取消平滑关闭"}, + {"Start graceful shutdown", "平滑关闭"}, {"Force shutdown", "强制停止"}, {"Reload external CSS styles", "重载外部 CSS 样式"}, {"Note: any action done here are not persistent and not changes your config files.", "注意: 此处完成的任何操作都不是永久的,不会更改您的配置文件。"}, diff --git a/i18n/German.cpp b/i18n/German.cpp index f114bf8e..489a93a7 100644 --- a/i18n/German.cpp +++ b/i18n/German.cpp @@ -31,7 +31,6 @@ namespace german // language namespace static std::map strings { - {"Purple I2P Webconsole", "Purple-I2P-Webkonsole"}, {"KiB", "KiB"}, {"MiB", "MiB"}, {"GiB", "GiB"}, @@ -41,6 +40,7 @@ namespace german // language namespace {"established", "hergestellt"}, {"unknown", "Unbekannt"}, {"exploratory", "erforschend"}, + {"Purple I2P Webconsole", "Purple I2P-Webkonsole"}, {"i2pd webconsole", "i2pd-Webkonsole"}, {"Main page", "Startseite"}, {"Router commands", "Routerbefehle"}, @@ -49,8 +49,8 @@ namespace german // language namespace {"Tunnels", "Tunnel"}, {"Transit Tunnels", "Transittunnel"}, {"Transports", "Transporte"}, - {"I2P tunnels", "I2P-Tunnel"}, - {"SAM sessions", "SAM-Sitzungen"}, + {"I2P tunnels", "I2P Tunnel"}, + {"SAM sessions", "SAM Sitzungen"}, {"ERROR", "FEHLER"}, {"OK", "OK"}, {"Testing", "Testen"}, From 8df4082d6fef5afa64384cf3b5d9e7291a34364a Mon Sep 17 00:00:00 2001 From: R4SAS Date: Sun, 20 Nov 2022 08:40:03 +0300 Subject: [PATCH 216/219] [cmake] Use std::atomic on PowerPC inside boost (#1726) Signed-off-by: R4SAS --- build/CMakeLists.txt | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/build/CMakeLists.txt b/build/CMakeLists.txt index 0c40d5a9..11036f16 100644 --- a/build/CMakeLists.txt +++ b/build/CMakeLists.txt @@ -172,6 +172,13 @@ if(WITH_THREADSANITIZER) endif() +# Enable usage of STD's Atomic instead of Boost's on PowerPC +# For more information refer to https://github.com/PurpleI2P/i2pd/issues/1726#issuecomment-1306335111 +if(ARCHITECTURE MATCHES "ppc") + add_definitions(-DBOOST_SP_USE_STD_ATOMIC) +endif() + + # libraries set(THREADS_PREFER_PTHREAD_FLAG ON) find_package(Threads REQUIRED) From 9f59ff2df4286bd130d4a8fd85d938d681974b4c Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 20 Nov 2022 08:56:05 -0500 Subject: [PATCH 217/219] 2.44.0 --- ChangeLog | 30 ++++++++++++++++++++++++++++++ contrib/i2pd.conf | 10 +++++----- contrib/rpm/i2pd-git.spec | 5 ++++- contrib/rpm/i2pd.spec | 5 ++++- debian/changelog | 6 ++++++ libi2pd/version.h | 4 ++-- 6 files changed, 51 insertions(+), 9 deletions(-) diff --git a/ChangeLog b/ChangeLog index 95bc2c46..a5d12e8b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,36 @@ # for this file format description, # see https://github.com/olivierlacan/keep-a-changelog +## [2.44.0] - 2022-11-21 +### Added +- SSL connection for server I2P tunnels +- Localization to Italian and Spanish +- SSU2 through SOCKS5 UDP proxy +- Reload tunnels through web console +- SSU2 send immediate ack request flag +- SSU2 send and verify path challenge +- Configurable ssu2.mtu4 and ssu2.mtu6 +### Changed +- SSU2 is enbaled and SSU is disabled by default +- Separate network status and error +- Random selection between NTCP2 and SSU2 priority +- Added notbob.i2p to jump services +- Remove DoNotTrack flag from HTTP Request header +- Skip addresshelper page if destination was not changed +- SSU2 allow different ports from RelayReponse and HolePunch +- SSU2 resend PeerTest msg 1 and msg 2 +- SSU2 Send Retry instead SessionCreated if clock skew detected +### Fixed +- Long HTTP headers for HTTP proxy and HTTP server tunnel +- SSU2 resends and resend limits +- Crash at startup if addressbook is disabled +- NTCP2 ipv6 connection through SOCKS5 proxy +- SSU2 SessionRequest with zero token +- SSU2 MTU less than 1280 +- SSU2 port=1 +- Incorrect addresses from network interfaces +- Definitions for Darwin PPC; do not use pthread_setname_np + ## [2.43.0] - 2022-08-22 ### Added - Complete SSU2 implementation diff --git a/contrib/i2pd.conf b/contrib/i2pd.conf index d0a9e141..b281ce8f 100644 --- a/contrib/i2pd.conf +++ b/contrib/i2pd.conf @@ -75,7 +75,7 @@ ipv4 = true ## Enable communication through ipv6 ipv6 = false -## Enable SSU transport (default = true) +## Enable SSU transport ssu = false ## Bandwidth configuration @@ -105,10 +105,10 @@ ssu = false # port = 4567 [ssu2] -## Enable SSU2 transport (default = false for 2.43.0) -enabled = true -## Publish address in RouterInfo (default = false for 2.43.0) -published = true +## Enable SSU2 transport +# enabled = true +## Publish address in RouterInfo +# published = true ## Port for incoming connections (default is global port option value or port + 1 if SSU is enabled) # port = 4567 diff --git a/contrib/rpm/i2pd-git.spec b/contrib/rpm/i2pd-git.spec index 95a64402..b0d8151f 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.43.0 +Version: 2.44.0 Release: git%{git_hash}%{?dist} Summary: I2P router written in C++ Conflicts: i2pd @@ -158,6 +158,9 @@ getent passwd i2pd >/dev/null || \ %changelog +* Mon Nov 21 2022 orignal - 2.44.0 +- update to 2.44.0 + * Mon Aug 22 2022 orignal - 2.43.0 - update to 2.43.0 diff --git a/contrib/rpm/i2pd.spec b/contrib/rpm/i2pd.spec index eda2914e..ce4854fe 100644 --- a/contrib/rpm/i2pd.spec +++ b/contrib/rpm/i2pd.spec @@ -1,5 +1,5 @@ Name: i2pd -Version: 2.43.0 +Version: 2.44.0 Release: 1%{?dist} Summary: I2P router written in C++ Conflicts: i2pd-git @@ -155,6 +155,9 @@ getent passwd i2pd >/dev/null || \ %changelog +* Mon Nov 21 2022 orignal - 2.44.0 +- update to 2.44.0 + * Mon Aug 22 2022 orignal - 2.43.0 - update to 2.43.0 diff --git a/debian/changelog b/debian/changelog index 78ce9472..864a9d81 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +i2pd (2.44.0-1) unstable; urgency=medium + + * updated to version 2.44.0/0.9.56 + + -- orignal Mon, 21 Nov 2022 16:00:00 +0000 + i2pd (2.43.0-1) unstable; urgency=medium * updated to version 2.43.0/0.9.55 diff --git a/libi2pd/version.h b/libi2pd/version.h index 5b6925cc..94d14403 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 43 +#define I2PD_VERSION_MINOR 44 #define I2PD_VERSION_MICRO 0 #define I2PD_VERSION_PATCH 0 #ifdef GITVER @@ -31,7 +31,7 @@ #define I2P_VERSION_MAJOR 0 #define I2P_VERSION_MINOR 9 -#define I2P_VERSION_MICRO 55 +#define I2P_VERSION_MICRO 56 #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) From ba3cee1cf1724a74c6f6d6d60e83d324e5af04cd Mon Sep 17 00:00:00 2001 From: R4SAS Date: Sun, 20 Nov 2022 22:05:39 +0300 Subject: [PATCH 218/219] 2.44.0 Signed-off-by: R4SAS --- ChangeLog | 10 +++++----- contrib/rpm/i2pd-git.spec | 2 +- contrib/rpm/i2pd.spec | 2 +- debian/changelog | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/ChangeLog b/ChangeLog index a5d12e8b..9f3faf11 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,7 +1,7 @@ # for this file format description, # see https://github.com/olivierlacan/keep-a-changelog -## [2.44.0] - 2022-11-21 +## [2.44.0] - 2022-11-20 ### Added - SSL connection for server I2P tunnels - Localization to Italian and Spanish @@ -9,7 +9,7 @@ - Reload tunnels through web console - SSU2 send immediate ack request flag - SSU2 send and verify path challenge -- Configurable ssu2.mtu4 and ssu2.mtu6 +- Configurable ssu2.mtu4 and ssu2.mtu6 ### Changed - SSU2 is enbaled and SSU is disabled by default - Separate network status and error @@ -29,7 +29,7 @@ - SSU2 MTU less than 1280 - SSU2 port=1 - Incorrect addresses from network interfaces -- Definitions for Darwin PPC; do not use pthread_setname_np +- Definitions for Darwin PPC; do not use pthread_setname_np ## [2.43.0] - 2022-08-22 ### Added @@ -441,7 +441,7 @@ ### Added - Client auth flag for b33 address ### Changed -- Remove incoming NTCP2 session from pending list when established +- Remove incoming NTCP2 session from pending list when established - Handle errors for NTCP2 SessionConfrimed send ### Fixed - Failure to start on Windows XP @@ -745,7 +745,7 @@ ### Added - Datagram i2p tunnels - Unique local addresses for server tunnels -- Configurable list of reseed servers and initial addressbook +- Configurable list of reseed servers and initial addressbook - Configurable netid - Initial iOS support diff --git a/contrib/rpm/i2pd-git.spec b/contrib/rpm/i2pd-git.spec index b0d8151f..9183b529 100644 --- a/contrib/rpm/i2pd-git.spec +++ b/contrib/rpm/i2pd-git.spec @@ -158,7 +158,7 @@ getent passwd i2pd >/dev/null || \ %changelog -* Mon Nov 21 2022 orignal - 2.44.0 +* Sun Nov 20 2022 orignal - 2.44.0 - update to 2.44.0 * Mon Aug 22 2022 orignal - 2.43.0 diff --git a/contrib/rpm/i2pd.spec b/contrib/rpm/i2pd.spec index ce4854fe..16734f3f 100644 --- a/contrib/rpm/i2pd.spec +++ b/contrib/rpm/i2pd.spec @@ -155,7 +155,7 @@ getent passwd i2pd >/dev/null || \ %changelog -* Mon Nov 21 2022 orignal - 2.44.0 +* Sun Nov 20 2022 orignal - 2.44.0 - update to 2.44.0 * Mon Aug 22 2022 orignal - 2.43.0 diff --git a/debian/changelog b/debian/changelog index 864a9d81..accbf46a 100644 --- a/debian/changelog +++ b/debian/changelog @@ -2,7 +2,7 @@ i2pd (2.44.0-1) unstable; urgency=medium * updated to version 2.44.0/0.9.56 - -- orignal Mon, 21 Nov 2022 16:00:00 +0000 + -- orignal Sun, 20 Nov 2022 19:00:00 +0000 i2pd (2.43.0-1) unstable; urgency=medium From 9e02c99db50394d9f4c453d77c119e6aa9a671b3 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 22 Nov 2022 15:40:48 -0500 Subject: [PATCH 219/219] check and limit LeaseSet's buffer size --- libi2pd/LeaseSet.cpp | 23 +++++++++++++---------- libi2pd/NetDb.cpp | 10 ++++++++++ 2 files changed, 23 insertions(+), 10 deletions(-) diff --git a/libi2pd/LeaseSet.cpp b/libi2pd/LeaseSet.cpp index 387527e3..12b064b5 100644 --- a/libi2pd/LeaseSet.cpp +++ b/libi2pd/LeaseSet.cpp @@ -37,14 +37,7 @@ namespace data void LeaseSet::Update (const uint8_t * buf, size_t len, bool verifySignature) { - if (len > m_BufferLen) - { - auto oldBuffer = m_Buffer; - m_Buffer = new uint8_t[len]; - delete[] oldBuffer; - } - memcpy (m_Buffer, buf, len); - m_BufferLen = len; + SetBuffer (buf, len); ReadFromBuffer (false, verifySignature); } @@ -264,8 +257,18 @@ namespace data void LeaseSet::SetBuffer (const uint8_t * buf, size_t len) { - if (m_Buffer) delete[] m_Buffer; - m_Buffer = new uint8_t[len]; + if (len > MAX_LS_BUFFER_SIZE) + { + LogPrint (eLogError, "LeaseSet: Buffer is too long ", len); + len = MAX_LS_BUFFER_SIZE; + } + if (m_Buffer && len > m_BufferLen) + { + delete[] m_Buffer; + m_Buffer = nullptr; + } + if (!m_Buffer) + m_Buffer = new uint8_t[len]; m_BufferLen = len; memcpy (m_Buffer, buf, len); } diff --git a/libi2pd/NetDb.cpp b/libi2pd/NetDb.cpp index 5abe2fdc..193bfdc3 100644 --- a/libi2pd/NetDb.cpp +++ b/libi2pd/NetDb.cpp @@ -749,6 +749,11 @@ namespace data { const uint8_t * buf = m->GetPayload (); size_t len = m->GetSize (); + if (len < DATABASE_STORE_HEADER_SIZE) + { + LogPrint (eLogError, "NetDb: Database store msg is too short ", len, ". Dropped"); + return; + } IdentHash ident (buf + DATABASE_STORE_KEY_OFFSET); if (ident.IsZero ()) { @@ -759,6 +764,11 @@ namespace data size_t offset = DATABASE_STORE_HEADER_SIZE; if (replyToken) { + if (len < offset + 36) // 32 + 4 + { + LogPrint (eLogError, "NetDb: Database store msg with reply token is too short ", len, ". Dropped"); + return; + } auto deliveryStatus = CreateDeliveryStatusMsg (replyToken); uint32_t tunnelID = bufbe32toh (buf + offset); offset += 4;
" + << tr("Streams") + << "
StreamID" // Stream closing button column + << "DestinationSentReceivedOutInBufRTTWindowStatus