Skip to content

net: dial a proxied DNS seed by name - #1100

Merged
reardencode merged 1 commit into
reardencode:masterfrom
portlandhodl:net/proxy-seed-dns-dial
Oct 20, 2026
Merged

reardencode merged 1 commit into
reardencode:masterfrom
portlandhodl:net/proxy-seed-dns-dial

Conversation

@portlandhodl

@portlandhodl portlandhodl commented Oct 20, 2026 •

Copy link
Copy Markdown
Contributor

Problem

With --proxy, a fresh node queues each DNS seed as an addr-fetch dial by host name (queue_proxy_seed_addrfetch). Since e56eb9d, prepare_outbound_session calls DialTarget::net_addr() for every dial, and net_addr() expects a Domain to parse as an overlay NetAddr. A DNS name does not, so every seed dial panics its task:

thread 'tokio-rt-worker' panicked at crates/rbitcoin-net/src/peers.rs:210:18:
DialTarget::Domain is host:port from overlay NetAddr: Encode("bad peer address seed.bitcoin.sipa.be:8333")

Seen on a mainnet host running --proxy 127.0.0.1:9050 --tor-control … --listen-onion.

Fix

  • DialTarget::net_addr(): a Domain that is not an overlay host is the 0.0.0.0:port version_socket identity, which is what the peer row had before e56eb9d.
  • prepare_outbound_session: a Domain connects through Dialer::connect_domain (SOCKS by name). That function already hands .onion / .b32.i2p to connect_net, so overlay dials are unchanged.

Test

service::tests::proxied_dns_seed_dials_by_name_through_socks drives run_outbound_session_with_abort with a Domain addr-fetch through a mock SOCKS5 proxy and asserts that the proxy gets an ATYP-domain CONNECT for seed.example:8333. It fails on master with the panic above.

Local: cargo fmt --check, cargo clippy --workspace --all-targets -D warnings, cargo test --workspace, ./scripts/ci-os-smoke.sh all pass. cargo deny and ast-grep are not installed on this host, so those are left to qc. A signet run through Tor --proxy no longer panics.

Related: fresh --proxy bootstrap

This is one of five PRs that together let a fresh --proxy datadir bootstrap. Each one stands alone against master:

With all five, fresh signet and mainnet datadirs bootstrap through Tor --proxy and start IBD.

🤖 Generated with Claude Code

With --proxy the DNS seeds are queued as addr-fetch dials by host name.
e56eb9d made prepare_outbound_session take DialTarget::net_addr() for
every dial, and net_addr() expected a Domain to parse as an overlay
NetAddr. A DNS name does not, so every seed dial panicked the task.

A Domain that is not an overlay host now keeps the 0.0.0.0:port
identity it had before that change, and the connect goes through
Dialer::connect_domain, which hands overlay hosts to connect_net.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@rearden-grok rearden-grok Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Summary

The patch does what it claims. DialTarget::net_addr() no longer expects every Domain to be an overlay address: a name that does not parse as onion, I2P, or a socket falls back to version_socket() (0.0.0.0:port), and prepare_outbound_session dials Domain targets with Dialer::connect_domain instead of connect_net on that placeholder. Overlay names still round-trip through connect_domain into connect_net (.onion / .b32.i2p, then the existing SOCKS or SAM path). DNS seeds are the only dial_domain caller, and they are queued only when --proxy is set, so this path sends SOCKS ATYP 0x03 and does not resolve locally. The new test’s mock matches Dialer::socks(proxy, false) (method 0x02 plus RFC 1929 user/pass), asserts ATYP domain before the session result, and would not go green on the old expect panic or on a connect that never reached the proxy.

A separate security pass checked the same delta. DialTarget::Domain is built only by from_net (onion or I2P, re-encoded from an already parsed NetAddr) and by dial_domain (compiled-in seeds under --proxy). SOCKS rejects an empty host or one longer than 255 bytes and length-prefixes the name before the port. The shared 0.0.0.0:port identity is not a discourage key (0.0.0.0/8 is skipped), is not an inbound-eviction or full-relay slot key, and unroutable-gossip filters drop it before the address book or addr relay. No correctness or security defect in the diff.

The fast clean exit while a fresh --proxy datadir is still waiting on addr-fetch is the limitation called out in the PR body. It is unchanged by this dial fix.

Issue counts by severity

  • bugs: 0
  • suggestions: 0
  • nits: 0

@reardencode
reardencode merged commit e2af5dd into reardencode:master Oct 20, 2026
18 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants