mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-02-04 10:07:27 -05:00
be55f545d5
This is an extraction of ArgsManager related functions from util/system into their own common file. Config file related functions are moved to common/config.cpp. The background of this commit is an ongoing effort to decouple the libbitcoinkernel library from the ArgsManager. The ArgsManager belongs into the common library, since the kernel library should not depend on it. See doc/design/libraries.md for more information on this rationale.
217 lines
5.5 KiB
C++
217 lines
5.5 KiB
C++
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
|
// Copyright (c) 2009-2022 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 <logging.h>
|
|
#include <netaddress.h>
|
|
#include <node/interface_ui.h>
|
|
#include <sync.h>
|
|
#include <util/system.h>
|
|
#include <util/time.h>
|
|
#include <util/translation.h>
|
|
|
|
|
|
BanMan::BanMan(fs::path ban_file, CClientUIInterface* client_interface, int64_t default_ban_time)
|
|
: m_client_interface(client_interface), m_ban_db(std::move(ban_file)), m_default_ban_time(default_ban_time)
|
|
{
|
|
LoadBanlist();
|
|
DumpBanlist();
|
|
}
|
|
|
|
BanMan::~BanMan()
|
|
{
|
|
DumpBanlist();
|
|
}
|
|
|
|
void BanMan::LoadBanlist()
|
|
{
|
|
LOCK(m_cs_banned);
|
|
|
|
if (m_client_interface) m_client_interface->InitMessage(_("Loading banlist…").translated);
|
|
|
|
const auto start{SteadyClock::now()};
|
|
if (m_ban_db.Read(m_banned)) {
|
|
SweepBanned(); // sweep out unused entries
|
|
|
|
LogPrint(BCLog::NET, "Loaded %d banned node addresses/subnets %dms\n", m_banned.size(),
|
|
Ticks<std::chrono::milliseconds>(SteadyClock::now() - start));
|
|
} else {
|
|
LogPrintf("Recreating the banlist database\n");
|
|
m_banned = {};
|
|
m_is_dirty = true;
|
|
}
|
|
}
|
|
|
|
void BanMan::DumpBanlist()
|
|
{
|
|
static Mutex dump_mutex;
|
|
LOCK(dump_mutex);
|
|
|
|
banmap_t banmap;
|
|
{
|
|
LOCK(m_cs_banned);
|
|
SweepBanned();
|
|
if (!BannedSetIsDirty()) return;
|
|
banmap = m_banned;
|
|
SetBannedSetDirty(false);
|
|
}
|
|
|
|
const auto start{SteadyClock::now()};
|
|
if (!m_ban_db.Write(banmap)) {
|
|
SetBannedSetDirty(true);
|
|
}
|
|
|
|
LogPrint(BCLog::NET, "Flushed %d banned node addresses/subnets to disk %dms\n", banmap.size(),
|
|
Ticks<std::chrono::milliseconds>(SteadyClock::now() - start));
|
|
}
|
|
|
|
void BanMan::ClearBanned()
|
|
{
|
|
{
|
|
LOCK(m_cs_banned);
|
|
m_banned.clear();
|
|
m_is_dirty = true;
|
|
}
|
|
DumpBanlist(); //store banlist to disk
|
|
if (m_client_interface) m_client_interface->BannedListChanged();
|
|
}
|
|
|
|
bool BanMan::IsDiscouraged(const CNetAddr& net_addr)
|
|
{
|
|
LOCK(m_cs_banned);
|
|
return m_discouraged.contains(net_addr.GetAddrBytes());
|
|
}
|
|
|
|
bool BanMan::IsBanned(const CNetAddr& net_addr)
|
|
{
|
|
auto current_time = GetTime();
|
|
LOCK(m_cs_banned);
|
|
for (const auto& it : m_banned) {
|
|
CSubNet sub_net = it.first;
|
|
CBanEntry ban_entry = it.second;
|
|
|
|
if (current_time < ban_entry.nBanUntil && sub_net.Match(net_addr)) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool BanMan::IsBanned(const CSubNet& sub_net)
|
|
{
|
|
auto current_time = GetTime();
|
|
LOCK(m_cs_banned);
|
|
banmap_t::iterator i = m_banned.find(sub_net);
|
|
if (i != m_banned.end()) {
|
|
CBanEntry ban_entry = (*i).second;
|
|
if (current_time < ban_entry.nBanUntil) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void BanMan::Ban(const CNetAddr& net_addr, int64_t ban_time_offset, bool since_unix_epoch)
|
|
{
|
|
CSubNet sub_net(net_addr);
|
|
Ban(sub_net, ban_time_offset, since_unix_epoch);
|
|
}
|
|
|
|
void BanMan::Discourage(const CNetAddr& net_addr)
|
|
{
|
|
LOCK(m_cs_banned);
|
|
m_discouraged.insert(net_addr.GetAddrBytes());
|
|
}
|
|
|
|
void BanMan::Ban(const CSubNet& sub_net, int64_t ban_time_offset, bool since_unix_epoch)
|
|
{
|
|
CBanEntry ban_entry(GetTime());
|
|
|
|
int64_t normalized_ban_time_offset = ban_time_offset;
|
|
bool normalized_since_unix_epoch = since_unix_epoch;
|
|
if (ban_time_offset <= 0) {
|
|
normalized_ban_time_offset = m_default_ban_time;
|
|
normalized_since_unix_epoch = false;
|
|
}
|
|
ban_entry.nBanUntil = (normalized_since_unix_epoch ? 0 : GetTime()) + normalized_ban_time_offset;
|
|
|
|
{
|
|
LOCK(m_cs_banned);
|
|
if (m_banned[sub_net].nBanUntil < ban_entry.nBanUntil) {
|
|
m_banned[sub_net] = ban_entry;
|
|
m_is_dirty = true;
|
|
} else
|
|
return;
|
|
}
|
|
if (m_client_interface) m_client_interface->BannedListChanged();
|
|
|
|
//store banlist to disk immediately
|
|
DumpBanlist();
|
|
}
|
|
|
|
bool BanMan::Unban(const CNetAddr& net_addr)
|
|
{
|
|
CSubNet sub_net(net_addr);
|
|
return Unban(sub_net);
|
|
}
|
|
|
|
bool BanMan::Unban(const CSubNet& sub_net)
|
|
{
|
|
{
|
|
LOCK(m_cs_banned);
|
|
if (m_banned.erase(sub_net) == 0) return false;
|
|
m_is_dirty = true;
|
|
}
|
|
if (m_client_interface) m_client_interface->BannedListChanged();
|
|
DumpBanlist(); //store banlist to disk immediately
|
|
return true;
|
|
}
|
|
|
|
void BanMan::GetBanned(banmap_t& banmap)
|
|
{
|
|
LOCK(m_cs_banned);
|
|
// Sweep the banlist so expired bans are not returned
|
|
SweepBanned();
|
|
banmap = m_banned; //create a thread safe copy
|
|
}
|
|
|
|
void BanMan::SweepBanned()
|
|
{
|
|
AssertLockHeld(m_cs_banned);
|
|
|
|
int64_t now = GetTime();
|
|
bool notify_ui = false;
|
|
banmap_t::iterator it = m_banned.begin();
|
|
while (it != m_banned.end()) {
|
|
CSubNet sub_net = (*it).first;
|
|
CBanEntry ban_entry = (*it).second;
|
|
if (!sub_net.IsValid() || now > ban_entry.nBanUntil) {
|
|
m_banned.erase(it++);
|
|
m_is_dirty = true;
|
|
notify_ui = true;
|
|
LogPrint(BCLog::NET, "Removed banned node address/subnet: %s\n", sub_net.ToString());
|
|
} else {
|
|
++it;
|
|
}
|
|
}
|
|
|
|
// update UI
|
|
if (notify_ui && m_client_interface) {
|
|
m_client_interface->BannedListChanged();
|
|
}
|
|
}
|
|
|
|
bool BanMan::BannedSetIsDirty()
|
|
{
|
|
LOCK(m_cs_banned);
|
|
return m_is_dirty;
|
|
}
|
|
|
|
void BanMan::SetBannedSetDirty(bool dirty)
|
|
{
|
|
LOCK(m_cs_banned); //reuse m_banned lock for the m_is_dirty flag
|
|
m_is_dirty = dirty;
|
|
}
|