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