mirror of
https://github.com/bitcoin/bitcoin.git
synced 2024-11-20 02:25:40 +01:00
banman: create and split out banman
Some say he has always been.
This commit is contained in:
parent
83c1ea2e5e
commit
4c0d961eb0
17
src/init.cpp
17
src/init.cpp
@ -73,8 +73,12 @@ static const bool DEFAULT_PROXYRANDOMIZE = true;
|
||||
static const bool DEFAULT_REST_ENABLE = false;
|
||||
static const bool DEFAULT_STOPAFTERBLOCKIMPORT = false;
|
||||
|
||||
// Dump addresses to banlist.dat every 15 minutes (900s)
|
||||
static constexpr int DUMP_BANS_INTERVAL = 60 * 15;
|
||||
|
||||
std::unique_ptr<CConnman> g_connman;
|
||||
std::unique_ptr<PeerLogicValidation> peerLogic;
|
||||
std::unique_ptr<BanMan> g_banman;
|
||||
|
||||
#ifdef WIN32
|
||||
// Win32 LevelDB doesn't use filedescriptors, and the ones used for
|
||||
@ -199,6 +203,7 @@ void Shutdown(InitInterfaces& interfaces)
|
||||
// destruct and reset all to nullptr.
|
||||
peerLogic.reset();
|
||||
g_connman.reset();
|
||||
g_banman.reset();
|
||||
g_txindex.reset();
|
||||
|
||||
if (g_is_mempool_loaded && gArgs.GetArg("-persistmempool", DEFAULT_PERSIST_MEMPOOL)) {
|
||||
@ -1290,11 +1295,12 @@ bool AppInitMain(InitInterfaces& interfaces)
|
||||
// is not yet setup and may end up being set up twice if we
|
||||
// need to reindex later.
|
||||
|
||||
assert(!g_banman);
|
||||
g_banman = MakeUnique<BanMan>(&uiInterface);
|
||||
assert(!g_connman);
|
||||
g_connman = std::unique_ptr<CConnman>(new CConnman(GetRand(std::numeric_limits<uint64_t>::max()), GetRand(std::numeric_limits<uint64_t>::max())));
|
||||
CConnman& connman = *g_connman;
|
||||
|
||||
peerLogic.reset(new PeerLogicValidation(&connman, scheduler, gArgs.GetBoolArg("-enablebip61", DEFAULT_ENABLE_BIP61)));
|
||||
peerLogic.reset(new PeerLogicValidation(g_connman.get(), g_banman.get(), scheduler, gArgs.GetBoolArg("-enablebip61", DEFAULT_ENABLE_BIP61)));
|
||||
RegisterValidationInterface(peerLogic.get());
|
||||
|
||||
// sanitize comments per BIP-0014, format user agent and check total size
|
||||
@ -1704,6 +1710,7 @@ bool AppInitMain(InitInterfaces& interfaces)
|
||||
connOptions.nMaxFeeler = 1;
|
||||
connOptions.nBestHeight = chain_active_height;
|
||||
connOptions.uiInterface = &uiInterface;
|
||||
connOptions.m_banman = g_banman.get();
|
||||
connOptions.m_msgproc = peerLogic.get();
|
||||
connOptions.nSendBufferMaxSize = 1000*gArgs.GetArg("-maxsendbuffer", DEFAULT_MAXSENDBUFFER);
|
||||
connOptions.nReceiveFloodSize = 1000*gArgs.GetArg("-maxreceivebuffer", DEFAULT_MAXRECEIVEBUFFER);
|
||||
@ -1749,7 +1756,7 @@ bool AppInitMain(InitInterfaces& interfaces)
|
||||
connOptions.m_specified_outgoing = connect;
|
||||
}
|
||||
}
|
||||
if (!connman.Start(scheduler, connOptions)) {
|
||||
if (!g_connman->Start(scheduler, connOptions)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -1762,5 +1769,9 @@ bool AppInitMain(InitInterfaces& interfaces)
|
||||
client->start(scheduler);
|
||||
}
|
||||
|
||||
scheduler.scheduleEvery([]{
|
||||
g_banman->DumpBanlist();
|
||||
}, DUMP_BANS_INTERVAL * 1000);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -122,24 +122,24 @@ public:
|
||||
}
|
||||
bool getBanned(banmap_t& banmap) override
|
||||
{
|
||||
if (g_connman) {
|
||||
g_connman->GetBanned(banmap);
|
||||
if (g_banman) {
|
||||
g_banman->GetBanned(banmap);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool ban(const CNetAddr& net_addr, BanReason reason, int64_t ban_time_offset) override
|
||||
{
|
||||
if (g_connman) {
|
||||
g_connman->Ban(net_addr, reason, ban_time_offset);
|
||||
if (g_banman) {
|
||||
g_banman->Ban(net_addr, reason, ban_time_offset);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool unban(const CSubNet& ip) override
|
||||
{
|
||||
if (g_connman) {
|
||||
g_connman->Unban(ip);
|
||||
if (g_banman) {
|
||||
g_banman->Unban(ip);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
81
src/net.cpp
81
src/net.cpp
@ -44,9 +44,6 @@
|
||||
// Dump addresses to peers.dat every 15 minutes (900s)
|
||||
static constexpr int DUMP_PEERS_INTERVAL = 15 * 60;
|
||||
|
||||
// Dump addresses to banlist.dat every 15 minutes (900s)
|
||||
static constexpr int DUMP_BANS_INTERVAL = 60 * 15;
|
||||
|
||||
// We add a random period time (0 to 1 seconds) to feeler connections to prevent synchronization.
|
||||
#define FEELER_SLEEP_WINDOW 1
|
||||
|
||||
@ -460,7 +457,7 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo
|
||||
return pnode;
|
||||
}
|
||||
|
||||
void CConnman::DumpBanlist()
|
||||
void BanMan::DumpBanlist()
|
||||
{
|
||||
SweepBanned(); // clean unused entries (if bantime has expired)
|
||||
|
||||
@ -491,7 +488,7 @@ void CNode::CloseSocketDisconnect()
|
||||
}
|
||||
}
|
||||
|
||||
void CConnman::ClearBanned()
|
||||
void BanMan::ClearBanned()
|
||||
{
|
||||
{
|
||||
LOCK(cs_setBanned);
|
||||
@ -503,7 +500,7 @@ void CConnman::ClearBanned()
|
||||
clientInterface->BannedListChanged();
|
||||
}
|
||||
|
||||
bool CConnman::IsBanned(CNetAddr ip)
|
||||
bool BanMan::IsBanned(CNetAddr ip)
|
||||
{
|
||||
LOCK(cs_setBanned);
|
||||
for (const auto& it : setBanned) {
|
||||
@ -517,7 +514,7 @@ bool CConnman::IsBanned(CNetAddr ip)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CConnman::IsBanned(CSubNet subnet)
|
||||
bool BanMan::IsBanned(CSubNet subnet)
|
||||
{
|
||||
LOCK(cs_setBanned);
|
||||
banmap_t::iterator i = setBanned.find(subnet);
|
||||
@ -531,12 +528,12 @@ bool CConnman::IsBanned(CSubNet subnet)
|
||||
return false;
|
||||
}
|
||||
|
||||
void CConnman::Ban(const CNetAddr& addr, const BanReason &banReason, int64_t bantimeoffset, bool sinceUnixEpoch) {
|
||||
void BanMan::Ban(const CNetAddr& addr, const BanReason &banReason, int64_t bantimeoffset, bool sinceUnixEpoch) {
|
||||
CSubNet subNet(addr);
|
||||
Ban(subNet, banReason, bantimeoffset, sinceUnixEpoch);
|
||||
}
|
||||
|
||||
void CConnman::Ban(const CSubNet& subNet, const BanReason &banReason, int64_t bantimeoffset, bool sinceUnixEpoch) {
|
||||
void BanMan::Ban(const CSubNet& subNet, const BanReason &banReason, int64_t bantimeoffset, bool sinceUnixEpoch) {
|
||||
CBanEntry banEntry(GetTime());
|
||||
banEntry.banReason = banReason;
|
||||
if (bantimeoffset <= 0)
|
||||
@ -561,12 +558,12 @@ void CConnman::Ban(const CSubNet& subNet, const BanReason &banReason, int64_t ba
|
||||
DumpBanlist(); //store banlist to disk immediately if user requested ban
|
||||
}
|
||||
|
||||
bool CConnman::Unban(const CNetAddr &addr) {
|
||||
bool BanMan::Unban(const CNetAddr &addr) {
|
||||
CSubNet subNet(addr);
|
||||
return Unban(subNet);
|
||||
}
|
||||
|
||||
bool CConnman::Unban(const CSubNet &subNet) {
|
||||
bool BanMan::Unban(const CSubNet &subNet) {
|
||||
{
|
||||
LOCK(cs_setBanned);
|
||||
if (!setBanned.erase(subNet))
|
||||
@ -579,7 +576,7 @@ bool CConnman::Unban(const CSubNet &subNet) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void CConnman::GetBanned(banmap_t &banMap)
|
||||
void BanMan::GetBanned(banmap_t &banMap)
|
||||
{
|
||||
LOCK(cs_setBanned);
|
||||
// Sweep the banlist so expired bans are not returned
|
||||
@ -587,14 +584,14 @@ void CConnman::GetBanned(banmap_t &banMap)
|
||||
banMap = setBanned; //create a thread safe copy
|
||||
}
|
||||
|
||||
void CConnman::SetBanned(const banmap_t &banMap)
|
||||
void BanMan::SetBanned(const banmap_t &banMap)
|
||||
{
|
||||
LOCK(cs_setBanned);
|
||||
setBanned = banMap;
|
||||
setBannedIsDirty = true;
|
||||
}
|
||||
|
||||
void CConnman::SweepBanned()
|
||||
void BanMan::SweepBanned()
|
||||
{
|
||||
int64_t now = GetTime();
|
||||
bool notifyUI = false;
|
||||
@ -622,13 +619,13 @@ void CConnman::SweepBanned()
|
||||
}
|
||||
}
|
||||
|
||||
bool CConnman::BannedSetIsDirty()
|
||||
bool BanMan::BannedSetIsDirty()
|
||||
{
|
||||
LOCK(cs_setBanned);
|
||||
return setBannedIsDirty;
|
||||
}
|
||||
|
||||
void CConnman::SetBannedSetDirty(bool dirty)
|
||||
void BanMan::SetBannedSetDirty(bool dirty)
|
||||
{
|
||||
LOCK(cs_setBanned); //reuse setBanned lock for the isDirty flag
|
||||
setBannedIsDirty = dirty;
|
||||
@ -1103,7 +1100,7 @@ void CConnman::AcceptConnection(const ListenSocket& hListenSocket) {
|
||||
// on all platforms. Set it again here just to be sure.
|
||||
SetSocketNoDelay(hSocket);
|
||||
|
||||
if (IsBanned(addr) && !whitelisted)
|
||||
if (m_banman && m_banman->IsBanned(addr) && !whitelisted)
|
||||
{
|
||||
LogPrint(BCLog::NET, "connection from %s dropped (banned)\n", addr.ToString());
|
||||
CloseSocket(hSocket);
|
||||
@ -2075,7 +2072,7 @@ void CConnman::OpenNetworkConnection(const CAddress& addrConnect, bool fCountFai
|
||||
}
|
||||
if (!pszDest) {
|
||||
if (IsLocal(addrConnect) ||
|
||||
FindNode(static_cast<CNetAddr>(addrConnect)) || IsBanned(addrConnect) ||
|
||||
FindNode(static_cast<CNetAddr>(addrConnect)) || (m_banman && m_banman->IsBanned(addrConnect)) ||
|
||||
FindNode(addrConnect.ToStringIPPort()))
|
||||
return;
|
||||
} else if (FindNode(std::string(pszDest)))
|
||||
@ -2376,24 +2373,6 @@ bool CConnman::Start(CScheduler& scheduler, const Options& connOptions)
|
||||
DumpAddresses();
|
||||
}
|
||||
}
|
||||
if (clientInterface)
|
||||
clientInterface->InitMessage(_("Loading banlist..."));
|
||||
// Load addresses from banlist.dat
|
||||
nStart = GetTimeMillis();
|
||||
CBanDB bandb;
|
||||
banmap_t banmap;
|
||||
if (bandb.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();
|
||||
}
|
||||
|
||||
uiInterface.InitMessage(_("Starting network threads..."));
|
||||
|
||||
@ -2448,11 +2427,38 @@ bool CConnman::Start(CScheduler& scheduler, const Options& connOptions)
|
||||
|
||||
// Dump network addresses
|
||||
scheduler.scheduleEvery(std::bind(&CConnman::DumpAddresses, this), DUMP_PEERS_INTERVAL * 1000);
|
||||
scheduler.scheduleEvery(std::bind(&CConnman::DumpBanlist, this), DUMP_BANS_INTERVAL * 1000);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
BanMan::BanMan(CClientUIInterface* client_interface) : clientInterface(client_interface)
|
||||
{
|
||||
if (clientInterface) clientInterface->InitMessage(_("Loading banlist..."));
|
||||
// Load addresses from banlist.dat
|
||||
|
||||
int64_t nStart = GetTimeMillis();
|
||||
setBannedIsDirty = false;
|
||||
CBanDB bandb;
|
||||
banmap_t banmap;
|
||||
if (bandb.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:
|
||||
@ -2508,7 +2514,6 @@ void CConnman::Stop()
|
||||
if (fAddressesInitialized)
|
||||
{
|
||||
DumpAddresses();
|
||||
DumpBanlist();
|
||||
fAddressesInitialized = false;
|
||||
}
|
||||
|
||||
|
85
src/net.h
85
src/net.h
@ -86,7 +86,7 @@ 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 const unsigned int DEFAULT_MISBEHAVING_BANTIME = 60 * 60 * 24; // Default 24-hour ban
|
||||
static constexpr unsigned int DEFAULT_MISBEHAVING_BANTIME = 60 * 60 * 24; // Default 24-hour ban
|
||||
|
||||
typedef int64_t NodeId;
|
||||
|
||||
@ -114,6 +114,50 @@ struct CSerializedNetMsg
|
||||
std::string command;
|
||||
};
|
||||
|
||||
|
||||
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(CClientUIInterface* client_interface);
|
||||
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;
|
||||
};
|
||||
|
||||
class NetEventsInterface;
|
||||
class CConnman
|
||||
{
|
||||
@ -136,6 +180,7 @@ public:
|
||||
int nBestHeight = 0;
|
||||
CClientUIInterface* uiInterface = nullptr;
|
||||
NetEventsInterface* m_msgproc = nullptr;
|
||||
BanMan* m_banman = nullptr;
|
||||
unsigned int nSendBufferMaxSize = 0;
|
||||
unsigned int nReceiveFloodSize = 0;
|
||||
uint64_t nMaxOutboundTimeframe = 0;
|
||||
@ -158,6 +203,7 @@ public:
|
||||
nMaxFeeler = connOptions.nMaxFeeler;
|
||||
nBestHeight = connOptions.nBestHeight;
|
||||
clientInterface = connOptions.uiInterface;
|
||||
m_banman = connOptions.m_banman;
|
||||
m_msgproc = connOptions.m_msgproc;
|
||||
nSendBufferMaxSize = connOptions.nSendBufferMaxSize;
|
||||
nReceiveFloodSize = connOptions.nReceiveFloodSize;
|
||||
@ -238,30 +284,6 @@ public:
|
||||
void AddNewAddresses(const std::vector<CAddress>& vAddr, const CAddress& addrFrom, int64_t nTimePenalty = 0);
|
||||
std::vector<CAddress> GetAddresses();
|
||||
|
||||
// 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.
|
||||
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 SetBanned(const banmap_t &banmap);
|
||||
|
||||
// This allows temporarily exceeding nMaxOutbound, with the goal of finding
|
||||
// a peer that is better than all our current peers.
|
||||
void SetTryNewOutboundPeer(bool flag);
|
||||
@ -370,15 +392,7 @@ private:
|
||||
NodeId GetNewNodeId();
|
||||
|
||||
size_t SocketSendData(CNode *pnode) const;
|
||||
//!check is the banlist has unwritten changes
|
||||
bool BannedSetIsDirty();
|
||||
//!set the "dirty" flag for the banlist
|
||||
void SetBannedSetDirty(bool dirty=true);
|
||||
//!clean unused entries (if bantime has expired)
|
||||
void SweepBanned();
|
||||
void DumpAddresses();
|
||||
void DumpData();
|
||||
void DumpBanlist();
|
||||
|
||||
// Network stats
|
||||
void RecordBytesRecv(uint64_t bytes);
|
||||
@ -411,9 +425,6 @@ private:
|
||||
|
||||
std::vector<ListenSocket> vhListenSocket;
|
||||
std::atomic<bool> fNetworkActive{true};
|
||||
banmap_t setBanned GUARDED_BY(cs_setBanned);
|
||||
CCriticalSection cs_setBanned;
|
||||
bool setBannedIsDirty GUARDED_BY(cs_setBanned){false};
|
||||
bool fAddressesInitialized{false};
|
||||
CAddrMan addrman;
|
||||
std::deque<std::string> vOneShots GUARDED_BY(cs_vOneShots);
|
||||
@ -439,6 +450,7 @@ private:
|
||||
std::atomic<int> nBestHeight;
|
||||
CClientUIInterface* clientInterface;
|
||||
NetEventsInterface* m_msgproc;
|
||||
BanMan* m_banman;
|
||||
|
||||
/** SipHasher seeds for deterministic randomness */
|
||||
const uint64_t nSeed0, nSeed1;
|
||||
@ -468,6 +480,7 @@ private:
|
||||
friend struct CConnmanTest;
|
||||
};
|
||||
extern std::unique_ptr<CConnman> g_connman;
|
||||
extern std::unique_ptr<BanMan> g_banman;
|
||||
void Discover();
|
||||
void StartMapPort();
|
||||
void InterruptMapPort();
|
||||
|
@ -841,9 +841,8 @@ static bool BlockRequestAllowed(const CBlockIndex* pindex, const Consensus::Para
|
||||
(GetBlockProofEquivalentTime(*pindexBestHeader, *pindex, *pindexBestHeader, consensusParams) < STALE_RELAY_AGE_LIMIT);
|
||||
}
|
||||
|
||||
PeerLogicValidation::PeerLogicValidation(CConnman* connmanIn, CScheduler &scheduler, bool enable_bip61)
|
||||
: connman(connmanIn), m_stale_tip_check_time(0), m_enable_bip61(enable_bip61) {
|
||||
|
||||
PeerLogicValidation::PeerLogicValidation(CConnman* connmanIn, BanMan* banman, CScheduler &scheduler, bool enable_bip61)
|
||||
: connman(connmanIn), m_banman(banman), m_stale_tip_check_time(0), m_enable_bip61(enable_bip61) {
|
||||
// Initialize global variables that cannot be constructed at startup.
|
||||
recentRejects.reset(new CRollingBloomFilter(120000, 0.000001));
|
||||
|
||||
@ -2943,7 +2942,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool SendRejectsAndCheckIfBanned(CNode* pnode, CConnman* connman, bool enable_bip61) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
|
||||
bool PeerLogicValidation::SendRejectsAndCheckIfBanned(CNode* pnode, bool enable_bip61) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
|
||||
{
|
||||
AssertLockHeld(cs_main);
|
||||
CNodeState &state = *State(pnode->GetId());
|
||||
@ -2967,7 +2966,9 @@ static bool SendRejectsAndCheckIfBanned(CNode* pnode, CConnman* connman, bool en
|
||||
pnode->fDisconnect = true;
|
||||
} else {
|
||||
// Disconnect and ban all nodes sharing the address
|
||||
connman->Ban(pnode->addr, BanReasonNodeMisbehaving);
|
||||
if (m_banman) {
|
||||
m_banman->Ban(pnode->addr, BanReasonNodeMisbehaving);
|
||||
}
|
||||
connman->DisconnectNode(pnode->addr);
|
||||
}
|
||||
return true;
|
||||
@ -3092,7 +3093,7 @@ bool PeerLogicValidation::ProcessMessages(CNode* pfrom, std::atomic<bool>& inter
|
||||
}
|
||||
|
||||
LOCK(cs_main);
|
||||
SendRejectsAndCheckIfBanned(pfrom, connman, m_enable_bip61);
|
||||
SendRejectsAndCheckIfBanned(pfrom, m_enable_bip61);
|
||||
|
||||
return fMoreWork;
|
||||
}
|
||||
@ -3293,8 +3294,7 @@ bool PeerLogicValidation::SendMessages(CNode* pto)
|
||||
if (!lockMain)
|
||||
return true;
|
||||
|
||||
if (SendRejectsAndCheckIfBanned(pto, connman, m_enable_bip61))
|
||||
return true;
|
||||
if (SendRejectsAndCheckIfBanned(pto, m_enable_bip61)) return true;
|
||||
CNodeState &state = *State(pto->GetId());
|
||||
|
||||
// Address refresh broadcast
|
||||
|
@ -23,9 +23,11 @@ static constexpr bool DEFAULT_ENABLE_BIP61{false};
|
||||
class PeerLogicValidation final : public CValidationInterface, public NetEventsInterface {
|
||||
private:
|
||||
CConnman* const connman;
|
||||
BanMan* const m_banman;
|
||||
|
||||
bool SendRejectsAndCheckIfBanned(CNode* pnode, bool enable_bip61) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
||||
public:
|
||||
explicit PeerLogicValidation(CConnman* connman, CScheduler &scheduler, bool enable_bip61);
|
||||
PeerLogicValidation(CConnman* connman, BanMan* banman, CScheduler &scheduler, bool enable_bip61);
|
||||
|
||||
/**
|
||||
* Overridden from CValidationInterface.
|
||||
|
@ -531,8 +531,9 @@ static UniValue setban(const JSONRPCRequest& request)
|
||||
+ HelpExampleCli("setban", "\"192.168.0.0/24\" \"add\"")
|
||||
+ HelpExampleRpc("setban", "\"192.168.0.6\", \"add\", 86400")
|
||||
);
|
||||
if(!g_connman)
|
||||
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
|
||||
if (!g_banman) {
|
||||
throw JSONRPCError(RPC_DATABASE_ERROR, "Error: Ban database not loaded");
|
||||
}
|
||||
|
||||
CSubNet subNet;
|
||||
CNetAddr netAddr;
|
||||
@ -554,8 +555,9 @@ static UniValue setban(const JSONRPCRequest& request)
|
||||
|
||||
if (strCommand == "add")
|
||||
{
|
||||
if (isSubnet ? g_connman->IsBanned(subNet) : g_connman->IsBanned(netAddr))
|
||||
if (isSubnet ? g_banman->IsBanned(subNet) : g_banman->IsBanned(netAddr)) {
|
||||
throw JSONRPCError(RPC_CLIENT_NODE_ALREADY_ADDED, "Error: IP/Subnet already banned");
|
||||
}
|
||||
|
||||
int64_t banTime = 0; //use standard bantime if not specified
|
||||
if (!request.params[2].isNull())
|
||||
@ -566,17 +568,22 @@ static UniValue setban(const JSONRPCRequest& request)
|
||||
absolute = true;
|
||||
|
||||
if (isSubnet) {
|
||||
g_connman->Ban(subNet, BanReasonManuallyAdded, banTime, absolute);
|
||||
g_connman->DisconnectNode(subNet);
|
||||
g_banman->Ban(subNet, BanReasonManuallyAdded, banTime, absolute);
|
||||
if (g_connman) {
|
||||
g_connman->DisconnectNode(subNet);
|
||||
}
|
||||
} else {
|
||||
g_connman->Ban(netAddr, BanReasonManuallyAdded, banTime, absolute);
|
||||
g_connman->DisconnectNode(netAddr);
|
||||
g_banman->Ban(netAddr, BanReasonManuallyAdded, banTime, absolute);
|
||||
if (g_connman) {
|
||||
g_connman->DisconnectNode(netAddr);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(strCommand == "remove")
|
||||
{
|
||||
if (!( isSubnet ? g_connman->Unban(subNet) : g_connman->Unban(netAddr) ))
|
||||
if (!( isSubnet ? g_banman->Unban(subNet) : g_banman->Unban(netAddr) )) {
|
||||
throw JSONRPCError(RPC_CLIENT_INVALID_IP_OR_SUBNET, "Error: Unban failed. Requested address/subnet was not previously banned.");
|
||||
}
|
||||
}
|
||||
return NullUniValue;
|
||||
}
|
||||
@ -593,11 +600,12 @@ static UniValue listbanned(const JSONRPCRequest& request)
|
||||
+ HelpExampleRpc("listbanned", "")
|
||||
);
|
||||
|
||||
if(!g_connman)
|
||||
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
|
||||
if(!g_banman) {
|
||||
throw JSONRPCError(RPC_DATABASE_ERROR, "Error: Ban database not loaded");
|
||||
}
|
||||
|
||||
banmap_t banMap;
|
||||
g_connman->GetBanned(banMap);
|
||||
g_banman->GetBanned(banMap);
|
||||
|
||||
UniValue bannedAddresses(UniValue::VARR);
|
||||
for (const auto& entry : banMap)
|
||||
@ -626,10 +634,11 @@ static UniValue clearbanned(const JSONRPCRequest& request)
|
||||
+ HelpExampleCli("clearbanned", "")
|
||||
+ HelpExampleRpc("clearbanned", "")
|
||||
);
|
||||
if(!g_connman)
|
||||
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
|
||||
if (!g_banman) {
|
||||
throw JSONRPCError(RPC_DATABASE_ERROR, "Error: Ban database not loaded");
|
||||
}
|
||||
|
||||
g_connman->ClearBanned();
|
||||
g_banman->ClearBanned();
|
||||
|
||||
return NullUniValue;
|
||||
}
|
||||
|
@ -75,7 +75,7 @@ BOOST_FIXTURE_TEST_SUITE(denialofservice_tests, TestingSetup)
|
||||
BOOST_AUTO_TEST_CASE(outbound_slow_chain_eviction)
|
||||
{
|
||||
auto connman = MakeUnique<CConnman>(0x1337, 0x1337);
|
||||
auto peerLogic = MakeUnique<PeerLogicValidation>(connman.get(), scheduler, false);
|
||||
auto peerLogic = MakeUnique<PeerLogicValidation>(connman.get(), nullptr, scheduler, false);
|
||||
|
||||
// Mock an outbound peer
|
||||
CAddress addr1(ip(0xa0b0c001), NODE_NONE);
|
||||
@ -145,7 +145,7 @@ static void AddRandomOutboundPeer(std::vector<CNode *> &vNodes, PeerLogicValidat
|
||||
BOOST_AUTO_TEST_CASE(stale_tip_peer_management)
|
||||
{
|
||||
auto connman = MakeUnique<CConnmanTest>(0x1337, 0x1337);
|
||||
auto peerLogic = MakeUnique<PeerLogicValidation>(connman.get(), scheduler, false);
|
||||
auto peerLogic = MakeUnique<PeerLogicValidation>(connman.get(), nullptr, scheduler, false);
|
||||
|
||||
const Consensus::Params& consensusParams = Params().GetConsensus();
|
||||
constexpr int nMaxOutbound = 8;
|
||||
@ -216,10 +216,11 @@ BOOST_AUTO_TEST_CASE(stale_tip_peer_management)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(DoS_banning)
|
||||
{
|
||||
auto banman = MakeUnique<BanMan>(nullptr);
|
||||
auto connman = MakeUnique<CConnman>(0x1337, 0x1337);
|
||||
auto peerLogic = MakeUnique<PeerLogicValidation>(connman.get(), scheduler, false);
|
||||
auto peerLogic = MakeUnique<PeerLogicValidation>(connman.get(), banman.get(), scheduler, false);
|
||||
|
||||
connman->ClearBanned();
|
||||
banman->ClearBanned();
|
||||
CAddress addr1(ip(0xa0b0c001), NODE_NONE);
|
||||
CNode dummyNode1(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr1, 0, 0, CAddress(), "", true);
|
||||
dummyNode1.SetSendVersion(PROTOCOL_VERSION);
|
||||
@ -234,8 +235,8 @@ BOOST_AUTO_TEST_CASE(DoS_banning)
|
||||
LOCK2(cs_main, dummyNode1.cs_sendProcessing);
|
||||
BOOST_CHECK(peerLogic->SendMessages(&dummyNode1));
|
||||
}
|
||||
BOOST_CHECK(connman->IsBanned(addr1));
|
||||
BOOST_CHECK(!connman->IsBanned(ip(0xa0b0c001|0x0000ff00))); // Different IP, not banned
|
||||
BOOST_CHECK(banman->IsBanned(addr1));
|
||||
BOOST_CHECK(!banman->IsBanned(ip(0xa0b0c001|0x0000ff00))); // Different IP, not banned
|
||||
|
||||
CAddress addr2(ip(0xa0b0c002), NODE_NONE);
|
||||
CNode dummyNode2(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr2, 1, 1, CAddress(), "", true);
|
||||
@ -251,8 +252,8 @@ BOOST_AUTO_TEST_CASE(DoS_banning)
|
||||
LOCK2(cs_main, dummyNode2.cs_sendProcessing);
|
||||
BOOST_CHECK(peerLogic->SendMessages(&dummyNode2));
|
||||
}
|
||||
BOOST_CHECK(!connman->IsBanned(addr2)); // 2 not banned yet...
|
||||
BOOST_CHECK(connman->IsBanned(addr1)); // ... but 1 still should be
|
||||
BOOST_CHECK(!banman->IsBanned(addr2)); // 2 not banned yet...
|
||||
BOOST_CHECK(banman->IsBanned(addr1)); // ... but 1 still should be
|
||||
{
|
||||
LOCK(cs_main);
|
||||
Misbehaving(dummyNode2.GetId(), 50);
|
||||
@ -261,7 +262,7 @@ BOOST_AUTO_TEST_CASE(DoS_banning)
|
||||
LOCK2(cs_main, dummyNode2.cs_sendProcessing);
|
||||
BOOST_CHECK(peerLogic->SendMessages(&dummyNode2));
|
||||
}
|
||||
BOOST_CHECK(connman->IsBanned(addr2));
|
||||
BOOST_CHECK(banman->IsBanned(addr2));
|
||||
|
||||
bool dummy;
|
||||
peerLogic->FinalizeNode(dummyNode1.GetId(), dummy);
|
||||
@ -270,10 +271,11 @@ BOOST_AUTO_TEST_CASE(DoS_banning)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(DoS_banscore)
|
||||
{
|
||||
auto banman = MakeUnique<BanMan>(nullptr);
|
||||
auto connman = MakeUnique<CConnman>(0x1337, 0x1337);
|
||||
auto peerLogic = MakeUnique<PeerLogicValidation>(connman.get(), scheduler, false);
|
||||
auto peerLogic = MakeUnique<PeerLogicValidation>(connman.get(), banman.get(), scheduler, false);
|
||||
|
||||
connman->ClearBanned();
|
||||
banman->ClearBanned();
|
||||
gArgs.ForceSetArg("-banscore", "111"); // because 11 is my favorite number
|
||||
CAddress addr1(ip(0xa0b0c001), NODE_NONE);
|
||||
CNode dummyNode1(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr1, 3, 1, CAddress(), "", true);
|
||||
@ -289,7 +291,7 @@ BOOST_AUTO_TEST_CASE(DoS_banscore)
|
||||
LOCK2(cs_main, dummyNode1.cs_sendProcessing);
|
||||
BOOST_CHECK(peerLogic->SendMessages(&dummyNode1));
|
||||
}
|
||||
BOOST_CHECK(!connman->IsBanned(addr1));
|
||||
BOOST_CHECK(!banman->IsBanned(addr1));
|
||||
{
|
||||
LOCK(cs_main);
|
||||
Misbehaving(dummyNode1.GetId(), 10);
|
||||
@ -298,7 +300,7 @@ BOOST_AUTO_TEST_CASE(DoS_banscore)
|
||||
LOCK2(cs_main, dummyNode1.cs_sendProcessing);
|
||||
BOOST_CHECK(peerLogic->SendMessages(&dummyNode1));
|
||||
}
|
||||
BOOST_CHECK(!connman->IsBanned(addr1));
|
||||
BOOST_CHECK(!banman->IsBanned(addr1));
|
||||
{
|
||||
LOCK(cs_main);
|
||||
Misbehaving(dummyNode1.GetId(), 1);
|
||||
@ -307,7 +309,7 @@ BOOST_AUTO_TEST_CASE(DoS_banscore)
|
||||
LOCK2(cs_main, dummyNode1.cs_sendProcessing);
|
||||
BOOST_CHECK(peerLogic->SendMessages(&dummyNode1));
|
||||
}
|
||||
BOOST_CHECK(connman->IsBanned(addr1));
|
||||
BOOST_CHECK(banman->IsBanned(addr1));
|
||||
gArgs.ForceSetArg("-banscore", std::to_string(DEFAULT_BANSCORE_THRESHOLD));
|
||||
|
||||
bool dummy;
|
||||
@ -316,10 +318,11 @@ BOOST_AUTO_TEST_CASE(DoS_banscore)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(DoS_bantime)
|
||||
{
|
||||
auto banman = MakeUnique<BanMan>(nullptr);
|
||||
auto connman = MakeUnique<CConnman>(0x1337, 0x1337);
|
||||
auto peerLogic = MakeUnique<PeerLogicValidation>(connman.get(), scheduler, false);
|
||||
auto peerLogic = MakeUnique<PeerLogicValidation>(connman.get(), banman.get(), scheduler, false);
|
||||
|
||||
connman->ClearBanned();
|
||||
banman->ClearBanned();
|
||||
int64_t nStartTime = GetTime();
|
||||
SetMockTime(nStartTime); // Overrides future calls to GetTime()
|
||||
|
||||
@ -338,13 +341,13 @@ BOOST_AUTO_TEST_CASE(DoS_bantime)
|
||||
LOCK2(cs_main, dummyNode.cs_sendProcessing);
|
||||
BOOST_CHECK(peerLogic->SendMessages(&dummyNode));
|
||||
}
|
||||
BOOST_CHECK(connman->IsBanned(addr));
|
||||
BOOST_CHECK(banman->IsBanned(addr));
|
||||
|
||||
SetMockTime(nStartTime+60*60);
|
||||
BOOST_CHECK(connman->IsBanned(addr));
|
||||
BOOST_CHECK(banman->IsBanned(addr));
|
||||
|
||||
SetMockTime(nStartTime+60*60*24+1);
|
||||
BOOST_CHECK(!connman->IsBanned(addr));
|
||||
BOOST_CHECK(!banman->IsBanned(addr));
|
||||
|
||||
bool dummy;
|
||||
peerLogic->FinalizeNode(dummyNode.GetId(), dummy);
|
||||
|
@ -93,6 +93,8 @@ TestingSetup::TestingSetup(const std::string& chainName) : BasicTestingSetup(cha
|
||||
nScriptCheckThreads = 3;
|
||||
for (int i=0; i < nScriptCheckThreads-1; i++)
|
||||
threadGroup.create_thread(&ThreadScriptCheck);
|
||||
|
||||
g_banman = MakeUnique<BanMan>(nullptr);
|
||||
g_connman = MakeUnique<CConnman>(0x1337, 0x1337); // Deterministic randomness for tests.
|
||||
}
|
||||
|
||||
@ -103,6 +105,7 @@ TestingSetup::~TestingSetup()
|
||||
GetMainSignals().FlushBackgroundCallbacks();
|
||||
GetMainSignals().UnregisterBackgroundSignalScheduler();
|
||||
g_connman.reset();
|
||||
g_banman.reset();
|
||||
UnloadBlockIndex();
|
||||
pcoinsTip.reset();
|
||||
pcoinsdbview.reset();
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
std::unique_ptr<CConnman> g_connman;
|
||||
std::unique_ptr<BanMan> g_banman;
|
||||
|
||||
[[noreturn]] void Shutdown(void* parg)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user