Inside Bitcoin
Opening the selected file…
Opening the selected file…
The code behind the network, with room to understand it.
Release published 2026-10-28 · Snapshot fetched 2026-11-01. Latest stable release at fetch time; development branches and Git history are excluded. Only the selected code window and visible folders load here.
1// Copyright (c) 2009-2010 Satoshi Nakamoto2// Copyright (c) 2009-present The Bitcoin Core developers3// Distributed under the MIT software license, see the accompanying4// file COPYING or http://www.opensource.org/licenses/mit-license.php.6#include <banman.h>8#include <common/system.h>9#include <netaddress.h>10#include <node/interface_ui.h>11#include <sync.h>12#include <util/log.h>13#include <util/time.h>14#include <util/translation.h>17BanMan::BanMan(fs::path ban_file, CClientUIInterface* client_interface, int64_t default_ban_time)18: m_client_interface(client_interface), m_ban_db(std::move(ban_file)), m_default_ban_time(default_ban_time)19{20LoadBanlist();21DumpBanlist();22}24BanMan::~BanMan()25{26DumpBanlist();27}29void BanMan::LoadBanlist()30{31LOCK(m_banned_mutex);33if (m_client_interface) m_client_interface->InitMessage(_("Loading banlist…"));35const auto start{SteadyClock::now()};36if (m_ban_db.Read(m_banned)) {37SweepBanned(); // sweep out unused entries39LogDebug(BCLog::NET, "Loaded %d banned node addresses/subnets %dms", m_banned.size(),40Ticks<std::chrono::milliseconds>(SteadyClock::now() - start));41} else {42LogInfo("Recreating the banlist database");43m_banned = {};44m_is_dirty = true;45}46}48void BanMan::DumpBanlist()49{50static Mutex dump_mutex;51LOCK(dump_mutex);53banmap_t banmap;54{55LOCK(m_banned_mutex);56SweepBanned();57if (!m_is_dirty) return;58banmap = m_banned;59m_is_dirty = false;60}62const auto start{SteadyClock::now()};63if (!m_ban_db.Write(banmap)) {64LOCK(m_banned_mutex);65m_is_dirty = true;66}68LogDebug(BCLog::NET, "Flushed %d banned node addresses/subnets to disk %dms", banmap.size(),69Ticks<std::chrono::milliseconds>(SteadyClock::now() - start));70}72void BanMan::ClearBanned()73{74{75LOCK(m_banned_mutex);76m_banned.clear();77m_is_dirty = true;78}79DumpBanlist(); //store banlist to disk80if (m_client_interface) m_client_interface->BannedListChanged();81}83bool BanMan::IsDiscouraged(const CNetAddr& net_addr)84{85LOCK(m_banned_mutex);86return m_discouraged.contains(net_addr.GetAddrBytes());87}89bool BanMan::IsBanned(const CNetAddr& net_addr)90{91auto current_time = GetTime();92LOCK(m_banned_mutex);93for (const auto& it : m_banned) {94CSubNet sub_net = it.first;95CBanEntry ban_entry = it.second;97if (current_time < ban_entry.nBanUntil && sub_net.Match(net_addr)) {98return true;99}100}101return false;102}104bool BanMan::IsBanned(const CSubNet& sub_net)105{106auto current_time = GetTime();107LOCK(m_banned_mutex);108banmap_t::iterator i = m_banned.find(sub_net);109if (i != m_banned.end()) {110CBanEntry ban_entry = (*i).second;111if (current_time < ban_entry.nBanUntil) {112return true;113}114}115return false;116}118void BanMan::Ban(const CNetAddr& net_addr, int64_t ban_time_offset, bool since_unix_epoch)119{120CSubNet sub_net(net_addr);121Ban(sub_net, ban_time_offset, since_unix_epoch);122}124void BanMan::Discourage(const CNetAddr& net_addr)125{126LOCK(m_banned_mutex);127m_discouraged.insert(net_addr.GetAddrBytes());128}130void BanMan::Ban(const CSubNet& sub_net, int64_t ban_time_offset, bool since_unix_epoch)131{132CBanEntry ban_entry(GetTime());134int64_t normalized_ban_time_offset = ban_time_offset;135bool normalized_since_unix_epoch = since_unix_epoch;136if (ban_time_offset <= 0) {137normalized_ban_time_offset = m_default_ban_time;138normalized_since_unix_epoch = false;139}140ban_entry.nBanUntil = (normalized_since_unix_epoch ? 0 : GetTime()) + normalized_ban_time_offset;142{143LOCK(m_banned_mutex);144if (m_banned[sub_net].nBanUntil < ban_entry.nBanUntil) {145m_banned[sub_net] = ban_entry;146m_is_dirty = true;147} else148return;149}150if (m_client_interface) m_client_interface->BannedListChanged();152//store banlist to disk immediately153DumpBanlist();154}156bool BanMan::Unban(const CNetAddr& net_addr)157{158CSubNet sub_net(net_addr);159return Unban(sub_net);160}162bool BanMan::Unban(const CSubNet& sub_net)163{164{165LOCK(m_banned_mutex);166if (m_banned.erase(sub_net) == 0) return false;167m_is_dirty = true;168}169if (m_client_interface) m_client_interface->BannedListChanged();170DumpBanlist(); //store banlist to disk immediately171return true;172}174void BanMan::GetBanned(banmap_t& banmap)175{176LOCK(m_banned_mutex);177// Sweep the banlist so expired bans are not returned178SweepBanned();179banmap = m_banned; //create a thread safe copy180}182void BanMan::SweepBanned()183{184AssertLockHeld(m_banned_mutex);186int64_t now = GetTime();187bool notify_ui = false;188banmap_t::iterator it = m_banned.begin();189while (it != m_banned.end()) {190CSubNet sub_net = (*it).first;191CBanEntry ban_entry = (*it).second;192if (!sub_net.IsValid() || now > ban_entry.nBanUntil) {193m_banned.erase(it++);194m_is_dirty = true;195notify_ui = true;196LogDebug(BCLog::NET, "Removed banned node address/subnet: %s\n", sub_net.ToString());197} else {198++it;199}200}202// update UI203if (notify_ui && m_client_interface) {204m_client_interface->BannedListChanged();205}206}