diff --git a/src/net.h b/src/net.h --- a/src/net.h +++ b/src/net.h @@ -747,6 +747,9 @@ int64_t nNextAddrSend GUARDED_BY(cs_sendProcessing){0}; int64_t nNextLocalAddrSend GUARDED_BY(cs_sendProcessing){0}; + const bool m_addr_relay_peer; + bool IsAddrRelayPeer() const { return m_addr_relay_peer; } + // List of block ids we still have to announce. // There is no final sorting before sending, as they are always sent // immediately and in the order requested. @@ -787,6 +790,7 @@ // m_tx_relay == nullptr if we're not relaying transactions with this peer std::unique_ptr m_tx_relay; + // Used for headers announcements - unfiltered blocks to relay std::vector vBlockHashesToAnnounce GUARDED_BY(cs_inventory); diff --git a/src/net.cpp b/src/net.cpp --- a/src/net.cpp +++ b/src/net.cpp @@ -2751,7 +2751,11 @@ bool fInboundIn, bool block_relay_only) : nTimeConnected(GetSystemTimeInSeconds()), addr(addrIn), addrBind(addrBindIn), fInbound(fInboundIn), - nKeyedNetGroup(nKeyedNetGroupIn), addrKnown(5000, 0.001), id(idIn), + nKeyedNetGroup(nKeyedNetGroupIn), addrKnown(5000, 0.001), + // Don't relay addr messages to peers that we connect to as + // block-relay-only peers (to prevent adversaries from inferring these + // links from addr traffic). + m_addr_relay_peer(!block_relay_only), id(idIn), nLocalHostNonce(nLocalHostNonceIn), nLocalServices(nLocalServicesIn), nMyStartingHeight(nMyStartingHeightIn) { hSocket = hSocketIn; diff --git a/src/net_processing.cpp b/src/net_processing.cpp --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -1483,7 +1483,7 @@ assert(nRelayNodes <= best.size()); auto sortfunc = [&best, &hasher, nRelayNodes](CNode *pnode) { - if (pnode->nVersion >= CADDR_TIME_VERSION) { + if (pnode->nVersion >= CADDR_TIME_VERSION && pnode->IsAddrRelayPeer()) { uint64_t hashKey = CSipHasher(hasher).Write(pnode->GetId()).Finalize(); for (unsigned int i = 0; i < nRelayNodes; i++) { @@ -2336,7 +2336,7 @@ UpdatePreferredDownload(pfrom, State(pfrom->GetId())); } - if (!pfrom->fInbound) { + if (!pfrom->fInbound && pfrom->IsAddrRelayPeer()) { // Advertise our address if (fListen && !::ChainstateActive().IsInitialBlockDownload()) { CAddress addr = @@ -2466,6 +2466,9 @@ connman->GetAddressCount() > 1000) { return true; } + if (!pfrom->IsAddrRelayPeer()) { + return true; + } if (vAddr.size() > 1000) { LOCK(cs_main); Misbehaving(pfrom, 20, "oversized-addr"); @@ -3564,6 +3567,13 @@ pfrom->GetId()); return true; } + if (!pfrom->IsAddrRelayPeer()) { + LogPrint(BCLog::NET, + "Ignoring \"getaddr\" from block-relay-only connection. " + "peer=%d\n", + pfrom->GetId()); + return true; + } // Only send one GetAddr response per connection to reduce resource // waste and discourage addr stamping of INV announcements. @@ -4287,7 +4297,8 @@ // Address refresh broadcast int64_t nNow = GetTimeMicros(); - if (!::ChainstateActive().IsInitialBlockDownload() && + if (pto->IsAddrRelayPeer() && + !::ChainstateActive().IsInitialBlockDownload() && pto->nNextLocalAddrSend < nNow) { AdvertiseLocal(pto); pto->nNextLocalAddrSend = @@ -4297,7 +4308,7 @@ // // Message: addr // - if (pto->nNextAddrSend < nNow) { + if (pto->IsAddrRelayPeer() && pto->nNextAddrSend < nNow) { pto->nNextAddrSend = PoissonNextSend(nNow, AVG_ADDRESS_BROADCAST_INTERVAL); std::vector vAddr;