aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/Makefile.am2
-rw-r--r--src/banman.cpp195
-rw-r--r--src/banman.h69
-rw-r--r--src/init.cpp1
-rw-r--r--src/interfaces/node.cpp1
-rw-r--r--src/interfaces/node.h1
-rw-r--r--src/net.cpp190
-rw-r--r--src/net.h49
-rw-r--r--src/net_processing.cpp1
-rw-r--r--src/rpc/net.cpp1
-rw-r--r--src/test/denialofservice_tests.cpp1
-rw-r--r--src/test/test_bitcoin.cpp1
-rw-r--r--src/test/test_bitcoin_main.cpp1
13 files changed, 276 insertions, 237 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 09daaebd23..4b07f06c95 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -96,6 +96,7 @@ BITCOIN_CORE_H = \
addrdb.h \
addrman.h \
attributes.h \
+ banman.h \
base58.h \
bech32.h \
bloom.h \
@@ -225,6 +226,7 @@ libbitcoin_server_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
libbitcoin_server_a_SOURCES = \
addrdb.cpp \
addrman.cpp \
+ banman.cpp \
bloom.cpp \
blockencodings.cpp \
blockfilter.cpp \
diff --git a/src/banman.cpp b/src/banman.cpp
new file mode 100644
index 0000000000..59cfe26318
--- /dev/null
+++ b/src/banman.cpp
@@ -0,0 +1,195 @@
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Copyright (c) 2009-2017 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include <banman.h>
+
+#include <netaddress.h>
+#include <ui_interface.h>
+#include <util/system.h>
+#include <util/time.h>
+
+
+BanMan::BanMan(fs::path ban_file, CClientUIInterface* client_interface, int64_t default_ban_time)
+ : clientInterface(client_interface), m_ban_db(std::move(ban_file)), m_default_ban_time(default_ban_time)
+{
+ if (clientInterface) clientInterface->InitMessage(_("Loading banlist..."));
+
+ int64_t nStart = GetTimeMillis();
+ setBannedIsDirty = false;
+ banmap_t banmap;
+ if (m_ban_db.Read(banmap)) {
+ SetBanned(banmap); // thread save setter
+ SetBannedSetDirty(false); // no need to write down, just read data
+ SweepBanned(); // sweep out unused entries
+
+ LogPrint(BCLog::NET, "Loaded %d banned node ips/subnets from banlist.dat %dms\n",
+ banmap.size(), GetTimeMillis() - nStart);
+ } else {
+ LogPrintf("Invalid or missing banlist.dat; recreating\n");
+ SetBannedSetDirty(true); // force write
+ DumpBanlist();
+ }
+}
+
+BanMan::~BanMan()
+{
+ DumpBanlist();
+}
+
+void BanMan::DumpBanlist()
+{
+ SweepBanned(); // clean unused entries (if bantime has expired)
+
+ if (!BannedSetIsDirty()) return;
+
+ int64_t nStart = GetTimeMillis();
+
+ banmap_t banmap;
+ GetBanned(banmap);
+ if (m_ban_db.Write(banmap)) {
+ SetBannedSetDirty(false);
+ }
+
+ LogPrint(BCLog::NET, "Flushed %d banned node ips/subnets to banlist.dat %dms\n",
+ banmap.size(), GetTimeMillis() - nStart);
+}
+
+void BanMan::ClearBanned()
+{
+ {
+ LOCK(cs_setBanned);
+ setBanned.clear();
+ setBannedIsDirty = true;
+ }
+ DumpBanlist(); //store banlist to disk
+ if (clientInterface) clientInterface->BannedListChanged();
+}
+
+bool BanMan::IsBanned(CNetAddr netAddr)
+{
+ LOCK(cs_setBanned);
+ for (const auto& it : setBanned) {
+ CSubNet subNet = it.first;
+ CBanEntry banEntry = it.second;
+
+ if (subNet.Match(netAddr) && GetTime() < banEntry.nBanUntil) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool BanMan::IsBanned(CSubNet subNet)
+{
+ LOCK(cs_setBanned);
+ banmap_t::iterator i = setBanned.find(subNet);
+ if (i != setBanned.end()) {
+ CBanEntry banEntry = (*i).second;
+ if (GetTime() < banEntry.nBanUntil) {
+ return true;
+ }
+ }
+ return false;
+}
+
+void BanMan::Ban(const CNetAddr& netAddr, const BanReason& banReason, int64_t bantimeoffset, bool sinceUnixEpoch)
+{
+ CSubNet subNet(netAddr);
+ Ban(subNet, banReason, bantimeoffset, sinceUnixEpoch);
+}
+
+void BanMan::Ban(const CSubNet& subNet, const BanReason& banReason, int64_t bantimeoffset, bool sinceUnixEpoch)
+{
+ CBanEntry banEntry(GetTime());
+ banEntry.banReason = banReason;
+ if (bantimeoffset <= 0) {
+ bantimeoffset = m_default_ban_time;
+ sinceUnixEpoch = false;
+ }
+ banEntry.nBanUntil = (sinceUnixEpoch ? 0 : GetTime()) + bantimeoffset;
+
+ {
+ LOCK(cs_setBanned);
+ if (setBanned[subNet].nBanUntil < banEntry.nBanUntil) {
+ setBanned[subNet] = banEntry;
+ setBannedIsDirty = true;
+ } else
+ return;
+ }
+ if (clientInterface) clientInterface->BannedListChanged();
+
+ //store banlist to disk immediately if user requested ban
+ if (banReason == BanReasonManuallyAdded) DumpBanlist();
+}
+
+bool BanMan::Unban(const CNetAddr& netAddr)
+{
+ CSubNet subNet(netAddr);
+ return Unban(subNet);
+}
+
+bool BanMan::Unban(const CSubNet& subNet)
+{
+ {
+ LOCK(cs_setBanned);
+ if (setBanned.erase(subNet) == 0) return false;
+ setBannedIsDirty = true;
+ }
+ if (clientInterface) clientInterface->BannedListChanged();
+ DumpBanlist(); //store banlist to disk immediately
+ return true;
+}
+
+void BanMan::GetBanned(banmap_t& banMap)
+{
+ LOCK(cs_setBanned);
+ // Sweep the banlist so expired bans are not returned
+ SweepBanned();
+ banMap = setBanned; //create a thread safe copy
+}
+
+void BanMan::SetBanned(const banmap_t& banMap)
+{
+ LOCK(cs_setBanned);
+ setBanned = banMap;
+ setBannedIsDirty = true;
+}
+
+void BanMan::SweepBanned()
+{
+ int64_t now = GetTime();
+ bool notifyUI = false;
+ {
+ LOCK(cs_setBanned);
+ banmap_t::iterator it = setBanned.begin();
+ while (it != setBanned.end()) {
+ CSubNet subNet = (*it).first;
+ CBanEntry banEntry = (*it).second;
+ if (now > banEntry.nBanUntil) {
+ setBanned.erase(it++);
+ setBannedIsDirty = true;
+ notifyUI = true;
+ LogPrint(BCLog::NET, "%s: Removed banned node ip/subnet from banlist.dat: %s\n", __func__, subNet.ToString());
+ } else
+ ++it;
+ }
+ }
+ // update UI
+ if (notifyUI && clientInterface) {
+ clientInterface->BannedListChanged();
+ }
+}
+
+bool BanMan::BannedSetIsDirty()
+{
+ LOCK(cs_setBanned);
+ return setBannedIsDirty;
+}
+
+void BanMan::SetBannedSetDirty(bool dirty)
+{
+ LOCK(cs_setBanned); //reuse setBanned lock for the setBannedIsDirty flag
+ setBannedIsDirty = dirty;
+}
diff --git a/src/banman.h b/src/banman.h
new file mode 100644
index 0000000000..898ae85197
--- /dev/null
+++ b/src/banman.h
@@ -0,0 +1,69 @@
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Copyright (c) 2009-2017 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#ifndef BITCOIN_BANMAN_H
+#define BITCOIN_BANMAN_H
+
+#include <cstdint>
+#include <memory>
+
+#include <addrdb.h>
+#include <fs.h>
+#include <sync.h>
+
+// NOTE: When adjusting this, update rpcnet:setban's help ("24h")
+static constexpr unsigned int DEFAULT_MISBEHAVING_BANTIME = 60 * 60 * 24; // Default 24-hour ban
+
+class CClientUIInterface;
+class CNetAddr;
+class CSubNet;
+
+// Denial-of-service detection/prevention
+// The idea is to detect peers that are behaving
+// badly and disconnect/ban them, but do it in a
+// one-coding-mistake-won't-shatter-the-entire-network
+// way.
+// IMPORTANT: There should be nothing I can give a
+// node that it will forward on that will make that
+// node's peers drop it. If there is, an attacker
+// can isolate a node and/or try to split the network.
+// Dropping a node for sending stuff that is invalid
+// now but might be valid in a later version is also
+// dangerous, because it can cause a network split
+// between nodes running old code and nodes running
+// new code.
+
+class BanMan
+{
+public:
+ ~BanMan();
+ BanMan(fs::path ban_file, CClientUIInterface* client_interface, int64_t default_ban_time);
+ void Ban(const CNetAddr& netAddr, const BanReason& banReason, int64_t bantimeoffset = 0, bool sinceUnixEpoch = false);
+ void Ban(const CSubNet& subNet, const BanReason& banReason, int64_t bantimeoffset = 0, bool sinceUnixEpoch = false);
+ void ClearBanned(); // needed for unit testing
+ bool IsBanned(CNetAddr netAddr);
+ bool IsBanned(CSubNet subNet);
+ bool Unban(const CNetAddr& netAddr);
+ bool Unban(const CSubNet& subNet);
+ void GetBanned(banmap_t& banMap);
+ void DumpBanlist();
+
+private:
+ void SetBanned(const banmap_t& banMap);
+ bool BannedSetIsDirty();
+ //!set the "dirty" flag for the banlist
+ void SetBannedSetDirty(bool dirty = true);
+ //!clean unused entries (if bantime has expired)
+ void SweepBanned();
+
+ banmap_t setBanned;
+ CCriticalSection cs_setBanned;
+ bool setBannedIsDirty;
+ CClientUIInterface* clientInterface = nullptr;
+ CBanDB m_ban_db;
+ int64_t m_default_ban_time;
+};
+
+extern std::unique_ptr<BanMan> g_banman;
+#endif
diff --git a/src/init.cpp b/src/init.cpp
index 0f59dfbef5..77d0505610 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -11,6 +11,7 @@
#include <addrman.h>
#include <amount.h>
+#include <banman.h>
#include <chain.h>
#include <chainparams.h>
#include <checkpoints.h>
diff --git a/src/interfaces/node.cpp b/src/interfaces/node.cpp
index c535b29315..c574f960e6 100644
--- a/src/interfaces/node.cpp
+++ b/src/interfaces/node.cpp
@@ -6,6 +6,7 @@
#include <addrdb.h>
#include <amount.h>
+#include <banman.h>
#include <chain.h>
#include <chainparams.h>
#include <init.h>
diff --git a/src/interfaces/node.h b/src/interfaces/node.h
index 6aa8ce0797..54c2d78338 100644
--- a/src/interfaces/node.h
+++ b/src/interfaces/node.h
@@ -18,6 +18,7 @@
#include <tuple>
#include <vector>
+class BanMan;
class CCoinControl;
class CFeeRate;
class CNodeStats;
diff --git a/src/net.cpp b/src/net.cpp
index f6491bc8db..0490ccd6db 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -9,6 +9,7 @@
#include <net.h>
+#include <banman.h>
#include <chainparams.h>
#include <clientversion.h>
#include <consensus/consensus.h>
@@ -457,25 +458,6 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo
return pnode;
}
-void BanMan::DumpBanlist()
-{
- SweepBanned(); // clean unused entries (if bantime has expired)
-
- if (!BannedSetIsDirty())
- return;
-
- int64_t nStart = GetTimeMillis();
-
- banmap_t banmap;
- GetBanned(banmap);
- if (m_ban_db.Write(banmap)) {
- SetBannedSetDirty(false);
- }
-
- LogPrint(BCLog::NET, "Flushed %d banned node ips/subnets to banlist.dat %dms\n",
- banmap.size(), GetTimeMillis() - nStart);
-}
-
void CNode::CloseSocketDisconnect()
{
fDisconnect = true;
@@ -487,150 +469,6 @@ void CNode::CloseSocketDisconnect()
}
}
-void BanMan::ClearBanned()
-{
- {
- LOCK(cs_setBanned);
- setBanned.clear();
- setBannedIsDirty = true;
- }
- DumpBanlist(); //store banlist to disk
- if(clientInterface)
- clientInterface->BannedListChanged();
-}
-
-bool BanMan::IsBanned(CNetAddr ip)
-{
- LOCK(cs_setBanned);
- for (const auto& it : setBanned) {
- CSubNet subNet = it.first;
- CBanEntry banEntry = it.second;
-
- if (subNet.Match(ip) && GetTime() < banEntry.nBanUntil) {
- return true;
- }
- }
- return false;
-}
-
-bool BanMan::IsBanned(CSubNet subnet)
-{
- LOCK(cs_setBanned);
- banmap_t::iterator i = setBanned.find(subnet);
- if (i != setBanned.end())
- {
- CBanEntry banEntry = (*i).second;
- if (GetTime() < banEntry.nBanUntil) {
- return true;
- }
- }
- return false;
-}
-
-void BanMan::Ban(const CNetAddr& addr, const BanReason &banReason, int64_t bantimeoffset, bool sinceUnixEpoch) {
- CSubNet subNet(addr);
- Ban(subNet, banReason, bantimeoffset, sinceUnixEpoch);
-}
-
-void BanMan::Ban(const CSubNet& subNet, const BanReason &banReason, int64_t bantimeoffset, bool sinceUnixEpoch) {
- CBanEntry banEntry(GetTime());
- banEntry.banReason = banReason;
- if (bantimeoffset <= 0)
- {
- bantimeoffset = m_default_ban_time;
- sinceUnixEpoch = false;
- }
- banEntry.nBanUntil = (sinceUnixEpoch ? 0 : GetTime() )+bantimeoffset;
-
- {
- LOCK(cs_setBanned);
- if (setBanned[subNet].nBanUntil < banEntry.nBanUntil) {
- setBanned[subNet] = banEntry;
- setBannedIsDirty = true;
- }
- else
- return;
- }
- if(clientInterface)
- clientInterface->BannedListChanged();
- if(banReason == BanReasonManuallyAdded)
- DumpBanlist(); //store banlist to disk immediately if user requested ban
-}
-
-bool BanMan::Unban(const CNetAddr &addr) {
- CSubNet subNet(addr);
- return Unban(subNet);
-}
-
-bool BanMan::Unban(const CSubNet &subNet) {
- {
- LOCK(cs_setBanned);
- if (!setBanned.erase(subNet))
- return false;
- setBannedIsDirty = true;
- }
- if(clientInterface)
- clientInterface->BannedListChanged();
- DumpBanlist(); //store banlist to disk immediately
- return true;
-}
-
-void BanMan::GetBanned(banmap_t &banMap)
-{
- LOCK(cs_setBanned);
- // Sweep the banlist so expired bans are not returned
- SweepBanned();
- banMap = setBanned; //create a thread safe copy
-}
-
-void BanMan::SetBanned(const banmap_t &banMap)
-{
- LOCK(cs_setBanned);
- setBanned = banMap;
- setBannedIsDirty = true;
-}
-
-void BanMan::SweepBanned()
-{
- int64_t now = GetTime();
- bool notifyUI = false;
- {
- LOCK(cs_setBanned);
- banmap_t::iterator it = setBanned.begin();
- while(it != setBanned.end())
- {
- CSubNet subNet = (*it).first;
- CBanEntry banEntry = (*it).second;
- if(now > banEntry.nBanUntil)
- {
- setBanned.erase(it++);
- setBannedIsDirty = true;
- notifyUI = true;
- LogPrint(BCLog::NET, "%s: Removed banned node ip/subnet from banlist.dat: %s\n", __func__, subNet.ToString());
- }
- else
- ++it;
- }
- }
- // update UI
- if(notifyUI && clientInterface) {
- clientInterface->BannedListChanged();
- }
-}
-
-bool BanMan::BannedSetIsDirty()
-{
- LOCK(cs_setBanned);
- return setBannedIsDirty;
-}
-
-void BanMan::SetBannedSetDirty(bool dirty)
-{
- LOCK(cs_setBanned); //reuse setBanned lock for the isDirty flag
- setBannedIsDirty = dirty;
-}
-
-
bool CConnman::IsWhitelistedRange(const CNetAddr &addr) {
for (const CSubNet& subnet : vWhitelistedRange) {
if (subnet.Match(addr))
@@ -2430,32 +2268,6 @@ bool CConnman::Start(CScheduler& scheduler, const Options& connOptions)
return true;
}
-BanMan::BanMan(fs::path ban_file, CClientUIInterface* client_interface, int64_t default_ban_time) : clientInterface(client_interface), m_ban_db(std::move(ban_file)), m_default_ban_time(default_ban_time)
-{
- if (clientInterface) clientInterface->InitMessage(_("Loading banlist..."));
-
- int64_t nStart = GetTimeMillis();
- setBannedIsDirty = false;
- banmap_t banmap;
- if (m_ban_db.Read(banmap)) {
- SetBanned(banmap); // thread save setter
- SetBannedSetDirty(false); // no need to write down, just read data
- SweepBanned(); // sweep out unused entries
-
- LogPrint(BCLog::NET, "Loaded %d banned node ips/subnets from banlist.dat %dms\n",
- banmap.size(), GetTimeMillis() - nStart);
- } else {
- LogPrintf("Invalid or missing banlist.dat; recreating\n");
- SetBannedSetDirty(true); // force write
- DumpBanlist();
- }
-}
-
-BanMan::~BanMan()
-{
- DumpBanlist();
-}
-
class CNetCleanup
{
public:
diff --git a/src/net.h b/src/net.h
index a6a536d68a..3606b4d7ba 100644
--- a/src/net.h
+++ b/src/net.h
@@ -37,6 +37,7 @@
class CScheduler;
class CNode;
+class BanMan;
/** Time between pings automatically sent out for latency probing and keepalive (in seconds). */
static const int PING_INTERVAL = 2 * 60;
@@ -85,9 +86,6 @@ static const bool DEFAULT_FORCEDNSSEED = false;
static const size_t DEFAULT_MAXRECEIVEBUFFER = 5 * 1000;
static const size_t DEFAULT_MAXSENDBUFFER = 1 * 1000;
-// NOTE: When adjusting this, update rpcnet:setban's help ("24h")
-static constexpr unsigned int DEFAULT_MISBEHAVING_BANTIME = 60 * 60 * 24; // Default 24-hour ban
-
typedef int64_t NodeId;
struct AddedNodeInfo
@@ -115,51 +113,6 @@ struct CSerializedNetMsg
};
-class BanMan
-{
-public:
- // Denial-of-service detection/prevention
- // The idea is to detect peers that are behaving
- // badly and disconnect/ban them, but do it in a
- // one-coding-mistake-won't-shatter-the-entire-network
- // way.
- // IMPORTANT: There should be nothing I can give a
- // node that it will forward on that will make that
- // node's peers drop it. If there is, an attacker
- // can isolate a node and/or try to split the network.
- // Dropping a node for sending stuff that is invalid
- // now but might be valid in a later version is also
- // dangerous, because it can cause a network split
- // between nodes running old code and nodes running
- // new code.
- ~BanMan();
- BanMan(fs::path ban_file, CClientUIInterface* client_interface, int64_t default_ban_time);
- void Ban(const CNetAddr& netAddr, const BanReason& reason, int64_t bantimeoffset = 0, bool sinceUnixEpoch = false);
- void Ban(const CSubNet& subNet, const BanReason& reason, int64_t bantimeoffset = 0, bool sinceUnixEpoch = false);
- void ClearBanned(); // needed for unit testing
- bool IsBanned(CNetAddr ip);
- bool IsBanned(CSubNet subnet);
- bool Unban(const CNetAddr &ip);
- bool Unban(const CSubNet &ip);
- void GetBanned(banmap_t &banmap);
- void DumpBanlist();
-
-private:
- void SetBanned(const banmap_t &banmap);
- bool BannedSetIsDirty();
- //!set the "dirty" flag for the banlist
- void SetBannedSetDirty(bool dirty=true);
- //!clean unused entries (if bantime has expired)
- void SweepBanned();
-
- banmap_t setBanned;
- CCriticalSection cs_setBanned;
- bool setBannedIsDirty;
- CClientUIInterface* clientInterface = nullptr;
- CBanDB m_ban_db;
- int64_t m_default_ban_time;
-};
-
class NetEventsInterface;
class CConnman
{
diff --git a/src/net_processing.cpp b/src/net_processing.cpp
index 6dd6368f74..62b7d4e966 100644
--- a/src/net_processing.cpp
+++ b/src/net_processing.cpp
@@ -6,6 +6,7 @@
#include <net_processing.h>
#include <addrman.h>
+#include <banman.h>
#include <arith_uint256.h>
#include <blockencodings.h>
#include <chainparams.h>
diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp
index 19561c4fc7..7994d3b125 100644
--- a/src/rpc/net.cpp
+++ b/src/rpc/net.cpp
@@ -4,6 +4,7 @@
#include <rpc/server.h>
+#include <banman.h>
#include <chainparams.h>
#include <clientversion.h>
#include <core_io.h>
diff --git a/src/test/denialofservice_tests.cpp b/src/test/denialofservice_tests.cpp
index 29bb34bddc..e5d62a3ab2 100644
--- a/src/test/denialofservice_tests.cpp
+++ b/src/test/denialofservice_tests.cpp
@@ -4,6 +4,7 @@
// Unit tests for denial-of-service detection/prevention code
+#include <banman.h>
#include <chainparams.h>
#include <keystore.h>
#include <net.h>
diff --git a/src/test/test_bitcoin.cpp b/src/test/test_bitcoin.cpp
index 75bd8db67e..ad7fa01710 100644
--- a/src/test/test_bitcoin.cpp
+++ b/src/test/test_bitcoin.cpp
@@ -4,6 +4,7 @@
#include <test/test_bitcoin.h>
+#include <banman.h>
#include <chainparams.h>
#include <consensus/consensus.h>
#include <consensus/params.h>
diff --git a/src/test/test_bitcoin_main.cpp b/src/test/test_bitcoin_main.cpp
index caa35c0efc..46b63b93b4 100644
--- a/src/test/test_bitcoin_main.cpp
+++ b/src/test/test_bitcoin_main.cpp
@@ -4,6 +4,7 @@
#define BOOST_TEST_MODULE Bitcoin Test Suite
+#include <banman.h>
#include <net.h>
#include <memory>