Branch data Line data Source code
1 : : // Copyright (c) 2009-2021 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 [ + - # # ]: 1 : const std::vector<std::string> NET_PERMISSIONS_DOC{
14 [ + - ]: 1 : "bloomfilter (allow requesting BIP37 filtered blocks and transactions)",
15 [ + - ]: 1 : "noban (do not ban for misbehavior; implies download)",
16 [ + - ]: 1 : "forcerelay (relay transactions that are already in the mempool; implies relay)",
17 [ + - ]: 1 : "relay (relay even in -blocksonly mode, and unlimited transaction announcements)",
18 [ + - ]: 1 : "mempool (allow requesting BIP35 mempool contents)",
19 [ + - ]: 1 : "download (allow getheaders during IBD, no disconnect after maxuploadtarget limit)",
20 [ + - ]: 1 : "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 : 1096 : static bool TryParsePermissionFlags(const std::string& str, NetPermissionFlags& output, ConnectionDirection* output_connection_direction, size_t& readen, bilingual_str& error)
27 : : {
28 : 1096 : NetPermissionFlags flags = NetPermissionFlags::None;
29 : 1096 : ConnectionDirection connection_direction = ConnectionDirection::None;
30 : 1096 : const auto atSeparator = str.find('@');
31 : :
32 : : // if '@' is not found (ie, "xxxxx"), the caller should apply implicit permissions
33 [ + + ]: 1096 : if (atSeparator == std::string::npos) {
34 : 604 : NetPermissions::AddFlag(flags, NetPermissionFlags::Implicit);
35 : 604 : readen = 0;
36 : 604 : }
37 : : // else (ie, "perm1,perm2@xxxxx"), let's enumerate the permissions by splitting by ',' and calculate the flags
38 : : else {
39 : 492 : readen = 0;
40 : : // permissions == perm1,perm2
41 : 492 : const auto permissions = str.substr(0, atSeparator);
42 [ + + ]: 21973 : while (readen < permissions.length()) {
43 : 21701 : const auto commaSeparator = permissions.find(',', readen);
44 [ + + ]: 21701 : const auto len = commaSeparator == std::string::npos ? permissions.length() - readen : commaSeparator - readen;
45 : : // permission == perm1
46 [ + - ]: 21701 : const auto permission = permissions.substr(readen, len);
47 : 21701 : readen += len; // We read "perm1"
48 [ + + ]: 21701 : if (commaSeparator != std::string::npos) readen++; // We read ","
49 : :
50 [ + - + + : 21701 : if (permission == "bloomfilter" || permission == "bloom") NetPermissions::AddFlag(flags, NetPermissionFlags::BloomFilter);
+ - + + +
- ]
51 [ + - + + : 21117 : else if (permission == "noban") NetPermissions::AddFlag(flags, NetPermissionFlags::NoBan);
+ - ]
52 [ + - + + : 20324 : else if (permission == "forcerelay") NetPermissions::AddFlag(flags, NetPermissionFlags::ForceRelay);
+ - ]
53 [ + - + + : 20204 : else if (permission == "mempool") NetPermissions::AddFlag(flags, NetPermissionFlags::Mempool);
+ - ]
54 [ + - + + : 19792 : else if (permission == "download") NetPermissions::AddFlag(flags, NetPermissionFlags::Download);
+ - ]
55 [ + - + + : 19333 : else if (permission == "all") NetPermissions::AddFlag(flags, NetPermissionFlags::All);
+ - ]
56 [ + - + + : 18545 : else if (permission == "relay") NetPermissions::AddFlag(flags, NetPermissionFlags::Relay);
+ - ]
57 [ + - + + : 17928 : else if (permission == "addr") NetPermissions::AddFlag(flags, NetPermissionFlags::Addr);
+ - ]
58 [ + - + + : 17434 : else if (permission == "in") connection_direction |= ConnectionDirection::In;
+ - ]
59 [ + - + + ]: 15613 : else if (permission == "out") {
60 [ + + ]: 770 : if (output_connection_direction == nullptr) {
61 : : // Only NetWhitebindPermissions() should pass a nullptr.
62 [ + - ]: 81 : error = _("whitebind may only be used for incoming connections (\"out\" was passed)");
63 : 81 : return false;
64 : : }
65 [ + - ]: 689 : connection_direction |= ConnectionDirection::Out;
66 : 689 : }
67 [ + + ]: 14843 : else if (permission.length() == 0); // Allow empty entries
68 : : else {
69 [ - + + - ]: 139 : error = strprintf(_("Invalid P2P permission: '%s'"), permission);
70 : 139 : return false;
71 : : }
72 [ + + ]: 21701 : }
73 : 272 : readen++;
74 [ + + ]: 492 : }
75 : :
76 : : // By default, whitelist only applies to incoming connections
77 [ + + ]: 876 : if (connection_direction == ConnectionDirection::None) {
78 : 806 : connection_direction = ConnectionDirection::In;
79 [ + + ]: 876 : } else if (flags == NetPermissionFlags::None) {
80 [ + - ]: 17 : error = strprintf(_("Only direction was set, no permissions: '%s'"), str);
81 : 17 : return false;
82 : : }
83 : :
84 : 859 : output = flags;
85 [ + + ]: 859 : if (output_connection_direction) *output_connection_direction = connection_direction;
86 [ + - + - ]: 859 : error = Untranslated("");
87 : 859 : return true;
88 : 1096 : }
89 : :
90 : : }
91 : :
92 : 252 : std::vector<std::string> NetPermissions::ToStrings(NetPermissionFlags flags)
93 : : {
94 : 252 : std::vector<std::string> strings;
95 [ + - + + : 252 : if (NetPermissions::HasFlag(flags, NetPermissionFlags::BloomFilter)) strings.emplace_back("bloomfilter");
+ - ]
96 [ + - + + : 252 : if (NetPermissions::HasFlag(flags, NetPermissionFlags::NoBan)) strings.emplace_back("noban");
+ - ]
97 [ + - + + : 252 : if (NetPermissions::HasFlag(flags, NetPermissionFlags::ForceRelay)) strings.emplace_back("forcerelay");
+ - ]
98 [ + - + + : 252 : if (NetPermissions::HasFlag(flags, NetPermissionFlags::Relay)) strings.emplace_back("relay");
+ - ]
99 [ + - + + : 252 : if (NetPermissions::HasFlag(flags, NetPermissionFlags::Mempool)) strings.emplace_back("mempool");
+ - ]
100 [ + - + + : 252 : if (NetPermissions::HasFlag(flags, NetPermissionFlags::Download)) strings.emplace_back("download");
+ - ]
101 [ + - + + : 252 : if (NetPermissions::HasFlag(flags, NetPermissionFlags::Addr)) strings.emplace_back("addr");
+ - ]
102 : 252 : return strings;
103 [ + - ]: 252 : }
104 : :
105 : 548 : bool NetWhitebindPermissions::TryParse(const std::string& str, NetWhitebindPermissions& output, bilingual_str& error)
106 : : {
107 : 548 : NetPermissionFlags flags;
108 : 548 : size_t offset;
109 [ + + ]: 548 : if (!TryParsePermissionFlags(str, flags, /*output_connection_direction=*/nullptr, offset, error)) return false;
110 : :
111 : 410 : const std::string strBind = str.substr(offset);
112 [ + - + - ]: 410 : const std::optional<CService> addrBind{Lookup(strBind, 0, false)};
113 [ + + ]: 410 : if (!addrBind.has_value()) {
114 [ + - + - ]: 333 : error = ResolveErrMsg("whitebind", strBind);
115 : 333 : return false;
116 : : }
117 [ + - + - : 77 : if (addrBind.value().GetPort() == 0) {
+ + ]
118 [ + - + - ]: 57 : error = strprintf(_("Need to specify a port with -whitebind: '%s'"), strBind);
119 : 57 : return false;
120 : : }
121 : :
122 : 20 : output.m_flags = flags;
123 [ + - + - ]: 20 : output.m_service = addrBind.value();
124 [ + - + - ]: 20 : error = Untranslated("");
125 : 20 : return true;
126 : 548 : }
127 : :
128 : 548 : bool NetWhitelistPermissions::TryParse(const std::string& str, NetWhitelistPermissions& output, ConnectionDirection& output_connection_direction, bilingual_str& error)
129 : : {
130 : 548 : NetPermissionFlags flags;
131 : 548 : size_t offset;
132 : : // Only NetWhitebindPermissions should pass a nullptr for output_connection_direction.
133 [ + + ]: 548 : if (!TryParsePermissionFlags(str, flags, &output_connection_direction, offset, error)) return false;
134 : :
135 : 449 : const std::string net = str.substr(offset);
136 [ + - ]: 449 : const CSubNet subnet{LookupSubNet(net)};
137 [ + - + + ]: 449 : if (!subnet.IsValid()) {
138 [ + - + - ]: 343 : error = strprintf(_("Invalid netmask specified in -whitelist: '%s'"), net);
139 : 343 : return false;
140 : : }
141 : :
142 : 106 : output.m_flags = flags;
143 [ + - ]: 106 : output.m_subnet = subnet;
144 [ + - + - ]: 106 : error = Untranslated("");
145 : 106 : return true;
146 : 548 : }
|