aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/net_processing.cpp24
-rwxr-xr-xtest/functional/p2p_addr_relay.py37
2 files changed, 48 insertions, 13 deletions
diff --git a/src/net_processing.cpp b/src/net_processing.cpp
index ce4ac3cd75..96cfbc7079 100644
--- a/src/net_processing.cpp
+++ b/src/net_processing.cpp
@@ -1517,7 +1517,23 @@ void RelayTransaction(const uint256& txid, const uint256& wtxid, const CConnman&
});
}
-static void RelayAddress(const CAddress& addr, bool fReachable, const CConnman& connman)
+/**
+ * Relay (gossip) an address to a few randomly chosen nodes.
+ * We choose the same nodes within a given 24h window (if the list of connected
+ * nodes does not change) and we don't relay to nodes that already know an
+ * address. So within 24h we will likely relay a given address once. This is to
+ * prevent a peer from unjustly giving their address better propagation by sending
+ * it to us repeatedly.
+ * @param[in] originator The peer that sent us the address. We don't want to relay it back.
+ * @param[in] addr Address to relay.
+ * @param[in] fReachable Whether the address' network is reachable. We relay unreachable
+ * addresses less.
+ * @param[in] connman Connection manager to choose nodes to relay to.
+ */
+static void RelayAddress(const CNode& originator,
+ const CAddress& addr,
+ bool fReachable,
+ const CConnman& connman)
{
unsigned int nRelayNodes = fReachable ? 2 : 1; // limited relaying of addresses outside our network(s)
@@ -1531,8 +1547,8 @@ static void RelayAddress(const CAddress& addr, bool fReachable, const CConnman&
std::array<std::pair<uint64_t, CNode*>,2> best{{{0, nullptr}, {0, nullptr}}};
assert(nRelayNodes <= best.size());
- auto sortfunc = [&best, &hasher, nRelayNodes](CNode* pnode) {
- if (pnode->RelayAddrsWithConn()) {
+ auto sortfunc = [&best, &hasher, nRelayNodes, &originator](CNode* pnode) {
+ if (pnode->RelayAddrsWithConn() && pnode != &originator) {
uint64_t hashKey = CSipHasher(hasher).Write(pnode->GetId()).Finalize();
for (unsigned int i = 0; i < nRelayNodes; i++) {
if (hashKey > best[i].first) {
@@ -2637,7 +2653,7 @@ void PeerLogicValidation::ProcessMessage(CNode& pfrom, const std::string& msg_ty
if (addr.nTime > nSince && !pfrom.fGetAddr && vAddr.size() <= 10 && addr.IsRoutable())
{
// Relay to a limited number of other nodes
- RelayAddress(addr, fReachable, m_connman);
+ RelayAddress(pfrom, addr, fReachable, m_connman);
}
// Do not store addresses outside our network
if (fReachable)
diff --git a/test/functional/p2p_addr_relay.py b/test/functional/p2p_addr_relay.py
index 80f262d0d3..91fbd722cf 100755
--- a/test/functional/p2p_addr_relay.py
+++ b/test/functional/p2p_addr_relay.py
@@ -19,8 +19,11 @@ from test_framework.util import (
)
import time
+# Keep this with length <= 10. Addresses from larger messages are not relayed.
ADDRS = []
-for i in range(10):
+num_ipv4_addrs = 10
+
+for i in range(num_ipv4_addrs):
addr = CAddress()
addr.time = int(time.time()) + i
addr.nServices = NODE_NETWORK | NODE_WITNESS
@@ -30,11 +33,15 @@ for i in range(10):
class AddrReceiver(P2PInterface):
+ num_ipv4_received = 0
+
def on_addr(self, message):
for addr in message.addrs:
assert_equal(addr.nServices, 9)
+ if not 8333 <= addr.port < 8343:
+ raise AssertionError("Invalid addr.port of {} (8333-8342 expected)".format(addr.port))
assert addr.ip.startswith('123.123.123.')
- assert (8333 <= addr.port < 8343)
+ self.num_ipv4_received += 1
class AddrTest(BitcoinTestFramework):
@@ -48,21 +55,33 @@ class AddrTest(BitcoinTestFramework):
msg = msg_addr()
self.log.info('Send too-large addr message')
- msg.addrs = ADDRS * 101
+ msg.addrs = ADDRS * 101 # more than 1000 addresses in one message
with self.nodes[0].assert_debug_log(['addr message size = 1010']):
addr_source.send_and_ping(msg)
self.log.info('Check that addr message content is relayed and added to addrman')
- addr_receiver = self.nodes[0].add_p2p_connection(AddrReceiver())
+ num_receivers = 7
+ receivers = []
+ for _ in range(num_receivers):
+ receivers.append(self.nodes[0].add_p2p_connection(AddrReceiver()))
msg.addrs = ADDRS
- with self.nodes[0].assert_debug_log([
- 'Added 10 addresses from 127.0.0.1: 0 tried',
+ with self.nodes[0].assert_debug_log(
+ [
+ 'Added {} addresses from 127.0.0.1: 0 tried'.format(num_ipv4_addrs),
'received: addr (301 bytes) peer=0',
- 'sending addr (301 bytes) peer=1',
- ]):
+ ]
+ ):
addr_source.send_and_ping(msg)
self.nodes[0].setmocktime(int(time.time()) + 30 * 60)
- addr_receiver.sync_with_ping()
+ for receiver in receivers:
+ receiver.sync_with_ping()
+
+ total_ipv4_received = sum(r.num_ipv4_received for r in receivers)
+
+ # Every IPv4 address must be relayed to two peers, other than the
+ # originating node (addr_source).
+ ipv4_branching_factor = 2
+ assert_equal(total_ipv4_received, num_ipv4_addrs * ipv4_branching_factor)
if __name__ == '__main__':