Skip to content

Commit 81b00f8

Browse files
committed
Add indexing ADDR cache by local socket addr
1 parent 42ec558 commit 81b00f8

File tree

3 files changed

+23
-11
lines changed

3 files changed

+23
-11
lines changed

src/net.cpp

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ const std::string NET_MESSAGE_COMMAND_OTHER = "*other*";
9494

9595
static const uint64_t RANDOMIZER_ID_NETGROUP = 0x6c0edd8036ef4036ULL; // SHA256("netgroup")[0:8]
9696
static const uint64_t RANDOMIZER_ID_LOCALHOSTNONCE = 0xd93e69e2bbfa5735ULL; // SHA256("localhostnonce")[0:8]
97+
static const uint64_t RANDOMIZER_ID_ADDRCACHE = 0x1cf2e4ddd306dda9ULL; // SHA256("addrcache")[0:8]
9798
//
9899
// Global state variables
99100
//
@@ -2539,12 +2540,19 @@ std::vector<CAddress> CConnman::GetAddresses(size_t max_addresses, size_t max_pc
25392540
return addresses;
25402541
}
25412542

2542-
std::vector<CAddress> CConnman::GetAddresses(Network requestor_network, size_t max_addresses, size_t max_pct)
2543+
std::vector<CAddress> CConnman::GetAddresses(CNode& requestor, size_t max_addresses, size_t max_pct)
25432544
{
2545+
SOCKET socket;
2546+
WITH_LOCK(requestor.cs_hSocket, socket = requestor.hSocket);
2547+
auto local_socket_bytes = GetBindAddress(socket).GetAddrBytes();
2548+
uint64_t cache_id = GetDeterministicRandomizer(RANDOMIZER_ID_ADDRCACHE)
2549+
.Write(requestor.addr.GetNetwork())
2550+
.Write(local_socket_bytes.data(), local_socket_bytes.size())
2551+
.Finalize();
25442552
const auto current_time = GetTime<std::chrono::microseconds>();
2545-
if (m_addr_response_caches.find(requestor_network) == m_addr_response_caches.end() ||
2546-
m_addr_response_caches[requestor_network].m_update_addr_response < current_time) {
2547-
m_addr_response_caches[requestor_network].m_addrs_response_cache = GetAddresses(max_addresses, max_pct);
2553+
if (m_addr_response_caches.find(cache_id) == m_addr_response_caches.end() ||
2554+
m_addr_response_caches[cache_id].m_update_addr_response < current_time) {
2555+
m_addr_response_caches[cache_id].m_addrs_response_cache = GetAddresses(max_addresses, max_pct);
25482556

25492557
// Choosing a proper cache lifetime is a trade-off between the privacy leak minimization
25502558
// and the usefulness of ADDR responses to honest users.
@@ -2570,9 +2578,9 @@ std::vector<CAddress> CConnman::GetAddresses(Network requestor_network, size_t m
25702578
// nodes to be "terrible" (see IsTerrible()) if the timestamps are older than 30 days,
25712579
// max. 24 hours of "penalty" due to cache shouldn't make any meaningful difference
25722580
// in terms of the freshness of the response.
2573-
m_addr_response_caches[requestor_network].m_update_addr_response = current_time + std::chrono::hours(21) + GetRandMillis(std::chrono::hours(6));
2581+
m_addr_response_caches[cache_id].m_update_addr_response = current_time + std::chrono::hours(21) + GetRandMillis(std::chrono::hours(6));
25742582
}
2575-
return m_addr_response_caches[requestor_network].m_addrs_response_cache;
2583+
return m_addr_response_caches[cache_id].m_addrs_response_cache;
25762584
}
25772585

25782586
bool CConnman::AddNode(const std::string& strNode)

src/net.h

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,7 @@ class CConnman
269269
* A non-malicious call (from RPC or a peer with addr permission) should
270270
* call the function without a parameter to avoid using the cache.
271271
*/
272-
std::vector<CAddress> GetAddresses(Network requestor_network, size_t max_addresses, size_t max_pct);
272+
std::vector<CAddress> GetAddresses(CNode& requestor, size_t max_addresses, size_t max_pct);
273273

274274
// This allows temporarily exceeding m_max_outbound_full_relay, with the goal of finding
275275
// a peer that is better than all our current peers.
@@ -447,15 +447,19 @@ class CConnman
447447

448448
/**
449449
* Addr responses stored in different caches
450-
* per network prevent cross-network node identification.
450+
* per (network, local socket) prevent cross-network node identification.
451451
* If a node for example is multi-homed under Tor and IPv6,
452452
* a single cache (or no cache at all) would let an attacker
453453
* to easily detect that it is the same node by comparing responses.
454+
* Indexing by local socket prevents leakage when a node has multiple
455+
* listening addresses on the same network.
456+
*
454457
* The used memory equals to 1000 CAddress records (or around 32 bytes) per
455458
* distinct Network (up to 5) we have/had an inbound peer from,
456-
* resulting in at most ~160 KB.
459+
* resulting in at most ~160 KB. Every separate local socket may
460+
* add up to ~160 KB extra.
457461
*/
458-
std::map<Network, CachedAddrResponse> m_addr_response_caches;
462+
std::map<uint64_t, CachedAddrResponse> m_addr_response_caches;
459463

460464
/**
461465
* Services this instance offers.

src/net_processing.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3516,7 +3516,7 @@ void PeerLogicValidation::ProcessMessage(CNode& pfrom, const std::string& msg_ty
35163516
if (pfrom.HasPermission(PF_ADDR)) {
35173517
vAddr = m_connman.GetAddresses(MAX_ADDR_TO_SEND, MAX_PCT_ADDR_TO_SEND);
35183518
} else {
3519-
vAddr = m_connman.GetAddresses(pfrom.addr.GetNetwork(), MAX_ADDR_TO_SEND, MAX_PCT_ADDR_TO_SEND);
3519+
vAddr = m_connman.GetAddresses(pfrom, MAX_ADDR_TO_SEND, MAX_PCT_ADDR_TO_SEND);
35203520
}
35213521
FastRandomContext insecure_rand;
35223522
for (const CAddress &addr : vAddr) {

0 commit comments

Comments
 (0)