1 // Copyright (c) 2011-2016 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.
5 // Unit tests for denial-of-service detection/prevention code
7 #include "chainparams.h"
10 #include "net_processing.h"
12 #include "script/sign.h"
13 #include "serialize.h"
15 #include "validation.h"
17 #include "test/test_bitcoin.h"
21 #include <boost/test/unit_test.hpp>
23 // Tests these internal-to-net_processing.cpp methods:
24 extern bool AddOrphanTx(const CTransactionRef
& tx
, NodeId peer
);
25 extern void EraseOrphansFor(NodeId peer
);
26 extern unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans
);
32 extern std::map
<uint256
, COrphanTx
> mapOrphanTransactions
;
34 CService
ip(uint32_t i
)
38 return CService(CNetAddr(s
), Params().GetDefaultPort());
43 BOOST_FIXTURE_TEST_SUITE(DoS_tests
, TestingSetup
)
45 // Test eviction of an outbound peer whose chain never advances
46 // Mock a node connection, and use mocktime to simulate a peer
47 // which never sends any headers messages. PeerLogic should
48 // decide to evict that outbound peer, after the appropriate timeouts.
49 // Note that we protect 4 outbound nodes from being subject to
50 // this logic; this test takes advantage of that protection only
51 // being applied to nodes which send headers with sufficient
53 BOOST_AUTO_TEST_CASE(outbound_slow_chain_eviction
)
55 std::atomic
<bool> interruptDummy(false);
57 // Mock an outbound peer
58 CAddress
addr1(ip(0xa0b0c001), NODE_NONE
);
59 CNode
dummyNode1(id
++, ServiceFlags(NODE_NETWORK
|NODE_WITNESS
), 0, INVALID_SOCKET
, addr1
, 0, 0, CAddress(), "", /*fInboundIn=*/ false);
60 dummyNode1
.SetSendVersion(PROTOCOL_VERSION
);
62 peerLogic
->InitializeNode(&dummyNode1
);
63 dummyNode1
.nVersion
= 1;
64 dummyNode1
.fSuccessfullyConnected
= true;
66 // This test requires that we have a chain with non-zero work.
67 BOOST_CHECK(chainActive
.Tip() != nullptr);
68 BOOST_CHECK(chainActive
.Tip()->nChainWork
> 0);
71 peerLogic
->SendMessages(&dummyNode1
, interruptDummy
); // should result in getheaders
72 BOOST_CHECK(dummyNode1
.vSendMsg
.size() > 0);
73 dummyNode1
.vSendMsg
.clear();
75 int64_t nStartTime
= GetTime();
77 SetMockTime(nStartTime
+21*60);
78 peerLogic
->SendMessages(&dummyNode1
, interruptDummy
); // should result in getheaders
79 BOOST_CHECK(dummyNode1
.vSendMsg
.size() > 0);
80 // Wait 3 more minutes
81 SetMockTime(nStartTime
+24*60);
82 peerLogic
->SendMessages(&dummyNode1
, interruptDummy
); // should result in disconnect
83 BOOST_CHECK(dummyNode1
.fDisconnect
== true);
87 peerLogic
->FinalizeNode(dummyNode1
.GetId(), dummy
);
90 BOOST_AUTO_TEST_CASE(DoS_banning
)
92 std::atomic
<bool> interruptDummy(false);
94 connman
->ClearBanned();
95 CAddress
addr1(ip(0xa0b0c001), NODE_NONE
);
96 CNode
dummyNode1(id
++, NODE_NETWORK
, 0, INVALID_SOCKET
, addr1
, 0, 0, CAddress(), "", true);
97 dummyNode1
.SetSendVersion(PROTOCOL_VERSION
);
98 peerLogic
->InitializeNode(&dummyNode1
);
99 dummyNode1
.nVersion
= 1;
100 dummyNode1
.fSuccessfullyConnected
= true;
101 Misbehaving(dummyNode1
.GetId(), 100); // Should get banned
102 peerLogic
->SendMessages(&dummyNode1
, interruptDummy
);
103 BOOST_CHECK(connman
->IsBanned(addr1
));
104 BOOST_CHECK(!connman
->IsBanned(ip(0xa0b0c001|0x0000ff00))); // Different IP, not banned
106 CAddress
addr2(ip(0xa0b0c002), NODE_NONE
);
107 CNode
dummyNode2(id
++, NODE_NETWORK
, 0, INVALID_SOCKET
, addr2
, 1, 1, CAddress(), "", true);
108 dummyNode2
.SetSendVersion(PROTOCOL_VERSION
);
109 peerLogic
->InitializeNode(&dummyNode2
);
110 dummyNode2
.nVersion
= 1;
111 dummyNode2
.fSuccessfullyConnected
= true;
112 Misbehaving(dummyNode2
.GetId(), 50);
113 peerLogic
->SendMessages(&dummyNode2
, interruptDummy
);
114 BOOST_CHECK(!connman
->IsBanned(addr2
)); // 2 not banned yet...
115 BOOST_CHECK(connman
->IsBanned(addr1
)); // ... but 1 still should be
116 Misbehaving(dummyNode2
.GetId(), 50);
117 peerLogic
->SendMessages(&dummyNode2
, interruptDummy
);
118 BOOST_CHECK(connman
->IsBanned(addr2
));
121 peerLogic
->FinalizeNode(dummyNode1
.GetId(), dummy
);
122 peerLogic
->FinalizeNode(dummyNode2
.GetId(), dummy
);
125 BOOST_AUTO_TEST_CASE(DoS_banscore
)
127 std::atomic
<bool> interruptDummy(false);
129 connman
->ClearBanned();
130 gArgs
.ForceSetArg("-banscore", "111"); // because 11 is my favorite number
131 CAddress
addr1(ip(0xa0b0c001), NODE_NONE
);
132 CNode
dummyNode1(id
++, NODE_NETWORK
, 0, INVALID_SOCKET
, addr1
, 3, 1, CAddress(), "", true);
133 dummyNode1
.SetSendVersion(PROTOCOL_VERSION
);
134 peerLogic
->InitializeNode(&dummyNode1
);
135 dummyNode1
.nVersion
= 1;
136 dummyNode1
.fSuccessfullyConnected
= true;
137 Misbehaving(dummyNode1
.GetId(), 100);
138 peerLogic
->SendMessages(&dummyNode1
, interruptDummy
);
139 BOOST_CHECK(!connman
->IsBanned(addr1
));
140 Misbehaving(dummyNode1
.GetId(), 10);
141 peerLogic
->SendMessages(&dummyNode1
, interruptDummy
);
142 BOOST_CHECK(!connman
->IsBanned(addr1
));
143 Misbehaving(dummyNode1
.GetId(), 1);
144 peerLogic
->SendMessages(&dummyNode1
, interruptDummy
);
145 BOOST_CHECK(connman
->IsBanned(addr1
));
146 gArgs
.ForceSetArg("-banscore", std::to_string(DEFAULT_BANSCORE_THRESHOLD
));
149 peerLogic
->FinalizeNode(dummyNode1
.GetId(), dummy
);
152 BOOST_AUTO_TEST_CASE(DoS_bantime
)
154 std::atomic
<bool> interruptDummy(false);
156 connman
->ClearBanned();
157 int64_t nStartTime
= GetTime();
158 SetMockTime(nStartTime
); // Overrides future calls to GetTime()
160 CAddress
addr(ip(0xa0b0c001), NODE_NONE
);
161 CNode
dummyNode(id
++, NODE_NETWORK
, 0, INVALID_SOCKET
, addr
, 4, 4, CAddress(), "", true);
162 dummyNode
.SetSendVersion(PROTOCOL_VERSION
);
163 peerLogic
->InitializeNode(&dummyNode
);
164 dummyNode
.nVersion
= 1;
165 dummyNode
.fSuccessfullyConnected
= true;
167 Misbehaving(dummyNode
.GetId(), 100);
168 peerLogic
->SendMessages(&dummyNode
, interruptDummy
);
169 BOOST_CHECK(connman
->IsBanned(addr
));
171 SetMockTime(nStartTime
+60*60);
172 BOOST_CHECK(connman
->IsBanned(addr
));
174 SetMockTime(nStartTime
+60*60*24+1);
175 BOOST_CHECK(!connman
->IsBanned(addr
));
178 peerLogic
->FinalizeNode(dummyNode
.GetId(), dummy
);
181 CTransactionRef
RandomOrphan()
183 std::map
<uint256
, COrphanTx
>::iterator it
;
184 it
= mapOrphanTransactions
.lower_bound(InsecureRand256());
185 if (it
== mapOrphanTransactions
.end())
186 it
= mapOrphanTransactions
.begin();
187 return it
->second
.tx
;
190 BOOST_AUTO_TEST_CASE(DoS_mapOrphans
)
193 key
.MakeNewKey(true);
194 CBasicKeyStore keystore
;
195 keystore
.AddKey(key
);
197 // 50 orphan transactions:
198 for (int i
= 0; i
< 50; i
++)
200 CMutableTransaction tx
;
202 tx
.vin
[0].prevout
.n
= 0;
203 tx
.vin
[0].prevout
.hash
= InsecureRand256();
204 tx
.vin
[0].scriptSig
<< OP_1
;
206 tx
.vout
[0].nValue
= 1*CENT
;
207 tx
.vout
[0].scriptPubKey
= GetScriptForDestination(key
.GetPubKey().GetID());
209 AddOrphanTx(MakeTransactionRef(tx
), i
);
212 // ... and 50 that depend on other orphans:
213 for (int i
= 0; i
< 50; i
++)
215 CTransactionRef txPrev
= RandomOrphan();
217 CMutableTransaction tx
;
219 tx
.vin
[0].prevout
.n
= 0;
220 tx
.vin
[0].prevout
.hash
= txPrev
->GetHash();
222 tx
.vout
[0].nValue
= 1*CENT
;
223 tx
.vout
[0].scriptPubKey
= GetScriptForDestination(key
.GetPubKey().GetID());
224 SignSignature(keystore
, *txPrev
, tx
, 0, SIGHASH_ALL
);
226 AddOrphanTx(MakeTransactionRef(tx
), i
);
229 // This really-big orphan should be ignored:
230 for (int i
= 0; i
< 10; i
++)
232 CTransactionRef txPrev
= RandomOrphan();
234 CMutableTransaction tx
;
236 tx
.vout
[0].nValue
= 1*CENT
;
237 tx
.vout
[0].scriptPubKey
= GetScriptForDestination(key
.GetPubKey().GetID());
239 for (unsigned int j
= 0; j
< tx
.vin
.size(); j
++)
241 tx
.vin
[j
].prevout
.n
= j
;
242 tx
.vin
[j
].prevout
.hash
= txPrev
->GetHash();
244 SignSignature(keystore
, *txPrev
, tx
, 0, SIGHASH_ALL
);
245 // Re-use same signature for other inputs
246 // (they don't have to be valid for this test)
247 for (unsigned int j
= 1; j
< tx
.vin
.size(); j
++)
248 tx
.vin
[j
].scriptSig
= tx
.vin
[0].scriptSig
;
250 BOOST_CHECK(!AddOrphanTx(MakeTransactionRef(tx
), i
));
253 // Test EraseOrphansFor:
254 for (NodeId i
= 0; i
< 3; i
++)
256 size_t sizeBefore
= mapOrphanTransactions
.size();
258 BOOST_CHECK(mapOrphanTransactions
.size() < sizeBefore
);
261 // Test LimitOrphanTxSize() function:
262 LimitOrphanTxSize(40);
263 BOOST_CHECK(mapOrphanTransactions
.size() <= 40);
264 LimitOrphanTxSize(10);
265 BOOST_CHECK(mapOrphanTransactions
.size() <= 10);
266 LimitOrphanTxSize(0);
267 BOOST_CHECK(mapOrphanTransactions
.empty());
270 BOOST_AUTO_TEST_SUITE_END()