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