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