Bitcoin Core  26.1.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 
17 BanMan::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 {
20  LoadBanlist();
21  DumpBanlist();
22 }
23 
25 {
26  DumpBanlist();
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  LogPrint(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  {
56  SweepBanned();
57  if (!BannedSetIsDirty()) return;
58  banmap = m_banned;
59  SetBannedSetDirty(false);
60  }
61 
62  const auto start{SteadyClock::now()};
63  if (!m_ban_db.Write(banmap)) {
64  SetBannedSetDirty(true);
65  }
66 
67  LogPrint(BCLog::NET, "Flushed %d banned node addresses/subnets to disk %dms\n", banmap.size(),
68  Ticks<std::chrono::milliseconds>(SteadyClock::now() - start));
69 }
70 
72 {
73  {
75  m_banned.clear();
76  m_is_dirty = true;
77  }
78  DumpBanlist(); //store banlist to disk
79  if (m_client_interface) m_client_interface->BannedListChanged();
80 }
81 
82 bool BanMan::IsDiscouraged(const CNetAddr& net_addr)
83 {
85  return m_discouraged.contains(net_addr.GetAddrBytes());
86 }
87 
88 bool BanMan::IsBanned(const CNetAddr& net_addr)
89 {
90  auto current_time = GetTime();
92  for (const auto& it : m_banned) {
93  CSubNet sub_net = it.first;
94  CBanEntry ban_entry = it.second;
95 
96  if (current_time < ban_entry.nBanUntil && sub_net.Match(net_addr)) {
97  return true;
98  }
99  }
100  return false;
101 }
102 
103 bool BanMan::IsBanned(const CSubNet& sub_net)
104 {
105  auto current_time = GetTime();
106  LOCK(m_cs_banned);
107  banmap_t::iterator i = m_banned.find(sub_net);
108  if (i != m_banned.end()) {
109  CBanEntry ban_entry = (*i).second;
110  if (current_time < ban_entry.nBanUntil) {
111  return true;
112  }
113  }
114  return false;
115 }
116 
117 void BanMan::Ban(const CNetAddr& net_addr, int64_t ban_time_offset, bool since_unix_epoch)
118 {
119  CSubNet sub_net(net_addr);
120  Ban(sub_net, ban_time_offset, since_unix_epoch);
121 }
122 
123 void BanMan::Discourage(const CNetAddr& net_addr)
124 {
125  LOCK(m_cs_banned);
126  m_discouraged.insert(net_addr.GetAddrBytes());
127 }
128 
129 void BanMan::Ban(const CSubNet& sub_net, int64_t ban_time_offset, bool since_unix_epoch)
130 {
131  CBanEntry ban_entry(GetTime());
132 
133  int64_t normalized_ban_time_offset = ban_time_offset;
134  bool normalized_since_unix_epoch = since_unix_epoch;
135  if (ban_time_offset <= 0) {
136  normalized_ban_time_offset = m_default_ban_time;
137  normalized_since_unix_epoch = false;
138  }
139  ban_entry.nBanUntil = (normalized_since_unix_epoch ? 0 : GetTime()) + normalized_ban_time_offset;
140 
141  {
142  LOCK(m_cs_banned);
143  if (m_banned[sub_net].nBanUntil < ban_entry.nBanUntil) {
144  m_banned[sub_net] = ban_entry;
145  m_is_dirty = true;
146  } else
147  return;
148  }
149  if (m_client_interface) m_client_interface->BannedListChanged();
150 
151  //store banlist to disk immediately
152  DumpBanlist();
153 }
154 
155 bool BanMan::Unban(const CNetAddr& net_addr)
156 {
157  CSubNet sub_net(net_addr);
158  return Unban(sub_net);
159 }
160 
161 bool BanMan::Unban(const CSubNet& sub_net)
162 {
163  {
164  LOCK(m_cs_banned);
165  if (m_banned.erase(sub_net) == 0) return false;
166  m_is_dirty = true;
167  }
168  if (m_client_interface) m_client_interface->BannedListChanged();
169  DumpBanlist(); //store banlist to disk immediately
170  return true;
171 }
172 
174 {
175  LOCK(m_cs_banned);
176  // Sweep the banlist so expired bans are not returned
177  SweepBanned();
178  banmap = m_banned; //create a thread safe copy
179 }
180 
182 {
184 
185  int64_t now = GetTime();
186  bool notify_ui = false;
187  banmap_t::iterator it = m_banned.begin();
188  while (it != m_banned.end()) {
189  CSubNet sub_net = (*it).first;
190  CBanEntry ban_entry = (*it).second;
191  if (!sub_net.IsValid() || now > ban_entry.nBanUntil) {
192  m_banned.erase(it++);
193  m_is_dirty = true;
194  notify_ui = true;
195  LogPrint(BCLog::NET, "Removed banned node address/subnet: %s\n", sub_net.ToString());
196  } else {
197  ++it;
198  }
199  }
200 
201  // update UI
202  if (notify_ui && m_client_interface) {
203  m_client_interface->BannedListChanged();
204  }
205 }
206 
208 {
209  LOCK(m_cs_banned);
210  return m_is_dirty;
211 }
212 
214 {
215  LOCK(m_cs_banned); //reuse m_banned lock for the m_is_dirty flag
216  m_is_dirty = dirty;
217 }
void Ban(const CNetAddr &net_addr, int64_t ban_time_offset=0, bool since_unix_epoch=false)
Definition: banman.cpp:117
AssertLockHeld(pool.cs)
void Discourage(const CNetAddr &net_addr)
Definition: banman.cpp:123
#define LogPrint(category,...)
Definition: logging.h:246
CClientUIInterface * m_client_interface
Definition: banman.h:93
void SetBannedSetDirty(bool dirty=true)
set the "dirty" flag for the banlist
Definition: banman.cpp:213
Signals for UI communication.
Definition: interface_ui.h:24
~BanMan()
Definition: banman.cpp:24
void ClearBanned()
Definition: banman.cpp:71
bool IsDiscouraged(const CNetAddr &net_addr)
Return whether net_addr is discouraged.
Definition: banman.cpp:82
#define LOCK(cs)
Definition: sync.h:258
bilingual_str _(const char *psz)
Translation function.
Definition: translation.h:74
bool BannedSetIsDirty()
Definition: banman.cpp:207
void LoadBanlist() EXCLUSIVE_LOCKS_REQUIRED(!m_cs_banned)
Definition: banman.cpp:29
RecursiveMutex m_cs_banned
Definition: banman.h:90
CBanDB m_ban_db
Definition: banman.h:94
bool Write(const banmap_t &banSet)
Definition: addrdb.cpp:131
void DumpBanlist()
Definition: banman.cpp:48
int64_t nBanUntil
Definition: net_types.h:20
void GetBanned(banmap_t &banmap)
Definition: banman.cpp:173
bool Match(const CNetAddr &addr) const
const int64_t m_default_ban_time
Definition: banman.h:95
bool Read(banmap_t &banSet)
Read the banlist from disk.
Definition: addrdb.cpp:144
Network address.
Definition: netaddress.h:115
bool IsValid() const
std::string ToString() const
bool Unban(const CNetAddr &net_addr)
Definition: banman.cpp:155
BanMan(fs::path ban_file, CClientUIInterface *client_interface, int64_t default_ban_time)
Definition: banman.cpp:17
std::map< CSubNet, CBanEntry > banmap_t
Definition: net_types.h:41
bool IsBanned(const CNetAddr &net_addr)
Return whether net_addr is banned.
Definition: banman.cpp:88
void SweepBanned() EXCLUSIVE_LOCKS_REQUIRED(m_cs_banned)
clean unused entries (if bantime has expired)
Definition: banman.cpp:181
Definition: net_types.h:14
#define LogPrintf(...)
Definition: logging.h:237
int64_t GetTime()
DEPRECATED, see GetTime.
Definition: time.cpp:97
Path class wrapper to block calls to the fs::path(std::string) implicit constructor and the fs::path:...
Definition: fs.h:30
std::vector< unsigned char > GetAddrBytes() const
Definition: netaddress.cpp:693