0
0
Fork 0
mirror of https://github.com/bitcoin/bitcoin.git synced 2025-02-13 11:25:02 -05:00

Add indexing ADDR cache by local socket addr

This commit is contained in:
Gleb Naumenko 2020-08-11 12:41:26 +03:00
parent 42ec558542
commit 81b00f8780
3 changed files with 23 additions and 11 deletions

View file

@ -94,6 +94,7 @@ const std::string NET_MESSAGE_COMMAND_OTHER = "*other*";
static const uint64_t RANDOMIZER_ID_NETGROUP = 0x6c0edd8036ef4036ULL; // SHA256("netgroup")[0:8] 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_LOCALHOSTNONCE = 0xd93e69e2bbfa5735ULL; // SHA256("localhostnonce")[0:8]
static const uint64_t RANDOMIZER_ID_ADDRCACHE = 0x1cf2e4ddd306dda9ULL; // SHA256("addrcache")[0:8]
// //
// Global state variables // Global state variables
// //
@ -2539,12 +2540,19 @@ std::vector<CAddress> CConnman::GetAddresses(size_t max_addresses, size_t max_pc
return addresses; return addresses;
} }
std::vector<CAddress> CConnman::GetAddresses(Network requestor_network, size_t max_addresses, size_t max_pct) std::vector<CAddress> CConnman::GetAddresses(CNode& requestor, size_t max_addresses, size_t max_pct)
{ {
SOCKET socket;
WITH_LOCK(requestor.cs_hSocket, socket = requestor.hSocket);
auto local_socket_bytes = GetBindAddress(socket).GetAddrBytes();
uint64_t cache_id = GetDeterministicRandomizer(RANDOMIZER_ID_ADDRCACHE)
.Write(requestor.addr.GetNetwork())
.Write(local_socket_bytes.data(), local_socket_bytes.size())
.Finalize();
const auto current_time = GetTime<std::chrono::microseconds>(); const auto current_time = GetTime<std::chrono::microseconds>();
if (m_addr_response_caches.find(requestor_network) == m_addr_response_caches.end() || if (m_addr_response_caches.find(cache_id) == m_addr_response_caches.end() ||
m_addr_response_caches[requestor_network].m_update_addr_response < current_time) { m_addr_response_caches[cache_id].m_update_addr_response < current_time) {
m_addr_response_caches[requestor_network].m_addrs_response_cache = GetAddresses(max_addresses, max_pct); m_addr_response_caches[cache_id].m_addrs_response_cache = GetAddresses(max_addresses, max_pct);
// Choosing a proper cache lifetime is a trade-off between the privacy leak minimization // Choosing a proper cache lifetime is a trade-off between the privacy leak minimization
// and the usefulness of ADDR responses to honest users. // and the usefulness of ADDR responses to honest users.
@ -2570,9 +2578,9 @@ std::vector<CAddress> CConnman::GetAddresses(Network requestor_network, size_t m
// nodes to be "terrible" (see IsTerrible()) if the timestamps are older than 30 days, // nodes to be "terrible" (see IsTerrible()) if the timestamps are older than 30 days,
// max. 24 hours of "penalty" due to cache shouldn't make any meaningful difference // max. 24 hours of "penalty" due to cache shouldn't make any meaningful difference
// in terms of the freshness of the response. // in terms of the freshness of the response.
m_addr_response_caches[requestor_network].m_update_addr_response = current_time + std::chrono::hours(21) + GetRandMillis(std::chrono::hours(6)); m_addr_response_caches[cache_id].m_update_addr_response = current_time + std::chrono::hours(21) + GetRandMillis(std::chrono::hours(6));
} }
return m_addr_response_caches[requestor_network].m_addrs_response_cache; return m_addr_response_caches[cache_id].m_addrs_response_cache;
} }
bool CConnman::AddNode(const std::string& strNode) bool CConnman::AddNode(const std::string& strNode)

View file

@ -269,7 +269,7 @@ public:
* A non-malicious call (from RPC or a peer with addr permission) should * A non-malicious call (from RPC or a peer with addr permission) should
* call the function without a parameter to avoid using the cache. * call the function without a parameter to avoid using the cache.
*/ */
std::vector<CAddress> GetAddresses(Network requestor_network, size_t max_addresses, size_t max_pct); std::vector<CAddress> GetAddresses(CNode& requestor, size_t max_addresses, size_t max_pct);
// This allows temporarily exceeding m_max_outbound_full_relay, with the goal of finding // This allows temporarily exceeding m_max_outbound_full_relay, with the goal of finding
// a peer that is better than all our current peers. // a peer that is better than all our current peers.
@ -447,15 +447,19 @@ private:
/** /**
* Addr responses stored in different caches * Addr responses stored in different caches
* per network prevent cross-network node identification. * per (network, local socket) prevent cross-network node identification.
* If a node for example is multi-homed under Tor and IPv6, * If a node for example is multi-homed under Tor and IPv6,
* a single cache (or no cache at all) would let an attacker * a single cache (or no cache at all) would let an attacker
* to easily detect that it is the same node by comparing responses. * to easily detect that it is the same node by comparing responses.
* Indexing by local socket prevents leakage when a node has multiple
* listening addresses on the same network.
*
* The used memory equals to 1000 CAddress records (or around 32 bytes) per * The used memory equals to 1000 CAddress records (or around 32 bytes) per
* distinct Network (up to 5) we have/had an inbound peer from, * distinct Network (up to 5) we have/had an inbound peer from,
* resulting in at most ~160 KB. * resulting in at most ~160 KB. Every separate local socket may
* add up to ~160 KB extra.
*/ */
std::map<Network, CachedAddrResponse> m_addr_response_caches; std::map<uint64_t, CachedAddrResponse> m_addr_response_caches;
/** /**
* Services this instance offers. * Services this instance offers.

View file

@ -3516,7 +3516,7 @@ void PeerLogicValidation::ProcessMessage(CNode& pfrom, const std::string& msg_ty
if (pfrom.HasPermission(PF_ADDR)) { if (pfrom.HasPermission(PF_ADDR)) {
vAddr = m_connman.GetAddresses(MAX_ADDR_TO_SEND, MAX_PCT_ADDR_TO_SEND); vAddr = m_connman.GetAddresses(MAX_ADDR_TO_SEND, MAX_PCT_ADDR_TO_SEND);
} else { } else {
vAddr = m_connman.GetAddresses(pfrom.addr.GetNetwork(), MAX_ADDR_TO_SEND, MAX_PCT_ADDR_TO_SEND); vAddr = m_connman.GetAddresses(pfrom, MAX_ADDR_TO_SEND, MAX_PCT_ADDR_TO_SEND);
} }
FastRandomContext insecure_rand; FastRandomContext insecure_rand;
for (const CAddress &addr : vAddr) { for (const CAddress &addr : vAddr) {