mirror of
https://github.com/bitcoin/bitcoin
synced 2025-10-05 23:42:53 +02:00
net: use generic network key for addrcache
The generic key can also be used in other places where behavior between different network identities should be uncorrelated to avoid fingerprinting. This also changes RANDOMIZER_ID - since it is not being persisted to disk, there are no compatibility issues.
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
|
||||
//
|
||||
@@ -530,6 +530,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,
|
||||
@@ -539,6 +546,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),
|
||||
@@ -1832,6 +1840,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},
|
||||
@@ -1841,6 +1854,7 @@ void CConnman::CreateNodeFromAcceptedSocket(std::unique_ptr<Sock>&& sock,
|
||||
/*addrNameIn=*/"",
|
||||
ConnectionType::INBOUND,
|
||||
inbound_onion,
|
||||
network_id,
|
||||
CNodeOptions{
|
||||
.permission_flags = permission_flags,
|
||||
.prefer_evict = discouraged,
|
||||
@@ -3519,15 +3533,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);
|
||||
@@ -3804,6 +3812,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},
|
||||
@@ -3816,6 +3825,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},
|
||||
|
@@ -738,6 +738,10 @@ public:
|
||||
std::atomic_bool fPauseRecv{false};
|
||||
std::atomic_bool fPauseSend{false};
|
||||
|
||||
/** Network key used to prevent fingerprinting our node across networks.
|
||||
* Influenced by the network and the bind address (+ bind port for inbounds) */
|
||||
const uint64_t m_network_key;
|
||||
|
||||
const ConnectionType m_conn_type;
|
||||
|
||||
/** Move all messages from the received queue to the processing queue. */
|
||||
@@ -889,6 +893,7 @@ public:
|
||||
const std::string& addrNameIn,
|
||||
ConnectionType conn_type_in,
|
||||
bool inbound_onion,
|
||||
uint64_t network_key,
|
||||
CNodeOptions&& node_opts = {});
|
||||
CNode(const CNode&) = delete;
|
||||
CNode& operator=(const CNode&) = delete;
|
||||
|
@@ -62,7 +62,8 @@ BOOST_AUTO_TEST_CASE(outbound_slow_chain_eviction)
|
||||
CAddress(),
|
||||
/*addrNameIn=*/"",
|
||||
ConnectionType::OUTBOUND_FULL_RELAY,
|
||||
/*inbound_onion=*/false};
|
||||
/*inbound_onion=*/false,
|
||||
/*network_key=*/0};
|
||||
|
||||
connman.Handshake(
|
||||
/*node=*/dummyNode1,
|
||||
@@ -128,7 +129,8 @@ void AddRandomOutboundPeer(NodeId& id, std::vector<CNode*>& vNodes, PeerManager&
|
||||
CAddress(),
|
||||
/*addrNameIn=*/"",
|
||||
connType,
|
||||
/*inbound_onion=*/false});
|
||||
/*inbound_onion=*/false,
|
||||
/*network_key=*/0});
|
||||
CNode &node = *vNodes.back();
|
||||
node.SetCommonVersion(PROTOCOL_VERSION);
|
||||
|
||||
@@ -327,7 +329,8 @@ BOOST_AUTO_TEST_CASE(peer_discouragement)
|
||||
CAddress(),
|
||||
/*addrNameIn=*/"",
|
||||
ConnectionType::INBOUND,
|
||||
/*inbound_onion=*/false};
|
||||
/*inbound_onion=*/false,
|
||||
/*network_key=*/1};
|
||||
nodes[0]->SetCommonVersion(PROTOCOL_VERSION);
|
||||
peerLogic->InitializeNode(*nodes[0], NODE_NETWORK);
|
||||
nodes[0]->fSuccessfullyConnected = true;
|
||||
@@ -347,7 +350,8 @@ BOOST_AUTO_TEST_CASE(peer_discouragement)
|
||||
CAddress(),
|
||||
/*addrNameIn=*/"",
|
||||
ConnectionType::INBOUND,
|
||||
/*inbound_onion=*/false};
|
||||
/*inbound_onion=*/false,
|
||||
/*network_key=*/1};
|
||||
nodes[1]->SetCommonVersion(PROTOCOL_VERSION);
|
||||
peerLogic->InitializeNode(*nodes[1], NODE_NETWORK);
|
||||
nodes[1]->fSuccessfullyConnected = true;
|
||||
@@ -377,7 +381,8 @@ BOOST_AUTO_TEST_CASE(peer_discouragement)
|
||||
CAddress(),
|
||||
/*addrNameIn=*/"",
|
||||
ConnectionType::OUTBOUND_FULL_RELAY,
|
||||
/*inbound_onion=*/false};
|
||||
/*inbound_onion=*/false,
|
||||
/*network_key=*/2};
|
||||
nodes[2]->SetCommonVersion(PROTOCOL_VERSION);
|
||||
peerLogic->InitializeNode(*nodes[2], NODE_NETWORK);
|
||||
nodes[2]->fSuccessfullyConnected = true;
|
||||
@@ -419,7 +424,8 @@ BOOST_AUTO_TEST_CASE(DoS_bantime)
|
||||
CAddress(),
|
||||
/*addrNameIn=*/"",
|
||||
ConnectionType::INBOUND,
|
||||
/*inbound_onion=*/false};
|
||||
/*inbound_onion=*/false,
|
||||
/*network_key=*/1};
|
||||
dummyNode.SetCommonVersion(PROTOCOL_VERSION);
|
||||
peerLogic->InitializeNode(dummyNode, NODE_NETWORK);
|
||||
dummyNode.fSuccessfullyConnected = true;
|
||||
|
@@ -70,7 +70,7 @@ void HeadersSyncSetup::ResetAndInitialize()
|
||||
|
||||
for (auto conn_type : conn_types) {
|
||||
CAddress addr{};
|
||||
m_connections.push_back(new CNode(id++, nullptr, addr, 0, 0, addr, "", conn_type, false));
|
||||
m_connections.push_back(new CNode(id++, nullptr, addr, 0, 0, addr, "", conn_type, false, 0));
|
||||
CNode& p2p_node = *m_connections.back();
|
||||
|
||||
connman.Handshake(
|
||||
|
@@ -239,6 +239,8 @@ auto ConsumeNode(FuzzedDataProvider& fuzzed_data_provider, const std::optional<N
|
||||
const std::string addr_name = fuzzed_data_provider.ConsumeRandomLengthString(64);
|
||||
const ConnectionType conn_type = fuzzed_data_provider.PickValueInArray(ALL_CONNECTION_TYPES);
|
||||
const bool inbound_onion{conn_type == ConnectionType::INBOUND ? fuzzed_data_provider.ConsumeBool() : false};
|
||||
const uint64_t network_id = fuzzed_data_provider.ConsumeIntegral<uint64_t>();
|
||||
|
||||
NetPermissionFlags permission_flags = ConsumeWeakEnum(fuzzed_data_provider, ALL_NET_PERMISSION_FLAGS);
|
||||
if constexpr (ReturnUniquePtr) {
|
||||
return std::make_unique<CNode>(node_id,
|
||||
@@ -250,6 +252,7 @@ auto ConsumeNode(FuzzedDataProvider& fuzzed_data_provider, const std::optional<N
|
||||
addr_name,
|
||||
conn_type,
|
||||
inbound_onion,
|
||||
network_id,
|
||||
CNodeOptions{ .permission_flags = permission_flags });
|
||||
} else {
|
||||
return CNode{node_id,
|
||||
@@ -261,6 +264,7 @@ auto ConsumeNode(FuzzedDataProvider& fuzzed_data_provider, const std::optional<N
|
||||
addr_name,
|
||||
conn_type,
|
||||
inbound_onion,
|
||||
network_id,
|
||||
CNodeOptions{ .permission_flags = permission_flags }};
|
||||
}
|
||||
}
|
||||
|
@@ -72,7 +72,8 @@ void AddPeer(NodeId& id, std::vector<CNode*>& nodes, PeerManager& peerman, Connm
|
||||
CAddress{},
|
||||
/*addrNameIn=*/"",
|
||||
conn_type,
|
||||
/*inbound_onion=*/inbound_onion});
|
||||
/*inbound_onion=*/inbound_onion,
|
||||
/*network_key=*/0});
|
||||
CNode& node = *nodes.back();
|
||||
node.SetCommonVersion(PROTOCOL_VERSION);
|
||||
|
||||
|
@@ -67,7 +67,8 @@ BOOST_AUTO_TEST_CASE(cnode_simple_test)
|
||||
CAddress(),
|
||||
pszDest,
|
||||
ConnectionType::OUTBOUND_FULL_RELAY,
|
||||
/*inbound_onion=*/false);
|
||||
/*inbound_onion=*/false,
|
||||
/*network_key=*/0);
|
||||
BOOST_CHECK(pnode1->IsFullOutboundConn() == true);
|
||||
BOOST_CHECK(pnode1->IsManualConn() == false);
|
||||
BOOST_CHECK(pnode1->IsBlockOnlyConn() == false);
|
||||
@@ -85,7 +86,8 @@ BOOST_AUTO_TEST_CASE(cnode_simple_test)
|
||||
CAddress(),
|
||||
pszDest,
|
||||
ConnectionType::INBOUND,
|
||||
/*inbound_onion=*/false);
|
||||
/*inbound_onion=*/false,
|
||||
/*network_key=*/1);
|
||||
BOOST_CHECK(pnode2->IsFullOutboundConn() == false);
|
||||
BOOST_CHECK(pnode2->IsManualConn() == false);
|
||||
BOOST_CHECK(pnode2->IsBlockOnlyConn() == false);
|
||||
@@ -103,7 +105,8 @@ BOOST_AUTO_TEST_CASE(cnode_simple_test)
|
||||
CAddress(),
|
||||
pszDest,
|
||||
ConnectionType::OUTBOUND_FULL_RELAY,
|
||||
/*inbound_onion=*/false);
|
||||
/*inbound_onion=*/false,
|
||||
/*network_key=*/2);
|
||||
BOOST_CHECK(pnode3->IsFullOutboundConn() == true);
|
||||
BOOST_CHECK(pnode3->IsManualConn() == false);
|
||||
BOOST_CHECK(pnode3->IsBlockOnlyConn() == false);
|
||||
@@ -121,7 +124,8 @@ BOOST_AUTO_TEST_CASE(cnode_simple_test)
|
||||
CAddress(),
|
||||
pszDest,
|
||||
ConnectionType::INBOUND,
|
||||
/*inbound_onion=*/true);
|
||||
/*inbound_onion=*/true,
|
||||
/*network_key=*/3);
|
||||
BOOST_CHECK(pnode4->IsFullOutboundConn() == false);
|
||||
BOOST_CHECK(pnode4->IsManualConn() == false);
|
||||
BOOST_CHECK(pnode4->IsBlockOnlyConn() == false);
|
||||
@@ -613,7 +617,8 @@ BOOST_AUTO_TEST_CASE(ipv4_peer_with_ipv6_addrMe_test)
|
||||
CAddress{},
|
||||
/*pszDest=*/std::string{},
|
||||
ConnectionType::OUTBOUND_FULL_RELAY,
|
||||
/*inbound_onion=*/false);
|
||||
/*inbound_onion=*/false,
|
||||
/*network_key=*/0);
|
||||
pnode->fSuccessfullyConnected.store(true);
|
||||
|
||||
// the peer claims to be reaching us via IPv6
|
||||
@@ -667,7 +672,8 @@ BOOST_AUTO_TEST_CASE(get_local_addr_for_peer_port)
|
||||
/*addrBindIn=*/CService{},
|
||||
/*addrNameIn=*/std::string{},
|
||||
/*conn_type_in=*/ConnectionType::OUTBOUND_FULL_RELAY,
|
||||
/*inbound_onion=*/false};
|
||||
/*inbound_onion=*/false,
|
||||
/*network_key=*/0};
|
||||
peer_out.fSuccessfullyConnected = true;
|
||||
peer_out.SetAddrLocal(peer_us);
|
||||
|
||||
@@ -688,7 +694,8 @@ BOOST_AUTO_TEST_CASE(get_local_addr_for_peer_port)
|
||||
/*addrBindIn=*/CService{},
|
||||
/*addrNameIn=*/std::string{},
|
||||
/*conn_type_in=*/ConnectionType::INBOUND,
|
||||
/*inbound_onion=*/false};
|
||||
/*inbound_onion=*/false,
|
||||
/*network_key=*/1};
|
||||
peer_in.fSuccessfullyConnected = true;
|
||||
peer_in.SetAddrLocal(peer_us);
|
||||
|
||||
@@ -825,7 +832,8 @@ BOOST_AUTO_TEST_CASE(initial_advertise_from_version_message)
|
||||
/*addrBindIn=*/CService{},
|
||||
/*addrNameIn=*/std::string{},
|
||||
/*conn_type_in=*/ConnectionType::OUTBOUND_FULL_RELAY,
|
||||
/*inbound_onion=*/false};
|
||||
/*inbound_onion=*/false,
|
||||
/*network_key=*/2};
|
||||
|
||||
const uint64_t services{NODE_NETWORK | NODE_WITNESS};
|
||||
const int64_t time{0};
|
||||
@@ -900,7 +908,8 @@ BOOST_AUTO_TEST_CASE(advertise_local_address)
|
||||
CAddress{},
|
||||
/*pszDest=*/std::string{},
|
||||
ConnectionType::OUTBOUND_FULL_RELAY,
|
||||
/*inbound_onion=*/false);
|
||||
/*inbound_onion=*/false,
|
||||
/*network_key=*/0);
|
||||
};
|
||||
g_reachable_nets.Add(NET_CJDNS);
|
||||
|
||||
|
Reference in New Issue
Block a user