]>
Commit | Line | Data |
---|---|---|
3fc68461 | 1 | // Copyright (c) 2011-2014 The Bitcoin Core developers |
78253fcb | 2 | // Distributed under the MIT software license, see the accompanying |
3fc68461 WL |
3 | // file COPYING or http://www.opensource.org/licenses/mit-license.php. |
4 | ||
15f3ad4d GA |
5 | // |
6 | // Unit tests for denial-of-service detection/prevention code | |
7 | // | |
62922c8a | 8 | |
15f3ad4d | 9 | |
51ed9ec9 | 10 | |
51ed9ec9 | 11 | #include "keystore.h" |
1466b8b7 | 12 | #include "main.h" |
1466b8b7 | 13 | #include "net.h" |
df852d2b | 14 | #include "pow.h" |
e088d65a | 15 | #include "script/sign.h" |
51ed9ec9 | 16 | #include "serialize.h" |
ad49c256 | 17 | #include "util.h" |
15f3ad4d | 18 | |
51598b26 PW |
19 | #include "test/test_bitcoin.h" |
20 | ||
67a42f92 PW |
21 | #include <stdint.h> |
22 | ||
51ed9ec9 BD |
23 | #include <boost/assign/list_of.hpp> // for 'map_list_of()' |
24 | #include <boost/date_time/posix_time/posix_time_types.hpp> | |
25 | #include <boost/foreach.hpp> | |
26 | #include <boost/test/unit_test.hpp> | |
27 | ||
142e6041 | 28 | // Tests this internal-to-main.cpp method: |
c74332c6 GA |
29 | extern bool AddOrphanTx(const CTransaction& tx, NodeId peer); |
30 | extern void EraseOrphansFor(NodeId peer); | |
7bd9c3a3 | 31 | extern unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans); |
33a27716 WL |
32 | struct COrphanTx { |
33 | CTransaction tx; | |
34 | NodeId fromPeer; | |
35 | }; | |
36 | extern std::map<uint256, COrphanTx> mapOrphanTransactions; | |
159bc481 | 37 | extern std::map<uint256, std::set<uint256> > mapOrphanTransactionsByPrev; |
142e6041 | 38 | |
67a42f92 PW |
39 | CService ip(uint32_t i) |
40 | { | |
41 | struct in_addr s; | |
42 | s.s_addr = i; | |
0e4b3175 | 43 | return CService(CNetAddr(s), Params().GetDefaultPort()); |
67a42f92 | 44 | } |
15f3ad4d | 45 | |
51598b26 | 46 | BOOST_FIXTURE_TEST_SUITE(DoS_tests, TestingSetup) |
15f3ad4d GA |
47 | |
48 | BOOST_AUTO_TEST_CASE(DoS_banning) | |
49 | { | |
50 | CNode::ClearBanned(); | |
67a42f92 | 51 | CAddress addr1(ip(0xa0b0c001)); |
39857190 | 52 | CNode dummyNode1(INVALID_SOCKET, addr1, "", true); |
b2864d2f PW |
53 | dummyNode1.nVersion = 1; |
54 | Misbehaving(dummyNode1.GetId(), 100); // Should get banned | |
55 | SendMessages(&dummyNode1, false); | |
67a42f92 | 56 | BOOST_CHECK(CNode::IsBanned(addr1)); |
814efd6f | 57 | BOOST_CHECK(!CNode::IsBanned(ip(0xa0b0c001|0x0000ff00))); // Different IP, not banned |
15f3ad4d | 58 | |
67a42f92 | 59 | CAddress addr2(ip(0xa0b0c002)); |
39857190 | 60 | CNode dummyNode2(INVALID_SOCKET, addr2, "", true); |
b2864d2f PW |
61 | dummyNode2.nVersion = 1; |
62 | Misbehaving(dummyNode2.GetId(), 50); | |
63 | SendMessages(&dummyNode2, false); | |
67a42f92 PW |
64 | BOOST_CHECK(!CNode::IsBanned(addr2)); // 2 not banned yet... |
65 | BOOST_CHECK(CNode::IsBanned(addr1)); // ... but 1 still should be | |
b2864d2f PW |
66 | Misbehaving(dummyNode2.GetId(), 50); |
67 | SendMessages(&dummyNode2, false); | |
67a42f92 | 68 | BOOST_CHECK(CNode::IsBanned(addr2)); |
729b1806 | 69 | } |
15f3ad4d GA |
70 | |
71 | BOOST_AUTO_TEST_CASE(DoS_banscore) | |
72 | { | |
73 | CNode::ClearBanned(); | |
74 | mapArgs["-banscore"] = "111"; // because 11 is my favorite number | |
67a42f92 | 75 | CAddress addr1(ip(0xa0b0c001)); |
39857190 | 76 | CNode dummyNode1(INVALID_SOCKET, addr1, "", true); |
b2864d2f PW |
77 | dummyNode1.nVersion = 1; |
78 | Misbehaving(dummyNode1.GetId(), 100); | |
79 | SendMessages(&dummyNode1, false); | |
67a42f92 | 80 | BOOST_CHECK(!CNode::IsBanned(addr1)); |
b2864d2f PW |
81 | Misbehaving(dummyNode1.GetId(), 10); |
82 | SendMessages(&dummyNode1, false); | |
67a42f92 | 83 | BOOST_CHECK(!CNode::IsBanned(addr1)); |
b2864d2f PW |
84 | Misbehaving(dummyNode1.GetId(), 1); |
85 | SendMessages(&dummyNode1, false); | |
67a42f92 | 86 | BOOST_CHECK(CNode::IsBanned(addr1)); |
62922c8a | 87 | mapArgs.erase("-banscore"); |
15f3ad4d GA |
88 | } |
89 | ||
90 | BOOST_AUTO_TEST_CASE(DoS_bantime) | |
91 | { | |
92 | CNode::ClearBanned(); | |
51ed9ec9 | 93 | int64_t nStartTime = GetTime(); |
15f3ad4d GA |
94 | SetMockTime(nStartTime); // Overrides future calls to GetTime() |
95 | ||
67a42f92 | 96 | CAddress addr(ip(0xa0b0c001)); |
39857190 | 97 | CNode dummyNode(INVALID_SOCKET, addr, "", true); |
b2864d2f | 98 | dummyNode.nVersion = 1; |
15f3ad4d | 99 | |
b2864d2f PW |
100 | Misbehaving(dummyNode.GetId(), 100); |
101 | SendMessages(&dummyNode, false); | |
67a42f92 | 102 | BOOST_CHECK(CNode::IsBanned(addr)); |
15f3ad4d GA |
103 | |
104 | SetMockTime(nStartTime+60*60); | |
67a42f92 | 105 | BOOST_CHECK(CNode::IsBanned(addr)); |
15f3ad4d GA |
106 | |
107 | SetMockTime(nStartTime+60*60*24+1); | |
67a42f92 PW |
108 | BOOST_CHECK(!CNode::IsBanned(addr)); |
109 | } | |
15f3ad4d | 110 | |
142e6041 GA |
111 | CTransaction RandomOrphan() |
112 | { | |
33a27716 | 113 | std::map<uint256, COrphanTx>::iterator it; |
f718aedd | 114 | it = mapOrphanTransactions.lower_bound(GetRandHash()); |
142e6041 GA |
115 | if (it == mapOrphanTransactions.end()) |
116 | it = mapOrphanTransactions.begin(); | |
33a27716 | 117 | return it->second.tx; |
142e6041 GA |
118 | } |
119 | ||
120 | BOOST_AUTO_TEST_CASE(DoS_mapOrphans) | |
121 | { | |
122 | CKey key; | |
123 | key.MakeNewKey(true); | |
124 | CBasicKeyStore keystore; | |
125 | keystore.AddKey(key); | |
126 | ||
127 | // 50 orphan transactions: | |
128 | for (int i = 0; i < 50; i++) | |
129 | { | |
4949004d | 130 | CMutableTransaction tx; |
142e6041 GA |
131 | tx.vin.resize(1); |
132 | tx.vin[0].prevout.n = 0; | |
f718aedd | 133 | tx.vin[0].prevout.hash = GetRandHash(); |
142e6041 GA |
134 | tx.vin[0].scriptSig << OP_1; |
135 | tx.vout.resize(1); | |
136 | tx.vout[0].nValue = 1*CENT; | |
0be990ba | 137 | tx.vout[0].scriptPubKey = GetScriptForDestination(key.GetPubKey().GetID()); |
142e6041 | 138 | |
c74332c6 | 139 | AddOrphanTx(tx, i); |
142e6041 GA |
140 | } |
141 | ||
142 | // ... and 50 that depend on other orphans: | |
143 | for (int i = 0; i < 50; i++) | |
144 | { | |
145 | CTransaction txPrev = RandomOrphan(); | |
146 | ||
4949004d | 147 | CMutableTransaction tx; |
142e6041 GA |
148 | tx.vin.resize(1); |
149 | tx.vin[0].prevout.n = 0; | |
150 | tx.vin[0].prevout.hash = txPrev.GetHash(); | |
151 | tx.vout.resize(1); | |
152 | tx.vout[0].nValue = 1*CENT; | |
0be990ba | 153 | tx.vout[0].scriptPubKey = GetScriptForDestination(key.GetPubKey().GetID()); |
142e6041 GA |
154 | SignSignature(keystore, txPrev, tx, 0); |
155 | ||
c74332c6 | 156 | AddOrphanTx(tx, i); |
142e6041 GA |
157 | } |
158 | ||
77b99cf7 GA |
159 | // This really-big orphan should be ignored: |
160 | for (int i = 0; i < 10; i++) | |
161 | { | |
162 | CTransaction txPrev = RandomOrphan(); | |
163 | ||
4949004d | 164 | CMutableTransaction tx; |
77b99cf7 GA |
165 | tx.vout.resize(1); |
166 | tx.vout[0].nValue = 1*CENT; | |
0be990ba | 167 | tx.vout[0].scriptPubKey = GetScriptForDestination(key.GetPubKey().GetID()); |
77b99cf7 | 168 | tx.vin.resize(500); |
b92095f1 | 169 | for (unsigned int j = 0; j < tx.vin.size(); j++) |
77b99cf7 GA |
170 | { |
171 | tx.vin[j].prevout.n = j; | |
172 | tx.vin[j].prevout.hash = txPrev.GetHash(); | |
173 | } | |
174 | SignSignature(keystore, txPrev, tx, 0); | |
175 | // Re-use same signature for other inputs | |
176 | // (they don't have to be valid for this test) | |
b92095f1 | 177 | for (unsigned int j = 1; j < tx.vin.size(); j++) |
77b99cf7 GA |
178 | tx.vin[j].scriptSig = tx.vin[0].scriptSig; |
179 | ||
c74332c6 GA |
180 | BOOST_CHECK(!AddOrphanTx(tx, i)); |
181 | } | |
182 | ||
183 | // Test EraseOrphansFor: | |
184 | for (NodeId i = 0; i < 3; i++) | |
185 | { | |
186 | size_t sizeBefore = mapOrphanTransactions.size(); | |
187 | EraseOrphansFor(i); | |
188 | BOOST_CHECK(mapOrphanTransactions.size() < sizeBefore); | |
77b99cf7 GA |
189 | } |
190 | ||
142e6041 GA |
191 | // Test LimitOrphanTxSize() function: |
192 | LimitOrphanTxSize(40); | |
193 | BOOST_CHECK(mapOrphanTransactions.size() <= 40); | |
194 | LimitOrphanTxSize(10); | |
195 | BOOST_CHECK(mapOrphanTransactions.size() <= 10); | |
196 | LimitOrphanTxSize(0); | |
197 | BOOST_CHECK(mapOrphanTransactions.empty()); | |
198 | BOOST_CHECK(mapOrphanTransactionsByPrev.empty()); | |
199 | } | |
200 | ||
15f3ad4d | 201 | BOOST_AUTO_TEST_SUITE_END() |