1 // Copyright (c) 2011-2015 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"
12 #include "script/sign.h"
13 #include "serialize.h"
16 #include "test/test_bitcoin.h"
20 #include <boost/assign/list_of.hpp> // for 'map_list_of()'
21 #include <boost/date_time/posix_time/posix_time_types.hpp>
22 #include <boost/foreach.hpp>
23 #include <boost/test/unit_test.hpp>
25 // Tests this internal-to-main.cpp method:
26 extern bool AddOrphanTx(const CTransaction
& tx
, NodeId peer
);
27 extern void EraseOrphansFor(NodeId peer
);
28 extern unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans
);
33 extern std::map
<uint256
, COrphanTx
> mapOrphanTransactions
;
34 extern std::map
<uint256
, std::set
<uint256
> > mapOrphanTransactionsByPrev
;
36 CService
ip(uint32_t i
)
40 return CService(CNetAddr(s
), Params().GetDefaultPort());
45 BOOST_FIXTURE_TEST_SUITE(DoS_tests
, TestingSetup
)
47 BOOST_AUTO_TEST_CASE(DoS_banning
)
49 connman
->ClearBanned();
50 CAddress
addr1(ip(0xa0b0c001), NODE_NONE
);
51 CNode
dummyNode1(id
++, NODE_NETWORK
, 0, INVALID_SOCKET
, addr1
, "", true);
52 GetNodeSignals().InitializeNode(dummyNode1
.GetId(), &dummyNode1
);
53 dummyNode1
.nVersion
= 1;
54 Misbehaving(dummyNode1
.GetId(), 100); // Should get banned
55 SendMessages(&dummyNode1
, *connman
);
56 BOOST_CHECK(connman
->IsBanned(addr1
));
57 BOOST_CHECK(!connman
->IsBanned(ip(0xa0b0c001|0x0000ff00))); // Different IP, not banned
59 CAddress
addr2(ip(0xa0b0c002), NODE_NONE
);
60 CNode
dummyNode2(id
++, NODE_NETWORK
, 0, INVALID_SOCKET
, addr2
, "", true);
61 GetNodeSignals().InitializeNode(dummyNode2
.GetId(), &dummyNode2
);
62 dummyNode2
.nVersion
= 1;
63 Misbehaving(dummyNode2
.GetId(), 50);
64 SendMessages(&dummyNode2
, *connman
);
65 BOOST_CHECK(!connman
->IsBanned(addr2
)); // 2 not banned yet...
66 BOOST_CHECK(connman
->IsBanned(addr1
)); // ... but 1 still should be
67 Misbehaving(dummyNode2
.GetId(), 50);
68 SendMessages(&dummyNode2
, *connman
);
69 BOOST_CHECK(connman
->IsBanned(addr2
));
72 BOOST_AUTO_TEST_CASE(DoS_banscore
)
74 connman
->ClearBanned();
75 mapArgs
["-banscore"] = "111"; // because 11 is my favorite number
76 CAddress
addr1(ip(0xa0b0c001), NODE_NONE
);
77 CNode
dummyNode1(id
++, NODE_NETWORK
, 0, INVALID_SOCKET
, addr1
, "", true);
78 GetNodeSignals().InitializeNode(dummyNode1
.GetId(), &dummyNode1
);
79 dummyNode1
.nVersion
= 1;
80 Misbehaving(dummyNode1
.GetId(), 100);
81 SendMessages(&dummyNode1
, *connman
);
82 BOOST_CHECK(!connman
->IsBanned(addr1
));
83 Misbehaving(dummyNode1
.GetId(), 10);
84 SendMessages(&dummyNode1
, *connman
);
85 BOOST_CHECK(!connman
->IsBanned(addr1
));
86 Misbehaving(dummyNode1
.GetId(), 1);
87 SendMessages(&dummyNode1
, *connman
);
88 BOOST_CHECK(connman
->IsBanned(addr1
));
89 mapArgs
.erase("-banscore");
92 BOOST_AUTO_TEST_CASE(DoS_bantime
)
94 connman
->ClearBanned();
95 int64_t nStartTime
= GetTime();
96 SetMockTime(nStartTime
); // Overrides future calls to GetTime()
98 CAddress
addr(ip(0xa0b0c001), NODE_NONE
);
99 CNode
dummyNode(id
++, NODE_NETWORK
, 0, INVALID_SOCKET
, addr
, "", true);
100 GetNodeSignals().InitializeNode(dummyNode
.GetId(), &dummyNode
);
101 dummyNode
.nVersion
= 1;
103 Misbehaving(dummyNode
.GetId(), 100);
104 SendMessages(&dummyNode
, *connman
);
105 BOOST_CHECK(connman
->IsBanned(addr
));
107 SetMockTime(nStartTime
+60*60);
108 BOOST_CHECK(connman
->IsBanned(addr
));
110 SetMockTime(nStartTime
+60*60*24+1);
111 BOOST_CHECK(!connman
->IsBanned(addr
));
114 CTransaction
RandomOrphan()
116 std::map
<uint256
, COrphanTx
>::iterator it
;
117 it
= mapOrphanTransactions
.lower_bound(GetRandHash());
118 if (it
== mapOrphanTransactions
.end())
119 it
= mapOrphanTransactions
.begin();
120 return it
->second
.tx
;
123 BOOST_AUTO_TEST_CASE(DoS_mapOrphans
)
126 key
.MakeNewKey(true);
127 CBasicKeyStore keystore
;
128 keystore
.AddKey(key
);
130 // 50 orphan transactions:
131 for (int i
= 0; i
< 50; i
++)
133 CMutableTransaction tx
;
135 tx
.vin
[0].prevout
.n
= 0;
136 tx
.vin
[0].prevout
.hash
= GetRandHash();
137 tx
.vin
[0].scriptSig
<< OP_1
;
139 tx
.vout
[0].nValue
= 1*CENT
;
140 tx
.vout
[0].scriptPubKey
= GetScriptForDestination(key
.GetPubKey().GetID());
145 // ... and 50 that depend on other orphans:
146 for (int i
= 0; i
< 50; i
++)
148 CTransaction txPrev
= RandomOrphan();
150 CMutableTransaction tx
;
152 tx
.vin
[0].prevout
.n
= 0;
153 tx
.vin
[0].prevout
.hash
= txPrev
.GetHash();
155 tx
.vout
[0].nValue
= 1*CENT
;
156 tx
.vout
[0].scriptPubKey
= GetScriptForDestination(key
.GetPubKey().GetID());
157 SignSignature(keystore
, txPrev
, tx
, 0, SIGHASH_ALL
);
162 // This really-big orphan should be ignored:
163 for (int i
= 0; i
< 10; i
++)
165 CTransaction txPrev
= RandomOrphan();
167 CMutableTransaction tx
;
169 tx
.vout
[0].nValue
= 1*CENT
;
170 tx
.vout
[0].scriptPubKey
= GetScriptForDestination(key
.GetPubKey().GetID());
172 for (unsigned int j
= 0; j
< tx
.vin
.size(); j
++)
174 tx
.vin
[j
].prevout
.n
= j
;
175 tx
.vin
[j
].prevout
.hash
= txPrev
.GetHash();
177 SignSignature(keystore
, txPrev
, tx
, 0, SIGHASH_ALL
);
178 // Re-use same signature for other inputs
179 // (they don't have to be valid for this test)
180 for (unsigned int j
= 1; j
< tx
.vin
.size(); j
++)
181 tx
.vin
[j
].scriptSig
= tx
.vin
[0].scriptSig
;
183 BOOST_CHECK(!AddOrphanTx(tx
, i
));
186 // Test EraseOrphansFor:
187 for (NodeId i
= 0; i
< 3; i
++)
189 size_t sizeBefore
= mapOrphanTransactions
.size();
191 BOOST_CHECK(mapOrphanTransactions
.size() < sizeBefore
);
194 // Test LimitOrphanTxSize() function:
195 LimitOrphanTxSize(40);
196 BOOST_CHECK(mapOrphanTransactions
.size() <= 40);
197 LimitOrphanTxSize(10);
198 BOOST_CHECK(mapOrphanTransactions
.size() <= 10);
199 LimitOrphanTxSize(0);
200 BOOST_CHECK(mapOrphanTransactions
.empty());
201 BOOST_CHECK(mapOrphanTransactionsByPrev
.empty());
204 BOOST_AUTO_TEST_SUITE_END()