/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 | } |