Skip to content

Commit acd6135

Browse files
committed
Cache responses to addr requests
Prevents a spy from scraping victim's AddrMan by reconnecting and re-requesting addrs.
1 parent 7cc0e81 commit acd6135

File tree

3 files changed

+43
-1
lines changed

3 files changed

+43
-1
lines changed

src/net.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2539,6 +2539,17 @@ std::vector<CAddress> CConnman::GetAddresses()
25392539
return addresses;
25402540
}
25412541

2542+
std::vector<CAddress> CConnman::GetAddresses(Network requestor_network)
2543+
{
2544+
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();
2548+
m_addr_response_caches[requestor_network].m_update_addr_response = current_time + std::chrono::hours(21) + GetRandMillis(std::chrono::hours(6));
2549+
}
2550+
return m_addr_response_caches[requestor_network].m_addrs_response_cache;
2551+
}
2552+
25422553
bool CConnman::AddNode(const std::string& strNode)
25432554
{
25442555
LOCK(cs_vAddedNodes);

src/net.h

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include <atomic>
2828
#include <cstdint>
2929
#include <deque>
30+
#include <map>
3031
#include <thread>
3132
#include <memory>
3233
#include <condition_variable>
@@ -254,6 +255,13 @@ class CConnman
254255
void MarkAddressGood(const CAddress& addr);
255256
void AddNewAddresses(const std::vector<CAddress>& vAddr, const CAddress& addrFrom, int64_t nTimePenalty = 0);
256257
std::vector<CAddress> GetAddresses();
258+
/**
259+
* Cache is used to minimize topology leaks, so it should
260+
* be used for all non-trusted calls, for example, p2p.
261+
* A non-malicious call (from RPC) should
262+
* call the function without a parameter to avoid using the cache.
263+
*/
264+
std::vector<CAddress> GetAddresses(Network requestor_network);
257265

258266
// This allows temporarily exceeding m_max_outbound_full_relay, with the goal of finding
259267
// a peer that is better than all our current peers.
@@ -418,6 +426,29 @@ class CConnman
418426
std::atomic<NodeId> nLastNodeId{0};
419427
unsigned int nPrevNodeCount{0};
420428

429+
/**
430+
* Cache responses to addr requests to minimize privacy leak.
431+
* Attack example: scraping addrs in real-time may allow an attacker
432+
* to infer new connections of the victim by detecting new records
433+
* with fresh timestamps (per self-announcement).
434+
*/
435+
struct CachedAddrResponse {
436+
std::vector<CAddress> m_addrs_response_cache;
437+
std::chrono::microseconds m_update_addr_response{0};
438+
};
439+
440+
/**
441+
* Addr responses stored in different caches
442+
* per network prevent cross-network node identification.
443+
* If a node for example is multi-homed under Tor and IPv6,
444+
* a single cache (or no cache at all) would let an attacker
445+
* to easily detect that it is the same node by comparing responses.
446+
* The used memory equals to 1000 CAddress records (or around 32 bytes) per
447+
* distinct Network (up to 5) we have/had an inbound peer from,
448+
* resulting in at most ~160 KB.
449+
*/
450+
std::map<Network, CachedAddrResponse> m_addr_response_caches;
451+
421452
/**
422453
* Services this instance offers.
423454
*

src/net_processing.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3477,7 +3477,7 @@ void ProcessMessage(
34773477
pfrom.fSentAddr = true;
34783478

34793479
pfrom.vAddrToSend.clear();
3480-
std::vector<CAddress> vAddr = connman.GetAddresses();
3480+
std::vector<CAddress> vAddr = connman.GetAddresses(pfrom.addr.GetNetwork());
34813481
FastRandomContext insecure_rand;
34823482
for (const CAddress &addr : vAddr) {
34833483
pfrom.PushAddress(addr, insecure_rand);

0 commit comments

Comments
 (0)