Bitcoin Core 28.99.0
P2P Digital Currency
banman.cpp
Go to the documentation of this file.
1// Copyright (c) 2009-2010 Satoshi Nakamoto
2// Copyright (c) 2009-2022 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 <common/system.h>
9#include <logging.h>
10#include <netaddress.h>
11#include <node/interface_ui.h>
12#include <sync.h>
13#include <util/time.h>
14#include <util/translation.h>
15
16
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{
22}
23
25{
27}
28
30{
32
33 if (m_client_interface) m_client_interface->InitMessage(_("Loading banlist…").translated);
34
35 const auto start{SteadyClock::now()};
36 if (m_ban_db.Read(m_banned)) {
37 SweepBanned(); // sweep out unused entries
38
39 LogDebug(BCLog::NET, "Loaded %d banned node addresses/subnets %dms\n", m_banned.size(),
40 Ticks<std::chrono::milliseconds>(SteadyClock::now() - start));
41 } else {
42 LogPrintf("Recreating the banlist database\n");
43 m_banned = {};
44 m_is_dirty = true;
45 }
46}
47
49{
50 static Mutex dump_mutex;
51 LOCK(dump_mutex);
52
53 banmap_t banmap;
54 {
57 if (!m_is_dirty) return;
58 banmap = m_banned;
59 m_is_dirty = false;
60 }
61
62 const auto start{SteadyClock::now()};
63 if (!m_ban_db.Write(banmap)) {
65 m_is_dirty = true;
66 }
67
68 LogDebug(BCLog::NET, "Flushed %d banned node addresses/subnets to disk %dms\n", banmap.size(),
69 Ticks<std::chrono::milliseconds>(SteadyClock::now() - start));
70}
71
73{
74 {
76 m_banned.clear();
77 m_is_dirty = true;
78 }
79 DumpBanlist(); //store banlist to disk
80 if (m_client_interface) m_client_interface->BannedListChanged();
81}
82
83bool BanMan::IsDiscouraged(const CNetAddr& net_addr)
84{
86 return m_discouraged.contains(net_addr.GetAddrBytes());
87}
88
89bool BanMan::IsBanned(const CNetAddr& net_addr)
90{
91 auto current_time = GetTime();
93 for (const auto& it : m_banned) {
94 CSubNet sub_net = it.first;
95 CBanEntry ban_entry = it.second;
96
97 if (current_time < ban_entry.nBanUntil && sub_net.Match(net_addr)) {
98 return true;
99 }
100 }
101 return false;
102}
103
104bool BanMan::IsBanned(const CSubNet& sub_net)
105{
106 auto current_time = GetTime();
108 banmap_t::iterator i = m_banned.find(sub_net);
109 if (i != m_banned.end()) {
110 CBanEntry ban_entry = (*i).second;
111 if (current_time < ban_entry.nBanUntil) {
112 return true;
113 }
114 }
115 return false;
116}
117
118void BanMan::Ban(const CNetAddr& net_addr, int64_t ban_time_offset, bool since_unix_epoch)
119{
120 CSubNet sub_net(net_addr);
121 Ban(sub_net, ban_time_offset, since_unix_epoch);
122}
123
124void BanMan::Discourage(const CNetAddr& net_addr)
125{
127 m_discouraged.insert(net_addr.GetAddrBytes());
128}
129
130void BanMan::Ban(const CSubNet& sub_net, int64_t ban_time_offset, bool since_unix_epoch)
131{
132 CBanEntry ban_entry(GetTime());
133
134 int64_t normalized_ban_time_offset = ban_time_offset;
135 bool normalized_since_unix_epoch = since_unix_epoch;
136 if (ban_time_offset <= 0) {
137 normalized_ban_time_offset = m_default_ban_time;
138 normalized_since_unix_epoch = false;
139 }
140 ban_entry.nBanUntil = (normalized_since_unix_epoch ? 0 : GetTime()) + normalized_ban_time_offset;
141
142 {
144 if (m_banned[sub_net].nBanUntil < ban_entry.nBanUntil) {
145 m_banned[sub_net] = ban_entry;
146 m_is_dirty = true;
147 } else
148 return;
149 }
150 if (m_client_interface) m_client_interface->BannedListChanged();
151
152 //store banlist to disk immediately
153 DumpBanlist();
154}
155
156bool BanMan::Unban(const CNetAddr& net_addr)
157{
158 CSubNet sub_net(net_addr);
159 return Unban(sub_net);
160}
161
162bool BanMan::Unban(const CSubNet& sub_net)
163{
164 {
166 if (m_banned.erase(sub_net) == 0) return false;
167 m_is_dirty = true;
168 }
169 if (m_client_interface) m_client_interface->BannedListChanged();
170 DumpBanlist(); //store banlist to disk immediately
171 return true;
172}
173
175{
177 // Sweep the banlist so expired bans are not returned
178 SweepBanned();
179 banmap = m_banned; //create a thread safe copy
180}
181
183{
185
186 int64_t now = GetTime();
187 bool notify_ui = false;
188 banmap_t::iterator it = m_banned.begin();
189 while (it != m_banned.end()) {
190 CSubNet sub_net = (*it).first;
191 CBanEntry ban_entry = (*it).second;
192 if (!sub_net.IsValid() || now > ban_entry.nBanUntil) {
193 m_banned.erase(it++);
194 m_is_dirty = true;
195 notify_ui = true;
196 LogDebug(BCLog::NET, "Removed banned node address/subnet: %s\n", sub_net.ToString());
197 } else {
198 ++it;
199 }
200 }
201
202 // update UI
203 if (notify_ui && m_client_interface) {
204 m_client_interface->BannedListChanged();
205 }
206}
void DumpBanlist() EXCLUSIVE_LOCKS_REQUIRED(!m_banned_mutex)
Definition: banman.cpp:48
void Ban(const CNetAddr &net_addr, int64_t ban_time_offset=0, bool since_unix_epoch=false) EXCLUSIVE_LOCKS_REQUIRED(!m_banned_mutex)
Definition: banman.cpp:118
BanMan(fs::path ban_file, CClientUIInterface *client_interface, int64_t default_ban_time)
Definition: banman.cpp:17
void SweepBanned() EXCLUSIVE_LOCKS_REQUIRED(m_banned_mutex)
clean unused entries (if bantime has expired)
Definition: banman.cpp:182
const int64_t m_default_ban_time
Definition: banman.h:92
bool IsBanned(const CNetAddr &net_addr) EXCLUSIVE_LOCKS_REQUIRED(!m_banned_mutex)
Return whether net_addr is banned.
Definition: banman.cpp:89
void GetBanned(banmap_t &banmap) EXCLUSIVE_LOCKS_REQUIRED(!m_banned_mutex)
Definition: banman.cpp:174
Mutex m_banned_mutex
Definition: banman.h:87
void ClearBanned() EXCLUSIVE_LOCKS_REQUIRED(!m_banned_mutex)
Definition: banman.cpp:72
void LoadBanlist() EXCLUSIVE_LOCKS_REQUIRED(!m_banned_mutex)
Definition: banman.cpp:29
CClientUIInterface * m_client_interface
Definition: banman.h:90
CBanDB m_ban_db
Definition: banman.h:91
bool Unban(const CNetAddr &net_addr) EXCLUSIVE_LOCKS_REQUIRED(!m_banned_mutex)
Definition: banman.cpp:156
bool IsDiscouraged(const CNetAddr &net_addr) EXCLUSIVE_LOCKS_REQUIRED(!m_banned_mutex)
Return whether net_addr is discouraged.
Definition: banman.cpp:83
void Discourage(const CNetAddr &net_addr) EXCLUSIVE_LOCKS_REQUIRED(!m_banned_mutex)
Definition: banman.cpp:124
~BanMan()
Definition: banman.cpp:24
bool Write(const banmap_t &banSet)
Definition: addrdb.cpp:137
bool Read(banmap_t &banSet)
Read the banlist from disk.
Definition: addrdb.cpp:150
Definition: net_types.h:15
int64_t nBanUntil
Definition: net_types.h:20
Signals for UI communication.
Definition: interface_ui.h:26
Network address.
Definition: netaddress.h:112
std::vector< unsigned char > GetAddrBytes() const
Definition: netaddress.cpp:696
std::string ToString() const
bool IsValid() const
bool Match(const CNetAddr &addr) const
Path class wrapper to block calls to the fs::path(std::string) implicit constructor and the fs::path:...
Definition: fs.h:33
#define LogDebug(category,...)
Definition: logging.h:280
#define LogPrintf(...)
Definition: logging.h:266
@ NET
Definition: logging.h:43
std::map< CSubNet, CBanEntry > banmap_t
Definition: net_types.h:41
#define LOCK(cs)
Definition: sync.h:257
int64_t GetTime()
DEPRECATED Use either ClockType::now() or Now<TimePointType>() if a cast is needed.
Definition: time.cpp:47
bilingual_str _(ConstevalStringLiteral str)
Translation function.
Definition: translation.h:80
AssertLockHeld(pool.cs)