fuzz coverage

Coverage Report

Created: 2025-06-01 19:34

/Users/eugenesiegel/btc/bitcoin/src/banman.cpp
Line
Count
Source (jump to first uncovered line)
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
BanMan::BanMan(fs::path ban_file, CClientUIInterface* client_interface, int64_t default_ban_time)
18
49.9k
    : m_client_interface(client_interface), m_ban_db(std::move(ban_file)), m_default_ban_time(default_ban_time)
19
49.9k
{
20
49.9k
    LoadBanlist();
21
49.9k
    DumpBanlist();
22
49.9k
}
23
24
BanMan::~BanMan()
25
49.9k
{
26
49.9k
    DumpBanlist();
27
49.9k
}
28
29
void BanMan::LoadBanlist()
30
49.9k
{
31
49.9k
    LOCK(m_banned_mutex);
Line
Count
Source
257
49.9k
#define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__)
Line
Count
Source
11
49.9k
#define UNIQUE_NAME(name) PASTE2(name, __COUNTER__)
Line
Count
Source
9
49.9k
#define PASTE2(x, y) PASTE(x, y)
Line
Count
Source
8
49.9k
#define PASTE(x, y) x ## y
32
33
49.9k
    if (m_client_interface) 
m_client_interface->InitMessage(_("Loading banlist…"))0
;
34
35
49.9k
    const auto start{SteadyClock::now()};
36
49.9k
    if (m_ban_db.Read(m_banned)) {
37
0
        SweepBanned(); // sweep out unused entries
38
39
0
        LogDebug(BCLog::NET, "Loaded %d banned node addresses/subnets  %dms\n", m_banned.size(),
Line
Count
Source
280
0
#define LogDebug(category, ...) LogPrintLevel(category, BCLog::Level::Debug, __VA_ARGS__)
Line
Count
Source
273
0
    do {                                                  \
274
0
        if (LogAcceptCategory((category), (level))) {     \
275
0
            LogPrintLevel_(category, level, __VA_ARGS__); \
Line
Count
Source
255
0
#define LogPrintLevel_(category, level, ...) LogPrintFormatInternal(__func__, __FILE__, __LINE__, category, level, __VA_ARGS__)
276
0
        }                                                 \
277
0
    } while (0)
40
0
                 Ticks<std::chrono::milliseconds>(SteadyClock::now() - start));
41
49.9k
    } else {
42
49.9k
        LogPrintf("Recreating the banlist database\n");
Line
Count
Source
266
49.9k
#define LogPrintf(...) LogInfo(__VA_ARGS__)
Line
Count
Source
261
49.9k
#define LogInfo(...) LogPrintLevel_(BCLog::LogFlags::ALL, BCLog::Level::Info, __VA_ARGS__)
Line
Count
Source
255
49.9k
#define LogPrintLevel_(category, level, ...) LogPrintFormatInternal(__func__, __FILE__, __LINE__, category, level, __VA_ARGS__)
43
49.9k
        m_banned = {};
44
49.9k
        m_is_dirty = true;
45
49.9k
    }
46
49.9k
}
47
48
void BanMan::DumpBanlist()
49
99.9k
{
50
99.9k
    static Mutex dump_mutex;
51
99.9k
    LOCK(dump_mutex);
Line
Count
Source
257
99.9k
#define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__)
Line
Count
Source
11
99.9k
#define UNIQUE_NAME(name) PASTE2(name, __COUNTER__)
Line
Count
Source
9
99.9k
#define PASTE2(x, y) PASTE(x, y)
Line
Count
Source
8
99.9k
#define PASTE(x, y) x ## y
52
53
99.9k
    banmap_t banmap;
54
99.9k
    {
55
99.9k
        LOCK(m_banned_mutex);
Line
Count
Source
257
99.9k
#define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__)
Line
Count
Source
11
99.9k
#define UNIQUE_NAME(name) PASTE2(name, __COUNTER__)
Line
Count
Source
9
99.9k
#define PASTE2(x, y) PASTE(x, y)
Line
Count
Source
8
99.9k
#define PASTE(x, y) x ## y
56
99.9k
        SweepBanned();
57
99.9k
        if (!m_is_dirty) 
return49.9k
;
58
49.9k
        banmap = m_banned;
59
49.9k
        m_is_dirty = false;
60
49.9k
    }
61
62
0
    const auto start{SteadyClock::now()};
63
49.9k
    if (!m_ban_db.Write(banmap)) {
64
0
        LOCK(m_banned_mutex);
Line
Count
Source
257
0
#define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__)
Line
Count
Source
11
0
#define UNIQUE_NAME(name) PASTE2(name, __COUNTER__)
Line
Count
Source
9
0
#define PASTE2(x, y) PASTE(x, y)
Line
Count
Source
8
0
#define PASTE(x, y) x ## y
65
0
        m_is_dirty = true;
66
0
    }
67
68
49.9k
    LogDebug(BCLog::NET, "Flushed %d banned node addresses/subnets to disk  %dms\n", banmap.size(),
Line
Count
Source
280
49.9k
#define LogDebug(category, ...) LogPrintLevel(category, BCLog::Level::Debug, __VA_ARGS__)
Line
Count
Source
273
49.9k
    do {                                                  \
274
49.9k
        if (LogAcceptCategory((category), (level))) {     \
275
0
            LogPrintLevel_(category, level, __VA_ARGS__); \
Line
Count
Source
255
0
#define LogPrintLevel_(category, level, ...) LogPrintFormatInternal(__func__, __FILE__, __LINE__, category, level, __VA_ARGS__)
276
0
        }                                                 \
277
49.9k
    } while (0)
69
49.9k
             Ticks<std::chrono::milliseconds>(SteadyClock::now() - start));
70
49.9k
}
71
72
void BanMan::ClearBanned()
73
0
{
74
0
    {
75
0
        LOCK(m_banned_mutex);
Line
Count
Source
257
0
#define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__)
Line
Count
Source
11
0
#define UNIQUE_NAME(name) PASTE2(name, __COUNTER__)
Line
Count
Source
9
0
#define PASTE2(x, y) PASTE(x, y)
Line
Count
Source
8
0
#define PASTE(x, y) x ## y
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
bool BanMan::IsDiscouraged(const CNetAddr& net_addr)
84
0
{
85
0
    LOCK(m_banned_mutex);
Line
Count
Source
257
0
#define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__)
Line
Count
Source
11
0
#define UNIQUE_NAME(name) PASTE2(name, __COUNTER__)
Line
Count
Source
9
0
#define PASTE2(x, y) PASTE(x, y)
Line
Count
Source
8
0
#define PASTE(x, y) x ## y
86
0
    return m_discouraged.contains(net_addr.GetAddrBytes());
87
0
}
88
89
bool BanMan::IsBanned(const CNetAddr& net_addr)
90
0
{
91
0
    auto current_time = GetTime();
92
0
    LOCK(m_banned_mutex);
Line
Count
Source
257
0
#define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__)
Line
Count
Source
11
0
#define UNIQUE_NAME(name) PASTE2(name, __COUNTER__)
Line
Count
Source
9
0
#define PASTE2(x, y) PASTE(x, y)
Line
Count
Source
8
0
#define PASTE(x, y) x ## y
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
0
        }
100
0
    }
101
0
    return false;
102
0
}
103
104
bool BanMan::IsBanned(const CSubNet& sub_net)
105
0
{
106
0
    auto current_time = GetTime();
107
0
    LOCK(m_banned_mutex);
Line
Count
Source
257
0
#define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__)
Line
Count
Source
11
0
#define UNIQUE_NAME(name) PASTE2(name, __COUNTER__)
Line
Count
Source
9
0
#define PASTE2(x, y) PASTE(x, y)
Line
Count
Source
8
0
#define PASTE(x, y) x ## y
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
0
        }
114
0
    }
115
0
    return false;
116
0
}
117
118
void BanMan::Ban(const CNetAddr& net_addr, int64_t ban_time_offset, bool since_unix_epoch)
119
0
{
120
0
    CSubNet sub_net(net_addr);
121
0
    Ban(sub_net, ban_time_offset, since_unix_epoch);
122
0
}
123
124
void BanMan::Discourage(const CNetAddr& net_addr)
125
29.4k
{
126
29.4k
    LOCK(m_banned_mutex);
Line
Count
Source
257
29.4k
#define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__)
Line
Count
Source
11
29.4k
#define UNIQUE_NAME(name) PASTE2(name, __COUNTER__)
Line
Count
Source
9
29.4k
#define PASTE2(x, y) PASTE(x, y)
Line
Count
Source
8
29.4k
#define PASTE(x, y) x ## y
127
29.4k
    m_discouraged.insert(net_addr.GetAddrBytes());
128
29.4k
}
129
130
void BanMan::Ban(const CSubNet& sub_net, int64_t ban_time_offset, bool since_unix_epoch)
131
0
{
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
0
    {
143
0
        LOCK(m_banned_mutex);
Line
Count
Source
257
0
#define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__)
Line
Count
Source
11
0
#define UNIQUE_NAME(name) PASTE2(name, __COUNTER__)
Line
Count
Source
9
0
#define PASTE2(x, y) PASTE(x, y)
Line
Count
Source
8
0
#define PASTE(x, y) x ## y
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
bool BanMan::Unban(const CNetAddr& net_addr)
157
0
{
158
0
    CSubNet sub_net(net_addr);
159
0
    return Unban(sub_net);
160
0
}
161
162
bool BanMan::Unban(const CSubNet& sub_net)
163
0
{
164
0
    {
165
0
        LOCK(m_banned_mutex);
Line
Count
Source
257
0
#define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__)
Line
Count
Source
11
0
#define UNIQUE_NAME(name) PASTE2(name, __COUNTER__)
Line
Count
Source
9
0
#define PASTE2(x, y) PASTE(x, y)
Line
Count
Source
8
0
#define PASTE(x, y) x ## y
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
void BanMan::GetBanned(banmap_t& banmap)
175
0
{
176
0
    LOCK(m_banned_mutex);
Line
Count
Source
257
0
#define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__)
Line
Count
Source
11
0
#define UNIQUE_NAME(name) PASTE2(name, __COUNTER__)
Line
Count
Source
9
0
#define PASTE2(x, y) PASTE(x, y)
Line
Count
Source
8
0
#define PASTE(x, y) x ## y
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
void BanMan::SweepBanned()
183
99.9k
{
184
99.9k
    AssertLockHeld(m_banned_mutex);
Line
Count
Source
142
99.9k
#define AssertLockHeld(cs) AssertLockHeldInternal(#cs, __FILE__, __LINE__, &cs)
185
186
99.9k
    int64_t now = GetTime();
187
99.9k
    bool notify_ui = false;
188
99.9k
    banmap_t::iterator it = m_banned.begin();
189
99.9k
    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
            LogDebug(BCLog::NET, "Removed banned node address/subnet: %s\n", sub_net.ToString());
Line
Count
Source
280
0
#define LogDebug(category, ...) LogPrintLevel(category, BCLog::Level::Debug, __VA_ARGS__)
Line
Count
Source
273
0
    do {                                                  \
274
0
        if (LogAcceptCategory((category), (level))) {     \
275
0
            LogPrintLevel_(category, level, __VA_ARGS__); \
Line
Count
Source
255
0
#define LogPrintLevel_(category, level, ...) LogPrintFormatInternal(__func__, __FILE__, __LINE__, category, level, __VA_ARGS__)
276
0
        }                                                 \
277
0
    } while (0)
197
0
        } else {
198
0
            ++it;
199
0
        }
200
0
    }
201
202
    // update UI
203
99.9k
    if (notify_ui && 
m_client_interface0
) {
204
0
        m_client_interface->BannedListChanged();
205
0
    }
206
99.9k
}