Branch data Line data Source code
1 : : // Copyright (c) 2009-2010 Satoshi Nakamoto
2 : : // Copyright (c) 2009-present 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 : 5512 : BanMan::BanMan(fs::path ban_file, CClientUIInterface* client_interface, int64_t default_ban_time)
18 [ + - + - ]: 11024 : : m_client_interface(client_interface), m_ban_db(std::move(ban_file)), m_default_ban_time(default_ban_time)
19 : : {
20 [ + - ]: 5512 : LoadBanlist();
21 [ + - ]: 5512 : DumpBanlist();
22 : 5512 : }
23 : :
24 : 5512 : BanMan::~BanMan()
25 : : {
26 : 5512 : DumpBanlist();
27 : 5512 : }
28 : :
29 : 5512 : void BanMan::LoadBanlist()
30 : : {
31 : 5512 : LOCK(m_banned_mutex);
32 : :
33 [ - + - - : 5512 : if (m_client_interface) m_client_interface->InitMessage(_("Loading banlist…"));
- - ]
34 : :
35 : 5512 : const auto start{SteadyClock::now()};
36 [ + - + + ]: 5512 : if (m_ban_db.Read(m_banned)) {
37 [ + - ]: 3114 : SweepBanned(); // sweep out unused entries
38 : :
39 [ + - - + : 3114 : LogDebug(BCLog::NET, "Loaded %d banned node addresses/subnets %dms\n", m_banned.size(),
- - ]
40 : : Ticks<std::chrono::milliseconds>(SteadyClock::now() - start));
41 : : } else {
42 [ + - ]: 2398 : LogInfo("Recreating the banlist database");
43 [ + - ]: 2398 : m_banned = {};
44 : 2398 : m_is_dirty = true;
45 : : }
46 : 5512 : }
47 : :
48 : 60245 : void BanMan::DumpBanlist()
49 : : {
50 [ + + + - ]: 60245 : static Mutex dump_mutex;
51 : 60245 : LOCK(dump_mutex);
52 : :
53 [ + - ]: 60245 : banmap_t banmap;
54 : 60245 : {
55 [ + - ]: 60245 : LOCK(m_banned_mutex);
56 [ + - ]: 60245 : SweepBanned();
57 [ + + + - ]: 60245 : if (!m_is_dirty) return;
58 [ + - ]: 48198 : banmap = m_banned;
59 [ + - ]: 48198 : m_is_dirty = false;
60 : 12047 : }
61 : :
62 : 48198 : const auto start{SteadyClock::now()};
63 [ + - + + ]: 48198 : if (!m_ban_db.Write(banmap)) {
64 [ + - ]: 9862 : LOCK(m_banned_mutex);
65 [ + - ]: 9862 : m_is_dirty = true;
66 : 9862 : }
67 : :
68 [ + - + + : 48198 : LogDebug(BCLog::NET, "Flushed %d banned node addresses/subnets to disk %dms\n", banmap.size(),
+ - ]
69 : : Ticks<std::chrono::milliseconds>(SteadyClock::now() - start));
70 [ + - + - ]: 120490 : }
71 : :
72 : 6335 : void BanMan::ClearBanned()
73 : : {
74 : 6335 : {
75 : 6335 : LOCK(m_banned_mutex);
76 : 6335 : m_banned.clear();
77 [ + - ]: 6335 : m_is_dirty = true;
78 : 6335 : }
79 : 6335 : DumpBanlist(); //store banlist to disk
80 [ - + ]: 6335 : if (m_client_interface) m_client_interface->BannedListChanged();
81 : 6335 : }
82 : :
83 : 8693 : bool BanMan::IsDiscouraged(const CNetAddr& net_addr)
84 : : {
85 : 8693 : LOCK(m_banned_mutex);
86 [ + - + - : 17386 : return m_discouraged.contains(net_addr.GetAddrBytes());
+ - ]
87 : 8693 : }
88 : :
89 : 7805 : bool BanMan::IsBanned(const CNetAddr& net_addr)
90 : : {
91 : 7805 : auto current_time = GetTime();
92 : 7805 : LOCK(m_banned_mutex);
93 [ + + ]: 149236 : for (const auto& it : m_banned) {
94 : 143509 : CSubNet sub_net = it.first;
95 : 143509 : CBanEntry ban_entry = it.second;
96 : :
97 [ + + + - : 143509 : if (current_time < ban_entry.nBanUntil && sub_net.Match(net_addr)) {
+ + ]
98 : 2078 : return true;
99 : : }
100 : 143509 : }
101 : : return false;
102 : 7805 : }
103 : :
104 : 6422 : bool BanMan::IsBanned(const CSubNet& sub_net)
105 : : {
106 : 6422 : auto current_time = GetTime();
107 : 6422 : LOCK(m_banned_mutex);
108 [ + - ]: 6422 : banmap_t::iterator i = m_banned.find(sub_net);
109 [ + + ]: 6422 : if (i != m_banned.end()) {
110 [ + + ]: 2568 : CBanEntry ban_entry = (*i).second;
111 [ + + ]: 2568 : if (current_time < ban_entry.nBanUntil) {
112 : 1598 : return true;
113 : : }
114 : : }
115 : : return false;
116 : 6422 : }
117 : :
118 : 46609 : void BanMan::Ban(const CNetAddr& net_addr, int64_t ban_time_offset, bool since_unix_epoch)
119 : : {
120 : 46609 : CSubNet sub_net(net_addr);
121 [ + - ]: 46609 : Ban(sub_net, ban_time_offset, since_unix_epoch);
122 : 46609 : }
123 : :
124 : 4307 : void BanMan::Discourage(const CNetAddr& net_addr)
125 : : {
126 : 4307 : LOCK(m_banned_mutex);
127 [ + - + - : 12921 : m_discouraged.insert(net_addr.GetAddrBytes());
+ - ]
128 : 4307 : }
129 : :
130 : 54611 : void BanMan::Ban(const CSubNet& sub_net, int64_t ban_time_offset, bool since_unix_epoch)
131 : : {
132 [ + + ]: 54611 : CBanEntry ban_entry(GetTime());
133 : :
134 : 54611 : int64_t normalized_ban_time_offset = ban_time_offset;
135 : 54611 : bool normalized_since_unix_epoch = since_unix_epoch;
136 [ + + ]: 54611 : if (ban_time_offset <= 0) {
137 : 53450 : normalized_ban_time_offset = m_default_ban_time;
138 : 53450 : normalized_since_unix_epoch = false;
139 : : }
140 [ + + ]: 54611 : ban_entry.nBanUntil = (normalized_since_unix_epoch ? 0 : GetTime()) + normalized_ban_time_offset;
141 : :
142 : 54611 : {
143 : 54611 : LOCK(m_banned_mutex);
144 [ + - + + ]: 54611 : if (m_banned[sub_net].nBanUntil < ban_entry.nBanUntil) {
145 [ + - ]: 32172 : m_banned[sub_net] = ban_entry;
146 [ + - ]: 32172 : m_is_dirty = true;
147 : : } else
148 [ + - ]: 22439 : return;
149 : 22439 : }
150 [ - + ]: 32172 : if (m_client_interface) m_client_interface->BannedListChanged();
151 : :
152 : : //store banlist to disk immediately
153 : 32172 : DumpBanlist();
154 : : }
155 : :
156 : 6565 : bool BanMan::Unban(const CNetAddr& net_addr)
157 : : {
158 : 6565 : CSubNet sub_net(net_addr);
159 [ + - ]: 6565 : return Unban(sub_net);
160 : 6565 : }
161 : :
162 : 9753 : bool BanMan::Unban(const CSubNet& sub_net)
163 : : {
164 : 9753 : {
165 : 9753 : LOCK(m_banned_mutex);
166 [ + - + + : 9753 : if (m_banned.erase(sub_net) == 0) return false;
+ - ]
167 [ + - ]: 1502 : m_is_dirty = true;
168 : 8251 : }
169 [ - + ]: 1502 : if (m_client_interface) m_client_interface->BannedListChanged();
170 : 1502 : DumpBanlist(); //store banlist to disk immediately
171 : 1502 : return true;
172 : : }
173 : :
174 : 7072 : void BanMan::GetBanned(banmap_t& banmap)
175 : : {
176 : 7072 : LOCK(m_banned_mutex);
177 : : // Sweep the banlist so expired bans are not returned
178 [ + - ]: 7072 : SweepBanned();
179 [ + - + - ]: 7072 : banmap = m_banned; //create a thread safe copy
180 : 7072 : }
181 : :
182 : 70431 : void BanMan::SweepBanned()
183 : : {
184 : 70431 : AssertLockHeld(m_banned_mutex);
185 : :
186 : 70431 : int64_t now = GetTime();
187 : 70431 : bool notify_ui = false;
188 : 70431 : banmap_t::iterator it = m_banned.begin();
189 [ + + ]: 2004805 : while (it != m_banned.end()) {
190 : 1934374 : CSubNet sub_net = (*it).first;
191 [ + - ]: 1934374 : CBanEntry ban_entry = (*it).second;
192 [ + - + + : 1934374 : if (!sub_net.IsValid() || now > ban_entry.nBanUntil) {
+ + ]
193 : 11168 : m_banned.erase(it++);
194 : 11168 : m_is_dirty = true;
195 : 11168 : notify_ui = true;
196 [ + - - + : 11168 : LogDebug(BCLog::NET, "Removed banned node address/subnet: %s\n", sub_net.ToString());
- - - - ]
197 : : } else {
198 : 1923206 : ++it;
199 : : }
200 : 1934374 : }
201 : :
202 : : // update UI
203 [ + + - + ]: 70431 : if (notify_ui && m_client_interface) {
204 : 0 : m_client_interface->BannedListChanged();
205 : : }
206 : 70431 : }
|