bitcoin/src/net_permissions.cpp
Andrew Chow 71300489af
Merge bitcoin/bitcoin#26261: p2p: cleanup LookupIntern, Lookup and LookupHost
5c832c3820 p2p, refactor: return `std::optional<CNetAddr>` in `LookupHost` (brunoerg)
34bcdfc6a6 p2p, refactor: return vector/optional<CService> in `Lookup` (brunoerg)
7799eb125b p2p, refactor: return `std::vector<CNetAddr>` in `LookupHost` (brunoerg)
5c1774a563 p2p, refactor: return `std::vector<CNetAddr>` in `LookupIntern` (brunoerg)

Pull request description:

  Continuation of #26078.

  To improve readability instead of returning a bool and passing stuff by reference, this PR changes:

  - `LookupHost` to return `std::vector<CNetAddr>`
  - `LookupHost` to return `std::optional<CNetAddr>`
  - `Lookup` to return `std::vector<CService>`
  - `Lookup` to return `std::optional<CService>`.
  - `LookupIntern` to return `std::vector<CNetAddr>`

  As discussed in #26078, it would be better to avoid using `optional` in some cases, but for specific `Lookup` and `LookupHost` functions it's necessary to use `optional` to verify if they were able to catch some data from their overloaded function.

ACKs for top commit:
  achow101:
    ACK 5c832c3820
  stickies-v:
    re-ACK 5c832c3820 - just addressing two nits, no other changes
  theStack:
    re-ACK 5c832c3820

Tree-SHA512: ea346fdc54463999646269bd600cd4a1590ef958001d2f0fc2be608ca51e1b4365efccca76dd4972b023e12fcc6e67d226608b0df7beb901bdeadd19948df840
2023-05-30 11:39:59 -04:00

125 lines
5.4 KiB
C++

// Copyright (c) 2009-2021 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <common/system.h>
#include <net_permissions.h>
#include <netbase.h>
#include <util/error.h>
#include <util/translation.h>
const std::vector<std::string> NET_PERMISSIONS_DOC{
"bloomfilter (allow requesting BIP37 filtered blocks and transactions)",
"noban (do not ban for misbehavior; implies download)",
"forcerelay (relay transactions that are already in the mempool; implies relay)",
"relay (relay even in -blocksonly mode, and unlimited transaction announcements)",
"mempool (allow requesting BIP35 mempool contents)",
"download (allow getheaders during IBD, no disconnect after maxuploadtarget limit)",
"addr (responses to GETADDR avoid hitting the cache and contain random records with the most up-to-date info)"
};
namespace {
// Parse the following format: "perm1,perm2@xxxxxx"
bool TryParsePermissionFlags(const std::string& str, NetPermissionFlags& output, size_t& readen, bilingual_str& error)
{
NetPermissionFlags flags = NetPermissionFlags::None;
const auto atSeparator = str.find('@');
// if '@' is not found (ie, "xxxxx"), the caller should apply implicit permissions
if (atSeparator == std::string::npos) {
NetPermissions::AddFlag(flags, NetPermissionFlags::Implicit);
readen = 0;
}
// else (ie, "perm1,perm2@xxxxx"), let's enumerate the permissions by splitting by ',' and calculate the flags
else {
readen = 0;
// permissions == perm1,perm2
const auto permissions = str.substr(0, atSeparator);
while (readen < permissions.length()) {
const auto commaSeparator = permissions.find(',', readen);
const auto len = commaSeparator == std::string::npos ? permissions.length() - readen : commaSeparator - readen;
// permission == perm1
const auto permission = permissions.substr(readen, len);
readen += len; // We read "perm1"
if (commaSeparator != std::string::npos) readen++; // We read ","
if (permission == "bloomfilter" || permission == "bloom") NetPermissions::AddFlag(flags, NetPermissionFlags::BloomFilter);
else if (permission == "noban") NetPermissions::AddFlag(flags, NetPermissionFlags::NoBan);
else if (permission == "forcerelay") NetPermissions::AddFlag(flags, NetPermissionFlags::ForceRelay);
else if (permission == "mempool") NetPermissions::AddFlag(flags, NetPermissionFlags::Mempool);
else if (permission == "download") NetPermissions::AddFlag(flags, NetPermissionFlags::Download);
else if (permission == "all") NetPermissions::AddFlag(flags, NetPermissionFlags::All);
else if (permission == "relay") NetPermissions::AddFlag(flags, NetPermissionFlags::Relay);
else if (permission == "addr") NetPermissions::AddFlag(flags, NetPermissionFlags::Addr);
else if (permission.length() == 0); // Allow empty entries
else {
error = strprintf(_("Invalid P2P permission: '%s'"), permission);
return false;
}
}
readen++;
}
output = flags;
error = Untranslated("");
return true;
}
}
std::vector<std::string> NetPermissions::ToStrings(NetPermissionFlags flags)
{
std::vector<std::string> strings;
if (NetPermissions::HasFlag(flags, NetPermissionFlags::BloomFilter)) strings.push_back("bloomfilter");
if (NetPermissions::HasFlag(flags, NetPermissionFlags::NoBan)) strings.push_back("noban");
if (NetPermissions::HasFlag(flags, NetPermissionFlags::ForceRelay)) strings.push_back("forcerelay");
if (NetPermissions::HasFlag(flags, NetPermissionFlags::Relay)) strings.push_back("relay");
if (NetPermissions::HasFlag(flags, NetPermissionFlags::Mempool)) strings.push_back("mempool");
if (NetPermissions::HasFlag(flags, NetPermissionFlags::Download)) strings.push_back("download");
if (NetPermissions::HasFlag(flags, NetPermissionFlags::Addr)) strings.push_back("addr");
return strings;
}
bool NetWhitebindPermissions::TryParse(const std::string& str, NetWhitebindPermissions& output, bilingual_str& error)
{
NetPermissionFlags flags;
size_t offset;
if (!TryParsePermissionFlags(str, flags, offset, error)) return false;
const std::string strBind = str.substr(offset);
const std::optional<CService> addrBind{Lookup(strBind, 0, false)};
if (!addrBind.has_value()) {
error = ResolveErrMsg("whitebind", strBind);
return false;
}
if (addrBind.value().GetPort() == 0) {
error = strprintf(_("Need to specify a port with -whitebind: '%s'"), strBind);
return false;
}
output.m_flags = flags;
output.m_service = addrBind.value();
error = Untranslated("");
return true;
}
bool NetWhitelistPermissions::TryParse(const std::string& str, NetWhitelistPermissions& output, bilingual_str& error)
{
NetPermissionFlags flags;
size_t offset;
if (!TryParsePermissionFlags(str, flags, offset, error)) return false;
const std::string net = str.substr(offset);
CSubNet subnet;
LookupSubNet(net, subnet);
if (!subnet.IsValid()) {
error = strprintf(_("Invalid netmask specified in -whitelist: '%s'"), net);
return false;
}
output.m_flags = flags;
output.m_subnet = subnet;
error = Untranslated("");
return true;
}