Coverage Report

Created: 2026-09-01 13:33

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/root/bitcoin/src/net_permissions.cpp
Line
Count
Source
1
// Copyright (c) 2009-present The Bitcoin Core developers
2
// Distributed under the MIT software license, see the accompanying
3
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4
5
#include <common/messages.h>
6
#include <common/system.h>
7
#include <net_permissions.h>
8
#include <netbase.h>
9
#include <util/translation.h>
10
11
using common::ResolveErrMsg;
12
13
const std::vector<std::string> NET_PERMISSIONS_DOC{
14
    "bloomfilter (allow requesting BIP37 filtered blocks and transactions)",
15
    "noban (do not ban for misbehavior; implies download)",
16
    "forcerelay (relay transactions that are already in the mempool; implies relay)",
17
    "relay (relay even in -blocksonly mode, and unlimited transaction announcements)",
18
    "mempool (allow requesting BIP35 mempool contents)",
19
    "download (allow getheaders during IBD, no disconnect after maxuploadtarget limit)",
20
    "addr (responses to GETADDR avoid hitting the cache and contain random records with the most up-to-date info)"
21
};
22
23
namespace {
24
25
// Parse the following format: "perm1,perm2@xxxxxx"
26
static bool TryParsePermissionFlags(const std::string& str, NetPermissionFlags& output, ConnectionDirection* output_connection_direction, size_t& readen, bilingual_str& error)
27
618
{
28
618
    NetPermissionFlags flags = NetPermissionFlags::None;
29
618
    ConnectionDirection connection_direction = ConnectionDirection::None;
30
618
    const auto atSeparator = str.find('@');
31
32
    // if '@' is not found (ie, "xxxxx"), the caller should apply implicit permissions
33
618
    if (atSeparator == std::string::npos) {
  Branch (33:9): [True: 392, False: 226]
34
392
        NetPermissions::AddFlag(flags, NetPermissionFlags::Implicit);
35
392
        readen = 0;
36
392
    }
37
    // else (ie, "perm1,perm2@xxxxx"), let's enumerate the permissions by splitting by ',' and calculate the flags
38
226
    else {
39
226
        readen = 0;
40
        // permissions == perm1,perm2
41
226
        const auto permissions = str.substr(0, atSeparator);
42
5.36k
        while (readen < permissions.length()) {
  Branch (42:16): [True: 5.22k, False: 144]
43
5.22k
            const auto commaSeparator = permissions.find(',', readen);
44
5.22k
            const auto len = commaSeparator == std::string::npos ? permissions.length() - readen : commaSeparator - readen;
  Branch (44:30): [True: 148, False: 5.07k]
45
            // permission == perm1
46
5.22k
            const auto permission = permissions.substr(readen, len);
47
5.22k
            readen += len; // We read "perm1"
48
5.22k
            if (commaSeparator != std::string::npos) readen++; // We read ","
  Branch (48:17): [True: 5.07k, False: 148]
49
50
5.22k
            if (permission == "bloomfilter" || permission == "bloom") NetPermissions::AddFlag(flags, NetPermissionFlags::BloomFilter);
  Branch (50:17): [True: 211, False: 5.01k]
  Branch (50:48): [True: 207, False: 4.80k]
51
4.80k
            else if (permission == "noban") NetPermissions::AddFlag(flags, NetPermissionFlags::NoBan);
  Branch (51:22): [True: 232, False: 4.57k]
52
4.57k
            else if (permission == "forcerelay") NetPermissions::AddFlag(flags, NetPermissionFlags::ForceRelay);
  Branch (52:22): [True: 212, False: 4.36k]
53
4.36k
            else if (permission == "mempool") NetPermissions::AddFlag(flags, NetPermissionFlags::Mempool);
  Branch (53:22): [True: 201, False: 4.16k]
54
4.16k
            else if (permission == "download") NetPermissions::AddFlag(flags, NetPermissionFlags::Download);
  Branch (54:22): [True: 208, False: 3.95k]
55
3.95k
            else if (permission == "all") NetPermissions::AddFlag(flags, NetPermissionFlags::All);
  Branch (55:22): [True: 224, False: 3.72k]
56
3.72k
            else if (permission == "relay") NetPermissions::AddFlag(flags, NetPermissionFlags::Relay);
  Branch (56:22): [True: 203, False: 3.52k]
57
3.52k
            else if (permission == "addr") NetPermissions::AddFlag(flags, NetPermissionFlags::Addr);
  Branch (57:22): [True: 246, False: 3.27k]
58
3.27k
            else if (permission == "in") connection_direction |= ConnectionDirection::In;
  Branch (58:22): [True: 683, False: 2.59k]
59
2.59k
            else if (permission == "out") {
  Branch (59:22): [True: 311, False: 2.28k]
60
311
                if (output_connection_direction == nullptr) {
  Branch (60:21): [True: 40, False: 271]
61
                    // Only NetWhitebindPermissions() should pass a nullptr.
62
40
                    error = _("whitebind may only be used for incoming connections (\"out\" was passed)");
63
40
                    return false;
64
40
                }
65
271
                connection_direction |= ConnectionDirection::Out;
66
271
            }
67
2.28k
            else if (permission.length() == 0); // Allow empty entries
  Branch (67:22): [True: 2.24k, False: 42]
68
42
            else {
69
42
                error = strprintf(_("Invalid P2P permission: '%s'"), permission);
70
42
                return false;
71
42
            }
72
5.22k
        }
73
144
        readen++;
74
144
    }
75
76
    // By default, whitelist only applies to incoming connections
77
536
    if (connection_direction == ConnectionDirection::None) {
  Branch (77:9): [True: 498, False: 38]
78
498
        connection_direction = ConnectionDirection::In;
79
498
    } else if (flags == NetPermissionFlags::None) {
  Branch (79:16): [True: 12, False: 26]
80
12
        error = strprintf(_("Only direction was set, no permissions: '%s'"), str);
81
12
        return false;
82
12
    }
83
84
524
    output = flags;
85
524
    if (output_connection_direction) *output_connection_direction = connection_direction;
  Branch (85:9): [True: 273, False: 251]
86
524
    error = Untranslated("");
87
524
    return true;
88
536
}
89
90
}
91
92
std::vector<std::string> NetPermissions::ToStrings(NetPermissionFlags flags)
93
112
{
94
112
    std::vector<std::string> strings;
95
112
    if (NetPermissions::HasFlag(flags, NetPermissionFlags::BloomFilter)) strings.emplace_back("bloomfilter");
  Branch (95:9): [True: 23, False: 89]
96
112
    if (NetPermissions::HasFlag(flags, NetPermissionFlags::NoBan)) strings.emplace_back("noban");
  Branch (96:9): [True: 37, False: 75]
97
112
    if (NetPermissions::HasFlag(flags, NetPermissionFlags::ForceRelay)) strings.emplace_back("forcerelay");
  Branch (97:9): [True: 22, False: 90]
98
112
    if (NetPermissions::HasFlag(flags, NetPermissionFlags::Relay)) strings.emplace_back("relay");
  Branch (98:9): [True: 30, False: 82]
99
112
    if (NetPermissions::HasFlag(flags, NetPermissionFlags::Mempool)) strings.emplace_back("mempool");
  Branch (99:9): [True: 25, False: 87]
100
112
    if (NetPermissions::HasFlag(flags, NetPermissionFlags::Download)) strings.emplace_back("download");
  Branch (100:9): [True: 43, False: 69]
101
112
    if (NetPermissions::HasFlag(flags, NetPermissionFlags::Addr)) strings.emplace_back("addr");
  Branch (101:9): [True: 32, False: 80]
102
112
    return strings;
103
112
}
104
105
bool NetWhitebindPermissions::TryParse(const std::string& str, NetWhitebindPermissions& output, bilingual_str& error)
106
309
{
107
309
    NetPermissionFlags flags;
108
309
    size_t offset;
109
309
    if (!TryParsePermissionFlags(str, flags, /*output_connection_direction=*/nullptr, offset, error)) return false;
  Branch (109:9): [True: 58, False: 251]
110
111
251
    const std::string strBind = str.substr(offset);
112
251
    const std::optional<CService> addrBind{Lookup(strBind, 0, false)};
113
251
    if (!addrBind.has_value()) {
  Branch (113:9): [True: 218, False: 33]
114
218
        error = ResolveErrMsg("whitebind", strBind);
115
218
        return false;
116
218
    }
117
33
    if (addrBind.value().GetPort() == 0) {
  Branch (117:9): [True: 23, False: 10]
118
23
        error = strprintf(_("Need to specify a port with -whitebind: '%s'"), strBind);
119
23
        return false;
120
23
    }
121
122
10
    output.m_flags = flags;
123
10
    output.m_service = addrBind.value();
124
10
    error = Untranslated("");
125
10
    return true;
126
33
}
127
128
bool NetWhitelistPermissions::TryParse(const std::string& str, NetWhitelistPermissions& output, ConnectionDirection& output_connection_direction, bilingual_str& error)
129
309
{
130
309
    NetPermissionFlags flags;
131
309
    size_t offset;
132
    // Only NetWhitebindPermissions should pass a nullptr for output_connection_direction.
133
309
    if (!TryParsePermissionFlags(str, flags, &output_connection_direction, offset, error)) return false;
  Branch (133:9): [True: 36, False: 273]
134
135
273
    const std::string net = str.substr(offset);
136
273
    const CSubNet subnet{LookupSubNet(net)};
137
273
    if (!subnet.IsValid()) {
  Branch (137:9): [True: 227, False: 46]
138
227
        error = strprintf(_("Invalid netmask specified in -whitelist: '%s'"), net);
139
227
        return false;
140
227
    }
141
142
46
    output.m_flags = flags;
143
46
    output.m_subnet = subnet;
144
46
    error = Untranslated("");
145
46
    return true;
146
273
}