Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

DoS_tests.cpp 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315
  1. //
  2. // Unit tests for denial-of-service detection/prevention code
  3. //
  4. #include <algorithm>
  5. #include <boost/assign/list_of.hpp> // for 'map_list_of()'
  6. #include <boost/date_time/posix_time/posix_time_types.hpp>
  7. #include <boost/test/unit_test.hpp>
  8. #include <boost/foreach.hpp>
  9. #include "chainparams.h"
  10. #include "main.h"
  11. #include "wallet.h"
  12. #include "net.h"
  13. #include "util.h"
  14. #include <stdint.h>
  15. // Tests this internal-to-main.cpp method:
  16. extern bool AddOrphanTx(const CDataStream& vMsg);
  17. extern unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans);
  18. extern std::map<uint256, CDataStream*> mapOrphanTransactions;
  19. extern std::map<uint256, std::map<uint256, CDataStream*> > mapOrphanTransactionsByPrev;
  20. CService ip(uint32_t i)
  21. {
  22. struct in_addr s;
  23. s.s_addr = i;
  24. return CService(CNetAddr(s), Params().GetDefaultPort());
  25. }
  26. BOOST_AUTO_TEST_SUITE(DoS_tests)
  27. BOOST_AUTO_TEST_CASE(DoS_banning)
  28. {
  29. CNode::ClearBanned();
  30. CAddress addr1(ip(0xa0b0c001));
  31. CNode dummyNode1(INVALID_SOCKET, addr1, "", true);
  32. dummyNode1.Misbehaving(100); // Should get banned
  33. BOOST_CHECK(CNode::IsBanned(addr1));
  34. BOOST_CHECK(!CNode::IsBanned(ip(0xa0b0c001|0x0000ff00))); // Different IP, not banned
  35. CAddress addr2(ip(0xa0b0c002));
  36. CNode dummyNode2(INVALID_SOCKET, addr2, "", true);
  37. dummyNode2.Misbehaving(50);
  38. BOOST_CHECK(!CNode::IsBanned(addr2)); // 2 not banned yet...
  39. BOOST_CHECK(CNode::IsBanned(addr1)); // ... but 1 still should be
  40. dummyNode2.Misbehaving(50);
  41. BOOST_CHECK(CNode::IsBanned(addr2));
  42. }
  43. BOOST_AUTO_TEST_CASE(DoS_banscore)
  44. {
  45. CNode::ClearBanned();
  46. mapArgs["-banscore"] = "111"; // because 11 is my favorite number
  47. CAddress addr1(ip(0xa0b0c001));
  48. CNode dummyNode1(INVALID_SOCKET, addr1, "", true);
  49. dummyNode1.Misbehaving(100);
  50. BOOST_CHECK(!CNode::IsBanned(addr1));
  51. dummyNode1.Misbehaving(10);
  52. BOOST_CHECK(!CNode::IsBanned(addr1));
  53. dummyNode1.Misbehaving(1);
  54. BOOST_CHECK(CNode::IsBanned(addr1));
  55. mapArgs.erase("-banscore");
  56. }
  57. BOOST_AUTO_TEST_CASE(DoS_bantime)
  58. {
  59. CNode::ClearBanned();
  60. int64 nStartTime = GetTime();
  61. SetMockTime(nStartTime); // Overrides future calls to GetTime()
  62. CAddress addr(ip(0xa0b0c001));
  63. CNode dummyNode(INVALID_SOCKET, addr, "", true);
  64. dummyNode.Misbehaving(100);
  65. BOOST_CHECK(CNode::IsBanned(addr));
  66. SetMockTime(nStartTime+60*60);
  67. BOOST_CHECK(CNode::IsBanned(addr));
  68. SetMockTime(nStartTime+60*60*24+1);
  69. BOOST_CHECK(!CNode::IsBanned(addr));
  70. }
  71. static bool CheckNBits(unsigned int nbits1, int64 time1, unsigned int nbits2, int64 time2)\
  72. {
  73. if (time1 > time2)
  74. return CheckNBits(nbits2, time2, nbits1, time1);
  75. int64 deltaTime = time2-time1;
  76. CBigNum required;
  77. required.SetCompact(ComputeMinWork(nbits1, deltaTime));
  78. CBigNum have;
  79. have.SetCompact(nbits2);
  80. return (have <= required);
  81. }
  82. BOOST_AUTO_TEST_CASE(DoS_checknbits)
  83. {
  84. using namespace boost::assign; // for 'map_list_of()'
  85. // Timestamps,nBits from the bitcoin block chain.
  86. // These are the block-chain checkpoint blocks
  87. typedef std::map<int64, unsigned int> BlockData;
  88. BlockData chainData =
  89. map_list_of(1239852051,486604799)(1262749024,486594666)
  90. (1279305360,469854461)(1280200847,469830746)(1281678674,469809688)
  91. (1296207707,453179945)(1302624061,453036989)(1309640330,437004818)
  92. (1313172719,436789733);
  93. // Make sure CheckNBits considers every combination of block-chain-lock-in-points
  94. // "sane":
  95. BOOST_FOREACH(const BlockData::value_type& i, chainData)
  96. {
  97. BOOST_FOREACH(const BlockData::value_type& j, chainData)
  98. {
  99. BOOST_CHECK(CheckNBits(i.second, i.first, j.second, j.first));
  100. }
  101. }
  102. // Test a couple of insane combinations:
  103. BlockData::value_type firstcheck = *(chainData.begin());
  104. BlockData::value_type lastcheck = *(chainData.rbegin());
  105. // First checkpoint difficulty at or a while after the last checkpoint time should fail when
  106. // compared to last checkpoint
  107. BOOST_CHECK(!CheckNBits(firstcheck.second, lastcheck.first+60*10, lastcheck.second, lastcheck.first));
  108. BOOST_CHECK(!CheckNBits(firstcheck.second, lastcheck.first+60*60*24*14, lastcheck.second, lastcheck.first));
  109. // ... but OK if enough time passed for difficulty to adjust downward:
  110. BOOST_CHECK(CheckNBits(firstcheck.second, lastcheck.first+60*60*24*365*4, lastcheck.second, lastcheck.first));
  111. }
  112. CTransaction RandomOrphan()
  113. {
  114. std::map<uint256, CDataStream*>::iterator it;
  115. it = mapOrphanTransactions.lower_bound(GetRandHash());
  116. if (it == mapOrphanTransactions.end())
  117. it = mapOrphanTransactions.begin();
  118. const CDataStream* pvMsg = it->second;
  119. CTransaction tx;
  120. CDataStream(*pvMsg) >> tx;
  121. return tx;
  122. }
  123. BOOST_AUTO_TEST_CASE(DoS_mapOrphans)
  124. {
  125. CKey key;
  126. key.MakeNewKey(true);
  127. CBasicKeyStore keystore;
  128. keystore.AddKey(key);
  129. // 50 orphan transactions:
  130. for (int i = 0; i < 50; i++)
  131. {
  132. CTransaction tx;
  133. tx.vin.resize(1);
  134. tx.vin[0].prevout.n = 0;
  135. tx.vin[0].prevout.hash = GetRandHash();
  136. tx.vin[0].scriptSig << OP_1;
  137. tx.vout.resize(1);
  138. tx.vout[0].nValue = 1*CENT;
  139. tx.vout[0].scriptPubKey.SetDestination(key.GetPubKey().GetID());
  140. CDataStream ds(SER_DISK, CLIENT_VERSION);
  141. ds << tx;
  142. AddOrphanTx(ds);
  143. }
  144. // ... and 50 that depend on other orphans:
  145. for (int i = 0; i < 50; i++)
  146. {
  147. CTransaction txPrev = RandomOrphan();
  148. CTransaction tx;
  149. tx.vin.resize(1);
  150. tx.vin[0].prevout.n = 0;
  151. tx.vin[0].prevout.hash = txPrev.GetHash();
  152. tx.vout.resize(1);
  153. tx.vout[0].nValue = 1*CENT;
  154. tx.vout[0].scriptPubKey.SetDestination(key.GetPubKey().GetID());
  155. SignSignature(keystore, txPrev, tx, 0);
  156. CDataStream ds(SER_DISK, CLIENT_VERSION);
  157. ds << tx;
  158. AddOrphanTx(ds);
  159. }
  160. // This really-big orphan should be ignored:
  161. for (int i = 0; i < 10; i++)
  162. {
  163. CTransaction txPrev = RandomOrphan();
  164. CTransaction tx;
  165. tx.vout.resize(1);
  166. tx.vout[0].nValue = 1*CENT;
  167. tx.vout[0].scriptPubKey.SetDestination(key.GetPubKey().GetID());
  168. tx.vin.resize(500);
  169. for (unsigned int j = 0; j < tx.vin.size(); j++)
  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)
  177. for (unsigned int j = 1; j < tx.vin.size(); j++)
  178. tx.vin[j].scriptSig = tx.vin[0].scriptSig;
  179. CDataStream ds(SER_DISK, CLIENT_VERSION);
  180. ds << tx;
  181. BOOST_CHECK(!AddOrphanTx(ds));
  182. }
  183. // Test LimitOrphanTxSize() function:
  184. LimitOrphanTxSize(40);
  185. BOOST_CHECK(mapOrphanTransactions.size() <= 40);
  186. LimitOrphanTxSize(10);
  187. BOOST_CHECK(mapOrphanTransactions.size() <= 10);
  188. LimitOrphanTxSize(0);
  189. BOOST_CHECK(mapOrphanTransactions.empty());
  190. BOOST_CHECK(mapOrphanTransactionsByPrev.empty());
  191. }
  192. BOOST_AUTO_TEST_CASE(DoS_checkSig)
  193. {
  194. // Test signature caching code (see key.cpp Verify() methods)
  195. CKey key;
  196. key.MakeNewKey(true);
  197. CBasicKeyStore keystore;
  198. keystore.AddKey(key);
  199. unsigned int flags = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC;
  200. // 100 orphan transactions:
  201. static const int NPREV=100;
  202. CTransaction orphans[NPREV];
  203. for (int i = 0; i < NPREV; i++)
  204. {
  205. CTransaction& tx = orphans[i];
  206. tx.vin.resize(1);
  207. tx.vin[0].prevout.n = 0;
  208. tx.vin[0].prevout.hash = GetRandHash();
  209. tx.vin[0].scriptSig << OP_1;
  210. tx.vout.resize(1);
  211. tx.vout[0].nValue = 1*CENT;
  212. tx.vout[0].scriptPubKey.SetDestination(key.GetPubKey().GetID());
  213. CDataStream ds(SER_DISK, CLIENT_VERSION);
  214. ds << tx;
  215. AddOrphanTx(ds);
  216. }
  217. // Create a transaction that depends on orphans:
  218. CTransaction tx;
  219. tx.vout.resize(1);
  220. tx.vout[0].nValue = 1*CENT;
  221. tx.vout[0].scriptPubKey.SetDestination(key.GetPubKey().GetID());
  222. tx.vin.resize(NPREV);
  223. for (unsigned int j = 0; j < tx.vin.size(); j++)
  224. {
  225. tx.vin[j].prevout.n = 0;
  226. tx.vin[j].prevout.hash = orphans[j].GetHash();
  227. }
  228. // Creating signatures primes the cache:
  229. boost::posix_time::ptime mst1 = boost::posix_time::microsec_clock::local_time();
  230. for (unsigned int j = 0; j < tx.vin.size(); j++)
  231. BOOST_CHECK(SignSignature(keystore, orphans[j], tx, j));
  232. boost::posix_time::ptime mst2 = boost::posix_time::microsec_clock::local_time();
  233. boost::posix_time::time_duration msdiff = mst2 - mst1;
  234. long nOneValidate = msdiff.total_milliseconds();
  235. if (fDebug) printf("DoS_Checksig sign: %ld\n", nOneValidate);
  236. // ... now validating repeatedly should be quick:
  237. // 2.8GHz machine, -g build: Sign takes ~760ms,
  238. // uncached Verify takes ~250ms, cached Verify takes ~50ms
  239. // (for 100 single-signature inputs)
  240. mst1 = boost::posix_time::microsec_clock::local_time();
  241. for (unsigned int i = 0; i < 5; i++)
  242. for (unsigned int j = 0; j < tx.vin.size(); j++)
  243. BOOST_CHECK(VerifySignature(CCoins(orphans[j], MEMPOOL_HEIGHT), tx, j, flags, SIGHASH_ALL));
  244. mst2 = boost::posix_time::microsec_clock::local_time();
  245. msdiff = mst2 - mst1;
  246. long nManyValidate = msdiff.total_milliseconds();
  247. if (fDebug) printf("DoS_Checksig five: %ld\n", nManyValidate);
  248. BOOST_CHECK_MESSAGE(nManyValidate < nOneValidate, "Signature cache timing failed");
  249. // Empty a signature, validation should fail:
  250. CScript save = tx.vin[0].scriptSig;
  251. tx.vin[0].scriptSig = CScript();
  252. BOOST_CHECK(!VerifySignature(CCoins(orphans[0], MEMPOOL_HEIGHT), tx, 0, flags, SIGHASH_ALL));
  253. tx.vin[0].scriptSig = save;
  254. // Swap signatures, validation should fail:
  255. std::swap(tx.vin[0].scriptSig, tx.vin[1].scriptSig);
  256. BOOST_CHECK(!VerifySignature(CCoins(orphans[0], MEMPOOL_HEIGHT), tx, 0, flags, SIGHASH_ALL));
  257. BOOST_CHECK(!VerifySignature(CCoins(orphans[1], MEMPOOL_HEIGHT), tx, 1, flags, SIGHASH_ALL));
  258. std::swap(tx.vin[0].scriptSig, tx.vin[1].scriptSig);
  259. // Exercise -maxsigcachesize code:
  260. mapArgs["-maxsigcachesize"] = "10";
  261. // Generate a new, different signature for vin[0] to trigger cache clear:
  262. CScript oldSig = tx.vin[0].scriptSig;
  263. BOOST_CHECK(SignSignature(keystore, orphans[0], tx, 0));
  264. BOOST_CHECK(tx.vin[0].scriptSig != oldSig);
  265. for (unsigned int j = 0; j < tx.vin.size(); j++)
  266. BOOST_CHECK(VerifySignature(CCoins(orphans[j], MEMPOOL_HEIGHT), tx, j, flags, SIGHASH_ALL));
  267. mapArgs.erase("-maxsigcachesize");
  268. LimitOrphanTxSize(0);
  269. }
  270. BOOST_AUTO_TEST_SUITE_END()