2022-12-24 23:49:50 +00:00
|
|
|
// Copyright (c) 2011-2022 The Bitcoin Core developers
|
2014-12-13 12:09:33 +08:00
|
|
|
// Distributed under the MIT software license, see the accompanying
|
2014-03-18 10:11:00 +01:00
|
|
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
|
|
|
|
2011-09-06 16:09:04 -04:00
|
|
|
// Unit tests for denial-of-service detection/prevention code
|
2013-04-13 00:13:08 -05:00
|
|
|
|
2017-10-05 16:40:43 -04:00
|
|
|
#include <banman.h>
|
2017-11-10 13:57:53 +13:00
|
|
|
#include <chainparams.h>
|
2023-03-23 12:23:29 +01:00
|
|
|
#include <common/args.h>
|
2017-11-10 13:57:53 +13:00
|
|
|
#include <net.h>
|
|
|
|
#include <net_processing.h>
|
2019-09-15 16:04:57 +03:00
|
|
|
#include <pubkey.h>
|
2017-11-10 13:57:53 +13:00
|
|
|
#include <script/sign.h>
|
2019-06-06 22:52:24 +02:00
|
|
|
#include <script/signingprovider.h>
|
2017-11-10 13:57:53 +13:00
|
|
|
#include <serialize.h>
|
2020-04-08 19:34:56 +02:00
|
|
|
#include <test/util/net.h>
|
2023-01-22 09:57:19 -08:00
|
|
|
#include <test/util/random.h>
|
2020-04-08 19:34:56 +02:00
|
|
|
#include <test/util/setup_common.h>
|
2022-02-07 17:13:54 +00:00
|
|
|
#include <timedata.h>
|
2020-02-12 23:01:45 -05:00
|
|
|
#include <util/string.h>
|
2019-06-24 17:22:28 +02:00
|
|
|
#include <util/time.h>
|
2017-11-10 13:57:53 +13:00
|
|
|
#include <validation.h>
|
|
|
|
|
2021-01-20 11:26:43 +01:00
|
|
|
#include <array>
|
2012-01-03 23:33:31 +01:00
|
|
|
#include <stdint.h>
|
|
|
|
|
2013-04-13 00:13:08 -05:00
|
|
|
#include <boost/test/unit_test.hpp>
|
|
|
|
|
2018-05-02 17:14:48 +02:00
|
|
|
static CService ip(uint32_t i)
|
2012-01-03 23:33:31 +01:00
|
|
|
{
|
|
|
|
struct in_addr s;
|
|
|
|
s.s_addr = i;
|
2013-05-07 15:16:25 +02:00
|
|
|
return CService(CNetAddr(s), Params().GetDefaultPort());
|
2012-01-03 23:33:31 +01:00
|
|
|
}
|
2011-09-06 16:09:04 -04:00
|
|
|
|
2018-05-23 14:14:58 +02:00
|
|
|
BOOST_FIXTURE_TEST_SUITE(denialofservice_tests, TestingSetup)
|
2011-09-06 16:09:04 -04:00
|
|
|
|
2017-10-19 11:42:47 -04:00
|
|
|
// Test eviction of an outbound peer whose chain never advances
|
|
|
|
// Mock a node connection, and use mocktime to simulate a peer
|
|
|
|
// which never sends any headers messages. PeerLogic should
|
|
|
|
// decide to evict that outbound peer, after the appropriate timeouts.
|
|
|
|
// Note that we protect 4 outbound nodes from being subject to
|
|
|
|
// this logic; this test takes advantage of that protection only
|
|
|
|
// being applied to nodes which send headers with sufficient
|
|
|
|
// work.
|
|
|
|
BOOST_AUTO_TEST_CASE(outbound_slow_chain_eviction)
|
|
|
|
{
|
2022-09-07 13:57:18 +10:00
|
|
|
LOCK(NetEventsInterface::g_msgproc_mutex);
|
|
|
|
|
2022-02-07 17:13:54 +00:00
|
|
|
ConnmanTestMsg& connman = static_cast<ConnmanTestMsg&>(*m_node.connman);
|
2021-10-07 13:22:51 +02:00
|
|
|
// Disable inactivity checks for this test to avoid interference
|
2022-02-07 17:13:54 +00:00
|
|
|
connman.SetPeerConnectTimeout(99999s);
|
|
|
|
PeerManager& peerman = *m_node.peerman;
|
2017-10-19 11:42:47 -04:00
|
|
|
|
|
|
|
// Mock an outbound peer
|
|
|
|
CAddress addr1(ip(0xa0b0c001), NODE_NONE);
|
2020-03-29 23:12:45 +02:00
|
|
|
NodeId id{0};
|
2021-04-23 15:15:23 +02:00
|
|
|
CNode dummyNode1{id++,
|
|
|
|
/*sock=*/nullptr,
|
|
|
|
addr1,
|
|
|
|
/*nKeyedNetGroupIn=*/0,
|
|
|
|
/*nLocalHostNonceIn=*/0,
|
|
|
|
CAddress(),
|
|
|
|
/*addrNameIn=*/"",
|
|
|
|
ConnectionType::OUTBOUND_FULL_RELAY,
|
|
|
|
/*inbound_onion=*/false};
|
2017-10-19 11:42:47 -04:00
|
|
|
|
2022-02-07 17:13:54 +00:00
|
|
|
connman.Handshake(
|
|
|
|
/*node=*/dummyNode1,
|
|
|
|
/*successfully_connected=*/true,
|
|
|
|
/*remote_services=*/ServiceFlags(NODE_NETWORK | NODE_WITNESS),
|
2020-07-20 20:28:37 +01:00
|
|
|
/*local_services=*/ServiceFlags(NODE_NETWORK | NODE_WITNESS),
|
2022-02-07 17:13:54 +00:00
|
|
|
/*version=*/PROTOCOL_VERSION,
|
|
|
|
/*relay_txs=*/true);
|
|
|
|
TestOnlyResetTimeData();
|
2017-10-19 11:42:47 -04:00
|
|
|
|
|
|
|
// This test requires that we have a chain with non-zero work.
|
2018-04-04 14:04:10 +02:00
|
|
|
{
|
|
|
|
LOCK(cs_main);
|
2020-09-09 16:15:15 -04:00
|
|
|
BOOST_CHECK(m_node.chainman->ActiveChain().Tip() != nullptr);
|
|
|
|
BOOST_CHECK(m_node.chainman->ActiveChain().Tip()->nChainWork > 0);
|
2018-04-04 14:04:10 +02:00
|
|
|
}
|
2017-10-19 11:42:47 -04:00
|
|
|
|
|
|
|
// Test starts here
|
2022-09-13 12:22:18 +10:00
|
|
|
BOOST_CHECK(peerman.SendMessages(&dummyNode1)); // should result in getheaders
|
|
|
|
|
2018-04-04 14:04:10 +02:00
|
|
|
{
|
2019-06-11 20:10:25 -04:00
|
|
|
LOCK(dummyNode1.cs_vSend);
|
net: add have_next_message argument to Transport::GetBytesToSend()
Before this commit, there are only two possibly outcomes for the "more" prediction
in Transport::GetBytesToSend():
* true: the transport itself has more to send, so the answer is certainly yes.
* false: the transport has nothing further to send, but if vSendMsg has more message(s)
left, that still will result in more wire bytes after the next
SetMessageToSend().
For the BIP324 v2 transport, there will arguably be a third state:
* definitely not: the transport has nothing further to send, but even if vSendMsg has
more messages left, they can't be sent (right now). This happens
before the handshake is complete.
To implement this, we move the entire decision logic to the Transport, by adding a
boolean to GetBytesToSend(), called have_next_message, which informs the transport
whether more messages are available. The return values are still true and false, but
they mean "definitely yes" and "definitely no", rather than "yes" and "maybe".
2023-08-16 13:21:35 -04:00
|
|
|
const auto& [to_send, _more, _msg_type] = dummyNode1.m_transport->GetBytesToSend(false);
|
net: move message conversion to wire bytes from PushMessage to SocketSendData
This furthers transport abstraction by removing the assumption that a message
can always immediately be converted to wire bytes. This assumption does not hold
for the v2 transport proposed by BIP324, as no messages can be sent before the
handshake completes.
This is done by only keeping (complete) CSerializedNetMsg objects in vSendMsg,
rather than the resulting bytes (for header and payload) that need to be sent.
In SocketSendData, these objects are handed to the transport as permitted by it,
and sending out the bytes the transport tells us to send. This also removes the
nSendOffset member variable in CNode, as keeping track of how much has been sent
is now a responsability of the transport.
This is not a pure refactor, and has the following effects even for the current
v1 transport:
* Checksum calculation now happens in SocketSendData rather than PushMessage.
For non-optimistic-send messages, that means this computation now happens in
the network thread rather than the message handler thread (generally a good
thing, as the message handler thread is more of a computational bottleneck).
* Checksum calculation now happens while holding the cs_vSend lock. This is
technically unnecessary for the v1 transport, as messages are encoded
independent from one another, but is untenable for the v2 transport anyway.
* Statistics updates about per-message sent bytes now happen when those bytes
are actually handed to the OS, rather than at PushMessage time.
2023-08-16 13:31:50 -04:00
|
|
|
BOOST_CHECK(!to_send.empty());
|
2018-04-04 14:04:10 +02:00
|
|
|
}
|
net: move message conversion to wire bytes from PushMessage to SocketSendData
This furthers transport abstraction by removing the assumption that a message
can always immediately be converted to wire bytes. This assumption does not hold
for the v2 transport proposed by BIP324, as no messages can be sent before the
handshake completes.
This is done by only keeping (complete) CSerializedNetMsg objects in vSendMsg,
rather than the resulting bytes (for header and payload) that need to be sent.
In SocketSendData, these objects are handed to the transport as permitted by it,
and sending out the bytes the transport tells us to send. This also removes the
nSendOffset member variable in CNode, as keeping track of how much has been sent
is now a responsability of the transport.
This is not a pure refactor, and has the following effects even for the current
v1 transport:
* Checksum calculation now happens in SocketSendData rather than PushMessage.
For non-optimistic-send messages, that means this computation now happens in
the network thread rather than the message handler thread (generally a good
thing, as the message handler thread is more of a computational bottleneck).
* Checksum calculation now happens while holding the cs_vSend lock. This is
technically unnecessary for the v1 transport, as messages are encoded
independent from one another, but is untenable for the v2 transport anyway.
* Statistics updates about per-message sent bytes now happen when those bytes
are actually handed to the OS, rather than at PushMessage time.
2023-08-16 13:31:50 -04:00
|
|
|
connman.FlushSendBuffer(dummyNode1);
|
2017-10-19 11:42:47 -04:00
|
|
|
|
|
|
|
int64_t nStartTime = GetTime();
|
|
|
|
// Wait 21 minutes
|
|
|
|
SetMockTime(nStartTime+21*60);
|
2022-09-13 12:22:18 +10:00
|
|
|
BOOST_CHECK(peerman.SendMessages(&dummyNode1)); // should result in getheaders
|
2018-04-04 14:04:10 +02:00
|
|
|
{
|
2019-06-11 20:10:25 -04:00
|
|
|
LOCK(dummyNode1.cs_vSend);
|
net: add have_next_message argument to Transport::GetBytesToSend()
Before this commit, there are only two possibly outcomes for the "more" prediction
in Transport::GetBytesToSend():
* true: the transport itself has more to send, so the answer is certainly yes.
* false: the transport has nothing further to send, but if vSendMsg has more message(s)
left, that still will result in more wire bytes after the next
SetMessageToSend().
For the BIP324 v2 transport, there will arguably be a third state:
* definitely not: the transport has nothing further to send, but even if vSendMsg has
more messages left, they can't be sent (right now). This happens
before the handshake is complete.
To implement this, we move the entire decision logic to the Transport, by adding a
boolean to GetBytesToSend(), called have_next_message, which informs the transport
whether more messages are available. The return values are still true and false, but
they mean "definitely yes" and "definitely no", rather than "yes" and "maybe".
2023-08-16 13:21:35 -04:00
|
|
|
const auto& [to_send, _more, _msg_type] = dummyNode1.m_transport->GetBytesToSend(false);
|
net: move message conversion to wire bytes from PushMessage to SocketSendData
This furthers transport abstraction by removing the assumption that a message
can always immediately be converted to wire bytes. This assumption does not hold
for the v2 transport proposed by BIP324, as no messages can be sent before the
handshake completes.
This is done by only keeping (complete) CSerializedNetMsg objects in vSendMsg,
rather than the resulting bytes (for header and payload) that need to be sent.
In SocketSendData, these objects are handed to the transport as permitted by it,
and sending out the bytes the transport tells us to send. This also removes the
nSendOffset member variable in CNode, as keeping track of how much has been sent
is now a responsability of the transport.
This is not a pure refactor, and has the following effects even for the current
v1 transport:
* Checksum calculation now happens in SocketSendData rather than PushMessage.
For non-optimistic-send messages, that means this computation now happens in
the network thread rather than the message handler thread (generally a good
thing, as the message handler thread is more of a computational bottleneck).
* Checksum calculation now happens while holding the cs_vSend lock. This is
technically unnecessary for the v1 transport, as messages are encoded
independent from one another, but is untenable for the v2 transport anyway.
* Statistics updates about per-message sent bytes now happen when those bytes
are actually handed to the OS, rather than at PushMessage time.
2023-08-16 13:31:50 -04:00
|
|
|
BOOST_CHECK(!to_send.empty());
|
2018-04-04 14:04:10 +02:00
|
|
|
}
|
2017-10-19 11:42:47 -04:00
|
|
|
// Wait 3 more minutes
|
|
|
|
SetMockTime(nStartTime+24*60);
|
2022-09-13 12:22:18 +10:00
|
|
|
BOOST_CHECK(peerman.SendMessages(&dummyNode1)); // should result in disconnect
|
2017-10-19 11:42:47 -04:00
|
|
|
BOOST_CHECK(dummyNode1.fDisconnect == true);
|
|
|
|
|
2022-02-07 17:13:54 +00:00
|
|
|
peerman.FinalizeNode(dummyNode1);
|
2017-10-19 11:42:47 -04:00
|
|
|
}
|
|
|
|
|
2023-02-08 17:42:12 -05:00
|
|
|
static void AddRandomOutboundPeer(NodeId& id, std::vector<CNode*>& vNodes, PeerManager& peerLogic, ConnmanTestMsg& connman, ConnectionType connType, bool onion_peer = false)
|
2017-10-26 10:32:46 -04:00
|
|
|
{
|
2023-02-08 17:42:12 -05:00
|
|
|
CAddress addr;
|
|
|
|
|
|
|
|
if (onion_peer) {
|
|
|
|
auto tor_addr{g_insecure_rand_ctx.randbytes(ADDR_TORV3_SIZE)};
|
|
|
|
BOOST_REQUIRE(addr.SetSpecial(OnionToString(tor_addr)));
|
|
|
|
}
|
|
|
|
|
|
|
|
while (!addr.IsRoutable()) {
|
|
|
|
addr = CAddress(ip(g_insecure_rand_ctx.randbits(32)), NODE_NONE);
|
|
|
|
}
|
|
|
|
|
2021-04-23 15:15:23 +02:00
|
|
|
vNodes.emplace_back(new CNode{id++,
|
|
|
|
/*sock=*/nullptr,
|
|
|
|
addr,
|
|
|
|
/*nKeyedNetGroupIn=*/0,
|
|
|
|
/*nLocalHostNonceIn=*/0,
|
|
|
|
CAddress(),
|
|
|
|
/*addrNameIn=*/"",
|
|
|
|
connType,
|
|
|
|
/*inbound_onion=*/false});
|
2017-10-26 10:32:46 -04:00
|
|
|
CNode &node = *vNodes.back();
|
2020-06-05 10:22:53 +03:00
|
|
|
node.SetCommonVersion(PROTOCOL_VERSION);
|
2017-10-26 10:32:46 -04:00
|
|
|
|
2020-07-20 20:28:37 +01:00
|
|
|
peerLogic.InitializeNode(node, ServiceFlags(NODE_NETWORK | NODE_WITNESS));
|
2017-10-26 10:32:46 -04:00
|
|
|
node.fSuccessfullyConnected = true;
|
|
|
|
|
2020-04-08 19:34:56 +02:00
|
|
|
connman.AddTestNode(node);
|
2017-10-26 10:32:46 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
BOOST_AUTO_TEST_CASE(stale_tip_peer_management)
|
|
|
|
{
|
2020-03-29 23:12:45 +02:00
|
|
|
NodeId id{0};
|
2023-09-12 13:42:36 +02:00
|
|
|
auto connman = std::make_unique<ConnmanTestMsg>(0x1337, 0x1337, *m_node.addrman, *m_node.netgroupman, Params());
|
2023-04-20 13:05:23 +02:00
|
|
|
auto peerLogic = PeerManager::make(*connman, *m_node.addrman, nullptr, *m_node.chainman, *m_node.mempool, {});
|
2017-10-05 11:52:50 -04:00
|
|
|
|
2020-05-12 17:29:36 +08:00
|
|
|
constexpr int max_outbound_full_relay = MAX_OUTBOUND_FULL_RELAY_CONNECTIONS;
|
2017-10-26 10:32:46 -04:00
|
|
|
CConnman::Options options;
|
2023-08-30 13:51:09 -07:00
|
|
|
options.m_max_automatic_connections = DEFAULT_MAX_PEER_CONNECTIONS;
|
2017-10-26 10:32:46 -04:00
|
|
|
|
2021-12-13 12:11:14 +01:00
|
|
|
const auto time_init{GetTime<std::chrono::seconds>()};
|
|
|
|
SetMockTime(time_init);
|
2022-05-18 18:36:31 +02:00
|
|
|
const auto time_later{time_init + 3 * std::chrono::seconds{m_node.chainman->GetConsensus().nPowTargetSpacing} + 1s};
|
2017-10-26 10:32:46 -04:00
|
|
|
connman->Init(options);
|
|
|
|
std::vector<CNode *> vNodes;
|
|
|
|
|
|
|
|
// Mock some outbound peers
|
2020-04-08 19:34:56 +02:00
|
|
|
for (int i = 0; i < max_outbound_full_relay; ++i) {
|
2020-03-29 23:12:45 +02:00
|
|
|
AddRandomOutboundPeer(id, vNodes, *peerLogic, *connman, ConnectionType::OUTBOUND_FULL_RELAY);
|
2017-10-26 10:32:46 -04:00
|
|
|
}
|
|
|
|
|
2020-09-08 08:03:01 +02:00
|
|
|
peerLogic->CheckForStaleTipAndEvictPeers();
|
2017-10-26 10:32:46 -04:00
|
|
|
|
|
|
|
// No nodes should be marked for disconnection while we have no extra peers
|
|
|
|
for (const CNode *node : vNodes) {
|
|
|
|
BOOST_CHECK(node->fDisconnect == false);
|
|
|
|
}
|
|
|
|
|
2021-12-13 12:11:14 +01:00
|
|
|
SetMockTime(time_later);
|
2017-10-26 10:32:46 -04:00
|
|
|
|
|
|
|
// Now tip should definitely be stale, and we should look for an extra
|
|
|
|
// outbound peer
|
2020-09-08 08:03:01 +02:00
|
|
|
peerLogic->CheckForStaleTipAndEvictPeers();
|
2017-10-26 10:32:46 -04:00
|
|
|
BOOST_CHECK(connman->GetTryNewOutboundPeer());
|
|
|
|
|
|
|
|
// Still no peers should be marked for disconnection
|
|
|
|
for (const CNode *node : vNodes) {
|
|
|
|
BOOST_CHECK(node->fDisconnect == false);
|
|
|
|
}
|
|
|
|
|
|
|
|
// If we add one more peer, something should get marked for eviction
|
|
|
|
// on the next check (since we're mocking the time to be in the future, the
|
|
|
|
// required time connected check should be satisfied).
|
2021-12-13 12:11:14 +01:00
|
|
|
SetMockTime(time_init);
|
2020-03-29 23:12:45 +02:00
|
|
|
AddRandomOutboundPeer(id, vNodes, *peerLogic, *connman, ConnectionType::OUTBOUND_FULL_RELAY);
|
2021-12-13 12:11:14 +01:00
|
|
|
SetMockTime(time_later);
|
2017-10-26 10:32:46 -04:00
|
|
|
|
2020-09-08 08:03:01 +02:00
|
|
|
peerLogic->CheckForStaleTipAndEvictPeers();
|
|
|
|
for (int i = 0; i < max_outbound_full_relay; ++i) {
|
2017-10-26 10:32:46 -04:00
|
|
|
BOOST_CHECK(vNodes[i]->fDisconnect == false);
|
|
|
|
}
|
|
|
|
// Last added node should get marked for eviction
|
|
|
|
BOOST_CHECK(vNodes.back()->fDisconnect == true);
|
|
|
|
|
|
|
|
vNodes.back()->fDisconnect = false;
|
|
|
|
|
|
|
|
// Update the last announced block time for the last
|
|
|
|
// peer, and check that the next newest node gets evicted.
|
2022-02-20 15:20:15 +01:00
|
|
|
peerLogic->UpdateLastBlockAnnounceTime(vNodes.back()->GetId(), GetTime());
|
2017-10-26 10:32:46 -04:00
|
|
|
|
2020-09-08 08:03:01 +02:00
|
|
|
peerLogic->CheckForStaleTipAndEvictPeers();
|
|
|
|
for (int i = 0; i < max_outbound_full_relay - 1; ++i) {
|
2017-10-26 10:32:46 -04:00
|
|
|
BOOST_CHECK(vNodes[i]->fDisconnect == false);
|
|
|
|
}
|
2019-03-09 12:55:06 -05:00
|
|
|
BOOST_CHECK(vNodes[max_outbound_full_relay-1]->fDisconnect == true);
|
2017-10-26 10:32:46 -04:00
|
|
|
BOOST_CHECK(vNodes.back()->fDisconnect == false);
|
|
|
|
|
2023-02-08 17:42:12 -05:00
|
|
|
vNodes[max_outbound_full_relay - 1]->fDisconnect = false;
|
|
|
|
|
|
|
|
// Add an onion peer, that will be protected because it is the only one for
|
|
|
|
// its network, so another peer gets disconnected instead.
|
|
|
|
SetMockTime(time_init);
|
|
|
|
AddRandomOutboundPeer(id, vNodes, *peerLogic, *connman, ConnectionType::OUTBOUND_FULL_RELAY, /*onion_peer=*/true);
|
|
|
|
SetMockTime(time_later);
|
|
|
|
peerLogic->CheckForStaleTipAndEvictPeers();
|
|
|
|
|
|
|
|
for (int i = 0; i < max_outbound_full_relay - 2; ++i) {
|
|
|
|
BOOST_CHECK(vNodes[i]->fDisconnect == false);
|
|
|
|
}
|
|
|
|
BOOST_CHECK(vNodes[max_outbound_full_relay - 2]->fDisconnect == false);
|
|
|
|
BOOST_CHECK(vNodes[max_outbound_full_relay - 1]->fDisconnect == true);
|
|
|
|
BOOST_CHECK(vNodes[max_outbound_full_relay]->fDisconnect == false);
|
|
|
|
|
|
|
|
// Add a second onion peer which won't be protected
|
|
|
|
SetMockTime(time_init);
|
|
|
|
AddRandomOutboundPeer(id, vNodes, *peerLogic, *connman, ConnectionType::OUTBOUND_FULL_RELAY, /*onion_peer=*/true);
|
|
|
|
SetMockTime(time_later);
|
|
|
|
peerLogic->CheckForStaleTipAndEvictPeers();
|
|
|
|
|
|
|
|
BOOST_CHECK(vNodes.back()->fDisconnect == true);
|
|
|
|
|
2017-10-26 10:32:46 -04:00
|
|
|
for (const CNode *node : vNodes) {
|
2020-10-23 10:28:33 +01:00
|
|
|
peerLogic->FinalizeNode(*node);
|
2017-10-26 10:32:46 -04:00
|
|
|
}
|
|
|
|
|
2020-04-08 19:34:56 +02:00
|
|
|
connman->ClearTestNodes();
|
2017-10-26 10:32:46 -04:00
|
|
|
}
|
|
|
|
|
2021-11-27 00:48:41 +01:00
|
|
|
BOOST_AUTO_TEST_CASE(block_relay_only_eviction)
|
|
|
|
{
|
2020-03-29 23:12:45 +02:00
|
|
|
NodeId id{0};
|
2023-09-12 13:42:36 +02:00
|
|
|
auto connman = std::make_unique<ConnmanTestMsg>(0x1337, 0x1337, *m_node.addrman, *m_node.netgroupman, Params());
|
2023-04-20 13:05:23 +02:00
|
|
|
auto peerLogic = PeerManager::make(*connman, *m_node.addrman, nullptr, *m_node.chainman, *m_node.mempool, {});
|
2021-11-27 00:48:41 +01:00
|
|
|
|
|
|
|
constexpr int max_outbound_block_relay{MAX_BLOCK_RELAY_ONLY_CONNECTIONS};
|
|
|
|
constexpr int64_t MINIMUM_CONNECT_TIME{30};
|
|
|
|
CConnman::Options options;
|
2023-08-30 13:51:09 -07:00
|
|
|
options.m_max_automatic_connections = DEFAULT_MAX_PEER_CONNECTIONS;
|
2021-11-27 00:48:41 +01:00
|
|
|
|
|
|
|
connman->Init(options);
|
|
|
|
std::vector<CNode*> vNodes;
|
|
|
|
|
|
|
|
// Add block-relay-only peers up to the limit
|
|
|
|
for (int i = 0; i < max_outbound_block_relay; ++i) {
|
2020-03-29 23:12:45 +02:00
|
|
|
AddRandomOutboundPeer(id, vNodes, *peerLogic, *connman, ConnectionType::BLOCK_RELAY);
|
2021-11-27 00:48:41 +01:00
|
|
|
}
|
|
|
|
peerLogic->CheckForStaleTipAndEvictPeers();
|
|
|
|
|
|
|
|
for (int i = 0; i < max_outbound_block_relay; ++i) {
|
|
|
|
BOOST_CHECK(vNodes[i]->fDisconnect == false);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add an extra block-relay-only peer breaking the limit (mocks logic in ThreadOpenConnections)
|
2020-03-29 23:12:45 +02:00
|
|
|
AddRandomOutboundPeer(id, vNodes, *peerLogic, *connman, ConnectionType::BLOCK_RELAY);
|
2021-11-27 00:48:41 +01:00
|
|
|
peerLogic->CheckForStaleTipAndEvictPeers();
|
|
|
|
|
|
|
|
// The extra peer should only get marked for eviction after MINIMUM_CONNECT_TIME
|
|
|
|
for (int i = 0; i < max_outbound_block_relay; ++i) {
|
|
|
|
BOOST_CHECK(vNodes[i]->fDisconnect == false);
|
|
|
|
}
|
|
|
|
BOOST_CHECK(vNodes.back()->fDisconnect == false);
|
|
|
|
|
|
|
|
SetMockTime(GetTime() + MINIMUM_CONNECT_TIME + 1);
|
|
|
|
peerLogic->CheckForStaleTipAndEvictPeers();
|
|
|
|
for (int i = 0; i < max_outbound_block_relay; ++i) {
|
|
|
|
BOOST_CHECK(vNodes[i]->fDisconnect == false);
|
|
|
|
}
|
|
|
|
BOOST_CHECK(vNodes.back()->fDisconnect == true);
|
|
|
|
|
|
|
|
// Update the last block time for the extra peer,
|
|
|
|
// and check that the next youngest peer gets evicted.
|
|
|
|
vNodes.back()->fDisconnect = false;
|
2021-12-13 12:32:28 +01:00
|
|
|
vNodes.back()->m_last_block_time = GetTime<std::chrono::seconds>();
|
2021-11-27 00:48:41 +01:00
|
|
|
|
|
|
|
peerLogic->CheckForStaleTipAndEvictPeers();
|
|
|
|
for (int i = 0; i < max_outbound_block_relay - 1; ++i) {
|
|
|
|
BOOST_CHECK(vNodes[i]->fDisconnect == false);
|
|
|
|
}
|
|
|
|
BOOST_CHECK(vNodes[max_outbound_block_relay - 1]->fDisconnect == true);
|
|
|
|
BOOST_CHECK(vNodes.back()->fDisconnect == false);
|
|
|
|
|
|
|
|
for (const CNode* node : vNodes) {
|
|
|
|
peerLogic->FinalizeNode(*node);
|
|
|
|
}
|
|
|
|
connman->ClearTestNodes();
|
|
|
|
}
|
|
|
|
|
2020-07-14 09:52:57 +02:00
|
|
|
BOOST_AUTO_TEST_CASE(peer_discouragement)
|
2011-09-06 16:09:04 -04:00
|
|
|
{
|
2022-09-07 13:57:18 +10:00
|
|
|
LOCK(NetEventsInterface::g_msgproc_mutex);
|
|
|
|
|
2021-01-14 09:33:04 +01:00
|
|
|
auto banman = std::make_unique<BanMan>(m_args.GetDataDirBase() / "banlist", nullptr, DEFAULT_MISBEHAVING_BANTIME);
|
2023-09-12 13:42:36 +02:00
|
|
|
auto connman = std::make_unique<ConnmanTestMsg>(0x1337, 0x1337, *m_node.addrman, *m_node.netgroupman, Params());
|
2023-04-20 13:05:23 +02:00
|
|
|
auto peerLogic = PeerManager::make(*connman, *m_node.addrman, banman.get(), *m_node.chainman, *m_node.mempool, {});
|
2016-12-27 17:13:04 -05:00
|
|
|
|
2021-01-20 11:54:17 +01:00
|
|
|
CNetAddr tor_netaddr;
|
|
|
|
BOOST_REQUIRE(
|
|
|
|
tor_netaddr.SetSpecial("pg6mmjiyjmcrsslvykfwnntlaru7p5svn6y2ymmju6nubxndf4pscryd.onion"));
|
|
|
|
const CService tor_service{tor_netaddr, Params().GetDefaultPort()};
|
|
|
|
|
|
|
|
const std::array<CAddress, 3> addr{CAddress{ip(0xa0b0c001), NODE_NONE},
|
|
|
|
CAddress{ip(0xa0b0c002), NODE_NONE},
|
|
|
|
CAddress{tor_service, NODE_NONE}};
|
2021-01-20 11:26:43 +01:00
|
|
|
|
|
|
|
const CNetAddr other_addr{ip(0xa0b0ff01)}; // Not any of addr[].
|
|
|
|
|
2021-01-20 11:54:17 +01:00
|
|
|
std::array<CNode*, 3> nodes;
|
2021-01-20 11:26:43 +01:00
|
|
|
|
2017-10-05 13:10:58 -04:00
|
|
|
banman->ClearBanned();
|
2020-03-29 23:12:45 +02:00
|
|
|
NodeId id{0};
|
2021-04-23 15:15:23 +02:00
|
|
|
nodes[0] = new CNode{id++,
|
|
|
|
/*sock=*/nullptr,
|
|
|
|
addr[0],
|
|
|
|
/*nKeyedNetGroupIn=*/0,
|
|
|
|
/*nLocalHostNonceIn=*/0,
|
|
|
|
CAddress(),
|
|
|
|
/*addrNameIn=*/"",
|
|
|
|
ConnectionType::INBOUND,
|
|
|
|
/*inbound_onion=*/false};
|
2021-01-20 11:26:43 +01:00
|
|
|
nodes[0]->SetCommonVersion(PROTOCOL_VERSION);
|
2020-07-20 20:28:37 +01:00
|
|
|
peerLogic->InitializeNode(*nodes[0], NODE_NETWORK);
|
2021-01-20 11:26:43 +01:00
|
|
|
nodes[0]->fSuccessfullyConnected = true;
|
2020-04-08 19:34:56 +02:00
|
|
|
connman->AddTestNode(*nodes[0]);
|
2022-05-16 16:45:53 +02:00
|
|
|
peerLogic->UnitTestMisbehaving(nodes[0]->GetId(), DISCOURAGEMENT_THRESHOLD); // Should be discouraged
|
2022-09-13 12:22:18 +10:00
|
|
|
BOOST_CHECK(peerLogic->SendMessages(nodes[0]));
|
|
|
|
|
2021-01-20 11:26:43 +01:00
|
|
|
BOOST_CHECK(banman->IsDiscouraged(addr[0]));
|
2021-01-20 11:40:01 +01:00
|
|
|
BOOST_CHECK(nodes[0]->fDisconnect);
|
2021-01-20 11:26:43 +01:00
|
|
|
BOOST_CHECK(!banman->IsDiscouraged(other_addr)); // Different address, not discouraged
|
|
|
|
|
2021-04-23 15:15:23 +02:00
|
|
|
nodes[1] = new CNode{id++,
|
|
|
|
/*sock=*/nullptr,
|
|
|
|
addr[1],
|
|
|
|
/*nKeyedNetGroupIn=*/1,
|
|
|
|
/*nLocalHostNonceIn=*/1,
|
|
|
|
CAddress(),
|
|
|
|
/*addrNameIn=*/"",
|
|
|
|
ConnectionType::INBOUND,
|
|
|
|
/*inbound_onion=*/false};
|
2021-01-20 11:26:43 +01:00
|
|
|
nodes[1]->SetCommonVersion(PROTOCOL_VERSION);
|
2020-07-20 20:28:37 +01:00
|
|
|
peerLogic->InitializeNode(*nodes[1], NODE_NETWORK);
|
2021-01-20 11:26:43 +01:00
|
|
|
nodes[1]->fSuccessfullyConnected = true;
|
2020-04-08 19:34:56 +02:00
|
|
|
connman->AddTestNode(*nodes[1]);
|
2022-05-16 16:45:53 +02:00
|
|
|
peerLogic->UnitTestMisbehaving(nodes[1]->GetId(), DISCOURAGEMENT_THRESHOLD - 1);
|
2022-09-13 12:22:18 +10:00
|
|
|
BOOST_CHECK(peerLogic->SendMessages(nodes[1]));
|
2021-01-20 11:40:01 +01:00
|
|
|
// [0] is still discouraged/disconnected.
|
|
|
|
BOOST_CHECK(banman->IsDiscouraged(addr[0]));
|
|
|
|
BOOST_CHECK(nodes[0]->fDisconnect);
|
|
|
|
// [1] is not discouraged/disconnected yet.
|
|
|
|
BOOST_CHECK(!banman->IsDiscouraged(addr[1]));
|
|
|
|
BOOST_CHECK(!nodes[1]->fDisconnect);
|
2022-05-16 16:45:53 +02:00
|
|
|
peerLogic->UnitTestMisbehaving(nodes[1]->GetId(), 1); // [1] reaches discouragement threshold
|
2022-09-13 12:22:18 +10:00
|
|
|
BOOST_CHECK(peerLogic->SendMessages(nodes[1]));
|
2021-01-20 11:40:01 +01:00
|
|
|
// Expect both [0] and [1] to be discouraged/disconnected now.
|
2021-01-20 11:26:43 +01:00
|
|
|
BOOST_CHECK(banman->IsDiscouraged(addr[0]));
|
2021-01-20 11:40:01 +01:00
|
|
|
BOOST_CHECK(nodes[0]->fDisconnect);
|
2021-01-20 11:26:43 +01:00
|
|
|
BOOST_CHECK(banman->IsDiscouraged(addr[1]));
|
2021-01-20 11:40:01 +01:00
|
|
|
BOOST_CHECK(nodes[1]->fDisconnect);
|
2017-10-19 11:42:47 -04:00
|
|
|
|
2021-01-20 11:54:17 +01:00
|
|
|
// Make sure non-IP peers are discouraged and disconnected properly.
|
|
|
|
|
2021-04-23 15:15:23 +02:00
|
|
|
nodes[2] = new CNode{id++,
|
|
|
|
/*sock=*/nullptr,
|
|
|
|
addr[2],
|
|
|
|
/*nKeyedNetGroupIn=*/1,
|
|
|
|
/*nLocalHostNonceIn=*/1,
|
|
|
|
CAddress(),
|
|
|
|
/*addrNameIn=*/"",
|
|
|
|
ConnectionType::OUTBOUND_FULL_RELAY,
|
|
|
|
/*inbound_onion=*/false};
|
2021-01-20 11:54:17 +01:00
|
|
|
nodes[2]->SetCommonVersion(PROTOCOL_VERSION);
|
2020-07-20 20:28:37 +01:00
|
|
|
peerLogic->InitializeNode(*nodes[2], NODE_NETWORK);
|
2021-01-20 11:54:17 +01:00
|
|
|
nodes[2]->fSuccessfullyConnected = true;
|
2020-04-08 19:34:56 +02:00
|
|
|
connman->AddTestNode(*nodes[2]);
|
2022-05-16 16:45:53 +02:00
|
|
|
peerLogic->UnitTestMisbehaving(nodes[2]->GetId(), DISCOURAGEMENT_THRESHOLD);
|
2022-09-13 12:22:18 +10:00
|
|
|
BOOST_CHECK(peerLogic->SendMessages(nodes[2]));
|
2021-01-20 11:54:17 +01:00
|
|
|
BOOST_CHECK(banman->IsDiscouraged(addr[0]));
|
|
|
|
BOOST_CHECK(banman->IsDiscouraged(addr[1]));
|
|
|
|
BOOST_CHECK(banman->IsDiscouraged(addr[2]));
|
|
|
|
BOOST_CHECK(nodes[0]->fDisconnect);
|
|
|
|
BOOST_CHECK(nodes[1]->fDisconnect);
|
|
|
|
BOOST_CHECK(nodes[2]->fDisconnect);
|
|
|
|
|
2021-01-20 11:26:43 +01:00
|
|
|
for (CNode* node : nodes) {
|
|
|
|
peerLogic->FinalizeNode(*node);
|
|
|
|
}
|
2020-04-08 19:34:56 +02:00
|
|
|
connman->ClearTestNodes();
|
2012-10-05 19:22:21 +02:00
|
|
|
}
|
2011-09-06 16:09:04 -04:00
|
|
|
|
|
|
|
BOOST_AUTO_TEST_CASE(DoS_bantime)
|
|
|
|
{
|
2022-09-07 13:57:18 +10:00
|
|
|
LOCK(NetEventsInterface::g_msgproc_mutex);
|
|
|
|
|
2021-01-14 09:33:04 +01:00
|
|
|
auto banman = std::make_unique<BanMan>(m_args.GetDataDirBase() / "banlist", nullptr, DEFAULT_MISBEHAVING_BANTIME);
|
2023-09-12 13:42:36 +02:00
|
|
|
auto connman = std::make_unique<CConnman>(0x1337, 0x1337, *m_node.addrman, *m_node.netgroupman, Params());
|
2023-04-20 13:05:23 +02:00
|
|
|
auto peerLogic = PeerManager::make(*connman, *m_node.addrman, banman.get(), *m_node.chainman, *m_node.mempool, {});
|
2016-12-27 17:13:04 -05:00
|
|
|
|
2017-10-05 13:10:58 -04:00
|
|
|
banman->ClearBanned();
|
2013-04-13 00:13:08 -05:00
|
|
|
int64_t nStartTime = GetTime();
|
2011-09-06 16:09:04 -04:00
|
|
|
SetMockTime(nStartTime); // Overrides future calls to GetTime()
|
|
|
|
|
2016-06-08 19:12:22 +02:00
|
|
|
CAddress addr(ip(0xa0b0c001), NODE_NONE);
|
2020-03-29 23:12:45 +02:00
|
|
|
NodeId id{0};
|
2021-04-23 15:15:23 +02:00
|
|
|
CNode dummyNode{id++,
|
|
|
|
/*sock=*/nullptr,
|
|
|
|
addr,
|
|
|
|
/*nKeyedNetGroupIn=*/4,
|
|
|
|
/*nLocalHostNonceIn=*/4,
|
|
|
|
CAddress(),
|
|
|
|
/*addrNameIn=*/"",
|
|
|
|
ConnectionType::INBOUND,
|
|
|
|
/*inbound_onion=*/false};
|
2020-06-05 10:22:53 +03:00
|
|
|
dummyNode.SetCommonVersion(PROTOCOL_VERSION);
|
2020-07-20 20:28:37 +01:00
|
|
|
peerLogic->InitializeNode(dummyNode, NODE_NETWORK);
|
2017-01-26 12:35:49 -05:00
|
|
|
dummyNode.fSuccessfullyConnected = true;
|
2011-09-06 16:09:04 -04:00
|
|
|
|
2022-05-16 16:45:53 +02:00
|
|
|
peerLogic->UnitTestMisbehaving(dummyNode.GetId(), DISCOURAGEMENT_THRESHOLD);
|
2022-09-13 12:22:18 +10:00
|
|
|
BOOST_CHECK(peerLogic->SendMessages(&dummyNode));
|
2020-06-10 17:11:38 -07:00
|
|
|
BOOST_CHECK(banman->IsDiscouraged(addr));
|
2011-09-06 16:09:04 -04:00
|
|
|
|
2020-10-23 10:28:33 +01:00
|
|
|
peerLogic->FinalizeNode(dummyNode);
|
2012-01-03 23:33:31 +01:00
|
|
|
}
|
2011-09-06 16:09:04 -04:00
|
|
|
|
|
|
|
BOOST_AUTO_TEST_SUITE_END()
|