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 <net_permissions.h>
6 : #include <netbase.h>
7 : #include <util/error.h>
8 : #include <util/system.h>
9 : #include <util/translation.h>
10 :
11 146 : const std::vector<std::string> NET_PERMISSIONS_DOC{
12 146 : "bloomfilter (allow requesting BIP37 filtered blocks and transactions)",
13 146 : "noban (do not ban for misbehavior; implies download)",
14 146 : "forcerelay (relay transactions that are already in the mempool; implies relay)",
15 146 : "relay (relay even in -blocksonly mode)",
16 146 : "mempool (allow requesting BIP35 mempool contents)",
17 146 : "download (allow getheaders during IBD, no disconnect after maxuploadtarget limit)",
18 146 : "addr (responses to GETADDR avoid hitting the cache and contain random records with the most up-to-date info)"
19 : };
20 :
21 : namespace {
22 :
23 : // Parse the following format: "perm1,perm2@xxxxxx"
24 23 : bool TryParsePermissionFlags(const std::string& str, NetPermissionFlags& output, size_t& readen, bilingual_str& error)
25 : {
26 23 : NetPermissionFlags flags = NetPermissionFlags::None;
27 23 : const auto atSeparator = str.find('@');
28 :
29 : // if '@' is not found (ie, "xxxxx"), the caller should apply implicit permissions
30 23 : if (atSeparator == std::string::npos) {
31 4 : NetPermissions::AddFlag(flags, NetPermissionFlags::Implicit);
32 4 : readen = 0;
33 4 : }
34 : // else (ie, "perm1,perm2@xxxxx"), let's enumerate the permissions by splitting by ',' and calculate the flags
35 : else {
36 19 : readen = 0;
37 : // permissions == perm1,perm2
38 19 : const auto permissions = str.substr(0, atSeparator);
39 61 : while (readen < permissions.length()) {
40 43 : const auto commaSeparator = permissions.find(',', readen);
41 43 : const auto len = commaSeparator == std::string::npos ? permissions.length() - readen : commaSeparator - readen;
42 : // permission == perm1
43 43 : const auto permission = permissions.substr(readen, len);
44 43 : readen += len; // We read "perm1"
45 43 : if (commaSeparator != std::string::npos) readen++; // We read ","
46 :
47 43 : if (permission == "bloomfilter" || permission == "bloom") NetPermissions::AddFlag(flags, NetPermissionFlags::BloomFilter);
48 33 : else if (permission == "noban") NetPermissions::AddFlag(flags, NetPermissionFlags::NoBan);
49 21 : else if (permission == "forcerelay") NetPermissions::AddFlag(flags, NetPermissionFlags::ForceRelay);
50 15 : else if (permission == "mempool") NetPermissions::AddFlag(flags, NetPermissionFlags::Mempool);
51 14 : else if (permission == "download") NetPermissions::AddFlag(flags, NetPermissionFlags::Download);
52 11 : else if (permission == "all") NetPermissions::AddFlag(flags, NetPermissionFlags::All);
53 10 : else if (permission == "relay") NetPermissions::AddFlag(flags, NetPermissionFlags::Relay);
54 5 : else if (permission == "addr") NetPermissions::AddFlag(flags, NetPermissionFlags::Addr);
55 5 : else if (permission.length() == 0); // Allow empty entries
56 : else {
57 1 : error = strprintf(_("Invalid P2P permission: '%s'"), permission);
58 1 : return false;
59 : }
60 43 : }
61 18 : readen++;
62 19 : }
63 :
64 22 : output = flags;
65 22 : error = Untranslated("");
66 22 : return true;
67 23 : }
68 :
69 : }
70 :
71 1 : std::vector<std::string> NetPermissions::ToStrings(NetPermissionFlags flags)
72 : {
73 1 : std::vector<std::string> strings;
74 1 : if (NetPermissions::HasFlag(flags, NetPermissionFlags::BloomFilter)) strings.emplace_back("bloomfilter");
75 1 : if (NetPermissions::HasFlag(flags, NetPermissionFlags::NoBan)) strings.emplace_back("noban");
76 1 : if (NetPermissions::HasFlag(flags, NetPermissionFlags::ForceRelay)) strings.emplace_back("forcerelay");
77 1 : if (NetPermissions::HasFlag(flags, NetPermissionFlags::Relay)) strings.emplace_back("relay");
78 1 : if (NetPermissions::HasFlag(flags, NetPermissionFlags::Mempool)) strings.emplace_back("mempool");
79 1 : if (NetPermissions::HasFlag(flags, NetPermissionFlags::Download)) strings.emplace_back("download");
80 1 : if (NetPermissions::HasFlag(flags, NetPermissionFlags::Addr)) strings.emplace_back("addr");
81 1 : return strings;
82 1 : }
83 :
84 19 : bool NetWhitebindPermissions::TryParse(const std::string& str, NetWhitebindPermissions& output, bilingual_str& error)
85 : {
86 : NetPermissionFlags flags;
87 : size_t offset;
88 19 : if (!TryParsePermissionFlags(str, flags, offset, error)) return false;
89 :
90 18 : const std::string strBind = str.substr(offset);
91 18 : const std::optional<CService> addrBind{Lookup(strBind, 0, false)};
92 18 : if (!addrBind.has_value()) {
93 2 : error = ResolveErrMsg("whitebind", strBind);
94 2 : return false;
95 : }
96 16 : if (addrBind.value().GetPort() == 0) {
97 1 : error = strprintf(_("Need to specify a port with -whitebind: '%s'"), strBind);
98 1 : return false;
99 : }
100 :
101 15 : output.m_flags = flags;
102 15 : output.m_service = addrBind.value();
103 15 : error = Untranslated("");
104 15 : return true;
105 19 : }
106 :
107 4 : bool NetWhitelistPermissions::TryParse(const std::string& str, NetWhitelistPermissions& output, bilingual_str& error)
108 : {
109 : NetPermissionFlags flags;
110 : size_t offset;
111 4 : if (!TryParsePermissionFlags(str, flags, offset, error)) return false;
112 :
113 4 : const std::string net = str.substr(offset);
114 4 : const CSubNet subnet{LookupSubNet(net)};
115 4 : if (!subnet.IsValid()) {
116 1 : error = strprintf(_("Invalid netmask specified in -whitelist: '%s'"), net);
117 1 : return false;
118 : }
119 :
120 3 : output.m_flags = flags;
121 3 : output.m_subnet = subnet;
122 3 : error = Untranslated("");
123 3 : return true;
124 4 : }
|