p2p: Mitigate GETADDR fingerprinting by setting address timestamps to a fixed value #33498

pull naiyoma wants to merge 2 commits into bitcoin:master from naiyoma:2025_3/getaddr_timestamp_changes changing 2 files +42 −0
  1. naiyoma commented at 3:21 pm on September 29, 2025: contributor

    TLDR: When a node is connected to multiple networks (e.g., clearnet and Tor), it keeps separate ADDR response caches for each network. These are refreshed about once per day (randomized between 21 and 27 hours). See → https://github.com/bitcoin/bitcoin/blob/master/src/net.cpp#L3519 This is an example of a dual-homed node’s addrman response, with separate caches:

    IPv4 response:

    0{102.130.242.11:8333 : 1741100851}
    1{119.17.151.161:8333 : 1739825443}
    2{ubeirqalc4vj54baszpatvctpohn62hzj7vfnbncy6upa6vywvgewrad.onion:8333 : 1739825443}
    

    Tor response:

    0{102.130.242.11:8333 : 1741100851}
    1{94.23.167.176:8333 : 1740895525}
    2{ubeirqalc4vj54baszpatvctpohn62hzj7vfnbncy6upa6vywvgewrad.onion:8333 : 1739825443}
    

    Currently, there’s a fingerprinting attack that exploits responses to GETADDR messages. An attacker can collect responses from supposedly different nodes and compare the timestamps. By looking at overlaps in responses, they can correlate Tor and clearnet identities — effectively linking them back to the same node. More details on this attack here: https://delvingbitcoin.org/t/fingerprinting-nodes-via-addr-requests/1786

    This PR mitigates the attack by setting the timestamps in different caches to a fixed value in the past (10.5 ± 2.5 days), preventing correlation through timestamps. After the change, timestamps in each cache are now uniform, but differ between caches:

    IPv4 response:

    0{102.130.242.11:8333 : 1757964675}
    1{119.17.151.161:8333 : 1757964675}
    2{ubeirqalc4vj54baszpatvctpohn62hzj7vfnbncy6upa6vywvgewrad.onion:8333 : 1757964675}
    

    Tor response:

    0{102.130.242.11:8333 : 1757878277}
    1{119.17.151.161:8333 : 1757878277}
    2{ubeirqalc4vj54baszpatvctpohn62hzj7vfnbncy6upa6vywvgewrad.onion:8333 : 1757878277}
    

    We initially considered setting the timestamps to 0, since they would eventually be updated and saved. However, this isn’t compatible with btcd (see details here → https://github.com/btcsuite/btcd/issues/2411 ). This is still a work in progress — we’re continuing to test and are open to trying other solutions as well.

    This is joint work with @danielabrozzoni

  2. DrahtBot added the label P2P on Sep 29, 2025
  3. DrahtBot commented at 3:21 pm on September 29, 2025: contributor

    The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.

    Code Coverage & Benchmarks

    For details see: https://corecheck.dev/bitcoin/bitcoin/pulls/33498.

    Reviews

    See the guideline for information on the review process.

    Type Reviewers
    Concept ACK jonatack, mzumsande, sipa

    If your review is incorrectly listed, please react with 👎 to this comment and the bot will ignore it on the next update.

  4. jonatack commented at 4:38 pm on September 30, 2025: member
    Concept ACK on working on this. Good to see proposals like this and #33464.
  5. in src/net.cpp:3559 in ece2916552 outdated
    3553@@ -3554,6 +3554,17 @@ std::vector<CAddress> CConnman::GetAddresses(CNode& requestor, size_t max_addres
    3554         // in terms of the freshness of the response.
    3555         cache_entry.m_cache_entry_expiration = current_time +
    3556             21h + FastRandomContext().randrange<std::chrono::microseconds>(6h);
    3557+
    3558+        const auto now{Now<NodeSeconds>()};
    3559+        const auto new_timestamp = now - std::chrono::minutes(8 * 60 * 24 + FastRandomContext().randrange(5 * 60 * 24));
    


    mzumsande commented at 5:30 pm on September 30, 2025:
    Since this is calculated on a level of minutes, it looks like it would give a range 10.5±2.5 days, not 10±2 days.

    naiyoma commented at 11:52 am on October 3, 2025:
    Yes, this is more precise, ive updated
  6. mzumsande commented at 5:45 pm on September 30, 2025: contributor

    Concept ACK

    The suggested solution reduces the precision of timestamps for the receiving party, but makes fingerprinting harder - seems like an acceptable trade-off to me.

    If there is an active node behind the address it won’t be Terrible for another ~20 days - until that happens, we could update it with a more accurate timestamp when we connect to it or receive the addr via gossip relay.

  7. sipa commented at 1:32 pm on October 1, 2025: member
    Concept ACK
  8. net: set timestamps to a fixed time(10.5±2.5 days ago) for each cache
    Co-authored-by: Daniela Brozzoni <danielabrozzoni@protonmail.com>
    cec21bd2f7
  9. test: check timestamp uniqueness per cache
    Co-authored-by: Daniela Brozzoni <danielabrozzoni@protonmail.com>
    28fe8ecae6
  10. naiyoma force-pushed on Oct 3, 2025
  11. naiyoma marked this as ready for review on Oct 8, 2025
  12. mzumsande commented at 4:11 pm on October 9, 2025: contributor

    I wonder if this could lead to addrs of nodes that have left the network never getting removed:

    The scenario is a well-connected node that is present in most other nodes’ addrmans, but that suddenly leaves the network or changes its IP.

    Currently what happens is that 1) It won’t self-advertise anymore and 2) after 30 days, the addr gets Terrible and won’t be part of GetAddr interactions between other nodes. So it won’t be relayed by anyone after that - It will stay a while in most nodes’ addrmans and eventually be replaced due to addrman collisions.

    With this PR, if an address older than 10 days (but not older than 30 days) is part of a GetAddr answer, the receiving peer will postdate its timestamp, giving it more time until it gets Terrible. There is a chaining effect, because the receiving peer will also relay it longer when it answers GetAddr requests itself, and so on. If this would happen frequently enough, the addr of the node that has left the network would always stay in the 10-30 day range and never cease to be relayed, and we’d be stuck with it forever - which would be problematic, because with enough time and node turnover, everyone’s addrman would get “full” and there would be no more room for actual new nodes. The crucial question is if GetAddr interactions happen frequently enough for this to be an important effect.


github-metadata-mirror

This is a metadata mirror of the GitHub repository bitcoin/bitcoin. This site is not affiliated with GitHub. Content is generated from a GitHub metadata backup.
generated: 2025-10-10 15:13 UTC

This site is hosted by @0xB10C
More mirrored repositories can be found on mirror.b10c.me