mirror of
https://github.com/dashpay/dash.git
synced 2024-12-25 12:02:48 +01:00
merge bitcoin#27411: Restrict self-advertisements with privacy networks to avoid fingerprinting
The old `GetLocal()` has been moved to `masternode/node.cpp` due to its use in determining a node's external address. We don't want the old variant to be used otherwise so we'll move it out of `net.{cpp,h}` for good measure. Co-authored-by: UdjinM6 <UdjinM6@users.noreply.github.com>
This commit is contained in:
parent
1376289b11
commit
8320e0ca8e
@ -15,6 +15,42 @@
|
||||
#include <validation.h>
|
||||
#include <warnings.h>
|
||||
|
||||
namespace {
|
||||
bool GetLocal(CService& addr, const CNetAddr* paddrPeer)
|
||||
{
|
||||
if (!fListen)
|
||||
return false;
|
||||
|
||||
int nBestScore = -1;
|
||||
{
|
||||
LOCK(g_maplocalhost_mutex);
|
||||
int nBestReachability = -1;
|
||||
for (const auto& entry : mapLocalHost)
|
||||
{
|
||||
// For privacy reasons, don't advertise our privacy-network address
|
||||
// to other networks and don't advertise our other-network address
|
||||
// to privacy networks.
|
||||
const Network our_net{entry.first.GetNetwork()};
|
||||
const Network peers_net{paddrPeer->GetNetwork()};
|
||||
if (our_net != peers_net &&
|
||||
(our_net == NET_ONION || our_net == NET_I2P ||
|
||||
peers_net == NET_ONION || peers_net == NET_I2P)) {
|
||||
continue;
|
||||
}
|
||||
int nScore = entry.second.nScore;
|
||||
int nReachability = entry.first.GetReachabilityFrom(*paddrPeer);
|
||||
if (nReachability > nBestReachability || (nReachability == nBestReachability && nScore > nBestScore))
|
||||
{
|
||||
addr = CService(entry.first, entry.second.nPort);
|
||||
nBestReachability = nReachability;
|
||||
nBestScore = nScore;
|
||||
}
|
||||
}
|
||||
}
|
||||
return nBestScore >= 0;
|
||||
}
|
||||
} // anonymous namespace
|
||||
|
||||
CActiveMasternodeManager::CActiveMasternodeManager(const CBLSSecretKey& sk, CConnman& connman, const std::unique_ptr<CDeterministicMNManager>& dmnman) :
|
||||
m_info(sk, sk.GetPublicKey()),
|
||||
m_connman{connman},
|
||||
@ -204,8 +240,7 @@ bool CActiveMasternodeManager::GetLocalAddress(CService& addrRet)
|
||||
auto service = m_info.service;
|
||||
m_connman.ForEachNodeContinueIf(CConnman::AllNodes, [&](CNode* pnode) {
|
||||
empty = false;
|
||||
if (pnode->addr.IsIPv4())
|
||||
fFoundLocal = GetLocal(service, &pnode->addr) && IsValidNetAddr(service);
|
||||
if (pnode->addr.IsIPv4()) fFoundLocal = GetLocal(service, *pnode) && IsValidNetAddr(service);
|
||||
return !fFoundLocal;
|
||||
});
|
||||
// nothing and no live connections, can't do anything for now
|
||||
|
20
src/net.cpp
20
src/net.cpp
@ -186,7 +186,7 @@ uint16_t GetListenPort()
|
||||
}
|
||||
|
||||
// find 'best' local address for a particular peer
|
||||
bool GetLocal(CService& addr, const CNetAddr *paddrPeer)
|
||||
bool GetLocal(CService& addr, const CNode& peer)
|
||||
{
|
||||
if (!fListen)
|
||||
return false;
|
||||
@ -197,8 +197,18 @@ bool GetLocal(CService& addr, const CNetAddr *paddrPeer)
|
||||
LOCK(g_maplocalhost_mutex);
|
||||
for (const auto& entry : mapLocalHost)
|
||||
{
|
||||
// For privacy reasons, don't advertise our privacy-network address
|
||||
// to other networks and don't advertise our other-network address
|
||||
// to privacy networks.
|
||||
const Network our_net{entry.first.GetNetwork()};
|
||||
const Network peers_net{peer.ConnectedThroughNetwork()};
|
||||
if (our_net != peers_net &&
|
||||
(our_net == NET_ONION || our_net == NET_I2P ||
|
||||
peers_net == NET_ONION || peers_net == NET_I2P)) {
|
||||
continue;
|
||||
}
|
||||
int nScore = entry.second.nScore;
|
||||
int nReachability = entry.first.GetReachabilityFrom(paddrPeer);
|
||||
int nReachability = entry.first.GetReachabilityFrom(peer.addr);
|
||||
if (nReachability > nBestReachability || (nReachability == nBestReachability && nScore > nBestScore))
|
||||
{
|
||||
addr = CService(entry.first, entry.second.nPort);
|
||||
@ -236,10 +246,10 @@ static std::vector<CAddress> ConvertSeeds(const std::vector<uint8_t> &vSeedsIn)
|
||||
// Otherwise, return the unroutable 0.0.0.0 but filled in with
|
||||
// the normal parameters, since the IP may be changed to a useful
|
||||
// one by discovery.
|
||||
CService GetLocalAddress(const CNetAddr& addrPeer)
|
||||
CService GetLocalAddress(const CNode& peer)
|
||||
{
|
||||
CService addr;
|
||||
if (GetLocal(addr, &addrPeer)) {
|
||||
if (GetLocal(addr, peer)) {
|
||||
return addr;
|
||||
}
|
||||
return CService{CNetAddr(), GetListenPort()};
|
||||
@ -262,7 +272,7 @@ bool IsPeerAddrLocalGood(CNode *pnode)
|
||||
|
||||
std::optional<CService> GetLocalAddrForPeer(CNode& node)
|
||||
{
|
||||
CService addrLocal{GetLocalAddress(node.addr)};
|
||||
CService addrLocal{GetLocalAddress(node)};
|
||||
// If discovery is enabled, sometimes give our peer the address it
|
||||
// tells us that it sees us as in case it has a better idea of our
|
||||
// address than we do.
|
||||
|
@ -199,8 +199,8 @@ bool AddLocal(const CNetAddr& addr, int nScore = LOCAL_NONE);
|
||||
void RemoveLocal(const CService& addr);
|
||||
bool SeenLocal(const CService& addr);
|
||||
bool IsLocal(const CService& addr);
|
||||
bool GetLocal(CService &addr, const CNetAddr *paddrPeer = nullptr);
|
||||
CService GetLocalAddress(const CNetAddr& addrPeer);
|
||||
bool GetLocal(CService& addr, const CNode& peer);
|
||||
CService GetLocalAddress(const CNode& peer);
|
||||
|
||||
|
||||
extern bool fDiscover;
|
||||
|
@ -3460,7 +3460,7 @@ void PeerManagerImpl::ProcessMessage(
|
||||
// indicate to the peer that we will participate in addr relay.
|
||||
if (fListen && !m_chainman.ActiveChainstate().IsInitialBlockDownload())
|
||||
{
|
||||
CAddress addr{GetLocalAddress(pfrom.addr), peer->m_our_services, (uint32_t)GetAdjustedTime()};
|
||||
CAddress addr{GetLocalAddress(pfrom), peer->m_our_services, (uint32_t)GetAdjustedTime()};
|
||||
FastRandomContext insecure_rand;
|
||||
if (addr.IsRoutable())
|
||||
{
|
||||
|
@ -742,19 +742,16 @@ uint64_t CNetAddr::GetHash() const
|
||||
|
||||
// private extensions to enum Network, only returned by GetExtNetwork,
|
||||
// and only used in GetReachabilityFrom
|
||||
static const int NET_UNKNOWN = NET_MAX + 0;
|
||||
static const int NET_TEREDO = NET_MAX + 1;
|
||||
int static GetExtNetwork(const CNetAddr *addr)
|
||||
static const int NET_TEREDO = NET_MAX;
|
||||
int static GetExtNetwork(const CNetAddr& addr)
|
||||
{
|
||||
if (addr == nullptr)
|
||||
return NET_UNKNOWN;
|
||||
if (addr->IsRFC4380())
|
||||
if (addr.IsRFC4380())
|
||||
return NET_TEREDO;
|
||||
return addr->GetNetwork();
|
||||
return addr.GetNetwork();
|
||||
}
|
||||
|
||||
/** Calculates a metric for how reachable (*this) is from a given partner */
|
||||
int CNetAddr::GetReachabilityFrom(const CNetAddr *paddrPartner) const
|
||||
int CNetAddr::GetReachabilityFrom(const CNetAddr& paddrPartner) const
|
||||
{
|
||||
enum Reachability {
|
||||
REACH_UNREACHABLE,
|
||||
@ -769,7 +766,7 @@ int CNetAddr::GetReachabilityFrom(const CNetAddr *paddrPartner) const
|
||||
if (!IsRoutable() || IsInternal())
|
||||
return REACH_UNREACHABLE;
|
||||
|
||||
int ourNet = GetExtNetwork(this);
|
||||
int ourNet = GetExtNetwork(*this);
|
||||
int theirNet = GetExtNetwork(paddrPartner);
|
||||
bool fTunnel = IsRFC3964() || IsRFC6052() || IsRFC6145();
|
||||
|
||||
@ -809,7 +806,6 @@ int CNetAddr::GetReachabilityFrom(const CNetAddr *paddrPartner) const
|
||||
case NET_IPV6: return REACH_IPV6_WEAK;
|
||||
case NET_IPV4: return REACH_IPV4;
|
||||
}
|
||||
case NET_UNKNOWN:
|
||||
case NET_UNROUTABLE:
|
||||
default:
|
||||
switch(ourNet) {
|
||||
|
@ -211,7 +211,7 @@ public:
|
||||
bool HasLinkedIPv4() const;
|
||||
|
||||
std::vector<unsigned char> GetAddrBytes() const;
|
||||
int GetReachabilityFrom(const CNetAddr *paddrPartner = nullptr) const;
|
||||
int GetReachabilityFrom(const CNetAddr& paddrPartner) const;
|
||||
|
||||
explicit CNetAddr(const struct in6_addr& pipv6Addr, const uint32_t scope = 0);
|
||||
bool GetIn6Addr(struct in6_addr* pipv6Addr) const;
|
||||
|
@ -83,7 +83,7 @@ FUZZ_TARGET(netaddress)
|
||||
(void)service.ToStringAddrPort();
|
||||
|
||||
const CNetAddr other_net_addr = ConsumeNetAddr(fuzzed_data_provider);
|
||||
(void)net_addr.GetReachabilityFrom(&other_net_addr);
|
||||
(void)net_addr.GetReachabilityFrom(other_net_addr);
|
||||
(void)sub_net.Match(other_net_addr);
|
||||
|
||||
const CService other_service{net_addr, fuzzed_data_provider.ConsumeIntegral<uint16_t>()};
|
||||
|
@ -908,4 +908,109 @@ BOOST_AUTO_TEST_CASE(initial_advertise_from_version_message)
|
||||
TestOnlyResetTimeData();
|
||||
}
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_CASE(advertise_local_address)
|
||||
{
|
||||
auto CreatePeer = [](const CAddress& addr) {
|
||||
return std::make_unique<CNode>(/*id=*/0,
|
||||
/*sock=*/nullptr,
|
||||
addr,
|
||||
/*nKeyedNetGroupIn=*/0,
|
||||
/*nLocalHostNonceIn=*/0,
|
||||
CAddress{},
|
||||
/*pszDest=*/std::string{},
|
||||
ConnectionType::OUTBOUND_FULL_RELAY,
|
||||
/*inbound_onion=*/false);
|
||||
};
|
||||
SetReachable(NET_CJDNS, true);
|
||||
|
||||
CAddress addr_ipv4{Lookup("1.2.3.4", 8333, false).value(), NODE_NONE};
|
||||
BOOST_REQUIRE(addr_ipv4.IsValid());
|
||||
BOOST_REQUIRE(addr_ipv4.IsIPv4());
|
||||
|
||||
CAddress addr_ipv6{Lookup("1122:3344:5566:7788:9900:aabb:ccdd:eeff", 8333, false).value(), NODE_NONE};
|
||||
BOOST_REQUIRE(addr_ipv6.IsValid());
|
||||
BOOST_REQUIRE(addr_ipv6.IsIPv6());
|
||||
|
||||
CAddress addr_ipv6_tunnel{Lookup("2002:3344:5566:7788:9900:aabb:ccdd:eeff", 8333, false).value(), NODE_NONE};
|
||||
BOOST_REQUIRE(addr_ipv6_tunnel.IsValid());
|
||||
BOOST_REQUIRE(addr_ipv6_tunnel.IsIPv6());
|
||||
BOOST_REQUIRE(addr_ipv6_tunnel.IsRFC3964());
|
||||
|
||||
CAddress addr_teredo{Lookup("2001:0000:5566:7788:9900:aabb:ccdd:eeff", 8333, false).value(), NODE_NONE};
|
||||
BOOST_REQUIRE(addr_teredo.IsValid());
|
||||
BOOST_REQUIRE(addr_teredo.IsIPv6());
|
||||
BOOST_REQUIRE(addr_teredo.IsRFC4380());
|
||||
|
||||
CAddress addr_onion;
|
||||
BOOST_REQUIRE(addr_onion.SetSpecial("pg6mmjiyjmcrsslvykfwnntlaru7p5svn6y2ymmju6nubxndf4pscryd.onion"));
|
||||
BOOST_REQUIRE(addr_onion.IsValid());
|
||||
BOOST_REQUIRE(addr_onion.IsTor());
|
||||
|
||||
CAddress addr_i2p;
|
||||
BOOST_REQUIRE(addr_i2p.SetSpecial("udhdrtrcetjm5sxzskjyr5ztpeszydbh4dpl3pl4utgqqw2v4jna.b32.i2p"));
|
||||
BOOST_REQUIRE(addr_i2p.IsValid());
|
||||
BOOST_REQUIRE(addr_i2p.IsI2P());
|
||||
|
||||
CService service_cjdns{Lookup("fc00:3344:5566:7788:9900:aabb:ccdd:eeff", 8333, false).value(), NODE_NONE};
|
||||
CAddress addr_cjdns{MaybeFlipIPv6toCJDNS(service_cjdns), NODE_NONE};
|
||||
BOOST_REQUIRE(addr_cjdns.IsValid());
|
||||
BOOST_REQUIRE(addr_cjdns.IsCJDNS());
|
||||
|
||||
const auto peer_ipv4{CreatePeer(addr_ipv4)};
|
||||
const auto peer_ipv6{CreatePeer(addr_ipv6)};
|
||||
const auto peer_ipv6_tunnel{CreatePeer(addr_ipv6_tunnel)};
|
||||
const auto peer_teredo{CreatePeer(addr_teredo)};
|
||||
const auto peer_onion{CreatePeer(addr_onion)};
|
||||
const auto peer_i2p{CreatePeer(addr_i2p)};
|
||||
const auto peer_cjdns{CreatePeer(addr_cjdns)};
|
||||
|
||||
// one local clearnet address - advertise to all but privacy peers
|
||||
AddLocal(addr_ipv4);
|
||||
BOOST_CHECK(GetLocalAddress(*peer_ipv4) == addr_ipv4);
|
||||
BOOST_CHECK(GetLocalAddress(*peer_ipv6) == addr_ipv4);
|
||||
BOOST_CHECK(GetLocalAddress(*peer_ipv6_tunnel) == addr_ipv4);
|
||||
BOOST_CHECK(GetLocalAddress(*peer_teredo) == addr_ipv4);
|
||||
BOOST_CHECK(GetLocalAddress(*peer_cjdns) == addr_ipv4);
|
||||
BOOST_CHECK(!GetLocalAddress(*peer_onion).IsValid());
|
||||
BOOST_CHECK(!GetLocalAddress(*peer_i2p).IsValid());
|
||||
RemoveLocal(addr_ipv4);
|
||||
|
||||
// local privacy addresses - don't advertise to clearnet peers
|
||||
AddLocal(addr_onion);
|
||||
AddLocal(addr_i2p);
|
||||
BOOST_CHECK(!GetLocalAddress(*peer_ipv4).IsValid());
|
||||
BOOST_CHECK(!GetLocalAddress(*peer_ipv6).IsValid());
|
||||
BOOST_CHECK(!GetLocalAddress(*peer_ipv6_tunnel).IsValid());
|
||||
BOOST_CHECK(!GetLocalAddress(*peer_teredo).IsValid());
|
||||
BOOST_CHECK(!GetLocalAddress(*peer_cjdns).IsValid());
|
||||
BOOST_CHECK(GetLocalAddress(*peer_onion) == addr_onion);
|
||||
BOOST_CHECK(GetLocalAddress(*peer_i2p) == addr_i2p);
|
||||
RemoveLocal(addr_onion);
|
||||
RemoveLocal(addr_i2p);
|
||||
|
||||
// local addresses from all networks
|
||||
AddLocal(addr_ipv4);
|
||||
AddLocal(addr_ipv6);
|
||||
AddLocal(addr_ipv6_tunnel);
|
||||
AddLocal(addr_teredo);
|
||||
AddLocal(addr_onion);
|
||||
AddLocal(addr_i2p);
|
||||
AddLocal(addr_cjdns);
|
||||
BOOST_CHECK(GetLocalAddress(*peer_ipv4) == addr_ipv4);
|
||||
BOOST_CHECK(GetLocalAddress(*peer_ipv6) == addr_ipv6);
|
||||
BOOST_CHECK(GetLocalAddress(*peer_ipv6_tunnel) == addr_ipv6);
|
||||
BOOST_CHECK(GetLocalAddress(*peer_teredo) == addr_ipv4);
|
||||
BOOST_CHECK(GetLocalAddress(*peer_onion) == addr_onion);
|
||||
BOOST_CHECK(GetLocalAddress(*peer_i2p) == addr_i2p);
|
||||
BOOST_CHECK(GetLocalAddress(*peer_cjdns) == addr_cjdns);
|
||||
RemoveLocal(addr_ipv4);
|
||||
RemoveLocal(addr_ipv6);
|
||||
RemoveLocal(addr_ipv6_tunnel);
|
||||
RemoveLocal(addr_teredo);
|
||||
RemoveLocal(addr_onion);
|
||||
RemoveLocal(addr_i2p);
|
||||
RemoveLocal(addr_cjdns);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
Loading…
Reference in New Issue
Block a user