Merge bitcoin/bitcoin#34997: p2p: Don't participate in addr relay with feelers

b0735336ee p2p: Don't participate in addr relay with feeler connections (Daniela Brozzoni)

Pull request description:

  Feeler connections are short-lived connection made to check that a node is alive, useful for test-before-evict, and for moving addresses from the new to the tried table.

  We currently send a GETADDR message to feelers, but then disconnect before being able to receive a response. This GETADDR is not useful and can be removed.

  I couldn't find any previous discussion about this, but I found PR #22777, that similarly made sure that we don't ask for tx relay to feelers.

  ---

  I noticed this behavior on my peer-observer instance: I would see the number of sent GETADDR messages increase over time, but the number of ADDR messages with >100 addresses received (which are likely GETADDR responses and not self announcements relays) wouldn't increase as much. I later realized that it was my node opening feeler connections, sending a GETADDR, and closing the connection.

  You can see the same behavior using this command - the node is making feeler connections, sending getaddr to them, closing before receiving the addr response:

  ```
  ~ ₿ tail -f ~/.bitcoin/debug.log | grep -E "(Making feeler connection|Added connection to|sending getaddr|feeler connection completed|Received addr: [0-9]{2,} addresses)"

  2026-04-02T13:25:50Z [net] Making feeler connection to xyz.onion:8333
  2026-04-02T13:26:06Z [net] Added connection to xyz.onion:8333 peer=27
  2026-04-02T13:26:08Z [net] sending getaddr (0 bytes) peer=27
  2026-04-02T13:26:08Z [net] feeler connection completed, disconnecting peer=27, peeraddr=xyz.onion:8333
  ```

  On a node that accepts inbounds connections, this command can be used to see in the logs all the nodes that connected, sent a getaddr, and disconnected before receiving a reply. It is possible that these nodes connected to us as a feeler:
  ```
  ~ ₿ cat .bitcoin/debug.log | awk '

    /received: getaddr/ {
        split($0, a, "peer=")
        got_getaddr[a[2]] = $0
    }

    /sending addr/ {
        split($0, a, "peer=")
        sent_addr[a[2]] = 1
    }

    /socket closed/ {
        split($0, a, "peer=")
        id = a[2]

        if (id in got_getaddr && !(id in sent_addr)) {
            print "possible feeler: " got_getaddr[id]
            print "                 " $0
        }

        delete got_getaddr[id]
        delete sent_addr[id]
    }
  '

  possible feeler: 2026-04-01T21:45:13Z [net] received: getaddr (0 bytes) peer=2311974
                   2026-04-01T21:45:13Z [net] socket closed, disconnecting peer=2311974
  possible feeler: 2026-04-02T00:18:58Z [net] received: getaddr (0 bytes) peer=2426389
                   2026-04-02T00:18:58Z [net] socket closed, disconnecting peer=2426389
  ...
  ```

  Then, you can manually inspect one of them:
  ```
  ~ ₿ cat .bitcoin/debug.log | grep -E "peer=2311974"
  2026-04-01T21:45:13Z [net] Added connection peer=2311974
  2026-04-01T21:45:13Z [net] received: version (102 bytes) peer=2311974
  2026-04-01T21:45:13Z [net] sending version (102 bytes) peer=2311974
  2026-04-01T21:45:13Z [net] send version message: version 70016, blocks=943279, txrelay=0, peer=2311974
  2026-04-01T21:45:13Z [net] sending wtxidrelay (0 bytes) peer=2311974
  2026-04-01T21:45:13Z [net] sending sendaddrv2 (0 bytes) peer=2311974
  2026-04-01T21:45:13Z [net] sending verack (0 bytes) peer=2311974
  2026-04-01T21:45:13Z [net] receive version message: /Satoshi:27.0.0/: version 70016, blocks=943279, us=x.x.x.x:8333, txrelay=0, peer=2311974
  2026-04-01T21:45:13Z [net] received: wtxidrelay (0 bytes) peer=2311974
  2026-04-01T21:45:13Z [net] received: sendaddrv2 (0 bytes) peer=2311974
  2026-04-01T21:45:13Z [net] received: verack (0 bytes) peer=2311974
  2026-04-01T21:45:13Z New inbound v1 peer connected: version: 70016, blocks=943279, peer=2311974
  2026-04-01T21:45:13Z [net] sending sendcmpct (9 bytes) peer=2311974
  2026-04-01T21:45:13Z [net] sending ping (8 bytes) peer=2311974
  2026-04-01T21:45:13Z [net] sending getheaders (1029 bytes) peer=2311974
  2026-04-01T21:45:13Z [net] initial getheaders (943278) to peer=2311974 (startheight:943279)
  2026-04-01T21:45:13Z [net] received: getaddr (0 bytes) peer=2311974
  2026-04-01T21:45:13Z [net] Advertising address x.x.x.x:8333 to peer=2311974
  2026-04-01T21:45:13Z [net] socket closed, disconnecting peer=2311974
  2026-04-01T21:45:13Z [net] Resetting socket for peer=2311974
  2026-04-01T21:45:13Z [net] sending addrv2 (24665 bytes) peer=2311974
  2026-04-01T21:45:13Z [net] Cleared nodestate for peer=2311974
  ```

ACKs for top commit:
  0xB10C:
    ACK b0735336ee
  achow101:
    ACK b0735336ee
  andrewtoth:
    ACK b0735336ee
  stratospher:
    ACK b073533. didn't see any addr message from feelers in my node's last 24 hours/it would disconnect before addr message is received. so consistent with today's behaviour.

Tree-SHA512: 1ac220dfd8361c4687399546a0d968d268e447446053fb8b90ba6b987482cc038e2ad94e670f33181d08d6d0c576882328bb5d0a8b8b1175a5e2ec31ff051833
This commit is contained in:
Ava Chow
2026-07-08 11:49:10 -07:00
2 changed files with 12 additions and 2 deletions

View File

@@ -3792,7 +3792,7 @@ void PeerManagerImpl::ProcessMessage(Peer& peer, CNode& pfrom, const std::string
// Attempt to initialize address relay for outbound peers and use result
// to decide whether to send GETADDR, so that we don't send it to
// inbound or outbound block-relay-only peers.
// inbound, feelers, or outbound block-relay-only peers.
bool send_getaddr{false};
if (!pfrom.IsInboundConn()) {
send_getaddr = SetupAddressRelay(pfrom, peer);
@@ -5724,6 +5724,11 @@ bool PeerManagerImpl::SetupAddressRelay(const CNode& node, Peer& peer)
// information of addr traffic to infer the link.
if (node.IsBlockOnlyConn()) return false;
// We don't participate in addr relay with feeler connections because
// they are disconnected shortly after the handshake completes,
// before the node will receive the addr response.
if (node.IsFeelerConn()) return false;
if (!peer.m_addr_relay_enabled.exchange(true)) {
// During version message processing (non-block-relay-only outbound peers)
// or on first addr-related message we have received (inbound peers), initialize

View File

@@ -280,12 +280,17 @@ class AddrTest(BitcoinTestFramework):
tip_header = from_hex(CBlockHeader(), self.nodes[0].getblockheader(self.nodes[0].getbestblockhash(), False))
full_outbound_peer.send_and_ping(msg_headers([tip_header]))
self.log.info('Check that we do not send a getaddr message to a block-relay-only or inbound peer')
self.log.info('Check that we do not send a getaddr message to a block-relay-only, feeler or inbound peer')
block_relay_peer = self.nodes[0].add_outbound_p2p_connection(AddrReceiver(), p2p_idx=1, connection_type="block-relay-only")
block_relay_peer.sync_with_ping()
assert_equal(block_relay_peer.getaddr_received(), False)
block_relay_peer.send_and_ping(msg_headers([tip_header]))
feeler_peer = self.nodes[0].add_outbound_p2p_connection(AddrReceiver(), p2p_idx=2, connection_type="feeler")
# bitcoind closes feeler connections as soon as it receives a version message
assert_equal(feeler_peer.is_connected, False)
assert_equal(feeler_peer.getaddr_received(), False)
inbound_peer = self.nodes[0].add_p2p_connection(AddrReceiver(send_getaddr=False))
inbound_peer.sync_with_ping()
assert_equal(inbound_peer.getaddr_received(), False)