mirror of
https://github.com/bitcoin/bitcoin.git
synced 2026-01-20 07:09:15 +01:00
Merge bitcoin/bitcoin#33464: p2p: Use network-dependent timers for inbound inv scheduling
0f7d4ee4e8p2p: Use different inbound inv timer per network (Martin Zumsande)94db966a3bnet: use generic network key for addrcache (Martin Zumsande) Pull request description: Currently, `NextInvToInbounds` schedules each round of `inv` at the same time for all inbound peers. It's being done this way because with a separate timer per peer (like it's done for outbounds), an attacker could do multiple connections to learn about the time a transaction arrived. (#13298). However, having a single timer for inbounds of all networks is also an obvious fingerprinting vector: Connecting to a suspected pair of privacy-network and clearnet addresses and observing the `inv` pattern makes it trivial to confirm or refute that they are the same node. This PR changes it such that a separate timer is used for each network. It uses the existing method from `getaddr` caching and generalizes it to be saved in a new field `m_network_key` in `CNode` which will be used for both `getaddr` caching and `inv` scheduling, and can also be used for any future anti-fingerprinting measures. ACKs for top commit: sipa: utACK0f7d4ee4e8stratospher: reACK0f7d4ee. naiyoma: Tested ACK0f7d4ee4e8danielabrozzoni: reACK0f7d4ee4e8Tree-SHA512: e197c3005b2522051db432948874320b74c23e01e66988ee1ee11917dac0923f58c1252fa47da24e68b08d7a355d8e5e0a3ccdfa6e4324cb901f21dfa880cd9c
This commit is contained in:
28
src/net.cpp
28
src/net.cpp
@@ -108,7 +108,7 @@ const std::string NET_MESSAGE_TYPE_OTHER = "*other*";
|
||||
|
||||
static const uint64_t RANDOMIZER_ID_NETGROUP = 0x6c0edd8036ef4036ULL; // SHA256("netgroup")[0:8]
|
||||
static const uint64_t RANDOMIZER_ID_LOCALHOSTNONCE = 0xd93e69e2bbfa5735ULL; // SHA256("localhostnonce")[0:8]
|
||||
static const uint64_t RANDOMIZER_ID_ADDRCACHE = 0x1cf2e4ddd306dda9ULL; // SHA256("addrcache")[0:8]
|
||||
static const uint64_t RANDOMIZER_ID_NETWORKKEY = 0x0e8a2b136c592a7dULL; // SHA256("networkkey")[0:8]
|
||||
//
|
||||
// Global state variables
|
||||
//
|
||||
@@ -506,6 +506,13 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo
|
||||
if (!addr_bind.IsValid()) {
|
||||
addr_bind = GetBindAddress(*sock);
|
||||
}
|
||||
uint64_t network_id = GetDeterministicRandomizer(RANDOMIZER_ID_NETWORKKEY)
|
||||
.Write(target_addr.GetNetClass())
|
||||
.Write(addr_bind.GetAddrBytes())
|
||||
// For outbound connections, the port of the bound address is randomly
|
||||
// assigned by the OS and would therefore not be useful for seeding.
|
||||
.Write(0)
|
||||
.Finalize();
|
||||
CNode* pnode = new CNode(id,
|
||||
std::move(sock),
|
||||
target_addr,
|
||||
@@ -515,6 +522,7 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo
|
||||
pszDest ? pszDest : "",
|
||||
conn_type,
|
||||
/*inbound_onion=*/false,
|
||||
network_id,
|
||||
CNodeOptions{
|
||||
.permission_flags = permission_flags,
|
||||
.i2p_sam_session = std::move(i2p_transient_session),
|
||||
@@ -1808,6 +1816,11 @@ void CConnman::CreateNodeFromAcceptedSocket(std::unique_ptr<Sock>&& sock,
|
||||
ServiceFlags local_services = GetLocalServices();
|
||||
const bool use_v2transport(local_services & NODE_P2P_V2);
|
||||
|
||||
uint64_t network_id = GetDeterministicRandomizer(RANDOMIZER_ID_NETWORKKEY)
|
||||
.Write(inbound_onion ? NET_ONION : addr.GetNetClass())
|
||||
.Write(addr_bind.GetAddrBytes())
|
||||
.Write(addr_bind.GetPort()) // inbound connections use bind port
|
||||
.Finalize();
|
||||
CNode* pnode = new CNode(id,
|
||||
std::move(sock),
|
||||
CAddress{addr, NODE_NONE},
|
||||
@@ -1817,6 +1830,7 @@ void CConnman::CreateNodeFromAcceptedSocket(std::unique_ptr<Sock>&& sock,
|
||||
/*addrNameIn=*/"",
|
||||
ConnectionType::INBOUND,
|
||||
inbound_onion,
|
||||
network_id,
|
||||
CNodeOptions{
|
||||
.permission_flags = permission_flags,
|
||||
.prefer_evict = discouraged,
|
||||
@@ -3506,15 +3520,9 @@ std::vector<CAddress> CConnman::GetAddressesUnsafe(size_t max_addresses, size_t
|
||||
std::vector<CAddress> CConnman::GetAddresses(CNode& requestor, size_t max_addresses, size_t max_pct)
|
||||
{
|
||||
auto local_socket_bytes = requestor.addrBind.GetAddrBytes();
|
||||
uint64_t cache_id = GetDeterministicRandomizer(RANDOMIZER_ID_ADDRCACHE)
|
||||
.Write(requestor.ConnectedThroughNetwork())
|
||||
.Write(local_socket_bytes)
|
||||
// For outbound connections, the port of the bound address is randomly
|
||||
// assigned by the OS and would therefore not be useful for seeding.
|
||||
.Write(requestor.IsInboundConn() ? requestor.addrBind.GetPort() : 0)
|
||||
.Finalize();
|
||||
uint64_t network_id = requestor.m_network_key;
|
||||
const auto current_time = GetTime<std::chrono::microseconds>();
|
||||
auto r = m_addr_response_caches.emplace(cache_id, CachedAddrResponse{});
|
||||
auto r = m_addr_response_caches.emplace(network_id, CachedAddrResponse{});
|
||||
CachedAddrResponse& cache_entry = r.first->second;
|
||||
if (cache_entry.m_cache_entry_expiration < current_time) { // If emplace() added new one it has expiration 0.
|
||||
cache_entry.m_addrs_response_cache = GetAddressesUnsafe(max_addresses, max_pct, /*network=*/std::nullopt);
|
||||
@@ -3793,6 +3801,7 @@ CNode::CNode(NodeId idIn,
|
||||
const std::string& addrNameIn,
|
||||
ConnectionType conn_type_in,
|
||||
bool inbound_onion,
|
||||
uint64_t network_key,
|
||||
CNodeOptions&& node_opts)
|
||||
: m_transport{MakeTransport(idIn, node_opts.use_v2transport, conn_type_in == ConnectionType::INBOUND)},
|
||||
m_permission_flags{node_opts.permission_flags},
|
||||
@@ -3805,6 +3814,7 @@ CNode::CNode(NodeId idIn,
|
||||
m_inbound_onion{inbound_onion},
|
||||
m_prefer_evict{node_opts.prefer_evict},
|
||||
nKeyedNetGroup{nKeyedNetGroupIn},
|
||||
m_network_key{network_key},
|
||||
m_conn_type{conn_type_in},
|
||||
id{idIn},
|
||||
nLocalHostNonce{nLocalHostNonceIn},
|
||||
|
||||
Reference in New Issue
Block a user