Bitcoin Core  27.99.0
P2P Digital Currency
net_permissions.cpp
Go to the documentation of this file.
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/system.h>
6 #include <net_permissions.h>
7 #include <netbase.h>
8 #include <util/error.h>
9 #include <util/translation.h>
10 
11 const std::vector<std::string> NET_PERMISSIONS_DOC{
12  "bloomfilter (allow requesting BIP37 filtered blocks and transactions)",
13  "noban (do not ban for misbehavior; implies download)",
14  "forcerelay (relay transactions that are already in the mempool; implies relay)",
15  "relay (relay even in -blocksonly mode, and unlimited transaction announcements)",
16  "mempool (allow requesting BIP35 mempool contents)",
17  "download (allow getheaders during IBD, no disconnect after maxuploadtarget limit)",
18  "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 static bool TryParsePermissionFlags(const std::string& str, NetPermissionFlags& output, ConnectionDirection* output_connection_direction, size_t& readen, bilingual_str& error)
25 {
27  ConnectionDirection connection_direction = ConnectionDirection::None;
28  const auto atSeparator = str.find('@');
29 
30  // if '@' is not found (ie, "xxxxx"), the caller should apply implicit permissions
31  if (atSeparator == std::string::npos) {
33  readen = 0;
34  }
35  // else (ie, "perm1,perm2@xxxxx"), let's enumerate the permissions by splitting by ',' and calculate the flags
36  else {
37  readen = 0;
38  // permissions == perm1,perm2
39  const auto permissions = str.substr(0, atSeparator);
40  while (readen < permissions.length()) {
41  const auto commaSeparator = permissions.find(',', readen);
42  const auto len = commaSeparator == std::string::npos ? permissions.length() - readen : commaSeparator - readen;
43  // permission == perm1
44  const auto permission = permissions.substr(readen, len);
45  readen += len; // We read "perm1"
46  if (commaSeparator != std::string::npos) readen++; // We read ","
47 
48  if (permission == "bloomfilter" || permission == "bloom") NetPermissions::AddFlag(flags, NetPermissionFlags::BloomFilter);
49  else if (permission == "noban") NetPermissions::AddFlag(flags, NetPermissionFlags::NoBan);
50  else if (permission == "forcerelay") NetPermissions::AddFlag(flags, NetPermissionFlags::ForceRelay);
51  else if (permission == "mempool") NetPermissions::AddFlag(flags, NetPermissionFlags::Mempool);
52  else if (permission == "download") NetPermissions::AddFlag(flags, NetPermissionFlags::Download);
53  else if (permission == "all") NetPermissions::AddFlag(flags, NetPermissionFlags::All);
54  else if (permission == "relay") NetPermissions::AddFlag(flags, NetPermissionFlags::Relay);
55  else if (permission == "addr") NetPermissions::AddFlag(flags, NetPermissionFlags::Addr);
56  else if (permission == "in") connection_direction |= ConnectionDirection::In;
57  else if (permission == "out") {
58  if (output_connection_direction == nullptr) {
59  // Only NetWhitebindPermissions() should pass a nullptr.
60  error = _("whitebind may only be used for incoming connections (\"out\" was passed)");
61  return false;
62  }
63  connection_direction |= ConnectionDirection::Out;
64  }
65  else if (permission.length() == 0); // Allow empty entries
66  else {
67  error = strprintf(_("Invalid P2P permission: '%s'"), permission);
68  return false;
69  }
70  }
71  readen++;
72  }
73 
74  // By default, whitelist only applies to incoming connections
75  if (connection_direction == ConnectionDirection::None) {
76  connection_direction = ConnectionDirection::In;
77  } else if (flags == NetPermissionFlags::None) {
78  error = strprintf(_("Only direction was set, no permissions: '%s'"), str);
79  return false;
80  }
81 
82  output = flags;
83  if (output_connection_direction) *output_connection_direction = connection_direction;
84  error = Untranslated("");
85  return true;
86 }
87 
88 }
89 
91 {
92  std::vector<std::string> strings;
93  if (NetPermissions::HasFlag(flags, NetPermissionFlags::BloomFilter)) strings.emplace_back("bloomfilter");
94  if (NetPermissions::HasFlag(flags, NetPermissionFlags::NoBan)) strings.emplace_back("noban");
95  if (NetPermissions::HasFlag(flags, NetPermissionFlags::ForceRelay)) strings.emplace_back("forcerelay");
96  if (NetPermissions::HasFlag(flags, NetPermissionFlags::Relay)) strings.emplace_back("relay");
97  if (NetPermissions::HasFlag(flags, NetPermissionFlags::Mempool)) strings.emplace_back("mempool");
98  if (NetPermissions::HasFlag(flags, NetPermissionFlags::Download)) strings.emplace_back("download");
99  if (NetPermissions::HasFlag(flags, NetPermissionFlags::Addr)) strings.emplace_back("addr");
100  return strings;
101 }
102 
103 bool NetWhitebindPermissions::TryParse(const std::string& str, NetWhitebindPermissions& output, bilingual_str& error)
104 {
106  size_t offset;
107  if (!TryParsePermissionFlags(str, flags, /*output_connection_direction=*/nullptr, offset, error)) return false;
108 
109  const std::string strBind = str.substr(offset);
110  const std::optional<CService> addrBind{Lookup(strBind, 0, false)};
111  if (!addrBind.has_value()) {
112  error = ResolveErrMsg("whitebind", strBind);
113  return false;
114  }
115  if (addrBind.value().GetPort() == 0) {
116  error = strprintf(_("Need to specify a port with -whitebind: '%s'"), strBind);
117  return false;
118  }
119 
120  output.m_flags = flags;
121  output.m_service = addrBind.value();
122  error = Untranslated("");
123  return true;
124 }
125 
126 bool NetWhitelistPermissions::TryParse(const std::string& str, NetWhitelistPermissions& output, ConnectionDirection& output_connection_direction, bilingual_str& error)
127 {
129  size_t offset;
130  // Only NetWhitebindPermissions should pass a nullptr for output_connection_direction.
131  if (!TryParsePermissionFlags(str, flags, &output_connection_direction, offset, error)) return false;
132 
133  const std::string net = str.substr(offset);
134  const CSubNet subnet{LookupSubNet(net)};
135  if (!subnet.IsValid()) {
136  error = strprintf(_("Invalid netmask specified in -whitelist: '%s'"), net);
137  return false;
138  }
139 
140  output.m_flags = flags;
141  output.m_subnet = subnet;
142  error = Untranslated("");
143  return true;
144 }
int flags
Definition: bitcoin-tx.cpp:530
NetPermissionFlags m_flags
static void AddFlag(NetPermissionFlags &flags, NetPermissionFlags f)
static std::vector< std::string > ToStrings(NetPermissionFlags flags)
static bool HasFlag(NetPermissionFlags flags, NetPermissionFlags f)
static bool TryParse(const std::string &str, NetWhitebindPermissions &output, bilingual_str &error)
static bool TryParse(const std::string &str, NetWhitelistPermissions &output, ConnectionDirection &output_connection_direction, bilingual_str &error)
bilingual_str ResolveErrMsg(const std::string &optname, const std::string &strBind)
Definition: error.cpp:49
const std::vector< std::string > NET_PERMISSIONS_DOC
NetPermissionFlags
CSubNet LookupSubNet(const std::string &subnet_str)
Parse and resolve a specified subnet string into the appropriate internal representation.
Definition: netbase.cpp:745
std::vector< CService > Lookup(const std::string &name, uint16_t portDefault, bool fAllowLookup, unsigned int nMaxSolutions, DNSLookupFn dns_lookup_function)
Resolve a service string to its corresponding service.
Definition: netbase.cpp:184
ConnectionDirection
Definition: netbase.h:33
Bilingual messages:
Definition: translation.h:18
#define strprintf
Format arguments and return the string or write to given std::ostream (see tinyformat::format doc for...
Definition: tinyformat.h:1162
bilingual_str _(const char *psz)
Translation function.
Definition: translation.h:74
bilingual_str Untranslated(std::string original)
Mark a bilingual_str as untranslated.
Definition: translation.h:48