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