Bitcoin Core  27.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 
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 (!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  LogPrint(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 
83 bool BanMan::IsDiscouraged(const CNetAddr& net_addr)
84 {
86  return m_discouraged.contains(net_addr.GetAddrBytes());
87 }
88 
89 bool 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 
104 bool 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 
118 void 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 
124 void BanMan::Discourage(const CNetAddr& net_addr)
125 {
127  m_discouraged.insert(net_addr.GetAddrBytes());
128 }
129 
130 void 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 
156 bool BanMan::Unban(const CNetAddr& net_addr)
157 {
158  CSubNet sub_net(net_addr);
159  return Unban(sub_net);
160 }
161 
162 bool 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  LogPrint(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:139
bool Read(banmap_t &banSet)
Read the banlist from disk.
Definition: addrdb.cpp:152
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:112
std::vector< unsigned char > GetAddrBytes() const
Definition: netaddress.cpp:693
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 LogPrint(category,...)
Definition: logging.h:263
#define LogPrintf(...)
Definition: logging.h:244
@ NET
Definition: logging.h:41
std::map< CSubNet, CBanEntry > banmap_t
Definition: net_types.h:41
#define LOCK(cs)
Definition: sync.h:257
int64_t GetTime()
Definition: time.cpp:48
bilingual_str _(const char *psz)
Translation function.
Definition: translation.h:74
AssertLockHeld(pool.cs)