Skip to content

Connect handshake advertises loopback/private addresses to remote peers #2087

@sanity

Description

@sanity

Summary
Nodes started via freenet local keep advertising 127.0.0.1:<port> to remote peers during the connect handshake. Remote peers (e.g. Nova gateway at 5.9.111.215:31337) dutifully try to deliver follow-up messages to that loopback address and fail, which is why SuccessfulPut never makes it back to the publisher in #2086.

Evidence

  • When Nova processed PUT transaction 01KA2R1W285XGJG4M0CNWPNB81, it tried to send SuccessfulPut to peer v6MWKgqKCpsc5rkG at 127.0.0.1:36078 and eventually logged TransportError("failed while establishing connection, reason: max connection attempts reached") (journalctl -u freenet-gateway --since "2025-11-14 21:10" --until "21:20" | grep 01KA2R1W285XGJG4M0CNWPNB81). That loopback address originated in the connect exchange with the publisher.
  • In p2p_protoc::handle_peer_connection_msg (crates/core/src/node/network_bridge/p2p_protoc.rs:1609-1645), we only overwrite sender.peer.addr with the actual TCP/UDP socket when the incoming message’s address is 0.0.0.0 or already matches remote_addr. If the joiner pre-fills from.peer.addr = 127.0.0.1:<port>, we never correct it even though the packets clearly arrive from an external IP.
  • ConnectOp::handle_request (crates/core/src/operations/connect.rs:500-520) passes from.peer.addr straight into RelayState::handle_request as the observed address. RelayState then emits ConnectMsg::ObservedAddress with that same value (lines 194-212) instead of the socket we actually observed in the transport layer. So the joiner keeps telling everyone its address is 127.0.0.1.
  • We only call state.update_observed_address when the joiner’s IP is is_unspecified(), so loopback/private addresses are never replaced even when we learn better information.

Impact

  • Any node started on a loopback-only interface can never receive SuccessfulPut, SuccessfulSub, etc., from remote peers, because those peers will try to connect back to 127.0.0.1.
  • CI/integration tests don’t catch this because all peers run on the same host, so connecting to 127.0.0.1 works.

What needs fixing

  1. When processing inbound messages (handle_peer_connection_msg), always overwrite the sender’s peer.addr with the connection’s remote_addr when the sender’s public key matches the connection, even if they pre-filled loopback/private addresses.
  2. When relaying ConnectMsg::Request, pass the actual socket address observed by the transport to RelayState::handle_request, so the emitted ObservedAddress reflects reality.
  3. Loosen the guard in RelayState::handle_request / JoinerState::update_observed_address so we also replace loopback/private addresses, not only 0.0.0.0.

Fixing this will stop remote peers from trying to call us on 127.0.0.1 and will unblock SuccessfulPut delivery for single-node publishers.

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-networkingArea: Networking, ring protocol, peer discoveryE-mediumExperience needed to fix/implement: Medium / intermediateP-highHigh priorityT-bugType: Something is broken

    Type

    No type

    Projects

    Status

    Done

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions