Skip to content

Commit af3503d

Browse files
theunidongcarl
authored andcommitted
net: move BanMan to its own files
1 parent d0469b2 commit af3503d

File tree

13 files changed

+276
-237
lines changed

13 files changed

+276
-237
lines changed

src/Makefile.am

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ BITCOIN_CORE_H = \
9696
addrdb.h \
9797
addrman.h \
9898
attributes.h \
99+
banman.h \
99100
base58.h \
100101
bech32.h \
101102
bloom.h \
@@ -225,6 +226,7 @@ libbitcoin_server_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
225226
libbitcoin_server_a_SOURCES = \
226227
addrdb.cpp \
227228
addrman.cpp \
229+
banman.cpp \
228230
bloom.cpp \
229231
blockencodings.cpp \
230232
blockfilter.cpp \

src/banman.cpp

Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
// Copyright (c) 2009-2010 Satoshi Nakamoto
2+
// Copyright (c) 2009-2017 The Bitcoin Core developers
3+
// Distributed under the MIT software license, see the accompanying
4+
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
5+
6+
#include <banman.h>
7+
8+
#include <netaddress.h>
9+
#include <ui_interface.h>
10+
#include <util/system.h>
11+
#include <util/time.h>
12+
13+
14+
BanMan::BanMan(fs::path ban_file, CClientUIInterface* client_interface, int64_t default_ban_time)
15+
: clientInterface(client_interface), m_ban_db(std::move(ban_file)), m_default_ban_time(default_ban_time)
16+
{
17+
if (clientInterface) clientInterface->InitMessage(_("Loading banlist..."));
18+
19+
int64_t nStart = GetTimeMillis();
20+
setBannedIsDirty = false;
21+
banmap_t banmap;
22+
if (m_ban_db.Read(banmap)) {
23+
SetBanned(banmap); // thread save setter
24+
SetBannedSetDirty(false); // no need to write down, just read data
25+
SweepBanned(); // sweep out unused entries
26+
27+
LogPrint(BCLog::NET, "Loaded %d banned node ips/subnets from banlist.dat %dms\n",
28+
banmap.size(), GetTimeMillis() - nStart);
29+
} else {
30+
LogPrintf("Invalid or missing banlist.dat; recreating\n");
31+
SetBannedSetDirty(true); // force write
32+
DumpBanlist();
33+
}
34+
}
35+
36+
BanMan::~BanMan()
37+
{
38+
DumpBanlist();
39+
}
40+
41+
void BanMan::DumpBanlist()
42+
{
43+
SweepBanned(); // clean unused entries (if bantime has expired)
44+
45+
if (!BannedSetIsDirty()) return;
46+
47+
int64_t nStart = GetTimeMillis();
48+
49+
banmap_t banmap;
50+
GetBanned(banmap);
51+
if (m_ban_db.Write(banmap)) {
52+
SetBannedSetDirty(false);
53+
}
54+
55+
LogPrint(BCLog::NET, "Flushed %d banned node ips/subnets to banlist.dat %dms\n",
56+
banmap.size(), GetTimeMillis() - nStart);
57+
}
58+
59+
void BanMan::ClearBanned()
60+
{
61+
{
62+
LOCK(cs_setBanned);
63+
setBanned.clear();
64+
setBannedIsDirty = true;
65+
}
66+
DumpBanlist(); //store banlist to disk
67+
if (clientInterface) clientInterface->BannedListChanged();
68+
}
69+
70+
bool BanMan::IsBanned(CNetAddr netAddr)
71+
{
72+
LOCK(cs_setBanned);
73+
for (const auto& it : setBanned) {
74+
CSubNet subNet = it.first;
75+
CBanEntry banEntry = it.second;
76+
77+
if (subNet.Match(netAddr) && GetTime() < banEntry.nBanUntil) {
78+
return true;
79+
}
80+
}
81+
return false;
82+
}
83+
84+
bool BanMan::IsBanned(CSubNet subNet)
85+
{
86+
LOCK(cs_setBanned);
87+
banmap_t::iterator i = setBanned.find(subNet);
88+
if (i != setBanned.end()) {
89+
CBanEntry banEntry = (*i).second;
90+
if (GetTime() < banEntry.nBanUntil) {
91+
return true;
92+
}
93+
}
94+
return false;
95+
}
96+
97+
void BanMan::Ban(const CNetAddr& netAddr, const BanReason& banReason, int64_t bantimeoffset, bool sinceUnixEpoch)
98+
{
99+
CSubNet subNet(netAddr);
100+
Ban(subNet, banReason, bantimeoffset, sinceUnixEpoch);
101+
}
102+
103+
void BanMan::Ban(const CSubNet& subNet, const BanReason& banReason, int64_t bantimeoffset, bool sinceUnixEpoch)
104+
{
105+
CBanEntry banEntry(GetTime());
106+
banEntry.banReason = banReason;
107+
if (bantimeoffset <= 0) {
108+
bantimeoffset = m_default_ban_time;
109+
sinceUnixEpoch = false;
110+
}
111+
banEntry.nBanUntil = (sinceUnixEpoch ? 0 : GetTime()) + bantimeoffset;
112+
113+
{
114+
LOCK(cs_setBanned);
115+
if (setBanned[subNet].nBanUntil < banEntry.nBanUntil) {
116+
setBanned[subNet] = banEntry;
117+
setBannedIsDirty = true;
118+
} else
119+
return;
120+
}
121+
if (clientInterface) clientInterface->BannedListChanged();
122+
123+
//store banlist to disk immediately if user requested ban
124+
if (banReason == BanReasonManuallyAdded) DumpBanlist();
125+
}
126+
127+
bool BanMan::Unban(const CNetAddr& netAddr)
128+
{
129+
CSubNet subNet(netAddr);
130+
return Unban(subNet);
131+
}
132+
133+
bool BanMan::Unban(const CSubNet& subNet)
134+
{
135+
{
136+
LOCK(cs_setBanned);
137+
if (setBanned.erase(subNet) == 0) return false;
138+
setBannedIsDirty = true;
139+
}
140+
if (clientInterface) clientInterface->BannedListChanged();
141+
DumpBanlist(); //store banlist to disk immediately
142+
return true;
143+
}
144+
145+
void BanMan::GetBanned(banmap_t& banMap)
146+
{
147+
LOCK(cs_setBanned);
148+
// Sweep the banlist so expired bans are not returned
149+
SweepBanned();
150+
banMap = setBanned; //create a thread safe copy
151+
}
152+
153+
void BanMan::SetBanned(const banmap_t& banMap)
154+
{
155+
LOCK(cs_setBanned);
156+
setBanned = banMap;
157+
setBannedIsDirty = true;
158+
}
159+
160+
void BanMan::SweepBanned()
161+
{
162+
int64_t now = GetTime();
163+
bool notifyUI = false;
164+
{
165+
LOCK(cs_setBanned);
166+
banmap_t::iterator it = setBanned.begin();
167+
while (it != setBanned.end()) {
168+
CSubNet subNet = (*it).first;
169+
CBanEntry banEntry = (*it).second;
170+
if (now > banEntry.nBanUntil) {
171+
setBanned.erase(it++);
172+
setBannedIsDirty = true;
173+
notifyUI = true;
174+
LogPrint(BCLog::NET, "%s: Removed banned node ip/subnet from banlist.dat: %s\n", __func__, subNet.ToString());
175+
} else
176+
++it;
177+
}
178+
}
179+
// update UI
180+
if (notifyUI && clientInterface) {
181+
clientInterface->BannedListChanged();
182+
}
183+
}
184+
185+
bool BanMan::BannedSetIsDirty()
186+
{
187+
LOCK(cs_setBanned);
188+
return setBannedIsDirty;
189+
}
190+
191+
void BanMan::SetBannedSetDirty(bool dirty)
192+
{
193+
LOCK(cs_setBanned); //reuse setBanned lock for the setBannedIsDirty flag
194+
setBannedIsDirty = dirty;
195+
}

src/banman.h

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
// Copyright (c) 2009-2010 Satoshi Nakamoto
2+
// Copyright (c) 2009-2017 The Bitcoin Core developers
3+
// Distributed under the MIT software license, see the accompanying
4+
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
5+
#ifndef BITCOIN_BANMAN_H
6+
#define BITCOIN_BANMAN_H
7+
8+
#include <cstdint>
9+
#include <memory>
10+
11+
#include <addrdb.h>
12+
#include <fs.h>
13+
#include <sync.h>
14+
15+
// NOTE: When adjusting this, update rpcnet:setban's help ("24h")
16+
static constexpr unsigned int DEFAULT_MISBEHAVING_BANTIME = 60 * 60 * 24; // Default 24-hour ban
17+
18+
class CClientUIInterface;
19+
class CNetAddr;
20+
class CSubNet;
21+
22+
// Denial-of-service detection/prevention
23+
// The idea is to detect peers that are behaving
24+
// badly and disconnect/ban them, but do it in a
25+
// one-coding-mistake-won't-shatter-the-entire-network
26+
// way.
27+
// IMPORTANT: There should be nothing I can give a
28+
// node that it will forward on that will make that
29+
// node's peers drop it. If there is, an attacker
30+
// can isolate a node and/or try to split the network.
31+
// Dropping a node for sending stuff that is invalid
32+
// now but might be valid in a later version is also
33+
// dangerous, because it can cause a network split
34+
// between nodes running old code and nodes running
35+
// new code.
36+
37+
class BanMan
38+
{
39+
public:
40+
~BanMan();
41+
BanMan(fs::path ban_file, CClientUIInterface* client_interface, int64_t default_ban_time);
42+
void Ban(const CNetAddr& netAddr, const BanReason& banReason, int64_t bantimeoffset = 0, bool sinceUnixEpoch = false);
43+
void Ban(const CSubNet& subNet, const BanReason& banReason, int64_t bantimeoffset = 0, bool sinceUnixEpoch = false);
44+
void ClearBanned(); // needed for unit testing
45+
bool IsBanned(CNetAddr netAddr);
46+
bool IsBanned(CSubNet subNet);
47+
bool Unban(const CNetAddr& netAddr);
48+
bool Unban(const CSubNet& subNet);
49+
void GetBanned(banmap_t& banMap);
50+
void DumpBanlist();
51+
52+
private:
53+
void SetBanned(const banmap_t& banMap);
54+
bool BannedSetIsDirty();
55+
//!set the "dirty" flag for the banlist
56+
void SetBannedSetDirty(bool dirty = true);
57+
//!clean unused entries (if bantime has expired)
58+
void SweepBanned();
59+
60+
banmap_t setBanned;
61+
CCriticalSection cs_setBanned;
62+
bool setBannedIsDirty;
63+
CClientUIInterface* clientInterface = nullptr;
64+
CBanDB m_ban_db;
65+
int64_t m_default_ban_time;
66+
};
67+
68+
extern std::unique_ptr<BanMan> g_banman;
69+
#endif

src/init.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
#include <addrman.h>
1313
#include <amount.h>
14+
#include <banman.h>
1415
#include <chain.h>
1516
#include <chainparams.h>
1617
#include <checkpoints.h>

src/interfaces/node.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
#include <addrdb.h>
88
#include <amount.h>
9+
#include <banman.h>
910
#include <chain.h>
1011
#include <chainparams.h>
1112
#include <init.h>

src/interfaces/node.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include <tuple>
1919
#include <vector>
2020

21+
class BanMan;
2122
class CCoinControl;
2223
class CFeeRate;
2324
class CNodeStats;

0 commit comments

Comments
 (0)