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.cpp32
1 files changed, 32 insertions, 0 deletions
diff --git a/src/net_processing.cpp b/src/net_processing.cpp
index 315d2ac5cd..8d24b00887 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,11 @@ 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>()};
/** Set of txids to reconsider once their parent transactions have been accepted **/
std::set<uint256> m_orphan_work_set GUARDED_BY(g_cs_orphans);
@@ -2583,6 +2595,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 +2792,28 @@ 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);
for (CAddress& addr : vAddr)
{
if (interruptMsgProc)
return;
+ // Apply rate limiting.
+ if (rate_limited) {
+ if (peer->m_addr_token_bucket < 1.0) break;
+ 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.