aboutsummaryrefslogtreecommitdiff
path: root/src/net_processing.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/net_processing.cpp')
-rw-r--r--src/net_processing.cpp54
1 files changed, 54 insertions, 0 deletions
diff --git a/src/net_processing.cpp b/src/net_processing.cpp
index 315d2ac5cd..9c4544df21 100644
--- a/src/net_processing.cpp
+++ b/src/net_processing.cpp
@@ -155,6 +155,13 @@ static constexpr uint32_t MAX_GETCFHEADERS_SIZE = 2000;
static constexpr size_t MAX_PCT_ADDR_TO_SEND = 23;
/** The maximum number of address records permitted in an ADDR message. */
static constexpr size_t MAX_ADDR_TO_SEND{1000};
+/** The maximum rate of address records we're willing to process on average. Can be bypassed using
+ * the NetPermissionFlags::Addr permission. */
+static constexpr double MAX_ADDR_RATE_PER_SECOND{0.1};
+/** The soft limit of the address processing token bucket (the regular MAX_ADDR_RATE_PER_SECOND
+ * based increments won't go above this, but the MAX_ADDR_TO_SEND increment following GETADDR
+ * is exempt from this limit. */
+static constexpr size_t MAX_ADDR_PROCESSING_TOKEN_BUCKET{MAX_ADDR_TO_SEND};
// Internal stuff
namespace {
@@ -233,6 +240,15 @@ struct Peer {
std::atomic_bool m_wants_addrv2{false};
/** Whether this peer has already sent us a getaddr message. */
bool m_getaddr_recvd{false};
+ /** Number of addr messages that can be processed from this peer. Start at 1 to
+ * permit self-announcement. */
+ double m_addr_token_bucket{1.0};
+ /** When m_addr_token_bucket was last updated */
+ std::chrono::microseconds m_addr_token_timestamp{GetTime<std::chrono::microseconds>()};
+ /** Total number of addresses that were dropped due to rate limiting. */
+ std::atomic<uint64_t> m_addr_rate_limited{0};
+ /** Total number of addresses that were processed (excludes rate limited ones). */
+ std::atomic<uint64_t> m_addr_processed{0};
/** Set of txids to reconsider once their parent transactions have been accepted **/
std::set<uint256> m_orphan_work_set GUARDED_BY(g_cs_orphans);
@@ -1239,6 +1255,8 @@ bool PeerManagerImpl::GetNodeStateStats(NodeId nodeid, CNodeStateStats& stats) c
}
stats.m_ping_wait = ping_wait;
+ stats.m_addr_processed = peer->m_addr_processed.load();
+ stats.m_addr_rate_limited = peer->m_addr_rate_limited.load();
return true;
}
@@ -2583,6 +2601,9 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
// Get recent addresses
m_connman.PushMessage(&pfrom, CNetMsgMaker(greatest_common_version).Make(NetMsgType::GETADDR));
peer->m_getaddr_sent = true;
+ // When requesting a getaddr, accept an additional MAX_ADDR_TO_SEND addresses in response
+ // (bypassing the MAX_ADDR_PROCESSING_TOKEN_BUCKET limit).
+ peer->m_addr_token_bucket += MAX_ADDR_TO_SEND;
}
if (!pfrom.IsInboundConn()) {
@@ -2777,11 +2798,34 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
std::vector<CAddress> vAddrOk;
int64_t nNow = GetAdjustedTime();
int64_t nSince = nNow - 10 * 60;
+
+ // Update/increment addr rate limiting bucket.
+ const auto current_time = GetTime<std::chrono::microseconds>();
+ if (peer->m_addr_token_bucket < MAX_ADDR_PROCESSING_TOKEN_BUCKET) {
+ // Don't increment bucket if it's already full
+ const auto time_diff = std::max(current_time - peer->m_addr_token_timestamp, 0us);
+ const double increment = CountSecondsDouble(time_diff) * MAX_ADDR_RATE_PER_SECOND;
+ peer->m_addr_token_bucket = std::min<double>(peer->m_addr_token_bucket + increment, MAX_ADDR_PROCESSING_TOKEN_BUCKET);
+ }
+ peer->m_addr_token_timestamp = current_time;
+
+ const bool rate_limited = !pfrom.HasPermission(NetPermissionFlags::Addr);
+ uint64_t num_proc = 0;
+ uint64_t num_rate_limit = 0;
+ Shuffle(vAddr.begin(), vAddr.end(), FastRandomContext());
for (CAddress& addr : vAddr)
{
if (interruptMsgProc)
return;
+ // Apply rate limiting.
+ if (rate_limited) {
+ if (peer->m_addr_token_bucket < 1.0) {
+ ++num_rate_limit;
+ continue;
+ }
+ peer->m_addr_token_bucket -= 1.0;
+ }
// We only bother storing full nodes, though this may include
// things which we would not make an outbound connection to, in
// part because we may make feeler connections to them.
@@ -2795,6 +2839,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
// Do not process banned/discouraged addresses beyond remembering we received them
continue;
}
+ ++num_proc;
bool fReachable = IsReachable(addr);
if (addr.nTime > nSince && !peer->m_getaddr_sent && vAddr.size() <= 10 && addr.IsRoutable()) {
// Relay to a limited number of other nodes
@@ -2804,6 +2849,15 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
if (fReachable)
vAddrOk.push_back(addr);
}
+ peer->m_addr_processed += num_proc;
+ peer->m_addr_rate_limited += num_rate_limit;
+ LogPrint(BCLog::NET, "Received addr: %u addresses (%u processed, %u rate-limited) from peer=%d%s\n",
+ vAddr.size(),
+ num_proc,
+ num_rate_limit,
+ pfrom.GetId(),
+ fLogIPs ? ", peeraddr=" + pfrom.addr.ToString() : "");
+
m_addrman.Add(vAddrOk, pfrom.addr, 2 * 60 * 60);
if (vAddr.size() < 1000) peer->m_getaddr_sent = false;
if (pfrom.IsAddrFetchConn()) {