Skip to content

Commit 1d1ef2d

Browse files
committed
[net_processing] Defer initializing m_addr_known
Use SetupAddressRelay to only initialize `m_addr_known` as needed. For outbound peers, we initialize the filter before sending our self announcement (not applicable for block-relay-only connections). For inbound peers, we initialize the filter when we get an addr related message (ADDR, ADDRV2, GETADDR). These changes intend to mitigate address blackholes. Since an inbound peer has to send us an addr related message to become eligible as a candidate for addr relay, this should reduce our likelihood of sending them self-announcements.
1 parent 6653fa3 commit 1d1ef2d

File tree

3 files changed

+22
-11
lines changed

3 files changed

+22
-11
lines changed

src/net_processing.cpp

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -224,8 +224,13 @@ struct Peer {
224224

225225
/** A vector of addresses to send to the peer, limited to MAX_ADDR_TO_SEND. */
226226
std::vector<CAddress> m_addrs_to_send;
227-
/** Probabilistic filter of addresses that this peer already knows.
228-
* Used to avoid relaying addresses to this peer more than once. */
227+
/** Probabilistic filter to track recent addr messages relayed with this
228+
* peer. Used to avoid relaying redundant addresses to this peer.
229+
*
230+
* We initialize this filter for outbound peers (other than
231+
* block-relay-only connections) or when an inbound peer sends us an
232+
* address related message (ADDR, ADDRV2, GETADDR).
233+
**/
229234
std::unique_ptr<CRollingBloomFilter> m_addr_known;
230235
/** Whether a getaddr request to this peer is outstanding. */
231236
bool m_getaddr_sent{false};
@@ -258,9 +263,8 @@ struct Peer {
258263
/** Work queue of items requested by this peer **/
259264
std::deque<CInv> m_getdata_requests GUARDED_BY(m_getdata_requests_mutex);
260265

261-
explicit Peer(NodeId id, bool addr_relay)
266+
explicit Peer(NodeId id)
262267
: m_id(id)
263-
, m_addr_known{addr_relay ? std::make_unique<CRollingBloomFilter>(5000, 0.001) : nullptr}
264268
{}
265269
};
266270

@@ -1125,9 +1129,7 @@ void PeerManagerImpl::InitializeNode(CNode *pnode)
11251129
assert(m_txrequest.Count(nodeid) == 0);
11261130
}
11271131
{
1128-
// Addr relay is disabled for outbound block-relay-only peers to
1129-
// prevent adversaries from inferring these links from addr traffic.
1130-
PeerRef peer = std::make_shared<Peer>(nodeid, /* addr_relay = */ !pnode->IsBlockOnlyConn());
1132+
PeerRef peer = std::make_shared<Peer>(nodeid);
11311133
LOCK(m_peer_mutex);
11321134
m_peer_map.emplace_hint(m_peer_map.end(), nodeid, std::move(peer));
11331135
}
@@ -2580,7 +2582,8 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
25802582
UpdatePreferredDownload(pfrom, State(pfrom.GetId()));
25812583
}
25822584

2583-
if (!pfrom.IsInboundConn() && !pfrom.IsBlockOnlyConn()) {
2585+
// Self advertisement & GETADDR logic
2586+
if (!pfrom.IsInboundConn() && SetupAddressRelay(pfrom, *peer)) {
25842587
// For outbound peers, we try to relay our address (so that other
25852588
// nodes can try to find us more quickly, as we have no guarantee
25862589
// that an outbound peer is even aware of how to reach us) and do a
@@ -2589,8 +2592,9 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
25892592
// empty and no one will know who we are, so these mechanisms are
25902593
// important to help us connect to the network.
25912594
//
2592-
// We skip this for block-relay-only peers to avoid potentially leaking
2593-
// information about our block-relay-only connections via address relay.
2595+
// We skip this for block-relay-only peers. We want to avoid
2596+
// potentially leaking addr information and we do not want to
2597+
// indicate to the peer that we will participate in addr relay.
25942598
if (fListen && !m_chainman.ActiveChainstate().IsInitialBlockDownload())
25952599
{
25962600
CAddress addr = GetLocalAddress(&pfrom.addr, pfrom.GetLocalServices());
@@ -2788,10 +2792,11 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
27882792

27892793
s >> vAddr;
27902794

2791-
if (!RelayAddrsWithPeer(*peer)) {
2795+
if (!SetupAddressRelay(pfrom, *peer)) {
27922796
LogPrint(BCLog::NET, "ignoring %s message from %s peer=%d\n", msg_type, pfrom.ConnectionTypeAsString(), pfrom.GetId());
27932797
return;
27942798
}
2799+
27952800
if (vAddr.size() > MAX_ADDR_TO_SEND)
27962801
{
27972802
Misbehaving(pfrom.GetId(), 20, strprintf("%s message size = %u", msg_type, vAddr.size()));
@@ -3725,6 +3730,8 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
37253730
return;
37263731
}
37273732

3733+
SetupAddressRelay(pfrom, *peer);
3734+
37283735
// Only send one GetAddr response per connection to reduce resource waste
37293736
// and discourage addr stamping of INV announcements.
37303737
if (peer->m_getaddr_recvd) {

test/functional/p2p_addr_relay.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,9 @@ def relay_tests(self):
175175
# of the outbound peer which is often sent before the GETADDR response.
176176
assert_equal(inbound_peer.num_ipv4_received, 0)
177177

178+
# Send an empty ADDR message to intialize address relay on this connection.
179+
inbound_peer.send_and_ping(msg_addr())
180+
178181
self.log.info('Check that subsequent addr messages sent from an outbound peer are relayed')
179182
msg2 = self.setup_addr_msg(2)
180183
self.send_addr_msg(full_outbound_peer, msg2, [inbound_peer])

test/functional/test_framework/p2p.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -438,6 +438,7 @@ def on_version(self, message):
438438
self.send_message(msg_sendaddrv2())
439439
self.send_message(msg_verack())
440440
self.nServices = message.nServices
441+
self.send_message(msg_getaddr())
441442

442443
# Connection helper methods
443444

0 commit comments

Comments
 (0)