LCOV - code coverage report
Current view: top level - src - banman.cpp (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 131 136 96.3 %
Date: 2020-09-26 01:30:44 Functions: 19 19 100.0 %

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

Generated by: LCOV version 1.15