Branch data Line data Source code
1 : : // Copyright (c) 2011-present The Bitcoin Core developers
2 : : // Distributed under the MIT software license, see the accompanying
3 : : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4 : :
5 : : // Unit tests for denial-of-service detection/prevention code
6 : :
7 : : #include <banman.h>
8 : : #include <chainparams.h>
9 : : #include <common/args.h>
10 : : #include <key.h>
11 : : #include <net.h>
12 : : #include <net_processing.h>
13 : : #include <primitives/transaction.h>
14 : : #include <pubkey.h>
15 : : #include <script/sign.h>
16 : : #include <script/signingprovider.h>
17 : : #include <script/solver.h>
18 : : #include <serialize.h>
19 : : #include <test/util/net.h>
20 : : #include <test/util/random.h>
21 : : #include <test/util/setup_common.h>
22 : : #include <test/util/time.h>
23 : : #include <util/string.h>
24 : : #include <util/time.h>
25 : : #include <validation.h>
26 : :
27 : : #include <array>
28 : : #include <cstdint>
29 : :
30 : : #include <boost/test/unit_test.hpp>
31 : :
32 : 18 : static CService ip(uint32_t i)
33 : : {
34 : 18 : struct in_addr s;
35 : 18 : s.s_addr = i;
36 [ + - ]: 36 : return CService(CNetAddr(s), Params().GetDefaultPort());
37 : : }
38 : :
39 : : BOOST_FIXTURE_TEST_SUITE(denialofservice_tests, TestingSetup)
40 : :
41 : : // Test eviction of an outbound peer whose chain never advances
42 : : // Mock a node connection, and use mocktime to simulate a peer
43 : : // which never sends any headers messages. PeerLogic should
44 : : // decide to evict that outbound peer, after the appropriate timeouts.
45 : : // Note that we protect 4 outbound nodes from being subject to
46 : : // this logic; this test takes advantage of that protection only
47 : : // being applied to nodes which send headers with sufficient
48 : : // work.
49 [ + - + - : 7 : BOOST_AUTO_TEST_CASE(outbound_slow_chain_eviction)
+ - + - -
+ + - + -
+ - + - +
- + - - +
+ - + - +
- + - + -
+ - - + +
- + - + -
+ - + - +
- + - - +
+ - + - +
- + - + -
+ - - + +
- ]
50 : : {
51 : 1 : LOCK(NetEventsInterface::g_msgproc_mutex);
52 : :
53 [ + - ]: 1 : ConnmanTestMsg& connman = static_cast<ConnmanTestMsg&>(*m_node.connman);
54 : : // Disable inactivity checks for this test to avoid interference
55 [ + - ]: 1 : connman.SetPeerConnectTimeout(99999s);
56 : 1 : PeerManager& peerman = *m_node.peerman;
57 : :
58 : : // Mock an outbound peer
59 [ + - ]: 2 : CAddress addr1(ip(0xa0b0c001), NODE_NONE);
60 : 1 : NodeId id{0};
61 : 1 : CNode dummyNode1{id++,
62 : : /*sock=*/nullptr,
63 : : addr1,
64 : : /*nKeyedNetGroupIn=*/0,
65 : : /*nLocalHostNonceIn=*/0,
66 [ - + ]: 1 : CAddress(),
67 [ + - ]: 2 : /*addrNameIn=*/"",
68 : : ConnectionType::OUTBOUND_FULL_RELAY,
69 : : /*inbound_onion=*/false,
70 [ + - + - ]: 2 : /*network_key=*/0};
71 : :
72 [ + - ]: 1 : connman.Handshake(
73 : : /*node=*/dummyNode1,
74 : : /*successfully_connected=*/true,
75 : : /*remote_services=*/ServiceFlags(NODE_NETWORK | NODE_WITNESS),
76 : : /*local_services=*/ServiceFlags(NODE_NETWORK | NODE_WITNESS),
77 : : /*version=*/PROTOCOL_VERSION,
78 : : /*relay_txs=*/true);
79 : :
80 : : // This test requires that we have a chain with non-zero work.
81 : 1 : {
82 [ + - ]: 1 : LOCK(cs_main);
83 [ + - + - : 3 : BOOST_CHECK(m_node.chainman->ActiveChain().Tip() != nullptr);
+ - - + +
- + - ]
84 [ + - + - : 3 : BOOST_CHECK(m_node.chainman->ActiveChain().Tip()->nChainWork > 0);
- + + - +
- + - ]
85 : 0 : }
86 : :
87 : : // Test starts here
88 [ + - + - : 2 : BOOST_CHECK(peerman.SendMessages(dummyNode1)); // should result in getheaders
+ - + - ]
89 : :
90 : 1 : {
91 [ + - ]: 1 : LOCK(dummyNode1.cs_vSend);
92 [ + - ]: 1 : const auto& [to_send, _more, _msg_type] = dummyNode1.m_transport->GetBytesToSend(false);
93 [ + - + - : 2 : BOOST_CHECK(!to_send.empty());
+ - ]
94 : 0 : }
95 [ + - ]: 1 : connman.FlushSendBuffer(dummyNode1);
96 : :
97 [ + - ]: 1 : FakeNodeClock clock{};
98 [ + - ]: 1 : clock += 21min;
99 : :
100 [ + - + - : 2 : BOOST_CHECK(peerman.SendMessages(dummyNode1)); // should result in getheaders
+ - + - ]
101 : 1 : {
102 [ + - ]: 1 : LOCK(dummyNode1.cs_vSend);
103 [ + - ]: 1 : const auto& [to_send, _more, _msg_type] = dummyNode1.m_transport->GetBytesToSend(false);
104 [ + - + - : 2 : BOOST_CHECK(!to_send.empty());
+ - ]
105 : 0 : }
106 : :
107 [ + - ]: 1 : clock += 3min;
108 [ + - + - : 2 : BOOST_CHECK(peerman.SendMessages(dummyNode1)); // should result in disconnect
+ - + - ]
109 [ + - + - : 2 : BOOST_CHECK(dummyNode1.fDisconnect == true);
+ - ]
110 : :
111 [ + - ]: 1 : peerman.FinalizeNode(dummyNode1);
112 [ + - ]: 2 : }
113 : :
114 : 4 : struct OutboundTest : TestingSetup {
115 : 14 : void AddRandomOutboundPeer(NodeId& id, std::vector<CNode*>& vNodes, PeerManager& peerLogic, ConnmanTestMsg& connman, ConnectionType connType, bool onion_peer = false)
116 : : {
117 : 14 : CAddress addr;
118 : :
119 [ + + ]: 14 : if (onion_peer) {
120 : 2 : auto tor_addr{m_rng.randbytes(ADDR_TORV3_SIZE)};
121 [ + - - + : 6 : BOOST_REQUIRE(addr.SetSpecial(OnionToString(tor_addr)));
+ - + - +
- ]
122 : 2 : }
123 : :
124 [ + - + + ]: 26 : while (!addr.IsRoutable()) {
125 [ + - ]: 24 : addr = CAddress(ip(m_rng.randbits(32)), NODE_NONE);
126 : : }
127 : :
128 [ + - - - ]: 14 : vNodes.emplace_back(new CNode{id++,
129 : : /*sock=*/nullptr,
130 : : addr,
131 : : /*nKeyedNetGroupIn=*/0,
132 : : /*nLocalHostNonceIn=*/0,
133 [ - + ]: 14 : CAddress(),
134 [ + - ]: 28 : /*addrNameIn=*/"",
135 : : connType,
136 : : /*inbound_onion=*/false,
137 [ + - + - : 42 : /*network_key=*/0});
+ - ]
138 : 14 : CNode &node = *vNodes.back();
139 : 14 : node.SetCommonVersion(PROTOCOL_VERSION);
140 : :
141 [ + - ]: 14 : peerLogic.InitializeNode(node, ServiceFlags(NODE_NETWORK | NODE_WITNESS));
142 [ + - ]: 14 : node.fSuccessfullyConnected = true;
143 : :
144 [ + - ]: 14 : connman.AddTestNode(node);
145 : 14 : }
146 : : }; // struct OutboundTest
147 : :
148 [ + - + - : 7 : BOOST_FIXTURE_TEST_CASE(stale_tip_peer_management, OutboundTest)
+ - + - -
+ + - + -
+ - + - +
- + - - +
+ - + - +
- + - + -
+ - - + +
- + - + -
+ - + - +
- + - - +
+ - + - +
- + - + -
+ - - + +
- ]
149 : : {
150 : 1 : NodeId id{0};
151 : 1 : auto connman = std::make_unique<ConnmanTestMsg>(0x1337, 0x1337, *m_node.addrman, *m_node.netgroupman, Params());
152 [ + - ]: 1 : auto peerLogic = PeerManager::make(*connman, *m_node.addrman, nullptr, *m_node.chainman, *m_node.mempool, *m_node.warnings, {});
153 : :
154 : 1 : constexpr int max_outbound_full_relay = MAX_OUTBOUND_FULL_RELAY_CONNECTIONS;
155 : 1 : CConnman::Options options;
156 : 1 : options.m_max_automatic_connections = DEFAULT_MAX_PEER_CONNECTIONS;
157 : :
158 : 1 : const auto time_init{Now<NodeSeconds>()};
159 [ + - ]: 1 : FakeNodeClock clock{time_init};
160 [ + - ]: 1 : const auto delta{3 * std::chrono::seconds{m_node.chainman->GetConsensus().nPowTargetSpacing} + 1s};
161 [ + - ]: 1 : connman->Init(options);
162 : 1 : std::vector<CNode *> vNodes;
163 : :
164 : : // Mock some outbound peers
165 [ + + ]: 9 : for (int i = 0; i < max_outbound_full_relay; ++i) {
166 [ + - ]: 8 : AddRandomOutboundPeer(id, vNodes, *peerLogic, *connman, ConnectionType::OUTBOUND_FULL_RELAY);
167 : : }
168 : :
169 [ + - ]: 1 : peerLogic->CheckForStaleTipAndEvictPeers();
170 : :
171 : : // No nodes should be marked for disconnection while we have no extra peers
172 [ + + ]: 9 : for (const CNode *node : vNodes) {
173 [ + - + - ]: 16 : BOOST_CHECK(node->fDisconnect == false);
174 : : }
175 : :
176 [ + - ]: 1 : clock += delta;
177 : :
178 : : // Now tip should definitely be stale, and we should look for an extra
179 : : // outbound peer
180 [ + - ]: 1 : peerLogic->CheckForStaleTipAndEvictPeers();
181 [ + - + - : 2 : BOOST_CHECK(connman->GetTryNewOutboundPeer());
+ - ]
182 : :
183 : : // Still no peers should be marked for disconnection
184 [ + + ]: 9 : for (const CNode *node : vNodes) {
185 [ + - + - ]: 16 : BOOST_CHECK(node->fDisconnect == false);
186 : : }
187 : :
188 : : // If we add one more peer, something should get marked for eviction
189 : : // on the next check (since we're mocking the time to be in the future, the
190 : : // required time connected check should be satisfied).
191 [ + - ]: 1 : clock.set(time_init);
192 [ + - ]: 1 : AddRandomOutboundPeer(id, vNodes, *peerLogic, *connman, ConnectionType::OUTBOUND_FULL_RELAY);
193 [ + - ]: 1 : clock += delta;
194 : :
195 [ + - ]: 1 : peerLogic->CheckForStaleTipAndEvictPeers();
196 [ + + ]: 9 : for (int i = 0; i < max_outbound_full_relay; ++i) {
197 [ + - + - ]: 16 : BOOST_CHECK(vNodes[i]->fDisconnect == false);
198 : : }
199 : : // Last added node should get marked for eviction
200 [ + - + - ]: 2 : BOOST_CHECK(vNodes.back()->fDisconnect == true);
201 : :
202 : 1 : vNodes.back()->fDisconnect = false;
203 : :
204 : : // Update the last announced block time for the last
205 : : // peer, and check that the next newest node gets evicted.
206 [ + - ]: 1 : peerLogic->UpdateLastBlockAnnounceTime(vNodes.back()->GetId(), NodeClock::now());
207 : :
208 [ + - ]: 1 : peerLogic->CheckForStaleTipAndEvictPeers();
209 [ + + ]: 8 : for (int i = 0; i < max_outbound_full_relay - 1; ++i) {
210 [ + - + - ]: 14 : BOOST_CHECK(vNodes[i]->fDisconnect == false);
211 : : }
212 [ + - + - : 2 : BOOST_CHECK(vNodes[max_outbound_full_relay-1]->fDisconnect == true);
+ - ]
213 [ + - + - : 2 : BOOST_CHECK(vNodes.back()->fDisconnect == false);
+ - ]
214 : :
215 [ + - ]: 1 : vNodes[max_outbound_full_relay - 1]->fDisconnect = false;
216 : :
217 : : // Add an onion peer, that will be protected because it is the only one for
218 : : // its network, so another peer gets disconnected instead.
219 [ + - ]: 1 : clock.set(time_init);
220 [ + - ]: 1 : AddRandomOutboundPeer(id, vNodes, *peerLogic, *connman, ConnectionType::OUTBOUND_FULL_RELAY, /*onion_peer=*/true);
221 [ + - ]: 1 : clock += delta;
222 [ + - ]: 1 : peerLogic->CheckForStaleTipAndEvictPeers();
223 : :
224 [ + + ]: 7 : for (int i = 0; i < max_outbound_full_relay - 2; ++i) {
225 [ + - + - ]: 12 : BOOST_CHECK(vNodes[i]->fDisconnect == false);
226 : : }
227 [ + - + - : 2 : BOOST_CHECK(vNodes[max_outbound_full_relay - 2]->fDisconnect == false);
+ - ]
228 [ + - + - : 2 : BOOST_CHECK(vNodes[max_outbound_full_relay - 1]->fDisconnect == true);
+ - ]
229 [ + - + - : 2 : BOOST_CHECK(vNodes[max_outbound_full_relay]->fDisconnect == false);
+ - ]
230 : :
231 : : // Add a second onion peer which won't be protected
232 [ + - ]: 1 : clock.set(time_init);
233 [ + - ]: 1 : AddRandomOutboundPeer(id, vNodes, *peerLogic, *connman, ConnectionType::OUTBOUND_FULL_RELAY, /*onion_peer=*/true);
234 [ + - ]: 1 : clock += delta;
235 [ + - ]: 1 : peerLogic->CheckForStaleTipAndEvictPeers();
236 : :
237 [ + - + - ]: 2 : BOOST_CHECK(vNodes.back()->fDisconnect == true);
238 : :
239 [ + + ]: 12 : for (const CNode *node : vNodes) {
240 [ + - ]: 11 : peerLogic->FinalizeNode(*node);
241 : : }
242 : :
243 [ + - ]: 1 : connman->ClearTestNodes();
244 : 1 : }
245 : :
246 [ + - + - : 7 : BOOST_FIXTURE_TEST_CASE(block_relay_only_eviction, OutboundTest)
+ - + - -
+ + - + -
+ - + - +
- + - - +
+ - + - +
- + - + -
+ - - + +
- + - + -
+ - + - +
- + - - +
+ - + - +
- + - + -
+ - - + +
- ]
247 : : {
248 : 1 : NodeId id{0};
249 : 1 : FakeNodeClock clock{};
250 [ + - + - ]: 1 : auto connman = std::make_unique<ConnmanTestMsg>(0x1337, 0x1337, *m_node.addrman, *m_node.netgroupman, Params());
251 [ + - ]: 1 : auto peerLogic = PeerManager::make(*connman, *m_node.addrman, nullptr, *m_node.chainman, *m_node.mempool, *m_node.warnings, {});
252 : :
253 : 1 : constexpr int max_outbound_block_relay{MAX_BLOCK_RELAY_ONLY_CONNECTIONS};
254 : 1 : constexpr auto MINIMUM_CONNECT_TIME{30s};
255 : 1 : CConnman::Options options;
256 : 1 : options.m_max_automatic_connections = DEFAULT_MAX_PEER_CONNECTIONS;
257 : :
258 [ + - ]: 1 : connman->Init(options);
259 : 1 : std::vector<CNode*> vNodes;
260 : :
261 : : // Add block-relay-only peers up to the limit
262 [ + + ]: 3 : for (int i = 0; i < max_outbound_block_relay; ++i) {
263 [ + - ]: 2 : AddRandomOutboundPeer(id, vNodes, *peerLogic, *connman, ConnectionType::BLOCK_RELAY);
264 : : }
265 [ + - ]: 1 : peerLogic->CheckForStaleTipAndEvictPeers();
266 : :
267 [ + + ]: 3 : for (int i = 0; i < max_outbound_block_relay; ++i) {
268 [ + - + - ]: 4 : BOOST_CHECK(vNodes[i]->fDisconnect == false);
269 : : }
270 : :
271 : : // Add an extra block-relay-only peer breaking the limit (mocks logic in ThreadOpenConnections)
272 [ + - ]: 1 : AddRandomOutboundPeer(id, vNodes, *peerLogic, *connman, ConnectionType::BLOCK_RELAY);
273 [ + - ]: 1 : peerLogic->CheckForStaleTipAndEvictPeers();
274 : :
275 : : // The extra peer should only get marked for eviction after MINIMUM_CONNECT_TIME
276 [ + + ]: 3 : for (int i = 0; i < max_outbound_block_relay; ++i) {
277 [ + - + - ]: 4 : BOOST_CHECK(vNodes[i]->fDisconnect == false);
278 : : }
279 [ + - + - : 2 : BOOST_CHECK(vNodes.back()->fDisconnect == false);
+ - ]
280 : :
281 [ + - ]: 1 : clock += MINIMUM_CONNECT_TIME;
282 [ + - ]: 1 : peerLogic->CheckForStaleTipAndEvictPeers();
283 [ + + ]: 3 : for (int i = 0; i < max_outbound_block_relay; ++i) {
284 [ + - + - ]: 4 : BOOST_CHECK(vNodes[i]->fDisconnect == false);
285 : : }
286 [ + - + - ]: 2 : BOOST_CHECK(vNodes.back()->fDisconnect == true);
287 : :
288 : : // Update the last block time for the extra peer,
289 : : // and check that the next youngest peer gets evicted.
290 : 1 : vNodes.back()->fDisconnect = false;
291 : 1 : vNodes.back()->m_last_block_time = GetTime<std::chrono::seconds>();
292 : :
293 [ + - ]: 1 : peerLogic->CheckForStaleTipAndEvictPeers();
294 [ + + ]: 2 : for (int i = 0; i < max_outbound_block_relay - 1; ++i) {
295 [ + - + - ]: 2 : BOOST_CHECK(vNodes[i]->fDisconnect == false);
296 : : }
297 [ + - + - : 2 : BOOST_CHECK(vNodes[max_outbound_block_relay - 1]->fDisconnect == true);
+ - ]
298 [ + - + - ]: 2 : BOOST_CHECK(vNodes.back()->fDisconnect == false);
299 : :
300 [ + + ]: 4 : for (const CNode* node : vNodes) {
301 [ + - ]: 3 : peerLogic->FinalizeNode(*node);
302 : : }
303 [ + - ]: 1 : connman->ClearTestNodes();
304 : 1 : }
305 : :
306 [ + - + - : 7 : BOOST_AUTO_TEST_CASE(peer_discouragement)
+ - + - -
+ + - + -
+ - + - +
- + - - +
+ - + - +
- + - + -
+ - - + +
- + - + -
+ - + - +
- + - - +
+ - + - +
- + - + -
+ - - + +
- ]
307 : : {
308 : 1 : LOCK(NetEventsInterface::g_msgproc_mutex);
309 : :
310 [ + - + - ]: 3 : auto banman = std::make_unique<BanMan>(m_args.GetDataDirBase() / "banlist", nullptr, DEFAULT_MISBEHAVING_BANTIME);
311 [ + - + - ]: 1 : auto connman = std::make_unique<ConnmanTestMsg>(0x1337, 0x1337, *m_node.addrman, *m_node.netgroupman, Params());
312 [ + - ]: 1 : auto peerLogic = PeerManager::make(*connman, *m_node.addrman, banman.get(), *m_node.chainman, *m_node.mempool, *m_node.warnings, {});
313 : :
314 [ + - ]: 1 : CNetAddr tor_netaddr;
315 [ + - + - : 2 : BOOST_REQUIRE(
+ - + - ]
316 : : tor_netaddr.SetSpecial("pg6mmjiyjmcrsslvykfwnntlaru7p5svn6y2ymmju6nubxndf4pscryd.onion"));
317 [ + - + - ]: 1 : const CService tor_service{tor_netaddr, Params().GetDefaultPort()};
318 : :
319 [ + - ]: 1 : const std::array<CAddress, 3> addr{CAddress{ip(0xa0b0c001), NODE_NONE},
320 : 1 : CAddress{ip(0xa0b0c002), NODE_NONE},
321 [ + - - - ]: 2 : CAddress{tor_service, NODE_NONE}};
322 : :
323 [ + - ]: 1 : const CNetAddr other_addr{ip(0xa0b0ff01)}; // Not any of addr[].
324 : :
325 : 1 : std::array<CNode*, 5> nodes;
326 : :
327 [ + - ]: 1 : banman->ClearBanned();
328 : 1 : NodeId id{0};
329 : 2 : nodes[0] = new CNode{id++,
330 : : /*sock=*/nullptr,
331 [ + - ]: 1 : addr[0],
332 : : /*nKeyedNetGroupIn=*/0,
333 : : /*nLocalHostNonceIn=*/0,
334 [ - + ]: 1 : CAddress(),
335 [ + - ]: 2 : /*addrNameIn=*/"",
336 : : ConnectionType::INBOUND,
337 : : /*inbound_onion=*/false,
338 [ + - + - : 2 : /*network_key=*/1};
+ - ]
339 : 1 : nodes[0]->SetCommonVersion(PROTOCOL_VERSION);
340 [ + - ]: 1 : peerLogic->InitializeNode(*nodes[0], NODE_NETWORK);
341 [ + - ]: 1 : nodes[0]->fSuccessfullyConnected = true;
342 [ + - ]: 1 : connman->AddTestNode(*nodes[0]);
343 [ + - ]: 1 : peerLogic->UnitTestMisbehaving(nodes[0]->GetId()); // Should be discouraged
344 [ + - + - : 2 : BOOST_CHECK(peerLogic->SendMessages(*nodes[0]));
+ - + - ]
345 : :
346 [ + - + - : 2 : BOOST_CHECK(banman->IsDiscouraged(addr[0]));
+ - + - ]
347 [ + - + - : 2 : BOOST_CHECK(nodes[0]->fDisconnect);
+ - ]
348 [ + - + - : 2 : BOOST_CHECK(!banman->IsDiscouraged(other_addr)); // Different address, not discouraged
+ - + - ]
349 : :
350 : 2 : nodes[1] = new CNode{id++,
351 : : /*sock=*/nullptr,
352 [ + - ]: 1 : addr[1],
353 : : /*nKeyedNetGroupIn=*/1,
354 : : /*nLocalHostNonceIn=*/1,
355 [ - + ]: 1 : CAddress(),
356 [ + - ]: 2 : /*addrNameIn=*/"",
357 : : ConnectionType::INBOUND,
358 : : /*inbound_onion=*/false,
359 [ + - + - : 2 : /*network_key=*/1};
+ - ]
360 : 1 : nodes[1]->SetCommonVersion(PROTOCOL_VERSION);
361 [ + - ]: 1 : peerLogic->InitializeNode(*nodes[1], NODE_NETWORK);
362 [ + - ]: 1 : nodes[1]->fSuccessfullyConnected = true;
363 [ + - ]: 1 : connman->AddTestNode(*nodes[1]);
364 [ + - + - : 2 : BOOST_CHECK(peerLogic->SendMessages(*nodes[1]));
+ - + - ]
365 : : // [0] is still discouraged/disconnected.
366 [ + - + - : 2 : BOOST_CHECK(banman->IsDiscouraged(addr[0]));
+ - + - ]
367 [ + - + - : 2 : BOOST_CHECK(nodes[0]->fDisconnect);
+ - ]
368 : : // [1] is not discouraged/disconnected yet.
369 [ + - + - : 2 : BOOST_CHECK(!banman->IsDiscouraged(addr[1]));
+ - + - ]
370 [ + - + - : 2 : BOOST_CHECK(!nodes[1]->fDisconnect);
+ - ]
371 [ + - ]: 1 : peerLogic->UnitTestMisbehaving(nodes[1]->GetId());
372 [ + - + - : 2 : BOOST_CHECK(peerLogic->SendMessages(*nodes[1]));
+ - + - ]
373 : : // Expect both [0] and [1] to be discouraged/disconnected now.
374 [ + - + - : 2 : BOOST_CHECK(banman->IsDiscouraged(addr[0]));
+ - + - ]
375 [ + - + - : 2 : BOOST_CHECK(nodes[0]->fDisconnect);
+ - ]
376 [ + - + - : 2 : BOOST_CHECK(banman->IsDiscouraged(addr[1]));
+ - + - ]
377 [ + - + - : 2 : BOOST_CHECK(nodes[1]->fDisconnect);
+ - ]
378 : :
379 : : // Make sure non-IP peers are discouraged and disconnected properly.
380 : :
381 : 2 : nodes[2] = new CNode{id++,
382 : : /*sock=*/nullptr,
383 [ + - ]: 1 : addr[2],
384 : : /*nKeyedNetGroupIn=*/1,
385 : : /*nLocalHostNonceIn=*/1,
386 : 1 : CAddress(),
387 [ + - ]: 2 : /*addrNameIn=*/"",
388 : : ConnectionType::OUTBOUND_FULL_RELAY,
389 : : /*inbound_onion=*/false,
390 [ + - + - : 2 : /*network_key=*/2};
+ - ]
391 : 1 : nodes[2]->SetCommonVersion(PROTOCOL_VERSION);
392 [ + - ]: 1 : peerLogic->InitializeNode(*nodes[2], NODE_NETWORK);
393 [ + - ]: 1 : nodes[2]->fSuccessfullyConnected = true;
394 [ + - ]: 1 : connman->AddTestNode(*nodes[2]);
395 : :
396 : 2 : nodes[3] = new CNode{/*id=*/id++,
397 : : /*sock=*/nullptr,
398 [ + - ]: 1 : /*addrIn=*/addr[2],
399 : : /*nKeyedNetGroupIn=*/0,
400 : : /*nLocalHostNonceIn=*/0,
401 [ - + ]: 1 : /*addrBindIn=*/CAddress{},
402 [ + - ]: 2 : /*addrNameIn=*/"",
403 : : /*conn_type_in=*/ConnectionType::PRIVATE_BROADCAST,
404 : : /*inbound_onion=*/false,
405 [ + - + - : 2 : /*network_key=*/0};
+ - ]
406 [ + - ]: 1 : peerLogic->InitializeNode(*nodes[3], NODE_NETWORK);
407 [ + - ]: 1 : connman->AddTestNode(*nodes[3]);
408 : :
409 [ + - ]: 1 : peerLogic->UnitTestMisbehaving(nodes[2]->GetId());
410 [ + - + - : 2 : BOOST_CHECK(peerLogic->SendMessages(*nodes[2]));
+ - + - ]
411 [ + - + - : 2 : BOOST_CHECK(banman->IsDiscouraged(addr[0]));
+ - + - ]
412 [ + - + - : 2 : BOOST_CHECK(banman->IsDiscouraged(addr[1]));
+ - + - ]
413 [ + - + - : 2 : BOOST_CHECK(banman->IsDiscouraged(addr[2]));
+ - + - ]
414 [ + - + - : 2 : BOOST_CHECK(nodes[0]->fDisconnect);
+ - ]
415 [ + - + - : 2 : BOOST_CHECK(nodes[1]->fDisconnect);
+ - ]
416 [ + - + - : 2 : BOOST_CHECK(nodes[2]->fDisconnect);
+ - ]
417 [ + - + - : 2 : BOOST_CHECK(!nodes[3]->fDisconnect);
+ - ]
418 : :
419 : 2 : nodes[4] = new CNode{/*id=*/id++,
420 : : /*sock=*/nullptr,
421 [ + - + - : 3 : /*addrIn=*/CAddress{CService{other_addr, Params().GetDefaultPort()}, NODE_NONE},
- + ]
422 : : /*nKeyedNetGroupIn=*/0,
423 : : /*nLocalHostNonceIn=*/0,
424 : 1 : /*addrBindIn=*/CAddress{},
425 [ + - ]: 2 : /*addrNameIn=*/"",
426 : : /*conn_type_in=*/ConnectionType::PRIVATE_BROADCAST,
427 : : /*inbound_onion=*/false,
428 [ + - + - : 2 : /*network_key=*/0};
+ - ]
429 [ + - ]: 1 : peerLogic->InitializeNode(*nodes[4], NODE_NETWORK);
430 [ + - ]: 1 : connman->AddTestNode(*nodes[4]);
431 : :
432 [ + - ]: 1 : peerLogic->UnitTestMisbehaving(nodes[4]->GetId());
433 [ + - + - : 2 : BOOST_CHECK(peerLogic->SendMessages(*nodes[4]));
+ - + - ]
434 [ + - + - : 2 : BOOST_CHECK(nodes[4]->fDisconnect);
+ - ]
435 [ + - + - : 2 : BOOST_CHECK(!banman->IsDiscouraged(other_addr));
+ - ]
436 : :
437 [ + + ]: 6 : for (CNode* node : nodes) {
438 [ + - ]: 5 : peerLogic->FinalizeNode(*node);
439 : : }
440 [ + - ]: 1 : connman->ClearTestNodes();
441 [ + - ]: 3 : }
442 : :
443 [ + - + - : 7 : BOOST_AUTO_TEST_CASE(DoS_bantime)
+ - + - -
+ + - + -
+ - + - +
- + - - +
+ - + - +
- + - + -
+ - - + +
- + - + -
+ - + - +
- + - - +
+ - + - +
- + - + -
+ - - + +
- ]
444 : : {
445 : 1 : LOCK(NetEventsInterface::g_msgproc_mutex);
446 : :
447 [ + - + - ]: 3 : auto banman = std::make_unique<BanMan>(m_args.GetDataDirBase() / "banlist", nullptr, DEFAULT_MISBEHAVING_BANTIME);
448 [ + - + - ]: 1 : auto connman = std::make_unique<CConnman>(0x1337, 0x1337, *m_node.addrman, *m_node.netgroupman, Params());
449 [ + - ]: 1 : auto peerLogic = PeerManager::make(*connman, *m_node.addrman, banman.get(), *m_node.chainman, *m_node.mempool, *m_node.warnings, {});
450 : :
451 [ + - ]: 1 : banman->ClearBanned();
452 [ + - ]: 1 : const FakeNodeClock clock{}; // keep mocktime constant
453 : :
454 [ + - ]: 2 : CAddress addr(ip(0xa0b0c001), NODE_NONE);
455 : 1 : NodeId id{0};
456 : 1 : CNode dummyNode{id++,
457 : : /*sock=*/nullptr,
458 : : addr,
459 : : /*nKeyedNetGroupIn=*/4,
460 : : /*nLocalHostNonceIn=*/4,
461 [ - + ]: 1 : CAddress(),
462 [ + - ]: 2 : /*addrNameIn=*/"",
463 : : ConnectionType::INBOUND,
464 : : /*inbound_onion=*/false,
465 [ + - + - ]: 2 : /*network_key=*/1};
466 : 1 : dummyNode.SetCommonVersion(PROTOCOL_VERSION);
467 [ + - ]: 1 : peerLogic->InitializeNode(dummyNode, NODE_NETWORK);
468 [ + - ]: 1 : dummyNode.fSuccessfullyConnected = true;
469 : :
470 [ + - ]: 1 : peerLogic->UnitTestMisbehaving(dummyNode.GetId());
471 [ + - + - : 2 : BOOST_CHECK(peerLogic->SendMessages(dummyNode));
+ - + - ]
472 [ + - + - : 2 : BOOST_CHECK(banman->IsDiscouraged(addr));
+ - + - ]
473 : :
474 [ + - ]: 1 : peerLogic->FinalizeNode(dummyNode);
475 [ + - ]: 2 : }
476 : :
477 : : // Reconsidering orphans must be interruptible: at most one orphan is accepted
478 : : // or rejected per ProcessMessages() call.
479 : : // See https://bitcoincore.org/en/2024/07/03/disclose-orphan-dos.
480 [ + - + - : 7 : BOOST_FIXTURE_TEST_CASE(orphan_reconsideration_interruptible, TestChain100Setup)
+ - + - -
+ + - + -
+ - + - +
- + - - +
+ - + - +
- + - + -
+ - - + +
- + - + -
+ - + - +
- + - - +
+ - + - +
- + - + -
+ - - + +
- ]
481 : : {
482 : 1 : LOCK(NetEventsInterface::g_msgproc_mutex);
483 : :
484 [ + - ]: 1 : ConnmanTestMsg& connman = static_cast<ConnmanTestMsg&>(*m_node.connman);
485 : 1 : PeerManager& peerman = *m_node.peerman;
486 : 1 : const CTxMemPool& mempool = *m_node.mempool;
487 : :
488 : 1 : CNode peer{/*id=*/0,
489 : : /*sock=*/nullptr,
490 [ + - - + ]: 2 : CAddress(ip(0xa0b0c001), NODE_NONE),
491 : : /*nKeyedNetGroupIn=*/0,
492 : : /*nLocalHostNonceIn=*/0,
493 : 1 : CAddress(),
494 [ + - ]: 2 : /*addrNameIn=*/"",
495 : : ConnectionType::OUTBOUND_FULL_RELAY,
496 : : /*inbound_onion=*/false,
497 [ + - + - ]: 2 : /*network_key=*/0};
498 [ + - ]: 1 : connman.Handshake(
499 : : /*node=*/peer,
500 : : /*successfully_connected=*/true,
501 : : /*remote_services=*/ServiceFlags(NODE_NETWORK | NODE_WITNESS),
502 : : /*local_services=*/ServiceFlags(NODE_NETWORK | NODE_WITNESS),
503 : : /*version=*/PROTOCOL_VERSION,
504 : : /*relay_txs=*/true);
505 : :
506 [ + - + - ]: 1 : const CScript script{GetScriptForRawPubKey(coinbaseKey.GetPubKey())};
507 : 1 : const int num_children{6};
508 [ + - + - : 6 : const auto parent{MakeTransactionRef(CreateValidMempoolTransaction(
+ - + + +
- + + - -
- - - - ]
509 [ + - + - ]: 1 : {m_coinbase_txns[0]}, {COutPoint{m_coinbase_txns[0]->GetHash(), 0}}, /*input_height=*/1, {coinbaseKey},
510 [ + - + - ]: 3 : std::vector<CTxOut>(num_children, CTxOut{5 * COIN, script}), /*submit=*/false))};
511 : :
512 : 8 : const auto send_tx{[&](const CTransactionRef& tx) EXCLUSIVE_LOCKS_REQUIRED(NetEventsInterface::g_msgproc_mutex) {
513 : 7 : connman.FlushSendBuffer(peer); // Drop messages we sent, the transport is shared with the fake peer.
514 [ + - + - : 21 : BOOST_REQUIRE(connman.ReceiveMsgFrom(peer, NetMsg::Make(NetMsgType::TX, TX_WITH_WITNESS(*tx))));
+ - + - ]
515 : 7 : peer.fPauseSend = false;
516 : 7 : return connman.ProcessMessagesOnce(peer);
517 : 1 : }};
518 : :
519 : : // Children arrive first and become orphans. Half of them pay no fee and will be rejected.
520 [ + + ]: 7 : for (int i{0}; i < num_children; ++i) {
521 [ + + ]: 6 : const CAmount output_value{i % 2 ? 5 * COIN : 4 * COIN};
522 [ + - + - : 36 : send_tx(MakeTransactionRef(CreateValidMempoolTransaction(parent, i, /*input_height=*/101, coinbaseKey, script, output_value, /*submit=*/false)));
+ - + - +
- ]
523 : : }
524 [ + - + - : 2 : BOOST_CHECK_EQUAL(peerman.GetOrphanTransactions().size(), num_children);
+ - ]
525 [ + - + - : 1 : BOOST_CHECK_EQUAL(mempool.size(), 0U);
+ - ]
526 : :
527 : : // Accepting the parent schedules all children for reconsideration.
528 [ + - + - : 2 : BOOST_CHECK(send_tx(parent));
+ - + - ]
529 [ + - + - : 2 : BOOST_CHECK_EQUAL(peerman.GetOrphanTransactions().size(), num_children);
+ - ]
530 [ + - + - : 1 : BOOST_CHECK_EQUAL(mempool.size(), 1U);
+ - ]
531 : :
532 : : // Each call accepts or rejects exactly one orphan, whether it is valid or not.
533 [ + + ]: 7 : for (int i{1}; i <= num_children; ++i) {
534 [ + - + - : 12 : BOOST_CHECK(connman.ProcessMessagesOnce(peer));
+ - + - ]
535 [ + - + - : 12 : BOOST_CHECK_EQUAL(peerman.GetOrphanTransactions().size(), num_children - i);
+ - ]
536 : : }
537 [ + - + - : 1 : BOOST_CHECK_EQUAL(mempool.size(), 1U + num_children / 2);
+ - ]
538 [ + - + - : 2 : BOOST_CHECK(!connman.ProcessMessagesOnce(peer));
+ - + - ]
539 : :
540 [ + - ]: 1 : peerman.FinalizeNode(peer);
541 [ + - + - : 4 : }
+ - ]
542 : :
543 : : BOOST_AUTO_TEST_SUITE_END()
|