ban by IP list

This commit is contained in:
orignal
2026-02-06 12:58:16 -05:00
parent 279d59bfce
commit 9080fcfa4d
5 changed files with 187 additions and 109 deletions

View File

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

View File

@@ -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)
{

View File

@@ -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 ())

View File

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

View File

@@ -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