mirror of
https://github.com/PurpleI2P/i2pd.git
synced 2025-03-22 17:10:32 +01:00
Compare commits
9 commits
6d37f9934f
...
40e5d4c5e3
Author | SHA1 | Date | |
---|---|---|---|
|
40e5d4c5e3 | ||
|
d3630fb2b2 | ||
|
500afe745f | ||
|
26901e2945 | ||
|
64bde69967 | ||
|
ddf30784ec | ||
|
ea14b00d63 | ||
|
f98a310235 | ||
|
32a70562c4 |
8 changed files with 97 additions and 31 deletions
|
@ -122,7 +122,7 @@ namespace transport
|
||||||
err = UPNP_GetValidIGD (m_Devlist, &m_upnpUrls, &m_upnpData, m_NetworkAddr, sizeof (m_NetworkAddr));
|
err = UPNP_GetValidIGD (m_Devlist, &m_upnpUrls, &m_upnpData, m_NetworkAddr, sizeof (m_NetworkAddr));
|
||||||
#endif
|
#endif
|
||||||
m_upnpUrlsInitialized=err!=0;
|
m_upnpUrlsInitialized=err!=0;
|
||||||
if (err == UPNP_IGD_VALID_CONNECTED)
|
if (err == UPNP_IGD_VALID_CONNECTED || err == UPNP_IGD_VALID_NOT_CONNECTED)
|
||||||
{
|
{
|
||||||
#if (MINIUPNPC_API_VERSION < 18)
|
#if (MINIUPNPC_API_VERSION < 18)
|
||||||
err = UPNP_GetExternalIPAddress (m_upnpUrls.controlURL, m_upnpData.first.servicetype, m_externalIPAddress);
|
err = UPNP_GetExternalIPAddress (m_upnpUrls.controlURL, m_upnpData.first.servicetype, m_externalIPAddress);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2013-2020, The PurpleI2P Project
|
* Copyright (c) 2013-2024, The PurpleI2P Project
|
||||||
*
|
*
|
||||||
* This file is part of Purple i2pd project and licensed under BSD3
|
* This file is part of Purple i2pd project and licensed under BSD3
|
||||||
*
|
*
|
||||||
|
@ -25,6 +25,7 @@
|
||||||
#include "RouterContext.h"
|
#include "RouterContext.h"
|
||||||
#include "ClientContext.h"
|
#include "ClientContext.h"
|
||||||
#include "Transports.h"
|
#include "Transports.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
void handle_signal(int sig)
|
void handle_signal(int sig)
|
||||||
{
|
{
|
||||||
|
@ -220,6 +221,7 @@ namespace i2p
|
||||||
|
|
||||||
void DaemonLinux::run ()
|
void DaemonLinux::run ()
|
||||||
{
|
{
|
||||||
|
i2p::util::SetThreadName ("Daemon");
|
||||||
while (running)
|
while (running)
|
||||||
{
|
{
|
||||||
std::this_thread::sleep_for (std::chrono::seconds(1));
|
std::this_thread::sleep_for (std::chrono::seconds(1));
|
||||||
|
|
|
@ -997,7 +997,7 @@ namespace crypto
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
#if defined(LIBRESSL_VERSION_NUMBER)
|
#if defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x4000000fL
|
||||||
std::vector<uint8_t> m(msgLen + 16);
|
std::vector<uint8_t> m(msgLen + 16);
|
||||||
if (msg == buf)
|
if (msg == buf)
|
||||||
{
|
{
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <future>
|
#include <future>
|
||||||
|
#include <boost/asio.hpp>
|
||||||
#include "Identity.h"
|
#include "Identity.h"
|
||||||
|
|
||||||
namespace i2p
|
namespace i2p
|
||||||
|
@ -68,6 +69,11 @@ namespace data
|
||||||
bool IsUseful() const;
|
bool IsUseful() const;
|
||||||
bool IsDuplicated () const { return m_IsDuplicated; };
|
bool IsDuplicated () const { return m_IsDuplicated; };
|
||||||
|
|
||||||
|
const boost::asio::ip::udp::endpoint& GetLastEndpoint () const { return m_LastEndpoint; }
|
||||||
|
void SetLastEndpoint (const boost::asio::ip::udp::endpoint& ep) { m_LastEndpoint = ep; }
|
||||||
|
bool HasLastEndpoint (bool v4) const { return !m_LastEndpoint.address ().is_unspecified () && m_LastEndpoint.port () &&
|
||||||
|
((v4 && m_LastEndpoint.address ().is_v4 ()) || (!v4 && m_LastEndpoint.address ().is_v6 ())); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void UpdateTime ();
|
void UpdateTime ();
|
||||||
|
@ -90,6 +96,8 @@ namespace data
|
||||||
uint32_t m_NumTimesRejected;
|
uint32_t m_NumTimesRejected;
|
||||||
bool m_HasConnected; // successful trusted(incoming or NTCP2) connection
|
bool m_HasConnected; // successful trusted(incoming or NTCP2) connection
|
||||||
bool m_IsDuplicated;
|
bool m_IsDuplicated;
|
||||||
|
// connectivity
|
||||||
|
boost::asio::ip::udp::endpoint m_LastEndpoint; // SSU2 for non-published addresses
|
||||||
};
|
};
|
||||||
|
|
||||||
std::shared_ptr<RouterProfile> GetRouterProfile (const IdentHash& identHash);
|
std::shared_ptr<RouterProfile> GetRouterProfile (const IdentHash& identHash);
|
||||||
|
|
|
@ -216,15 +216,16 @@ namespace transport
|
||||||
return ep.port ();
|
return ep.port ();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SSU2Server::IsConnectedRecently (const boost::asio::ip::udp::endpoint& ep)
|
bool SSU2Server::IsConnectedRecently (const boost::asio::ip::udp::endpoint& ep, bool max)
|
||||||
{
|
{
|
||||||
if (!ep.port () || ep.address ().is_unspecified ()) return false;
|
if (!ep.port () || ep.address ().is_unspecified ()) return false;
|
||||||
|
std::lock_guard<std::mutex> l(m_ConnectedRecentlyMutex);
|
||||||
auto it = m_ConnectedRecently.find (ep);
|
auto it = m_ConnectedRecently.find (ep);
|
||||||
if (it != m_ConnectedRecently.end ())
|
if (it != m_ConnectedRecently.end ())
|
||||||
{
|
{
|
||||||
if (i2p::util::GetSecondsSinceEpoch () <= it->second + SSU2_HOLE_PUNCH_EXPIRATION)
|
if (i2p::util::GetSecondsSinceEpoch () <= it->second + (max ? SSU2_MAX_HOLE_PUNCH_EXPIRATION : SSU2_MIN_HOLE_PUNCH_EXPIRATION))
|
||||||
return true;
|
return true;
|
||||||
else
|
else if (max)
|
||||||
m_ConnectedRecently.erase (it);
|
m_ConnectedRecently.erase (it);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -233,7 +234,8 @@ namespace transport
|
||||||
void SSU2Server::AddConnectedRecently (const boost::asio::ip::udp::endpoint& ep, uint64_t ts)
|
void SSU2Server::AddConnectedRecently (const boost::asio::ip::udp::endpoint& ep, uint64_t ts)
|
||||||
{
|
{
|
||||||
if (!ep.port () || ep.address ().is_unspecified () ||
|
if (!ep.port () || ep.address ().is_unspecified () ||
|
||||||
i2p::util::GetSecondsSinceEpoch () > ts + SSU2_HOLE_PUNCH_EXPIRATION) return;
|
i2p::util::GetSecondsSinceEpoch () > ts + SSU2_MAX_HOLE_PUNCH_EXPIRATION) return;
|
||||||
|
std::lock_guard<std::mutex> l(m_ConnectedRecentlyMutex);
|
||||||
auto [it, added] = m_ConnectedRecently.try_emplace (ep, ts);
|
auto [it, added] = m_ConnectedRecently.try_emplace (ep, ts);
|
||||||
if (!added && ts > it->second)
|
if (!added && ts > it->second)
|
||||||
it->second = ts; // renew timestamp of existing endpoint
|
it->second = ts; // renew timestamp of existing endpoint
|
||||||
|
@ -833,6 +835,29 @@ namespace transport
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool SSU2Server::CheckPendingOutgoingSession (const boost::asio::ip::udp::endpoint& ep, bool peerTest)
|
||||||
|
{
|
||||||
|
auto s = FindPendingOutgoingSession (ep);
|
||||||
|
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]() { s->SendPeerTest (); });
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool SSU2Server::CreateSession (std::shared_ptr<const i2p::data::RouterInfo> router,
|
bool SSU2Server::CreateSession (std::shared_ptr<const i2p::data::RouterInfo> router,
|
||||||
std::shared_ptr<const i2p::data::RouterInfo::Address> address, bool peerTest)
|
std::shared_ptr<const i2p::data::RouterInfo::Address> address, bool peerTest)
|
||||||
{
|
{
|
||||||
|
@ -852,34 +877,28 @@ namespace transport
|
||||||
if (isValidEndpoint)
|
if (isValidEndpoint)
|
||||||
{
|
{
|
||||||
if (i2p::transport::transports.IsInReservedRange(address->host)) return false;
|
if (i2p::transport::transports.IsInReservedRange(address->host)) return false;
|
||||||
auto s = FindPendingOutgoingSession (boost::asio::ip::udp::endpoint (address->host, address->port));
|
if (CheckPendingOutgoingSession (boost::asio::ip::udp::endpoint (address->host, address->port), peerTest)) return false;
|
||||||
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]() { s->SendPeerTest (); });
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto session = std::make_shared<SSU2Session> (*this, router, address);
|
auto session = std::make_shared<SSU2Session> (*this, router, address);
|
||||||
|
if (!isValidEndpoint && router->GetProfile ()->HasLastEndpoint (address->IsV4 ()))
|
||||||
|
{
|
||||||
|
// router doesn't publish endpoint, but we connected before and hole punch might be alive
|
||||||
|
auto ep = router->GetProfile ()->GetLastEndpoint ();
|
||||||
|
if (IsConnectedRecently (ep, false))
|
||||||
|
{
|
||||||
|
if (CheckPendingOutgoingSession (ep, peerTest)) return false;
|
||||||
|
session->SetRemoteEndpoint (ep);
|
||||||
|
isValidEndpoint = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (peerTest)
|
if (peerTest)
|
||||||
session->SetOnEstablished ([session]() {session->SendPeerTest (); });
|
session->SetOnEstablished ([session]() {session->SendPeerTest (); });
|
||||||
|
|
||||||
if (address->UsesIntroducer ())
|
if (isValidEndpoint) // we know endpoint
|
||||||
GetService ().post (std::bind (&SSU2Server::ConnectThroughIntroducer, this, session));
|
|
||||||
else if (isValidEndpoint) // we can't connect without endpoint
|
|
||||||
GetService ().post ([session]() { session->Connect (); });
|
GetService ().post ([session]() { session->Connect (); });
|
||||||
|
else if (address->UsesIntroducer ()) // we don't know endpoint yet
|
||||||
|
GetService ().post (std::bind (&SSU2Server::ConnectThroughIntroducer, this, session));
|
||||||
else
|
else
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -1129,7 +1148,7 @@ namespace transport
|
||||||
|
|
||||||
for (auto it = m_ConnectedRecently.begin (); it != m_ConnectedRecently.end (); )
|
for (auto it = m_ConnectedRecently.begin (); it != m_ConnectedRecently.end (); )
|
||||||
{
|
{
|
||||||
if (ts > it->second + SSU2_HOLE_PUNCH_EXPIRATION)
|
if (ts > it->second + SSU2_MAX_HOLE_PUNCH_EXPIRATION)
|
||||||
it = m_ConnectedRecently.erase (it);
|
it = m_ConnectedRecently.erase (it);
|
||||||
else
|
else
|
||||||
it++;
|
it++;
|
||||||
|
|
|
@ -42,7 +42,8 @@ namespace transport
|
||||||
const int SSU2_KEEP_ALIVE_INTERVAL = 15; // in seconds
|
const int SSU2_KEEP_ALIVE_INTERVAL = 15; // in seconds
|
||||||
const int SSU2_KEEP_ALIVE_INTERVAL_VARIANCE = 4; // in seconds
|
const int SSU2_KEEP_ALIVE_INTERVAL_VARIANCE = 4; // in seconds
|
||||||
const int SSU2_PROXY_CONNECT_RETRY_TIMEOUT = 30; // in seconds
|
const int SSU2_PROXY_CONNECT_RETRY_TIMEOUT = 30; // in seconds
|
||||||
const int SSU2_HOLE_PUNCH_EXPIRATION = 150; // in seconds
|
const int SSU2_MIN_HOLE_PUNCH_EXPIRATION = 45; // in seconds
|
||||||
|
const int SSU2_MAX_HOLE_PUNCH_EXPIRATION = 181; // in seconds
|
||||||
const size_t SSU2_MAX_NUM_PACKETS_PER_BATCH = 64;
|
const size_t SSU2_MAX_NUM_PACKETS_PER_BATCH = 64;
|
||||||
|
|
||||||
class SSU2Server: private i2p::util::RunnableServiceWithWork
|
class SSU2Server: private i2p::util::RunnableServiceWithWork
|
||||||
|
@ -77,7 +78,7 @@ namespace transport
|
||||||
bool UsesProxy () const { return m_IsThroughProxy; };
|
bool UsesProxy () const { return m_IsThroughProxy; };
|
||||||
bool IsSupported (const boost::asio::ip::address& addr) const;
|
bool IsSupported (const boost::asio::ip::address& addr) const;
|
||||||
uint16_t GetPort (bool v4) const;
|
uint16_t GetPort (bool v4) const;
|
||||||
bool IsConnectedRecently (const boost::asio::ip::udp::endpoint& ep);
|
bool IsConnectedRecently (const boost::asio::ip::udp::endpoint& ep, bool max = true);
|
||||||
void AddConnectedRecently (const boost::asio::ip::udp::endpoint& ep, uint64_t ts);
|
void AddConnectedRecently (const boost::asio::ip::udp::endpoint& ep, uint64_t ts);
|
||||||
std::mt19937& GetRng () { return m_Rng; }
|
std::mt19937& GetRng () { return m_Rng; }
|
||||||
bool IsMaxNumIntroducers (bool v4) const { return (v4 ? m_Introducers.size () : m_IntroducersV6.size ()) >= SSU2_MAX_NUM_INTRODUCERS; }
|
bool IsMaxNumIntroducers (bool v4) const { return (v4 ? m_Introducers.size () : m_IntroducersV6.size ()) >= SSU2_MAX_NUM_INTRODUCERS; }
|
||||||
|
@ -147,6 +148,7 @@ namespace transport
|
||||||
void ScheduleResend (bool more);
|
void ScheduleResend (bool more);
|
||||||
void HandleResendTimer (const boost::system::error_code& ecode);
|
void HandleResendTimer (const boost::system::error_code& ecode);
|
||||||
|
|
||||||
|
bool CheckPendingOutgoingSession (const boost::asio::ip::udp::endpoint& ep, bool peerTest);
|
||||||
void ConnectThroughIntroducer (std::shared_ptr<SSU2Session> session);
|
void ConnectThroughIntroducer (std::shared_ptr<SSU2Session> session);
|
||||||
std::vector<std::shared_ptr<SSU2Session> > FindIntroducers (int maxNumIntroducers,
|
std::vector<std::shared_ptr<SSU2Session> > FindIntroducers (int maxNumIntroducers,
|
||||||
bool v4, const std::unordered_set<i2p::data::IdentHash>& excluded);
|
bool v4, const std::unordered_set<i2p::data::IdentHash>& excluded);
|
||||||
|
@ -193,6 +195,7 @@ namespace transport
|
||||||
std::shared_ptr<const i2p::data::IdentityEx> m_PendingTimeOffsetFrom;
|
std::shared_ptr<const i2p::data::IdentityEx> m_PendingTimeOffsetFrom;
|
||||||
std::mt19937 m_Rng;
|
std::mt19937 m_Rng;
|
||||||
std::map<boost::asio::ip::udp::endpoint, uint64_t> m_ConnectedRecently; // endpoint -> last activity time in seconds
|
std::map<boost::asio::ip::udp::endpoint, uint64_t> m_ConnectedRecently; // endpoint -> last activity time in seconds
|
||||||
|
mutable std::mutex m_ConnectedRecentlyMutex;
|
||||||
std::unordered_map<uint32_t, std::pair <std::weak_ptr<SSU2PeerTestSession>, uint64_t > > m_RequestedPeerTests; // nonce->(Alice, timestamp)
|
std::unordered_map<uint32_t, std::pair <std::weak_ptr<SSU2PeerTestSession>, uint64_t > > m_RequestedPeerTests; // nonce->(Alice, timestamp)
|
||||||
std::list<Packet *> m_ReceivedPacketsQueue;
|
std::list<Packet *> m_ReceivedPacketsQueue;
|
||||||
mutable std::mutex m_ReceivedPacketsQueueMutex;
|
mutable std::mutex m_ReceivedPacketsQueueMutex;
|
||||||
|
|
|
@ -226,6 +226,13 @@ namespace transport
|
||||||
if (m_Server.AddPendingOutgoingSession (shared_from_this ()))
|
if (m_Server.AddPendingOutgoingSession (shared_from_this ()))
|
||||||
{
|
{
|
||||||
m_Server.RemoveSession (GetConnID ());
|
m_Server.RemoveSession (GetConnID ());
|
||||||
|
// update endpoint in profile because we know it now
|
||||||
|
auto identity = GetRemoteIdentity ();
|
||||||
|
if (identity)
|
||||||
|
{
|
||||||
|
auto profile = i2p::data::GetRouterProfile (identity->GetIdentHash ());
|
||||||
|
if (profile) profile->SetLastEndpoint (m_RemoteEndpoint);
|
||||||
|
}
|
||||||
// connect
|
// connect
|
||||||
LogPrint (eLogDebug, "SSU2: Connecting after introduction to ", GetIdentHashBase64());
|
LogPrint (eLogDebug, "SSU2: Connecting after introduction to ", GetIdentHashBase64());
|
||||||
Connect ();
|
Connect ();
|
||||||
|
@ -1169,6 +1176,8 @@ namespace transport
|
||||||
" and actual endpoint ", m_RemoteEndpoint.address (), " from ", i2p::data::GetIdentHashAbbreviation (ri->GetIdentHash ()));
|
" and actual endpoint ", m_RemoteEndpoint.address (), " from ", i2p::data::GetIdentHashAbbreviation (ri->GetIdentHash ()));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (!m_Address->published)
|
||||||
|
ri->GetProfile ()->SetLastEndpoint (m_RemoteEndpoint);
|
||||||
SetRemoteIdentity (ri->GetRouterIdentity ());
|
SetRemoteIdentity (ri->GetRouterIdentity ());
|
||||||
AdjustMaxPayloadSize ();
|
AdjustMaxPayloadSize ();
|
||||||
m_Server.AddSessionByRouterHash (shared_from_this ()); // we know remote router now
|
m_Server.AddSessionByRouterHash (shared_from_this ()); // we know remote router now
|
||||||
|
|
|
@ -672,6 +672,31 @@ namespace transport
|
||||||
if (transport & compatibleTransports)
|
if (transport & compatibleTransports)
|
||||||
peer->priority.push_back (transport);
|
peer->priority.push_back (transport);
|
||||||
}
|
}
|
||||||
|
if (peer->priority.empty ())
|
||||||
|
{
|
||||||
|
// try recently connected SSU2 if any
|
||||||
|
auto supportedTransports = context.GetRouterInfo ().GetCompatibleTransports (false) &
|
||||||
|
peer->router->GetCompatibleTransports (false);
|
||||||
|
if (supportedTransports & (i2p::data::RouterInfo::eSSU2V4 | i2p::data::RouterInfo::eSSU2V6))
|
||||||
|
{
|
||||||
|
auto ep = peer->router->GetProfile ()->GetLastEndpoint ();
|
||||||
|
if (!ep.address ().is_unspecified () && ep.port ())
|
||||||
|
{
|
||||||
|
if (ep.address ().is_v4 ())
|
||||||
|
{
|
||||||
|
if ((supportedTransports & i2p::data::RouterInfo::eSSU2V4) &&
|
||||||
|
m_SSU2Server->IsConnectedRecently (ep, false))
|
||||||
|
peer->priority.push_back (i2p::data::RouterInfo::eSSU2V4);
|
||||||
|
}
|
||||||
|
else if (ep.address ().is_v6 ())
|
||||||
|
{
|
||||||
|
if ((supportedTransports & i2p::data::RouterInfo::eSSU2V6) &&
|
||||||
|
m_SSU2Server->IsConnectedRecently (ep))
|
||||||
|
peer->priority.push_back (i2p::data::RouterInfo::eSSU2V6);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Transports::RequestComplete (std::shared_ptr<const i2p::data::RouterInfo> r, const i2p::data::IdentHash& ident)
|
void Transports::RequestComplete (std::shared_ptr<const i2p::data::RouterInfo> r, const i2p::data::IdentHash& ident)
|
||||||
|
|
Loading…
Add table
Reference in a new issue