mirror of
https://github.com/PurpleI2P/i2pd.git
synced 2026-03-30 17:16:05 +00:00
ban by IP list
This commit is contained in:
@@ -1047,9 +1047,9 @@ namespace transport
|
||||
|
||||
auto addr = m_RemoteEndpoint.address ().is_v4 () ? ri1->GetNTCP2V4Address () :
|
||||
(i2p::util::net::IsYggdrasilAddress (m_RemoteEndpoint.address ()) ? ri1->GetYggdrasilAddress () : ri1->GetNTCP2V6Address ());
|
||||
if (!addr || memcmp (m_Establisher->m_RemoteStaticKey, addr->s, 32))
|
||||
if (!addr)
|
||||
{
|
||||
LogPrint (eLogError, "NTCP2: Wrong static key in SessionConfirmed");
|
||||
LogPrint (eLogError, "NTCP2: Address not found in SessionConfirmed");
|
||||
Terminate ();
|
||||
return;
|
||||
}
|
||||
@@ -1069,6 +1069,14 @@ namespace transport
|
||||
SendTerminationAndTerminate (eNTCP2Banned);
|
||||
return;
|
||||
}
|
||||
if (memcmp (m_Establisher->m_RemoteStaticKey, addr->s, 32))
|
||||
{
|
||||
LogPrint (eLogError, "NTCP2: Wrong static key in SessionConfirmed");
|
||||
if (addr->IsPublishedNTCP2 ())
|
||||
i2p::transport::transports.AddBan (m_RemoteEndpoint.address ());
|
||||
Terminate ();
|
||||
return;
|
||||
}
|
||||
// TODO: process options block
|
||||
|
||||
// ready to communicate
|
||||
@@ -1936,7 +1944,7 @@ namespace transport
|
||||
if (!ec)
|
||||
{
|
||||
LogPrint (eLogDebug, "NTCP2: Connected from ", ep);
|
||||
if (!i2p::transport::transports.IsInReservedRange(ep.address ()))
|
||||
if (!i2p::transport::transports.IsInReservedRange(ep.address ()) && !i2p::transport::transports.IsBanned(ep.address ()))
|
||||
{
|
||||
if (m_PendingIncomingSessions.emplace (ep.address (), conn).second)
|
||||
{
|
||||
@@ -1948,7 +1956,7 @@ namespace transport
|
||||
LogPrint (eLogInfo, "NTCP2: Incoming session from ", ep.address (), " is already pending");
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "NTCP2: Incoming connection from invalid IP ", ep.address ());
|
||||
LogPrint (eLogError, "NTCP2: Incoming connection from invalid or banned IP ", ep.address ());
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "NTCP2: Connected from error ", ec.message ());
|
||||
@@ -1983,8 +1991,9 @@ namespace transport
|
||||
if (!ec)
|
||||
{
|
||||
LogPrint (eLogDebug, "NTCP2: Connected from ", ep);
|
||||
if (!i2p::transport::transports.IsInReservedRange(ep.address ()) ||
|
||||
i2p::util::net::IsYggdrasilAddress (ep.address ()))
|
||||
if ((!i2p::transport::transports.IsInReservedRange(ep.address ()) ||
|
||||
i2p::util::net::IsYggdrasilAddress (ep.address ())) &&
|
||||
!i2p::transport::transports.IsBanned(ep.address ()))
|
||||
{
|
||||
if (m_PendingIncomingSessions.emplace (ep.address (), conn).second)
|
||||
{
|
||||
@@ -1996,7 +2005,7 @@ namespace transport
|
||||
LogPrint (eLogInfo, "NTCP2: Incoming session from ", ep.address (), " is already pending");
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "NTCP2: Incoming connection from invalid IP ", ep.address ());
|
||||
LogPrint (eLogError, "NTCP2: Incoming connection from invalid or banned IP ", ep.address ());
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "NTCP2: Connected from error ", ec.message ());
|
||||
|
||||
199
libi2pd/SSU2.cpp
199
libi2pd/SSU2.cpp
@@ -225,40 +225,40 @@ namespace transport
|
||||
std::lock_guard<std::mutex> l(m_ConnectedRecentlyMutex);
|
||||
auto it = m_ConnectedRecently.find (ep);
|
||||
if (it != m_ConnectedRecently.end ())
|
||||
{
|
||||
{
|
||||
if (i2p::util::GetSecondsSinceEpoch () <= it->second + (max ? SSU2_MAX_HOLE_PUNCH_EXPIRATION : SSU2_MIN_HOLE_PUNCH_EXPIRATION))
|
||||
return true;
|
||||
else if (max)
|
||||
m_ConnectedRecently.erase (it);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
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_MAX_HOLE_PUNCH_EXPIRATION) return;
|
||||
std::lock_guard<std::mutex> l(m_ConnectedRecentlyMutex);
|
||||
auto [it, added] = m_ConnectedRecently.try_emplace (ep, ts);
|
||||
if (!added && ts > it->second)
|
||||
it->second = ts; // renew timestamp of existing endpoint
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void SSU2Server::AdjustTimeOffset (int64_t offset, std::shared_ptr<const i2p::data::IdentityEx> from)
|
||||
{
|
||||
if (offset)
|
||||
{
|
||||
{
|
||||
if (m_PendingTimeOffset) // one more
|
||||
{
|
||||
if (m_PendingTimeOffsetFrom && from &&
|
||||
{
|
||||
if (m_PendingTimeOffsetFrom && from &&
|
||||
m_PendingTimeOffsetFrom->GetIdentHash ().GetLL()[0] != from->GetIdentHash ().GetLL()[0]) // from different routers
|
||||
{
|
||||
{
|
||||
if (std::abs (m_PendingTimeOffset - offset) < SSU2_CLOCK_SKEW)
|
||||
{
|
||||
{
|
||||
offset = (m_PendingTimeOffset + offset)/2; // average
|
||||
LogPrint (eLogWarning, "SSU2: Clock adjusted by ", offset, " seconds");
|
||||
i2p::util::AdjustTimeOffset (offset);
|
||||
}
|
||||
}
|
||||
else
|
||||
LogPrint (eLogWarning, "SSU2: Time offsets are too different. Clock not adjusted");
|
||||
m_PendingTimeOffset = 0;
|
||||
@@ -268,18 +268,18 @@ namespace transport
|
||||
LogPrint (eLogWarning, "SSU2: Time offsets from same router. Clock not adjusted");
|
||||
}
|
||||
else
|
||||
{
|
||||
m_PendingTimeOffset = offset; // first
|
||||
{
|
||||
m_PendingTimeOffset = offset; // first
|
||||
m_PendingTimeOffsetFrom = from;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
{
|
||||
m_PendingTimeOffset = 0; // reset
|
||||
m_PendingTimeOffsetFrom = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
@@ -289,14 +289,14 @@ namespace transport
|
||||
socket.close ();
|
||||
socket.open (localEndpoint.protocol ());
|
||||
if (localEndpoint.address ().is_v6 ())
|
||||
#if !defined(__HAIKU__)
|
||||
#if !defined(__HAIKU__)
|
||||
socket.set_option (boost::asio::ip::v6_only (true));
|
||||
#else
|
||||
{
|
||||
LogPrint (eLogWarning, "SSU2: Socket option IPV6_V6ONLY is not supported");
|
||||
m_IsForcedFirewalled6 = true; // IPV6_V6ONLY is not supported, always Firewalled for ipv6
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
uint64_t bufferSize = i2p::context.GetBandwidthLimit() * 1024 / 5; // max lag = 200ms
|
||||
bufferSize = std::max(SSU2_SOCKET_MIN_BUFFER_SIZE, std::min(bufferSize, SSU2_SOCKET_MAX_BUFFER_SIZE));
|
||||
@@ -377,9 +377,9 @@ namespace transport
|
||||
m_PacketsPool.ReleaseMt (packet);
|
||||
Receive (socket);
|
||||
return;
|
||||
}
|
||||
}
|
||||
packet->len = bytes_transferred;
|
||||
|
||||
|
||||
boost::system::error_code ec;
|
||||
size_t moreBytes = socket.available (ec);
|
||||
if (!ec && moreBytes)
|
||||
@@ -387,7 +387,7 @@ namespace transport
|
||||
std::list<Packet *> packets;
|
||||
packets.push_back (packet);
|
||||
while (moreBytes && packets.size () < SSU2_MAX_NUM_PACKETS_PER_BATCH)
|
||||
{
|
||||
{
|
||||
packet = m_PacketsPool.AcquireMt ();
|
||||
packet->len = socket.receive_from (boost::asio::buffer (packet->buf, SSU2_MAX_PACKET_SIZE), packet->from, 0, ec);
|
||||
if (!ec)
|
||||
@@ -410,7 +410,7 @@ namespace transport
|
||||
InsertToReceivedPacketsQueue (packets);
|
||||
}
|
||||
else
|
||||
InsertToReceivedPacketsQueue (packet);
|
||||
InsertToReceivedPacketsQueue (packet);
|
||||
Receive (socket);
|
||||
}
|
||||
else
|
||||
@@ -462,7 +462,7 @@ namespace transport
|
||||
}
|
||||
if (empty)
|
||||
boost::asio::post (GetService (), [this]() { HandleReceivedPacketsQueue (); });
|
||||
}
|
||||
}
|
||||
|
||||
void SSU2Server::InsertToReceivedPacketsQueue (std::list<Packet *>& packets)
|
||||
{
|
||||
@@ -478,12 +478,12 @@ namespace transport
|
||||
LogPrint (eLogError, "SSU2: Received queue size ", queueSize, " exceeds max size ", SSU2_MAX_RECEIVED_QUEUE_SIZE);
|
||||
m_PacketsPool.ReleaseMt (packets);
|
||||
queueSize = 0; // invoke processing just in case
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!queueSize)
|
||||
boost::asio::post (GetService (), [this]() { HandleReceivedPacketsQueue (); });
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void SSU2Server::HandleReceivedPacketsQueue ()
|
||||
{
|
||||
std::list<Packet *> receivedPackets;
|
||||
@@ -492,18 +492,18 @@ namespace transport
|
||||
m_ReceivedPacketsQueue.swap (receivedPackets);
|
||||
}
|
||||
HandleReceivedPackets (std::move (receivedPackets));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool SSU2Server::AddSession (std::shared_ptr<SSU2Session> session)
|
||||
{
|
||||
if (session)
|
||||
{
|
||||
if (m_Sessions.emplace (session->GetConnID (), session).second)
|
||||
{
|
||||
{
|
||||
if (session->GetState () != eSSU2SessionStatePeerTest)
|
||||
AddSessionByRouterHash (session);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -514,7 +514,7 @@ namespace transport
|
||||
if (it != m_Sessions.end ())
|
||||
{
|
||||
if (it->second->GetState () != eSSU2SessionStatePeerTest)
|
||||
{
|
||||
{
|
||||
auto ident = it->second->GetRemoteIdentity ();
|
||||
if (ident)
|
||||
{
|
||||
@@ -522,7 +522,7 @@ namespace transport
|
||||
auto it1 = m_SessionsByRouterHash.find (ident->GetIdentHash ());
|
||||
if (it1 != m_SessionsByRouterHash.end () && it->second == it1->second.lock ())
|
||||
m_SessionsByRouterHash.erase (it1);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (m_LastSession == it->second)
|
||||
m_LastSession = nullptr;
|
||||
@@ -533,8 +533,8 @@ namespace transport
|
||||
void SSU2Server::RequestRemoveSession (uint64_t connID)
|
||||
{
|
||||
boost::asio::post (GetService (), [connID, this]() { RemoveSession (connID); });
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void SSU2Server::AddSessionByRouterHash (std::shared_ptr<SSU2Session> session)
|
||||
{
|
||||
if (session)
|
||||
@@ -551,17 +551,17 @@ namespace transport
|
||||
oldSession = ret.first->second.lock ();
|
||||
// update session
|
||||
ret.first->second = session;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (oldSession && oldSession != session)
|
||||
{
|
||||
{
|
||||
// session already exists
|
||||
LogPrint (eLogWarning, "SSU2: Session to ", ident->GetIdentHash ().ToBase64 (), " already exists");
|
||||
// move unsent msgs to new session
|
||||
oldSession->MoveSendQueue (session);
|
||||
// terminate existing
|
||||
boost::asio::post (GetService (), std::bind (&SSU2Session::RequestTermination, oldSession, eSSU2TerminationReasonReplacedByNewSession));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -578,7 +578,7 @@ namespace transport
|
||||
std::lock_guard<std::mutex> l(m_SessionsByRouterHashMutex);
|
||||
auto it = m_SessionsByRouterHash.find (ident);
|
||||
if (it != m_SessionsByRouterHash.end ())
|
||||
{
|
||||
{
|
||||
if (!it->second.expired ())
|
||||
{
|
||||
auto s = it->second.lock ();
|
||||
@@ -586,7 +586,7 @@ namespace transport
|
||||
return s;
|
||||
}
|
||||
m_SessionsByRouterHash.erase (it);
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -647,11 +647,11 @@ namespace transport
|
||||
if (it != m_Relays.end ())
|
||||
{
|
||||
if (!it->second.expired ())
|
||||
{
|
||||
{
|
||||
auto s = it->second.lock ();
|
||||
if (s && s->IsEstablished ())
|
||||
return s;
|
||||
}
|
||||
}
|
||||
m_Relays.erase (it);
|
||||
}
|
||||
return nullptr;
|
||||
@@ -660,7 +660,7 @@ namespace transport
|
||||
bool SSU2Server::AddPeerTest (uint32_t nonce, std::shared_ptr<SSU2Session> aliceSession, uint64_t ts)
|
||||
{
|
||||
return m_PeerTests.emplace (nonce, std::pair{ aliceSession, ts }).second;
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<SSU2Session> SSU2Server::GetPeerTest (uint32_t nonce)
|
||||
{
|
||||
@@ -672,13 +672,13 @@ namespace transport
|
||||
return s;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool SSU2Server::AddRequestedPeerTest (uint32_t nonce, std::shared_ptr<SSU2PeerTestSession> session, uint64_t ts)
|
||||
{
|
||||
return m_RequestedPeerTests.emplace (nonce, std::pair{ session, ts }).second;
|
||||
}
|
||||
|
||||
|
||||
std::shared_ptr<SSU2PeerTestSession> SSU2Server::GetRequestedPeerTest (uint32_t nonce)
|
||||
{
|
||||
auto it = m_RequestedPeerTests.find (nonce);
|
||||
@@ -689,8 +689,8 @@ namespace transport
|
||||
return s;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void SSU2Server::ProcessNextPacket (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint)
|
||||
{
|
||||
if (len < 24) return;
|
||||
@@ -740,7 +740,7 @@ namespace transport
|
||||
break;
|
||||
case eSSU2SessionStateHolePunch:
|
||||
m_LastSession->ProcessFirstIncomingMessage (connID, buf, len); // SessionRequest
|
||||
break;
|
||||
break;
|
||||
case eSSU2SessionStateClosing:
|
||||
m_LastSession->ProcessData (buf, len, senderEndpoint); // we might receive termintaion block
|
||||
if (m_LastSession && m_LastSession->GetState () == eSSU2SessionStateClosing)
|
||||
@@ -769,7 +769,8 @@ namespace transport
|
||||
else
|
||||
it1->second->ProcessRetry (buf, len);
|
||||
}
|
||||
else if (!i2p::transport::transports.IsInReservedRange(senderEndpoint.address ()) && senderEndpoint.port ())
|
||||
else if (!i2p::transport::transports.IsInReservedRange(senderEndpoint.address ()) && senderEndpoint.port () &&
|
||||
!i2p::transport::transports.IsBanned (senderEndpoint.address ()))
|
||||
{
|
||||
// assume new incoming session
|
||||
auto session = std::make_shared<SSU2Session> (*this);
|
||||
@@ -777,7 +778,7 @@ namespace transport
|
||||
session->ProcessFirstIncomingMessage (connID, buf, len);
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "SSU2: Incoming packet received from invalid endpoint ", senderEndpoint);
|
||||
LogPrint (eLogError, "SSU2: Incoming packet received from invalid or banned endpoint ", senderEndpoint);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -875,8 +876,8 @@ namespace transport
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool SSU2Server::CreateSession (std::shared_ptr<const i2p::data::RouterInfo> router,
|
||||
std::shared_ptr<const i2p::data::RouterInfo::Address> address, bool peerTest)
|
||||
{
|
||||
@@ -909,8 +910,8 @@ namespace transport
|
||||
if (CheckPendingOutgoingSession (ep, peerTest)) return false;
|
||||
session->SetRemoteEndpoint (ep);
|
||||
isValidEndpoint = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (peerTest)
|
||||
session->SetOnEstablished ([session]() {session->SendPeerTest (); });
|
||||
|
||||
@@ -944,14 +945,14 @@ namespace transport
|
||||
{
|
||||
auto addr = s->GetAddress ();
|
||||
if (addr && addr->IsIntroducer ())
|
||||
{
|
||||
{
|
||||
s->Introduce (session, it.iTag);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
indices.push_back(i);
|
||||
}
|
||||
}
|
||||
i++;
|
||||
}
|
||||
// we have to start a new session to an introducer
|
||||
@@ -970,9 +971,9 @@ namespace transport
|
||||
// introducer is not expired, because in indices
|
||||
r = i2p::data::netdb.FindRouter (introducer.iH);
|
||||
if (r)
|
||||
{
|
||||
{
|
||||
if (r->IsPublishedOn (i2p::context.GetRouterInfo ().GetCompatibleTransports (false) & // outgoing
|
||||
(i2p::data::RouterInfo::eSSU2V4 | i2p::data::RouterInfo::eSSU2V6)))
|
||||
(i2p::data::RouterInfo::eSSU2V4 | i2p::data::RouterInfo::eSSU2V6)))
|
||||
{
|
||||
relayTag = introducer.iTag;
|
||||
addr = address->IsV6 () ? r->GetSSU2V6Address () : r->GetSSU2V4Address ();
|
||||
@@ -986,27 +987,27 @@ namespace transport
|
||||
{
|
||||
if (i2p::context.SupportsV6 ())
|
||||
addr = r->GetSSU2V6Address ();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (i2p::context.SupportsV4 ())
|
||||
addr = r->GetSSU2V4Address ();
|
||||
}
|
||||
}
|
||||
if (addr && addr->IsIntroducer () && !addr->host.is_unspecified () && addr->port &&
|
||||
!i2p::transport::transports.IsInReservedRange(addr->host))
|
||||
break;
|
||||
else
|
||||
{
|
||||
{
|
||||
// all addresses are invalid, try next introducer
|
||||
relayTag = 0;
|
||||
addr = nullptr;
|
||||
r = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
r = nullptr;
|
||||
}
|
||||
}
|
||||
else if (!i2p::data::IsRouterBanned (introducer.iH))
|
||||
newRouters.push_back (introducer.iH);
|
||||
}
|
||||
@@ -1058,7 +1059,7 @@ namespace transport
|
||||
{
|
||||
auto remoteAddr = session->GetAddress ();
|
||||
if (!remoteAddr || !remoteAddr->IsPeerTesting () ||
|
||||
(v4 && !remoteAddr->IsV4 ()) || (!v4 && !remoteAddr->IsV6 ())) return false;
|
||||
(v4 && !remoteAddr->IsV4 ()) || (!v4 && !remoteAddr->IsV6 ())) return false;
|
||||
if (session->IsEstablished ())
|
||||
boost::asio::post (GetService (), [session]() { session->SendPeerTest (); });
|
||||
else
|
||||
@@ -1096,7 +1097,7 @@ namespace transport
|
||||
else
|
||||
it++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (auto it: m_Sessions)
|
||||
{
|
||||
@@ -1148,7 +1149,7 @@ namespace transport
|
||||
else
|
||||
it++;
|
||||
}
|
||||
|
||||
|
||||
for (auto it = m_IncomingTokens.begin (); it != m_IncomingTokens.end (); )
|
||||
{
|
||||
if (ts > it->second.second)
|
||||
@@ -1171,7 +1172,7 @@ namespace transport
|
||||
it = m_ConnectedRecently.erase (it);
|
||||
else
|
||||
it++;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto it = m_RequestedPeerTests.begin (); it != m_RequestedPeerTests.end ();)
|
||||
{
|
||||
@@ -1190,8 +1191,8 @@ namespace transport
|
||||
else
|
||||
it++;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
m_PacketsPool.CleanUpMt ();
|
||||
m_SentPacketsPool.CleanUp ();
|
||||
m_IncompleteMessagesPool.CleanUp ();
|
||||
@@ -1202,7 +1203,7 @@ namespace transport
|
||||
|
||||
void SSU2Server::ScheduleResend (bool more)
|
||||
{
|
||||
m_ResendTimer.expires_from_now (boost::posix_time::milliseconds (more ?
|
||||
m_ResendTimer.expires_from_now (boost::posix_time::milliseconds (more ?
|
||||
(SSU2_RESEND_CHECK_MORE_TIMEOUT + m_Rng () % SSU2_RESEND_CHECK_MORE_TIMEOUT_VARIANCE):
|
||||
(SSU2_RESEND_CHECK_TIMEOUT + m_Rng () % SSU2_RESEND_CHECK_TIMEOUT_VARIANCE)));
|
||||
m_ResendTimer.async_wait (std::bind (&SSU2Server::HandleResendTimer,
|
||||
@@ -1283,7 +1284,7 @@ namespace transport
|
||||
{
|
||||
std::vector<std::shared_ptr<SSU2Session> > ret;
|
||||
if (maxNumIntroducers <= 0 || m_Sessions.empty ()) return ret;
|
||||
|
||||
|
||||
std::vector<std::shared_ptr<SSU2Session> > eligible;
|
||||
eligible.reserve (m_Sessions.size ()/2);
|
||||
auto ts = i2p::util::GetSecondsSinceEpoch ();
|
||||
@@ -1299,7 +1300,7 @@ namespace transport
|
||||
|
||||
if (eligible.size () <= (size_t)maxNumIntroducers)
|
||||
return eligible;
|
||||
else
|
||||
else
|
||||
std::sample (eligible.begin(), eligible.end(), std::back_inserter(ret), maxNumIntroducers, m_Rng);
|
||||
return ret;
|
||||
}
|
||||
@@ -1316,31 +1317,31 @@ namespace transport
|
||||
if (session)
|
||||
excluded.insert (ident);
|
||||
if (session)
|
||||
{
|
||||
{
|
||||
if (session->IsEstablished () && session->GetRelayTag () && session->IsOutgoing () && // still session with introducer?
|
||||
ts < session->GetCreationTime () + SSU2_TO_INTRODUCER_SESSION_EXPIRATION)
|
||||
{
|
||||
{
|
||||
session->SendKeepAlive ();
|
||||
if (ts < session->GetCreationTime () + SSU2_TO_INTRODUCER_SESSION_DURATION)
|
||||
{
|
||||
if (ts < session->GetCreationTime () + SSU2_TO_INTRODUCER_SESSION_DURATION)
|
||||
{
|
||||
newList.push_back ({ident, session->GetRelayTag ()});
|
||||
if (tag != session->GetRelayTag ())
|
||||
{
|
||||
LogPrint (eLogDebug, "SSU2: Introducer session to ", session->GetIdentHashBase64() , " was replaced. iTag ", tag, "->", session->GetRelayTag ());
|
||||
i2p::context.UpdateSSU2Introducer (ident, v4, session->GetRelayTag (),
|
||||
session->GetCreationTime () + SSU2_TO_INTRODUCER_SESSION_EXPIRATION);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
else
|
||||
{
|
||||
impliedList.push_back ({ident, session->GetRelayTag ()}); // keep in introducers list, but not publish
|
||||
session = nullptr;
|
||||
session = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
session = nullptr;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (!session)
|
||||
i2p::context.RemoveSSU2Introducer (ident, v4);
|
||||
}
|
||||
@@ -1356,12 +1357,12 @@ namespace transport
|
||||
auto session = FindSession (it.first);
|
||||
if (session)
|
||||
{
|
||||
if (std::find_if (newList.begin (), newList.end (),
|
||||
if (std::find_if (newList.begin (), newList.end (),
|
||||
[&ident = it.first](const auto& s){ return ident == s.first; }) == newList.end ())
|
||||
{
|
||||
{
|
||||
sessions.push_back (session);
|
||||
numOldSessions++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
impliedList.clear ();
|
||||
@@ -1369,9 +1370,9 @@ namespace transport
|
||||
|
||||
for (const auto& it : sessions)
|
||||
{
|
||||
uint32_t tag = it->GetRelayTag ();
|
||||
uint32_t tag = it->GetRelayTag ();
|
||||
uint32_t exp = it->GetCreationTime () + SSU2_TO_INTRODUCER_SESSION_EXPIRATION;
|
||||
if (!tag && ts >= exp)
|
||||
if (!tag && ts >= exp)
|
||||
continue; // don't publish expired introducer
|
||||
i2p::data::RouterInfo::Introducer introducer;
|
||||
introducer.iTag = tag;
|
||||
@@ -1393,14 +1394,14 @@ namespace transport
|
||||
if (introducers.size () < SSU2_MAX_NUM_INTRODUCERS || numOldSessions)
|
||||
{
|
||||
// we need to create more sessions with relay tag
|
||||
|
||||
|
||||
// exclude all existing sessions
|
||||
excluded.clear ();
|
||||
{
|
||||
std::lock_guard<std::mutex> l(m_SessionsByRouterHashMutex);
|
||||
for (const auto& [ident, s] : m_SessionsByRouterHash)
|
||||
excluded.insert (ident);
|
||||
}
|
||||
}
|
||||
|
||||
// session about to expire are not counted
|
||||
for (auto i = introducers.size (); i < SSU2_MAX_NUM_INTRODUCERS + numOldSessions; i++)
|
||||
@@ -1544,8 +1545,8 @@ namespace transport
|
||||
void SSU2Server::ChaCha20 (const uint8_t * msg, size_t msgLen, const uint8_t * key, const uint8_t * nonce, uint8_t * out)
|
||||
{
|
||||
m_ChaCha20 (msg, msgLen, key, nonce, out);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
|
||||
@@ -1200,9 +1200,9 @@ namespace transport
|
||||
ri = ri1;
|
||||
|
||||
m_Address = m_RemoteEndpoint.address ().is_v6 () ? ri->GetSSU2V6Address () : ri->GetSSU2V4Address ();
|
||||
if (!m_Address || memcmp (S, m_Address->s, 32))
|
||||
if (!m_Address)
|
||||
{
|
||||
LogPrint (eLogError, "SSU2: Wrong static key in SessionConfirmed from ", i2p::data::GetIdentHashAbbreviation (ri->GetIdentHash ()));
|
||||
LogPrint (eLogError, "SSU2: Address not found in SessionConfirmed from ", i2p::data::GetIdentHashAbbreviation (ri->GetIdentHash ()));
|
||||
return false;
|
||||
}
|
||||
if (m_Address->published && m_RemoteEndpoint.address () != m_Address->host &&
|
||||
@@ -1220,6 +1220,13 @@ namespace transport
|
||||
" and actual endpoint ", m_RemoteEndpoint.address (), " from ", i2p::data::GetIdentHashAbbreviation (ri->GetIdentHash ()));
|
||||
return false;
|
||||
}
|
||||
if (memcmp (S, m_Address->s, 32))
|
||||
{
|
||||
LogPrint (eLogError, "SSU2: Wrong static key in SessionConfirmed from ", i2p::data::GetIdentHashAbbreviation (ri->GetIdentHash ()));
|
||||
if (m_Address->published)
|
||||
i2p::transport::transports.AddBan (m_RemoteEndpoint.address ());
|
||||
return false;
|
||||
}
|
||||
if (!m_Address->published)
|
||||
{
|
||||
if (ri->HasProfile ())
|
||||
|
||||
@@ -187,6 +187,7 @@ namespace transport
|
||||
m_PeerCleanupTimer = new boost::asio::deadline_timer (*m_Service);
|
||||
m_PeerTestTimer = new boost::asio::deadline_timer (*m_Service);
|
||||
m_UpdateBandwidthTimer = new boost::asio::deadline_timer (*m_Service);
|
||||
m_BanListCleanupTimer = std::make_unique<boost::asio::steady_timer>(*m_Service);
|
||||
}
|
||||
|
||||
bool ipv4; i2p::config::GetOption("ipv4", ipv4);
|
||||
@@ -347,12 +348,15 @@ namespace transport
|
||||
m_PeerTestTimer->expires_from_now (boost::posix_time::seconds(PEER_TEST_INTERVAL + m_Rng() % PEER_TEST_INTERVAL_VARIANCE));
|
||||
m_PeerTestTimer->async_wait (std::bind (&Transports::HandlePeerTestTimer, this, std::placeholders::_1));
|
||||
}
|
||||
m_BanListCleanupTimer->expires_after (std::chrono::seconds(BAN_LIST_CLEANUP_INTERVAL + m_Rng () % BAN_LIST_CLEANUP_INTERVAL_VARIANCE));
|
||||
m_BanListCleanupTimer->async_wait (std::bind (&Transports::HandleBanListCleanupTimer, this, std::placeholders::_1));
|
||||
}
|
||||
|
||||
void Transports::Stop ()
|
||||
{
|
||||
if (m_PeerCleanupTimer) m_PeerCleanupTimer->cancel ();
|
||||
if (m_PeerTestTimer) m_PeerTestTimer->cancel ();
|
||||
if (m_BanListCleanupTimer) m_BanListCleanupTimer->cancel ();
|
||||
|
||||
if (m_SSU2Server)
|
||||
{
|
||||
@@ -1076,6 +1080,29 @@ namespace transport
|
||||
}
|
||||
}
|
||||
|
||||
void Transports::HandleBanListCleanupTimer (const boost::system::error_code& ecode)
|
||||
{
|
||||
if (ecode != boost::asio::error::operation_aborted)
|
||||
{
|
||||
if (!m_BanList.empty ())
|
||||
{
|
||||
auto ts = i2p::util::GetMonotonicSeconds ();
|
||||
{
|
||||
std::lock_guard<std::mutex> l(m_BanListMutex);
|
||||
for (auto it = m_BanList.begin (); it != m_BanList.end (); )
|
||||
{
|
||||
if (ts < it->second)
|
||||
it++;
|
||||
else
|
||||
it = m_BanList.erase (it);
|
||||
}
|
||||
}
|
||||
}
|
||||
m_BanListCleanupTimer->expires_after (std::chrono::seconds(BAN_LIST_CLEANUP_INTERVAL + m_Rng () % BAN_LIST_CLEANUP_INTERVAL_VARIANCE));
|
||||
m_BanListCleanupTimer->async_wait (std::bind (&Transports::HandleBanListCleanupTimer, this, std::placeholders::_1));
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Filter>
|
||||
std::shared_ptr<const i2p::data::RouterInfo> Transports::GetRandomPeer (Filter filter) const
|
||||
{
|
||||
@@ -1299,6 +1326,27 @@ namespace transport
|
||||
return IsCheckReserved () && i2p::util::net::IsInReservedRange (host);
|
||||
}
|
||||
|
||||
bool Transports::IsBanned (const boost::asio::ip::address& addr)
|
||||
{
|
||||
std::lock_guard<std::mutex> l(m_BanListMutex);
|
||||
auto it = m_BanList.find (addr);
|
||||
if (it != m_BanList.end ())
|
||||
{
|
||||
if (it->second < i2p::util::GetMonotonicSeconds ())
|
||||
return true;
|
||||
else
|
||||
m_BanList.erase (it);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Transports::AddBan (const boost::asio::ip::address& addr)
|
||||
{
|
||||
auto ts = i2p::util::GetMonotonicSeconds () + IP_BAN_TIME + m_Rng () % IP_BAN_TIME_VARIANCE;
|
||||
std::lock_guard<std::mutex> l(m_BanListMutex);
|
||||
return m_BanList.emplace (addr, ts).second;
|
||||
}
|
||||
|
||||
void InitAddressFromIface ()
|
||||
{
|
||||
bool ipv6; i2p::config::GetOption("ipv6", ipv6);
|
||||
|
||||
@@ -116,8 +116,12 @@ namespace transport
|
||||
const int CHECK_PROFILE_NUM_DELAYED_MESSAGES = 15; // check profile after
|
||||
const int NUM_X25519_PRE_GENERATED_KEYS = 25; // pre-generated x25519 keys pairs
|
||||
|
||||
const int TRAFFIC_SAMPLE_COUNT = 301; // seconds
|
||||
const int IP_BAN_TIME = 1800; // in seconds
|
||||
const int IP_BAN_TIME_VARIANCE = 540; // in seconds
|
||||
const int BAN_LIST_CLEANUP_INTERVAL = 66; // in seconds
|
||||
const int BAN_LIST_CLEANUP_INTERVAL_VARIANCE = 20; // in seconds
|
||||
|
||||
const int TRAFFIC_SAMPLE_COUNT = 301; // seconds
|
||||
struct TrafficSample
|
||||
{
|
||||
uint64_t Timestamp;
|
||||
@@ -190,6 +194,9 @@ namespace transport
|
||||
bool IsCheckReserved () const { return m_CheckReserved; };
|
||||
bool IsInReservedRange (const boost::asio::ip::address& host) const;
|
||||
|
||||
bool IsBanned (const boost::asio::ip::address& addr);
|
||||
bool AddBan (const boost::asio::ip::address& addr);
|
||||
|
||||
private:
|
||||
|
||||
void Run ();
|
||||
@@ -201,6 +208,7 @@ namespace transport
|
||||
void HandlePeerCleanupTimer (const boost::system::error_code& ecode);
|
||||
void HandlePeerTestTimer (const boost::system::error_code& ecode);
|
||||
void HandleUpdateBandwidthTimer (const boost::system::error_code& ecode);
|
||||
void HandleBanListCleanupTimer (const boost::system::error_code& ecode);
|
||||
void UpdateBandwidthValues (int interval, uint32_t& in, uint32_t& out, uint32_t& transit);
|
||||
|
||||
void DetectExternalIP ();
|
||||
@@ -247,6 +255,11 @@ namespace transport
|
||||
i2p::I2NPMessagesHandler m_LoopbackHandler;
|
||||
std::mt19937 m_Rng;
|
||||
|
||||
std::map<boost::asio::ip::address, uint64_t> m_BanList; // ip->expiration time in seconds
|
||||
mutable std::mutex m_BanListMutex;
|
||||
std::unique_ptr<boost::asio::steady_timer> m_BanListCleanupTimer;
|
||||
|
||||
|
||||
public:
|
||||
|
||||
// for HTTP only
|
||||
|
||||
Reference in New Issue
Block a user