diff options
Diffstat (limited to 'src/test/DoS_tests.cpp')
| -rw-r--r-- | src/test/DoS_tests.cpp | 204 |
1 files changed, 204 insertions, 0 deletions
diff --git a/src/test/DoS_tests.cpp b/src/test/DoS_tests.cpp new file mode 100644 index 000000000..97abeb721 --- /dev/null +++ b/src/test/DoS_tests.cpp @@ -0,0 +1,204 @@ +// Copyright (c) 2011-2015 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +// Unit tests for denial-of-service detection/prevention code + +#include "chainparams.h" +#include "keystore.h" +#include "main.h" +#include "net.h" +#include "pow.h" +#include "script/sign.h" +#include "serialize.h" +#include "util.h" + +#include "test/test_bitcoin.h" + +#include <stdint.h> + +#include <boost/assign/list_of.hpp> // for 'map_list_of()' +#include <boost/date_time/posix_time/posix_time_types.hpp> +#include <boost/foreach.hpp> +#include <boost/test/unit_test.hpp> + +// Tests this internal-to-main.cpp method: +extern bool AddOrphanTx(const CTransaction& tx, NodeId peer); +extern void EraseOrphansFor(NodeId peer); +extern unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans); +struct COrphanTx { + CTransaction tx; + NodeId fromPeer; +}; +extern std::map<uint256, COrphanTx> mapOrphanTransactions; +extern std::map<uint256, std::set<uint256> > mapOrphanTransactionsByPrev; + +CService ip(uint32_t i) +{ + struct in_addr s; + s.s_addr = i; + return CService(CNetAddr(s), Params().GetDefaultPort()); +} + +static NodeId id = 0; + +BOOST_FIXTURE_TEST_SUITE(DoS_tests, TestingSetup) + +BOOST_AUTO_TEST_CASE(DoS_banning) +{ + connman->ClearBanned(); + CAddress addr1(ip(0xa0b0c001), NODE_NONE); + CNode dummyNode1(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr1, 0, "", true); + GetNodeSignals().InitializeNode(dummyNode1.GetId(), &dummyNode1); + dummyNode1.nVersion = 1; + Misbehaving(dummyNode1.GetId(), 100); // Should get banned + SendMessages(&dummyNode1, *connman); + BOOST_CHECK(connman->IsBanned(addr1)); + BOOST_CHECK(!connman->IsBanned(ip(0xa0b0c001|0x0000ff00))); // Different IP, not banned + + CAddress addr2(ip(0xa0b0c002), NODE_NONE); + CNode dummyNode2(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr2, 1, "", true); + GetNodeSignals().InitializeNode(dummyNode2.GetId(), &dummyNode2); + dummyNode2.nVersion = 1; + Misbehaving(dummyNode2.GetId(), 50); + SendMessages(&dummyNode2, *connman); + BOOST_CHECK(!connman->IsBanned(addr2)); // 2 not banned yet... + BOOST_CHECK(connman->IsBanned(addr1)); // ... but 1 still should be + Misbehaving(dummyNode2.GetId(), 50); + SendMessages(&dummyNode2, *connman); + BOOST_CHECK(connman->IsBanned(addr2)); +} + +BOOST_AUTO_TEST_CASE(DoS_banscore) +{ + connman->ClearBanned(); + mapArgs["-banscore"] = "111"; // because 11 is my favorite number + CAddress addr1(ip(0xa0b0c001), NODE_NONE); + CNode dummyNode1(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr1, 3, "", true); + GetNodeSignals().InitializeNode(dummyNode1.GetId(), &dummyNode1); + dummyNode1.nVersion = 1; + Misbehaving(dummyNode1.GetId(), 100); + SendMessages(&dummyNode1, *connman); + BOOST_CHECK(!connman->IsBanned(addr1)); + Misbehaving(dummyNode1.GetId(), 10); + SendMessages(&dummyNode1, *connman); + BOOST_CHECK(!connman->IsBanned(addr1)); + Misbehaving(dummyNode1.GetId(), 1); + SendMessages(&dummyNode1, *connman); + BOOST_CHECK(connman->IsBanned(addr1)); + mapArgs.erase("-banscore"); +} + +BOOST_AUTO_TEST_CASE(DoS_bantime) +{ + connman->ClearBanned(); + int64_t nStartTime = GetTime(); + SetMockTime(nStartTime); // Overrides future calls to GetTime() + + CAddress addr(ip(0xa0b0c001), NODE_NONE); + CNode dummyNode(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr, 4, "", true); + GetNodeSignals().InitializeNode(dummyNode.GetId(), &dummyNode); + dummyNode.nVersion = 1; + + Misbehaving(dummyNode.GetId(), 100); + SendMessages(&dummyNode, *connman); + BOOST_CHECK(connman->IsBanned(addr)); + + SetMockTime(nStartTime+60*60); + BOOST_CHECK(connman->IsBanned(addr)); + + SetMockTime(nStartTime+60*60*24+1); + BOOST_CHECK(!connman->IsBanned(addr)); +} + +CTransaction RandomOrphan() +{ + std::map<uint256, COrphanTx>::iterator it; + it = mapOrphanTransactions.lower_bound(GetRandHash()); + if (it == mapOrphanTransactions.end()) + it = mapOrphanTransactions.begin(); + return it->second.tx; +} + +BOOST_AUTO_TEST_CASE(DoS_mapOrphans) +{ + CKey key; + key.MakeNewKey(true); + CBasicKeyStore keystore; + keystore.AddKey(key); + + // 50 orphan transactions: + for (int i = 0; i < 50; i++) + { + CMutableTransaction tx; + tx.vin.resize(1); + tx.vin[0].prevout.n = 0; + tx.vin[0].prevout.hash = GetRandHash(); + tx.vin[0].scriptSig << OP_1; + tx.vout.resize(1); + tx.vout[0].nValue = 1*CENT; + tx.vout[0].scriptPubKey = GetScriptForDestination(key.GetPubKey().GetID()); + + AddOrphanTx(tx, i); + } + + // ... and 50 that depend on other orphans: + for (int i = 0; i < 50; i++) + { + CTransaction txPrev = RandomOrphan(); + + CMutableTransaction tx; + tx.vin.resize(1); + tx.vin[0].prevout.n = 0; + tx.vin[0].prevout.hash = txPrev.GetHash(); + tx.vout.resize(1); + tx.vout[0].nValue = 1*CENT; + tx.vout[0].scriptPubKey = GetScriptForDestination(key.GetPubKey().GetID()); + SignSignature(keystore, txPrev, tx, 0, SIGHASH_ALL); + + AddOrphanTx(tx, i); + } + + // This really-big orphan should be ignored: + for (int i = 0; i < 10; i++) + { + CTransaction txPrev = RandomOrphan(); + + CMutableTransaction tx; + tx.vout.resize(1); + tx.vout[0].nValue = 1*CENT; + tx.vout[0].scriptPubKey = GetScriptForDestination(key.GetPubKey().GetID()); + tx.vin.resize(2777); + for (unsigned int j = 0; j < tx.vin.size(); j++) + { + tx.vin[j].prevout.n = j; + tx.vin[j].prevout.hash = txPrev.GetHash(); + } + SignSignature(keystore, txPrev, tx, 0, SIGHASH_ALL); + // Re-use same signature for other inputs + // (they don't have to be valid for this test) + for (unsigned int j = 1; j < tx.vin.size(); j++) + tx.vin[j].scriptSig = tx.vin[0].scriptSig; + + BOOST_CHECK(!AddOrphanTx(tx, i)); + } + + // Test EraseOrphansFor: + for (NodeId i = 0; i < 3; i++) + { + size_t sizeBefore = mapOrphanTransactions.size(); + EraseOrphansFor(i); + BOOST_CHECK(mapOrphanTransactions.size() < sizeBefore); + } + + // Test LimitOrphanTxSize() function: + LimitOrphanTxSize(40); + BOOST_CHECK(mapOrphanTransactions.size() <= 40); + LimitOrphanTxSize(10); + BOOST_CHECK(mapOrphanTransactions.size() <= 10); + LimitOrphanTxSize(0); + BOOST_CHECK(mapOrphanTransactions.empty()); + BOOST_CHECK(mapOrphanTransactionsByPrev.empty()); +} + +BOOST_AUTO_TEST_SUITE_END() |