Line data Source code
1 : // Copyright (c) 2011-2014 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 "chainparams.h"
8 : #include "keystore.h"
9 : #include "main.h"
10 : #include "net.h"
11 : #include "pow.h"
12 : #include "script/sign.h"
13 : #include "serialize.h"
14 : #include "util.h"
15 :
16 : #include "test/test_bitcoin.h"
17 :
18 : #include <stdint.h>
19 :
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>
24 :
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);
29 : struct COrphanTx {
30 : CTransaction tx;
31 : NodeId fromPeer;
32 : };
33 : extern std::map<uint256, COrphanTx> mapOrphanTransactions;
34 : extern std::map<uint256, std::set<uint256> > mapOrphanTransactionsByPrev;
35 :
36 5 : CService ip(uint32_t i)
37 : {
38 : struct in_addr s;
39 5 : s.s_addr = i;
40 5 : return CService(CNetAddr(s), Params().GetDefaultPort());
41 : }
42 :
43 1 : BOOST_FIXTURE_TEST_SUITE(DoS_tests, TestingSetup)
44 :
45 6 : BOOST_AUTO_TEST_CASE(DoS_banning)
46 : {
47 1 : CNode::ClearBanned();
48 1 : CAddress addr1(ip(0xa0b0c001));
49 3 : CNode dummyNode1(INVALID_SOCKET, addr1, "", true);
50 1 : dummyNode1.nVersion = 1;
51 1 : Misbehaving(dummyNode1.GetId(), 100); // Should get banned
52 1 : SendMessages(&dummyNode1, false);
53 8 : BOOST_CHECK(CNode::IsBanned(addr1));
54 8 : BOOST_CHECK(!CNode::IsBanned(ip(0xa0b0c001|0x0000ff00))); // Different IP, not banned
55 :
56 1 : CAddress addr2(ip(0xa0b0c002));
57 4 : CNode dummyNode2(INVALID_SOCKET, addr2, "", true);
58 1 : dummyNode2.nVersion = 1;
59 1 : Misbehaving(dummyNode2.GetId(), 50);
60 1 : SendMessages(&dummyNode2, false);
61 8 : BOOST_CHECK(!CNode::IsBanned(addr2)); // 2 not banned yet...
62 8 : BOOST_CHECK(CNode::IsBanned(addr1)); // ... but 1 still should be
63 1 : Misbehaving(dummyNode2.GetId(), 50);
64 1 : SendMessages(&dummyNode2, false);
65 9 : BOOST_CHECK(CNode::IsBanned(addr2));
66 1 : }
67 :
68 6 : BOOST_AUTO_TEST_CASE(DoS_banscore)
69 : {
70 1 : CNode::ClearBanned();
71 3 : mapArgs["-banscore"] = "111"; // because 11 is my favorite number
72 1 : CAddress addr1(ip(0xa0b0c001));
73 3 : CNode dummyNode1(INVALID_SOCKET, addr1, "", true);
74 1 : dummyNode1.nVersion = 1;
75 1 : Misbehaving(dummyNode1.GetId(), 100);
76 1 : SendMessages(&dummyNode1, false);
77 8 : BOOST_CHECK(!CNode::IsBanned(addr1));
78 1 : Misbehaving(dummyNode1.GetId(), 10);
79 1 : SendMessages(&dummyNode1, false);
80 8 : BOOST_CHECK(!CNode::IsBanned(addr1));
81 1 : Misbehaving(dummyNode1.GetId(), 1);
82 1 : SendMessages(&dummyNode1, false);
83 8 : BOOST_CHECK(CNode::IsBanned(addr1));
84 3 : mapArgs.erase("-banscore");
85 1 : }
86 :
87 6 : BOOST_AUTO_TEST_CASE(DoS_bantime)
88 : {
89 1 : CNode::ClearBanned();
90 1 : int64_t nStartTime = GetTime();
91 1 : SetMockTime(nStartTime); // Overrides future calls to GetTime()
92 :
93 1 : CAddress addr(ip(0xa0b0c001));
94 3 : CNode dummyNode(INVALID_SOCKET, addr, "", true);
95 1 : dummyNode.nVersion = 1;
96 :
97 1 : Misbehaving(dummyNode.GetId(), 100);
98 1 : SendMessages(&dummyNode, false);
99 8 : BOOST_CHECK(CNode::IsBanned(addr));
100 :
101 1 : SetMockTime(nStartTime+60*60);
102 8 : BOOST_CHECK(CNode::IsBanned(addr));
103 :
104 1 : SetMockTime(nStartTime+60*60*24+1);
105 8 : BOOST_CHECK(!CNode::IsBanned(addr));
106 1 : }
107 :
108 60 : CTransaction RandomOrphan()
109 : {
110 : std::map<uint256, COrphanTx>::iterator it;
111 120 : it = mapOrphanTransactions.lower_bound(GetRandHash());
112 60 : if (it == mapOrphanTransactions.end())
113 1 : it = mapOrphanTransactions.begin();
114 60 : return it->second.tx;
115 : }
116 :
117 6 : BOOST_AUTO_TEST_CASE(DoS_mapOrphans)
118 : {
119 : CKey key;
120 1 : key.MakeNewKey(true);
121 2 : CBasicKeyStore keystore;
122 1 : keystore.AddKey(key);
123 :
124 : // 50 orphan transactions:
125 50 : for (int i = 0; i < 50; i++)
126 : {
127 50 : CMutableTransaction tx;
128 100 : tx.vin.resize(1);
129 50 : tx.vin[0].prevout.n = 0;
130 50 : tx.vin[0].prevout.hash = GetRandHash();
131 50 : tx.vin[0].scriptSig << OP_1;
132 100 : tx.vout.resize(1);
133 50 : tx.vout[0].nValue = 1*CENT;
134 200 : tx.vout[0].scriptPubKey = GetScriptForDestination(key.GetPubKey().GetID());
135 :
136 100 : AddOrphanTx(tx, i);
137 : }
138 :
139 : // ... and 50 that depend on other orphans:
140 50 : for (int i = 0; i < 50; i++)
141 : {
142 50 : CTransaction txPrev = RandomOrphan();
143 :
144 50 : CMutableTransaction tx;
145 100 : tx.vin.resize(1);
146 50 : tx.vin[0].prevout.n = 0;
147 50 : tx.vin[0].prevout.hash = txPrev.GetHash();
148 100 : tx.vout.resize(1);
149 50 : tx.vout[0].nValue = 1*CENT;
150 200 : tx.vout[0].scriptPubKey = GetScriptForDestination(key.GetPubKey().GetID());
151 50 : SignSignature(keystore, txPrev, tx, 0);
152 :
153 100 : AddOrphanTx(tx, i);
154 : }
155 :
156 : // This really-big orphan should be ignored:
157 10 : for (int i = 0; i < 10; i++)
158 : {
159 10 : CTransaction txPrev = RandomOrphan();
160 :
161 10 : CMutableTransaction tx;
162 20 : tx.vout.resize(1);
163 10 : tx.vout[0].nValue = 1*CENT;
164 40 : tx.vout[0].scriptPubKey = GetScriptForDestination(key.GetPubKey().GetID());
165 20 : tx.vin.resize(500);
166 10020 : for (unsigned int j = 0; j < tx.vin.size(); j++)
167 : {
168 10000 : tx.vin[j].prevout.n = j;
169 5000 : tx.vin[j].prevout.hash = txPrev.GetHash();
170 : }
171 10 : SignSignature(keystore, txPrev, tx, 0);
172 : // Re-use same signature for other inputs
173 : // (they don't have to be valid for this test)
174 9990 : for (unsigned int j = 1; j < tx.vin.size(); j++)
175 9980 : tx.vin[j].scriptSig = tx.vin[0].scriptSig;
176 :
177 90 : BOOST_CHECK(!AddOrphanTx(tx, i));
178 : }
179 :
180 : // Test EraseOrphansFor:
181 3 : for (NodeId i = 0; i < 3; i++)
182 : {
183 3 : size_t sizeBefore = mapOrphanTransactions.size();
184 3 : EraseOrphansFor(i);
185 24 : BOOST_CHECK(mapOrphanTransactions.size() < sizeBefore);
186 : }
187 :
188 : // Test LimitOrphanTxSize() function:
189 1 : LimitOrphanTxSize(40);
190 8 : BOOST_CHECK(mapOrphanTransactions.size() <= 40);
191 1 : LimitOrphanTxSize(10);
192 8 : BOOST_CHECK(mapOrphanTransactions.size() <= 10);
193 1 : LimitOrphanTxSize(0);
194 8 : BOOST_CHECK(mapOrphanTransactions.empty());
195 8 : BOOST_CHECK(mapOrphanTransactionsByPrev.empty());
196 1 : }
197 :
198 3 : BOOST_AUTO_TEST_SUITE_END()
|