Repository navigation
net: learn an addr-fetch getaddr reply, then disconnect - #1101
Conversation
There was a problem hiding this comment.
Review
The addrv2 path for a reply of 2..=1000 addresses does what this PR claims. Sending getaddr on an addr-fetch session credits MAX_ADDR_TO_SEND, learn_addrv2 runs, then request_disconnect with ban score 0, and that multi-address message is not relayed. Non-addr-fetch peers never take the credit or the new disconnect. addrfetch_learns_the_getaddr_reply_then_disconnects fails on master: the old punish_disconnect returns before learn_addrv2 and sets the ban score, so learned > 1 and ban_score == 0 both fail.
Leaving these as comments. The 2..=1000 fix is the Core getaddr behavior this commit is for.
| Severity | Location | Finding |
|---|---|---|
| Medium | crates/rbitcoin-net/src/peer.rs:3036 |
The live addrv2 (18385 bytes) trace is still dropped. That payload is 1414 IPv4 records (3 + 1414 * 13). n > MAX_ADDR_TO_SEND still bans and returns before learn_addrv2. A Core seed caps a reply at 1000, so keep the cap; the cited trace is the size check, and the new test sends exactly 1000. |
| Medium | crates/rbitcoin-net/src/peer.rs:3009 |
A v1 addr reply still never reaches AddrMan. on_addr_list only disconnects. Peers that answer getaddr with addr are no longer banned and still contribute nothing. The v1 half of the test asserts stop and ban_score == 0 and does not read the book. |
| Medium | crates/rbitcoin-net/src/peer.rs:3016 |
Disconnect and the relay skip share n > 1 on a single message. After the new credit, a stream of one-address addrv2 messages is learned and falls through into the neighbor relay loop, and the session stays up until a larger message or the 300s addr-fetch timeout. Core disconnects on vAddr.size() > 1 as well, and only relays when the message has at most 10 addresses with a recent nTime. This relay path has neither check. One credit plus the 0.1 token/s refill bounds it. |
| Low | crates/rbitcoin-net/src/peer_tests.rs:5013 |
learned > 1 passes if 2 of 1000 are stored. The test never registers a second wants_addrv2 peer, so a relay regression stays green. |
credit_getaddr_reply is only reached from maybe_queue_addrfetch_getaddr, and end_addrfetch_on_reply is false unless conn_type is AddrFetch. n == 1 still stays connected, which is Core's self-announce exception.
Review follow-up. The wait had no deadline, so a proxy that never answered held run_p2p before catch-up and RPC for good. It now gives up after PROXY_SEED_WAIT (180 s) and the empty book takes the existing awaiting_dialable path. It also ended on "book non-empty and no addr-fetch session live", which a stored one-address self-announce can satisfy. PeerHub now counts addr-fetch getaddr replies learned (more than one address, bumped only in learn_addrfetch_reply), and the wait ends when that count rises. Seeds are re-queued only while no addr-fetch session is live. Stacked on the addr-fetch learn fix (reardencode#1101): without it no seed reply is learned and the count never rises. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Thanks. Addressed in
|
An addr-fetch session (the --proxy DNS seeds, -seednode) that got more than one address back called punish_disconnect and returned before learn_addrv2, so the reply never reached AddrMan and the seed took a full ban score. The getaddr also never credited the token bucket, so even a learned reply would have kept one address. Follow Core ProcessMessage ADDR/ADDRV2: sending getaddr adds MAX_ADDR_TO_SEND tokens, the reply is learned, and the addr-fetch session then ends with request_disconnect and no misbehavior. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review follow-up. A v1 addr reply to an addr-fetch getaddr was only a disconnect and never reached AddrMan; it is now converted and learned. An addr-fetch session no longer relays what it learns: Core sets m_getaddr_sent and does not relay a getaddr reply, and a run of one-address addrv2 messages fell through to the neighbor relay. learn_addrfetch_reply is the one path for both. The test checks at least 900 of the 1000 addresses are learned, that a wants_addrv2 neighbor gets nothing relayed, that a one-address self-announce is learned without ending the session, and that the v1 reply reaches the book. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
3e05721 to
507bda9
Compare
Review follow-up. The wait had no deadline, so a proxy that never answered held run_p2p before catch-up and RPC for good. It now gives up after PROXY_SEED_WAIT (180 s) and the empty book takes the existing awaiting_dialable path. It also ended on "book non-empty and no addr-fetch session live", which a stored one-address self-announce can satisfy. PeerHub now counts addr-fetch getaddr replies learned (more than one address, bumped only in learn_addrfetch_reply), and the wait ends when that count rises. Seeds are re-queued only while no addr-fetch session is live. Stacked on the addr-fetch learn fix (reardencode#1101): without it no seed reply is learned and the count never rises. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
Review
The holes from the last review are fixed on 507bda95.
An addr-fetch getaddr credits MAX_ADDR_TO_SEND, then both addrv2 and v1 addr go through learn_addrfetch_reply and return before the neighbor relay. Learn runs before request_disconnect. More than one address ends the session with ban score 0. A one-address self-announce is learned and the session stays up. Non-addr-fetch addrv2 still learns and relays. Non-addr-fetch v1 is still ignored. A count above MAX_ADDR_TO_SEND still calls misbehaving and returns before learn, which is the right place for the 1414-record message.
addrfetch_learns_the_getaddr_reply_then_disconnects now requires at least 900 of 1000 stored, an empty neighbor channel, a learned v1 reply, ban score 0, and a one-address self-announce that leaves the session up. On master the n > 1 path still punish-disconnects before learn, so that test fails there.
Problem
An addr-fetch session (the
--proxyDNS seeds,-seednode) that receives more than one address callspunish_disconnectand returns beforelearn_addrv2. The reply the node asked for never reaches AddrMan, and the seed takes a full ban score. Thegetaddralso never credits the token bucket, so a learned reply would still be cut to one address. A v1addrreply never reaches AddrMan at all.(An earlier version of this description cited a live
received: addrv2 (18385 bytes)trace. As review pointed out, that message is overMAX_ADDR_TO_SEND, so the size check still drops it, as Core does. It is not the case this PR fixes.)Fix (Core
ProcessMessageADDR/ADDRV2)getaddraddsMAX_ADDR_TO_SENDtokens (m_addr_token_bucket += MAX_ADDR_TO_SEND).learn_addrfetch_replyis the one path foraddrv2and for v1addr(converted): the addresses are learned and not relayed (Core setsm_getaddr_sent), and more than one address ends the session withrequest_disconnectand no misbehavior. A one-address self-announce is learned and the session stays up.MAX_ADDR_TO_SENDsize check is unchanged.addrfrom a non-addr-fetch peer is still not learned, as onmaster.Test
addrfetch_learns_the_getaddr_reply_then_disconnects(crates/rbitcoin-net/tests/peer/mod.rs) drivesmaybe_queue_addrfetch_getaddrand thenhandle_peer_frameon live addr-fetch sessions, with awants_addrv2neighbor attached:addrv2reply: at least 900 learned, session stopped,ban_score == 0, nothing relayed to the neighboraddrreply: reaches the book, session stopped,ban_score == 0, nothing relayedOn
masterit fails withlearned 0. Hand mutations were checked: relaying from addr-fetch fails "an addr-fetch reply is not relayed", and not learning v1 fails "a v1 getaddr reply is learned".Part of making a fresh
--proxynode bootstrap, together with #1102 (stacked on this), #1103, #1104 and #1105.🤖 Generated with Claude Code