Skip to content

Commit 944c542

Browse files
committed
net_processing: drop Misbehavior for unconnecting headers
This misbehavior was originally intended to prevent bandwidth wastage due to actually observed very broken (but likely non-malicious) nodes that respond to GETHEADERS with a response unrelated to the request, triggering a request cycle. This has however largely been addressed by the previous commit, which causes non-connecting HEADERS that are received while a GETHEADERS has not been responded to, to be ignored, as long as they do not time out (2 minutes). With that, the specific misbehavior is largely irrelevant (for inbound peers, it is now harmless; for outbound peers, the eviction logic will eventually kick them out if they're not keeping up with headers at all).
1 parent 9f66ac7 commit 944c542

File tree

2 files changed

+8
-62
lines changed

2 files changed

+8
-62
lines changed

src/net_processing.cpp

Lines changed: 2 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -130,8 +130,6 @@ static constexpr double BLOCK_DOWNLOAD_TIMEOUT_BASE = 1;
130130
static constexpr double BLOCK_DOWNLOAD_TIMEOUT_PER_PEER = 0.5;
131131
/** Maximum number of headers to announce when relaying blocks with headers message.*/
132132
static const unsigned int MAX_BLOCKS_TO_ANNOUNCE = 8;
133-
/** Maximum number of unconnecting headers announcements before DoS score */
134-
static const int MAX_NUM_UNCONNECTING_HEADERS_MSGS = 10;
135133
/** Minimum blocks required to signal NODE_NETWORK_LIMITED */
136134
static const unsigned int NODE_NETWORK_LIMITED_MIN_BLOCKS = 288;
137135
/** Window, in blocks, for connecting to NODE_NETWORK_LIMITED peers */
@@ -382,9 +380,6 @@ struct Peer {
382380
/** Whether we've sent our peer a sendheaders message. **/
383381
std::atomic<bool> m_sent_sendheaders{false};
384382

385-
/** Length of current-streak of unconnecting headers announcements */
386-
int m_num_unconnecting_headers_msgs GUARDED_BY(NetEventsInterface::g_msgproc_mutex){0};
387-
388383
/** When to potentially disconnect peer for stalling headers download */
389384
std::chrono::microseconds m_headers_sync_timeout GUARDED_BY(NetEventsInterface::g_msgproc_mutex){0us};
390385

@@ -2719,37 +2714,24 @@ arith_uint256 PeerManagerImpl::GetAntiDoSWorkThreshold()
27192714
* announcement.
27202715
*
27212716
* We'll send a getheaders message in response to try to connect the chain.
2722-
*
2723-
* The peer can send up to MAX_NUM_UNCONNECTING_HEADERS_MSGS in a row that
2724-
* don't connect before given DoS points.
2725-
*
2726-
* Once a headers message is received that is valid and does connect,
2727-
* m_num_unconnecting_headers_msgs gets reset back to 0.
27282717
*/
27292718
void PeerManagerImpl::HandleFewUnconnectingHeaders(CNode& pfrom, Peer& peer,
27302719
const std::vector<CBlockHeader>& headers)
27312720
{
2732-
peer.m_num_unconnecting_headers_msgs++;
27332721
// Try to fill in the missing headers.
27342722
const CBlockIndex* best_header{WITH_LOCK(cs_main, return m_chainman.m_best_header)};
27352723
if (MaybeSendGetHeaders(pfrom, GetLocator(best_header), peer)) {
2736-
LogPrint(BCLog::NET, "received header %s: missing prev block %s, sending getheaders (%d) to end (peer=%d, m_num_unconnecting_headers_msgs=%d)\n",
2724+
LogPrint(BCLog::NET, "received header %s: missing prev block %s, sending getheaders (%d) to end (peer=%d)\n",
27372725
headers[0].GetHash().ToString(),
27382726
headers[0].hashPrevBlock.ToString(),
27392727
best_header->nHeight,
2740-
pfrom.GetId(), peer.m_num_unconnecting_headers_msgs);
2728+
pfrom.GetId());
27412729
}
27422730

27432731
// Set hashLastUnknownBlock for this peer, so that if we
27442732
// eventually get the headers - even from a different peer -
27452733
// we can use this peer to download.
27462734
WITH_LOCK(cs_main, UpdateBlockAvailability(pfrom.GetId(), headers.back().GetHash()));
2747-
2748-
// The peer may just be broken, so periodically assign DoS points if this
2749-
// condition persists.
2750-
if (peer.m_num_unconnecting_headers_msgs % MAX_NUM_UNCONNECTING_HEADERS_MSGS == 0) {
2751-
Misbehaving(peer, 20, strprintf("%d non-connecting headers", peer.m_num_unconnecting_headers_msgs));
2752-
}
27532735
}
27542736

27552737
bool PeerManagerImpl::CheckHeadersAreContinuous(const std::vector<CBlockHeader>& headers) const
@@ -2991,11 +2973,6 @@ void PeerManagerImpl::HeadersDirectFetchBlocks(CNode& pfrom, const Peer& peer, c
29912973
void PeerManagerImpl::UpdatePeerStateForReceivedHeaders(CNode& pfrom, Peer& peer,
29922974
const CBlockIndex& last_header, bool received_new_header, bool may_have_more_headers)
29932975
{
2994-
if (peer.m_num_unconnecting_headers_msgs > 0) {
2995-
LogPrint(BCLog::NET, "peer=%d: resetting m_num_unconnecting_headers_msgs (%d -> 0)\n", pfrom.GetId(), peer.m_num_unconnecting_headers_msgs);
2996-
}
2997-
peer.m_num_unconnecting_headers_msgs = 0;
2998-
29992976
LOCK(cs_main);
30002977
CNodeState *nodestate = State(pfrom.GetId());
30012978

@@ -3122,8 +3099,6 @@ void PeerManagerImpl::ProcessHeadersMessage(CNode& pfrom, Peer& peer,
31223099
// special logic for handling headers that don't connect, as this
31233100
// could be benign.
31243101
HandleFewUnconnectingHeaders(pfrom, peer, headers);
3125-
} else {
3126-
Misbehaving(peer, 10, "invalid header received");
31273102
}
31283103
return;
31293104
}

test/functional/p2p_sendheaders.py

Lines changed: 6 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -71,19 +71,13 @@
7171
Expect: no response.
7272
7373
Part 5: Test handling of headers that don't connect.
74-
a. Repeat 10 times:
74+
a. Repeat 100 times:
7575
1. Announce a header that doesn't connect.
7676
Expect: getheaders message
7777
2. Send headers chain.
7878
Expect: getdata for the missing blocks, tip update.
79-
b. Then send 9 more headers that don't connect.
79+
b. Then send 99 more headers that don't connect.
8080
Expect: getheaders message each time.
81-
c. Announce a header that does connect.
82-
Expect: no response.
83-
d. Announce 49 headers that don't connect.
84-
Expect: getheaders message each time.
85-
e. Announce one more that doesn't connect.
86-
Expect: disconnect.
8781
"""
8882
from test_framework.blocktools import create_block, create_coinbase
8983
from test_framework.messages import CInv
@@ -526,7 +520,8 @@ def test_nonnull_locators(self, test_node, inv_node):
526520
# First we test that receipt of an unconnecting header doesn't prevent
527521
# chain sync.
528522
expected_hash = tip
529-
for i in range(10):
523+
NUM_HEADERS = 100
524+
for i in range(NUM_HEADERS):
530525
self.log.debug("Part 5.{}: starting...".format(i))
531526
test_node.last_message.pop("getdata", None)
532527
blocks = []
@@ -550,15 +545,14 @@ def test_nonnull_locators(self, test_node, inv_node):
550545
blocks = []
551546
# Now we test that if we repeatedly don't send connecting headers, we
552547
# don't go into an infinite loop trying to get them to connect.
553-
MAX_NUM_UNCONNECTING_HEADERS_MSGS = 10
554-
for _ in range(MAX_NUM_UNCONNECTING_HEADERS_MSGS + 1):
548+
for _ in range(NUM_HEADERS + 1):
555549
blocks.append(create_block(tip, create_coinbase(height), block_time))
556550
blocks[-1].solve()
557551
tip = blocks[-1].sha256
558552
block_time += 1
559553
height += 1
560554

561-
for i in range(1, MAX_NUM_UNCONNECTING_HEADERS_MSGS):
555+
for i in range(1, NUM_HEADERS):
562556
with p2p_lock:
563557
test_node.last_message.pop("getheaders", None)
564558
# Send an empty header as a failed response to the received getheaders
@@ -569,29 +563,6 @@ def test_nonnull_locators(self, test_node, inv_node):
569563
test_node.send_header_for_blocks([blocks[i]])
570564
test_node.wait_for_getheaders(block_hash=expected_hash)
571565

572-
# Next header will connect, should re-set our count:
573-
test_node.send_header_for_blocks([blocks[0]])
574-
expected_hash = blocks[0].sha256
575-
576-
# Remove the first two entries (blocks[1] would connect):
577-
blocks = blocks[2:]
578-
579-
# Now try to see how many unconnecting headers we can send
580-
# before we get disconnected. Should be 5*MAX_NUM_UNCONNECTING_HEADERS_MSGS
581-
for i in range(5 * MAX_NUM_UNCONNECTING_HEADERS_MSGS - 1):
582-
# Send a header that doesn't connect, check that we get a getheaders.
583-
test_node.send_header_for_blocks([])
584-
test_node.send_header_for_blocks([blocks[i % len(blocks)]])
585-
test_node.wait_for_getheaders(block_hash=expected_hash)
586-
587-
# Eventually this stops working.
588-
test_node.send_header_for_blocks([blocks[-1]])
589-
590-
# Should get disconnected
591-
test_node.wait_for_disconnect()
592-
593-
self.log.info("Part 5: success!")
594-
595566
# Finally, check that the inv node never received a getdata request,
596567
# throughout the test
597568
assert "getdata" not in inv_node.last_message

0 commit comments

Comments
 (0)